diff --git a/.mailmap b/.mailmap index d357e1bd2a43..0d971cfb0772 100644 --- a/.mailmap +++ b/.mailmap @@ -73,6 +73,7 @@ Juha Yrjola Juha Yrjola Kay Sievers Kenneth W Chen +Konstantin Khlebnikov Koushik Kuninori Morimoto Leonid I Ananiev diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 1750fcef1ab4..cd077ca0e1b8 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -29,8 +29,6 @@ DMA-ISA-LPC.txt - How to do DMA with ISA (and LPC) devices. DMA-attributes.txt - listing of the various possible attributes a DMA region can have -dmatest.txt - - how to compile, configure and use the dmatest system. DocBook/ - directory with DocBook templates etc. for kernel documentation. EDID/ @@ -163,8 +161,6 @@ digsig.txt -info on the Digital Signature Verification API dma-buf-sharing.txt - the DMA Buffer Sharing API Guide -dmaengine.txt - -the DMA Engine API Guide dontdiff - file containing a list of files that should never be diff'ed. driver-model/ @@ -209,6 +205,8 @@ hid/ - directory with information on human interface devices highuid.txt - notes on the change from 16 bit to 32 bit user/group IDs. +hsi.txt + - HSI subsystem overview. hwspinlock.txt - hardware spinlock provides hardware assistance for synchronization timers/ @@ -277,6 +275,8 @@ kprobes.txt - documents the kernel probes debugging feature. kref.txt - docs on adding reference counters (krefs) to kernel objects. +kselftest.txt + - small unittests for (some) individual codepaths in the kernel. laptops/ - directory with laptop related info and laptop driver documentation. ldm.txt @@ -285,22 +285,22 @@ leds/ - directory with info about LED handling under Linux. local_ops.txt - semantics and behavior of local atomic operations. -lockdep-design.txt - - documentation on the runtime locking correctness validator. locking/ - directory with info about kernel locking primitives -lockstat.txt - - info on collecting statistics on locks (and contention). lockup-watchdogs.txt - info on soft and hard lockup detectors (aka nmi_watchdog). logo.gif - full colour GIF image of Linux logo (penguin - Tux). logo.txt - info on creator of above logo & site to get additional images from. +lzo.txt + - kernel LZO decompressor input formats m68k/ - directory with info about Linux on Motorola 68k architecture. magic-number.txt - list of magic numbers used to mark/protect kernel data structures. +mailbox.txt + - How to write drivers for the common mailbox framework (IPC). md.txt - info on boot arguments for the multiple devices driver. media-framework.txt @@ -327,8 +327,6 @@ mtd/ - directory with info about memory technology devices (flash) mono.txt - how to execute Mono-based .NET binaries with the help of BINFMT_MISC. -mutex-design.txt - - info on the generic mutex subsystem. namespaces/ - directory with various information about namespaces netlabel/ @@ -395,10 +393,6 @@ robust-futexes.txt - a description of what robust futexes are. rpmsg.txt - info on the Remote Processor Messaging (rpmsg) Framework -rt-mutex-design.txt - - description of the RealTime mutex implementation design. -rt-mutex.txt - - desc. of RT-mutex subsystem with PI (Priority Inheritance) support. rtc.txt - notes on how to use the Real Time Clock (aka CMOS clock) driver. s390/ @@ -425,8 +419,6 @@ sparse.txt - info on how to obtain and use the sparse tool for typechecking. spi/ - overview of Linux kernel Serial Peripheral Interface (SPI) support. -spinlocks.txt - - info on using spinlocks to provide exclusive access in kernel. stable_api_nonsense.txt - info on why the kernel does not have a stable in-kernel api or abi. stable_kernel_rules.txt @@ -483,10 +475,10 @@ wimax/ - directory with info about Intel Wireless Wimax Connections workqueue.txt - information on the Concurrency Managed Workqueue implementation -ww-mutex-design.txt - - Intro to Mutex wait/would deadlock handling.s x86/x86_64/ - directory with info on Linux support for AMD x86-64 (Hammer) machines. +xillybus.txt + - Overview and basic ui of xillybus driver xtensa/ - directory with documents relating to arch/xtensa port/implementation xz.txt diff --git a/Documentation/ABI/stable/sysfs-class-tpm b/Documentation/ABI/stable/sysfs-class-tpm index a60b45e2493b..9f790eebb5d2 100644 --- a/Documentation/ABI/stable/sysfs-class-tpm +++ b/Documentation/ABI/stable/sysfs-class-tpm @@ -1,4 +1,4 @@ -What: /sys/class/misc/tpmX/device/ +What: /sys/class/tpm/tpmX/device/ Date: April 2005 KernelVersion: 2.6.12 Contact: tpmdd-devel@lists.sf.net @@ -6,7 +6,7 @@ Description: The device/ directory under a specific TPM instance exposes the properties of that TPM chip -What: /sys/class/misc/tpmX/device/active +What: /sys/class/tpm/tpmX/device/active Date: April 2006 KernelVersion: 2.6.17 Contact: tpmdd-devel@lists.sf.net @@ -18,7 +18,7 @@ Description: The "active" property prints a '1' if the TPM chip is accepting section 17 for more information on which commands are available. -What: /sys/class/misc/tpmX/device/cancel +What: /sys/class/tpm/tpmX/device/cancel Date: June 2005 KernelVersion: 2.6.13 Contact: tpmdd-devel@lists.sf.net @@ -26,7 +26,7 @@ Description: The "cancel" property allows you to cancel the currently pending TPM command. Writing any value to cancel will call the TPM vendor specific cancel operation. -What: /sys/class/misc/tpmX/device/caps +What: /sys/class/tpm/tpmX/device/caps Date: April 2005 KernelVersion: 2.6.12 Contact: tpmdd-devel@lists.sf.net @@ -43,7 +43,7 @@ Description: The "caps" property contains TPM manufacturer and version info. the chip supports. Firmware version is that of the chip and is manufacturer specific. -What: /sys/class/misc/tpmX/device/durations +What: /sys/class/tpm/tpmX/device/durations Date: March 2011 KernelVersion: 3.1 Contact: tpmdd-devel@lists.sf.net @@ -66,7 +66,7 @@ Description: The "durations" property shows the 3 vendor-specific values scaled to be displayed in usecs. In this case "[adjusted]" will be displayed in place of "[original]". -What: /sys/class/misc/tpmX/device/enabled +What: /sys/class/tpm/tpmX/device/enabled Date: April 2006 KernelVersion: 2.6.17 Contact: tpmdd-devel@lists.sf.net @@ -75,7 +75,7 @@ Description: The "enabled" property prints a '1' if the TPM chip is enabled, may be visible but produce a '0' after some operation that disables the TPM. -What: /sys/class/misc/tpmX/device/owned +What: /sys/class/tpm/tpmX/device/owned Date: April 2006 KernelVersion: 2.6.17 Contact: tpmdd-devel@lists.sf.net @@ -83,7 +83,7 @@ Description: The "owned" property produces a '1' if the TPM_TakeOwnership ordinal has been executed successfully in the chip. A '0' indicates that ownership hasn't been taken. -What: /sys/class/misc/tpmX/device/pcrs +What: /sys/class/tpm/tpmX/device/pcrs Date: April 2005 KernelVersion: 2.6.12 Contact: tpmdd-devel@lists.sf.net @@ -106,7 +106,7 @@ Description: The "pcrs" property will dump the current value of all Platform 1.2 chips, PCRs represent SHA-1 hashes, which are 20 bytes long. Use the "caps" property to determine TPM version. -What: /sys/class/misc/tpmX/device/pubek +What: /sys/class/tpm/tpmX/device/pubek Date: April 2005 KernelVersion: 2.6.12 Contact: tpmdd-devel@lists.sf.net @@ -158,7 +158,7 @@ Description: The "pubek" property will return the TPM's public endorsement Modulus Length: 256 (bytes) Modulus: The 256 byte Endorsement Key modulus -What: /sys/class/misc/tpmX/device/temp_deactivated +What: /sys/class/tpm/tpmX/device/temp_deactivated Date: April 2006 KernelVersion: 2.6.17 Contact: tpmdd-devel@lists.sf.net @@ -167,7 +167,7 @@ Description: The "temp_deactivated" property returns a '1' if the chip has cycle. Whether a warm boot (reboot) will clear a TPM chip from a temp_deactivated state is platform specific. -What: /sys/class/misc/tpmX/device/timeouts +What: /sys/class/tpm/tpmX/device/timeouts Date: March 2011 KernelVersion: 3.1 Contact: tpmdd-devel@lists.sf.net diff --git a/Documentation/ABI/testing/sysfs-bus-amba b/Documentation/ABI/testing/sysfs-bus-amba new file mode 100644 index 000000000000..e7b54677cfbe --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-amba @@ -0,0 +1,20 @@ +What: /sys/bus/amba/devices/.../driver_override +Date: September 2014 +Contact: Antonios Motakis +Description: + This file allows the driver for a device to be specified which + will override standard OF, ACPI, ID table, and name matching. + When specified, only a driver with a name matching the value + written to driver_override will have an opportunity to bind to + the device. The override is specified by writing a string to the + driver_override file (echo vfio-amba > driver_override) and may + be cleared with an empty string (echo > driver_override). + This returns the device to standard matching rules binding. + Writing to driver_override does not automatically unbind the + device from its current driver or make any attempt to + automatically load the specified driver. If no driver with a + matching name is currently loaded in the kernel, the device will + not bind to any driver. This also allows devices to opt-out of + driver binding using a driver_override name such as "none". + Only a single driver may be specified in the override, there is + no support for parsing delimiters. diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-events b/Documentation/ABI/testing/sysfs-bus-event_source-devices-events index 20979f8b3edb..505f080d20a1 100644 --- a/Documentation/ABI/testing/sysfs-bus-event_source-devices-events +++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-events @@ -52,12 +52,18 @@ Description: Per-pmu performance monitoring events specific to the running syste event=0x2abc event=0x423,inv,cmask=0x3 domain=0x1,offset=0x8,starting_index=0xffff + domain=0x1,offset=0x8,core=? Each of the assignments indicates a value to be assigned to a particular set of bits (as defined by the format file corresponding to the ) in the perf_event structure passed to the perf_open syscall. + In the case of the last example, a value replacing "?" would + need to be provided by the user selecting the particular event. + This is referred to as "event parameterization". Event + parameters have the format 'param=?'. + What: /sys/bus/event_source/devices//events/.unit Date: 2014/02/24 Contact: Linux kernel mailing list diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7 b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7 index 32f3f5f8bba2..f893337570c1 100644 --- a/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7 +++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-hv_24x7 @@ -21,3 +21,25 @@ Contact: Linux on PowerPC Developer List Description: Exposes the "version" field of the 24x7 catalog. This is also extractable from the provided binary "catalog" sysfs entry. + +What: /sys/bus/event_source/devices/hv_24x7/event_descs/ +Date: February 2014 +Contact: Linux on PowerPC Developer List +Description: + Provides the description of a particular event as provided by + the firmware. If firmware does not provide a description, no + file will be created. + + Note that the event-name lacks the domain suffix appended for + events in the events/ dir. + +What: /sys/bus/event_source/devices/hv_24x7/event_long_descs/ +Date: February 2014 +Contact: Linux on PowerPC Developer List +Description: + Provides the "long" description of a particular event as + provided by the firmware. If firmware does not provide a + description, no file will be created. + + Note that the event-name lacks the domain suffix appended for + events in the events/ dir. diff --git a/Documentation/ABI/testing/sysfs-class-cxl b/Documentation/ABI/testing/sysfs-class-cxl index 554405ec1955..3680364b4048 100644 --- a/Documentation/ABI/testing/sysfs-class-cxl +++ b/Documentation/ABI/testing/sysfs-class-cxl @@ -1,3 +1,9 @@ +Note: Attributes that are shared between devices are stored in the directory +pointed to by the symlink device/. +Example: The real path of the attribute /sys/class/cxl/afu0.0s/irqs_max is +/sys/class/cxl/afu0.0s/device/irqs_max, i.e. /sys/class/cxl/afu0.0/irqs_max. + + Slave contexts (eg. /sys/class/cxl/afu0.0s): What: /sys/class/cxl//irqs_max @@ -67,7 +73,7 @@ Contact: linuxppc-dev@lists.ozlabs.org Description: read only Decimal value of the current version of the kernel/user API. -What: /sys/class/cxl//api_version_com +What: /sys/class/cxl//api_version_compatible Date: September 2014 Contact: linuxppc-dev@lists.ozlabs.org Description: read only @@ -75,6 +81,42 @@ Description: read only this this kernel supports. +AFU configuration records (eg. /sys/class/cxl/afu0.0/cr0): + +An AFU may optionally export one or more PCIe like configuration records, known +as AFU configuration records, which will show up here (if present). + +What: /sys/class/cxl//cr/vendor +Date: February 2015 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read only + Hexadecimal value of the vendor ID found in this AFU + configuration record. + +What: /sys/class/cxl//cr/device +Date: February 2015 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read only + Hexadecimal value of the device ID found in this AFU + configuration record. + +What: /sys/class/cxl//cr/vendor +Date: February 2015 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read only + Hexadecimal value of the class code found in this AFU + configuration record. + +What: /sys/class/cxl//cr/config +Date: February 2015 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read only + This binary file provides raw access to the AFU configuration + record. The format is expected to match the either the standard + or extended configuration space defined by the PCIe + specification. + + Master contexts (eg. /sys/class/cxl/afu0.0m) @@ -106,7 +148,7 @@ Contact: linuxppc-dev@lists.ozlabs.org Description: read only Identifies the CAIA Version the card implements. -What: /sys/class/cxl//psl_version +What: /sys/class/cxl//psl_revision Date: September 2014 Contact: linuxppc-dev@lists.ozlabs.org Description: read only @@ -127,3 +169,24 @@ Contact: linuxppc-dev@lists.ozlabs.org Description: read only Will return "user" or "factory" depending on the image loaded onto the card. + +What: /sys/class/cxl//load_image_on_perst +Date: December 2014 +Contact: linuxppc-dev@lists.ozlabs.org +Description: read/write + Valid entries are "none", "user", and "factory". + "none" means PERST will not cause image to be loaded to the + card. A power cycle is required to load the image. + "none" could be useful for debugging because the trace arrays + are preserved. + "user" and "factory" means PERST will cause either the user or + user or factory image to be loaded. + Default is to reload on PERST whichever image the card has + loaded. + +What: /sys/class/cxl//reset +Date: October 2014 +Contact: linuxppc-dev@lists.ozlabs.org +Description: write only + Writing 1 will issue a PERST to card which may cause the card + to reload the FPGA depending on load_image_on_perst. diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power index 909e7602c717..369d2a2d7d3e 100644 --- a/Documentation/ABI/testing/sysfs-class-power +++ b/Documentation/ABI/testing/sysfs-class-power @@ -32,3 +32,45 @@ Description: Valid values: - 5, 6 or 7 (hours), - 0: disabled. + +What: /sys/class/power_supply/max77693-charger/device/fast_charge_timer +Date: January 2015 +KernelVersion: 3.19.0 +Contact: Krzysztof Kozlowski +Description: + This entry shows and sets the maximum time the max77693 + charger operates in fast-charge mode. When the timer expires + the device will terminate fast-charge mode (charging current + will drop to 0 A) and will trigger interrupt. + + Valid values: + - 4 - 16 (hours), step by 2 (rounded down) + - 0: disabled. + +What: /sys/class/power_supply/max77693-charger/device/top_off_threshold_current +Date: January 2015 +KernelVersion: 3.19.0 +Contact: Krzysztof Kozlowski +Description: + This entry shows and sets the charging current threshold for + entering top-off charging mode. When charging current in fast + charge mode drops below this value, the charger will trigger + interrupt and start top-off charging mode. + + Valid values: + - 100000 - 200000 (microamps), step by 25000 (rounded down) + - 200000 - 350000 (microamps), step by 50000 (rounded down) + - 0: disabled. + +What: /sys/class/power_supply/max77693-charger/device/top_off_timer +Date: January 2015 +KernelVersion: 3.19.0 +Contact: Krzysztof Kozlowski +Description: + This entry shows and sets the maximum time the max77693 + charger operates in top-off charge mode. When the timer expires + the device will terminate top-off charge mode (charging current + will drop to 0 A) and will trigger interrupt. + + Valid values: + - 0 - 70 (minutes), step by 10 (rounded down) diff --git a/Documentation/ABI/testing/sysfs-driver-input-axp-pek b/Documentation/ABI/testing/sysfs-driver-input-axp-pek new file mode 100644 index 000000000000..a5e671b9fa79 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-input-axp-pek @@ -0,0 +1,11 @@ +What: /sys/class/input/input(x)/device/startup +Date: March 2014 +Contact: Carlo Caione +Description: Startup time in us. Board is powered on if the button is pressed + for more than + +What: /sys/class/input/input(x)/device/shutdown +Date: March 2014 +Contact: Carlo Caione +Description: Shutdown time in us. Board is powered off if the button is pressed + for more than diff --git a/Documentation/ABI/testing/sysfs-kernel-livepatch b/Documentation/ABI/testing/sysfs-kernel-livepatch new file mode 100644 index 000000000000..5bf42a840b22 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-kernel-livepatch @@ -0,0 +1,44 @@ +What: /sys/kernel/livepatch +Date: Nov 2014 +KernelVersion: 3.19.0 +Contact: live-patching@vger.kernel.org +Description: + Interface for kernel live patching + + The /sys/kernel/livepatch directory contains subdirectories for + each loaded live patch module. + +What: /sys/kernel/livepatch/ +Date: Nov 2014 +KernelVersion: 3.19.0 +Contact: live-patching@vger.kernel.org +Description: + The patch directory contains subdirectories for each kernel + object (vmlinux or a module) in which it patched functions. + +What: /sys/kernel/livepatch//enabled +Date: Nov 2014 +KernelVersion: 3.19.0 +Contact: live-patching@vger.kernel.org +Description: + A writable attribute that indicates whether the patched + code is currently applied. Writing 0 will disable the patch + while writing 1 will re-enable the patch. + +What: /sys/kernel/livepatch// +Date: Nov 2014 +KernelVersion: 3.19.0 +Contact: live-patching@vger.kernel.org +Description: + The object directory contains subdirectories for each function + that is patched within the object. + +What: /sys/kernel/livepatch/// +Date: Nov 2014 +KernelVersion: 3.19.0 +Contact: live-patching@vger.kernel.org +Description: + The function directory contains attributes regarding the + properties and state of the patched function. + + There are currently no such attributes. diff --git a/Documentation/ABI/testing/sysfs-platform-dell-laptop b/Documentation/ABI/testing/sysfs-platform-dell-laptop deleted file mode 100644 index 7969443ef0ef..000000000000 --- a/Documentation/ABI/testing/sysfs-platform-dell-laptop +++ /dev/null @@ -1,60 +0,0 @@ -What: /sys/class/leds/dell::kbd_backlight/als_setting -Date: December 2014 -KernelVersion: 3.19 -Contact: Gabriele Mazzotta , - Pali Rohár -Description: - This file allows to control the automatic keyboard - illumination mode on some systems that have an ambient - light sensor. Write 1 to this file to enable the auto - mode, 0 to disable it. - -What: /sys/class/leds/dell::kbd_backlight/start_triggers -Date: December 2014 -KernelVersion: 3.19 -Contact: Gabriele Mazzotta , - Pali Rohár -Description: - This file allows to control the input triggers that - turn on the keyboard backlight illumination that is - disabled because of inactivity. - Read the file to see the triggers available. The ones - enabled are preceded by '+', those disabled by '-'. - - To enable a trigger, write its name preceded by '+' to - this file. To disable a trigger, write its name preceded - by '-' instead. - - For example, to enable the keyboard as trigger run: - echo +keyboard > /sys/class/leds/dell::kbd_backlight/start_triggers - To disable it: - echo -keyboard > /sys/class/leds/dell::kbd_backlight/start_triggers - - Note that not all the available triggers can be configured. - -What: /sys/class/leds/dell::kbd_backlight/stop_timeout -Date: December 2014 -KernelVersion: 3.19 -Contact: Gabriele Mazzotta , - Pali Rohár -Description: - This file allows to specify the interval after which the - keyboard illumination is disabled because of inactivity. - The timeouts are expressed in seconds, minutes, hours and - days, for which the symbols are 's', 'm', 'h' and 'd' - respectively. - - To configure the timeout, write to this file a value along - with any the above units. If no unit is specified, the value - is assumed to be expressed in seconds. - - For example, to set the timeout to 10 minutes run: - echo 10m > /sys/class/leds/dell::kbd_backlight/stop_timeout - - Note that when this file is read, the returned value might be - expressed in a different unit than the one used when the timeout - was set. - - Also note that only some timeouts are supported and that - some systems might fall back to a specific timeout in case - an invalid timeout is written to this file. diff --git a/Documentation/Changes b/Documentation/Changes index 74bdda9272a4..646cdaa6e9d1 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -21,8 +21,8 @@ running a Linux kernel. Also, not all tools are necessary on all systems; obviously, if you don't have any ISDN hardware, for example, you probably needn't concern yourself with isdn4k-utils. -o Gnu C 3.2 # gcc --version -o Gnu make 3.80 # make --version +o GNU C 3.2 # gcc --version +o GNU make 3.80 # make --version o binutils 2.12 # ld -v o util-linux 2.10o # fdformat --version o module-init-tools 0.9.10 # depmod -V @@ -57,7 +57,7 @@ computer. Make ---- -You will need Gnu make 3.80 or later to build the kernel. +You will need GNU make 3.80 or later to build the kernel. Binutils -------- diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index 618a33c940df..449a8a19fc21 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -527,6 +527,7 @@ values. To do the latter, you can stick the following in your .emacs file: (string-match (expand-file-name "~/src/linux-trees") filename)) (setq indent-tabs-mode t) + (setq show-trailing-whitespace t) (c-set-style "linux-tabs-only"))))) This will make emacs go better with the kernel coding style for C diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl index d9b9416c989f..aac9357d4866 100644 --- a/Documentation/DocBook/80211.tmpl +++ b/Documentation/DocBook/80211.tmpl @@ -113,7 +113,6 @@ !Finclude/net/cfg80211.h cfg80211_beacon_data !Finclude/net/cfg80211.h cfg80211_ap_settings !Finclude/net/cfg80211.h station_parameters -!Finclude/net/cfg80211.h station_info_flags !Finclude/net/cfg80211.h rate_info_flags !Finclude/net/cfg80211.h rate_info !Finclude/net/cfg80211.h station_info @@ -435,7 +434,6 @@
support for powersaving clients !Pinclude/net/mac80211.h AP support for powersaving clients -
!Finclude/net/mac80211.h ieee80211_get_buffered_bc !Finclude/net/mac80211.h ieee80211_beacon_get !Finclude/net/mac80211.h ieee80211_sta_eosp @@ -444,6 +442,7 @@ !Finclude/net/mac80211.h ieee80211_sta_ps_transition_ni !Finclude/net/mac80211.h ieee80211_sta_set_buffered !Finclude/net/mac80211.h ieee80211_sta_block_awake + @@ -488,8 +487,8 @@ RX A-MPDU aggregation !Pnet/mac80211/agg-rx.c RX A-MPDU aggregation !Cnet/mac80211/agg-rx.c - !Finclude/net/mac80211.h ieee80211_ampdu_mlme_action + diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 9c7d92d03f62..b6a6a2e0dd3b 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -56,7 +56,7 @@ htmldocs: $(HTML) MAN := $(patsubst %.xml, %.9, $(BOOKS)) mandocs: $(MAN) - $(if $(wildcard $(obj)/man/*.9),gzip -f $(obj)/man/*.9) + find $(obj)/man -name '*.9' | xargs gzip -f installmandocs: mandocs mkdir -p /usr/local/man/man9/ diff --git a/Documentation/DocBook/crypto-API.tmpl b/Documentation/DocBook/crypto-API.tmpl index c763d30f4893..04a8c24ead47 100644 --- a/Documentation/DocBook/crypto-API.tmpl +++ b/Documentation/DocBook/crypto-API.tmpl @@ -111,7 +111,7 @@ This specification is intended for consumers of the kernel crypto API as well as for developers implementing ciphers. This API - specification, however, does not discusses all API calls available + specification, however, does not discuss all API calls available to data transformation implementations (i.e. implementations of ciphers and other transformations (such as CRC or even compression algorithms) that can register with the kernel crypto API). diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl index f77358f96930..2428cc04dbc8 100644 --- a/Documentation/DocBook/kgdb.tmpl +++ b/Documentation/DocBook/kgdb.tmpl @@ -75,7 +75,7 @@ a development machine and the other is the target machine. The kernel to be debugged runs on the target machine. The development machine runs an instance of gdb against the vmlinux file which - contains the symbols (not boot image such as bzImage, zImage, + contains the symbols (not a boot image such as bzImage, zImage, uImage...). In gdb the developer specifies the connection parameters and connects to kgdb. The type of connection a developer makes with gdb depends on the availability of kgdb I/O @@ -95,7 +95,7 @@ Kernel config options for kgdb To enable CONFIG_KGDB you should look under - "Kernel debugging" and select "KGDB: kernel debugger". + "Kernel hacking" / "Kernel debugging" and select "KGDB: kernel debugger". While it is not a hard requirement that you have symbols in your @@ -105,7 +105,7 @@ kernel with debug info" in the config menu. - It is advised, but not required that you turn on the + It is advised, but not required, that you turn on the CONFIG_FRAME_POINTER kernel option which is called "Compile the kernel with frame pointers" in the config menu. This option inserts code to into the compiled executable which saves the frame @@ -181,7 +181,7 @@ This section describes the various runtime kernel parameters that affect the configuration of the kernel debugger. The following chapter covers using kdb and kgdb as well as - provides some examples of the configuration parameters. + providing some examples of the configuration parameters. Kernel parameter: kgdboc The kgdboc driver was originally an abbreviation meant to @@ -219,8 +219,8 @@ kbd = Keyboard - You can configure kgdboc to use the keyboard, and or a serial - device depending on if you are using kdb and or kgdb, in one of the + You can configure kgdboc to use the keyboard, and/or a serial + device depending on if you are using kdb and/or kgdb, in one of the following scenarios. The order listed above must be observed if you use any of the optional configurations together. Using kms + only gdb is generally not a useful combination. @@ -261,11 +261,8 @@ More examples - You can configure kgdboc to use the keyboard, and or a serial - device depending on if you are using kdb and or kgdb, in one of the - following scenarios. - You can configure kgdboc to use the keyboard, and or a serial device - depending on if you are using kdb and or kgdb, in one of the + You can configure kgdboc to use the keyboard, and/or a serial device + depending on if you are using kdb and/or kgdb, in one of the following scenarios. kdb and kgdb over only a serial port @@ -315,7 +312,7 @@ The Kernel command line option kgdbwait makes kgdb wait for a debugger connection during booting of a kernel. You - can only use this option you compiled a kgdb I/O driver into the + can only use this option if you compiled a kgdb I/O driver into the kernel and you specified the I/O driver configuration as a kernel command line option. The kgdbwait parameter should always follow the configuration parameter for the kgdb I/O driver in the kernel @@ -354,7 +351,7 @@ IMPORTANT NOTE: You cannot use kgdboc + kgdbcon on a tty that is an - active system console. An example incorrect usage is console=ttyS0,115200 kgdboc=ttyS0 kgdbcon + active system console. An example of incorrect usage is console=ttyS0,115200 kgdboc=ttyS0 kgdbcon It is possible to use this option with kgdboc on a tty that is not a system console. @@ -386,12 +383,12 @@ Quick start for kdb on a serial port This is a quick example of how to use kdb. - Boot kernel with arguments: + Configure kgdboc at boot using kernel parameters: console=ttyS0,115200 kgdboc=ttyS0,115200 OR - Configure kgdboc after the kernel booted; assuming you are using a serial port console: + Configure kgdboc after the kernel has booted; assuming you are using a serial port console: echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc @@ -442,12 +439,12 @@ Quick start for kdb using a keyboard connected console This is a quick example of how to use kdb with a keyboard. - Boot kernel with arguments: + Configure kgdboc at boot using kernel parameters: kgdboc=kbd OR - Configure kgdboc after the kernel booted: + Configure kgdboc after the kernel has booted: echo kbd > /sys/module/kgdboc/parameters/kgdboc @@ -501,12 +498,12 @@ Connecting with gdb to a serial port Configure kgdboc - Boot kernel with arguments: + Configure kgdboc at boot using kernel parameters: kgdboc=ttyS0,115200 OR - Configure kgdboc after the kernel booted: + Configure kgdboc after the kernel has booted: echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc @@ -536,7 +533,7 @@ - Connect from from gdb + Connect from gdb Example (using a directly connected port): @@ -584,7 +581,7 @@ There are two ways to switch from kgdb to kdb: you can use gdb to issue a maintenance packet, or you can blindly type the command $3#33. - Whenever kernel debugger stops in kgdb mode it will print the + Whenever the kernel debugger stops in kgdb mode it will print the message KGDB or $3#33 for KDB. It is important to note that you have to type the sequence correctly in one pass. You cannot type a backspace or delete because kgdb will interpret @@ -704,7 +701,7 @@ Task Addr Pid Parent [*] cpu State Thread Command Registration and unregistration of architecture specific trap hooks Any special exception handling and cleanup NMI exception handling and cleanup - (optional)HW breakpoints + (optional) HW breakpoints @@ -760,7 +757,7 @@ Task Addr Pid Parent [*] cpu State Thread Command a kgdb I/O driver for characters when it needs input. The I/O driver is expected to return immediately if there is no data available. Doing so allows for the future possibility to touch - watch dog hardware in such a way as to have a target system not + watchdog hardware in such a way as to have a target system not reset when these are enabled. @@ -779,21 +776,25 @@ Task Addr Pid Parent [*] cpu State Thread Command their <asm/kgdb.h> file. These are: - - NUMREGBYTES: The size in bytes of all of the registers, so - that we can ensure they will all fit into a packet. - - - BUFMAX: The size in bytes of the buffer GDB will read into. - This must be larger than NUMREGBYTES. - - - CACHE_FLUSH_IS_SAFE: Set to 1 if it is always safe to call - flush_cache_range or flush_icache_range. On some architectures, - these functions may not be safe to call on SMP since we keep other - CPUs in a holding pattern. - - + + NUMREGBYTES: The size in bytes of all of the registers, so + that we can ensure they will all fit into a packet. + + + + + BUFMAX: The size in bytes of the buffer GDB will read into. + This must be larger than NUMREGBYTES. + + + + + CACHE_FLUSH_IS_SAFE: Set to 1 if it is always safe to call + flush_cache_range or flush_icache_range. On some architectures, + these functions may not be safe to call on SMP since we keep other + CPUs in a holding pattern. + + @@ -812,8 +813,8 @@ Task Addr Pid Parent [*] cpu State Thread Command The kgdboc driver is actually a very thin driver that relies on the underlying low level to the hardware driver having "polling hooks" - which the to which the tty driver is attached. In the initial - implementation of kgdboc it the serial_core was changed to expose a + to which the tty driver is attached. In the initial + implementation of kgdboc the serial_core was changed to expose a low level UART hook for doing polled mode reading and writing of a single character while in an atomic context. When kgdb makes an I/O request to the debugger, kgdboc invokes a callback in the serial diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index e013e4bf244c..4e9462f1ab4c 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -2692,12 +2692,11 @@ in the S5P family of SoCs by Samsung. V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE  - integer - If the display delay is enabled then the decoder has to return a -CAPTURE buffer after processing a certain number of OUTPUT buffers. If this number is low, then it may result in -buffers not being dequeued in display order. In addition hardware may still use those buffers as reference, thus -application should not write to those buffers. This feature can be used for example for generating thumbnails of videos. -Applicable to the H264 decoder. + boolean + If the display delay is enabled then the decoder is forced to return a +CAPTURE buffer (decoded frame) after processing a certain number of OUTPUT buffers. The delay can be set through +V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY. This feature can be used for example +for generating thumbnails of videos. Applicable to the H264 decoder. diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml index c1c62a9acc2a..f34d03ebda3a 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml @@ -17,7 +17,7 @@ Description - The following four pixel formats are raw sRGB / Bayer formats with + These four pixel formats are raw sRGB / Bayer formats with 10 bits per colour. Each colour component is stored in a 16-bit word, with 6 unused high bits filled with zeros. Each n-pixel row contains n/2 green samples and n/2 blue or red samples, with alternating red and blue rows. Bytes are diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml index 29acc2098cc2..d2e5845e57fb 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10alaw8.xml @@ -25,7 +25,7 @@ Description - The following four pixel formats are raw sRGB / Bayer + These four pixel formats are raw sRGB / Bayer formats with 10 bits per color compressed to 8 bits each, using the A-LAW algorithm. Each color component consumes 8 bits of memory. In other respects this format is similar to diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml index 2d3f0b1aefe0..bde89878c5c5 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml @@ -18,7 +18,7 @@ Description - The following four pixel formats are raw sRGB / Bayer formats + These four pixel formats are raw sRGB / Bayer formats with 10 bits per colour compressed to 8 bits each, using DPCM compression. DPCM, differential pulse-code modulation, is lossy. Each colour component consumes 8 bits of memory. In other respects diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml new file mode 100644 index 000000000000..30aa63581fe3 --- /dev/null +++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml @@ -0,0 +1,99 @@ + + + V4L2_PIX_FMT_SRGGB10P ('pRAA'), + V4L2_PIX_FMT_SGRBG10P ('pgAA'), + V4L2_PIX_FMT_SGBRG10P ('pGAA'), + V4L2_PIX_FMT_SBGGR10P ('pBAA'), + + &manvol; + + + V4L2_PIX_FMT_SRGGB10P + V4L2_PIX_FMT_SGRBG10P + V4L2_PIX_FMT_SGBRG10P + V4L2_PIX_FMT_SBGGR10P + 10-bit packed Bayer formats + + + Description + + These four pixel formats are packed raw sRGB / + Bayer formats with 10 bits per colour. Every four consecutive + colour components are packed into 5 bytes. Each of the first 4 + bytes contain the 8 high order bits of the pixels, and the + fifth byte contains the two least significants bits of each + pixel, in the same order. + + Each n-pixel row contains n/2 green samples and n/2 blue + or red samples, with alternating green-red and green-blue + rows. They are conventionally described as GRGR... BGBG..., + RGRG... GBGB..., etc. Below is an example of one of these + formats: + + + <constant>V4L2_PIX_FMT_SBGGR10P</constant> 4 × 4 + pixel image + + + Byte Order. + Each cell is one byte. + + + + + + start + 0: + B00high + G01high + B02high + G03high + B00low(bits 7--6) + G01low(bits 5--4) + B02low(bits 3--2) + G03low(bits 1--0) + + + + start + 5: + G10high + R11high + G12high + R13high + G10low(bits 7--6) + R11low(bits 5--4) + G12low(bits 3--2) + R13low(bits 1--0) + + + + start + 10: + B20high + G21high + B22high + G23high + B20low(bits 7--6) + G21low(bits 5--4) + B22low(bits 3--2) + G23low(bits 1--0) + + + + start + 15: + G30high + R31high + G32high + R33high + G30low(bits 7--6) + R31low(bits 5--4) + G32low(bits 3--2) + R33low(bits 1--0) + + + + + + + + + + diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml index 96947f17fca1..0c8e4adf417f 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml @@ -17,7 +17,7 @@ Description - The following four pixel formats are raw sRGB / Bayer formats with + These four pixel formats are raw sRGB / Bayer formats with 12 bits per colour. Each colour component is stored in a 16-bit word, with 4 unused high bits filled with zeros. Each n-pixel row contains n/2 green samples and n/2 blue or red samples, with alternating red and blue rows. Bytes are diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index d5eca4b8f74b..5e0352c50324 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -1405,6 +1405,7 @@ access the palette, this must be done with ioctls of the Linux framebuffer API.< &sub-srggb8; &sub-sbggr16; &sub-srggb10; + &sub-srggb10p; &sub-srggb10alaw8; &sub-srggb10dpcm8; &sub-srggb12; diff --git a/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml b/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml index 28a8c1e1c705..a2017bfcaed2 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml @@ -212,11 +212,3 @@ standards set in the standards field. &return-value; - - diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml index b9fdfeacdbcb..6e3cadd4e1f9 100644 --- a/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml @@ -131,11 +131,3 @@ is out of bounds or the pad number is invalid. - - diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index ed186a902d31..b57c0c1cdac6 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -15,7 +15,7 @@ CONFIG_RCU_CPU_STALL_TIMEOUT 21 seconds. This configuration parameter may be changed at runtime via the - /sys/module/rcutree/parameters/rcu_cpu_stall_timeout, however + /sys/module/rcupdate/parameters/rcu_cpu_stall_timeout, however this parameter is checked only at the beginning of a cycle. So if you are 10 seconds into a 40-second stall, setting this sysfs parameter to (say) five will shorten the timeout for the @@ -152,6 +152,15 @@ no non-lazy callbacks ("." is printed otherwise, as shown above) and "D" indicates that dyntick-idle processing is enabled ("." is printed otherwise, for example, if disabled via the "nohz=" kernel boot parameter). +If the relevant grace-period kthread has been unable to run prior to +the stall warning, the following additional line is printed: + + rcu_preempt kthread starved for 2023 jiffies! + +Starving the grace-period kthreads of CPU time can of course result in +RCU CPU stall warnings even when all CPUs and tasks have passed through +the required quiescent states. + Multiple Warnings From One Stall @@ -187,6 +196,11 @@ o For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the behavior, you might need to replace some of the cond_resched() calls with calls to cond_resched_rcu_qs(). +o Anything that prevents RCU's grace-period kthreads from running. + This can result in the "All QSes seen" console-log message. + This message will include information on when the kthread last + ran and how often it should be expected to run. + o A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might happen to preempt a low-priority task in the middle of an RCU read-side critical section. This is especially damaging if diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index b63b9bb3bc0c..08651da15448 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -56,14 +56,14 @@ rcuboost: The output of "cat rcu/rcu_preempt/rcudata" looks as follows: - 0!c=30455 g=30456 pq=1 qp=1 dt=126535/140000000000000/0 df=2002 of=4 ql=0/0 qs=N... b=10 ci=74572 nci=0 co=1131 ca=716 - 1!c=30719 g=30720 pq=1 qp=0 dt=132007/140000000000000/0 df=1874 of=10 ql=0/0 qs=N... b=10 ci=123209 nci=0 co=685 ca=982 - 2!c=30150 g=30151 pq=1 qp=1 dt=138537/140000000000000/0 df=1707 of=8 ql=0/0 qs=N... b=10 ci=80132 nci=0 co=1328 ca=1458 - 3 c=31249 g=31250 pq=1 qp=0 dt=107255/140000000000000/0 df=1749 of=6 ql=0/450 qs=NRW. b=10 ci=151700 nci=0 co=509 ca=622 - 4!c=29502 g=29503 pq=1 qp=1 dt=83647/140000000000000/0 df=965 of=5 ql=0/0 qs=N... b=10 ci=65643 nci=0 co=1373 ca=1521 - 5 c=31201 g=31202 pq=1 qp=1 dt=70422/0/0 df=535 of=7 ql=0/0 qs=.... b=10 ci=58500 nci=0 co=764 ca=698 - 6!c=30253 g=30254 pq=1 qp=1 dt=95363/140000000000000/0 df=780 of=5 ql=0/0 qs=N... b=10 ci=100607 nci=0 co=1414 ca=1353 - 7 c=31178 g=31178 pq=1 qp=0 dt=91536/0/0 df=547 of=4 ql=0/0 qs=.... b=10 ci=109819 nci=0 co=1115 ca=969 + 0!c=30455 g=30456 pq=1/0 qp=1 dt=126535/140000000000000/0 df=2002 of=4 ql=0/0 qs=N... b=10 ci=74572 nci=0 co=1131 ca=716 + 1!c=30719 g=30720 pq=1/0 qp=0 dt=132007/140000000000000/0 df=1874 of=10 ql=0/0 qs=N... b=10 ci=123209 nci=0 co=685 ca=982 + 2!c=30150 g=30151 pq=1/1 qp=1 dt=138537/140000000000000/0 df=1707 of=8 ql=0/0 qs=N... b=10 ci=80132 nci=0 co=1328 ca=1458 + 3 c=31249 g=31250 pq=1/1 qp=0 dt=107255/140000000000000/0 df=1749 of=6 ql=0/450 qs=NRW. b=10 ci=151700 nci=0 co=509 ca=622 + 4!c=29502 g=29503 pq=1/0 qp=1 dt=83647/140000000000000/0 df=965 of=5 ql=0/0 qs=N... b=10 ci=65643 nci=0 co=1373 ca=1521 + 5 c=31201 g=31202 pq=1/0 qp=1 dt=70422/0/0 df=535 of=7 ql=0/0 qs=.... b=10 ci=58500 nci=0 co=764 ca=698 + 6!c=30253 g=30254 pq=1/0 qp=1 dt=95363/140000000000000/0 df=780 of=5 ql=0/0 qs=N... b=10 ci=100607 nci=0 co=1414 ca=1353 + 7 c=31178 g=31178 pq=1/0 qp=0 dt=91536/0/0 df=547 of=4 ql=0/0 qs=.... b=10 ci=109819 nci=0 co=1115 ca=969 This file has one line per CPU, or eight for this 8-CPU system. The fields are as follows: @@ -188,14 +188,14 @@ o "ca" is the number of RCU callbacks that have been adopted by this Kernels compiled with CONFIG_RCU_BOOST=y display the following from /debug/rcu/rcu_preempt/rcudata: - 0!c=12865 g=12866 pq=1 qp=1 dt=83113/140000000000000/0 df=288 of=11 ql=0/0 qs=N... kt=0/O ktl=944 b=10 ci=60709 nci=0 co=748 ca=871 - 1 c=14407 g=14408 pq=1 qp=0 dt=100679/140000000000000/0 df=378 of=7 ql=0/119 qs=NRW. kt=0/W ktl=9b6 b=10 ci=109740 nci=0 co=589 ca=485 - 2 c=14407 g=14408 pq=1 qp=0 dt=105486/0/0 df=90 of=9 ql=0/89 qs=NRW. kt=0/W ktl=c0c b=10 ci=83113 nci=0 co=533 ca=490 - 3 c=14407 g=14408 pq=1 qp=0 dt=107138/0/0 df=142 of=8 ql=0/188 qs=NRW. kt=0/W ktl=b96 b=10 ci=121114 nci=0 co=426 ca=290 - 4 c=14405 g=14406 pq=1 qp=1 dt=50238/0/0 df=706 of=7 ql=0/0 qs=.... kt=0/W ktl=812 b=10 ci=34929 nci=0 co=643 ca=114 - 5!c=14168 g=14169 pq=1 qp=0 dt=45465/140000000000000/0 df=161 of=11 ql=0/0 qs=N... kt=0/O ktl=b4d b=10 ci=47712 nci=0 co=677 ca=722 - 6 c=14404 g=14405 pq=1 qp=0 dt=59454/0/0 df=94 of=6 ql=0/0 qs=.... kt=0/W ktl=e57 b=10 ci=55597 nci=0 co=701 ca=811 - 7 c=14407 g=14408 pq=1 qp=1 dt=68850/0/0 df=31 of=8 ql=0/0 qs=.... kt=0/W ktl=14bd b=10 ci=77475 nci=0 co=508 ca=1042 + 0!c=12865 g=12866 pq=1/0 qp=1 dt=83113/140000000000000/0 df=288 of=11 ql=0/0 qs=N... kt=0/O ktl=944 b=10 ci=60709 nci=0 co=748 ca=871 + 1 c=14407 g=14408 pq=1/0 qp=0 dt=100679/140000000000000/0 df=378 of=7 ql=0/119 qs=NRW. kt=0/W ktl=9b6 b=10 ci=109740 nci=0 co=589 ca=485 + 2 c=14407 g=14408 pq=1/0 qp=0 dt=105486/0/0 df=90 of=9 ql=0/89 qs=NRW. kt=0/W ktl=c0c b=10 ci=83113 nci=0 co=533 ca=490 + 3 c=14407 g=14408 pq=1/0 qp=0 dt=107138/0/0 df=142 of=8 ql=0/188 qs=NRW. kt=0/W ktl=b96 b=10 ci=121114 nci=0 co=426 ca=290 + 4 c=14405 g=14406 pq=1/0 qp=1 dt=50238/0/0 df=706 of=7 ql=0/0 qs=.... kt=0/W ktl=812 b=10 ci=34929 nci=0 co=643 ca=114 + 5!c=14168 g=14169 pq=1/0 qp=0 dt=45465/140000000000000/0 df=161 of=11 ql=0/0 qs=N... kt=0/O ktl=b4d b=10 ci=47712 nci=0 co=677 ca=722 + 6 c=14404 g=14405 pq=1/0 qp=0 dt=59454/0/0 df=94 of=6 ql=0/0 qs=.... kt=0/W ktl=e57 b=10 ci=55597 nci=0 co=701 ca=811 + 7 c=14407 g=14408 pq=1/0 qp=1 dt=68850/0/0 df=31 of=8 ql=0/0 qs=.... kt=0/W ktl=14bd b=10 ci=77475 nci=0 co=508 ca=1042 This is similar to the output discussed above, but contains the following additional fields: diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 1fa1caa198eb..447671bd2927 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -10,27 +10,49 @@ kernel, the process can sometimes be daunting if you're not familiar with "the system." This text is a collection of suggestions which can greatly increase the chances of your change being accepted. -Read Documentation/SubmitChecklist for a list of items to check -before submitting code. If you are submitting a driver, also read -Documentation/SubmittingDrivers. +This document contains a large number of suggestions in a relatively terse +format. For detailed information on how the kernel development process +works, see Documentation/development-process. Also, read +Documentation/SubmitChecklist for a list of items to check before +submitting code. If you are submitting a driver, also read +Documentation/SubmittingDrivers; for device tree binding patches, read +Documentation/devicetree/bindings/submitting-patches.txt. Many of these steps describe the default behavior of the git version control system; if you use git to prepare your patches, you'll find much of the mechanical work done for you, though you'll still need to prepare -and document a sensible set of patches. +and document a sensible set of patches. In general, use of git will make +your life as a kernel developer easier. -------------------------------------------- SECTION 1 - CREATING AND SENDING YOUR CHANGE -------------------------------------------- +0) Obtain a current source tree +------------------------------- + +If you do not have a repository with the current kernel source handy, use +git to obtain one. You'll want to start with the mainline repository, +which can be grabbed with: + + git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git + +Note, however, that you may not want to develop against the mainline tree +directly. Most subsystem maintainers run their own trees and want to see +patches prepared against those trees. See the "T:" entry for the subsystem +in the MAINTAINERS file to find that tree, or simply ask the maintainer if +the tree is not listed there. + +It is still possible to download kernel releases via tarballs (as described +in the next section), but that is the hard way to do kernel development. 1) "diff -up" ------------ -Use "diff -up" or "diff -uprN" to create patches. git generates patches -in this form by default; if you're using git, you can skip this section -entirely. +If you must generate your patches by hand, use "diff -up" or "diff -uprN" +to create patches. Git generates patches in this form by default; if +you're using git, you can skip this section entirely. All changes to the Linux kernel occur in the form of patches, as generated by diff(1). When creating your patch, make sure to create it @@ -42,7 +64,7 @@ not in any lower subdirectory. To create a patch for a single file, it is often sufficient to do: - SRCTREE= linux-2.6 + SRCTREE= linux MYFILE= drivers/net/mydriver.c cd $SRCTREE @@ -55,17 +77,16 @@ To create a patch for multiple files, you should unpack a "vanilla", or unmodified kernel source tree, and generate a diff against your own source tree. For example: - MYSRC= /devel/linux-2.6 + MYSRC= /devel/linux - tar xvfz linux-2.6.12.tar.gz - mv linux-2.6.12 linux-2.6.12-vanilla - diff -uprN -X linux-2.6.12-vanilla/Documentation/dontdiff \ - linux-2.6.12-vanilla $MYSRC > /tmp/patch + tar xvfz linux-3.19.tar.gz + mv linux-3.19 linux-3.19-vanilla + diff -uprN -X linux-3.19-vanilla/Documentation/dontdiff \ + linux-3.19-vanilla $MYSRC > /tmp/patch "dontdiff" is a list of files which are generated by the kernel during the build process, and should be ignored in any diff(1)-generated -patch. The "dontdiff" file is included in the kernel tree in -2.6.12 and later. +patch. Make sure your patch does not include any extra files which do not belong in a patch submission. Make sure to review your patch -after- @@ -83,6 +104,7 @@ is another popular alternative. 2) Describe your changes. +------------------------- Describe your problem. Whether your patch is a one-line bug fix or 5000 lines of a new feature, there must be an underlying problem that @@ -124,10 +146,10 @@ See #3, next. When you submit or resubmit a patch or patch series, include the complete patch description and justification for it. Don't just say that this is version N of the patch (series). Don't expect the -patch merger to refer back to earlier patch versions or referenced +subsystem maintainer to refer back to earlier patch versions or referenced URLs to find the patch description and put that into the patch. I.e., the patch (series) and its description should be self-contained. -This benefits both the patch merger(s) and reviewers. Some reviewers +This benefits both the maintainers and reviewers. Some reviewers probably didn't even receive earlier versions of the patch. Describe your changes in imperative mood, e.g. "make xyzzy do frotz" @@ -156,10 +178,15 @@ Example: platform_set_drvdata(), but left the variable "dev" unused, delete it. +You should also be sure to use at least the first twelve characters of the +SHA-1 ID. The kernel repository holds a *lot* of objects, making +collisions with shorter IDs a real possibility. Bear in mind that, even if +there is no collision with your six-character ID now, that condition may +change five years from now. + If your patch fixes a bug in a specific commit, e.g. you found an issue using git-bisect, please use the 'Fixes:' tag with the first 12 characters of the -SHA-1 ID, and the one line summary. -Example: +SHA-1 ID, and the one line summary. For example: Fixes: e21d2170f366 ("video: remove unnecessary platform_set_drvdata()") @@ -172,8 +199,9 @@ outputting the above style in the git log or git show commands fixes = Fixes: %h (\"%s\") 3) Separate your changes. +------------------------- -Separate _logical changes_ into a single patch file. +Separate each _logical change_ into a separate patch. For example, if your changes include both bug fixes and performance enhancements for a single driver, separate those changes into two @@ -184,90 +212,116 @@ On the other hand, if you make a single change to numerous files, group those changes into a single patch. Thus a single logical change is contained within a single patch. +The point to remember is that each patch should make an easily understood +change that can be verified by reviewers. Each patch should be justifiable +on its own merits. + If one patch depends on another patch in order for a change to be complete, that is OK. Simply note "this patch depends on patch X" in your patch description. +When dividing your change into a series of patches, take special care to +ensure that the kernel builds and runs properly after each patch in the +series. Developers using "git bisect" to track down a problem can end up +splitting your patch series at any point; they will not thank you if you +introduce bugs in the middle. + If you cannot condense your patch set into a smaller set of patches, then only post say 15 or so at a time and wait for review and integration. -4) Style check your changes. +4) Style-check your changes. +---------------------------- Check your patch for basic style violations, details of which can be found in Documentation/CodingStyle. Failure to do so simply wastes the reviewers time and will get your patch rejected, probably without even being read. -At a minimum you should check your patches with the patch style -checker prior to submission (scripts/checkpatch.pl). You should -be able to justify all violations that remain in your patch. +One significant exception is when moving code from one file to +another -- in this case you should not modify the moved code at all in +the same patch which moves it. This clearly delineates the act of +moving the code and your changes. This greatly aids review of the +actual differences and allows tools to better track the history of +the code itself. + +Check your patches with the patch style checker prior to submission +(scripts/checkpatch.pl). Note, though, that the style checker should be +viewed as a guide, not as a replacement for human judgment. If your code +looks better with a violation then its probably best left alone. + +The checker reports at three levels: + - ERROR: things that are very likely to be wrong + - WARNING: things requiring careful review + - CHECK: things requiring thought + +You should be able to justify all violations that remain in your +patch. +5) Select the recipients for your patch. +---------------------------------------- -5) Select e-mail destination. +You should always copy the appropriate subsystem maintainer(s) on any patch +to code that they maintain; look through the MAINTAINERS file and the +source code revision history to see who those maintainers are. The +script scripts/get_maintainer.pl can be very useful at this step. If you +cannot find a maintainer for the subsystem your are working on, Andrew +Morton (akpm@linux-foundation.org) serves as a maintainer of last resort. -Look through the MAINTAINERS file and the source code, and determine -if your change applies to a specific subsystem of the kernel, with -an assigned maintainer. If so, e-mail that person. The script -scripts/get_maintainer.pl can be very useful at this step. - -If no maintainer is listed, or the maintainer does not respond, send -your patch to the primary Linux kernel developer's mailing list, -linux-kernel@vger.kernel.org. Most kernel developers monitor this -e-mail list, and can comment on your changes. +You should also normally choose at least one mailing list to receive a copy +of your patch set. linux-kernel@vger.kernel.org functions as a list of +last resort, but the volume on that list has caused a number of developers +to tune it out. Look in the MAINTAINERS file for a subsystem-specific +list; your patch will probably get more attention there. Please do not +spam unrelated lists, though. +Many kernel-related lists are hosted on vger.kernel.org; you can find a +list of them at http://vger.kernel.org/vger-lists.html. There are +kernel-related lists hosted elsewhere as well, though. Do not send more than 15 patches at once to the vger mailing lists!!! - Linus Torvalds is the final arbiter of all changes accepted into the -Linux kernel. His e-mail address is . -He gets a lot of e-mail, so typically you should do your best to -avoid- -sending him e-mail. +Linux kernel. His e-mail address is . +He gets a lot of e-mail, and, at this point, very few patches go through +Linus directly, so typically you should do your best to -avoid- +sending him e-mail. -Patches which are bug fixes, are "obvious" changes, or similarly -require little discussion should be sent or CC'd to Linus. Patches -which require discussion or do not have a clear advantage should -usually be sent first to linux-kernel. Only after the patch is -discussed should the patch then be submitted to Linus. +If you have a patch that fixes an exploitable security bug, send that patch +to security@kernel.org. For severe bugs, a short embargo may be considered +to allow distrbutors to get the patch out to users; in such cases, +obviously, the patch should not be sent to any public lists. +Patches that fix a severe bug in a released kernel should be directed +toward the stable maintainers by putting a line like this: + Cc: stable@vger.kernel.org -6) Select your CC (e-mail carbon copy) list. +into your patch. -Unless you have a reason NOT to do so, CC linux-kernel@vger.kernel.org. +Note, however, that some subsystem maintainers want to come to their own +conclusions on which patches should go to the stable trees. The networking +maintainer, in particular, would rather not see individual developers +adding lines like the above to their patches. -Other kernel developers besides Linus need to be aware of your change, -so that they may comment on it and offer code review and suggestions. -linux-kernel is the primary Linux kernel developer mailing list. -Other mailing lists are available for specific subsystems, such as -USB, framebuffer devices, the VFS, the SCSI subsystem, etc. See the -MAINTAINERS file for a mailing list that relates specifically to -your change. - -Majordomo lists of VGER.KERNEL.ORG at: - - -If changes affect userland-kernel interfaces, please send -the MAN-PAGES maintainer (as listed in the MAINTAINERS file) -a man-pages patch, or at least a notification of the change, -so that some information makes its way into the manual pages. - -Even if the maintainer did not respond in step #5, make sure to ALWAYS -copy the maintainer when you change their code. +If changes affect userland-kernel interfaces, please send the MAN-PAGES +maintainer (as listed in the MAINTAINERS file) a man-pages patch, or at +least a notification of the change, so that some information makes its way +into the manual pages. User-space API changes should also be copied to +linux-api@vger.kernel.org. For small patches you may want to CC the Trivial Patch Monkey trivial@kernel.org which collects "trivial" patches. Have a look into the MAINTAINERS file for its current manager. Trivial patches must qualify for one of the following rules: Spelling fixes in documentation - Spelling fixes which could break grep(1) + Spelling fixes for errors which could break grep(1) Warning fixes (cluttering with useless warnings is bad) Compilation fixes (only if they are actually correct) Runtime fixes (only if they actually fix things) - Removing use of deprecated functions/macros (eg. check_region) + Removing use of deprecated functions/macros Contact detail and documentation fixes Non-portable code replaced by portable code (even in arch-specific, since people copy, as long as it's trivial) @@ -276,7 +330,8 @@ Trivial patches must qualify for one of the following rules: -7) No MIME, no links, no compression, no attachments. Just plain text. +6) No MIME, no links, no compression, no attachments. Just plain text. +----------------------------------------------------------------------- Linus and other kernel developers need to be able to read and comment on the changes you are submitting. It is important for a kernel @@ -299,54 +354,48 @@ you to re-send them using MIME. See Documentation/email-clients.txt for hints about configuring your e-mail client so that it sends your patches untouched. -8) E-mail size. - -When sending patches to Linus, always follow step #7. +7) E-mail size. +--------------- Large changes are not appropriate for mailing lists, and some maintainers. If your patch, uncompressed, exceeds 300 kB in size, it is preferred that you store your patch on an Internet-accessible -server, and provide instead a URL (link) pointing to your patch. +server, and provide instead a URL (link) pointing to your patch. But note +that if your patch exceeds 300 kB, it almost certainly needs to be broken up +anyway. + +8) Respond to review comments. +------------------------------ + +Your patch will almost certainly get comments from reviewers on ways in +which the patch can be improved. You must respond to those comments; +ignoring reviewers is a good way to get ignored in return. Review comments +or questions that do not lead to a code change should almost certainly +bring about a comment or changelog entry so that the next reviewer better +understands what is going on. + +Be sure to tell the reviewers what changes you are making and to thank them +for their time. Code review is a tiring and time-consuming process, and +reviewers sometimes get grumpy. Even in that case, though, respond +politely and address the problems they have pointed out. +9) Don't get discouraged - or impatient. +---------------------------------------- -9) Name your kernel version. +After you have submitted your change, be patient and wait. Reviewers are +busy people and may not get to your patch right away. -It is important to note, either in the subject line or in the patch -description, the kernel version to which this patch applies. - -If the patch does not apply cleanly to the latest kernel version, -Linus will not apply it. +Once upon a time, patches used to disappear into the void without comment, +but the development process works more smoothly than that now. You should +receive comments within a week or so; if that does not happen, make sure +that you have sent your patches to the right place. Wait for a minimum of +one week before resubmitting or pinging reviewers - possibly longer during +busy times like merge windows. - -10) Don't get discouraged. Re-submit. - -After you have submitted your change, be patient and wait. If Linus -likes your change and applies it, it will appear in the next version -of the kernel that he releases. - -However, if your change doesn't appear in the next version of the -kernel, there could be any number of reasons. It's YOUR job to -narrow down those reasons, correct what was wrong, and submit your -updated change. - -It is quite common for Linus to "drop" your patch without comment. -That's the nature of the system. If he drops your patch, it could be -due to -* Your patch did not apply cleanly to the latest kernel version. -* Your patch was not sufficiently discussed on linux-kernel. -* A style issue (see section 2). -* An e-mail formatting issue (re-read this section). -* A technical problem with your change. -* He gets tons of e-mail, and yours got lost in the shuffle. -* You are being annoying. - -When in doubt, solicit comments on linux-kernel mailing list. - - - -11) Include PATCH in the subject +10) Include PATCH in the subject +-------------------------------- Due to high e-mail traffic to Linus, and to linux-kernel, it is common convention to prefix your subject line with [PATCH]. This lets Linus @@ -355,7 +404,8 @@ e-mail discussions. -12) Sign your work +11) Sign your work +------------------ To improve tracking of who did what, especially with patches that can percolate to their final resting place in the kernel through several @@ -387,11 +437,11 @@ can certify the below: person who certified (a), (b) or (c) and I have not modified it. - (d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. + (d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. then you just add a line saying @@ -401,7 +451,7 @@ using your real name (sorry, no pseudonyms or anonymous contributions.) Some people also put extra tags at the end. They'll just be ignored for now, but you can do this to mark internal company procedures or just -point out some special detail about the sign-off. +point out some special detail about the sign-off. If you are a subsystem or branch maintainer, sometimes you need to slightly modify patches you receive in order to merge them, because the code is not @@ -429,15 +479,15 @@ which appears in the changelog. Special note to back-porters: It seems to be a common and useful practice to insert an indication of the origin of a patch at the top of the commit message (just after the subject line) to facilitate tracking. For instance, -here's what we see in 2.6-stable : +here's what we see in a 3.x-stable release: - Date: Tue May 13 19:10:30 2008 +0000 +Date: Tue Oct 7 07:26:38 2014 -0400 - SCSI: libiscsi regression in 2.6.25: fix nop timer handling + libata: Un-break ATA blacklist - commit 4cf1043593db6a337f10e006c23c69e5fc93e722 upstream + commit 1c40279960bcd7d52dbdf1d466b20d24b99176c8 upstream. -And here's what appears in 2.4 : +And here's what might appear in an older kernel once a patch is backported: Date: Tue May 13 22:12:27 2008 +0200 @@ -446,18 +496,19 @@ And here's what appears in 2.4 : [backport of 2.6 commit b7acbdfbd1f277c1eb23f344f899cfa4cd0bf36a] Whatever the format, this information provides a valuable help to people -tracking your trees, and to people trying to trouble-shoot bugs in your +tracking your trees, and to people trying to troubleshoot bugs in your tree. -13) When to use Acked-by: and Cc: +12) When to use Acked-by: and Cc: +--------------------------------- The Signed-off-by: tag indicates that the signer was involved in the development of the patch, or that he/she was in the patch's delivery path. If a person was not directly involved in the preparation or handling of a patch but wishes to signify and record their approval of it then they can -arrange to have an Acked-by: line added to the patch's changelog. +ask to have an Acked-by: line added to the patch's changelog. Acked-by: is often used by the maintainer of the affected code when that maintainer neither contributed to nor forwarded the patch. @@ -465,7 +516,8 @@ maintainer neither contributed to nor forwarded the patch. Acked-by: is not as formal as Signed-off-by:. It is a record that the acker has at least reviewed the patch and has indicated acceptance. Hence patch mergers will sometimes manually convert an acker's "yep, looks good to me" -into an Acked-by:. +into an Acked-by: (but note that it is usually better to ask for an +explicit ack). Acked-by: does not necessarily indicate acknowledgement of the entire patch. For example, if a patch affects multiple subsystems and has an Acked-by: from @@ -477,11 +529,13 @@ list archives. If a person has had the opportunity to comment on a patch, but has not provided such comments, you may optionally add a "Cc:" tag to the patch. This is the only tag which might be added without an explicit action by the -person it names. This tag documents that potentially interested parties -have been included in the discussion +person it names - but it should indicate that this person was copied on the +patch. This tag documents that potentially interested parties +have been included in the discussion. -14) Using Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: and Fixes: +13) Using Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: and Fixes: +-------------------------------------------------------------------------- The Reported-by tag gives credit to people who find bugs and report them and it hopefully inspires them to help us again in the future. Please note that if @@ -541,7 +595,13 @@ which stable kernel versions should receive your fix. This is the preferred method for indicating a bug fixed by the patch. See #2 above for more details. -15) The canonical patch format +14) The canonical patch format +------------------------------ + +This section describes how the patch itself should be formatted. Note +that, if you have your patches stored in a git repository, proper patch +formatting can be had with "git format-patch". The tools cannot create +the necessary text, though, so read the instructions below anyway. The canonical patch subject line is: @@ -549,7 +609,8 @@ The canonical patch subject line is: The canonical patch message body contains the following: - - A "from" line specifying the patch author. + - A "from" line specifying the patch author (only needed if the person + sending the patch is not the author). - An empty line. @@ -656,128 +717,63 @@ See more details on the proper patch format in the following references. -16) Sending "git pull" requests (from Linus emails) +15) Sending "git pull" requests +------------------------------- -Please write the git repo address and branch name alone on the same line -so that I can't even by mistake pull from the wrong branch, and so -that a triple-click just selects the whole thing. +If you have a series of patches, it may be most convenient to have the +maintainer pull them directly into the subsystem repository with a +"git pull" operation. Note, however, that pulling patches from a developer +requires a higher degree of trust than taking patches from a mailing list. +As a result, many subsystem maintainers are reluctant to take pull +requests, especially from new, unknown developers. If in doubt you can use +the pull request as the cover letter for a normal posting of the patch +series, giving the maintainer the option of using either. -So the proper format is something along the lines of: +A pull request should have [GIT] or [PULL] in the subject line. The +request itself should include the repository name and the branch of +interest on a single line; it should look something like: - "Please pull from + Please pull from - git://jdelvare.pck.nerim.net/jdelvare-2.6 i2c-for-linus + git://jdelvare.pck.nerim.net/jdelvare-2.6 i2c-for-linus - to get these changes:" + to get these changes:" -so that I don't have to hunt-and-peck for the address and inevitably -get it wrong (actually, I've only gotten it wrong a few times, and -checking against the diffstat tells me when I get it wrong, but I'm -just a lot more comfortable when I don't have to "look for" the right -thing to pull, and double-check that I have the right branch-name). +A pull request should also include an overall message saying what will be +included in the request, a "git shortlog" listing of the patches +themselves, and a diffstat showing the overall effect of the patch series. +The easiest way to get all this information together is, of course, to let +git do it for you with the "git request-pull" command. +Some maintainers (including Linus) want to see pull requests from signed +commits; that increases their confidence that the request actually came +from you. Linus, in particular, will not pull from public hosting sites +like GitHub in the absence of a signed tag. -Please use "git diff -M --stat --summary" to generate the diffstat: -the -M enables rename detection, and the summary enables a summary of -new/deleted or renamed files. +The first step toward creating such tags is to make a GNUPG key and get it +signed by one or more core kernel developers. This step can be hard for +new developers, but there is no way around it. Attending conferences can +be a good way to find developers who can sign your key. -With rename detection, the statistics are rather different [...] -because git will notice that a fair number of the changes are renames. +Once you have prepared a patch series in git that you wish to have somebody +pull, create a signed tag with "git tag -s". This will create a new tag +identifying the last commit in the series and containing a signature +created with your private key. You will also have the opportunity to add a +changelog-style message to the tag; this is an ideal place to describe the +effects of the pull request as a whole. ------------------------------------ -SECTION 2 - HINTS, TIPS, AND TRICKS ------------------------------------ +If the tree the maintainer will be pulling from is not the repository you +are working from, don't forget to push the signed tag explicitly to the +public tree. -This section lists many of the common "rules" associated with code -submitted to the kernel. There are always exceptions... but you must -have a really good reason for doing so. You could probably call this -section Linus Computer Science 101. - - - -1) Read Documentation/CodingStyle - -Nuff said. If your code deviates too much from this, it is likely -to be rejected without further review, and without comment. - -One significant exception is when moving code from one file to -another -- in this case you should not modify the moved code at all in -the same patch which moves it. This clearly delineates the act of -moving the code and your changes. This greatly aids review of the -actual differences and allows tools to better track the history of -the code itself. - -Check your patches with the patch style checker prior to submission -(scripts/checkpatch.pl). The style checker should be viewed as -a guide not as the final word. If your code looks better with -a violation then its probably best left alone. - -The checker reports at three levels: - - ERROR: things that are very likely to be wrong - - WARNING: things requiring careful review - - CHECK: things requiring thought - -You should be able to justify all violations that remain in your -patch. - - - -2) #ifdefs are ugly - -Code cluttered with ifdefs is difficult to read and maintain. Don't do -it. Instead, put your ifdefs in a header, and conditionally define -'static inline' functions, or macros, which are used in the code. -Let the compiler optimize away the "no-op" case. - -Simple example, of poor code: - - dev = alloc_etherdev (sizeof(struct funky_private)); - if (!dev) - return -ENODEV; - #ifdef CONFIG_NET_FUNKINESS - init_funky_net(dev); - #endif - -Cleaned-up example: - -(in header) - #ifndef CONFIG_NET_FUNKINESS - static inline void init_funky_net (struct net_device *d) {} - #endif - -(in the code itself) - dev = alloc_etherdev (sizeof(struct funky_private)); - if (!dev) - return -ENODEV; - init_funky_net(dev); - - - -3) 'static inline' is better than a macro - -Static inline functions are greatly preferred over macros. -They provide type safety, have no length limitations, no formatting -limitations, and under gcc they are as cheap as macros. - -Macros should only be used for cases where a static inline is clearly -suboptimal [there are a few, isolated cases of this in fast paths], -or where it is impossible to use a static inline function [such as -string-izing]. - -'static inline' is preferred over 'static __inline__', 'extern inline', -and 'extern __inline__'. - - - -4) Don't over-design. - -Don't try to anticipate nebulous future cases which may or may not -be useful: "Make it as simple as you can, and no simpler." +When generating your pull request, use the signed tag as the target. A +command like this will do the trick: + git request-pull master git://my.public.tree/linux.git my-signed-tag ---------------------- -SECTION 3 - REFERENCES +SECTION 2 - REFERENCES ---------------------- Andrew Morton, "The perfect patch" (tpp). diff --git a/Documentation/acpi/enumeration.txt b/Documentation/acpi/enumeration.txt index b60d2ab69497..9b121a569ab4 100644 --- a/Documentation/acpi/enumeration.txt +++ b/Documentation/acpi/enumeration.txt @@ -243,7 +243,7 @@ input driver: .owner = THIS_MODULE, .pm = &mpu3050_pm, .of_match_table = mpu3050_of_match, - .acpi_match_table ACPI_PTR(mpu3050_acpi_match), + .acpi_match_table = ACPI_PTR(mpu3050_acpi_match), }, .probe = mpu3050_probe, .remove = mpu3050_remove, diff --git a/Documentation/arm/00-INDEX b/Documentation/arm/00-INDEX index 3b08bc2b04cf..8edb9007844e 100644 --- a/Documentation/arm/00-INDEX +++ b/Documentation/arm/00-INDEX @@ -2,11 +2,15 @@ - this file Booting - requirements for booting +CCN.txt + - Cache Coherent Network ring-bus and perf PMU driver. Interrupts - ARM Interrupt subsystem documentation IXP4xx - Intel IXP4xx Network processor. -msm +Makefile + - Build sourcefiles as part of the Documentation-build for arm +msm/ - MSM specific documentation Netwinder - Netwinder specific documentation @@ -18,11 +22,9 @@ README - General ARM documentation SA1100/ - SA1100 documentation -Samsung-S3C24XX +Samsung-S3C24XX/ - S3C24XX ARM Linux Overview -Sharp-LH - - Linux on Sharp LH79524 and LH7A40X System On a Chip (SOC) -SPEAr +SPEAr/ - ST SPEAr platform Linux Overview VFP/ - Release notes for Linux Kernel Vector Floating Point support code diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt index a3b3da2ec6ed..01bf3d9fac85 100644 --- a/Documentation/arm64/legacy_instructions.txt +++ b/Documentation/arm64/legacy_instructions.txt @@ -32,6 +32,9 @@ The default mode depends on the status of the instruction in the architecture. Deprecated instructions should default to emulation while obsolete instructions must be undefined by default. +Note: Instruction emulation may not be possible in all cases. See +individual instruction notes for further information. + Supported legacy instructions ----------------------------- * SWP{B} @@ -43,3 +46,12 @@ Default: Undef (0) Node: /proc/sys/abi/cp15_barrier Status: Deprecated Default: Emulate (1) + +* SETEND +Node: /proc/sys/abi/setend +Status: Deprecated +Default: Emulate (1)* +Note: All the cpus on the system must have mixed endian support at EL0 +for this feature to be enabled. If a new CPU - which doesn't support mixed +endian - is hotplugged in after this feature has been enabled, there could +be unexpected results in the application. diff --git a/Documentation/blackfin/Makefile b/Documentation/blackfin/Makefile index c7e6c99bad81..03f78059d6f5 100644 --- a/Documentation/blackfin/Makefile +++ b/Documentation/blackfin/Makefile @@ -1,3 +1,5 @@ ifneq ($(CONFIG_BLACKFIN),) +ifneq ($(CONFIG_BFIN_GPTIMERS,) obj-m := gptimers-example.o endif +endif diff --git a/Documentation/cachetlb.txt b/Documentation/cachetlb.txt index d79b008e4a32..3f9f808b5119 100644 --- a/Documentation/cachetlb.txt +++ b/Documentation/cachetlb.txt @@ -317,10 +317,10 @@ maps this page at its virtual address. about doing this. The idea is, first at flush_dcache_page() time, if - page->mapping->i_mmap is an empty tree and ->i_mmap_nonlinear - an empty list, just mark the architecture private page flag bit. - Later, in update_mmu_cache(), a check is made of this flag bit, - and if set the flush is done and the flag bit is cleared. + page->mapping->i_mmap is an empty tree, just mark the architecture + private page flag bit. Later, in update_mmu_cache(), a check is + made of this flag bit, and if set the flush is done and the flag + bit is cleared. IMPORTANT NOTE: It is often important, if you defer the flush, that the actual flush occurs on the same CPU diff --git a/Documentation/cgroups/00-INDEX b/Documentation/cgroups/00-INDEX index bc461b6425a7..96ce071a3633 100644 --- a/Documentation/cgroups/00-INDEX +++ b/Documentation/cgroups/00-INDEX @@ -24,3 +24,5 @@ net_prio.txt - Network priority cgroups details and usages. resource_counter.txt - Resource Counter API. +unified-hierarchy.txt + - Description the new/next cgroup interface. diff --git a/Documentation/cgroups/unified-hierarchy.txt b/Documentation/cgroups/unified-hierarchy.txt index 4f4563277864..71daa35ec2d9 100644 --- a/Documentation/cgroups/unified-hierarchy.txt +++ b/Documentation/cgroups/unified-hierarchy.txt @@ -327,6 +327,85 @@ supported and the interface files "release_agent" and - use_hierarchy is on by default and the cgroup file for the flag is not created. +- The original lower boundary, the soft limit, is defined as a limit + that is per default unset. As a result, the set of cgroups that + global reclaim prefers is opt-in, rather than opt-out. The costs + for optimizing these mostly negative lookups are so high that the + implementation, despite its enormous size, does not even provide the + basic desirable behavior. First off, the soft limit has no + hierarchical meaning. All configured groups are organized in a + global rbtree and treated like equal peers, regardless where they + are located in the hierarchy. This makes subtree delegation + impossible. Second, the soft limit reclaim pass is so aggressive + that it not just introduces high allocation latencies into the + system, but also impacts system performance due to overreclaim, to + the point where the feature becomes self-defeating. + + The memory.low boundary on the other hand is a top-down allocated + reserve. A cgroup enjoys reclaim protection when it and all its + ancestors are below their low boundaries, which makes delegation of + subtrees possible. Secondly, new cgroups have no reserve per + default and in the common case most cgroups are eligible for the + preferred reclaim pass. This allows the new low boundary to be + efficiently implemented with just a minor addition to the generic + reclaim code, without the need for out-of-band data structures and + reclaim passes. Because the generic reclaim code considers all + cgroups except for the ones running low in the preferred first + reclaim pass, overreclaim of individual groups is eliminated as + well, resulting in much better overall workload performance. + +- The original high boundary, the hard limit, is defined as a strict + limit that can not budge, even if the OOM killer has to be called. + But this generally goes against the goal of making the most out of + the available memory. The memory consumption of workloads varies + during runtime, and that requires users to overcommit. But doing + that with a strict upper limit requires either a fairly accurate + prediction of the working set size or adding slack to the limit. + Since working set size estimation is hard and error prone, and + getting it wrong results in OOM kills, most users tend to err on the + side of a looser limit and end up wasting precious resources. + + The memory.high boundary on the other hand can be set much more + conservatively. When hit, it throttles allocations by forcing them + into direct reclaim to work off the excess, but it never invokes the + OOM killer. As a result, a high boundary that is chosen too + aggressively will not terminate the processes, but instead it will + lead to gradual performance degradation. The user can monitor this + and make corrections until the minimal memory footprint that still + gives acceptable performance is found. + + In extreme cases, with many concurrent allocations and a complete + breakdown of reclaim progress within the group, the high boundary + can be exceeded. But even then it's mostly better to satisfy the + allocation from the slack available in other groups or the rest of + the system than killing the group. Otherwise, memory.max is there + to limit this type of spillover and ultimately contain buggy or even + malicious applications. + +- The original control file names are unwieldy and inconsistent in + many different ways. For example, the upper boundary hit count is + exported in the memory.failcnt file, but an OOM event count has to + be manually counted by listening to memory.oom_control events, and + lower boundary / soft limit events have to be counted by first + setting a threshold for that value and then counting those events. + Also, usage and limit files encode their units in the filename. + That makes the filenames very long, even though this is not + information that a user needs to be reminded of every time they type + out those names. + + To address these naming issues, as well as to signal clearly that + the new interface carries a new configuration model, the naming + conventions in it necessarily differ from the old interface. + +- The original limit files indicate the state of an unset limit with a + Very High Number, and a configured limit can be unset by echoing -1 + into those files. But that very high number is implementation and + architecture dependent and not very descriptive. And while -1 can + be understood as an underflow into the highest possible value, -2 or + -10M etc. do not work, so it's not consistent. + + memory.low, memory.high, and memory.max will use the string + "infinity" to indicate and set the highest possible value. 5. Planned Changes diff --git a/Documentation/cpu-freq/intel-pstate.txt b/Documentation/cpu-freq/intel-pstate.txt index 765d7fc0e692..655750743fb0 100644 --- a/Documentation/cpu-freq/intel-pstate.txt +++ b/Documentation/cpu-freq/intel-pstate.txt @@ -37,6 +37,14 @@ controlling P state selection. These files have been added to no_turbo: limits the driver to selecting P states below the turbo frequency range. + turbo_pct: displays the percentage of the total performance that + is supported by hardware that is in the turbo range. This number + is independent of whether turbo has been disabled or not. + + num_pstates: displays the number of pstates that are supported + by hardware. This number is independent of whether turbo has + been disabled or not. + For contemporary Intel processors, the frequency is controlled by the processor itself and the P-states exposed to software are related to performance levels. The idea that frequency can be set to a single diff --git a/Documentation/devicetree/bindings/arm/arm-boards b/Documentation/devicetree/bindings/arm/arm-boards index 556c8665fdbf..b78564b2b201 100644 --- a/Documentation/devicetree/bindings/arm/arm-boards +++ b/Documentation/devicetree/bindings/arm/arm-boards @@ -23,7 +23,7 @@ Required nodes: range of 0x200 bytes. - syscon: the root node of the Integrator platforms must have a - system controller node pointong to the control registers, + system controller node pointing to the control registers, with the compatible string "arm,integrator-ap-syscon" "arm,integrator-cp-syscon" diff --git a/Documentation/devicetree/bindings/arm/brcm-brcmstb.txt b/Documentation/devicetree/bindings/arm/brcm-brcmstb.txt index 3c436cc4f35d..430608ec09f0 100644 --- a/Documentation/devicetree/bindings/arm/brcm-brcmstb.txt +++ b/Documentation/devicetree/bindings/arm/brcm-brcmstb.txt @@ -79,7 +79,9 @@ reboot Required properties - compatible - The string property "brcm,brcmstb-reboot". + The string property "brcm,brcmstb-reboot" for 40nm/28nm chips with + the new SYS_CTRL interface, or "brcm,bcm7038-reboot" for 65nm + chips with the old SUN_TOP_CTRL interface. - syscon A phandle / integer array that points to the syscon node which describes diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index b2aacbe16ed9..8b9e0a95de31 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt @@ -175,6 +175,7 @@ nodes to be present and contain the properties described below. "marvell,pj4a" "marvell,pj4b" "marvell,sheeva-v5" + "nvidia,tegra132-denver" "qcom,krait" "qcom,scorpion" - enable-method diff --git a/Documentation/devicetree/bindings/arm/fw-cfg.txt b/Documentation/devicetree/bindings/arm/fw-cfg.txt new file mode 100644 index 000000000000..953fb640d9c4 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/fw-cfg.txt @@ -0,0 +1,72 @@ +* QEMU Firmware Configuration bindings for ARM + +QEMU's arm-softmmu and aarch64-softmmu emulation / virtualization targets +provide the following Firmware Configuration interface on the "virt" machine +type: + +- A write-only, 16-bit wide selector (or control) register, +- a read-write, 64-bit wide data register. + +QEMU exposes the control and data register to ARM guests as memory mapped +registers; their location is communicated to the guest's UEFI firmware in the +DTB that QEMU places at the bottom of the guest's DRAM. + +The guest writes a selector value (a key) to the selector register, and then +can read the corresponding data (produced by QEMU) via the data register. If +the selected entry is writable, the guest can rewrite it through the data +register. + +The selector register takes keys in big endian byte order. + +The data register allows accesses with 8, 16, 32 and 64-bit width (only at +offset 0 of the register). Accesses larger than a byte are interpreted as +arrays, bundled together only for better performance. The bytes constituting +such a word, in increasing address order, correspond to the bytes that would +have been transferred by byte-wide accesses in chronological order. + +The interface allows guest firmware to download various parameters and blobs +that affect how the firmware works and what tables it installs for the guest +OS. For example, boot order of devices, ACPI tables, SMBIOS tables, kernel and +initrd images for direct kernel booting, virtual machine UUID, SMP information, +virtual NUMA topology, and so on. + +The authoritative registry of the valid selector values and their meanings is +the QEMU source code; the structure of the data blobs corresponding to the +individual key values is also defined in the QEMU source code. + +The presence of the registers can be verified by selecting the "signature" blob +with key 0x0000, and reading four bytes from the data register. The returned +signature is "QEMU". + +The outermost protocol (involving the write / read sequences of the control and +data registers) is expected to be versioned, and/or described by feature bits. +The interface revision / feature bitmap can be retrieved with key 0x0001. The +blob to be read from the data register has size 4, and it is to be interpreted +as a uint32_t value in little endian byte order. The current value +(corresponding to the above outer protocol) is zero. + +The guest kernel is not expected to use these registers (although it is +certainly allowed to); the device tree bindings are documented here because +this is where device tree bindings reside in general. + +Required properties: + +- compatible: "qemu,fw-cfg-mmio". + +- reg: the MMIO region used by the device. + * Bytes 0x0 to 0x7 cover the data register. + * Bytes 0x8 to 0x9 cover the selector register. + * Further registers may be appended to the region in case of future interface + revisions / feature bits. + +Example: + +/ { + #size-cells = <0x2>; + #address-cells = <0x2>; + + fw-cfg@9020000 { + compatible = "qemu,fw-cfg-mmio"; + reg = <0x0 0x9020000 0x0 0xa>; + }; +}; diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt index 292ef7ca3058..0dbabe9a6b0a 100644 --- a/Documentation/devicetree/bindings/arm/l2cc.txt +++ b/Documentation/devicetree/bindings/arm/l2cc.txt @@ -57,6 +57,16 @@ Optional properties: - cache-id-part: cache id part number to be used if it is not present on hardware - wt-override: If present then L2 is forced to Write through mode +- arm,double-linefill : Override double linefill enable setting. Enable if + non-zero, disable if zero. +- arm,double-linefill-incr : Override double linefill on INCR read. Enable + if non-zero, disable if zero. +- arm,double-linefill-wrap : Override double linefill on WRAP read. Enable + if non-zero, disable if zero. +- arm,prefetch-drop : Override prefetch drop enable setting. Enable if non-zero, + disable if zero. +- arm,prefetch-offset : Override prefetch offset value. Valid values are + 0-7, 15, 23, and 31. Example: diff --git a/Documentation/devicetree/bindings/arm/msm/timer.txt b/Documentation/devicetree/bindings/arm/msm/timer.txt index c6ef8f13dc7e..74607b6c1117 100644 --- a/Documentation/devicetree/bindings/arm/msm/timer.txt +++ b/Documentation/devicetree/bindings/arm/msm/timer.txt @@ -8,7 +8,7 @@ Properties: "qcom,kpss-timer" - krait subsystem "qcom,scss-timer" - scorpion subsystem -- interrupts : Interrupts for the the debug timer, the first general purpose +- interrupts : Interrupts for the debug timer, the first general purpose timer, and optionally a second general purpose timer in that order. diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-ahb.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-ahb.txt index 234406d41c12..067c9790062f 100644 --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-ahb.txt +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-ahb.txt @@ -1,7 +1,10 @@ NVIDIA Tegra AHB Required properties: -- compatible : "nvidia,tegra20-ahb" or "nvidia,tegra30-ahb" +- compatible : For Tegra20, must contain "nvidia,tegra20-ahb". For + Tegra30, must contain "nvidia,tegra30-ahb". Otherwise, must contain + '"nvidia,-ahb", "nvidia,tegra30-ahb"' where is tegra124, + tegra132, or tegra210. - reg : Should contain 1 register ranges(address and length) Example: diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt index 68ac65f82a1c..dd75b972ee37 100644 --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt @@ -6,7 +6,11 @@ modes. It provides power-gating controllers for SoC and CPU power-islands. Required properties: - name : Should be pmc -- compatible : Should contain "nvidia,tegra-pmc". +- compatible : For Tegra20, must contain "nvidia,tegra20-pmc". For Tegra30, + must contain "nvidia,tegra30-pmc". For Tegra114, must contain + "nvidia,tegra114-pmc". For Tegra124, must contain "nvidia,tegra124-pmc". + Otherwise, must contain "nvidia,-pmc", plus at least one of the + above, where is tegra132. - reg : Offset and length of the register set for the device - clocks : Must contain an entry for each entry in clock-names. See ../clocks/clock-bindings.txt for details. diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt index 4ab09f2202d4..c2340eeeb97f 100644 --- a/Documentation/devicetree/bindings/ata/ahci-platform.txt +++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt @@ -37,9 +37,10 @@ Required properties when using sub-nodes: Sub-nodes required properties: -- reg : the port number -- phys : reference to the SATA PHY node - +- reg : the port number +And at least one of the following properties: +- phys : reference to the SATA PHY node +- target-supply : regulator for SATA target power Examples: sata@ffe08000 { @@ -68,10 +69,12 @@ With sub-nodes: sata0: sata-port@0 { reg = <0>; phys = <&sata_phy 0>; + target-supply = <®_sata0>; }; sata1: sata-port@1 { reg = <1>; phys = <&sata_phy 1>; + target-supply = <®_sata1>;; }; }; diff --git a/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt b/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt index 93986a5a8018..3bacc8e0931e 100644 --- a/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt +++ b/Documentation/devicetree/bindings/ata/cavium-compact-flash.txt @@ -9,7 +9,7 @@ Properties: Compatibility with many Cavium evaluation boards. -- reg: The base address of the the CF chip select banks. Depending on +- reg: The base address of the CF chip select banks. Depending on the device configuration, there may be one or two banks. - cavium,bus-width: The width of the connection to the CF devices. Valid diff --git a/Documentation/devicetree/bindings/ata/tegra-sata.txt b/Documentation/devicetree/bindings/ata/tegra-sata.txt index 946f2072570b..66c83c3e8915 100644 --- a/Documentation/devicetree/bindings/ata/tegra-sata.txt +++ b/Documentation/devicetree/bindings/ata/tegra-sata.txt @@ -1,7 +1,9 @@ Tegra124 SoC SATA AHCI controller Required properties : -- compatible : "nvidia,tegra124-ahci". +- compatible : For Tegra124, must contain "nvidia,tegra124-ahci". Otherwise, + must contain '"nvidia,-ahci", "nvidia,tegra124-ahci"', where + is tegra132. - reg : Should contain 2 entries: - AHCI register set (SATA BAR5) - SATA register set diff --git a/Documentation/devicetree/bindings/c6x/dscr.txt b/Documentation/devicetree/bindings/c6x/dscr.txt index b0e97144cfb1..92672235de57 100644 --- a/Documentation/devicetree/bindings/c6x/dscr.txt +++ b/Documentation/devicetree/bindings/c6x/dscr.txt @@ -12,7 +12,7 @@ configuration register for writes. These configuration register may be used to enable (and disable in some cases) SoC pin drivers, select peripheral clock sources (internal or pin), etc. In some cases, a configuration register is write once or the individual bits are write once. In addition to device config, -the DSCR block may provide registers which which are used to reset peripherals, +the DSCR block may provide registers which are used to reset peripherals, provide device ID information, provide ethernet MAC addresses, as well as other miscellaneous functions. diff --git a/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt b/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt new file mode 100644 index 000000000000..b54bf3a2ff57 --- /dev/null +++ b/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt @@ -0,0 +1,110 @@ + +* Samsung Exynos PPMU (Platform Performance Monitoring Unit) device + +The Samsung Exynos SoC has PPMU (Platform Performance Monitoring Unit) for +each IP. PPMU provides the primitive values to get performance data. These +PPMU events provide information of the SoC's behaviors so that you may +use to analyze system performance, to make behaviors visible and to count +usages of each IP (DMC, CPU, RIGHTBUS, LEFTBUS, CAM interface, LCD, G3D, MFC). +The Exynos PPMU driver uses the devfreq-event class to provide event data +to various devfreq devices. The devfreq devices would use the event data when +derterming the current state of each IP. + +Required properties: +- compatible: Should be "samsung,exynos-ppmu". +- reg: physical base address of each PPMU and length of memory mapped region. + +Optional properties: +- clock-names : the name of clock used by the PPMU, "ppmu" +- clocks : phandles for clock specified in "clock-names" property +- #clock-cells: should be 1. + +Example1 : PPMU nodes in exynos3250.dtsi are listed below. + + ppmu_dmc0: ppmu_dmc0@106a0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x106a0000 0x2000>; + status = "disabled"; + }; + + ppmu_dmc1: ppmu_dmc1@106b0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x106b0000 0x2000>; + status = "disabled"; + }; + + ppmu_cpu: ppmu_cpu@106c0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x106c0000 0x2000>; + status = "disabled"; + }; + + ppmu_rightbus: ppmu_rightbus@112a0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x112a0000 0x2000>; + clocks = <&cmu CLK_PPMURIGHT>; + clock-names = "ppmu"; + status = "disabled"; + }; + + ppmu_leftbus: ppmu_leftbus0@116a0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x116a0000 0x2000>; + clocks = <&cmu CLK_PPMULEFT>; + clock-names = "ppmu"; + status = "disabled"; + }; + +Example2 : Events of each PPMU node in exynos3250-rinato.dts are listed below. + + &ppmu_dmc0 { + status = "okay"; + + events { + ppmu_dmc0_3: ppmu-event3-dmc0 { + event-name = "ppmu-event3-dmc0"; + }; + + ppmu_dmc0_2: ppmu-event2-dmc0 { + event-name = "ppmu-event2-dmc0"; + }; + + ppmu_dmc0_1: ppmu-event1-dmc0 { + event-name = "ppmu-event1-dmc0"; + }; + + ppmu_dmc0_0: ppmu-event0-dmc0 { + event-name = "ppmu-event0-dmc0"; + }; + }; + }; + + &ppmu_dmc1 { + status = "okay"; + + events { + ppmu_dmc1_3: ppmu-event3-dmc1 { + event-name = "ppmu-event3-dmc1"; + }; + }; + }; + + &ppmu_leftbus { + status = "okay"; + + events { + ppmu_leftbus_3: ppmu-event3-leftbus { + event-name = "ppmu-event3-leftbus"; + }; + }; + }; + + &ppmu_rightbus { + status = "okay"; + + events { + ppmu_rightbus_3: ppmu-event3-rightbus { + event-name = "ppmu-event3-rightbus"; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt index df0f48bcf75a..f7e21b1c2a05 100644 --- a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt +++ b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt @@ -1,6 +1,6 @@ * Renesas R-Car DMA Controller Device Tree bindings -Renesas R-Car Generation 2 SoCs have have multiple multi-channel DMA +Renesas R-Car Generation 2 SoCs have multiple multi-channel DMA controller instances named DMAC capable of serving multiple clients. Channels can be dedicated to specific clients or shared between a large number of clients. diff --git a/Documentation/devicetree/bindings/fpga/altera-socfpga-fpga-mgr.txt b/Documentation/devicetree/bindings/fpga/altera-socfpga-fpga-mgr.txt new file mode 100644 index 000000000000..9b027a615486 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/altera-socfpga-fpga-mgr.txt @@ -0,0 +1,17 @@ +Altera SOCFPGA FPGA Manager + +Required properties: +- compatible : should contain "altr,socfpga-fpga-mgr" +- reg : base address and size for memory mapped io. + - The first index is for FPGA manager register access. + - The second index is for writing FPGA configuration data. +- interrupts : interrupt for the FPGA Manager device. + +Example: + + hps_0_fpgamgr: fpgamgr@0xff706000 { + compatible = "altr,socfpga-fpga-mgr"; + reg = <0xFF706000 0x1000 + 0xFFB90000 0x1000>; + interrupts = <0 175 4>; + }; diff --git a/Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt b/Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt index d8c98c7614d0..23e1d3194174 100644 --- a/Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt +++ b/Documentation/devicetree/bindings/fuse/nvidia,tegra20-fuse.txt @@ -1,11 +1,11 @@ NVIDIA Tegra20/Tegra30/Tegr114/Tegra124 fuse block. Required properties: -- compatible : should be: - "nvidia,tegra20-efuse" - "nvidia,tegra30-efuse" - "nvidia,tegra114-efuse" - "nvidia,tegra124-efuse" +- compatible : For Tegra20, must contain "nvidia,tegra20-efuse". For Tegra30, + must contain "nvidia,tegra30-efuse". For Tegra114, must contain + "nvidia,tegra114-efuse". For Tegra124, must contain "nvidia,tegra124-efuse". + Otherwise, must contain "nvidia,-efuse", plus one of the above, where + is tegra132. Details: nvidia,tegra20-efuse: Tegra20 requires using APB DMA to read the fuse data due to a hardware bug. Tegra20 also lacks certain information which is diff --git a/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt new file mode 100644 index 000000000000..bef353f370d8 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt @@ -0,0 +1,20 @@ +Fujitsu MB86S7x GPIO Controller +------------------------------- + +Required properties: +- compatible: Should be "fujitsu,mb86s70-gpio" +- reg: Base address and length of register space +- clocks: Specify the clock +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be <2>. The first cell is the pin number and the + second cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted). + +Examples: + gpio0: gpio@31000000 { + compatible = "fujitsu,mb86s70-gpio"; + reg = <0 0x31000000 0x10000>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&clk 0 2 1>; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-max732x.txt b/Documentation/devicetree/bindings/gpio/gpio-max732x.txt new file mode 100644 index 000000000000..5fdc843b4542 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-max732x.txt @@ -0,0 +1,59 @@ +* MAX732x-compatible I/O expanders + +Required properties: + - compatible: Should be one of the following: + - "maxim,max7319": For the Maxim MAX7319 + - "maxim,max7320": For the Maxim MAX7320 + - "maxim,max7321": For the Maxim MAX7321 + - "maxim,max7322": For the Maxim MAX7322 + - "maxim,max7323": For the Maxim MAX7323 + - "maxim,max7324": For the Maxim MAX7324 + - "maxim,max7325": For the Maxim MAX7325 + - "maxim,max7326": For the Maxim MAX7326 + - "maxim,max7327": For the Maxim MAX7327 + - reg: I2C slave address for this device. + - gpio-controller: Marks the device node as a GPIO controller. + - #gpio-cells: Should be 2. + - first cell is the GPIO number + - second cell specifies GPIO flags, as defined in . + Only the GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported. + +Optional properties: + + The I/O expander can detect input state changes, and thus optionally act as + an interrupt controller. When the expander interrupt line is connected all the + following properties must be set. For more information please see the + interrupt controller device tree bindings documentation available at + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt. + + - interrupt-controller: Identifies the node as an interrupt controller. + - #interrupt-cells: Number of cells to encode an interrupt source, shall be 2. + - first cell is the pin number + - second cell is used to specify flags + - interrupt-parent: phandle of the parent interrupt controller. + - interrupts: Interrupt specifier for the controllers interrupt. + +Please refer to gpio.txt in this directory for details of the common GPIO +bindings used by client devices. + +Example 1. MAX7325 with interrupt support enabled (CONFIG_GPIO_MAX732X_IRQ=y): + + expander: max7325@6d { + compatible = "maxim,max7325"; + reg = <0x6d>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gpio4>; + interrupts = <29 IRQ_TYPE_EDGE_FALLING>; + }; + +Example 2. MAX7325 with interrupt support disabled (CONFIG_GPIO_MAX732X_IRQ=n): + + expander: max7325@6d { + compatible = "maxim,max7325"; + reg = <0x6d>; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-pcf857x.txt b/Documentation/devicetree/bindings/gpio/gpio-pcf857x.txt index d63194a2c848..ada4e2973323 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-pcf857x.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-pcf857x.txt @@ -39,7 +39,7 @@ Optional Properties: - lines-initial-states: Bitmask that specifies the initial state of each line. When a bit is set to zero, the corresponding line will be initialized to the input (pulled-up) state. When the bit is set to one, the line will be - initialized the the low-level output state. If the property is not specified + initialized the low-level output state. If the property is not specified all lines will be initialized to the input state. The I/O expander can detect input state changes, and thus optionally act as diff --git a/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt b/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt new file mode 100644 index 000000000000..ba2bb84eeac3 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-sx150x.txt @@ -0,0 +1,40 @@ +SEMTECH SX150x GPIO expander bindings + + +Required properties: + +- compatible: should be "semtech,sx1506q", + "semtech,sx1508q", + "semtech,sx1509q". + +- reg: The I2C slave address for this device. + +- interrupt-parent: phandle of the parent interrupt controller. + +- interrupts: Interrupt specifier for the controllers interrupt. + +- #gpio-cells: Should be 2. The first cell is the GPIO number and the + second cell is used to specify optional parameters: + bit 0: polarity (0: normal, 1: inverted) + +- gpio-controller: Marks the device as a GPIO controller. + +- interrupt-controller: Marks the device as a interrupt controller. + +The GPIO expander can optionally be used as an interrupt controller, in +which case it uses the default two cell specifier as described in +Documentation/devicetree/bindings/interrupt-controller/interrupts.txt. + +Example: + + i2c_gpio_expander@20{ + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "semtech,sx1506q"; + reg = <0x20>; + interrupt-parent = <&gpio_1>; + interrupts = <16 0>; + + gpio-controller; + interrupt-controller; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt b/Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt new file mode 100644 index 000000000000..dae130060537 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-xgene-sb.txt @@ -0,0 +1,32 @@ +APM X-Gene Standby GPIO controller bindings + +This is a gpio controller in the standby domain. + +There are 20 GPIO pins from 0..21. There is no GPIO_DS14 or GPIO_DS15, +only GPIO_DS8..GPIO_DS13 support interrupts. The IRQ mapping +is currently 1-to-1 on interrupts 0x28 thru 0x2d. + +Required properties: +- compatible: "apm,xgene-gpio-sb" for the X-Gene Standby GPIO controller +- reg: Physical base address and size of the controller's registers +- #gpio-cells: Should be two. + - first cell is the pin number + - second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low +- gpio-controller: Marks the device node as a GPIO controller. +- interrupts: Shall contain exactly 6 interrupts. + +Example: + sbgpio: sbgpio@17001000 { + compatible = "apm,xgene-gpio-sb"; + reg = <0x0 0x17001000 0x0 0x400>; + #gpio-cells = <2>; + gpio-controller; + interrupts = <0x0 0x28 0x1>, + <0x0 0x29 0x1>, + <0x0 0x2a 0x1>, + <0x0 0x2b 0x1>, + <0x0 0x2c 0x1>, + <0x0 0x2d 0x1>; + }; diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt index b9bd1d64cfa6..f7a158d85862 100644 --- a/Documentation/devicetree/bindings/gpio/gpio.txt +++ b/Documentation/devicetree/bindings/gpio/gpio.txt @@ -69,7 +69,8 @@ GPIO pin number, and GPIO flags as accepted by the "qe_pio_e" gpio-controller. ---------------------------------- A gpio-specifier should contain a flag indicating the GPIO polarity; active- -high or active-low. If it does, the follow best practices should be followed: +high or active-low. If it does, the following best practices should be +followed: The gpio-specifier's polarity flag should represent the physical level at the GPIO controller that achieves (or represents, for inputs) a logically asserted @@ -147,7 +148,7 @@ contains information structures as follows: numeric-gpio-range ::= named-gpio-range ::= '<0 0>' - gpio-phandle : phandle to pin controller node. + pinctrl-phandle : phandle to pin controller node gpio-base : Base GPIO ID in the GPIO controller pinctrl-base : Base pinctrl pin ID in the pin controller count : The number of GPIOs/pins in this range diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt index b2afdb27adeb..67a2e4e414a5 100644 --- a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt @@ -3,8 +3,8 @@ Required properties: - compatible : Should be "intel,pxa25x-gpio", "intel,pxa26x-gpio", "intel,pxa27x-gpio", "intel,pxa3xx-gpio", - "marvell,pxa93x-gpio", "marvell,mmp-gpio" or - "marvell,mmp2-gpio". + "marvell,pxa93x-gpio", "marvell,mmp-gpio", + "marvell,mmp2-gpio" or marvell,pxa1928-gpio. - reg : Address and length of the register set for the device - interrupts : Should be the port interrupt shared by all gpio pins. There're three gpio interrupts in arch-pxa, and they're gpio0, diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt index 4c32ef0b7db8..009f4bfa1590 100644 --- a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt @@ -197,7 +197,9 @@ of the following host1x client modules: - sor: serial output resource Required properties: - - compatible: "nvidia,tegra124-sor" + - compatible: For Tegra124, must contain "nvidia,tegra124-sor". Otherwise, + must contain '"nvidia,-sor", "nvidia,tegra124-sor"', where + is tegra132. - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. - clocks: Must contain an entry for each entry in clock-names. @@ -222,7 +224,9 @@ of the following host1x client modules: - nvidia,dpaux: phandle to a DispayPort AUX interface - dpaux: DisplayPort AUX interface - - compatible: "nvidia,tegra124-dpaux" + - compatible: For Tegra124, must contain "nvidia,tegra124-dpaux". Otherwise, + must contain '"nvidia,-dpaux", "nvidia,tegra124-dpaux"', where + is tegra132. - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. - clocks: Must contain an entry for each entry in clock-names. diff --git a/Documentation/devicetree/bindings/graph.txt b/Documentation/devicetree/bindings/graph.txt index 1a69c078adf2..fcb1c6a4787b 100644 --- a/Documentation/devicetree/bindings/graph.txt +++ b/Documentation/devicetree/bindings/graph.txt @@ -19,7 +19,7 @@ type of the connections, they just map their existence. Specific properties may be described by specialized bindings depending on the type of connection. To see how this binding applies to video pipelines, for example, see -Documentation/device-tree/bindings/media/video-interfaces.txt. +Documentation/devicetree/bindings/media/video-interfaces.txt. Here the ports describe data interfaces, and the links between them are the connecting data buses. A single port with multiple connections can correspond to multiple devices being connected to the same physical bus. diff --git a/Documentation/devicetree/bindings/i2c/i2c-st.txt b/Documentation/devicetree/bindings/i2c/i2c-st.txt index 437e0db3823c..4c26fda3844a 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-st.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-st.txt @@ -31,7 +31,7 @@ i2c0: i2c@fed40000 { compatible = "st,comms-ssc4-i2c"; reg = <0xfed40000 0x110>; interrupts = ; - clocks = <&CLK_S_ICN_REG_0>; + clocks = <&clk_s_a0_ls CLK_ICN_REG>; clock-names = "ssc"; clock-frequency = <400000>; pinctrl-names = "default"; diff --git a/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt b/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt index 87507e9ce6db..656716b72cc4 100644 --- a/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt +++ b/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt @@ -1,11 +1,11 @@ NVIDIA Tegra20/Tegra30/Tegra114 I2C controller driver. Required properties: -- compatible : should be: - "nvidia,tegra114-i2c" - "nvidia,tegra30-i2c" - "nvidia,tegra20-i2c" - "nvidia,tegra20-i2c-dvc" +- compatible : For Tegra20, must be one of "nvidia,tegra20-i2c-dvc" or + "nvidia,tegra20-i2c". For Tegra30, must be "nvidia,tegra30-i2c". + For Tegra114, must be "nvidia,tegra114-i2c". Otherwise, must be + "nvidia,-i2c", plus at least one of the above, where is + tegra124, tegra132, or tegra210. Details of compatible are as follows: nvidia,tegra20-i2c-dvc: Tegra20 has specific I2C controller called as DVC I2C controller. This only support master mode of I2C communication. Register diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index 9f4e3824e71e..9f41d05be3be 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt @@ -47,6 +47,7 @@ dallas,ds3232 Extremely Accurate I²C RTC with Integrated Crystal and SRAM dallas,ds4510 CPU Supervisor with Nonvolatile Memory and Programmable I/O dallas,ds75 Digital Thermometer and Thermostat dlg,da9053 DA9053: flexible system level PMIC with multicore support +dlg,da9063 DA9063: system PMIC for quad-core application processors epson,rx8025 High-Stability. I2C-Bus INTERFACE REAL TIME CLOCK MODULE epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE fsl,mag3110 MAG3110: Xtrinsic High Accuracy, 3D Magnetometer diff --git a/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt b/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt index d9ee909d2b78..d71258e2d456 100644 --- a/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt +++ b/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt @@ -59,7 +59,7 @@ Optional properties: Each child node represents one channel and has the following properties: Required properties: - * reg: Pair of pins the the channel is connected to. + * reg: Pair of pins the channel is connected to. 0: VP/VN 1: VAUXP[0]/VAUXN[0] 2: VAUXP[1]/VAUXN[1] diff --git a/Documentation/devicetree/bindings/input/e3x0-button.txt b/Documentation/devicetree/bindings/input/e3x0-button.txt new file mode 100644 index 000000000000..751665e8e47a --- /dev/null +++ b/Documentation/devicetree/bindings/input/e3x0-button.txt @@ -0,0 +1,25 @@ +National Instruments Ettus Research USRP E3x0 button driver + +This module is part of the NI Ettus Research USRP E3x0 SDR. + +This module provides a simple power button event via two interrupts. + +Required properties: +- compatible: should be one of the following + - "ettus,e3x0-button": For devices such as the NI Ettus Research USRP E3x0 +- interrupt-parent: + - a phandle to the interrupt controller that it is attached to. +- interrupts: should be one of the following + - <0 30 1>, <0 31 1>: For devices such as the NI Ettus Research USRP E3x0 +- interrupt-names: should be one of the following + - "press", "release": For devices such as the NI Ettus Research USRP E3x0 + +Note: Interrupt numbers might vary depending on the FPGA configuration. + +Example: + button { + compatible = "ettus,e3x0-button"; + interrupt-parent = <&intc>; + interrupts = <0 30 1>, <0 31 1>; + interrupt-names = "press", "release"; + } diff --git a/Documentation/devicetree/bindings/input/regulator-haptic.txt b/Documentation/devicetree/bindings/input/regulator-haptic.txt new file mode 100644 index 000000000000..3ed1c7eb2f97 --- /dev/null +++ b/Documentation/devicetree/bindings/input/regulator-haptic.txt @@ -0,0 +1,21 @@ +* Regulator Haptic Device Tree Bindings + +Required Properties: + - compatible : Should be "regulator-haptic" + - haptic-supply : Power supply to the haptic motor. + [*] refer Documentation/devicetree/bindings/regulator/regulator.txt + + - max-microvolt : The maximum voltage value supplied to the haptic motor. + [The unit of the voltage is a micro] + + - min-microvolt : The minimum voltage value supplied to the haptic motor. + [The unit of the voltage is a micro] + +Example: + + haptics { + compatible = "regulator-haptic"; + haptic-supply = <&motor_regulator>; + max-microvolt = <2700000>; + min-microvolt = <1100000>; + }; diff --git a/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt b/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt new file mode 100644 index 000000000000..b9c32f6fd687 --- /dev/null +++ b/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt @@ -0,0 +1,62 @@ +Allwinner sun4i low res adc attached tablet keys +------------------------------------------------ + +Required properties: + - compatible: "allwinner,sun4i-a10-lradc-keys" + - reg: mmio address range of the chip + - interrupts: interrupt to which the chip is connected + - vref-supply: powersupply for the lradc reference voltage + +Each key is represented as a sub-node of "allwinner,sun4i-a10-lradc-keys": + +Required subnode-properties: + - label: Descriptive name of the key. + - linux,code: Keycode to emit. + - channel: Channel this key is attached to, mut be 0 or 1. + - voltage: Voltage in µV at lradc input when this key is pressed. + +Example: + +#include + + lradc: lradc@01c22800 { + compatible = "allwinner,sun4i-a10-lradc-keys"; + reg = <0x01c22800 0x100>; + interrupts = <31>; + vref-supply = <®_vcc3v0>; + + button@191 { + label = "Volume Up"; + linux,code = ; + channel = <0>; + voltage = <191274>; + }; + + button@392 { + label = "Volume Down"; + linux,code = ; + channel = <0>; + voltage = <392644>; + }; + + button@601 { + label = "Menu"; + linux,code = ; + channel = <0>; + voltage = <601151>; + }; + + button@795 { + label = "Enter"; + linux,code = ; + channel = <0>; + voltage = <795090>; + }; + + button@987 { + label = "Home"; + linux,code = ; + channel = <0>; + voltage = <987387>; + }; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt index aef57791f40b..433332d3b2ba 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt @@ -2,9 +2,10 @@ sun4i resistive touchscreen controller -------------------------------------- Required properties: - - compatible: "allwinner,sun4i-a10-ts" + - compatible: "allwinner,sun4i-a10-ts" or "allwinner,sun6i-a31-ts" - reg: mmio address range of the chip - interrupts: interrupt to which the chip is connected + - #thermal-sensor-cells: shall be 0 Optional properties: - allwinner,ts-attached: boolean indicating that an actual touchscreen is @@ -17,4 +18,5 @@ Example: reg = <0x01c25000 0x100>; interrupts = <29>; allwinner,ts-attached; + #thermal-sensor-cells = <0>; }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt b/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt index 878549ba814d..6c4fb34823d3 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt @@ -28,6 +28,20 @@ Required properties: ti,adc-channels: List of analog inputs available for ADC. AIN0 = 0, AIN1 = 1 and so on till AIN7 = 7. +Optional properties: +- child "tsc" + ti,charge-delay: Length of touch screen charge delay step in terms of + ADC clock cycles. Charge delay value should be large + in order to avoid false pen-up events. This value + effects the overall sampling speed, hence need to be + kept as low as possible, while avoiding false pen-up + event. Start from a lower value, say 0x400, and + increase value until false pen-up events are avoided. + The pen-up detection happens immediately after the + charge step, so this does in fact function as a + hardware knob for adjusting the amount of "settling + time". + Example: tscadc: tscadc@44e0d000 { compatible = "ti,am3359-tscadc"; @@ -36,6 +50,7 @@ Example: ti,x-plate-resistance = <200>; ti,coordiante-readouts = <5>; ti,wire-config = <0x00 0x11 0x22 0x33>; + ti,charge-delay = <0x400>; }; adc { diff --git a/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt b/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt new file mode 100644 index 000000000000..e30e0b93f2b3 --- /dev/null +++ b/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt @@ -0,0 +1,17 @@ +Texas Instruments TPS65218 power button + +This driver provides a simple power button event via an Interrupt. + +Required properties: +- compatible: should be "ti,tps65218-pwrbutton" +- interrupts: should be one of the following + - <3 IRQ_TYPE_EDGE_BOTH>: For controllers compatible with tps65218 + +Example: + +&tps { + power-button { + compatible = "ti,tps65218-pwrbutton"; + interrupts = <3 IRQ_TYPE_EDGE_BOTH>; + }; +}; diff --git a/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt new file mode 100644 index 000000000000..cd29083e16ec --- /dev/null +++ b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt @@ -0,0 +1,41 @@ +* Renesas VMSA-Compatible IOMMU + +The IPMMU is an IOMMU implementation compatible with the ARM VMSA page tables. +It provides address translation for bus masters outside of the CPU, each +connected to the IPMMU through a port called micro-TLB. + + +Required Properties: + + - compatible: Must contain "renesas,ipmmu-vmsa". + - reg: Base address and size of the IPMMU registers. + - interrupts: Specifiers for the MMU fault interrupts. For instances that + support secure mode two interrupts must be specified, for non-secure and + secure mode, in that order. For instances that don't support secure mode a + single interrupt must be specified. + + - #iommu-cells: Must be 1. + +Each bus master connected to an IPMMU must reference the IPMMU in its device +node with the following property: + + - iommus: A reference to the IPMMU in two cells. The first cell is a phandle + to the IPMMU and the second cell the number of the micro-TLB that the + device is connected to. + + +Example: R8A7791 IPMMU-MX and VSP1-D0 bus master + + ipmmu_mx: mmu@fe951000 { + compatible = "renasas,ipmmu-vmsa"; + reg = <0 0xfe951000 0 0x1000>; + interrupts = <0 222 IRQ_TYPE_LEVEL_HIGH>, + <0 221 IRQ_TYPE_LEVEL_HIGH>; + #iommu-cells = <1>; + }; + + vsp1@fe928000 { + ... + iommus = <&ipmmu_mx 13>; + ... + }; diff --git a/Documentation/devicetree/bindings/mailbox/altera-mailbox.txt b/Documentation/devicetree/bindings/mailbox/altera-mailbox.txt new file mode 100644 index 000000000000..c2619797ce0c --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/altera-mailbox.txt @@ -0,0 +1,49 @@ +Altera Mailbox Driver +===================== + +Required properties: +- compatible : "altr,mailbox-1.0". +- reg : physical base address of the mailbox and length of + memory mapped region. +- #mbox-cells: Common mailbox binding property to identify the number + of cells required for the mailbox specifier. Should be 1. + +Optional properties: +- interrupt-parent : interrupt source phandle. +- interrupts : interrupt number. The interrupt specifier format + depends on the interrupt controller parent. + +Example: + mbox_tx: mailbox@0x100 { + compatible = "altr,mailbox-1.0"; + reg = <0x100 0x8>; + interrupt-parent = < &gic_0 >; + interrupts = <5>; + #mbox-cells = <1>; + }; + + mbox_rx: mailbox@0x200 { + compatible = "altr,mailbox-1.0"; + reg = <0x200 0x8>; + interrupt-parent = < &gic_0 >; + interrupts = <6>; + #mbox-cells = <1>; + }; + +Mailbox client +=============== +"mboxes" and the optional "mbox-names" (please see +Documentation/devicetree/bindings/mailbox/mailbox.txt for details). Each value +of the mboxes property should contain a phandle to the mailbox controller +device node and second argument is the channel index. It must be 0 (hardware +support only one channel).The equivalent "mbox-names" property value can be +used to give a name to the communication channel to be used by the client user. + +Example: + mclient0: mclient0@0x400 { + compatible = "client-1.0"; + reg = <0x400 0x10>; + mbox-names = "mbox-tx", "mbox-rx"; + mboxes = <&mbox_tx 0>, + <&mbox_rx 0>; + }; diff --git a/Documentation/devicetree/bindings/media/atmel-isi.txt b/Documentation/devicetree/bindings/media/atmel-isi.txt index 17e71b7b44c6..251f008f220c 100644 --- a/Documentation/devicetree/bindings/media/atmel-isi.txt +++ b/Documentation/devicetree/bindings/media/atmel-isi.txt @@ -38,7 +38,7 @@ Example: i2c1: i2c@f0018000 { ov2640: camera@0x30 { - compatible = "omnivision,ov2640"; + compatible = "ovti,ov2640"; reg = <0x30>; port { diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt new file mode 100644 index 000000000000..855e1faf73e2 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt @@ -0,0 +1,63 @@ +SMIA/SMIA++ sensor + +SMIA (Standard Mobile Imaging Architecture) is an image sensor standard +defined jointly by Nokia and ST. SMIA++, defined by Nokia, is an extension +of that. These definitions are valid for both types of sensors. + +More detailed documentation can be found in +Documentation/devicetree/bindings/media/video-interfaces.txt . + + +Mandatory properties +-------------------- + +- compatible: "nokia,smia" +- reg: I2C address (0x10, or an alternative address) +- vana-supply: Analogue voltage supply (VANA), typically 2,8 volts (sensor + dependent). +- clocks: External clock to the sensor +- clock-frequency: Frequency of the external clock to the sensor +- link-frequencies: List of allowed data link frequencies. An array of + 64-bit elements. + + +Optional properties +------------------- + +- nokia,nvm-size: The size of the NVM, in bytes. If the size is not given, + the NVM contents will not be read. +- reset-gpios: XSHUTDOWN GPIO + + +Endpoint node mandatory properties +---------------------------------- + +- clock-lanes: <0> +- data-lanes: <1..n> +- remote-endpoint: A phandle to the bus receiver's endpoint node. + + +Example +------- + +&i2c2 { + clock-frequency = <400000>; + + smiapp_1: camera@10 { + compatible = "nokia,smia"; + reg = <0x10>; + reset-gpios = <&gpio3 20 0>; + vana-supply = <&vaux3>; + clocks = <&omap3_isp 0>; + clock-frequency = <9600000>; + nokia,nvm-size = <512>; /* 8 * 64 */ + link-frequencies = /bits/ 64 <199200000 210000000 499200000>; + port { + smiapp_1_1: endpoint { + clock-lanes = <0>; + data-lanes = <1 2>; + remote-endpoint = <&csi2a_ep>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/media/sunxi-ir.txt b/Documentation/devicetree/bindings/media/sunxi-ir.txt index 23dd5ad07b7c..1811a067c72c 100644 --- a/Documentation/devicetree/bindings/media/sunxi-ir.txt +++ b/Documentation/devicetree/bindings/media/sunxi-ir.txt @@ -1,7 +1,7 @@ Device-Tree bindings for SUNXI IR controller found in sunXi SoC family Required properties: -- compatible : should be "allwinner,sun4i-a10-ir"; +- compatible : "allwinner,sun4i-a10-ir" or "allwinner,sun5i-a13-ir" - clocks : list of clock specifiers, corresponding to entries in clock-names property; - clock-names : should contain "apb" and "ir" entries; @@ -10,6 +10,7 @@ Required properties: Optional properties: - linux,rc-map-name : Remote control map name. +- resets : phandle + reset specifier pair Example: @@ -17,6 +18,7 @@ ir0: ir@01c21800 { compatible = "allwinner,sun4i-a10-ir"; clocks = <&apb0_gates 6>, <&ir0_clk>; clock-names = "apb", "ir"; + resets = <&apb0_rst 1>; interrupts = <0 5 1>; reg = <0x01C21800 0x40>; linux,rc-map-name = "rc-rc6-mce"; diff --git a/Documentation/devicetree/bindings/media/ti-am437x-vpfe.txt b/Documentation/devicetree/bindings/media/ti-am437x-vpfe.txt new file mode 100644 index 000000000000..3932e766553a --- /dev/null +++ b/Documentation/devicetree/bindings/media/ti-am437x-vpfe.txt @@ -0,0 +1,61 @@ +Texas Instruments AM437x CAMERA (VPFE) +-------------------------------------- + +The Video Processing Front End (VPFE) is a key component for image capture +applications. The capture module provides the system interface and the +processing capability to connect RAW image-sensor modules and video decoders +to the AM437x device. + +Required properties: +- compatible: must be "ti,am437x-vpfe" +- reg: physical base address and length of the registers set for the device; +- interrupts: should contain IRQ line for the VPFE; +- ti,am437x-vpfe-interface: can be one of the following, + 0 - Raw Bayer Interface. + 1 - 8 Bit BT656 Interface. + 2 - 10 Bit BT656 Interface. + 3 - YCbCr 8 Bit Interface. + 4 - YCbCr 16 Bit Interface. + +VPFE supports a single port node with parallel bus. It should contain one +'port' child node with child 'endpoint' node. Please refer to the bindings +defined in Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + vpfe: vpfe@f0034000 { + compatible = "ti,am437x-vpfe"; + reg = <0x48328000 0x2000>; + interrupts = ; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&vpfe_pins_default>; + pinctrl-1 = <&vpfe_pins_sleep>; + + port { + #address-cells = <1>; + #size-cells = <0>; + + vpfe0_ep: endpoint { + remote-endpoint = <&ov2659_1>; + ti,am437x-vpfe-interface = <0>; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + }; + }; + }; + + i2c1: i2c@4802a000 { + + ov2659@30 { + compatible = "ti,ov2659"; + reg = <0x30>; + + port { + ov2659_1: endpoint { + remote-endpoint = <&vpfe0_ep>; + bus-width = <8>; + mclk-frequency = <12000000>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt index ce719f89dd1c..571b4c60665f 100644 --- a/Documentation/devicetree/bindings/media/video-interfaces.txt +++ b/Documentation/devicetree/bindings/media/video-interfaces.txt @@ -103,6 +103,9 @@ Optional endpoint properties array contains only one entry. - clock-noncontinuous: a boolean property to allow MIPI CSI-2 non-continuous clock mode. +- link-frequencies: Allowed data bus frequencies. For MIPI CSI-2, for + instance, this is the actual frequency of the bus, not bits per clock per + lane value. An array of 64-bit unsigned integers. Example @@ -159,7 +162,7 @@ pipelines can be active: ov772x -> ceu0 or imx074 -> csi2 -> ceu0. i2c0: i2c@0xfff20000 { ... ov772x_1: camera@0x21 { - compatible = "omnivision,ov772x"; + compatible = "ovti,ov772x"; reg = <0x21>; vddio-supply = <®ulator1>; vddcore-supply = <®ulator2>; diff --git a/Documentation/devicetree/bindings/mfd/max77686.txt b/Documentation/devicetree/bindings/mfd/max77686.txt index 75fdfaf41831..e39f0bc1f55e 100644 --- a/Documentation/devicetree/bindings/mfd/max77686.txt +++ b/Documentation/devicetree/bindings/mfd/max77686.txt @@ -39,6 +39,12 @@ to get matched with their hardware counterparts as follow: -BUCKn : 1-4. Use standard regulator bindings for it ('regulator-off-in-suspend'). + LDO20, LDO21, LDO22, BUCK8 and BUCK9 can be configured to GPIO enable + control. To turn this feature on this property must be added to the regulator + sub-node: + - maxim,ena-gpios : one GPIO specifier enable control (the gpio + flags are actually ignored and always + ACTIVE_HIGH is used) Example: @@ -65,4 +71,12 @@ Example: regulator-always-on; regulator-boot-on; }; + + buck9_reg { + regulator-compatible = "BUCK9"; + regulator-name = "CAM_ISP_CORE_1.2V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + maxim,ena-gpios = <&gpm0 3 GPIO_ACTIVE_HIGH>; + }; } diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt index 01e9f30fe678..38e64405e98d 100644 --- a/Documentation/devicetree/bindings/mfd/max77693.txt +++ b/Documentation/devicetree/bindings/mfd/max77693.txt @@ -41,6 +41,41 @@ Optional properties: To get more informations, please refer to documentaion. [*] refer Documentation/devicetree/bindings/pwm/pwm.txt +- charger : Node configuring the charger driver. + If present, required properties: + - compatible : Must be "maxim,max77693-charger". + + Optional properties (if not set, defaults will be used): + - maxim,constant-microvolt : Battery constant voltage in uV. The charger + will operate in fast charge constant current mode till battery voltage + reaches this level. Then the charger will switch to fast charge constant + voltage mode. Also vsys (system voltage) will be set to this value when + DC power is supplied but charger is not enabled. + Valid values: 3650000 - 4400000, step by 25000 (rounded down) + Default: 4200000 + + - maxim,min-system-microvolt : Minimal system voltage in uV. + Valid values: 3000000 - 3700000, step by 100000 (rounded down) + Default: 3600000 + + - maxim,thermal-regulation-celsius : Temperature in Celsius for entering + high temperature charging mode. If die temperature exceeds this value + the charging current will be reduced by 105 mA/Celsius. + Valid values: 70, 85, 100, 115 + Default: 100 + + - maxim,battery-overcurrent-microamp : Overcurrent protection threshold + in uA (current from battery to system). + Valid values: 2000000 - 3500000, step by 250000 (rounded down) + Default: 3500000 + + - maxim,charge-input-threshold-microvolt : Threshold voltage in uV for + triggering input voltage regulation loop. If input voltage decreases + below this value, the input current will be reduced to reach the + threshold voltage. + Valid values: 4300000, 4700000, 4800000, 4900000 + Default: 4300000 + Example: max77693@66 { compatible = "maxim,max77693"; @@ -73,4 +108,14 @@ Example: pwms = <&pwm 0 40000 0>; pwm-names = "haptic"; }; + + charger { + compatible = "maxim,max77693-charger"; + + maxim,constant-microvolt = <4200000>; + maxim,min-system-microvolt = <3600000>; + maxim,thermal-regulation-celsius = <75>; + maxim,battery-overcurrent-microamp = <3000000>; + maxim,charge-input-threshold-microvolt = <4300000>; + }; }; diff --git a/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt b/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt index b97b8bef1fe5..47b205cc9cc7 100644 --- a/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt +++ b/Documentation/devicetree/bindings/misc/nvidia,tegra20-apbmisc.txt @@ -1,11 +1,10 @@ NVIDIA Tegra20/Tegra30/Tegr114/Tegra124 apbmisc block Required properties: -- compatible : should be: - "nvidia,tegra20-apbmisc" - "nvidia,tegra30-apbmisc" - "nvidia,tegra114-apbmisc" - "nvidia,tegra124-apbmisc" +- compatible : For Tegra20, must be "nvidia,tegra20-apbmisc". For Tegra30, + must be "nvidia,tegra30-apbmisc". Otherwise, must contain + "nvidia,-apbmisc", plus one of the above, where is tegra114, + tegra124, tegra132. - reg: Should contain 2 entries: the first entry gives the physical address and length of the registers which contain revision and debug features. The second entry gives the physical address and length of the diff --git a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-emmc.txt b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-emmc.txt new file mode 100644 index 000000000000..0cb827bf9435 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-emmc.txt @@ -0,0 +1,25 @@ +* The simple eMMC hardware reset provider + +The purpose of this driver is to perform standard eMMC hw reset +procedure, as descibed by Jedec 4.4 specification. This procedure is +performed just after MMC core enabled power to the given mmc host (to +fix possible issues if bootloader has left eMMC card in initialized or +unknown state), and before performing complete system reboot (also in +case of emergency reboot call). The latter is needed on boards, which +doesn't have hardware reset logic connected to emmc card and (limited or +broken) ROM bootloaders are unable to read second stage from the emmc +card if the card is left in unknown or already initialized state. + +Required properties: +- compatible : contains "mmc-pwrseq-emmc". +- reset-gpios : contains a GPIO specifier. The reset GPIO is asserted + and then deasserted to perform eMMC card reset. To perform + reset procedure as described in Jedec 4.4 specification, the + gpio line should be defined as GPIO_ACTIVE_LOW. + +Example: + + sdhci0_pwrseq { + compatible = "mmc-pwrseq-emmc"; + reset-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>; + } diff --git a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt new file mode 100644 index 000000000000..a462c50f19a8 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt @@ -0,0 +1,25 @@ +* The simple MMC power sequence provider + +The purpose of the simple MMC power sequence provider is to supports a set of +common properties between various SOC designs. It thus enables us to use the +same provider for several SOC designs. + +Required properties: +- compatible : contains "mmc-pwrseq-simple". + +Optional properties: +- reset-gpios : contains a list of GPIO specifiers. The reset GPIOs are asserted + at initialization and prior we start the power up procedure of the card. + They will be de-asserted right after the power has been provided to the + card. +- clocks : Must contain an entry for the entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entry: + "ext_clock" (External clock provided to the card). + +Example: + + sdhci0_pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio1 12 0>; + } diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt index b52628b18a53..438899e8829b 100644 --- a/Documentation/devicetree/bindings/mmc/mmc.txt +++ b/Documentation/devicetree/bindings/mmc/mmc.txt @@ -64,7 +64,43 @@ Optional SDIO properties: - keep-power-in-suspend: Preserves card power during a suspend/resume cycle - enable-sdio-wakeup: Enables wake up of host system on SDIO IRQ assertion -Example: + +MMC power sequences: +-------------------- + +System on chip designs may specify a specific MMC power sequence. To +successfully detect an (e)MMC/SD/SDIO card, that power sequence must be +maintained while initializing the card. + +Optional property: +- mmc-pwrseq: phandle to the MMC power sequence node. See "mmc-pwrseq-*" + for documentation of MMC power sequence bindings. + + +Use of Function subnodes +------------------------ + +On embedded systems the cards connected to a host may need additional +properties. These can be specified in subnodes to the host controller node. +The subnodes are identified by the standard 'reg' property. +Which information exactly can be specified depends on the bindings for the +SDIO function driver for the subnode, as specified by the compatible string. + +Required host node properties when using function subnodes: +- #address-cells: should be one. The cell is the slot id. +- #size-cells: should be zero. + +Required function subnode properties: +- compatible: name of SDIO function following generic names recommended practice +- reg: Must contain the SDIO function number of the function this subnode + describes. A value of 0 denotes the memory SD function, values from + 1 to 7 denote the SDIO functions. + + +Examples +-------- + +Basic example: sdhci@ab000000 { compatible = "sdhci"; @@ -77,4 +113,28 @@ sdhci@ab000000 { max-frequency = <50000000>; keep-power-in-suspend; enable-sdio-wakeup; + mmc-pwrseq = <&sdhci0_pwrseq> } + +Example with sdio function subnode: + +mmc3: mmc@01c12000 { + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-names = "default"; + pinctrl-0 = <&mmc3_pins_a>; + vmmc-supply = <®_vmmc3>; + bus-width = <4>; + non-removable; + mmc-pwrseq = <&sdhci0_pwrseq> + status = "okay"; + + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm43xx-fmac"; + interrupt-parent = <&pio>; + interrupts = <10 8>; /* PH10 / EINT10 */ + interrupt-names = "host-wake"; + }; +}; diff --git a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt index f357c16ea815..15b8368ee1f2 100644 --- a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt @@ -7,7 +7,11 @@ This file documents differences between the core properties described by mmc.txt and the properties used by the sdhci-tegra driver. Required properties: -- compatible : Should be "nvidia,-sdhci" +- compatible : For Tegra20, must contain "nvidia,tegra20-sdhci". + For Tegra30, must contain "nvidia,tegra30-sdhci". For Tegra114, + must contain "nvidia,tegra114-sdhci". For Tegra124, must contain + "nvidia,tegra124-sdhci". Otherwise, must contain "nvidia,-sdhci", + plus one of the above, where is tegra132 or tegra210. - clocks : Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. - resets : Must contain an entry for each entry in reset-names. diff --git a/Documentation/devicetree/bindings/mmc/sdhci-fujitsu.txt b/Documentation/devicetree/bindings/mmc/sdhci-fujitsu.txt new file mode 100644 index 000000000000..de2c53cff4f1 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/sdhci-fujitsu.txt @@ -0,0 +1,30 @@ +* Fujitsu SDHCI controller + +This file documents differences between the core properties in mmc.txt +and the properties used by the sdhci_f_sdh30 driver. + +Required properties: +- compatible: "fujitsu,mb86s70-sdhci-3.0" +- clocks: Must contain an entry for each entry in clock-names. It is a + list of phandles and clock-specifier pairs. + See ../clocks/clock-bindings.txt for details. +- clock-names: Should contain the following two entries: + "iface" - clock used for sdhci interface + "core" - core clock for sdhci controller + +Optional properties: +- vqmmc-supply: phandle to the regulator device tree node, mentioned + as the VCCQ/VDD_IO supply in the eMMC/SD specs. + +Example: + + sdhci1: mmc@36600000 { + compatible = "fujitsu,mb86s70-sdhci-3.0"; + reg = <0 0x36600000 0x1000>; + interrupts = <0 172 0x4>, + <0 173 0x4>; + bus-width = <4>; + vqmmc-supply = <&vccq_sdhci1>; + clocks = <&clock 2 2 0>, <&clock 2 3 0>; + clock-names = "iface", "core"; + }; diff --git a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt index 4dd6deb90719..3d1b449d6097 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt @@ -9,9 +9,13 @@ Required properties: - reg: * for "mrvl,pxav2-mmc" and "mrvl,pxav3-mmc", one register area for the SDHCI registers. - * for "marvell,armada-380-sdhci", two register areas. The first one - for the SDHCI registers themselves, and the second one for the - AXI/Mbus bridge registers of the SDHCI unit. + + * for "marvell,armada-380-sdhci", three register areas. The first + one for the SDHCI registers themselves, the second one for the + AXI/Mbus bridge registers of the SDHCI unit, the third one for the + SDIO3 Configuration register +- reg names: should be "sdhci", "mbus", "conf-sdio3". only mandatory + for "marvell,armada-380-sdhci" - clocks: Array of clocks required for SDHCI; requires at least one for I/O clock. - clock-names: Array of names corresponding to clocks property; shall be @@ -35,7 +39,10 @@ sdhci@d4280800 { sdhci@d8000 { compatible = "marvell,armada-380-sdhci"; - reg = <0xd8000 0x1000>, <0xdc000 0x100>; + reg-names = "sdhci", "mbus", "conf-sdio3"; + reg = <0xd8000 0x1000>, + <0xdc000 0x100>; + <0x18454 0x4>; interrupts = <0 25 0x4>; clocks = <&gateclk 17>; clock-names = "io"; diff --git a/Documentation/devicetree/bindings/mtd/fsmc-nand.txt b/Documentation/devicetree/bindings/mtd/fsmc-nand.txt index ec42935f3908..5235cbc551b0 100644 --- a/Documentation/devicetree/bindings/mtd/fsmc-nand.txt +++ b/Documentation/devicetree/bindings/mtd/fsmc-nand.txt @@ -9,7 +9,7 @@ Required properties: Optional properties: - bank-width : Width (in bytes) of the device. If not present, the width defaults to 1 byte -- nand-skip-bbtscan: Indicates the the BBT scanning should be skipped +- nand-skip-bbtscan: Indicates the BBT scanning should be skipped - timings: array of 6 bytes for NAND timings. The meanings of these bytes are: byte 0 TCLR : CLE to RE delay in number of AHB clock cycles, only 4 bits diff --git a/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt b/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt index 42409bfe04c4..33df3932168e 100644 --- a/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt +++ b/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt @@ -7,17 +7,38 @@ Required properties: - SerDes Rx/Tx registers - SerDes integration registers (1/2) - SerDes integration registers (2/2) +- interrupt-parent: Should be the phandle for the interrupt controller + that services interrupts for this device +- interrupts: Should contain the amd-xgbe-phy interrupt. Optional properties: - amd,speed-set: Speed capabilities of the device 0 - 1GbE and 10GbE (default) 1 - 2.5GbE and 10GbE +The following optional properties are represented by an array with each +value corresponding to a particular speed. The first array value represents +the setting for the 1GbE speed, the second value for the 2.5GbE speed and +the third value for the 10GbE speed. All three values are required if the +property is used. +- amd,serdes-blwc: Baseline wandering correction enablement + 0 - Off + 1 - On +- amd,serdes-cdr-rate: CDR rate speed selection +- amd,serdes-pq-skew: PQ (data sampling) skew +- amd,serdes-tx-amp: TX amplitude boost + Example: xgbe_phy@e1240800 { compatible = "amd,xgbe-phy-seattle-v1a", "ethernet-phy-ieee802.3-c45"; reg = <0 0xe1240800 0 0x00400>, <0 0xe1250000 0 0x00060>, <0 0xe1250080 0 0x00004>; + interrupt-parent = <&gic>; + interrupts = <0 323 4>; amd,speed-set = <0>; + amd,serdes-blwc = <1>, <1>, <0>; + amd,serdes-cdr-rate = <2>, <2>, <7>; + amd,serdes-pq-skew = <10>, <10>, <30>; + amd,serdes-tx-amp = <15>, <15>, <10>; }; diff --git a/Documentation/devicetree/bindings/net/broadcom-systemport.txt b/Documentation/devicetree/bindings/net/broadcom-systemport.txt index aa7ad622259d..877da34145b0 100644 --- a/Documentation/devicetree/bindings/net/broadcom-systemport.txt +++ b/Documentation/devicetree/bindings/net/broadcom-systemport.txt @@ -3,7 +3,7 @@ Required properties: - compatible: should be one of "brcm,systemport-v1.00" or "brcm,systemport" - reg: address and length of the register set for the device. -- interrupts: interrupts for the device, first cell must be for the the rx +- interrupts: interrupts for the device, first cell must be for the rx interrupts, and the second cell should be for the transmit queues. An optional third interrupt cell for Wake-on-LAN can be specified - local-mac-address: Ethernet MAC address (48 bits) of this adapter diff --git a/Documentation/devicetree/bindings/net/davicom-dm9000.txt b/Documentation/devicetree/bindings/net/davicom-dm9000.txt index 28767ed7c1bd..5224bf05f6f8 100644 --- a/Documentation/devicetree/bindings/net/davicom-dm9000.txt +++ b/Documentation/devicetree/bindings/net/davicom-dm9000.txt @@ -11,6 +11,8 @@ Required properties: Optional properties: - davicom,no-eeprom : Configuration EEPROM is not available - davicom,ext-phy : Use external PHY +- reset-gpios : phandle of gpio that will be used to reset chip during probe +- vcc-supply : phandle of regulator that will be used to enable power to chip Example: @@ -21,4 +23,6 @@ Example: interrupts = <7 4>; local-mac-address = [00 00 de ad be ef]; davicom,no-eeprom; + reset-gpios = <&gpf 12 GPIO_ACTIVE_LOW>; + vcc-supply = <ð0_power>; }; diff --git a/Documentation/devicetree/bindings/net/davinci_emac.txt b/Documentation/devicetree/bindings/net/davinci_emac.txt index 032808843f90..24c5cdaba8d2 100644 --- a/Documentation/devicetree/bindings/net/davinci_emac.txt +++ b/Documentation/devicetree/bindings/net/davinci_emac.txt @@ -4,7 +4,8 @@ This file provides information, what the device node for the davinci_emac interface contains. Required properties: -- compatible: "ti,davinci-dm6467-emac" or "ti,am3517-emac" +- compatible: "ti,davinci-dm6467-emac", "ti,am3517-emac" or + "ti,dm816-emac" - reg: Offset and length of the register set for the device - ti,davinci-ctrl-reg-offset: offset to control register - ti,davinci-ctrl-mod-reg-offset: offset to control module register diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt index 0c8775c45798..a9eb611bee68 100644 --- a/Documentation/devicetree/bindings/net/fsl-fec.txt +++ b/Documentation/devicetree/bindings/net/fsl-fec.txt @@ -22,6 +22,8 @@ Optional properties: - fsl,num-rx-queues : The property is valid for enet-avb IP, which supports hw multi queues. Should specify the rx queue number, otherwise set rx queue number to 1. +- fsl,magic-packet : If present, indicates that the hardware supports waking + up via magic packet. Optional subnodes: - mdio : specifies the mdio bus in the FEC, used as a container for phy nodes diff --git a/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt b/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt index be6ea8960f20..1e97532a0b79 100644 --- a/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt +++ b/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt @@ -8,7 +8,16 @@ of how to define a PHY. Required properties: - reg : Offset and length of the register set for the device - compatible : Should define the compatible device type for the - mdio. Currently, this is most likely to be "fsl,gianfar-mdio" + mdio. Currently supported strings/devices are: + - "fsl,gianfar-tbi" + - "fsl,gianfar-mdio" + - "fsl,etsec2-tbi" + - "fsl,etsec2-mdio" + - "fsl,ucc-mdio" + - "fsl,fman-mdio" + When device_type is "mdio", the following strings are also considered: + - "gianfar" + - "ucc_geth_phy" Example: diff --git a/Documentation/devicetree/bindings/net/hisilicon-hip04-net.txt b/Documentation/devicetree/bindings/net/hisilicon-hip04-net.txt new file mode 100644 index 000000000000..988fc694b663 --- /dev/null +++ b/Documentation/devicetree/bindings/net/hisilicon-hip04-net.txt @@ -0,0 +1,88 @@ +Hisilicon hip04 Ethernet Controller + +* Ethernet controller node + +Required properties: +- compatible: should be "hisilicon,hip04-mac". +- reg: address and length of the register set for the device. +- interrupts: interrupt for the device. +- port-handle: + phandle, specifies a reference to the syscon ppe node + port, port number connected to the controller + channel, recv channel start from channel * number (RX_DESC_NUM) +- phy-mode: see ethernet.txt [1]. + +Optional properties: +- phy-handle: see ethernet.txt [1]. + +[1] Documentation/devicetree/bindings/net/ethernet.txt + + +* Ethernet ppe node: +Control rx & tx fifos of all ethernet controllers. +Have 2048 recv channels shared by all ethernet controllers, only if no overlap. +Each controller's recv channel start from channel * number (RX_DESC_NUM). + +Required properties: +- compatible: "hisilicon,hip04-ppe", "syscon". +- reg: address and length of the register set for the device. + + +* MDIO bus node: + +Required properties: + +- compatible: should be "hisilicon,hip04-mdio". +- Inherits from MDIO bus node binding [2] +[2] Documentation/devicetree/bindings/net/phy.txt + +Example: + mdio { + compatible = "hisilicon,hip04-mdio"; + reg = <0x28f1000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + marvell,reg-init = <18 0x14 0 0x8001>; + }; + + phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + marvell,reg-init = <18 0x14 0 0x8001>; + }; + }; + + ppe: ppe@28c0000 { + compatible = "hisilicon,hip04-ppe", "syscon"; + reg = <0x28c0000 0x10000>; + }; + + fe: ethernet@28b0000 { + compatible = "hisilicon,hip04-mac"; + reg = <0x28b0000 0x10000>; + interrupts = <0 413 4>; + phy-mode = "mii"; + port-handle = <&ppe 31 0>; + }; + + ge0: ethernet@2800000 { + compatible = "hisilicon,hip04-mac"; + reg = <0x2800000 0x10000>; + interrupts = <0 402 4>; + phy-mode = "sgmii"; + port-handle = <&ppe 0 1>; + phy-handle = <&phy0>; + }; + + ge8: ethernet@2880000 { + compatible = "hisilicon,hip04-mac"; + reg = <0x2880000 0x10000>; + interrupts = <0 410 4>; + phy-mode = "sgmii"; + port-handle = <&ppe 8 2>; + phy-handle = <&phy1>; + }; diff --git a/Documentation/devicetree/bindings/net/keystone-netcp.txt b/Documentation/devicetree/bindings/net/keystone-netcp.txt new file mode 100644 index 000000000000..f9c07710478d --- /dev/null +++ b/Documentation/devicetree/bindings/net/keystone-netcp.txt @@ -0,0 +1,197 @@ +This document describes the device tree bindings associated with the +keystone network coprocessor(NetCP) driver support. + +The network coprocessor (NetCP) is a hardware accelerator that processes +Ethernet packets. NetCP has a gigabit Ethernet (GbE) subsytem with a ethernet +switch sub-module to send and receive packets. NetCP also includes a packet +accelerator (PA) module to perform packet classification operations such as +header matching, and packet modification operations such as checksum +generation. NetCP can also optionally include a Security Accelerator (SA) +capable of performing IPSec operations on ingress/egress packets. + +Keystone II SoC's also have a 10 Gigabit Ethernet Subsystem (XGbE) which +includes a 3-port Ethernet switch sub-module capable of 10Gb/s and 1Gb/s rates +per Ethernet port. + +Keystone NetCP driver has a plug-in module architecture where each of the NetCP +sub-modules exist as a loadable kernel module which plug in to the netcp core. +These sub-modules are represented as "netcp-devices" in the dts bindings. It is +mandatory to have the ethernet switch sub-module for the ethernet interface to +be operational. Any other sub-module like the PA is optional. + +NetCP Ethernet SubSystem Layout: + +----------------------------- + NetCP subsystem(10G or 1G) +----------------------------- + | + |-> NetCP Devices -> | + | |-> GBE/XGBE Switch + | | + | |-> Packet Accelerator + | | + | |-> Security Accelerator + | + | + | + |-> NetCP Interfaces -> | + |-> Ethernet Port 0 + | + |-> Ethernet Port 1 + | + |-> Ethernet Port 2 + | + |-> Ethernet Port 3 + + +NetCP subsystem properties: +Required properties: +- compatible: Should be "ti,netcp-1.0" +- clocks: phandle to the reference clocks for the subsystem. +- dma-id: Navigator packet dma instance id. + +Optional properties: +- reg: register location and the size for the following register + regions in the specified order. + - Efuse MAC address register +- dma-coherent: Present if dma operations are coherent +- big-endian: Keystone devices can be operated in a mode where the DSP is in + the big endian mode. In such cases enable this option. This + option should also be enabled if the ARM is operated in + big endian mode with the DSP in little endian. + +NetCP device properties: Device specification for NetCP sub-modules. +1Gb/10Gb (gbe/xgbe) ethernet switch sub-module specifications. +Required properties: +- label: Must be "netcp-gbe" for 1Gb & "netcp-xgbe" for 10Gb. +- reg: register location and the size for the following register + regions in the specified order. + - subsystem registers + - serdes registers +- tx-channel: the navigator packet dma channel name for tx. +- tx-queue: the navigator queue number associated with the tx dma channel. +- interfaces: specification for each of the switch port to be registered as a + network interface in the stack. +-- slave-port: Switch port number, 0 based numbering. +-- link-interface: type of link interface, supported options are + - mac<->mac auto negotiate mode: 0 + - mac<->phy mode: 1 + - mac<->mac forced mode: 2 + - mac<->fiber mode: 3 + - mac<->phy mode with no mdio: 4 + - 10Gb mac<->phy mode : 10 + - 10Gb mac<->mac forced mode : 11 +----phy-handle: phandle to PHY device + +Optional properties: +- enable-ale: NetCP driver keeps the address learning feature in the ethernet + switch module disabled. This attribute is to enable the address + learning. +- secondary-slave-ports: specification for each of the switch port not be + registered as a network interface. NetCP driver + will only initialize these ports and attach PHY + driver to them if needed. + +NetCP interface properties: Interface specification for NetCP sub-modules. +Required properties: +- rx-channel: the navigator packet dma channel name for rx. +- rx-queue: the navigator queue number associated with rx dma channel. +- rx-pool: specifies the number of descriptors to be used & the region-id + for creating the rx descriptor pool. +- tx-pool: specifies the number of descriptors to be used & the region-id + for creating the tx descriptor pool. +- rx-queue-depth: number of descriptors in each of the free descriptor + queue (FDQ) for the pktdma Rx flow. There can be at + present a maximum of 4 queues per Rx flow. +- rx-buffer-size: the buffer size for each of the Rx flow FDQ. +- tx-completion-queue: the navigator queue number where the descriptors are + recycled after Tx DMA completion. + +Optional properties: +- efuse-mac: If this is 1, then the MAC address for the interface is + obtained from the device efuse mac address register +- local-mac-address: the driver is designed to use the of_get_mac_address api + only if efuse-mac is 0. When efuse-mac is 0, the MAC + address is obtained from local-mac-address. If this + attribute is not present, then the driver will use a + random MAC address. +- "netcp-device label": phandle to the device specification for each of NetCP + sub-module attached to this interface. + +Example binding: + +netcp: netcp@2090000 { + reg = <0x2620110 0x8>; + reg-names = "efuse"; + compatible = "ti,netcp-1.0"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + clocks = <&papllclk>, <&clkcpgmac>, <&chipclk12>; + dma-coherent; + /* big-endian; */ + dma-id = <0>; + + netcp-devices { + #address-cells = <1>; + #size-cells = <1>; + ranges; + gbe@0x2090000 { + label = "netcp-gbe"; + reg = <0x2090000 0xf00>; + /* enable-ale; */ + tx-queue = <648>; + tx-channel = <8>; + + interfaces { + gbe0: interface-0 { + slave-port = <0>; + link-interface = <4>; + }; + gbe1: interface-1 { + slave-port = <1>; + link-interface = <4>; + }; + }; + + secondary-slave-ports { + port-2 { + slave-port = <2>; + link-interface = <2>; + }; + port-3 { + slave-port = <3>; + link-interface = <2>; + }; + }; + }; + }; + + netcp-interfaces { + interface-0 { + rx-channel = <22>; + rx-pool = <1024 12>; + tx-pool = <1024 12>; + rx-queue-depth = <128 128 0 0>; + rx-buffer-size = <1518 4096 0 0>; + rx-queue = <8704>; + tx-completion-queue = <8706>; + efuse-mac = <1>; + netcp-gbe = <&gbe0>; + + }; + interface-1 { + rx-channel = <23>; + rx-pool = <1024 12>; + tx-pool = <1024 12>; + rx-queue-depth = <128 128 0 0>; + rx-buffer-size = <1518 4096 0 0>; + rx-queue = <8705>; + tx-completion-queue = <8707>; + efuse-mac = <0>; + local-mac-address = [02 18 31 7e 3e 6f]; + netcp-gbe = <&gbe1>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/net/nfc/st21nfca.txt b/Documentation/devicetree/bindings/net/nfc/st21nfca.txt index e4faa2e8dfeb..7bb2e213d6f9 100644 --- a/Documentation/devicetree/bindings/net/nfc/st21nfca.txt +++ b/Documentation/devicetree/bindings/net/nfc/st21nfca.txt @@ -1,7 +1,7 @@ * STMicroelectronics SAS. ST21NFCA NFC Controller Required properties: -- compatible: Should be "st,st21nfca_i2c". +- compatible: Should be "st,st21nfca-i2c". - clock-frequency: I²C work frequency. - reg: address on the bus - interrupt-parent: phandle for the interrupt gpio controller @@ -11,6 +11,10 @@ Required properties: Optional SoC Specific Properties: - pinctrl-names: Contains only one value - "default". - pintctrl-0: Specifies the pin control groups used for this controller. +- ese-present: Specifies that an ese is physically connected to the nfc +controller. +- uicc-present: Specifies that the uicc swp signal can be physically +connected to the nfc controller. Example (for ARM-based BeagleBoard xM with ST21NFCA on I2C2): @@ -20,7 +24,7 @@ Example (for ARM-based BeagleBoard xM with ST21NFCA on I2C2): st21nfca: st21nfca@1 { - compatible = "st,st21nfca_i2c"; + compatible = "st,st21nfca-i2c"; reg = <0x01>; clock-frequency = <400000>; @@ -29,5 +33,8 @@ Example (for ARM-based BeagleBoard xM with ST21NFCA on I2C2): interrupts = <2 IRQ_TYPE_LEVEL_LOW>; enable-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>; + + ese-present; + uicc-present; }; }; diff --git a/Documentation/devicetree/bindings/net/nfc/st21nfcb.txt b/Documentation/devicetree/bindings/net/nfc/st21nfcb.txt index 9005608cbbd1..bb237072dbe9 100644 --- a/Documentation/devicetree/bindings/net/nfc/st21nfcb.txt +++ b/Documentation/devicetree/bindings/net/nfc/st21nfcb.txt @@ -1,7 +1,7 @@ * STMicroelectronics SAS. ST21NFCB NFC Controller Required properties: -- compatible: Should be "st,st21nfcb_i2c". +- compatible: Should be "st,st21nfcb-i2c". - clock-frequency: I²C work frequency. - reg: address on the bus - interrupt-parent: phandle for the interrupt gpio controller @@ -20,7 +20,7 @@ Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2): st21nfcb: st21nfcb@8 { - compatible = "st,st21nfcb_i2c"; + compatible = "st,st21nfcb-i2c"; reg = <0x08>; clock-frequency = <400000>; diff --git a/Documentation/devicetree/bindings/net/rockchip-dwmac.txt b/Documentation/devicetree/bindings/net/rockchip-dwmac.txt new file mode 100644 index 000000000000..21fd199e89b5 --- /dev/null +++ b/Documentation/devicetree/bindings/net/rockchip-dwmac.txt @@ -0,0 +1,68 @@ +Rockchip SoC RK3288 10/100/1000 Ethernet driver(GMAC) + +The device node has following properties. + +Required properties: + - compatible: Can be "rockchip,rk3288-gmac". + - reg: addresses and length of the register sets for the device. + - interrupts: Should contain the GMAC interrupts. + - interrupt-names: Should contain the interrupt names "macirq". + - rockchip,grf: phandle to the syscon grf used to control speed and mode. + - clocks: <&cru SCLK_MAC>: clock selector for main clock, from PLL or PHY. + <&cru SCLK_MAC_PLL>: PLL clock for SCLK_MAC + <&cru SCLK_MAC_RX>: clock gate for RX + <&cru SCLK_MAC_TX>: clock gate for TX + <&cru SCLK_MACREF>: clock gate for RMII referce clock + <&cru SCLK_MACREF_OUT> clock gate for RMII reference clock output + <&cru ACLK_GMAC>: AXI clock gate for GMAC + <&cru PCLK_GMAC>: APB clock gate for GMAC + - clock-names: One name for each entry in the clocks property. + - phy-mode: See ethernet.txt file in the same directory. + - pinctrl-names: Names corresponding to the numbered pinctrl states. + - pinctrl-0: pin-control mode. can be <&rgmii_pins> or <&rmii_pins>. + - clock_in_out: For RGMII, it must be "input", means main clock(125MHz) + is not sourced from SoC's PLL, but input from PHY; For RMII, "input" means + PHY provides the reference clock(50MHz), "output" means GMAC provides the + reference clock. + - snps,reset-gpio gpio number for phy reset. + - snps,reset-active-low boolean flag to indicate if phy reset is active low. + - assigned-clocks: main clock, should be <&cru SCLK_MAC>; + - assigned-clock-parents = parent of main clock. + can be <&ext_gmac> or <&cru SCLK_MAC_PLL>. + +Optional properties: + - tx_delay: Delay value for TXD timing. Range value is 0~0x7F, 0x30 as default. + - rx_delay: Delay value for RXD timing. Range value is 0~0x7F, 0x10 as default. + - phy-supply: phandle to a regulator if the PHY needs one + +Example: + +gmac: ethernet@ff290000 { + compatible = "rockchip,rk3288-gmac"; + reg = <0xff290000 0x10000>; + interrupts = ; + interrupt-names = "macirq"; + rockchip,grf = <&grf>; + clocks = <&cru SCLK_MAC>, + <&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>, + <&cru SCLK_MACREF>, <&cru SCLK_MACREF_OUT>, + <&cru ACLK_GMAC>, <&cru PCLK_GMAC>; + clock-names = "stmmaceth", + "mac_clk_rx", "mac_clk_tx", + "clk_mac_ref", "clk_mac_refout", + "aclk_mac", "pclk_mac"; + phy-mode = "rgmii"; + pinctrl-names = "default"; + pinctrl-0 = <&rgmii_pins /*&rmii_pins*/>; + + clock_in_out = "input"; + snps,reset-gpio = <&gpio4 7 0>; + snps,reset-active-low; + + assigned-clocks = <&cru SCLK_MAC>; + assigned-clock-parents = <&ext_gmac>; + tx_delay = <0x30>; + rx_delay = <0x10>; + + status = "ok"; +}; diff --git a/Documentation/devicetree/bindings/net/sti-dwmac.txt b/Documentation/devicetree/bindings/net/sti-dwmac.txt index 6762a6b5da7e..d05c1e1fd9b6 100644 --- a/Documentation/devicetree/bindings/net/sti-dwmac.txt +++ b/Documentation/devicetree/bindings/net/sti-dwmac.txt @@ -9,14 +9,10 @@ The device node has following properties. Required properties: - compatible : Can be "st,stih415-dwmac", "st,stih416-dwmac", "st,stih407-dwmac", "st,stid127-dwmac". - - reg : Offset of the glue configuration register map in system - configuration regmap pointed by st,syscon property and size. - - st,syscon : Should be phandle to system configuration node which - encompases this glue registers. + - st,syscon : Should be phandle/offset pair. The phandle to the syscon node which + encompases the glue register, and the offset of the control register. - st,gmac_en: this is to enable the gmac into a dedicated sysctl control register available on STiH407 SoC. - - sti-ethconf: this is the gmac glue logic register to enable the GMAC, - select among the different modes and program the clk retiming. - pinctrl-0: pin-control for all the MII mode supported. Optional properties: @@ -40,10 +36,10 @@ ethernet0: dwmac@9630000 { device_type = "network"; status = "disabled"; compatible = "st,stih407-dwmac", "snps,dwmac", "snps,dwmac-3.710"; - reg = <0x9630000 0x8000>, <0x80 0x4>; - reg-names = "stmmaceth", "sti-ethconf"; + reg = <0x9630000 0x8000>; + reg-names = "stmmaceth"; - st,syscon = <&syscfg_sbc_reg>; + st,syscon = <&syscfg_sbc_reg 0x80>; st,gmac_en; resets = <&softreset STIH407_ETH1_SOFTRESET>; reset-names = "stmmaceth"; diff --git a/Documentation/devicetree/bindings/net/stmmac.txt b/Documentation/devicetree/bindings/net/stmmac.txt index c41afd963edf..8ca65cec52ae 100644 --- a/Documentation/devicetree/bindings/net/stmmac.txt +++ b/Documentation/devicetree/bindings/net/stmmac.txt @@ -43,6 +43,7 @@ Optional properties: available this clock is used for programming the Timestamp Addend Register. If not passed then the system clock will be used and this is fine on some platforms. +- snps,burst_len: The AXI burst lenth value of the AXI BUS MODE register. Examples: diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt new file mode 100644 index 000000000000..edefc26c6204 --- /dev/null +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt @@ -0,0 +1,30 @@ +* Qualcomm Atheros ath10k wireless devices + +For ath10k devices the calibration data can be provided through Device +Tree. The node is a child node of the PCI controller. + +Required properties: +-compatible : Should be "qcom,ath10k" + +Optional properties: +- qcom,ath10k-calibration-data : calibration data as an array, the + length can vary between hw versions + + +Example: + +pci { + pcie@0 { + reg = <0 0 0 0 0>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + + ath10k@0,0 { + reg = <0 0 0 0 0>; + device_type = "pci"; + qcom,ath10k-calibration-data = [ 01 02 03 ... ]; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt index d763e047c6ae..75321ae23c08 100644 --- a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt +++ b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt @@ -1,10 +1,10 @@ NVIDIA Tegra PCIe controller Required properties: -- compatible: Must be one of: - - "nvidia,tegra20-pcie" - - "nvidia,tegra30-pcie" - - "nvidia,tegra124-pcie" +- compatible: For Tegra20, must contain "nvidia,tegra20-pcie". For Tegra30, + "nvidia,tegra30-pcie". For Tegra124, must contain "nvidia,tegra124-pcie". + Otherwise, must contain "nvidia,-pcie", plus one of the above, where + is tegra132 or tegra210. - device_type: Must be "pci" - reg: A list of physical base address and length for each set of controller registers. Must contain an entry for each entry in the reg-names property. diff --git a/Documentation/devicetree/bindings/pci/versatile.txt b/Documentation/devicetree/bindings/pci/versatile.txt new file mode 100644 index 000000000000..ebd1e7d0403e --- /dev/null +++ b/Documentation/devicetree/bindings/pci/versatile.txt @@ -0,0 +1,59 @@ +* ARM Versatile Platform Baseboard PCI interface + +PCI host controller found on the ARM Versatile PB board's FPGA. + +Required properties: +- compatible: should contain "arm,versatile-pci" to identify the Versatile PCI + controller. +- reg: base addresses and lengths of the pci controller. There must be 3 + entries: + - Versatile-specific registers + - Self Config space + - Config space +- #address-cells: set to <3> +- #size-cells: set to <2> +- device_type: set to "pci" +- bus-range: set to <0 0xff> +- ranges: ranges for the PCI memory and I/O regions +- #interrupt-cells: set to <1> +- interrupt-map-mask and interrupt-map: standard PCI properties to define + the mapping of the PCI interface to interrupt numbers. + +Example: + +pci-controller@10001000 { + compatible = "arm,versatile-pci"; + device_type = "pci"; + reg = <0x10001000 0x1000 + 0x41000000 0x10000 + 0x42000000 0x100000>; + bus-range = <0 0xff>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + ranges = <0x01000000 0 0x00000000 0x43000000 0 0x00010000 /* downstream I/O */ + 0x02000000 0 0x50000000 0x50000000 0 0x10000000 /* non-prefetchable memory */ + 0x42000000 0 0x60000000 0x60000000 0 0x10000000>; /* prefetchable memory */ + + interrupt-map-mask = <0x1800 0 0 7>; + interrupt-map = <0x1800 0 0 1 &sic 28 + 0x1800 0 0 2 &sic 29 + 0x1800 0 0 3 &sic 30 + 0x1800 0 0 4 &sic 27 + + 0x1000 0 0 1 &sic 27 + 0x1000 0 0 2 &sic 28 + 0x1000 0 0 3 &sic 29 + 0x1000 0 0 4 &sic 30 + + 0x0800 0 0 1 &sic 30 + 0x0800 0 0 2 &sic 27 + 0x0800 0 0 3 &sic 28 + 0x0800 0 0 4 &sic 29 + + 0x0000 0 0 1 &sic 29 + 0x0000 0 0 2 &sic 30 + 0x0000 0 0 3 &sic 27 + 0x0000 0 0 4 &sic 28>; +}; diff --git a/Documentation/devicetree/bindings/phy/phy-miphy365x.txt b/Documentation/devicetree/bindings/phy/phy-miphy365x.txt index 42c880886cf7..9802d5d911aa 100644 --- a/Documentation/devicetree/bindings/phy/phy-miphy365x.txt +++ b/Documentation/devicetree/bindings/phy/phy-miphy365x.txt @@ -6,8 +6,10 @@ for SATA and PCIe. Required properties (controller (parent) node): - compatible : Should be "st,miphy365x-phy" -- st,syscfg : Should be a phandle of the system configuration register group - which contain the SATA, PCIe mode setting bits +- st,syscfg : Phandle / integer array property. Phandle of sysconfig group + containing the miphy registers and integer array should contain + an entry for each port sub-node, specifying the control + register offset inside the sysconfig group. Required nodes : A sub-node is required for each channel the controller provides. Address range information including the usual @@ -26,7 +28,6 @@ Required properties (port (child) node): registers filled in "reg": - sata: For SATA devices - pcie: For PCIe devices - - syscfg: To specify the syscfg based config register Optional properties (port (child) node): - st,sata-gen : Generation of locally attached SATA IP. Expected values @@ -39,20 +40,20 @@ Example: miphy365x_phy: miphy365x@fe382000 { compatible = "st,miphy365x-phy"; - st,syscfg = <&syscfg_rear>; + st,syscfg = <&syscfg_rear 0x824 0x828>; #address-cells = <1>; #size-cells = <1>; ranges; phy_port0: port@fe382000 { - reg = <0xfe382000 0x100>, <0xfe394000 0x100>, <0x824 0x4>; - reg-names = "sata", "pcie", "syscfg"; + reg = <0xfe382000 0x100>, <0xfe394000 0x100>; + reg-names = "sata", "pcie"; #phy-cells = <1>; st,sata-gen = <3>; }; phy_port1: port@fe38a000 { - reg = <0xfe38a000 0x100>, <0xfe804000 0x100>, <0x828 0x4>;; + reg = <0xfe38a000 0x100>, <0xfe804000 0x100>;; reg-names = "sata", "pcie", "syscfg"; #phy-cells = <1>; st,pcie-tx-pol-inv; diff --git a/Documentation/devicetree/bindings/phy/phy-stih407-usb.txt b/Documentation/devicetree/bindings/phy/phy-stih407-usb.txt index 1ef8228db73b..de6a706abcdb 100644 --- a/Documentation/devicetree/bindings/phy/phy-stih407-usb.txt +++ b/Documentation/devicetree/bindings/phy/phy-stih407-usb.txt @@ -5,10 +5,7 @@ host controllers (when controlling usb2/1.1 devices) available on STiH407 SoC fa Required properties: - compatible : should be "st,stih407-usb2-phy" -- reg : contain the offset and length of the system configuration registers - used as glue logic to control & parameter phy -- reg-names : the names of the system configuration registers in "reg", should be "param" and "reg" -- st,syscfg : sysconfig register to manage phy parameter at driver level +- st,syscfg : phandle of sysconfig bank plus integer array containing phyparam and phyctrl register offsets - resets : list of phandle and reset specifier pairs. There should be two entries, one for the whole phy and one for the port - reset-names : list of reset signal names. Should be "global" and "port" @@ -19,11 +16,8 @@ Example: usb2_picophy0: usbpicophy@f8 { compatible = "st,stih407-usb2-phy"; - reg = <0xf8 0x04>, /* syscfg 5062 */ - <0xf4 0x04>; /* syscfg 5061 */ - reg-names = "param", "ctrl"; #phy-cells = <0>; - st,syscfg = <&syscfg_core>; + st,syscfg = <&syscfg_core 0x100 0xf4>; resets = <&softreset STIH407_PICOPHY_SOFTRESET>, <&picophyreset STIH407_PICOPHY0_RESET>; reset-names = "global", "port"; diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt index 93ce12eb422a..fdd8046e650a 100644 --- a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt @@ -11,6 +11,7 @@ Required properties: "allwinner,sun5i-a10s-pinctrl" "allwinner,sun5i-a13-pinctrl" "allwinner,sun6i-a31-pinctrl" + "allwinner,sun6i-a31s-pinctrl" "allwinner,sun6i-a31-r-pinctrl" "allwinner,sun7i-a20-pinctrl" "allwinner,sun8i-a23-pinctrl" diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt index 189814e7cdc7..ecb5c0d25218 100644 --- a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt +++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt @@ -6,7 +6,8 @@ nvidia,tegra30-pinmux.txt. In fact, this document assumes that binding as a baseline, and only documents the differences between the two bindings. Required properties: -- compatible: "nvidia,tegra124-pinmux" +- compatible: For Tegra124, must contain "nvidia,tegra124-pinmux". For + Tegra132, must contain '"nvidia,tegra132-pinmux", "nvidia-tegra124-pinmux"'. - reg: Should contain a list of base address and size pairs for: -- first entry - the drive strength and pad control registers. -- second entry - the pinmux registers diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt index 2f9c0bd66457..30676ded85bb 100644 --- a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt +++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt @@ -13,7 +13,9 @@ how to describe and reference PHYs in device trees. Required properties: -------------------- -- compatible: should be "nvidia,tegra124-xusb-padctl" +- compatible: For Tegra124, must contain "nvidia,tegra124-xusb-padctl". + Otherwise, must contain '"nvidia,-xusb-padctl", + "nvidia-tegra124-xusb-padctl"', where is tegra132 or tegra210. - reg: Physical base address and length of the controller's registers. - resets: Must contain an entry for each entry in reset-names. See ../reset/reset.txt for details. diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.txt new file mode 100644 index 000000000000..498caff6029e --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.txt @@ -0,0 +1,186 @@ +Qualcomm MSM8916 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +MSM8916 platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,msm8916-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. Valid pins are: + gpio0-gpio121, + sdc1_clk, + sdc1_cmd, + sdc1_data + sdc2_clk, + sdc2_cmd, + sdc2_data, + qdsd_cmd, + qdsd_data0, + qdsd_data1, + qdsd_data2, + qdsd_data3 + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + adsp_ext, alsp_int, atest_bbrx0, atest_bbrx1, atest_char, atest_char0, + atest_char1, atest_char2, atest_char3, atest_combodac, atest_gpsadc0, + atest_gpsadc1, atest_tsens, atest_wlan0, atest_wlan1, backlight_en, + bimc_dte0,bimc_dte1, blsp_i2c1, blsp_i2c2, blsp_i2c3, blsp_i2c4, + blsp_i2c5, blsp_i2c6, blsp_spi1, blsp_spi1_cs1, blsp_spi1_cs2, + blsp_spi1_cs3, blsp_spi2, blsp_spi2_cs1, blsp_spi2_cs2, blsp_spi2_cs3, + blsp_spi3, blsp_spi3_cs1, blsp_spi3_cs2, blsp_spi3_cs3, blsp_spi4, + blsp_spi5, blsp_spi6, blsp_uart1, blsp_uart2, blsp_uim1, blsp_uim2, + cam1_rst, cam1_standby, cam_mclk0, cam_mclk1, cci_async, cci_i2c, + cci_timer0, cci_timer1, cci_timer2, cdc_pdm0, codec_mad, dbg_out, + display_5v, dmic0_clk, dmic0_data, dsi_rst, ebi0_wrcdc, euro_us, + ext_lpass, flash_strobe, gcc_gp1_clk_a, gcc_gp1_clk_b, gcc_gp2_clk_a, + gcc_gp2_clk_b, gcc_gp3_clk_a, gcc_gp3_clk_b, gpio, gsm0_tx0, gsm0_tx1, + gsm1_tx0, gsm1_tx1, gyro_accl, kpsns0, kpsns1, kpsns2, ldo_en, + ldo_update, mag_int, mdp_vsync, modem_tsync, m_voc, nav_pps, nav_tsync, + pa_indicator, pbs0, pbs1, pbs2, pri_mi2s, pri_mi2s_ws, prng_rosc, + pwr_crypto_enabled_a, pwr_crypto_enabled_b, pwr_modem_enabled_a, + pwr_modem_enabled_b, pwr_nav_enabled_a, pwr_nav_enabled_b, + qdss_ctitrig_in_a0, qdss_ctitrig_in_a1, qdss_ctitrig_in_b0, + qdss_ctitrig_in_b1, qdss_ctitrig_out_a0, qdss_ctitrig_out_a1, + qdss_ctitrig_out_b0, qdss_ctitrig_out_b1, qdss_traceclk_a, + qdss_traceclk_b, qdss_tracectl_a, qdss_tracectl_b, qdss_tracedata_a, + qdss_tracedata_b, reset_n, sd_card, sd_write, sec_mi2s, smb_int, + ssbi_wtr0, ssbi_wtr1, uim1, uim2, uim3, uim_batt, wcss_bt, wcss_fm, + wcss_wlan, webcam1_rst + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@1000000 { + compatible = "qcom,msm8916-pinctrl"; + reg = <0x1000000 0x300000>; + interrupts = <0 208 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + + uart2: uart2-default { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart2"; + }; + + tx { + pins = "gpio4"; + drive-strength = <4>; + bias-disable; + }; + + rx { + pins = "gpio5"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt index daef6fad6a5f..bfe72ec055e3 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt @@ -1,7 +1,7 @@ * Renesas Pin Function Controller (GPIO and Pin Mux/Config) -The Pin Function Controller (PFC) is a Pin Mux/Config controller. On SH7372, -SH73A0, R8A73A4 and R8A7740 it also acts as a GPIO controller. +The Pin Function Controller (PFC) is a Pin Mux/Config controller. On SH73A0, +R8A73A4 and R8A7740 it also acts as a GPIO controller. Pin Control @@ -10,13 +10,13 @@ Pin Control Required Properties: - compatible: should be one of the following. + - "renesas,pfc-emev2": for EMEV2 (EMMA Mobile EV2) compatible pin-controller. - "renesas,pfc-r8a73a4": for R8A73A4 (R-Mobile APE6) compatible pin-controller. - "renesas,pfc-r8a7740": for R8A7740 (R-Mobile A1) compatible pin-controller. - "renesas,pfc-r8a7778": for R8A7778 (R-Mobile M1) compatible pin-controller. - "renesas,pfc-r8a7779": for R8A7779 (R-Car H1) compatible pin-controller. - "renesas,pfc-r8a7790": for R8A7790 (R-Car H2) compatible pin-controller. - "renesas,pfc-r8a7791": for R8A7791 (R-Car M2) compatible pin-controller. - - "renesas,pfc-sh7372": for SH7372 (SH-Mobile AP4) compatible pin-controller. - "renesas,pfc-sh73a0": for SH73A0 (SH-Mobile AG5) compatible pin-controller. - reg: Base address and length of each memory resource used by the pin @@ -75,8 +75,7 @@ bias-disable, bias-pull-up and bias-pull-down. GPIO ---- -On SH7372, SH73A0, R8A73A4 and R8A7740 the PFC node is also a GPIO controller -node. +On SH73A0, R8A73A4 and R8A7740 the PFC node is also a GPIO controller node. Required Properties: diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt index 8425838a6dff..9d2a995293e6 100644 --- a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt @@ -171,6 +171,18 @@ Aliases: All the pin controller nodes should be represented in the aliases node using the following format 'pinctrl{n}' where n is a unique number for the alias. +Aliases for controllers compatible with "samsung,exynos7-pinctrl": +- pinctrl0: pin controller of ALIVE block, +- pinctrl1: pin controller of BUS0 block, +- pinctrl2: pin controller of NFC block, +- pinctrl3: pin controller of TOUCH block, +- pinctrl4: pin controller of FF block, +- pinctrl5: pin controller of ESE block, +- pinctrl6: pin controller of FSYS0 block, +- pinctrl7: pin controller of FSYS1 block, +- pinctrl8: pin controller of BUS1 block, +- pinctrl9: pin controller of AUDIO block, + Example: A pin-controller node with pin banks: pinctrl_0: pinctrl@11400000 { diff --git a/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt b/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt index 6b33b9f18e88..f63fcb3ed352 100644 --- a/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt +++ b/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt @@ -16,17 +16,22 @@ mux function to select on those pin(s)/group(s), and various pin configuration parameters, such as input, output, pull up, pull down... The name of each subnode is not important; all subnodes should be enumerated -and processed purely based on their content. +and processed purely based on their content. The subnodes use the generic +pin multiplexing node layout from the standard pin control bindings +(see pinctrl-bindings.txt): -Required subnode-properties: -- ste,pins : An array of strings. Each string contains the name of a pin or - group. - -Optional subnode-properties: -- ste,function: A string containing the name of the function to mux to the +Required pin multiplexing subnode properties: +- function: A string containing the name of the function to mux to the pin or group. +- groups : An array of strings. Each string contains the name of a pin + group that will be combined with the function to form a multiplexing + set-up. -- ste,config: Handle of pin configuration node (e.g. ste,config = <&slpm_in_wkup_pdis>) +Required pin configuration subnode properties: +- pins: A string array describing the pins affected by the configuration + in the node. +- ste,config: Handle of pin configuration node + (e.g. ste,config = <&slpm_in_wkup_pdis>) - ste,input : <0/1/2> 0: input with no pull @@ -97,32 +102,32 @@ Example board file extract: uart0 { uart0_default_mux: uart0_mux { u0_default_mux { - ste,function = "u0"; - ste,pins = "u0_a_1"; + function = "u0"; + pins = "u0_a_1"; }; }; uart0_default_mode: uart0_default { uart0_default_cfg1 { - ste,pins = "GPIO0", "GPIO2"; + pins = "GPIO0", "GPIO2"; ste,input = <1>; }; uart0_default_cfg2 { - ste,pins = "GPIO1", "GPIO3"; + pins = "GPIO1", "GPIO3"; ste,output = <1>; }; }; uart0_sleep_mode: uart0_sleep { uart0_sleep_cfg1 { - ste,pins = "GPIO0", "GPIO2"; + pins = "GPIO0", "GPIO2"; ste,config = <&slpm_in_wkup_pdis>; }; uart0_sleep_cfg2 { - ste,pins = "GPIO1"; + pins = "GPIO1"; ste,config = <&slpm_out_hi_wkup_pdis>; }; uart0_sleep_cfg3 { - ste,pins = "GPIO3"; + pins = "GPIO3"; ste,config = <&slpm_out_wkup_pdis>; }; }; diff --git a/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.txt new file mode 100644 index 000000000000..b7b55a964f65 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.txt @@ -0,0 +1,104 @@ + Binding for Xilinx Zynq Pinctrl + +Required properties: +- compatible: "xlnx,zynq-pinctrl" +- syscon: phandle to SLCR +- reg: Offset and length of pinctrl space in SLCR + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Zynq's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, slew rate, etc. + +Each configuration node can consist of multiple nodes describing the pinmux and +pinconf options. Those nodes can be pinmux nodes or pinconf nodes. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Required properties for pinmux nodes are: + - groups: A list of pinmux groups. + - function: The name of a pinmux function to activate for the specified set + of groups. + +Required properties for configuration nodes: +One of: + - pins: a list of pin names + - groups: A list of pinmux groups. + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pinmux subnode: + groups, function + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pinconf subnode: + groups, pins, bias-disable, bias-high-impedance, bias-pull-up, slew-rate, + low-power-disable, low-power-enable + + Valid arguments for 'slew-rate' are '0' and '1' to select between slow and fast + respectively. + + Valid values for groups are: + ethernet0_0_grp, ethernet1_0_grp, mdio0_0_grp, mdio1_0_grp, + qspi0_0_grp, qspi1_0_grp, qspi_fbclk, qspi_cs1_grp, spi0_0_grp, + spi0_1_grp - spi0_2_grp, spi1_0_grp - spi1_3_grp, sdio0_0_grp - sdio0_2_grp, + sdio1_0_grp - sdio1_3_grp, sdio0_emio_wp, sdio0_emio_cd, sdio1_emio_wp, + sdio1_emio_cd, smc0_nor, smc0_nor_cs1_grp, smc0_nor_addr25_grp, smc0_nand, + can0_0_grp - can0_10_grp, can1_0_grp - can1_11_grp, uart0_0_grp - uart0_10_grp, + uart1_0_grp - uart1_11_grp, i2c0_0_grp - i2c0_10_grp, i2c1_0_grp - i2c1_10_grp, + ttc0_0_grp - ttc0_2_grp, ttc1_0_grp - ttc1_2_grp, swdt0_0_grp - swdt0_4_grp, + gpio0_0_grp - gpio0_53_grp, usb0_0_grp, usb1_0_grp + + Valid values for pins are: + MIO0 - MIO53 + + Valid values for function are: + ethernet0, ethernet1, mdio0, mdio1, qspi0, qspi1, qspi_fbclk, qspi_cs1, + spi0, spi1, sdio0, sdio0_pc, sdio0_cd, sdio0_wp, + sdio1, sdio1_pc, sdio1_cd, sdio1_wp, + smc0_nor, smc0_nor_cs1, smc0_nor_addr25, smc0_nand, can0, can1, uart0, uart1, + i2c0, i2c1, ttc0, ttc1, swdt0, gpio0, usb0, usb1 + +The following driver-specific properties as defined here are valid to specify in +a pin configuration subnode: + - io-standard: Configure the pin to use the selected IO standard according to + this mapping: + 1: LVCMOS18 + 2: LVCMOS25 + 3: LVCMOS33 + 4: HSTL + +Example: + pinctrl0: pinctrl@700 { + compatible = "xlnx,pinctrl-zynq"; + reg = <0x700 0x200>; + syscon = <&slcr>; + + pinctrl_uart1_default: uart1-default { + mux { + groups = "uart1_10_grp"; + function = "uart1"; + }; + + conf { + groups = "uart1_10_grp"; + slew-rate = <0>; + io-standard = <1>; + }; + + conf-rx { + pins = "MIO49"; + bias-high-impedance; + }; + + conf-tx { + pins = "MIO48"; + bias-disable; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/power/ltc2941.txt b/Documentation/devicetree/bindings/power/ltc2941.txt new file mode 100644 index 000000000000..ea42ae12d924 --- /dev/null +++ b/Documentation/devicetree/bindings/power/ltc2941.txt @@ -0,0 +1,27 @@ +binding for LTC2941 and LTC2943 battery gauges + +Both the LTC2941 and LTC2943 measure battery capacity. +The LTC2943 is compatible with the LTC2941, it adds voltage and +temperature monitoring, and uses a slightly different conversion +formula for the charge counter. + +Required properties: +- compatible: Should contain "ltc2941" or "ltc2943" which also indicates the + type of I2C chip attached. +- reg: The 7-bit I2C address. +- lltc,resistor-sense: The sense resistor value in milli-ohms. Can be a 32-bit + negative value when the battery has been connected to the wrong end of the + resistor. +- lltc,prescaler-exponent: The prescaler exponent as explained in the datasheet. + This determines the range and accuracy of the gauge. The value is programmed + into the chip only if it differs from the current setting. The setting is + lost when the battery is disconnected. + +Example from the Topic Miami Florida board: + + fuelgauge: ltc2943@64 { + compatible = "ltc2943"; + reg = <0x64>; + lltc,resistor-sense = <15>; + lltc,prescaler-exponent = <5>; /* 2^(2*5) = 1024 */ + }; diff --git a/Documentation/devicetree/bindings/power/reset/ltc2952-poweroff.txt b/Documentation/devicetree/bindings/power/reset/ltc2952-poweroff.txt index 0c94c637f63b..cd2d7f58a9d7 100644 --- a/Documentation/devicetree/bindings/power/reset/ltc2952-poweroff.txt +++ b/Documentation/devicetree/bindings/power/reset/ltc2952-poweroff.txt @@ -1,20 +1,23 @@ Binding for the LTC2952 PowerPath controller This chip is used to externally trigger a system shut down. Once the trigger has -been sent, the chips' watchdog has to be reset to gracefully shut down. -If the Linux systems decides to shut down it powers off the platform via the -kill signal. +been sent, the chip's watchdog has to be reset to gracefully shut down. +A full powerdown can be triggered via the kill signal. Required properties: - compatible: Must contain: "lltc,ltc2952" -- trigger-gpios: phandle + gpio-specifier for the GPIO connected to the - chip's trigger line - watchdog-gpios: phandle + gpio-specifier for the GPIO connected to the chip's watchdog line - kill-gpios: phandle + gpio-specifier for the GPIO connected to the chip's kill line +Optional properties: +- trigger-gpios: phandle + gpio-specifier for the GPIO connected to the + chip's trigger line. If this property is not set, the + trigger function is ignored and the chip is kept alive + until an explicit kill signal is received + Example: ltc2952 { diff --git a/Documentation/devicetree/bindings/power/rockchip-io-domain.txt b/Documentation/devicetree/bindings/power/rockchip-io-domain.txt index 6fbf6e7ecde6..8b70db103ca7 100644 --- a/Documentation/devicetree/bindings/power/rockchip-io-domain.txt +++ b/Documentation/devicetree/bindings/power/rockchip-io-domain.txt @@ -37,7 +37,7 @@ Required properties: You specify supplies using the standard regulator bindings by including -a phandle the the relevant regulator. All specified supplies must be able +a phandle the relevant regulator. All specified supplies must be able to report their voltage. The IO Voltage Domain for any non-specified supplies will be not be touched. diff --git a/Documentation/devicetree/bindings/powerpc/fsl/fman.txt b/Documentation/devicetree/bindings/powerpc/fsl/fman.txt index edeea160ca39..edda55f74004 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/fman.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/fman.txt @@ -7,6 +7,7 @@ CONTENTS - FMan MURAM Node - FMan dTSEC/XGEC/mEMAC Node - FMan IEEE 1588 Node + - FMan MDIO Node - Example ============================================================================= @@ -356,6 +357,69 @@ ptp-timer@fe000 { reg = <0xfe000 0x1000>; }; +============================================================================= +FMan MDIO Node + +DESCRIPTION + +The MDIO is a bus to which the PHY devices are connected. + +PROPERTIES + +- compatible + Usage: required + Value type: + Definition: A standard property. + Must include "fsl,fman-mdio" for 1 Gb/s MDIO from FMan v2. + Must include "fsl,fman-xmdio" for 10 Gb/s MDIO from FMan v2. + Must include "fsl,fman-memac-mdio" for 1/10 Gb/s MDIO from + FMan v3. + +- reg + Usage: required + Value type: + Definition: A standard property. + +- bus-frequency + Usage: optional + Value type: + Definition: Specifies the external MDIO bus clock speed to + be used, if different from the standard 2.5 MHz. + This may be due to the standard speed being unsupported (e.g. + due to a hardware problem), or to advertise that all relevant + components in the system support a faster speed. + +- interrupts + Usage: required for external MDIO + Value type: + Definition: Event interrupt of external MDIO controller. + +- fsl,fman-internal-mdio + Usage: required for internal MDIO + Value type: boolean + Definition: Fman has internal MDIO for internal PCS(Physical + Coding Sublayer) PHYs and external MDIO for external PHYs. + The settings and programming routines for internal/external + MDIO are different. Must be included for internal MDIO. + +EXAMPLE + +Example for FMan v2 external MDIO: + +mdio@f1000 { + compatible = "fsl,fman-xmdio"; + reg = <0xf1000 0x1000>; + interrupts = <101 2 0 0>; +}; + +Example for FMan v3 internal MDIO: + +mdio@f1000 { + compatible = "fsl,fman-memac-mdio"; + reg = <0xf1000 0x1000>; + fsl,fman-internal-mdio; +}; + ============================================================================= Example @@ -531,4 +595,10 @@ fman@400000 { compatible = "fsl,fman-ptp-timer"; reg = <0xfe000 0x1000>; }; + + mdio@f1000 { + compatible = "fsl,fman-xmdio"; + reg = <0xf1000 0x1000>; + interrupts = <101 2 0 0>; + }; }; diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt index c7ea9d4a988b..c52f03b5032f 100644 --- a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt +++ b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt @@ -1,9 +1,10 @@ Tegra SoC PWFM controller Required properties: -- compatible: should be one of: - - "nvidia,tegra20-pwm" - - "nvidia,tegra30-pwm" +- compatible: For Tegra20, must contain "nvidia,tegra20-pwm". For Tegra30, + must contain "nvidia,tegra30-pwm". Otherwise, must contain + "nvidia,-pwm", plus one of the above, where is tegra114, + tegra124, tegra132, or tegra210. - reg: physical base address and length of the controller's registers - #pwm-cells: should be 2. See pwm.txt in this directory for a description of the cells format. diff --git a/Documentation/devicetree/bindings/regulator/da9211.txt b/Documentation/devicetree/bindings/regulator/da9211.txt index 240019a82f9a..eb618907c7de 100644 --- a/Documentation/devicetree/bindings/regulator/da9211.txt +++ b/Documentation/devicetree/bindings/regulator/da9211.txt @@ -11,6 +11,7 @@ Required properties: BUCKA and BUCKB. Optional properties: +- enable-gpios: platform gpio for control of BUCKA/BUCKB. - Any optional property defined in regulator.txt Example 1) DA9211 @@ -27,6 +28,7 @@ Example 1) DA9211 regulator-max-microvolt = <1570000>; regulator-min-microamp = <2000000>; regulator-max-microamp = <5000000>; + enable-gpios = <&gpio 27 0>; }; BUCKB { regulator-name = "VBUCKB"; @@ -34,11 +36,12 @@ Example 1) DA9211 regulator-max-microvolt = <1570000>; regulator-min-microamp = <2000000>; regulator-max-microamp = <5000000>; + enable-gpios = <&gpio 17 0>; }; }; }; -Example 2) DA92113 +Example 2) DA9213 pmic: da9213@68 { compatible = "dlg,da9213"; reg = <0x68>; @@ -51,6 +54,7 @@ Example 2) DA92113 regulator-max-microvolt = <1570000>; regulator-min-microamp = <3000000>; regulator-max-microamp = <6000000>; + enable-gpios = <&gpio 27 0>; }; BUCKB { regulator-name = "VBUCKB"; @@ -58,6 +62,7 @@ Example 2) DA92113 regulator-max-microvolt = <1570000>; regulator-min-microamp = <3000000>; regulator-max-microamp = <6000000>; + enable-gpios = <&gpio 17 0>; }; }; }; diff --git a/Documentation/devicetree/bindings/regulator/isl9305.txt b/Documentation/devicetree/bindings/regulator/isl9305.txt index a626fc1bbf0d..d6e7c9ec9413 100644 --- a/Documentation/devicetree/bindings/regulator/isl9305.txt +++ b/Documentation/devicetree/bindings/regulator/isl9305.txt @@ -2,7 +2,7 @@ Intersil ISL9305/ISL9305H voltage regulator Required properties: -- compatible: "isl,isl9305" or "isl,isl9305h" +- compatible: "isil,isl9305" or "isil,isl9305h" - reg: I2C slave address, usually 0x68. - regulators: A node that houses a sub-node for each regulator within the device. Each sub-node is identified using the node's name, with valid @@ -19,7 +19,7 @@ Optional properties: Example pmic: isl9305@68 { - compatible = "isl,isl9305"; + compatible = "isil,isl9305"; reg = <0x68>; VINDCD1-supply = <&system_power>; diff --git a/Documentation/devicetree/bindings/regulator/mt6397-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6397-regulator.txt new file mode 100644 index 000000000000..a42b1d6e9863 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/mt6397-regulator.txt @@ -0,0 +1,217 @@ +Mediatek MT6397 Regulator Driver + +Required properties: +- compatible: "mediatek,mt6397-regulator" +- mt6397regulator: List of regulators provided by this controller. It is named + according to its regulator type, buck_ and ldo_. + The definition for each of these nodes is defined using the standard binding + for regulators at Documentation/devicetree/bindings/regulator/regulator.txt. + +The valid names for regulators are:: +BUCK: + buck_vpca15, buck_vpca7, buck_vsramca15, buck_vsramca7, buck_vcore, buck_vgpu, + buck_vdrm, buck_vio18 +LDO: + ldo_vtcxo, ldo_va28, ldo_vcama, ldo_vio28, ldo_vusb, ldo_vmc, ldo_vmch, + ldo_vemc3v3, ldo_vgp1, ldo_vgp2, ldo_vgp3, ldo_vgp4, ldo_vgp5, ldo_vgp6, + ldo_vibr + +Example: + pmic { + compatible = "mediatek,mt6397"; + + mt6397regulator: mt6397regulator { + compatible = "mediatek,mt6397-regulator"; + + mt6397_vpca15_reg: buck_vpca15 { + regulator-compatible = "buck_vpca15"; + regulator-name = "vpca15"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <200>; + }; + + mt6397_vpca7_reg: buck_vpca7 { + regulator-compatible = "buck_vpca7"; + regulator-name = "vpca7"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + }; + + mt6397_vsramca15_reg: buck_vsramca15 { + regulator-compatible = "buck_vsramca15"; + regulator-name = "vsramca15"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + + }; + + mt6397_vsramca7_reg: buck_vsramca7 { + regulator-compatible = "buck_vsramca7"; + regulator-name = "vsramca7"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + + }; + + mt6397_vcore_reg: buck_vcore { + regulator-compatible = "buck_vcore"; + regulator-name = "vcore"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + }; + + mt6397_vgpu_reg: buck_vgpu { + regulator-compatible = "buck_vgpu"; + regulator-name = "vgpu"; + regulator-min-microvolt = < 700000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + }; + + mt6397_vdrm_reg: buck_vdrm { + regulator-compatible = "buck_vdrm"; + regulator-name = "vdrm"; + regulator-min-microvolt = < 800000>; + regulator-max-microvolt = <1400000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <500>; + }; + + mt6397_vio18_reg: buck_vio18 { + regulator-compatible = "buck_vio18"; + regulator-name = "vio18"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2120000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <500>; + }; + + mt6397_vtcxo_reg: ldo_vtcxo { + regulator-compatible = "ldo_vtcxo"; + regulator-name = "vtcxo"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <90>; + }; + + mt6397_va28_reg: ldo_va28 { + regulator-compatible = "ldo_va28"; + regulator-name = "va28"; + /* fixed output 2.8 V */ + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vcama_reg: ldo_vcama { + regulator-compatible = "ldo_vcama"; + regulator-name = "vcama"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vio28_reg: ldo_vio28 { + regulator-compatible = "ldo_vio28"; + regulator-name = "vio28"; + /* fixed output 2.8 V */ + regulator-enable-ramp-delay = <240>; + }; + + mt6397_usb_reg: ldo_vusb { + regulator-compatible = "ldo_vusb"; + regulator-name = "vusb"; + /* fixed output 3.3 V */ + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vmc_reg: ldo_vmc { + regulator-compatible = "ldo_vmc"; + regulator-name = "vmc"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vmch_reg: ldo_vmch { + regulator-compatible = "ldo_vmch"; + regulator-name = "vmch"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vemc_3v3_reg: ldo_vemc3v3 { + regulator-compatible = "ldo_vemc3v3"; + regulator-name = "vemc_3v3"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp1_reg: ldo_vgp1 { + regulator-compatible = "ldo_vgp1"; + regulator-name = "vcamd"; + regulator-min-microvolt = <1220000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <240>; + }; + + mt6397_vgp2_reg: ldo_vgp2 { + egulator-compatible = "ldo_vgp2"; + regulator-name = "vcamio"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp3_reg: ldo_vgp3 { + regulator-compatible = "ldo_vgp3"; + regulator-name = "vcamaf"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp4_reg: ldo_vgp4 { + regulator-compatible = "ldo_vgp4"; + regulator-name = "vgp4"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp5_reg: ldo_vgp5 { + regulator-compatible = "ldo_vgp5"; + regulator-name = "vgp5"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp6_reg: ldo_vgp6 { + regulator-compatible = "ldo_vgp6"; + regulator-name = "vgp6"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vibr_reg: ldo_vibr { + regulator-compatible = "ldo_vibr"; + regulator-name = "vibr"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/pfuze100.txt b/Documentation/devicetree/bindings/regulator/pfuze100.txt index 34ef5d16d0f1..9b40db88f637 100644 --- a/Documentation/devicetree/bindings/regulator/pfuze100.txt +++ b/Documentation/devicetree/bindings/regulator/pfuze100.txt @@ -1,7 +1,7 @@ PFUZE100 family of regulators Required properties: -- compatible: "fsl,pfuze100" or "fsl,pfuze200" +- compatible: "fsl,pfuze100", "fsl,pfuze200", "fsl,pfuze3000" - reg: I2C slave address Required child node: @@ -14,6 +14,8 @@ Required child node: sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6 --PFUZE200 sw1ab,sw2,sw3a,sw3b,swbst,vsnvs,vrefddr,vgen1~vgen6 + --PFUZE3000 + sw1a,sw1b,sw2,sw3,swbst,vsnvs,vrefddr,vldo1,vldo2,vccsd,v33,vldo3,vldo4 Each regulator is defined using the standard binding for regulators. @@ -205,3 +207,93 @@ Example 2: PFUZE200 }; }; }; + +Example 3: PFUZE3000 + + pmic: pfuze3000@08 { + compatible = "fsl,pfuze3000"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1a { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1475000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + /* use sw1c_reg to align with pfuze100/pfuze200 */ + sw1c_reg: sw1b { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1475000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1650000>; + regulator-boot-on; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen2_reg: vldo2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vccsd { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen4_reg: v33 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + }; + + vgen5_reg: vldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vldo4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/rtc/nvidia,tegra20-rtc.txt b/Documentation/devicetree/bindings/rtc/nvidia,tegra20-rtc.txt index 652d1ff2e8be..b7d98ed3e098 100644 --- a/Documentation/devicetree/bindings/rtc/nvidia,tegra20-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/nvidia,tegra20-rtc.txt @@ -6,7 +6,9 @@ state. Required properties: -- compatible : should be "nvidia,tegra20-rtc". +- compatible : For Tegra20, must contain "nvidia,tegra20-rtc". Otherwise, + must contain '"nvidia,-rtc", "nvidia,tegra20-rtc"', where + can be tegra30, tegra114, tegra124, or tegra132. - reg : Specifies base physical address and size of the registers. - interrupts : A single interrupt specifier. - clocks : Must contain one entry, for the module clock. diff --git a/Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt b/Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt new file mode 100644 index 000000000000..3ad115efed1e --- /dev/null +++ b/Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt @@ -0,0 +1,36 @@ +* STMicroelectronics SAS. ST33ZP24 TPM SoC + +Required properties: +- compatible: Should be "st,st33zp24-i2c". +- clock-frequency: I²C work frequency. +- reg: address on the bus + +Optional ST33ZP24 Properties: +- interrupt-parent: phandle for the interrupt gpio controller +- interrupts: GPIO interrupt to which the chip is connected +- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state. +If set, power must be present when the platform is going into sleep/hibernate mode. + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBoard xM with ST33ZP24 on I2C2): + +&i2c2 { + + status = "okay"; + + st33zp24: st33zp24@13 { + + compatible = "st,st33zp24-i2c"; + + reg = <0x13>; + clock-frequency = <400000>; + + interrupt-parent = <&gpio5>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; + + lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/Documentation/devicetree/bindings/serial/of-serial.txt b/Documentation/devicetree/bindings/serial/of-serial.txt index b52b98234b9b..bea60ef6cdc5 100644 --- a/Documentation/devicetree/bindings/serial/of-serial.txt +++ b/Documentation/devicetree/bindings/serial/of-serial.txt @@ -8,7 +8,10 @@ Required properties: - "ns16550" - "ns16750" - "ns16850" - - "nvidia,tegra20-uart" + - For Tegra20, must contain "nvidia,tegra20-uart" + - For other Tegra, must contain '"nvidia,-uart", + "nvidia,tegra20-uart"' where is tegra30, tegra114, tegra124, + tegra132, or tegra210. - "nxp,lpc3220-uart" - "ralink,rt2880-uart" - "ibm,qpace-nwp-serial" diff --git a/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt b/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt new file mode 100644 index 000000000000..362a76925bcd --- /dev/null +++ b/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt @@ -0,0 +1,23 @@ +* Device tree bindings for Allwinner A10, A20 PS2 host controller + +A20 PS2 is dual role controller (PS2 host and PS2 device). These bindings are +for PS2 A10/A20 host controller. IBM compliant IBM PS2 and AT-compatible keyboard +and mouse can be connected. + +Required properties: + + - reg : Offset and length of the register set for the device. + - compatible : Should be as of the following: + - "allwinner,sun4i-a10-ps2" + - interrupts : The interrupt line connected to the PS2. + - clocks : The gate clk connected to the PS2. + + +Example: + ps20: ps2@0x01c2a000 { + compatible = "allwinner,sun4i-a10-ps2"; + reg = <0x01c2a000 0x400>; + interrupts = <0 62 4>; + clocks = <&apb1_gates 6>; + status = "disabled"; + }; diff --git a/Documentation/devicetree/bindings/soc/fsl/bman.txt b/Documentation/devicetree/bindings/soc/fsl/bman.txt index 9f80bf8709ac..47ac834414d8 100644 --- a/Documentation/devicetree/bindings/soc/fsl/bman.txt +++ b/Documentation/devicetree/bindings/soc/fsl/bman.txt @@ -36,6 +36,11 @@ are located at offsets 0xbf8 and 0xbfc Value type: Definition: Standard property. The error interrupt +- fsl,bman-portals + Usage: Required + Value type: + Definition: Phandle to this BMan instance's portals + - fsl,liodn Usage: See pamu.txt Value type: @@ -96,7 +101,7 @@ The example below shows a BMan FBPR dynamic allocation memory node bman_fbpr: bman-fbpr { compatible = "fsl,bman-fbpr"; - alloc-ranges = <0 0 0xf 0xffffffff>; + alloc-ranges = <0 0 0x10 0>; size = <0 0x1000000>; alignment = <0 0x1000000>; }; @@ -104,6 +109,10 @@ The example below shows a BMan FBPR dynamic allocation memory node The example below shows a (P4080) BMan CCSR-space node + bportals: bman-portals@ff4000000 { + ... + }; + crypto@300000 { ... fsl,bman = <&bman, 2>; @@ -115,6 +124,7 @@ The example below shows a (P4080) BMan CCSR-space node reg = <0x31a000 0x1000>; interrupts = <16 2 1 2>; fsl,liodn = <0x17>; + fsl,bman-portals = <&bportals>; memory-region = <&bman_fbpr>; }; diff --git a/Documentation/devicetree/bindings/soc/fsl/qman.txt b/Documentation/devicetree/bindings/soc/fsl/qman.txt index 063e3a0b9d04..556ebb8be75d 100644 --- a/Documentation/devicetree/bindings/soc/fsl/qman.txt +++ b/Documentation/devicetree/bindings/soc/fsl/qman.txt @@ -38,6 +38,11 @@ are located at offsets 0xbf8 and 0xbfc Value type: Definition: Standard property. The error interrupt +- fsl,qman-portals + Usage: Required + Value type: + Definition: Phandle to this QMan instance's portals + - fsl,liodn Usage: See pamu.txt Value type: @@ -113,13 +118,13 @@ The example below shows a QMan FQD and a PFDR dynamic allocation memory nodes qman_fqd: qman-fqd { compatible = "fsl,qman-fqd"; - alloc-ranges = <0 0 0xf 0xffffffff>; + alloc-ranges = <0 0 0x10 0>; size = <0 0x400000>; alignment = <0 0x400000>; }; qman_pfdr: qman-pfdr { compatible = "fsl,qman-pfdr"; - alloc-ranges = <0 0 0xf 0xffffffff>; + alloc-ranges = <0 0 0x10 0>; size = <0 0x2000000>; alignment = <0 0x2000000>; }; @@ -127,6 +132,10 @@ The example below shows a QMan FQD and a PFDR dynamic allocation memory nodes The example below shows a (P4080) QMan CCSR-space node + qportals: qman-portals@ff4200000 { + ... + }; + clockgen: global-utilities@e1000 { ... sysclk: sysclk { @@ -154,6 +163,7 @@ The example below shows a (P4080) QMan CCSR-space node reg = <0x318000 0x1000>; interrupts = <16 2 1 3> fsl,liodn = <0x16>; + fsl,qman-portals = <&qportals>; memory-region = <&qman_fqd &qman_pfdr>; clocks = <&platform_pll 1>; }; diff --git a/Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.txt b/Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.txt new file mode 100644 index 000000000000..befd125d18bb --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.txt @@ -0,0 +1,18 @@ +Bindings for I2S controller built into xtfpga Xtensa bitstreams. + +Required properties: +- compatible: shall be "cdns,xtfpga-i2s". +- reg: memory region (address and length) with device registers. +- interrupts: interrupt for the device. +- clocks: phandle to the clk used as master clock. I2S bus clock + is derived from it. + +Examples: + + i2s0: xtfpga-i2s@0d080000 { + #sound-dai-cells = <0>; + compatible = "cdns,xtfpga-i2s"; + reg = <0x0d080000 0x40>; + interrupts = <2 1>; + clocks = <&cdce706 4>; + }; diff --git a/Documentation/devicetree/bindings/sound/designware-i2s.txt b/Documentation/devicetree/bindings/sound/designware-i2s.txt new file mode 100644 index 000000000000..7bb54247f8e8 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/designware-i2s.txt @@ -0,0 +1,31 @@ +DesignWare I2S controller + +Required properties: + - compatible : Must be "snps,designware-i2s" + - reg : Must contain the I2S core's registers location and length + - clocks : Pairs of phandle and specifier referencing the controller's + clocks. The controller expects one clock: the clock used as the sampling + rate reference clock sample. + - clock-names : "i2sclk" for the sample rate reference clock. + - dmas: Pairs of phandle and specifier for the DMA channels that are used by + the core. The core expects one or two dma channels: one for transmit and + one for receive. + - dma-names : "tx" for the transmit channel, "rx" for the receive channel. + +For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' +properties please check: + * resource-names.txt + * clock/clock-bindings.txt + * dma/dma.txt + +Example: + + soc_i2s: i2s@7ff90000 { + compatible = "snps,designware-i2s"; + reg = <0x0 0x7ff90000 0x0 0x1000>; + clocks = <&scpi_i2sclk 0>; + clock-names = "i2sclk"; + #sound-dai-cells = <0>; + dmas = <&dma0 5>; + dma-names = "tx"; + }; diff --git a/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt b/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt new file mode 100644 index 000000000000..b41433386e2f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt @@ -0,0 +1,23 @@ +Ingenic JZ4740 I2S controller + +Required properties: +- compatible : "ingenic,jz4740-i2s" +- reg : I2S registers location and length +- clocks : AIC and I2S PLL clock specifiers. +- clock-names: "aic" and "i2s" +- dmas: DMA controller phandle and DMA request line for I2S Tx and Rx channels +- dma-names: Must be "tx" and "rx" + +Example: + +i2s: i2s@10020000 { + compatible = "ingenic,jz4740-i2s"; + reg = <0x10020000 0x94>; + + clocks = <&cgu JZ4740_CLK_AIC>, <&cgu JZ4740_CLK_I2SPLL>; + clock-names = "aic", "i2s"; + + dmas = <&dma 2>, <&dma 3>; + dma-names = "tx", "rx"; + +}; diff --git a/Documentation/devicetree/bindings/sound/max98357a.txt b/Documentation/devicetree/bindings/sound/max98357a.txt new file mode 100644 index 000000000000..a7a149a236e5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/max98357a.txt @@ -0,0 +1,14 @@ +Maxim MAX98357A audio DAC + +This node models the Maxim MAX98357A DAC. + +Required properties: +- compatible : "maxim,max98357a" +- sdmode-gpios : GPIO specifier for the GPIO -> DAC SDMODE pin + +Example: + +max98357a { + compatible = "maxim,max98357a"; + sdmode-gpios = <&qcom_pinmux 25 0>; +}; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt new file mode 100644 index 000000000000..a4589cda214e --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt @@ -0,0 +1,67 @@ +NVIDIA Tegra audio complex, with RT5677 CODEC + +Required properties: +- compatible : "nvidia,tegra-audio-rt5677" +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) +- nvidia,model : The user-visible name of this sound complex. +- nvidia,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the RT5677's pins (as documented in its binding), and the jacks + on the board: + + * Headphone + * Speaker + * Headset Mic + * Internal Mic 1 + * Internal Mic 2 + +- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's + connected to the CODEC. +- nvidia,audio-codec : The phandle of the RT5677 audio codec. This binding + assumes that AIF1 on the CODEC is connected to Tegra. + +Optional properties: +- nvidia,hp-det-gpios : The GPIO that detects headphones are plugged in +- nvidia,hp-en-gpios : The GPIO that enables headphone amplifier +- nvidia,mic-present-gpios: The GPIO that mic jack is plugged in +- nvidia,dmic-clk-en-gpios : The GPIO that gates DMIC clock signal + +Example: + +sound { + compatible = "nvidia,tegra-audio-rt5677-ryu", + "nvidia,tegra-audio-rt5677"; + nvidia,model = "NVIDIA Tegra Ryu"; + + nvidia,audio-routing = + "Headphone", "LOUT2", + "Headphone", "LOUT1", + "Headset Mic", "MICBIAS1", + "IN1P", "Headset Mic", + "IN1N", "Headset Mic", + "DMIC L1", "Internal Mic 1", + "DMIC R1", "Internal Mic 1", + "DMIC L2", "Internal Mic 2", + "DMIC R2", "Internal Mic 2", + "Speaker", "PDM1L", + "Speaker", "PDM1R"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&rt5677>; + + nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(R, 7) GPIO_ACTIVE_HIGH>; + nvidia,mic-present-gpios = <&gpio TEGRA_GPIO(O, 5) GPIO_ACTIVE_LOW>; + nvidia,hp-en-gpios = <&rt5677 1 GPIO_ACTIVE_HIGH>; + nvidia,dmic-clk-en-gpios = <&rt5677 2 GPIO_ACTIVE_HIGH>; + + clocks = <&tegra_car TEGRA124_CLK_PLL_A>, + <&tegra_car TEGRA124_CLK_PLL_A_OUT0>, + <&tegra_car TEGRA124_CLK_EXTERN1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; +}; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt index 946e2ac46091..0e9a1895d7fb 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt @@ -1,7 +1,10 @@ NVIDIA Tegra30 AHUB (Audio Hub) Required properties: -- compatible : "nvidia,tegra30-ahub", "nvidia,tegra114-ahub", etc. +- compatible : For Tegra30, must contain "nvidia,tegra30-ahub". For Tegra114, + must contain "nvidia,tegra114-ahub". For Tegra124, must contain + "nvidia,tegra124-ahub". Otherwise, must contain "nvidia,-ahub", + plus at least one of the above, where is tegra132. - reg : Should contain the register physical address and length for each of the AHUB's register blocks. - Tegra30 requires 2 entries, for the APBIF and AHUB/AUDIO register blocks. diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt index b4730c2822bc..13e2ef496724 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt @@ -1,7 +1,9 @@ NVIDIA Tegra30 HDA controller Required properties: -- compatible : "nvidia,tegra30-hda" +- compatible : For Tegra30, must contain "nvidia,tegra30-hda". Otherwise, + must contain '"nvidia,-hda", "nvidia,tegra30-hda"', where is + tegra114, tegra124, or tegra132. - reg : Should contain the HDA registers location and length. - interrupts : The interrupt from the HDA controller. - clocks : Must contain an entry for each required entry in clock-names. diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt index 0c113ffe3814..38caa936f6f8 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt @@ -1,7 +1,10 @@ NVIDIA Tegra30 I2S controller Required properties: -- compatible : "nvidia,tegra30-i2s" +- compatible : For Tegra30, must contain "nvidia,tegra30-i2s". For Tegra124, + must contain "nvidia,tegra124-i2s". Otherwise, must contain + "nvidia,-i2s" plus at least one of the above, where is + tegra114 or tegra132. - reg : Should contain I2S registers location and length - clocks : Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt b/Documentation/devicetree/bindings/sound/pcm512x.txt index faff75e64573..3aae3b41bd8e 100644 --- a/Documentation/devicetree/bindings/sound/pcm512x.txt +++ b/Documentation/devicetree/bindings/sound/pcm512x.txt @@ -5,7 +5,8 @@ on the board). Required properties: - - compatible : One of "ti,pcm5121" or "ti,pcm5122" + - compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141" or + "ti,pcm5142" - reg : the I2C address of the device for I2C, the chip select number for SPI. @@ -16,9 +17,16 @@ Required properties: Optional properties: - clocks : A clock specifier for the clock connected as SCLK. If this - is absent the device will be configured to clock from BCLK. + is absent the device will be configured to clock from BCLK. If pll-in + and pll-out are specified in addition to a clock, the device is + configured to accept clock input on a specified gpio pin. -Example: + - pll-in, pll-out : gpio pins used to connect the pll using <1> + through <6>. The device will be configured for clock input on the + given pll-in pin and PLL output on the given pll-out pin. An + external connection from the pll-out pin to the SCLK pin is assumed. + +Examples: pcm5122: pcm5122@4c { compatible = "ti,pcm5122"; @@ -28,3 +36,17 @@ Example: DVDD-supply = <®_1v8>; CPVDD-supply = <®_3v3>; }; + + + pcm5142: pcm5142@4c { + compatible = "ti,pcm5142"; + reg = <0x4c>; + + AVDD-supply = <®_3v3_analog>; + DVDD-supply = <®_1v8>; + CPVDD-supply = <®_3v3>; + + clocks = <&sck>; + pll-in = <3>; + pll-out = <6>; + }; diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.txt b/Documentation/devicetree/bindings/sound/samsung-i2s.txt index d188296bb6ec..09e0e18591ae 100644 --- a/Documentation/devicetree/bindings/sound/samsung-i2s.txt +++ b/Documentation/devicetree/bindings/sound/samsung-i2s.txt @@ -33,6 +33,25 @@ Required SoC Specific Properties: "iis" is the i2s bus clock and i2s_opclk0, i2s_opclk1 are sources of the root clk. i2s0 has internal mux to select the source of root clk and i2s1 and i2s2 doesn't have any such mux. +- #clock-cells: should be 1, this property must be present if the I2S device + is a clock provider in terms of the common clock bindings, described in + ../clock/clock-bindings.txt. +- clock-output-names: from the common clock bindings, names of the CDCLK + I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1", + "i2s_cdclk3" for the I2S0, I2S1, I2S2 devices recpectively. + +There are following clocks available at the I2S device nodes: + CLK_I2S_CDCLK - the CDCLK (CODECLKO) gate clock, + CLK_I2S_RCLK_PSR - the RCLK prescaler divider clock (corresponding to the + IISPSR register), + CLK_I2S_RCLK_SRC - the RCLKSRC mux clock (corresponding to RCLKSRC bit in + IISMOD register). + +Refer to the SoC datasheet for availability of the above clocks. +The CLK_I2S_RCLK_PSR and CLK_I2S_RCLK_SRC clocks are usually only available +in the IIS Multi Audio Interface (I2S0). +Note: Old DTs may not have the #clock-cells, clock-output-names properties +and then not use the I2S node as a clock supplier. Optional SoC Specific Properties: @@ -41,6 +60,7 @@ Optional SoC Specific Properties: - pinctrl-0: Should specify pin control groups used for this controller. - pinctrl-names: Should contain only one value - "default". + Example: i2s0: i2s@03830000 { @@ -54,6 +74,8 @@ i2s0: i2s@03830000 { <&clock_audss EXYNOS_I2S_BUS>, <&clock_audss EXYNOS_SCLK_I2S>; clock-names = "iis", "i2s_opclk0", "i2s_opclk1"; + #clock-cells; + clock-output-names = "i2s_cdclk0"; samsung,idma-addr = <0x03000000>; pinctrl-names = "default"; pinctrl-0 = <&i2s0_bus>; diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt index c3cba600bf11..73bf314f7240 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -75,6 +75,11 @@ Optional CPU/CODEC subnodes properties: it can be specified via "clocks" if system has clock node (= common clock), or "system-clock-frequency" (if system doens't support common clock) + If a clock is specified, it is + enabled with clk_prepare_enable() + in dai startup() and disabled with + clk_disable_unprepare() in dai + shutdown(). Example 1 - single DAI link: diff --git a/Documentation/devicetree/bindings/sound/st,sta32x.txt b/Documentation/devicetree/bindings/sound/st,sta32x.txt new file mode 100644 index 000000000000..255de3ae5b2f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,sta32x.txt @@ -0,0 +1,92 @@ +STA32X audio CODEC + +The driver for this device only supports I2C. + +Required properties: + + - compatible: "st,sta32x" + - reg: the I2C address of the device for I2C + - reset-gpios: a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the codec starts. + + - power-down-gpios: a GPIO spec for the power down pin. If specified, + it will be deasserted before communication to the codec + starts. + + - Vdda-supply: regulator spec, providing 3.3V + - Vdd3-supply: regulator spec, providing 3.3V + - Vcc-supply: regulator spec, providing 5V - 26V + +Optional properties: + + - st,output-conf: number, Selects the output configuration: + 0: 2-channel (full-bridge) power, 2-channel data-out + 1: 2 (half-bridge). 1 (full-bridge) on-board power + 2: 2 Channel (Full-Bridge) Power, 1 Channel FFX + 3: 1 Channel Mono-Parallel + If parameter is missing, mode 0 will be enabled. + This property has to be specified as '/bits/ 8' value. + + - st,ch1-output-mapping: Channel 1 output mapping + - st,ch2-output-mapping: Channel 2 output mapping + - st,ch3-output-mapping: Channel 3 output mapping + 0: Channel 1 + 1: Channel 2 + 2: Channel 3 + If parameter is missing, channel 1 is chosen. + This properties have to be specified as '/bits/ 8' values. + + - st,thermal-warning-recover: + If present, thermal warning recovery is enabled. + + - st,thermal-warning-adjustment: + If present, thermal warning adjustment is enabled. + + - st,fault-detect-recovery: + If present, then fault recovery will be enabled. + + - st,drop-compensation-ns: number + Only required for "st,ffx-power-output-mode" == + "variable-drop-compensation". + Specifies the drop compensation in nanoseconds. + The value must be in the range of 0..300, and only + multiples of 20 are allowed. Default is 140ns. + + - st,max-power-use-mpcc: + If present, then MPCC bits are used for MPC coefficients, + otherwise standard MPC coefficients are used. + + - st,max-power-corr: + If present, power bridge correction for THD reduction near maximum + power output is enabled. + + - st,am-reduction-mode: + If present, FFX mode runs in AM reduction mode, otherwise normal + FFX mode is used. + + - st,odd-pwm-speed-mode: + If present, PWM speed mode run on odd speed mode (341.3 kHz) on all + channels. If not present, normal PWM spped mode (384 kHz) will be used. + + - st,invalid-input-detect-mute: + If present, automatic invalid input detect mute is enabled. + +Example: + +codec: sta32x@38 { + compatible = "st,sta32x"; + reg = <0x1c>; + reset-gpios = <&gpio1 19 0>; + power-down-gpios = <&gpio1 16 0>; + st,output-conf = /bits/ 8 <0x3>; // set output to 2-channel + // (full-bridge) power, + // 2-channel data-out + st,ch1-output-mapping = /bits/ 8 <0>; // set channel 1 output ch 1 + st,ch2-output-mapping = /bits/ 8 <0>; // set channel 2 output ch 1 + st,ch3-output-mapping = /bits/ 8 <0>; // set channel 3 output ch 1 + st,max-power-correction; // enables power bridge + // correction for THD reduction + // near maximum power output + st,invalid-input-detect-mute; // mute if no valid digital + // audio signal is provided. +}; diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt index 5e6040c2c2e9..47a213c411ce 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -9,6 +9,7 @@ Required properties: "ti,tlv320aic33" - TLV320AIC33 "ti,tlv320aic3007" - TLV320AIC3007 "ti,tlv320aic3106" - TLV320AIC3106 + "ti,tlv320aic3104" - TLV320AIC3104 - reg - - I2C slave address @@ -18,6 +19,7 @@ Optional properties: - gpio-reset - gpio pin number used for codec reset - ai3x-gpio-func - - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality + - Not supported on tlv320aic3104 - ai3x-micbias-vg - MicBias Voltage required. 1 - MICBIAS output is powered to 2.0V, 2 - MICBIAS output is powered to 2.5V, @@ -36,7 +38,13 @@ CODEC output pins: * HPLCOM * HPRCOM -CODEC input pins: +CODEC input pins for TLV320AIC3104: + * MIC2L + * MIC2R + * LINE1L + * LINE1R + +CODEC input pins for other compatible codecs: * MIC3L * MIC3R * LINE1L diff --git a/Documentation/devicetree/bindings/sound/ts3a227e.txt b/Documentation/devicetree/bindings/sound/ts3a227e.txt index e8bf23eb1803..a836881d9608 100644 --- a/Documentation/devicetree/bindings/sound/ts3a227e.txt +++ b/Documentation/devicetree/bindings/sound/ts3a227e.txt @@ -13,6 +13,11 @@ Required properties: - interrupt-parent: The parent interrupt controller - interrupts: Interrupt number for /INT pin from the 227e +Optional properies: + - ti,micbias: Intended MICBIAS voltage (datasheet section 9.6.7). + Select 0/1/2/3/4/5/6/7 to specify MACBIAS voltage + 2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V + Default value is "1" (2.2V). Examples: diff --git a/Documentation/devicetree/bindings/sound/wm8904.txt b/Documentation/devicetree/bindings/sound/wm8904.txt index e99f4097c83c..66bf261423b9 100644 --- a/Documentation/devicetree/bindings/sound/wm8904.txt +++ b/Documentation/devicetree/bindings/sound/wm8904.txt @@ -3,7 +3,7 @@ WM8904 audio CODEC This device supports I2C only. Required properties: - - compatible: "wlf,wm8904" + - compatible: "wlf,wm8904" or "wlf,wm8912" - reg: the I2C address of the device. - clock-names: "mclk" - clocks: reference to diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt index 7ea701e07dc2..b785976fe98a 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt @@ -1,7 +1,9 @@ NVIDIA Tegra114 SPI controller. Required properties: -- compatible : should be "nvidia,tegra114-spi". +- compatible : For Tegra114, must contain "nvidia,tegra114-spi". + Otherwise, must contain '"nvidia,-spi", "nvidia,tegra114-spi"' where + is tegra124, tegra132, or tegra210. - reg: Should contain SPI registers location and length. - interrupts: Should contain SPI interrupts. - clock-names : Must include the following entries: diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt index d11c3721e7cd..4c388bb2f0a2 100644 --- a/Documentation/devicetree/bindings/spi/sh-msiof.txt +++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt @@ -30,6 +30,22 @@ Optional properties: specifiers, one for transmission, and one for reception. - dma-names : Must contain a list of two DMA names, "tx" and "rx". +- renesas,dtdl : delay sync signal (setup) in transmit mode. + Must contain one of the following values: + 0 (no bit delay) + 50 (0.5-clock-cycle delay) + 100 (1-clock-cycle delay) + 150 (1.5-clock-cycle delay) + 200 (2-clock-cycle delay) + +- renesas,syncdl : delay sync signal (hold) in transmit mode. + Must contain one of the following values: + 0 (no bit delay) + 50 (0.5-clock-cycle delay) + 100 (1-clock-cycle delay) + 150 (1.5-clock-cycle delay) + 200 (2-clock-cycle delay) + 300 (3-clock-cycle delay) Optional properties, deprecated for soctype-specific bindings: - renesas,tx-fifo-size : Overrides the default tx fifo size given in words diff --git a/Documentation/devicetree/bindings/spi/spi-sirf.txt b/Documentation/devicetree/bindings/spi/spi-sirf.txt new file mode 100644 index 000000000000..4c7adb8f777c --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-sirf.txt @@ -0,0 +1,41 @@ +* CSR SiRFprimaII Serial Peripheral Interface + +Required properties: +- compatible : Should be "sirf,prima2-spi" +- reg : Offset and length of the register set for the device +- interrupts : Should contain SPI interrupt +- resets: phandle to the reset controller asserting this device in + reset + See ../reset/reset.txt for details. +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + +- #address-cells: Number of cells required to define a chip select + address on the SPI bus. Should be set to 1. +- #size-cells: Should be zero. + +Optional properties: +- spi-max-frequency: Specifies maximum SPI clock frequency, + Units - Hz. Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt +- cs-gpios: should specify GPIOs used for chipselects. + +Example: + +spi0: spi@b00d0000 { + compatible = "sirf,prima2-spi"; + reg = <0xb00d0000 0x10000>; + interrupts = <15>; + dmas = <&dmac1 9>, + <&dmac1 4>; + dma-names = "rx", "tx"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clks 19>; + resets = <&rstc 26>; +}; diff --git a/Documentation/devicetree/bindings/spi/spi-st-ssc.txt b/Documentation/devicetree/bindings/spi/spi-st-ssc.txt new file mode 100644 index 000000000000..fe54959ec957 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-st-ssc.txt @@ -0,0 +1,40 @@ +STMicroelectronics SSC (SPI) Controller +--------------------------------------- + +Required properties: +- compatible : "st,comms-ssc4-spi" +- reg : Offset and length of the device's register set +- interrupts : The interrupt specifier +- clock-names : Must contain "ssc" +- clocks : Must contain an entry for each name in clock-names + See ../clk/* +- pinctrl-names : Uses "default", can use "sleep" if provided + See ../pinctrl/pinctrl-binding.txt + +Optional properties: +- cs-gpios : List of GPIO chip selects + See ../spi/spi-bus.txt + +Child nodes represent devices on the SPI bus + See ../spi/spi-bus.txt + +Example: + spi@9840000 { + compatible = "st,comms-ssc4-spi"; + reg = <0x9840000 0x110>; + interrupts = ; + clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>; + clock-names = "ssc"; + pinctrl-0 = <&pinctrl_spi0_default>; + pinctrl-names = "default"; + cs-gpios = <&pio17 5 0>; + #address-cells = <1>; + #size-cells = <0>; + + st95hf@0{ + compatible = "st,st95hf"; + reg = <0>; + spi-max-frequency = <1000000>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + }; + }; diff --git a/Documentation/devicetree/bindings/submitting-patches.txt b/Documentation/devicetree/bindings/submitting-patches.txt index b7ba01ad1426..56742bc70218 100644 --- a/Documentation/devicetree/bindings/submitting-patches.txt +++ b/Documentation/devicetree/bindings/submitting-patches.txt @@ -15,6 +15,29 @@ I. For patch submitters 3) The Documentation/ portion of the patch should come in the series before the code implementing the binding. + 4) Any compatible strings used in a chip or board DTS file must be + previously documented in the corresponding DT binding text file + in Documentation/devicetree/bindings. This rule applies even if + the Linux device driver does not yet match on the compatible + string. [ checkpatch will emit warnings if this step is not + followed as of commit bff5da4335256513497cc8c79f9a9d1665e09864 + ("checkpatch: add DT compatible string documentation checks"). ] + + 5) The wildcard "" may be used in compatible strings, as in + the following example: + + - compatible: Must contain '"nvidia,-pcie", + "nvidia,tegra20-pcie"' where is tegra30, tegra132, ... + + As in the above example, the known values of "" should be + documented if it is used. + + 6) If a documented compatible string is not yet matched by the + driver, the documentation should also include a compatible + string that is matched by the driver (as in the "nvidia,tegra20-pcie" + example above). + + II. For kernel maintainers 1) If you aren't comfortable reviewing a given binding, reply to it and ask diff --git a/Documentation/devicetree/bindings/thermal/tegra-soctherm.txt b/Documentation/devicetree/bindings/thermal/tegra-soctherm.txt index ecf3ed76cd46..6b68cd150405 100644 --- a/Documentation/devicetree/bindings/thermal/tegra-soctherm.txt +++ b/Documentation/devicetree/bindings/thermal/tegra-soctherm.txt @@ -7,7 +7,9 @@ notifications. It is also used to manage emergency shutdown in an overheating situation. Required properties : -- compatible : "nvidia,tegra124-soctherm". +- compatible : For Tegra124, must contain "nvidia,tegra124-soctherm". + For Tegra132, must contain "nvidia,tegra132-soctherm". + For Tegra210, must contain "nvidia,tegra210-soctherm". - reg : Should contain 1 entry: - SOCTHERM register set - interrupts : Defines the interrupt used by SOCTHERM diff --git a/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt b/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt index b5082a1cf461..1761f53ee36f 100644 --- a/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt +++ b/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt @@ -6,7 +6,9 @@ trigger a legacy watchdog reset. Required properties: -- compatible : should be "nvidia,tegra30-timer", "nvidia,tegra20-timer". +- compatible : For Tegra30, must contain "nvidia,tegra30-timer". Otherwise, + must contain '"nvidia,-timer", "nvidia,tegra30-timer"' where + is tegra124 or tegra132. - reg : Specifies base physical address and size of the registers. - interrupts : A list of 6 interrupts; one per each of timer channels 1 through 5, and one for the shared interrupt for the remaining channels. diff --git a/Documentation/devicetree/bindings/unittest.txt b/Documentation/devicetree/bindings/unittest.txt index 0f92a22fddfa..8933211f32f9 100644 --- a/Documentation/devicetree/bindings/unittest.txt +++ b/Documentation/devicetree/bindings/unittest.txt @@ -1,4 +1,4 @@ -* OF selftest platform device +1) OF selftest platform device ** selftest @@ -12,3 +12,60 @@ Example: compatible = "selftest"; status = "okay"; }; + +2) OF selftest i2c adapter platform device + +** platform device unittest adapter + +Required properties: +- compatible: must be selftest-i2c-bus + +Children nodes contain selftest i2c devices. + +Example: + selftest-i2c-bus { + compatible = "selftest-i2c-bus"; + status = "okay"; + }; + +3) OF selftest i2c device + +** I2C selftest device + +Required properties: +- compatible: must be selftest-i2c-dev + +All other properties are optional + +Example: + selftest-i2c-dev { + compatible = "selftest-i2c-dev"; + status = "okay"; + }; + +4) OF selftest i2c mux device + +** I2C selftest mux + +Required properties: +- compatible: must be selftest-i2c-mux + +Children nodes contain selftest i2c bus nodes per channel. + +Example: + selftest-i2c-mux { + compatible = "selftest-i2c-mux"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + channel-0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + i2c-dev { + reg = <8>; + compatible = "selftest-i2c-dev"; + status = "okay"; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt index 3dc9140e3dfb..f60785f73d3d 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt @@ -6,7 +6,10 @@ Practice : Universal Serial Bus" with the following modifications and additions : Required properties : - - compatible : Should be "nvidia,tegra20-ehci". + - compatible : For Tegra20, must contain "nvidia,tegra20-ehci". + For Tegra30, must contain "nvidia,tegra30-ehci". Otherwise, must contain + "nvidia,-ehci" plus at least one of the above, where is + tegra114, tegra124, tegra132, or tegra210. - nvidia,phy : phandle of the PHY that the controller is connected to. - clocks : Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt index c9205fbf26e2..a9aa79fb90ed 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt @@ -3,7 +3,10 @@ Tegra SOC USB PHY The device node for Tegra SOC USB PHY: Required properties : - - compatible : Should be "nvidia,tegra-usb-phy". + - compatible : For Tegra20, must contain "nvidia,tegra20-usb-phy". + For Tegra30, must contain "nvidia,tegra30-usb-phy". Otherwise, must contain + "nvidia,-usb-phy" plus at least one of the above, where is + tegra114, tegra124, tegra132, or tegra210. - reg : Defines the following set of registers, in the order listed: - The PHY's own register set. Always present. diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index b1df0ad1306c..7075698abd8c 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -7,9 +7,9 @@ abilis Abilis Systems active-semi Active-Semi International Inc ad Avionic Design GmbH adapteva Adapteva, Inc. +adh AD Holdings Plc. adi Analog Devices, Inc. aeroflexgaisler Aeroflex Gaisler AB -ak Asahi Kasei Corp. allwinner Allwinner Technology Co., Ltd. altr Altera Corp. amcc Applied Micro Circuits Corporation (APM, formally AMCC) @@ -20,6 +20,7 @@ amstaos AMS-Taos Inc. apm Applied Micro Circuits Corporation (APM) arm ARM Ltd. armadeus ARMadeus Systems SARL +asahi-kasei Asahi Kasei Corp. atmel Atmel Corporation auo AU Optronics Corporation avago Avago Technologies @@ -54,8 +55,10 @@ epcos EPCOS AG epfl Ecole Polytechnique Fédérale de Lausanne epson Seiko Epson Corp. est ESTeem Wireless Modems +ettus NI Ettus Research eukrea Eukréa Electromatique everest Everest Semiconductor Co. Ltd. +everspin Everspin Technologies, Inc. excito Excito fcs Fairchild Semiconductor fsl Freescale Semiconductor @@ -69,6 +72,7 @@ gumstix Gumstix, Inc. gw Gateworks Corporation hannstar HannStar Display Corporation haoyu Haoyu Microelectronic Co. Ltd. +himax Himax Technologies, Inc. hisilicon Hisilicon Limited. hit Hitachi Ltd. honeywell Honeywell @@ -82,8 +86,7 @@ innolux Innolux Corporation intel Intel Corporation intercontrol Inter Control Group isee ISEE 2007 S.L. -isil Intersil (deprecated, use isl) -isl Intersil +isil Intersil karo Ka-Ro electronics GmbH keymile Keymile GmbH lacie LaCie @@ -118,6 +121,7 @@ nvidia NVIDIA nxp NXP Semiconductors onnn ON Semiconductor Corp. opencores OpenCores.org +ovti OmniVision Technologies panasonic Panasonic Corporation pericom Pericom Technology Inc. phytec PHYTEC Messtechnik GmbH @@ -127,6 +131,7 @@ pixcir PIXCIR MICROELECTRONICS Co., Ltd powervr PowerVR (deprecated, use img) qca Qualcomm Atheros, Inc. qcom Qualcomm Technologies, Inc +qemu QEMU, a generic and open source machine emulator and virtualizer qnap QNAP Systems, Inc. radxa Radxa raidsonic RaidSonic Technology GmbH @@ -141,8 +146,10 @@ sandisk Sandisk Corporation sbs Smart Battery System schindler Schindler seagate Seagate Technology PLC +semtech Semtech Corporation sil Silicon Image silabs Silicon Laboratories +siliconmitus Silicon Mitus, Inc. simtek sii Seiko Instruments, Inc. silergy Silergy Corp. @@ -164,10 +171,12 @@ tlm Trusted Logic Mobility toradex Toradex AG toshiba Toshiba Corporation toumaz Toumaz +truly Truly Semiconductors Limited usi Universal Scientific Industrial Co., Ltd. v3 V3 Semiconductor variscite Variscite Ltd. via VIA Technologies, Inc. +virtio Virtual I/O Device Specification, developed by the OASIS consortium voipac Voipac Technologies s.r.o. winbond Winbond Electronics corp. wlf Wolfson Microelectronics diff --git a/Documentation/devicetree/bindings/video/ti,dra7-dss.txt b/Documentation/devicetree/bindings/video/ti,dra7-dss.txt new file mode 100644 index 000000000000..f33a05137b0e --- /dev/null +++ b/Documentation/devicetree/bindings/video/ti,dra7-dss.txt @@ -0,0 +1,69 @@ +Texas Instruments DRA7x Display Subsystem +========================================= + +See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic +description about OMAP Display Subsystem bindings. + +DSS Core +-------- + +Required properties: +- compatible: "ti,dra7-dss" +- reg: address and length of the register spaces for 'dss' +- ti,hwmods: "dss_core" +- clocks: handle to fclk +- clock-names: "fck" +- syscon: phandle to control module core syscon node + +Optional properties: + +Some DRA7xx SoCs have one dedicated video PLL, some have two. These properties +can be used to describe the video PLLs: + +- reg: address and length of the register spaces for 'pll1_clkctrl', + 'pll1', 'pll2_clkctrl', 'pll2' +- clocks: handle to video1 pll clock and video2 pll clock +- clock-names: "video1_clk" and "video2_clk" + +Required nodes: +- DISPC + +Optional nodes: +- DSS Submodules: HDMI +- Video port for DPI output + +DPI Endpoint required properties: +- data-lines: number of lines used + + +DISPC +----- + +Required properties: +- compatible: "ti,dra7-dispc" +- reg: address and length of the register space +- ti,hwmods: "dss_dispc" +- interrupts: the DISPC interrupt +- clocks: handle to fclk +- clock-names: "fck" + +HDMI +---- + +Required properties: +- compatible: "ti,dra7-hdmi" +- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy', + 'core' +- reg-names: "wp", "pll", "phy", "core" +- interrupts: the HDMI interrupt line +- ti,hwmods: "dss_hdmi" +- vdda-supply: vdda power supply +- clocks: handles to fclk and pll clock +- clock-names: "fck", "sys_clk" + +Optional nodes: +- Video port for HDMI output + +HDMI Endpoint optional properties: +- lanes: list of 8 pin numbers for the HDMI lanes: CLK+, CLK-, D0+, D0-, + D1+, D1-, D2+, D2-. (default: 0,1,2,3,4,5,6,7) diff --git a/Documentation/devicetree/bindings/video/ti,opa362.txt b/Documentation/devicetree/bindings/video/ti,opa362.txt new file mode 100644 index 000000000000..f96083c0bd17 --- /dev/null +++ b/Documentation/devicetree/bindings/video/ti,opa362.txt @@ -0,0 +1,38 @@ +OPA362 analog video amplifier + +Required properties: +- compatible: "ti,opa362" +- enable-gpios: enable/disable output gpio + +Required node: +- Video port 0 for opa362 input +- Video port 1 for opa362 output + +Example: + +tv_amp: opa362 { + compatible = "ti,opa362"; + enable-gpios = <&gpio1 23 0>; /* GPIO to enable video out amplifier */ + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + opa_in: endpoint@0 { + remote-endpoint = <&venc_out>; + }; + }; + + port@1 { + reg = <1>; + opa_out: endpoint@0 { + remote-endpoint = <&tv_connector_in>; + }; + }; + }; +}; + + + diff --git a/Documentation/devicetree/overlay-notes.txt b/Documentation/devicetree/overlay-notes.txt index 30ae758e3eef..d418a6ce9812 100644 --- a/Documentation/devicetree/overlay-notes.txt +++ b/Documentation/devicetree/overlay-notes.txt @@ -10,7 +10,7 @@ How overlays work ----------------- A Device Tree's overlay purpose is to modify the kernel's live tree, and -have the modification affecting the state of the the kernel in a way that +have the modification affecting the state of the kernel in a way that is reflecting the changes. Since the kernel mainly deals with devices, any new device node that result in an active device should have it created while if the device node is either @@ -80,7 +80,7 @@ result in foo+bar.dts }; ---- foo+bar.dts ------------------------------------------------------------- -As a result of the the overlay, a new device node (bar) has been created +As a result of the overlay, a new device node (bar) has been created so a bar platform device will be registered and if a matching device driver is loaded the device will be created as expected. diff --git a/Documentation/dmaengine/00-INDEX b/Documentation/dmaengine/00-INDEX new file mode 100644 index 000000000000..07de6573d22b --- /dev/null +++ b/Documentation/dmaengine/00-INDEX @@ -0,0 +1,8 @@ +00-INDEX + - this file. +client.txt + -the DMA Engine API Guide. +dmatest.txt + - how to compile, configure and use the dmatest system. +provider.txt + - the DMA controller API. \ No newline at end of file diff --git a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt index 6754b2df8aa1..b577a45b93ea 100644 --- a/Documentation/driver-model/bus.txt +++ b/Documentation/driver-model/bus.txt @@ -45,7 +45,7 @@ them are inherently bus-specific. Drivers typically declare an array of device IDs of devices they support that reside in a bus-specific driver structure. -The purpose of the match callback is provide the bus an opportunity to +The purpose of the match callback is to give the bus an opportunity to determine if a particular driver supports a particular device by comparing the device IDs the driver supports with the device ID of a particular device, without sacrificing bus-specific functionality or diff --git a/Documentation/filesystems/fiemap.txt b/Documentation/filesystems/fiemap.txt index 1b805a0efbb0..f6d9c99103a4 100644 --- a/Documentation/filesystems/fiemap.txt +++ b/Documentation/filesystems/fiemap.txt @@ -196,7 +196,8 @@ struct fiemap_extent_info { }; It is intended that the file system should not need to access any of this -structure directly. +structure directly. Filesystem handlers should be tolerant to signals and return +EINTR once fatal signal received. Flag checking should be done at the beginning of the ->fiemap callback via the diff --git a/Documentation/filesystems/inotify.txt b/Documentation/filesystems/inotify.txt index cfd02712b83e..51f61db787fb 100644 --- a/Documentation/filesystems/inotify.txt +++ b/Documentation/filesystems/inotify.txt @@ -4,201 +4,10 @@ Document started 15 Mar 2005 by Robert Love +Document updated 4 Jan 2015 by Zhang Zhen + --Deleted obsoleted interface, just refer to manpages for user interface. - -(i) User Interface - -Inotify is controlled by a set of three system calls and normal file I/O on a -returned file descriptor. - -First step in using inotify is to initialise an inotify instance: - - int fd = inotify_init (); - -Each instance is associated with a unique, ordered queue. - -Change events are managed by "watches". A watch is an (object,mask) pair where -the object is a file or directory and the mask is a bit mask of one or more -inotify events that the application wishes to receive. See -for valid events. A watch is referenced by a watch descriptor, or wd. - -Watches are added via a path to the file. - -Watches on a directory will return events on any files inside of the directory. - -Adding a watch is simple: - - int wd = inotify_add_watch (fd, path, mask); - -Where "fd" is the return value from inotify_init(), path is the path to the -object to watch, and mask is the watch mask (see ). - -You can update an existing watch in the same manner, by passing in a new mask. - -An existing watch is removed via - - int ret = inotify_rm_watch (fd, wd); - -Events are provided in the form of an inotify_event structure that is read(2) -from a given inotify instance. The filename is of dynamic length and follows -the struct. It is of size len. The filename is padded with null bytes to -ensure proper alignment. This padding is reflected in len. - -You can slurp multiple events by passing a large buffer, for example - - size_t len = read (fd, buf, BUF_LEN); - -Where "buf" is a pointer to an array of "inotify_event" structures at least -BUF_LEN bytes in size. The above example will return as many events as are -available and fit in BUF_LEN. - -Each inotify instance fd is also select()- and poll()-able. - -You can find the size of the current event queue via the standard FIONREAD -ioctl on the fd returned by inotify_init(). - -All watches are destroyed and cleaned up on close. - - -(ii) - -Prototypes: - - int inotify_init (void); - int inotify_add_watch (int fd, const char *path, __u32 mask); - int inotify_rm_watch (int fd, __u32 mask); - - -(iii) Kernel Interface - -Inotify's kernel API consists a set of functions for managing watches and an -event callback. - -To use the kernel API, you must first initialize an inotify instance with a set -of inotify_operations. You are given an opaque inotify_handle, which you use -for any further calls to inotify. - - struct inotify_handle *ih = inotify_init(my_event_handler); - -You must provide a function for processing events and a function for destroying -the inotify watch. - - void handle_event(struct inotify_watch *watch, u32 wd, u32 mask, - u32 cookie, const char *name, struct inode *inode) - - watch - the pointer to the inotify_watch that triggered this call - wd - the watch descriptor - mask - describes the event that occurred - cookie - an identifier for synchronizing events - name - the dentry name for affected files in a directory-based event - inode - the affected inode in a directory-based event - - void destroy_watch(struct inotify_watch *watch) - -You may add watches by providing a pre-allocated and initialized inotify_watch -structure and specifying the inode to watch along with an inotify event mask. -You must pin the inode during the call. You will likely wish to embed the -inotify_watch structure in a structure of your own which contains other -information about the watch. Once you add an inotify watch, it is immediately -subject to removal depending on filesystem events. You must grab a reference if -you depend on the watch hanging around after the call. - - inotify_init_watch(&my_watch->iwatch); - inotify_get_watch(&my_watch->iwatch); // optional - s32 wd = inotify_add_watch(ih, &my_watch->iwatch, inode, mask); - inotify_put_watch(&my_watch->iwatch); // optional - -You may use the watch descriptor (wd) or the address of the inotify_watch for -other inotify operations. You must not directly read or manipulate data in the -inotify_watch. Additionally, you must not call inotify_add_watch() more than -once for a given inotify_watch structure, unless you have first called either -inotify_rm_watch() or inotify_rm_wd(). - -To determine if you have already registered a watch for a given inode, you may -call inotify_find_watch(), which gives you both the wd and the watch pointer for -the inotify_watch, or an error if the watch does not exist. - - wd = inotify_find_watch(ih, inode, &watchp); - -You may use container_of() on the watch pointer to access your own data -associated with a given watch. When an existing watch is found, -inotify_find_watch() bumps the refcount before releasing its locks. You must -put that reference with: - - put_inotify_watch(watchp); - -Call inotify_find_update_watch() to update the event mask for an existing watch. -inotify_find_update_watch() returns the wd of the updated watch, or an error if -the watch does not exist. - - wd = inotify_find_update_watch(ih, inode, mask); - -An existing watch may be removed by calling either inotify_rm_watch() or -inotify_rm_wd(). - - int ret = inotify_rm_watch(ih, &my_watch->iwatch); - int ret = inotify_rm_wd(ih, wd); - -A watch may be removed while executing your event handler with the following: - - inotify_remove_watch_locked(ih, iwatch); - -Call inotify_destroy() to remove all watches from your inotify instance and -release it. If there are no outstanding references, inotify_destroy() will call -your destroy_watch op for each watch. - - inotify_destroy(ih); - -When inotify removes a watch, it sends an IN_IGNORED event to your callback. -You may use this event as an indication to free the watch memory. Note that -inotify may remove a watch due to filesystem events, as well as by your request. -If you use IN_ONESHOT, inotify will remove the watch after the first event, at -which point you may call the final inotify_put_watch. - -(iv) Kernel Interface Prototypes - - struct inotify_handle *inotify_init(struct inotify_operations *ops); - - inotify_init_watch(struct inotify_watch *watch); - - s32 inotify_add_watch(struct inotify_handle *ih, - struct inotify_watch *watch, - struct inode *inode, u32 mask); - - s32 inotify_find_watch(struct inotify_handle *ih, struct inode *inode, - struct inotify_watch **watchp); - - s32 inotify_find_update_watch(struct inotify_handle *ih, - struct inode *inode, u32 mask); - - int inotify_rm_wd(struct inotify_handle *ih, u32 wd); - - int inotify_rm_watch(struct inotify_handle *ih, - struct inotify_watch *watch); - - void inotify_remove_watch_locked(struct inotify_handle *ih, - struct inotify_watch *watch); - - void inotify_destroy(struct inotify_handle *ih); - - void get_inotify_watch(struct inotify_watch *watch); - void put_inotify_watch(struct inotify_watch *watch); - - -(v) Internal Kernel Implementation - -Each inotify instance is represented by an inotify_handle structure. -Inotify's userspace consumers also have an inotify_device which is -associated with the inotify_handle, and on which events are queued. - -Each watch is associated with an inotify_watch structure. Watches are chained -off of each associated inotify_handle and each associated inode. - -See fs/notify/inotify/inotify_fsnotify.c and fs/notify/inotify/inotify_user.c -for the locking and lifetime rules. - - -(vi) Rationale +(i) Rationale Q: What is the design decision behind not tying the watch to the open fd of the watched object? diff --git a/Documentation/filesystems/nfs/nfs41-server.txt b/Documentation/filesystems/nfs/nfs41-server.txt index c49cd7e796e7..682a59fabe3f 100644 --- a/Documentation/filesystems/nfs/nfs41-server.txt +++ b/Documentation/filesystems/nfs/nfs41-server.txt @@ -24,11 +24,6 @@ focuses on the mandatory-to-implement NFSv4.1 Sessions, providing "exactly once" semantics and better control and throttling of the resources allocated for each client. -Other NFSv4.1 features, Parallel NFS operations in particular, -are still under development out of tree. -See http://wiki.linux-nfs.org/wiki/index.php/PNFS_prototype_design -for more information. - The table below, taken from the NFSv4.1 document, lists the operations that are mandatory to implement (REQ), optional (OPT), and NFSv4.0 operations that are required not to implement (MNI) @@ -43,9 +38,7 @@ The OPTIONAL features identified and their abbreviations are as follows: The following abbreviations indicate the linux server implementation status. I Implemented NFSv4.1 operations. NS Not Supported. - NS* unimplemented optional feature. - P pNFS features implemented out of tree. - PNS pNFS features that are not supported yet (out of tree). + NS* Unimplemented optional feature. Operations @@ -70,13 +63,13 @@ I | DESTROY_SESSION | REQ | | Section 18.37 | I | EXCHANGE_ID | REQ | | Section 18.35 | I | FREE_STATEID | REQ | | Section 18.38 | | GETATTR | REQ | | Section 18.7 | -P | GETDEVICEINFO | OPT | pNFS (REQ) | Section 18.40 | -P | GETDEVICELIST | OPT | pNFS (OPT) | Section 18.41 | +I | GETDEVICEINFO | OPT | pNFS (REQ) | Section 18.40 | +NS*| GETDEVICELIST | OPT | pNFS (OPT) | Section 18.41 | | GETFH | REQ | | Section 18.8 | NS*| GET_DIR_DELEGATION | OPT | DDELG (REQ) | Section 18.39 | -P | LAYOUTCOMMIT | OPT | pNFS (REQ) | Section 18.42 | -P | LAYOUTGET | OPT | pNFS (REQ) | Section 18.43 | -P | LAYOUTRETURN | OPT | pNFS (REQ) | Section 18.44 | +I | LAYOUTCOMMIT | OPT | pNFS (REQ) | Section 18.42 | +I | LAYOUTGET | OPT | pNFS (REQ) | Section 18.43 | +I | LAYOUTRETURN | OPT | pNFS (REQ) | Section 18.44 | | LINK | OPT | | Section 18.9 | | LOCK | REQ | | Section 18.10 | | LOCKT | REQ | | Section 18.11 | @@ -122,9 +115,9 @@ Callback Operations | | MNI | or OPT) | | +-------------------------+-----------+-------------+---------------+ | CB_GETATTR | OPT | FDELG (REQ) | Section 20.1 | -P | CB_LAYOUTRECALL | OPT | pNFS (REQ) | Section 20.3 | +I | CB_LAYOUTRECALL | OPT | pNFS (REQ) | Section 20.3 | NS*| CB_NOTIFY | OPT | DDELG (REQ) | Section 20.4 | -P | CB_NOTIFY_DEVICEID | OPT | pNFS (OPT) | Section 20.12 | +NS*| CB_NOTIFY_DEVICEID | OPT | pNFS (OPT) | Section 20.12 | NS*| CB_NOTIFY_LOCK | OPT | | Section 20.11 | NS*| CB_PUSH_DELEG | OPT | FDELG (OPT) | Section 20.5 | | CB_RECALL | OPT | FDELG, | Section 20.2 | diff --git a/Documentation/filesystems/nfs/pnfs-block-server.txt b/Documentation/filesystems/nfs/pnfs-block-server.txt new file mode 100644 index 000000000000..2143673cf154 --- /dev/null +++ b/Documentation/filesystems/nfs/pnfs-block-server.txt @@ -0,0 +1,37 @@ +pNFS block layout server user guide + +The Linux NFS server now supports the pNFS block layout extension. In this +case the NFS server acts as Metadata Server (MDS) for pNFS, which in addition +to handling all the metadata access to the NFS export also hands out layouts +to the clients to directly access the underlying block devices that are +shared with the client. + +To use pNFS block layouts with with the Linux NFS server the exported file +system needs to support the pNFS block layouts (currently just XFS), and the +file system must sit on shared storage (typically iSCSI) that is accessible +to the clients in addition to the MDS. As of now the file system needs to +sit directly on the exported volume, striping or concatenation of +volumes on the MDS and clients is not supported yet. + +On the server, pNFS block volume support is automatically if the file system +support it. On the client make sure the kernel has the CONFIG_PNFS_BLOCK +option enabled, the blkmapd daemon from nfs-utils is running, and the +file system is mounted using the NFSv4.1 protocol version (mount -o vers=4.1). + +If the nfsd server needs to fence a non-responding client it calls +/sbin/nfsd-recall-failed with the first argument set to the IP address of +the client, and the second argument set to the device node without the /dev +prefix for the file system to be fenced. Below is an example file that shows +how to translate the device into a serial number from SCSI EVPD 0x80: + +cat > /sbin/nfsd-recall-failed << EOF +#!/bin/sh + +CLIENT="$1" +DEV="/dev/$2" +EVPD=`sg_inq --page=0x80 ${DEV} | \ + grep "Unit serial number:" | \ + awk -F ': ' '{print $2}'` + +echo "fencing client ${CLIENT} serial ${EVPD}" >> /var/log/pnfsd-fence.log +EOF diff --git a/Documentation/filesystems/ocfs2.txt b/Documentation/filesystems/ocfs2.txt index 7618a287aa41..28f8c08201e2 100644 --- a/Documentation/filesystems/ocfs2.txt +++ b/Documentation/filesystems/ocfs2.txt @@ -100,3 +100,7 @@ coherency=full (*) Disallow concurrent O_DIRECT writes, cluster inode coherency=buffered Allow concurrent O_DIRECT writes without EX lock among nodes, which gains high performance at risk of getting stale data on other nodes. +journal_async_commit Commit block can be written to disk without waiting + for descriptor blocks. If enabled older kernels cannot + mount the device. This will enable 'journal_checksum' + internally. diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index aae9dd13c91f..cf8fc2f0b34b 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -28,7 +28,7 @@ Table of Contents 1.6 Parallel port info in /proc/parport 1.7 TTY info in /proc/tty 1.8 Miscellaneous kernel statistics in /proc/stat - 1.9 Ext4 file system parameters + 1.9 Ext4 file system parameters 2 Modifying System Parameters @@ -42,6 +42,7 @@ Table of Contents 3.6 /proc//comm & /proc//task//comm 3.7 /proc//task//children - Information about task children 3.8 /proc//fdinfo/ - Information about opened file + 3.9 /proc//map_files - Information about memory mapped files 4 Configuring procfs 4.1 Mount options @@ -1763,6 +1764,28 @@ pair provide additional information particular to the objects they represent. with TIMER_ABSTIME option which will be shown in 'settime flags', but 'it_value' still exhibits timer's remaining time. +3.9 /proc//map_files - Information about memory mapped files +--------------------------------------------------------------------- +This directory contains symbolic links which represent memory mapped files +the process is maintaining. Example output: + + | lr-------- 1 root root 64 Jan 27 11:24 333c600000-333c620000 -> /usr/lib64/ld-2.18.so + | lr-------- 1 root root 64 Jan 27 11:24 333c81f000-333c820000 -> /usr/lib64/ld-2.18.so + | lr-------- 1 root root 64 Jan 27 11:24 333c820000-333c821000 -> /usr/lib64/ld-2.18.so + | ... + | lr-------- 1 root root 64 Jan 27 11:24 35d0421000-35d0422000 -> /usr/lib64/libselinux.so.1 + | lr-------- 1 root root 64 Jan 27 11:24 400000-41a000 -> /usr/bin/ls + +The name of a link represents the virtual memory bounds of a mapping, i.e. +vm_area_struct::vm_start-vm_area_struct::vm_end. + +The main purpose of the map_files is to retrieve a set of memory mapped +files in a fast way instead of parsing /proc//maps or +/proc//smaps, both of which contain many more records. At the same +time one can open(2) mappings from the listings of two processes and +comparing their inode numbers to figure out which anonymous memory areas +are actually shared. + ------------------------------------------------------------------------------ Configuring procfs ------------------------------------------------------------------------------ diff --git a/Documentation/filesystems/seq_file.txt b/Documentation/filesystems/seq_file.txt index b797ed38de46..9de4303201e1 100644 --- a/Documentation/filesystems/seq_file.txt +++ b/Documentation/filesystems/seq_file.txt @@ -194,16 +194,16 @@ which is in the string esc will be represented in octal form in the output. There are also a pair of functions for printing filenames: - int seq_path(struct seq_file *m, struct path *path, char *esc); - int seq_path_root(struct seq_file *m, struct path *path, - struct path *root, char *esc) + int seq_path(struct seq_file *m, const struct path *path, + const char *esc); + int seq_path_root(struct seq_file *m, const struct path *path, + const struct path *root, const char *esc) Here, path indicates the file of interest, and esc is a set of characters which should be escaped in the output. A call to seq_path() will output the path relative to the current process's filesystem root. If a different -root is desired, it can be used with seq_path_root(). Note that, if it -turns out that path cannot be reached from root, the value of root will be -changed in seq_file_root() to a root which *does* work. +root is desired, it can be used with seq_path_root(). If it turns out that +path cannot be reached from root, seq_path_root() returns SEQ_SKIP. A function producing complicated output may want to check bool seq_has_overflowed(struct seq_file *m); diff --git a/Documentation/filesystems/xfs.txt b/Documentation/filesystems/xfs.txt index 5be51fd888bd..0bfafe108357 100644 --- a/Documentation/filesystems/xfs.txt +++ b/Documentation/filesystems/xfs.txt @@ -287,9 +287,9 @@ The following sysctls are available for the XFS filesystem: XFS_ERRLEVEL_LOW: 1 XFS_ERRLEVEL_HIGH: 5 - fs.xfs.panic_mask (Min: 0 Default: 0 Max: 127) + fs.xfs.panic_mask (Min: 0 Default: 0 Max: 255) Causes certain error conditions to call BUG(). Value is a bitmask; - AND together the tags which represent errors which should cause panics: + OR together the tags which represent errors which should cause panics: XFS_NO_PTAG 0 XFS_PTAG_IFLUSH 0x00000001 @@ -299,6 +299,7 @@ The following sysctls are available for the XFS filesystem: XFS_PTAG_SHUTDOWN_CORRUPT 0x00000010 XFS_PTAG_SHUTDOWN_IOERROR 0x00000020 XFS_PTAG_SHUTDOWN_LOGERROR 0x00000040 + XFS_PTAG_FSBLOCK_ZERO 0x00000080 This option is intended for debugging only. @@ -348,16 +349,13 @@ The following sysctls are available for the XFS filesystem: Deprecated Sysctls ================== - fs.xfs.xfsbufd_centisecs (Min: 50 Default: 100 Max: 3000) - Dirty metadata is now tracked by the log subsystem and - flushing is driven by log space and idling demands. The - xfsbufd no longer exists, so this syctl does nothing. +None at present. - Due for removal in 3.14. - fs.xfs.age_buffer_centisecs (Min: 100 Default: 1500 Max: 720000) - Dirty metadata is now tracked by the log subsystem and - flushing is driven by log space and idling demands. The - xfsbufd no longer exists, so this syctl does nothing. +Removed Sysctls +=============== - Due for removal in 3.14. + Name Removed + ---- ------- + fs.xfs.xfsbufd_centisec v3.20 + fs.xfs.age_buffer_centisecs v3.20 diff --git a/Documentation/futex-requeue-pi.txt b/Documentation/futex-requeue-pi.txt index 31b16610c416..77b36f59d16b 100644 --- a/Documentation/futex-requeue-pi.txt +++ b/Documentation/futex-requeue-pi.txt @@ -98,7 +98,7 @@ rt_mutex_start_proxy_lock() and rt_mutex_finish_proxy_lock(), which allow the requeue code to acquire an uncontended rt_mutex on behalf of the waiter and to enqueue the waiter on a contended rt_mutex. Two new system calls provide the kernel<->user interface to -requeue_pi: FUTEX_WAIT_REQUEUE_PI and FUTEX_REQUEUE_CMP_PI. +requeue_pi: FUTEX_WAIT_REQUEUE_PI and FUTEX_CMP_REQUEUE_PI. FUTEX_WAIT_REQUEUE_PI is called by the waiter (pthread_cond_wait() and pthread_cond_timedwait()) to block on the initial futex and wait @@ -107,7 +107,7 @@ result of a high-speed collision between futex_wait() and futex_lock_pi(), with some extra logic to check for the additional wake-up scenarios. -FUTEX_REQUEUE_CMP_PI is called by the waker +FUTEX_CMP_REQUEUE_PI is called by the waker (pthread_cond_broadcast() and pthread_cond_signal()) to requeue and possibly wake the waiting tasks. Internally, this system call is still handled by futex_requeue (by passing requeue_pi=1). Before @@ -120,12 +120,12 @@ task as a waiter on the underlying rt_mutex. It is possible that the lock can be acquired at this stage as well, if so, the next waiter is woken to finish the acquisition of the lock. -FUTEX_REQUEUE_PI accepts nr_wake and nr_requeue as arguments, but +FUTEX_CMP_REQUEUE_PI accepts nr_wake and nr_requeue as arguments, but their sum is all that really matters. futex_requeue() will wake or requeue up to nr_wake + nr_requeue tasks. It will wake only as many tasks as it can acquire the lock for, which in the majority of cases should be 0 as good programming practice dictates that the caller of either pthread_cond_broadcast() or pthread_cond_signal() acquire the -mutex prior to making the call. FUTEX_REQUEUE_PI requires that +mutex prior to making the call. FUTEX_CMP_REQUEUE_PI requires that nr_wake=1. nr_requeue should be INT_MAX for broadcast and 0 for signal. diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt index 4452786225b8..8b35f51fe7b6 100644 --- a/Documentation/gpio/board.txt +++ b/Documentation/gpio/board.txt @@ -31,7 +31,7 @@ through gpiod_get(). For example: <&gpio 16 GPIO_ACTIVE_HIGH>, /* green */ <&gpio 17 GPIO_ACTIVE_HIGH>; /* blue */ - power-gpio = <&gpio 1 GPIO_ACTIVE_LOW>; + power-gpios = <&gpio 1 GPIO_ACTIVE_LOW>; }; This property will make GPIOs 15, 16 and 17 available to the driver under the diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx index 4223c2d3b508..cfd31d94c872 100644 --- a/Documentation/hwmon/ina2xx +++ b/Documentation/hwmon/ina2xx @@ -26,6 +26,12 @@ Supported chips: Datasheet: Publicly available at the Texas Instruments website http://www.ti.com/ + * Texas Instruments INA231 + Prefix: 'ina231' + Addresses: I2C 0x40 - 0x4f + Datasheet: Publicly available at the Texas Instruments website + http://www.ti.com/ + Author: Lothar Felten Description @@ -41,9 +47,18 @@ interface. The INA220 monitors both shunt drop and supply voltage. The INA226 is a current shunt and power monitor with an I2C interface. The INA226 monitors both a shunt voltage drop and bus supply voltage. -The INA230 is a high or low side current shunt and power monitor with an I2C -interface. The INA230 monitors both a shunt voltage drop and bus supply voltage. +INA230 and INA231 are high or low side current shunt and power monitors +with an I2C interface. The chips monitor both a shunt voltage drop and +bus supply voltage. -The shunt value in micro-ohms can be set via platform data or device tree. -Please refer to the Documentation/devicetree/bindings/i2c/ina2xx.txt for bindings +The shunt value in micro-ohms can be set via platform data or device tree at +compile-time or via the shunt_resistor attribute in sysfs at run-time. Please +refer to the Documentation/devicetree/bindings/i2c/ina2xx.txt for bindings if the device tree is used. + +Additionally ina226 supports update_interval attribute as described in +Documentation/hwmon/sysfs-interface. Internally the interval is the sum of +bus and shunt voltage conversion times multiplied by the averaging rate. We +don't touch the conversion times and only modify the number of averages. The +lower limit of the update_interval is 2 ms, the upper limit is 2253 ms. +The actual programmed interval may vary from the desired value. diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 4df73da11adc..a89e32637570 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1277,6 +1277,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. i8042.notimeout [HW] Ignore timeout condition signalled by controller i8042.reset [HW] Reset the controller during init and cleanup i8042.unlock [HW] Unlock (ignore) the keylock + i8042.kbdreset [HW] Reset device connected to KBD port i810= [HW,DRM] @@ -1469,6 +1470,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. no_hwp Do not enable hardware P state control (HWP) if available. + hwp_only + Only load intel_pstate on systems which support + hardware P state control (HWP) if available. intremap= [X86-64, Intel-IOMMU] on enable Interrupt Remapping (default) @@ -1493,6 +1497,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. forcesac soft pt [x86, IA-64] + nobypass [PPC/POWERNV] + Disable IOMMU bypass, using IOMMU for PCI devices. io7= [HW] IO7 for Marvel based alpha systems @@ -3206,6 +3212,18 @@ bytes respectively. Such letter suffixes can also be entirely omitted. retain_initrd [RAM] Keep initrd memory after extraction + rfkill.default_state= + 0 "airplane mode". All wifi, bluetooth, wimax, gps, fm, + etc. communication is blocked by default. + 1 Unblocked. + + rfkill.master_switch_mode= + 0 The "airplane mode" button does nothing. + 1 The "airplane mode" button toggles between everything + blocked and the previous configuration. + 2 The "airplane mode" button toggles between everything + blocked and everything unblocked. + rhash_entries= [KNL,NET] Set number of hash buckets for route cache diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt index 4227ec2e3ab2..1488b6525eb6 100644 --- a/Documentation/kprobes.txt +++ b/Documentation/kprobes.txt @@ -702,7 +702,8 @@ a virtual address that is no longer valid (module init sections, module virtual addresses that correspond to modules that've been unloaded), such probes are marked with [GONE]. If the probe is temporarily disabled, such probes are marked with [DISABLED]. If the probe is optimized, it is -marked with [OPTIMIZED]. +marked with [OPTIMIZED]. If the probe is ftrace-based, it is marked with +[FTRACE]. /sys/kernel/debug/kprobes/enabled: Turn kprobes ON/OFF forcibly. diff --git a/Documentation/locking/00-INDEX b/Documentation/locking/00-INDEX new file mode 100644 index 000000000000..c256c9bee2a4 --- /dev/null +++ b/Documentation/locking/00-INDEX @@ -0,0 +1,16 @@ +00-INDEX + - this file. +lockdep-design.txt + - documentation on the runtime locking correctness validator. +lockstat.txt + - info on collecting statistics on locks (and contention). +mutex-design.txt + - info on the generic mutex subsystem. +rt-mutex-design.txt + - description of the RealTime mutex implementation design. +rt-mutex.txt + - desc. of RT-mutex subsystem with PI (Priority Inheritance) support. +spinlocks.txt + - info on using spinlocks to provide exclusive access in kernel. +ww-mutex-design.txt + - Intro to Mutex wait/would deadlock handling.s diff --git a/Documentation/locking/lockdep-design.txt b/Documentation/locking/lockdep-design.txt index 5dbc99c04f6e..5001280e9d82 100644 --- a/Documentation/locking/lockdep-design.txt +++ b/Documentation/locking/lockdep-design.txt @@ -34,7 +34,7 @@ The validator tracks lock-class usage history into 4n + 1 separate state bits: - 'ever held with STATE enabled' - 'ever held as readlock with STATE enabled' -Where STATE can be either one of (kernel/lockdep_states.h) +Where STATE can be either one of (kernel/locking/lockdep_states.h) - hardirq - softirq - reclaim_fs diff --git a/Documentation/locking/lockstat.txt b/Documentation/locking/lockstat.txt index 7428773a1e69..568bbbacee91 100644 --- a/Documentation/locking/lockstat.txt +++ b/Documentation/locking/lockstat.txt @@ -121,6 +121,11 @@ show the header with column descriptions. Lines 05-18 and 20-31 show the actual statistics. These statistics come in two parts; the actual stats separated by a short separator (line 08, 13) from the contention points. +Lines 09-12 show the first 4 recorded contention points (the code +which tries to get the lock) and lines 14-17 show the first 4 recorded +contended points (the lock holder). It is possible that the max +con-bounces point is missing in the statistics. + The first lock (05-18) is a read/write lock, and shows two lines above the short separator. The contention points don't match the column descriptors, they have two: contentions and [] symbol. The second set of contention diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 70a09f8a0383..ca2387ef27ab 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -269,6 +269,50 @@ And there are a number of things that _must_ or _must_not_ be assumed: STORE *(A + 4) = Y; STORE *A = X; STORE {*A, *(A + 4) } = {X, Y}; +And there are anti-guarantees: + + (*) These guarantees do not apply to bitfields, because compilers often + generate code to modify these using non-atomic read-modify-write + sequences. Do not attempt to use bitfields to synchronize parallel + algorithms. + + (*) Even in cases where bitfields are protected by locks, all fields + in a given bitfield must be protected by one lock. If two fields + in a given bitfield are protected by different locks, the compiler's + non-atomic read-modify-write sequences can cause an update to one + field to corrupt the value of an adjacent field. + + (*) These guarantees apply only to properly aligned and sized scalar + variables. "Properly sized" currently means variables that are + the same size as "char", "short", "int" and "long". "Properly + aligned" means the natural alignment, thus no constraints for + "char", two-byte alignment for "short", four-byte alignment for + "int", and either four-byte or eight-byte alignment for "long", + on 32-bit and 64-bit systems, respectively. Note that these + guarantees were introduced into the C11 standard, so beware when + using older pre-C11 compilers (for example, gcc 4.6). The portion + of the standard containing this guarantee is Section 3.14, which + defines "memory location" as follows: + + memory location + either an object of scalar type, or a maximal sequence + of adjacent bit-fields all having nonzero width + + NOTE 1: Two threads of execution can update and access + separate memory locations without interfering with + each other. + + NOTE 2: A bit-field and an adjacent non-bit-field member + are in separate memory locations. The same applies + to two bit-fields, if one is declared inside a nested + structure declaration and the other is not, or if the two + are separated by a zero-length bit-field declaration, + or if they are separated by a non-bit-field member + declaration. It is not safe to concurrently update two + bit-fields in the same structure if all members declared + between them are also bit-fields, no matter what the + sizes of those intervening bit-fields happen to be. + ========================= WHAT ARE MEMORY BARRIERS? @@ -750,7 +794,7 @@ In summary: However, they do -not- guarantee any other sort of ordering: Not prior loads against later loads, nor prior stores against later anything. If you need these other forms of ordering, - use smb_rmb(), smp_wmb(), or, in the case of prior stores and + use smp_rmb(), smp_wmb(), or, in the case of prior stores and later loads, smp_mb(). (*) If both legs of the "if" statement begin with identical stores diff --git a/Documentation/misc-devices/mei/mei-client-bus.txt b/Documentation/misc-devices/mei/mei-client-bus.txt index f83910a8ce76..743be4ec8989 100644 --- a/Documentation/misc-devices/mei/mei-client-bus.txt +++ b/Documentation/misc-devices/mei/mei-client-bus.txt @@ -1,9 +1,10 @@ Intel(R) Management Engine (ME) Client bus API -=============================================== +============================================== Rationale ========= + MEI misc character device is useful for dedicated applications to send and receive data to the many FW appliance found in Intel's ME from the user space. However for some of the ME functionalities it make sense to leverage existing software @@ -17,7 +18,8 @@ the existing code. MEI CL bus API -=========== +============== + A driver implementation for an MEI Client is very similar to existing bus based device drivers. The driver registers itself as an MEI CL bus driver through the mei_cl_driver structure: @@ -55,6 +57,7 @@ received buffers. Example ======= + As a theoretical example let's pretend the ME comes with a "contact" NFC IP. The driver init and exit routines for this device would look like: @@ -69,11 +72,11 @@ static struct mei_cl_device_id contact_mei_cl_tbl[] = { MODULE_DEVICE_TABLE(mei_cl, contact_mei_cl_tbl); static struct mei_cl_driver contact_driver = { - .id_table = contact_mei_tbl, - .name = CONTACT_DRIVER_NAME, + .id_table = contact_mei_tbl, + .name = CONTACT_DRIVER_NAME, - .probe = contact_probe, - .remove = contact_remove, + .probe = contact_probe, + .remove = contact_remove, }; static int contact_init(void) @@ -109,7 +112,7 @@ int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id) mei_cl_register_event_cb(dev, contact_event_cb, contact); return 0; - } +} In the probe routine the driver first enable the MEI device and then registers an ME bus event handler which is as close as it can get to registering a diff --git a/Documentation/misc-devices/mei/mei.txt b/Documentation/misc-devices/mei/mei.txt index 15bba1aeba9a..8d47501bba0a 100644 --- a/Documentation/misc-devices/mei/mei.txt +++ b/Documentation/misc-devices/mei/mei.txt @@ -1,8 +1,8 @@ Intel(R) Management Engine Interface (Intel(R) MEI) -======================= +=================================================== Introduction -======================= +============ The Intel Management Engine (Intel ME) is an isolated and protected computing resource (Co-processor) residing inside certain Intel chipsets. The Intel ME @@ -19,7 +19,7 @@ each client has its own protocol. The protocol is message-based with a header and payload up to 512 bytes. Prominent usage of the Intel ME Interface is to communicate with Intel(R) -Active Management Technology (Intel AMT)implemented in firmware running on +Active Management Technology (Intel AMT) implemented in firmware running on the Intel ME. Intel AMT provides the ability to manage a host remotely out-of-band (OOB) @@ -44,8 +44,9 @@ HTTP/S that are received from a remote management console application. For more information about Intel AMT: http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide + Intel MEI Driver -======================= +================ The driver exposes a misc device called /dev/mei. @@ -91,8 +92,10 @@ A code snippet for an application communicating with Intel AMTHI client: [...] close(fd); -IOCTL: -====== + +IOCTL +===== + The Intel MEI Driver supports the following IOCTL command: IOCTL_MEI_CONNECT_CLIENT Connect to firmware Feature (client). @@ -122,58 +125,61 @@ The Intel MEI Driver supports the following IOCTL command: data that can be sent or received. (e.g. if MTU=2K, can send requests up to bytes 2k and received responses up to 2k bytes). -Intel ME Applications: -============== -1) Intel Local Management Service (Intel LMS) +Intel ME Applications +===================== - Applications running locally on the platform communicate with Intel AMT Release - 2.0 and later releases in the same way that network applications do via SOAP - over HTTP (deprecated starting with Release 6.0) or with WS-Management over - SOAP over HTTP. This means that some Intel AMT features can be accessed from a - local application using the same network interface as a remote application - communicating with Intel AMT over the network. + 1) Intel Local Management Service (Intel LMS) - When a local application sends a message addressed to the local Intel AMT host - name, the Intel LMS, which listens for traffic directed to the host name, - intercepts the message and routes it to the Intel MEI. - For more information: - http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide - Under "About Intel AMT" => "Local Access" + Applications running locally on the platform communicate with Intel AMT Release + 2.0 and later releases in the same way that network applications do via SOAP + over HTTP (deprecated starting with Release 6.0) or with WS-Management over + SOAP over HTTP. This means that some Intel AMT features can be accessed from a + local application using the same network interface as a remote application + communicating with Intel AMT over the network. - For downloading Intel LMS: - http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers/ + When a local application sends a message addressed to the local Intel AMT host + name, the Intel LMS, which listens for traffic directed to the host name, + intercepts the message and routes it to the Intel MEI. + For more information: + http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide + Under "About Intel AMT" => "Local Access" - The Intel LMS opens a connection using the Intel MEI driver to the Intel LMS - firmware feature using a defined UUID and then communicates with the feature - using a protocol called Intel AMT Port Forwarding Protocol(Intel APF protocol). - The protocol is used to maintain multiple sessions with Intel AMT from a - single application. + For downloading Intel LMS: + http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers/ - See the protocol specification in the Intel AMT Software Development Kit(SDK) - http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide - Under "SDK Resources" => "Intel(R) vPro(TM) Gateway(MPS)" - => "Information for Intel(R) vPro(TM) Gateway Developers" - => "Description of the Intel AMT Port Forwarding (APF)Protocol" + The Intel LMS opens a connection using the Intel MEI driver to the Intel LMS + firmware feature using a defined UUID and then communicates with the feature + using a protocol called Intel AMT Port Forwarding Protocol (Intel APF protocol). + The protocol is used to maintain multiple sessions with Intel AMT from a + single application. - 2) Intel AMT Remote configuration using a Local Agent - A Local Agent enables IT personnel to configure Intel AMT out-of-the-box - without requiring installing additional data to enable setup. The remote - configuration process may involve an ISV-developed remote configuration - agent that runs on the host. - For more information: - http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide - Under "Setup and Configuration of Intel AMT" => - "SDK Tools Supporting Setup and Configuration" => - "Using the Local Agent Sample" + See the protocol specification in the Intel AMT Software Development Kit (SDK) + http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide + Under "SDK Resources" => "Intel(R) vPro(TM) Gateway (MPS)" + => "Information for Intel(R) vPro(TM) Gateway Developers" + => "Description of the Intel AMT Port Forwarding (APF) Protocol" - An open source Intel AMT configuration utility, implementing a local agent - that accesses the Intel MEI driver, can be found here: - http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers/ + 2) Intel AMT Remote configuration using a Local Agent + + A Local Agent enables IT personnel to configure Intel AMT out-of-the-box + without requiring installing additional data to enable setup. The remote + configuration process may involve an ISV-developed remote configuration + agent that runs on the host. + For more information: + http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide + Under "Setup and Configuration of Intel AMT" => + "SDK Tools Supporting Setup and Configuration" => + "Using the Local Agent Sample" + + An open source Intel AMT configuration utility, implementing a local agent + that accesses the Intel MEI driver, can be found here: + http://software.intel.com/en-us/articles/download-the-latest-intel-amt-open-source-drivers/ -Intel AMT OS Health Watchdog: -============================= +Intel AMT OS Health Watchdog +============================ + The Intel AMT Watchdog is an OS Health (Hang/Crash) watchdog. Whenever the OS hangs or crashes, Intel AMT will send an event to any subscriber to this event. This mechanism means that @@ -192,8 +198,10 @@ watchdog is 120 seconds. If the Intel AMT Watchdog feature does not exist (i.e. the connection failed), the Intel MEI driver will disable the sending of heartbeats. -Supported Chipsets: + +Supported Chipsets ================== + 7 Series Chipset Family 6 Series Chipset Family 5 Series Chipset Family diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index 557b6ef70c26..df27a1a50776 100644 --- a/Documentation/networking/00-INDEX +++ b/Documentation/networking/00-INDEX @@ -1,7 +1,5 @@ 00-INDEX - this file -3c505.txt - - information on the 3Com EtherLink Plus (3c505) driver. 3c509.txt - information on the 3Com Etherlink III Series Ethernet cards. 6pack.txt @@ -24,6 +22,8 @@ README.sb1000 - info on General Instrument/NextLevel SURFboard1000 cable modem. alias.txt - info on using alias network devices. +altera_tse.txt + - Altera Triple-Speed Ethernet controller. arcnet-hardware.txt - tons of info on ARCnet, hubs, jumper settings for ARCnet cards, etc. arcnet.txt @@ -42,6 +42,8 @@ bridge.txt - where to get user space programs for ethernet bridging with Linux. can.txt - documentation on CAN protocol family. +cdc_mbim.txt + - 3G/LTE USB modem (Mobile Broadband Interface Model) cops.txt - info on the COPS LocalTalk Linux driver cs89x0.txt @@ -54,6 +56,8 @@ cxgb.txt - Release Notes for the Chelsio N210 Linux device driver. dccp.txt - the Datagram Congestion Control Protocol (DCCP) (RFC 4340..42). +dctcp.txt + - DataCenter TCP congestion control de4x5.txt - the Digital EtherWORKS DE4?? and DE5?? PCI Ethernet driver decnet.txt diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt index 2236d6dcb7da..0a2859a8ee7e 100644 --- a/Documentation/networking/can.txt +++ b/Documentation/networking/can.txt @@ -234,7 +234,7 @@ solution for a couple of reasons: mechanisms. Inside this filter definition the (interested) type of errors may be selected. The reception of error messages is disabled by default. The format of the CAN error message frame is briefly - described in the Linux header file "include/linux/can/error.h". + described in the Linux header file "include/uapi/linux/can/error.h". 4. How to use SocketCAN ------------------------ diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt index 58d08f8d8d80..9930ecfbb465 100644 --- a/Documentation/networking/filter.txt +++ b/Documentation/networking/filter.txt @@ -279,8 +279,8 @@ Possible BPF extensions are shown in the following table: hatype skb->dev->type rxhash skb->hash cpu raw_smp_processor_id() - vlan_tci vlan_tx_tag_get(skb) - vlan_pr vlan_tx_tag_present(skb) + vlan_tci skb_vlan_tag_get(skb) + vlan_pr skb_vlan_tag_present(skb) rand prandom_u32() These extensions can also be prefixed with '#'. diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 85b022179104..1b8c964b0d17 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -290,6 +290,28 @@ tcp_frto - INTEGER By default it's enabled with a non-zero value. 0 disables F-RTO. +tcp_invalid_ratelimit - INTEGER + Limit the maximal rate for sending duplicate acknowledgments + in response to incoming TCP packets that are for an existing + connection but that are invalid due to any of these reasons: + + (a) out-of-window sequence number, + (b) out-of-window acknowledgment number, or + (c) PAWS (Protection Against Wrapped Sequence numbers) check failure + + This can help mitigate simple "ack loop" DoS attacks, wherein + a buggy or malicious middlebox or man-in-the-middle can + rewrite TCP header fields in manner that causes each endpoint + to think that the other is sending invalid TCP segments, thus + causing each side to send an unterminating stream of duplicate + acknowledgments for invalid segments. + + Using 0 disables rate-limiting of dupacks in response to + invalid segments; otherwise this value specifies the minimal + space between sending such dupacks, in milliseconds. + + Default: 500 (milliseconds). + tcp_keepalive_time - INTEGER How often TCP sends out keepalive messages when keepalive is enabled. Default: 2hours. @@ -1287,6 +1309,13 @@ accept_ra_rtr_pref - BOOLEAN Functional default: enabled if accept_ra is enabled. disabled if accept_ra is disabled. +accept_ra_mtu - BOOLEAN + Apply the MTU value specified in RA option 5 (RFC4861). If + disabled, the MTU specified in the RA will be ignored. + + Functional default: enabled if accept_ra is enabled. + disabled if accept_ra is disabled. + accept_redirects - BOOLEAN Accept Redirects. diff --git a/Documentation/networking/netlink_mmap.txt b/Documentation/networking/netlink_mmap.txt index c6af4bac5aa8..54f10478e8e3 100644 --- a/Documentation/networking/netlink_mmap.txt +++ b/Documentation/networking/netlink_mmap.txt @@ -199,16 +199,9 @@ frame header. TX limitations -------------- -Kernel processing usually involves validation of the message received by -user-space, then processing its contents. The kernel must assure that -userspace is not able to modify the message contents after they have been -validated. In order to do so, the message is copied from the ring frame -to an allocated buffer if either of these conditions is false: - -- only a single mapping of the ring exists -- the file descriptor is not shared between processes - -This means that for threaded programs, the kernel will fall back to copying. +As of Jan 2015 the message is always copied from the ring frame to an +allocated buffer due to unresolved security concerns. +See commit 4682a0358639b29cf ("netlink: Always copy on mmap TX."). Example ------- diff --git a/Documentation/networking/nf_conntrack-sysctl.txt b/Documentation/networking/nf_conntrack-sysctl.txt index 70da5086153d..f55599c62c9d 100644 --- a/Documentation/networking/nf_conntrack-sysctl.txt +++ b/Documentation/networking/nf_conntrack-sysctl.txt @@ -11,7 +11,8 @@ nf_conntrack_buckets - INTEGER (read-only) Size of hash table. If not specified as parameter during module loading, the default size is calculated by dividing total memory by 16384 to determine the number of buckets but the hash table will - never have fewer than 32 or more than 16384 buckets. + never have fewer than 32 and limited to 16384 buckets. For systems + with more than 4GB of memory it will be 65536 buckets. nf_conntrack_checksum - BOOLEAN 0 - disabled diff --git a/Documentation/networking/openvswitch.txt b/Documentation/networking/openvswitch.txt index 37c20ee2455e..b3b9ac61d29d 100644 --- a/Documentation/networking/openvswitch.txt +++ b/Documentation/networking/openvswitch.txt @@ -131,6 +131,19 @@ performs best-effort detection of overlapping wildcarded flows and may reject some but not all of them. However, this behavior may change in future versions. +Unique flow identifiers +----------------------- + +An alternative to using the original match portion of a key as the handle for +flow identification is a unique flow identifier, or "UFID". UFIDs are optional +for both the kernel and user space program. + +User space programs that support UFID are expected to provide it during flow +setup in addition to the flow, then refer to the flow using the UFID for all +future operations. The kernel is not required to index flows by the original +flow key if a UFID is specified. + + Basic rule for evolving flow keys --------------------------------- diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt index a5c784c89312..5f0922613f1a 100644 --- a/Documentation/networking/timestamping.txt +++ b/Documentation/networking/timestamping.txt @@ -162,6 +162,27 @@ SOF_TIMESTAMPING_OPT_CMSG: option IP_PKTINFO simultaneously. +SOF_TIMESTAMPING_OPT_TSONLY: + + Applies to transmit timestamps only. Makes the kernel return the + timestamp as a cmsg alongside an empty packet, as opposed to + alongside the original packet. This reduces the amount of memory + charged to the socket's receive budget (SO_RCVBUF) and delivers + the timestamp even if sysctl net.core.tstamp_allow_data is 0. + This option disables SOF_TIMESTAMPING_OPT_CMSG. + + +New applications are encouraged to pass SOF_TIMESTAMPING_OPT_ID to +disambiguate timestamps and SOF_TIMESTAMPING_OPT_TSONLY to operate +regardless of the setting of sysctl net.core.tstamp_allow_data. + +An exception is when a process needs additional cmsg data, for +instance SOL_IP/IP_PKTINFO to detect the egress network interface. +Then pass option SOF_TIMESTAMPING_OPT_CMSG. This option depends on +having access to the contents of the original packet, so cannot be +combined with SOF_TIMESTAMPING_OPT_TSONLY. + + 1.4 Bytestream Timestamps The SO_TIMESTAMPING interface supports timestamping of bytes in a diff --git a/Documentation/networking/timestamping/txtimestamp.c b/Documentation/networking/timestamping/txtimestamp.c index 876f71c5625a..8217510d3842 100644 --- a/Documentation/networking/timestamping/txtimestamp.c +++ b/Documentation/networking/timestamping/txtimestamp.c @@ -30,6 +30,8 @@ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ +#define _GNU_SOURCE + #include #include #include @@ -59,14 +61,6 @@ #include #include -/* ugly hack to work around netinet/in.h and linux/ipv6.h conflicts */ -#ifndef in6_pktinfo -struct in6_pktinfo { - struct in6_addr ipi6_addr; - int ipi6_ifindex; -}; -#endif - /* command line parameters */ static int cfg_proto = SOCK_STREAM; static int cfg_ipproto = IPPROTO_TCP; @@ -76,6 +70,7 @@ static int do_ipv6 = 1; static int cfg_payload_len = 10; static bool cfg_show_payload; static bool cfg_do_pktinfo; +static bool cfg_loop_nodata; static uint16_t dest_port = 9000; static struct sockaddr_in daddr; @@ -147,6 +142,9 @@ static void print_payload(char *data, int len) { int i; + if (!len) + return; + if (len > 70) len = 70; @@ -183,6 +181,7 @@ static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len) struct sock_extended_err *serr = NULL; struct scm_timestamping *tss = NULL; struct cmsghdr *cm; + int batch = 0; for (cm = CMSG_FIRSTHDR(msg); cm && cm->cmsg_len; @@ -215,10 +214,18 @@ static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len) } else fprintf(stderr, "unknown cmsg %d,%d\n", cm->cmsg_level, cm->cmsg_type); + + if (serr && tss) { + print_timestamp(tss, serr->ee_info, serr->ee_data, + payload_len); + serr = NULL; + tss = NULL; + batch++; + } } - if (serr && tss) - print_timestamp(tss, serr->ee_info, serr->ee_data, payload_len); + if (batch > 1) + fprintf(stderr, "batched %d timestamps\n", batch); } static int recv_errmsg(int fd) @@ -250,7 +257,7 @@ static int recv_errmsg(int fd) if (ret == -1 && errno != EAGAIN) error(1, errno, "recvmsg"); - if (ret > 0) { + if (ret >= 0) { __recv_errmsg_cmsg(&msg, ret); if (cfg_show_payload) print_payload(data, cfg_payload_len); @@ -315,6 +322,9 @@ static void do_test(int family, unsigned int opt) opt |= SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_OPT_CMSG | SOF_TIMESTAMPING_OPT_ID; + if (cfg_loop_nodata) + opt |= SOF_TIMESTAMPING_OPT_TSONLY; + if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, (char *) &opt, sizeof(opt))) error(1, 0, "setsockopt timestamping"); @@ -384,6 +394,7 @@ static void __attribute__((noreturn)) usage(const char *filepath) " -h: show this message\n" " -I: request PKTINFO\n" " -l N: send N bytes at a time\n" + " -n: set no-payload option\n" " -r: use raw\n" " -R: use raw (IP_HDRINCL)\n" " -p N: connect to port N\n" @@ -398,7 +409,7 @@ static void parse_opt(int argc, char **argv) int proto_count = 0; char c; - while ((c = getopt(argc, argv, "46hIl:p:rRux")) != -1) { + while ((c = getopt(argc, argv, "46hIl:np:rRux")) != -1) { switch (c) { case '4': do_ipv6 = 0; @@ -409,6 +420,9 @@ static void parse_opt(int argc, char **argv) case 'I': cfg_do_pktinfo = true; break; + case 'n': + cfg_loop_nodata = true; + break; case 'r': proto_count++; cfg_proto = SOCK_RAW; diff --git a/Documentation/nommu-mmap.txt b/Documentation/nommu-mmap.txt index 8e1ddec2c78a..ae57b9ea0d41 100644 --- a/Documentation/nommu-mmap.txt +++ b/Documentation/nommu-mmap.txt @@ -43,12 +43,12 @@ and it's also much more restricted in the latter case: even if this was created by another process. - If possible, the file mapping will be directly on the backing device - if the backing device has the BDI_CAP_MAP_DIRECT capability and + if the backing device has the NOMMU_MAP_DIRECT capability and appropriate mapping protection capabilities. Ramfs, romfs, cramfs and mtd might all permit this. - If the backing device device can't or won't permit direct sharing, - but does have the BDI_CAP_MAP_COPY capability, then a copy of the + but does have the NOMMU_MAP_COPY capability, then a copy of the appropriate bit of the file will be read into a contiguous bit of memory and any extraneous space beyond the EOF will be cleared @@ -220,7 +220,7 @@ directly (can't be copied). The file->f_op->mmap() operation will be called to actually inaugurate the mapping. It can be rejected at that point. Returning the ENOSYS error will -cause the mapping to be copied instead if BDI_CAP_MAP_COPY is specified. +cause the mapping to be copied instead if NOMMU_MAP_COPY is specified. The vm_ops->close() routine will be invoked when the last mapping on a chardev is removed. An existing mapping will be shared, partially or not, if possible @@ -232,7 +232,7 @@ want to handle it, despite the fact it's got an operation. For instance, it might try directing the call to a secondary driver which turns out not to implement it. Such is the case for the framebuffer driver which attempts to direct the call to the device-specific driver. Under such circumstances, the -mapping request will be rejected if BDI_CAP_MAP_COPY is not specified, and a +mapping request will be rejected if NOMMU_MAP_COPY is not specified, and a copy mapped otherwise. IMPORTANT NOTE: diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt index beefb9f82902..f3ac05cc23e4 100644 --- a/Documentation/oops-tracing.txt +++ b/Documentation/oops-tracing.txt @@ -270,6 +270,8 @@ characters, each representing a particular tainted value. 15: 'L' if a soft lockup has previously occurred on the system. + 16: 'K' if the kernel has been live patched. + The primary reason for the 'Tainted: ' string is to tell kernel debuggers if this is a clean kernel or if anything unusual has occurred. Tainting is permanent: even if an offending module is diff --git a/Documentation/power/s2ram.txt b/Documentation/power/s2ram.txt index 1bdfa0443773..4685aee197fd 100644 --- a/Documentation/power/s2ram.txt +++ b/Documentation/power/s2ram.txt @@ -69,6 +69,10 @@ Reason for this is that the RTC is the only reliably available piece of hardware during resume operations where a value can be set that will survive a reboot. +pm_trace is not compatible with asynchronous suspend, so it turns +asynchronous suspend off (which may work around timing or +ordering-sensitive bugs). + Consequence is that after a resume (even if it is successful) your system clock will have a value corresponding to the magic number instead of the correct date/time! It is therefore advisable to use a program like ntp-date diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index 427e89712f4a..2ee6ef9a6554 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt @@ -25,6 +25,9 @@ whether they can be changed or not: - soft block: writable radio block (need not be readable) that is set by the system software. +The rfkill subsystem has two parameters, rfkill.default_state and +rfkill.master_switch_mode, which are documented in kernel-parameters.txt. + 2. Implementation details diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt index 08911b5c6b0e..3df8babcdc41 100644 --- a/Documentation/s390/Debugging390.txt +++ b/Documentation/s390/Debugging390.txt @@ -1,14 +1,14 @@ - - Debugging on Linux for s/390 & z/Architecture - by - Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - Copyright (C) 2000-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation - Best viewed with fixed width fonts + + Debugging on Linux for s/390 & z/Architecture + by + Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + Copyright (C) 2000-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + Best viewed with fixed width fonts Overview of Document: ===================== -This document is intended to give a good overview of how to debug -Linux for s/390 & z/Architecture. It isn't intended as a complete reference & not a +This document is intended to give a good overview of how to debug Linux for +s/390 and z/Architecture. It is not intended as a complete reference and not a tutorial on the fundamentals of C & assembly. It doesn't go into 390 IO in any detail. It is intended to complement the documents in the reference section below & any other worthwhile references you get. @@ -35,7 +35,6 @@ Examining core dumps ldd Debugging modules The proc file system -Starting points for debugging scripting languages etc. SysRq References Special Thanks @@ -44,18 +43,20 @@ Register Set ============ The current architectures have the following registers. -16 General propose registers, 32 bit on s/390 64 bit on z/Architecture, r0-r15 or gpr0-gpr15 used for arithmetic & addressing. +16 General propose registers, 32 bit on s/390 and 64 bit on z/Architecture, +r0-r15 (or gpr0-gpr15), used for arithmetic and addressing. -16 Control registers, 32 bit on s/390 64 bit on z/Architecture, ( cr0-cr15 kernel usage only ) used for memory management, -interrupt control,debugging control etc. +16 Control registers, 32 bit on s/390 and 64 bit on z/Architecture, cr0-cr15, +kernel usage only, used for memory management, interrupt control, debugging +control etc. -16 Access registers ( ar0-ar15 ) 32 bit on s/390 & z/Architecture -not used by normal programs but potentially could -be used as temporary storage. Their main purpose is their 1 to 1 -association with general purpose registers and are used in -the kernel for copying data between kernel & user address spaces. -Access register 0 ( & access register 1 on z/Architecture ( needs 64 bit -pointer ) ) is currently used by the pthread library as a pointer to +16 Access registers (ar0-ar15), 32 bit on both s/390 and z/Architecture, +normally not used by normal programs but potentially could be used as +temporary storage. These registers have a 1:1 association with general +purpose registers and are designed to be used in the so-called access +register mode to select different address spaces. +Access register 0 (and access register 1 on z/Architecture, which needs a +64 bit pointer) is currently used by the pthread library as a pointer to the current running threads private area. 16 64 bit floating point registers (fp0-fp15 ) IEEE & HFP floating @@ -90,18 +91,19 @@ s/390 z/Architecture 6 6 Input/Output interrupt Mask -7 7 External interrupt Mask used primarily for interprocessor signalling & - clock interrupts. +7 7 External interrupt Mask used primarily for interprocessor + signalling and clock interrupts. -8-11 8-11 PSW Key used for complex memory protection mechanism not used under linux +8-11 8-11 PSW Key used for complex memory protection mechanism + (not used under linux) 12 12 1 on s/390 0 on z/Architecture 13 13 Machine Check Mask 1=enable machine check interrupts -14 14 Wait State set this to 1 to stop the processor except for interrupts & give - time to other LPARS used in CPU idle in the kernel to increase overall - usage of processor resources. +14 14 Wait State. Set this to 1 to stop the processor except for + interrupts and give time to other LPARS. Used in CPU idle in + the kernel to increase overall usage of processor resources. 15 15 Problem state ( if set to 1 certain instructions are disabled ) all linux user programs run with this bit 1 @@ -165,21 +167,23 @@ s/390 z/Architecture when loading the address with LPSWE otherwise a specification exception occurs, LPSW is fully backward compatible. - - + + Prefix Page(s) --------------- +-------------- This per cpu memory area is too intimately tied to the processor not to mention. -It exists between the real addresses 0-4096 on s/390 & 0-8192 z/Architecture & is exchanged -with a 1 page on s/390 or 2 pages on z/Architecture in absolute storage by the set -prefix instruction in linux'es startup. -This page is mapped to a different prefix for each processor in an SMP configuration -( assuming the os designer is sane of course :-) ). -Bytes 0-512 ( 200 hex ) on s/390 & 0-512,4096-4544,4604-5119 currently on z/Architecture -are used by the processor itself for holding such information as exception indications & -entry points for exceptions. -Bytes after 0xc00 hex are used by linux for per processor globals on s/390 & z/Architecture -( there is a gap on z/Architecture too currently between 0xc00 & 1000 which linux uses ). +It exists between the real addresses 0-4096 on s/390 and between 0-8192 on +z/Architecture and is exchanged with one page on s/390 or two pages on +z/Architecture in absolute storage by the set prefix instruction during Linux +startup. +This page is mapped to a different prefix for each processor in an SMP +configuration (assuming the OS designer is sane of course). +Bytes 0-512 (200 hex) on s/390 and 0-512, 4096-4544, 4604-5119 currently on +z/Architecture are used by the processor itself for holding such information +as exception indications and entry points for exceptions. +Bytes after 0xc00 hex are used by linux for per processor globals on s/390 and +z/Architecture (there is a gap on z/Architecture currently between 0xc00 and +0x1000, too, which is used by Linux). The closest thing to this on traditional architectures is the interrupt vector table. This is a good thing & does simplify some of the kernel coding however it means that we now cannot catch stray NULL pointers in the @@ -192,26 +196,26 @@ Address Spaces on Intel Linux The traditional Intel Linux is approximately mapped as follows forgive the ascii art. -0xFFFFFFFF 4GB Himem ***************** - * * - * Kernel Space * - * * - ***************** **************** -User Space Himem (typically 0xC0000000 3GB )* User Stack * * * - ***************** * * - * Shared Libs * * Next Process * - ***************** * to * - * * <== * Run * <== - * User Program * * * - * Data BSS * * * - * Text * * * - * Sections * * * -0x00000000 ***************** **************** +0xFFFFFFFF 4GB Himem ***************** + * * + * Kernel Space * + * * + ***************** **************** +User Space Himem * User Stack * * * +(typically 0xC0000000 3GB ) ***************** * * + * Shared Libs * * Next Process * + ***************** * to * + * * <== * Run * <== + * User Program * * * + * Data BSS * * * + * Text * * * + * Sections * * * +0x00000000 ***************** **************** -Now it is easy to see that on Intel it is quite easy to recognise a kernel address -as being one greater than user space himem ( in this case 0xC0000000). -& addresses of less than this are the ones in the current running program on this -processor ( if an smp box ). +Now it is easy to see that on Intel it is quite easy to recognise a kernel +address as being one greater than user space himem (in this case 0xC0000000), +and addresses of less than this are the ones in the current running program on +this processor (if an smp box). If using the virtual machine ( VM ) as a debugger it is quite difficult to know which user process is running as the address space you are looking at could be from any process in the run queue. @@ -247,8 +251,8 @@ Our addressing scheme is basically as follows: Himem 0x7fffffff 2GB on s/390 ***************** **************** currently 0x3ffffffffff (2^42)-1 * User Stack * * * on z/Architecture. ***************** * * - * Shared Libs * * * - ***************** * * + * Shared Libs * * * + ***************** * * * * * Kernel * * User Program * * * * Data BSS * * * @@ -301,10 +305,10 @@ Virtual Addresses on s/390 & z/Architecture =========================================== A virtual address on s/390 is made up of 3 parts -The SX ( segment index, roughly corresponding to the PGD & PMD in linux terminology ) -being bits 1-11. -The PX ( page index, corresponding to the page table entry (pte) in linux terminology ) -being bits 12-19. +The SX (segment index, roughly corresponding to the PGD & PMD in Linux +terminology) being bits 1-11. +The PX (page index, corresponding to the page table entry (pte) in Linux +terminology) being bits 12-19. The remaining bits BX (the byte index are the offset in the page ) i.e. bits 20 to 31. @@ -368,9 +372,9 @@ each processor as follows. * ( 8K ) * 16K aligned ************************ -What this means is that we don't need to dedicate any register or global variable -to point to the current running process & can retrieve it with the following -very simple construct for s/390 & one very similar for z/Architecture. +What this means is that we don't need to dedicate any register or global +variable to point to the current running process & can retrieve it with the +following very simple construct for s/390 & one very similar for z/Architecture. static inline struct task_struct * get_current(void) { @@ -403,8 +407,8 @@ Note: To follow stackframes requires a knowledge of C or Pascal & limited knowledge of one assembly language. It should be noted that there are some differences between the -s/390 & z/Architecture stack layouts as the z/Architecture stack layout didn't have -to maintain compatibility with older linkage formats. +s/390 and z/Architecture stack layouts as the z/Architecture stack layout +didn't have to maintain compatibility with older linkage formats. Glossary: --------- @@ -440,7 +444,7 @@ The code generated by the compiler to return to the caller. frameless-function A frameless function in Linux for s390 & z/Architecture is one which doesn't -need more than the register save area ( 96 bytes on s/390, 160 on z/Architecture ) +need more than the register save area (96 bytes on s/390, 160 on z/Architecture) given to it by the caller. A frameless function never: 1) Sets up a back chain. @@ -588,8 +592,8 @@ A sample program with comments. Comments on the function test ----------------------------- -1) It didn't need to set up a pointer to the constant pool gpr13 as it isn't used -( :-( ). +1) It didn't need to set up a pointer to the constant pool gpr13 as it is not +used ( :-( ). 2) This is a frameless function & no stack is bought. 3) The compiler was clever enough to recognise that it could return the value in r2 as well as use it for the passed in parameter ( :-) ). @@ -743,35 +747,34 @@ Debugging under VM Notes ----- Addresses & values in the VM debugger are always hex never decimal -Address ranges are of the format - or . -e.g. The address range 0x2000 to 0x3000 can be described as 2000-3000 or 2000.1000 +Address ranges are of the format - or +. +For example, the address range 0x2000 to 0x3000 can be described as 2000-3000 +or 2000.1000 The VM Debugger is case insensitive. -VM's strengths are usually other debuggers weaknesses you can get at any resource -no matter how sensitive e.g. memory management resources,change address translation -in the PSW. For kernel hacking you will reap dividends if you get good at it. +VM's strengths are usually other debuggers weaknesses you can get at any +resource no matter how sensitive e.g. memory management resources, change +address translation in the PSW. For kernel hacking you will reap dividends if +you get good at it. -The VM Debugger displays operators but not operands, probably because some -of it was written when memory was expensive & the programmer was probably proud that -it fitted into 2k of memory & the programmers & didn't want to shock hardcore VM'ers by -changing the interface :-), also the debugger displays useful information on the same line & -the author of the code probably felt that it was a good idea not to go over -the 80 columns on the screen. - -As some of you are probably in a panic now this isn't as unintuitive as it may seem -as the 390 instructions are easy to decode mentally & you can make a good guess at a lot -of them as all the operands are nibble ( half byte aligned ) & if you have an objdump listing -also it is quite easy to follow, if you don't have an objdump listing keep a copy of -the s/390 Reference Summary & look at between pages 2 & 7 or alternatively the -s/390 principles of operation. +The VM Debugger displays operators but not operands, and also the debugger +displays useful information on the same line as the author of the code probably +felt that it was a good idea not to go over the 80 columns on the screen. +This isn't as unintuitive as it may seem as the s/390 instructions are easy to +decode mentally and you can make a good guess at a lot of them as all the +operands are nibble (half byte aligned). +So if you have an objdump listing by hand, it is quite easy to follow, and if +you don't have an objdump listing keep a copy of the s/390 Reference Summary +or alternatively the s/390 principles of operation next to you. e.g. even I can guess that 0001AFF8' LR 180F CC 0 is a ( load register ) lr r0,r15 -Also it is very easy to tell the length of a 390 instruction from the 2 most significant -bits in the instruction ( not that this info is really useful except if you are trying to -make sense of a hexdump of code ). +Also it is very easy to tell the length of a 390 instruction from the 2 most +significant bits in the instruction (not that this info is really useful except +if you are trying to make sense of a hexdump of code). Here is a table Bits Instruction Length ------------------------------------------ @@ -780,9 +783,6 @@ Bits Instruction Length 10 4 Bytes 11 6 Bytes - - - The debugger also displays other useful info on the same line such as the addresses being operated on destination addresses of branches & condition codes. e.g. @@ -853,8 +853,8 @@ Displaying & modifying Registers -------------------------------- D G will display all the gprs Adding a extra G to all the commands is necessary to access the full 64 bit -content in VM on z/Architecture obviously this isn't required for access registers -as these are still 32 bit. +content in VM on z/Architecture. Obviously this isn't required for access +registers as these are still 32 bit. e.g. DGG instead of DG D X will display all the control registers D AR will display all the access registers @@ -870,10 +870,11 @@ Displaying Memory ----------------- To display memory mapped using the current PSW's mapping try D -To make VM display a message each time it hits a particular address & continue try +To make VM display a message each time it hits a particular address and +continue try D I will disassemble/display a range of instructions. ST addr 32 bit word will store a 32 bit aligned address -D T will display the EBCDIC in an address ( if you are that way inclined ) +D T will display the EBCDIC in an address (if you are that way inclined) D R will display real addresses ( without DAT ) but with prefixing. There are other complex options to display if you need to get at say home space but are in primary space the easiest thing to do is to temporarily @@ -884,8 +885,8 @@ restore it. Hints ----- -If you want to issue a debugger command without halting your virtual machine with the -PA1 key try prefixing the command with #CP e.g. +If you want to issue a debugger command without halting your virtual machine +with the PA1 key try prefixing the command with #CP e.g. #cp tr i pswa 2000 also suffixing most debugger commands with RUN will cause them not to stop just display the mnemonic at the current instruction on the console. @@ -903,9 +904,10 @@ This sends a message to your own console each time do_signal is entered. script with breakpoints on every kernel procedure, this isn't a good idea because there are thousands of these routines & VM can only set 255 breakpoints at a time so you nearly had to spend as long pruning the file down as you would -entering the msg's by hand ),however, the trick might be useful for a single object file. -On linux'es 3270 emulator x3270 there is a very useful option under the file ment -Save Screens In File this is very good of keeping a copy of traces. +entering the msgs by hand), however, the trick might be useful for a single +object file. In the 3270 terminal emulator x3270 there is a very useful option +in the file menu called "Save Screen In File" - this is very good for keeping a +copy of traces. From CMS help will give you online help on a particular command. e.g. @@ -920,7 +922,8 @@ SET PF9 IMM B This does a single step in VM on pressing F8. SET PF10 ^ This sets up the ^ key. -which can be used for ^c (ctrl-c),^z (ctrl-z) which can't be typed directly into some 3270 consoles. +which can be used for ^c (ctrl-c),^z (ctrl-z) which can't be typed directly +into some 3270 consoles. SET PF11 ^- This types the starting keystrokes for a sysrq see SysRq below. SET PF12 RETRIEVE @@ -1014,8 +1017,8 @@ Tracing Program Exceptions -------------------------- If you get a crash which says something like illegal operation or specification exception followed by a register dump -You can restart linux & trace these using the tr prog trace option. - +You can restart linux & trace these using the tr prog trace +option. The most common ones you will normally be tracing for is @@ -1057,9 +1060,10 @@ TR GOTO INITIAL Tracing linux syscalls under VM ------------------------------- -Syscalls are implemented on Linux for S390 by the Supervisor call instruction (SVC) there 256 -possibilities of these as the instruction is made up of a 0xA opcode & the second byte being -the syscall number. They are traced using the simple command. +Syscalls are implemented on Linux for S390 by the Supervisor call instruction +(SVC). There 256 possibilities of these as the instruction is made up of a 0xA +opcode and the second byte being the syscall number. They are traced using the +simple command: TR SVC the syscalls are defined in linux/arch/s390/include/asm/unistd.h e.g. to trace all file opens just do @@ -1070,12 +1074,12 @@ SMP Specific commands --------------------- To find out how many cpus you have Q CPUS displays all the CPU's available to your virtual machine -To find the cpu that the current cpu VM debugger commands are being directed at do -Q CPU to change the current cpu VM debugger commands are being directed at do +To find the cpu that the current cpu VM debugger commands are being directed at +do Q CPU to change the current cpu VM debugger commands are being directed at do CPU -On a SMP guest issue a command to all CPUs try prefixing the command with cpu all. -To issue a command to a particular cpu try cpu e.g. +On a SMP guest issue a command to all CPUs try prefixing the command with cpu +all. To issue a command to a particular cpu try cpu e.g. CPU 01 TR I R 2000.3000 If you are running on a guest with several cpus & you have a IO related problem & cannot follow the flow of code but you know it isn't smp related. @@ -1101,10 +1105,10 @@ D TX0.100 Alternatively ============= -Under older VM debuggers ( I love EBDIC too ) you can use this little program I wrote which -will convert a command line of hex digits to ascii text which can be compiled under linux & -you can copy the hex digits from your x3270 terminal to your xterm if you are debugging -from a linuxbox. +Under older VM debuggers (I love EBDIC too) you can use following little +program which converts a command line of hex digits to ascii text. It can be +compiled under linux and you can copy the hex digits from your x3270 terminal +to your xterm if you are debugging from a linuxbox. This is quite useful when looking at a parameter passed in as a text string under VM ( unless you are good at decoding ASCII in your head ). @@ -1114,14 +1118,14 @@ TR SVC 5 We have stopped at a breakpoint 000151B0' SVC 0A05 -> 0001909A' CC 0 -D 20.8 to check the SVC old psw in the prefix area & see was it from userspace -( for the layout of the prefix area consult P18 of the s/390 390 Reference Summary -if you have it available ). +D 20.8 to check the SVC old psw in the prefix area and see was it from userspace +(for the layout of the prefix area consult the "Fixed Storage Locations" +chapter of the s/390 Reference Summary if you have it available). V00000020 070C2000 800151B2 The problem state bit wasn't set & it's also too early in the boot sequence for it to be a userspace SVC if it was we would have to temporarily switch the -psw to user space addressing so we could get at the first parameter of the open in -gpr2. +psw to user space addressing so we could get at the first parameter of the open +in gpr2. Next do a D G2 GPR 2 = 00014CB4 @@ -1208,9 +1212,9 @@ Here are the tricks I use 9 out of 10 times it works pretty well, When your backchain reaches a dead end -------------------------------------- -This can happen when an exception happens in the kernel & the kernel is entered twice -if you reach the NULL pointer at the end of the back chain you should be -able to sniff further back if you follow the following tricks. +This can happen when an exception happens in the kernel and the kernel is +entered twice. If you reach the NULL pointer at the end of the back chain you +should be able to sniff further back if you follow the following tricks. 1) A kernel address should be easy to recognise since it is in primary space & the problem state bit isn't set & also The Hi bit of the address is set. @@ -1260,8 +1264,8 @@ V000FFFD0 00010400 80010802 8001085A 000FFFA0 our 3rd return address is 8001085A -as the 04B52002 looks suspiciously like rubbish it is fair to assume that the kernel entry routines -for the sake of optimisation don't set up a backchain. +as the 04B52002 looks suspiciously like rubbish it is fair to assume that the +kernel entry routines for the sake of optimisation don't set up a backchain. now look at System.map to see if the addresses make any sense. @@ -1289,67 +1293,75 @@ Congrats you've done your first backchain. s/390 & z/Architecture IO Overview ================================== -I am not going to give a course in 390 IO architecture as this would take me quite a -while & I'm no expert. Instead I'll give a 390 IO architecture summary for Dummies if you have -the s/390 principles of operation available read this instead. If nothing else you may find a few -useful keywords in here & be able to use them on a web search engine like altavista to find -more useful information. +I am not going to give a course in 390 IO architecture as this would take me +quite a while and I'm no expert. Instead I'll give a 390 IO architecture +summary for Dummies. If you have the s/390 principles of operation available +read this instead. If nothing else you may find a few useful keywords in here +and be able to use them on a web search engine to find more useful information. Unlike other bus architectures modern 390 systems do their IO using mostly -fibre optics & devices such as tapes & disks can be shared between several mainframes, -also S390 can support up to 65536 devices while a high end PC based system might be choking -with around 64. Here is some of the common IO terminology +fibre optics and devices such as tapes and disks can be shared between several +mainframes. Also S390 can support up to 65536 devices while a high end PC based +system might be choking with around 64. + +Here is some of the common IO terminology: Subchannel: -This is the logical number most IO commands use to talk to an IO device there can be up to -0x10000 (65536) of these in a configuration typically there is a few hundred. Under VM -for simplicity they are allocated contiguously, however on the native hardware they are not -they typically stay consistent between boots provided no new hardware is inserted or removed. -Under Linux for 390 we use these as IRQ's & also when issuing an IO command (CLEAR SUBCHANNEL, -HALT SUBCHANNEL,MODIFY SUBCHANNEL,RESUME SUBCHANNEL,START SUBCHANNEL,STORE SUBCHANNEL & -TEST SUBCHANNEL ) we use this as the ID of the device we wish to talk to, the most -important of these instructions are START SUBCHANNEL ( to start IO ), TEST SUBCHANNEL ( to check -whether the IO completed successfully ), & HALT SUBCHANNEL ( to kill IO ), a subchannel -can have up to 8 channel paths to a device this offers redundancy if one is not available. - +This is the logical number most IO commands use to talk to an IO device. There +can be up to 0x10000 (65536) of these in a configuration, typically there are a +few hundred. Under VM for simplicity they are allocated contiguously, however +on the native hardware they are not. They typically stay consistent between +boots provided no new hardware is inserted or removed. +Under Linux for s390 we use these as IRQ's and also when issuing an IO command +(CLEAR SUBCHANNEL, HALT SUBCHANNEL, MODIFY SUBCHANNEL, RESUME SUBCHANNEL, +START SUBCHANNEL, STORE SUBCHANNEL and TEST SUBCHANNEL). We use this as the ID +of the device we wish to talk to. The most important of these instructions are +START SUBCHANNEL (to start IO), TEST SUBCHANNEL (to check whether the IO +completed successfully) and HALT SUBCHANNEL (to kill IO). A subchannel can have +up to 8 channel paths to a device, this offers redundancy if one is not +available. Device Number: -This number remains static & Is closely tied to the hardware, there are 65536 of these -also they are made up of a CHPID ( Channel Path ID, the most significant 8 bits ) -& another lsb 8 bits. These remain static even if more devices are inserted or removed -from the hardware, there is a 1 to 1 mapping between Subchannels & Device Numbers provided -devices aren't inserted or removed. +This number remains static and is closely tied to the hardware. There are 65536 +of these, made up of a CHPID (Channel Path ID, the most significant 8 bits) and +another lsb 8 bits. These remain static even if more devices are inserted or +removed from the hardware. There is a 1 to 1 mapping between subchannels and +device numbers, provided devices aren't inserted or removed. Channel Control Words: -CCWS are linked lists of instructions initially pointed to by an operation request block (ORB), -which is initially given to Start Subchannel (SSCH) command along with the subchannel number -for the IO subsystem to process while the CPU continues executing normal code. -These come in two flavours, Format 0 ( 24 bit for backward ) -compatibility & Format 1 ( 31 bit ). These are typically used to issue read & write -( & many other instructions ) they consist of a length field & an absolute address field. -For each IO typically get 1 or 2 interrupts one for channel end ( primary status ) when the -channel is idle & the second for device end ( secondary status ) sometimes you get both -concurrently, you check how the IO went on by issuing a TEST SUBCHANNEL at each interrupt, -from which you receive an Interruption response block (IRB). If you get channel & device end -status in the IRB without channel checks etc. your IO probably went okay. If you didn't you -probably need a doctor to examine the IRB & extended status word etc. +CCWs are linked lists of instructions initially pointed to by an operation +request block (ORB), which is initially given to Start Subchannel (SSCH) +command along with the subchannel number for the IO subsystem to process +while the CPU continues executing normal code. +CCWs come in two flavours, Format 0 (24 bit for backward compatibility) and +Format 1 (31 bit). These are typically used to issue read and write (and many +other) instructions. They consist of a length field and an absolute address +field. +Each IO typically gets 1 or 2 interrupts, one for channel end (primary status) +when the channel is idle, and the second for device end (secondary status). +Sometimes you get both concurrently. You check how the IO went on by issuing a +TEST SUBCHANNEL at each interrupt, from which you receive an Interruption +response block (IRB). If you get channel and device end status in the IRB +without channel checks etc. your IO probably went okay. If you didn't you +probably need to examine the IRB, extended status word etc. If an error occurs, more sophisticated control units have a facility known as -concurrent sense this means that if an error occurs Extended sense information will -be presented in the Extended status word in the IRB if not you have to issue a -subsequent SENSE CCW command after the test subchannel. +concurrent sense. This means that if an error occurs Extended sense information +will be presented in the Extended status word in the IRB. If not you have to +issue a subsequent SENSE CCW command after the test subchannel. -TPI( Test pending interrupt) can also be used for polled IO but in multitasking multiprocessor -systems it isn't recommended except for checking special cases ( i.e. non looping checks for -pending IO etc. ). +TPI (Test pending interrupt) can also be used for polled IO, but in +multitasking multiprocessor systems it isn't recommended except for +checking special cases (i.e. non looping checks for pending IO etc.). -Store Subchannel & Modify Subchannel can be used to examine & modify operating characteristics -of a subchannel ( e.g. channel paths ). +Store Subchannel and Modify Subchannel can be used to examine and modify +operating characteristics of a subchannel (e.g. channel paths). Other IO related Terms: Sysplex: S390's Clustering Technology -QDIO: S390's new high speed IO architecture to support devices such as gigabit ethernet, -this architecture is also designed to be forward compatible with up & coming 64 bit machines. +QDIO: S390's new high speed IO architecture to support devices such as gigabit +ethernet, this architecture is also designed to be forward compatible with +upcoming 64 bit machines. General Concepts @@ -1406,37 +1418,40 @@ sometimes called Bus-and Tag & sometimes Original Equipment Manufacturers Interface (OEMI). This byte wide Parallel channel path/bus has parity & data on the "Bus" cable -& control lines on the "Tag" cable. These can operate in byte multiplex mode for -sharing between several slow devices or burst mode & monopolize the channel for the -whole burst. Up to 256 devices can be addressed on one of these cables. These cables are -about one inch in diameter. The maximum unextended length supported by these cables is -125 Meters but this can be extended up to 2km with a fibre optic channel extended -such as a 3044. The maximum burst speed supported is 4.5 megabytes per second however -some really old processors support only transfer rates of 3.0, 2.0 & 1.0 MB/sec. +and control lines on the "Tag" cable. These can operate in byte multiplex mode +for sharing between several slow devices or burst mode and monopolize the +channel for the whole burst. Up to 256 devices can be addressed on one of these +cables. These cables are about one inch in diameter. The maximum unextended +length supported by these cables is 125 Meters but this can be extended up to +2km with a fibre optic channel extended such as a 3044. The maximum burst speed +supported is 4.5 megabytes per second. However, some really old processors +support only transfer rates of 3.0, 2.0 & 1.0 MB/sec. One of these paths can be daisy chained to up to 8 control units. ESCON if fibre optic it is also called FICON -Was introduced by IBM in 1990. Has 2 fibre optic cables & uses either leds or lasers -for communication at a signaling rate of up to 200 megabits/sec. As 10bits are transferred -for every 8 bits info this drops to 160 megabits/sec & to 18.6 Megabytes/sec once -control info & CRC are added. ESCON only operates in burst mode. +Was introduced by IBM in 1990. Has 2 fibre optic cables and uses either leds or +lasers for communication at a signaling rate of up to 200 megabits/sec. As +10bits are transferred for every 8 bits info this drops to 160 megabits/sec +and to 18.6 Megabytes/sec once control info and CRC are added. ESCON only +operates in burst mode. -ESCONs typical max cable length is 3km for the led version & 20km for the laser version -known as XDF ( extended distance facility ). This can be further extended by using an -ESCON director which triples the above mentioned ranges. Unlike Bus & Tag as ESCON is -serial it uses a packet switching architecture the standard Bus & Tag control protocol -is however present within the packets. Up to 256 devices can be attached to each control -unit that uses one of these interfaces. +ESCONs typical max cable length is 3km for the led version and 20km for the +laser version known as XDF (extended distance facility). This can be further +extended by using an ESCON director which triples the above mentioned ranges. +Unlike Bus & Tag as ESCON is serial it uses a packet switching architecture, +the standard Bus & Tag control protocol is however present within the packets. +Up to 256 devices can be attached to each control unit that uses one of these +interfaces. Common 390 Devices include: Network adapters typically OSA2,3172's,2116's & OSA-E gigabit ethernet adapters, -Consoles 3270 & 3215 ( a teletype emulated under linux for a line mode console ). +Consoles 3270 & 3215 (a teletype emulated under linux for a line mode console). DASD's direct access storage devices ( otherwise known as hard disks ). Tape Drives. CTC ( Channel to Channel Adapters ), ESCON or Parallel Cables used as a very high speed serial link -between 2 machines. We use 2 cables under linux to do a bi-directional serial link. +between 2 machines. Debugging IO on s/390 & z/Architecture under VM @@ -1475,9 +1490,9 @@ or the halt subchannels or TR HSCH 7C08-7C09 MSCH's ,STSCH's I think you can guess the rest -Ingo's favourite trick is tracing all the IO's & CCWS & spooling them into the reader of another -VM guest so he can ftp the logfile back to his own machine.I'll do a small bit of this & give you - a look at the output. +A good trick is tracing all the IO's and CCWS and spooling them into the reader +of another VM guest so he can ftp the logfile back to his own machine. I'll do +a small bit of this and give you a look at the output. 1) Spool stdout to VM reader SP PRT TO (another vm guest ) or * for the local vm guest @@ -1593,8 +1608,8 @@ undisplay : undo's display's info breakpoints: shows all current breakpoints -info stack: shows stack back trace ( if this doesn't work too well, I'll show you the -stacktrace by hand below ). +info stack: shows stack back trace (if this doesn't work too well, I'll show +you the stacktrace by hand below). info locals: displays local variables. @@ -1619,7 +1634,8 @@ next: like step except this will not step into subroutines stepi: steps a single machine code instruction. e.g. stepi 100 -nexti: steps a single machine code instruction but will not step into subroutines. +nexti: steps a single machine code instruction but will not step into +subroutines. finish: will run until exit of the current routine @@ -1721,7 +1737,8 @@ e.g. outputs: $1 = 11 -You might now be thinking that the line above didn't work, something extra had to be done. +You might now be thinking that the line above didn't work, something extra had +to be done. (gdb) call fflush(stdout) hello world$2 = 0 As an aside the debugger also calls malloc & free under the hood @@ -1804,26 +1821,17 @@ man gdb or info gdb. core dumps ---------- What a core dump ?, -A core dump is a file generated by the kernel ( if allowed ) which contains the registers, -& all active pages of the program which has crashed. -From this file gdb will allow you to look at the registers & stack trace & memory of the -program as if it just crashed on your system, it is usually called core & created in the -current working directory. -This is very useful in that a customer can mail a core dump to a technical support department -& the technical support department can reconstruct what happened. -Provided they have an identical copy of this program with debugging symbols compiled in & -the source base of this build is available. -In short it is far more useful than something like a crash log could ever hope to be. - -In theory all that is missing to restart a core dumped program is a kernel patch which -will do the following. -1) Make a new kernel task structure -2) Reload all the dumped pages back into the kernel's memory management structures. -3) Do the required clock fixups -4) Get all files & network connections for the process back into an identical state ( really difficult ). -5) A few more difficult things I haven't thought of. - - +A core dump is a file generated by the kernel (if allowed) which contains the +registers and all active pages of the program which has crashed. +From this file gdb will allow you to look at the registers, stack trace and +memory of the program as if it just crashed on your system. It is usually +called core and created in the current working directory. +This is very useful in that a customer can mail a core dump to a technical +support department and the technical support department can reconstruct what +happened. Provided they have an identical copy of this program with debugging +symbols compiled in and the source base of this build is available. +In short it is far more useful than something like a crash log could ever hope +to be. Why have I never seen one ?. Probably because you haven't used the command @@ -1868,7 +1876,7 @@ Breakpoint 2 at 0x4d87a4: file top.c, line 2609. #3 0x5167e6 in readline_internal_char () at readline.c:454 #4 0x5168ee in readline_internal_charloop () at readline.c:507 #5 0x51692c in readline_internal () at readline.c:521 -#6 0x5164fe in readline (prompt=0x7ffff810 "\177ÿøx\177ÿ÷Ø\177ÿøxÀ") +#6 0x5164fe in readline (prompt=0x7ffff810) at readline.c:349 #7 0x4d7a8a in command_line_input (prompt=0x564420 "(gdb) ", repeat=1, annotation_suffix=0x4d6b44 "prompt") at top.c:2091 @@ -1929,8 +1937,8 @@ cat /proc/sys/net/ipv4/ip_forward On my machine now outputs 1 IP forwarding is on. -There is a lot of useful info in here best found by going in & having a look around, -so I'll take you through some entries I consider important. +There is a lot of useful info in here best found by going in and having a look +around, so I'll take you through some entries I consider important. All the processes running on the machine have their own entry defined by /proc/ @@ -2060,7 +2068,8 @@ if the device doesn't say up try /etc/rc.d/init.d/network start ( this starts the network stack & hopefully calls ifconfig tr0 up ). -ifconfig looks at the output of /proc/net/dev & presents it in a more presentable form +ifconfig looks at the output of /proc/net/dev and presents it in a more +presentable form. Now ping the device from a machine in the same subnet. if the RX packets count & TX packets counts don't increment you probably have problems. @@ -2086,34 +2095,6 @@ of the device. See the manpage chandev.8 &type cat /proc/chandev for more info. - -Starting points for debugging scripting languages etc. -====================================================== - -bash/sh - -bash -x -e.g. bash -x /usr/bin/bashbug -displays the following lines as it executes them. -+ MACHINE=i586 -+ OS=linux-gnu -+ CC=gcc -+ CFLAGS= -DPROGRAM='bash' -DHOSTTYPE='i586' -DOSTYPE='linux-gnu' -DMACHTYPE='i586-pc-linux-gnu' -DSHELL -DHAVE_CONFIG_H -I. -I. -I./lib -O2 -pipe -+ RELEASE=2.01 -+ PATCHLEVEL=1 -+ RELSTATUS=release -+ MACHTYPE=i586-pc-linux-gnu - -perl -d runs the perlscript in a fully interactive debugger -. -Type 'h' in the debugger for help. - -for debugging java type -jdb another fully interactive gdb style debugger. -& type ? in the debugger for help. - - - SysRq ===== This is now supported by linux for s/390 & z/Architecture. diff --git a/Documentation/scheduler/completion.txt b/Documentation/scheduler/completion.txt new file mode 100644 index 000000000000..f77651eca31e --- /dev/null +++ b/Documentation/scheduler/completion.txt @@ -0,0 +1,236 @@ +completions - wait for completion handling +========================================== + +This document was originally written based on 3.18.0 (linux-next) + +Introduction: +------------- + +If you have one or more threads of execution that must wait for some process +to have reached a point or a specific state, completions can provide a race +free solution to this problem. Semantically they are somewhat like a +pthread_barriers and have similar use-cases. + +Completions are a code synchronization mechanism that is preferable to any +misuse of locks. Any time you think of using yield() or some quirky +msleep(1); loop to allow something else to proceed, you probably want to +look into using one of the wait_for_completion*() calls instead. The +advantage of using completions is clear intent of the code but also more +efficient code as both threads can continue until the result is actually +needed. + +Completions are built on top of the generic event infrastructure in Linux, +with the event reduced to a simple flag appropriately called "done" in +struct completion, that tells the waiting threads of execution if they +can continue safely. + +As completions are scheduling related the code is found in +kernel/sched/completion.c - for details on completion design and +implementation see completions-design.txt + + +Usage: +------ + +There are three parts to the using completions, the initialization of the +struct completion, the waiting part through a call to one of the variants of +wait_for_completion() and the signaling side through a call to complete(), +or complete_all(). Further there are some helper functions for checking the +state of completions. + +To use completions one needs to include and +create a variable of type struct completion. The structure used for +handling of completions is: + + struct completion { + unsigned int done; + wait_queue_head_t wait; + }; + +providing the wait queue to place tasks on for waiting and the flag for +indicating the state of affairs. + +Completions should be named to convey the intent of the waiter. A good +example is: + + wait_for_completion(&early_console_added); + + complete(&early_console_added); + +Good naming (as always) helps code readability. + + +Initializing completions: +------------------------- + +Initialization of dynamically allocated completions, often embedded in +other structures, is done with: + + void init_completion(&done); + +Initialization is accomplished by initializing the wait queue and setting +the default state to "not available", that is, "done" is set to 0. + +The re-initialization function, reinit_completion(), simply resets the +done element to "not available", thus again to 0, without touching the +wait queue. Calling init_completion() on the same completions object is +most likely a bug as it re-initializes the queue to an empty queue and +enqueued tasks could get "lost" - use reinit_completion() in that case. + +For static declaration and initialization, macros are available. These are: + + static DECLARE_COMPLETION(setup_done) + +used for static declarations in file scope. Within functions the static +initialization should always use: + + DECLARE_COMPLETION_ONSTACK(setup_done) + +suitable for automatic/local variables on the stack and will make lockdep +happy. Note also that one needs to making *sure* the completion passt to +work threads remains in-scope, and no references remain to on-stack data +when the initiating function returns. + + +Waiting for completions: +------------------------ + +For a thread of execution to wait for some concurrent work to finish, it +calls wait_for_completion() on the initialized completion structure. +A typical usage scenario is: + + structure completion setup_done; + init_completion(&setup_done); + initialze_work(...,&setup_done,...) + + /* run non-dependent code */ /* do setup */ + + wait_for_completion(&seupt_done); complete(setup_done) + +This is not implying any temporal order of wait_for_completion() and the +call to complete() - if the call to complete() happened before the call +to wait_for_completion() then the waiting side simply will continue +immediately as all dependencies are satisfied. + +Note that wait_for_completion() is calling spin_lock_irq/spin_unlock_irq +so it can only be called safely when you know that interrupts are enabled. +Calling it from hard-irq context will result in hard to detect spurious +enabling of interrupts. + +wait_for_completion(): + + void wait_for_completion(struct completion *done): + +The default behavior is to wait without a timeout and mark the task as +uninterruptible. wait_for_completion() and its variants are only safe +in soft-interrupt or process context but not in hard-irq context. +As all variants of wait_for_completion() can (obviously) block for a long +time, you probably don't want to call this with held locks - see also +try_wait_for_completion() below. + + +Variants available: +------------------- + +The below variants all return status and this status should be checked in +most(/all) cases - in cases where the status is deliberately not checked you +probably want to make a note explaining this (e.g. see +arch/arm/kernel/smp.c:__cpu_up()). + +A common problem that occurs is to have unclean assignment of return types, +so care should be taken with assigning return-values to variables of proper +type. Checking for the specific meaning of return values also has been found +to be quite inaccurate e.g. constructs like +if(!wait_for_completion_interruptible_timeout(...)) would execute the same +code path for successful completion and for the interrupted case - which is +probably not what you want. + + int wait_for_completion_interruptible(struct completion *done) + +marking the task TASK_INTERRUPTIBLE. If a signal was received while waiting. +It will return -ERESTARTSYS and 0 otherwise. + + unsigned long wait_for_completion_timeout(struct completion *done, + unsigned long timeout) + +The task is marked as TASK_UNINTERRUPTIBLE and will wait at most timeout +(in jiffies). If timeout occurs it return 0 else the remaining time in +jiffies (but at least 1). Timeouts are preferably passed by msecs_to_jiffies() +or usecs_to_jiffies(). If the returned timeout value is deliberately ignored +a comment should probably explain why (e.g. see drivers/mfd/wm8350-core.c +wm8350_read_auxadc()) + + long wait_for_completion_interruptible_timeout( + struct completion *done, unsigned long timeout) + +passing a timeout in jiffies and marking the task as TASK_INTERRUPTIBLE. If a +signal was received it will return -ERESTARTSYS, 0 if completion timed-out and +the remaining time in jiffies if completion occurred. + +Further variants include _killable which passes TASK_KILLABLE as the +designated tasks state and will return a -ERESTARTSYS if interrupted or +else 0 if completions was achieved as well as a _timeout variant. + + long wait_for_completion_killable(struct completion *done) + long wait_for_completion_killable_timeout(struct completion *done, + unsigned long timeout) + +The _io variants wait_for_completion_io behave the same as the non-_io +variants, except for accounting waiting time as waiting on IO, which has +an impact on how scheduling is calculated. + + void wait_for_completion_io(struct completion *done) + unsigned long wait_for_completion_io_timeout(struct completion *done + unsigned long timeout) + + +Signaling completions: +---------------------- + +A thread of execution that wants to signal that the conditions for +continuation have been achieved calls complete() to signal exactly one +of the waiters that it can continue. + + void complete(struct completion *done) + +or calls complete_all to signal all current and future waiters. + + void complete_all(struct completion *done) + +The signaling will work as expected even if completions are signaled before +a thread starts waiting. This is achieved by the waiter "consuming" +(decrementing) the done element of struct completion. Waiting threads +wakeup order is the same in which they were enqueued (FIFO order). + +If complete() is called multiple times then this will allow for that number +of waiters to continue - each call to complete() will simply increment the +done element. Calling complete_all() multiple times is a bug though. Both +complete() and complete_all() can be called in hard-irq context safely. + +There only can be one thread calling complete() or complete_all() on a +particular struct completions at any time - serialized through the wait +queue spinlock. Any such concurrent calls to complete() or complete_all() +probably are a design bug. + +Signaling completion from hard-irq context is fine as it will appropriately +lock with spin_lock_irqsave/spin_unlock_irqrestore. + + +try_wait_for_completion()/completion_done(): +-------------------------------------------- + +The try_wait_for_completion will not put the thread on the wait queue but +rather returns false if it would need to enqueue (block) the thread, else it +consumes any posted completions and returns true. + + bool try_wait_for_completion(struct completion *done) + +Finally to check state of a completions without changing it in any way is +provided by completion_done() returning false if there are any posted +completion that was not yet consumed by waiters implying that there are +waiters and true otherwise; + + bool completion_done(struct completion *done) + +Both try_wait_for_completion() and completion_done() are safe to be called in +hard-irq context. diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt index 821c936e1a63..c9e7f4f223a5 100644 --- a/Documentation/security/keys.txt +++ b/Documentation/security/keys.txt @@ -323,8 +323,6 @@ about the status of the key service: U Under construction by callback to userspace N Negative key - This file must be enabled at kernel configuration time as it allows anyone - to list the keys database. (*) /proc/key-users diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 75511efefc64..83ab25660fc9 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -843,6 +843,7 @@ can be ORed together: 8192 - An unsigned module has been loaded in a kernel supporting module signature. 16384 - A soft lockup has previously occurred on the system. +32768 - The kernel has been live patched. ============================================================== diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt index 666594b43cff..6294b5186ae5 100644 --- a/Documentation/sysctl/net.txt +++ b/Documentation/sysctl/net.txt @@ -97,6 +97,14 @@ rmem_max The maximum receive socket buffer size in bytes. +tstamp_allow_data +----------------- +Allow processes to receive tx timestamps looped together with the original +packet contents. If disabled, transmit timestamp requests from unprivileged +processes are dropped unless socket option SOF_TIMESTAMPING_OPT_TSONLY is set. +Default: 1 (on) + + wmem_default ------------ diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 4415aa915681..902b4574acfb 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -555,12 +555,12 @@ this is causing problems for your system/application. oom_dump_tasks -Enables a system-wide task dump (excluding kernel threads) to be -produced when the kernel performs an OOM-killing and includes such -information as pid, uid, tgid, vm size, rss, nr_ptes, swapents, -oom_score_adj score, and name. This is helpful to determine why the -OOM killer was invoked, to identify the rogue task that caused it, -and to determine why the OOM killer chose the task it did to kill. +Enables a system-wide task dump (excluding kernel threads) to be produced +when the kernel performs an OOM-killing and includes such information as +pid, uid, tgid, vm size, rss, nr_ptes, nr_pmds, swapents, oom_score_adj +score, and name. This is helpful to determine why the OOM killer was +invoked, to identify the rogue task that caused it, and to determine why +the OOM killer chose the task it did to kill. If this is set to zero, this information is suppressed. On very large systems with thousands of tasks it may not be feasible to dump @@ -728,7 +728,7 @@ The default value is 60. - user_reserve_kbytes -When overcommit_memory is set to 2, "never overommit" mode, reserve +When overcommit_memory is set to 2, "never overcommit" mode, reserve min(3% of current process size, user_reserve_kbytes) of free memory. This is intended to prevent a user from starting a single memory hogging process, such that they cannot recover (kill the hog). diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt index 8408e040f06f..572ca923631a 100644 --- a/Documentation/trace/ftrace.txt +++ b/Documentation/trace/ftrace.txt @@ -1740,7 +1740,7 @@ no pid yum-updatesd-3111 [003] 1637.254683: lock_hrtimer_base <-hrtimer_try_to_cancel yum-updatesd-3111 [003] 1637.254685: fget_light <-do_sys_poll yum-updatesd-3111 [003] 1637.254686: pipe_poll <-do_sys_poll -# echo -1 > set_ftrace_pid +# echo > set_ftrace_pid # cat trace |head # tracer: function # diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt index c42bb9cd3b43..7587d84ebd16 100644 --- a/Documentation/usb/usbmon.txt +++ b/Documentation/usb/usbmon.txt @@ -231,7 +231,7 @@ number. Number zero (/dev/usbmon0) is special and means "all buses". Note that specific naming policy is set by your Linux distribution. If you create /dev/usbmon0 by hand, make sure that it is owned by root -and has mode 0600. Otherwise, unpriviledged users will be able to snoop +and has mode 0600. Otherwise, unprivileged users will be able to snoop keyboard traffic. The following ioctl calls are available, with MON_IOC_MAGIC 0x92: diff --git a/Documentation/video4linux/CQcam.txt b/Documentation/video4linux/CQcam.txt deleted file mode 100644 index 0b69e4ee8e31..000000000000 --- a/Documentation/video4linux/CQcam.txt +++ /dev/null @@ -1,205 +0,0 @@ -c-qcam - Connectix Color QuickCam video4linux kernel driver - -Copyright (C) 1999 Dave Forrest - released under GNU GPL. - -1999-12-08 Dave Forrest, written with kernel version 2.2.12 in mind - - -Table of Contents - -1.0 Introduction -2.0 Compilation, Installation, and Configuration -3.0 Troubleshooting -4.0 Future Work / current work arounds -9.0 Sample Program, v4lgrab -10.0 Other Information - - -1.0 Introduction - - The file ../../drivers/media/parport/c-qcam.c is a device driver for -the Logitech (nee Connectix) parallel port interface color CCD camera. -This is a fairly inexpensive device for capturing images. Logitech -does not currently provide information for developers, but many people -have engineered several solutions for non-Microsoft use of the Color -Quickcam. - -1.1 Motivation - - I spent a number of hours trying to get my camera to work, and I -hope this document saves you some time. My camera will not work with -the 2.2.13 kernel as distributed, but with a few patches to the -module, I was able to grab some frames. See 4.0, Future Work. - - - -2.0 Compilation, Installation, and Configuration - - The c-qcam depends on parallel port support, video4linux, and the -Color Quickcam. It is also nice to have the parallel port readback -support enabled. I enabled these as modules during the kernel -configuration. The appropriate flags are: - - CONFIG_PRINTER M for lp.o, parport.o parport_pc.o modules - CONFIG_PNP_PARPORT M for autoprobe.o IEEE1284 readback module - CONFIG_PRINTER_READBACK M for parport_probe.o IEEE1284 readback module - CONFIG_VIDEO_DEV M for videodev.o video4linux module - CONFIG_VIDEO_CQCAM M for c-qcam.o Color Quickcam module - - With these flags, the kernel should compile and install the modules. -To record and monitor the compilation, I use: - - (make zlilo ; \ - make modules; \ - make modules_install ; - depmod -a ) &>log & - less log # then a capital 'F' to watch the progress - -But that is my personal preference. - -2.2 Configuration - - The configuration requires module configuration and device -configuration. The following sections detail these procedures. - - -2.1 Module Configuration - - Using modules requires a bit of work to install and pass the -parameters. Understand that entries in /etc/modprobe.d/*.conf of: - - alias parport_lowlevel parport_pc - options parport_pc io=0x378 irq=none - alias char-major-81 videodev - alias char-major-81-0 c-qcam - -2.2 Device Configuration - - At this point, we need to ensure that the device files exist. -Video4linux used the /dev/video* files, and we want to attach the -Quickcam to one of these. - - ls -lad /dev/video* # should produce a list of the video devices - -If the video devices do not exist, you can create them with: - - su - cd /dev - for ii in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do - mknod video$ii c 81 $ii # char-major-81-[0-16] - chown root.root video$ii # owned by root - chmod 600 video$ii # read/writable by root only - done - - Lots of people connect video0 to video and bttv, but you might want -your c-qcam to mean something more: - - ln -s video0 c-qcam # make /dev/c-qcam a working file - ln -s c-qcam video # make /dev/c-qcam your default video source - - But these are conveniences. The important part is to make the proper -special character files with the right major and minor numbers. All -of the special device files are listed in ../devices.txt. If you -would like the c-qcam readable by non-root users, you will need to -change the permissions. - -3.0 Troubleshooting - - If the sample program below, v4lgrab, gives you output then -everything is working. - - v4lgrab | wc # should give you a count of characters - - Otherwise, you have some problem. - - The c-qcam is IEEE1284 compatible, so if you are using the proc file -system (CONFIG_PROC_FS), the parallel printer support -(CONFIG_PRINTER), the IEEE 1284 system,(CONFIG_PRINTER_READBACK), you -should be able to read some identification from your quickcam with - - modprobe -v parport - modprobe -v parport_probe - cat /proc/parport/PORTNUMBER/autoprobe -Returns: - CLASS:MEDIA; - MODEL:Color QuickCam 2.0; - MANUFACTURER:Connectix; - - A good response to this indicates that your color quickcam is alive -and well. A common problem is that the current driver does not -reliably detect a c-qcam, even though one is attached. In this case, - - modprobe -v c-qcam -or - insmod -v c-qcam - - Returns a message saying "Device or resource busy" Development is -currently underway, but a workaround is to patch the module to skip -the detection code and attach to a defined port. Check the -video4linux mailing list and archive for more current information. - -3.1 Checklist: - - Can you get an image? - v4lgrab >qcam.ppm ; wc qcam.ppm ; xv qcam.ppm - - Is a working c-qcam connected to the port? - grep ^ /proc/parport/?/autoprobe - - Do the /dev/video* files exist? - ls -lad /dev/video - - Is the c-qcam module loaded? - modprobe -v c-qcam ; lsmod - - Does the camera work with alternate programs? cqcam, etc? - - - - -4.0 Future Work / current workarounds - - It is hoped that this section will soon become obsolete, but if it -isn't, you might try patching the c-qcam module to add a parport=xxx -option as in the bw-qcam module so you can specify the parallel port: - - insmod -v c-qcam parport=0 - -And bypass the detection code, see ../../drivers/char/c-qcam.c and -look for the 'qc_detect' code and call. - - Note that there is work in progress to change the video4linux API, -this work is documented at the video4linux2 site listed below. - - -9.0 --- A sample program using v4lgrabber, - -v4lgrab is a simple image grabber that will copy a frame from the -first video device, /dev/video0 to standard output in portable pixmap -format (.ppm) To produce .jpg output, you can use it like this: -'v4lgrab | convert - c-qcam.jpg' - - -10.0 --- Other Information - -Use the ../../Maintainers file, particularly the VIDEO FOR LINUX and PARALLEL -PORT SUPPORT sections - -The video4linux page: - http://linuxtv.org - -The V4L2 API spec: - http://v4l2spec.bytesex.org/ - -Some web pages about the quickcams: - http://www.pingouin-land.com/howto/QuickCam-HOWTO.html - - http://www.crynwr.com/qcpc/ QuickCam Third-Party Drivers - http://www.crynwr.com/qcpc/re.html Some Reverse Engineering - http://www.wirelesscouch.net/software/gqcam/ v4l client - http://phobos.illtel.denver.co.us/pub/qcread/ doesn't use v4l - ftp://ftp.cs.unm.edu/pub/chris/quickcam/ Has lots of drivers - http://www.cs.duke.edu/~reynolds/quickcam/ Has lots of information - - diff --git a/Documentation/video4linux/README.tlg2300 b/Documentation/video4linux/README.tlg2300 deleted file mode 100644 index 416ccb93d8c9..000000000000 --- a/Documentation/video4linux/README.tlg2300 +++ /dev/null @@ -1,47 +0,0 @@ -tlg2300 release notes -==================== - -This is a v4l2/dvb device driver for the tlg2300 chip. - - -current status -============== - -video - - support mmap and read().(no overlay) - -audio - - The driver will register a ALSA card for the audio input. - -vbi - - Works for almost TV norms. - -dvb-t - - works for DVB-T - -FM - - Works for radio. - ---------------------------------------------------------------------------- -TESTED APPLICATIONS: - --VLC1.0.4 test the video and dvb. The GUI is friendly to use. - --Mplayer test the video. - --Mplayer test the FM. The mplayer should be compiled with --enable-radio and - --enable-radio-capture. - The command runs as this(The alsa audio registers to card 1): - #mplayer radio://103.7/capture/ -radio adevice=hw=1,0:arate=48000 \ - -rawaudio rate=48000:channels=2 - ---------------------------------------------------------------------------- -KNOWN PROBLEMS: -about preemphasis: - You can set the preemphasis for radio by the following command: - #v4l2-ctl -d /dev/radio0 --set-ctrl=pre_emphasis_settings=1 - - "pre_emphasis_settings=1" means that you select the 50us. If you want - to select the 75us, please use "pre_emphasis_settings=2" - - diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index a11dff07ef71..f586e29ce221 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt @@ -793,8 +793,10 @@ video_register_device_no_warn() instead. Whenever a device node is created some attributes are also created for you. If you look in /sys/class/video4linux you see the devices. Go into e.g. -video0 and you will see 'name' and 'index' attributes. The 'name' attribute -is the 'name' field of the video_device struct. +video0 and you will see 'name', 'debug' and 'index' attributes. The 'name' +attribute is the 'name' field of the video_device struct. The 'debug' attribute +can be used to enable core debugging. See the next section for more detailed +information on this. The 'index' attribute is the index of the device node: for each call to video_register_device() the index is just increased by 1. The first video @@ -816,6 +818,25 @@ video_device was embedded in it. The vdev->release() callback will never be called if the registration failed, nor should you ever attempt to unregister the device if the registration failed. +video device debugging +---------------------- + +The 'debug' attribute that is created for each video, vbi, radio or swradio +device in /sys/class/video4linux// allows you to enable logging of +file operations. + +It is a bitmask and the following bits can be set: + +0x01: Log the ioctl name and error code. VIDIOC_(D)QBUF ioctls are only logged + if bit 0x08 is also set. +0x02: Log the ioctl name arguments and error code. VIDIOC_(D)QBUF ioctls are + only logged if bit 0x08 is also set. +0x04: Log the file operations open, release, read, write, mmap and + get_unmapped_area. The read and write operations are only logged if + bit 0x08 is also set. +0x08: Log the read and write file operations and the VIDIOC_QBUF and + VIDIOC_DQBUF ioctls. +0x10: Log the poll file operation. video_device cleanup -------------------- diff --git a/Documentation/video4linux/w9966.txt b/Documentation/video4linux/w9966.txt deleted file mode 100644 index 855024525fd2..000000000000 --- a/Documentation/video4linux/w9966.txt +++ /dev/null @@ -1,33 +0,0 @@ -W9966 Camera driver, written by Jakob Kemi (jakob.kemi@telia.com) - -After a lot of work in softice & wdasm, reading .pdf-files and tiresome -trial-and-error work I've finally got everything to work. I needed vision for a -robotics project so I borrowed this camera from a friend and started hacking. -Anyway I've converted my original code from the AVR 8bit RISC C/ASM code into -a working Linux driver. - -To get it working simply configure your kernel to support -parport, ieee1284, video4linux and w9966 - -If w9966 is statically linked it will always perform aggressive probing for -the camera. If built as a module you'll have more configuration options. - -Options: - modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp) -voila! - -you can also type 'modinfo -p w9966.o' for option usage -(or checkout w9966.c) - -The only thing to keep in mind is that the image format is in Y-U-Y-V format -where every two pixels take 4 bytes. In SDL (www.libsdl.org) this format -is called VIDEO_PALETTE_YUV422 (16 bpp). - -A minimal test application (with source) is available from: - http://www.slackwaresupport.com/howtos/Webcam-HOWTO - -The slow framerate is due to missing DMA ECP read support in the -parport drivers. I might add working EPP support later. - -Good luck! - /Jakob Kemi diff --git a/Documentation/vm/cleancache.txt b/Documentation/vm/cleancache.txt index 142fbb0f325a..01d76282444e 100644 --- a/Documentation/vm/cleancache.txt +++ b/Documentation/vm/cleancache.txt @@ -85,7 +85,7 @@ lock the page to ensure serial behavior. CLEANCACHE PERFORMANCE METRICS If properly configured, monitoring of cleancache is done via debugfs in -the /sys/kernel/debug/mm/cleancache directory. The effectiveness of cleancache +the /sys/kernel/debug/cleancache directory. The effectiveness of cleancache can be measured (across all filesystems) with: succ_gets - number of gets that were successful diff --git a/Documentation/vm/pagemap.txt b/Documentation/vm/pagemap.txt index 5948e455c4d2..6fbd55ef6b45 100644 --- a/Documentation/vm/pagemap.txt +++ b/Documentation/vm/pagemap.txt @@ -62,6 +62,8 @@ There are three components to pagemap: 20. NOPAGE 21. KSM 22. THP + 23. BALLOON + 24. ZERO_PAGE Short descriptions to the page flags: @@ -102,6 +104,12 @@ Short descriptions to the page flags: 22. THP contiguous pages which construct transparent hugepages +23. BALLOON + balloon compaction page + +24. ZERO_PAGE + zero page for pfn_zero or huge_zero page + [IO related page flags] 1. ERROR IO error occurred 3. UPTODATE page has up-to-date data diff --git a/Documentation/vm/remap_file_pages.txt b/Documentation/vm/remap_file_pages.txt index 560e4363a55d..f609142f406a 100644 --- a/Documentation/vm/remap_file_pages.txt +++ b/Documentation/vm/remap_file_pages.txt @@ -18,10 +18,9 @@ on 32-bit systems to map files bigger than can linearly fit into 32-bit virtual address space. This use-case is not critical anymore since 64-bit systems are widely available. -The plan is to deprecate the syscall and replace it with an emulation. -The emulation will create new VMAs instead of nonlinear mappings. It's -going to work slower for rare users of remap_file_pages() but ABI is -preserved. +The syscall is deprecated and replaced it with an emulation now. The +emulation creates new VMAs instead of nonlinear mappings. It's going to +work slower for rare users of remap_file_pages() but ABI is preserved. One side effect of emulation (apart from performance) is that user can hit vm.max_map_count limit more easily due to additional VMAs. See comment for diff --git a/Documentation/x86/entry_64.txt b/Documentation/x86/entry_64.txt index 4a1c5c2dc5a9..9132b86176a3 100644 --- a/Documentation/x86/entry_64.txt +++ b/Documentation/x86/entry_64.txt @@ -78,9 +78,6 @@ The expensive (paranoid) way is to read back the MSR_GS_BASE value xorl %ebx,%ebx 1: ret -and the whole paranoid non-paranoid macro complexity is about whether -to suffer that RDMSR cost. - If we are at an interrupt or user-trap/gate-alike boundary then we can use the faster check: the stack will be a reliable indicator of whether SWAPGS was already done: if we see that we are a secondary @@ -93,6 +90,15 @@ which might have triggered right after a normal entry wrote CS to the stack but before we executed SWAPGS, then the only safe way to check for GS is the slower method: the RDMSR. -So we try only to mark those entry methods 'paranoid' that absolutely -need the more expensive check for the GS base - and we generate all -'normal' entry points with the regular (faster) entry macros. +Therefore, super-atomic entries (except NMI, which is handled separately) +must use idtentry with paranoid=1 to handle gsbase correctly. This +triggers three main behavior changes: + + - Interrupt entry will use the slower gsbase check. + - Interrupt entry from user mode will switch off the IST stack. + - Interrupt exit to kernel mode will not attempt to reschedule. + +We try to only use IST entries and the paranoid entry code for vectors +that absolutely need the more expensive check for the GS base - and we +generate all 'normal' entry points with the regular (faster) paranoid=0 +variant. diff --git a/Documentation/x86/x86_64/kernel-stacks b/Documentation/x86/x86_64/kernel-stacks index a01eec5d1d0b..e3c8a49d1a2f 100644 --- a/Documentation/x86/x86_64/kernel-stacks +++ b/Documentation/x86/x86_64/kernel-stacks @@ -40,9 +40,11 @@ An IST is selected by a non-zero value in the IST field of an interrupt-gate descriptor. When an interrupt occurs and the hardware loads such a descriptor, the hardware automatically sets the new stack pointer based on the IST value, then invokes the interrupt handler. If -software wants to allow nested IST interrupts then the handler must -adjust the IST values on entry to and exit from the interrupt handler. -(This is occasionally done, e.g. for debug exceptions.) +the interrupt came from user mode, then the interrupt handler prologue +will switch back to the per-thread stack. If software wants to allow +nested IST interrupts then the handler must adjust the IST values on +entry to and exit from the interrupt handler. (This is occasionally +done, e.g. for debug exceptions.) Events with different IST codes (i.e. with different stacks) can be nested. For example, a debug interrupt can safely be interrupted by an diff --git a/MAINTAINERS b/MAINTAINERS index b30d937c3ec8..22999654195a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -270,12 +270,12 @@ F: drivers/acpi/ F: drivers/pnp/pnpacpi/ F: include/linux/acpi.h F: include/acpi/ -F: Documentation/acpi +F: Documentation/acpi/ F: Documentation/ABI/testing/sysfs-bus-acpi F: drivers/pci/*acpi* F: drivers/pci/*/*acpi* F: drivers/pci/*/*/*acpi* -F: tools/power/acpi +F: tools/power/acpi/ ACPI COMPONENT ARCHITECTURE (ACPICA) M: Robert Moore @@ -563,6 +563,12 @@ S: Odd Fixes L: linux-alpha@vger.kernel.org F: arch/alpha/ +ALTERA MAILBOX DRIVER +M: Ley Foon Tan +L: nios2-dev@lists.rocketboards.org (moderated for non-subscribers) +S: Maintained +F: drivers/mailbox/mailbox-altera.c + ALTERA TRIPLE SPEED ETHERNET DRIVER M: Vince Bridgers L: netdev@vger.kernel.org @@ -659,6 +665,13 @@ L: linux-media@vger.kernel.org S: Maintained F: drivers/media/i2c/ad9389b* +ANALOG DEVICES INC ADV7180 DRIVER +M: Lars-Peter Clausen +L: linux-media@vger.kernel.org +W: http://ez.analog.com/community/linux-device-drivers +S: Supported +F: drivers/media/i2c/adv7180.c + ANALOG DEVICES INC ADV7511 DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org @@ -696,7 +709,7 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) W: http://blackfin.uclinux.org/ S: Supported F: sound/soc/blackfin/* - + ANALOG DEVICES INC IIO DRIVERS M: Lars-Peter Clausen M: Michael Hennerich @@ -708,6 +721,16 @@ X: drivers/iio/*/adjd* F: drivers/staging/iio/*/ad* F: staging/iio/trigger/iio-trig-bfin-timer.c +ANDROID DRIVERS +M: Greg Kroah-Hartman +M: Arve Hjnnevg +M: Riley Andrews +T: git git://git.kernel.org/pub/scm/linux/kernel/gregkh/staging.git +L: devel@driverdev.osuosl.org +S: Supported +F: drivers/android/ +F: drivers/staging/android/ + AOA (Apple Onboard Audio) ALSA DRIVER M: Johannes Berg L: linuxppc-dev@lists.ozlabs.org @@ -754,13 +777,6 @@ L: linux-media@vger.kernel.org S: Maintained F: drivers/media/i2c/aptina-pll.* -ARASAN COMPACT FLASH PATA CONTROLLER -M: Viresh Kumar -L: linux-ide@vger.kernel.org -S: Maintained -F: include/linux/pata_arasan_cf_data.h -F: drivers/ata/pata_arasan_cf.c - ARC FRAMEBUFFER DRIVER M: Jaya Kumar S: Maintained @@ -1583,12 +1599,14 @@ N: xilinx F: drivers/clocksource/cadence_ttc_timer.c F: drivers/i2c/busses/i2c-cadence.c F: drivers/mmc/host/sdhci-of-arasan.c +F: drivers/edac/synopsys_edac.c ARM SMMU DRIVER M: Will Deacon L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/iommu/arm-smmu.c +F: drivers/iommu/io-pgtable-arm.c ARM64 PORT (AARCH64 ARCHITECTURE) M: Catalin Marinas @@ -1657,7 +1675,6 @@ M: Jiri Slaby M: Nick Kossifidis M: "Luis R. Rodriguez" L: linux-wireless@vger.kernel.org -L: ath5k-devel@lists.ath5k.org W: http://wireless.kernel.org/en/users/Drivers/ath5k S: Maintained F: drivers/net/wireless/ath/ath5k/ @@ -2346,7 +2363,8 @@ CAN NETWORK LAYER M: Oliver Hartkopp L: linux-can@vger.kernel.org W: http://gitorious.org/linux-can -T: git git://gitorious.org/linux-can/linux-can-next.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git S: Maintained F: Documentation/networking/can.txt F: net/can/ @@ -2361,7 +2379,8 @@ M: Wolfgang Grandegger M: Marc Kleine-Budde L: linux-can@vger.kernel.org W: http://gitorious.org/linux-can -T: git git://gitorious.org/linux-can/linux-can-next.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git S: Maintained F: drivers/net/can/ F: include/linux/can/dev.h @@ -3208,6 +3227,7 @@ F: Documentation/ X: Documentation/ABI/ X: Documentation/devicetree/ X: Documentation/[a-z][a-z]_[A-Z][A-Z]/ +T: git git://git.lwn.net/linux-2.6.git docs-next DOUBLETALK DRIVER M: "James R. Van Zandt" @@ -3467,6 +3487,14 @@ M: "Maciej W. Rozycki" S: Maintained F: drivers/tty/serial/dz.* +E3X0 POWER BUTTON DRIVER +M: Moritz Fischer +L: usrp-users@lists.ettus.com +W: http://www.ettus.com +S: Supported +F: drivers/input/misc/e3x0-button.c +F: Documentation/devicetree/bindings/input/e3x0-button.txt + E4000 MEDIA DRIVER M: Antti Palosaari L: linux-media@vger.kernel.org @@ -3508,6 +3536,8 @@ M: Borislav Petkov M: Mauro Carvalho Chehab L: linux-edac@vger.kernel.org W: bluesmoke.sourceforge.net +T: git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git#for-next +T: git://git.kernel.org/pub/linux/kernel/git/mchehab/linux-edac.git#linux_next S: Supported F: Documentation/edac.txt F: drivers/edac/ @@ -4755,14 +4785,14 @@ S: Supported F: drivers/net/ethernet/ibm/ibmveth.* IBM Power Virtual SCSI Device Drivers -M: Nathan Fontenot +M: Tyrel Datwyler L: linux-scsi@vger.kernel.org S: Supported F: drivers/scsi/ibmvscsi/ibmvscsi* F: drivers/scsi/ibmvscsi/viosrp.h IBM Power Virtual FC Device Drivers -M: Brian King +M: Tyrel Datwyler L: linux-scsi@vger.kernel.org S: Supported F: drivers/scsi/ibmvscsi/ibmvfc* @@ -4888,7 +4918,7 @@ F: drivers/ipack/ INTEGRITY MEASUREMENT ARCHITECTURE (IMA) M: Mimi Zohar -M: Dmitry Kasatkin +M: Dmitry Kasatkin L: linux-ima-devel@lists.sourceforge.net L: linux-ima-user@lists.sourceforge.net L: linux-security-module@vger.kernel.org @@ -4930,7 +4960,6 @@ F: include/uapi/linux/inotify.h INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS M: Dmitry Torokhov -M: Dmitry Torokhov L: linux-input@vger.kernel.org Q: http://patchwork.kernel.org/project/linux-input/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git @@ -4949,10 +4978,19 @@ F: Documentation/input/multi-touch-protocol.txt F: drivers/input/input-mt.c K: \b(ABS|SYN)_MT_ +INTEL ASoC BDW/HSW DRIVERS +M: Jie Yang +L: alsa-devel@alsa-project.org +S: Supported +F: sound/soc/intel/sst-haswell* +F: sound/soc/intel/sst-dsp* +F: sound/soc/intel/sst-firmware.c +F: sound/soc/intel/broadwell.c +F: sound/soc/intel/haswell.c + INTEL C600 SERIES SAS CONTROLLER DRIVER M: Intel SCU Linux support M: Artur Paszkiewicz -M: Dave Jiang L: linux-scsi@vger.kernel.org T: git git://git.code.sf.net/p/intel-sas/isci S: Supported @@ -5703,6 +5741,49 @@ F: drivers/lguest/ F: include/linux/lguest*.h F: tools/lguest/ +LIBATA SUBSYSTEM (Serial and Parallel ATA drivers) +M: Tejun Heo +L: linux-ide@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git +S: Maintained +F: drivers/ata/ +F: include/linux/ata.h +F: include/linux/libata.h + +LIBATA PATA ARASAN COMPACT FLASH CONTROLLER +M: Viresh Kumar +L: linux-ide@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git +S: Maintained +F: include/linux/pata_arasan_cf_data.h +F: drivers/ata/pata_arasan_cf.c + +LIBATA PATA DRIVERS +M: Bartlomiej Zolnierkiewicz +M: Tejun Heo +L: linux-ide@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git +S: Maintained +F: drivers/ata/pata_*.c +F: drivers/ata/ata_generic.c + +LIBATA SATA AHCI PLATFORM devices support +M: Hans de Goede +M: Tejun Heo +L: linux-ide@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git +S: Maintained +F: drivers/ata/ahci_platform.c +F: drivers/ata/libahci_platform.c +F: include/linux/ahci_platform.h + +LIBATA SATA PROMISE TX2/TX4 CONTROLLER DRIVER +M: Mikael Pettersson +L: linux-ide@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git +S: Maintained +F: drivers/ata/sata_promise.* + LIBLOCKDEP M: Sasha Levin S: Maintained @@ -5794,6 +5875,21 @@ F: Documentation/misc-devices/lis3lv02d F: drivers/misc/lis3lv02d/ F: drivers/platform/x86/hp_accel.c +LIVE PATCHING +M: Josh Poimboeuf +M: Seth Jennings +M: Jiri Kosina +M: Vojtech Pavlik +S: Maintained +F: kernel/livepatch/ +F: include/linux/livepatch.h +F: arch/x86/include/asm/livepatch.h +F: arch/x86/kernel/livepatch.c +F: Documentation/ABI/testing/sysfs-kernel-livepatch +F: samples/livepatch/ +L: live-patching@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching.git + LLC (802.2) M: Arnaldo Carvalho de Melo S: Maintained @@ -6092,6 +6188,13 @@ F: Documentation/devicetree/bindings/i2c/max6697.txt F: drivers/hwmon/max6697.c F: include/linux/platform_data/max6697.h +MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS +M: Krzysztof Kozlowski +L: linux-pm@vger.kernel.org +S: Supported +F: drivers/power/max14577_charger.c +F: drivers/power/max77693_charger.c + MAXIRADIO FM RADIO RECEIVER DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org @@ -6122,14 +6225,6 @@ F: include/uapi/linux/meye.h F: include/uapi/linux/ivtv* F: include/uapi/linux/uvcvideo.h -MEDIAVISION PRO MOVIE STUDIO DRIVER -M: Hans Verkuil -L: linux-media@vger.kernel.org -T: git git://linuxtv.org/media_tree.git -W: http://linuxtv.org -S: Odd Fixes -F: drivers/media/parport/pms* - MEGARAID SCSI/SAS DRIVERS M: Kashyap Desai M: Sumit Saxena @@ -6578,6 +6673,7 @@ F: include/linux/netdevice.h F: include/uapi/linux/in.h F: include/uapi/linux/net.h F: include/uapi/linux/netdevice.h +F: include/uapi/linux/net_namespace.h F: tools/net/ F: tools/testing/selftests/net/ F: lib/random32.c @@ -6988,14 +7084,12 @@ OPEN FIRMWARE AND FLATTENED DEVICE TREE M: Grant Likely M: Rob Herring L: devicetree@vger.kernel.org -W: http://fdt.secretlab.ca -T: git git://git.secretlab.ca/git/linux-2.6.git +W: http://www.devicetree.org/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/glikely/linux.git S: Maintained F: drivers/of/ F: include/linux/of*.h F: scripts/dtc/ -K: of_get_property -K: of_match_table OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS M: Rob Herring @@ -7019,11 +7113,12 @@ F: arch/openrisc/ OPENVSWITCH M: Pravin Shelar +L: netdev@vger.kernel.org L: dev@openvswitch.org W: http://openvswitch.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/pshelar/openvswitch.git S: Maintained F: net/openvswitch/ +F: include/uapi/linux/openvswitch.h OPL4 DRIVER M: Clemens Ladisch @@ -7221,6 +7316,14 @@ F: include/linux/pci* F: arch/x86/pci/ F: arch/x86/kernel/quirks.c +PCI DRIVER FOR ARM VERSATILE PLATFORM +M: Rob Herring +L: linux-pci@vger.kernel.org +L: linux-arm-kernel@lists.infradead.org +S: Maintained +F: Documentation/devicetree/bindings/pci/versatile.txt +F: drivers/pci/host/pci-versatile.c + PCI DRIVER FOR APPLIEDMICRO XGENE M: Tanmay Inamdar L: linux-pci@vger.kernel.org @@ -7240,7 +7343,7 @@ S: Maintained F: drivers/pci/host/*layerscape* PCI DRIVER FOR IMX6 -M: Richard Zhu +M: Richard Zhu M: Lucas Stach L: linux-pci@vger.kernel.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -7410,6 +7513,7 @@ F: drivers/crypto/picoxcell* PIN CONTROL SUBSYSTEM M: Linus Walleij L: linux-gpio@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git S: Maintained F: drivers/pinctrl/ F: include/linux/pinctrl/ @@ -7577,12 +7681,6 @@ W: http://wireless.kernel.org/en/users/Drivers/p54 S: Obsolete F: drivers/net/wireless/prism54/ -PROMISE SATA TX2/TX4 CONTROLLER LIBATA DRIVER -M: Mikael Pettersson -L: linux-ide@vger.kernel.org -S: Maintained -F: drivers/ata/sata_promise.* - PS3 NETWORK SUPPORT M: Geoff Levand L: netdev@vger.kernel.org @@ -7827,14 +7925,6 @@ T: git git://github.com/KrasnikovEugene/wcn36xx.git S: Supported F: drivers/net/wireless/ath/wcn36xx/ -QUICKCAM PARALLEL PORT WEBCAMS -M: Hans Verkuil -L: linux-media@vger.kernel.org -T: git git://linuxtv.org/media_tree.git -W: http://linuxtv.org -S: Odd Fixes -F: drivers/media/parport/*-qcam* - RADOS BLOCK DEVICE (RBD) M: Yehuda Sadeh M: Sage Weil @@ -8023,6 +8113,13 @@ S: Maintained F: Documentation/rfkill.txt F: net/rfkill/ +RHASHTABLE +M: Thomas Graf +L: netdev@vger.kernel.org +S: Maintained +F: lib/rhashtable.c +F: include/linux/rhashtable.h + RICOH SMARTMEDIA/XD DRIVER M: Maxim Levitsky S: Maintained @@ -8365,12 +8462,6 @@ F: kernel/time/clocksource.c F: kernel/time/time*.c F: kernel/time/ntp.c -TLG2300 VIDEO4LINUX-2 DRIVER -M: Huang Shijie -M: Hans Verkuil -S: Odd Fixes -F: drivers/media/usb/tlg2300/ - SC1200 WDT DRIVER M: Zwane Mwaikambo S: Maintained @@ -8556,25 +8647,6 @@ S: Maintained F: drivers/misc/phantom.c F: include/uapi/linux/phantom.h -SERIAL ATA (SATA) SUBSYSTEM -M: Tejun Heo -L: linux-ide@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git -S: Supported -F: drivers/ata/ -F: include/linux/ata.h -F: include/linux/libata.h - -SERIAL ATA AHCI PLATFORM devices support -M: Hans de Goede -M: Tejun Heo -L: linux-ide@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git -S: Supported -F: drivers/ata/ahci_platform.c -F: drivers/ata/libahci_platform.c -F: include/linux/ahci_platform.h - SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER M: Jayamohan Kallickal L: linux-scsi@vger.kernel.org @@ -8755,6 +8827,15 @@ S: Maintained F: drivers/media/platform/davinci/ F: include/media/davinci/ +TI AM437X VPFE DRIVER +M: Lad, Prabhakar +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git +S: Maintained +F: drivers/media/platform/am437x/ + SIS 190 ETHERNET DRIVER M: Francois Romieu L: netdev@vger.kernel.org @@ -8836,6 +8917,8 @@ F: drivers/media/i2c/smiapp/ F: include/media/smiapp.h F: drivers/media/i2c/smiapp-pll.c F: drivers/media/i2c/smiapp-pll.h +F: include/uapi/linux/smiapp.h +F: Documentation/devicetree/bindings/media/i2c/nokia,smia.txt SMM665 HARDWARE MONITOR DRIVER M: Guenter Roeck @@ -8902,6 +8985,7 @@ SOFTLOGIC 6x10 MPEG CODEC M: Bluecherry Maintainers M: Andrey Utkin M: Andrey Utkin +M: Ismael Luceno L: linux-media@vger.kernel.org S: Supported F: drivers/media/pci/solo6x10/ @@ -9214,6 +9298,13 @@ F: arch/m68k/sun3*/ F: arch/m68k/include/asm/sun3* F: drivers/net/ethernet/i825xx/sun3* +SUN4I LOW RES ADC ATTACHED TABLET KEYS DRIVER +M: Hans de Goede +L: linux-input@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt +F: drivers/input/keyboard/sun4i-lradc-keys.c + SUNDANCE NETWORK DRIVER M: Denis Kirjanov L: netdev@vger.kernel.org @@ -9222,7 +9313,6 @@ F: drivers/net/ethernet/dlink/sundance.c SUPERH L: linux-sh@vger.kernel.org -W: http://www.linux-sh.org Q: http://patchwork.kernel.org/project/linux-sh/list/ S: Orphan F: Documentation/sh/ @@ -9601,6 +9691,13 @@ F: drivers/power/lp8788-charger.c F: drivers/regulator/lp8788-*.c F: include/linux/mfd/lp8788*.h +TI NETCP ETHERNET DRIVER +M: Wingman Kwok +M: Murali Karicheri +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/ethernet/ti/netcp* + TI TWL4030 SERIES SOC CODEC DRIVER M: Peter Ujfalusi L: alsa-devel@alsa-project.org (moderated for non-subscribers) @@ -9721,13 +9818,21 @@ F: drivers/media/pci/tw68/ TPM DEVICE DRIVER M: Peter Huewe -M: Ashley Lai M: Marcel Selhorst W: http://tpmdd.sourceforge.net L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers) +Q: git git://github.com/PeterHuewe/linux-tpmdd.git +T: https://github.com/PeterHuewe/linux-tpmdd S: Maintained F: drivers/char/tpm/ +TPM IBM_VTPM DEVICE DRIVER +M: Ashley Lai +W: http://tpmdd.sourceforge.net +L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers) +S: Maintained +F: drivers/char/tpm/tpm_ibmvtpm* + TRACING M: Steven Rostedt M: Ingo Molnar @@ -10157,6 +10262,7 @@ USERSPACE I/O (UIO) M: "Hans J. Koch" M: Greg Kroah-Hartman S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git F: Documentation/DocBook/uio-howto.tmpl F: drivers/uio/ F: include/linux/uio*.h @@ -10639,6 +10745,7 @@ M: Max Filippov L: linux-xtensa@linux-xtensa.org S: Maintained F: drivers/spi/spi-xtensa-xtfpga.c +F: sound/soc/xtensa/xtfpga-i2s.c YAM DRIVER FOR AX.25 M: Jean-Paul Roubelat diff --git a/Makefile b/Makefile index fb93350cf645..5fa2e3035509 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 19 SUBLEVEL = 0 -EXTRAVERSION = -rc5 +EXTRAVERSION = NAME = Diseased Newt # *DOCUMENTATION* @@ -726,10 +726,14 @@ KBUILD_CFLAGS += $(call cc-option, -femit-struct-debug-baseonly) \ endif ifdef CONFIG_FUNCTION_TRACER +ifndef CC_FLAGS_FTRACE +CC_FLAGS_FTRACE := -pg +endif +export CC_FLAGS_FTRACE ifdef CONFIG_HAVE_FENTRY CC_USING_FENTRY := $(call cc-option, -mfentry -DCC_USING_FENTRY) endif -KBUILD_CFLAGS += -pg $(CC_USING_FENTRY) +KBUILD_CFLAGS += $(CC_FLAGS_FTRACE) $(CC_USING_FENTRY) KBUILD_AFLAGS += $(CC_USING_FENTRY) ifdef CONFIG_DYNAMIC_FTRACE ifdef CONFIG_HAVE_C_RECORDMCOUNT diff --git a/arch/alpha/include/asm/pgtable.h b/arch/alpha/include/asm/pgtable.h index d8f9b7e89234..a9a119592372 100644 --- a/arch/alpha/include/asm/pgtable.h +++ b/arch/alpha/include/asm/pgtable.h @@ -45,7 +45,7 @@ struct vm_area_struct; #define PTRS_PER_PMD (1UL << (PAGE_SHIFT-3)) #define PTRS_PER_PGD (1UL << (PAGE_SHIFT-3)) #define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL /* Number of pointers that fit on a page: this will go away. */ #define PTRS_PER_PAGE (1UL << (PAGE_SHIFT-3)) @@ -73,7 +73,6 @@ struct vm_area_struct; /* .. and these are ours ... */ #define _PAGE_DIRTY 0x20000 #define _PAGE_ACCESSED 0x40000 -#define _PAGE_FILE 0x80000 /* set:pagecache, unset:swap */ /* * NOTE! The "accessed" bit isn't necessarily exact: it can be kept exactly @@ -268,7 +267,6 @@ extern inline void pgd_clear(pgd_t * pgdp) { pgd_val(*pgdp) = 0; } extern inline int pte_write(pte_t pte) { return !(pte_val(pte) & _PAGE_FOW); } extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } -extern inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } extern inline int pte_special(pte_t pte) { return 0; } extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) |= _PAGE_FOW; return pte; } @@ -345,11 +343,6 @@ extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -#define pte_to_pgoff(pte) (pte_val(pte) >> 32) -#define pgoff_to_pte(off) ((pte_t) { ((off) << 32) | _PAGE_FILE }) - -#define PTE_FILE_MAX_BITS 32 - #ifndef CONFIG_DISCONTIGMEM #define kern_addr_valid(addr) (1) #endif diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index 076c35cd6cde..98a1525fa164 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -285,8 +285,12 @@ pcibios_claim_one_bus(struct pci_bus *b) if (r->parent || !r->start || !r->flags) continue; if (pci_has_flag(PCI_PROBE_ONLY) || - (r->flags & IORESOURCE_PCI_FIXED)) - pci_claim_resource(dev, i); + (r->flags & IORESOURCE_PCI_FIXED)) { + if (pci_claim_resource(dev, i) == 0) + continue; + + pci_claim_bridge_resource(dev, i); + } } } diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index 98838a05ba6d..9d0ac091a52a 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -156,6 +156,8 @@ retry: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h index 6b0b7f7ef783..ffed3b2cf313 100644 --- a/arch/arc/include/asm/pgtable.h +++ b/arch/arc/include/asm/pgtable.h @@ -61,7 +61,6 @@ #define _PAGE_WRITE (1<<4) /* Page has user write perm (H) */ #define _PAGE_READ (1<<5) /* Page has user read perm (H) */ #define _PAGE_MODIFIED (1<<6) /* Page modified (dirty) (S) */ -#define _PAGE_FILE (1<<7) /* page cache/ swap (S) */ #define _PAGE_GLOBAL (1<<8) /* Page is global (H) */ #define _PAGE_PRESENT (1<<10) /* TLB entry is valid (H) */ @@ -73,7 +72,6 @@ #define _PAGE_READ (1<<3) /* Page has user read perm (H) */ #define _PAGE_ACCESSED (1<<4) /* Page is accessed (S) */ #define _PAGE_MODIFIED (1<<5) /* Page modified (dirty) (S) */ -#define _PAGE_FILE (1<<6) /* page cache/ swap (S) */ #define _PAGE_GLOBAL (1<<8) /* Page is global (H) */ #define _PAGE_PRESENT (1<<9) /* TLB entry is valid (H) */ #define _PAGE_SHARED_CODE (1<<11) /* Shared Code page with cmn vaddr @@ -213,7 +211,7 @@ * No special requirements for lowest virtual address we permit any user space * mapping to be mapped at. */ -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL /**************************************************************** @@ -268,15 +266,6 @@ static inline void pmd_set(pmd_t *pmdp, pte_t *ptep) pte; \ }) -/* TBD: Non linear mapping stuff */ -static inline int pte_file(pte_t pte) -{ - return pte_val(pte) & _PAGE_FILE; -} - -#define PTE_FILE_MAX_BITS 30 -#define pgoff_to_pte(x) __pte(x) -#define pte_to_pgoff(x) (pte_val(x) >> 2) #define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) #define pfn_pte(pfn, prot) (__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))) #define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) @@ -364,7 +353,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, /* Encode swap {type,off} tuple into PTE * We reserve 13 bits for 5-bit @type, keeping bits 12-5 zero, ensuring that - * both PAGE_FILE and PAGE_PRESENT are zero in a PTE holding swap "identifier" + * PAGE_PRESENT is zero in a PTE holding swap "identifier" */ #define __swp_entry(type, off) ((swp_entry_t) { \ ((type) & 0x1f) | ((off) << 13) }) diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c index 6f7e3a68803a..563cb27e37f5 100644 --- a/arch/arc/mm/fault.c +++ b/arch/arc/mm/fault.c @@ -161,6 +161,8 @@ good_area: if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 97d07ed60a0b..0850fc0f9658 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -29,6 +29,7 @@ config ARM select HANDLE_DOMAIN_IRQ select HARDIRQS_SW_RESEND select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT) + select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6 select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL select HAVE_ARCH_KGDB select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT) @@ -60,6 +61,7 @@ config ARM select HAVE_MEMBLOCK select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND select HAVE_OPROFILE if (HAVE_PERF_EVENTS) + select HAVE_OPTPROBES if !THUMB2_KERNEL select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP @@ -1279,6 +1281,9 @@ config PCI_DOMAINS bool depends on PCI +config PCI_DOMAINS_GENERIC + def_bool PCI_DOMAINS + config PCI_NANOENGINE bool "BSE nanoEngine PCI support" depends on SA1100_NANOENGINE diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 5ddd4906f7a7..a324ecdfeb21 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -397,6 +397,13 @@ choice Say Y here if you want the debug print routines to direct their output to UART1 serial port on KEYSTONE2 devices. + config DEBUG_KS8695_UART + bool "KS8695 Debug UART" + depends on ARCH_KS8695 + help + Say Y here if you want kernel low-level debugging support + on KS8695. + config DEBUG_MESON_UARTAO bool "Kernel low-level debugging via Meson6 UARTAO" depends on ARCH_MESON @@ -496,6 +503,13 @@ choice Say Y here if you want kernel low-level debugging support on Vybrid based platforms. + config DEBUG_NETX_UART + bool "Kernel low-level debugging messages via NetX UART" + depends on ARCH_NETX + help + Say Y here if you want kernel low-level debugging support + on Hilscher NetX based platforms. + config DEBUG_NOMADIK_UART bool "Kernel low-level debugging messages via NOMADIK UART" depends on ARCH_NOMADIK @@ -520,6 +534,30 @@ choice Say Y here if you want kernel low-level debugging support on TI-NSPIRE CX models. + config DEBUG_OMAP1UART1 + bool "Kernel low-level debugging via OMAP1 UART1" + depends on ARCH_OMAP1 + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + on OMAP1 based platforms (except OMAP730) on the UART1. + + config DEBUG_OMAP1UART2 + bool "Kernel low-level debugging via OMAP1 UART2" + depends on ARCH_OMAP1 + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + on OMAP1 based platforms (except OMAP730) on the UART2. + + config DEBUG_OMAP1UART3 + bool "Kernel low-level debugging via OMAP1 UART3" + depends on ARCH_OMAP1 + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + on OMAP1 based platforms (except OMAP730) on the UART3. + config DEBUG_OMAP2UART1 bool "OMAP2/3/4 UART1 (omap2/3 sdp boards and some omap3 boards)" depends on ARCH_OMAP2PLUS @@ -562,6 +600,30 @@ choice depends on ARCH_OMAP2PLUS select DEBUG_OMAP2PLUS_UART + config DEBUG_OMAP7XXUART1 + bool "Kernel low-level debugging via OMAP730 UART1" + depends on ARCH_OMAP730 + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + on OMAP730 based platforms on the UART1. + + config DEBUG_OMAP7XXUART2 + bool "Kernel low-level debugging via OMAP730 UART2" + depends on ARCH_OMAP730 + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + on OMAP730 based platforms on the UART2. + + config DEBUG_OMAP7XXUART3 + bool "Kernel low-level debugging via OMAP730 UART3" + depends on ARCH_OMAP730 + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + on OMAP730 based platforms on the UART3. + config DEBUG_TI81XXUART1 bool "Kernel low-level debugging messages via TI81XX UART1 (ti8148evm)" depends on ARCH_OMAP2PLUS @@ -1031,15 +1093,6 @@ choice This option selects UART0 on VIA/Wondermedia System-on-a-chip devices, including VT8500, WM8505, WM8650 and WM8850. - config DEBUG_LL_UART_NONE - bool "No low-level debugging UART" - depends on !ARCH_MULTIPLATFORM - help - Say Y here if your platform doesn't provide a UART option - above. This relies on your platform choosing the right UART - definition internally in order for low-level debugging to - work. - config DEBUG_ICEDCC bool "Kernel low-level debugging via EmbeddedICE DCC channel" help @@ -1183,7 +1236,9 @@ config DEBUG_LL_INCLUDE DEBUG_IMX6Q_UART || \ DEBUG_IMX6SL_UART || \ DEBUG_IMX6SX_UART + default "debug/ks8695.S" if DEBUG_KS8695_UART default "debug/msm.S" if DEBUG_MSM_UART || DEBUG_QCOM_UARTDM + default "debug/netx.S" if DEBUG_NETX_UART default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART default "debug/renesas-scif.S" if DEBUG_R7S72100_SCIF2 default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF0 @@ -1208,12 +1263,7 @@ config DEBUG_LL_INCLUDE # Compatibility options for PL01x config DEBUG_UART_PL01X - def_bool ARCH_EP93XX || \ - ARCH_INTEGRATOR || \ - ARCH_SPEAR3XX || \ - ARCH_SPEAR6XX || \ - ARCH_SPEAR13XX || \ - ARCH_VERSATILE + bool # Compatibility options for 8250 config DEBUG_UART_8250 @@ -1229,6 +1279,7 @@ config DEBUG_UART_BCM63XX config DEBUG_UART_PHYS hex "Physical base address of debug UART" + default 0x00100a00 if DEBUG_NETX_UART default 0x01c20000 if DEBUG_DAVINCI_DMx_UART0 default 0x01c28000 if DEBUG_SUNXI_UART0 default 0x01c28400 if DEBUG_SUNXI_UART1 @@ -1269,7 +1320,6 @@ config DEBUG_UART_PHYS DEBUG_S3C2410_UART2) default 0x78000000 if DEBUG_CNS3XXX default 0x7c0003f8 if FOOTBRIDGE - default 0x78000000 if DEBUG_CNS3XXX default 0x80010000 if DEBUG_ASM9260_UART default 0x80070000 if DEBUG_IMX23_UART default 0x80074000 if DEBUG_IMX28_UART @@ -1310,12 +1360,17 @@ config DEBUG_UART_PHYS default 0xffe40000 if DEBUG_RCAR_GEN1_SCIF0 default 0xffe42000 if DEBUG_RCAR_GEN1_SCIF2 default 0xfff36000 if DEBUG_HIGHBANK_UART + default 0xfffb0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1 + default 0xfffb0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2 + default 0xfffb9800 if DEBUG_OMAP1UART3 || DEBUG_OMAP7XXUART3 default 0xfffe8600 if DEBUG_UART_BCM63XX default 0xfffff700 if ARCH_IOP33X - depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ + depends on ARCH_EP93XX || \ + DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ DEBUG_LL_UART_EFM32 || \ DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ - DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_R7S72100_SCIF2 || \ + DEBUG_MSM_UART || DEBUG_NETX_UART || \ + DEBUG_QCOM_UARTDM || DEBUG_R7S72100_SCIF2 || \ DEBUG_RCAR_GEN1_SCIF0 || DEBUG_RCAR_GEN1_SCIF2 || \ DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF2 || \ DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \ @@ -1324,6 +1379,7 @@ config DEBUG_UART_PHYS config DEBUG_UART_VIRT hex "Virtual base address of debug UART" + default 0xe0000a00 if DEBUG_NETX_UART default 0xe0010fe0 if ARCH_RPC default 0xe1000000 if DEBUG_MSM_UART default 0xf0000be0 if ARCH_EBSA110 @@ -1392,18 +1448,23 @@ config DEBUG_UART_VIRT default 0xfef00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN default 0xfef00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN default 0xfef36000 if DEBUG_HIGHBANK_UART + default 0xfefb0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1 + default 0xfefb0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2 + default 0xfefb9800 if DEBUG_OMAP1UART3 || DEBUG_OMAP7XXUART3 default 0xfefff700 if ARCH_IOP33X default 0xff003000 if DEBUG_U300_UART default DEBUG_UART_PHYS if !MMU depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ - DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \ + DEBUG_MSM_UART || DEBUG_NETX_UART || \ + DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \ DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART config DEBUG_UART_8250_SHIFT int "Register offset shift for the 8250 debug UART" depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250 - default 0 if FOOTBRIDGE || ARCH_IOP32X || DEBUG_BCM_5301X + default 0 if FOOTBRIDGE || ARCH_IOP32X || DEBUG_BCM_5301X || \ + DEBUG_OMAP7XXUART1 || DEBUG_OMAP7XXUART2 || DEBUG_OMAP7XXUART3 default 2 config DEBUG_UART_8250_WORD diff --git a/arch/arm/Makefile b/arch/arm/Makefile index c1785eec2cf7..7f99cd652203 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -266,6 +266,7 @@ core-$(CONFIG_KVM_ARM_HOST) += arch/arm/kvm/ # If we have a machine-specific directory, then include it in the build. core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ +core-y += arch/arm/probes/ core-y += arch/arm/net/ core-y += arch/arm/crypto/ core-y += arch/arm/firmware/ diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 68be9017593d..c41a793b519c 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -178,7 +178,7 @@ not_angel: /* * Set up a page table only if it won't overwrite ourself. - * That means r4 < pc && r4 - 16k page directory > &_end. + * That means r4 < pc || r4 - 16k page directory > &_end. * Given that r4 > &_end is most unfrequent, we add a rough * additional 1MB of room for a possible appended DTB. */ @@ -263,16 +263,37 @@ restart: adr r0, LC0 * OK... Let's do some funky business here. * If we do have a DTB appended to zImage, and we do have * an ATAG list around, we want the later to be translated - * and folded into the former here. To be on the safe side, - * let's temporarily move the stack away into the malloc - * area. No GOT fixup has occurred yet, but none of the - * code we're about to call uses any global variable. + * and folded into the former here. No GOT fixup has occurred + * yet, but none of the code we're about to call uses any + * global variable. */ - add sp, sp, #0x10000 + + /* Get the initial DTB size */ + ldr r5, [r6, #4] +#ifndef __ARMEB__ + /* convert to little endian */ + eor r1, r5, r5, ror #16 + bic r1, r1, #0x00ff0000 + mov r5, r5, ror #8 + eor r5, r5, r1, lsr #8 +#endif + /* 50% DTB growth should be good enough */ + add r5, r5, r5, lsr #1 + /* preserve 64-bit alignment */ + add r5, r5, #7 + bic r5, r5, #7 + /* clamp to 32KB min and 1MB max */ + cmp r5, #(1 << 15) + movlo r5, #(1 << 15) + cmp r5, #(1 << 20) + movhi r5, #(1 << 20) + /* temporarily relocate the stack past the DTB work space */ + add sp, sp, r5 + stmfd sp!, {r0-r3, ip, lr} mov r0, r8 mov r1, r6 - sub r2, sp, r6 + mov r2, r5 bl atags_to_fdt /* @@ -285,11 +306,11 @@ restart: adr r0, LC0 bic r0, r0, #1 add r0, r0, #0x100 mov r1, r6 - sub r2, sp, r6 + mov r2, r5 bleq atags_to_fdt ldmfd sp!, {r0-r3, ip, lr} - sub sp, sp, #0x10000 + sub sp, sp, r5 #endif mov r8, r6 @ use the appended device tree @@ -306,7 +327,7 @@ restart: adr r0, LC0 subs r1, r5, r1 addhi r9, r9, r1 - /* Get the dtb's size */ + /* Get the current DTB size */ ldr r5, [r6, #4] #ifndef __ARMEB__ /* convert r5 (dtb size) to little endian */ diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts index 54f118c08db8..66342515df20 100644 --- a/arch/arm/boot/dts/am335x-evm.dts +++ b/arch/arm/boot/dts/am335x-evm.dts @@ -648,6 +648,7 @@ ti,x-plate-resistance = <200>; ti,coordinate-readouts = <5>; ti,wire-config = <0x00 0x11 0x22 0x33>; + ti,charge-delay = <0x400>; }; adc { diff --git a/arch/arm/boot/dts/am3517.dtsi b/arch/arm/boot/dts/am3517.dtsi index 5a452fdd7c5d..c90724bded10 100644 --- a/arch/arm/boot/dts/am3517.dtsi +++ b/arch/arm/boot/dts/am3517.dtsi @@ -31,6 +31,7 @@ status = "disabled"; reg = <0x5c000000 0x30000>; interrupts = <67 68 69 70>; + syscon = <&omap3_scm_general>; ti,davinci-ctrl-reg-offset = <0x10000>; ti,davinci-ctrl-mod-reg-offset = <0>; ti,davinci-ctrl-ram-offset = <0x20000>; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 22771bc1643a..63f8b007bdc5 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1257,6 +1257,8 @@ tx-fifo-resize; maximum-speed = "super-speed"; dr_mode = "otg"; + snps,dis_u3_susphy_quirk; + snps,dis_u2_susphy_quirk; }; }; @@ -1278,6 +1280,8 @@ tx-fifo-resize; maximum-speed = "high-speed"; dr_mode = "otg"; + snps,dis_u3_susphy_quirk; + snps,dis_u2_susphy_quirk; }; }; @@ -1299,6 +1303,8 @@ tx-fifo-resize; maximum-speed = "high-speed"; dr_mode = "otg"; + snps,dis_u3_susphy_quirk; + snps,dis_u2_susphy_quirk; }; }; diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index b8168f1f8139..cb6001085f1a 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -61,9 +61,12 @@ reg = <0x03830000 0x100>; clocks = <&clock_audss EXYNOS_I2S_BUS>; clock-names = "iis"; + #clock-cells = <1>; + clock-output-names = "i2s_cdclk0"; dmas = <&pdma0 12>, <&pdma0 11>, <&pdma0 10>; dma-names = "tx", "rx", "tx-sec"; samsung,idma-addr = <0x03000000>; + #sound-dai-cells = <1>; status = "disabled"; }; @@ -368,22 +371,28 @@ }; i2s1: i2s@13960000 { - compatible = "samsung,s5pv210-i2s"; + compatible = "samsung,s3c6410-i2s"; reg = <0x13960000 0x100>; clocks = <&clock CLK_I2S1>; clock-names = "iis"; + #clock-cells = <1>; + clock-output-names = "i2s_cdclk1"; dmas = <&pdma1 12>, <&pdma1 11>; dma-names = "tx", "rx"; + #sound-dai-cells = <1>; status = "disabled"; }; i2s2: i2s@13970000 { - compatible = "samsung,s5pv210-i2s"; + compatible = "samsung,s3c6410-i2s"; reg = <0x13970000 0x100>; clocks = <&clock CLK_I2S2>; clock-names = "iis"; + #clock-cells = <1>; + clock-output-names = "i2s_cdclk2"; dmas = <&pdma0 14>, <&pdma0 13>; dma-names = "tx", "rx"; + #sound-dai-cells = <1>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi index bcc9e63c8070..8e45ea44317e 100644 --- a/arch/arm/boot/dts/exynos4210.dtsi +++ b/arch/arm/boot/dts/exynos4210.dtsi @@ -81,6 +81,15 @@ reg = <0x10023CA0 0x20>; }; + l2c: l2-cache-controller@10502000 { + compatible = "arm,pl310-cache"; + reg = <0x10502000 0x1000>; + cache-unified; + cache-level = <2>; + arm,tag-latency = <2 2 1>; + arm,data-latency = <2 2 1>; + }; + gic: interrupt-controller@10490000 { cpu-offset = <0x8000>; }; diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index 3fbf588682b9..abd63366298a 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -7,6 +7,7 @@ * published by the Free Software Foundation. */ +#include #include #include "exynos4412.dtsi" @@ -37,14 +38,13 @@ pinctrl-names = "default"; status = "okay"; clocks = <&clock_audss EXYNOS_I2S_BUS>, - <&clock_audss EXYNOS_DOUT_AUD_BUS>; - clock-names = "iis", "i2s_opclk0"; + <&clock_audss EXYNOS_DOUT_AUD_BUS>, + <&clock_audss EXYNOS_SCLK_I2S>; + clock-names = "iis", "i2s_opclk0", "i2s_opclk1"; }; sound: sound { - compatible = "samsung,odroidx2-audio"; - samsung,i2s-controller = <&i2s0>; - samsung,audio-codec = <&max98090>; + compatible = "simple-audio-card"; assigned-clocks = <&clock_audss EXYNOS_MOUT_AUDSS>, <&clock_audss EXYNOS_MOUT_I2S>, <&clock_audss EXYNOS_DOUT_SRP>, @@ -55,6 +55,20 @@ <0>, <192000000>, <19200000>; + + simple-audio-card,format = "i2s"; + simple-audio-card,bitclock-master = <&link0_codec>; + simple-audio-card,frame-master = <&link0_codec>; + + simple-audio-card,cpu { + sound-dai = <&i2s0 0>; + system-clock-frequency = <19200000>; + }; + + link0_codec: simple-audio-card,codec { + sound-dai = <&max98090>; + clocks = <&i2s0 CLK_I2S_CDCLK>; + }; }; mmc@12550000 { @@ -373,6 +387,9 @@ reg = <0x10>; interrupt-parent = <&gpx0>; interrupts = <0 0>; + clocks = <&i2s0 CLK_I2S_CDCLK>; + clock-names = "mclk"; + #sound-dai-cells = <0>; }; }; diff --git a/arch/arm/boot/dts/exynos4412-odroidu3.dts b/arch/arm/boot/dts/exynos4412-odroidu3.dts index c8a64be55d07..44684e57ead1 100644 --- a/arch/arm/boot/dts/exynos4412-odroidu3.dts +++ b/arch/arm/boot/dts/exynos4412-odroidu3.dts @@ -49,9 +49,11 @@ }; &sound { - compatible = "samsung,odroidu3-audio"; - samsung,model = "Odroid-U3"; - samsung,audio-routing = + simple-audio-card,name = "Odroid-U3"; + simple-audio-card,widgets = + "Headphone", "Headphone Jack", + "Speakers", "Speakers"; + simple-audio-card,routing = "Headphone Jack", "HPL", "Headphone Jack", "HPR", "Headphone Jack", "MICBIAS", diff --git a/arch/arm/boot/dts/exynos4412-odroidx2.dts b/arch/arm/boot/dts/exynos4412-odroidx2.dts index 96b43f4497cc..6e33678562ae 100644 --- a/arch/arm/boot/dts/exynos4412-odroidx2.dts +++ b/arch/arm/boot/dts/exynos4412-odroidx2.dts @@ -23,8 +23,12 @@ }; &sound { - samsung,model = "Odroid-X2"; - samsung,audio-routing = + simple-audio-card,name = "Odroid-X2"; + simple-audio-card,widgets = + "Headphone", "Headphone Jack", + "Microphone", "Mic Jack", + "Microphone", "DMIC"; + simple-audio-card,routing = "Headphone Jack", "HPL", "Headphone Jack", "HPR", "IN1", "Mic Jack", diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi index 93b70402e943..8bc97c415c9a 100644 --- a/arch/arm/boot/dts/exynos4x12.dtsi +++ b/arch/arm/boot/dts/exynos4x12.dtsi @@ -54,6 +54,20 @@ reg = <0x10023CA0 0x20>; }; + l2c: l2-cache-controller@10502000 { + compatible = "arm,pl310-cache"; + reg = <0x10502000 0x1000>; + cache-unified; + cache-level = <2>; + arm,tag-latency = <2 2 1>; + arm,data-latency = <3 2 1>; + arm,double-linefill = <1>; + arm,double-linefill-incr = <0>; + arm,double-linefill-wrap = <1>; + arm,prefetch-drop = <1>; + arm,prefetch-offset = <7>; + }; + clock: clock-controller@10030000 { compatible = "samsung,exynos4412-clock"; reg = <0x10030000 0x20000>; diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi index d238676a9107..e4d3aecc4ed2 100644 --- a/arch/arm/boot/dts/imx25.dtsi +++ b/arch/arm/boot/dts/imx25.dtsi @@ -369,7 +369,7 @@ compatible = "fsl,imx25-pwm", "fsl,imx27-pwm"; #pwm-cells = <2>; reg = <0x53fa0000 0x4000>; - clocks = <&clks 106>, <&clks 36>; + clocks = <&clks 106>, <&clks 52>; clock-names = "ipg", "per"; interrupts = <36>; }; @@ -388,7 +388,7 @@ compatible = "fsl,imx25-pwm", "fsl,imx27-pwm"; #pwm-cells = <2>; reg = <0x53fa8000 0x4000>; - clocks = <&clks 107>, <&clks 36>; + clocks = <&clks 107>, <&clks 52>; clock-names = "ipg", "per"; interrupts = <41>; }; @@ -429,7 +429,7 @@ pwm4: pwm@53fc8000 { compatible = "fsl,imx25-pwm", "fsl,imx27-pwm"; reg = <0x53fc8000 0x4000>; - clocks = <&clks 108>, <&clks 36>; + clocks = <&clks 108>, <&clks 52>; clock-names = "ipg", "per"; interrupts = <42>; }; @@ -476,7 +476,7 @@ compatible = "fsl,imx25-pwm", "fsl,imx27-pwm"; #pwm-cells = <2>; reg = <0x53fe0000 0x4000>; - clocks = <&clks 105>, <&clks 36>; + clocks = <&clks 105>, <&clks 52>; clock-names = "ipg", "per"; interrupts = <26>; }; diff --git a/arch/arm/boot/dts/imx6sx-sdb.dts b/arch/arm/boot/dts/imx6sx-sdb.dts index 8c1febd7e3f2..c108bb451337 100644 --- a/arch/arm/boot/dts/imx6sx-sdb.dts +++ b/arch/arm/boot/dts/imx6sx-sdb.dts @@ -166,12 +166,12 @@ #address-cells = <1>; #size-cells = <0>; - ethphy1: ethernet-phy@0 { - reg = <0>; + ethphy1: ethernet-phy@1 { + reg = <1>; }; - ethphy2: ethernet-phy@1 { - reg = <1>; + ethphy2: ethernet-phy@2 { + reg = <2>; }; }; }; diff --git a/arch/arm/boot/dts/rk3288-evb-rk808.dts b/arch/arm/boot/dts/rk3288-evb-rk808.dts index d8c775e6d5fe..e1d3eeb8f094 100644 --- a/arch/arm/boot/dts/rk3288-evb-rk808.dts +++ b/arch/arm/boot/dts/rk3288-evb-rk808.dts @@ -15,6 +15,13 @@ / { compatible = "rockchip,rk3288-evb-rk808", "rockchip,rk3288"; + + ext_gmac: external-gmac-clock { + compatible = "fixed-clock"; + clock-frequency = <125000000>; + clock-output-names = "ext_gmac"; + #clock-cells = <0>; + }; }; &cpu0 { @@ -152,3 +159,19 @@ }; }; }; + +&gmac { + phy-supply = <&vcc_phy>; + phy-mode = "rgmii"; + clock_in_out = "input"; + snps,reset-gpio = <&gpio4 7 0>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 1000000>; + assigned-clocks = <&cru SCLK_MAC>; + assigned-clock-parents = <&ext_gmac>; + pinctrl-names = "default"; + pinctrl-0 = <&rgmii_pins>; + tx_delay = <0x30>; + rx_delay = <0x10>; + status = "ok"; +}; diff --git a/arch/arm/boot/dts/rk3288-evb.dtsi b/arch/arm/boot/dts/rk3288-evb.dtsi index 6194d673e80b..1c08eb0ecdb9 100644 --- a/arch/arm/boot/dts/rk3288-evb.dtsi +++ b/arch/arm/boot/dts/rk3288-evb.dtsi @@ -90,6 +90,19 @@ regulator-always-on; regulator-boot-on; }; + + vcc_phy: vcc-phy-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <ð_phy_pwr>; + regulator-name = "vcc_phy"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; }; &emmc { @@ -208,6 +221,12 @@ rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>; }; }; + + eth_phy { + eth_phy_pwr: eth-phy-pwr { + rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; }; &usb_host0_ehci { diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index fd19f00784bd..910dcad2088a 100644 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -380,6 +380,22 @@ status = "disabled"; }; + gmac: ethernet@ff290000 { + compatible = "rockchip,rk3288-gmac"; + reg = <0xff290000 0x10000>; + interrupts = ; + interrupt-names = "macirq"; + rockchip,grf = <&grf>; + clocks = <&cru SCLK_MAC>, + <&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>, + <&cru SCLK_MACREF>, <&cru SCLK_MACREF_OUT>, + <&cru ACLK_GMAC>, <&cru PCLK_GMAC>; + clock-names = "stmmaceth", + "mac_clk_rx", "mac_clk_tx", + "clk_mac_ref", "clk_mac_refout", + "aclk_mac", "pclk_mac"; + }; + usb_host0_ehci: usb@ff500000 { compatible = "generic-ehci"; reg = <0xff500000 0x100>; @@ -725,6 +741,11 @@ bias-disable; }; + pcfg_pull_none_12ma: pcfg-pull-none-12ma { + bias-disable; + drive-strength = <12>; + }; + i2c0 { i2c0_xfer: i2c0-xfer { rockchip,pins = <0 15 RK_FUNC_1 &pcfg_pull_none>, @@ -1068,5 +1089,38 @@ rockchip,pins = <7 23 3 &pcfg_pull_none>; }; }; + + gmac { + rgmii_pins: rgmii-pins { + rockchip,pins = <3 30 3 &pcfg_pull_none>, + <3 31 3 &pcfg_pull_none>, + <3 26 3 &pcfg_pull_none>, + <3 27 3 &pcfg_pull_none>, + <3 28 3 &pcfg_pull_none_12ma>, + <3 29 3 &pcfg_pull_none_12ma>, + <3 24 3 &pcfg_pull_none_12ma>, + <3 25 3 &pcfg_pull_none_12ma>, + <4 0 3 &pcfg_pull_none>, + <4 5 3 &pcfg_pull_none>, + <4 6 3 &pcfg_pull_none>, + <4 9 3 &pcfg_pull_none_12ma>, + <4 4 3 &pcfg_pull_none_12ma>, + <4 1 3 &pcfg_pull_none>, + <4 3 3 &pcfg_pull_none>; + }; + + rmii_pins: rmii-pins { + rockchip,pins = <3 30 3 &pcfg_pull_none>, + <3 31 3 &pcfg_pull_none>, + <3 28 3 &pcfg_pull_none>, + <3 29 3 &pcfg_pull_none>, + <4 0 3 &pcfg_pull_none>, + <4 5 3 &pcfg_pull_none>, + <4 4 3 &pcfg_pull_none>, + <4 1 3 &pcfg_pull_none>, + <4 2 3 &pcfg_pull_none>, + <4 3 3 &pcfg_pull_none>; + }; + }; }; }; diff --git a/arch/arm/boot/dts/stih407-family.dtsi b/arch/arm/boot/dts/stih407-family.dtsi index 3e31d32133b8..d4a8f843cdc8 100644 --- a/arch/arm/boot/dts/stih407-family.dtsi +++ b/arch/arm/boot/dts/stih407-family.dtsi @@ -274,5 +274,14 @@ status = "disabled"; }; + + usb2_picophy0: phy1 { + compatible = "st,stih407-usb2-phy"; + #phy-cells = <0>; + st,syscfg = <&syscfg_core 0x100 0xf4>; + resets = <&softreset STIH407_PICOPHY_SOFTRESET>, + <&picophyreset STIH407_PICOPHY0_RESET>; + reset-names = "global", "port"; + }; }; }; diff --git a/arch/arm/boot/dts/stih410.dtsi b/arch/arm/boot/dts/stih410.dtsi index c05627eb717d..37995f4739d2 100644 --- a/arch/arm/boot/dts/stih410.dtsi +++ b/arch/arm/boot/dts/stih410.dtsi @@ -10,5 +10,75 @@ #include "stih407-family.dtsi" #include "stih410-pinctrl.dtsi" / { + soc { + usb2_picophy1: phy2 { + compatible = "st,stih407-usb2-phy"; + #phy-cells = <0>; + st,syscfg = <&syscfg_core 0xf8 0xf4>; + resets = <&softreset STIH407_PICOPHY_SOFTRESET>, + <&picophyreset STIH407_PICOPHY0_RESET>; + reset-names = "global", "port"; + }; + usb2_picophy2: phy3 { + compatible = "st,stih407-usb2-phy"; + #phy-cells = <0>; + st,syscfg = <&syscfg_core 0xfc 0xf4>; + resets = <&softreset STIH407_PICOPHY_SOFTRESET>, + <&picophyreset STIH407_PICOPHY1_RESET>; + reset-names = "global", "port"; + }; + + ohci0: usb@9a03c00 { + compatible = "st,st-ohci-300x"; + reg = <0x9a03c00 0x100>; + interrupts = ; + clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>; + resets = <&powerdown STIH407_USB2_PORT0_POWERDOWN>, + <&softreset STIH407_USB2_PORT0_SOFTRESET>; + reset-names = "power", "softreset"; + phys = <&usb2_picophy1>; + phy-names = "usb"; + }; + + ehci0: usb@9a03e00 { + compatible = "st,st-ehci-300x"; + reg = <0x9a03e00 0x100>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb0>; + clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>; + resets = <&powerdown STIH407_USB2_PORT0_POWERDOWN>, + <&softreset STIH407_USB2_PORT0_SOFTRESET>; + reset-names = "power", "softreset"; + phys = <&usb2_picophy1>; + phy-names = "usb"; + }; + + ohci1: usb@9a83c00 { + compatible = "st,st-ohci-300x"; + reg = <0x9a83c00 0x100>; + interrupts = ; + clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>; + resets = <&powerdown STIH407_USB2_PORT1_POWERDOWN>, + <&softreset STIH407_USB2_PORT1_SOFTRESET>; + reset-names = "power", "softreset"; + phys = <&usb2_picophy2>; + phy-names = "usb"; + }; + + ehci1: usb@9a83e00 { + compatible = "st,st-ehci-300x"; + reg = <0x9a83e00 0x100>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb1>; + clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>; + resets = <&powerdown STIH407_USB2_PORT1_POWERDOWN>, + <&softreset STIH407_USB2_PORT1_SOFTRESET>; + reset-names = "power", "softreset"; + phys = <&usb2_picophy2>; + phy-names = "usb"; + }; + }; }; diff --git a/arch/arm/boot/dts/stih415.dtsi b/arch/arm/boot/dts/stih415.dtsi index 9198c12765ea..19b019b5f30e 100644 --- a/arch/arm/boot/dts/stih415.dtsi +++ b/arch/arm/boot/dts/stih415.dtsi @@ -153,8 +153,8 @@ compatible = "st,stih415-dwmac", "snps,dwmac", "snps,dwmac-3.610"; status = "disabled"; - reg = <0xfe810000 0x8000>, <0x148 0x4>; - reg-names = "stmmaceth", "sti-ethconf"; + reg = <0xfe810000 0x8000>; + reg-names = "stmmaceth"; interrupts = <0 147 0>, <0 148 0>, <0 149 0>; interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; @@ -165,7 +165,7 @@ snps,mixed-burst; snps,force_sf_dma_mode; - st,syscon = <&syscfg_rear>; + st,syscon = <&syscfg_rear 0x148>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_mii0>; @@ -177,8 +177,8 @@ device_type = "network"; compatible = "st,stih415-dwmac", "snps,dwmac", "snps,dwmac-3.610"; status = "disabled"; - reg = <0xfef08000 0x8000>, <0x74 0x4>; - reg-names = "stmmaceth", "sti-ethconf"; + reg = <0xfef08000 0x8000>; + reg-names = "stmmaceth"; interrupts = <0 150 0>, <0 151 0>, <0 152 0>; interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; @@ -186,7 +186,7 @@ snps,mixed-burst; snps,force_sf_dma_mode; - st,syscon = <&syscfg_sbc>; + st,syscon = <&syscfg_sbc 0x74>; resets = <&softreset STIH415_ETH1_SOFTRESET>; reset-names = "stmmaceth"; diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi index fad9073ddeed..ea28ebadab1a 100644 --- a/arch/arm/boot/dts/stih416.dtsi +++ b/arch/arm/boot/dts/stih416.dtsi @@ -163,8 +163,8 @@ device_type = "network"; compatible = "st,stih416-dwmac", "snps,dwmac", "snps,dwmac-3.710"; status = "disabled"; - reg = <0xfe810000 0x8000>, <0x8bc 0x4>; - reg-names = "stmmaceth", "sti-ethconf"; + reg = <0xfe810000 0x8000>; + reg-names = "stmmaceth"; interrupts = <0 133 0>, <0 134 0>, <0 135 0>; interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; @@ -172,7 +172,7 @@ snps,pbl = <32>; snps,mixed-burst; - st,syscon = <&syscfg_rear>; + st,syscon = <&syscfg_rear 0x8bc>; resets = <&softreset STIH416_ETH0_SOFTRESET>; reset-names = "stmmaceth"; pinctrl-names = "default"; @@ -185,15 +185,15 @@ device_type = "network"; compatible = "st,stih416-dwmac", "snps,dwmac", "snps,dwmac-3.710"; status = "disabled"; - reg = <0xfef08000 0x8000>, <0x7f0 0x4>; - reg-names = "stmmaceth", "sti-ethconf"; + reg = <0xfef08000 0x8000>; + reg-names = "stmmaceth"; interrupts = <0 136 0>, <0 137 0>, <0 138 0>; interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; snps,pbl = <32>; snps,mixed-burst; - st,syscon = <&syscfg_sbc>; + st,syscon = <&syscfg_sbc 0x7f0>; resets = <&softreset STIH416_ETH1_SOFTRESET>; reset-names = "stmmaceth"; @@ -283,21 +283,21 @@ miphy365x_phy: phy@fe382000 { compatible = "st,miphy365x-phy"; - st,syscfg = <&syscfg_rear>; + st,syscfg = <&syscfg_rear 0x824 0x828>; #address-cells = <1>; #size-cells = <1>; ranges; phy_port0: port@fe382000 { #phy-cells = <1>; - reg = <0xfe382000 0x100>, <0xfe394000 0x100>, <0x824 0x4>; - reg-names = "sata", "pcie", "syscfg"; + reg = <0xfe382000 0x100>, <0xfe394000 0x100>; + reg-names = "sata", "pcie"; }; phy_port1: port@fe38a000 { #phy-cells = <1>; - reg = <0xfe38a000 0x100>, <0xfe804000 0x100>, <0x828 0x4>; - reg-names = "sata", "pcie", "syscfg"; + reg = <0xfe38a000 0x100>, <0xfe804000 0x100>; + reg-names = "sata", "pcie"; }; }; diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi index 7b4099fcf817..d5c4669224b1 100644 --- a/arch/arm/boot/dts/sun4i-a10.dtsi +++ b/arch/arm/boot/dts/sun4i-a10.dtsi @@ -17,14 +17,6 @@ aliases { ethernet0 = &emac; - serial0 = &uart0; - serial1 = &uart1; - serial2 = &uart2; - serial3 = &uart3; - serial4 = &uart4; - serial5 = &uart5; - serial6 = &uart6; - serial7 = &uart7; }; chosen { @@ -39,6 +31,14 @@ <&ahb_gates 44>; status = "disabled"; }; + + framebuffer@1 { + compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; + allwinner,pipeline = "de_fe0-de_be0-lcd0-hdmi"; + clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>, + <&ahb_gates 44>, <&ahb_gates 46>; + status = "disabled"; + }; }; cpus { @@ -438,8 +438,8 @@ reg-names = "phy_ctrl", "pmu1", "pmu2"; clocks = <&usb_clk 8>; clock-names = "usb_phy"; - resets = <&usb_clk 1>, <&usb_clk 2>; - reset-names = "usb1_reset", "usb2_reset"; + resets = <&usb_clk 0>, <&usb_clk 1>, <&usb_clk 2>; + reset-names = "usb0_reset", "usb1_reset", "usb2_reset"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts index fe3c559ca6a8..bfa742817690 100644 --- a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts +++ b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts @@ -55,6 +55,12 @@ model = "Olimex A10s-Olinuxino Micro"; compatible = "olimex,a10s-olinuxino-micro", "allwinner,sun5i-a10s"; + aliases { + serial0 = &uart0; + serial1 = &uart2; + serial2 = &uart3; + }; + soc@01c00000 { emac: ethernet@01c0b000 { pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi index 1b76667f3182..2e7d8263799d 100644 --- a/arch/arm/boot/dts/sun5i-a10s.dtsi +++ b/arch/arm/boot/dts/sun5i-a10s.dtsi @@ -18,10 +18,6 @@ aliases { ethernet0 = &emac; - serial0 = &uart0; - serial1 = &uart1; - serial2 = &uart2; - serial3 = &uart3; }; chosen { @@ -390,8 +386,8 @@ reg-names = "phy_ctrl", "pmu1"; clocks = <&usb_clk 8>; clock-names = "usb_phy"; - resets = <&usb_clk 1>; - reset-names = "usb1_reset"; + resets = <&usb_clk 0>, <&usb_clk 1>; + reset-names = "usb0_reset", "usb1_reset"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts b/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts index eeed1f236ee8..c7be3abd9fcc 100644 --- a/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts +++ b/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts @@ -53,6 +53,10 @@ model = "HSG H702"; compatible = "hsg,h702", "allwinner,sun5i-a13"; + aliases { + serial0 = &uart1; + }; + soc@01c00000 { mmc0: mmc@01c0f000 { pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts index 916ee8bb826f..3decefb3c37a 100644 --- a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts +++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts @@ -54,6 +54,10 @@ model = "Olimex A13-Olinuxino Micro"; compatible = "olimex,a13-olinuxino-micro", "allwinner,sun5i-a13"; + aliases { + serial0 = &uart1; + }; + soc@01c00000 { mmc0: mmc@01c0f000 { pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts index e31d291d14cb..b421f7fa197b 100644 --- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts +++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts @@ -55,6 +55,10 @@ model = "Olimex A13-Olinuxino"; compatible = "olimex,a13-olinuxino", "allwinner,sun5i-a13"; + aliases { + serial0 = &uart1; + }; + soc@01c00000 { mmc0: mmc@01c0f000 { pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi index c35217ea1f64..c556688f8b8b 100644 --- a/arch/arm/boot/dts/sun5i-a13.dtsi +++ b/arch/arm/boot/dts/sun5i-a13.dtsi @@ -16,11 +16,6 @@ / { interrupt-parent = <&intc>; - aliases { - serial0 = &uart1; - serial1 = &uart3; - }; - cpus { #address-cells = <1>; #size-cells = <0>; @@ -349,8 +344,8 @@ reg-names = "phy_ctrl", "pmu1"; clocks = <&usb_clk 8>; clock-names = "usb_phy"; - resets = <&usb_clk 1>; - reset-names = "usb1_reset"; + resets = <&usb_clk 0>, <&usb_clk 1>; + reset-names = "usb0_reset", "usb1_reset"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi index f47156b6572b..1e7e7bcf8307 100644 --- a/arch/arm/boot/dts/sun6i-a31.dtsi +++ b/arch/arm/boot/dts/sun6i-a31.dtsi @@ -53,12 +53,6 @@ interrupt-parent = <&gic>; aliases { - serial0 = &uart0; - serial1 = &uart1; - serial2 = &uart2; - serial3 = &uart3; - serial4 = &uart4; - serial5 = &uart5; ethernet0 = &gmac; }; diff --git a/arch/arm/boot/dts/sun7i-a20-bananapi.dts b/arch/arm/boot/dts/sun7i-a20-bananapi.dts index 1cf1214cc068..bd7b15add697 100644 --- a/arch/arm/boot/dts/sun7i-a20-bananapi.dts +++ b/arch/arm/boot/dts/sun7i-a20-bananapi.dts @@ -55,6 +55,12 @@ model = "LeMaker Banana Pi"; compatible = "lemaker,bananapi", "allwinner,sun7i-a20"; + aliases { + serial0 = &uart0; + serial1 = &uart3; + serial2 = &uart7; + }; + soc@01c00000 { spi0: spi@01c05000 { pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/sun7i-a20-hummingbird.dts b/arch/arm/boot/dts/sun7i-a20-hummingbird.dts index 0e4bfa3b2b85..0bcefcbbb756 100644 --- a/arch/arm/boot/dts/sun7i-a20-hummingbird.dts +++ b/arch/arm/boot/dts/sun7i-a20-hummingbird.dts @@ -19,6 +19,14 @@ model = "Merrii A20 Hummingbird"; compatible = "merrii,a20-hummingbird", "allwinner,sun7i-a20"; + aliases { + serial0 = &uart0; + serial1 = &uart2; + serial2 = &uart3; + serial3 = &uart4; + serial4 = &uart5; + }; + soc@01c00000 { mmc0: mmc@01c0f000 { pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts index 9d669cdf031d..66cc77707198 100644 --- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts +++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts @@ -20,6 +20,9 @@ compatible = "olimex,a20-olinuxino-micro", "allwinner,sun7i-a20"; aliases { + serial0 = &uart0; + serial1 = &uart6; + serial2 = &uart7; spi0 = &spi1; spi1 = &spi2; }; diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index e21ce5992d56..89749ce34a84 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -54,14 +54,6 @@ aliases { ethernet0 = &gmac; - serial0 = &uart0; - serial1 = &uart1; - serial2 = &uart2; - serial3 = &uart3; - serial4 = &uart4; - serial5 = &uart5; - serial6 = &uart6; - serial7 = &uart7; }; chosen { diff --git a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts index 7f2117ce6985..32ad80804dbb 100644 --- a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts +++ b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts @@ -55,6 +55,10 @@ model = "Ippo Q8H Dual Core Tablet (v5)"; compatible = "ippo,q8h-v5", "allwinner,sun8i-a23"; + aliases { + serial0 = &r_uart; + }; + chosen { bootargs = "earlyprintk console=ttyS0,115200"; }; diff --git a/arch/arm/boot/dts/sun8i-a23.dtsi b/arch/arm/boot/dts/sun8i-a23.dtsi index 0746cd1024d7..86584fcf5e32 100644 --- a/arch/arm/boot/dts/sun8i-a23.dtsi +++ b/arch/arm/boot/dts/sun8i-a23.dtsi @@ -52,15 +52,6 @@ / { interrupt-parent = <&gic>; - aliases { - serial0 = &uart0; - serial1 = &uart1; - serial2 = &uart2; - serial3 = &uart3; - serial4 = &uart4; - serial5 = &r_uart; - }; - cpus { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts index 506948f582ee..11ec71072e81 100644 --- a/arch/arm/boot/dts/sun9i-a80-optimus.dts +++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts @@ -54,6 +54,11 @@ model = "Merrii A80 Optimus Board"; compatible = "merrii,a80-optimus", "allwinner,sun9i-a80"; + aliases { + serial0 = &uart0; + serial1 = &uart4; + }; + chosen { bootargs = "earlyprintk console=ttyS0,115200"; }; diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi index 494714f67b57..9ef4438206a9 100644 --- a/arch/arm/boot/dts/sun9i-a80.dtsi +++ b/arch/arm/boot/dts/sun9i-a80.dtsi @@ -52,16 +52,6 @@ / { interrupt-parent = <&gic>; - aliases { - serial0 = &uart0; - serial1 = &uart1; - serial2 = &uart2; - serial3 = &uart3; - serial4 = &uart4; - serial5 = &uart5; - serial6 = &r_uart; - }; - cpus { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts index ea282c7c0ca5..e2fed2712249 100644 --- a/arch/arm/boot/dts/tegra20-seaboard.dts +++ b/arch/arm/boot/dts/tegra20-seaboard.dts @@ -406,7 +406,7 @@ clock-frequency = <400000>; magnetometer@c { - compatible = "ak,ak8975"; + compatible = "asahi-kasei,ak8975"; reg = <0xc>; interrupt-parent = <&gpio>; interrupts = ; diff --git a/arch/arm/boot/dts/versatile-pb.dts b/arch/arm/boot/dts/versatile-pb.dts index e36c1e82fea7..b83137f66034 100644 --- a/arch/arm/boot/dts/versatile-pb.dts +++ b/arch/arm/boot/dts/versatile-pb.dts @@ -29,6 +29,43 @@ clock-names = "apb_pclk"; }; + pci-controller@10001000 { + compatible = "arm,versatile-pci"; + device_type = "pci"; + reg = <0x10001000 0x1000 + 0x41000000 0x10000 + 0x42000000 0x100000>; + bus-range = <0 0xff>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + ranges = <0x01000000 0 0x00000000 0x43000000 0 0x00010000 /* downstream I/O */ + 0x02000000 0 0x50000000 0x50000000 0 0x10000000 /* non-prefetchable memory */ + 0x42000000 0 0x60000000 0x60000000 0 0x10000000>; /* prefetchable memory */ + + interrupt-map-mask = <0x1800 0 0 7>; + interrupt-map = <0x1800 0 0 1 &sic 28 + 0x1800 0 0 2 &sic 29 + 0x1800 0 0 3 &sic 30 + 0x1800 0 0 4 &sic 27 + + 0x1000 0 0 1 &sic 27 + 0x1000 0 0 2 &sic 28 + 0x1000 0 0 3 &sic 29 + 0x1000 0 0 4 &sic 30 + + 0x0800 0 0 1 &sic 30 + 0x0800 0 0 2 &sic 27 + 0x0800 0 0 3 &sic 28 + 0x0800 0 0 4 &sic 29 + + 0x0000 0 0 1 &sic 29 + 0x0000 0 0 2 &sic 30 + 0x0000 0 0 3 &sic 27 + 0x0000 0 0 4 &sic 28>; + }; + fpga { uart@9000 { compatible = "arm,pl011", "arm,primecell"; diff --git a/arch/arm/configs/iop32x_defconfig b/arch/arm/configs/iop32x_defconfig index 4f2ec3ac138e..c3058da631da 100644 --- a/arch/arm/configs/iop32x_defconfig +++ b/arch/arm/configs/iop32x_defconfig @@ -106,6 +106,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_UART_8250=y CONFIG_KEYS=y CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_CRYPTO_NULL=y diff --git a/arch/arm/configs/iop33x_defconfig b/arch/arm/configs/iop33x_defconfig index aa36128abca2..713faeee8cf4 100644 --- a/arch/arm/configs/iop33x_defconfig +++ b/arch/arm/configs/iop33x_defconfig @@ -87,5 +87,6 @@ CONFIG_DEBUG_KERNEL=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_DEBUG_USER=y CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_UART_8250=y # CONFIG_CRYPTO_ANSI_CPRNG is not set # CONFIG_CRC32 is not set diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig index 1af665e847d1..24636cfdf6df 100644 --- a/arch/arm/configs/ixp4xx_defconfig +++ b/arch/arm/configs/ixp4xx_defconfig @@ -202,3 +202,4 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_UART_8250=y diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig index 9f56ca3985ae..c100b7df5441 100644 --- a/arch/arm/configs/lpc32xx_defconfig +++ b/arch/arm/configs/lpc32xx_defconfig @@ -204,6 +204,7 @@ CONFIG_DEBUG_INFO=y # CONFIG_FTRACE is not set # CONFIG_ARM_UNWIND is not set CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_UART_8250=y CONFIG_EARLY_PRINTK=y CONFIG_CRYPTO_ANSI_CPRNG=y # CONFIG_CRYPTO_HW is not set diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index bc393b7e5ece..444685c44055 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -456,6 +456,7 @@ CONFIG_OMAP_USB2=y CONFIG_TI_PIPE3=y CONFIG_PHY_MIPHY365X=y CONFIG_PHY_STIH41X_USB=y +CONFIG_PHY_STIH407_USB=y CONFIG_PHY_SUN4I_USB=y CONFIG_EXT4_FS=y CONFIG_AUTOFS4_FS=y diff --git a/arch/arm/configs/mv78xx0_defconfig b/arch/arm/configs/mv78xx0_defconfig index 0dae1c1f007a..85d10d2e3d66 100644 --- a/arch/arm/configs/mv78xx0_defconfig +++ b/arch/arm/configs/mv78xx0_defconfig @@ -132,6 +132,7 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_UART_8250=y CONFIG_CRYPTO_CBC=m CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m diff --git a/arch/arm/configs/orion5x_defconfig b/arch/arm/configs/orion5x_defconfig index 952430d9e2d9..855143fac6bd 100644 --- a/arch/arm/configs/orion5x_defconfig +++ b/arch/arm/configs/orion5x_defconfig @@ -156,6 +156,7 @@ CONFIG_LATENCYTOP=y # CONFIG_FTRACE is not set CONFIG_DEBUG_USER=y CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_UART_8250=y CONFIG_CRYPTO_CBC=m CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m diff --git a/arch/arm/configs/rpc_defconfig b/arch/arm/configs/rpc_defconfig index 00515ef9782d..89631795a915 100644 --- a/arch/arm/configs/rpc_defconfig +++ b/arch/arm/configs/rpc_defconfig @@ -131,3 +131,4 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_UART_8250=y diff --git a/arch/arm/include/asm/bitrev.h b/arch/arm/include/asm/bitrev.h new file mode 100644 index 000000000000..ec291c350ea3 --- /dev/null +++ b/arch/arm/include/asm/bitrev.h @@ -0,0 +1,20 @@ +#ifndef __ASM_BITREV_H +#define __ASM_BITREV_H + +static __always_inline __attribute_const__ u32 __arch_bitrev32(u32 x) +{ + __asm__ ("rbit %0, %1" : "=r" (x) : "r" (x)); + return x; +} + +static __always_inline __attribute_const__ u16 __arch_bitrev16(u16 x) +{ + return __arch_bitrev32((u32)x) >> 16; +} + +static __always_inline __attribute_const__ u8 __arch_bitrev8(u8 x) +{ + return __arch_bitrev32((u32)x) >> 24; +} + +#endif diff --git a/arch/arm/include/asm/compiler.h b/arch/arm/include/asm/compiler.h index 8155db2f7fa1..29fe85e59439 100644 --- a/arch/arm/include/asm/compiler.h +++ b/arch/arm/include/asm/compiler.h @@ -8,8 +8,21 @@ * This string is meant to be concatenated with the inline asm string and * will cause compilation to stop on mismatch. * (for details, see gcc PR 15089) + * For compatibility with clang, we have to specifically take the equivalence + * of 'r11' <-> 'fp' and 'r12' <-> 'ip' into account as well. */ -#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t" +#define __asmeq(x, y) \ + ".ifnc " x "," y "; " \ + ".ifnc " x y ",fpr11; " \ + ".ifnc " x y ",r11fp; " \ + ".ifnc " x y ",ipr12; " \ + ".ifnc " x y ",r12ip; " \ + ".err; " \ + ".endif; " \ + ".endif; " \ + ".endif; " \ + ".endif; " \ + ".endif\n\t" #endif /* __ASM_ARM_COMPILER_H */ diff --git a/arch/arm/kernel/insn.h b/arch/arm/include/asm/insn.h similarity index 100% rename from arch/arm/kernel/insn.h rename to arch/arm/include/asm/insn.h diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index 49fa0dfaad33..3ea9be559726 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h @@ -22,7 +22,6 @@ #define __ARCH_WANT_KPROBES_INSN_SLOT #define MAX_INSN_SIZE 2 -#define MAX_STACK_SIZE 64 /* 32 would probably be OK */ #define flush_insn_slot(p) do { } while (0) #define kretprobe_blacklist_size 0 @@ -51,5 +50,37 @@ int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr); int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data); +/* optinsn template addresses */ +extern __visible kprobe_opcode_t optprobe_template_entry; +extern __visible kprobe_opcode_t optprobe_template_val; +extern __visible kprobe_opcode_t optprobe_template_call; +extern __visible kprobe_opcode_t optprobe_template_end; +extern __visible kprobe_opcode_t optprobe_template_sub_sp; +extern __visible kprobe_opcode_t optprobe_template_add_sp; +extern __visible kprobe_opcode_t optprobe_template_restore_begin; +extern __visible kprobe_opcode_t optprobe_template_restore_orig_insn; +extern __visible kprobe_opcode_t optprobe_template_restore_end; + +#define MAX_OPTIMIZED_LENGTH 4 +#define MAX_OPTINSN_SIZE \ + ((unsigned long)&optprobe_template_end - \ + (unsigned long)&optprobe_template_entry) +#define RELATIVEJUMP_SIZE 4 + +struct arch_optimized_insn { + /* + * copy of the original instructions. + * Different from x86, ARM kprobe_opcode_t is u32. + */ +#define MAX_COPIED_INSN DIV_ROUND_UP(RELATIVEJUMP_SIZE, sizeof(kprobe_opcode_t)) + kprobe_opcode_t copied_insn[MAX_COPIED_INSN]; + /* detour code buffer */ + kprobe_opcode_t *insn; + /* + * We always copy one instruction on ARM, + * so size will always be 4, and unlike x86, there is no + * need for a size field. + */ +}; #endif /* _ARM_KPROBES_H */ diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h index 66ce17655bb9..7b0152321b20 100644 --- a/arch/arm/include/asm/kvm_emulate.h +++ b/arch/arm/include/asm/kvm_emulate.h @@ -38,6 +38,16 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu) vcpu->arch.hcr = HCR_GUEST_MASK; } +static inline unsigned long vcpu_get_hcr(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.hcr; +} + +static inline void vcpu_set_hcr(struct kvm_vcpu *vcpu, unsigned long hcr) +{ + vcpu->arch.hcr = hcr; +} + static inline bool vcpu_mode_is_32bit(struct kvm_vcpu *vcpu) { return 1; diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 254e0650e48b..04b4ea0b550a 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -125,9 +125,6 @@ struct kvm_vcpu_arch { * Anything that is not used directly from assembly code goes * here. */ - /* dcache set/way operation pending */ - int last_pcpu; - cpumask_t require_dcache_flush; /* Don't run the guest on this vcpu */ bool pause; diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index 63e0ecc04901..1bca8f8af442 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h @@ -44,6 +44,7 @@ #ifndef __ASSEMBLY__ +#include #include #include @@ -161,13 +162,10 @@ static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu) return (vcpu->arch.cp15[c1_SCTLR] & 0b101) == 0b101; } -static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva, - unsigned long size, - bool ipa_uncached) +static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn, + unsigned long size, + bool ipa_uncached) { - if (!vcpu_has_cache_enabled(vcpu) || ipa_uncached) - kvm_flush_dcache_to_poc((void *)hva, size); - /* * If we are going to insert an instruction page and the icache is * either VIPT or PIPT, there is a potential problem where the host @@ -179,18 +177,77 @@ static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva, * * VIVT caches are tagged using both the ASID and the VMID and doesn't * need any kind of flushing (DDI 0406C.b - Page B3-1392). + * + * We need to do this through a kernel mapping (using the + * user-space mapping has proved to be the wrong + * solution). For that, we need to kmap one page at a time, + * and iterate over the range. */ - if (icache_is_pipt()) { - __cpuc_coherent_user_range(hva, hva + size); - } else if (!icache_is_vivt_asid_tagged()) { + + bool need_flush = !vcpu_has_cache_enabled(vcpu) || ipa_uncached; + + VM_BUG_ON(size & PAGE_MASK); + + if (!need_flush && !icache_is_pipt()) + goto vipt_cache; + + while (size) { + void *va = kmap_atomic_pfn(pfn); + + if (need_flush) + kvm_flush_dcache_to_poc(va, PAGE_SIZE); + + if (icache_is_pipt()) + __cpuc_coherent_user_range((unsigned long)va, + (unsigned long)va + PAGE_SIZE); + + size -= PAGE_SIZE; + pfn++; + + kunmap_atomic(va); + } + +vipt_cache: + if (!icache_is_pipt() && !icache_is_vivt_asid_tagged()) { /* any kind of VIPT cache */ __flush_icache_all(); } } +static inline void __kvm_flush_dcache_pte(pte_t pte) +{ + void *va = kmap_atomic(pte_page(pte)); + + kvm_flush_dcache_to_poc(va, PAGE_SIZE); + + kunmap_atomic(va); +} + +static inline void __kvm_flush_dcache_pmd(pmd_t pmd) +{ + unsigned long size = PMD_SIZE; + pfn_t pfn = pmd_pfn(pmd); + + while (size) { + void *va = kmap_atomic_pfn(pfn); + + kvm_flush_dcache_to_poc(va, PAGE_SIZE); + + pfn++; + size -= PAGE_SIZE; + + kunmap_atomic(va); + } +} + +static inline void __kvm_flush_dcache_pud(pud_t pud) +{ +} + #define kvm_virt_to_phys(x) virt_to_idmap((unsigned long)(x)) -void stage2_flush_vm(struct kvm *kvm); +void kvm_set_way_flush(struct kvm_vcpu *vcpu); +void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled); #endif /* !__ASSEMBLY__ */ diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h index 8292b5f81e23..28b9bb35949e 100644 --- a/arch/arm/include/asm/mach/pci.h +++ b/arch/arm/include/asm/mach/pci.h @@ -19,9 +19,6 @@ struct pci_bus; struct device; struct hw_pci { -#ifdef CONFIG_PCI_DOMAINS - int domain; -#endif #ifdef CONFIG_PCI_MSI struct msi_controller *msi_ctrl; #endif @@ -45,9 +42,6 @@ struct hw_pci { * Per-controller structure */ struct pci_sys_data { -#ifdef CONFIG_PCI_DOMAINS - int domain; -#endif #ifdef CONFIG_PCI_MSI struct msi_controller *msi_ctrl; #endif diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h index 891a56b35bcf..563b92fc2f41 100644 --- a/arch/arm/include/asm/outercache.h +++ b/arch/arm/include/asm/outercache.h @@ -23,6 +23,8 @@ #include +struct l2x0_regs; + struct outer_cache_fns { void (*inv_range)(unsigned long, unsigned long); void (*clean_range)(unsigned long, unsigned long); @@ -36,6 +38,7 @@ struct outer_cache_fns { /* This is an ARM L2C thing */ void (*write_sec)(unsigned long, unsigned); + void (*configure)(const struct l2x0_regs *); }; extern struct outer_cache_fns outer_cache; diff --git a/arch/arm/kernel/patch.h b/arch/arm/include/asm/patch.h similarity index 100% rename from arch/arm/kernel/patch.h rename to arch/arm/include/asm/patch.h diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h index 7e95d8535e24..585dc33a7a24 100644 --- a/arch/arm/include/asm/pci.h +++ b/arch/arm/include/asm/pci.h @@ -18,13 +18,6 @@ static inline int pcibios_assign_all_busses(void) } #ifdef CONFIG_PCI_DOMAINS -static inline int pci_domain_nr(struct pci_bus *bus) -{ - struct pci_sys_data *root = bus->sysdata; - - return root->domain; -} - static inline int pci_proc_domain(struct pci_bus *bus) { return pci_domain_nr(bus); diff --git a/arch/arm/include/asm/pgtable-2level.h b/arch/arm/include/asm/pgtable-2level.h index f0279411847d..bfd662e49a25 100644 --- a/arch/arm/include/asm/pgtable-2level.h +++ b/arch/arm/include/asm/pgtable-2level.h @@ -10,6 +10,8 @@ #ifndef _ASM_PGTABLE_2LEVEL_H #define _ASM_PGTABLE_2LEVEL_H +#define __PAGETABLE_PMD_FOLDED + /* * Hardware-wise, we have a two level page table structure, where the first * level has 4096 entries, and the second level has 256 entries. Each entry @@ -118,7 +120,6 @@ #define L_PTE_VALID (_AT(pteval_t, 1) << 0) /* Valid */ #define L_PTE_PRESENT (_AT(pteval_t, 1) << 0) #define L_PTE_YOUNG (_AT(pteval_t, 1) << 1) -#define L_PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !PRESENT */ #define L_PTE_DIRTY (_AT(pteval_t, 1) << 6) #define L_PTE_RDONLY (_AT(pteval_t, 1) << 7) #define L_PTE_USER (_AT(pteval_t, 1) << 8) diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h index a31ecdad4b59..18dbc82f85e5 100644 --- a/arch/arm/include/asm/pgtable-3level.h +++ b/arch/arm/include/asm/pgtable-3level.h @@ -77,7 +77,6 @@ */ #define L_PTE_VALID (_AT(pteval_t, 1) << 0) /* Valid */ #define L_PTE_PRESENT (_AT(pteval_t, 3) << 0) /* Present */ -#define L_PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !PRESENT */ #define L_PTE_USER (_AT(pteval_t, 1) << 6) /* AP[1] */ #define L_PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */ #define L_PTE_YOUNG (_AT(pteval_t, 1) << 10) /* AF */ diff --git a/arch/arm/include/asm/pgtable-nommu.h b/arch/arm/include/asm/pgtable-nommu.h index 0642228ff785..add094d09e3e 100644 --- a/arch/arm/include/asm/pgtable-nommu.h +++ b/arch/arm/include/asm/pgtable-nommu.h @@ -54,8 +54,6 @@ typedef pte_t *pte_addr_t; -static inline int pte_file(pte_t pte) { return 0; } - /* * ZERO_PAGE is a global shared page that is always zero: used * for zero-mapped memory areas etc.. @@ -87,7 +85,7 @@ extern unsigned int kobjsize(const void *objp); #define VMALLOC_START 0UL #define VMALLOC_END 0xffffffffUL -#define FIRST_USER_ADDRESS (0) +#define FIRST_USER_ADDRESS 0UL #include diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index d5cac545ba33..f40354198bad 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -318,12 +318,12 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) * * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * <--------------- offset ----------------------> < type -> 0 0 0 + * <--------------- offset ------------------------> < type -> 0 0 * - * This gives us up to 31 swap files and 64GB per swap file. Note that + * This gives us up to 31 swap files and 128GB per swap file. Note that * the offset field is always non-zero. */ -#define __SWP_TYPE_SHIFT 3 +#define __SWP_TYPE_SHIFT 2 #define __SWP_TYPE_BITS 5 #define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) #define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) @@ -342,20 +342,6 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) */ #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS) -/* - * Encode and decode a file entry. File entries are stored in the Linux - * page tables as follows: - * - * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * <----------------------- offset ------------------------> 1 0 0 - */ -#define pte_file(pte) (pte_val(pte) & L_PTE_FILE) -#define pte_to_pgoff(x) (pte_val(x) >> 3) -#define pgoff_to_pte(x) __pte(((x) << 3) | L_PTE_FILE) - -#define PTE_FILE_MAX_BITS 29 - /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ /* FIXME: this is not correct */ #define kern_addr_valid(addr) (1) diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h index 806cfe622a9e..1e5b9bb92270 100644 --- a/arch/arm/include/asm/probes.h +++ b/arch/arm/include/asm/probes.h @@ -19,6 +19,8 @@ #ifndef _ASM_PROBES_H #define _ASM_PROBES_H +#ifndef __ASSEMBLY__ + typedef u32 probes_opcode_t; struct arch_probes_insn; @@ -38,6 +40,19 @@ struct arch_probes_insn { probes_check_cc *insn_check_cc; probes_insn_singlestep_t *insn_singlestep; probes_insn_fn_t *insn_fn; + int stack_space; + unsigned long register_usage_flags; + bool kprobe_direct_exec; }; +#endif /* __ASSEMBLY__ */ + +/* + * We assume one instruction can consume at most 64 bytes stack, which is + * 'push {r0-r15}'. Instructions consume more or unknown stack space like + * 'str r0, [sp, #-80]' and 'str r0, [sp, r1]' should be prohibit to probe. + * Both kprobe and jprobe use this macro. + */ +#define MAX_STACK_SIZE 64 + #endif diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h index 68c739b3fdf4..2f7e6ff67d51 100644 --- a/arch/arm/include/asm/xen/page.h +++ b/arch/arm/include/asm/xen/page.h @@ -92,7 +92,7 @@ extern int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, struct page **pages, unsigned int count); extern int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, - struct gnttab_map_grant_ref *kmap_ops, + struct gnttab_unmap_grant_ref *kunmap_ops, struct page **pages, unsigned int count); bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn); diff --git a/arch/arm/mach-ks8695/include/mach/debug-macro.S b/arch/arm/include/debug/ks8695.S similarity index 80% rename from arch/arm/mach-ks8695/include/mach/debug-macro.S rename to arch/arm/include/debug/ks8695.S index a79e48981202..961da1f32ab3 100644 --- a/arch/arm/mach-ks8695/include/mach/debug-macro.S +++ b/arch/arm/include/debug/ks8695.S @@ -1,5 +1,5 @@ /* - * arch/arm/mach-ks8695/include/mach/debug-macro.S + * arch/arm/include/debug/ks8695.S * * Copyright (C) 2006 Ben Dooks * Copyright (C) 2006 Simtec Electronics @@ -11,8 +11,12 @@ * published by the Free Software Foundation. */ -#include -#include +#define KS8695_UART_PA 0x03ffe000 +#define KS8695_UART_VA 0xf00fe000 +#define KS8695_URTH (0x04) +#define KS8695_URLS (0x14) +#define URLS_URTE (1 << 6) +#define URLS_URTHRE (1 << 5) .macro addruart, rp, rv, tmp ldr \rp, =KS8695_UART_PA @ physical base address diff --git a/arch/arm/mach-netx/include/mach/debug-macro.S b/arch/arm/include/debug/netx.S similarity index 62% rename from arch/arm/mach-netx/include/mach/debug-macro.S rename to arch/arm/include/debug/netx.S index 247781e096e2..81e1b2af70f7 100644 --- a/arch/arm/mach-netx/include/mach/debug-macro.S +++ b/arch/arm/include/debug/netx.S @@ -1,5 +1,4 @@ -/* arch/arm/mach-netx/include/mach/debug-macro.S - * +/* * Debugging macro include header * * Copyright (C) 1994-1999 Russell King @@ -11,26 +10,27 @@ * */ -#include "hardware.h" +#define UART_DATA 0 +#define UART_FLAG 0x18 +#define UART_FLAG_BUSY (1 << 3) .macro addruart, rp, rv, tmp - mov \rp, #0x00000a00 - orr \rv, \rp, #io_p2v(0x00100000) @ virtual - orr \rp, \rp, #0x00100000 @ physical + ldr \rp, =CONFIG_DEBUG_UART_PHYS + ldr \rv, =CONFIG_DEBUG_UART_VIRT .endm .macro senduart,rd,rx - str \rd, [\rx, #0] + str \rd, [\rx, #UART_DATA] .endm .macro busyuart,rd,rx -1002: ldr \rd, [\rx, #0x18] - tst \rd, #(1 << 3) +1002: ldr \rd, [\rx, #UART_FLAG] + tst \rd, #UART_FLAG_BUSY bne 1002b .endm .macro waituart,rd,rx -1001: ldr \rd, [\rx, #0x18] - tst \rd, #(1 << 3) +1001: ldr \rd, [\rx, #UART_FLAG] + tst \rd, #UART_FLAG_BUSY bne 1001b .endm diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index fb2b71ebe3f2..902397dd1000 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -51,20 +51,8 @@ obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o -obj-$(CONFIG_UPROBES) += probes.o probes-arm.o uprobes.o uprobes-arm.o -obj-$(CONFIG_KPROBES) += probes.o kprobes.o kprobes-common.o patch.o -ifdef CONFIG_THUMB2_KERNEL -obj-$(CONFIG_KPROBES) += kprobes-thumb.o probes-thumb.o -else -obj-$(CONFIG_KPROBES) += kprobes-arm.o probes-arm.o -endif -obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o -test-kprobes-objs := kprobes-test.o -ifdef CONFIG_THUMB2_KERNEL -test-kprobes-objs += kprobes-test-thumb.o -else -test-kprobes-objs += kprobes-test-arm.o -endif +# Main staffs in KPROBES are in arch/arm/probes/ . +obj-$(CONFIG_KPROBES) += patch.o insn.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o obj-$(CONFIG_ARM_THUMBEE) += thumbee.o obj-$(CONFIG_KGDB) += kgdb.o patch.o diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index a4effd6d8f2f..ab19b7c03423 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -422,17 +422,16 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) static int pcibios_init_resources(int busnr, struct pci_sys_data *sys) { int ret; - struct pci_host_bridge_window *window; + struct resource_entry *window; if (list_empty(&sys->resources)) { pci_add_resource_offset(&sys->resources, &iomem_resource, sys->mem_offset); } - list_for_each_entry(window, &sys->resources, list) { + resource_list_for_each_entry(window, &sys->resources) if (resource_type(window->res) == IORESOURCE_IO) return 0; - } sys->io_res.start = (busnr * SZ_64K) ? : pcibios_min_io; sys->io_res.end = (busnr + 1) * SZ_64K - 1; @@ -463,9 +462,6 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw, if (!sys) panic("PCI: unable to allocate sys data!"); -#ifdef CONFIG_PCI_DOMAINS - sys->domain = hw->domain; -#endif #ifdef CONFIG_PCI_MSI sys->msi_ctrl = hw->msi_ctrl; #endif diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 2f5555d307b3..672b21942fff 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -31,6 +31,7 @@ #include "entry-header.S" #include +#include /* * Interrupt handling. @@ -249,7 +250,7 @@ __und_svc: @ If a kprobe is about to simulate a "stmdb sp..." instruction, @ it obviously needs free stack space which then will belong to @ the saved context. - svc_entry 64 + svc_entry MAX_STACK_SIZE #else svc_entry #endif diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 4176df721bf0..1a0045abead7 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -253,21 +253,22 @@ .endm .macro restore_user_regs, fast = 0, offset = 0 - ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr - ldr lr, [sp, #\offset + S_PC]! @ get pc + mov r2, sp + ldr r1, [r2, #\offset + S_PSR] @ get calling cpsr + ldr lr, [r2, #\offset + S_PC]! @ get pc msr spsr_cxsf, r1 @ save in spsr_svc #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_32v6K) @ We must avoid clrex due to Cortex-A15 erratum #830321 - strex r1, r2, [sp] @ clear the exclusive monitor + strex r1, r2, [r2] @ clear the exclusive monitor #endif .if \fast - ldmdb sp, {r1 - lr}^ @ get calling r1 - lr + ldmdb r2, {r1 - lr}^ @ get calling r1 - lr .else - ldmdb sp, {r0 - lr}^ @ get calling r0 - lr + ldmdb r2, {r0 - lr}^ @ get calling r0 - lr .endif mov r0, r0 @ ARMv5T and earlier require a nop @ after ldm {}^ - add sp, sp, #S_FRAME_SIZE - S_PC + add sp, sp, #\offset + S_FRAME_SIZE movs pc, lr @ return & move spsr_svc into cpsr .endm diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S index 2260f1855820..8944f4991c3c 100644 --- a/arch/arm/kernel/entry-v7m.S +++ b/arch/arm/kernel/entry-v7m.S @@ -22,10 +22,12 @@ __invalid_entry: v7m_exception_entry +#ifdef CONFIG_PRINTK adr r0, strerr mrs r1, ipsr mov r2, lr bl printk +#endif mov r0, sp bl show_regs 1: b 1b diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index b8c75e45a950..709ee1d6d4df 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -20,8 +20,7 @@ #include #include #include - -#include "insn.h" +#include #ifdef CONFIG_THUMB2_KERNEL #define NOP 0xf85deb04 /* pop.w {lr} */ diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 664eee8c4a26..01963273c07a 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -346,6 +346,12 @@ __turn_mmu_on_loc: #if defined(CONFIG_SMP) .text +ENTRY(secondary_startup_arm) + .arm + THUMB( adr r9, BSYM(1f) ) @ Kernel is entered in ARM. + THUMB( bx r9 ) @ If this is a Thumb-2 kernel, + THUMB( .thumb ) @ switch to Thumb now. + THUMB(1: ) ENTRY(secondary_startup) /* * Common entry point for secondary CPUs. @@ -385,6 +391,7 @@ ENTRY(secondary_startup) THUMB( add r12, r10, #PROCINFO_INITFUNC ) THUMB( ret r12 ) ENDPROC(secondary_startup) +ENDPROC(secondary_startup_arm) /* * r6 = &secondary_data @@ -586,7 +593,7 @@ __fixup_pv_table: add r5, r5, r3 @ adjust table end address add r6, r6, r3 @ adjust __pv_phys_pfn_offset address add r7, r7, r3 @ adjust __pv_offset address - mov r0, r8, lsr #12 @ convert to PFN + mov r0, r8, lsr #PAGE_SHIFT @ convert to PFN str r0, [r6] @ save computed PHYS_OFFSET to __pv_phys_pfn_offset strcc ip, [r7, #HIGH_OFFSET] @ save to __pv_offset high bits mov r6, r3, lsr #24 @ constant for add/sub instructions diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index ad857bada96c..350f188c92d2 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -109,7 +109,8 @@ void __init init_IRQ(void) if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_CACHE_L2X0) && (machine_desc->l2c_aux_mask || machine_desc->l2c_aux_val)) { - outer_cache.write_sec = machine_desc->l2c_write_sec; + if (!outer_cache.write_sec) + outer_cache.write_sec = machine_desc->l2c_write_sec; ret = l2x0_of_init(machine_desc->l2c_aux_val, machine_desc->l2c_aux_mask); if (ret) diff --git a/arch/arm/kernel/jump_label.c b/arch/arm/kernel/jump_label.c index afeeb9ea6f43..e39cbf488cfe 100644 --- a/arch/arm/kernel/jump_label.c +++ b/arch/arm/kernel/jump_label.c @@ -1,8 +1,7 @@ #include #include - -#include "insn.h" -#include "patch.h" +#include +#include #ifdef HAVE_JUMP_LABEL diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c index 07db2f8a1b45..a6ad93c9bce3 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c @@ -14,10 +14,9 @@ #include #include +#include #include -#include "patch.h" - struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { { "r0", 4, offsetof(struct pt_regs, ARM_r0)}, diff --git a/arch/arm/kernel/patch.c b/arch/arm/kernel/patch.c index 5038960e3c55..69bda1a5707e 100644 --- a/arch/arm/kernel/patch.c +++ b/arch/arm/kernel/patch.c @@ -8,8 +8,7 @@ #include #include #include - -#include "patch.h" +#include struct patch { void *addr; diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index f7c65adaa428..557e128e4df0 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -116,8 +116,14 @@ int armpmu_event_set_period(struct perf_event *event) ret = 1; } - if (left > (s64)armpmu->max_period) - left = armpmu->max_period; + /* + * Limit the maximum period to prevent the counter value + * from overtaking the one we are about to program. In + * effect we are reducing max_period to account for + * interrupt latency (and we are being very conservative). + */ + if (left > (armpmu->max_period >> 1)) + left = armpmu->max_period >> 1; local64_set(&hwc->prev_count, (u64)-left); diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 715ae19bc7c8..e55408e96559 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -657,10 +657,13 @@ int __init arm_add_memory(u64 start, u64 size) /* * Ensure that start/size are aligned to a page boundary. - * Size is appropriately rounded down, start is rounded up. + * Size is rounded down, start is rounded up. */ - size -= start & ~PAGE_MASK; aligned_start = PAGE_ALIGN(start); + if (aligned_start > start + size) + size = 0; + else + size -= aligned_start - start; #ifndef CONFIG_ARCH_PHYS_ADDR_T_64BIT if (aligned_start > ULONG_MAX) { diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c index 2835d35234ca..9a2f882a0a2d 100644 --- a/arch/arm/kernel/suspend.c +++ b/arch/arm/kernel/suspend.c @@ -14,10 +14,6 @@ extern int __cpu_suspend(unsigned long, int (*)(unsigned long), u32 cpuid); extern void cpu_resume_mmu(void); #ifdef CONFIG_MMU -/* - * Hide the first two arguments to __cpu_suspend - these are an implementation - * detail which platform code shouldn't have to know about. - */ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) { struct mm_struct *mm = current->active_mm; diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig index 466bd299b1a8..3afee5f40f4f 100644 --- a/arch/arm/kvm/Kconfig +++ b/arch/arm/kvm/Kconfig @@ -23,6 +23,7 @@ config KVM select HAVE_KVM_CPU_RELAX_INTERCEPT select KVM_MMIO select KVM_ARM_HOST + select SRCU depends on ARM_VIRT_EXT && ARM_LPAE ---help--- Support hosting virtualized guest machines. You will also diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 2d6d91001062..0b0d58a905c4 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -281,15 +281,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) vcpu->cpu = cpu; vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state); - /* - * Check whether this vcpu requires the cache to be flushed on - * this physical CPU. This is a consequence of doing dcache - * operations by set/way on this vcpu. We do it here to be in - * a non-preemptible section. - */ - if (cpumask_test_and_clear_cpu(cpu, &vcpu->arch.require_dcache_flush)) - flush_cache_all(); /* We'd really want v7_flush_dcache_all() */ - kvm_arm_set_running_vcpu(vcpu); } @@ -541,7 +532,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) ret = kvm_call_hyp(__kvm_vcpu_run, vcpu); vcpu->mode = OUTSIDE_GUEST_MODE; - vcpu->arch.last_pcpu = smp_processor_id(); kvm_guest_exit(); trace_kvm_exit(*vcpu_pc(vcpu)); /* diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c index 7928dbdf2102..f3d88dc388bc 100644 --- a/arch/arm/kvm/coproc.c +++ b/arch/arm/kvm/coproc.c @@ -189,82 +189,40 @@ static bool access_l2ectlr(struct kvm_vcpu *vcpu, return true; } -/* See note at ARM ARM B1.14.4 */ +/* + * See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized). + */ static bool access_dcsw(struct kvm_vcpu *vcpu, const struct coproc_params *p, const struct coproc_reg *r) { - unsigned long val; - int cpu; - if (!p->is_write) return read_from_write_only(vcpu, p); - cpu = get_cpu(); - - cpumask_setall(&vcpu->arch.require_dcache_flush); - cpumask_clear_cpu(cpu, &vcpu->arch.require_dcache_flush); - - /* If we were already preempted, take the long way around */ - if (cpu != vcpu->arch.last_pcpu) { - flush_cache_all(); - goto done; - } - - val = *vcpu_reg(vcpu, p->Rt1); - - switch (p->CRm) { - case 6: /* Upgrade DCISW to DCCISW, as per HCR.SWIO */ - case 14: /* DCCISW */ - asm volatile("mcr p15, 0, %0, c7, c14, 2" : : "r" (val)); - break; - - case 10: /* DCCSW */ - asm volatile("mcr p15, 0, %0, c7, c10, 2" : : "r" (val)); - break; - } - -done: - put_cpu(); - + kvm_set_way_flush(vcpu); return true; } /* * Generic accessor for VM registers. Only called as long as HCR_TVM - * is set. + * is set. If the guest enables the MMU, we stop trapping the VM + * sys_regs and leave it in complete control of the caches. + * + * Used by the cpu-specific code. */ -static bool access_vm_reg(struct kvm_vcpu *vcpu, - const struct coproc_params *p, - const struct coproc_reg *r) +bool access_vm_reg(struct kvm_vcpu *vcpu, + const struct coproc_params *p, + const struct coproc_reg *r) { + bool was_enabled = vcpu_has_cache_enabled(vcpu); + BUG_ON(!p->is_write); vcpu->arch.cp15[r->reg] = *vcpu_reg(vcpu, p->Rt1); if (p->is_64bit) vcpu->arch.cp15[r->reg + 1] = *vcpu_reg(vcpu, p->Rt2); - return true; -} - -/* - * SCTLR accessor. Only called as long as HCR_TVM is set. If the - * guest enables the MMU, we stop trapping the VM sys_regs and leave - * it in complete control of the caches. - * - * Used by the cpu-specific code. - */ -bool access_sctlr(struct kvm_vcpu *vcpu, - const struct coproc_params *p, - const struct coproc_reg *r) -{ - access_vm_reg(vcpu, p, r); - - if (vcpu_has_cache_enabled(vcpu)) { /* MMU+Caches enabled? */ - vcpu->arch.hcr &= ~HCR_TVM; - stage2_flush_vm(vcpu->kvm); - } - + kvm_toggle_cache(vcpu, was_enabled); return true; } diff --git a/arch/arm/kvm/coproc.h b/arch/arm/kvm/coproc.h index 1a44bbe39643..88d24a3a9778 100644 --- a/arch/arm/kvm/coproc.h +++ b/arch/arm/kvm/coproc.h @@ -153,8 +153,8 @@ static inline int cmp_reg(const struct coproc_reg *i1, #define is64 .is_64 = true #define is32 .is_64 = false -bool access_sctlr(struct kvm_vcpu *vcpu, - const struct coproc_params *p, - const struct coproc_reg *r); +bool access_vm_reg(struct kvm_vcpu *vcpu, + const struct coproc_params *p, + const struct coproc_reg *r); #endif /* __ARM_KVM_COPROC_LOCAL_H__ */ diff --git a/arch/arm/kvm/coproc_a15.c b/arch/arm/kvm/coproc_a15.c index e6f4ae48bda9..a7136757d373 100644 --- a/arch/arm/kvm/coproc_a15.c +++ b/arch/arm/kvm/coproc_a15.c @@ -34,7 +34,7 @@ static const struct coproc_reg a15_regs[] = { /* SCTLR: swapped by interrupt.S. */ { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32, - access_sctlr, reset_val, c1_SCTLR, 0x00C50078 }, + access_vm_reg, reset_val, c1_SCTLR, 0x00C50078 }, }; static struct kvm_coproc_target_table a15_target_table = { diff --git a/arch/arm/kvm/coproc_a7.c b/arch/arm/kvm/coproc_a7.c index 17fc7cd479d3..b19e46d1b2c0 100644 --- a/arch/arm/kvm/coproc_a7.c +++ b/arch/arm/kvm/coproc_a7.c @@ -37,7 +37,7 @@ static const struct coproc_reg a7_regs[] = { /* SCTLR: swapped by interrupt.S. */ { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32, - access_sctlr, reset_val, c1_SCTLR, 0x00C50878 }, + access_vm_reg, reset_val, c1_SCTLR, 0x00C50878 }, }; static struct kvm_coproc_target_table a7_target_table = { diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index 1dc9778a00af..136662547ca6 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -58,6 +58,26 @@ static void kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa) kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, kvm, ipa); } +/* + * D-Cache management functions. They take the page table entries by + * value, as they are flushing the cache using the kernel mapping (or + * kmap on 32bit). + */ +static void kvm_flush_dcache_pte(pte_t pte) +{ + __kvm_flush_dcache_pte(pte); +} + +static void kvm_flush_dcache_pmd(pmd_t pmd) +{ + __kvm_flush_dcache_pmd(pmd); +} + +static void kvm_flush_dcache_pud(pud_t pud) +{ + __kvm_flush_dcache_pud(pud); +} + static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache, int min, int max) { @@ -119,6 +139,26 @@ static void clear_pmd_entry(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr) put_page(virt_to_page(pmd)); } +/* + * Unmapping vs dcache management: + * + * If a guest maps certain memory pages as uncached, all writes will + * bypass the data cache and go directly to RAM. However, the CPUs + * can still speculate reads (not writes) and fill cache lines with + * data. + * + * Those cache lines will be *clean* cache lines though, so a + * clean+invalidate operation is equivalent to an invalidate + * operation, because no cache lines are marked dirty. + * + * Those clean cache lines could be filled prior to an uncached write + * by the guest, and the cache coherent IO subsystem would therefore + * end up writing old data to disk. + * + * This is why right after unmapping a page/section and invalidating + * the corresponding TLBs, we call kvm_flush_dcache_p*() to make sure + * the IO subsystem will never hit in the cache. + */ static void unmap_ptes(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr, phys_addr_t end) { @@ -128,9 +168,16 @@ static void unmap_ptes(struct kvm *kvm, pmd_t *pmd, start_pte = pte = pte_offset_kernel(pmd, addr); do { if (!pte_none(*pte)) { + pte_t old_pte = *pte; + kvm_set_pte(pte, __pte(0)); - put_page(virt_to_page(pte)); kvm_tlb_flush_vmid_ipa(kvm, addr); + + /* No need to invalidate the cache for device mappings */ + if ((pte_val(old_pte) & PAGE_S2_DEVICE) != PAGE_S2_DEVICE) + kvm_flush_dcache_pte(old_pte); + + put_page(virt_to_page(pte)); } } while (pte++, addr += PAGE_SIZE, addr != end); @@ -149,8 +196,13 @@ static void unmap_pmds(struct kvm *kvm, pud_t *pud, next = kvm_pmd_addr_end(addr, end); if (!pmd_none(*pmd)) { if (kvm_pmd_huge(*pmd)) { + pmd_t old_pmd = *pmd; + pmd_clear(pmd); kvm_tlb_flush_vmid_ipa(kvm, addr); + + kvm_flush_dcache_pmd(old_pmd); + put_page(virt_to_page(pmd)); } else { unmap_ptes(kvm, pmd, addr, next); @@ -173,8 +225,13 @@ static void unmap_puds(struct kvm *kvm, pgd_t *pgd, next = kvm_pud_addr_end(addr, end); if (!pud_none(*pud)) { if (pud_huge(*pud)) { + pud_t old_pud = *pud; + pud_clear(pud); kvm_tlb_flush_vmid_ipa(kvm, addr); + + kvm_flush_dcache_pud(old_pud); + put_page(virt_to_page(pud)); } else { unmap_pmds(kvm, pud, addr, next); @@ -209,10 +266,9 @@ static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd, pte = pte_offset_kernel(pmd, addr); do { - if (!pte_none(*pte)) { - hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT); - kvm_flush_dcache_to_poc((void*)hva, PAGE_SIZE); - } + if (!pte_none(*pte) && + (pte_val(*pte) & PAGE_S2_DEVICE) != PAGE_S2_DEVICE) + kvm_flush_dcache_pte(*pte); } while (pte++, addr += PAGE_SIZE, addr != end); } @@ -226,12 +282,10 @@ static void stage2_flush_pmds(struct kvm *kvm, pud_t *pud, do { next = kvm_pmd_addr_end(addr, end); if (!pmd_none(*pmd)) { - if (kvm_pmd_huge(*pmd)) { - hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT); - kvm_flush_dcache_to_poc((void*)hva, PMD_SIZE); - } else { + if (kvm_pmd_huge(*pmd)) + kvm_flush_dcache_pmd(*pmd); + else stage2_flush_ptes(kvm, pmd, addr, next); - } } } while (pmd++, addr = next, addr != end); } @@ -246,12 +300,10 @@ static void stage2_flush_puds(struct kvm *kvm, pgd_t *pgd, do { next = kvm_pud_addr_end(addr, end); if (!pud_none(*pud)) { - if (pud_huge(*pud)) { - hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT); - kvm_flush_dcache_to_poc((void*)hva, PUD_SIZE); - } else { + if (pud_huge(*pud)) + kvm_flush_dcache_pud(*pud); + else stage2_flush_pmds(kvm, pud, addr, next); - } } } while (pud++, addr = next, addr != end); } @@ -278,7 +330,7 @@ static void stage2_flush_memslot(struct kvm *kvm, * Go through the stage 2 page tables and invalidate any cache lines * backing memory already mapped to the VM. */ -void stage2_flush_vm(struct kvm *kvm) +static void stage2_flush_vm(struct kvm *kvm) { struct kvm_memslots *slots; struct kvm_memory_slot *memslot; @@ -905,6 +957,12 @@ static bool kvm_is_device_pfn(unsigned long pfn) return !pfn_valid(pfn); } +static void coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn, + unsigned long size, bool uncached) +{ + __coherent_cache_guest_page(vcpu, pfn, size, uncached); +} + static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, struct kvm_memory_slot *memslot, unsigned long hva, unsigned long fault_status) @@ -994,8 +1052,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, kvm_set_s2pmd_writable(&new_pmd); kvm_set_pfn_dirty(pfn); } - coherent_cache_guest_page(vcpu, hva & PMD_MASK, PMD_SIZE, - fault_ipa_uncached); + coherent_cache_guest_page(vcpu, pfn, PMD_SIZE, fault_ipa_uncached); ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd); } else { pte_t new_pte = pfn_pte(pfn, mem_type); @@ -1003,8 +1060,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, kvm_set_s2pte_writable(&new_pte); kvm_set_pfn_dirty(pfn); } - coherent_cache_guest_page(vcpu, hva, PAGE_SIZE, - fault_ipa_uncached); + coherent_cache_guest_page(vcpu, pfn, PAGE_SIZE, fault_ipa_uncached); ret = stage2_set_pte(kvm, memcache, fault_ipa, &new_pte, pgprot_val(mem_type) == pgprot_val(PAGE_S2_DEVICE)); } @@ -1411,3 +1467,71 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm, unmap_stage2_range(kvm, gpa, size); spin_unlock(&kvm->mmu_lock); } + +/* + * See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized). + * + * Main problems: + * - S/W ops are local to a CPU (not broadcast) + * - We have line migration behind our back (speculation) + * - System caches don't support S/W at all (damn!) + * + * In the face of the above, the best we can do is to try and convert + * S/W ops to VA ops. Because the guest is not allowed to infer the + * S/W to PA mapping, it can only use S/W to nuke the whole cache, + * which is a rather good thing for us. + * + * Also, it is only used when turning caches on/off ("The expected + * usage of the cache maintenance instructions that operate by set/way + * is associated with the cache maintenance instructions associated + * with the powerdown and powerup of caches, if this is required by + * the implementation."). + * + * We use the following policy: + * + * - If we trap a S/W operation, we enable VM trapping to detect + * caches being turned on/off, and do a full clean. + * + * - We flush the caches on both caches being turned on and off. + * + * - Once the caches are enabled, we stop trapping VM ops. + */ +void kvm_set_way_flush(struct kvm_vcpu *vcpu) +{ + unsigned long hcr = vcpu_get_hcr(vcpu); + + /* + * If this is the first time we do a S/W operation + * (i.e. HCR_TVM not set) flush the whole memory, and set the + * VM trapping. + * + * Otherwise, rely on the VM trapping to wait for the MMU + + * Caches to be turned off. At that point, we'll be able to + * clean the caches again. + */ + if (!(hcr & HCR_TVM)) { + trace_kvm_set_way_flush(*vcpu_pc(vcpu), + vcpu_has_cache_enabled(vcpu)); + stage2_flush_vm(vcpu->kvm); + vcpu_set_hcr(vcpu, hcr | HCR_TVM); + } +} + +void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled) +{ + bool now_enabled = vcpu_has_cache_enabled(vcpu); + + /* + * If switching the MMU+caches on, need to invalidate the caches. + * If switching it off, need to clean the caches. + * Clean + invalidate does the trick always. + */ + if (now_enabled != was_enabled) + stage2_flush_vm(vcpu->kvm); + + /* Caches are now on, stop trapping VM ops (until a S/W op) */ + if (now_enabled) + vcpu_set_hcr(vcpu, vcpu_get_hcr(vcpu) & ~HCR_TVM); + + trace_kvm_toggle_cache(*vcpu_pc(vcpu), was_enabled, now_enabled); +} diff --git a/arch/arm/kvm/trace.h b/arch/arm/kvm/trace.h index b1d640f78623..b6a6e7102201 100644 --- a/arch/arm/kvm/trace.h +++ b/arch/arm/kvm/trace.h @@ -223,6 +223,45 @@ TRACE_EVENT(kvm_hvc, __entry->vcpu_pc, __entry->r0, __entry->imm) ); +TRACE_EVENT(kvm_set_way_flush, + TP_PROTO(unsigned long vcpu_pc, bool cache), + TP_ARGS(vcpu_pc, cache), + + TP_STRUCT__entry( + __field( unsigned long, vcpu_pc ) + __field( bool, cache ) + ), + + TP_fast_assign( + __entry->vcpu_pc = vcpu_pc; + __entry->cache = cache; + ), + + TP_printk("S/W flush at 0x%016lx (cache %s)", + __entry->vcpu_pc, __entry->cache ? "on" : "off") +); + +TRACE_EVENT(kvm_toggle_cache, + TP_PROTO(unsigned long vcpu_pc, bool was, bool now), + TP_ARGS(vcpu_pc, was, now), + + TP_STRUCT__entry( + __field( unsigned long, vcpu_pc ) + __field( bool, was ) + __field( bool, now ) + ), + + TP_fast_assign( + __entry->vcpu_pc = vcpu_pc; + __entry->was = was; + __entry->now = now; + ), + + TP_printk("VM op at 0x%016lx (cache was %s, now %s)", + __entry->vcpu_pc, __entry->was ? "on" : "off", + __entry->now ? "on" : "off") +); + #endif /* _TRACE_KVM_H */ #undef TRACE_INCLUDE_PATH diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 0573faab96ad..d8a780799506 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -15,19 +15,8 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ io-readsb.o io-writesb.o io-readsl.o io-writesl.o \ call_with_stack.o bswapsdi2.o -mmu-y := clear_user.o copy_page.o getuser.o putuser.o - -# the code in uaccess.S is not preemption safe and -# probably faster on ARMv3 only -ifeq ($(CONFIG_PREEMPT),y) - mmu-y += copy_from_user.o copy_to_user.o -else -ifneq ($(CONFIG_CPU_32v3),y) - mmu-y += copy_from_user.o copy_to_user.o -else - mmu-y += uaccess.o -endif -endif +mmu-y := clear_user.o copy_page.o getuser.o putuser.o \ + copy_from_user.o copy_to_user.o # using lib_ here won't override already available weak symbols obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o diff --git a/arch/arm/lib/uaccess.S b/arch/arm/lib/uaccess.S deleted file mode 100644 index e50520904b76..000000000000 --- a/arch/arm/lib/uaccess.S +++ /dev/null @@ -1,564 +0,0 @@ -/* - * linux/arch/arm/lib/uaccess.S - * - * Copyright (C) 1995, 1996,1997,1998 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Routines to block copy data to/from user memory - * These are highly optimised both for the 4k page size - * and for various alignments. - */ -#include -#include -#include -#include - - .text - -#define PAGE_SHIFT 12 - -/* Prototype: int __copy_to_user(void *to, const char *from, size_t n) - * Purpose : copy a block to user memory from kernel memory - * Params : to - user memory - * : from - kernel memory - * : n - number of bytes to copy - * Returns : Number of bytes NOT copied. - */ - -.Lc2u_dest_not_aligned: - rsb ip, ip, #4 - cmp ip, #2 - ldrb r3, [r1], #1 -USER( TUSER( strb) r3, [r0], #1) @ May fault - ldrgeb r3, [r1], #1 -USER( TUSER( strgeb) r3, [r0], #1) @ May fault - ldrgtb r3, [r1], #1 -USER( TUSER( strgtb) r3, [r0], #1) @ May fault - sub r2, r2, ip - b .Lc2u_dest_aligned - -ENTRY(__copy_to_user) - stmfd sp!, {r2, r4 - r7, lr} - cmp r2, #4 - blt .Lc2u_not_enough - ands ip, r0, #3 - bne .Lc2u_dest_not_aligned -.Lc2u_dest_aligned: - - ands ip, r1, #3 - bne .Lc2u_src_not_aligned -/* - * Seeing as there has to be at least 8 bytes to copy, we can - * copy one word, and force a user-mode page fault... - */ - -.Lc2u_0fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lc2u_0nowords - ldr r3, [r1], #4 -USER( TUSER( str) r3, [r0], #4) @ May fault - mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lc2u_0fupi -/* - * ip = max no. of bytes to copy before needing another "strt" insn - */ - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #32 - blt .Lc2u_0rem8lp - -.Lc2u_0cpy8lp: ldmia r1!, {r3 - r6} - stmia r0!, {r3 - r6} @ Shouldnt fault - ldmia r1!, {r3 - r6} - subs ip, ip, #32 - stmia r0!, {r3 - r6} @ Shouldnt fault - bpl .Lc2u_0cpy8lp - -.Lc2u_0rem8lp: cmn ip, #16 - ldmgeia r1!, {r3 - r6} - stmgeia r0!, {r3 - r6} @ Shouldnt fault - tst ip, #8 - ldmneia r1!, {r3 - r4} - stmneia r0!, {r3 - r4} @ Shouldnt fault - tst ip, #4 - ldrne r3, [r1], #4 - TUSER( strne) r3, [r0], #4 @ Shouldnt fault - ands ip, ip, #3 - beq .Lc2u_0fupi -.Lc2u_0nowords: teq ip, #0 - beq .Lc2u_finished -.Lc2u_nowords: cmp ip, #2 - ldrb r3, [r1], #1 -USER( TUSER( strb) r3, [r0], #1) @ May fault - ldrgeb r3, [r1], #1 -USER( TUSER( strgeb) r3, [r0], #1) @ May fault - ldrgtb r3, [r1], #1 -USER( TUSER( strgtb) r3, [r0], #1) @ May fault - b .Lc2u_finished - -.Lc2u_not_enough: - movs ip, r2 - bne .Lc2u_nowords -.Lc2u_finished: mov r0, #0 - ldmfd sp!, {r2, r4 - r7, pc} - -.Lc2u_src_not_aligned: - bic r1, r1, #3 - ldr r7, [r1], #4 - cmp ip, #2 - bgt .Lc2u_3fupi - beq .Lc2u_2fupi -.Lc2u_1fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lc2u_1nowords - mov r3, r7, lspull #8 - ldr r7, [r1], #4 - orr r3, r3, r7, lspush #24 -USER( TUSER( str) r3, [r0], #4) @ May fault - mov ip, r0, lsl #32 - PAGE_SHIFT - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lc2u_1fupi - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #16 - blt .Lc2u_1rem8lp - -.Lc2u_1cpy8lp: mov r3, r7, lspull #8 - ldmia r1!, {r4 - r7} - subs ip, ip, #16 - orr r3, r3, r4, lspush #24 - mov r4, r4, lspull #8 - orr r4, r4, r5, lspush #24 - mov r5, r5, lspull #8 - orr r5, r5, r6, lspush #24 - mov r6, r6, lspull #8 - orr r6, r6, r7, lspush #24 - stmia r0!, {r3 - r6} @ Shouldnt fault - bpl .Lc2u_1cpy8lp - -.Lc2u_1rem8lp: tst ip, #8 - movne r3, r7, lspull #8 - ldmneia r1!, {r4, r7} - orrne r3, r3, r4, lspush #24 - movne r4, r4, lspull #8 - orrne r4, r4, r7, lspush #24 - stmneia r0!, {r3 - r4} @ Shouldnt fault - tst ip, #4 - movne r3, r7, lspull #8 - ldrne r7, [r1], #4 - orrne r3, r3, r7, lspush #24 - TUSER( strne) r3, [r0], #4 @ Shouldnt fault - ands ip, ip, #3 - beq .Lc2u_1fupi -.Lc2u_1nowords: mov r3, r7, get_byte_1 - teq ip, #0 - beq .Lc2u_finished - cmp ip, #2 -USER( TUSER( strb) r3, [r0], #1) @ May fault - movge r3, r7, get_byte_2 -USER( TUSER( strgeb) r3, [r0], #1) @ May fault - movgt r3, r7, get_byte_3 -USER( TUSER( strgtb) r3, [r0], #1) @ May fault - b .Lc2u_finished - -.Lc2u_2fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lc2u_2nowords - mov r3, r7, lspull #16 - ldr r7, [r1], #4 - orr r3, r3, r7, lspush #16 -USER( TUSER( str) r3, [r0], #4) @ May fault - mov ip, r0, lsl #32 - PAGE_SHIFT - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lc2u_2fupi - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #16 - blt .Lc2u_2rem8lp - -.Lc2u_2cpy8lp: mov r3, r7, lspull #16 - ldmia r1!, {r4 - r7} - subs ip, ip, #16 - orr r3, r3, r4, lspush #16 - mov r4, r4, lspull #16 - orr r4, r4, r5, lspush #16 - mov r5, r5, lspull #16 - orr r5, r5, r6, lspush #16 - mov r6, r6, lspull #16 - orr r6, r6, r7, lspush #16 - stmia r0!, {r3 - r6} @ Shouldnt fault - bpl .Lc2u_2cpy8lp - -.Lc2u_2rem8lp: tst ip, #8 - movne r3, r7, lspull #16 - ldmneia r1!, {r4, r7} - orrne r3, r3, r4, lspush #16 - movne r4, r4, lspull #16 - orrne r4, r4, r7, lspush #16 - stmneia r0!, {r3 - r4} @ Shouldnt fault - tst ip, #4 - movne r3, r7, lspull #16 - ldrne r7, [r1], #4 - orrne r3, r3, r7, lspush #16 - TUSER( strne) r3, [r0], #4 @ Shouldnt fault - ands ip, ip, #3 - beq .Lc2u_2fupi -.Lc2u_2nowords: mov r3, r7, get_byte_2 - teq ip, #0 - beq .Lc2u_finished - cmp ip, #2 -USER( TUSER( strb) r3, [r0], #1) @ May fault - movge r3, r7, get_byte_3 -USER( TUSER( strgeb) r3, [r0], #1) @ May fault - ldrgtb r3, [r1], #0 -USER( TUSER( strgtb) r3, [r0], #1) @ May fault - b .Lc2u_finished - -.Lc2u_3fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lc2u_3nowords - mov r3, r7, lspull #24 - ldr r7, [r1], #4 - orr r3, r3, r7, lspush #8 -USER( TUSER( str) r3, [r0], #4) @ May fault - mov ip, r0, lsl #32 - PAGE_SHIFT - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lc2u_3fupi - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #16 - blt .Lc2u_3rem8lp - -.Lc2u_3cpy8lp: mov r3, r7, lspull #24 - ldmia r1!, {r4 - r7} - subs ip, ip, #16 - orr r3, r3, r4, lspush #8 - mov r4, r4, lspull #24 - orr r4, r4, r5, lspush #8 - mov r5, r5, lspull #24 - orr r5, r5, r6, lspush #8 - mov r6, r6, lspull #24 - orr r6, r6, r7, lspush #8 - stmia r0!, {r3 - r6} @ Shouldnt fault - bpl .Lc2u_3cpy8lp - -.Lc2u_3rem8lp: tst ip, #8 - movne r3, r7, lspull #24 - ldmneia r1!, {r4, r7} - orrne r3, r3, r4, lspush #8 - movne r4, r4, lspull #24 - orrne r4, r4, r7, lspush #8 - stmneia r0!, {r3 - r4} @ Shouldnt fault - tst ip, #4 - movne r3, r7, lspull #24 - ldrne r7, [r1], #4 - orrne r3, r3, r7, lspush #8 - TUSER( strne) r3, [r0], #4 @ Shouldnt fault - ands ip, ip, #3 - beq .Lc2u_3fupi -.Lc2u_3nowords: mov r3, r7, get_byte_3 - teq ip, #0 - beq .Lc2u_finished - cmp ip, #2 -USER( TUSER( strb) r3, [r0], #1) @ May fault - ldrgeb r3, [r1], #1 -USER( TUSER( strgeb) r3, [r0], #1) @ May fault - ldrgtb r3, [r1], #0 -USER( TUSER( strgtb) r3, [r0], #1) @ May fault - b .Lc2u_finished -ENDPROC(__copy_to_user) - - .pushsection .fixup,"ax" - .align 0 -9001: ldmfd sp!, {r0, r4 - r7, pc} - .popsection - -/* Prototype: unsigned long __copy_from_user(void *to,const void *from,unsigned long n); - * Purpose : copy a block from user memory to kernel memory - * Params : to - kernel memory - * : from - user memory - * : n - number of bytes to copy - * Returns : Number of bytes NOT copied. - */ -.Lcfu_dest_not_aligned: - rsb ip, ip, #4 - cmp ip, #2 -USER( TUSER( ldrb) r3, [r1], #1) @ May fault - strb r3, [r0], #1 -USER( TUSER( ldrgeb) r3, [r1], #1) @ May fault - strgeb r3, [r0], #1 -USER( TUSER( ldrgtb) r3, [r1], #1) @ May fault - strgtb r3, [r0], #1 - sub r2, r2, ip - b .Lcfu_dest_aligned - -ENTRY(__copy_from_user) - stmfd sp!, {r0, r2, r4 - r7, lr} - cmp r2, #4 - blt .Lcfu_not_enough - ands ip, r0, #3 - bne .Lcfu_dest_not_aligned -.Lcfu_dest_aligned: - ands ip, r1, #3 - bne .Lcfu_src_not_aligned - -/* - * Seeing as there has to be at least 8 bytes to copy, we can - * copy one word, and force a user-mode page fault... - */ - -.Lcfu_0fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lcfu_0nowords -USER( TUSER( ldr) r3, [r1], #4) - str r3, [r0], #4 - mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lcfu_0fupi -/* - * ip = max no. of bytes to copy before needing another "strt" insn - */ - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #32 - blt .Lcfu_0rem8lp - -.Lcfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault - stmia r0!, {r3 - r6} - ldmia r1!, {r3 - r6} @ Shouldnt fault - subs ip, ip, #32 - stmia r0!, {r3 - r6} - bpl .Lcfu_0cpy8lp - -.Lcfu_0rem8lp: cmn ip, #16 - ldmgeia r1!, {r3 - r6} @ Shouldnt fault - stmgeia r0!, {r3 - r6} - tst ip, #8 - ldmneia r1!, {r3 - r4} @ Shouldnt fault - stmneia r0!, {r3 - r4} - tst ip, #4 - TUSER( ldrne) r3, [r1], #4 @ Shouldnt fault - strne r3, [r0], #4 - ands ip, ip, #3 - beq .Lcfu_0fupi -.Lcfu_0nowords: teq ip, #0 - beq .Lcfu_finished -.Lcfu_nowords: cmp ip, #2 -USER( TUSER( ldrb) r3, [r1], #1) @ May fault - strb r3, [r0], #1 -USER( TUSER( ldrgeb) r3, [r1], #1) @ May fault - strgeb r3, [r0], #1 -USER( TUSER( ldrgtb) r3, [r1], #1) @ May fault - strgtb r3, [r0], #1 - b .Lcfu_finished - -.Lcfu_not_enough: - movs ip, r2 - bne .Lcfu_nowords -.Lcfu_finished: mov r0, #0 - add sp, sp, #8 - ldmfd sp!, {r4 - r7, pc} - -.Lcfu_src_not_aligned: - bic r1, r1, #3 -USER( TUSER( ldr) r7, [r1], #4) @ May fault - cmp ip, #2 - bgt .Lcfu_3fupi - beq .Lcfu_2fupi -.Lcfu_1fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lcfu_1nowords - mov r3, r7, lspull #8 -USER( TUSER( ldr) r7, [r1], #4) @ May fault - orr r3, r3, r7, lspush #24 - str r3, [r0], #4 - mov ip, r1, lsl #32 - PAGE_SHIFT - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lcfu_1fupi - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #16 - blt .Lcfu_1rem8lp - -.Lcfu_1cpy8lp: mov r3, r7, lspull #8 - ldmia r1!, {r4 - r7} @ Shouldnt fault - subs ip, ip, #16 - orr r3, r3, r4, lspush #24 - mov r4, r4, lspull #8 - orr r4, r4, r5, lspush #24 - mov r5, r5, lspull #8 - orr r5, r5, r6, lspush #24 - mov r6, r6, lspull #8 - orr r6, r6, r7, lspush #24 - stmia r0!, {r3 - r6} - bpl .Lcfu_1cpy8lp - -.Lcfu_1rem8lp: tst ip, #8 - movne r3, r7, lspull #8 - ldmneia r1!, {r4, r7} @ Shouldnt fault - orrne r3, r3, r4, lspush #24 - movne r4, r4, lspull #8 - orrne r4, r4, r7, lspush #24 - stmneia r0!, {r3 - r4} - tst ip, #4 - movne r3, r7, lspull #8 -USER( TUSER( ldrne) r7, [r1], #4) @ May fault - orrne r3, r3, r7, lspush #24 - strne r3, [r0], #4 - ands ip, ip, #3 - beq .Lcfu_1fupi -.Lcfu_1nowords: mov r3, r7, get_byte_1 - teq ip, #0 - beq .Lcfu_finished - cmp ip, #2 - strb r3, [r0], #1 - movge r3, r7, get_byte_2 - strgeb r3, [r0], #1 - movgt r3, r7, get_byte_3 - strgtb r3, [r0], #1 - b .Lcfu_finished - -.Lcfu_2fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lcfu_2nowords - mov r3, r7, lspull #16 -USER( TUSER( ldr) r7, [r1], #4) @ May fault - orr r3, r3, r7, lspush #16 - str r3, [r0], #4 - mov ip, r1, lsl #32 - PAGE_SHIFT - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lcfu_2fupi - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #16 - blt .Lcfu_2rem8lp - - -.Lcfu_2cpy8lp: mov r3, r7, lspull #16 - ldmia r1!, {r4 - r7} @ Shouldnt fault - subs ip, ip, #16 - orr r3, r3, r4, lspush #16 - mov r4, r4, lspull #16 - orr r4, r4, r5, lspush #16 - mov r5, r5, lspull #16 - orr r5, r5, r6, lspush #16 - mov r6, r6, lspull #16 - orr r6, r6, r7, lspush #16 - stmia r0!, {r3 - r6} - bpl .Lcfu_2cpy8lp - -.Lcfu_2rem8lp: tst ip, #8 - movne r3, r7, lspull #16 - ldmneia r1!, {r4, r7} @ Shouldnt fault - orrne r3, r3, r4, lspush #16 - movne r4, r4, lspull #16 - orrne r4, r4, r7, lspush #16 - stmneia r0!, {r3 - r4} - tst ip, #4 - movne r3, r7, lspull #16 -USER( TUSER( ldrne) r7, [r1], #4) @ May fault - orrne r3, r3, r7, lspush #16 - strne r3, [r0], #4 - ands ip, ip, #3 - beq .Lcfu_2fupi -.Lcfu_2nowords: mov r3, r7, get_byte_2 - teq ip, #0 - beq .Lcfu_finished - cmp ip, #2 - strb r3, [r0], #1 - movge r3, r7, get_byte_3 - strgeb r3, [r0], #1 -USER( TUSER( ldrgtb) r3, [r1], #0) @ May fault - strgtb r3, [r0], #1 - b .Lcfu_finished - -.Lcfu_3fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lcfu_3nowords - mov r3, r7, lspull #24 -USER( TUSER( ldr) r7, [r1], #4) @ May fault - orr r3, r3, r7, lspush #8 - str r3, [r0], #4 - mov ip, r1, lsl #32 - PAGE_SHIFT - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lcfu_3fupi - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #16 - blt .Lcfu_3rem8lp - -.Lcfu_3cpy8lp: mov r3, r7, lspull #24 - ldmia r1!, {r4 - r7} @ Shouldnt fault - orr r3, r3, r4, lspush #8 - mov r4, r4, lspull #24 - orr r4, r4, r5, lspush #8 - mov r5, r5, lspull #24 - orr r5, r5, r6, lspush #8 - mov r6, r6, lspull #24 - orr r6, r6, r7, lspush #8 - stmia r0!, {r3 - r6} - subs ip, ip, #16 - bpl .Lcfu_3cpy8lp - -.Lcfu_3rem8lp: tst ip, #8 - movne r3, r7, lspull #24 - ldmneia r1!, {r4, r7} @ Shouldnt fault - orrne r3, r3, r4, lspush #8 - movne r4, r4, lspull #24 - orrne r4, r4, r7, lspush #8 - stmneia r0!, {r3 - r4} - tst ip, #4 - movne r3, r7, lspull #24 -USER( TUSER( ldrne) r7, [r1], #4) @ May fault - orrne r3, r3, r7, lspush #8 - strne r3, [r0], #4 - ands ip, ip, #3 - beq .Lcfu_3fupi -.Lcfu_3nowords: mov r3, r7, get_byte_3 - teq ip, #0 - beq .Lcfu_finished - cmp ip, #2 - strb r3, [r0], #1 -USER( TUSER( ldrgeb) r3, [r1], #1) @ May fault - strgeb r3, [r0], #1 -USER( TUSER( ldrgtb) r3, [r1], #1) @ May fault - strgtb r3, [r0], #1 - b .Lcfu_finished -ENDPROC(__copy_from_user) - - .pushsection .fixup,"ax" - .align 0 - /* - * We took an exception. r0 contains a pointer to - * the byte not copied. - */ -9001: ldr r2, [sp], #4 @ void *to - sub r2, r0, r2 @ bytes copied - ldr r1, [sp], #4 @ unsigned long count - subs r4, r1, r2 @ bytes left to copy - movne r1, r4 - blne __memzero - mov r0, r4 - ldmfd sp!, {r4 - r7, pc} - .popsection - diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c index 45d6bd09e6ef..c622c306c390 100644 --- a/arch/arm/mach-cns3xxx/pcie.c +++ b/arch/arm/mach-cns3xxx/pcie.c @@ -30,18 +30,15 @@ struct cns3xxx_pcie { unsigned int irqs[2]; struct resource res_io; struct resource res_mem; - struct hw_pci hw_pci; - + int port; bool linked; }; -static struct cns3xxx_pcie cns3xxx_pcie[]; /* forward decl. */ - static struct cns3xxx_pcie *sysdata_to_cnspci(void *sysdata) { struct pci_sys_data *root = sysdata; - return &cns3xxx_pcie[root->domain]; + return root->private_data; } static struct cns3xxx_pcie *pdev_to_cnspci(const struct pci_dev *dev) @@ -54,8 +51,8 @@ static struct cns3xxx_pcie *pbus_to_cnspci(struct pci_bus *bus) return sysdata_to_cnspci(bus->sysdata); } -static void __iomem *cns3xxx_pci_cfg_base(struct pci_bus *bus, - unsigned int devfn, int where) +static void __iomem *cns3xxx_pci_map_bus(struct pci_bus *bus, + unsigned int devfn, int where) { struct cns3xxx_pcie *cnspci = pbus_to_cnspci(bus); int busno = bus->number; @@ -91,55 +88,22 @@ static void __iomem *cns3xxx_pci_cfg_base(struct pci_bus *bus, static int cns3xxx_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { - u32 v; - void __iomem *base; + int ret; u32 mask = (0x1ull << (size * 8)) - 1; int shift = (where % 4) * 8; - base = cns3xxx_pci_cfg_base(bus, devfn, where); - if (!base) { - *val = 0xffffffff; - return PCIBIOS_SUCCESSFUL; - } + ret = pci_generic_config_read32(bus, devfn, where, size, val); - v = __raw_readl(base); - - if (bus->number == 0 && devfn == 0 && - (where & 0xffc) == PCI_CLASS_REVISION) { + if (ret == PCIBIOS_SUCCESSFUL && !bus->number && !devfn && + (where & 0xffc) == PCI_CLASS_REVISION) /* * RC's class is 0xb, but Linux PCI driver needs 0x604 * for a PCIe bridge. So we must fixup the class code * to 0x604 here. */ - v &= 0xff; - v |= 0x604 << 16; - } + *val = ((((*val << shift) & 0xff) | (0x604 << 16)) >> shift) & mask; - *val = (v >> shift) & mask; - - return PCIBIOS_SUCCESSFUL; -} - -static int cns3xxx_pci_write_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val) -{ - u32 v; - void __iomem *base; - u32 mask = (0x1ull << (size * 8)) - 1; - int shift = (where % 4) * 8; - - base = cns3xxx_pci_cfg_base(bus, devfn, where); - if (!base) - return PCIBIOS_SUCCESSFUL; - - v = __raw_readl(base); - - v &= ~(mask << shift); - v |= (val & mask) << shift; - - __raw_writel(v, base); - - return PCIBIOS_SUCCESSFUL; + return ret; } static int cns3xxx_pci_setup(int nr, struct pci_sys_data *sys) @@ -158,8 +122,9 @@ static int cns3xxx_pci_setup(int nr, struct pci_sys_data *sys) } static struct pci_ops cns3xxx_pcie_ops = { + .map_bus = cns3xxx_pci_map_bus, .read = cns3xxx_pci_read_config, - .write = cns3xxx_pci_write_config, + .write = pci_generic_config_write, }; static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) @@ -192,13 +157,7 @@ static struct cns3xxx_pcie cns3xxx_pcie[] = { .flags = IORESOURCE_MEM, }, .irqs = { IRQ_CNS3XXX_PCIE0_RC, IRQ_CNS3XXX_PCIE0_DEVICE, }, - .hw_pci = { - .domain = 0, - .nr_controllers = 1, - .ops = &cns3xxx_pcie_ops, - .setup = cns3xxx_pci_setup, - .map_irq = cns3xxx_pcie_map_irq, - }, + .port = 0, }, [1] = { .host_regs = (void __iomem *)CNS3XXX_PCIE1_HOST_BASE_VIRT, @@ -217,19 +176,13 @@ static struct cns3xxx_pcie cns3xxx_pcie[] = { .flags = IORESOURCE_MEM, }, .irqs = { IRQ_CNS3XXX_PCIE1_RC, IRQ_CNS3XXX_PCIE1_DEVICE, }, - .hw_pci = { - .domain = 1, - .nr_controllers = 1, - .ops = &cns3xxx_pcie_ops, - .setup = cns3xxx_pci_setup, - .map_irq = cns3xxx_pcie_map_irq, - }, + .port = 1, }, }; static void __init cns3xxx_pcie_check_link(struct cns3xxx_pcie *cnspci) { - int port = cnspci->hw_pci.domain; + int port = cnspci->port; u32 reg; unsigned long time; @@ -260,9 +213,9 @@ static void __init cns3xxx_pcie_check_link(struct cns3xxx_pcie *cnspci) static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci) { - int port = cnspci->hw_pci.domain; + int port = cnspci->port; struct pci_sys_data sd = { - .domain = port, + .private_data = cnspci, }; struct pci_bus bus = { .number = 0, @@ -323,6 +276,14 @@ static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr, void __init cns3xxx_pcie_init_late(void) { int i; + void *private_data; + struct hw_pci hw_pci = { + .nr_controllers = 1, + .ops = &cns3xxx_pcie_ops, + .setup = cns3xxx_pci_setup, + .map_irq = cns3xxx_pcie_map_irq, + .private_data = &private_data, + }; pcibios_min_io = 0; pcibios_min_mem = 0; @@ -335,7 +296,8 @@ void __init cns3xxx_pcie_init_late(void) cns3xxx_pwr_soft_rst(0x1 << PM_SOFT_RST_REG_OFFST_PCIE(i)); cns3xxx_pcie_check_link(&cns3xxx_pcie[i]); cns3xxx_pcie_hw_init(&cns3xxx_pcie[i]); - pci_common_init(&cns3xxx_pcie[i].hw_pci); + private_data = &cns3xxx_pcie[i]; + pci_common_init(&hw_pci); } pci_assign_unassigned_resources(); diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index 766f57d2f029..4791a3cc00f9 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -136,6 +137,43 @@ static const struct firmware_ops exynos_firmware_ops = { .resume = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_resume : NULL, }; +static void exynos_l2_write_sec(unsigned long val, unsigned reg) +{ + static int l2cache_enabled; + + switch (reg) { + case L2X0_CTRL: + if (val & L2X0_CTRL_EN) { + /* + * Before the cache can be enabled, due to firmware + * design, SMC_CMD_L2X0INVALL must be called. + */ + if (!l2cache_enabled) { + exynos_smc(SMC_CMD_L2X0INVALL, 0, 0, 0); + l2cache_enabled = 1; + } + } else { + l2cache_enabled = 0; + } + exynos_smc(SMC_CMD_L2X0CTRL, val, 0, 0); + break; + + case L2X0_DEBUG_CTRL: + exynos_smc(SMC_CMD_L2X0DEBUG, val, 0, 0); + break; + + default: + WARN_ONCE(1, "%s: ignoring write to reg 0x%x\n", __func__, reg); + } +} + +static void exynos_l2_configure(const struct l2x0_regs *regs) +{ + exynos_smc(SMC_CMD_L2X0SETUP1, regs->tag_latency, regs->data_latency, + regs->prefetch_ctrl); + exynos_smc(SMC_CMD_L2X0SETUP2, regs->pwr_ctrl, regs->aux_ctrl, 0); +} + void __init exynos_firmware_init(void) { struct device_node *nd; @@ -155,4 +193,16 @@ void __init exynos_firmware_init(void) pr_info("Running under secure firmware.\n"); register_firmware_ops(&exynos_firmware_ops); + + /* + * Exynos 4 SoCs (based on Cortex A9 and equipped with L2C-310), + * running under secure firmware, require certain registers of L2 + * cache controller to be written in secure mode. Here .write_sec + * callback is provided to perform necessary SMC calls. + */ + if (IS_ENABLED(CONFIG_CACHE_L2X0) && + read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { + outer_cache.write_sec = exynos_l2_write_sec; + outer_cache.configure = exynos_l2_configure; + } } diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S index e3c373082bbe..31d25834b9c4 100644 --- a/arch/arm/mach-exynos/sleep.S +++ b/arch/arm/mach-exynos/sleep.S @@ -16,6 +16,8 @@ */ #include +#include +#include #include "smc.h" #define CPU_MASK 0xff0ffff0 @@ -74,6 +76,45 @@ ENTRY(exynos_cpu_resume_ns) mov r0, #SMC_CMD_C15RESUME dsb smc #0 +#ifdef CONFIG_CACHE_L2X0 + adr r0, 1f + ldr r2, [r0] + add r0, r2, r0 + + /* Check that the address has been initialised. */ + ldr r1, [r0, #L2X0_R_PHY_BASE] + teq r1, #0 + beq skip_l2x0 + + /* Check if controller has been enabled. */ + ldr r2, [r1, #L2X0_CTRL] + tst r2, #0x1 + bne skip_l2x0 + + ldr r1, [r0, #L2X0_R_TAG_LATENCY] + ldr r2, [r0, #L2X0_R_DATA_LATENCY] + ldr r3, [r0, #L2X0_R_PREFETCH_CTRL] + mov r0, #SMC_CMD_L2X0SETUP1 + smc #0 + + /* Reload saved regs pointer because smc corrupts registers. */ + adr r0, 1f + ldr r2, [r0] + add r0, r2, r0 + + ldr r1, [r0, #L2X0_R_PWR_CTRL] + ldr r2, [r0, #L2X0_R_AUX_CTRL] + mov r0, #SMC_CMD_L2X0SETUP2 + smc #0 + + mov r0, #SMC_CMD_L2X0INVALL + smc #0 + + mov r1, #1 + mov r0, #SMC_CMD_L2X0CTRL + smc #0 +skip_l2x0: +#endif /* CONFIG_CACHE_L2X0 */ skip_cp15: b cpu_resume ENDPROC(exynos_cpu_resume_ns) @@ -83,3 +124,8 @@ cp15_save_diag: .globl cp15_save_power cp15_save_power: .long 0 @ cp15 power control + +#ifdef CONFIG_CACHE_L2X0 + .align +1: .long l2x0_saved_regs - . +#endif /* CONFIG_CACHE_L2X0 */ diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c index c186a17c2cff..2565f0e7b5cf 100644 --- a/arch/arm/mach-integrator/pci_v3.c +++ b/arch/arm/mach-integrator/pci_v3.c @@ -356,7 +356,6 @@ static u64 pre_mem_pci_sz; * 7:2 register number * */ -static DEFINE_RAW_SPINLOCK(v3_lock); #undef V3_LB_BASE_PREFETCH #define V3_LB_BASE_PREFETCH 0 @@ -457,67 +456,21 @@ static void v3_close_config_window(void) static int v3_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { - void __iomem *addr; - unsigned long flags; - u32 v; - - raw_spin_lock_irqsave(&v3_lock, flags); - addr = v3_open_config_window(bus, devfn, where); - - switch (size) { - case 1: - v = __raw_readb(addr); - break; - - case 2: - v = __raw_readw(addr); - break; - - default: - v = __raw_readl(addr); - break; - } - + int ret = pci_generic_config_read(bus, devfn, where, size, val); v3_close_config_window(); - raw_spin_unlock_irqrestore(&v3_lock, flags); - - *val = v; - return PCIBIOS_SUCCESSFUL; + return ret; } static int v3_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { - void __iomem *addr; - unsigned long flags; - - raw_spin_lock_irqsave(&v3_lock, flags); - addr = v3_open_config_window(bus, devfn, where); - - switch (size) { - case 1: - __raw_writeb((u8)val, addr); - __raw_readb(addr); - break; - - case 2: - __raw_writew((u16)val, addr); - __raw_readw(addr); - break; - - case 4: - __raw_writel(val, addr); - __raw_readl(addr); - break; - } - + int ret = pci_generic_config_write(bus, devfn, where, size, val); v3_close_config_window(); - raw_spin_unlock_irqrestore(&v3_lock, flags); - - return PCIBIOS_SUCCESSFUL; + return ret; } static struct pci_ops pci_v3_ops = { + .map_bus = v3_open_config_window, .read = v3_read_config, .write = v3_write_config, }; @@ -658,7 +611,6 @@ static int __init pci_v3_setup(int nr, struct pci_sys_data *sys) */ static void __init pci_v3_preinit(void) { - unsigned long flags; unsigned int temp; phys_addr_t io_address = pci_pio_to_address(io_mem.start); @@ -672,8 +624,6 @@ static void __init pci_v3_preinit(void) hook_fault_code(8, v3_pci_fault, SIGBUS, 0, "external abort on non-linefetch"); hook_fault_code(10, v3_pci_fault, SIGBUS, 0, "external abort on non-linefetch"); - raw_spin_lock_irqsave(&v3_lock, flags); - /* * Unlock V3 registers, but only if they were previously locked. */ @@ -736,8 +686,6 @@ static void __init pci_v3_preinit(void) v3_writew(V3_LB_CFG, v3_readw(V3_LB_CFG) | (1 << 10)); v3_writeb(V3_LB_IMASK, 0x28); __raw_writel(3, ap_syscon_base + INTEGRATOR_SC_PCIENABLE_OFFSET); - - raw_spin_unlock_irqrestore(&v3_lock, flags); } static void __init pci_v3_postinit(void) diff --git a/arch/arm/mach-ks8695/pci.c b/arch/arm/mach-ks8695/pci.c index bb18193b4bac..c1bc4c3716ed 100644 --- a/arch/arm/mach-ks8695/pci.c +++ b/arch/arm/mach-ks8695/pci.c @@ -38,8 +38,6 @@ static int pci_dbg; -static int pci_cfg_dbg; - static void ks8695_pci_setupconfig(unsigned int bus_nr, unsigned int devfn, unsigned int where) { @@ -59,75 +57,11 @@ static void ks8695_pci_setupconfig(unsigned int bus_nr, unsigned int devfn, unsi } } - -/* - * The KS8695 datasheet prohibits anything other than 32bit accesses - * to the IO registers, so all our configuration must be done with - * 32bit operations, and the correct bit masking and shifting. - */ - -static int ks8695_pci_readconfig(struct pci_bus *bus, - unsigned int devfn, int where, int size, u32 *value) +static void __iomem *ks8695_pci_map_bus(struct pci_bus *bus, unsigned int devfn, + int where) { ks8695_pci_setupconfig(bus->number, devfn, where); - - *value = __raw_readl(KS8695_PCI_VA + KS8695_PBCD); - - switch (size) { - case 4: - break; - case 2: - *value = *value >> ((where & 2) * 8); - *value &= 0xffff; - break; - case 1: - *value = *value >> ((where & 3) * 8); - *value &= 0xff; - break; - } - - if (pci_cfg_dbg) { - printk("read: %d,%08x,%02x,%d: %08x (%08x)\n", - bus->number, devfn, where, size, *value, - __raw_readl(KS8695_PCI_VA + KS8695_PBCD)); - } - - return PCIBIOS_SUCCESSFUL; -} - -static int ks8695_pci_writeconfig(struct pci_bus *bus, - unsigned int devfn, int where, int size, u32 value) -{ - unsigned long tmp; - - if (pci_cfg_dbg) { - printk("write: %d,%08x,%02x,%d: %08x\n", - bus->number, devfn, where, size, value); - } - - ks8695_pci_setupconfig(bus->number, devfn, where); - - switch (size) { - case 4: - __raw_writel(value, KS8695_PCI_VA + KS8695_PBCD); - break; - case 2: - tmp = __raw_readl(KS8695_PCI_VA + KS8695_PBCD); - tmp &= ~(0xffff << ((where & 2) * 8)); - tmp |= value << ((where & 2) * 8); - - __raw_writel(tmp, KS8695_PCI_VA + KS8695_PBCD); - break; - case 1: - tmp = __raw_readl(KS8695_PCI_VA + KS8695_PBCD); - tmp &= ~(0xff << ((where & 3) * 8)); - tmp |= value << ((where & 3) * 8); - - __raw_writel(tmp, KS8695_PCI_VA + KS8695_PBCD); - break; - } - - return PCIBIOS_SUCCESSFUL; + return KS8695_PCI_VA + KS8695_PBCD; } static void ks8695_local_writeconfig(int where, u32 value) @@ -137,8 +71,9 @@ static void ks8695_local_writeconfig(int where, u32 value) } static struct pci_ops ks8695_pci_ops = { - .read = ks8695_pci_readconfig, - .write = ks8695_pci_writeconfig, + .map_bus = ks8695_pci_map_bus, + .read = pci_generic_config_read32, + .write = pci_generic_config_write32, }; static struct resource pci_mem = { diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 3585cb394e9b..ccef8806bb58 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -189,6 +189,13 @@ static void __init armada_375_380_coherency_init(struct device_node *np) coherency_cpu_base = of_iomap(np, 0); arch_ioremap_caller = armada_pcie_wa_ioremap_caller; + /* + * We should switch the PL310 to I/O coherency mode only if + * I/O coherency is actually enabled. + */ + if (!coherency_available()) + return; + /* * Add the PL310 property "arm,io-coherent". This makes sure the * outer sync operation is not used, which allows to @@ -246,9 +253,14 @@ static int coherency_type(void) return type; } +/* + * As a precaution, we currently completely disable hardware I/O + * coherency, until enough testing is done with automatic I/O + * synchronization barriers to validate that it is a proper solution. + */ int coherency_available(void) { - return coherency_type() != COHERENCY_FABRIC_TYPE_NONE; + return false; } int __init coherency_init(void) diff --git a/arch/arm/mach-omap1/include/mach/debug-macro.S b/arch/arm/mach-omap1/include/mach/debug-macro.S deleted file mode 100644 index 5c1a26c9f490..000000000000 --- a/arch/arm/mach-omap1/include/mach/debug-macro.S +++ /dev/null @@ -1,101 +0,0 @@ -/* arch/arm/mach-omap1/include/mach/debug-macro.S - * - * Debugging macro include header - * - * Copyright (C) 1994-1999 Russell King - * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks - * - * This 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 "serial.h" - - .pushsection .data -omap_uart_phys: .word 0x0 -omap_uart_virt: .word 0x0 - .popsection - - /* - * Note that this code won't work if the bootloader passes - * a wrong machine ID number in r1. To debug, just hardcode - * the desired UART phys and virt addresses temporarily into - * the omap_uart_phys and omap_uart_virt above. - */ - .macro addruart, rp, rv, tmp - - /* Use omap_uart_phys/virt if already configured */ -9: adr \rp, 99f @ get effective addr of 99f - ldr \rv, [\rp] @ get absolute addr of 99f - sub \rv, \rv, \rp @ offset between the two - ldr \rp, [\rp, #4] @ abs addr of omap_uart_phys - sub \tmp, \rp, \rv @ make it effective - ldr \rp, [\tmp, #0] @ omap_uart_phys - ldr \rv, [\tmp, #4] @ omap_uart_virt - cmp \rp, #0 @ is port configured? - cmpne \rv, #0 - bne 100f @ already configured - - /* Check the debug UART configuration set in uncompress.h */ - and \rp, pc, #0xff000000 - ldr \rv, =OMAP_UART_INFO_OFS - ldr \rp, [\rp, \rv] - - /* Select the UART to use based on the UART1 scratchpad value */ -10: cmp \rp, #0 @ no port configured? - beq 11f @ if none, try to use UART1 - cmp \rp, #OMAP1UART1 - beq 11f @ configure OMAP1UART1 - cmp \rp, #OMAP1UART2 - beq 12f @ configure OMAP1UART2 - cmp \rp, #OMAP1UART3 - beq 13f @ configure OMAP2UART3 - - /* Configure the UART offset from the phys/virt base */ -11: mov \rp, #0x00fb0000 @ OMAP1UART1 - b 98f -12: mov \rp, #0x00fb0000 @ OMAP1UART1 - orr \rp, \rp, #0x00000800 @ OMAP1UART2 - b 98f -13: mov \rp, #0x00fb0000 @ OMAP1UART1 - orr \rp, \rp, #0x00000800 @ OMAP1UART2 - orr \rp, \rp, #0x00009000 @ OMAP1UART3 - - /* Store both phys and virt address for the uart */ -98: add \rp, \rp, #0xff000000 @ phys base - str \rp, [\tmp, #0] @ omap_uart_phys - sub \rp, \rp, #0xff000000 @ phys base - add \rp, \rp, #0xfe000000 @ virt base - str \rp, [\tmp, #4] @ omap_uart_virt - b 9b - - .align -99: .word . - .word omap_uart_phys - .ltorg - -100: - .endm - - .macro senduart,rd,rx - strb \rd, [\rx] - .endm - - .macro busyuart,rd,rx -1001: ldrb \rd, [\rx, #(UART_LSR << OMAP_PORT_SHIFT)] - and \rd, \rd, #(UART_LSR_TEMT | UART_LSR_THRE) - teq \rd, #(UART_LSR_TEMT | UART_LSR_THRE) - beq 1002f - ldrb \rd, [\rx, #(UART_LSR << OMAP7XX_PORT_SHIFT)] - and \rd, \rd, #(UART_LSR_TEMT | UART_LSR_THRE) - teq \rd, #(UART_LSR_TEMT | UART_LSR_THRE) - bne 1001b -1002: - .endm - - .macro waituart,rd,rx - .endm diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index b61c049f92d6..42b7f4c9169b 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -189,6 +189,9 @@ static const char *const omap4_boards_compat[] __initconst = { }; DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)") + .l2c_aux_val = OMAP_L2C_AUX_CTRL, + .l2c_aux_mask = 0xcf9fffff, + .l2c_write_sec = omap4_l2c310_write_sec, .reserve = omap_reserve, .smp = smp_ops(omap4_smp_ops), .map_io = omap4_map_io, @@ -232,6 +235,9 @@ static const char *const am43_boards_compat[] __initconst = { }; DT_MACHINE_START(AM43_DT, "Generic AM43 (Flattened Device Tree)") + .l2c_aux_val = OMAP_L2C_AUX_CTRL, + .l2c_aux_mask = 0xcf9fffff, + .l2c_write_sec = omap4_l2c310_write_sec, .map_io = am33xx_map_io, .init_early = am43xx_init_early, .init_late = am43xx_init_late, diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index 7f1708738c30..969e1003dd92 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -254,12 +254,14 @@ static void pandora_wl1251_init_card(struct mmc_card *card) * We have TI wl1251 attached to MMC3. Pass this information to * SDIO core because it can't be probed by normal methods. */ - card->quirks |= MMC_QUIRK_NONSTD_SDIO; - card->cccr.wide_bus = 1; - card->cis.vendor = 0x104c; - card->cis.device = 0x9066; - card->cis.blksize = 512; - card->cis.max_dtr = 20000000; + if (card->type == MMC_TYPE_SDIO || card->type == MMC_TYPE_SD_COMBO) { + card->quirks |= MMC_QUIRK_NONSTD_SDIO; + card->cccr.wide_bus = 1; + card->cis.vendor = 0x104c; + card->cis.device = 0x9066; + card->cis.blksize = 512; + card->cis.max_dtr = 20000000; + } } static struct omap2_hsmmc_info omap3pandora_mmc[] = { diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index db57741c9c8a..3933b8aa4f01 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -35,6 +35,7 @@ #include #include +#include #include "i2c.h" #include "serial.h" @@ -94,11 +95,18 @@ extern void omap3_gptimer_timer_init(void); extern void omap4_local_timer_init(void); #ifdef CONFIG_CACHE_L2X0 int omap_l2_cache_init(void); +#define OMAP_L2C_AUX_CTRL (L2C_AUX_CTRL_SHARED_OVERRIDE | \ + L310_AUX_CTRL_DATA_PREFETCH | \ + L310_AUX_CTRL_INSTR_PREFETCH) +void omap4_l2c310_write_sec(unsigned long val, unsigned reg); #else static inline int omap_l2_cache_init(void) { return 0; } + +#define OMAP_L2C_AUX_CTRL 0 +#define omap4_l2c310_write_sec NULL #endif extern void omap5_realtime_timer_init(void); @@ -211,6 +219,7 @@ extern struct device *omap2_get_iva_device(void); extern struct device *omap2_get_l3_device(void); extern struct device *omap4_get_dsp_device(void); +unsigned int omap4_xlate_irq(unsigned int hwirq); void omap_gic_of_init(void); #ifdef CONFIG_CACHE_L2X0 diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index b7cb44abe49b..2418bdf28ca2 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -166,7 +166,7 @@ void __iomem *omap4_get_l2cache_base(void) return l2cache_base; } -static void omap4_l2c310_write_sec(unsigned long val, unsigned reg) +void omap4_l2c310_write_sec(unsigned long val, unsigned reg) { unsigned smc_op; @@ -201,24 +201,10 @@ static void omap4_l2c310_write_sec(unsigned long val, unsigned reg) int __init omap_l2_cache_init(void) { - u32 aux_ctrl; - /* Static mapping, never released */ l2cache_base = ioremap(OMAP44XX_L2CACHE_BASE, SZ_4K); if (WARN_ON(!l2cache_base)) return -ENOMEM; - - /* 16-way associativity, parity disabled, way size - 64KB (es2.0 +) */ - aux_ctrl = L2C_AUX_CTRL_SHARED_OVERRIDE | - L310_AUX_CTRL_DATA_PREFETCH | - L310_AUX_CTRL_INSTR_PREFETCH; - - outer_cache.write_sec = omap4_l2c310_write_sec; - if (of_have_populated_dt()) - l2x0_of_init(aux_ctrl, 0xcf9fffff); - else - l2x0_init(l2cache_base, aux_ctrl, 0xcf9fffff); - return 0; } #endif @@ -256,6 +242,38 @@ static int __init omap4_sar_ram_init(void) } omap_early_initcall(omap4_sar_ram_init); +static struct of_device_id gic_match[] = { + { .compatible = "arm,cortex-a9-gic", }, + { .compatible = "arm,cortex-a15-gic", }, + { }, +}; + +static struct device_node *gic_node; + +unsigned int omap4_xlate_irq(unsigned int hwirq) +{ + struct of_phandle_args irq_data; + unsigned int irq; + + if (!gic_node) + gic_node = of_find_matching_node(NULL, gic_match); + + if (WARN_ON(!gic_node)) + return hwirq; + + irq_data.np = gic_node; + irq_data.args_count = 3; + irq_data.args[0] = 0; + irq_data.args[1] = hwirq - OMAP44XX_IRQ_GIC_START; + irq_data.args[2] = IRQ_TYPE_LEVEL_HIGH; + + irq = irq_create_of_mapping(&irq_data); + if (WARN_ON(!irq)) + irq = hwirq; + + return irq; +} + void __init omap_gic_of_init(void) { struct device_node *np; diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index cbb908dc5cf0..9025ffffd2dc 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -3534,9 +3534,15 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) mpu_irqs_cnt = _count_mpu_irqs(oh); for (i = 0; i < mpu_irqs_cnt; i++) { + unsigned int irq; + + if (oh->xlate_irq) + irq = oh->xlate_irq((oh->mpu_irqs + i)->irq); + else + irq = (oh->mpu_irqs + i)->irq; (res + r)->name = (oh->mpu_irqs + i)->name; - (res + r)->start = (oh->mpu_irqs + i)->irq; - (res + r)->end = (oh->mpu_irqs + i)->irq; + (res + r)->start = irq; + (res + r)->end = irq; (res + r)->flags = IORESOURCE_IRQ; r++; } diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h index 35ca6efbec31..5b42fafcaf55 100644 --- a/arch/arm/mach-omap2/omap_hwmod.h +++ b/arch/arm/mach-omap2/omap_hwmod.h @@ -676,6 +676,7 @@ struct omap_hwmod { spinlock_t _lock; struct list_head node; struct omap_hwmod_ocp_if *_mpu_port; + unsigned int (*xlate_irq)(unsigned int); u16 flags; u8 mpu_rt_idx; u8 response_lat; diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index c314b3c31117..f5e68a782025 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -479,6 +479,7 @@ static struct omap_hwmod omap44xx_dma_system_hwmod = { .class = &omap44xx_dma_hwmod_class, .clkdm_name = "l3_dma_clkdm", .mpu_irqs = omap44xx_dma_system_irqs, + .xlate_irq = omap4_xlate_irq, .main_clk = "l3_div_ck", .prcm = { .omap4 = { @@ -640,6 +641,7 @@ static struct omap_hwmod omap44xx_dss_dispc_hwmod = { .class = &omap44xx_dispc_hwmod_class, .clkdm_name = "l3_dss_clkdm", .mpu_irqs = omap44xx_dss_dispc_irqs, + .xlate_irq = omap4_xlate_irq, .sdma_reqs = omap44xx_dss_dispc_sdma_reqs, .main_clk = "dss_dss_clk", .prcm = { @@ -693,6 +695,7 @@ static struct omap_hwmod omap44xx_dss_dsi1_hwmod = { .class = &omap44xx_dsi_hwmod_class, .clkdm_name = "l3_dss_clkdm", .mpu_irqs = omap44xx_dss_dsi1_irqs, + .xlate_irq = omap4_xlate_irq, .sdma_reqs = omap44xx_dss_dsi1_sdma_reqs, .main_clk = "dss_dss_clk", .prcm = { @@ -726,6 +729,7 @@ static struct omap_hwmod omap44xx_dss_dsi2_hwmod = { .class = &omap44xx_dsi_hwmod_class, .clkdm_name = "l3_dss_clkdm", .mpu_irqs = omap44xx_dss_dsi2_irqs, + .xlate_irq = omap4_xlate_irq, .sdma_reqs = omap44xx_dss_dsi2_sdma_reqs, .main_clk = "dss_dss_clk", .prcm = { @@ -784,6 +788,7 @@ static struct omap_hwmod omap44xx_dss_hdmi_hwmod = { */ .flags = HWMOD_SWSUP_SIDLE, .mpu_irqs = omap44xx_dss_hdmi_irqs, + .xlate_irq = omap4_xlate_irq, .sdma_reqs = omap44xx_dss_hdmi_sdma_reqs, .main_clk = "dss_48mhz_clk", .prcm = { diff --git a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c index 3e9523084b2a..7c3fac035e93 100644 --- a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c @@ -288,6 +288,7 @@ static struct omap_hwmod omap54xx_dma_system_hwmod = { .class = &omap54xx_dma_hwmod_class, .clkdm_name = "dma_clkdm", .mpu_irqs = omap54xx_dma_system_irqs, + .xlate_irq = omap4_xlate_irq, .main_clk = "l3_iclk_div", .prcm = { .omap4 = { diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h index a8e4b582c527..6163d66102a3 100644 --- a/arch/arm/mach-omap2/prcm-common.h +++ b/arch/arm/mach-omap2/prcm-common.h @@ -498,6 +498,7 @@ struct omap_prcm_irq_setup { u8 nr_irqs; const struct omap_prcm_irq *irqs; int irq; + unsigned int (*xlate_irq)(unsigned int); void (*read_pending_irqs)(unsigned long *events); void (*ocp_barrier)(void); void (*save_and_clear_irqen)(u32 *saved_mask); diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index cc170fb81ff7..408c64efb807 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -49,6 +49,7 @@ static struct omap_prcm_irq_setup omap4_prcm_irq_setup = { .irqs = omap4_prcm_irqs, .nr_irqs = ARRAY_SIZE(omap4_prcm_irqs), .irq = 11 + OMAP44XX_IRQ_GIC_START, + .xlate_irq = omap4_xlate_irq, .read_pending_irqs = &omap44xx_prm_read_pending_irqs, .ocp_barrier = &omap44xx_prm_ocp_barrier, .save_and_clear_irqen = &omap44xx_prm_save_and_clear_irqen, @@ -751,8 +752,10 @@ static int omap44xx_prm_late_init(void) } /* Once OMAP4 DT is filled as well */ - if (irq_num >= 0) + if (irq_num >= 0) { omap4_prcm_irq_setup.irq = irq_num; + omap4_prcm_irq_setup.xlate_irq = NULL; + } } omap44xx_prm_enable_io_wakeup(); diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index 779940cb6e56..dea2833ca627 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c @@ -187,6 +187,7 @@ int omap_prcm_event_to_irq(const char *name) */ void omap_prcm_irq_cleanup(void) { + unsigned int irq; int i; if (!prcm_irq_setup) { @@ -211,7 +212,11 @@ void omap_prcm_irq_cleanup(void) kfree(prcm_irq_setup->priority_mask); prcm_irq_setup->priority_mask = NULL; - irq_set_chained_handler(prcm_irq_setup->irq, NULL); + if (prcm_irq_setup->xlate_irq) + irq = prcm_irq_setup->xlate_irq(prcm_irq_setup->irq); + else + irq = prcm_irq_setup->irq; + irq_set_chained_handler(irq, NULL); if (prcm_irq_setup->base_irq > 0) irq_free_descs(prcm_irq_setup->base_irq, @@ -259,6 +264,7 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup) int offset, i; struct irq_chip_generic *gc; struct irq_chip_type *ct; + unsigned int irq; if (!irq_setup) return -EINVAL; @@ -298,7 +304,11 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup) 1 << (offset & 0x1f); } - irq_set_chained_handler(irq_setup->irq, omap_prcm_irq_handler); + if (irq_setup->xlate_irq) + irq = irq_setup->xlate_irq(irq_setup->irq); + else + irq = irq_setup->irq; + irq_set_chained_handler(irq, omap_prcm_irq_handler); irq_setup->base_irq = irq_alloc_descs(-1, 0, irq_setup->nr_regs * 32, 0); diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c index 4457e731f7a4..292eca0e78ed 100644 --- a/arch/arm/mach-omap2/twl-common.c +++ b/arch/arm/mach-omap2/twl-common.c @@ -66,19 +66,24 @@ void __init omap_pmic_init(int bus, u32 clkrate, omap_register_i2c_bus(bus, clkrate, &pmic_i2c_board_info, 1); } +#ifdef CONFIG_ARCH_OMAP4 void __init omap4_pmic_init(const char *pmic_type, struct twl4030_platform_data *pmic_data, struct i2c_board_info *devices, int nr_devices) { /* PMIC part*/ + unsigned int irq; + omap_mux_init_signal("sys_nirq1", OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE); omap_mux_init_signal("fref_clk0_out.sys_drm_msecure", OMAP_PIN_OUTPUT); - omap_pmic_init(1, 400, pmic_type, 7 + OMAP44XX_IRQ_GIC_START, pmic_data); + irq = omap4_xlate_irq(7 + OMAP44XX_IRQ_GIC_START); + omap_pmic_init(1, 400, pmic_type, irq, pmic_data); /* Register additional devices on i2c1 bus if needed */ if (devices) i2c_register_board_info(1, devices, nr_devices); } +#endif void __init omap_pmic_late_init(void) { diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c index d6908569ecaf..09cffed4c0a4 100644 --- a/arch/arm/mach-qcom/platsmp.c +++ b/arch/arm/mach-qcom/platsmp.c @@ -44,7 +44,7 @@ #define APCS_SAW2_VCTL 0x14 #define APCS_SAW2_2_VCTL 0x1c -extern void secondary_startup(void); +extern void secondary_startup_arm(void); static DEFINE_SPINLOCK(boot_lock); @@ -337,7 +337,7 @@ static void __init qcom_smp_prepare_cpus(unsigned int max_cpus) flags |= cold_boot_flags[map]; } - if (scm_set_boot_addr(virt_to_phys(secondary_startup), flags)) { + if (scm_set_boot_addr(virt_to_phys(secondary_startup_arm), flags)) { for_each_present_cpu(cpu) { if (cpu == smp_processor_id()) continue; diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile index f1114d11fe13..61ff91e76e0a 100644 --- a/arch/arm/mach-sa1100/Makefile +++ b/arch/arm/mach-sa1100/Makefile @@ -3,7 +3,7 @@ # # Common support -obj-y := clock.o generic.o irq.o time.o #nmi-oopser.o +obj-y := clock.o generic.o irq.o #nmi-oopser.o # Specific board support obj-$(CONFIG_SA1100_ASSABET) += assabet.o diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index 7dd894ece9ae..d28ecb9ef172 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -37,7 +37,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c index 03c75a811cb0..cbf53bb9c814 100644 --- a/arch/arm/mach-sa1100/clock.c +++ b/arch/arm/mach-sa1100/clock.c @@ -119,6 +119,17 @@ static DEFINE_CLK(gpio27, &clk_gpio27_ops); static DEFINE_CLK(cpu, &clk_cpu_ops); +static unsigned long clk_36864_get_rate(struct clk *clk) +{ + return 3686400; +} + +static struct clkops clk_36864_ops = { + .get_rate = clk_36864_get_rate, +}; + +static DEFINE_CLK(36864, &clk_36864_ops); + static struct clk_lookup sa11xx_clkregs[] = { CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27), CLKDEV_INIT("sa1100-rtc", NULL, NULL), @@ -126,6 +137,7 @@ static struct clk_lookup sa11xx_clkregs[] = { CLKDEV_INIT("sa11x0-pcmcia", NULL, &clk_cpu), /* sa1111 names devices using internal offsets, PCMCIA is at 0x1800 */ CLKDEV_INIT("1800", NULL, &clk_cpu), + CLKDEV_INIT(NULL, "OSTIMER0", &clk_36864), }; static int __init sa11xx_clk_init(void) diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index b90c7d828391..3cc2b71e16f0 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include @@ -371,8 +371,7 @@ static void __init collie_init(void) PPC_LDD6 | PPC_LDD7 | PPC_L_PCLK | PPC_L_LCLK | PPC_L_FCLK | PPC_L_BIAS | PPC_TXD1 | PPC_TXD2 | PPC_TXD3 | PPC_TXD4 | PPC_SCLK | PPC_SFRM; - PWER = _COLLIE_GPIO_AC_IN | _COLLIE_GPIO_CO | _COLLIE_GPIO_ON_KEY | - _COLLIE_GPIO_WAKEUP | _COLLIE_GPIO_nREMOCON_INT | PWER_RTC; + PWER = 0; PGSR = _COLLIE_GPIO_nREMOCON_ON; diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index d4ea142c4edd..40e0d8619a2d 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -33,6 +33,7 @@ #include #include "generic.h" +#include unsigned int reset_status; EXPORT_SYMBOL(reset_status); @@ -369,6 +370,11 @@ void __init sa1100_map_io(void) iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc)); } +void __init sa1100_timer_init(void) +{ + pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x90000000), 3686400); +} + /* * Disable the memory bus request/grant signals on the SA1110 to * ensure that we don't receive spurious memory requests. We set diff --git a/arch/arm/mach-sa1100/h3100.c b/arch/arm/mach-sa1100/h3100.c index 3c43219bc881..c6b412054a3c 100644 --- a/arch/arm/mach-sa1100/h3100.c +++ b/arch/arm/mach-sa1100/h3100.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c index 5be54c214c7c..118338efd790 100644 --- a/arch/arm/mach-sa1100/h3600.c +++ b/arch/arm/mach-sa1100/h3600.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-sa1100/include/mach/irqs.h b/arch/arm/mach-sa1100/include/mach/irqs.h index de0983494c7e..734e30e406a3 100644 --- a/arch/arm/mach-sa1100/include/mach/irqs.h +++ b/arch/arm/mach-sa1100/include/mach/irqs.h @@ -8,17 +8,17 @@ * 2001/11/14 RMK Cleaned up and standardised a lot of the IRQs. */ -#define IRQ_GPIO0 1 -#define IRQ_GPIO1 2 -#define IRQ_GPIO2 3 -#define IRQ_GPIO3 4 -#define IRQ_GPIO4 5 -#define IRQ_GPIO5 6 -#define IRQ_GPIO6 7 -#define IRQ_GPIO7 8 -#define IRQ_GPIO8 9 -#define IRQ_GPIO9 10 -#define IRQ_GPIO10 11 +#define IRQ_GPIO0_SC 1 +#define IRQ_GPIO1_SC 2 +#define IRQ_GPIO2_SC 3 +#define IRQ_GPIO3_SC 4 +#define IRQ_GPIO4_SC 5 +#define IRQ_GPIO5_SC 6 +#define IRQ_GPIO6_SC 7 +#define IRQ_GPIO7_SC 8 +#define IRQ_GPIO8_SC 9 +#define IRQ_GPIO9_SC 10 +#define IRQ_GPIO10_SC 11 #define IRQ_GPIO11_27 12 #define IRQ_LCD 13 /* LCD controller */ #define IRQ_Ser0UDC 14 /* Ser. port 0 UDC */ @@ -41,32 +41,43 @@ #define IRQ_RTC1Hz 31 /* RTC 1 Hz clock */ #define IRQ_RTCAlrm 32 /* RTC Alarm */ -#define IRQ_GPIO11 33 -#define IRQ_GPIO12 34 -#define IRQ_GPIO13 35 -#define IRQ_GPIO14 36 -#define IRQ_GPIO15 37 -#define IRQ_GPIO16 38 -#define IRQ_GPIO17 39 -#define IRQ_GPIO18 40 -#define IRQ_GPIO19 41 -#define IRQ_GPIO20 42 -#define IRQ_GPIO21 43 -#define IRQ_GPIO22 44 -#define IRQ_GPIO23 45 -#define IRQ_GPIO24 46 -#define IRQ_GPIO25 47 -#define IRQ_GPIO26 48 -#define IRQ_GPIO27 49 +#define IRQ_GPIO0 33 +#define IRQ_GPIO1 34 +#define IRQ_GPIO2 35 +#define IRQ_GPIO3 36 +#define IRQ_GPIO4 37 +#define IRQ_GPIO5 38 +#define IRQ_GPIO6 39 +#define IRQ_GPIO7 40 +#define IRQ_GPIO8 41 +#define IRQ_GPIO9 42 +#define IRQ_GPIO10 43 +#define IRQ_GPIO11 44 +#define IRQ_GPIO12 45 +#define IRQ_GPIO13 46 +#define IRQ_GPIO14 47 +#define IRQ_GPIO15 48 +#define IRQ_GPIO16 49 +#define IRQ_GPIO17 50 +#define IRQ_GPIO18 51 +#define IRQ_GPIO19 52 +#define IRQ_GPIO20 53 +#define IRQ_GPIO21 54 +#define IRQ_GPIO22 55 +#define IRQ_GPIO23 56 +#define IRQ_GPIO24 57 +#define IRQ_GPIO25 58 +#define IRQ_GPIO26 59 +#define IRQ_GPIO27 60 /* * The next 16 interrupts are for board specific purposes. Since * the kernel can only run on one machine at a time, we can re-use * these. If you need more, increase IRQ_BOARD_END, but keep it - * within sensible limits. IRQs 49 to 64 are available. + * within sensible limits. IRQs 61 to 76 are available. */ -#define IRQ_BOARD_START 50 -#define IRQ_BOARD_END 66 +#define IRQ_BOARD_START 61 +#define IRQ_BOARD_END 77 /* * Figure out the MAX IRQ number. diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c index 63e2901db416..65aebfa66fe5 100644 --- a/arch/arm/mach-sa1100/irq.c +++ b/arch/arm/mach-sa1100/irq.c @@ -80,170 +80,6 @@ static struct irq_domain_ops sa1100_normal_irqdomain_ops = { static struct irq_domain *sa1100_normal_irqdomain; -/* - * SA1100 GPIO edge detection for IRQs: - * IRQs are generated on Falling-Edge, Rising-Edge, or both. - * Use this instead of directly setting GRER/GFER. - */ -static int GPIO_IRQ_rising_edge; -static int GPIO_IRQ_falling_edge; -static int GPIO_IRQ_mask = (1 << 11) - 1; - -static int sa1100_gpio_type(struct irq_data *d, unsigned int type) -{ - unsigned int mask; - - mask = BIT(d->hwirq); - - if (type == IRQ_TYPE_PROBE) { - if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask) - return 0; - type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; - } - - if (type & IRQ_TYPE_EDGE_RISING) { - GPIO_IRQ_rising_edge |= mask; - } else - GPIO_IRQ_rising_edge &= ~mask; - if (type & IRQ_TYPE_EDGE_FALLING) { - GPIO_IRQ_falling_edge |= mask; - } else - GPIO_IRQ_falling_edge &= ~mask; - - GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; - GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; - - return 0; -} - -/* - * GPIO IRQs must be acknowledged. - */ -static void sa1100_gpio_ack(struct irq_data *d) -{ - GEDR = BIT(d->hwirq); -} - -static int sa1100_gpio_wake(struct irq_data *d, unsigned int on) -{ - if (on) - PWER |= BIT(d->hwirq); - else - PWER &= ~BIT(d->hwirq); - return 0; -} - -/* - * This is for IRQs from 0 to 10. - */ -static struct irq_chip sa1100_low_gpio_chip = { - .name = "GPIO-l", - .irq_ack = sa1100_gpio_ack, - .irq_mask = sa1100_mask_irq, - .irq_unmask = sa1100_unmask_irq, - .irq_set_type = sa1100_gpio_type, - .irq_set_wake = sa1100_gpio_wake, -}; - -static int sa1100_low_gpio_irqdomain_map(struct irq_domain *d, - unsigned int irq, irq_hw_number_t hwirq) -{ - irq_set_chip_and_handler(irq, &sa1100_low_gpio_chip, - handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - - return 0; -} - -static struct irq_domain_ops sa1100_low_gpio_irqdomain_ops = { - .map = sa1100_low_gpio_irqdomain_map, - .xlate = irq_domain_xlate_onetwocell, -}; - -static struct irq_domain *sa1100_low_gpio_irqdomain; - -/* - * IRQ11 (GPIO11 through 27) handler. We enter here with the - * irq_controller_lock held, and IRQs disabled. Decode the IRQ - * and call the handler. - */ -static void -sa1100_high_gpio_handler(unsigned int irq, struct irq_desc *desc) -{ - unsigned int mask; - - mask = GEDR & 0xfffff800; - do { - /* - * clear down all currently active IRQ sources. - * We will be processing them all. - */ - GEDR = mask; - - irq = IRQ_GPIO11; - mask >>= 11; - do { - if (mask & 1) - generic_handle_irq(irq); - mask >>= 1; - irq++; - } while (mask); - - mask = GEDR & 0xfffff800; - } while (mask); -} - -/* - * Like GPIO0 to 10, GPIO11-27 IRQs need to be handled specially. - * In addition, the IRQs are all collected up into one bit in the - * interrupt controller registers. - */ -static void sa1100_high_gpio_mask(struct irq_data *d) -{ - unsigned int mask = BIT(d->hwirq); - - GPIO_IRQ_mask &= ~mask; - - GRER &= ~mask; - GFER &= ~mask; -} - -static void sa1100_high_gpio_unmask(struct irq_data *d) -{ - unsigned int mask = BIT(d->hwirq); - - GPIO_IRQ_mask |= mask; - - GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; - GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; -} - -static struct irq_chip sa1100_high_gpio_chip = { - .name = "GPIO-h", - .irq_ack = sa1100_gpio_ack, - .irq_mask = sa1100_high_gpio_mask, - .irq_unmask = sa1100_high_gpio_unmask, - .irq_set_type = sa1100_gpio_type, - .irq_set_wake = sa1100_gpio_wake, -}; - -static int sa1100_high_gpio_irqdomain_map(struct irq_domain *d, - unsigned int irq, irq_hw_number_t hwirq) -{ - irq_set_chip_and_handler(irq, &sa1100_high_gpio_chip, - handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - - return 0; -} - -static struct irq_domain_ops sa1100_high_gpio_irqdomain_ops = { - .map = sa1100_high_gpio_irqdomain_map, - .xlate = irq_domain_xlate_onetwocell, -}; - -static struct irq_domain *sa1100_high_gpio_irqdomain; - static struct resource irq_resource = DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs"); @@ -270,17 +106,6 @@ static int sa1100irq_suspend(void) IC_GPIO6|IC_GPIO5|IC_GPIO4|IC_GPIO3|IC_GPIO2| IC_GPIO1|IC_GPIO0); - /* - * Set the appropriate edges for wakeup. - */ - GRER = PWER & GPIO_IRQ_rising_edge; - GFER = PWER & GPIO_IRQ_falling_edge; - - /* - * Clear any pending GPIO interrupts. - */ - GEDR = GEDR; - return 0; } @@ -292,9 +117,6 @@ static void sa1100irq_resume(void) ICCR = st->iccr; ICLR = st->iclr; - GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; - GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; - ICMR = st->icmr; } } @@ -325,7 +147,8 @@ sa1100_handle_irq(struct pt_regs *regs) if (mask == 0) break; - handle_IRQ(ffs(mask) - 1 + IRQ_GPIO0, regs); + handle_domain_irq(sa1100_normal_irqdomain, + ffs(mask) - 1, regs); } while (1); } @@ -339,34 +162,16 @@ void __init sa1100_init_irq(void) /* all IRQs are IRQ, not FIQ */ ICLR = 0; - /* clear all GPIO edge detects */ - GFER = 0; - GRER = 0; - GEDR = -1; - /* * Whatever the doc says, this has to be set for the wait-on-irq * instruction to work... on a SA1100 rev 9 at least. */ ICCR = 1; - sa1100_low_gpio_irqdomain = irq_domain_add_legacy(NULL, - 11, IRQ_GPIO0, 0, - &sa1100_low_gpio_irqdomain_ops, NULL); - - sa1100_normal_irqdomain = irq_domain_add_legacy(NULL, - 21, IRQ_GPIO11_27, 11, + sa1100_normal_irqdomain = irq_domain_add_simple(NULL, + 32, IRQ_GPIO0_SC, &sa1100_normal_irqdomain_ops, NULL); - sa1100_high_gpio_irqdomain = irq_domain_add_legacy(NULL, - 17, IRQ_GPIO11, 11, - &sa1100_high_gpio_irqdomain_ops, NULL); - - /* - * Install handler for GPIO 11-27 edge detect interrupts - */ - irq_set_chained_handler(IRQ_GPIO11_27, sa1100_high_gpio_handler); - set_handle_irq(sa1100_handle_irq); sa1100_init_gpio(); diff --git a/arch/arm/mach-sa1100/pci-nanoengine.c b/arch/arm/mach-sa1100/pci-nanoengine.c index b704433c529c..d7ae8d50f6d8 100644 --- a/arch/arm/mach-sa1100/pci-nanoengine.c +++ b/arch/arm/mach-sa1100/pci-nanoengine.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -30,97 +29,20 @@ #include #include -static DEFINE_SPINLOCK(nano_lock); - -static int nanoengine_get_pci_address(struct pci_bus *bus, - unsigned int devfn, int where, void __iomem **address) +static void __iomem *nanoengine_pci_map_bus(struct pci_bus *bus, + unsigned int devfn, int where) { - int ret = PCIBIOS_DEVICE_NOT_FOUND; - unsigned int busnr = bus->number; + if (bus->number != 0 || (devfn >> 3) != 0) + return NULL; - *address = (void __iomem *)NANO_PCI_CONFIG_SPACE_VIRT + + return (void __iomem *)NANO_PCI_CONFIG_SPACE_VIRT + ((bus->number << 16) | (devfn << 8) | (where & ~3)); - - ret = (busnr > 255 || devfn > 255 || where > 255) ? - PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; - - return ret; -} - -static int nanoengine_read_config(struct pci_bus *bus, unsigned int devfn, int where, - int size, u32 *val) -{ - int ret; - void __iomem *address; - unsigned long flags; - u32 v; - - /* nanoEngine PCI bridge does not return -1 for a non-existing - * device. We must fake the answer. We know that the only valid - * device is device zero at bus 0, which is the network chip. */ - if (bus->number != 0 || (devfn >> 3) != 0) { - v = -1; - nanoengine_get_pci_address(bus, devfn, where, &address); - goto exit_function; - } - - spin_lock_irqsave(&nano_lock, flags); - - ret = nanoengine_get_pci_address(bus, devfn, where, &address); - if (ret != PCIBIOS_SUCCESSFUL) - return ret; - v = __raw_readl(address); - - spin_unlock_irqrestore(&nano_lock, flags); - - v >>= ((where & 3) * 8); - v &= (unsigned long)(-1) >> ((4 - size) * 8); - -exit_function: - *val = v; - return PCIBIOS_SUCCESSFUL; -} - -static int nanoengine_write_config(struct pci_bus *bus, unsigned int devfn, int where, - int size, u32 val) -{ - int ret; - void __iomem *address; - unsigned long flags; - unsigned shift; - u32 v; - - shift = (where & 3) * 8; - - spin_lock_irqsave(&nano_lock, flags); - - ret = nanoengine_get_pci_address(bus, devfn, where, &address); - if (ret != PCIBIOS_SUCCESSFUL) - return ret; - v = __raw_readl(address); - switch (size) { - case 1: - v &= ~(0xFF << shift); - v |= val << shift; - break; - case 2: - v &= ~(0xFFFF << shift); - v |= val << shift; - break; - case 4: - v = val; - break; - } - __raw_writel(v, address); - - spin_unlock_irqrestore(&nano_lock, flags); - - return PCIBIOS_SUCCESSFUL; } static struct pci_ops pci_nano_ops = { - .read = nanoengine_read_config, - .write = nanoengine_write_config, + .map_bus = nanoengine_pci_map_bus, + .read = pci_generic_config_read32, + .write = pci_generic_config_write32, }; static int __init pci_nanoengine_map_irq(const struct pci_dev *dev, u8 slot, diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c index 6645d1e31f14..34853d5dfda2 100644 --- a/arch/arm/mach-sa1100/pm.c +++ b/arch/arm/mach-sa1100/pm.c @@ -81,6 +81,7 @@ static int sa11x0_pm_enter(suspend_state_t state) /* * Ensure not to come back here if it wasn't intended */ + RCSR = RCSR_SMR; PSPR = 0; /* diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c deleted file mode 100644 index 1dea6cfafb31..000000000000 --- a/arch/arm/mach-sa1100/time.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/time.c - * - * Copyright (C) 1998 Deborah Wallach. - * Twiddles (C) 1999 Hugo Fiennes - * - * 2000/03/29 (C) Nicolas Pitre - * Rewritten: big cleanup, much simpler, better HZ accuracy. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define SA1100_CLOCK_FREQ 3686400 -#define SA1100_LATCH DIV_ROUND_CLOSEST(SA1100_CLOCK_FREQ, HZ) - -static u64 notrace sa1100_read_sched_clock(void) -{ - return readl_relaxed(OSCR); -} - -#define MIN_OSCR_DELTA 2 - -static irqreturn_t sa1100_ost0_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *c = dev_id; - - /* Disarm the compare/match, signal the event. */ - writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER); - writel_relaxed(OSSR_M0, OSSR); - c->event_handler(c); - - return IRQ_HANDLED; -} - -static int -sa1100_osmr0_set_next_event(unsigned long delta, struct clock_event_device *c) -{ - unsigned long next, oscr; - - writel_relaxed(readl_relaxed(OIER) | OIER_E0, OIER); - next = readl_relaxed(OSCR) + delta; - writel_relaxed(next, OSMR0); - oscr = readl_relaxed(OSCR); - - return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0; -} - -static void -sa1100_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *c) -{ - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER); - writel_relaxed(OSSR_M0, OSSR); - break; - - case CLOCK_EVT_MODE_RESUME: - case CLOCK_EVT_MODE_PERIODIC: - break; - } -} - -#ifdef CONFIG_PM -unsigned long osmr[4], oier; - -static void sa1100_timer_suspend(struct clock_event_device *cedev) -{ - osmr[0] = readl_relaxed(OSMR0); - osmr[1] = readl_relaxed(OSMR1); - osmr[2] = readl_relaxed(OSMR2); - osmr[3] = readl_relaxed(OSMR3); - oier = readl_relaxed(OIER); -} - -static void sa1100_timer_resume(struct clock_event_device *cedev) -{ - writel_relaxed(0x0f, OSSR); - writel_relaxed(osmr[0], OSMR0); - writel_relaxed(osmr[1], OSMR1); - writel_relaxed(osmr[2], OSMR2); - writel_relaxed(osmr[3], OSMR3); - writel_relaxed(oier, OIER); - - /* - * OSMR0 is the system timer: make sure OSCR is sufficiently behind - */ - writel_relaxed(OSMR0 - SA1100_LATCH, OSCR); -} -#else -#define sa1100_timer_suspend NULL -#define sa1100_timer_resume NULL -#endif - -static struct clock_event_device ckevt_sa1100_osmr0 = { - .name = "osmr0", - .features = CLOCK_EVT_FEAT_ONESHOT, - .rating = 200, - .set_next_event = sa1100_osmr0_set_next_event, - .set_mode = sa1100_osmr0_set_mode, - .suspend = sa1100_timer_suspend, - .resume = sa1100_timer_resume, -}; - -static struct irqaction sa1100_timer_irq = { - .name = "ost0", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = sa1100_ost0_interrupt, - .dev_id = &ckevt_sa1100_osmr0, -}; - -void __init sa1100_timer_init(void) -{ - writel_relaxed(0, OIER); - writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR); - - sched_clock_register(sa1100_read_sched_clock, 32, 3686400); - - ckevt_sa1100_osmr0.cpumask = cpumask_of(0); - - setup_irq(IRQ_OST0, &sa1100_timer_irq); - - clocksource_mmio_init(OSCR, "oscr", SA1100_CLOCK_FREQ, 200, 32, - clocksource_mmio_readl_up); - clockevents_config_and_register(&ckevt_sa1100_osmr0, 3686400, - MIN_OSCR_DELTA * 2, 0x7fffffff); -} diff --git a/arch/arm/mach-shmobile/board-ape6evm.c b/arch/arm/mach-shmobile/board-ape6evm.c index 66f67816a844..444f22d370f0 100644 --- a/arch/arm/mach-shmobile/board-ape6evm.c +++ b/arch/arm/mach-shmobile/board-ape6evm.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -273,6 +275,22 @@ static void __init ape6evm_add_standard_devices(void) sizeof(ape6evm_leds_pdata)); } +static void __init ape6evm_legacy_init_time(void) +{ + /* Do not invoke DT-based timers via clocksource_of_init() */ +} + +static void __init ape6evm_legacy_init_irq(void) +{ + void __iomem *gic_dist_base = ioremap_nocache(0xf1001000, 0x1000); + void __iomem *gic_cpu_base = ioremap_nocache(0xf1002000, 0x1000); + + gic_init(0, 29, gic_dist_base, gic_cpu_base); + + /* Do not invoke DT-based interrupt code via irqchip_init() */ +} + + static const char *ape6evm_boards_compat_dt[] __initdata = { "renesas,ape6evm", NULL, @@ -280,7 +298,9 @@ static const char *ape6evm_boards_compat_dt[] __initdata = { DT_MACHINE_START(APE6EVM_DT, "ape6evm") .init_early = shmobile_init_delay, + .init_irq = ape6evm_legacy_init_irq, .init_machine = ape6evm_add_standard_devices, .init_late = shmobile_init_late, .dt_compat = ape6evm_boards_compat_dt, + .init_time = ape6evm_legacy_init_time, MACHINE_END diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index f8197eb6e566..65b128dd4072 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include #include @@ -811,6 +813,16 @@ static void __init lager_init(void) lager_ksz8041_fixup); } +static void __init lager_legacy_init_irq(void) +{ + void __iomem *gic_dist_base = ioremap_nocache(0xf1001000, 0x1000); + void __iomem *gic_cpu_base = ioremap_nocache(0xf1002000, 0x1000); + + gic_init(0, 29, gic_dist_base, gic_cpu_base); + + /* Do not invoke DT-based interrupt code via irqchip_init() */ +} + static const char * const lager_boards_compat_dt[] __initconst = { "renesas,lager", NULL, @@ -819,6 +831,7 @@ static const char * const lager_boards_compat_dt[] __initconst = { DT_MACHINE_START(LAGER_DT, "lager") .smp = smp_ops(r8a7790_smp_ops), .init_early = shmobile_init_delay, + .init_irq = lager_legacy_init_irq, .init_time = rcar_gen2_timer_init, .init_machine = lager_init, .init_late = shmobile_init_late, diff --git a/arch/arm/mach-shmobile/setup-r8a7778.c b/arch/arm/mach-shmobile/setup-r8a7778.c index 170bd146ba17..cef8895a9b82 100644 --- a/arch/arm/mach-shmobile/setup-r8a7778.c +++ b/arch/arm/mach-shmobile/setup-r8a7778.c @@ -576,11 +576,18 @@ void __init r8a7778_init_irq_extpin(int irlm) void __init r8a7778_init_irq_dt(void) { void __iomem *base = ioremap_nocache(0xfe700000, 0x00100000); +#ifdef CONFIG_ARCH_SHMOBILE_LEGACY + void __iomem *gic_dist_base = ioremap_nocache(0xfe438000, 0x1000); + void __iomem *gic_cpu_base = ioremap_nocache(0xfe430000, 0x1000); +#endif BUG_ON(!base); +#ifdef CONFIG_ARCH_SHMOBILE_LEGACY + gic_init(0, 29, gic_dist_base, gic_cpu_base); +#else irqchip_init(); - +#endif /* route all interrupts to ARM */ __raw_writel(0x73ffffff, base + INT2NTSR0); __raw_writel(0xffffffff, base + INT2NTSR1); diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c index 6156d172cf31..27dceaf9e688 100644 --- a/arch/arm/mach-shmobile/setup-r8a7779.c +++ b/arch/arm/mach-shmobile/setup-r8a7779.c @@ -720,10 +720,17 @@ static int r8a7779_set_wake(struct irq_data *data, unsigned int on) void __init r8a7779_init_irq_dt(void) { +#ifdef CONFIG_ARCH_SHMOBILE_LEGACY + void __iomem *gic_dist_base = ioremap_nocache(0xf0001000, 0x1000); + void __iomem *gic_cpu_base = ioremap_nocache(0xf0000100, 0x1000); +#endif gic_arch_extn.irq_set_wake = r8a7779_set_wake; +#ifdef CONFIG_ARCH_SHMOBILE_LEGACY + gic_init(0, 29, gic_dist_base, gic_cpu_base); +#else irqchip_init(); - +#endif /* route all interrupts to ARM */ __raw_writel(0xffffffff, INT2NTSR0); __raw_writel(0x3fffffff, INT2NTSR1); diff --git a/arch/arm/mach-shmobile/setup-rcar-gen2.c b/arch/arm/mach-shmobile/setup-rcar-gen2.c index 3dd6edd9bd1d..cc9470dfb1ce 100644 --- a/arch/arm/mach-shmobile/setup-rcar-gen2.c +++ b/arch/arm/mach-shmobile/setup-rcar-gen2.c @@ -133,7 +133,9 @@ void __init rcar_gen2_timer_init(void) #ifdef CONFIG_COMMON_CLK rcar_gen2_clocks_init(mode); #endif +#ifdef CONFIG_ARCH_SHMOBILE_MULTI clocksource_of_init(); +#endif } struct memory_reserve_config { diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c index f1d027aa7a81..0edf2a6d2bbe 100644 --- a/arch/arm/mach-shmobile/timer.c +++ b/arch/arm/mach-shmobile/timer.c @@ -70,6 +70,18 @@ void __init shmobile_init_delay(void) if (!max_freq) return; +#ifdef CONFIG_ARCH_SHMOBILE_LEGACY + /* Non-multiplatform r8a73a4 SoC cannot use arch timer due + * to GIC being initialized from C and arch timer via DT */ + if (of_machine_is_compatible("renesas,r8a73a4")) + has_arch_timer = false; + + /* Non-multiplatform r8a7790 SoC cannot use arch timer due + * to GIC being initialized from C and arch timer via DT */ + if (of_machine_is_compatible("renesas,r8a7790")) + has_arch_timer = false; +#endif + if (!has_arch_timer || !IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) { if (is_a7_a8_a9) shmobile_setup_delay_hz(max_freq, 1, 3); diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 03823e784f63..c43c71455566 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -1012,6 +1012,7 @@ config ARCH_SUPPORTS_BIG_ENDIAN config ARM_KERNMEM_PERMS bool "Restrict kernel memory permissions" + depends on MMU help If this is set, kernel memory other than kernel text (and rodata) will be made non-executable. The tradeoff is that each region is diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 5e65ca8dea62..c6c7696b8db9 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -1,5 +1,5 @@ /* - * arch/arm/mm/cache-l2x0.c - L210/L220 cache controller support + * arch/arm/mm/cache-l2x0.c - L210/L220/L310 cache controller support * * Copyright (C) 2007 ARM Limited * @@ -41,12 +41,14 @@ struct l2c_init_data { void (*enable)(void __iomem *, u32, unsigned); void (*fixup)(void __iomem *, u32, struct outer_cache_fns *); void (*save)(void __iomem *); + void (*configure)(void __iomem *); struct outer_cache_fns outer_cache; }; #define CACHE_LINE_SIZE 32 static void __iomem *l2x0_base; +static const struct l2c_init_data *l2x0_data; static DEFINE_RAW_SPINLOCK(l2x0_lock); static u32 l2x0_way_mask; /* Bitmask of active ways */ static u32 l2x0_size; @@ -106,6 +108,19 @@ static inline void l2c_unlock(void __iomem *base, unsigned num) } } +static void l2c_configure(void __iomem *base) +{ + if (outer_cache.configure) { + outer_cache.configure(&l2x0_saved_regs); + return; + } + + if (l2x0_data->configure) + l2x0_data->configure(base); + + l2c_write_sec(l2x0_saved_regs.aux_ctrl, base, L2X0_AUX_CTRL); +} + /* * Enable the L2 cache controller. This function must only be * called when the cache controller is known to be disabled. @@ -114,7 +129,12 @@ static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock) { unsigned long flags; - l2c_write_sec(aux, base, L2X0_AUX_CTRL); + /* Do not touch the controller if already enabled. */ + if (readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN) + return; + + l2x0_saved_regs.aux_ctrl = aux; + l2c_configure(base); l2c_unlock(base, num_lock); @@ -136,78 +156,16 @@ static void l2c_disable(void) dsb(st); } -#ifdef CONFIG_CACHE_PL310 -static inline void cache_wait(void __iomem *reg, unsigned long mask) -{ - /* cache operations by line are atomic on PL310 */ -} -#else -#define cache_wait l2c_wait_mask -#endif - -static inline void cache_sync(void) -{ - void __iomem *base = l2x0_base; - - writel_relaxed(0, base + sync_reg_offset); - cache_wait(base + L2X0_CACHE_SYNC, 1); -} - -#if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915) -static inline void debug_writel(unsigned long val) -{ - l2c_set_debug(l2x0_base, val); -} -#else -/* Optimised out for non-errata case */ -static inline void debug_writel(unsigned long val) -{ -} -#endif - -static void l2x0_cache_sync(void) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&l2x0_lock, flags); - cache_sync(); - raw_spin_unlock_irqrestore(&l2x0_lock, flags); -} - -static void __l2x0_flush_all(void) -{ - debug_writel(0x03); - __l2c_op_way(l2x0_base + L2X0_CLEAN_INV_WAY); - cache_sync(); - debug_writel(0x00); -} - -static void l2x0_flush_all(void) -{ - unsigned long flags; - - /* clean all ways */ - raw_spin_lock_irqsave(&l2x0_lock, flags); - __l2x0_flush_all(); - raw_spin_unlock_irqrestore(&l2x0_lock, flags); -} - -static void l2x0_disable(void) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&l2x0_lock, flags); - __l2x0_flush_all(); - l2c_write_sec(0, l2x0_base, L2X0_CTRL); - dsb(st); - raw_spin_unlock_irqrestore(&l2x0_lock, flags); -} - static void l2c_save(void __iomem *base) { l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); } +static void l2c_resume(void) +{ + l2c_enable(l2x0_base, l2x0_saved_regs.aux_ctrl, l2x0_data->num_lock); +} + /* * L2C-210 specific code. * @@ -288,14 +246,6 @@ static void l2c210_sync(void) __l2c210_cache_sync(l2x0_base); } -static void l2c210_resume(void) -{ - void __iomem *base = l2x0_base; - - if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) - l2c_enable(base, l2x0_saved_regs.aux_ctrl, 1); -} - static const struct l2c_init_data l2c210_data __initconst = { .type = "L2C-210", .way_size_0 = SZ_8K, @@ -309,7 +259,7 @@ static const struct l2c_init_data l2c210_data __initconst = { .flush_all = l2c210_flush_all, .disable = l2c_disable, .sync = l2c210_sync, - .resume = l2c210_resume, + .resume = l2c_resume, }, }; @@ -466,7 +416,7 @@ static const struct l2c_init_data l2c220_data = { .flush_all = l2c220_flush_all, .disable = l2c_disable, .sync = l2c220_sync, - .resume = l2c210_resume, + .resume = l2c_resume, }, }; @@ -615,39 +565,29 @@ static void __init l2c310_save(void __iomem *base) L310_POWER_CTRL); } -static void l2c310_resume(void) +static void l2c310_configure(void __iomem *base) { - void __iomem *base = l2x0_base; + unsigned revision; - if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) { - unsigned revision; + /* restore pl310 setup */ + l2c_write_sec(l2x0_saved_regs.tag_latency, base, + L310_TAG_LATENCY_CTRL); + l2c_write_sec(l2x0_saved_regs.data_latency, base, + L310_DATA_LATENCY_CTRL); + l2c_write_sec(l2x0_saved_regs.filter_end, base, + L310_ADDR_FILTER_END); + l2c_write_sec(l2x0_saved_regs.filter_start, base, + L310_ADDR_FILTER_START); - /* restore pl310 setup */ - writel_relaxed(l2x0_saved_regs.tag_latency, - base + L310_TAG_LATENCY_CTRL); - writel_relaxed(l2x0_saved_regs.data_latency, - base + L310_DATA_LATENCY_CTRL); - writel_relaxed(l2x0_saved_regs.filter_end, - base + L310_ADDR_FILTER_END); - writel_relaxed(l2x0_saved_regs.filter_start, - base + L310_ADDR_FILTER_START); + revision = readl_relaxed(base + L2X0_CACHE_ID) & + L2X0_CACHE_ID_RTL_MASK; - revision = readl_relaxed(base + L2X0_CACHE_ID) & - L2X0_CACHE_ID_RTL_MASK; - - if (revision >= L310_CACHE_ID_RTL_R2P0) - l2c_write_sec(l2x0_saved_regs.prefetch_ctrl, base, - L310_PREFETCH_CTRL); - if (revision >= L310_CACHE_ID_RTL_R3P0) - l2c_write_sec(l2x0_saved_regs.pwr_ctrl, base, - L310_POWER_CTRL); - - l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8); - - /* Re-enable full-line-of-zeros for Cortex-A9 */ - if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO) - set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); - } + if (revision >= L310_CACHE_ID_RTL_R2P0) + l2c_write_sec(l2x0_saved_regs.prefetch_ctrl, base, + L310_PREFETCH_CTRL); + if (revision >= L310_CACHE_ID_RTL_R3P0) + l2c_write_sec(l2x0_saved_regs.pwr_ctrl, base, + L310_POWER_CTRL); } static int l2c310_cpu_enable_flz(struct notifier_block *nb, unsigned long act, void *data) @@ -699,6 +639,23 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock) aux &= ~(L310_AUX_CTRL_FULL_LINE_ZERO | L310_AUX_CTRL_EARLY_BRESP); } + /* r3p0 or later has power control register */ + if (rev >= L310_CACHE_ID_RTL_R3P0) + l2x0_saved_regs.pwr_ctrl = L310_DYNAMIC_CLK_GATING_EN | + L310_STNDBY_MODE_EN; + + /* + * Always enable non-secure access to the lockdown registers - + * we write to them as part of the L2C enable sequence so they + * need to be accessible. + */ + aux |= L310_AUX_CTRL_NS_LOCKDOWN; + + l2c_enable(base, aux, num_lock); + + /* Read back resulting AUX_CTRL value as it could have been altered. */ + aux = readl_relaxed(base + L2X0_AUX_CTRL); + if (aux & (L310_AUX_CTRL_DATA_PREFETCH | L310_AUX_CTRL_INSTR_PREFETCH)) { u32 prefetch = readl_relaxed(base + L310_PREFETCH_CTRL); @@ -712,23 +669,12 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock) if (rev >= L310_CACHE_ID_RTL_R3P0) { u32 power_ctrl; - l2c_write_sec(L310_DYNAMIC_CLK_GATING_EN | L310_STNDBY_MODE_EN, - base, L310_POWER_CTRL); power_ctrl = readl_relaxed(base + L310_POWER_CTRL); pr_info("L2C-310 dynamic clock gating %sabled, standby mode %sabled\n", power_ctrl & L310_DYNAMIC_CLK_GATING_EN ? "en" : "dis", power_ctrl & L310_STNDBY_MODE_EN ? "en" : "dis"); } - /* - * Always enable non-secure access to the lockdown registers - - * we write to them as part of the L2C enable sequence so they - * need to be accessible. - */ - aux |= L310_AUX_CTRL_NS_LOCKDOWN; - - l2c_enable(base, aux, num_lock); - if (aux & L310_AUX_CTRL_FULL_LINE_ZERO) { set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); cpu_notifier(l2c310_cpu_enable_flz, 0); @@ -760,11 +706,11 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id, if (revision >= L310_CACHE_ID_RTL_R3P0 && revision < L310_CACHE_ID_RTL_R3P2) { - u32 val = readl_relaxed(base + L310_PREFETCH_CTRL); + u32 val = l2x0_saved_regs.prefetch_ctrl; /* I don't think bit23 is required here... but iMX6 does so */ if (val & (BIT(30) | BIT(23))) { val &= ~(BIT(30) | BIT(23)); - l2c_write_sec(val, base, L310_PREFETCH_CTRL); + l2x0_saved_regs.prefetch_ctrl = val; errata[n++] = "752271"; } } @@ -800,6 +746,15 @@ static void l2c310_disable(void) l2c_disable(); } +static void l2c310_resume(void) +{ + l2c_resume(); + + /* Re-enable full-line-of-zeros for Cortex-A9 */ + if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO) + set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); +} + static const struct l2c_init_data l2c310_init_fns __initconst = { .type = "L2C-310", .way_size_0 = SZ_8K, @@ -807,6 +762,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = { .enable = l2c310_enable, .fixup = l2c310_fixup, .save = l2c310_save, + .configure = l2c310_configure, .outer_cache = { .inv_range = l2c210_inv_range, .clean_range = l2c210_clean_range, @@ -818,13 +774,21 @@ static const struct l2c_init_data l2c310_init_fns __initconst = { }, }; -static void __init __l2c_init(const struct l2c_init_data *data, - u32 aux_val, u32 aux_mask, u32 cache_id) +static int __init __l2c_init(const struct l2c_init_data *data, + u32 aux_val, u32 aux_mask, u32 cache_id) { struct outer_cache_fns fns; unsigned way_size_bits, ways; u32 aux, old_aux; + /* + * Save the pointer globally so that callbacks which do not receive + * context from callers can access the structure. + */ + l2x0_data = kmemdup(data, sizeof(*data), GFP_KERNEL); + if (!l2x0_data) + return -ENOMEM; + /* * Sanity check the aux values. aux_mask is the bits we preserve * from reading the hardware register, and aux_val is the bits we @@ -884,6 +848,7 @@ static void __init __l2c_init(const struct l2c_init_data *data, fns = data->outer_cache; fns.write_sec = outer_cache.write_sec; + fns.configure = outer_cache.configure; if (data->fixup) data->fixup(l2x0_base, cache_id, &fns); @@ -910,6 +875,8 @@ static void __init __l2c_init(const struct l2c_init_data *data, data->type, ways, l2x0_size >> 10); pr_info("%s: CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n", data->type, cache_id, aux); + + return 0; } void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) @@ -936,6 +903,10 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) break; } + /* Read back current (default) hardware configuration */ + if (data->save) + data->save(l2x0_base); + __l2c_init(data, aux_val, aux_mask, cache_id); } @@ -979,7 +950,7 @@ static int __init l2x0_cache_size_of_parse(const struct device_node *np, /* All these l2 caches have the same line = block size actually */ if (!line_size) { if (block_size) { - /* If linesize if not given, it is equal to blocksize */ + /* If linesize is not given, it is equal to blocksize */ line_size = block_size; } else { /* Fall back to known size */ @@ -1102,7 +1073,7 @@ static const struct l2c_init_data of_l2c210_data __initconst = { .flush_all = l2c210_flush_all, .disable = l2c_disable, .sync = l2c210_sync, - .resume = l2c210_resume, + .resume = l2c_resume, }, }; @@ -1120,7 +1091,7 @@ static const struct l2c_init_data of_l2c220_data __initconst = { .flush_all = l2c220_flush_all, .disable = l2c_disable, .sync = l2c220_sync, - .resume = l2c210_resume, + .resume = l2c_resume, }, }; @@ -1131,32 +1102,32 @@ static void __init l2c310_of_parse(const struct device_node *np, u32 tag[3] = { 0, 0, 0 }; u32 filter[2] = { 0, 0 }; u32 assoc; + u32 prefetch; + u32 val; int ret; of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag)); if (tag[0] && tag[1] && tag[2]) - writel_relaxed( + l2x0_saved_regs.tag_latency = L310_LATENCY_CTRL_RD(tag[0] - 1) | L310_LATENCY_CTRL_WR(tag[1] - 1) | - L310_LATENCY_CTRL_SETUP(tag[2] - 1), - l2x0_base + L310_TAG_LATENCY_CTRL); + L310_LATENCY_CTRL_SETUP(tag[2] - 1); of_property_read_u32_array(np, "arm,data-latency", data, ARRAY_SIZE(data)); if (data[0] && data[1] && data[2]) - writel_relaxed( + l2x0_saved_regs.data_latency = L310_LATENCY_CTRL_RD(data[0] - 1) | L310_LATENCY_CTRL_WR(data[1] - 1) | - L310_LATENCY_CTRL_SETUP(data[2] - 1), - l2x0_base + L310_DATA_LATENCY_CTRL); + L310_LATENCY_CTRL_SETUP(data[2] - 1); of_property_read_u32_array(np, "arm,filter-ranges", filter, ARRAY_SIZE(filter)); if (filter[1]) { - writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M), - l2x0_base + L310_ADDR_FILTER_END); - writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L310_ADDR_FILTER_EN, - l2x0_base + L310_ADDR_FILTER_START); + l2x0_saved_regs.filter_end = + ALIGN(filter[0] + filter[1], SZ_1M); + l2x0_saved_regs.filter_start = (filter[0] & ~(SZ_1M - 1)) + | L310_ADDR_FILTER_EN; } ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_512K); @@ -1178,6 +1149,58 @@ static void __init l2c310_of_parse(const struct device_node *np, assoc); break; } + + prefetch = l2x0_saved_regs.prefetch_ctrl; + + ret = of_property_read_u32(np, "arm,double-linefill", &val); + if (ret == 0) { + if (val) + prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL; + else + prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL; + } else if (ret != -EINVAL) { + pr_err("L2C-310 OF arm,double-linefill property value is missing\n"); + } + + ret = of_property_read_u32(np, "arm,double-linefill-incr", &val); + if (ret == 0) { + if (val) + prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL_INCR; + else + prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL_INCR; + } else if (ret != -EINVAL) { + pr_err("L2C-310 OF arm,double-linefill-incr property value is missing\n"); + } + + ret = of_property_read_u32(np, "arm,double-linefill-wrap", &val); + if (ret == 0) { + if (!val) + prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL_WRAP; + else + prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL_WRAP; + } else if (ret != -EINVAL) { + pr_err("L2C-310 OF arm,double-linefill-wrap property value is missing\n"); + } + + ret = of_property_read_u32(np, "arm,prefetch-drop", &val); + if (ret == 0) { + if (val) + prefetch |= L310_PREFETCH_CTRL_PREFETCH_DROP; + else + prefetch &= ~L310_PREFETCH_CTRL_PREFETCH_DROP; + } else if (ret != -EINVAL) { + pr_err("L2C-310 OF arm,prefetch-drop property value is missing\n"); + } + + ret = of_property_read_u32(np, "arm,prefetch-offset", &val); + if (ret == 0) { + prefetch &= ~L310_PREFETCH_CTRL_OFFSET_MASK; + prefetch |= val & L310_PREFETCH_CTRL_OFFSET_MASK; + } else if (ret != -EINVAL) { + pr_err("L2C-310 OF arm,prefetch-offset property value is missing\n"); + } + + l2x0_saved_regs.prefetch_ctrl = prefetch; } static const struct l2c_init_data of_l2c310_data __initconst = { @@ -1188,6 +1211,7 @@ static const struct l2c_init_data of_l2c310_data __initconst = { .enable = l2c310_enable, .fixup = l2c310_fixup, .save = l2c310_save, + .configure = l2c310_configure, .outer_cache = { .inv_range = l2c210_inv_range, .clean_range = l2c210_clean_range, @@ -1216,6 +1240,7 @@ static const struct l2c_init_data of_l2c310_coherent_data __initconst = { .enable = l2c310_enable, .fixup = l2c310_fixup, .save = l2c310_save, + .configure = l2c310_configure, .outer_cache = { .inv_range = l2c210_inv_range, .clean_range = l2c210_clean_range, @@ -1231,7 +1256,7 @@ static const struct l2c_init_data of_l2c310_coherent_data __initconst = { * noninclusive, while the hardware cache range operations use * inclusive start and end addresses. */ -static unsigned long calc_range_end(unsigned long start, unsigned long end) +static unsigned long aurora_range_end(unsigned long start, unsigned long end) { /* * Limit the number of cache lines processed at once, @@ -1250,25 +1275,13 @@ static unsigned long calc_range_end(unsigned long start, unsigned long end) return end; } -/* - * Make sure 'start' and 'end' reference the same page, as L2 is PIPT - * and range operations only do a TLB lookup on the start address. - */ static void aurora_pa_range(unsigned long start, unsigned long end, - unsigned long offset) + unsigned long offset) { + void __iomem *base = l2x0_base; + unsigned long range_end; unsigned long flags; - raw_spin_lock_irqsave(&l2x0_lock, flags); - writel_relaxed(start, l2x0_base + AURORA_RANGE_BASE_ADDR_REG); - writel_relaxed(end, l2x0_base + offset); - raw_spin_unlock_irqrestore(&l2x0_lock, flags); - - cache_sync(); -} - -static void aurora_inv_range(unsigned long start, unsigned long end) -{ /* * round start and end adresses up to cache line size */ @@ -1276,15 +1289,24 @@ static void aurora_inv_range(unsigned long start, unsigned long end) end = ALIGN(end, CACHE_LINE_SIZE); /* - * Invalidate all full cache lines between 'start' and 'end'. + * perform operation on all full cache lines between 'start' and 'end' */ while (start < end) { - unsigned long range_end = calc_range_end(start, end); - aurora_pa_range(start, range_end - CACHE_LINE_SIZE, - AURORA_INVAL_RANGE_REG); + range_end = aurora_range_end(start, end); + + raw_spin_lock_irqsave(&l2x0_lock, flags); + writel_relaxed(start, base + AURORA_RANGE_BASE_ADDR_REG); + writel_relaxed(range_end - CACHE_LINE_SIZE, base + offset); + raw_spin_unlock_irqrestore(&l2x0_lock, flags); + + writel_relaxed(0, base + AURORA_SYNC_REG); start = range_end; } } +static void aurora_inv_range(unsigned long start, unsigned long end) +{ + aurora_pa_range(start, end, AURORA_INVAL_RANGE_REG); +} static void aurora_clean_range(unsigned long start, unsigned long end) { @@ -1292,36 +1314,47 @@ static void aurora_clean_range(unsigned long start, unsigned long end) * If L2 is forced to WT, the L2 will always be clean and we * don't need to do anything here. */ - if (!l2_wt_override) { - start &= ~(CACHE_LINE_SIZE - 1); - end = ALIGN(end, CACHE_LINE_SIZE); - while (start != end) { - unsigned long range_end = calc_range_end(start, end); - aurora_pa_range(start, range_end - CACHE_LINE_SIZE, - AURORA_CLEAN_RANGE_REG); - start = range_end; - } - } + if (!l2_wt_override) + aurora_pa_range(start, end, AURORA_CLEAN_RANGE_REG); } static void aurora_flush_range(unsigned long start, unsigned long end) { - start &= ~(CACHE_LINE_SIZE - 1); - end = ALIGN(end, CACHE_LINE_SIZE); - while (start != end) { - unsigned long range_end = calc_range_end(start, end); - /* - * If L2 is forced to WT, the L2 will always be clean and we - * just need to invalidate. - */ - if (l2_wt_override) - aurora_pa_range(start, range_end - CACHE_LINE_SIZE, - AURORA_INVAL_RANGE_REG); - else - aurora_pa_range(start, range_end - CACHE_LINE_SIZE, - AURORA_FLUSH_RANGE_REG); - start = range_end; - } + if (l2_wt_override) + aurora_pa_range(start, end, AURORA_INVAL_RANGE_REG); + else + aurora_pa_range(start, end, AURORA_FLUSH_RANGE_REG); +} + +static void aurora_flush_all(void) +{ + void __iomem *base = l2x0_base; + unsigned long flags; + + /* clean all ways */ + raw_spin_lock_irqsave(&l2x0_lock, flags); + __l2c_op_way(base + L2X0_CLEAN_INV_WAY); + raw_spin_unlock_irqrestore(&l2x0_lock, flags); + + writel_relaxed(0, base + AURORA_SYNC_REG); +} + +static void aurora_cache_sync(void) +{ + writel_relaxed(0, l2x0_base + AURORA_SYNC_REG); +} + +static void aurora_disable(void) +{ + void __iomem *base = l2x0_base; + unsigned long flags; + + raw_spin_lock_irqsave(&l2x0_lock, flags); + __l2c_op_way(base + L2X0_CLEAN_INV_WAY); + writel_relaxed(0, base + AURORA_SYNC_REG); + l2c_write_sec(0, base, L2X0_CTRL); + dsb(st); + raw_spin_unlock_irqrestore(&l2x0_lock, flags); } static void aurora_save(void __iomem *base) @@ -1330,16 +1363,6 @@ static void aurora_save(void __iomem *base) l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL); } -static void aurora_resume(void) -{ - void __iomem *base = l2x0_base; - - if (!(readl(base + L2X0_CTRL) & L2X0_CTRL_EN)) { - writel_relaxed(l2x0_saved_regs.aux_ctrl, base + L2X0_AUX_CTRL); - writel_relaxed(l2x0_saved_regs.ctrl, base + L2X0_CTRL); - } -} - /* * For Aurora cache in no outer mode, enable via the CP15 coprocessor * broadcasting of cache commands to L2. @@ -1398,10 +1421,10 @@ static const struct l2c_init_data of_aurora_with_outer_data __initconst = { .inv_range = aurora_inv_range, .clean_range = aurora_clean_range, .flush_range = aurora_flush_range, - .flush_all = l2x0_flush_all, - .disable = l2x0_disable, - .sync = l2x0_cache_sync, - .resume = aurora_resume, + .flush_all = aurora_flush_all, + .disable = aurora_disable, + .sync = aurora_cache_sync, + .resume = l2c_resume, }, }; @@ -1414,7 +1437,7 @@ static const struct l2c_init_data of_aurora_no_outer_data __initconst = { .fixup = aurora_fixup, .save = aurora_save, .outer_cache = { - .resume = aurora_resume, + .resume = l2c_resume, }, }; @@ -1562,6 +1585,7 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = { .of_parse = l2c310_of_parse, .enable = l2c310_enable, .save = l2c310_save, + .configure = l2c310_configure, .outer_cache = { .inv_range = bcm_inv_range, .clean_range = bcm_clean_range, @@ -1583,18 +1607,12 @@ static void __init tauros3_save(void __iomem *base) readl_relaxed(base + L310_PREFETCH_CTRL); } -static void tauros3_resume(void) +static void tauros3_configure(void __iomem *base) { - void __iomem *base = l2x0_base; - - if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) { - writel_relaxed(l2x0_saved_regs.aux2_ctrl, - base + TAUROS3_AUX2_CTRL); - writel_relaxed(l2x0_saved_regs.prefetch_ctrl, - base + L310_PREFETCH_CTRL); - - l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8); - } + writel_relaxed(l2x0_saved_regs.aux2_ctrl, + base + TAUROS3_AUX2_CTRL); + writel_relaxed(l2x0_saved_regs.prefetch_ctrl, + base + L310_PREFETCH_CTRL); } static const struct l2c_init_data of_tauros3_data __initconst = { @@ -1603,9 +1621,10 @@ static const struct l2c_init_data of_tauros3_data __initconst = { .num_lock = 8, .enable = l2c_enable, .save = tauros3_save, + .configure = tauros3_configure, /* Tauros3 broadcasts L1 cache operations to L2 */ .outer_cache = { - .resume = tauros3_resume, + .resume = l2c_resume, }, }; @@ -1661,6 +1680,10 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask) if (!of_property_read_bool(np, "cache-unified")) pr_err("L2C: device tree omits to specify unified cache\n"); + /* Read back current (default) hardware configuration */ + if (data->save) + data->save(l2x0_base); + /* L2 configuration can only be changed if the cache is disabled */ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) if (data->of_parse) @@ -1671,8 +1694,6 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask) else cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID); - __l2c_init(data, aux_val, aux_mask, cache_id); - - return 0; + return __l2c_init(data, aux_val, aux_mask, cache_id); } #endif diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c index 91892569710f..845769e41332 100644 --- a/arch/arm/mm/context.c +++ b/arch/arm/mm/context.c @@ -144,21 +144,17 @@ static void flush_context(unsigned int cpu) /* Update the list of reserved ASIDs and the ASID bitmap. */ bitmap_clear(asid_map, 0, NUM_USER_ASIDS); for_each_possible_cpu(i) { - if (i == cpu) { - asid = 0; - } else { - asid = atomic64_xchg(&per_cpu(active_asids, i), 0); - /* - * If this CPU has already been through a - * rollover, but hasn't run another task in - * the meantime, we must preserve its reserved - * ASID, as this is the only trace we have of - * the process it is still running. - */ - if (asid == 0) - asid = per_cpu(reserved_asids, i); - __set_bit(asid & ~ASID_MASK, asid_map); - } + asid = atomic64_xchg(&per_cpu(active_asids, i), 0); + /* + * If this CPU has already been through a + * rollover, but hasn't run another task in + * the meantime, we must preserve its reserved + * ASID, as this is the only trace we have of + * the process it is still running. + */ + if (asid == 0) + asid = per_cpu(reserved_asids, i); + __set_bit(asid & ~ASID_MASK, asid_map); per_cpu(reserved_asids, i) = asid; } diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 7864797609b3..903dba064a03 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1940,18 +1940,8 @@ void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping) } EXPORT_SYMBOL_GPL(arm_iommu_release_mapping); -/** - * arm_iommu_attach_device - * @dev: valid struct device pointer - * @mapping: io address space mapping structure (returned from - * arm_iommu_create_mapping) - * - * Attaches specified io address space mapping to the provided device, - * More than one client might be attached to the same io address space - * mapping. - */ -int arm_iommu_attach_device(struct device *dev, - struct dma_iommu_mapping *mapping) +static int __arm_iommu_attach_device(struct device *dev, + struct dma_iommu_mapping *mapping) { int err; @@ -1965,15 +1955,35 @@ int arm_iommu_attach_device(struct device *dev, pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev)); return 0; } -EXPORT_SYMBOL_GPL(arm_iommu_attach_device); /** - * arm_iommu_detach_device + * arm_iommu_attach_device * @dev: valid struct device pointer + * @mapping: io address space mapping structure (returned from + * arm_iommu_create_mapping) * - * Detaches the provided device from a previously attached map. + * Attaches specified io address space mapping to the provided device. + * This replaces the dma operations (dma_map_ops pointer) with the + * IOMMU aware version. + * + * More than one client might be attached to the same io address space + * mapping. */ -void arm_iommu_detach_device(struct device *dev) +int arm_iommu_attach_device(struct device *dev, + struct dma_iommu_mapping *mapping) +{ + int err; + + err = __arm_iommu_attach_device(dev, mapping); + if (err) + return err; + + set_dma_ops(dev, &iommu_ops); + return 0; +} +EXPORT_SYMBOL_GPL(arm_iommu_attach_device); + +static void __arm_iommu_detach_device(struct device *dev) { struct dma_iommu_mapping *mapping; @@ -1989,6 +1999,19 @@ void arm_iommu_detach_device(struct device *dev) pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev)); } + +/** + * arm_iommu_detach_device + * @dev: valid struct device pointer + * + * Detaches the provided device from a previously attached map. + * This voids the dma operations (dma_map_ops pointer) + */ +void arm_iommu_detach_device(struct device *dev) +{ + __arm_iommu_detach_device(dev); + set_dma_ops(dev, NULL); +} EXPORT_SYMBOL_GPL(arm_iommu_detach_device); static struct dma_map_ops *arm_get_iommu_dma_map_ops(bool coherent) @@ -2011,7 +2034,7 @@ static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size, return false; } - if (arm_iommu_attach_device(dev, mapping)) { + if (__arm_iommu_attach_device(dev, mapping)) { pr_warn("Failed to attached device %s to IOMMU_mapping\n", dev_name(dev)); arm_iommu_release_mapping(mapping); @@ -2025,7 +2048,10 @@ static void arm_teardown_iommu_dma_ops(struct device *dev) { struct dma_iommu_mapping *mapping = dev->archdata.mapping; - arm_iommu_detach_device(dev); + if (!mapping) + return; + + __arm_iommu_detach_device(dev); arm_iommu_release_mapping(mapping); } diff --git a/arch/arm/mm/hugetlbpage.c b/arch/arm/mm/hugetlbpage.c index 66781bf34077..c72412415093 100644 --- a/arch/arm/mm/hugetlbpage.c +++ b/arch/arm/mm/hugetlbpage.c @@ -36,12 +36,6 @@ * of type casting from pmd_t * to pte_t *. */ -struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, - int write) -{ - return ERR_PTR(-EINVAL); -} - int pud_huge(pud_t pud) { return 0; diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 2495c8cb47ba..1609b022a72f 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -319,10 +319,7 @@ void __init arm_memblock_init(const struct machine_desc *mdesc) early_init_fdt_scan_reserved_mem(); - /* - * reserve memory for DMA contigouos allocations, - * must come from DMA area inside low memory - */ + /* reserve memory for DMA contiguous allocations */ dma_contiguous_reserve(arm_dma_limit); arm_memblock_steal_permitted = false; diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c index 249379535be2..a3681f11dd9f 100644 --- a/arch/arm/mm/pgd.c +++ b/arch/arm/mm/pgd.c @@ -97,6 +97,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm) no_pte: pmd_free(mm, new_pmd); + mm_dec_nr_pmds(mm); no_pmd: pud_free(mm, new_pud); no_pud: @@ -130,9 +131,11 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd_base) pte = pmd_pgtable(*pmd); pmd_clear(pmd); pte_free(mm, pte); + atomic_long_dec(&mm->nr_ptes); no_pmd: pud_clear(pud); pmd_free(mm, pmd); + mm_dec_nr_pmds(mm); no_pud: pgd_clear(pgd); pud_free(mm, pud); @@ -152,6 +155,7 @@ no_pgd: pmd = pmd_offset(pud, 0); pud_clear(pud); pmd_free(mm, pmd); + mm_dec_nr_pmds(mm); pgd_clear(pgd); pud_free(mm, pud); } diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index ba1196c968d8..082b9f2f7e90 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -98,7 +98,7 @@ #endif #if !defined (CONFIG_ARM_LPAE) && \ (L_PTE_XN+L_PTE_USER+L_PTE_RDONLY+L_PTE_DIRTY+L_PTE_YOUNG+\ - L_PTE_FILE+L_PTE_PRESENT) > L_PTE_SHARED + L_PTE_PRESENT) > L_PTE_SHARED #error Invalid Linux PTE bit settings #endif #endif /* CONFIG_MMU */ diff --git a/arch/arm/probes/Makefile b/arch/arm/probes/Makefile new file mode 100644 index 000000000000..aa1f8590dcdd --- /dev/null +++ b/arch/arm/probes/Makefile @@ -0,0 +1,7 @@ +obj-$(CONFIG_UPROBES) += decode.o decode-arm.o uprobes/ +obj-$(CONFIG_KPROBES) += decode.o kprobes/ +ifdef CONFIG_THUMB2_KERNEL +obj-$(CONFIG_KPROBES) += decode-thumb.o +else +obj-$(CONFIG_KPROBES) += decode-arm.o +endif diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/probes/decode-arm.c similarity index 98% rename from arch/arm/kernel/probes-arm.c rename to arch/arm/probes/decode-arm.c index 8eaef81d8344..f72c33a2dcfb 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/probes/decode-arm.c @@ -1,5 +1,6 @@ /* - * arch/arm/kernel/probes-arm.c + * + * arch/arm/probes/decode-arm.c * * Some code moved here from arch/arm/kernel/kprobes-arm.c * @@ -20,8 +21,8 @@ #include #include -#include "probes.h" -#include "probes-arm.h" +#include "decode.h" +#include "decode-arm.h" #define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) @@ -369,17 +370,17 @@ static const union decode_item arm_cccc_001x_table[] = { /* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ /* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0fb00000, 0x03000000, PROBES_DATA_PROCESSING_IMM, + DECODE_EMULATEX (0x0fb00000, 0x03000000, PROBES_MOV_HALFWORD, REGS(0, NOPC, 0, 0, 0)), /* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ DECODE_OR (0x0fff00ff, 0x03200001), /* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ - DECODE_EMULATE (0x0fff00ff, 0x03200004, PROBES_EMULATE_NONE), + DECODE_EMULATE (0x0fff00ff, 0x03200004, PROBES_SEV), /* 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 */ - DECODE_SIMULATE (0x0fff00fc, 0x03200000, PROBES_SIMULATE_NOP), + DECODE_SIMULATE (0x0fff00fc, 0x03200000, PROBES_WFE), /* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */ /* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ /* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */ @@ -725,10 +726,11 @@ static void __kprobes arm_singlestep(probes_opcode_t insn, */ enum probes_insn __kprobes arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, - bool emulate, const union decode_action *actions) + bool emulate, const union decode_action *actions, + const struct decode_checker *checkers[]) { asi->insn_singlestep = arm_singlestep; asi->insn_check_cc = probes_condition_checks[insn>>28]; return probes_decode_insn(insn, asi, probes_decode_arm_table, false, - emulate, actions); + emulate, actions, checkers); } diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/probes/decode-arm.h similarity index 92% rename from arch/arm/kernel/probes-arm.h rename to arch/arm/probes/decode-arm.h index ace6572f6e26..b3b80f6d414b 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/probes/decode-arm.h @@ -1,5 +1,5 @@ /* - * arch/arm/kernel/probes-arm.h + * arch/arm/probes/decode-arm.h * * Copyright 2013 Linaro Ltd. * Written by: David A. Long @@ -15,9 +15,9 @@ #ifndef _ARM_KERNEL_PROBES_ARM_H #define _ARM_KERNEL_PROBES_ARM_H +#include "decode.h" + enum probes_arm_action { - PROBES_EMULATE_NONE, - PROBES_SIMULATE_NOP, PROBES_PRELOAD_IMM, PROBES_PRELOAD_REG, PROBES_BRANCH_IMM, @@ -68,6 +68,7 @@ extern const union decode_item probes_decode_arm_table[]; enum probes_insn arm_probes_decode_insn(probes_opcode_t, struct arch_probes_insn *, bool emulate, - const union decode_action *actions); + const union decode_action *actions, + const struct decode_checker *checkers[]); #endif diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/probes/decode-thumb.c similarity index 98% rename from arch/arm/kernel/probes-thumb.c rename to arch/arm/probes/decode-thumb.c index 4131351e812f..985e7dd4cac6 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/probes/decode-thumb.c @@ -1,5 +1,5 @@ /* - * arch/arm/kernel/probes-thumb.c + * arch/arm/probes/decode-thumb.c * * Copyright (C) 2011 Jon Medhurst . * @@ -12,8 +12,8 @@ #include #include -#include "probes.h" -#include "probes-thumb.h" +#include "decode.h" +#include "decode-thumb.h" static const union decode_item t32_table_1110_100x_x0xx[] = { @@ -863,20 +863,22 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode, enum probes_insn __kprobes thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, - bool emulate, const union decode_action *actions) + bool emulate, const union decode_action *actions, + const struct decode_checker *checkers[]) { asi->insn_singlestep = thumb16_singlestep; asi->insn_check_cc = thumb_check_cc; return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true, - emulate, actions); + emulate, actions, checkers); } enum probes_insn __kprobes thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, - bool emulate, const union decode_action *actions) + bool emulate, const union decode_action *actions, + const struct decode_checker *checkers[]) { asi->insn_singlestep = thumb32_singlestep; asi->insn_check_cc = thumb_check_cc; return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true, - emulate, actions); + emulate, actions, checkers); } diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/probes/decode-thumb.h similarity index 90% rename from arch/arm/kernel/probes-thumb.h rename to arch/arm/probes/decode-thumb.h index 7c6f6ebe514f..8457add0a2d8 100644 --- a/arch/arm/kernel/probes-thumb.h +++ b/arch/arm/probes/decode-thumb.h @@ -1,5 +1,5 @@ /* - * arch/arm/kernel/probes-thumb.h + * arch/arm/probes/decode-thumb.h * * Copyright 2013 Linaro Ltd. * Written by: David A. Long @@ -15,6 +15,8 @@ #ifndef _ARM_KERNEL_PROBES_THUMB_H #define _ARM_KERNEL_PROBES_THUMB_H +#include "decode.h" + /* * True if current instruction is in an IT block. */ @@ -89,9 +91,11 @@ extern const union decode_item probes_decode_thumb16_table[]; enum probes_insn __kprobes thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, - bool emulate, const union decode_action *actions); + bool emulate, const union decode_action *actions, + const struct decode_checker *checkers[]); enum probes_insn __kprobes thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, - bool emulate, const union decode_action *actions); + bool emulate, const union decode_action *actions, + const struct decode_checker *checkers[]); #endif diff --git a/arch/arm/kernel/probes.c b/arch/arm/probes/decode.c similarity index 84% rename from arch/arm/kernel/probes.c rename to arch/arm/probes/decode.c index a8ab540d7e73..880ebe0cdf19 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/probes/decode.c @@ -1,5 +1,5 @@ /* - * arch/arm/kernel/probes.c + * arch/arm/probes/decode.c * * Copyright (C) 2011 Jon Medhurst . * @@ -17,7 +17,7 @@ #include #include -#include "probes.h" +#include "decode.h" #ifndef find_str_pc_offset @@ -342,6 +342,31 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { [DECODE_TYPE_REJECT] = sizeof(struct decode_reject) }; +static int run_checkers(const struct decode_checker *checkers[], + int action, probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + const struct decode_checker **p; + + if (!checkers) + return INSN_GOOD; + + p = checkers; + while (*p != NULL) { + int retval; + probes_check_t *checker_func = (*p)[action].checker; + + retval = INSN_GOOD; + if (checker_func) + retval = checker_func(insn, asi, h); + if (retval == INSN_REJECTED) + return retval; + p++; + } + return INSN_GOOD; +} + /* * probes_decode_insn operates on data tables in order to decode an ARM * architecture instruction onto which a kprobe has been placed. @@ -388,11 +413,34 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { int __kprobes probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, const union decode_item *table, bool thumb, - bool emulate, const union decode_action *actions) + bool emulate, const union decode_action *actions, + const struct decode_checker *checkers[]) { const struct decode_header *h = (struct decode_header *)table; const struct decode_header *next; bool matched = false; + /* + * @insn can be modified by decode_regs. Save its original + * value for checkers. + */ + probes_opcode_t origin_insn = insn; + + /* + * stack_space is initialized to 0 here. Checker functions + * should update is value if they find this is a stack store + * instruction: positive value means bytes of stack usage, + * negitive value means unable to determine stack usage + * statically. For instruction doesn't store to stack, checker + * do nothing with it. + */ + asi->stack_space = 0; + + /* + * Similarly to stack_space, register_usage_flags is filled by + * checkers. Its default value is set to ~0, which is 'all + * registers are used', to prevent any potential optimization. + */ + asi->register_usage_flags = ~0UL; if (emulate) insn = prepare_emulated_insn(insn, asi, thumb); @@ -422,24 +470,41 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, } case DECODE_TYPE_CUSTOM: { + int err; struct decode_custom *d = (struct decode_custom *)h; - return actions[d->decoder.action].decoder(insn, asi, h); + int action = d->decoder.action; + + err = run_checkers(checkers, action, origin_insn, asi, h); + if (err == INSN_REJECTED) + return INSN_REJECTED; + return actions[action].decoder(insn, asi, h); } case DECODE_TYPE_SIMULATE: { + int err; struct decode_simulate *d = (struct decode_simulate *)h; - asi->insn_handler = actions[d->handler.action].handler; + int action = d->handler.action; + + err = run_checkers(checkers, action, origin_insn, asi, h); + if (err == INSN_REJECTED) + return INSN_REJECTED; + asi->insn_handler = actions[action].handler; return INSN_GOOD_NO_SLOT; } case DECODE_TYPE_EMULATE: { + int err; struct decode_emulate *d = (struct decode_emulate *)h; + int action = d->handler.action; + + err = run_checkers(checkers, action, origin_insn, asi, h); + if (err == INSN_REJECTED) + return INSN_REJECTED; if (!emulate) - return actions[d->handler.action].decoder(insn, - asi, h); + return actions[action].decoder(insn, asi, h); - asi->insn_handler = actions[d->handler.action].handler; + asi->insn_handler = actions[action].handler; set_emulated_insn(insn, asi, thumb); return INSN_GOOD; } diff --git a/arch/arm/kernel/probes.h b/arch/arm/probes/decode.h similarity index 97% rename from arch/arm/kernel/probes.h rename to arch/arm/probes/decode.h index dba9f2466a93..f9b08ba7fe73 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/probes/decode.h @@ -1,5 +1,5 @@ /* - * arch/arm/kernel/probes.h + * arch/arm/probes/decode.h * * Copyright (C) 2011 Jon Medhurst . * @@ -314,6 +314,14 @@ union decode_action { probes_custom_decode_t *decoder; }; +typedef enum probes_insn (probes_check_t)(probes_opcode_t, + struct arch_probes_insn *, + const struct decode_header *); + +struct decode_checker { + probes_check_t *checker; +}; + #define DECODE_END \ {.bits = DECODE_TYPE_END} @@ -402,6 +410,7 @@ probes_insn_handler_t probes_emulate_none; int __kprobes probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, const union decode_item *table, bool thumb, bool emulate, - const union decode_action *actions); + const union decode_action *actions, + const struct decode_checker **checkers); #endif diff --git a/arch/arm/probes/kprobes/Makefile b/arch/arm/probes/kprobes/Makefile new file mode 100644 index 000000000000..76a36bf102b7 --- /dev/null +++ b/arch/arm/probes/kprobes/Makefile @@ -0,0 +1,12 @@ +obj-$(CONFIG_KPROBES) += core.o actions-common.o checkers-common.o +obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o +test-kprobes-objs := test-core.o + +ifdef CONFIG_THUMB2_KERNEL +obj-$(CONFIG_KPROBES) += actions-thumb.o checkers-thumb.o +test-kprobes-objs += test-thumb.o +else +obj-$(CONFIG_KPROBES) += actions-arm.o checkers-arm.o +obj-$(CONFIG_OPTPROBES) += opt-arm.o +test-kprobes-objs += test-arm.o +endif diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/probes/kprobes/actions-arm.c similarity index 98% rename from arch/arm/kernel/kprobes-arm.c rename to arch/arm/probes/kprobes/actions-arm.c index ac300c60d656..b9056d649607 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/probes/kprobes/actions-arm.c @@ -1,5 +1,5 @@ /* - * arch/arm/kernel/kprobes-decode.c + * arch/arm/probes/kprobes/actions-arm.c * * Copyright (C) 2006, 2007 Motorola Inc. * @@ -62,8 +62,9 @@ #include #include -#include "kprobes.h" -#include "probes-arm.h" +#include "../decode-arm.h" +#include "core.h" +#include "checkers.h" #if __LINUX_ARM_ARCH__ >= 6 #define BLX(reg) "blx "reg" \n\t" @@ -302,8 +303,6 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn, } const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { - [PROBES_EMULATE_NONE] = {.handler = probes_emulate_none}, - [PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop}, [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, @@ -341,3 +340,5 @@ const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { [PROBES_BRANCH] = {.handler = simulate_bbl}, [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} }; + +const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL}; diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/probes/kprobes/actions-common.c similarity index 98% rename from arch/arm/kernel/kprobes-common.c rename to arch/arm/probes/kprobes/actions-common.c index 0bf5d64eba1d..bd20a71cd34a 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/probes/kprobes/actions-common.c @@ -1,5 +1,5 @@ /* - * arch/arm/kernel/kprobes-common.c + * arch/arm/probes/kprobes/actions-common.c * * Copyright (C) 2011 Jon Medhurst . * @@ -15,7 +15,7 @@ #include #include -#include "kprobes.h" +#include "core.h" static void __kprobes simulate_ldm1stm1(probes_opcode_t insn, diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/probes/kprobes/actions-thumb.c similarity index 98% rename from arch/arm/kernel/kprobes-thumb.c rename to arch/arm/probes/kprobes/actions-thumb.c index 9495d7f3516f..07cfd9bef340 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/probes/kprobes/actions-thumb.c @@ -1,5 +1,5 @@ /* - * arch/arm/kernel/kprobes-thumb.c + * arch/arm/probes/kprobes/actions-thumb.c * * Copyright (C) 2011 Jon Medhurst . * @@ -13,8 +13,9 @@ #include #include -#include "kprobes.h" -#include "probes-thumb.h" +#include "../decode-thumb.h" +#include "core.h" +#include "checkers.h" /* These emulation encodings are functionally equivalent... */ #define t32_emulate_rd8rn16rm0ra12_noflags \ @@ -664,3 +665,6 @@ const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = { [PROBES_T32_MUL_ADD_LONG] = { .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags}, }; + +const struct decode_checker *kprobes_t32_checkers[] = {t32_stack_checker, NULL}; +const struct decode_checker *kprobes_t16_checkers[] = {t16_stack_checker, NULL}; diff --git a/arch/arm/probes/kprobes/checkers-arm.c b/arch/arm/probes/kprobes/checkers-arm.c new file mode 100644 index 000000000000..7b9817333b68 --- /dev/null +++ b/arch/arm/probes/kprobes/checkers-arm.c @@ -0,0 +1,192 @@ +/* + * arch/arm/probes/kprobes/checkers-arm.c + * + * Copyright (C) 2014 Huawei Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include "../decode.h" +#include "../decode-arm.h" +#include "checkers.h" + +static enum probes_insn __kprobes arm_check_stack(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + /* + * PROBES_LDRSTRD, PROBES_LDMSTM, PROBES_STORE, + * PROBES_STORE_EXTRA may get here. Simply mark all normal + * insns as STACK_USE_NONE. + */ + static const union decode_item table[] = { + /* + * 'STR{,D,B,H}, Rt, [Rn, Rm]' should be marked as UNKNOWN + * if Rn or Rm is SP. + * x + * STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx + * STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx + */ + DECODE_OR (0x0e10000f, 0x0600000d), + DECODE_OR (0x0e1f0000, 0x060d0000), + + /* + * x + * STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx + * STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx + */ + DECODE_OR (0x0e5000bf, 0x000000bd), + DECODE_CUSTOM (0x0e5f00b0, 0x000d00b0, STACK_USE_UNKNOWN), + + /* + * For PROBES_LDMSTM, only stmdx sp, [...] need to examine + * + * Bit B/A (bit 24) encodes arithmetic operation order. 1 means + * before, 0 means after. + * Bit I/D (bit 23) encodes arithmetic operation. 1 means + * increment, 0 means decrement. + * + * So: + * B I + * / / + * A D | Rn | + * STMDX SP, [...] cccc 100x 00x0 xxxx xxxx xxxx xxxx xxxx + */ + DECODE_CUSTOM (0x0edf0000, 0x080d0000, STACK_USE_STMDX), + + /* P U W | Rn | Rt | imm12 |*/ + /* STR (immediate) cccc 010x x0x0 1101 xxxx xxxx xxxx xxxx */ + /* STRB (immediate) cccc 010x x1x0 1101 xxxx xxxx xxxx xxxx */ + /* P U W | Rn | Rt |imm4| |imm4|*/ + /* STRD (immediate) cccc 000x x1x0 1101 xxxx xxxx 1111 xxxx */ + /* STRH (immediate) cccc 000x x1x0 1101 xxxx xxxx 1011 xxxx */ + /* + * index = (P == '1'); add = (U == '1'). + * Above insns with: + * index == 0 (str{,d,h} rx, [sp], #+/-imm) or + * add == 1 (str{,d,h} rx, [sp, #+]) + * should be STACK_USE_NONE. + * Only str{,b,d,h} rx,[sp,#-n] (P == 1 and U == 0) are + * required to be examined. + */ + /* STR{,B} Rt,[SP,#-n] cccc 0101 0xx0 1101 xxxx xxxx xxxx xxxx */ + DECODE_CUSTOM (0x0f9f0000, 0x050d0000, STACK_USE_FIXED_XXX), + + /* STR{D,H} Rt,[SP,#-n] cccc 0001 01x0 1101 xxxx xxxx 1x11 xxxx */ + DECODE_CUSTOM (0x0fdf00b0, 0x014d00b0, STACK_USE_FIXED_X0X), + + /* fall through */ + DECODE_CUSTOM (0, 0, STACK_USE_NONE), + DECODE_END + }; + + return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL); +} + +const struct decode_checker arm_stack_checker[NUM_PROBES_ARM_ACTIONS] = { + [PROBES_LDRSTRD] = {.checker = arm_check_stack}, + [PROBES_STORE_EXTRA] = {.checker = arm_check_stack}, + [PROBES_STORE] = {.checker = arm_check_stack}, + [PROBES_LDMSTM] = {.checker = arm_check_stack}, +}; + +static enum probes_insn __kprobes arm_check_regs_nouse(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + asi->register_usage_flags = 0; + return INSN_GOOD; +} + +static enum probes_insn arm_check_regs_normal(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS; + int i; + + asi->register_usage_flags = 0; + for (i = 0; i < 5; regs >>= 4, insn >>= 4, i++) + if (regs & 0xf) + asi->register_usage_flags |= 1 << (insn & 0xf); + + return INSN_GOOD; +} + + +static enum probes_insn arm_check_regs_ldmstm(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + unsigned int reglist = insn & 0xffff; + unsigned int rn = (insn >> 16) & 0xf; + asi->register_usage_flags = reglist | (1 << rn); + return INSN_GOOD; +} + +static enum probes_insn arm_check_regs_mov_ip_sp(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + /* Instruction is 'mov ip, sp' i.e. 'mov r12, r13' */ + asi->register_usage_flags = (1 << 12) | (1<< 13); + return INSN_GOOD; +} + +/* + * | Rn |Rt/d| | Rm | + * LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx + * STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx + * | Rn |Rt/d| |imm4L| + * LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx + * STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx + * + * Such instructions access Rt/d and its next register, so different + * from others, a specific checker is required to handle this extra + * implicit register usage. + */ +static enum probes_insn arm_check_regs_ldrdstrd(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + int rdt = (insn >> 12) & 0xf; + arm_check_regs_normal(insn, asi, h); + asi->register_usage_flags |= 1 << (rdt + 1); + return INSN_GOOD; +} + + +const struct decode_checker arm_regs_checker[NUM_PROBES_ARM_ACTIONS] = { + [PROBES_MRS] = {.checker = arm_check_regs_normal}, + [PROBES_SATURATING_ARITHMETIC] = {.checker = arm_check_regs_normal}, + [PROBES_MUL1] = {.checker = arm_check_regs_normal}, + [PROBES_MUL2] = {.checker = arm_check_regs_normal}, + [PROBES_MUL_ADD_LONG] = {.checker = arm_check_regs_normal}, + [PROBES_MUL_ADD] = {.checker = arm_check_regs_normal}, + [PROBES_LOAD] = {.checker = arm_check_regs_normal}, + [PROBES_LOAD_EXTRA] = {.checker = arm_check_regs_normal}, + [PROBES_STORE] = {.checker = arm_check_regs_normal}, + [PROBES_STORE_EXTRA] = {.checker = arm_check_regs_normal}, + [PROBES_DATA_PROCESSING_REG] = {.checker = arm_check_regs_normal}, + [PROBES_DATA_PROCESSING_IMM] = {.checker = arm_check_regs_normal}, + [PROBES_SEV] = {.checker = arm_check_regs_nouse}, + [PROBES_WFE] = {.checker = arm_check_regs_nouse}, + [PROBES_SATURATE] = {.checker = arm_check_regs_normal}, + [PROBES_REV] = {.checker = arm_check_regs_normal}, + [PROBES_MMI] = {.checker = arm_check_regs_normal}, + [PROBES_PACK] = {.checker = arm_check_regs_normal}, + [PROBES_EXTEND] = {.checker = arm_check_regs_normal}, + [PROBES_EXTEND_ADD] = {.checker = arm_check_regs_normal}, + [PROBES_BITFIELD] = {.checker = arm_check_regs_normal}, + [PROBES_LDMSTM] = {.checker = arm_check_regs_ldmstm}, + [PROBES_MOV_IP_SP] = {.checker = arm_check_regs_mov_ip_sp}, + [PROBES_LDRSTRD] = {.checker = arm_check_regs_ldrdstrd}, +}; diff --git a/arch/arm/probes/kprobes/checkers-common.c b/arch/arm/probes/kprobes/checkers-common.c new file mode 100644 index 000000000000..971119c29474 --- /dev/null +++ b/arch/arm/probes/kprobes/checkers-common.c @@ -0,0 +1,101 @@ +/* + * arch/arm/probes/kprobes/checkers-common.c + * + * Copyright (C) 2014 Huawei Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include "../decode.h" +#include "../decode-arm.h" +#include "checkers.h" + +enum probes_insn checker_stack_use_none(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + asi->stack_space = 0; + return INSN_GOOD_NO_SLOT; +} + +enum probes_insn checker_stack_use_unknown(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + asi->stack_space = -1; + return INSN_GOOD_NO_SLOT; +} + +#ifdef CONFIG_THUMB2_KERNEL +enum probes_insn checker_stack_use_imm_0xx(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + int imm = insn & 0xff; + asi->stack_space = imm; + return INSN_GOOD_NO_SLOT; +} + +/* + * Different from other insn uses imm8, the real addressing offset of + * STRD in T32 encoding should be imm8 * 4. See ARMARM description. + */ +enum probes_insn checker_stack_use_t32strd(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + int imm = insn & 0xff; + asi->stack_space = imm << 2; + return INSN_GOOD_NO_SLOT; +} +#else +enum probes_insn checker_stack_use_imm_x0x(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + int imm = ((insn & 0xf00) >> 4) + (insn & 0xf); + asi->stack_space = imm; + return INSN_GOOD_NO_SLOT; +} +#endif + +enum probes_insn checker_stack_use_imm_xxx(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + int imm = insn & 0xfff; + asi->stack_space = imm; + return INSN_GOOD_NO_SLOT; +} + +enum probes_insn checker_stack_use_stmdx(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + unsigned int reglist = insn & 0xffff; + int pbit = insn & (1 << 24); + asi->stack_space = (hweight32(reglist) - (!pbit ? 1 : 0)) * 4; + + return INSN_GOOD_NO_SLOT; +} + +const union decode_action stack_check_actions[] = { + [STACK_USE_NONE] = {.decoder = checker_stack_use_none}, + [STACK_USE_UNKNOWN] = {.decoder = checker_stack_use_unknown}, +#ifdef CONFIG_THUMB2_KERNEL + [STACK_USE_FIXED_0XX] = {.decoder = checker_stack_use_imm_0xx}, + [STACK_USE_T32STRD] = {.decoder = checker_stack_use_t32strd}, +#else + [STACK_USE_FIXED_X0X] = {.decoder = checker_stack_use_imm_x0x}, +#endif + [STACK_USE_FIXED_XXX] = {.decoder = checker_stack_use_imm_xxx}, + [STACK_USE_STMDX] = {.decoder = checker_stack_use_stmdx}, +}; diff --git a/arch/arm/probes/kprobes/checkers-thumb.c b/arch/arm/probes/kprobes/checkers-thumb.c new file mode 100644 index 000000000000..d608e3b9017a --- /dev/null +++ b/arch/arm/probes/kprobes/checkers-thumb.c @@ -0,0 +1,110 @@ +/* + * arch/arm/probes/kprobes/checkers-thumb.c + * + * Copyright (C) 2014 Huawei Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include "../decode.h" +#include "../decode-thumb.h" +#include "checkers.h" + +static enum probes_insn __kprobes t32_check_stack(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + /* + * PROBES_T32_LDMSTM, PROBES_T32_LDRDSTRD and PROBES_T32_LDRSTR + * may get here. Simply mark all normal insns as STACK_USE_NONE. + */ + static const union decode_item table[] = { + + /* + * First, filter out all ldr insns to make our life easier. + * Following load insns may come here: + * LDM, LDRD, LDR. + * In T32 encoding, bit 20 is enough for distinguishing + * load and store. All load insns have this bit set, when + * all store insns have this bit clear. + */ + DECODE_CUSTOM (0x00100000, 0x00100000, STACK_USE_NONE), + + /* + * Mark all 'STR{,B,H}, Rt, [Rn, Rm]' as STACK_USE_UNKNOWN + * if Rn or Rm is SP. T32 doesn't encode STRD. + */ + /* xx | Rn | Rt | | Rm |*/ + /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ + /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ + /* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */ + /* INVALID INSN 1111 1000 0110 xxxx xxxx 0000 00xx xxxx */ + /* By Introducing INVALID INSN, bit 21 and 22 can be ignored. */ + DECODE_OR (0xff9f0fc0, 0xf80d0000), + DECODE_CUSTOM (0xff900fcf, 0xf800000d, STACK_USE_UNKNOWN), + + + /* xx | Rn | Rt | PUW| imm8 |*/ + /* STR (imm 8) 1111 1000 0100 1101 xxxx 110x xxxx xxxx */ + /* STRB (imm 8) 1111 1000 0000 1101 xxxx 110x xxxx xxxx */ + /* STRH (imm 8) 1111 1000 0010 1101 xxxx 110x xxxx xxxx */ + /* INVALID INSN 1111 1000 0110 1101 xxxx 110x xxxx xxxx */ + /* Only consider U == 0 and P == 1: strx rx, [sp, #-] */ + DECODE_CUSTOM (0xff9f0e00, 0xf80d0c00, STACK_USE_FIXED_0XX), + + /* For STR{,B,H} (imm 12), offset is always positive, so ignore them. */ + + /* P U W | Rn | Rt | Rt2| imm8 |*/ + /* STRD (immediate) 1110 1001 01x0 1101 xxxx xxxx xxxx xxxx */ + /* + * Only consider U == 0 and P == 1. + * Also note that STRD in T32 encoding is special: + * imm = ZeroExtend(imm8:'00', 32) + */ + DECODE_CUSTOM (0xffdf0000, 0xe94d0000, STACK_USE_T32STRD), + + /* | Rn | */ + /* STMDB 1110 1001 00x0 1101 xxxx xxxx xxxx xxxx */ + DECODE_CUSTOM (0xffdf0000, 0xe90d0000, STACK_USE_STMDX), + + /* fall through */ + DECODE_CUSTOM (0, 0, STACK_USE_NONE), + DECODE_END + }; + + return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL); +} + +const struct decode_checker t32_stack_checker[NUM_PROBES_T32_ACTIONS] = { + [PROBES_T32_LDMSTM] = {.checker = t32_check_stack}, + [PROBES_T32_LDRDSTRD] = {.checker = t32_check_stack}, + [PROBES_T32_LDRSTR] = {.checker = t32_check_stack}, +}; + +/* + * See following comments. This insn must be 'push'. + */ +static enum probes_insn __kprobes t16_check_stack(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *h) +{ + unsigned int reglist = insn & 0x1ff; + asi->stack_space = hweight32(reglist) * 4; + return INSN_GOOD; +} + +/* + * T16 encoding is simple: only the 'push' insn can need extra stack space. + * Other insns, like str, can only use r0-r7 as Rn. + */ +const struct decode_checker t16_stack_checker[NUM_PROBES_T16_ACTIONS] = { + [PROBES_T16_PUSH] = {.checker = t16_check_stack}, +}; diff --git a/arch/arm/probes/kprobes/checkers.h b/arch/arm/probes/kprobes/checkers.h new file mode 100644 index 000000000000..cf6c9e74d666 --- /dev/null +++ b/arch/arm/probes/kprobes/checkers.h @@ -0,0 +1,55 @@ +/* + * arch/arm/probes/kprobes/checkers.h + * + * Copyright (C) 2014 Huawei Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#ifndef _ARM_KERNEL_PROBES_CHECKERS_H +#define _ARM_KERNEL_PROBES_CHECKERS_H + +#include +#include +#include "../decode.h" + +extern probes_check_t checker_stack_use_none; +extern probes_check_t checker_stack_use_unknown; +#ifdef CONFIG_THUMB2_KERNEL +extern probes_check_t checker_stack_use_imm_0xx; +#else +extern probes_check_t checker_stack_use_imm_x0x; +#endif +extern probes_check_t checker_stack_use_imm_xxx; +extern probes_check_t checker_stack_use_stmdx; + +enum { + STACK_USE_NONE, + STACK_USE_UNKNOWN, +#ifdef CONFIG_THUMB2_KERNEL + STACK_USE_FIXED_0XX, + STACK_USE_T32STRD, +#else + STACK_USE_FIXED_X0X, +#endif + STACK_USE_FIXED_XXX, + STACK_USE_STMDX, + NUM_STACK_USE_TYPES +}; + +extern const union decode_action stack_check_actions[]; + +#ifndef CONFIG_THUMB2_KERNEL +extern const struct decode_checker arm_stack_checker[]; +extern const struct decode_checker arm_regs_checker[]; +#else +#endif +extern const struct decode_checker t32_stack_checker[]; +extern const struct decode_checker t16_stack_checker[]; +#endif diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/probes/kprobes/core.c similarity index 94% rename from arch/arm/kernel/kprobes.c rename to arch/arm/probes/kprobes/core.c index 6d644202c8dc..a4ec240ee7ba 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/probes/kprobes/core.c @@ -30,11 +30,11 @@ #include #include #include +#include -#include "kprobes.h" -#include "probes-arm.h" -#include "probes-thumb.h" -#include "patch.h" +#include "../decode-arm.h" +#include "../decode-thumb.h" +#include "core.h" #define MIN_STACK_SIZE(addr) \ min((unsigned long)MAX_STACK_SIZE, \ @@ -61,6 +61,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) kprobe_decode_insn_t *decode_insn; const union decode_action *actions; int is; + const struct decode_checker **checkers; if (in_exception_text(addr)) return -EINVAL; @@ -74,9 +75,11 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) insn = __opcode_thumb32_compose(insn, inst2); decode_insn = thumb32_probes_decode_insn; actions = kprobes_t32_actions; + checkers = kprobes_t32_checkers; } else { decode_insn = thumb16_probes_decode_insn; actions = kprobes_t16_actions; + checkers = kprobes_t16_checkers; } #else /* !CONFIG_THUMB2_KERNEL */ thumb = false; @@ -85,12 +88,13 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) insn = __mem_to_opcode_arm(*p->addr); decode_insn = arm_probes_decode_insn; actions = kprobes_arm_actions; + checkers = kprobes_arm_checkers; #endif p->opcode = insn; p->ainsn.insn = tmp_insn; - switch ((*decode_insn)(insn, &p->ainsn, true, actions)) { + switch ((*decode_insn)(insn, &p->ainsn, true, actions, checkers)) { case INSN_REJECTED: /* not supported */ return -EINVAL; @@ -111,6 +115,15 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) break; } + /* + * Never instrument insn like 'str r0, [sp, +/-r1]'. Also, insn likes + * 'str r0, [sp, #-68]' should also be prohibited. + * See __und_svc. + */ + if ((p->ainsn.stack_space < 0) || + (p->ainsn.stack_space > MAX_STACK_SIZE)) + return -EINVAL; + return 0; } @@ -150,19 +163,31 @@ void __kprobes arch_arm_kprobe(struct kprobe *p) * memory. It is also needed to atomically set the two half-words of a 32-bit * Thumb breakpoint. */ -int __kprobes __arch_disarm_kprobe(void *p) +struct patch { + void *addr; + unsigned int insn; +}; + +static int __kprobes_remove_breakpoint(void *data) { - struct kprobe *kp = p; - void *addr = (void *)((uintptr_t)kp->addr & ~1); - - __patch_text(addr, kp->opcode); - + struct patch *p = data; + __patch_text(p->addr, p->insn); return 0; } +void __kprobes kprobes_remove_breakpoint(void *addr, unsigned int insn) +{ + struct patch p = { + .addr = addr, + .insn = insn, + }; + stop_machine(__kprobes_remove_breakpoint, &p, cpu_online_mask); +} + void __kprobes arch_disarm_kprobe(struct kprobe *p) { - stop_machine(__arch_disarm_kprobe, p, cpu_online_mask); + kprobes_remove_breakpoint((void *)((uintptr_t)p->addr & ~1), + p->opcode); } void __kprobes arch_remove_kprobe(struct kprobe *p) diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/probes/kprobes/core.h similarity index 80% rename from arch/arm/kernel/kprobes.h rename to arch/arm/probes/kprobes/core.h index 9a2712ecefc3..ec5d1f20a085 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/probes/kprobes/core.h @@ -19,7 +19,8 @@ #ifndef _ARM_KERNEL_KPROBES_H #define _ARM_KERNEL_KPROBES_H -#include "probes.h" +#include +#include "../decode.h" /* * These undefined instructions must be unique and @@ -29,6 +30,8 @@ #define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18 #define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018 +extern void kprobes_remove_breakpoint(void *addr, unsigned int insn); + enum probes_insn __kprobes kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *h); @@ -36,16 +39,19 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi, typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, struct arch_probes_insn *, bool, - const union decode_action *); + const union decode_action *, + const struct decode_checker *[]); #ifdef CONFIG_THUMB2_KERNEL extern const union decode_action kprobes_t32_actions[]; extern const union decode_action kprobes_t16_actions[]; - +extern const struct decode_checker *kprobes_t32_checkers[]; +extern const struct decode_checker *kprobes_t16_checkers[]; #else /* !CONFIG_THUMB2_KERNEL */ extern const union decode_action kprobes_arm_actions[]; +extern const struct decode_checker *kprobes_arm_checkers[]; #endif diff --git a/arch/arm/probes/kprobes/opt-arm.c b/arch/arm/probes/kprobes/opt-arm.c new file mode 100644 index 000000000000..bcdecc25461b --- /dev/null +++ b/arch/arm/probes/kprobes/opt-arm.c @@ -0,0 +1,370 @@ +/* + * Kernel Probes Jump Optimization (Optprobes) + * + * 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. + * + * Copyright (C) IBM Corporation, 2002, 2004 + * Copyright (C) Hitachi Ltd., 2012 + * Copyright (C) Huawei Inc., 2014 + */ + +#include +#include +#include +#include +/* for arm_gen_branch */ +#include +/* for patch_text */ +#include + +#include "core.h" + +/* + * See register_usage_flags. If the probed instruction doesn't use PC, + * we can copy it into template and have it executed directly without + * simulation or emulation. + */ +#define ARM_REG_PC 15 +#define can_kprobe_direct_exec(m) (!test_bit(ARM_REG_PC, &(m))) + +/* + * NOTE: the first sub and add instruction will be modified according + * to the stack cost of the instruction. + */ +asm ( + ".global optprobe_template_entry\n" + "optprobe_template_entry:\n" + ".global optprobe_template_sub_sp\n" + "optprobe_template_sub_sp:" + " sub sp, sp, #0xff\n" + " stmia sp, {r0 - r14} \n" + ".global optprobe_template_add_sp\n" + "optprobe_template_add_sp:" + " add r3, sp, #0xff\n" + " str r3, [sp, #52]\n" + " mrs r4, cpsr\n" + " str r4, [sp, #64]\n" + " mov r1, sp\n" + " ldr r0, 1f\n" + " ldr r2, 2f\n" + /* + * AEABI requires an 8-bytes alignment stack. If + * SP % 8 != 0 (SP % 4 == 0 should be ensured), + * alloc more bytes here. + */ + " and r4, sp, #4\n" + " sub sp, sp, r4\n" +#if __LINUX_ARM_ARCH__ >= 5 + " blx r2\n" +#else + " mov lr, pc\n" + " mov pc, r2\n" +#endif + " add sp, sp, r4\n" + " ldr r1, [sp, #64]\n" + " tst r1, #"__stringify(PSR_T_BIT)"\n" + " ldrne r2, [sp, #60]\n" + " orrne r2, #1\n" + " strne r2, [sp, #60] @ set bit0 of PC for thumb\n" + " msr cpsr_cxsf, r1\n" + ".global optprobe_template_restore_begin\n" + "optprobe_template_restore_begin:\n" + " ldmia sp, {r0 - r15}\n" + ".global optprobe_template_restore_orig_insn\n" + "optprobe_template_restore_orig_insn:\n" + " nop\n" + ".global optprobe_template_restore_end\n" + "optprobe_template_restore_end:\n" + " nop\n" + ".global optprobe_template_val\n" + "optprobe_template_val:\n" + "1: .long 0\n" + ".global optprobe_template_call\n" + "optprobe_template_call:\n" + "2: .long 0\n" + ".global optprobe_template_end\n" + "optprobe_template_end:\n"); + +#define TMPL_VAL_IDX \ + ((unsigned long *)&optprobe_template_val - (unsigned long *)&optprobe_template_entry) +#define TMPL_CALL_IDX \ + ((unsigned long *)&optprobe_template_call - (unsigned long *)&optprobe_template_entry) +#define TMPL_END_IDX \ + ((unsigned long *)&optprobe_template_end - (unsigned long *)&optprobe_template_entry) +#define TMPL_ADD_SP \ + ((unsigned long *)&optprobe_template_add_sp - (unsigned long *)&optprobe_template_entry) +#define TMPL_SUB_SP \ + ((unsigned long *)&optprobe_template_sub_sp - (unsigned long *)&optprobe_template_entry) +#define TMPL_RESTORE_BEGIN \ + ((unsigned long *)&optprobe_template_restore_begin - (unsigned long *)&optprobe_template_entry) +#define TMPL_RESTORE_ORIGN_INSN \ + ((unsigned long *)&optprobe_template_restore_orig_insn - (unsigned long *)&optprobe_template_entry) +#define TMPL_RESTORE_END \ + ((unsigned long *)&optprobe_template_restore_end - (unsigned long *)&optprobe_template_entry) + +/* + * ARM can always optimize an instruction when using ARM ISA, except + * instructions like 'str r0, [sp, r1]' which store to stack and unable + * to determine stack space consumption statically. + */ +int arch_prepared_optinsn(struct arch_optimized_insn *optinsn) +{ + return optinsn->insn != NULL; +} + +/* + * In ARM ISA, kprobe opt always replace one instruction (4 bytes + * aligned and 4 bytes long). It is impossible to encounter another + * kprobe in the address range. So always return 0. + */ +int arch_check_optimized_kprobe(struct optimized_kprobe *op) +{ + return 0; +} + +/* Caller must ensure addr & 3 == 0 */ +static int can_optimize(struct kprobe *kp) +{ + if (kp->ainsn.stack_space < 0) + return 0; + /* + * 255 is the biggest imm can be used in 'sub r0, r0, #'. + * Number larger than 255 needs special encoding. + */ + if (kp->ainsn.stack_space > 255 - sizeof(struct pt_regs)) + return 0; + return 1; +} + +/* Free optimized instruction slot */ +static void +__arch_remove_optimized_kprobe(struct optimized_kprobe *op, int dirty) +{ + if (op->optinsn.insn) { + free_optinsn_slot(op->optinsn.insn, dirty); + op->optinsn.insn = NULL; + } +} + +extern void kprobe_handler(struct pt_regs *regs); + +static void +optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs) +{ + unsigned long flags; + struct kprobe *p = &op->kp; + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + /* Save skipped registers */ + regs->ARM_pc = (unsigned long)op->kp.addr; + regs->ARM_ORIG_r0 = ~0UL; + + local_irq_save(flags); + + if (kprobe_running()) { + kprobes_inc_nmissed_count(&op->kp); + } else { + __this_cpu_write(current_kprobe, &op->kp); + kcb->kprobe_status = KPROBE_HIT_ACTIVE; + opt_pre_handler(&op->kp, regs); + __this_cpu_write(current_kprobe, NULL); + } + + /* + * We singlestep the replaced instruction only when it can't be + * executed directly during restore. + */ + if (!p->ainsn.kprobe_direct_exec) + op->kp.ainsn.insn_singlestep(p->opcode, &p->ainsn, regs); + + local_irq_restore(flags); +} + +int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *orig) +{ + kprobe_opcode_t *code; + unsigned long rel_chk; + unsigned long val; + unsigned long stack_protect = sizeof(struct pt_regs); + + if (!can_optimize(orig)) + return -EILSEQ; + + code = get_optinsn_slot(); + if (!code) + return -ENOMEM; + + /* + * Verify if the address gap is in 32MiB range, because this uses + * a relative jump. + * + * kprobe opt use a 'b' instruction to branch to optinsn.insn. + * According to ARM manual, branch instruction is: + * + * 31 28 27 24 23 0 + * +------+---+---+---+---+----------------+ + * | cond | 1 | 0 | 1 | 0 | imm24 | + * +------+---+---+---+---+----------------+ + * + * imm24 is a signed 24 bits integer. The real branch offset is computed + * by: imm32 = SignExtend(imm24:'00', 32); + * + * So the maximum forward branch should be: + * (0x007fffff << 2) = 0x01fffffc = 0x1fffffc + * The maximum backword branch should be: + * (0xff800000 << 2) = 0xfe000000 = -0x2000000 + * + * We can simply check (rel & 0xfe000003): + * if rel is positive, (rel & 0xfe000000) shoule be 0 + * if rel is negitive, (rel & 0xfe000000) should be 0xfe000000 + * the last '3' is used for alignment checking. + */ + rel_chk = (unsigned long)((long)code - + (long)orig->addr + 8) & 0xfe000003; + + if ((rel_chk != 0) && (rel_chk != 0xfe000000)) { + /* + * Different from x86, we free code buf directly instead of + * calling __arch_remove_optimized_kprobe() because + * we have not fill any field in op. + */ + free_optinsn_slot(code, 0); + return -ERANGE; + } + + /* Copy arch-dep-instance from template. */ + memcpy(code, &optprobe_template_entry, + TMPL_END_IDX * sizeof(kprobe_opcode_t)); + + /* Adjust buffer according to instruction. */ + BUG_ON(orig->ainsn.stack_space < 0); + + stack_protect += orig->ainsn.stack_space; + + /* Should have been filtered by can_optimize(). */ + BUG_ON(stack_protect > 255); + + /* Create a 'sub sp, sp, #' */ + code[TMPL_SUB_SP] = __opcode_to_mem_arm(0xe24dd000 | stack_protect); + /* Create a 'add r3, sp, #' */ + code[TMPL_ADD_SP] = __opcode_to_mem_arm(0xe28d3000 | stack_protect); + + /* Set probe information */ + val = (unsigned long)op; + code[TMPL_VAL_IDX] = val; + + /* Set probe function call */ + val = (unsigned long)optimized_callback; + code[TMPL_CALL_IDX] = val; + + /* If possible, copy insn and have it executed during restore */ + orig->ainsn.kprobe_direct_exec = false; + if (can_kprobe_direct_exec(orig->ainsn.register_usage_flags)) { + kprobe_opcode_t final_branch = arm_gen_branch( + (unsigned long)(&code[TMPL_RESTORE_END]), + (unsigned long)(op->kp.addr) + 4); + if (final_branch != 0) { + /* + * Replace original 'ldmia sp, {r0 - r15}' with + * 'ldmia {r0 - r14}', restore all registers except pc. + */ + code[TMPL_RESTORE_BEGIN] = __opcode_to_mem_arm(0xe89d7fff); + + /* The original probed instruction */ + code[TMPL_RESTORE_ORIGN_INSN] = __opcode_to_mem_arm(orig->opcode); + + /* Jump back to next instruction */ + code[TMPL_RESTORE_END] = __opcode_to_mem_arm(final_branch); + orig->ainsn.kprobe_direct_exec = true; + } + } + + flush_icache_range((unsigned long)code, + (unsigned long)(&code[TMPL_END_IDX])); + + /* Set op->optinsn.insn means prepared. */ + op->optinsn.insn = code; + return 0; +} + +void __kprobes arch_optimize_kprobes(struct list_head *oplist) +{ + struct optimized_kprobe *op, *tmp; + + list_for_each_entry_safe(op, tmp, oplist, list) { + unsigned long insn; + WARN_ON(kprobe_disabled(&op->kp)); + + /* + * Backup instructions which will be replaced + * by jump address + */ + memcpy(op->optinsn.copied_insn, op->kp.addr, + RELATIVEJUMP_SIZE); + + insn = arm_gen_branch((unsigned long)op->kp.addr, + (unsigned long)op->optinsn.insn); + BUG_ON(insn == 0); + + /* + * Make it a conditional branch if replaced insn + * is consitional + */ + insn = (__mem_to_opcode_arm( + op->optinsn.copied_insn[0]) & 0xf0000000) | + (insn & 0x0fffffff); + + /* + * Similar to __arch_disarm_kprobe, operations which + * removing breakpoints must be wrapped by stop_machine + * to avoid racing. + */ + kprobes_remove_breakpoint(op->kp.addr, insn); + + list_del_init(&op->list); + } +} + +void arch_unoptimize_kprobe(struct optimized_kprobe *op) +{ + arch_arm_kprobe(&op->kp); +} + +/* + * Recover original instructions and breakpoints from relative jumps. + * Caller must call with locking kprobe_mutex. + */ +void arch_unoptimize_kprobes(struct list_head *oplist, + struct list_head *done_list) +{ + struct optimized_kprobe *op, *tmp; + + list_for_each_entry_safe(op, tmp, oplist, list) { + arch_unoptimize_kprobe(op); + list_move(&op->list, done_list); + } +} + +int arch_within_optimized_kprobe(struct optimized_kprobe *op, + unsigned long addr) +{ + return ((unsigned long)op->kp.addr <= addr && + (unsigned long)op->kp.addr + RELATIVEJUMP_SIZE > addr); +} + +void arch_remove_optimized_kprobe(struct optimized_kprobe *op) +{ + __arch_remove_optimized_kprobe(op, 1); +} diff --git a/arch/arm/kernel/kprobes-test-arm.c b/arch/arm/probes/kprobes/test-arm.c similarity index 97% rename from arch/arm/kernel/kprobes-test-arm.c rename to arch/arm/probes/kprobes/test-arm.c index cb1424240ff6..8866aedfdea2 100644 --- a/arch/arm/kernel/kprobes-test-arm.c +++ b/arch/arm/probes/kprobes/test-arm.c @@ -12,8 +12,9 @@ #include #include #include +#include -#include "kprobes-test.h" +#include "test-core.h" #define TEST_ISA "32" @@ -203,9 +204,9 @@ void kprobe_arm_test_cases(void) #endif TEST_GROUP("Miscellaneous instructions") - TEST("mrs r0, cpsr") - TEST("mrspl r7, cpsr") - TEST("mrs r14, cpsr") + TEST_RMASKED("mrs r",0,~PSR_IGNORE_BITS,", cpsr") + TEST_RMASKED("mrspl r",7,~PSR_IGNORE_BITS,", cpsr") + TEST_RMASKED("mrs r",14,~PSR_IGNORE_BITS,", cpsr") TEST_UNSUPPORTED(__inst_arm(0xe10ff000) " @ mrs r15, cpsr") TEST_UNSUPPORTED("mrs r0, spsr") TEST_UNSUPPORTED("mrs lr, spsr") @@ -214,9 +215,12 @@ void kprobe_arm_test_cases(void) TEST_UNSUPPORTED("msr cpsr_f, lr") TEST_UNSUPPORTED("msr spsr, r0") +#if __LINUX_ARM_ARCH__ >= 5 || \ + (__LINUX_ARM_ARCH__ == 4 && !defined(CONFIG_CPU_32v4)) TEST_BF_R("bx r",0,2f,"") TEST_BB_R("bx r",7,2f,"") TEST_BF_R("bxeq r",14,2f,"") +#endif #if __LINUX_ARM_ARCH__ >= 5 TEST_R("clz r0, r",0, 0x0,"") @@ -476,7 +480,9 @@ void kprobe_arm_test_cases(void) TEST_GROUP("Extra load/store instructions") TEST_RPR( "strh r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") - TEST_RPR( "streqh r",14,VAL2,", [r",13,0, ", r",12, 48,"]") + TEST_RPR( "streqh r",14,VAL2,", [r",11,0, ", r",12, 48,"]") + TEST_UNSUPPORTED( "streqh r14, [r13, r12]") + TEST_UNSUPPORTED( "streqh r14, [r12, r13]") TEST_RPR( "strh r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") TEST_RPR( "strneh r",12,VAL2,", [r",11,48,", -r",10,24,"]!") TEST_RPR( "strh r",2, VAL1,", [r",3, 24,"], r",4, 48,"") @@ -501,6 +507,9 @@ void kprobe_arm_test_cases(void) TEST_RP( "strplh r",12,VAL2,", [r",11,24,", #-4]!") TEST_RP( "strh r",2, VAL1,", [r",3, 24,"], #48") TEST_RP( "strh r",10,VAL2,", [r",9, 64,"], #-48") + TEST_RP( "strh r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strh r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RP( "strh r",4, VAL1,", [r",14,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_arm(0xe1efc3b0) " @ strh r12, [pc, #48]!") TEST_UNSUPPORTED(__inst_arm(0xe0c9f3b0) " @ strh pc, [r9], #48") @@ -565,7 +574,9 @@ void kprobe_arm_test_cases(void) #if __LINUX_ARM_ARCH__ >= 5 TEST_RPR( "strd r",0, VAL1,", [r",1, 48,", -r",2,24,"]") - TEST_RPR( "strccd r",8, VAL2,", [r",13,0, ", r",12,48,"]") + TEST_RPR( "strccd r",8, VAL2,", [r",11,0, ", r",12,48,"]") + TEST_UNSUPPORTED( "strccd r8, [r13, r12]") + TEST_UNSUPPORTED( "strccd r8, [r12, r13]") TEST_RPR( "strd r",4, VAL1,", [r",2, 24,", r",3, 48,"]!") TEST_RPR( "strcsd r",12,VAL2,", [r",11,48,", -r",10,24,"]!") TEST_RPR( "strd r",2, VAL1,", [r",5, 24,"], r",4,48,"") @@ -589,6 +600,9 @@ void kprobe_arm_test_cases(void) TEST_RP( "strvcd r",12,VAL2,", [r",11,24,", #-16]!") TEST_RP( "strd r",2, VAL1,", [r",4, 24,"], #48") TEST_RP( "strd r",10,VAL2,", [r",9, 64,"], #-48") + TEST_RP( "strd r",6, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strd r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RP( "strd r",4, VAL1,", [r",12,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_arm(0xe1efc3f0) " @ strd r12, [pc, #48]!") TEST_P( "ldrd r0, [r",0, 24,", #-8]") @@ -637,14 +651,20 @@ void kprobe_arm_test_cases(void) TEST_RP( "str"byte" r",12,VAL2,", [r",11,24,", #-4]!") \ TEST_RP( "str"byte" r",2, VAL1,", [r",3, 24,"], #48") \ TEST_RP( "str"byte" r",10,VAL2,", [r",9, 64,"], #-48") \ + TEST_RP( "str"byte" r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \ + TEST_UNSUPPORTED("str"byte" r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \ + TEST_RP( "str"byte" r",4, VAL1,", [r",10,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") \ - TEST_RPR("str"byte" r",14,VAL2,", [r",13,0, ", r",12, 48,"]") \ + TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 48,"]") \ + TEST_UNSUPPORTED("str"byte" r14, [r13, r12]") \ + TEST_UNSUPPORTED("str"byte" r14, [r12, r13]") \ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") \ TEST_RPR("str"byte" r",12,VAL2,", [r",11,48,", -r",10,24,"]!") \ TEST_RPR("str"byte" r",2, VAL1,", [r",3, 24,"], r",4, 48,"") \ TEST_RPR("str"byte" r",10,VAL2,", [r",9, 48,"], -r",11,24,"") \ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 24,", r",2, 32,", asl #1]")\ - TEST_RPR("str"byte" r",14,VAL2,", [r",13,0, ", r",12, 32,", lsr #2]")\ + TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 32,", lsr #2]")\ + TEST_UNSUPPORTED("str"byte" r14, [r13, r12, lsr #2]") \ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 32,", asr #3]!")\ TEST_RPR("str"byte" r",12,VAL2,", [r",11,24,", r",10, 4,", ror #31]!")\ TEST_P( "ldr"byte" r0, [r",0, 24,", #-2]") \ @@ -668,12 +688,12 @@ void kprobe_arm_test_cases(void) LOAD_STORE("") TEST_P( "str pc, [r",0,0,", #15*4]") - TEST_R( "str pc, [sp, r",2,15*4,"]") + TEST_UNSUPPORTED( "str pc, [sp, r2]") TEST_BF( "ldr pc, [sp, #15*4]") TEST_BF_R("ldr pc, [sp, r",2,15*4,"]") TEST_P( "str sp, [r",0,0,", #13*4]") - TEST_R( "str sp, [sp, r",2,13*4,"]") + TEST_UNSUPPORTED( "str sp, [sp, r2]") TEST_BF( "ldr sp, [sp, #13*4]") TEST_BF_R("ldr sp, [sp, r",2,13*4,"]") diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/probes/kprobes/test-core.c similarity index 98% rename from arch/arm/kernel/kprobes-test.c rename to arch/arm/probes/kprobes/test-core.c index b206d7790c77..9775de22e2ff 100644 --- a/arch/arm/kernel/kprobes-test.c +++ b/arch/arm/probes/kprobes/test-core.c @@ -209,10 +209,10 @@ #include #include -#include "kprobes.h" -#include "probes-arm.h" -#include "probes-thumb.h" -#include "kprobes-test.h" +#include "core.h" +#include "test-core.h" +#include "../decode-arm.h" +#include "../decode-thumb.h" #define BENCHMARKING 1 @@ -236,6 +236,8 @@ static int tests_failed; #ifndef CONFIG_THUMB2_KERNEL +#define RET(reg) "mov pc, "#reg + long arm_func(long r0, long r1); static void __used __naked __arm_kprobes_test_func(void) @@ -245,7 +247,7 @@ static void __used __naked __arm_kprobes_test_func(void) ".type arm_func, %%function \n\t" "arm_func: \n\t" "adds r0, r0, r1 \n\t" - "bx lr \n\t" + "mov pc, lr \n\t" ".code "NORMAL_ISA /* Back to Thumb if necessary */ : : : "r0", "r1", "cc" ); @@ -253,6 +255,8 @@ static void __used __naked __arm_kprobes_test_func(void) #else /* CONFIG_THUMB2_KERNEL */ +#define RET(reg) "bx "#reg + long thumb16_func(long r0, long r1); long thumb32even_func(long r0, long r1); long thumb32odd_func(long r0, long r1); @@ -494,7 +498,7 @@ static void __naked benchmark_nop(void) { __asm__ __volatile__ ( "nop \n\t" - "bx lr" + RET(lr)" \n\t" ); } @@ -977,7 +981,7 @@ void __naked __kprobes_test_case_start(void) "bic r0, lr, #1 @ r0 = inline data \n\t" "mov r1, sp \n\t" "bl kprobes_test_case_start \n\t" - "bx r0 \n\t" + RET(r0)" \n\t" ); } @@ -1056,15 +1060,6 @@ static int test_case_run_count; static bool test_case_is_thumb; static int test_instance; -/* - * We ignore the state of the imprecise abort disable flag (CPSR.A) because this - * can change randomly as the kernel doesn't take care to preserve or initialise - * this across context switches. Also, with Security Extentions, the flag may - * not be under control of the kernel; for this reason we ignore the state of - * the FIQ disable flag CPSR.F as well. - */ -#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT) - static unsigned long test_check_cc(int cc, unsigned long cpsr) { int ret = arm_check_condition(cc << 28, cpsr); @@ -1196,6 +1191,13 @@ static void setup_test_context(struct pt_regs *regs) regs->uregs[arg->reg] = (unsigned long)current_stack + arg->val; memory_needs_checking = true; + /* + * Test memory at an address below SP is in danger of + * being altered by an interrupt occurring and pushing + * data onto the stack. Disable interrupts to stop this. + */ + if (arg->reg == 13) + regs->ARM_cpsr |= PSR_I_BIT; break; } case ARG_TYPE_MEM: { @@ -1264,14 +1266,26 @@ test_case_pre_handler(struct kprobe *p, struct pt_regs *regs) static int __kprobes test_after_pre_handler(struct kprobe *p, struct pt_regs *regs) { + struct test_arg *args; + if (container_of(p, struct test_probe, kprobe)->hit == test_instance) return 0; /* Already run for this test instance */ result_regs = *regs; + + /* Mask out results which are indeterminate */ result_regs.ARM_cpsr &= ~PSR_IGNORE_BITS; + for (args = current_args; args[0].type != ARG_TYPE_END; ++args) + if (args[0].type == ARG_TYPE_REG_MASKED) { + struct test_arg_regptr *arg = + (struct test_arg_regptr *)args; + result_regs.uregs[arg->reg] &= arg->val; + } /* Undo any changes done to SP by the test case */ regs->ARM_sp = (unsigned long)current_stack; + /* Enable interrupts in case setup_test_context disabled them */ + regs->ARM_cpsr &= ~PSR_I_BIT; container_of(p, struct test_probe, kprobe)->hit = test_instance; return 0; diff --git a/arch/arm/kernel/kprobes-test.h b/arch/arm/probes/kprobes/test-core.h similarity index 92% rename from arch/arm/kernel/kprobes-test.h rename to arch/arm/probes/kprobes/test-core.h index 4430990e90e7..94285203e9f7 100644 --- a/arch/arm/kernel/kprobes-test.h +++ b/arch/arm/probes/kprobes/test-core.h @@ -1,5 +1,5 @@ /* - * arch/arm/kernel/kprobes-test.h + * arch/arm/probes/kprobes/test-core.h * * Copyright (C) 2011 Jon Medhurst . * @@ -45,10 +45,11 @@ extern int kprobe_test_cc_position; * */ -#define ARG_TYPE_END 0 -#define ARG_TYPE_REG 1 -#define ARG_TYPE_PTR 2 -#define ARG_TYPE_MEM 3 +#define ARG_TYPE_END 0 +#define ARG_TYPE_REG 1 +#define ARG_TYPE_PTR 2 +#define ARG_TYPE_MEM 3 +#define ARG_TYPE_REG_MASKED 4 #define ARG_FLAG_UNSUPPORTED 0x01 #define ARG_FLAG_SUPPORTED 0x02 @@ -61,7 +62,7 @@ struct test_arg { }; struct test_arg_regptr { - u8 type; /* ARG_TYPE_REG or ARG_TYPE_PTR */ + u8 type; /* ARG_TYPE_REG or ARG_TYPE_PTR or ARG_TYPE_REG_MASKED */ u8 reg; u8 _padding[2]; u32 val; @@ -138,6 +139,12 @@ struct test_arg_end { ".short 0 \n\t" \ ".word "#val" \n\t" +#define TEST_ARG_REG_MASKED(reg, val) \ + ".byte "__stringify(ARG_TYPE_REG_MASKED)" \n\t" \ + ".byte "#reg" \n\t" \ + ".short 0 \n\t" \ + ".word "#val" \n\t" + #define TEST_ARG_END(flags) \ ".byte "__stringify(ARG_TYPE_END)" \n\t" \ ".byte "TEST_ISA flags" \n\t" \ @@ -395,6 +402,22 @@ struct test_arg_end { " "codex" \n\t" \ TESTCASE_END +#define TEST_RMASKED(code1, reg, mask, code2) \ + TESTCASE_START(code1 #reg code2) \ + TEST_ARG_REG_MASKED(reg, mask) \ + TEST_ARG_END("") \ + TEST_INSTRUCTION(code1 #reg code2) \ + TESTCASE_END + +/* + * We ignore the state of the imprecise abort disable flag (CPSR.A) because this + * can change randomly as the kernel doesn't take care to preserve or initialise + * this across context switches. Also, with Security Extensions, the flag may + * not be under control of the kernel; for this reason we ignore the state of + * the FIQ disable flag CPSR.F as well. + */ +#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT) + /* * Macros for defining space directives spread over multiple lines. diff --git a/arch/arm/kernel/kprobes-test-thumb.c b/arch/arm/probes/kprobes/test-thumb.c similarity index 97% rename from arch/arm/kernel/kprobes-test-thumb.c rename to arch/arm/probes/kprobes/test-thumb.c index 844dd10d8593..b683b4517458 100644 --- a/arch/arm/kernel/kprobes-test-thumb.c +++ b/arch/arm/probes/kprobes/test-thumb.c @@ -1,5 +1,5 @@ /* - * arch/arm/kernel/kprobes-test-thumb.c + * arch/arm/probes/kprobes/test-thumb.c * * Copyright (C) 2011 Jon Medhurst . * @@ -11,8 +11,9 @@ #include #include #include +#include -#include "kprobes-test.h" +#include "test-core.h" #define TEST_ISA "16" @@ -416,6 +417,9 @@ void kprobe_thumb32_test_cases(void) TEST_RR( "strd r",14,VAL2,", r",12,VAL1,", [sp, #16]!") TEST_RRP("strd r",1, VAL1,", r",0, VAL2,", [r",7, 24,"], #16") TEST_RR( "strd r",7, VAL2,", r",8, VAL1,", [sp], #-16") + TEST_RRP("strd r",6, VAL1,", r",7, VAL2,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") + TEST_UNSUPPORTED("strd r6, r7, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") + TEST_RRP("strd r",4, VAL1,", r",5, VAL2,", [r",14, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") TEST_UNSUPPORTED(__inst_thumb32(0xe9efec04) " @ strd r14, r12, [pc, #16]!") TEST_UNSUPPORTED(__inst_thumb32(0xe8efec04) " @ strd r14, r12, [pc], #16") @@ -774,8 +778,8 @@ CONDITION_INSTRUCTIONS(22, TEST_UNSUPPORTED("subs pc, lr, #4") - TEST("mrs r0, cpsr") - TEST("mrs r14, cpsr") + TEST_RMASKED("mrs r",0,~PSR_IGNORE_BITS,", cpsr") + TEST_RMASKED("mrs r",14,~PSR_IGNORE_BITS,", cpsr") TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8d00) " @ mrs sp, spsr") TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8f00) " @ mrs pc, spsr") TEST_UNSUPPORTED("mrs r0, spsr") @@ -821,14 +825,22 @@ CONDITION_INSTRUCTIONS(22, TEST_RP( "str"size" r",14,VAL2,", [r",1, 256, ", #-128]!") \ TEST_RPR("str"size".w r",0, VAL1,", [r",1, 0,", r",2, 4,"]") \ TEST_RPR("str"size" r",14,VAL2,", [r",10,0,", r",11,4,", lsl #1]") \ + TEST_UNSUPPORTED("str"size" r0, [r13, r1]") \ TEST_R( "str"size".w r",7, VAL1,", [sp, #24]") \ TEST_RP( "str"size".w r",0, VAL2,", [r",0,0, "]") \ + TEST_RP( "str"size" r",6, VAL1,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \ + TEST_UNSUPPORTED("str"size" r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \ + TEST_RP( "str"size" r",4, VAL2,", [r",12, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \ TEST_UNSUPPORTED("str"size"t r0, [r1, #4]") SINGLE_STORE("b") SINGLE_STORE("h") SINGLE_STORE("") + TEST_UNSUPPORTED(__inst_thumb32(0xf801000d) " @ strb r0, [r1, r13]") + TEST_UNSUPPORTED(__inst_thumb32(0xf821000d) " @ strh r0, [r1, r13]") + TEST_UNSUPPORTED(__inst_thumb32(0xf841000d) " @ str r0, [r1, r13]") + TEST("str sp, [sp]") TEST_UNSUPPORTED(__inst_thumb32(0xf8cfe000) " @ str r14, [pc]") TEST_UNSUPPORTED(__inst_thumb32(0xf8cef000) " @ str pc, [r14]") diff --git a/arch/arm/probes/uprobes/Makefile b/arch/arm/probes/uprobes/Makefile new file mode 100644 index 000000000000..e1dc3d0f6d5a --- /dev/null +++ b/arch/arm/probes/uprobes/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_UPROBES) += core.o actions-arm.o diff --git a/arch/arm/kernel/uprobes-arm.c b/arch/arm/probes/uprobes/actions-arm.c similarity index 97% rename from arch/arm/kernel/uprobes-arm.c rename to arch/arm/probes/uprobes/actions-arm.c index d3b655ff17da..76eb44972ebe 100644 --- a/arch/arm/kernel/uprobes-arm.c +++ b/arch/arm/probes/uprobes/actions-arm.c @@ -13,9 +13,9 @@ #include #include -#include "probes.h" -#include "probes-arm.h" -#include "uprobes.h" +#include "../decode.h" +#include "../decode-arm.h" +#include "core.h" static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs) { @@ -195,8 +195,6 @@ uprobe_decode_ldmstm(probes_opcode_t insn, } const union decode_action uprobes_probes_actions[] = { - [PROBES_EMULATE_NONE] = {.handler = probes_simulate_nop}, - [PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop}, [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop}, [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop}, [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, diff --git a/arch/arm/kernel/uprobes.c b/arch/arm/probes/uprobes/core.c similarity index 97% rename from arch/arm/kernel/uprobes.c rename to arch/arm/probes/uprobes/core.c index 56adf9c1fde0..d1329f1ba4e4 100644 --- a/arch/arm/kernel/uprobes.c +++ b/arch/arm/probes/uprobes/core.c @@ -17,9 +17,9 @@ #include #include -#include "probes.h" -#include "probes-arm.h" -#include "uprobes.h" +#include "../decode.h" +#include "../decode-arm.h" +#include "core.h" #define UPROBE_TRAP_NR UINT_MAX @@ -88,7 +88,7 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN); ret = arm_probes_decode_insn(insn, &auprobe->asi, false, - uprobes_probes_actions); + uprobes_probes_actions, NULL); switch (ret) { case INSN_REJECTED: return -EINVAL; diff --git a/arch/arm/kernel/uprobes.h b/arch/arm/probes/uprobes/core.h similarity index 100% rename from arch/arm/kernel/uprobes.h rename to arch/arm/probes/uprobes/core.h diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c index c7ca936ebd99..263a2044c65b 100644 --- a/arch/arm/xen/enlighten.c +++ b/arch/arm/xen/enlighten.c @@ -29,10 +29,10 @@ struct start_info _xen_start_info; struct start_info *xen_start_info = &_xen_start_info; -EXPORT_SYMBOL_GPL(xen_start_info); +EXPORT_SYMBOL(xen_start_info); enum xen_domain_type xen_domain_type = XEN_NATIVE; -EXPORT_SYMBOL_GPL(xen_domain_type); +EXPORT_SYMBOL(xen_domain_type); struct shared_info xen_dummy_shared_info; struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info; diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c index 351b24a979d4..793551d15f1d 100644 --- a/arch/arm/xen/mm.c +++ b/arch/arm/xen/mm.c @@ -149,7 +149,7 @@ void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order) EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region); struct dma_map_ops *xen_dma_ops; -EXPORT_SYMBOL_GPL(xen_dma_ops); +EXPORT_SYMBOL(xen_dma_ops); static struct dma_map_ops xen_swiotlb_dma_ops = { .mapping_error = xen_swiotlb_dma_mapping_error, diff --git a/arch/arm/xen/p2m.c b/arch/arm/xen/p2m.c index 054857776254..cb7a14c5cd69 100644 --- a/arch/arm/xen/p2m.c +++ b/arch/arm/xen/p2m.c @@ -102,7 +102,7 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, EXPORT_SYMBOL_GPL(set_foreign_p2m_mapping); int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, - struct gnttab_map_grant_ref *kmap_ops, + struct gnttab_unmap_grant_ref *kunmap_ops, struct page **pages, unsigned int count) { int i; diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index b1f9a20a3677..676454a65af8 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -39,6 +39,7 @@ config ARM64 select HARDIRQS_SW_RESEND select HAVE_ALIGNED_STRUCT_PAGE if SLUB select HAVE_ARCH_AUDITSYSCALL + select HAVE_ARCH_BITREVERSE select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_KGDB select HAVE_ARCH_SECCOMP_FILTER @@ -349,7 +350,6 @@ config ARM64_VA_BITS_42 config ARM64_VA_BITS_48 bool "48-bit" - depends on !ARM_SMMU endchoice @@ -540,6 +540,21 @@ config CP15_BARRIER_EMULATION If unsure, say Y +config SETEND_EMULATION + bool "Emulate SETEND instruction" + help + The SETEND instruction alters the data-endianness of the + AArch32 EL0, and is deprecated in ARMv8. + + Say Y here to enable software emulation of the instruction + for AArch32 userspace code. + + Note: All the cpus on the system must have mixed endian support at EL0 + for this feature to be enabled. If a new CPU - which doesn't support mixed + endian - is hotplugged in after this feature has been enabled, there could + be unexpected results in the applications. + + If unsure, say Y endif endmenu @@ -627,9 +642,6 @@ source "kernel/power/Kconfig" config ARCH_SUSPEND_POSSIBLE def_bool y -config ARM64_CPU_SUSPEND - def_bool PM_SLEEP - endmenu menu "CPU Power Management" diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug index 5fdd6dce8061..4a8741073c90 100644 --- a/arch/arm64/Kconfig.debug +++ b/arch/arm64/Kconfig.debug @@ -66,4 +66,27 @@ config DEBUG_SET_MODULE_RONX against certain classes of kernel exploits. If in doubt, say "N". +config DEBUG_RODATA + bool "Make kernel text and rodata read-only" + help + If this is set, kernel text and rodata will be made read-only. This + is to help catch accidental or malicious attempts to change the + kernel's executable code. Additionally splits rodata from kernel + text so it can be made explicitly non-executable. + + If in doubt, say Y + +config DEBUG_ALIGN_RODATA + depends on DEBUG_RODATA && !ARM64_64K_PAGES + bool "Align linker sections up to SECTION_SIZE" + help + If this option is enabled, sections that may potentially be marked as + read only or non-executable will be aligned up to the section size of + the kernel. This prevents sections from being split into pages and + avoids a potential TLB penalty. The downside is an increase in + alignment and potentially wasted space. Turn on this option if + performance is more important than memory pressure. + + If in doubt, say N + endmenu diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 1c43cec971b5..69ceedc982a5 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -15,8 +15,6 @@ CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET) OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S GZFLAGS :=-9 -LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) - KBUILD_DEFCONFIG := defconfig KBUILD_CFLAGS += -mgeneral-regs-only @@ -50,7 +48,6 @@ core-$(CONFIG_KVM) += arch/arm64/kvm/ core-$(CONFIG_XEN) += arch/arm64/xen/ core-$(CONFIG_CRYPTO) += arch/arm64/crypto/ libs-y := arch/arm64/lib/ $(libs-y) -libs-y += $(LIBGCC) libs-$(CONFIG_EFI_STUB) += drivers/firmware/efi/libstub/ # Default target when executing plain make @@ -85,6 +82,7 @@ vdso_install: # We use MRPROPER_FILES and CLEAN_FILES now archclean: $(Q)$(MAKE) $(clean)=$(boot) + $(Q)$(MAKE) $(clean)=$(boot)/dts define archhelp echo '* Image.gz - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)' diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile index 3b8d427c3985..c62b0f4d9ef6 100644 --- a/arch/arm64/boot/dts/Makefile +++ b/arch/arm64/boot/dts/Makefile @@ -3,6 +3,4 @@ dts-dirs += apm dts-dirs += arm dts-dirs += cavium -always := $(dtb-y) subdir-y := $(dts-dirs) -clean-files := *.dtb diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts index cb3073e4e7a8..d429129ecb3d 100644 --- a/arch/arm64/boot/dts/arm/juno.dts +++ b/arch/arm64/boot/dts/arm/juno.dts @@ -22,7 +22,7 @@ }; chosen { - stdout-path = &soc_uart0; + stdout-path = "serial0:115200n8"; }; psci { diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 5376d908eabe..66b6cacc3251 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -45,6 +45,8 @@ CONFIG_CMA=y CONFIG_CMDLINE="console=ttyAMA0" # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y +CONFIG_CPU_IDLE=y +CONFIG_ARM64_CPUIDLE=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y diff --git a/arch/arm64/include/asm/bitrev.h b/arch/arm64/include/asm/bitrev.h new file mode 100644 index 000000000000..a5a0c3660137 --- /dev/null +++ b/arch/arm64/include/asm/bitrev.h @@ -0,0 +1,19 @@ +#ifndef __ASM_BITREV_H +#define __ASM_BITREV_H +static __always_inline __attribute_const__ u32 __arch_bitrev32(u32 x) +{ + __asm__ ("rbit %w0, %w1" : "=r" (x) : "r" (x)); + return x; +} + +static __always_inline __attribute_const__ u16 __arch_bitrev16(u16 x) +{ + return __arch_bitrev32((u32)x) >> 16; +} + +static __always_inline __attribute_const__ u8 __arch_bitrev8(u8 x) +{ + return __arch_bitrev32((u32)x) >> 24; +} + +#endif diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h index 7ae31a2cc6c0..67d309cc3b6b 100644 --- a/arch/arm64/include/asm/cacheflush.h +++ b/arch/arm64/include/asm/cacheflush.h @@ -152,4 +152,9 @@ int set_memory_ro(unsigned long addr, int numpages); int set_memory_rw(unsigned long addr, int numpages); int set_memory_x(unsigned long addr, int numpages); int set_memory_nx(unsigned long addr, int numpages); + +#ifdef CONFIG_DEBUG_RODATA +void mark_rodata_ro(void); +#endif + #endif diff --git a/arch/arm64/include/asm/cachetype.h b/arch/arm64/include/asm/cachetype.h index 4c631a0a3609..da2fc9e3cedd 100644 --- a/arch/arm64/include/asm/cachetype.h +++ b/arch/arm64/include/asm/cachetype.h @@ -39,24 +39,41 @@ extern unsigned long __icache_flags; +/* + * NumSets, bits[27:13] - (Number of sets in cache) - 1 + * Associativity, bits[12:3] - (Associativity of cache) - 1 + * LineSize, bits[2:0] - (Log2(Number of words in cache line)) - 2 + */ +#define CCSIDR_EL1_WRITE_THROUGH BIT(31) +#define CCSIDR_EL1_WRITE_BACK BIT(30) +#define CCSIDR_EL1_READ_ALLOCATE BIT(29) +#define CCSIDR_EL1_WRITE_ALLOCATE BIT(28) #define CCSIDR_EL1_LINESIZE_MASK 0x7 #define CCSIDR_EL1_LINESIZE(x) ((x) & CCSIDR_EL1_LINESIZE_MASK) - +#define CCSIDR_EL1_ASSOCIATIVITY_SHIFT 3 +#define CCSIDR_EL1_ASSOCIATIVITY_MASK 0x3ff +#define CCSIDR_EL1_ASSOCIATIVITY(x) \ + (((x) >> CCSIDR_EL1_ASSOCIATIVITY_SHIFT) & CCSIDR_EL1_ASSOCIATIVITY_MASK) #define CCSIDR_EL1_NUMSETS_SHIFT 13 -#define CCSIDR_EL1_NUMSETS_MASK (0x7fff << CCSIDR_EL1_NUMSETS_SHIFT) +#define CCSIDR_EL1_NUMSETS_MASK 0x7fff #define CCSIDR_EL1_NUMSETS(x) \ - (((x) & CCSIDR_EL1_NUMSETS_MASK) >> CCSIDR_EL1_NUMSETS_SHIFT) + (((x) >> CCSIDR_EL1_NUMSETS_SHIFT) & CCSIDR_EL1_NUMSETS_MASK) -extern u64 __attribute_const__ icache_get_ccsidr(void); +#define CACHE_LINESIZE(x) (16 << CCSIDR_EL1_LINESIZE(x)) +#define CACHE_NUMSETS(x) (CCSIDR_EL1_NUMSETS(x) + 1) +#define CACHE_ASSOCIATIVITY(x) (CCSIDR_EL1_ASSOCIATIVITY(x) + 1) +extern u64 __attribute_const__ cache_get_ccsidr(u64 csselr); + +/* Helpers for Level 1 Instruction cache csselr = 1L */ static inline int icache_get_linesize(void) { - return 16 << CCSIDR_EL1_LINESIZE(icache_get_ccsidr()); + return CACHE_LINESIZE(cache_get_ccsidr(1L)); } static inline int icache_get_numsets(void) { - return 1 + CCSIDR_EL1_NUMSETS(icache_get_ccsidr()); + return CACHE_NUMSETS(cache_get_ccsidr(1L)); } /* diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h index 3fb053fa6e98..7fbed6919b54 100644 --- a/arch/arm64/include/asm/compat.h +++ b/arch/arm64/include/asm/compat.h @@ -161,7 +161,6 @@ typedef struct compat_siginfo { int si_code; union { - /* The padding is the same size as AArch64. */ int _pad[128/sizeof(int) - 3]; /* kill() */ diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h index 6f8e2ef9094a..da301ee7395c 100644 --- a/arch/arm64/include/asm/cpu_ops.h +++ b/arch/arm64/include/asm/cpu_ops.h @@ -28,8 +28,6 @@ struct device_node; * enable-method property. * @cpu_init: Reads any data necessary for a specific enable-method from the * devicetree, for a given cpu node and proposed logical id. - * @cpu_init_idle: Reads any data necessary to initialize CPU idle states from - * devicetree, for a given cpu node and proposed logical id. * @cpu_prepare: Early one-time preparation step for a cpu. If there is a * mechanism for doing so, tests whether it is possible to boot * the given CPU. @@ -42,6 +40,8 @@ struct device_node; * @cpu_die: Makes a cpu leave the kernel. Must not fail. Called from the * cpu being killed. * @cpu_kill: Ensures a cpu has left the kernel. Called from another cpu. + * @cpu_init_idle: Reads any data necessary to initialize CPU idle states from + * devicetree, for a given cpu node and proposed logical id. * @cpu_suspend: Suspends a cpu and saves the required context. May fail owing * to wrong parameters or error conditions. Called from the * CPU being suspended. Must be called with IRQs disabled. @@ -49,7 +49,6 @@ struct device_node; struct cpu_operations { const char *name; int (*cpu_init)(struct device_node *, unsigned int); - int (*cpu_init_idle)(struct device_node *, unsigned int); int (*cpu_prepare)(unsigned int); int (*cpu_boot)(unsigned int); void (*cpu_postboot)(void); @@ -58,7 +57,8 @@ struct cpu_operations { void (*cpu_die)(unsigned int cpu); int (*cpu_kill)(unsigned int cpu); #endif -#ifdef CONFIG_ARM64_CPU_SUSPEND +#ifdef CONFIG_CPU_IDLE + int (*cpu_init_idle)(struct device_node *, unsigned int); int (*cpu_suspend)(unsigned long); #endif }; diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 07547ccc1f2b..b6c16d5f622f 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -52,6 +52,8 @@ static inline void cpus_set_cap(unsigned int num) } void check_local_cpu_errata(void); +bool cpu_supports_mixed_endian_el0(void); +bool system_supports_mixed_endian_el0(void); #endif /* __ASSEMBLY__ */ diff --git a/arch/arm64/include/asm/cpuidle.h b/arch/arm64/include/asm/cpuidle.h index b52a9932e2b1..0710654631e7 100644 --- a/arch/arm64/include/asm/cpuidle.h +++ b/arch/arm64/include/asm/cpuidle.h @@ -3,11 +3,17 @@ #ifdef CONFIG_CPU_IDLE extern int cpu_init_idle(unsigned int cpu); +extern int cpu_suspend(unsigned long arg); #else static inline int cpu_init_idle(unsigned int cpu) { return -EOPNOTSUPP; } + +static inline int cpu_suspend(unsigned long arg) +{ + return -EOPNOTSUPP; +} #endif #endif diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 8adb986a3086..a84ec605bed8 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -72,6 +72,18 @@ #define APM_CPU_PART_POTENZA 0x000 +#define ID_AA64MMFR0_BIGENDEL0_SHIFT 16 +#define ID_AA64MMFR0_BIGENDEL0_MASK (0xf << ID_AA64MMFR0_BIGENDEL0_SHIFT) +#define ID_AA64MMFR0_BIGENDEL0(mmfr0) \ + (((mmfr0) & ID_AA64MMFR0_BIGENDEL0_MASK) >> ID_AA64MMFR0_BIGENDEL0_SHIFT) +#define ID_AA64MMFR0_BIGEND_SHIFT 8 +#define ID_AA64MMFR0_BIGEND_MASK (0xf << ID_AA64MMFR0_BIGEND_SHIFT) +#define ID_AA64MMFR0_BIGEND(mmfr0) \ + (((mmfr0) & ID_AA64MMFR0_BIGEND_MASK) >> ID_AA64MMFR0_BIGEND_SHIFT) + +#define SCTLR_EL1_CP15BEN (0x1 << 5) +#define SCTLR_EL1_SED (0x1 << 8) + #ifndef __ASSEMBLY__ /* @@ -104,6 +116,11 @@ static inline u32 __attribute_const__ read_cpuid_cachetype(void) return read_cpuid(CTR_EL0); } +static inline bool id_aa64mmfr0_mixed_endian_el0(u64 mmfr0) +{ + return (ID_AA64MMFR0_BIGEND(mmfr0) == 0x1) || + (ID_AA64MMFR0_BIGENDEL0(mmfr0) == 0x1); +} #endif /* __ASSEMBLY__ */ #endif diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h index 9ce3e680ae1c..6932bb57dba0 100644 --- a/arch/arm64/include/asm/dma-mapping.h +++ b/arch/arm64/include/asm/dma-mapping.h @@ -28,8 +28,6 @@ #define DMA_ERROR_CODE (~(dma_addr_t)0) extern struct dma_map_ops *dma_ops; -extern struct dma_map_ops coherent_swiotlb_dma_ops; -extern struct dma_map_ops noncoherent_swiotlb_dma_ops; static inline struct dma_map_ops *__generic_dma_ops(struct device *dev) { @@ -47,23 +45,18 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) return __generic_dma_ops(dev); } -static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops) -{ - dev->archdata.dma_ops = ops; -} - static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, struct iommu_ops *iommu, bool coherent) { dev->archdata.dma_coherent = coherent; - if (coherent) - set_dma_ops(dev, &coherent_swiotlb_dma_ops); } #define arch_setup_dma_ops arch_setup_dma_ops /* do not use this function in a driver */ static inline bool is_device_dma_coherent(struct device *dev) { + if (!dev) + return false; return dev->archdata.dma_coherent; } diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index a34fd3b12e2b..ef572206f1c3 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -6,29 +6,33 @@ #ifdef CONFIG_EFI extern void efi_init(void); -extern void efi_idmap_init(void); #else #define efi_init() -#define efi_idmap_init() #endif #define efi_call_virt(f, ...) \ ({ \ - efi_##f##_t *__f = efi.systab->runtime->f; \ + efi_##f##_t *__f; \ efi_status_t __s; \ \ kernel_neon_begin(); \ + efi_virtmap_load(); \ + __f = efi.systab->runtime->f; \ __s = __f(__VA_ARGS__); \ + efi_virtmap_unload(); \ kernel_neon_end(); \ __s; \ }) #define __efi_call_virt(f, ...) \ ({ \ - efi_##f##_t *__f = efi.systab->runtime->f; \ + efi_##f##_t *__f; \ \ kernel_neon_begin(); \ + efi_virtmap_load(); \ + __f = efi.systab->runtime->f; \ __f(__VA_ARGS__); \ + efi_virtmap_unload(); \ kernel_neon_end(); \ }) @@ -44,4 +48,22 @@ extern void efi_idmap_init(void); #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__) +#define EFI_ALLOC_ALIGN SZ_64K + +/* + * On ARM systems, virtually remapped UEFI runtime services are set up in two + * distinct stages: + * - The stub retrieves the final version of the memory map from UEFI, populates + * the virt_addr fields and calls the SetVirtualAddressMap() [SVAM] runtime + * service to communicate the new mapping to the firmware (Note that the new + * mapping is not live at this time) + * - During an early initcall(), the EFI system table is permanently remapped + * and the virtual remapping of the UEFI Runtime Services regions is loaded + * into a private set of page tables. If this all succeeds, the Runtime + * Services are enabled and the EFI_RUNTIME_SERVICES bit set. + */ + +void efi_virtmap_load(void); +void efi_virtmap_unload(void); + #endif /* _ASM_EFI_H */ diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h index 72674f4c3871..62167090937d 100644 --- a/arch/arm64/include/asm/esr.h +++ b/arch/arm64/include/asm/esr.h @@ -18,40 +18,89 @@ #ifndef __ASM_ESR_H #define __ASM_ESR_H -#define ESR_EL1_WRITE (1 << 6) -#define ESR_EL1_CM (1 << 8) -#define ESR_EL1_IL (1 << 25) +#define ESR_ELx_EC_UNKNOWN (0x00) +#define ESR_ELx_EC_WFx (0x01) +/* Unallocated EC: 0x02 */ +#define ESR_ELx_EC_CP15_32 (0x03) +#define ESR_ELx_EC_CP15_64 (0x04) +#define ESR_ELx_EC_CP14_MR (0x05) +#define ESR_ELx_EC_CP14_LS (0x06) +#define ESR_ELx_EC_FP_ASIMD (0x07) +#define ESR_ELx_EC_CP10_ID (0x08) +/* Unallocated EC: 0x09 - 0x0B */ +#define ESR_ELx_EC_CP14_64 (0x0C) +/* Unallocated EC: 0x0d */ +#define ESR_ELx_EC_ILL (0x0E) +/* Unallocated EC: 0x0F - 0x10 */ +#define ESR_ELx_EC_SVC32 (0x11) +#define ESR_ELx_EC_HVC32 (0x12) +#define ESR_ELx_EC_SMC32 (0x13) +/* Unallocated EC: 0x14 */ +#define ESR_ELx_EC_SVC64 (0x15) +#define ESR_ELx_EC_HVC64 (0x16) +#define ESR_ELx_EC_SMC64 (0x17) +#define ESR_ELx_EC_SYS64 (0x18) +/* Unallocated EC: 0x19 - 0x1E */ +#define ESR_ELx_EC_IMP_DEF (0x1f) +#define ESR_ELx_EC_IABT_LOW (0x20) +#define ESR_ELx_EC_IABT_CUR (0x21) +#define ESR_ELx_EC_PC_ALIGN (0x22) +/* Unallocated EC: 0x23 */ +#define ESR_ELx_EC_DABT_LOW (0x24) +#define ESR_ELx_EC_DABT_CUR (0x25) +#define ESR_ELx_EC_SP_ALIGN (0x26) +/* Unallocated EC: 0x27 */ +#define ESR_ELx_EC_FP_EXC32 (0x28) +/* Unallocated EC: 0x29 - 0x2B */ +#define ESR_ELx_EC_FP_EXC64 (0x2C) +/* Unallocated EC: 0x2D - 0x2E */ +#define ESR_ELx_EC_SERROR (0x2F) +#define ESR_ELx_EC_BREAKPT_LOW (0x30) +#define ESR_ELx_EC_BREAKPT_CUR (0x31) +#define ESR_ELx_EC_SOFTSTP_LOW (0x32) +#define ESR_ELx_EC_SOFTSTP_CUR (0x33) +#define ESR_ELx_EC_WATCHPT_LOW (0x34) +#define ESR_ELx_EC_WATCHPT_CUR (0x35) +/* Unallocated EC: 0x36 - 0x37 */ +#define ESR_ELx_EC_BKPT32 (0x38) +/* Unallocated EC: 0x39 */ +#define ESR_ELx_EC_VECTOR32 (0x3A) +/* Unallocted EC: 0x3B */ +#define ESR_ELx_EC_BRK64 (0x3C) +/* Unallocated EC: 0x3D - 0x3F */ +#define ESR_ELx_EC_MAX (0x3F) -#define ESR_EL1_EC_SHIFT (26) -#define ESR_EL1_EC_UNKNOWN (0x00) -#define ESR_EL1_EC_WFI (0x01) -#define ESR_EL1_EC_CP15_32 (0x03) -#define ESR_EL1_EC_CP15_64 (0x04) -#define ESR_EL1_EC_CP14_MR (0x05) -#define ESR_EL1_EC_CP14_LS (0x06) -#define ESR_EL1_EC_FP_ASIMD (0x07) -#define ESR_EL1_EC_CP10_ID (0x08) -#define ESR_EL1_EC_CP14_64 (0x0C) -#define ESR_EL1_EC_ILL_ISS (0x0E) -#define ESR_EL1_EC_SVC32 (0x11) -#define ESR_EL1_EC_SVC64 (0x15) -#define ESR_EL1_EC_SYS64 (0x18) -#define ESR_EL1_EC_IABT_EL0 (0x20) -#define ESR_EL1_EC_IABT_EL1 (0x21) -#define ESR_EL1_EC_PC_ALIGN (0x22) -#define ESR_EL1_EC_DABT_EL0 (0x24) -#define ESR_EL1_EC_DABT_EL1 (0x25) -#define ESR_EL1_EC_SP_ALIGN (0x26) -#define ESR_EL1_EC_FP_EXC32 (0x28) -#define ESR_EL1_EC_FP_EXC64 (0x2C) -#define ESR_EL1_EC_SERROR (0x2F) -#define ESR_EL1_EC_BREAKPT_EL0 (0x30) -#define ESR_EL1_EC_BREAKPT_EL1 (0x31) -#define ESR_EL1_EC_SOFTSTP_EL0 (0x32) -#define ESR_EL1_EC_SOFTSTP_EL1 (0x33) -#define ESR_EL1_EC_WATCHPT_EL0 (0x34) -#define ESR_EL1_EC_WATCHPT_EL1 (0x35) -#define ESR_EL1_EC_BKPT32 (0x38) -#define ESR_EL1_EC_BRK64 (0x3C) +#define ESR_ELx_EC_SHIFT (26) +#define ESR_ELx_EC_MASK (UL(0x3F) << ESR_ELx_EC_SHIFT) + +#define ESR_ELx_IL (UL(1) << 25) +#define ESR_ELx_ISS_MASK (ESR_ELx_IL - 1) +#define ESR_ELx_ISV (UL(1) << 24) +#define ESR_ELx_SAS_SHIFT (22) +#define ESR_ELx_SAS (UL(3) << ESR_ELx_SAS_SHIFT) +#define ESR_ELx_SSE (UL(1) << 21) +#define ESR_ELx_SRT_SHIFT (16) +#define ESR_ELx_SRT_MASK (UL(0x1F) << ESR_ELx_SRT_SHIFT) +#define ESR_ELx_SF (UL(1) << 15) +#define ESR_ELx_AR (UL(1) << 14) +#define ESR_ELx_EA (UL(1) << 9) +#define ESR_ELx_CM (UL(1) << 8) +#define ESR_ELx_S1PTW (UL(1) << 7) +#define ESR_ELx_WNR (UL(1) << 6) +#define ESR_ELx_FSC (0x3F) +#define ESR_ELx_FSC_TYPE (0x3C) +#define ESR_ELx_FSC_EXTABT (0x10) +#define ESR_ELx_FSC_FAULT (0x04) +#define ESR_ELx_FSC_PERM (0x0C) +#define ESR_ELx_CV (UL(1) << 24) +#define ESR_ELx_COND_SHIFT (20) +#define ESR_ELx_COND_MASK (UL(0xF) << ESR_ELx_COND_SHIFT) +#define ESR_ELx_WFx_ISS_WFE (UL(1) << 0) + +#ifndef __ASSEMBLY__ +#include + +const char *esr_get_class_string(u32 esr); +#endif /* __ASSEMBLY */ #endif /* __ASM_ESR_H */ diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h index 9ef6eca905ca..defa0ff98250 100644 --- a/arch/arm64/include/asm/fixmap.h +++ b/arch/arm64/include/asm/fixmap.h @@ -49,6 +49,7 @@ enum fixed_addresses { FIX_BTMAP_END = __end_of_permanent_fixed_addresses, FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1, + FIX_TEXT_POKE0, __end_of_fixed_addresses }; diff --git a/arch/arm64/include/asm/fpsimdmacros.h b/arch/arm64/include/asm/fpsimdmacros.h index 007618b8188c..a2daf1293028 100644 --- a/arch/arm64/include/asm/fpsimdmacros.h +++ b/arch/arm64/include/asm/fpsimdmacros.h @@ -76,7 +76,6 @@ fpsimd_restore_fpcr x\tmpnr, \state .endm -.altmacro .macro fpsimd_save_partial state, numnr, tmpnr1, tmpnr2 mrs x\tmpnr1, fpsr str w\numnr, [\state, #8] @@ -86,11 +85,22 @@ add \state, \state, x\numnr, lsl #4 sub x\tmpnr1, x\tmpnr1, x\numnr, lsl #1 br x\tmpnr1 - .irp qa, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0 - .irp qb, %(qa + 1) - stp q\qa, q\qb, [\state, # -16 * \qa - 16] - .endr - .endr + stp q30, q31, [\state, #-16 * 30 - 16] + stp q28, q29, [\state, #-16 * 28 - 16] + stp q26, q27, [\state, #-16 * 26 - 16] + stp q24, q25, [\state, #-16 * 24 - 16] + stp q22, q23, [\state, #-16 * 22 - 16] + stp q20, q21, [\state, #-16 * 20 - 16] + stp q18, q19, [\state, #-16 * 18 - 16] + stp q16, q17, [\state, #-16 * 16 - 16] + stp q14, q15, [\state, #-16 * 14 - 16] + stp q12, q13, [\state, #-16 * 12 - 16] + stp q10, q11, [\state, #-16 * 10 - 16] + stp q8, q9, [\state, #-16 * 8 - 16] + stp q6, q7, [\state, #-16 * 6 - 16] + stp q4, q5, [\state, #-16 * 4 - 16] + stp q2, q3, [\state, #-16 * 2 - 16] + stp q0, q1, [\state, #-16 * 0 - 16] 0: .endm @@ -103,10 +113,21 @@ add \state, \state, x\tmpnr2, lsl #4 sub x\tmpnr1, x\tmpnr1, x\tmpnr2, lsl #1 br x\tmpnr1 - .irp qa, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0 - .irp qb, %(qa + 1) - ldp q\qa, q\qb, [\state, # -16 * \qa - 16] - .endr - .endr + ldp q30, q31, [\state, #-16 * 30 - 16] + ldp q28, q29, [\state, #-16 * 28 - 16] + ldp q26, q27, [\state, #-16 * 26 - 16] + ldp q24, q25, [\state, #-16 * 24 - 16] + ldp q22, q23, [\state, #-16 * 22 - 16] + ldp q20, q21, [\state, #-16 * 20 - 16] + ldp q18, q19, [\state, #-16 * 18 - 16] + ldp q16, q17, [\state, #-16 * 16 - 16] + ldp q14, q15, [\state, #-16 * 14 - 16] + ldp q12, q13, [\state, #-16 * 12 - 16] + ldp q10, q11, [\state, #-16 * 10 - 16] + ldp q8, q9, [\state, #-16 * 8 - 16] + ldp q6, q7, [\state, #-16 * 6 - 16] + ldp q4, q5, [\state, #-16 * 4 - 16] + ldp q2, q3, [\state, #-16 * 2 - 16] + ldp q0, q1, [\state, #-16 * 0 - 16] 0: .endm diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h index e8a3268a891c..6aae421f4d73 100644 --- a/arch/arm64/include/asm/hardirq.h +++ b/arch/arm64/include/asm/hardirq.h @@ -20,7 +20,7 @@ #include #include -#define NR_IPI 6 +#define NR_IPI 5 typedef struct { unsigned int __softirq_pending; diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h index 949c406d4df4..540f7c0aea82 100644 --- a/arch/arm64/include/asm/io.h +++ b/arch/arm64/include/asm/io.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -145,8 +146,8 @@ static inline u64 __raw_readq(const volatile void __iomem *addr) * I/O port access primitives. */ #define arch_has_dev_port() (1) -#define IO_SPACE_LIMIT (SZ_32M - 1) -#define PCI_IOBASE ((void __iomem *)(MODULES_VADDR - SZ_32M)) +#define IO_SPACE_LIMIT (PCI_IO_SIZE - 1) +#define PCI_IOBASE ((void __iomem *)PCI_IO_START) /* * String version of I/O memory access operations. diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 8afb863f5a9e..94674eb7e7bb 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -18,6 +18,7 @@ #ifndef __ARM64_KVM_ARM_H__ #define __ARM64_KVM_ARM_H__ +#include #include #include @@ -184,77 +185,11 @@ #define MDCR_EL2_TPMCR (1 << 5) #define MDCR_EL2_HPMN_MASK (0x1F) -/* Exception Syndrome Register (ESR) bits */ -#define ESR_EL2_EC_SHIFT (26) -#define ESR_EL2_EC (UL(0x3f) << ESR_EL2_EC_SHIFT) -#define ESR_EL2_IL (UL(1) << 25) -#define ESR_EL2_ISS (ESR_EL2_IL - 1) -#define ESR_EL2_ISV_SHIFT (24) -#define ESR_EL2_ISV (UL(1) << ESR_EL2_ISV_SHIFT) -#define ESR_EL2_SAS_SHIFT (22) -#define ESR_EL2_SAS (UL(3) << ESR_EL2_SAS_SHIFT) -#define ESR_EL2_SSE (1 << 21) -#define ESR_EL2_SRT_SHIFT (16) -#define ESR_EL2_SRT_MASK (0x1f << ESR_EL2_SRT_SHIFT) -#define ESR_EL2_SF (1 << 15) -#define ESR_EL2_AR (1 << 14) -#define ESR_EL2_EA (1 << 9) -#define ESR_EL2_CM (1 << 8) -#define ESR_EL2_S1PTW (1 << 7) -#define ESR_EL2_WNR (1 << 6) -#define ESR_EL2_FSC (0x3f) -#define ESR_EL2_FSC_TYPE (0x3c) - -#define ESR_EL2_CV_SHIFT (24) -#define ESR_EL2_CV (UL(1) << ESR_EL2_CV_SHIFT) -#define ESR_EL2_COND_SHIFT (20) -#define ESR_EL2_COND (UL(0xf) << ESR_EL2_COND_SHIFT) - - -#define FSC_FAULT (0x04) -#define FSC_PERM (0x0c) +/* For compatibility with fault code shared with 32-bit */ +#define FSC_FAULT ESR_ELx_FSC_FAULT +#define FSC_PERM ESR_ELx_FSC_PERM /* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */ #define HPFAR_MASK (~UL(0xf)) -#define ESR_EL2_EC_UNKNOWN (0x00) -#define ESR_EL2_EC_WFI (0x01) -#define ESR_EL2_EC_CP15_32 (0x03) -#define ESR_EL2_EC_CP15_64 (0x04) -#define ESR_EL2_EC_CP14_MR (0x05) -#define ESR_EL2_EC_CP14_LS (0x06) -#define ESR_EL2_EC_FP_ASIMD (0x07) -#define ESR_EL2_EC_CP10_ID (0x08) -#define ESR_EL2_EC_CP14_64 (0x0C) -#define ESR_EL2_EC_ILL_ISS (0x0E) -#define ESR_EL2_EC_SVC32 (0x11) -#define ESR_EL2_EC_HVC32 (0x12) -#define ESR_EL2_EC_SMC32 (0x13) -#define ESR_EL2_EC_SVC64 (0x15) -#define ESR_EL2_EC_HVC64 (0x16) -#define ESR_EL2_EC_SMC64 (0x17) -#define ESR_EL2_EC_SYS64 (0x18) -#define ESR_EL2_EC_IABT (0x20) -#define ESR_EL2_EC_IABT_HYP (0x21) -#define ESR_EL2_EC_PC_ALIGN (0x22) -#define ESR_EL2_EC_DABT (0x24) -#define ESR_EL2_EC_DABT_HYP (0x25) -#define ESR_EL2_EC_SP_ALIGN (0x26) -#define ESR_EL2_EC_FP_EXC32 (0x28) -#define ESR_EL2_EC_FP_EXC64 (0x2C) -#define ESR_EL2_EC_SERROR (0x2F) -#define ESR_EL2_EC_BREAKPT (0x30) -#define ESR_EL2_EC_BREAKPT_HYP (0x31) -#define ESR_EL2_EC_SOFTSTP (0x32) -#define ESR_EL2_EC_SOFTSTP_HYP (0x33) -#define ESR_EL2_EC_WATCHPT (0x34) -#define ESR_EL2_EC_WATCHPT_HYP (0x35) -#define ESR_EL2_EC_BKPT32 (0x38) -#define ESR_EL2_EC_VECTOR32 (0x3A) -#define ESR_EL2_EC_BRK64 (0x3C) - -#define ESR_EL2_EC_xABT_xFSR_EXTABT 0x10 - -#define ESR_EL2_EC_WFI_ISS_WFE (1 << 0) - #endif /* __ARM64_KVM_ARM_H__ */ diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 865a7e28ea2d..0163b5775ca5 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -23,8 +23,10 @@ #define __ARM64_KVM_EMULATE_H__ #include -#include + +#include #include +#include #include #include @@ -45,6 +47,16 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu) vcpu->arch.hcr_el2 &= ~HCR_RW; } +static inline unsigned long vcpu_get_hcr(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.hcr_el2; +} + +static inline void vcpu_set_hcr(struct kvm_vcpu *vcpu, unsigned long hcr) +{ + vcpu->arch.hcr_el2 = hcr; +} + static inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu) { return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pc; @@ -130,63 +142,63 @@ static inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu *vcpu) static inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu) { - return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_ISV); + return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_ISV); } static inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu) { - return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_WNR); + return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WNR); } static inline bool kvm_vcpu_dabt_issext(const struct kvm_vcpu *vcpu) { - return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_SSE); + return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SSE); } static inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu) { - return (kvm_vcpu_get_hsr(vcpu) & ESR_EL2_SRT_MASK) >> ESR_EL2_SRT_SHIFT; + return (kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SRT_MASK) >> ESR_ELx_SRT_SHIFT; } static inline bool kvm_vcpu_dabt_isextabt(const struct kvm_vcpu *vcpu) { - return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_EA); + return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_EA); } static inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu) { - return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_S1PTW); + return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_S1PTW); } static inline int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu) { - return 1 << ((kvm_vcpu_get_hsr(vcpu) & ESR_EL2_SAS) >> ESR_EL2_SAS_SHIFT); + return 1 << ((kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SAS) >> ESR_ELx_SAS_SHIFT); } /* This one is not specific to Data Abort */ static inline bool kvm_vcpu_trap_il_is32bit(const struct kvm_vcpu *vcpu) { - return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_IL); + return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_IL); } static inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu) { - return kvm_vcpu_get_hsr(vcpu) >> ESR_EL2_EC_SHIFT; + return kvm_vcpu_get_hsr(vcpu) >> ESR_ELx_EC_SHIFT; } static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu) { - return kvm_vcpu_trap_get_class(vcpu) == ESR_EL2_EC_IABT; + return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW; } static inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu) { - return kvm_vcpu_get_hsr(vcpu) & ESR_EL2_FSC; + return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_FSC; } static inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu) { - return kvm_vcpu_get_hsr(vcpu) & ESR_EL2_FSC_TYPE; + return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_FSC_TYPE; } static inline unsigned long kvm_vcpu_get_mpidr(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 0b7dfdb931df..acd101a9014d 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -116,9 +116,6 @@ struct kvm_vcpu_arch { * Anything that is not used directly from assembly code goes * here. */ - /* dcache set/way operation pending */ - int last_pcpu; - cpumask_t require_dcache_flush; /* Don't run the guest */ bool pause; diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index 14a74f136272..adcf49547301 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -243,24 +243,46 @@ static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu) return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101; } -static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva, - unsigned long size, - bool ipa_uncached) +static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn, + unsigned long size, + bool ipa_uncached) { + void *va = page_address(pfn_to_page(pfn)); + if (!vcpu_has_cache_enabled(vcpu) || ipa_uncached) - kvm_flush_dcache_to_poc((void *)hva, size); + kvm_flush_dcache_to_poc(va, size); if (!icache_is_aliasing()) { /* PIPT */ - flush_icache_range(hva, hva + size); + flush_icache_range((unsigned long)va, + (unsigned long)va + size); } else if (!icache_is_aivivt()) { /* non ASID-tagged VIVT */ /* any kind of VIPT cache */ __flush_icache_all(); } } +static inline void __kvm_flush_dcache_pte(pte_t pte) +{ + struct page *page = pte_page(pte); + kvm_flush_dcache_to_poc(page_address(page), PAGE_SIZE); +} + +static inline void __kvm_flush_dcache_pmd(pmd_t pmd) +{ + struct page *page = pmd_page(pmd); + kvm_flush_dcache_to_poc(page_address(page), PMD_SIZE); +} + +static inline void __kvm_flush_dcache_pud(pud_t pud) +{ + struct page *page = pud_page(pud); + kvm_flush_dcache_to_poc(page_address(page), PUD_SIZE); +} + #define kvm_virt_to_phys(x) __virt_to_phys((unsigned long)(x)) -void stage2_flush_vm(struct kvm *kvm); +void kvm_set_way_flush(struct kvm_vcpu *vcpu); +void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled); #endif /* __ASSEMBLY__ */ #endif /* __ARM64_KVM_MMU_H__ */ diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 6486b2bfd562..f800d45ea226 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -32,6 +32,12 @@ */ #define UL(x) _AC(x, UL) +/* + * Size of the PCI I/O space. This must remain a power of two so that + * IO_SPACE_LIMIT acts as a mask for the low bits of I/O addresses. + */ +#define PCI_IO_SIZE SZ_16M + /* * PAGE_OFFSET - the virtual address of the start of the kernel image (top * (VA_BITS - 1)) @@ -45,7 +51,9 @@ #define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1)) #define MODULES_END (PAGE_OFFSET) #define MODULES_VADDR (MODULES_END - SZ_64M) -#define FIXADDR_TOP (MODULES_VADDR - SZ_2M - PAGE_SIZE) +#define PCI_IO_END (MODULES_VADDR - SZ_2M) +#define PCI_IO_START (PCI_IO_END - PCI_IO_SIZE) +#define FIXADDR_TOP (PCI_IO_START - SZ_2M) #define TASK_SIZE_64 (UL(1) << VA_BITS) #ifdef CONFIG_COMPAT diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index c2f006c48bdb..3d311761e3c2 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -31,7 +31,8 @@ extern void paging_init(void); extern void setup_mm_for_reboot(void); extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); extern void init_mem_pgprot(void); -/* create an identity mapping for memory (or io if map_io is true) */ -extern void create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io); +extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, + unsigned long virt, phys_addr_t size, + pgprot_t prot); #endif diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 210d632aa5ad..16449c535e50 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -25,7 +25,6 @@ * Software defined PTE bits definition. */ #define PTE_VALID (_AT(pteval_t, 1) << 0) -#define PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !pte_present() */ #define PTE_DIRTY (_AT(pteval_t, 1) << 55) #define PTE_SPECIAL (_AT(pteval_t, 1) << 56) #define PTE_WRITE (_AT(pteval_t, 1) << 57) @@ -46,7 +45,7 @@ #define vmemmap ((struct page *)(VMALLOC_END + SZ_64K)) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #ifndef __ASSEMBLY__ extern void __pte_error(const char *file, int line, unsigned long val); @@ -264,6 +263,11 @@ static inline pmd_t pte_pmd(pte_t pte) return __pmd(pte_val(pte)); } +static inline pgprot_t mk_sect_prot(pgprot_t prot) +{ + return __pgprot(pgprot_val(prot) & ~PTE_TABLE_BIT); +} + /* * THP definitions. */ @@ -337,9 +341,12 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, #ifdef CONFIG_ARM64_64K_PAGES #define pud_sect(pud) (0) +#define pud_table(pud) (1) #else #define pud_sect(pud) ((pud_val(pud) & PUD_TYPE_MASK) == \ PUD_TYPE_SECT) +#define pud_table(pud) ((pud_val(pud) & PUD_TYPE_MASK) == \ + PUD_TYPE_TABLE) #endif static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) @@ -469,13 +476,12 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; /* * Encode and decode a swap entry: * bits 0-1: present (must be zero) - * bit 2: PTE_FILE - * bits 3-8: swap type - * bits 9-57: swap offset + * bits 2-7: swap type + * bits 8-57: swap offset */ -#define __SWP_TYPE_SHIFT 3 +#define __SWP_TYPE_SHIFT 2 #define __SWP_TYPE_BITS 6 -#define __SWP_OFFSET_BITS 49 +#define __SWP_OFFSET_BITS 50 #define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) #define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) #define __SWP_OFFSET_MASK ((1UL << __SWP_OFFSET_BITS) - 1) @@ -493,18 +499,6 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; */ #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS) -/* - * Encode and decode a file entry: - * bits 0-1: present (must be zero) - * bit 2: PTE_FILE - * bits 3-57: file offset / PAGE_SIZE - */ -#define pte_file(pte) (pte_val(pte) & PTE_FILE) -#define pte_to_pgoff(x) (pte_val(x) >> 3) -#define pgoff_to_pte(x) __pte(((x) << 3) | PTE_FILE) - -#define PTE_FILE_MAX_BITS 55 - extern int kern_addr_valid(unsigned long addr); #include diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h index 41ed9e13795e..d6dd9fdbc3be 100644 --- a/arch/arm64/include/asm/ptrace.h +++ b/arch/arm64/include/asm/ptrace.h @@ -58,6 +58,13 @@ #define COMPAT_PSR_Z_BIT 0x40000000 #define COMPAT_PSR_N_BIT 0x80000000 #define COMPAT_PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ + +#ifdef CONFIG_CPU_BIG_ENDIAN +#define COMPAT_PSR_ENDSTATE COMPAT_PSR_E_BIT +#else +#define COMPAT_PSR_ENDSTATE 0 +#endif + /* * These are 'magic' values for PTRACE_PEEKUSR that return info about where a * process is located in memory. diff --git a/arch/arm64/include/asm/suspend.h b/arch/arm64/include/asm/suspend.h index 456d67c1f0fa..003802f58963 100644 --- a/arch/arm64/include/asm/suspend.h +++ b/arch/arm64/include/asm/suspend.h @@ -23,6 +23,4 @@ struct sleep_save_sp { extern int __cpu_suspend(unsigned long arg, int (*fn)(unsigned long)); extern void cpu_resume(void); -extern int cpu_suspend(unsigned long); - #endif diff --git a/arch/arm64/include/asm/syscalls.h b/arch/arm64/include/asm/syscalls.h deleted file mode 100644 index 48fe7c600e98..000000000000 --- a/arch/arm64/include/asm/syscalls.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2012 ARM Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef __ASM_SYSCALLS_H -#define __ASM_SYSCALLS_H - -#include -#include -#include - -/* - * System call wrappers implemented in kernel/entry.S. - */ -asmlinkage long sys_rt_sigreturn_wrapper(void); - -#include - -#endif /* __ASM_SYSCALLS_H */ diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h index 23e9432ac112..3bc498c250dc 100644 --- a/arch/arm64/include/asm/unistd.h +++ b/arch/arm64/include/asm/unistd.h @@ -48,6 +48,9 @@ #endif #define __ARCH_WANT_SYS_CLONE + +#ifndef __COMPAT_SYSCALL_NR #include +#endif #define NR_syscalls (__NR_syscalls) diff --git a/arch/arm64/include/uapi/asm/Kbuild b/arch/arm64/include/uapi/asm/Kbuild index 942376d37d22..825b0fe51c2b 100644 --- a/arch/arm64/include/uapi/asm/Kbuild +++ b/arch/arm64/include/uapi/asm/Kbuild @@ -18,4 +18,5 @@ header-y += siginfo.h header-y += signal.h header-y += stat.h header-y += statfs.h +header-y += ucontext.h header-y += unistd.h diff --git a/arch/arm64/include/asm/ucontext.h b/arch/arm64/include/uapi/asm/ucontext.h similarity index 88% rename from arch/arm64/include/asm/ucontext.h rename to arch/arm64/include/uapi/asm/ucontext.h index 42e04c877428..791de8e89e35 100644 --- a/arch/arm64/include/asm/ucontext.h +++ b/arch/arm64/include/uapi/asm/ucontext.h @@ -13,8 +13,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#ifndef __ASM_UCONTEXT_H -#define __ASM_UCONTEXT_H +#ifndef _UAPI__ASM_UCONTEXT_H +#define _UAPI__ASM_UCONTEXT_H + +#include struct ucontext { unsigned long uc_flags; @@ -27,4 +29,4 @@ struct ucontext { struct sigcontext uc_mcontext; }; -#endif /* __ASM_UCONTEXT_H */ +#endif /* _UAPI__ASM_UCONTEXT_H */ diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index eaa77ed7766a..bef04afd6031 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -16,10 +16,10 @@ arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ entry-fpsimd.o process.o ptrace.o setup.o signal.o \ sys.o stacktrace.o time.o traps.o io.o vdso.o \ hyp-stub.o psci.o cpu_ops.o insn.o return_address.o \ - cpuinfo.o cpu_errata.o alternative.o + cpuinfo.o cpu_errata.o alternative.o cacheinfo.o arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ - sys_compat.o \ + sys_compat.o entry32.o \ ../../arm/kernel/opcodes.o arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o @@ -27,7 +27,7 @@ arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o -arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o +arm64-obj-$(CONFIG_CPU_PM) += sleep.o suspend.o arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o arm64-obj-$(CONFIG_KGDB) += kgdb.o diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index c363671d7509..7922c2e710ca 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -19,6 +19,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include "trace-events-emulation.h" @@ -85,6 +86,57 @@ static void remove_emulation_hooks(struct insn_emulation_ops *ops) pr_notice("Removed %s emulation handler\n", ops->name); } +static void enable_insn_hw_mode(void *data) +{ + struct insn_emulation *insn = (struct insn_emulation *)data; + if (insn->ops->set_hw_mode) + insn->ops->set_hw_mode(true); +} + +static void disable_insn_hw_mode(void *data) +{ + struct insn_emulation *insn = (struct insn_emulation *)data; + if (insn->ops->set_hw_mode) + insn->ops->set_hw_mode(false); +} + +/* Run set_hw_mode(mode) on all active CPUs */ +static int run_all_cpu_set_hw_mode(struct insn_emulation *insn, bool enable) +{ + if (!insn->ops->set_hw_mode) + return -EINVAL; + if (enable) + on_each_cpu(enable_insn_hw_mode, (void *)insn, true); + else + on_each_cpu(disable_insn_hw_mode, (void *)insn, true); + return 0; +} + +/* + * Run set_hw_mode for all insns on a starting CPU. + * Returns: + * 0 - If all the hooks ran successfully. + * -EINVAL - At least one hook is not supported by the CPU. + */ +static int run_all_insn_set_hw_mode(unsigned long cpu) +{ + int rc = 0; + unsigned long flags; + struct insn_emulation *insn; + + raw_spin_lock_irqsave(&insn_emulation_lock, flags); + list_for_each_entry(insn, &insn_emulation, node) { + bool enable = (insn->current_mode == INSN_HW); + if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(enable)) { + pr_warn("CPU[%ld] cannot support the emulation of %s", + cpu, insn->ops->name); + rc = -EINVAL; + } + } + raw_spin_unlock_irqrestore(&insn_emulation_lock, flags); + return rc; +} + static int update_insn_emulation_mode(struct insn_emulation *insn, enum insn_emulation_mode prev) { @@ -97,10 +149,8 @@ static int update_insn_emulation_mode(struct insn_emulation *insn, remove_emulation_hooks(insn->ops); break; case INSN_HW: - if (insn->ops->set_hw_mode) { - insn->ops->set_hw_mode(false); + if (!run_all_cpu_set_hw_mode(insn, false)) pr_notice("Disabled %s support\n", insn->ops->name); - } break; } @@ -111,10 +161,9 @@ static int update_insn_emulation_mode(struct insn_emulation *insn, register_emulation_hooks(insn->ops); break; case INSN_HW: - if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(true)) + ret = run_all_cpu_set_hw_mode(insn, true); + if (!ret) pr_notice("Enabled %s support\n", insn->ops->name); - else - ret = -EINVAL; break; } @@ -133,6 +182,8 @@ static void register_insn_emulation(struct insn_emulation_ops *ops) switch (ops->status) { case INSN_DEPRECATED: insn->current_mode = INSN_EMULATE; + /* Disable the HW mode if it was turned on at early boot time */ + run_all_cpu_set_hw_mode(insn, false); insn->max = INSN_HW; break; case INSN_OBSOLETE: @@ -453,8 +504,6 @@ ret: return 0; } -#define SCTLR_EL1_CP15BEN (1 << 5) - static inline void config_sctlr_el1(u32 clear, u32 set) { u32 val; @@ -465,48 +514,13 @@ static inline void config_sctlr_el1(u32 clear, u32 set) asm volatile("msr sctlr_el1, %0" : : "r" (val)); } -static void enable_cp15_ben(void *info) -{ - config_sctlr_el1(0, SCTLR_EL1_CP15BEN); -} - -static void disable_cp15_ben(void *info) -{ - config_sctlr_el1(SCTLR_EL1_CP15BEN, 0); -} - -static int cpu_hotplug_notify(struct notifier_block *b, - unsigned long action, void *hcpu) -{ - switch (action) { - case CPU_STARTING: - case CPU_STARTING_FROZEN: - enable_cp15_ben(NULL); - return NOTIFY_DONE; - case CPU_DYING: - case CPU_DYING_FROZEN: - disable_cp15_ben(NULL); - return NOTIFY_DONE; - } - - return NOTIFY_OK; -} - -static struct notifier_block cpu_hotplug_notifier = { - .notifier_call = cpu_hotplug_notify, -}; - static int cp15_barrier_set_hw_mode(bool enable) { - if (enable) { - register_cpu_notifier(&cpu_hotplug_notifier); - on_each_cpu(enable_cp15_ben, NULL, true); - } else { - unregister_cpu_notifier(&cpu_hotplug_notifier); - on_each_cpu(disable_cp15_ben, NULL, true); - } - - return true; + if (enable) + config_sctlr_el1(0, SCTLR_EL1_CP15BEN); + else + config_sctlr_el1(SCTLR_EL1_CP15BEN, 0); + return 0; } static struct undef_hook cp15_barrier_hooks[] = { @@ -534,6 +548,93 @@ static struct insn_emulation_ops cp15_barrier_ops = { .set_hw_mode = cp15_barrier_set_hw_mode, }; +static int setend_set_hw_mode(bool enable) +{ + if (!cpu_supports_mixed_endian_el0()) + return -EINVAL; + + if (enable) + config_sctlr_el1(SCTLR_EL1_SED, 0); + else + config_sctlr_el1(0, SCTLR_EL1_SED); + return 0; +} + +static int compat_setend_handler(struct pt_regs *regs, u32 big_endian) +{ + char *insn; + + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); + + if (big_endian) { + insn = "setend be"; + regs->pstate |= COMPAT_PSR_E_BIT; + } else { + insn = "setend le"; + regs->pstate &= ~COMPAT_PSR_E_BIT; + } + + trace_instruction_emulation(insn, regs->pc); + pr_warn_ratelimited("\"%s\" (%ld) uses deprecated setend instruction at 0x%llx\n", + current->comm, (unsigned long)current->pid, regs->pc); + + return 0; +} + +static int a32_setend_handler(struct pt_regs *regs, u32 instr) +{ + int rc = compat_setend_handler(regs, (instr >> 9) & 1); + regs->pc += 4; + return rc; +} + +static int t16_setend_handler(struct pt_regs *regs, u32 instr) +{ + int rc = compat_setend_handler(regs, (instr >> 3) & 1); + regs->pc += 2; + return rc; +} + +static struct undef_hook setend_hooks[] = { + { + .instr_mask = 0xfffffdff, + .instr_val = 0xf1010000, + .pstate_mask = COMPAT_PSR_MODE_MASK, + .pstate_val = COMPAT_PSR_MODE_USR, + .fn = a32_setend_handler, + }, + { + /* Thumb mode */ + .instr_mask = 0x0000fff7, + .instr_val = 0x0000b650, + .pstate_mask = (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_MASK), + .pstate_val = (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_USR), + .fn = t16_setend_handler, + }, + {} +}; + +static struct insn_emulation_ops setend_ops = { + .name = "setend", + .status = INSN_DEPRECATED, + .hooks = setend_hooks, + .set_hw_mode = setend_set_hw_mode, +}; + +static int insn_cpu_hotplug_notify(struct notifier_block *b, + unsigned long action, void *hcpu) +{ + int rc = 0; + if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING) + rc = run_all_insn_set_hw_mode((unsigned long)hcpu); + + return notifier_from_errno(rc); +} + +static struct notifier_block insn_cpu_hotplug_notifier = { + .notifier_call = insn_cpu_hotplug_notify, +}; + /* * Invoked as late_initcall, since not needed before init spawned. */ @@ -545,6 +646,14 @@ static int __init armv8_deprecated_init(void) if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION)) register_insn_emulation(&cp15_barrier_ops); + if (IS_ENABLED(CONFIG_SETEND_EMULATION)) { + if(system_supports_mixed_endian_el0()) + register_insn_emulation(&setend_ops); + else + pr_info("setend instruction emulation is not supported on the system"); + } + + register_cpu_notifier(&insn_cpu_hotplug_notifier); register_insn_emulation_sysctl(ctl_abi); return 0; diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 9a9fce090d58..a2ae19403abb 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -152,7 +152,7 @@ int main(void) DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr)); DEFINE(KVM_VGIC_VCTRL, offsetof(struct kvm, arch.vgic.vctrl_base)); #endif -#ifdef CONFIG_ARM64_CPU_SUSPEND +#ifdef CONFIG_CPU_PM DEFINE(CPU_SUSPEND_SZ, sizeof(struct cpu_suspend_ctx)); DEFINE(CPU_CTX_SP, offsetof(struct cpu_suspend_ctx, sp)); DEFINE(MPIDR_HASH_MASK, offsetof(struct mpidr_hash, mask)); diff --git a/arch/arm64/kernel/cacheinfo.c b/arch/arm64/kernel/cacheinfo.c new file mode 100644 index 000000000000..b8629d52fba9 --- /dev/null +++ b/arch/arm64/kernel/cacheinfo.c @@ -0,0 +1,128 @@ +/* + * ARM64 cacheinfo support + * + * Copyright (C) 2015 ARM Ltd. + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define MAX_CACHE_LEVEL 7 /* Max 7 level supported */ +/* Ctypen, bits[3(n - 1) + 2 : 3(n - 1)], for n = 1 to 7 */ +#define CLIDR_CTYPE_SHIFT(level) (3 * (level - 1)) +#define CLIDR_CTYPE_MASK(level) (7 << CLIDR_CTYPE_SHIFT(level)) +#define CLIDR_CTYPE(clidr, level) \ + (((clidr) & CLIDR_CTYPE_MASK(level)) >> CLIDR_CTYPE_SHIFT(level)) + +static inline enum cache_type get_cache_type(int level) +{ + u64 clidr; + + if (level > MAX_CACHE_LEVEL) + return CACHE_TYPE_NOCACHE; + asm volatile ("mrs %x0, clidr_el1" : "=r" (clidr)); + return CLIDR_CTYPE(clidr, level); +} + +/* + * Cache Size Selection Register(CSSELR) selects which Cache Size ID + * Register(CCSIDR) is accessible by specifying the required cache + * level and the cache type. We need to ensure that no one else changes + * CSSELR by calling this in non-preemtible context + */ +u64 __attribute_const__ cache_get_ccsidr(u64 csselr) +{ + u64 ccsidr; + + WARN_ON(preemptible()); + + /* Put value into CSSELR */ + asm volatile("msr csselr_el1, %x0" : : "r" (csselr)); + isb(); + /* Read result out of CCSIDR */ + asm volatile("mrs %x0, ccsidr_el1" : "=r" (ccsidr)); + + return ccsidr; +} + +static void ci_leaf_init(struct cacheinfo *this_leaf, + enum cache_type type, unsigned int level) +{ + bool is_icache = type & CACHE_TYPE_INST; + u64 tmp = cache_get_ccsidr((level - 1) << 1 | is_icache); + + this_leaf->level = level; + this_leaf->type = type; + this_leaf->coherency_line_size = CACHE_LINESIZE(tmp); + this_leaf->number_of_sets = CACHE_NUMSETS(tmp); + this_leaf->ways_of_associativity = CACHE_ASSOCIATIVITY(tmp); + this_leaf->size = this_leaf->number_of_sets * + this_leaf->coherency_line_size * this_leaf->ways_of_associativity; + this_leaf->attributes = + ((tmp & CCSIDR_EL1_WRITE_THROUGH) ? CACHE_WRITE_THROUGH : 0) | + ((tmp & CCSIDR_EL1_WRITE_BACK) ? CACHE_WRITE_BACK : 0) | + ((tmp & CCSIDR_EL1_READ_ALLOCATE) ? CACHE_READ_ALLOCATE : 0) | + ((tmp & CCSIDR_EL1_WRITE_ALLOCATE) ? CACHE_WRITE_ALLOCATE : 0); +} + +static int __init_cache_level(unsigned int cpu) +{ + unsigned int ctype, level, leaves; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + + for (level = 1, leaves = 0; level <= MAX_CACHE_LEVEL; level++) { + ctype = get_cache_type(level); + if (ctype == CACHE_TYPE_NOCACHE) { + level--; + break; + } + /* Separate instruction and data caches */ + leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1; + } + + this_cpu_ci->num_levels = level; + this_cpu_ci->num_leaves = leaves; + return 0; +} + +static int __populate_cache_leaves(unsigned int cpu) +{ + unsigned int level, idx; + enum cache_type type; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *this_leaf = this_cpu_ci->info_list; + + for (idx = 0, level = 1; level <= this_cpu_ci->num_levels && + idx < this_cpu_ci->num_leaves; idx++, level++) { + type = get_cache_type(level); + if (type == CACHE_TYPE_SEPARATE) { + ci_leaf_init(this_leaf++, CACHE_TYPE_DATA, level); + ci_leaf_init(this_leaf++, CACHE_TYPE_INST, level); + } else { + ci_leaf_init(this_leaf++, type, level); + } + } + return 0; +} + +DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level) +DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves) diff --git a/arch/arm64/kernel/cpuidle.c b/arch/arm64/kernel/cpuidle.c index 19d17f51db37..5c0896647fd1 100644 --- a/arch/arm64/kernel/cpuidle.c +++ b/arch/arm64/kernel/cpuidle.c @@ -29,3 +29,23 @@ int cpu_init_idle(unsigned int cpu) of_node_put(cpu_node); return ret; } + +/** + * cpu_suspend() - function to enter a low-power idle state + * @arg: argument to pass to CPU suspend operations + * + * Return: 0 on success, -EOPNOTSUPP if CPU suspend hook not initialized, CPU + * operations back-end error code otherwise. + */ +int cpu_suspend(unsigned long arg) +{ + int cpu = smp_processor_id(); + + /* + * If cpu_ops have not been registered or suspend + * has not been initialized, cpu_suspend call fails early. + */ + if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_suspend) + return -EOPNOTSUPP; + return cpu_ops[cpu]->cpu_suspend(arg); +} diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index 07d435cf2eea..929855691dae 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -35,6 +35,7 @@ */ DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data); static struct cpuinfo_arm64 boot_cpu_data; +static bool mixed_endian_el0 = true; static char *icache_policy_str[] = { [ICACHE_POLICY_RESERVED] = "RESERVED/UNKNOWN", @@ -68,6 +69,26 @@ static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info) pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu); } +bool cpu_supports_mixed_endian_el0(void) +{ + return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1)); +} + +bool system_supports_mixed_endian_el0(void) +{ + return mixed_endian_el0; +} + +static void update_mixed_endian_el0_support(struct cpuinfo_arm64 *info) +{ + mixed_endian_el0 &= id_aa64mmfr0_mixed_endian_el0(info->reg_id_aa64mmfr0); +} + +static void update_cpu_features(struct cpuinfo_arm64 *info) +{ + update_mixed_endian_el0_support(info); +} + static int check_reg_mask(char *name, u64 mask, u64 boot, u64 cur, int cpu) { if ((boot & mask) == (cur & mask)) @@ -215,6 +236,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) cpuinfo_detect_icache_policy(info); check_local_cpu_errata(); + update_cpu_features(info); } void cpuinfo_store_cpu(void) @@ -231,15 +253,3 @@ void __init cpuinfo_store_boot_cpu(void) boot_cpu_data = *info; } - -u64 __attribute_const__ icache_get_ccsidr(void) -{ - u64 ccsidr; - - WARN_ON(preemptible()); - - /* Select L1 I-cache and read its size ID register */ - asm("msr csselr_el1, %1; isb; mrs %0, ccsidr_el1" - : "=r"(ccsidr) : "r"(1L)); - return ccsidr; -} diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c index d27dd982ff26..f5374065ad53 100644 --- a/arch/arm64/kernel/efi-stub.c +++ b/arch/arm64/kernel/efi-stub.c @@ -13,13 +13,13 @@ #include #include -efi_status_t handle_kernel_image(efi_system_table_t *sys_table, - unsigned long *image_addr, - unsigned long *image_size, - unsigned long *reserve_addr, - unsigned long *reserve_size, - unsigned long dram_base, - efi_loaded_image_t *image) +efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table, + unsigned long *image_addr, + unsigned long *image_size, + unsigned long *reserve_addr, + unsigned long *reserve_size, + unsigned long dram_base, + efi_loaded_image_t *image) { efi_status_t status; unsigned long kernel_size, kernel_memsize = 0; diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 2bb4347d0edf..b42c7b480e1e 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -11,27 +11,46 @@ * */ +#include #include #include #include #include +#include #include #include #include +#include +#include +#include #include #include +#include #include #include #include #include +#include +#include struct efi_memory_map memmap; -static efi_runtime_services_t *runtime; - static u64 efi_system_table; +static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss; + +static struct mm_struct efi_mm = { + .mm_rb = RB_ROOT, + .pgd = efi_pgd, + .mm_users = ATOMIC_INIT(2), + .mm_count = ATOMIC_INIT(1), + .mmap_sem = __RWSEM_INITIALIZER(efi_mm.mmap_sem), + .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock), + .mmlist = LIST_HEAD_INIT(efi_mm.mmlist), + INIT_MM_CONTEXT(efi_mm) +}; + static int uefi_debug __initdata; static int __init uefi_debug_setup(char *str) { @@ -48,30 +67,33 @@ static int __init is_normal_ram(efi_memory_desc_t *md) return 0; } -static void __init efi_setup_idmap(void) +/* + * Translate a EFI virtual address into a physical address: this is necessary, + * as some data members of the EFI system table are virtually remapped after + * SetVirtualAddressMap() has been called. + */ +static phys_addr_t efi_to_phys(unsigned long addr) { - struct memblock_region *r; efi_memory_desc_t *md; - u64 paddr, npages, size; - for_each_memblock(memory, r) - create_id_mapping(r->base, r->size, 0); - - /* map runtime io spaces */ for_each_efi_memory_desc(&memmap, md) { - if (!(md->attribute & EFI_MEMORY_RUNTIME) || is_normal_ram(md)) + if (!(md->attribute & EFI_MEMORY_RUNTIME)) continue; - paddr = md->phys_addr; - npages = md->num_pages; - memrange_efi_to_native(&paddr, &npages); - size = npages << PAGE_SHIFT; - create_id_mapping(paddr, size, 1); + if (md->virt_addr == 0) + /* no virtual mapping has been installed by the stub */ + break; + if (md->virt_addr <= addr && + (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT)) + return md->phys_addr + addr - md->virt_addr; } + return addr; } static int __init uefi_init(void) { efi_char16_t *c16; + void *config_tables; + u64 table_size; char vendor[100] = "unknown"; int i, retval; @@ -99,7 +121,7 @@ static int __init uefi_init(void) efi.systab->hdr.revision & 0xffff); /* Show what we know for posterity */ - c16 = early_memremap(efi.systab->fw_vendor, + c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor), sizeof(vendor)); if (c16) { for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) @@ -112,8 +134,14 @@ static int __init uefi_init(void) efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff, vendor); - retval = efi_config_init(NULL); + table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables; + config_tables = early_memremap(efi_to_phys(efi.systab->tables), + table_size); + retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables, + sizeof(efi_config_table_64_t), NULL); + + early_memunmap(config_tables, table_size); out: early_memunmap(efi.systab, sizeof(efi_system_table_t)); return retval; @@ -163,9 +191,7 @@ static __init void reserve_regions(void) if (is_normal_ram(md)) early_init_dt_add_memory_arch(paddr, size); - if (is_reserve_region(md) || - md->type == EFI_BOOT_SERVICES_CODE || - md->type == EFI_BOOT_SERVICES_DATA) { + if (is_reserve_region(md)) { memblock_reserve(paddr, size); if (uefi_debug) pr_cont("*"); @@ -178,123 +204,6 @@ static __init void reserve_regions(void) set_bit(EFI_MEMMAP, &efi.flags); } - -static u64 __init free_one_region(u64 start, u64 end) -{ - u64 size = end - start; - - if (uefi_debug) - pr_info(" EFI freeing: 0x%012llx-0x%012llx\n", start, end - 1); - - free_bootmem_late(start, size); - return size; -} - -static u64 __init free_region(u64 start, u64 end) -{ - u64 map_start, map_end, total = 0; - - if (end <= start) - return total; - - map_start = (u64)memmap.phys_map; - map_end = PAGE_ALIGN(map_start + (memmap.map_end - memmap.map)); - map_start &= PAGE_MASK; - - if (start < map_end && end > map_start) { - /* region overlaps UEFI memmap */ - if (start < map_start) - total += free_one_region(start, map_start); - - if (map_end < end) - total += free_one_region(map_end, end); - } else - total += free_one_region(start, end); - - return total; -} - -static void __init free_boot_services(void) -{ - u64 total_freed = 0; - u64 keep_end, free_start, free_end; - efi_memory_desc_t *md; - - /* - * If kernel uses larger pages than UEFI, we have to be careful - * not to inadvertantly free memory we want to keep if there is - * overlap at the kernel page size alignment. We do not want to - * free is_reserve_region() memory nor the UEFI memmap itself. - * - * The memory map is sorted, so we keep track of the end of - * any previous region we want to keep, remember any region - * we want to free and defer freeing it until we encounter - * the next region we want to keep. This way, before freeing - * it, we can clip it as needed to avoid freeing memory we - * want to keep for UEFI. - */ - - keep_end = 0; - free_start = 0; - - for_each_efi_memory_desc(&memmap, md) { - u64 paddr, npages, size; - - if (is_reserve_region(md)) { - /* - * We don't want to free any memory from this region. - */ - if (free_start) { - /* adjust free_end then free region */ - if (free_end > md->phys_addr) - free_end -= PAGE_SIZE; - total_freed += free_region(free_start, free_end); - free_start = 0; - } - keep_end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT); - continue; - } - - if (md->type != EFI_BOOT_SERVICES_CODE && - md->type != EFI_BOOT_SERVICES_DATA) { - /* no need to free this region */ - continue; - } - - /* - * We want to free memory from this region. - */ - paddr = md->phys_addr; - npages = md->num_pages; - memrange_efi_to_native(&paddr, &npages); - size = npages << PAGE_SHIFT; - - if (free_start) { - if (paddr <= free_end) - free_end = paddr + size; - else { - total_freed += free_region(free_start, free_end); - free_start = paddr; - free_end = paddr + size; - } - } else { - free_start = paddr; - free_end = paddr + size; - } - if (free_start < keep_end) { - free_start += PAGE_SIZE; - if (free_start >= free_end) - free_start = 0; - } - } - if (free_start) - total_freed += free_region(free_start, free_end); - - if (total_freed) - pr_info("Freed 0x%llx bytes of EFI boot services memory", - total_freed); -} - void __init efi_init(void) { struct efi_fdt_params params; @@ -317,159 +226,100 @@ void __init efi_init(void) return; reserve_regions(); + early_memunmap(memmap.map, params.mmap_size); } -void __init efi_idmap_init(void) +static bool __init efi_virtmap_init(void) { - if (!efi_enabled(EFI_BOOT)) - return; + efi_memory_desc_t *md; - /* boot time idmap_pg_dir is incomplete, so fill in missing parts */ - efi_setup_idmap(); - early_memunmap(memmap.map, memmap.map_end - memmap.map); -} + for_each_efi_memory_desc(&memmap, md) { + u64 paddr, npages, size; + pgprot_t prot; -static int __init remap_region(efi_memory_desc_t *md, void **new) -{ - u64 paddr, vaddr, npages, size; + if (!(md->attribute & EFI_MEMORY_RUNTIME)) + continue; + if (md->virt_addr == 0) + return false; - paddr = md->phys_addr; - npages = md->num_pages; - memrange_efi_to_native(&paddr, &npages); - size = npages << PAGE_SHIFT; + paddr = md->phys_addr; + npages = md->num_pages; + memrange_efi_to_native(&paddr, &npages); + size = npages << PAGE_SHIFT; - if (is_normal_ram(md)) - vaddr = (__force u64)ioremap_cache(paddr, size); - else - vaddr = (__force u64)ioremap(paddr, size); - - if (!vaddr) { - pr_err("Unable to remap 0x%llx pages @ %p\n", - npages, (void *)paddr); - return 0; - } - - /* adjust for any rounding when EFI and system pagesize differs */ - md->virt_addr = vaddr + (md->phys_addr - paddr); - - if (uefi_debug) - pr_info(" EFI remap 0x%012llx => %p\n", + pr_info(" EFI remap 0x%016llx => %p\n", md->phys_addr, (void *)md->virt_addr); - memcpy(*new, md, memmap.desc_size); - *new += memmap.desc_size; + /* + * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be + * executable, everything else can be mapped with the XN bits + * set. + */ + if (!is_normal_ram(md)) + prot = __pgprot(PROT_DEVICE_nGnRE); + else if (md->type == EFI_RUNTIME_SERVICES_CODE) + prot = PAGE_KERNEL_EXEC; + else + prot = PAGE_KERNEL; - return 1; + create_pgd_mapping(&efi_mm, paddr, md->virt_addr, size, prot); + } + return true; } /* - * Switch UEFI from an identity map to a kernel virtual map + * Enable the UEFI Runtime Services if all prerequisites are in place, i.e., + * non-early mapping of the UEFI system table and virtual mappings for all + * EFI_MEMORY_RUNTIME regions. */ -static int __init arm64_enter_virtual_mode(void) +static int __init arm64_enable_runtime_services(void) { - efi_memory_desc_t *md; - phys_addr_t virtmap_phys; - void *virtmap, *virt_md; - efi_status_t status; u64 mapsize; - int count = 0; - unsigned long flags; if (!efi_enabled(EFI_BOOT)) { pr_info("EFI services will not be available.\n"); return -1; } - mapsize = memmap.map_end - memmap.map; - if (efi_runtime_disabled()) { pr_info("EFI runtime services will be disabled.\n"); return -1; } pr_info("Remapping and enabling EFI services.\n"); - /* replace early memmap mapping with permanent mapping */ + + mapsize = memmap.map_end - memmap.map; memmap.map = (__force void *)ioremap_cache((phys_addr_t)memmap.phys_map, mapsize); - memmap.map_end = memmap.map + mapsize; - - efi.memmap = &memmap; - - /* Map the runtime regions */ - virtmap = kmalloc(mapsize, GFP_KERNEL); - if (!virtmap) { - pr_err("Failed to allocate EFI virtual memmap\n"); + if (!memmap.map) { + pr_err("Failed to remap EFI memory map\n"); return -1; } - virtmap_phys = virt_to_phys(virtmap); - virt_md = virtmap; + memmap.map_end = memmap.map + mapsize; + efi.memmap = &memmap; - for_each_efi_memory_desc(&memmap, md) { - if (!(md->attribute & EFI_MEMORY_RUNTIME)) - continue; - if (!remap_region(md, &virt_md)) - goto err_unmap; - ++count; - } - - efi.systab = (__force void *)efi_lookup_mapped_addr(efi_system_table); + efi.systab = (__force void *)ioremap_cache(efi_system_table, + sizeof(efi_system_table_t)); if (!efi.systab) { - /* - * If we have no virtual mapping for the System Table at this - * point, the memory map doesn't cover the physical offset where - * it resides. This means the System Table will be inaccessible - * to Runtime Services themselves once the virtual mapping is - * installed. - */ - pr_err("Failed to remap EFI System Table -- buggy firmware?\n"); - goto err_unmap; + pr_err("Failed to remap EFI System Table\n"); + return -1; } set_bit(EFI_SYSTEM_TABLES, &efi.flags); - local_irq_save(flags); - cpu_switch_mm(idmap_pg_dir, &init_mm); - - /* Call SetVirtualAddressMap with the physical address of the map */ - runtime = efi.systab->runtime; - efi.set_virtual_address_map = runtime->set_virtual_address_map; - - status = efi.set_virtual_address_map(count * memmap.desc_size, - memmap.desc_size, - memmap.desc_version, - (efi_memory_desc_t *)virtmap_phys); - cpu_set_reserved_ttbr0(); - flush_tlb_all(); - local_irq_restore(flags); - - kfree(virtmap); - - free_boot_services(); - - if (status != EFI_SUCCESS) { - pr_err("Failed to set EFI virtual address map! [%lx]\n", - status); + if (!efi_virtmap_init()) { + pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n"); return -1; } /* Set up runtime services function pointers */ - runtime = efi.systab->runtime; efi_native_runtime_setup(); set_bit(EFI_RUNTIME_SERVICES, &efi.flags); efi.runtime_version = efi.systab->hdr.revision; return 0; - -err_unmap: - /* unmap all mappings that succeeded: there are 'count' of those */ - for (virt_md = virtmap; count--; virt_md += memmap.desc_size) { - md = virt_md; - iounmap((__force void __iomem *)md->virt_addr); - } - kfree(virtmap); - return -1; } -early_initcall(arm64_enter_virtual_mode); +early_initcall(arm64_enable_runtime_services); static int __init arm64_dmi_init(void) { @@ -484,3 +334,23 @@ static int __init arm64_dmi_init(void) return 0; } core_initcall(arm64_dmi_init); + +static void efi_set_pgd(struct mm_struct *mm) +{ + cpu_switch_mm(mm->pgd, mm); + flush_tlb_all(); + if (icache_is_aivivt()) + __flush_icache_all(); +} + +void efi_virtmap_load(void) +{ + preempt_disable(); + efi_set_pgd(&efi_mm); +} + +void efi_virtmap_unload(void) +{ + efi_set_pgd(current->active_mm); + preempt_enable(); +} diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index fd4fa374e5d2..cf21bb3bf752 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -269,18 +269,18 @@ ENDPROC(el1_error_invalid) el1_sync: kernel_entry 1 mrs x1, esr_el1 // read the syndrome register - lsr x24, x1, #ESR_EL1_EC_SHIFT // exception class - cmp x24, #ESR_EL1_EC_DABT_EL1 // data abort in EL1 + lsr x24, x1, #ESR_ELx_EC_SHIFT // exception class + cmp x24, #ESR_ELx_EC_DABT_CUR // data abort in EL1 b.eq el1_da - cmp x24, #ESR_EL1_EC_SYS64 // configurable trap + cmp x24, #ESR_ELx_EC_SYS64 // configurable trap b.eq el1_undef - cmp x24, #ESR_EL1_EC_SP_ALIGN // stack alignment exception + cmp x24, #ESR_ELx_EC_SP_ALIGN // stack alignment exception b.eq el1_sp_pc - cmp x24, #ESR_EL1_EC_PC_ALIGN // pc alignment exception + cmp x24, #ESR_ELx_EC_PC_ALIGN // pc alignment exception b.eq el1_sp_pc - cmp x24, #ESR_EL1_EC_UNKNOWN // unknown exception in EL1 + cmp x24, #ESR_ELx_EC_UNKNOWN // unknown exception in EL1 b.eq el1_undef - cmp x24, #ESR_EL1_EC_BREAKPT_EL1 // debug exception in EL1 + cmp x24, #ESR_ELx_EC_BREAKPT_CUR // debug exception in EL1 b.ge el1_dbg b el1_inv el1_da: @@ -318,7 +318,7 @@ el1_dbg: /* * Debug exception handling */ - cmp x24, #ESR_EL1_EC_BRK64 // if BRK64 + cmp x24, #ESR_ELx_EC_BRK64 // if BRK64 cinc x24, x24, eq // set bit '0' tbz x24, #0, el1_inv // EL1 only mrs x0, far_el1 @@ -375,26 +375,26 @@ el1_preempt: el0_sync: kernel_entry 0 mrs x25, esr_el1 // read the syndrome register - lsr x24, x25, #ESR_EL1_EC_SHIFT // exception class - cmp x24, #ESR_EL1_EC_SVC64 // SVC in 64-bit state + lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class + cmp x24, #ESR_ELx_EC_SVC64 // SVC in 64-bit state b.eq el0_svc - cmp x24, #ESR_EL1_EC_DABT_EL0 // data abort in EL0 + cmp x24, #ESR_ELx_EC_DABT_LOW // data abort in EL0 b.eq el0_da - cmp x24, #ESR_EL1_EC_IABT_EL0 // instruction abort in EL0 + cmp x24, #ESR_ELx_EC_IABT_LOW // instruction abort in EL0 b.eq el0_ia - cmp x24, #ESR_EL1_EC_FP_ASIMD // FP/ASIMD access + cmp x24, #ESR_ELx_EC_FP_ASIMD // FP/ASIMD access b.eq el0_fpsimd_acc - cmp x24, #ESR_EL1_EC_FP_EXC64 // FP/ASIMD exception + cmp x24, #ESR_ELx_EC_FP_EXC64 // FP/ASIMD exception b.eq el0_fpsimd_exc - cmp x24, #ESR_EL1_EC_SYS64 // configurable trap + cmp x24, #ESR_ELx_EC_SYS64 // configurable trap b.eq el0_undef - cmp x24, #ESR_EL1_EC_SP_ALIGN // stack alignment exception + cmp x24, #ESR_ELx_EC_SP_ALIGN // stack alignment exception b.eq el0_sp_pc - cmp x24, #ESR_EL1_EC_PC_ALIGN // pc alignment exception + cmp x24, #ESR_ELx_EC_PC_ALIGN // pc alignment exception b.eq el0_sp_pc - cmp x24, #ESR_EL1_EC_UNKNOWN // unknown exception in EL0 + cmp x24, #ESR_ELx_EC_UNKNOWN // unknown exception in EL0 b.eq el0_undef - cmp x24, #ESR_EL1_EC_BREAKPT_EL0 // debug exception in EL0 + cmp x24, #ESR_ELx_EC_BREAKPT_LOW // debug exception in EL0 b.ge el0_dbg b el0_inv @@ -403,37 +403,37 @@ el0_sync: el0_sync_compat: kernel_entry 0, 32 mrs x25, esr_el1 // read the syndrome register - lsr x24, x25, #ESR_EL1_EC_SHIFT // exception class - cmp x24, #ESR_EL1_EC_SVC32 // SVC in 32-bit state + lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class + cmp x24, #ESR_ELx_EC_SVC32 // SVC in 32-bit state b.eq el0_svc_compat - cmp x24, #ESR_EL1_EC_DABT_EL0 // data abort in EL0 + cmp x24, #ESR_ELx_EC_DABT_LOW // data abort in EL0 b.eq el0_da - cmp x24, #ESR_EL1_EC_IABT_EL0 // instruction abort in EL0 + cmp x24, #ESR_ELx_EC_IABT_LOW // instruction abort in EL0 b.eq el0_ia - cmp x24, #ESR_EL1_EC_FP_ASIMD // FP/ASIMD access + cmp x24, #ESR_ELx_EC_FP_ASIMD // FP/ASIMD access b.eq el0_fpsimd_acc - cmp x24, #ESR_EL1_EC_FP_EXC32 // FP/ASIMD exception + cmp x24, #ESR_ELx_EC_FP_EXC32 // FP/ASIMD exception b.eq el0_fpsimd_exc - cmp x24, #ESR_EL1_EC_UNKNOWN // unknown exception in EL0 + cmp x24, #ESR_ELx_EC_UNKNOWN // unknown exception in EL0 b.eq el0_undef - cmp x24, #ESR_EL1_EC_CP15_32 // CP15 MRC/MCR trap + cmp x24, #ESR_ELx_EC_CP15_32 // CP15 MRC/MCR trap b.eq el0_undef - cmp x24, #ESR_EL1_EC_CP15_64 // CP15 MRRC/MCRR trap + cmp x24, #ESR_ELx_EC_CP15_64 // CP15 MRRC/MCRR trap b.eq el0_undef - cmp x24, #ESR_EL1_EC_CP14_MR // CP14 MRC/MCR trap + cmp x24, #ESR_ELx_EC_CP14_MR // CP14 MRC/MCR trap b.eq el0_undef - cmp x24, #ESR_EL1_EC_CP14_LS // CP14 LDC/STC trap + cmp x24, #ESR_ELx_EC_CP14_LS // CP14 LDC/STC trap b.eq el0_undef - cmp x24, #ESR_EL1_EC_CP14_64 // CP14 MRRC/MCRR trap + cmp x24, #ESR_ELx_EC_CP14_64 // CP14 MRRC/MCRR trap b.eq el0_undef - cmp x24, #ESR_EL1_EC_BREAKPT_EL0 // debug exception in EL0 + cmp x24, #ESR_ELx_EC_BREAKPT_LOW // debug exception in EL0 b.ge el0_dbg b el0_inv el0_svc_compat: /* * AArch32 syscall handling */ - adr stbl, compat_sys_call_table // load compat syscall table pointer + adrp stbl, compat_sys_call_table // load compat syscall table pointer uxtw scno, w7 // syscall number in w7 (r7) mov sc_nr, #__NR_compat_syscalls b el0_svc_naked diff --git a/arch/arm64/kernel/sys32.S b/arch/arm64/kernel/entry32.S similarity index 80% rename from arch/arm64/kernel/sys32.S rename to arch/arm64/kernel/entry32.S index 423a5b3fc2be..9a8f6ae2530e 100644 --- a/arch/arm64/kernel/sys32.S +++ b/arch/arm64/kernel/entry32.S @@ -27,26 +27,26 @@ * System call wrappers for the AArch32 compatibility layer. */ -compat_sys_sigreturn_wrapper: +ENTRY(compat_sys_sigreturn_wrapper) mov x0, sp mov x27, #0 // prevent syscall restart handling (why) b compat_sys_sigreturn ENDPROC(compat_sys_sigreturn_wrapper) -compat_sys_rt_sigreturn_wrapper: +ENTRY(compat_sys_rt_sigreturn_wrapper) mov x0, sp mov x27, #0 // prevent syscall restart handling (why) b compat_sys_rt_sigreturn ENDPROC(compat_sys_rt_sigreturn_wrapper) -compat_sys_statfs64_wrapper: +ENTRY(compat_sys_statfs64_wrapper) mov w3, #84 cmp w1, #88 csel w1, w3, w1, eq b compat_sys_statfs64 ENDPROC(compat_sys_statfs64_wrapper) -compat_sys_fstatfs64_wrapper: +ENTRY(compat_sys_fstatfs64_wrapper) mov w3, #84 cmp w1, #88 csel w1, w3, w1, eq @@ -58,33 +58,33 @@ ENDPROC(compat_sys_fstatfs64_wrapper) * in registers or that take 32-bit parameters which require sign * extension. */ -compat_sys_pread64_wrapper: +ENTRY(compat_sys_pread64_wrapper) regs_to_64 x3, x4, x5 b sys_pread64 ENDPROC(compat_sys_pread64_wrapper) -compat_sys_pwrite64_wrapper: +ENTRY(compat_sys_pwrite64_wrapper) regs_to_64 x3, x4, x5 b sys_pwrite64 ENDPROC(compat_sys_pwrite64_wrapper) -compat_sys_truncate64_wrapper: +ENTRY(compat_sys_truncate64_wrapper) regs_to_64 x1, x2, x3 b sys_truncate ENDPROC(compat_sys_truncate64_wrapper) -compat_sys_ftruncate64_wrapper: +ENTRY(compat_sys_ftruncate64_wrapper) regs_to_64 x1, x2, x3 b sys_ftruncate ENDPROC(compat_sys_ftruncate64_wrapper) -compat_sys_readahead_wrapper: +ENTRY(compat_sys_readahead_wrapper) regs_to_64 x1, x2, x3 mov w2, w4 b sys_readahead ENDPROC(compat_sys_readahead_wrapper) -compat_sys_fadvise64_64_wrapper: +ENTRY(compat_sys_fadvise64_64_wrapper) mov w6, w1 regs_to_64 x1, x2, x3 regs_to_64 x2, x4, x5 @@ -92,24 +92,14 @@ compat_sys_fadvise64_64_wrapper: b sys_fadvise64_64 ENDPROC(compat_sys_fadvise64_64_wrapper) -compat_sys_sync_file_range2_wrapper: +ENTRY(compat_sys_sync_file_range2_wrapper) regs_to_64 x2, x2, x3 regs_to_64 x3, x4, x5 b sys_sync_file_range2 ENDPROC(compat_sys_sync_file_range2_wrapper) -compat_sys_fallocate_wrapper: +ENTRY(compat_sys_fallocate_wrapper) regs_to_64 x2, x2, x3 regs_to_64 x3, x4, x5 b sys_fallocate ENDPROC(compat_sys_fallocate_wrapper) - -#undef __SYSCALL -#define __SYSCALL(x, y) .quad y // x - -/* - * The system calls table must be 4KB aligned. - */ - .align 12 -ENTRY(compat_sys_call_table) -#include diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index df1cf15377b4..98bbe06e469c 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c @@ -894,7 +894,7 @@ static struct notifier_block hw_breakpoint_reset_nb = { .notifier_call = hw_breakpoint_reset_notify, }; -#ifdef CONFIG_ARM64_CPU_SUSPEND +#ifdef CONFIG_CPU_PM extern void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)); #else static inline void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index 7e9327a0986d..27d4864577e5 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c @@ -17,14 +17,19 @@ * along with this program. If not, see . */ #include +#include #include #include +#include #include +#include #include +#include #include #include #include +#include #include #define AARCH64_INSN_SF_BIT BIT(31) @@ -72,6 +77,29 @@ bool __kprobes aarch64_insn_is_nop(u32 insn) } } +static DEFINE_SPINLOCK(patch_lock); + +static void __kprobes *patch_map(void *addr, int fixmap) +{ + unsigned long uintaddr = (uintptr_t) addr; + bool module = !core_kernel_text(uintaddr); + struct page *page; + + if (module && IS_ENABLED(CONFIG_DEBUG_SET_MODULE_RONX)) + page = vmalloc_to_page(addr); + else + page = virt_to_page(addr); + + BUG_ON(!page); + set_fixmap(fixmap, page_to_phys(page)); + + return (void *) (__fix_to_virt(fixmap) + (uintaddr & ~PAGE_MASK)); +} + +static void __kprobes patch_unmap(int fixmap) +{ + clear_fixmap(fixmap); +} /* * In ARMv8-A, A64 instructions have a fixed length of 32 bits and are always * little-endian. @@ -88,10 +116,27 @@ int __kprobes aarch64_insn_read(void *addr, u32 *insnp) return ret; } +static int __kprobes __aarch64_insn_write(void *addr, u32 insn) +{ + void *waddr = addr; + unsigned long flags = 0; + int ret; + + spin_lock_irqsave(&patch_lock, flags); + waddr = patch_map(addr, FIX_TEXT_POKE0); + + ret = probe_kernel_write(waddr, &insn, AARCH64_INSN_SIZE); + + patch_unmap(FIX_TEXT_POKE0); + spin_unlock_irqrestore(&patch_lock, flags); + + return ret; +} + int __kprobes aarch64_insn_write(void *addr, u32 insn) { insn = cpu_to_le32(insn); - return probe_kernel_write(addr, &insn, AARCH64_INSN_SIZE); + return __aarch64_insn_write(addr, insn); } static bool __kprobes __aarch64_insn_hotpatch_safe(u32 insn) diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index ce5836c14ec1..6f93c24ca801 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -46,25 +46,3 @@ int pcibios_add_device(struct pci_dev *dev) return 0; } - - -#ifdef CONFIG_PCI_DOMAINS_GENERIC -static bool dt_domain_found = false; - -void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent) -{ - int domain = of_get_pci_domain_nr(parent->of_node); - - if (domain >= 0) { - dt_domain_found = true; - } else if (dt_domain_found == true) { - dev_err(parent, "Node %s is missing \"linux,pci-domain\" property in DT\n", - parent->of_node->full_name); - return; - } else { - domain = pci_get_new_domain_nr(); - } - - bus->domain_nr = domain; -} -#endif diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index f1dbca7d5c96..3425f311c49e 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -540,8 +540,6 @@ const struct cpu_operations cpu_psci_ops = { .name = "psci", #ifdef CONFIG_CPU_IDLE .cpu_init_idle = cpu_psci_cpu_init_idle, -#endif -#ifdef CONFIG_ARM64_CPU_SUSPEND .cpu_suspend = cpu_psci_cpu_suspend, #endif #ifdef CONFIG_SMP diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 20fe2932ad0c..e8420f635bd4 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -322,25 +323,6 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys) dump_stack_set_arch_desc("%s (DT)", of_flat_dt_get_machine_name()); } -/* - * Limit the memory size that was specified via FDT. - */ -static int __init early_mem(char *p) -{ - phys_addr_t limit; - - if (!p) - return 1; - - limit = memparse(p, &p) & PAGE_MASK; - pr_notice("Memory limited to %lldMB\n", limit >> 20); - - memblock_enforce_memory_limit(limit); - - return 0; -} -early_param("mem", early_mem); - static void __init request_standard_resources(void) { struct memblock_region *region; @@ -401,7 +383,6 @@ void __init setup_arch(char **cmdline_p) paging_init(); request_standard_resources(); - efi_idmap_init(); early_ioremap_reset(); unflatten_device_tree(); @@ -425,6 +406,7 @@ void __init setup_arch(char **cmdline_p) static int __init arm64_device_init(void) { + of_iommu_init(); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); return 0; } diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index 5a1ba6e80d4e..e299de396e9b 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -440,7 +440,7 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka, { compat_ulong_t handler = ptr_to_compat(ka->sa.sa_handler); compat_ulong_t retcode; - compat_ulong_t spsr = regs->pstate & ~PSR_f; + compat_ulong_t spsr = regs->pstate & ~(PSR_f | COMPAT_PSR_E_BIT); int thumb; /* Check if the handler is written for ARM or Thumb */ @@ -454,6 +454,9 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka, /* The IT state must be cleared for both ARM and Thumb-2 */ spsr &= ~COMPAT_PSR_IT_MASK; + /* Restore the original endianness */ + spsr |= COMPAT_PSR_ENDSTATE; + if (ka->sa.sa_flags & SA_RESTORER) { retcode = ptr_to_compat(ka->sa.sa_restorer); } else { @@ -501,7 +504,7 @@ static int compat_setup_sigframe(struct compat_sigframe __user *sf, __put_user_error((compat_ulong_t)0, &sf->uc.uc_mcontext.trap_no, err); /* set the compat FSR WnR */ - __put_user_error(!!(current->thread.fault_code & ESR_EL1_WRITE) << + __put_user_error(!!(current->thread.fault_code & ESR_ELx_WNR) << FSR_WRITE_SHIFT, &sf->uc.uc_mcontext.error_code, err); __put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err); __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err); diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 7ae6ee085261..328b8ce4b007 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -65,7 +65,6 @@ struct secondary_data secondary_data; enum ipi_msg_type { IPI_RESCHEDULE, IPI_CALL_FUNC, - IPI_CALL_FUNC_SINGLE, IPI_CPU_STOP, IPI_TIMER, IPI_IRQ_WORK, @@ -483,7 +482,6 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = { #define S(x,s) [x] = s S(IPI_RESCHEDULE, "Rescheduling interrupts"), S(IPI_CALL_FUNC, "Function call interrupts"), - S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), S(IPI_CPU_STOP, "CPU stop interrupts"), S(IPI_TIMER, "Timer broadcast interrupts"), S(IPI_IRQ_WORK, "IRQ work interrupts"), @@ -527,7 +525,7 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask) void arch_send_call_function_single_ipi(int cpu) { - smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); + smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC); } #ifdef CONFIG_IRQ_WORK @@ -585,12 +583,6 @@ void handle_IPI(int ipinr, struct pt_regs *regs) irq_exit(); break; - case IPI_CALL_FUNC_SINGLE: - irq_enter(); - generic_smp_call_function_single_interrupt(); - irq_exit(); - break; - case IPI_CPU_STOP: irq_enter(); ipi_cpu_stop(cpu); diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c index 2d6b6065fe7f..d7daf45ae7a2 100644 --- a/arch/arm64/kernel/suspend.c +++ b/arch/arm64/kernel/suspend.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -51,26 +50,6 @@ void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) hw_breakpoint_restore = hw_bp_restore; } -/** - * cpu_suspend() - function to enter a low-power state - * @arg: argument to pass to CPU suspend operations - * - * Return: 0 on success, -EOPNOTSUPP if CPU suspend hook not initialized, CPU - * operations back-end error code otherwise. - */ -int cpu_suspend(unsigned long arg) -{ - int cpu = smp_processor_id(); - - /* - * If cpu_ops have not been registered or suspend - * has not been initialized, cpu_suspend call fails early. - */ - if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_suspend) - return -EOPNOTSUPP; - return cpu_ops[cpu]->cpu_suspend(arg); -} - /* * __cpu_suspend * diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c index 3fa98ff14f0e..75151aaf1a52 100644 --- a/arch/arm64/kernel/sys.c +++ b/arch/arm64/kernel/sys.c @@ -39,10 +39,9 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len, /* * Wrappers to pass the pt_regs argument. */ +asmlinkage long sys_rt_sigreturn_wrapper(void); #define sys_rt_sigreturn sys_rt_sigreturn_wrapper -#include - #undef __SYSCALL #define __SYSCALL(nr, sym) [nr] = sym, @@ -50,7 +49,7 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len, * The sys_call_table array must be 4K aligned to be accessible from * kernel/entry.S. */ -void *sys_call_table[__NR_syscalls] __aligned(4096) = { +void * const sys_call_table[__NR_syscalls] __aligned(4096) = { [0 ... __NR_syscalls - 1] = sys_ni_syscall, #include }; diff --git a/arch/arm64/kernel/sys32.c b/arch/arm64/kernel/sys32.c new file mode 100644 index 000000000000..2d5ab3c90b82 --- /dev/null +++ b/arch/arm64/kernel/sys32.c @@ -0,0 +1,51 @@ +/* + * arch/arm64/kernel/sys32.c + * + * Copyright (C) 2015 ARM Ltd. + * + * This program is free software(void); you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * Needed to avoid conflicting __NR_* macros between uapi/asm/unistd.h and + * asm/unistd32.h. + */ +#define __COMPAT_SYSCALL_NR + +#include +#include + +asmlinkage long compat_sys_sigreturn_wrapper(void); +asmlinkage long compat_sys_rt_sigreturn_wrapper(void); +asmlinkage long compat_sys_statfs64_wrapper(void); +asmlinkage long compat_sys_fstatfs64_wrapper(void); +asmlinkage long compat_sys_pread64_wrapper(void); +asmlinkage long compat_sys_pwrite64_wrapper(void); +asmlinkage long compat_sys_truncate64_wrapper(void); +asmlinkage long compat_sys_ftruncate64_wrapper(void); +asmlinkage long compat_sys_readahead_wrapper(void); +asmlinkage long compat_sys_fadvise64_64_wrapper(void); +asmlinkage long compat_sys_sync_file_range2_wrapper(void); +asmlinkage long compat_sys_fallocate_wrapper(void); + +#undef __SYSCALL +#define __SYSCALL(nr, sym) [nr] = sym, + +/* + * The sys_call_table array must be 4K aligned to be accessible from + * kernel/entry.S. + */ +void * const compat_sys_call_table[__NR_compat_syscalls] __aligned(4096) = { + [0 ... __NR_compat_syscalls - 1] = sys_ni_syscall, +#include +}; diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 0a801e3743d5..1ef2940df13c 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -373,6 +374,51 @@ asmlinkage long do_ni_syscall(struct pt_regs *regs) return sys_ni_syscall(); } +static const char *esr_class_str[] = { + [0 ... ESR_ELx_EC_MAX] = "UNRECOGNIZED EC", + [ESR_ELx_EC_UNKNOWN] = "Unknown/Uncategorized", + [ESR_ELx_EC_WFx] = "WFI/WFE", + [ESR_ELx_EC_CP15_32] = "CP15 MCR/MRC", + [ESR_ELx_EC_CP15_64] = "CP15 MCRR/MRRC", + [ESR_ELx_EC_CP14_MR] = "CP14 MCR/MRC", + [ESR_ELx_EC_CP14_LS] = "CP14 LDC/STC", + [ESR_ELx_EC_FP_ASIMD] = "ASIMD", + [ESR_ELx_EC_CP10_ID] = "CP10 MRC/VMRS", + [ESR_ELx_EC_CP14_64] = "CP14 MCRR/MRRC", + [ESR_ELx_EC_ILL] = "PSTATE.IL", + [ESR_ELx_EC_SVC32] = "SVC (AArch32)", + [ESR_ELx_EC_HVC32] = "HVC (AArch32)", + [ESR_ELx_EC_SMC32] = "SMC (AArch32)", + [ESR_ELx_EC_SVC64] = "SVC (AArch64)", + [ESR_ELx_EC_HVC64] = "HVC (AArch64)", + [ESR_ELx_EC_SMC64] = "SMC (AArch64)", + [ESR_ELx_EC_SYS64] = "MSR/MRS (AArch64)", + [ESR_ELx_EC_IMP_DEF] = "EL3 IMP DEF", + [ESR_ELx_EC_IABT_LOW] = "IABT (lower EL)", + [ESR_ELx_EC_IABT_CUR] = "IABT (current EL)", + [ESR_ELx_EC_PC_ALIGN] = "PC Alignment", + [ESR_ELx_EC_DABT_LOW] = "DABT (lower EL)", + [ESR_ELx_EC_DABT_CUR] = "DABT (current EL)", + [ESR_ELx_EC_SP_ALIGN] = "SP Alignment", + [ESR_ELx_EC_FP_EXC32] = "FP (AArch32)", + [ESR_ELx_EC_FP_EXC64] = "FP (AArch64)", + [ESR_ELx_EC_SERROR] = "SError", + [ESR_ELx_EC_BREAKPT_LOW] = "Breakpoint (lower EL)", + [ESR_ELx_EC_BREAKPT_CUR] = "Breakpoint (current EL)", + [ESR_ELx_EC_SOFTSTP_LOW] = "Software Step (lower EL)", + [ESR_ELx_EC_SOFTSTP_CUR] = "Software Step (current EL)", + [ESR_ELx_EC_WATCHPT_LOW] = "Watchpoint (lower EL)", + [ESR_ELx_EC_WATCHPT_CUR] = "Watchpoint (current EL)", + [ESR_ELx_EC_BKPT32] = "BKPT (AArch32)", + [ESR_ELx_EC_VECTOR32] = "Vector catch (AArch32)", + [ESR_ELx_EC_BRK64] = "BRK (AArch64)", +}; + +const char *esr_get_class_string(u32 esr) +{ + return esr_class_str[esr >> ESR_ELx_EC_SHIFT]; +} + /* * bad_mode handles the impossible case in the exception vector. */ @@ -382,8 +428,8 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr) void __user *pc = (void __user *)instruction_pointer(regs); console_verbose(); - pr_crit("Bad mode in %s handler detected, code 0x%08x\n", - handler[reason], esr); + pr_crit("Bad mode in %s handler detected, code 0x%08x -- %s\n", + handler[reason], esr, esr_get_class_string(esr)); __show_regs(regs); info.si_signo = SIGILL; diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 9965ec87cbec..5d9d2dca530d 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -8,6 +8,7 @@ #include #include #include +#include #include "image.h" @@ -49,6 +50,14 @@ PECOFF_FILE_ALIGNMENT = 0x200; #define PECOFF_EDATA_PADDING #endif +#ifdef CONFIG_DEBUG_ALIGN_RODATA +#define ALIGN_DEBUG_RO . = ALIGN(1< +#include #include /* @@ -55,8 +56,8 @@ static int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu) { u32 esr = kvm_vcpu_get_hsr(vcpu); - if (esr & ESR_EL2_CV) - return (esr & ESR_EL2_COND) >> ESR_EL2_COND_SHIFT; + if (esr & ESR_ELx_CV) + return (esr & ESR_ELx_COND_MASK) >> ESR_ELx_COND_SHIFT; return -1; } diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 34b8bd0711e9..29b184a8f3f8 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -21,8 +21,10 @@ #include #include -#include + +#include #include +#include #include #include @@ -61,7 +63,7 @@ static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) */ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run) { - if (kvm_vcpu_get_hsr(vcpu) & ESR_EL2_EC_WFI_ISS_WFE) + if (kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WFx_ISS_WFE) kvm_vcpu_on_spin(vcpu); else kvm_vcpu_block(vcpu); @@ -72,29 +74,30 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run) } static exit_handle_fn arm_exit_handlers[] = { - [ESR_EL2_EC_WFI] = kvm_handle_wfx, - [ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32, - [ESR_EL2_EC_CP15_64] = kvm_handle_cp15_64, - [ESR_EL2_EC_CP14_MR] = kvm_handle_cp14_32, - [ESR_EL2_EC_CP14_LS] = kvm_handle_cp14_load_store, - [ESR_EL2_EC_CP14_64] = kvm_handle_cp14_64, - [ESR_EL2_EC_HVC32] = handle_hvc, - [ESR_EL2_EC_SMC32] = handle_smc, - [ESR_EL2_EC_HVC64] = handle_hvc, - [ESR_EL2_EC_SMC64] = handle_smc, - [ESR_EL2_EC_SYS64] = kvm_handle_sys_reg, - [ESR_EL2_EC_IABT] = kvm_handle_guest_abort, - [ESR_EL2_EC_DABT] = kvm_handle_guest_abort, + [ESR_ELx_EC_WFx] = kvm_handle_wfx, + [ESR_ELx_EC_CP15_32] = kvm_handle_cp15_32, + [ESR_ELx_EC_CP15_64] = kvm_handle_cp15_64, + [ESR_ELx_EC_CP14_MR] = kvm_handle_cp14_32, + [ESR_ELx_EC_CP14_LS] = kvm_handle_cp14_load_store, + [ESR_ELx_EC_CP14_64] = kvm_handle_cp14_64, + [ESR_ELx_EC_HVC32] = handle_hvc, + [ESR_ELx_EC_SMC32] = handle_smc, + [ESR_ELx_EC_HVC64] = handle_hvc, + [ESR_ELx_EC_SMC64] = handle_smc, + [ESR_ELx_EC_SYS64] = kvm_handle_sys_reg, + [ESR_ELx_EC_IABT_LOW] = kvm_handle_guest_abort, + [ESR_ELx_EC_DABT_LOW] = kvm_handle_guest_abort, }; static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu) { - u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu); + u32 hsr = kvm_vcpu_get_hsr(vcpu); + u8 hsr_ec = hsr >> ESR_ELx_EC_SHIFT; if (hsr_ec >= ARRAY_SIZE(arm_exit_handlers) || !arm_exit_handlers[hsr_ec]) { - kvm_err("Unknown exception class: hsr: %#08x\n", - (unsigned int)kvm_vcpu_get_hsr(vcpu)); + kvm_err("Unknown exception class: hsr: %#08x -- %s\n", + hsr, esr_get_class_string(hsr)); BUG(); } diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index c3ca89c27c6b..9bff671cc561 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -17,15 +17,16 @@ #include -#include -#include #include +#include #include +#include #include #include -#include #include +#include #include +#include #define CPU_GP_REG_OFFSET(x) (CPU_GP_REGS + x) #define CPU_XREG_OFFSET(x) CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x) @@ -1141,9 +1142,9 @@ el1_sync: // Guest trapped into EL2 push x2, x3 mrs x1, esr_el2 - lsr x2, x1, #ESR_EL2_EC_SHIFT + lsr x2, x1, #ESR_ELx_EC_SHIFT - cmp x2, #ESR_EL2_EC_HVC64 + cmp x2, #ESR_ELx_EC_HVC64 b.ne el1_trap mrs x3, vttbr_el2 // If vttbr is valid, the 64bit guest @@ -1178,13 +1179,13 @@ el1_trap: * x1: ESR * x2: ESR_EC */ - cmp x2, #ESR_EL2_EC_DABT - mov x0, #ESR_EL2_EC_IABT + cmp x2, #ESR_ELx_EC_DABT_LOW + mov x0, #ESR_ELx_EC_IABT_LOW ccmp x2, x0, #4, ne b.ne 1f // Not an abort we care about /* This is an abort. Check for permission fault */ - and x2, x1, #ESR_EL2_FSC_TYPE + and x2, x1, #ESR_ELx_FSC_TYPE cmp x2, #FSC_PERM b.ne 1f // Not a permission fault diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c index 81a02a8762b0..f02530e726f6 100644 --- a/arch/arm64/kvm/inject_fault.c +++ b/arch/arm64/kvm/inject_fault.c @@ -118,27 +118,27 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr * instruction set. Report an external synchronous abort. */ if (kvm_vcpu_trap_il_is32bit(vcpu)) - esr |= ESR_EL1_IL; + esr |= ESR_ELx_IL; /* * Here, the guest runs in AArch64 mode when in EL1. If we get * an AArch32 fault, it means we managed to trap an EL0 fault. */ if (is_aarch32 || (cpsr & PSR_MODE_MASK) == PSR_MODE_EL0t) - esr |= (ESR_EL1_EC_IABT_EL0 << ESR_EL1_EC_SHIFT); + esr |= (ESR_ELx_EC_IABT_LOW << ESR_ELx_EC_SHIFT); else - esr |= (ESR_EL1_EC_IABT_EL1 << ESR_EL1_EC_SHIFT); + esr |= (ESR_ELx_EC_IABT_CUR << ESR_ELx_EC_SHIFT); if (!is_iabt) - esr |= ESR_EL1_EC_DABT_EL0; + esr |= ESR_ELx_EC_DABT_LOW; - vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_EL2_EC_xABT_xFSR_EXTABT; + vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_ELx_FSC_EXTABT; } static void inject_undef64(struct kvm_vcpu *vcpu) { unsigned long cpsr = *vcpu_cpsr(vcpu); - u32 esr = (ESR_EL1_EC_UNKNOWN << ESR_EL1_EC_SHIFT); + u32 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT); *vcpu_spsr(vcpu) = cpsr; *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu); @@ -151,7 +151,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu) * set. */ if (kvm_vcpu_trap_il_is32bit(vcpu)) - esr |= ESR_EL1_IL; + esr |= ESR_ELx_IL; vcpu_sys_reg(vcpu, ESR_EL1) = esr; } diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 3d7c2df89946..b96afdf6cee4 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -20,17 +20,20 @@ * along with this program. If not, see . */ -#include #include +#include #include -#include -#include -#include -#include -#include + #include #include #include +#include +#include +#include +#include +#include +#include + #include #include "sys_regs.h" @@ -69,68 +72,31 @@ static u32 get_ccsidr(u32 csselr) return ccsidr; } -static void do_dc_cisw(u32 val) -{ - asm volatile("dc cisw, %x0" : : "r" (val)); - dsb(ish); -} - -static void do_dc_csw(u32 val) -{ - asm volatile("dc csw, %x0" : : "r" (val)); - dsb(ish); -} - -/* See note at ARM ARM B1.14.4 */ +/* + * See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized). + */ static bool access_dcsw(struct kvm_vcpu *vcpu, const struct sys_reg_params *p, const struct sys_reg_desc *r) { - unsigned long val; - int cpu; - if (!p->is_write) return read_from_write_only(vcpu, p); - cpu = get_cpu(); - - cpumask_setall(&vcpu->arch.require_dcache_flush); - cpumask_clear_cpu(cpu, &vcpu->arch.require_dcache_flush); - - /* If we were already preempted, take the long way around */ - if (cpu != vcpu->arch.last_pcpu) { - flush_cache_all(); - goto done; - } - - val = *vcpu_reg(vcpu, p->Rt); - - switch (p->CRm) { - case 6: /* Upgrade DCISW to DCCISW, as per HCR.SWIO */ - case 14: /* DCCISW */ - do_dc_cisw(val); - break; - - case 10: /* DCCSW */ - do_dc_csw(val); - break; - } - -done: - put_cpu(); - + kvm_set_way_flush(vcpu); return true; } /* * Generic accessor for VM registers. Only called as long as HCR_TVM - * is set. + * is set. If the guest enables the MMU, we stop trapping the VM + * sys_regs and leave it in complete control of the caches. */ static bool access_vm_reg(struct kvm_vcpu *vcpu, const struct sys_reg_params *p, const struct sys_reg_desc *r) { unsigned long val; + bool was_enabled = vcpu_has_cache_enabled(vcpu); BUG_ON(!p->is_write); @@ -143,25 +109,7 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu, vcpu_cp15_64_low(vcpu, r->reg) = val & 0xffffffffUL; } - return true; -} - -/* - * SCTLR_EL1 accessor. Only called as long as HCR_TVM is set. If the - * guest enables the MMU, we stop trapping the VM sys_regs and leave - * it in complete control of the caches. - */ -static bool access_sctlr(struct kvm_vcpu *vcpu, - const struct sys_reg_params *p, - const struct sys_reg_desc *r) -{ - access_vm_reg(vcpu, p, r); - - if (vcpu_has_cache_enabled(vcpu)) { /* MMU+Caches enabled? */ - vcpu->arch.hcr_el2 &= ~HCR_TVM; - stage2_flush_vm(vcpu->kvm); - } - + kvm_toggle_cache(vcpu, was_enabled); return true; } @@ -377,7 +325,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { NULL, reset_mpidr, MPIDR_EL1 }, /* SCTLR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b000), - access_sctlr, reset_val, SCTLR_EL1, 0x00C50078 }, + access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 }, /* CPACR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b010), NULL, reset_val, CPACR_EL1, 0 }, @@ -657,7 +605,7 @@ static const struct sys_reg_desc cp14_64_regs[] = { * register). */ static const struct sys_reg_desc cp15_regs[] = { - { Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_sctlr, NULL, c1_SCTLR }, + { Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_vm_reg, NULL, c1_SCTLR }, { Op1( 0), CRn( 2), CRm( 0), Op2( 0), access_vm_reg, NULL, c2_TTBR0 }, { Op1( 0), CRn( 2), CRm( 0), Op2( 1), access_vm_reg, NULL, c2_TTBR1 }, { Op1( 0), CRn( 2), CRm( 0), Op2( 2), access_vm_reg, NULL, c2_TTBCR }, @@ -815,12 +763,12 @@ static void unhandled_cp_access(struct kvm_vcpu *vcpu, int cp; switch(hsr_ec) { - case ESR_EL2_EC_CP15_32: - case ESR_EL2_EC_CP15_64: + case ESR_ELx_EC_CP15_32: + case ESR_ELx_EC_CP15_64: cp = 15; break; - case ESR_EL2_EC_CP14_MR: - case ESR_EL2_EC_CP14_64: + case ESR_ELx_EC_CP14_MR: + case ESR_ELx_EC_CP14_64: cp = 14; break; default: diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index d92094203913..0a24b9b8c698 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -134,16 +134,17 @@ static void __dma_free_coherent(struct device *dev, size_t size, swiotlb_free_coherent(dev, size, vaddr, dma_handle); } -static void *__dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flags, - struct dma_attrs *attrs) +static void *__dma_alloc(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flags, + struct dma_attrs *attrs) { struct page *page; void *ptr, *coherent_ptr; + bool coherent = is_device_dma_coherent(dev); size = PAGE_ALIGN(size); - if (!(flags & __GFP_WAIT)) { + if (!coherent && !(flags & __GFP_WAIT)) { struct page *page = NULL; void *addr = __alloc_from_pool(size, &page); @@ -151,13 +152,16 @@ static void *__dma_alloc_noncoherent(struct device *dev, size_t size, *dma_handle = phys_to_dma(dev, page_to_phys(page)); return addr; - } ptr = __dma_alloc_coherent(dev, size, dma_handle, flags, attrs); if (!ptr) goto no_mem; + /* no need for non-cacheable mapping if coherent */ + if (coherent) + return ptr; + /* remove any dirty cache lines on the kernel alias */ __dma_flush_range(ptr, ptr + size); @@ -179,15 +183,17 @@ no_mem: return NULL; } -static void __dma_free_noncoherent(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle, - struct dma_attrs *attrs) +static void __dma_free(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle, + struct dma_attrs *attrs) { void *swiotlb_addr = phys_to_virt(dma_to_phys(dev, dma_handle)); - if (__free_from_pool(vaddr, size)) - return; - vunmap(vaddr); + if (!is_device_dma_coherent(dev)) { + if (__free_from_pool(vaddr, size)) + return; + vunmap(vaddr); + } __dma_free_coherent(dev, size, swiotlb_addr, dma_handle, attrs); } @@ -199,7 +205,8 @@ static dma_addr_t __swiotlb_map_page(struct device *dev, struct page *page, dma_addr_t dev_addr; dev_addr = swiotlb_map_page(dev, page, offset, size, dir, attrs); - __dma_map_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir); + if (!is_device_dma_coherent(dev)) + __dma_map_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir); return dev_addr; } @@ -209,7 +216,8 @@ static void __swiotlb_unmap_page(struct device *dev, dma_addr_t dev_addr, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs) { - __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir); + if (!is_device_dma_coherent(dev)) + __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir); swiotlb_unmap_page(dev, dev_addr, size, dir, attrs); } @@ -221,9 +229,10 @@ static int __swiotlb_map_sg_attrs(struct device *dev, struct scatterlist *sgl, int i, ret; ret = swiotlb_map_sg_attrs(dev, sgl, nelems, dir, attrs); - for_each_sg(sgl, sg, ret, i) - __dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)), - sg->length, dir); + if (!is_device_dma_coherent(dev)) + for_each_sg(sgl, sg, ret, i) + __dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)), + sg->length, dir); return ret; } @@ -236,9 +245,10 @@ static void __swiotlb_unmap_sg_attrs(struct device *dev, struct scatterlist *sg; int i; - for_each_sg(sgl, sg, nelems, i) - __dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)), - sg->length, dir); + if (!is_device_dma_coherent(dev)) + for_each_sg(sgl, sg, nelems, i) + __dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)), + sg->length, dir); swiotlb_unmap_sg_attrs(dev, sgl, nelems, dir, attrs); } @@ -246,7 +256,8 @@ static void __swiotlb_sync_single_for_cpu(struct device *dev, dma_addr_t dev_addr, size_t size, enum dma_data_direction dir) { - __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir); + if (!is_device_dma_coherent(dev)) + __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir); swiotlb_sync_single_for_cpu(dev, dev_addr, size, dir); } @@ -255,7 +266,8 @@ static void __swiotlb_sync_single_for_device(struct device *dev, enum dma_data_direction dir) { swiotlb_sync_single_for_device(dev, dev_addr, size, dir); - __dma_map_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir); + if (!is_device_dma_coherent(dev)) + __dma_map_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir); } static void __swiotlb_sync_sg_for_cpu(struct device *dev, @@ -265,9 +277,10 @@ static void __swiotlb_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg; int i; - for_each_sg(sgl, sg, nelems, i) - __dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)), - sg->length, dir); + if (!is_device_dma_coherent(dev)) + for_each_sg(sgl, sg, nelems, i) + __dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)), + sg->length, dir); swiotlb_sync_sg_for_cpu(dev, sgl, nelems, dir); } @@ -279,9 +292,10 @@ static void __swiotlb_sync_sg_for_device(struct device *dev, int i; swiotlb_sync_sg_for_device(dev, sgl, nelems, dir); - for_each_sg(sgl, sg, nelems, i) - __dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)), - sg->length, dir); + if (!is_device_dma_coherent(dev)) + for_each_sg(sgl, sg, nelems, i) + __dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)), + sg->length, dir); } /* vma->vm_page_prot must be set appropriately before calling this function */ @@ -308,28 +322,20 @@ static int __dma_common_mmap(struct device *dev, struct vm_area_struct *vma, return ret; } -static int __swiotlb_mmap_noncoherent(struct device *dev, - struct vm_area_struct *vma, - void *cpu_addr, dma_addr_t dma_addr, size_t size, - struct dma_attrs *attrs) +static int __swiotlb_mmap(struct device *dev, + struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + struct dma_attrs *attrs) { - vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot, false); + vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot, + is_device_dma_coherent(dev)); return __dma_common_mmap(dev, vma, cpu_addr, dma_addr, size); } -static int __swiotlb_mmap_coherent(struct device *dev, - struct vm_area_struct *vma, - void *cpu_addr, dma_addr_t dma_addr, size_t size, - struct dma_attrs *attrs) -{ - /* Just use whatever page_prot attributes were specified */ - return __dma_common_mmap(dev, vma, cpu_addr, dma_addr, size); -} - -struct dma_map_ops noncoherent_swiotlb_dma_ops = { - .alloc = __dma_alloc_noncoherent, - .free = __dma_free_noncoherent, - .mmap = __swiotlb_mmap_noncoherent, +static struct dma_map_ops swiotlb_dma_ops = { + .alloc = __dma_alloc, + .free = __dma_free, + .mmap = __swiotlb_mmap, .map_page = __swiotlb_map_page, .unmap_page = __swiotlb_unmap_page, .map_sg = __swiotlb_map_sg_attrs, @@ -341,24 +347,6 @@ struct dma_map_ops noncoherent_swiotlb_dma_ops = { .dma_supported = swiotlb_dma_supported, .mapping_error = swiotlb_dma_mapping_error, }; -EXPORT_SYMBOL(noncoherent_swiotlb_dma_ops); - -struct dma_map_ops coherent_swiotlb_dma_ops = { - .alloc = __dma_alloc_coherent, - .free = __dma_free_coherent, - .mmap = __swiotlb_mmap_coherent, - .map_page = swiotlb_map_page, - .unmap_page = swiotlb_unmap_page, - .map_sg = swiotlb_map_sg_attrs, - .unmap_sg = swiotlb_unmap_sg_attrs, - .sync_single_for_cpu = swiotlb_sync_single_for_cpu, - .sync_single_for_device = swiotlb_sync_single_for_device, - .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu, - .sync_sg_for_device = swiotlb_sync_sg_for_device, - .dma_supported = swiotlb_dma_supported, - .mapping_error = swiotlb_dma_mapping_error, -}; -EXPORT_SYMBOL(coherent_swiotlb_dma_ops); extern int swiotlb_late_init_with_default_size(size_t default_size); @@ -427,7 +415,7 @@ static int __init swiotlb_late_init(void) { size_t swiotlb_size = min(SZ_64M, MAX_ORDER_NR_PAGES << PAGE_SHIFT); - dma_ops = &noncoherent_swiotlb_dma_ops; + dma_ops = &swiotlb_dma_ops; return swiotlb_late_init_with_default_size(swiotlb_size); } diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c index cf33f33333cc..74c256744b25 100644 --- a/arch/arm64/mm/dump.c +++ b/arch/arm64/mm/dump.c @@ -14,13 +14,18 @@ * of the License. */ #include +#include #include +#include +#include #include #include #include #include +#include #include +#include #define LOWEST_ADDR (UL(0xffffffffffffffff) << VA_BITS) @@ -36,10 +41,10 @@ enum address_markers_idx { VMEMMAP_START_NR, VMEMMAP_END_NR, #endif - PCI_START_NR, - PCI_END_NR, FIXADDR_START_NR, FIXADDR_END_NR, + PCI_START_NR, + PCI_END_NR, MODULES_START_NR, MODUELS_END_NR, KERNEL_SPACE_NR, @@ -52,10 +57,10 @@ static struct addr_marker address_markers[] = { { 0, "vmemmap start" }, { 0, "vmemmap end" }, #endif - { (unsigned long) PCI_IOBASE, "PCI I/O start" }, - { (unsigned long) PCI_IOBASE + SZ_16M, "PCI I/O end" }, { FIXADDR_START, "Fixmap start" }, { FIXADDR_TOP, "Fixmap end" }, + { PCI_IO_START, "PCI I/O start" }, + { PCI_IO_END, "PCI I/O end" }, { MODULES_VADDR, "Modules start" }, { MODULES_END, "Modules end" }, { PAGE_OFFSET, "Kernel Mapping" }, @@ -245,10 +250,12 @@ static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start) for (i = 0; i < PTRS_PER_PMD; i++, pmd++) { addr = start + i * PMD_SIZE; - if (pmd_none(*pmd) || pmd_sect(*pmd) || pmd_bad(*pmd)) + if (pmd_none(*pmd) || pmd_sect(*pmd)) { note_page(st, addr, 3, pmd_val(*pmd)); - else + } else { + BUG_ON(pmd_bad(*pmd)); walk_pte(st, pmd, addr); + } } } @@ -260,10 +267,12 @@ static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start) for (i = 0; i < PTRS_PER_PUD; i++, pud++) { addr = start + i * PUD_SIZE; - if (pud_none(*pud) || pud_sect(*pud) || pud_bad(*pud)) + if (pud_none(*pud) || pud_sect(*pud)) { note_page(st, addr, 2, pud_val(*pud)); - else + } else { + BUG_ON(pud_bad(*pud)); walk_pmd(st, pud, addr); + } } } @@ -275,10 +284,12 @@ static void walk_pgd(struct pg_state *st, struct mm_struct *mm, unsigned long st for (i = 0; i < PTRS_PER_PGD; i++, pgd++) { addr = start + i * PGDIR_SIZE; - if (pgd_none(*pgd) || pgd_bad(*pgd)) + if (pgd_none(*pgd)) { note_page(st, addr, 1, pgd_val(*pgd)); - else + } else { + BUG_ON(pgd_bad(*pgd)); walk_pud(st, pgd, addr); + } } } diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index c11cd27ca8f5..96da13167d4a 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -219,7 +219,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, if (esr & ESR_LNX_EXEC) { vm_flags = VM_EXEC; - } else if ((esr & ESR_EL1_WRITE) && !(esr & ESR_EL1_CM)) { + } else if ((esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM)) { vm_flags = VM_WRITE; mm_flags |= FAULT_FLAG_WRITE; } diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c index 023747bf4dd7..2de9d2e59d96 100644 --- a/arch/arm64/mm/hugetlbpage.c +++ b/arch/arm64/mm/hugetlbpage.c @@ -38,12 +38,6 @@ int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) } #endif -struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, - int write) -{ - return ERR_PTR(-EINVAL); -} - int pmd_huge(pmd_t pmd) { return !(pmd_val(pmd) & PMD_TABLE_BIT); diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index c95464a33f36..71145f952070 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -136,10 +137,29 @@ static void arm64_memory_present(void) } #endif +static phys_addr_t memory_limit = (phys_addr_t)ULLONG_MAX; + +/* + * Limit the memory size that was specified via FDT. + */ +static int __init early_mem(char *p) +{ + if (!p) + return 1; + + memory_limit = memparse(p, &p) & PAGE_MASK; + pr_notice("Memory limited to %lldMB\n", memory_limit >> 20); + + return 0; +} +early_param("mem", early_mem); + void __init arm64_memblock_init(void) { phys_addr_t dma_phys_limit = 0; + memblock_enforce_memory_limit(memory_limit); + /* * Register the kernel text, kernel data, initrd, and initial * pagetables with memblock. @@ -277,8 +297,8 @@ void __init mem_init(void) " vmemmap : 0x%16lx - 0x%16lx (%6ld GB maximum)\n" " 0x%16lx - 0x%16lx (%6ld MB actual)\n" #endif - " PCI I/O : 0x%16lx - 0x%16lx (%6ld MB)\n" " fixed : 0x%16lx - 0x%16lx (%6ld KB)\n" + " PCI I/O : 0x%16lx - 0x%16lx (%6ld MB)\n" " modules : 0x%16lx - 0x%16lx (%6ld MB)\n" " memory : 0x%16lx - 0x%16lx (%6ld MB)\n" " .init : 0x%p" " - 0x%p" " (%6ld KB)\n" @@ -291,8 +311,8 @@ void __init mem_init(void) MLM((unsigned long)virt_to_page(PAGE_OFFSET), (unsigned long)virt_to_page(high_memory)), #endif - MLM((unsigned long)PCI_IOBASE, (unsigned long)PCI_IOBASE + SZ_16M), MLK(FIXADDR_START, FIXADDR_TOP), + MLM(PCI_IO_START, PCI_IO_END), MLM(MODULES_VADDR, MODULES_END), MLM(PAGE_OFFSET, (unsigned long)high_memory), MLK_ROUNDUP(__init_begin, __init_end), @@ -325,6 +345,7 @@ void __init mem_init(void) void free_initmem(void) { + fixup_init(); free_initmem_default(0); free_alternatives_memory(); } diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c index cbb99c8f1e04..01e88c8bcab0 100644 --- a/arch/arm64/mm/ioremap.c +++ b/arch/arm64/mm/ioremap.c @@ -62,6 +62,7 @@ static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size, if (!area) return NULL; addr = (unsigned long)area->addr; + area->phys_addr = phys_addr; err = ioremap_page_range(addr, addr + size, phys_addr, prot); if (err) { diff --git a/arch/arm64/mm/mm.h b/arch/arm64/mm/mm.h index 50c3351df9c7..ef47d99b5cbc 100644 --- a/arch/arm64/mm/mm.h +++ b/arch/arm64/mm/mm.h @@ -1 +1,3 @@ extern void __init bootmem_init(void); + +void fixup_init(void); diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 6032f3e3056a..c6daaf6c6f97 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include @@ -45,80 +47,6 @@ struct page *empty_zero_page; EXPORT_SYMBOL(empty_zero_page); -struct cachepolicy { - const char policy[16]; - u64 mair; - u64 tcr; -}; - -static struct cachepolicy cache_policies[] __initdata = { - { - .policy = "uncached", - .mair = 0x44, /* inner, outer non-cacheable */ - .tcr = TCR_IRGN_NC | TCR_ORGN_NC, - }, { - .policy = "writethrough", - .mair = 0xaa, /* inner, outer write-through, read-allocate */ - .tcr = TCR_IRGN_WT | TCR_ORGN_WT, - }, { - .policy = "writeback", - .mair = 0xee, /* inner, outer write-back, read-allocate */ - .tcr = TCR_IRGN_WBnWA | TCR_ORGN_WBnWA, - } -}; - -/* - * These are useful for identifying cache coherency problems by allowing the - * cache or the cache and writebuffer to be turned off. It changes the Normal - * memory caching attributes in the MAIR_EL1 register. - */ -static int __init early_cachepolicy(char *p) -{ - int i; - u64 tmp; - - for (i = 0; i < ARRAY_SIZE(cache_policies); i++) { - int len = strlen(cache_policies[i].policy); - - if (memcmp(p, cache_policies[i].policy, len) == 0) - break; - } - if (i == ARRAY_SIZE(cache_policies)) { - pr_err("ERROR: unknown or unsupported cache policy: %s\n", p); - return 0; - } - - flush_cache_all(); - - /* - * Modify MT_NORMAL attributes in MAIR_EL1. - */ - asm volatile( - " mrs %0, mair_el1\n" - " bfi %0, %1, %2, #8\n" - " msr mair_el1, %0\n" - " isb\n" - : "=&r" (tmp) - : "r" (cache_policies[i].mair), "i" (MT_NORMAL * 8)); - - /* - * Modify TCR PTW cacheability attributes. - */ - asm volatile( - " mrs %0, tcr_el1\n" - " bic %0, %0, %2\n" - " orr %0, %0, %1\n" - " msr tcr_el1, %0\n" - " isb\n" - : "=&r" (tmp) - : "r" (cache_policies[i].tcr), "r" (TCR_IRGN_MASK | TCR_ORGN_MASK)); - - flush_cache_all(); - - return 0; -} -early_param("cachepolicy", early_cachepolicy); - pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, pgprot_t vma_prot) { @@ -133,19 +61,42 @@ EXPORT_SYMBOL(phys_mem_access_prot); static void __init *early_alloc(unsigned long sz) { void *ptr = __va(memblock_alloc(sz, sz)); + BUG_ON(!ptr); memset(ptr, 0, sz); return ptr; } -static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, +/* + * remap a PMD into pages + */ +static void split_pmd(pmd_t *pmd, pte_t *pte) +{ + unsigned long pfn = pmd_pfn(*pmd); + int i = 0; + + do { + /* + * Need to have the least restrictive permissions available + * permissions will be fixed up later + */ + set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); + pfn++; + } while (pte++, i++, i < PTRS_PER_PTE); +} + +static void alloc_init_pte(pmd_t *pmd, unsigned long addr, unsigned long end, unsigned long pfn, - pgprot_t prot) + pgprot_t prot, + void *(*alloc)(unsigned long size)) { pte_t *pte; - if (pmd_none(*pmd)) { - pte = early_alloc(PTRS_PER_PTE * sizeof(pte_t)); + if (pmd_none(*pmd) || pmd_sect(*pmd)) { + pte = alloc(PTRS_PER_PTE * sizeof(pte_t)); + if (pmd_sect(*pmd)) + split_pmd(pmd, pte); __pmd_populate(pmd, __pa(pte), PMD_TYPE_TABLE); + flush_tlb_all(); } BUG_ON(pmd_bad(*pmd)); @@ -156,30 +107,42 @@ static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, } while (pte++, addr += PAGE_SIZE, addr != end); } -static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, - unsigned long end, phys_addr_t phys, - int map_io) +void split_pud(pud_t *old_pud, pmd_t *pmd) +{ + unsigned long addr = pud_pfn(*old_pud) << PAGE_SHIFT; + pgprot_t prot = __pgprot(pud_val(*old_pud) ^ addr); + int i = 0; + + do { + set_pmd(pmd, __pmd(addr | prot)); + addr += PMD_SIZE; + } while (pmd++, i++, i < PTRS_PER_PMD); +} + +static void alloc_init_pmd(struct mm_struct *mm, pud_t *pud, + unsigned long addr, unsigned long end, + phys_addr_t phys, pgprot_t prot, + void *(*alloc)(unsigned long size)) { pmd_t *pmd; unsigned long next; - pmdval_t prot_sect; - pgprot_t prot_pte; - - if (map_io) { - prot_sect = PROT_SECT_DEVICE_nGnRE; - prot_pte = __pgprot(PROT_DEVICE_nGnRE); - } else { - prot_sect = PROT_SECT_NORMAL_EXEC; - prot_pte = PAGE_KERNEL_EXEC; - } /* * Check for initial section mappings in the pgd/pud and remove them. */ - if (pud_none(*pud) || pud_bad(*pud)) { - pmd = early_alloc(PTRS_PER_PMD * sizeof(pmd_t)); - pud_populate(&init_mm, pud, pmd); + if (pud_none(*pud) || pud_sect(*pud)) { + pmd = alloc(PTRS_PER_PMD * sizeof(pmd_t)); + if (pud_sect(*pud)) { + /* + * need to have the 1G of mappings continue to be + * present + */ + split_pud(pud, pmd); + } + pud_populate(mm, pud, pmd); + flush_tlb_all(); } + BUG_ON(pud_bad(*pud)); pmd = pmd_offset(pud, addr); do { @@ -187,31 +150,51 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, /* try section mapping first */ if (((addr | next | phys) & ~SECTION_MASK) == 0) { pmd_t old_pmd =*pmd; - set_pmd(pmd, __pmd(phys | prot_sect)); + set_pmd(pmd, __pmd(phys | + pgprot_val(mk_sect_prot(prot)))); /* * Check for previous table entries created during * boot (__create_page_tables) and flush them. */ - if (!pmd_none(old_pmd)) + if (!pmd_none(old_pmd)) { flush_tlb_all(); + if (pmd_table(old_pmd)) { + phys_addr_t table = __pa(pte_offset_map(&old_pmd, 0)); + if (!WARN_ON_ONCE(slab_is_available())) + memblock_free(table, PAGE_SIZE); + } + } } else { alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys), - prot_pte); + prot, alloc); } phys += next - addr; } while (pmd++, addr = next, addr != end); } -static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, - unsigned long end, phys_addr_t phys, - int map_io) +static inline bool use_1G_block(unsigned long addr, unsigned long next, + unsigned long phys) +{ + if (PAGE_SHIFT != 12) + return false; + + if (((addr | next | phys) & ~PUD_MASK) != 0) + return false; + + return true; +} + +static void alloc_init_pud(struct mm_struct *mm, pgd_t *pgd, + unsigned long addr, unsigned long end, + phys_addr_t phys, pgprot_t prot, + void *(*alloc)(unsigned long size)) { pud_t *pud; unsigned long next; if (pgd_none(*pgd)) { - pud = early_alloc(PTRS_PER_PUD * sizeof(pud_t)); - pgd_populate(&init_mm, pgd, pud); + pud = alloc(PTRS_PER_PUD * sizeof(pud_t)); + pgd_populate(mm, pgd, pud); } BUG_ON(pgd_bad(*pgd)); @@ -222,10 +205,10 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, /* * For 4K granule only, attempt to put down a 1GB block */ - if (!map_io && (PAGE_SHIFT == 12) && - ((addr | next | phys) & ~PUD_MASK) == 0) { + if (use_1G_block(addr, next, phys)) { pud_t old_pud = *pud; - set_pud(pud, __pud(phys | PROT_SECT_NORMAL_EXEC)); + set_pud(pud, __pud(phys | + pgprot_val(mk_sect_prot(prot)))); /* * If we have an old value for a pud, it will @@ -235,12 +218,15 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, * Look up the old pmd table and free it. */ if (!pud_none(old_pud)) { - phys_addr_t table = __pa(pmd_offset(&old_pud, 0)); - memblock_free(table, PAGE_SIZE); flush_tlb_all(); + if (pud_table(old_pud)) { + phys_addr_t table = __pa(pmd_offset(&old_pud, 0)); + if (!WARN_ON_ONCE(slab_is_available())) + memblock_free(table, PAGE_SIZE); + } } } else { - alloc_init_pmd(pud, addr, next, phys, map_io); + alloc_init_pmd(mm, pud, addr, next, phys, prot, alloc); } phys += next - addr; } while (pud++, addr = next, addr != end); @@ -250,9 +236,10 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, * Create the page directory entries and any necessary page tables for the * mapping specified by 'md'. */ -static void __init __create_mapping(pgd_t *pgd, phys_addr_t phys, - unsigned long virt, phys_addr_t size, - int map_io) +static void __create_mapping(struct mm_struct *mm, pgd_t *pgd, + phys_addr_t phys, unsigned long virt, + phys_addr_t size, pgprot_t prot, + void *(*alloc)(unsigned long size)) { unsigned long addr, length, end, next; @@ -262,32 +249,96 @@ static void __init __create_mapping(pgd_t *pgd, phys_addr_t phys, end = addr + length; do { next = pgd_addr_end(addr, end); - alloc_init_pud(pgd, addr, next, phys, map_io); + alloc_init_pud(mm, pgd, addr, next, phys, prot, alloc); phys += next - addr; } while (pgd++, addr = next, addr != end); } -static void __init create_mapping(phys_addr_t phys, unsigned long virt, - phys_addr_t size) +static void *late_alloc(unsigned long size) +{ + void *ptr; + + BUG_ON(size > PAGE_SIZE); + ptr = (void *)__get_free_page(PGALLOC_GFP); + BUG_ON(!ptr); + return ptr; +} + +static void __ref create_mapping(phys_addr_t phys, unsigned long virt, + phys_addr_t size, pgprot_t prot) { if (virt < VMALLOC_START) { pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n", &phys, virt); return; } - __create_mapping(pgd_offset_k(virt & PAGE_MASK), phys, virt, size, 0); + __create_mapping(&init_mm, pgd_offset_k(virt & PAGE_MASK), phys, virt, + size, prot, early_alloc); } -void __init create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io) +void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, + unsigned long virt, phys_addr_t size, + pgprot_t prot) { - if ((addr >> PGDIR_SHIFT) >= ARRAY_SIZE(idmap_pg_dir)) { - pr_warn("BUG: not creating id mapping for %pa\n", &addr); + __create_mapping(mm, pgd_offset(mm, virt), phys, virt, size, prot, + late_alloc); +} + +static void create_mapping_late(phys_addr_t phys, unsigned long virt, + phys_addr_t size, pgprot_t prot) +{ + if (virt < VMALLOC_START) { + pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n", + &phys, virt); return; } - __create_mapping(&idmap_pg_dir[pgd_index(addr)], - addr, addr, size, map_io); + + return __create_mapping(&init_mm, pgd_offset_k(virt & PAGE_MASK), + phys, virt, size, prot, late_alloc); } +#ifdef CONFIG_DEBUG_RODATA +static void __init __map_memblock(phys_addr_t start, phys_addr_t end) +{ + /* + * Set up the executable regions using the existing section mappings + * for now. This will get more fine grained later once all memory + * is mapped + */ + unsigned long kernel_x_start = round_down(__pa(_stext), SECTION_SIZE); + unsigned long kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE); + + if (end < kernel_x_start) { + create_mapping(start, __phys_to_virt(start), + end - start, PAGE_KERNEL); + } else if (start >= kernel_x_end) { + create_mapping(start, __phys_to_virt(start), + end - start, PAGE_KERNEL); + } else { + if (start < kernel_x_start) + create_mapping(start, __phys_to_virt(start), + kernel_x_start - start, + PAGE_KERNEL); + create_mapping(kernel_x_start, + __phys_to_virt(kernel_x_start), + kernel_x_end - kernel_x_start, + PAGE_KERNEL_EXEC); + if (kernel_x_end < end) + create_mapping(kernel_x_end, + __phys_to_virt(kernel_x_end), + end - kernel_x_end, + PAGE_KERNEL); + } + +} +#else +static void __init __map_memblock(phys_addr_t start, phys_addr_t end) +{ + create_mapping(start, __phys_to_virt(start), end - start, + PAGE_KERNEL_EXEC); +} +#endif + static void __init map_mem(void) { struct memblock_region *reg; @@ -332,14 +383,53 @@ static void __init map_mem(void) memblock_set_current_limit(limit); } #endif - - create_mapping(start, __phys_to_virt(start), end - start); + __map_memblock(start, end); } /* Limit no longer required. */ memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE); } +void __init fixup_executable(void) +{ +#ifdef CONFIG_DEBUG_RODATA + /* now that we are actually fully mapped, make the start/end more fine grained */ + if (!IS_ALIGNED((unsigned long)_stext, SECTION_SIZE)) { + unsigned long aligned_start = round_down(__pa(_stext), + SECTION_SIZE); + + create_mapping(aligned_start, __phys_to_virt(aligned_start), + __pa(_stext) - aligned_start, + PAGE_KERNEL); + } + + if (!IS_ALIGNED((unsigned long)__init_end, SECTION_SIZE)) { + unsigned long aligned_end = round_up(__pa(__init_end), + SECTION_SIZE); + create_mapping(__pa(__init_end), (unsigned long)__init_end, + aligned_end - __pa(__init_end), + PAGE_KERNEL); + } +#endif +} + +#ifdef CONFIG_DEBUG_RODATA +void mark_rodata_ro(void) +{ + create_mapping_late(__pa(_stext), (unsigned long)_stext, + (unsigned long)_etext - (unsigned long)_stext, + PAGE_KERNEL_EXEC | PTE_RDONLY); + +} +#endif + +void fixup_init(void) +{ + create_mapping_late(__pa(__init_begin), (unsigned long)__init_begin, + (unsigned long)__init_end - (unsigned long)__init_begin, + PAGE_KERNEL); +} + /* * paging_init() sets up the page tables, initialises the zone memory * maps and sets up the zero page. @@ -349,13 +439,7 @@ void __init paging_init(void) void *zero_page; map_mem(); - - /* - * Finally flush the caches and tlb to ensure that we're in a - * consistent state. - */ - flush_cache_all(); - flush_tlb_all(); + fixup_executable(); /* allocate the zero page. */ zero_page = early_alloc(PAGE_SIZE); diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 4e778b13291b..28eebfb6af76 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -102,7 +102,7 @@ ENTRY(cpu_do_idle) ret ENDPROC(cpu_do_idle) -#ifdef CONFIG_ARM64_CPU_SUSPEND +#ifdef CONFIG_CPU_PM /** * cpu_do_suspend - save CPU registers context * @@ -244,14 +244,18 @@ ENTRY(__cpu_setup) ENDPROC(__cpu_setup) /* + * We set the desired value explicitly, including those of the + * reserved bits. The values of bits EE & E0E were set early in + * el2_setup, which are left untouched below. + * * n n T * U E WT T UD US IHBS * CE0 XWHW CZ ME TEEA S * .... .IEE .... NEAI TE.I ..AD DEN0 ACAM - * 0011 0... 1101 ..0. ..0. 10.. .... .... < hardware reserved - * .... .1.. .... 01.1 11.1 ..01 0001 1101 < software settings + * 0011 0... 1101 ..0. ..0. 10.. .0.. .... < hardware reserved + * .... .1.. .... 01.1 11.1 ..01 0.01 1101 < software settings */ .type crval, #object crval: - .word 0x000802e2 // clear - .word 0x0405d11d // set + .word 0xfcffffff // clear + .word 0x34d5d91d // set diff --git a/arch/avr32/configs/atngw100_defconfig b/arch/avr32/configs/atngw100_defconfig index 4733e38e7ae6..ce0030020c25 100644 --- a/arch/avr32/configs/atngw100_defconfig +++ b/arch/avr32/configs/atngw100_defconfig @@ -1,33 +1,28 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=m -# CONFIG_KPROBES is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BOARD_ATNGW100_MKI=y # CONFIG_OWNERSHIP_TRACE is not set CONFIG_NMI_DEBUGGING=y -CONFIG_PM=y CONFIG_CPU_FREQ=y # CONFIG_CPU_FREQ_STAT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_AVR32_AT32AP_CPUFREQ=y -CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -52,7 +47,6 @@ CONFIG_INET6_IPCOMP=y CONFIG_NETFILTER=y # CONFIG_NETFILTER_ADVANCED is not set CONFIG_NETFILTER_XTABLES=y -# CONFIG_IP_NF_TARGET_ULOG is not set CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" @@ -60,7 +54,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -70,28 +63,24 @@ CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=m -CONFIG_MISC_DEVICES=y CONFIG_ATMEL_TCLIB=y CONFIG_NETDEVICES=y CONFIG_TUN=m -CONFIG_NET_ETHERNET=y CONFIG_MACB=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_PPP=m -CONFIG_PPP_FILTER=y -CONFIG_PPP_ASYNC=m -CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=m CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=m CONFIG_I2C_CHARDEV=m @@ -128,7 +117,6 @@ CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set CONFIG_EXT4_FS=y -# CONFIG_EXT4_FS_XATTR is not set # CONFIG_DNOTIFY is not set CONFIG_FUSE_FS=m CONFIG_MSDOS_FS=m @@ -140,7 +128,6 @@ CONFIG_CONFIGFS_FS=y CONFIG_JFFS2_FS=y CONFIG_UBIFS_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NFSD=m CONFIG_NFSD_V3=y @@ -149,8 +136,7 @@ CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_CODEPAGE_850=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_UTF8=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_FRAME_POINTER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/avr32/configs/atngw100_evklcd100_defconfig b/arch/avr32/configs/atngw100_evklcd100_defconfig index 1be0ee31bd91..01ff632249c0 100644 --- a/arch/avr32/configs/atngw100_evklcd100_defconfig +++ b/arch/avr32/configs/atngw100_evklcd100_defconfig @@ -1,35 +1,30 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=m -# CONFIG_KPROBES is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BOARD_ATNGW100_MKI=y CONFIG_BOARD_ATNGW100_EVKLCD10X=y CONFIG_BOARD_ATNGW100_EVKLCD10X_QVGA=y # CONFIG_OWNERSHIP_TRACE is not set CONFIG_NMI_DEBUGGING=y -CONFIG_PM=y CONFIG_CPU_FREQ=y # CONFIG_CPU_FREQ_STAT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_AVR32_AT32AP_CPUFREQ=y -CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -54,7 +49,6 @@ CONFIG_INET6_IPCOMP=y CONFIG_NETFILTER=y # CONFIG_NETFILTER_ADVANCED is not set CONFIG_NETFILTER_XTABLES=y -# CONFIG_IP_NF_TARGET_ULOG is not set CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" @@ -62,7 +56,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -72,21 +65,17 @@ CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=m -CONFIG_MISC_DEVICES=y CONFIG_ATMEL_TCLIB=y CONFIG_NETDEVICES=y CONFIG_TUN=m -CONFIG_NET_ETHERNET=y CONFIG_MACB=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_PPP=m -CONFIG_PPP_FILTER=y -CONFIG_PPP_ASYNC=m -CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=m CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m # CONFIG_INPUT_MOUSEDEV is not set CONFIG_INPUT_EVDEV=m # CONFIG_INPUT_KEYBOARD is not set @@ -94,9 +83,9 @@ CONFIG_INPUT_EVDEV=m CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_WM97XX=m # CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=m CONFIG_I2C_CHARDEV=m @@ -144,7 +133,6 @@ CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set CONFIG_EXT4_FS=y -# CONFIG_EXT4_FS_XATTR is not set # CONFIG_DNOTIFY is not set CONFIG_FUSE_FS=m CONFIG_MSDOS_FS=m @@ -156,7 +144,6 @@ CONFIG_CONFIGFS_FS=y CONFIG_JFFS2_FS=y CONFIG_UBIFS_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NFSD=m CONFIG_NFSD_V3=y @@ -165,8 +152,7 @@ CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_CODEPAGE_850=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_UTF8=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_FRAME_POINTER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/avr32/configs/atngw100_evklcd101_defconfig b/arch/avr32/configs/atngw100_evklcd101_defconfig index 796e536f7bc4..c4021dfd5347 100644 --- a/arch/avr32/configs/atngw100_evklcd101_defconfig +++ b/arch/avr32/configs/atngw100_evklcd101_defconfig @@ -1,34 +1,29 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=m -# CONFIG_KPROBES is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BOARD_ATNGW100_MKI=y CONFIG_BOARD_ATNGW100_EVKLCD10X=y # CONFIG_OWNERSHIP_TRACE is not set CONFIG_NMI_DEBUGGING=y -CONFIG_PM=y CONFIG_CPU_FREQ=y # CONFIG_CPU_FREQ_STAT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_AVR32_AT32AP_CPUFREQ=y -CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -53,7 +48,6 @@ CONFIG_INET6_IPCOMP=y CONFIG_NETFILTER=y # CONFIG_NETFILTER_ADVANCED is not set CONFIG_NETFILTER_XTABLES=y -# CONFIG_IP_NF_TARGET_ULOG is not set CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" @@ -61,7 +55,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -71,21 +64,17 @@ CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=m -CONFIG_MISC_DEVICES=y CONFIG_ATMEL_TCLIB=y CONFIG_NETDEVICES=y CONFIG_TUN=m -CONFIG_NET_ETHERNET=y CONFIG_MACB=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_PPP=m -CONFIG_PPP_FILTER=y -CONFIG_PPP_ASYNC=m -CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=m CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m # CONFIG_INPUT_MOUSEDEV is not set CONFIG_INPUT_EVDEV=m # CONFIG_INPUT_KEYBOARD is not set @@ -93,9 +82,9 @@ CONFIG_INPUT_EVDEV=m CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_WM97XX=m # CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=m CONFIG_I2C_CHARDEV=m @@ -143,7 +132,6 @@ CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set CONFIG_EXT4_FS=y -# CONFIG_EXT4_FS_XATTR is not set # CONFIG_DNOTIFY is not set CONFIG_FUSE_FS=m CONFIG_MSDOS_FS=m @@ -155,7 +143,6 @@ CONFIG_CONFIGFS_FS=y CONFIG_JFFS2_FS=y CONFIG_UBIFS_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NFSD=m CONFIG_NFSD_V3=y @@ -164,8 +151,7 @@ CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_CODEPAGE_850=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_UTF8=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_FRAME_POINTER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/avr32/configs/atngw100_mrmt_defconfig b/arch/avr32/configs/atngw100_mrmt_defconfig index 6838781e966f..ffcc28df9dbc 100644 --- a/arch/avr32/configs/atngw100_mrmt_defconfig +++ b/arch/avr32/configs/atngw100_mrmt_defconfig @@ -1,14 +1,11 @@ -CONFIG_EXPERIMENTAL=y # 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_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set # CONFIG_SLUB_DEBUG is not set CONFIG_MODULES=y @@ -17,8 +14,8 @@ CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set # CONFIG_OWNERSHIP_TRACE is not set -CONFIG_PM=y # CONFIG_SUSPEND is not set +CONFIG_PM=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y @@ -37,7 +34,6 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_LRO is not set # CONFIG_IPV6 is not set CONFIG_BT=m -CONFIG_BT_L2CAP=m CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_HIDP=m @@ -49,7 +45,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -57,10 +52,7 @@ CONFIG_MTD_PHYSMAP=y CONFIG_MTD_DATAFLASH=y CONFIG_BLK_DEV_LOOP=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_MACB=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT_MOUSEDEV is not set CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set @@ -70,9 +62,9 @@ CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ADS7846=m # CONFIG_SERIO is not set CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=y CONFIG_I2C_CHARDEV=y @@ -84,9 +76,7 @@ CONFIG_WATCHDOG=y CONFIG_AT32AP700X_WDT=y CONFIG_FB=y CONFIG_FB_ATMEL=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_SOUND=m CONFIG_SND=m CONFIG_SND_MIXER_OSS=m @@ -129,10 +119,7 @@ CONFIG_TMPFS=y CONFIG_CONFIGFS_FS=y CONFIG_JFFS2_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_SMB_FS=m -CONFIG_SMB_NLS_DEFAULT=y CONFIG_CIFS=m CONFIG_CIFS_STATS=y CONFIG_CIFS_WEAK_PW_HASH=y @@ -142,10 +129,8 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_850=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_FRAME_POINTER=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y CONFIG_CRC_CCITT=y diff --git a/arch/avr32/configs/atngw100mkii_defconfig b/arch/avr32/configs/atngw100mkii_defconfig index 97fe1b399b06..04962641c936 100644 --- a/arch/avr32/configs/atngw100mkii_defconfig +++ b/arch/avr32/configs/atngw100mkii_defconfig @@ -1,33 +1,28 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=m -# CONFIG_KPROBES is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BOARD_ATNGW100_MKII=y # CONFIG_OWNERSHIP_TRACE is not set CONFIG_NMI_DEBUGGING=y -CONFIG_PM=y CONFIG_CPU_FREQ=y # CONFIG_CPU_FREQ_STAT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_AVR32_AT32AP_CPUFREQ=y -CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -52,7 +47,6 @@ CONFIG_INET6_IPCOMP=y CONFIG_NETFILTER=y # CONFIG_NETFILTER_ADVANCED is not set CONFIG_NETFILTER_XTABLES=y -# CONFIG_IP_NF_TARGET_ULOG is not set CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" @@ -60,7 +54,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y @@ -72,28 +65,24 @@ CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=m -CONFIG_MISC_DEVICES=y CONFIG_ATMEL_TCLIB=y CONFIG_NETDEVICES=y CONFIG_TUN=m -CONFIG_NET_ETHERNET=y CONFIG_MACB=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_PPP=m -CONFIG_PPP_FILTER=y -CONFIG_PPP_ASYNC=m -CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=m CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=m CONFIG_I2C_CHARDEV=m @@ -130,7 +119,6 @@ CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set CONFIG_EXT4_FS=y -# CONFIG_EXT4_FS_XATTR is not set # CONFIG_DNOTIFY is not set CONFIG_FUSE_FS=m CONFIG_MSDOS_FS=m @@ -142,7 +130,6 @@ CONFIG_CONFIGFS_FS=y CONFIG_JFFS2_FS=y CONFIG_UBIFS_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NFSD=m CONFIG_NFSD_V3=y @@ -151,8 +138,7 @@ CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_CODEPAGE_850=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_UTF8=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_FRAME_POINTER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/avr32/configs/atngw100mkii_evklcd100_defconfig b/arch/avr32/configs/atngw100mkii_evklcd100_defconfig index a176d24467e9..89c2cda573da 100644 --- a/arch/avr32/configs/atngw100mkii_evklcd100_defconfig +++ b/arch/avr32/configs/atngw100mkii_evklcd100_defconfig @@ -1,36 +1,31 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=m -# CONFIG_KPROBES is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BOARD_ATNGW100_MKII=y CONFIG_BOARD_ATNGW100_MKII_LCD=y CONFIG_BOARD_ATNGW100_EVKLCD10X=y CONFIG_BOARD_ATNGW100_EVKLCD10X_QVGA=y # CONFIG_OWNERSHIP_TRACE is not set CONFIG_NMI_DEBUGGING=y -CONFIG_PM=y CONFIG_CPU_FREQ=y # CONFIG_CPU_FREQ_STAT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_AVR32_AT32AP_CPUFREQ=y -CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -55,7 +50,6 @@ CONFIG_INET6_IPCOMP=y CONFIG_NETFILTER=y # CONFIG_NETFILTER_ADVANCED is not set CONFIG_NETFILTER_XTABLES=y -# CONFIG_IP_NF_TARGET_ULOG is not set CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" @@ -63,7 +57,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y @@ -75,21 +68,17 @@ CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=m -CONFIG_MISC_DEVICES=y CONFIG_ATMEL_TCLIB=y CONFIG_NETDEVICES=y CONFIG_TUN=m -CONFIG_NET_ETHERNET=y CONFIG_MACB=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_PPP=m -CONFIG_PPP_FILTER=y -CONFIG_PPP_ASYNC=m -CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=m CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m # CONFIG_INPUT_MOUSEDEV is not set CONFIG_INPUT_EVDEV=m # CONFIG_INPUT_KEYBOARD is not set @@ -97,9 +86,9 @@ CONFIG_INPUT_EVDEV=m CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_WM97XX=m # CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=m CONFIG_I2C_CHARDEV=m @@ -147,7 +136,6 @@ CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set CONFIG_EXT4_FS=y -# CONFIG_EXT4_FS_XATTR is not set # CONFIG_DNOTIFY is not set CONFIG_FUSE_FS=m CONFIG_MSDOS_FS=m @@ -159,7 +147,6 @@ CONFIG_CONFIGFS_FS=y CONFIG_JFFS2_FS=y CONFIG_UBIFS_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NFSD=m CONFIG_NFSD_V3=y @@ -168,8 +155,7 @@ CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_CODEPAGE_850=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_UTF8=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_FRAME_POINTER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/avr32/configs/atngw100mkii_evklcd101_defconfig b/arch/avr32/configs/atngw100mkii_evklcd101_defconfig index d1bf6dcfc47d..1b4d4a87a356 100644 --- a/arch/avr32/configs/atngw100mkii_evklcd101_defconfig +++ b/arch/avr32/configs/atngw100mkii_evklcd101_defconfig @@ -1,35 +1,30 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=m -# CONFIG_KPROBES is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BOARD_ATNGW100_MKII=y CONFIG_BOARD_ATNGW100_MKII_LCD=y CONFIG_BOARD_ATNGW100_EVKLCD10X=y # CONFIG_OWNERSHIP_TRACE is not set CONFIG_NMI_DEBUGGING=y -CONFIG_PM=y CONFIG_CPU_FREQ=y # CONFIG_CPU_FREQ_STAT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_AVR32_AT32AP_CPUFREQ=y -CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -54,7 +49,6 @@ CONFIG_INET6_IPCOMP=y CONFIG_NETFILTER=y # CONFIG_NETFILTER_ADVANCED is not set CONFIG_NETFILTER_XTABLES=y -# CONFIG_IP_NF_TARGET_ULOG is not set CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" @@ -62,7 +56,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y @@ -74,21 +67,17 @@ CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=m -CONFIG_MISC_DEVICES=y CONFIG_ATMEL_TCLIB=y CONFIG_NETDEVICES=y CONFIG_TUN=m -CONFIG_NET_ETHERNET=y CONFIG_MACB=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_PPP=m -CONFIG_PPP_FILTER=y -CONFIG_PPP_ASYNC=m -CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y CONFIG_PPP_MPPE=m CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m # CONFIG_INPUT_MOUSEDEV is not set CONFIG_INPUT_EVDEV=m # CONFIG_INPUT_KEYBOARD is not set @@ -96,9 +85,9 @@ CONFIG_INPUT_EVDEV=m CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_WM97XX=m # CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=m CONFIG_I2C_CHARDEV=m @@ -146,7 +135,6 @@ CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set CONFIG_EXT4_FS=y -# CONFIG_EXT4_FS_XATTR is not set # CONFIG_DNOTIFY is not set CONFIG_FUSE_FS=m CONFIG_MSDOS_FS=m @@ -158,7 +146,6 @@ CONFIG_CONFIGFS_FS=y CONFIG_JFFS2_FS=y CONFIG_UBIFS_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NFSD=m CONFIG_NFSD_V3=y @@ -167,8 +154,7 @@ CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_CODEPAGE_850=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_UTF8=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_FRAME_POINTER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/avr32/configs/atstk1002_defconfig b/arch/avr32/configs/atstk1002_defconfig index b056820eef33..9b8b52e54b79 100644 --- a/arch/avr32/configs/atstk1002_defconfig +++ b/arch/avr32/configs/atstk1002_defconfig @@ -1,32 +1,27 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=m -# CONFIG_KPROBES is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y # CONFIG_OWNERSHIP_TRACE is not set CONFIG_NMI_DEBUGGING=y -CONFIG_PM=y CONFIG_CPU_FREQ=y # CONFIG_CPU_FREQ_STAT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_AVR32_AT32AP_CPUFREQ=y -CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -54,7 +49,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -63,7 +57,6 @@ CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=m -CONFIG_MISC_DEVICES=y CONFIG_ATMEL_TCLIB=y CONFIG_ATMEL_SSC=m # CONFIG_SCSI_PROC_FS is not set @@ -75,14 +68,11 @@ CONFIG_ATA=m CONFIG_PATA_AT32=m CONFIG_NETDEVICES=y CONFIG_TUN=m -CONFIG_NET_ETHERNET=y CONFIG_MACB=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_PPP=m -CONFIG_PPP_ASYNC=m -CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_ASYNC=m CONFIG_INPUT=m CONFIG_INPUT_EVDEV=m # CONFIG_KEYBOARD_ATKBD is not set @@ -91,10 +81,10 @@ CONFIG_KEYBOARD_GPIO=m CONFIG_MOUSE_GPIO=m # CONFIG_SERIO is not set # CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=m CONFIG_I2C_CHARDEV=m @@ -108,10 +98,8 @@ CONFIG_WATCHDOG=y CONFIG_AT32AP700X_WDT=y CONFIG_FB=y CONFIG_FB_ATMEL=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_LTV350QV=y -# CONFIG_BACKLIGHT_CLASS_DEVICE is not set CONFIG_SOUND=m CONFIG_SND=m CONFIG_SND_MIXER_OSS=m @@ -119,7 +107,6 @@ CONFIG_SND_PCM_OSS=m # CONFIG_SND_SUPPORT_OLD_API is not set # CONFIG_SND_VERBOSE_PROCFS is not set CONFIG_SND_AT73C213=m -# CONFIG_HID_SUPPORT is not set CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m @@ -147,7 +134,6 @@ CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set CONFIG_EXT4_FS=y -# CONFIG_EXT4_FS_XATTR is not set # CONFIG_DNOTIFY is not set CONFIG_FUSE_FS=m CONFIG_MSDOS_FS=m @@ -159,15 +145,13 @@ CONFIG_CONFIGFS_FS=y CONFIG_JFFS2_FS=y CONFIG_UBIFS_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_CIFS=m CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_CODEPAGE_850=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_UTF8=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_FRAME_POINTER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/avr32/configs/atstk1003_defconfig b/arch/avr32/configs/atstk1003_defconfig index 0cd23a303da1..ccce1a0b7917 100644 --- a/arch/avr32/configs/atstk1003_defconfig +++ b/arch/avr32/configs/atstk1003_defconfig @@ -1,33 +1,28 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=m -# CONFIG_KPROBES is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BOARD_ATSTK1003=y # CONFIG_OWNERSHIP_TRACE is not set CONFIG_NMI_DEBUGGING=y -CONFIG_PM=y CONFIG_CPU_FREQ=y # CONFIG_CPU_FREQ_STAT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_AVR32_AT32AP_CPUFREQ=y -CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -43,7 +38,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -52,7 +46,6 @@ CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=m -CONFIG_MISC_DEVICES=y CONFIG_ATMEL_TCLIB=y CONFIG_ATMEL_SSC=m # CONFIG_SCSI_PROC_FS is not set @@ -63,12 +56,10 @@ CONFIG_ATA=m # CONFIG_SATA_PMP is not set CONFIG_PATA_AT32=m CONFIG_NETDEVICES=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_PPP=m -CONFIG_PPP_ASYNC=m -CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_ASYNC=m CONFIG_INPUT=m CONFIG_INPUT_EVDEV=m # CONFIG_KEYBOARD_ATKBD is not set @@ -77,10 +68,10 @@ CONFIG_KEYBOARD_GPIO=m CONFIG_MOUSE_GPIO=m # CONFIG_SERIO is not set # CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=m CONFIG_I2C_CHARDEV=m @@ -98,7 +89,6 @@ CONFIG_SND_MIXER_OSS=m CONFIG_SND_PCM_OSS=m # CONFIG_SND_DRIVERS is not set CONFIG_SND_AT73C213=m -# CONFIG_HID_SUPPORT is not set CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m @@ -126,7 +116,6 @@ CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set CONFIG_EXT4_FS=y -# CONFIG_EXT4_FS_XATTR is not set # CONFIG_DNOTIFY is not set CONFIG_FUSE_FS=m CONFIG_MSDOS_FS=m @@ -142,8 +131,7 @@ CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_CODEPAGE_850=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_UTF8=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_FRAME_POINTER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/avr32/configs/atstk1004_defconfig b/arch/avr32/configs/atstk1004_defconfig index ac1041f5f85a..e64288fc794d 100644 --- a/arch/avr32/configs/atstk1004_defconfig +++ b/arch/avr32/configs/atstk1004_defconfig @@ -1,33 +1,28 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=m -# CONFIG_KPROBES is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BOARD_ATSTK1004=y # CONFIG_OWNERSHIP_TRACE is not set CONFIG_NMI_DEBUGGING=y -CONFIG_PM=y CONFIG_CPU_FREQ=y # CONFIG_CPU_FREQ_STAT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_AVR32_AT32AP_CPUFREQ=y -CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -43,7 +38,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -52,7 +46,6 @@ CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=m -CONFIG_MISC_DEVICES=y CONFIG_ATMEL_TCLIB=y CONFIG_ATMEL_SSC=m # CONFIG_SCSI_PROC_FS is not set @@ -63,12 +56,10 @@ CONFIG_ATA=m # CONFIG_SATA_PMP is not set CONFIG_PATA_AT32=m CONFIG_NETDEVICES=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_PPP=m -CONFIG_PPP_ASYNC=m -CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_ASYNC=m CONFIG_INPUT=m CONFIG_INPUT_EVDEV=m # CONFIG_KEYBOARD_ATKBD is not set @@ -77,10 +68,10 @@ CONFIG_KEYBOARD_GPIO=m CONFIG_MOUSE_GPIO=m # CONFIG_SERIO is not set # CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=m CONFIG_I2C_CHARDEV=m @@ -94,10 +85,8 @@ CONFIG_WATCHDOG=y CONFIG_AT32AP700X_WDT=y CONFIG_FB=y CONFIG_FB_ATMEL=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_LTV350QV=y -# CONFIG_BACKLIGHT_CLASS_DEVICE is not set CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m @@ -125,7 +114,6 @@ CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set CONFIG_EXT4_FS=y -# CONFIG_EXT4_FS_XATTR is not set # CONFIG_DNOTIFY is not set CONFIG_FUSE_FS=m CONFIG_MSDOS_FS=m @@ -141,8 +129,7 @@ CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_CODEPAGE_850=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_UTF8=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_FRAME_POINTER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/avr32/configs/atstk1006_defconfig b/arch/avr32/configs/atstk1006_defconfig index ea4f670cb995..7d669f79ff74 100644 --- a/arch/avr32/configs/atstk1006_defconfig +++ b/arch/avr32/configs/atstk1006_defconfig @@ -1,33 +1,28 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=m -# CONFIG_KPROBES is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BOARD_ATSTK1006=y # CONFIG_OWNERSHIP_TRACE is not set CONFIG_NMI_DEBUGGING=y -CONFIG_PM=y CONFIG_CPU_FREQ=y # CONFIG_CPU_FREQ_STAT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_AVR32_AT32AP_CPUFREQ=y -CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -55,7 +50,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -66,7 +60,6 @@ CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=m -CONFIG_MISC_DEVICES=y CONFIG_ATMEL_TCLIB=y CONFIG_ATMEL_SSC=m # CONFIG_SCSI_PROC_FS is not set @@ -78,14 +71,11 @@ CONFIG_ATA=m CONFIG_PATA_AT32=m CONFIG_NETDEVICES=y CONFIG_TUN=m -CONFIG_NET_ETHERNET=y CONFIG_MACB=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_PPP=m -CONFIG_PPP_ASYNC=m -CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_ASYNC=m CONFIG_INPUT=m CONFIG_INPUT_EVDEV=m # CONFIG_KEYBOARD_ATKBD is not set @@ -94,10 +84,10 @@ CONFIG_KEYBOARD_GPIO=m CONFIG_MOUSE_GPIO=m # CONFIG_SERIO is not set # CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=m CONFIG_I2C_CHARDEV=m @@ -111,10 +101,8 @@ CONFIG_WATCHDOG=y CONFIG_AT32AP700X_WDT=y CONFIG_FB=y CONFIG_FB_ATMEL=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_LTV350QV=y -# CONFIG_BACKLIGHT_CLASS_DEVICE is not set CONFIG_SOUND=m CONFIG_SND=m CONFIG_SND_MIXER_OSS=m @@ -122,7 +110,6 @@ CONFIG_SND_PCM_OSS=m # CONFIG_SND_SUPPORT_OLD_API is not set # CONFIG_SND_VERBOSE_PROCFS is not set CONFIG_SND_AT73C213=m -# CONFIG_HID_SUPPORT is not set CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m @@ -150,7 +137,6 @@ CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set CONFIG_EXT4_FS=y -# CONFIG_EXT4_FS_XATTR is not set # CONFIG_DNOTIFY is not set CONFIG_FUSE_FS=m CONFIG_MSDOS_FS=m @@ -162,15 +148,13 @@ CONFIG_CONFIGFS_FS=y CONFIG_JFFS2_FS=y CONFIG_UBIFS_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_CIFS=m CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_CODEPAGE_850=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_UTF8=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_FRAME_POINTER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/avr32/configs/favr-32_defconfig b/arch/avr32/configs/favr-32_defconfig index b3eb67dc05ac..560c52f87d45 100644 --- a/arch/avr32/configs/favr-32_defconfig +++ b/arch/avr32/configs/favr-32_defconfig @@ -1,28 +1,23 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=m -# CONFIG_KPROBES is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BOARD_FAVR_32=y # CONFIG_OWNERSHIP_TRACE is not set CONFIG_NMI_DEBUGGING=y -CONFIG_PM=y CONFIG_CPU_FREQ=y # CONFIG_CPU_FREQ_STAT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y @@ -37,7 +32,6 @@ CONFIG_INET=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_NET_IPIP=m -CONFIG_NET_IPGRE=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_XFRM_MODE_TRANSPORT=m @@ -59,7 +53,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -70,14 +63,11 @@ CONFIG_BLK_DEV_RAM=m CONFIG_ATMEL_TCLIB=y CONFIG_ATMEL_SSC=m CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_MACB=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_PPP=m -CONFIG_PPP_ASYNC=m -CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_ASYNC=m CONFIG_INPUT_MOUSEDEV=m CONFIG_INPUT_EVDEV=m # CONFIG_KEYBOARD_ATKBD is not set @@ -88,10 +78,10 @@ CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ADS7846=m # CONFIG_SERIO is not set # CONFIG_CONSOLE_TRANSLATIONS is not set +# CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=m CONFIG_I2C_CHARDEV=m @@ -105,12 +95,10 @@ CONFIG_WATCHDOG=y CONFIG_AT32AP700X_WDT=y CONFIG_FB=y CONFIG_FB_ATMEL=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y # CONFIG_LCD_CLASS_DEVICE is not set CONFIG_BACKLIGHT_PWM=m CONFIG_SOUND=m CONFIG_SOUND_PRIME=m -# CONFIG_HID_SUPPORT is not set CONFIG_USB_GADGET=y CONFIG_USB_ZERO=m CONFIG_USB_ETH=m @@ -145,13 +133,11 @@ CONFIG_CONFIGFS_FS=y CONFIG_JFFS2_FS=y # CONFIG_JFFS2_FS_WRITEBUFFER is not set CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_UTF8=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y CONFIG_FRAME_POINTER=y +CONFIG_MAGIC_SYSRQ=y # CONFIG_CRYPTO_HW is not set diff --git a/arch/avr32/configs/hammerhead_defconfig b/arch/avr32/configs/hammerhead_defconfig index 4912f0aadaa1..d57fadb9e6b6 100644 --- a/arch/avr32/configs/hammerhead_defconfig +++ b/arch/avr32/configs/hammerhead_defconfig @@ -1,26 +1,22 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=m -# CONFIG_KPROBES is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BOARD_HAMMERHEAD=y CONFIG_BOARD_HAMMERHEAD_USB=y CONFIG_BOARD_HAMMERHEAD_LCD=y @@ -53,13 +49,11 @@ CONFIG_INET_IPCOMP=y CONFIG_NETFILTER=y # CONFIG_NETFILTER_ADVANCED is not set CONFIG_NETFILTER_XTABLES=y -# CONFIG_IP_NF_TARGET_ULOG is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_PREVENT_FIRMWARE_BUILD is not set # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -70,16 +64,13 @@ CONFIG_ATMEL_TCLIB=y CONFIG_SCSI=m CONFIG_BLK_DEV_SD=m CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_MACB=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_INPUT_FF_MEMLESS=m CONFIG_INPUT_EVDEV=m CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=m CONFIG_I2C_CHARDEV=m @@ -114,10 +105,8 @@ CONFIG_HID_MONTEREY=m CONFIG_HID_PANTHERLORD=m CONFIG_HID_PETALYNX=m CONFIG_HID_SAMSUNG=m -CONFIG_HID_SONY=m CONFIG_HID_SUNPLUS=m CONFIG_USB=m -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=m CONFIG_USB_ISP116X_HCD=m CONFIG_USB_STORAGE=m @@ -140,16 +129,13 @@ CONFIG_TMPFS=y CONFIG_CONFIGFS_FS=y CONFIG_JFFS2_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_CODEPAGE_850=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_UTF8=m -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y CONFIG_FRAME_POINTER=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_MAGIC_SYSRQ=y CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_ARC4=m diff --git a/arch/avr32/configs/merisc_defconfig b/arch/avr32/configs/merisc_defconfig index b9ef4cc85d08..e6a9cb7d574e 100644 --- a/arch/avr32/configs/merisc_defconfig +++ b/arch/avr32/configs/merisc_defconfig @@ -1,22 +1,19 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BOARD_MERISC=y CONFIG_AP700X_32_BIT_SMC=y # CONFIG_OWNERSHIP_TRACE is not set @@ -39,14 +36,10 @@ CONFIG_INET_IPCOMP=y # CONFIG_INET_LRO is not set # CONFIG_IPV6 is not set CONFIG_CAN=y -CONFIG_CAN_RAW=y -CONFIG_CAN_BCM=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_PREVENT_FIRMWARE_BUILD is not set # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CONCAT=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y @@ -60,10 +53,7 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_MACB=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT_MOUSEDEV is not set CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set @@ -74,11 +64,10 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_UINPUT=y # CONFIG_SERIO is not set # CONFIG_CONSOLE_TRANSLATIONS is not set -CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=y CONFIG_I2C_CHARDEV=y @@ -89,13 +78,9 @@ CONFIG_SPI_SPIDEV=y CONFIG_GPIO_SYSFS=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_FB=y CONFIG_FB_ATMEL=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y # CONFIG_LCD_CLASS_DEVICE is not set -# CONFIG_BACKLIGHT_CLASS_DEVICE is not set -CONFIG_DISPLAY_SUPPORT=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y CONFIG_MMC=y @@ -121,12 +106,10 @@ CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_WBUF_VERIFY=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_850=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set # CONFIG_CRYPTO_ANSI_CPRNG is not set # CONFIG_CRYPTO_HW is not set diff --git a/arch/avr32/configs/mimc200_defconfig b/arch/avr32/configs/mimc200_defconfig index d630e089dd32..49c7e890af7b 100644 --- a/arch/avr32/configs/mimc200_defconfig +++ b/arch/avr32/configs/mimc200_defconfig @@ -1,25 +1,21 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_BASE_FULL is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BOARD_MIMC200=y # CONFIG_OWNERSHIP_TRACE is not set CONFIG_NMI_DEBUGGING=y -CONFIG_PM=y CONFIG_CPU_FREQ=y # CONFIG_CPU_FREQ_STAT is not set CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y @@ -50,7 +46,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -60,17 +55,14 @@ CONFIG_ATMEL_TCLIB=y CONFIG_EEPROM_AT24=y CONFIG_EEPROM_AT25=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_MACB=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=y CONFIG_I2C_CHARDEV=y @@ -109,15 +101,13 @@ CONFIG_TMPFS=y CONFIG_CONFIGFS_FS=y CONFIG_JFFS2_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_850=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y CONFIG_FRAME_POINTER=y +CONFIG_MAGIC_SYSRQ=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y CONFIG_CRYPTO_ARC4=y diff --git a/arch/avr32/include/asm/pgtable.h b/arch/avr32/include/asm/pgtable.h index 4beff97e2033..35800664076e 100644 --- a/arch/avr32/include/asm/pgtable.h +++ b/arch/avr32/include/asm/pgtable.h @@ -30,7 +30,7 @@ #define PGDIR_MASK (~(PGDIR_SIZE-1)) #define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #ifndef __ASSEMBLY__ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; @@ -86,9 +86,6 @@ extern struct page *empty_zero_page; #define _PAGE_BIT_PRESENT 10 #define _PAGE_BIT_ACCESSED 11 /* software: page was accessed */ -/* The following flags are only valid when !PRESENT */ -#define _PAGE_BIT_FILE 0 /* software: pagecache or swap? */ - #define _PAGE_WT (1 << _PAGE_BIT_WT) #define _PAGE_DIRTY (1 << _PAGE_BIT_DIRTY) #define _PAGE_EXECUTE (1 << _PAGE_BIT_EXECUTE) @@ -101,7 +98,6 @@ extern struct page *empty_zero_page; /* Software flags */ #define _PAGE_ACCESSED (1 << _PAGE_BIT_ACCESSED) #define _PAGE_PRESENT (1 << _PAGE_BIT_PRESENT) -#define _PAGE_FILE (1 << _PAGE_BIT_FILE) /* * Page types, i.e. sizes. _PAGE_TYPE_NONE corresponds to what is @@ -210,14 +206,6 @@ static inline int pte_special(pte_t pte) return 0; } -/* - * The following only work if pte_present() is not true. - */ -static inline int pte_file(pte_t pte) -{ - return pte_val(pte) & _PAGE_FILE; -} - /* Mutator functions for PTE bits */ static inline pte_t pte_wrprotect(pte_t pte) { @@ -329,7 +317,6 @@ extern void update_mmu_cache(struct vm_area_struct * vma, * Encode and decode a swap entry * * Constraints: - * _PAGE_FILE at bit 0 * _PAGE_TYPE_* at bits 2-3 (for emulating _PAGE_PROTNONE) * _PAGE_PRESENT at bit 10 * @@ -346,18 +333,6 @@ extern void update_mmu_cache(struct vm_area_struct * vma, #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -/* - * Encode and decode a nonlinear file mapping entry. We have to - * preserve _PAGE_FILE and _PAGE_PRESENT here. _PAGE_TYPE_* isn't - * necessary, since _PAGE_FILE implies !_PAGE_PROTNONE (?) - */ -#define PTE_FILE_MAX_BITS 30 -#define pte_to_pgoff(pte) (((pte_val(pte) >> 1) & 0x1ff) \ - | ((pte_val(pte) >> 11) << 9)) -#define pgoff_to_pte(off) ((pte_t) { ((((off) & 0x1ff) << 1) \ - | (((off) >> 9) << 11) \ - | _PAGE_FILE) }) - typedef pte_t *pte_addr_t; #define kern_addr_valid(addr) (1) diff --git a/arch/avr32/include/asm/unistd.h b/arch/avr32/include/asm/unistd.h index c1eb080e45fe..2011bee3f252 100644 --- a/arch/avr32/include/asm/unistd.h +++ b/arch/avr32/include/asm/unistd.h @@ -10,7 +10,7 @@ #include -#define NR_syscalls 284 +#define NR_syscalls 321 /* Old stuff */ #define __IGNORE_uselib diff --git a/arch/avr32/include/uapi/asm/unistd.h b/arch/avr32/include/uapi/asm/unistd.h index 8822bf46ddc6..bbe2fba565cd 100644 --- a/arch/avr32/include/uapi/asm/unistd.h +++ b/arch/avr32/include/uapi/asm/unistd.h @@ -222,7 +222,6 @@ #define __NR_epoll_wait 207 #define __NR_remap_file_pages 208 #define __NR_set_tid_address 209 - #define __NR_timer_create 210 #define __NR_timer_settime 211 #define __NR_timer_gettime 212 @@ -238,7 +237,6 @@ /* 222 reserved for tux */ #define __NR_utimes 223 #define __NR_fadvise64_64 224 - #define __NR_cacheflush 225 #define __NR_vserver 226 @@ -281,7 +279,6 @@ #define __NR_tee 263 #define __NR_vmsplice 264 #define __NR_epoll_pwait 265 - #define __NR_msgget 266 #define __NR_msgsnd 267 #define __NR_msgrcv 268 @@ -294,11 +291,47 @@ #define __NR_shmget 275 #define __NR_shmdt 276 #define __NR_shmctl 277 - #define __NR_utimensat 278 #define __NR_signalfd 279 /* 280 was __NR_timerfd */ #define __NR_eventfd 281 #define __NR_setns 283 +#define __NR_pread64 284 +#define __NR_pwrite64 285 +#define __NR_timerfd_create 286 +#define __NR_fallocate 287 +#define __NR_timerfd_settime 288 +#define __NR_timerfd_gettime 289 +#define __NR_signalfd4 290 +#define __NR_eventfd2 291 +#define __NR_epoll_create1 292 +#define __NR_dup3 293 +#define __NR_pipe2 294 +#define __NR_inotify_init1 295 +#define __NR_preadv 296 +#define __NR_pwritev 297 +#define __NR_rt_tgsigqueueinfo 298 +#define __NR_perf_event_open 299 +#define __NR_recvmmsg 300 +#define __NR_fanotify_init 301 +#define __NR_fanotify_mark 302 +#define __NR_prlimit64 303 +#define __NR_name_to_handle_at 304 +#define __NR_open_by_handle_at 305 +#define __NR_clock_adjtime 306 +#define __NR_syncfs 307 +#define __NR_sendmmsg 308 +#define __NR_process_vm_readv 309 +#define __NR_process_vm_writev 310 +#define __NR_kcmp 311 +#define __NR_finit_module 312 +#define __NR_sched_setattr 313 +#define __NR_sched_getattr 314 +#define __NR_renameat2 315 +#define __NR_seccomp 316 +#define __NR_getrandom 317 +#define __NR_memfd_create 318 +#define __NR_bpf 319 +#define __NR_execveat 320 #endif /* _UAPI__ASM_AVR32_UNISTD_H */ diff --git a/arch/avr32/kernel/module.c b/arch/avr32/kernel/module.c index 2c9412908024..164efa009e5b 100644 --- a/arch/avr32/kernel/module.c +++ b/arch/avr32/kernel/module.c @@ -19,12 +19,10 @@ #include #include -void module_free(struct module *mod, void *module_region) +void module_arch_freeing_init(struct module *mod) { vfree(mod->arch.syminfo); mod->arch.syminfo = NULL; - - vfree(module_region); } static inline int check_rela(Elf32_Rela *rela, struct module *module, @@ -291,12 +289,3 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, return ret; } - -int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, - struct module *module) -{ - vfree(module->arch.syminfo); - module->arch.syminfo = NULL; - - return 0; -} diff --git a/arch/avr32/kernel/syscall-stubs.S b/arch/avr32/kernel/syscall-stubs.S index b5fc927cd398..f9c68fab0e2f 100644 --- a/arch/avr32/kernel/syscall-stubs.S +++ b/arch/avr32/kernel/syscall-stubs.S @@ -88,3 +88,39 @@ __sys_sync_file_range: call sys_sync_file_range sub sp, -4 popm pc + + .global __sys_fallocate + .type __sys_fallocate,@function +__sys_fallocate: + pushm lr + st.w --sp, ARG6 + call sys_fallocate + sub sp, -4 + popm pc + + .global __sys_fanotify_mark + .type __sys_fanotify_mark,@function +__sys_fanotify_mark: + pushm lr + st.w --sp, ARG6 + call sys_fanotify_mark + sub sp, -4 + popm pc + + .global __sys_process_vm_readv + .type __sys_process_vm_readv,@function +__sys_process_vm_readv: + pushm lr + st.w --sp, ARG6 + call sys_process_vm_readv + sub sp, -4 + popm pc + + .global __sys_process_vm_writev + .type __sys_process_vm_writev,@function +__sys_process_vm_writev: + pushm lr + st.w --sp, ARG6 + call sys_process_vm_writev + sub sp, -4 + popm pc diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S index 017a904180c8..c3b593bfc3b3 100644 --- a/arch/avr32/kernel/syscall_table.S +++ b/arch/avr32/kernel/syscall_table.S @@ -297,4 +297,41 @@ sys_call_table: .long sys_eventfd .long sys_recvmmsg .long sys_setns + .long sys_pread64 + .long sys_pwrite64 /* 285 */ + .long sys_timerfd_create + .long __sys_fallocate + .long sys_timerfd_settime + .long sys_timerfd_gettime + .long sys_signalfd4 /* 290 */ + .long sys_eventfd2 + .long sys_epoll_create1 + .long sys_dup3 + .long sys_pipe2 + .long sys_inotify_init1 /* 295 */ + .long sys_preadv + .long sys_pwritev + .long sys_rt_tgsigqueueinfo + .long sys_perf_event_open + .long sys_recvmmsg /* 300 */ + .long sys_fanotify_init + .long __sys_fanotify_mark + .long sys_prlimit64 + .long sys_name_to_handle_at + .long sys_open_by_handle_at /* 305 */ + .long sys_clock_adjtime + .long sys_syncfs + .long sys_sendmmsg + .long __sys_process_vm_readv + .long __sys_process_vm_writev /* 310 */ + .long sys_kcmp + .long sys_finit_module + .long sys_sched_setattr + .long sys_sched_getattr + .long sys_renameat2 /* 315 */ + .long sys_seccomp + .long sys_getrandom + .long sys_memfd_create + .long sys_bpf + .long sys_execveat /* 320 */ .long sys_ni_syscall /* r8 is saturated at nr_syscalls */ diff --git a/arch/avr32/mach-at32ap/include/mach/cpu.h b/arch/avr32/mach-at32ap/include/mach/cpu.h index 16a24b14146c..4181086f4ddc 100644 --- a/arch/avr32/mach-at32ap/include/mach/cpu.h +++ b/arch/avr32/mach-at32ap/include/mach/cpu.h @@ -1,5 +1,5 @@ /* - * AVR32 and (fake) AT91 CPU identification + * AVR32 CPU identification * * Copyright (C) 2007 Atmel Corporation * @@ -20,28 +20,4 @@ # define cpu_is_at32ap7000() (0) #endif -/* - * Since this is AVR32, we will never run on any AT91 CPU. But these - * definitions may reduce clutter in common drivers. - */ -#define cpu_is_at91rm9200() (0) -#define cpu_is_at91sam9xe() (0) -#define cpu_is_at91sam9260() (0) -#define cpu_is_at91sam9261() (0) -#define cpu_is_at91sam9263() (0) -#define cpu_is_at91sam9rl() (0) -#define cpu_is_at91sam9g10() (0) -#define cpu_is_at91sam9g20() (0) -#define cpu_is_at91sam9g45() (0) -#define cpu_is_at91sam9g45es() (0) -#define cpu_is_at91sam9m10() (0) -#define cpu_is_at91sam9g46() (0) -#define cpu_is_at91sam9m11() (0) -#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 /* __ASM_ARCH_CPU_H */ diff --git a/arch/avr32/mm/fault.c b/arch/avr32/mm/fault.c index 0eca93327195..d223a8b57c1e 100644 --- a/arch/avr32/mm/fault.c +++ b/arch/avr32/mm/fault.c @@ -142,6 +142,8 @@ good_area: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/blackfin/include/asm/pgtable.h b/arch/blackfin/include/asm/pgtable.h index 0b049019eba7..b88a1558b0b9 100644 --- a/arch/blackfin/include/asm/pgtable.h +++ b/arch/blackfin/include/asm/pgtable.h @@ -45,11 +45,6 @@ extern void paging_init(void); #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_file(pte_t pte) -{ - return 0; -} - #define set_pte(pteptr, pteval) (*(pteptr) = pteval) #define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval) diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index dd2af74aff80..7236bdfc71e6 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -429,14 +429,6 @@ static void init_software_driven_irq(void) bfin_sec_enable_ssi(37); } -void bfin_sec_resume(void) -{ - bfin_write_SEC_SCI(0, SEC_CCTL, SEC_CCTL_RESET); - udelay(100); - bfin_write_SEC_GCTL(SEC_GCTL_EN); - bfin_write_SEC_SCI(0, SEC_CCTL, SEC_CCTL_EN | SEC_CCTL_NMI_EN); -} - void handle_sec_sfi_fault(uint32_t gstat) { diff --git a/arch/c6x/include/asm/pgtable.h b/arch/c6x/include/asm/pgtable.h index c0eed5b18860..78d4483ba40c 100644 --- a/arch/c6x/include/asm/pgtable.h +++ b/arch/c6x/include/asm/pgtable.h @@ -50,11 +50,6 @@ extern void paging_init(void); #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_file(pte_t pte) -{ - return 0; -} - #define set_pte(pteptr, pteval) (*(pteptr) = pteval) #define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval) diff --git a/arch/cris/arch-v32/drivers/sync_serial.c b/arch/cris/arch-v32/drivers/sync_serial.c index 08a313fc2241..f772068d9e79 100644 --- a/arch/cris/arch-v32/drivers/sync_serial.c +++ b/arch/cris/arch-v32/drivers/sync_serial.c @@ -604,7 +604,7 @@ static ssize_t __sync_serial_read(struct file *file, struct timespec *ts) { unsigned long flags; - int dev = MINOR(file->f_dentry->d_inode->i_rdev); + int dev = MINOR(file_inode(file)->i_rdev); int avail; struct sync_port *port; unsigned char *start; diff --git a/arch/cris/include/arch-v10/arch/mmu.h b/arch/cris/include/arch-v10/arch/mmu.h index e829e5a37bbe..47a5dd21749d 100644 --- a/arch/cris/include/arch-v10/arch/mmu.h +++ b/arch/cris/include/arch-v10/arch/mmu.h @@ -58,7 +58,6 @@ typedef struct /* Bits the HW doesn't care about but the kernel uses them in SW */ #define _PAGE_PRESENT (1<<4) /* page present in memory */ -#define _PAGE_FILE (1<<5) /* set: pagecache, unset: swap (when !PRESENT) */ #define _PAGE_ACCESSED (1<<5) /* simulated in software using valid bit */ #define _PAGE_MODIFIED (1<<6) /* simulated in software using we bit */ #define _PAGE_READ (1<<7) /* read-enabled */ @@ -105,6 +104,4 @@ typedef struct #define __S110 PAGE_SHARED #define __S111 PAGE_SHARED -#define PTE_FILE_MAX_BITS 26 - #endif diff --git a/arch/cris/include/arch-v32/arch/mmu.h b/arch/cris/include/arch-v32/arch/mmu.h index c1a13e05e963..e6db1616dee5 100644 --- a/arch/cris/include/arch-v32/arch/mmu.h +++ b/arch/cris/include/arch-v32/arch/mmu.h @@ -53,7 +53,6 @@ typedef struct * software. */ #define _PAGE_PRESENT (1 << 5) /* Page is present in memory. */ -#define _PAGE_FILE (1 << 6) /* 1=pagecache, 0=swap (when !present) */ #define _PAGE_ACCESSED (1 << 6) /* Simulated in software using valid bit. */ #define _PAGE_MODIFIED (1 << 7) /* Simulated in software using we bit. */ #define _PAGE_READ (1 << 8) /* Read enabled. */ @@ -108,6 +107,4 @@ typedef struct #define __S110 PAGE_SHARED_EXEC #define __S111 PAGE_SHARED_EXEC -#define PTE_FILE_MAX_BITS 25 - #endif /* _ASM_CRIS_ARCH_MMU_H */ diff --git a/arch/cris/include/asm/pgtable.h b/arch/cris/include/asm/pgtable.h index 8b8c86793225..ceefc314d64d 100644 --- a/arch/cris/include/asm/pgtable.h +++ b/arch/cris/include/asm/pgtable.h @@ -67,7 +67,7 @@ extern void paging_init(void); */ #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL /* zero page used for uninitialized stuff */ #ifndef __ASSEMBLY__ @@ -114,7 +114,6 @@ extern unsigned long empty_zero_page; static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_MODIFIED; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } static inline int pte_special(pte_t pte) { return 0; } static inline pte_t pte_wrprotect(pte_t pte) @@ -290,9 +289,6 @@ static inline void update_mmu_cache(struct vm_area_struct * vma, */ #define pgtable_cache_init() do { } while (0) -#define pte_to_pgoff(x) (pte_val(x) >> 6) -#define pgoff_to_pte(x) __pte(((x) << 6) | _PAGE_FILE) - typedef pte_t *pte_addr_t; #endif /* __ASSEMBLY__ */ diff --git a/arch/cris/kernel/module.c b/arch/cris/kernel/module.c index 51123f985eb5..af04cb6b6dc9 100644 --- a/arch/cris/kernel/module.c +++ b/arch/cris/kernel/module.c @@ -36,7 +36,7 @@ void *module_alloc(unsigned long size) } /* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) +void module_memfree(void *module_region) { kfree(module_region); } diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c index 1790f22e71a2..2686a7aa8ec8 100644 --- a/arch/cris/mm/fault.c +++ b/arch/cris/mm/fault.c @@ -176,6 +176,8 @@ retry: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/frv/include/asm/pgtable.h b/arch/frv/include/asm/pgtable.h index eb0110acd19b..93bcf2abd1a1 100644 --- a/arch/frv/include/asm/pgtable.h +++ b/arch/frv/include/asm/pgtable.h @@ -62,10 +62,6 @@ typedef pte_t *pte_addr_t; #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -#ifndef __ASSEMBLY__ -static inline int pte_file(pte_t pte) { return 0; } -#endif - #define ZERO_PAGE(vaddr) ({ BUG(); NULL; }) #define swapper_pg_dir ((pgd_t *) NULL) @@ -144,7 +140,7 @@ extern unsigned long empty_zero_page; #define PTRS_PER_PTE 4096 #define USER_PGDS_IN_LAST_PML4 (TASK_SIZE / PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT) #define KERNEL_PGD_PTRS (PTRS_PER_PGD - USER_PGD_PTRS) @@ -298,7 +294,6 @@ static inline pmd_t *pmd_offset(pud_t *dir, unsigned long address) #define _PAGE_RESERVED_MASK (xAMPRx_RESERVED8 | xAMPRx_RESERVED13) -#define _PAGE_FILE 0x002 /* set:pagecache unset:swap */ #define _PAGE_PROTNONE 0x000 /* If not present */ #define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) @@ -463,27 +458,15 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) * Handle swap and file entries * - the PTE is encoded in the following format: * bit 0: Must be 0 (!_PAGE_PRESENT) - * bit 1: Type: 0 for swap, 1 for file (_PAGE_FILE) - * bits 2-7: Swap type - * bits 8-31: Swap offset - * bits 2-31: File pgoff + * bits 1-6: Swap type + * bits 7-31: Swap offset */ -#define __swp_type(x) (((x).val >> 2) & 0x1f) -#define __swp_offset(x) ((x).val >> 8) -#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 2) | ((offset) << 8) }) +#define __swp_type(x) (((x).val >> 1) & 0x1f) +#define __swp_offset(x) ((x).val >> 7) +#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 7) }) #define __pte_to_swp_entry(_pte) ((swp_entry_t) { (_pte).pte }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_file(pte_t pte) -{ - return pte.pte & _PAGE_FILE; -} - -#define PTE_FILE_MAX_BITS 29 - -#define pte_to_pgoff(PTE) ((PTE).pte >> 2) -#define pgoff_to_pte(off) __pte((off) << 2 | _PAGE_FILE) - /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ #define PageSkip(page) (0) #define kern_addr_valid(addr) (1) diff --git a/arch/frv/mb93090-mb00/pci-frv.c b/arch/frv/mb93090-mb00/pci-frv.c index 67b1d1685759..0635bd6c2af3 100644 --- a/arch/frv/mb93090-mb00/pci-frv.c +++ b/arch/frv/mb93090-mb00/pci-frv.c @@ -94,7 +94,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) r = &dev->resource[idx]; if (!r->start) continue; - pci_claim_resource(dev, idx); + pci_claim_bridge_resource(dev, idx); } } pcibios_allocate_bus_resources(&bus->children); diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c index efa5d65b0007..b073f4d771a5 100644 --- a/arch/frv/mb93090-mb00/pci-vdk.c +++ b/arch/frv/mb93090-mb00/pci-vdk.c @@ -168,8 +168,8 @@ static int pci_frv_write_config(struct pci_bus *bus, unsigned int devfn, int whe } static struct pci_ops pci_direct_frv = { - pci_frv_read_config, - pci_frv_write_config, + .read = pci_frv_read_config, + .write = pci_frv_write_config, }; /* diff --git a/arch/frv/mm/fault.c b/arch/frv/mm/fault.c index 9a66372fc7c7..ec4917ddf678 100644 --- a/arch/frv/mm/fault.c +++ b/arch/frv/mm/fault.c @@ -168,6 +168,8 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/hexagon/include/asm/pgtable.h b/arch/hexagon/include/asm/pgtable.h index d8bd54fa431e..49eab8136ec3 100644 --- a/arch/hexagon/include/asm/pgtable.h +++ b/arch/hexagon/include/asm/pgtable.h @@ -61,13 +61,6 @@ extern unsigned long zero_page_mask; #define _PAGE_DIRTY (1<<1) #define _PAGE_ACCESSED (1<<2) -/* - * _PAGE_FILE is only meaningful if _PAGE_PRESENT is false, while - * _PAGE_DIRTY is only meaningful if _PAGE_PRESENT is true. - * So we can overload the bit... - */ -#define _PAGE_FILE _PAGE_DIRTY /* set: pagecache, unset = swap */ - /* * For now, let's say that Valid and Present are the same thing. * Alternatively, we could say that it's the "or" of R, W, and X @@ -178,7 +171,7 @@ extern unsigned long _dflt_cache_att; extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* located in head.S */ /* Seems to be zero even in architectures where the zero page is firewalled? */ -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define pte_special(pte) 0 #define pte_mkspecial(pte) (pte) @@ -456,57 +449,36 @@ static inline int pte_exec(pte_t pte) #define pgtable_cache_init() do { } while (0) /* - * Swap/file PTE definitions. If _PAGE_PRESENT is zero, the rest of the - * PTE is interpreted as swap information. Depending on the _PAGE_FILE - * bit, the remaining free bits are eitehr interpreted as a file offset - * or a swap type/offset tuple. Rather than have the TLB fill handler - * test _PAGE_PRESENT, we're going to reserve the permissions bits - * and set them to all zeros for swap entries, which speeds up the - * miss handler at the cost of 3 bits of offset. That trade-off can - * be revisited if necessary, but Hexagon processor architecture and - * target applications suggest a lot of TLB misses and not much swap space. + * Swap/file PTE definitions. If _PAGE_PRESENT is zero, the rest of the PTE is + * interpreted as swap information. The remaining free bits are interpreted as + * swap type/offset tuple. Rather than have the TLB fill handler test + * _PAGE_PRESENT, we're going to reserve the permissions bits and set them to + * all zeros for swap entries, which speeds up the miss handler at the cost of + * 3 bits of offset. That trade-off can be revisited if necessary, but Hexagon + * processor architecture and target applications suggest a lot of TLB misses + * and not much swap space. * * Format of swap PTE: * bit 0: Present (zero) - * bit 1: _PAGE_FILE (zero) - * bits 2-6: swap type (arch independent layer uses 5 bits max) - * bits 7-9: bits 2:0 of offset - * bits 10-12: effectively _PAGE_PROTNONE (all zero) - * bits 13-31: bits 21:3 of swap offset - * - * Format of file PTE: - * bit 0: Present (zero) - * bit 1: _PAGE_FILE (zero) - * bits 2-9: bits 7:0 of offset - * bits 10-12: effectively _PAGE_PROTNONE (all zero) - * bits 13-31: bits 26:8 of swap offset + * bits 1-5: swap type (arch independent layer uses 5 bits max) + * bits 6-9: bits 3:0 of offset + * bits 10-12: effectively _PAGE_PROTNONE (all zero) + * bits 13-31: bits 22:4 of swap offset * * The split offset makes some of the following macros a little gnarly, * but there's plenty of precedent for this sort of thing. */ -#define PTE_FILE_MAX_BITS 27 /* Used for swap PTEs */ -#define __swp_type(swp_pte) (((swp_pte).val >> 2) & 0x1f) +#define __swp_type(swp_pte) (((swp_pte).val >> 1) & 0x1f) #define __swp_offset(swp_pte) \ - ((((swp_pte).val >> 7) & 0x7) | (((swp_pte).val >> 10) & 0x003ffff8)) + ((((swp_pte).val >> 6) & 0xf) | (((swp_pte).val >> 9) & 0x7ffff0)) #define __swp_entry(type, offset) \ ((swp_entry_t) { \ - ((type << 2) | \ - ((offset & 0x3ffff8) << 10) | ((offset & 0x7) << 7)) }) - -/* Used for file PTEs */ -#define pte_file(pte) \ - ((pte_val(pte) & (_PAGE_FILE | _PAGE_PRESENT)) == _PAGE_FILE) - -#define pte_to_pgoff(pte) \ - (((pte_val(pte) >> 2) & 0xff) | ((pte_val(pte) >> 5) & 0x07ffff00)) - -#define pgoff_to_pte(off) \ - ((pte_t) { ((((off) & 0x7ffff00) << 5) | (((off) & 0xff) << 2)\ - | _PAGE_FILE) }) + ((type << 1) | \ + ((offset & 0x7ffff0) << 9) | ((offset & 0xf) << 6)) }) /* Oh boy. There are a lot of possible arch overrides found in this file. */ #include diff --git a/arch/ia64/include/asm/pgtable.h b/arch/ia64/include/asm/pgtable.h index 7935115398a6..7b6f8801df57 100644 --- a/arch/ia64/include/asm/pgtable.h +++ b/arch/ia64/include/asm/pgtable.h @@ -57,9 +57,6 @@ #define _PAGE_ED (__IA64_UL(1) << 52) /* exception deferral */ #define _PAGE_PROTNONE (__IA64_UL(1) << 63) -/* Valid only for a PTE with the present bit cleared: */ -#define _PAGE_FILE (1 << 1) /* see swap & file pte remarks below */ - #define _PFN_MASK _PAGE_PPN_MASK /* Mask of bits which may be changed by pte_modify(); the odd bits are there for _PAGE_PROTNONE */ #define _PAGE_CHG_MASK (_PAGE_P | _PAGE_PROTNONE | _PAGE_PL_MASK | _PAGE_AR_MASK | _PAGE_ED) @@ -130,7 +127,7 @@ #define PTRS_PER_PGD_SHIFT PTRS_PER_PTD_SHIFT #define PTRS_PER_PGD (1UL << PTRS_PER_PGD_SHIFT) #define USER_PTRS_PER_PGD (5*PTRS_PER_PGD/8) /* regions 0-4 are user regions */ -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL /* * All the normal masks have the "page accessed" bits on, as any time @@ -300,7 +297,6 @@ extern unsigned long VMALLOC_END; #define pte_exec(pte) ((pte_val(pte) & _PAGE_AR_RX) != 0) #define pte_dirty(pte) ((pte_val(pte) & _PAGE_D) != 0) #define pte_young(pte) ((pte_val(pte) & _PAGE_A) != 0) -#define pte_file(pte) ((pte_val(pte) & _PAGE_FILE) != 0) #define pte_special(pte) 0 /* @@ -472,27 +468,16 @@ extern void paging_init (void); * * Format of swap pte: * bit 0 : present bit (must be zero) - * bit 1 : _PAGE_FILE (must be zero) - * bits 2- 8: swap-type - * bits 9-62: swap offset - * bit 63 : _PAGE_PROTNONE bit - * - * Format of file pte: - * bit 0 : present bit (must be zero) - * bit 1 : _PAGE_FILE (must be one) - * bits 2-62: file_offset/PAGE_SIZE + * bits 1- 7: swap-type + * bits 8-62: swap offset * bit 63 : _PAGE_PROTNONE bit */ -#define __swp_type(entry) (((entry).val >> 2) & 0x7f) -#define __swp_offset(entry) (((entry).val << 1) >> 10) -#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << 2) | ((long) (offset) << 9) }) +#define __swp_type(entry) (((entry).val >> 1) & 0x7f) +#define __swp_offset(entry) (((entry).val << 1) >> 9) +#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << 1) | ((long) (offset) << 8) }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -#define PTE_FILE_MAX_BITS 61 -#define pte_to_pgoff(pte) ((pte_val(pte) << 1) >> 3) -#define pgoff_to_pte(off) ((pte_t) { ((off) << 2) | _PAGE_FILE }) - /* * ZERO_PAGE is a global shared page that is always zero: used * for zero-mapped memory areas etc.. diff --git a/arch/ia64/kernel/acpi-ext.c b/arch/ia64/kernel/acpi-ext.c index 8b9318d311a0..bd09bf74f187 100644 --- a/arch/ia64/kernel/acpi-ext.c +++ b/arch/ia64/kernel/acpi-ext.c @@ -69,10 +69,10 @@ static acpi_status find_csr_space(struct acpi_resource *resource, void *data) status = acpi_resource_to_address64(resource, &addr); if (ACPI_SUCCESS(status) && addr.resource_type == ACPI_MEMORY_RANGE && - addr.address_length && + addr.address.address_length && addr.producer_consumer == ACPI_CONSUMER) { - space->base = addr.minimum; - space->length = addr.address_length; + space->base = addr.address.minimum; + space->length = addr.address.address_length; return AE_CTRL_TERMINATE; } return AE_OK; /* keep looking */ diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index e795cb848154..2c4498919d3c 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -380,9 +380,6 @@ static void __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) static int __init acpi_parse_madt(struct acpi_table_header *table) { - if (!table) - return -EINVAL; - acpi_madt = (struct acpi_table_madt *)table; acpi_madt_rev = acpi_madt->header.revision; @@ -645,9 +642,6 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table) struct acpi_table_header *fadt_header; struct acpi_table_fadt *fadt; - if (!table) - return -EINVAL; - fadt_header = (struct acpi_table_header *)table; if (fadt_header->revision != 3) return -ENODEV; /* Only deal with ACPI 2.0 FADT */ diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c index 24603be24c14..29754aae5177 100644 --- a/arch/ia64/kernel/module.c +++ b/arch/ia64/kernel/module.c @@ -305,14 +305,12 @@ plt_target (struct plt_entry *plt) #endif /* !USE_BRL */ void -module_free (struct module *mod, void *module_region) +module_arch_freeing_init (struct module *mod) { - if (mod && mod->arch.init_unw_table && - module_region == mod->module_init) { + if (mod->arch.init_unw_table) { unw_remove_unwind_table(mod->arch.init_unw_table); mod->arch.init_unw_table = NULL; } - vfree(module_region); } /* Have we already seen one of these relocations? */ diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index 7225dad87094..ba5ba7accd0d 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -172,6 +172,8 @@ retry: */ if (fault & VM_FAULT_OOM) { goto out_of_memory; + } else if (fault & VM_FAULT_SIGSEGV) { + goto bad_area; } else if (fault & VM_FAULT_SIGBUS) { signal = SIGBUS; goto bad_area; diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c index 76069c18ee42..52b7604b5215 100644 --- a/arch/ia64/mm/hugetlbpage.c +++ b/arch/ia64/mm/hugetlbpage.c @@ -114,12 +114,6 @@ int pud_huge(pud_t pud) return 0; } -struct page * -follow_huge_pmd(struct mm_struct *mm, unsigned long address, pmd_t *pmd, int write) -{ - return NULL; -} - void hugetlb_free_pgd_range(struct mmu_gather *tlb, unsigned long addr, unsigned long end, unsigned long floor, unsigned long ceiling) diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 291a582777cf..48cc65705db4 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -188,12 +188,12 @@ static u64 add_io_space(struct pci_root_info *info, name = (char *)(iospace + 1); - min = addr->minimum; - max = min + addr->address_length - 1; + min = addr->address.minimum; + max = min + addr->address.address_length - 1; if (addr->info.io.translation_type == ACPI_SPARSE_TRANSLATION) sparse = 1; - space_nr = new_space(addr->translation_offset, sparse); + space_nr = new_space(addr->address.translation_offset, sparse); if (space_nr == ~0) goto free_resource; @@ -247,7 +247,7 @@ static acpi_status resource_to_window(struct acpi_resource *resource, if (ACPI_SUCCESS(status) && (addr->resource_type == ACPI_MEMORY_RANGE || addr->resource_type == ACPI_IO_RANGE) && - addr->address_length && + addr->address.address_length && addr->producer_consumer == ACPI_PRODUCER) return AE_OK; @@ -284,7 +284,7 @@ static acpi_status add_window(struct acpi_resource *res, void *data) if (addr.resource_type == ACPI_MEMORY_RANGE) { flags = IORESOURCE_MEM; root = &iomem_resource; - offset = addr.translation_offset; + offset = addr.address.translation_offset; } else if (addr.resource_type == ACPI_IO_RANGE) { flags = IORESOURCE_IO; root = &ioport_resource; @@ -297,8 +297,8 @@ static acpi_status add_window(struct acpi_resource *res, void *data) resource = &info->res[info->res_num]; resource->name = info->name; resource->flags = flags; - resource->start = addr.minimum + offset; - resource->end = resource->start + addr.address_length - 1; + resource->start = addr.address.minimum + offset; + resource->end = resource->start + addr.address.address_length - 1; info->res_offset[info->res_num] = offset; if (insert_resource(root, resource)) { @@ -487,45 +487,39 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) return 0; } -static int is_valid_resource(struct pci_dev *dev, int idx) -{ - unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM; - struct resource *devr = &dev->resource[idx], *busr; - - if (!dev->bus) - return 0; - - pci_bus_for_each_resource(dev->bus, busr, i) { - if (!busr || ((busr->flags ^ devr->flags) & type_mask)) - continue; - if ((devr->start) && (devr->start >= busr->start) && - (devr->end <= busr->end)) - return 1; - } - return 0; -} - -static void pcibios_fixup_resources(struct pci_dev *dev, int start, int limit) -{ - int i; - - for (i = start; i < limit; i++) { - if (!dev->resource[i].flags) - continue; - if ((is_valid_resource(dev, i))) - pci_claim_resource(dev, i); - } -} - void pcibios_fixup_device_resources(struct pci_dev *dev) { - pcibios_fixup_resources(dev, 0, PCI_BRIDGE_RESOURCES); + int idx; + + if (!dev->bus) + return; + + for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) { + struct resource *r = &dev->resource[idx]; + + if (!r->flags || r->parent || !r->start) + continue; + + pci_claim_resource(dev, idx); + } } EXPORT_SYMBOL_GPL(pcibios_fixup_device_resources); static void pcibios_fixup_bridge_resources(struct pci_dev *dev) { - pcibios_fixup_resources(dev, PCI_BRIDGE_RESOURCES, PCI_NUM_RESOURCES); + int idx; + + if (!dev->bus) + return; + + for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { + struct resource *r = &dev->resource[idx]; + + if (!r->flags || r->parent || !r->start) + continue; + + pci_claim_bridge_resource(dev, idx); + } } /* diff --git a/arch/m32r/include/asm/pgtable-2level.h b/arch/m32r/include/asm/pgtable-2level.h index 9cdaf7350ef6..8fd8ee70266a 100644 --- a/arch/m32r/include/asm/pgtable-2level.h +++ b/arch/m32r/include/asm/pgtable-2level.h @@ -70,9 +70,5 @@ static inline pmd_t *pmd_offset(pgd_t * dir, unsigned long address) #define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) #define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) -#define PTE_FILE_MAX_BITS 29 -#define pte_to_pgoff(pte) (((pte_val(pte) >> 2) & 0x7f) | (((pte_val(pte) >> 10)) << 7)) -#define pgoff_to_pte(off) ((pte_t) { (((off) & 0x7f) << 2) | (((off) >> 7) << 10) | _PAGE_FILE }) - #endif /* __KERNEL__ */ #endif /* _ASM_M32R_PGTABLE_2LEVEL_H */ diff --git a/arch/m32r/include/asm/pgtable.h b/arch/m32r/include/asm/pgtable.h index 103ce6710f07..8c1fb902a9ce 100644 --- a/arch/m32r/include/asm/pgtable.h +++ b/arch/m32r/include/asm/pgtable.h @@ -53,7 +53,7 @@ extern unsigned long empty_zero_page[1024]; #define PGDIR_MASK (~(PGDIR_SIZE - 1)) #define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #ifndef __ASSEMBLY__ /* Just any arbitrary offset to the start of the vmalloc VM area: the @@ -80,8 +80,6 @@ extern unsigned long empty_zero_page[1024]; */ #define _PAGE_BIT_DIRTY 0 /* software: page changed */ -#define _PAGE_BIT_FILE 0 /* when !present: nonlinear file - mapping */ #define _PAGE_BIT_PRESENT 1 /* Valid: page is valid */ #define _PAGE_BIT_GLOBAL 2 /* Global */ #define _PAGE_BIT_LARGE 3 /* Large */ @@ -93,7 +91,6 @@ extern unsigned long empty_zero_page[1024]; #define _PAGE_BIT_PROTNONE 9 /* software: if not present */ #define _PAGE_DIRTY (1UL << _PAGE_BIT_DIRTY) -#define _PAGE_FILE (1UL << _PAGE_BIT_FILE) #define _PAGE_PRESENT (1UL << _PAGE_BIT_PRESENT) #define _PAGE_GLOBAL (1UL << _PAGE_BIT_GLOBAL) #define _PAGE_LARGE (1UL << _PAGE_BIT_LARGE) @@ -206,14 +203,6 @@ static inline int pte_write(pte_t pte) return pte_val(pte) & _PAGE_WRITE; } -/* - * The following only works if pte_present() is not true. - */ -static inline int pte_file(pte_t pte) -{ - return pte_val(pte) & _PAGE_FILE; -} - static inline int pte_special(pte_t pte) { return 0; diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c index e9c6a8014bd6..e3d4d4890104 100644 --- a/arch/m32r/mm/fault.c +++ b/arch/m32r/mm/fault.c @@ -200,6 +200,8 @@ good_area: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index 95022b04b62d..264db1126803 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -170,7 +170,6 @@ repeat: if (acia_stat & ACIA_RDRF) { /* received a character */ scancode = acia.key_data; /* get it or reset the ACIA, I'll get it! */ - tasklet_schedule(&keyboard_tasklet); interpret_scancode: switch (kb_state.state) { case KEYBOARD: @@ -430,14 +429,6 @@ void ikbd_mouse_y0_top(void) } EXPORT_SYMBOL(ikbd_mouse_y0_top); -/* Resume */ -void ikbd_resume(void) -{ - static const char cmd[1] = { 0x11 }; - - ikbd_write(cmd, 1); -} - /* Disable mouse */ void ikbd_mouse_disable(void) { @@ -447,14 +438,6 @@ void ikbd_mouse_disable(void) } EXPORT_SYMBOL(ikbd_mouse_disable); -/* Pause output */ -void ikbd_pause(void) -{ - static const char cmd[1] = { 0x13 }; - - ikbd_write(cmd, 1); -} - /* Set joystick event reporting */ void ikbd_joystick_event_on(void) { @@ -502,56 +485,6 @@ void ikbd_joystick_disable(void) ikbd_write(cmd, 1); } -/* Time-of-day clock set */ -void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second) -{ - char cmd[7] = { 0x1B, year, month, day, hour, minute, second }; - - ikbd_write(cmd, 7); -} - -/* Interrogate time-of-day clock */ -void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second) -{ - static const char cmd[1] = { 0x1C }; - - ikbd_write(cmd, 1); -} - -/* Memory load */ -void ikbd_mem_write(int address, int size, char *data) -{ - panic("Attempt to write data into keyboard memory"); -} - -/* Memory read */ -void ikbd_mem_read(int address, char data[6]) -{ - char cmd[3] = { 0x21, address>>8, address&0xFF }; - - ikbd_write(cmd, 3); - - /* receive data and put it in data */ -} - -/* Controller execute */ -void ikbd_exec(int address) -{ - char cmd[3] = { 0x22, address>>8, address&0xFF }; - - ikbd_write(cmd, 3); -} - -/* Status inquiries (0x87-0x9A) not yet implemented */ - -/* Set the state of the caps lock led. */ -void atari_kbd_leds(unsigned int leds) -{ - char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0}; - - ikbd_write(cmd, 6); -} - /* * The original code sometimes left the interrupt line of * the ACIAs low forever. I hope, it is fixed now. @@ -571,9 +504,8 @@ int atari_keyb_init(void) kb_state.state = KEYBOARD; kb_state.len = 0; - error = request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, - IRQ_TYPE_SLOW, "keyboard,mouse,MIDI", - atari_keyboard_interrupt); + error = request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, 0, + "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 e5a66596b116..ba65f942d0c7 100644 --- a/arch/m68k/atari/stdma.c +++ b/arch/m68k/atari/stdma.c @@ -198,7 +198,7 @@ EXPORT_SYMBOL(stdma_islocked); void __init stdma_init(void) { stdma_isr = NULL; - if (request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW | IRQF_SHARED, + if (request_irq(IRQ_MFP_FDC, stdma_int, IRQF_SHARED, "ST-DMA floppy,ACSI,IDE,Falcon-SCSI", stdma_int)) pr_err("Couldn't register ST-DMA interrupt\n"); } diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c index da8f981c36d6..c549b48174ec 100644 --- a/arch/m68k/atari/time.c +++ b/arch/m68k/atari/time.c @@ -32,8 +32,7 @@ atari_sched_init(irq_handler_t timer_routine) /* start timer C, div = 1:100 */ st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60; /* install interrupt service routine for MFP Timer C */ - if (request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, - "timer", timer_routine)) + if (request_irq(IRQ_MFP_TIMC, timer_routine, 0, "timer", timer_routine)) pr_err("Couldn't register timer interrupt\n"); } diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig index 399df883c8bb..1a10a08ebec7 100644 --- a/arch/m68k/configs/amiga_defconfig +++ b/arch/m68k/configs/amiga_defconfig @@ -36,6 +36,7 @@ CONFIG_AMIGA_PCMCIA=y CONFIG_ZORRO_NAMES=y # CONFIG_COMPACTION is not set CONFIG_CLEANCACHE=y +CONFIG_ZPOOL=m # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_AOUT=m CONFIG_BINFMT_MISC=m @@ -55,6 +56,8 @@ CONFIG_NET_IPIP=m CONFIG_NET_IPGRE_DEMUX=m CONFIG_NET_IPGRE=m CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_GENEVE=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -96,6 +99,8 @@ CONFIG_NFT_HASH=m CONFIG_NFT_COUNTER=m CONFIG_NFT_LOG=m CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m CONFIG_NFT_NAT=m CONFIG_NFT_QUEUE=m CONFIG_NFT_REJECT=m @@ -142,6 +147,7 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=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 @@ -163,6 +169,7 @@ CONFIG_IP_SET_HASH_IPMARK=m CONFIG_IP_SET_HASH_IPPORT=m CONFIG_IP_SET_HASH_IPPORTIP=m CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_MAC=m CONFIG_IP_SET_HASH_NETPORTNET=m CONFIG_IP_SET_HASH_NET=m CONFIG_IP_SET_HASH_NETNET=m @@ -170,9 +177,12 @@ CONFIG_IP_SET_HASH_NETPORT=m CONFIG_IP_SET_HASH_NETIFACE=m CONFIG_IP_SET_LIST_SET=m CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_LOG_ARP=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m -CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NFT_MASQ_IPV4=m +CONFIG_NFT_REDIR_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -181,8 +191,7 @@ CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m +CONFIG_IP_NF_NAT=m CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_REDIRECT=m @@ -197,6 +206,8 @@ CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NFT_MASQ_IPV6=m +CONFIG_NFT_REDIR_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -213,17 +224,43 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_TARGET_SYNPROXY=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m -CONFIG_NF_NAT_IPV6=m +CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_LOG_BRIDGE=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_NFLOG=m CONFIG_IP_DCCP=m # CONFIG_IP_DCCP_CCID3 is not set CONFIG_SCTP_COOKIE_HMAC_SHA1=y CONFIG_RDS=m CONFIG_RDS_TCP=m CONFIG_L2TP=m +CONFIG_BRIDGE=m CONFIG_ATALK=m +CONFIG_6LOWPAN=m CONFIG_DNS_RESOLVER=y CONFIG_BATMAN_ADV=m CONFIG_BATMAN_ADV_DAT=y @@ -232,9 +269,10 @@ CONFIG_BATMAN_ADV_MCAST=y CONFIG_NETLINK_DIAG=m CONFIG_NET_MPLS_GSO=m # CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set -# CONFIG_FW_LOADER_USER_HELPER is not set CONFIG_CONNECTOR=m CONFIG_PARPORT=m CONFIG_PARPORT_AMIGA=m @@ -299,6 +337,9 @@ CONFIG_NET_TEAM_MODE_ROUNDROBIN=m CONFIG_NET_TEAM_MODE_RANDOM=m CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -316,6 +357,8 @@ CONFIG_ARIADNE=y CONFIG_HYDRA=y CONFIG_APNE=y CONFIG_ZORRO8390=y +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set # CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set # CONFIG_NET_VENDOR_SMSC is not set @@ -371,6 +414,7 @@ CONFIG_HID=m CONFIG_HIDRAW=y CONFIG_UHID=m # CONFIG_HID_GENERIC is not set +# CONFIG_HID_PLANTRONICS is not set # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_MSM6242=m @@ -392,6 +436,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -407,6 +452,7 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_CRAMFS=m CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZO=y CONFIG_MINIX_FS=m CONFIG_OMFS_FS=m @@ -476,10 +522,18 @@ CONFIG_DLM=m CONFIG_MAGIC_SYSRQ=y CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_STRING_HELPERS=m +CONFIG_TEST_KSTRTOX=m +CONFIG_TEST_LKM=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_UDELAY=m +CONFIG_EARLY_PRINTK=y CONFIG_ENCRYPTED_KEYS=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m @@ -514,13 +568,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m # CONFIG_CRYPTO_HW is not set -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_XZ_DEC_TEST=m diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig index be16740c0749..7859a738c81e 100644 --- a/arch/m68k/configs/apollo_defconfig +++ b/arch/m68k/configs/apollo_defconfig @@ -34,6 +34,7 @@ CONFIG_M68060=y CONFIG_APOLLO=y # CONFIG_COMPACTION is not set CONFIG_CLEANCACHE=y +CONFIG_ZPOOL=m # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_AOUT=m CONFIG_BINFMT_MISC=m @@ -53,6 +54,8 @@ CONFIG_NET_IPIP=m CONFIG_NET_IPGRE_DEMUX=m CONFIG_NET_IPGRE=m CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_GENEVE=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -94,6 +97,8 @@ CONFIG_NFT_HASH=m CONFIG_NFT_COUNTER=m CONFIG_NFT_LOG=m CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m CONFIG_NFT_NAT=m CONFIG_NFT_QUEUE=m CONFIG_NFT_REJECT=m @@ -140,6 +145,7 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=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 @@ -161,6 +167,7 @@ CONFIG_IP_SET_HASH_IPMARK=m CONFIG_IP_SET_HASH_IPPORT=m CONFIG_IP_SET_HASH_IPPORTIP=m CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_MAC=m CONFIG_IP_SET_HASH_NETPORTNET=m CONFIG_IP_SET_HASH_NET=m CONFIG_IP_SET_HASH_NETNET=m @@ -168,9 +175,12 @@ CONFIG_IP_SET_HASH_NETPORT=m CONFIG_IP_SET_HASH_NETIFACE=m CONFIG_IP_SET_LIST_SET=m CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_LOG_ARP=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m -CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NFT_MASQ_IPV4=m +CONFIG_NFT_REDIR_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -179,8 +189,7 @@ CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m +CONFIG_IP_NF_NAT=m CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_REDIRECT=m @@ -195,6 +204,8 @@ CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NFT_MASQ_IPV6=m +CONFIG_NFT_REDIR_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -211,17 +222,43 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_TARGET_SYNPROXY=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m -CONFIG_NF_NAT_IPV6=m +CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_LOG_BRIDGE=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_NFLOG=m CONFIG_IP_DCCP=m # CONFIG_IP_DCCP_CCID3 is not set CONFIG_SCTP_COOKIE_HMAC_SHA1=y CONFIG_RDS=m CONFIG_RDS_TCP=m CONFIG_L2TP=m +CONFIG_BRIDGE=m CONFIG_ATALK=m +CONFIG_6LOWPAN=m CONFIG_DNS_RESOLVER=y CONFIG_BATMAN_ADV=m CONFIG_BATMAN_ADV_DAT=y @@ -230,9 +267,10 @@ CONFIG_BATMAN_ADV_MCAST=y CONFIG_NETLINK_DIAG=m CONFIG_NET_MPLS_GSO=m # CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set -# CONFIG_FW_LOADER_USER_HELPER is not set CONFIG_CONNECTOR=m CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=m @@ -281,6 +319,9 @@ CONFIG_NET_TEAM_MODE_ROUNDROBIN=m CONFIG_NET_TEAM_MODE_RANDOM=m CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -291,6 +332,8 @@ CONFIG_VETH=m # CONFIG_NET_VENDOR_MARVELL is not set # CONFIG_NET_VENDOR_MICREL is not set # CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set # CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set # CONFIG_NET_VENDOR_STMICRO is not set @@ -332,6 +375,7 @@ CONFIG_HID=m CONFIG_HIDRAW=y CONFIG_UHID=m # CONFIG_HID_GENERIC is not set +# CONFIG_HID_PLANTRONICS is not set # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_GENERIC=m @@ -350,6 +394,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -365,6 +410,7 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_CRAMFS=m CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZO=y CONFIG_MINIX_FS=m CONFIG_OMFS_FS=m @@ -434,10 +480,18 @@ CONFIG_DLM=m CONFIG_MAGIC_SYSRQ=y CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_STRING_HELPERS=m +CONFIG_TEST_KSTRTOX=m +CONFIG_TEST_LKM=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_UDELAY=m +CONFIG_EARLY_PRINTK=y CONFIG_ENCRYPTED_KEYS=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m @@ -472,13 +526,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m # CONFIG_CRYPTO_HW is not set -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_XZ_DEC_TEST=m diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig index 391e185d73be..372593a3b398 100644 --- a/arch/m68k/configs/atari_defconfig +++ b/arch/m68k/configs/atari_defconfig @@ -31,8 +31,10 @@ CONFIG_M68030=y CONFIG_M68040=y CONFIG_M68060=y CONFIG_ATARI=y +CONFIG_ATARI_ROM_ISA=y # CONFIG_COMPACTION is not set CONFIG_CLEANCACHE=y +CONFIG_ZPOOL=m # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_AOUT=m CONFIG_BINFMT_MISC=m @@ -52,6 +54,8 @@ CONFIG_NET_IPIP=m CONFIG_NET_IPGRE_DEMUX=m CONFIG_NET_IPGRE=m CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_GENEVE=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -93,6 +97,8 @@ CONFIG_NFT_HASH=m CONFIG_NFT_COUNTER=m CONFIG_NFT_LOG=m CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m CONFIG_NFT_NAT=m CONFIG_NFT_QUEUE=m CONFIG_NFT_REJECT=m @@ -139,6 +145,7 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=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 @@ -160,6 +167,7 @@ CONFIG_IP_SET_HASH_IPMARK=m CONFIG_IP_SET_HASH_IPPORT=m CONFIG_IP_SET_HASH_IPPORTIP=m CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_MAC=m CONFIG_IP_SET_HASH_NETPORTNET=m CONFIG_IP_SET_HASH_NET=m CONFIG_IP_SET_HASH_NETNET=m @@ -167,9 +175,12 @@ CONFIG_IP_SET_HASH_NETPORT=m CONFIG_IP_SET_HASH_NETIFACE=m CONFIG_IP_SET_LIST_SET=m CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_LOG_ARP=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m -CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NFT_MASQ_IPV4=m +CONFIG_NFT_REDIR_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -178,8 +189,7 @@ CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m +CONFIG_IP_NF_NAT=m CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_REDIRECT=m @@ -194,6 +204,8 @@ CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NFT_MASQ_IPV6=m +CONFIG_NFT_REDIR_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -210,17 +222,43 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_TARGET_SYNPROXY=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m -CONFIG_NF_NAT_IPV6=m +CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_LOG_BRIDGE=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_NFLOG=m CONFIG_IP_DCCP=m # CONFIG_IP_DCCP_CCID3 is not set CONFIG_SCTP_COOKIE_HMAC_SHA1=y CONFIG_RDS=m CONFIG_RDS_TCP=m CONFIG_L2TP=m +CONFIG_BRIDGE=m CONFIG_ATALK=m +CONFIG_6LOWPAN=m CONFIG_DNS_RESOLVER=y CONFIG_BATMAN_ADV=m CONFIG_BATMAN_ADV_DAT=y @@ -229,9 +267,10 @@ CONFIG_BATMAN_ADV_MCAST=y CONFIG_NETLINK_DIAG=m CONFIG_NET_MPLS_GSO=m # CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set -# CONFIG_FW_LOADER_USER_HELPER is not set CONFIG_CONNECTOR=m CONFIG_PARPORT=m CONFIG_PARPORT_ATARI=m @@ -289,6 +328,9 @@ CONFIG_NET_TEAM_MODE_ROUNDROBIN=m CONFIG_NET_TEAM_MODE_RANDOM=m CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -299,8 +341,12 @@ CONFIG_ATARILANCE=y # CONFIG_NET_VENDOR_INTEL is not set # CONFIG_NET_VENDOR_MARVELL is not set # CONFIG_NET_VENDOR_MICREL is not set +CONFIG_NE2000=y +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set # CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set +CONFIG_SMC91X=y # CONFIG_NET_VENDOR_STMICRO is not set # CONFIG_NET_VENDOR_VIA is not set # CONFIG_NET_VENDOR_WIZNET is not set @@ -345,6 +391,7 @@ CONFIG_DMASOUND_ATARI=m CONFIG_HID=m CONFIG_HIDRAW=y CONFIG_UHID=m +# CONFIG_HID_PLANTRONICS is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_GENERIC=m # CONFIG_IOMMU_SUPPORT is not set @@ -354,6 +401,8 @@ CONFIG_NATFEAT=y CONFIG_NFBLOCK=y CONFIG_NFCON=y CONFIG_NFETH=y +CONFIG_ATARI_ETHERNAT=y +CONFIG_ATARI_ETHERNEC=y CONFIG_ATARI_DSP56K=m CONFIG_EXT4_FS=y CONFIG_REISERFS_FS=m @@ -367,6 +416,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -382,6 +432,7 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_CRAMFS=m CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZO=y CONFIG_MINIX_FS=m CONFIG_OMFS_FS=m @@ -451,10 +502,18 @@ CONFIG_DLM=m CONFIG_MAGIC_SYSRQ=y CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_STRING_HELPERS=m +CONFIG_TEST_KSTRTOX=m +CONFIG_TEST_LKM=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_UDELAY=m +CONFIG_EARLY_PRINTK=y CONFIG_ENCRYPTED_KEYS=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m @@ -489,13 +548,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m # CONFIG_CRYPTO_HW is not set -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_XZ_DEC_TEST=m diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig index d0e705d1a063..f3bd35e76ea4 100644 --- a/arch/m68k/configs/bvme6000_defconfig +++ b/arch/m68k/configs/bvme6000_defconfig @@ -32,6 +32,7 @@ CONFIG_VME=y CONFIG_BVME6000=y # CONFIG_COMPACTION is not set CONFIG_CLEANCACHE=y +CONFIG_ZPOOL=m # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_AOUT=m CONFIG_BINFMT_MISC=m @@ -51,6 +52,8 @@ CONFIG_NET_IPIP=m CONFIG_NET_IPGRE_DEMUX=m CONFIG_NET_IPGRE=m CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_GENEVE=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -92,6 +95,8 @@ CONFIG_NFT_HASH=m CONFIG_NFT_COUNTER=m CONFIG_NFT_LOG=m CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m CONFIG_NFT_NAT=m CONFIG_NFT_QUEUE=m CONFIG_NFT_REJECT=m @@ -138,6 +143,7 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=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 @@ -159,6 +165,7 @@ CONFIG_IP_SET_HASH_IPMARK=m CONFIG_IP_SET_HASH_IPPORT=m CONFIG_IP_SET_HASH_IPPORTIP=m CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_MAC=m CONFIG_IP_SET_HASH_NETPORTNET=m CONFIG_IP_SET_HASH_NET=m CONFIG_IP_SET_HASH_NETNET=m @@ -166,9 +173,12 @@ CONFIG_IP_SET_HASH_NETPORT=m CONFIG_IP_SET_HASH_NETIFACE=m CONFIG_IP_SET_LIST_SET=m CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_LOG_ARP=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m -CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NFT_MASQ_IPV4=m +CONFIG_NFT_REDIR_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -177,8 +187,7 @@ CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m +CONFIG_IP_NF_NAT=m CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_REDIRECT=m @@ -193,6 +202,8 @@ CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NFT_MASQ_IPV6=m +CONFIG_NFT_REDIR_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -209,17 +220,43 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_TARGET_SYNPROXY=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m -CONFIG_NF_NAT_IPV6=m +CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_LOG_BRIDGE=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_NFLOG=m CONFIG_IP_DCCP=m # CONFIG_IP_DCCP_CCID3 is not set CONFIG_SCTP_COOKIE_HMAC_SHA1=y CONFIG_RDS=m CONFIG_RDS_TCP=m CONFIG_L2TP=m +CONFIG_BRIDGE=m CONFIG_ATALK=m +CONFIG_6LOWPAN=m CONFIG_DNS_RESOLVER=y CONFIG_BATMAN_ADV=m CONFIG_BATMAN_ADV_DAT=y @@ -228,9 +265,10 @@ CONFIG_BATMAN_ADV_MCAST=y CONFIG_NETLINK_DIAG=m CONFIG_NET_MPLS_GSO=m # CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set -# CONFIG_FW_LOADER_USER_HELPER is not set CONFIG_CONNECTOR=m CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=m @@ -280,6 +318,9 @@ CONFIG_NET_TEAM_MODE_ROUNDROBIN=m CONFIG_NET_TEAM_MODE_RANDOM=m CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -290,6 +331,8 @@ CONFIG_BVME6000_NET=y # CONFIG_NET_VENDOR_MARVELL is not set # CONFIG_NET_VENDOR_MICREL is not set # CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set # CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set # CONFIG_NET_VENDOR_STMICRO is not set @@ -326,6 +369,7 @@ CONFIG_HID=m CONFIG_HIDRAW=y CONFIG_UHID=m # CONFIG_HID_GENERIC is not set +# CONFIG_HID_PLANTRONICS is not set # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_GENERIC=m @@ -343,6 +387,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -358,6 +403,7 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_CRAMFS=m CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZO=y CONFIG_MINIX_FS=m CONFIG_OMFS_FS=m @@ -427,10 +473,18 @@ CONFIG_DLM=m CONFIG_MAGIC_SYSRQ=y CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_STRING_HELPERS=m +CONFIG_TEST_KSTRTOX=m +CONFIG_TEST_LKM=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_UDELAY=m +CONFIG_EARLY_PRINTK=y CONFIG_ENCRYPTED_KEYS=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m @@ -465,13 +519,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m # CONFIG_CRYPTO_HW is not set -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_XZ_DEC_TEST=m diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig index fdc7e9672249..9f9793fb2b73 100644 --- a/arch/m68k/configs/hp300_defconfig +++ b/arch/m68k/configs/hp300_defconfig @@ -34,6 +34,7 @@ CONFIG_M68060=y CONFIG_HP300=y # CONFIG_COMPACTION is not set CONFIG_CLEANCACHE=y +CONFIG_ZPOOL=m # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_AOUT=m CONFIG_BINFMT_MISC=m @@ -53,6 +54,8 @@ CONFIG_NET_IPIP=m CONFIG_NET_IPGRE_DEMUX=m CONFIG_NET_IPGRE=m CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_GENEVE=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -94,6 +97,8 @@ CONFIG_NFT_HASH=m CONFIG_NFT_COUNTER=m CONFIG_NFT_LOG=m CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m CONFIG_NFT_NAT=m CONFIG_NFT_QUEUE=m CONFIG_NFT_REJECT=m @@ -140,6 +145,7 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=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 @@ -161,6 +167,7 @@ CONFIG_IP_SET_HASH_IPMARK=m CONFIG_IP_SET_HASH_IPPORT=m CONFIG_IP_SET_HASH_IPPORTIP=m CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_MAC=m CONFIG_IP_SET_HASH_NETPORTNET=m CONFIG_IP_SET_HASH_NET=m CONFIG_IP_SET_HASH_NETNET=m @@ -168,9 +175,12 @@ CONFIG_IP_SET_HASH_NETPORT=m CONFIG_IP_SET_HASH_NETIFACE=m CONFIG_IP_SET_LIST_SET=m CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_LOG_ARP=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m -CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NFT_MASQ_IPV4=m +CONFIG_NFT_REDIR_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -179,8 +189,7 @@ CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m +CONFIG_IP_NF_NAT=m CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_REDIRECT=m @@ -195,6 +204,8 @@ CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NFT_MASQ_IPV6=m +CONFIG_NFT_REDIR_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -211,17 +222,43 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_TARGET_SYNPROXY=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m -CONFIG_NF_NAT_IPV6=m +CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_LOG_BRIDGE=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_NFLOG=m CONFIG_IP_DCCP=m # CONFIG_IP_DCCP_CCID3 is not set CONFIG_SCTP_COOKIE_HMAC_SHA1=y CONFIG_RDS=m CONFIG_RDS_TCP=m CONFIG_L2TP=m +CONFIG_BRIDGE=m CONFIG_ATALK=m +CONFIG_6LOWPAN=m CONFIG_DNS_RESOLVER=y CONFIG_BATMAN_ADV=m CONFIG_BATMAN_ADV_DAT=y @@ -230,9 +267,10 @@ CONFIG_BATMAN_ADV_MCAST=y CONFIG_NETLINK_DIAG=m CONFIG_NET_MPLS_GSO=m # CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set -# CONFIG_FW_LOADER_USER_HELPER is not set CONFIG_CONNECTOR=m CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=m @@ -281,6 +319,9 @@ CONFIG_NET_TEAM_MODE_ROUNDROBIN=m CONFIG_NET_TEAM_MODE_RANDOM=m CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -292,6 +333,8 @@ CONFIG_HPLANCE=y # CONFIG_NET_VENDOR_MARVELL is not set # CONFIG_NET_VENDOR_MICREL is not set # CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set # CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set # CONFIG_NET_VENDOR_STMICRO is not set @@ -335,6 +378,7 @@ CONFIG_HID=m CONFIG_HIDRAW=y CONFIG_UHID=m # CONFIG_HID_GENERIC is not set +# CONFIG_HID_PLANTRONICS is not set # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_GENERIC=m @@ -352,6 +396,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -367,6 +412,7 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_CRAMFS=m CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZO=y CONFIG_MINIX_FS=m CONFIG_OMFS_FS=m @@ -436,10 +482,18 @@ CONFIG_DLM=m CONFIG_MAGIC_SYSRQ=y CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_STRING_HELPERS=m +CONFIG_TEST_KSTRTOX=m +CONFIG_TEST_LKM=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_UDELAY=m +CONFIG_EARLY_PRINTK=y CONFIG_ENCRYPTED_KEYS=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m @@ -474,13 +528,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m # CONFIG_CRYPTO_HW is not set -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_XZ_DEC_TEST=m diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig index 3d345641d5a0..89f225c01a0b 100644 --- a/arch/m68k/configs/mac_defconfig +++ b/arch/m68k/configs/mac_defconfig @@ -33,6 +33,7 @@ CONFIG_M68KFPU_EMU=y CONFIG_MAC=y # CONFIG_COMPACTION is not set CONFIG_CLEANCACHE=y +CONFIG_ZPOOL=m # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_AOUT=m CONFIG_BINFMT_MISC=m @@ -52,6 +53,8 @@ CONFIG_NET_IPIP=m CONFIG_NET_IPGRE_DEMUX=m CONFIG_NET_IPGRE=m CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_GENEVE=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -93,6 +96,8 @@ CONFIG_NFT_HASH=m CONFIG_NFT_COUNTER=m CONFIG_NFT_LOG=m CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m CONFIG_NFT_NAT=m CONFIG_NFT_QUEUE=m CONFIG_NFT_REJECT=m @@ -139,6 +144,7 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=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 @@ -160,6 +166,7 @@ CONFIG_IP_SET_HASH_IPMARK=m CONFIG_IP_SET_HASH_IPPORT=m CONFIG_IP_SET_HASH_IPPORTIP=m CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_MAC=m CONFIG_IP_SET_HASH_NETPORTNET=m CONFIG_IP_SET_HASH_NET=m CONFIG_IP_SET_HASH_NETNET=m @@ -167,9 +174,12 @@ CONFIG_IP_SET_HASH_NETPORT=m CONFIG_IP_SET_HASH_NETIFACE=m CONFIG_IP_SET_LIST_SET=m CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_LOG_ARP=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m -CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NFT_MASQ_IPV4=m +CONFIG_NFT_REDIR_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -178,8 +188,7 @@ CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m +CONFIG_IP_NF_NAT=m CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_REDIRECT=m @@ -194,6 +203,8 @@ CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NFT_MASQ_IPV6=m +CONFIG_NFT_REDIR_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -210,20 +221,46 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_TARGET_SYNPROXY=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m -CONFIG_NF_NAT_IPV6=m +CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_LOG_BRIDGE=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_NFLOG=m CONFIG_IP_DCCP=m # CONFIG_IP_DCCP_CCID3 is not set CONFIG_SCTP_COOKIE_HMAC_SHA1=y CONFIG_RDS=m CONFIG_RDS_TCP=m CONFIG_L2TP=m +CONFIG_BRIDGE=m CONFIG_ATALK=m CONFIG_DEV_APPLETALK=m CONFIG_IPDDP=m CONFIG_IPDDP_ENCAP=y +CONFIG_6LOWPAN=m CONFIG_DNS_RESOLVER=y CONFIG_BATMAN_ADV=m CONFIG_BATMAN_ADV_DAT=y @@ -232,9 +269,10 @@ CONFIG_BATMAN_ADV_MCAST=y CONFIG_NETLINK_DIAG=m CONFIG_NET_MPLS_GSO=m # CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set -# CONFIG_FW_LOADER_USER_HELPER is not set CONFIG_CONNECTOR=m CONFIG_BLK_DEV_SWIM=m CONFIG_BLK_DEV_LOOP=y @@ -297,6 +335,9 @@ CONFIG_NET_TEAM_MODE_ROUNDROBIN=m CONFIG_NET_TEAM_MODE_RANDOM=m CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -310,6 +351,8 @@ CONFIG_MAC89x0=y # CONFIG_NET_VENDOR_MICREL is not set CONFIG_MACSONIC=y CONFIG_MAC8390=y +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set # CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set # CONFIG_NET_VENDOR_SMSC is not set @@ -357,6 +400,7 @@ CONFIG_HID=m CONFIG_HIDRAW=y CONFIG_UHID=m # CONFIG_HID_GENERIC is not set +# CONFIG_HID_PLANTRONICS is not set # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_GENERIC=m @@ -374,6 +418,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -389,6 +434,7 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_CRAMFS=m CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZO=y CONFIG_MINIX_FS=m CONFIG_OMFS_FS=m @@ -458,11 +504,18 @@ CONFIG_DLM=m CONFIG_MAGIC_SYSRQ=y CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_STRING_HELPERS=m +CONFIG_TEST_KSTRTOX=m +CONFIG_TEST_LKM=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_UDELAY=m CONFIG_EARLY_PRINTK=y CONFIG_ENCRYPTED_KEYS=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m @@ -497,13 +550,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m # CONFIG_CRYPTO_HW is not set -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_XZ_DEC_TEST=m diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig index 59aa42096000..d3cdb5447a2c 100644 --- a/arch/m68k/configs/multi_defconfig +++ b/arch/m68k/configs/multi_defconfig @@ -39,9 +39,11 @@ CONFIG_SUN3X=y CONFIG_Q40=y CONFIG_ZORRO=y CONFIG_AMIGA_PCMCIA=y +CONFIG_ATARI_ROM_ISA=y CONFIG_ZORRO_NAMES=y # CONFIG_COMPACTION is not set CONFIG_CLEANCACHE=y +CONFIG_ZPOOL=m # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_AOUT=m CONFIG_BINFMT_MISC=m @@ -61,6 +63,8 @@ CONFIG_NET_IPIP=m CONFIG_NET_IPGRE_DEMUX=m CONFIG_NET_IPGRE=m CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_GENEVE=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -102,6 +106,8 @@ CONFIG_NFT_HASH=m CONFIG_NFT_COUNTER=m CONFIG_NFT_LOG=m CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m CONFIG_NFT_NAT=m CONFIG_NFT_QUEUE=m CONFIG_NFT_REJECT=m @@ -148,6 +154,7 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=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 @@ -169,6 +176,7 @@ CONFIG_IP_SET_HASH_IPMARK=m CONFIG_IP_SET_HASH_IPPORT=m CONFIG_IP_SET_HASH_IPPORTIP=m CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_MAC=m CONFIG_IP_SET_HASH_NETPORTNET=m CONFIG_IP_SET_HASH_NET=m CONFIG_IP_SET_HASH_NETNET=m @@ -176,9 +184,12 @@ CONFIG_IP_SET_HASH_NETPORT=m CONFIG_IP_SET_HASH_NETIFACE=m CONFIG_IP_SET_LIST_SET=m CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_LOG_ARP=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m -CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NFT_MASQ_IPV4=m +CONFIG_NFT_REDIR_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -187,8 +198,7 @@ CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m +CONFIG_IP_NF_NAT=m CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_REDIRECT=m @@ -203,6 +213,8 @@ CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NFT_MASQ_IPV6=m +CONFIG_NFT_REDIR_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -219,20 +231,46 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_TARGET_SYNPROXY=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m -CONFIG_NF_NAT_IPV6=m +CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_LOG_BRIDGE=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_NFLOG=m CONFIG_IP_DCCP=m # CONFIG_IP_DCCP_CCID3 is not set CONFIG_SCTP_COOKIE_HMAC_SHA1=y CONFIG_RDS=m CONFIG_RDS_TCP=m CONFIG_L2TP=m +CONFIG_BRIDGE=m CONFIG_ATALK=m CONFIG_DEV_APPLETALK=m CONFIG_IPDDP=m CONFIG_IPDDP_ENCAP=y +CONFIG_6LOWPAN=m CONFIG_DNS_RESOLVER=y CONFIG_BATMAN_ADV=m CONFIG_BATMAN_ADV_DAT=y @@ -241,9 +279,10 @@ CONFIG_BATMAN_ADV_MCAST=y CONFIG_NETLINK_DIAG=m CONFIG_NET_MPLS_GSO=m # CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set -# CONFIG_FW_LOADER_USER_HELPER is not set CONFIG_CONNECTOR=m CONFIG_PARPORT=m CONFIG_PARPORT_PC=m @@ -329,6 +368,9 @@ CONFIG_NET_TEAM_MODE_ROUNDROBIN=m CONFIG_NET_TEAM_MODE_RANDOM=m CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -352,11 +394,14 @@ CONFIG_MVME16x_NET=y CONFIG_MACSONIC=y CONFIG_HYDRA=y CONFIG_MAC8390=y -CONFIG_NE2000=m +CONFIG_NE2000=y CONFIG_APNE=y CONFIG_ZORRO8390=y +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set # CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set +CONFIG_SMC91X=y # CONFIG_NET_VENDOR_STMICRO is not set # CONFIG_NET_VENDOR_VIA is not set # CONFIG_NET_VENDOR_WIZNET is not set @@ -423,6 +468,7 @@ CONFIG_HID=m CONFIG_HIDRAW=y CONFIG_UHID=m # CONFIG_HID_GENERIC is not set +# CONFIG_HID_PLANTRONICS is not set # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_MSM6242=m @@ -435,6 +481,8 @@ CONFIG_NATFEAT=y CONFIG_NFBLOCK=y CONFIG_NFCON=y CONFIG_NFETH=y +CONFIG_ATARI_ETHERNAT=y +CONFIG_ATARI_ETHERNEC=y CONFIG_ATARI_DSP56K=m CONFIG_AMIGA_BUILTIN_SERIAL=y CONFIG_SERIAL_CONSOLE=y @@ -450,6 +498,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -465,6 +514,7 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_CRAMFS=m CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZO=y CONFIG_MINIX_FS=m CONFIG_OMFS_FS=m @@ -534,11 +584,18 @@ CONFIG_DLM=m CONFIG_MAGIC_SYSRQ=y CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_STRING_HELPERS=m +CONFIG_TEST_KSTRTOX=m +CONFIG_TEST_LKM=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_UDELAY=m CONFIG_EARLY_PRINTK=y CONFIG_ENCRYPTED_KEYS=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m @@ -573,13 +630,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m # CONFIG_CRYPTO_HW is not set -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_XZ_DEC_TEST=m diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig index 066b24af095e..b4c76640973e 100644 --- a/arch/m68k/configs/mvme147_defconfig +++ b/arch/m68k/configs/mvme147_defconfig @@ -31,6 +31,7 @@ CONFIG_VME=y CONFIG_MVME147=y # CONFIG_COMPACTION is not set CONFIG_CLEANCACHE=y +CONFIG_ZPOOL=m # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_AOUT=m CONFIG_BINFMT_MISC=m @@ -50,6 +51,8 @@ CONFIG_NET_IPIP=m CONFIG_NET_IPGRE_DEMUX=m CONFIG_NET_IPGRE=m CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_GENEVE=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -91,6 +94,8 @@ CONFIG_NFT_HASH=m CONFIG_NFT_COUNTER=m CONFIG_NFT_LOG=m CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m CONFIG_NFT_NAT=m CONFIG_NFT_QUEUE=m CONFIG_NFT_REJECT=m @@ -137,6 +142,7 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=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 @@ -158,6 +164,7 @@ CONFIG_IP_SET_HASH_IPMARK=m CONFIG_IP_SET_HASH_IPPORT=m CONFIG_IP_SET_HASH_IPPORTIP=m CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_MAC=m CONFIG_IP_SET_HASH_NETPORTNET=m CONFIG_IP_SET_HASH_NET=m CONFIG_IP_SET_HASH_NETNET=m @@ -165,9 +172,12 @@ CONFIG_IP_SET_HASH_NETPORT=m CONFIG_IP_SET_HASH_NETIFACE=m CONFIG_IP_SET_LIST_SET=m CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_LOG_ARP=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m -CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NFT_MASQ_IPV4=m +CONFIG_NFT_REDIR_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -176,8 +186,7 @@ CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m +CONFIG_IP_NF_NAT=m CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_REDIRECT=m @@ -192,6 +201,8 @@ CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NFT_MASQ_IPV6=m +CONFIG_NFT_REDIR_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -208,17 +219,43 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_TARGET_SYNPROXY=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m -CONFIG_NF_NAT_IPV6=m +CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_LOG_BRIDGE=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_NFLOG=m CONFIG_IP_DCCP=m # CONFIG_IP_DCCP_CCID3 is not set CONFIG_SCTP_COOKIE_HMAC_SHA1=y CONFIG_RDS=m CONFIG_RDS_TCP=m CONFIG_L2TP=m +CONFIG_BRIDGE=m CONFIG_ATALK=m +CONFIG_6LOWPAN=m CONFIG_DNS_RESOLVER=y CONFIG_BATMAN_ADV=m CONFIG_BATMAN_ADV_DAT=y @@ -227,9 +264,10 @@ CONFIG_BATMAN_ADV_MCAST=y CONFIG_NETLINK_DIAG=m CONFIG_NET_MPLS_GSO=m # CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set -# CONFIG_FW_LOADER_USER_HELPER is not set CONFIG_CONNECTOR=m CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=m @@ -279,6 +317,9 @@ CONFIG_NET_TEAM_MODE_ROUNDROBIN=m CONFIG_NET_TEAM_MODE_RANDOM=m CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -290,6 +331,8 @@ CONFIG_MVME147_NET=y # CONFIG_NET_VENDOR_MARVELL is not set # CONFIG_NET_VENDOR_MICREL is not set # CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set # CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set # CONFIG_NET_VENDOR_STMICRO is not set @@ -326,6 +369,7 @@ CONFIG_HID=m CONFIG_HIDRAW=y CONFIG_UHID=m # CONFIG_HID_GENERIC is not set +# CONFIG_HID_PLANTRONICS is not set # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_GENERIC=m @@ -343,6 +387,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -358,6 +403,7 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_CRAMFS=m CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZO=y CONFIG_MINIX_FS=m CONFIG_OMFS_FS=m @@ -427,10 +473,18 @@ CONFIG_DLM=m CONFIG_MAGIC_SYSRQ=y CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_STRING_HELPERS=m +CONFIG_TEST_KSTRTOX=m +CONFIG_TEST_LKM=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_UDELAY=m +CONFIG_EARLY_PRINTK=y CONFIG_ENCRYPTED_KEYS=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m @@ -465,13 +519,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m # CONFIG_CRYPTO_HW is not set -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_XZ_DEC_TEST=m diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig index 9326ea664a5b..0d4a26f9b58c 100644 --- a/arch/m68k/configs/mvme16x_defconfig +++ b/arch/m68k/configs/mvme16x_defconfig @@ -32,6 +32,7 @@ CONFIG_VME=y CONFIG_MVME16x=y # CONFIG_COMPACTION is not set CONFIG_CLEANCACHE=y +CONFIG_ZPOOL=m # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_AOUT=m CONFIG_BINFMT_MISC=m @@ -51,6 +52,8 @@ CONFIG_NET_IPIP=m CONFIG_NET_IPGRE_DEMUX=m CONFIG_NET_IPGRE=m CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_GENEVE=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -92,6 +95,8 @@ CONFIG_NFT_HASH=m CONFIG_NFT_COUNTER=m CONFIG_NFT_LOG=m CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m CONFIG_NFT_NAT=m CONFIG_NFT_QUEUE=m CONFIG_NFT_REJECT=m @@ -138,6 +143,7 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=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 @@ -159,6 +165,7 @@ CONFIG_IP_SET_HASH_IPMARK=m CONFIG_IP_SET_HASH_IPPORT=m CONFIG_IP_SET_HASH_IPPORTIP=m CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_MAC=m CONFIG_IP_SET_HASH_NETPORTNET=m CONFIG_IP_SET_HASH_NET=m CONFIG_IP_SET_HASH_NETNET=m @@ -166,9 +173,12 @@ CONFIG_IP_SET_HASH_NETPORT=m CONFIG_IP_SET_HASH_NETIFACE=m CONFIG_IP_SET_LIST_SET=m CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_LOG_ARP=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m -CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NFT_MASQ_IPV4=m +CONFIG_NFT_REDIR_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -177,8 +187,7 @@ CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m +CONFIG_IP_NF_NAT=m CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_REDIRECT=m @@ -193,6 +202,8 @@ CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NFT_MASQ_IPV6=m +CONFIG_NFT_REDIR_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -209,17 +220,43 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_TARGET_SYNPROXY=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m -CONFIG_NF_NAT_IPV6=m +CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_LOG_BRIDGE=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_NFLOG=m CONFIG_IP_DCCP=m # CONFIG_IP_DCCP_CCID3 is not set CONFIG_SCTP_COOKIE_HMAC_SHA1=y CONFIG_RDS=m CONFIG_RDS_TCP=m CONFIG_L2TP=m +CONFIG_BRIDGE=m CONFIG_ATALK=m +CONFIG_6LOWPAN=m CONFIG_DNS_RESOLVER=y CONFIG_BATMAN_ADV=m CONFIG_BATMAN_ADV_DAT=y @@ -228,9 +265,10 @@ CONFIG_BATMAN_ADV_MCAST=y CONFIG_NETLINK_DIAG=m CONFIG_NET_MPLS_GSO=m # CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set -# CONFIG_FW_LOADER_USER_HELPER is not set CONFIG_CONNECTOR=m CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=m @@ -280,6 +318,9 @@ CONFIG_NET_TEAM_MODE_ROUNDROBIN=m CONFIG_NET_TEAM_MODE_RANDOM=m CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -290,6 +331,8 @@ CONFIG_MVME16x_NET=y # CONFIG_NET_VENDOR_MARVELL is not set # CONFIG_NET_VENDOR_MICREL is not set # CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set # CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set # CONFIG_NET_VENDOR_STMICRO is not set @@ -326,6 +369,7 @@ CONFIG_HID=m CONFIG_HIDRAW=y CONFIG_UHID=m # CONFIG_HID_GENERIC is not set +# CONFIG_HID_PLANTRONICS is not set # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_GENERIC=m @@ -343,6 +387,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -358,6 +403,7 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_CRAMFS=m CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZO=y CONFIG_MINIX_FS=m CONFIG_OMFS_FS=m @@ -427,11 +473,18 @@ CONFIG_DLM=m CONFIG_MAGIC_SYSRQ=y CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_STRING_HELPERS=m +CONFIG_TEST_KSTRTOX=m +CONFIG_TEST_LKM=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_UDELAY=m CONFIG_EARLY_PRINTK=y CONFIG_ENCRYPTED_KEYS=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m @@ -466,13 +519,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m # CONFIG_CRYPTO_HW is not set -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_XZ_DEC_TEST=m diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig index d7d1101e31b5..5d581c503fa3 100644 --- a/arch/m68k/configs/q40_defconfig +++ b/arch/m68k/configs/q40_defconfig @@ -32,6 +32,7 @@ CONFIG_M68060=y CONFIG_Q40=y # CONFIG_COMPACTION is not set CONFIG_CLEANCACHE=y +CONFIG_ZPOOL=m # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_AOUT=m CONFIG_BINFMT_MISC=m @@ -51,6 +52,8 @@ CONFIG_NET_IPIP=m CONFIG_NET_IPGRE_DEMUX=m CONFIG_NET_IPGRE=m CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_GENEVE=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -92,6 +95,8 @@ CONFIG_NFT_HASH=m CONFIG_NFT_COUNTER=m CONFIG_NFT_LOG=m CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m CONFIG_NFT_NAT=m CONFIG_NFT_QUEUE=m CONFIG_NFT_REJECT=m @@ -138,6 +143,7 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=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 @@ -159,6 +165,7 @@ CONFIG_IP_SET_HASH_IPMARK=m CONFIG_IP_SET_HASH_IPPORT=m CONFIG_IP_SET_HASH_IPPORTIP=m CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_MAC=m CONFIG_IP_SET_HASH_NETPORTNET=m CONFIG_IP_SET_HASH_NET=m CONFIG_IP_SET_HASH_NETNET=m @@ -166,9 +173,12 @@ CONFIG_IP_SET_HASH_NETPORT=m CONFIG_IP_SET_HASH_NETIFACE=m CONFIG_IP_SET_LIST_SET=m CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_LOG_ARP=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m -CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NFT_MASQ_IPV4=m +CONFIG_NFT_REDIR_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -177,8 +187,7 @@ CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m +CONFIG_IP_NF_NAT=m CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_REDIRECT=m @@ -193,6 +202,8 @@ CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NFT_MASQ_IPV6=m +CONFIG_NFT_REDIR_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -209,17 +220,43 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_TARGET_SYNPROXY=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m -CONFIG_NF_NAT_IPV6=m +CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_LOG_BRIDGE=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_NFLOG=m CONFIG_IP_DCCP=m # CONFIG_IP_DCCP_CCID3 is not set CONFIG_SCTP_COOKIE_HMAC_SHA1=y CONFIG_RDS=m CONFIG_RDS_TCP=m CONFIG_L2TP=m +CONFIG_BRIDGE=m CONFIG_ATALK=m +CONFIG_6LOWPAN=m CONFIG_DNS_RESOLVER=y CONFIG_BATMAN_ADV=m CONFIG_BATMAN_ADV_DAT=y @@ -228,9 +265,10 @@ CONFIG_BATMAN_ADV_MCAST=y CONFIG_NETLINK_DIAG=m CONFIG_NET_MPLS_GSO=m # CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set -# CONFIG_FW_LOADER_USER_HELPER is not set CONFIG_CONNECTOR=m CONFIG_PARPORT=m CONFIG_PARPORT_PC=m @@ -286,6 +324,9 @@ CONFIG_NET_TEAM_MODE_ROUNDROBIN=m CONFIG_NET_TEAM_MODE_RANDOM=m CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -300,6 +341,8 @@ CONFIG_VETH=m # CONFIG_NET_VENDOR_MARVELL is not set # CONFIG_NET_VENDOR_MICREL is not set CONFIG_NE2000=m +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set # CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set # CONFIG_NET_VENDOR_SMSC is not set @@ -347,6 +390,7 @@ CONFIG_HID=m CONFIG_HIDRAW=y CONFIG_UHID=m # CONFIG_HID_GENERIC is not set +# CONFIG_HID_PLANTRONICS is not set # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_GENERIC=m @@ -365,6 +409,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -380,6 +425,7 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_CRAMFS=m CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZO=y CONFIG_MINIX_FS=m CONFIG_OMFS_FS=m @@ -449,10 +495,18 @@ CONFIG_DLM=m CONFIG_MAGIC_SYSRQ=y CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_STRING_HELPERS=m +CONFIG_TEST_KSTRTOX=m +CONFIG_TEST_LKM=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_UDELAY=m +CONFIG_EARLY_PRINTK=y CONFIG_ENCRYPTED_KEYS=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m @@ -487,13 +541,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m # CONFIG_CRYPTO_HW is not set -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_XZ_DEC_TEST=m diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig index 98522e8fb852..c6b49a4a887c 100644 --- a/arch/m68k/configs/sun3_defconfig +++ b/arch/m68k/configs/sun3_defconfig @@ -29,6 +29,7 @@ CONFIG_BOOTINFO_PROC=y CONFIG_SUN3=y # CONFIG_COMPACTION is not set CONFIG_CLEANCACHE=y +CONFIG_ZPOOL=m # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_AOUT=m CONFIG_BINFMT_MISC=m @@ -48,6 +49,8 @@ CONFIG_NET_IPIP=m CONFIG_NET_IPGRE_DEMUX=m CONFIG_NET_IPGRE=m CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_GENEVE=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -89,6 +92,8 @@ CONFIG_NFT_HASH=m CONFIG_NFT_COUNTER=m CONFIG_NFT_LOG=m CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m CONFIG_NFT_NAT=m CONFIG_NFT_QUEUE=m CONFIG_NFT_REJECT=m @@ -135,6 +140,7 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=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 @@ -156,6 +162,7 @@ CONFIG_IP_SET_HASH_IPMARK=m CONFIG_IP_SET_HASH_IPPORT=m CONFIG_IP_SET_HASH_IPPORTIP=m CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_MAC=m CONFIG_IP_SET_HASH_NETPORTNET=m CONFIG_IP_SET_HASH_NET=m CONFIG_IP_SET_HASH_NETNET=m @@ -163,9 +170,12 @@ CONFIG_IP_SET_HASH_NETPORT=m CONFIG_IP_SET_HASH_NETIFACE=m CONFIG_IP_SET_LIST_SET=m CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_LOG_ARP=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m -CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NFT_MASQ_IPV4=m +CONFIG_NFT_REDIR_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -174,8 +184,7 @@ CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m +CONFIG_IP_NF_NAT=m CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_REDIRECT=m @@ -190,6 +199,8 @@ CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NFT_MASQ_IPV6=m +CONFIG_NFT_REDIR_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -206,17 +217,43 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_TARGET_SYNPROXY=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m -CONFIG_NF_NAT_IPV6=m +CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_LOG_BRIDGE=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_NFLOG=m CONFIG_IP_DCCP=m # CONFIG_IP_DCCP_CCID3 is not set CONFIG_SCTP_COOKIE_HMAC_SHA1=y CONFIG_RDS=m CONFIG_RDS_TCP=m CONFIG_L2TP=m +CONFIG_BRIDGE=m CONFIG_ATALK=m +CONFIG_6LOWPAN=m CONFIG_DNS_RESOLVER=y CONFIG_BATMAN_ADV=m CONFIG_BATMAN_ADV_DAT=y @@ -225,9 +262,10 @@ CONFIG_BATMAN_ADV_MCAST=y CONFIG_NETLINK_DIAG=m CONFIG_NET_MPLS_GSO=m # CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set -# CONFIG_FW_LOADER_USER_HELPER is not set CONFIG_CONNECTOR=m CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=m @@ -277,6 +315,9 @@ CONFIG_NET_TEAM_MODE_ROUNDROBIN=m CONFIG_NET_TEAM_MODE_RANDOM=m CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -287,6 +328,8 @@ CONFIG_SUN3_82586=y # CONFIG_NET_VENDOR_MARVELL is not set # CONFIG_NET_VENDOR_MICREL is not set # CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set # CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set # CONFIG_NET_VENDOR_STMICRO is not set @@ -327,6 +370,7 @@ CONFIG_HID=m CONFIG_HIDRAW=y CONFIG_UHID=m # CONFIG_HID_GENERIC is not set +# CONFIG_HID_PLANTRONICS is not set # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_GENERIC=m @@ -344,6 +388,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -359,6 +404,7 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_CRAMFS=m CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZO=y CONFIG_MINIX_FS=m CONFIG_OMFS_FS=m @@ -428,10 +474,17 @@ CONFIG_DLM=m CONFIG_MAGIC_SYSRQ=y CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_STRING_HELPERS=m +CONFIG_TEST_KSTRTOX=m +CONFIG_TEST_LKM=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_UDELAY=m CONFIG_ENCRYPTED_KEYS=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m @@ -466,13 +519,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m # CONFIG_CRYPTO_HW is not set -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_XZ_DEC_TEST=m diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig index 5128a8c3f4e3..b65785eaff8d 100644 --- a/arch/m68k/configs/sun3x_defconfig +++ b/arch/m68k/configs/sun3x_defconfig @@ -29,6 +29,7 @@ CONFIG_BOOTINFO_PROC=y CONFIG_SUN3X=y # CONFIG_COMPACTION is not set CONFIG_CLEANCACHE=y +CONFIG_ZPOOL=m # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_AOUT=m CONFIG_BINFMT_MISC=m @@ -48,6 +49,8 @@ CONFIG_NET_IPIP=m CONFIG_NET_IPGRE_DEMUX=m CONFIG_NET_IPGRE=m CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_GENEVE=m CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m @@ -89,6 +92,8 @@ CONFIG_NFT_HASH=m CONFIG_NFT_COUNTER=m CONFIG_NFT_LOG=m CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m CONFIG_NFT_NAT=m CONFIG_NFT_QUEUE=m CONFIG_NFT_REJECT=m @@ -135,6 +140,7 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=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 @@ -156,6 +162,7 @@ CONFIG_IP_SET_HASH_IPMARK=m CONFIG_IP_SET_HASH_IPPORT=m CONFIG_IP_SET_HASH_IPPORTIP=m CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_MAC=m CONFIG_IP_SET_HASH_NETPORTNET=m CONFIG_IP_SET_HASH_NET=m CONFIG_IP_SET_HASH_NETNET=m @@ -163,9 +170,12 @@ CONFIG_IP_SET_HASH_NETPORT=m CONFIG_IP_SET_HASH_NETIFACE=m CONFIG_IP_SET_LIST_SET=m CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_LOG_ARP=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m -CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NFT_CHAIN_NAT_IPV4=m +CONFIG_NFT_MASQ_IPV4=m +CONFIG_NFT_REDIR_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -174,8 +184,7 @@ CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m +CONFIG_IP_NF_NAT=m CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_TARGET_REDIRECT=m @@ -190,6 +199,8 @@ CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NFT_MASQ_IPV6=m +CONFIG_NFT_REDIR_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -206,17 +217,43 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_TARGET_SYNPROXY=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m -CONFIG_NF_NAT_IPV6=m +CONFIG_IP6_NF_NAT=m CONFIG_IP6_NF_TARGET_MASQUERADE=m CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_LOG_BRIDGE=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_NFLOG=m CONFIG_IP_DCCP=m # CONFIG_IP_DCCP_CCID3 is not set CONFIG_SCTP_COOKIE_HMAC_SHA1=y CONFIG_RDS=m CONFIG_RDS_TCP=m CONFIG_L2TP=m +CONFIG_BRIDGE=m CONFIG_ATALK=m +CONFIG_6LOWPAN=m CONFIG_DNS_RESOLVER=y CONFIG_BATMAN_ADV=m CONFIG_BATMAN_ADV_DAT=y @@ -225,9 +262,10 @@ CONFIG_BATMAN_ADV_MCAST=y CONFIG_NETLINK_DIAG=m CONFIG_NET_MPLS_GSO=m # CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FIRMWARE_IN_KERNEL is not set -# CONFIG_FW_LOADER_USER_HELPER is not set CONFIG_CONNECTOR=m CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=m @@ -277,6 +315,9 @@ CONFIG_NET_TEAM_MODE_ROUNDROBIN=m CONFIG_NET_TEAM_MODE_RANDOM=m CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -288,6 +329,8 @@ CONFIG_SUN3LANCE=y # CONFIG_NET_VENDOR_MARVELL is not set # CONFIG_NET_VENDOR_MICREL is not set # CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set # CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set # CONFIG_NET_VENDOR_STMICRO is not set @@ -327,6 +370,7 @@ CONFIG_HID=m CONFIG_HIDRAW=y CONFIG_UHID=m # CONFIG_HID_GENERIC is not set +# CONFIG_HID_PLANTRONICS is not set # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_GENERIC=m @@ -344,6 +388,7 @@ CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -359,6 +404,7 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_CRAMFS=m CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZO=y CONFIG_MINIX_FS=m CONFIG_OMFS_FS=m @@ -428,10 +474,18 @@ CONFIG_DLM=m CONFIG_MAGIC_SYSRQ=y CONFIG_ASYNC_RAID6_TEST=m CONFIG_TEST_STRING_HELPERS=m +CONFIG_TEST_KSTRTOX=m +CONFIG_TEST_LKM=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_UDELAY=m +CONFIG_EARLY_PRINTK=y CONFIG_ENCRYPTED_KEYS=m CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_MCRYPTD=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m @@ -466,13 +520,10 @@ CONFIG_CRYPTO_LZO=m CONFIG_CRYPTO_LZ4=m CONFIG_CRYPTO_LZ4HC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m # CONFIG_CRYPTO_HW is not set -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_XZ_DEC_TEST=m diff --git a/arch/m68k/include/asm/Kbuild b/arch/m68k/include/asm/Kbuild index 9b6c691874bd..1517ed1c6471 100644 --- a/arch/m68k/include/asm/Kbuild +++ b/arch/m68k/include/asm/Kbuild @@ -6,6 +6,7 @@ generic-y += device.h generic-y += emergency-restart.h generic-y += errno.h generic-y += exec.h +generic-y += futex.h generic-y += hw_irq.h generic-y += ioctl.h generic-y += ipcbuf.h diff --git a/arch/m68k/include/asm/atariints.h b/arch/m68k/include/asm/atariints.h index 953e0ac6855e..6321c4495620 100644 --- a/arch/m68k/include/asm/atariints.h +++ b/arch/m68k/include/asm/atariints.h @@ -40,11 +40,6 @@ /* convert irq_handler index to vector number */ #define IRQ_SOURCE_TO_VECTOR(i) ((i) + ((i) < 8 ? 0x18 : (0x40-8))) -/* interrupt service types */ -#define IRQ_TYPE_SLOW 0 -#define IRQ_TYPE_FAST 1 -#define IRQ_TYPE_PRIO 2 - /* ST-MFP interrupts */ #define IRQ_MFP_BUSY (8) #define IRQ_MFP_DCD (9) diff --git a/arch/m68k/include/asm/futex.h b/arch/m68k/include/asm/futex.h deleted file mode 100644 index bc868af10c96..000000000000 --- a/arch/m68k/include/asm/futex.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef _ASM_M68K_FUTEX_H -#define _ASM_M68K_FUTEX_H - -#ifdef __KERNEL__ -#if !defined(CONFIG_MMU) -#include -#else /* CONFIG_MMU */ - -#include -#include -#include - -static inline int -futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, - u32 oldval, u32 newval) -{ - u32 val; - - if (unlikely(get_user(val, uaddr) != 0)) - return -EFAULT; - - if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) - return -EFAULT; - - *uval = val; - - return 0; -} - -static inline int -futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval, ret; - u32 tmp; - - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - pagefault_disable(); /* implies preempt_disable() */ - - ret = -EFAULT; - if (unlikely(get_user(oldval, uaddr) != 0)) - goto out_pagefault_enable; - - ret = 0; - tmp = oldval; - - switch (op) { - case FUTEX_OP_SET: - tmp = oparg; - break; - case FUTEX_OP_ADD: - tmp += oparg; - break; - case FUTEX_OP_OR: - tmp |= oparg; - break; - case FUTEX_OP_ANDN: - tmp &= ~oparg; - break; - case FUTEX_OP_XOR: - tmp ^= oparg; - break; - default: - ret = -ENOSYS; - } - - if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0)) - ret = -EFAULT; - -out_pagefault_enable: - pagefault_enable(); /* subsumes preempt_enable() */ - - if (ret == 0) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif /* CONFIG_MMU */ -#endif /* __KERNEL__ */ -#endif /* _ASM_M68K_FUTEX_H */ diff --git a/arch/m68k/include/asm/macintosh.h b/arch/m68k/include/asm/macintosh.h index 29c7c6c3a5f2..42235e7fbeed 100644 --- a/arch/m68k/include/asm/macintosh.h +++ b/arch/m68k/include/asm/macintosh.h @@ -55,7 +55,7 @@ struct mac_model #define MAC_SCSI_QUADRA3 4 #define MAC_SCSI_IIFX 5 #define MAC_SCSI_DUO 6 -#define MAC_SCSI_CCL 7 +#define MAC_SCSI_LC 7 #define MAC_SCSI_LATE 8 #define MAC_IDE_NONE 0 diff --git a/arch/m68k/include/asm/mcf_pgtable.h b/arch/m68k/include/asm/mcf_pgtable.h index 3c793682e5d9..2500ce04fcc4 100644 --- a/arch/m68k/include/asm/mcf_pgtable.h +++ b/arch/m68k/include/asm/mcf_pgtable.h @@ -35,7 +35,6 @@ * hitting hardware. */ #define CF_PAGE_DIRTY 0x00000001 -#define CF_PAGE_FILE 0x00000200 #define CF_PAGE_ACCESSED 0x00001000 #define _PAGE_CACHE040 0x020 /* 68040 cache mode, cachable, copyback */ @@ -243,11 +242,6 @@ static inline int pte_young(pte_t pte) return pte_val(pte) & CF_PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) -{ - return pte_val(pte) & CF_PAGE_FILE; -} - static inline int pte_special(pte_t pte) { return 0; @@ -391,26 +385,13 @@ static inline void cache_page(void *vaddr) *ptep = pte_mkcache(*ptep); } -#define PTE_FILE_MAX_BITS 21 -#define PTE_FILE_SHIFT 11 - -static inline unsigned long pte_to_pgoff(pte_t pte) -{ - return pte_val(pte) >> PTE_FILE_SHIFT; -} - -static inline pte_t pgoff_to_pte(unsigned pgoff) -{ - return __pte((pgoff << PTE_FILE_SHIFT) + CF_PAGE_FILE); -} - /* * Encode and de-code a swap entry (must be !pte_none(e) && !pte_present(e)) */ #define __swp_type(x) ((x).val & 0xFF) -#define __swp_offset(x) ((x).val >> PTE_FILE_SHIFT) +#define __swp_offset(x) ((x).val >> 11) #define __swp_entry(typ, off) ((swp_entry_t) { (typ) | \ - (off << PTE_FILE_SHIFT) }) + (off << 11) }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) (__pte((x).val)) diff --git a/arch/m68k/include/asm/motorola_pgtable.h b/arch/m68k/include/asm/motorola_pgtable.h index e0fdd4d08075..0085aab80e5a 100644 --- a/arch/m68k/include/asm/motorola_pgtable.h +++ b/arch/m68k/include/asm/motorola_pgtable.h @@ -28,7 +28,6 @@ #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_NOCACHE) #define _PAGE_PROTNONE 0x004 -#define _PAGE_FILE 0x008 /* pagecache or swap? */ #ifndef __ASSEMBLY__ @@ -168,7 +167,6 @@ static inline void pgd_set(pgd_t *pgdp, pmd_t *pmdp) static inline int pte_write(pte_t pte) { return !(pte_val(pte) & _PAGE_RONLY); } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } static inline int pte_special(pte_t pte) { return 0; } static inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) |= _PAGE_RONLY; return pte; } @@ -266,19 +264,6 @@ static inline void cache_page(void *vaddr) } } -#define PTE_FILE_MAX_BITS 28 - -static inline unsigned long pte_to_pgoff(pte_t pte) -{ - return pte.pte >> 4; -} - -static inline pte_t pgoff_to_pte(unsigned off) -{ - pte_t pte = { (off << 4) + _PAGE_FILE }; - return pte; -} - /* Encode and de-code a swap entry (must be !pte_none(e) && !pte_present(e)) */ #define __swp_type(x) (((x).val >> 4) & 0xff) #define __swp_offset(x) ((x).val >> 12) diff --git a/arch/m68k/include/asm/pgtable_mm.h b/arch/m68k/include/asm/pgtable_mm.h index 9f5abbda1ea7..28a145bfbb71 100644 --- a/arch/m68k/include/asm/pgtable_mm.h +++ b/arch/m68k/include/asm/pgtable_mm.h @@ -66,7 +66,7 @@ #define PTRS_PER_PGD 128 #endif #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL /* Virtual address region for use by kernel_map() */ #ifdef CONFIG_SUN3 diff --git a/arch/m68k/include/asm/pgtable_no.h b/arch/m68k/include/asm/pgtable_no.h index 11859b86b1f9..ac7d87a02335 100644 --- a/arch/m68k/include/asm/pgtable_no.h +++ b/arch/m68k/include/asm/pgtable_no.h @@ -37,8 +37,6 @@ extern void paging_init(void); #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -static inline int pte_file(pte_t pte) { return 0; } - /* * ZERO_PAGE is a global shared page that is always zero: used * for zero-mapped memory areas etc.. diff --git a/arch/m68k/include/asm/sun3_pgtable.h b/arch/m68k/include/asm/sun3_pgtable.h index f55aa04161e8..48657f9fdece 100644 --- a/arch/m68k/include/asm/sun3_pgtable.h +++ b/arch/m68k/include/asm/sun3_pgtable.h @@ -38,8 +38,6 @@ #define _PAGE_PRESENT (SUN3_PAGE_VALID) #define _PAGE_ACCESSED (SUN3_PAGE_ACCESSED) -#define PTE_FILE_MAX_BITS 28 - /* Compound page protection values. */ //todo: work out which ones *should* have SUN3_PAGE_NOCACHE and fix... // is it just PAGE_KERNEL and PAGE_SHARED? @@ -168,7 +166,6 @@ static inline void pgd_clear (pgd_t *pgdp) {} static inline int pte_write(pte_t pte) { return pte_val(pte) & SUN3_PAGE_WRITEABLE; } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & SUN3_PAGE_MODIFIED; } static inline int pte_young(pte_t pte) { return pte_val(pte) & SUN3_PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) { return pte_val(pte) & SUN3_PAGE_ACCESSED; } static inline int pte_special(pte_t pte) { return 0; } static inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~SUN3_PAGE_WRITEABLE; return pte; } @@ -202,18 +199,6 @@ static inline pmd_t *pmd_offset (pgd_t *pgd, unsigned long address) return (pmd_t *) pgd; } -static inline unsigned long pte_to_pgoff(pte_t pte) -{ - return pte.pte & SUN3_PAGE_PGNUM_MASK; -} - -static inline pte_t pgoff_to_pte(unsigned off) -{ - pte_t pte = { off + SUN3_PAGE_ACCESSED }; - return pte; -} - - /* Find an entry in the third-level pagetable. */ #define pte_index(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE-1)) #define pte_offset_kernel(pmd, address) ((pte_t *) __pmd_page(*pmd) + pte_index(address)) diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index e9c3756139fc..689b47d292ac 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -296,7 +296,7 @@ static struct mac_model mac_data_table[] = { .name = "IIvi", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -305,7 +305,7 @@ static struct mac_model mac_data_table[] = { .name = "IIvx", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -320,7 +320,7 @@ static struct mac_model mac_data_table[] = { .name = "Classic II", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -329,7 +329,7 @@ static struct mac_model mac_data_table[] = { .name = "Color Classic", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_CCL, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -338,7 +338,7 @@ static struct mac_model mac_data_table[] = { .name = "Color Classic II", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_CCL, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -353,7 +353,7 @@ static struct mac_model mac_data_table[] = { .name = "LC", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -362,7 +362,7 @@ static struct mac_model mac_data_table[] = { .name = "LC II", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -371,7 +371,7 @@ static struct mac_model mac_data_table[] = { .name = "LC III", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -499,7 +499,7 @@ static struct mac_model mac_data_table[] = { .name = "Performa 460", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -526,7 +526,7 @@ static struct mac_model mac_data_table[] = { .name = "Performa 520", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_CCL, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -535,7 +535,7 @@ static struct mac_model mac_data_table[] = { .name = "Performa 550", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_CCL, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -567,7 +567,7 @@ static struct mac_model mac_data_table[] = { .name = "TV", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_CCL, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -576,7 +576,7 @@ static struct mac_model mac_data_table[] = { .name = "Performa 600", .adb_type = MAC_ADB_IISI, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LC, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -1109,8 +1109,10 @@ int __init mac_platform_init(void) platform_device_register_simple("mac_scsi", 0, mac_scsi_late_rsrc, ARRAY_SIZE(mac_scsi_late_rsrc)); break; - case MAC_SCSI_CCL: - /* Addresses from the Color Classic Developer Note. + case MAC_SCSI_LC: + /* Addresses from Mac LC data in Designing Cards & Drivers 3ed. + * Also from the Developer Notes for Classic II, LC III, + * Color Classic and IIvx. * $50F0 6000 - $50F0 7FFF: SCSI handshake * $50F1 0000 - $50F1 1FFF: SCSI * $50F1 2000 - $50F1 3FFF: SCSI DMA diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c index 2bd7487440c4..b2f04aee46ec 100644 --- a/arch/m68k/mm/fault.c +++ b/arch/m68k/mm/fault.c @@ -145,6 +145,8 @@ good_area: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto map_err; else if (fault & VM_FAULT_SIGBUS) goto bus_err; BUG(); diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c index 1bb3ce6634d3..e6a3b56c6481 100644 --- a/arch/m68k/mvme147/config.c +++ b/arch/m68k/mvme147/config.c @@ -168,49 +168,3 @@ int mvme147_set_clock_mmss (unsigned long nowtime) { return 0; } - -/*------------------- Serial console stuff ------------------------*/ - -static void scc_delay (void) -{ - int n; - volatile int trash; - - for (n = 0; n < 20; n++) - trash = n; -} - -static void scc_write (char ch) -{ - volatile char *p = (volatile char *)M147_SCC_A_ADDR; - - do { - scc_delay(); - } - while (!(*p & 4)); - scc_delay(); - *p = 8; - scc_delay(); - *p = ch; -} - - -void m147_scc_write (struct console *co, const char *str, unsigned count) -{ - unsigned long flags; - - local_irq_save(flags); - - while (count--) - { - if (*str == '\n') - scc_write ('\r'); - scc_write (*str++); - } - local_irq_restore(flags); -} - -void mvme147_init_console_port (struct console *co, int cflag) -{ - co->write = m147_scc_write; -} diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c index 6ef7a81a3b12..1755e2f7137d 100644 --- a/arch/m68k/mvme16x/rtc.c +++ b/arch/m68k/mvme16x/rtc.c @@ -161,4 +161,4 @@ static int __init rtc_MK48T08_init(void) printk(KERN_INFO "MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION); return misc_register(&rtc_dev); } -module_init(rtc_MK48T08_init); +device_initcall(rtc_MK48T08_init); diff --git a/arch/metag/include/asm/pgtable.h b/arch/metag/include/asm/pgtable.h index 0d9dc5487296..d0604c0a8702 100644 --- a/arch/metag/include/asm/pgtable.h +++ b/arch/metag/include/asm/pgtable.h @@ -47,7 +47,6 @@ */ #define _PAGE_ACCESSED _PAGE_ALWAYS_ZERO_1 #define _PAGE_DIRTY _PAGE_ALWAYS_ZERO_2 -#define _PAGE_FILE _PAGE_ALWAYS_ZERO_3 /* Pages owned, and protected by, the kernel. */ #define _PAGE_KERNEL _PAGE_PRIV @@ -219,7 +218,6 @@ extern unsigned long empty_zero_page; static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } static inline int pte_special(pte_t pte) { return 0; } static inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= (~_PAGE_WRITE); return pte; } @@ -327,10 +325,6 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -#define PTE_FILE_MAX_BITS 22 -#define pte_to_pgoff(x) (pte_val(x) >> 10) -#define pgoff_to_pte(x) __pte(((x) << 10) | _PAGE_FILE) - #define kern_addr_valid(addr) (1) /* diff --git a/arch/metag/mm/fault.c b/arch/metag/mm/fault.c index 332680e5ebf2..2de5dc695a87 100644 --- a/arch/metag/mm/fault.c +++ b/arch/metag/mm/fault.c @@ -141,6 +141,8 @@ good_area: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/metag/mm/hugetlbpage.c b/arch/metag/mm/hugetlbpage.c index 3c32075d2945..7ca80ac42ed5 100644 --- a/arch/metag/mm/hugetlbpage.c +++ b/arch/metag/mm/hugetlbpage.c @@ -94,12 +94,6 @@ int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) return 0; } -struct page *follow_huge_addr(struct mm_struct *mm, - unsigned long address, int write) -{ - return ERR_PTR(-EINVAL); -} - int pmd_huge(pmd_t pmd) { return pmd_page_shift(pmd) > PAGE_SHIFT; diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile index 8e211cc28dac..91d2068da1b9 100644 --- a/arch/microblaze/boot/Makefile +++ b/arch/microblaze/boot/Makefile @@ -34,5 +34,4 @@ $(obj)/simpleImage.%: vmlinux FORCE $(call if_changed,strip) @echo 'Kernel: $@ is ready' ' (#'`cat .version`')' - -clean-files += simpleImage.*.unstrip linux.bin.ub +clean-files += simpleImage.*.unstrip linux.bin.ub dts/*.dtb diff --git a/arch/microblaze/boot/dts/Makefile b/arch/microblaze/boot/dts/Makefile index c4982d16e555..a3d2e42c3c97 100644 --- a/arch/microblaze/boot/dts/Makefile +++ b/arch/microblaze/boot/dts/Makefile @@ -16,5 +16,3 @@ quiet_cmd_cp = CP $< $@$2 # Rule to build device tree blobs DTC_FLAGS := -p 1024 - -clean-files += *.dtb diff --git a/arch/microblaze/include/asm/delay.h b/arch/microblaze/include/asm/delay.h index 60cb39deb533..ea2a9cd9b159 100644 --- a/arch/microblaze/include/asm/delay.h +++ b/arch/microblaze/include/asm/delay.h @@ -15,7 +15,7 @@ #include -extern inline void __delay(unsigned long loops) +static inline void __delay(unsigned long loops) { asm volatile ("# __delay \n\t" \ "1: addi %0, %0, -1\t\n" \ @@ -43,7 +43,7 @@ extern inline void __delay(unsigned long loops) extern unsigned long loops_per_jiffy; -extern inline void __udelay(unsigned int x) +static inline void __udelay(unsigned int x) { unsigned long long tmp = diff --git a/arch/microblaze/include/asm/kgdb.h b/arch/microblaze/include/asm/kgdb.h index 78b17d40b235..ad27acb2b15f 100644 --- a/arch/microblaze/include/asm/kgdb.h +++ b/arch/microblaze/include/asm/kgdb.h @@ -23,6 +23,9 @@ static inline void arch_kgdb_breakpoint(void) __asm__ __volatile__("brki r16, 0x18;"); } +struct pt_regs; +asmlinkage void microblaze_kgdb_break(struct pt_regs *regs); + #endif /* __ASSEMBLY__ */ #endif /* __MICROBLAZE_KGDB_H__ */ #endif /* __KERNEL__ */ diff --git a/arch/microblaze/include/asm/linkage.h b/arch/microblaze/include/asm/linkage.h index 3a8e36d057eb..0540bbaad897 100644 --- a/arch/microblaze/include/asm/linkage.h +++ b/arch/microblaze/include/asm/linkage.h @@ -1,15 +1 @@ -/* - * Copyright (C) 2006 Atmark Techno, 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 - * for more details. - */ - -#ifndef _ASM_MICROBLAZE_LINKAGE_H -#define _ASM_MICROBLAZE_LINKAGE_H - -#define __ALIGN .align 4 -#define __ALIGN_STR ".align 4" - -#endif /* _ASM_MICROBLAZE_LINKAGE_H */ +#include diff --git a/arch/microblaze/include/asm/pgalloc.h b/arch/microblaze/include/asm/pgalloc.h index 7fdf7fabc7d7..61436d69775c 100644 --- a/arch/microblaze/include/asm/pgalloc.h +++ b/arch/microblaze/include/asm/pgalloc.h @@ -60,7 +60,7 @@ extern unsigned long get_zero_page_fast(void); extern void __bad_pte(pmd_t *pmd); -extern inline pgd_t *get_pgd_slow(void) +static inline pgd_t *get_pgd_slow(void) { pgd_t *ret; @@ -70,7 +70,7 @@ extern inline pgd_t *get_pgd_slow(void) return ret; } -extern inline pgd_t *get_pgd_fast(void) +static inline pgd_t *get_pgd_fast(void) { unsigned long *ret; @@ -84,14 +84,14 @@ extern inline pgd_t *get_pgd_fast(void) return (pgd_t *)ret; } -extern inline void free_pgd_fast(pgd_t *pgd) +static inline void free_pgd_fast(pgd_t *pgd) { *(unsigned long **)pgd = pgd_quicklist; pgd_quicklist = (unsigned long *) pgd; pgtable_cache_size++; } -extern inline void free_pgd_slow(pgd_t *pgd) +static inline void free_pgd_slow(pgd_t *pgd) { free_page((unsigned long)pgd); } @@ -146,19 +146,19 @@ static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, return (pte_t *)ret; } -extern inline void pte_free_fast(pte_t *pte) +static inline void pte_free_fast(pte_t *pte) { *(unsigned long **)pte = pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } -extern inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) +static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) { free_page((unsigned long)pte); } -extern inline void pte_free_slow(struct page *ptepage) +static inline void pte_free_slow(struct page *ptepage) { __free_page(ptepage); } diff --git a/arch/microblaze/include/asm/pgtable.h b/arch/microblaze/include/asm/pgtable.h index df19d0c47be8..e53b8532353c 100644 --- a/arch/microblaze/include/asm/pgtable.h +++ b/arch/microblaze/include/asm/pgtable.h @@ -40,10 +40,6 @@ extern int mem_init_done; #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -#ifndef __ASSEMBLY__ -static inline int pte_file(pte_t pte) { return 0; } -#endif /* __ASSEMBLY__ */ - #define ZERO_PAGE(vaddr) ({ BUG(); NULL; }) #define swapper_pg_dir ((pgd_t *) NULL) @@ -65,6 +61,8 @@ static inline int pte_file(pte_t pte) { return 0; } #include +#define __PAGETABLE_PMD_FOLDED + #ifdef __KERNEL__ #ifndef __ASSEMBLY__ @@ -74,7 +72,7 @@ static inline int pte_file(pte_t pte) { return 0; } #include #include -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL extern unsigned long va_to_phys(unsigned long address); extern pte_t *va_to_pte(unsigned long address); @@ -207,7 +205,6 @@ static inline pte_t pte_mkspecial(pte_t pte) { return pte; } /* Definitions for MicroBlaze. */ #define _PAGE_GUARDED 0x001 /* G: page is guarded from prefetch */ -#define _PAGE_FILE 0x001 /* when !present: nonlinear file mapping */ #define _PAGE_PRESENT 0x002 /* software: PTE contains a translation */ #define _PAGE_NO_CACHE 0x004 /* I: caching is inhibited */ #define _PAGE_WRITETHRU 0x008 /* W: caching is write-through */ @@ -337,7 +334,6 @@ static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; } static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC; } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; } static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACHE; } @@ -499,11 +495,6 @@ static inline pmd_t *pmd_offset(pgd_t *dir, unsigned long address) #define pte_unmap(pte) kunmap_atomic(pte) -/* Encode and decode a nonlinear file mapping entry */ -#define PTE_FILE_MAX_BITS 29 -#define pte_to_pgoff(pte) (pte_val(pte) >> 3) -#define pgoff_to_pte(off) ((pte_t) { ((off) << 3) | _PAGE_FILE }) - extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* diff --git a/arch/microblaze/include/asm/syscall.h b/arch/microblaze/include/asm/syscall.h index 53cfaf34c343..04a5bece8168 100644 --- a/arch/microblaze/include/asm/syscall.h +++ b/arch/microblaze/include/asm/syscall.h @@ -97,7 +97,7 @@ static inline void syscall_set_arguments(struct task_struct *task, microblaze_set_syscall_arg(regs, i++, *args++); } -asmlinkage long do_syscall_trace_enter(struct pt_regs *regs); +asmlinkage unsigned long do_syscall_trace_enter(struct pt_regs *regs); asmlinkage void do_syscall_trace_leave(struct pt_regs *regs); static inline int syscall_get_arch(void) diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 59a89a64a865..62942fd12672 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -220,7 +220,7 @@ extern long __user_bad(void); } else { \ __gu_err = -EFAULT; \ } \ - x = (typeof(*(ptr)))__gu_val; \ + x = (__force typeof(*(ptr)))__gu_val; \ __gu_err; \ }) @@ -242,7 +242,7 @@ extern long __user_bad(void); default: \ /* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\ } \ - x = (__typeof__(*(ptr))) __gu_val; \ + x = (__force __typeof__(*(ptr))) __gu_val; \ __gu_err; \ }) @@ -306,7 +306,7 @@ extern long __user_bad(void); #define __put_user_check(x, ptr, size) \ ({ \ - typeof(*(ptr)) volatile __pu_val = x; \ + typeof(*(ptr)) volatile __pu_val = x; \ typeof(*(ptr)) __user *__pu_addr = (ptr); \ int __pu_err = 0; \ \ diff --git a/arch/microblaze/include/asm/unistd.h b/arch/microblaze/include/asm/unistd.h index 0a53362d5548..76ed17b56fea 100644 --- a/arch/microblaze/include/asm/unistd.h +++ b/arch/microblaze/include/asm/unistd.h @@ -38,6 +38,6 @@ #endif /* __ASSEMBLY__ */ -#define __NR_syscalls 388 +#define __NR_syscalls 389 #endif /* _ASM_MICROBLAZE_UNISTD_H */ diff --git a/arch/microblaze/include/uapi/asm/unistd.h b/arch/microblaze/include/uapi/asm/unistd.h index c712677f8a2a..32850c73be09 100644 --- a/arch/microblaze/include/uapi/asm/unistd.h +++ b/arch/microblaze/include/uapi/asm/unistd.h @@ -403,5 +403,6 @@ #define __NR_getrandom 385 #define __NR_memfd_create 386 #define __NR_bpf 387 +#define __NR_execveat 388 #endif /* _UAPI_ASM_MICROBLAZE_UNISTD_H */ diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile index 08d50cc55e7d..f08bacaf8a95 100644 --- a/arch/microblaze/kernel/Makefile +++ b/arch/microblaze/kernel/Makefile @@ -16,7 +16,7 @@ extra-y := head.o vmlinux.lds obj-y += dma.o exceptions.o \ hw_exception_handler.o intc.o irq.o \ - platform.o process.o prom.o prom_parse.o ptrace.o \ + platform.o process.o prom.o ptrace.o \ reset.o setup.o signal.o sys_microblaze.o timer.o traps.o unwind.o obj-y += cpu/ diff --git a/arch/microblaze/kernel/cpu/cache.c b/arch/microblaze/kernel/cpu/cache.c index a6e44410672d..0bde47e4fa69 100644 --- a/arch/microblaze/kernel/cpu/cache.c +++ b/arch/microblaze/kernel/cpu/cache.c @@ -140,10 +140,10 @@ do { \ /* It is used only first parameter for OP - for wic, wdc */ #define CACHE_RANGE_LOOP_1(start, end, line_length, op) \ do { \ - int volatile temp = 0; \ - int align = ~(line_length - 1); \ + unsigned int volatile temp = 0; \ + unsigned int align = ~(line_length - 1); \ end = ((end & align) == end) ? end - line_length : end & align; \ - WARN_ON(end - start < 0); \ + WARN_ON(end < start); \ \ __asm__ __volatile__ (" 1: " #op " %1, r0;" \ "cmpu %0, %1, %2;" \ diff --git a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c index 93c26cf50de5..a32daec96c12 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c +++ b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c @@ -33,7 +33,7 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu) { struct pvr_s pvr; - int temp; /* for saving temp value */ + u32 temp; /* for saving temp value */ get_pvr(&pvr); CI(ver_code, VERSION); diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c index 4854285b26e7..85dbda4a08a8 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo-static.c +++ b/arch/microblaze/kernel/cpu/cpuinfo-static.c @@ -22,7 +22,7 @@ static const char cpu_ver_string[] = CONFIG_XILINX_MICROBLAZE0_HW_VER; void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu) { - int i = 0; + u32 i = 0; ci->use_instr = (fcpu(cpu, "xlnx,use-barrel") ? PVR0_USE_BARREL_MASK : 0) | diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c index 234acad79b9e..d1dd6e83d59b 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo.c +++ b/arch/microblaze/kernel/cpu/cpuinfo.c @@ -41,8 +41,12 @@ const struct cpu_ver_key cpu_ver_lookup[] = { {"8.40.a", 0x18}, {"8.40.b", 0x19}, {"8.50.a", 0x1a}, + {"8.50.b", 0x1c}, + {"8.50.c", 0x1e}, {"9.0", 0x1b}, {"9.1", 0x1d}, + {"9.2", 0x1f}, + {"9.3", 0x20}, {NULL, 0}, }; @@ -61,11 +65,14 @@ const struct family_string_key family_string_lookup[] = { {"spartan3adsp", 0xc}, {"spartan6", 0xd}, {"virtex6", 0xe}, + {"virtex7", 0xf}, /* FIXME There is no key code defined for spartan2 */ {"spartan2", 0xf0}, {"kintex7", 0x10}, {"artix7", 0x11}, {"zynq7000", 0x12}, + {"UltraScale Virtex", 0x13}, + {"UltraScale Kintex", 0x14}, {NULL, 0}, }; diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c index 15c7c12ea0e7..719feee1e043 100644 --- a/arch/microblaze/kernel/intc.c +++ b/arch/microblaze/kernel/intc.c @@ -148,17 +148,17 @@ static int __init xilinx_intc_of_init(struct device_node *intc, ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &nr_irq); if (ret < 0) { pr_err("%s: unable to read xlnx,num-intr-inputs\n", __func__); - return -EINVAL; + return ret; } ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &intr_mask); if (ret < 0) { pr_err("%s: unable to read xlnx,kind-of-intr\n", __func__); - return -EINVAL; + return ret; } - if (intr_mask > (u32)((1ULL << nr_irq) - 1)) - pr_info(" ERROR: Mismatch in kind-of-intr param\n"); + if (intr_mask >> nr_irq) + pr_warn("%s: mismatch in kind-of-intr param\n", __func__); pr_info("%s: num_irq=%d, edge=0x%x\n", intc->full_name, nr_irq, intr_mask); diff --git a/arch/microblaze/kernel/kgdb.c b/arch/microblaze/kernel/kgdb.c index 09a5e8286137..8736af5806ae 100644 --- a/arch/microblaze/kernel/kgdb.c +++ b/arch/microblaze/kernel/kgdb.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #define GDB_REG 0 @@ -35,9 +36,10 @@ struct pvr_s pvr; void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) { - int i; + unsigned int i; unsigned long *pt_regb = (unsigned long *)regs; int temp; + /* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */ for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++) gdb_regs[i] = pt_regb[i]; @@ -67,7 +69,7 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) { - int i; + unsigned int i; unsigned long *pt_regb = (unsigned long *)regs; /* pt_regs and gdb_regs have the same 37 values. @@ -77,7 +79,7 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) pt_regb[i] = gdb_regs[i]; } -void microblaze_kgdb_break(struct pt_regs *regs) +asmlinkage void microblaze_kgdb_break(struct pt_regs *regs) { if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0) return; @@ -91,7 +93,7 @@ void microblaze_kgdb_break(struct pt_regs *regs) /* untested */ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) { - int i; + unsigned int i; unsigned long *pt_regb = (unsigned long *)(p->thread.regs); /* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */ diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c deleted file mode 100644 index 068762f55fd6..000000000000 --- a/arch/microblaze/kernel/prom_parse.c +++ /dev/null @@ -1,35 +0,0 @@ -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include - -void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, - unsigned long *busno, unsigned long *phys, unsigned long *size) -{ - const u32 *dma_window; - u32 cells; - const unsigned char *prop; - - dma_window = dma_window_prop; - - /* busno is always one cell */ - *busno = *(dma_window++); - - prop = of_get_property(dn, "ibm,#dma-address-cells", NULL); - if (!prop) - prop = of_get_property(dn, "#address-cells", NULL); - - cells = prop ? *(u32 *)prop : of_n_addr_cells(dn); - *phys = of_read_number(dma_window, cells); - - dma_window += cells; - - prop = of_get_property(dn, "ibm,#dma-size-cells", NULL); - cells = prop ? *(u32 *)prop : of_n_size_cells(dn); - *size = of_read_number(dma_window, cells); -} diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c index bb10637ce688..8cfa98cadf3d 100644 --- a/arch/microblaze/kernel/ptrace.c +++ b/arch/microblaze/kernel/ptrace.c @@ -132,9 +132,9 @@ long arch_ptrace(struct task_struct *child, long request, return rval; } -asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) +asmlinkage unsigned long do_syscall_trace_enter(struct pt_regs *regs) { - long ret = 0; + unsigned long ret = 0; secure_computing_strict(regs->r12); diff --git a/arch/microblaze/kernel/reset.c b/arch/microblaze/kernel/reset.c index fbe58c6554a8..bab4c8330ef4 100644 --- a/arch/microblaze/kernel/reset.c +++ b/arch/microblaze/kernel/reset.c @@ -9,7 +9,6 @@ #include #include -#include /* Trigger specific functions */ #ifdef CONFIG_GPIOLIB diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 8955a3829cf0..235706055b7f 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -158,7 +158,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, { struct rt_sigframe __user *frame; int err = 0, sig = ksig->sig; - int signal; + unsigned long signal; unsigned long address = 0; #ifdef CONFIG_MMU pmd_t *pmdp; @@ -174,7 +174,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, && current_thread_info()->exec_domain->signal_invmap && sig < 32 ? current_thread_info()->exec_domain->signal_invmap[sig] - : sig; + : (unsigned long)sig; if (ksig->ka.sa.sa_flags & SA_SIGINFO) err |= copy_siginfo_to_user(&frame->info, &ksig->info); diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S index 0166e890486c..29c8568ec55c 100644 --- a/arch/microblaze/kernel/syscall_table.S +++ b/arch/microblaze/kernel/syscall_table.S @@ -388,3 +388,4 @@ ENTRY(sys_call_table) .long sys_getrandom /* 385 */ .long sys_memfd_create .long sys_bpf + .long sys_execveat diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index dd96f0e4bfa2..c8977450e28c 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -17,6 +17,7 @@ #include #include #include +#include #include static void __iomem *timer_baseaddr; diff --git a/arch/microblaze/kernel/unwind.c b/arch/microblaze/kernel/unwind.c index 1f7b8d449668..61c04eed14d5 100644 --- a/arch/microblaze/kernel/unwind.c +++ b/arch/microblaze/kernel/unwind.c @@ -59,7 +59,7 @@ struct stack_trace; * * Return - Number of stack bytes the instruction reserves or reclaims */ -inline long get_frame_size(unsigned long instr) +static inline long get_frame_size(unsigned long instr) { return abs((s16)(instr & 0xFFFF)); } diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c index fa4cf52aa7a6..d46a5ebb7570 100644 --- a/arch/microblaze/mm/fault.c +++ b/arch/microblaze/mm/fault.c @@ -224,6 +224,8 @@ good_area: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c index b30e41c0c033..48528fb81eff 100644 --- a/arch/microblaze/pci/pci-common.c +++ b/arch/microblaze/pci/pci-common.c @@ -1026,6 +1026,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) pr, (pr && pr->name) ? pr->name : "nil"); if (pr && !(pr->flags & IORESOURCE_UNSET)) { + struct pci_dev *dev = bus->self; + if (request_resource(pr, res) == 0) continue; /* @@ -1035,6 +1037,12 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) */ if (reparent_resources(pr, res) == 0) continue; + + if (dev && i < PCI_BRIDGE_RESOURCE_NUM && + pci_claim_bridge_resource(dev, + i + PCI_BRIDGE_RESOURCES) == 0) + continue; + } pr_warn("PCI: Cannot allocate resource region "); pr_cont("%d of PCI bridge %d, will remap\n", i, bus->number); @@ -1227,7 +1235,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus) (unsigned long long)r->end, (unsigned int)r->flags); - pci_claim_resource(dev, i); + if (pci_claim_resource(dev, i) == 0) + continue; + + pci_claim_bridge_resource(dev, i); } } diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 3289969ee423..843713c05b79 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2656,27 +2656,21 @@ config TRAD_SIGNALS bool config MIPS32_COMPAT - bool "Kernel support for Linux/MIPS 32-bit binary compatibility" - depends on 64BIT - help - Select this option if you want Linux/MIPS 32-bit binary - compatibility. Since all software available for Linux/MIPS is - currently 32-bit you should say Y here. + bool config COMPAT bool - depends on MIPS32_COMPAT - select ARCH_WANT_OLD_COMPAT_IPC - default y config SYSVIPC_COMPAT bool - depends on COMPAT && SYSVIPC - default y config MIPS32_O32 bool "Kernel support for o32 binaries" - depends on MIPS32_COMPAT + depends on 64BIT + select ARCH_WANT_OLD_COMPAT_IPC + select COMPAT + select MIPS32_COMPAT + select SYSVIPC_COMPAT if SYSVIPC help Select this option if you want to run o32 binaries. These are pure 32-bit binaries as used by the 32-bit Linux/MIPS port. Most of @@ -2686,7 +2680,10 @@ config MIPS32_O32 config MIPS32_N32 bool "Kernel support for n32 binaries" - depends on MIPS32_COMPAT + depends on 64BIT + select COMPAT + select MIPS32_COMPAT + select SYSVIPC_COMPAT if SYSVIPC help Select this option if you want to run n32 binaries. These are 64-bit binaries using 32-bit quantities for addressing and certain diff --git a/arch/mips/boot/elf2ecoff.c b/arch/mips/boot/elf2ecoff.c index 8585078ae50e..2a4c52e27f41 100644 --- a/arch/mips/boot/elf2ecoff.c +++ b/arch/mips/boot/elf2ecoff.c @@ -49,7 +49,8 @@ /* * Some extra ELF definitions */ -#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +#define PT_MIPS_ABIFLAGS 0x70000003 /* Records ABI related flags */ /* -------------------------------------------------------------------- */ @@ -349,39 +350,46 @@ int main(int argc, char *argv[]) for (i = 0; i < ex.e_phnum; i++) { /* Section types we can ignore... */ - if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE || - ph[i].p_type == PT_PHDR - || ph[i].p_type == PT_MIPS_REGINFO) + switch (ph[i].p_type) { + case PT_NULL: + case PT_NOTE: + case PT_PHDR: + case PT_MIPS_REGINFO: + case PT_MIPS_ABIFLAGS: continue; - /* Section types we can't handle... */ - else if (ph[i].p_type != PT_LOAD) { + + case PT_LOAD: + /* Writable (data) segment? */ + if (ph[i].p_flags & PF_W) { + struct sect ndata, nbss; + + ndata.vaddr = ph[i].p_vaddr; + ndata.len = ph[i].p_filesz; + nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz; + nbss.len = ph[i].p_memsz - ph[i].p_filesz; + + combine(&data, &ndata, 0); + combine(&bss, &nbss, 1); + } else { + struct sect ntxt; + + ntxt.vaddr = ph[i].p_vaddr; + ntxt.len = ph[i].p_filesz; + + combine(&text, &ntxt, 0); + } + /* Remember the lowest segment start address. */ + if (ph[i].p_vaddr < cur_vma) + cur_vma = ph[i].p_vaddr; + break; + + default: + /* Section types we can't handle... */ fprintf(stderr, "Program header %d type %d can't be converted.\n", ex.e_phnum, ph[i].p_type); exit(1); } - /* Writable (data) segment? */ - if (ph[i].p_flags & PF_W) { - struct sect ndata, nbss; - - ndata.vaddr = ph[i].p_vaddr; - ndata.len = ph[i].p_filesz; - nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz; - nbss.len = ph[i].p_memsz - ph[i].p_filesz; - - combine(&data, &ndata, 0); - combine(&bss, &nbss, 1); - } else { - struct sect ntxt; - - ntxt.vaddr = ph[i].p_vaddr; - ntxt.len = ph[i].p_filesz; - - combine(&text, &ntxt, 0); - } - /* Remember the lowest segment start address. */ - if (ph[i].p_vaddr < cur_vma) - cur_vma = ph[i].p_vaddr; } /* Sections must be in order to be converted... */ diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index ecd903dd1c45..8b1eeffa12ed 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -240,9 +240,7 @@ static int octeon_cpu_disable(void) set_cpu_online(cpu, false); cpu_clear(cpu, cpu_callin_map); - local_irq_disable(); octeon_fixup_irqs(); - local_irq_enable(); flush_cache_all(); local_flush_tlb_all(); diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index f57b96dcf7df..61a4460d67d3 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -132,7 +132,6 @@ 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_ULOG=m CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_CLUSTERIP=m CONFIG_IP_NF_TARGET_ECN=m @@ -175,7 +174,6 @@ 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_SCTP=m CONFIG_BRIDGE=m @@ -220,8 +218,6 @@ CONFIG_NET_ACT_SKBEDIT=m CONFIG_NET_CLS_IND=y CONFIG_CFG80211=m CONFIG_MAC80211=m -CONFIG_MAC80211_RC_PID=y -CONFIG_MAC80211_RC_DEFAULT_PID=y CONFIG_MAC80211_MESH=y CONFIG_RFKILL=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" @@ -248,19 +244,13 @@ CONFIG_ATA_OVER_ETH=m CONFIG_IDE=y CONFIG_BLK_DEV_IDECD=y CONFIG_IDE_GENERIC=y -CONFIG_BLK_DEV_GENERIC=y -CONFIG_BLK_DEV_PIIX=y -CONFIG_BLK_DEV_IT8213=m -CONFIG_BLK_DEV_TC86C001=m CONFIG_RAID_ATTRS=m -CONFIG_SCSI=m -CONFIG_BLK_DEV_SD=m +CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=m CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=m CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SCAN_ASYNC=y @@ -273,6 +263,8 @@ CONFIG_SCSI_AACRAID=m CONFIG_SCSI_AIC7XXX=m CONFIG_AIC7XXX_RESET_DELAY_MS=15000 # CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_ATA=y +CONFIG_ATA_PIIX=y CONFIG_MD=y CONFIG_BLK_DEV_MD=m CONFIG_MD_LINEAR=m @@ -340,6 +332,7 @@ CONFIG_UIO=m CONFIG_UIO_CIF=m CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y CONFIG_REISERFS_FS=m CONFIG_REISERFS_PROC_INFO=y CONFIG_REISERFS_FS_XATTR=y @@ -441,4 +434,3 @@ CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m # CONFIG_CRYPTO_ANSI_CPRNG is not set -CONFIG_CRC16=m diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h index 994d21939676..affebb78f5d6 100644 --- a/arch/mips/include/asm/fpu.h +++ b/arch/mips/include/asm/fpu.h @@ -64,7 +64,7 @@ static inline int __enable_fpu(enum fpu_mode mode) return SIGFPE; /* set FRE */ - write_c0_config5(read_c0_config5() | MIPS_CONF5_FRE); + set_c0_config5(MIPS_CONF5_FRE); goto fr_common; case FPU_64BIT: @@ -74,8 +74,10 @@ static inline int __enable_fpu(enum fpu_mode mode) #endif /* fall through */ case FPU_32BIT: - /* clear FRE */ - write_c0_config5(read_c0_config5() & ~MIPS_CONF5_FRE); + if (cpu_has_fre) { + /* clear FRE */ + clear_c0_config5(MIPS_CONF5_FRE); + } fr_common: /* set CU1 & change FR appropriately */ fr = (int)mode & FPU_FR_MASK; @@ -182,25 +184,32 @@ static inline int init_fpu(void) int ret = 0; if (cpu_has_fpu) { + unsigned int config5; + ret = __own_fpu(); - if (!ret) { - unsigned int config5 = read_c0_config5(); - - /* - * Ensure FRE is clear whilst running _init_fpu, since - * single precision FP instructions are used. If FRE - * was set then we'll just end up initialising all 32 - * 64b registers. - */ - write_c0_config5(config5 & ~MIPS_CONF5_FRE); - enable_fpu_hazard(); + if (ret) + return ret; + if (!cpu_has_fre) { _init_fpu(); - /* Restore FRE */ - write_c0_config5(config5); - enable_fpu_hazard(); + return 0; } + + /* + * Ensure FRE is clear whilst running _init_fpu, since + * single precision FP instructions are used. If FRE + * was set then we'll just end up initialising all 32 + * 64b registers. + */ + config5 = clear_c0_config5(MIPS_CONF5_FRE); + enable_fpu_hazard(); + + _init_fpu(); + + /* Restore FRE */ + write_c0_config5(config5); + enable_fpu_hazard(); } else fpu_emulator_init_fpu(); diff --git a/arch/mips/include/asm/fw/arc/hinv.h b/arch/mips/include/asm/fw/arc/hinv.h index f8d37d1df5de..9fac64a26353 100644 --- a/arch/mips/include/asm/fw/arc/hinv.h +++ b/arch/mips/include/asm/fw/arc/hinv.h @@ -119,7 +119,7 @@ union key_u { #define SGI_ARCS_REV 10 /* rev .10, 3/04/92 */ #endif -typedef struct component { +typedef struct { CONFIGCLASS Class; CONFIGTYPE Type; IDENTIFIERFLAG Flags; @@ -140,7 +140,7 @@ struct cfgdata { }; /* System ID */ -typedef struct systemid { +typedef struct { CHAR VendorId[8]; CHAR ProductId[8]; } SYSTEMID; @@ -166,7 +166,7 @@ typedef enum memorytype { #endif /* _NT_PROM */ } MEMORYTYPE; -typedef struct memorydescriptor { +typedef struct { MEMORYTYPE Type; LONG BasePage; LONG PageCount; diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index b95a827d763e..59c0901bdd84 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -89,9 +89,9 @@ static inline bool mips_cm_has_l2sync(void) /* Macros to ease the creation of register access functions */ #define BUILD_CM_R_(name, off) \ -static inline u32 *addr_gcr_##name(void) \ +static inline u32 __iomem *addr_gcr_##name(void) \ { \ - return (u32 *)(mips_cm_base + (off)); \ + return (u32 __iomem *)(mips_cm_base + (off)); \ } \ \ static inline u32 read_gcr_##name(void) \ diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 5e4aef304b02..5b720d8c2745 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -1386,12 +1386,27 @@ do { \ __res; \ }) +#define _write_32bit_cp1_register(dest, val, gas_hardfloat) \ +do { \ + __asm__ __volatile__( \ + " .set push \n" \ + " .set reorder \n" \ + " "STR(gas_hardfloat)" \n" \ + " ctc1 %0,"STR(dest)" \n" \ + " .set pop \n" \ + : : "r" (val)); \ +} while (0) + #ifdef GAS_HAS_SET_HARDFLOAT #define read_32bit_cp1_register(source) \ _read_32bit_cp1_register(source, .set hardfloat) +#define write_32bit_cp1_register(dest, val) \ + _write_32bit_cp1_register(dest, val, .set hardfloat) #else #define read_32bit_cp1_register(source) \ _read_32bit_cp1_register(source, ) +#define write_32bit_cp1_register(dest, val) \ + _write_32bit_cp1_register(dest, val, ) #endif #ifdef HAVE_AS_DSP diff --git a/arch/mips/include/asm/pgtable-32.h b/arch/mips/include/asm/pgtable-32.h index 68984b612f9d..a6be006b6f75 100644 --- a/arch/mips/include/asm/pgtable-32.h +++ b/arch/mips/include/asm/pgtable-32.h @@ -57,7 +57,7 @@ extern int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, #define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t)) #define USER_PTRS_PER_PGD (0x80000000UL/PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define VMALLOC_START MAP_BASE @@ -161,22 +161,6 @@ pfn_pte(unsigned long pfn, pgprot_t prot) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -/* - * Encode and decode a nonlinear file mapping entry - */ -#define pte_to_pgoff(_pte) ((((_pte).pte >> 1 ) & 0x07) | \ - (((_pte).pte >> 2 ) & 0x38) | \ - (((_pte).pte >> 10) << 6 )) - -#define pgoff_to_pte(off) ((pte_t) { (((off) & 0x07) << 1 ) | \ - (((off) & 0x38) << 2 ) | \ - (((off) >> 6 ) << 10) | \ - _PAGE_FILE }) - -/* - * Bits 0, 4, 8, and 9 are taken, split up 28 bits of offset into this range: - */ -#define PTE_FILE_MAX_BITS 28 #else #if defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) @@ -188,13 +172,6 @@ pfn_pte(unsigned long pfn, pgprot_t prot) #define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_high }) #define __swp_entry_to_pte(x) ((pte_t) { 0, (x).val }) -/* - * Bits 0 and 1 of pte_high are taken, use the rest for the page offset... - */ -#define pte_to_pgoff(_pte) ((_pte).pte_high >> 2) -#define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) << 2 }) - -#define PTE_FILE_MAX_BITS 30 #else /* * Constraints: @@ -209,19 +186,6 @@ pfn_pte(unsigned long pfn, pgprot_t prot) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -/* - * Encode and decode a nonlinear file mapping entry - */ -#define pte_to_pgoff(_pte) ((((_pte).pte >> 1) & 0x7) | \ - (((_pte).pte >> 2) & 0x8) | \ - (((_pte).pte >> 8) << 4)) - -#define pgoff_to_pte(off) ((pte_t) { (((off) & 0x7) << 1) | \ - (((off) & 0x8) << 2) | \ - (((off) >> 4) << 8) | \ - _PAGE_FILE }) - -#define PTE_FILE_MAX_BITS 28 #endif /* defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) */ #endif /* defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) */ diff --git a/arch/mips/include/asm/pgtable-64.h b/arch/mips/include/asm/pgtable-64.h index e1c49a96807d..1659bb91ae21 100644 --- a/arch/mips/include/asm/pgtable-64.h +++ b/arch/mips/include/asm/pgtable-64.h @@ -291,13 +291,4 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -/* - * Bits 0, 4, 6, and 7 are taken. Let's leave bits 1, 2, 3, and 5 alone to - * make things easier, and only use the upper 56 bits for the page offset... - */ -#define PTE_FILE_MAX_BITS 56 - -#define pte_to_pgoff(_pte) ((_pte).pte >> 8) -#define pgoff_to_pte(off) ((pte_t) { ((off) << 8) | _PAGE_FILE }) - #endif /* _ASM_PGTABLE_64_H */ diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h index ca11f14f40a3..fc807aa5ec8d 100644 --- a/arch/mips/include/asm/pgtable-bits.h +++ b/arch/mips/include/asm/pgtable-bits.h @@ -48,8 +48,6 @@ /* * The following bits are implemented in software - * - * _PAGE_FILE semantics: set:pagecache unset:swap */ #define _PAGE_PRESENT_SHIFT (_CACHE_SHIFT + 3) #define _PAGE_PRESENT (1 << _PAGE_PRESENT_SHIFT) @@ -64,7 +62,6 @@ #define _PAGE_SILENT_READ _PAGE_VALID #define _PAGE_SILENT_WRITE _PAGE_DIRTY -#define _PAGE_FILE _PAGE_MODIFIED #define _PFN_SHIFT (PAGE_SHIFT - 12 + _CACHE_SHIFT + 3) @@ -72,8 +69,6 @@ /* * The following are implemented by software - * - * _PAGE_FILE semantics: set:pagecache unset:swap */ #define _PAGE_PRESENT_SHIFT 0 #define _PAGE_PRESENT (1 << _PAGE_PRESENT_SHIFT) @@ -85,8 +80,6 @@ #define _PAGE_ACCESSED (1 << _PAGE_ACCESSED_SHIFT) #define _PAGE_MODIFIED_SHIFT 4 #define _PAGE_MODIFIED (1 << _PAGE_MODIFIED_SHIFT) -#define _PAGE_FILE_SHIFT 4 -#define _PAGE_FILE (1 << _PAGE_FILE_SHIFT) /* * And these are the hardware TLB bits @@ -116,7 +109,6 @@ * The following bits are implemented in software * * _PAGE_READ / _PAGE_READ_SHIFT should be unused if cpu_has_rixi. - * _PAGE_FILE semantics: set:pagecache unset:swap */ #define _PAGE_PRESENT_SHIFT (0) #define _PAGE_PRESENT (1 << _PAGE_PRESENT_SHIFT) @@ -128,7 +120,6 @@ #define _PAGE_ACCESSED (1 << _PAGE_ACCESSED_SHIFT) #define _PAGE_MODIFIED_SHIFT (_PAGE_ACCESSED_SHIFT + 1) #define _PAGE_MODIFIED (1 << _PAGE_MODIFIED_SHIFT) -#define _PAGE_FILE (_PAGE_MODIFIED) #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT /* huge tlb page */ diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 62a6ba383d4f..583ff4215479 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -231,7 +231,6 @@ extern pgd_t swapper_pg_dir[]; static inline int pte_write(pte_t pte) { return pte.pte_low & _PAGE_WRITE; } static inline int pte_dirty(pte_t pte) { return pte.pte_low & _PAGE_MODIFIED; } static inline int pte_young(pte_t pte) { return pte.pte_low & _PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) { return pte.pte_low & _PAGE_FILE; } static inline pte_t pte_wrprotect(pte_t pte) { @@ -287,7 +286,6 @@ static inline pte_t pte_mkyoung(pte_t pte) static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_MODIFIED; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } static inline pte_t pte_wrprotect(pte_t pte) { diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h index bb7963753730..6499d93ae68d 100644 --- a/arch/mips/include/asm/syscall.h +++ b/arch/mips/include/asm/syscall.h @@ -29,13 +29,7 @@ static inline long syscall_get_nr(struct task_struct *task, struct pt_regs *regs) { - /* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */ - if ((config_enabled(CONFIG_32BIT) || - test_tsk_thread_flag(task, TIF_32BIT_REGS)) && - (regs->regs[2] == __NR_syscall)) - return regs->regs[4]; - else - return regs->regs[2]; + return current_thread_info()->syscall; } static inline unsigned long mips_get_syscall_arg(unsigned long *arg, diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index 99eea59604e9..e4440f92b366 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -36,6 +36,7 @@ struct thread_info { */ struct restart_block restart_block; struct pt_regs *regs; + long syscall; /* syscall number */ }; /* diff --git a/arch/mips/include/uapi/asm/unistd.h b/arch/mips/include/uapi/asm/unistd.h index d001bb1ad177..c03088f9f514 100644 --- a/arch/mips/include/uapi/asm/unistd.h +++ b/arch/mips/include/uapi/asm/unistd.h @@ -376,16 +376,17 @@ #define __NR_getrandom (__NR_Linux + 353) #define __NR_memfd_create (__NR_Linux + 354) #define __NR_bpf (__NR_Linux + 355) +#define __NR_execveat (__NR_Linux + 356) /* * Offset of the last Linux o32 flavoured syscall */ -#define __NR_Linux_syscalls 355 +#define __NR_Linux_syscalls 356 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ #define __NR_O32_Linux 4000 -#define __NR_O32_Linux_syscalls 355 +#define __NR_O32_Linux_syscalls 356 #if _MIPS_SIM == _MIPS_SIM_ABI64 @@ -709,16 +710,17 @@ #define __NR_getrandom (__NR_Linux + 313) #define __NR_memfd_create (__NR_Linux + 314) #define __NR_bpf (__NR_Linux + 315) +#define __NR_execveat (__NR_Linux + 316) /* * Offset of the last Linux 64-bit flavoured syscall */ -#define __NR_Linux_syscalls 315 +#define __NR_Linux_syscalls 316 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ #define __NR_64_Linux 5000 -#define __NR_64_Linux_syscalls 315 +#define __NR_64_Linux_syscalls 316 #if _MIPS_SIM == _MIPS_SIM_NABI32 @@ -1046,15 +1048,16 @@ #define __NR_getrandom (__NR_Linux + 317) #define __NR_memfd_create (__NR_Linux + 318) #define __NR_bpf (__NR_Linux + 319) +#define __NR_execveat (__NR_Linux + 320) /* * Offset of the last N32 flavoured syscall */ -#define __NR_Linux_syscalls 319 +#define __NR_Linux_syscalls 320 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ #define __NR_N32_Linux 6000 -#define __NR_N32_Linux_syscalls 319 +#define __NR_N32_Linux_syscalls 320 #endif /* _UAPI_ASM_UNISTD_H */ diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c index 2531da1d3add..97206b3deb97 100644 --- a/arch/mips/jz4740/irq.c +++ b/arch/mips/jz4740/irq.c @@ -30,6 +30,9 @@ #include #include +#include + +#include "irq.h" static void __iomem *jz_intc_base; diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index c92b15df6893..a5b5b56485c1 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -19,8 +19,8 @@ enum { int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf, bool is_interp, struct arch_elf_state *state) { - struct elfhdr *ehdr = _ehdr; - struct elf_phdr *phdr = _phdr; + struct elf32_hdr *ehdr = _ehdr; + struct elf32_phdr *phdr = _phdr; struct mips_elf_abiflags_v0 abiflags; int ret; @@ -48,7 +48,7 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf, return 0; } -static inline unsigned get_fp_abi(struct elfhdr *ehdr, int in_abi) +static inline unsigned get_fp_abi(struct elf32_hdr *ehdr, int in_abi) { /* If the ABI requirement is provided, simply return that */ if (in_abi != -1) @@ -65,7 +65,7 @@ static inline unsigned get_fp_abi(struct elfhdr *ehdr, int in_abi) int arch_check_elf(void *_ehdr, bool has_interpreter, struct arch_elf_state *state) { - struct elfhdr *ehdr = _ehdr; + struct elf32_hdr *ehdr = _ehdr; unsigned fp_abi, interp_fp_abi, abi0, abi1; /* Ignore non-O32 binaries */ diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index 590c2c980fd3..6eb7a3f515fc 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -57,6 +57,8 @@ static struct irq_chip mips_cpu_irq_controller = { .irq_mask_ack = mask_mips_irq, .irq_unmask = unmask_mips_irq, .irq_eoi = unmask_mips_irq, + .irq_disable = mask_mips_irq, + .irq_enable = unmask_mips_irq, }; /* @@ -93,6 +95,8 @@ static struct irq_chip mips_mt_cpu_irq_controller = { .irq_mask_ack = mips_mt_cpu_irq_ack, .irq_unmask = unmask_mips_irq, .irq_eoi = unmask_mips_irq, + .irq_disable = mask_mips_irq, + .irq_enable = unmask_mips_irq, }; asmlinkage void __weak plat_irq_dispatch(void) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index eb76434828e8..85bff5d513e5 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -82,6 +82,30 @@ void flush_thread(void) { } +int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) +{ + /* + * Save any process state which is live in hardware registers to the + * parent context prior to duplication. This prevents the new child + * state becoming stale if the parent is preempted before copy_thread() + * gets a chance to save the parent's live hardware registers to the + * child context. + */ + preempt_disable(); + + if (is_msa_enabled()) + save_msa(current); + else if (is_fpu_owner()) + _save_fp(current); + + save_dsp(current); + + preempt_enable(); + + *dst = *src; + return 0; +} + int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, struct task_struct *p) { @@ -92,18 +116,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, childksp = (unsigned long)task_stack_page(p) + THREAD_SIZE - 32; - preempt_disable(); - - if (is_msa_enabled()) - save_msa(p); - else if (is_fpu_owner()) - save_fp(p); - - if (cpu_has_dsp) - save_dsp(p); - - preempt_enable(); - /* set up new TSS. */ childregs = (struct pt_regs *) childksp - 1; /* Put the stack after the struct pt_regs. */ diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 9d1487d83293..510452812594 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -770,6 +770,8 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall) long ret = 0; user_exit(); + current_thread_info()->syscall = syscall; + if (secure_computing() == -1) return -1; diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 00cad1005a16..6e8de80bb446 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -181,6 +181,7 @@ illegal_syscall: sll t1, t0, 2 beqz v0, einval lw t2, sys_call_table(t1) # syscall routine + sw a0, PT_R2(sp) # call routine directly on restart /* Some syscalls like execve get their arguments from struct pt_regs and claim zero arguments in the syscall table. Thus we have to @@ -580,3 +581,4 @@ EXPORT(sys_call_table) PTR sys_getrandom PTR sys_memfd_create PTR sys_bpf /* 4355 */ + PTR sys_execveat diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 5251565e344b..ad4d44635c76 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -435,4 +435,5 @@ EXPORT(sys_call_table) PTR sys_getrandom PTR sys_memfd_create PTR sys_bpf /* 5315 */ + PTR sys_execveat .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 77e74398b828..446cc654da56 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -428,4 +428,5 @@ EXPORT(sysn32_call_table) PTR sys_getrandom PTR sys_memfd_create PTR sys_bpf + PTR compat_sys_execveat /* 6320 */ .size sysn32_call_table,.-sysn32_call_table diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 6f8db9f728e8..d07b210fbeff 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -186,6 +186,7 @@ LEAF(sys32_syscall) dsll t1, t0, 3 beqz v0, einval ld t2, sys32_call_table(t1) # syscall routine + sd a0, PT_R2(sp) # call routine directly on restart move a0, a1 # shift argument registers move a1, a2 @@ -565,4 +566,5 @@ EXPORT(sys32_call_table) PTR sys_getrandom PTR sys_memfd_create PTR sys_bpf /* 4355 */ + PTR compat_sys_execveat .size sys32_call_table,.-sys32_call_table diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c index 1e0a93c5a3e7..e36a859af666 100644 --- a/arch/mips/kernel/smp-cmp.c +++ b/arch/mips/kernel/smp-cmp.c @@ -44,8 +44,8 @@ static void cmp_init_secondary(void) struct cpuinfo_mips *c __maybe_unused = ¤t_cpu_data; /* Assume GIC is present */ - change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP6 | - STATUSF_IP7); + change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | + STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7); /* Enable per-cpu interrupts: platform specific */ diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index ad86951b73bd..17ea705f6c40 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c @@ -161,7 +161,8 @@ static void vsmp_init_secondary(void) #ifdef CONFIG_MIPS_GIC /* This is Malta specific: IPI,performance and timer interrupts */ if (gic_present) - change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | + change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | + STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7); else #endif diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index c94c4e92e17d..1c0d8c50b7e1 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -123,10 +123,10 @@ asmlinkage void start_secondary(void) unsigned int cpu; cpu_probe(); - cpu_report(); per_cpu_trap_init(false); mips_clockevent_init(); mp_ops->init_secondary(); + cpu_report(); /* * XXX parity protection should be folded in here when it's converted diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index ad3d2031c327..c3b41e24c05a 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1231,7 +1231,8 @@ static int enable_restore_fp_context(int msa) /* Restore the scalar FP control & status register */ if (!was_fpu_owner) - asm volatile("ctc1 %0, $31" : : "r"(current->thread.fpu.fcr31)); + write_32bit_cp1_register(CP1_STATUS, + current->thread.fpu.fcr31); } out: diff --git a/arch/mips/kvm/Kconfig b/arch/mips/kvm/Kconfig index 30e334e823bd..2ae12825529f 100644 --- a/arch/mips/kvm/Kconfig +++ b/arch/mips/kvm/Kconfig @@ -20,6 +20,7 @@ config KVM select PREEMPT_NOTIFIERS select ANON_INODES select KVM_MMIO + select SRCU ---help--- Support for hosting Guest kernels. Currently supported on MIPS32 processors. diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index becc42bb1849..70ab5d664332 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -158,6 +158,8 @@ good_area: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/mips/mm/gup.c b/arch/mips/mm/gup.c index 70795a67a276..349995d19c7f 100644 --- a/arch/mips/mm/gup.c +++ b/arch/mips/mm/gup.c @@ -301,11 +301,9 @@ slow_irqon: start += nr << PAGE_SHIFT; pages += nr; - down_read(&mm->mmap_sem); - ret = get_user_pages(current, mm, start, - (end - start) >> PAGE_SHIFT, - write, 0, pages, NULL); - up_read(&mm->mmap_sem); + ret = get_user_pages_unlocked(current, mm, start, + (end - start) >> PAGE_SHIFT, + write, 0, pages); /* Have to be a bit careful with return values */ if (nr > 0) { diff --git a/arch/mips/mm/hugetlbpage.c b/arch/mips/mm/hugetlbpage.c index 4ec8ee10d371..06e0f421b41b 100644 --- a/arch/mips/mm/hugetlbpage.c +++ b/arch/mips/mm/hugetlbpage.c @@ -68,12 +68,6 @@ int is_aligned_hugepage_range(unsigned long addr, unsigned long len) return 0; } -struct page * -follow_huge_addr(struct mm_struct *mm, unsigned long address, int write) -{ - return ERR_PTR(-EINVAL); -} - int pmd_huge(pmd_t pmd) { return (pmd_val(pmd) & _PAGE_HUGE) != 0; @@ -83,15 +77,3 @@ int pud_huge(pud_t pud) { return (pud_val(pud) & _PAGE_HUGE) != 0; } - -struct page * -follow_huge_pmd(struct mm_struct *mm, unsigned long address, - pmd_t *pmd, int write) -{ - struct page *page; - - page = pte_page(*(pte_t *)pmd); - if (page) - page += ((address & ~HPAGE_MASK) >> PAGE_SHIFT); - return page; -} diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index e90b2e899291..30639a6e9b8c 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -489,6 +489,8 @@ static void r4k_tlb_configure(void) #ifdef CONFIG_64BIT pg |= PG_ELPA; #endif + if (cpu_has_rixiex) + pg |= PG_IEC; write_c0_pagegrain(pg); } diff --git a/arch/mips/net/bpf_jit.c b/arch/mips/net/bpf_jit.c index 9fd6834a2172..5d6139390bf8 100644 --- a/arch/mips/net/bpf_jit.c +++ b/arch/mips/net/bpf_jit.c @@ -1388,7 +1388,7 @@ out: void bpf_jit_free(struct bpf_prog *fp) { if (fp->jited) - module_free(NULL, fp->bpf_func); + module_memfree(fp->bpf_func); bpf_prog_unlock_free(fp); } diff --git a/arch/mips/pci/pci-bcm1480.c b/arch/mips/pci/pci-bcm1480.c index 5ec2a7bae02c..f2355e3e65a1 100644 --- a/arch/mips/pci/pci-bcm1480.c +++ b/arch/mips/pci/pci-bcm1480.c @@ -173,8 +173,8 @@ static int bcm1480_pcibios_write(struct pci_bus *bus, unsigned int devfn, } struct pci_ops bcm1480_pci_ops = { - bcm1480_pcibios_read, - bcm1480_pcibios_write, + .read = bcm1480_pcibios_read, + .write = bcm1480_pcibios_write, }; static struct resource bcm1480_mem_resource = { diff --git a/arch/mips/pci/pci-octeon.c b/arch/mips/pci/pci-octeon.c index d07e04121cc6..bedb72bd3a27 100644 --- a/arch/mips/pci/pci-octeon.c +++ b/arch/mips/pci/pci-octeon.c @@ -327,8 +327,8 @@ static int octeon_write_config(struct pci_bus *bus, unsigned int devfn, static struct pci_ops octeon_pci_ops = { - octeon_read_config, - octeon_write_config, + .read = octeon_read_config, + .write = octeon_write_config, }; static struct resource octeon_pci_mem_resource = { diff --git a/arch/mips/pci/pcie-octeon.c b/arch/mips/pci/pcie-octeon.c index 5e36c33e5543..eb4a17ba4a53 100644 --- a/arch/mips/pci/pcie-octeon.c +++ b/arch/mips/pci/pcie-octeon.c @@ -1792,8 +1792,8 @@ static int octeon_dummy_write_config(struct pci_bus *bus, unsigned int devfn, } static struct pci_ops octeon_pcie0_ops = { - octeon_pcie0_read_config, - octeon_pcie0_write_config, + .read = octeon_pcie0_read_config, + .write = octeon_pcie0_write_config, }; static struct resource octeon_pcie0_mem_resource = { @@ -1813,8 +1813,8 @@ static struct pci_controller octeon_pcie0_controller = { }; static struct pci_ops octeon_pcie1_ops = { - octeon_pcie1_read_config, - octeon_pcie1_write_config, + .read = octeon_pcie1_read_config, + .write = octeon_pcie1_write_config, }; static struct resource octeon_pcie1_mem_resource = { @@ -1834,8 +1834,8 @@ static struct pci_controller octeon_pcie1_controller = { }; static struct pci_ops octeon_dummy_ops = { - octeon_dummy_read_config, - octeon_dummy_write_config, + .read = octeon_dummy_read_config, + .write = octeon_dummy_write_config, }; static struct resource octeon_dummy_mem_resource = { diff --git a/arch/mn10300/include/asm/cacheflush.h b/arch/mn10300/include/asm/cacheflush.h index faed90240ded..6d6df839948f 100644 --- a/arch/mn10300/include/asm/cacheflush.h +++ b/arch/mn10300/include/asm/cacheflush.h @@ -159,13 +159,6 @@ extern void flush_icache_range(unsigned long start, unsigned long end); #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ memcpy(dst, src, len) -/* - * Internal debugging function - */ -#ifdef CONFIG_DEBUG_PAGEALLOC -extern void kernel_map_pages(struct page *page, int numpages, int enable); -#endif - #endif /* __ASSEMBLY__ */ #endif /* _ASM_CACHEFLUSH_H */ diff --git a/arch/mn10300/include/asm/pgtable.h b/arch/mn10300/include/asm/pgtable.h index 2ddaa67e7983..afab728ab65e 100644 --- a/arch/mn10300/include/asm/pgtable.h +++ b/arch/mn10300/include/asm/pgtable.h @@ -65,7 +65,7 @@ extern void paging_init(void); #define PGDIR_MASK (~(PGDIR_SIZE - 1)) #define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT) #define KERNEL_PGD_PTRS (PTRS_PER_PGD - USER_PGD_PTRS) @@ -134,7 +134,6 @@ extern pte_t kernel_vmalloc_ptes[(VMALLOC_END - VMALLOC_START) / PAGE_SIZE]; #define _PAGE_NX 0 /* no-execute bit */ /* If _PAGE_VALID is clear, we use these: */ -#define _PAGE_FILE xPTEL2_C /* set:pagecache unset:swap */ #define _PAGE_PROTNONE 0x000 /* If not present */ #define __PAGE_PROT_UWAUX 0x010 @@ -241,11 +240,6 @@ static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } static inline int pte_write(pte_t pte) { return pte_val(pte) & __PAGE_PROT_WRITE; } static inline int pte_special(pte_t pte){ return 0; } -/* - * The following only works if pte_present() is not true. - */ -static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } - static inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) &= ~(__PAGE_PROT_USER|__PAGE_PROT_UWAUX); return pte; @@ -338,16 +332,11 @@ static inline int pte_exec_kernel(pte_t pte) return 1; } -#define PTE_FILE_MAX_BITS 30 - -#define pte_to_pgoff(pte) (pte_val(pte) >> 2) -#define pgoff_to_pte(off) __pte((off) << 2 | _PAGE_FILE) - /* Encode and de-code a swap entry */ -#define __swp_type(x) (((x).val >> 2) & 0x3f) -#define __swp_offset(x) ((x).val >> 8) +#define __swp_type(x) (((x).val >> 1) & 0x3f) +#define __swp_offset(x) ((x).val >> 7) #define __swp_entry(type, offset) \ - ((swp_entry_t) { ((type) << 2) | ((offset) << 8) }) + ((swp_entry_t) { ((type) << 1) | ((offset) << 7) }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) __pte((x).val) diff --git a/arch/mn10300/mm/fault.c b/arch/mn10300/mm/fault.c index 3516cbdf1ee9..0c2cc5d39c8e 100644 --- a/arch/mn10300/mm/fault.c +++ b/arch/mn10300/mm/fault.c @@ -262,6 +262,8 @@ good_area: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.c b/arch/mn10300/unit-asb2305/pci-asb2305.c index febb9cd83177..b5b036f64275 100644 --- a/arch/mn10300/unit-asb2305/pci-asb2305.c +++ b/arch/mn10300/unit-asb2305/pci-asb2305.c @@ -106,7 +106,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) if (!r->flags) continue; if (!r->start || - pci_claim_resource(dev, idx) < 0) { + pci_claim_bridge_resource(dev, idx) < 0) { printk(KERN_ERR "PCI:" " Cannot allocate resource" " region %d of bridge %s\n", diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c index 6b4339f8c9c2..613ca1e55b4b 100644 --- a/arch/mn10300/unit-asb2305/pci.c +++ b/arch/mn10300/unit-asb2305/pci.c @@ -228,8 +228,8 @@ static int pci_ampci_write_config(struct pci_bus *bus, unsigned int devfn, } static struct pci_ops pci_direct_ampci = { - pci_ampci_read_config, - pci_ampci_write_config, + .read = pci_ampci_read_config, + .write = pci_ampci_write_config, }; /* @@ -281,42 +281,37 @@ static int __init pci_check_direct(void) return -ENODEV; } -static int is_valid_resource(struct pci_dev *dev, int idx) -{ - unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM; - struct resource *devr = &dev->resource[idx], *busr; - - if (dev->bus) { - pci_bus_for_each_resource(dev->bus, busr, i) { - if (!busr || (busr->flags ^ devr->flags) & type_mask) - continue; - - if (devr->start && - devr->start >= busr->start && - devr->end <= busr->end) - return 1; - } - } - - return 0; -} - static void pcibios_fixup_device_resources(struct pci_dev *dev) { - int limit, i; + int idx; - if (dev->bus->number != 0) + if (!dev->bus) return; - limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ? - PCI_BRIDGE_RESOURCES : PCI_NUM_RESOURCES; + for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) { + struct resource *r = &dev->resource[idx]; - for (i = 0; i < limit; i++) { - if (!dev->resource[i].flags) + if (!r->flags || r->parent || !r->start) continue; - if (is_valid_resource(dev, i)) - pci_claim_resource(dev, i); + pci_claim_resource(dev, idx); + } +} + +static void pcibios_fixup_bridge_resources(struct pci_dev *dev) +{ + int idx; + + if (!dev->bus) + return; + + for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { + struct resource *r = &dev->resource[idx]; + + if (!r->flags || r->parent || !r->start) + continue; + + pci_claim_bridge_resource(dev, idx); } } @@ -330,7 +325,7 @@ void pcibios_fixup_bus(struct pci_bus *bus) if (bus->self) { pci_read_bridge_bases(bus); - pcibios_fixup_device_resources(bus->self); + pcibios_fixup_bridge_resources(bus->self); } list_for_each_entry(dev, &bus->devices, bus_list) diff --git a/arch/nios2/include/asm/pgtable-bits.h b/arch/nios2/include/asm/pgtable-bits.h index ce9e7069aa96..bfddff383e89 100644 --- a/arch/nios2/include/asm/pgtable-bits.h +++ b/arch/nios2/include/asm/pgtable-bits.h @@ -30,6 +30,5 @@ #define _PAGE_PRESENT (1<<25) /* PTE contains a translation */ #define _PAGE_ACCESSED (1<<26) /* page referenced */ #define _PAGE_DIRTY (1<<27) /* dirty page */ -#define _PAGE_FILE (1<<28) /* PTE used for file mapping or swap */ #endif /* _ASM_NIOS2_PGTABLE_BITS_H */ diff --git a/arch/nios2/include/asm/pgtable.h b/arch/nios2/include/asm/pgtable.h index ccbaffd47671..a213e8c9aad0 100644 --- a/arch/nios2/include/asm/pgtable.h +++ b/arch/nios2/include/asm/pgtable.h @@ -24,7 +24,7 @@ #include #include -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define VMALLOC_START CONFIG_NIOS2_KERNEL_MMU_REGION_BASE #define VMALLOC_END (CONFIG_NIOS2_KERNEL_REGION_BASE - 1) @@ -112,8 +112,6 @@ static inline int pte_dirty(pte_t pte) \ { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) \ { return pte_val(pte) & _PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) \ - { return pte_val(pte) & _PAGE_FILE; } static inline int pte_special(pte_t pte) { return 0; } #define pgprot_noncached pgprot_noncached @@ -272,8 +270,7 @@ static inline void pte_clear(struct mm_struct *mm, __FILE__, __LINE__, pgd_val(e)) /* - * Encode and decode a swap entry (must be !pte_none(pte) && !pte_present(pte) - * && !pte_file(pte)): + * Encode and decode a swap entry (must be !pte_none(pte) && !pte_present(pte): * * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 ... 1 0 * 0 0 0 0 type. 0 0 0 0 0 0 offset......... @@ -290,11 +287,6 @@ static inline void pte_clear(struct mm_struct *mm, #define __swp_entry_to_pte(swp) ((pte_t) { (swp).val }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -/* Encode and decode a nonlinear file mapping entry */ -#define PTE_FILE_MAX_BITS 25 -#define pte_to_pgoff(pte) (pte_val(pte) & 0x1ffffff) -#define pgoff_to_pte(off) __pte(((off) & 0x1ffffff) | _PAGE_FILE) - #define kern_addr_valid(addr) (1) #include diff --git a/arch/nios2/kernel/module.c b/arch/nios2/kernel/module.c index cc924a38f22a..e2e3f13f98d5 100644 --- a/arch/nios2/kernel/module.c +++ b/arch/nios2/kernel/module.c @@ -36,7 +36,7 @@ void *module_alloc(unsigned long size) } /* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) +void module_memfree(void *module_region) { kfree(module_region); } diff --git a/arch/nios2/kernel/signal.c b/arch/nios2/kernel/signal.c index f9d27883a714..2d0ea25be171 100644 --- a/arch/nios2/kernel/signal.c +++ b/arch/nios2/kernel/signal.c @@ -200,7 +200,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, /* Set up to return from userspace; jump to fixed address sigreturn trampoline on kuser page. */ - regs->ra = (unsigned long) (0x1040); + regs->ra = (unsigned long) (0x1044); /* Set up registers for signal handler */ regs->sp = (unsigned long) frame; diff --git a/arch/nios2/mm/fault.c b/arch/nios2/mm/fault.c index 15a0bb5fc06d..d194c0427b26 100644 --- a/arch/nios2/mm/fault.c +++ b/arch/nios2/mm/fault.c @@ -135,6 +135,8 @@ survive: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); @@ -157,9 +159,11 @@ bad_area: bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ if (user_mode(regs)) { - pr_alert("%s: unhandled page fault (%d) at 0x%08lx, " - "cause %ld\n", current->comm, SIGSEGV, address, cause); - show_regs(regs); + if (unhandled_signal(current, SIGSEGV) && printk_ratelimit()) { + pr_info("%s: unhandled page fault (%d) at 0x%08lx, " + "cause %ld\n", current->comm, SIGSEGV, address, cause); + show_regs(regs); + } _exception(SIGSEGV, regs, code, address); return; } diff --git a/arch/openrisc/include/asm/pgtable.h b/arch/openrisc/include/asm/pgtable.h index 37bf6a3ef8f4..69c7df0e1420 100644 --- a/arch/openrisc/include/asm/pgtable.h +++ b/arch/openrisc/include/asm/pgtable.h @@ -77,7 +77,7 @@ extern void paging_init(void); */ #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL /* * Kernels own virtual memory area. @@ -125,7 +125,6 @@ extern void paging_init(void); #define _PAGE_CC 0x001 /* software: pte contains a translation */ #define _PAGE_CI 0x002 /* cache inhibit */ #define _PAGE_WBC 0x004 /* write back cache */ -#define _PAGE_FILE 0x004 /* set: pagecache, unset: swap (when !PRESENT) */ #define _PAGE_WOM 0x008 /* weakly ordered memory */ #define _PAGE_A 0x010 /* accessed */ @@ -240,7 +239,6 @@ static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC; } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } static inline int pte_special(pte_t pte) { return 0; } static inline pte_t pte_mkspecial(pte_t pte) { return pte; } @@ -438,12 +436,6 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -/* Encode and decode a nonlinear file mapping entry */ - -#define PTE_FILE_MAX_BITS 26 -#define pte_to_pgoff(x) (pte_val(x) >> 6) -#define pgoff_to_pte(x) __pte(((x) << 6) | _PAGE_FILE) - #define kern_addr_valid(addr) (1) #include diff --git a/arch/openrisc/kernel/head.S b/arch/openrisc/kernel/head.S index 1d3c9c28ac25..f14793306b03 100644 --- a/arch/openrisc/kernel/head.S +++ b/arch/openrisc/kernel/head.S @@ -754,11 +754,6 @@ _dc_enable: /* ===============================================[ page table masks ]=== */ -/* bit 4 is used in hardware as write back cache bit. we never use this bit - * explicitly, so we can reuse it as _PAGE_FILE bit and mask it out when - * writing into hardware pte's - */ - #define DTLB_UP_CONVERT_MASK 0x3fa #define ITLB_UP_CONVERT_MASK 0x3a diff --git a/arch/openrisc/mm/fault.c b/arch/openrisc/mm/fault.c index 0703acf7d327..230ac20ae794 100644 --- a/arch/openrisc/mm/fault.c +++ b/arch/openrisc/mm/fault.c @@ -171,6 +171,8 @@ good_area: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h index 22b89d1edba7..8c966b2270aa 100644 --- a/arch/parisc/include/asm/pgtable.h +++ b/arch/parisc/include/asm/pgtable.h @@ -134,7 +134,7 @@ extern void purge_tlb_entries(struct mm_struct *, unsigned long); * pgd entries used up by user/kernel: */ -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL /* NB: The tlb miss handlers make certain assumptions about the order */ /* of the following bits, so be careful (One example, bits 25-31 */ @@ -146,7 +146,6 @@ extern void purge_tlb_entries(struct mm_struct *, unsigned long); #define _PAGE_GATEWAY_BIT 28 /* (0x008) privilege promotion allowed */ #define _PAGE_DMB_BIT 27 /* (0x010) Data Memory Break enable (B bit) */ #define _PAGE_DIRTY_BIT 26 /* (0x020) Page Dirty (D bit) */ -#define _PAGE_FILE_BIT _PAGE_DIRTY_BIT /* overload this bit */ #define _PAGE_REFTRAP_BIT 25 /* (0x040) Page Ref. Trap enable (T bit) */ #define _PAGE_NO_CACHE_BIT 24 /* (0x080) Uncached Page (U bit) */ #define _PAGE_ACCESSED_BIT 23 /* (0x100) Software: Page Accessed */ @@ -167,13 +166,6 @@ extern void purge_tlb_entries(struct mm_struct *, unsigned long); /* PFN_PTE_SHIFT defines the shift of a PTE value to access the PFN field */ #define PFN_PTE_SHIFT 12 - -/* this is how many bits may be used by the file functions */ -#define PTE_FILE_MAX_BITS (BITS_PER_LONG - PTE_SHIFT) - -#define pte_to_pgoff(pte) (pte_val(pte) >> PTE_SHIFT) -#define pgoff_to_pte(off) ((pte_t) { ((off) << PTE_SHIFT) | _PAGE_FILE }) - #define _PAGE_READ (1 << xlate_pabit(_PAGE_READ_BIT)) #define _PAGE_WRITE (1 << xlate_pabit(_PAGE_WRITE_BIT)) #define _PAGE_RW (_PAGE_READ | _PAGE_WRITE) @@ -186,7 +178,6 @@ extern void purge_tlb_entries(struct mm_struct *, unsigned long); #define _PAGE_ACCESSED (1 << xlate_pabit(_PAGE_ACCESSED_BIT)) #define _PAGE_PRESENT (1 << xlate_pabit(_PAGE_PRESENT_BIT)) #define _PAGE_USER (1 << xlate_pabit(_PAGE_USER_BIT)) -#define _PAGE_FILE (1 << xlate_pabit(_PAGE_FILE_BIT)) #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED) #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) @@ -344,7 +335,6 @@ static inline void pgd_clear(pgd_t * pgdp) { } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } -static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } static inline int pte_special(pte_t pte) { return 0; } static inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; } diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index 50dfafc3f2c1..5822e8e200e6 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c @@ -298,14 +298,10 @@ static inline unsigned long count_stubs(const Elf_Rela *rela, unsigned long n) } #endif - -/* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) +void module_arch_freeing_init(struct module *mod) { kfree(mod->arch.section); mod->arch.section = NULL; - - vfree(module_region); } /* Additional bytes needed in front of individual sections */ diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 3ca9c1131cfe..e5120e653240 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -256,6 +256,8 @@ good_area: */ if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto bad_area; BUG(); diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index a2a168e2dfe7..22b0940494bb 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -256,6 +256,7 @@ config PPC_OF_PLATFORM_PCI default n config ARCH_SUPPORTS_DEBUG_PAGEALLOC + depends on PPC32 || PPC_STD_MMU_64 def_bool y config ARCH_SUPPORTS_UPROBES diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi index 1382fec9e8c5..7fcb1ac0f232 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi @@ -50,6 +50,7 @@ ethernet@b0000 { fsl,num_tx_queues = <0x8>; fsl,magic-packet; local-mac-address = [ 00 00 00 00 00 00 ]; + ranges; queue-group@b0000 { #address-cells = <1>; diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec2-1.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec2-1.dtsi index 221cd2ea5b31..9f25427c1527 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec2-1.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec2-1.dtsi @@ -50,6 +50,7 @@ ethernet@b1000 { fsl,num_tx_queues = <0x8>; fsl,magic-packet; local-mac-address = [ 00 00 00 00 00 00 ]; + ranges; queue-group@b1000 { #address-cells = <1>; diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec2-2.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec2-2.dtsi index 61456c317609..cd7c318ab131 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec2-2.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec2-2.dtsi @@ -49,6 +49,7 @@ ethernet@b2000 { fsl,num_tx_queues = <0x8>; fsl,magic-packet; local-mac-address = [ 00 00 00 00 00 00 ]; + ranges; queue-group@b2000 { #address-cells = <1>; diff --git a/arch/powerpc/boot/dts/fsl/pq3-gpio-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-gpio-0.dtsi index 72a3ef5945c1..a1b48546b02d 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-gpio-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-gpio-0.dtsi @@ -1,5 +1,5 @@ /* - * PQ3 GPIO device tree stub [ controller @ offset 0xf000 ] + * PQ3 GPIO device tree stub [ controller @ offset 0xfc00 ] * * Copyright 2011 Freescale Semiconductor Inc. * @@ -32,10 +32,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -gpio-controller@f000 { +gpio-controller@fc00 { #gpio-cells = <2>; compatible = "fsl,pq3-gpio"; - reg = <0xf000 0x100>; + reg = <0xfc00 0x100>; interrupts = <47 0x2 0 0>; gpio-controller; }; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-bman1-portals.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-bman1-portals.dtsi new file mode 100644 index 000000000000..5022432ebaa9 --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/qoriq-bman1-portals.dtsi @@ -0,0 +1,90 @@ +/* + * QorIQ BMan Portal device tree stub for 10 portals + * + * Copyright 2011 - 2014 Freescale Semiconductor Inc. + * + * 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 of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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. + */ + +&bportals { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + + bman-portal@0 { + compatible = "fsl,bman-portal"; + reg = <0x0 0x4000>, <0x100000 0x1000>; + interrupts = <105 2 0 0>; + }; + bman-portal@4000 { + compatible = "fsl,bman-portal"; + reg = <0x4000 0x4000>, <0x101000 0x1000>; + interrupts = <107 2 0 0>; + }; + bman-portal@8000 { + compatible = "fsl,bman-portal"; + reg = <0x8000 0x4000>, <0x102000 0x1000>; + interrupts = <109 2 0 0>; + }; + bman-portal@c000 { + compatible = "fsl,bman-portal"; + reg = <0xc000 0x4000>, <0x103000 0x1000>; + interrupts = <111 2 0 0>; + }; + bman-portal@10000 { + compatible = "fsl,bman-portal"; + reg = <0x10000 0x4000>, <0x104000 0x1000>; + interrupts = <113 2 0 0>; + }; + bman-portal@14000 { + compatible = "fsl,bman-portal"; + reg = <0x14000 0x4000>, <0x105000 0x1000>; + interrupts = <115 2 0 0>; + }; + bman-portal@18000 { + compatible = "fsl,bman-portal"; + reg = <0x18000 0x4000>, <0x106000 0x1000>; + interrupts = <117 2 0 0>; + }; + bman-portal@1c000 { + compatible = "fsl,bman-portal"; + reg = <0x1c000 0x4000>, <0x107000 0x1000>; + interrupts = <119 2 0 0>; + }; + bman-portal@20000 { + compatible = "fsl,bman-portal"; + reg = <0x20000 0x4000>, <0x108000 0x1000>; + interrupts = <121 2 0 0>; + }; + bman-portal@24000 { + compatible = "fsl,bman-portal"; + reg = <0x24000 0x4000>, <0x109000 0x1000>; + interrupts = <123 2 0 0>; + }; +}; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-bman1.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-bman1.dtsi new file mode 100644 index 000000000000..3b5e3504acb7 --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/qoriq-bman1.dtsi @@ -0,0 +1,41 @@ +/* + * QorIQ BMan device tree stub [ controller @ offset 0x31a000 ] + * + * Copyright 2011 - 2014 Freescale Semiconductor Inc. + * + * 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 of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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. + */ + +bman: bman@31a000 { + compatible = "fsl,bman"; + reg = <0x31a000 0x1000>; + interrupts = <16 2 1 2>; + fsl,bman-portals = <&bportals>; + memory-region = <&bman_fbpr>; +}; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-qman1-portals.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-qman1-portals.dtsi new file mode 100644 index 000000000000..05d51acafa67 --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/qoriq-qman1-portals.dtsi @@ -0,0 +1,101 @@ +/* + * QorIQ QMan Portal device tree stub for 10 portals & 15 pool channels + * + * Copyright 2011 - 2014 Freescale Semiconductor Inc. + * + * 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 of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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. + */ + +&qportals { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + + qportal0: qman-portal@0 { + compatible = "fsl,qman-portal"; + reg = <0x0 0x4000>, <0x100000 0x1000>; + interrupts = <104 2 0 0>; + fsl,qman-channel-id = <0x0>; + }; + qportal1: qman-portal@4000 { + compatible = "fsl,qman-portal"; + reg = <0x4000 0x4000>, <0x101000 0x1000>; + interrupts = <106 2 0 0>; + fsl,qman-channel-id = <1>; + }; + qportal2: qman-portal@8000 { + compatible = "fsl,qman-portal"; + reg = <0x8000 0x4000>, <0x102000 0x1000>; + interrupts = <108 2 0 0>; + fsl,qman-channel-id = <2>; + }; + qportal3: qman-portal@c000 { + compatible = "fsl,qman-portal"; + reg = <0xc000 0x4000>, <0x103000 0x1000>; + interrupts = <110 2 0 0>; + fsl,qman-channel-id = <3>; + }; + qportal4: qman-portal@10000 { + compatible = "fsl,qman-portal"; + reg = <0x10000 0x4000>, <0x104000 0x1000>; + interrupts = <112 2 0 0>; + fsl,qman-channel-id = <4>; + }; + qportal5: qman-portal@14000 { + compatible = "fsl,qman-portal"; + reg = <0x14000 0x4000>, <0x105000 0x1000>; + interrupts = <114 2 0 0>; + fsl,qman-channel-id = <5>; + }; + qportal6: qman-portal@18000 { + compatible = "fsl,qman-portal"; + reg = <0x18000 0x4000>, <0x106000 0x1000>; + interrupts = <116 2 0 0>; + fsl,qman-channel-id = <6>; + }; + + qportal7: qman-portal@1c000 { + compatible = "fsl,qman-portal"; + reg = <0x1c000 0x4000>, <0x107000 0x1000>; + interrupts = <118 2 0 0>; + fsl,qman-channel-id = <7>; + }; + qportal8: qman-portal@20000 { + compatible = "fsl,qman-portal"; + reg = <0x20000 0x4000>, <0x108000 0x1000>; + interrupts = <120 2 0 0>; + fsl,qman-channel-id = <8>; + }; + qportal9: qman-portal@24000 { + compatible = "fsl,qman-portal"; + reg = <0x24000 0x4000>, <0x109000 0x1000>; + interrupts = <122 2 0 0>; + fsl,qman-channel-id = <9>; + }; +}; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-qman1.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-qman1.dtsi new file mode 100644 index 000000000000..0695778c4386 --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/qoriq-qman1.dtsi @@ -0,0 +1,41 @@ +/* + * QorIQ QMan device tree stub [ controller @ offset 0x318000 ] + * + * Copyright 2011 - 2014 Freescale Semiconductor Inc. + * + * 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 of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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. + */ + +qman: qman@318000 { + compatible = "fsl,qman"; + reg = <0x318000 0x1000>; + interrupts = <16 2 1 3>; + fsl,qman-portals = <&qportals>; + memory-region = <&qman_fqd &qman_pfdr>; +}; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-qman3.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-qman3.dtsi new file mode 100644 index 000000000000..b379abd1439d --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/qoriq-qman3.dtsi @@ -0,0 +1,41 @@ +/* + * QorIQ QMan rev3 device tree stub [ controller @ offset 0x318000 ] + * + * Copyright 2014 Freescale Semiconductor Inc. + * + * 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 of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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. + */ + +qman: qman@318000 { + compatible = "fsl,qman"; + reg = <0x318000 0x2000>; + interrupts = <16 2 1 3>; + fsl,qman-portals = <&qportals>; + memory-region = <&qman_fqd &qman_pfdr>; +}; diff --git a/arch/powerpc/boot/dts/mvme2500.dts b/arch/powerpc/boot/dts/mvme2500.dts new file mode 100644 index 000000000000..67714cf0f745 --- /dev/null +++ b/arch/powerpc/boot/dts/mvme2500.dts @@ -0,0 +1,280 @@ +/* + * Device tree source for the Emerson/Artesyn MVME2500 + * + * Copyright 2014 Elettra-Sincrotrone Trieste S.C.p.A. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Based on: P2020 DS Device Tree Source + * Copyright 2009 Freescale Semiconductor Inc. + */ + +/include/ "fsl/p2020si-pre.dtsi" + +/ { + model = "MVME2500"; + compatible = "artesyn,MVME2500"; + + aliases { + serial2 = &serial2; + serial3 = &serial3; + serial4 = &serial4; + serial5 = &serial5; + }; + + memory { + device_type = "memory"; + }; + + soc: soc@ffe00000 { + ranges = <0x0 0 0xffe00000 0x100000>; + + i2c@3000 { + hwmon@4c { + compatible = "adi,adt7461"; + reg = <0x4c>; + }; + + rtc@68 { + compatible = "dallas,ds1337"; + reg = <0x68>; + interrupts = <8 1 0 0>; + }; + + eeprom@54 { + compatible = "atmel,24c64"; + reg = <0x54>; + }; + + eeprom@52 { + compatible = "atmel,24c512"; + reg = <0x52>; + }; + + eeprom@53 { + compatible = "atmel,24c512"; + reg = <0x53>; + }; + + eeprom@50 { + compatible = "atmel,24c02"; + reg = <0x50>; + }; + + }; + + spi0: spi@7000 { + fsl,espi-num-chipselects = <2>; + + flash@0 { + compatible = "atmel,at25df641"; + reg = <0>; + spi-max-frequency = <10000000>; + }; + flash@1 { + compatible = "atmel,at25df641"; + reg = <1>; + spi-max-frequency = <10000000>; + }; + }; + + usb@22000 { + dr_mode = "host"; + phy_type = "ulpi"; + }; + + enet0: ethernet@24000 { + tbi-handle = <&tbi0>; + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + }; + + mdio@24520 { + phy1: ethernet-phy@1 { + compatible = "brcm,bcm54616S"; + interrupts = <6 1 0 0>; + reg = <0x1>; + }; + + phy2: ethernet-phy@2 { + compatible = "brcm,bcm54616S"; + interrupts = <6 1 0 0>; + reg = <0x2>; + }; + + phy3: ethernet-phy@3 { + compatible = "brcm,bcm54616S"; + interrupts = <5 1 0 0>; + reg = <0x3>; + }; + + phy7: ethernet-phy@7 { + compatible = "brcm,bcm54616S"; + interrupts = <7 1 0 0>; + reg = <0x7>; + }; + + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet1: ethernet@25000 { + tbi-handle = <&tbi1>; + phy-handle = <&phy7>; + phy-connection-type = "rgmii-id"; + }; + + mdio@25520 { + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet2: ethernet@26000 { + tbi-handle = <&tbi2>; + phy-handle = <&phy3>; + phy-connection-type = "rgmii-id"; + }; + + mdio@26520 { + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + }; + + lbc: localbus@ffe05000 { + reg = <0 0xffe05000 0 0x1000>; + + ranges = <0x0 0x0 0x0 0xfff00000 0x00080000 + 0x1 0x0 0x0 0xffc40000 0x00010000 + 0x2 0x0 0x0 0xffc50000 0x00010000 + 0x3 0x0 0x0 0xffc60000 0x00010000 + 0x4 0x0 0x0 0xffc70000 0x00010000 + 0x6 0x0 0x0 0xffc80000 0x00010000 + 0x5 0x0 0x0 0xffdf0000 0x00008000>; + + serial2: serial@1,0 { + device_type = "serial"; + compatible = "ns16550"; + reg = <0x1 0x0 0x100>; + clock-frequency = <1843200>; + interrupts = <11 2 0 0>; + }; + + serial3: serial@2,0 { + device_type = "serial"; + compatible = "ns16550"; + reg = <0x2 0x0 0x100>; + clock-frequency = <1843200>; + interrupts = <1 2 0 0>; + }; + + serial4: serial@3,0 { + device_type = "serial"; + compatible = "ns16550"; + reg = <0x3 0x0 0x100>; + clock-frequency = <1843200>; + interrupts = <2 2 0 0>; + }; + + serial5: serial@4,0 { + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4 0x0 0x100>; + clock-frequency = <1843200>; + interrupts = <3 2 0 0>; + }; + + mram@0,0 { + compatible = "everspin,mram", "mtd-ram"; + reg = <0x0 0x0 0x80000>; + bank-width = <2>; + }; + + board-control@5,0 { + compatible = "artesyn,mvme2500-fpga"; + reg = <0x5 0x0 0x01000>; + }; + + cpld@6,0 { + compatible = "artesyn,mvme2500-cpld"; + reg = <0x6 0x0 0x10000>; + interrupts = <9 1 0 0>; + }; + }; + + pci0: pcie@ffe08000 { + reg = <0 0xffe08000 0 0x1000>; + ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x10000>; + }; + }; + + pci1: pcie@ffe09000 { + reg = <0 0xffe09000 0 0x1000>; + ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x10000>; + }; + + }; + + pci2: pcie@ffe0a000 { + reg = <0 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xc0000000 + 0x2000000 0x0 0xc0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x10000>; + }; + }; +}; + +/include/ "fsl/p2020si-post.dtsi" + +/ { + soc@ffe00000 { + serial@4600 { + status = "disabled"; + }; + + i2c@3100 { + status = "disabled"; + }; + + sdhc@2e000 { + compatible = "fsl,p2020-esdhc", "fsl,esdhc"; + non-removable; + }; + + }; + +}; diff --git a/arch/powerpc/boot/dts/t4240emu.dts b/arch/powerpc/boot/dts/t4240emu.dts deleted file mode 100644 index decaf357db9c..000000000000 --- a/arch/powerpc/boot/dts/t4240emu.dts +++ /dev/null @@ -1,281 +0,0 @@ -/* - * T4240 emulator Device Tree Source - * - * Copyright 2013 Freescale Semiconductor Inc. - * - * 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 of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "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 Freescale Semiconductor 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. - */ - -/dts-v1/; - -/include/ "fsl/e6500_power_isa.dtsi" -/ { - compatible = "fsl,T4240"; - #address-cells = <2>; - #size-cells = <2>; - interrupt-parent = <&mpic>; - - aliases { - ccsr = &soc; - - serial0 = &serial0; - serial1 = &serial1; - serial2 = &serial2; - serial3 = &serial3; - dma0 = &dma0; - dma1 = &dma1; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu0: PowerPC,e6500@0 { - device_type = "cpu"; - reg = <0 1>; - next-level-cache = <&L2_1>; - fsl,portid-mapping = <0x80000000>; - }; - cpu1: PowerPC,e6500@2 { - device_type = "cpu"; - reg = <2 3>; - next-level-cache = <&L2_1>; - fsl,portid-mapping = <0x80000000>; - }; - cpu2: PowerPC,e6500@4 { - device_type = "cpu"; - reg = <4 5>; - next-level-cache = <&L2_1>; - fsl,portid-mapping = <0x80000000>; - }; - cpu3: PowerPC,e6500@6 { - device_type = "cpu"; - reg = <6 7>; - next-level-cache = <&L2_1>; - fsl,portid-mapping = <0x80000000>; - }; - - cpu4: PowerPC,e6500@8 { - device_type = "cpu"; - reg = <8 9>; - next-level-cache = <&L2_2>; - fsl,portid-mapping = <0x40000000>; - }; - cpu5: PowerPC,e6500@10 { - device_type = "cpu"; - reg = <10 11>; - next-level-cache = <&L2_2>; - fsl,portid-mapping = <0x40000000>; - }; - cpu6: PowerPC,e6500@12 { - device_type = "cpu"; - reg = <12 13>; - next-level-cache = <&L2_2>; - fsl,portid-mapping = <0x40000000>; - }; - cpu7: PowerPC,e6500@14 { - device_type = "cpu"; - reg = <14 15>; - next-level-cache = <&L2_2>; - fsl,portid-mapping = <0x40000000>; - }; - - cpu8: PowerPC,e6500@16 { - device_type = "cpu"; - reg = <16 17>; - next-level-cache = <&L2_3>; - fsl,portid-mapping = <0x20000000>; - }; - cpu9: PowerPC,e6500@18 { - device_type = "cpu"; - reg = <18 19>; - next-level-cache = <&L2_3>; - fsl,portid-mapping = <0x20000000>; - }; - cpu10: PowerPC,e6500@20 { - device_type = "cpu"; - reg = <20 21>; - next-level-cache = <&L2_3>; - fsl,portid-mapping = <0x20000000>; - }; - cpu11: PowerPC,e6500@22 { - device_type = "cpu"; - reg = <22 23>; - next-level-cache = <&L2_3>; - fsl,portid-mapping = <0x20000000>; - }; - }; -}; - -/ { - model = "fsl,T4240QDS"; - compatible = "fsl,T4240EMU", "fsl,T4240QDS"; - #address-cells = <2>; - #size-cells = <2>; - interrupt-parent = <&mpic>; - - ifc: localbus@ffe124000 { - reg = <0xf 0xfe124000 0 0x2000>; - ranges = <0 0 0xf 0xe8000000 0x08000000 - 2 0 0xf 0xff800000 0x00010000 - 3 0 0xf 0xffdf0000 0x00008000>; - - nor@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cfi-flash"; - reg = <0x0 0x0 0x8000000>; - - bank-width = <2>; - device-width = <1>; - }; - - }; - - memory { - device_type = "memory"; - }; - - soc: soc@ffe000000 { - ranges = <0x00000000 0xf 0xfe000000 0x1000000>; - reg = <0xf 0xfe000000 0 0x00001000>; - - }; -}; - -&ifc { - #address-cells = <2>; - #size-cells = <1>; - compatible = "fsl,ifc", "simple-bus"; - interrupts = <25 2 0 0>; -}; - -&soc { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "simple-bus"; - - soc-sram-error { - compatible = "fsl,soc-sram-error"; - interrupts = <16 2 1 29>; - }; - - corenet-law@0 { - compatible = "fsl,corenet-law"; - reg = <0x0 0x1000>; - fsl,num-laws = <32>; - }; - - ddr1: memory-controller@8000 { - compatible = "fsl,qoriq-memory-controller-v4.7", - "fsl,qoriq-memory-controller"; - reg = <0x8000 0x1000>; - interrupts = <16 2 1 23>; - }; - - ddr2: memory-controller@9000 { - compatible = "fsl,qoriq-memory-controller-v4.7", - "fsl,qoriq-memory-controller"; - reg = <0x9000 0x1000>; - interrupts = <16 2 1 22>; - }; - - ddr3: memory-controller@a000 { - compatible = "fsl,qoriq-memory-controller-v4.7", - "fsl,qoriq-memory-controller"; - reg = <0xa000 0x1000>; - interrupts = <16 2 1 21>; - }; - - cpc: l3-cache-controller@10000 { - compatible = "fsl,t4240-l3-cache-controller", "cache"; - reg = <0x10000 0x1000 - 0x11000 0x1000 - 0x12000 0x1000>; - interrupts = <16 2 1 27 - 16 2 1 26 - 16 2 1 25>; - }; - - corenet-cf@18000 { - compatible = "fsl,corenet2-cf", "fsl,corenet-cf"; - reg = <0x18000 0x1000>; - interrupts = <16 2 1 31>; - fsl,ccf-num-csdids = <32>; - fsl,ccf-num-snoopids = <32>; - }; - - iommu@20000 { - compatible = "fsl,pamu-v1.0", "fsl,pamu"; - reg = <0x20000 0x6000>; - fsl,portid-mapping = <0x8000>; - interrupts = < - 24 2 0 0 - 16 2 1 30>; - }; - -/include/ "fsl/qoriq-mpic.dtsi" - - guts: global-utilities@e0000 { - compatible = "fsl,t4240-device-config", "fsl,qoriq-device-config-2.0"; - reg = <0xe0000 0xe00>; - fsl,has-rstcr; - fsl,liodn-bits = <12>; - }; - -/include/ "fsl/qoriq-clockgen2.dtsi" - global-utilities@e1000 { - compatible = "fsl,t4240-clockgen", "fsl,qoriq-clockgen-2.0"; - }; - -/include/ "fsl/qoriq-dma-0.dtsi" -/include/ "fsl/qoriq-dma-1.dtsi" - -/include/ "fsl/qoriq-i2c-0.dtsi" -/include/ "fsl/qoriq-i2c-1.dtsi" -/include/ "fsl/qoriq-duart-0.dtsi" -/include/ "fsl/qoriq-duart-1.dtsi" - - L2_1: l2-cache-controller@c20000 { - compatible = "fsl,t4240-l2-cache-controller"; - reg = <0xc20000 0x40000>; - next-level-cache = <&cpc>; - }; - L2_2: l2-cache-controller@c60000 { - compatible = "fsl,t4240-l2-cache-controller"; - reg = <0xc60000 0x40000>; - next-level-cache = <&cpc>; - }; - L2_3: l2-cache-controller@ca0000 { - compatible = "fsl,t4240-l2-cache-controller"; - reg = <0xca0000 0x40000>; - next-level-cache = <&cpc>; - }; -}; diff --git a/arch/powerpc/configs/40x/acadia_defconfig b/arch/powerpc/configs/40x/acadia_defconfig index 69e06eeae6a6..9110a5cb1bb7 100644 --- a/arch/powerpc/configs/40x/acadia_defconfig +++ b/arch/powerpc/configs/40x/acadia_defconfig @@ -1,19 +1,15 @@ CONFIG_40x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_ACADIA=y # CONFIG_WALNUT is not set -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -31,27 +27,18 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=m CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 -# CONFIG_MISC_DEVICES is not set CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y -CONFIG_MII=y CONFIG_IBM_EMAC=y CONFIG_IBM_EMAC_RXB=256 CONFIG_IBM_EMAC_TXB=256 CONFIG_IBM_EMAC_DEBUG=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -65,20 +52,14 @@ CONFIG_SERIAL_OF_PLATFORM=y CONFIG_THERMAL=y # CONFIG_USB_SUPPORT is not set CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_CRYPTO=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/40x/ep405_defconfig b/arch/powerpc/configs/40x/ep405_defconfig index e9d84b5d0ab6..790366652ba3 100644 --- a/arch/powerpc/configs/40x/ep405_defconfig +++ b/arch/powerpc/configs/40x/ep405_defconfig @@ -1,19 +1,15 @@ CONFIG_40x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_EP405=y # CONFIG_WALNUT is not set -CONFIG_SPARSE_IRQ=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -30,19 +26,14 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=m CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set @@ -55,27 +46,20 @@ CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HW_RANDOM is not set # CONFIG_HWMON is not set CONFIG_THERMAL=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_USB=y CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD_PPC_OF_BE=y CONFIG_USB_OHCI_HCD_PPC_OF_LE=y CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_CRYPTO=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/40x/kilauea_defconfig b/arch/powerpc/configs/40x/kilauea_defconfig index 5ff338f6443f..01bd71bac027 100644 --- a/arch/powerpc/configs/40x/kilauea_defconfig +++ b/arch/powerpc/configs/40x/kilauea_defconfig @@ -1,21 +1,17 @@ CONFIG_40x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_KILAUEA=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y # CONFIG_WALNUT is not set -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -33,8 +29,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y @@ -42,21 +36,12 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_NDFC=y -CONFIG_PROC_DEVICETREE=y -CONFIG_PM=y -CONFIG_SUSPEND=y -CONFIG_PPC4xx_CPM=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 -# CONFIG_MISC_DEVICES is not set CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y CONFIG_IBM_EMAC_RXB=256 CONFIG_IBM_EMAC_TXB=256 -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -75,20 +60,14 @@ CONFIG_THERMAL=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=y CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_CRYPTO=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/40x/klondike_defconfig b/arch/powerpc/configs/40x/klondike_defconfig index c0d228dc73dc..e2036b7c7edb 100644 --- a/arch/powerpc/configs/40x/klondike_defconfig +++ b/arch/powerpc/configs/40x/klondike_defconfig @@ -1,5 +1,4 @@ CONFIG_40x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_SYSFS_DEPRECATED=y @@ -14,10 +13,8 @@ CONFIG_MODULE_UNLOAD=y CONFIG_APM8018X=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_MATH_EMULATION=y -# CONFIG_MIGRATION is not set # CONFIG_SUSPEND is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_SCSI=y @@ -51,5 +48,4 @@ CONFIG_AVERAGE=y CONFIG_MAGIC_SYSRQ=y # CONFIG_SCHED_DEBUG is not set # CONFIG_DEBUG_BUGVERBOSE is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_FTRACE is not set diff --git a/arch/powerpc/configs/40x/makalu_defconfig b/arch/powerpc/configs/40x/makalu_defconfig index 84505e3aa0fb..efd51701fb4d 100644 --- a/arch/powerpc/configs/40x/makalu_defconfig +++ b/arch/powerpc/configs/40x/makalu_defconfig @@ -1,19 +1,15 @@ CONFIG_40x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_MAKALU=y # CONFIG_WALNUT is not set -CONFIG_SPARSE_IRQ=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -30,25 +26,17 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=m CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 -# CONFIG_MISC_DEVICES is not set CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y CONFIG_IBM_EMAC_RXB=256 CONFIG_IBM_EMAC_TXB=256 -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -62,20 +50,14 @@ CONFIG_SERIAL_OF_PLATFORM=y CONFIG_THERMAL=y # CONFIG_USB_SUPPORT is not set CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_CRYPTO=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/40x/obs600_defconfig b/arch/powerpc/configs/40x/obs600_defconfig index 91c110dad2d6..5ded3dcdf60a 100644 --- a/arch/powerpc/configs/40x/obs600_defconfig +++ b/arch/powerpc/configs/40x/obs600_defconfig @@ -1,7 +1,8 @@ CONFIG_40x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y CONFIG_EXPERT=y @@ -11,8 +12,6 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_WALNUT is not set CONFIG_OBS600=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_MATH_EMULATION=y CONFIG_NET=y CONFIG_PACKET=y @@ -30,8 +29,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y @@ -39,7 +36,6 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_NDFC=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_NETDEVICES=y @@ -68,13 +64,10 @@ CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y CONFIG_DETECT_HUNG_TASK=y -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_CRYPTO=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/40x/virtex_defconfig b/arch/powerpc/configs/40x/virtex_defconfig index 0a81e1f7dd59..bcb0c4d854db 100644 --- a/arch/powerpc/configs/40x/virtex_defconfig +++ b/arch/powerpc/configs/40x/virtex_defconfig @@ -1,5 +1,4 @@ CONFIG_40x=y -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -7,7 +6,6 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -35,16 +33,11 @@ CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_MANGLE=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_XILINX_SYSACE=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -# CONFIG_NETDEV_10000 is not set -# CONFIG_SERIO_I8042 is not set # CONFIG_SERIO_SERPORT is not set CONFIG_SERIO_XILINX_XPS_PS2=y CONFIG_SERIAL_8250=y @@ -60,15 +53,9 @@ CONFIG_GPIO_XILINX=y CONFIG_FB=y CONFIG_FB_XILINX=y CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FONTS=y -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y CONFIG_LOGO=y -# CONFIG_HID_SUPPORT is not set # CONFIG_USB_SUPPORT is not set CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y -CONFIG_AUTOFS_FS=y CONFIG_AUTOFS4_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y @@ -76,16 +63,16 @@ CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_ROMFS_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_UTF8=m CONFIG_CRC_CCITT=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y CONFIG_PRINTK_TIME=y -CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_DEBUG_KERNEL=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/40x/walnut_defconfig b/arch/powerpc/configs/40x/walnut_defconfig index 0a19f4386ee9..37c838f26e53 100644 --- a/arch/powerpc/configs/40x/walnut_defconfig +++ b/arch/powerpc/configs/40x/walnut_defconfig @@ -1,17 +1,13 @@ CONFIG_40x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set -CONFIG_SPARSE_IRQ=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -28,19 +24,14 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=m CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set @@ -53,22 +44,15 @@ CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HW_RANDOM is not set # CONFIG_HWMON is not set CONFIG_THERMAL=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_CRYPTO=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/44x/akebono_defconfig b/arch/powerpc/configs/44x/akebono_defconfig index 7e2530cd9d30..ea4ef02a0578 100644 --- a/arch/powerpc/configs/44x/akebono_defconfig +++ b/arch/powerpc/configs/44x/akebono_defconfig @@ -4,9 +4,6 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_RD_XZ=y CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y # CONFIG_SLUB_CPU_PARTIAL is not set @@ -15,7 +12,6 @@ CONFIG_OPROFILE=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set -# CONFIG_POWERNV_MSI is not set CONFIG_PPC_47x=y # CONFIG_EBONY is not set CONFIG_AKEBONO=y @@ -26,7 +22,6 @@ CONFIG_IRQ_ALL_CPUS=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="" # CONFIG_SUSPEND is not set -CONFIG_PCI_MSI=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -48,7 +43,6 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 # CONFIG_SCSI_PROC_FS is not set @@ -62,7 +56,6 @@ CONFIG_BLK_DEV_SD=y # CONFIG_NET_VENDOR_AMD is not set # CONFIG_NET_VENDOR_ARC is not set # CONFIG_NET_VENDOR_ATHEROS is not set -# CONFIG_NET_CADENCE is not set # CONFIG_NET_VENDOR_BROADCOM is not set # CONFIG_NET_VENDOR_BROCADE is not set # CONFIG_NET_VENDOR_CHELSIO is not set diff --git a/arch/powerpc/configs/44x/arches_defconfig b/arch/powerpc/configs/44x/arches_defconfig index 44355c53cd30..95494209c124 100644 --- a/arch/powerpc/configs/44x/arches_defconfig +++ b/arch/powerpc/configs/44x/arches_defconfig @@ -1,19 +1,16 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_EBONY is not set CONFIG_ARCHES=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="" CONFIG_NET=y @@ -32,24 +29,16 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 -# CONFIG_MISC_DEVICES is not set CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y CONFIG_IBM_EMAC_RXB=256 CONFIG_IBM_EMAC_TXB=256 -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -64,21 +53,15 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_IBM_IIC=y CONFIG_SENSORS_AD7414=y -CONFIG_VIDEO_OUTPUT_CONTROL=m # CONFIG_USB_SUPPORT is not set CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=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 diff --git a/arch/powerpc/configs/44x/bamboo_defconfig b/arch/powerpc/configs/44x/bamboo_defconfig index cef7d62560c4..a046f08413fd 100644 --- a/arch/powerpc/configs/44x/bamboo_defconfig +++ b/arch/powerpc/configs/44x/bamboo_defconfig @@ -1,17 +1,14 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_BAMBOO=y # CONFIG_EBONY is not set -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="" CONFIG_NET=y @@ -28,12 +25,9 @@ CONFIG_IP_PNP_BOOTP=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set @@ -47,23 +41,16 @@ CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HW_RANDOM is not set # CONFIG_HWMON is not set CONFIG_THERMAL=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=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=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/44x/bluestone_defconfig b/arch/powerpc/configs/44x/bluestone_defconfig index ca7f1f32f2b2..a326b773ac05 100644 --- a/arch/powerpc/configs/44x/bluestone_defconfig +++ b/arch/powerpc/configs/44x/bluestone_defconfig @@ -1,19 +1,16 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y CONFIG_EXPERT=y -# CONFIG_VM_EVENT_COUNTERS is not set # CONFIG_PCI_QUIRKS is not set +# CONFIG_VM_EVENT_COUNTERS is not set # CONFIG_COMPAT_BRK is not set CONFIG_BLUESTONE=y # CONFIG_EBONY is not set -# CONFIG_KVM_GUEST is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="" CONFIG_NET=y @@ -27,18 +24,13 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y CONFIG_IBM_EMAC_RXB=256 CONFIG_IBM_EMAC_TXB=256 @@ -53,7 +45,6 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_IBM_IIC=y CONFIG_SENSORS_AD7414=y -# CONFIG_HID_SUPPORT is not set # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_M41T80=y @@ -63,6 +54,5 @@ CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NLS=y diff --git a/arch/powerpc/configs/44x/canyonlands_defconfig b/arch/powerpc/configs/44x/canyonlands_defconfig index 9919a91add12..d939e71fff7d 100644 --- a/arch/powerpc/configs/44x/canyonlands_defconfig +++ b/arch/powerpc/configs/44x/canyonlands_defconfig @@ -1,19 +1,16 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_EBONY is not set CONFIG_CANYONLANDS=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="" CONFIG_NET=y @@ -32,29 +29,18 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_NDFC=y -CONFIG_PROC_DEVICETREE=y -CONFIG_PM=y -CONFIG_SUSPEND=y -CONFIG_PPC4xx_CPM=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 -# CONFIG_MISC_DEVICES is not set CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y CONFIG_IBM_EMAC_RXB=256 CONFIG_IBM_EMAC_TXB=256 -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -76,21 +62,15 @@ CONFIG_USB_EHCI_HCD=m CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD_PPC_OF_BE=y CONFIG_USB_OHCI_HCD_PPC_OF_LE=y -CONFIG_USB_LIBUSUAL=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_M41T80=y CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=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 diff --git a/arch/powerpc/configs/44x/currituck_defconfig b/arch/powerpc/configs/44x/currituck_defconfig index 47de68261443..5aa312a158dd 100644 --- a/arch/powerpc/configs/44x/currituck_defconfig +++ b/arch/powerpc/configs/44x/currituck_defconfig @@ -1,9 +1,7 @@ CONFIG_44x=y CONFIG_SMP=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y -CONFIG_SPARSE_IRQ=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y @@ -39,12 +37,10 @@ CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_CONNECTOR=y CONFIG_MTD=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 # CONFIG_SCSI_PROC_FS is not set @@ -56,7 +52,6 @@ CONFIG_SATA_SIL24=y # CONFIG_ATA_SFF is not set CONFIG_NETDEVICES=y CONFIG_E1000E=y -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -84,22 +79,18 @@ CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_NLS_DEFAULT="n" -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y -CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y CONFIG_PPC_EARLY_DEBUG=y CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW=0x10000000 CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH=0x200 -CONFIG_CRYPTO=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/44x/ebony_defconfig b/arch/powerpc/configs/44x/ebony_defconfig index 31b58b0d52e2..5909e016c37d 100644 --- a/arch/powerpc/configs/44x/ebony_defconfig +++ b/arch/powerpc/configs/44x/ebony_defconfig @@ -1,18 +1,14 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -28,19 +24,14 @@ CONFIG_IP_PNP_BOOTP=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set @@ -55,21 +46,15 @@ CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HWMON is not set CONFIG_THERMAL=y CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_CRYPTO=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/44x/eiger_defconfig b/arch/powerpc/configs/44x/eiger_defconfig index faccaf65f394..57499d25c877 100644 --- a/arch/powerpc/configs/44x/eiger_defconfig +++ b/arch/powerpc/configs/44x/eiger_defconfig @@ -1,19 +1,15 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set # CONFIG_EBONY is not set CONFIG_EIGER=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="" CONFIG_PCIEPORTBUS=y @@ -33,20 +29,15 @@ CONFIG_IP_PNP_BOOTP=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y -CONFIG_MTD_CONCAT=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_NDFC=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 -# CONFIG_MISC_DEVICES is not set CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -54,13 +45,10 @@ CONFIG_FUSION=y CONFIG_FUSION_SAS=y CONFIG_I2O=y CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y CONFIG_IBM_EMAC_RXB=256 CONFIG_IBM_EMAC_TXB=256 CONFIG_E1000E=y -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -80,25 +68,18 @@ CONFIG_I2C_DEBUG_CORE=y CONFIG_I2C_DEBUG_ALGO=y CONFIG_I2C_DEBUG_BUS=y # CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=m # CONFIG_USB_SUPPORT is not set CONFIG_DMADEVICES=y CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=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=y CONFIG_CRYPTO_CRYPTD=y CONFIG_CRYPTO_AUTHENC=y CONFIG_CRYPTO_CCM=y @@ -116,7 +97,6 @@ CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_SHA1=y CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y -CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_ARC4=y CONFIG_CRYPTO_BLOWFISH=y CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/44x/icon_defconfig b/arch/powerpc/configs/44x/icon_defconfig index 05782c145141..5d52185d8f5a 100644 --- a/arch/powerpc/configs/44x/icon_defconfig +++ b/arch/powerpc/configs/44x/icon_defconfig @@ -1,19 +1,14 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=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 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set # CONFIG_EBONY is not set CONFIG_ICON=y CONFIG_HIGHMEM=y -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="" CONFIG_PCIEPORTBUS=y @@ -34,17 +29,13 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_XILINX_SYSACE=y -# CONFIG_MISC_DEVICES is not set CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_SCSI_CONSTANTS=y @@ -55,11 +46,7 @@ CONFIG_FUSION_SAS=y CONFIG_FUSION_CTL=y CONFIG_FUSION_LOGGING=y CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_WLAN is not set CONFIG_INPUT_MOUSEDEV_SCREEN_X=640 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480 @@ -79,7 +66,6 @@ CONFIG_I2C_CHARDEV=y CONFIG_I2C_IBM_IIC=y # CONFIG_HWMON is not set CONFIG_MFD_SM501=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y CONFIG_FB_SM501=y CONFIG_FRAMEBUFFER_CONSOLE=y @@ -92,25 +78,19 @@ CONFIG_RTC_DRV_DS1307=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_850=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_15=y CONFIG_MAGIC_SYSRQ=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=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/44x/iss476-smp_defconfig b/arch/powerpc/configs/44x/iss476-smp_defconfig index 49a1518a4e69..0ad3e449526e 100644 --- a/arch/powerpc/configs/44x/iss476-smp_defconfig +++ b/arch/powerpc/configs/44x/iss476-smp_defconfig @@ -1,15 +1,11 @@ CONFIG_44x=y CONFIG_SMP=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y -CONFIG_SPARSE_IRQ=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_PROFILING=y CONFIG_OPROFILE=y CONFIG_MODULES=y @@ -25,7 +21,6 @@ CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="root=/dev/issblk0" # CONFIG_PCI is not set CONFIG_ADVANCED_OPTIONS=y -CONFIG_NONSTATIC_KERNEL=y CONFIG_DYNAMIC_MEMSTART=y CONFIG_NET=y CONFIG_PACKET=y @@ -42,13 +37,10 @@ CONFIG_IP_PNP_BOOTP=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 # CONFIG_INPUT is not set @@ -72,15 +64,11 @@ CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y # CONFIG_NETWORK_FILESYSTEMS is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y CONFIG_PPC_EARLY_DEBUG=y -CONFIG_CRYPTO=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/44x/katmai_defconfig b/arch/powerpc/configs/44x/katmai_defconfig index f1137972ed41..a042335971da 100644 --- a/arch/powerpc/configs/44x/katmai_defconfig +++ b/arch/powerpc/configs/44x/katmai_defconfig @@ -1,17 +1,14 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_EBONY is not set CONFIG_KATMAI=y -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="" CONFIG_NET=y @@ -30,19 +27,14 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_MACINTOSH_DRIVERS=y CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set @@ -55,22 +47,15 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HW_RANDOM is not set # CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_MAGIC_SYSRQ=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=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/44x/rainier_defconfig b/arch/powerpc/configs/44x/rainier_defconfig index 4b91a44c4c32..91c2aff9bd55 100644 --- a/arch/powerpc/configs/44x/rainier_defconfig +++ b/arch/powerpc/configs/44x/rainier_defconfig @@ -1,10 +1,8 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -12,7 +10,6 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_EBONY is not set CONFIG_RAINIER=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="" CONFIG_NET=y @@ -31,14 +28,11 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_MACINTOSH_DRIVERS=y @@ -55,26 +49,19 @@ CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HW_RANDOM is not set # CONFIG_HWMON is not set CONFIG_THERMAL=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=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_PPC_EARLY_DEBUG=y CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW=0xef600300 -CONFIG_CRYPTO=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/44x/redwood_defconfig b/arch/powerpc/configs/44x/redwood_defconfig index b7113e114a14..7fddf3fe275c 100644 --- a/arch/powerpc/configs/44x/redwood_defconfig +++ b/arch/powerpc/configs/44x/redwood_defconfig @@ -1,19 +1,15 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set # CONFIG_EBONY is not set CONFIG_REDWOOD=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="" CONFIG_PCIEPORTBUS=y @@ -33,18 +29,13 @@ CONFIG_IP_PNP_BOOTP=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y -CONFIG_MTD_CONCAT=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 -# CONFIG_MISC_DEVICES is not set CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -52,14 +43,11 @@ CONFIG_FUSION=y CONFIG_FUSION_SAS=y CONFIG_I2O=y CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y CONFIG_IBM_EMAC_RXB=256 CONFIG_IBM_EMAC_TXB=256 CONFIG_IBM_EMAC_DEBUG=y CONFIG_E1000E=y -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -79,25 +67,18 @@ CONFIG_I2C_DEBUG_CORE=y CONFIG_I2C_DEBUG_ALGO=y CONFIG_I2C_DEBUG_BUS=y # CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=m # CONFIG_USB_SUPPORT is not set CONFIG_DMADEVICES=y CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=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=y CONFIG_CRYPTO_CRYPTD=y CONFIG_CRYPTO_AUTHENC=y CONFIG_CRYPTO_CCM=y @@ -115,7 +96,6 @@ CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_SHA1=y CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y -CONFIG_CRYPTO_AES=y CONFIG_CRYPTO_ARC4=y CONFIG_CRYPTO_BLOWFISH=y CONFIG_CRYPTO_DES=y diff --git a/arch/powerpc/configs/44x/sam440ep_defconfig b/arch/powerpc/configs/44x/sam440ep_defconfig index 9622eb2a3e37..6928012f3813 100644 --- a/arch/powerpc/configs/44x/sam440ep_defconfig +++ b/arch/powerpc/configs/44x/sam440ep_defconfig @@ -1,20 +1,19 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_IKCONFIG=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_AMIGA_PARTITION=y # CONFIG_IOSCHED_DEADLINE is not set # CONFIG_IOSCHED_CFQ is not set # CONFIG_EBONY is not set CONFIG_SAM440EP=y -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="" CONFIG_NET=y @@ -31,11 +30,9 @@ CONFIG_IP_PNP_BOOTP=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 -# CONFIG_MISC_DEVICES is not set CONFIG_BLK_DEV_SD=y CONFIG_BLK_DEV_SR=y CONFIG_CHR_DEV_SG=y @@ -44,11 +41,7 @@ CONFIG_ATA=y # CONFIG_SATA_PMP is not set CONFIG_SATA_SIL=y CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_INPUT_FF_MEMLESS=m CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y @@ -59,7 +52,6 @@ CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HW_RANDOM is not set CONFIG_I2C_IBM_IIC=y # CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_FB=y CONFIG_FB_RADEON=y CONFIG_LCD_CLASS_DEVICE=y @@ -80,10 +72,8 @@ CONFIG_HID_MONTEREY=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_EHCI_HCD=m CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD_PPC_OF_BE=y @@ -99,7 +89,6 @@ CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT3_FS_POSIX_ACL=y CONFIG_REISERFS_FS=y -CONFIG_INOTIFY=y CONFIG_AUTOFS4_FS=y CONFIG_ISO9660_FS=y CONFIG_JOLIET=y @@ -111,11 +100,7 @@ CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_AFFS_FS=m # CONFIG_NETWORK_FILESYSTEMS is not set -CONFIG_PARTITION_ADVANCED=y -CONFIG_AMIGA_PARTITION=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_CRC_T10DIF=y CONFIG_MAGIC_SYSRQ=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y diff --git a/arch/powerpc/configs/44x/sequoia_defconfig b/arch/powerpc/configs/44x/sequoia_defconfig index 9642d99b47f1..c294369cc39f 100644 --- a/arch/powerpc/configs/44x/sequoia_defconfig +++ b/arch/powerpc/configs/44x/sequoia_defconfig @@ -1,19 +1,16 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_EBONY is not set CONFIG_SEQUOIA=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="" CONFIG_NET=y @@ -32,8 +29,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_INTELEXT=y @@ -41,12 +36,9 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_NDFC=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set @@ -60,24 +52,17 @@ CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HW_RANDOM is not set # CONFIG_HWMON is not set CONFIG_THERMAL=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=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=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/44x/taishan_defconfig b/arch/powerpc/configs/44x/taishan_defconfig index 09e3075030bf..e779228d6cd6 100644 --- a/arch/powerpc/configs/44x/taishan_defconfig +++ b/arch/powerpc/configs/44x/taishan_defconfig @@ -1,17 +1,14 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_EBONY is not set CONFIG_TAISHAN=y -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="" CONFIG_NET=y @@ -30,17 +27,13 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_MACINTOSH_DRIVERS=y CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set @@ -54,23 +47,16 @@ CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HW_RANDOM is not set # CONFIG_HWMON is not set CONFIG_THERMAL=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=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=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/44x/virtex5_defconfig b/arch/powerpc/configs/44x/virtex5_defconfig index 1eb3caf828a5..53d0300b3390 100644 --- a/arch/powerpc/configs/44x/virtex5_defconfig +++ b/arch/powerpc/configs/44x/virtex5_defconfig @@ -1,5 +1,4 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -7,7 +6,6 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -34,16 +32,11 @@ CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_MANGLE=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_XILINX_SYSACE=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -# CONFIG_NETDEV_10000 is not set -# CONFIG_SERIO_I8042 is not set # CONFIG_SERIO_SERPORT is not set CONFIG_SERIO_XILINX_XPS_PS2=y CONFIG_SERIAL_8250=y @@ -59,15 +52,9 @@ CONFIG_GPIO_XILINX=y CONFIG_FB=y CONFIG_FB_XILINX=y CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FONTS=y -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y CONFIG_LOGO=y -# CONFIG_HID_SUPPORT is not set # CONFIG_USB_SUPPORT is not set CONFIG_EXT2_FS=y -CONFIG_INOTIFY=y -CONFIG_AUTOFS_FS=y CONFIG_AUTOFS4_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y @@ -75,16 +62,16 @@ CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_ROMFS_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=m CONFIG_NLS_ISO8859_1=m CONFIG_NLS_UTF8=m CONFIG_CRC_CCITT=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y CONFIG_PRINTK_TIME=y -CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_DEBUG_KERNEL=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/44x/warp_defconfig b/arch/powerpc/configs/44x/warp_defconfig index 551e50a0be5e..ee434375fc24 100644 --- a/arch/powerpc/configs/44x/warp_defconfig +++ b/arch/powerpc/configs/44x/warp_defconfig @@ -1,5 +1,4 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_LOCALVERSION="-pika" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y @@ -7,7 +6,6 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y @@ -16,7 +14,6 @@ CONFIG_MODULE_UNLOAD=y CONFIG_WARP=y CONFIG_PPC4xx_GPIO=y CONFIG_HZ_1000=y -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="ip=on" # CONFIG_PCI is not set @@ -35,8 +32,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -44,21 +39,14 @@ CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_NDFC=y CONFIG_MTD_UBI=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y -CONFIG_MISC_DEVICES=y CONFIG_EEPROM_AT24=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_SCSI_SPI_ATTRS=y # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y -CONFIG_MII=y CONFIG_IBM_EMAC=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -72,7 +60,6 @@ CONFIG_I2C_IBM_IIC=y CONFIG_GPIO_SYSFS=y CONFIG_SENSORS_AD7414=y CONFIG_THERMAL=y -CONFIG_THERMAL_HWMON=y CONFIG_WATCHDOG=y CONFIG_USB=y CONFIG_USB_MON=y @@ -83,14 +70,12 @@ CONFIG_MMC=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y -# CONFIG_LEDS_GPIO_PLATFORM is not set CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_DEFAULT_ON=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set -CONFIG_INOTIFY=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y @@ -99,7 +84,6 @@ CONFIG_JFFS2_FS=y CONFIG_UBIFS_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_850=y @@ -110,13 +94,10 @@ CONFIG_NLS_UTF8=y CONFIG_CRC_CCITT=y CONFIG_CRC_T10DIF=y CONFIG_PRINTK_TIME=y -CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_INFO=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y CONFIG_DETECT_HUNG_TASK=y # CONFIG_SCHED_DEBUG is not set # CONFIG_DEBUG_BUGVERBOSE is not set -CONFIG_DEBUG_INFO=y -# 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/52xx/cm5200_defconfig b/arch/powerpc/configs/52xx/cm5200_defconfig index 0dc99e141035..19fad0e0016e 100644 --- a/arch/powerpc/configs/52xx/cm5200_defconfig +++ b/arch/powerpc/configs/52xx/cm5200_defconfig @@ -1,18 +1,15 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_EPOLL is not set # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_CHRP is not set CONFIG_PPC_MPC52xx=y CONFIG_PPC_MPC5200_SIMPLE=y # CONFIG_PPC_PMAC is not set -CONFIG_SPARSE_IRQ=y CONFIG_PM=y # CONFIG_PCI is not set CONFIG_NET=y @@ -31,26 +28,20 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 -# CONFIG_MISC_DEVICES is not set CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y -CONFIG_LXT_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_FEC_MPC52xx=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set +CONFIG_LXT_PHY=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -64,7 +55,6 @@ CONFIG_I2C_MPC=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD_PPC_OF_BE=y CONFIG_USB_STORAGE=y @@ -73,7 +63,6 @@ CONFIG_PPC_BESTCOMM=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y @@ -81,17 +70,13 @@ CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=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_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/52xx/lite5200b_defconfig b/arch/powerpc/configs/52xx/lite5200b_defconfig index 104a332e79ab..5f40ba92a39a 100644 --- a/arch/powerpc/configs/52xx/lite5200b_defconfig +++ b/arch/powerpc/configs/52xx/lite5200b_defconfig @@ -1,10 +1,9 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_EPOLL is not set CONFIG_MODULES=y @@ -15,10 +14,6 @@ CONFIG_PPC_MPC52xx=y CONFIG_PPC_MPC5200_SIMPLE=y CONFIG_PPC_LITE5200=y # CONFIG_PPC_PMAC is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y -CONFIG_PM=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -33,7 +28,6 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 @@ -42,9 +36,8 @@ CONFIG_BLK_DEV_SD=y CONFIG_ATA=y CONFIG_PATA_MPC52xx=y CONFIG_NETDEVICES=y -CONFIG_LXT_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_FEC_MPC52xx=y +CONFIG_LXT_PHY=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -57,23 +50,18 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y # CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_DMADEVICES=y CONFIG_PPC_BESTCOMM=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_PRINTK_TIME=y -CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_INFO=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_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/52xx/motionpro_defconfig b/arch/powerpc/configs/52xx/motionpro_defconfig index c936fab9ec4a..909e185a88d1 100644 --- a/arch/powerpc/configs/52xx/motionpro_defconfig +++ b/arch/powerpc/configs/52xx/motionpro_defconfig @@ -1,18 +1,15 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_EPOLL is not set # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_CHRP is not set CONFIG_PPC_MPC52xx=y CONFIG_PPC_MPC5200_SIMPLE=y # CONFIG_PPC_PMAC is not set -CONFIG_SPARSE_IRQ=y CONFIG_PM=y # CONFIG_PCI is not set CONFIG_NET=y @@ -30,24 +27,21 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CONCAT=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_ROM=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 -CONFIG_MISC_DEVICES=y CONFIG_EEPROM_LEGACY=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y CONFIG_ATA=y CONFIG_PATA_MPC52xx=y CONFIG_NETDEVICES=y +CONFIG_FEC_MPC52xx=y CONFIG_MARVELL_PHY=y CONFIG_DAVICOM_PHY=y CONFIG_QSEMI_PHY=y @@ -58,11 +52,6 @@ CONFIG_SMSC_PHY=y CONFIG_BROADCOM_PHY=y CONFIG_ICPLUS_PHY=y CONFIG_MDIO_BITBANG=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_FEC_MPC52xx=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -86,7 +75,6 @@ CONFIG_PPC_BESTCOMM=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y @@ -94,18 +82,14 @@ CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y -CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_INFO=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_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/52xx/pcm030_defconfig b/arch/powerpc/configs/52xx/pcm030_defconfig index 1d03c35540c7..649a01a0044d 100644 --- a/arch/powerpc/configs/52xx/pcm030_defconfig +++ b/arch/powerpc/configs/52xx/pcm030_defconfig @@ -1,15 +1,14 @@ -CONFIG_EXPERIMENTAL=y CONFIG_LOCALVERSION="trunk" # CONFIG_LOCALVERSION_AUTO is not set # CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_VM_EVENT_COUNTERS is not set CONFIG_SLAB=y CONFIG_MODULES=y @@ -21,11 +20,8 @@ CONFIG_MODULE_UNLOAD=y CONFIG_PPC_MPC52xx=y CONFIG_PPC_MPC5200_SIMPLE=y # CONFIG_PPC_PMAC is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_100=y CONFIG_PREEMPT=y -CONFIG_SPARSE_IRQ=y # CONFIG_SECCOMP is not set CONFIG_NET=y CONFIG_PACKET=y @@ -45,40 +41,31 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_PHYSMAP=y -CONFIG_PROC_DEVICETREE=y # CONFIG_BLK_DEV is not set -# CONFIG_MISC_DEVICES is not set # CONFIG_SCSI_PROC_FS is not set CONFIG_BLK_DEV_SD=m # CONFIG_SCSI_LOWLEVEL is not set CONFIG_ATA=m CONFIG_PATA_MPC52xx=m CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_FEC_MPC52xx=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_MPC52xx=y CONFIG_SERIAL_MPC52xx_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set CONFIG_HW_RANDOM=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y # CONFIG_HWMON is not set CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_OHCI_HCD=m -# CONFIG_USB_OHCI_HCD_PPC_SOC is not set CONFIG_USB_OHCI_HCD_PPC_OF_BE=y # CONFIG_USB_OHCI_HCD_PCI is not set CONFIG_USB_STORAGE=m @@ -95,8 +82,6 @@ CONFIG_FAT_DEFAULT_CODEPAGE=850 CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_850=y CONFIG_NLS_ISO8859_1=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set diff --git a/arch/powerpc/configs/52xx/tqm5200_defconfig b/arch/powerpc/configs/52xx/tqm5200_defconfig index ca83ec88b114..efab8388ea92 100644 --- a/arch/powerpc/configs/52xx/tqm5200_defconfig +++ b/arch/powerpc/configs/52xx/tqm5200_defconfig @@ -1,17 +1,14 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y -CONFIG_SPARSE_IRQ=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EMBEDDED=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_KALLSYMS is not set # CONFIG_EPOLL is not set +CONFIG_EMBEDDED=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_CHRP is not set CONFIG_PPC_MPC52xx=y CONFIG_PPC_MPC5200_SIMPLE=y @@ -34,17 +31,13 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CONCAT=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_ROM=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_PLATRAM=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 @@ -54,12 +47,9 @@ CONFIG_ATA=y CONFIG_PATA_MPC52xx=y CONFIG_PATA_PLATFORM=y CONFIG_NETDEVICES=y +CONFIG_FEC_MPC52xx=y CONFIG_LXT_PHY=y CONFIG_FIXED_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_FEC_MPC52xx=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_SERIAL_MPC52xx=y CONFIG_SERIAL_MPC52xx_CONSOLE=y CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200 @@ -75,7 +65,6 @@ CONFIG_FB_FOREIGN_ENDIAN=y CONFIG_FB_SM501=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD_PPC_OF_BE=y @@ -95,17 +84,14 @@ CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y -CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_INFO=y CONFIG_DETECT_HUNG_TASK=y # CONFIG_DEBUG_BUGVERBOSE is not set -CONFIG_DEBUG_INFO=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/83xx/asp8347_defconfig b/arch/powerpc/configs/83xx/asp8347_defconfig index 985f95c7280a..bcdfb07921fc 100644 --- a/arch/powerpc/configs/83xx/asp8347_defconfig +++ b/arch/powerpc/configs/83xx/asp8347_defconfig @@ -1,21 +1,20 @@ CONFIG_FSL_EMB_PERFMON=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MSDOS_PARTITION is not set # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y CONFIG_ASP834x=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -34,22 +33,16 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y CONFIG_MTD_REDBOOT_PARTS=y CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_GIANFAR=y -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -63,8 +56,6 @@ CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y CONFIG_THERMAL=y CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=m -# CONFIG_HID_SUPPORT is not set CONFIG_USB=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y @@ -74,17 +65,12 @@ CONFIG_RTC_DRV_DS1374=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION is not set -# CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/83xx/kmeter1_defconfig b/arch/powerpc/configs/83xx/kmeter1_defconfig index e12e60c3b9a2..11a959283149 100644 --- a/arch/powerpc/configs/83xx/kmeter1_defconfig +++ b/arch/powerpc/configs/83xx/kmeter1_defconfig @@ -1,4 +1,3 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -36,7 +35,6 @@ CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y @@ -45,10 +43,8 @@ CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_PHRAM=y CONFIG_MTD_UBI=y CONFIG_MTD_UBI_GLUEBI=y -CONFIG_PROC_DEVICETREE=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y -CONFIG_MII=y CONFIG_TUN=y CONFIG_UCC_GETH=y CONFIG_MARVELL_PHY=y diff --git a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig index 4b4a2a9133a5..b47a41f77836 100644 --- a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig @@ -1,20 +1,18 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y CONFIG_MPC831x_RDB=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -30,15 +28,12 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSL_ELBC=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 @@ -51,12 +46,10 @@ CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y CONFIG_NETDEVICES=y +CONFIG_GIANFAR=y +CONFIG_E100=y CONFIG_CICADA_PHY=y CONFIG_FIXED_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_NET_PCI=y -CONFIG_E100=y -CONFIG_GIANFAR=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -71,7 +64,6 @@ CONFIG_I2C_MPC=y CONFIG_SPI=y CONFIG_SPI_BITBANG=y CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=m # CONFIG_USB_HID is not set CONFIG_USB=y CONFIG_USB_MON=y @@ -82,7 +74,6 @@ CONFIG_USB_OHCI_HCD_PPC_OF_BE=y CONFIG_USB_UHCI_HCD=y CONFIG_USB_STORAGE=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_NET2280=y CONFIG_USB_ETH=m CONFIG_RTC_CLASS=y CONFIG_RTC_INTF_DEV_UIE_EMUL=y @@ -90,18 +81,12 @@ CONFIG_RTC_DRV_DS1307=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig index 5871395573c5..e28c83f320c1 100644 --- a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig @@ -1,20 +1,18 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y CONFIG_MPC831x_RDB=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -30,13 +28,11 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 @@ -50,10 +46,8 @@ CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_NET_PCI=y -CONFIG_E100=y CONFIG_GIANFAR=y +CONFIG_E100=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -68,7 +62,6 @@ CONFIG_I2C_MPC=y CONFIG_SPI=y CONFIG_SPI_BITBANG=y CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=m # CONFIG_USB_HID is not set CONFIG_USB=y CONFIG_USB_MON=y @@ -79,7 +72,6 @@ CONFIG_USB_OHCI_HCD_PPC_OF_BE=y CONFIG_USB_UHCI_HCD=y CONFIG_USB_STORAGE=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_NET2280=y CONFIG_USB_ETH=m CONFIG_RTC_CLASS=y CONFIG_RTC_INTF_DEV_UIE_EMUL=y @@ -87,18 +79,12 @@ CONFIG_RTC_DRV_DS1307=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/83xx/mpc832x_mds_defconfig b/arch/powerpc/configs/83xx/mpc832x_mds_defconfig index a5699a1f7d0a..e84d35b848c0 100644 --- a/arch/powerpc/configs/83xx/mpc832x_mds_defconfig +++ b/arch/powerpc/configs/83xx/mpc832x_mds_defconfig @@ -1,22 +1,21 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MSDOS_PARTITION is not set # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y CONFIG_MPC832x_MDS=y CONFIG_QUICC_ENGINE=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -31,16 +30,13 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_SCSI=y CONFIG_NETDEVICES=y -CONFIG_DAVICOM_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_UCC_GETH=y +CONFIG_DAVICOM_PHY=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -53,23 +49,16 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1374=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION is not set -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig b/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig index 5adc4cea42d3..ae145f410590 100644 --- a/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig @@ -1,22 +1,21 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_LDM_PARTITION=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y CONFIG_MPC832x_RDB=y CONFIG_QUICC_ENGINE=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -31,18 +30,15 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_NETDEVICES=y -CONFIG_ICPLUS_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_E1000=y CONFIG_UCC_GETH=y +CONFIG_E1000=y +CONFIG_ICPLUS_PHY=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -58,7 +54,6 @@ CONFIG_I2C_MPC=y CONFIG_SPI=y CONFIG_SPI_BITBANG=y CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=m # CONFIG_USB_HID is not set CONFIG_USB=y CONFIG_USB_MON=y @@ -71,24 +66,18 @@ CONFIG_MMC_SPI=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_LDM_PARTITION=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_932=y CONFIG_NLS_ISO8859_8=y CONFIG_NLS_ISO8859_1=y CONFIG_CRC_T10DIF=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/83xx/mpc834x_itx_defconfig b/arch/powerpc/configs/83xx/mpc834x_itx_defconfig index 82b6b6c88d6a..2a5fdcbabcdd 100644 --- a/arch/powerpc/configs/83xx/mpc834x_itx_defconfig +++ b/arch/powerpc/configs/83xx/mpc834x_itx_defconfig @@ -1,20 +1,19 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_MAC_PARTITION=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y CONFIG_MPC834x_ITX=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -30,11 +29,9 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CHAR=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 @@ -52,9 +49,9 @@ CONFIG_MD_LINEAR=y CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y CONFIG_NETDEVICES=y +CONFIG_GIANFAR=y CONFIG_CICADA_PHY=y CONFIG_FIXED_PHY=y -CONFIG_GIANFAR=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -69,7 +66,6 @@ CONFIG_SPI=y CONFIG_SPI_BITBANG=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_USB=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y @@ -82,19 +78,13 @@ CONFIG_RTC_DRV_DS1307=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y CONFIG_CRC_T10DIF=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig b/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig index f8b228aaa03a..9a2ff25a2e98 100644 --- a/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig +++ b/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig @@ -1,20 +1,19 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_MAC_PARTITION=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y CONFIG_MPC834x_ITX=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -30,11 +29,9 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CHAR=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 @@ -43,8 +40,8 @@ CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y CONFIG_SCSI_SPI_ATTRS=y CONFIG_NETDEVICES=y -CONFIG_CICADA_PHY=y CONFIG_GIANFAR=y +CONFIG_CICADA_PHY=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -59,7 +56,6 @@ CONFIG_SPI=y CONFIG_SPI_BITBANG=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_USB=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y @@ -72,19 +68,13 @@ CONFIG_RTC_DRV_DS1307=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y CONFIG_CRC_T10DIF=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/83xx/mpc834x_mds_defconfig b/arch/powerpc/configs/83xx/mpc834x_mds_defconfig index 99660c062191..e44edc575549 100644 --- a/arch/powerpc/configs/83xx/mpc834x_mds_defconfig +++ b/arch/powerpc/configs/83xx/mpc834x_mds_defconfig @@ -1,20 +1,19 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MSDOS_PARTITION is not set # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y CONFIG_MPC834x_MDS=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -30,16 +29,13 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_NETDEVICES=y -CONFIG_MARVELL_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_NET_PCI=y -CONFIG_E100=y CONFIG_GIANFAR=y +CONFIG_E100=y +CONFIG_MARVELL_PHY=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -52,23 +48,16 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1374=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION is not set -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig index 05710bbfd2ef..94a7d85f1603 100644 --- a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig +++ b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig @@ -1,21 +1,20 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MSDOS_PARTITION is not set # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y CONFIG_MPC836x_MDS=y CONFIG_QUICC_ENGINE=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -32,21 +31,17 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_SCSI=y CONFIG_NETDEVICES=y -CONFIG_MARVELL_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_UCC_GETH=y +CONFIG_MARVELL_PHY=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -59,23 +54,16 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1374=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION is not set -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig b/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig index 0540d673a052..761ed8ea0729 100644 --- a/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig +++ b/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig @@ -1,20 +1,19 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MSDOS_PARTITION is not set # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y CONFIG_MPC836x_RDK=y CONFIG_QUICC_ENGINE=y CONFIG_QE_GPIO=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -30,20 +29,17 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_ADV_OPTIONS=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_NETDEVICES=y -CONFIG_BROADCOM_PHY=y CONFIG_UCC_GETH=y -# CONFIG_NETDEV_10000 is not set +CONFIG_BROADCOM_PHY=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -71,17 +67,11 @@ CONFIG_LOGO=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION is not set -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_PPC_EARLY_DEBUG=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/83xx/mpc837x_mds_defconfig b/arch/powerpc/configs/83xx/mpc837x_mds_defconfig index f367985be6f7..bcf1b48cc9e6 100644 --- a/arch/powerpc/configs/83xx/mpc837x_mds_defconfig +++ b/arch/powerpc/configs/83xx/mpc837x_mds_defconfig @@ -1,18 +1,16 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y CONFIG_MPC837x_MDS=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -28,7 +26,6 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 @@ -37,10 +34,8 @@ CONFIG_CHR_DEV_SG=y CONFIG_ATA=y CONFIG_SATA_FSL=y CONFIG_NETDEVICES=y -CONFIG_MARVELL_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_GIANFAR=y +CONFIG_MARVELL_PHY=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -54,21 +49,15 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y CONFIG_CRC_T10DIF=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig b/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig index 414eda381591..f0f0ebf75125 100644 --- a/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig @@ -1,18 +1,16 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y CONFIG_MPC837x_RDB=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -30,7 +28,6 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 @@ -43,12 +40,9 @@ CONFIG_BLK_DEV_MD=y CONFIG_MD_RAID1=y CONFIG_MD_RAID456=y CONFIG_NETDEVICES=y +CONFIG_GIANFAR=y CONFIG_MARVELL_PHY=y CONFIG_FIXED_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_GIANFAR=y -# CONFIG_NETDEV_10000 is not set CONFIG_INPUT_FF_MEMLESS=m # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set @@ -63,7 +57,6 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_HID_A4TECH=y CONFIG_HID_APPLE=y CONFIG_HID_BELKIN=y @@ -78,7 +71,6 @@ CONFIG_HID_MONTEREY=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y CONFIG_USB_MON=y @@ -87,18 +79,13 @@ CONFIG_USB_EHCI_FSL=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y CONFIG_CRC_T10DIF=y # CONFIG_ENABLE_MUST_CHECK is not set -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/83xx/sbc834x_defconfig b/arch/powerpc/configs/83xx/sbc834x_defconfig index 4ae385894c64..d2e4d82de14d 100644 --- a/arch/powerpc/configs/83xx/sbc834x_defconfig +++ b/arch/powerpc/configs/83xx/sbc834x_defconfig @@ -1,8 +1,6 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set CONFIG_SLAB=y @@ -13,7 +11,6 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y CONFIG_SBC834x=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -30,15 +27,11 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CONCAT=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 @@ -47,11 +40,8 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y -CONFIG_BROADCOM_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_GIANFAR=y -# CONFIG_NETDEV_10000 is not set +CONFIG_BROADCOM_PHY=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -78,15 +68,11 @@ CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/85xx/ge_imp3a_defconfig b/arch/powerpc/configs/85xx/ge_imp3a_defconfig index b4c4b469e320..b0939dd9ad6f 100644 --- a/arch/powerpc/configs/85xx/ge_imp3a_defconfig +++ b/arch/powerpc/configs/85xx/ge_imp3a_defconfig @@ -1,17 +1,15 @@ CONFIG_PPC_85xx=y CONFIG_SMP=y CONFIG_NR_CPUS=2 -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y -CONFIG_SPARSE_IRQ=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_UTS_NS is not set # CONFIG_IPC_NS is not set -# CONFIG_USER_NS is not set # CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_SYSFS_DEPRECATED=y @@ -28,7 +26,6 @@ CONFIG_QUICC_ENGINE=y CONFIG_QE_GPIO=y CONFIG_CPM2=y CONFIG_HIGHMEM=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_1000=y CONFIG_PREEMPT=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set @@ -71,8 +68,6 @@ CONFIG_IPV6_TUNNEL=m CONFIG_NET_PKTGEN=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y @@ -81,13 +76,11 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSL_ELBC=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 -CONFIG_MISC_DEVICES=y CONFIG_DS1682=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y @@ -125,7 +118,6 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=2 CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_DETECT_IRQ=y CONFIG_SERIAL_8250_RSA=y @@ -141,7 +133,6 @@ CONFIG_SENSORS_LM90=y CONFIG_SENSORS_LM92=y CONFIG_WATCHDOG=y CONFIG_GEF_WDT=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_HID_DRAGONRISE=y CONFIG_HID_GYRATION=y CONFIG_HID_TWINHAN=y @@ -149,7 +140,6 @@ CONFIG_HID_ORTEK=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_HID_GREENASIA=y CONFIG_HID_SMARTJOYPLUS=y @@ -172,7 +162,6 @@ CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_RX8581=y CONFIG_DMADEVICES=y CONFIG_FSL_DMA=y -# CONFIG_NET_DMA is not set CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y @@ -194,7 +183,6 @@ CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_NFSD=y @@ -244,10 +232,8 @@ CONFIG_CRC_CCITT=y CONFIG_CRC_T10DIF=y CONFIG_LIBCRC32C=y CONFIG_MAGIC_SYSRQ=y -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/85xx/kmp204x_defconfig b/arch/powerpc/configs/85xx/kmp204x_defconfig index e362d588dfbf..e94d3eb4a8c1 100644 --- a/arch/powerpc/configs/85xx/kmp204x_defconfig +++ b/arch/powerpc/configs/85xx/kmp204x_defconfig @@ -94,7 +94,6 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_M25P80=y CONFIG_MTD_PHRAM=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_ECC_BCH=y @@ -111,7 +110,6 @@ CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SYM53C8XX_2=y CONFIG_NETDEVICES=y @@ -120,7 +118,6 @@ CONFIG_NETDEVICES=y # CONFIG_NET_VENDOR_ALTEON is not set # CONFIG_NET_VENDOR_AMD is not set # CONFIG_NET_VENDOR_ATHEROS is not set -# CONFIG_NET_CADENCE is not set # CONFIG_NET_VENDOR_BROADCOM is not set # CONFIG_NET_VENDOR_BROCADE is not set # CONFIG_NET_VENDOR_CHELSIO is not set diff --git a/arch/powerpc/configs/85xx/ksi8560_defconfig b/arch/powerpc/configs/85xx/ksi8560_defconfig index aee0d17a9551..3be85c5f1a2a 100644 --- a/arch/powerpc/configs/85xx/ksi8560_defconfig +++ b/arch/powerpc/configs/85xx/ksi8560_defconfig @@ -1,17 +1,16 @@ CONFIG_PPC_85xx=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MSDOS_PARTITION is not set CONFIG_KSI8560=y CONFIG_CPM2=y CONFIG_HIGHMEM=y CONFIG_BINFMT_MISC=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y # CONFIG_SECCOMP is not set CONFIG_NET=y CONFIG_PACKET=y @@ -27,8 +26,6 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CONCAT=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y @@ -39,12 +36,11 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_IDE=y CONFIG_NETDEVICES=y -CONFIG_MARVELL_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_FS_ENET=y # CONFIG_FS_ENET_HAS_SCC is not set CONFIG_FS_ENET_MDIO_FCC=y CONFIG_GIANFAR=y +CONFIG_MARVELL_PHY=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -53,22 +49,15 @@ CONFIG_GIANFAR=y CONFIG_SERIAL_CPM=y CONFIG_SERIAL_CPM_CONSOLE=y CONFIG_GEN_RTC=y -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION is not set CONFIG_DEBUG_FS=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/mpc8540_ads_defconfig b/arch/powerpc/configs/85xx/mpc8540_ads_defconfig index 11662c217ac0..e38c373f2edf 100644 --- a/arch/powerpc/configs/85xx/mpc8540_ads_defconfig +++ b/arch/powerpc/configs/85xx/mpc8540_ads_defconfig @@ -1,17 +1,16 @@ CONFIG_PPC_85xx=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EXPERT=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_MPC8540_ADS=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MSDOS_PARTITION is not set +CONFIG_MPC8540_ADS=y CONFIG_BINFMT_MISC=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y # CONFIG_SECCOMP is not set CONFIG_NET=y CONFIG_PACKET=y @@ -27,13 +26,10 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_GIANFAR=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set @@ -44,20 +40,13 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_HW_RANDOM is not set CONFIG_GEN_RTC=y -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION is not set -CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_MUTEXES=y -# 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 ebe9b30b0721..48fc8e3a7be0 100644 --- a/arch/powerpc/configs/85xx/mpc8560_ads_defconfig +++ b/arch/powerpc/configs/85xx/mpc8560_ads_defconfig @@ -1,15 +1,14 @@ CONFIG_PPC_85xx=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MSDOS_PARTITION is not set CONFIG_MPC8560_ADS=y CONFIG_BINFMT_MISC=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y # CONFIG_SECCOMP is not set CONFIG_PCI=y CONFIG_PCI_DEBUG=y @@ -30,13 +29,12 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_NETDEVICES=y -CONFIG_MARVELL_PHY=y -CONFIG_DAVICOM_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_FS_ENET=y # CONFIG_FS_ENET_HAS_SCC is not set -CONFIG_E1000=y CONFIG_GIANFAR=y +CONFIG_E1000=y +CONFIG_MARVELL_PHY=y +CONFIG_DAVICOM_PHY=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -45,20 +43,13 @@ CONFIG_GIANFAR=y CONFIG_SERIAL_CPM=y CONFIG_SERIAL_CPM_CONSOLE=y CONFIG_GEN_RTC=y -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION is not set -CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_MUTEXES=y -# 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 eb25229b387a..ecb0c3bf8796 100644 --- a/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig +++ b/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig @@ -1,17 +1,16 @@ CONFIG_PPC_85xx=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -CONFIG_EXPERT=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_MPC85xx_CDS=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MSDOS_PARTITION is not set +CONFIG_MPC85xx_CDS=y CONFIG_BINFMT_MISC=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y # CONFIG_SECCOMP is not set CONFIG_PCI=y CONFIG_NET=y @@ -28,7 +27,6 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 @@ -36,10 +34,8 @@ CONFIG_IDE=y CONFIG_BLK_DEV_GENERIC=y CONFIG_BLK_DEV_VIA82CXXX=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_E1000=y CONFIG_GIANFAR=y +CONFIG_E1000=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -49,20 +45,13 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_HW_RANDOM is not set CONFIG_GEN_RTC=y -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION is not set -CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_MUTEXES=y -# 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/ppa8548_defconfig b/arch/powerpc/configs/85xx/ppa8548_defconfig index e80bb9b21eac..190978a5b7d5 100644 --- a/arch/powerpc/configs/85xx/ppa8548_defconfig +++ b/arch/powerpc/configs/85xx/ppa8548_defconfig @@ -1,11 +1,16 @@ CONFIG_PPC_85xx=y -CONFIG_PPA8548=y -CONFIG_DTC=y -CONFIG_DEFAULT_UIMAGE=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y -# CONFIG_PCI is not set -# CONFIG_USB_SUPPORT is not set +CONFIG_PPA8548=y +CONFIG_FSL_LBC=y +CONFIG_RAPIDIO=y +CONFIG_FSL_RIO=y +CONFIG_RAPIDIO_DMA_ENGINE=y +CONFIG_RAPIDIO_ENUM_BASIC=y +CONFIG_RAPIDIO_TSI57X=y +CONFIG_RAPIDIO_CPS_XX=y +CONFIG_RAPIDIO_TSI568=y +CONFIG_RAPIDIO_CPS_GEN2=y CONFIG_ADVANCED_OPTIONS=y CONFIG_LOWMEM_SIZE_BOOL=y CONFIG_LOWMEM_SIZE=0x40000000 @@ -14,51 +19,28 @@ CONFIG_LOWMEM_CAM_NUM=4 CONFIG_PAGE_OFFSET_BOOL=y CONFIG_PAGE_OFFSET=0xb0000000 CONFIG_KERNEL_START_BOOL=y -CONFIG_KERNEL_START=0xb0000000 -# CONFIG_PHYSICAL_START_BOOL is not set -CONFIG_PHYSICAL_START=0x00000000 -CONFIG_PHYSICAL_ALIGN=0x04000000 CONFIG_TASK_SIZE_BOOL=y CONFIG_TASK_SIZE=0xb0000000 - -CONFIG_FSL_LBC=y -CONFIG_FSL_DMA=y -CONFIG_FSL_RIO=y - -CONFIG_RAPIDIO=y -CONFIG_RAPIDIO_DMA_ENGINE=y -CONFIG_RAPIDIO_TSI57X=y -CONFIG_RAPIDIO_TSI568=y -CONFIG_RAPIDIO_CPS_XX=y -CONFIG_RAPIDIO_CPS_GEN2=y -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_PROC_DEVICETREE=y - -CONFIG_MTD=y -CONFIG_MTD_BLKDEVS=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CONCAT=y -CONFIG_MTD_PHYSMAP_OF=y - -CONFIG_I2C=y -CONFIG_I2C_MPC=y -CONFIG_I2C_CHARDEV -CONFIG_RTC_CLASS=y -CONFIG_RTC_HCTOSYS=y -CONFIG_RTC_DRV_ISL1208=y - CONFIG_NET=y CONFIG_INET=y CONFIG_IP_PNP=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_PHYSMAP_OF=y CONFIG_NETDEVICES=y -CONFIG_MII=y CONFIG_GIANFAR=y CONFIG_MARVELL_PHY=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_I2C=y +CONFIG_I2C_MPC=y +# CONFIG_USB_SUPPORT is not set +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_ISL1208=y +CONFIG_FSL_DMA=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y diff --git a/arch/powerpc/configs/85xx/sbc8548_defconfig b/arch/powerpc/configs/85xx/sbc8548_defconfig index 008a7a47b89b..72b7ccfbe2c2 100644 --- a/arch/powerpc/configs/85xx/sbc8548_defconfig +++ b/arch/powerpc/configs/85xx/sbc8548_defconfig @@ -1,16 +1,13 @@ CONFIG_PPC_85xx=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_SLAB=y # CONFIG_BLK_DEV_BSG is not set CONFIG_SBC8548=y CONFIG_BINFMT_MISC=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y # CONFIG_SECCOMP is not set CONFIG_PCI=y CONFIG_NET=y @@ -27,14 +24,19 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set -CONFIG_PROC_DEVICETREE=y +CONFIG_MTD=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_GEOMETRY=y +CONFIG_MTD_CFI_I4=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_PHYSMAP_OF=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_NETDEVICES=y -CONFIG_BROADCOM_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_GIANFAR=y +CONFIG_BROADCOM_PHY=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -44,33 +46,9 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_HW_RANDOM is not set CONFIG_GEN_RTC=y -CONFIG_VIDEO_OUTPUT_CONTROL=y -# CONFIG_HID_SUPPORT is not set # CONFIG_USB_SUPPORT is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_CRYPTO_ANSI_CPRNG is not set -CONFIG_MTD=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLKDEVS=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_GEN_PROBE=y -CONFIG_MTD_CFI_ADV_OPTIONS=y -CONFIG_MTD_CFI_NOSWAP=y -CONFIG_MTD_CFI_GEOMETRY=y -CONFIG_MTD_MAP_BANK_WIDTH_1=y -CONFIG_MTD_MAP_BANK_WIDTH_2=y -CONFIG_MTD_MAP_BANK_WIDTH_4=y -CONFIG_MTD_CFI_I1=y -CONFIG_MTD_CFI_I2=y -CONFIG_MTD_CFI_I4=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_CFI_UTIL=y -CONFIG_MTD_PHYSMAP_OF=y diff --git a/arch/powerpc/configs/85xx/socrates_defconfig b/arch/powerpc/configs/85xx/socrates_defconfig index 435fd408eef1..0ad7bd5ee6b6 100644 --- a/arch/powerpc/configs/85xx/socrates_defconfig +++ b/arch/powerpc/configs/85xx/socrates_defconfig @@ -1,20 +1,17 @@ CONFIG_PPC_85xx=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set -# CONFIG_HOTPLUG is not set # CONFIG_EPOLL is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y CONFIG_SOCRATES=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -28,13 +25,8 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_LRO is not set # CONFIG_IPV6 is not set CONFIG_CAN=y -CONFIG_CAN_RAW=y -CONFIG_CAN_BCM=y CONFIG_MTD=y -CONFIG_MTD_CONCAT=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y @@ -49,11 +41,8 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y -CONFIG_MARVELL_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_GIANFAR=y -# CONFIG_NETDEV_10000 is not set +CONFIG_MARVELL_PHY=y CONFIG_INPUT_MOUSEDEV_SCREEN_X=800 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480 CONFIG_INPUT_EVDEV=y @@ -65,7 +54,6 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=2 CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_DETECT_IRQ=y CONFIG_SERIAL_8250_RSA=y @@ -82,8 +70,6 @@ CONFIG_FB_MB862XX=y CONFIG_FB_MB862XX_LIME=y # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FONTS=y -CONFIG_FONT_8x16=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_MON=y @@ -95,15 +81,11 @@ CONFIG_RTC_CLASS=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_FONTS=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/85xx/stx_gp3_defconfig b/arch/powerpc/configs/85xx/stx_gp3_defconfig index 5d4db154bf59..f66d16ba8c58 100644 --- a/arch/powerpc/configs/85xx/stx_gp3_defconfig +++ b/arch/powerpc/configs/85xx/stx_gp3_defconfig @@ -1,9 +1,7 @@ CONFIG_PPC_85xx=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODVERSIONS=y @@ -12,7 +10,6 @@ CONFIG_STX_GP3=y CONFIG_HIGHMEM=y CONFIG_BINFMT_MISC=m CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -28,7 +25,6 @@ CONFIG_IP_NF_FILTER=m CONFIG_NET_PKTGEN=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set -CONFIG_PROC_DEVICETREE=y CONFIG_PARPORT=m CONFIG_PARPORT_PC=m CONFIG_BLK_DEV_LOOP=m @@ -42,12 +38,10 @@ CONFIG_BLK_DEV_SD=m CONFIG_CHR_DEV_ST=m CONFIG_BLK_DEV_SR=m CONFIG_CHR_DEV_SG=m -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_NETDEVICES=y -CONFIG_MARVELL_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_GIANFAR=y +CONFIG_MARVELL_PHY=y CONFIG_INPUT_MOUSEDEV_SCREEN_X=1280 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=1024 CONFIG_INPUT_JOYDEV=m @@ -63,8 +57,6 @@ CONFIG_SOUND=m CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y -CONFIG_AUTOFS_FS=m CONFIG_AUTOFS4_FS=y CONFIG_ISO9660_FS=m CONFIG_UDF_FS=m @@ -73,16 +65,11 @@ CONFIG_VFAT_FS=m CONFIG_TMPFS=y CONFIG_CRAMFS=m CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_SMB_FS=m CONFIG_NLS=y CONFIG_CRC_CCITT=y CONFIG_CRC_T10DIF=m -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_BDI_SWITCH=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/85xx/tqm8540_defconfig b/arch/powerpc/configs/85xx/tqm8540_defconfig index 5a800e6e38e3..4daaf2943b44 100644 --- a/arch/powerpc/configs/85xx/tqm8540_defconfig +++ b/arch/powerpc/configs/85xx/tqm8540_defconfig @@ -1,17 +1,15 @@ CONFIG_PPC_85xx=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set -# CONFIG_HOTPLUG is not set # CONFIG_EPOLL is not set # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MSDOS_PARTITION is not set CONFIG_TQM8540=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -25,9 +23,7 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_LRO is not set # CONFIG_IPV6 is not set CONFIG_MTD=y -CONFIG_MTD_CONCAT=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -38,10 +34,8 @@ CONFIG_IDE=y CONFIG_BLK_DEV_GENERIC=y CONFIG_BLK_DEV_VIA82CXXX=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_NET_PCI=y -CONFIG_E100=y CONFIG_GIANFAR=y +CONFIG_E100=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -58,15 +52,10 @@ CONFIG_SENSORS_LM75=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION 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/tqm8541_defconfig b/arch/powerpc/configs/85xx/tqm8541_defconfig index 2d936697d69e..bb402b3cf786 100644 --- a/arch/powerpc/configs/85xx/tqm8541_defconfig +++ b/arch/powerpc/configs/85xx/tqm8541_defconfig @@ -1,17 +1,15 @@ CONFIG_PPC_85xx=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set -# CONFIG_HOTPLUG is not set # CONFIG_EPOLL is not set # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MSDOS_PARTITION is not set CONFIG_TQM8541=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -25,9 +23,7 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_LRO is not set # CONFIG_IPV6 is not set CONFIG_MTD=y -CONFIG_MTD_CONCAT=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -38,10 +34,8 @@ CONFIG_IDE=y CONFIG_BLK_DEV_GENERIC=y CONFIG_BLK_DEV_VIA82CXXX=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_NET_PCI=y -CONFIG_E100=y CONFIG_GIANFAR=y +CONFIG_E100=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -60,15 +54,10 @@ CONFIG_SENSORS_LM75=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION 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/tqm8548_defconfig b/arch/powerpc/configs/85xx/tqm8548_defconfig index ce8a67e89473..685d0fb132d6 100644 --- a/arch/powerpc/configs/85xx/tqm8548_defconfig +++ b/arch/powerpc/configs/85xx/tqm8548_defconfig @@ -1,20 +1,19 @@ CONFIG_PPC_85xx=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MSDOS_PARTITION is not set CONFIG_TQM8548=y CONFIG_HIGHMEM=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y # CONFIG_SECCOMP is not set CONFIG_PCI=y CONFIG_PCIEPORTBUS=y @@ -34,22 +33,16 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLKDEVS=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND_ECC_SMC=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSL_UPM=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_GIANFAR=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set @@ -63,22 +56,15 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y CONFIG_SENSORS_LM75=y -CONFIG_VIDEO_OUTPUT_CONTROL=y # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION is not set -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/tqm8555_defconfig b/arch/powerpc/configs/85xx/tqm8555_defconfig index a4e12971ccac..02a931d4e954 100644 --- a/arch/powerpc/configs/85xx/tqm8555_defconfig +++ b/arch/powerpc/configs/85xx/tqm8555_defconfig @@ -1,17 +1,15 @@ CONFIG_PPC_85xx=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set -# CONFIG_HOTPLUG is not set # CONFIG_EPOLL is not set # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MSDOS_PARTITION is not set CONFIG_TQM8555=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -25,9 +23,7 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_LRO is not set # CONFIG_IPV6 is not set CONFIG_MTD=y -CONFIG_MTD_CONCAT=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -38,10 +34,8 @@ CONFIG_IDE=y CONFIG_BLK_DEV_GENERIC=y CONFIG_BLK_DEV_VIA82CXXX=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_NET_PCI=y -CONFIG_E100=y CONFIG_GIANFAR=y +CONFIG_E100=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -60,15 +54,10 @@ CONFIG_SENSORS_LM75=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION 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/tqm8560_defconfig b/arch/powerpc/configs/85xx/tqm8560_defconfig index 341abe18a74d..633d5b759a36 100644 --- a/arch/powerpc/configs/85xx/tqm8560_defconfig +++ b/arch/powerpc/configs/85xx/tqm8560_defconfig @@ -1,17 +1,15 @@ CONFIG_PPC_85xx=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_KALLSYMS is not set -# CONFIG_HOTPLUG is not set # CONFIG_EPOLL is not set # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_MSDOS_PARTITION is not set CONFIG_TQM8560=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -25,9 +23,7 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_LRO is not set # CONFIG_IPV6 is not set CONFIG_MTD=y -CONFIG_MTD_CONCAT=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -38,10 +34,8 @@ CONFIG_IDE=y CONFIG_BLK_DEV_GENERIC=y CONFIG_BLK_DEV_VIA82CXXX=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_NET_PCI=y -CONFIG_E100=y CONFIG_GIANFAR=y +CONFIG_E100=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -60,15 +54,10 @@ CONFIG_SENSORS_LM75=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_MSDOS_PARTITION 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/xes_mpc85xx_defconfig b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig index 72df8ab8449e..34f3ea1729e0 100644 --- a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig +++ b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig @@ -1,29 +1,25 @@ CONFIG_PPC_85xx=y CONFIG_SMP=y CONFIG_NR_CPUS=2 -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y CONFIG_AUDIT=y +CONFIG_BSD_PROCESS_ACCT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y CONFIG_XES_MPC85xx=y -CONFIG_GPIO_MPC8XXX=y CONFIG_HIGHMEM=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_PCIEPORTBUS=y # CONFIG_PCIEASPM is not set @@ -52,12 +48,9 @@ CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y CONFIG_NET_IPIP=y -CONFIG_NET_IPGRE=y -CONFIG_NET_IPGRE_BROADCAST=y CONFIG_IP_MROUTE=y CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y -CONFIG_ARPD=y # CONFIG_INET_XFRM_MODE_TRANSPORT is not set # CONFIG_INET_XFRM_MODE_TUNNEL is not set # CONFIG_INET_XFRM_MODE_BEET is not set @@ -67,8 +60,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y CONFIG_MTD_REDBOOT_PARTS=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y @@ -79,7 +70,6 @@ CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSL_ELBC=y CONFIG_MTD_NAND_FSL_UPM=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y @@ -88,19 +78,15 @@ CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_LOGGING=y CONFIG_ATA=y CONFIG_SATA_AHCI=y CONFIG_PATA_ALI=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y -CONFIG_BROADCOM_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_E1000=y CONFIG_GIANFAR=y -# CONFIG_NETDEV_10000 is not set +CONFIG_E1000=y +CONFIG_BROADCOM_PHY=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -109,7 +95,6 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=2 CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_DETECT_IRQ=y CONFIG_SERIAL_8250_RSA=y @@ -118,25 +103,19 @@ CONFIG_NVRAM=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_PCA953X=y CONFIG_SENSORS_DS1621=y CONFIG_SENSORS_LM90=y CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_ISP1760_HCD=y CONFIG_USB_STORAGE=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y -CONFIG_LEDS_GPIO=y CONFIG_LEDS_PCA955X=y CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y -CONFIG_LEDS_TRIGGER_GPIO=y CONFIG_EDAC=y CONFIG_EDAC_MM_EDAC=y CONFIG_RTC_CLASS=y @@ -147,7 +126,6 @@ CONFIG_FSL_DMA=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -159,17 +137,13 @@ CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_JFFS2_SUMMARY=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NFSD=y -CONFIG_PARTITION_ADVANCED=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_CRC_T10DIF=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_CRYPTO_HMAC=y CONFIG_CRYPTO_MD5=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig index 7cb9719abf3d..9792a2cb9b20 100644 --- a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig +++ b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig @@ -1,8 +1,8 @@ CONFIG_SMP=y CONFIG_NR_CPUS=2 -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_IKCONFIG=y @@ -10,7 +10,6 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -21,11 +20,9 @@ CONFIG_MODULE_UNLOAD=y CONFIG_PPC_86xx=y CONFIG_GEF_PPC9A=y CONFIG_HIGHMEM=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_1000=y CONFIG_PREEMPT=y CONFIG_BINFMT_MISC=m -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_PCIEPORTBUS=y # CONFIG_PCIEASPM is not set @@ -52,8 +49,6 @@ CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y CONFIG_NET_IPIP=m -CONFIG_NET_IPGRE=m -CONFIG_NET_IPGRE_BROADCAST=y CONFIG_IP_MROUTE=y CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y @@ -69,9 +64,6 @@ CONFIG_IPV6_TUNNEL=m CONFIG_NET_PKTGEN=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y -CONFIG_MTD_CONCAT=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y @@ -83,7 +75,6 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 -CONFIG_MISC_DEVICES=y CONFIG_DS1682=y CONFIG_IDE=y CONFIG_BLK_DEV_IDECS=y @@ -93,35 +84,32 @@ CONFIG_BLK_DEV_SR=y CONFIG_ATA=y CONFIG_SATA_SIL=y CONFIG_NETDEVICES=y -CONFIG_DUMMY=m CONFIG_BONDING=m +CONFIG_DUMMY=m +CONFIG_NETCONSOLE=y CONFIG_TUN=m -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_GIANFAR=y -# CONFIG_NETDEV_10000 is not set CONFIG_PPP=m -CONFIG_PPP_MULTILINK=y +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m CONFIG_PPP_FILTER=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=m CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m CONFIG_SLIP=m CONFIG_SLIP_COMPRESSED=y CONFIG_SLIP_SMART=y CONFIG_SLIP_MODE_SLIP6=y -CONFIG_NETCONSOLE=y # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_SERIAL_8250_PCI is not set CONFIG_SERIAL_8250_NR_UARTS=2 CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -# CONFIG_LEGACY_PTYS is not set CONFIG_HW_RANDOM=y CONFIG_NVRAM=y CONFIG_I2C=y @@ -133,7 +121,6 @@ CONFIG_SENSORS_LM90=y CONFIG_SENSORS_LM92=y CONFIG_WATCHDOG=y CONFIG_GEF_WDT=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_HID_A4TECH=y CONFIG_HID_APPLE=y CONFIG_HID_BELKIN=y @@ -148,10 +135,8 @@ CONFIG_HID_MONTEREY=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_EHCI_HCD=y # CONFIG_USB_EHCI_HCD_PPC_OF is not set CONFIG_USB_OHCI_HCD=y @@ -160,7 +145,6 @@ CONFIG_RTC_CLASS=y # CONFIG_RTC_INTF_PROC is not set CONFIG_RTC_DRV_RX8581=y CONFIG_STAGING=y -# CONFIG_STAGING_EXCLUDE_BUILD is not set CONFIG_VME_BUS=y CONFIG_VME_TSI148=y CONFIG_EXT2_FS=y @@ -169,7 +153,6 @@ CONFIG_EXT2_FS_POSIX_ACL=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_INOTIFY=y CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -182,7 +165,6 @@ CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_CIFS=m @@ -230,7 +212,5 @@ CONFIG_CRC_CCITT=y CONFIG_CRC_T10DIF=y CONFIG_LIBCRC32C=y CONFIG_MAGIC_SYSRQ=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_CRYPTO_ANSI_CPRNG is not set # CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/configs/86xx/gef_sbc310_defconfig b/arch/powerpc/configs/86xx/gef_sbc310_defconfig index ecabf625d249..cadc36682bb4 100644 --- a/arch/powerpc/configs/86xx/gef_sbc310_defconfig +++ b/arch/powerpc/configs/86xx/gef_sbc310_defconfig @@ -1,8 +1,8 @@ CONFIG_SMP=y CONFIG_NR_CPUS=2 -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_IKCONFIG=y @@ -10,7 +10,6 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -21,11 +20,9 @@ CONFIG_MODULE_UNLOAD=y CONFIG_PPC_86xx=y CONFIG_GEF_SBC310=y CONFIG_HIGHMEM=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_1000=y CONFIG_PREEMPT=y CONFIG_BINFMT_MISC=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_PCIEPORTBUS=y # CONFIG_PCIEASPM is not set @@ -52,8 +49,6 @@ CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y CONFIG_NET_IPIP=m -CONFIG_NET_IPGRE=m -CONFIG_NET_IPGRE_BROADCAST=y CONFIG_IP_MROUTE=y CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y @@ -69,9 +64,6 @@ CONFIG_IPV6_TUNNEL=m CONFIG_NET_PKTGEN=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y -CONFIG_MTD_CONCAT=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y @@ -83,7 +75,6 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 -CONFIG_MISC_DEVICES=y CONFIG_DS1682=y CONFIG_IDE=y CONFIG_BLK_DEV_IDECS=y @@ -94,35 +85,32 @@ CONFIG_ATA=y CONFIG_SATA_SIL24=y # CONFIG_ATA_SFF is not set CONFIG_NETDEVICES=y -CONFIG_DUMMY=m CONFIG_BONDING=m +CONFIG_DUMMY=m +CONFIG_NETCONSOLE=y CONFIG_TUN=m -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_GIANFAR=y -# CONFIG_NETDEV_10000 is not set CONFIG_PPP=m -CONFIG_PPP_MULTILINK=y +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m CONFIG_PPP_FILTER=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=m CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m CONFIG_SLIP=m CONFIG_SLIP_COMPRESSED=y CONFIG_SLIP_SMART=y CONFIG_SLIP_MODE_SLIP6=y -CONFIG_NETCONSOLE=y # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_SERIAL_8250_PCI is not set CONFIG_SERIAL_8250_NR_UARTS=2 CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -# CONFIG_LEGACY_PTYS is not set CONFIG_HW_RANDOM=y CONFIG_NVRAM=y CONFIG_I2C=y @@ -134,7 +122,6 @@ CONFIG_SENSORS_LM90=y CONFIG_SENSORS_LM92=y CONFIG_WATCHDOG=y CONFIG_GEF_WDT=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_HID_A4TECH=y CONFIG_HID_APPLE=y CONFIG_HID_BELKIN=y @@ -149,10 +136,8 @@ CONFIG_HID_MONTEREY=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_EHCI_HCD=y # CONFIG_USB_EHCI_HCD_PPC_OF is not set CONFIG_USB_OHCI_HCD=y @@ -166,7 +151,6 @@ CONFIG_EXT2_FS_POSIX_ACL=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_INOTIFY=y CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -179,7 +163,6 @@ CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_CIFS=m @@ -227,7 +210,5 @@ CONFIG_CRC_CCITT=y CONFIG_CRC_T10DIF=y CONFIG_LIBCRC32C=y CONFIG_MAGIC_SYSRQ=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_CRYPTO_ANSI_CPRNG is not set # CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig index 4a4a86fb0d3d..2aa7d9737e43 100644 --- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig +++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig @@ -1,8 +1,8 @@ CONFIG_SMP=y CONFIG_NR_CPUS=2 -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_IKCONFIG=y @@ -10,7 +10,6 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -21,11 +20,9 @@ CONFIG_MODULE_UNLOAD=y CONFIG_PPC_86xx=y CONFIG_GEF_SBC610=y CONFIG_HIGHMEM=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_1000=y CONFIG_PREEMPT=y CONFIG_BINFMT_MISC=m -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_PCIEPORTBUS=y # CONFIG_PCIEASPM is not set @@ -46,8 +43,6 @@ CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y CONFIG_NET_IPIP=m -CONFIG_NET_IPGRE=m -CONFIG_NET_IPGRE_BROADCAST=y CONFIG_IP_MROUTE=y CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y @@ -62,22 +57,17 @@ CONFIG_INET6_IPCOMP=m CONFIG_IPV6_TUNNEL=m CONFIG_NETFILTER=y # CONFIG_NETFILTER_XT_MATCH_SCTP is not set -CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_ADDRTYPE=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_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_ECN=m CONFIG_IP_NF_RAW=m CONFIG_IP_NF_ARPTABLES=m CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m -CONFIG_IP6_NF_QUEUE=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_EUI64=m CONFIG_IP6_NF_MATCH_FRAG=m @@ -85,7 +75,6 @@ CONFIG_IP6_NF_MATCH_OPTS=m CONFIG_IP6_NF_MATCH_HL=m CONFIG_IP6_NF_MATCH_IPV6HEADER=m CONFIG_IP6_NF_MATCH_RT=m -CONFIG_IP6_NF_TARGET_LOG=m CONFIG_IP6_NF_FILTER=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m @@ -98,7 +87,6 @@ CONFIG_ATM_MPOA=m CONFIG_ATM_BR2684=m CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m -CONFIG_WAN_ROUTER=m CONFIG_NET_SCHED=y CONFIG_NET_SCH_CBQ=m CONFIG_NET_SCH_HTB=m @@ -122,9 +110,6 @@ CONFIG_NET_PKTGEN=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CONCAT=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y @@ -136,7 +121,6 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 -CONFIG_MISC_DEVICES=y CONFIG_DS1682=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y @@ -144,37 +128,34 @@ CONFIG_BLK_DEV_SR=y CONFIG_ATA=y CONFIG_SATA_SIL=y CONFIG_NETDEVICES=y -CONFIG_DUMMY=m CONFIG_BONDING=m +CONFIG_DUMMY=m +CONFIG_NETCONSOLE=y CONFIG_TUN=m -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_GIANFAR=y -# CONFIG_NETDEV_10000 is not set CONFIG_PPP=m -CONFIG_PPP_MULTILINK=y +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m CONFIG_PPP_FILTER=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOATM=m +CONFIG_PPPOE=m CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m -CONFIG_PPPOATM=m CONFIG_SLIP=m CONFIG_SLIP_COMPRESSED=y CONFIG_SLIP_SMART=y CONFIG_SLIP_MODE_SLIP6=y -CONFIG_NETCONSOLE=y CONFIG_INPUT_FF_MEMLESS=m # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_SERIAL_8250_PCI is not set CONFIG_SERIAL_8250_NR_UARTS=2 CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -# CONFIG_LEGACY_PTYS is not set CONFIG_HW_RANDOM=y CONFIG_NVRAM=y CONFIG_I2C=y @@ -186,7 +167,6 @@ CONFIG_SENSORS_LM90=y CONFIG_SENSORS_LM92=y CONFIG_WATCHDOG=y CONFIG_GEF_WDT=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_HID_A4TECH=y CONFIG_HID_APPLE=y CONFIG_HID_BELKIN=y @@ -201,10 +181,8 @@ CONFIG_HID_MONTEREY=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_EHCI_HCD=y # CONFIG_USB_EHCI_HCD_PPC_OF is not set CONFIG_USB_OHCI_HCD=y @@ -213,7 +191,6 @@ CONFIG_RTC_CLASS=y # CONFIG_RTC_INTF_PROC is not set CONFIG_RTC_DRV_RX8581=y CONFIG_STAGING=y -# CONFIG_STAGING_EXCLUDE_BUILD is not set CONFIG_VME_BUS=y CONFIG_VME_TSI148=y CONFIG_EXT2_FS=y @@ -222,14 +199,12 @@ CONFIG_EXT2_FS_POSIX_ACL=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_INOTIFY=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_CIFS=m @@ -273,28 +248,20 @@ CONFIG_NLS_ISO8859_15=m CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_U=m CONFIG_NLS_UTF8=m +CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=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_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_MD4=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m diff --git a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig index 9b192bb6bd3d..e32207de2b77 100644 --- a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig +++ b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig @@ -1,27 +1,25 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_SWAP is not set CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y -CONFIG_KALLSYMS_EXTRA_PASS=y # CONFIG_ELF_CORE is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_LDM_PARTITION=y # CONFIG_IOSCHED_CFQ is not set # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_86xx=y CONFIG_MPC8610_HPCD=y CONFIG_HIGHMEM=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_1000=y -CONFIG_SPARSE_IRQ=y CONFIG_FORCE_MAX_ZONEORDER=12 # CONFIG_SECCOMP is not set CONFIG_PCI=y @@ -42,14 +40,12 @@ CONFIG_IPV6=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSL_ELBC=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 @@ -61,15 +57,13 @@ CONFIG_SATA_AHCI=y CONFIG_PATA_ALI=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y -CONFIG_NET_ETHERNET=y CONFIG_NET_TULIP=y CONFIG_ULI526X=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set CONFIG_SERIO_LIBPS2=y +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=2 @@ -79,19 +73,14 @@ CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_8250_DETECT_IRQ=y CONFIG_SERIAL_8250_RSA=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_I2C=y CONFIG_I2C_MPC=y # CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_FB=y CONFIG_FB_FSL_DIU=y CONFIG_VGACON_SOFT_SCROLLBACK=y CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FONTS=y -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_MIXER_OSS=y @@ -108,17 +97,14 @@ CONFIG_EXT3_FS=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NFSD=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_LDM_PARTITION=y CONFIG_NLS=y CONFIG_CRC_T10DIF=y -CONFIG_DEBUG_KERNEL=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_DEBUG_INFO=y CONFIG_DEBUG_SHIRQ=y CONFIG_DETECT_HUNG_TASK=y -CONFIG_DEBUG_INFO=y -# 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 76f43df3dec7..a36e11ddaebd 100644 --- a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig +++ b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig @@ -1,33 +1,31 @@ CONFIG_SMP=y CONFIG_NR_CPUS=2 -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BSD_PROCESS_ACCT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_MAC_PARTITION=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_86xx=y CONFIG_MPC8641_HPCN=y CONFIG_HIGHMEM=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_1000=y CONFIG_BINFMT_MISC=m -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -45,12 +43,9 @@ CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y CONFIG_NET_IPIP=y -CONFIG_NET_IPGRE=y -CONFIG_NET_IPGRE_BROADCAST=y CONFIG_IP_MROUTE=y CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y -CONFIG_ARPD=y # CONFIG_INET_XFRM_MODE_TRANSPORT is not set # CONFIG_INET_XFRM_MODE_TUNNEL is not set # CONFIG_INET_XFRM_MODE_BEET is not set @@ -58,28 +53,23 @@ CONFIG_ARPD=y CONFIG_IPV6=y CONFIG_IP_SCTP=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 -CONFIG_MISC_DEVICES=y CONFIG_EEPROM_LEGACY=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_LOGGING=y CONFIG_ATA=y CONFIG_SATA_AHCI=y CONFIG_PATA_ALI=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y -CONFIG_VITESSE_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_GIANFAR=y +CONFIG_VITESSE_PHY=y CONFIG_INPUT_FF_MEMLESS=m # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set @@ -99,7 +89,6 @@ CONFIG_NVRAM=y CONFIG_I2C=y CONFIG_I2C_MPC=y # CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_MIXER_OSS=y @@ -120,7 +109,6 @@ CONFIG_HID_MONTEREY=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y CONFIG_USB_MON=y @@ -134,7 +122,6 @@ CONFIG_RTC_DRV_CMOS=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_ISO9660_FS=m CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -158,18 +145,12 @@ CONFIG_QNX4FS_FS=m CONFIG_SYSV_FS=m CONFIG_UFS_FS=m CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_NFSD=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y CONFIG_CRC_T10DIF=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_DETECT_HUNG_TASK=y CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_HMAC=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/86xx/sbc8641d_defconfig b/arch/powerpc/configs/86xx/sbc8641d_defconfig index 99ea8746bbaf..db79bdee844b 100644 --- a/arch/powerpc/configs/86xx/sbc8641d_defconfig +++ b/arch/powerpc/configs/86xx/sbc8641d_defconfig @@ -1,8 +1,8 @@ CONFIG_SMP=y CONFIG_NR_CPUS=2 -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_IKCONFIG=y @@ -10,7 +10,6 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -20,10 +19,8 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_PPC_PMAC is not set CONFIG_PPC_86xx=y CONFIG_SBC8641D=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT=y CONFIG_BINFMT_MISC=m -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_PCIEPORTBUS=y # CONFIG_PCIEASPM is not set @@ -43,8 +40,6 @@ CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y CONFIG_NET_IPIP=m -CONFIG_NET_IPGRE=m -CONFIG_NET_IPGRE_BROADCAST=y CONFIG_IP_MROUTE=y CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y @@ -59,22 +54,17 @@ CONFIG_INET6_IPCOMP=m CONFIG_IPV6_TUNNEL=m CONFIG_NETFILTER=y # CONFIG_NETFILTER_XT_MATCH_SCTP is not set -CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_ADDRTYPE=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_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_ECN=m CONFIG_IP_NF_RAW=m CONFIG_IP_NF_ARPTABLES=m CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m -CONFIG_IP6_NF_QUEUE=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_EUI64=m CONFIG_IP6_NF_MATCH_FRAG=m @@ -82,7 +72,6 @@ CONFIG_IP6_NF_MATCH_OPTS=m CONFIG_IP6_NF_MATCH_HL=m CONFIG_IP6_NF_MATCH_IPV6HEADER=m CONFIG_IP6_NF_MATCH_RT=m -CONFIG_IP6_NF_TARGET_LOG=m CONFIG_IP6_NF_FILTER=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m @@ -95,7 +84,6 @@ CONFIG_ATM_MPOA=m CONFIG_ATM_BR2684=m CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m -CONFIG_WAN_ROUTER=m CONFIG_NET_SCHED=y CONFIG_NET_SCH_CBQ=m CONFIG_NET_SCH_HTB=m @@ -119,8 +107,6 @@ CONFIG_NET_PKTGEN=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CONCAT=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_ADV_OPTIONS=y @@ -145,28 +131,25 @@ CONFIG_DM_SNAPSHOT=y CONFIG_DM_MIRROR=y CONFIG_DM_ZERO=y CONFIG_NETDEVICES=y -CONFIG_DUMMY=m CONFIG_BONDING=m +CONFIG_DUMMY=m +CONFIG_NETCONSOLE=y CONFIG_TUN=m -CONFIG_BROADCOM_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_GIANFAR=y -# CONFIG_NETDEV_10000 is not set +CONFIG_BROADCOM_PHY=y CONFIG_PPP=m -CONFIG_PPP_MULTILINK=y +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m CONFIG_PPP_FILTER=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOATM=m +CONFIG_PPPOE=m CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m -CONFIG_PPPOATM=m CONFIG_SLIP=m CONFIG_SLIP_COMPRESSED=y CONFIG_SLIP_SMART=y CONFIG_SLIP_MODE_SLIP6=y -CONFIG_NETCONSOLE=y # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_SERIO is not set @@ -180,7 +163,6 @@ CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y CONFIG_WATCHDOG=y CONFIG_SOFT_WATCHDOG=m -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y @@ -190,20 +172,14 @@ CONFIG_EXT3_FS_POSIX_ACL=y CONFIG_REISERFS_FS=m CONFIG_REISERFS_FS_XATTR=y CONFIG_REISERFS_FS_POSIX_ACL=y -CONFIG_OCFS2_FS=m -CONFIG_INOTIFY=y -CONFIG_AUTOFS_FS=m CONFIG_AUTOFS4_FS=m CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_MINIX_FS=m CONFIG_ROMFS_FS=m CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_SMB_FS=m -CONFIG_SMB_NLS_DEFAULT=y CONFIG_CIFS=m CONFIG_CIFS_XATTR=y CONFIG_CIFS_POSIX=y @@ -245,29 +221,21 @@ CONFIG_NLS_ISO8859_15=m CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_U=m CONFIG_NLS_UTF8=m -CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_INFO=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=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_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_MD4=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m diff --git a/arch/powerpc/configs/adder875_defconfig b/arch/powerpc/configs/adder875_defconfig index 15b1ff5d96e7..d89ff40d39b7 100644 --- a/arch/powerpc/configs/adder875_defconfig +++ b/arch/powerpc/configs/adder875_defconfig @@ -1,21 +1,18 @@ CONFIG_PPC_8xx=y -CONFIG_EXPERIMENTAL=y # CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_BASE_FULL is not set # CONFIG_FUTEX is not set # CONFIG_VM_EVENT_COUNTERS is not set # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_CFQ is not set CONFIG_PPC_ADDER875=y CONFIG_8xx_COPYBACK=y CONFIG_HZ_1000=y -CONFIG_SPARSE_IRQ=y # CONFIG_SECCOMP is not set CONFIG_NET=y CONFIG_PACKET=y @@ -32,42 +29,30 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y # CONFIG_BLK_DEV is not set -# CONFIG_MISC_DEVICES is not set CONFIG_NETDEVICES=y -CONFIG_DAVICOM_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_FS_ENET=y # CONFIG_FS_ENET_HAS_SCC is not set -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set +CONFIG_DAVICOM_PHY=y # CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_CPM=y CONFIG_SERIAL_CPM_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set CONFIG_GEN_RTC=y # CONFIG_HWMON is not set CONFIG_THERMAL=y -CONFIG_VIDEO_OUTPUT_CONTROL=y -# CONFIG_HID_SUPPORT is not set # CONFIG_USB_SUPPORT is not set # CONFIG_DNOTIFY is not set CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_CRC32 is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y -CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_CRC32_SLICEBY4=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/powerpc/configs/amigaone_defconfig b/arch/powerpc/configs/amigaone_defconfig index 8c66b13e59fc..84f1b4140579 100644 --- a/arch/powerpc/configs/amigaone_defconfig +++ b/arch/powerpc/configs/amigaone_defconfig @@ -1,8 +1,9 @@ CONFIG_ALTIVEC=y -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=15 @@ -12,14 +13,13 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_AMIGA_PARTITION=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_AMIGAONE=y CONFIG_HIGHMEM=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=y -# CONFIG_MIGRATION is not set CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -37,11 +37,9 @@ CONFIG_NETFILTER=y # CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set # CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set # CONFIG_NETFILTER_XT_MATCH_STATE is not set -# CONFIG_IP_NF_TARGET_ULOG is not set # CONFIG_IP_NF_MANGLE is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_STANDALONE is not set -CONFIG_PROC_DEVICETREE=y CONFIG_PARPORT=y CONFIG_PARPORT_PC=y CONFIG_PARPORT_PC_FIFO=y @@ -65,24 +63,19 @@ CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 # CONFIG_SCSI_SYM53C8XX_MMIO is not set CONFIG_NETDEVICES=y -CONFIG_PHYLIB=y -CONFIG_NET_ETHERNET=y -CONFIG_NET_VENDOR_3COM=y CONFIG_VORTEX=y -CONFIG_NET_PCI=y CONFIG_8139CP=y CONFIG_8139TOO=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set +CONFIG_PHYLIB=y CONFIG_PPP=m -CONFIG_PPP_MULTILINK=y +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=m CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPP_MPPE=m -CONFIG_PPPOE=m CONFIG_INPUT_EVDEV=y CONFIG_INPUT_MISC=y CONFIG_INPUT_PCSPKR=y @@ -96,7 +89,6 @@ CONFIG_FIRMWARE_EDID=y CONFIG_FB_TILEBLITTING=y CONFIG_FB_RADEON=y CONFIG_FB_3DFX=y -CONFIG_DISPLAY_SUPPORT=m CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y CONFIG_HID_GYRATION=y @@ -104,7 +96,6 @@ CONFIG_HID_NTRIG=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_HID_TOPSEED=y CONFIG_USB=y @@ -117,27 +108,20 @@ CONFIG_RTC_DRV_CMOS=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y CONFIG_EXT4_FS=y -CONFIG_INOTIFY=y CONFIG_ISO9660_FS=y CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=m CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_AFFS_FS=m -CONFIG_PARTITION_ADVANCED=y -CONFIG_AMIGA_PARTITION=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=m CONFIG_CRC_T10DIF=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y -CONFIG_CRYPTO=y CONFIG_CRYPTO_CBC=m CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/c2k_defconfig b/arch/powerpc/configs/c2k_defconfig index 8a08d6dcb0b4..91862292cd55 100644 --- a/arch/powerpc/configs/c2k_defconfig +++ b/arch/powerpc/configs/c2k_defconfig @@ -1,17 +1,23 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y CONFIG_AUDIT=y +CONFIG_BSD_PROCESS_ACCT=y CONFIG_BLK_DEV_INITRD=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_PROFILING=y CONFIG_OPROFILE=m CONFIG_KPROBES=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y -# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_OSF_PARTITION=y +CONFIG_MAC_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_SGI_PARTITION=y +CONFIG_SUN_PARTITION=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_EMBEDDED6xx=y @@ -24,7 +30,6 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=m CONFIG_HIGHMEM=y CONFIG_PREEMPT_VOLUNTARY=y CONFIG_BINFMT_MISC=y -CONFIG_SPARSE_IRQ=y CONFIG_PM=y CONFIG_PCI_MSI=y CONFIG_HOTPLUG_PCI=y @@ -43,8 +48,6 @@ CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_NET_IPIP=m -CONFIG_NET_IPGRE=m -CONFIG_NET_IPGRE_BROADCAST=y CONFIG_IP_MROUTE=y CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y @@ -52,22 +55,17 @@ CONFIG_SYN_COOKIES=y CONFIG_INET_AH=m CONFIG_INET_ESP=m CONFIG_INET_IPCOMP=m -CONFIG_IPV6_PRIVACY=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m CONFIG_IPV6_TUNNEL=m CONFIG_NETFILTER=y # CONFIG_NETFILTER_XT_MATCH_SCTP is not set -CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_ADDRTYPE=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_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_ECN=m CONFIG_IP_NF_RAW=m @@ -81,7 +79,6 @@ CONFIG_IP6_NF_MATCH_OPTS=m CONFIG_IP6_NF_MATCH_HL=m CONFIG_IP6_NF_MATCH_IPV6HEADER=m CONFIG_IP6_NF_MATCH_RT=m -CONFIG_IP6_NF_TARGET_LOG=m CONFIG_IP6_NF_FILTER=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m @@ -133,8 +130,6 @@ CONFIG_NET_CLS_RSVP=m CONFIG_NET_CLS_RSVP6=m CONFIG_NET_CLS_IND=y CONFIG_BT=m -CONFIG_BT_L2CAP=y -CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m @@ -149,9 +144,6 @@ CONFIG_BT_HCIBFUSB=m CONFIG_BT_HCIVHCI=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y -CONFIG_MTD_CONCAT=m -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=m CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -162,7 +154,6 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=16384 -# CONFIG_MISC_DEVICES is not set CONFIG_SCSI=m CONFIG_BLK_DEV_SD=m CONFIG_CHR_DEV_ST=m @@ -182,7 +173,6 @@ CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 CONFIG_AIC7XXX_RESET_DELAY_MS=15000 # CONFIG_AIC7XXX_DEBUG_ENABLE is not set # CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set -CONFIG_SCSI_AIC7XXX_OLD=m CONFIG_SCSI_AIC79XX=m CONFIG_AIC79XX_CMDS_PER_DEVICE=4 CONFIG_AIC79XX_RESET_DELAY_MS=15000 @@ -199,18 +189,14 @@ CONFIG_SCSI_IPS=m CONFIG_SCSI_INITIO=m CONFIG_SCSI_SYM53C8XX_2=m CONFIG_SCSI_QLOGIC_1280=m -CONFIG_SCSI_LPFC=m CONFIG_NETDEVICES=y -CONFIG_DUMMY=m CONFIG_BONDING=m -CONFIG_TUN=m -CONFIG_VITESSE_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_MV643XX_ETH=y -# CONFIG_NETDEV_10000 is not set -# CONFIG_ATM_DRIVERS is not set +CONFIG_DUMMY=m CONFIG_NETCONSOLE=m +CONFIG_TUN=m +# CONFIG_ATM_DRIVERS is not set +CONFIG_MV643XX_ETH=y +CONFIG_VITESSE_PHY=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_KEYBOARD is not set @@ -218,10 +204,10 @@ CONFIG_INPUT_EVDEV=y CONFIG_INPUT_MISC=y CONFIG_INPUT_UINPUT=m # CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_NONSTANDARD=y CONFIG_SERIAL_MPSC=y CONFIG_SERIAL_MPSC_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set CONFIG_NVRAM=m CONFIG_GEN_RTC=m CONFIG_RAW_DRIVER=y @@ -236,7 +222,7 @@ CONFIG_SENSORS_ADM1026=m CONFIG_SENSORS_ADM1031=m CONFIG_SENSORS_DS1621=m CONFIG_SENSORS_GL518SM=m -CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_MAX1619=m CONFIG_SENSORS_LM75=m CONFIG_SENSORS_LM77=m CONFIG_SENSORS_LM78=m @@ -245,23 +231,17 @@ CONFIG_SENSORS_LM83=m CONFIG_SENSORS_LM85=m CONFIG_SENSORS_LM87=m CONFIG_SENSORS_LM90=m -CONFIG_SENSORS_MAX1619=m CONFIG_SENSORS_PCF8591=m -CONFIG_SENSORS_SMSC47M1=m -CONFIG_SENSORS_SMSC47B397=m CONFIG_SENSORS_VIA686A=m CONFIG_SENSORS_W83781D=m CONFIG_SENSORS_W83L785TS=m -CONFIG_SENSORS_W83627HF=m CONFIG_WATCHDOG=y CONFIG_SOFT_WATCHDOG=m CONFIG_PCIPCWATCHDOG=m CONFIG_WDTPCI=m CONFIG_USBPCWATCHDOG=m # CONFIG_VGA_CONSOLE is not set -# CONFIG_HID_SUPPORT is not set CONFIG_USB=m -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=m CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y @@ -350,24 +330,12 @@ CONFIG_JFFS2_FS=y CONFIG_CRAMFS=m CONFIG_VXFS_FS=m CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_RPCSEC_GSS_SPKM3=m CONFIG_CIFS=m CONFIG_CIFS_XATTR=y CONFIG_CIFS_POSIX=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_OSF_PARTITION=y -CONFIG_MAC_PARTITION=y -CONFIG_BSD_DISKLABEL=y -CONFIG_MINIX_SUBPARTITION=y -CONFIG_SOLARIS_X86_PARTITION=y -CONFIG_UNIXWARE_DISKLABEL=y -CONFIG_SGI_PARTITION=y -CONFIG_SUN_PARTITION=y -CONFIG_EFI_PARTITION=y CONFIG_NLS=y CONFIG_NLS_DEFAULT="utf8" CONFIG_NLS_CODEPAGE_437=y @@ -409,21 +377,16 @@ CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_U=m CONFIG_CRC_CCITT=m CONFIG_CRC_T10DIF=m +CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_HIGHMEM=y +CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y -CONFIG_DEBUG_HIGHMEM=y -CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_DEBUG_STACKOVERFLOW=y -CONFIG_DEBUG_STACK_USAGE=y CONFIG_BOOTX_TEXT=y CONFIG_PPC_EARLY_DEBUG=y -CONFIG_PPC_EARLY_DEBUG_BOOTX=y -CONFIG_KEYS=y CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y @@ -431,16 +394,11 @@ CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y CONFIG_SECURITY_SELINUX_DISABLE=y CONFIG_CRYPTO_NULL=m -CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_MD4=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_SHA1=y -CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_AES=m -CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_KHAZAD=m diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig index 7a7b3c879f96..9788b3c2d563 100644 --- a/arch/powerpc/configs/cell_defconfig +++ b/arch/powerpc/configs/cell_defconfig @@ -3,9 +3,10 @@ CONFIG_TUNE_CELL=y CONFIG_ALTIVEC=y CONFIG_SMP=y CONFIG_NR_CPUS=4 -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_FHANDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=15 @@ -17,7 +18,7 @@ CONFIG_PROFILING=y CONFIG_OPROFILE=m CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_POWERNV is not set # CONFIG_PPC_PSERIES is not set # CONFIG_PPC_PMAC is not set @@ -34,8 +35,6 @@ CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=m CONFIG_IRQ_ALL_CPUS=y CONFIG_NUMA=y @@ -63,7 +62,6 @@ CONFIG_INET6_IPCOMP=m # CONFIG_IPV6_SIT is not set CONFIG_IPV6_TUNNEL=m CONFIG_NETFILTER=y -CONFIG_NETFILTER_NETLINK_QUEUE=m CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m CONFIG_NETFILTER_XT_TARGET_DSCP=m CONFIG_NETFILTER_XT_TARGET_MARK=m @@ -94,16 +92,12 @@ 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_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_ADDRTYPE=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_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_ECN=m CONFIG_IP_NF_TARGET_TTL=m @@ -112,7 +106,6 @@ CONFIG_IP_NF_ARPTABLES=m CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 @@ -144,26 +137,24 @@ CONFIG_NETDEVICES=y CONFIG_BONDING=m CONFIG_MACVLAN=m CONFIG_TUN=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y +CONFIG_TIGON3=y CONFIG_E1000=m CONFIG_SKGE=m CONFIG_SKY2=m -CONFIG_TIGON3=y -CONFIG_SPIDER_NET=y CONFIG_GELIC_NET=m CONFIG_GELIC_WIRELESS=y +CONFIG_SPIDER_NET=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_SERIO_I8042 is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_NONSTANDARD=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_TXX9_NR_UARTS=2 CONFIG_SERIAL_TXX9_CONSOLE=y CONFIG_SERIAL_OF_PLATFORM=y -# CONFIG_LEGACY_PTYS is not set CONFIG_HVC_RTAS=y CONFIG_HVC_BEAT=y CONFIG_IPMI_HANDLER=m @@ -174,9 +165,7 @@ CONFIG_IPMI_POWEROFF=m # CONFIG_HW_RANDOM is not set CONFIG_GEN_RTC=y CONFIG_I2C=y -# CONFIG_HWMON is not set CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=m # CONFIG_VGA_CONSOLE is not set CONFIG_HID=m # CONFIG_USB_HID is not set @@ -199,7 +188,6 @@ CONFIG_EDAC_CELL=y CONFIG_UIO=m CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y -CONFIG_INOTIFY=y CONFIG_AUTOFS4_FS=m CONFIG_ISO9660_FS=m CONFIG_JOLIET=y @@ -210,11 +198,8 @@ CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_HUGETLBFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_EFI_PARTITION=y CONFIG_NLS_ISO8859_1=m CONFIG_NLS_ISO8859_2=m CONFIG_NLS_ISO8859_3=m @@ -227,11 +212,10 @@ CONFIG_NLS_ISO8859_13=m CONFIG_NLS_ISO8859_14=m CONFIG_NLS_ISO8859_15=m # CONFIG_ENABLE_MUST_CHECK is not set -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y CONFIG_CRYPTO_ECB=m diff --git a/arch/powerpc/configs/celleb_defconfig b/arch/powerpc/configs/celleb_defconfig index acccbfde8a50..ff454dcd2dd3 100644 --- a/arch/powerpc/configs/celleb_defconfig +++ b/arch/powerpc/configs/celleb_defconfig @@ -3,9 +3,10 @@ CONFIG_TUNE_CELL=y CONFIG_ALTIVEC=y CONFIG_SMP=y CONFIG_NR_CPUS=4 -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_FHANDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=15 @@ -15,6 +16,7 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_POWERNV is not set # CONFIG_PPC_PSERIES is not set # CONFIG_PPC_PMAC is not set @@ -23,8 +25,6 @@ CONFIG_SPU_FS=y # CONFIG_CBE_THERM is not set CONFIG_UDBG_RTAS_CONSOLE=y # CONFIG_RTAS_PROC is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=m CONFIG_KEXEC=y CONFIG_NUMA=y @@ -40,9 +40,7 @@ CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m CONFIG_IPV6_TUNNEL=m CONFIG_NETFILTER=y -CONFIG_IP_NF_QUEUE=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 @@ -55,7 +53,6 @@ CONFIG_SCSI=m CONFIG_BLK_DEV_SD=m CONFIG_BLK_DEV_SR=m CONFIG_CHR_DEV_SG=m -CONFIG_SCSI_MULTI_LUN=y CONFIG_MD=y CONFIG_BLK_DEV_MD=m CONFIG_MD_LINEAR=m @@ -68,17 +65,15 @@ CONFIG_DM_MIRROR=m CONFIG_DM_ZERO=m CONFIG_DM_MULTIPATH=m CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_SPIDER_NET=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_SERIO_I8042 is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_NONSTANDARD=y CONFIG_SERIAL_TXX9_NR_UARTS=3 CONFIG_SERIAL_TXX9_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set CONFIG_HVC_RTAS=y CONFIG_HVC_BEAT=y # CONFIG_HW_RANDOM is not set @@ -89,7 +84,6 @@ CONFIG_WATCHDOG=y # CONFIG_VGA_CONSOLE is not set CONFIG_USB_HIDDEV=y CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_HCD_PPC_OF is not set @@ -103,7 +97,6 @@ CONFIG_EXT2_FS_XIP=y CONFIG_EXT3_FS=y CONFIG_EXT3_FS_POSIX_ACL=y CONFIG_EXT3_FS_SECURITY=y -CONFIG_INOTIFY=y CONFIG_ISO9660_FS=m CONFIG_JOLIET=y CONFIG_UDF_FS=m @@ -113,13 +106,10 @@ CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_HUGETLBFS=y CONFIG_NFS_FS=m -CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFSD=m CONFIG_NFSD_V3=y CONFIG_NFSD_V3_ACL=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_EFI_PARTITION=y CONFIG_NLS_ISO8859_1=m CONFIG_NLS_ISO8859_2=m CONFIG_NLS_ISO8859_3=m @@ -132,11 +122,10 @@ CONFIG_NLS_ISO8859_13=m CONFIG_NLS_ISO8859_14=m CONFIG_NLS_ISO8859_15=m CONFIG_LIBCRC32C=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y CONFIG_CRYPTO_NULL=m diff --git a/arch/powerpc/configs/chrp32_defconfig b/arch/powerpc/configs/chrp32_defconfig index db5b30857e1c..253a9f200097 100644 --- a/arch/powerpc/configs/chrp32_defconfig +++ b/arch/powerpc/configs/chrp32_defconfig @@ -1,25 +1,24 @@ CONFIG_SMP=y -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=15 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_COMPAT_BRK is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_MAC_PARTITION=y # CONFIG_PPC_PMAC is not set CONFIG_HIGHMEM=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=y CONFIG_IRQ_ALL_CPUS=y -# CONFIG_MIGRATION is not set CONFIG_ISA=y CONFIG_NET=y CONFIG_PACKET=y @@ -37,11 +36,9 @@ CONFIG_NETFILTER=y # CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set # CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set # CONFIG_NETFILTER_XT_MATCH_STATE is not set -# CONFIG_IP_NF_TARGET_ULOG is not set # CONFIG_IP_NF_MANGLE is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_STANDALONE is not set -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_FD=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y @@ -60,31 +57,28 @@ CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y +CONFIG_PCNET32=y CONFIG_NET_TULIP=y CONFIG_DE4X5=y -CONFIG_NET_PCI=y -CONFIG_PCNET32=y +CONFIG_MV643XX_ETH=y CONFIG_8139CP=y CONFIG_8139TOO=y # CONFIG_8139TOO_PIO is not set CONFIG_VIA_RHINE=y -CONFIG_MV643XX_ETH=y CONFIG_PPP=m -CONFIG_PPP_MULTILINK=y +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=m CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPP_MPPE=m -CONFIG_PPPOE=m CONFIG_INPUT_EVDEV=y CONFIG_INPUT_MISC=y CONFIG_INPUT_UINPUT=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_BRIQ_PANEL=m # CONFIG_HW_RANDOM is not set CONFIG_NVRAM=y CONFIG_GEN_RTC=y @@ -101,14 +95,12 @@ CONFIG_FB_ATY=y CONFIG_FB_ATY_CT=y CONFIG_FB_ATY_GX=y CONFIG_FB_3DFX=y -CONFIG_DISPLAY_SUPPORT=m CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y CONFIG_HID_GYRATION=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y CONFIG_USB_MON=y @@ -120,26 +112,19 @@ CONFIG_USB_STORAGE=m CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y CONFIG_EXT4_FS=y -CONFIG_INOTIFY=y CONFIG_ISO9660_FS=y CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=m CONFIG_PROC_KCORE=y CONFIG_TMPFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=m CONFIG_CRC_T10DIF=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y -CONFIG_CRYPTO=y CONFIG_CRYPTO_CBC=m CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/corenet32_smp_defconfig b/arch/powerpc/configs/corenet32_smp_defconfig index 611efe99faeb..51866f170684 100644 --- a/arch/powerpc/configs/corenet32_smp_defconfig +++ b/arch/powerpc/configs/corenet32_smp_defconfig @@ -1,13 +1,12 @@ CONFIG_PPC_85xx=y CONFIG_SMP=y CONFIG_NR_CPUS=8 -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_BSD_PROCESS_ACCT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 @@ -57,7 +56,6 @@ CONFIG_NET_IPIP=y CONFIG_IP_MROUTE=y CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y -CONFIG_ARPD=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -69,17 +67,15 @@ CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_M25P80=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSL_ELBC=y CONFIG_MTD_NAND_FSL_IFC=y -CONFIG_PROC_DEVICETREE=y +CONFIG_MTD_SPI_NOR=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 @@ -87,7 +83,6 @@ CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SYM53C8XX_2=y CONFIG_ATA=y @@ -98,10 +93,11 @@ CONFIG_SATA_SIL=y CONFIG_PATA_SIL680=y CONFIG_NETDEVICES=y CONFIG_FSL_PQ_MDIO=y +CONFIG_FSL_XGMAC_MDIO=y CONFIG_E1000=y CONFIG_E1000E=y -CONFIG_VITESSE_PHY=y CONFIG_AT803X_PHY=y +CONFIG_VITESSE_PHY=y CONFIG_FIXED_PHY=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set @@ -123,7 +119,6 @@ CONFIG_SPI_GPIO=y CONFIG_SPI_FSL_SPI=y CONFIG_SPI_FSL_ESPI=y # CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_USB_HID=m CONFIG_USB=y CONFIG_USB_MON=y @@ -143,10 +138,10 @@ CONFIG_RTC_DRV_DS1307=y CONFIG_RTC_DRV_DS1374=y CONFIG_RTC_DRV_DS3232=y CONFIG_UIO=y -CONFIG_STAGING=y -CONFIG_MEMORY=y CONFIG_VIRT_DRIVERS=y CONFIG_FSL_HV_MANAGER=y +CONFIG_STAGING=y +CONFIG_FSL_CORENET_CF=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set @@ -170,17 +165,15 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_850=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=m +CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_SHIRQ=y CONFIG_DETECT_HUNG_TASK=y -CONFIG_DEBUG_INFO=y CONFIG_RCU_TRACE=y CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y -CONFIG_CRYPTO_AES=y # CONFIG_CRYPTO_ANSI_CPRNG is not set CONFIG_CRYPTO_DEV_FSL_CAAM=y -CONFIG_FSL_CORENET_CF=y diff --git a/arch/powerpc/configs/corenet64_smp_defconfig b/arch/powerpc/configs/corenet64_smp_defconfig index be24a18c0d96..d6c0c8198952 100644 --- a/arch/powerpc/configs/corenet64_smp_defconfig +++ b/arch/powerpc/configs/corenet64_smp_defconfig @@ -69,6 +69,7 @@ CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSL_ELBC=y CONFIG_MTD_NAND_FSL_IFC=y +CONFIG_MTD_SPI_NOR=y CONFIG_MTD_UBI=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y @@ -79,7 +80,11 @@ CONFIG_SATA_FSL=y CONFIG_SATA_SIL24=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y +CONFIG_FSL_PQ_MDIO=y +CONFIG_FSL_XGMAC_MDIO=y CONFIG_E1000E=y +CONFIG_VITESSE_PHY=y +CONFIG_FIXED_PHY=y CONFIG_INPUT_FF_MEMLESS=m # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set @@ -118,7 +123,6 @@ CONFIG_FSL_DMA=y CONFIG_VIRT_DRIVERS=y CONFIG_FSL_HV_MANAGER=y CONFIG_FSL_CORENET_CF=y -CONFIG_MEMORY=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y CONFIG_ISO9660_FS=m diff --git a/arch/powerpc/configs/ep8248e_defconfig b/arch/powerpc/configs/ep8248e_defconfig index fceffb3cffbe..7c137041f1d6 100644 --- a/arch/powerpc/configs/ep8248e_defconfig +++ b/arch/powerpc/configs/ep8248e_defconfig @@ -5,13 +5,13 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_SLAB=y +CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_CFQ is not set # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_82xx=y CONFIG_EP8248E=y CONFIG_BINFMT_MISC=y -CONFIG_SPARSE_IRQ=y # CONFIG_SECCOMP is not set CONFIG_PCI=y CONFIG_NET=y @@ -28,7 +28,6 @@ CONFIG_NETFILTER=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_ADV_OPTIONS=y @@ -38,14 +37,11 @@ CONFIG_MTD_CFI_GEOMETRY=y # CONFIG_MTD_CFI_I1 is not set CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y -# CONFIG_MISC_DEVICES is not set CONFIG_NETDEVICES=y -CONFIG_DAVICOM_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_FS_ENET=y # CONFIG_FS_ENET_HAS_SCC is not set +CONFIG_DAVICOM_PHY=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -57,27 +53,20 @@ CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set -CONFIG_INOTIFY=y CONFIG_AUTOFS4_FS=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y CONFIG_NLS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y -# CONFIG_CRC32 is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y -# CONFIG_SCHED_DEBUG is not set CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_SCHED_DEBUG is not set CONFIG_BDI_SWITCH=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y diff --git a/arch/powerpc/configs/ep88xc_defconfig b/arch/powerpc/configs/ep88xc_defconfig index b8a79d7ee89f..ee96be889dac 100644 --- a/arch/powerpc/configs/ep88xc_defconfig +++ b/arch/powerpc/configs/ep88xc_defconfig @@ -1,24 +1,20 @@ CONFIG_PPC_8xx=y -CONFIG_EXPERIMENTAL=y # CONFIG_SWAP is not set CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_BASE_FULL is not set # CONFIG_FUTEX is not set # CONFIG_VM_EVENT_COUNTERS is not set # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_CFQ is not set CONFIG_PPC_EP88XC=y CONFIG_8xx_COPYBACK=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_100=y -CONFIG_8XX_MINIMAL_FPEMU=y -CONFIG_SPARSE_IRQ=y # CONFIG_SECCOMP is not set CONFIG_NET=y CONFIG_PACKET=y @@ -35,27 +31,21 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y # CONFIG_BLK_DEV is not set -# CONFIG_MISC_DEVICES is not set CONFIG_NETDEVICES=y -CONFIG_LXT_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_FS_ENET=y # CONFIG_FS_ENET_HAS_SCC is not set -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set +CONFIG_LXT_PHY=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_CPM=y CONFIG_SERIAL_CPM_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set CONFIG_GEN_RTC=y # CONFIG_HWMON is not set # CONFIG_USB_SUPPORT is not set @@ -63,13 +53,8 @@ CONFIG_GEN_RTC=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_CRC32 is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y -CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_CRC32_SLICEBY4=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig index 6fab06f7f411..1d9ad8500909 100644 --- a/arch/powerpc/configs/g5_defconfig +++ b/arch/powerpc/configs/g5_defconfig @@ -2,12 +2,14 @@ CONFIG_PPC64=y CONFIG_ALTIVEC=y CONFIG_SMP=y CONFIG_NR_CPUS=4 -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_FHANDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y CONFIG_BLK_DEV_INITRD=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y @@ -16,17 +18,15 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_POWERNV is not set # CONFIG_PPC_PSERIES is not set CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_PMAC64=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_KEXEC=y CONFIG_IRQ_ALL_CPUS=y -# CONFIG_MIGRATION is not set CONFIG_PCI_MSI=y CONFIG_NET=y CONFIG_PACKET=y @@ -52,9 +52,9 @@ CONFIG_NF_CONNTRACK_IRC=m CONFIG_NF_CONNTRACK_TFTP=m CONFIG_NF_CT_NETLINK=m CONFIG_NF_CONNTRACK_IPV4=m -CONFIG_IP_NF_QUEUE=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_PROC_DEVICETREE=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y @@ -69,7 +69,6 @@ CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_SPI_ATTRS=y CONFIG_ATA=y @@ -87,33 +86,29 @@ CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m CONFIG_DM_MIRROR=m CONFIG_DM_ZERO=m -CONFIG_IEEE1394=y -CONFIG_IEEE1394_OHCI1394=y -CONFIG_IEEE1394_SBP2=m -CONFIG_IEEE1394_ETH1394=m -CONFIG_IEEE1394_RAWIO=y -CONFIG_IEEE1394_VIDEO1394=m -CONFIG_IEEE1394_DV1394=m CONFIG_ADB_PMU=y CONFIG_PMAC_SMU=y CONFIG_MAC_EMUMOUSEBTN=y -CONFIG_THERM_PM72=y CONFIG_WINDFARM=y CONFIG_WINDFARM_PM81=y CONFIG_WINDFARM_PM91=y CONFIG_WINDFARM_PM112=y CONFIG_WINDFARM_PM121=y CONFIG_NETDEVICES=y -CONFIG_DUMMY=m CONFIG_BONDING=m +CONFIG_DUMMY=m CONFIG_TUN=m -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_SUNGEM=y CONFIG_ACENIC=m CONFIG_ACENIC_OMIT_TIGON_I=y -CONFIG_E1000=y CONFIG_TIGON3=y +CONFIG_E1000=y +CONFIG_SUNGEM=y +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m CONFIG_USB_CATC=m CONFIG_USB_KAWETH=m CONFIG_USB_PEGASUS=m @@ -123,12 +118,6 @@ CONFIG_USB_USBNET=m # CONFIG_USB_NET_NET1080 is not set # CONFIG_USB_NET_CDC_SUBSET is not set # CONFIG_USB_NET_ZAURUS is not set -CONFIG_PPP=m -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m # CONFIG_INPUT_MOUSEDEV_PSAUX is not set CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y @@ -140,10 +129,8 @@ CONFIG_INPUT_EVDEV=y CONFIG_GEN_RTC=y CONFIG_RAW_DRIVER=y CONFIG_I2C_CHARDEV=y -# CONFIG_HWMON is not set CONFIG_AGP=m CONFIG_AGP_UNINORTH=m -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y CONFIG_FIRMWARE_EDID=y CONFIG_FB_TILEBLITTING=y @@ -167,15 +154,14 @@ CONFIG_SND_AOA_ONYX=m CONFIG_SND_AOA_TAS=m CONFIG_SND_AOA_TOONIE=m CONFIG_SND_USB_AUDIO=m -CONFIG_HID_PID=y -CONFIG_USB_HIDDEV=y CONFIG_HID_GYRATION=y CONFIG_LOGITECH_FF=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y CONFIG_USB=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y @@ -245,8 +231,6 @@ CONFIG_REISERFS_FS_POSIX_ACL=y CONFIG_REISERFS_FS_SECURITY=y CONFIG_XFS_FS=m CONFIG_XFS_POSIX_ACL=y -CONFIG_INOTIFY=y -CONFIG_AUTOFS_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -260,14 +244,12 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_NFSD=y CONFIG_NFSD_V3_ACL=y CONFIG_NFSD_V4=y CONFIG_CIFS=m -CONFIG_PARTITION_ADVANCED=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_1250=y CONFIG_NLS_CODEPAGE_1251=y @@ -276,30 +258,21 @@ CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_15=y CONFIG_NLS_UTF8=y CONFIG_CRC_T10DIF=y -CONFIG_LIBCRC32C=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_MUTEXES=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_LATENCYTOP=y -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_BOOTX_TEXT=y CONFIG_PPC_EARLY_DEBUG=y -CONFIG_PPC_EARLY_DEBUG_BOOTX=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_MD4=m CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m diff --git a/arch/powerpc/configs/gamecube_defconfig b/arch/powerpc/configs/gamecube_defconfig index 9ef2cc13e1b4..6c6c60f1aba4 100644 --- a/arch/powerpc/configs/gamecube_defconfig +++ b/arch/powerpc/configs/gamecube_defconfig @@ -1,11 +1,9 @@ -CONFIG_EXPERIMENTAL=y CONFIG_LOCALVERSION="-gcn" CONFIG_SYSVIPC=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_ELF_CORE is not set CONFIG_PERF_EVENTS=y @@ -22,7 +20,6 @@ CONFIG_GAMECUBE=y CONFIG_PREEMPT=y CONFIG_BINFMT_MISC=m CONFIG_KEXEC=y -# CONFIG_MIGRATION is not set # CONFIG_SECCOMP is not set CONFIG_ADVANCED_OPTIONS=y CONFIG_NET=y @@ -42,15 +39,11 @@ CONFIG_IP_PNP_RARP=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_STANDALONE is not set # CONFIG_FW_LOADER is not set -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=2 CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_WLAN is not set CONFIG_INPUT_FF_MEMLESS=m # CONFIG_INPUT_MOUSEDEV is not set @@ -61,8 +54,8 @@ CONFIG_INPUT_EVDEV=y CONFIG_INPUT_JOYSTICK=y # CONFIG_SERIO_I8042 is not set # CONFIG_SERIO_SERPORT is not set -# CONFIG_DEVKMEM is not set CONFIG_LEGACY_PTY_COUNT=64 +# CONFIG_DEVKMEM is not set # CONFIG_HW_RANDOM is not set # CONFIG_HWMON is not set CONFIG_FB=y @@ -86,7 +79,6 @@ CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set -CONFIG_INOTIFY=y CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_MSDOS_FS=y @@ -95,20 +87,15 @@ CONFIG_PROC_KCORE=y # CONFIG_PROC_PAGE_MONITOR is not set CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_CIFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_CRC_CCITT=y CONFIG_PRINTK_TIME=y -CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_LATENCYTOP=y -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_SCHED_TRACER=y CONFIG_DMA_API_DEBUG=y CONFIG_PPC_EARLY_DEBUG=y diff --git a/arch/powerpc/configs/holly_defconfig b/arch/powerpc/configs/holly_defconfig index 94ebfee188db..5e0f2551e5c7 100644 --- a/arch/powerpc/configs/holly_defconfig +++ b/arch/powerpc/configs/holly_defconfig @@ -1,17 +1,16 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_MODULES=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_EMBEDDED6xx=y CONFIG_PPC_HOLLY=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="console=ttyS0,115200" @@ -30,18 +29,15 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 CONFIG_BLK_DEV_SD=y CONFIG_ATA=y CONFIG_NETDEVICES=y -CONFIG_PHYLIB=y -CONFIG_NET_ETHERNET=y -CONFIG_NET_VENDOR_3COM=y CONFIG_VORTEX=y CONFIG_TSI108_ETH=y +CONFIG_PHYLIB=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -57,14 +53,11 @@ CONFIG_SERIAL_OF_PLATFORM=y CONFIG_GEN_RTC=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y # CONFIG_SCHED_DEBUG is not set # CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_XMON=y diff --git a/arch/powerpc/configs/linkstation_defconfig b/arch/powerpc/configs/linkstation_defconfig index b5e684640fdf..62ae92956d05 100644 --- a/arch/powerpc/configs/linkstation_defconfig +++ b/arch/powerpc/configs/linkstation_defconfig @@ -1,6 +1,7 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 @@ -13,10 +14,7 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_PPC_PMAC is not set CONFIG_EMBEDDED6xx=y CONFIG_LINKSTATION=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_100=y -CONFIG_SPARSE_IRQ=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -43,12 +41,8 @@ CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m CONFIG_NETFILTER_XT_MATCH_STATE=m CONFIG_NF_CONNTRACK_IPV4=m CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_ADDRTYPE=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_NF_NAT=m -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_ECN=m CONFIG_IP_NF_TARGET_TTL=m @@ -58,10 +52,7 @@ CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y -CONFIG_MTD_CONCAT=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y @@ -72,27 +63,23 @@ CONFIG_MTD_CFI_GEOMETRY=y # CONFIG_MTD_CFI_I2 is not set CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=2 CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_MISC_DEVICES=y CONFIG_EEPROM_LEGACY=m CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_ATA=y CONFIG_PATA_IT821X=y CONFIG_PATA_SIL680=y CONFIG_NETDEVICES=y +CONFIG_NETCONSOLE=y CONFIG_TUN=m -CONFIG_NET_ETHERNET=y CONFIG_NET_TULIP=y CONFIG_TULIP=y CONFIG_TULIP_MMIO=y CONFIG_R8169=y -CONFIG_NETCONSOLE=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set CONFIG_INPUT_EVDEV=m # CONFIG_INPUT_KEYBOARD is not set @@ -106,7 +93,6 @@ CONFIG_HW_RANDOM=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y -CONFIG_VIDEO_OUTPUT_CONTROL=m # CONFIG_VGA_CONSOLE is not set CONFIG_HID=m # CONFIG_USB_HID is not set @@ -126,7 +112,6 @@ CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_XFS_FS=m -CONFIG_INOTIFY=y CONFIG_ISO9660_FS=m CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -137,7 +122,6 @@ CONFIG_NTFS_FS=m CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y @@ -153,15 +137,9 @@ CONFIG_CRC_T10DIF=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_MD4=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_SHA1=m -CONFIG_CRYPTO_AES=m -CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_TWOFISH=m diff --git a/arch/powerpc/configs/maple_defconfig b/arch/powerpc/configs/maple_defconfig index fbd9e4163311..ac9666f8abf1 100644 --- a/arch/powerpc/configs/maple_defconfig +++ b/arch/powerpc/configs/maple_defconfig @@ -1,10 +1,11 @@ CONFIG_PPC64=y CONFIG_SMP=y CONFIG_NR_CPUS=4 -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_FHANDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_COMPAT_BRK is not set @@ -16,16 +17,15 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_MAC_PARTITION=y # CONFIG_PPC_POWERNV is not set # CONFIG_PPC_PSERIES is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_MAPLE=y CONFIG_UDBG_RTAS_CONSOLE=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_KEXEC=y CONFIG_IRQ_ALL_CPUS=y -# CONFIG_MIGRATION is not set CONFIG_PCI_MSI=y CONFIG_NET=y CONFIG_PACKET=y @@ -38,7 +38,6 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_INET_LRO is not set # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_IDE=y @@ -52,11 +51,9 @@ CONFIG_CHR_DEV_SG=y CONFIG_SCSI_IPR=y CONFIG_ATA=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_NET_PCI=y CONFIG_AMD8111_ETH=y -CONFIG_E1000=y CONFIG_TIGON3=y +CONFIG_E1000=y CONFIG_USB_PEGASUS=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set CONFIG_INPUT_MOUSEDEV_SCREEN_X=1600 @@ -72,13 +69,11 @@ CONFIG_GEN_RTC=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_AMD8111=y -# CONFIG_HWMON is not set # CONFIG_VGA_CONSOLE is not set CONFIG_HID_GYRATION=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y CONFIG_USB_MON=y @@ -111,7 +106,6 @@ CONFIG_EXT2_FS_XIP=y CONFIG_EXT3_FS=y # CONFIG_EXT3_FS_XATTR is not set CONFIG_EXT4_FS=y -CONFIG_INOTIFY=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y @@ -119,28 +113,22 @@ CONFIG_TMPFS=y CONFIG_HUGETLBFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y CONFIG_NLS_DEFAULT="utf-8" CONFIG_NLS_UTF8=y CONFIG_CRC_CCITT=y CONFIG_CRC_T10DIF=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_LATENCYTOP=y -CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_STACKOVERFLOW=y +CONFIG_LATENCYTOP=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y CONFIG_BOOTX_TEXT=y CONFIG_PPC_EARLY_DEBUG=y -CONFIG_PPC_EARLY_DEBUG_BOOTX=y CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/mgcoge_defconfig b/arch/powerpc/configs/mgcoge_defconfig index 8fa84f156ef3..666922c5b572 100644 --- a/arch/powerpc/configs/mgcoge_defconfig +++ b/arch/powerpc/configs/mgcoge_defconfig @@ -1,7 +1,7 @@ -CONFIG_EXPERIMENTAL=y # CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 @@ -16,7 +16,6 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_PMAC is not set CONFIG_PPC_82xx=y CONFIG_MGCOGE=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=y # CONFIG_SECCOMP is not set CONFIG_NET=y @@ -36,8 +35,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLKDEVS=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_ADV_OPTIONS=y CONFIG_MTD_CFI_GEOMETRY=y @@ -45,7 +42,6 @@ CONFIG_MTD_CFI_GEOMETRY=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_NETDEVICES=y @@ -68,7 +64,6 @@ CONFIG_USB_GADGET=y CONFIG_USB_FSL_USB2=y CONFIG_USB_G_SERIAL=y CONFIG_UIO=y -CONFIG_UIO_PDRV=y CONFIG_EXT2_FS=y CONFIG_AUTOFS4_FS=y CONFIG_PROC_KCORE=y @@ -77,16 +72,15 @@ CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_SQUASHFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_FS=y -# CONFIG_SCHED_DEBUG is not set CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_SCHED_DEBUG is not set CONFIG_BDI_SWITCH=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/mpc512x_defconfig b/arch/powerpc/configs/mpc512x_defconfig index ee853a1b1b2c..59b85cb95259 100644 --- a/arch/powerpc/configs/mpc512x_defconfig +++ b/arch/powerpc/configs/mpc512x_defconfig @@ -50,7 +50,6 @@ CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_MPC5121_NFC=y CONFIG_MTD_UBI=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=1 CONFIG_BLK_DEV_RAM_SIZE=8192 @@ -81,7 +80,6 @@ CONFIG_MDIO_BITBANG=y # CONFIG_WLAN is not set # CONFIG_INPUT_MOUSEDEV_PSAUX is not set CONFIG_INPUT_EVDEV=y -CONFIG_VT_HW_CONSOLE_BINDING=y # CONFIG_DEVKMEM is not set CONFIG_SERIAL_MPC52xx=y CONFIG_SERIAL_MPC52xx_CONSOLE=y diff --git a/arch/powerpc/configs/mpc5200_defconfig b/arch/powerpc/configs/mpc5200_defconfig index 69fd8adf9f5e..9fd041bfd778 100644 --- a/arch/powerpc/configs/mpc5200_defconfig +++ b/arch/powerpc/configs/mpc5200_defconfig @@ -1,6 +1,6 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y -CONFIG_SPARSE_IRQ=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y CONFIG_MODULES=y @@ -16,8 +16,6 @@ CONFIG_PPC_MPC5200_BUGFIX=y CONFIG_PPC_MPC5200_LPBFIFO=m # CONFIG_PPC_PMAC is not set CONFIG_SIMPLE_GPIO=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -33,8 +31,6 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y @@ -42,7 +38,6 @@ CONFIG_MTD_ROM=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_PLATRAM=y CONFIG_MTD_UBI=m -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 @@ -77,7 +72,6 @@ CONFIG_SENSORS_LM87=m CONFIG_WATCHDOG=y CONFIG_MFD_SM501=m CONFIG_DRM=y -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_FB=y CONFIG_FB_FOREIGN_ENDIAN=y CONFIG_FB_RADEON=y @@ -94,9 +88,6 @@ CONFIG_SND=y # CONFIG_SND_SPI is not set # CONFIG_SND_USB is not set CONFIG_SND_SOC=y -CONFIG_SND_SOC_MPC5200_I2S=y -CONFIG_SND_MPC52xx_SOC_PCM030=y -CONFIG_SND_MPC52xx_SOC_EFIKA=y CONFIG_HID_DRAGONRISE=y CONFIG_HID_GYRATION=y CONFIG_HID_TWINHAN=y @@ -104,7 +95,6 @@ CONFIG_HID_ORTEK=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_HID_GREENASIA=y CONFIG_HID_SMARTJOYPLUS=y @@ -112,7 +102,6 @@ CONFIG_HID_TOPSEED=y CONFIG_HID_THRUSTMASTER=y CONFIG_HID_ZEROPLUS=y CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD_PPC_OF_BE=y @@ -135,13 +124,12 @@ CONFIG_JFFS2_FS=y CONFIG_UBIFS_FS=m CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -CONFIG_DEBUG_INFO=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/mpc7448_hpc2_defconfig b/arch/powerpc/configs/mpc7448_hpc2_defconfig index 75f0bbf0f6e8..e2647d5bb605 100644 --- a/arch/powerpc/configs/mpc7448_hpc2_defconfig +++ b/arch/powerpc/configs/mpc7448_hpc2_defconfig @@ -1,19 +1,17 @@ CONFIG_ALTIVEC=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_EMBEDDED6xx=y CONFIG_MPC7448HPC2=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=y -CONFIG_SPARSE_IRQ=y # CONFIG_SECCOMP is not set CONFIG_NET=y CONFIG_PACKET=y @@ -29,7 +27,6 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 @@ -37,13 +34,11 @@ CONFIG_BLK_DEV_SD=y CONFIG_ATA=y CONFIG_SATA_MV=y CONFIG_NETDEVICES=y -CONFIG_PHYLIB=y -CONFIG_NET_ETHERNET=y -CONFIG_NET_PCI=y CONFIG_E100=y CONFIG_8139TOO=y # CONFIG_8139TOO_PIO is not set CONFIG_TSI108_ETH=y +CONFIG_PHYLIB=y # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set @@ -53,17 +48,12 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_HW_RANDOM is not set CONFIG_GEN_RTC=y -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y CONFIG_CRC_T10DIF=y -# 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/mpc8272_ads_defconfig b/arch/powerpc/configs/mpc8272_ads_defconfig index 6a22400f73c1..825b052176af 100644 --- a/arch/powerpc/configs/mpc8272_ads_defconfig +++ b/arch/powerpc/configs/mpc8272_ads_defconfig @@ -1,17 +1,17 @@ CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_82xx=y CONFIG_MPC8272_ADS=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -27,7 +27,6 @@ CONFIG_NETFILTER=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_ADV_OPTIONS=y @@ -39,52 +38,41 @@ CONFIG_MTD_CFI_GEOMETRY=y CONFIG_MTD_CFI_I4=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y -# CONFIG_MISC_DEVICES is not set CONFIG_NETDEVICES=y CONFIG_TUN=y -CONFIG_DAVICOM_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_FS_ENET=y # CONFIG_FS_ENET_HAS_SCC is not set CONFIG_FS_ENET_MDIO_FCC=y +CONFIG_DAVICOM_PHY=y CONFIG_PPP=y +CONFIG_PPP_DEFLATE=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y -CONFIG_PPP_DEFLATE=y CONFIG_INPUT_EVDEV=y -# CONFIG_SERIO_I8042 is not set # CONFIG_VT is not set CONFIG_SERIAL_CPM=y CONFIG_SERIAL_CPM_CONSOLE=y # CONFIG_HWMON is not set -# CONFIG_HID_SUPPORT is not set # CONFIG_USB_SUPPORT is not set CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_AUTOFS4_FS=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y CONFIG_NLS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y CONFIG_BDI_SWITCH=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y diff --git a/arch/powerpc/configs/mpc83xx_defconfig b/arch/powerpc/configs/mpc83xx_defconfig index 23fec79964cf..671e220a9a98 100644 --- a/arch/powerpc/configs/mpc83xx_defconfig +++ b/arch/powerpc/configs/mpc83xx_defconfig @@ -1,4 +1,3 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y @@ -45,14 +44,12 @@ CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSL_ELBC=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 @@ -62,7 +59,6 @@ CONFIG_ATA=y CONFIG_SATA_FSL=y CONFIG_SATA_SIL=y CONFIG_NETDEVICES=y -CONFIG_MII=y CONFIG_UCC_GETH=y CONFIG_GIANFAR=y CONFIG_MARVELL_PHY=y @@ -82,7 +78,6 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y CONFIG_WATCHDOG=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_HID_A4TECH=y CONFIG_HID_APPLE=y CONFIG_HID_BELKIN=y @@ -97,7 +92,6 @@ CONFIG_HID_MONTEREY=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y CONFIG_USB_MON=y @@ -119,6 +113,5 @@ CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y -CONFIG_CRYPTO_AES=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 02395fab19bd..8535c343dd57 100644 --- a/arch/powerpc/configs/mpc85xx_defconfig +++ b/arch/powerpc/configs/mpc85xx_defconfig @@ -20,6 +20,7 @@ CONFIG_MODVERSIONS=y # CONFIG_BLK_DEV_BSG is not set CONFIG_PARTITION_ADVANCED=y CONFIG_MAC_PARTITION=y +CONFIG_C293_PCIE=y CONFIG_MPC8540_ADS=y CONFIG_MPC8560_ADS=y CONFIG_MPC85xx_CDS=y @@ -27,7 +28,6 @@ CONFIG_MPC85xx_MDS=y CONFIG_MPC8536_DS=y CONFIG_MPC85xx_DS=y CONFIG_MPC85xx_RDB=y -CONFIG_C293_PCIE=y CONFIG_P1010_RDB=y CONFIG_P1022_DS=y CONFIG_P1022_RDK=y @@ -42,6 +42,7 @@ CONFIG_TQM8548=y CONFIG_TQM8555=y CONFIG_TQM8560=y CONFIG_SBC8548=y +CONFIG_MVME2500=y CONFIG_QUICC_ENGINE=y CONFIG_QE_GPIO=y CONFIG_HIGHMEM=y @@ -49,6 +50,8 @@ CONFIG_BINFMT_MISC=m CONFIG_MATH_EMULATION=y CONFIG_FORCE_MAX_ZONEORDER=12 CONFIG_PCI=y +CONFIG_PCIEPORTBUS=y +# CONFIG_PCIEASPM is not set CONFIG_PCI_MSI=y CONFIG_RAPIDIO=y CONFIG_NET=y @@ -70,7 +73,6 @@ 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 @@ -80,33 +82,21 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_MTD=y -CONFIG_MTD_OF_PARTS=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLKDEVS=y CONFIG_MTD_BLOCK=y CONFIG_FTL=y CONFIG_MTD_CFI=y -CONFIG_MTD_GEN_PROBE=y -CONFIG_MTD_MAP_BANK_WIDTH_1=y -CONFIG_MTD_MAP_BANK_WIDTH_2=y -CONFIG_MTD_MAP_BANK_WIDTH_4=y -CONFIG_MTD_CFI_I1=y -CONFIG_MTD_CFI_I2=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_PLATRAM=y CONFIG_MTD_M25P80=y -CONFIG_MTD_CFI_UTIL=y -CONFIG_MTD_NAND_ECC=y CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_IDS=y CONFIG_MTD_NAND_FSL_ELBC=y CONFIG_MTD_NAND_FSL_IFC=y +CONFIG_MTD_SPI_NOR=y CONFIG_MTD_UBI=y -CONFIG_MTD_UBI_WL_THRESHOLD=4096 -CONFIG_MTD_UBI_BEB_RESERVE=1 -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y @@ -117,7 +107,6 @@ CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_LOGGING=y CONFIG_ATA=y CONFIG_SATA_AHCI=y @@ -133,11 +122,12 @@ CONFIG_GIANFAR=y CONFIG_E1000=y CONFIG_E1000E=y CONFIG_IGB=y +CONFIG_AT803X_PHY=y CONFIG_MARVELL_PHY=y CONFIG_DAVICOM_PHY=y CONFIG_CICADA_PHY=y CONFIG_VITESSE_PHY=y -CONFIG_AT803X_PHY=y +CONFIG_BROADCOM_PHY=y CONFIG_FIXED_PHY=y CONFIG_INPUT_FF_MEMLESS=m # CONFIG_INPUT_MOUSEDEV is not set @@ -146,8 +136,8 @@ CONFIG_INPUT_FF_MEMLESS=m CONFIG_SERIO_LIBPS2=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=2 -CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +CONFIG_SERIAL_8250_NR_UARTS=6 +CONFIG_SERIAL_8250_RUNTIME_UARTS=6 CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_DETECT_IRQ=y CONFIG_SERIAL_8250_RSA=y @@ -160,15 +150,12 @@ CONFIG_SPI=y CONFIG_SPI_FSL_SPI=y CONFIG_SPI_FSL_ESPI=y CONFIG_GPIO_MPC8XXX=y -# CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=y +CONFIG_HWMON=m +CONFIG_SENSORS_LM90=m CONFIG_FB=y CONFIG_FB_FSL_DIU=y # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FONTS=y -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y CONFIG_SOUND=y CONFIG_SND=y # CONFIG_SND_SUPPORT_OLD_API is not set @@ -192,7 +179,6 @@ CONFIG_HID_MONTEREY=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y CONFIG_USB_MON=y @@ -208,6 +194,7 @@ CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_OF_ESDHC=y CONFIG_EDAC=y CONFIG_EDAC_MM_EDAC=y +CONFIG_EDAC_MPC85XX=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=y CONFIG_RTC_DRV_DS1374=y @@ -215,8 +202,6 @@ CONFIG_RTC_DRV_DS3232=y CONFIG_RTC_DRV_CMOS=y CONFIG_DMADEVICES=y CONFIG_FSL_DMA=y -CONFIG_MEMORY=y -# CONFIG_NET_DMA is not set CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set @@ -227,21 +212,9 @@ CONFIG_UDF_FS=m CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=y CONFIG_NTFS_FS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_850=y -CONFIG_NLS_ISO8859_1=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_HUGETLBFS=y -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_FS_DEBUG=1 -CONFIG_JFFS2_FS_WRITEBUFFER=y -CONFIG_JFFS2_ZLIB=y -CONFIG_JFFS2_RTIME=y -CONFIG_UBIFS_FS=y -CONFIG_UBIFS_FS_XATTR=y -CONFIG_UBIFS_FS_LZO=y -CONFIG_UBIFS_FS_ZLIB=y CONFIG_ADFS_FS=m CONFIG_AFFS_FS=m CONFIG_HFS_FS=m @@ -249,6 +222,9 @@ CONFIG_HFSPLUS_FS=m CONFIG_BEFS_FS=m CONFIG_BFS_FS=m CONFIG_EFS_FS=m +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=1 +CONFIG_UBIFS_FS=y CONFIG_CRAMFS=y CONFIG_VXFS_FS=m CONFIG_HPFS_FS=m @@ -259,16 +235,16 @@ CONFIG_NFS_FS=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_NFSD=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_850=y +CONFIG_NLS_ISO8859_1=y CONFIG_CRC_T10DIF=y -CONFIG_CRC16=y -CONFIG_ZLIB_DEFLATE=y -CONFIG_LZO_COMPRESS=y -CONFIG_LZO_DECOMPRESS=y -CONFIG_CRYPTO_DEFLATE=y -CONFIG_CRYPTO_LZO=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_DEBUG_INFO=y CONFIG_DEBUG_FS=y CONFIG_DETECT_HUNG_TASK=y -CONFIG_DEBUG_INFO=y CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig index b5d1b82a1b43..c45ad2e01b0c 100644 --- a/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig @@ -2,14 +2,13 @@ CONFIG_PPC_85xx=y CONFIG_PHYS_64BIT=y CONFIG_SMP=y CONFIG_NR_CPUS=8 -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y CONFIG_AUDIT=y CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_BSD_PROCESS_ACCT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 @@ -23,6 +22,7 @@ CONFIG_MODVERSIONS=y # CONFIG_BLK_DEV_BSG is not set CONFIG_PARTITION_ADVANCED=y CONFIG_MAC_PARTITION=y +CONFIG_C293_PCIE=y CONFIG_MPC8540_ADS=y CONFIG_MPC8560_ADS=y CONFIG_MPC85xx_CDS=y @@ -30,7 +30,6 @@ CONFIG_MPC85xx_MDS=y CONFIG_MPC8536_DS=y CONFIG_MPC85xx_DS=y CONFIG_MPC85xx_RDB=y -CONFIG_C293_PCIE=y CONFIG_P1010_RDB=y CONFIG_P1022_DS=y CONFIG_P1022_RDK=y @@ -73,7 +72,6 @@ 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 @@ -83,33 +81,18 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_MTD=y -CONFIG_MTD_OF_PARTS=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLKDEVS=y CONFIG_MTD_BLOCK=y CONFIG_FTL=y CONFIG_MTD_CFI=y -CONFIG_MTD_GEN_PROBE=y -CONFIG_MTD_MAP_BANK_WIDTH_1=y -CONFIG_MTD_MAP_BANK_WIDTH_2=y -CONFIG_MTD_MAP_BANK_WIDTH_4=y -CONFIG_MTD_CFI_I1=y -CONFIG_MTD_CFI_I2=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_M25P80=y -CONFIG_MTD_CFI_UTIL=y -CONFIG_MTD_NAND_ECC=y CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_IDS=y CONFIG_MTD_NAND_FSL_ELBC=y CONFIG_MTD_NAND_FSL_IFC=y +CONFIG_MTD_SPI_NOR=y CONFIG_MTD_UBI=y -CONFIG_MTD_UBI_WL_THRESHOLD=4096 -CONFIG_MTD_UBI_BEB_RESERVE=1 -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y @@ -120,7 +103,6 @@ CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_LOGGING=y CONFIG_ATA=y CONFIG_SATA_AHCI=y @@ -133,11 +115,11 @@ CONFIG_FS_ENET=y CONFIG_UCC_GETH=y CONFIG_GIANFAR=y CONFIG_E1000E=y +CONFIG_AT803X_PHY=y CONFIG_MARVELL_PHY=y CONFIG_DAVICOM_PHY=y CONFIG_CICADA_PHY=y CONFIG_VITESSE_PHY=y -CONFIG_AT803X_PHY=y CONFIG_FIXED_PHY=y CONFIG_INPUT_FF_MEMLESS=m # CONFIG_INPUT_MOUSEDEV is not set @@ -162,14 +144,10 @@ CONFIG_SPI_FSL_SPI=y CONFIG_SPI_FSL_ESPI=y CONFIG_GPIO_MPC8XXX=y # CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_FB=y CONFIG_FB_FSL_DIU=y # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FONTS=y -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y CONFIG_SOUND=y CONFIG_SND=y # CONFIG_SND_SUPPORT_OLD_API is not set @@ -193,7 +171,6 @@ CONFIG_HID_MONTEREY=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y CONFIG_USB_MON=y @@ -216,8 +193,6 @@ CONFIG_RTC_DRV_DS3232=y CONFIG_RTC_DRV_CMOS=y CONFIG_DMADEVICES=y CONFIG_FSL_DMA=y -CONFIG_MEMORY=y -# CONFIG_NET_DMA is not set CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set @@ -228,21 +203,9 @@ CONFIG_UDF_FS=m CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=y CONFIG_NTFS_FS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_850=y -CONFIG_NLS_ISO8859_1=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_HUGETLBFS=y -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_FS_DEBUG=1 -CONFIG_JFFS2_FS_WRITEBUFFER=y -CONFIG_JFFS2_ZLIB=y -CONFIG_JFFS2_RTIME=y -CONFIG_UBIFS_FS=y -CONFIG_UBIFS_FS_XATTR=y -CONFIG_UBIFS_FS_LZO=y -CONFIG_UBIFS_FS_ZLIB=y CONFIG_ADFS_FS=m CONFIG_AFFS_FS=m CONFIG_HFS_FS=m @@ -250,6 +213,9 @@ CONFIG_HFSPLUS_FS=m CONFIG_BEFS_FS=m CONFIG_BFS_FS=m CONFIG_EFS_FS=m +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=1 +CONFIG_UBIFS_FS=y CONFIG_CRAMFS=y CONFIG_VXFS_FS=m CONFIG_HPFS_FS=m @@ -260,20 +226,19 @@ CONFIG_NFS_FS=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_NFSD=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_850=y +CONFIG_NLS_ISO8859_1=y CONFIG_CRC_T10DIF=y -CONFIG_CRC16=y -CONFIG_ZLIB_DEFLATE=y -CONFIG_LZO_COMPRESS=y -CONFIG_LZO_DECOMPRESS=y -CONFIG_CRYPTO_DEFLATE=y -CONFIG_CRYPTO_LZO=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_DEBUG_INFO=y CONFIG_DEBUG_FS=y CONFIG_DETECT_HUNG_TASK=y -CONFIG_DEBUG_INFO=y CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y -CONFIG_CRYPTO_AES=y # CONFIG_CRYPTO_ANSI_CPRNG is not set CONFIG_CRYPTO_DEV_FSL_CAAM=y CONFIG_CRYPTO_DEV_TALITOS=y diff --git a/arch/powerpc/configs/mpc866_ads_defconfig b/arch/powerpc/configs/mpc866_ads_defconfig index d954e80c286a..321412c5dae4 100644 --- a/arch/powerpc/configs/mpc866_ads_defconfig +++ b/arch/powerpc/configs/mpc866_ads_defconfig @@ -1,25 +1,21 @@ CONFIG_PPC_8xx=y -CONFIG_EXPERIMENTAL=y # CONFIG_SWAP is not set CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y -# CONFIG_SYSCTL_SYSCALL is not set -# CONFIG_HOTPLUG is not set # CONFIG_BUG is not set # CONFIG_BASE_FULL is not set # CONFIG_EPOLL is not set # CONFIG_VM_EVENT_COUNTERS is not set # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y CONFIG_MPC86XADS=y CONFIG_8xx_COPYBACK=y CONFIG_8xx_CPU6=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_1000=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y # CONFIG_SECCOMP is not set CONFIG_NET=y CONFIG_PACKET=y @@ -32,27 +28,21 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set CONFIG_BLK_DEV_LOOP=y CONFIG_NETDEVICES=y -CONFIG_FIXED_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_FS_ENET=y +CONFIG_FIXED_PHY=y # CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_CPM=y CONFIG_SERIAL_CPM_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set CONFIG_GEN_RTC=y -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y CONFIG_CRC_CCITT=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -# CONFIG_CRYPTO_ANSI_CPRNG is not set CONFIG_CRC32_SLICEBY4=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/mpc86xx_defconfig b/arch/powerpc/configs/mpc86xx_defconfig index fc58aa8a89e4..a4572563681c 100644 --- a/arch/powerpc/configs/mpc86xx_defconfig +++ b/arch/powerpc/configs/mpc86xx_defconfig @@ -1,23 +1,24 @@ CONFIG_SMP=y CONFIG_NR_CPUS=2 -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BSD_PROCESS_ACCT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_MAC_PARTITION=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_86xx=y @@ -26,11 +27,8 @@ CONFIG_SBC8641D=y CONFIG_MPC8610_HPCD=y CONFIG_GEF_SBC610=y CONFIG_HIGHMEM=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_1000=y CONFIG_BINFMT_MISC=m -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -48,12 +46,9 @@ CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y CONFIG_NET_IPIP=y -CONFIG_NET_IPGRE=y -CONFIG_NET_IPGRE_BROADCAST=y CONFIG_IP_MROUTE=y CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y -CONFIG_ARPD=y # CONFIG_INET_XFRM_MODE_TRANSPORT is not set # CONFIG_INET_XFRM_MODE_TUNNEL is not set # CONFIG_INET_XFRM_MODE_BEET is not set @@ -61,28 +56,23 @@ CONFIG_ARPD=y CONFIG_IPV6=y CONFIG_IP_SCTP=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 -CONFIG_MISC_DEVICES=y CONFIG_EEPROM_LEGACY=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_LOGGING=y CONFIG_ATA=y CONFIG_SATA_AHCI=y CONFIG_PATA_ALI=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y -CONFIG_VITESSE_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y CONFIG_GIANFAR=y +CONFIG_VITESSE_PHY=y CONFIG_INPUT_FF_MEMLESS=m # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set @@ -102,7 +92,6 @@ CONFIG_NVRAM=y CONFIG_I2C=y CONFIG_I2C_MPC=y # CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_MIXER_OSS=y @@ -123,7 +112,6 @@ CONFIG_HID_MONTEREY=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y CONFIG_USB_MON=y @@ -137,7 +125,6 @@ CONFIG_RTC_DRV_CMOS=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_ISO9660_FS=m CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -145,9 +132,6 @@ CONFIG_UDF_FS=m CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=y CONFIG_NTFS_FS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_850=y -CONFIG_NLS_ISO8859_1=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_ADFS_FS=m @@ -164,18 +148,15 @@ CONFIG_QNX4FS_FS=m CONFIG_SYSV_FS=m CONFIG_UFS_FS=m CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_NFSD=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_850=y +CONFIG_NLS_ISO8859_1=y CONFIG_CRC_T10DIF=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_DETECT_HUNG_TASK=y CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_HMAC=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/mpc885_ads_defconfig b/arch/powerpc/configs/mpc885_ads_defconfig index 3f47d00a10c0..2a10f98d4ee5 100644 --- a/arch/powerpc/configs/mpc885_ads_defconfig +++ b/arch/powerpc/configs/mpc885_ads_defconfig @@ -1,23 +1,19 @@ CONFIG_PPC_8xx=y -CONFIG_EXPERIMENTAL=y # CONFIG_SWAP is not set CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_BASE_FULL is not set # CONFIG_FUTEX is not set # CONFIG_VM_EVENT_COUNTERS is not set # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_CFQ is not set CONFIG_8xx_COPYBACK=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_100=y -CONFIG_8XX_MINIMAL_FPEMU=y -CONFIG_SPARSE_IRQ=y # CONFIG_SECCOMP is not set CONFIG_NET=y CONFIG_PACKET=y @@ -34,7 +30,6 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_ADV_OPTIONS=y @@ -46,22 +41,17 @@ CONFIG_MTD_CFI_GEOMETRY=y CONFIG_MTD_CFI_I4=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y # CONFIG_BLK_DEV is not set -# CONFIG_MISC_DEVICES is not set CONFIG_NETDEVICES=y -CONFIG_DAVICOM_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_FS_ENET=y # CONFIG_FS_ENET_HAS_SCC is not set -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set +CONFIG_DAVICOM_PHY=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_CPM=y CONFIG_SERIAL_CPM_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set CONFIG_GEN_RTC=y # CONFIG_HWMON is not set # CONFIG_USB_SUPPORT is not set @@ -69,13 +59,8 @@ CONFIG_GEN_RTC=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_CRC32 is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y -CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_CRC32_SLICEBY4=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/powerpc/configs/mvme5100_defconfig b/arch/powerpc/configs/mvme5100_defconfig index 93c7752e2dbb..525a2cb500a7 100644 --- a/arch/powerpc/configs/mvme5100_defconfig +++ b/arch/powerpc/configs/mvme5100_defconfig @@ -61,7 +61,6 @@ CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m CONFIG_LAPB=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=2 @@ -88,13 +87,10 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y # CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=m # CONFIG_VGA_CONSOLE is not set # CONFIG_HID is not set # CONFIG_USB_SUPPORT is not set # CONFIG_IOMMU_SUPPORT is not set -CONFIG_VME_BUS=m -CONFIG_VME_CA91CX42=m CONFIG_EXT2_FS=m CONFIG_EXT3_FS=m # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set @@ -122,11 +118,6 @@ CONFIG_NLS_UTF8=m CONFIG_CRC_CCITT=m CONFIG_CRC_T10DIF=y CONFIG_XZ_DEC=y -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/powerpc/configs/pasemi_defconfig b/arch/powerpc/configs/pasemi_defconfig index 3e72c8c06a0d..8f94782eb907 100644 --- a/arch/powerpc/configs/pasemi_defconfig +++ b/arch/powerpc/configs/pasemi_defconfig @@ -54,7 +54,6 @@ CONFIG_MTD_SLRAM=y CONFIG_MTD_PHRAM=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_PASEMI=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=16384 @@ -69,7 +68,6 @@ CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_ATA=y @@ -134,7 +132,6 @@ CONFIG_HID_NTRIG=y CONFIG_HID_PANTHERLORD=y CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_HID_GREENASIA=y CONFIG_HID_SMARTJOYPLUS=y diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig index 0351b5ffdfef..ea8705ffcd76 100644 --- a/arch/powerpc/configs/pmac32_defconfig +++ b/arch/powerpc/configs/pmac32_defconfig @@ -1,19 +1,20 @@ CONFIG_ALTIVEC=y -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_CHRP is not set CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y @@ -21,13 +22,9 @@ CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_PMAC=y CONFIG_PPC601_SYNC_FIX=y CONFIG_HIGHMEM=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=m -# CONFIG_MIGRATION is not set -CONFIG_PM=y -CONFIG_PM_DEBUG=y CONFIG_HIBERNATION=y +CONFIG_PM_DEBUG=y CONFIG_APM_EMULATION=y CONFIG_PCCARD=m CONFIG_YENTA=m @@ -46,7 +43,6 @@ CONFIG_INET_ESP=y # CONFIG_INET_LRO is not set # CONFIG_IPV6 is not set CONFIG_NETFILTER=y -CONFIG_NETFILTER_NETLINK_QUEUE=m CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_FTP=m CONFIG_NF_CONNTRACK_IRC=m @@ -84,18 +80,11 @@ CONFIG_NETFILTER_XT_MATCH_TIME=m CONFIG_NETFILTER_XT_MATCH_U32=m CONFIG_NF_CONNTRACK_IPV4=m CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_ADDRTYPE=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_ECN=m CONFIG_IP_NF_TARGET_TTL=m @@ -112,8 +101,6 @@ CONFIG_IRDA_CACHE_LAST_LSAP=y CONFIG_IRDA_FAST_RR=y CONFIG_IRTTY_SIR=m CONFIG_BT=m -CONFIG_BT_L2CAP=y -CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m @@ -128,10 +115,8 @@ CONFIG_MAC80211_LEDS=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_STANDALONE is not set CONFIG_CONNECTOR=y -CONFIG_PROC_DEVICETREE=y CONFIG_MAC_FLOPPY=m CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_UB=m CONFIG_BLK_DEV_RAM=y CONFIG_IDE=y CONFIG_BLK_DEV_IDECS=m @@ -152,7 +137,6 @@ CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_AIC7XXX=m CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 CONFIG_AIC7XXX_RESET_DELAY_MS=15000 -CONFIG_SCSI_AIC7XXX_OLD=m CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 CONFIG_SCSI_MESH=y @@ -170,12 +154,6 @@ CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m CONFIG_DM_MIRROR=m CONFIG_DM_ZERO=m -CONFIG_IEEE1394=m -CONFIG_IEEE1394_OHCI1394=m -CONFIG_IEEE1394_SBP2=m -CONFIG_IEEE1394_RAWIO=m -CONFIG_IEEE1394_VIDEO1394=m -CONFIG_IEEE1394_DV1394=m CONFIG_ADB=y CONFIG_ADB_CUDA=y CONFIG_ADB_PMU=y @@ -193,27 +171,22 @@ CONFIG_PMAC_RACKMETER=m CONFIG_NETDEVICES=y CONFIG_DUMMY=m CONFIG_TUN=m -CONFIG_NET_ETHERNET=y +CONFIG_PCNET32=y CONFIG_MACE=y CONFIG_BMAC=y CONFIG_SUNGEM=y -CONFIG_NET_PCI=y -CONFIG_PCNET32=y -CONFIG_PRISM54=m -CONFIG_B43=m -CONFIG_B43LEGACY=m -CONFIG_HERMES=m -CONFIG_APPLE_AIRPORT=m -CONFIG_PCMCIA_HERMES=m -CONFIG_P54_COMMON=m -CONFIG_USB_USBNET=m -# CONFIG_USB_NET_CDC_SUBSET is not set CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=y CONFIG_PPP_MULTILINK=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_BSDCOMP=m +CONFIG_USB_USBNET=m +# CONFIG_USB_NET_CDC_SUBSET is not set +CONFIG_PRISM54=m +CONFIG_B43=m +CONFIG_B43LEGACY=m +CONFIG_P54_COMMON=m CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set # CONFIG_MOUSE_PS2 is not set @@ -226,7 +199,6 @@ CONFIG_SERIAL_PMACZILOG_TTYS=y CONFIG_NVRAM=y CONFIG_GEN_RTC=y CONFIG_I2C_CHARDEV=m -CONFIG_POWER_SUPPLY=y CONFIG_APM_POWER=y CONFIG_BATTERY_PMU=y CONFIG_HWMON=m @@ -253,7 +225,6 @@ CONFIG_FB_ATY=y CONFIG_FB_ATY_CT=y CONFIG_FB_ATY_GX=y CONFIG_FB_3DFX=y -CONFIG_DISPLAY_SUPPORT=y # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y @@ -314,7 +285,6 @@ CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT3_FS_POSIX_ACL=y CONFIG_EXT4_FS=y -CONFIG_INOTIFY=y CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_ISO9660_FS=y @@ -328,34 +298,27 @@ CONFIG_TMPFS=y CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_NFSD=m CONFIG_NFSD_V3_ACL=y CONFIG_NFSD_V4=y -CONFIG_SMB_FS=m -CONFIG_PARTITION_ADVANCED=y CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_ISO8859_1=m CONFIG_CRC_T10DIF=y CONFIG_LIBCRC32C=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_LATENCYTOP=y -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_XMON=y CONFIG_XMON_DEFAULT=y CONFIG_BOOTX_TEXT=y CONFIG_PPC_EARLY_DEBUG=y -CONFIG_PPC_EARLY_DEBUG_BOOTX=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m diff --git a/arch/powerpc/configs/ppc40x_defconfig b/arch/powerpc/configs/ppc40x_defconfig index 52908c7897d9..a43bf6ea10fb 100644 --- a/arch/powerpc/configs/ppc40x_defconfig +++ b/arch/powerpc/configs/ppc40x_defconfig @@ -1,13 +1,10 @@ CONFIG_40x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set @@ -18,7 +15,6 @@ CONFIG_HOTFOOT=y CONFIG_KILAUEA=y CONFIG_MAKALU=y CONFIG_XILINX_VIRTEX_GENERIC_BOARD=y -CONFIG_SPARSE_IRQ=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -34,8 +30,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=m CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y @@ -43,13 +37,10 @@ CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_UBI=m CONFIG_MTD_UBI_GLUEBI=m -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_XILINX_SYSACE=m CONFIG_NETDEVICES=y -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y # CONFIG_INPUT is not set CONFIG_SERIO=m @@ -73,13 +64,11 @@ CONFIG_I2C_IBM_IIC=m CONFIG_GPIO_XILINX=y # CONFIG_HWMON is not set CONFIG_THERMAL=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=m CONFIG_FB_XILINX=m CONFIG_EXT2_FS=y CONFIG_EXT3_FS=m # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_VFAT_FS=m CONFIG_PROC_KCORE=y CONFIG_TMPFS=y @@ -87,16 +76,12 @@ CONFIG_JFFS2_FS=m CONFIG_UBIFS_FS=m CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_ISO8859_1=m -CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y diff --git a/arch/powerpc/configs/ppc44x_defconfig b/arch/powerpc/configs/ppc44x_defconfig index 924e10df1844..bbc7f76d52c8 100644 --- a/arch/powerpc/configs/ppc44x_defconfig +++ b/arch/powerpc/configs/ppc44x_defconfig @@ -1,13 +1,10 @@ CONFIG_44x=y -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set @@ -28,7 +25,6 @@ CONFIG_YOSEMITE=y CONFIG_XILINX_VIRTEX440_GENERIC_BOARD=y CONFIG_PPC4xx_GPIO=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -44,8 +40,6 @@ CONFIG_BRIDGE=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_CONNECTOR=y CONFIG_MTD=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y @@ -55,7 +49,6 @@ CONFIG_MTD_NAND=m CONFIG_MTD_NAND_NDFC=m CONFIG_MTD_UBI=m CONFIG_MTD_UBI_GLUEBI=m -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=35000 CONFIG_XILINX_SYSACE=m @@ -64,8 +57,6 @@ CONFIG_BLK_DEV_SD=m # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y CONFIG_TUN=m -CONFIG_ETHERNET=y -CONFIG_NET_VENDOR_IBM=y CONFIG_IBM_EMAC=y # CONFIG_INPUT is not set CONFIG_SERIO=m @@ -105,23 +96,18 @@ CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_UBIFS_FS=m -CONFIG_UBIFS_FS_XATTR=y CONFIG_LOGFS=m CONFIG_CRAMFS=y CONFIG_SQUASHFS=m CONFIG_SQUASHFS_XATTR=y CONFIG_SQUASHFS_LZO=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=m CONFIG_NLS_ISO8859_1=m CONFIG_CRC_T10DIF=m CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_ECB=y CONFIG_CRYPTO_PCBC=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index 5830d735c5c3..3315c9f0828a 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -1,6 +1,4 @@ CONFIG_PPC64=y -CONFIG_ALTIVEC=y -CONFIG_VSX=y CONFIG_SMP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -42,10 +40,8 @@ CONFIG_PPC_CELLEB=y CONFIG_PPC_CELL_QPACE=y CONFIG_RTAS_FLASH=m CONFIG_IBMEBUS=y -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=y -CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_PMAC64=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_HZ_100=y CONFIG_BINFMT_MISC=m CONFIG_PPC_TRANSACTIONAL_MEM=y @@ -53,6 +49,7 @@ CONFIG_KEXEC=y CONFIG_CRASH_DUMP=y CONFIG_IRQ_ALL_CPUS=y CONFIG_MEMORY_HOTREMOVE=y +CONFIG_KSM=y CONFIG_SCHED_SMT=y CONFIG_PCCARD=y CONFIG_ELECTRA_CF=y @@ -82,7 +79,6 @@ CONFIG_BPF_JIT=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_FD=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=m @@ -101,7 +97,6 @@ CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_CXGB3_ISCSI=m @@ -122,6 +117,7 @@ CONFIG_SCSI_DH=m CONFIG_SCSI_DH_RDAC=m CONFIG_SCSI_DH_ALUA=m CONFIG_ATA=y +CONFIG_SATA_AHCI=y CONFIG_SATA_SIL24=y CONFIG_SATA_MV=y CONFIG_SATA_SVW=y @@ -145,7 +141,6 @@ CONFIG_DM_MULTIPATH_ST=m CONFIG_DM_UEVENT=y CONFIG_ADB_PMU=y CONFIG_PMAC_SMU=y -CONFIG_THERM_PM72=y CONFIG_WINDFARM=y CONFIG_WINDFARM_PM81=y CONFIG_WINDFARM_PM91=y @@ -209,7 +204,6 @@ CONFIG_RAW_DRIVER=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_AMD8111=y CONFIG_I2C_PASEMI=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y CONFIG_FIRMWARE_EDID=y CONFIG_FB_OF=y @@ -296,6 +290,7 @@ CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_NILFS2_FS=m CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_UDF_FS=m CONFIG_MSDOS_FS=y @@ -326,7 +321,6 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y -CONFIG_CRC_T10DIF=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_STACK_USAGE=y @@ -362,4 +356,4 @@ CONFIG_CRYPTO_DEV_NX=y CONFIG_CRYPTO_DEV_NX_ENCRYPT=m CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m -CONFIG_KVM_BOOK3S_64_HV=y +CONFIG_KVM_BOOK3S_64_HV=m diff --git a/arch/powerpc/configs/ppc64e_defconfig b/arch/powerpc/configs/ppc64e_defconfig index 67885b2d70aa..ddf9773458cf 100644 --- a/arch/powerpc/configs/ppc64e_defconfig +++ b/arch/powerpc/configs/ppc64e_defconfig @@ -22,7 +22,6 @@ CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y CONFIG_PARTITION_ADVANCED=y CONFIG_MAC_PARTITION=y -CONFIG_EFI_PARTITION=y CONFIG_CORENET_GENERIC=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y @@ -55,7 +54,6 @@ CONFIG_BRIDGE=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_FD=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=m @@ -70,7 +68,6 @@ CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_SRP_ATTRS=y @@ -131,7 +128,6 @@ CONFIG_SERIAL_8250_CONSOLE=y CONFIG_RAW_DRIVER=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_AMD8111=y -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y CONFIG_FIRMWARE_EDID=y CONFIG_FB_OF=y diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index ad6d6b5af7d7..e5d2c3dc07f1 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -1,26 +1,22 @@ CONFIG_FSL_EMB_PERFMON=y -CONFIG_EXPERIMENTAL=y # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_TASKSTATS=y CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_AUDIT=y CONFIG_CGROUPS=y CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_CPUACCT=y -CONFIG_RESOURCE_COUNTERS=y CONFIG_CGROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y -CONFIG_UTS_NS=y -CONFIG_IPC_NS=y CONFIG_USER_NS=y -CONFIG_PID_NS=y CONFIG_BLK_DEV_INITRD=y -CONFIG_KALLSYMS_EXTRA_PASS=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=m @@ -29,10 +25,19 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_SRCVERSION_ALL=y CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_SGI_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y CONFIG_PPC_MPC52xx=y CONFIG_PPC_EFIKA=y CONFIG_PPC_MPC5200_BUGFIX=y -CONFIG_PPC_MPC5200_GPIO=y CONFIG_PPC_82xx=y CONFIG_MPC8272_ADS=y CONFIG_PQ2FADS=y @@ -56,7 +61,6 @@ CONFIG_SBC8641D=y CONFIG_MPC8610_HPCD=y CONFIG_GEF_SBC610=y CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_DEBUG=y CONFIG_CPU_FREQ_STAT=m CONFIG_CPU_FREQ_STAT_DETAILS=y CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y @@ -69,19 +73,13 @@ CONFIG_TAU=y CONFIG_TAU_AVERAGE=y CONFIG_QUICC_ENGINE=y CONFIG_QE_GPIO=y -CONFIG_PPC_BESTCOMM=y -CONFIG_GPIO_MPC8XXX=y CONFIG_MCU_MPC8349EMITX=y CONFIG_HIGHMEM=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_1000=y CONFIG_PREEMPT_VOLUNTARY=y CONFIG_BINFMT_MISC=y -# CONFIG_MIGRATION is not set -CONFIG_PM=y -CONFIG_PM_DEBUG=y CONFIG_HIBERNATION=y +CONFIG_PM_DEBUG=y CONFIG_ISA=y CONFIG_PCIEPORTBUS=y CONFIG_PCI_MSI=y @@ -106,8 +104,6 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_MULTIPATH=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_NET_IPIP=m -CONFIG_NET_IPGRE=m -CONFIG_NET_IPGRE_BROADCAST=y CONFIG_IP_MROUTE=y CONFIG_IP_PIMSM_V1=y CONFIG_IP_PIMSM_V2=y @@ -128,7 +124,6 @@ CONFIG_TCP_CONG_VENO=m CONFIG_TCP_CONG_YEAH=m CONFIG_TCP_CONG_ILLINOIS=m CONFIG_TCP_MD5SIG=y -CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_IPV6_OPTIMISTIC_DAD=y @@ -144,7 +139,6 @@ CONFIG_IPV6_MROUTE=y CONFIG_IPV6_PIMSM_V2=y CONFIG_NETLABEL=y CONFIG_NETFILTER=y -CONFIG_NETFILTER_NETLINK_QUEUE=m CONFIG_NF_CONNTRACK=m CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y @@ -159,7 +153,6 @@ 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 @@ -204,21 +197,12 @@ CONFIG_NETFILTER_XT_MATCH_TIME=m CONFIG_NETFILTER_XT_MATCH_U32=m CONFIG_NF_CONNTRACK_IPV4=m # CONFIG_NF_CONNTRACK_PROC_COMPAT is not set -CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_ADDRTYPE=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_NF_NAT_SNMP_BASIC=m CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_CLUSTERIP=m CONFIG_IP_NF_TARGET_ECN=m @@ -229,7 +213,6 @@ 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 @@ -240,7 +223,6 @@ 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 @@ -266,7 +248,6 @@ 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_NET_DCCPPROBE=m @@ -284,8 +265,6 @@ CONFIG_ATALK=m CONFIG_DEV_APPLETALK=m CONFIG_IPDDP=m CONFIG_IPDDP_ENCAP=y -CONFIG_IPDDP_DECAP=y -CONFIG_WAN_ROUTER=m CONFIG_NET_SCHED=y CONFIG_NET_SCH_CBQ=m CONFIG_NET_SCH_HTB=m @@ -349,8 +328,6 @@ CONFIG_VLSI_FIR=m CONFIG_VIA_FIR=m CONFIG_MCS_FIR=m CONFIG_BT=m -CONFIG_BT_L2CAP=y -CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m @@ -380,7 +357,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FIRMWARE_IN_KERNEL is not set CONFIG_DEBUG_DEVRES=y CONFIG_CONNECTOR=y -CONFIG_PROC_DEVICETREE=y CONFIG_PARPORT=m CONFIG_PARPORT_PC=m CONFIG_PARPORT_SERIAL=m @@ -396,7 +372,6 @@ CONFIG_BLK_DEV_RAM_SIZE=16384 CONFIG_CDROM_PKTCDVD=m CONFIG_VIRTIO_BLK=m CONFIG_BLK_DEV_HD=y -CONFIG_MISC_DEVICES=y CONFIG_ENCLOSURE_SERVICES=m CONFIG_SENSORS_TSL2550=m CONFIG_EEPROM_AT24=m @@ -419,7 +394,6 @@ CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=m CONFIG_SCSI_ENCLOSURE=m -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SCAN_ASYNC=y @@ -436,8 +410,8 @@ CONFIG_ATA=y # CONFIG_SATA_PMP is not set CONFIG_SATA_FSL=m CONFIG_PDC_ADMA=m -CONFIG_PATA_MPC52xx=m CONFIG_ATA_PIIX=m +CONFIG_PATA_MPC52xx=m CONFIG_PATA_OPTIDMA=m CONFIG_PATA_SCH=m CONFIG_PATA_VIA=m @@ -479,14 +453,108 @@ CONFIG_THERM_WINDTUNNEL=m CONFIG_THERM_ADT746X=m CONFIG_WINDFARM=y CONFIG_PMAC_RACKMETER=m +CONFIG_SENSORS_AMS=m CONFIG_NETDEVICES=y -CONFIG_IFB=m -CONFIG_DUMMY=m CONFIG_BONDING=m -CONFIG_MACVLAN=m +CONFIG_DUMMY=m CONFIG_EQUALIZER=m +CONFIG_NET_FC=y +CONFIG_IFB=m +CONFIG_MACVLAN=m +CONFIG_NETCONSOLE=m CONFIG_TUN=m CONFIG_VETH=m +CONFIG_VIRTIO_NET=m +CONFIG_ATM_TCP=m +CONFIG_ATM_LANAI=m +CONFIG_ATM_ENI=m +CONFIG_ATM_NICSTAR=m +CONFIG_ATM_IDT77252=m +CONFIG_ATM_HE=m +CONFIG_EL3=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_3C589=m +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ACENIC=m +CONFIG_AMD8111_ETH=m +CONFIG_PCNET32=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_MACE=m +CONFIG_BMAC=m +CONFIG_ATL1=m +CONFIG_B44=m +CONFIG_BNX2=m +CONFIG_TIGON3=m +CONFIG_BNX2X=m +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T3=m +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +CONFIG_TULIP_MMIO=y +CONFIG_DE4X5=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_ULI526X=m +CONFIG_PCMCIA_XIRCOM=m +CONFIG_DL2K=m +CONFIG_SUNDANCE=m +CONFIG_S2IO=m +CONFIG_FEC_MPC52xx=m +CONFIG_GIANFAR=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +CONFIG_IGB=m +CONFIG_IXGB=m +CONFIG_IXGBE=m +CONFIG_IP1000=m +CONFIG_MV643XX_ETH=m +CONFIG_SKGE=m +CONFIG_SKY2=m +CONFIG_MYRI10GE=m +CONFIG_FEALNX=m +CONFIG_NATSEMI=m +CONFIG_NS83820=m +CONFIG_PCMCIA_AXNET=m +CONFIG_NE2000=m +CONFIG_NE2K_PCI=m +CONFIG_PCMCIA_PCNET=m +CONFIG_ULTRA=m +CONFIG_FORCEDETH=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_QLA3XXX=m +CONFIG_QLGE=m +CONFIG_NETXEN_NIC=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +# CONFIG_8139TOO_PIO is not set +CONFIG_8139TOO_8129=y +CONFIG_R8169=m +CONFIG_R6040=m +CONFIG_SC92031=m +CONFIG_SIS900=m +CONFIG_SIS190=m +CONFIG_SFC=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_EPIC100=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_CASSINI=m +CONFIG_NIU=m +CONFIG_TEHUTI=m +CONFIG_TLAN=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_VELOCITY=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_FDDI=y +CONFIG_SKFP=m CONFIG_NET_SB1000=m CONFIG_MARVELL_PHY=m CONFIG_DAVICOM_PHY=m @@ -498,90 +566,18 @@ CONFIG_SMSC_PHY=m CONFIG_BROADCOM_PHY=m CONFIG_ICPLUS_PHY=m CONFIG_REALTEK_PHY=m -CONFIG_NET_ETHERNET=y -CONFIG_MACE=m -CONFIG_BMAC=m -CONFIG_HAPPYMEAL=m -CONFIG_SUNGEM=m -CONFIG_CASSINI=m -CONFIG_NET_VENDOR_3COM=y -CONFIG_EL3=m -CONFIG_VORTEX=m -CONFIG_TYPHOON=m -CONFIG_NET_VENDOR_SMC=y -CONFIG_ULTRA=m -CONFIG_NET_TULIP=y -CONFIG_DE2104X=m -CONFIG_TULIP=m -CONFIG_TULIP_MMIO=y -CONFIG_DE4X5=m -CONFIG_WINBOND_840=m -CONFIG_DM9102=m -CONFIG_ULI526X=m -CONFIG_PCMCIA_XIRCOM=m -CONFIG_NET_ISA=y -CONFIG_EWRK3=m -CONFIG_NE2000=m -CONFIG_NET_PCI=y -CONFIG_PCNET32=m -CONFIG_AMD8111_ETH=m -CONFIG_ADAPTEC_STARFIRE=m -CONFIG_B44=m -CONFIG_FORCEDETH=m -CONFIG_E100=m -CONFIG_FEALNX=m -CONFIG_NATSEMI=m -CONFIG_NE2K_PCI=m -CONFIG_8139CP=m -CONFIG_8139TOO=m -# CONFIG_8139TOO_PIO is not set -CONFIG_8139TOO_8129=y -CONFIG_R6040=m -CONFIG_SIS900=m -CONFIG_EPIC100=m -CONFIG_SUNDANCE=m -CONFIG_TLAN=m -CONFIG_VIA_RHINE=m -CONFIG_VIA_RHINE_MMIO=y -CONFIG_SC92031=m -CONFIG_NET_POCKET=y -CONFIG_DE600=m -CONFIG_DE620=m -CONFIG_FEC_MPC52xx=m -CONFIG_ACENIC=m -CONFIG_DL2K=m -CONFIG_E1000=m -CONFIG_E1000E=m -CONFIG_IP1000=m -CONFIG_IGB=m -CONFIG_NS83820=m -CONFIG_HAMACHI=m -CONFIG_YELLOWFIN=m -CONFIG_R8169=m -CONFIG_R8169_VLAN=y -CONFIG_SIS190=m -CONFIG_SKGE=m -CONFIG_SKY2=m -CONFIG_VIA_VELOCITY=m -CONFIG_TIGON3=m -CONFIG_BNX2=m -CONFIG_GIANFAR=m -CONFIG_MV643XX_ETH=m -CONFIG_QLA3XXX=m -CONFIG_ATL1=m -CONFIG_CHELSIO_T1=m -CONFIG_CHELSIO_T1_1G=y -CONFIG_CHELSIO_T3=m -CONFIG_IXGBE=m -CONFIG_IXGB=m -CONFIG_S2IO=m -CONFIG_MYRI10GE=m -CONFIG_NETXEN_NIC=m -CONFIG_NIU=m -CONFIG_TEHUTI=m -CONFIG_BNX2X=m -CONFIG_QLGE=m -CONFIG_SFC=m +CONFIG_PLIP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOATM=m +CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y CONFIG_USB_CATC=m CONFIG_USB_KAWETH=m CONFIG_USB_PEGASUS=m @@ -597,39 +593,6 @@ CONFIG_USB_ALI_M5632=y CONFIG_USB_AN2720=y CONFIG_USB_EPSON2888=y CONFIG_USB_KC2190=y -CONFIG_NET_PCMCIA=y -CONFIG_PCMCIA_3C589=m -CONFIG_PCMCIA_3C574=m -CONFIG_PCMCIA_FMVJ18X=m -CONFIG_PCMCIA_PCNET=m -CONFIG_PCMCIA_NMCLAN=m -CONFIG_PCMCIA_SMC91C92=m -CONFIG_PCMCIA_XIRC2PS=m -CONFIG_PCMCIA_AXNET=m -CONFIG_ATM_TCP=m -CONFIG_ATM_LANAI=m -CONFIG_ATM_ENI=m -CONFIG_ATM_NICSTAR=m -CONFIG_ATM_IDT77252=m -CONFIG_ATM_HE=m -CONFIG_FDDI=y -CONFIG_SKFP=m -CONFIG_PLIP=m -CONFIG_PPP_MULTILINK=y -CONFIG_PPP_FILTER=y -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_MPPE=m -CONFIG_PPPOE=m -CONFIG_PPPOATM=m -CONFIG_SLIP=m -CONFIG_SLIP_COMPRESSED=y -CONFIG_SLIP_SMART=y -CONFIG_NET_FC=y -CONFIG_NETCONSOLE=m -CONFIG_NETCONSOLE_DYNAMIC=y -CONFIG_VIRTIO_NET=m # CONFIG_INPUT_MOUSEDEV_PSAUX is not set CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y @@ -670,10 +633,8 @@ CONFIG_TABLET_USB_ACECAD=m CONFIG_TABLET_USB_AIPTEK=m CONFIG_TABLET_USB_GTCO=m CONFIG_TABLET_USB_KBTAB=m -CONFIG_TABLET_USB_WACOM=m CONFIG_INPUT_MISC=y CONFIG_INPUT_PCSPKR=m -CONFIG_INPUT_ATI_REMOTE=m CONFIG_INPUT_ATI_REMOTE2=m CONFIG_INPUT_KEYSPAN_REMOTE=m CONFIG_INPUT_POWERMATE=m @@ -685,16 +646,16 @@ CONFIG_GAMEPORT_NS558=m CONFIG_GAMEPORT_L4=m CONFIG_GAMEPORT_EMU10K1=m CONFIG_GAMEPORT_FM801=m -CONFIG_VT_HW_CONSOLE_BINDING=y -# CONFIG_DEVKMEM is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_NONSTANDARD=y CONFIG_ROCKETPORT=m CONFIG_CYCLADES=m CONFIG_SYNCLINK=m CONFIG_SYNCLINKMP=m CONFIG_SYNCLINK_GT=m -CONFIG_N_HDLC=m CONFIG_NOZOMI=m +CONFIG_N_HDLC=m +# CONFIG_DEVKMEM is not set CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_CS=m @@ -711,8 +672,6 @@ CONFIG_SERIAL_MPC52xx_CONSOLE=y CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200 CONFIG_SERIAL_JSM=m CONFIG_SERIAL_OF_PLATFORM=y -# CONFIG_LEGACY_PTYS is not set -CONFIG_BRIQ_PANEL=m CONFIG_PRINTER=m CONFIG_LP_CONSOLE=y CONFIG_PPDEV=m @@ -735,6 +694,7 @@ CONFIG_I2C_TINY_USB=m CONFIG_I2C_PCA_ISA=m CONFIG_I2C_STUB=m CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_MPC8XXX=y CONFIG_W1=m CONFIG_W1_MASTER_DS2490=m CONFIG_W1_MASTER_DS2482=m @@ -754,15 +714,13 @@ CONFIG_SENSORS_ADM1029=m CONFIG_SENSORS_ADM1031=m CONFIG_SENSORS_ADM9240=m CONFIG_SENSORS_ADT7470=m -CONFIG_SENSORS_AMS=m CONFIG_SENSORS_ATXP1=m CONFIG_SENSORS_DS1621=m -CONFIG_SENSORS_F71805F=m -CONFIG_SENSORS_F71882FG=m CONFIG_SENSORS_F75375S=m CONFIG_SENSORS_GL518SM=m CONFIG_SENSORS_GL520SM=m -CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX6650=m CONFIG_SENSORS_LM63=m CONFIG_SENSORS_LM75=m CONFIG_SENSORS_LM77=m @@ -774,20 +732,12 @@ CONFIG_SENSORS_LM87=m CONFIG_SENSORS_LM90=m CONFIG_SENSORS_LM92=m CONFIG_SENSORS_LM93=m -CONFIG_SENSORS_MAX1619=m -CONFIG_SENSORS_MAX6650=m -CONFIG_SENSORS_PC87360=m -CONFIG_SENSORS_PC87427=m CONFIG_SENSORS_PCF8591=m CONFIG_SENSORS_SIS5595=m -CONFIG_SENSORS_DME1737=m -CONFIG_SENSORS_SMSC47M1=m CONFIG_SENSORS_SMSC47M192=m -CONFIG_SENSORS_SMSC47B397=m CONFIG_SENSORS_ADS7828=m CONFIG_SENSORS_THMC50=m CONFIG_SENSORS_VIA686A=m -CONFIG_SENSORS_VT1211=m CONFIG_SENSORS_VT8231=m CONFIG_SENSORS_W83781D=m CONFIG_SENSORS_W83791D=m @@ -795,8 +745,6 @@ CONFIG_SENSORS_W83792D=m CONFIG_SENSORS_W83793=m CONFIG_SENSORS_W83L785TS=m CONFIG_SENSORS_W83L786NG=m -CONFIG_SENSORS_W83627HF=m -CONFIG_SENSORS_W83627EHF=m CONFIG_THERMAL=y CONFIG_WATCHDOG=y CONFIG_SOFT_WATCHDOG=m @@ -815,7 +763,6 @@ CONFIG_DRM_MGA=m CONFIG_DRM_SIS=m CONFIG_DRM_VIA=m CONFIG_DRM_SAVAGE=m -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y CONFIG_FB_CIRRUS=m CONFIG_FB_OF=y @@ -850,10 +797,8 @@ CONFIG_FB_TRIDENT=m CONFIG_FB_SM501=m CONFIG_FB_IBM_GXT4500=y CONFIG_LCD_PLATFORM=m -CONFIG_DISPLAY_SUPPORT=m CONFIG_VGACON_SOFT_SCROLLBACK=y CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set @@ -897,7 +842,6 @@ CONFIG_SND_CMIPCI=m CONFIG_SND_OXYGEN=m CONFIG_SND_CS4281=m CONFIG_SND_CS46XX=m -CONFIG_SND_CS5530=m CONFIG_SND_DARLA20=m CONFIG_SND_GINA20=m CONFIG_SND_LAYLA20=m @@ -919,7 +863,6 @@ CONFIG_SND_ES1968=m CONFIG_SND_FM801=m CONFIG_SND_HDSP=m CONFIG_SND_HDSPM=m -CONFIG_SND_HIFIER=m CONFIG_SND_ICE1712=m CONFIG_SND_ICE1724=m CONFIG_SND_KORG1212=m @@ -949,8 +892,6 @@ CONFIG_SND_USB_CAIAQ=m CONFIG_SND_USB_CAIAQ_INPUT=y # CONFIG_SND_PCMCIA is not set CONFIG_HIDRAW=y -CONFIG_HID_PID=y -CONFIG_USB_HIDDEV=y CONFIG_HID_GYRATION=y CONFIG_LOGITECH_FF=y CONFIG_LOGIRUMBLEPAD2_FF=y @@ -960,12 +901,12 @@ CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=m -CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_FSL=y CONFIG_USB_OHCI_HCD=m CONFIG_USB_OHCI_HCD_PPC_OF_BE=y @@ -1001,7 +942,6 @@ CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m CONFIG_USB_SERIAL_CYPRESS_M8=m CONFIG_USB_SERIAL_EMPEG=m CONFIG_USB_SERIAL_FTDI_SIO=m -CONFIG_USB_SERIAL_FUNSOFT=m CONFIG_USB_SERIAL_VISOR=m CONFIG_USB_SERIAL_IPAQ=m CONFIG_USB_SERIAL_IR=m @@ -1016,12 +956,10 @@ CONFIG_USB_SERIAL_KOBIL_SCT=m CONFIG_USB_SERIAL_MCT_U232=m CONFIG_USB_SERIAL_MOS7720=m CONFIG_USB_SERIAL_MOS7840=m -CONFIG_USB_SERIAL_MOTOROLA=m CONFIG_USB_SERIAL_NAVMAN=m CONFIG_USB_SERIAL_PL2303=m CONFIG_USB_SERIAL_OTI6858=m CONFIG_USB_SERIAL_SPCP8X5=m -CONFIG_USB_SERIAL_HP4X=m CONFIG_USB_SERIAL_SAFE=m CONFIG_USB_SERIAL_SAFE_PADDED=y CONFIG_USB_SERIAL_SIERRAWIRELESS=m @@ -1083,12 +1021,14 @@ CONFIG_RTC_DRV_M48T35=m CONFIG_RTC_DRV_M48T59=m CONFIG_RTC_DRV_V3020=m CONFIG_DMADEVICES=y +CONFIG_PPC_BESTCOMM=y CONFIG_AUXDISPLAY=y CONFIG_KS0108=m CONFIG_UIO=m CONFIG_UIO_CIF=m -CONFIG_UIO_PDRV=m CONFIG_UIO_PDRV_GENIRQ=m +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_BALLOON=m CONFIG_EXT2_FS=m CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y @@ -1111,12 +1051,7 @@ CONFIG_XFS_FS=m CONFIG_XFS_QUOTA=y CONFIG_XFS_POSIX_ACL=y CONFIG_GFS2_FS=m -CONFIG_OCFS2_FS=m -# CONFIG_OCFS2_DEBUG_MASKLOG is not set CONFIG_QUOTA_NETLINK_INTERFACE=y -# CONFIG_PRINT_QUOTA_WARNING is not set -CONFIG_QFMT_V2=y -CONFIG_AUTOFS_FS=m CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m CONFIG_ISO9660_FS=y @@ -1145,20 +1080,17 @@ CONFIG_ROMFS_FS=m CONFIG_SYSV_FS=m CONFIG_UFS_FS=m CONFIG_NFS_FS=m -CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y -CONFIG_NFS_V4=y +CONFIG_NFS_V4=m CONFIG_NFSD=m CONFIG_NFSD_V3_ACL=y CONFIG_NFSD_V4=y -CONFIG_RPCSEC_GSS_SPKM3=m 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 @@ -1170,17 +1102,6 @@ CONFIG_NCPFS_NLS=y CONFIG_NCPFS_EXTRAS=y CONFIG_CODA_FS=m CONFIG_9P_FS=m -CONFIG_PARTITION_ADVANCED=y -CONFIG_OSF_PARTITION=y -CONFIG_AMIGA_PARTITION=y -CONFIG_BSD_DISKLABEL=y -CONFIG_MINIX_SUBPARTITION=y -CONFIG_SOLARIS_X86_PARTITION=y -CONFIG_UNIXWARE_DISKLABEL=y -CONFIG_SGI_PARTITION=y -CONFIG_SUN_PARTITION=y -CONFIG_KARMA_PARTITION=y -CONFIG_EFI_PARTITION=y CONFIG_NLS_DEFAULT="utf8" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_737=m @@ -1219,29 +1140,27 @@ CONFIG_NLS_ISO8859_14=m CONFIG_NLS_ISO8859_15=m CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_U=m -CONFIG_DLM=m -CONFIG_DLM_DEBUG=y +CONFIG_DEBUG_INFO=y # CONFIG_ENABLE_WARN_DEPRECATED is not set -CONFIG_MAGIC_SYSRQ=y CONFIG_UNUSED_SYMBOLS=y CONFIG_HEADERS_CHECK=y +CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_SHIRQ=y -CONFIG_TIMER_STATS=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_FREE=y CONFIG_DEBUG_OBJECTS_TIMERS=y CONFIG_SLUB_DEBUG_ON=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_VM=y +CONFIG_DEBUG_HIGHMEM=y +CONFIG_DEBUG_STACKOVERFLOW=y +CONFIG_DEBUG_SHIRQ=y +CONFIG_TIMER_STATS=y CONFIG_DEBUG_RT_MUTEXES=y CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y -CONFIG_DEBUG_HIGHMEM=y -CONFIG_DEBUG_INFO=y -CONFIG_DEBUG_VM=y CONFIG_DEBUG_LIST=y CONFIG_DEBUG_SG=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_FAULT_INJECTION=y CONFIG_FAILSLAB=y CONFIG_FAIL_PAGE_ALLOC=y @@ -1250,17 +1169,12 @@ CONFIG_FAIL_IO_TIMEOUT=y CONFIG_FAULT_INJECTION_DEBUG_FS=y CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y CONFIG_LATENCYTOP=y -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_SCHED_TRACER=y CONFIG_STACK_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y -CONFIG_DEBUG_STACKOVERFLOW=y -CONFIG_DEBUG_STACK_USAGE=y CONFIG_XMON=y CONFIG_BOOTX_TEXT=y CONFIG_PPC_EARLY_DEBUG=y -CONFIG_PPC_EARLY_DEBUG_BOOTX=y -CONFIG_KEYS=y CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y @@ -1268,9 +1182,7 @@ CONFIG_SECURITY_NETWORK_XFRM=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y CONFIG_SECURITY_SELINUX_DISABLE=y -CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m CONFIG_CRYPTO_CTS=m CONFIG_CRYPTO_LRW=m @@ -1278,14 +1190,12 @@ CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_XTS=m CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_XCBC=m -CONFIG_CRYPTO_MD4=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m CONFIG_CRYPTO_RMD256=m CONFIG_CRYPTO_RMD320=m CONFIG_CRYPTO_SHA1=y -CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m @@ -1306,5 +1216,3 @@ CONFIG_CRYPTO_DEV_HIFN_795X=m CONFIG_CRYPTO_DEV_HIFN_795X_RNG=y CONFIG_CRYPTO_DEV_TALITOS=m CONFIG_VIRTUALIZATION=y -CONFIG_VIRTIO_PCI=m -CONFIG_VIRTIO_BALLOON=m diff --git a/arch/powerpc/configs/pq2fads_defconfig b/arch/powerpc/configs/pq2fads_defconfig index baad8db21b61..3e336ee8bb4a 100644 --- a/arch/powerpc/configs/pq2fads_defconfig +++ b/arch/powerpc/configs/pq2fads_defconfig @@ -1,20 +1,19 @@ CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_82xx=y CONFIG_PQ2FADS=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y -# CONFIG_8260_PCI9 is not set CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -29,7 +28,6 @@ CONFIG_NETFILTER=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_CFI_ADV_OPTIONS=y @@ -41,55 +39,43 @@ CONFIG_MTD_CFI_GEOMETRY=y CONFIG_MTD_CFI_I4=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_IDE=y CONFIG_NETDEVICES=y CONFIG_TUN=y -CONFIG_DAVICOM_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_FS_ENET=y # CONFIG_FS_ENET_HAS_SCC is not set CONFIG_FS_ENET_MDIO_FCC=y +CONFIG_DAVICOM_PHY=y CONFIG_PPP=y +CONFIG_PPP_DEFLATE=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y -CONFIG_PPP_DEFLATE=y CONFIG_INPUT_EVDEV=y -# CONFIG_SERIO_I8042 is not set # CONFIG_VT is not set CONFIG_SERIAL_CPM=y CONFIG_SERIAL_CPM_CONSOLE=y # CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=y -# CONFIG_HID_SUPPORT is not set CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_M66592=y +CONFIG_USB_ETH=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_AUTOFS4_FS=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_NLS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y +CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y # CONFIG_SCHED_DEBUG is not set -CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_BDI_SWITCH=y CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_ECB=y diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig index 879de5efb073..adc14e813a49 100644 --- a/arch/powerpc/configs/ps3_defconfig +++ b/arch/powerpc/configs/ps3_defconfig @@ -8,7 +8,6 @@ CONFIG_POSIX_MQUEUE=y CONFIG_FHANDLE=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_LZMA=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_EMBEDDED=y # CONFIG_PERF_EVENTS is not set @@ -22,6 +21,8 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_PPC_PSERIES is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_PS3=y +CONFIG_PS3_ADVANCED=y +CONFIG_PS3_REPOSITORY_WRITE=y CONFIG_PS3_DISK=y CONFIG_PS3_ROM=y CONFIG_PS3_FLASH=y @@ -64,11 +65,9 @@ CONFIG_BT_HCIBTUSB=m CONFIG_CFG80211=m CONFIG_CFG80211_WEXT=y CONFIG_MAC80211=m -CONFIG_MAC80211_RC_PID=y # CONFIG_MAC80211_RC_MINSTREL is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FIRMWARE_IN_KERNEL is not set -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=65535 @@ -76,7 +75,6 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_BLK_DEV_SR=y CONFIG_CHR_DEV_SG=m -CONFIG_SCSI_MULTI_LUN=y # CONFIG_SCSI_LOWLEVEL is not set CONFIG_MD=y CONFIG_BLK_DEV_DM=m @@ -107,7 +105,6 @@ CONFIG_INPUT_EVDEV=m # CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set # CONFIG_HWMON is not set -CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y CONFIG_FB_PS3=y # CONFIG_VGA_CONSOLE is not set @@ -130,8 +127,6 @@ CONFIG_HID_TWINHAN=m CONFIG_HID_LOGITECH=m CONFIG_HID_LOGITECH_DJ=m CONFIG_HID_MICROSOFT=m -CONFIG_HID_PS3REMOTE=m -CONFIG_HID_SONY=m CONFIG_HID_SUNPLUS=m CONFIG_HID_SMARTJOYPLUS=m CONFIG_USB_HIDDEV=y @@ -169,18 +164,17 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_CRC_CCITT=m CONFIG_CRC_T10DIF=y -CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_INFO=y CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_DEBUG_STACKOVERFLOW=y CONFIG_DETECT_HUNG_TASK=y CONFIG_PROVE_LOCKING=y CONFIG_DEBUG_LOCKDEP=y -CONFIG_DEBUG_INFO=y -CONFIG_DEBUG_MEMORY_INIT=y CONFIG_DEBUG_LIST=y CONFIG_RCU_CPU_STALL_TIMEOUT=60 # CONFIG_FTRACE is not set -CONFIG_DEBUG_STACKOVERFLOW=y -CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_MICHAEL_MIC=m diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 1f97364017c7..c2e39f66b182 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -1,6 +1,4 @@ CONFIG_PPC64=y -CONFIG_ALTIVEC=y -CONFIG_VSX=y CONFIG_SMP=y CONFIG_NR_CPUS=2048 CONFIG_SYSVIPC=y @@ -17,11 +15,18 @@ CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_NUMA_BALANCING=y +CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y CONFIG_CGROUPS=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_DEVICE=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_SCHED=y +CONFIG_USER_NS=y CONFIG_BLK_DEV_INITRD=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y @@ -40,6 +45,7 @@ CONFIG_DTL=y # CONFIG_PPC_PMAC is not set CONFIG_RTAS_FLASH=m CONFIG_IBMEBUS=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_HZ_100=y CONFIG_BINFMT_MISC=m CONFIG_PPC_TRANSACTIONAL_MEM=y @@ -47,6 +53,8 @@ CONFIG_KEXEC=y CONFIG_IRQ_ALL_CPUS=y CONFIG_MEMORY_HOTPLUG=y CONFIG_MEMORY_HOTREMOVE=y +CONFIG_KSM=y +CONFIG_TRANSPARENT_HUGEPAGE=y CONFIG_PPC_64K_PAGES=y CONFIG_PPC_SUBPAGE_PROT=y CONFIG_SCHED_SMT=y @@ -69,10 +77,10 @@ CONFIG_INET_IPCOMP=m CONFIG_NETFILTER=y # CONFIG_NETFILTER_ADVANCED is not set CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y -CONFIG_PROC_DEVICETREE=y CONFIG_PARPORT=m CONFIG_PARPORT_PC=m CONFIG_BLK_DEV_FD=m @@ -90,7 +98,6 @@ CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_CXGB3_ISCSI=m @@ -111,6 +118,7 @@ CONFIG_SCSI_DH=m CONFIG_SCSI_DH_RDAC=m CONFIG_SCSI_DH_ALUA=m CONFIG_ATA=y +CONFIG_SATA_AHCI=y # CONFIG_ATA_SFF is not set CONFIG_MD=y CONFIG_BLK_DEV_MD=y @@ -124,6 +132,7 @@ CONFIG_MD_FAULTY=m CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m +CONFIG_DM_THIN_PROVISIONING=m CONFIG_DM_MIRROR=m CONFIG_DM_ZERO=m CONFIG_DM_MULTIPATH=m @@ -132,8 +141,12 @@ CONFIG_DM_MULTIPATH_ST=m CONFIG_DM_UEVENT=y CONFIG_BONDING=m CONFIG_DUMMY=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_VXLAN=m CONFIG_NETCONSOLE=y CONFIG_TUN=m +CONFIG_VETH=m CONFIG_VIRTIO_NET=m CONFIG_VHOST_NET=m CONFIG_VORTEX=y @@ -166,6 +179,7 @@ CONFIG_INPUT_EVDEV=m CONFIG_INPUT_MISC=y CONFIG_INPUT_PCSPKR=m # CONFIG_SERIO_SERPORT is not set +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_ICOM=m @@ -242,6 +256,7 @@ CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_NILFS2_FS=m CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_UDF_FS=m CONFIG_MSDOS_FS=y @@ -270,7 +285,6 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y -CONFIG_CRC_T10DIF=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_STACK_USAGE=y @@ -304,7 +318,4 @@ CONFIG_CRYPTO_DEV_NX=y CONFIG_CRYPTO_DEV_NX_ENCRYPT=m CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m -CONFIG_KVM_BOOK3S_64_HV=y -CONFIG_TRANSPARENT_HUGEPAGE=y -CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y -CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_KVM_BOOK3S_64_HV=m diff --git a/arch/powerpc/configs/pseries_le_defconfig b/arch/powerpc/configs/pseries_le_defconfig index ac7ca5852827..09bc96e792cd 100644 --- a/arch/powerpc/configs/pseries_le_defconfig +++ b/arch/powerpc/configs/pseries_le_defconfig @@ -1,6 +1,4 @@ CONFIG_PPC64=y -CONFIG_ALTIVEC=y -CONFIG_VSX=y CONFIG_SMP=y CONFIG_NR_CPUS=2048 CONFIG_CPU_LITTLE_ENDIAN=y @@ -18,11 +16,18 @@ CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_NUMA_BALANCING=y +CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y CONFIG_CGROUPS=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_DEVICE=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_SCHED=y +CONFIG_USER_NS=y CONFIG_BLK_DEV_INITRD=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y @@ -41,6 +46,7 @@ CONFIG_DTL=y # CONFIG_PPC_PMAC is not set CONFIG_RTAS_FLASH=m CONFIG_IBMEBUS=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_HZ_100=y CONFIG_BINFMT_MISC=m CONFIG_PPC_TRANSACTIONAL_MEM=y @@ -48,6 +54,8 @@ CONFIG_KEXEC=y CONFIG_IRQ_ALL_CPUS=y CONFIG_MEMORY_HOTPLUG=y CONFIG_MEMORY_HOTREMOVE=y +CONFIG_KSM=y +CONFIG_TRANSPARENT_HUGEPAGE=y CONFIG_PPC_64K_PAGES=y CONFIG_PPC_SUBPAGE_PROT=y CONFIG_SCHED_SMT=y @@ -70,10 +78,10 @@ CONFIG_INET_IPCOMP=m CONFIG_NETFILTER=y # CONFIG_NETFILTER_ADVANCED is not set CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y -CONFIG_PROC_DEVICETREE=y CONFIG_PARPORT=m CONFIG_PARPORT_PC=m CONFIG_BLK_DEV_FD=m @@ -91,7 +99,6 @@ CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_CXGB3_ISCSI=m @@ -112,6 +119,7 @@ CONFIG_SCSI_DH=m CONFIG_SCSI_DH_RDAC=m CONFIG_SCSI_DH_ALUA=m CONFIG_ATA=y +CONFIG_SATA_AHCI=y # CONFIG_ATA_SFF is not set CONFIG_MD=y CONFIG_BLK_DEV_MD=y @@ -125,6 +133,7 @@ CONFIG_MD_FAULTY=m CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m +CONFIG_DM_THIN_PROVISIONING=m CONFIG_DM_MIRROR=m CONFIG_DM_ZERO=m CONFIG_DM_MULTIPATH=m @@ -133,8 +142,12 @@ CONFIG_DM_MULTIPATH_ST=m CONFIG_DM_UEVENT=y CONFIG_BONDING=m CONFIG_DUMMY=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_VXLAN=m CONFIG_NETCONSOLE=y CONFIG_TUN=m +CONFIG_VETH=m CONFIG_VIRTIO_NET=m CONFIG_VHOST_NET=m CONFIG_VORTEX=y @@ -167,6 +180,7 @@ CONFIG_INPUT_EVDEV=m CONFIG_INPUT_MISC=y CONFIG_INPUT_PCSPKR=m # CONFIG_SERIO_SERPORT is not set +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_ICOM=m @@ -243,6 +257,7 @@ CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_NILFS2_FS=m CONFIG_AUTOFS4_FS=m CONFIG_FUSE_FS=m +CONFIG_OVERLAY_FS=m CONFIG_ISO9660_FS=y CONFIG_UDF_FS=m CONFIG_MSDOS_FS=y @@ -271,7 +286,6 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=y -CONFIG_CRC_T10DIF=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_STACK_USAGE=y @@ -300,11 +314,6 @@ CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m # CONFIG_CRYPTO_ANSI_CPRNG is not set -CONFIG_CRYPTO_DEV_NX=y -CONFIG_CRYPTO_DEV_NX_ENCRYPT=m CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m -CONFIG_KVM_BOOK3S_64_HV=y -CONFIG_TRANSPARENT_HUGEPAGE=y -CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y -CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_KVM_BOOK3S_64_HV=m diff --git a/arch/powerpc/configs/storcenter_defconfig b/arch/powerpc/configs/storcenter_defconfig index 60ad2c08caa6..b5db7dffe86d 100644 --- a/arch/powerpc/configs/storcenter_defconfig +++ b/arch/powerpc/configs/storcenter_defconfig @@ -1,4 +1,3 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_EXPERT=y @@ -6,13 +5,13 @@ CONFIG_EXPERT=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_EMBEDDED6xx=y CONFIG_STORCENTER=y CONFIG_HZ_100=y CONFIG_BINFMT_MISC=y -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="console=ttyS0,115200" # CONFIG_SECCOMP is not set @@ -29,11 +28,8 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_INET_LRO is not set # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -# CONFIG_FW_LOADER is not set CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_FTL=y CONFIG_NFTL=y @@ -41,7 +37,6 @@ CONFIG_NFTL_RW=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP=y -CONFIG_PROC_DEVICETREE=y CONFIG_IDE=y CONFIG_BLK_DEV_VIA82CXXX=y CONFIG_SCSI=y @@ -57,7 +52,6 @@ CONFIG_MD_RAID456=y CONFIG_NETDEVICES=y CONFIG_DUMMY=m CONFIG_R8169=y -# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -81,12 +75,10 @@ CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_XFS_FS=m -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y # CONFIG_NETWORK_FILESYSTEMS is not set -CONFIG_PARTITION_ADVANCED=y CONFIG_NLS_DEFAULT="utf8" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y @@ -94,5 +86,3 @@ CONFIG_NLS_UTF8=y CONFIG_CRC_T10DIF=y # CONFIG_ENABLE_WARN_DEPRECATED is not set # CONFIG_ENABLE_MUST_CHECK is not set -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y diff --git a/arch/powerpc/configs/tqm8xx_defconfig b/arch/powerpc/configs/tqm8xx_defconfig index 7fe277a7b422..4c973c5321c6 100644 --- a/arch/powerpc/configs/tqm8xx_defconfig +++ b/arch/powerpc/configs/tqm8xx_defconfig @@ -1,12 +1,10 @@ CONFIG_PPC_8xx=y -CONFIG_EXPERIMENTAL=y # CONFIG_SWAP is not set CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y -# CONFIG_SYSCTL_SYSCALL is not set # CONFIG_ELF_CORE is not set # CONFIG_BASE_FULL is not set # CONFIG_FUTEX is not set @@ -15,15 +13,12 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_SRCVERSION_ALL=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_CFQ is not set CONFIG_TQM8XX=y CONFIG_8xx_COPYBACK=y # CONFIG_8xx_CPU15 is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_100=y -CONFIG_8XX_MINIMAL_FPEMU=y -CONFIG_SPARSE_IRQ=y # CONFIG_SECCOMP is not set CONFIG_NET=y CONFIG_PACKET=y @@ -40,32 +35,24 @@ CONFIG_SYN_COOKIES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_CONCAT=y CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_PROC_DEVICETREE=y # CONFIG_BLK_DEV is not set -# CONFIG_MISC_DEVICES is not set CONFIG_NETDEVICES=y +CONFIG_FS_ENET=y CONFIG_DAVICOM_PHY=y CONFIG_FIXED_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_FS_ENET=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set # CONFIG_WLAN is not set # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_CPM=y CONFIG_SERIAL_CPM_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set CONFIG_HW_RANDOM=y CONFIG_GEN_RTC=y # CONFIG_HWMON is not set @@ -74,13 +61,8 @@ CONFIG_GEN_RTC=y CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -# CONFIG_CRC32 is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DETECT_HUNG_TASK=y -CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_CRC32_SLICEBY4=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DETECT_HUNG_TASK=y diff --git a/arch/powerpc/configs/wii_defconfig b/arch/powerpc/configs/wii_defconfig index 1e2b7d062aa4..34eaf528fa87 100644 --- a/arch/powerpc/configs/wii_defconfig +++ b/arch/powerpc/configs/wii_defconfig @@ -1,4 +1,3 @@ -CONFIG_EXPERIMENTAL=y CONFIG_LOCALVERSION="-wii" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y @@ -6,7 +5,6 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y # CONFIG_ELF_CORE is not set CONFIG_PERF_EVENTS=y @@ -22,7 +20,6 @@ CONFIG_WII=y CONFIG_PREEMPT=y CONFIG_BINFMT_MISC=m CONFIG_KEXEC=y -# CONFIG_MIGRATION is not set # CONFIG_SECCOMP is not set CONFIG_ADVANCED_OPTIONS=y CONFIG_NET=y @@ -39,7 +36,6 @@ CONFIG_IP_PNP_RARP=y # CONFIG_INET_DIAG is not set # CONFIG_IPV6 is not set CONFIG_BT=y -CONFIG_BT_L2CAP=y CONFIG_BT_RFCOMM=y CONFIG_BT_BNEP=y CONFIG_BT_BNEP_MC_FILTER=y @@ -49,18 +45,12 @@ CONFIG_MAC80211=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_STANDALONE is not set # CONFIG_FIRMWARE_IN_KERNEL is not set -CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=2 CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set CONFIG_B43=y CONFIG_B43_SDIO=y # CONFIG_B43_PHY_LP is not set @@ -78,8 +68,8 @@ CONFIG_INPUT_MISC=y CONFIG_INPUT_UINPUT=y # CONFIG_SERIO_I8042 is not set # CONFIG_SERIO_SERPORT is not set -# CONFIG_DEVKMEM is not set CONFIG_LEGACY_PTY_COUNT=64 +# CONFIG_DEVKMEM is not set # CONFIG_HW_RANDOM is not set CONFIG_NVRAM=y CONFIG_I2C=y @@ -109,7 +99,6 @@ CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set -CONFIG_INOTIFY=y CONFIG_FUSE_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y @@ -119,7 +108,6 @@ CONFIG_PROC_KCORE=y # CONFIG_PROC_PAGE_MONITOR is not set CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_CIFS=m CONFIG_NLS_CODEPAGE_437=y @@ -127,13 +115,9 @@ CONFIG_NLS_ISO8859_1=y CONFIG_CRC_CCITT=y CONFIG_PRINTK_TIME=y CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_LATENCYTOP=y -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_SCHED_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_DMA_API_DEBUG=y diff --git a/arch/powerpc/crypto/sha1.c b/arch/powerpc/crypto/sha1.c index d3feba5a275f..c154cebc1041 100644 --- a/arch/powerpc/crypto/sha1.c +++ b/arch/powerpc/crypto/sha1.c @@ -154,4 +154,5 @@ module_exit(sha1_powerpc_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); +MODULE_ALIAS_CRYPTO("sha1"); MODULE_ALIAS_CRYPTO("sha1-powerpc"); diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index 5b9312220e84..30b35fff2dea 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -60,13 +60,6 @@ extern void flush_dcache_phys_range(unsigned long start, unsigned long stop); #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ memcpy(dst, src, len) - - -#ifdef CONFIG_DEBUG_PAGEALLOC -/* internal debugging function */ -void kernel_map_pages(struct page *page, int numpages, int enable); -#endif - #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_CACHEFLUSH_H */ diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 22d5a7da9e68..5cf5a6d10685 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -165,7 +165,7 @@ extern const char *powerpc_base_platform; #define CPU_FTR_ARCH_201 LONG_ASM_CONST(0x0000000200000000) #define CPU_FTR_ARCH_206 LONG_ASM_CONST(0x0000000400000000) #define CPU_FTR_ARCH_207S LONG_ASM_CONST(0x0000000800000000) -#define CPU_FTR_IABR LONG_ASM_CONST(0x0000001000000000) +/* Free LONG_ASM_CONST(0x0000001000000000) */ #define CPU_FTR_MMCRA LONG_ASM_CONST(0x0000002000000000) #define CPU_FTR_CTRL LONG_ASM_CONST(0x0000004000000000) #define CPU_FTR_SMT LONG_ASM_CONST(0x0000008000000000) diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 0652ebe117af..55abfd09e47f 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -38,8 +38,9 @@ struct device_node; #define EEH_FORCE_DISABLED 0x02 /* EEH disabled */ #define EEH_PROBE_MODE_DEV 0x04 /* From PCI device */ #define EEH_PROBE_MODE_DEVTREE 0x08 /* From device tree */ -#define EEH_ENABLE_IO_FOR_LOG 0x10 /* Enable IO for log */ -#define EEH_EARLY_DUMP_LOG 0x20 /* Dump log immediately */ +#define EEH_VALID_PE_ZERO 0x10 /* PE#0 is valid */ +#define EEH_ENABLE_IO_FOR_LOG 0x20 /* Enable IO for log */ +#define EEH_EARLY_DUMP_LOG 0x40 /* Dump log immediately */ /* * Delay for PE reset, all in ms @@ -77,6 +78,7 @@ struct device_node; #define EEH_PE_KEEP (1 << 8) /* Keep PE on hotplug */ #define EEH_PE_CFG_RESTRICTED (1 << 9) /* Block config on error */ +#define EEH_PE_REMOVED (1 << 10) /* Removed permanently */ struct eeh_pe { int type; /* PE type: PHB/Bus/Device */ @@ -216,6 +218,7 @@ struct eeh_ops { }; extern int eeh_subsystem_flags; +extern int eeh_max_freezes; extern struct eeh_ops *eeh_ops; extern raw_spinlock_t confirm_error_lock; @@ -253,12 +256,6 @@ static inline void eeh_serialize_unlock(unsigned long flags) raw_spin_unlock_irqrestore(&confirm_error_lock, flags); } -/* - * Max number of EEH freezes allowed before we consider the device - * to be permanently disabled. - */ -#define EEH_MAX_ALLOWED_FREEZES 5 - typedef void *(*eeh_traverse_func)(void *data, void *flag); void eeh_set_pe_aux_size(int size); int eeh_phb_pe_create(struct pci_controller *phb); diff --git a/arch/powerpc/include/asm/fsl_pamu_stash.h b/arch/powerpc/include/asm/fsl_pamu_stash.h index caa1b21c25cd..38311c98eed9 100644 --- a/arch/powerpc/include/asm/fsl_pamu_stash.h +++ b/arch/powerpc/include/asm/fsl_pamu_stash.h @@ -32,8 +32,8 @@ enum pamu_stash_target { */ struct pamu_stash_attribute { - u32 cpu; /* cpu number */ - u32 cache; /* cache to stash to: L1,L2,L3 */ + u32 cpu; /* cpu number */ + u32 cache; /* cache to stash to: L1,L2,L3 */ }; #endif /* __FSL_PAMU_STASH_H */ diff --git a/arch/powerpc/include/asm/kprobes.h b/arch/powerpc/include/asm/kprobes.h index af15d4d8d604..039b583db029 100644 --- a/arch/powerpc/include/asm/kprobes.h +++ b/arch/powerpc/include/asm/kprobes.h @@ -41,34 +41,59 @@ typedef ppc_opcode_t kprobe_opcode_t; #define MAX_INSN_SIZE 1 #ifdef CONFIG_PPC64 -/* - * 64bit powerpc uses function descriptors. - * Handle cases where: - * - User passes a <.symbol> or - * - User passes a or - * - User passes a non-existent symbol, kallsyms_lookup_name - * returns 0. Don't deref the NULL pointer in that case - */ +#if defined(_CALL_ELF) && _CALL_ELF == 2 +/* PPC64 ABIv2 needs local entry point */ #define kprobe_lookup_name(name, addr) \ { \ addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); \ - if (addr) { \ - char *colon; \ - if ((colon = strchr(name, ':')) != NULL) { \ - colon++; \ - if (*colon != '\0' && *colon != '.') \ - addr = (kprobe_opcode_t *)ppc_function_entry(addr); \ - } else if (name[0] != '.') \ - addr = (kprobe_opcode_t *)ppc_function_entry(addr); \ - } else { \ - char dot_name[KSYM_NAME_LEN]; \ + if (addr) \ + addr = (kprobe_opcode_t *)ppc_function_entry(addr); \ +} +#else +/* + * 64bit powerpc ABIv1 uses function descriptors: + * - Check for the dot variant of the symbol first. + * - If that fails, try looking up the symbol provided. + * + * This ensures we always get to the actual symbol and not the descriptor. + * Also handle format. + */ +#define kprobe_lookup_name(name, addr) \ +{ \ + char dot_name[MODULE_NAME_LEN + 1 + KSYM_NAME_LEN]; \ + char *modsym; \ + bool dot_appended = false; \ + if ((modsym = strchr(name, ':')) != NULL) { \ + modsym++; \ + if (*modsym != '\0' && *modsym != '.') { \ + /* Convert to */ \ + strncpy(dot_name, name, modsym - name); \ + dot_name[modsym - name] = '.'; \ + dot_name[modsym - name + 1] = '\0'; \ + strncat(dot_name, modsym, \ + sizeof(dot_name) - (modsym - name) - 2);\ + dot_appended = true; \ + } else { \ + dot_name[0] = '\0'; \ + strncat(dot_name, name, sizeof(dot_name) - 1); \ + } \ + } else if (name[0] != '.') { \ dot_name[0] = '.'; \ dot_name[1] = '\0'; \ strncat(dot_name, name, KSYM_NAME_LEN - 2); \ - addr = (kprobe_opcode_t *)kallsyms_lookup_name(dot_name); \ + dot_appended = true; \ + } else { \ + dot_name[0] = '\0'; \ + strncat(dot_name, name, KSYM_NAME_LEN - 1); \ + } \ + addr = (kprobe_opcode_t *)kallsyms_lookup_name(dot_name); \ + if (!addr && dot_appended) { \ + /* Let's try the original non-dot symbol lookup */ \ + addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); \ } \ } -#endif +#endif /* defined(_CALL_ELF) && _CALL_ELF == 2 */ +#endif /* CONFIG_PPC64 */ #define flush_insn_slot(p) do { } while (0) #define kretprobe_blacklist_size 0 diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index eb95b675109b..9ee0a30a02ce 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -304,7 +304,7 @@ enum OpalMessageType { */ OPAL_MSG_MEM_ERR, OPAL_MSG_EPOW, - OPAL_MSG_SHUTDOWN, + OPAL_MSG_SHUTDOWN, /* params[0] = 1 reboot, 0 shutdown */ OPAL_MSG_HMI_EVT, OPAL_MSG_TYPE_MAX, }; @@ -595,6 +595,14 @@ enum { OPAL_PHB3_NUM_PEST_REGS = 256 }; +/* CAPI modes for PHB */ +enum { + OPAL_PHB_CAPI_MODE_PCIE = 0, + OPAL_PHB_CAPI_MODE_CAPI = 1, + OPAL_PHB_CAPI_MODE_SNOOP_OFF = 2, + OPAL_PHB_CAPI_MODE_SNOOP_ON = 3, +}; + struct OpalIoPhbErrorCommon { __be32 version; __be32 ioType; diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index 725247beebec..546d036fe925 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h @@ -119,6 +119,10 @@ extern void setup_indirect_pci(struct pci_controller* hose, extern int indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val); +extern int __indirect_read_config(struct pci_controller *hose, + unsigned char bus_number, unsigned int devfn, + int offset, int len, u32 *val); + extern int indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val); diff --git a/arch/powerpc/include/asm/pgtable-ppc32.h b/arch/powerpc/include/asm/pgtable-ppc32.h index 234e07c47803..14bdcbd31670 100644 --- a/arch/powerpc/include/asm/pgtable-ppc32.h +++ b/arch/powerpc/include/asm/pgtable-ppc32.h @@ -45,7 +45,7 @@ extern int icache_44x_need_flush; #define PTRS_PER_PGD (1 << (32 - PGDIR_SHIFT)) #define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define pte_ERROR(e) \ pr_err("%s:%d: bad pte %llx.\n", __FILE__, __LINE__, \ @@ -178,12 +178,11 @@ static inline unsigned long pte_update(pte_t *p, andc %1,%0,%5\n\ or %1,%1,%6\n\ /* 0x200 == Extended encoding, bit 22 */ \ - /* Bit 22 has to be 1 if neither _PAGE_USER nor _PAGE_RW are set */ \ - rlwimi %1,%1,32-2,0x200\n /* get _PAGE_USER */ \ - rlwinm %3,%1,32-1,0x200\n /* get _PAGE_RW */ \ - or %1,%3,%1\n\ - xori %1,%1,0x200\n" -" stwcx. %1,0,%4\n\ + /* Bit 22 has to be 1 when _PAGE_USER is unset and _PAGE_RO is set */ \ + rlwimi %1,%1,32-1,0x200\n /* get _PAGE_RO */ \ + rlwinm %3,%1,32-2,0x200\n /* get _PAGE_USER */ \ + andc %1,%1,%3\n\ + stwcx. %1,0,%4\n\ bne- 1b" : "=&r" (old), "=&r" (tmp), "=m" (*p), "=&r" (tmp2) : "r" (p), "r" (clr), "r" (set), "m" (*p) @@ -275,7 +274,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), 0); + pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), _PAGE_RO); } static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) @@ -286,9 +285,11 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry) { - unsigned long bits = pte_val(entry) & + unsigned long set = pte_val(entry) & (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC); - pte_update(ptep, 0, bits); + unsigned long clr = ~pte_val(entry) & _PAGE_RO; + + pte_update(ptep, clr, set); } #define __HAVE_ARCH_PTE_SAME @@ -346,10 +347,14 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry) #define pte_to_pgoff(pte) (pte_val(pte) >> 3) #define pgoff_to_pte(off) ((pte_t) { ((off) << 3) | _PAGE_FILE }) +#ifndef CONFIG_PPC_4K_PAGES +void pgtable_cache_init(void); +#else /* * No page table caches to initialise */ #define pgtable_cache_init() do { } while (0) +#endif extern int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp); diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h index b9dcc936e2d1..d46532ccc386 100644 --- a/arch/powerpc/include/asm/pgtable-ppc64.h +++ b/arch/powerpc/include/asm/pgtable-ppc64.h @@ -12,7 +12,7 @@ #endif #include -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL /* * Size of EA range mapped by our pagetables. diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index a8805fee0df9..7e77f2ca5132 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h @@ -30,7 +30,8 @@ struct mm_struct; #include /* Generic accessors to PTE bits */ -static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; } +static inline int pte_write(pte_t pte) +{ return (pte_val(pte) & (_PAGE_RW | _PAGE_RO)) != _PAGE_RO; } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } @@ -115,12 +116,14 @@ static inline unsigned long pte_pfn(pte_t pte) { /* Generic modifiers for PTE bits */ static inline pte_t pte_wrprotect(pte_t pte) { - pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; } + pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); + pte_val(pte) |= _PAGE_RO; return pte; } static inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; } static inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; } static inline pte_t pte_mkwrite(pte_t pte) { + pte_val(pte) &= ~_PAGE_RO; pte_val(pte) |= _PAGE_RW; return pte; } static inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; } diff --git a/arch/powerpc/include/asm/pnv-pci.h b/arch/powerpc/include/asm/pnv-pci.h index f09a22fa1bd7..f9b498292a5c 100644 --- a/arch/powerpc/include/asm/pnv-pci.h +++ b/arch/powerpc/include/asm/pnv-pci.h @@ -13,13 +13,13 @@ #include #include -int pnv_phb_to_cxl(struct pci_dev *dev); +int pnv_phb_to_cxl_mode(struct pci_dev *dev, uint64_t mode); int pnv_cxl_ioda_msi_setup(struct pci_dev *dev, unsigned int hwirq, unsigned int virq); int pnv_cxl_alloc_hwirqs(struct pci_dev *dev, int num); void pnv_cxl_release_hwirqs(struct pci_dev *dev, int hwirq, int num); int pnv_cxl_get_irq_count(struct pci_dev *dev); -struct device_node *pnv_pci_to_phb_node(struct pci_dev *dev); +struct device_node *pnv_pci_get_phb_node(struct pci_dev *dev); #ifdef CONFIG_CXL_BASE int pnv_cxl_alloc_hwirq_ranges(struct cxl_irq_ranges *irqs, diff --git a/arch/powerpc/include/asm/pte-8xx.h b/arch/powerpc/include/asm/pte-8xx.h index daa4616e61c4..eb6edb44f140 100644 --- a/arch/powerpc/include/asm/pte-8xx.h +++ b/arch/powerpc/include/asm/pte-8xx.h @@ -46,9 +46,9 @@ * require a TLB exception handler change. It is assumed unused bits * are always zero. */ -#define _PAGE_RW 0x0400 /* lsb PP bits, inverted in HW */ +#define _PAGE_RO 0x0400 /* lsb PP bits */ #define _PAGE_USER 0x0800 /* msb PP bits */ -/* set when neither _PAGE_USER nor _PAGE_RW are set */ +/* set when _PAGE_USER is unset and _PAGE_RO is set */ #define _PAGE_KNLRO 0x0200 #define _PMD_PRESENT 0x0001 @@ -62,9 +62,8 @@ #define PTE_ATOMIC_UPDATES 1 /* We need to add _PAGE_SHARED to kernel pages */ -#define _PAGE_KERNEL_RO (_PAGE_SHARED | _PAGE_KNLRO) -#define _PAGE_KERNEL_ROX (_PAGE_EXEC | _PAGE_KNLRO) -#define _PAGE_KERNEL_RW (_PAGE_DIRTY | _PAGE_RW | _PAGE_HWWRITE) +#define _PAGE_KERNEL_RO (_PAGE_SHARED | _PAGE_RO | _PAGE_KNLRO) +#define _PAGE_KERNEL_ROX (_PAGE_EXEC | _PAGE_RO | _PAGE_KNLRO) #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_PTE_8xx_H */ diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h index e040c3595129..2aef9b7a0eb2 100644 --- a/arch/powerpc/include/asm/pte-common.h +++ b/arch/powerpc/include/asm/pte-common.h @@ -34,6 +34,12 @@ #ifndef _PAGE_PSIZE #define _PAGE_PSIZE 0 #endif +/* _PAGE_RO and _PAGE_RW shall not be defined at the same time */ +#ifndef _PAGE_RO +#define _PAGE_RO 0 +#else +#define _PAGE_RW 0 +#endif #ifndef _PMD_PRESENT_MASK #define _PMD_PRESENT_MASK _PMD_PRESENT #endif @@ -42,10 +48,10 @@ #define PMD_PAGE_SIZE(pmd) bad_call_to_PMD_PAGE_SIZE() #endif #ifndef _PAGE_KERNEL_RO -#define _PAGE_KERNEL_RO 0 +#define _PAGE_KERNEL_RO (_PAGE_RO) #endif #ifndef _PAGE_KERNEL_ROX -#define _PAGE_KERNEL_ROX (_PAGE_EXEC) +#define _PAGE_KERNEL_ROX (_PAGE_EXEC | _PAGE_RO) #endif #ifndef _PAGE_KERNEL_RW #define _PAGE_KERNEL_RW (_PAGE_DIRTY | _PAGE_RW | _PAGE_HWWRITE) @@ -95,7 +101,7 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void); /* Mask of bits returned by pte_pgprot() */ #define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \ _PAGE_WRITETHRU | _PAGE_ENDIAN | _PAGE_4K_PFN | \ - _PAGE_USER | _PAGE_ACCESSED | \ + _PAGE_USER | _PAGE_ACCESSED | _PAGE_RO | \ _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | _PAGE_EXEC) #ifdef CONFIG_NUMA_BALANCING @@ -128,11 +134,14 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void); */ #define PAGE_NONE __pgprot(_PAGE_BASE) #define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW) -#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC) -#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER) -#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) -#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER) -#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC) +#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | \ + _PAGE_EXEC) +#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO) +#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO | \ + _PAGE_EXEC) +#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO) +#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RO | \ + _PAGE_EXEC) #define __P000 PAGE_NONE #define __P001 PAGE_READONLY diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index b390f55b0df1..2e23e92a4372 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -327,7 +327,7 @@ extern int rtas_suspend_cpu(struct rtas_suspend_me_data *data); extern int rtas_suspend_last_cpu(struct rtas_suspend_me_data *data); extern int rtas_online_cpus_mask(cpumask_var_t cpus); extern int rtas_offline_cpus_mask(cpumask_var_t cpus); -extern int rtas_ibm_suspend_me(struct rtas_args *); +extern int rtas_ibm_suspend_me(u64 handle, int *vasi_return); struct rtc_time; extern unsigned long rtas_get_boot_time(void); diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 5a6614a7f0b2..d607df5081a7 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -64,7 +64,6 @@ DECLARE_PER_CPU(unsigned int, cpu_pvr); extern void migrate_irqs(void); int generic_cpu_disable(void); void generic_cpu_die(unsigned int cpu); -void generic_mach_cpu_die(void); void generic_set_cpu_dead(unsigned int cpu); void generic_set_cpu_up(unsigned int cpu); int generic_check_cpu_restart(unsigned int cpu); diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 0be6c681cab1..e8abc83e699f 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -125,7 +125,7 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SYSCALL_TRACEPOINT (1<freeze_count++; - if (pe->freeze_count > EEH_MAX_ALLOWED_FREEZES) + if (pe->freeze_count > eeh_max_freezes) goto excess_failures; pr_warn("EEH: This PCI device has failed %d times in the last hour\n", pe->freeze_count); @@ -806,7 +806,7 @@ perm_error: eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); /* Mark the PE to be removed permanently */ - pe->freeze_count = EEH_MAX_ALLOWED_FREEZES + 1; + eeh_pe_state_mark(pe, EEH_PE_REMOVED); /* * Shut down the device drivers for good. We mark diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index 5a63e2b0f65b..1e4946c36f9e 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c @@ -239,10 +239,18 @@ static void *__eeh_pe_get(void *data, void *flag) if (pe->type & EEH_PE_PHB) return NULL; - /* We prefer PE address */ - if (edev->pe_config_addr && - (edev->pe_config_addr == pe->addr)) + /* + * We prefer PE address. For most cases, we should + * have non-zero PE address + */ + if (eeh_has_flag(EEH_VALID_PE_ZERO)) { + if (edev->pe_config_addr == pe->addr) + return pe; + } else { + if (edev->pe_config_addr && + (edev->pe_config_addr == pe->addr)) return pe; + } /* Try BDF address */ if (edev->config_addr && @@ -518,8 +526,7 @@ static void *__eeh_pe_state_mark(void *data, void *flag) struct pci_dev *pdev; /* Keep the state of permanently removed PE intact */ - if ((pe->freeze_count > EEH_MAX_ALLOWED_FREEZES) && - (state & (EEH_PE_ISOLATED | EEH_PE_RECOVERING))) + if (pe->state & EEH_PE_REMOVED) return NULL; pe->state |= state; @@ -592,8 +599,7 @@ static void *__eeh_pe_state_clear(void *data, void *flag) struct pci_dev *pdev; /* Keep the state of permanently removed PE intact */ - if ((pe->freeze_count > EEH_MAX_ALLOWED_FREEZES) && - (state & EEH_PE_ISOLATED)) + if (pe->state & EEH_PE_REMOVED) return NULL; pe->state &= ~state; diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 10a093579191..46fc0f4d8982 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -33,9 +33,6 @@ #include #include -#undef SHOW_SYSCALLS -#undef SHOW_SYSCALLS_TASK - /* * MSR_KERNEL is > 0x10000 on 4xx/Book-E since it include MSR_CE. */ @@ -307,9 +304,6 @@ _GLOBAL(DoSyscall) lwz r11,_CCR(r1) /* Clear SO bit in CR */ rlwinm r11,r11,0,4,2 stw r11,_CCR(r1) -#ifdef SHOW_SYSCALLS - bl do_show_syscall -#endif /* SHOW_SYSCALLS */ #ifdef CONFIG_TRACE_IRQFLAGS /* Return from syscalls can (and generally will) hard enable * interrupts. You aren't supposed to call a syscall with @@ -337,7 +331,7 @@ _GLOBAL(DoSyscall) #endif /* CONFIG_TRACE_IRQFLAGS */ CURRENT_THREAD_INFO(r10, r1) lwz r11,TI_FLAGS(r10) - andi. r11,r11,_TIF_SYSCALL_T_OR_A + andi. r11,r11,_TIF_SYSCALL_DOTRACE bne- syscall_dotrace syscall_dotrace_cont: cmplwi 0,r0,NR_syscalls @@ -352,9 +346,6 @@ syscall_dotrace_cont: blrl /* Call handler */ .globl ret_from_syscall ret_from_syscall: -#ifdef SHOW_SYSCALLS - bl do_show_syscall_exit -#endif mr r6,r3 CURRENT_THREAD_INFO(r12, r1) /* disable interrupts so current_thread_info()->flags can't change */ @@ -364,7 +355,7 @@ ret_from_syscall: MTMSRD(r10) lwz r9,TI_FLAGS(r12) li r8,-_LAST_ERRNO - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK) + andi. r0,r9,(_TIF_SYSCALL_DOTRACE|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK) bne- syscall_exit_work cmplw 0,r3,r8 blt+ syscall_exit_cont @@ -501,7 +492,7 @@ syscall_exit_work: subi r12,r12,TI_FLAGS 4: /* Anything which requires enabling interrupts? */ - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) + andi. r0,r9,(_TIF_SYSCALL_DOTRACE|_TIF_SINGLESTEP) beq ret_from_except /* Re-enable interrupts. There is no need to trace that with @@ -523,74 +514,6 @@ syscall_exit_work: bl do_syscall_trace_leave b ret_from_except_full -#ifdef SHOW_SYSCALLS -do_show_syscall: -#ifdef SHOW_SYSCALLS_TASK - lis r11,show_syscalls_task@ha - lwz r11,show_syscalls_task@l(r11) - cmp 0,r2,r11 - bnelr -#endif - stw r31,GPR31(r1) - mflr r31 - lis r3,7f@ha - addi r3,r3,7f@l - lwz r4,GPR0(r1) - lwz r5,GPR3(r1) - lwz r6,GPR4(r1) - lwz r7,GPR5(r1) - lwz r8,GPR6(r1) - lwz r9,GPR7(r1) - bl printk - lis r3,77f@ha - addi r3,r3,77f@l - lwz r4,GPR8(r1) - mr r5,r2 - bl printk - lwz r0,GPR0(r1) - lwz r3,GPR3(r1) - lwz r4,GPR4(r1) - lwz r5,GPR5(r1) - lwz r6,GPR6(r1) - lwz r7,GPR7(r1) - lwz r8,GPR8(r1) - mtlr r31 - lwz r31,GPR31(r1) - blr - -do_show_syscall_exit: -#ifdef SHOW_SYSCALLS_TASK - lis r11,show_syscalls_task@ha - lwz r11,show_syscalls_task@l(r11) - cmp 0,r2,r11 - bnelr -#endif - stw r31,GPR31(r1) - mflr r31 - stw r3,RESULT(r1) /* Save result */ - mr r4,r3 - lis r3,79f@ha - addi r3,r3,79f@l - bl printk - lwz r3,RESULT(r1) - mtlr r31 - lwz r31,GPR31(r1) - blr - -7: .string "syscall %d(%x, %x, %x, %x, %x, " -77: .string "%x), current=%p\n" -79: .string " -> %x\n" - .align 2,0 - -#ifdef SHOW_SYSCALLS_TASK - .data - .globl show_syscalls_task -show_syscalls_task: - .long -1 - .text -#endif -#endif /* SHOW_SYSCALLS */ - /* * The fork/clone functions need to copy the full register set into * the child process. Therefore we need to save all the nonvolatile diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 194e46dcf08d..d180caf2d6de 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -49,8 +49,6 @@ exception_marker: .section ".text" .align 7 -#undef SHOW_SYSCALLS - .globl system_call_common system_call_common: andi. r10,r12,MSR_PR @@ -142,16 +140,9 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) li r10,1 std r10,SOFTE(r1) -#ifdef SHOW_SYSCALLS - bl do_show_syscall - REST_GPR(0,r1) - REST_4GPRS(3,r1) - REST_2GPRS(7,r1) - addi r9,r1,STACK_FRAME_OVERHEAD -#endif CURRENT_THREAD_INFO(r11, r1) ld r10,TI_FLAGS(r11) - andi. r11,r10,_TIF_SYSCALL_T_OR_A + andi. r11,r10,_TIF_SYSCALL_DOTRACE bne syscall_dotrace .Lsyscall_dotrace_cont: cmpldi 0,r0,NR_syscalls @@ -178,12 +169,8 @@ system_call: /* label this so stack traces look sane */ mtctr r12 bctrl /* Call handler */ -syscall_exit: +.Lsyscall_exit: std r3,RESULT(r1) -#ifdef SHOW_SYSCALLS - bl do_show_syscall_exit - ld r3,RESULT(r1) -#endif CURRENT_THREAD_INFO(r12, r1) ld r8,_MSR(r1) @@ -214,7 +201,7 @@ syscall_exit: ld r9,TI_FLAGS(r12) li r11,-_LAST_ERRNO - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK) + andi. r0,r9,(_TIF_SYSCALL_DOTRACE|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK) bne- syscall_exit_work cmpld r3,r11 ld r5,_CCR(r1) @@ -270,7 +257,7 @@ syscall_dotrace: syscall_enosys: li r3,-ENOSYS - b syscall_exit + b .Lsyscall_exit syscall_exit_work: #ifdef CONFIG_PPC_BOOK3S @@ -307,7 +294,7 @@ syscall_exit_work: 4: /* Anything else left to do? */ SET_DEFAULT_THREAD_PPR(r3, r10) /* Set thread.ppr = 3 */ - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) + andi. r0,r9,(_TIF_SYSCALL_DOTRACE|_TIF_SINGLESTEP) beq ret_from_except_lite /* Re-enable interrupts */ @@ -347,33 +334,33 @@ _GLOBAL(save_nvgprs) _GLOBAL(ppc_fork) bl save_nvgprs bl sys_fork - b syscall_exit + b .Lsyscall_exit _GLOBAL(ppc_vfork) bl save_nvgprs bl sys_vfork - b syscall_exit + b .Lsyscall_exit _GLOBAL(ppc_clone) bl save_nvgprs bl sys_clone - b syscall_exit + b .Lsyscall_exit _GLOBAL(ppc32_swapcontext) bl save_nvgprs bl compat_sys_swapcontext - b syscall_exit + b .Lsyscall_exit _GLOBAL(ppc64_swapcontext) bl save_nvgprs bl sys_swapcontext - b syscall_exit + b .Lsyscall_exit _GLOBAL(ret_from_fork) bl schedule_tail REST_NVGPRS(r1) li r3,0 - b syscall_exit + b .Lsyscall_exit _GLOBAL(ret_from_kernel_thread) bl schedule_tail @@ -385,7 +372,7 @@ _GLOBAL(ret_from_kernel_thread) #endif blrl li r3,0 - b syscall_exit + b .Lsyscall_exit /* * This routine switches between two different tasks. The process diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index d99aac0d69f1..9b53fe139bf6 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -319,36 +319,29 @@ InstructionTLBMiss: * pin the first 8MB of kernel memory */ andis. r11, r10, 0x8000 /* Address >= 0x80000000 */ #endif - mfspr r11, SPRN_M_TW /* Get level 1 table base address */ + mfspr r11, SPRN_M_TW /* Get level 1 table */ #ifdef CONFIG_MODULES beq 3f - lis r11, (swapper_pg_dir-PAGE_OFFSET)@h - ori r11, r11, (swapper_pg_dir-PAGE_OFFSET)@l + lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha 3: #endif - /* Extract level 1 index */ - rlwinm r10, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29 - lwzx r11, r10, r11 /* Get the level 1 entry */ - rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */ - beq 2f /* If zero, don't try to find a pte */ + /* Insert level 1 index */ + rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29 + lwz r11, (swapper_pg_dir-PAGE_OFFSET)@l(r11) /* Get the level 1 entry */ - /* We have a pte table, so load the MI_TWC with the attributes - * for this "segment." - */ + /* Load the MI_TWC with the attributes for this "segment." */ MTSPR_CPU6(SPRN_MI_TWC, r11, r3) /* Set segment attributes */ - mfspr r11, SPRN_SRR0 /* Get effective address of fault */ + rlwinm r11, r11,0,0,19 /* Extract page descriptor page address */ /* Extract level 2 index */ - rlwinm r11, r11, 32 - (PAGE_SHIFT - 2), 32 - PAGE_SHIFT, 29 + rlwinm r10, r10, 32 - (PAGE_SHIFT - 2), 32 - PAGE_SHIFT, 29 lwzx r10, r10, r11 /* Get the pte */ #ifdef CONFIG_SWAP - andi. r11, r10, _PAGE_ACCESSED | _PAGE_PRESENT - cmpwi cr0, r11, _PAGE_ACCESSED | _PAGE_PRESENT - li r11, RPN_PATTERN - bne- cr0, 2f -#else - li r11, RPN_PATTERN + rlwinm r11, r10, 32-5, _PAGE_PRESENT + and r11, r11, r10 + rlwimi r10, r11, 0, _PAGE_PRESENT #endif + li r11, RPN_PATTERN /* The Linux PTE won't go exactly into the MMU TLB. * Software indicator bits 21 and 28 must be clear. * Software indicator bits 24, 25, 26, and 27 must be @@ -366,21 +359,6 @@ InstructionTLBMiss: mfspr r10, SPRN_SPRG_SCRATCH2 EXCEPTION_EPILOG_0 rfi -2: - mfspr r10, SPRN_SRR1 - /* clear all error bits as TLB Miss - * sets a few unconditionally - */ - rlwinm r10, r10, 0, 0xffff - mtspr SPRN_SRR1, r10 - - /* Restore registers */ -#ifdef CONFIG_8xx_CPU6 - mfspr r3, SPRN_DAR - mtspr SPRN_DAR, r11 /* Tag DAR */ -#endif - mfspr r10, SPRN_SPRG_SCRATCH2 - b InstructionTLBError1 . = 0x1200 DataStoreTLBMiss: @@ -395,20 +373,16 @@ DataStoreTLBMiss: * kernel page tables. */ andis. r11, r10, 0x8000 - mfspr r11, SPRN_M_TW /* Get level 1 table base address */ + mfspr r11, SPRN_M_TW /* Get level 1 table */ beq 3f - lis r11, (swapper_pg_dir-PAGE_OFFSET)@h - ori r11, r11, (swapper_pg_dir-PAGE_OFFSET)@l + lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha 3: - /* Extract level 1 index */ - rlwinm r10, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29 - lwzx r11, r10, r11 /* Get the level 1 entry */ - rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */ - beq 2f /* If zero, don't try to find a pte */ + /* Insert level 1 index */ + rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29 + lwz r11, (swapper_pg_dir-PAGE_OFFSET)@l(r11) /* Get the level 1 entry */ /* We have a pte table, so load fetch the pte from the table. */ - mfspr r10, SPRN_MD_EPN /* Get address of fault */ /* Extract level 2 index */ rlwinm r10, r10, 32 - (PAGE_SHIFT - 2), 32 - PAGE_SHIFT, 29 rlwimi r10, r11, 0, 0, 32 - PAGE_SHIFT - 1 /* Add level 2 base */ @@ -441,16 +415,13 @@ DataStoreTLBMiss: and r11, r11, r10 rlwimi r10, r11, 0, _PAGE_PRESENT #endif - /* invert RW */ - xori r10, r10, _PAGE_RW - /* The Linux PTE won't go exactly into the MMU TLB. * Software indicator bits 22 and 28 must be clear. * Software indicator bits 24, 25, 26, and 27 must be * set. All other Linux PTE bits control the behavior * of the MMU. */ -2: li r11, RPN_PATTERN + li r11, RPN_PATTERN rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ MTSPR_CPU6(SPRN_MD_RPN, r10, r3) /* Update TLB entry */ @@ -469,10 +440,7 @@ DataStoreTLBMiss: */ . = 0x1300 InstructionTLBError: - EXCEPTION_PROLOG_0 -InstructionTLBError1: - EXCEPTION_PROLOG_1 - EXCEPTION_PROLOG_2 + EXCEPTION_PROLOG mr r4,r12 mr r5,r9 andis. r10,r5,0x4000 @@ -532,30 +500,21 @@ DARFixed:/* Return from dcbx instruction bug workaround */ /* define if you don't want to use self modifying code */ #define NO_SELF_MODIFYING_CODE FixupDAR:/* Entry point for dcbx workaround. */ -#ifdef CONFIG_8xx_CPU6 - mtspr SPRN_DAR, r3 -#endif mtspr SPRN_SPRG_SCRATCH2, r10 /* fetch instruction from memory. */ mfspr r10, SPRN_SRR0 andis. r11, r10, 0x8000 /* Address >= 0x80000000 */ - mfspr r11, SPRN_M_TW /* Get level 1 table base address */ - beq- 3f /* Branch if user space */ - lis r11, (swapper_pg_dir-PAGE_OFFSET)@h - ori r11, r11, (swapper_pg_dir-PAGE_OFFSET)@l - /* Extract level 1 index */ -3: rlwinm r10, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29 - lwzx r11, r10, r11 /* Get the level 1 entry */ - rlwinm r10, r11,0,0,19 /* Extract page descriptor page address */ - mfspr r11, SPRN_SRR0 /* Get effective address of fault */ - /* Extract level 2 index */ - rlwinm r11, r11, 32 - (PAGE_SHIFT - 2), 32 - PAGE_SHIFT, 29 - lwzx r11, r10, r11 /* Get the pte */ -#ifdef CONFIG_8xx_CPU6 - mfspr r3, SPRN_DAR -#endif + mfspr r11, SPRN_M_TW /* Get level 1 table */ + beq 3f + lis r11, (swapper_pg_dir-PAGE_OFFSET)@ha + /* Insert level 1 index */ +3: rlwimi r11, r10, 32 - ((PAGE_SHIFT - 2) << 1), (PAGE_SHIFT - 2) << 1, 29 + lwz r11, (swapper_pg_dir-PAGE_OFFSET)@l(r11) /* Get the level 1 entry */ + rlwinm r11, r11,0,0,19 /* Extract page descriptor page address */ + /* Insert level 2 index */ + rlwimi r11, r10, 32 - (PAGE_SHIFT - 2), 32 - PAGE_SHIFT, 29 + lwz r11, 0(r11) /* Get the pte */ /* concat physical page address(r11) and page offset(r10) */ - mfspr r10, SPRN_SRR0 rlwimi r11, r10, 0, 32 - PAGE_SHIFT, 31 lwz r11,0(r11) /* Check if it really is a dcbx instruction. */ @@ -705,8 +664,7 @@ start_here: * init's THREAD like the context switch code does, but this is * easier......until someone changes init's static structures. */ - lis r6, swapper_pg_dir@h - ori r6, r6, swapper_pg_dir@l + lis r6, swapper_pg_dir@ha tophys(r6,r6) #ifdef CONFIG_8xx_CPU6 lis r4, cpu6_errata_word@h @@ -885,23 +843,28 @@ _GLOBAL(set_context) stw r4, 0x4(r5) #endif + /* Register M_TW will contain base address of level 1 table minus the + * lower part of the kernel PGDIR base address, so that all accesses to + * level 1 table are done relative to lower part of kernel PGDIR base + * address. + */ + li r5, (swapper_pg_dir-PAGE_OFFSET)@l + sub r4, r4, r5 + tophys (r4, r4) #ifdef CONFIG_8xx_CPU6 lis r6, cpu6_errata_word@h ori r6, r6, cpu6_errata_word@l - tophys (r4, r4) li r7, 0x3f80 stw r7, 12(r6) lwz r7, 12(r6) - mtspr SPRN_M_TW, r4 /* Update MMU base address */ +#endif + mtspr SPRN_M_TW, r4 /* Update pointeur to level 1 table */ +#ifdef CONFIG_8xx_CPU6 li r7, 0x3380 stw r7, 12(r6) lwz r7, 12(r6) - mtspr SPRN_M_CASID, r3 /* Update context */ -#else - mtspr SPRN_M_CASID,r3 /* Update context */ - tophys (r4, r4) - mtspr SPRN_M_TW, r4 /* and pgd */ #endif + mtspr SPRN_M_CASID, r3 /* Update context */ SYNC blr diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index d6e195e8cd4c..5a23b69f8129 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -115,6 +115,14 @@ static struct slb_shadow * __init init_slb_shadow(int cpu) { struct slb_shadow *s = &slb_shadow[cpu]; + /* + * When we come through here to initialise boot_paca, the slb_shadow + * buffers are not allocated yet. That's OK, we'll get one later in + * boot, but make sure we don't corrupt memory at 0. + */ + if (!slb_shadow) + return NULL; + s->persistent = cpu_to_be32(SLB_NUM_BOLTED); s->buffer_length = cpu_to_be32(sizeof(*s)); diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 37d512d35943..2a525c938158 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1184,6 +1184,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) pr, (pr && pr->name) ? pr->name : "nil"); if (pr && !(pr->flags & IORESOURCE_UNSET)) { + struct pci_dev *dev = bus->self; + if (request_resource(pr, res) == 0) continue; /* @@ -1193,6 +1195,11 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus) */ if (reparent_resources(pr, res) == 0) continue; + + if (dev && i < PCI_BRIDGE_RESOURCE_NUM && + pci_claim_bridge_resource(dev, + i + PCI_BRIDGE_RESOURCES) == 0) + continue; } pr_warning("PCI: Cannot allocate resource region " "%d of PCI bridge %d, will remap\n", i, bus->number); @@ -1401,7 +1408,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus) (unsigned long long)r->end, (unsigned int)r->flags); - pci_claim_resource(dev, i); + if (pci_claim_resource(dev, i) == 0) + continue; + + pci_claim_bridge_resource(dev, i); } } diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c index 1f61fab59d9b..83df3075d3df 100644 --- a/arch/powerpc/kernel/pci_dn.c +++ b/arch/powerpc/kernel/pci_dn.c @@ -147,10 +147,8 @@ void pci_devs_phb_init_dynamic(struct pci_controller *phb) /* PHB nodes themselves must not match */ update_dn_pci_info(dn, phb); pdn = dn->data; - if (pdn) { + if (pdn) pdn->devfn = pdn->busno = -1; - pdn->phb = phb; - } /* Update dn->phb ptrs for new phb and children devices */ traverse_pci_devices(dn, update_dn_pci_info, phb); diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 6a799b3cc6b4..b8e15c678960 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -652,9 +652,6 @@ void __init early_init_devtree(void *params) if (!early_init_dt_verify(params)) panic("BUG: Failed verifying flat device tree, bad version?"); - /* Setup flat device-tree pointer */ - initial_boot_params = params; - #ifdef CONFIG_PPC_RTAS /* Some machines might need RTAS info for debugging, grab it now. */ of_scan_flat_dt(early_init_dt_scan_rtas, NULL); diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 4af905e81ab0..21c45a2d0706 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -897,7 +897,7 @@ int rtas_offline_cpus_mask(cpumask_var_t cpus) } EXPORT_SYMBOL(rtas_offline_cpus_mask); -int rtas_ibm_suspend_me(struct rtas_args *args) +int rtas_ibm_suspend_me(u64 handle, int *vasi_return) { long state; long rc; @@ -911,8 +911,7 @@ int rtas_ibm_suspend_me(struct rtas_args *args) return -ENOSYS; /* Make sure the state is valid */ - rc = plpar_hcall(H_VASI_STATE, retbuf, - ((u64)args->args[0] << 32) | args->args[1]); + rc = plpar_hcall(H_VASI_STATE, retbuf, handle); state = retbuf[0]; @@ -920,12 +919,12 @@ int rtas_ibm_suspend_me(struct rtas_args *args) printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned %ld\n",rc); return rc; } else if (state == H_VASI_ENABLED) { - args->args[args->nargs] = RTAS_NOT_SUSPENDABLE; + *vasi_return = RTAS_NOT_SUSPENDABLE; return 0; } else if (state != H_VASI_SUSPENDING) { printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned state %ld\n", state); - args->args[args->nargs] = -1; + *vasi_return = -1; return 0; } @@ -973,7 +972,7 @@ out: return atomic_read(&data.error); } #else /* CONFIG_PPC_PSERIES */ -int rtas_ibm_suspend_me(struct rtas_args *args) +int rtas_ibm_suspend_me(u64 handle, int *vasi_return) { return -ENOSYS; } @@ -1053,7 +1052,16 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) /* Need to handle ibm,suspend_me call specially */ if (token == ibm_suspend_me_token) { - rc = rtas_ibm_suspend_me(&args); + + /* + * rtas_ibm_suspend_me assumes args are in cpu endian, or at least the + * hcall within it requires it. + */ + int vasi_rc = 0; + u64 handle = ((u64)be32_to_cpu(args.args[0]) << 32) + | be32_to_cpu(args.args[1]); + rc = rtas_ibm_suspend_me(handle, &vasi_rc); + args.rets[0] = cpu_to_be32(vasi_rc); if (rc) return rc; goto copy_return; diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 8b2d2dc8ef10..6e19afa35a15 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -434,20 +434,6 @@ void generic_cpu_die(unsigned int cpu) printk(KERN_ERR "CPU%d didn't die...\n", cpu); } -void generic_mach_cpu_die(void) -{ - unsigned int cpu; - - local_irq_disable(); - idle_task_exit(); - cpu = smp_processor_id(); - printk(KERN_DEBUG "CPU%d offline\n", cpu); - __this_cpu_write(cpu_state, CPU_DEAD); - smp_wmb(); - while (__this_cpu_read(cpu_state) != CPU_UP_PREPARE) - cpu_relax(); -} - void generic_set_cpu_dead(unsigned int cpu) { per_cpu(cpu_state, cpu) = CPU_DEAD; diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index cd9be9aa016d..b2702e87db0d 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -121,17 +121,3 @@ long ppc_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low, return sys_fadvise64(fd, (u64)offset_high << 32 | offset_low, (u64)len_high << 32 | len_low, advice); } - -void do_show_syscall(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, unsigned long r8, - struct pt_regs *regs) -{ - printk("syscall %ld(%lx, %lx, %lx, %lx, %lx, %lx) regs=%p current=%p" - " cpu=%d\n", regs->gpr[0], r3, r4, r5, r6, r7, r8, regs, - current, smp_processor_id()); -} - -void do_show_syscall_exit(unsigned long r3) -{ - printk(" -> %lx, current=%p cpu=%d\n", r3, current, smp_processor_id()); -} diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index e6595b72269b..19e4744b6eba 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -1707,21 +1707,6 @@ void altivec_assist_exception(struct pt_regs *regs) } #endif /* CONFIG_ALTIVEC */ -#ifdef CONFIG_VSX -void vsx_assist_exception(struct pt_regs *regs) -{ - if (!user_mode(regs)) { - printk(KERN_EMERG "VSX assist exception in kernel mode" - " at %lx\n", regs->nip); - die("Kernel VSX assist exception", regs, SIGILL); - } - - flush_vsx_to_thread(current); - printk(KERN_INFO "VSX assist not supported at %lx\n", regs->nip); - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); -} -#endif /* CONFIG_VSX */ - #ifdef CONFIG_FSL_BOOKE void CacheLockingException(struct pt_regs *regs, unsigned long address, unsigned long error_code) diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index f5769f19ae25..11850f310fb4 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig @@ -21,6 +21,7 @@ config KVM select PREEMPT_NOTIFIERS select ANON_INODES select HAVE_KVM_EVENTFD + select SRCU config KVM_BOOK3S_HANDLER bool diff --git a/arch/powerpc/kvm/book3s_hv_interrupts.S b/arch/powerpc/kvm/book3s_hv_interrupts.S index 36540a99d178..0fdc4a28970b 100644 --- a/arch/powerpc/kvm/book3s_hv_interrupts.S +++ b/arch/powerpc/kvm/book3s_hv_interrupts.S @@ -93,15 +93,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) mfspr r5, SPRN_MMCR1 mfspr r9, SPRN_SIAR mfspr r10, SPRN_SDAR - std r7, HSTATE_MMCR(r13) - std r5, HSTATE_MMCR + 8(r13) - std r6, HSTATE_MMCR + 16(r13) - std r9, HSTATE_MMCR + 24(r13) - std r10, HSTATE_MMCR + 32(r13) + std r7, HSTATE_MMCR0(r13) + std r5, HSTATE_MMCR1(r13) + std r6, HSTATE_MMCRA(r13) + std r9, HSTATE_SIAR(r13) + std r10, HSTATE_SDAR(r13) BEGIN_FTR_SECTION mfspr r9, SPRN_SIER - std r8, HSTATE_MMCR + 40(r13) - std r9, HSTATE_MMCR + 48(r13) + std r8, HSTATE_MMCR2(r13) + std r9, HSTATE_SIER(r13) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) mfspr r3, SPRN_PMC1 mfspr r5, SPRN_PMC2 @@ -109,12 +109,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) mfspr r7, SPRN_PMC4 mfspr r8, SPRN_PMC5 mfspr r9, SPRN_PMC6 - stw r3, HSTATE_PMC(r13) - stw r5, HSTATE_PMC + 4(r13) - stw r6, HSTATE_PMC + 8(r13) - stw r7, HSTATE_PMC + 12(r13) - stw r8, HSTATE_PMC + 16(r13) - stw r9, HSTATE_PMC + 20(r13) + stw r3, HSTATE_PMC1(r13) + stw r5, HSTATE_PMC2(r13) + stw r6, HSTATE_PMC3(r13) + stw r7, HSTATE_PMC4(r13) + stw r8, HSTATE_PMC5(r13) + stw r9, HSTATE_PMC6(r13) 31: /* diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 10554df13852..bb94e6f20c81 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -83,35 +83,35 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) cmpwi r4, 0 beq 23f /* skip if not */ BEGIN_FTR_SECTION - ld r3, HSTATE_MMCR(r13) + ld r3, HSTATE_MMCR0(r13) andi. r4, r3, MMCR0_PMAO_SYNC | MMCR0_PMAO cmpwi r4, MMCR0_PMAO beql kvmppc_fix_pmao END_FTR_SECTION_IFSET(CPU_FTR_PMAO_BUG) - lwz r3, HSTATE_PMC(r13) - lwz r4, HSTATE_PMC + 4(r13) - lwz r5, HSTATE_PMC + 8(r13) - lwz r6, HSTATE_PMC + 12(r13) - lwz r8, HSTATE_PMC + 16(r13) - lwz r9, HSTATE_PMC + 20(r13) + lwz r3, HSTATE_PMC1(r13) + lwz r4, HSTATE_PMC2(r13) + lwz r5, HSTATE_PMC3(r13) + lwz r6, HSTATE_PMC4(r13) + lwz r8, HSTATE_PMC5(r13) + lwz r9, HSTATE_PMC6(r13) mtspr SPRN_PMC1, r3 mtspr SPRN_PMC2, r4 mtspr SPRN_PMC3, r5 mtspr SPRN_PMC4, r6 mtspr SPRN_PMC5, r8 mtspr SPRN_PMC6, r9 - ld r3, HSTATE_MMCR(r13) - ld r4, HSTATE_MMCR + 8(r13) - ld r5, HSTATE_MMCR + 16(r13) - ld r6, HSTATE_MMCR + 24(r13) - ld r7, HSTATE_MMCR + 32(r13) + ld r3, HSTATE_MMCR0(r13) + ld r4, HSTATE_MMCR1(r13) + ld r5, HSTATE_MMCRA(r13) + ld r6, HSTATE_SIAR(r13) + ld r7, HSTATE_SDAR(r13) mtspr SPRN_MMCR1, r4 mtspr SPRN_MMCRA, r5 mtspr SPRN_SIAR, r6 mtspr SPRN_SDAR, r7 BEGIN_FTR_SECTION - ld r8, HSTATE_MMCR + 40(r13) - ld r9, HSTATE_MMCR + 48(r13) + ld r8, HSTATE_MMCR2(r13) + ld r9, HSTATE_SIER(r13) mtspr SPRN_MMCR2, r8 mtspr SPRN_SIER, r9 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 597562f69b2d..7902802a19a5 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -9,33 +9,30 @@ ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC) CFLAGS_REMOVE_code-patching.o = -pg CFLAGS_REMOVE_feature-fixups.o = -pg -obj-y := string.o alloc.o \ - crtsavres.o ppc_ksyms.o +obj-y += string.o alloc.o crtsavres.o ppc_ksyms.o code-patching.o \ + feature-fixups.o + obj-$(CONFIG_PPC32) += div64.o copy_32.o -obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \ - usercopy_64.o mem_64.o string.o \ - hweight_64.o \ - copyuser_power7.o string_64.o copypage_power7.o +obj64-y += copypage_64.o copyuser_64.o usercopy_64.o mem_64.o hweight_64.o \ + copyuser_power7.o string_64.o copypage_power7.o memcpy_power7.o \ + memcpy_64.o memcmp_64.o + +obj64-$(CONFIG_SMP) += locks.o +obj64-$(CONFIG_ALTIVEC) += vmx-helper.o + ifeq ($(CONFIG_GENERIC_CSUM),) obj-y += checksum_$(CONFIG_WORD_SIZE).o obj-$(CONFIG_PPC64) += checksum_wrappers_64.o endif -obj-$(CONFIG_PPC64) += memcpy_power7.o memcpy_64.o - obj-$(CONFIG_PPC_EMULATE_SSTEP) += sstep.o ldstfp.o -ifeq ($(CONFIG_PPC64),y) -obj-$(CONFIG_SMP) += locks.o -obj-$(CONFIG_ALTIVEC) += vmx-helper.o -endif - obj-$(CONFIG_PPC_LIB_RHEAP) += rheap.o -obj-y += code-patching.o -obj-y += feature-fixups.o obj-$(CONFIG_FTR_FIXUP_SELFTEST) += feature-fixups-test.o obj-$(CONFIG_ALTIVEC) += xor_vmx.o CFLAGS_xor_vmx.o += -maltivec -mabi=altivec + +obj-$(CONFIG_PPC64) += $(obj64-y) diff --git a/arch/powerpc/lib/memcmp_64.S b/arch/powerpc/lib/memcmp_64.S new file mode 100644 index 000000000000..8953d2382a65 --- /dev/null +++ b/arch/powerpc/lib/memcmp_64.S @@ -0,0 +1,233 @@ +/* + * Author: Anton Blanchard + * Copyright 2015 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 + +#define off8 r6 +#define off16 r7 +#define off24 r8 + +#define rA r9 +#define rB r10 +#define rC r11 +#define rD r27 +#define rE r28 +#define rF r29 +#define rG r30 +#define rH r31 + +#ifdef __LITTLE_ENDIAN__ +#define LD ldbrx +#else +#define LD ldx +#endif + +_GLOBAL(memcmp) + cmpdi cr1,r5,0 + + /* Use the short loop if both strings are not 8B aligned */ + or r6,r3,r4 + andi. r6,r6,7 + + /* Use the short loop if length is less than 32B */ + cmpdi cr6,r5,31 + + beq cr1,.Lzero + bne .Lshort + bgt cr6,.Llong + +.Lshort: + mtctr r5 + +1: lbz rA,0(r3) + lbz rB,0(r4) + subf. rC,rB,rA + bne .Lnon_zero + bdz .Lzero + + lbz rA,1(r3) + lbz rB,1(r4) + subf. rC,rB,rA + bne .Lnon_zero + bdz .Lzero + + lbz rA,2(r3) + lbz rB,2(r4) + subf. rC,rB,rA + bne .Lnon_zero + bdz .Lzero + + lbz rA,3(r3) + lbz rB,3(r4) + subf. rC,rB,rA + bne .Lnon_zero + + addi r3,r3,4 + addi r4,r4,4 + + bdnz 1b + +.Lzero: + li r3,0 + blr + +.Lnon_zero: + mr r3,rC + blr + +.Llong: + li off8,8 + li off16,16 + li off24,24 + + std r31,-8(r1) + std r30,-16(r1) + std r29,-24(r1) + std r28,-32(r1) + std r27,-40(r1) + + srdi r0,r5,5 + mtctr r0 + andi. r5,r5,31 + + LD rA,0,r3 + LD rB,0,r4 + + LD rC,off8,r3 + LD rD,off8,r4 + + LD rE,off16,r3 + LD rF,off16,r4 + + LD rG,off24,r3 + LD rH,off24,r4 + cmpld cr0,rA,rB + + addi r3,r3,32 + addi r4,r4,32 + + bdz .Lfirst32 + + LD rA,0,r3 + LD rB,0,r4 + cmpld cr1,rC,rD + + LD rC,off8,r3 + LD rD,off8,r4 + cmpld cr6,rE,rF + + LD rE,off16,r3 + LD rF,off16,r4 + cmpld cr7,rG,rH + bne cr0,.LcmpAB + + LD rG,off24,r3 + LD rH,off24,r4 + cmpld cr0,rA,rB + bne cr1,.LcmpCD + + addi r3,r3,32 + addi r4,r4,32 + + bdz .Lsecond32 + + .balign 16 + +1: LD rA,0,r3 + LD rB,0,r4 + cmpld cr1,rC,rD + bne cr6,.LcmpEF + + LD rC,off8,r3 + LD rD,off8,r4 + cmpld cr6,rE,rF + bne cr7,.LcmpGH + + LD rE,off16,r3 + LD rF,off16,r4 + cmpld cr7,rG,rH + bne cr0,.LcmpAB + + LD rG,off24,r3 + LD rH,off24,r4 + cmpld cr0,rA,rB + bne cr1,.LcmpCD + + addi r3,r3,32 + addi r4,r4,32 + + bdnz 1b + +.Lsecond32: + cmpld cr1,rC,rD + bne cr6,.LcmpEF + + cmpld cr6,rE,rF + bne cr7,.LcmpGH + + cmpld cr7,rG,rH + bne cr0,.LcmpAB + + bne cr1,.LcmpCD + bne cr6,.LcmpEF + bne cr7,.LcmpGH + +.Ltail: + ld r31,-8(r1) + ld r30,-16(r1) + ld r29,-24(r1) + ld r28,-32(r1) + ld r27,-40(r1) + + cmpdi r5,0 + beq .Lzero + b .Lshort + +.Lfirst32: + cmpld cr1,rC,rD + cmpld cr6,rE,rF + cmpld cr7,rG,rH + + bne cr0,.LcmpAB + bne cr1,.LcmpCD + bne cr6,.LcmpEF + bne cr7,.LcmpGH + + b .Ltail + +.LcmpAB: + li r3,1 + bgt cr0,.Lout + li r3,-1 + b .Lout + +.LcmpCD: + li r3,1 + bgt cr1,.Lout + li r3,-1 + b .Lout + +.LcmpEF: + li r3,1 + bgt cr6,.Lout + li r3,-1 + b .Lout + +.LcmpGH: + li r3,1 + bgt cr7,.Lout + li r3,-1 + +.Lout: + ld r31,-8(r1) + ld r30,-16(r1) + ld r29,-24(r1) + ld r28,-32(r1) + ld r27,-40(r1) + blr diff --git a/arch/powerpc/lib/string.S b/arch/powerpc/lib/string.S index 1b5a0a09d609..c80fb49ce607 100644 --- a/arch/powerpc/lib/string.S +++ b/arch/powerpc/lib/string.S @@ -93,6 +93,7 @@ _GLOBAL(strlen) subf r3,r3,r4 blr +#ifdef CONFIG_PPC32 _GLOBAL(memcmp) PPC_LCMPI 0,r5,0 beq- 2f @@ -106,6 +107,7 @@ _GLOBAL(memcmp) blr 2: li r3,0 blr +#endif _GLOBAL(memchr) PPC_LCMPI 0,r5,0 diff --git a/arch/powerpc/mm/copro_fault.c b/arch/powerpc/mm/copro_fault.c index 5a236f082c78..1b5305d4bdab 100644 --- a/arch/powerpc/mm/copro_fault.c +++ b/arch/powerpc/mm/copro_fault.c @@ -76,7 +76,7 @@ int copro_handle_mm_fault(struct mm_struct *mm, unsigned long ea, if (*flt & VM_FAULT_OOM) { ret = -ENOMEM; goto out_unlock; - } else if (*flt & VM_FAULT_SIGBUS) { + } else if (*flt & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV)) { ret = -EFAULT; goto out_unlock; } diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index eb79907f34fa..6154b0a2b063 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -437,6 +437,8 @@ good_area: */ fault = handle_mm_fault(mm, vma, address, flags); if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) { + if (fault & VM_FAULT_SIGSEGV) + goto bad_area; rc = mm_fault_error(regs, address, fault); if (rc >= MM_FAULT_RETURN) goto bail; diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c index 94cd728166d3..b46912fee7cd 100644 --- a/arch/powerpc/mm/fsl_booke_mmu.c +++ b/arch/powerpc/mm/fsl_booke_mmu.c @@ -67,8 +67,6 @@ struct tlbcamrange { phys_addr_t phys; } tlbcam_addrs[NUM_TLBCAMS]; -extern unsigned int tlbcam_index; - unsigned long tlbcam_sz(int idx) { return tlbcam_addrs[idx].limit - tlbcam_addrs[idx].start + 1; diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 5ff4e07d920a..cf0464f4284f 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -714,6 +714,14 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address, return NULL; } +struct page * +follow_huge_pud(struct mm_struct *mm, unsigned long address, + pud_t *pud, int write) +{ + BUG(); + return NULL; +} + static unsigned long hugepte_addr_end(unsigned long addr, unsigned long end, unsigned long sz) { diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c index 9cba6cba2e50..986afbc22c76 100644 --- a/arch/powerpc/mm/mmu_context_nohash.c +++ b/arch/powerpc/mm/mmu_context_nohash.c @@ -52,12 +52,15 @@ #include #include +#include "mmu_decl.h" + static unsigned int first_context, last_context; static unsigned int next_context, nr_free_contexts; static unsigned long *context_map; static unsigned long *stale_map[NR_CPUS]; static struct mm_struct **context_mm; static DEFINE_RAW_SPINLOCK(context_lock); +static bool no_selective_tlbil; #define CTX_MAP_SIZE \ (sizeof(unsigned long) * (last_context / BITS_PER_LONG + 1)) @@ -133,6 +136,38 @@ static unsigned int steal_context_smp(unsigned int id) } #endif /* CONFIG_SMP */ +static unsigned int steal_all_contexts(void) +{ + struct mm_struct *mm; + int cpu = smp_processor_id(); + unsigned int id; + + for (id = first_context; id <= last_context; id++) { + /* Pick up the victim mm */ + mm = context_mm[id]; + + pr_hardcont(" | steal %d from 0x%p", id, mm); + + /* Mark this mm as having no context anymore */ + mm->context.id = MMU_NO_CONTEXT; + if (id != first_context) { + context_mm[id] = NULL; + __clear_bit(id, context_map); +#ifdef DEBUG_MAP_CONSISTENCY + mm->context.active = 0; +#endif + } + __clear_bit(id, stale_map[cpu]); + } + + /* Flush the TLB for all contexts (not to be used on SMP) */ + _tlbil_all(); + + nr_free_contexts = last_context - first_context; + + return first_context; +} + /* Note that this will also be called on SMP if all other CPUs are * offlined, which means that it may be called for cpu != 0. For * this to work, we somewhat assume that CPUs that are onlined @@ -241,7 +276,10 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next) goto stolen; } #endif /* CONFIG_SMP */ - id = steal_context_up(id); + if (no_selective_tlbil) + id = steal_all_contexts(); + else + id = steal_context_up(id); goto stolen; } nr_free_contexts--; @@ -407,12 +445,15 @@ void __init mmu_context_init(void) if (mmu_has_feature(MMU_FTR_TYPE_8xx)) { first_context = 0; last_context = 15; + no_selective_tlbil = true; } else if (mmu_has_feature(MMU_FTR_TYPE_47x)) { first_context = 1; last_context = 65535; + no_selective_tlbil = false; } else { first_context = 1; last_context = 255; + no_selective_tlbil = false; } #ifdef DEBUG_CLAMP_LAST_CONTEXT diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 50fad3801f30..03b1a3b0fbd5 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -63,7 +63,6 @@ void setbat(int index, unsigned long virt, phys_addr_t phys, #endif /* HAVE_BATS */ #ifdef HAVE_TLBCAM -extern unsigned int tlbcam_index; extern phys_addr_t v_mapped_by_tlbcam(unsigned long va); extern unsigned long p_mapped_by_tlbcam(phys_addr_t pa); #else /* !HAVE_TLBCAM */ @@ -73,13 +72,25 @@ extern unsigned long p_mapped_by_tlbcam(phys_addr_t pa); #define PGDIR_ORDER (32 + PGD_T_LOG2 - PGDIR_SHIFT) +#ifndef CONFIG_PPC_4K_PAGES +static struct kmem_cache *pgtable_cache; + +void pgtable_cache_init(void) +{ + pgtable_cache = kmem_cache_create("PGDIR cache", 1 << PGDIR_ORDER, + 1 << PGDIR_ORDER, 0, NULL); + if (pgtable_cache == NULL) + panic("Couldn't allocate pgtable caches"); +} +#endif + pgd_t *pgd_alloc(struct mm_struct *mm) { pgd_t *ret; /* pgdir take page or two with 4K pages and a page fraction otherwise */ #ifndef CONFIG_PPC_4K_PAGES - ret = kzalloc(1 << PGDIR_ORDER, GFP_KERNEL); + ret = kmem_cache_alloc(pgtable_cache, GFP_KERNEL | __GFP_ZERO); #else ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGDIR_ORDER - PAGE_SHIFT); @@ -90,7 +101,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm) void pgd_free(struct mm_struct *mm, pgd_t *pgd) { #ifndef CONFIG_PPC_4K_PAGES - kfree((void *)pgd); + kmem_cache_free(pgtable_cache, (void *)pgd); #else free_pages((unsigned long)pgd, PGDIR_ORDER - PAGE_SHIFT); #endif @@ -147,7 +158,7 @@ void __iomem * ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags) { /* writeable implies dirty for kernel addresses */ - if (flags & _PAGE_RW) + if ((flags & (_PAGE_RW | _PAGE_RO)) != _PAGE_RO) flags |= _PAGE_DIRTY | _PAGE_HWWRITE; /* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */ diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index ded0ea1afde4..0f432a702870 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -645,35 +645,6 @@ void slice_set_user_psize(struct mm_struct *mm, unsigned int psize) spin_unlock_irqrestore(&slice_convert_lock, flags); } -void slice_set_psize(struct mm_struct *mm, unsigned long address, - unsigned int psize) -{ - unsigned char *hpsizes; - unsigned long i, flags; - u64 *lpsizes; - - spin_lock_irqsave(&slice_convert_lock, flags); - if (address < SLICE_LOW_TOP) { - i = GET_LOW_SLICE_INDEX(address); - lpsizes = &mm->context.low_slices_psize; - *lpsizes = (*lpsizes & ~(0xful << (i * 4))) | - ((unsigned long) psize << (i * 4)); - } else { - int index, mask_index; - i = GET_HIGH_SLICE_INDEX(address); - hpsizes = mm->context.high_slices_psize; - mask_index = i & 0x1; - index = i >> 1; - hpsizes[index] = (hpsizes[index] & - ~(0xf << (mask_index * 4))) | - (((unsigned long)psize) << (mask_index * 4)); - } - - spin_unlock_irqrestore(&slice_convert_lock, flags); - - copro_flush_all_slbs(mm); -} - void slice_set_range_psize(struct mm_struct *mm, unsigned long start, unsigned long len, unsigned int psize) { diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c index 6c0b1f5f8d2c..fa9fb5b4c66c 100644 --- a/arch/powerpc/mm/subpage-prot.c +++ b/arch/powerpc/mm/subpage-prot.c @@ -134,7 +134,7 @@ static void subpage_prot_clear(unsigned long addr, unsigned long len) static int subpage_walk_pmd_entry(pmd_t *pmd, unsigned long addr, unsigned long end, struct mm_walk *walk) { - struct vm_area_struct *vma = walk->private; + struct vm_area_struct *vma = walk->vma; split_huge_page_pmd(vma, addr, pmd); return 0; } @@ -163,9 +163,7 @@ static void subpage_mark_vma_nohuge(struct mm_struct *mm, unsigned long addr, if (vma->vm_start >= (addr + len)) break; vma->vm_flags |= VM_NOHUGEPAGE; - subpage_proto_walk.private = vma; - walk_page_range(vma->vm_start, vma->vm_end, - &subpage_proto_walk); + walk_page_vma(vma, &subpage_proto_walk); vma = vma->vm_next; } } diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index f38ea4df6a85..cbd3d069897f 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c @@ -284,8 +284,15 @@ void __flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr, struct cpumask *cpu_mask; unsigned int pid; + /* + * This function as well as __local_flush_tlb_page() must only be called + * for user contexts. + */ + if (unlikely(WARN_ON(!mm))) + return; + preempt_disable(); - pid = mm ? mm->context.id : 0; + pid = mm->context.id; if (unlikely(pid == MMU_NO_CONTEXT)) goto bail; cpu_mask = mm_cpumask(mm); diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c index 1ca125b9c226..d1916b577f2c 100644 --- a/arch/powerpc/net/bpf_jit_comp.c +++ b/arch/powerpc/net/bpf_jit_comp.c @@ -699,7 +699,7 @@ out: void bpf_jit_free(struct bpf_prog *fp) { if (fp->jited) - module_free(NULL, fp->bpf_func); + module_memfree(fp->bpf_func); bpf_prog_unlock_free(fp); } diff --git a/arch/powerpc/perf/core-fsl-emb.c b/arch/powerpc/perf/core-fsl-emb.c index 4acaea01fe03..5d747b4cb8ee 100644 --- a/arch/powerpc/perf/core-fsl-emb.c +++ b/arch/powerpc/perf/core-fsl-emb.c @@ -330,9 +330,11 @@ static int fsl_emb_pmu_add(struct perf_event *event, int flags) } local64_set(&event->hw.prev_count, val); - if (!(flags & PERF_EF_START)) { + if (unlikely(!(flags & PERF_EF_START))) { event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE; val = 0; + } else { + event->hw.state &= ~(PERF_HES_STOPPED | PERF_HES_UPTODATE); } write_pmc(i, val); @@ -389,6 +391,7 @@ static void fsl_emb_pmu_del(struct perf_event *event, int flags) static void fsl_emb_pmu_start(struct perf_event *event, int ef_flags) { unsigned long flags; + unsigned long val; s64 left; if (event->hw.idx < 0 || !event->hw.sample_period) @@ -405,7 +408,10 @@ static void fsl_emb_pmu_start(struct perf_event *event, int ef_flags) event->hw.state = 0; left = local64_read(&event->hw.period_left); - write_pmc(event->hw.idx, left); + val = 0; + if (left < 0x80000000L) + val = 0x80000000L - left; + write_pmc(event->hw.idx, val); perf_event_update_userpage(event); perf_pmu_enable(event->pmu); diff --git a/arch/powerpc/perf/hv-24x7-catalog.h b/arch/powerpc/perf/hv-24x7-catalog.h index 21b19dd86d9c..69e2e1faf902 100644 --- a/arch/powerpc/perf/hv-24x7-catalog.h +++ b/arch/powerpc/perf/hv-24x7-catalog.h @@ -30,4 +30,29 @@ struct hv_24x7_catalog_page_0 { __u8 reserved6[2]; } __packed; +struct hv_24x7_event_data { + __be16 length; /* in bytes, must be a multiple of 16 */ + __u8 reserved1[2]; + __u8 domain; /* Chip = 1, Core = 2 */ + __u8 reserved2[1]; + __be16 event_group_record_offs; /* in bytes, must be 8 byte aligned */ + __be16 event_group_record_len; /* in bytes */ + + /* in bytes, offset from event_group_record */ + __be16 event_counter_offs; + + /* verified_state, unverified_state, caveat_state, broken_state, ... */ + __be32 flags; + + __be16 primary_group_ix; + __be16 group_count; + __be16 event_name_len; + __u8 remainder[]; + /* __u8 event_name[event_name_len - 2]; */ + /* __be16 event_description_len; */ + /* __u8 event_desc[event_description_len - 2]; */ + /* __be16 detailed_desc_len; */ + /* __u8 detailed_desc[detailed_desc_len - 2]; */ +} __packed; + #endif diff --git a/arch/powerpc/perf/hv-24x7-domains.h b/arch/powerpc/perf/hv-24x7-domains.h new file mode 100644 index 000000000000..49c1efd50045 --- /dev/null +++ b/arch/powerpc/perf/hv-24x7-domains.h @@ -0,0 +1,28 @@ + +/* + * DOMAIN(name, num, index_kind, is_physical) + * + * @name: An all caps token, suitable for use in generating an enum + * member and appending to an event name in sysfs. + * + * @num: The number corresponding to the domain as given in + * documentation. We assume the catalog domain and the hcall + * domain have the same numbering (so far they do), but this + * may need to be changed in the future. + * + * @index_kind: A stringifiable token describing the meaning of the index + * within the given domain. Must fit the parsing rules of the + * perf sysfs api. + * + * @is_physical: True if the domain is physical, false otherwise (if virtual). + * + * Note: The terms PHYS_CHIP, PHYS_CORE, VCPU correspond to physical chip, + * physical core and virtual processor in 24x7 Counters specifications. + */ + +DOMAIN(PHYS_CHIP, 0x01, chip, true) +DOMAIN(PHYS_CORE, 0x02, core, true) +DOMAIN(VCPU_HOME_CORE, 0x03, vcpu, false) +DOMAIN(VCPU_HOME_CHIP, 0x04, vcpu, false) +DOMAIN(VCPU_HOME_NODE, 0x05, vcpu, false) +DOMAIN(VCPU_REMOTE_NODE, 0x06, vcpu, false) diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c index f162d0b8eea3..9445a824819e 100644 --- a/arch/powerpc/perf/hv-24x7.c +++ b/arch/powerpc/perf/hv-24x7.c @@ -13,16 +13,66 @@ #define pr_fmt(fmt) "hv-24x7: " fmt #include +#include #include #include +#include + #include #include #include +#include #include "hv-24x7.h" #include "hv-24x7-catalog.h" #include "hv-common.h" +static const char *event_domain_suffix(unsigned domain) +{ + switch (domain) { +#define DOMAIN(n, v, x, c) \ + case HV_PERF_DOMAIN_##n: \ + return "__" #n; +#include "hv-24x7-domains.h" +#undef DOMAIN + default: + WARN(1, "unknown domain %d\n", domain); + return "__UNKNOWN_DOMAIN_SUFFIX"; + } +} + +static bool domain_is_valid(unsigned domain) +{ + switch (domain) { +#define DOMAIN(n, v, x, c) \ + case HV_PERF_DOMAIN_##n: \ + /* fall through */ +#include "hv-24x7-domains.h" +#undef DOMAIN + return true; + default: + return false; + } +} + +static bool is_physical_domain(unsigned domain) +{ + switch (domain) { +#define DOMAIN(n, v, x, c) \ + case HV_PERF_DOMAIN_##n: \ + return c; +#include "hv-24x7-domains.h" +#undef DOMAIN + default: + return false; + } +} + +static bool catalog_entry_domain_is_valid(unsigned domain) +{ + return is_physical_domain(domain); +} + /* * TODO: Merging events: * - Think of the hcall as an interface to a 4d array of counters: @@ -44,13 +94,14 @@ /* * Example usage: - * perf stat -e 'hv_24x7/domain=2,offset=8,starting_index=0,lpar=0xffffffff/' + * perf stat -e 'hv_24x7/domain=2,offset=8,vcpu=0,lpar=0xffffffff/' */ /* u3 0-6, one of HV_24X7_PERF_DOMAIN */ EVENT_DEFINE_RANGE_FORMAT(domain, config, 0, 3); /* u16 */ -EVENT_DEFINE_RANGE_FORMAT(starting_index, config, 16, 31); +EVENT_DEFINE_RANGE_FORMAT(core, config, 16, 31); +EVENT_DEFINE_RANGE_FORMAT(vcpu, config, 16, 31); /* u32, see "data_offset" */ EVENT_DEFINE_RANGE_FORMAT(offset, config, 32, 63); /* u16 */ @@ -63,7 +114,8 @@ EVENT_DEFINE_RANGE(reserved3, config2, 0, 63); static struct attribute *format_attrs[] = { &format_attr_domain.attr, &format_attr_offset.attr, - &format_attr_starting_index.attr, + &format_attr_core.attr, + &format_attr_vcpu.attr, &format_attr_lpar.attr, NULL, }; @@ -73,8 +125,115 @@ static struct attribute_group format_group = { .attrs = format_attrs, }; +static struct attribute_group event_group = { + .name = "events", + /* .attrs is set in init */ +}; + +static struct attribute_group event_desc_group = { + .name = "event_descs", + /* .attrs is set in init */ +}; + +static struct attribute_group event_long_desc_group = { + .name = "event_long_descs", + /* .attrs is set in init */ +}; + static struct kmem_cache *hv_page_cache; +static char *event_name(struct hv_24x7_event_data *ev, int *len) +{ + *len = be16_to_cpu(ev->event_name_len) - 2; + return (char *)ev->remainder; +} + +static char *event_desc(struct hv_24x7_event_data *ev, int *len) +{ + unsigned nl = be16_to_cpu(ev->event_name_len); + __be16 *desc_len = (__be16 *)(ev->remainder + nl - 2); + *len = be16_to_cpu(*desc_len) - 2; + return (char *)ev->remainder + nl; +} + +static char *event_long_desc(struct hv_24x7_event_data *ev, int *len) +{ + unsigned nl = be16_to_cpu(ev->event_name_len); + __be16 *desc_len_ = (__be16 *)(ev->remainder + nl - 2); + unsigned desc_len = be16_to_cpu(*desc_len_); + __be16 *long_desc_len = (__be16 *)(ev->remainder + nl + desc_len - 2); + *len = be16_to_cpu(*long_desc_len) - 2; + return (char *)ev->remainder + nl + desc_len; +} + +static bool event_fixed_portion_is_within(struct hv_24x7_event_data *ev, + void *end) +{ + void *start = ev; + + return (start + offsetof(struct hv_24x7_event_data, remainder)) < end; +} + +/* + * Things we don't check: + * - padding for desc, name, and long/detailed desc is required to be '\0' + * bytes. + * + * Return NULL if we pass end, + * Otherwise return the address of the byte just following the event. + */ +static void *event_end(struct hv_24x7_event_data *ev, void *end) +{ + void *start = ev; + __be16 *dl_, *ldl_; + unsigned dl, ldl; + unsigned nl = be16_to_cpu(ev->event_name_len); + + if (nl < 2) { + pr_debug("%s: name length too short: %d", __func__, nl); + return NULL; + } + + if (start + nl > end) { + pr_debug("%s: start=%p + nl=%u > end=%p", + __func__, start, nl, end); + return NULL; + } + + dl_ = (__be16 *)(ev->remainder + nl - 2); + if (!IS_ALIGNED((uintptr_t)dl_, 2)) + pr_warn("desc len not aligned %p", dl_); + dl = be16_to_cpu(*dl_); + if (dl < 2) { + pr_debug("%s: desc len too short: %d", __func__, dl); + return NULL; + } + + if (start + nl + dl > end) { + pr_debug("%s: (start=%p + nl=%u + dl=%u)=%p > end=%p", + __func__, start, nl, dl, start + nl + dl, end); + return NULL; + } + + ldl_ = (__be16 *)(ev->remainder + nl + dl - 2); + if (!IS_ALIGNED((uintptr_t)ldl_, 2)) + pr_warn("long desc len not aligned %p", ldl_); + ldl = be16_to_cpu(*ldl_); + if (ldl < 2) { + pr_debug("%s: long desc len too short (ldl=%u)", + __func__, ldl); + return NULL; + } + + if (start + nl + dl + ldl > end) { + pr_debug("%s: start=%p + nl=%u + dl=%u + ldl=%u > end=%p", + __func__, start, nl, dl, ldl, end); + return NULL; + } + + return start + nl + dl + ldl; +} + static unsigned long h_get_24x7_catalog_page_(unsigned long phys_4096, unsigned long version, unsigned long index) @@ -97,6 +256,609 @@ static unsigned long h_get_24x7_catalog_page(char page[], version, index); } +static unsigned core_domains[] = { + HV_PERF_DOMAIN_PHYS_CORE, + HV_PERF_DOMAIN_VCPU_HOME_CORE, + HV_PERF_DOMAIN_VCPU_HOME_CHIP, + HV_PERF_DOMAIN_VCPU_HOME_NODE, + HV_PERF_DOMAIN_VCPU_REMOTE_NODE, +}; +/* chip event data always yeilds a single event, core yeilds multiple */ +#define MAX_EVENTS_PER_EVENT_DATA ARRAY_SIZE(core_domains) + +static char *event_fmt(struct hv_24x7_event_data *event, unsigned domain) +{ + const char *sindex; + const char *lpar; + + if (is_physical_domain(domain)) { + lpar = "0x0"; + sindex = "core"; + } else { + lpar = "?"; + sindex = "vcpu"; + } + + return kasprintf(GFP_KERNEL, + "domain=0x%x,offset=0x%x,%s=?,lpar=%s", + domain, + be16_to_cpu(event->event_counter_offs) + + be16_to_cpu(event->event_group_record_offs), + sindex, + lpar); +} + +/* Avoid trusting fw to NUL terminate strings */ +static char *memdup_to_str(char *maybe_str, int max_len, gfp_t gfp) +{ + return kasprintf(gfp, "%.*s", max_len, maybe_str); +} + +static ssize_t device_show_string(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dev_ext_attribute *d; + + d = container_of(attr, struct dev_ext_attribute, attr); + return sprintf(buf, "%s\n", (char *)d->var); +} + +static struct attribute *device_str_attr_create_(char *name, char *str) +{ + struct dev_ext_attribute *attr = kzalloc(sizeof(*attr), GFP_KERNEL); + + if (!attr) + return NULL; + + attr->var = str; + attr->attr.attr.name = name; + attr->attr.attr.mode = 0444; + attr->attr.show = device_show_string; + return &attr->attr.attr; +} + +static struct attribute *device_str_attr_create(char *name, int name_max, + int name_nonce, + char *str, size_t str_max) +{ + char *n; + char *s = memdup_to_str(str, str_max, GFP_KERNEL); + struct attribute *a; + + if (!s) + return NULL; + + if (!name_nonce) + n = kasprintf(GFP_KERNEL, "%.*s", name_max, name); + else + n = kasprintf(GFP_KERNEL, "%.*s__%d", name_max, name, + name_nonce); + if (!n) + goto out_s; + + a = device_str_attr_create_(n, s); + if (!a) + goto out_n; + + return a; +out_n: + kfree(n); +out_s: + kfree(s); + return NULL; +} + +static void device_str_attr_destroy(struct attribute *attr) +{ + struct dev_ext_attribute *d; + + d = container_of(attr, struct dev_ext_attribute, attr.attr); + kfree(d->var); + kfree(d->attr.attr.name); + kfree(d); +} + +static struct attribute *event_to_attr(unsigned ix, + struct hv_24x7_event_data *event, + unsigned domain, + int nonce) +{ + int event_name_len; + char *ev_name, *a_ev_name, *val; + const char *ev_suffix; + struct attribute *attr; + + if (!domain_is_valid(domain)) { + pr_warn("catalog event %u has invalid domain %u\n", + ix, domain); + return NULL; + } + + val = event_fmt(event, domain); + if (!val) + return NULL; + + ev_suffix = event_domain_suffix(domain); + ev_name = event_name(event, &event_name_len); + if (!nonce) + a_ev_name = kasprintf(GFP_KERNEL, "%.*s%s", + (int)event_name_len, ev_name, ev_suffix); + else + a_ev_name = kasprintf(GFP_KERNEL, "%.*s%s__%d", + (int)event_name_len, ev_name, ev_suffix, nonce); + + + if (!a_ev_name) + goto out_val; + + attr = device_str_attr_create_(a_ev_name, val); + if (!attr) + goto out_name; + + return attr; +out_name: + kfree(a_ev_name); +out_val: + kfree(val); + return NULL; +} + +static struct attribute *event_to_desc_attr(struct hv_24x7_event_data *event, + int nonce) +{ + int nl, dl; + char *name = event_name(event, &nl); + char *desc = event_desc(event, &dl); + + /* If there isn't a description, don't create the sysfs file */ + if (!dl) + return NULL; + + return device_str_attr_create(name, nl, nonce, desc, dl); +} + +static struct attribute * +event_to_long_desc_attr(struct hv_24x7_event_data *event, int nonce) +{ + int nl, dl; + char *name = event_name(event, &nl); + char *desc = event_long_desc(event, &dl); + + /* If there isn't a description, don't create the sysfs file */ + if (!dl) + return NULL; + + return device_str_attr_create(name, nl, nonce, desc, dl); +} + +static ssize_t event_data_to_attrs(unsigned ix, struct attribute **attrs, + struct hv_24x7_event_data *event, int nonce) +{ + unsigned i; + + switch (event->domain) { + case HV_PERF_DOMAIN_PHYS_CHIP: + *attrs = event_to_attr(ix, event, event->domain, nonce); + return 1; + case HV_PERF_DOMAIN_PHYS_CORE: + for (i = 0; i < ARRAY_SIZE(core_domains); i++) { + attrs[i] = event_to_attr(ix, event, core_domains[i], + nonce); + if (!attrs[i]) { + pr_warn("catalog event %u: individual attr %u " + "creation failure\n", ix, i); + for (; i; i--) + device_str_attr_destroy(attrs[i - 1]); + return -1; + } + } + return i; + default: + pr_warn("catalog event %u: domain %u is not allowed in the " + "catalog\n", ix, event->domain); + return -1; + } +} + +static size_t event_to_attr_ct(struct hv_24x7_event_data *event) +{ + switch (event->domain) { + case HV_PERF_DOMAIN_PHYS_CHIP: + return 1; + case HV_PERF_DOMAIN_PHYS_CORE: + return ARRAY_SIZE(core_domains); + default: + return 0; + } +} + +static unsigned long vmalloc_to_phys(void *v) +{ + struct page *p = vmalloc_to_page(v); + + BUG_ON(!p); + return page_to_phys(p) + offset_in_page(v); +} + +/* */ +struct event_uniq { + struct rb_node node; + const char *name; + int nl; + unsigned ct; + unsigned domain; +}; + +static int memord(const void *d1, size_t s1, const void *d2, size_t s2) +{ + if (s1 < s2) + return 1; + if (s2 > s1) + return -1; + + return memcmp(d1, d2, s1); +} + +static int ev_uniq_ord(const void *v1, size_t s1, unsigned d1, const void *v2, + size_t s2, unsigned d2) +{ + int r = memord(v1, s1, v2, s2); + + if (r) + return r; + if (d1 > d2) + return 1; + if (d2 > d1) + return -1; + return 0; +} + +static int event_uniq_add(struct rb_root *root, const char *name, int nl, + unsigned domain) +{ + struct rb_node **new = &(root->rb_node), *parent = NULL; + struct event_uniq *data; + + /* Figure out where to put new node */ + while (*new) { + struct event_uniq *it; + int result; + + it = container_of(*new, struct event_uniq, node); + result = ev_uniq_ord(name, nl, domain, it->name, it->nl, + it->domain); + + parent = *new; + if (result < 0) + new = &((*new)->rb_left); + else if (result > 0) + new = &((*new)->rb_right); + else { + it->ct++; + pr_info("found a duplicate event %.*s, ct=%u\n", nl, + name, it->ct); + return it->ct; + } + } + + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + *data = (struct event_uniq) { + .name = name, + .nl = nl, + .ct = 0, + .domain = domain, + }; + + /* Add new node and rebalance tree. */ + rb_link_node(&data->node, parent, new); + rb_insert_color(&data->node, root); + + /* data->ct */ + return 0; +} + +static void event_uniq_destroy(struct rb_root *root) +{ + /* + * the strings we point to are in the giant block of memory filled by + * the catalog, and are freed separately. + */ + struct event_uniq *pos, *n; + + rbtree_postorder_for_each_entry_safe(pos, n, root, node) + kfree(pos); +} + + +/* + * ensure the event structure's sizes are self consistent and don't cause us to + * read outside of the event + * + * On success, return the event length in bytes. + * Otherwise, return -1 (and print as appropriate). + */ +static ssize_t catalog_event_len_validate(struct hv_24x7_event_data *event, + size_t event_idx, + size_t event_data_bytes, + size_t event_entry_count, + size_t offset, void *end) +{ + ssize_t ev_len; + void *ev_end, *calc_ev_end; + + if (offset >= event_data_bytes) + return -1; + + if (event_idx >= event_entry_count) { + pr_devel("catalog event data has %zu bytes of padding after last event\n", + event_data_bytes - offset); + return -1; + } + + if (!event_fixed_portion_is_within(event, end)) { + pr_warn("event %zu fixed portion is not within range\n", + event_idx); + return -1; + } + + ev_len = be16_to_cpu(event->length); + + if (ev_len % 16) + pr_info("event %zu has length %zu not divisible by 16: event=%pK\n", + event_idx, ev_len, event); + + ev_end = (__u8 *)event + ev_len; + if (ev_end > end) { + pr_warn("event %zu has .length=%zu, ends after buffer end: ev_end=%pK > end=%pK, offset=%zu\n", + event_idx, ev_len, ev_end, end, + offset); + return -1; + } + + calc_ev_end = event_end(event, end); + if (!calc_ev_end) { + pr_warn("event %zu has a calculated length which exceeds buffer length %zu: event=%pK end=%pK, offset=%zu\n", + event_idx, event_data_bytes, event, end, + offset); + return -1; + } + + if (calc_ev_end > ev_end) { + pr_warn("event %zu exceeds it's own length: event=%pK, end=%pK, offset=%zu, calc_ev_end=%pK\n", + event_idx, event, ev_end, offset, calc_ev_end); + return -1; + } + + return ev_len; +} + +#define MAX_4K (SIZE_MAX / 4096) + +static void create_events_from_catalog(struct attribute ***events_, + struct attribute ***event_descs_, + struct attribute ***event_long_descs_) +{ + unsigned long hret; + size_t catalog_len, catalog_page_len, event_entry_count, + event_data_len, event_data_offs, + event_data_bytes, junk_events, event_idx, event_attr_ct, i, + attr_max, event_idx_last, desc_ct, long_desc_ct; + ssize_t ct, ev_len; + uint32_t catalog_version_num; + struct attribute **events, **event_descs, **event_long_descs; + struct hv_24x7_catalog_page_0 *page_0 = + kmem_cache_alloc(hv_page_cache, GFP_KERNEL); + void *page = page_0; + void *event_data, *end; + struct hv_24x7_event_data *event; + struct rb_root ev_uniq = RB_ROOT; + + if (!page) + goto e_out; + + hret = h_get_24x7_catalog_page(page, 0, 0); + if (hret) + goto e_free; + + catalog_version_num = be64_to_cpu(page_0->version); + catalog_page_len = be32_to_cpu(page_0->length); + + if (MAX_4K < catalog_page_len) { + pr_err("invalid page count: %zu\n", catalog_page_len); + goto e_free; + } + + catalog_len = catalog_page_len * 4096; + + event_entry_count = be16_to_cpu(page_0->event_entry_count); + event_data_offs = be16_to_cpu(page_0->event_data_offs); + event_data_len = be16_to_cpu(page_0->event_data_len); + + pr_devel("cv %zu cl %zu eec %zu edo %zu edl %zu\n", + (size_t)catalog_version_num, catalog_len, + event_entry_count, event_data_offs, event_data_len); + + if ((MAX_4K < event_data_len) + || (MAX_4K < event_data_offs) + || (MAX_4K - event_data_offs < event_data_len)) { + pr_err("invalid event data offs %zu and/or len %zu\n", + event_data_offs, event_data_len); + goto e_free; + } + + if ((event_data_offs + event_data_len) > catalog_page_len) { + pr_err("event data %zu-%zu does not fit inside catalog 0-%zu\n", + event_data_offs, + event_data_offs + event_data_len, + catalog_page_len); + goto e_free; + } + + if (SIZE_MAX / MAX_EVENTS_PER_EVENT_DATA - 1 < event_entry_count) { + pr_err("event_entry_count %zu is invalid\n", + event_entry_count); + goto e_free; + } + + event_data_bytes = event_data_len * 4096; + + /* + * event data can span several pages, events can cross between these + * pages. Use vmalloc to make this easier. + */ + event_data = vmalloc(event_data_bytes); + if (!event_data) { + pr_err("could not allocate event data\n"); + goto e_free; + } + + end = event_data + event_data_bytes; + + /* + * using vmalloc_to_phys() like this only works if PAGE_SIZE is + * divisible by 4096 + */ + BUILD_BUG_ON(PAGE_SIZE % 4096); + + for (i = 0; i < event_data_len; i++) { + hret = h_get_24x7_catalog_page_( + vmalloc_to_phys(event_data + i * 4096), + catalog_version_num, + i + event_data_offs); + if (hret) { + pr_err("failed to get event data in page %zu\n", + i + event_data_offs); + goto e_event_data; + } + } + + /* + * scan the catalog to determine the number of attributes we need, and + * verify it at the same time. + */ + for (junk_events = 0, event = event_data, event_idx = 0, attr_max = 0; + ; + event_idx++, event = (void *)event + ev_len) { + size_t offset = (void *)event - (void *)event_data; + char *name; + int nl; + + ev_len = catalog_event_len_validate(event, event_idx, + event_data_bytes, + event_entry_count, + offset, end); + if (ev_len < 0) + break; + + name = event_name(event, &nl); + + if (event->event_group_record_len == 0) { + pr_devel("invalid event %zu (%.*s): group_record_len == 0, skipping\n", + event_idx, nl, name); + junk_events++; + continue; + } + + if (!catalog_entry_domain_is_valid(event->domain)) { + pr_info("event %zu (%.*s) has invalid domain %d\n", + event_idx, nl, name, event->domain); + junk_events++; + continue; + } + + attr_max += event_to_attr_ct(event); + } + + event_idx_last = event_idx; + if (event_idx_last != event_entry_count) + pr_warn("event buffer ended before listed # of events were parsed (got %zu, wanted %zu, junk %zu)\n", + event_idx_last, event_entry_count, junk_events); + + events = kmalloc_array(attr_max + 1, sizeof(*events), GFP_KERNEL); + if (!events) + goto e_event_data; + + event_descs = kmalloc_array(event_idx + 1, sizeof(*event_descs), + GFP_KERNEL); + if (!event_descs) + goto e_event_attrs; + + event_long_descs = kmalloc_array(event_idx + 1, + sizeof(*event_long_descs), GFP_KERNEL); + if (!event_long_descs) + goto e_event_descs; + + /* Iterate over the catalog filling in the attribute vector */ + for (junk_events = 0, event_attr_ct = 0, desc_ct = 0, long_desc_ct = 0, + event = event_data, event_idx = 0; + event_idx < event_idx_last; + event_idx++, ev_len = be16_to_cpu(event->length), + event = (void *)event + ev_len) { + char *name; + int nl; + int nonce; + /* + * these are the only "bad" events that are intermixed and that + * we can ignore without issue. make sure to skip them here + */ + if (event->event_group_record_len == 0) + continue; + if (!catalog_entry_domain_is_valid(event->domain)) + continue; + + name = event_name(event, &nl); + nonce = event_uniq_add(&ev_uniq, name, nl, event->domain); + ct = event_data_to_attrs(event_idx, events + event_attr_ct, + event, nonce); + if (ct <= 0) { + pr_warn("event %zu (%.*s) creation failure, skipping\n", + event_idx, nl, name); + junk_events++; + } else { + event_attr_ct += ct; + event_descs[desc_ct] = event_to_desc_attr(event, nonce); + if (event_descs[desc_ct]) + desc_ct++; + event_long_descs[long_desc_ct] = + event_to_long_desc_attr(event, nonce); + if (event_long_descs[long_desc_ct]) + long_desc_ct++; + } + } + + pr_info("read %zu catalog entries, created %zu event attrs (%zu failures), %zu descs\n", + event_idx, event_attr_ct, junk_events, desc_ct); + + events[event_attr_ct] = NULL; + event_descs[desc_ct] = NULL; + event_long_descs[long_desc_ct] = NULL; + + event_uniq_destroy(&ev_uniq); + vfree(event_data); + kmem_cache_free(hv_page_cache, page); + + *events_ = events; + *event_descs_ = event_descs; + *event_long_descs_ = event_long_descs; + return; + +e_event_descs: + kfree(event_descs); +e_event_attrs: + kfree(events); +e_event_data: + vfree(event_data); +e_free: + kmem_cache_free(hv_page_cache, page); +e_out: + *events_ = NULL; + *event_descs_ = NULL; + *event_long_descs_ = NULL; +} + static ssize_t catalog_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t offset, size_t count) @@ -207,16 +969,13 @@ static struct attribute_group if_group = { static const struct attribute_group *attr_groups[] = { &format_group, + &event_group, + &event_desc_group, + &event_long_desc_group, &if_group, NULL, }; -static bool is_physical_domain(int domain) -{ - return domain == HV_24X7_PERF_DOMAIN_PHYSICAL_CHIP || - domain == HV_24X7_PERF_DOMAIN_PHYSICAL_CORE; -} - DEFINE_PER_CPU(char, hv_24x7_reqb[4096]) __aligned(4096); DEFINE_PER_CPU(char, hv_24x7_resb[4096]) __aligned(4096); @@ -291,9 +1050,17 @@ out: static unsigned long event_24x7_request(struct perf_event *event, u64 *res, bool success_expected) { + u16 idx; + unsigned domain = event_get_domain(event); + + if (is_physical_domain(domain)) + idx = event_get_core(event); + else + idx = event_get_vcpu(event); + return single_24x7_request(event_get_domain(event), event_get_offset(event), - event_get_starting_index(event), + idx, event_get_lpar(event), res, success_expected); @@ -356,7 +1123,7 @@ static int h_24x7_event_init(struct perf_event *event) return -EIO; } - /* PHYSICAL domains & other lpars require extra capabilities */ + /* Physical domains & other lpars require extra capabilities */ if (!caps.collect_privileged && (is_physical_domain(domain) || (event_get_lpar(event) != event_get_lpar_max()))) { pr_devel("hv permisions disallow: is_physical_domain:%d, lpar=0x%llx\n", @@ -452,6 +1219,10 @@ static int hv_24x7_init(void) /* sampling not supported */ h_24x7_pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; + create_events_from_catalog(&event_group.attrs, + &event_desc_group.attrs, + &event_long_desc_group.attrs); + r = perf_pmu_register(&h_24x7_pmu, h_24x7_pmu.name, -1); if (r) return r; diff --git a/arch/powerpc/perf/hv-24x7.h b/arch/powerpc/perf/hv-24x7.h index 720ebce4b435..69cd4e690f58 100644 --- a/arch/powerpc/perf/hv-24x7.h +++ b/arch/powerpc/perf/hv-24x7.h @@ -3,14 +3,14 @@ #include +enum hv_perf_domains { +#define DOMAIN(n, v, x, c) HV_PERF_DOMAIN_##n = v, +#include "hv-24x7-domains.h" +#undef DOMAIN +}; + struct hv_24x7_request { /* PHYSICAL domains require enabling via phyp/hmc. */ -#define HV_24X7_PERF_DOMAIN_PHYSICAL_CHIP 0x01 -#define HV_24X7_PERF_DOMAIN_PHYSICAL_CORE 0x02 -#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_HOME_CORE 0x03 -#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_HOME_CHIP 0x04 -#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_HOME_NODE 0x05 -#define HV_24X7_PERF_DOMAIN_VIRTUAL_PROCESSOR_REMOTE_NODE 0x06 __u8 performance_domain; __u8 reserved[0x1]; diff --git a/arch/powerpc/perf/hv-common.c b/arch/powerpc/perf/hv-common.c index 47e02b366f58..7dce8f109967 100644 --- a/arch/powerpc/perf/hv-common.c +++ b/arch/powerpc/perf/hv-common.c @@ -9,13 +9,13 @@ unsigned long hv_perf_caps_get(struct hv_perf_caps *caps) unsigned long r; struct p { struct hv_get_perf_counter_info_params params; - struct cv_system_performance_capabilities caps; + struct hv_gpci_system_performance_capabilities caps; } __packed __aligned(sizeof(uint64_t)); struct p arg = { .params = { .counter_request = cpu_to_be32( - CIR_SYSTEM_PERFORMANCE_CAPABILITIES), + HV_GPCI_system_performance_capabilities), .starting_index = cpu_to_be32(-1), .counter_info_version_in = 0, } @@ -31,9 +31,9 @@ unsigned long hv_perf_caps_get(struct hv_perf_caps *caps) caps->version = arg.params.counter_info_version_out; caps->collect_privileged = !!arg.caps.perf_collect_privileged; - caps->ga = !!(arg.caps.capability_mask & CV_CM_GA); - caps->expanded = !!(arg.caps.capability_mask & CV_CM_EXPANDED); - caps->lab = !!(arg.caps.capability_mask & CV_CM_LAB); + caps->ga = !!(arg.caps.capability_mask & HV_GPCI_CM_GA); + caps->expanded = !!(arg.caps.capability_mask & HV_GPCI_CM_EXPANDED); + caps->lab = !!(arg.caps.capability_mask & HV_GPCI_CM_LAB); return r; } diff --git a/arch/powerpc/perf/hv-common.h b/arch/powerpc/perf/hv-common.h index 5d79cecbd73d..349aaba4d2d1 100644 --- a/arch/powerpc/perf/hv-common.h +++ b/arch/powerpc/perf/hv-common.h @@ -20,6 +20,16 @@ unsigned long hv_perf_caps_get(struct hv_perf_caps *caps); PMU_FORMAT_ATTR(name, #attr_var ":" #bit_start "-" #bit_end); \ EVENT_DEFINE_RANGE(name, attr_var, bit_start, bit_end) +/* + * The EVENT_DEFINE_RANGE_FORMAT() macro above includes helper functions + * for the fields (eg: event_get_starting_index()). For some fields we + * need the bit-range definition, but no the helper functions. Define a + * lite version of the above macro without the helpers and silence + * compiler warnings unused static functions. + */ +#define EVENT_DEFINE_RANGE_FORMAT_LITE(name, attr_var, bit_start, bit_end) \ +PMU_FORMAT_ATTR(name, #attr_var ":" #bit_start "-" #bit_end); + #define EVENT_DEFINE_RANGE(name, attr_var, bit_start, bit_end) \ static u64 event_get_##name##_max(void) \ { \ diff --git a/arch/powerpc/perf/hv-gpci-requests.h b/arch/powerpc/perf/hv-gpci-requests.h new file mode 100644 index 000000000000..acd17648cd18 --- /dev/null +++ b/arch/powerpc/perf/hv-gpci-requests.h @@ -0,0 +1,261 @@ + +#include "req-gen/_begin.h" + +/* + * Based on the document "getPerfCountInfo v1.07" + */ + +/* + * #define REQUEST_NAME counter_request_name + * #define REQUEST_NUM r_num + * #define REQUEST_IDX_KIND starting_index_kind + * #include I(REQUEST_BEGIN) + * REQUEST( + * __field(...) + * __field(...) + * __array(...) + * __count(...) + * ) + * #include I(REQUEST_END) + * + * - starting_index_kind is one of the following, depending on the event: + * + * hw_chip_id: hardware chip id or -1 for current hw chip + * partition_id + * sibling_part_id, + * phys_processor_idx: + * 0xffffffffffffffff: or -1, which means it is irrelavant for the event + * + * __count(offset, bytes, name): + * a counter that should be exposed via perf + * __field(offset, bytes, name) + * a normal field + * __array(offset, bytes, name) + * an array of bytes + * + * + * @bytes for __count, and __field _must_ be a numeral token + * in decimal, not an expression and not in hex. + * + * + * TODO: + * - expose secondary index (if any counter ever uses it, only 0xA0 + * appears to use it right now, and it doesn't have any counters) + * - embed versioning info + * - include counter descriptions + */ +#define REQUEST_NAME dispatch_timebase_by_processor +#define REQUEST_NUM 0x10 +#define REQUEST_IDX_KIND "phys_processor_idx=?" +#include I(REQUEST_BEGIN) +REQUEST(__count(0, 8, processor_time_in_timebase_cycles) + __field(0x8, 4, hw_processor_id) + __field(0xC, 2, owning_part_id) + __field(0xE, 1, processor_state) + __field(0xF, 1, version) + __field(0x10, 4, hw_chip_id) + __field(0x14, 4, phys_module_id) + __field(0x18, 4, primary_affinity_domain_idx) + __field(0x1C, 4, secondary_affinity_domain_idx) + __field(0x20, 4, processor_version) + __field(0x24, 2, logical_processor_idx) + __field(0x26, 2, reserved) + __field(0x28, 4, processor_id_register) + __field(0x2C, 4, phys_processor_idx) +) +#include I(REQUEST_END) + +#define REQUEST_NAME entitled_capped_uncapped_donated_idle_timebase_by_partition +#define REQUEST_NUM 0x20 +#define REQUEST_IDX_KIND "sibling_part_id=?" +#include I(REQUEST_BEGIN) +REQUEST(__field(0, 8, partition_id) + __count(0x8, 8, entitled_cycles) + __count(0x10, 8, consumed_capped_cycles) + __count(0x18, 8, consumed_uncapped_cycles) + __count(0x20, 8, cycles_donated) + __count(0x28, 8, purr_idle_cycles) +) +#include I(REQUEST_END) + +/* + * Not available for counter_info_version >= 0x8, use + * run_instruction_cycles_by_partition(0x100) instead. + */ +#define REQUEST_NAME run_instructions_run_cycles_by_partition +#define REQUEST_NUM 0x30 +#define REQUEST_IDX_KIND "sibling_part_id=?" +#include I(REQUEST_BEGIN) +REQUEST(__field(0, 8, partition_id) + __count(0x8, 8, instructions_completed) + __count(0x10, 8, cycles) +) +#include I(REQUEST_END) + +#define REQUEST_NAME system_performance_capabilities +#define REQUEST_NUM 0x40 +#define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff" +#include I(REQUEST_BEGIN) +REQUEST(__field(0, 1, perf_collect_privileged) + __field(0x1, 1, capability_mask) + __array(0x2, 0xE, reserved) +) +#include I(REQUEST_END) + +#define REQUEST_NAME processor_bus_utilization_abc_links +#define REQUEST_NUM 0x50 +#define REQUEST_IDX_KIND "hw_chip_id=?" +#include I(REQUEST_BEGIN) +REQUEST(__field(0, 4, hw_chip_id) + __array(0x4, 0xC, reserved1) + __count(0x10, 8, total_link_cycles) + __count(0x18, 8, idle_cycles_for_a_link) + __count(0x20, 8, idle_cycles_for_b_link) + __count(0x28, 8, idle_cycles_for_c_link) + __array(0x30, 0x20, reserved2) +) +#include I(REQUEST_END) + +#define REQUEST_NAME processor_bus_utilization_wxyz_links +#define REQUEST_NUM 0x60 +#define REQUEST_IDX_KIND "hw_chip_id=?" +#include I(REQUEST_BEGIN) +REQUEST(__field(0, 4, hw_chip_id) + __array(0x4, 0xC, reserved1) + __count(0x10, 8, total_link_cycles) + __count(0x18, 8, idle_cycles_for_w_link) + __count(0x20, 8, idle_cycles_for_x_link) + __count(0x28, 8, idle_cycles_for_y_link) + __count(0x30, 8, idle_cycles_for_z_link) + __array(0x38, 0x28, reserved2) +) +#include I(REQUEST_END) + +#define REQUEST_NAME processor_bus_utilization_gx_links +#define REQUEST_NUM 0x70 +#define REQUEST_IDX_KIND "hw_chip_id=?" +#include I(REQUEST_BEGIN) +REQUEST(__field(0, 4, hw_chip_id) + __array(0x4, 0xC, reserved1) + __count(0x10, 8, gx0_in_address_cycles) + __count(0x18, 8, gx0_in_data_cycles) + __count(0x20, 8, gx0_in_retries) + __count(0x28, 8, gx0_in_bus_cycles) + __count(0x30, 8, gx0_in_cycles_total) + __count(0x38, 8, gx0_out_address_cycles) + __count(0x40, 8, gx0_out_data_cycles) + __count(0x48, 8, gx0_out_retries) + __count(0x50, 8, gx0_out_bus_cycles) + __count(0x58, 8, gx0_out_cycles_total) + __count(0x60, 8, gx1_in_address_cycles) + __count(0x68, 8, gx1_in_data_cycles) + __count(0x70, 8, gx1_in_retries) + __count(0x78, 8, gx1_in_bus_cycles) + __count(0x80, 8, gx1_in_cycles_total) + __count(0x88, 8, gx1_out_address_cycles) + __count(0x90, 8, gx1_out_data_cycles) + __count(0x98, 8, gx1_out_retries) + __count(0xA0, 8, gx1_out_bus_cycles) + __count(0xA8, 8, gx1_out_cycles_total) +) +#include I(REQUEST_END) + +#define REQUEST_NAME processor_bus_utilization_mc_links +#define REQUEST_NUM 0x80 +#define REQUEST_IDX_KIND "hw_chip_id=?" +#include I(REQUEST_BEGIN) +REQUEST(__field(0, 4, hw_chip_id) + __array(0x4, 0xC, reserved1) + __count(0x10, 8, mc0_frames) + __count(0x18, 8, mc0_reads) + __count(0x20, 8, mc0_write) + __count(0x28, 8, mc0_total_cycles) + __count(0x30, 8, mc1_frames) + __count(0x38, 8, mc1_reads) + __count(0x40, 8, mc1_writes) + __count(0x48, 8, mc1_total_cycles) +) +#include I(REQUEST_END) + +/* Processor_config (0x90) skipped, no counters */ +/* Current_processor_frequency (0x91) skipped, no counters */ + +#define REQUEST_NAME processor_core_utilization +#define REQUEST_NUM 0x94 +#define REQUEST_IDX_KIND "phys_processor_idx=?" +#include I(REQUEST_BEGIN) +REQUEST(__field(0, 4, phys_processor_idx) + __field(0x4, 4, hw_processor_id) + __count(0x8, 8, cycles_across_any_thread) + __count(0x10, 8, timebase_at_collection) + __count(0x18, 8, purr_cycles) + __count(0x20, 8, sum_of_cycles_across_all_threads) + __count(0x28, 8, instructions_completed) +) +#include I(REQUEST_END) + +/* Processor_core_power_mode (0x95) skipped, no counters */ +/* Affinity_domain_information_by_virtual_processor (0xA0) skipped, + * no counters */ +/* Affinity_domain_information_by_domain (0xB0) skipped, no counters */ +/* Affinity_domain_information_by_partition (0xB1) skipped, no counters */ +/* Physical_memory_info (0xC0) skipped, no counters */ +/* Processor_bus_topology (0xD0) skipped, no counters */ + +#define REQUEST_NAME partition_hypervisor_queuing_times +#define REQUEST_NUM 0xE0 +#define REQUEST_IDX_KIND "partition_id=?" +#include I(REQUEST_BEGIN) +REQUEST(__field(0, 2, partition_id) + __array(0x2, 6, reserved1) + __count(0x8, 8, time_waiting_for_entitlement) + __count(0x10, 8, times_waited_for_entitlement) + __count(0x18, 8, time_waiting_for_phys_processor) + __count(0x20, 8, times_waited_for_phys_processor) + __count(0x28, 8, dispatches_on_home_core) + __count(0x30, 8, dispatches_on_home_primary_affinity_domain) + __count(0x38, 8, dispatches_on_home_secondary_affinity_domain) + __count(0x40, 8, dispatches_off_home_secondary_affinity_domain) + __count(0x48, 8, dispatches_on_dedicated_processor_donating_cycles) +) +#include I(REQUEST_END) + +#define REQUEST_NAME system_hypervisor_times +#define REQUEST_NUM 0xF0 +#define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff" +#include I(REQUEST_BEGIN) +REQUEST(__count(0, 8, time_spent_to_dispatch_virtual_processors) + __count(0x8, 8, time_spent_processing_virtual_processor_timers) + __count(0x10, 8, time_spent_managing_partitions_over_entitlement) + __count(0x18, 8, time_spent_on_system_management) +) +#include I(REQUEST_END) + +#define REQUEST_NAME system_tlbie_count_and_time +#define REQUEST_NUM 0xF4 +#define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff" +#include I(REQUEST_BEGIN) +REQUEST(__count(0, 8, tlbie_instructions_issued) + /* + * FIXME: The spec says the offset here is 0x10, which I suspect + * is wrong. + */ + __count(0x8, 8, time_spent_issuing_tlbies) +) +#include I(REQUEST_END) + +#define REQUEST_NAME partition_instruction_count_and_time +#define REQUEST_NUM 0x100 +#define REQUEST_IDX_KIND "partition_id=?" +#include I(REQUEST_BEGIN) +REQUEST(__field(0, 2, partition_id) + __array(0x2, 0x6, reserved1) + __count(0x8, 8, instructions_performed) + __count(0x10, 8, time_collected) +) +#include I(REQUEST_END) + +/* set_mmcrh (0x80001000) skipped, no counters */ +/* retrieve_hpmcx (0x80002000) skipped, no counters */ + +#include "req-gen/_end.h" diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c index a051fe946c63..856fe6e03c2a 100644 --- a/arch/powerpc/perf/hv-gpci.c +++ b/arch/powerpc/perf/hv-gpci.c @@ -31,7 +31,18 @@ /* u32 */ EVENT_DEFINE_RANGE_FORMAT(request, config, 0, 31); /* u32 */ +/* + * Note that starting_index, phys_processor_idx, sibling_part_id, + * hw_chip_id, partition_id all refer to the same bit range. They + * are basically aliases for the starting_index. The specific alias + * used depends on the event. See REQUEST_IDX_KIND in hv-gpci-requests.h + */ EVENT_DEFINE_RANGE_FORMAT(starting_index, config, 32, 63); +EVENT_DEFINE_RANGE_FORMAT_LITE(phys_processor_idx, config, 32, 63); +EVENT_DEFINE_RANGE_FORMAT_LITE(sibling_part_id, config, 32, 63); +EVENT_DEFINE_RANGE_FORMAT_LITE(hw_chip_id, config, 32, 63); +EVENT_DEFINE_RANGE_FORMAT_LITE(partition_id, config, 32, 63); + /* u16 */ EVENT_DEFINE_RANGE_FORMAT(secondary_index, config1, 0, 15); /* u8 */ @@ -44,6 +55,10 @@ EVENT_DEFINE_RANGE_FORMAT(offset, config1, 32, 63); static struct attribute *format_attrs[] = { &format_attr_request.attr, &format_attr_starting_index.attr, + &format_attr_phys_processor_idx.attr, + &format_attr_sibling_part_id.attr, + &format_attr_hw_chip_id.attr, + &format_attr_partition_id.attr, &format_attr_secondary_index.attr, &format_attr_counter_info_version.attr, @@ -57,6 +72,11 @@ static struct attribute_group format_group = { .attrs = format_attrs, }; +static struct attribute_group event_group = { + .name = "events", + .attrs = hv_gpci_event_attrs, +}; + #define HV_CAPS_ATTR(_name, _format) \ static ssize_t _name##_show(struct device *dev, \ struct device_attribute *attr, \ @@ -102,6 +122,7 @@ static struct attribute_group interface_group = { static const struct attribute_group *attr_groups[] = { &format_group, + &event_group, &interface_group, NULL, }; @@ -265,6 +286,8 @@ static int hv_gpci_init(void) unsigned long hret; struct hv_perf_caps caps; + hv_gpci_assert_offsets_correct(); + if (!firmware_has_feature(FW_FEATURE_LPAR)) { pr_debug("not a virtualized system, not enabling\n"); return -ENODEV; diff --git a/arch/powerpc/perf/hv-gpci.h b/arch/powerpc/perf/hv-gpci.h index b25f460c9cce..86ede8275961 100644 --- a/arch/powerpc/perf/hv-gpci.h +++ b/arch/powerpc/perf/hv-gpci.h @@ -42,32 +42,19 @@ struct hv_get_perf_counter_info_params { */ #define COUNTER_INFO_VERSION_CURRENT 0x8 -/* - * These determine the counter_value[] layout and the meaning of starting_index - * and secondary_index. - * - * Unless otherwise noted, @secondary_index is unused and ignored. - */ -enum counter_info_requests { - - /* GENERAL */ - - /* @starting_index: must be -1 (to refer to the current partition) - */ - CIR_SYSTEM_PERFORMANCE_CAPABILITIES = 0X40, +/* capability mask masks. */ +enum { + HV_GPCI_CM_GA = (1 << 7), + HV_GPCI_CM_EXPANDED = (1 << 6), + HV_GPCI_CM_LAB = (1 << 5) }; -struct cv_system_performance_capabilities { - /* If != 0, allowed to collect data from other partitions */ - __u8 perf_collect_privileged; - - /* These following are only valid if counter_info_version >= 0x3 */ -#define CV_CM_GA (1 << 7) -#define CV_CM_EXPANDED (1 << 6) -#define CV_CM_LAB (1 << 5) - /* remaining bits are reserved */ - __u8 capability_mask; - __u8 reserved[0xE]; -} __packed; +#define REQUEST_FILE "../hv-gpci-requests.h" +#define NAME_LOWER hv_gpci +#define NAME_UPPER HV_GPCI +#include "req-gen/perf.h" +#undef REQUEST_FILE +#undef NAME_LOWER +#undef NAME_UPPER #endif diff --git a/arch/powerpc/perf/req-gen/_begin.h b/arch/powerpc/perf/req-gen/_begin.h new file mode 100644 index 000000000000..acfb17a55c16 --- /dev/null +++ b/arch/powerpc/perf/req-gen/_begin.h @@ -0,0 +1,13 @@ +/* Include paths to be used in interface defining headers */ +#ifndef POWERPC_PERF_REQ_GEN_H_ +#define POWERPC_PERF_REQ_GEN_H_ + +#define CAT2_STR_(t, s) __stringify(t/s) +#define CAT2_STR(t, s) CAT2_STR_(t, s) +#define I(...) __VA_ARGS__ + +#endif + +#define REQ_GEN_PREFIX req-gen +#define REQUEST_BEGIN CAT2_STR(REQ_GEN_PREFIX, _request-begin.h) +#define REQUEST_END CAT2_STR(REQ_GEN_PREFIX, _request-end.h) diff --git a/arch/powerpc/perf/req-gen/_clear.h b/arch/powerpc/perf/req-gen/_clear.h new file mode 100644 index 000000000000..422974f89573 --- /dev/null +++ b/arch/powerpc/perf/req-gen/_clear.h @@ -0,0 +1,5 @@ + +#undef __field_ +#undef __count_ +#undef __array_ +#undef REQUEST_ diff --git a/arch/powerpc/perf/req-gen/_end.h b/arch/powerpc/perf/req-gen/_end.h new file mode 100644 index 000000000000..8a406980b6bf --- /dev/null +++ b/arch/powerpc/perf/req-gen/_end.h @@ -0,0 +1,4 @@ + +#undef REQ_GEN_PREFIX +#undef REQUEST_BEGIN +#undef REQUEST_END diff --git a/arch/powerpc/perf/req-gen/_request-begin.h b/arch/powerpc/perf/req-gen/_request-begin.h new file mode 100644 index 000000000000..f6d98642cf1d --- /dev/null +++ b/arch/powerpc/perf/req-gen/_request-begin.h @@ -0,0 +1,15 @@ + +#define REQUEST(r_contents) \ + REQUEST_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, I(r_contents)) + +#define __field(f_offset, f_bytes, f_name) \ + __field_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, \ + f_offset, f_bytes, f_name) + +#define __array(f_offset, f_bytes, f_name) \ + __array_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, \ + f_offset, f_bytes, f_name) + +#define __count(f_offset, f_bytes, f_name) \ + __count_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, \ + f_offset, f_bytes, f_name) diff --git a/arch/powerpc/perf/req-gen/_request-end.h b/arch/powerpc/perf/req-gen/_request-end.h new file mode 100644 index 000000000000..5573be6c3588 --- /dev/null +++ b/arch/powerpc/perf/req-gen/_request-end.h @@ -0,0 +1,8 @@ +#undef REQUEST +#undef __field +#undef __array +#undef __count + +#undef REQUEST_NAME +#undef REQUEST_NUM +#undef REQUEST_IDX_KIND diff --git a/arch/powerpc/perf/req-gen/perf.h b/arch/powerpc/perf/req-gen/perf.h new file mode 100644 index 000000000000..1b122469323d --- /dev/null +++ b/arch/powerpc/perf/req-gen/perf.h @@ -0,0 +1,155 @@ +#ifndef LINUX_POWERPC_PERF_REQ_GEN_PERF_H_ +#define LINUX_POWERPC_PERF_REQ_GEN_PERF_H_ + +#include + +#ifndef REQUEST_FILE +#error "REQUEST_FILE must be defined before including" +#endif + +#ifndef NAME_LOWER +#error "NAME_LOWER must be defined before including" +#endif + +#ifndef NAME_UPPER +#error "NAME_UPPER must be defined before including" +#endif + +#define BE_TYPE_b1 __u8 +#define BE_TYPE_b2 __be16 +#define BE_TYPE_b4 __be32 +#define BE_TYPE_b8 __be64 + +#define BYTES_TO_BE_TYPE(bytes) \ + BE_TYPE_b##bytes + +#define CAT2_(a, b) a ## b +#define CAT2(a, b) CAT2_(a, b) +#define CAT3_(a, b, c) a ## b ## c +#define CAT3(a, b, c) CAT3_(a, b, c) + +/* + * enumerate the request values as + * _ = + */ +#define REQUEST_VALUE__(name_upper, r_name) name_upper ## _ ## r_name +#define REQUEST_VALUE_(name_upper, r_name) REQUEST_VALUE__(name_upper, r_name) +#define REQUEST_VALUE(r_name) REQUEST_VALUE_(NAME_UPPER, r_name) + +#include "_clear.h" +#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \ + REQUEST_VALUE(r_name) = r_value, +enum CAT2(NAME_LOWER, _requests) { +#include REQUEST_FILE +}; + +/* + * For each request: + * struct _ { + * r_fields + * }; + */ +#include "_clear.h" +#define STRUCT_NAME__(name_lower, r_name) name_lower ## _ ## r_name +#define STRUCT_NAME_(name_lower, r_name) STRUCT_NAME__(name_lower, r_name) +#define STRUCT_NAME(r_name) STRUCT_NAME_(NAME_LOWER, r_name) +#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \ +struct STRUCT_NAME(r_name) { \ + r_fields \ +}; +#define __field_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name) \ + BYTES_TO_BE_TYPE(f_bytes) f_name; +#define __count_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name) \ + __field_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name) +#define __array_(r_name, r_value, r_idx_1, a_offset, a_bytes, a_name) \ + __u8 a_name[a_bytes]; + +#include REQUEST_FILE + +/* + * Generate a check of the field offsets + * _assert_offsets_correct() + */ +#include "_clear.h" +#define REQUEST_(r_name, r_value, index, r_fields) \ +r_fields +#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name) \ + BUILD_BUG_ON(offsetof(struct STRUCT_NAME(r_name), f_name) != f_offset); +#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \ + __field_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) +#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name) \ + __field_(r_name, r_value, r_idx_1, a_offset, a_size, a_name) + +static inline void CAT2(NAME_LOWER, _assert_offsets_correct)(void) +{ +#include REQUEST_FILE +} + +/* + * Generate event attributes: + * PMU_EVENT_ATTR_STRING(_, + * _event_attr__, + * "request=" + * "starting_index=" + * "counter_info_version=CURRENT_COUNTER_INFO_VERSION" + * "length=" + * "offset=") + * + * TODO: counter_info_version may need to vary, we should interperate the + * value to some extent + */ +#define EVENT_ATTR_NAME__(name, r_name, c_name) \ + name ## _event_attr_ ## r_name ## _ ## c_name +#define EVENT_ATTR_NAME_(name, r_name, c_name) \ + EVENT_ATTR_NAME__(name, r_name, c_name) +#define EVENT_ATTR_NAME(r_name, c_name) \ + EVENT_ATTR_NAME_(NAME_LOWER, r_name, c_name) + +#include "_clear.h" +#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name) +#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name) +#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \ +PMU_EVENT_ATTR_STRING( \ + CAT3(r_name, _, c_name), \ + EVENT_ATTR_NAME(r_name, c_name), \ + "request=" __stringify(r_value) "," \ + r_idx_1 "," \ + "counter_info_version=" \ + __stringify(COUNTER_INFO_VERSION_CURRENT) "," \ + "length=" #c_size "," \ + "offset=" #c_offset) +#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \ + r_fields + +#include REQUEST_FILE + +/* + * Define event attribute array + * static struct attribute *hv_gpci_event_attrs[] = { + * &_event_attr__.attr, + * }; + */ +#include "_clear.h" +#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name) +#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \ + &EVENT_ATTR_NAME(r_name, c_name).attr.attr, +#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name) +#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \ + r_fields + +static __maybe_unused struct attribute *hv_gpci_event_attrs[] = { +#include REQUEST_FILE + NULL +}; + +/* cleanup */ +#include "_clear.h" +#undef EVENT_ATTR_NAME +#undef EVENT_ATTR_NAME_ +#undef BIT_NAME +#undef BIT_NAME_ +#undef STRUCT_NAME +#undef REQUEST_VALUE +#undef REQUEST_VALUE_ + +#endif diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index d2ac1c116454..5538e57c36c1 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -214,7 +214,6 @@ config AKEBONO select ETHERNET select NET_VENDOR_IBM select IBM_EMAC_EMAC4 - select IBM_EMAC_RGMII_WOL select USB if USB_SUPPORT select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c index 1ad748bb39b4..5c31d8292d3b 100644 --- a/arch/powerpc/platforms/83xx/usb.c +++ b/arch/powerpc/platforms/83xx/usb.c @@ -162,8 +162,7 @@ int mpc831x_usb_cfg(void) iounmap(immap); - if (immr_node) - of_node_put(immr_node); + of_node_put(immr_node); /* Map USB SOC space */ ret = of_address_to_resource(np, 0, &res); diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index f22635a71d01..2fb4b24368a6 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -241,6 +241,12 @@ config SGY_CTS1000 help Enable this to support functionality in Servergy's CTS-1000 systems. +config MVME2500 + bool "Artesyn MVME2500" + select DEFAULT_UIMAGE + help + This option enables support for the Emerson/Artesyn MVME2500 board. + endif # PPC32 config PPC_QEMU_E500 diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 730326046625..1fe7fb95175a 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_XES_MPC85xx) += xes_mpc85xx.o obj-$(CONFIG_GE_IMP3A) += ge_imp3a.o obj-$(CONFIG_PPC_QEMU_E500) += qemu_e500.o obj-$(CONFIG_SGY_CTS1000) += sgy_cts1000.o +obj-$(CONFIG_MVME2500) += mvme2500.o diff --git a/arch/powerpc/platforms/85xx/mvme2500.c b/arch/powerpc/platforms/85xx/mvme2500.c new file mode 100644 index 000000000000..1233050560ae --- /dev/null +++ b/arch/powerpc/platforms/85xx/mvme2500.c @@ -0,0 +1,74 @@ +/* + * Board setup routines for the Emerson/Artesyn MVME2500 + * + * Copyright 2014 Elettra-Sincrotrone Trieste S.C.p.A. + * + * Based on earlier code by: + * + * Xianghua Xiao (x.xiao@freescale.com) + * Tom Armistead (tom.armistead@emerson.com) + * Copyright 2012 Emerson + * + * 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. + * + * Author Alessio Igor Bogani + * + */ + +#include +#include +#include +#include +#include + +#include "mpc85xx.h" + +void __init mvme2500_pic_init(void) +{ + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, + 0, 256, " OpenPIC "); + BUG_ON(mpic == NULL); + mpic_init(mpic); +} + +/* + * Setup the architecture + */ +static void __init mvme2500_setup_arch(void) +{ + if (ppc_md.progress) + ppc_md.progress("mvme2500_setup_arch()", 0); + fsl_pci_assign_primary(); + pr_info("MVME2500 board from Artesyn\n"); +} + +machine_arch_initcall(mvme2500, mpc85xx_common_publish_devices); + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mvme2500_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "artesyn,MVME2500"); +} + +define_machine(mvme2500) { + .name = "MVME2500", + .probe = mvme2500_probe, + .setup_arch = mvme2500_setup_arch, + .init_IRQ = mvme2500_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_phb = fsl_pcibios_fixup_phb, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/cell/celleb_scc_pciex.c b/arch/powerpc/platforms/cell/celleb_scc_pciex.c index f22387598040..94170e4f2ce7 100644 --- a/arch/powerpc/platforms/cell/celleb_scc_pciex.c +++ b/arch/powerpc/platforms/cell/celleb_scc_pciex.c @@ -399,8 +399,8 @@ static int scc_pciex_write_config(struct pci_bus *bus, unsigned int devfn, } static struct pci_ops scc_pciex_pci_ops = { - scc_pciex_read_config, - scc_pciex_write_config, + .read = scc_pciex_read_config, + .write = scc_pciex_write_config, }; static void pciex_clear_intr_all(unsigned int __iomem *base) diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c index c8017a7bcabd..b64e7ead752f 100644 --- a/arch/powerpc/platforms/cell/smp.c +++ b/arch/powerpc/platforms/cell/smp.c @@ -106,7 +106,7 @@ static int __init smp_iic_probe(void) { iic_request_IPIs(); - return cpumask_weight(cpu_possible_mask); + return num_possible_cpus(); } static void smp_cell_setup_cpu(int cpu) diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index beeaf4a173e1..df4ad95f183e 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -156,17 +156,6 @@ void mpc7448_hpc2_restart(char *cmd) for (;;) ; /* Spin until reset happens */ } -void mpc7448_hpc2_power_off(void) -{ - local_irq_disable(); - for (;;) ; /* No way to shut power off with software */ -} - -void mpc7448_hpc2_halt(void) -{ - mpc7448_hpc2_power_off(); -} - /* * Called very early, device-tree isn't unflattened */ diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 04702db35d45..f4071a67ad00 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -133,17 +133,23 @@ static void __init fixup_bus_range(struct device_node *bridge) |(((unsigned int)(off)) & 0xFCUL) \ |1UL) -static volatile void __iomem *macrisc_cfg_access(struct pci_controller* hose, - u8 bus, u8 dev_fn, u8 offset) +static void __iomem *macrisc_cfg_map_bus(struct pci_bus *bus, + unsigned int dev_fn, + int offset) { unsigned int caddr; + struct pci_controller *hose; - if (bus == hose->first_busno) { + hose = pci_bus_to_host(bus); + if (hose == NULL) + return NULL; + + if (bus->number == hose->first_busno) { if (dev_fn < (11 << 3)) return NULL; caddr = MACRISC_CFA0(dev_fn, offset); } else - caddr = MACRISC_CFA1(bus, dev_fn, offset); + caddr = MACRISC_CFA1(bus->number, dev_fn, offset); /* Uninorth will return garbage if we don't read back the value ! */ do { @@ -154,129 +160,46 @@ static volatile void __iomem *macrisc_cfg_access(struct pci_controller* hose, return hose->cfg_data + offset; } -static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) -{ - struct pci_controller *hose; - volatile void __iomem *addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset >= 0x100) - return PCIBIOS_BAD_REGISTER_NUMBER; - addr = macrisc_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - *val = in_8(addr); - break; - case 2: - *val = in_le16(addr); - break; - default: - *val = in_le32(addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct pci_controller *hose; - volatile void __iomem *addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset >= 0x100) - return PCIBIOS_BAD_REGISTER_NUMBER; - addr = macrisc_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - out_8(addr, val); - break; - case 2: - out_le16(addr, val); - break; - default: - out_le32(addr, val); - break; - } - return PCIBIOS_SUCCESSFUL; -} - static struct pci_ops macrisc_pci_ops = { - .read = macrisc_read_config, - .write = macrisc_write_config, + .map_bus = macrisc_cfg_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, }; #ifdef CONFIG_PPC32 /* * Verify that a specific (bus, dev_fn) exists on chaos */ -static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset) +static void __iomem *chaos_map_bus(struct pci_bus *bus, unsigned int devfn, + int offset) { struct device_node *np; const u32 *vendor, *device; if (offset >= 0x100) - return PCIBIOS_BAD_REGISTER_NUMBER; + return NULL; np = of_pci_find_child_device(bus->dev.of_node, devfn); if (np == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; + return NULL; vendor = of_get_property(np, "vendor-id", NULL); device = of_get_property(np, "device-id", NULL); if (vendor == NULL || device == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; + return NULL; if ((*vendor == 0x106b) && (*device == 3) && (offset >= 0x10) && (offset != 0x14) && (offset != 0x18) && (offset <= 0x24)) - return PCIBIOS_BAD_REGISTER_NUMBER; + return NULL; - return PCIBIOS_SUCCESSFUL; -} - -static int -chaos_read_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 *val) -{ - int result = chaos_validate_dev(bus, devfn, offset); - if (result == PCIBIOS_BAD_REGISTER_NUMBER) - *val = ~0U; - if (result != PCIBIOS_SUCCESSFUL) - return result; - return macrisc_read_config(bus, devfn, offset, len, val); -} - -static int -chaos_write_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 val) -{ - int result = chaos_validate_dev(bus, devfn, offset); - if (result != PCIBIOS_SUCCESSFUL) - return result; - return macrisc_write_config(bus, devfn, offset, len, val); + return macrisc_cfg_map_bus(bus, devfn, offset); } static struct pci_ops chaos_pci_ops = { - .read = chaos_read_config, - .write = chaos_write_config, + .map_bus = chaos_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, }; static void __init setup_chaos(struct pci_controller *hose, @@ -471,15 +394,24 @@ static struct pci_ops u3_ht_pci_ops = |(((unsigned int)(off)) & 0xfcU) \ |1UL) -static volatile void __iomem *u4_pcie_cfg_access(struct pci_controller* hose, - u8 bus, u8 dev_fn, int offset) +static void __iomem *u4_pcie_cfg_map_bus(struct pci_bus *bus, + unsigned int dev_fn, + int offset) { + struct pci_controller *hose; unsigned int caddr; - if (bus == hose->first_busno) { + if (offset >= 0x1000) + return NULL; + + hose = pci_bus_to_host(bus); + if (!hose) + return NULL; + + if (bus->number == hose->first_busno) { caddr = U4_PCIE_CFA0(dev_fn, offset); } else - caddr = U4_PCIE_CFA1(bus, dev_fn, offset); + caddr = U4_PCIE_CFA1(bus->number, dev_fn, offset); /* Uninorth will return garbage if we don't read back the value ! */ do { @@ -490,74 +422,11 @@ static volatile void __iomem *u4_pcie_cfg_access(struct pci_controller* hose, return hose->cfg_data + offset; } -static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) -{ - struct pci_controller *hose; - volatile void __iomem *addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset >= 0x1000) - return PCIBIOS_BAD_REGISTER_NUMBER; - addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - *val = in_8(addr); - break; - case 2: - *val = in_le16(addr); - break; - default: - *val = in_le32(addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct pci_controller *hose; - volatile void __iomem *addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset >= 0x1000) - return PCIBIOS_BAD_REGISTER_NUMBER; - addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - out_8(addr, val); - break; - case 2: - out_le16(addr, val); - break; - default: - out_le32(addr, val); - break; - } - return PCIBIOS_SUCCESSFUL; -} - static struct pci_ops u4_pcie_pci_ops = { - .read = u4_pcie_read_config, - .write = u4_pcie_write_config, + .map_bus = u4_pcie_cfg_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, }; static void pmac_pci_fixup_u4_of_node(struct pci_dev *dev) diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile index f241accc053d..6f3c5d33c3af 100644 --- a/arch/powerpc/platforms/powernv/Makefile +++ b/arch/powerpc/platforms/powernv/Makefile @@ -1,7 +1,7 @@ obj-y += setup.o opal-wrappers.o opal.o opal-async.o obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o obj-y += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o -obj-y += opal-msglog.o opal-hmi.o +obj-y += opal-msglog.o opal-hmi.o opal-power.o obj-$(CONFIG_SMP) += smp.o subcore.o subcore-asm.o obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index 1d19e7917d7f..e261869adc86 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -68,6 +68,17 @@ static int powernv_eeh_init(void) if (phb->model == PNV_PHB_MODEL_P7IOC) eeh_add_flag(EEH_ENABLE_IO_FOR_LOG); + + /* + * PE#0 should be regarded as valid by EEH core + * if it's not the reserved one. Currently, we + * have the reserved PE#0 and PE#127 for PHB3 + * and P7IOC separately. So we should regard + * PE#0 as valid for P7IOC. + */ + if (phb->ioda.reserved_pe != 0) + eeh_add_flag(EEH_VALID_PE_ZERO); + break; } diff --git a/arch/powerpc/platforms/powernv/opal-power.c b/arch/powerpc/platforms/powernv/opal-power.c new file mode 100644 index 000000000000..48bf5b080bcf --- /dev/null +++ b/arch/powerpc/platforms/powernv/opal-power.c @@ -0,0 +1,65 @@ +/* + * PowerNV OPAL power control for graceful shutdown handling + * + * Copyright 2015 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 + +#define SOFT_OFF 0x00 +#define SOFT_REBOOT 0x01 + +static int opal_power_control_event(struct notifier_block *nb, + unsigned long msg_type, void *msg) +{ + struct opal_msg *power_msg = msg; + uint64_t type; + + type = be64_to_cpu(power_msg->params[0]); + + switch (type) { + case SOFT_REBOOT: + /* Fall through. The service processor is responsible for + * bringing the machine back up */ + case SOFT_OFF: + pr_info("OPAL: poweroff requested\n"); + orderly_poweroff(true); + break; + default: + pr_err("OPAL: power control type unexpected %016llx\n", type); + } + + return 0; +} + +static struct notifier_block opal_power_control_nb = { + .notifier_call = opal_power_control_event, + .next = NULL, + .priority = 0, +}; + +static int __init opal_power_control_init(void) +{ + int ret; + + ret = opal_message_notifier_register(OPAL_MSG_SHUTDOWN, + &opal_power_control_nb); + if (ret) { + pr_err("%s: Can't register OPAL event notifier (%d)\n", + __func__, ret); + return ret; + } + + return 0; +} +machine_subsys_initcall(powernv, opal_power_control_init); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index f10b9ec8c1f5..18fd4e71c9c1 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -208,7 +208,7 @@ static int __init opal_register_exception_handlers(void) * start catching/handling HMI directly in Linux. */ if (!opal_check_token(OPAL_HANDLE_HMI)) { - pr_info("opal: Old firmware detected, OPAL handles HMIs.\n"); + pr_info("Old firmware detected, OPAL handles HMIs.\n"); opal_register_exception_handler( OPAL_HYPERVISOR_MAINTENANCE_HANDLER, 0, glue); @@ -667,7 +667,13 @@ static void __init opal_dump_region_init(void) /* Register kernel log buffer */ addr = log_buf_addr_get(); + if (addr == NULL) + return; + size = log_buf_len_get(); + if (size == 0) + return; + rc = opal_register_dump_region(OPAL_DUMP_REGION_LOG_BUF, __pa(addr), size); /* Don't warn if this is just an older OPAL that doesn't @@ -695,15 +701,54 @@ static void opal_i2c_create_devs(void) of_platform_device_create(np, NULL, NULL); } +static void __init opal_irq_init(struct device_node *dn) +{ + const __be32 *irqs; + int i, irqlen; + + /* Get interrupt property */ + irqs = of_get_property(opal_node, "opal-interrupts", &irqlen); + opal_irq_count = irqs ? (irqlen / 4) : 0; + pr_debug("Found %d interrupts reserved for OPAL\n", opal_irq_count); + if (!opal_irq_count) + return; + + /* Install interrupt handlers */ + opal_irqs = kzalloc(opal_irq_count * sizeof(unsigned int), GFP_KERNEL); + for (i = 0; irqs && i < opal_irq_count; i++, irqs++) { + unsigned int irq, virq; + int rc; + + /* Get hardware and virtual IRQ */ + irq = be32_to_cpup(irqs); + virq = irq_create_mapping(NULL, irq); + if (virq == NO_IRQ) { + pr_warn("Failed to map irq 0x%x\n", irq); + continue; + } + + /* Install interrupt handler */ + rc = request_irq(virq, opal_interrupt, 0, "opal", NULL); + if (rc) { + irq_dispose_mapping(virq); + pr_warn("Error %d requesting irq %d (0x%x)\n", + rc, virq, irq); + continue; + } + + /* Cache IRQ */ + opal_irqs[i] = virq; + } +} + static int __init opal_init(void) { struct device_node *np, *consoles; - const __be32 *irqs; - int rc, i, irqlen; + int rc; opal_node = of_find_node_by_path("/ibm,opal"); if (!opal_node) { - pr_warn("opal: Node not found\n"); + pr_warn("Device node not found\n"); return -ENODEV; } @@ -725,24 +770,7 @@ static int __init opal_init(void) opal_i2c_create_devs(); /* Find all OPAL interrupts and request them */ - irqs = of_get_property(opal_node, "opal-interrupts", &irqlen); - pr_debug("opal: Found %d interrupts reserved for OPAL\n", - irqs ? (irqlen / 4) : 0); - opal_irq_count = irqlen / 4; - opal_irqs = kzalloc(opal_irq_count * sizeof(unsigned int), GFP_KERNEL); - for (i = 0; irqs && i < (irqlen / 4); i++, irqs++) { - unsigned int hwirq = be32_to_cpup(irqs); - unsigned int irq = irq_create_mapping(NULL, hwirq); - if (irq == NO_IRQ) { - pr_warning("opal: Failed to map irq 0x%x\n", hwirq); - continue; - } - rc = request_irq(irq, opal_interrupt, 0, "opal", NULL); - if (rc) - pr_warning("opal: Error %d requesting irq %d" - " (0x%x)\n", rc, irq, hwirq); - opal_irqs[i] = irq; - } + opal_irq_init(opal_node); /* Create "opal" kobject under /sys/firmware */ rc = opal_sysfs_init(); diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index fac88ed8a915..6c9ff2b95119 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -75,6 +75,28 @@ static void pe_level_printk(const struct pnv_ioda_pe *pe, const char *level, #define pe_info(pe, fmt, ...) \ pe_level_printk(pe, KERN_INFO, fmt, ##__VA_ARGS__) +static bool pnv_iommu_bypass_disabled __read_mostly; + +static int __init iommu_setup(char *str) +{ + if (!str) + return -EINVAL; + + while (*str) { + if (!strncmp(str, "nobypass", 8)) { + pnv_iommu_bypass_disabled = true; + pr_info("PowerNV: IOMMU bypass window disabled.\n"); + break; + } + str += strcspn(str, ","); + if (*str == ',') + str++; + } + + return 0; +} +early_param("iommu", iommu_setup); + /* * stdcix is only supposed to be used in hypervisor real mode as per * the architecture spec @@ -357,6 +379,9 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb) phb->ioda.m64_segsize = phb->ioda.m64_size / phb->ioda.total_pe; phb->ioda.m64_base = pci_addr; + pr_info(" MEM64 0x%016llx..0x%016llx -> 0x%016llx\n", + res->start, res->end, pci_addr); + /* Use last M64 BAR to cover M64 window */ phb->ioda.m64_bar_idx = 15; phb->init_m64 = pnv_ioda2_init_m64; @@ -1348,7 +1373,9 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb, pnv_ioda_setup_bus_dma(pe, pe->pbus, true); /* Also create a bypass window */ - pnv_pci_ioda2_setup_bypass_pe(phb, pe); + if (!pnv_iommu_bypass_disabled) + pnv_pci_ioda2_setup_bypass_pe(phb, pe); + return; fail: if (pe->tce32_seg >= 0) @@ -1460,15 +1487,15 @@ static void set_msi_irq_chip(struct pnv_phb *phb, unsigned int virq) #ifdef CONFIG_CXL_BASE -struct device_node *pnv_pci_to_phb_node(struct pci_dev *dev) +struct device_node *pnv_pci_get_phb_node(struct pci_dev *dev) { struct pci_controller *hose = pci_bus_to_host(dev->bus); - return hose->dn; + return of_node_get(hose->dn); } -EXPORT_SYMBOL(pnv_pci_to_phb_node); +EXPORT_SYMBOL(pnv_pci_get_phb_node); -int pnv_phb_to_cxl(struct pci_dev *dev) +int pnv_phb_to_cxl_mode(struct pci_dev *dev, uint64_t mode) { struct pci_controller *hose = pci_bus_to_host(dev->bus); struct pnv_phb *phb = hose->private_data; @@ -1481,13 +1508,13 @@ int pnv_phb_to_cxl(struct pci_dev *dev) pe_info(pe, "Switching PHB to CXL\n"); - rc = opal_pci_set_phb_cxl_mode(phb->opal_id, 1, pe->pe_number); + rc = opal_pci_set_phb_cxl_mode(phb->opal_id, mode, pe->pe_number); if (rc) dev_err(&dev->dev, "opal_pci_set_phb_cxl_mode failed: %i\n", rc); return rc; } -EXPORT_SYMBOL(pnv_phb_to_cxl); +EXPORT_SYMBOL(pnv_phb_to_cxl_mode); /* Find PHB for cxl dev and allocate MSI hwirqs? * Returns the absolute hardware IRQ number diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 4945e87f12dc..e69142f4af08 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -781,35 +781,6 @@ static void pnv_p7ioc_rc_quirk(struct pci_dev *dev) } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_IBM, 0x3b9, pnv_p7ioc_rc_quirk); -static int pnv_pci_probe_mode(struct pci_bus *bus) -{ - struct pci_controller *hose = pci_bus_to_host(bus); - const __be64 *tstamp; - u64 now, target; - - - /* We hijack this as a way to ensure we have waited long - * enough since the reset was lifted on the PCI bus - */ - if (bus != hose->bus) - return PCI_PROBE_NORMAL; - tstamp = of_get_property(hose->dn, "reset-clear-timestamp", NULL); - if (!tstamp || !*tstamp) - return PCI_PROBE_NORMAL; - - now = mftb() / tb_ticks_per_usec; - target = (be64_to_cpup(tstamp) / tb_ticks_per_usec) - + PCI_RESET_DELAY_US; - - pr_devel("pci %04d: Reset target: 0x%llx now: 0x%llx\n", - hose->global_number, target, now); - - if (now < target) - msleep((target - now + 999) / 1000); - - return PCI_PROBE_NORMAL; -} - void __init pnv_pci_init(void) { struct device_node *np; @@ -856,7 +827,6 @@ void __init pnv_pci_init(void) ppc_md.tce_build_rm = pnv_tce_build_rm; ppc_md.tce_free_rm = pnv_tce_free_rm; ppc_md.tce_get = pnv_tce_get; - ppc_md.pci_probe_mode = pnv_pci_probe_mode; set_pci_dma_ops(&dma_iommu_ops); /* Configure MSIs */ diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index b700a329c31d..d2de7d5d7574 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -304,7 +304,7 @@ int pnv_save_sprs_for_winkle(void) * all cpus at boot. Get these reg values of current cpu and use the * same accross all cpus. */ - uint64_t lpcr_val = mfspr(SPRN_LPCR); + uint64_t lpcr_val = mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1; uint64_t hid0_val = mfspr(SPRN_HID0); uint64_t hid1_val = mfspr(SPRN_HID1); uint64_t hid4_val = mfspr(SPRN_HID4); diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 0c9f643d9e2a..b0f34663b1ae 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -223,6 +223,44 @@ void ps3_mm_vas_destroy(void) } } +static int ps3_mm_get_repository_highmem(struct mem_region *r) +{ + int result; + + /* Assume a single highmem region. */ + + result = ps3_repository_read_highmem_info(0, &r->base, &r->size); + + if (result) + goto zero_region; + + if (!r->base || !r->size) { + result = -1; + goto zero_region; + } + + r->offset = r->base - map.rm.size; + + DBG("%s:%d: Found high region in repository: %llxh %llxh\n", + __func__, __LINE__, r->base, r->size); + + return 0; + +zero_region: + DBG("%s:%d: No high region in repository.\n", __func__, __LINE__); + + r->size = r->base = r->offset = 0; + return result; +} + +static int ps3_mm_set_repository_highmem(const struct mem_region *r) +{ + /* Assume a single highmem region. */ + + return r ? ps3_repository_write_highmem_info(0, r->base, r->size) : + ps3_repository_write_highmem_info(0, 0, 0); +} + /** * ps3_mm_region_create - create a memory region in the vas * @r: pointer to a struct mem_region to accept initialized values @@ -291,36 +329,7 @@ static void ps3_mm_region_destroy(struct mem_region *r) r->size = r->base = r->offset = 0; map.total = map.rm.size; } -} - -static int ps3_mm_get_repository_highmem(struct mem_region *r) -{ - int result; - - /* Assume a single highmem region. */ - - result = ps3_repository_read_highmem_info(0, &r->base, &r->size); - - if (result) - goto zero_region; - - if (!r->base || !r->size) { - result = -1; - goto zero_region; - } - - r->offset = r->base - map.rm.size; - - DBG("%s:%d: Found high region in repository: %llxh %llxh\n", - __func__, __LINE__, r->base, r->size); - - return 0; - -zero_region: - DBG("%s:%d: No high region in repository.\n", __func__, __LINE__); - - r->size = r->base = r->offset = 0; - return result; + ps3_mm_set_repository_highmem(NULL); } /*============================================================================*/ @@ -1210,8 +1219,12 @@ void __init ps3_mm_init(void) /* Check if we got the highmem region from an earlier boot step */ - if (ps3_mm_get_repository_highmem(&map.r1)) - ps3_mm_region_create(&map.r1, map.total - map.rm.size); + if (ps3_mm_get_repository_highmem(&map.r1)) { + result = ps3_mm_region_create(&map.r1, map.total - map.rm.size); + + if (!result) + ps3_mm_set_repository_highmem(&map.r1); + } /* correct map.total for the real total amount of memory we use */ map.total = map.rm.size + map.r1.size; diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index d71329a8e325..1809cfc562ee 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -196,6 +196,7 @@ int ps3_repository_read_highmem_size(unsigned int region_index, int ps3_repository_read_highmem_info(unsigned int region_index, u64 *highmem_base, u64 *highmem_size); +#if defined (CONFIG_PS3_REPOSITORY_WRITE) int ps3_repository_write_highmem_region_count(unsigned int region_count); int ps3_repository_write_highmem_base(unsigned int region_index, u64 highmem_base); @@ -204,6 +205,18 @@ int ps3_repository_write_highmem_size(unsigned int region_index, int ps3_repository_write_highmem_info(unsigned int region_index, u64 highmem_base, u64 highmem_size); int ps3_repository_delete_highmem_info(unsigned int region_index); +#else +static inline int ps3_repository_write_highmem_region_count( + unsigned int region_count) {return 0;} +static inline int ps3_repository_write_highmem_base(unsigned int region_index, + u64 highmem_base) {return 0;} +static inline int ps3_repository_write_highmem_size(unsigned int region_index, + u64 highmem_size) {return 0;} +static inline int ps3_repository_write_highmem_info(unsigned int region_index, + u64 highmem_base, u64 highmem_size) {return 0;} +static inline int ps3_repository_delete_highmem_info(unsigned int region_index) + {return 0;} +#endif /* repository pme info */ diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 756b482f819a..a758a9c3bbba 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -34,6 +34,16 @@ config PPC_SPLPAR processors, that is, which share physical processors between two or more partitions. +config DTL + bool "Dispatch Trace Log" + depends on PPC_SPLPAR && DEBUG_FS + help + SPLPAR machines can log hypervisor preempt & dispatch events to a + kernel buffer. Saying Y here will enable logging these events, + which are accessible through a debugfs file. + + Say N if you are unsure. + config PSERIES_MSI bool depends on PCI_MSI && PPC_PSERIES && EEH @@ -123,13 +133,3 @@ config HV_PERF_CTRS systems. 24x7 is available on Power 8 systems. If unsure, select Y. - -config DTL - bool "Dispatch Trace Log" - depends on PPC_SPLPAR && DEBUG_FS - help - SPLPAR machines can log hypervisor preempt & dispatch events to a - kernel buffer. Saying Y here will enable logging these events, - which are accessible through a debugfs file. - - Say N if you are unsure. diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index f30cf4d136a4..62475440fd45 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -272,7 +272,7 @@ static int pseries_add_processor(struct device_node *np) */ printk(KERN_ERR "Cannot add cpu %s; this system configuration" " supports %d logical cpus.\n", np->full_name, - cpumask_weight(cpu_possible_mask)); + num_possible_cpus()); goto out_unlock; } diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index e7cb6d4a871a..90cf3dcbd9f2 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -316,34 +316,24 @@ void post_mobility_fixup(void) static ssize_t migrate_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count) { - struct rtas_args args; u64 streamid; int rc; + int vasi_rc = 0; rc = kstrtou64(buf, 0, &streamid); if (rc) return rc; - memset(&args, 0, sizeof(args)); - args.token = rtas_token("ibm,suspend-me"); - args.nargs = 2; - args.nret = 1; - - args.args[0] = streamid >> 32 ; - args.args[1] = streamid & 0xffffffff; - args.rets = &args.args[args.nargs]; - do { - args.rets[0] = 0; - rc = rtas_ibm_suspend_me(&args); - if (!rc && args.rets[0] == RTAS_NOT_SUSPENDABLE) + rc = rtas_ibm_suspend_me(streamid, &vasi_rc); + if (!rc && vasi_rc == RTAS_NOT_SUSPENDABLE) ssleep(1); - } while (!rc && args.rets[0] == RTAS_NOT_SUSPENDABLE); + } while (!rc && vasi_rc == RTAS_NOT_SUSPENDABLE); if (rc) return rc; - else if (args.rets[0]) - return args.rets[0]; + if (vasi_rc) + return vasi_rc; post_mobility_fixup(); return count; diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index c3b2a7e81ddb..02e4a1745516 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -89,6 +89,8 @@ static void handle_system_shutdown(char event_modifier) case EPOW_SHUTDOWN_ON_UPS: pr_emerg("Loss of power reported by firmware, system is " "running on UPS/battery"); + pr_emerg("Check RTAS error log for details"); + orderly_poweroff(true); break; case EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS: diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 6455c1eada1a..4b74c276e427 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -68,13 +68,10 @@ static int fsl_pcie_check_link(struct pci_controller *hose) u32 val = 0; if (hose->indirect_type & PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK) { - if (hose->ops->read == fsl_indirect_read_config) { - struct pci_bus bus; - bus.number = hose->first_busno; - bus.sysdata = hose; - bus.ops = hose->ops; - indirect_read_config(&bus, 0, PCIE_LTSSM, 4, &val); - } else + if (hose->ops->read == fsl_indirect_read_config) + __indirect_read_config(hose, hose->first_busno, 0, + PCIE_LTSSM, 4, &val); + else early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val); if (val < PCIE_LTSSM_L0) return 1; @@ -645,61 +642,21 @@ mapped: return pcie->cfg_type1 + offset; } -static int mpc83xx_pcie_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) -{ - void __iomem *cfg_addr; - - cfg_addr = mpc83xx_pcie_remap_cfg(bus, devfn, offset); - if (!cfg_addr) - return PCIBIOS_DEVICE_NOT_FOUND; - - switch (len) { - case 1: - *val = in_8(cfg_addr); - break; - case 2: - *val = in_le16(cfg_addr); - break; - default: - *val = in_le32(cfg_addr); - break; - } - - return PCIBIOS_SUCCESSFUL; -} - static int mpc83xx_pcie_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { struct pci_controller *hose = pci_bus_to_host(bus); - void __iomem *cfg_addr; - - cfg_addr = mpc83xx_pcie_remap_cfg(bus, devfn, offset); - if (!cfg_addr) - return PCIBIOS_DEVICE_NOT_FOUND; /* PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS */ if (offset == PCI_PRIMARY_BUS && bus->number == hose->first_busno) val &= 0xffffff00; - switch (len) { - case 1: - out_8(cfg_addr, val); - break; - case 2: - out_le16(cfg_addr, val); - break; - default: - out_le32(cfg_addr, val); - break; - } - - return PCIBIOS_SUCCESSFUL; + return pci_generic_config_write(bus, devfn, offset, len, val); } static struct pci_ops mpc83xx_pcie_ops = { - .read = mpc83xx_pcie_read_config, + .map_bus = mpc83xx_pcie_remap_cfg, + .read = pci_generic_config_read, .write = mpc83xx_pcie_write_config, }; diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c index 1f6c570d66d4..692de9dbc680 100644 --- a/arch/powerpc/sysdev/indirect_pci.c +++ b/arch/powerpc/sysdev/indirect_pci.c @@ -20,31 +20,31 @@ #include #include -int indirect_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) +int __indirect_read_config(struct pci_controller *hose, + unsigned char bus_number, unsigned int devfn, + int offset, int len, u32 *val) { - struct pci_controller *hose = pci_bus_to_host(bus); volatile void __iomem *cfg_data; u8 cfg_type = 0; u32 bus_no, reg; if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) { - if (bus->number != hose->first_busno) + if (bus_number != hose->first_busno) return PCIBIOS_DEVICE_NOT_FOUND; if (devfn != 0) return PCIBIOS_DEVICE_NOT_FOUND; } if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) + if (ppc_md.pci_exclude_device(hose, bus_number, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE) - if (bus->number != hose->first_busno) + if (bus_number != hose->first_busno) cfg_type = 1; - bus_no = (bus->number == hose->first_busno) ? - hose->self_busno : bus->number; + bus_no = (bus_number == hose->first_busno) ? + hose->self_busno : bus_number; if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG) reg = ((offset & 0xf00) << 16) | (offset & 0xfc); @@ -77,6 +77,15 @@ int indirect_read_config(struct pci_bus *bus, unsigned int devfn, return PCIBIOS_SUCCESSFUL; } +int indirect_read_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 *val) +{ + struct pci_controller *hose = pci_bus_to_host(bus); + + return __indirect_read_config(hose, bus->number, devfn, offset, len, + val); +} + int indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index c4648ad5c1f3..bbfbbf2025fd 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1929,7 +1929,7 @@ int __init smp_mpic_probe(void) DBG("smp_mpic_probe()...\n"); - nr_cpus = cpumask_weight(cpu_possible_mask); + nr_cpus = num_possible_cpus(); DBG("nr_cpus: %d\n", nr_cpus); diff --git a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c index ed9970ff8d94..f366d2d4c079 100644 --- a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c +++ b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c @@ -145,7 +145,7 @@ static int hsta_msi_probe(struct platform_device *pdev) ppc4xx_hsta_msi.address = mem->start; ppc4xx_hsta_msi.data = ioremap(mem->start, resource_size(mem)); ppc4xx_hsta_msi.irq_count = irq_count; - if (IS_ERR(ppc4xx_hsta_msi.data)) { + if (!ppc4xx_hsta_msi.data) { dev_err(dev, "Unable to map memory\n"); return -ENOMEM; } diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index 1f29cee8da7b..c2518cdb7ddb 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c @@ -497,7 +497,7 @@ int qe_upload_firmware(const struct qe_firmware *firmware) * saved microcode information and put in the new. */ memset(&qe_firmware_info, 0, sizeof(qe_firmware_info)); - strcpy(qe_firmware_info.id, firmware->id); + strlcpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id)); qe_firmware_info.extended_modes = firmware->extended_modes; memcpy(qe_firmware_info.vtraps, firmware->vtraps, sizeof(firmware->vtraps)); @@ -583,8 +583,8 @@ struct qe_firmware_info *qe_get_firmware_info(void) /* Copy the data into qe_firmware_info*/ sprop = of_get_property(fw, "id", NULL); if (sprop) - strncpy(qe_firmware_info.id, sprop, - sizeof(qe_firmware_info.id) - 1); + strlcpy(qe_firmware_info.id, sprop, + sizeof(qe_firmware_info.id)); prop = of_find_property(fw, "extended-modes", NULL); if (prop && (prop->length == sizeof(u64))) { diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index 365249cd346b..125743b58c70 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -148,7 +148,7 @@ int __init xics_smp_probe(void) /* Register all the IPIs */ xics_request_ipi(); - return cpumask_weight(cpu_possible_mask); + return num_possible_cpus(); } #endif /* CONFIG_SMP */ diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 5b150f0c5df9..e599259d84fc 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -183,14 +184,6 @@ extern void xmon_leave(void); #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) #endif -#define isxdigit(c) (('0' <= (c) && (c) <= '9') \ - || ('a' <= (c) && (c) <= 'f') \ - || ('A' <= (c) && (c) <= 'F')) -#define isalnum(c) (('0' <= (c) && (c) <= '9') \ - || ('a' <= (c) && (c) <= 'z') \ - || ('A' <= (c) && (c) <= 'Z')) -#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0) - static char *help_string = "\ Commands:\n\ b show breakpoints\n\ @@ -337,6 +330,7 @@ static inline void disable_surveillance(void) args.token = rtas_token("set-indicator"); if (args.token == RTAS_UNKNOWN_SERVICE) return; + args.token = cpu_to_be32(args.token); args.nargs = cpu_to_be32(3); args.nret = cpu_to_be32(1); args.rets = &args.args[3]; @@ -2164,9 +2158,6 @@ static void dump_pacas(void) } #endif -#define isxdigit(c) (('0' <= (c) && (c) <= '9') \ - || ('a' <= (c) && (c) <= 'f') \ - || ('A' <= (c) && (c) <= 'F')) static void dump(void) { @@ -2569,7 +2560,7 @@ scanhex(unsigned long *vp) int i; for (i=0; i<63; i++) { c = inchar(); - if (isspace(c)) { + if (isspace(c) || c == '\0') { termch = c; break; } diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 68b68d755fdf..373cd5badf1c 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -66,6 +66,7 @@ config S390 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS select ARCH_HAS_GCOV_PROFILE_ALL + select ARCH_HAS_SG_CHAIN select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_INLINE_READ_LOCK select ARCH_INLINE_READ_LOCK_BH @@ -116,7 +117,6 @@ config S390 select HAVE_BPF_JIT if 64BIT && PACK_STACK select HAVE_CMPXCHG_DOUBLE select HAVE_CMPXCHG_LOCAL - select HAVE_C_RECORDMCOUNT select HAVE_DEBUG_KMEMLEAK select HAVE_DYNAMIC_FTRACE if 64BIT select HAVE_DYNAMIC_FTRACE_WITH_REGS if 64BIT @@ -151,7 +151,6 @@ config S390 select TTY select VIRT_CPU_ACCOUNTING select VIRT_TO_BUS - select ARCH_HAS_SG_CHAIN config SCHED_OMIT_FRAME_POINTER def_bool y @@ -185,6 +184,10 @@ config HAVE_MARCH_ZEC12_FEATURES def_bool n select HAVE_MARCH_Z196_FEATURES +config HAVE_MARCH_Z13_FEATURES + def_bool n + select HAVE_MARCH_ZEC12_FEATURES + choice prompt "Processor type" default MARCH_G5 @@ -244,6 +247,14 @@ config MARCH_ZEC12 2827 series). The kernel will be slightly faster but will not work on older machines. +config MARCH_Z13 + bool "IBM z13" + select HAVE_MARCH_Z13_FEATURES if 64BIT + help + Select this to enable optimizations for IBM z13 (2964 series). + The kernel will be slightly faster but will not work on older + machines. + endchoice config MARCH_G5_TUNE @@ -267,6 +278,9 @@ config MARCH_Z196_TUNE config MARCH_ZEC12_TUNE def_bool TUNE_ZEC12 || MARCH_ZEC12 && TUNE_DEFAULT +config MARCH_Z13_TUNE + def_bool TUNE_Z13 || MARCH_Z13 && TUNE_DEFAULT + choice prompt "Tune code generation" default TUNE_DEFAULT @@ -305,6 +319,9 @@ config TUNE_Z196 config TUNE_ZEC12 bool "IBM zBC12 and zEC12" +config TUNE_Z13 + bool "IBM z13" + endchoice config 64BIT @@ -356,14 +373,14 @@ config SMP Even if you don't know what to do here, say Y. config NR_CPUS - int "Maximum number of CPUs (2-256)" - range 2 256 + int "Maximum number of CPUs (2-512)" + range 2 512 depends on SMP default "32" if !64BIT default "64" if 64BIT help This allows you to specify the maximum number of CPUs which this - kernel will support. The maximum supported value is 256 and the + kernel will support. The maximum supported value is 512 and the minimum value which makes sense is 2. This is purely to save memory - each supported CPU adds @@ -378,17 +395,26 @@ config HOTPLUG_CPU can be controlled through /sys/devices/system/cpu/cpu#. Say N if you want to disable CPU hotplug. +config SCHED_SMT + def_bool n + config SCHED_MC def_bool n config SCHED_BOOK + def_bool n + +config SCHED_TOPOLOGY def_bool y - prompt "Book scheduler support" + prompt "Topology scheduler support" depends on SMP + select SCHED_SMT select SCHED_MC + select SCHED_BOOK help - Book scheduler support improves the CPU scheduler's decision making - when dealing with machines that have several books. + Topology scheduler support improves the CPU scheduler's decision + making when dealing with machines that have multi-threading, + multiple cores or multiple books. source kernel/Kconfig.preempt diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 878e67973151..acb6859c6a95 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -42,6 +42,7 @@ mflags-$(CONFIG_MARCH_Z9_109) := -march=z9-109 mflags-$(CONFIG_MARCH_Z10) := -march=z10 mflags-$(CONFIG_MARCH_Z196) := -march=z196 mflags-$(CONFIG_MARCH_ZEC12) := -march=zEC12 +mflags-$(CONFIG_MARCH_Z13) := -march=z13 aflags-y += $(mflags-y) cflags-y += $(mflags-y) @@ -53,6 +54,7 @@ cflags-$(CONFIG_MARCH_Z9_109_TUNE) += -mtune=z9-109 cflags-$(CONFIG_MARCH_Z10_TUNE) += -mtune=z10 cflags-$(CONFIG_MARCH_Z196_TUNE) += -mtune=z196 cflags-$(CONFIG_MARCH_ZEC12_TUNE) += -mtune=zEC12 +cflags-$(CONFIG_MARCH_Z13_TUNE) += -mtune=z13 #KBUILD_IMAGE is necessary for make rpm KBUILD_IMAGE :=arch/s390/boot/image @@ -85,6 +87,16 @@ ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y) cflags-$(CONFIG_WARN_DYNAMIC_STACK) += -mwarn-dynamicstack endif +ifdef CONFIG_FUNCTION_TRACER +# make use of hotpatch feature if the compiler supports it +cc_hotpatch := -mhotpatch=0,3 +ifeq ($(call cc-option-yn,$(cc_hotpatch)),y) +CC_FLAGS_FTRACE := $(cc_hotpatch) +KBUILD_AFLAGS += -DCC_USING_HOTPATCH +KBUILD_CFLAGS += -DCC_USING_HOTPATCH +endif +endif + KBUILD_CFLAGS += -mbackchain -msoft-float $(cflags-y) KBUILD_CFLAGS += -pipe -fno-strength-reduce -Wno-sign-compare KBUILD_AFLAGS += $(aflags-y) diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c index 57cbaff1f397..42506b371b74 100644 --- a/arch/s390/boot/compressed/misc.c +++ b/arch/s390/boot/compressed/misc.c @@ -8,6 +8,7 @@ #include #include +#include #include #include "sizes.h" @@ -63,8 +64,6 @@ static unsigned long free_mem_end_ptr; #include "../../../../lib/decompress_unxz.c" #endif -extern _sclp_print_early(const char *); - static int puts(const char *s) { _sclp_print_early(s); diff --git a/arch/s390/configs/default_defconfig b/arch/s390/configs/default_defconfig index 9432d0f202ef..64707750c780 100644 --- a/arch/s390/configs/default_defconfig +++ b/arch/s390/configs/default_defconfig @@ -555,7 +555,6 @@ CONFIG_DEBUG_OBJECTS_RCU_HEAD=y CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y CONFIG_SLUB_DEBUG_ON=y CONFIG_SLUB_STATS=y -CONFIG_DEBUG_KMEMLEAK=y CONFIG_DEBUG_STACK_USAGE=y CONFIG_DEBUG_VM=y CONFIG_DEBUG_VM_RB=y @@ -563,6 +562,7 @@ CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m CONFIG_DEBUG_PER_CPU_MAPS=y CONFIG_DEBUG_SHIRQ=y CONFIG_DETECT_HUNG_TASK=y +CONFIG_PANIC_ON_OOPS=y CONFIG_TIMER_STATS=y CONFIG_DEBUG_RT_MUTEXES=y CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y diff --git a/arch/s390/configs/gcov_defconfig b/arch/s390/configs/gcov_defconfig index 219dca6ea926..5c3097272cd8 100644 --- a/arch/s390/configs/gcov_defconfig +++ b/arch/s390/configs/gcov_defconfig @@ -540,6 +540,7 @@ CONFIG_UNUSED_SYMBOLS=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m +CONFIG_PANIC_ON_OOPS=y CONFIG_TIMER_STATS=y CONFIG_RCU_TORTURE_TEST=m CONFIG_RCU_CPU_STALL_TIMEOUT=60 diff --git a/arch/s390/configs/performance_defconfig b/arch/s390/configs/performance_defconfig index 822c2f2e0c25..bda70f1ffd2c 100644 --- a/arch/s390/configs/performance_defconfig +++ b/arch/s390/configs/performance_defconfig @@ -537,6 +537,7 @@ CONFIG_FRAME_WARN=1024 CONFIG_UNUSED_SYMBOLS=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y +CONFIG_PANIC_ON_OOPS=y CONFIG_TIMER_STATS=y CONFIG_RCU_TORTURE_TEST=m CONFIG_RCU_CPU_STALL_TIMEOUT=60 diff --git a/arch/s390/configs/zfcpdump_defconfig b/arch/s390/configs/zfcpdump_defconfig index 9d63051ebec4..1b0184a0f7f2 100644 --- a/arch/s390/configs/zfcpdump_defconfig +++ b/arch/s390/configs/zfcpdump_defconfig @@ -71,6 +71,7 @@ CONFIG_PRINTK_TIME=y CONFIG_DEBUG_INFO=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y +CONFIG_PANIC_ON_OOPS=y # CONFIG_SCHED_DEBUG is not set CONFIG_RCU_CPU_STALL_TIMEOUT=60 # CONFIG_FTRACE is not set diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 1f272b24fc0b..5566ce80abdb 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -134,7 +134,7 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { - const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); if (unlikely(need_fallback(sctx->key_len))) { crypto_cipher_encrypt_one(sctx->fallback.cip, out, in); @@ -159,7 +159,7 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { - const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); if (unlikely(need_fallback(sctx->key_len))) { crypto_cipher_decrypt_one(sctx->fallback.cip, out, in); diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 785c5f24d6f9..83ef702d2403 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -14,7 +14,6 @@ CONFIG_IKCONFIG_PROC=y CONFIG_CGROUPS=y CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y -CONFIG_RESOURCE_COUNTERS=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_CGROUP_SCHED=y @@ -22,12 +21,8 @@ CONFIG_RT_GROUP_SCHED=y CONFIG_BLK_CGROUP=y CONFIG_NAMESPACES=y CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_RD_XZ=y -CONFIG_RD_LZO=y -CONFIG_RD_LZ4=y CONFIG_EXPERT=y +CONFIG_BPF_SYSCALL=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_OPROFILE=y diff --git a/arch/s390/hypfs/Makefile b/arch/s390/hypfs/Makefile index 06f8d95a16cd..2ee25ba252d6 100644 --- a/arch/s390/hypfs/Makefile +++ b/arch/s390/hypfs/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o hypfs_sprp.o +s390_hypfs-objs += hypfs_diag0c.o diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h index b34b5ab90a31..eecde500ed49 100644 --- a/arch/s390/hypfs/hypfs.h +++ b/arch/s390/hypfs/hypfs.h @@ -37,6 +37,10 @@ extern int hypfs_vm_init(void); extern void hypfs_vm_exit(void); extern int hypfs_vm_create_files(struct dentry *root); +/* VM diagnose 0c */ +int hypfs_diag0c_init(void); +void hypfs_diag0c_exit(void); + /* Set Partition-Resource Parameter */ int hypfs_sprp_init(void); void hypfs_sprp_exit(void); @@ -49,7 +53,6 @@ struct hypfs_dbfs_data { void *buf_free_ptr; size_t size; struct hypfs_dbfs_file *dbfs_file; - struct kref kref; }; struct hypfs_dbfs_file { @@ -61,8 +64,6 @@ struct hypfs_dbfs_file { unsigned long); /* Private data for hypfs_dbfs.c */ - struct hypfs_dbfs_data *data; - struct delayed_work data_free_work; struct mutex lock; struct dentry *dentry; }; diff --git a/arch/s390/hypfs/hypfs_dbfs.c b/arch/s390/hypfs/hypfs_dbfs.c index 47fe1055c714..752f6df3e697 100644 --- a/arch/s390/hypfs/hypfs_dbfs.c +++ b/arch/s390/hypfs/hypfs_dbfs.c @@ -17,33 +17,16 @@ static struct hypfs_dbfs_data *hypfs_dbfs_data_alloc(struct hypfs_dbfs_file *f) data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return NULL; - kref_init(&data->kref); data->dbfs_file = f; return data; } -static void hypfs_dbfs_data_free(struct kref *kref) +static void hypfs_dbfs_data_free(struct hypfs_dbfs_data *data) { - struct hypfs_dbfs_data *data; - - data = container_of(kref, struct hypfs_dbfs_data, kref); data->dbfs_file->data_free(data->buf_free_ptr); kfree(data); } -static void data_free_delayed(struct work_struct *work) -{ - struct hypfs_dbfs_data *data; - struct hypfs_dbfs_file *df; - - df = container_of(work, struct hypfs_dbfs_file, data_free_work.work); - mutex_lock(&df->lock); - data = df->data; - df->data = NULL; - mutex_unlock(&df->lock); - kref_put(&data->kref, hypfs_dbfs_data_free); -} - static ssize_t dbfs_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { @@ -56,28 +39,21 @@ static ssize_t dbfs_read(struct file *file, char __user *buf, df = file_inode(file)->i_private; mutex_lock(&df->lock); - if (!df->data) { - data = hypfs_dbfs_data_alloc(df); - if (!data) { - mutex_unlock(&df->lock); - return -ENOMEM; - } - rc = df->data_create(&data->buf, &data->buf_free_ptr, - &data->size); - if (rc) { - mutex_unlock(&df->lock); - kfree(data); - return rc; - } - df->data = data; - schedule_delayed_work(&df->data_free_work, HZ); + data = hypfs_dbfs_data_alloc(df); + if (!data) { + mutex_unlock(&df->lock); + return -ENOMEM; + } + rc = df->data_create(&data->buf, &data->buf_free_ptr, &data->size); + if (rc) { + mutex_unlock(&df->lock); + kfree(data); + return rc; } - data = df->data; - kref_get(&data->kref); mutex_unlock(&df->lock); rc = simple_read_from_buffer(buf, size, ppos, data->buf, data->size); - kref_put(&data->kref, hypfs_dbfs_data_free); + hypfs_dbfs_data_free(data); return rc; } @@ -108,7 +84,6 @@ int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df) if (IS_ERR(df->dentry)) return PTR_ERR(df->dentry); mutex_init(&df->lock); - INIT_DELAYED_WORK(&df->data_free_work, data_free_delayed); return 0; } diff --git a/arch/s390/hypfs/hypfs_diag0c.c b/arch/s390/hypfs/hypfs_diag0c.c new file mode 100644 index 000000000000..d4c0d3717543 --- /dev/null +++ b/arch/s390/hypfs/hypfs_diag0c.c @@ -0,0 +1,139 @@ +/* + * Hypervisor filesystem for Linux on s390 + * + * Diag 0C implementation + * + * Copyright IBM Corp. 2014 + */ + +#include +#include +#include +#include "hypfs.h" + +#define DBFS_D0C_HDR_VERSION 0 + +/* + * Execute diagnose 0c in 31 bit mode + */ +static void diag0c(struct hypfs_diag0c_entry *entry) +{ + asm volatile ( +#ifdef CONFIG_64BIT + " sam31\n" + " diag %0,%0,0x0c\n" + " sam64\n" +#else + " diag %0,%0,0x0c\n" +#endif + : /* no output register */ + : "a" (entry) + : "memory"); +} + +/* + * Get hypfs_diag0c_entry from CPU vector and store diag0c data + */ +static void diag0c_fn(void *data) +{ + diag0c(((void **) data)[smp_processor_id()]); +} + +/* + * Allocate buffer and store diag 0c data + */ +static void *diag0c_store(unsigned int *count) +{ + struct hypfs_diag0c_data *diag0c_data; + unsigned int cpu_count, cpu, i; + void **cpu_vec; + + get_online_cpus(); + cpu_count = num_online_cpus(); + cpu_vec = kmalloc(sizeof(*cpu_vec) * num_possible_cpus(), GFP_KERNEL); + if (!cpu_vec) + goto fail_put_online_cpus; + /* Note: Diag 0c needs 8 byte alignment and real storage */ + diag0c_data = kzalloc(sizeof(struct hypfs_diag0c_hdr) + + cpu_count * sizeof(struct hypfs_diag0c_entry), + GFP_KERNEL | GFP_DMA); + if (!diag0c_data) + goto fail_kfree_cpu_vec; + i = 0; + /* Fill CPU vector for each online CPU */ + for_each_online_cpu(cpu) { + diag0c_data->entry[i].cpu = cpu; + cpu_vec[cpu] = &diag0c_data->entry[i++]; + } + /* Collect data all CPUs */ + on_each_cpu(diag0c_fn, cpu_vec, 1); + *count = cpu_count; + kfree(cpu_vec); + put_online_cpus(); + return diag0c_data; + +fail_kfree_cpu_vec: + kfree(cpu_vec); +fail_put_online_cpus: + put_online_cpus(); + return ERR_PTR(-ENOMEM); +} + +/* + * Hypfs DBFS callback: Free diag 0c data + */ +static void dbfs_diag0c_free(const void *data) +{ + kfree(data); +} + +/* + * Hypfs DBFS callback: Create diag 0c data + */ +static int dbfs_diag0c_create(void **data, void **data_free_ptr, size_t *size) +{ + struct hypfs_diag0c_data *diag0c_data; + unsigned int count; + + diag0c_data = diag0c_store(&count); + if (IS_ERR(diag0c_data)) + return PTR_ERR(diag0c_data); + memset(&diag0c_data->hdr, 0, sizeof(diag0c_data->hdr)); + get_tod_clock_ext(diag0c_data->hdr.tod_ext); + diag0c_data->hdr.len = count * sizeof(struct hypfs_diag0c_entry); + diag0c_data->hdr.version = DBFS_D0C_HDR_VERSION; + diag0c_data->hdr.count = count; + *data = diag0c_data; + *data_free_ptr = diag0c_data; + *size = diag0c_data->hdr.len + sizeof(struct hypfs_diag0c_hdr); + return 0; +} + +/* + * Hypfs DBFS file structure + */ +static struct hypfs_dbfs_file dbfs_file_0c = { + .name = "diag_0c", + .data_create = dbfs_diag0c_create, + .data_free = dbfs_diag0c_free, +}; + +/* + * Initialize diag 0c interface for z/VM + */ +int __init hypfs_diag0c_init(void) +{ + if (!MACHINE_IS_VM) + return 0; + return hypfs_dbfs_create_file(&dbfs_file_0c); +} + +/* + * Shutdown diag 0c interface for z/VM + */ +void hypfs_diag0c_exit(void) +{ + if (!MACHINE_IS_VM) + return; + hypfs_dbfs_remove_file(&dbfs_file_0c); +} diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index c952b981e4f2..4c8008dd938e 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -482,10 +482,14 @@ static int __init hypfs_init(void) rc = -ENODATA; goto fail_hypfs_vm_exit; } + if (hypfs_diag0c_init()) { + rc = -ENODATA; + goto fail_hypfs_sprp_exit; + } s390_kobj = kobject_create_and_add("s390", hypervisor_kobj); if (!s390_kobj) { rc = -ENOMEM; - goto fail_hypfs_sprp_exit; + goto fail_hypfs_diag0c_exit; } rc = register_filesystem(&hypfs_type); if (rc) @@ -494,6 +498,8 @@ static int __init hypfs_init(void) fail_filesystem: kobject_put(s390_kobj); +fail_hypfs_diag0c_exit: + hypfs_diag0c_exit(); fail_hypfs_sprp_exit: hypfs_sprp_exit(); fail_hypfs_vm_exit: @@ -510,6 +516,7 @@ static void __exit hypfs_exit(void) { unregister_filesystem(&hypfs_type); kobject_put(s390_kobj); + hypfs_diag0c_exit(); hypfs_sprp_exit(); hypfs_vm_exit(); hypfs_diag_exit(); diff --git a/arch/s390/include/asm/cacheflush.h b/arch/s390/include/asm/cacheflush.h index 3e20383d0921..58fae7d098cf 100644 --- a/arch/s390/include/asm/cacheflush.h +++ b/arch/s390/include/asm/cacheflush.h @@ -4,10 +4,6 @@ /* Caches aren't brain-dead on the s390. */ #include -#ifdef CONFIG_DEBUG_PAGEALLOC -void kernel_map_pages(struct page *page, int numpages, int enable); -#endif - 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); diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h index cb700d54bd83..5243a8679a1d 100644 --- a/arch/s390/include/asm/cpu_mf.h +++ b/arch/s390/include/asm/cpu_mf.h @@ -189,6 +189,20 @@ static inline int ecctr(u64 ctr, u64 *val) return cc; } +/* Store CPU counter multiple for the MT utilization counter set */ +static inline int stcctm5(u64 num, u64 *val) +{ + typedef struct { u64 _[num]; } addrtype; + int cc; + + asm volatile ( + " .insn rsy,0xeb0000000017,%2,5,%1\n" + " ipm %0\n" + " srl %0,28\n" + : "=d" (cc), "=Q" (*(addrtype *) val) : "d" (num) : "cc"); + return cc; +} + /* Query sampling information */ static inline int qsi(struct hws_qsi_info_block *info) { diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index f6e43d39e3d8..c9df40b5c0ac 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h @@ -163,8 +163,8 @@ extern unsigned int vdso_enabled; the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ -extern unsigned long randomize_et_dyn(unsigned long base); -#define ELF_ET_DYN_BASE (randomize_et_dyn(STACK_TOP / 3 * 2)) +extern unsigned long randomize_et_dyn(void); +#define ELF_ET_DYN_BASE randomize_et_dyn() /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. */ @@ -209,7 +209,9 @@ do { \ } while (0) #endif /* CONFIG_COMPAT */ -#define STACK_RND_MASK 0x7ffUL +extern unsigned long mmap_rnd_mask; + +#define STACK_RND_MASK (mmap_rnd_mask) #define ARCH_DLINFO \ do { \ diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h index abb618f1ead2..836c56290499 100644 --- a/arch/s390/include/asm/ftrace.h +++ b/arch/s390/include/asm/ftrace.h @@ -3,8 +3,12 @@ #define ARCH_SUPPORTS_FTRACE_OPS 1 +#ifdef CC_USING_HOTPATCH +#define MCOUNT_INSN_SIZE 6 +#else #define MCOUNT_INSN_SIZE 24 #define MCOUNT_RETURN_FIXUP 18 +#endif #ifndef __ASSEMBLY__ @@ -37,17 +41,28 @@ struct ftrace_insn { static inline void ftrace_generate_nop_insn(struct ftrace_insn *insn) { #ifdef CONFIG_FUNCTION_TRACER +#ifdef CC_USING_HOTPATCH + /* brcl 0,0 */ + insn->opc = 0xc004; + insn->disp = 0; +#else /* jg .+24 */ insn->opc = 0xc0f4; insn->disp = MCOUNT_INSN_SIZE / 2; #endif +#endif } static inline int is_ftrace_nop(struct ftrace_insn *insn) { #ifdef CONFIG_FUNCTION_TRACER +#ifdef CC_USING_HOTPATCH + if (insn->disp == 0) + return 1; +#else if (insn->disp == MCOUNT_INSN_SIZE / 2) return 1; +#endif #endif return 0; } diff --git a/arch/s390/include/asm/jump_label.h b/arch/s390/include/asm/jump_label.h index 346b1c85ffb4..58642fd29c87 100644 --- a/arch/s390/include/asm/jump_label.h +++ b/arch/s390/include/asm/jump_label.h @@ -4,6 +4,7 @@ #include #define JUMP_LABEL_NOP_SIZE 6 +#define JUMP_LABEL_NOP_OFFSET 2 #ifdef CONFIG_64BIT #define ASM_PTR ".quad" @@ -13,9 +14,13 @@ #define ASM_ALIGN ".balign 4" #endif +/* + * We use a brcl 0,2 instruction for jump labels at compile time so it + * can be easily distinguished from a hotpatch generated instruction. + */ static __always_inline bool arch_static_branch(struct static_key *key) { - asm_volatile_goto("0: brcl 0,0\n" + asm_volatile_goto("0: brcl 0,"__stringify(JUMP_LABEL_NOP_OFFSET)"\n" ".pushsection __jump_table, \"aw\"\n" ASM_ALIGN "\n" ASM_PTR " 0b, %l[label], %0\n" diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 5e102422c9ab..fbb5ee3ae57c 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -99,7 +99,7 @@ extern unsigned long zero_page_mask; #endif /* CONFIG_64BIT */ #define PTRS_PER_PGD 2048 -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define pte_ERROR(e) \ printk("%s:%d: bad pte %p.\n", __FILE__, __LINE__, (void *) pte_val(e)) @@ -249,10 +249,10 @@ static inline int is_module_addr(void *addr) _PAGE_YOUNG) /* - * handle_pte_fault uses pte_present, pte_none and pte_file to find out the - * pte type WITHOUT holding the page table lock. The _PAGE_PRESENT bit - * is used to distinguish present from not-present ptes. It is changed only - * with the page table lock held. + * handle_pte_fault uses pte_present and pte_none to find out the pte type + * WITHOUT holding the page table lock. The _PAGE_PRESENT bit is used to + * distinguish present from not-present ptes. It is changed only with the page + * table lock held. * * The following table gives the different possible bit combinations for * the pte hardware and software bits in the last 12 bits of a pte: @@ -279,7 +279,6 @@ static inline int is_module_addr(void *addr) * * pte_present is true for the bit pattern .xx...xxxxx1, (pte & 0x001) == 0x001 * pte_none is true for the bit pattern .10...xxxx00, (pte & 0x603) == 0x400 - * pte_file is true for the bit pattern .11...xxxxx0, (pte & 0x601) == 0x600 * pte_swap is true for the bit pattern .10...xxxx10, (pte & 0x603) == 0x402 */ @@ -671,13 +670,6 @@ static inline int pte_swap(pte_t pte) == (_PAGE_INVALID | _PAGE_TYPE); } -static inline int pte_file(pte_t pte) -{ - /* Bit pattern: (pte & 0x601) == 0x600 */ - return (pte_val(pte) & (_PAGE_INVALID | _PAGE_PROTECT | _PAGE_PRESENT)) - == (_PAGE_INVALID | _PAGE_PROTECT); -} - static inline int pte_special(pte_t pte) { return (pte_val(pte) & _PAGE_SPECIAL); @@ -1756,19 +1748,6 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -#ifndef CONFIG_64BIT -# define PTE_FILE_MAX_BITS 26 -#else /* CONFIG_64BIT */ -# define PTE_FILE_MAX_BITS 59 -#endif /* CONFIG_64BIT */ - -#define pte_to_pgoff(__pte) \ - ((((__pte).pte >> 12) << 7) + (((__pte).pte >> 1) & 0x7f)) - -#define pgoff_to_pte(__off) \ - ((pte_t) { ((((__off) & 0x7f) << 1) + (((__off) >> 7) << 12)) \ - | _PAGE_INVALID | _PAGE_PROTECT }) - #endif /* !__ASSEMBLY__ */ #define kern_addr_valid(addr) (1) @@ -1779,6 +1758,10 @@ extern int s390_enable_sie(void); extern int s390_enable_skey(void); extern void s390_reset_cmma(struct mm_struct *mm); +/* s390 has a private copy of get unmapped area to deal with cache synonyms */ +#define HAVE_ARCH_UNMAPPED_AREA +#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN + /* * No page table caches to initialise */ diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index bed05ea7ec27..e7cbbdcdee13 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -215,10 +215,7 @@ static inline unsigned short stap(void) /* * Give up the time slice of the virtual PU. */ -static inline void cpu_relax(void) -{ - barrier(); -} +void cpu_relax(void); #define cpu_relax_lowlatency() barrier() diff --git a/arch/s390/include/asm/reset.h b/arch/s390/include/asm/reset.h index 804578587a7a..72786067b300 100644 --- a/arch/s390/include/asm/reset.h +++ b/arch/s390/include/asm/reset.h @@ -15,5 +15,6 @@ struct reset_call { extern void register_reset_call(struct reset_call *reset); extern void unregister_reset_call(struct reset_call *reset); -extern void s390_reset_system(void (*func)(void *), void *data); +extern void s390_reset_system(void (*fn_pre)(void), + void (*fn_post)(void *), void *data); #endif /* _ASM_S390_RESET_H */ diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 1aba89b53cb9..edb453cfc2c6 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -27,7 +27,7 @@ struct sclp_ipl_info { }; struct sclp_cpu_entry { - u8 address; + u8 core_id; u8 reserved0[2]; u8 : 3; u8 siif : 1; @@ -51,6 +51,9 @@ int sclp_cpu_deconfigure(u8 cpu); unsigned long long sclp_get_rnmax(void); unsigned long long sclp_get_rzm(void); unsigned int sclp_get_max_cpu(void); +unsigned int sclp_get_mtid(u8 cpu_type); +unsigned int sclp_get_mtid_max(void); +unsigned int sclp_get_mtid_prev(void); int sclp_sdias_blk_count(void); int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); int sclp_chp_configure(struct chp_id chpid); @@ -68,4 +71,6 @@ void sclp_early_detect(void); int sclp_has_siif(void); unsigned int sclp_get_ibc(void); +long _sclp_print_early(const char *); + #endif /* _ASM_S390_SCLP_H */ diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 7736fdd72595..b8d1e54b4733 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -57,6 +57,7 @@ extern void detect_memory_memblock(void); #define MACHINE_FLAG_TE (1UL << 15) #define MACHINE_FLAG_TLB_LC (1UL << 17) #define MACHINE_FLAG_VX (1UL << 18) +#define MACHINE_FLAG_CAD (1UL << 19) #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) @@ -80,6 +81,7 @@ extern void detect_memory_memblock(void); #define MACHINE_HAS_TE (0) #define MACHINE_HAS_TLB_LC (0) #define MACHINE_HAS_VX (0) +#define MACHINE_HAS_CAD (0) #else /* CONFIG_64BIT */ #define MACHINE_HAS_IEEE (1) #define MACHINE_HAS_CSP (1) @@ -93,6 +95,7 @@ extern void detect_memory_memblock(void); #define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE) #define MACHINE_HAS_TLB_LC (S390_lowcore.machine_flags & MACHINE_FLAG_TLB_LC) #define MACHINE_HAS_VX (S390_lowcore.machine_flags & MACHINE_FLAG_VX) +#define MACHINE_HAS_CAD (S390_lowcore.machine_flags & MACHINE_FLAG_CAD) #endif /* CONFIG_64BIT */ /* diff --git a/arch/s390/include/asm/sigp.h b/arch/s390/include/asm/sigp.h index fad4ae23ece0..ec60cf7fa0a2 100644 --- a/arch/s390/include/asm/sigp.h +++ b/arch/s390/include/asm/sigp.h @@ -16,6 +16,7 @@ #define SIGP_SET_ARCHITECTURE 18 #define SIGP_COND_EMERGENCY_SIGNAL 19 #define SIGP_SENSE_RUNNING 21 +#define SIGP_SET_MULTI_THREADING 22 #define SIGP_STORE_ADDITIONAL_STATUS 23 /* SIGP condition codes */ diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h index 762d4f88af5a..b3bd0282dd98 100644 --- a/arch/s390/include/asm/smp.h +++ b/arch/s390/include/asm/smp.h @@ -16,6 +16,8 @@ #define raw_smp_processor_id() (S390_lowcore.cpu_nr) extern struct mutex smp_cpu_state_mutex; +extern unsigned int smp_cpu_mt_shift; +extern unsigned int smp_cpu_mtid; extern int __cpu_up(unsigned int cpu, struct task_struct *tidle); @@ -35,6 +37,8 @@ extern void smp_fill_possible_mask(void); #else /* CONFIG_SMP */ +#define smp_cpu_mtid 0 + static inline void smp_call_ipl_cpu(void (*func)(void *), void *data) { func(data); diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h index f92428e459f8..73f12d21af4d 100644 --- a/arch/s390/include/asm/sysinfo.h +++ b/arch/s390/include/asm/sysinfo.h @@ -90,7 +90,11 @@ struct sysinfo_2_2_2 { unsigned short cpus_reserved; char name[8]; unsigned int caf; - char reserved_2[16]; + char reserved_2[8]; + unsigned char mt_installed; + unsigned char mt_general; + unsigned char mt_psmtid; + char reserved_3[5]; unsigned short cpus_dedicated; unsigned short cpus_shared; }; @@ -120,26 +124,28 @@ struct sysinfo_3_2_2 { extern int topology_max_mnest; -#define TOPOLOGY_CPU_BITS 64 +#define TOPOLOGY_CORE_BITS 64 #define TOPOLOGY_NR_MAG 6 -struct topology_cpu { - unsigned char reserved0[4]; +struct topology_core { + unsigned char nl; + unsigned char reserved0[3]; unsigned char :6; unsigned char pp:2; unsigned char reserved1; unsigned short origin; - unsigned long mask[TOPOLOGY_CPU_BITS / BITS_PER_LONG]; + unsigned long mask[TOPOLOGY_CORE_BITS / BITS_PER_LONG]; }; struct topology_container { - unsigned char reserved[7]; + unsigned char nl; + unsigned char reserved[6]; unsigned char id; }; union topology_entry { unsigned char nl; - struct topology_cpu cpu; + struct topology_core cpu; struct topology_container container; }; diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h index 56af53093d24..c4fbb9527c5c 100644 --- a/arch/s390/include/asm/topology.h +++ b/arch/s390/include/asm/topology.h @@ -9,9 +9,11 @@ struct cpu; #ifdef CONFIG_SCHED_BOOK struct cpu_topology_s390 { + unsigned short thread_id; unsigned short core_id; unsigned short socket_id; unsigned short book_id; + cpumask_t thread_mask; cpumask_t core_mask; cpumask_t book_mask; }; @@ -19,6 +21,8 @@ struct cpu_topology_s390 { extern struct cpu_topology_s390 cpu_topology[NR_CPUS]; #define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id) +#define topology_thread_id(cpu) (cpu_topology[cpu].thread_id) +#define topology_thread_cpumask(cpu) (&cpu_topology[cpu].thread_mask) #define topology_core_id(cpu) (cpu_topology[cpu].core_id) #define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_mask) #define topology_book_id(cpu) (cpu_topology[cpu].book_id) diff --git a/arch/s390/include/uapi/asm/hypfs.h b/arch/s390/include/uapi/asm/hypfs.h index 37998b449531..b3fe12d8dd87 100644 --- a/arch/s390/include/uapi/asm/hypfs.h +++ b/arch/s390/include/uapi/asm/hypfs.h @@ -1,16 +1,19 @@ /* - * IOCTL interface for hypfs + * Structures for hypfs interface * * Copyright IBM Corp. 2013 * * Author: Martin Schwidefsky */ -#ifndef _ASM_HYPFS_CTL_H -#define _ASM_HYPFS_CTL_H +#ifndef _ASM_HYPFS_H +#define _ASM_HYPFS_H #include +/* + * IOCTL for binary interface /sys/kernel/debug/diag_304 + */ struct hypfs_diag304 { __u32 args[2]; __u64 data; @@ -22,4 +25,30 @@ struct hypfs_diag304 { #define HYPFS_DIAG304 \ _IOWR(HYPFS_IOCTL_MAGIC, 0x20, struct hypfs_diag304) +/* + * Structures for binary interface /sys/kernel/debug/diag_0c + */ +struct hypfs_diag0c_hdr { + __u64 len; /* Length of diag0c buffer without header */ + __u16 version; /* Version of header */ + char reserved1[6]; /* Reserved */ + char tod_ext[16]; /* TOD clock for diag0c */ + __u64 count; /* Number of entries (CPUs) in diag0c array */ + char reserved2[24]; /* Reserved */ +}; + +struct hypfs_diag0c_entry { + char date[8]; /* MM/DD/YY in EBCDIC */ + char time[8]; /* HH:MM:SS in EBCDIC */ + __u64 virtcpu; /* Virtual time consumed by the virt CPU (us) */ + __u64 totalproc; /* Total of virtual and simulation time (us) */ + __u32 cpu; /* Linux logical CPU number */ + __u32 reserved; /* Align to 8 byte */ +}; + +struct hypfs_diag0c_data { + struct hypfs_diag0c_hdr hdr; /* 64 byte header */ + struct hypfs_diag0c_entry entry[]; /* diag0c entry array */ +}; + #endif diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 204c43a4c245..31fab2676fe9 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -4,8 +4,8 @@ ifdef CONFIG_FUNCTION_TRACER # Don't trace early setup code and tracing code -CFLAGS_REMOVE_early.o = -pg -CFLAGS_REMOVE_ftrace.o = -pg +CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE) +CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) endif # diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S index 797a823a2275..f74a53d339b0 100644 --- a/arch/s390/kernel/base.S +++ b/arch/s390/kernel/base.S @@ -97,7 +97,8 @@ ENTRY(diag308_reset) lg %r4,0(%r4) # Save PSW sturg %r4,%r3 # Use sturg, because of large pages lghi %r1,1 - diag %r1,%r1,0x308 + lghi %r0,0 + diag %r0,%r1,0x308 .Lrestart_part2: lhi %r0,0 # Load r0 with zero lhi %r1,2 # Use mode 2 = ESAME (dump) diff --git a/arch/s390/kernel/cache.c b/arch/s390/kernel/cache.c index c0b03c28d157..632fa06ea162 100644 --- a/arch/s390/kernel/cache.c +++ b/arch/s390/kernel/cache.c @@ -5,37 +5,11 @@ * Author(s): Heiko Carstens */ -#include #include -#include -#include -#include #include +#include #include -struct cache { - unsigned long size; - unsigned int line_size; - unsigned int associativity; - unsigned int nr_sets; - unsigned int level : 3; - unsigned int type : 2; - unsigned int private : 1; - struct list_head list; -}; - -struct cache_dir { - struct kobject *kobj; - struct cache_index_dir *index; -}; - -struct cache_index_dir { - struct kobject kobj; - int cpu; - struct cache *cache; - struct cache_index_dir *next; -}; - enum { CACHE_SCOPE_NOTEXISTS, CACHE_SCOPE_PRIVATE, @@ -44,10 +18,10 @@ enum { }; enum { - CACHE_TYPE_SEPARATE, - CACHE_TYPE_DATA, - CACHE_TYPE_INSTRUCTION, - CACHE_TYPE_UNIFIED, + CTYPE_SEPARATE, + CTYPE_DATA, + CTYPE_INSTRUCTION, + CTYPE_UNIFIED, }; enum { @@ -70,37 +44,60 @@ struct cache_info { }; #define CACHE_MAX_LEVEL 8 - union cache_topology { struct cache_info ci[CACHE_MAX_LEVEL]; unsigned long long raw; }; static const char * const cache_type_string[] = { - "Data", + "", "Instruction", + "Data", + "", "Unified", }; -static struct cache_dir *cache_dir_cpu[NR_CPUS]; -static LIST_HEAD(cache_list); +static const enum cache_type cache_type_map[] = { + [CTYPE_SEPARATE] = CACHE_TYPE_SEPARATE, + [CTYPE_DATA] = CACHE_TYPE_DATA, + [CTYPE_INSTRUCTION] = CACHE_TYPE_INST, + [CTYPE_UNIFIED] = CACHE_TYPE_UNIFIED, +}; void show_cacheinfo(struct seq_file *m) { - struct cache *cache; - int index = 0; + struct cpu_cacheinfo *this_cpu_ci; + struct cacheinfo *cache; + int idx; - list_for_each_entry(cache, &cache_list, list) { - seq_printf(m, "cache%-11d: ", index); + get_online_cpus(); + this_cpu_ci = get_cpu_cacheinfo(cpumask_any(cpu_online_mask)); + for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) { + cache = this_cpu_ci->info_list + idx; + seq_printf(m, "cache%-11d: ", idx); seq_printf(m, "level=%d ", cache->level); seq_printf(m, "type=%s ", cache_type_string[cache->type]); - seq_printf(m, "scope=%s ", cache->private ? "Private" : "Shared"); - seq_printf(m, "size=%luK ", cache->size >> 10); - seq_printf(m, "line_size=%u ", cache->line_size); - seq_printf(m, "associativity=%d", cache->associativity); + seq_printf(m, "scope=%s ", + cache->disable_sysfs ? "Shared" : "Private"); + seq_printf(m, "size=%dK ", cache->size >> 10); + seq_printf(m, "line_size=%u ", cache->coherency_line_size); + seq_printf(m, "associativity=%d", cache->ways_of_associativity); seq_puts(m, "\n"); - index++; } + put_online_cpus(); +} + +static inline enum cache_type get_cache_type(struct cache_info *ci, int level) +{ + if (level >= CACHE_MAX_LEVEL) + return CACHE_TYPE_NOCACHE; + + ci += level; + + if (ci->scope != CACHE_SCOPE_SHARED && ci->scope != CACHE_SCOPE_PRIVATE) + return CACHE_TYPE_NOCACHE; + + return cache_type_map[ci->type]; } static inline unsigned long ecag(int ai, int li, int ti) @@ -113,277 +110,79 @@ static inline unsigned long ecag(int ai, int li, int ti) return val; } -static int __init cache_add(int level, int private, int type) +static void ci_leaf_init(struct cacheinfo *this_leaf, int private, + enum cache_type type, unsigned int level) { - struct cache *cache; - int ti; + int ti, num_sets; + int cpu = smp_processor_id(); - cache = kzalloc(sizeof(*cache), GFP_KERNEL); - if (!cache) - return -ENOMEM; - if (type == CACHE_TYPE_INSTRUCTION) + if (type == CACHE_TYPE_INST) ti = CACHE_TI_INSTRUCTION; else ti = CACHE_TI_UNIFIED; - cache->size = ecag(EXTRACT_SIZE, level, ti); - cache->line_size = ecag(EXTRACT_LINE_SIZE, level, ti); - cache->associativity = ecag(EXTRACT_ASSOCIATIVITY, level, ti); - cache->nr_sets = cache->size / cache->associativity; - cache->nr_sets /= cache->line_size; - cache->private = private; - cache->level = level + 1; - cache->type = type - 1; - list_add_tail(&cache->list, &cache_list); - return 0; + + this_leaf->level = level + 1; + this_leaf->type = type; + this_leaf->coherency_line_size = ecag(EXTRACT_LINE_SIZE, level, ti); + this_leaf->ways_of_associativity = ecag(EXTRACT_ASSOCIATIVITY, + level, ti); + this_leaf->size = ecag(EXTRACT_SIZE, level, ti); + + num_sets = this_leaf->size / this_leaf->coherency_line_size; + num_sets /= this_leaf->ways_of_associativity; + this_leaf->number_of_sets = num_sets; + cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map); + if (!private) + this_leaf->disable_sysfs = true; } -static void __init cache_build_info(void) +int init_cache_level(unsigned int cpu) { - struct cache *cache, *next; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + unsigned int level = 0, leaves = 0; union cache_topology ct; - int level, private, rc; + enum cache_type ctype; + + if (!this_cpu_ci) + return -EINVAL; ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0); - for (level = 0; level < CACHE_MAX_LEVEL; level++) { - switch (ct.ci[level].scope) { - case CACHE_SCOPE_SHARED: - private = 0; + do { + ctype = get_cache_type(&ct.ci[0], level); + if (ctype == CACHE_TYPE_NOCACHE) break; - case CACHE_SCOPE_PRIVATE: - private = 1; - break; - default: - return; - } - if (ct.ci[level].type == CACHE_TYPE_SEPARATE) { - rc = cache_add(level, private, CACHE_TYPE_DATA); - rc |= cache_add(level, private, CACHE_TYPE_INSTRUCTION); + /* Separate instruction and data caches */ + leaves += (ctype == CACHE_TYPE_SEPARATE) ? 2 : 1; + } while (++level < CACHE_MAX_LEVEL); + + this_cpu_ci->num_levels = level; + this_cpu_ci->num_leaves = leaves; + + return 0; +} + +int populate_cache_leaves(unsigned int cpu) +{ + unsigned int level, idx, pvt; + union cache_topology ct; + enum cache_type ctype; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *this_leaf = this_cpu_ci->info_list; + + ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0); + for (idx = 0, level = 0; level < this_cpu_ci->num_levels && + idx < this_cpu_ci->num_leaves; idx++, level++) { + if (!this_leaf) + return -EINVAL; + + pvt = (ct.ci[level].scope == CACHE_SCOPE_PRIVATE) ? 1 : 0; + ctype = get_cache_type(&ct.ci[0], level); + if (ctype == CACHE_TYPE_SEPARATE) { + ci_leaf_init(this_leaf++, pvt, CACHE_TYPE_DATA, level); + ci_leaf_init(this_leaf++, pvt, CACHE_TYPE_INST, level); } else { - rc = cache_add(level, private, ct.ci[level].type); + ci_leaf_init(this_leaf++, pvt, ctype, level); } - if (rc) - goto error; - } - return; -error: - list_for_each_entry_safe(cache, next, &cache_list, list) { - list_del(&cache->list); - kfree(cache); - } -} - -static struct cache_dir *cache_create_cache_dir(int cpu) -{ - struct cache_dir *cache_dir; - struct kobject *kobj = NULL; - struct device *dev; - - dev = get_cpu_device(cpu); - if (!dev) - goto out; - kobj = kobject_create_and_add("cache", &dev->kobj); - if (!kobj) - goto out; - cache_dir = kzalloc(sizeof(*cache_dir), GFP_KERNEL); - if (!cache_dir) - goto out; - cache_dir->kobj = kobj; - cache_dir_cpu[cpu] = cache_dir; - return cache_dir; -out: - kobject_put(kobj); - return NULL; -} - -static struct cache_index_dir *kobj_to_cache_index_dir(struct kobject *kobj) -{ - return container_of(kobj, struct cache_index_dir, kobj); -} - -static void cache_index_release(struct kobject *kobj) -{ - struct cache_index_dir *index; - - index = kobj_to_cache_index_dir(kobj); - kfree(index); -} - -static ssize_t cache_index_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct kobj_attribute *kobj_attr; - - kobj_attr = container_of(attr, struct kobj_attribute, attr); - return kobj_attr->show(kobj, kobj_attr, buf); -} - -#define DEFINE_CACHE_ATTR(_name, _format, _value) \ -static ssize_t cache_##_name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, \ - char *buf) \ -{ \ - struct cache_index_dir *index; \ - \ - index = kobj_to_cache_index_dir(kobj); \ - return sprintf(buf, _format, _value); \ -} \ -static struct kobj_attribute cache_##_name##_attr = \ - __ATTR(_name, 0444, cache_##_name##_show, NULL); - -DEFINE_CACHE_ATTR(size, "%luK\n", index->cache->size >> 10); -DEFINE_CACHE_ATTR(coherency_line_size, "%u\n", index->cache->line_size); -DEFINE_CACHE_ATTR(number_of_sets, "%u\n", index->cache->nr_sets); -DEFINE_CACHE_ATTR(ways_of_associativity, "%u\n", index->cache->associativity); -DEFINE_CACHE_ATTR(type, "%s\n", cache_type_string[index->cache->type]); -DEFINE_CACHE_ATTR(level, "%d\n", index->cache->level); - -static ssize_t shared_cpu_map_func(struct kobject *kobj, int type, char *buf) -{ - struct cache_index_dir *index; - int len; - - index = kobj_to_cache_index_dir(kobj); - len = type ? - cpulist_scnprintf(buf, PAGE_SIZE - 2, cpumask_of(index->cpu)) : - cpumask_scnprintf(buf, PAGE_SIZE - 2, cpumask_of(index->cpu)); - len += sprintf(&buf[len], "\n"); - return len; -} - -static ssize_t shared_cpu_map_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return shared_cpu_map_func(kobj, 0, buf); -} -static struct kobj_attribute cache_shared_cpu_map_attr = - __ATTR(shared_cpu_map, 0444, shared_cpu_map_show, NULL); - -static ssize_t shared_cpu_list_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return shared_cpu_map_func(kobj, 1, buf); -} -static struct kobj_attribute cache_shared_cpu_list_attr = - __ATTR(shared_cpu_list, 0444, shared_cpu_list_show, NULL); - -static struct attribute *cache_index_default_attrs[] = { - &cache_type_attr.attr, - &cache_size_attr.attr, - &cache_number_of_sets_attr.attr, - &cache_ways_of_associativity_attr.attr, - &cache_level_attr.attr, - &cache_coherency_line_size_attr.attr, - &cache_shared_cpu_map_attr.attr, - &cache_shared_cpu_list_attr.attr, - NULL, -}; - -static const struct sysfs_ops cache_index_ops = { - .show = cache_index_show, -}; - -static struct kobj_type cache_index_type = { - .sysfs_ops = &cache_index_ops, - .release = cache_index_release, - .default_attrs = cache_index_default_attrs, -}; - -static int cache_create_index_dir(struct cache_dir *cache_dir, - struct cache *cache, int index, int cpu) -{ - struct cache_index_dir *index_dir; - int rc; - - index_dir = kzalloc(sizeof(*index_dir), GFP_KERNEL); - if (!index_dir) - return -ENOMEM; - index_dir->cache = cache; - index_dir->cpu = cpu; - rc = kobject_init_and_add(&index_dir->kobj, &cache_index_type, - cache_dir->kobj, "index%d", index); - if (rc) - goto out; - index_dir->next = cache_dir->index; - cache_dir->index = index_dir; - return 0; -out: - kfree(index_dir); - return rc; -} - -static int cache_add_cpu(int cpu) -{ - struct cache_dir *cache_dir; - struct cache *cache; - int rc, index = 0; - - if (list_empty(&cache_list)) - return 0; - cache_dir = cache_create_cache_dir(cpu); - if (!cache_dir) - return -ENOMEM; - list_for_each_entry(cache, &cache_list, list) { - if (!cache->private) - break; - rc = cache_create_index_dir(cache_dir, cache, index, cpu); - if (rc) - return rc; - index++; } return 0; } - -static void cache_remove_cpu(int cpu) -{ - struct cache_index_dir *index, *next; - struct cache_dir *cache_dir; - - cache_dir = cache_dir_cpu[cpu]; - if (!cache_dir) - return; - index = cache_dir->index; - while (index) { - next = index->next; - kobject_put(&index->kobj); - index = next; - } - kobject_put(cache_dir->kobj); - kfree(cache_dir); - cache_dir_cpu[cpu] = NULL; -} - -static int cache_hotplug(struct notifier_block *nfb, unsigned long action, - void *hcpu) -{ - int cpu = (long)hcpu; - int rc = 0; - - switch (action & ~CPU_TASKS_FROZEN) { - case CPU_ONLINE: - rc = cache_add_cpu(cpu); - if (rc) - cache_remove_cpu(cpu); - break; - case CPU_DEAD: - cache_remove_cpu(cpu); - break; - } - return rc ? NOTIFY_BAD : NOTIFY_OK; -} - -static int __init cache_init(void) -{ - int cpu; - - if (!test_facility(34)) - return 0; - cache_build_info(); - - cpu_notifier_register_begin(); - for_each_online_cpu(cpu) - cache_add_cpu(cpu); - __hotcpu_notifier(cache_hotplug, 0); - cpu_notifier_register_done(); - return 0; -} -device_initcall(cache_init); diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index f3762937dd82..533430307da8 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -137,7 +137,7 @@ enum { INSTR_RSI_RRP, INSTR_RSL_LRDFU, INSTR_RSL_R0RD, INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD, INSTR_RSY_RURD, - INSTR_RSY_RDRM, + INSTR_RSY_RDRM, INSTR_RSY_RMRD, INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, INSTR_RS_RRRD, INSTR_RS_RURD, INSTR_RXE_FRRD, INSTR_RXE_RRRD, INSTR_RXE_RRRDM, @@ -226,7 +226,6 @@ static const struct s390_operand operands[] = [U16_32] = { 16, 32, 0 }, [J16_16] = { 16, 16, OPERAND_PCREL }, [J16_32] = { 16, 32, OPERAND_PCREL }, - [I16_32] = { 16, 32, OPERAND_SIGNED }, [I24_24] = { 24, 24, OPERAND_SIGNED }, [J32_16] = { 32, 16, OPERAND_PCREL }, [I32_16] = { 32, 16, OPERAND_SIGNED }, @@ -308,6 +307,7 @@ static const unsigned char formats[][7] = { [INSTR_RSY_AARD] = { 0xff, A_8,A_12,D20_20,B_16,0,0 }, [INSTR_RSY_CCRD] = { 0xff, C_8,C_12,D20_20,B_16,0,0 }, [INSTR_RSY_RDRM] = { 0xff, R_8,D20_20,B_16,U4_12,0,0 }, + [INSTR_RSY_RMRD] = { 0xff, R_8,U4_12,D20_20,B_16,0,0 }, [INSTR_RSY_RRRD] = { 0xff, R_8,R_12,D20_20,B_16,0,0 }, [INSTR_RSY_RURD] = { 0xff, R_8,U4_12,D20_20,B_16,0,0 }, [INSTR_RS_AARD] = { 0xff, A_8,A_12,D_20,B_16,0,0 }, @@ -451,7 +451,8 @@ enum { LONG_INSN_VERLLV, LONG_INSN_VESRAV, LONG_INSN_VESRLV, - LONG_INSN_VSBCBI + LONG_INSN_VSBCBI, + LONG_INSN_STCCTM }; static char *long_insn_name[] = { @@ -531,6 +532,7 @@ static char *long_insn_name[] = { [LONG_INSN_VESRAV] = "vesrav", [LONG_INSN_VESRLV] = "vesrlv", [LONG_INSN_VSBCBI] = "vsbcbi", + [LONG_INSN_STCCTM] = "stcctm", }; static struct s390_insn opcode[] = { @@ -1656,6 +1658,7 @@ static struct s390_insn opcode_eb[] = { { "lric", 0x60, INSTR_RSY_RDRM }, { "stric", 0x61, INSTR_RSY_RDRM }, { "mric", 0x62, INSTR_RSY_RDRM }, + { { 0, LONG_INSN_STCCTM }, 0x17, INSTR_RSY_RMRD }, #endif { "rll", 0x1d, INSTR_RSY_RRRD }, { "mvclu", 0x8e, INSTR_RSY_RRRD }, diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 302ac1f7f8e7..70a329450901 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -393,9 +393,27 @@ static __init void detect_machine_facilities(void) S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC; if (test_facility(129)) S390_lowcore.machine_flags |= MACHINE_FLAG_VX; + if (test_facility(128)) + S390_lowcore.machine_flags |= MACHINE_FLAG_CAD; #endif } +static int __init nocad_setup(char *str) +{ + S390_lowcore.machine_flags &= ~MACHINE_FLAG_CAD; + return 0; +} +early_param("nocad", nocad_setup); + +static int __init cad_init(void) +{ + if (MACHINE_HAS_CAD) + /* Enable problem state CAD. */ + __ctl_set_bit(2, 3); + return 0; +} +early_initcall(cad_init); + static __init void rescue_initrd(void) { #ifdef CONFIG_BLK_DEV_INITRD diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index 8e61393c8275..834df047d35f 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h @@ -71,9 +71,11 @@ struct s390_mmap_arg_struct; struct fadvise64_64_args; struct old_sigaction; +long sys_rt_sigreturn(void); +long sys_sigreturn(void); + long sys_s390_personality(unsigned int personality); long sys_s390_runtime_instr(int command, int signum); - long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t); long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t); #endif /* _ENTRY_H */ diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index b86bb8823f15..82c19899574f 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c @@ -46,6 +46,13 @@ * lg %r14,8(%r15) # offset 18 * The jg instruction branches to offset 24 to skip as many instructions * as possible. + * In case we use gcc's hotpatch feature the original and also the disabled + * function prologue contains only a single six byte instruction and looks + * like this: + * > brcl 0,0 # offset 0 + * To enable ftrace the code gets patched like above and afterwards looks + * like this: + * > brasl %r0,ftrace_caller # offset 0 */ unsigned long ftrace_plt; @@ -59,62 +66,71 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) { - struct ftrace_insn insn; - unsigned short op; - void *from, *to; - size_t size; + struct ftrace_insn orig, new, old; - ftrace_generate_nop_insn(&insn); - size = sizeof(insn); - from = &insn; - to = (void *) rec->ip; - if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op))) + if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old))) return -EFAULT; - /* - * If we find a breakpoint instruction, a kprobe has been placed - * at the beginning of the function. We write the constant - * KPROBE_ON_FTRACE_NOP into the remaining four bytes of the original - * instruction so that the kprobes handler can execute a nop, if it - * reaches this breakpoint. - */ - if (op == BREAKPOINT_INSTRUCTION) { - size -= 2; - from += 2; - to += 2; - insn.disp = KPROBE_ON_FTRACE_NOP; + if (addr == MCOUNT_ADDR) { + /* Initial code replacement */ +#ifdef CC_USING_HOTPATCH + /* We expect to see brcl 0,0 */ + ftrace_generate_nop_insn(&orig); +#else + /* We expect to see stg r14,8(r15) */ + orig.opc = 0xe3e0; + orig.disp = 0xf0080024; +#endif + ftrace_generate_nop_insn(&new); + } else if (old.opc == BREAKPOINT_INSTRUCTION) { + /* + * If we find a breakpoint instruction, a kprobe has been + * placed at the beginning of the function. We write the + * constant KPROBE_ON_FTRACE_NOP into the remaining four + * bytes of the original instruction so that the kprobes + * handler can execute a nop, if it reaches this breakpoint. + */ + new.opc = orig.opc = BREAKPOINT_INSTRUCTION; + orig.disp = KPROBE_ON_FTRACE_CALL; + new.disp = KPROBE_ON_FTRACE_NOP; + } else { + /* Replace ftrace call with a nop. */ + ftrace_generate_call_insn(&orig, rec->ip); + ftrace_generate_nop_insn(&new); } - if (probe_kernel_write(to, from, size)) + /* Verify that the to be replaced code matches what we expect. */ + if (memcmp(&orig, &old, sizeof(old))) + return -EINVAL; + if (probe_kernel_write((void *) rec->ip, &new, sizeof(new))) return -EPERM; return 0; } int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { - struct ftrace_insn insn; - unsigned short op; - void *from, *to; - size_t size; + struct ftrace_insn orig, new, old; - ftrace_generate_call_insn(&insn, rec->ip); - size = sizeof(insn); - from = &insn; - to = (void *) rec->ip; - if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op))) + if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old))) return -EFAULT; - /* - * If we find a breakpoint instruction, a kprobe has been placed - * at the beginning of the function. We write the constant - * KPROBE_ON_FTRACE_CALL into the remaining four bytes of the original - * instruction so that the kprobes handler can execute a brasl if it - * reaches this breakpoint. - */ - if (op == BREAKPOINT_INSTRUCTION) { - size -= 2; - from += 2; - to += 2; - insn.disp = KPROBE_ON_FTRACE_CALL; + if (old.opc == BREAKPOINT_INSTRUCTION) { + /* + * If we find a breakpoint instruction, a kprobe has been + * placed at the beginning of the function. We write the + * constant KPROBE_ON_FTRACE_CALL into the remaining four + * bytes of the original instruction so that the kprobes + * handler can execute a brasl if it reaches this breakpoint. + */ + new.opc = orig.opc = BREAKPOINT_INSTRUCTION; + orig.disp = KPROBE_ON_FTRACE_NOP; + new.disp = KPROBE_ON_FTRACE_CALL; + } else { + /* Replace nop with an ftrace call. */ + ftrace_generate_nop_insn(&orig); + ftrace_generate_call_insn(&new, rec->ip); } - if (probe_kernel_write(to, from, size)) + /* Verify that the to be replaced code matches what we expect. */ + if (memcmp(&orig, &old, sizeof(old))) + return -EINVAL; + if (probe_kernel_write((void *) rec->ip, &new, sizeof(new))) return -EPERM; return 0; } diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index d62eee11f0b5..132f4c9ade60 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -436,7 +436,9 @@ ENTRY(startup_kdump) # followed by the facility words. #if defined(CONFIG_64BIT) -#if defined(CONFIG_MARCH_ZEC12) +#if defined(CONFIG_MARCH_Z13) + .long 3, 0xc100eff2, 0xf46ce800, 0x00400000 +#elif defined(CONFIG_MARCH_ZEC12) .long 3, 0xc100eff2, 0xf46ce800, 0x00400000 #elif defined(CONFIG_MARCH_Z196) .long 2, 0xc100eff2, 0xf46c0000 diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 39badb9ca0b3..5c8651f36509 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -2074,7 +2074,8 @@ static void do_reset_calls(void) u32 dump_prefix_page; -void s390_reset_system(void (*func)(void *), void *data) +void s390_reset_system(void (*fn_pre)(void), + void (*fn_post)(void *), void *data) { struct _lowcore *lc; @@ -2112,7 +2113,11 @@ void s390_reset_system(void (*func)(void *), void *data) /* Store status at absolute zero */ store_status(); + /* Call function before reset */ + if (fn_pre) + fn_pre(); do_reset_calls(); - if (func) - func(data); + /* Call function after reset */ + if (fn_post) + fn_post(data); } diff --git a/arch/s390/kernel/jump_label.c b/arch/s390/kernel/jump_label.c index b987ab2c1541..cb2d51e779df 100644 --- a/arch/s390/kernel/jump_label.c +++ b/arch/s390/kernel/jump_label.c @@ -22,31 +22,66 @@ struct insn_args { enum jump_label_type type; }; -static void __jump_label_transform(struct jump_entry *entry, - enum jump_label_type type) +static void jump_label_make_nop(struct jump_entry *entry, struct insn *insn) { - struct insn insn; - int rc; + /* brcl 0,0 */ + insn->opcode = 0xc004; + insn->offset = 0; +} + +static void jump_label_make_branch(struct jump_entry *entry, struct insn *insn) +{ + /* brcl 15,offset */ + insn->opcode = 0xc0f4; + insn->offset = (entry->target - entry->code) >> 1; +} + +static void jump_label_bug(struct jump_entry *entry, struct insn *insn) +{ + unsigned char *ipc = (unsigned char *)entry->code; + unsigned char *ipe = (unsigned char *)insn; + + pr_emerg("Jump label code mismatch at %pS [%p]\n", ipc, ipc); + pr_emerg("Found: %02x %02x %02x %02x %02x %02x\n", + ipc[0], ipc[1], ipc[2], ipc[3], ipc[4], ipc[5]); + pr_emerg("Expected: %02x %02x %02x %02x %02x %02x\n", + ipe[0], ipe[1], ipe[2], ipe[3], ipe[4], ipe[5]); + panic("Corrupted kernel text"); +} + +static struct insn orignop = { + .opcode = 0xc004, + .offset = JUMP_LABEL_NOP_OFFSET >> 1, +}; + +static void __jump_label_transform(struct jump_entry *entry, + enum jump_label_type type, + int init) +{ + struct insn old, new; if (type == JUMP_LABEL_ENABLE) { - /* brcl 15,offset */ - insn.opcode = 0xc0f4; - insn.offset = (entry->target - entry->code) >> 1; + jump_label_make_nop(entry, &old); + jump_label_make_branch(entry, &new); } else { - /* brcl 0,0 */ - insn.opcode = 0xc004; - insn.offset = 0; + jump_label_make_branch(entry, &old); + jump_label_make_nop(entry, &new); } - - rc = probe_kernel_write((void *)entry->code, &insn, JUMP_LABEL_NOP_SIZE); - WARN_ON_ONCE(rc < 0); + if (init) { + if (memcmp((void *)entry->code, &orignop, sizeof(orignop))) + jump_label_bug(entry, &old); + } else { + if (memcmp((void *)entry->code, &old, sizeof(old))) + jump_label_bug(entry, &old); + } + probe_kernel_write((void *)entry->code, &new, sizeof(new)); } static int __sm_arch_jump_label_transform(void *data) { struct insn_args *args = data; - __jump_label_transform(args->entry, args->type); + __jump_label_transform(args->entry, args->type, 0); return 0; } @@ -64,7 +99,7 @@ void arch_jump_label_transform(struct jump_entry *entry, void arch_jump_label_transform_static(struct jump_entry *entry, enum jump_label_type type) { - __jump_label_transform(entry, type); + __jump_label_transform(entry, type, 1); } #endif diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 1e4c710dfb92..f516edc1fbe3 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -69,7 +69,8 @@ static void copy_instruction(struct kprobe *p) /* * If kprobes patches the instruction that is morphed by * ftrace make sure that kprobes always sees the branch - * "jg .+24" that skips the mcount block + * "jg .+24" that skips the mcount block or the "brcl 0,0" + * in case of hotpatch. */ ftrace_generate_nop_insn((struct ftrace_insn *)p->ainsn.insn); p->ainsn.is_ftrace_insn = 1; diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index 4685337fa7c6..fb0901ec4306 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c @@ -103,21 +103,18 @@ static int __init machine_kdump_pm_init(void) return 0; } arch_initcall(machine_kdump_pm_init); -#endif /* * Start kdump: We expect here that a store status has been done on our CPU */ static void __do_machine_kdump(void *image) { -#ifdef CONFIG_CRASH_DUMP int (*start_kdump)(int) = (void *)((struct kimage *) image)->start; - setup_regs(); __load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA); start_kdump(1); -#endif } +#endif /* * Check if kdump checksums are valid: We call purgatory with parameter "0" @@ -249,18 +246,18 @@ static void __do_machine_kexec(void *data) */ static void __machine_kexec(void *data) { - struct kimage *image = data; - __arch_local_irq_stosm(0x04); /* enable DAT */ pfault_fini(); tracing_off(); debug_locks_off(); - if (image->type == KEXEC_TYPE_CRASH) { +#ifdef CONFIG_CRASH_DUMP + if (((struct kimage *) data)->type == KEXEC_TYPE_CRASH) { + lgr_info_log(); - s390_reset_system(__do_machine_kdump, data); - } else { - s390_reset_system(__do_machine_kexec, data); - } + s390_reset_system(setup_regs, __do_machine_kdump, data); + } else +#endif + s390_reset_system(NULL, __do_machine_kexec, data); disabled_wait((unsigned long) __builtin_return_address(0)); } diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S index b6dfc5bfcb89..e499370fbccb 100644 --- a/arch/s390/kernel/mcount.S +++ b/arch/s390/kernel/mcount.S @@ -27,7 +27,9 @@ ENTRY(ftrace_caller) .globl ftrace_regs_caller .set ftrace_regs_caller,ftrace_caller lgr %r1,%r15 +#ifndef CC_USING_HOTPATCH aghi %r0,MCOUNT_RETURN_FIXUP +#endif aghi %r15,-STACK_FRAME_SIZE stg %r1,__SF_BACKCHAIN(%r15) stg %r1,(STACK_PTREGS_GPRS+15*8)(%r15) diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index b89b59158b95..409d152585be 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -55,14 +55,10 @@ void *module_alloc(unsigned long size) } #endif -/* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) +void module_arch_freeing_init(struct module *mod) { - if (mod) { - vfree(mod->arch.syminfo); - mod->arch.syminfo = NULL; - } - vfree(module_region); + vfree(mod->arch.syminfo); + mod->arch.syminfo = NULL; } static void check_rela(Elf_Rela *rela, struct module *me) diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index aa7a83948c7b..13fc0978ca7e 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -79,6 +79,14 @@ void release_thread(struct task_struct *dead_task) { } +#ifdef CONFIG_64BIT +void arch_release_task_struct(struct task_struct *tsk) +{ + if (tsk->thread.vxrs) + kfree(tsk->thread.vxrs); +} +#endif + int copy_thread(unsigned long clone_flags, unsigned long new_stackp, unsigned long arg, struct task_struct *p) { @@ -243,13 +251,3 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) ret = PAGE_ALIGN(mm->brk + brk_rnd()); return (ret > mm->brk) ? ret : mm->brk; } - -unsigned long randomize_et_dyn(unsigned long base) -{ - unsigned long ret; - - if (!(current->flags & PF_RANDOMIZE)) - return base; - ret = PAGE_ALIGN(base + brk_rnd()); - return (ret > base) ? ret : base; -} diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index dbdd33ee0102..26108232fcaa 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -8,16 +8,24 @@ #include #include -#include #include #include #include #include #include #include +#include static DEFINE_PER_CPU(struct cpuid, cpu_id); +void cpu_relax(void) +{ + if (!smp_cpu_mtid && MACHINE_HAS_DIAG44) + asm volatile("diag 0,0,0x44"); + barrier(); +} +EXPORT_SYMBOL(cpu_relax); + /* * cpu_init - initializes state that is per-CPU. */ diff --git a/arch/s390/kernel/sclp.S b/arch/s390/kernel/sclp.S index a41f2c99dcc8..7e77e03378f3 100644 --- a/arch/s390/kernel/sclp.S +++ b/arch/s390/kernel/sclp.S @@ -294,7 +294,8 @@ ENTRY(_sclp_print_early) #ifdef CONFIG_64BIT tm LC_AR_MODE_ID,1 jno .Lesa3 - lmh %r6,%r15,96(%r15) # store upper register halves + lgfr %r2,%r2 # sign extend return value + lmh %r6,%r15,96(%r15) # restore upper register halves ahi %r15,80 .Lesa3: #endif diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 4e532c67832f..bfac77ada4f2 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -810,6 +810,9 @@ static void __init setup_hwcaps(void) case 0x2828: strcpy(elf_platform, "zEC12"); break; + case 0x2964: + strcpy(elf_platform, "z13"); + break; } } diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 0b499f5cbe19..a668993ff577 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -71,9 +71,30 @@ struct pcpu { }; static u8 boot_cpu_type; -static u16 boot_cpu_address; static struct pcpu pcpu_devices[NR_CPUS]; +unsigned int smp_cpu_mt_shift; +EXPORT_SYMBOL(smp_cpu_mt_shift); + +unsigned int smp_cpu_mtid; +EXPORT_SYMBOL(smp_cpu_mtid); + +static unsigned int smp_max_threads __initdata = -1U; + +static int __init early_nosmt(char *s) +{ + smp_max_threads = 1; + return 0; +} +early_param("nosmt", early_nosmt); + +static int __init early_smt(char *s) +{ + get_option(&s, &smp_max_threads); + return 0; +} +early_param("smt", early_smt); + /* * The smp_cpu_state_mutex must be held when changing the state or polarization * member of a pcpu data structure within the pcpu_devices arreay. @@ -132,7 +153,7 @@ static inline int pcpu_running(struct pcpu *pcpu) /* * Find struct pcpu by cpu address. */ -static struct pcpu *pcpu_find_address(const struct cpumask *mask, int address) +static struct pcpu *pcpu_find_address(const struct cpumask *mask, u16 address) { int cpu; @@ -298,6 +319,32 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *), for (;;) ; } +/* + * Enable additional logical cpus for multi-threading. + */ +static int pcpu_set_smt(unsigned int mtid) +{ + register unsigned long reg1 asm ("1") = (unsigned long) mtid; + int cc; + + if (smp_cpu_mtid == mtid) + return 0; + asm volatile( + " sigp %1,0,%2 # sigp set multi-threading\n" + " ipm %0\n" + " srl %0,28\n" + : "=d" (cc) : "d" (reg1), "K" (SIGP_SET_MULTI_THREADING) + : "cc"); + if (cc == 0) { + smp_cpu_mtid = mtid; + smp_cpu_mt_shift = 0; + while (smp_cpu_mtid >= (1U << smp_cpu_mt_shift)) + smp_cpu_mt_shift++; + pcpu_devices[0].address = stap(); + } + return cc; +} + /* * Call function on an online CPU. */ @@ -512,22 +559,17 @@ EXPORT_SYMBOL(smp_ctl_clear_bit); #ifdef CONFIG_CRASH_DUMP -static void __init smp_get_save_area(int cpu, u16 address) +static inline void __smp_store_cpu_state(int cpu, u16 address, int is_boot_cpu) { void *lc = pcpu_devices[0].lowcore; struct save_area_ext *sa_ext; unsigned long vx_sa; - if (is_kdump_kernel()) - return; - if (!OLDMEM_BASE && (address == boot_cpu_address || - ipl_info.type != IPL_TYPE_FCP_DUMP)) - return; sa_ext = dump_save_area_create(cpu); if (!sa_ext) panic("could not allocate memory for save area\n"); - if (address == boot_cpu_address) { - /* Copy the registers of the boot cpu. */ + if (is_boot_cpu) { + /* Copy the registers of the boot CPU. */ copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa), SAVE_AREA_BASE - PAGE_SIZE, 0); if (MACHINE_HAS_VX) @@ -548,6 +590,64 @@ static void __init smp_get_save_area(int cpu, u16 address) free_page(vx_sa); } +/* + * Collect CPU state of the previous, crashed system. + * There are four cases: + * 1) standard zfcp dump + * condition: OLDMEM_BASE == NULL && ipl_info.type == IPL_TYPE_FCP_DUMP + * The state for all CPUs except the boot CPU needs to be collected + * with sigp stop-and-store-status. The boot CPU state is located in + * the absolute lowcore of the memory stored in the HSA. The zcore code + * will allocate the save area and copy the boot CPU state from the HSA. + * 2) stand-alone kdump for SCSI (zfcp dump with swapped memory) + * condition: OLDMEM_BASE != NULL && ipl_info.type == IPL_TYPE_FCP_DUMP + * The state for all CPUs except the boot CPU needs to be collected + * with sigp stop-and-store-status. The firmware or the boot-loader + * stored the registers of the boot CPU in the absolute lowcore in the + * memory of the old system. + * 3) kdump and the old kernel did not store the CPU state, + * or stand-alone kdump for DASD + * condition: OLDMEM_BASE != NULL && !is_kdump_kernel() + * The state for all CPUs except the boot CPU needs to be collected + * with sigp stop-and-store-status. The kexec code or the boot-loader + * stored the registers of the boot CPU in the memory of the old system. + * 4) kdump and the old kernel stored the CPU state + * condition: OLDMEM_BASE != NULL && is_kdump_kernel() + * The state of all CPUs is stored in ELF sections in the memory of the + * old system. The ELF sections are picked up by the crash_dump code + * via elfcorehdr_addr. + */ +static void __init smp_store_cpu_states(struct sclp_cpu_info *info) +{ + unsigned int cpu, address, i, j; + int is_boot_cpu; + + if (is_kdump_kernel()) + /* Previous system stored the CPU states. Nothing to do. */ + return; + if (!(OLDMEM_BASE || ipl_info.type == IPL_TYPE_FCP_DUMP)) + /* No previous system present, normal boot. */ + return; + /* Set multi-threading state to the previous system. */ + pcpu_set_smt(sclp_get_mtid_prev()); + /* Collect CPU states. */ + cpu = 0; + for (i = 0; i < info->configured; i++) { + /* Skip CPUs with different CPU type. */ + if (info->has_cpu_type && info->cpu[i].type != boot_cpu_type) + continue; + for (j = 0; j <= smp_cpu_mtid; j++, cpu++) { + address = (info->cpu[i].core_id << smp_cpu_mt_shift) + j; + is_boot_cpu = (address == pcpu_devices[0].address); + if (is_boot_cpu && !OLDMEM_BASE) + /* Skip boot CPU for standard zfcp dump. */ + continue; + /* Get state for this CPu. */ + __smp_store_cpu_state(cpu, address, is_boot_cpu); + } + } +} + int smp_store_status(int cpu) { unsigned long vx_sa; @@ -565,10 +665,6 @@ int smp_store_status(int cpu) return 0; } -#else /* CONFIG_CRASH_DUMP */ - -static inline void smp_get_save_area(int cpu, u16 address) { } - #endif /* CONFIG_CRASH_DUMP */ void smp_cpu_set_polarization(int cpu, int val) @@ -590,11 +686,13 @@ static struct sclp_cpu_info *smp_get_cpu_info(void) info = kzalloc(sizeof(*info), GFP_KERNEL); if (info && (use_sigp_detection || sclp_get_cpu_info(info))) { use_sigp_detection = 1; - for (address = 0; address <= MAX_CPU_ADDRESS; address++) { + for (address = 0; address <= MAX_CPU_ADDRESS; + address += (1U << smp_cpu_mt_shift)) { if (__pcpu_sigp_relax(address, SIGP_SENSE, 0, NULL) == SIGP_CC_NOT_OPERATIONAL) continue; - info->cpu[info->configured].address = address; + info->cpu[info->configured].core_id = + address >> smp_cpu_mt_shift; info->configured++; } info->combined = info->configured; @@ -608,7 +706,8 @@ static int __smp_rescan_cpus(struct sclp_cpu_info *info, int sysfs_add) { struct pcpu *pcpu; cpumask_t avail; - int cpu, nr, i; + int cpu, nr, i, j; + u16 address; nr = 0; cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask); @@ -616,51 +715,76 @@ static int __smp_rescan_cpus(struct sclp_cpu_info *info, int sysfs_add) for (i = 0; (i < info->combined) && (cpu < nr_cpu_ids); i++) { if (info->has_cpu_type && info->cpu[i].type != boot_cpu_type) continue; - if (pcpu_find_address(cpu_present_mask, info->cpu[i].address)) - continue; - pcpu = pcpu_devices + cpu; - pcpu->address = info->cpu[i].address; - pcpu->state = (i >= info->configured) ? - CPU_STATE_STANDBY : CPU_STATE_CONFIGURED; - smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); - set_cpu_present(cpu, true); - if (sysfs_add && smp_add_present_cpu(cpu) != 0) - set_cpu_present(cpu, false); - else - nr++; - cpu = cpumask_next(cpu, &avail); + address = info->cpu[i].core_id << smp_cpu_mt_shift; + for (j = 0; j <= smp_cpu_mtid; j++) { + if (pcpu_find_address(cpu_present_mask, address + j)) + continue; + pcpu = pcpu_devices + cpu; + pcpu->address = address + j; + pcpu->state = + (cpu >= info->configured*(smp_cpu_mtid + 1)) ? + CPU_STATE_STANDBY : CPU_STATE_CONFIGURED; + smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); + set_cpu_present(cpu, true); + if (sysfs_add && smp_add_present_cpu(cpu) != 0) + set_cpu_present(cpu, false); + else + nr++; + cpu = cpumask_next(cpu, &avail); + if (cpu >= nr_cpu_ids) + break; + } } return nr; } static void __init smp_detect_cpus(void) { - unsigned int cpu, c_cpus, s_cpus; + unsigned int cpu, mtid, c_cpus, s_cpus; struct sclp_cpu_info *info; + u16 address; + /* Get CPU information */ info = smp_get_cpu_info(); if (!info) panic("smp_detect_cpus failed to allocate memory\n"); + + /* Find boot CPU type */ if (info->has_cpu_type) { - for (cpu = 0; cpu < info->combined; cpu++) { - if (info->cpu[cpu].address != boot_cpu_address) - continue; - /* The boot cpu dictates the cpu type. */ - boot_cpu_type = info->cpu[cpu].type; - break; - } + address = stap(); + for (cpu = 0; cpu < info->combined; cpu++) + if (info->cpu[cpu].core_id == address) { + /* The boot cpu dictates the cpu type. */ + boot_cpu_type = info->cpu[cpu].type; + break; + } + if (cpu >= info->combined) + panic("Could not find boot CPU type"); } + +#ifdef CONFIG_CRASH_DUMP + /* Collect CPU state of previous system */ + smp_store_cpu_states(info); +#endif + + /* Set multi-threading state for the current system */ + mtid = sclp_get_mtid(boot_cpu_type); + mtid = (mtid < smp_max_threads) ? mtid : smp_max_threads - 1; + pcpu_set_smt(mtid); + + /* Print number of CPUs */ c_cpus = s_cpus = 0; for (cpu = 0; cpu < info->combined; cpu++) { if (info->has_cpu_type && info->cpu[cpu].type != boot_cpu_type) continue; - if (cpu < info->configured) { - smp_get_save_area(c_cpus, info->cpu[cpu].address); - c_cpus++; - } else - s_cpus++; + if (cpu < info->configured) + c_cpus += smp_cpu_mtid + 1; + else + s_cpus += smp_cpu_mtid + 1; } pr_info("%d configured CPUs, %d standby CPUs\n", c_cpus, s_cpus); + + /* Add CPUs present at boot */ get_online_cpus(); __smp_rescan_cpus(info, 0); put_online_cpus(); @@ -696,12 +820,23 @@ static void smp_start_secondary(void *cpuvoid) int __cpu_up(unsigned int cpu, struct task_struct *tidle) { struct pcpu *pcpu; - int rc; + int base, i, rc; pcpu = pcpu_devices + cpu; if (pcpu->state != CPU_STATE_CONFIGURED) return -EIO; - if (pcpu_sigp_retry(pcpu, SIGP_INITIAL_CPU_RESET, 0) != + base = cpu - (cpu % (smp_cpu_mtid + 1)); + for (i = 0; i <= smp_cpu_mtid; i++) { + if (base + i < nr_cpu_ids) + if (cpu_online(base + i)) + break; + } + /* + * If this is the first CPU of the core to get online + * do an initial CPU reset. + */ + if (i > smp_cpu_mtid && + pcpu_sigp_retry(pcpu_devices + base, SIGP_INITIAL_CPU_RESET, 0) != SIGP_CC_ORDER_CODE_ACCEPTED) return -EIO; @@ -774,7 +909,8 @@ void __init smp_fill_possible_mask(void) { unsigned int possible, sclp, cpu; - sclp = sclp_get_max_cpu() ?: nr_cpu_ids; + sclp = min(smp_max_threads, sclp_get_mtid_max() + 1); + sclp = sclp_get_max_cpu()*sclp ?: nr_cpu_ids; possible = setup_possible_cpus ?: nr_cpu_ids; possible = min(possible, sclp); for (cpu = 0; cpu < possible && cpu < nr_cpu_ids; cpu++) @@ -796,9 +932,8 @@ void __init smp_prepare_boot_cpu(void) { struct pcpu *pcpu = pcpu_devices; - boot_cpu_address = stap(); pcpu->state = CPU_STATE_CONFIGURED; - pcpu->address = boot_cpu_address; + pcpu->address = stap(); pcpu->lowcore = (struct _lowcore *)(unsigned long) store_prefix(); pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE + STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); @@ -848,7 +983,7 @@ static ssize_t cpu_configure_store(struct device *dev, const char *buf, size_t count) { struct pcpu *pcpu; - int cpu, val, rc; + int cpu, val, rc, i; char delim; if (sscanf(buf, "%d %c", &val, &delim) != 1) @@ -860,29 +995,43 @@ static ssize_t cpu_configure_store(struct device *dev, rc = -EBUSY; /* disallow configuration changes of online cpus and cpu 0 */ cpu = dev->id; - if (cpu_online(cpu) || cpu == 0) + cpu -= cpu % (smp_cpu_mtid + 1); + if (cpu == 0) goto out; + for (i = 0; i <= smp_cpu_mtid; i++) + if (cpu_online(cpu + i)) + goto out; pcpu = pcpu_devices + cpu; rc = 0; switch (val) { case 0: if (pcpu->state != CPU_STATE_CONFIGURED) break; - rc = sclp_cpu_deconfigure(pcpu->address); + rc = sclp_cpu_deconfigure(pcpu->address >> smp_cpu_mt_shift); if (rc) break; - pcpu->state = CPU_STATE_STANDBY; - smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); + for (i = 0; i <= smp_cpu_mtid; i++) { + if (cpu + i >= nr_cpu_ids || !cpu_present(cpu + i)) + continue; + pcpu[i].state = CPU_STATE_STANDBY; + smp_cpu_set_polarization(cpu + i, + POLARIZATION_UNKNOWN); + } topology_expect_change(); break; case 1: if (pcpu->state != CPU_STATE_STANDBY) break; - rc = sclp_cpu_configure(pcpu->address); + rc = sclp_cpu_configure(pcpu->address >> smp_cpu_mt_shift); if (rc) break; - pcpu->state = CPU_STATE_CONFIGURED; - smp_cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); + for (i = 0; i <= smp_cpu_mtid; i++) { + if (cpu + i >= nr_cpu_ids || !cpu_present(cpu + i)) + continue; + pcpu[i].state = CPU_STATE_CONFIGURED; + smp_cpu_set_polarization(cpu + i, + POLARIZATION_UNKNOWN); + } topology_expect_change(); break; default: diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c index 811f542b8ed4..85565f1ff474 100644 --- a/arch/s390/kernel/sysinfo.c +++ b/arch/s390/kernel/sysinfo.c @@ -194,6 +194,14 @@ static void stsi_2_2_2(struct seq_file *m, struct sysinfo_2_2_2 *info) seq_printf(m, "LPAR CPUs Reserved: %d\n", info->cpus_reserved); seq_printf(m, "LPAR CPUs Dedicated: %d\n", info->cpus_dedicated); seq_printf(m, "LPAR CPUs Shared: %d\n", info->cpus_shared); + if (info->mt_installed & 0x80) { + seq_printf(m, "LPAR CPUs G-MTID: %d\n", + info->mt_general & 0x1f); + seq_printf(m, "LPAR CPUs S-MTID: %d\n", + info->mt_installed & 0x1f); + seq_printf(m, "LPAR CPUs PS-MTID: %d\n", + info->mt_psmtid & 0x1f); + } } static void stsi_3_2_2(struct seq_file *m, struct sysinfo_3_2_2 *info) diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index b93bed76ea94..24ee33f1af24 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -59,32 +59,50 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) return mask; } -static struct mask_info *add_cpus_to_mask(struct topology_cpu *tl_cpu, +static cpumask_t cpu_thread_map(unsigned int cpu) +{ + cpumask_t mask; + int i; + + cpumask_copy(&mask, cpumask_of(cpu)); + if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) + return mask; + cpu -= cpu % (smp_cpu_mtid + 1); + for (i = 0; i <= smp_cpu_mtid; i++) + if (cpu_present(cpu + i)) + cpumask_set_cpu(cpu + i, &mask); + return mask; +} + +static struct mask_info *add_cpus_to_mask(struct topology_core *tl_core, struct mask_info *book, struct mask_info *socket, int one_socket_per_cpu) { - unsigned int cpu; + unsigned int core; - for_each_set_bit(cpu, &tl_cpu->mask[0], TOPOLOGY_CPU_BITS) { - unsigned int rcpu; - int lcpu; + for_each_set_bit(core, &tl_core->mask[0], TOPOLOGY_CORE_BITS) { + unsigned int rcore; + int lcpu, i; - rcpu = TOPOLOGY_CPU_BITS - 1 - cpu + tl_cpu->origin; - lcpu = smp_find_processor_id(rcpu); + rcore = TOPOLOGY_CORE_BITS - 1 - core + tl_core->origin; + lcpu = smp_find_processor_id(rcore << smp_cpu_mt_shift); if (lcpu < 0) continue; - cpumask_set_cpu(lcpu, &book->mask); - cpu_topology[lcpu].book_id = book->id; - cpumask_set_cpu(lcpu, &socket->mask); - cpu_topology[lcpu].core_id = rcpu; - if (one_socket_per_cpu) { - cpu_topology[lcpu].socket_id = rcpu; - socket = socket->next; - } else { - cpu_topology[lcpu].socket_id = socket->id; + for (i = 0; i <= smp_cpu_mtid; i++) { + cpu_topology[lcpu + i].book_id = book->id; + cpu_topology[lcpu + i].core_id = rcore; + cpu_topology[lcpu + i].thread_id = lcpu + i; + cpumask_set_cpu(lcpu + i, &book->mask); + cpumask_set_cpu(lcpu + i, &socket->mask); + if (one_socket_per_cpu) + cpu_topology[lcpu + i].socket_id = rcore; + else + cpu_topology[lcpu + i].socket_id = socket->id; + smp_cpu_set_polarization(lcpu + i, tl_core->pp); } - smp_cpu_set_polarization(lcpu, tl_cpu->pp); + if (one_socket_per_cpu) + socket = socket->next; } return socket; } @@ -108,7 +126,7 @@ static void clear_masks(void) static union topology_entry *next_tle(union topology_entry *tle) { if (!tle->nl) - return (union topology_entry *)((struct topology_cpu *)tle + 1); + return (union topology_entry *)((struct topology_core *)tle + 1); return (union topology_entry *)((struct topology_container *)tle + 1); } @@ -231,9 +249,11 @@ static void update_cpu_masks(void) spin_lock_irqsave(&topology_lock, flags); for_each_possible_cpu(cpu) { + cpu_topology[cpu].thread_mask = cpu_thread_map(cpu); cpu_topology[cpu].core_mask = cpu_group_map(&socket_info, cpu); cpu_topology[cpu].book_mask = cpu_group_map(&book_info, cpu); if (!MACHINE_HAS_TOPOLOGY) { + cpu_topology[cpu].thread_id = cpu; cpu_topology[cpu].core_id = cpu; cpu_topology[cpu].socket_id = cpu; cpu_topology[cpu].book_id = cpu; @@ -445,6 +465,12 @@ int topology_cpu_init(struct cpu *cpu) return sysfs_create_group(&cpu->dev.kobj, &topology_cpu_attr_group); } +const struct cpumask *cpu_thread_mask(int cpu) +{ + return &cpu_topology[cpu].thread_mask; +} + + const struct cpumask *cpu_coregroup_mask(int cpu) { return &cpu_topology[cpu].core_mask; @@ -456,6 +482,7 @@ static const struct cpumask *cpu_book_mask(int cpu) } static struct sched_domain_topology_level s390_topology[] = { + { cpu_thread_mask, cpu_smt_flags, SD_INIT_NAME(SMT) }, { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) }, { cpu_book_mask, SD_INIT_NAME(BOOK) }, { cpu_cpu_mask, SD_INIT_NAME(DIE) }, diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index e34122e539a1..e53d3595a7c8 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include static void virt_timer_expire(void); @@ -23,6 +25,10 @@ static DEFINE_SPINLOCK(virt_timer_lock); static atomic64_t virt_timer_current; static atomic64_t virt_timer_elapsed; +static DEFINE_PER_CPU(u64, mt_cycles[32]); +static DEFINE_PER_CPU(u64, mt_scaling_mult) = { 1 }; +static DEFINE_PER_CPU(u64, mt_scaling_div) = { 1 }; + static inline u64 get_vtimer(void) { u64 timer; @@ -61,6 +67,8 @@ static int do_account_vtime(struct task_struct *tsk, int hardirq_offset) { struct thread_info *ti = task_thread_info(tsk); u64 timer, clock, user, system, steal; + u64 user_scaled, system_scaled; + int i; timer = S390_lowcore.last_update_timer; clock = S390_lowcore.last_update_clock; @@ -76,15 +84,49 @@ static int do_account_vtime(struct task_struct *tsk, int hardirq_offset) S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer; S390_lowcore.steal_timer += S390_lowcore.last_update_clock - clock; + /* Do MT utilization calculation */ + if (smp_cpu_mtid) { + u64 cycles_new[32], *cycles_old; + u64 delta, mult, div; + + cycles_old = this_cpu_ptr(mt_cycles); + if (stcctm5(smp_cpu_mtid + 1, cycles_new) < 2) { + mult = div = 0; + for (i = 0; i <= smp_cpu_mtid; i++) { + delta = cycles_new[i] - cycles_old[i]; + mult += delta; + div += (i + 1) * delta; + } + if (mult > 0) { + /* Update scaling factor */ + __this_cpu_write(mt_scaling_mult, mult); + __this_cpu_write(mt_scaling_div, div); + memcpy(cycles_old, cycles_new, + sizeof(u64) * (smp_cpu_mtid + 1)); + } + } + } + user = S390_lowcore.user_timer - ti->user_timer; S390_lowcore.steal_timer -= user; ti->user_timer = S390_lowcore.user_timer; - account_user_time(tsk, user, user); system = S390_lowcore.system_timer - ti->system_timer; S390_lowcore.steal_timer -= system; ti->system_timer = S390_lowcore.system_timer; - account_system_time(tsk, hardirq_offset, system, system); + + user_scaled = user; + system_scaled = system; + /* Do MT utilization scaling */ + if (smp_cpu_mtid) { + u64 mult = __this_cpu_read(mt_scaling_mult); + u64 div = __this_cpu_read(mt_scaling_div); + + user_scaled = (user_scaled * mult) / div; + system_scaled = (system_scaled * mult) / div; + } + account_user_time(tsk, user, user_scaled); + account_system_time(tsk, hardirq_offset, system, system_scaled); steal = S390_lowcore.steal_timer; if ((s64) steal > 0) { @@ -126,7 +168,7 @@ void vtime_account_user(struct task_struct *tsk) void vtime_account_irq_enter(struct task_struct *tsk) { struct thread_info *ti = task_thread_info(tsk); - u64 timer, system; + u64 timer, system, system_scaled; timer = S390_lowcore.last_update_timer; S390_lowcore.last_update_timer = get_vtimer(); @@ -135,7 +177,15 @@ void vtime_account_irq_enter(struct task_struct *tsk) system = S390_lowcore.system_timer - ti->system_timer; S390_lowcore.steal_timer -= system; ti->system_timer = S390_lowcore.system_timer; - account_system_time(tsk, 0, system, system); + system_scaled = system; + /* Do MT utilization scaling */ + if (smp_cpu_mtid) { + u64 mult = __this_cpu_read(mt_scaling_mult); + u64 div = __this_cpu_read(mt_scaling_div); + + system_scaled = (system_scaled * mult) / div; + } + account_system_time(tsk, 0, system, system_scaled); virt_timer_forward(system); } diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index 646db9c467d1..5fce52cf0e57 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig @@ -28,6 +28,7 @@ config KVM select HAVE_KVM_IRQCHIP select HAVE_KVM_IRQFD select HAVE_KVM_IRQ_ROUTING + select SRCU ---help--- Support hosting paravirtualized guest machines using the SIE virtualization capability on the mainframe. This should work diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c index 034a35a3e9c1..d6c9991f7797 100644 --- a/arch/s390/lib/spinlock.c +++ b/arch/s390/lib/spinlock.c @@ -12,7 +12,15 @@ #include #include -int spin_retry = 1000; +int spin_retry = -1; + +static int __init spin_retry_init(void) +{ + if (spin_retry < 0) + spin_retry = MACHINE_HAS_CAD ? 10 : 1000; + return 0; +} +early_initcall(spin_retry_init); /** * spin_retry= parameter @@ -24,6 +32,11 @@ static int __init spin_retry_setup(char *str) } __setup("spin_retry=", spin_retry_setup); +static inline void _raw_compare_and_delay(unsigned int *lock, unsigned int old) +{ + asm(".insn rsy,0xeb0000000022,%0,0,%1" : : "d" (old), "Q" (*lock)); +} + void arch_spin_lock_wait(arch_spinlock_t *lp) { unsigned int cpu = SPINLOCK_LOCKVAL; @@ -46,6 +59,8 @@ void arch_spin_lock_wait(arch_spinlock_t *lp) /* Loop for a while on the lock value. */ count = spin_retry; do { + if (MACHINE_HAS_CAD) + _raw_compare_and_delay(&lp->lock, owner); owner = ACCESS_ONCE(lp->lock); } while (owner && count-- > 0); if (!owner) @@ -84,6 +99,8 @@ void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags) /* Loop for a while on the lock value. */ count = spin_retry; do { + if (MACHINE_HAS_CAD) + _raw_compare_and_delay(&lp->lock, owner); owner = ACCESS_ONCE(lp->lock); } while (owner && count-- > 0); if (!owner) @@ -100,11 +117,19 @@ EXPORT_SYMBOL(arch_spin_lock_wait_flags); int arch_spin_trylock_retry(arch_spinlock_t *lp) { + unsigned int cpu = SPINLOCK_LOCKVAL; + unsigned int owner; int count; - for (count = spin_retry; count > 0; count--) - if (arch_spin_trylock_once(lp)) - return 1; + for (count = spin_retry; count > 0; count--) { + owner = ACCESS_ONCE(lp->lock); + /* Try to get the lock if it is free. */ + if (!owner) { + if (_raw_compare_and_swap(&lp->lock, 0, cpu)) + return 1; + } else if (MACHINE_HAS_CAD) + _raw_compare_and_delay(&lp->lock, owner); + } return 0; } EXPORT_SYMBOL(arch_spin_trylock_retry); @@ -126,8 +151,11 @@ void _raw_read_lock_wait(arch_rwlock_t *rw) } old = ACCESS_ONCE(rw->lock); owner = ACCESS_ONCE(rw->owner); - if ((int) old < 0) + if ((int) old < 0) { + if (MACHINE_HAS_CAD) + _raw_compare_and_delay(&rw->lock, old); continue; + } if (_raw_compare_and_swap(&rw->lock, old, old + 1)) return; } @@ -141,8 +169,11 @@ int _raw_read_trylock_retry(arch_rwlock_t *rw) while (count-- > 0) { old = ACCESS_ONCE(rw->lock); - if ((int) old < 0) + if ((int) old < 0) { + if (MACHINE_HAS_CAD) + _raw_compare_and_delay(&rw->lock, old); continue; + } if (_raw_compare_and_swap(&rw->lock, old, old + 1)) return 1; } @@ -173,6 +204,8 @@ void _raw_write_lock_wait(arch_rwlock_t *rw, unsigned int prev) } if ((old & 0x7fffffff) == 0 && (int) prev >= 0) break; + if (MACHINE_HAS_CAD) + _raw_compare_and_delay(&rw->lock, old); } } EXPORT_SYMBOL(_raw_write_lock_wait); @@ -201,6 +234,8 @@ void _raw_write_lock_wait(arch_rwlock_t *rw) smp_rmb(); if ((old & 0x7fffffff) == 0 && (int) prev >= 0) break; + if (MACHINE_HAS_CAD) + _raw_compare_and_delay(&rw->lock, old); } } EXPORT_SYMBOL(_raw_write_lock_wait); @@ -214,8 +249,11 @@ int _raw_write_trylock_retry(arch_rwlock_t *rw) while (count-- > 0) { old = ACCESS_ONCE(rw->lock); - if (old) + if (old) { + if (MACHINE_HAS_CAD) + _raw_compare_and_delay(&rw->lock, old); continue; + } if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) return 1; } diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 811937bb90be..3ff86533f7db 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -171,7 +171,7 @@ static void dump_pagetable(unsigned long asce, unsigned long address) table = table + ((address >> 20) & 0x7ff); if (bad_address(table)) goto bad; - pr_cont(KERN_CONT "S:%016lx ", *table); + pr_cont("S:%016lx ", *table); if (*table & (_SEGMENT_ENTRY_INVALID | _SEGMENT_ENTRY_LARGE)) goto out; table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN); @@ -261,7 +261,7 @@ static inline void report_user_fault(struct pt_regs *regs, long signr) return; if (!printk_ratelimit()) return; - printk(KERN_ALERT "User process fault: interruption code %04x ilc:%d", + printk(KERN_ALERT "User process fault: interruption code %04x ilc:%d ", regs->int_code & 0xffff, regs->int_code >> 17); print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN); printk(KERN_CONT "\n"); @@ -374,6 +374,12 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault) do_no_context(regs); else pagefault_out_of_memory(); + } else if (fault & VM_FAULT_SIGSEGV) { + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) + do_no_context(regs); + else + do_sigsegv(regs, SEGV_MAPERR); } else if (fault & VM_FAULT_SIGBUS) { /* Kernel mode? Handle exceptions or die */ if (!user_mode(regs)) diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c index 639fce464008..5c586c78ca8d 100644 --- a/arch/s390/mm/gup.c +++ b/arch/s390/mm/gup.c @@ -235,10 +235,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, /* Try to get the remaining pages with get_user_pages */ start += nr << PAGE_SHIFT; pages += nr; - down_read(&mm->mmap_sem); - ret = get_user_pages(current, mm, start, - nr_pages - nr, write, 0, pages, NULL); - up_read(&mm->mmap_sem); + ret = get_user_pages_unlocked(current, mm, start, + nr_pages - nr, write, 0, pages); /* Have to be a bit careful with return values */ if (nr > 0) ret = (ret < 0) ? nr : ret + nr; diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c index 3c80d2e38f03..210ffede0153 100644 --- a/arch/s390/mm/hugetlbpage.c +++ b/arch/s390/mm/hugetlbpage.c @@ -192,12 +192,6 @@ int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) return 0; } -struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, - int write) -{ - return ERR_PTR(-EINVAL); -} - int pmd_huge(pmd_t pmd) { if (!MACHINE_HAS_HPAGE) @@ -210,17 +204,3 @@ int pud_huge(pud_t pud) { return 0; } - -struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, - pmd_t *pmdp, int write) -{ - struct page *page; - - if (!MACHINE_HAS_HPAGE) - return NULL; - - page = pmd_page(*pmdp); - if (page) - page += ((address & ~HPAGE_MASK) >> PAGE_SHIFT); - return page; -} diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index c7235e01fd67..d35b15113b17 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -71,13 +71,16 @@ static void __init setup_zero_pages(void) break; case 0x2827: /* zEC12 */ case 0x2828: /* zEC12 */ - default: order = 5; break; + case 0x2964: /* z13 */ + default: + order = 7; + break; } /* Limit number of empty zero pages for small memory sizes */ - if (order > 2 && totalram_pages <= 16384) - order = 2; + while (order > 2 && (totalram_pages >> 10) < (1UL << order)) + order--; empty_zero_page = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order); if (!empty_zero_page) diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index 9b436c21195e..d008f638b2cd 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -28,8 +28,12 @@ #include #include #include +#include #include +unsigned long mmap_rnd_mask; +unsigned long mmap_align_mask; + static unsigned long stack_maxrandom_size(void) { if (!(current->flags & PF_RANDOMIZE)) @@ -60,8 +64,10 @@ static unsigned long mmap_rnd(void) { if (!(current->flags & PF_RANDOMIZE)) return 0; - /* 8MB randomization for mmap_base */ - return (get_random_int() & 0x7ffUL) << PAGE_SHIFT; + if (is_32bit_task()) + return (get_random_int() & 0x7ff) << PAGE_SHIFT; + else + return (get_random_int() & mmap_rnd_mask) << PAGE_SHIFT; } static unsigned long mmap_base_legacy(void) @@ -81,6 +87,106 @@ static inline unsigned long mmap_base(void) return STACK_TOP - stack_maxrandom_size() - mmap_rnd() - gap; } +unsigned long +arch_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + struct vm_unmapped_area_info info; + int do_color_align; + + if (len > TASK_SIZE - mmap_min_addr) + return -ENOMEM; + + if (flags & MAP_FIXED) + return addr; + + if (addr) { + addr = PAGE_ALIGN(addr); + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && + (!vma || addr + len <= vma->vm_start)) + return addr; + } + + do_color_align = 0; + if (filp || (flags & MAP_SHARED)) + do_color_align = !is_32bit_task(); + + info.flags = 0; + info.length = len; + info.low_limit = mm->mmap_base; + info.high_limit = TASK_SIZE; + info.align_mask = do_color_align ? (mmap_align_mask << PAGE_SHIFT) : 0; + info.align_offset = pgoff << PAGE_SHIFT; + return vm_unmapped_area(&info); +} + +unsigned long +arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, + const unsigned long len, const unsigned long pgoff, + const unsigned long flags) +{ + struct vm_area_struct *vma; + struct mm_struct *mm = current->mm; + unsigned long addr = addr0; + struct vm_unmapped_area_info info; + int do_color_align; + + /* requested length too big for entire address space */ + if (len > TASK_SIZE - mmap_min_addr) + return -ENOMEM; + + if (flags & MAP_FIXED) + return addr; + + /* requesting a specific address */ + if (addr) { + addr = PAGE_ALIGN(addr); + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && + (!vma || addr + len <= vma->vm_start)) + return addr; + } + + do_color_align = 0; + if (filp || (flags & MAP_SHARED)) + do_color_align = !is_32bit_task(); + + info.flags = VM_UNMAPPED_AREA_TOPDOWN; + info.length = len; + info.low_limit = max(PAGE_SIZE, mmap_min_addr); + info.high_limit = mm->mmap_base; + info.align_mask = do_color_align ? (mmap_align_mask << PAGE_SHIFT) : 0; + info.align_offset = pgoff << PAGE_SHIFT; + addr = vm_unmapped_area(&info); + + /* + * A failed mmap() very likely causes application failure, + * so fall back to the bottom-up function here. This scenario + * can happen with large stack limits and large mmap() + * allocations. + */ + if (addr & ~PAGE_MASK) { + VM_BUG_ON(addr != -ENOMEM); + info.flags = 0; + info.low_limit = TASK_UNMAPPED_BASE; + info.high_limit = TASK_SIZE; + addr = vm_unmapped_area(&info); + } + + return addr; +} + +unsigned long randomize_et_dyn(void) +{ + unsigned long base; + + base = (STACK_TOP / 3 * 2) & (~mmap_align_mask << PAGE_SHIFT); + return base + mmap_rnd(); +} + #ifndef CONFIG_64BIT /* @@ -177,4 +283,36 @@ void arch_pick_mmap_layout(struct mm_struct *mm) } } +static int __init setup_mmap_rnd(void) +{ + struct cpuid cpu_id; + + get_cpu_id(&cpu_id); + switch (cpu_id.machine) { + case 0x9672: + case 0x2064: + case 0x2066: + case 0x2084: + case 0x2086: + case 0x2094: + case 0x2096: + case 0x2097: + case 0x2098: + case 0x2817: + case 0x2818: + case 0x2827: + case 0x2828: + mmap_rnd_mask = 0x7ffUL; + mmap_align_mask = 0UL; + break; + case 0x2964: /* z13 */ + default: + mmap_rnd_mask = 0x3ff80UL; + mmap_align_mask = 0x7fUL; + break; + } + return 0; +} +early_initcall(setup_mmap_rnd); + #endif diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 3cf8cc03fff6..b2c1542f2ba2 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -527,7 +527,7 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr) table += (gaddr >> 53) & 0x7ff; if ((*table & _REGION_ENTRY_INVALID) && gmap_alloc_table(gmap, table, _REGION2_ENTRY_EMPTY, - gaddr & 0xffe0000000000000)) + gaddr & 0xffe0000000000000UL)) return -ENOMEM; table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); } @@ -535,7 +535,7 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr) table += (gaddr >> 42) & 0x7ff; if ((*table & _REGION_ENTRY_INVALID) && gmap_alloc_table(gmap, table, _REGION3_ENTRY_EMPTY, - gaddr & 0xfffffc0000000000)) + gaddr & 0xfffffc0000000000UL)) return -ENOMEM; table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); } @@ -543,7 +543,7 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr) table += (gaddr >> 31) & 0x7ff; if ((*table & _REGION_ENTRY_INVALID) && gmap_alloc_table(gmap, table, _SEGMENT_ENTRY_EMPTY, - gaddr & 0xffffffff80000000)) + gaddr & 0xffffffff80000000UL)) return -ENOMEM; table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); } diff --git a/arch/s390/net/bpf_jit.S b/arch/s390/net/bpf_jit.S index 7e45d13816c1..ba44c9f55346 100644 --- a/arch/s390/net/bpf_jit.S +++ b/arch/s390/net/bpf_jit.S @@ -22,8 +22,8 @@ * skb_copy_bits takes 4 parameters: * %r2 = skb pointer * %r3 = offset into skb data - * %r4 = length to copy - * %r5 = pointer to temp buffer + * %r4 = pointer to temp buffer + * %r5 = length to copy */ #define SKBDATA %r8 @@ -44,8 +44,9 @@ ENTRY(sk_load_word) sk_load_word_slow: lgr %r9,%r2 # save %r2 - lhi %r4,4 # 4 bytes - la %r5,160(%r15) # pointer to temp buffer + lgr %r3,%r1 # offset + la %r4,160(%r15) # pointer to temp buffer + lghi %r5,4 # 4 bytes brasl %r14,skb_copy_bits # get data from skb l %r5,160(%r15) # load result from temp buffer ltgr %r2,%r2 # set cc to (%r2 != 0) @@ -69,8 +70,9 @@ ENTRY(sk_load_half) sk_load_half_slow: lgr %r9,%r2 # save %r2 - lhi %r4,2 # 2 bytes - la %r5,162(%r15) # pointer to temp buffer + lgr %r3,%r1 # offset + la %r4,162(%r15) # pointer to temp buffer + lghi %r5,2 # 2 bytes brasl %r14,skb_copy_bits # get data from skb xc 160(2,%r15),160(%r15) l %r5,160(%r15) # load result from temp buffer @@ -95,8 +97,9 @@ ENTRY(sk_load_byte) sk_load_byte_slow: lgr %r9,%r2 # save %r2 - lhi %r4,1 # 1 bytes - la %r5,163(%r15) # pointer to temp buffer + lgr %r3,%r1 # offset + la %r4,163(%r15) # pointer to temp buffer + lghi %r5,1 # 1 byte brasl %r14,skb_copy_bits # get data from skb xc 160(3,%r15),160(%r15) l %r5,160(%r15) # load result from temp buffer @@ -104,11 +107,11 @@ sk_load_byte_slow: lgr %r2,%r9 # restore %r2 br %r8 - /* A = (*(u8 *)(skb->data+K) & 0xf) << 2 */ + /* X = (*(u8 *)(skb->data+K) & 0xf) << 2 */ ENTRY(sk_load_byte_msh) llgfr %r1,%r3 # extend offset clr %r11,%r3 # hlen < offset ? - jle sk_load_byte_slow + jle sk_load_byte_msh_slow lhi %r12,0 ic %r12,0(%r1,%r10) # get byte from skb nill %r12,0x0f @@ -118,8 +121,9 @@ ENTRY(sk_load_byte_msh) sk_load_byte_msh_slow: lgr %r9,%r2 # save %r2 - lhi %r4,2 # 2 bytes - la %r5,162(%r15) # pointer to temp buffer + lgr %r3,%r1 # offset + la %r4,163(%r15) # pointer to temp buffer + lghi %r5,1 # 1 byte brasl %r14,skb_copy_bits # get data from skb xc 160(3,%r15),160(%r15) l %r12,160(%r15) # load result from temp buffer diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index 524496d47ef5..bbd1981cc150 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -448,15 +448,12 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter, mask = 0x800000; /* je */ kbranch: /* Emit compare if the branch targets are different */ if (filter->jt != filter->jf) { - if (K <= 16383) - /* chi %r5, */ - EMIT4_IMM(0xa75e0000, K); - else if (test_facility(21)) + if (test_facility(21)) /* clfi %r5, */ EMIT6_IMM(0xc25f0000, K); else - /* c %r5,(%r13) */ - EMIT4_DISP(0x5950d000, EMIT_CONST(K)); + /* cl %r5,(%r13) */ + EMIT4_DISP(0x5550d000, EMIT_CONST(K)); } branch: if (filter->jt == filter->jf) { if (filter->jt == 0) diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c index 62c5ea6d8682..8aa271b3d1ad 100644 --- a/arch/s390/pci/pci_mmio.c +++ b/arch/s390/pci/pci_mmio.c @@ -55,7 +55,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr, ret = get_pfn(mmio_addr, VM_WRITE, &pfn); if (ret) goto out; - io_addr = (void *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK)); + io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK)); ret = -EFAULT; if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE) @@ -96,7 +96,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr, ret = get_pfn(mmio_addr, VM_READ, &pfn); if (ret) goto out; - io_addr = (void *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK)); + io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK)); ret = -EFAULT; if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE) diff --git a/arch/score/include/asm/pgtable-bits.h b/arch/score/include/asm/pgtable-bits.h index 7d65a96a82e5..0e5c6f466520 100644 --- a/arch/score/include/asm/pgtable-bits.h +++ b/arch/score/include/asm/pgtable-bits.h @@ -6,7 +6,6 @@ #define _PAGE_WRITE (1<<7) /* implemented in software */ #define _PAGE_PRESENT (1<<9) /* implemented in software */ #define _PAGE_MODIFIED (1<<10) /* implemented in software */ -#define _PAGE_FILE (1<<10) #define _PAGE_GLOBAL (1<<0) #define _PAGE_VALID (1<<1) diff --git a/arch/score/include/asm/pgtable.h b/arch/score/include/asm/pgtable.h index db96ad9afc03..0553e5cd5985 100644 --- a/arch/score/include/asm/pgtable.h +++ b/arch/score/include/asm/pgtable.h @@ -27,7 +27,7 @@ extern pte_t invalid_pte_table[PAGE_SIZE/sizeof(pte_t)]; #define PTRS_PER_PTE 1024 #define USER_PTRS_PER_PGD (0x80000000UL/PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define VMALLOC_START (0xc0000000UL) @@ -90,15 +90,6 @@ static inline void pmd_clear(pmd_t *pmdp) ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address)) #define pte_unmap(pte) ((void)(pte)) -/* - * Bits 9(_PAGE_PRESENT) and 10(_PAGE_FILE)are taken, - * split up 30 bits of offset into this range: - */ -#define PTE_FILE_MAX_BITS 30 -#define pte_to_pgoff(_pte) \ - (((_pte).pte & 0x1ff) | (((_pte).pte >> 11) << 9)) -#define pgoff_to_pte(off) \ - ((pte_t) {((off) & 0x1ff) | (((off) >> 9) << 11) | _PAGE_FILE}) #define __pte_to_swp_entry(pte) \ ((swp_entry_t) { pte_val(pte)}) #define __swp_entry_to_pte(x) ((pte_t) {(x).val}) @@ -169,8 +160,8 @@ static inline pgprot_t pgprot_noncached(pgprot_t _prot) } #define __swp_type(x) ((x).val & 0x1f) -#define __swp_offset(x) ((x).val >> 11) -#define __swp_entry(type, offset) ((swp_entry_t){(type) | ((offset) << 11)}) +#define __swp_offset(x) ((x).val >> 10) +#define __swp_entry(type, offset) ((swp_entry_t){(type) | ((offset) << 10)}) extern unsigned long empty_zero_page; extern unsigned long zero_page_mask; @@ -198,11 +189,6 @@ static inline int pte_young(pte_t pte) return pte_val(pte) & _PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) -{ - return pte_val(pte) & _PAGE_FILE; -} - #define pte_special(pte) (0) static inline pte_t pte_wrprotect(pte_t pte) diff --git a/arch/score/mm/fault.c b/arch/score/mm/fault.c index 52238983527d..6860beb2a280 100644 --- a/arch/score/mm/fault.c +++ b/arch/score/mm/fault.c @@ -114,6 +114,8 @@ good_area: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 0f09f5285d5e..eb4ef274ae9b 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -1,7 +1,7 @@ config SUPERH def_bool y select ARCH_MIGHT_HAVE_PC_PARPORT - select EXPERT + select HAVE_PATA_PLATFORM select CLKDEV_LOOKUP select HAVE_IDE if HAS_IOPORT_MAP select HAVE_MEMBLOCK diff --git a/arch/sh/boards/mach-se/7343/irq.c b/arch/sh/boards/mach-se/7343/irq.c index 7646bf0486c2..1087dba9b015 100644 --- a/arch/sh/boards/mach-se/7343/irq.c +++ b/arch/sh/boards/mach-se/7343/irq.c @@ -14,9 +14,6 @@ #define DRV_NAME "SE7343-FPGA" #define pr_fmt(fmt) DRV_NAME ": " fmt -#define irq_reg_readl ioread16 -#define irq_reg_writel iowrite16 - #include #include #include diff --git a/arch/sh/boards/mach-se/7722/irq.c b/arch/sh/boards/mach-se/7722/irq.c index f5e2af1bf040..00e699232621 100644 --- a/arch/sh/boards/mach-se/7722/irq.c +++ b/arch/sh/boards/mach-se/7722/irq.c @@ -11,9 +11,6 @@ #define DRV_NAME "SE7722-FPGA" #define pr_fmt(fmt) DRV_NAME ": " fmt -#define irq_reg_readl ioread16 -#define irq_reg_writel iowrite16 - #include #include #include diff --git a/arch/sh/include/asm/pgtable.h b/arch/sh/include/asm/pgtable.h index cf434c64408d..89c513a982fc 100644 --- a/arch/sh/include/asm/pgtable.h +++ b/arch/sh/include/asm/pgtable.h @@ -62,7 +62,7 @@ static inline unsigned long long neff_sign_extend(unsigned long val) /* Entries per level */ #define PTRS_PER_PTE (PAGE_SIZE / (1 << PTE_MAGNITUDE)) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define PHYS_ADDR_MASK29 0x1fffffff #define PHYS_ADDR_MASK32 0xffffffff diff --git a/arch/sh/include/asm/pgtable_32.h b/arch/sh/include/asm/pgtable_32.h index 0bce3d81569e..c646e563abce 100644 --- a/arch/sh/include/asm/pgtable_32.h +++ b/arch/sh/include/asm/pgtable_32.h @@ -26,8 +26,6 @@ * and timing control which (together with bit 0) are moved into the * old-style PTEA on the parts that support it. * - * XXX: Leave the _PAGE_FILE and _PAGE_WT overhaul for a rainy day. - * * SH-X2 MMUs and extended PTEs * * SH-X2 supports an extended mode TLB with split data arrays due to the @@ -51,7 +49,6 @@ #define _PAGE_PRESENT 0x100 /* V-bit : page is valid */ #define _PAGE_PROTNONE 0x200 /* software: if not present */ #define _PAGE_ACCESSED 0x400 /* software: page referenced */ -#define _PAGE_FILE _PAGE_WT /* software: pagecache or swap? */ #define _PAGE_SPECIAL 0x800 /* software: special page */ #define _PAGE_SZ_MASK (_PAGE_SZ0 | _PAGE_SZ1) @@ -105,14 +102,13 @@ static inline unsigned long copy_ptea_attributes(unsigned long x) /* Mask which drops unused bits from the PTEL value */ #if defined(CONFIG_CPU_SH3) #define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED| \ - _PAGE_FILE | _PAGE_SZ1 | \ - _PAGE_HW_SHARED) + _PAGE_SZ1 | _PAGE_HW_SHARED) #elif defined(CONFIG_X2TLB) /* Get rid of the legacy PR/SZ bits when using extended mode */ #define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | \ - _PAGE_FILE | _PAGE_PR_MASK | _PAGE_SZ_MASK) + _PAGE_PR_MASK | _PAGE_SZ_MASK) #else -#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_FILE) +#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED) #endif #define _PAGE_FLAGS_HARDWARE_MASK (phys_addr_mask() & ~(_PAGE_CLEAR_FLAGS)) @@ -343,7 +339,6 @@ static inline void set_pte(pte_t *ptep, pte_t pte) #define pte_not_present(pte) (!((pte).pte_low & _PAGE_PRESENT)) #define pte_dirty(pte) ((pte).pte_low & _PAGE_DIRTY) #define pte_young(pte) ((pte).pte_low & _PAGE_ACCESSED) -#define pte_file(pte) ((pte).pte_low & _PAGE_FILE) #define pte_special(pte) ((pte).pte_low & _PAGE_SPECIAL) #ifdef CONFIG_X2TLB @@ -445,7 +440,6 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) * Encode and de-code a swap entry * * Constraints: - * _PAGE_FILE at bit 0 * _PAGE_PRESENT at bit 8 * _PAGE_PROTNONE at bit 9 * @@ -453,9 +447,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) * swap offset into bits 10:30. For the 64-bit PTE case, we keep the * preserved bits in the low 32-bits and use the upper 32 as the swap * offset (along with a 5-bit type), following the same approach as x86 - * PAE. This keeps the logic quite simple, and allows for a full 32 - * PTE_FILE_MAX_BITS, as opposed to the 29-bits we're constrained with - * in the pte_low case. + * PAE. This keeps the logic quite simple. * * As is evident by the Alpha code, if we ever get a 64-bit unsigned * long (swp_entry_t) to match up with the 64-bit PTEs, this all becomes @@ -471,13 +463,6 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) #define __pte_to_swp_entry(pte) ((swp_entry_t){ (pte).pte_high }) #define __swp_entry_to_pte(x) ((pte_t){ 0, (x).val }) -/* - * Encode and decode a nonlinear file mapping entry - */ -#define pte_to_pgoff(pte) ((pte).pte_high) -#define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) }) - -#define PTE_FILE_MAX_BITS 32 #else #define __swp_type(x) ((x).val & 0xff) #define __swp_offset(x) ((x).val >> 10) @@ -485,13 +470,6 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) >> 1 }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val << 1 }) - -/* - * Encode and decode a nonlinear file mapping entry - */ -#define PTE_FILE_MAX_BITS 29 -#define pte_to_pgoff(pte) (pte_val(pte) >> 1) -#define pgoff_to_pte(off) ((pte_t) { ((off) << 1) | _PAGE_FILE }) #endif #endif /* __ASSEMBLY__ */ diff --git a/arch/sh/include/asm/pgtable_64.h b/arch/sh/include/asm/pgtable_64.h index dda8c82601b9..07424968df62 100644 --- a/arch/sh/include/asm/pgtable_64.h +++ b/arch/sh/include/asm/pgtable_64.h @@ -107,7 +107,6 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval) #define _PAGE_DEVICE 0x001 /* CB0: if uncacheable, 1->device (i.e. no write-combining or reordering at bus level) */ #define _PAGE_CACHABLE 0x002 /* CB1: uncachable/cachable */ #define _PAGE_PRESENT 0x004 /* software: page referenced */ -#define _PAGE_FILE 0x004 /* software: only when !present */ #define _PAGE_SIZE0 0x008 /* SZ0-bit : size of page */ #define _PAGE_SIZE1 0x010 /* SZ1-bit : size of page */ #define _PAGE_SHARED 0x020 /* software: reflects PTEH's SH */ @@ -129,7 +128,7 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval) #define _PAGE_WIRED _PAGE_EXT(0x001) /* software: wire the tlb entry */ #define _PAGE_SPECIAL _PAGE_EXT(0x002) -#define _PAGE_CLEAR_FLAGS (_PAGE_PRESENT | _PAGE_FILE | _PAGE_SHARED | \ +#define _PAGE_CLEAR_FLAGS (_PAGE_PRESENT | _PAGE_SHARED | \ _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_WIRED) /* Mask which drops software flags */ @@ -260,7 +259,6 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval) */ static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } static inline int pte_special(pte_t pte){ return pte_val(pte) & _PAGE_SPECIAL; } @@ -304,11 +302,6 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -/* Encode and decode a nonlinear file mapping entry */ -#define PTE_FILE_MAX_BITS 29 -#define pte_to_pgoff(pte) (pte_val(pte)) -#define pgoff_to_pte(off) ((pte_t) { (off) | _PAGE_FILE }) - #endif /* !__ASSEMBLY__ */ #define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 541dc6101508..a58fec9b55e0 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c @@ -353,6 +353,8 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code, } else { if (fault & VM_FAULT_SIGBUS) do_sigbus(regs, error_code, address); + else if (fault & VM_FAULT_SIGSEGV) + bad_area(regs, error_code, address); else BUG(); } diff --git a/arch/sh/mm/gup.c b/arch/sh/mm/gup.c index 37458f38b220..e15f52a17b6c 100644 --- a/arch/sh/mm/gup.c +++ b/arch/sh/mm/gup.c @@ -257,10 +257,8 @@ slow_irqon: start += nr << PAGE_SHIFT; pages += nr; - down_read(&mm->mmap_sem); - ret = get_user_pages(current, mm, start, - (end - start) >> PAGE_SHIFT, write, 0, pages, NULL); - up_read(&mm->mmap_sem); + ret = get_user_pages_unlocked(current, mm, start, + (end - start) >> PAGE_SHIFT, write, 0, pages); /* Have to be a bit careful with return values */ if (nr > 0) { diff --git a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c index d7762349ea48..534bc978af8a 100644 --- a/arch/sh/mm/hugetlbpage.c +++ b/arch/sh/mm/hugetlbpage.c @@ -67,12 +67,6 @@ int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) return 0; } -struct page *follow_huge_addr(struct mm_struct *mm, - unsigned long address, int write) -{ - return ERR_PTR(-EINVAL); -} - int pmd_huge(pmd_t pmd) { return 0; @@ -82,9 +76,3 @@ int pud_huge(pud_t pud) { return 0; } - -struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, - pmd_t *pmd, int write) -{ - return NULL; -} diff --git a/arch/sparc/include/asm/cacheflush_64.h b/arch/sparc/include/asm/cacheflush_64.h index 38965379e350..68513c41e10d 100644 --- a/arch/sparc/include/asm/cacheflush_64.h +++ b/arch/sparc/include/asm/cacheflush_64.h @@ -74,11 +74,6 @@ void flush_ptrace_access(struct vm_area_struct *, struct page *, #define flush_cache_vmap(start, end) do { } while (0) #define flush_cache_vunmap(start, end) do { } while (0) -#ifdef CONFIG_DEBUG_PAGEALLOC -/* internal debugging function */ -void kernel_map_pages(struct page *page, int numpages, int enable); -#endif - #endif /* !__ASSEMBLY__ */ #endif /* _SPARC64_CACHEFLUSH_H */ diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h index b9b91ae19fe1..f06b36a00a3b 100644 --- a/arch/sparc/include/asm/pgtable_32.h +++ b/arch/sparc/include/asm/pgtable_32.h @@ -44,7 +44,7 @@ unsigned long __init bootmem_init(unsigned long *pages_avail); #define PTRS_PER_PMD SRMMU_PTRS_PER_PMD #define PTRS_PER_PGD SRMMU_PTRS_PER_PGD #define USER_PTRS_PER_PGD PAGE_OFFSET / SRMMU_PGDIR_SIZE -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define PTE_SIZE (PTRS_PER_PTE*4) #define PAGE_NONE SRMMU_PAGE_NONE @@ -102,7 +102,8 @@ extern unsigned long empty_zero_page; */ static inline unsigned long srmmu_swap(unsigned long *addr, unsigned long value) { - __asm__ __volatile__("swap [%2], %0" : "=&r" (value) : "0" (value), "r" (addr)); + __asm__ __volatile__("swap [%2], %0" : + "=&r" (value) : "0" (value), "r" (addr) : "memory"); return value; } @@ -221,14 +222,6 @@ static inline int pte_young(pte_t pte) return pte_val(pte) & SRMMU_REF; } -/* - * The following only work if pte_present() is not true. - */ -static inline int pte_file(pte_t pte) -{ - return pte_val(pte) & SRMMU_FILE; -} - static inline int pte_special(pte_t pte) { return 0; @@ -375,22 +368,6 @@ static inline swp_entry_t __swp_entry(unsigned long type, unsigned long offset) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -/* file-offset-in-pte helpers */ -static inline unsigned long pte_to_pgoff(pte_t pte) -{ - return pte_val(pte) >> SRMMU_PTE_FILE_SHIFT; -} - -static inline pte_t pgoff_to_pte(unsigned long pgoff) -{ - return __pte((pgoff << SRMMU_PTE_FILE_SHIFT) | SRMMU_FILE); -} - -/* - * This is made a constant because mm/fremap.c required a constant. - */ -#define PTE_FILE_MAX_BITS 24 - static inline unsigned long __get_phys (unsigned long addr) { diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 1ff9e7864168..dc165ebdf05a 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -93,7 +93,7 @@ bool kern_addr_valid(unsigned long addr); #define PTRS_PER_PGD (1UL << PGDIR_BITS) /* Kernel has a separate 44bit address space. */ -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define pmd_ERROR(e) \ pr_err("%s:%d: bad pmd %p(%016lx) seen at (%pS)\n", \ @@ -137,7 +137,6 @@ bool kern_addr_valid(unsigned long addr); #define _PAGE_SOFT_4U _AC(0x0000000000001F80,UL) /* Software bits: */ #define _PAGE_EXEC_4U _AC(0x0000000000001000,UL) /* Executable SW bit */ #define _PAGE_MODIFIED_4U _AC(0x0000000000000800,UL) /* Modified (dirty) */ -#define _PAGE_FILE_4U _AC(0x0000000000000800,UL) /* Pagecache page */ #define _PAGE_ACCESSED_4U _AC(0x0000000000000400,UL) /* Accessed (ref'd) */ #define _PAGE_READ_4U _AC(0x0000000000000200,UL) /* Readable SW Bit */ #define _PAGE_WRITE_4U _AC(0x0000000000000100,UL) /* Writable SW Bit */ @@ -167,7 +166,6 @@ bool kern_addr_valid(unsigned long addr); #define _PAGE_EXEC_4V _AC(0x0000000000000080,UL) /* Executable Page */ #define _PAGE_W_4V _AC(0x0000000000000040,UL) /* Writable */ #define _PAGE_SOFT_4V _AC(0x0000000000000030,UL) /* Software bits */ -#define _PAGE_FILE_4V _AC(0x0000000000000020,UL) /* Pagecache page */ #define _PAGE_PRESENT_4V _AC(0x0000000000000010,UL) /* Present */ #define _PAGE_RESV_4V _AC(0x0000000000000008,UL) /* Reserved */ #define _PAGE_SZ16GB_4V _AC(0x0000000000000007,UL) /* 16GB Page */ @@ -332,22 +330,6 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) } #endif -static inline pte_t pgoff_to_pte(unsigned long off) -{ - off <<= PAGE_SHIFT; - - __asm__ __volatile__( - "\n661: or %0, %2, %0\n" - " .section .sun4v_1insn_patch, \"ax\"\n" - " .word 661b\n" - " or %0, %3, %0\n" - " .previous\n" - : "=r" (off) - : "0" (off), "i" (_PAGE_FILE_4U), "i" (_PAGE_FILE_4V)); - - return __pte(off); -} - static inline pgprot_t pgprot_noncached(pgprot_t prot) { unsigned long val = pgprot_val(prot); @@ -609,22 +591,6 @@ static inline unsigned long pte_exec(pte_t pte) return (pte_val(pte) & mask); } -static inline unsigned long pte_file(pte_t pte) -{ - unsigned long val = pte_val(pte); - - __asm__ __volatile__( - "\n661: and %0, %2, %0\n" - " .section .sun4v_1insn_patch, \"ax\"\n" - " .word 661b\n" - " and %0, %3, %0\n" - " .previous\n" - : "=r" (val) - : "0" (val), "i" (_PAGE_FILE_4U), "i" (_PAGE_FILE_4V)); - - return val; -} - static inline unsigned long pte_present(pte_t pte) { unsigned long val = pte_val(pte); @@ -971,12 +937,6 @@ pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -/* File offset in PTE support. */ -unsigned long pte_file(pte_t); -#define pte_to_pgoff(pte) (pte_val(pte) >> PAGE_SHIFT) -pte_t pgoff_to_pte(unsigned long); -#define PTE_FILE_MAX_BITS (64UL - PAGE_SHIFT - 1UL) - int page_in_phys_avail(unsigned long paddr); /* diff --git a/arch/sparc/include/asm/pgtsrmmu.h b/arch/sparc/include/asm/pgtsrmmu.h index 79da17866fa8..ae51a111a8c7 100644 --- a/arch/sparc/include/asm/pgtsrmmu.h +++ b/arch/sparc/include/asm/pgtsrmmu.h @@ -80,10 +80,6 @@ #define SRMMU_PRIV 0x1c #define SRMMU_PRIV_RDONLY 0x18 -#define SRMMU_FILE 0x40 /* Implemented in software */ - -#define SRMMU_PTE_FILE_SHIFT 8 /* == 32-PTE_FILE_MAX_BITS */ - #define SRMMU_CHG_MASK (0xffffff00 | SRMMU_REF | SRMMU_DIRTY) /* SRMMU swap entry encoding @@ -94,13 +90,13 @@ * oooooooooooooooooootttttRRRRRRRR * fedcba9876543210fedcba9876543210 * - * The bottom 8 bits are reserved for protection and status bits, especially - * FILE and PRESENT. + * The bottom 7 bits are reserved for protection and status bits, especially + * PRESENT. */ #define SRMMU_SWP_TYPE_MASK 0x1f -#define SRMMU_SWP_TYPE_SHIFT SRMMU_PTE_FILE_SHIFT -#define SRMMU_SWP_OFF_MASK 0x7ffff -#define SRMMU_SWP_OFF_SHIFT (SRMMU_PTE_FILE_SHIFT + 5) +#define SRMMU_SWP_TYPE_SHIFT 7 +#define SRMMU_SWP_OFF_MASK 0xfffff +#define SRMMU_SWP_OFF_SHIFT (SRMMU_SWP_TYPE_SHIFT + 5) /* Some day I will implement true fine grained access bits for * user pages because the SRMMU gives us the capabilities to diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index b36365f49478..9ce5afe167ff 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -639,7 +639,10 @@ static void pci_claim_bus_resources(struct pci_bus *bus) (unsigned long long)r->end, (unsigned int)r->flags); - pci_claim_resource(dev, i); + if (pci_claim_resource(dev, i) == 0) + continue; + + pci_claim_bridge_resource(dev, i); } } diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c index 908e8c17c902..70d817154fe8 100644 --- a/arch/sparc/mm/fault_32.c +++ b/arch/sparc/mm/fault_32.c @@ -249,6 +249,8 @@ good_area: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c index 18fcd7167095..479823249429 100644 --- a/arch/sparc/mm/fault_64.c +++ b/arch/sparc/mm/fault_64.c @@ -446,6 +446,8 @@ good_area: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/sparc/mm/gup.c b/arch/sparc/mm/gup.c index ae6ce383d4df..2e5c4fc2daa9 100644 --- a/arch/sparc/mm/gup.c +++ b/arch/sparc/mm/gup.c @@ -249,10 +249,8 @@ slow: start += nr << PAGE_SHIFT; pages += nr; - down_read(&mm->mmap_sem); - ret = get_user_pages(current, mm, start, - (end - start) >> PAGE_SHIFT, write, 0, pages, NULL); - up_read(&mm->mmap_sem); + ret = get_user_pages_unlocked(current, mm, start, + (end - start) >> PAGE_SHIFT, write, 0, pages); /* Have to be a bit careful with return values */ if (nr > 0) { diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c index d329537739c6..4242eab12e10 100644 --- a/arch/sparc/mm/hugetlbpage.c +++ b/arch/sparc/mm/hugetlbpage.c @@ -215,12 +215,6 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, return entry; } -struct page *follow_huge_addr(struct mm_struct *mm, - unsigned long address, int write) -{ - return ERR_PTR(-EINVAL); -} - int pmd_huge(pmd_t pmd) { return 0; @@ -230,9 +224,3 @@ int pud_huge(pud_t pud) { return 0; } - -struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, - pmd_t *pmd, int write) -{ - return NULL; -} diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c index f33e7c7a3bf7..7931eeeb649a 100644 --- a/arch/sparc/net/bpf_jit_comp.c +++ b/arch/sparc/net/bpf_jit_comp.c @@ -776,7 +776,7 @@ cond_branch: f_offset = addrs[i + filter[i].jf]; if (unlikely(proglen + ilen > oldproglen)) { pr_err("bpb_jit_compile fatal error\n"); kfree(addrs); - module_free(NULL, image); + module_memfree(image); return; } memcpy(image + proglen, temp, ilen); @@ -822,7 +822,7 @@ out: void bpf_jit_free(struct bpf_prog *fp) { if (fp->jited) - module_free(NULL, fp->bpf_func); + module_memfree(fp->bpf_func); bpf_prog_unlock_free(fp); } diff --git a/arch/tile/include/asm/pgtable.h b/arch/tile/include/asm/pgtable.h index 5d1950788c69..95a4f19d16c5 100644 --- a/arch/tile/include/asm/pgtable.h +++ b/arch/tile/include/asm/pgtable.h @@ -67,7 +67,7 @@ extern void pgtable_cache_init(void); extern void paging_init(void); extern void set_page_homes(void); -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define _PAGE_PRESENT HV_PTE_PRESENT #define _PAGE_HUGE_PAGE HV_PTE_PAGE @@ -284,17 +284,6 @@ static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot) extern void start_mm_caching(struct mm_struct *mm); extern void check_mm_caching(struct mm_struct *prev, struct mm_struct *next); -/* - * Support non-linear file mappings (see sys_remap_file_pages). - * This is defined by CLIENT1 set but CLIENT0 and _PAGE_PRESENT clear, and the - * file offset in the 32 high bits. - */ -#define _PAGE_FILE HV_PTE_CLIENT1 -#define PTE_FILE_MAX_BITS 32 -#define pte_file(pte) (hv_pte_get_client1(pte) && !hv_pte_get_client0(pte)) -#define pte_to_pgoff(pte) ((pte).val >> 32) -#define pgoff_to_pte(off) ((pte_t) { (((long long)(off)) << 32) | _PAGE_FILE }) - /* * Encode and de-code a swap entry (see ). * We put the swap file type+offset in the 32 high bits; diff --git a/arch/tile/kernel/module.c b/arch/tile/kernel/module.c index 96447c9160a0..2305084c9b93 100644 --- a/arch/tile/kernel/module.c +++ b/arch/tile/kernel/module.c @@ -74,7 +74,7 @@ error: /* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) +void module_memfree(void *module_region) { vfree(module_region); @@ -83,7 +83,7 @@ void module_free(struct module *mod, void *module_region) 0, 0, 0, NULL, NULL, 0); /* - * FIXME: If module_region == mod->module_init, trim exception + * FIXME: Add module_arch_freeing_init to trim exception * table entries. */ } diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c index f70c7892fa25..325df47f114d 100644 --- a/arch/tile/kernel/pci.c +++ b/arch/tile/kernel/pci.c @@ -245,7 +245,7 @@ static void fixup_read_and_payload_sizes(void) { struct pci_dev *dev = NULL; int smallest_max_payload = 0x1; /* Tile maxes out at 256 bytes. */ - int max_read_size = 0x2; /* Limit to 512 byte reads. */ + int max_read_size = PCI_EXP_DEVCTL_READRQ_512B; u16 new_values; /* Scan for the smallest maximum payload size. */ @@ -258,7 +258,7 @@ static void fixup_read_and_payload_sizes(void) } /* Now, set the max_payload_size for all devices to that value. */ - new_values = (max_read_size << 12) | (smallest_max_payload << 5); + new_values = max_read_size | (smallest_max_payload << 5); for_each_pci_dev(dev) pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ, diff --git a/arch/tile/kvm/Kconfig b/arch/tile/kvm/Kconfig index 2298cb1daff7..1e968f7550dc 100644 --- a/arch/tile/kvm/Kconfig +++ b/arch/tile/kvm/Kconfig @@ -21,6 +21,7 @@ config KVM depends on HAVE_KVM && MODULES select PREEMPT_NOTIFIERS select ANON_INODES + select SRCU ---help--- Support hosting paravirtualized guest machines. diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c index 565e25a98334..0f61a73534e6 100644 --- a/arch/tile/mm/fault.c +++ b/arch/tile/mm/fault.c @@ -442,6 +442,8 @@ good_area: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/arch/tile/mm/homecache.c b/arch/tile/mm/homecache.c index cd3387370ebb..0029b3fb651b 100644 --- a/arch/tile/mm/homecache.c +++ b/arch/tile/mm/homecache.c @@ -263,10 +263,6 @@ static int pte_to_home(pte_t pte) /* Update the home of a PTE if necessary (can also be used for a pgprot_t). */ pte_t pte_set_home(pte_t pte, int home) { - /* Check for non-linear file mapping "PTEs" and pass them through. */ - if (pte_file(pte)) - return pte; - #if CHIP_HAS_MMIO() /* Check for MMIO mappings and pass them through. */ if (hv_pte_get_mode(pte) == HV_PTE_MODE_MMIO) diff --git a/arch/tile/mm/hugetlbpage.c b/arch/tile/mm/hugetlbpage.c index 3270e0019266..8416240c322c 100644 --- a/arch/tile/mm/hugetlbpage.c +++ b/arch/tile/mm/hugetlbpage.c @@ -150,12 +150,6 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) return NULL; } -struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, - int write) -{ - return ERR_PTR(-EINVAL); -} - int pmd_huge(pmd_t pmd) { return !!(pmd_val(pmd) & _PAGE_HUGE_PAGE); @@ -166,28 +160,6 @@ int pud_huge(pud_t pud) return !!(pud_val(pud) & _PAGE_HUGE_PAGE); } -struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, - pmd_t *pmd, int write) -{ - struct page *page; - - page = pte_page(*(pte_t *)pmd); - if (page) - page += ((address & ~PMD_MASK) >> PAGE_SHIFT); - return page; -} - -struct page *follow_huge_pud(struct mm_struct *mm, unsigned long address, - pud_t *pud, int write) -{ - struct page *page; - - page = pte_page(*(pte_t *)pud); - if (page) - page += ((address & ~PUD_MASK) >> PAGE_SHIFT); - return page; -} - int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) { return 0; diff --git a/arch/um/include/asm/pgtable-2level.h b/arch/um/include/asm/pgtable-2level.h index f534b73e753e..cfbe59752469 100644 --- a/arch/um/include/asm/pgtable-2level.h +++ b/arch/um/include/asm/pgtable-2level.h @@ -23,7 +23,7 @@ #define PTRS_PER_PTE 1024 #define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE) #define PTRS_PER_PGD 1024 -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define pte_ERROR(e) \ printk("%s:%d: bad pte %p(%08lx).\n", __FILE__, __LINE__, &(e), \ @@ -41,13 +41,4 @@ static inline void pgd_mkuptodate(pgd_t pgd) { } #define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot)) #define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot)) -/* - * Bits 0 through 4 are taken - */ -#define PTE_FILE_MAX_BITS 27 - -#define pte_to_pgoff(pte) (pte_val(pte) >> 5) - -#define pgoff_to_pte(off) ((pte_t) { ((off) << 5) + _PAGE_FILE }) - #endif diff --git a/arch/um/include/asm/pgtable-3level.h b/arch/um/include/asm/pgtable-3level.h index 0032f9212e74..2b4274e7c095 100644 --- a/arch/um/include/asm/pgtable-3level.h +++ b/arch/um/include/asm/pgtable-3level.h @@ -41,7 +41,7 @@ #endif #define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define pte_ERROR(e) \ printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), \ @@ -112,25 +112,5 @@ static inline pmd_t pfn_pmd(pfn_t page_nr, pgprot_t pgprot) return __pmd((page_nr << PAGE_SHIFT) | pgprot_val(pgprot)); } -/* - * Bits 0 through 3 are taken in the low part of the pte, - * put the 32 bits of offset into the high part. - */ -#define PTE_FILE_MAX_BITS 32 - -#ifdef CONFIG_64BIT - -#define pte_to_pgoff(p) ((p).pte >> 32) - -#define pgoff_to_pte(off) ((pte_t) { ((off) << 32) | _PAGE_FILE }) - -#else - -#define pte_to_pgoff(pte) ((pte).pte_high) - -#define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) }) - -#endif - #endif diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h index bf974f712af7..2324b624f195 100644 --- a/arch/um/include/asm/pgtable.h +++ b/arch/um/include/asm/pgtable.h @@ -18,7 +18,6 @@ #define _PAGE_ACCESSED 0x080 #define _PAGE_DIRTY 0x100 /* If _PAGE_PRESENT is clear, we use these: */ -#define _PAGE_FILE 0x008 /* nonlinear file mapping, saved PTE; unset:swap */ #define _PAGE_PROTNONE 0x010 /* if the user mapped it with PROT_NONE; pte_present gives true */ @@ -151,14 +150,6 @@ static inline int pte_write(pte_t pte) !(pte_get_bits(pte, _PAGE_PROTNONE))); } -/* - * The following only works if pte_present() is not true. - */ -static inline int pte_file(pte_t pte) -{ - return pte_get_bits(pte, _PAGE_FILE); -} - static inline int pte_dirty(pte_t pte) { return pte_get_bits(pte, _PAGE_DIRTY); diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index 5678c3571e7c..209617302df8 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -80,6 +80,8 @@ good_area: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) { goto out_of_memory; + } else if (fault & VM_FAULT_SIGSEGV) { + goto out; } else if (fault & VM_FAULT_SIGBUS) { err = -EACCES; goto out; diff --git a/arch/unicore32/include/asm/pgtable-hwdef.h b/arch/unicore32/include/asm/pgtable-hwdef.h index 7314e859cca0..e37fa471c2be 100644 --- a/arch/unicore32/include/asm/pgtable-hwdef.h +++ b/arch/unicore32/include/asm/pgtable-hwdef.h @@ -44,7 +44,6 @@ #define PTE_TYPE_INVALID (3 << 0) #define PTE_PRESENT (1 << 2) -#define PTE_FILE (1 << 3) /* only when !PRESENT */ #define PTE_YOUNG (1 << 3) #define PTE_DIRTY (1 << 4) #define PTE_CACHEABLE (1 << 5) diff --git a/arch/unicore32/include/asm/pgtable.h b/arch/unicore32/include/asm/pgtable.h index ed6f7d000fba..818d0f5598e3 100644 --- a/arch/unicore32/include/asm/pgtable.h +++ b/arch/unicore32/include/asm/pgtable.h @@ -283,20 +283,6 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; #define MAX_SWAPFILES_CHECK() \ BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS) -/* - * Encode and decode a file entry. File entries are stored in the Linux - * page tables as follows: - * - * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * <----------------------- offset ----------------------> 1 0 0 0 - */ -#define pte_file(pte) (pte_val(pte) & PTE_FILE) -#define pte_to_pgoff(x) (pte_val(x) >> 4) -#define pgoff_to_pte(x) __pte(((x) << 4) | PTE_FILE) - -#define PTE_FILE_MAX_BITS 28 - /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ /* FIXME: this is not correct */ #define kern_addr_valid(addr) (1) diff --git a/arch/unicore32/mm/pgd.c b/arch/unicore32/mm/pgd.c index 08b8d4295e70..2ade20d8eab3 100644 --- a/arch/unicore32/mm/pgd.c +++ b/arch/unicore32/mm/pgd.c @@ -69,6 +69,7 @@ pgd_t *get_pgd_slow(struct mm_struct *mm) no_pte: pmd_free(mm, new_pmd); + mm_dec_nr_pmds(mm); no_pmd: free_pages((unsigned long)new_pgd, 0); no_pgd: @@ -96,7 +97,9 @@ void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd) pte = pmd_pgtable(*pmd); pmd_clear(pmd); pte_free(mm, pte); + atomic_long_dec(&mm->nr_ptes); pmd_free(mm, pmd); + mm_dec_nr_pmds(mm); free: free_pages((unsigned long) pgd, 0); } diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ba397bde7948..33ce9a344e38 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -17,6 +17,7 @@ config X86_64 depends on 64BIT select X86_DEV_DMA_OPS select ARCH_USE_CMPXCHG_LOCKREF + select HAVE_LIVEPATCH ### Arch settings config X86 @@ -138,6 +139,7 @@ config X86 select HAVE_ACPI_APEI_NMI if ACPI select ACPI_LEGACY_TABLES_LOOKUP if ACPI select X86_FEATURE_NAMES if PROC_FS + select SRCU config INSTRUCTION_DECODER def_bool y @@ -496,6 +498,17 @@ config X86_INTEL_LPSS things like clock tree (common clock framework) and pincontrol which are needed by the LPSS peripheral drivers. +config X86_AMD_PLATFORM_DEVICE + bool "AMD ACPI2Platform devices support" + depends on ACPI + select COMMON_CLK + select PINCTRL + ---help--- + Select to interpret AMD specific ACPI device to platform device + such as I2C, UART, GPIO found on AMD Carrizo and later chipsets. + I2C and UART depend on COMMON_CLK to set clock. GPIO driver is + implemented under PINCTRL subsystem. + config IOSF_MBI tristate "Intel SoC IOSF Sideband support for SoC platforms" depends on PCI @@ -855,9 +868,13 @@ config SCHED_MC source "kernel/Kconfig.preempt" +config UP_LATE_INIT + def_bool y + depends on !SMP && X86_LOCAL_APIC + config X86_UP_APIC bool "Local APIC support on uniprocessors" - depends on X86_32 && !SMP && !X86_32_NON_STANDARD && !PCI_MSI + depends on X86_32 && !SMP && !X86_32_NON_STANDARD ---help--- A local APIC (Advanced Programmable Interrupt Controller) is an integrated interrupt controller in the CPU. If you have a single-CPU @@ -868,6 +885,10 @@ config X86_UP_APIC performance counters), and the NMI watchdog which detects hard lockups. +config X86_UP_APIC_MSI + def_bool y + select X86_UP_APIC if X86_32 && !SMP && !X86_32_NON_STANDARD && PCI_MSI + config X86_UP_IOAPIC bool "IO-APIC support on uniprocessors" depends on X86_UP_APIC @@ -2008,6 +2029,8 @@ config CMDLINE_OVERRIDE This is used to work around broken boot loaders. This should be set to 'N' under normal conditions. +source "kernel/livepatch/Kconfig" + endmenu config ARCH_ENABLE_MEMORY_HOTPLUG diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 920e6160c535..5ba2d9ce82dc 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -148,6 +148,7 @@ cfi-sections := $(call as-instr,.cfi_sections .debug_frame,-DCONFIG_AS_CFI_SECTI # does binutils support specific instructions? asinstr := $(call as-instr,fxsaveq (%rax),-DCONFIG_AS_FXSAVEQ=1) +asinstr += $(call as-instr,pshufb %xmm0$(comma)%xmm0,-DCONFIG_AS_SSSE3=1) asinstr += $(call as-instr,crc32l %eax$(comma)%eax,-DCONFIG_AS_CRC32=1) avx_instr := $(call as-instr,vxorps %ymm0$(comma)%ymm1$(comma)%ymm2,-DCONFIG_AS_AVX=1) avx2_instr :=$(call as-instr,vpbroadcastb %xmm0$(comma)%ymm1,-DCONFIG_AS_AVX2=1) diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index d999398928bc..ad754b4411f7 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -90,7 +90,7 @@ suffix-$(CONFIG_KERNEL_LZO) := lzo suffix-$(CONFIG_KERNEL_LZ4) := lz4 RUN_SIZE = $(shell $(OBJDUMP) -h vmlinux | \ - perl $(srctree)/arch/x86/tools/calc_run_size.pl) + $(CONFIG_SHELL) $(srctree)/arch/x86/tools/calc_run_size.sh) quiet_cmd_mkpiggy = MKPIGGY $@ cmd_mkpiggy = $(obj)/mkpiggy $< $(RUN_SIZE) > $@ || ( rm -f $@ ; false ) diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index dcc1c536cc21..a950864a64da 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -373,6 +373,8 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap, unsigned long output_len, unsigned long run_size) { + unsigned char *output_orig = output; + real_mode = rmode; sanitize_boot_params(real_mode); @@ -421,7 +423,12 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap, debug_putstr("\nDecompressing Linux... "); decompress(input_data, input_len, NULL, NULL, output, NULL, error); parse_elf(output); - handle_relocations(output, output_len); + /* + * 32-bit always performs relocations. 64-bit relocations are only + * needed if kASLR has chosen a different load address. + */ + if (!IS_ENABLED(CONFIG_X86_64) || output != output_orig) + handle_relocations(output, output_len); debug_putstr("done.\nBooting the kernel.\n"); return output; } diff --git a/arch/x86/boot/ctype.h b/arch/x86/boot/ctype.h index 25e13403193c..020f137df7a2 100644 --- a/arch/x86/boot/ctype.h +++ b/arch/x86/boot/ctype.h @@ -1,6 +1,5 @@ -#ifndef BOOT_ISDIGIT_H - -#define BOOT_ISDIGIT_H +#ifndef BOOT_CTYPE_H +#define BOOT_CTYPE_H static inline int isdigit(int ch) { diff --git a/arch/x86/boot/early_serial_console.c b/arch/x86/boot/early_serial_console.c index 5df2869c874b..45a07684bbab 100644 --- a/arch/x86/boot/early_serial_console.c +++ b/arch/x86/boot/early_serial_console.c @@ -2,8 +2,6 @@ #define DEFAULT_SERIAL_PORT 0x3f8 /* ttyS0 */ -#define XMTRDY 0x20 - #define DLAB 0x80 #define TXR 0 /* Transmit register (WRITE) */ @@ -74,8 +72,8 @@ static void parse_earlyprintk(void) static const int bases[] = { 0x3f8, 0x2f8 }; int idx = 0; - if (!strncmp(arg + pos, "ttyS", 4)) - pos += 4; + /* += strlen("ttyS"); */ + pos += 4; if (arg[pos++] == '1') idx = 1; diff --git a/arch/x86/crypto/sha-mb/sha1_mb.c b/arch/x86/crypto/sha-mb/sha1_mb.c index a225a5ca1037..fd9f6b035b16 100644 --- a/arch/x86/crypto/sha-mb/sha1_mb.c +++ b/arch/x86/crypto/sha-mb/sha1_mb.c @@ -931,4 +931,4 @@ module_exit(sha1_mb_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm, multi buffer accelerated"); -MODULE_ALIAS("sha1"); +MODULE_ALIAS_CRYPTO("sha1"); diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 82e8a1d44658..156ebcab4ada 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -179,8 +179,8 @@ sysenter_dispatch: sysexit_from_sys_call: andl $~TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET) /* clear IF, that popfq doesn't enable interrupts early */ - andl $~0x200,EFLAGS-R11(%rsp) - movl RIP-R11(%rsp),%edx /* User %eip */ + andl $~0x200,EFLAGS-ARGOFFSET(%rsp) + movl RIP-ARGOFFSET(%rsp),%edx /* User %eip */ CFI_REGISTER rip,rdx RESTORE_ARGS 0,24,0,0,0,0 xorq %r8,%r8 diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index 0ab4f9fd2687..3a45668f6dc3 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h @@ -50,6 +50,7 @@ void acpi_pic_sci_set_trigger(unsigned int, u16); extern int (*__acpi_register_gsi)(struct device *dev, u32 gsi, int trigger, int polarity); +extern void (*__acpi_unregister_gsi)(u32 gsi); static inline void disable_acpi(void) { diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 465b309af254..92003f3c8a42 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -106,7 +106,14 @@ extern u32 native_safe_apic_wait_icr_idle(void); extern void native_apic_icr_write(u32 low, u32 id); extern u64 native_apic_icr_read(void); -extern int x2apic_mode; +static inline bool apic_is_x2apic_enabled(void) +{ + u64 msr; + + if (rdmsrl_safe(MSR_IA32_APICBASE, &msr)) + return false; + return msr & X2APIC_ENABLE; +} #ifdef CONFIG_X86_X2APIC /* @@ -169,48 +176,23 @@ static inline u64 native_x2apic_icr_read(void) return val; } +extern int x2apic_mode; extern int x2apic_phys; -extern int x2apic_preenabled; -extern void check_x2apic(void); -extern void enable_x2apic(void); +extern void __init check_x2apic(void); +extern void x2apic_setup(void); static inline int x2apic_enabled(void) { - u64 msr; - - if (!cpu_has_x2apic) - return 0; - - rdmsrl(MSR_IA32_APICBASE, msr); - if (msr & X2APIC_ENABLE) - return 1; - return 0; + return cpu_has_x2apic && apic_is_x2apic_enabled(); } #define x2apic_supported() (cpu_has_x2apic) -static inline void x2apic_force_phys(void) -{ - x2apic_phys = 1; -} #else -static inline void disable_x2apic(void) -{ -} -static inline void check_x2apic(void) -{ -} -static inline void enable_x2apic(void) -{ -} -static inline int x2apic_enabled(void) -{ - return 0; -} -static inline void x2apic_force_phys(void) -{ -} +static inline void check_x2apic(void) { } +static inline void x2apic_setup(void) { } +static inline int x2apic_enabled(void) { return 0; } -#define x2apic_preenabled 0 -#define x2apic_supported() 0 +#define x2apic_mode (0) +#define x2apic_supported() (0) #endif extern void enable_IR_x2apic(void); @@ -219,7 +201,6 @@ extern int get_physical_broadcast(void); extern int lapic_get_maxlvt(void); extern void clear_local_APIC(void); -extern void connect_bsp_APIC(void); extern void disconnect_bsp_APIC(int virt_wire_setup); extern void disable_local_APIC(void); extern void lapic_shutdown(void); @@ -227,8 +208,6 @@ extern int verify_local_APIC(void); extern void sync_Arb_IDs(void); extern void init_bsp_APIC(void); extern void setup_local_APIC(void); -extern void end_local_APIC_setup(void); -extern void bsp_end_local_APIC_setup(void); extern void init_apic_mappings(void); void register_lapic_address(unsigned long address); extern void setup_boot_APIC_clock(void); @@ -236,6 +215,9 @@ extern void setup_secondary_APIC_clock(void); extern int APIC_init_uniprocessor(void); extern int apic_force_enable(unsigned long addr); +extern int apic_bsp_setup(bool upmode); +extern void apic_ap_setup(void); + /* * On 32bit this is mach-xxx local */ diff --git a/arch/x86/include/asm/calling.h b/arch/x86/include/asm/calling.h index 76659b67fd11..1f1297b46f83 100644 --- a/arch/x86/include/asm/calling.h +++ b/arch/x86/include/asm/calling.h @@ -83,7 +83,6 @@ For 32-bit we have the following conventions - kernel is built with #define SS 160 #define ARGOFFSET R11 -#define SWFRAME ORIG_RAX .macro SAVE_ARGS addskip=0, save_rcx=1, save_r891011=1, rax_enosys=0 subq $9*8+\addskip, %rsp diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index aede2c347bde..90a54851aedc 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -174,6 +174,7 @@ #define X86_FEATURE_TOPOEXT ( 6*32+22) /* topology extensions CPUID leafs */ #define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* core performance counter extensions */ #define X86_FEATURE_PERFCTR_NB ( 6*32+24) /* NB performance counter extensions */ +#define X86_FEATURE_BPEXT (6*32+26) /* data breakpoint extension */ #define X86_FEATURE_PERFCTR_L2 ( 6*32+28) /* L2 performance counter extensions */ /* @@ -388,6 +389,7 @@ extern const char * const x86_bug_flags[NBUGINTS*32]; #define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16) #define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU) #define cpu_has_topoext boot_cpu_has(X86_FEATURE_TOPOEXT) +#define cpu_has_bpext boot_cpu_has(X86_FEATURE_BPEXT) #if __GNUC__ >= 4 extern void warn_pre_alternatives(void); diff --git a/arch/x86/include/asm/debugreg.h b/arch/x86/include/asm/debugreg.h index 61fd18b83b6c..12cb66f6d3a5 100644 --- a/arch/x86/include/asm/debugreg.h +++ b/arch/x86/include/asm/debugreg.h @@ -114,5 +114,10 @@ static inline void debug_stack_usage_inc(void) { } static inline void debug_stack_usage_dec(void) { } #endif /* X86_64 */ +#ifdef CONFIG_CPU_SUP_AMD +extern void set_dr_addr_mask(unsigned long mask, int dr); +#else +static inline void set_dr_addr_mask(unsigned long mask, int dr) { } +#endif #endif /* _ASM_X86_DEBUGREG_H */ diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h index 50d033a8947d..a94b82e8f156 100644 --- a/arch/x86/include/asm/desc.h +++ b/arch/x86/include/asm/desc.h @@ -251,7 +251,8 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; } -#define _LDT_empty(info) \ +/* This intentionally ignores lm, since 32-bit apps don't have that field. */ +#define LDT_empty(info) \ ((info)->base_addr == 0 && \ (info)->limit == 0 && \ (info)->contents == 0 && \ @@ -261,11 +262,18 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) (info)->seg_not_present == 1 && \ (info)->useable == 0) -#ifdef CONFIG_X86_64 -#define LDT_empty(info) (_LDT_empty(info) && ((info)->lm == 0)) -#else -#define LDT_empty(info) (_LDT_empty(info)) -#endif +/* Lots of programs expect an all-zero user_desc to mean "no segment at all". */ +static inline bool LDT_zero(const struct user_desc *info) +{ + return (info->base_addr == 0 && + info->limit == 0 && + info->contents == 0 && + info->read_exec_only == 0 && + info->seg_32bit == 0 && + info->limit_in_pages == 0 && + info->seg_not_present == 0 && + info->useable == 0); +} static inline void clear_LDT(void) { diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h index e97622f57722..0dbc08282291 100644 --- a/arch/x86/include/asm/fpu-internal.h +++ b/arch/x86/include/asm/fpu-internal.h @@ -207,7 +207,7 @@ static inline void fpu_fxsave(struct fpu *fpu) if (config_enabled(CONFIG_X86_32)) asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state->fxsave)); else if (config_enabled(CONFIG_AS_FXSAVEQ)) - asm volatile("fxsaveq %0" : "=m" (fpu->state->fxsave)); + asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state->fxsave)); else { /* Using "rex64; fxsave %0" is broken because, if the memory * operand uses any extended registers for addressing, a second @@ -290,9 +290,11 @@ static inline int fpu_restore_checking(struct fpu *fpu) static inline int restore_fpu_checking(struct task_struct *tsk) { - /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception - is pending. Clear the x87 state here by setting it to fixed - values. "m" is a random variable that should be in L1 */ + /* + * AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception is + * pending. Clear the x87 state here by setting it to fixed values. + * "m" is a random variable that should be in L1. + */ if (unlikely(static_cpu_has_bug_safe(X86_BUG_FXSAVE_LEAK))) { asm volatile( "fnclex\n\t" diff --git a/arch/x86/include/asm/hw_breakpoint.h b/arch/x86/include/asm/hw_breakpoint.h index ef1c4d2d41ec..6c98be864a75 100644 --- a/arch/x86/include/asm/hw_breakpoint.h +++ b/arch/x86/include/asm/hw_breakpoint.h @@ -12,6 +12,7 @@ */ struct arch_hw_breakpoint { unsigned long address; + unsigned long mask; u8 len; u8 type; }; diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index ed8089d69094..6eb6fcb83f63 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -40,8 +40,8 @@ extern void __kernel_fpu_end(void); static inline void kernel_fpu_begin(void) { - WARN_ON_ONCE(!irq_fpu_usable()); preempt_disable(); + WARN_ON_ONCE(!irq_fpu_usable()); __kernel_fpu_begin(); } @@ -51,6 +51,10 @@ static inline void kernel_fpu_end(void) preempt_enable(); } +/* Must be called with preempt disabled */ +extern void kernel_fpu_disable(void); +extern void kernel_fpu_enable(void); + /* * Some instructions like VIA's padlock instructions generate a spurious * DNA fault but don't modify SSE registers. And these instructions diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index bf006cce9418..2f91685fe1cd 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h @@ -279,6 +279,11 @@ static inline void disable_ioapic_support(void) { } #define native_ioapic_set_affinity NULL #define native_setup_ioapic_entry NULL #define native_eoi_ioapic_pin NULL + +static inline void setup_IO_APIC(void) { } +static inline void enable_IO_APIC(void) { } +static inline void setup_ioapic_dest(void) { } + #endif #endif /* _ASM_X86_IO_APIC_H */ diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h index b7747c4c2cf2..6224d316c405 100644 --- a/arch/x86/include/asm/irq_remapping.h +++ b/arch/x86/include/asm/irq_remapping.h @@ -33,8 +33,6 @@ struct irq_cfg; #ifdef CONFIG_IRQ_REMAP -extern void setup_irq_remapping_ops(void); -extern int irq_remapping_supported(void); extern void set_irq_remapping_broken(void); extern int irq_remapping_prepare(void); extern int irq_remapping_enable(void); @@ -60,8 +58,6 @@ void irq_remap_modify_chip_defaults(struct irq_chip *chip); #else /* CONFIG_IRQ_REMAP */ -static inline void setup_irq_remapping_ops(void) { } -static inline int irq_remapping_supported(void) { return 0; } static inline void set_irq_remapping_broken(void) { } static inline int irq_remapping_prepare(void) { return -ENODEV; } static inline int irq_remapping_enable(void) { return -ENODEV; } diff --git a/arch/x86/include/asm/livepatch.h b/arch/x86/include/asm/livepatch.h new file mode 100644 index 000000000000..a455a53d789a --- /dev/null +++ b/arch/x86/include/asm/livepatch.h @@ -0,0 +1,46 @@ +/* + * livepatch.h - x86-specific Kernel Live Patching Core + * + * Copyright (C) 2014 Seth Jennings + * Copyright (C) 2014 SUSE + * + * 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, see . + */ + +#ifndef _ASM_X86_LIVEPATCH_H +#define _ASM_X86_LIVEPATCH_H + +#include +#include + +#ifdef CONFIG_LIVEPATCH +static inline int klp_check_compiler_support(void) +{ +#ifndef CC_USING_FENTRY + return 1; +#endif + return 0; +} +extern int klp_write_module_reloc(struct module *mod, unsigned long type, + unsigned long loc, unsigned long value); + +static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip) +{ + regs->ip = ip; +} +#else +#error Live patching support is disabled; check CONFIG_LIVEPATCH +#endif + +#endif /* _ASM_X86_LIVEPATCH_H */ diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index 51b26e895933..9b3de99dc004 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -190,7 +190,6 @@ enum mcp_flags { void machine_check_poll(enum mcp_flags flags, mce_banks_t *b); int mce_notify_irq(void); -void mce_notify_process(void); DECLARE_PER_CPU(struct mce, injectm); diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h index 40269a2bf6f9..4b75d591eb5e 100644 --- a/arch/x86/include/asm/mmu_context.h +++ b/arch/x86/include/asm/mmu_context.h @@ -130,7 +130,25 @@ static inline void arch_bprm_mm_init(struct mm_struct *mm, static inline void arch_unmap(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long start, unsigned long end) { - mpx_notify_unmap(mm, vma, start, end); + /* + * mpx_notify_unmap() goes and reads a rarely-hot + * cacheline in the mm_struct. That can be expensive + * enough to be seen in profiles. + * + * The mpx_notify_unmap() call and its contents have been + * observed to affect munmap() performance on hardware + * where MPX is not present. + * + * The unlikely() optimizes for the fast case: no MPX + * in the CPU, or no MPX use in the process. Even if + * we get this wrong (in the unlikely event that MPX + * is widely enabled on some system) the overhead of + * MPX itself (reading bounds tables) is expected to + * overwhelm the overhead of getting this unlikely() + * consistently wrong. + */ + if (unlikely(cpu_feature_enabled(X86_FEATURE_MPX))) + mpx_notify_unmap(mm, vma, start, end); } #endif /* _ASM_X86_MMU_CONTEXT_H */ diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h index 164e3f8d3c3d..fa1195dae425 100644 --- a/arch/x86/include/asm/pci_x86.h +++ b/arch/x86/include/asm/pci_x86.h @@ -93,8 +93,6 @@ extern raw_spinlock_t pci_config_lock; extern int (*pcibios_enable_irq)(struct pci_dev *dev); extern void (*pcibios_disable_irq)(struct pci_dev *dev); -extern bool mp_should_keep_irq(struct device *dev); - struct pci_raw_ops { int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn, int reg, int len, u32 *val); diff --git a/arch/x86/include/asm/pgtable-2level.h b/arch/x86/include/asm/pgtable-2level.h index 206a87fdd22d..fd74a11959de 100644 --- a/arch/x86/include/asm/pgtable-2level.h +++ b/arch/x86/include/asm/pgtable-2level.h @@ -62,44 +62,8 @@ static inline unsigned long pte_bitop(unsigned long value, unsigned int rightshi return ((value >> rightshift) & mask) << leftshift; } -/* - * Bits _PAGE_BIT_PRESENT, _PAGE_BIT_FILE and _PAGE_BIT_PROTNONE are taken, - * split up the 29 bits of offset into this range. - */ -#define PTE_FILE_MAX_BITS 29 -#define PTE_FILE_SHIFT1 (_PAGE_BIT_PRESENT + 1) -#define PTE_FILE_SHIFT2 (_PAGE_BIT_FILE + 1) -#define PTE_FILE_SHIFT3 (_PAGE_BIT_PROTNONE + 1) -#define PTE_FILE_BITS1 (PTE_FILE_SHIFT2 - PTE_FILE_SHIFT1 - 1) -#define PTE_FILE_BITS2 (PTE_FILE_SHIFT3 - PTE_FILE_SHIFT2 - 1) - -#define PTE_FILE_MASK1 ((1U << PTE_FILE_BITS1) - 1) -#define PTE_FILE_MASK2 ((1U << PTE_FILE_BITS2) - 1) - -#define PTE_FILE_LSHIFT2 (PTE_FILE_BITS1) -#define PTE_FILE_LSHIFT3 (PTE_FILE_BITS1 + PTE_FILE_BITS2) - -static __always_inline pgoff_t pte_to_pgoff(pte_t pte) -{ - return (pgoff_t) - (pte_bitop(pte.pte_low, PTE_FILE_SHIFT1, PTE_FILE_MASK1, 0) + - pte_bitop(pte.pte_low, PTE_FILE_SHIFT2, PTE_FILE_MASK2, PTE_FILE_LSHIFT2) + - pte_bitop(pte.pte_low, PTE_FILE_SHIFT3, -1UL, PTE_FILE_LSHIFT3)); -} - -static __always_inline pte_t pgoff_to_pte(pgoff_t off) -{ - return (pte_t){ - .pte_low = - pte_bitop(off, 0, PTE_FILE_MASK1, PTE_FILE_SHIFT1) + - pte_bitop(off, PTE_FILE_LSHIFT2, PTE_FILE_MASK2, PTE_FILE_SHIFT2) + - pte_bitop(off, PTE_FILE_LSHIFT3, -1UL, PTE_FILE_SHIFT3) + - _PAGE_FILE, - }; -} - /* Encode and de-code a swap entry */ -#define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1) +#define SWP_TYPE_BITS 5 #define SWP_OFFSET_SHIFT (_PAGE_BIT_PROTNONE + 1) #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS) diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h index 81bb91b49a88..cdaa58c9b39e 100644 --- a/arch/x86/include/asm/pgtable-3level.h +++ b/arch/x86/include/asm/pgtable-3level.h @@ -176,18 +176,6 @@ static inline pmd_t native_pmdp_get_and_clear(pmd_t *pmdp) #define native_pmdp_get_and_clear(xp) native_local_pmdp_get_and_clear(xp) #endif -/* - * Bits 0, 6 and 7 are taken in the low part of the pte, - * put the 32 bits of offset into the high part. - * - * For soft-dirty tracking 11 bit is taken from - * the low part of pte as well. - */ -#define pte_to_pgoff(pte) ((pte).pte_high) -#define pgoff_to_pte(off) \ - ((pte_t) { { .pte_low = _PAGE_FILE, .pte_high = (off) } }) -#define PTE_FILE_MAX_BITS 32 - /* Encode and de-code a swap entry */ #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > 5) #define __swp_type(x) (((x).val) & 0x1f) diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index e8a5454acc99..0fe03f834fb1 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -115,11 +115,6 @@ static inline int pte_write(pte_t pte) return pte_flags(pte) & _PAGE_RW; } -static inline int pte_file(pte_t pte) -{ - return pte_flags(pte) & _PAGE_FILE; -} - static inline int pte_huge(pte_t pte) { return pte_flags(pte) & _PAGE_PSE; @@ -329,21 +324,6 @@ static inline pmd_t pmd_mksoft_dirty(pmd_t pmd) return pmd_set_flags(pmd, _PAGE_SOFT_DIRTY); } -static inline pte_t pte_file_clear_soft_dirty(pte_t pte) -{ - return pte_clear_flags(pte, _PAGE_SOFT_DIRTY); -} - -static inline pte_t pte_file_mksoft_dirty(pte_t pte) -{ - return pte_set_flags(pte, _PAGE_SOFT_DIRTY); -} - -static inline int pte_file_soft_dirty(pte_t pte) -{ - return pte_flags(pte) & _PAGE_SOFT_DIRTY; -} - #endif /* CONFIG_HAVE_ARCH_SOFT_DIRTY */ /* diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h index 4572b2f30237..e227970f983e 100644 --- a/arch/x86/include/asm/pgtable_64.h +++ b/arch/x86/include/asm/pgtable_64.h @@ -133,10 +133,6 @@ static inline int pgd_large(pgd_t pgd) { return 0; } /* PUD - Level3 access */ /* PMD - Level 2 access */ -#define pte_to_pgoff(pte) ((pte_val((pte)) & PHYSICAL_PAGE_MASK) >> PAGE_SHIFT) -#define pgoff_to_pte(off) ((pte_t) { .pte = ((off) << PAGE_SHIFT) | \ - _PAGE_FILE }) -#define PTE_FILE_MAX_BITS __PHYSICAL_MASK_SHIFT /* PTE - Level 1 access. */ @@ -145,7 +141,7 @@ static inline int pgd_large(pgd_t pgd) { return 0; } #define pte_unmap(pte) ((void)(pte))/* NOP */ /* Encode and de-code a swap entry */ -#define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1) +#define SWP_TYPE_BITS 5 #ifdef CONFIG_NUMA_BALANCING /* Automatic NUMA balancing needs to be distinguishable from swap entries */ #define SWP_OFFSET_SHIFT (_PAGE_BIT_PROTNONE + 2) diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index 25bcd4a89517..3e0230c94cff 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -4,7 +4,7 @@ #include #include -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define _PAGE_BIT_PRESENT 0 /* is present */ #define _PAGE_BIT_RW 1 /* writeable */ @@ -38,8 +38,6 @@ /* If _PAGE_BIT_PRESENT is clear, we use these: */ /* - if the user mapped it with PROT_NONE; pte_present gives true */ #define _PAGE_BIT_PROTNONE _PAGE_BIT_GLOBAL -/* - set: nonlinear file mapping, saved PTE; unset:swap */ -#define _PAGE_BIT_FILE _PAGE_BIT_DIRTY #define _PAGE_PRESENT (_AT(pteval_t, 1) << _PAGE_BIT_PRESENT) #define _PAGE_RW (_AT(pteval_t, 1) << _PAGE_BIT_RW) @@ -114,7 +112,6 @@ #define _PAGE_NX (_AT(pteval_t, 0)) #endif -#define _PAGE_FILE (_AT(pteval_t, 1) << _PAGE_BIT_FILE) #define _PAGE_PROTNONE (_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE) #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \ diff --git a/arch/x86/include/asm/pmc_atom.h b/arch/x86/include/asm/pmc_atom.h index fc7a17c05d35..bc0fc0866553 100644 --- a/arch/x86/include/asm/pmc_atom.h +++ b/arch/x86/include/asm/pmc_atom.h @@ -53,6 +53,28 @@ /* Sleep state counter is in units of of 32us */ #define PMC_TMR_SHIFT 5 +/* Power status of power islands */ +#define PMC_PSS 0x98 + +#define PMC_PSS_BIT_GBE BIT(0) +#define PMC_PSS_BIT_SATA BIT(1) +#define PMC_PSS_BIT_HDA BIT(2) +#define PMC_PSS_BIT_SEC BIT(3) +#define PMC_PSS_BIT_PCIE BIT(4) +#define PMC_PSS_BIT_LPSS BIT(5) +#define PMC_PSS_BIT_LPE BIT(6) +#define PMC_PSS_BIT_DFX BIT(7) +#define PMC_PSS_BIT_USH_CTRL BIT(8) +#define PMC_PSS_BIT_USH_SUS BIT(9) +#define PMC_PSS_BIT_USH_VCCS BIT(10) +#define PMC_PSS_BIT_USH_VCCA BIT(11) +#define PMC_PSS_BIT_OTG_CTRL BIT(12) +#define PMC_PSS_BIT_OTG_VCCS BIT(13) +#define PMC_PSS_BIT_OTG_VCCA_CLK BIT(14) +#define PMC_PSS_BIT_OTG_VCCA BIT(15) +#define PMC_PSS_BIT_USB BIT(16) +#define PMC_PSS_BIT_USB_SUS BIT(17) + /* These registers reflect D3 status of functions */ #define PMC_D3_STS_0 0xA0 diff --git a/arch/x86/include/asm/smpboot_hooks.h b/arch/x86/include/asm/smpboot_hooks.h deleted file mode 100644 index 0da7409f0bec..000000000000 --- a/arch/x86/include/asm/smpboot_hooks.h +++ /dev/null @@ -1,68 +0,0 @@ -/* two abstractions specific to kernel/smpboot.c, mainly to cater to visws - * which needs to alter them. */ - -static inline void smpboot_clear_io_apic_irqs(void) -{ -#ifdef CONFIG_X86_IO_APIC - io_apic_irqs = 0; -#endif -} - -static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) -{ - unsigned long flags; - - spin_lock_irqsave(&rtc_lock, flags); - CMOS_WRITE(0xa, 0xf); - spin_unlock_irqrestore(&rtc_lock, flags); - local_flush_tlb(); - pr_debug("1.\n"); - *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) = - start_eip >> 4; - pr_debug("2.\n"); - *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = - start_eip & 0xf; - pr_debug("3.\n"); -} - -static inline void smpboot_restore_warm_reset_vector(void) -{ - unsigned long flags; - - /* - * Install writable page 0 entry to set BIOS data area. - */ - local_flush_tlb(); - - /* - * Paranoid: Set warm reset code and vector here back - * to default values. - */ - spin_lock_irqsave(&rtc_lock, flags); - CMOS_WRITE(0, 0xf); - spin_unlock_irqrestore(&rtc_lock, flags); - - *((volatile u32 *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = 0; -} - -static inline void __init smpboot_setup_io_apic(void) -{ -#ifdef CONFIG_X86_IO_APIC - /* - * Here we can be sure that there is an IO-APIC in the system. Let's - * go and set it up: - */ - if (!skip_ioapic_setup && nr_ioapics) - setup_IO_APIC(); - else { - nr_ioapics = 0; - } -#endif -} - -static inline void smpboot_clear_io_apic(void) -{ -#ifdef CONFIG_X86_IO_APIC - nr_ioapics = 0; -#endif -} diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 547e344a6dc6..e82e95abc92b 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -75,7 +75,6 @@ struct thread_info { #define TIF_SYSCALL_EMU 6 /* syscall emulation active */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ #define TIF_SECCOMP 8 /* secure computing */ -#define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */ #define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */ #define TIF_UPROBE 12 /* breakpointed or singlestepping */ #define TIF_NOTSC 16 /* TSC is not accessible in userland */ @@ -100,7 +99,6 @@ struct thread_info { #define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SECCOMP (1 << TIF_SECCOMP) -#define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY) #define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY) #define _TIF_UPROBE (1 << TIF_UPROBE) #define _TIF_NOTSC (1 << TIF_NOTSC) @@ -140,7 +138,7 @@ struct thread_info { /* Only used for 64 bit */ #define _TIF_DO_NOTIFY_MASK \ - (_TIF_SIGPENDING | _TIF_MCE_NOTIFY | _TIF_NOTIFY_RESUME | \ + (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | \ _TIF_USER_RETURN_NOTIFY | _TIF_UPROBE) /* flags to check in __switch_to() */ @@ -170,6 +168,17 @@ static inline struct thread_info *current_thread_info(void) return ti; } +static inline unsigned long current_stack_pointer(void) +{ + unsigned long sp; +#ifdef CONFIG_X86_64 + asm("mov %%rsp,%0" : "=g" (sp)); +#else + asm("mov %%esp,%0" : "=g" (sp)); +#endif + return sp; +} + #else /* !__ASSEMBLY__ */ /* how to get the thread information struct from ASM */ diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index 707adc6549d8..4e49d7dff78e 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h @@ -1,6 +1,7 @@ #ifndef _ASM_X86_TRAPS_H #define _ASM_X86_TRAPS_H +#include #include #include @@ -110,6 +111,11 @@ asmlinkage void smp_thermal_interrupt(void); asmlinkage void mce_threshold_interrupt(void); #endif +extern enum ctx_state ist_enter(struct pt_regs *regs); +extern void ist_exit(struct pt_regs *regs, enum ctx_state prev_state); +extern void ist_begin_non_atomic(struct pt_regs *regs); +extern void ist_end_non_atomic(void); + /* Interrupts/Exceptions */ enum { X86_TRAP_DE = 0, /* 0, Divide-by-zero */ diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index 5eea09915a15..358dcd338915 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -55,9 +55,8 @@ extern int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, struct gnttab_map_grant_ref *kmap_ops, struct page **pages, unsigned int count); extern int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, - struct gnttab_map_grant_ref *kmap_ops, + struct gnttab_unmap_grant_ref *kunmap_ops, struct page **pages, unsigned int count); -extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn); /* * Helper functions to write or read unsigned long values to/from @@ -154,21 +153,12 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn) return mfn; pfn = mfn_to_pfn_no_overrides(mfn); - if (__pfn_to_mfn(pfn) != mfn) { - /* - * If this appears to be a foreign mfn (because the pfn - * doesn't map back to the mfn), then check the local override - * table to see if there's a better pfn to use. - * - * m2p_find_override_pfn returns ~0 if it doesn't find anything. - */ - pfn = m2p_find_override_pfn(mfn, ~0); - } + if (__pfn_to_mfn(pfn) != mfn) + pfn = ~0; /* - * pfn is ~0 if there are no entries in the m2p for mfn or if the - * entry doesn't map back to the mfn and m2p_override doesn't have a - * valid entry for it. + * pfn is ~0 if there are no entries in the m2p for mfn or the + * entry doesn't map back to the mfn. */ if (pfn == ~0 && __pfn_to_mfn(mfn) == IDENTITY_FRAME(mfn)) pfn = mfn; diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h index c8aa65d56027..536240fa9a95 100644 --- a/arch/x86/include/uapi/asm/msr-index.h +++ b/arch/x86/include/uapi/asm/msr-index.h @@ -152,6 +152,10 @@ #define MSR_CC6_DEMOTION_POLICY_CONFIG 0x00000668 #define MSR_MC6_DEMOTION_POLICY_CONFIG 0x00000669 +#define MSR_CORE_PERF_LIMIT_REASONS 0x00000690 +#define MSR_GFX_PERF_LIMIT_REASONS 0x000006B0 +#define MSR_RING_PERF_LIMIT_REASONS 0x000006B1 + /* Hardware P state interface */ #define MSR_PPERF 0x0000064e #define MSR_PERF_LIMIT_REASONS 0x0000064f @@ -251,6 +255,10 @@ /* Fam 16h MSRs */ #define MSR_F16H_L2I_PERF_CTL 0xc0010230 #define MSR_F16H_L2I_PERF_CTR 0xc0010231 +#define MSR_F16H_DR1_ADDR_MASK 0xc0011019 +#define MSR_F16H_DR2_ADDR_MASK 0xc001101a +#define MSR_F16H_DR3_ADDR_MASK 0xc001101b +#define MSR_F16H_DR0_ADDR_MASK 0xc0011027 /* Fam 15h MSRs */ #define MSR_F15H_PERF_CTL 0xc0010200 @@ -358,6 +366,7 @@ #define MSR_IA32_PERF_STATUS 0x00000198 #define MSR_IA32_PERF_CTL 0x00000199 +#define INTEL_PERF_CTL_MASK 0xffff #define MSR_AMD_PSTATE_DEF_BASE 0xc0010064 #define MSR_AMD_PERF_STATUS 0xc0010063 #define MSR_AMD_PERF_CTL 0xc0010062 diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 5d4502c8b983..732223496968 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_X86_MPPARSE) += mpparse.o obj-y += apic/ obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o +obj-$(CONFIG_LIVEPATCH) += livepatch.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o obj-$(CONFIG_X86_TSC) += trace_clock.o diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index d1626364a28a..ae97ed0873c6 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -611,20 +611,20 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp) { - int irq; + int rc, irq, trigger, polarity; - if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) { - *irqp = gsi; - } else { - mutex_lock(&acpi_ioapic_lock); - irq = mp_map_gsi_to_irq(gsi, - IOAPIC_MAP_ALLOC | IOAPIC_MAP_CHECK); - mutex_unlock(&acpi_ioapic_lock); - if (irq < 0) - return -1; - *irqp = irq; + rc = acpi_get_override_irq(gsi, &trigger, &polarity); + if (rc == 0) { + trigger = trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; + polarity = polarity ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; + irq = acpi_register_gsi(NULL, gsi, trigger, polarity); + if (irq >= 0) { + *irqp = irq; + return 0; + } } - return 0; + + return -1; } EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); @@ -653,6 +653,7 @@ static int acpi_register_gsi_pic(struct device *dev, u32 gsi, return gsi; } +#ifdef CONFIG_X86_LOCAL_APIC static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi, int trigger, int polarity) { @@ -675,6 +676,7 @@ static void acpi_unregister_gsi_ioapic(u32 gsi) mutex_unlock(&acpi_ioapic_lock); #endif } +#endif int (*__acpi_register_gsi)(struct device *dev, u32 gsi, int trigger, int polarity) = acpi_register_gsi_pic; @@ -843,13 +845,7 @@ int acpi_ioapic_registered(acpi_handle handle, u32 gsi_base) static int __init acpi_parse_sbf(struct acpi_table_header *table) { - struct acpi_table_boot *sb; - - sb = (struct acpi_table_boot *)table; - if (!sb) { - printk(KERN_WARNING PREFIX "Unable to map SBF\n"); - return -ENODEV; - } + struct acpi_table_boot *sb = (struct acpi_table_boot *)table; sbf_port = sb->cmos_index; /* Save CMOS port */ @@ -863,13 +859,7 @@ static struct resource *hpet_res __initdata; static int __init acpi_parse_hpet(struct acpi_table_header *table) { - struct acpi_table_hpet *hpet_tbl; - - hpet_tbl = (struct acpi_table_hpet *)table; - if (!hpet_tbl) { - printk(KERN_WARNING PREFIX "Unable to map HPET\n"); - return -ENODEV; - } + struct acpi_table_hpet *hpet_tbl = (struct acpi_table_hpet *)table; if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) { printk(KERN_WARNING PREFIX "HPET timers must be located in " diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c index b708738d016e..6a7c23ff21d3 100644 --- a/arch/x86/kernel/apb_timer.c +++ b/arch/x86/kernel/apb_timer.c @@ -135,14 +135,6 @@ static inline void apbt_clear_mapping(void) apbt_virt_address = NULL; } -/* - * APBT timer interrupt enable / disable - */ -static inline int is_apbt_capable(void) -{ - return apbt_virt_address ? 1 : 0; -} - static int __init apbt_clockevent_register(void) { struct sfi_timer_table_entry *mtmr; diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 29b5b18afa27..b665d241efad 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -134,9 +134,6 @@ static inline void imcr_apic_to_pic(void) */ static int force_enable_local_apic __initdata; -/* Control whether x2APIC mode is enabled or not */ -static bool nox2apic __initdata; - /* * APIC command line parameters */ @@ -161,33 +158,6 @@ static __init int setup_apicpmtimer(char *s) __setup("apicpmtimer", setup_apicpmtimer); #endif -int x2apic_mode; -#ifdef CONFIG_X86_X2APIC -/* x2apic enabled before OS handover */ -int x2apic_preenabled; -static int x2apic_disabled; -static int __init setup_nox2apic(char *str) -{ - if (x2apic_enabled()) { - int apicid = native_apic_msr_read(APIC_ID); - - if (apicid >= 255) { - pr_warning("Apicid: %08x, cannot enforce nox2apic\n", - apicid); - return 0; - } - - pr_warning("x2apic already enabled. will disable it\n"); - } else - setup_clear_cpu_cap(X86_FEATURE_X2APIC); - - nox2apic = true; - - return 0; -} -early_param("nox2apic", setup_nox2apic); -#endif - unsigned long mp_lapic_addr; int disable_apic; /* Disable local APIC timer from the kernel commandline or via dmi quirk */ @@ -1475,7 +1445,7 @@ void setup_local_APIC(void) #endif } -void end_local_APIC_setup(void) +static void end_local_APIC_setup(void) { lapic_setup_esr(); @@ -1492,116 +1462,184 @@ void end_local_APIC_setup(void) apic_pm_activate(); } -void __init bsp_end_local_APIC_setup(void) +/* + * APIC setup function for application processors. Called from smpboot.c + */ +void apic_ap_setup(void) { + setup_local_APIC(); end_local_APIC_setup(); - - /* - * Now that local APIC setup is completed for BP, configure the fault - * handling for interrupt remapping. - */ - irq_remap_enable_fault_handling(); - } #ifdef CONFIG_X86_X2APIC -/* - * Need to disable xapic and x2apic at the same time and then enable xapic mode - */ -static inline void __disable_x2apic(u64 msr) -{ - wrmsrl(MSR_IA32_APICBASE, - msr & ~(X2APIC_ENABLE | XAPIC_ENABLE)); - wrmsrl(MSR_IA32_APICBASE, msr & ~X2APIC_ENABLE); -} +int x2apic_mode; -static __init void disable_x2apic(void) +enum { + X2APIC_OFF, + X2APIC_ON, + X2APIC_DISABLED, +}; +static int x2apic_state; + +static inline void __x2apic_disable(void) { u64 msr; - if (!cpu_has_x2apic) + if (cpu_has_apic) return; rdmsrl(MSR_IA32_APICBASE, msr); - if (msr & X2APIC_ENABLE) { - u32 x2apic_id = read_apic_id(); - - if (x2apic_id >= 255) - panic("Cannot disable x2apic, id: %08x\n", x2apic_id); - - pr_info("Disabling x2apic\n"); - __disable_x2apic(msr); - - if (nox2apic) { - clear_cpu_cap(&cpu_data(0), X86_FEATURE_X2APIC); - setup_clear_cpu_cap(X86_FEATURE_X2APIC); - } - - x2apic_disabled = 1; - x2apic_mode = 0; - - register_lapic_address(mp_lapic_addr); - } + if (!(msr & X2APIC_ENABLE)) + return; + /* Disable xapic and x2apic first and then reenable xapic mode */ + wrmsrl(MSR_IA32_APICBASE, msr & ~(X2APIC_ENABLE | XAPIC_ENABLE)); + wrmsrl(MSR_IA32_APICBASE, msr & ~X2APIC_ENABLE); + printk_once(KERN_INFO "x2apic disabled\n"); } -void check_x2apic(void) +static inline void __x2apic_enable(void) +{ + u64 msr; + + rdmsrl(MSR_IA32_APICBASE, msr); + if (msr & X2APIC_ENABLE) + return; + wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE); + printk_once(KERN_INFO "x2apic enabled\n"); +} + +static int __init setup_nox2apic(char *str) { if (x2apic_enabled()) { - pr_info("x2apic enabled by BIOS, switching to x2apic ops\n"); - x2apic_preenabled = x2apic_mode = 1; + int apicid = native_apic_msr_read(APIC_ID); + + if (apicid >= 255) { + pr_warning("Apicid: %08x, cannot enforce nox2apic\n", + apicid); + return 0; + } + pr_warning("x2apic already enabled.\n"); + __x2apic_disable(); } + setup_clear_cpu_cap(X86_FEATURE_X2APIC); + x2apic_state = X2APIC_DISABLED; + x2apic_mode = 0; + return 0; } +early_param("nox2apic", setup_nox2apic); -void enable_x2apic(void) +/* Called from cpu_init() to enable x2apic on (secondary) cpus */ +void x2apic_setup(void) { - u64 msr; - - rdmsrl(MSR_IA32_APICBASE, msr); - if (x2apic_disabled) { - __disable_x2apic(msr); + /* + * If x2apic is not in ON state, disable it if already enabled + * from BIOS. + */ + if (x2apic_state != X2APIC_ON) { + __x2apic_disable(); return; } + __x2apic_enable(); +} - if (!x2apic_mode) +static __init void x2apic_disable(void) +{ + u32 x2apic_id; + + if (x2apic_state != X2APIC_ON) + goto out; + + x2apic_id = read_apic_id(); + if (x2apic_id >= 255) + panic("Cannot disable x2apic, id: %08x\n", x2apic_id); + + __x2apic_disable(); + register_lapic_address(mp_lapic_addr); +out: + x2apic_state = X2APIC_DISABLED; + x2apic_mode = 0; +} + +static __init void x2apic_enable(void) +{ + if (x2apic_state != X2APIC_OFF) return; - if (!(msr & X2APIC_ENABLE)) { - printk_once(KERN_INFO "Enabling x2apic\n"); - wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE); + x2apic_mode = 1; + x2apic_state = X2APIC_ON; + __x2apic_enable(); +} + +static __init void try_to_enable_x2apic(int remap_mode) +{ + if (x2apic_state == X2APIC_DISABLED) + return; + + if (remap_mode != IRQ_REMAP_X2APIC_MODE) { + /* IR is required if there is APIC ID > 255 even when running + * under KVM + */ + if (max_physical_apicid > 255 || + (IS_ENABLED(CONFIG_HYPERVISOR_GUEST) && + !hypervisor_x2apic_available())) { + pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n"); + x2apic_disable(); + return; + } + + /* + * without IR all CPUs can be addressed by IOAPIC/MSI + * only in physical mode + */ + x2apic_phys = 1; + } + x2apic_enable(); +} + +void __init check_x2apic(void) +{ + if (x2apic_enabled()) { + pr_info("x2apic: enabled by BIOS, switching to x2apic ops\n"); + x2apic_mode = 1; + x2apic_state = X2APIC_ON; + } else if (!cpu_has_x2apic) { + x2apic_state = X2APIC_DISABLED; } } -#endif /* CONFIG_X86_X2APIC */ - -int __init enable_IR(void) +#else /* CONFIG_X86_X2APIC */ +static int __init validate_x2apic(void) { -#ifdef CONFIG_IRQ_REMAP - if (!irq_remapping_supported()) { - pr_debug("intr-remapping not supported\n"); + if (!apic_is_x2apic_enabled()) + return 0; + /* + * Checkme: Can we simply turn off x2apic here instead of panic? + */ + panic("BIOS has enabled x2apic but kernel doesn't support x2apic, please disable x2apic in BIOS.\n"); +} +early_initcall(validate_x2apic); + +static inline void try_to_enable_x2apic(int remap_mode) { } +static inline void __x2apic_enable(void) { } +#endif /* !CONFIG_X86_X2APIC */ + +static int __init try_to_enable_IR(void) +{ +#ifdef CONFIG_X86_IO_APIC + if (!x2apic_enabled() && skip_ioapic_setup) { + pr_info("Not enabling interrupt remapping due to skipped IO-APIC setup\n"); return -1; } - - if (!x2apic_preenabled && skip_ioapic_setup) { - pr_info("Skipped enabling intr-remap because of skipping " - "io-apic setup\n"); - return -1; - } - - return irq_remapping_enable(); #endif - return -1; + return irq_remapping_enable(); } void __init enable_IR_x2apic(void) { unsigned long flags; - int ret, x2apic_enabled = 0; - int hardware_init_ret; + int ret, ir_stat; - /* Make sure irq_remap_ops are initialized */ - setup_irq_remapping_ops(); - - hardware_init_ret = irq_remapping_prepare(); - if (hardware_init_ret && !x2apic_supported()) + ir_stat = irq_remapping_prepare(); + if (ir_stat < 0 && !x2apic_supported()) return; ret = save_ioapic_entries(); @@ -1614,49 +1652,13 @@ void __init enable_IR_x2apic(void) legacy_pic->mask_all(); mask_ioapic_entries(); - if (x2apic_preenabled && nox2apic) - disable_x2apic(); + /* If irq_remapping_prepare() succeded, try to enable it */ + if (ir_stat >= 0) + ir_stat = try_to_enable_IR(); + /* ir_stat contains the remap mode or an error code */ + try_to_enable_x2apic(ir_stat); - if (hardware_init_ret) - ret = -1; - else - ret = enable_IR(); - - if (!x2apic_supported()) - goto skip_x2apic; - - if (ret < 0) { - /* IR is required if there is APIC ID > 255 even when running - * under KVM - */ - if (max_physical_apicid > 255 || - !hypervisor_x2apic_available()) { - if (x2apic_preenabled) - disable_x2apic(); - goto skip_x2apic; - } - /* - * without IR all CPUs can be addressed by IOAPIC/MSI - * only in physical mode - */ - x2apic_force_phys(); - } - - if (ret == IRQ_REMAP_XAPIC_MODE) { - pr_info("x2apic not enabled, IRQ remapping is in xapic mode\n"); - goto skip_x2apic; - } - - x2apic_enabled = 1; - - if (x2apic_supported() && !x2apic_mode) { - x2apic_mode = 1; - enable_x2apic(); - pr_info("Enabled x2apic\n"); - } - -skip_x2apic: - if (ret < 0) /* IR enabling failed */ + if (ir_stat < 0) restore_ioapic_entries(); legacy_pic->restore_mask(); local_irq_restore(flags); @@ -1847,82 +1849,8 @@ void __init register_lapic_address(unsigned long address) } } -/* - * This initializes the IO-APIC and APIC hardware if this is - * a UP kernel. - */ int apic_version[MAX_LOCAL_APIC]; -int __init APIC_init_uniprocessor(void) -{ - if (disable_apic) { - pr_info("Apic disabled\n"); - return -1; - } -#ifdef CONFIG_X86_64 - if (!cpu_has_apic) { - disable_apic = 1; - pr_info("Apic disabled by BIOS\n"); - return -1; - } -#else - if (!smp_found_config && !cpu_has_apic) - return -1; - - /* - * Complain if the BIOS pretends there is one. - */ - if (!cpu_has_apic && - APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { - pr_err("BIOS bug, local APIC 0x%x not detected!...\n", - boot_cpu_physical_apicid); - return -1; - } -#endif - - default_setup_apic_routing(); - - verify_local_APIC(); - connect_bsp_APIC(); - -#ifdef CONFIG_X86_64 - apic_write(APIC_ID, SET_APIC_ID(boot_cpu_physical_apicid)); -#else - /* - * Hack: In case of kdump, after a crash, kernel might be booting - * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid - * might be zero if read from MP tables. Get it from LAPIC. - */ -# ifdef CONFIG_CRASH_DUMP - boot_cpu_physical_apicid = read_apic_id(); -# endif -#endif - physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); - setup_local_APIC(); - -#ifdef CONFIG_X86_IO_APIC - /* - * Now enable IO-APICs, actually call clear_IO_APIC - * We need clear_IO_APIC before enabling error vector - */ - if (!skip_ioapic_setup && nr_ioapics) - enable_IO_APIC(); -#endif - - bsp_end_local_APIC_setup(); - -#ifdef CONFIG_X86_IO_APIC - if (smp_found_config && !skip_ioapic_setup && nr_ioapics) - setup_IO_APIC(); - else { - nr_ioapics = 0; - } -#endif - - x86_init.timers.setup_percpu_clockev(); - return 0; -} - /* * Local APIC interrupts */ @@ -2027,7 +1955,7 @@ __visible void smp_trace_error_interrupt(struct pt_regs *regs) /** * connect_bsp_APIC - attach the APIC to the interrupt system */ -void __init connect_bsp_APIC(void) +static void __init connect_bsp_APIC(void) { #ifdef CONFIG_X86_32 if (pic_mode) { @@ -2274,6 +2202,100 @@ void __init apic_set_eoi_write(void (*eoi_write)(u32 reg, u32 v)) } } +static void __init apic_bsp_up_setup(void) +{ +#ifdef CONFIG_X86_64 + apic_write(APIC_ID, SET_APIC_ID(boot_cpu_physical_apicid)); +#else + /* + * Hack: In case of kdump, after a crash, kernel might be booting + * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid + * might be zero if read from MP tables. Get it from LAPIC. + */ +# ifdef CONFIG_CRASH_DUMP + boot_cpu_physical_apicid = read_apic_id(); +# endif +#endif + physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); +} + +/** + * apic_bsp_setup - Setup function for local apic and io-apic + * @upmode: Force UP mode (for APIC_init_uniprocessor) + * + * Returns: + * apic_id of BSP APIC + */ +int __init apic_bsp_setup(bool upmode) +{ + int id; + + connect_bsp_APIC(); + if (upmode) + apic_bsp_up_setup(); + setup_local_APIC(); + + if (x2apic_mode) + id = apic_read(APIC_LDR); + else + id = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR)); + + enable_IO_APIC(); + end_local_APIC_setup(); + irq_remap_enable_fault_handling(); + setup_IO_APIC(); + /* Setup local timer */ + x86_init.timers.setup_percpu_clockev(); + return id; +} + +/* + * This initializes the IO-APIC and APIC hardware if this is + * a UP kernel. + */ +int __init APIC_init_uniprocessor(void) +{ + if (disable_apic) { + pr_info("Apic disabled\n"); + return -1; + } +#ifdef CONFIG_X86_64 + if (!cpu_has_apic) { + disable_apic = 1; + pr_info("Apic disabled by BIOS\n"); + return -1; + } +#else + if (!smp_found_config && !cpu_has_apic) + return -1; + + /* + * Complain if the BIOS pretends there is one. + */ + if (!cpu_has_apic && + APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { + pr_err("BIOS bug, local APIC 0x%x not detected!...\n", + boot_cpu_physical_apicid); + return -1; + } +#endif + + if (!smp_found_config) + disable_ioapic_support(); + + default_setup_apic_routing(); + verify_local_APIC(); + apic_bsp_setup(true); + return 0; +} + +#ifdef CONFIG_UP_LATE_INIT +void __init up_late_init(void) +{ + APIC_init_uniprocessor(); +} +#endif + /* * Power management */ @@ -2359,9 +2381,9 @@ static void lapic_resume(void) mask_ioapic_entries(); legacy_pic->mask_all(); - if (x2apic_mode) - enable_x2apic(); - else { + if (x2apic_mode) { + __x2apic_enable(); + } else { /* * Make sure the APICBASE points to the right address * diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 3f5f60406ab1..f4dc2462a1ac 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -1507,7 +1507,10 @@ void __init enable_IO_APIC(void) int i8259_apic, i8259_pin; int apic, pin; - if (!nr_legacy_irqs()) + if (skip_ioapic_setup) + nr_ioapics = 0; + + if (!nr_legacy_irqs() || !nr_ioapics) return; for_each_ioapic_pin(apic, pin) { @@ -2295,7 +2298,7 @@ static inline void __init check_timer(void) } local_irq_disable(); apic_printk(APIC_QUIET, KERN_INFO "..... failed :(.\n"); - if (x2apic_preenabled) + if (apic_is_x2apic_enabled()) apic_printk(APIC_QUIET, KERN_INFO "Perhaps problem with the pre-enabled x2apic mode\n" "Try booting with x2apic and interrupt-remapping disabled in the bios.\n"); @@ -2373,9 +2376,9 @@ void __init setup_IO_APIC(void) { int ioapic; - /* - * calling enable_IO_APIC() is moved to setup_local_APIC for BP - */ + if (skip_ioapic_setup || !nr_ioapics) + return; + io_apic_irqs = nr_legacy_irqs() ? ~PIC_IRQS : ~0UL; apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 15c5df92f74e..a220239cea65 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -869,3 +869,22 @@ static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum) return false; } + +void set_dr_addr_mask(unsigned long mask, int dr) +{ + if (!cpu_has_bpext) + return; + + switch (dr) { + case 0: + wrmsr(MSR_F16H_DR0_ADDR_MASK, mask, 0); + break; + case 1: + case 2: + case 3: + wrmsr(MSR_F16H_DR1_ADDR_MASK - 1 + dr, mask, 0); + break; + default: + break; + } +} diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index c6049650c093..b15bffcaba6d 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -491,17 +491,18 @@ u16 __read_mostly tlb_lld_2m[NR_INFO]; u16 __read_mostly tlb_lld_4m[NR_INFO]; u16 __read_mostly tlb_lld_1g[NR_INFO]; -void cpu_detect_tlb(struct cpuinfo_x86 *c) +static void cpu_detect_tlb(struct cpuinfo_x86 *c) { if (this_cpu->c_detect_tlb) this_cpu->c_detect_tlb(c); - printk(KERN_INFO "Last level iTLB entries: 4KB %d, 2MB %d, 4MB %d\n" - "Last level dTLB entries: 4KB %d, 2MB %d, 4MB %d, 1GB %d\n", + pr_info("Last level iTLB entries: 4KB %d, 2MB %d, 4MB %d\n", tlb_lli_4k[ENTRIES], tlb_lli_2m[ENTRIES], - tlb_lli_4m[ENTRIES], tlb_lld_4k[ENTRIES], - tlb_lld_2m[ENTRIES], tlb_lld_4m[ENTRIES], - tlb_lld_1g[ENTRIES]); + tlb_lli_4m[ENTRIES]); + + pr_info("Last level dTLB entries: 4KB %d, 2MB %d, 4MB %d, 1GB %d\n", + tlb_lld_4k[ENTRIES], tlb_lld_2m[ENTRIES], + tlb_lld_4m[ENTRIES], tlb_lld_1g[ENTRIES]); } void detect_ht(struct cpuinfo_x86 *c) @@ -1332,7 +1333,7 @@ void cpu_init(void) barrier(); x86_configure_nx(); - enable_x2apic(); + x2apic_setup(); /* * set up and load the per-CPU TSS diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 9cc6b6f25f42..94d7dcb12145 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -487,10 +487,8 @@ static void init_intel(struct cpuinfo_x86 *c) rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb); if ((epb & 0xF) == ENERGY_PERF_BIAS_PERFORMANCE) { - printk_once(KERN_WARNING "ENERGY_PERF_BIAS:" - " Set to 'normal', was 'performance'\n" - "ENERGY_PERF_BIAS: View and update with" - " x86_energy_perf_policy(8)\n"); + pr_warn_once("ENERGY_PERF_BIAS: Set to 'normal', was 'performance'\n"); + pr_warn_once("ENERGY_PERF_BIAS: View and update with x86_energy_perf_policy(8)\n"); epb = (epb & ~0xF) | ENERGY_PERF_BIAS_NORMAL; wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb); } diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index d2c611699cd9..cdfed7953963 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -115,7 +116,7 @@ static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs); * CPU/chipset specific EDAC code can register a notifier call here to print * MCE errors in a human-readable form. */ -ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain); +static ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain); /* Do initial initialization of a struct mce */ void mce_setup(struct mce *m) @@ -311,7 +312,7 @@ static void wait_for_panic(void) panic("Panicing machine check CPU died"); } -static void mce_panic(char *msg, struct mce *final, char *exp) +static void mce_panic(const char *msg, struct mce *final, char *exp) { int i, apei_err = 0; @@ -529,7 +530,7 @@ static void mce_schedule_work(void) schedule_work(this_cpu_ptr(&mce_work)); } -DEFINE_PER_CPU(struct irq_work, mce_irq_work); +static DEFINE_PER_CPU(struct irq_work, mce_irq_work); static void mce_irq_work_cb(struct irq_work *entry) { @@ -735,7 +736,7 @@ static atomic_t mce_callin; /* * Check if a timeout waiting for other CPUs happened. */ -static int mce_timed_out(u64 *t) +static int mce_timed_out(u64 *t, const char *msg) { /* * The others already did panic for some reason. @@ -750,8 +751,7 @@ static int mce_timed_out(u64 *t) goto out; if ((s64)*t < SPINUNIT) { if (mca_cfg.tolerant <= 1) - mce_panic("Timeout synchronizing machine check over CPUs", - NULL, NULL); + mce_panic(msg, NULL, NULL); cpu_missing = 1; return 1; } @@ -867,7 +867,8 @@ static int mce_start(int *no_way_out) * Wait for everyone. */ while (atomic_read(&mce_callin) != cpus) { - if (mce_timed_out(&timeout)) { + if (mce_timed_out(&timeout, + "Timeout: Not all CPUs entered broadcast exception handler")) { atomic_set(&global_nwo, 0); return -1; } @@ -892,7 +893,8 @@ static int mce_start(int *no_way_out) * only seen by one CPU before cleared, avoiding duplicates. */ while (atomic_read(&mce_executing) < order) { - if (mce_timed_out(&timeout)) { + if (mce_timed_out(&timeout, + "Timeout: Subject CPUs unable to finish machine check processing")) { atomic_set(&global_nwo, 0); return -1; } @@ -936,7 +938,8 @@ static int mce_end(int order) * loops. */ while (atomic_read(&mce_executing) <= cpus) { - if (mce_timed_out(&timeout)) + if (mce_timed_out(&timeout, + "Timeout: Monarch CPU unable to finish machine check processing")) goto reset; ndelay(SPINUNIT); } @@ -949,7 +952,8 @@ static int mce_end(int order) * Subject: Wait for Monarch to finish. */ while (atomic_read(&mce_executing) != 0) { - if (mce_timed_out(&timeout)) + if (mce_timed_out(&timeout, + "Timeout: Monarch CPU did not finish machine check processing")) goto reset; ndelay(SPINUNIT); } @@ -1002,51 +1006,6 @@ static void mce_clear_state(unsigned long *toclear) } } -/* - * Need to save faulting physical address associated with a process - * in the machine check handler some place where we can grab it back - * later in mce_notify_process() - */ -#define MCE_INFO_MAX 16 - -struct mce_info { - atomic_t inuse; - struct task_struct *t; - __u64 paddr; - int restartable; -} mce_info[MCE_INFO_MAX]; - -static void mce_save_info(__u64 addr, int c) -{ - struct mce_info *mi; - - for (mi = mce_info; mi < &mce_info[MCE_INFO_MAX]; mi++) { - if (atomic_cmpxchg(&mi->inuse, 0, 1) == 0) { - mi->t = current; - mi->paddr = addr; - mi->restartable = c; - return; - } - } - - mce_panic("Too many concurrent recoverable errors", NULL, NULL); -} - -static struct mce_info *mce_find_info(void) -{ - struct mce_info *mi; - - for (mi = mce_info; mi < &mce_info[MCE_INFO_MAX]; mi++) - if (atomic_read(&mi->inuse) && mi->t == current) - return mi; - return NULL; -} - -static void mce_clear_info(struct mce_info *mi) -{ - atomic_set(&mi->inuse, 0); -} - /* * The actual machine check handler. This only handles real * exceptions when something got corrupted coming in through int 18. @@ -1063,6 +1022,7 @@ void do_machine_check(struct pt_regs *regs, long error_code) { struct mca_config *cfg = &mca_cfg; struct mce m, *final; + enum ctx_state prev_state; int i; int worst = 0; int severity; @@ -1084,6 +1044,10 @@ void do_machine_check(struct pt_regs *regs, long error_code) DECLARE_BITMAP(toclear, MAX_NR_BANKS); DECLARE_BITMAP(valid_banks, MAX_NR_BANKS); char *msg = "Unknown"; + u64 recover_paddr = ~0ull; + int flags = MF_ACTION_REQUIRED; + + prev_state = ist_enter(regs); this_cpu_inc(mce_exception_count); @@ -1203,9 +1167,9 @@ void do_machine_check(struct pt_regs *regs, long error_code) if (no_way_out) mce_panic("Fatal machine check on current CPU", &m, msg); if (worst == MCE_AR_SEVERITY) { - /* schedule action before return to userland */ - mce_save_info(m.addr, m.mcgstatus & MCG_STATUS_RIPV); - set_thread_flag(TIF_MCE_NOTIFY); + recover_paddr = m.addr; + if (!(m.mcgstatus & MCG_STATUS_RIPV)) + flags |= MF_MUST_KILL; } else if (kill_it) { force_sig(SIGBUS, current); } @@ -1216,6 +1180,27 @@ void do_machine_check(struct pt_regs *regs, long error_code) mce_wrmsrl(MSR_IA32_MCG_STATUS, 0); out: sync_core(); + + if (recover_paddr == ~0ull) + goto done; + + pr_err("Uncorrected hardware memory error in user-access at %llx", + recover_paddr); + /* + * We must call memory_failure() here even if the current process is + * doomed. We still need to mark the page as poisoned and alert any + * other users of the page. + */ + ist_begin_non_atomic(regs); + local_irq_enable(); + if (memory_failure(recover_paddr >> PAGE_SHIFT, MCE_VECTOR, flags) < 0) { + pr_err("Memory error not recovered"); + force_sig(SIGBUS, current); + } + local_irq_disable(); + ist_end_non_atomic(); +done: + ist_exit(regs, prev_state); } EXPORT_SYMBOL_GPL(do_machine_check); @@ -1232,42 +1217,6 @@ int memory_failure(unsigned long pfn, int vector, int flags) } #endif -/* - * Called in process context that interrupted by MCE and marked with - * TIF_MCE_NOTIFY, just before returning to erroneous userland. - * This code is allowed to sleep. - * Attempt possible recovery such as calling the high level VM handler to - * process any corrupted pages, and kill/signal current process if required. - * Action required errors are handled here. - */ -void mce_notify_process(void) -{ - unsigned long pfn; - struct mce_info *mi = mce_find_info(); - int flags = MF_ACTION_REQUIRED; - - if (!mi) - mce_panic("Lost physical address for unconsumed uncorrectable error", NULL, NULL); - pfn = mi->paddr >> PAGE_SHIFT; - - clear_thread_flag(TIF_MCE_NOTIFY); - - pr_err("Uncorrected hardware memory error in user-access at %llx", - mi->paddr); - /* - * We must call memory_failure() here even if the current process is - * doomed. We still need to mark the page as poisoned and alert any - * other users of the page. - */ - if (!mi->restartable) - flags |= MF_MUST_KILL; - if (memory_failure(pfn, MCE_VECTOR, flags) < 0) { - pr_err("Memory error not recovered"); - force_sig(SIGBUS, current); - } - mce_clear_info(mi); -} - /* * Action optional processing happens here (picking up * from the list of faulting pages that do_machine_check() diff --git a/arch/x86/kernel/cpu/mcheck/p5.c b/arch/x86/kernel/cpu/mcheck/p5.c index a3042989398c..ec2663a708e4 100644 --- a/arch/x86/kernel/cpu/mcheck/p5.c +++ b/arch/x86/kernel/cpu/mcheck/p5.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -17,8 +18,11 @@ int mce_p5_enabled __read_mostly; /* Machine check handler for Pentium class Intel CPUs: */ static void pentium_machine_check(struct pt_regs *regs, long error_code) { + enum ctx_state prev_state; u32 loaddr, hi, lotype; + prev_state = ist_enter(regs); + rdmsr(MSR_IA32_P5_MC_ADDR, loaddr, hi); rdmsr(MSR_IA32_P5_MC_TYPE, lotype, hi); @@ -33,6 +37,8 @@ static void pentium_machine_check(struct pt_regs *regs, long error_code) } add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE); + + ist_exit(regs, prev_state); } /* Set up machine check reporting for processors with Intel style MCE: */ diff --git a/arch/x86/kernel/cpu/mcheck/winchip.c b/arch/x86/kernel/cpu/mcheck/winchip.c index 7dc5564d0cdf..bd5d46a32210 100644 --- a/arch/x86/kernel/cpu/mcheck/winchip.c +++ b/arch/x86/kernel/cpu/mcheck/winchip.c @@ -7,14 +7,19 @@ #include #include +#include #include #include /* Machine check handler for WinChip C6: */ static void winchip_machine_check(struct pt_regs *regs, long error_code) { + enum ctx_state prev_state = ist_enter(regs); + printk(KERN_EMERG "CPU0: Machine Check Exception.\n"); add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE); + + ist_exit(regs, prev_state); } /* Set up machine check reporting on the Winchip C6 series */ diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 15c29096136b..36a83617eb21 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -552,7 +552,7 @@ static int __init microcode_init(void) int error; if (paravirt_enabled() || dis_ucode_ldr) - return 0; + return -EINVAL; if (c->x86_vendor == X86_VENDOR_INTEL) microcode_ops = init_intel_microcode(); diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index a450373e8e91..939155ffdece 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -107,6 +107,7 @@ static struct clocksource hyperv_cs = { .rating = 400, /* use this when running on Hyperv*/ .read = read_hv_clock, .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static void __init ms_hyperv_init_platform(void) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 944bf019b74f..498b6d967138 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -2431,6 +2431,7 @@ __init int intel_pmu_init(void) break; case 55: /* 22nm Atom "Silvermont" */ + case 76: /* 14nm Atom "Airmont" */ case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */ memcpy(hw_cache_event_ids, slm_hw_cache_event_ids, sizeof(hw_cache_event_ids)); diff --git a/arch/x86/kernel/cpu/perf_event_intel_rapl.c b/arch/x86/kernel/cpu/perf_event_intel_rapl.c index 6e434f8e5fc8..c4bb8b8e5017 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_rapl.c +++ b/arch/x86/kernel/cpu/perf_event_intel_rapl.c @@ -142,7 +142,7 @@ static inline u64 rapl_scale(u64 v) * or use ldexp(count, -32). * Watts = Joules/Time delta */ - return v << (32 - __this_cpu_read(rapl_pmu->hw_unit)); + return v << (32 - __this_cpu_read(rapl_pmu)->hw_unit); } static u64 rapl_event_update(struct perf_event *event) diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index 10b8d3eaaf15..c635b8b49e93 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -840,7 +840,6 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id box->phys_id = phys_id; box->pci_dev = pdev; box->pmu = pmu; - uncore_box_init(box); pci_set_drvdata(pdev, box); raw_spin_lock(&uncore_box_lock); @@ -1004,10 +1003,8 @@ static int uncore_cpu_starting(int cpu) pmu = &type->pmus[j]; box = *per_cpu_ptr(pmu->box, cpu); /* called by uncore_cpu_init? */ - if (box && box->phys_id >= 0) { - uncore_box_init(box); + if (box && box->phys_id >= 0) continue; - } for_each_online_cpu(k) { exist = *per_cpu_ptr(pmu->box, k); @@ -1023,10 +1020,8 @@ static int uncore_cpu_starting(int cpu) } } - if (box) { + if (box) box->phys_id = phys_id; - uncore_box_init(box); - } } } return 0; diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h index 863d9b02563e..6c8c1e7e69d8 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h @@ -257,6 +257,14 @@ static inline int uncore_num_counters(struct intel_uncore_box *box) return box->pmu->type->num_counters; } +static inline void uncore_box_init(struct intel_uncore_box *box) +{ + if (!test_and_set_bit(UNCORE_BOX_FLAG_INITIATED, &box->flags)) { + if (box->pmu->type->ops->init_box) + box->pmu->type->ops->init_box(box); + } +} + static inline void uncore_disable_box(struct intel_uncore_box *box) { if (box->pmu->type->ops->disable_box) @@ -265,6 +273,8 @@ static inline void uncore_disable_box(struct intel_uncore_box *box) static inline void uncore_enable_box(struct intel_uncore_box *box) { + uncore_box_init(box); + if (box->pmu->type->ops->enable_box) box->pmu->type->ops->enable_box(box); } @@ -287,14 +297,6 @@ static inline u64 uncore_read_counter(struct intel_uncore_box *box, return box->pmu->type->ops->read_counter(box, event); } -static inline void uncore_box_init(struct intel_uncore_box *box) -{ - if (!test_and_set_bit(UNCORE_BOX_FLAG_INITIATED, &box->flags)) { - if (box->pmu->type->ops->init_box) - box->pmu->type->ops->init_box(box); - } -} - static inline bool uncore_box_is_fake(struct intel_uncore_box *box) { return (box->phys_id < 0); diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index dd2f07ae9d0c..46201deee923 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -184,9 +184,9 @@ void __init e820_print_map(char *who) * overwritten in the same location, starting at biosmap. * * The integer pointed to by pnr_map must be valid on entry (the - * current number of valid entries located at biosmap) and will - * be updated on return, with the new number of valid entries - * (something no more than max_nr_map.) + * current number of valid entries located at biosmap). If the + * sanitizing succeeds the *pnr_map will be updated with the new + * number of valid entries (something no more than max_nr_map). * * The return value from sanitize_e820_map() is zero if it * successfully 'sanitized' the map entries passed in, and is -1 @@ -561,23 +561,15 @@ u64 __init e820_remove_range(u64 start, u64 size, unsigned old_type, void __init update_e820(void) { - u32 nr_map; - - nr_map = e820.nr_map; - if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr_map)) + if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map)) return; - e820.nr_map = nr_map; printk(KERN_INFO "e820: modified physical RAM map:\n"); e820_print_map("modified"); } static void __init update_e820_saved(void) { - u32 nr_map; - - nr_map = e820_saved.nr_map; - if (sanitize_e820_map(e820_saved.map, ARRAY_SIZE(e820_saved.map), &nr_map)) - return; - e820_saved.nr_map = nr_map; + sanitize_e820_map(e820_saved.map, ARRAY_SIZE(e820_saved.map), + &e820_saved.nr_map); } #define MAX_GAP_END 0x100000000ull /* @@ -898,11 +890,9 @@ early_param("memmap", parse_memmap_opt); void __init finish_e820_parsing(void) { if (userdef) { - u32 nr = e820.nr_map; - - if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr) < 0) + if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), + &e820.nr_map) < 0) early_panic("Invalid user supplied memory map"); - e820.nr_map = nr; printk(KERN_INFO "e820: user-defined physical RAM map:\n"); e820_print_map("user"); diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 9ebaf63ba182..db13655c3a2a 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -143,7 +143,8 @@ ENDPROC(native_usergs_sysret64) movq \tmp,RSP+\offset(%rsp) movq $__USER_DS,SS+\offset(%rsp) movq $__USER_CS,CS+\offset(%rsp) - movq $-1,RCX+\offset(%rsp) + movq RIP+\offset(%rsp),\tmp /* get rip */ + movq \tmp,RCX+\offset(%rsp) /* copy it to rcx as sysret would do */ movq R11+\offset(%rsp),\tmp /* get eflags */ movq \tmp,EFLAGS+\offset(%rsp) .endm @@ -155,27 +156,6 @@ ENDPROC(native_usergs_sysret64) movq \tmp,R11+\offset(%rsp) .endm - .macro FAKE_STACK_FRAME child_rip - /* push in order ss, rsp, eflags, cs, rip */ - xorl %eax, %eax - pushq_cfi $__KERNEL_DS /* ss */ - /*CFI_REL_OFFSET ss,0*/ - pushq_cfi %rax /* rsp */ - CFI_REL_OFFSET rsp,0 - pushq_cfi $(X86_EFLAGS_IF|X86_EFLAGS_FIXED) /* eflags - interrupts on */ - /*CFI_REL_OFFSET rflags,0*/ - pushq_cfi $__KERNEL_CS /* cs */ - /*CFI_REL_OFFSET cs,0*/ - pushq_cfi \child_rip /* rip */ - CFI_REL_OFFSET rip,0 - pushq_cfi %rax /* orig rax */ - .endm - - .macro UNFAKE_STACK_FRAME - addq $8*6, %rsp - CFI_ADJUST_CFA_OFFSET -(6*8) - .endm - /* * initial frame state for interrupts (and exceptions without error code) */ @@ -238,51 +218,6 @@ ENDPROC(native_usergs_sysret64) CFI_REL_OFFSET r15, R15+\offset .endm -/* save partial stack frame */ - .macro SAVE_ARGS_IRQ - cld - /* start from rbp in pt_regs and jump over */ - movq_cfi rdi, (RDI-RBP) - movq_cfi rsi, (RSI-RBP) - movq_cfi rdx, (RDX-RBP) - movq_cfi rcx, (RCX-RBP) - movq_cfi rax, (RAX-RBP) - movq_cfi r8, (R8-RBP) - movq_cfi r9, (R9-RBP) - movq_cfi r10, (R10-RBP) - movq_cfi r11, (R11-RBP) - - /* Save rbp so that we can unwind from get_irq_regs() */ - movq_cfi rbp, 0 - - /* Save previous stack value */ - movq %rsp, %rsi - - leaq -RBP(%rsp),%rdi /* arg1 for handler */ - testl $3, CS-RBP(%rsi) - je 1f - SWAPGS - /* - * irq_count is used to check if a CPU is already on an interrupt stack - * or not. While this is essentially redundant with preempt_count it is - * a little cheaper to use a separate counter in the PDA (short of - * moving irq_enter into assembly, which would be too much work) - */ -1: incl PER_CPU_VAR(irq_count) - cmovzq PER_CPU_VAR(irq_stack_ptr),%rsp - CFI_DEF_CFA_REGISTER rsi - - /* Store previous stack value */ - pushq %rsi - CFI_ESCAPE 0x0f /* DW_CFA_def_cfa_expression */, 6, \ - 0x77 /* DW_OP_breg7 */, 0, \ - 0x06 /* DW_OP_deref */, \ - 0x08 /* DW_OP_const1u */, SS+8-RBP, \ - 0x22 /* DW_OP_plus */ - /* We entered an interrupt context - irqs are off: */ - TRACE_IRQS_OFF - .endm - ENTRY(save_paranoid) XCPT_FRAME 1 RDI+8 cld @@ -426,15 +361,12 @@ system_call_fastpath: * Has incomplete stack frame and undefined top of stack. */ ret_from_sys_call: - movl $_TIF_ALLWORK_MASK,%edi - /* edi: flagmask */ -sysret_check: + testl $_TIF_ALLWORK_MASK,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET) + jnz int_ret_from_sys_call_fixup /* Go the the slow path */ + LOCKDEP_SYS_EXIT DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF - movl TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET),%edx - andl %edi,%edx - jnz sysret_careful CFI_REMEMBER_STATE /* * sysretq will re-enable interrupts: @@ -448,49 +380,10 @@ sysret_check: USERGS_SYSRET64 CFI_RESTORE_STATE - /* Handle reschedules */ - /* edx: work, edi: workmask */ -sysret_careful: - bt $TIF_NEED_RESCHED,%edx - jnc sysret_signal - TRACE_IRQS_ON - ENABLE_INTERRUPTS(CLBR_NONE) - pushq_cfi %rdi - SCHEDULE_USER - popq_cfi %rdi - jmp sysret_check - /* Handle a signal */ -sysret_signal: - TRACE_IRQS_ON - ENABLE_INTERRUPTS(CLBR_NONE) -#ifdef CONFIG_AUDITSYSCALL - bt $TIF_SYSCALL_AUDIT,%edx - jc sysret_audit -#endif - /* - * We have a signal, or exit tracing or single-step. - * These all wind up with the iret return path anyway, - * so just join that path right now. - */ +int_ret_from_sys_call_fixup: FIXUP_TOP_OF_STACK %r11, -ARGOFFSET - jmp int_check_syscall_exit_work - -#ifdef CONFIG_AUDITSYSCALL - /* - * Return fast path for syscall audit. Call __audit_syscall_exit() - * directly and then jump back to the fast path with TIF_SYSCALL_AUDIT - * masked off. - */ -sysret_audit: - movq RAX-ARGOFFSET(%rsp),%rsi /* second arg, syscall return value */ - cmpq $-MAX_ERRNO,%rsi /* is it < -MAX_ERRNO? */ - setbe %al /* 1 if so, 0 if not */ - movzbl %al,%edi /* zero-extend that into %edi */ - call __audit_syscall_exit - movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi - jmp sysret_check -#endif /* CONFIG_AUDITSYSCALL */ + jmp int_ret_from_sys_call /* Do syscall tracing */ tracesys: @@ -626,19 +519,6 @@ END(\label) FORK_LIKE vfork FIXED_FRAME stub_iopl, sys_iopl -ENTRY(ptregscall_common) - DEFAULT_FRAME 1 8 /* offset 8: return address */ - RESTORE_TOP_OF_STACK %r11, 8 - movq_cfi_restore R15+8, r15 - movq_cfi_restore R14+8, r14 - movq_cfi_restore R13+8, r13 - movq_cfi_restore R12+8, r12 - movq_cfi_restore RBP+8, rbp - movq_cfi_restore RBX+8, rbx - ret $REST_SKIP /* pop extended registers */ - CFI_ENDPROC -END(ptregscall_common) - ENTRY(stub_execve) CFI_STARTPROC addq $8, %rsp @@ -779,7 +659,48 @@ END(interrupt) /* reserve pt_regs for scratch regs and rbp */ subq $ORIG_RAX-RBP, %rsp CFI_ADJUST_CFA_OFFSET ORIG_RAX-RBP - SAVE_ARGS_IRQ + cld + /* start from rbp in pt_regs and jump over */ + movq_cfi rdi, (RDI-RBP) + movq_cfi rsi, (RSI-RBP) + movq_cfi rdx, (RDX-RBP) + movq_cfi rcx, (RCX-RBP) + movq_cfi rax, (RAX-RBP) + movq_cfi r8, (R8-RBP) + movq_cfi r9, (R9-RBP) + movq_cfi r10, (R10-RBP) + movq_cfi r11, (R11-RBP) + + /* Save rbp so that we can unwind from get_irq_regs() */ + movq_cfi rbp, 0 + + /* Save previous stack value */ + movq %rsp, %rsi + + leaq -RBP(%rsp),%rdi /* arg1 for handler */ + testl $3, CS-RBP(%rsi) + je 1f + SWAPGS + /* + * irq_count is used to check if a CPU is already on an interrupt stack + * or not. While this is essentially redundant with preempt_count it is + * a little cheaper to use a separate counter in the PDA (short of + * moving irq_enter into assembly, which would be too much work) + */ +1: incl PER_CPU_VAR(irq_count) + cmovzq PER_CPU_VAR(irq_stack_ptr),%rsp + CFI_DEF_CFA_REGISTER rsi + + /* Store previous stack value */ + pushq %rsi + CFI_ESCAPE 0x0f /* DW_CFA_def_cfa_expression */, 6, \ + 0x77 /* DW_OP_breg7 */, 0, \ + 0x06 /* DW_OP_deref */, \ + 0x08 /* DW_OP_const1u */, SS+8-RBP, \ + 0x22 /* DW_OP_plus */ + /* We entered an interrupt context - irqs are off: */ + TRACE_IRQS_OFF + call \func .endm @@ -831,6 +752,60 @@ retint_swapgs: /* return to user-space */ */ DISABLE_INTERRUPTS(CLBR_ANY) TRACE_IRQS_IRETQ + + /* + * Try to use SYSRET instead of IRET if we're returning to + * a completely clean 64-bit userspace context. + */ + movq (RCX-R11)(%rsp), %rcx + cmpq %rcx,(RIP-R11)(%rsp) /* RCX == RIP */ + jne opportunistic_sysret_failed + + /* + * On Intel CPUs, sysret with non-canonical RCX/RIP will #GP + * in kernel space. This essentially lets the user take over + * the kernel, since userspace controls RSP. It's not worth + * testing for canonicalness exactly -- this check detects any + * of the 17 high bits set, which is true for non-canonical + * or kernel addresses. (This will pessimize vsyscall=native. + * Big deal.) + * + * If virtual addresses ever become wider, this will need + * to be updated to remain correct on both old and new CPUs. + */ + .ifne __VIRTUAL_MASK_SHIFT - 47 + .error "virtual address width changed -- sysret checks need update" + .endif + shr $__VIRTUAL_MASK_SHIFT, %rcx + jnz opportunistic_sysret_failed + + cmpq $__USER_CS,(CS-R11)(%rsp) /* CS must match SYSRET */ + jne opportunistic_sysret_failed + + movq (R11-ARGOFFSET)(%rsp), %r11 + cmpq %r11,(EFLAGS-ARGOFFSET)(%rsp) /* R11 == RFLAGS */ + jne opportunistic_sysret_failed + + testq $X86_EFLAGS_RF,%r11 /* sysret can't restore RF */ + jnz opportunistic_sysret_failed + + /* nothing to check for RSP */ + + cmpq $__USER_DS,(SS-ARGOFFSET)(%rsp) /* SS must match SYSRET */ + jne opportunistic_sysret_failed + + /* + * We win! This label is here just for ease of understanding + * perf profiles. Nothing jumps here. + */ +irq_return_via_sysret: + CFI_REMEMBER_STATE + RESTORE_ARGS 1,8,1 + movq (RSP-RIP)(%rsp),%rsp + USERGS_SYSRET64 + CFI_RESTORE_STATE + +opportunistic_sysret_failed: SWAPGS jmp restore_args @@ -1048,6 +1023,11 @@ ENTRY(\sym) CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15 .if \paranoid + .if \paranoid == 1 + CFI_REMEMBER_STATE + testl $3, CS(%rsp) /* If coming from userspace, switch */ + jnz 1f /* stacks. */ + .endif call save_paranoid .else call error_entry @@ -1088,6 +1068,36 @@ ENTRY(\sym) jmp error_exit /* %ebx: no swapgs flag */ .endif + .if \paranoid == 1 + CFI_RESTORE_STATE + /* + * Paranoid entry from userspace. Switch stacks and treat it + * as a normal entry. This means that paranoid handlers + * run in real process context if user_mode(regs). + */ +1: + call error_entry + + DEFAULT_FRAME 0 + + movq %rsp,%rdi /* pt_regs pointer */ + call sync_regs + movq %rax,%rsp /* switch stack */ + + movq %rsp,%rdi /* pt_regs pointer */ + + .if \has_error_code + movq ORIG_RAX(%rsp),%rsi /* get error code */ + movq $-1,ORIG_RAX(%rsp) /* no syscall to restart */ + .else + xorl %esi,%esi /* no error code */ + .endif + + call \do_sym + + jmp error_exit /* %ebx: no swapgs flag */ + .endif + CFI_ENDPROC END(\sym) .endm @@ -1108,7 +1118,7 @@ idtentry overflow do_overflow has_error_code=0 idtentry bounds do_bounds has_error_code=0 idtentry invalid_op do_invalid_op has_error_code=0 idtentry device_not_available do_device_not_available has_error_code=0 -idtentry double_fault do_double_fault has_error_code=1 paranoid=1 +idtentry double_fault do_double_fault has_error_code=1 paranoid=2 idtentry coprocessor_segment_overrun do_coprocessor_segment_overrun has_error_code=0 idtentry invalid_TSS do_invalid_TSS has_error_code=1 idtentry segment_not_present do_segment_not_present has_error_code=1 @@ -1289,16 +1299,14 @@ idtentry machine_check has_error_code=0 paranoid=1 do_sym=*machine_check_vector( #endif /* - * "Paranoid" exit path from exception stack. - * Paranoid because this is used by NMIs and cannot take - * any kernel state for granted. - * We don't do kernel preemption checks here, because only - * NMI should be common and it does not enable IRQs and - * cannot get reschedule ticks. + * "Paranoid" exit path from exception stack. This is invoked + * only on return from non-NMI IST interrupts that came + * from kernel space. * - * "trace" is 0 for the NMI handler only, because irq-tracing - * is fundamentally NMI-unsafe. (we cannot change the soft and - * hard flags at once, atomically) + * We may be returning to very strange contexts (e.g. very early + * in syscall entry), so checking for preemption here would + * be complicated. Fortunately, we there's no good reason + * to try to handle preemption here. */ /* ebx: no swapgs flag */ @@ -1308,43 +1316,14 @@ ENTRY(paranoid_exit) TRACE_IRQS_OFF_DEBUG testl %ebx,%ebx /* swapgs needed? */ jnz paranoid_restore - testl $3,CS(%rsp) - jnz paranoid_userspace -paranoid_swapgs: TRACE_IRQS_IRETQ 0 SWAPGS_UNSAFE_STACK RESTORE_ALL 8 - jmp irq_return + INTERRUPT_RETURN paranoid_restore: TRACE_IRQS_IRETQ_DEBUG 0 RESTORE_ALL 8 - jmp irq_return -paranoid_userspace: - GET_THREAD_INFO(%rcx) - movl TI_flags(%rcx),%ebx - andl $_TIF_WORK_MASK,%ebx - jz paranoid_swapgs - movq %rsp,%rdi /* &pt_regs */ - call sync_regs - movq %rax,%rsp /* switch stack for scheduling */ - testl $_TIF_NEED_RESCHED,%ebx - jnz paranoid_schedule - movl %ebx,%edx /* arg3: thread flags */ - TRACE_IRQS_ON - ENABLE_INTERRUPTS(CLBR_NONE) - xorl %esi,%esi /* arg2: oldset */ - movq %rsp,%rdi /* arg1: &pt_regs */ - call do_notify_resume - DISABLE_INTERRUPTS(CLBR_NONE) - TRACE_IRQS_OFF - jmp paranoid_userspace -paranoid_schedule: - TRACE_IRQS_ON - ENABLE_INTERRUPTS(CLBR_ANY) - SCHEDULE_USER - DISABLE_INTERRUPTS(CLBR_ANY) - TRACE_IRQS_OFF - jmp paranoid_userspace + INTERRUPT_RETURN CFI_ENDPROC END(paranoid_exit) diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 2142376dc8c6..8b7b0a51e742 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -674,7 +674,7 @@ static inline void *alloc_tramp(unsigned long size) } static inline void tramp_free(void *tramp) { - module_free(NULL, tramp); + module_memfree(tramp); } #else /* Trampolines can only be created if modules are supported */ diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c index 3d5fb509bdeb..7114ba220fd4 100644 --- a/arch/x86/kernel/hw_breakpoint.c +++ b/arch/x86/kernel/hw_breakpoint.c @@ -126,6 +126,8 @@ int arch_install_hw_breakpoint(struct perf_event *bp) *dr7 |= encode_dr7(i, info->len, info->type); set_debugreg(*dr7, 7); + if (info->mask) + set_dr_addr_mask(info->mask, i); return 0; } @@ -161,29 +163,8 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp) *dr7 &= ~__encode_dr7(i, info->len, info->type); set_debugreg(*dr7, 7); -} - -static int get_hbp_len(u8 hbp_len) -{ - unsigned int len_in_bytes = 0; - - switch (hbp_len) { - case X86_BREAKPOINT_LEN_1: - len_in_bytes = 1; - break; - case X86_BREAKPOINT_LEN_2: - len_in_bytes = 2; - break; - case X86_BREAKPOINT_LEN_4: - len_in_bytes = 4; - break; -#ifdef CONFIG_X86_64 - case X86_BREAKPOINT_LEN_8: - len_in_bytes = 8; - break; -#endif - } - return len_in_bytes; + if (info->mask) + set_dr_addr_mask(0, i); } /* @@ -196,7 +177,7 @@ int arch_check_bp_in_kernelspace(struct perf_event *bp) struct arch_hw_breakpoint *info = counter_arch_bp(bp); va = info->address; - len = get_hbp_len(info->len); + len = bp->attr.bp_len; return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); } @@ -277,6 +258,8 @@ static int arch_build_bp_info(struct perf_event *bp) } /* Len */ + info->mask = 0; + switch (bp->attr.bp_len) { case HW_BREAKPOINT_LEN_1: info->len = X86_BREAKPOINT_LEN_1; @@ -293,11 +276,17 @@ static int arch_build_bp_info(struct perf_event *bp) break; #endif default: - return -EINVAL; + if (!is_power_of_2(bp->attr.bp_len)) + return -EINVAL; + if (!cpu_has_bpext) + return -EOPNOTSUPP; + info->mask = bp->attr.bp_len - 1; + info->len = X86_BREAKPOINT_LEN_1; } return 0; } + /* * Validate the arch-specific HW Breakpoint register settings */ @@ -312,11 +301,11 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) if (ret) return ret; - ret = -EINVAL; - switch (info->len) { case X86_BREAKPOINT_LEN_1: align = 0; + if (info->mask) + align = info->mask; break; case X86_BREAKPOINT_LEN_2: align = 1; @@ -330,7 +319,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) break; #endif default: - return ret; + WARN_ON_ONCE(1); } /* diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index a9a4229f6161..81049ffab2d6 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c @@ -19,6 +19,19 @@ #include #include +static DEFINE_PER_CPU(bool, in_kernel_fpu); + +void kernel_fpu_disable(void) +{ + WARN_ON(this_cpu_read(in_kernel_fpu)); + this_cpu_write(in_kernel_fpu, true); +} + +void kernel_fpu_enable(void) +{ + this_cpu_write(in_kernel_fpu, false); +} + /* * Were we in an interrupt that interrupted kernel mode? * @@ -33,6 +46,9 @@ */ static inline bool interrupted_kernel_fpu_idle(void) { + if (this_cpu_read(in_kernel_fpu)) + return false; + if (use_eager_fpu()) return __thread_has_fpu(current); @@ -73,10 +89,10 @@ void __kernel_fpu_begin(void) { struct task_struct *me = current; + this_cpu_write(in_kernel_fpu, true); + if (__thread_has_fpu(me)) { - __thread_clear_has_fpu(me); __save_init_fpu(me); - /* We do 'stts()' in __kernel_fpu_end() */ } else if (!use_eager_fpu()) { this_cpu_write(fpu_owner_task, NULL); clts(); @@ -86,19 +102,16 @@ EXPORT_SYMBOL(__kernel_fpu_begin); void __kernel_fpu_end(void) { - if (use_eager_fpu()) { - /* - * For eager fpu, most the time, tsk_used_math() is true. - * Restore the user math as we are done with the kernel usage. - * At few instances during thread exit, signal handling etc, - * tsk_used_math() is false. Those few places will take proper - * actions, so we don't need to restore the math here. - */ - if (likely(tsk_used_math(current))) - math_state_restore(); - } else { + struct task_struct *me = current; + + if (__thread_has_fpu(me)) { + if (WARN_ON(restore_fpu_checking(me))) + drop_init_fpu(me); + } else if (!use_eager_fpu()) { stts(); } + + this_cpu_write(in_kernel_fpu, false); } EXPORT_SYMBOL(__kernel_fpu_end); diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 6307a0f0cf17..705ef8d48e2d 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -127,7 +127,7 @@ int arch_show_interrupts(struct seq_file *p, int prec) seq_puts(p, " Machine check polls\n"); #endif #if IS_ENABLED(CONFIG_HYPERV) || defined(CONFIG_XEN) - seq_printf(p, "%*s: ", prec, "THR"); + seq_printf(p, "%*s: ", prec, "HYP"); for_each_online_cpu(j) seq_printf(p, "%10u ", irq_stats(j)->irq_hv_callback_count); seq_puts(p, " Hypervisor callback interrupts\n"); diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index 63ce838e5a54..28d28f5eb8f4 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c @@ -69,16 +69,9 @@ static void call_on_stack(void *func, void *stack) : "memory", "cc", "edx", "ecx", "eax"); } -/* how to get the current stack pointer from C */ -#define current_stack_pointer ({ \ - unsigned long sp; \ - asm("mov %%esp,%0" : "=g" (sp)); \ - sp; \ -}) - static inline void *current_stack(void) { - return (void *)(current_stack_pointer & ~(THREAD_SIZE - 1)); + return (void *)(current_stack_pointer() & ~(THREAD_SIZE - 1)); } static inline int @@ -103,7 +96,7 @@ execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq) /* Save the next esp at the bottom of the stack */ prev_esp = (u32 *)irqstk; - *prev_esp = current_stack_pointer; + *prev_esp = current_stack_pointer(); if (unlikely(overflow)) call_on_stack(print_stack_overflow, isp); @@ -156,7 +149,7 @@ void do_softirq_own_stack(void) /* Push the previous esp onto the stack */ prev_esp = (u32 *)irqstk; - *prev_esp = current_stack_pointer; + *prev_esp = current_stack_pointer(); call_on_stack(__do_softirq, isp); } diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index 7c523bbf3dc8..0dd8d089c315 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c @@ -322,7 +322,8 @@ void arch_remove_optimized_kprobe(struct optimized_kprobe *op) * Target instructions MUST be relocatable (checked inside) * This is called when new aggr(opt)probe is allocated or reused. */ -int arch_prepare_optimized_kprobe(struct optimized_kprobe *op) +int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, + struct kprobe *__unused) { u8 *buf; int ret; diff --git a/arch/x86/kernel/livepatch.c b/arch/x86/kernel/livepatch.c new file mode 100644 index 000000000000..ff3c3101d003 --- /dev/null +++ b/arch/x86/kernel/livepatch.c @@ -0,0 +1,90 @@ +/* + * livepatch.c - x86-specific Kernel Live Patching Core + * + * Copyright (C) 2014 Seth Jennings + * Copyright (C) 2014 SUSE + * + * 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, see . + */ + +#include +#include +#include +#include +#include +#include + +/** + * klp_write_module_reloc() - write a relocation in a module + * @mod: module in which the section to be modified is found + * @type: ELF relocation type (see asm/elf.h) + * @loc: address that the relocation should be written to + * @value: relocation value (sym address + addend) + * + * This function writes a relocation to the specified location for + * a particular module. + */ +int klp_write_module_reloc(struct module *mod, unsigned long type, + unsigned long loc, unsigned long value) +{ + int ret, numpages, size = 4; + bool readonly; + unsigned long val; + unsigned long core = (unsigned long)mod->module_core; + unsigned long core_ro_size = mod->core_ro_size; + unsigned long core_size = mod->core_size; + + switch (type) { + case R_X86_64_NONE: + return 0; + case R_X86_64_64: + val = value; + size = 8; + break; + case R_X86_64_32: + val = (u32)value; + break; + case R_X86_64_32S: + val = (s32)value; + break; + case R_X86_64_PC32: + val = (u32)(value - loc); + break; + default: + /* unsupported relocation type */ + return -EINVAL; + } + + if (loc < core || loc >= core + core_size) + /* loc does not point to any symbol inside the module */ + return -EINVAL; + + if (loc < core + core_ro_size) + readonly = true; + else + readonly = false; + + /* determine if the relocation spans a page boundary */ + numpages = ((loc & PAGE_MASK) == ((loc + size) & PAGE_MASK)) ? 1 : 2; + + if (readonly) + set_memory_rw(loc & PAGE_MASK, numpages); + + ret = probe_kernel_write((void *)loc, &val, size); + + if (readonly) + set_memory_ro(loc & PAGE_MASK, numpages); + + return ret; +} diff --git a/arch/x86/kernel/pmc_atom.c b/arch/x86/kernel/pmc_atom.c index 0ee5025e0fa4..d66a4fe6caee 100644 --- a/arch/x86/kernel/pmc_atom.c +++ b/arch/x86/kernel/pmc_atom.c @@ -25,8 +25,6 @@ #include -#define DRIVER_NAME KBUILD_MODNAME - struct pmc_dev { u32 base_addr; void __iomem *regmap; @@ -38,12 +36,12 @@ struct pmc_dev { static struct pmc_dev pmc_device; static u32 acpi_base_addr; -struct pmc_dev_map { +struct pmc_bit_map { const char *name; u32 bit_mask; }; -static const struct pmc_dev_map dev_map[] = { +static const struct pmc_bit_map dev_map[] = { {"0 - LPSS1_F0_DMA", BIT_LPSS1_F0_DMA}, {"1 - LPSS1_F1_PWM1", BIT_LPSS1_F1_PWM1}, {"2 - LPSS1_F2_PWM2", BIT_LPSS1_F2_PWM2}, @@ -82,6 +80,27 @@ static const struct pmc_dev_map dev_map[] = { {"35 - DFX", BIT_DFX}, }; +static const struct pmc_bit_map pss_map[] = { + {"0 - GBE", PMC_PSS_BIT_GBE}, + {"1 - SATA", PMC_PSS_BIT_SATA}, + {"2 - HDA", PMC_PSS_BIT_HDA}, + {"3 - SEC", PMC_PSS_BIT_SEC}, + {"4 - PCIE", PMC_PSS_BIT_PCIE}, + {"5 - LPSS", PMC_PSS_BIT_LPSS}, + {"6 - LPE", PMC_PSS_BIT_LPE}, + {"7 - DFX", PMC_PSS_BIT_DFX}, + {"8 - USH_CTRL", PMC_PSS_BIT_USH_CTRL}, + {"9 - USH_SUS", PMC_PSS_BIT_USH_SUS}, + {"10 - USH_VCCS", PMC_PSS_BIT_USH_VCCS}, + {"11 - USH_VCCA", PMC_PSS_BIT_USH_VCCA}, + {"12 - OTG_CTRL", PMC_PSS_BIT_OTG_CTRL}, + {"13 - OTG_VCCS", PMC_PSS_BIT_OTG_VCCS}, + {"14 - OTG_VCCA_CLK", PMC_PSS_BIT_OTG_VCCA_CLK}, + {"15 - OTG_VCCA", PMC_PSS_BIT_OTG_VCCA}, + {"16 - USB", PMC_PSS_BIT_USB}, + {"17 - USB_SUS", PMC_PSS_BIT_USB_SUS}, +}; + static inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset) { return readl(pmc->regmap + reg_offset); @@ -169,6 +188,32 @@ static const struct file_operations pmc_dev_state_ops = { .release = single_release, }; +static int pmc_pss_state_show(struct seq_file *s, void *unused) +{ + struct pmc_dev *pmc = s->private; + u32 pss = pmc_reg_read(pmc, PMC_PSS); + int pss_index; + + for (pss_index = 0; pss_index < ARRAY_SIZE(pss_map); pss_index++) { + seq_printf(s, "Island: %-32s\tState: %s\n", + pss_map[pss_index].name, + pss_map[pss_index].bit_mask & pss ? "Off" : "On"); + } + return 0; +} + +static int pmc_pss_state_open(struct inode *inode, struct file *file) +{ + return single_open(file, pmc_pss_state_show, inode->i_private); +} + +static const struct file_operations pmc_pss_state_ops = { + .open = pmc_pss_state_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int pmc_sleep_tmr_show(struct seq_file *s, void *unused) { struct pmc_dev *pmc = s->private; @@ -202,11 +247,7 @@ static const struct file_operations pmc_sleep_tmr_ops = { static void pmc_dbgfs_unregister(struct pmc_dev *pmc) { - if (!pmc->dbgfs_dir) - return; - debugfs_remove_recursive(pmc->dbgfs_dir); - pmc->dbgfs_dir = NULL; } static int pmc_dbgfs_register(struct pmc_dev *pmc, struct pci_dev *pdev) @@ -217,19 +258,29 @@ static int pmc_dbgfs_register(struct pmc_dev *pmc, struct pci_dev *pdev) if (!dir) return -ENOMEM; + pmc->dbgfs_dir = dir; + f = debugfs_create_file("dev_state", S_IFREG | S_IRUGO, dir, pmc, &pmc_dev_state_ops); if (!f) { - dev_err(&pdev->dev, "dev_states register failed\n"); + dev_err(&pdev->dev, "dev_state register failed\n"); goto err; } + + f = debugfs_create_file("pss_state", S_IFREG | S_IRUGO, + dir, pmc, &pmc_pss_state_ops); + if (!f) { + dev_err(&pdev->dev, "pss_state register failed\n"); + goto err; + } + f = debugfs_create_file("sleep_state", S_IFREG | S_IRUGO, dir, pmc, &pmc_sleep_tmr_ops); if (!f) { dev_err(&pdev->dev, "sleep_state register failed\n"); goto err; } - pmc->dbgfs_dir = dir; + return 0; err: pmc_dbgfs_unregister(pmc); @@ -292,7 +343,6 @@ MODULE_DEVICE_TABLE(pci, pmc_pci_ids); static int __init pmc_atom_init(void) { - int err = -ENODEV; struct pci_dev *pdev = NULL; const struct pci_device_id *ent; @@ -306,14 +356,11 @@ static int __init pmc_atom_init(void) */ for_each_pci_dev(pdev) { ent = pci_match_id(pmc_pci_ids, pdev); - if (ent) { - err = pmc_setup_dev(pdev); - goto out; - } + if (ent) + return pmc_setup_dev(pdev); } /* Device not found. */ -out: - return err; + return -ENODEV; } module_init(pmc_atom_init); diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c index ca9622a25e95..fe3dbfe0c4a5 100644 --- a/arch/x86/kernel/rtc.c +++ b/arch/x86/kernel/rtc.c @@ -170,7 +170,7 @@ static struct platform_device rtc_device = { static __init int add_rtc_cmos(void) { #ifdef CONFIG_PNP - static const char * const const ids[] __initconst = + static const char * const ids[] __initconst = { "PNP0b00", "PNP0b01", "PNP0b02", }; struct pnp_dev *dev; struct pnp_id *id; diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index ab4734e5411d..c4648adadd7d 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -431,15 +431,13 @@ static void __init parse_setup_data(void) pa_data = boot_params.hdr.setup_data; while (pa_data) { - u32 data_len, map_len, data_type; + u32 data_len, data_type; - map_len = max(PAGE_SIZE - (pa_data & ~PAGE_MASK), - (u64)sizeof(struct setup_data)); - data = early_memremap(pa_data, map_len); + data = early_memremap(pa_data, sizeof(*data)); data_len = data->len + sizeof(struct setup_data); data_type = data->type; pa_next = data->next; - early_iounmap(data, map_len); + early_iounmap(data, sizeof(*data)); switch (data_type) { case SETUP_E820_EXT: diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index ed37a768d0fc..2a33c8f68319 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -740,12 +740,6 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) { user_exit(); -#ifdef CONFIG_X86_MCE - /* notify userspace of pending MCEs */ - if (thread_info_flags & _TIF_MCE_NOTIFY) - mce_notify_process(); -#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ - if (thread_info_flags & _TIF_UPROBE) uprobe_notify_resume(regs); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 6d7022c683e3..febc6aabc72e 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -73,7 +73,6 @@ #include #include #include -#include #include #include #include @@ -104,6 +103,43 @@ EXPORT_PER_CPU_SYMBOL(cpu_info); atomic_t init_deasserted; +static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) +{ + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); + CMOS_WRITE(0xa, 0xf); + spin_unlock_irqrestore(&rtc_lock, flags); + local_flush_tlb(); + pr_debug("1.\n"); + *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) = + start_eip >> 4; + pr_debug("2.\n"); + *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = + start_eip & 0xf; + pr_debug("3.\n"); +} + +static inline void smpboot_restore_warm_reset_vector(void) +{ + unsigned long flags; + + /* + * Install writable page 0 entry to set BIOS data area. + */ + local_flush_tlb(); + + /* + * Paranoid: Set warm reset code and vector here back + * to default values. + */ + spin_lock_irqsave(&rtc_lock, flags); + CMOS_WRITE(0, 0xf); + spin_unlock_irqrestore(&rtc_lock, flags); + + *((volatile u32 *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = 0; +} + /* * Report back to the Boot Processor during boot time or to the caller processor * during CPU online. @@ -136,8 +172,7 @@ static void smp_callin(void) * CPU, first the APIC. (this is probably redundant on most * boards) */ - setup_local_APIC(); - end_local_APIC_setup(); + apic_ap_setup(); /* * Need to setup vector mappings before we enable interrupts. @@ -955,9 +990,12 @@ void arch_disable_smp_support(void) */ static __init void disable_smp(void) { + pr_info("SMP disabled\n"); + + disable_ioapic_support(); + init_cpu_present(cpumask_of(0)); init_cpu_possible(cpumask_of(0)); - smpboot_clear_io_apic_irqs(); if (smp_found_config) physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); @@ -967,6 +1005,13 @@ static __init void disable_smp(void) cpumask_set_cpu(0, cpu_core_mask(0)); } +enum { + SMP_OK, + SMP_NO_CONFIG, + SMP_NO_APIC, + SMP_FORCE_UP, +}; + /* * Various sanity checks. */ @@ -1014,10 +1059,7 @@ static int __init smp_sanity_check(unsigned max_cpus) if (!smp_found_config && !acpi_lapic) { preempt_enable(); pr_notice("SMP motherboard not detected\n"); - disable_smp(); - if (APIC_init_uniprocessor()) - pr_notice("Local APIC not detected. Using dummy APIC emulation.\n"); - return -1; + return SMP_NO_CONFIG; } /* @@ -1041,9 +1083,7 @@ static int __init smp_sanity_check(unsigned max_cpus) boot_cpu_physical_apicid); pr_err("... forcing use of dummy APIC emulation (tell your hw vendor)\n"); } - smpboot_clear_io_apic(); - disable_ioapic_support(); - return -1; + return SMP_NO_APIC; } verify_local_APIC(); @@ -1053,15 +1093,10 @@ static int __init smp_sanity_check(unsigned max_cpus) */ if (!max_cpus) { pr_info("SMP mode deactivated\n"); - smpboot_clear_io_apic(); - - connect_bsp_APIC(); - setup_local_APIC(); - bsp_end_local_APIC_setup(); - return -1; + return SMP_FORCE_UP; } - return 0; + return SMP_OK; } static void __init smp_cpu_index_default(void) @@ -1101,10 +1136,21 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) } set_cpu_sibling_map(0); - if (smp_sanity_check(max_cpus) < 0) { - pr_info("SMP disabled\n"); + switch (smp_sanity_check(max_cpus)) { + case SMP_NO_CONFIG: + disable_smp(); + if (APIC_init_uniprocessor()) + pr_notice("Local APIC not detected. Using dummy APIC emulation.\n"); + return; + case SMP_NO_APIC: disable_smp(); return; + case SMP_FORCE_UP: + disable_smp(); + apic_bsp_setup(false); + return; + case SMP_OK: + break; } default_setup_apic_routing(); @@ -1115,33 +1161,10 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) /* Or can we switch back to PIC here? */ } - connect_bsp_APIC(); - - /* - * Switch from PIC to APIC mode. - */ - setup_local_APIC(); - - if (x2apic_mode) - cpu0_logical_apicid = apic_read(APIC_LDR); - else - cpu0_logical_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR)); - - /* - * Enable IO APIC before setting up error vector - */ - if (!skip_ioapic_setup && nr_ioapics) - enable_IO_APIC(); - - bsp_end_local_APIC_setup(); - smpboot_setup_io_apic(); - /* - * Set up local APIC timer on boot CPU. - */ + cpu0_logical_apicid = apic_bsp_setup(false); pr_info("CPU%d: ", 0); print_cpu_info(&cpu_data(0)); - x86_init.timers.setup_percpu_clockev(); if (is_uv_system()) uv_system_init(); @@ -1177,9 +1200,7 @@ void __init native_smp_cpus_done(unsigned int max_cpus) nmi_selftest(); impress_friends(); -#ifdef CONFIG_X86_IO_APIC setup_ioapic_dest(); -#endif mtrr_aps_init(); } diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index 4e942f31b1a7..7fc5e843f247 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c @@ -29,7 +29,28 @@ static int get_free_idx(void) static bool tls_desc_okay(const struct user_desc *info) { - if (LDT_empty(info)) + /* + * For historical reasons (i.e. no one ever documented how any + * of the segmentation APIs work), user programs can and do + * assume that a struct user_desc that's all zeros except for + * entry_number means "no segment at all". This never actually + * worked. In fact, up to Linux 3.19, a struct user_desc like + * this would create a 16-bit read-write segment with base and + * limit both equal to zero. + * + * That was close enough to "no segment at all" until we + * hardened this function to disallow 16-bit TLS segments. Fix + * it up by interpreting these zeroed segments the way that they + * were almost certainly intended to be interpreted. + * + * The correct way to ask for "no segment at all" is to specify + * a user_desc that satisfies LDT_empty. To keep everything + * working, we accept both. + * + * Note that there's a similar kludge in modify_ldt -- look at + * the distinction between modes 1 and 0x11. + */ + if (LDT_empty(info) || LDT_zero(info)) return true; /* @@ -71,7 +92,7 @@ static void set_tls_desc(struct task_struct *p, int idx, cpu = get_cpu(); while (n-- > 0) { - if (LDT_empty(info)) + if (LDT_empty(info) || LDT_zero(info)) desc->a = desc->b = 0; else fill_ldt(desc, info); diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 88900e288021..9d2073e2ecc9 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -108,6 +108,88 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) preempt_count_dec(); } +enum ctx_state ist_enter(struct pt_regs *regs) +{ + enum ctx_state prev_state; + + if (user_mode_vm(regs)) { + /* Other than that, we're just an exception. */ + prev_state = exception_enter(); + } else { + /* + * We might have interrupted pretty much anything. In + * fact, if we're a machine check, we can even interrupt + * NMI processing. We don't want in_nmi() to return true, + * but we need to notify RCU. + */ + rcu_nmi_enter(); + prev_state = IN_KERNEL; /* the value is irrelevant. */ + } + + /* + * We are atomic because we're on the IST stack (or we're on x86_32, + * in which case we still shouldn't schedule). + * + * This must be after exception_enter(), because exception_enter() + * won't do anything if in_interrupt() returns true. + */ + preempt_count_add(HARDIRQ_OFFSET); + + /* This code is a bit fragile. Test it. */ + rcu_lockdep_assert(rcu_is_watching(), "ist_enter didn't work"); + + return prev_state; +} + +void ist_exit(struct pt_regs *regs, enum ctx_state prev_state) +{ + /* Must be before exception_exit. */ + preempt_count_sub(HARDIRQ_OFFSET); + + if (user_mode_vm(regs)) + return exception_exit(prev_state); + else + rcu_nmi_exit(); +} + +/** + * ist_begin_non_atomic() - begin a non-atomic section in an IST exception + * @regs: regs passed to the IST exception handler + * + * IST exception handlers normally cannot schedule. As a special + * exception, if the exception interrupted userspace code (i.e. + * user_mode_vm(regs) would return true) and the exception was not + * a double fault, it can be safe to schedule. ist_begin_non_atomic() + * begins a non-atomic section within an ist_enter()/ist_exit() region. + * Callers are responsible for enabling interrupts themselves inside + * the non-atomic section, and callers must call is_end_non_atomic() + * before ist_exit(). + */ +void ist_begin_non_atomic(struct pt_regs *regs) +{ + BUG_ON(!user_mode_vm(regs)); + + /* + * Sanity check: we need to be on the normal thread stack. This + * will catch asm bugs and any attempt to use ist_preempt_enable + * from double_fault. + */ + BUG_ON(((current_stack_pointer() ^ this_cpu_read_stable(kernel_stack)) + & ~(THREAD_SIZE - 1)) != 0); + + preempt_count_sub(HARDIRQ_OFFSET); +} + +/** + * ist_end_non_atomic() - begin a non-atomic section in an IST exception + * + * Ends a non-atomic section started with ist_begin_non_atomic(). + */ +void ist_end_non_atomic(void) +{ + preempt_count_add(HARDIRQ_OFFSET); +} + static nokprobe_inline int do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str, struct pt_regs *regs, long error_code) @@ -251,6 +333,8 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) * end up promoting it to a doublefault. In that case, modify * the stack to make it look like we just entered the #GP * handler from user space, similar to bad_iret. + * + * No need for ist_enter here because we don't use RCU. */ if (((long)regs->sp >> PGDIR_SHIFT) == ESPFIX_PGD_ENTRY && regs->cs == __KERNEL_CS && @@ -263,12 +347,12 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) normal_regs->orig_ax = 0; /* Missing (lost) #GP error code */ regs->ip = (unsigned long)general_protection; regs->sp = (unsigned long)&normal_regs->orig_ax; + return; } #endif - exception_enter(); - /* Return not checked because double check cannot be ignored */ + ist_enter(regs); /* Discard prev_state because we won't return. */ notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV); tsk->thread.error_code = error_code; @@ -434,7 +518,7 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code) if (poke_int3_handler(regs)) return; - prev_state = exception_enter(); + prev_state = ist_enter(regs); #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, SIGTRAP) == NOTIFY_STOP) @@ -460,33 +544,20 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code) preempt_conditional_cli(regs); debug_stack_usage_dec(); exit: - exception_exit(prev_state); + ist_exit(regs, prev_state); } NOKPROBE_SYMBOL(do_int3); #ifdef CONFIG_X86_64 /* - * Help handler running on IST stack to switch back to user stack - * for scheduling or signal handling. The actual stack switch is done in - * entry.S + * Help handler running on IST stack to switch off the IST stack if the + * interrupted code was in user mode. The actual stack switch is done in + * entry_64.S */ asmlinkage __visible notrace struct pt_regs *sync_regs(struct pt_regs *eregs) { - struct pt_regs *regs = eregs; - /* Did already sync */ - if (eregs == (struct pt_regs *)eregs->sp) - ; - /* Exception from user space */ - else if (user_mode(eregs)) - regs = task_pt_regs(current); - /* - * Exception from kernel and interrupts are enabled. Move to - * kernel process stack. - */ - else if (eregs->flags & X86_EFLAGS_IF) - regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs)); - if (eregs != regs) - *regs = *eregs; + struct pt_regs *regs = task_pt_regs(current); + *regs = *eregs; return regs; } NOKPROBE_SYMBOL(sync_regs); @@ -554,7 +625,7 @@ dotraplinkage void do_debug(struct pt_regs *regs, long error_code) unsigned long dr6; int si_code; - prev_state = exception_enter(); + prev_state = ist_enter(regs); get_debugreg(dr6, 6); @@ -629,7 +700,7 @@ dotraplinkage void do_debug(struct pt_regs *regs, long error_code) debug_stack_usage_dec(); exit: - exception_exit(prev_state); + ist_exit(regs, prev_state); } NOKPROBE_SYMBOL(do_debug); @@ -788,18 +859,16 @@ void math_state_restore(void) local_irq_disable(); } + /* Avoid __kernel_fpu_begin() right after __thread_fpu_begin() */ + kernel_fpu_disable(); __thread_fpu_begin(tsk); - - /* - * Paranoid restore. send a SIGSEGV if we fail to restore the state. - */ if (unlikely(restore_fpu_checking(tsk))) { drop_init_fpu(tsk); force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk); - return; + } else { + tsk->thread.fpu_counter++; } - - tsk->thread.fpu_counter++; + kernel_fpu_enable(); } EXPORT_SYMBOL_GPL(math_state_restore); diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index b7e50bba3bbb..505449700e0c 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -617,7 +617,7 @@ static unsigned long quick_pit_calibrate(void) goto success; } } - pr_err("Fast TSC calibration failed\n"); + pr_info("Fast TSC calibration failed\n"); return 0; success: diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index f9d16ff56c6b..7dc7ba577ecd 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -40,6 +40,7 @@ config KVM select HAVE_KVM_MSI select HAVE_KVM_CPU_RELAX_INTERCEPT select KVM_VFIO + select SRCU ---help--- Support hosting fully virtualized guest machines using hardware virtualization extensions. You will need a fairly recent diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 169b09d76ddd..de12c1d379f1 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -2348,7 +2348,7 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) * Not recognized on AMD in compat mode (but is recognized in legacy * mode). */ - if ((ctxt->mode == X86EMUL_MODE_PROT32) && (efer & EFER_LMA) + if ((ctxt->mode != X86EMUL_MODE_PROT64) && (efer & EFER_LMA) && !vendor_intel(ctxt)) return emulate_ud(ctxt); @@ -2359,25 +2359,13 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) setup_syscalls_segments(ctxt, &cs, &ss); ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data); - switch (ctxt->mode) { - case X86EMUL_MODE_PROT32: - if ((msr_data & 0xfffc) == 0x0) - return emulate_gp(ctxt, 0); - break; - case X86EMUL_MODE_PROT64: - if (msr_data == 0x0) - return emulate_gp(ctxt, 0); - break; - default: - break; - } + if ((msr_data & 0xfffc) == 0x0) + return emulate_gp(ctxt, 0); ctxt->eflags &= ~(EFLG_VM | EFLG_IF); - cs_sel = (u16)msr_data; - cs_sel &= ~SELECTOR_RPL_MASK; + cs_sel = (u16)msr_data & ~SELECTOR_RPL_MASK; ss_sel = cs_sel + 8; - ss_sel &= ~SELECTOR_RPL_MASK; - if (ctxt->mode == X86EMUL_MODE_PROT64 || (efer & EFER_LMA)) { + if (efer & EFER_LMA) { cs.d = 0; cs.l = 1; } @@ -2386,10 +2374,11 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); ops->get_msr(ctxt, MSR_IA32_SYSENTER_EIP, &msr_data); - ctxt->_eip = msr_data; + ctxt->_eip = (efer & EFER_LMA) ? msr_data : (u32)msr_data; ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data); - *reg_write(ctxt, VCPU_REGS_RSP) = msr_data; + *reg_write(ctxt, VCPU_REGS_RSP) = (efer & EFER_LMA) ? msr_data : + (u32)msr_data; return X86EMUL_CONTINUE; } @@ -3791,8 +3780,8 @@ static const struct opcode group5[] = { }; static const struct opcode group6[] = { - DI(Prot, sldt), - DI(Prot, str), + DI(Prot | DstMem, sldt), + DI(Prot | DstMem, str), II(Prot | Priv | SrcMem16, em_lldt, lldt), II(Prot | Priv | SrcMem16, em_ltr, ltr), N, N, N, N, diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 4f0c0b954686..d52dcf0776ea 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -192,6 +192,9 @@ static void recalculate_apic_map(struct kvm *kvm) u16 cid, lid; u32 ldr, aid; + if (!kvm_apic_present(vcpu)) + continue; + aid = kvm_apic_id(apic); ldr = kvm_apic_get_reg(apic, APIC_LDR); cid = apic_cluster_id(new, ldr); diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 38dcec403b46..e3ff27a5b634 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -898,6 +898,8 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code, if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON| VM_FAULT_HWPOISON_LARGE)) do_sigbus(regs, error_code, address, fault); + else if (fault & VM_FAULT_SIGSEGV) + bad_area_nosemaphore(regs, error_code, address); else BUG(); } diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c index d7547824e763..89df70e0caa6 100644 --- a/arch/x86/mm/gup.c +++ b/arch/x86/mm/gup.c @@ -172,7 +172,7 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end, */ if (pmd_none(pmd) || pmd_trans_splitting(pmd)) return 0; - if (unlikely(pmd_large(pmd))) { + if (unlikely(pmd_large(pmd) || !pmd_present(pmd))) { /* * NUMA hinting faults need to be handled in the GUP * slowpath for accounting purposes and so that they @@ -388,10 +388,9 @@ slow_irqon: start += nr << PAGE_SHIFT; pages += nr; - down_read(&mm->mmap_sem); - ret = get_user_pages(current, mm, start, - (end - start) >> PAGE_SHIFT, write, 0, pages, NULL); - up_read(&mm->mmap_sem); + ret = get_user_pages_unlocked(current, mm, start, + (end - start) >> PAGE_SHIFT, + write, 0, pages); /* Have to be a bit careful with return values */ if (nr > 0) { diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c index 8b977ebf9388..42982b26e32b 100644 --- a/arch/x86/mm/hugetlbpage.c +++ b/arch/x86/mm/hugetlbpage.c @@ -52,23 +52,17 @@ int pud_huge(pud_t pud) return 0; } -struct page * -follow_huge_pmd(struct mm_struct *mm, unsigned long address, - pmd_t *pmd, int write) -{ - return NULL; -} #else -struct page * -follow_huge_addr(struct mm_struct *mm, unsigned long address, int write) -{ - return ERR_PTR(-EINVAL); -} - +/* + * pmd_huge() returns 1 if @pmd is hugetlb related entry, that is normal + * hugetlb entry or non-present (migration or hwpoisoned) hugetlb entry. + * Otherwise, returns 0. + */ int pmd_huge(pmd_t pmd) { - return !!(pmd_val(pmd) & _PAGE_PSE); + return !pmd_none(pmd) && + (pmd_val(pmd) & (_PAGE_PRESENT|_PAGE_PSE)) != _PAGE_PRESENT; } int pud_huge(pud_t pud) @@ -178,4 +172,15 @@ static __init int setup_hugepagesz(char *opt) return 1; } __setup("hugepagesz=", setup_hugepagesz); + +#ifdef CONFIG_CMA +static __init int gigantic_pages_init(void) +{ + /* With CMA we can allocate gigantic pages at runtime */ + if (cpu_has_gbpages && !size_to_hstate(1UL << PUD_SHIFT)) + hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT); + return 0; +} +arch_initcall(gigantic_pages_init); +#endif #endif diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 08a7d313538a..649da47d3827 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -43,7 +43,7 @@ uint16_t __cachemode2pte_tbl[_PAGE_CACHE_MODE_NUM] = { [_PAGE_CACHE_MODE_WT] = _PAGE_PCD, [_PAGE_CACHE_MODE_WP] = _PAGE_PCD, }; -EXPORT_SYMBOL_GPL(__cachemode2pte_tbl); +EXPORT_SYMBOL(__cachemode2pte_tbl); uint8_t __pte2cachemode_tbl[8] = { [__pte2cm_idx(0)] = _PAGE_CACHE_MODE_WB, [__pte2cm_idx(_PAGE_PWT)] = _PAGE_CACHE_MODE_WC, @@ -54,7 +54,7 @@ uint8_t __pte2cachemode_tbl[8] = { [__pte2cm_idx(_PAGE_PCD | _PAGE_PAT)] = _PAGE_CACHE_MODE_UC_MINUS, [__pte2cm_idx(_PAGE_PWT | _PAGE_PCD | _PAGE_PAT)] = _PAGE_CACHE_MODE_UC, }; -EXPORT_SYMBOL_GPL(__pte2cachemode_tbl); +EXPORT_SYMBOL(__pte2cachemode_tbl); static unsigned long __initdata pgt_buf_start; static unsigned long __initdata pgt_buf_end; @@ -608,7 +608,7 @@ void __init init_mem_mapping(void) * * * On x86, access has to be given to the first megabyte of ram because that area - * contains bios code and data regions used by X and dosemu and similar apps. + * contains BIOS code and data regions used by X and dosemu and similar apps. * Access has to be given to non-kernel-ram areas as well, these contain the PCI * mmio resources as well as potential bios/acpi data regions. */ diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c index 67ebf5751222..c439ec478216 100644 --- a/arch/x86/mm/mpx.c +++ b/arch/x86/mm/mpx.c @@ -348,6 +348,12 @@ static __user void *task_get_bounds_dir(struct task_struct *tsk) if (!cpu_feature_enabled(X86_FEATURE_MPX)) return MPX_INVALID_BOUNDS_DIR; + /* + * 32-bit binaries on 64-bit kernels are currently + * unsupported. + */ + if (IS_ENABLED(CONFIG_X86_64) && test_thread_flag(TIF_IA32)) + return MPX_INVALID_BOUNDS_DIR; /* * The bounds directory pointer is stored in a register * only accessible if we first do an xsave. diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index edf299c8ff6c..7ac68698406c 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -234,8 +234,13 @@ void pat_init(void) PAT(4, WB) | PAT(5, WC) | PAT(6, UC_MINUS) | PAT(7, UC); /* Boot CPU check */ - if (!boot_pat_state) + if (!boot_pat_state) { rdmsrl(MSR_IA32_CR_PAT, boot_pat_state); + if (!boot_pat_state) { + pat_disable("PAT read returns always zero, disabled."); + return; + } + } wrmsrl(MSR_IA32_CR_PAT, pat); diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index 6fb6927f9e76..7b22adaad4f1 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -190,7 +190,7 @@ void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd) #endif /* CONFIG_X86_PAE */ -static void free_pmds(pmd_t *pmds[]) +static void free_pmds(struct mm_struct *mm, pmd_t *pmds[]) { int i; @@ -198,10 +198,11 @@ static void free_pmds(pmd_t *pmds[]) if (pmds[i]) { pgtable_pmd_page_dtor(virt_to_page(pmds[i])); free_page((unsigned long)pmds[i]); + mm_dec_nr_pmds(mm); } } -static int preallocate_pmds(pmd_t *pmds[]) +static int preallocate_pmds(struct mm_struct *mm, pmd_t *pmds[]) { int i; bool failed = false; @@ -215,11 +216,13 @@ static int preallocate_pmds(pmd_t *pmds[]) pmd = NULL; failed = true; } + if (pmd) + mm_inc_nr_pmds(mm); pmds[i] = pmd; } if (failed) { - free_pmds(pmds); + free_pmds(mm, pmds); return -ENOMEM; } @@ -246,6 +249,7 @@ static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp) paravirt_release_pmd(pgd_val(pgd) >> PAGE_SHIFT); pmd_free(mm, pmd); + mm_dec_nr_pmds(mm); } } } @@ -283,7 +287,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm) mm->pgd = pgd; - if (preallocate_pmds(pmds) != 0) + if (preallocate_pmds(mm, pmds) != 0) goto out_free_pgd; if (paravirt_pgd_alloc(mm) != 0) @@ -304,7 +308,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm) return pgd; out_free_pmds: - free_pmds(pmds); + free_pmds(mm, pmds); out_free_pgd: free_page((unsigned long)pgd); out: diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index cfd1b132b8e3..6ac273832f28 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -10,9 +10,6 @@ struct pci_root_info { struct acpi_device *bridge; char name[16]; - unsigned int res_num; - struct resource *res; - resource_size_t *res_offset; struct pci_sysdata sd; #ifdef CONFIG_PCI_MMCONFIG bool mcfg_added; @@ -218,130 +215,41 @@ static void teardown_mcfg_map(struct pci_root_info *info) } #endif -static acpi_status resource_to_addr(struct acpi_resource *resource, - struct acpi_resource_address64 *addr) +static void validate_resources(struct device *dev, struct list_head *crs_res, + unsigned long type) { - acpi_status status; - struct acpi_resource_memory24 *memory24; - struct acpi_resource_memory32 *memory32; - struct acpi_resource_fixed_memory32 *fixed_memory32; + LIST_HEAD(list); + struct resource *res1, *res2, *root = NULL; + struct resource_entry *tmp, *entry, *entry2; - memset(addr, 0, sizeof(*addr)); - switch (resource->type) { - case ACPI_RESOURCE_TYPE_MEMORY24: - memory24 = &resource->data.memory24; - addr->resource_type = ACPI_MEMORY_RANGE; - addr->minimum = memory24->minimum; - addr->address_length = memory24->address_length; - addr->maximum = addr->minimum + addr->address_length - 1; - return AE_OK; - case ACPI_RESOURCE_TYPE_MEMORY32: - memory32 = &resource->data.memory32; - addr->resource_type = ACPI_MEMORY_RANGE; - addr->minimum = memory32->minimum; - addr->address_length = memory32->address_length; - addr->maximum = addr->minimum + addr->address_length - 1; - return AE_OK; - case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - fixed_memory32 = &resource->data.fixed_memory32; - addr->resource_type = ACPI_MEMORY_RANGE; - addr->minimum = fixed_memory32->address; - addr->address_length = fixed_memory32->address_length; - addr->maximum = addr->minimum + addr->address_length - 1; - return AE_OK; - case ACPI_RESOURCE_TYPE_ADDRESS16: - case ACPI_RESOURCE_TYPE_ADDRESS32: - case ACPI_RESOURCE_TYPE_ADDRESS64: - status = acpi_resource_to_address64(resource, addr); - if (ACPI_SUCCESS(status) && - (addr->resource_type == ACPI_MEMORY_RANGE || - addr->resource_type == ACPI_IO_RANGE) && - addr->address_length > 0) { - return AE_OK; - } - break; - } - return AE_ERROR; -} + BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0); + root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource; -static acpi_status count_resource(struct acpi_resource *acpi_res, void *data) -{ - struct pci_root_info *info = data; - struct acpi_resource_address64 addr; - acpi_status status; + list_splice_init(crs_res, &list); + resource_list_for_each_entry_safe(entry, tmp, &list) { + bool free = false; + resource_size_t end; - status = resource_to_addr(acpi_res, &addr); - if (ACPI_SUCCESS(status)) - info->res_num++; - return AE_OK; -} - -static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data) -{ - struct pci_root_info *info = data; - struct resource *res; - struct acpi_resource_address64 addr; - acpi_status status; - unsigned long flags; - u64 start, orig_end, end; - - status = resource_to_addr(acpi_res, &addr); - if (!ACPI_SUCCESS(status)) - return AE_OK; - - if (addr.resource_type == ACPI_MEMORY_RANGE) { - flags = IORESOURCE_MEM; - if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY) - flags |= IORESOURCE_PREFETCH; - } else if (addr.resource_type == ACPI_IO_RANGE) { - flags = IORESOURCE_IO; - } else - return AE_OK; - - start = addr.minimum + addr.translation_offset; - orig_end = end = addr.maximum + addr.translation_offset; - - /* Exclude non-addressable range or non-addressable portion of range */ - end = min(end, (u64)iomem_resource.end); - if (end <= start) { - dev_info(&info->bridge->dev, - "host bridge window [%#llx-%#llx] " - "(ignored, not CPU addressable)\n", start, orig_end); - return AE_OK; - } else if (orig_end != end) { - dev_info(&info->bridge->dev, - "host bridge window [%#llx-%#llx] " - "([%#llx-%#llx] ignored, not CPU addressable)\n", - start, orig_end, end + 1, orig_end); - } - - res = &info->res[info->res_num]; - res->name = info->name; - res->flags = flags; - res->start = start; - res->end = end; - info->res_offset[info->res_num] = addr.translation_offset; - info->res_num++; - - if (!pci_use_crs) - dev_printk(KERN_DEBUG, &info->bridge->dev, - "host bridge window %pR (ignored)\n", res); - - return AE_OK; -} - -static void coalesce_windows(struct pci_root_info *info, unsigned long type) -{ - int i, j; - struct resource *res1, *res2; - - for (i = 0; i < info->res_num; i++) { - res1 = &info->res[i]; + res1 = entry->res; if (!(res1->flags & type)) - continue; + goto next; - for (j = i + 1; j < info->res_num; j++) { - res2 = &info->res[j]; + /* Exclude non-addressable range or non-addressable portion */ + end = min(res1->end, root->end); + if (end <= res1->start) { + dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n", + res1); + free = true; + goto next; + } else if (res1->end != end) { + dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n", + res1, (unsigned long long)end + 1, + (unsigned long long)res1->end); + res1->end = end; + } + + resource_list_for_each_entry(entry2, crs_res) { + res2 = entry2->res; if (!(res2->flags & type)) continue; @@ -353,118 +261,92 @@ static void coalesce_windows(struct pci_root_info *info, unsigned long type) if (resource_overlaps(res1, res2)) { res2->start = min(res1->start, res2->start); res2->end = max(res1->end, res2->end); - dev_info(&info->bridge->dev, - "host bridge window expanded to %pR; %pR ignored\n", + dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n", res2, res1); - res1->flags = 0; + free = true; + goto next; } } + +next: + resource_list_del(entry); + if (free) + resource_list_free_entry(entry); + else + resource_list_add_tail(entry, crs_res); } } static void add_resources(struct pci_root_info *info, - struct list_head *resources) + struct list_head *resources, + struct list_head *crs_res) { - int i; - struct resource *res, *root, *conflict; + struct resource_entry *entry, *tmp; + struct resource *res, *conflict, *root = NULL; - coalesce_windows(info, IORESOURCE_MEM); - coalesce_windows(info, IORESOURCE_IO); - - for (i = 0; i < info->res_num; i++) { - res = &info->res[i]; + validate_resources(&info->bridge->dev, crs_res, IORESOURCE_MEM); + validate_resources(&info->bridge->dev, crs_res, IORESOURCE_IO); + resource_list_for_each_entry_safe(entry, tmp, crs_res) { + res = entry->res; if (res->flags & IORESOURCE_MEM) root = &iomem_resource; else if (res->flags & IORESOURCE_IO) root = &ioport_resource; else - continue; + BUG_ON(res); conflict = insert_resource_conflict(root, res); - if (conflict) + if (conflict) { dev_info(&info->bridge->dev, "ignoring host bridge window %pR (conflicts with %s %pR)\n", res, conflict->name, conflict); - else - pci_add_resource_offset(resources, res, - info->res_offset[i]); - } -} - -static void free_pci_root_info_res(struct pci_root_info *info) -{ - kfree(info->res); - info->res = NULL; - kfree(info->res_offset); - info->res_offset = NULL; - info->res_num = 0; -} - -static void __release_pci_root_info(struct pci_root_info *info) -{ - int i; - struct resource *res; - - for (i = 0; i < info->res_num; i++) { - res = &info->res[i]; - - if (!res->parent) - continue; - - if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) - continue; - - release_resource(res); + resource_list_destroy_entry(entry); + } } - free_pci_root_info_res(info); - - teardown_mcfg_map(info); - - kfree(info); + list_splice_tail(crs_res, resources); } static void release_pci_root_info(struct pci_host_bridge *bridge) { + struct resource *res; + struct resource_entry *entry; struct pci_root_info *info = bridge->release_data; - __release_pci_root_info(info); + resource_list_for_each_entry(entry, &bridge->windows) { + res = entry->res; + if (res->parent && + (res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) + release_resource(res); + } + + teardown_mcfg_map(info); + kfree(info); } static void probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device, - int busnum, int domain) + int busnum, int domain, + struct list_head *list) { - size_t size; + int ret; + struct resource_entry *entry; sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum); info->bridge = device; - - info->res_num = 0; - acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, - info); - if (!info->res_num) - return; - - size = sizeof(*info->res) * info->res_num; - info->res = kzalloc_node(size, GFP_KERNEL, info->sd.node); - if (!info->res) { - info->res_num = 0; - return; - } - - size = sizeof(*info->res_offset) * info->res_num; - info->res_num = 0; - info->res_offset = kzalloc_node(size, GFP_KERNEL, info->sd.node); - if (!info->res_offset) { - kfree(info->res); - info->res = NULL; - return; - } - - acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, - info); + ret = acpi_dev_get_resources(device, list, + acpi_dev_filter_resource_type_cb, + (void *)(IORESOURCE_IO | IORESOURCE_MEM)); + if (ret < 0) + dev_warn(&device->dev, + "failed to parse _CRS method, error code %d\n", ret); + else if (ret == 0) + dev_dbg(&device->dev, + "no IO and memory resources present in _CRS\n"); + else + resource_list_for_each_entry(entry, list) + entry->res->name = info->name; } struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) @@ -473,6 +355,8 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) struct pci_root_info *info; int domain = root->segment; int busnum = root->secondary.start; + struct resource_entry *res_entry; + LIST_HEAD(crs_res); LIST_HEAD(resources); struct pci_bus *bus; struct pci_sysdata *sd; @@ -520,18 +404,22 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) memcpy(bus->sysdata, sd, sizeof(*sd)); kfree(info); } else { - probe_pci_root_info(info, device, busnum, domain); - /* insert busn res at first */ pci_add_resource(&resources, &root->secondary); + /* * _CRS with no apertures is normal, so only fall back to * defaults or native bridge info if we're ignoring _CRS. */ - if (pci_use_crs) - add_resources(info, &resources); - else { - free_pci_root_info_res(info); + probe_pci_root_info(info, device, busnum, domain, &crs_res); + if (pci_use_crs) { + add_resources(info, &resources, &crs_res); + } else { + resource_list_for_each_entry(res_entry, &crs_res) + dev_printk(KERN_DEBUG, &device->dev, + "host bridge window %pR (ignored)\n", + res_entry->res); + resource_list_free(&crs_res); x86_pci_root_bus_resources(busnum, &resources); } @@ -546,8 +434,9 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) to_pci_host_bridge(bus->bridge), release_pci_root_info, info); } else { - pci_free_resource_list(&resources); - __release_pci_root_info(info); + resource_list_free(&resources); + teardown_mcfg_map(info); + kfree(info); } } diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c index f3a2cfc14125..7bcf06a7cd12 100644 --- a/arch/x86/pci/bus_numa.c +++ b/arch/x86/pci/bus_numa.c @@ -31,7 +31,7 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources) { struct pci_root_info *info = x86_find_pci_root_info(bus); struct pci_root_res *root_res; - struct pci_host_bridge_window *window; + struct resource_entry *window; bool found = false; if (!info) @@ -41,7 +41,7 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources) bus); /* already added by acpi ? */ - list_for_each_entry(window, resources, list) + resource_list_for_each_entry(window, resources) if (window->res->flags & IORESOURCE_BUS) { found = true; break; diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 7b20bccf3648..3d2612b68694 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -448,6 +448,22 @@ static const struct dmi_system_id pciprobe_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_NAME, "ftServer"), }, }, + { + .callback = set_scan_all, + .ident = "Stratus/NEC ftServer", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "NEC"), + DMI_MATCH(DMI_PRODUCT_NAME, "Express5800/R32"), + }, + }, + { + .callback = set_scan_all, + .ident = "Stratus/NEC ftServer", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "NEC"), + DMI_MATCH(DMI_PRODUCT_NAME, "Express5800/R31"), + }, + }, {} }; @@ -497,6 +513,31 @@ void __init pcibios_set_cache_line_size(void) } } +/* + * Some device drivers assume dev->irq won't change after calling + * pci_disable_device(). So delay releasing of IRQ resource to driver + * unbinding time. Otherwise it will break PM subsystem and drivers + * like xen-pciback etc. + */ +static int pci_irq_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct pci_dev *dev = to_pci_dev(data); + + if (action != BUS_NOTIFY_UNBOUND_DRIVER) + return NOTIFY_DONE; + + if (pcibios_disable_irq) + pcibios_disable_irq(dev); + + return NOTIFY_OK; +} + +static struct notifier_block pci_irq_nb = { + .notifier_call = pci_irq_notifier, + .priority = INT_MIN, +}; + int __init pcibios_init(void) { if (!raw_pci_ops) { @@ -509,6 +550,9 @@ int __init pcibios_init(void) if (pci_bf_sort >= pci_force_bf) pci_sort_breadthfirst(); + + bus_register_notifier(&pci_bus_type, &pci_irq_nb); + return 0; } @@ -667,12 +711,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) return 0; } -void pcibios_disable_device (struct pci_dev *dev) -{ - if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq) - pcibios_disable_irq(dev); -} - int pci_ext_cfg_avail(void) { if (raw_pci_ext_ops) diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 9b18ef315a55..349c0d32cc0b 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -216,7 +216,7 @@ static void pcibios_allocate_bridge_resources(struct pci_dev *dev) continue; if (r->parent) /* Already allocated */ continue; - if (!r->start || pci_claim_resource(dev, idx) < 0) { + if (!r->start || pci_claim_bridge_resource(dev, idx) < 0) { /* * Something is wrong with the region. * Invalidate the resource to prevent diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index 44b9271580b5..efb849323c74 100644 --- a/arch/x86/pci/intel_mid_pci.c +++ b/arch/x86/pci/intel_mid_pci.c @@ -234,10 +234,10 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev) static void intel_mid_pci_irq_disable(struct pci_dev *dev) { - if (!mp_should_keep_irq(&dev->dev) && dev->irq_managed && - dev->irq > 0) { + if (dev->irq_managed && dev->irq > 0) { mp_unmap_irq(dev->irq); dev->irq_managed = 0; + dev->irq = 0; } } @@ -293,7 +293,6 @@ static void mrst_power_off_unused_dev(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0801, mrst_power_off_unused_dev); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0809, mrst_power_off_unused_dev); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x080C, mrst_power_off_unused_dev); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0812, mrst_power_off_unused_dev); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0815, mrst_power_off_unused_dev); /* diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index 5dc6ca5e1741..e71b3dbd87b8 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -1256,22 +1256,9 @@ static int pirq_enable_irq(struct pci_dev *dev) return 0; } -bool mp_should_keep_irq(struct device *dev) -{ - if (dev->power.is_prepared) - return true; -#ifdef CONFIG_PM - if (dev->power.runtime_status == RPM_SUSPENDING) - return true; -#endif - - return false; -} - static void pirq_disable_irq(struct pci_dev *dev) { - if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) && - dev->irq_managed && dev->irq) { + if (io_apic_assign_pci_irqs && dev->irq_managed && dev->irq) { mp_unmap_irq(dev->irq); dev->irq = 0; dev->irq_managed = 0; diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 326198a4434e..dd30b7e08bc2 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c @@ -397,12 +397,12 @@ static acpi_status check_mcfg_resource(struct acpi_resource *res, void *data) status = acpi_resource_to_address64(res, &address); if (ACPI_FAILURE(status) || - (address.address_length <= 0) || + (address.address.address_length <= 0) || (address.resource_type != ACPI_MEMORY_RANGE)) return AE_OK; - if ((mcfg_res->start >= address.minimum) && - (mcfg_res->end < (address.minimum + address.address_length))) { + if ((mcfg_res->start >= address.address.minimum) && + (mcfg_res->end < (address.address.minimum + address.address.address_length))) { mcfg_res->flags = 1; return AE_CTRL_TERMINATE; } @@ -610,6 +610,32 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header) return 0; } +#ifdef CONFIG_ACPI_APEI +extern int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size, + void *data), void *data); + +static int pci_mmcfg_for_each_region(int (*func)(__u64 start, __u64 size, + void *data), void *data) +{ + struct pci_mmcfg_region *cfg; + int rc; + + if (list_empty(&pci_mmcfg_list)) + return 0; + + list_for_each_entry(cfg, &pci_mmcfg_list, list) { + rc = func(cfg->res.start, resource_size(&cfg->res), data); + if (rc) + return rc; + } + + return 0; +} +#define set_apei_filter() (arch_apei_filter_addr = pci_mmcfg_for_each_region) +#else +#define set_apei_filter() +#endif + static void __init __pci_mmcfg_init(int early) { pci_mmcfg_reject_broken(early); @@ -644,6 +670,8 @@ void __init pci_mmcfg_early_init(void) else acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg); __pci_mmcfg_init(1); + + set_apei_filter(); } } diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index c489ef2c1a39..d22f4b5bbc04 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -298,12 +298,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) map_irq.entry_nr = nvec; } else if (type == PCI_CAP_ID_MSIX) { int pos; + unsigned long flags; u32 table_offset, bir; pos = dev->msix_cap; pci_read_config_dword(dev, pos + PCI_MSIX_TABLE, &table_offset); bir = (u8)(table_offset & PCI_MSIX_TABLE_BIR); + flags = pci_resource_flags(dev, bir); + if (!flags || (flags & IORESOURCE_UNSET)) + return -EINVAL; map_irq.table_base = pci_resource_start(dev, bir); map_irq.entry_nr = msidesc->msi_attrib.entry_nr; @@ -458,6 +462,7 @@ int __init pci_xen_hvm_init(void) * just how GSIs get registered. */ __acpi_register_gsi = acpi_register_gsi_xen_hvm; + __acpi_unregister_gsi = NULL; #endif #ifdef CONFIG_PCI_MSI @@ -471,52 +476,6 @@ int __init pci_xen_hvm_init(void) } #ifdef CONFIG_XEN_DOM0 -static __init void xen_setup_acpi_sci(void) -{ - int rc; - int trigger, polarity; - int gsi = acpi_sci_override_gsi; - int irq = -1; - int gsi_override = -1; - - if (!gsi) - return; - - rc = acpi_get_override_irq(gsi, &trigger, &polarity); - if (rc) { - printk(KERN_WARNING "xen: acpi_get_override_irq failed for acpi" - " sci, rc=%d\n", rc); - return; - } - trigger = trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; - polarity = polarity ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; - - printk(KERN_INFO "xen: sci override: global_irq=%d trigger=%d " - "polarity=%d\n", gsi, trigger, polarity); - - /* Before we bind the GSI to a Linux IRQ, check whether - * we need to override it with bus_irq (IRQ) value. Usually for - * IRQs below IRQ_LEGACY_IRQ this holds IRQ == GSI, as so: - * ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 low level) - * but there are oddballs where the IRQ != GSI: - * ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 20 low level) - * which ends up being: gsi_to_irq[9] == 20 - * (which is what acpi_gsi_to_irq ends up calling when starting the - * the ACPI interpreter and keels over since IRQ 9 has not been - * setup as we had setup IRQ 20 for it). - */ - if (acpi_gsi_to_irq(gsi, &irq) == 0) { - /* Use the provided value if it's valid. */ - if (irq >= 0) - gsi_override = irq; - } - - gsi = xen_register_gsi(gsi, gsi_override, trigger, polarity); - printk(KERN_INFO "xen: acpi sci %d\n", gsi); - - return; -} - int __init pci_xen_initial_domain(void) { int irq; @@ -527,8 +486,8 @@ int __init pci_xen_initial_domain(void) x86_msi.restore_msi_irqs = xen_initdom_restore_msi_irqs; pci_msi_ignore_mask = 1; #endif - xen_setup_acpi_sci(); __acpi_register_gsi = acpi_register_gsi_xen; + __acpi_unregister_gsi = NULL; /* Pre-allocate legacy irqs */ for (irq = 0; irq < nr_legacy_irqs(); irq++) { int trigger, polarity; diff --git a/arch/x86/tools/calc_run_size.pl b/arch/x86/tools/calc_run_size.pl deleted file mode 100644 index 23210baade2d..000000000000 --- a/arch/x86/tools/calc_run_size.pl +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/perl -# -# Calculate the amount of space needed to run the kernel, including room for -# the .bss and .brk sections. -# -# Usage: -# objdump -h a.out | perl calc_run_size.pl -use strict; - -my $mem_size = 0; -my $file_offset = 0; - -my $sections=" *[0-9]+ \.(?:bss|brk) +"; -while (<>) { - if (/^$sections([0-9a-f]+) +(?:[0-9a-f]+ +){2}([0-9a-f]+)/) { - my $size = hex($1); - my $offset = hex($2); - $mem_size += $size; - if ($file_offset == 0) { - $file_offset = $offset; - } elsif ($file_offset != $offset) { - # BFD linker shows the same file offset in ELF. - # Gold linker shows them as consecutive. - next if ($file_offset + $mem_size == $offset + $size); - - printf STDERR "file_offset: 0x%lx\n", $file_offset; - printf STDERR "mem_size: 0x%lx\n", $mem_size; - printf STDERR "offset: 0x%lx\n", $offset; - printf STDERR "size: 0x%lx\n", $size; - - die ".bss and .brk are non-contiguous\n"; - } - } -} - -if ($file_offset == 0) { - die "Never found .bss or .brk file offset\n"; -} -printf("%d\n", $mem_size + $file_offset); diff --git a/arch/x86/tools/calc_run_size.sh b/arch/x86/tools/calc_run_size.sh new file mode 100644 index 000000000000..1a4c17bb3910 --- /dev/null +++ b/arch/x86/tools/calc_run_size.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# +# Calculate the amount of space needed to run the kernel, including room for +# the .bss and .brk sections. +# +# Usage: +# objdump -h a.out | sh calc_run_size.sh + +NUM='\([0-9a-fA-F]*[ \t]*\)' +OUT=$(sed -n 's/^[ \t0-9]*.b[sr][sk][ \t]*'"$NUM$NUM$NUM$NUM"'.*/\1\4/p') +if [ -z "$OUT" ] ; then + echo "Never found .bss or .brk file offset" >&2 + exit 1 +fi + +OUT=$(echo ${OUT# }) +sizeA=$(printf "%d" 0x${OUT%% *}) +OUT=${OUT#* } +offsetA=$(printf "%d" 0x${OUT%% *}) +OUT=${OUT#* } +sizeB=$(printf "%d" 0x${OUT%% *}) +OUT=${OUT#* } +offsetB=$(printf "%d" 0x${OUT%% *}) + +run_size=$(( $offsetA + $sizeA + $sizeB )) + +# BFD linker shows the same file offset in ELF. +if [ "$offsetA" -ne "$offsetB" ] ; then + # Gold linker shows them as consecutive. + endB=$(( $offsetB + $sizeB )) + if [ "$endB" != "$run_size" ] ; then + printf "sizeA: 0x%x\n" $sizeA >&2 + printf "offsetA: 0x%x\n" $offsetA >&2 + printf "sizeB: 0x%x\n" $sizeB >&2 + printf "offsetB: 0x%x\n" $offsetB >&2 + echo ".bss and .brk are non-contiguous" >&2 + exit 1 + fi +fi + +printf "%d\n" $run_size +exit 0 diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile index 5a4affe025e8..09297c8e1fcd 100644 --- a/arch/x86/vdso/Makefile +++ b/arch/x86/vdso/Makefile @@ -205,4 +205,4 @@ $(vdso_img_insttargets): install_%: $(obj)/%.dbg $(MODLIB)/vdso FORCE PHONY += vdso_install $(vdso_img_insttargets) vdso_install: $(vdso_img_insttargets) FORCE -clean-files := vdso32-syscall* vdso32-sysenter* vdso32-int80* +clean-files := vdso32-syscall* vdso32-sysenter* vdso32-int80* vdso64* diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 5c1f9ace7ae7..adca9e2b6553 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1489,7 +1489,7 @@ static void __init xen_set_pte_init(pte_t *ptep, pte_t pte) native_set_pte(ptep, pte); } -static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn) +static void __init pin_pagetable_pfn(unsigned cmd, unsigned long pfn) { struct mmuext_op op; op.cmd = cmd; @@ -1657,7 +1657,7 @@ void __init xen_reserve_top(void) * Like __va(), but returns address in the kernel mapping (which is * all we have until the physical memory mapping has been set up. */ -static void *__ka(phys_addr_t paddr) +static void * __init __ka(phys_addr_t paddr) { #ifdef CONFIG_X86_64 return (void *)(paddr + __START_KERNEL_map); @@ -1667,7 +1667,7 @@ static void *__ka(phys_addr_t paddr) } /* Convert a machine address to physical address */ -static unsigned long m2p(phys_addr_t maddr) +static unsigned long __init m2p(phys_addr_t maddr) { phys_addr_t paddr; @@ -1678,13 +1678,14 @@ static unsigned long m2p(phys_addr_t maddr) } /* Convert a machine address to kernel virtual */ -static void *m2v(phys_addr_t maddr) +static void * __init m2v(phys_addr_t maddr) { return __ka(m2p(maddr)); } /* Set the page permissions on an identity-mapped pages */ -static void set_page_prot_flags(void *addr, pgprot_t prot, unsigned long flags) +static void __init set_page_prot_flags(void *addr, pgprot_t prot, + unsigned long flags) { unsigned long pfn = __pa(addr) >> PAGE_SHIFT; pte_t pte = pfn_pte(pfn, prot); @@ -1696,7 +1697,7 @@ static void set_page_prot_flags(void *addr, pgprot_t prot, unsigned long flags) if (HYPERVISOR_update_va_mapping((unsigned long)addr, pte, flags)) BUG(); } -static void set_page_prot(void *addr, pgprot_t prot) +static void __init set_page_prot(void *addr, pgprot_t prot) { return set_page_prot_flags(addr, prot, UVMF_NONE); } @@ -1733,10 +1734,8 @@ static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) for (pteidx = 0; pteidx < PTRS_PER_PTE; pteidx++, pfn++) { pte_t pte; -#ifdef CONFIG_X86_32 if (pfn > max_pfn_mapped) max_pfn_mapped = pfn; -#endif if (!pte_none(pte_page[pteidx])) continue; @@ -1769,7 +1768,7 @@ void __init xen_setup_machphys_mapping(void) } #ifdef CONFIG_X86_64 -static void convert_pfn_mfn(void *v) +static void __init convert_pfn_mfn(void *v) { pte_t *pte = v; int i; diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 70fb5075c901..f18fd1d411f6 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -84,8 +84,6 @@ #define PMDS_PER_MID_PAGE (P2M_MID_PER_PAGE / PTRS_PER_PTE) -static void __init m2p_override_init(void); - unsigned long *xen_p2m_addr __read_mostly; EXPORT_SYMBOL_GPL(xen_p2m_addr); unsigned long xen_p2m_size __read_mostly; @@ -402,8 +400,6 @@ void __init xen_vmalloc_p2m_tree(void) xen_p2m_size = xen_max_p2m_pfn; xen_inv_extra_mem(); - - m2p_override_init(); } unsigned long get_phys_to_machine(unsigned long pfn) @@ -652,100 +648,21 @@ bool set_phys_to_machine(unsigned long pfn, unsigned long mfn) return true; } -#define M2P_OVERRIDE_HASH_SHIFT 10 -#define M2P_OVERRIDE_HASH (1 << M2P_OVERRIDE_HASH_SHIFT) - -static struct list_head *m2p_overrides; -static DEFINE_SPINLOCK(m2p_override_lock); - -static void __init m2p_override_init(void) -{ - unsigned i; - - m2p_overrides = alloc_bootmem_align( - sizeof(*m2p_overrides) * M2P_OVERRIDE_HASH, - sizeof(unsigned long)); - - for (i = 0; i < M2P_OVERRIDE_HASH; i++) - INIT_LIST_HEAD(&m2p_overrides[i]); -} - -static unsigned long mfn_hash(unsigned long mfn) -{ - return hash_long(mfn, M2P_OVERRIDE_HASH_SHIFT); -} - -/* Add an MFN override for a particular page */ -static int m2p_add_override(unsigned long mfn, struct page *page, - struct gnttab_map_grant_ref *kmap_op) -{ - unsigned long flags; - unsigned long pfn; - unsigned long uninitialized_var(address); - unsigned level; - pte_t *ptep = NULL; - - pfn = page_to_pfn(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; - } - - if (kmap_op != NULL) { - if (!PageHighMem(page)) { - struct multicall_space mcs = - xen_mc_entry(sizeof(*kmap_op)); - - MULTI_grant_table_op(mcs.mc, - GNTTABOP_map_grant_ref, kmap_op, 1); - - xen_mc_issue(PARAVIRT_LAZY_MMU); - } - } - spin_lock_irqsave(&m2p_override_lock, flags); - list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]); - spin_unlock_irqrestore(&m2p_override_lock, flags); - - /* p2m(m2p(mfn)) == mfn: the mfn is already present somewhere in - * this domain. Set the FOREIGN_FRAME_BIT in the p2m for the other - * pfn so that the following mfn_to_pfn(mfn) calls will return the - * pfn from the m2p_override (the backend pfn) instead. - * We need to do this because the pages shared by the frontend - * (xen-blkfront) can be already locked (lock_page, called by - * do_read_cache_page); when the userspace backend tries to use them - * with direct_IO, mfn_to_pfn returns the pfn of the frontend, so - * do_blockdev_direct_IO is going to try to lock the same pages - * again resulting in a deadlock. - * As a side effect get_user_pages_fast might not be safe on the - * frontend pages while they are being shared with the backend, - * because mfn_to_pfn (that ends up being called by GUPF) will - * return the backend pfn rather than the frontend pfn. */ - pfn = mfn_to_pfn_no_overrides(mfn); - if (__pfn_to_mfn(pfn) == mfn) - set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)); - - return 0; -} - int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, struct gnttab_map_grant_ref *kmap_ops, struct page **pages, unsigned int count) { int i, ret = 0; - bool lazy = false; pte_t *pte; if (xen_feature(XENFEAT_auto_translated_physmap)) return 0; - if (kmap_ops && - !in_interrupt() && - paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) { - arch_enter_lazy_mmu_mode(); - lazy = true; + if (kmap_ops) { + ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, + kmap_ops, count); + if (ret) + goto out; } for (i = 0; i < count; i++) { @@ -764,170 +681,28 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, } pfn = page_to_pfn(pages[i]); - WARN_ON(PagePrivate(pages[i])); - SetPagePrivate(pages[i]); - set_page_private(pages[i], mfn); - pages[i]->index = pfn_to_mfn(pfn); + WARN(pfn_to_mfn(pfn) != INVALID_P2M_ENTRY, "page must be ballooned"); if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) { ret = -ENOMEM; goto out; } - - if (kmap_ops) { - ret = m2p_add_override(mfn, pages[i], &kmap_ops[i]); - if (ret) - goto out; - } } out: - if (lazy) - arch_leave_lazy_mmu_mode(); - return ret; } EXPORT_SYMBOL_GPL(set_foreign_p2m_mapping); -static struct page *m2p_find_override(unsigned long mfn) -{ - unsigned long flags; - struct list_head *bucket; - struct page *p, *ret; - - if (unlikely(!m2p_overrides)) - return NULL; - - ret = NULL; - bucket = &m2p_overrides[mfn_hash(mfn)]; - - spin_lock_irqsave(&m2p_override_lock, flags); - - list_for_each_entry(p, bucket, lru) { - if (page_private(p) == mfn) { - ret = p; - break; - } - } - - spin_unlock_irqrestore(&m2p_override_lock, flags); - - return ret; -} - -static int m2p_remove_override(struct page *page, - struct gnttab_map_grant_ref *kmap_op, - unsigned long mfn) -{ - unsigned long flags; - unsigned long pfn; - unsigned long uninitialized_var(address); - unsigned level; - pte_t *ptep = NULL; - - pfn = page_to_pfn(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_remove_override: pfn %lx not mapped", pfn)) - return -EINVAL; - } - - spin_lock_irqsave(&m2p_override_lock, flags); - list_del(&page->lru); - spin_unlock_irqrestore(&m2p_override_lock, flags); - - if (kmap_op != NULL) { - if (!PageHighMem(page)) { - struct multicall_space mcs; - struct gnttab_unmap_and_replace *unmap_op; - struct page *scratch_page = get_balloon_scratch_page(); - unsigned long scratch_page_address = (unsigned long) - __va(page_to_pfn(scratch_page) << PAGE_SHIFT); - - /* - * It might be that we queued all the m2p grant table - * hypercalls in a multicall, then m2p_remove_override - * get called before the multicall has actually been - * issued. In this case handle is going to -1 because - * it hasn't been modified yet. - */ - if (kmap_op->handle == -1) - xen_mc_flush(); - /* - * Now if kmap_op->handle is negative it means that the - * hypercall actually returned an error. - */ - if (kmap_op->handle == GNTST_general_error) { - pr_warn("m2p_remove_override: pfn %lx mfn %lx, failed to modify kernel mappings", - pfn, mfn); - put_balloon_scratch_page(); - return -1; - } - - xen_mc_batch(); - - mcs = __xen_mc_entry( - sizeof(struct gnttab_unmap_and_replace)); - unmap_op = mcs.args; - unmap_op->host_addr = kmap_op->host_addr; - unmap_op->new_addr = scratch_page_address; - unmap_op->handle = kmap_op->handle; - - MULTI_grant_table_op(mcs.mc, - GNTTABOP_unmap_and_replace, unmap_op, 1); - - mcs = __xen_mc_entry(0); - MULTI_update_va_mapping(mcs.mc, scratch_page_address, - pfn_pte(page_to_pfn(scratch_page), - PAGE_KERNEL_RO), 0); - - xen_mc_issue(PARAVIRT_LAZY_MMU); - - kmap_op->host_addr = 0; - put_balloon_scratch_page(); - } - } - - /* p2m(m2p(mfn)) == FOREIGN_FRAME(mfn): the mfn is already present - * somewhere in this domain, even before being added to the - * m2p_override (see comment above in m2p_add_override). - * If there are no other entries in the m2p_override corresponding - * to this mfn, then remove the FOREIGN_FRAME_BIT from the p2m for - * the original pfn (the one shared by the frontend): the backend - * cannot do any IO on this page anymore because it has been - * unshared. Removing the FOREIGN_FRAME_BIT from the p2m entry of - * the original pfn causes mfn_to_pfn(mfn) to return the frontend - * pfn again. */ - mfn &= ~FOREIGN_FRAME_BIT; - pfn = mfn_to_pfn_no_overrides(mfn); - if (__pfn_to_mfn(pfn) == FOREIGN_FRAME(mfn) && - m2p_find_override(mfn) == NULL) - set_phys_to_machine(pfn, mfn); - - return 0; -} - int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, - struct gnttab_map_grant_ref *kmap_ops, + struct gnttab_unmap_grant_ref *kunmap_ops, struct page **pages, unsigned int count) { int i, ret = 0; - bool lazy = false; if (xen_feature(XENFEAT_auto_translated_physmap)) return 0; - if (kmap_ops && - !in_interrupt() && - paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) { - arch_enter_lazy_mmu_mode(); - lazy = true; - } - for (i = 0; i < count; i++) { unsigned long mfn = __pfn_to_mfn(page_to_pfn(pages[i])); unsigned long pfn = page_to_pfn(pages[i]); @@ -937,36 +712,16 @@ int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, goto out; } - set_page_private(pages[i], INVALID_P2M_ENTRY); - WARN_ON(!PagePrivate(pages[i])); - ClearPagePrivate(pages[i]); - set_phys_to_machine(pfn, pages[i]->index); - - if (kmap_ops) - ret = m2p_remove_override(pages[i], &kmap_ops[i], mfn); - if (ret) - goto out; + set_phys_to_machine(pfn, INVALID_P2M_ENTRY); } - + if (kunmap_ops) + ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, + kunmap_ops, count); out: - if (lazy) - arch_leave_lazy_mmu_mode(); return ret; } EXPORT_SYMBOL_GPL(clear_foreign_p2m_mapping); -unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn) -{ - struct page *p = m2p_find_override(mfn); - unsigned long ret = pfn; - - if (p) - ret = page_to_pfn(p); - - return ret; -} -EXPORT_SYMBOL_GPL(m2p_find_override_pfn); - #ifdef CONFIG_XEN_DEBUG_FS #include #include "debugfs.h" diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 865e56cea7a0..55f388ef481a 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -32,16 +32,6 @@ #include "p2m.h" #include "mmu.h" -/* These are code, but not functions. Defined in entry.S */ -extern const char xen_hypervisor_callback[]; -extern const char xen_failsafe_callback[]; -#ifdef CONFIG_X86_64 -extern asmlinkage void nmi(void); -#endif -extern void xen_sysenter_target(void); -extern void xen_syscall_target(void); -extern void xen_syscall32_target(void); - /* Amount of extra memory space we add to the e820 ranges */ struct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS] __initdata; @@ -74,7 +64,7 @@ static unsigned long xen_remap_mfn __initdata = INVALID_P2M_ENTRY; */ #define EXTRA_MEM_RATIO (10) -static void __init xen_add_extra_mem(u64 start, u64 size) +static void __init xen_add_extra_mem(phys_addr_t start, phys_addr_t size) { int i; @@ -97,10 +87,10 @@ static void __init xen_add_extra_mem(u64 start, u64 size) memblock_reserve(start, size); } -static void __init xen_del_extra_mem(u64 start, u64 size) +static void __init xen_del_extra_mem(phys_addr_t start, phys_addr_t size) { int i; - u64 start_r, size_r; + phys_addr_t start_r, size_r; for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) { start_r = xen_extra_mem[i].start; @@ -267,7 +257,7 @@ static void __init xen_set_identity_and_release_chunk(unsigned long start_pfn, static void __init xen_update_mem_tables(unsigned long pfn, unsigned long mfn) { struct mmu_update update = { - .ptr = ((unsigned long long)mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, + .ptr = ((uint64_t)mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, .val = pfn }; @@ -545,20 +535,21 @@ static unsigned long __init xen_get_max_pages(void) return min(max_pages, MAX_DOMAIN_PAGES); } -static void xen_align_and_add_e820_region(u64 start, u64 size, int type) +static void __init xen_align_and_add_e820_region(phys_addr_t start, + phys_addr_t size, int type) { - u64 end = start + size; + phys_addr_t end = start + size; /* Align RAM regions to page boundaries. */ if (type == E820_RAM) { start = PAGE_ALIGN(start); - end &= ~((u64)PAGE_SIZE - 1); + end &= ~((phys_addr_t)PAGE_SIZE - 1); } e820_add_region(start, end - start, type); } -void xen_ignore_unusable(struct e820entry *list, size_t map_size) +static void __init xen_ignore_unusable(struct e820entry *list, size_t map_size) { struct e820entry *entry; unsigned int i; @@ -577,7 +568,7 @@ char * __init xen_memory_setup(void) static struct e820entry map[E820MAX] __initdata; unsigned long max_pfn = xen_start_info->nr_pages; - unsigned long long mem_end; + phys_addr_t mem_end; int rc; struct xen_memory_map memmap; unsigned long max_pages; @@ -652,16 +643,16 @@ char * __init xen_memory_setup(void) extra_pages); i = 0; while (i < memmap.nr_entries) { - u64 addr = map[i].addr; - u64 size = map[i].size; + phys_addr_t addr = map[i].addr; + phys_addr_t size = map[i].size; u32 type = map[i].type; if (type == E820_RAM) { if (addr < mem_end) { size = min(size, mem_end - addr); } else if (extra_pages) { - size = min(size, (u64)extra_pages * PAGE_SIZE); - extra_pages -= size / PAGE_SIZE; + size = min(size, PFN_PHYS(extra_pages)); + extra_pages -= PFN_DOWN(size); xen_add_extra_mem(addr, size); xen_max_p2m_pfn = PFN_DOWN(addr + size); } else diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 4c071aeb8417..08e8489c47f1 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -507,7 +507,7 @@ static int xen_cpu_disable(void) static void xen_cpu_die(unsigned int cpu) { while (xen_pv_domain() && HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) { - current->state = TASK_UNINTERRUPTIBLE; + __set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); } diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 69087341d9ae..55da33b1d51c 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -479,6 +479,10 @@ static void __init xen_time_init(void) int cpu = smp_processor_id(); struct timespec tp; + /* As Dom0 is never moved, no penalty on using TSC there */ + if (xen_initial_domain()) + xen_clocksource.rating = 275; + clocksource_register_hz(&xen_clocksource, NSEC_PER_SEC); if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) { diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index 5686bd9d58cc..9e195c683549 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h @@ -10,6 +10,12 @@ extern const char xen_hypervisor_callback[]; extern const char xen_failsafe_callback[]; +void xen_sysenter_target(void); +#ifdef CONFIG_X86_64 +void xen_syscall_target(void); +void xen_syscall32_target(void); +#endif + extern void *xen_initial_gdt; struct trap_info; diff --git a/arch/xtensa/include/asm/pgtable.h b/arch/xtensa/include/asm/pgtable.h index 872bf0194e6d..a5e929a10c20 100644 --- a/arch/xtensa/include/asm/pgtable.h +++ b/arch/xtensa/include/asm/pgtable.h @@ -57,7 +57,7 @@ #define PTRS_PER_PGD 1024 #define PGD_ORDER 0 #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0UL #define FIRST_USER_PGD_NR (FIRST_USER_ADDRESS >> PGDIR_SHIFT) /* @@ -89,8 +89,6 @@ * (PAGE_NONE)| PPN | 0 | 00 | ADW | 01 | 11 | 11 | * +-----------------------------------------+ * swap | index | type | 01 | 11 | 00 | - * +- - - - - - - - - - - - - - - - - - - - -+ - * file | file offset | 01 | 11 | 10 | * +-----------------------------------------+ * * For T1050 hardware and earlier the layout differs for present and (PAGE_NONE) @@ -111,7 +109,6 @@ * index swap offset / PAGE_SIZE (bit 11-31: 21 bits -> 8 GB) * (note that the index is always non-zero) * type swap type (5 bits -> 32 types) - * file offset 26-bit offset into the file, in increments of PAGE_SIZE * * Notes: * - (PROT_NONE) is a special case of 'present' but causes an exception for @@ -144,7 +141,6 @@ #define _PAGE_HW_VALID 0x00 #define _PAGE_NONE 0x0f #endif -#define _PAGE_FILE (1<<1) /* file mapped page, only if !present */ #define _PAGE_USER (1<<4) /* user access (ring=1) */ @@ -260,7 +256,6 @@ static inline void pgtable_cache_init(void) { } static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITABLE; } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } -static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } static inline int pte_special(pte_t pte) { return 0; } static inline pte_t pte_wrprotect(pte_t pte) @@ -390,11 +385,6 @@ ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -#define PTE_FILE_MAX_BITS 26 -#define pte_to_pgoff(pte) (pte_val(pte) >> 6) -#define pgoff_to_pte(off) \ - ((pte_t) { ((off) << 6) | _PAGE_CA_INVALID | _PAGE_FILE | _PAGE_USER }) - #endif /* !defined (__ASSEMBLY__) */ diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c index b57c4f91f487..9e3571a6535c 100644 --- a/arch/xtensa/mm/fault.c +++ b/arch/xtensa/mm/fault.c @@ -117,6 +117,8 @@ good_area: if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; + else if (fault & VM_FAULT_SIGSEGV) + goto bad_area; else if (fault & VM_FAULT_SIGBUS) goto do_sigbus; BUG(); diff --git a/block/blk-core.c b/block/blk-core.c index 3ad405571dcc..928aac29bccd 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -607,7 +607,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) q->backing_dev_info.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; q->backing_dev_info.state = 0; - q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY; + q->backing_dev_info.capabilities = 0; q->backing_dev_info.name = "block"; q->node = node_id; diff --git a/block/blk-mq.c b/block/blk-mq.c index 2f95747c287e..2390c5541e71 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1641,10 +1641,8 @@ static void blk_mq_free_hw_queues(struct request_queue *q, struct blk_mq_hw_ctx *hctx; unsigned int i; - queue_for_each_hw_ctx(q, hctx, i) { + queue_for_each_hw_ctx(q, hctx, i) free_cpumask_var(hctx->cpumask); - kfree(hctx); - } } static int blk_mq_init_hctx(struct request_queue *q, @@ -1869,6 +1867,27 @@ static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set, mutex_unlock(&set->tag_list_lock); } +/* + * It is the actual release handler for mq, but we do it from + * request queue's release handler for avoiding use-after-free + * and headache because q->mq_kobj shouldn't have been introduced, + * but we can't group ctx/kctx kobj without it. + */ +void blk_mq_release(struct request_queue *q) +{ + struct blk_mq_hw_ctx *hctx; + unsigned int i; + + /* hctx kobj stays in hctx */ + queue_for_each_hw_ctx(q, hctx, i) + kfree(hctx); + + kfree(q->queue_hw_ctx); + + /* ctx kobj stays in queue_ctx */ + free_percpu(q->queue_ctx); +} + struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) { struct blk_mq_hw_ctx **hctxs; @@ -2002,12 +2021,8 @@ void blk_mq_free_queue(struct request_queue *q) percpu_ref_exit(&q->mq_usage_counter); - free_percpu(q->queue_ctx); - kfree(q->queue_hw_ctx); kfree(q->mq_map); - q->queue_ctx = NULL; - q->queue_hw_ctx = NULL; q->mq_map = NULL; mutex_lock(&all_q_mutex); diff --git a/block/blk-mq.h b/block/blk-mq.h index 4f4f943c22c3..6a48c4c0d8a2 100644 --- a/block/blk-mq.h +++ b/block/blk-mq.h @@ -62,6 +62,8 @@ extern void blk_mq_sysfs_unregister(struct request_queue *q); extern void blk_mq_rq_timed_out(struct request *req, bool reserved); +void blk_mq_release(struct request_queue *q); + /* * Basic implementation of sparser bitmap, allowing the user to spread * the bits over more cachelines. diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 935ea2aa0730..faaf36ade7eb 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -517,6 +517,8 @@ static void blk_release_queue(struct kobject *kobj) if (!q->mq_ops) blk_free_flush_queue(q->fq); + else + blk_mq_release(q); blk_trace_shutdown(q); diff --git a/block/partitions/efi.c b/block/partitions/efi.c index 56d08fd75b1a..26cb624ace05 100644 --- a/block/partitions/efi.c +++ b/block/partitions/efi.c @@ -715,7 +715,7 @@ int efi_partition(struct parsed_partitions *state) state->parts[i + 1].flags = ADDPART_FLAG_RAID; info = &state->parts[i + 1].info; - efi_guid_unparse(&ptes[i].unique_partition_guid, info->uuid); + efi_guid_to_str(&ptes[i].unique_partition_guid, info->uuid); /* Naively convert UTF16-LE to 7 bits. */ label_max = min(ARRAY_SIZE(info->volname) - 1, diff --git a/crypto/aes_generic.c b/crypto/aes_generic.c index 9b3c54c1cbe8..3dd101144a58 100644 --- a/crypto/aes_generic.c +++ b/crypto/aes_generic.c @@ -1475,3 +1475,4 @@ module_exit(aes_fini); MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS_CRYPTO("aes"); +MODULE_ALIAS_CRYPTO("aes-generic"); diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 4665b79c729a..3e80d8b8be45 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -338,49 +338,31 @@ static const struct net_proto_family alg_family = { .owner = THIS_MODULE, }; -int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len, - int write) +int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len) { - unsigned long from = (unsigned long)addr; - unsigned long npages; - unsigned off; - int err; - int i; + size_t off; + ssize_t n; + int npages, i; - err = -EFAULT; - if (!access_ok(write ? VERIFY_READ : VERIFY_WRITE, addr, len)) - goto out; + n = iov_iter_get_pages(iter, sgl->pages, len, ALG_MAX_PAGES, &off); + if (n < 0) + return n; - off = from & ~PAGE_MASK; - npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (npages > ALG_MAX_PAGES) - npages = ALG_MAX_PAGES; - - err = get_user_pages_fast(from, npages, write, sgl->pages); - if (err < 0) - goto out; - - npages = err; - err = -EINVAL; + npages = (off + n + PAGE_SIZE - 1) >> PAGE_SHIFT; if (WARN_ON(npages == 0)) - goto out; - - err = 0; + return -EINVAL; sg_init_table(sgl->sg, npages); - for (i = 0; i < npages; i++) { + for (i = 0, len = n; i < npages; i++) { int plen = min_t(int, len, PAGE_SIZE - off); sg_set_page(sgl->sg + i, sgl->pages[i], plen, off); off = 0; len -= plen; - err += plen; } - -out: - return err; + return n; } EXPORT_SYMBOL_GPL(af_alg_make_sg); diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index 01f56eb7816e..01da360bdb55 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -41,8 +41,6 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock, struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); struct hash_ctx *ctx = ask->private; - unsigned long iovlen; - const struct iovec *iov; long copied = 0; int err; @@ -58,37 +56,28 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock, ctx->more = 0; - for (iov = msg->msg_iter.iov, iovlen = msg->msg_iter.nr_segs; iovlen > 0; - iovlen--, iov++) { - unsigned long seglen = iov->iov_len; - char __user *from = iov->iov_base; + while (iov_iter_count(&msg->msg_iter)) { + int len = iov_iter_count(&msg->msg_iter); - while (seglen) { - int len = min_t(unsigned long, seglen, limit); - int newlen; + if (len > limit) + len = limit; - newlen = af_alg_make_sg(&ctx->sgl, from, len, 0); - if (newlen < 0) { - err = copied ? 0 : newlen; - goto unlock; - } - - ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, NULL, - newlen); - - err = af_alg_wait_for_completion( - crypto_ahash_update(&ctx->req), - &ctx->completion); - - af_alg_free_sg(&ctx->sgl); - - if (err) - goto unlock; - - seglen -= newlen; - from += newlen; - copied += newlen; + len = af_alg_make_sg(&ctx->sgl, &msg->msg_iter, len); + if (len < 0) { + err = copied ? 0 : len; + goto unlock; } + + ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, NULL, len); + + err = af_alg_wait_for_completion(crypto_ahash_update(&ctx->req), + &ctx->completion); + af_alg_free_sg(&ctx->sgl); + if (err) + goto unlock; + + copied += len; + iov_iter_advance(&msg->msg_iter, len); } err = 0; diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index c12207c8dde9..6fc12c3fc4b9 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -426,67 +426,58 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock, &ctx->req)); struct skcipher_sg_list *sgl; struct scatterlist *sg; - unsigned long iovlen; - const struct iovec *iov; int err = -EAGAIN; int used; long copied = 0; lock_sock(sk); - for (iov = msg->msg_iter.iov, iovlen = msg->msg_iter.nr_segs; iovlen > 0; - iovlen--, iov++) { - unsigned long seglen = iov->iov_len; - char __user *from = iov->iov_base; + while (iov_iter_count(&msg->msg_iter)) { + sgl = list_first_entry(&ctx->tsgl, + struct skcipher_sg_list, list); + sg = sgl->sg; - while (seglen) { - sgl = list_first_entry(&ctx->tsgl, - struct skcipher_sg_list, list); - sg = sgl->sg; + while (!sg->length) + sg++; - while (!sg->length) - sg++; - - if (!ctx->used) { - err = skcipher_wait_for_data(sk, flags); - if (err) - goto unlock; - } - - used = min_t(unsigned long, ctx->used, seglen); - - used = af_alg_make_sg(&ctx->rsgl, from, used, 1); - err = used; - if (err < 0) + if (!ctx->used) { + err = skcipher_wait_for_data(sk, flags); + if (err) goto unlock; + } - if (ctx->more || used < ctx->used) - used -= used % bs; + used = min_t(unsigned long, ctx->used, iov_iter_count(&msg->msg_iter)); - err = -EINVAL; - if (!used) - goto free; + used = af_alg_make_sg(&ctx->rsgl, &msg->msg_iter, used); + err = used; + if (err < 0) + goto unlock; - ablkcipher_request_set_crypt(&ctx->req, sg, - ctx->rsgl.sg, used, - ctx->iv); + if (ctx->more || used < ctx->used) + used -= used % bs; - err = af_alg_wait_for_completion( + err = -EINVAL; + if (!used) + goto free; + + ablkcipher_request_set_crypt(&ctx->req, sg, + ctx->rsgl.sg, used, + ctx->iv); + + err = af_alg_wait_for_completion( ctx->enc ? crypto_ablkcipher_encrypt(&ctx->req) : crypto_ablkcipher_decrypt(&ctx->req), &ctx->completion); free: - af_alg_free_sg(&ctx->rsgl); + af_alg_free_sg(&ctx->rsgl); - if (err) - goto unlock; + if (err) + goto unlock; - copied += used; - from += used; - seglen -= used; - skcipher_pull_sgl(sk, used); - } + copied += used; + skcipher_pull_sgl(sk, used); + iov_iter_advance(&msg->msg_iter, used); } err = 0; diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index b4485a108389..6f5bebc9bf01 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -477,3 +477,4 @@ MODULE_PARM_DESC(dbg, "Boolean to enable debugging (0/1 == off/on)"); module_init(prng_mod_init); module_exit(prng_mod_fini); MODULE_ALIAS_CRYPTO("stdrng"); +MODULE_ALIAS_CRYPTO("ansi_cprng"); diff --git a/crypto/blowfish_generic.c b/crypto/blowfish_generic.c index 7bd71f02d0dd..87b392a77a93 100644 --- a/crypto/blowfish_generic.c +++ b/crypto/blowfish_generic.c @@ -139,3 +139,4 @@ module_exit(blowfish_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Blowfish Cipher Algorithm"); MODULE_ALIAS_CRYPTO("blowfish"); +MODULE_ALIAS_CRYPTO("blowfish-generic"); diff --git a/crypto/camellia_generic.c b/crypto/camellia_generic.c index 1b74c5a3e891..a02286bf319e 100644 --- a/crypto/camellia_generic.c +++ b/crypto/camellia_generic.c @@ -1099,3 +1099,4 @@ module_exit(camellia_fini); MODULE_DESCRIPTION("Camellia Cipher Algorithm"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CRYPTO("camellia"); +MODULE_ALIAS_CRYPTO("camellia-generic"); diff --git a/crypto/cast5_generic.c b/crypto/cast5_generic.c index 84c86db67ec7..df5c72629383 100644 --- a/crypto/cast5_generic.c +++ b/crypto/cast5_generic.c @@ -550,3 +550,4 @@ module_exit(cast5_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cast5 Cipher Algorithm"); MODULE_ALIAS_CRYPTO("cast5"); +MODULE_ALIAS_CRYPTO("cast5-generic"); diff --git a/crypto/cast6_generic.c b/crypto/cast6_generic.c index f408f0bd8de2..058c8d755d03 100644 --- a/crypto/cast6_generic.c +++ b/crypto/cast6_generic.c @@ -292,3 +292,4 @@ module_exit(cast6_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cast6 Cipher Algorithm"); MODULE_ALIAS_CRYPTO("cast6"); +MODULE_ALIAS_CRYPTO("cast6-generic"); diff --git a/crypto/crc32c_generic.c b/crypto/crc32c_generic.c index 2a062025749d..06f1b60f02b2 100644 --- a/crypto/crc32c_generic.c +++ b/crypto/crc32c_generic.c @@ -171,4 +171,5 @@ MODULE_AUTHOR("Clay Haapala "); MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations wrapper for lib/crc32c"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CRYPTO("crc32c"); +MODULE_ALIAS_CRYPTO("crc32c-generic"); MODULE_SOFTDEP("pre: crc32c"); diff --git a/crypto/crct10dif_generic.c b/crypto/crct10dif_generic.c index 08bb4f504520..c1229614c7e3 100644 --- a/crypto/crct10dif_generic.c +++ b/crypto/crct10dif_generic.c @@ -125,3 +125,4 @@ MODULE_AUTHOR("Tim Chen "); MODULE_DESCRIPTION("T10 DIF CRC calculation."); MODULE_LICENSE("GPL"); MODULE_ALIAS_CRYPTO("crct10dif"); +MODULE_ALIAS_CRYPTO("crct10dif-generic"); diff --git a/crypto/des_generic.c b/crypto/des_generic.c index 42912948776b..a71720544d11 100644 --- a/crypto/des_generic.c +++ b/crypto/des_generic.c @@ -983,8 +983,6 @@ static struct crypto_alg des_algs[2] = { { .cia_decrypt = des3_ede_decrypt } } } }; -MODULE_ALIAS_CRYPTO("des3_ede"); - static int __init des_generic_mod_init(void) { return crypto_register_algs(des_algs, ARRAY_SIZE(des_algs)); @@ -1001,4 +999,7 @@ module_exit(des_generic_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms"); MODULE_AUTHOR("Dag Arne Osvik "); -MODULE_ALIAS("des"); +MODULE_ALIAS_CRYPTO("des"); +MODULE_ALIAS_CRYPTO("des-generic"); +MODULE_ALIAS_CRYPTO("des3_ede"); +MODULE_ALIAS_CRYPTO("des3_ede-generic"); diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c index 4e97fae9666f..bac70995e064 100644 --- a/crypto/ghash-generic.c +++ b/crypto/ghash-generic.c @@ -173,3 +173,4 @@ module_exit(ghash_mod_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("GHASH Message Digest Algorithm"); MODULE_ALIAS_CRYPTO("ghash"); +MODULE_ALIAS_CRYPTO("ghash-generic"); diff --git a/crypto/krng.c b/crypto/krng.c index 67c88b331210..0224841b6579 100644 --- a/crypto/krng.c +++ b/crypto/krng.c @@ -63,3 +63,4 @@ module_exit(krng_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Kernel Random Number Generator"); MODULE_ALIAS_CRYPTO("stdrng"); +MODULE_ALIAS_CRYPTO("krng"); diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c index 3d0f9df30ac9..f550b5d94630 100644 --- a/crypto/salsa20_generic.c +++ b/crypto/salsa20_generic.c @@ -249,3 +249,4 @@ module_exit(salsa20_generic_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION ("Salsa20 stream cipher algorithm"); MODULE_ALIAS_CRYPTO("salsa20"); +MODULE_ALIAS_CRYPTO("salsa20-generic"); diff --git a/crypto/serpent_generic.c b/crypto/serpent_generic.c index a53b5e2af335..94970a794975 100644 --- a/crypto/serpent_generic.c +++ b/crypto/serpent_generic.c @@ -667,3 +667,4 @@ MODULE_DESCRIPTION("Serpent and tnepres (kerneli compatible serpent reversed) Ci MODULE_AUTHOR("Dag Arne Osvik "); MODULE_ALIAS_CRYPTO("tnepres"); MODULE_ALIAS_CRYPTO("serpent"); +MODULE_ALIAS_CRYPTO("serpent-generic"); diff --git a/crypto/sha1_generic.c b/crypto/sha1_generic.c index 039e58cfa155..a3e50c37eb6f 100644 --- a/crypto/sha1_generic.c +++ b/crypto/sha1_generic.c @@ -154,3 +154,4 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm"); MODULE_ALIAS_CRYPTO("sha1"); +MODULE_ALIAS_CRYPTO("sha1-generic"); diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c index 5eb21b120033..b001ff5c2efc 100644 --- a/crypto/sha256_generic.c +++ b/crypto/sha256_generic.c @@ -385,4 +385,6 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm"); MODULE_ALIAS_CRYPTO("sha224"); +MODULE_ALIAS_CRYPTO("sha224-generic"); MODULE_ALIAS_CRYPTO("sha256"); +MODULE_ALIAS_CRYPTO("sha256-generic"); diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c index 8d0b19ed4f4b..1c3c3767e079 100644 --- a/crypto/sha512_generic.c +++ b/crypto/sha512_generic.c @@ -289,4 +289,6 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SHA-512 and SHA-384 Secure Hash Algorithms"); MODULE_ALIAS_CRYPTO("sha384"); +MODULE_ALIAS_CRYPTO("sha384-generic"); MODULE_ALIAS_CRYPTO("sha512"); +MODULE_ALIAS_CRYPTO("sha512-generic"); diff --git a/crypto/tea.c b/crypto/tea.c index 495be2d0077d..b70b441c7d1e 100644 --- a/crypto/tea.c +++ b/crypto/tea.c @@ -270,6 +270,7 @@ static void __exit tea_mod_fini(void) crypto_unregister_algs(tea_algs, ARRAY_SIZE(tea_algs)); } +MODULE_ALIAS_CRYPTO("tea"); MODULE_ALIAS_CRYPTO("xtea"); MODULE_ALIAS_CRYPTO("xeta"); diff --git a/crypto/tgr192.c b/crypto/tgr192.c index 6e5651c66cf8..321bc6ff2a9d 100644 --- a/crypto/tgr192.c +++ b/crypto/tgr192.c @@ -676,6 +676,7 @@ static void __exit tgr192_mod_fini(void) crypto_unregister_shashes(tgr_algs, ARRAY_SIZE(tgr_algs)); } +MODULE_ALIAS_CRYPTO("tgr192"); MODULE_ALIAS_CRYPTO("tgr160"); MODULE_ALIAS_CRYPTO("tgr128"); diff --git a/crypto/twofish_generic.c b/crypto/twofish_generic.c index 523ad8c4e359..ebf7a3efb572 100644 --- a/crypto/twofish_generic.c +++ b/crypto/twofish_generic.c @@ -212,3 +212,4 @@ module_exit(twofish_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION ("Twofish Cipher Algorithm"); MODULE_ALIAS_CRYPTO("twofish"); +MODULE_ALIAS_CRYPTO("twofish-generic"); diff --git a/crypto/wp512.c b/crypto/wp512.c index 0de42eb3d040..7ee5a043a988 100644 --- a/crypto/wp512.c +++ b/crypto/wp512.c @@ -1167,6 +1167,7 @@ static void __exit wp512_mod_fini(void) crypto_unregister_shashes(wp_algs, ARRAY_SIZE(wp_algs)); } +MODULE_ALIAS_CRYPTO("wp512"); MODULE_ALIAS_CRYPTO("wp384"); MODULE_ALIAS_CRYPTO("wp256"); diff --git a/drivers/Kconfig b/drivers/Kconfig index 694d5a70d6ce..c70d6e45dc10 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -134,8 +134,6 @@ source "drivers/staging/Kconfig" source "drivers/platform/Kconfig" -source "drivers/soc/Kconfig" - source "drivers/clk/Kconfig" source "drivers/hwspinlock/Kconfig" diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 8951cefb0a96..e6c3ddd92665 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -315,6 +315,12 @@ config ACPI_HOTPLUG_MEMORY To compile this driver as a module, choose M here: the module will be called acpi_memhotplug. +config ACPI_HOTPLUG_IOAPIC + bool + depends on PCI + depends on X86_IO_APIC + default y + config ACPI_SBS tristate "Smart Battery System" depends on X86 diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index f74317cc1ca9..b18cd2151ddb 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -40,7 +40,7 @@ acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-y += pci_root.o pci_link.o pci_irq.o -acpi-y += acpi_lpss.o +acpi-y += acpi_lpss.o acpi_apd.o acpi-y += acpi_platform.o acpi-y += acpi_pnp.o acpi-y += int340x_thermal.o @@ -70,6 +70,7 @@ obj-$(CONFIG_ACPI_PROCESSOR) += processor.o obj-y += container.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o obj-y += acpi_memhotplug.o +obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_SBS) += sbshc.o obj-$(CONFIG_ACPI_SBS) += sbs.o diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c new file mode 100644 index 000000000000..3984ea96e5f7 --- /dev/null +++ b/drivers/acpi/acpi_apd.c @@ -0,0 +1,150 @@ +/* + * AMD ACPI support for ACPI2platform device. + * + * Copyright (c) 2014,2015 AMD Corporation. + * Authors: Ken Xue + * Wu, Jeff + * + * This 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 "internal.h" + +ACPI_MODULE_NAME("acpi_apd"); +struct apd_private_data; + +/** + * ACPI_APD_SYSFS : add device attributes in sysfs + * ACPI_APD_PM : attach power domain to device + */ +#define ACPI_APD_SYSFS BIT(0) +#define ACPI_APD_PM BIT(1) + +/** + * struct apd_device_desc - a descriptor for apd device + * @flags: device flags like %ACPI_APD_SYSFS, %ACPI_APD_PM + * @fixed_clk_rate: fixed rate input clock source for acpi device; + * 0 means no fixed rate input clock source + * @setup: a hook routine to set device resource during create platform device + * + * Device description defined as acpi_device_id.driver_data + */ +struct apd_device_desc { + unsigned int flags; + unsigned int fixed_clk_rate; + int (*setup)(struct apd_private_data *pdata); +}; + +struct apd_private_data { + struct clk *clk; + struct acpi_device *adev; + const struct apd_device_desc *dev_desc; +}; + +#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE +#define APD_ADDR(desc) ((unsigned long)&desc) + +static int acpi_apd_setup(struct apd_private_data *pdata) +{ + const struct apd_device_desc *dev_desc = pdata->dev_desc; + struct clk *clk = ERR_PTR(-ENODEV); + + if (dev_desc->fixed_clk_rate) { + clk = clk_register_fixed_rate(&pdata->adev->dev, + dev_name(&pdata->adev->dev), + NULL, CLK_IS_ROOT, + dev_desc->fixed_clk_rate); + clk_register_clkdev(clk, NULL, dev_name(&pdata->adev->dev)); + pdata->clk = clk; + } + + return 0; +} + +static struct apd_device_desc cz_i2c_desc = { + .setup = acpi_apd_setup, + .fixed_clk_rate = 133000000, +}; + +static struct apd_device_desc cz_uart_desc = { + .setup = acpi_apd_setup, + .fixed_clk_rate = 48000000, +}; + +#else + +#define APD_ADDR(desc) (0UL) + +#endif /* CONFIG_X86_AMD_PLATFORM_DEVICE */ + +/** +* Create platform device during acpi scan attach handle. +* Return value > 0 on success of creating device. +*/ +static int acpi_apd_create_device(struct acpi_device *adev, + const struct acpi_device_id *id) +{ + const struct apd_device_desc *dev_desc = (void *)id->driver_data; + struct apd_private_data *pdata; + struct platform_device *pdev; + int ret; + + if (!dev_desc) { + pdev = acpi_create_platform_device(adev); + return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1; + } + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->adev = adev; + pdata->dev_desc = dev_desc; + + if (dev_desc->setup) { + ret = dev_desc->setup(pdata); + if (ret) + goto err_out; + } + + adev->driver_data = pdata; + pdev = acpi_create_platform_device(adev); + if (!IS_ERR_OR_NULL(pdev)) + return 1; + + ret = PTR_ERR(pdev); + adev->driver_data = NULL; + + err_out: + kfree(pdata); + return ret; +} + +static const struct acpi_device_id acpi_apd_device_ids[] = { + /* Generic apd devices */ + { "AMD0010", APD_ADDR(cz_i2c_desc) }, + { "AMD0020", APD_ADDR(cz_uart_desc) }, + { "AMD0030", }, + { } +}; + +static struct acpi_scan_handler apd_handler = { + .ids = acpi_apd_device_ids, + .attach = acpi_apd_create_device, +}; + +void __init acpi_apd_init(void) +{ + acpi_scan_add_handler(&apd_handler); +} diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 4f3febf8a589..02e835f3cf8a 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -1,7 +1,7 @@ /* * ACPI support for Intel Lynxpoint LPSS. * - * Copyright (C) 2013, 2014, Intel Corporation + * Copyright (C) 2013, Intel Corporation * Authors: Mika Westerberg * Rafael J. Wysocki * @@ -60,8 +60,6 @@ ACPI_MODULE_NAME("acpi_lpss"); #define LPSS_CLK_DIVIDER BIT(2) #define LPSS_LTR BIT(3) #define LPSS_SAVE_CTX BIT(4) -#define LPSS_DEV_PROXY BIT(5) -#define LPSS_PROXY_REQ BIT(6) struct lpss_private_data; @@ -72,10 +70,8 @@ struct lpss_device_desc { void (*setup)(struct lpss_private_data *pdata); }; -static struct device *proxy_device; - static struct lpss_device_desc lpss_dma_desc = { - .flags = LPSS_CLK | LPSS_PROXY_REQ, + .flags = LPSS_CLK, }; struct lpss_private_data { @@ -129,7 +125,7 @@ static struct lpss_device_desc lpt_dev_desc = { }; static struct lpss_device_desc lpt_i2c_dev_desc = { - .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_LTR, + .flags = LPSS_CLK | LPSS_LTR, .prv_offset = 0x800, }; @@ -150,24 +146,22 @@ static struct lpss_device_desc byt_pwm_dev_desc = { }; static struct lpss_device_desc byt_uart_dev_desc = { - .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX | - LPSS_DEV_PROXY, + .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX, .prv_offset = 0x800, .setup = lpss_uart_setup, }; static struct lpss_device_desc byt_spi_dev_desc = { - .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX | - LPSS_DEV_PROXY, + .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX, .prv_offset = 0x400, }; static struct lpss_device_desc byt_sdio_dev_desc = { - .flags = LPSS_CLK | LPSS_DEV_PROXY, + .flags = LPSS_CLK, }; static struct lpss_device_desc byt_i2c_dev_desc = { - .flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_DEV_PROXY, + .flags = LPSS_CLK | LPSS_SAVE_CTX, .prv_offset = 0x800, .setup = byt_i2c_setup, }; @@ -313,7 +307,7 @@ static int acpi_lpss_create_device(struct acpi_device *adev, { struct lpss_device_desc *dev_desc; struct lpss_private_data *pdata; - struct resource_list_entry *rentry; + struct resource_entry *rentry; struct list_head resource_list; struct platform_device *pdev; int ret; @@ -333,13 +327,15 @@ static int acpi_lpss_create_device(struct acpi_device *adev, goto err_out; list_for_each_entry(rentry, &resource_list, node) - if (resource_type(&rentry->res) == IORESOURCE_MEM) { + if (resource_type(rentry->res) == IORESOURCE_MEM) { if (dev_desc->prv_size_override) pdata->mmio_size = dev_desc->prv_size_override; else - pdata->mmio_size = resource_size(&rentry->res); - pdata->mmio_base = ioremap(rentry->res.start, + pdata->mmio_size = resource_size(rentry->res); + pdata->mmio_base = ioremap(rentry->res->start, pdata->mmio_size); + if (!pdata->mmio_base) + goto err_out; break; } @@ -374,8 +370,6 @@ static int acpi_lpss_create_device(struct acpi_device *adev, adev->driver_data = pdata; pdev = acpi_create_platform_device(adev); if (!IS_ERR_OR_NULL(pdev)) { - if (!proxy_device && dev_desc->flags & LPSS_DEV_PROXY) - proxy_device = &pdev->dev; return 1; } @@ -600,14 +594,7 @@ static int acpi_lpss_runtime_suspend(struct device *dev) if (pdata->dev_desc->flags & LPSS_SAVE_CTX) acpi_lpss_save_ctx(dev, pdata); - ret = acpi_dev_runtime_suspend(dev); - if (ret) - return ret; - - if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device) - return pm_runtime_put_sync_suspend(proxy_device); - - return 0; + return acpi_dev_runtime_suspend(dev); } static int acpi_lpss_runtime_resume(struct device *dev) @@ -615,12 +602,6 @@ static int acpi_lpss_runtime_resume(struct device *dev) struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); int ret; - if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device) { - ret = pm_runtime_get_sync(proxy_device); - if (ret) - return ret; - } - ret = acpi_dev_runtime_resume(dev); if (ret) return ret; diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 23e2319ead41..ee28f4d15625 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -101,8 +101,8 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context) /* Can we combine the resource range information? */ if ((info->caching == address64.info.mem.caching) && (info->write_protect == address64.info.mem.write_protect) && - (info->start_addr + info->length == address64.minimum)) { - info->length += address64.address_length; + (info->start_addr + info->length == address64.address.minimum)) { + info->length += address64.address.address_length; return AE_OK; } } @@ -114,8 +114,8 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context) INIT_LIST_HEAD(&new->list); new->caching = address64.info.mem.caching; new->write_protect = address64.info.mem.write_protect; - new->start_addr = address64.minimum; - new->length = address64.address_length; + new->start_addr = address64.address.minimum; + new->length = address64.address.address_length; list_add_tail(&new->list, &mem_device->res_list); return AE_OK; diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 6ba8beb6b9d2..1284138e42ab 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -45,7 +45,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) struct platform_device *pdev = NULL; struct acpi_device *acpi_parent; struct platform_device_info pdevinfo; - struct resource_list_entry *rentry; + struct resource_entry *rentry; struct list_head resource_list; struct resource *resources = NULL; int count; @@ -71,7 +71,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) } count = 0; list_for_each_entry(rentry, &resource_list, node) - resources[count++] = rentry->res; + resources[count++] = *rentry->res; acpi_dev_free_resource_list(&resource_list); } diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index 3d2c88289da9..d863016565b5 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,7 +47,7 @@ /* Common info for tool signons */ #define ACPICA_NAME "Intel ACPI Component Architecture" -#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2014 Intel Corporation" +#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2015 Intel Corporation" #if ACPI_MACHINE_WIDTH == 64 #define ACPI_WIDTH "-64" diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h index 6f1c616910ac..853aa2dbdb61 100644 --- a/drivers/acpi/acpica/accommon.h +++ b/drivers/acpi/acpica/accommon.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 1d026ff1683f..4169bb87a996 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h index d3e2cc395d7f..408f04bcaab4 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 7a7811a9fc26..228704b78657 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -143,8 +143,6 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle, acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context); -u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info); - acpi_status acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, void *context); diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 7f60582d0c8c..a165d25343e8 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index c318d3e27893..196a55244559 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index b01f71ce0523..1886bde54b5d 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 680d23bbae7c..7add32e5d8c5 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index 4bceb11c7380..cf607fe69dbd 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index ee1c040f321c..952fbe0b7231 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 8abb393dafab..3e9720e1f34f 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index dda0e6affcf1..a5f17de45ac6 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h index 6168b85463ed..74a390c6db16 100644 --- a/drivers/acpi/acpica/acparser.h +++ b/drivers/acpi/acpica/acparser.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index bd3908d26c4f..a972d11c97c9 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h index 4b008e8884a1..efc4c7124ccc 100644 --- a/drivers/acpi/acpica/acresrc.h +++ b/drivers/acpi/acpica/acresrc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index cf7346110bd8..d14b547b7cd5 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 1afe46e44dac..1c127a43017b 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 486d342e74b6..c2f03e8774ad 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 5908ccec6aea..3a95068fc119 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index 3a0beeb86ba5..ee0cdd60b93d 100644 --- a/drivers/acpi/acpica/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c index 720b1cdda711..3e6989738e85 100644 --- a/drivers/acpi/acpica/dsargs.c +++ b/drivers/acpi/acpica/dsargs.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c index 8daf9de82b73..39da9da62bbf 100644 --- a/drivers/acpi/acpica/dscontrol.c +++ b/drivers/acpi/acpica/dscontrol.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index c57666196672..43b40de90484 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index aee5e45f6d35..bbe74bcebbae 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 3c7f7378b94d..d72565a3c646 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index b67522df01ac..2e4c42b377ec 100644 --- a/drivers/acpi/acpica/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index a1e7e6b6fcf7..8a7b07b6adc8 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index 6c0759c0db47..77244182ff02 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index 9f74795e2268..e5ff89bcb3f5 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index f7f5107e754d..df54d46225cd 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 15623da26200..843942fb4be5 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index 2ac28d297305..fcaa30c611fb 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c index 9d6e2c1de1f8..43b3ea40c0b6 100644 --- a/drivers/acpi/acpica/dswscope.c +++ b/drivers/acpi/acpica/dswscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index 24f7d5ea678a..89ac2022465e 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c index c7bffff9ed32..bf6873f95e72 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c index 3393a73ca0d6..b78dc7c6d5d7 100644 --- a/drivers/acpi/acpica/evglock.c +++ b/drivers/acpi/acpica/evglock.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index aa70154cf4fa..5ed064e8673c 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -114,17 +114,6 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) ACPI_FUNCTION_TRACE(ev_enable_gpe); - /* - * We will only allow a GPE to be enabled if it has either an associated - * method (_Lxx/_Exx) or a handler, or is using the implicit notify - * feature. Otherwise, the GPE will be immediately disabled by - * acpi_ev_gpe_dispatch the first time it fires. - */ - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == - ACPI_GPE_DISPATCH_NONE) { - return_ACPI_STATUS(AE_NO_HANDLER); - } - /* Clear the GPE (of stale events) */ status = acpi_hw_clear_gpe(gpe_event_info); @@ -339,7 +328,11 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) { acpi_status status; struct acpi_gpe_block_info *gpe_block; + struct acpi_namespace_node *gpe_device; struct acpi_gpe_register_info *gpe_register_info; + struct acpi_gpe_event_info *gpe_event_info; + u32 gpe_number; + struct acpi_gpe_handler_info *gpe_handler_info; u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; u8 enabled_status_byte; u32 status_reg; @@ -367,6 +360,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) gpe_block = gpe_xrupt_list->gpe_block_list_head; while (gpe_block) { + gpe_device = gpe_block->node; + /* * Read all of the 8-bit GPE status and enable registers in this GPE * block, saving all of them. Find all currently active GP events. @@ -442,16 +437,68 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) /* Examine one GPE bit */ + gpe_event_info = + &gpe_block-> + event_info[((acpi_size) i * + ACPI_GPE_REGISTER_WIDTH) + j]; + gpe_number = + j + gpe_register_info->base_gpe_number; + if (enabled_status_byte & (1 << j)) { - /* - * Found an active GPE. Dispatch the event to a handler - * or method. - */ - int_status |= - acpi_ev_gpe_dispatch(gpe_block-> - node, - &gpe_block-> - event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number); + + /* Invoke global event handler if present */ + + acpi_gpe_count++; + if (acpi_gbl_global_event_handler) { + acpi_gbl_global_event_handler + (ACPI_EVENT_TYPE_GPE, + gpe_device, gpe_number, + acpi_gbl_global_event_handler_context); + } + + /* Found an active GPE */ + + if (ACPI_GPE_DISPATCH_TYPE + (gpe_event_info->flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER) { + + /* Dispatch the event to a raw handler */ + + gpe_handler_info = + gpe_event_info->dispatch. + handler; + + /* + * There is no protection around the namespace node + * and the GPE handler to ensure a safe destruction + * because: + * 1. The namespace node is expected to always + * exist after loading a table. + * 2. The GPE handler is expected to be flushed by + * acpi_os_wait_events_complete() before the + * destruction. + */ + acpi_os_release_lock + (acpi_gbl_gpe_lock, flags); + int_status |= + gpe_handler_info-> + address(gpe_device, + gpe_number, + gpe_handler_info-> + context); + flags = + acpi_os_acquire_lock + (acpi_gbl_gpe_lock); + } else { + /* + * Dispatch the event to a standard handler or + * method. + */ + int_status |= + acpi_ev_gpe_dispatch + (gpe_device, gpe_event_info, + gpe_number); + } } } } @@ -484,52 +531,15 @@ unlock_and_exit: static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) { struct acpi_gpe_event_info *gpe_event_info = context; - acpi_status status; - struct acpi_gpe_event_info *local_gpe_event_info; + acpi_status status = AE_OK; struct acpi_evaluate_info *info; struct acpi_gpe_notify_info *notify; ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); - /* Allocate a local GPE block */ - - local_gpe_event_info = - ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_event_info)); - if (!local_gpe_event_info) { - ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "while handling a GPE")); - return_VOID; - } - - status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); - if (ACPI_FAILURE(status)) { - ACPI_FREE(local_gpe_event_info); - return_VOID; - } - - /* Must revalidate the gpe_number/gpe_block */ - - if (!acpi_ev_valid_gpe_event(gpe_event_info)) { - status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); - ACPI_FREE(local_gpe_event_info); - return_VOID; - } - - /* - * Take a snapshot of the GPE info for this level - we copy the info to - * prevent a race condition with remove_handler/remove_block. - */ - ACPI_MEMCPY(local_gpe_event_info, gpe_event_info, - sizeof(struct acpi_gpe_event_info)); - - status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); - if (ACPI_FAILURE(status)) { - ACPI_FREE(local_gpe_event_info); - return_VOID; - } - /* Do the correct dispatch - normal method or implicit notify */ - switch (local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { + switch (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) { case ACPI_GPE_DISPATCH_NOTIFY: /* * Implicit notify. @@ -542,7 +552,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) * June 2012: Expand implicit notify mechanism to support * notifies on multiple device objects. */ - notify = local_gpe_event_info->dispatch.notify_list; + notify = gpe_event_info->dispatch.notify_list; while (ACPI_SUCCESS(status) && notify) { status = acpi_ev_queue_notify_request(notify->device_node, @@ -566,7 +576,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) * _Lxx/_Exx control method that corresponds to this GPE */ info->prefix_node = - local_gpe_event_info->dispatch.method_node; + gpe_event_info->dispatch.method_node; info->flags = ACPI_IGNORE_RETURN_VALUE; status = acpi_ns_evaluate(info); @@ -576,25 +586,27 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "while evaluating GPE method [%4.4s]", - acpi_ut_get_node_name - (local_gpe_event_info->dispatch. - method_node))); + acpi_ut_get_node_name(gpe_event_info-> + dispatch. + method_node))); } break; default: - return_VOID; /* Should never happen */ + goto error_exit; /* Should never happen */ } /* Defer enabling of GPE until all notify handlers are done */ status = acpi_os_execute(OSL_NOTIFY_HANDLER, - acpi_ev_asynch_enable_gpe, - local_gpe_event_info); - if (ACPI_FAILURE(status)) { - ACPI_FREE(local_gpe_event_info); + acpi_ev_asynch_enable_gpe, gpe_event_info); + if (ACPI_SUCCESS(status)) { + return_VOID; } + +error_exit: + acpi_ev_asynch_enable_gpe(gpe_event_info); return_VOID; } @@ -622,7 +634,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context) (void)acpi_ev_finish_gpe(gpe_event_info); acpi_os_release_lock(acpi_gbl_gpe_lock, flags); - ACPI_FREE(gpe_event_info); return; } @@ -692,15 +703,6 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, ACPI_FUNCTION_TRACE(ev_gpe_dispatch); - /* Invoke global event handler if present */ - - acpi_gpe_count++; - if (acpi_gbl_global_event_handler) { - acpi_gbl_global_event_handler(ACPI_EVENT_TYPE_GPE, gpe_device, - gpe_number, - acpi_gbl_global_event_handler_context); - } - /* * Always disable the GPE so that it does not keep firing before * any asynchronous activity completes (either from the execution @@ -741,7 +743,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, * If there is neither a handler nor a method, leave the GPE * disabled. */ - switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { + switch (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) { case ACPI_GPE_DISPATCH_HANDLER: /* Invoke the installed handler (at interrupt level) */ diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index d86699eea33c..e0f24c504513 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -474,10 +474,12 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, * Ignore GPEs that have no corresponding _Lxx/_Exx method * and GPEs that are used to wake the system */ - if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == ACPI_GPE_DISPATCH_NONE) - || ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) - == ACPI_GPE_DISPATCH_HANDLER) + || (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_HANDLER) + || (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER) || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { continue; } diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index 7be928379879..8840296d5b20 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -401,15 +401,17 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle, return_ACPI_STATUS(AE_OK); } - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == - ACPI_GPE_DISPATCH_HANDLER) { + if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_HANDLER) || + (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER)) { /* If there is already a handler, ignore this GPE method */ return_ACPI_STATUS(AE_OK); } - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == ACPI_GPE_DISPATCH_METHOD) { /* * If there is already a method, ignore this method. But check diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index 17e4bbfdb096..3a958f3612fe 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -106,53 +106,6 @@ unlock_and_exit: return_ACPI_STATUS(status); } -/******************************************************************************* - * - * FUNCTION: acpi_ev_valid_gpe_event - * - * PARAMETERS: gpe_event_info - Info for this GPE - * - * RETURN: TRUE if the gpe_event is valid - * - * DESCRIPTION: Validate a GPE event. DO NOT CALL FROM INTERRUPT LEVEL. - * Should be called only when the GPE lists are semaphore locked - * and not subject to change. - * - ******************************************************************************/ - -u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info) -{ - struct acpi_gpe_xrupt_info *gpe_xrupt_block; - struct acpi_gpe_block_info *gpe_block; - - ACPI_FUNCTION_ENTRY(); - - /* No need for spin lock since we are not changing any list elements */ - - /* Walk the GPE interrupt levels */ - - gpe_xrupt_block = acpi_gbl_gpe_xrupt_list_head; - while (gpe_xrupt_block) { - gpe_block = gpe_xrupt_block->gpe_block_list_head; - - /* Walk the GPE blocks on this interrupt level */ - - while (gpe_block) { - if ((&gpe_block->event_info[0] <= gpe_event_info) && - (&gpe_block->event_info[gpe_block->gpe_count] > - gpe_event_info)) { - return (TRUE); - } - - gpe_block = gpe_block->next; - } - - gpe_xrupt_block = gpe_xrupt_block->next; - } - - return (FALSE); -} - /******************************************************************************* * * FUNCTION: acpi_ev_get_gpe_device @@ -371,8 +324,10 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, ACPI_GPE_REGISTER_WIDTH) + j]; - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == - ACPI_GPE_DISPATCH_HANDLER) { + if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_HANDLER) || + (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER)) { /* Delete an installed handler block */ @@ -380,10 +335,8 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, gpe_event_info->dispatch.handler = NULL; gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; - } else - if ((gpe_event_info-> - flags & ACPI_GPE_DISPATCH_MASK) == - ACPI_GPE_DISPATCH_NOTIFY) { + } else if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) + == ACPI_GPE_DISPATCH_NOTIFY) { /* Delete the implicit notification device list */ diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c index 78ac29351c9e..74e8595f5a2b 100644 --- a/drivers/acpi/acpica/evhandler.c +++ b/drivers/acpi/acpica/evhandler.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index 24ea3424981b..f7c9dfe7b990 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 8eb8575e8c16..9abace3401f9 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 1b148a440d67..da323390bb70 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c index 29630e303829..0366703d2970 100644 --- a/drivers/acpi/acpica/evsci.c +++ b/drivers/acpi/acpica/evsci.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 55a58f3ec8df..81f2d9e87fad 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -51,6 +51,16 @@ #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evxface") +#if (!ACPI_REDUCED_HARDWARE) +/* Local prototypes */ +static acpi_status +acpi_ev_install_gpe_handler(acpi_handle gpe_device, + u32 gpe_number, + u32 type, + u8 is_raw_handler, + acpi_gpe_handler address, void *context); + +#endif /******************************************************************************* @@ -76,6 +86,7 @@ ACPI_MODULE_NAME("evxface") * handlers. * ******************************************************************************/ + acpi_status acpi_install_notify_handler(acpi_handle device, u32 handler_type, @@ -717,32 +728,37 @@ ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler) /******************************************************************************* * - * FUNCTION: acpi_install_gpe_handler + * FUNCTION: acpi_ev_install_gpe_handler * * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT * defined GPEs) * gpe_number - The GPE number within the GPE block * type - Whether this GPE should be treated as an * edge- or level-triggered interrupt. + * is_raw_handler - Whether this GPE should be handled using + * the special GPE handler mode. * address - Address of the handler * context - Value passed to the handler on each GPE * * RETURN: Status * - * DESCRIPTION: Install a handler for a General Purpose Event. + * DESCRIPTION: Internal function to install a handler for a General Purpose + * Event. * ******************************************************************************/ -acpi_status -acpi_install_gpe_handler(acpi_handle gpe_device, - u32 gpe_number, - u32 type, acpi_gpe_handler address, void *context) +static acpi_status +acpi_ev_install_gpe_handler(acpi_handle gpe_device, + u32 gpe_number, + u32 type, + u8 is_raw_handler, + acpi_gpe_handler address, void *context) { struct acpi_gpe_event_info *gpe_event_info; struct acpi_gpe_handler_info *handler; acpi_status status; acpi_cpu_flags flags; - ACPI_FUNCTION_TRACE(acpi_install_gpe_handler); + ACPI_FUNCTION_TRACE(ev_install_gpe_handler); /* Parameter validation */ @@ -775,8 +791,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device, /* Make sure that there isn't a handler there already */ - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == - ACPI_GPE_DISPATCH_HANDLER) { + if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_HANDLER) || + (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == + ACPI_GPE_DISPATCH_RAW_HANDLER)) { status = AE_ALREADY_EXISTS; goto free_and_exit; } @@ -793,9 +811,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device, * automatically during initialization, in which case it has to be * disabled now to avoid spurious execution of the handler. */ - if (((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) || - (handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) && - gpe_event_info->runtime_count) { + if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == + ACPI_GPE_DISPATCH_METHOD) || + (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == + ACPI_GPE_DISPATCH_NOTIFY)) && gpe_event_info->runtime_count) { handler->originally_enabled = TRUE; (void)acpi_ev_remove_gpe_reference(gpe_event_info); @@ -816,7 +835,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device, gpe_event_info->flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); - gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_HANDLER); + gpe_event_info->flags |= + (u8)(type | + (is_raw_handler ? ACPI_GPE_DISPATCH_RAW_HANDLER : + ACPI_GPE_DISPATCH_HANDLER)); acpi_os_release_lock(acpi_gbl_gpe_lock, flags); @@ -830,8 +852,76 @@ free_and_exit: goto unlock_and_exit; } +/******************************************************************************* + * + * FUNCTION: acpi_install_gpe_handler + * + * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT + * defined GPEs) + * gpe_number - The GPE number within the GPE block + * type - Whether this GPE should be treated as an + * edge- or level-triggered interrupt. + * address - Address of the handler + * context - Value passed to the handler on each GPE + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for a General Purpose Event. + * + ******************************************************************************/ + +acpi_status +acpi_install_gpe_handler(acpi_handle gpe_device, + u32 gpe_number, + u32 type, acpi_gpe_handler address, void *context) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_install_gpe_handler); + + status = + acpi_ev_install_gpe_handler(gpe_device, gpe_number, type, FALSE, + address, context); + + return_ACPI_STATUS(status); +} + ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler) +/******************************************************************************* + * + * FUNCTION: acpi_install_gpe_raw_handler + * + * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT + * defined GPEs) + * gpe_number - The GPE number within the GPE block + * type - Whether this GPE should be treated as an + * edge- or level-triggered interrupt. + * address - Address of the handler + * context - Value passed to the handler on each GPE + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for a General Purpose Event. + * + ******************************************************************************/ +acpi_status +acpi_install_gpe_raw_handler(acpi_handle gpe_device, + u32 gpe_number, + u32 type, acpi_gpe_handler address, void *context) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_install_gpe_raw_handler); + + status = acpi_ev_install_gpe_handler(gpe_device, gpe_number, type, TRUE, + address, context); + + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_install_gpe_raw_handler) + /******************************************************************************* * * FUNCTION: acpi_remove_gpe_handler @@ -880,8 +970,10 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, /* Make sure that a handler is indeed installed */ - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != - ACPI_GPE_DISPATCH_HANDLER) { + if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != + ACPI_GPE_DISPATCH_HANDLER) && + (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != + ACPI_GPE_DISPATCH_RAW_HANDLER)) { status = AE_NOT_EXIST; goto unlock_and_exit; } @@ -896,6 +988,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, /* Remove the handler */ handler = gpe_event_info->dispatch.handler; + gpe_event_info->dispatch.handler = NULL; /* Restore Method node (if any), set dispatch flags */ @@ -909,9 +1002,10 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, * enabled, it should be enabled at this point to restore the * post-initialization configuration. */ - if (((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) || - (handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) && - handler->originally_enabled) { + if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == + ACPI_GPE_DISPATCH_METHOD) || + (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == + ACPI_GPE_DISPATCH_NOTIFY)) && handler->originally_enabled) { (void)acpi_ev_add_gpe_reference(gpe_event_info); } diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index bb8cbf5961bf..df06a23c4197 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index e889a5304abd..70eb47e3d724 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -132,7 +132,7 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (gpe_event_info) { - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != ACPI_GPE_DISPATCH_NONE) { status = acpi_ev_add_gpe_reference(gpe_event_info); } else { @@ -183,6 +183,77 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number) ACPI_EXPORT_SYMBOL(acpi_disable_gpe) +/******************************************************************************* + * + * FUNCTION: acpi_set_gpe + * + * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 + * gpe_number - GPE level within the GPE block + * action - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE + * + * RETURN: Status + * + * DESCRIPTION: Enable or disable an individual GPE. This function bypasses + * the reference count mechanism used in the acpi_enable_gpe(), + * acpi_disable_gpe() interfaces. + * This API is typically used by the GPE raw handler mode driver + * to switch between the polling mode and the interrupt mode after + * the driver has enabled the GPE. + * The APIs should be invoked in this order: + * acpi_enable_gpe() <- Ensure the reference count > 0 + * acpi_set_gpe(ACPI_GPE_DISABLE) <- Enter polling mode + * acpi_set_gpe(ACPI_GPE_ENABLE) <- Leave polling mode + * acpi_disable_gpe() <- Decrease the reference count + * + * Note: If a GPE is shared by 2 silicon components, then both the drivers + * should support GPE polling mode or disabling the GPE for long period + * for one driver may break the other. So use it with care since all + * firmware _Lxx/_Exx handlers currently rely on the GPE interrupt mode. + * + ******************************************************************************/ +acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action) +{ + struct acpi_gpe_event_info *gpe_event_info; + acpi_status status; + acpi_cpu_flags flags; + + ACPI_FUNCTION_TRACE(acpi_set_gpe); + + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (!gpe_event_info) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* Perform the action */ + + switch (action) { + case ACPI_GPE_ENABLE: + + status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE); + break; + + case ACPI_GPE_DISABLE: + + status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); + break; + + default: + + status = AE_BAD_PARAMETER; + break; + } + +unlock_and_exit: + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_set_gpe) /******************************************************************************* * @@ -313,7 +384,7 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, * known as an "implicit notify". Note: The GPE is assumed to be * level-triggered (for windows compatibility). */ - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == ACPI_GPE_DISPATCH_NONE) { /* * This is the first device for implicit notify on this GPE. @@ -327,7 +398,7 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, * If we already have an implicit notify on this GPE, add * this device to the notify list. */ - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == ACPI_GPE_DISPATCH_NOTIFY) { /* Ensure that the device is not already in the list */ @@ -530,6 +601,49 @@ unlock_and_exit: ACPI_EXPORT_SYMBOL(acpi_get_gpe_status) +/******************************************************************************* + * + * FUNCTION: acpi_finish_gpe + * + * PARAMETERS: gpe_device - Namespace node for the GPE Block + * (NULL for FADT defined GPEs) + * gpe_number - GPE level within the GPE block + * + * RETURN: Status + * + * DESCRIPTION: Clear and conditionally reenable a GPE. This completes the GPE + * processing. Intended for use by asynchronous host-installed + * GPE handlers. The GPE is only reenabled if the enable_for_run bit + * is set in the GPE info. + * + ******************************************************************************/ +acpi_status acpi_finish_gpe(acpi_handle gpe_device, u32 gpe_number) +{ + struct acpi_gpe_event_info *gpe_event_info; + acpi_status status; + acpi_cpu_flags flags; + + ACPI_FUNCTION_TRACE(acpi_finish_gpe); + + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (!gpe_event_info) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + status = acpi_ev_finish_gpe(gpe_event_info); + +unlock_and_exit: + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_finish_gpe) + /****************************************************************************** * * FUNCTION: acpi_disable_all_gpes @@ -604,7 +718,6 @@ ACPI_EXPORT_SYMBOL(acpi_enable_all_runtime_gpes) * all GPE blocks. * ******************************************************************************/ - acpi_status acpi_enable_all_wakeup_gpes(void) { acpi_status status; diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index 2d6f187939c7..f21afbab03f7 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 7d2949420db7..6e0df2b9d5a4 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index c545386fee96..89a976b4ccf2 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 95d23dabcfbb..aaeea4840aaa 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index 6fbfad47518c..e67d0aca3fe6 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 0f23c3f2678e..7c213b6b6472 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index b994845ed359..c161dd974f74 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 1d1b27a96c5b..49479927e7f7 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index 2207e624f538..b56fc9d6f48e 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index b49ea2a95f4f..472030f2b5bb 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index dbb03b544e8c..453b00c30177 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index 1b8e94104407..77930683ab7d 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 2ede656ee26a..fcc618aa2061 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 363767cf01e5..b813fed95e56 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index 29e9e99f7fe3..c930edda3f65 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c index 118e942005e5..4c2836dc825b 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index cd5288a257a9..0fe188e238ef 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index ab060261b43e..c7e3b929aa85 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index 3cde553bcbe1..b6b7f3af29e4 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c index 3af8de3fcea4..d2964af9ad4d 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index daf49f7ea311..a7eee2400ce0 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c index 04bd16c08f9e..3101607b4efe 100644 --- a/drivers/acpi/acpica/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c index fd11018b0168..6fa3c8d8fc5f 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c index f7da64123ed5..05450656fe3d 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index d9d72dff2a76..3f4225e95d93 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index 1e66d960fc11..e5c5949f9081 100644 --- a/drivers/acpi/acpica/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c index 858fdd6be598..e5599f610808 100644 --- a/drivers/acpi/acpica/hwesleep.c +++ b/drivers/acpi/acpica/hwesleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 494027f5c067..84bc550f4f1d 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,6 +54,10 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, void *context); +static acpi_status +acpi_hw_gpe_enable_write(u8 enable_mask, + struct acpi_gpe_register_info *gpe_register_info); + /****************************************************************************** * * FUNCTION: acpi_hw_get_gpe_register_bit @@ -146,7 +150,7 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action) status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address); if (ACPI_SUCCESS(status) && (action & ACPI_GPE_SAVE_MASK)) { - gpe_register_info->enable_mask = enable_mask; + gpe_register_info->enable_mask = (u8)enable_mask; } return (status); } @@ -221,7 +225,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, /* GPE currently handled? */ - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != + if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != ACPI_GPE_DISPATCH_NONE) { local_event_status |= ACPI_EVENT_FLAG_HAS_HANDLER; } diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c index 6aade8e1d2a1..c5214dec4988 100644 --- a/drivers/acpi/acpica/hwpci.c +++ b/drivers/acpi/acpica/hwpci.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index a4c34d2c556b..3cf77afd142c 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index d590693eb54e..7d21cae6d602 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index 76ab5c1a814e..675c709a300b 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index 6b919127cd9d..2bd33fe56cb3 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 96d007df65ec..5f97468df8ff 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index 6921c7f3d208..3b3767698827 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index f1249e3463be..24fa19a76d70 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index 607eb9e5150d..e107f929d9cf 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsarguments.c b/drivers/acpi/acpica/nsarguments.c index 80fcfc8c9c1b..5d347a71bd0b 100644 --- a/drivers/acpi/acpica/nsarguments.c +++ b/drivers/acpi/acpica/nsarguments.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c index b55642c4ee58..1a8b39c8d969 100644 --- a/drivers/acpi/acpica/nsconvert.c +++ b/drivers/acpi/acpica/nsconvert.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 3d88ef4a3e0d..80f097eb7381 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c index 42d37109aa5d..7dc367e6fe09 100644 --- a/drivers/acpi/acpica/nsdumpdv.c +++ b/drivers/acpi/acpica/nsdumpdv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index e634a05974db..7bcc68f57afa 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index a3fb7e4c0809..4a85c4517988 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index 7c9d0181f341..bd6cd4a81316 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index 7eee0a6f02f6..d293d9748036 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index a42ee9d6970d..677bc9330e64 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index e83cff31754b..c95a119767b5 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 392910ffbed9..0eb54315b4be 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c index 1b13b921dda9..8b79958b7aca 100644 --- a/drivers/acpi/acpica/nsprepkg.c +++ b/drivers/acpi/acpica/nsprepkg.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index 7e417aa5c91e..151fcd95ba84 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index b09e6bef72b8..c30672d23878 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index af1cc42a8aa1..4a9d4a66016e 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 4a5e3f5c0ff7..6ad02008c0c2 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 4758a1f2ce22..c68609a2bc1b 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index 4bd558bf10d2..b6030a2deee1 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 8c6c11ce9760..d66c326485d8 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index dae9401be7a2..793383501f81 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -51,50 +51,6 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfobj") -/******************************************************************************* - * - * FUNCTION: acpi_get_id - * - * PARAMETERS: Handle - Handle of object whose id is desired - * ret_id - Where the id will be placed - * - * RETURN: Status - * - * DESCRIPTION: This routine returns the owner id associated with a handle - * - ******************************************************************************/ -acpi_status acpi_get_id(acpi_handle handle, acpi_owner_id * ret_id) -{ - struct acpi_namespace_node *node; - acpi_status status; - - /* Parameter Validation */ - - if (!ret_id) { - return (AE_BAD_PARAMETER); - } - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return (status); - } - - /* Convert and validate the handle */ - - node = acpi_ns_validate_handle(handle); - if (!node) { - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - return (AE_BAD_PARAMETER); - } - - *ret_id = node->owner_id; - - status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - return (status); -} - -ACPI_EXPORT_SYMBOL(acpi_get_id) - /******************************************************************************* * * FUNCTION: acpi_get_type diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 314d314340ae..6d038770577b 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index b058e2390fdd..90437227d790 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index a6885077d59e..2f5ddd806c58 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index 1755d2ac5656..1af4a405e351 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c index 0d8d37ffd04d..e18e7c47f482 100644 --- a/drivers/acpi/acpica/psopinfo.c +++ b/drivers/acpi/acpica/psopinfo.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 6d27b597394e..a555f7f7b9a2 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c index 32d250feea21..9d669cc6cb62 100644 --- a/drivers/acpi/acpica/psscope.c +++ b/drivers/acpi/acpica/psscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c index 0b64181e7720..89984f30addc 100644 --- a/drivers/acpi/acpica/pstree.c +++ b/drivers/acpi/acpica/pstree.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 3cd48802eede..960505ab409a 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c index 9cb07e1e76d9..ba5f69171288 100644 --- a/drivers/acpi/acpica/pswalk.c +++ b/drivers/acpi/acpica/pswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index e135acaa5e1c..841a5ea06094 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c index 916fd095ff34..66d406e8fe36 100644 --- a/drivers/acpi/acpica/rsaddr.c +++ b/drivers/acpi/acpica/rsaddr.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -74,7 +74,7 @@ struct acpi_rsconvert_info acpi_rs_convert_address16[5] = { * Address Translation Offset * Address Length */ - {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.address16.granularity), + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.address16.address.granularity), AML_OFFSET(address16.granularity), 5}, @@ -112,7 +112,7 @@ struct acpi_rsconvert_info acpi_rs_convert_address32[5] = { * Address Translation Offset * Address Length */ - {ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.address32.granularity), + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.address32.address.granularity), AML_OFFSET(address32.granularity), 5}, @@ -150,7 +150,7 @@ struct acpi_rsconvert_info acpi_rs_convert_address64[5] = { * Address Translation Offset * Address Length */ - {ACPI_RSC_MOVE64, ACPI_RS_OFFSET(data.address64.granularity), + {ACPI_RSC_MOVE64, ACPI_RS_OFFSET(data.address64.address.granularity), AML_OFFSET(address64.granularity), 5}, @@ -194,7 +194,8 @@ struct acpi_rsconvert_info acpi_rs_convert_ext_address64[5] = { * Address Length * Type-Specific Attribute */ - {ACPI_RSC_MOVE64, ACPI_RS_OFFSET(data.ext_address64.granularity), + {ACPI_RSC_MOVE64, + ACPI_RS_OFFSET(data.ext_address64.address.granularity), AML_OFFSET(ext_address64.granularity), 6} }; diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index 689556744b03..cb739a694931 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index 049d9c22a0f9..15434e4c9b34 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c index c3c56b5a9788..1539394c8c52 100644 --- a/drivers/acpi/acpica/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsdumpinfo.c b/drivers/acpi/acpica/rsdumpinfo.c index 2f9332d5c973..b29d9ec63d1b 100644 --- a/drivers/acpi/acpica/rsdumpinfo.c +++ b/drivers/acpi/acpica/rsdumpinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -183,15 +183,15 @@ struct acpi_rsdump_info acpi_rs_dump_address16[8] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address16), "16-Bit WORD Address Space", NULL}, {ACPI_RSD_ADDRESS, 0, NULL, NULL}, - {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.granularity), "Granularity", - NULL}, - {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.minimum), "Address Minimum", - NULL}, - {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.maximum), "Address Maximum", - NULL}, - {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.translation_offset), + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.granularity), + "Granularity", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.minimum), + "Address Minimum", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.maximum), + "Address Maximum", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.translation_offset), "Translation Offset", NULL}, - {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address_length), + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.address_length), "Address Length", NULL}, {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address16.resource_source), NULL, NULL} }; @@ -200,15 +200,15 @@ struct acpi_rsdump_info acpi_rs_dump_address32[8] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address32), "32-Bit DWORD Address Space", NULL}, {ACPI_RSD_ADDRESS, 0, NULL, NULL}, - {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.granularity), "Granularity", - NULL}, - {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.minimum), "Address Minimum", - NULL}, - {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.maximum), "Address Maximum", - NULL}, - {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.translation_offset), + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.granularity), + "Granularity", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.minimum), + "Address Minimum", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.maximum), + "Address Maximum", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.translation_offset), "Translation Offset", NULL}, - {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address_length), + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.address_length), "Address Length", NULL}, {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address32.resource_source), NULL, NULL} }; @@ -217,15 +217,15 @@ struct acpi_rsdump_info acpi_rs_dump_address64[8] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address64), "64-Bit QWORD Address Space", NULL}, {ACPI_RSD_ADDRESS, 0, NULL, NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.granularity), "Granularity", - NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.minimum), "Address Minimum", - NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.maximum), "Address Maximum", - NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.translation_offset), + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.granularity), + "Granularity", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.minimum), + "Address Minimum", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.maximum), + "Address Maximum", NULL}, + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.translation_offset), "Translation Offset", NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address_length), + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.address_length), "Address Length", NULL}, {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address64.resource_source), NULL, NULL} }; @@ -234,15 +234,16 @@ struct acpi_rsdump_info acpi_rs_dump_ext_address64[8] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_ext_address64), "64-Bit Extended Address Space", NULL}, {ACPI_RSD_ADDRESS, 0, NULL, NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.granularity), + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.granularity), "Granularity", NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.minimum), + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.minimum), "Address Minimum", NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.maximum), + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.maximum), "Address Maximum", NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.translation_offset), + {ACPI_RSD_UINT64, + ACPI_RSD_OFFSET(ext_address64.address.translation_offset), "Translation Offset", NULL}, - {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address_length), + {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.address_length), "Address Length", NULL}, {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.type_specific), "Type-Specific Attribute", NULL} diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c index 9d3f8a9a24bd..edecfc675979 100644 --- a/drivers/acpi/acpica/rsinfo.c +++ b/drivers/acpi/acpica/rsinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c index 19d64873290a..5adba018bab0 100644 --- a/drivers/acpi/acpica/rsio.c +++ b/drivers/acpi/acpica/rsio.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsirq.c b/drivers/acpi/acpica/rsirq.c index 3461f7db26df..07cfa70a475b 100644 --- a/drivers/acpi/acpica/rsirq.c +++ b/drivers/acpi/acpica/rsirq.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c index 77291293af64..50d5be2ee062 100644 --- a/drivers/acpi/acpica/rslist.c +++ b/drivers/acpi/acpica/rslist.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c index eab4483ff5f8..c6b80862030e 100644 --- a/drivers/acpi/acpica/rsmemory.c +++ b/drivers/acpi/acpica/rsmemory.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index 41eea4bc089c..1fe49d223663 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c index 9e8407223d95..4c8c6fe6ea74 100644 --- a/drivers/acpi/acpica/rsserial.c +++ b/drivers/acpi/acpica/rsserial.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c index 897a5ceb0420..ece3cd60cc6a 100644 --- a/drivers/acpi/acpica/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 877ab9202133..8e6276df0226 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -60,11 +60,11 @@ ACPI_MODULE_NAME("rsxface") ACPI_COPY_FIELD(out, in, min_address_fixed); \ ACPI_COPY_FIELD(out, in, max_address_fixed); \ ACPI_COPY_FIELD(out, in, info); \ - ACPI_COPY_FIELD(out, in, granularity); \ - ACPI_COPY_FIELD(out, in, minimum); \ - ACPI_COPY_FIELD(out, in, maximum); \ - ACPI_COPY_FIELD(out, in, translation_offset); \ - ACPI_COPY_FIELD(out, in, address_length); \ + ACPI_COPY_FIELD(out, in, address.granularity); \ + ACPI_COPY_FIELD(out, in, address.minimum); \ + ACPI_COPY_FIELD(out, in, address.maximum); \ + ACPI_COPY_FIELD(out, in, address.translation_offset); \ + ACPI_COPY_FIELD(out, in, address.address_length); \ ACPI_COPY_FIELD(out, in, resource_source); /* Local prototypes */ static acpi_status diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index f499c10ceb4a..6a144957aadd 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 41519a958083..7d2486005e3f 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index cb947700206c..0b879fcfef67 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 755b90c40ddf..9bad45e63a45 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c index df3bb20ea325..ef16c06e5091 100644 --- a/drivers/acpi/acpica/tbprint.c +++ b/drivers/acpi/acpica/tbprint.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 6b1ca9991b90..6559a58439c5 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 6482b0ded652..60e94f87f27a 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -263,45 +263,6 @@ acpi_get_table_header(char *signature, ACPI_EXPORT_SYMBOL(acpi_get_table_header) -/******************************************************************************* - * - * FUNCTION: acpi_unload_table_id - * - * PARAMETERS: id - Owner ID of the table to be removed. - * - * RETURN: Status - * - * DESCRIPTION: This routine is used to force the unload of a table (by id) - * - ******************************************************************************/ -acpi_status acpi_unload_table_id(acpi_owner_id id) -{ - int i; - acpi_status status = AE_NOT_EXIST; - - ACPI_FUNCTION_TRACE(acpi_unload_table_id); - - /* Find table in the global table list */ - for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { - if (id != acpi_gbl_root_table_list.tables[i].owner_id) { - continue; - } - /* - * Delete all namespace objects owned by this table. Note that these - * objects can appear anywhere in the namespace by virtue of the AML - * "Scope" operator. Thus, we need to track ownership by an ID, not - * simply a position within the hierarchy - */ - acpi_tb_delete_namespace_by_owner(i); - status = acpi_tb_release_owner_id(i); - acpi_tb_set_table_loaded_flag(i, FALSE); - break; - } - return_ACPI_STATUS(status); -} - -ACPI_EXPORT_SYMBOL(acpi_unload_table_id) - /******************************************************************************* * * FUNCTION: acpi_get_table_with_size diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index ab5308b81aa8..aadb3002a2dd 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index 43a54af2b548..eac52cf14f1a 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c index a1acec9d2ef3..1279f50da757 100644 --- a/drivers/acpi/acpica/utaddress.c +++ b/drivers/acpi/acpica/utaddress.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c index efac83c606dc..61d8f6d186d1 100644 --- a/drivers/acpi/acpica/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c index 038ea887f562..242bd071f007 100644 --- a/drivers/acpi/acpica/utbuffer.c +++ b/drivers/acpi/acpica/utbuffer.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c index 78fde0aac487..eacc5eee362e 100644 --- a/drivers/acpi/acpica/utcache.c +++ b/drivers/acpi/acpica/utcache.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index ff601c0f7c7a..c37ec5035f4c 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index e516254c63b2..57078e3ea9b7 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index 40e923e675fc..988e23b7795c 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index a3516de213fa..71fce389fd48 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uterror.c b/drivers/acpi/acpica/uterror.c index 8e544d4688cd..9ef80f2828e3 100644 --- a/drivers/acpi/acpica/uterror.c +++ b/drivers/acpi/acpica/uterror.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c index 8fed1482d228..6c738fa0cd42 100644 --- a/drivers/acpi/acpica/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utexcep.c b/drivers/acpi/acpica/utexcep.c index 0403dcaabaf2..743a0ae9fb17 100644 --- a/drivers/acpi/acpica/utexcep.c +++ b/drivers/acpi/acpica/utexcep.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utfileio.c b/drivers/acpi/acpica/utfileio.c index 4e263a8cc6f0..7e1168be39fa 100644 --- a/drivers/acpi/acpica/utfileio.c +++ b/drivers/acpi/acpica/utfileio.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 77ceac715f28..5e8df9177da4 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uthex.c b/drivers/acpi/acpica/uthex.c index 9afa9441b183..aa448278ba28 100644 --- a/drivers/acpi/acpica/uthex.c +++ b/drivers/acpi/acpica/uthex.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index 4b12880e5b11..27431cfc1c44 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index 77120ec9ea86..e402e07b4846 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c index dc6e96547f18..089f78bbd59b 100644 --- a/drivers/acpi/acpica/utlock.c +++ b/drivers/acpi/acpica/utlock.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c index d44dee6ee10a..f9ff100f0159 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 2e2bb14e1099..56bbacd576f2 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 82717fff9ffc..37b8b58fcd56 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index dfa9009bfc87..7d83efe1ea29 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 685766fc6ca8..574cd3118313 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utownerid.c b/drivers/acpi/acpica/utownerid.c index 36bec57ebd23..2959217067cb 100644 --- a/drivers/acpi/acpica/utownerid.c +++ b/drivers/acpi/acpica/utownerid.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utpredef.c b/drivers/acpi/acpica/utpredef.c index db30caff130a..29e449935a82 100644 --- a/drivers/acpi/acpica/utpredef.c +++ b/drivers/acpi/acpica/utpredef.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c index 0ce3f5a0dd67..82ca9142e10d 100644 --- a/drivers/acpi/acpica/utprint.c +++ b/drivers/acpi/acpica/utprint.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index bc1ff820c7dd..b3505dbc715e 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c index 1cc97a752c15..8274cc16edc3 100644 --- a/drivers/acpi/acpica/utstate.c +++ b/drivers/acpi/acpica/utstate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index 6dc54b3c28b0..83b6c52490dc 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c index 7d0ee969d781..130dd9f96f0f 100644 --- a/drivers/acpi/acpica/uttrack.c +++ b/drivers/acpi/acpica/uttrack.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utuuid.c b/drivers/acpi/acpica/utuuid.c index 4dc33130f134..c6149a212149 100644 --- a/drivers/acpi/acpica/utuuid.c +++ b/drivers/acpi/acpica/utuuid.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index 49c873c68756..0929187bdce0 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index 88ef77f3cf88..306e785f9418 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index b1fd6886e439..083a76891889 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxfmutex.c b/drivers/acpi/acpica/utxfmutex.c index 2a0f9e04d3a4..f2606af3364c 100644 --- a/drivers/acpi/acpica/utxfmutex.c +++ b/drivers/acpi/acpica/utxfmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2014, Intel Corp. + * Copyright (C) 2000 - 2015, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index 2cd7bdd6c8b3..a85ac07f3da3 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -449,7 +449,7 @@ int apei_resources_sub(struct apei_resources *resources1, } EXPORT_SYMBOL_GPL(apei_resources_sub); -static int apei_get_nvs_callback(__u64 start, __u64 size, void *data) +static int apei_get_res_callback(__u64 start, __u64 size, void *data) { struct apei_resources *resources = data; return apei_res_add(&resources->iomem, start, size); @@ -457,7 +457,15 @@ static int apei_get_nvs_callback(__u64 start, __u64 size, void *data) static int apei_get_nvs_resources(struct apei_resources *resources) { - return acpi_nvs_for_each_region(apei_get_nvs_callback, resources); + return acpi_nvs_for_each_region(apei_get_res_callback, resources); +} + +int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size, + void *data), void *data); +static int apei_get_arch_resources(struct apei_resources *resources) + +{ + return arch_apei_filter_addr(apei_get_res_callback, resources); } /* @@ -470,7 +478,7 @@ int apei_resources_request(struct apei_resources *resources, { struct apei_res *res, *res_bak = NULL; struct resource *r; - struct apei_resources nvs_resources; + struct apei_resources nvs_resources, arch_res; int rc; rc = apei_resources_sub(resources, &apei_resources_all); @@ -485,10 +493,20 @@ int apei_resources_request(struct apei_resources *resources, apei_resources_init(&nvs_resources); rc = apei_get_nvs_resources(&nvs_resources); if (rc) - goto res_fini; + goto nvs_res_fini; rc = apei_resources_sub(resources, &nvs_resources); if (rc) - goto res_fini; + goto nvs_res_fini; + + if (arch_apei_filter_addr) { + apei_resources_init(&arch_res); + rc = apei_get_arch_resources(&arch_res); + if (rc) + goto arch_res_fini; + rc = apei_resources_sub(resources, &arch_res); + if (rc) + goto arch_res_fini; + } rc = -EINVAL; list_for_each_entry(res, &resources->iomem, list) { @@ -536,7 +554,9 @@ err_unmap_iomem: break; release_mem_region(res->start, res->end - res->start); } -res_fini: +arch_res_fini: + apei_resources_fini(&arch_res); +nvs_res_fini: apei_resources_fini(&nvs_resources); return rc; } diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index c0d44d394ca3..735db11a9b00 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -1027,7 +1027,6 @@ EXPORT_SYMBOL_GPL(acpi_subsys_freeze); static struct dev_pm_domain acpi_general_pm_domain = { .ops = { -#ifdef CONFIG_PM .runtime_suspend = acpi_subsys_runtime_suspend, .runtime_resume = acpi_subsys_runtime_resume, #ifdef CONFIG_PM_SLEEP @@ -1040,7 +1039,6 @@ static struct dev_pm_domain acpi_general_pm_domain = { .poweroff = acpi_subsys_suspend, .poweroff_late = acpi_subsys_suspend_late, .restore_early = acpi_subsys_resume_early, -#endif #endif }, }; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 1b5853f384e2..14d0c89ada2a 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1,8 +1,8 @@ /* - * ec.c - ACPI Embedded Controller Driver (v2.2) + * ec.c - ACPI Embedded Controller Driver (v3) * - * Copyright (C) 2001-2014 Intel Corporation - * Author: 2014 Lv Zheng + * Copyright (C) 2001-2015 Intel Corporation + * Author: 2014, 2015 Lv Zheng * 2006, 2007 Alexey Starikovskiy * 2006 Denis Sadykov * 2004 Luming Yu @@ -31,6 +31,7 @@ /* Uncomment next line to get verbose printout */ /* #define DEBUG */ +#define DEBUG_REF 0 #define pr_fmt(fmt) "ACPI : EC: " fmt #include @@ -71,20 +72,32 @@ enum ec_command { #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ #define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */ +#define ACPI_EC_UDELAY_POLL 1000 /* Wait 1ms for EC transaction polling */ #define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query * when trying to clear the EC */ enum { - EC_FLAGS_QUERY_PENDING, /* Query is pending */ - EC_FLAGS_GPE_STORM, /* GPE storm detected */ + EC_FLAGS_EVENT_ENABLED, /* Event is enabled */ + EC_FLAGS_EVENT_PENDING, /* Event is pending */ + EC_FLAGS_EVENT_DETECTED, /* Event is detected */ EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and * OpReg are installed */ - EC_FLAGS_BLOCKED, /* Transactions are blocked */ + EC_FLAGS_STARTED, /* Driver is started */ + EC_FLAGS_STOPPED, /* Driver is stopped */ + EC_FLAGS_COMMAND_STORM, /* GPE storms occurred to the + * current command processing */ }; #define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */ #define ACPI_EC_COMMAND_COMPLETE 0x02 /* Completed last byte */ +#define ec_debug_ref(ec, fmt, ...) \ + do { \ + if (DEBUG_REF) \ + pr_debug("%lu: " fmt, ec->reference_count, \ + ## __VA_ARGS__); \ + } while (0) + /* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */ static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY; module_param(ec_delay, uint, 0644); @@ -105,6 +118,7 @@ struct acpi_ec_query_handler { acpi_handle handle; void *data; u8 query_bit; + struct kref kref; }; struct transaction { @@ -117,8 +131,12 @@ struct transaction { u8 wlen; u8 rlen; u8 flags; + unsigned long timestamp; }; +static int acpi_ec_query(struct acpi_ec *ec, u8 *data); +static void advance_transaction(struct acpi_ec *ec); + struct acpi_ec *boot_ec, *first_ec; EXPORT_SYMBOL(first_ec); @@ -129,7 +147,28 @@ static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ /* -------------------------------------------------------------------------- - * Transaction Management + * Device Flags + * -------------------------------------------------------------------------- */ + +static bool acpi_ec_started(struct acpi_ec *ec) +{ + return test_bit(EC_FLAGS_STARTED, &ec->flags) && + !test_bit(EC_FLAGS_STOPPED, &ec->flags); +} + +static bool acpi_ec_flushed(struct acpi_ec *ec) +{ + return ec->reference_count == 1; +} + +static bool acpi_ec_has_pending_event(struct acpi_ec *ec) +{ + return test_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags) || + test_bit(EC_FLAGS_EVENT_PENDING, &ec->flags); +} + +/* -------------------------------------------------------------------------- + * EC Registers * -------------------------------------------------------------------------- */ static inline u8 acpi_ec_read_status(struct acpi_ec *ec) @@ -151,6 +190,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec) { u8 x = inb(ec->data_addr); + ec->curr->timestamp = jiffies; pr_debug("EC_DATA(R) = 0x%2.2x\n", x); return x; } @@ -159,12 +199,14 @@ static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) { pr_debug("EC_SC(W) = 0x%2.2x\n", command); outb(command, ec->command_addr); + ec->curr->timestamp = jiffies; } static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) { pr_debug("EC_DATA(W) = 0x%2.2x\n", data); outb(data, ec->data_addr); + ec->curr->timestamp = jiffies; } #ifdef DEBUG @@ -188,6 +230,203 @@ static const char *acpi_ec_cmd_string(u8 cmd) #define acpi_ec_cmd_string(cmd) "UNDEF" #endif +/* -------------------------------------------------------------------------- + * GPE Registers + * -------------------------------------------------------------------------- */ + +static inline bool acpi_ec_is_gpe_raised(struct acpi_ec *ec) +{ + acpi_event_status gpe_status = 0; + + (void)acpi_get_gpe_status(NULL, ec->gpe, &gpe_status); + return (gpe_status & ACPI_EVENT_FLAG_SET) ? true : false; +} + +static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open) +{ + if (open) + acpi_enable_gpe(NULL, ec->gpe); + else { + BUG_ON(ec->reference_count < 1); + acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE); + } + if (acpi_ec_is_gpe_raised(ec)) { + /* + * On some platforms, EN=1 writes cannot trigger GPE. So + * software need to manually trigger a pseudo GPE event on + * EN=1 writes. + */ + pr_debug("***** Polling quirk *****\n"); + advance_transaction(ec); + } +} + +static inline void acpi_ec_disable_gpe(struct acpi_ec *ec, bool close) +{ + if (close) + acpi_disable_gpe(NULL, ec->gpe); + else { + BUG_ON(ec->reference_count < 1); + acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE); + } +} + +static inline void acpi_ec_clear_gpe(struct acpi_ec *ec) +{ + /* + * GPE STS is a W1C register, which means: + * 1. Software can clear it without worrying about clearing other + * GPEs' STS bits when the hardware sets them in parallel. + * 2. As long as software can ensure only clearing it when it is + * set, hardware won't set it in parallel. + * So software can clear GPE in any contexts. + * Warning: do not move the check into advance_transaction() as the + * EC commands will be sent without GPE raised. + */ + if (!acpi_ec_is_gpe_raised(ec)) + return; + acpi_clear_gpe(NULL, ec->gpe); +} + +/* -------------------------------------------------------------------------- + * Transaction Management + * -------------------------------------------------------------------------- */ + +static void acpi_ec_submit_request(struct acpi_ec *ec) +{ + ec->reference_count++; + if (ec->reference_count == 1) + acpi_ec_enable_gpe(ec, true); +} + +static void acpi_ec_complete_request(struct acpi_ec *ec) +{ + bool flushed = false; + + ec->reference_count--; + if (ec->reference_count == 0) + acpi_ec_disable_gpe(ec, true); + flushed = acpi_ec_flushed(ec); + if (flushed) + wake_up(&ec->wait); +} + +static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag) +{ + if (!test_bit(flag, &ec->flags)) { + acpi_ec_disable_gpe(ec, false); + pr_debug("+++++ Polling enabled +++++\n"); + set_bit(flag, &ec->flags); + } +} + +static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag) +{ + if (test_bit(flag, &ec->flags)) { + clear_bit(flag, &ec->flags); + acpi_ec_enable_gpe(ec, false); + pr_debug("+++++ Polling disabled +++++\n"); + } +} + +/* + * acpi_ec_submit_flushable_request() - Increase the reference count unless + * the flush operation is not in + * progress + * @ec: the EC device + * @allow_event: whether event should be handled + * + * This function must be used before taking a new action that should hold + * the reference count. If this function returns false, then the action + * must be discarded or it will prevent the flush operation from being + * completed. + * + * During flushing, QR_EC command need to pass this check when there is a + * pending event, so that the reference count held for the pending event + * can be decreased by the completion of the QR_EC command. + */ +static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec, + bool allow_event) +{ + if (!acpi_ec_started(ec)) { + if (!allow_event || !acpi_ec_has_pending_event(ec)) + return false; + } + acpi_ec_submit_request(ec); + return true; +} + +static void acpi_ec_submit_event(struct acpi_ec *ec) +{ + if (!test_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags) || + !test_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags)) + return; + /* Hold reference for pending event */ + if (!acpi_ec_submit_flushable_request(ec, true)) + return; + ec_debug_ref(ec, "Increase event\n"); + if (!test_and_set_bit(EC_FLAGS_EVENT_PENDING, &ec->flags)) { + pr_debug("***** Event query started *****\n"); + schedule_work(&ec->work); + return; + } + acpi_ec_complete_request(ec); + ec_debug_ref(ec, "Decrease event\n"); +} + +static void acpi_ec_complete_event(struct acpi_ec *ec) +{ + if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { + clear_bit(EC_FLAGS_EVENT_PENDING, &ec->flags); + pr_debug("***** Event query stopped *****\n"); + /* Unhold reference for pending event */ + acpi_ec_complete_request(ec); + ec_debug_ref(ec, "Decrease event\n"); + /* Check if there is another SCI_EVT detected */ + acpi_ec_submit_event(ec); + } +} + +static void acpi_ec_submit_detection(struct acpi_ec *ec) +{ + /* Hold reference for query submission */ + if (!acpi_ec_submit_flushable_request(ec, false)) + return; + ec_debug_ref(ec, "Increase query\n"); + if (!test_and_set_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags)) { + pr_debug("***** Event detection blocked *****\n"); + acpi_ec_submit_event(ec); + return; + } + acpi_ec_complete_request(ec); + ec_debug_ref(ec, "Decrease query\n"); +} + +static void acpi_ec_complete_detection(struct acpi_ec *ec) +{ + if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { + clear_bit(EC_FLAGS_EVENT_DETECTED, &ec->flags); + pr_debug("***** Event detetion unblocked *****\n"); + /* Unhold reference for query submission */ + acpi_ec_complete_request(ec); + ec_debug_ref(ec, "Decrease query\n"); + } +} + +static void acpi_ec_enable_event(struct acpi_ec *ec) +{ + unsigned long flags; + + spin_lock_irqsave(&ec->lock, flags); + set_bit(EC_FLAGS_EVENT_ENABLED, &ec->flags); + /* + * An event may be pending even with SCI_EVT=0, so QR_EC should + * always be issued right after started. + */ + acpi_ec_submit_detection(ec); + spin_unlock_irqrestore(&ec->lock, flags); +} + static int ec_transaction_completed(struct acpi_ec *ec) { unsigned long flags; @@ -200,7 +439,7 @@ static int ec_transaction_completed(struct acpi_ec *ec) return ret; } -static bool advance_transaction(struct acpi_ec *ec) +static void advance_transaction(struct acpi_ec *ec) { struct transaction *t; u8 status; @@ -208,6 +447,12 @@ static bool advance_transaction(struct acpi_ec *ec) pr_debug("===== %s (%d) =====\n", in_interrupt() ? "IRQ" : "TASK", smp_processor_id()); + /* + * By always clearing STS before handling all indications, we can + * ensure a hardware STS 0->1 change after this clearing can always + * trigger a GPE interrupt. + */ + acpi_ec_clear_gpe(ec); status = acpi_ec_read_status(ec); t = ec->curr; if (!t) @@ -223,6 +468,7 @@ static bool advance_transaction(struct acpi_ec *ec) t->rdata[t->ri++] = acpi_ec_read_data(ec); if (t->rlen == t->ri) { t->flags |= ACPI_EC_COMMAND_COMPLETE; + acpi_ec_complete_event(ec); if (t->command == ACPI_EC_COMMAND_QUERY) pr_debug("***** Command(%s) hardware completion *****\n", acpi_ec_cmd_string(t->command)); @@ -233,25 +479,29 @@ static bool advance_transaction(struct acpi_ec *ec) } else if (t->wlen == t->wi && (status & ACPI_EC_FLAG_IBF) == 0) { t->flags |= ACPI_EC_COMMAND_COMPLETE; + acpi_ec_complete_event(ec); wakeup = true; } - return wakeup; + goto out; } else { if (EC_FLAGS_QUERY_HANDSHAKE && !(status & ACPI_EC_FLAG_SCI) && (t->command == ACPI_EC_COMMAND_QUERY)) { t->flags |= ACPI_EC_COMMAND_POLL; + acpi_ec_complete_detection(ec); t->rdata[t->ri++] = 0x00; t->flags |= ACPI_EC_COMMAND_COMPLETE; + acpi_ec_complete_event(ec); pr_debug("***** Command(%s) software completion *****\n", acpi_ec_cmd_string(t->command)); wakeup = true; } else if ((status & ACPI_EC_FLAG_IBF) == 0) { acpi_ec_write_cmd(ec, t->command); t->flags |= ACPI_EC_COMMAND_POLL; + acpi_ec_complete_detection(ec); } else goto err; - return wakeup; + goto out; } err: /* @@ -259,28 +509,27 @@ err: * otherwise will take a not handled IRQ as a false one. */ if (!(status & ACPI_EC_FLAG_SCI)) { - if (in_interrupt() && t) - ++t->irq_count; + if (in_interrupt() && t) { + if (t->irq_count < ec_storm_threshold) + ++t->irq_count; + /* Allow triggering on 0 threshold */ + if (t->irq_count == ec_storm_threshold) + acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM); + } } - return wakeup; +out: + if (status & ACPI_EC_FLAG_SCI) + acpi_ec_submit_detection(ec); + if (wakeup && in_interrupt()) + wake_up(&ec->wait); } static void start_transaction(struct acpi_ec *ec) { ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0; ec->curr->flags = 0; - (void)advance_transaction(ec); -} - -static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data); - -static int ec_check_sci_sync(struct acpi_ec *ec, u8 state) -{ - if (state & ACPI_EC_FLAG_SCI) { - if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) - return acpi_ec_sync_query(ec, NULL); - } - return 0; + ec->curr->timestamp = jiffies; + advance_transaction(ec); } static int ec_poll(struct acpi_ec *ec) @@ -291,20 +540,25 @@ static int ec_poll(struct acpi_ec *ec) while (repeat--) { unsigned long delay = jiffies + msecs_to_jiffies(ec_delay); + unsigned long usecs = ACPI_EC_UDELAY_POLL; do { /* don't sleep with disabled interrupts */ if (EC_FLAGS_MSI || irqs_disabled()) { - udelay(ACPI_EC_MSI_UDELAY); + usecs = ACPI_EC_MSI_UDELAY; + udelay(usecs); if (ec_transaction_completed(ec)) return 0; } else { if (wait_event_timeout(ec->wait, ec_transaction_completed(ec), - msecs_to_jiffies(1))) + usecs_to_jiffies(usecs))) return 0; } spin_lock_irqsave(&ec->lock, flags); - (void)advance_transaction(ec); + if (time_after(jiffies, + ec->curr->timestamp + + usecs_to_jiffies(usecs))) + advance_transaction(ec); spin_unlock_irqrestore(&ec->lock, flags); } while (time_before(jiffies, delay)); pr_debug("controller reset, restart transaction\n"); @@ -325,21 +579,29 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, udelay(ACPI_EC_MSI_UDELAY); /* start transaction */ spin_lock_irqsave(&ec->lock, tmp); + /* Enable GPE for command processing (IBF=0/OBF=1) */ + if (!acpi_ec_submit_flushable_request(ec, true)) { + ret = -EINVAL; + goto unlock; + } + ec_debug_ref(ec, "Increase command\n"); /* following two actions should be kept atomic */ ec->curr = t; pr_debug("***** Command(%s) started *****\n", acpi_ec_cmd_string(t->command)); start_transaction(ec); - if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { - clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); - pr_debug("***** Event stopped *****\n"); - } spin_unlock_irqrestore(&ec->lock, tmp); ret = ec_poll(ec); spin_lock_irqsave(&ec->lock, tmp); + if (t->irq_count == ec_storm_threshold) + acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM); pr_debug("***** Command(%s) stopped *****\n", acpi_ec_cmd_string(t->command)); ec->curr = NULL; + /* Disable GPE for command processing (IBF=0/OBF=1) */ + acpi_ec_complete_request(ec); + ec_debug_ref(ec, "Decrease command\n"); +unlock: spin_unlock_irqrestore(&ec->lock, tmp); return ret; } @@ -354,10 +616,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) if (t->rdata) memset(t->rdata, 0, t->rlen); mutex_lock(&ec->mutex); - if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) { - status = -EINVAL; - goto unlock; - } if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); if (ACPI_FAILURE(status)) { @@ -365,26 +623,11 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) goto unlock; } } - /* disable GPE during transaction if storm is detected */ - if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { - /* It has to be disabled, so that it doesn't trigger. */ - acpi_disable_gpe(NULL, ec->gpe); - } status = acpi_ec_transaction_unlocked(ec, t); - /* check if we received SCI during transaction */ - ec_check_sci_sync(ec, acpi_ec_read_status(ec)); - if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { + if (test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags)) msleep(1); - /* It is safe to enable the GPE outside of the transaction. */ - acpi_enable_gpe(NULL, ec->gpe); - } else if (t->irq_count > ec_storm_threshold) { - pr_info("GPE storm detected(%d GPEs), " - "transactions will use polling mode\n", - t->irq_count); - set_bit(EC_FLAGS_GPE_STORM, &ec->flags); - } if (ec->global_lock) acpi_release_global_lock(glk); unlock: @@ -500,7 +743,7 @@ static void acpi_ec_clear(struct acpi_ec *ec) u8 value = 0; for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { - status = acpi_ec_sync_query(ec, &value); + status = acpi_ec_query(ec, &value); if (status || !value) break; } @@ -511,6 +754,57 @@ static void acpi_ec_clear(struct acpi_ec *ec) pr_info("%d stale EC events cleared\n", i); } +static void acpi_ec_start(struct acpi_ec *ec, bool resuming) +{ + unsigned long flags; + + spin_lock_irqsave(&ec->lock, flags); + if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) { + pr_debug("+++++ Starting EC +++++\n"); + /* Enable GPE for event processing (SCI_EVT=1) */ + if (!resuming) { + acpi_ec_submit_request(ec); + ec_debug_ref(ec, "Increase driver\n"); + } + pr_info("+++++ EC started +++++\n"); + } + spin_unlock_irqrestore(&ec->lock, flags); +} + +static bool acpi_ec_stopped(struct acpi_ec *ec) +{ + unsigned long flags; + bool flushed; + + spin_lock_irqsave(&ec->lock, flags); + flushed = acpi_ec_flushed(ec); + spin_unlock_irqrestore(&ec->lock, flags); + return flushed; +} + +static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) +{ + unsigned long flags; + + spin_lock_irqsave(&ec->lock, flags); + if (acpi_ec_started(ec)) { + pr_debug("+++++ Stopping EC +++++\n"); + set_bit(EC_FLAGS_STOPPED, &ec->flags); + spin_unlock_irqrestore(&ec->lock, flags); + wait_event(ec->wait, acpi_ec_stopped(ec)); + spin_lock_irqsave(&ec->lock, flags); + /* Disable GPE for event processing (SCI_EVT=1) */ + if (!suspending) { + acpi_ec_complete_request(ec); + ec_debug_ref(ec, "Decrease driver\n"); + } + clear_bit(EC_FLAGS_STARTED, &ec->flags); + clear_bit(EC_FLAGS_STOPPED, &ec->flags); + pr_info("+++++ EC stopped +++++\n"); + } + spin_unlock_irqrestore(&ec->lock, flags); +} + void acpi_ec_block_transactions(void) { struct acpi_ec *ec = first_ec; @@ -520,7 +814,7 @@ void acpi_ec_block_transactions(void) mutex_lock(&ec->mutex); /* Prevent transactions from being carried out */ - set_bit(EC_FLAGS_BLOCKED, &ec->flags); + acpi_ec_stop(ec, true); mutex_unlock(&ec->mutex); } @@ -531,14 +825,11 @@ void acpi_ec_unblock_transactions(void) if (!ec) return; - mutex_lock(&ec->mutex); /* Allow transactions to be carried out again */ - clear_bit(EC_FLAGS_BLOCKED, &ec->flags); + acpi_ec_start(ec, true); if (EC_FLAGS_CLEAR_ON_RESUME) acpi_ec_clear(ec); - - mutex_unlock(&ec->mutex); } void acpi_ec_unblock_transactions_early(void) @@ -548,36 +839,33 @@ void acpi_ec_unblock_transactions_early(void) * atomic context during wakeup, so we don't need to acquire the mutex). */ if (first_ec) - clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags); -} - -static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data) -{ - int result; - u8 d; - struct transaction t = {.command = ACPI_EC_COMMAND_QUERY, - .wdata = NULL, .rdata = &d, - .wlen = 0, .rlen = 1}; - - if (!ec || !data) - return -EINVAL; - /* - * Query the EC to find out which _Qxx method we need to evaluate. - * Note that successful completion of the query causes the ACPI_EC_SCI - * bit to be cleared (and thus clearing the interrupt source). - */ - result = acpi_ec_transaction_unlocked(ec, &t); - if (result) - return result; - if (!d) - return -ENODATA; - *data = d; - return 0; + acpi_ec_start(first_ec, true); } /* -------------------------------------------------------------------------- Event Management -------------------------------------------------------------------------- */ +static struct acpi_ec_query_handler * +acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler) +{ + if (handler) + kref_get(&handler->kref); + return handler; +} + +static void acpi_ec_query_handler_release(struct kref *kref) +{ + struct acpi_ec_query_handler *handler = + container_of(kref, struct acpi_ec_query_handler, kref); + + kfree(handler); +} + +static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler) +{ + kref_put(&handler->kref, acpi_ec_query_handler_release); +} + int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, acpi_handle handle, acpi_ec_query_func func, void *data) @@ -593,6 +881,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, handler->func = func; handler->data = data; mutex_lock(&ec->mutex); + kref_init(&handler->kref); list_add(&handler->node, &ec->list); mutex_unlock(&ec->mutex); return 0; @@ -602,15 +891,18 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) { struct acpi_ec_query_handler *handler, *tmp; + LIST_HEAD(free_list); mutex_lock(&ec->mutex); list_for_each_entry_safe(handler, tmp, &ec->list, node) { if (query_bit == handler->query_bit) { - list_del(&handler->node); - kfree(handler); + list_del_init(&handler->node); + list_add(&handler->node, &free_list); } } mutex_unlock(&ec->mutex); + list_for_each_entry(handler, &free_list, node) + acpi_ec_put_query_handler(handler); } EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); @@ -626,59 +918,58 @@ static void acpi_ec_run(void *cxt) else if (handler->handle) acpi_evaluate_object(handler->handle, NULL, NULL, NULL); pr_debug("##### Query(0x%02x) stopped #####\n", handler->query_bit); - kfree(handler); + acpi_ec_put_query_handler(handler); } -static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) +static int acpi_ec_query(struct acpi_ec *ec, u8 *data) { u8 value = 0; - int status; - struct acpi_ec_query_handler *handler, *copy; + int result; + acpi_status status; + struct acpi_ec_query_handler *handler; + struct transaction t = {.command = ACPI_EC_COMMAND_QUERY, + .wdata = NULL, .rdata = &value, + .wlen = 0, .rlen = 1}; - status = acpi_ec_query_unlocked(ec, &value); + /* + * Query the EC to find out which _Qxx method we need to evaluate. + * Note that successful completion of the query causes the ACPI_EC_SCI + * bit to be cleared (and thus clearing the interrupt source). + */ + result = acpi_ec_transaction(ec, &t); + if (result) + return result; if (data) *data = value; - if (status) - return status; + if (!value) + return -ENODATA; + mutex_lock(&ec->mutex); list_for_each_entry(handler, &ec->list, node) { if (value == handler->query_bit) { /* have custom handler for this bit */ - copy = kmalloc(sizeof(*handler), GFP_KERNEL); - if (!copy) - return -ENOMEM; - memcpy(copy, handler, sizeof(*copy)); + handler = acpi_ec_get_query_handler(handler); pr_debug("##### Query(0x%02x) scheduled #####\n", handler->query_bit); - return acpi_os_execute((copy->func) ? + status = acpi_os_execute((handler->func) ? OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER, - acpi_ec_run, copy); + acpi_ec_run, handler); + if (ACPI_FAILURE(status)) + result = -EBUSY; + break; } } - return 0; -} - -static void acpi_ec_gpe_query(void *ec_cxt) -{ - struct acpi_ec *ec = ec_cxt; - - if (!ec) - return; - mutex_lock(&ec->mutex); - acpi_ec_sync_query(ec, NULL); mutex_unlock(&ec->mutex); + return result; } -static int ec_check_sci(struct acpi_ec *ec, u8 state) +static void acpi_ec_gpe_poller(struct work_struct *work) { - if (state & ACPI_EC_FLAG_SCI) { - if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { - pr_debug("***** Event started *****\n"); - return acpi_os_execute(OSL_NOTIFY_HANDLER, - acpi_ec_gpe_query, ec); - } - } - return 0; + struct acpi_ec *ec = container_of(work, struct acpi_ec, work); + + pr_debug("***** Event poller started *****\n"); + acpi_ec_query(ec, NULL); + pr_debug("***** Event poller stopped *****\n"); } static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, @@ -688,11 +979,9 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, struct acpi_ec *ec = data; spin_lock_irqsave(&ec->lock, flags); - if (advance_transaction(ec)) - wake_up(&ec->wait); + advance_transaction(ec); spin_unlock_irqrestore(&ec->lock, flags); - ec_check_sci(ec, acpi_ec_read_status(ec)); - return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE; + return ACPI_INTERRUPT_HANDLED; } /* -------------------------------------------------------------------------- @@ -750,11 +1039,11 @@ static struct acpi_ec *make_acpi_ec(void) if (!ec) return NULL; - ec->flags = 1 << EC_FLAGS_QUERY_PENDING; mutex_init(&ec->mutex); init_waitqueue_head(&ec->wait); INIT_LIST_HEAD(&ec->list); spin_lock_init(&ec->lock); + INIT_WORK(&ec->work, acpi_ec_gpe_poller); return ec; } @@ -810,13 +1099,13 @@ static int ec_install_handlers(struct acpi_ec *ec) if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) return 0; - status = acpi_install_gpe_handler(NULL, ec->gpe, + status = acpi_install_gpe_raw_handler(NULL, ec->gpe, ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec); if (ACPI_FAILURE(status)) return -ENODEV; - acpi_enable_gpe(NULL, ec->gpe); + acpi_ec_start(ec, false); status = acpi_install_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, @@ -831,7 +1120,7 @@ static int ec_install_handlers(struct acpi_ec *ec) pr_err("Fail in evaluating the _REG object" " of EC device. Broken bios is suspected.\n"); } else { - acpi_disable_gpe(NULL, ec->gpe); + acpi_ec_stop(ec, false); acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); return -ENODEV; @@ -846,7 +1135,7 @@ static void ec_remove_handlers(struct acpi_ec *ec) { if (!test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) return; - acpi_disable_gpe(NULL, ec->gpe); + acpi_ec_stop(ec, false); if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) pr_err("failed to remove space handler\n"); @@ -900,14 +1189,11 @@ static int acpi_ec_add(struct acpi_device *device) ret = ec_install_handlers(ec); /* EC is fully operational, allow queries */ - clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); + acpi_ec_enable_event(ec); /* Clear stale _Q events if hardware might require that */ - if (EC_FLAGS_CLEAR_ON_RESUME) { - mutex_lock(&ec->mutex); + if (EC_FLAGS_CLEAR_ON_RESUME) acpi_ec_clear(ec); - mutex_unlock(&ec->mutex); - } return ret; } diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index ef2d730734dc..e24ea4e796e4 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -100,7 +100,6 @@ int acpi_bus_generate_netlink_event(const char *device_class, struct acpi_genl_event *event; void *msg_header; int size; - int result; /* allocate memory */ size = nla_total_size(sizeof(struct acpi_genl_event)) + @@ -137,11 +136,7 @@ int acpi_bus_generate_netlink_event(const char *device_class, event->data = data; /* send multicast genetlink message */ - result = genlmsg_end(skb, msg_header); - if (result < 0) { - nlmsg_free(skb); - return result; - } + genlmsg_end(skb, msg_header); genlmsg_multicast(&acpi_event_genl_family, skb, 0, 0, GFP_ATOMIC); return 0; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 163e82f536fa..56b321aa2b1c 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -35,6 +35,13 @@ void acpi_int340x_thermal_init(void); int acpi_sysfs_init(void); void acpi_container_init(void); void acpi_memory_hotplug_init(void); +#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC +int acpi_ioapic_add(struct acpi_pci_root *root); +int acpi_ioapic_remove(struct acpi_pci_root *root); +#else +static inline int acpi_ioapic_add(struct acpi_pci_root *root) { return 0; } +static inline int acpi_ioapic_remove(struct acpi_pci_root *root) { return 0; } +#endif #ifdef CONFIG_ACPI_DOCK void register_dock_dependent_device(struct acpi_device *adev, acpi_handle dshandle); @@ -68,6 +75,8 @@ static inline void acpi_debugfs_init(void) { return; } #endif void acpi_lpss_init(void); +void acpi_apd_init(void); + acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src); bool acpi_queue_hotplug_work(struct work_struct *work); void acpi_device_hotplug(struct acpi_device *adev, u32 src); @@ -122,11 +131,13 @@ struct acpi_ec { unsigned long data_addr; unsigned long global_lock; unsigned long flags; + unsigned long reference_count; struct mutex mutex; wait_queue_head_t wait; struct list_head list; struct transaction *curr; spinlock_t lock; + struct work_struct work; }; extern struct acpi_ec *first_ec; diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c new file mode 100644 index 000000000000..ccdc8db16bb8 --- /dev/null +++ b/drivers/acpi/ioapic.c @@ -0,0 +1,229 @@ +/* + * IOAPIC/IOxAPIC/IOSAPIC driver + * + * Copyright (C) 2009 Fujitsu Limited. + * (c) Copyright 2009 Hewlett-Packard Development Company, L.P. + * + * Copyright (C) 2014 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Based on original drivers/pci/ioapic.c + * Yinghai Lu + * Jiang Liu + */ + +/* + * This driver manages I/O APICs added by hotplug after boot. + * We try to claim all I/O APIC devices, but those present at boot were + * registered when we parsed the ACPI MADT. + */ + +#define pr_fmt(fmt) "ACPI : IOAPIC: " fmt + +#include +#include +#include +#include + +struct acpi_pci_ioapic { + acpi_handle root_handle; + acpi_handle handle; + u32 gsi_base; + struct resource res; + struct pci_dev *pdev; + struct list_head list; +}; + +static LIST_HEAD(ioapic_list); +static DEFINE_MUTEX(ioapic_list_lock); + +static acpi_status setup_res(struct acpi_resource *acpi_res, void *data) +{ + struct resource *res = data; + struct resource_win win; + + res->flags = 0; + if (acpi_dev_filter_resource_type(acpi_res, IORESOURCE_MEM) == 0) + return AE_OK; + + if (!acpi_dev_resource_memory(acpi_res, res)) { + if (acpi_dev_resource_address_space(acpi_res, &win) || + acpi_dev_resource_ext_address_space(acpi_res, &win)) + *res = win.res; + } + if ((res->flags & IORESOURCE_PREFETCH) || + (res->flags & IORESOURCE_DISABLED)) + res->flags = 0; + + return AE_CTRL_TERMINATE; +} + +static bool acpi_is_ioapic(acpi_handle handle, char **type) +{ + acpi_status status; + struct acpi_device_info *info; + char *hid = NULL; + bool match = false; + + if (!acpi_has_method(handle, "_GSB")) + return false; + + status = acpi_get_object_info(handle, &info); + if (ACPI_SUCCESS(status)) { + if (info->valid & ACPI_VALID_HID) + hid = info->hardware_id.string; + if (hid) { + if (strcmp(hid, "ACPI0009") == 0) { + *type = "IOxAPIC"; + match = true; + } else if (strcmp(hid, "ACPI000A") == 0) { + *type = "IOAPIC"; + match = true; + } + } + kfree(info); + } + + return match; +} + +static acpi_status handle_ioapic_add(acpi_handle handle, u32 lvl, + void *context, void **rv) +{ + acpi_status status; + unsigned long long gsi_base; + struct acpi_pci_ioapic *ioapic; + struct pci_dev *dev = NULL; + struct resource *res = NULL; + char *type = NULL; + + if (!acpi_is_ioapic(handle, &type)) + return AE_OK; + + mutex_lock(&ioapic_list_lock); + list_for_each_entry(ioapic, &ioapic_list, list) + if (ioapic->handle == handle) { + mutex_unlock(&ioapic_list_lock); + return AE_OK; + } + + status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsi_base); + if (ACPI_FAILURE(status)) { + acpi_handle_warn(handle, "failed to evaluate _GSB method\n"); + goto exit; + } + + ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL); + if (!ioapic) { + pr_err("cannot allocate memory for new IOAPIC\n"); + goto exit; + } else { + ioapic->root_handle = (acpi_handle)context; + ioapic->handle = handle; + ioapic->gsi_base = (u32)gsi_base; + INIT_LIST_HEAD(&ioapic->list); + } + + if (acpi_ioapic_registered(handle, (u32)gsi_base)) + goto done; + + dev = acpi_get_pci_dev(handle); + if (dev && pci_resource_len(dev, 0)) { + if (pci_enable_device(dev) < 0) + goto exit_put; + pci_set_master(dev); + if (pci_request_region(dev, 0, type)) + goto exit_disable; + res = &dev->resource[0]; + ioapic->pdev = dev; + } else { + pci_dev_put(dev); + dev = NULL; + + res = &ioapic->res; + acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, res); + if (res->flags == 0) { + acpi_handle_warn(handle, "failed to get resource\n"); + goto exit_free; + } else if (request_resource(&iomem_resource, res)) { + acpi_handle_warn(handle, "failed to insert resource\n"); + goto exit_free; + } + } + + if (acpi_register_ioapic(handle, res->start, (u32)gsi_base)) { + acpi_handle_warn(handle, "failed to register IOAPIC\n"); + goto exit_release; + } +done: + list_add(&ioapic->list, &ioapic_list); + mutex_unlock(&ioapic_list_lock); + + if (dev) + dev_info(&dev->dev, "%s at %pR, GSI %u\n", + type, res, (u32)gsi_base); + else + acpi_handle_info(handle, "%s at %pR, GSI %u\n", + type, res, (u32)gsi_base); + + return AE_OK; + +exit_release: + if (dev) + pci_release_region(dev, 0); + else + release_resource(res); +exit_disable: + if (dev) + pci_disable_device(dev); +exit_put: + pci_dev_put(dev); +exit_free: + kfree(ioapic); +exit: + mutex_unlock(&ioapic_list_lock); + *(acpi_status *)rv = AE_ERROR; + return AE_OK; +} + +int acpi_ioapic_add(struct acpi_pci_root *root) +{ + acpi_status status, retval = AE_OK; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root->device->handle, + UINT_MAX, handle_ioapic_add, NULL, + root->device->handle, (void **)&retval); + + return ACPI_SUCCESS(status) && ACPI_SUCCESS(retval) ? 0 : -ENODEV; +} + +int acpi_ioapic_remove(struct acpi_pci_root *root) +{ + int retval = 0; + struct acpi_pci_ioapic *ioapic, *tmp; + + mutex_lock(&ioapic_list_lock); + list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) { + if (root->device->handle != ioapic->root_handle) + continue; + + if (acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base)) + retval = -EBUSY; + + if (ioapic->pdev) { + pci_release_region(ioapic->pdev, 0); + pci_disable_device(ioapic->pdev); + pci_dev_put(ioapic->pdev); + } else if (ioapic->res.flags && ioapic->res.parent) { + release_resource(&ioapic->res); + } + list_del(&ioapic->list); + kfree(ioapic); + } + mutex_unlock(&ioapic_list_lock); + + return retval; +} diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 24b5476449a1..1333cbdc3ea2 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -177,12 +177,7 @@ static int __init slit_valid(struct acpi_table_slit *slit) static int __init acpi_parse_slit(struct acpi_table_header *table) { - struct acpi_table_slit *slit; - - if (!table) - return -EINVAL; - - slit = (struct acpi_table_slit *)table; + struct acpi_table_slit *slit = (struct acpi_table_slit *)table; if (!slit_valid(slit)) { printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n"); @@ -260,11 +255,8 @@ acpi_parse_memory_affinity(struct acpi_subtable_header * header, static int __init acpi_parse_srat(struct acpi_table_header *table) { - struct acpi_table_srat *srat; - if (!table) - return -EINVAL; + struct acpi_table_srat *srat = (struct acpi_table_srat *)table; - srat = (struct acpi_table_srat *)table; acpi_srat_revision = srat->header.revision; /* Real work done in acpi_table_parse_srat below. */ diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 5277a0ee5704..e7f718d6918a 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -485,14 +485,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) if (!pin || !dev->irq_managed || dev->irq <= 0) return; - /* Keep IOAPIC pin configuration when suspending */ - if (dev->dev.power.is_prepared) - return; -#ifdef CONFIG_PM - if (dev->dev.power.runtime_status == RPM_SUSPENDING) - return; -#endif - entry = acpi_pci_irq_lookup(dev, pin); if (!entry) return; @@ -512,7 +504,7 @@ void acpi_pci_irq_disable(struct pci_dev *dev) dev_dbg(&dev->dev, "PCI INT %c disabled\n", pin_name(pin)); if (gsi >= 0) { acpi_unregister_gsi(gsi); - dev->irq = 0; dev->irq_managed = 0; + dev->irq = 0; } } diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index c6bcb8c719d8..68a5f712cd19 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -112,10 +112,10 @@ get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) if (ACPI_FAILURE(status)) return AE_OK; - if ((address.address_length > 0) && + if ((address.address.address_length > 0) && (address.resource_type == ACPI_BUS_NUMBER_RANGE)) { - res->start = address.minimum; - res->end = address.minimum + address.address_length - 1; + res->start = address.address.minimum; + res->end = address.address.minimum + address.address.address_length - 1; } return AE_OK; @@ -621,6 +621,7 @@ static int acpi_pci_root_add(struct acpi_device *device, if (hotadd) { pcibios_resource_survey_bus(root->bus); pci_assign_unassigned_root_bus_resources(root->bus); + acpi_ioapic_add(root); } pci_lock_rescan_remove(); @@ -644,6 +645,8 @@ static void acpi_pci_root_remove(struct acpi_device *device) pci_stop_root_bus(root->bus); + WARN_ON(acpi_ioapic_remove(root)); + device_set_run_wake(root->bus->bridge, false); pci_acpi_remove_bus_pm_notifier(device); diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 02e48394276c..7962651cdbd4 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -4,6 +4,10 @@ * * Alex Chiang * - Unified x86/ia64 implementations + * + * I/O APIC hotplug support + * Yinghai Lu + * Jiang Liu */ #include #include @@ -12,6 +16,21 @@ #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME("processor_core"); +static struct acpi_table_madt *get_madt_table(void) +{ + static struct acpi_table_madt *madt; + static int read_madt; + + if (!read_madt) { + if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, + (struct acpi_table_header **)&madt))) + madt = NULL; + read_madt++; + } + + return madt; +} + static int map_lapic_id(struct acpi_subtable_header *entry, u32 acpi_id, int *apic_id) { @@ -67,17 +86,10 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, static int map_madt_entry(int type, u32 acpi_id) { unsigned long madt_end, entry; - static struct acpi_table_madt *madt; - static int read_madt; int phys_id = -1; /* CPU hardware ID */ + struct acpi_table_madt *madt; - if (!read_madt) { - if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, - (struct acpi_table_header **)&madt))) - madt = NULL; - read_madt++; - } - + madt = get_madt_table(); if (!madt) return phys_id; @@ -203,3 +215,96 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) return acpi_map_cpuid(phys_id, acpi_id); } EXPORT_SYMBOL_GPL(acpi_get_cpuid); + +#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC +static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base, + u64 *phys_addr, int *ioapic_id) +{ + struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry; + + if (ioapic->global_irq_base != gsi_base) + return 0; + + *phys_addr = ioapic->address; + *ioapic_id = ioapic->id; + return 1; +} + +static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr) +{ + struct acpi_subtable_header *hdr; + unsigned long madt_end, entry; + struct acpi_table_madt *madt; + int apic_id = -1; + + madt = get_madt_table(); + if (!madt) + return apic_id; + + entry = (unsigned long)madt; + madt_end = entry + madt->header.length; + + /* Parse all entries looking for a match. */ + entry += sizeof(struct acpi_table_madt); + while (entry + sizeof(struct acpi_subtable_header) < madt_end) { + hdr = (struct acpi_subtable_header *)entry; + if (hdr->type == ACPI_MADT_TYPE_IO_APIC && + get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id)) + break; + else + entry += hdr->length; + } + + return apic_id; +} + +static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base, + u64 *phys_addr) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_subtable_header *header; + union acpi_object *obj; + int apic_id = -1; + + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) + goto exit; + + if (!buffer.length || !buffer.pointer) + goto exit; + + obj = buffer.pointer; + if (obj->type != ACPI_TYPE_BUFFER || + obj->buffer.length < sizeof(struct acpi_subtable_header)) + goto exit; + + header = (struct acpi_subtable_header *)obj->buffer.pointer; + if (header->type == ACPI_MADT_TYPE_IO_APIC) + get_ioapic_id(header, gsi_base, phys_addr, &apic_id); + +exit: + kfree(buffer.pointer); + return apic_id; +} + +/** + * acpi_get_ioapic_id - Get IOAPIC ID and physical address matching @gsi_base + * @handle: ACPI object for IOAPIC device + * @gsi_base: GSI base to match with + * @phys_addr: Pointer to store physical address of matching IOAPIC record + * + * Walk resources returned by ACPI_MAT method, then ACPI MADT table, to search + * for an ACPI IOAPIC record matching @gsi_base. + * Return IOAPIC id and store physical address in @phys_addr if found a match, + * otherwise return <0. + */ +int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr) +{ + int apic_id; + + apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr); + if (apic_id == -1) + apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr); + + return apic_id; +} +#endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */ diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 87b704e41877..c256bd7fbd78 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -681,15 +681,13 @@ static int acpi_idle_bm_check(void) } /** - * acpi_idle_do_entry - a helper function that does C2 and C3 type entry + * acpi_idle_do_entry - enter idle state using the appropriate method * @cx: cstate data * * Caller disables interrupt before call and enables interrupt after return. */ -static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) +static void acpi_idle_do_entry(struct acpi_processor_cx *cx) { - /* Don't trace irqs off for idle */ - stop_critical_timings(); if (cx->entry_method == ACPI_CSTATE_FFH) { /* Call into architectural FFH based C-state */ acpi_processor_ffh_cstate_enter(cx); @@ -703,37 +701,8 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) gets asserted in time to freeze execution properly. */ inl(acpi_gbl_FADT.xpm_timer_block.address); } - start_critical_timings(); } -/** - * acpi_idle_enter_c1 - enters an ACPI C1 state-type - * @dev: the target CPU - * @drv: cpuidle driver containing cpuidle state info - * @index: index of target state - * - * This is equivalent to the HALT instruction. - */ -static int acpi_idle_enter_c1(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int index) -{ - struct acpi_processor *pr; - struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); - - pr = __this_cpu_read(processors); - - if (unlikely(!pr)) - return -EINVAL; - - lapic_timer_state_broadcast(pr, cx, 1); - acpi_idle_do_entry(cx); - - lapic_timer_state_broadcast(pr, cx, 0); - - return index; -} - - /** * acpi_idle_play_dead - enters an ACPI state for long-term idle (i.e. off-lining) * @dev: the target CPU @@ -761,47 +730,11 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) return 0; } -/** - * acpi_idle_enter_simple - enters an ACPI state without BM handling - * @dev: the target CPU - * @drv: cpuidle driver with cpuidle state information - * @index: the index of suggested state - */ -static int acpi_idle_enter_simple(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int index) +static bool acpi_idle_fallback_to_c1(struct acpi_processor *pr) { - struct acpi_processor *pr; - struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); - - pr = __this_cpu_read(processors); - - if (unlikely(!pr)) - return -EINVAL; - -#ifdef CONFIG_HOTPLUG_CPU - if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && - !pr->flags.has_cst && - !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) - return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START); -#endif - - /* - * Must be done before busmaster disable as we might need to - * access HPET ! - */ - lapic_timer_state_broadcast(pr, cx, 1); - - if (cx->type == ACPI_STATE_C3) - ACPI_FLUSH_CPU_CACHE(); - - /* Tell the scheduler that we are going deep-idle: */ - sched_clock_idle_sleep_event(); - acpi_idle_do_entry(cx); - - sched_clock_idle_wakeup_event(0); - - lapic_timer_state_broadcast(pr, cx, 0); - return index; + return IS_ENABLED(CONFIG_HOTPLUG_CPU) && num_online_cpus() > 1 && + !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED) && + !pr->flags.has_cst; } static int c3_cpu_count; @@ -809,44 +742,14 @@ static DEFINE_RAW_SPINLOCK(c3_lock); /** * acpi_idle_enter_bm - enters C3 with proper BM handling - * @dev: the target CPU - * @drv: cpuidle driver containing state data - * @index: the index of suggested state - * - * If BM is detected, the deepest non-C3 idle state is entered instead. + * @pr: Target processor + * @cx: Target state context */ -static int acpi_idle_enter_bm(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int index) +static void acpi_idle_enter_bm(struct acpi_processor *pr, + struct acpi_processor_cx *cx) { - struct acpi_processor *pr; - struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); - - pr = __this_cpu_read(processors); - - if (unlikely(!pr)) - return -EINVAL; - -#ifdef CONFIG_HOTPLUG_CPU - if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && - !pr->flags.has_cst && - !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) - return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START); -#endif - - if (!cx->bm_sts_skip && acpi_idle_bm_check()) { - if (drv->safe_state_index >= 0) { - return drv->states[drv->safe_state_index].enter(dev, - drv, drv->safe_state_index); - } else { - acpi_safe_halt(); - return -EBUSY; - } - } - acpi_unlazy_tlb(smp_processor_id()); - /* Tell the scheduler that we are going deep-idle: */ - sched_clock_idle_sleep_event(); /* * Must be done before busmaster disable as we might need to * access HPET ! @@ -856,37 +759,71 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, /* * disable bus master * bm_check implies we need ARB_DIS - * !bm_check implies we need cache flush * bm_control implies whether we can do ARB_DIS * * That leaves a case where bm_check is set and bm_control is * not set. In that case we cannot do much, we enter C3 * without doing anything. */ - if (pr->flags.bm_check && pr->flags.bm_control) { + if (pr->flags.bm_control) { raw_spin_lock(&c3_lock); c3_cpu_count++; /* Disable bus master arbitration when all CPUs are in C3 */ if (c3_cpu_count == num_online_cpus()) acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1); raw_spin_unlock(&c3_lock); - } else if (!pr->flags.bm_check) { - ACPI_FLUSH_CPU_CACHE(); } acpi_idle_do_entry(cx); /* Re-enable bus master arbitration */ - if (pr->flags.bm_check && pr->flags.bm_control) { + if (pr->flags.bm_control) { raw_spin_lock(&c3_lock); acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0); c3_cpu_count--; raw_spin_unlock(&c3_lock); } - sched_clock_idle_wakeup_event(0); + lapic_timer_state_broadcast(pr, cx, 0); +} + +static int acpi_idle_enter(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); + struct acpi_processor *pr; + + pr = __this_cpu_read(processors); + if (unlikely(!pr)) + return -EINVAL; + + if (cx->type != ACPI_STATE_C1) { + if (acpi_idle_fallback_to_c1(pr)) { + index = CPUIDLE_DRIVER_STATE_START; + cx = per_cpu(acpi_cstate[index], dev->cpu); + } else if (cx->type == ACPI_STATE_C3 && pr->flags.bm_check) { + if (cx->bm_sts_skip || !acpi_idle_bm_check()) { + acpi_idle_enter_bm(pr, cx); + return index; + } else if (drv->safe_state_index >= 0) { + index = drv->safe_state_index; + cx = per_cpu(acpi_cstate[index], dev->cpu); + } else { + acpi_safe_halt(); + return -EBUSY; + } + } + } + + lapic_timer_state_broadcast(pr, cx, 1); + + if (cx->type == ACPI_STATE_C3) + ACPI_FLUSH_CPU_CACHE(); + + acpi_idle_do_entry(cx); lapic_timer_state_broadcast(pr, cx, 0); + return index; } @@ -981,27 +918,12 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); state->exit_latency = cx->latency; state->target_residency = cx->latency * latency_factor; + state->enter = acpi_idle_enter; state->flags = 0; - switch (cx->type) { - case ACPI_STATE_C1: - - state->enter = acpi_idle_enter_c1; + if (cx->type == ACPI_STATE_C1 || cx->type == ACPI_STATE_C2) { state->enter_dead = acpi_idle_play_dead; drv->safe_state_index = count; - break; - - case ACPI_STATE_C2: - state->enter = acpi_idle_enter_simple; - state->enter_dead = acpi_idle_play_dead; - drv->safe_state_index = count; - break; - - case ACPI_STATE_C3: - state->enter = pr->flags.bm_check ? - acpi_idle_enter_bm : - acpi_idle_enter_simple; - break; } count++; diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 782a0d15c25f..4752b9939987 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -34,21 +34,34 @@ #define valid_IRQ(i) (true) #endif -static unsigned long acpi_dev_memresource_flags(u64 len, u8 write_protect, - bool window) +static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io) { - unsigned long flags = IORESOURCE_MEM; + u64 reslen = end - start + 1; - if (len == 0) - flags |= IORESOURCE_DISABLED; + /* + * CHECKME: len might be required to check versus a minimum + * length as well. 1 for io is fine, but for memory it does + * not make any sense at all. + */ + if (len && reslen && reslen == len && start <= end) + return true; + + pr_info("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]\n", + io ? "io" : "mem", start, end, len); + + return false; +} + +static void acpi_dev_memresource_flags(struct resource *res, u64 len, + u8 write_protect) +{ + res->flags = IORESOURCE_MEM; + + if (!acpi_dev_resource_len_valid(res->start, res->end, len, false)) + res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; if (write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; - - if (window) - flags |= IORESOURCE_WINDOW; - - return flags; + res->flags |= IORESOURCE_MEM_WRITEABLE; } static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, @@ -56,7 +69,7 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, { res->start = start; res->end = start + len - 1; - res->flags = acpi_dev_memresource_flags(len, write_protect, false); + acpi_dev_memresource_flags(res, len, write_protect); } /** @@ -67,6 +80,11 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, * Check if the given ACPI resource object represents a memory resource and * if that's the case, use the information in it to populate the generic * resource object pointed to by @res. + * + * Return: + * 1) false with res->flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 3) true: valid assigned resource */ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) { @@ -77,60 +95,52 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) switch (ares->type) { case ACPI_RESOURCE_TYPE_MEMORY24: memory24 = &ares->data.memory24; - if (!memory24->minimum && !memory24->address_length) - return false; - acpi_dev_get_memresource(res, memory24->minimum, - memory24->address_length, + acpi_dev_get_memresource(res, memory24->minimum << 8, + memory24->address_length << 8, memory24->write_protect); break; case ACPI_RESOURCE_TYPE_MEMORY32: memory32 = &ares->data.memory32; - if (!memory32->minimum && !memory32->address_length) - return false; acpi_dev_get_memresource(res, memory32->minimum, memory32->address_length, memory32->write_protect); break; case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: fixed_memory32 = &ares->data.fixed_memory32; - if (!fixed_memory32->address && !fixed_memory32->address_length) - return false; acpi_dev_get_memresource(res, fixed_memory32->address, fixed_memory32->address_length, fixed_memory32->write_protect); break; default: + res->flags = 0; return false; } - return true; + + return !(res->flags & IORESOURCE_DISABLED); } EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); -static unsigned int acpi_dev_ioresource_flags(u64 start, u64 end, u8 io_decode, - bool window) +static void acpi_dev_ioresource_flags(struct resource *res, u64 len, + u8 io_decode) { - int flags = IORESOURCE_IO; + res->flags = IORESOURCE_IO; + + if (!acpi_dev_resource_len_valid(res->start, res->end, len, true)) + res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; + + if (res->end >= 0x10003) + res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; if (io_decode == ACPI_DECODE_16) - flags |= IORESOURCE_IO_16BIT_ADDR; - - if (start > end || end >= 0x10003) - flags |= IORESOURCE_DISABLED; - - if (window) - flags |= IORESOURCE_WINDOW; - - return flags; + res->flags |= IORESOURCE_IO_16BIT_ADDR; } static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, u8 io_decode) { - u64 end = start + len - 1; - res->start = start; - res->end = end; - res->flags = acpi_dev_ioresource_flags(start, end, io_decode, false); + res->end = start + len - 1; + acpi_dev_ioresource_flags(res, len, io_decode); } /** @@ -141,6 +151,11 @@ static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, * Check if the given ACPI resource object represents an I/O resource and * if that's the case, use the information in it to populate the generic * resource object pointed to by @res. + * + * Return: + * 1) false with res->flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 3) true: valid assigned resource */ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) { @@ -150,135 +165,143 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) switch (ares->type) { case ACPI_RESOURCE_TYPE_IO: io = &ares->data.io; - if (!io->minimum && !io->address_length) - return false; acpi_dev_get_ioresource(res, io->minimum, io->address_length, io->io_decode); break; case ACPI_RESOURCE_TYPE_FIXED_IO: fixed_io = &ares->data.fixed_io; - if (!fixed_io->address && !fixed_io->address_length) - return false; acpi_dev_get_ioresource(res, fixed_io->address, fixed_io->address_length, ACPI_DECODE_10); break; default: + res->flags = 0; return false; } - return true; + + return !(res->flags & IORESOURCE_DISABLED); } EXPORT_SYMBOL_GPL(acpi_dev_resource_io); -/** - * acpi_dev_resource_address_space - Extract ACPI address space information. - * @ares: Input ACPI resource object. - * @res: Output generic resource object. - * - * Check if the given ACPI resource object represents an address space resource - * and if that's the case, use the information in it to populate the generic - * resource object pointed to by @res. - */ -bool acpi_dev_resource_address_space(struct acpi_resource *ares, - struct resource *res) +static bool acpi_decode_space(struct resource_win *win, + struct acpi_resource_address *addr, + struct acpi_address64_attribute *attr) { - acpi_status status; - struct acpi_resource_address64 addr; - bool window; - u64 len; - u8 io_decode; + u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; + bool wp = addr->info.mem.write_protect; + u64 len = attr->address_length; + struct resource *res = &win->res; - switch (ares->type) { - case ACPI_RESOURCE_TYPE_ADDRESS16: - case ACPI_RESOURCE_TYPE_ADDRESS32: - case ACPI_RESOURCE_TYPE_ADDRESS64: - break; - default: - return false; + /* + * Filter out invalid descriptor according to ACPI Spec 5.0, section + * 6.4.3.5 Address Space Resource Descriptors. + */ + if ((addr->min_address_fixed != addr->max_address_fixed && len) || + (addr->min_address_fixed && addr->max_address_fixed && !len)) + pr_debug("ACPI: Invalid address space min_addr_fix %d, max_addr_fix %d, len %llx\n", + addr->min_address_fixed, addr->max_address_fixed, len); + + res->start = attr->minimum; + res->end = attr->maximum; + + /* + * For bridges that translate addresses across the bridge, + * translation_offset is the offset that must be added to the + * address on the secondary side to obtain the address on the + * primary side. Non-bridge devices must list 0 for all Address + * Translation offset bits. + */ + if (addr->producer_consumer == ACPI_PRODUCER) { + res->start += attr->translation_offset; + res->end += attr->translation_offset; + } else if (attr->translation_offset) { + pr_debug("ACPI: translation_offset(%lld) is invalid for non-bridge device.\n", + attr->translation_offset); } - status = acpi_resource_to_address64(ares, &addr); - if (ACPI_FAILURE(status)) - return false; - - res->start = addr.minimum; - res->end = addr.maximum; - window = addr.producer_consumer == ACPI_PRODUCER; - - switch(addr.resource_type) { + switch (addr->resource_type) { case ACPI_MEMORY_RANGE: - len = addr.maximum - addr.minimum + 1; - res->flags = acpi_dev_memresource_flags(len, - addr.info.mem.write_protect, - window); + acpi_dev_memresource_flags(res, len, wp); break; case ACPI_IO_RANGE: - io_decode = addr.granularity == 0xfff ? - ACPI_DECODE_10 : ACPI_DECODE_16; - res->flags = acpi_dev_ioresource_flags(addr.minimum, - addr.maximum, - io_decode, window); + acpi_dev_ioresource_flags(res, len, iodec); break; case ACPI_BUS_NUMBER_RANGE: res->flags = IORESOURCE_BUS; break; default: - res->flags = 0; + return false; } - return true; + win->offset = attr->translation_offset; + + if (addr->producer_consumer == ACPI_PRODUCER) + res->flags |= IORESOURCE_WINDOW; + + if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY) + res->flags |= IORESOURCE_PREFETCH; + + return !(res->flags & IORESOURCE_DISABLED); +} + +/** + * acpi_dev_resource_address_space - Extract ACPI address space information. + * @ares: Input ACPI resource object. + * @win: Output generic resource object. + * + * Check if the given ACPI resource object represents an address space resource + * and if that's the case, use the information in it to populate the generic + * resource object pointed to by @win. + * + * Return: + * 1) false with win->res.flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned + * resource + * 3) true: valid assigned resource + */ +bool acpi_dev_resource_address_space(struct acpi_resource *ares, + struct resource_win *win) +{ + struct acpi_resource_address64 addr; + + win->res.flags = 0; + if (ACPI_FAILURE(acpi_resource_to_address64(ares, &addr))) + return false; + + return acpi_decode_space(win, (struct acpi_resource_address *)&addr, + &addr.address); } EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); /** * acpi_dev_resource_ext_address_space - Extract ACPI address space information. * @ares: Input ACPI resource object. - * @res: Output generic resource object. + * @win: Output generic resource object. * * Check if the given ACPI resource object represents an extended address space * resource and if that's the case, use the information in it to populate the - * generic resource object pointed to by @res. + * generic resource object pointed to by @win. + * + * Return: + * 1) false with win->res.flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned + * resource + * 3) true: valid assigned resource */ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, - struct resource *res) + struct resource_win *win) { struct acpi_resource_extended_address64 *ext_addr; - bool window; - u64 len; - u8 io_decode; + win->res.flags = 0; if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) return false; ext_addr = &ares->data.ext_address64; - res->start = ext_addr->minimum; - res->end = ext_addr->maximum; - window = ext_addr->producer_consumer == ACPI_PRODUCER; - - switch(ext_addr->resource_type) { - case ACPI_MEMORY_RANGE: - len = ext_addr->maximum - ext_addr->minimum + 1; - res->flags = acpi_dev_memresource_flags(len, - ext_addr->info.mem.write_protect, - window); - break; - case ACPI_IO_RANGE: - io_decode = ext_addr->granularity == 0xfff ? - ACPI_DECODE_10 : ACPI_DECODE_16; - res->flags = acpi_dev_ioresource_flags(ext_addr->minimum, - ext_addr->maximum, - io_decode, window); - break; - case ACPI_BUS_NUMBER_RANGE: - res->flags = IORESOURCE_BUS; - break; - default: - res->flags = 0; - } - - return true; + return acpi_decode_space(win, (struct acpi_resource_address *)ext_addr, + &ext_addr->address); } EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); @@ -310,7 +333,7 @@ static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi) { res->start = gsi; res->end = gsi; - res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED; + res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET; } static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, @@ -369,6 +392,11 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, * represented by the resource and populate the generic resource object pointed * to by @res accordingly. If the registration of the GSI is not successful, * IORESOURCE_DISABLED will be set it that object's flags. + * + * Return: + * 1) false with res->flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 3) true: valid assigned resource */ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, struct resource *res) @@ -402,6 +430,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, ext_irq->sharable, false); break; default: + res->flags = 0; return false; } @@ -415,12 +444,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt); */ void acpi_dev_free_resource_list(struct list_head *list) { - struct resource_list_entry *rentry, *re; - - list_for_each_entry_safe(rentry, re, list, node) { - list_del(&rentry->node); - kfree(rentry); - } + resource_list_free(list); } EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list); @@ -432,18 +456,19 @@ struct res_proc_context { int error; }; -static acpi_status acpi_dev_new_resource_entry(struct resource *r, +static acpi_status acpi_dev_new_resource_entry(struct resource_win *win, struct res_proc_context *c) { - struct resource_list_entry *rentry; + struct resource_entry *rentry; - rentry = kmalloc(sizeof(*rentry), GFP_KERNEL); + rentry = resource_list_create_entry(NULL, 0); if (!rentry) { c->error = -ENOMEM; return AE_NO_MEMORY; } - rentry->res = *r; - list_add_tail(&rentry->node, c->list); + *rentry->res = win->res; + rentry->offset = win->offset; + resource_list_add_tail(rentry, c->list); c->count++; return AE_OK; } @@ -452,7 +477,8 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, void *context) { struct res_proc_context *c = context; - struct resource r; + struct resource_win win; + struct resource *res = &win.res; int i; if (c->preproc) { @@ -467,18 +493,18 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, } } - memset(&r, 0, sizeof(r)); + memset(&win, 0, sizeof(win)); - if (acpi_dev_resource_memory(ares, &r) - || acpi_dev_resource_io(ares, &r) - || acpi_dev_resource_address_space(ares, &r) - || acpi_dev_resource_ext_address_space(ares, &r)) - return acpi_dev_new_resource_entry(&r, c); + if (acpi_dev_resource_memory(ares, res) + || acpi_dev_resource_io(ares, res) + || acpi_dev_resource_address_space(ares, &win) + || acpi_dev_resource_ext_address_space(ares, &win)) + return acpi_dev_new_resource_entry(&win, c); - for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) { + for (i = 0; acpi_dev_resource_interrupt(ares, i, res); i++) { acpi_status status; - status = acpi_dev_new_resource_entry(&r, c); + status = acpi_dev_new_resource_entry(&win, c); if (ACPI_FAILURE(status)) return status; } @@ -503,7 +529,7 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, * returned as the final error code. * * The resultant struct resource objects are put on the list pointed to by - * @list, that must be empty initially, as members of struct resource_list_entry + * @list, that must be empty initially, as members of struct resource_entry * objects. Callers of this routine should use %acpi_dev_free_resource_list() to * free that list. * @@ -538,3 +564,58 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, return c.count; } EXPORT_SYMBOL_GPL(acpi_dev_get_resources); + +/** + * acpi_dev_filter_resource_type - Filter ACPI resource according to resource + * types + * @ares: Input ACPI resource object. + * @types: Valid resource types of IORESOURCE_XXX + * + * This is a hepler function to support acpi_dev_get_resources(), which filters + * ACPI resource objects according to resource types. + */ +int acpi_dev_filter_resource_type(struct acpi_resource *ares, + unsigned long types) +{ + unsigned long type = 0; + + switch (ares->type) { + case ACPI_RESOURCE_TYPE_MEMORY24: + case ACPI_RESOURCE_TYPE_MEMORY32: + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + type = IORESOURCE_MEM; + break; + case ACPI_RESOURCE_TYPE_IO: + case ACPI_RESOURCE_TYPE_FIXED_IO: + type = IORESOURCE_IO; + break; + case ACPI_RESOURCE_TYPE_IRQ: + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + type = IORESOURCE_IRQ; + break; + case ACPI_RESOURCE_TYPE_DMA: + case ACPI_RESOURCE_TYPE_FIXED_DMA: + type = IORESOURCE_DMA; + break; + case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: + type = IORESOURCE_REG; + break; + case ACPI_RESOURCE_TYPE_ADDRESS16: + case ACPI_RESOURCE_TYPE_ADDRESS32: + case ACPI_RESOURCE_TYPE_ADDRESS64: + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + if (ares->data.address.resource_type == ACPI_MEMORY_RANGE) + type = IORESOURCE_MEM; + else if (ares->data.address.resource_type == ACPI_IO_RANGE) + type = IORESOURCE_IO; + else if (ares->data.address.resource_type == + ACPI_BUS_NUMBER_RANGE) + type = IORESOURCE_BUS; + break; + default: + break; + } + + return (type & types) ? 0 : 1; +} +EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index dc4d8960684a..bbca7830e18a 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2544,6 +2544,7 @@ int __init acpi_scan_init(void) acpi_pci_link_init(); acpi_processor_init(); acpi_lpss_init(); + acpi_apd_init(); acpi_cmos_rtc_init(); acpi_container_init(); acpi_memory_hotplug_init(); diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 8aa9254a387f..7f251dd1a687 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -321,7 +321,7 @@ static struct dmi_system_id acpisleep_dmi_table[] __initdata = { {}, }; -static void acpi_sleep_dmi_check(void) +static void __init acpi_sleep_dmi_check(void) { int year; diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 032db459370f..88a4f99dd2a7 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -522,6 +522,24 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "370R4E/370R4V/370R5E/3570RE/370R5V"), }, }, + { + /* https://bugzilla.redhat.com/show_bug.cgi?id=1186097 */ + .callback = video_disable_native_backlight, + .ident = "SAMSUNG 3570R/370R/470R/450R/510R/4450RV", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "3570R/370R/470R/450R/510R/4450RV"), + }, + }, + { + /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */ + .callback = video_disable_native_backlight, + .ident = "SAMSUNG 730U3E/740U3E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"), + }, + }, { /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */ diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 52ddd9fbb55e..f0099360039e 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -43,6 +44,10 @@ static int amba_match(struct device *dev, struct device_driver *drv) struct amba_device *pcdev = to_amba_device(dev); struct amba_driver *pcdrv = to_amba_driver(drv); + /* When driver_override is set, only bind to the matching driver */ + if (pcdev->driver_override) + return !strcmp(pcdev->driver_override, drv->name); + return amba_lookup(pcdrv->id_table, pcdev) != NULL; } @@ -59,6 +64,47 @@ static int amba_uevent(struct device *dev, struct kobj_uevent_env *env) return retval; } +static ssize_t driver_override_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ + struct amba_device *dev = to_amba_device(_dev); + + if (!dev->driver_override) + return 0; + + return sprintf(buf, "%s\n", dev->driver_override); +} + +static ssize_t driver_override_store(struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct amba_device *dev = to_amba_device(_dev); + char *driver_override, *old = dev->driver_override, *cp; + + if (count > PATH_MAX) + return -EINVAL; + + driver_override = kstrndup(buf, count, GFP_KERNEL); + if (!driver_override) + return -ENOMEM; + + cp = strchr(driver_override, '\n'); + if (cp) + *cp = '\0'; + + if (strlen(driver_override)) { + dev->driver_override = driver_override; + } else { + kfree(driver_override); + dev->driver_override = NULL; + } + + kfree(old); + + return count; +} + #define amba_attr_func(name,fmt,arg...) \ static ssize_t name##_show(struct device *_dev, \ struct device_attribute *attr, char *buf) \ @@ -81,6 +127,7 @@ amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n", static struct device_attribute amba_dev_attrs[] = { __ATTR_RO(id), __ATTR_RO(resource), + __ATTR_RW(driver_override), __ATTR_NULL, }; diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index a3a13605a9c4..5f601553b9b0 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -835,6 +835,7 @@ config PATA_AT32 config PATA_AT91 tristate "PATA support for AT91SAM9260" depends on ARM && SOC_AT91SAM9 + depends on !ARCH_MULTIPLATFORM help This option enables support for IDE devices on the Atmel AT91SAM9260 SoC. diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 49f1e6890587..33bb06e006c9 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -325,7 +325,6 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */ { PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */ { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */ - { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */ diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 40f0e34f17af..71262e08648e 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -333,7 +333,7 @@ struct ahci_host_priv { u32 em_msg_type; /* EM message type */ bool got_runtime_pm; /* Did we do pm_runtime_get? */ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ - struct regulator *target_pwr; /* Optional */ + struct regulator **target_pwrs; /* Optional */ /* * If platform uses PHYs. There is a 1:1 relation between the port number and * the PHY position in this array. @@ -354,6 +354,10 @@ extern int ahci_ignore_sss; extern struct device_attribute *ahci_shost_attrs[]; extern struct device_attribute *ahci_sdev_attrs[]; +/* + * This must be instantiated by the edge drivers. Read the comments + * for ATA_BASE_SHT + */ #define AHCI_SHT(drv_name) \ ATA_NCQ_SHT(drv_name), \ .can_queue = AHCI_MAX_CMDS - 1, \ diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c index ce8a7a6d6c7f..267a3d3e79f4 100644 --- a/drivers/ata/ahci_da850.c +++ b/drivers/ata/ahci_da850.c @@ -16,6 +16,8 @@ #include #include "ahci.h" +#define DRV_NAME "ahci_da850" + /* SATA PHY Control Register offset from AHCI base */ #define SATA_P0PHYCR_REG 0x178 @@ -59,6 +61,10 @@ static const struct ata_port_info ahci_da850_port_info = { .port_ops = &ahci_platform_ops, }; +static struct scsi_host_template ahci_platform_sht = { + AHCI_SHT(DRV_NAME), +}; + static int ahci_da850_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -85,7 +91,8 @@ static int ahci_da850_probe(struct platform_device *pdev) da850_sata_init(dev, pwrdn_reg, hpriv->mmio); - rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info); + rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info, + &ahci_platform_sht); if (rc) goto disable_resources; @@ -102,7 +109,7 @@ static struct platform_driver ahci_da850_driver = { .probe = ahci_da850_probe, .remove = ata_platform_remove_one, .driver = { - .name = "ahci_da850", + .name = DRV_NAME, .pm = &ahci_da850_pm_ops, }, }; diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 35d51c59a370..3f3a7db208ae 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -28,6 +28,8 @@ #include #include "ahci.h" +#define DRV_NAME "ahci-imx" + enum { /* Timer 1-ms Register */ IMX_TIMER1MS = 0x00e0, @@ -221,11 +223,9 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv) if (imxpriv->no_device) return 0; - if (hpriv->target_pwr) { - ret = regulator_enable(hpriv->target_pwr); - if (ret) - return ret; - } + ret = ahci_platform_enable_regulators(hpriv); + if (ret) + return ret; ret = clk_prepare_enable(imxpriv->sata_ref_clk); if (ret < 0) @@ -270,8 +270,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv) disable_clk: clk_disable_unprepare(imxpriv->sata_ref_clk); disable_regulator: - if (hpriv->target_pwr) - regulator_disable(hpriv->target_pwr); + ahci_platform_disable_regulators(hpriv); return ret; } @@ -291,8 +290,7 @@ static void imx_sata_disable(struct ahci_host_priv *hpriv) clk_disable_unprepare(imxpriv->sata_ref_clk); - if (hpriv->target_pwr) - regulator_disable(hpriv->target_pwr); + ahci_platform_disable_regulators(hpriv); } static void ahci_imx_error_handler(struct ata_port *ap) @@ -524,6 +522,10 @@ static u32 imx_ahci_parse_props(struct device *dev, return reg_value; } +static struct scsi_host_template ahci_platform_sht = { + AHCI_SHT(DRV_NAME), +}; + static int imx_ahci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -620,7 +622,8 @@ static int imx_ahci_probe(struct platform_device *pdev) reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; writel(reg_val, hpriv->mmio + IMX_TIMER1MS); - ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info); + ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, + &ahci_platform_sht); if (ret) goto disable_sata; @@ -678,7 +681,7 @@ static struct platform_driver imx_ahci_driver = { .probe = imx_ahci_probe, .remove = ata_platform_remove_one, .driver = { - .name = "ahci-imx", + .name = DRV_NAME, .of_match_table = imx_ahci_of_match, .pm = &ahci_imx_pm_ops, }, diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c index 64bb08432b69..23716dd8a7ec 100644 --- a/drivers/ata/ahci_mvebu.c +++ b/drivers/ata/ahci_mvebu.c @@ -19,6 +19,8 @@ #include #include "ahci.h" +#define DRV_NAME "ahci-mvebu" + #define AHCI_VENDOR_SPECIFIC_0_ADDR 0xa0 #define AHCI_VENDOR_SPECIFIC_0_DATA 0xa4 @@ -67,6 +69,10 @@ static const struct ata_port_info ahci_mvebu_port_info = { .port_ops = &ahci_platform_ops, }; +static struct scsi_host_template ahci_platform_sht = { + AHCI_SHT(DRV_NAME), +}; + static int ahci_mvebu_probe(struct platform_device *pdev) { struct ahci_host_priv *hpriv; @@ -88,7 +94,8 @@ static int ahci_mvebu_probe(struct platform_device *pdev) ahci_mvebu_mbus_config(hpriv, dram); ahci_mvebu_regret_option(hpriv); - rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info); + rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info, + &ahci_platform_sht); if (rc) goto disable_resources; @@ -114,7 +121,7 @@ static struct platform_driver ahci_mvebu_driver = { .probe = ahci_mvebu_probe, .remove = ata_platform_remove_one, .driver = { - .name = "ahci-mvebu", + .name = DRV_NAME, .of_match_table = ahci_mvebu_of_match, }, }; diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 18d539837045..78d6ae0b90c4 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -22,6 +22,8 @@ #include #include "ahci.h" +#define DRV_NAME "ahci" + static const struct ata_port_info ahci_port_info = { .flags = AHCI_FLAG_COMMON, .pio_mask = ATA_PIO4, @@ -29,6 +31,10 @@ static const struct ata_port_info ahci_port_info = { .port_ops = &ahci_platform_ops, }; +static struct scsi_host_template ahci_platform_sht = { + AHCI_SHT(DRV_NAME), +}; + static int ahci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -46,7 +52,8 @@ static int ahci_probe(struct platform_device *pdev) if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci")) hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ; - rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info); + rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info, + &ahci_platform_sht); if (rc) goto disable_resources; @@ -75,7 +82,7 @@ static struct platform_driver ahci_driver = { .probe = ahci_probe, .remove = ata_platform_remove_one, .driver = { - .name = "ahci", + .name = DRV_NAME, .of_match_table = ahci_of_match, .pm = &ahci_pm_ops, }, diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c index 2f9e8317cc16..bc971af262e7 100644 --- a/drivers/ata/ahci_st.c +++ b/drivers/ata/ahci_st.c @@ -23,6 +23,8 @@ #include "ahci.h" +#define DRV_NAME "st_ahci" + #define ST_AHCI_OOBR 0xbc #define ST_AHCI_OOBR_WE BIT(31) #define ST_AHCI_OOBR_CWMIN_SHIFT 24 @@ -140,6 +142,10 @@ static const struct ata_port_info st_ahci_port_info = { .port_ops = &st_ahci_port_ops, }; +static struct scsi_host_template ahci_platform_sht = { + AHCI_SHT(DRV_NAME), +}; + static int st_ahci_probe(struct platform_device *pdev) { struct st_ahci_drv_data *drv_data; @@ -166,7 +172,8 @@ static int st_ahci_probe(struct platform_device *pdev) if (err) return err; - err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info); + err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info, + &ahci_platform_sht); if (err) { ahci_platform_disable_resources(hpriv); return err; @@ -229,7 +236,7 @@ MODULE_DEVICE_TABLE(of, st_ahci_match); static struct platform_driver st_ahci_driver = { .driver = { - .name = "st_ahci", + .name = DRV_NAME, .pm = &st_ahci_pm_ops, .of_match_table = of_match_ptr(st_ahci_match), }, diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c index e2e0da539a2f..b26437430163 100644 --- a/drivers/ata/ahci_sunxi.c +++ b/drivers/ata/ahci_sunxi.c @@ -27,6 +27,8 @@ #include #include "ahci.h" +#define DRV_NAME "ahci-sunxi" + /* Insmod parameters */ static bool enable_pmp; module_param(enable_pmp, bool, 0); @@ -169,6 +171,10 @@ static const struct ata_port_info ahci_sunxi_port_info = { .port_ops = &ahci_platform_ops, }; +static struct scsi_host_template ahci_platform_sht = { + AHCI_SHT(DRV_NAME), +}; + static int ahci_sunxi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -200,7 +206,8 @@ static int ahci_sunxi_probe(struct platform_device *pdev) if (!enable_pmp) hpriv->flags |= AHCI_HFLAG_NO_PMP; - rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info); + rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info, + &ahci_platform_sht); if (rc) goto disable_resources; @@ -251,7 +258,7 @@ static struct platform_driver ahci_sunxi_driver = { .probe = ahci_sunxi_probe, .remove = ata_platform_remove_one, .driver = { - .name = "ahci-sunxi", + .name = DRV_NAME, .of_match_table = ahci_sunxi_of_match, .pm = &ahci_sunxi_pm_ops, }, diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c index 032904402c95..3a62eb246d80 100644 --- a/drivers/ata/ahci_tegra.c +++ b/drivers/ata/ahci_tegra.c @@ -31,6 +31,8 @@ #include "ahci.h" +#define DRV_NAME "tegra-ahci" + #define SATA_CONFIGURATION_0 0x180 #define SATA_CONFIGURATION_EN_FPCI BIT(0) @@ -289,6 +291,10 @@ static const struct of_device_id tegra_ahci_of_match[] = { }; MODULE_DEVICE_TABLE(of, tegra_ahci_of_match); +static struct scsi_host_template ahci_platform_sht = { + AHCI_SHT(DRV_NAME), +}; + static int tegra_ahci_probe(struct platform_device *pdev) { struct ahci_host_priv *hpriv; @@ -354,7 +360,8 @@ static int tegra_ahci_probe(struct platform_device *pdev) if (ret) return ret; - ret = ahci_platform_init_host(pdev, hpriv, &ahci_tegra_port_info); + ret = ahci_platform_init_host(pdev, hpriv, &ahci_tegra_port_info, + &ahci_platform_sht); if (ret) goto deinit_controller; @@ -370,7 +377,7 @@ static struct platform_driver tegra_ahci_driver = { .probe = tegra_ahci_probe, .remove = ata_platform_remove_one, .driver = { - .name = "tegra-ahci", + .name = DRV_NAME, .of_match_table = tegra_ahci_of_match, }, /* LP0 suspend support not implemented */ diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index feeb8f1e2fe8..2e8bb603e447 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -30,6 +30,8 @@ #include #include "ahci.h" +#define DRV_NAME "xgene-ahci" + /* Max # of disk per a controller */ #define MAX_AHCI_CHN_PERCTR 2 @@ -85,6 +87,7 @@ struct xgene_ahci_context { struct ahci_host_priv *hpriv; struct device *dev; u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/ + u32 class[MAX_AHCI_CHN_PERCTR]; /* tracking the class of device */ void __iomem *csr_core; /* Core CSR address of IP */ void __iomem *csr_diag; /* Diag CSR address of IP */ void __iomem *csr_axi; /* AXI CSR address of IP */ @@ -104,18 +107,70 @@ static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx) return 0; } +/** + * xgene_ahci_poll_reg_val- Poll a register on a specific value. + * @ap : ATA port of interest. + * @reg : Register of interest. + * @val : Value to be attained. + * @interval : waiting interval for polling. + * @timeout : timeout for achieving the value. + */ +static int xgene_ahci_poll_reg_val(struct ata_port *ap, + void __iomem *reg, unsigned + int val, unsigned long interval, + unsigned long timeout) +{ + unsigned long deadline; + unsigned int tmp; + + tmp = ioread32(reg); + deadline = ata_deadline(jiffies, timeout); + + while (tmp != val && time_before(jiffies, deadline)) { + ata_msleep(ap, interval); + tmp = ioread32(reg); + } + + return tmp; +} + /** * xgene_ahci_restart_engine - Restart the dma engine. * @ap : ATA port of interest * - * Restarts the dma engine inside the controller. + * Waits for completion of multiple commands and restarts + * the DMA engine inside the controller. */ static int xgene_ahci_restart_engine(struct ata_port *ap) { struct ahci_host_priv *hpriv = ap->host->private_data; + struct ahci_port_priv *pp = ap->private_data; + void __iomem *port_mmio = ahci_port_base(ap); + u32 fbs; + + /* + * In case of PMP multiple IDENTIFY DEVICE commands can be + * issued inside PxCI. So need to poll PxCI for the + * completion of outstanding IDENTIFY DEVICE commands before + * we restart the DMA engine. + */ + if (xgene_ahci_poll_reg_val(ap, port_mmio + + PORT_CMD_ISSUE, 0x0, 1, 100)) + return -EBUSY; ahci_stop_engine(ap); ahci_start_fis_rx(ap); + + /* + * Enable the PxFBS.FBS_EN bit as it + * gets cleared due to stopping the engine. + */ + if (pp->fbs_supported) { + fbs = readl(port_mmio + PORT_FBS); + writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS); + fbs = readl(port_mmio + PORT_FBS); + } + hpriv->start_engine(ap); return 0; @@ -129,6 +184,13 @@ static int xgene_ahci_restart_engine(struct ata_port *ap) * clear the BSY bit after receiving the PIO setup FIS. This results in the dma * state machine goes into the CMFatalErrorUpdate state and locks up. By * restarting the dma engine, it removes the controller out of lock up state. + * + * Due to H/W errata, the controller is unable to save the PMP + * field fetched from command header before sending the H2D FIS. + * When the device returns the PMP port field in the D2H FIS, there is + * a mismatch and results in command completion failure. The + * workaround is to write the pmp value to PxFBS.DEV field before issuing + * any command to PMP. */ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc) { @@ -136,8 +198,23 @@ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc) struct ahci_host_priv *hpriv = ap->host->private_data; struct xgene_ahci_context *ctx = hpriv->plat_data; int rc = 0; + u32 port_fbs; + void *port_mmio = ahci_port_base(ap); - if (unlikely(ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA)) + /* + * Write the pmp value to PxFBS.DEV + * for case of Port Mulitplier. + */ + if (ctx->class[ap->port_no] == ATA_DEV_PMP) { + port_fbs = readl(port_mmio + PORT_FBS); + port_fbs &= ~PORT_FBS_DEV_MASK; + port_fbs |= qc->dev->link->pmp << PORT_FBS_DEV_OFFSET; + writel(port_fbs, port_mmio + PORT_FBS); + } + + if (unlikely((ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA) || + (ctx->last_cmd[ap->port_no] == ATA_CMD_PACKET) || + (ctx->last_cmd[ap->port_no] == ATA_CMD_SMART))) xgene_ahci_restart_engine(ap); rc = ahci_qc_issue(qc); @@ -188,7 +265,7 @@ static unsigned int xgene_ahci_read_id(struct ata_device *dev, * * Clear reserved bit 8 (DEVSLP bit) as we don't support DEVSLP */ - id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8); + id[ATA_ID_FEATURE_SUPP] &= cpu_to_le16(~(1 << 8)); return 0; } @@ -363,16 +440,119 @@ static void xgene_ahci_host_stop(struct ata_host *host) ahci_platform_disable_resources(hpriv); } +/** + * xgene_ahci_pmp_softreset - Issue the softreset to the drives connected + * to Port Multiplier. + * @link: link to reset + * @class: Return value to indicate class of device + * @deadline: deadline jiffies for the operation + * + * Due to H/W errata, the controller is unable to save the PMP + * field fetched from command header before sending the H2D FIS. + * When the device returns the PMP port field in the D2H FIS, there is + * a mismatch and results in command completion failure. The workaround + * is to write the pmp value to PxFBS.DEV field before issuing any command + * to PMP. + */ +static int xgene_ahci_pmp_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + int pmp = sata_srst_pmp(link); + struct ata_port *ap = link->ap; + u32 rc; + void *port_mmio = ahci_port_base(ap); + u32 port_fbs; + + /* + * Set PxFBS.DEV field with pmp + * value. + */ + port_fbs = readl(port_mmio + PORT_FBS); + port_fbs &= ~PORT_FBS_DEV_MASK; + port_fbs |= pmp << PORT_FBS_DEV_OFFSET; + writel(port_fbs, port_mmio + PORT_FBS); + + rc = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready); + + return rc; +} + +/** + * xgene_ahci_softreset - Issue the softreset to the drive. + * @link: link to reset + * @class: Return value to indicate class of device + * @deadline: deadline jiffies for the operation + * + * Due to H/W errata, the controller is unable to save the PMP + * field fetched from command header before sending the H2D FIS. + * When the device returns the PMP port field in the D2H FIS, there is + * a mismatch and results in command completion failure. The workaround + * is to write the pmp value to PxFBS.DEV field before issuing any command + * to PMP. Here is the algorithm to detect PMP : + * + * 1. Save the PxFBS value + * 2. Program PxFBS.DEV with pmp value send by framework. Framework sends + * 0xF for both PMP/NON-PMP initially + * 3. Issue softreset + * 4. If signature class is PMP goto 6 + * 5. restore the original PxFBS and goto 3 + * 6. return + */ +static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + int pmp = sata_srst_pmp(link); + struct ata_port *ap = link->ap; + struct ahci_host_priv *hpriv = ap->host->private_data; + struct xgene_ahci_context *ctx = hpriv->plat_data; + void *port_mmio = ahci_port_base(ap); + u32 port_fbs; + u32 port_fbs_save; + u32 retry = 1; + u32 rc; + + port_fbs_save = readl(port_mmio + PORT_FBS); + + /* + * Set PxFBS.DEV field with pmp + * value. + */ + port_fbs = readl(port_mmio + PORT_FBS); + port_fbs &= ~PORT_FBS_DEV_MASK; + port_fbs |= pmp << PORT_FBS_DEV_OFFSET; + writel(port_fbs, port_mmio + PORT_FBS); + +softreset_retry: + rc = ahci_do_softreset(link, class, pmp, + deadline, ahci_check_ready); + + ctx->class[ap->port_no] = *class; + if (*class != ATA_DEV_PMP) { + /* + * Retry for normal drives without + * setting PxFBS.DEV field with pmp value. + */ + if (retry--) { + writel(port_fbs_save, port_mmio + PORT_FBS); + goto softreset_retry; + } + } + + return rc; +} + static struct ata_port_operations xgene_ahci_ops = { .inherits = &ahci_ops, .host_stop = xgene_ahci_host_stop, .hardreset = xgene_ahci_hardreset, .read_id = xgene_ahci_read_id, .qc_issue = xgene_ahci_qc_issue, + .softreset = xgene_ahci_softreset, + .pmp_softreset = xgene_ahci_pmp_softreset }; static const struct ata_port_info xgene_ahci_port_info = { - .flags = AHCI_FLAG_COMMON, + .flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, .port_ops = &xgene_ahci_ops, @@ -444,6 +624,10 @@ static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx) return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0; } +static struct scsi_host_template ahci_platform_sht = { + AHCI_SHT(DRV_NAME), +}; + static int xgene_ahci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -521,7 +705,8 @@ static int xgene_ahci_probe(struct platform_device *pdev) skip_clk_phy: hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ; - rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info); + rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, + &ahci_platform_sht); if (rc) goto disable_resources; @@ -543,7 +728,7 @@ static struct platform_driver xgene_ahci_driver = { .probe = xgene_ahci_probe, .remove = ata_platform_remove_one, .driver = { - .name = "xgene-ahci", + .name = DRV_NAME, .of_match_table = xgene_ahci_of_match, }, }; diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 97683e45ab04..61a9c07e0dff 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -2003,7 +2003,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) devslp = readl(port_mmio + PORT_DEVSLP); if (!(devslp & PORT_DEVSLP_DSP)) { - dev_err(ap->host->dev, "port does not support device sleep\n"); + dev_info(ap->host->dev, "port does not support device sleep\n"); return; } diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index 0b03f9056692..d89305d289f6 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "ahci.h" static void ahci_host_stop(struct ata_host *host); @@ -34,10 +35,6 @@ struct ata_port_operations ahci_platform_ops = { }; EXPORT_SYMBOL_GPL(ahci_platform_ops); -static struct scsi_host_template ahci_platform_sht = { - AHCI_SHT("ahci_platform"), -}; - /** * ahci_platform_enable_phys - Enable PHYs * @hpriv: host private area to store config values @@ -54,9 +51,6 @@ static int ahci_platform_enable_phys(struct ahci_host_priv *hpriv) int rc, i; for (i = 0; i < hpriv->nports; i++) { - if (!hpriv->phys[i]) - continue; - rc = phy_init(hpriv->phys[i]); if (rc) goto disable_phys; @@ -89,9 +83,6 @@ static void ahci_platform_disable_phys(struct ahci_host_priv *hpriv) int i; for (i = 0; i < hpriv->nports; i++) { - if (!hpriv->phys[i]) - continue; - phy_power_off(hpriv->phys[i]); phy_exit(hpriv->phys[i]); } @@ -143,6 +134,59 @@ void ahci_platform_disable_clks(struct ahci_host_priv *hpriv) } EXPORT_SYMBOL_GPL(ahci_platform_disable_clks); +/** + * ahci_platform_enable_regulators - Enable regulators + * @hpriv: host private area to store config values + * + * This function enables all the regulators found in + * hpriv->target_pwrs, if any. If a regulator fails to be enabled, it + * disables all the regulators already enabled in reverse order and + * returns an error. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv) +{ + int rc, i; + + for (i = 0; i < hpriv->nports; i++) { + if (!hpriv->target_pwrs[i]) + continue; + + rc = regulator_enable(hpriv->target_pwrs[i]); + if (rc) + goto disable_target_pwrs; + } + + return 0; + +disable_target_pwrs: + while (--i >= 0) + if (hpriv->target_pwrs[i]) + regulator_disable(hpriv->target_pwrs[i]); + + return rc; +} +EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators); + +/** + * ahci_platform_disable_regulators - Disable regulators + * @hpriv: host private area to store config values + * + * This function disables all regulators found in hpriv->target_pwrs. + */ +void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv) +{ + int i; + + for (i = 0; i < hpriv->nports; i++) { + if (!hpriv->target_pwrs[i]) + continue; + regulator_disable(hpriv->target_pwrs[i]); + } +} +EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators); /** * ahci_platform_enable_resources - Enable platform resources * @hpriv: host private area to store config values @@ -163,11 +207,9 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv) { int rc; - if (hpriv->target_pwr) { - rc = regulator_enable(hpriv->target_pwr); - if (rc) - return rc; - } + rc = ahci_platform_enable_regulators(hpriv); + if (rc) + return rc; rc = ahci_platform_enable_clks(hpriv); if (rc) @@ -183,8 +225,8 @@ disable_clks: ahci_platform_disable_clks(hpriv); disable_regulator: - if (hpriv->target_pwr) - regulator_disable(hpriv->target_pwr); + ahci_platform_disable_regulators(hpriv); + return rc; } EXPORT_SYMBOL_GPL(ahci_platform_enable_resources); @@ -205,8 +247,7 @@ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) ahci_platform_disable_clks(hpriv); - if (hpriv->target_pwr) - regulator_disable(hpriv->target_pwr); + ahci_platform_disable_regulators(hpriv); } EXPORT_SYMBOL_GPL(ahci_platform_disable_resources); @@ -222,6 +263,69 @@ static void ahci_platform_put_resources(struct device *dev, void *res) for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) clk_put(hpriv->clks[c]); + /* + * The regulators are tied to child node device and not to the + * SATA device itself. So we can't use devm for automatically + * releasing them. We have to do it manually here. + */ + for (c = 0; c < hpriv->nports; c++) + if (hpriv->target_pwrs && hpriv->target_pwrs[c]) + regulator_put(hpriv->target_pwrs[c]); + + kfree(hpriv->target_pwrs); +} + +static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 port, + struct device *dev, struct device_node *node) +{ + int rc; + + hpriv->phys[port] = devm_of_phy_get(dev, node, NULL); + + if (!IS_ERR(hpriv->phys[port])) + return 0; + + rc = PTR_ERR(hpriv->phys[port]); + switch (rc) { + case -ENOSYS: + /* No PHY support. Check if PHY is required. */ + if (of_find_property(node, "phys", NULL)) { + dev_err(dev, + "couldn't get PHY in node %s: ENOSYS\n", + node->name); + break; + } + case -ENODEV: + /* continue normally */ + hpriv->phys[port] = NULL; + rc = 0; + break; + + default: + dev_err(dev, + "couldn't get PHY in node %s: %d\n", + node->name, rc); + + break; + } + + return rc; +} + +static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port, + struct device *dev) +{ + struct regulator *target_pwr; + int rc = 0; + + target_pwr = regulator_get_optional(dev, "target"); + + if (!IS_ERR(target_pwr)) + hpriv->target_pwrs[port] = target_pwr; + else + rc = PTR_ERR(target_pwr); + + return rc; } /** @@ -246,7 +350,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) struct ahci_host_priv *hpriv; struct clk *clk; struct device_node *child; - int i, enabled_ports = 0, rc = -ENOMEM; + int i, sz, enabled_ports = 0, rc = -ENOMEM, child_nodes; u32 mask_port_map = 0; if (!devres_open_group(dev, NULL, GFP_KERNEL)) @@ -267,14 +371,6 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) goto err_out; } - hpriv->target_pwr = devm_regulator_get_optional(dev, "target"); - if (IS_ERR(hpriv->target_pwr)) { - rc = PTR_ERR(hpriv->target_pwr); - if (rc == -EPROBE_DEFER) - goto err_out; - hpriv->target_pwr = NULL; - } - for (i = 0; i < AHCI_MAX_CLKS; i++) { /* * For now we must use clk_get(dev, NULL) for the first clock, @@ -296,19 +392,33 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) hpriv->clks[i] = clk; } - hpriv->nports = of_get_child_count(dev->of_node); + hpriv->nports = child_nodes = of_get_child_count(dev->of_node); - if (hpriv->nports) { - hpriv->phys = devm_kzalloc(dev, - hpriv->nports * sizeof(*hpriv->phys), - GFP_KERNEL); - if (!hpriv->phys) { - rc = -ENOMEM; - goto err_out; - } + /* + * If no sub-node was found, we still need to set nports to + * one in order to be able to use the + * ahci_platform_[en|dis]able_[phys|regulators] functions. + */ + if (!child_nodes) + hpriv->nports = 1; + sz = hpriv->nports * sizeof(*hpriv->phys); + hpriv->phys = devm_kzalloc(dev, sz, GFP_KERNEL); + if (!hpriv->phys) { + rc = -ENOMEM; + goto err_out; + } + sz = hpriv->nports * sizeof(*hpriv->target_pwrs); + hpriv->target_pwrs = kzalloc(sz, GFP_KERNEL); + if (!hpriv->target_pwrs) { + rc = -ENOMEM; + goto err_out; + } + + if (child_nodes) { for_each_child_of_node(dev->of_node, child) { u32 port; + struct platform_device *port_dev __maybe_unused; if (!of_device_is_available(child)) continue; @@ -322,17 +432,24 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) dev_warn(dev, "invalid port number %d\n", port); continue; } - mask_port_map |= BIT(port); - hpriv->phys[port] = devm_of_phy_get(dev, child, NULL); - if (IS_ERR(hpriv->phys[port])) { - rc = PTR_ERR(hpriv->phys[port]); - dev_err(dev, - "couldn't get PHY in node %s: %d\n", - child->name, rc); - goto err_out; +#ifdef CONFIG_OF_ADDRESS + of_platform_device_create(child, NULL, NULL); + + port_dev = of_find_device_by_node(child); + + if (port_dev) { + rc = ahci_platform_get_regulator(hpriv, port, + &port_dev->dev); + if (rc == -EPROBE_DEFER) + goto err_out; } +#endif + + rc = ahci_platform_get_phy(hpriv, port, dev, child); + if (rc) + goto err_out; enabled_ports++; } @@ -349,38 +466,14 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) * If no sub-node was found, keep this for device tree * compatibility */ - struct phy *phy = devm_phy_get(dev, "sata-phy"); - if (!IS_ERR(phy)) { - hpriv->phys = devm_kzalloc(dev, sizeof(*hpriv->phys), - GFP_KERNEL); - if (!hpriv->phys) { - rc = -ENOMEM; - goto err_out; - } + rc = ahci_platform_get_phy(hpriv, 0, dev, dev->of_node); + if (rc) + goto err_out; - hpriv->phys[0] = phy; - hpriv->nports = 1; - } else { - rc = PTR_ERR(phy); - switch (rc) { - case -ENOSYS: - /* No PHY support. Check if PHY is required. */ - if (of_find_property(dev->of_node, "phys", NULL)) { - dev_err(dev, "couldn't get sata-phy: ENOSYS\n"); - goto err_out; - } - case -ENODEV: - /* continue normally */ - hpriv->phys = NULL; - break; - - default: - goto err_out; - - } - } + rc = ahci_platform_get_regulator(hpriv, 0, dev); + if (rc == -EPROBE_DEFER) + goto err_out; } - pm_runtime_enable(dev); pm_runtime_get_sync(dev); hpriv->got_runtime_pm = true; @@ -399,6 +492,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_get_resources); * @pdev: platform device pointer for the host * @hpriv: ahci-host private data for the host * @pi_template: template for the ata_port_info to use + * @sht: scsi_host_template to use when registering * * This function does all the usual steps needed to bring up an * ahci-platform host, note any necessary resources (ie clks, phys, etc.) @@ -409,7 +503,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_get_resources); */ int ahci_platform_init_host(struct platform_device *pdev, struct ahci_host_priv *hpriv, - const struct ata_port_info *pi_template) + const struct ata_port_info *pi_template, + struct scsi_host_template *sht) { struct device *dev = &pdev->dev; struct ata_port_info pi = *pi_template; @@ -493,7 +588,7 @@ int ahci_platform_init_host(struct platform_device *pdev, ahci_init_controller(host); ahci_print_info(host, "platform"); - return ahci_host_activate(host, irq, &ahci_platform_sht); + return ahci_host_activate(host, irq, sht); } EXPORT_SYMBOL_GPL(ahci_platform_init_host); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 5c84fb5c3372..4b0d5e71858e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1751,33 +1751,6 @@ unsigned ata_exec_internal(struct ata_device *dev, timeout); } -/** - * ata_do_simple_cmd - execute simple internal command - * @dev: Device to which the command is sent - * @cmd: Opcode to execute - * - * Execute a 'simple' command, that only consists of the opcode - * 'cmd' itself, without filling any other registers - * - * LOCKING: - * Kernel thread context (may sleep). - * - * RETURNS: - * Zero on success, AC_ERR_* mask on failure - */ -unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd) -{ - struct ata_taskfile tf; - - ata_tf_init(dev, &tf); - - tf.command = cmd; - tf.flags |= ATA_TFLAG_DEVICE; - tf.protocol = ATA_PROT_NODATA; - - return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); -} - /** * ata_pio_need_iordy - check if iordy needed * @adev: ATA device @@ -4233,10 +4206,33 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER }, /* devices that don't properly handle queued TRIM commands */ - { "Micron_M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, - { "Crucial_CT???M500SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, - { "Micron_M550*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, - { "Crucial_CT*M550SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, + { "Micron_M[56]*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "Crucial_CT*SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, + + /* + * As defined, the DRAT (Deterministic Read After Trim) and RZAT + * (Return Zero After Trim) flags in the ATA Command Set are + * unreliable in the sense that they only define what happens if + * the device successfully executed the DSM TRIM command. TRIM + * is only advisory, however, and the device is free to silently + * ignore all or parts of the request. + * + * Whitelist drives that are known to reliably return zeroes + * after TRIM. + */ + + /* + * The intel 510 drive has buggy DRAT/RZAT. Explicitly exclude + * that model before whitelisting all other intel SSDs. + */ + { "INTEL*SSDSC2MH*", NULL, 0, }, + + { "INTEL*SSD*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "SSD*INTEL*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "Samsung*SSD*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "SAMSUNG*SSD*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "ST[1248][0248]0[FH]*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, }, /* * Some WD SATA-I drives spin up and down erratically when the link @@ -4748,7 +4744,10 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) return NULL; for (i = 0, tag = ap->last_tag + 1; i < max_queue; i++, tag++) { - tag = tag < max_queue ? tag : 0; + if (ap->flags & ATA_FLAG_LOWTAG) + tag = i; + else + tag = tag < max_queue ? tag : 0; /* the last tag is reserved for internal command. */ if (tag == ATA_TAG_INTERNAL) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 3dbec8954c86..d2029a462e2c 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1635,7 +1635,6 @@ unsigned int atapi_eh_request_sense(struct ata_device *dev, DPRINTK("ATAPI request sense\n"); - /* FIXME: is this needed? */ memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE); /* initialize sense_buf with the error register, @@ -2389,6 +2388,7 @@ const char *ata_get_cmd_descript(u8 command) return NULL; } +EXPORT_SYMBOL_GPL(ata_get_cmd_descript); /** * ata_eh_link_report - report error handling to user @@ -2481,7 +2481,6 @@ static void ata_eh_link_report(struct ata_link *link) for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf; - const u8 *cdb = qc->cdb; char data_buf[20] = ""; char cdb_buf[70] = ""; @@ -2509,16 +2508,15 @@ static void ata_eh_link_report(struct ata_link *link) } if (ata_is_atapi(qc->tf.protocol)) { - if (qc->scsicmd) - scsi_print_command(qc->scsicmd); - else - snprintf(cdb_buf, sizeof(cdb_buf), - "cdb %02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x\n ", - cdb[0], cdb[1], cdb[2], cdb[3], - cdb[4], cdb[5], cdb[6], cdb[7], - cdb[8], cdb[9], cdb[10], cdb[11], - cdb[12], cdb[13], cdb[14], cdb[15]); + const u8 *cdb = qc->cdb; + size_t cdb_len = qc->dev->cdb_len; + + if (qc->scsicmd) { + cdb = qc->scsicmd->cmnd; + cdb_len = qc->scsicmd->cmd_len; + } + __scsi_format_command(cdb_buf, sizeof(cdb_buf), + cdb, cdb_len); } else { const char *descr = ata_get_cmd_descript(cmd->command); if (descr) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e364e86e84d7..280729325ebd 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1995,8 +1995,8 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) VPRINTK("ENTER\n"); - /* set scsi removeable (RMB) bit per ata bit */ - if (ata_id_removeable(args->id)) + /* set scsi removable (RMB) bit per ata bit */ + if (ata_id_removable(args->id)) hdr[1] |= (1 << 7); if (args->dev->class == ATA_DEV_ZAC) { @@ -2532,13 +2532,15 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) rbuf[15] = lowest_aligned; if (ata_id_has_trim(args->id)) { - rbuf[14] |= 0x80; /* TPE */ + rbuf[14] |= 0x80; /* LBPME */ - if (ata_id_has_zero_after_trim(args->id)) - rbuf[14] |= 0x40; /* TPRZ */ + if (ata_id_has_zero_after_trim(args->id) && + dev->horkage & ATA_HORKAGE_ZERO_AFTER_TRIM) { + ata_dev_info(dev, "Enabling discard_zeroes_data\n"); + rbuf[14] |= 0x40; /* LBPRZ */ + } } } - return 0; } diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index db90aa35cb71..2e86e3b85266 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1333,7 +1333,19 @@ void ata_sff_flush_pio_task(struct ata_port *ap) DPRINTK("ENTER\n"); cancel_delayed_work_sync(&ap->sff_pio_task); + + /* + * We wanna reset the HSM state to IDLE. If we do so without + * grabbing the port lock, critical sections protected by it which + * expect the HSM state to stay stable may get surprised. For + * example, we may set IDLE in between the time + * __ata_sff_port_intr() checks for HSM_ST_IDLE and before it calls + * ata_sff_hsm_move() causing ata_sff_hsm_move() to BUG(). + */ + spin_lock_irq(ap->lock); ap->hsm_task_state = HSM_ST_IDLE; + spin_unlock_irq(ap->lock); + ap->sff_pio_task_link = NULL; if (ata_msg_ctl(ap)) diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 5f4e0cca56ec..82ebe263d2f1 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -76,7 +76,6 @@ extern unsigned ata_exec_internal_sg(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, int dma_dir, struct scatterlist *sg, unsigned int n_elem, unsigned long timeout); -extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd); extern int ata_wait_ready(struct ata_link *link, unsigned long deadline, int (*check_ready)(struct ata_link *link)); extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index 48ae4b434474..f9ca72e937ee 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -276,10 +276,8 @@ static int cs5530_init_chip(void) pci_dev_put(cs5530_0); return 0; fail_put: - if (master_0) - pci_dev_put(master_0); - if (cs5530_0) - pci_dev_put(cs5530_0); + pci_dev_put(master_0); + pci_dev_put(cs5530_0); return -ENODEV; } diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c index dcc408abe171..b6b7af894d9d 100644 --- a/drivers/ata/pata_of_platform.c +++ b/drivers/ata/pata_of_platform.c @@ -16,6 +16,12 @@ #include #include +#define DRV_NAME "pata_of_platform" + +static struct scsi_host_template pata_platform_sht = { + ATA_PIO_SHT(DRV_NAME), +}; + static int pata_of_platform_probe(struct platform_device *ofdev) { int ret; @@ -63,7 +69,7 @@ static int pata_of_platform_probe(struct platform_device *ofdev) pio_mask |= (1 << pio_mode) - 1; return __pata_platform_probe(&ofdev->dev, &io_res, &ctl_res, irq_res, - reg_shift, pio_mask); + reg_shift, pio_mask, &pata_platform_sht); } static struct of_device_id pata_of_platform_match[] = { @@ -74,7 +80,7 @@ MODULE_DEVICE_TABLE(of, pata_of_platform_match); static struct platform_driver pata_of_platform_driver = { .driver = { - .name = "pata_of_platform", + .name = DRV_NAME, .of_match_table = pata_of_platform_match, }, .probe = pata_of_platform_probe, diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 4d06a5cda987..dca8251b1aea 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -605,7 +606,7 @@ static long pdc_detect_pll_input_clock(struct ata_host *host) void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR]; u32 scr; long start_count, end_count; - struct timeval start_time, end_time; + ktime_t start_time, end_time; long pll_clock, usec_elapsed; /* Start the test mode */ @@ -616,14 +617,14 @@ static long pdc_detect_pll_input_clock(struct ata_host *host) /* Read current counter value */ start_count = pdc_read_counter(host); - do_gettimeofday(&start_time); + start_time = ktime_get(); /* Let the counter run for 100 ms. */ mdelay(100); /* Read the counter values again */ end_count = pdc_read_counter(host); - do_gettimeofday(&end_time); + end_time = ktime_get(); /* Stop the test mode */ scr = ioread32(mmio_base + PDC_SYS_CTL); @@ -632,8 +633,7 @@ static long pdc_detect_pll_input_clock(struct ata_host *host) ioread32(mmio_base + PDC_SYS_CTL); /* flush */ /* calculate the input clock in Hz */ - usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 + - (end_time.tv_usec - start_time.tv_usec); + usec_elapsed = (long) ktime_us_delta(end_time, start_time); pll_clock = ((start_count - end_count) & 0x3fffffff) / 100 * (100000000 / usec_elapsed); diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 1eedfe46d7c8..c503ded87bb8 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -78,6 +78,7 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr, * @irq_res: Resource representing IRQ and its flags * @ioport_shift: I/O port shift * @__pio_mask: PIO mask + * @sht: scsi_host_template to use when registering * * Register a platform bus IDE interface. Such interfaces are PIO and we * assume do not support IRQ sharing. @@ -99,7 +100,8 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr, */ int __pata_platform_probe(struct device *dev, struct resource *io_res, struct resource *ctl_res, struct resource *irq_res, - unsigned int ioport_shift, int __pio_mask) + unsigned int ioport_shift, int __pio_mask, + struct scsi_host_template *sht) { struct ata_host *host; struct ata_port *ap; @@ -170,7 +172,7 @@ int __pata_platform_probe(struct device *dev, struct resource *io_res, /* activate */ return ata_host_activate(host, irq, irq ? ata_sff_interrupt : NULL, - irq_flags, &pata_platform_sht); + irq_flags, sht); } EXPORT_SYMBOL_GPL(__pata_platform_probe); @@ -216,7 +218,7 @@ static int pata_platform_probe(struct platform_device *pdev) return __pata_platform_probe(&pdev->dev, io_res, ctl_res, irq_res, pp_info ? pp_info->ioport_shift : 0, - pio_mask); + pio_mask, &pata_platform_sht); } static struct platform_driver pata_platform_driver = { diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index c7ddef89e7b0..fdb0f2879ea7 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -48,6 +48,18 @@ #define DRV_NAME "sata-dwc" #define DRV_VERSION "1.3" +#ifndef out_le32 +#define out_le32(a, v) __raw_writel(__cpu_to_le32(v), (void __iomem *)(a)) +#endif + +#ifndef in_le32 +#define in_le32(a) __le32_to_cpu(__raw_readl((void __iomem *)(a))) +#endif + +#ifndef NO_IRQ +#define NO_IRQ 0 +#endif + /* SATA DMA driver Globals */ #define DMA_NUM_CHANS 1 #define DMA_NUM_CHAN_REGS 8 @@ -273,7 +285,7 @@ struct sata_dwc_device { struct device *dev; /* generic device struct */ struct ata_probe_ent *pe; /* ptr to probe-ent */ struct ata_host *host; - u8 *reg_base; + u8 __iomem *reg_base; struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */ int irq_dma; }; @@ -323,7 +335,9 @@ struct sata_dwc_host_priv { struct device *dwc_dev; int dma_channel; }; -struct sata_dwc_host_priv host_pvt; + +static struct sata_dwc_host_priv host_pvt; + /* * Prototypes */ @@ -580,9 +594,9 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems, sms_val = 0; dms_val = 1 + host_pvt.dma_channel; - dev_dbg(host_pvt.dwc_dev, "%s: sg=%p nelem=%d lli=%p dma_lli=0x%08x" - " dmadr=0x%08x\n", __func__, sg, num_elems, lli, (u32)dma_lli, - (u32)dmadr_addr); + dev_dbg(host_pvt.dwc_dev, + "%s: sg=%p nelem=%d lli=%p dma_lli=0x%pad dmadr=0x%p\n", + __func__, sg, num_elems, lli, &dma_lli, dmadr_addr); bl = get_burst_length_encode(AHB_DMA_BRST_DFLT); @@ -773,7 +787,7 @@ static void dma_dwc_exit(struct sata_dwc_device *hsdev) { dev_dbg(host_pvt.dwc_dev, "%s:\n", __func__); if (host_pvt.sata_dma_regs) { - iounmap(host_pvt.sata_dma_regs); + iounmap((void __iomem *)host_pvt.sata_dma_regs); host_pvt.sata_dma_regs = NULL; } @@ -797,7 +811,7 @@ static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq) if (err) { dev_err(host_pvt.dwc_dev, "%s: dma_request_interrupts returns" " %d\n", __func__, err); - goto error_out; + return err; } /* Enabe DMA */ @@ -808,11 +822,6 @@ static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq) sata_dma_regs); return 0; - -error_out: - dma_dwc_exit(hsdev); - - return err; } static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val) @@ -823,7 +832,7 @@ static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val) return -EINVAL; } - *val = in_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4)); + *val = in_le32(link->ap->ioaddr.scr_addr + (scr * 4)); dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n", __func__, link->ap->print_id, scr, *val); @@ -839,21 +848,19 @@ static int sata_dwc_scr_write(struct ata_link *link, unsigned int scr, u32 val) __func__, scr); return -EINVAL; } - out_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4), val); + out_le32(link->ap->ioaddr.scr_addr + (scr * 4), val); return 0; } static u32 core_scr_read(unsigned int scr) { - return in_le32((void __iomem *)(host_pvt.scr_addr_sstatus) +\ - (scr * 4)); + return in_le32(host_pvt.scr_addr_sstatus + (scr * 4)); } static void core_scr_write(unsigned int scr, u32 val) { - out_le32((void __iomem *)(host_pvt.scr_addr_sstatus) + (scr * 4), - val); + out_le32(host_pvt.scr_addr_sstatus + (scr * 4), val); } static void clear_serror(void) @@ -861,7 +868,6 @@ static void clear_serror(void) u32 val; val = core_scr_read(SCR_ERROR); core_scr_write(SCR_ERROR, val); - } static void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit) @@ -1261,24 +1267,24 @@ static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev) static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long base) { - port->cmd_addr = (void *)base + 0x00; - port->data_addr = (void *)base + 0x00; + port->cmd_addr = (void __iomem *)base + 0x00; + port->data_addr = (void __iomem *)base + 0x00; - port->error_addr = (void *)base + 0x04; - port->feature_addr = (void *)base + 0x04; + port->error_addr = (void __iomem *)base + 0x04; + port->feature_addr = (void __iomem *)base + 0x04; - port->nsect_addr = (void *)base + 0x08; + port->nsect_addr = (void __iomem *)base + 0x08; - port->lbal_addr = (void *)base + 0x0c; - port->lbam_addr = (void *)base + 0x10; - port->lbah_addr = (void *)base + 0x14; + port->lbal_addr = (void __iomem *)base + 0x0c; + port->lbam_addr = (void __iomem *)base + 0x10; + port->lbah_addr = (void __iomem *)base + 0x14; - port->device_addr = (void *)base + 0x18; - port->command_addr = (void *)base + 0x1c; - port->status_addr = (void *)base + 0x1c; + port->device_addr = (void __iomem *)base + 0x18; + port->command_addr = (void __iomem *)base + 0x1c; + port->status_addr = (void __iomem *)base + 0x1c; - port->altstatus_addr = (void *)base + 0x20; - port->ctl_addr = (void *)base + 0x20; + port->altstatus_addr = (void __iomem *)base + 0x20; + port->ctl_addr = (void __iomem *)base + 0x20; } /* @@ -1319,7 +1325,7 @@ static int sata_dwc_port_start(struct ata_port *ap) for (i = 0; i < SATA_DWC_QCMD_MAX; i++) hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; - ap->bmdma_prd = 0; /* set these so libata doesn't use them */ + ap->bmdma_prd = NULL; /* set these so libata doesn't use them */ ap->bmdma_prd_dma = 0; /* @@ -1516,8 +1522,8 @@ static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag) dma_chan = dma_dwc_xfer_setup(sg, qc->n_elem, hsdevp->llit[tag], hsdevp->llit_dma[tag], - (void *__iomem)(&hsdev->sata_dwc_regs->\ - dmadr), qc->dma_dir); + (void __iomem *)&hsdev->sata_dwc_regs->dmadr, + qc->dma_dir); if (dma_chan < 0) { dev_err(ap->dev, "%s: dma_dwc_xfer_setup returns err %d\n", __func__, dma_chan); @@ -1590,8 +1596,8 @@ static void sata_dwc_error_handler(struct ata_port *ap) ata_sff_error_handler(ap); } -int sata_dwc_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) +static int sata_dwc_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) { struct sata_dwc_device *hsdev = HSDEV_FROM_AP(link->ap); int ret; @@ -1623,7 +1629,7 @@ static struct scsi_host_template sata_dwc_sht = { * max of 1. This will get fixed in in a future release. */ .sg_tablesize = LIBATA_MAX_PRD, - .can_queue = ATA_DEF_QUEUE, /* ATA_MAX_QUEUE */ + /* .can_queue = ATA_MAX_QUEUE, */ .dma_boundary = ATA_DMA_BOUNDARY, }; @@ -1660,9 +1666,9 @@ static int sata_dwc_probe(struct platform_device *ofdev) struct sata_dwc_device *hsdev; u32 idr, versionr; char *ver = (char *)&versionr; - u8 *base = NULL; + u8 __iomem *base; int err = 0; - int irq, rc; + int irq; struct ata_host *host; struct ata_port_info pi = sata_dwc_port_info[0]; const struct ata_port_info *ppi[] = { &pi, NULL }; @@ -1670,12 +1676,12 @@ static int sata_dwc_probe(struct platform_device *ofdev) u32 dma_chan; /* Allocate DWC SATA device */ - hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL); - if (hsdev == NULL) { - dev_err(&ofdev->dev, "kmalloc failed for hsdev\n"); - err = -ENOMEM; - goto error; - } + host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_DWC_MAX_PORTS); + hsdev = devm_kzalloc(&ofdev->dev, sizeof(*hsdev), GFP_KERNEL); + if (!host || !hsdev) + return -ENOMEM; + + host->private_data = hsdev; if (of_property_read_u32(np, "dma-channel", &dma_chan)) { dev_warn(&ofdev->dev, "no dma-channel property set." @@ -1685,12 +1691,11 @@ static int sata_dwc_probe(struct platform_device *ofdev) host_pvt.dma_channel = dma_chan; /* Ioremap SATA registers */ - base = of_iomap(ofdev->dev.of_node, 0); + base = of_iomap(np, 0); if (!base) { dev_err(&ofdev->dev, "ioremap failed for SATA register" " address\n"); - err = -ENODEV; - goto error_kmalloc; + return -ENODEV; } hsdev->reg_base = base; dev_dbg(&ofdev->dev, "ioremap done for SATA register address\n"); @@ -1698,16 +1703,6 @@ static int sata_dwc_probe(struct platform_device *ofdev) /* Synopsys DWC SATA specific Registers */ hsdev->sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); - /* Allocate and fill host */ - host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_DWC_MAX_PORTS); - if (!host) { - dev_err(&ofdev->dev, "ata_host_alloc_pinfo failed\n"); - err = -ENOMEM; - goto error_iomap; - } - - host->private_data = hsdev; - /* Setup port */ host->ports[0]->ioaddr.cmd_addr = base; host->ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; @@ -1721,33 +1716,35 @@ static int sata_dwc_probe(struct platform_device *ofdev) idr, ver[0], ver[1], ver[2]); /* Get SATA DMA interrupt number */ - irq = irq_of_parse_and_map(ofdev->dev.of_node, 1); + irq = irq_of_parse_and_map(np, 1); if (irq == NO_IRQ) { dev_err(&ofdev->dev, "no SATA DMA irq\n"); err = -ENODEV; - goto error_out; + goto error_iomap; } /* Get physical SATA DMA register base address */ - host_pvt.sata_dma_regs = of_iomap(ofdev->dev.of_node, 1); + host_pvt.sata_dma_regs = (void *)of_iomap(np, 1); if (!(host_pvt.sata_dma_regs)) { dev_err(&ofdev->dev, "ioremap failed for AHBDMA register" " address\n"); err = -ENODEV; - goto error_out; + goto error_iomap; } /* Save dev for later use in dev_xxx() routines */ host_pvt.dwc_dev = &ofdev->dev; /* Initialize AHB DMAC */ - dma_dwc_init(hsdev, irq); + err = dma_dwc_init(hsdev, irq); + if (err) + goto error_dma_iomap; /* Enable SATA Interrupts */ sata_dwc_enable_interrupts(hsdev); /* Get SATA interrupt number */ - irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); + irq = irq_of_parse_and_map(np, 0); if (irq == NO_IRQ) { dev_err(&ofdev->dev, "no SATA DMA irq\n"); err = -ENODEV; @@ -1759,9 +1756,8 @@ static int sata_dwc_probe(struct platform_device *ofdev) * device discovery process, invoking our port_start() handler & * error_handler() to execute a dummy Softreset EH session */ - rc = ata_host_activate(host, irq, sata_dwc_isr, 0, &sata_dwc_sht); - - if (rc != 0) + err = ata_host_activate(host, irq, sata_dwc_isr, 0, &sata_dwc_sht); + if (err) dev_err(&ofdev->dev, "failed to activate host"); dev_set_drvdata(&ofdev->dev, host); @@ -1770,12 +1766,10 @@ static int sata_dwc_probe(struct platform_device *ofdev) error_out: /* Free SATA DMA resources */ dma_dwc_exit(hsdev); - +error_dma_iomap: + iounmap((void __iomem *)host_pvt.sata_dma_regs); error_iomap: iounmap(base); -error_kmalloc: - kfree(hsdev); -error: return err; } @@ -1786,14 +1780,12 @@ static int sata_dwc_remove(struct platform_device *ofdev) struct sata_dwc_device *hsdev = host->private_data; ata_host_detach(host); - dev_set_drvdata(dev, NULL); /* Free SATA DMA resources */ dma_dwc_exit(hsdev); + iounmap((void __iomem *)host_pvt.sata_dma_regs); iounmap(hsdev->reg_base); - kfree(hsdev); - kfree(host); dev_dbg(&ofdev->dev, "done\n"); return 0; } diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index f9a0e34eb111..f8c33e3772b8 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -4185,8 +4185,7 @@ err: clk_disable_unprepare(hpriv->port_clks[port]); clk_put(hpriv->port_clks[port]); } - if (hpriv->port_phys[port]) - phy_power_off(hpriv->port_phys[port]); + phy_power_off(hpriv->port_phys[port]); } return rc; @@ -4216,8 +4215,7 @@ static int mv_platform_remove(struct platform_device *pdev) clk_disable_unprepare(hpriv->port_clks[port]); clk_put(hpriv->port_clks[port]); } - if (hpriv->port_phys[port]) - phy_power_off(hpriv->port_phys[port]); + phy_power_off(hpriv->port_phys[port]); } return 0; } diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index cb0d2e644af5..d49a5193b7de 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -2,8 +2,8 @@ * Renesas R-Car SATA driver * * Author: Vladimir Barinov - * Copyright (C) 2013 Cogent Embedded, Inc. - * Copyright (C) 2013 Renesas Solutions Corp. + * Copyright (C) 2013-2015 Cogent Embedded, Inc. + * Copyright (C) 2013-2015 Renesas Solutions 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 @@ -992,9 +992,30 @@ static int sata_rcar_resume(struct device *dev) return 0; } +static int sata_rcar_restore(struct device *dev) +{ + struct ata_host *host = dev_get_drvdata(dev); + struct sata_rcar_priv *priv = host->private_data; + + clk_prepare_enable(priv->clk); + + sata_rcar_setup_port(host); + + /* initialize host controller */ + sata_rcar_init_controller(host); + + ata_host_resume(host); + + return 0; +} + static const struct dev_pm_ops sata_rcar_pm_ops = { .suspend = sata_rcar_suspend, .resume = sata_rcar_resume, + .freeze = sata_rcar_suspend, + .thaw = sata_rcar_resume, + .poweroff = sata_rcar_suspend, + .restore = sata_rcar_restore, }; #endif diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index d81b20ddb527..ea655949023f 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -246,7 +246,7 @@ enum { /* host flags */ SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA | - ATA_FLAG_AN | ATA_FLAG_PMP, + ATA_FLAG_AN | ATA_FLAG_PMP | ATA_FLAG_LOWTAG, SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */ IRQ_STAT_4PORTS = 0xf, diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index c7fab3ee14ee..6339efd32697 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -354,9 +354,9 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, eni_vcc = ENI_VCC(vcc); paddr = 0; /* GCC, shut up */ if (skb) { - paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len, - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(eni_dev->pci_dev, paddr)) + paddr = dma_map_single(&eni_dev->pci_dev->dev,skb->data,skb->len, + DMA_FROM_DEVICE); + if (dma_mapping_error(&eni_dev->pci_dev->dev, paddr)) goto dma_map_error; ENI_PRV_PADDR(skb) = paddr; if (paddr & 3) @@ -481,8 +481,8 @@ rx_enqueued++; trouble: if (paddr) - pci_unmap_single(eni_dev->pci_dev,paddr,skb->len, - PCI_DMA_FROMDEVICE); + dma_unmap_single(&eni_dev->pci_dev->dev,paddr,skb->len, + DMA_FROM_DEVICE); dma_map_error: if (skb) dev_kfree_skb_irq(skb); return -1; @@ -758,8 +758,8 @@ rx_dequeued++; } eni_vcc->rxing--; eni_vcc->rx_pos = ENI_PRV_POS(skb) & (eni_vcc->words-1); - pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len, - PCI_DMA_TODEVICE); + dma_unmap_single(&eni_dev->pci_dev->dev,ENI_PRV_PADDR(skb),skb->len, + DMA_TO_DEVICE); if (!skb->len) dev_kfree_skb_irq(skb); else { EVENT("pushing (len=%ld)\n",skb->len,0); @@ -1112,8 +1112,8 @@ DPRINTK("iovcnt = %d\n",skb_shinfo(skb)->nr_frags); vcc->dev->number); return enq_jam; } - paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len, - PCI_DMA_TODEVICE); + paddr = dma_map_single(&eni_dev->pci_dev->dev,skb->data,skb->len, + DMA_TO_DEVICE); ENI_PRV_PADDR(skb) = paddr; /* prepare DMA queue entries */ j = 0; @@ -1226,8 +1226,8 @@ static void dequeue_tx(struct atm_dev *dev) break; } ENI_VCC(vcc)->txing -= ENI_PRV_SIZE(skb); - pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len, - PCI_DMA_TODEVICE); + dma_unmap_single(&eni_dev->pci_dev->dev,ENI_PRV_PADDR(skb),skb->len, + DMA_TO_DEVICE); if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb_irq(skb); atomic_inc(&vcc->stats->tx); @@ -2240,13 +2240,18 @@ static int eni_init_one(struct pci_dev *pci_dev, if (rc < 0) goto out; + rc = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32)); + if (rc < 0) + goto out; + rc = -ENOMEM; eni_dev = kmalloc(sizeof(struct eni_dev), GFP_KERNEL); if (!eni_dev) goto err_disable; zero = &eni_dev->zero; - zero->addr = pci_alloc_consistent(pci_dev, ENI_ZEROES_SIZE, &zero->dma); + zero->addr = dma_alloc_coherent(&pci_dev->dev, + ENI_ZEROES_SIZE, &zero->dma, GFP_KERNEL); if (!zero->addr) goto err_kfree; @@ -2277,7 +2282,7 @@ err_eni_release: err_unregister: atm_dev_deregister(dev); err_free_consistent: - pci_free_consistent(pci_dev, ENI_ZEROES_SIZE, zero->addr, zero->dma); + dma_free_coherent(&pci_dev->dev, ENI_ZEROES_SIZE, zero->addr, zero->dma); err_kfree: kfree(eni_dev); err_disable: @@ -2302,7 +2307,7 @@ static void eni_remove_one(struct pci_dev *pdev) eni_do_release(dev); atm_dev_deregister(dev); - pci_free_consistent(pdev, ENI_ZEROES_SIZE, zero->addr, zero->dma); + dma_free_coherent(&pdev->dev, ENI_ZEROES_SIZE, zero->addr, zero->dma); kfree(ed); pci_disable_device(pdev); } diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index d5d9eafbbfcf..75dde903b238 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -425,7 +425,7 @@ static void fore200e_pca_write(u32 val, volatile u32 __iomem *addr) static u32 fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction) { - u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, direction); + u32 dma_addr = dma_map_single(&((struct pci_dev *) fore200e->bus_dev)->dev, virt_addr, size, direction); DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d, --> dma_addr = 0x%08x\n", virt_addr, size, direction, dma_addr); @@ -440,7 +440,7 @@ fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int di DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction); + dma_unmap_single(&((struct pci_dev *) fore200e->bus_dev)->dev, dma_addr, size, direction); } @@ -449,7 +449,7 @@ fore200e_pca_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, { DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - pci_dma_sync_single_for_cpu((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction); + dma_sync_single_for_cpu(&((struct pci_dev *) fore200e->bus_dev)->dev, dma_addr, size, direction); } static void @@ -457,7 +457,7 @@ fore200e_pca_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int si { DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - pci_dma_sync_single_for_device((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction); + dma_sync_single_for_device(&((struct pci_dev *) fore200e->bus_dev)->dev, dma_addr, size, direction); } @@ -470,9 +470,10 @@ fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, { /* returned chunks are page-aligned */ chunk->alloc_size = size * nbr; - chunk->alloc_addr = pci_alloc_consistent((struct pci_dev*)fore200e->bus_dev, - chunk->alloc_size, - &chunk->dma_addr); + chunk->alloc_addr = dma_alloc_coherent(&((struct pci_dev *) fore200e->bus_dev)->dev, + chunk->alloc_size, + &chunk->dma_addr, + GFP_KERNEL); if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0)) return -ENOMEM; @@ -488,7 +489,7 @@ fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, static void fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) { - pci_free_consistent((struct pci_dev*)fore200e->bus_dev, + dma_free_coherent(&((struct pci_dev *) fore200e->bus_dev)->dev, chunk->alloc_size, chunk->alloc_addr, chunk->dma_addr); @@ -2707,6 +2708,11 @@ static int fore200e_pca_detect(struct pci_dev *pci_dev, err = -EINVAL; goto out; } + + if (dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32))) { + err = -EINVAL; + goto out; + } fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL); if (fore200e == NULL) { diff --git a/drivers/atm/he.c b/drivers/atm/he.c index c39702bc279d..93dca2e73bf5 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -359,7 +359,7 @@ static int he_init_one(struct pci_dev *pci_dev, if (pci_enable_device(pci_dev)) return -EIO; - if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)) != 0) { + if (dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32)) != 0) { printk(KERN_WARNING "he: no suitable dma available\n"); err = -EIO; goto init_one_failure; @@ -533,9 +533,9 @@ static void he_init_tx_lbfp(struct he_dev *he_dev) static int he_init_tpdrq(struct he_dev *he_dev) { - he_dev->tpdrq_base = pci_zalloc_consistent(he_dev->pci_dev, - CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), - &he_dev->tpdrq_phys); + he_dev->tpdrq_base = dma_zalloc_coherent(&he_dev->pci_dev->dev, + CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), + &he_dev->tpdrq_phys, GFP_KERNEL); if (he_dev->tpdrq_base == NULL) { hprintk("failed to alloc tpdrq\n"); return -ENOMEM; @@ -796,16 +796,16 @@ static int he_init_group(struct he_dev *he_dev, int group) } /* large buffer pool */ - he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev, + he_dev->rbpl_pool = dma_pool_create("rbpl", &he_dev->pci_dev->dev, CONFIG_RBPL_BUFSIZE, 64, 0); if (he_dev->rbpl_pool == NULL) { hprintk("unable to create rbpl pool\n"); goto out_free_rbpl_virt; } - he_dev->rbpl_base = pci_zalloc_consistent(he_dev->pci_dev, - CONFIG_RBPL_SIZE * sizeof(struct he_rbp), - &he_dev->rbpl_phys); + he_dev->rbpl_base = dma_zalloc_coherent(&he_dev->pci_dev->dev, + CONFIG_RBPL_SIZE * sizeof(struct he_rbp), + &he_dev->rbpl_phys, GFP_KERNEL); if (he_dev->rbpl_base == NULL) { hprintk("failed to alloc rbpl_base\n"); goto out_destroy_rbpl_pool; @@ -815,7 +815,7 @@ static int he_init_group(struct he_dev *he_dev, int group) for (i = 0; i < CONFIG_RBPL_SIZE; ++i) { - heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &mapping); + heb = dma_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL, &mapping); if (!heb) goto out_free_rbpl; heb->mapping = mapping; @@ -842,9 +842,9 @@ static int he_init_group(struct he_dev *he_dev, int group) /* rx buffer ready queue */ - he_dev->rbrq_base = pci_zalloc_consistent(he_dev->pci_dev, - CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), - &he_dev->rbrq_phys); + he_dev->rbrq_base = dma_zalloc_coherent(&he_dev->pci_dev->dev, + CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), + &he_dev->rbrq_phys, GFP_KERNEL); if (he_dev->rbrq_base == NULL) { hprintk("failed to allocate rbrq\n"); goto out_free_rbpl; @@ -866,9 +866,9 @@ static int he_init_group(struct he_dev *he_dev, int group) /* tx buffer ready queue */ - he_dev->tbrq_base = pci_zalloc_consistent(he_dev->pci_dev, - CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), - &he_dev->tbrq_phys); + he_dev->tbrq_base = dma_zalloc_coherent(&he_dev->pci_dev->dev, + CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), + &he_dev->tbrq_phys, GFP_KERNEL); if (he_dev->tbrq_base == NULL) { hprintk("failed to allocate tbrq\n"); goto out_free_rbpq_base; @@ -884,18 +884,18 @@ static int he_init_group(struct he_dev *he_dev, int group) return 0; out_free_rbpq_base: - pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * - sizeof(struct he_rbrq), he_dev->rbrq_base, - he_dev->rbrq_phys); + dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBRQ_SIZE * + sizeof(struct he_rbrq), he_dev->rbrq_base, + he_dev->rbrq_phys); out_free_rbpl: list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry) - pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping); + dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping); - pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE * - sizeof(struct he_rbp), he_dev->rbpl_base, - he_dev->rbpl_phys); + dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBPL_SIZE * + sizeof(struct he_rbp), he_dev->rbpl_base, + he_dev->rbpl_phys); out_destroy_rbpl_pool: - pci_pool_destroy(he_dev->rbpl_pool); + dma_pool_destroy(he_dev->rbpl_pool); out_free_rbpl_virt: kfree(he_dev->rbpl_virt); out_free_rbpl_table: @@ -911,8 +911,11 @@ static int he_init_irq(struct he_dev *he_dev) /* 2.9.3.5 tail offset for each interrupt queue is located after the end of the interrupt queue */ - he_dev->irq_base = pci_alloc_consistent(he_dev->pci_dev, - (CONFIG_IRQ_SIZE+1) * sizeof(struct he_irq), &he_dev->irq_phys); + he_dev->irq_base = dma_zalloc_coherent(&he_dev->pci_dev->dev, + (CONFIG_IRQ_SIZE + 1) + * sizeof(struct he_irq), + &he_dev->irq_phys, + GFP_KERNEL); if (he_dev->irq_base == NULL) { hprintk("failed to allocate irq\n"); return -ENOMEM; @@ -1419,10 +1422,10 @@ static int he_start(struct atm_dev *dev) he_init_tpdrq(he_dev); - he_dev->tpd_pool = pci_pool_create("tpd", he_dev->pci_dev, - sizeof(struct he_tpd), TPD_ALIGNMENT, 0); + he_dev->tpd_pool = dma_pool_create("tpd", &he_dev->pci_dev->dev, + sizeof(struct he_tpd), TPD_ALIGNMENT, 0); if (he_dev->tpd_pool == NULL) { - hprintk("unable to create tpd pci_pool\n"); + hprintk("unable to create tpd dma_pool\n"); return -ENOMEM; } @@ -1459,9 +1462,9 @@ static int he_start(struct atm_dev *dev) /* host status page */ - he_dev->hsp = pci_zalloc_consistent(he_dev->pci_dev, - sizeof(struct he_hsp), - &he_dev->hsp_phys); + he_dev->hsp = dma_zalloc_coherent(&he_dev->pci_dev->dev, + sizeof(struct he_hsp), + &he_dev->hsp_phys, GFP_KERNEL); if (he_dev->hsp == NULL) { hprintk("failed to allocate host status page\n"); return -ENOMEM; @@ -1558,41 +1561,41 @@ he_stop(struct he_dev *he_dev) free_irq(he_dev->irq, he_dev); if (he_dev->irq_base) - pci_free_consistent(he_dev->pci_dev, (CONFIG_IRQ_SIZE+1) - * sizeof(struct he_irq), he_dev->irq_base, he_dev->irq_phys); + dma_free_coherent(&he_dev->pci_dev->dev, (CONFIG_IRQ_SIZE + 1) + * sizeof(struct he_irq), he_dev->irq_base, he_dev->irq_phys); if (he_dev->hsp) - pci_free_consistent(he_dev->pci_dev, sizeof(struct he_hsp), - he_dev->hsp, he_dev->hsp_phys); + dma_free_coherent(&he_dev->pci_dev->dev, sizeof(struct he_hsp), + he_dev->hsp, he_dev->hsp_phys); if (he_dev->rbpl_base) { list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry) - pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping); + dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping); - pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE - * sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys); + dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBPL_SIZE + * sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys); } kfree(he_dev->rbpl_virt); kfree(he_dev->rbpl_table); if (he_dev->rbpl_pool) - pci_pool_destroy(he_dev->rbpl_pool); + dma_pool_destroy(he_dev->rbpl_pool); if (he_dev->rbrq_base) - pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), - he_dev->rbrq_base, he_dev->rbrq_phys); + dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), + he_dev->rbrq_base, he_dev->rbrq_phys); if (he_dev->tbrq_base) - pci_free_consistent(he_dev->pci_dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), - he_dev->tbrq_base, he_dev->tbrq_phys); + dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), + he_dev->tbrq_base, he_dev->tbrq_phys); if (he_dev->tpdrq_base) - pci_free_consistent(he_dev->pci_dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), - he_dev->tpdrq_base, he_dev->tpdrq_phys); + dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), + he_dev->tpdrq_base, he_dev->tpdrq_phys); if (he_dev->tpd_pool) - pci_pool_destroy(he_dev->tpd_pool); + dma_pool_destroy(he_dev->tpd_pool); if (he_dev->pci_dev) { pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command); @@ -1610,7 +1613,7 @@ __alloc_tpd(struct he_dev *he_dev) struct he_tpd *tpd; dma_addr_t mapping; - tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|GFP_DMA, &mapping); + tpd = dma_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC, &mapping); if (tpd == NULL) return NULL; @@ -1681,7 +1684,7 @@ he_service_rbrq(struct he_dev *he_dev, int group) if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) { clear_bit(i, he_dev->rbpl_table); list_del(&heb->entry); - pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping); + dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping); } goto next_rbrq_entry; @@ -1774,7 +1777,7 @@ return_host_buffers: ++pdus_assembled; list_for_each_entry_safe(heb, next, &he_vcc->buffers, entry) - pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping); + dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping); INIT_LIST_HEAD(&he_vcc->buffers); he_vcc->pdu_len = 0; @@ -1843,10 +1846,10 @@ he_service_tbrq(struct he_dev *he_dev, int group) for (slot = 0; slot < TPD_MAXIOV; ++slot) { if (tpd->iovec[slot].addr) - pci_unmap_single(he_dev->pci_dev, + dma_unmap_single(&he_dev->pci_dev->dev, tpd->iovec[slot].addr, tpd->iovec[slot].len & TPD_LEN_MASK, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); if (tpd->iovec[slot].len & TPD_LST) break; @@ -1861,7 +1864,7 @@ he_service_tbrq(struct he_dev *he_dev, int group) next_tbrq_entry: if (tpd) - pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); + dma_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 + 1)); @@ -1905,7 +1908,7 @@ he_service_rbpl(struct he_dev *he_dev, int group) } he_dev->rbpl_hint = i + 1; - heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_ATOMIC|GFP_DMA, &mapping); + heb = dma_pool_alloc(he_dev->rbpl_pool, GFP_ATOMIC, &mapping); if (!heb) break; heb->mapping = mapping; @@ -2084,10 +2087,10 @@ __enqueue_tpd(struct he_dev *he_dev, struct he_tpd *tpd, unsigned cid) */ for (slot = 0; slot < TPD_MAXIOV; ++slot) { if (tpd->iovec[slot].addr) - pci_unmap_single(he_dev->pci_dev, + dma_unmap_single(&he_dev->pci_dev->dev, tpd->iovec[slot].addr, tpd->iovec[slot].len & TPD_LEN_MASK, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); } if (tpd->skb) { if (tpd->vcc->pop) @@ -2096,7 +2099,7 @@ __enqueue_tpd(struct he_dev *he_dev, struct he_tpd *tpd, unsigned cid) dev_kfree_skb_any(tpd->skb); atomic_inc(&tpd->vcc->stats->tx_err); } - pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); + dma_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); return; } } @@ -2550,8 +2553,8 @@ he_send(struct atm_vcc *vcc, struct sk_buff *skb) } #ifdef USE_SCATTERGATHER - tpd->iovec[slot].addr = pci_map_single(he_dev->pci_dev, skb->data, - skb_headlen(skb), PCI_DMA_TODEVICE); + tpd->iovec[slot].addr = dma_map_single(&he_dev->pci_dev->dev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); tpd->iovec[slot].len = skb_headlen(skb); ++slot; @@ -2579,9 +2582,9 @@ he_send(struct atm_vcc *vcc, struct sk_buff *skb) slot = 0; } - tpd->iovec[slot].addr = pci_map_single(he_dev->pci_dev, + tpd->iovec[slot].addr = dma_map_single(&he_dev->pci_dev->dev, (void *) page_address(frag->page) + frag->page_offset, - frag->size, PCI_DMA_TODEVICE); + frag->size, DMA_TO_DEVICE); tpd->iovec[slot].len = frag->size; ++slot; @@ -2589,7 +2592,7 @@ he_send(struct atm_vcc *vcc, struct sk_buff *skb) tpd->iovec[slot - 1].len |= TPD_LST; #else - tpd->address0 = pci_map_single(he_dev->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); + tpd->address0 = dma_map_single(&he_dev->pci_dev->dev, skb->data, skb->len, DMA_TO_DEVICE); tpd->length0 = skb->len | TPD_LST; #endif tpd->status |= TPD_INT; diff --git a/drivers/atm/he.h b/drivers/atm/he.h index 110a27d2ecfc..f3f53674ef3f 100644 --- a/drivers/atm/he.h +++ b/drivers/atm/he.h @@ -281,7 +281,7 @@ struct he_dev { int irq_peak; struct tasklet_struct tasklet; - struct pci_pool *tpd_pool; + struct dma_pool *tpd_pool; struct list_head outstanding_tpds; dma_addr_t tpdrq_phys; @@ -296,7 +296,7 @@ struct he_dev { struct he_buff **rbpl_virt; unsigned long *rbpl_table; unsigned long rbpl_hint; - struct pci_pool *rbpl_pool; + struct dma_pool *rbpl_pool; dma_addr_t rbpl_phys; struct he_rbp *rbpl_base, *rbpl_tail; struct list_head rbpl_outstanding; diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 1dc0519333f2..527bbd595e37 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -458,12 +458,6 @@ static inline void update_tx_channel_config (hrz_dev * dev, short chan, u8 mode, return; } -static inline u16 query_tx_channel_config (hrz_dev * dev, short chan, u8 mode) { - wr_regw (dev, TX_CHANNEL_CONFIG_COMMAND_OFF, - chan * TX_CHANNEL_CONFIG_MULT | mode); - return rd_regw (dev, TX_CHANNEL_CONFIG_DATA_OFF); -} - /********** dump functions **********/ static inline void dump_skb (char * prefix, unsigned int vc, struct sk_buff * skb) { @@ -513,16 +507,6 @@ static inline void dump_framer (hrz_dev * dev) { /* RX channels are 10 bit integers, these fns are quite paranoid */ -static inline int channel_to_vpivci (const u16 channel, short * vpi, int * vci) { - unsigned short vci_bits = 10 - vpi_bits; - if ((channel & RX_CHANNEL_MASK) == channel) { - *vci = channel & ((~0)<> vci_bits; - return channel ? 0 : -EINVAL; - } - return -EINVAL; -} - static inline int vpivci_to_channel (u16 * channel, const short vpi, const int vci) { unsigned short vci_bits = 10 - vpi_bits; if (0 <= vpi && vpi < 1<base = pci_zalloc_consistent(card->pcidev, SCQ_SIZE, &scq->paddr); + scq->base = dma_zalloc_coherent(&card->pcidev->dev, SCQ_SIZE, + &scq->paddr, GFP_KERNEL); if (scq->base == NULL) { kfree(scq); return NULL; @@ -669,12 +670,12 @@ free_scq(struct idt77252_dev *card, struct scq_info *scq) struct sk_buff *skb; struct atm_vcc *vcc; - pci_free_consistent(card->pcidev, SCQ_SIZE, - scq->base, scq->paddr); + dma_free_coherent(&card->pcidev->dev, SCQ_SIZE, + scq->base, scq->paddr); while ((skb = skb_dequeue(&scq->transmit))) { - pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), - skb->len, PCI_DMA_TODEVICE); + dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), + skb->len, DMA_TO_DEVICE); vcc = ATM_SKB(skb)->vcc; if (vcc->pop) @@ -684,8 +685,8 @@ free_scq(struct idt77252_dev *card, struct scq_info *scq) } while ((skb = skb_dequeue(&scq->pending))) { - pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), - skb->len, PCI_DMA_TODEVICE); + dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), + skb->len, DMA_TO_DEVICE); vcc = ATM_SKB(skb)->vcc; if (vcc->pop) @@ -800,8 +801,8 @@ drain_scq(struct idt77252_dev *card, struct vc_map *vc) if (skb) { TXPRINTK("%s: freeing skb at %p.\n", card->name, skb); - pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), - skb->len, PCI_DMA_TODEVICE); + dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), + skb->len, DMA_TO_DEVICE); vcc = ATM_SKB(skb)->vcc; @@ -846,8 +847,8 @@ queue_skb(struct idt77252_dev *card, struct vc_map *vc, tbd = &IDT77252_PRV_TBD(skb); vcc = ATM_SKB(skb)->vcc; - IDT77252_PRV_PADDR(skb) = pci_map_single(card->pcidev, skb->data, - skb->len, PCI_DMA_TODEVICE); + IDT77252_PRV_PADDR(skb) = dma_map_single(&card->pcidev->dev, skb->data, + skb->len, DMA_TO_DEVICE); error = -EINVAL; @@ -924,8 +925,8 @@ done: return 0; errout: - pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), - skb->len, PCI_DMA_TODEVICE); + dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), + skb->len, DMA_TO_DEVICE); return error; } @@ -970,8 +971,8 @@ init_rsq(struct idt77252_dev *card) { struct rsq_entry *rsqe; - card->rsq.base = pci_zalloc_consistent(card->pcidev, RSQSIZE, - &card->rsq.paddr); + card->rsq.base = dma_zalloc_coherent(&card->pcidev->dev, RSQSIZE, + &card->rsq.paddr, GFP_KERNEL); if (card->rsq.base == NULL) { printk("%s: can't allocate RSQ.\n", card->name); return -1; @@ -1001,8 +1002,8 @@ init_rsq(struct idt77252_dev *card) static void deinit_rsq(struct idt77252_dev *card) { - pci_free_consistent(card->pcidev, RSQSIZE, - card->rsq.base, card->rsq.paddr); + dma_free_coherent(&card->pcidev->dev, RSQSIZE, + card->rsq.base, card->rsq.paddr); } static void @@ -1057,9 +1058,9 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) vcc = vc->rx_vcc; - pci_dma_sync_single_for_cpu(card->pcidev, IDT77252_PRV_PADDR(skb), - skb_end_pointer(skb) - skb->data, - PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), + skb_end_pointer(skb) - skb->data, + DMA_FROM_DEVICE); if ((vcc->qos.aal == ATM_AAL0) || (vcc->qos.aal == ATM_AAL34)) { @@ -1180,9 +1181,9 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) return; } - pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), + dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), skb_end_pointer(skb) - skb->data, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); sb_pool_remove(card, skb); skb_trim(skb, len); @@ -1254,9 +1255,9 @@ idt77252_rx_raw(struct idt77252_dev *card) head = IDT77252_PRV_PADDR(queue) + (queue->data - queue->head - 16); tail = readl(SAR_REG_RAWCT); - pci_dma_sync_single_for_cpu(card->pcidev, IDT77252_PRV_PADDR(queue), - skb_end_offset(queue) - 16, - PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&card->pcidev->dev, IDT77252_PRV_PADDR(queue), + skb_end_offset(queue) - 16, + DMA_FROM_DEVICE); while (head != tail) { unsigned int vpi, vci; @@ -1348,11 +1349,11 @@ drop: if (next) { card->raw_cell_head = next; queue = card->raw_cell_head; - pci_dma_sync_single_for_cpu(card->pcidev, - IDT77252_PRV_PADDR(queue), - (skb_end_pointer(queue) - - queue->data), - PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&card->pcidev->dev, + IDT77252_PRV_PADDR(queue), + (skb_end_pointer(queue) - + queue->data), + DMA_FROM_DEVICE); } else { card->raw_cell_head = NULL; printk("%s: raw cell queue overrun\n", @@ -1375,8 +1376,8 @@ init_tsq(struct idt77252_dev *card) { struct tsq_entry *tsqe; - card->tsq.base = pci_alloc_consistent(card->pcidev, RSQSIZE, - &card->tsq.paddr); + card->tsq.base = dma_alloc_coherent(&card->pcidev->dev, RSQSIZE, + &card->tsq.paddr, GFP_KERNEL); if (card->tsq.base == NULL) { printk("%s: can't allocate TSQ.\n", card->name); return -1; @@ -1398,8 +1399,8 @@ init_tsq(struct idt77252_dev *card) static void deinit_tsq(struct idt77252_dev *card) { - pci_free_consistent(card->pcidev, TSQSIZE, - card->tsq.base, card->tsq.paddr); + dma_free_coherent(&card->pcidev->dev, TSQSIZE, + card->tsq.base, card->tsq.paddr); } static void @@ -1861,9 +1862,9 @@ add_rx_skb(struct idt77252_dev *card, int queue, goto outfree; } - paddr = pci_map_single(card->pcidev, skb->data, + paddr = dma_map_single(&card->pcidev->dev, skb->data, skb_end_pointer(skb) - skb->data, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); IDT77252_PRV_PADDR(skb) = paddr; if (push_rx_skb(card, skb, queue)) { @@ -1875,8 +1876,8 @@ add_rx_skb(struct idt77252_dev *card, int queue, return; outunmap: - pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), - skb_end_pointer(skb) - skb->data, PCI_DMA_FROMDEVICE); + dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), + skb_end_pointer(skb) - skb->data, DMA_FROM_DEVICE); handle = IDT77252_PRV_POOL(skb); card->sbpool[POOL_QUEUE(handle)].skb[POOL_INDEX(handle)] = NULL; @@ -1892,15 +1893,15 @@ recycle_rx_skb(struct idt77252_dev *card, struct sk_buff *skb) u32 handle = IDT77252_PRV_POOL(skb); int err; - pci_dma_sync_single_for_device(card->pcidev, IDT77252_PRV_PADDR(skb), - skb_end_pointer(skb) - skb->data, - PCI_DMA_FROMDEVICE); + dma_sync_single_for_device(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), + skb_end_pointer(skb) - skb->data, + DMA_FROM_DEVICE); err = push_rx_skb(card, skb, POOL_QUEUE(handle)); if (err) { - pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), + dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), skb_end_pointer(skb) - skb->data, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); sb_pool_remove(card, skb); dev_kfree_skb(skb); } @@ -3058,11 +3059,11 @@ deinit_card(struct idt77252_dev *card) for (j = 0; j < FBQ_SIZE; j++) { skb = card->sbpool[i].skb[j]; if (skb) { - pci_unmap_single(card->pcidev, + dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), (skb_end_pointer(skb) - skb->data), - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); card->sbpool[i].skb[j] = NULL; dev_kfree_skb(skb); } @@ -3076,8 +3077,8 @@ deinit_card(struct idt77252_dev *card) vfree(card->vcs); if (card->raw_cell_hnd) { - pci_free_consistent(card->pcidev, 2 * sizeof(u32), - card->raw_cell_hnd, card->raw_cell_paddr); + dma_free_coherent(&card->pcidev->dev, 2 * sizeof(u32), + card->raw_cell_hnd, card->raw_cell_paddr); } if (card->rsq.base) { @@ -3397,9 +3398,10 @@ static int init_card(struct atm_dev *dev) writel(0, SAR_REG_GP); /* Initialize RAW Cell Handle Register */ - card->raw_cell_hnd = pci_zalloc_consistent(card->pcidev, - 2 * sizeof(u32), - &card->raw_cell_paddr); + card->raw_cell_hnd = dma_zalloc_coherent(&card->pcidev->dev, + 2 * sizeof(u32), + &card->raw_cell_paddr, + GFP_KERNEL); if (!card->raw_cell_hnd) { printk("%s: memory allocation failure.\n", card->name); deinit_card(card); @@ -3611,6 +3613,11 @@ static int idt77252_init_one(struct pci_dev *pcidev, return err; } + if ((err = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32)))) { + printk("idt77252: can't enable DMA for PCI device at %s\n", pci_name(pcidev)); + return err; + } + card = kzalloc(sizeof(struct idt77252_dev), GFP_KERNEL); if (!card) { printk("idt77252-%d: can't allocate private data\n", index); diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 4217f29a85e0..924f8e26789d 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -1185,8 +1185,8 @@ static int rx_pkt(struct atm_dev *dev) /* Build the DLE structure */ wr_ptr = iadev->rx_dle_q.write; - wr_ptr->sys_pkt_addr = pci_map_single(iadev->pci, skb->data, - len, PCI_DMA_FROMDEVICE); + wr_ptr->sys_pkt_addr = dma_map_single(&iadev->pci->dev, skb->data, + len, DMA_FROM_DEVICE); wr_ptr->local_pkt_addr = buf_addr; wr_ptr->bytes = len; /* We don't know this do we ?? */ wr_ptr->mode = DMA_INT_ENABLE; @@ -1306,8 +1306,8 @@ static void rx_dle_intr(struct atm_dev *dev) u_short length; struct ia_vcc *ia_vcc; - pci_unmap_single(iadev->pci, iadev->rx_dle_q.write->sys_pkt_addr, - len, PCI_DMA_FROMDEVICE); + dma_unmap_single(&iadev->pci->dev, iadev->rx_dle_q.write->sys_pkt_addr, + len, DMA_FROM_DEVICE); /* no VCC related housekeeping done as yet. lets see */ vcc = ATM_SKB(skb)->vcc; if (!vcc) { @@ -1430,8 +1430,8 @@ static int rx_init(struct atm_dev *dev) // spin_lock_init(&iadev->rx_lock); /* Allocate 4k bytes - more aligned than needed (4k boundary) */ - dle_addr = pci_alloc_consistent(iadev->pci, DLE_TOTAL_SIZE, - &iadev->rx_dle_dma); + dle_addr = dma_alloc_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, + &iadev->rx_dle_dma, GFP_KERNEL); if (!dle_addr) { printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n"); goto err_out; @@ -1631,8 +1631,8 @@ static int rx_init(struct atm_dev *dev) return 0; err_free_dle: - pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->rx_dle_q.start, - iadev->rx_dle_dma); + dma_free_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, iadev->rx_dle_q.start, + iadev->rx_dle_dma); err_out: return -ENOMEM; } @@ -1702,8 +1702,8 @@ static void tx_dle_intr(struct atm_dev *dev) /* Revenge of the 2 dle (skb + trailer) used in ia_pkt_tx() */ if (!((dle - iadev->tx_dle_q.start)%(2*sizeof(struct dle)))) { - pci_unmap_single(iadev->pci, dle->sys_pkt_addr, skb->len, - PCI_DMA_TODEVICE); + dma_unmap_single(&iadev->pci->dev, dle->sys_pkt_addr, skb->len, + DMA_TO_DEVICE); } vcc = ATM_SKB(skb)->vcc; if (!vcc) { @@ -1917,8 +1917,8 @@ static int tx_init(struct atm_dev *dev) readw(iadev->seg_reg+SEG_MASK_REG));) /* Allocate 4k (boundary aligned) bytes */ - dle_addr = pci_alloc_consistent(iadev->pci, DLE_TOTAL_SIZE, - &iadev->tx_dle_dma); + dle_addr = dma_alloc_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, + &iadev->tx_dle_dma, GFP_KERNEL); if (!dle_addr) { printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n"); goto err_out; @@ -1989,8 +1989,10 @@ static int tx_init(struct atm_dev *dev) goto err_free_tx_bufs; } iadev->tx_buf[i].cpcs = cpcs; - iadev->tx_buf[i].dma_addr = pci_map_single(iadev->pci, - cpcs, sizeof(*cpcs), PCI_DMA_TODEVICE); + iadev->tx_buf[i].dma_addr = dma_map_single(&iadev->pci->dev, + cpcs, + sizeof(*cpcs), + DMA_TO_DEVICE); } iadev->desc_tbl = kmalloc(iadev->num_tx_desc * sizeof(struct desc_tbl_t), GFP_KERNEL); @@ -2198,14 +2200,14 @@ err_free_tx_bufs: while (--i >= 0) { struct cpcs_trailer_desc *desc = iadev->tx_buf + i; - pci_unmap_single(iadev->pci, desc->dma_addr, - sizeof(*desc->cpcs), PCI_DMA_TODEVICE); + dma_unmap_single(&iadev->pci->dev, desc->dma_addr, + sizeof(*desc->cpcs), DMA_TO_DEVICE); kfree(desc->cpcs); } kfree(iadev->tx_buf); err_free_dle: - pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->tx_dle_q.start, - iadev->tx_dle_dma); + dma_free_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, iadev->tx_dle_q.start, + iadev->tx_dle_dma); err_out: return -ENOMEM; } @@ -2476,20 +2478,20 @@ static void ia_free_tx(IADEV *iadev) for (i = 0; i < iadev->num_tx_desc; i++) { struct cpcs_trailer_desc *desc = iadev->tx_buf + i; - pci_unmap_single(iadev->pci, desc->dma_addr, - sizeof(*desc->cpcs), PCI_DMA_TODEVICE); + dma_unmap_single(&iadev->pci->dev, desc->dma_addr, + sizeof(*desc->cpcs), DMA_TO_DEVICE); kfree(desc->cpcs); } kfree(iadev->tx_buf); - pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->tx_dle_q.start, - iadev->tx_dle_dma); + dma_free_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, iadev->tx_dle_q.start, + iadev->tx_dle_dma); } static void ia_free_rx(IADEV *iadev) { kfree(iadev->rx_open); - pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->rx_dle_q.start, - iadev->rx_dle_dma); + dma_free_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, iadev->rx_dle_q.start, + iadev->rx_dle_dma); } static int ia_start(struct atm_dev *dev) @@ -3009,8 +3011,8 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) { /* Build the DLE structure */ wr_ptr = iadev->tx_dle_q.write; memset((caddr_t)wr_ptr, 0, sizeof(*wr_ptr)); - wr_ptr->sys_pkt_addr = pci_map_single(iadev->pci, skb->data, - skb->len, PCI_DMA_TODEVICE); + wr_ptr->sys_pkt_addr = dma_map_single(&iadev->pci->dev, skb->data, + skb->len, DMA_TO_DEVICE); wr_ptr->local_pkt_addr = (buf_desc_ptr->buf_start_hi << 16) | buf_desc_ptr->buf_start_lo; /* wr_ptr->bytes = swap_byte_order(total_len); didn't seem to affect?? */ diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c index 93eaf8d94492..ce43ae3e87b3 100644 --- a/drivers/atm/lanai.c +++ b/drivers/atm/lanai.c @@ -346,7 +346,8 @@ static void lanai_buf_allocate(struct lanai_buffer *buf, * everything, but the way the lanai uses DMA memory would * make that a terrific pain. This is much simpler. */ - buf->start = pci_alloc_consistent(pci, size, &buf->dmaaddr); + buf->start = dma_alloc_coherent(&pci->dev, + size, &buf->dmaaddr, GFP_KERNEL); if (buf->start != NULL) { /* Success */ /* Lanai requires 256-byte alignment of DMA bufs */ APRINTK((buf->dmaaddr & ~0xFFFFFF00) == 0, @@ -372,8 +373,8 @@ static void lanai_buf_deallocate(struct lanai_buffer *buf, struct pci_dev *pci) { if (buf->start != NULL) { - pci_free_consistent(pci, lanai_buf_size(buf), - buf->start, buf->dmaaddr); + dma_free_coherent(&pci->dev, lanai_buf_size(buf), + buf->start, buf->dmaaddr); buf->start = buf->end = buf->ptr = NULL; } } @@ -681,15 +682,6 @@ static inline int aal5_size(int size) return cells * 48; } -/* How many bytes can we send if we have "space" space, assuming we have - * to send full cells - */ -static inline int aal5_spacefor(int space) -{ - int cells = space / 48; - return cells * 48; -} - /* -------------------- FREE AN ATM SKB: */ static inline void lanai_free_skb(struct atm_vcc *atmvcc, struct sk_buff *skb) @@ -1953,12 +1945,7 @@ static int lanai_pci_start(struct lanai_dev *lanai) return -ENXIO; } pci_set_master(pci); - if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) != 0) { - printk(KERN_WARNING DEV_LABEL - "(itf %d): No suitable DMA available.\n", lanai->number); - return -EBUSY; - } - if (pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) != 0) { + if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32)) != 0) { printk(KERN_WARNING DEV_LABEL "(itf %d): No suitable DMA available.\n", lanai->number); return -EBUSY; diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index 9988ac98b6d8..b7e1cc0a97c8 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -252,10 +252,10 @@ static void nicstar_remove_one(struct pci_dev *pcidev) free_scq(card, card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc); } idr_destroy(&card->idr); - pci_free_consistent(card->pcidev, NS_RSQSIZE + NS_RSQ_ALIGNMENT, - card->rsq.org, card->rsq.dma); - pci_free_consistent(card->pcidev, NS_TSQSIZE + NS_TSQ_ALIGNMENT, - card->tsq.org, card->tsq.dma); + dma_free_coherent(&card->pcidev->dev, NS_RSQSIZE + NS_RSQ_ALIGNMENT, + card->rsq.org, card->rsq.dma); + dma_free_coherent(&card->pcidev->dev, NS_TSQSIZE + NS_TSQ_ALIGNMENT, + card->tsq.org, card->tsq.dma); free_irq(card->pcidev->irq, card); iounmap(card->membase); kfree(card); @@ -370,8 +370,7 @@ static int ns_init_card(int i, struct pci_dev *pcidev) ns_init_card_error(card, error); return error; } - if ((pci_set_dma_mask(pcidev, DMA_BIT_MASK(32)) != 0) || - (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32)) != 0)) { + if (dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32)) != 0) { printk(KERN_WARNING "nicstar%d: No suitable DMA available.\n", i); error = 2; @@ -535,9 +534,9 @@ static int ns_init_card(int i, struct pci_dev *pcidev) writel(0x00000000, card->membase + VPM); /* Initialize TSQ */ - card->tsq.org = pci_alloc_consistent(card->pcidev, - NS_TSQSIZE + NS_TSQ_ALIGNMENT, - &card->tsq.dma); + card->tsq.org = dma_alloc_coherent(&card->pcidev->dev, + NS_TSQSIZE + NS_TSQ_ALIGNMENT, + &card->tsq.dma, GFP_KERNEL); if (card->tsq.org == NULL) { printk("nicstar%d: can't allocate TSQ.\n", i); error = 10; @@ -554,9 +553,9 @@ static int ns_init_card(int i, struct pci_dev *pcidev) PRINTK("nicstar%d: TSQ base at 0x%p.\n", i, card->tsq.base); /* Initialize RSQ */ - card->rsq.org = pci_alloc_consistent(card->pcidev, - NS_RSQSIZE + NS_RSQ_ALIGNMENT, - &card->rsq.dma); + card->rsq.org = dma_alloc_coherent(&card->pcidev->dev, + NS_RSQSIZE + NS_RSQ_ALIGNMENT, + &card->rsq.dma, GFP_KERNEL); if (card->rsq.org == NULL) { printk("nicstar%d: can't allocate RSQ.\n", i); error = 11; @@ -874,7 +873,8 @@ static scq_info *get_scq(ns_dev *card, int size, u32 scd) scq = kmalloc(sizeof(scq_info), GFP_KERNEL); if (!scq) return NULL; - scq->org = pci_alloc_consistent(card->pcidev, 2 * size, &scq->dma); + scq->org = dma_alloc_coherent(&card->pcidev->dev, + 2 * size, &scq->dma, GFP_KERNEL); if (!scq->org) { kfree(scq); return NULL; @@ -936,10 +936,10 @@ static void free_scq(ns_dev *card, scq_info *scq, struct atm_vcc *vcc) } } kfree(scq->skb); - pci_free_consistent(card->pcidev, - 2 * (scq->num_entries == VBR_SCQ_NUM_ENTRIES ? - VBR_SCQSIZE : CBR_SCQSIZE), - scq->org, scq->dma); + dma_free_coherent(&card->pcidev->dev, + 2 * (scq->num_entries == VBR_SCQ_NUM_ENTRIES ? + VBR_SCQSIZE : CBR_SCQSIZE), + scq->org, scq->dma); kfree(scq); } @@ -957,11 +957,11 @@ static void push_rxbufs(ns_dev * card, struct sk_buff *skb) handle2 = NULL; addr2 = 0; handle1 = skb; - addr1 = pci_map_single(card->pcidev, + addr1 = dma_map_single(&card->pcidev->dev, skb->data, (NS_PRV_BUFTYPE(skb) == BUF_SM ? NS_SMSKBSIZE : NS_LGSKBSIZE), - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); NS_PRV_DMA(skb) = addr1; /* save so we can unmap later */ #ifdef GENERAL_DEBUG @@ -1670,8 +1670,8 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) ATM_SKB(skb)->vcc = vcc; - NS_PRV_DMA(skb) = pci_map_single(card->pcidev, skb->data, - skb->len, PCI_DMA_TODEVICE); + NS_PRV_DMA(skb) = dma_map_single(&card->pcidev->dev, skb->data, + skb->len, DMA_TO_DEVICE); if (vcc->qos.aal == ATM_AAL5) { buflen = (skb->len + 47 + 8) / 48 * 48; /* Multiple of 48 */ @@ -1930,10 +1930,10 @@ static void drain_scq(ns_dev * card, scq_info * scq, int pos) XPRINTK("nicstar%d: freeing skb at 0x%p (index %d).\n", card->index, skb, i); if (skb != NULL) { - pci_unmap_single(card->pcidev, + dma_unmap_single(&card->pcidev->dev, NS_PRV_DMA(skb), skb->len, - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); vcc = ATM_SKB(skb)->vcc; if (vcc && vcc->pop != NULL) { vcc->pop(vcc, skb); @@ -1992,16 +1992,16 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) return; } idr_remove(&card->idr, id); - pci_dma_sync_single_for_cpu(card->pcidev, - NS_PRV_DMA(skb), - (NS_PRV_BUFTYPE(skb) == BUF_SM - ? NS_SMSKBSIZE : NS_LGSKBSIZE), - PCI_DMA_FROMDEVICE); - pci_unmap_single(card->pcidev, + dma_sync_single_for_cpu(&card->pcidev->dev, + NS_PRV_DMA(skb), + (NS_PRV_BUFTYPE(skb) == BUF_SM + ? NS_SMSKBSIZE : NS_LGSKBSIZE), + DMA_FROM_DEVICE); + dma_unmap_single(&card->pcidev->dev, NS_PRV_DMA(skb), (NS_PRV_BUFTYPE(skb) == BUF_SM ? NS_SMSKBSIZE : NS_LGSKBSIZE), - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); vpi = ns_rsqe_vpi(rsqe); vci = ns_rsqe_vci(rsqe); if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits) { diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 21b0bc6a9c96..74e18b0a6d89 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -785,8 +785,8 @@ static void solos_bh(unsigned long card_arg) skb = card->rx_skb[port]; card->rx_skb[port] = NULL; - pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr, - RX_DMA_SIZE, PCI_DMA_FROMDEVICE); + dma_unmap_single(&card->dev->dev, SKB_CB(skb)->dma_addr, + RX_DMA_SIZE, DMA_FROM_DEVICE); header = (void *)skb->data; size = le16_to_cpu(header->size); @@ -872,8 +872,8 @@ static void solos_bh(unsigned long card_arg) struct sk_buff *skb = alloc_skb(RX_DMA_SIZE, GFP_ATOMIC); if (skb) { SKB_CB(skb)->dma_addr = - pci_map_single(card->dev, skb->data, - RX_DMA_SIZE, PCI_DMA_FROMDEVICE); + dma_map_single(&card->dev->dev, skb->data, + RX_DMA_SIZE, DMA_FROM_DEVICE); iowrite32(SKB_CB(skb)->dma_addr, card->config_regs + RX_DMA_ADDR(port)); card->rx_skb[port] = skb; @@ -1069,8 +1069,8 @@ static uint32_t fpga_tx(struct solos_card *card) if (tx_pending & 1) { struct sk_buff *oldskb = card->tx_skb[port]; if (oldskb) { - pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr, - oldskb->len, PCI_DMA_TODEVICE); + dma_unmap_single(&card->dev->dev, SKB_CB(oldskb)->dma_addr, + oldskb->len, DMA_TO_DEVICE); card->tx_skb[port] = NULL; } spin_lock(&card->tx_queue_lock); @@ -1089,8 +1089,8 @@ static uint32_t fpga_tx(struct solos_card *card) data = card->dma_bounce + (BUF_SIZE * port); memcpy(data, skb->data, skb->len); } - SKB_CB(skb)->dma_addr = pci_map_single(card->dev, data, - skb->len, PCI_DMA_TODEVICE); + SKB_CB(skb)->dma_addr = dma_map_single(&card->dev->dev, data, + skb->len, DMA_TO_DEVICE); card->tx_skb[port] = skb; iowrite32(SKB_CB(skb)->dma_addr, card->config_regs + TX_DMA_ADDR(port)); @@ -1210,7 +1210,7 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) goto out; } - err = pci_set_dma_mask(dev, DMA_BIT_MASK(32)); + err = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); if (err) { dev_warn(&dev->dev, "Failed to set 32-bit DMA mask\n"); goto out; @@ -1411,14 +1411,14 @@ static void atm_remove(struct solos_card *card) skb = card->rx_skb[i]; if (skb) { - pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr, - RX_DMA_SIZE, PCI_DMA_FROMDEVICE); + dma_unmap_single(&card->dev->dev, SKB_CB(skb)->dma_addr, + RX_DMA_SIZE, DMA_FROM_DEVICE); dev_kfree_skb(skb); } skb = card->tx_skb[i]; if (skb) { - pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr, - skb->len, PCI_DMA_TODEVICE); + dma_unmap_single(&card->dev->dev, SKB_CB(skb)->dma_addr, + skb->len, DMA_TO_DEVICE); dev_kfree_skb(skb); } while ((skb = skb_dequeue(&card->tx_queue[i]))) diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 969c3c29000c..cecfb943762f 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -1306,19 +1306,20 @@ static int zatm_start(struct atm_dev *dev) if (!mbx_entries[i]) continue; - mbx = pci_alloc_consistent(pdev, 2*MBX_SIZE(i), &mbx_dma); + mbx = dma_alloc_coherent(&pdev->dev, + 2 * MBX_SIZE(i), &mbx_dma, GFP_KERNEL); if (!mbx) { error = -ENOMEM; goto out; } /* - * Alignment provided by pci_alloc_consistent() isn't enough + * Alignment provided by dma_alloc_coherent() isn't enough * for this device. */ if (((unsigned long)mbx ^ mbx_dma) & 0xffff) { printk(KERN_ERR DEV_LABEL "(itf %d): system " "bus incompatible with driver\n", dev->number); - pci_free_consistent(pdev, 2*MBX_SIZE(i), mbx, mbx_dma); + dma_free_coherent(&pdev->dev, 2*MBX_SIZE(i), mbx, mbx_dma); error = -ENODEV; goto out; } @@ -1354,9 +1355,9 @@ out_tx: kfree(zatm_dev->tx_map); out: while (i-- > 0) { - pci_free_consistent(pdev, 2*MBX_SIZE(i), - (void *)zatm_dev->mbx_start[i], - zatm_dev->mbx_dma[i]); + dma_free_coherent(&pdev->dev, 2 * MBX_SIZE(i), + (void *)zatm_dev->mbx_start[i], + zatm_dev->mbx_dma[i]); } free_irq(zatm_dev->irq, dev); goto done; @@ -1608,6 +1609,10 @@ static int zatm_init_one(struct pci_dev *pci_dev, if (ret < 0) goto out_disable; + ret = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32)); + if (ret < 0) + goto out_disable; + zatm_dev->pci_dev = pci_dev; dev->dev_data = zatm_dev; zatm_dev->copper = (int)ent->driver_data; diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index b0f138806bbc..f32b802b98f4 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c @@ -19,8 +19,8 @@ * @dev: Device to handle. * * If power.subsys_data is NULL, point it to a new object, otherwise increment - * its reference counter. Return 1 if a new object has been created, otherwise - * return 0 or error code. + * its reference counter. Return 0 if new object has been created or refcount + * increased, otherwise negative error code. */ int dev_pm_get_subsys_data(struct device *dev) { @@ -56,13 +56,11 @@ EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data); * @dev: Device to handle. * * If the reference counter of power.subsys_data is zero after dropping the - * reference, power.subsys_data is removed. Return 1 if that happens or 0 - * otherwise. + * reference, power.subsys_data is removed. */ -int dev_pm_put_subsys_data(struct device *dev) +void dev_pm_put_subsys_data(struct device *dev) { struct pm_subsys_data *psd; - int ret = 1; spin_lock_irq(&dev->power.lock); @@ -70,18 +68,14 @@ int dev_pm_put_subsys_data(struct device *dev) if (!psd) goto out; - if (--psd->refcount == 0) { + if (--psd->refcount == 0) dev->power.subsys_data = NULL; - } else { + else psd = NULL; - ret = 0; - } out: spin_unlock_irq(&dev->power.lock); kfree(psd); - - return ret; } EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data); diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 0d8780c04a5e..ba4abbe4693c 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -344,14 +344,7 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, struct device *dev; gpd_data = container_of(nb, struct generic_pm_domain_data, nb); - - mutex_lock(&gpd_data->lock); dev = gpd_data->base.dev; - if (!dev) { - mutex_unlock(&gpd_data->lock); - return NOTIFY_DONE; - } - mutex_unlock(&gpd_data->lock); for (;;) { struct generic_pm_domain *genpd; @@ -1384,25 +1377,66 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron); #endif /* CONFIG_PM_SLEEP */ -static struct generic_pm_domain_data *__pm_genpd_alloc_dev_data(struct device *dev) +static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev, + struct generic_pm_domain *genpd, + struct gpd_timing_data *td) { struct generic_pm_domain_data *gpd_data; + int ret; + + ret = dev_pm_get_subsys_data(dev); + if (ret) + return ERR_PTR(ret); gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL); - if (!gpd_data) - return NULL; + if (!gpd_data) { + ret = -ENOMEM; + goto err_put; + } - mutex_init(&gpd_data->lock); + if (td) + gpd_data->td = *td; + + gpd_data->base.dev = dev; + gpd_data->need_restore = -1; + gpd_data->td.constraint_changed = true; + gpd_data->td.effective_constraint_ns = -1; gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; - dev_pm_qos_add_notifier(dev, &gpd_data->nb); + + spin_lock_irq(&dev->power.lock); + + if (dev->power.subsys_data->domain_data) { + ret = -EINVAL; + goto err_free; + } + + dev->power.subsys_data->domain_data = &gpd_data->base; + dev->pm_domain = &genpd->domain; + + spin_unlock_irq(&dev->power.lock); + return gpd_data; + + err_free: + spin_unlock_irq(&dev->power.lock); + kfree(gpd_data); + err_put: + dev_pm_put_subsys_data(dev); + return ERR_PTR(ret); } -static void __pm_genpd_free_dev_data(struct device *dev, - struct generic_pm_domain_data *gpd_data) +static void genpd_free_dev_data(struct device *dev, + struct generic_pm_domain_data *gpd_data) { - dev_pm_qos_remove_notifier(dev, &gpd_data->nb); + spin_lock_irq(&dev->power.lock); + + dev->pm_domain = NULL; + dev->power.subsys_data->domain_data = NULL; + + spin_unlock_irq(&dev->power.lock); + kfree(gpd_data); + dev_pm_put_subsys_data(dev); } /** @@ -1414,8 +1448,7 @@ static void __pm_genpd_free_dev_data(struct device *dev, int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, struct gpd_timing_data *td) { - struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL; - struct pm_domain_data *pdd; + struct generic_pm_domain_data *gpd_data; int ret = 0; dev_dbg(dev, "%s()\n", __func__); @@ -1423,9 +1456,9 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)) return -EINVAL; - gpd_data_new = __pm_genpd_alloc_dev_data(dev); - if (!gpd_data_new) - return -ENOMEM; + gpd_data = genpd_alloc_dev_data(dev, genpd, td); + if (IS_ERR(gpd_data)) + return PTR_ERR(gpd_data); genpd_acquire_lock(genpd); @@ -1434,50 +1467,22 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, goto out; } - list_for_each_entry(pdd, &genpd->dev_list, list_node) - if (pdd->dev == dev) { - ret = -EINVAL; - goto out; - } - - ret = dev_pm_get_subsys_data(dev); + ret = genpd->attach_dev ? genpd->attach_dev(genpd, dev) : 0; if (ret) goto out; genpd->device_count++; genpd->max_off_time_changed = true; - spin_lock_irq(&dev->power.lock); - - dev->pm_domain = &genpd->domain; - if (dev->power.subsys_data->domain_data) { - gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); - } else { - gpd_data = gpd_data_new; - dev->power.subsys_data->domain_data = &gpd_data->base; - } - gpd_data->refcount++; - if (td) - gpd_data->td = *td; - - spin_unlock_irq(&dev->power.lock); - - if (genpd->attach_dev) - genpd->attach_dev(genpd, dev); - - mutex_lock(&gpd_data->lock); - gpd_data->base.dev = dev; list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); - gpd_data->need_restore = -1; - gpd_data->td.constraint_changed = true; - gpd_data->td.effective_constraint_ns = -1; - mutex_unlock(&gpd_data->lock); out: genpd_release_lock(genpd); - if (gpd_data != gpd_data_new) - __pm_genpd_free_dev_data(dev, gpd_data_new); + if (ret) + genpd_free_dev_data(dev, gpd_data); + else + dev_pm_qos_add_notifier(dev, &gpd_data->nb); return ret; } @@ -1504,7 +1509,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, { struct generic_pm_domain_data *gpd_data; struct pm_domain_data *pdd; - bool remove = false; int ret = 0; dev_dbg(dev, "%s()\n", __func__); @@ -1514,6 +1518,11 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, || pd_to_genpd(dev->pm_domain) != genpd) return -EINVAL; + /* The above validation also means we have existing domain_data. */ + pdd = dev->power.subsys_data->domain_data; + gpd_data = to_gpd_data(pdd); + dev_pm_qos_remove_notifier(dev, &gpd_data->nb); + genpd_acquire_lock(genpd); if (genpd->prepared_count > 0) { @@ -1527,57 +1536,21 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, if (genpd->detach_dev) genpd->detach_dev(genpd, dev); - spin_lock_irq(&dev->power.lock); - - dev->pm_domain = NULL; - pdd = dev->power.subsys_data->domain_data; list_del_init(&pdd->list_node); - gpd_data = to_gpd_data(pdd); - if (--gpd_data->refcount == 0) { - dev->power.subsys_data->domain_data = NULL; - remove = true; - } - - spin_unlock_irq(&dev->power.lock); - - mutex_lock(&gpd_data->lock); - pdd->dev = NULL; - mutex_unlock(&gpd_data->lock); genpd_release_lock(genpd); - dev_pm_put_subsys_data(dev); - if (remove) - __pm_genpd_free_dev_data(dev, gpd_data); + genpd_free_dev_data(dev, gpd_data); return 0; out: genpd_release_lock(genpd); + dev_pm_qos_add_notifier(dev, &gpd_data->nb); return ret; } -/** - * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag. - * @dev: Device to set/unset the flag for. - * @val: The new value of the device's "need restore" flag. - */ -void pm_genpd_dev_need_restore(struct device *dev, bool val) -{ - struct pm_subsys_data *psd; - unsigned long flags; - - spin_lock_irqsave(&dev->power.lock, flags); - - psd = dev_to_psd(dev); - if (psd && psd->domain_data) - to_gpd_data(psd->domain_data)->need_restore = val ? 1 : 0; - - spin_unlock_irqrestore(&dev->power.lock, flags); -} -EXPORT_SYMBOL_GPL(pm_genpd_dev_need_restore); - /** * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. * @genpd: Master PM domain to add the subdomain to. diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 106c69359306..15bf29974c31 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -117,20 +117,20 @@ do { \ } while (0) /** - * find_device_opp() - find device_opp struct using device pointer + * _find_device_opp() - find device_opp struct using device pointer * @dev: device pointer used to lookup device OPPs * * Search list of device OPPs for one containing matching device. Does a RCU * reader operation to grab the pointer needed. * - * Returns pointer to 'struct device_opp' if found, otherwise -ENODEV or + * Return: pointer to 'struct device_opp' if found, otherwise -ENODEV or * -EINVAL based on type of error. * * Locking: This function must be called under rcu_read_lock(). device_opp * is a RCU protected pointer. This means that device_opp is valid as long * as we are under RCU lock. */ -static struct device_opp *find_device_opp(struct device *dev) +static struct device_opp *_find_device_opp(struct device *dev) { struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV); @@ -153,7 +153,7 @@ static struct device_opp *find_device_opp(struct device *dev) * dev_pm_opp_get_voltage() - Gets the voltage corresponding to an available opp * @opp: opp for which voltage has to be returned for * - * Return voltage in micro volt corresponding to the opp, else + * Return: voltage in micro volt corresponding to the opp, else * return 0 * * Locking: This function must be called under rcu_read_lock(). opp is a rcu @@ -169,6 +169,8 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) struct dev_pm_opp *tmp_opp; unsigned long v = 0; + opp_rcu_lockdep_assert(); + tmp_opp = rcu_dereference(opp); if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available) pr_err("%s: Invalid parameters\n", __func__); @@ -183,7 +185,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage); * dev_pm_opp_get_freq() - Gets the frequency corresponding to an available opp * @opp: opp for which frequency has to be returned for * - * Return frequency in hertz corresponding to the opp, else + * Return: frequency in hertz corresponding to the opp, else * return 0 * * Locking: This function must be called under rcu_read_lock(). opp is a rcu @@ -199,6 +201,8 @@ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp) struct dev_pm_opp *tmp_opp; unsigned long f = 0; + opp_rcu_lockdep_assert(); + tmp_opp = rcu_dereference(opp); if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available) pr_err("%s: Invalid parameters\n", __func__); @@ -213,7 +217,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq); * dev_pm_opp_get_opp_count() - Get number of opps available in the opp list * @dev: device for which we do this operation * - * This function returns the number of available opps if there are any, + * Return: This function returns the number of available opps if there are any, * else returns 0 if none or the corresponding error value. * * Locking: This function takes rcu_read_lock(). @@ -226,7 +230,7 @@ int dev_pm_opp_get_opp_count(struct device *dev) rcu_read_lock(); - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) { count = PTR_ERR(dev_opp); dev_err(dev, "%s: device OPP not found (%d)\n", @@ -251,9 +255,9 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count); * @freq: frequency to search for * @available: true/false - match for available opp * - * Searches for exact match in the opp list and returns pointer to the matching - * opp if found, else returns ERR_PTR in case of error and should be handled - * using IS_ERR. Error return values can be: + * Return: Searches for exact match in the opp list and returns pointer to the + * matching opp if found, else returns ERR_PTR in case of error and should + * be handled using IS_ERR. Error return values can be: * EINVAL: for bad pointer * ERANGE: no match found for search * ENODEV: if device not found in list of registered devices @@ -280,7 +284,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, opp_rcu_lockdep_assert(); - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) { int r = PTR_ERR(dev_opp); dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r); @@ -307,7 +311,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact); * Search for the matching ceil *available* OPP from a starting freq * for a device. * - * Returns matching *opp and refreshes *freq accordingly, else returns + * Return: matching *opp and refreshes *freq accordingly, else returns * ERR_PTR in case of error and should be handled using IS_ERR. Error return * values can be: * EINVAL: for bad pointer @@ -333,7 +337,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, return ERR_PTR(-EINVAL); } - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) return ERR_CAST(dev_opp); @@ -357,7 +361,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil); * Search for the matching floor *available* OPP from a starting freq * for a device. * - * Returns matching *opp and refreshes *freq accordingly, else returns + * Return: matching *opp and refreshes *freq accordingly, else returns * ERR_PTR in case of error and should be handled using IS_ERR. Error return * values can be: * EINVAL: for bad pointer @@ -383,7 +387,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, return ERR_PTR(-EINVAL); } - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) return ERR_CAST(dev_opp); @@ -403,7 +407,16 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, } EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor); -static struct device_opp *add_device_opp(struct device *dev) +/** + * _add_device_opp() - Allocate a new device OPP table + * @dev: device for which we do this operation + * + * New device node which uses OPPs - used when multiple devices with OPP tables + * are maintained. + * + * Return: valid device_opp pointer if success, else NULL. + */ +static struct device_opp *_add_device_opp(struct device *dev) { struct device_opp *dev_opp; @@ -424,8 +437,35 @@ static struct device_opp *add_device_opp(struct device *dev) return dev_opp; } -static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq, - unsigned long u_volt, bool dynamic) +/** + * _opp_add_dynamic() - Allocate a dynamic OPP. + * @dev: device for which we do this operation + * @freq: Frequency in Hz for this OPP + * @u_volt: Voltage in uVolts for this OPP + * @dynamic: Dynamically added OPPs. + * + * This function adds an opp definition to the opp list and returns status. + * The opp is made available by default and it can be controlled using + * dev_pm_opp_enable/disable functions and may be removed by dev_pm_opp_remove. + * + * NOTE: "dynamic" parameter impacts OPPs added by the of_init_opp_table and + * freed by of_free_opp_table. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function internally uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + * + * Return: + * 0 On success OR + * Duplicate OPPs (both freq and volt are same) and opp->available + * -EEXIST Freq are same and volt are different OR + * Duplicate OPPs (both freq and volt are same) and !opp->available + * -ENOMEM Memory allocation failure + */ +static int _opp_add_dynamic(struct device *dev, unsigned long freq, + long u_volt, bool dynamic) { struct device_opp *dev_opp = NULL; struct dev_pm_opp *opp, *new_opp; @@ -449,9 +489,9 @@ static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq, new_opp->dynamic = dynamic; /* Check for existing list for 'dev' */ - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) { - dev_opp = add_device_opp(dev); + dev_opp = _add_device_opp(dev); if (!dev_opp) { ret = -ENOMEM; goto free_opp; @@ -519,34 +559,53 @@ free_opp: * mutex cannot be locked. * * Return: - * 0: On success OR + * 0 On success OR * Duplicate OPPs (both freq and volt are same) and opp->available - * -EEXIST: Freq are same and volt are different OR + * -EEXIST Freq are same and volt are different OR * Duplicate OPPs (both freq and volt are same) and !opp->available - * -ENOMEM: Memory allocation failure + * -ENOMEM Memory allocation failure */ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) { - return dev_pm_opp_add_dynamic(dev, freq, u_volt, true); + return _opp_add_dynamic(dev, freq, u_volt, true); } EXPORT_SYMBOL_GPL(dev_pm_opp_add); -static void kfree_opp_rcu(struct rcu_head *head) +/** + * _kfree_opp_rcu() - Free OPP RCU handler + * @head: RCU head + */ +static void _kfree_opp_rcu(struct rcu_head *head) { struct dev_pm_opp *opp = container_of(head, struct dev_pm_opp, rcu_head); kfree_rcu(opp, rcu_head); } -static void kfree_device_rcu(struct rcu_head *head) +/** + * _kfree_device_rcu() - Free device_opp RCU handler + * @head: RCU head + */ +static void _kfree_device_rcu(struct rcu_head *head) { struct device_opp *device_opp = container_of(head, struct device_opp, rcu_head); kfree_rcu(device_opp, rcu_head); } -static void __dev_pm_opp_remove(struct device_opp *dev_opp, - struct dev_pm_opp *opp) +/** + * _opp_remove() - Remove an OPP from a table definition + * @dev_opp: points back to the device_opp struct this opp belongs to + * @opp: pointer to the OPP to remove + * + * This function removes an opp definition from the opp list. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * It is assumed that the caller holds required mutex for an RCU updater + * strategy. + */ +static void _opp_remove(struct device_opp *dev_opp, + struct dev_pm_opp *opp) { /* * Notify the changes in the availability of the operable @@ -554,12 +613,12 @@ static void __dev_pm_opp_remove(struct device_opp *dev_opp, */ srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp); list_del_rcu(&opp->node); - call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu); + call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); if (list_empty(&dev_opp->opp_list)) { list_del_rcu(&dev_opp->node); call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head, - kfree_device_rcu); + _kfree_device_rcu); } } @@ -569,6 +628,12 @@ static void __dev_pm_opp_remove(struct device_opp *dev_opp, * @freq: OPP to remove with matching 'freq' * * This function removes an opp from the opp list. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function internally uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. */ void dev_pm_opp_remove(struct device *dev, unsigned long freq) { @@ -579,7 +644,7 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq) /* Hold our list modification lock here */ mutex_lock(&dev_opp_list_lock); - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) goto unlock; @@ -596,14 +661,14 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq) goto unlock; } - __dev_pm_opp_remove(dev_opp, opp); + _opp_remove(dev_opp, opp); unlock: mutex_unlock(&dev_opp_list_lock); } EXPORT_SYMBOL_GPL(dev_pm_opp_remove); /** - * opp_set_availability() - helper to set the availability of an opp + * _opp_set_availability() - helper to set the availability of an opp * @dev: device for which we do this operation * @freq: OPP frequency to modify availability * @availability_req: availability status requested for this opp @@ -611,7 +676,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_remove); * Set the availability of an OPP with an RCU operation, opp_{enable,disable} * share a common logic which is isolated here. * - * Returns -EINVAL for bad pointers, -ENOMEM if no memory available for the + * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the * copy operation, returns 0 if no modifcation was done OR modification was * successful. * @@ -621,8 +686,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_remove); * that this function is *NOT* called under RCU protection or in contexts where * mutex locking or synchronize_rcu() blocking calls cannot be used. */ -static int opp_set_availability(struct device *dev, unsigned long freq, - bool availability_req) +static int _opp_set_availability(struct device *dev, unsigned long freq, + bool availability_req) { struct device_opp *dev_opp; struct dev_pm_opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV); @@ -638,7 +703,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq, mutex_lock(&dev_opp_list_lock); /* Find the device_opp */ - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) { r = PTR_ERR(dev_opp); dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r); @@ -668,7 +733,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq, list_replace_rcu(&opp->node, &new_opp->node); mutex_unlock(&dev_opp_list_lock); - call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu); + call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); /* Notify the change of the OPP availability */ if (availability_req) @@ -700,10 +765,14 @@ unlock: * integrity of the internal data structures. Callers should ensure that * this function is *NOT* called under RCU protection or in contexts where * mutex locking or synchronize_rcu() blocking calls cannot be used. + * + * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the + * copy operation, returns 0 if no modifcation was done OR modification was + * successful. */ int dev_pm_opp_enable(struct device *dev, unsigned long freq) { - return opp_set_availability(dev, freq, true); + return _opp_set_availability(dev, freq, true); } EXPORT_SYMBOL_GPL(dev_pm_opp_enable); @@ -722,26 +791,41 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_enable); * integrity of the internal data structures. Callers should ensure that * this function is *NOT* called under RCU protection or in contexts where * mutex locking or synchronize_rcu() blocking calls cannot be used. + * + * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the + * copy operation, returns 0 if no modifcation was done OR modification was + * successful. */ int dev_pm_opp_disable(struct device *dev, unsigned long freq) { - return opp_set_availability(dev, freq, false); + return _opp_set_availability(dev, freq, false); } EXPORT_SYMBOL_GPL(dev_pm_opp_disable); /** * dev_pm_opp_get_notifier() - find notifier_head of the device with opp * @dev: device pointer used to lookup device OPPs. + * + * Return: pointer to notifier head if found, otherwise -ENODEV or + * -EINVAL based on type of error casted as pointer. value must be checked + * with IS_ERR to determine valid pointer or error result. + * + * Locking: This function must be called under rcu_read_lock(). dev_opp is a RCU + * protected pointer. The reason for the same is that the opp pointer which is + * returned will remain valid for use with opp_get_{voltage, freq} only while + * under the locked area. The pointer returned must be used prior to unlocking + * with rcu_read_unlock() to maintain the integrity of the pointer. */ struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev) { - struct device_opp *dev_opp = find_device_opp(dev); + struct device_opp *dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) return ERR_CAST(dev_opp); /* matching type */ return &dev_opp->srcu_head; } +EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier); #ifdef CONFIG_OF /** @@ -749,6 +833,22 @@ struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev) * @dev: device pointer used to lookup device OPPs. * * Register the initial OPP table with the OPP library for given device. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function indirectly uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + * + * Return: + * 0 On success OR + * Duplicate OPPs (both freq and volt are same) and opp->available + * -EEXIST Freq are same and volt are different OR + * Duplicate OPPs (both freq and volt are same) and !opp->available + * -ENOMEM Memory allocation failure + * -ENODEV when 'operating-points' property is not found or is invalid data + * in device node. + * -ENODATA when empty 'operating-points' property is found */ int of_init_opp_table(struct device *dev) { @@ -777,7 +877,7 @@ int of_init_opp_table(struct device *dev) unsigned long freq = be32_to_cpup(val++) * 1000; unsigned long volt = be32_to_cpup(val++); - if (dev_pm_opp_add_dynamic(dev, freq, volt, false)) + if (_opp_add_dynamic(dev, freq, volt, false)) dev_warn(dev, "%s: Failed to add OPP %ld\n", __func__, freq); nr -= 2; @@ -792,6 +892,12 @@ EXPORT_SYMBOL_GPL(of_init_opp_table); * @dev: device pointer used to lookup device OPPs. * * Free OPPs created using static entries present in DT. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function indirectly uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. */ void of_free_opp_table(struct device *dev) { @@ -799,7 +905,7 @@ void of_free_opp_table(struct device *dev) struct dev_pm_opp *opp, *tmp; /* Check for existing list for 'dev' */ - dev_opp = find_device_opp(dev); + dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) { int error = PTR_ERR(dev_opp); if (error != -ENODEV) @@ -816,7 +922,7 @@ void of_free_opp_table(struct device *dev) /* Free static OPPs */ list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) { if (!opp->dynamic) - __dev_pm_opp_remove(dev_opp, opp); + _opp_remove(dev_opp, opp); } mutex_unlock(&dev_opp_list_lock); diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index a8fe4c1a8d07..e56d538d039e 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -64,6 +64,8 @@ enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask) struct pm_qos_flags *pqf; s32 val; + lockdep_assert_held(&dev->power.lock); + if (IS_ERR_OR_NULL(qos)) return PM_QOS_FLAGS_UNDEFINED; @@ -104,6 +106,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_flags); */ s32 __dev_pm_qos_read_value(struct device *dev) { + lockdep_assert_held(&dev->power.lock); + return IS_ERR_OR_NULL(dev->power.qos) ? 0 : pm_qos_read_value(&dev->power.qos->resume_latency); } diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 0da5865df5b1..beb8b27d4621 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -51,9 +51,11 @@ struct regmap_async { struct regmap { union { struct mutex mutex; - spinlock_t spinlock; + struct { + spinlock_t spinlock; + unsigned long spinlock_flags; + }; }; - unsigned long spinlock_flags; regmap_lock lock; regmap_unlock unlock; void *lock_arg; /* This is passed to lock/unlock functions */ @@ -233,6 +235,10 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, void regmap_async_complete_cb(struct regmap_async *async, int ret); +enum regmap_endian regmap_get_val_endian(struct device *dev, + const struct regmap_bus *bus, + const struct regmap_config *config); + extern struct regcache_ops regcache_rbtree_ops; extern struct regcache_ops regcache_lzo_ops; extern struct regcache_ops regcache_flat_ops; diff --git a/drivers/base/regmap/regmap-ac97.c b/drivers/base/regmap/regmap-ac97.c index e4c45d2299c1..8d304e2a943d 100644 --- a/drivers/base/regmap/regmap-ac97.c +++ b/drivers/base/regmap/regmap-ac97.c @@ -74,8 +74,8 @@ static int regmap_ac97_reg_write(void *context, unsigned int reg, } static const struct regmap_bus ac97_regmap_bus = { - .reg_write = regmap_ac97_reg_write, - .reg_read = regmap_ac97_reg_read, + .reg_write = regmap_ac97_reg_write, + .reg_read = regmap_ac97_reg_read, }; /** diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index 053150a7f9f2..4b76e33110a2 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -14,6 +14,7 @@ #include #include +#include "internal.h" static int regmap_smbus_byte_reg_read(void *context, unsigned int reg, unsigned int *val) @@ -87,6 +88,42 @@ static struct regmap_bus regmap_smbus_word = { .reg_read = regmap_smbus_word_reg_read, }; +static int regmap_smbus_word_read_swapped(void *context, unsigned int reg, + unsigned int *val) +{ + struct device *dev = context; + struct i2c_client *i2c = to_i2c_client(dev); + int ret; + + if (reg > 0xff) + return -EINVAL; + + ret = i2c_smbus_read_word_swapped(i2c, reg); + if (ret < 0) + return ret; + + *val = ret; + + return 0; +} + +static int regmap_smbus_word_write_swapped(void *context, unsigned int reg, + unsigned int val) +{ + struct device *dev = context; + struct i2c_client *i2c = to_i2c_client(dev); + + if (val > 0xffff || reg > 0xff) + return -EINVAL; + + return i2c_smbus_write_word_swapped(i2c, reg, val); +} + +static struct regmap_bus regmap_smbus_word_swapped = { + .reg_write = regmap_smbus_word_write_swapped, + .reg_read = regmap_smbus_word_read_swapped, +}; + static int regmap_i2c_write(void *context, const void *data, size_t count) { struct device *dev = context; @@ -180,7 +217,14 @@ static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, else if (config->val_bits == 16 && config->reg_bits == 8 && i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_WORD_DATA)) - return ®map_smbus_word; + switch (regmap_get_val_endian(&i2c->dev, NULL, config)) { + case REGMAP_ENDIAN_LITTLE: + return ®map_smbus_word; + case REGMAP_ENDIAN_BIG: + return ®map_smbus_word_swapped; + default: /* everything else is not supported */ + break; + } else if (config->val_bits == 8 && config->reg_bits == 8 && i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index d2f8a818d200..f99b098ddabf 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -473,9 +473,9 @@ static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus, return REGMAP_ENDIAN_BIG; } -static enum regmap_endian regmap_get_val_endian(struct device *dev, - const struct regmap_bus *bus, - const struct regmap_config *config) +enum regmap_endian regmap_get_val_endian(struct device *dev, + const struct regmap_bus *bus, + const struct regmap_config *config) { struct device_node *np; enum regmap_endian endian; @@ -513,6 +513,7 @@ static enum regmap_endian regmap_get_val_endian(struct device *dev, /* Use this if no other value was found */ return REGMAP_ENDIAN_BIG; } +EXPORT_SYMBOL_GPL(regmap_get_val_endian); /** * regmap_init(): Initialise register map diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 314ae4032f3e..ac6c5fca906d 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -25,22 +25,18 @@ struct bcma_bus; bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value, int timeout); void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core); +void bcma_init_bus(struct bcma_bus *bus); int bcma_bus_register(struct bcma_bus *bus); void bcma_bus_unregister(struct bcma_bus *bus); -int __init bcma_bus_early_register(struct bcma_bus *bus, - struct bcma_device *core_cc, - struct bcma_device *core_mips); +int __init bcma_bus_early_register(struct bcma_bus *bus); #ifdef CONFIG_PM int bcma_bus_suspend(struct bcma_bus *bus); int bcma_bus_resume(struct bcma_bus *bus); #endif /* scan.c */ +void bcma_detect_chip(struct bcma_bus *bus); int bcma_bus_scan(struct bcma_bus *bus); -int __init bcma_bus_scan_early(struct bcma_bus *bus, - struct bcma_device_id *match, - struct bcma_device *core); -void bcma_init_bus(struct bcma_bus *bus); /* sprom.c */ int bcma_sprom_get(struct bcma_bus *bus); @@ -111,6 +107,14 @@ extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc); #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc); void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc); +#else +static inline bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc) +{ + return false; +} +static inline void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc) +{ +} #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */ #ifdef CONFIG_BCMA_DRIVER_GPIO diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index 19f679667ca4..b7c8a8d4e6d1 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c @@ -79,7 +79,9 @@ static int bcma_chipco_watchdog_ticks_per_ms(struct bcma_drv_cc *cc) if (cc->capabilities & BCMA_CC_CAP_PMU) { if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) - /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP clock */ + /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP + * clock + */ return bcma_chipco_get_alp_clock(cc) / 4000; else /* based on 32KHz ILP clock */ @@ -97,7 +99,8 @@ int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc) wdt.driver_data = cc; wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt; wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt; - wdt.max_timer_ms = bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms; + wdt.max_timer_ms = + bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms; pdev = platform_device_register_data(NULL, "bcm47xx-wdt", cc->core->bus->num, &wdt, @@ -175,7 +178,6 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) { u32 maxt; - enum bcma_clkmode clkmode; maxt = bcma_chipco_watchdog_get_max_timer(cc); if (cc->capabilities & BCMA_CC_CAP_PMU) { @@ -185,8 +187,13 @@ u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) ticks = maxt; bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks); } else { - clkmode = ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC; - bcma_core_set_clockmode(cc->core, clkmode); + struct bcma_bus *bus = cc->core->bus; + + if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 && + bus->chipinfo.id != BCMA_CHIP_ID_BCM53018) + bcma_core_set_clockmode(cc->core, + ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC); + if (ticks > maxt) ticks = maxt; /* instant NMI */ @@ -335,7 +342,8 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc) | BCMA_CC_CORECTL_UARTCLKEN); } } else { - bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", ccrev); + bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", + ccrev); return; } diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index 50329d1057ed..786666488a2d 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -144,6 +144,47 @@ static u16 bcma_pcie_mdio_writeread(struct bcma_drv_pci *pc, u16 device, return bcma_pcie_mdio_read(pc, device, address); } +/************************************************** + * Early init. + **************************************************/ + +static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc) +{ + struct bcma_device *core = pc->core; + u16 val16, core_index; + uint regoff; + + regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET); + core_index = (u16)core->core_index; + + val16 = pcicore_read16(pc, regoff); + if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT) + != core_index) { + val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) | + (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK); + pcicore_write16(pc, regoff, val16); + } +} + +/* + * Apply some early fixes required before accessing SPROM. + * See also si_pci_fixcfg. + */ +void bcma_core_pci_early_init(struct bcma_drv_pci *pc) +{ + if (pc->early_setup_done) + return; + + pc->hostmode = bcma_core_pci_is_in_hostmode(pc); + if (pc->hostmode) + goto out; + + bcma_core_pci_fixcfg(pc); + +out: + pc->early_setup_done = true; +} + /************************************************** * Workarounds. **************************************************/ @@ -175,24 +216,6 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc) tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN); } -static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc) -{ - struct bcma_device *core = pc->core; - u16 val16, core_index; - uint regoff; - - regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET); - core_index = (u16)core->core_index; - - val16 = pcicore_read16(pc, regoff); - if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT) - != core_index) { - val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) | - (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK); - pcicore_write16(pc, regoff, val16); - } -} - /* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */ /* Needs to happen when coming out of 'standby'/'hibernate' */ static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc) @@ -216,7 +239,6 @@ static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc) static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc) { - bcma_core_pci_fixcfg(pc); bcma_pcicore_serdes_workaround(pc); bcma_core_pci_config_fixup(pc); } @@ -226,13 +248,11 @@ void bcma_core_pci_init(struct bcma_drv_pci *pc) if (pc->setup_done) return; -#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE - pc->hostmode = bcma_core_pci_is_in_hostmode(pc); + bcma_core_pci_early_init(pc); + if (pc->hostmode) bcma_core_pci_hostmode_init(pc); -#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */ - - if (!pc->hostmode) + else bcma_core_pci_clientmode_init(pc); } diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index cd9161a8b3a1..53c6a8a58859 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -13,10 +13,12 @@ static void bcma_host_pci_switch_core(struct bcma_device *core) { + int win2 = core->bus->host_is_pcie2 ? + BCMA_PCIE2_BAR0_WIN2 : BCMA_PCI_BAR0_WIN2; + 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); + pci_write_config_dword(core->bus->host_pci, win2, core->wrap); core->bus->mapped_core = core; bcma_debug(core->bus, "Switched to core: 0x%X\n", core->id.id); } diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c index 335cbcfd945b..2dce34789329 100644 --- a/drivers/bcma/host_soc.c +++ b/drivers/bcma/host_soc.c @@ -193,7 +193,7 @@ int __init bcma_host_soc_init(struct bcma_soc *soc) int err; /* Scan bus and initialize it */ - err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips); + err = bcma_bus_early_register(bus); if (err) iounmap(bus->mmio); diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 534e1337766d..38bde6eab8a4 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -268,6 +268,18 @@ void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core) } } +void bcma_init_bus(struct bcma_bus *bus) +{ + mutex_lock(&bcma_buses_mutex); + bus->num = bcma_bus_next_num++; + mutex_unlock(&bcma_buses_mutex); + + INIT_LIST_HEAD(&bus->cores); + bus->nr_cores = 0; + + bcma_detect_chip(bus); +} + static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core) { int err; @@ -356,12 +368,19 @@ static void bcma_unregister_cores(struct bcma_bus *bus) struct bcma_device *core, *tmp; list_for_each_entry_safe(core, tmp, &bus->cores, list) { + if (!core->dev_registered) + continue; list_del(&core->list); - if (core->dev_registered) - device_unregister(&core->dev); + device_unregister(&core->dev); } if (bus->hosttype == BCMA_HOSTTYPE_SOC) platform_device_unregister(bus->drv_cc.watchdog); + + /* Now noone uses internally-handled cores, we can free them */ + list_for_each_entry_safe(core, tmp, &bus->cores, list) { + list_del(&core->list); + kfree(core); + } } int bcma_bus_register(struct bcma_bus *bus) @@ -369,10 +388,6 @@ int bcma_bus_register(struct bcma_bus *bus) int err; struct bcma_device *core; - mutex_lock(&bcma_buses_mutex); - bus->num = bcma_bus_next_num++; - mutex_unlock(&bcma_buses_mutex); - /* Scan for devices (cores) */ err = bcma_bus_scan(bus); if (err) { @@ -387,6 +402,13 @@ int bcma_bus_register(struct bcma_bus *bus) bcma_core_chipcommon_early_init(&bus->drv_cc); } + /* Early init PCIE core */ + core = bcma_find_core(bus, BCMA_CORE_PCIE); + if (core) { + bus->drv_pci[0].core = core; + bcma_core_pci_early_init(&bus->drv_pci[0]); + } + /* Cores providing flash access go before SPROM init */ list_for_each_entry(core, &bus->cores, list) { if (bcma_is_core_needed_early(core->id.id)) @@ -459,7 +481,6 @@ int bcma_bus_register(struct bcma_bus *bus) void bcma_bus_unregister(struct bcma_bus *bus) { - struct bcma_device *cores[3]; int err; err = bcma_gpio_unregister(&bus->drv_cc); @@ -470,46 +491,23 @@ void bcma_bus_unregister(struct bcma_bus *bus) bcma_core_chipcommon_b_free(&bus->drv_cc_b); - cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K); - cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE); - cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON); - bcma_unregister_cores(bus); - - kfree(cores[2]); - kfree(cores[1]); - kfree(cores[0]); } -int __init bcma_bus_early_register(struct bcma_bus *bus, - struct bcma_device *core_cc, - struct bcma_device *core_mips) +/* + * This is a special version of bus registration function designed for SoCs. + * It scans bus and performs basic initialization of main cores only. + * Please note it requires memory allocation, however it won't try to sleep. + */ +int __init bcma_bus_early_register(struct bcma_bus *bus) { int err; struct bcma_device *core; - struct bcma_device_id match; - match.manuf = BCMA_MANUF_BCM; - match.id = bcma_cc_core_id(bus); - match.class = BCMA_CL_SIM; - match.rev = BCMA_ANY_REV; - - /* Scan for chip common core */ - err = bcma_bus_scan_early(bus, &match, core_cc); + /* Scan for devices (cores) */ + err = bcma_bus_scan(bus); if (err) { - bcma_err(bus, "Failed to scan for common core: %d\n", err); - return -1; - } - - match.manuf = BCMA_MANUF_MIPS; - match.id = BCMA_CORE_MIPS_74K; - match.class = BCMA_CL_SIM; - match.rev = BCMA_ANY_REV; - - /* Scan for mips core */ - err = bcma_bus_scan_early(bus, &match, core_mips); - if (err) { - bcma_err(bus, "Failed to scan for mips core: %d\n", err); + bcma_err(bus, "Failed to scan bus: %d\n", err); return -1; } diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index 917520776879..df806b9c5490 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -435,15 +435,12 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, return 0; } -void bcma_init_bus(struct bcma_bus *bus) +void bcma_detect_chip(struct bcma_bus *bus) { s32 tmp; struct bcma_chipinfo *chipinfo = &(bus->chipinfo); char chip_id[8]; - 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); @@ -464,6 +461,10 @@ int bcma_bus_scan(struct bcma_bus *bus) int err, core_num = 0; + /* Skip if bus was already scanned (e.g. during early register) */ + if (bus->nr_cores) + return 0; + erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); if (bus->hosttype == BCMA_HOSTTYPE_SOC) { eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE); @@ -522,61 +523,3 @@ out: return err; } - -int __init bcma_bus_scan_early(struct bcma_bus *bus, - struct bcma_device_id *match, - struct bcma_device *core) -{ - u32 erombase; - u32 __iomem *eromptr, *eromend; - - int err = -ENODEV; - int core_num = 0; - - erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); - if (bus->hosttype == BCMA_HOSTTYPE_SOC) { - eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE); - if (!eromptr) - return -ENOMEM; - } else { - eromptr = bus->mmio; - } - - eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); - - bcma_scan_switch_core(bus, erombase); - - while (eromptr < eromend) { - memset(core, 0, sizeof(*core)); - INIT_LIST_HEAD(&core->list); - core->bus = bus; - - err = bcma_get_next_core(bus, &eromptr, match, core_num, core); - if (err == -ENODEV) { - core_num++; - continue; - } else if (err == -ENXIO) - continue; - else if (err == -ESPIPE) - break; - else if (err < 0) - goto out; - - core->core_index = core_num++; - bus->nr_cores++; - bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", - core->core_index, bcma_device_name(&core->id), - core->id.manuf, core->id.id, core->id.rev, - core->id.class); - - list_add_tail(&core->list, &bus->cores); - err = 0; - break; - } - -out: - if (bus->hosttype == BCMA_HOSTTYPE_SOC) - iounmap(eromptr); - - return err; -} diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index efb037f9c98a..206edd3ba668 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -579,7 +579,8 @@ int bcma_sprom_get(struct bcma_bus *bus) u16 offset = BCMA_CC_SPROM; u16 *sprom; size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4, - SSB_SPROMSIZE_WORDS_R10, }; + SSB_SPROMSIZE_WORDS_R10, + SSB_SPROMSIZE_WORDS_R11, }; int i, err = 0; if (!bus->drv_cc.core) diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index cb529e9a82dd..d826bf3e62c8 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -106,7 +106,7 @@ struct nvme_queue { dma_addr_t cq_dma_addr; u32 __iomem *q_db; u16 q_depth; - u16 cq_vector; + s16 cq_vector; u16 sq_head; u16 sq_tail; u16 cq_head; diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 3ec85dfce124..8a86b62466f7 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2098,32 +2098,26 @@ static void rbd_dev_parent_put(struct rbd_device *rbd_dev) * If an image has a non-zero parent overlap, get a reference to its * parent. * - * We must get the reference before checking for the overlap to - * coordinate properly with zeroing the parent overlap in - * rbd_dev_v2_parent_info() when an image gets flattened. We - * drop it again if there is no overlap. - * * Returns true if the rbd device has a parent with a non-zero * overlap and a reference for it was successfully taken, or * false otherwise. */ static bool rbd_dev_parent_get(struct rbd_device *rbd_dev) { - int counter; + int counter = 0; if (!rbd_dev->parent_spec) return false; - counter = atomic_inc_return_safe(&rbd_dev->parent_ref); - if (counter > 0 && rbd_dev->parent_overlap) - return true; - - /* Image was flattened, but parent is not yet torn down */ + down_read(&rbd_dev->header_rwsem); + if (rbd_dev->parent_overlap) + counter = atomic_inc_return_safe(&rbd_dev->parent_ref); + up_read(&rbd_dev->header_rwsem); if (counter < 0) rbd_warn(rbd_dev, "parent reference overflow"); - return false; + return counter > 0; } /* @@ -4239,7 +4233,6 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev) */ if (rbd_dev->parent_overlap) { rbd_dev->parent_overlap = 0; - smp_mb(); rbd_dev_parent_put(rbd_dev); pr_info("%s: clone image has been flattened\n", rbd_dev->disk->disk_name); @@ -4285,7 +4278,6 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev) * treat it specially. */ rbd_dev->parent_overlap = overlap; - smp_mb(); if (!overlap) { /* A null parent_spec indicates it's the initial probe */ @@ -5114,10 +5106,7 @@ static void rbd_dev_unprobe(struct rbd_device *rbd_dev) { struct rbd_image_header *header; - /* Drop parent reference unless it's already been done (or none) */ - - if (rbd_dev->parent_overlap) - rbd_dev_parent_put(rbd_dev); + rbd_dev_parent_put(rbd_dev); /* Free dynamic fields from the header, then zero it out */ diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 63fc7f06a014..2a04d341e598 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -47,6 +47,7 @@ #include #include #include +#include #include "common.h" /* @@ -100,7 +101,7 @@ module_param(log_stats, int, 0644); #define BLKBACK_INVALID_HANDLE (~0) -/* Number of free pages to remove on each call to free_xenballooned_pages */ +/* Number of free pages to remove on each call to gnttab_free_pages */ #define NUM_BATCH_FREE_PAGES 10 static inline int get_free_page(struct xen_blkif *blkif, struct page **page) @@ -111,7 +112,7 @@ static inline int get_free_page(struct xen_blkif *blkif, struct page **page) if (list_empty(&blkif->free_pages)) { BUG_ON(blkif->free_pages_num != 0); spin_unlock_irqrestore(&blkif->free_pages_lock, flags); - return alloc_xenballooned_pages(1, page, false); + return gnttab_alloc_pages(1, page); } BUG_ON(blkif->free_pages_num == 0); page[0] = list_first_entry(&blkif->free_pages, struct page, lru); @@ -151,14 +152,14 @@ static inline void shrink_free_pagepool(struct xen_blkif *blkif, int num) blkif->free_pages_num--; if (++num_pages == NUM_BATCH_FREE_PAGES) { spin_unlock_irqrestore(&blkif->free_pages_lock, flags); - free_xenballooned_pages(num_pages, page); + gnttab_free_pages(num_pages, page); spin_lock_irqsave(&blkif->free_pages_lock, flags); num_pages = 0; } } spin_unlock_irqrestore(&blkif->free_pages_lock, flags); if (num_pages != 0) - free_xenballooned_pages(num_pages, page); + gnttab_free_pages(num_pages, page); } #define vaddr(page) ((unsigned long)pfn_to_kaddr(page_to_pfn(page))) @@ -262,6 +263,17 @@ static void put_persistent_gnt(struct xen_blkif *blkif, atomic_dec(&blkif->persistent_gnt_in_use); } +static void free_persistent_gnts_unmap_callback(int result, + struct gntab_unmap_queue_data *data) +{ + struct completion *c = data->data; + + /* BUG_ON used to reproduce existing behaviour, + but is this the best way to deal with this? */ + BUG_ON(result); + complete(c); +} + static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, unsigned int num) { @@ -269,8 +281,17 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; struct persistent_gnt *persistent_gnt; struct rb_node *n; - int ret = 0; int segs_to_unmap = 0; + struct gntab_unmap_queue_data unmap_data; + struct completion unmap_completion; + + init_completion(&unmap_completion); + + unmap_data.data = &unmap_completion; + unmap_data.done = &free_persistent_gnts_unmap_callback; + unmap_data.pages = pages; + unmap_data.unmap_ops = unmap; + unmap_data.kunmap_ops = NULL; foreach_grant_safe(persistent_gnt, n, root, node) { BUG_ON(persistent_gnt->handle == @@ -285,9 +306,11 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST || !rb_next(&persistent_gnt->node)) { - ret = gnttab_unmap_refs(unmap, NULL, pages, - segs_to_unmap); - BUG_ON(ret); + + unmap_data.count = segs_to_unmap; + gnttab_unmap_refs_async(&unmap_data); + wait_for_completion(&unmap_completion); + put_free_pages(blkif, pages, segs_to_unmap); segs_to_unmap = 0; } @@ -653,18 +676,14 @@ void xen_blkbk_free_caches(struct xen_blkif *blkif) shrink_free_pagepool(blkif, 0 /* All */); } -/* - * Unmap the grant references, and also remove the M2P over-rides - * used in the 'pending_req'. - */ -static void xen_blkbk_unmap(struct xen_blkif *blkif, - struct grant_page *pages[], - int num) +static unsigned int xen_blkbk_unmap_prepare( + struct xen_blkif *blkif, + struct grant_page **pages, + unsigned int num, + struct gnttab_unmap_grant_ref *unmap_ops, + struct page **unmap_pages) { - struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; - struct page *unmap_pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; unsigned int i, invcount = 0; - int ret; for (i = 0; i < num; i++) { if (pages[i]->persistent_gnt != NULL) { @@ -674,21 +693,95 @@ static void xen_blkbk_unmap(struct xen_blkif *blkif, if (pages[i]->handle == BLKBACK_INVALID_HANDLE) continue; unmap_pages[invcount] = pages[i]->page; - gnttab_set_unmap_op(&unmap[invcount], vaddr(pages[i]->page), + gnttab_set_unmap_op(&unmap_ops[invcount], vaddr(pages[i]->page), GNTMAP_host_map, pages[i]->handle); pages[i]->handle = BLKBACK_INVALID_HANDLE; - if (++invcount == BLKIF_MAX_SEGMENTS_PER_REQUEST) { - ret = gnttab_unmap_refs(unmap, NULL, unmap_pages, - invcount); + invcount++; + } + + return invcount; +} + +static void xen_blkbk_unmap_and_respond_callback(int result, struct gntab_unmap_queue_data *data) +{ + struct pending_req* pending_req = (struct pending_req*) (data->data); + struct xen_blkif *blkif = pending_req->blkif; + + /* BUG_ON used to reproduce existing behaviour, + but is this the best way to deal with this? */ + BUG_ON(result); + + put_free_pages(blkif, data->pages, data->count); + make_response(blkif, pending_req->id, + pending_req->operation, pending_req->status); + free_req(blkif, pending_req); + /* + * Make sure the request is freed before releasing blkif, + * or there could be a race between free_req and the + * cleanup done in xen_blkif_free during shutdown. + * + * NB: The fact that we might try to wake up pending_free_wq + * before drain_complete (in case there's a drain going on) + * it's not a problem with our current implementation + * because we can assure there's no thread waiting on + * pending_free_wq if there's a drain going on, but it has + * to be taken into account if the current model is changed. + */ + if (atomic_dec_and_test(&blkif->inflight) && atomic_read(&blkif->drain)) { + complete(&blkif->drain_complete); + } + xen_blkif_put(blkif); +} + +static void xen_blkbk_unmap_and_respond(struct pending_req *req) +{ + struct gntab_unmap_queue_data* work = &req->gnttab_unmap_data; + struct xen_blkif *blkif = req->blkif; + struct grant_page **pages = req->segments; + unsigned int invcount; + + invcount = xen_blkbk_unmap_prepare(blkif, pages, req->nr_pages, + req->unmap, req->unmap_pages); + + work->data = req; + work->done = xen_blkbk_unmap_and_respond_callback; + work->unmap_ops = req->unmap; + work->kunmap_ops = NULL; + work->pages = req->unmap_pages; + work->count = invcount; + + gnttab_unmap_refs_async(&req->gnttab_unmap_data); +} + + +/* + * Unmap the grant references. + * + * This could accumulate ops up to the batch size to reduce the number + * of hypercalls, but since this is only used in error paths there's + * no real need. + */ +static void xen_blkbk_unmap(struct xen_blkif *blkif, + struct grant_page *pages[], + int num) +{ + struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + struct page *unmap_pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + unsigned int invcount = 0; + int ret; + + while (num) { + unsigned int batch = min(num, BLKIF_MAX_SEGMENTS_PER_REQUEST); + + invcount = xen_blkbk_unmap_prepare(blkif, pages, batch, + unmap, unmap_pages); + if (invcount) { + ret = gnttab_unmap_refs(unmap, NULL, unmap_pages, invcount); BUG_ON(ret); put_free_pages(blkif, unmap_pages, invcount); - invcount = 0; } - } - if (invcount) { - ret = gnttab_unmap_refs(unmap, NULL, unmap_pages, invcount); - BUG_ON(ret); - put_free_pages(blkif, unmap_pages, invcount); + pages += batch; + num -= batch; } } @@ -982,32 +1075,8 @@ static void __end_block_io_op(struct pending_req *pending_req, int error) * the grant references associated with 'request' and provide * the proper response on the ring. */ - if (atomic_dec_and_test(&pending_req->pendcnt)) { - struct xen_blkif *blkif = pending_req->blkif; - - xen_blkbk_unmap(blkif, - pending_req->segments, - pending_req->nr_pages); - make_response(blkif, pending_req->id, - pending_req->operation, pending_req->status); - free_req(blkif, pending_req); - /* - * Make sure the request is freed before releasing blkif, - * or there could be a race between free_req and the - * cleanup done in xen_blkif_free during shutdown. - * - * NB: The fact that we might try to wake up pending_free_wq - * before drain_complete (in case there's a drain going on) - * it's not a problem with our current implementation - * because we can assure there's no thread waiting on - * pending_free_wq if there's a drain going on, but it has - * to be taken into account if the current model is changed. - */ - if (atomic_dec_and_test(&blkif->inflight) && atomic_read(&blkif->drain)) { - complete(&blkif->drain_complete); - } - xen_blkif_put(blkif); - } + if (atomic_dec_and_test(&pending_req->pendcnt)) + xen_blkbk_unmap_and_respond(pending_req); } /* diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index f65b807e3236..cc90a840e616 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -350,6 +350,9 @@ struct pending_req { struct grant_page *indirect_pages[MAX_INDIRECT_PAGES]; struct seg_buf seg[MAX_INDIRECT_SEGMENTS]; struct bio *biolist[MAX_INDIRECT_SEGMENTS]; + struct gnttab_unmap_grant_ref unmap[MAX_INDIRECT_SEGMENTS]; + struct page *unmap_pages[MAX_INDIRECT_SEGMENTS]; + struct gntab_unmap_queue_data gnttab_unmap_data; }; diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 1ee27ac18de0..de4c8499cbac 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -108,6 +108,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x13d3, 0x3393) }, { USB_DEVICE(0x13d3, 0x3402) }, { USB_DEVICE(0x13d3, 0x3408) }, + { USB_DEVICE(0x13d3, 0x3423) }, { USB_DEVICE(0x13d3, 0x3432) }, /* Atheros AR5BBU12 with sflash firmware */ @@ -162,6 +163,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU22 with sflash firmware */ @@ -174,6 +176,8 @@ static const struct usb_device_id ath3k_blist_tbl[] = { #define USB_REQ_DFU_DNLOAD 1 #define BULK_SIZE 4096 #define FW_HDR_SIZE 20 +#define TIMEGAP_USEC_MIN 50 +#define TIMEGAP_USEC_MAX 100 static int ath3k_load_firmware(struct usb_device *udev, const struct firmware *firmware) @@ -205,6 +209,9 @@ static int ath3k_load_firmware(struct usb_device *udev, pipe = usb_sndbulkpipe(udev, 0x02); while (count) { + /* workaround the compatibility issue with xHCI controller*/ + usleep_range(TIMEGAP_USEC_MIN, TIMEGAP_USEC_MAX); + size = min_t(uint, count, BULK_SIZE); memcpy(send_buf, firmware->data + sent, size); @@ -302,6 +309,9 @@ static int ath3k_load_fwfile(struct usb_device *udev, pipe = usb_sndbulkpipe(udev, 0x02); while (count) { + /* workaround the compatibility issue with xHCI controller*/ + usleep_range(TIMEGAP_USEC_MIN, TIMEGAP_USEC_MAX); + size = min_t(uint, count, BULK_SIZE); memcpy(send_buf, firmware->data + sent, size); diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index b2e7e94a6771..fcfb72e9e0ee 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -696,6 +696,8 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i hdev->flush = bfusb_flush; hdev->send = bfusb_send_frame; + set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks); + if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); hci_free_dev(hdev); diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 330f8f84928d..e75f8ee2512c 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -28,9 +28,9 @@ #define BTM_UPLD_SIZE 2312 /* Time to wait until Host Sleep state change in millisecond */ -#define WAIT_UNTIL_HS_STATE_CHANGED 5000 +#define WAIT_UNTIL_HS_STATE_CHANGED msecs_to_jiffies(5000) /* Time to wait for command response in millisecond */ -#define WAIT_UNTIL_CMD_RESP 5000 +#define WAIT_UNTIL_CMD_RESP msecs_to_jiffies(5000) enum rdwr_status { RDWR_STATUS_SUCCESS = 0, @@ -104,6 +104,7 @@ struct btmrvl_private { #ifdef CONFIG_DEBUG_FS void *debugfs_data; #endif + bool surprise_removed; }; #define MRVL_VENDOR_PKT 0xFE diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 30939c993d94..413597789c61 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -178,6 +178,11 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode, struct sk_buff *skb; struct hci_command_hdr *hdr; + if (priv->surprise_removed) { + BT_ERR("Card is removed"); + return -EFAULT; + } + skb = bt_skb_alloc(HCI_COMMAND_HDR_SIZE + len, GFP_ATOMIC); if (skb == NULL) { BT_ERR("No free skb"); @@ -202,10 +207,14 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode, wake_up_interruptible(&priv->main_thread.wait_q); if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q, - priv->adapter->cmd_complete, - msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) + priv->adapter->cmd_complete || + priv->surprise_removed, + WAIT_UNTIL_CMD_RESP)) return -ETIMEDOUT; + if (priv->surprise_removed) + return -EFAULT; + return 0; } @@ -287,9 +296,10 @@ int btmrvl_enable_hs(struct btmrvl_private *priv) } ret = wait_event_interruptible_timeout(adapter->event_hs_wait_q, - adapter->hs_state, - msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED)); - if (ret < 0) { + adapter->hs_state || + priv->surprise_removed, + WAIT_UNTIL_HS_STATE_CHANGED); + if (ret < 0 || priv->surprise_removed) { BT_ERR("event_hs_wait_q terminated (%d): %d,%d,%d", ret, adapter->hs_state, adapter->ps_state, adapter->wakeup_tries); @@ -538,8 +548,11 @@ static int btmrvl_check_device_tree(struct btmrvl_private *priv) static int btmrvl_setup(struct hci_dev *hdev) { struct btmrvl_private *priv = hci_get_drvdata(hdev); + int ret; - btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); + ret = btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); + if (ret) + return ret; priv->btmrvl_dev.gpio_gap = 0xffff; @@ -597,7 +610,7 @@ static int btmrvl_service_main_thread(void *data) add_wait_queue(&thread->wait_q, &wait); set_current_state(TASK_INTERRUPTIBLE); - if (kthread_should_stop()) { + if (kthread_should_stop() || priv->surprise_removed) { BT_DBG("main_thread: break from main thread"); break; } @@ -616,6 +629,11 @@ static int btmrvl_service_main_thread(void *data) BT_DBG("main_thread woke up"); + if (kthread_should_stop() || priv->surprise_removed) { + BT_DBG("main_thread: break from main thread"); + break; + } + spin_lock_irqsave(&priv->driver_lock, flags); if (adapter->int_count) { adapter->int_count = 0; diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 0057c0b7a776..01d6da577eeb 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -573,7 +573,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) offset += txlen; } while (true); - BT_DBG("FW download over, size %d bytes", offset); + BT_INFO("FW download over, size %d bytes", offset); ret = 0; @@ -798,6 +798,9 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func) priv = card->priv; + if (priv->surprise_removed) + return; + if (card->reg->int_read_to_clear) ret = btmrvl_sdio_read_to_clear(card, &ireg); else @@ -1466,6 +1469,7 @@ static void btmrvl_sdio_remove(struct sdio_func *func) btmrvl_sdio_disable_host_int(card); } BT_DBG("unregester dev"); + card->priv->surprise_removed = true; btmrvl_sdio_unregister_dev(card); btmrvl_remove_card(card->priv); } diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 19cf2cf22e87..b87688881143 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -28,7 +28,7 @@ #include #include -#define VERSION "0.6" +#define VERSION "0.7" static bool disable_scofix; static bool force_scofix; @@ -49,11 +49,17 @@ static struct usb_driver btusb_driver; #define BTUSB_INTEL_BOOT 0x200 #define BTUSB_BCM_PATCHRAM 0x400 #define BTUSB_MARVELL 0x800 +#define BTUSB_SWAVE 0x1000 +#define BTUSB_INTEL_NEW 0x2000 +#define BTUSB_AMP 0x4000 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ { USB_DEVICE_INFO(0xe0, 0x01, 0x01) }, + /* Generic Bluetooth AMP device */ + { USB_DEVICE_INFO(0xe0, 0x01, 0x04), .driver_info = BTUSB_AMP }, + /* Apple-specific (Broadcom) devices */ { USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01) }, @@ -85,7 +91,7 @@ static const struct usb_device_id btusb_table[] = { { USB_DEVICE(0x05ac, 0x8281) }, /* AVM BlueFRITZ! USB v2.0 */ - { USB_DEVICE(0x057c, 0x3800) }, + { USB_DEVICE(0x057c, 0x3800), .driver_info = BTUSB_SWAVE }, /* Bluetooth Ultraport Module from IBM */ { USB_DEVICE(0x04bf, 0x030a) }, @@ -109,16 +115,24 @@ static const struct usb_device_id btusb_table[] = { { USB_DEVICE(0x13d3, 0x3404), .driver_info = BTUSB_BCM_PATCHRAM }, + /* Broadcom BCM20702B0 (Dynex/Insignia) */ + { USB_DEVICE(0x19ff, 0x0239), .driver_info = BTUSB_BCM_PATCHRAM }, + /* Foxconn - Hon Hai */ { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01), .driver_info = BTUSB_BCM_PATCHRAM }, + /* Lite-On Technology - Broadcom based */ + { USB_VENDOR_AND_INTERFACE_INFO(0x04ca, 0xff, 0x01, 0x01), + .driver_info = BTUSB_BCM_PATCHRAM }, + /* Broadcom devices with vendor specific id */ { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01), .driver_info = BTUSB_BCM_PATCHRAM }, /* ASUSTek Computer - Broadcom based */ - { USB_VENDOR_AND_INTERFACE_INFO(0x0b05, 0xff, 0x01, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(0x0b05, 0xff, 0x01, 0x01), + .driver_info = BTUSB_BCM_PATCHRAM }, /* Belkin F8065bf - Broadcom based */ { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) }, @@ -188,6 +202,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ @@ -237,6 +252,9 @@ static const struct usb_device_id blacklist_table[] = { /* CONWISE Technology based adapters with buggy SCO support */ { USB_DEVICE(0x0e5e, 0x6622), .driver_info = BTUSB_BROKEN_ISOC }, + /* Roper Class 1 Bluetooth Dongle (Silicon Wave based) */ + { USB_DEVICE(0x1300, 0x0001), .driver_info = BTUSB_SWAVE }, + /* Digianswer devices */ { USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER }, { USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE }, @@ -249,14 +267,19 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER | BTUSB_BROKEN_ISOC }, - /* Intel Bluetooth device */ - { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL }, - { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, - - /* Marvell device */ + /* Marvell Bluetooth devices */ { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL }, + { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, + { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW }, + + /* Other Intel Bluetooth devices */ + { USB_VENDOR_AND_INTERFACE_INFO(0x8087, 0xe0, 0x01, 0x01), + .driver_info = BTUSB_IGNORE }, + { } /* Terminating entry */ }; @@ -267,6 +290,11 @@ static const struct usb_device_id blacklist_table[] = { #define BTUSB_ISOC_RUNNING 2 #define BTUSB_SUSPENDING 3 #define BTUSB_DID_ISO_RESUME 4 +#define BTUSB_BOOTLOADER 5 +#define BTUSB_DOWNLOADING 6 +#define BTUSB_FIRMWARE_LOADED 7 +#define BTUSB_FIRMWARE_FAILED 8 +#define BTUSB_BOOTING 9 struct btusb_data { struct hci_dev *hdev; @@ -300,14 +328,26 @@ struct btusb_data { struct usb_endpoint_descriptor *isoc_rx_ep; __u8 cmdreq_type; + __u8 cmdreq; unsigned int sco_num; int isoc_altsetting; int suspend_count; + int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb); int (*recv_bulk)(struct btusb_data *data, void *buffer, int count); }; +static int btusb_wait_on_bit_timeout(void *word, int bit, unsigned long timeout, + unsigned mode) +{ + might_sleep(); + if (!test_bit(bit, word)) + return 0; + return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, + mode, timeout); +} + static inline void btusb_free_frags(struct btusb_data *data) { unsigned long flags; @@ -370,7 +410,7 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count) if (bt_cb(skb)->expect == 0) { /* Complete frame */ - hci_recv_frame(data->hdev, skb); + data->recv_event(data->hdev, skb); skb = NULL; } } @@ -952,7 +992,7 @@ static struct urb *alloc_ctrl_urb(struct hci_dev *hdev, struct sk_buff *skb) } dr->bRequestType = data->cmdreq_type; - dr->bRequest = 0; + dr->bRequest = data->cmdreq; dr->wIndex = 0; dr->wValue = 0; dr->wLength = __cpu_to_le16(skb->len); @@ -1290,6 +1330,26 @@ struct intel_version { u8 fw_patch_num; } __packed; +struct intel_boot_params { + __u8 status; + __u8 otp_format; + __u8 otp_content; + __u8 otp_patch; + __le16 dev_revid; + __u8 secure_boot; + __u8 key_from_hdr; + __u8 key_type; + __u8 otp_lock; + __u8 api_lock; + __u8 debug_lock; + bdaddr_t otp_bdaddr; + __u8 min_fw_build_nn; + __u8 min_fw_build_cw; + __u8 min_fw_build_yy; + __u8 limited_cce; + __u8 unlocked_state; +} __packed; + static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev, struct intel_version *ver) { @@ -1698,6 +1758,562 @@ exit_mfg_deactivate: return 0; } +static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) +{ + struct sk_buff *skb; + struct hci_event_hdr *hdr; + struct hci_ev_cmd_complete *evt; + + skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + hdr = (struct hci_event_hdr *)skb_put(skb, sizeof(*hdr)); + hdr->evt = HCI_EV_CMD_COMPLETE; + hdr->plen = sizeof(*evt) + 1; + + evt = (struct hci_ev_cmd_complete *)skb_put(skb, sizeof(*evt)); + evt->ncmd = 0x01; + evt->opcode = cpu_to_le16(opcode); + + *skb_put(skb, 1) = 0x00; + + bt_cb(skb)->pkt_type = HCI_EVENT_PKT; + + return hci_recv_frame(hdev, skb); +} + +static int btusb_recv_bulk_intel(struct btusb_data *data, void *buffer, + int count) +{ + /* When the device is in bootloader mode, then it can send + * events via the bulk endpoint. These events are treated the + * same way as the ones received from the interrupt endpoint. + */ + if (test_bit(BTUSB_BOOTLOADER, &data->flags)) + return btusb_recv_intr(data, buffer, count); + + return btusb_recv_bulk(data, buffer, count); +} + +static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + + if (test_bit(BTUSB_BOOTLOADER, &data->flags)) { + struct hci_event_hdr *hdr = (void *)skb->data; + + /* When the firmware loading completes the device sends + * out a vendor specific event indicating the result of + * the firmware loading. + */ + if (skb->len == 7 && hdr->evt == 0xff && hdr->plen == 0x05 && + skb->data[2] == 0x06) { + if (skb->data[3] != 0x00) + test_bit(BTUSB_FIRMWARE_FAILED, &data->flags); + + if (test_and_clear_bit(BTUSB_DOWNLOADING, + &data->flags) && + test_bit(BTUSB_FIRMWARE_LOADED, &data->flags)) { + smp_mb__after_atomic(); + wake_up_bit(&data->flags, BTUSB_DOWNLOADING); + } + } + + /* When switching to the operational firmware the device + * sends a vendor specific event indicating that the bootup + * completed. + */ + if (skb->len == 9 && hdr->evt == 0xff && hdr->plen == 0x07 && + skb->data[2] == 0x02) { + if (test_and_clear_bit(BTUSB_BOOTING, &data->flags)) { + smp_mb__after_atomic(); + wake_up_bit(&data->flags, BTUSB_BOOTING); + } + } + } + + return hci_recv_frame(hdev, skb); +} + +static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + struct urb *urb; + + BT_DBG("%s", hdev->name); + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return -EBUSY; + + switch (bt_cb(skb)->pkt_type) { + case HCI_COMMAND_PKT: + if (test_bit(BTUSB_BOOTLOADER, &data->flags)) { + struct hci_command_hdr *cmd = (void *)skb->data; + __u16 opcode = le16_to_cpu(cmd->opcode); + + /* When in bootloader mode and the command 0xfc09 + * is received, it needs to be send down the + * bulk endpoint. So allocate a bulk URB instead. + */ + if (opcode == 0xfc09) + urb = alloc_bulk_urb(hdev, skb); + else + urb = alloc_ctrl_urb(hdev, skb); + + /* When the 0xfc01 command is issued to boot into + * the operational firmware, it will actually not + * send a command complete event. To keep the flow + * control working inject that event here. + */ + if (opcode == 0xfc01) + inject_cmd_complete(hdev, opcode); + } else { + urb = alloc_ctrl_urb(hdev, skb); + } + if (IS_ERR(urb)) + return PTR_ERR(urb); + + hdev->stat.cmd_tx++; + return submit_or_queue_tx_urb(hdev, urb); + + case HCI_ACLDATA_PKT: + urb = alloc_bulk_urb(hdev, skb); + if (IS_ERR(urb)) + return PTR_ERR(urb); + + hdev->stat.acl_tx++; + return submit_or_queue_tx_urb(hdev, urb); + + case HCI_SCODATA_PKT: + if (hci_conn_num(hdev, SCO_LINK) < 1) + return -ENODEV; + + urb = alloc_isoc_urb(hdev, skb); + if (IS_ERR(urb)) + return PTR_ERR(urb); + + hdev->stat.sco_tx++; + return submit_tx_urb(hdev, urb); + } + + return -EILSEQ; +} + +static int btusb_intel_secure_send(struct hci_dev *hdev, u8 fragment_type, + u32 plen, const void *param) +{ + while (plen > 0) { + struct sk_buff *skb; + u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen; + + cmd_param[0] = fragment_type; + memcpy(cmd_param + 1, param, fragment_len); + + skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1, + cmd_param, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + + plen -= fragment_len; + param += fragment_len; + } + + return 0; +} + +static void btusb_intel_version_info(struct hci_dev *hdev, + struct intel_version *ver) +{ + const char *variant; + + switch (ver->fw_variant) { + case 0x06: + variant = "Bootloader"; + break; + case 0x23: + variant = "Firmware"; + break; + default: + return; + } + + BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name, + variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f, + ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy); +} + +static int btusb_setup_intel_new(struct hci_dev *hdev) +{ + static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01, + 0x00, 0x08, 0x04, 0x00 }; + struct btusb_data *data = hci_get_drvdata(hdev); + struct sk_buff *skb; + struct intel_version *ver; + struct intel_boot_params *params; + const struct firmware *fw; + const u8 *fw_ptr; + char fwname[64]; + ktime_t calltime, delta, rettime; + unsigned long long duration; + int err; + + BT_DBG("%s", hdev->name); + + calltime = ktime_get(); + + /* Read the Intel version information to determine if the device + * is in bootloader mode or if it already has operational firmware + * loaded. + */ + skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Reading Intel version information failed (%ld)", + hdev->name, PTR_ERR(skb)); + return PTR_ERR(skb); + } + + if (skb->len != sizeof(*ver)) { + BT_ERR("%s: Intel version event size mismatch", hdev->name); + kfree_skb(skb); + return -EILSEQ; + } + + ver = (struct intel_version *)skb->data; + if (ver->status) { + BT_ERR("%s: Intel version command failure (%02x)", + hdev->name, ver->status); + err = -bt_to_errno(ver->status); + kfree_skb(skb); + return err; + } + + /* The hardware platform number has a fixed value of 0x37 and + * for now only accept this single value. + */ + if (ver->hw_platform != 0x37) { + BT_ERR("%s: Unsupported Intel hardware platform (%u)", + hdev->name, ver->hw_platform); + kfree_skb(skb); + return -EINVAL; + } + + /* At the moment only the hardware variant iBT 3.0 (LnP/SfP) is + * supported by this firmware loading method. This check has been + * put in place to ensure correct forward compatibility options + * when newer hardware variants come along. + */ + if (ver->hw_variant != 0x0b) { + BT_ERR("%s: Unsupported Intel hardware variant (%u)", + hdev->name, ver->hw_variant); + kfree_skb(skb); + return -EINVAL; + } + + btusb_intel_version_info(hdev, ver); + + /* The firmware variant determines if the device is in bootloader + * mode or is running operational firmware. The value 0x06 identifies + * the bootloader and the value 0x23 identifies the operational + * firmware. + * + * When the operational firmware is already present, then only + * the check for valid Bluetooth device address is needed. This + * determines if the device will be added as configured or + * unconfigured controller. + * + * It is not possible to use the Secure Boot Parameters in this + * case since that command is only available in bootloader mode. + */ + if (ver->fw_variant == 0x23) { + kfree_skb(skb); + clear_bit(BTUSB_BOOTLOADER, &data->flags); + btusb_check_bdaddr_intel(hdev); + return 0; + } + + /* If the device is not in bootloader mode, then the only possible + * choice is to return an error and abort the device initialization. + */ + if (ver->fw_variant != 0x06) { + BT_ERR("%s: Unsupported Intel firmware variant (%u)", + hdev->name, ver->fw_variant); + kfree_skb(skb); + return -ENODEV; + } + + kfree_skb(skb); + + /* Read the secure boot parameters to identify the operating + * details of the bootloader. + */ + skb = __hci_cmd_sync(hdev, 0xfc0d, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Reading Intel boot parameters failed (%ld)", + hdev->name, PTR_ERR(skb)); + return PTR_ERR(skb); + } + + if (skb->len != sizeof(*params)) { + BT_ERR("%s: Intel boot parameters size mismatch", hdev->name); + kfree_skb(skb); + return -EILSEQ; + } + + params = (struct intel_boot_params *)skb->data; + if (params->status) { + BT_ERR("%s: Intel boot parameters command failure (%02x)", + hdev->name, params->status); + err = -bt_to_errno(params->status); + kfree_skb(skb); + return err; + } + + BT_INFO("%s: Device revision is %u", hdev->name, + le16_to_cpu(params->dev_revid)); + + BT_INFO("%s: Secure boot is %s", hdev->name, + params->secure_boot ? "enabled" : "disabled"); + + BT_INFO("%s: Minimum firmware build %u week %u %u", hdev->name, + params->min_fw_build_nn, params->min_fw_build_cw, + 2000 + params->min_fw_build_yy); + + /* It is required that every single firmware fragment is acknowledged + * with a command complete event. If the boot parameters indicate + * that this bootloader does not send them, then abort the setup. + */ + if (params->limited_cce != 0x00) { + BT_ERR("%s: Unsupported Intel firmware loading method (%u)", + hdev->name, params->limited_cce); + kfree_skb(skb); + return -EINVAL; + } + + /* If the OTP has no valid Bluetooth device address, then there will + * also be no valid address for the operational firmware. + */ + if (!bacmp(¶ms->otp_bdaddr, BDADDR_ANY)) { + BT_INFO("%s: No device address configured", hdev->name); + set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + } + + /* With this Intel bootloader only the hardware variant and device + * revision information are used to select the right firmware. + * + * Currently this bootloader support is limited to hardware variant + * iBT 3.0 (LnP/SfP) which is identified by the value 11 (0x0b). + */ + snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.sfi", + le16_to_cpu(params->dev_revid)); + + err = request_firmware(&fw, fwname, &hdev->dev); + if (err < 0) { + BT_ERR("%s: Failed to load Intel firmware file (%d)", + hdev->name, err); + kfree_skb(skb); + return err; + } + + BT_INFO("%s: Found device firmware: %s", hdev->name, fwname); + + kfree_skb(skb); + + if (fw->size < 644) { + BT_ERR("%s: Invalid size of firmware file (%zu)", + hdev->name, fw->size); + err = -EBADF; + goto done; + } + + set_bit(BTUSB_DOWNLOADING, &data->flags); + + /* Start the firmware download transaction with the Init fragment + * represented by the 128 bytes of CSS header. + */ + err = btusb_intel_secure_send(hdev, 0x00, 128, fw->data); + if (err < 0) { + BT_ERR("%s: Failed to send firmware header (%d)", + hdev->name, err); + goto done; + } + + /* Send the 256 bytes of public key information from the firmware + * as the PKey fragment. + */ + err = btusb_intel_secure_send(hdev, 0x03, 256, fw->data + 128); + if (err < 0) { + BT_ERR("%s: Failed to send firmware public key (%d)", + hdev->name, err); + goto done; + } + + /* Send the 256 bytes of signature information from the firmware + * as the Sign fragment. + */ + err = btusb_intel_secure_send(hdev, 0x02, 256, fw->data + 388); + if (err < 0) { + BT_ERR("%s: Failed to send firmware signature (%d)", + hdev->name, err); + goto done; + } + + fw_ptr = fw->data + 644; + + while (fw_ptr - fw->data < fw->size) { + struct hci_command_hdr *cmd = (void *)fw_ptr; + u8 cmd_len; + + cmd_len = sizeof(*cmd) + cmd->plen; + + /* Send each command from the firmware data buffer as + * a single Data fragment. + */ + err = btusb_intel_secure_send(hdev, 0x01, cmd_len, fw_ptr); + if (err < 0) { + BT_ERR("%s: Failed to send firmware data (%d)", + hdev->name, err); + goto done; + } + + fw_ptr += cmd_len; + } + + set_bit(BTUSB_FIRMWARE_LOADED, &data->flags); + + BT_INFO("%s: Waiting for firmware download to complete", hdev->name); + + /* Before switching the device into operational mode and with that + * booting the loaded firmware, wait for the bootloader notification + * that all fragments have been successfully received. + * + * When the event processing receives the notification, then the + * BTUSB_DOWNLOADING flag will be cleared. + * + * The firmware loading should not take longer than 5 seconds + * and thus just timeout if that happens and fail the setup + * of this device. + */ + err = btusb_wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING, + msecs_to_jiffies(5000), + TASK_INTERRUPTIBLE); + if (err == 1) { + BT_ERR("%s: Firmware loading interrupted", hdev->name); + err = -EINTR; + goto done; + } + + if (err) { + BT_ERR("%s: Firmware loading timeout", hdev->name); + err = -ETIMEDOUT; + goto done; + } + + if (test_bit(BTUSB_FIRMWARE_FAILED, &data->flags)) { + BT_ERR("%s: Firmware loading failed", hdev->name); + err = -ENOEXEC; + goto done; + } + + rettime = ktime_get(); + delta = ktime_sub(rettime, calltime); + duration = (unsigned long long) ktime_to_ns(delta) >> 10; + + BT_INFO("%s: Firmware loaded in %llu usecs", hdev->name, duration); + +done: + release_firmware(fw); + + if (err < 0) + return err; + + calltime = ktime_get(); + + set_bit(BTUSB_BOOTING, &data->flags); + + skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(reset_param), reset_param, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + + /* The bootloader will not indicate when the device is ready. This + * is done by the operational firmware sending bootup notification. + * + * Booting into operational firmware should not take longer than + * 1 second. However if that happens, then just fail the setup + * since something went wrong. + */ + BT_INFO("%s: Waiting for device to boot", hdev->name); + + err = btusb_wait_on_bit_timeout(&data->flags, BTUSB_BOOTING, + msecs_to_jiffies(1000), + TASK_INTERRUPTIBLE); + + if (err == 1) { + BT_ERR("%s: Device boot interrupted", hdev->name); + return -EINTR; + } + + if (err) { + BT_ERR("%s: Device boot timeout", hdev->name); + return -ETIMEDOUT; + } + + rettime = ktime_get(); + delta = ktime_sub(rettime, calltime); + duration = (unsigned long long) ktime_to_ns(delta) >> 10; + + BT_INFO("%s: Device booted in %llu usecs", hdev->name, duration); + + clear_bit(BTUSB_BOOTLOADER, &data->flags); + + return 0; +} + +static void btusb_hw_error_intel(struct hci_dev *hdev, u8 code) +{ + struct sk_buff *skb; + u8 type = 0x00; + + BT_ERR("%s: Hardware error 0x%2.2x", hdev->name, code); + + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Reset after hardware error failed (%ld)", + hdev->name, PTR_ERR(skb)); + return; + } + kfree_skb(skb); + + skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Retrieving Intel exception info failed (%ld)", + hdev->name, PTR_ERR(skb)); + return; + } + + if (skb->len != 13) { + BT_ERR("%s: Exception info size mismatch", hdev->name); + kfree_skb(skb); + return; + } + + if (skb->data[0] != 0x00) { + BT_ERR("%s: Exception info command failure (%02x)", + hdev->name, skb->data[0]); + kfree_skb(skb); + return; + } + + BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1)); + + kfree_skb(skb); +} + static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr) { struct sk_buff *skb; @@ -1943,6 +2559,31 @@ static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr) return 0; } +static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev, + const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + u8 buf[10]; + long ret; + + buf[0] = 0x01; + buf[1] = 0x01; + buf[2] = 0x00; + buf[3] = sizeof(bdaddr_t); + memcpy(buf + 4, bdaddr, sizeof(bdaddr_t)); + + skb = __hci_cmd_sync(hdev, 0xfc0b, sizeof(buf), buf, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: Change address command failed (%ld)", + hdev->name, ret); + return ret; + } + kfree_skb(skb); + + return 0; +} + static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -2003,7 +2644,13 @@ static int btusb_probe(struct usb_interface *intf, if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) return -ENODEV; - data->cmdreq_type = USB_TYPE_CLASS; + if (id->driver_info & BTUSB_AMP) { + data->cmdreq_type = USB_TYPE_CLASS | 0x01; + data->cmdreq = 0x2b; + } else { + data->cmdreq_type = USB_TYPE_CLASS; + data->cmdreq = 0x00; + } data->udev = interface_to_usbdev(intf); data->intf = intf; @@ -2019,7 +2666,14 @@ static int btusb_probe(struct usb_interface *intf, init_usb_anchor(&data->isoc_anchor); spin_lock_init(&data->rxlock); - data->recv_bulk = btusb_recv_bulk; + if (id->driver_info & BTUSB_INTEL_NEW) { + data->recv_event = btusb_recv_event_intel; + data->recv_bulk = btusb_recv_bulk_intel; + set_bit(BTUSB_BOOTLOADER, &data->flags); + } else { + data->recv_event = hci_recv_frame; + data->recv_bulk = btusb_recv_bulk; + } hdev = hci_alloc_dev(); if (!hdev) @@ -2028,6 +2682,11 @@ static int btusb_probe(struct usb_interface *intf, hdev->bus = HCI_USB; hci_set_drvdata(hdev, data); + if (id->driver_info & BTUSB_AMP) + hdev->dev_type = HCI_AMP; + else + hdev->dev_type = HCI_BREDR; + data->hdev = hdev; SET_HCIDEV_DEV(hdev, &intf->dev); @@ -2050,16 +2709,40 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_INTEL) { hdev->setup = btusb_setup_intel; hdev->set_bdaddr = btusb_set_bdaddr_intel; + set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); + } + + if (id->driver_info & BTUSB_INTEL_NEW) { + hdev->send = btusb_send_frame_intel; + hdev->setup = btusb_setup_intel_new; + hdev->hw_error = btusb_hw_error_intel; + hdev->set_bdaddr = btusb_set_bdaddr_intel; + set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); } if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; + if (id->driver_info & BTUSB_SWAVE) { + set_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks); + set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks); + } + if (id->driver_info & BTUSB_INTEL_BOOT) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); - /* Interface numbers are hardcoded in the specification */ - data->isoc = usb_ifnum_to_if(data->udev, 1); + if (id->driver_info & BTUSB_ATH3012) { + hdev->set_bdaddr = btusb_set_bdaddr_ath3012; + set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); + } + + if (id->driver_info & BTUSB_AMP) { + /* AMP controllers do not support SCO packets */ + data->isoc = NULL; + } else { + /* Interface numbers are hardcoded in the specification */ + data->isoc = usb_ifnum_to_if(data->udev, 1); + } if (!reset) set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); @@ -2153,7 +2836,6 @@ static void btusb_disconnect(struct usb_interface *intf) else if (data->isoc) usb_driver_release_interface(&btusb_driver, data->isoc); - btusb_free_frags(data); hci_free_dev(hdev); } diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index eb7682dc123b..81bf297f1034 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -210,12 +210,25 @@ static void mvebu_mbus_disable_window(struct mvebu_mbus_state *mbus, } /* Checks whether the given window number is available */ + +/* On Armada XP, 375 and 38x the MBus window 13 has the remap + * capability, like windows 0 to 7. However, the mvebu-mbus driver + * isn't currently taking into account this special case, which means + * that when window 13 is actually used, the remap registers are left + * to 0, making the device using this MBus window unavailable. The + * quick fix for stable is to not use window 13. A follow up patch + * will correctly handle this window. +*/ static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus, const int win) { void __iomem *addr = mbus->mbuswins_base + mbus->soc->win_cfg_offset(win); u32 ctrl = readl(addr + WIN_CTRL_OFF); + + if (win == 13) + return false; + return !(ctrl & WIN_CTRL_ENABLE); } diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index d5d4cd82b9f7..5c0baa9ffc64 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -976,8 +976,8 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) status = acpi_resource_to_address64(res, &addr); if (ACPI_SUCCESS(status)) { - hdp->hd_phys_address = addr.minimum; - hdp->hd_address = ioremap(addr.minimum, addr.address_length); + hdp->hd_phys_address = addr.address.minimum; + hdp->hd_address = ioremap(addr.address.minimum, addr.address.address_length); if (hpet_is_known(hdp)) { iounmap(hdp->hd_address); diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 4c58333b4257..9a6b63783a94 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -287,13 +287,24 @@ static unsigned long get_unmapped_area_mem(struct file *file, return pgoff << PAGE_SHIFT; } +/* permit direct mmap, for read, write or exec */ +static unsigned memory_mmap_capabilities(struct file *file) +{ + return NOMMU_MAP_DIRECT | + NOMMU_MAP_READ | NOMMU_MAP_WRITE | NOMMU_MAP_EXEC; +} + +static unsigned zero_mmap_capabilities(struct file *file) +{ + return NOMMU_MAP_COPY; +} + /* can't do an in-place private mapping if there's no MMU */ static inline int private_mapping_ok(struct vm_area_struct *vma) { return vma->vm_flags & VM_MAYSHARE; } #else -#define get_unmapped_area_mem NULL static inline int private_mapping_ok(struct vm_area_struct *vma) { @@ -721,7 +732,10 @@ static const struct file_operations mem_fops = { .write = write_mem, .mmap = mmap_mem, .open = open_mem, +#ifndef CONFIG_MMU .get_unmapped_area = get_unmapped_area_mem, + .mmap_capabilities = memory_mmap_capabilities, +#endif }; #ifdef CONFIG_DEVKMEM @@ -731,7 +745,10 @@ static const struct file_operations kmem_fops = { .write = write_kmem, .mmap = mmap_kmem, .open = open_kmem, +#ifndef CONFIG_MMU .get_unmapped_area = get_unmapped_area_mem, + .mmap_capabilities = memory_mmap_capabilities, +#endif }; #endif @@ -760,16 +777,9 @@ static const struct file_operations zero_fops = { .read_iter = read_iter_zero, .aio_write = aio_write_zero, .mmap = mmap_zero, -}; - -/* - * capabilities for /dev/zero - * - permits private mappings, "copies" are taken of the source of zeros - * - no writeback happens - */ -static struct backing_dev_info zero_bdi = { - .name = "char/mem", - .capabilities = BDI_CAP_MAP_COPY | BDI_CAP_NO_ACCT_AND_WRITEBACK, +#ifndef CONFIG_MMU + .mmap_capabilities = zero_mmap_capabilities, +#endif }; static const struct file_operations full_fops = { @@ -783,22 +793,22 @@ static const struct memdev { const char *name; umode_t mode; const struct file_operations *fops; - struct backing_dev_info *dev_info; + fmode_t fmode; } devlist[] = { - [1] = { "mem", 0, &mem_fops, &directly_mappable_cdev_bdi }, + [1] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET }, #ifdef CONFIG_DEVKMEM - [2] = { "kmem", 0, &kmem_fops, &directly_mappable_cdev_bdi }, + [2] = { "kmem", 0, &kmem_fops, FMODE_UNSIGNED_OFFSET }, #endif - [3] = { "null", 0666, &null_fops, NULL }, + [3] = { "null", 0666, &null_fops, 0 }, #ifdef CONFIG_DEVPORT - [4] = { "port", 0, &port_fops, NULL }, + [4] = { "port", 0, &port_fops, 0 }, #endif - [5] = { "zero", 0666, &zero_fops, &zero_bdi }, - [7] = { "full", 0666, &full_fops, NULL }, - [8] = { "random", 0666, &random_fops, NULL }, - [9] = { "urandom", 0666, &urandom_fops, NULL }, + [5] = { "zero", 0666, &zero_fops, 0 }, + [7] = { "full", 0666, &full_fops, 0 }, + [8] = { "random", 0666, &random_fops, 0 }, + [9] = { "urandom", 0666, &urandom_fops, 0 }, #ifdef CONFIG_PRINTK - [11] = { "kmsg", 0644, &kmsg_fops, NULL }, + [11] = { "kmsg", 0644, &kmsg_fops, 0 }, #endif }; @@ -816,12 +826,7 @@ static int memory_open(struct inode *inode, struct file *filp) return -ENXIO; filp->f_op = dev->fops; - if (dev->dev_info) - filp->f_mapping->backing_dev_info = dev->dev_info; - - /* Is /dev/mem or /dev/kmem ? */ - if (dev->dev_info == &directly_mappable_cdev_bdi) - filp->f_mode |= FMODE_UNSIGNED_OFFSET; + filp->f_mode |= dev->fmode; if (dev->fops->open) return dev->fops->open(inode, filp); @@ -846,11 +851,6 @@ static struct class *mem_class; static int __init chr_dev_init(void) { int minor; - int err; - - err = bdi_init(&zero_bdi); - if (err) - return err; if (register_chrdev(MEM_MAJOR, "mem", &memory_fops)) printk("unable to get major %d for memory devs\n", MEM_MAJOR); diff --git a/drivers/char/random.c b/drivers/char/random.c index 04645c09fe5e..9cd6968e2f92 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -569,19 +569,19 @@ static void fast_mix(struct fast_pool *f) __u32 c = f->pool[2], d = f->pool[3]; a += b; c += d; - b = rol32(a, 6); d = rol32(c, 27); + b = rol32(b, 6); d = rol32(d, 27); d ^= a; b ^= c; a += b; c += d; - b = rol32(a, 16); d = rol32(c, 14); + b = rol32(b, 16); d = rol32(d, 14); d ^= a; b ^= c; a += b; c += d; - b = rol32(a, 6); d = rol32(c, 27); + b = rol32(b, 6); d = rol32(d, 27); d ^= a; b ^= c; a += b; c += d; - b = rol32(a, 16); d = rol32(c, 14); + b = rol32(b, 16); d = rol32(d, 14); d ^= a; b ^= c; f->pool[0] = a; f->pool[1] = b; diff --git a/drivers/char/raw.c b/drivers/char/raw.c index a24891b97547..6e29bf2db536 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -104,11 +104,9 @@ static int raw_release(struct inode *inode, struct file *filp) mutex_lock(&raw_mutex); bdev = raw_devices[minor].binding; - if (--raw_devices[minor].inuse == 0) { + if (--raw_devices[minor].inuse == 0) /* Here inode->i_mapping == bdev->bd_inode->i_mapping */ inode->i_mapping = &inode->i_data; - inode->i_mapping->backing_dev_info = &default_backing_dev_info; - } mutex_unlock(&raw_mutex); blkdev_put(bdev, filp->f_mode | FMODE_EXCL); diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index c54cac3f8bc8..9d4e37549eb2 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -100,15 +100,15 @@ config TCG_IBMVTPM will be accessible from within Linux. To compile this driver as a module, choose M here; the module will be called tpm_ibmvtpm. -config TCG_ST33_I2C - tristate "STMicroelectronics ST33 I2C TPM" +config TCG_TIS_I2C_ST33 + tristate "TPM Interface Specification 1.2 Interface (I2C - STMicroelectronics)" depends on I2C depends on GPIOLIB ---help--- If you have a TPM security chip from STMicroelectronics working with an I2C bus say Yes and it will be accessible from within Linux. To compile this driver as a module, choose M here; the module will be - called tpm_stm_st33_i2c. + called tpm_i2c_stm_st33. config TCG_XEN tristate "XEN TPM Interface" @@ -122,4 +122,13 @@ config TCG_XEN To compile this driver as a module, choose M here; the module will be called xen-tpmfront. +config TCG_CRB + tristate "TPM 2.0 CRB Interface" + depends on X86 && ACPI + ---help--- + If you have a TPM security chip that is compliant with the + TCG CRB 2.0 TPM specification say Yes and it will be accessible + from within Linux. To compile this driver as a module, choose + M here; the module will be called tpm_crb. + endif # TCG_TPM diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 4d85dd681b81..990cf183931d 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -2,7 +2,7 @@ # Makefile for the kernel tpm device drivers. # obj-$(CONFIG_TCG_TPM) += tpm.o -tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o tpm-$(CONFIG_ACPI) += tpm_ppi.o ifdef CONFIG_ACPI @@ -20,5 +20,6 @@ obj-$(CONFIG_TCG_NSC) += tpm_nsc.o obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o -obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o +obj-$(CONFIG_TCG_TIS_I2C_ST33) += tpm_i2c_stm_st33.o obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o +obj-$(CONFIG_TCG_CRB) += tpm_crb.o diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c new file mode 100644 index 000000000000..1d278ccd751f --- /dev/null +++ b/drivers/char/tpm/tpm-chip.c @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2004 IBM Corporation + * Copyright (C) 2014 Intel Corporation + * + * Authors: + * Jarkko Sakkinen + * Leendert van Doorn + * Dave Safford + * Reiner Sailer + * Kylene Hall + * + * Maintained by: + * + * TPM chip management routines. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + */ + +#include +#include +#include +#include +#include +#include +#include "tpm.h" +#include "tpm_eventlog.h" + +static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); +static LIST_HEAD(tpm_chip_list); +static DEFINE_SPINLOCK(driver_lock); + +struct class *tpm_class; +dev_t tpm_devt; + +/* + * tpm_chip_find_get - return tpm_chip for a given chip number + * @chip_num the device number for the chip + */ +struct tpm_chip *tpm_chip_find_get(int chip_num) +{ + struct tpm_chip *pos, *chip = NULL; + + rcu_read_lock(); + list_for_each_entry_rcu(pos, &tpm_chip_list, list) { + if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num) + continue; + + if (try_module_get(pos->pdev->driver->owner)) { + chip = pos; + break; + } + } + rcu_read_unlock(); + return chip; +} + +/** + * tpm_dev_release() - free chip memory and the device number + * @dev: the character device for the TPM chip + * + * This is used as the release function for the character device. + */ +static void tpm_dev_release(struct device *dev) +{ + struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); + + spin_lock(&driver_lock); + clear_bit(chip->dev_num, dev_mask); + spin_unlock(&driver_lock); + kfree(chip); +} + +/** + * tpmm_chip_alloc() - allocate a new struct tpm_chip instance + * @dev: device to which the chip is associated + * @ops: struct tpm_class_ops instance + * + * Allocates a new struct tpm_chip instance and assigns a free + * device number for it. Caller does not have to worry about + * freeing the allocated resources. When the devices is removed + * devres calls tpmm_chip_remove() to do the job. + */ +struct tpm_chip *tpmm_chip_alloc(struct device *dev, + const struct tpm_class_ops *ops) +{ + struct tpm_chip *chip; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) + return ERR_PTR(-ENOMEM); + + mutex_init(&chip->tpm_mutex); + INIT_LIST_HEAD(&chip->list); + + chip->ops = ops; + + spin_lock(&driver_lock); + chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES); + spin_unlock(&driver_lock); + + if (chip->dev_num >= TPM_NUM_DEVICES) { + dev_err(dev, "No available tpm device numbers\n"); + kfree(chip); + return ERR_PTR(-ENOMEM); + } + + set_bit(chip->dev_num, dev_mask); + + scnprintf(chip->devname, sizeof(chip->devname), "tpm%d", chip->dev_num); + + chip->pdev = dev; + + dev_set_drvdata(dev, chip); + + chip->dev.class = tpm_class; + chip->dev.release = tpm_dev_release; + chip->dev.parent = chip->pdev; + + if (chip->dev_num == 0) + chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR); + else + chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num); + + dev_set_name(&chip->dev, "%s", chip->devname); + + device_initialize(&chip->dev); + + chip->cdev.owner = chip->pdev->driver->owner; + cdev_init(&chip->cdev, &tpm_fops); + + return chip; +} +EXPORT_SYMBOL_GPL(tpmm_chip_alloc); + +static int tpm_dev_add_device(struct tpm_chip *chip) +{ + int rc; + + rc = device_add(&chip->dev); + if (rc) { + dev_err(&chip->dev, + "unable to device_register() %s, major %d, minor %d, err=%d\n", + chip->devname, MAJOR(chip->dev.devt), + MINOR(chip->dev.devt), rc); + + return rc; + } + + rc = cdev_add(&chip->cdev, chip->dev.devt, 1); + if (rc) { + dev_err(&chip->dev, + "unable to cdev_add() %s, major %d, minor %d, err=%d\n", + chip->devname, MAJOR(chip->dev.devt), + MINOR(chip->dev.devt), rc); + + device_unregister(&chip->dev); + return rc; + } + + return rc; +} + +static void tpm_dev_del_device(struct tpm_chip *chip) +{ + cdev_del(&chip->cdev); + device_unregister(&chip->dev); +} + +/* + * tpm_chip_register() - create a character device for the TPM chip + * @chip: TPM chip to use. + * + * Creates a character device for the TPM chip and adds sysfs interfaces for + * the device, PPI and TCPA. As the last step this function adds the + * chip to the list of TPM chips available for use. + * + * NOTE: This function should be only called after the chip initialization + * is complete. + * + * Called from tpm_.c probe function only for devices + * the driver has determined it should claim. Prior to calling + * this function the specific probe function has called pci_enable_device + * upon errant exit from this function specific probe function should call + * pci_disable_device + */ +int tpm_chip_register(struct tpm_chip *chip) +{ + int rc; + + rc = tpm_dev_add_device(chip); + if (rc) + return rc; + + /* Populate sysfs for TPM1 devices. */ + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { + rc = tpm_sysfs_add_device(chip); + if (rc) + goto del_misc; + + rc = tpm_add_ppi(chip); + if (rc) + goto del_sysfs; + + chip->bios_dir = tpm_bios_log_setup(chip->devname); + } + + /* Make the chip available. */ + spin_lock(&driver_lock); + list_add_rcu(&chip->list, &tpm_chip_list); + spin_unlock(&driver_lock); + + chip->flags |= TPM_CHIP_FLAG_REGISTERED; + + return 0; +del_sysfs: + tpm_sysfs_del_device(chip); +del_misc: + tpm_dev_del_device(chip); + return rc; +} +EXPORT_SYMBOL_GPL(tpm_chip_register); + +/* + * tpm_chip_unregister() - release the TPM driver + * @chip: TPM chip to use. + * + * Takes the chip first away from the list of available TPM chips and then + * cleans up all the resources reserved by tpm_chip_register(). + * + * NOTE: This function should be only called before deinitializing chip + * resources. + */ +void tpm_chip_unregister(struct tpm_chip *chip) +{ + if (!(chip->flags & TPM_CHIP_FLAG_REGISTERED)) + return; + + spin_lock(&driver_lock); + list_del_rcu(&chip->list); + spin_unlock(&driver_lock); + synchronize_rcu(); + + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { + if (chip->bios_dir) + tpm_bios_log_teardown(chip->bios_dir); + tpm_remove_ppi(chip); + tpm_sysfs_del_device(chip); + } + + tpm_dev_del_device(chip); +} +EXPORT_SYMBOL_GPL(tpm_chip_unregister); diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c index d9b774e02a1f..de0337ebd658 100644 --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -17,7 +17,6 @@ * License. * */ -#include #include #include #include "tpm.h" @@ -54,16 +53,15 @@ static void timeout_work(struct work_struct *work) static int tpm_open(struct inode *inode, struct file *file) { - struct miscdevice *misc = file->private_data; - struct tpm_chip *chip = container_of(misc, struct tpm_chip, - vendor.miscdev); + struct tpm_chip *chip = + container_of(inode->i_cdev, struct tpm_chip, cdev); struct file_priv *priv; /* It's assured that the chip will be opened just once, * by the check of is_open variable, which is protected * by driver_lock. */ if (test_and_set_bit(0, &chip->is_open)) { - dev_dbg(chip->dev, "Another process owns this TPM\n"); + dev_dbg(chip->pdev, "Another process owns this TPM\n"); return -EBUSY; } @@ -81,7 +79,7 @@ static int tpm_open(struct inode *inode, struct file *file) INIT_WORK(&priv->work, timeout_work); file->private_data = priv; - get_device(chip->dev); + get_device(chip->pdev); return 0; } @@ -168,12 +166,12 @@ static int tpm_release(struct inode *inode, struct file *file) file->private_data = NULL; atomic_set(&priv->data_pending, 0); clear_bit(0, &priv->chip->is_open); - put_device(priv->chip->dev); + put_device(priv->chip->pdev); kfree(priv); return 0; } -static const struct file_operations tpm_fops = { +const struct file_operations tpm_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .open = tpm_open, @@ -182,32 +180,4 @@ static const struct file_operations tpm_fops = { .release = tpm_release, }; -int tpm_dev_add_device(struct tpm_chip *chip) -{ - int rc; - chip->vendor.miscdev.fops = &tpm_fops; - if (chip->dev_num == 0) - chip->vendor.miscdev.minor = TPM_MINOR; - else - chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; - - chip->vendor.miscdev.name = chip->devname; - chip->vendor.miscdev.parent = chip->dev; - - rc = misc_register(&chip->vendor.miscdev); - if (rc) { - chip->vendor.miscdev.name = NULL; - dev_err(chip->dev, - "unable to misc_register %s, minor %d err=%d\n", - chip->vendor.miscdev.name, - chip->vendor.miscdev.minor, rc); - } - return rc; -} - -void tpm_dev_del_device(struct tpm_chip *chip) -{ - if (chip->vendor.miscdev.name) - misc_deregister(&chip->vendor.miscdev); -} diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 6af17002a115..bf53a3771da5 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2004 IBM Corporation + * Copyright (C) 2014 Intel Corporation * * Authors: * Leendert van Doorn @@ -47,10 +48,6 @@ module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644); MODULE_PARM_DESC(suspend_pcr, "PCR to use for dummy writes to faciltate flush on suspend."); -static LIST_HEAD(tpm_chip_list); -static DEFINE_SPINLOCK(driver_lock); -static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); - /* * Array with one entry per ordinal defining the maximum amount * of time the chip could take to return the result. The ordinal @@ -346,7 +343,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, if (count == 0) return -ENODATA; if (count > bufsiz) { - dev_err(chip->dev, + dev_err(chip->pdev, "invalid count value %x %zx\n", count, bufsiz); return -E2BIG; } @@ -355,7 +352,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { - dev_err(chip->dev, + dev_err(chip->pdev, "tpm_transmit: tpm_send: error %zd\n", rc); goto out; } @@ -363,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, if (chip->vendor.irq) goto out_recv; - stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); + if (chip->flags & TPM_CHIP_FLAG_TPM2) + stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal); + else + stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); do { u8 status = chip->ops->status(chip); if ((status & chip->ops->req_complete_mask) == @@ -371,7 +371,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, goto out_recv; if (chip->ops->req_canceled(chip, status)) { - dev_err(chip->dev, "Operation Canceled\n"); + dev_err(chip->pdev, "Operation Canceled\n"); rc = -ECANCELED; goto out; } @@ -381,14 +381,14 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, } while (time_before(jiffies, stop)); chip->ops->cancel(chip); - dev_err(chip->dev, "Operation Timed out\n"); + dev_err(chip->pdev, "Operation Timed out\n"); rc = -ETIME; goto out; out_recv: rc = chip->ops->recv(chip, (u8 *) buf, bufsiz); if (rc < 0) - dev_err(chip->dev, + dev_err(chip->pdev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: mutex_unlock(&chip->tpm_mutex); @@ -398,9 +398,10 @@ out: #define TPM_DIGEST_SIZE 20 #define TPM_RET_CODE_IDX 6 -static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, - int len, const char *desc) +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, + int len, const char *desc) { + struct tpm_output_header *header; int err; len = tpm_transmit(chip, (u8 *) cmd, len); @@ -409,9 +410,12 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, else if (len < TPM_HEADER_SIZE) return -EFAULT; - err = be32_to_cpu(cmd->header.out.return_code); + header = cmd; + + err = be32_to_cpu(header->return_code); if (err != 0 && desc) - dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); + dev_err(chip->pdev, "A TPM error (%d) occurred %s\n", err, + desc); return err; } @@ -448,7 +452,7 @@ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap, tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = subcap_id; } - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); if (!rc) *cap = tpm_cmd.params.getcap_out.cap; return rc; @@ -464,8 +468,8 @@ void tpm_gen_interrupt(struct tpm_chip *chip) tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, - "attempting to determine the timeouts"); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to determine the timeouts"); } EXPORT_SYMBOL_GPL(tpm_gen_interrupt); @@ -483,9 +487,10 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) { struct tpm_cmd_t start_cmd; start_cmd.header.in = tpm_startup_header; + start_cmd.params.startup_in.startup_type = startup_type; - return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, - "attempting to start the TPM"); + return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to start the TPM"); } int tpm_get_timeouts(struct tpm_chip *chip) @@ -500,12 +505,12 @@ int tpm_get_timeouts(struct tpm_chip *chip) tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL); if (rc == TPM_ERR_INVALID_POSTINIT) { /* The TPM is not started, we are the first to talk to it. Execute a startup command. */ - dev_info(chip->dev, "Issuing TPM_STARTUP"); + dev_info(chip->pdev, "Issuing TPM_STARTUP"); if (tpm_startup(chip, TPM_ST_CLEAR)) return rc; @@ -513,11 +518,11 @@ int tpm_get_timeouts(struct tpm_chip *chip) tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL); } if (rc) { - dev_err(chip->dev, + dev_err(chip->pdev, "A TPM error (%zd) occurred attempting to determine the timeouts\n", rc); goto duration; @@ -556,7 +561,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) /* Report adjusted timeouts */ if (chip->vendor.timeout_adjusted) { - dev_info(chip->dev, + dev_info(chip->pdev, HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n", old_timeout[0], new_timeout[0], old_timeout[1], new_timeout[1], @@ -575,8 +580,8 @@ duration: tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, - "attempting to determine the durations"); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to determine the durations"); if (rc) return rc; @@ -603,7 +608,7 @@ duration: chip->vendor.duration[TPM_MEDIUM] *= 1000; chip->vendor.duration[TPM_LONG] *= 1000; chip->vendor.duration_adjusted = true; - dev_info(chip->dev, "Adjusting TPM timeout parameters."); + dev_info(chip->pdev, "Adjusting TPM timeout parameters."); } return 0; } @@ -631,32 +636,11 @@ static int tpm_continue_selftest(struct tpm_chip *chip) struct tpm_cmd_t cmd; cmd.header.in = continue_selftest_header; - rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, - "continue selftest"); + rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, + "continue selftest"); return rc; } -/* - * tpm_chip_find_get - return tpm_chip for given chip number - */ -static struct tpm_chip *tpm_chip_find_get(int chip_num) -{ - struct tpm_chip *pos, *chip = NULL; - - rcu_read_lock(); - list_for_each_entry_rcu(pos, &tpm_chip_list, list) { - if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num) - continue; - - if (try_module_get(pos->dev->driver->owner)) { - chip = pos; - break; - } - } - rcu_read_unlock(); - return chip; -} - #define TPM_ORDINAL_PCRREAD cpu_to_be32(21) #define READ_PCR_RESULT_SIZE 30 static struct tpm_input_header pcrread_header = { @@ -672,8 +656,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) cmd.header.in = pcrread_header; cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); - rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, - "attempting to read a pcr value"); + rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, + "attempting to read a pcr value"); if (rc == 0) memcpy(res_buf, cmd.params.pcrread_out.pcr_result, @@ -700,7 +684,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) chip = tpm_chip_find_get(chip_num); if (chip == NULL) return -ENODEV; - rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); + if (chip->flags & TPM_CHIP_FLAG_TPM2) + rc = tpm2_pcr_read(chip, pcr_idx, res_buf); + else + rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); tpm_chip_put(chip); return rc; } @@ -734,11 +721,17 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) if (chip == NULL) return -ENODEV; + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + rc = tpm2_pcr_extend(chip, pcr_idx, hash); + tpm_chip_put(chip); + return rc; + } + cmd.header.in = pcrextend_header; cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); - rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, - "attempting extend a PCR value"); + rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + "attempting extend a PCR value"); tpm_chip_put(chip); return rc; @@ -781,7 +774,7 @@ int tpm_do_selftest(struct tpm_chip *chip) * around 300ms while the self test is ongoing, keep trying * until the self test duration expires. */ if (rc == -ETIME) { - dev_info(chip->dev, HW_ERR "TPM command timed out during continue self test"); + dev_info(chip->pdev, HW_ERR "TPM command timed out during continue self test"); msleep(delay_msec); continue; } @@ -791,7 +784,7 @@ int tpm_do_selftest(struct tpm_chip *chip) rc = be32_to_cpu(cmd.header.out.return_code); if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) { - dev_info(chip->dev, + dev_info(chip->pdev, "TPM is disabled/deactivated (0x%X)\n", rc); /* TPM is disabled and/or deactivated; driver can * proceed and TPM does handle commands for @@ -817,7 +810,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen) if (chip == NULL) return -ENODEV; - rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd"); + rc = tpm_transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd"); tpm_chip_put(chip); return rc; @@ -884,30 +877,6 @@ again: } EXPORT_SYMBOL_GPL(wait_for_tpm_stat); -void tpm_remove_hardware(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - - if (chip == NULL) { - dev_err(dev, "No device data found\n"); - return; - } - - spin_lock(&driver_lock); - list_del_rcu(&chip->list); - spin_unlock(&driver_lock); - synchronize_rcu(); - - tpm_dev_del_device(chip); - tpm_sysfs_del_device(chip); - tpm_remove_ppi(&dev->kobj); - tpm_bios_log_teardown(chip->bios_dir); - - /* write it this way to be explicit (chip->dev == dev) */ - put_device(chip->dev); -} -EXPORT_SYMBOL_GPL(tpm_remove_hardware); - #define TPM_ORD_SAVESTATE cpu_to_be32(152) #define SAVESTATE_RESULT_SIZE 10 @@ -932,20 +901,23 @@ int tpm_pm_suspend(struct device *dev) if (chip == NULL) return -ENODEV; + if (chip->flags & TPM_CHIP_FLAG_TPM2) + return tpm2_shutdown(chip, TPM2_SU_CLEAR); + /* for buggy tpm, flush pcrs with extend to selected dummy */ if (tpm_suspend_pcr) { cmd.header.in = pcrextend_header; cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr); memcpy(cmd.params.pcrextend_in.hash, dummy_hash, TPM_DIGEST_SIZE); - rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, - "extending dummy pcr before suspend"); + rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + "extending dummy pcr before suspend"); } /* now do the actual savestate */ for (try = 0; try < TPM_RETRY; try++) { cmd.header.in = savestate_header; - rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL); + rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL); /* * If the TPM indicates that it is too busy to respond to @@ -963,10 +935,10 @@ int tpm_pm_suspend(struct device *dev) } if (rc) - dev_err(chip->dev, + dev_err(chip->pdev, "Error (%d) sending savestate before suspend\n", rc); else if (try > 0) - dev_warn(chip->dev, "TPM savestate took %dms\n", + dev_warn(chip->pdev, "TPM savestate took %dms\n", try * TPM_TIMEOUT_RETRY); return rc; @@ -1018,11 +990,17 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) if (chip == NULL) return -ENODEV; + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + err = tpm2_get_random(chip, out, max); + tpm_chip_put(chip); + return err; + } + do { tpm_cmd.header.in = tpm_getrandom_header; tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); - err = transmit_cmd(chip, &tpm_cmd, + err = tpm_transmit_cmd(chip, &tpm_cmd, TPM_GETRANDOM_RESULT_SIZE + num_bytes, "attempting get random"); if (err) @@ -1041,103 +1019,34 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) } EXPORT_SYMBOL_GPL(tpm_get_random); -/* In case vendor provided release function, call it too.*/ - -void tpm_dev_vendor_release(struct tpm_chip *chip) +static int __init tpm_init(void) { - if (!chip) - return; + int rc; - clear_bit(chip->dev_num, dev_mask); -} -EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); - - -/* - * Once all references to platform device are down to 0, - * release all allocated structures. - */ -static void tpm_dev_release(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - - if (!chip) - return; - - tpm_dev_vendor_release(chip); - - chip->release(dev); - kfree(chip); -} - -/* - * Called from tpm_.c probe function only for devices - * the driver has determined it should claim. Prior to calling - * this function the specific probe function has called pci_enable_device - * upon errant exit from this function specific probe function should call - * pci_disable_device - */ -struct tpm_chip *tpm_register_hardware(struct device *dev, - const struct tpm_class_ops *ops) -{ - struct tpm_chip *chip; - - /* Driver specific per-device data */ - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - - if (chip == NULL) - return NULL; - - mutex_init(&chip->tpm_mutex); - INIT_LIST_HEAD(&chip->list); - - chip->ops = ops; - chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES); - - if (chip->dev_num >= TPM_NUM_DEVICES) { - dev_err(dev, "No available tpm device numbers\n"); - goto out_free; + tpm_class = class_create(THIS_MODULE, "tpm"); + if (IS_ERR(tpm_class)) { + pr_err("couldn't create tpm class\n"); + return PTR_ERR(tpm_class); } - set_bit(chip->dev_num, dev_mask); + rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm"); + if (rc < 0) { + pr_err("tpm: failed to allocate char dev region\n"); + class_destroy(tpm_class); + return rc; + } - scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm", - chip->dev_num); - - chip->dev = get_device(dev); - chip->release = dev->release; - dev->release = tpm_dev_release; - dev_set_drvdata(dev, chip); - - if (tpm_dev_add_device(chip)) - goto put_device; - - if (tpm_sysfs_add_device(chip)) - goto del_misc; - - if (tpm_add_ppi(&dev->kobj)) - goto del_sysfs; - - chip->bios_dir = tpm_bios_log_setup(chip->devname); - - /* Make chip available */ - spin_lock(&driver_lock); - list_add_rcu(&chip->list, &tpm_chip_list); - spin_unlock(&driver_lock); - - return chip; - -del_sysfs: - tpm_sysfs_del_device(chip); -del_misc: - tpm_dev_del_device(chip); -put_device: - put_device(chip->dev); -out_free: - kfree(chip); - return NULL; + return 0; } -EXPORT_SYMBOL_GPL(tpm_register_hardware); + +static void __exit tpm_exit(void) +{ + class_destroy(tpm_class); + unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES); +} + +subsys_initcall(tpm_init); +module_exit(tpm_exit); MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); MODULE_DESCRIPTION("TPM Driver"); diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 01730a27ae07..ee66fd4673f3 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -20,25 +20,6 @@ #include #include "tpm.h" -/* XXX for now this helper is duplicated in tpm-interface.c */ -static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, - int len, const char *desc) -{ - int err; - - len = tpm_transmit(chip, (u8 *) cmd, len); - if (len < 0) - return len; - else if (len < TPM_HEADER_SIZE) - return -EFAULT; - - err = be32_to_cpu(cmd->header.out.return_code); - if (err != 0 && desc) - dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); - - return err; -} - #define READ_PUBEK_RESULT_SIZE 314 #define TPM_ORD_READPUBEK cpu_to_be32(124) static struct tpm_input_header tpm_readpubek_header = { @@ -58,8 +39,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, struct tpm_chip *chip = dev_get_drvdata(dev); tpm_cmd.header.in = tpm_readpubek_header; - err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, - "attempting to read the PUBEK"); + err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, + "attempting to read the PUBEK"); if (err) goto out; @@ -303,16 +284,16 @@ static const struct attribute_group tpm_dev_group = { int tpm_sysfs_add_device(struct tpm_chip *chip) { int err; - err = sysfs_create_group(&chip->dev->kobj, + err = sysfs_create_group(&chip->pdev->kobj, &tpm_dev_group); if (err) - dev_err(chip->dev, + dev_err(chip->pdev, "failed to create sysfs attributes, %d\n", err); return err; } void tpm_sysfs_del_device(struct tpm_chip *chip) { - sysfs_remove_group(&chip->dev->kobj, &tpm_dev_group); + sysfs_remove_group(&chip->pdev->kobj, &tpm_dev_group); } diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index e4d0888d2eab..7b0727c5e803 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -10,23 +10,24 @@ * Maintained by: * * Device driver for TCG/TCPA TPM (trusted platform module). - * Specifications at www.trustedcomputinggroup.org + * Specifications at www.trustedcomputinggroup.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, version 2 of the * License. - * + * */ #include #include #include #include #include -#include #include #include #include +#include +#include enum tpm_const { TPM_MINOR = 224, /* officially assigned */ @@ -61,6 +62,59 @@ enum tpm_duration { #define TPM_ERR_INVALID_POSTINIT 38 #define TPM_HEADER_SIZE 10 + +enum tpm2_const { + TPM2_PLATFORM_PCR = 24, + TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8), + TPM2_TIMEOUT_A = 750, + TPM2_TIMEOUT_B = 2000, + TPM2_TIMEOUT_C = 200, + TPM2_TIMEOUT_D = 30, + TPM2_DURATION_SHORT = 20, + TPM2_DURATION_MEDIUM = 750, + TPM2_DURATION_LONG = 2000, +}; + +enum tpm2_structures { + TPM2_ST_NO_SESSIONS = 0x8001, + TPM2_ST_SESSIONS = 0x8002, +}; + +enum tpm2_return_codes { + TPM2_RC_INITIALIZE = 0x0100, + TPM2_RC_TESTING = 0x090A, + TPM2_RC_DISABLED = 0x0120, +}; + +enum tpm2_algorithms { + TPM2_ALG_SHA1 = 0x0004, +}; + +enum tpm2_command_codes { + TPM2_CC_FIRST = 0x011F, + TPM2_CC_SELF_TEST = 0x0143, + TPM2_CC_STARTUP = 0x0144, + TPM2_CC_SHUTDOWN = 0x0145, + TPM2_CC_GET_CAPABILITY = 0x017A, + TPM2_CC_GET_RANDOM = 0x017B, + TPM2_CC_PCR_READ = 0x017E, + TPM2_CC_PCR_EXTEND = 0x0182, + TPM2_CC_LAST = 0x018F, +}; + +enum tpm2_permanent_handles { + TPM2_RS_PW = 0x40000009, +}; + +enum tpm2_capabilities { + TPM2_CAP_TPM_PROPERTIES = 6, +}; + +enum tpm2_startup_types { + TPM2_SU_CLEAR = 0x0000, + TPM2_SU_STATE = 0x0001, +}; + struct tpm_chip; struct tpm_vendor_specific { @@ -73,7 +127,6 @@ struct tpm_vendor_specific { int region_size; int have_region; - struct miscdevice miscdev; struct list_head list; int locality; unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */ @@ -88,15 +141,27 @@ struct tpm_vendor_specific { u16 manufacturer_id; }; -#define TPM_VPRIV(c) (c)->vendor.priv +#define TPM_VPRIV(c) ((c)->vendor.priv) #define TPM_VID_INTEL 0x8086 #define TPM_VID_WINBOND 0x1050 #define TPM_VID_STM 0x104A +#define TPM_PPI_VERSION_LEN 3 + +enum tpm_chip_flags { + TPM_CHIP_FLAG_REGISTERED = BIT(0), + TPM_CHIP_FLAG_PPI = BIT(1), + TPM_CHIP_FLAG_TPM2 = BIT(2), +}; + struct tpm_chip { - struct device *dev; /* Device stuff */ + struct device *pdev; /* Device stuff */ + struct device dev; + struct cdev cdev; + const struct tpm_class_ops *ops; + unsigned int flags; int dev_num; /* /dev/tpm# */ char devname[7]; @@ -109,15 +174,19 @@ struct tpm_chip { struct dentry **bios_dir; +#ifdef CONFIG_ACPI + acpi_handle acpi_dev_handle; + char ppi_version[TPM_PPI_VERSION_LEN + 1]; +#endif /* CONFIG_ACPI */ + struct list_head list; - void (*release) (struct device *); }; #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor) static inline void tpm_chip_put(struct tpm_chip *chip) { - module_put(chip->dev->driver->owner); + module_put(chip->pdev->driver->owner); } static inline int tpm_read_index(int base, int index) @@ -313,40 +382,57 @@ struct tpm_cmd_t { tpm_cmd_params params; } __packed; -ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); +extern struct class *tpm_class; +extern dev_t tpm_devt; +extern const struct file_operations tpm_fops; +ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, size_t bufsiz); +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, int len, + const char *desc); extern int tpm_get_timeouts(struct tpm_chip *); extern void tpm_gen_interrupt(struct tpm_chip *); extern int tpm_do_selftest(struct tpm_chip *); extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); -extern struct tpm_chip* tpm_register_hardware(struct device *, - const struct tpm_class_ops *ops); -extern void tpm_dev_vendor_release(struct tpm_chip *); -extern void tpm_remove_hardware(struct device *); extern int tpm_pm_suspend(struct device *); extern int tpm_pm_resume(struct device *); extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long, wait_queue_head_t *, bool); -int tpm_dev_add_device(struct tpm_chip *chip); -void tpm_dev_del_device(struct tpm_chip *chip); +struct tpm_chip *tpm_chip_find_get(int chip_num); +extern struct tpm_chip *tpmm_chip_alloc(struct device *dev, + const struct tpm_class_ops *ops); +extern int tpm_chip_register(struct tpm_chip *chip); +extern void tpm_chip_unregister(struct tpm_chip *chip); + int tpm_sysfs_add_device(struct tpm_chip *chip); void tpm_sysfs_del_device(struct tpm_chip *chip); int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); #ifdef CONFIG_ACPI -extern int tpm_add_ppi(struct kobject *); -extern void tpm_remove_ppi(struct kobject *); +extern int tpm_add_ppi(struct tpm_chip *chip); +extern void tpm_remove_ppi(struct tpm_chip *chip); #else -static inline int tpm_add_ppi(struct kobject *parent) +static inline int tpm_add_ppi(struct tpm_chip *chip) { return 0; } -static inline void tpm_remove_ppi(struct kobject *parent) +static inline void tpm_remove_ppi(struct tpm_chip *chip) { } #endif + +int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); +int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash); +int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max); +ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, + u32 *value, const char *desc); + +extern int tpm2_startup(struct tpm_chip *chip, u16 startup_type); +extern int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type); +extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32); +extern int tpm2_do_selftest(struct tpm_chip *chip); +extern int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet); diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c new file mode 100644 index 000000000000..1abe6502219f --- /dev/null +++ b/drivers/char/tpm/tpm2-cmd.c @@ -0,0 +1,617 @@ +/* + * Copyright (C) 2014 Intel Corporation + * + * Authors: + * Jarkko Sakkinen + * + * Maintained by: + * + * This file contains TPM2 protocol implementations of the commands + * used by the kernel internally. + * + * 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 "tpm.h" + +struct tpm2_startup_in { + __be16 startup_type; +} __packed; + +struct tpm2_self_test_in { + u8 full_test; +} __packed; + +struct tpm2_pcr_read_in { + __be32 pcr_selects_cnt; + __be16 hash_alg; + u8 pcr_select_size; + u8 pcr_select[TPM2_PCR_SELECT_MIN]; +} __packed; + +struct tpm2_pcr_read_out { + __be32 update_cnt; + __be32 pcr_selects_cnt; + __be16 hash_alg; + u8 pcr_select_size; + u8 pcr_select[TPM2_PCR_SELECT_MIN]; + __be32 digests_cnt; + __be16 digest_size; + u8 digest[TPM_DIGEST_SIZE]; +} __packed; + +struct tpm2_null_auth_area { + __be32 handle; + __be16 nonce_size; + u8 attributes; + __be16 auth_size; +} __packed; + +struct tpm2_pcr_extend_in { + __be32 pcr_idx; + __be32 auth_area_size; + struct tpm2_null_auth_area auth_area; + __be32 digest_cnt; + __be16 hash_alg; + u8 digest[TPM_DIGEST_SIZE]; +} __packed; + +struct tpm2_get_tpm_pt_in { + __be32 cap_id; + __be32 property_id; + __be32 property_cnt; +} __packed; + +struct tpm2_get_tpm_pt_out { + u8 more_data; + __be32 subcap_id; + __be32 property_cnt; + __be32 property_id; + __be32 value; +} __packed; + +struct tpm2_get_random_in { + __be16 size; +} __packed; + +struct tpm2_get_random_out { + __be16 size; + u8 buffer[TPM_MAX_RNG_DATA]; +} __packed; + +union tpm2_cmd_params { + struct tpm2_startup_in startup_in; + struct tpm2_self_test_in selftest_in; + struct tpm2_pcr_read_in pcrread_in; + struct tpm2_pcr_read_out pcrread_out; + struct tpm2_pcr_extend_in pcrextend_in; + struct tpm2_get_tpm_pt_in get_tpm_pt_in; + struct tpm2_get_tpm_pt_out get_tpm_pt_out; + struct tpm2_get_random_in getrandom_in; + struct tpm2_get_random_out getrandom_out; +}; + +struct tpm2_cmd { + tpm_cmd_header header; + union tpm2_cmd_params params; +} __packed; + +/* + * Array with one entry per ordinal defining the maximum amount + * of time the chip could take to return the result. The values + * of the SHORT, MEDIUM, and LONG durations are taken from the + * PC Client Profile (PTP) specification. + */ +static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = { + TPM_UNDEFINED, /* 11F */ + TPM_UNDEFINED, /* 120 */ + TPM_LONG, /* 121 */ + TPM_UNDEFINED, /* 122 */ + TPM_UNDEFINED, /* 123 */ + TPM_UNDEFINED, /* 124 */ + TPM_UNDEFINED, /* 125 */ + TPM_UNDEFINED, /* 126 */ + TPM_UNDEFINED, /* 127 */ + TPM_UNDEFINED, /* 128 */ + TPM_LONG, /* 129 */ + TPM_UNDEFINED, /* 12a */ + TPM_UNDEFINED, /* 12b */ + TPM_UNDEFINED, /* 12c */ + TPM_UNDEFINED, /* 12d */ + TPM_UNDEFINED, /* 12e */ + TPM_UNDEFINED, /* 12f */ + TPM_UNDEFINED, /* 130 */ + TPM_UNDEFINED, /* 131 */ + TPM_UNDEFINED, /* 132 */ + TPM_UNDEFINED, /* 133 */ + TPM_UNDEFINED, /* 134 */ + TPM_UNDEFINED, /* 135 */ + TPM_UNDEFINED, /* 136 */ + TPM_UNDEFINED, /* 137 */ + TPM_UNDEFINED, /* 138 */ + TPM_UNDEFINED, /* 139 */ + TPM_UNDEFINED, /* 13a */ + TPM_UNDEFINED, /* 13b */ + TPM_UNDEFINED, /* 13c */ + TPM_UNDEFINED, /* 13d */ + TPM_MEDIUM, /* 13e */ + TPM_UNDEFINED, /* 13f */ + TPM_UNDEFINED, /* 140 */ + TPM_UNDEFINED, /* 141 */ + TPM_UNDEFINED, /* 142 */ + TPM_LONG, /* 143 */ + TPM_MEDIUM, /* 144 */ + TPM_UNDEFINED, /* 145 */ + TPM_UNDEFINED, /* 146 */ + TPM_UNDEFINED, /* 147 */ + TPM_UNDEFINED, /* 148 */ + TPM_UNDEFINED, /* 149 */ + TPM_UNDEFINED, /* 14a */ + TPM_UNDEFINED, /* 14b */ + TPM_UNDEFINED, /* 14c */ + TPM_UNDEFINED, /* 14d */ + TPM_LONG, /* 14e */ + TPM_UNDEFINED, /* 14f */ + TPM_UNDEFINED, /* 150 */ + TPM_UNDEFINED, /* 151 */ + TPM_UNDEFINED, /* 152 */ + TPM_UNDEFINED, /* 153 */ + TPM_UNDEFINED, /* 154 */ + TPM_UNDEFINED, /* 155 */ + TPM_UNDEFINED, /* 156 */ + TPM_UNDEFINED, /* 157 */ + TPM_UNDEFINED, /* 158 */ + TPM_UNDEFINED, /* 159 */ + TPM_UNDEFINED, /* 15a */ + TPM_UNDEFINED, /* 15b */ + TPM_MEDIUM, /* 15c */ + TPM_UNDEFINED, /* 15d */ + TPM_UNDEFINED, /* 15e */ + TPM_UNDEFINED, /* 15f */ + TPM_UNDEFINED, /* 160 */ + TPM_UNDEFINED, /* 161 */ + TPM_UNDEFINED, /* 162 */ + TPM_UNDEFINED, /* 163 */ + TPM_UNDEFINED, /* 164 */ + TPM_UNDEFINED, /* 165 */ + TPM_UNDEFINED, /* 166 */ + TPM_UNDEFINED, /* 167 */ + TPM_UNDEFINED, /* 168 */ + TPM_UNDEFINED, /* 169 */ + TPM_UNDEFINED, /* 16a */ + TPM_UNDEFINED, /* 16b */ + TPM_UNDEFINED, /* 16c */ + TPM_UNDEFINED, /* 16d */ + TPM_UNDEFINED, /* 16e */ + TPM_UNDEFINED, /* 16f */ + TPM_UNDEFINED, /* 170 */ + TPM_UNDEFINED, /* 171 */ + TPM_UNDEFINED, /* 172 */ + TPM_UNDEFINED, /* 173 */ + TPM_UNDEFINED, /* 174 */ + TPM_UNDEFINED, /* 175 */ + TPM_UNDEFINED, /* 176 */ + TPM_LONG, /* 177 */ + TPM_UNDEFINED, /* 178 */ + TPM_UNDEFINED, /* 179 */ + TPM_MEDIUM, /* 17a */ + TPM_LONG, /* 17b */ + TPM_UNDEFINED, /* 17c */ + TPM_UNDEFINED, /* 17d */ + TPM_UNDEFINED, /* 17e */ + TPM_UNDEFINED, /* 17f */ + TPM_UNDEFINED, /* 180 */ + TPM_UNDEFINED, /* 181 */ + TPM_MEDIUM, /* 182 */ + TPM_UNDEFINED, /* 183 */ + TPM_UNDEFINED, /* 184 */ + TPM_MEDIUM, /* 185 */ + TPM_MEDIUM, /* 186 */ + TPM_UNDEFINED, /* 187 */ + TPM_UNDEFINED, /* 188 */ + TPM_UNDEFINED, /* 189 */ + TPM_UNDEFINED, /* 18a */ + TPM_UNDEFINED, /* 18b */ + TPM_UNDEFINED, /* 18c */ + TPM_UNDEFINED, /* 18d */ + TPM_UNDEFINED, /* 18e */ + TPM_UNDEFINED /* 18f */ +}; + +#define TPM2_PCR_READ_IN_SIZE \ + (sizeof(struct tpm_input_header) + \ + sizeof(struct tpm2_pcr_read_in)) + +static const struct tpm_input_header tpm2_pcrread_header = { + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE), + .ordinal = cpu_to_be32(TPM2_CC_PCR_READ) +}; + +/** + * tpm2_pcr_read() - read a PCR value + * @chip: TPM chip to use. + * @pcr_idx: index of the PCR to read. + * @ref_buf: buffer to store the resulting hash, + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) +{ + int rc; + struct tpm2_cmd cmd; + u8 *buf; + + if (pcr_idx >= TPM2_PLATFORM_PCR) + return -EINVAL; + + cmd.header.in = tpm2_pcrread_header; + cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1); + cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); + cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN; + + memset(cmd.params.pcrread_in.pcr_select, 0, + sizeof(cmd.params.pcrread_in.pcr_select)); + cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7); + + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + "attempting to read a pcr value"); + if (rc == 0) { + buf = cmd.params.pcrread_out.digest; + memcpy(res_buf, buf, TPM_DIGEST_SIZE); + } + + return rc; +} + +#define TPM2_GET_PCREXTEND_IN_SIZE \ + (sizeof(struct tpm_input_header) + \ + sizeof(struct tpm2_pcr_extend_in)) + +static const struct tpm_input_header tpm2_pcrextend_header = { + .tag = cpu_to_be16(TPM2_ST_SESSIONS), + .length = cpu_to_be32(TPM2_GET_PCREXTEND_IN_SIZE), + .ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND) +}; + +/** + * tpm2_pcr_extend() - extend a PCR value + * @chip: TPM chip to use. + * @pcr_idx: index of the PCR. + * @hash: hash value to use for the extend operation. + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) +{ + struct tpm2_cmd cmd; + int rc; + + cmd.header.in = tpm2_pcrextend_header; + cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); + cmd.params.pcrextend_in.auth_area_size = + cpu_to_be32(sizeof(struct tpm2_null_auth_area)); + cmd.params.pcrextend_in.auth_area.handle = + cpu_to_be32(TPM2_RS_PW); + cmd.params.pcrextend_in.auth_area.nonce_size = 0; + cmd.params.pcrextend_in.auth_area.attributes = 0; + cmd.params.pcrextend_in.auth_area.auth_size = 0; + cmd.params.pcrextend_in.digest_cnt = cpu_to_be32(1); + cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); + memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE); + + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + "attempting extend a PCR value"); + + return rc; +} + +#define TPM2_GETRANDOM_IN_SIZE \ + (sizeof(struct tpm_input_header) + \ + sizeof(struct tpm2_get_random_in)) + +static const struct tpm_input_header tpm2_getrandom_header = { + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .length = cpu_to_be32(TPM2_GETRANDOM_IN_SIZE), + .ordinal = cpu_to_be32(TPM2_CC_GET_RANDOM) +}; + +/** + * tpm2_get_random() - get random bytes from the TPM RNG + * @chip: TPM chip to use + * @out: destination buffer for the random bytes + * @max: the max number of bytes to write to @out + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) +{ + struct tpm2_cmd cmd; + u32 recd; + u32 num_bytes; + int err; + int total = 0; + int retries = 5; + u8 *dest = out; + + num_bytes = min_t(u32, max, sizeof(cmd.params.getrandom_out.buffer)); + + if (!out || !num_bytes || + max > sizeof(cmd.params.getrandom_out.buffer)) + return -EINVAL; + + do { + cmd.header.in = tpm2_getrandom_header; + cmd.params.getrandom_in.size = cpu_to_be16(num_bytes); + + err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + "attempting get random"); + if (err) + break; + + recd = min_t(u32, be16_to_cpu(cmd.params.getrandom_out.size), + num_bytes); + memcpy(dest, cmd.params.getrandom_out.buffer, recd); + + dest += recd; + total += recd; + num_bytes -= recd; + } while (retries-- && total < max); + + return total ? total : -EIO; +} + +#define TPM2_GET_TPM_PT_IN_SIZE \ + (sizeof(struct tpm_input_header) + \ + sizeof(struct tpm2_get_tpm_pt_in)) + +static const struct tpm_input_header tpm2_get_tpm_pt_header = { + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .length = cpu_to_be32(TPM2_GET_TPM_PT_IN_SIZE), + .ordinal = cpu_to_be32(TPM2_CC_GET_CAPABILITY) +}; + +/** + * tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property + * @chip: TPM chip to use. + * @property_id: property ID. + * @value: output variable. + * @desc: passed to tpm_transmit_cmd() + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, + const char *desc) +{ + struct tpm2_cmd cmd; + int rc; + + cmd.header.in = tpm2_get_tpm_pt_header; + cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES); + cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id); + cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); + + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), desc); + if (!rc) + *value = cmd.params.get_tpm_pt_out.value; + + return rc; +} + +#define TPM2_STARTUP_IN_SIZE \ + (sizeof(struct tpm_input_header) + \ + sizeof(struct tpm2_startup_in)) + +static const struct tpm_input_header tpm2_startup_header = { + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .length = cpu_to_be32(TPM2_STARTUP_IN_SIZE), + .ordinal = cpu_to_be32(TPM2_CC_STARTUP) +}; + +/** + * tpm2_startup() - send startup command to the TPM chip + * @chip: TPM chip to use. + * @startup_type startup type. The value is either + * TPM_SU_CLEAR or TPM_SU_STATE. + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +int tpm2_startup(struct tpm_chip *chip, u16 startup_type) +{ + struct tpm2_cmd cmd; + + cmd.header.in = tpm2_startup_header; + + cmd.params.startup_in.startup_type = cpu_to_be16(startup_type); + return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + "attempting to start the TPM"); +} +EXPORT_SYMBOL_GPL(tpm2_startup); + +#define TPM2_SHUTDOWN_IN_SIZE \ + (sizeof(struct tpm_input_header) + \ + sizeof(struct tpm2_startup_in)) + +static const struct tpm_input_header tpm2_shutdown_header = { + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .length = cpu_to_be32(TPM2_SHUTDOWN_IN_SIZE), + .ordinal = cpu_to_be32(TPM2_CC_SHUTDOWN) +}; + +/** + * tpm2_shutdown() - send shutdown command to the TPM chip + * @chip: TPM chip to use. + * @shutdown_type shutdown type. The value is either + * TPM_SU_CLEAR or TPM_SU_STATE. + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) +{ + struct tpm2_cmd cmd; + + cmd.header.in = tpm2_shutdown_header; + + cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type); + return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + "stopping the TPM"); +} +EXPORT_SYMBOL_GPL(tpm2_shutdown); + +/* + * tpm2_calc_ordinal_duration() - maximum duration for a command + * @chip: TPM chip to use. + * @ordinal: command code number. + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) +{ + int index = TPM_UNDEFINED; + int duration = 0; + + if (ordinal >= TPM2_CC_FIRST && ordinal <= TPM2_CC_LAST) + index = tpm2_ordinal_duration[ordinal - TPM2_CC_FIRST]; + + if (index != TPM_UNDEFINED) + duration = chip->vendor.duration[index]; + + if (duration <= 0) + duration = 2 * 60 * HZ; + + return duration; +} +EXPORT_SYMBOL_GPL(tpm2_calc_ordinal_duration); + +#define TPM2_SELF_TEST_IN_SIZE \ + (sizeof(struct tpm_input_header) + \ + sizeof(struct tpm2_self_test_in)) + +static const struct tpm_input_header tpm2_selftest_header = { + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .length = cpu_to_be32(TPM2_SELF_TEST_IN_SIZE), + .ordinal = cpu_to_be32(TPM2_CC_SELF_TEST) +}; + +/** + * tpm2_continue_selftest() - start a self test + * @chip: TPM chip to use + * @full: test all commands instead of testing only those that were not + * previously tested. + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +static int tpm2_start_selftest(struct tpm_chip *chip, bool full) +{ + int rc; + struct tpm2_cmd cmd; + + cmd.header.in = tpm2_selftest_header; + cmd.params.selftest_in.full_test = full; + + rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, + "continue selftest"); + + /* At least some prototype chips seem to give RC_TESTING error + * immediately. This is a workaround for that. + */ + if (rc == TPM2_RC_TESTING) { + dev_warn(chip->pdev, "Got RC_TESTING, ignoring\n"); + rc = 0; + } + + return rc; +} + +/** + * tpm2_do_selftest() - run a full self test + * @chip: TPM chip to use + * + * During the self test TPM2 commands return with the error code RC_TESTING. + * Waiting is done by issuing PCR read until it executes successfully. + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +int tpm2_do_selftest(struct tpm_chip *chip) +{ + int rc; + unsigned int loops; + unsigned int delay_msec = 100; + unsigned long duration; + struct tpm2_cmd cmd; + int i; + + duration = tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST); + + loops = jiffies_to_msecs(duration) / delay_msec; + + rc = tpm2_start_selftest(chip, true); + if (rc) + return rc; + + for (i = 0; i < loops; i++) { + /* Attempt to read a PCR value */ + cmd.header.in = tpm2_pcrread_header; + cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1); + cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); + cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN; + cmd.params.pcrread_in.pcr_select[0] = 0x01; + cmd.params.pcrread_in.pcr_select[1] = 0x00; + cmd.params.pcrread_in.pcr_select[2] = 0x00; + + rc = tpm_transmit_cmd(chip, (u8 *) &cmd, sizeof(cmd), NULL); + if (rc < 0) + break; + + rc = be32_to_cpu(cmd.header.out.return_code); + if (rc != TPM2_RC_TESTING) + break; + + msleep(delay_msec); + } + + return rc; +} +EXPORT_SYMBOL_GPL(tpm2_do_selftest); + +/** + * tpm2_gen_interrupt() - generate an interrupt + * @chip: TPM chip to use + * @quiet: surpress the error message + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet) +{ + const char *desc = NULL; + u32 dummy; + + if (!quiet) + desc = "attempting to generate an interrupt"; + + return tpm2_get_tpm_pt(chip, TPM2_CAP_TPM_PROPERTIES, &dummy, desc); +} +EXPORT_SYMBOL_GPL(tpm2_gen_interrupt); diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index 435c8b9dd2f8..dfadad0916a1 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -49,7 +49,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) for (i = 0; i < 6; i++) { status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { - dev_err(chip->dev, "error reading header\n"); + dev_err(chip->pdev, "error reading header\n"); return -EIO; } *buf++ = ioread8(chip->vendor.iobase); @@ -60,12 +60,12 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) size = be32_to_cpu(*native_size); if (count < size) { - dev_err(chip->dev, + dev_err(chip->pdev, "Recv size(%d) less than available space\n", size); for (; i < size; i++) { /* clear the waiting data anyway */ status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { - dev_err(chip->dev, "error reading data\n"); + dev_err(chip->pdev, "error reading data\n"); return -EIO; } } @@ -76,7 +76,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) for (; i < size; i++) { status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { - dev_err(chip->dev, "error reading data\n"); + dev_err(chip->pdev, "error reading data\n"); return -EIO; } *buf++ = ioread8(chip->vendor.iobase); @@ -86,7 +86,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) status = ioread8(chip->vendor.iobase + 1); if (status & ATML_STATUS_DATA_AVAIL) { - dev_err(chip->dev, "data available is stuck\n"); + dev_err(chip->pdev, "data available is stuck\n"); return -EIO; } @@ -97,9 +97,9 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) { int i; - dev_dbg(chip->dev, "tpm_atml_send:\n"); + dev_dbg(chip->pdev, "tpm_atml_send:\n"); for (i = 0; i < count; i++) { - dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); + dev_dbg(chip->pdev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); iowrite8(buf[i], chip->vendor.iobase); } @@ -138,11 +138,11 @@ static void atml_plat_remove(void) struct tpm_chip *chip = dev_get_drvdata(&pdev->dev); if (chip) { + tpm_chip_unregister(chip); if (chip->vendor.have_region) atmel_release_region(chip->vendor.base, chip->vendor.region_size); atmel_put_base_addr(chip->vendor.iobase); - tpm_remove_hardware(chip->dev); platform_device_unregister(pdev); } } @@ -183,8 +183,9 @@ static int __init init_atmel(void) goto err_rel_reg; } - if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) { - rc = -ENODEV; + chip = tpmm_chip_alloc(&pdev->dev, &tpm_atmel); + if (IS_ERR(chip)) { + rc = PTR_ERR(chip); goto err_unreg_dev; } @@ -193,6 +194,10 @@ static int __init init_atmel(void) chip->vendor.have_region = have_region; chip->vendor.region_size = region_size; + rc = tpm_chip_register(chip); + if (rc) + goto err_unreg_dev; + return 0; err_unreg_dev: diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c new file mode 100644 index 000000000000..3dd23cfae4fe --- /dev/null +++ b/drivers/char/tpm/tpm_crb.c @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2014 Intel Corporation + * + * Authors: + * Jarkko Sakkinen + * + * Maintained by: + * + * This device driver implements the TPM interface as defined in + * the TCG CRB 2.0 TPM specification. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ + +#include +#include +#include +#include +#include +#include "tpm.h" + +#define ACPI_SIG_TPM2 "TPM2" + +static const u8 CRB_ACPI_START_UUID[] = { + /* 0000 */ 0xAB, 0x6C, 0xBF, 0x6B, 0x63, 0x54, 0x14, 0x47, + /* 0008 */ 0xB7, 0xCD, 0xF0, 0x20, 0x3C, 0x03, 0x68, 0xD4 +}; + +enum crb_defaults { + CRB_ACPI_START_REVISION_ID = 1, + CRB_ACPI_START_INDEX = 1, +}; + +enum crb_start_method { + CRB_SM_ACPI_START = 2, + CRB_SM_CRB = 7, + CRB_SM_CRB_WITH_ACPI_START = 8, +}; + +struct acpi_tpm2 { + struct acpi_table_header hdr; + u16 platform_class; + u16 reserved; + u64 control_area_pa; + u32 start_method; +} __packed; + +enum crb_ca_request { + CRB_CA_REQ_GO_IDLE = BIT(0), + CRB_CA_REQ_CMD_READY = BIT(1), +}; + +enum crb_ca_status { + CRB_CA_STS_ERROR = BIT(0), + CRB_CA_STS_TPM_IDLE = BIT(1), +}; + +enum crb_start { + CRB_START_INVOKE = BIT(0), +}; + +enum crb_cancel { + CRB_CANCEL_INVOKE = BIT(0), +}; + +struct crb_control_area { + u32 req; + u32 sts; + u32 cancel; + u32 start; + u32 int_enable; + u32 int_sts; + u32 cmd_size; + u64 cmd_pa; + u32 rsp_size; + u64 rsp_pa; +} __packed; + +enum crb_status { + CRB_STS_COMPLETE = BIT(0), +}; + +enum crb_flags { + CRB_FL_ACPI_START = BIT(0), + CRB_FL_CRB_START = BIT(1), +}; + +struct crb_priv { + unsigned int flags; + struct crb_control_area __iomem *cca; + u8 __iomem *cmd; + u8 __iomem *rsp; +}; + +#ifdef CONFIG_PM_SLEEP +static int crb_resume(struct device *dev) +{ + int rc; + struct tpm_chip *chip = dev_get_drvdata(dev); + + rc = tpm2_shutdown(chip, TPM2_SU_STATE); + if (!rc) + rc = tpm2_do_selftest(chip); + + return rc; +} +#endif + +static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, crb_resume); + +static u8 crb_status(struct tpm_chip *chip) +{ + struct crb_priv *priv = chip->vendor.priv; + u8 sts = 0; + + if ((le32_to_cpu(ioread32(&priv->cca->start)) & CRB_START_INVOKE) != + CRB_START_INVOKE) + sts |= CRB_STS_COMPLETE; + + return sts; +} + +static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) +{ + struct crb_priv *priv = chip->vendor.priv; + unsigned int expected; + + /* sanity check */ + if (count < 6) + return -EIO; + + if (le32_to_cpu(ioread32(&priv->cca->sts)) & CRB_CA_STS_ERROR) + return -EIO; + + memcpy_fromio(buf, priv->rsp, 6); + expected = be32_to_cpup((__be32 *) &buf[2]); + + if (expected > count) + return -EIO; + + memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6); + + return expected; +} + +static int crb_do_acpi_start(struct tpm_chip *chip) +{ + union acpi_object *obj; + int rc; + + obj = acpi_evaluate_dsm(chip->acpi_dev_handle, + CRB_ACPI_START_UUID, + CRB_ACPI_START_REVISION_ID, + CRB_ACPI_START_INDEX, + NULL); + if (!obj) + return -ENXIO; + rc = obj->integer.value == 0 ? 0 : -ENXIO; + ACPI_FREE(obj); + return rc; +} + +static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len) +{ + struct crb_priv *priv = chip->vendor.priv; + int rc = 0; + + if (len > le32_to_cpu(ioread32(&priv->cca->cmd_size))) { + dev_err(&chip->dev, + "invalid command count value %x %zx\n", + (unsigned int) len, + (size_t) le32_to_cpu(ioread32(&priv->cca->cmd_size))); + return -E2BIG; + } + + memcpy_toio(priv->cmd, buf, len); + + /* Make sure that cmd is populated before issuing start. */ + wmb(); + + if (priv->flags & CRB_FL_CRB_START) + iowrite32(cpu_to_le32(CRB_START_INVOKE), &priv->cca->start); + + if (priv->flags & CRB_FL_ACPI_START) + rc = crb_do_acpi_start(chip); + + return rc; +} + +static void crb_cancel(struct tpm_chip *chip) +{ + struct crb_priv *priv = chip->vendor.priv; + + iowrite32(cpu_to_le32(CRB_CANCEL_INVOKE), &priv->cca->cancel); + + /* Make sure that cmd is populated before issuing cancel. */ + wmb(); + + if ((priv->flags & CRB_FL_ACPI_START) && crb_do_acpi_start(chip)) + dev_err(&chip->dev, "ACPI Start failed\n"); + + iowrite32(0, &priv->cca->cancel); +} + +static bool crb_req_canceled(struct tpm_chip *chip, u8 status) +{ + struct crb_priv *priv = chip->vendor.priv; + u32 cancel = le32_to_cpu(ioread32(&priv->cca->cancel)); + + return (cancel & CRB_CANCEL_INVOKE) == CRB_CANCEL_INVOKE; +} + +static const struct tpm_class_ops tpm_crb = { + .status = crb_status, + .recv = crb_recv, + .send = crb_send, + .cancel = crb_cancel, + .req_canceled = crb_req_canceled, + .req_complete_mask = CRB_STS_COMPLETE, + .req_complete_val = CRB_STS_COMPLETE, +}; + +static int crb_acpi_add(struct acpi_device *device) +{ + struct tpm_chip *chip; + struct acpi_tpm2 *buf; + struct crb_priv *priv; + struct device *dev = &device->dev; + acpi_status status; + u32 sm; + u64 pa; + int rc; + + chip = tpmm_chip_alloc(dev, &tpm_crb); + if (IS_ERR(chip)) + return PTR_ERR(chip); + + chip->flags = TPM_CHIP_FLAG_TPM2; + + status = acpi_get_table(ACPI_SIG_TPM2, 1, + (struct acpi_table_header **) &buf); + if (ACPI_FAILURE(status)) { + dev_err(dev, "failed to get TPM2 ACPI table\n"); + return -ENODEV; + } + + if (buf->hdr.length < sizeof(struct acpi_tpm2)) { + dev_err(dev, "TPM2 ACPI table has wrong size"); + return -EINVAL; + } + + priv = (struct crb_priv *) devm_kzalloc(dev, sizeof(struct crb_priv), + GFP_KERNEL); + if (!priv) { + dev_err(dev, "failed to devm_kzalloc for private data\n"); + return -ENOMEM; + } + + sm = le32_to_cpu(buf->start_method); + + /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs + * report only ACPI start but in practice seems to require both + * ACPI start and CRB start. + */ + if (sm == CRB_SM_CRB || sm == CRB_SM_CRB_WITH_ACPI_START || + !strcmp(acpi_device_hid(device), "MSFT0101")) + priv->flags |= CRB_FL_CRB_START; + + if (sm == CRB_SM_ACPI_START || sm == CRB_SM_CRB_WITH_ACPI_START) + priv->flags |= CRB_FL_ACPI_START; + + priv->cca = (struct crb_control_area __iomem *) + devm_ioremap_nocache(dev, buf->control_area_pa, 0x1000); + if (!priv->cca) { + dev_err(dev, "ioremap of the control area failed\n"); + return -ENOMEM; + } + + memcpy_fromio(&pa, &priv->cca->cmd_pa, 8); + pa = le64_to_cpu(pa); + priv->cmd = devm_ioremap_nocache(dev, le64_to_cpu(pa), + ioread32(&priv->cca->cmd_size)); + if (!priv->cmd) { + dev_err(dev, "ioremap of the command buffer failed\n"); + return -ENOMEM; + } + + memcpy_fromio(&pa, &priv->cca->rsp_pa, 8); + pa = le64_to_cpu(pa); + priv->rsp = devm_ioremap_nocache(dev, le64_to_cpu(pa), + ioread32(&priv->cca->rsp_size)); + if (!priv->rsp) { + dev_err(dev, "ioremap of the response buffer failed\n"); + return -ENOMEM; + } + + chip->vendor.priv = priv; + + /* Default timeouts and durations */ + chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A); + chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B); + chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C); + chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D); + chip->vendor.duration[TPM_SHORT] = + msecs_to_jiffies(TPM2_DURATION_SHORT); + chip->vendor.duration[TPM_MEDIUM] = + msecs_to_jiffies(TPM2_DURATION_MEDIUM); + chip->vendor.duration[TPM_LONG] = + msecs_to_jiffies(TPM2_DURATION_LONG); + + chip->acpi_dev_handle = device->handle; + + rc = tpm2_do_selftest(chip); + if (rc) + return rc; + + return tpm_chip_register(chip); +} + +static int crb_acpi_remove(struct acpi_device *device) +{ + struct device *dev = &device->dev; + struct tpm_chip *chip = dev_get_drvdata(dev); + + tpm_chip_unregister(chip); + return 0; +} + +static struct acpi_device_id crb_device_ids[] = { + {"MSFT0101", 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, crb_device_ids); + +static struct acpi_driver crb_acpi_driver = { + .name = "tpm_crb", + .ids = crb_device_ids, + .ops = { + .add = crb_acpi_add, + .remove = crb_acpi_remove, + }, + .drv = { + .pm = &crb_pm, + }, +}; + +module_acpi_driver(crb_acpi_driver); +MODULE_AUTHOR("Jarkko Sakkinen "); +MODULE_DESCRIPTION("TPM2 Driver"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c index 77272925dee6..7a0ca78ad3c6 100644 --- a/drivers/char/tpm/tpm_i2c_atmel.c +++ b/drivers/char/tpm/tpm_i2c_atmel.c @@ -52,7 +52,7 @@ struct priv_data { static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) { struct priv_data *priv = chip->vendor.priv; - struct i2c_client *client = to_i2c_client(chip->dev); + struct i2c_client *client = to_i2c_client(chip->pdev); s32 status; priv->len = 0; @@ -62,7 +62,7 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) status = i2c_master_send(client, buf, len); - dev_dbg(chip->dev, + dev_dbg(chip->pdev, "%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__, (int)min_t(size_t, 64, len), buf, len, status); return status; @@ -71,7 +71,7 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) { struct priv_data *priv = chip->vendor.priv; - struct i2c_client *client = to_i2c_client(chip->dev); + struct i2c_client *client = to_i2c_client(chip->pdev); struct tpm_output_header *hdr = (struct tpm_output_header *)priv->buffer; u32 expected_len; @@ -88,7 +88,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) return -ENOMEM; if (priv->len >= expected_len) { - dev_dbg(chip->dev, + dev_dbg(chip->pdev, "%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__, (int)min_t(size_t, 64, expected_len), buf, count, expected_len); @@ -97,7 +97,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) } rc = i2c_master_recv(client, buf, expected_len); - dev_dbg(chip->dev, + dev_dbg(chip->pdev, "%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__, (int)min_t(size_t, 64, expected_len), buf, count, expected_len); @@ -106,13 +106,13 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) static void i2c_atmel_cancel(struct tpm_chip *chip) { - dev_err(chip->dev, "TPM operation cancellation was requested, but is not supported"); + dev_err(chip->pdev, "TPM operation cancellation was requested, but is not supported"); } static u8 i2c_atmel_read_status(struct tpm_chip *chip) { struct priv_data *priv = chip->vendor.priv; - struct i2c_client *client = to_i2c_client(chip->dev); + struct i2c_client *client = to_i2c_client(chip->pdev); int rc; /* The TPM fails the I2C read until it is ready, so we do the entire @@ -125,7 +125,7 @@ static u8 i2c_atmel_read_status(struct tpm_chip *chip) /* Once the TPM has completed the command the command remains readable * until another command is issued. */ rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer)); - dev_dbg(chip->dev, + dev_dbg(chip->pdev, "%s: sts=%d", __func__, rc); if (rc <= 0) return 0; @@ -153,21 +153,20 @@ static const struct tpm_class_ops i2c_atmel = { static int i2c_atmel_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int rc; struct tpm_chip *chip; struct device *dev = &client->dev; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; - chip = tpm_register_hardware(dev, &i2c_atmel); - if (!chip) { - dev_err(dev, "%s() error in tpm_register_hardware\n", __func__); - return -ENODEV; - } + chip = tpmm_chip_alloc(dev, &i2c_atmel); + if (IS_ERR(chip)) + return PTR_ERR(chip); chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL); + if (!chip->vendor.priv) + return -ENOMEM; /* Default timeouts */ chip->vendor.timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); @@ -179,33 +178,20 @@ static int i2c_atmel_probe(struct i2c_client *client, /* There is no known way to probe for this device, and all version * information seems to be read via TPM commands. Thus we rely on the * TPM startup process in the common code to detect the device. */ - if (tpm_get_timeouts(chip)) { - rc = -ENODEV; - goto out_err; - } + if (tpm_get_timeouts(chip)) + return -ENODEV; - if (tpm_do_selftest(chip)) { - rc = -ENODEV; - goto out_err; - } + if (tpm_do_selftest(chip)) + return -ENODEV; - return 0; - -out_err: - tpm_dev_vendor_release(chip); - tpm_remove_hardware(chip->dev); - return rc; + return tpm_chip_register(chip); } static int i2c_atmel_remove(struct i2c_client *client) { struct device *dev = &(client->dev); struct tpm_chip *chip = dev_get_drvdata(dev); - - if (chip) - tpm_dev_vendor_release(chip); - tpm_remove_hardware(dev); - kfree(chip); + tpm_chip_unregister(chip); return 0; } diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index 472af4bb1b61..33c5f360ab01 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -446,7 +446,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) /* read first 10 bytes, including tag, paramsize, and result */ size = recv_data(chip, buf, TPM_HEADER_SIZE); if (size < TPM_HEADER_SIZE) { - dev_err(chip->dev, "Unable to read header\n"); + dev_err(chip->pdev, "Unable to read header\n"); goto out; } @@ -459,14 +459,14 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) size += recv_data(chip, &buf[TPM_HEADER_SIZE], expected - TPM_HEADER_SIZE); if (size < expected) { - dev_err(chip->dev, "Unable to read remainder of result\n"); + dev_err(chip->pdev, "Unable to read remainder of result\n"); size = -ETIME; goto out; } wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); if (status & TPM_STS_DATA_AVAIL) { /* retry? */ - dev_err(chip->dev, "Error left over data\n"); + dev_err(chip->pdev, "Error left over data\n"); size = -EIO; goto out; } @@ -581,12 +581,9 @@ static int tpm_tis_i2c_init(struct device *dev) int rc = 0; struct tpm_chip *chip; - chip = tpm_register_hardware(dev, &tpm_tis_i2c); - if (!chip) { - dev_err(dev, "could not register hardware\n"); - rc = -ENODEV; - goto out_err; - } + chip = tpmm_chip_alloc(dev, &tpm_tis_i2c); + if (IS_ERR(chip)) + return PTR_ERR(chip); /* Disable interrupts */ chip->vendor.irq = 0; @@ -600,7 +597,7 @@ static int tpm_tis_i2c_init(struct device *dev) if (request_locality(chip, 0) != 0) { dev_err(dev, "could not request locality\n"); rc = -ENODEV; - goto out_vendor; + goto out_err; } /* read four bytes from DID_VID register */ @@ -628,21 +625,9 @@ static int tpm_tis_i2c_init(struct device *dev) tpm_get_timeouts(chip); tpm_do_selftest(chip); - return 0; - + return tpm_chip_register(chip); out_release: release_locality(chip, chip->vendor.locality, 1); - -out_vendor: - /* close file handles */ - tpm_dev_vendor_release(chip); - - /* remove hardware */ - tpm_remove_hardware(chip->dev); - - /* reset these pointers, otherwise we oops */ - chip->dev->release = NULL; - chip->release = NULL; tpm_dev.client = NULL; out_err: return rc; @@ -712,17 +697,9 @@ static int tpm_tis_i2c_probe(struct i2c_client *client, static int tpm_tis_i2c_remove(struct i2c_client *client) { struct tpm_chip *chip = tpm_dev.chip; + + tpm_chip_unregister(chip); release_locality(chip, chip->vendor.locality, 1); - - /* close file handles */ - tpm_dev_vendor_release(chip); - - /* remove hardware */ - tpm_remove_hardware(chip->dev); - - /* reset these pointers, otherwise we oops */ - chip->dev->release = NULL; - chip->release = NULL; tpm_dev.client = NULL; return 0; diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index 7b158efd49f7..9d42b7d78e50 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -96,13 +96,13 @@ static s32 i2c_nuvoton_write_buf(struct i2c_client *client, u8 offset, u8 size, /* read TPM_STS register */ static u8 i2c_nuvoton_read_status(struct tpm_chip *chip) { - struct i2c_client *client = to_i2c_client(chip->dev); + struct i2c_client *client = to_i2c_client(chip->pdev); s32 status; u8 data; status = i2c_nuvoton_read_buf(client, TPM_STS, 1, &data); if (status <= 0) { - dev_err(chip->dev, "%s() error return %d\n", __func__, + dev_err(chip->pdev, "%s() error return %d\n", __func__, status); data = TPM_STS_ERR_VAL; } @@ -127,13 +127,13 @@ static s32 i2c_nuvoton_write_status(struct i2c_client *client, u8 data) /* write commandReady to TPM_STS register */ static void i2c_nuvoton_ready(struct tpm_chip *chip) { - struct i2c_client *client = to_i2c_client(chip->dev); + struct i2c_client *client = to_i2c_client(chip->pdev); s32 status; /* this causes the current command to be aborted */ status = i2c_nuvoton_write_status(client, TPM_STS_COMMAND_READY); if (status < 0) - dev_err(chip->dev, + dev_err(chip->pdev, "%s() fail to write TPM_STS.commandReady\n", __func__); } @@ -212,7 +212,7 @@ static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value, return 0; } while (time_before(jiffies, stop)); } - dev_err(chip->dev, "%s(%02x, %02x) -> timeout\n", __func__, mask, + dev_err(chip->pdev, "%s(%02x, %02x) -> timeout\n", __func__, mask, value); return -ETIMEDOUT; } @@ -240,7 +240,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client, &chip->vendor.read_queue) == 0) { burst_count = i2c_nuvoton_get_burstcount(client, chip); if (burst_count < 0) { - dev_err(chip->dev, + dev_err(chip->pdev, "%s() fail to read burstCount=%d\n", __func__, burst_count); return -EIO; @@ -249,12 +249,12 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client, rc = i2c_nuvoton_read_buf(client, TPM_DATA_FIFO_R, bytes2read, &buf[size]); if (rc < 0) { - dev_err(chip->dev, + dev_err(chip->pdev, "%s() fail on i2c_nuvoton_read_buf()=%d\n", __func__, rc); return -EIO; } - dev_dbg(chip->dev, "%s(%d):", __func__, bytes2read); + dev_dbg(chip->pdev, "%s(%d):", __func__, bytes2read); size += bytes2read; } @@ -264,7 +264,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client, /* Read TPM command results */ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) { - struct device *dev = chip->dev; + struct device *dev = chip->pdev; struct i2c_client *client = to_i2c_client(dev); s32 rc; int expected, status, burst_count, retries, size = 0; @@ -334,7 +334,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) break; } i2c_nuvoton_ready(chip); - dev_dbg(chip->dev, "%s() -> %d\n", __func__, size); + dev_dbg(chip->pdev, "%s() -> %d\n", __func__, size); return size; } @@ -347,7 +347,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) */ static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len) { - struct device *dev = chip->dev; + struct device *dev = chip->pdev; struct i2c_client *client = to_i2c_client(dev); u32 ordinal; size_t count = 0; @@ -530,14 +530,15 @@ static int i2c_nuvoton_probe(struct i2c_client *client, dev_info(dev, "VID: %04X DID: %02X RID: %02X\n", (u16) vid, (u8) (vid >> 16), (u8) (vid >> 24)); - chip = tpm_register_hardware(dev, &tpm_i2c); - if (!chip) { - dev_err(dev, "%s() error in tpm_register_hardware\n", __func__); - return -ENODEV; - } + chip = tpmm_chip_alloc(dev, &tpm_i2c); + if (IS_ERR(chip)) + return PTR_ERR(chip); chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL); + if (!chip->vendor.priv) + return -ENOMEM; + init_waitqueue_head(&chip->vendor.read_queue); init_waitqueue_head(&chip->vendor.int_queue); @@ -559,7 +560,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client, rc = devm_request_irq(dev, chip->vendor.irq, i2c_nuvoton_int_handler, IRQF_TRIGGER_LOW, - chip->vendor.miscdev.name, + chip->devname, chip); if (rc) { dev_err(dev, "%s() Unable to request irq: %d for use\n", @@ -584,7 +585,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client, TPM_DATA_FIFO_W, 1, (u8 *) (&rc)); if (rc < 0) - goto out_err; + return rc; /* TPM_STS <- 0x40 (commandReady) */ i2c_nuvoton_ready(chip); } else { @@ -594,45 +595,29 @@ static int i2c_nuvoton_probe(struct i2c_client *client, * only TPM_STS_VALID should be set */ if (i2c_nuvoton_read_status(chip) != - TPM_STS_VALID) { - rc = -EIO; - goto out_err; - } + TPM_STS_VALID) + return -EIO; } } } - if (tpm_get_timeouts(chip)) { - rc = -ENODEV; - goto out_err; - } + if (tpm_get_timeouts(chip)) + return -ENODEV; - if (tpm_do_selftest(chip)) { - rc = -ENODEV; - goto out_err; - } + if (tpm_do_selftest(chip)) + return -ENODEV; - return 0; - -out_err: - tpm_dev_vendor_release(chip); - tpm_remove_hardware(chip->dev); - return rc; + return tpm_chip_register(chip); } static int i2c_nuvoton_remove(struct i2c_client *client) { struct device *dev = &(client->dev); struct tpm_chip *chip = dev_get_drvdata(dev); - - if (chip) - tpm_dev_vendor_release(chip); - tpm_remove_hardware(dev); - kfree(chip); + tpm_chip_unregister(chip); return 0; } - static const struct i2c_device_id i2c_nuvoton_id[] = { {I2C_DRIVER_NAME, 0}, {} diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 4669e3713428..612845b36c29 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -1,6 +1,6 @@ /* * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24 - * Copyright (C) 2009, 2010 STMicroelectronics + * Copyright (C) 2009, 2010, 2014 STMicroelectronics * * 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 @@ -12,11 +12,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU 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. + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . * - * STMicroelectronics version 1.2.0, Copyright (C) 2010 + * STMicroelectronics version 1.2.1, Copyright (C) 2014 * STMicroelectronics comes with ABSOLUTELY NO WARRANTY. * This is free software, and you are welcome to redistribute it * under certain conditions. @@ -27,7 +26,7 @@ * * @Synopsis: * 09/15/2010: First shot driver tpm_tis driver for - lpc is used as model. + * lpc is used as model. */ #include @@ -39,18 +38,38 @@ #include #include #include +#include #include #include -#include #include #include #include #include #include #include +#include +#include +#include #include "tpm.h" -#include "tpm_i2c_stm_st33.h" + +#define TPM_ACCESS 0x0 +#define TPM_STS 0x18 +#define TPM_HASH_END 0x20 +#define TPM_DATA_FIFO 0x24 +#define TPM_HASH_DATA 0x24 +#define TPM_HASH_START 0x28 +#define TPM_INTF_CAPABILITY 0x14 +#define TPM_INT_STATUS 0x10 +#define TPM_INT_ENABLE 0x08 + +#define TPM_DUMMY_BYTE 0xAA +#define TPM_WRITE_DIRECTION 0x80 +#define TPM_HEADER_SIZE 10 +#define TPM_BUFSIZE 2048 + +#define LOCALITY0 0 + enum stm33zp24_access { TPM_ACCESS_VALID = 0x80, @@ -82,6 +101,14 @@ enum tis_defaults { TIS_LONG_TIMEOUT = 2000, }; +struct tpm_stm_dev { + struct i2c_client *client; + struct tpm_chip *chip; + u8 buf[TPM_BUFSIZE + 1]; + u32 intrs; + int io_lpcpd; +}; + /* * write8_reg * Send byte to the TIS register according to the ST33ZP24 I2C protocol. @@ -90,17 +117,12 @@ enum tis_defaults { * @param: tpm_size, The length of the data * @return: Returns negative errno, or else the number of bytes written. */ -static int write8_reg(struct i2c_client *client, u8 tpm_register, +static int write8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register, u8 *tpm_data, u16 tpm_size) { - struct st33zp24_platform_data *pin_infos; - - pin_infos = client->dev.platform_data; - - pin_infos->tpm_i2c_buffer[0][0] = tpm_register; - memcpy(&pin_infos->tpm_i2c_buffer[0][1], tpm_data, tpm_size); - return i2c_master_send(client, pin_infos->tpm_i2c_buffer[0], - tpm_size + 1); + tpm_dev->buf[0] = tpm_register; + memcpy(tpm_dev->buf + 1, tpm_data, tpm_size); + return i2c_master_send(tpm_dev->client, tpm_dev->buf, tpm_size + 1); } /* write8_reg() */ /* @@ -111,118 +133,73 @@ static int write8_reg(struct i2c_client *client, u8 tpm_register, * @param: tpm_size, tpm TPM response size to read. * @return: number of byte read successfully: should be one if success. */ -static int read8_reg(struct i2c_client *client, u8 tpm_register, +static int read8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register, u8 *tpm_data, int tpm_size) { u8 status = 0; u8 data; data = TPM_DUMMY_BYTE; - status = write8_reg(client, tpm_register, &data, 1); + status = write8_reg(tpm_dev, tpm_register, &data, 1); if (status == 2) - status = i2c_master_recv(client, tpm_data, tpm_size); + status = i2c_master_recv(tpm_dev->client, tpm_data, tpm_size); return status; } /* read8_reg() */ /* * I2C_WRITE_DATA * Send byte to the TIS register according to the ST33ZP24 I2C protocol. - * @param: client, the chip description + * @param: tpm_dev, the chip description * @param: tpm_register, the tpm tis register where the data should be written * @param: tpm_data, the tpm_data to write inside the tpm_register * @param: tpm_size, The length of the data * @return: number of byte written successfully: should be one if success. */ -#define I2C_WRITE_DATA(client, tpm_register, tpm_data, tpm_size) \ - (write8_reg(client, tpm_register | \ +#define I2C_WRITE_DATA(tpm_dev, tpm_register, tpm_data, tpm_size) \ + (write8_reg(tpm_dev, tpm_register | \ TPM_WRITE_DIRECTION, tpm_data, tpm_size)) /* * I2C_READ_DATA * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. - * @param: tpm, the chip description + * @param: tpm_dev, the chip description * @param: tpm_register, the tpm tis register where the data should be read * @param: tpm_data, the TPM response * @param: tpm_size, tpm TPM response size to read. * @return: number of byte read successfully: should be one if success. */ -#define I2C_READ_DATA(client, tpm_register, tpm_data, tpm_size) \ - (read8_reg(client, tpm_register, tpm_data, tpm_size)) +#define I2C_READ_DATA(tpm_dev, tpm_register, tpm_data, tpm_size) \ + (read8_reg(tpm_dev, tpm_register, tpm_data, tpm_size)) /* * clear_interruption * clear the TPM interrupt register. * @param: tpm, the chip description + * @return: the TPM_INT_STATUS value */ -static void clear_interruption(struct i2c_client *client) +static u8 clear_interruption(struct tpm_stm_dev *tpm_dev) { u8 interrupt; - I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1); - I2C_WRITE_DATA(client, TPM_INT_STATUS, &interrupt, 1); - I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1); + + I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); + I2C_WRITE_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); + return interrupt; } /* clear_interruption() */ -/* - * _wait_for_interrupt_serirq_timeout - * @param: tpm, the chip description - * @param: timeout, the timeout of the interrupt - * @return: the status of the interruption. - */ -static long _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip, - unsigned long timeout) -{ - long status; - struct i2c_client *client; - struct st33zp24_platform_data *pin_infos; - - client = (struct i2c_client *)TPM_VPRIV(chip); - pin_infos = client->dev.platform_data; - - status = wait_for_completion_interruptible_timeout( - &pin_infos->irq_detection, - timeout); - if (status > 0) - enable_irq(gpio_to_irq(pin_infos->io_serirq)); - gpio_direction_input(pin_infos->io_serirq); - - return status; -} /* wait_for_interrupt_serirq_timeout() */ - -static int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition, - unsigned long timeout) -{ - int status = 2; - struct i2c_client *client; - - client = (struct i2c_client *)TPM_VPRIV(chip); - - status = _wait_for_interrupt_serirq_timeout(chip, timeout); - if (!status) { - status = -EBUSY; - } else { - clear_interruption(client); - if (condition) - status = 1; - } - return status; -} - /* * tpm_stm_i2c_cancel, cancel is not implemented. * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h */ static void tpm_stm_i2c_cancel(struct tpm_chip *chip) { - struct i2c_client *client; + struct tpm_stm_dev *tpm_dev; u8 data; - client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); data = TPM_STS_COMMAND_READY; - I2C_WRITE_DATA(client, TPM_STS, &data, 1); - if (chip->vendor.irq) - wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a); -} /* tpm_stm_i2c_cancel() */ + I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1); +} /* tpm_stm_i2c_cancel() */ /* * tpm_stm_spi_status return the TPM_STS register @@ -231,13 +208,14 @@ static void tpm_stm_i2c_cancel(struct tpm_chip *chip) */ static u8 tpm_stm_i2c_status(struct tpm_chip *chip) { - struct i2c_client *client; + struct tpm_stm_dev *tpm_dev; u8 data; - client = (struct i2c_client *)TPM_VPRIV(chip); - I2C_READ_DATA(client, TPM_STS, &data, 1); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + + I2C_READ_DATA(tpm_dev, TPM_STS, &data, 1); return data; -} /* tpm_stm_i2c_status() */ +} /* tpm_stm_i2c_status() */ /* @@ -247,20 +225,19 @@ static u8 tpm_stm_i2c_status(struct tpm_chip *chip) */ static int check_locality(struct tpm_chip *chip) { - struct i2c_client *client; + struct tpm_stm_dev *tpm_dev; u8 data; u8 status; - client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - status = I2C_READ_DATA(client, TPM_ACCESS, &data, 1); + status = I2C_READ_DATA(tpm_dev, TPM_ACCESS, &data, 1); if (status && (data & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) return chip->vendor.locality; return -EACCES; - } /* check_locality() */ /* @@ -271,37 +248,31 @@ static int check_locality(struct tpm_chip *chip) static int request_locality(struct tpm_chip *chip) { unsigned long stop; - long rc; - struct i2c_client *client; + long ret; + struct tpm_stm_dev *tpm_dev; u8 data; - client = (struct i2c_client *)TPM_VPRIV(chip); - if (check_locality(chip) == chip->vendor.locality) return chip->vendor.locality; + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + data = TPM_ACCESS_REQUEST_USE; - rc = I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1); - if (rc < 0) + ret = I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); + if (ret < 0) goto end; - if (chip->vendor.irq) { - rc = wait_for_serirq_timeout(chip, (check_locality - (chip) >= 0), - chip->vendor.timeout_a); - if (rc > 0) + stop = jiffies + chip->vendor.timeout_a; + + /* Request locality is usually effective after the request */ + do { + if (check_locality(chip) >= 0) return chip->vendor.locality; - } else { - stop = jiffies + chip->vendor.timeout_a; - do { - if (check_locality(chip) >= 0) - return chip->vendor.locality; - msleep(TPM_TIMEOUT); - } while (time_before(jiffies, stop)); - } - rc = -EACCES; + msleep(TPM_TIMEOUT); + } while (time_before(jiffies, stop)); + ret = -EACCES; end: - return rc; + return ret; } /* request_locality() */ /* @@ -310,13 +281,13 @@ end: */ static void release_locality(struct tpm_chip *chip) { - struct i2c_client *client; + struct tpm_stm_dev *tpm_dev; u8 data; - client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); data = TPM_ACCESS_ACTIVE_LOCALITY; - I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1); + I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); } /* @@ -329,19 +300,20 @@ static int get_burstcount(struct tpm_chip *chip) unsigned long stop; int burstcnt, status; u8 tpm_reg, temp; + struct tpm_stm_dev *tpm_dev; - struct i2c_client *client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); stop = jiffies + chip->vendor.timeout_d; do { tpm_reg = TPM_STS + 1; - status = I2C_READ_DATA(client, tpm_reg, &temp, 1); + status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1); if (status < 0) goto end; tpm_reg = tpm_reg + 1; burstcnt = temp; - status = I2C_READ_DATA(client, tpm_reg, &temp, 1); + status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1); if (status < 0) goto end; @@ -355,36 +327,107 @@ end: return -EBUSY; } /* get_burstcount() */ +static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, + bool check_cancel, bool *canceled) +{ + u8 status = chip->ops->status(chip); + + *canceled = false; + if ((status & mask) == mask) + return true; + if (check_cancel && chip->ops->req_canceled(chip, status)) { + *canceled = true; + return true; + } + return false; +} + +/* + * interrupt_to_status + * @param: irq_mask, the irq mask value to wait + * @return: the corresponding tpm_sts value + */ +static u8 interrupt_to_status(u8 irq_mask) +{ + u8 status = 0; + + if ((irq_mask & TPM_INTF_STS_VALID_INT) == TPM_INTF_STS_VALID_INT) + status |= TPM_STS_VALID; + if ((irq_mask & TPM_INTF_DATA_AVAIL_INT) == TPM_INTF_DATA_AVAIL_INT) + status |= TPM_STS_DATA_AVAIL; + if ((irq_mask & TPM_INTF_CMD_READY_INT) == TPM_INTF_CMD_READY_INT) + status |= TPM_STS_COMMAND_READY; + + return status; +} /* status_to_interrupt() */ + /* * wait_for_stat wait for a TPM_STS value * @param: chip, the tpm chip description * @param: mask, the value mask to wait * @param: timeout, the timeout * @param: queue, the wait queue. + * @param: check_cancel, does the command can be cancelled ? * @return: the tpm status, 0 if success, -ETIME if timeout is reached. */ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, - wait_queue_head_t *queue) + wait_queue_head_t *queue, bool check_cancel) { unsigned long stop; - long rc; - u8 status; + int ret; + bool canceled = false; + bool condition; + u32 cur_intrs; + u8 interrupt, status; + struct tpm_stm_dev *tpm_dev; - if (chip->vendor.irq) { - rc = wait_for_serirq_timeout(chip, ((tpm_stm_i2c_status - (chip) & mask) == - mask), timeout); - if (rc > 0) + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + + /* check current status */ + status = tpm_stm_i2c_status(chip); + if ((status & mask) == mask) + return 0; + + stop = jiffies + timeout; + + if (chip->vendor.irq) { + cur_intrs = tpm_dev->intrs; + interrupt = clear_interruption(tpm_dev); + enable_irq(chip->vendor.irq); + +again: + timeout = stop - jiffies; + if ((long) timeout <= 0) + return -1; + + ret = wait_event_interruptible_timeout(*queue, + cur_intrs != tpm_dev->intrs, timeout); + + interrupt |= clear_interruption(tpm_dev); + status = interrupt_to_status(interrupt); + condition = wait_for_tpm_stat_cond(chip, mask, + check_cancel, &canceled); + + if (ret >= 0 && condition) { + if (canceled) + return -ECANCELED; return 0; + } + if (ret == -ERESTARTSYS && freezing(current)) { + clear_thread_flag(TIF_SIGPENDING); + goto again; + } + disable_irq_nosync(chip->vendor.irq); + } else { - stop = jiffies + timeout; do { msleep(TPM_TIMEOUT); - status = tpm_stm_i2c_status(chip); + status = chip->ops->status(chip); if ((status & mask) == mask) return 0; } while (time_before(jiffies, stop)); } + return -ETIME; } /* wait_for_stat() */ @@ -397,22 +440,24 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, */ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) { - int size = 0, burstcnt, len; - struct i2c_client *client; + int size = 0, burstcnt, len, ret; + struct tpm_stm_dev *tpm_dev; - client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); while (size < count && wait_for_stat(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, chip->vendor.timeout_c, - &chip->vendor.read_queue) - == 0) { + &chip->vendor.read_queue, true) == 0) { burstcnt = get_burstcount(chip); if (burstcnt < 0) return burstcnt; len = min_t(int, burstcnt, count - size); - I2C_READ_DATA(client, TPM_DATA_FIFO, buf + size, len); + ret = I2C_READ_DATA(tpm_dev, TPM_DATA_FIFO, buf + size, len); + if (ret < 0) + return ret; + size += len; } return size; @@ -427,15 +472,14 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) { struct tpm_chip *chip = dev_id; - struct i2c_client *client; - struct st33zp24_platform_data *pin_infos; + struct tpm_stm_dev *tpm_dev; - disable_irq_nosync(irq); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - client = (struct i2c_client *)TPM_VPRIV(chip); - pin_infos = client->dev.platform_data; + tpm_dev->intrs++; + wake_up_interruptible(&chip->vendor.read_queue); + disable_irq_nosync(chip->vendor.irq); - complete(&pin_infos->irq_detection); return IRQ_HANDLED; } /* tpm_ioserirq_handler() */ @@ -457,13 +501,15 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, int ret; u8 data; struct i2c_client *client; + struct tpm_stm_dev *tpm_dev; - if (chip == NULL) + if (!chip) return -EBUSY; if (len < TPM_HEADER_SIZE) return -EBUSY; - client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + client = tpm_dev->client; client->flags = 0; @@ -476,7 +522,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, tpm_stm_i2c_cancel(chip); if (wait_for_stat (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, - &chip->vendor.int_queue) < 0) { + &chip->vendor.read_queue, false) < 0) { ret = -ETIME; goto out_err; } @@ -487,7 +533,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, if (burstcnt < 0) return burstcnt; size = min_t(int, len - i - 1, burstcnt); - ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size); + ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + i, size); if (ret < 0) goto out_err; @@ -500,7 +546,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, goto out_err; } - ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf + len - 1, 1); + ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + len - 1, 1); if (ret < 0) goto out_err; @@ -511,7 +557,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, } data = TPM_STS_GO; - I2C_WRITE_DATA(client, TPM_STS, &data, 1); + I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1); return len; out_err: @@ -526,7 +572,7 @@ out_err: * @param: buf, the buffer to store datas. * @param: count, the number of bytes to send. * @return: In case of success the number of bytes received. - * In other case, a < 0 value describing the issue. + * In other case, a < 0 value describing the issue. */ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, size_t count) @@ -534,7 +580,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, int size = 0; int expected; - if (chip == NULL) + if (!chip) return -EBUSY; if (count < TPM_HEADER_SIZE) { @@ -544,7 +590,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, size = recv_data(chip, buf, TPM_HEADER_SIZE); if (size < TPM_HEADER_SIZE) { - dev_err(chip->dev, "Unable to read header\n"); + dev_err(chip->pdev, "Unable to read header\n"); goto out; } @@ -555,9 +601,9 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, } size += recv_data(chip, &buf[TPM_HEADER_SIZE], - expected - TPM_HEADER_SIZE); + expected - TPM_HEADER_SIZE); if (size < expected) { - dev_err(chip->dev, "Unable to read remainder of result\n"); + dev_err(chip->pdev, "Unable to read remainder of result\n"); size = -ETIME; goto out; } @@ -568,7 +614,7 @@ out: return size; } -static bool tpm_st33_i2c_req_canceled(struct tpm_chip *chip, u8 status) +static bool tpm_stm_i2c_req_canceled(struct tpm_chip *chip, u8 status) { return (status == TPM_STS_COMMAND_READY); } @@ -580,75 +626,134 @@ static const struct tpm_class_ops st_i2c_tpm = { .status = tpm_stm_i2c_status, .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, - .req_canceled = tpm_st33_i2c_req_canceled, + .req_canceled = tpm_stm_i2c_req_canceled, }; -static int interrupts; -module_param(interrupts, int, 0444); -MODULE_PARM_DESC(interrupts, "Enable interrupts"); +#ifdef CONFIG_OF +static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip) +{ + struct device_node *pp; + struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + struct i2c_client *client = tpm_dev->client; + int gpio; + int ret; -static int power_mgt = 1; -module_param(power_mgt, int, 0444); -MODULE_PARM_DESC(power_mgt, "Power Management"); + pp = client->dev.of_node; + if (!pp) { + dev_err(chip->pdev, "No platform data\n"); + return -ENODEV; + } + + /* Get GPIO from device tree */ + gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0); + if (gpio < 0) { + dev_err(chip->pdev, "Failed to retrieve lpcpd-gpios from dts.\n"); + tpm_dev->io_lpcpd = -1; + /* + * lpcpd pin is not specified. This is not an issue as + * power management can be also managed by TPM specific + * commands. So leave with a success status code. + */ + return 0; + } + /* GPIO request and configuration */ + ret = devm_gpio_request_one(&client->dev, gpio, + GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD"); + if (ret) { + dev_err(chip->pdev, "Failed to request lpcpd pin\n"); + return -ENODEV; + } + tpm_dev->io_lpcpd = gpio; + + return 0; +} +#else +static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip) +{ + return -ENODEV; +} +#endif + +static int tpm_stm_i2c_request_resources(struct i2c_client *client, + struct tpm_chip *chip) +{ + struct st33zp24_platform_data *pdata; + struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + int ret; + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(chip->pdev, "No platform data\n"); + return -ENODEV; + } + + /* store for late use */ + tpm_dev->io_lpcpd = pdata->io_lpcpd; + + if (gpio_is_valid(pdata->io_lpcpd)) { + ret = devm_gpio_request_one(&client->dev, + pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH, + "TPM IO_LPCPD"); + if (ret) { + dev_err(chip->pdev, "%s : reset gpio_request failed\n", + __FILE__); + return ret; + } + } + + return 0; +} /* - * tpm_st33_i2c_probe initialize the TPM device + * tpm_stm_i2c_probe initialize the TPM device * @param: client, the i2c_client drescription (TPM I2C description). * @param: id, the i2c_device_id struct. * @return: 0 in case of success. * -1 in other case. */ static int -tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int err; - u8 intmask; + int ret; + u8 intmask = 0; struct tpm_chip *chip; struct st33zp24_platform_data *platform_data; + struct tpm_stm_dev *tpm_dev; - if (client == NULL) { + if (!client) { pr_info("%s: i2c client is NULL. Device not accessible.\n", __func__); - err = -ENODEV; - goto end; + return -ENODEV; } if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_info(&client->dev, "client not i2c capable\n"); - err = -ENODEV; - goto end; + return -ENODEV; } - chip = tpm_register_hardware(&client->dev, &st_i2c_tpm); - if (!chip) { - dev_info(&client->dev, "fail chip\n"); - err = -ENODEV; - goto end; - } + tpm_dev = devm_kzalloc(&client->dev, sizeof(struct tpm_stm_dev), + GFP_KERNEL); + if (!tpm_dev) + return -ENOMEM; + + chip = tpmm_chip_alloc(&client->dev, &st_i2c_tpm); + if (IS_ERR(chip)) + return PTR_ERR(chip); + + TPM_VPRIV(chip) = tpm_dev; + tpm_dev->client = client; platform_data = client->dev.platform_data; - - if (!platform_data) { - dev_info(&client->dev, "chip not available\n"); - err = -ENODEV; - goto _tpm_clean_answer; + if (!platform_data && client->dev.of_node) { + ret = tpm_stm_i2c_of_request_resources(chip); + if (ret) + goto _tpm_clean_answer; + } else if (platform_data) { + ret = tpm_stm_i2c_request_resources(client, chip); + if (ret) + goto _tpm_clean_answer; } - platform_data->tpm_i2c_buffer[0] = - kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); - if (platform_data->tpm_i2c_buffer[0] == NULL) { - err = -ENOMEM; - goto _tpm_clean_answer; - } - platform_data->tpm_i2c_buffer[1] = - kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); - if (platform_data->tpm_i2c_buffer[1] == NULL) { - err = -ENOMEM; - goto _tpm_clean_response1; - } - - TPM_VPRIV(chip) = client; - chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); @@ -656,59 +761,44 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) chip->vendor.locality = LOCALITY0; - if (power_mgt) { - err = gpio_request(platform_data->io_lpcpd, "TPM IO_LPCPD"); - if (err) - goto _gpio_init1; - gpio_set_value(platform_data->io_lpcpd, 1); - } + if (client->irq) { + /* INTERRUPT Setup */ + init_waitqueue_head(&chip->vendor.read_queue); + tpm_dev->intrs = 0; - if (interrupts) { - init_completion(&platform_data->irq_detection); if (request_locality(chip) != LOCALITY0) { - err = -ENODEV; - goto _tpm_clean_response2; + ret = -ENODEV; + goto _tpm_clean_answer; } - err = gpio_request(platform_data->io_serirq, "TPM IO_SERIRQ"); - if (err) - goto _gpio_init2; - clear_interruption(client); - err = request_irq(gpio_to_irq(platform_data->io_serirq), - &tpm_ioserirq_handler, + clear_interruption(tpm_dev); + ret = devm_request_irq(&client->dev, client->irq, + tpm_ioserirq_handler, IRQF_TRIGGER_HIGH, "TPM SERIRQ management", chip); - if (err < 0) { - dev_err(chip->dev , "TPM SERIRQ signals %d not available\n", - gpio_to_irq(platform_data->io_serirq)); - goto _irq_set; + if (ret < 0) { + dev_err(chip->pdev, "TPM SERIRQ signals %d not available\n", + client->irq); + goto _tpm_clean_answer; } - err = I2C_READ_DATA(client, TPM_INT_ENABLE, &intmask, 1); - if (err < 0) - goto _irq_set; - intmask |= TPM_INTF_CMD_READY_INT - | TPM_INTF_FIFO_AVALAIBLE_INT - | TPM_INTF_WAKE_UP_READY_INT - | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT | TPM_INTF_DATA_AVAIL_INT; - err = I2C_WRITE_DATA(client, TPM_INT_ENABLE, &intmask, 1); - if (err < 0) - goto _irq_set; + ret = I2C_WRITE_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); + if (ret < 0) + goto _tpm_clean_answer; intmask = TPM_GLOBAL_INT_ENABLE; - err = I2C_WRITE_DATA(client, (TPM_INT_ENABLE + 3), &intmask, 1); - if (err < 0) - goto _irq_set; + ret = I2C_WRITE_DATA(tpm_dev, (TPM_INT_ENABLE + 3), + &intmask, 1); + if (ret < 0) + goto _tpm_clean_answer; - err = I2C_READ_DATA(client, TPM_INT_STATUS, &intmask, 1); - if (err < 0) - goto _irq_set; + chip->vendor.irq = client->irq; - chip->vendor.irq = interrupts; + disable_irq_nosync(chip->vendor.irq); tpm_gen_interrupt(chip); } @@ -716,130 +806,106 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) tpm_get_timeouts(chip); tpm_do_selftest(chip); - dev_info(chip->dev, "TPM I2C Initialized\n"); - return 0; -_irq_set: - free_irq(gpio_to_irq(platform_data->io_serirq), (void *)chip); -_gpio_init2: - if (interrupts) - gpio_free(platform_data->io_serirq); -_gpio_init1: - if (power_mgt) - gpio_free(platform_data->io_lpcpd); -_tpm_clean_response2: - kzfree(platform_data->tpm_i2c_buffer[1]); - platform_data->tpm_i2c_buffer[1] = NULL; -_tpm_clean_response1: - kzfree(platform_data->tpm_i2c_buffer[0]); - platform_data->tpm_i2c_buffer[0] = NULL; + return tpm_chip_register(chip); _tpm_clean_answer: - tpm_remove_hardware(chip->dev); -end: - pr_info("TPM I2C initialisation fail\n"); - return err; + dev_info(chip->pdev, "TPM I2C initialisation fail\n"); + return ret; } /* - * tpm_st33_i2c_remove remove the TPM device - * @param: client, the i2c_client drescription (TPM I2C description). - clear_bit(0, &chip->is_open); + * tpm_stm_i2c_remove remove the TPM device + * @param: client, the i2c_client description (TPM I2C description). * @return: 0 in case of success. */ -static int tpm_st33_i2c_remove(struct i2c_client *client) +static int tpm_stm_i2c_remove(struct i2c_client *client) { - struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client); - struct st33zp24_platform_data *pin_infos = - ((struct i2c_client *)TPM_VPRIV(chip))->dev.platform_data; + struct tpm_chip *chip = + (struct tpm_chip *) i2c_get_clientdata(client); - if (pin_infos != NULL) { - free_irq(pin_infos->io_serirq, chip); - - gpio_free(pin_infos->io_serirq); - gpio_free(pin_infos->io_lpcpd); - - tpm_remove_hardware(chip->dev); - - if (pin_infos->tpm_i2c_buffer[1] != NULL) { - kzfree(pin_infos->tpm_i2c_buffer[1]); - pin_infos->tpm_i2c_buffer[1] = NULL; - } - if (pin_infos->tpm_i2c_buffer[0] != NULL) { - kzfree(pin_infos->tpm_i2c_buffer[0]); - pin_infos->tpm_i2c_buffer[0] = NULL; - } - } + if (chip) + tpm_chip_unregister(chip); return 0; } #ifdef CONFIG_PM_SLEEP /* - * tpm_st33_i2c_pm_suspend suspend the TPM device + * tpm_stm_i2c_pm_suspend suspend the TPM device * @param: client, the i2c_client drescription (TPM I2C description). * @param: mesg, the power management message. * @return: 0 in case of success. */ -static int tpm_st33_i2c_pm_suspend(struct device *dev) +static int tpm_stm_i2c_pm_suspend(struct device *dev) { struct st33zp24_platform_data *pin_infos = dev->platform_data; int ret = 0; - if (power_mgt) { + if (gpio_is_valid(pin_infos->io_lpcpd)) gpio_set_value(pin_infos->io_lpcpd, 0); - } else { + else ret = tpm_pm_suspend(dev); - } + return ret; -} /* tpm_st33_i2c_suspend() */ +} /* tpm_stm_i2c_suspend() */ /* - * tpm_st33_i2c_pm_resume resume the TPM device + * tpm_stm_i2c_pm_resume resume the TPM device * @param: client, the i2c_client drescription (TPM I2C description). * @return: 0 in case of success. */ -static int tpm_st33_i2c_pm_resume(struct device *dev) +static int tpm_stm_i2c_pm_resume(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); struct st33zp24_platform_data *pin_infos = dev->platform_data; int ret = 0; - if (power_mgt) { + if (gpio_is_valid(pin_infos->io_lpcpd)) { gpio_set_value(pin_infos->io_lpcpd, 1); - ret = wait_for_serirq_timeout(chip, - (chip->ops->status(chip) & - TPM_STS_VALID) == TPM_STS_VALID, - chip->vendor.timeout_b); + ret = wait_for_stat(chip, + TPM_STS_VALID, chip->vendor.timeout_b, + &chip->vendor.read_queue, false); } else { ret = tpm_pm_resume(dev); if (!ret) tpm_do_selftest(chip); } return ret; -} /* tpm_st33_i2c_pm_resume() */ +} /* tpm_stm_i2c_pm_resume() */ #endif -static const struct i2c_device_id tpm_st33_i2c_id[] = { +static const struct i2c_device_id tpm_stm_i2c_id[] = { {TPM_ST33_I2C, 0}, {} }; -MODULE_DEVICE_TABLE(i2c, tpm_st33_i2c_id); -static SIMPLE_DEV_PM_OPS(tpm_st33_i2c_ops, tpm_st33_i2c_pm_suspend, - tpm_st33_i2c_pm_resume); -static struct i2c_driver tpm_st33_i2c_driver = { +MODULE_DEVICE_TABLE(i2c, tpm_stm_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id of_st33zp24_i2c_match[] = { + { .compatible = "st,st33zp24-i2c", }, + {} +}; +MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match); +#endif + +static SIMPLE_DEV_PM_OPS(tpm_stm_i2c_ops, tpm_stm_i2c_pm_suspend, + tpm_stm_i2c_pm_resume); + +static struct i2c_driver tpm_stm_i2c_driver = { .driver = { - .owner = THIS_MODULE, - .name = TPM_ST33_I2C, - .pm = &tpm_st33_i2c_ops, - }, - .probe = tpm_st33_i2c_probe, - .remove = tpm_st33_i2c_remove, - .id_table = tpm_st33_i2c_id + .owner = THIS_MODULE, + .name = TPM_ST33_I2C, + .pm = &tpm_stm_i2c_ops, + .of_match_table = of_match_ptr(of_st33zp24_i2c_match), + }, + .probe = tpm_stm_i2c_probe, + .remove = tpm_stm_i2c_remove, + .id_table = tpm_stm_i2c_id }; -module_i2c_driver(tpm_st33_i2c_driver); +module_i2c_driver(tpm_stm_i2c_driver); MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)"); MODULE_DESCRIPTION("STM TPM I2C ST33 Driver"); -MODULE_VERSION("1.2.0"); +MODULE_VERSION("1.2.1"); MODULE_LICENSE("GPL"); diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index af74c57e5090..0840347e251c 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 IBM Corporation * - * Author: Ashley Lai + * Author: Ashley Lai * * Maintained by: * @@ -270,8 +270,11 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) static int tpm_ibmvtpm_remove(struct vio_dev *vdev) { struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); + struct tpm_chip *chip = dev_get_drvdata(ibmvtpm->dev); int rc = 0; + tpm_chip_unregister(chip); + free_irq(vdev->irq, ibmvtpm); do { @@ -290,8 +293,6 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev) kfree(ibmvtpm->rtce_buf); } - tpm_remove_hardware(ibmvtpm->dev); - kfree(ibmvtpm); return 0; @@ -307,6 +308,14 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev) static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev) { struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); + + /* ibmvtpm initializes at probe time, so the data we are + * asking for may not be set yet. Estimate that 4K required + * for TCE-mapped buffer in addition to CRQ. + */ + if (!ibmvtpm) + return CRQ_RES_BUF_SIZE + PAGE_SIZE; + return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size; } @@ -555,11 +564,9 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, struct tpm_chip *chip; int rc = -ENOMEM, rc1; - chip = tpm_register_hardware(dev, &tpm_ibmvtpm); - if (!chip) { - dev_err(dev, "tpm_register_hardware failed\n"); - return -ENODEV; - } + chip = tpmm_chip_alloc(dev, &tpm_ibmvtpm); + if (IS_ERR(chip)) + return PTR_ERR(chip); ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL); if (!ibmvtpm) { @@ -629,7 +636,7 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, if (rc) goto init_irq_cleanup; - return rc; + return tpm_chip_register(chip); init_irq_cleanup: do { rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address); @@ -644,8 +651,6 @@ cleanup: kfree(ibmvtpm); } - tpm_remove_hardware(dev); - return rc; } diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h index bd82a791f995..f595f14426bf 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.h +++ b/drivers/char/tpm/tpm_ibmvtpm.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 IBM Corporation * - * Author: Ashley Lai + * Author: Ashley Lai * * Maintained by: * diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index dc0a2554034e..6d492132ad2b 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -195,9 +195,9 @@ static int wait(struct tpm_chip *chip, int wait_for_bit) } if (i == TPM_MAX_TRIES) { /* timeout occurs */ if (wait_for_bit == STAT_XFE) - dev_err(chip->dev, "Timeout in wait(STAT_XFE)\n"); + dev_err(chip->pdev, "Timeout in wait(STAT_XFE)\n"); if (wait_for_bit == STAT_RDA) - dev_err(chip->dev, "Timeout in wait(STAT_RDA)\n"); + dev_err(chip->pdev, "Timeout in wait(STAT_RDA)\n"); return -EIO; } return 0; @@ -220,7 +220,7 @@ static void wait_and_send(struct tpm_chip *chip, u8 sendbyte) static void tpm_wtx(struct tpm_chip *chip) { number_of_wtx++; - dev_info(chip->dev, "Granting WTX (%02d / %02d)\n", + dev_info(chip->pdev, "Granting WTX (%02d / %02d)\n", number_of_wtx, TPM_MAX_WTX_PACKAGES); wait_and_send(chip, TPM_VL_VER); wait_and_send(chip, TPM_CTRL_WTX); @@ -231,7 +231,7 @@ static void tpm_wtx(struct tpm_chip *chip) static void tpm_wtx_abort(struct tpm_chip *chip) { - dev_info(chip->dev, "Aborting WTX\n"); + dev_info(chip->pdev, "Aborting WTX\n"); wait_and_send(chip, TPM_VL_VER); wait_and_send(chip, TPM_CTRL_WTX_ABORT); wait_and_send(chip, 0x00); @@ -257,7 +257,7 @@ recv_begin: } if (buf[0] != TPM_VL_VER) { - dev_err(chip->dev, + dev_err(chip->pdev, "Wrong transport protocol implementation!\n"); return -EIO; } @@ -272,7 +272,7 @@ recv_begin: } if ((size == 0x6D00) && (buf[1] == 0x80)) { - dev_err(chip->dev, "Error handling on vendor layer!\n"); + dev_err(chip->pdev, "Error handling on vendor layer!\n"); return -EIO; } @@ -284,7 +284,7 @@ recv_begin: } if (buf[1] == TPM_CTRL_WTX) { - dev_info(chip->dev, "WTX-package received\n"); + dev_info(chip->pdev, "WTX-package received\n"); if (number_of_wtx < TPM_MAX_WTX_PACKAGES) { tpm_wtx(chip); goto recv_begin; @@ -295,14 +295,14 @@ recv_begin: } if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) { - dev_info(chip->dev, "WTX-abort acknowledged\n"); + dev_info(chip->pdev, "WTX-abort acknowledged\n"); return size; } if (buf[1] == TPM_CTRL_ERROR) { - dev_err(chip->dev, "ERROR-package received:\n"); + dev_err(chip->pdev, "ERROR-package received:\n"); if (buf[4] == TPM_INF_NAK) - dev_err(chip->dev, + dev_err(chip->pdev, "-> Negative acknowledgement" " - retransmit command!\n"); return -EIO; @@ -321,7 +321,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count) ret = empty_fifo(chip, 1); if (ret) { - dev_err(chip->dev, "Timeout while clearing FIFO\n"); + dev_err(chip->pdev, "Timeout while clearing FIFO\n"); return -EIO; } @@ -546,7 +546,14 @@ static int tpm_inf_pnp_probe(struct pnp_dev *dev, vendorid[0], vendorid[1], productid[0], productid[1], chipname); - if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) + chip = tpmm_chip_alloc(&dev->dev, &tpm_inf); + if (IS_ERR(chip)) { + rc = PTR_ERR(chip); + goto err_release_region; + } + + rc = tpm_chip_register(chip); + if (rc) goto err_release_region; return 0; @@ -572,17 +579,15 @@ static void tpm_inf_pnp_remove(struct pnp_dev *dev) { struct tpm_chip *chip = pnp_get_drvdata(dev); - if (chip) { - if (tpm_dev.iotype == TPM_INF_IO_PORT) { - release_region(tpm_dev.data_regs, tpm_dev.data_size); - release_region(tpm_dev.config_port, - tpm_dev.config_size); - } else { - iounmap(tpm_dev.mem_base); - release_mem_region(tpm_dev.map_base, tpm_dev.map_size); - } - tpm_dev_vendor_release(chip); - tpm_remove_hardware(chip->dev); + tpm_chip_unregister(chip); + + if (tpm_dev.iotype == TPM_INF_IO_PORT) { + release_region(tpm_dev.data_regs, tpm_dev.data_size); + release_region(tpm_dev.config_port, + tpm_dev.config_size); + } else { + iounmap(tpm_dev.mem_base); + release_mem_region(tpm_dev.map_base, tpm_dev.map_size); } } diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 4d0a17ea8cde..289389ecef84 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -113,7 +113,7 @@ static int nsc_wait_for_ready(struct tpm_chip *chip) } while (time_before(jiffies, stop)); - dev_info(chip->dev, "wait for ready failed\n"); + dev_info(chip->pdev, "wait for ready failed\n"); return -EBUSY; } @@ -129,12 +129,12 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) return -EIO; if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) { - dev_err(chip->dev, "F0 timeout\n"); + dev_err(chip->pdev, "F0 timeout\n"); return -EIO; } if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) { - dev_err(chip->dev, "not in normal mode (0x%x)\n", + dev_err(chip->pdev, "not in normal mode (0x%x)\n", data); return -EIO; } @@ -143,7 +143,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) for (p = buffer; p < &buffer[count]; p++) { if (wait_for_stat (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) { - dev_err(chip->dev, + dev_err(chip->pdev, "OBF timeout (while reading data)\n"); return -EIO; } @@ -154,11 +154,11 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) if ((data & NSC_STATUS_F0) == 0 && (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) { - dev_err(chip->dev, "F0 not set\n"); + dev_err(chip->pdev, "F0 not set\n"); return -EIO; } if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) { - dev_err(chip->dev, + dev_err(chip->pdev, "expected end of command(0x%x)\n", data); return -EIO; } @@ -189,19 +189,19 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) return -EIO; if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { - dev_err(chip->dev, "IBF timeout\n"); + dev_err(chip->pdev, "IBF timeout\n"); return -EIO; } outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND); if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) { - dev_err(chip->dev, "IBR timeout\n"); + dev_err(chip->pdev, "IBR timeout\n"); return -EIO; } for (i = 0; i < count; i++) { if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { - dev_err(chip->dev, + dev_err(chip->pdev, "IBF timeout (while writing data)\n"); return -EIO; } @@ -209,7 +209,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) } if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { - dev_err(chip->dev, "IBF timeout\n"); + dev_err(chip->pdev, "IBF timeout\n"); return -EIO; } outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND); @@ -247,10 +247,9 @@ static struct platform_device *pdev = NULL; static void tpm_nsc_remove(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); - if ( chip ) { - release_region(chip->vendor.base, 2); - tpm_remove_hardware(chip->dev); - } + + tpm_chip_unregister(chip); + release_region(chip->vendor.base, 2); } static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume); @@ -307,11 +306,16 @@ static int __init init_nsc(void) goto err_del_dev; } - if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) { + chip = tpmm_chip_alloc(&pdev->dev, &tpm_nsc); + if (IS_ERR(chip)) { rc = -ENODEV; goto err_rel_reg; } + rc = tpm_chip_register(chip); + if (rc) + goto err_rel_reg; + dev_dbg(&pdev->dev, "NSC TPM detected\n"); dev_dbg(&pdev->dev, "NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n", diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index 98ba2bd1a355..c002d1bd9caf 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c @@ -1,7 +1,7 @@ /* * Copyright 2012 IBM Corporation * - * Author: Ashley Lai + * Author: Ashley Lai * * Maintained by: * diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index 61dcc8011ec7..6ca9b5d78144 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2012-2014 Intel Corporation + * + * Authors: + * Xiaoyan Zhang + * Jiang Liu + * Jarkko Sakkinen + * + * Maintained by: + * + * This file contains implementation of the sysfs interface for PPI. + * + * 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 "tpm.h" @@ -12,7 +31,6 @@ #define PPI_TPM_REQ_MAX 22 #define PPI_VS_REQ_START 128 #define PPI_VS_REQ_END 255 -#define PPI_VERSION_LEN 3 static const u8 tpm_ppi_uuid[] = { 0xA6, 0xFA, 0xDD, 0x3D, @@ -22,45 +40,22 @@ static const u8 tpm_ppi_uuid[] = { 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 }; -static char tpm_ppi_version[PPI_VERSION_LEN + 1]; -static acpi_handle tpm_ppi_handle; - -static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, - void **return_value) -{ - union acpi_object *obj; - - if (!acpi_check_dsm(handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, - 1 << TPM_PPI_FN_VERSION)) - return AE_OK; - - /* Cache version string */ - obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid, - TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, - NULL, ACPI_TYPE_STRING); - if (obj) { - strlcpy(tpm_ppi_version, obj->string.pointer, - PPI_VERSION_LEN + 1); - ACPI_FREE(obj); - } - - *return_value = handle; - - return AE_CTRL_TERMINATE; -} - static inline union acpi_object * -tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4) +tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type, + union acpi_object *argv4) { - BUG_ON(!tpm_ppi_handle); - return acpi_evaluate_dsm_typed(tpm_ppi_handle, tpm_ppi_uuid, - TPM_PPI_REVISION_ID, func, argv4, type); + BUG_ON(!ppi_handle); + return acpi_evaluate_dsm_typed(ppi_handle, tpm_ppi_uuid, + TPM_PPI_REVISION_ID, + func, argv4, type); } static ssize_t tpm_show_ppi_version(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%s\n", tpm_ppi_version); + struct tpm_chip *chip = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version); } static ssize_t tpm_show_ppi_request(struct device *dev, @@ -68,8 +63,10 @@ static ssize_t tpm_show_ppi_request(struct device *dev, { ssize_t size = -EINVAL; union acpi_object *obj; + struct tpm_chip *chip = dev_get_drvdata(dev); - obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL); + obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ, + ACPI_TYPE_PACKAGE, NULL); if (!obj) return -ENXIO; @@ -103,14 +100,15 @@ static ssize_t tpm_store_ppi_request(struct device *dev, int func = TPM_PPI_FN_SUBREQ; union acpi_object *obj, tmp; union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp); + struct tpm_chip *chip = dev_get_drvdata(dev); /* * the function to submit TPM operation request to pre-os environment * is updated with function index from SUBREQ to SUBREQ2 since PPI * version 1.1 */ - if (acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, - 1 << TPM_PPI_FN_SUBREQ2)) + if (acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid, + TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2)) func = TPM_PPI_FN_SUBREQ2; /* @@ -119,7 +117,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev, * string/package type. For PPI version 1.0 and 1.1, use buffer type * for compatibility, and use package type since 1.2 according to spec. */ - if (strcmp(tpm_ppi_version, "1.2") < 0) { + if (strcmp(chip->ppi_version, "1.2") < 0) { if (sscanf(buf, "%d", &req) != 1) return -EINVAL; argv4.type = ACPI_TYPE_BUFFER; @@ -131,7 +129,8 @@ static ssize_t tpm_store_ppi_request(struct device *dev, return -EINVAL; } - obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4); + obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER, + &argv4); if (!obj) { return -ENXIO; } else { @@ -157,6 +156,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev, .buffer.length = 0, .buffer.pointer = NULL }; + struct tpm_chip *chip = dev_get_drvdata(dev); static char *info[] = { "None", @@ -171,9 +171,10 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev, * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for * compatibility, define params[3].type as buffer, if PPI version < 1.2 */ - if (strcmp(tpm_ppi_version, "1.2") < 0) + if (strcmp(chip->ppi_version, "1.2") < 0) obj = &tmp; - obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj); + obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT, + ACPI_TYPE_INTEGER, obj); if (!obj) { return -ENXIO; } else { @@ -196,8 +197,10 @@ static ssize_t tpm_show_ppi_response(struct device *dev, acpi_status status = -EINVAL; union acpi_object *obj, *ret_obj; u64 req, res; + struct tpm_chip *chip = dev_get_drvdata(dev); - obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL); + obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP, + ACPI_TYPE_PACKAGE, NULL); if (!obj) return -ENXIO; @@ -248,7 +251,8 @@ cleanup: return status; } -static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) +static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start, + u32 end) { int i; u32 ret; @@ -264,14 +268,15 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) "User not required", }; - if (!acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, + if (!acpi_check_dsm(dev_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_GETOPR)) return -EPERM; tmp.integer.type = ACPI_TYPE_INTEGER; for (i = start; i <= end; i++) { tmp.integer.value = i; - obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv); + obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR, + ACPI_TYPE_INTEGER, &argv); if (!obj) { return -ENOMEM; } else { @@ -291,14 +296,20 @@ static ssize_t tpm_show_ppi_tcg_operations(struct device *dev, struct device_attribute *attr, char *buf) { - return show_ppi_operations(buf, 0, PPI_TPM_REQ_MAX); + struct tpm_chip *chip = dev_get_drvdata(dev); + + return show_ppi_operations(chip->acpi_dev_handle, buf, 0, + PPI_TPM_REQ_MAX); } static ssize_t tpm_show_ppi_vs_operations(struct device *dev, struct device_attribute *attr, char *buf) { - return show_ppi_operations(buf, PPI_VS_REQ_START, PPI_VS_REQ_END); + struct tpm_chip *chip = dev_get_drvdata(dev); + + return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START, + PPI_VS_REQ_END); } static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL); @@ -323,16 +334,38 @@ static struct attribute_group ppi_attr_grp = { .attrs = ppi_attrs }; -int tpm_add_ppi(struct kobject *parent) +int tpm_add_ppi(struct tpm_chip *chip) { - /* Cache TPM ACPI handle and version string */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, - ppi_callback, NULL, NULL, &tpm_ppi_handle); - return tpm_ppi_handle ? sysfs_create_group(parent, &ppi_attr_grp) : 0; + union acpi_object *obj; + int rc; + + if (!chip->acpi_dev_handle) + return 0; + + if (!acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid, + TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION)) + return 0; + + /* Cache PPI version string. */ + obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, tpm_ppi_uuid, + TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, + NULL, ACPI_TYPE_STRING); + if (obj) { + strlcpy(chip->ppi_version, obj->string.pointer, + sizeof(chip->ppi_version)); + ACPI_FREE(obj); + } + + rc = sysfs_create_group(&chip->pdev->kobj, &ppi_attr_grp); + + if (!rc) + chip->flags |= TPM_CHIP_FLAG_PPI; + + return rc; } -void tpm_remove_ppi(struct kobject *parent) +void tpm_remove_ppi(struct tpm_chip *chip) { - if (tpm_ppi_handle) - sysfs_remove_group(parent, &ppi_attr_grp); + if (chip->flags & TPM_CHIP_FLAG_PPI) + sysfs_remove_group(&chip->pdev->kobj, &ppi_attr_grp); } diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 6f1985496112..6725bef7cb96 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2005, 2006 IBM Corporation + * Copyright (C) 2014 Intel Corporation * * Authors: * Leendert van Doorn @@ -64,19 +65,30 @@ enum tis_defaults { TIS_LONG_TIMEOUT = 2000, /* 2 sec */ }; + +/* Some timeout values are needed before it is known whether the chip is + * TPM 1.0 or TPM 2.0. + */ +#define TIS_TIMEOUT_A_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_A) +#define TIS_TIMEOUT_B_MAX max(TIS_LONG_TIMEOUT, TPM2_TIMEOUT_B) +#define TIS_TIMEOUT_C_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_C) +#define TIS_TIMEOUT_D_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_D) + #define TPM_ACCESS(l) (0x0000 | ((l) << 12)) #define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12)) #define TPM_INT_VECTOR(l) (0x000C | ((l) << 12)) #define TPM_INT_STATUS(l) (0x0010 | ((l) << 12)) #define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12)) #define TPM_STS(l) (0x0018 | ((l) << 12)) +#define TPM_STS3(l) (0x001b | ((l) << 12)) #define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12)) #define TPM_DID_VID(l) (0x0F00 | ((l) << 12)) #define TPM_RID(l) (0x0F04 | ((l) << 12)) -static LIST_HEAD(tis_chips); -static DEFINE_MUTEX(tis_lock); +struct priv_data { + bool irq_tested; +}; #if defined(CONFIG_PNP) && defined(CONFIG_ACPI) static int is_itpm(struct pnp_dev *dev) @@ -241,7 +253,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) /* read first 10 bytes, including tag, paramsize, and result */ if ((size = recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) { - dev_err(chip->dev, "Unable to read header\n"); + dev_err(chip->pdev, "Unable to read header\n"); goto out; } @@ -254,7 +266,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) if ((size += recv_data(chip, &buf[TPM_HEADER_SIZE], expected - TPM_HEADER_SIZE)) < expected) { - dev_err(chip->dev, "Unable to read remainder of result\n"); + dev_err(chip->pdev, "Unable to read remainder of result\n"); size = -ETIME; goto out; } @@ -263,7 +275,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) &chip->vendor.int_queue, false); status = tpm_tis_status(chip); if (status & TPM_STS_DATA_AVAIL) { /* retry? */ - dev_err(chip->dev, "Error left over data\n"); + dev_err(chip->pdev, "Error left over data\n"); size = -EIO; goto out; } @@ -338,15 +350,31 @@ out_err: return rc; } +static void disable_interrupts(struct tpm_chip *chip) +{ + u32 intmask; + + intmask = + ioread32(chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + intmask &= ~TPM_GLOBAL_INT_ENABLE; + iowrite32(intmask, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + free_irq(chip->vendor.irq, chip); + chip->vendor.irq = 0; +} + /* * If interrupts are used (signaled by an irq set in the vendor structure) * tpm.c can skip polling for the data to be available as the interrupt is * waited for here */ -static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) +static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len) { int rc; u32 ordinal; + unsigned long dur; rc = tpm_tis_send_data(chip, buf, len); if (rc < 0) @@ -358,9 +386,14 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) if (chip->vendor.irq) { ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); + + if (chip->flags & TPM_CHIP_FLAG_TPM2) + dur = tpm2_calc_ordinal_duration(chip, ordinal); + else + dur = tpm_calc_ordinal_duration(chip, ordinal); + if (wait_for_tpm_stat - (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, - tpm_calc_ordinal_duration(chip, ordinal), + (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur, &chip->vendor.read_queue, false) < 0) { rc = -ETIME; goto out_err; @@ -373,6 +406,30 @@ out_err: return rc; } +static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) +{ + int rc, irq; + struct priv_data *priv = chip->vendor.priv; + + if (!chip->vendor.irq || priv->irq_tested) + return tpm_tis_send_main(chip, buf, len); + + /* Verify receipt of the expected IRQ */ + irq = chip->vendor.irq; + chip->vendor.irq = 0; + rc = tpm_tis_send_main(chip, buf, len); + chip->vendor.irq = irq; + if (!priv->irq_tested) + msleep(1); + if (!priv->irq_tested) { + disable_interrupts(chip); + dev_err(chip->pdev, + FW_BUG "TPM interrupt not working, polling instead\n"); + } + priv->irq_tested = true; + return rc; +} + struct tis_vendor_timeout_override { u32 did_vid; unsigned long timeout_us[4]; @@ -436,7 +493,7 @@ static int probe_itpm(struct tpm_chip *chip) rc = tpm_tis_send_data(chip, cmd_getticks, len); if (rc == 0) { - dev_info(chip->dev, "Detected an iTPM.\n"); + dev_info(chip->pdev, "Detected an iTPM.\n"); rc = 1; } else rc = -EFAULT; @@ -505,6 +562,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) if (interrupt == 0) return IRQ_NONE; + ((struct priv_data *)chip->vendor.priv)->irq_tested = true; if (interrupt & TPM_INTF_DATA_AVAIL_INT) wake_up_interruptible(&chip->vendor.read_queue); if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT) @@ -528,27 +586,48 @@ static bool interrupts = true; module_param(interrupts, bool, 0444); MODULE_PARM_DESC(interrupts, "Enable interrupts"); -static int tpm_tis_init(struct device *dev, resource_size_t start, - resource_size_t len, unsigned int irq) +static void tpm_tis_remove(struct tpm_chip *chip) +{ + iowrite32(~TPM_GLOBAL_INT_ENABLE & + ioread32(chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor. + locality)), + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + release_locality(chip, chip->vendor.locality, 1); +} + +static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle, + resource_size_t start, resource_size_t len, + unsigned int irq) { u32 vendor, intfcaps, intmask; int rc, i, irq_s, irq_e, probe; struct tpm_chip *chip; + struct priv_data *priv; - if (!(chip = tpm_register_hardware(dev, &tpm_tis))) - return -ENODEV; + priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; - chip->vendor.iobase = ioremap(start, len); - if (!chip->vendor.iobase) { - rc = -EIO; - goto out_err; - } + chip = tpmm_chip_alloc(dev, &tpm_tis); + if (IS_ERR(chip)) + return PTR_ERR(chip); - /* Default timeouts */ - chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); - chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); - chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); - chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->vendor.priv = priv; +#ifdef CONFIG_ACPI + chip->acpi_dev_handle = acpi_dev_handle; +#endif + + chip->vendor.iobase = devm_ioremap(dev, start, len); + if (!chip->vendor.iobase) + return -EIO; + + /* Maximum timeouts */ + chip->vendor.timeout_a = TIS_TIMEOUT_A_MAX; + chip->vendor.timeout_b = TIS_TIMEOUT_B_MAX; + chip->vendor.timeout_c = TIS_TIMEOUT_C_MAX; + chip->vendor.timeout_d = TIS_TIMEOUT_D_MAX; if (wait_startup(chip, 0) != 0) { rc = -ENODEV; @@ -560,11 +639,18 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, goto out_err; } + /* Every TPM 2.x command has a higher ordinal than TPM 1.x commands. + * Therefore, we can use an idempotent TPM 2.x command to probe TPM 2.x. + */ + rc = tpm2_gen_interrupt(chip, true); + if (rc == 0 || rc == TPM2_RC_INITIALIZE) + chip->flags |= TPM_CHIP_FLAG_TPM2; + vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0)); chip->vendor.manufacturer_id = vendor; - dev_info(dev, - "1.2 TPM (device-id 0x%X, rev-id %d)\n", + dev_info(dev, "%s TPM (device-id 0x%X, rev-id %d)\n", + (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2", vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); if (!itpm) { @@ -605,19 +691,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, if (intfcaps & TPM_INTF_DATA_AVAIL_INT) dev_dbg(dev, "\tData Avail Int Support\n"); - /* get the timeouts before testing for irqs */ - if (tpm_get_timeouts(chip)) { - dev_err(dev, "Could not get TPM timeouts and durations\n"); - rc = -ENODEV; - goto out_err; - } - - if (tpm_do_selftest(chip)) { - dev_err(dev, "TPM self test failed\n"); - rc = -ENODEV; - goto out_err; - } - /* INTERRUPT Setup */ init_waitqueue_head(&chip->vendor.read_queue); init_waitqueue_head(&chip->vendor.int_queue); @@ -649,10 +722,10 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) { iowrite8(i, chip->vendor.iobase + TPM_INT_VECTOR(chip->vendor.locality)); - if (request_irq - (i, tis_int_probe, IRQF_SHARED, - chip->vendor.miscdev.name, chip) != 0) { - dev_info(chip->dev, + if (devm_request_irq + (dev, i, tis_int_probe, IRQF_SHARED, + chip->devname, chip) != 0) { + dev_info(chip->pdev, "Unable to request irq: %d for probe\n", i); continue; @@ -673,7 +746,10 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, chip->vendor.probed_irq = 0; /* Generate Interrupts */ - tpm_gen_interrupt(chip); + if (chip->flags & TPM_CHIP_FLAG_TPM2) + tpm2_gen_interrupt(chip, false); + else + tpm_gen_interrupt(chip); chip->vendor.irq = chip->vendor.probed_irq; @@ -690,17 +766,16 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, iowrite32(intmask, chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); - free_irq(i, chip); } } if (chip->vendor.irq) { iowrite8(chip->vendor.irq, chip->vendor.iobase + TPM_INT_VECTOR(chip->vendor.locality)); - if (request_irq - (chip->vendor.irq, tis_int_handler, IRQF_SHARED, - chip->vendor.miscdev.name, chip) != 0) { - dev_info(chip->dev, + if (devm_request_irq + (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED, + chip->devname, chip) != 0) { + dev_info(chip->pdev, "Unable to request irq: %d for use\n", chip->vendor.irq); chip->vendor.irq = 0; @@ -719,17 +794,49 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, } } - INIT_LIST_HEAD(&chip->vendor.list); - mutex_lock(&tis_lock); - list_add(&chip->vendor.list, &tis_chips); - mutex_unlock(&tis_lock); + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A); + chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B); + chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C); + chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D); + chip->vendor.duration[TPM_SHORT] = + msecs_to_jiffies(TPM2_DURATION_SHORT); + chip->vendor.duration[TPM_MEDIUM] = + msecs_to_jiffies(TPM2_DURATION_MEDIUM); + chip->vendor.duration[TPM_LONG] = + msecs_to_jiffies(TPM2_DURATION_LONG); + rc = tpm2_do_selftest(chip); + if (rc == TPM2_RC_INITIALIZE) { + dev_warn(dev, "Firmware has not started TPM\n"); + rc = tpm2_startup(chip, TPM2_SU_CLEAR); + if (!rc) + rc = tpm2_do_selftest(chip); + } - return 0; + if (rc) { + dev_err(dev, "TPM self test failed\n"); + if (rc > 0) + rc = -ENODEV; + goto out_err; + } + } else { + if (tpm_get_timeouts(chip)) { + dev_err(dev, "Could not get TPM timeouts and durations\n"); + rc = -ENODEV; + goto out_err; + } + + if (tpm_do_selftest(chip)) { + dev_err(dev, "TPM self test failed\n"); + rc = -ENODEV; + goto out_err; + } + } + + return tpm_chip_register(chip); out_err: - if (chip->vendor.iobase) - iounmap(chip->vendor.iobase); - tpm_remove_hardware(chip->dev); + tpm_tis_remove(chip); return rc; } @@ -758,14 +865,23 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) static int tpm_tis_resume(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); - int ret; + int ret = 0; if (chip->vendor.irq) tpm_tis_reenable_interrupts(chip); - ret = tpm_pm_resume(dev); - if (!ret) - tpm_do_selftest(chip); + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + /* NOP if firmware properly does this. */ + tpm2_startup(chip, TPM2_SU_STATE); + + ret = tpm2_shutdown(chip, TPM2_SU_STATE); + if (!ret) + ret = tpm2_do_selftest(chip); + } else { + ret = tpm_pm_resume(dev); + if (!ret) + tpm_do_selftest(chip); + } return ret; } @@ -779,6 +895,7 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev, { resource_size_t start, len; unsigned int irq = 0; + acpi_handle acpi_dev_handle = NULL; start = pnp_mem_start(pnp_dev, 0); len = pnp_mem_len(pnp_dev, 0); @@ -791,7 +908,12 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev, if (is_itpm(pnp_dev)) itpm = true; - return tpm_tis_init(&pnp_dev->dev, start, len, irq); +#ifdef CONFIG_ACPI + if (pnp_acpi_device(pnp_dev)) + acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle; +#endif + + return tpm_tis_init(&pnp_dev->dev, acpi_dev_handle, start, len, irq); } static struct pnp_device_id tpm_pnp_tbl[] = { @@ -811,13 +933,10 @@ MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); static void tpm_tis_pnp_remove(struct pnp_dev *dev) { struct tpm_chip *chip = pnp_get_drvdata(dev); - - tpm_dev_vendor_release(chip); - - kfree(chip); + tpm_chip_unregister(chip); + tpm_tis_remove(chip); } - static struct pnp_driver tis_pnp_driver = { .name = "tpm_tis", .id_table = tpm_pnp_tbl, @@ -836,7 +955,7 @@ MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe"); static struct platform_driver tis_drv = { .driver = { - .name = "tpm_tis", + .name = "tpm_tis", .pm = &tpm_tis_pm, }, }; @@ -862,7 +981,7 @@ static int __init init_tis(void) rc = PTR_ERR(pdev); goto err_dev; } - rc = tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0); + rc = tpm_tis_init(&pdev->dev, NULL, TIS_MEM_BASE, TIS_MEM_LEN, 0); if (rc) goto err_init; return 0; @@ -875,31 +994,16 @@ err_dev: static void __exit cleanup_tis(void) { - struct tpm_vendor_specific *i, *j; struct tpm_chip *chip; - mutex_lock(&tis_lock); - list_for_each_entry_safe(i, j, &tis_chips, list) { - chip = to_tpm_chip(i); - tpm_remove_hardware(chip->dev); - iowrite32(~TPM_GLOBAL_INT_ENABLE & - ioread32(chip->vendor.iobase + - TPM_INT_ENABLE(chip->vendor. - locality)), - chip->vendor.iobase + - TPM_INT_ENABLE(chip->vendor.locality)); - release_locality(chip, chip->vendor.locality, 1); - if (chip->vendor.irq) - free_irq(chip->vendor.irq, chip); - iounmap(i->iobase); - list_del(&i->list); - } - mutex_unlock(&tis_lock); #ifdef CONFIG_PNP if (!force) { pnp_unregister_driver(&tis_pnp_driver); return; } #endif + chip = dev_get_drvdata(&pdev->dev); + tpm_chip_unregister(chip); + tpm_tis_remove(chip); platform_device_unregister(pdev); platform_driver_unregister(&tis_drv); } diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index 441b44e54226..c3b4f5a5ac10 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c @@ -175,9 +175,9 @@ static int setup_chip(struct device *dev, struct tpm_private *priv) { struct tpm_chip *chip; - chip = tpm_register_hardware(dev, &tpm_vtpm); - if (!chip) - return -ENODEV; + chip = tpmm_chip_alloc(dev, &tpm_vtpm); + if (IS_ERR(chip)) + return PTR_ERR(chip); init_waitqueue_head(&chip->vendor.read_queue); @@ -286,6 +286,7 @@ static int tpmfront_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { struct tpm_private *priv; + struct tpm_chip *chip; int rv; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -302,21 +303,22 @@ static int tpmfront_probe(struct xenbus_device *dev, rv = setup_ring(dev, priv); if (rv) { - tpm_remove_hardware(&dev->dev); + chip = dev_get_drvdata(&dev->dev); + tpm_chip_unregister(chip); ring_free(priv); return rv; } tpm_get_timeouts(priv->chip); - return rv; + return tpm_chip_register(priv->chip); } static int tpmfront_remove(struct xenbus_device *dev) { struct tpm_chip *chip = dev_get_drvdata(&dev->dev); struct tpm_private *priv = TPM_VPRIV(chip); - tpm_remove_hardware(&dev->dev); + tpm_chip_unregister(chip); ring_free(priv); TPM_VPRIV(chip) = NULL; return 0; diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 3f44f292d066..91f86131bb7a 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -13,6 +13,7 @@ config COMMON_CLK bool select HAVE_CLK_PREPARE select CLKDEV_LOOKUP + select SRCU ---help--- The common clock framework is a single definition of struct clk, useful across many platforms, as well as an diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 11194b8329fe..cbcddcc02475 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -190,7 +190,7 @@ PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" }; PNAME(mux_uart3_p) = { "uart3_src", "uart3_frac", "xin24m" }; PNAME(mux_uart4_p) = { "uart4_src", "uart4_frac", "xin24m" }; PNAME(mux_cif_out_p) = { "cif_src", "xin24m" }; -PNAME(mux_macref_p) = { "mac_src", "ext_gmac" }; +PNAME(mux_mac_p) = { "mac_pll_src", "ext_gmac" }; PNAME(mux_hsadcout_p) = { "hsadc_src", "ext_hsadc" }; PNAME(mux_edp_24m_p) = { "ext_edp_24m", "xin24m" }; PNAME(mux_tspout_p) = { "cpll", "gpll", "npll", "xin27m" }; @@ -575,18 +575,18 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, 0, RK3288_CLKSEL_CON(3), 8, 2, MFLAGS), - COMPOSITE(0, "mac_src", mux_pll_src_npll_cpll_gpll_p, 0, + COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0, RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS, RK3288_CLKGATE_CON(2), 5, GFLAGS), - MUX(0, "macref", mux_macref_p, 0, + MUX(SCLK_MAC, "mac_clk", mux_mac_p, 0, RK3288_CLKSEL_CON(21), 4, 1, MFLAGS), - GATE(0, "sclk_macref_out", "macref", 0, + GATE(SCLK_MACREF_OUT, "sclk_macref_out", "mac_clk", 0, RK3288_CLKGATE_CON(5), 3, GFLAGS), - GATE(SCLK_MACREF, "sclk_macref", "macref", 0, + GATE(SCLK_MACREF, "sclk_macref", "mac_clk", 0, RK3288_CLKGATE_CON(5), 2, GFLAGS), - GATE(SCLK_MAC_RX, "sclk_mac_rx", "macref", 0, + GATE(SCLK_MAC_RX, "sclk_mac_rx", "mac_clk", 0, RK3288_CLKGATE_CON(5), 0, GFLAGS), - GATE(SCLK_MAC_TX, "sclk_mac_tx", "macref", 0, + GATE(SCLK_MAC_TX, "sclk_mac_tx", "mac_clk", 0, RK3288_CLKGATE_CON(5), 1, GFLAGS), COMPOSITE(0, "hsadc_src", mux_pll_src_cpll_gpll_p, 0, diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index fc01ec27d3c8..8a1479fc6479 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -229,4 +229,11 @@ config CLKSRC_MIPS_GIC depends on MIPS_GIC select CLKSRC_OF +config CLKSRC_PXA + def_bool y if ARCH_PXA || ARCH_SA1100 + select CLKSRC_OF if USE_OF + help + This enables OST0 support available on PXA and SA-11x0 + platforms. + endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 94d90b24b56b..aa526f4bd3cf 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -21,7 +21,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clps711x-timer.o obj-$(CONFIG_ARCH_MARCO) += timer-marco.o obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o obj-$(CONFIG_ARCH_MXS) += mxs_timer.o -obj-$(CONFIG_ARCH_PXA) += pxa_timer.o +obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o obj-$(CONFIG_ARCH_U300) += timer-u300.o obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 095c1774592c..a3025e7ae35f 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c index 0595dc6c453e..f1e33d08dd83 100644 --- a/drivers/clocksource/bcm_kona_timer.c +++ b/drivers/clocksource/bcm_kona_timer.c @@ -68,9 +68,8 @@ static void kona_timer_disable_and_clear(void __iomem *base) } static void -kona_timer_get_counter(void *timer_base, uint32_t *msw, uint32_t *lsw) +kona_timer_get_counter(void __iomem *timer_base, uint32_t *msw, uint32_t *lsw) { - void __iomem *base = IOMEM(timer_base); int loop_limit = 4; /* @@ -86,9 +85,9 @@ kona_timer_get_counter(void *timer_base, uint32_t *msw, uint32_t *lsw) */ while (--loop_limit) { - *msw = readl(base + KONA_GPTIMER_STCHI_OFFSET); - *lsw = readl(base + KONA_GPTIMER_STCLO_OFFSET); - if (*msw == readl(base + KONA_GPTIMER_STCHI_OFFSET)) + *msw = readl(timer_base + KONA_GPTIMER_STCHI_OFFSET); + *lsw = readl(timer_base + KONA_GPTIMER_STCLO_OFFSET); + if (*msw == readl(timer_base + KONA_GPTIMER_STCHI_OFFSET)) break; } if (!loop_limit) { diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 9403061a2acc..83564c9cfdbe 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -97,8 +97,8 @@ static void exynos4_mct_write(unsigned int value, unsigned long offset) writel_relaxed(value, reg_base + offset); if (likely(offset >= EXYNOS4_MCT_L_BASE(0))) { - stat_addr = (offset & ~EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET; - switch (offset & EXYNOS4_MCT_L_MASK) { + stat_addr = (offset & EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET; + switch (offset & ~EXYNOS4_MCT_L_MASK) { case MCT_L_TCON_OFFSET: mask = 1 << 3; /* L_TCON write status */ break; diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 0f665b8f2461..f150ca82bfaf 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -428,7 +428,7 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch, ced->features = CLOCK_EVT_FEAT_PERIODIC; ced->features |= CLOCK_EVT_FEAT_ONESHOT; ced->rating = 200; - ced->cpumask = cpumask_of(0); + ced->cpumask = cpu_possible_mask; ced->set_next_event = sh_tmu_clock_event_next; ced->set_mode = sh_tmu_clock_event_mode; ced->suspend = sh_tmu_clock_event_suspend; diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 29b2ef5a68b9..a171fef2c2b6 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -2,6 +2,7 @@ menu "CPU Frequency scaling" config CPU_FREQ bool "CPU Frequency scaling" + select SRCU help CPU Frequency scaling allows you to change the clock speed of CPUs on the fly. This is a nice method to save power, because diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 index 89ae88f91895..c59bdcb83217 100644 --- a/drivers/cpufreq/Kconfig.x86 +++ b/drivers/cpufreq/Kconfig.x86 @@ -57,6 +57,16 @@ config X86_ACPI_CPUFREQ_CPB By enabling this option the acpi_cpufreq driver provides the old entry in addition to the new boost ones, for compatibility reasons. +config X86_SFI_CPUFREQ + tristate "SFI Performance-States driver" + depends on X86_INTEL_MID && SFI + help + This adds a CPUFreq driver for some Silvermont based Intel Atom + architectures like Z34xx and Z35xx which enumerate processor + performance states through SFI. + + If in doubt, say N. + config ELAN_CPUFREQ tristate "AMD Elan SC400 and SC410" depends on MELAN diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index b3ca7b0b2c33..8b4220ac888b 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o obj-$(CONFIG_X86_INTEL_PSTATE) += intel_pstate.o obj-$(CONFIG_X86_AMD_FREQ_SENSITIVITY) += amd_freq_sensitivity.o +obj-$(CONFIG_X86_SFI_CPUFREQ) += sfi-cpufreq.o ################################################################################## # ARM SoC drivers diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index fde97d6e31d6..bab67db54b7e 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -320,8 +320,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy) { struct private_data *priv = policy->driver_data; - if (priv->cdev) - cpufreq_cooling_unregister(priv->cdev); + cpufreq_cooling_unregister(priv->cdev); dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); of_free_opp_table(priv->cpu_dev); clk_put(policy->clk); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 46bed4f81cde..28e59a48b35f 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -27,9 +27,21 @@ #include #include #include +#include #include #include +/* Macros to iterate over lists */ +/* Iterate over online CPUs policies */ +static LIST_HEAD(cpufreq_policy_list); +#define for_each_policy(__policy) \ + list_for_each_entry(__policy, &cpufreq_policy_list, policy_list) + +/* Iterate over governors */ +static LIST_HEAD(cpufreq_governor_list); +#define for_each_governor(__governor) \ + list_for_each_entry(__governor, &cpufreq_governor_list, governor_list) + /** * The "cpufreq driver" - the arch- or hardware-dependent low * level driver of CPUFreq support, and its spinlock. This lock @@ -40,7 +52,6 @@ static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback); static DEFINE_RWLOCK(cpufreq_driver_lock); DEFINE_MUTEX(cpufreq_governor_lock); -static LIST_HEAD(cpufreq_policy_list); /* This one keeps track of the previously set governor of a removed CPU */ static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); @@ -62,7 +73,7 @@ static DECLARE_RWSEM(cpufreq_rwsem); /* internal prototypes */ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); -static unsigned int __cpufreq_get(unsigned int cpu); +static unsigned int __cpufreq_get(struct cpufreq_policy *policy); static void handle_update(struct work_struct *work); /** @@ -93,7 +104,6 @@ void disable_cpufreq(void) { off = 1; } -static LIST_HEAD(cpufreq_governor_list); static DEFINE_MUTEX(cpufreq_governor_mutex); bool have_governor_per_policy(void) @@ -202,7 +212,7 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) struct cpufreq_policy *policy = NULL; unsigned long flags; - if (cpufreq_disabled() || (cpu >= nr_cpu_ids)) + if (cpu >= nr_cpu_ids) return NULL; if (!down_read_trylock(&cpufreq_rwsem)) @@ -229,9 +239,6 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_get); void cpufreq_cpu_put(struct cpufreq_policy *policy) { - if (cpufreq_disabled()) - return; - kobject_put(&policy->kobj); up_read(&cpufreq_rwsem); } @@ -249,12 +256,12 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_put); * systems as each CPU might be scaled differently. So, use the arch * per-CPU loops_per_jiffy value wherever possible. */ -#ifndef CONFIG_SMP -static unsigned long l_p_j_ref; -static unsigned int l_p_j_ref_freq; - static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { +#ifndef CONFIG_SMP + static unsigned long l_p_j_ref; + static unsigned int l_p_j_ref_freq; + if (ci->flags & CPUFREQ_CONST_LOOPS) return; @@ -270,13 +277,8 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) pr_debug("scaling loops_per_jiffy to %lu for frequency %u kHz\n", loops_per_jiffy, ci->new); } -} -#else -static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) -{ - return; -} #endif +} static void __cpufreq_notify_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, unsigned int state) @@ -432,11 +434,11 @@ static ssize_t store_boost(struct kobject *kobj, struct attribute *attr, } define_one_global_rw(boost); -static struct cpufreq_governor *__find_governor(const char *str_governor) +static struct cpufreq_governor *find_governor(const char *str_governor) { struct cpufreq_governor *t; - list_for_each_entry(t, &cpufreq_governor_list, governor_list) + for_each_governor(t) if (!strncasecmp(str_governor, t->name, CPUFREQ_NAME_LEN)) return t; @@ -463,12 +465,12 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, *policy = CPUFREQ_POLICY_POWERSAVE; err = 0; } - } else if (has_target()) { + } else { struct cpufreq_governor *t; mutex_lock(&cpufreq_governor_mutex); - t = __find_governor(str_governor); + t = find_governor(str_governor); if (t == NULL) { int ret; @@ -478,7 +480,7 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, mutex_lock(&cpufreq_governor_mutex); if (ret == 0) - t = __find_governor(str_governor); + t = find_governor(str_governor); } if (t != NULL) { @@ -513,8 +515,7 @@ show_one(cpuinfo_transition_latency, cpuinfo.transition_latency); show_one(scaling_min_freq, min); show_one(scaling_max_freq, max); -static ssize_t show_scaling_cur_freq( - struct cpufreq_policy *policy, char *buf) +static ssize_t show_scaling_cur_freq(struct cpufreq_policy *policy, char *buf) { ssize_t ret; @@ -563,7 +564,7 @@ store_one(scaling_max_freq, max); static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy, char *buf) { - unsigned int cur_freq = __cpufreq_get(policy->cpu); + unsigned int cur_freq = __cpufreq_get(policy); if (!cur_freq) return sprintf(buf, ""); return sprintf(buf, "%u\n", cur_freq); @@ -639,7 +640,7 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy, goto out; } - list_for_each_entry(t, &cpufreq_governor_list, governor_list) { + for_each_governor(t) { if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) - (CPUFREQ_NAME_LEN + 2))) goto out; @@ -902,7 +903,7 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy, /* set up files for this cpu device */ drv_attr = cpufreq_driver->attr; - while ((drv_attr) && (*drv_attr)) { + while (drv_attr && *drv_attr) { ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); if (ret) return ret; @@ -936,7 +937,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy) memcpy(&new_policy, policy, sizeof(*policy)); /* Update governor of new_policy to the governor used before hotplug */ - gov = __find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu)); + gov = find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu)); if (gov) pr_debug("Restoring governor %s for cpu %d\n", policy->governor->name, policy->cpu); @@ -958,7 +959,6 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy) } } -#ifdef CONFIG_HOTPLUG_CPU static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu, struct device *dev) { @@ -996,7 +996,6 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, return sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"); } -#endif static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu) { @@ -1033,6 +1032,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(void) init_rwsem(&policy->rwsem); spin_lock_init(&policy->transition_lock); init_waitqueue_head(&policy->transition_wait); + init_completion(&policy->kobj_unregister); + INIT_WORK(&policy->update, handle_update); return policy; @@ -1091,15 +1092,9 @@ static int update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu, } down_write(&policy->rwsem); - - policy->last_cpu = policy->cpu; policy->cpu = cpu; - up_write(&policy->rwsem); - blocking_notifier_call_chain(&cpufreq_policy_notifier_list, - CPUFREQ_UPDATE_POLICY_CPU, policy); - return 0; } @@ -1110,41 +1105,32 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) struct cpufreq_policy *policy; unsigned long flags; bool recover_policy = cpufreq_suspended; -#ifdef CONFIG_HOTPLUG_CPU - struct cpufreq_policy *tpolicy; -#endif if (cpu_is_offline(cpu)) return 0; pr_debug("adding CPU %u\n", cpu); -#ifdef CONFIG_SMP /* check whether a different CPU already registered this * CPU because it is in the same boat. */ - policy = cpufreq_cpu_get(cpu); - if (unlikely(policy)) { - cpufreq_cpu_put(policy); + policy = cpufreq_cpu_get_raw(cpu); + if (unlikely(policy)) return 0; - } -#endif if (!down_read_trylock(&cpufreq_rwsem)) return 0; -#ifdef CONFIG_HOTPLUG_CPU /* Check if this cpu was hot-unplugged earlier and has siblings */ read_lock_irqsave(&cpufreq_driver_lock, flags); - list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) { - if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) { + for_each_policy(policy) { + if (cpumask_test_cpu(cpu, policy->related_cpus)) { read_unlock_irqrestore(&cpufreq_driver_lock, flags); - ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev); + ret = cpufreq_add_policy_cpu(policy, cpu, dev); up_read(&cpufreq_rwsem); return ret; } } read_unlock_irqrestore(&cpufreq_driver_lock, flags); -#endif /* * Restore the saved policy when doing light-weight init and fall back @@ -1171,9 +1157,6 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) cpumask_copy(policy->cpus, cpumask_of(cpu)); - init_completion(&policy->kobj_unregister); - INIT_WORK(&policy->update, handle_update); - /* call driver. From then on the cpufreq must be able * to accept all calls to ->verify and ->setpolicy for this CPU */ @@ -1371,11 +1354,10 @@ static int __cpufreq_remove_dev_prepare(struct device *dev, pr_err("%s: Failed to stop governor\n", __func__); return ret; } - } - if (!cpufreq_driver->setpolicy) strncpy(per_cpu(cpufreq_cpu_governor, cpu), policy->governor->name, CPUFREQ_NAME_LEN); + } down_read(&policy->rwsem); cpus = cpumask_weight(policy->cpus); @@ -1416,9 +1398,10 @@ static int __cpufreq_remove_dev_finish(struct device *dev, unsigned long flags; struct cpufreq_policy *policy; - read_lock_irqsave(&cpufreq_driver_lock, flags); + write_lock_irqsave(&cpufreq_driver_lock, flags); policy = per_cpu(cpufreq_cpu_data, cpu); - read_unlock_irqrestore(&cpufreq_driver_lock, flags); + per_cpu(cpufreq_cpu_data, cpu) = NULL; + write_unlock_irqrestore(&cpufreq_driver_lock, flags); if (!policy) { pr_debug("%s: No cpu_data found\n", __func__); @@ -1473,7 +1456,6 @@ static int __cpufreq_remove_dev_finish(struct device *dev, } } - per_cpu(cpufreq_cpu_data, cpu) = NULL; return 0; } @@ -1510,30 +1492,23 @@ static void handle_update(struct work_struct *work) /** * cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're * in deep trouble. - * @cpu: cpu number - * @old_freq: CPU frequency the kernel thinks the CPU runs at + * @policy: policy managing CPUs * @new_freq: CPU frequency the CPU actually runs at * * We adjust to current frequency first, and need to clean up later. * So either call to cpufreq_update_policy() or schedule handle_update()). */ -static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, +static void cpufreq_out_of_sync(struct cpufreq_policy *policy, unsigned int new_freq) { - struct cpufreq_policy *policy; struct cpufreq_freqs freqs; - unsigned long flags; pr_debug("Warning: CPU frequency out of sync: cpufreq and timing core thinks of %u, is %u kHz\n", - old_freq, new_freq); + policy->cur, new_freq); - freqs.old = old_freq; + freqs.old = policy->cur; freqs.new = new_freq; - read_lock_irqsave(&cpufreq_driver_lock, flags); - policy = per_cpu(cpufreq_cpu_data, cpu); - read_unlock_irqrestore(&cpufreq_driver_lock, flags); - cpufreq_freq_transition_begin(policy, &freqs); cpufreq_freq_transition_end(policy, &freqs, 0); } @@ -1583,22 +1558,21 @@ unsigned int cpufreq_quick_get_max(unsigned int cpu) } EXPORT_SYMBOL(cpufreq_quick_get_max); -static unsigned int __cpufreq_get(unsigned int cpu) +static unsigned int __cpufreq_get(struct cpufreq_policy *policy) { - struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); unsigned int ret_freq = 0; if (!cpufreq_driver->get) return ret_freq; - ret_freq = cpufreq_driver->get(cpu); + ret_freq = cpufreq_driver->get(policy->cpu); if (ret_freq && policy->cur && !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { /* verify no discrepancy between actual and saved value exists */ if (unlikely(ret_freq != policy->cur)) { - cpufreq_out_of_sync(cpu, policy->cur, ret_freq); + cpufreq_out_of_sync(policy, ret_freq); schedule_work(&policy->update); } } @@ -1619,7 +1593,7 @@ unsigned int cpufreq_get(unsigned int cpu) if (policy) { down_read(&policy->rwsem); - ret_freq = __cpufreq_get(cpu); + ret_freq = __cpufreq_get(policy); up_read(&policy->rwsem); cpufreq_cpu_put(policy); @@ -1682,7 +1656,7 @@ void cpufreq_suspend(void) pr_debug("%s: Suspending Governors\n", __func__); - list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { + for_each_policy(policy) { if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP)) pr_err("%s: Failed to stop governor for policy: %p\n", __func__, policy); @@ -1716,7 +1690,7 @@ void cpufreq_resume(void) pr_debug("%s: Resuming Governors\n", __func__); - list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { + for_each_policy(policy) { if (cpufreq_driver->resume && cpufreq_driver->resume(policy)) pr_err("%s: Failed to resume driver: %p\n", __func__, policy); @@ -2006,10 +1980,6 @@ int cpufreq_driver_target(struct cpufreq_policy *policy, } EXPORT_SYMBOL_GPL(cpufreq_driver_target); -/* - * when "event" is CPUFREQ_GOV_LIMITS - */ - static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event) { @@ -2107,7 +2077,7 @@ int cpufreq_register_governor(struct cpufreq_governor *governor) governor->initialized = 0; err = -EBUSY; - if (__find_governor(governor->name) == NULL) { + if (!find_governor(governor->name)) { err = 0; list_add(&governor->governor_list, &cpufreq_governor_list); } @@ -2307,8 +2277,7 @@ int cpufreq_update_policy(unsigned int cpu) policy->cur = new_policy.cur; } else { if (policy->cur != new_policy.cur && has_target()) - cpufreq_out_of_sync(cpu, policy->cur, - new_policy.cur); + cpufreq_out_of_sync(policy, new_policy.cur); } } @@ -2364,7 +2333,7 @@ static int cpufreq_boost_set_sw(int state) struct cpufreq_policy *policy; int ret = -EINVAL; - list_for_each_entry(policy, &cpufreq_policy_list, policy_list) { + for_each_policy(policy) { freq_table = cpufreq_frequency_get_table(policy->cpu); if (freq_table) { ret = cpufreq_frequency_table_cpuinfo(policy, @@ -2454,9 +2423,6 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) pr_debug("trying to register driver %s\n", driver_data->name); - if (driver_data->setpolicy) - driver_data->flags |= CPUFREQ_CONST_LOOPS; - write_lock_irqsave(&cpufreq_driver_lock, flags); if (cpufreq_driver) { write_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -2465,6 +2431,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) cpufreq_driver = driver_data; write_unlock_irqrestore(&cpufreq_driver_lock, flags); + if (driver_data->setpolicy) + driver_data->flags |= CPUFREQ_CONST_LOOPS; + if (cpufreq_boost_supported()) { /* * Check if driver provides function to enable boost - @@ -2485,23 +2454,12 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) if (ret) goto err_boost_unreg; - if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) { - int i; - ret = -ENODEV; - - /* check for at least one working CPU */ - for (i = 0; i < nr_cpu_ids; i++) - if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i)) { - ret = 0; - break; - } - + if (!(cpufreq_driver->flags & CPUFREQ_STICKY) && + list_empty(&cpufreq_policy_list)) { /* if all ->init() calls failed, unregister */ - if (ret) { - pr_debug("no CPU initialized for driver %s\n", - driver_data->name); - goto err_if_unreg; - } + pr_debug("%s: No CPU initialized for driver %s\n", __func__, + driver_data->name); + goto err_if_unreg; } register_hotcpu_notifier(&cpufreq_cpu_notifier); @@ -2556,6 +2514,14 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) } EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); +/* + * Stop cpufreq at shutdown to make sure it isn't holding any locks + * or mutexes when secondary CPUs are halted. + */ +static struct syscore_ops cpufreq_syscore_ops = { + .shutdown = cpufreq_suspend, +}; + static int __init cpufreq_core_init(void) { if (cpufreq_disabled()) @@ -2564,6 +2530,8 @@ static int __init cpufreq_core_init(void) cpufreq_global_kobject = kobject_create(); BUG_ON(!cpufreq_global_kobject); + register_syscore_ops(&cpufreq_syscore_ops); + return 0; } core_initcall(cpufreq_core_init); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 0cd9b4dcef99..5e370a30a964 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -18,7 +18,6 @@ static spinlock_t cpufreq_stats_lock; struct cpufreq_stats { - unsigned int cpu; unsigned int total_trans; unsigned long long last_time; unsigned int max_state; @@ -31,50 +30,33 @@ struct cpufreq_stats { #endif }; -static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table); - -struct cpufreq_stats_attribute { - struct attribute attr; - ssize_t(*show) (struct cpufreq_stats *, char *); -}; - -static int cpufreq_stats_update(unsigned int cpu) +static int cpufreq_stats_update(struct cpufreq_stats *stats) { - struct cpufreq_stats *stat; - unsigned long long cur_time; + unsigned long long cur_time = get_jiffies_64(); - cur_time = get_jiffies_64(); spin_lock(&cpufreq_stats_lock); - stat = per_cpu(cpufreq_stats_table, cpu); - if (stat->time_in_state) - stat->time_in_state[stat->last_index] += - cur_time - stat->last_time; - stat->last_time = cur_time; + stats->time_in_state[stats->last_index] += cur_time - stats->last_time; + stats->last_time = cur_time; spin_unlock(&cpufreq_stats_lock); return 0; } static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf) { - struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); - if (!stat) - return 0; - return sprintf(buf, "%d\n", - per_cpu(cpufreq_stats_table, stat->cpu)->total_trans); + return sprintf(buf, "%d\n", policy->stats->total_trans); } static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) { + struct cpufreq_stats *stats = policy->stats; ssize_t len = 0; int i; - struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); - if (!stat) - return 0; - cpufreq_stats_update(stat->cpu); - for (i = 0; i < stat->state_num; i++) { - len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i], + + cpufreq_stats_update(stats); + for (i = 0; i < stats->state_num; i++) { + len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i], (unsigned long long) - jiffies_64_to_clock_t(stat->time_in_state[i])); + jiffies_64_to_clock_t(stats->time_in_state[i])); } return len; } @@ -82,38 +64,35 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) #ifdef CONFIG_CPU_FREQ_STAT_DETAILS static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) { + struct cpufreq_stats *stats = policy->stats; ssize_t len = 0; int i, j; - struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); - if (!stat) - return 0; - cpufreq_stats_update(stat->cpu); len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); len += snprintf(buf + len, PAGE_SIZE - len, " : "); - for (i = 0; i < stat->state_num; i++) { + for (i = 0; i < stats->state_num; i++) { if (len >= PAGE_SIZE) break; len += snprintf(buf + len, PAGE_SIZE - len, "%9u ", - stat->freq_table[i]); + stats->freq_table[i]); } if (len >= PAGE_SIZE) return PAGE_SIZE; len += snprintf(buf + len, PAGE_SIZE - len, "\n"); - for (i = 0; i < stat->state_num; i++) { + for (i = 0; i < stats->state_num; i++) { if (len >= PAGE_SIZE) break; len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ", - stat->freq_table[i]); + stats->freq_table[i]); - for (j = 0; j < stat->state_num; j++) { + for (j = 0; j < stats->state_num; j++) { if (len >= PAGE_SIZE) break; len += snprintf(buf + len, PAGE_SIZE - len, "%9u ", - stat->trans_table[i*stat->max_state+j]); + stats->trans_table[i*stats->max_state+j]); } if (len >= PAGE_SIZE) break; @@ -142,28 +121,29 @@ static struct attribute_group stats_attr_group = { .name = "stats" }; -static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) +static int freq_table_get_index(struct cpufreq_stats *stats, unsigned int freq) { int index; - for (index = 0; index < stat->max_state; index++) - if (stat->freq_table[index] == freq) + for (index = 0; index < stats->max_state; index++) + if (stats->freq_table[index] == freq) return index; return -1; } static void __cpufreq_stats_free_table(struct cpufreq_policy *policy) { - struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); + struct cpufreq_stats *stats = policy->stats; - if (!stat) + /* Already freed */ + if (!stats) return; - pr_debug("%s: Free stat table\n", __func__); + pr_debug("%s: Free stats table\n", __func__); sysfs_remove_group(&policy->kobj, &stats_attr_group); - kfree(stat->time_in_state); - kfree(stat); - per_cpu(cpufreq_stats_table, policy->cpu) = NULL; + kfree(stats->time_in_state); + kfree(stats); + policy->stats = NULL; } static void cpufreq_stats_free_table(unsigned int cpu) @@ -174,37 +154,33 @@ static void cpufreq_stats_free_table(unsigned int cpu) if (!policy) return; - if (cpufreq_frequency_get_table(policy->cpu)) - __cpufreq_stats_free_table(policy); + __cpufreq_stats_free_table(policy); cpufreq_cpu_put(policy); } static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) { - unsigned int i, count = 0, ret = 0; - struct cpufreq_stats *stat; + unsigned int i = 0, count = 0, ret = -ENOMEM; + struct cpufreq_stats *stats; unsigned int alloc_size; unsigned int cpu = policy->cpu; struct cpufreq_frequency_table *pos, *table; + /* We need cpufreq table for creating stats table */ table = cpufreq_frequency_get_table(cpu); if (unlikely(!table)) return 0; - if (per_cpu(cpufreq_stats_table, cpu)) - return -EBUSY; - stat = kzalloc(sizeof(*stat), GFP_KERNEL); - if ((stat) == NULL) + /* stats already initialized */ + if (policy->stats) + return -EEXIST; + + stats = kzalloc(sizeof(*stats), GFP_KERNEL); + if (!stats) return -ENOMEM; - ret = sysfs_create_group(&policy->kobj, &stats_attr_group); - if (ret) - goto error_out; - - stat->cpu = cpu; - per_cpu(cpufreq_stats_table, cpu) = stat; - + /* Find total allocation size */ cpufreq_for_each_valid_entry(pos, table) count++; @@ -213,32 +189,40 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) #ifdef CONFIG_CPU_FREQ_STAT_DETAILS alloc_size += count * count * sizeof(int); #endif - stat->max_state = count; - stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL); - if (!stat->time_in_state) { - ret = -ENOMEM; - goto error_alloc; - } - stat->freq_table = (unsigned int *)(stat->time_in_state + count); + + /* Allocate memory for time_in_state/freq_table/trans_table in one go */ + stats->time_in_state = kzalloc(alloc_size, GFP_KERNEL); + if (!stats->time_in_state) + goto free_stat; + + stats->freq_table = (unsigned int *)(stats->time_in_state + count); #ifdef CONFIG_CPU_FREQ_STAT_DETAILS - stat->trans_table = stat->freq_table + count; + stats->trans_table = stats->freq_table + count; #endif - i = 0; + + stats->max_state = count; + + /* Find valid-unique entries */ cpufreq_for_each_valid_entry(pos, table) - if (freq_table_get_index(stat, pos->frequency) == -1) - stat->freq_table[i++] = pos->frequency; - stat->state_num = i; - spin_lock(&cpufreq_stats_lock); - stat->last_time = get_jiffies_64(); - stat->last_index = freq_table_get_index(stat, policy->cur); - spin_unlock(&cpufreq_stats_lock); - return 0; -error_alloc: - sysfs_remove_group(&policy->kobj, &stats_attr_group); -error_out: - kfree(stat); - per_cpu(cpufreq_stats_table, cpu) = NULL; + if (freq_table_get_index(stats, pos->frequency) == -1) + stats->freq_table[i++] = pos->frequency; + + stats->state_num = i; + stats->last_time = get_jiffies_64(); + stats->last_index = freq_table_get_index(stats, policy->cur); + + policy->stats = stats; + ret = sysfs_create_group(&policy->kobj, &stats_attr_group); + if (!ret) + return 0; + + /* We failed, release resources */ + policy->stats = NULL; + kfree(stats->time_in_state); +free_stat: + kfree(stats); + return ret; } @@ -259,30 +243,12 @@ static void cpufreq_stats_create_table(unsigned int cpu) cpufreq_cpu_put(policy); } -static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy) -{ - struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, - policy->last_cpu); - - pr_debug("Updating stats_table for new_cpu %u from last_cpu %u\n", - policy->cpu, policy->last_cpu); - per_cpu(cpufreq_stats_table, policy->cpu) = per_cpu(cpufreq_stats_table, - policy->last_cpu); - per_cpu(cpufreq_stats_table, policy->last_cpu) = NULL; - stat->cpu = policy->cpu; -} - static int cpufreq_stat_notifier_policy(struct notifier_block *nb, unsigned long val, void *data) { int ret = 0; struct cpufreq_policy *policy = data; - if (val == CPUFREQ_UPDATE_POLICY_CPU) { - cpufreq_stats_update_policy_cpu(policy); - return 0; - } - if (val == CPUFREQ_CREATE_POLICY) ret = __cpufreq_stats_create_table(policy); else if (val == CPUFREQ_REMOVE_POLICY) @@ -295,35 +261,45 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, unsigned long val, void *data) { struct cpufreq_freqs *freq = data; - struct cpufreq_stats *stat; + struct cpufreq_policy *policy = cpufreq_cpu_get(freq->cpu); + struct cpufreq_stats *stats; int old_index, new_index; + if (!policy) { + pr_err("%s: No policy found\n", __func__); + return 0; + } + if (val != CPUFREQ_POSTCHANGE) - return 0; + goto put_policy; - stat = per_cpu(cpufreq_stats_table, freq->cpu); - if (!stat) - return 0; + if (!policy->stats) { + pr_debug("%s: No stats found\n", __func__); + goto put_policy; + } - old_index = stat->last_index; - new_index = freq_table_get_index(stat, freq->new); + stats = policy->stats; - /* We can't do stat->time_in_state[-1]= .. */ + old_index = stats->last_index; + new_index = freq_table_get_index(stats, freq->new); + + /* We can't do stats->time_in_state[-1]= .. */ if (old_index == -1 || new_index == -1) - return 0; - - cpufreq_stats_update(freq->cpu); + goto put_policy; if (old_index == new_index) - return 0; + goto put_policy; - spin_lock(&cpufreq_stats_lock); - stat->last_index = new_index; + cpufreq_stats_update(stats); + + stats->last_index = new_index; #ifdef CONFIG_CPU_FREQ_STAT_DETAILS - stat->trans_table[old_index * stat->max_state + new_index]++; + stats->trans_table[old_index * stats->max_state + new_index]++; #endif - stat->total_trans++; - spin_unlock(&cpufreq_stats_lock); + stats->total_trans++; + +put_policy: + cpufreq_cpu_put(policy); return 0; } @@ -374,8 +350,7 @@ static void __exit cpufreq_stats_exit(void) } MODULE_AUTHOR("Zou Nan hai "); -MODULE_DESCRIPTION("'cpufreq_stats' - A driver to export cpufreq stats " - "through sysfs filesystem"); +MODULE_DESCRIPTION("Export cpufreq stats via sysfs"); MODULE_LICENSE("GPL"); module_init(cpufreq_stats_init); diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 742eefba12c2..872c5772c5d3 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -148,6 +148,8 @@ struct perf_limits { int32_t min_perf; int max_policy_pct; int max_sysfs_pct; + int min_policy_pct; + int min_sysfs_pct; }; static struct perf_limits limits = { @@ -159,6 +161,8 @@ static struct perf_limits limits = { .min_perf = 0, .max_policy_pct = 100, .max_sysfs_pct = 100, + .min_policy_pct = 0, + .min_sysfs_pct = 0, }; static inline void pid_reset(struct _pid *pid, int setpoint, int busy, @@ -338,6 +342,33 @@ static void __init intel_pstate_debug_expose_params(void) return sprintf(buf, "%u\n", limits.object); \ } +static ssize_t show_turbo_pct(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct cpudata *cpu; + int total, no_turbo, turbo_pct; + uint32_t turbo_fp; + + cpu = all_cpu_data[0]; + + total = cpu->pstate.turbo_pstate - cpu->pstate.min_pstate + 1; + no_turbo = cpu->pstate.max_pstate - cpu->pstate.min_pstate + 1; + turbo_fp = div_fp(int_tofp(no_turbo), int_tofp(total)); + turbo_pct = 100 - fp_toint(mul_fp(turbo_fp, int_tofp(100))); + return sprintf(buf, "%u\n", turbo_pct); +} + +static ssize_t show_num_pstates(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct cpudata *cpu; + int total; + + cpu = all_cpu_data[0]; + total = cpu->pstate.turbo_pstate - cpu->pstate.min_pstate + 1; + return sprintf(buf, "%u\n", total); +} + static ssize_t show_no_turbo(struct kobject *kobj, struct attribute *attr, char *buf) { @@ -404,7 +435,9 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b, ret = sscanf(buf, "%u", &input); if (ret != 1) return -EINVAL; - limits.min_perf_pct = clamp_t(int, input, 0 , 100); + + limits.min_sysfs_pct = clamp_t(int, input, 0 , 100); + limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct); limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100)); if (hwp_active) @@ -418,11 +451,15 @@ show_one(min_perf_pct, min_perf_pct); define_one_global_rw(no_turbo); define_one_global_rw(max_perf_pct); define_one_global_rw(min_perf_pct); +define_one_global_ro(turbo_pct); +define_one_global_ro(num_pstates); static struct attribute *intel_pstate_attributes[] = { &no_turbo.attr, &max_perf_pct.attr, &min_perf_pct.attr, + &turbo_pct.attr, + &num_pstates.attr, NULL }; @@ -825,6 +862,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = { ICPU(0x46, core_params), ICPU(0x47, core_params), ICPU(0x4c, byt_params), + ICPU(0x4e, core_params), ICPU(0x4f, core_params), ICPU(0x56, core_params), {} @@ -887,7 +925,9 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) if (!policy->cpuinfo.max_freq) return -ENODEV; - if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { + if (policy->policy == CPUFREQ_POLICY_PERFORMANCE && + policy->max >= policy->cpuinfo.max_freq) { + limits.min_policy_pct = 100; limits.min_perf_pct = 100; limits.min_perf = int_tofp(1); limits.max_policy_pct = 100; @@ -897,8 +937,9 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) return 0; } - limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq; - limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100); + limits.min_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq; + limits.min_policy_pct = clamp_t(int, limits.min_policy_pct, 0 , 100); + limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct); limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100)); limits.max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq; @@ -978,6 +1019,7 @@ static struct cpufreq_driver intel_pstate_driver = { static int __initdata no_load; static int __initdata no_hwp; +static int __initdata hwp_only; static unsigned int force_load; static int intel_pstate_msrs_not_valid(void) @@ -1175,6 +1217,9 @@ static int __init intel_pstate_init(void) if (cpu_has(c,X86_FEATURE_HWP) && !no_hwp) intel_pstate_hwp_enable(); + if (!hwp_active && hwp_only) + goto out; + rc = cpufreq_register_driver(&intel_pstate_driver); if (rc) goto out; @@ -1209,6 +1254,8 @@ static int __init intel_pstate_setup(char *str) no_hwp = 1; if (!strcmp(str, "force")) force_load = 1; + if (!strcmp(str, "hwp_only")) + hwp_only = 1; return 0; } early_param("intel_pstate", intel_pstate_setup); diff --git a/drivers/cpufreq/ls1x-cpufreq.c b/drivers/cpufreq/ls1x-cpufreq.c index 25fbd6a1374f..f0913eee2f50 100644 --- a/drivers/cpufreq/ls1x-cpufreq.c +++ b/drivers/cpufreq/ls1x-cpufreq.c @@ -210,7 +210,6 @@ out: static struct platform_driver ls1x_cpufreq_platdrv = { .driver = { .name = "ls1x-cpufreq", - .owner = THIS_MODULE, }, .probe = ls1x_cpufreq_probe, .remove = ls1x_cpufreq_remove, diff --git a/drivers/cpufreq/sfi-cpufreq.c b/drivers/cpufreq/sfi-cpufreq.c new file mode 100644 index 000000000000..ffa3389e535b --- /dev/null +++ b/drivers/cpufreq/sfi-cpufreq.c @@ -0,0 +1,136 @@ +/* + * SFI Performance States Driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * Author: Vishwesh M Rudramuni + * Author: Srinidhi Kasagar + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct cpufreq_frequency_table *freq_table; +static struct sfi_freq_table_entry *sfi_cpufreq_array; +static int num_freq_table_entries; + +static int sfi_parse_freq(struct sfi_table_header *table) +{ + struct sfi_table_simple *sb; + struct sfi_freq_table_entry *pentry; + int totallen; + + sb = (struct sfi_table_simple *)table; + num_freq_table_entries = SFI_GET_NUM_ENTRIES(sb, + struct sfi_freq_table_entry); + if (num_freq_table_entries <= 1) { + pr_err("No p-states discovered\n"); + return -ENODEV; + } + + pentry = (struct sfi_freq_table_entry *)sb->pentry; + totallen = num_freq_table_entries * sizeof(*pentry); + + sfi_cpufreq_array = kzalloc(totallen, GFP_KERNEL); + if (!sfi_cpufreq_array) + return -ENOMEM; + + memcpy(sfi_cpufreq_array, pentry, totallen); + + return 0; +} + +static int sfi_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) +{ + unsigned int next_perf_state = 0; /* Index into perf table */ + u32 lo, hi; + + next_perf_state = policy->freq_table[index].driver_data; + + rdmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, &lo, &hi); + lo = (lo & ~INTEL_PERF_CTL_MASK) | + ((u32) sfi_cpufreq_array[next_perf_state].ctrl_val & + INTEL_PERF_CTL_MASK); + wrmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, lo, hi); + + return 0; +} + +static int sfi_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + policy->shared_type = CPUFREQ_SHARED_TYPE_HW; + policy->cpuinfo.transition_latency = 100000; /* 100us */ + + return cpufreq_table_validate_and_show(policy, freq_table); +} + +static struct cpufreq_driver sfi_cpufreq_driver = { + .flags = CPUFREQ_CONST_LOOPS, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = sfi_cpufreq_target, + .init = sfi_cpufreq_cpu_init, + .name = "sfi-cpufreq", + .attr = cpufreq_generic_attr, +}; + +static int __init sfi_cpufreq_init(void) +{ + int ret, i; + + /* parse the freq table from SFI */ + ret = sfi_table_parse(SFI_SIG_FREQ, NULL, NULL, sfi_parse_freq); + if (ret) + return ret; + + freq_table = kzalloc(sizeof(*freq_table) * + (num_freq_table_entries + 1), GFP_KERNEL); + if (!freq_table) { + ret = -ENOMEM; + goto err_free_array; + } + + for (i = 0; i < num_freq_table_entries; i++) { + freq_table[i].driver_data = i; + freq_table[i].frequency = sfi_cpufreq_array[i].freq_mhz * 1000; + } + freq_table[i].frequency = CPUFREQ_TABLE_END; + + ret = cpufreq_register_driver(&sfi_cpufreq_driver); + if (ret) + goto err_free_tbl; + + return ret; + +err_free_tbl: + kfree(freq_table); +err_free_array: + kfree(sfi_cpufreq_array); + return ret; +} +late_initcall(sfi_cpufreq_init); + +static void __exit sfi_cpufreq_exit(void) +{ + cpufreq_unregister_driver(&sfi_cpufreq_driver); + kfree(freq_table); + kfree(sfi_cpufreq_array); +} +module_exit(sfi_cpufreq_exit); + +MODULE_AUTHOR("Vishwesh M Rudramuni "); +MODULE_DESCRIPTION("SFI Performance-States Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/cpuidle/Kconfig.arm64 b/drivers/cpuidle/Kconfig.arm64 index d0a08ed1b2ee..6effb3656735 100644 --- a/drivers/cpuidle/Kconfig.arm64 +++ b/drivers/cpuidle/Kconfig.arm64 @@ -4,7 +4,6 @@ config ARM64_CPUIDLE bool "Generic ARM64 CPU idle Driver" - select ARM64_CPU_SUSPEND select DT_IDLE_STATES help Select this to enable generic cpuidle driver for ARM64. diff --git a/drivers/cpuidle/cpuidle-arm64.c b/drivers/cpuidle/cpuidle-arm64.c index 80704b931ba4..39a2c62716c3 100644 --- a/drivers/cpuidle/cpuidle-arm64.c +++ b/drivers/cpuidle/cpuidle-arm64.c @@ -19,7 +19,6 @@ #include #include -#include #include "dt_idle_states.h" diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c index e3e225fe6b45..40c34faffe59 100644 --- a/drivers/cpuidle/cpuidle-big_little.c +++ b/drivers/cpuidle/cpuidle-big_little.c @@ -182,6 +182,10 @@ static int __init bl_idle_init(void) */ if (!of_match_node(compatible_machine_match, root)) return -ENODEV; + + if (!mcpm_is_available()) + return -EUNATCH; + /* * For now the differentiation between little and big cores * is based on the part number. A7 cores are considered little diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index faf4e70c42e0..64281bb2f650 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -1,5 +1,6 @@ menuconfig PM_DEVFREQ bool "Generic Dynamic Voltage and Frequency Scaling (DVFS) support" + select SRCU help A device may have a list of frequencies and voltages available. devfreq, a generic DVFS framework can be registered for a device @@ -87,4 +88,16 @@ config ARM_EXYNOS5_BUS_DEVFREQ It reads PPMU counters of memory controllers and adjusts the operating frequencies and voltages with OPP support. +config ARM_TEGRA_DEVFREQ + tristate "Tegra DEVFREQ Driver" + depends on ARCH_TEGRA_124_SOC + select DEVFREQ_GOV_SIMPLE_ONDEMAND + select PM_OPP + help + This adds the DEVFREQ driver for the Tegra family of SoCs. + It reads ACTMON counters of memory controllers and adjusts the + operating frequencies and voltages with OPP support. + +source "drivers/devfreq/event/Kconfig" + endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 16138c9e0d58..5134f9ee983d 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_PM_DEVFREQ) += devfreq.o +obj-$(CONFIG_PM_DEVFREQ_EVENT) += devfreq-event.o obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) += governor_simpleondemand.o obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE) += governor_performance.o obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o @@ -7,3 +8,7 @@ obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o # DEVFREQ Drivers obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos/ obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos/ +obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o + +# DEVFREQ Event Drivers +obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ diff --git a/drivers/devfreq/devfreq-event.c b/drivers/devfreq/devfreq-event.c new file mode 100644 index 000000000000..f304a0289eda --- /dev/null +++ b/drivers/devfreq/devfreq-event.c @@ -0,0 +1,494 @@ +/* + * devfreq-event: a framework to provide raw data and events of devfreq devices + * + * Copyright (C) 2015 Samsung Electronics + * Author: Chanwoo Choi + * + * This 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 driver is based on drivers/devfreq/devfreq.c. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct class *devfreq_event_class; + +/* The list of all devfreq event list */ +static LIST_HEAD(devfreq_event_list); +static DEFINE_MUTEX(devfreq_event_list_lock); + +#define to_devfreq_event(DEV) container_of(DEV, struct devfreq_event_dev, dev) + +/** + * devfreq_event_enable_edev() - Enable the devfreq-event dev and increase + * the enable_count of devfreq-event dev. + * @edev : the devfreq-event device + * + * Note that this function increase the enable_count and enable the + * devfreq-event device. The devfreq-event device should be enabled before + * using it by devfreq device. + */ +int devfreq_event_enable_edev(struct devfreq_event_dev *edev) +{ + int ret = 0; + + if (!edev || !edev->desc) + return -EINVAL; + + mutex_lock(&edev->lock); + if (edev->desc->ops && edev->desc->ops->enable + && edev->enable_count == 0) { + ret = edev->desc->ops->enable(edev); + if (ret < 0) + goto err; + } + edev->enable_count++; +err: + mutex_unlock(&edev->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(devfreq_event_enable_edev); + +/** + * devfreq_event_disable_edev() - Disable the devfreq-event dev and decrease + * the enable_count of the devfreq-event dev. + * @edev : the devfreq-event device + * + * Note that this function decrease the enable_count and disable the + * devfreq-event device. After the devfreq-event device is disabled, + * devfreq device can't use the devfreq-event device for get/set/reset + * operations. + */ +int devfreq_event_disable_edev(struct devfreq_event_dev *edev) +{ + int ret = 0; + + if (!edev || !edev->desc) + return -EINVAL; + + mutex_lock(&edev->lock); + if (edev->enable_count <= 0) { + dev_warn(&edev->dev, "unbalanced enable_count\n"); + ret = -EIO; + goto err; + } + + if (edev->desc->ops && edev->desc->ops->disable + && edev->enable_count == 1) { + ret = edev->desc->ops->disable(edev); + if (ret < 0) + goto err; + } + edev->enable_count--; +err: + mutex_unlock(&edev->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(devfreq_event_disable_edev); + +/** + * devfreq_event_is_enabled() - Check whether devfreq-event dev is enabled or + * not. + * @edev : the devfreq-event device + * + * Note that this function check whether devfreq-event dev is enabled or not. + * If return true, the devfreq-event dev is enabeld. If return false, the + * devfreq-event dev is disabled. + */ +bool devfreq_event_is_enabled(struct devfreq_event_dev *edev) +{ + bool enabled = false; + + if (!edev || !edev->desc) + return enabled; + + mutex_lock(&edev->lock); + + if (edev->enable_count > 0) + enabled = true; + + mutex_unlock(&edev->lock); + + return enabled; +} +EXPORT_SYMBOL_GPL(devfreq_event_is_enabled); + +/** + * devfreq_event_set_event() - Set event to devfreq-event dev to start. + * @edev : the devfreq-event device + * + * Note that this function set the event to the devfreq-event device to start + * for getting the event data which could be various event type. + */ +int devfreq_event_set_event(struct devfreq_event_dev *edev) +{ + int ret; + + if (!edev || !edev->desc) + return -EINVAL; + + if (!edev->desc->ops || !edev->desc->ops->set_event) + return -EINVAL; + + if (!devfreq_event_is_enabled(edev)) + return -EPERM; + + mutex_lock(&edev->lock); + ret = edev->desc->ops->set_event(edev); + mutex_unlock(&edev->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(devfreq_event_set_event); + +/** + * devfreq_event_get_event() - Get {load|total}_count from devfreq-event dev. + * @edev : the devfreq-event device + * @edata : the calculated data of devfreq-event device + * + * Note that this function get the calculated event data from devfreq-event dev + * after stoping the progress of whole sequence of devfreq-event dev. + */ +int devfreq_event_get_event(struct devfreq_event_dev *edev, + struct devfreq_event_data *edata) +{ + int ret; + + if (!edev || !edev->desc) + return -EINVAL; + + if (!edev->desc->ops || !edev->desc->ops->get_event) + return -EINVAL; + + if (!devfreq_event_is_enabled(edev)) + return -EINVAL; + + edata->total_count = edata->load_count = 0; + + mutex_lock(&edev->lock); + ret = edev->desc->ops->get_event(edev, edata); + if (ret < 0) + edata->total_count = edata->load_count = 0; + mutex_unlock(&edev->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(devfreq_event_get_event); + +/** + * devfreq_event_reset_event() - Reset all opeations of devfreq-event dev. + * @edev : the devfreq-event device + * + * Note that this function stop all operations of devfreq-event dev and reset + * the current event data to make the devfreq-event device into initial state. + */ +int devfreq_event_reset_event(struct devfreq_event_dev *edev) +{ + int ret = 0; + + if (!edev || !edev->desc) + return -EINVAL; + + if (!devfreq_event_is_enabled(edev)) + return -EPERM; + + mutex_lock(&edev->lock); + if (edev->desc->ops && edev->desc->ops->reset) + ret = edev->desc->ops->reset(edev); + mutex_unlock(&edev->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(devfreq_event_reset_event); + +/** + * devfreq_event_get_edev_by_phandle() - Get the devfreq-event dev from + * devicetree. + * @dev : the pointer to the given device + * @index : the index into list of devfreq-event device + * + * Note that this function return the pointer of devfreq-event device. + */ +struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(struct device *dev, + int index) +{ + struct device_node *node; + struct devfreq_event_dev *edev; + + if (!dev->of_node) { + dev_err(dev, "device does not have a device node entry\n"); + return ERR_PTR(-EINVAL); + } + + node = of_parse_phandle(dev->of_node, "devfreq-events", index); + if (!node) { + dev_err(dev, "failed to get phandle in %s node\n", + dev->of_node->full_name); + return ERR_PTR(-ENODEV); + } + + mutex_lock(&devfreq_event_list_lock); + list_for_each_entry(edev, &devfreq_event_list, node) { + if (!strcmp(edev->desc->name, node->name)) + goto out; + } + edev = NULL; +out: + mutex_unlock(&devfreq_event_list_lock); + + if (!edev) { + dev_err(dev, "unable to get devfreq-event device : %s\n", + node->name); + of_node_put(node); + return ERR_PTR(-ENODEV); + } + + of_node_put(node); + + return edev; +} +EXPORT_SYMBOL_GPL(devfreq_event_get_edev_by_phandle); + +/** + * devfreq_event_get_edev_count() - Get the count of devfreq-event dev + * @dev : the pointer to the given device + * + * Note that this function return the count of devfreq-event devices. + */ +int devfreq_event_get_edev_count(struct device *dev) +{ + int count; + + if (!dev->of_node) { + dev_err(dev, "device does not have a device node entry\n"); + return -EINVAL; + } + + count = of_property_count_elems_of_size(dev->of_node, "devfreq-events", + sizeof(u32)); + if (count < 0 ) { + dev_err(dev, + "failed to get the count of devfreq-event in %s node\n", + dev->of_node->full_name); + return count; + } + + return count; +} +EXPORT_SYMBOL_GPL(devfreq_event_get_edev_count); + +static void devfreq_event_release_edev(struct device *dev) +{ + struct devfreq_event_dev *edev = to_devfreq_event(dev); + + kfree(edev); +} + +/** + * devfreq_event_add_edev() - Add new devfreq-event device. + * @dev : the device owning the devfreq-event device being created + * @desc : the devfreq-event device's decriptor which include essential + * data for devfreq-event device. + * + * Note that this function add new devfreq-event device to devfreq-event class + * list and register the device of the devfreq-event device. + */ +struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev, + struct devfreq_event_desc *desc) +{ + struct devfreq_event_dev *edev; + static atomic_t event_no = ATOMIC_INIT(0); + int ret; + + if (!dev || !desc) + return ERR_PTR(-EINVAL); + + if (!desc->name || !desc->ops) + return ERR_PTR(-EINVAL); + + if (!desc->ops->set_event || !desc->ops->get_event) + return ERR_PTR(-EINVAL); + + edev = kzalloc(sizeof(struct devfreq_event_dev), GFP_KERNEL); + if (!edev) + return ERR_PTR(-ENOMEM); + + mutex_init(&edev->lock); + edev->desc = desc; + edev->enable_count = 0; + edev->dev.parent = dev; + edev->dev.class = devfreq_event_class; + edev->dev.release = devfreq_event_release_edev; + + dev_set_name(&edev->dev, "event.%d", atomic_inc_return(&event_no) - 1); + ret = device_register(&edev->dev); + if (ret < 0) { + put_device(&edev->dev); + return ERR_PTR(ret); + } + dev_set_drvdata(&edev->dev, edev); + + INIT_LIST_HEAD(&edev->node); + + mutex_lock(&devfreq_event_list_lock); + list_add(&edev->node, &devfreq_event_list); + mutex_unlock(&devfreq_event_list_lock); + + return edev; +} +EXPORT_SYMBOL_GPL(devfreq_event_add_edev); + +/** + * devfreq_event_remove_edev() - Remove the devfreq-event device registered. + * @dev : the devfreq-event device + * + * Note that this function remove the registered devfreq-event device. + */ +int devfreq_event_remove_edev(struct devfreq_event_dev *edev) +{ + if (!edev) + return -EINVAL; + + WARN_ON(edev->enable_count); + + mutex_lock(&devfreq_event_list_lock); + list_del(&edev->node); + mutex_unlock(&devfreq_event_list_lock); + + device_unregister(&edev->dev); + + return 0; +} +EXPORT_SYMBOL_GPL(devfreq_event_remove_edev); + +static int devm_devfreq_event_match(struct device *dev, void *res, void *data) +{ + struct devfreq_event_dev **r = res; + + if (WARN_ON(!r || !*r)) + return 0; + + return *r == data; +} + +static void devm_devfreq_event_release(struct device *dev, void *res) +{ + devfreq_event_remove_edev(*(struct devfreq_event_dev **)res); +} + +/** + * devm_devfreq_event_add_edev() - Resource-managed devfreq_event_add_edev() + * @dev : the device owning the devfreq-event device being created + * @desc : the devfreq-event device's decriptor which include essential + * data for devfreq-event device. + * + * Note that this function manages automatically the memory of devfreq-event + * device using device resource management and simplify the free operation + * for memory of devfreq-event device. + */ +struct devfreq_event_dev *devm_devfreq_event_add_edev(struct device *dev, + struct devfreq_event_desc *desc) +{ + struct devfreq_event_dev **ptr, *edev; + + ptr = devres_alloc(devm_devfreq_event_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + edev = devfreq_event_add_edev(dev, desc); + if (IS_ERR(edev)) { + devres_free(ptr); + return ERR_PTR(-ENOMEM); + } + + *ptr = edev; + devres_add(dev, ptr); + + return edev; +} +EXPORT_SYMBOL_GPL(devm_devfreq_event_add_edev); + +/** + * devm_devfreq_event_remove_edev()- Resource-managed devfreq_event_remove_edev() + * @dev : the device owning the devfreq-event device being created + * @edev : the devfreq-event device + * + * Note that this function manages automatically the memory of devfreq-event + * device using device resource management. + */ +void devm_devfreq_event_remove_edev(struct device *dev, + struct devfreq_event_dev *edev) +{ + WARN_ON(devres_release(dev, devm_devfreq_event_release, + devm_devfreq_event_match, edev)); +} +EXPORT_SYMBOL_GPL(devm_devfreq_event_remove_edev); + +/* + * Device attributes for devfreq-event class. + */ +static ssize_t name_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct devfreq_event_dev *edev = to_devfreq_event(dev); + + if (!edev || !edev->desc) + return -EINVAL; + + return sprintf(buf, "%s\n", edev->desc->name); +} +static DEVICE_ATTR_RO(name); + +static ssize_t enable_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct devfreq_event_dev *edev = to_devfreq_event(dev); + + if (!edev || !edev->desc) + return -EINVAL; + + return sprintf(buf, "%d\n", edev->enable_count); +} +static DEVICE_ATTR_RO(enable_count); + +static struct attribute *devfreq_event_attrs[] = { + &dev_attr_name.attr, + &dev_attr_enable_count.attr, + NULL, +}; +ATTRIBUTE_GROUPS(devfreq_event); + +static int __init devfreq_event_init(void) +{ + devfreq_event_class = class_create(THIS_MODULE, "devfreq-event"); + if (IS_ERR(devfreq_event_class)) { + pr_err("%s: couldn't create class\n", __FILE__); + return PTR_ERR(devfreq_event_class); + } + + devfreq_event_class->dev_groups = devfreq_event_groups; + + return 0; +} +subsys_initcall(devfreq_event_init); + +static void __exit devfreq_event_exit(void) +{ + class_destroy(devfreq_event_class); +} +module_exit(devfreq_event_exit); + +MODULE_AUTHOR("Chanwoo Choi "); +MODULE_DESCRIPTION("DEVFREQ-Event class support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig new file mode 100644 index 000000000000..a11720affc31 --- /dev/null +++ b/drivers/devfreq/event/Kconfig @@ -0,0 +1,25 @@ +menuconfig PM_DEVFREQ_EVENT + bool "DEVFREQ-Event device Support" + help + The devfreq-event device provide the raw data and events which + indicate the current state of devfreq-event device. The provided + data from devfreq-event device is used to monitor the state of + device and determine the suitable size of resource to reduce the + wasted resource. + + The devfreq-event device can support the various type of events + (e.g., raw data, utilization, latency, bandwidth). The events + may be used by devfreq governor and other subsystem. + +if PM_DEVFREQ_EVENT + +config DEVFREQ_EVENT_EXYNOS_PPMU + bool "EXYNOS PPMU (Platform Performance Monitoring Unit) DEVFREQ event Driver" + depends on ARCH_EXYNOS + select PM_OPP + help + This add the devfreq-event driver for Exynos SoC. It provides PPMU + (Platform Performance Monitoring Unit) counters to estimate the + utilization of each module. + +endif # PM_DEVFREQ_EVENT diff --git a/drivers/devfreq/event/Makefile b/drivers/devfreq/event/Makefile new file mode 100644 index 000000000000..be146ead79cf --- /dev/null +++ b/drivers/devfreq/event/Makefile @@ -0,0 +1,2 @@ +# Exynos DEVFREQ Event Drivers +obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU) += exynos-ppmu.o diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c new file mode 100644 index 000000000000..135be0aada9d --- /dev/null +++ b/drivers/devfreq/event/exynos-ppmu.c @@ -0,0 +1,374 @@ +/* + * exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Author : Chanwoo Choi + * + * This 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 driver is based on drivers/devfreq/exynos/exynos_ppmu.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "exynos-ppmu.h" + +struct exynos_ppmu_data { + void __iomem *base; + struct clk *clk; +}; + +struct exynos_ppmu { + struct devfreq_event_dev **edev; + struct devfreq_event_desc *desc; + unsigned int num_events; + + struct device *dev; + struct mutex lock; + + struct exynos_ppmu_data ppmu; +}; + +#define PPMU_EVENT(name) \ + { "ppmu-event0-"#name, PPMU_PMNCNT0 }, \ + { "ppmu-event1-"#name, PPMU_PMNCNT1 }, \ + { "ppmu-event2-"#name, PPMU_PMNCNT2 }, \ + { "ppmu-event3-"#name, PPMU_PMNCNT3 } + +struct __exynos_ppmu_events { + char *name; + int id; +} ppmu_events[] = { + /* For Exynos3250, Exynos4 and Exynos5260 */ + PPMU_EVENT(g3d), + PPMU_EVENT(fsys), + + /* For Exynos4 SoCs and Exynos3250 */ + PPMU_EVENT(dmc0), + PPMU_EVENT(dmc1), + PPMU_EVENT(cpu), + PPMU_EVENT(rightbus), + PPMU_EVENT(leftbus), + PPMU_EVENT(lcd0), + PPMU_EVENT(camif), + + /* Only for Exynos3250 and Exynos5260 */ + PPMU_EVENT(mfc), + + /* Only for Exynos4 SoCs */ + PPMU_EVENT(mfc-left), + PPMU_EVENT(mfc-right), + + /* Only for Exynos5260 SoCs */ + PPMU_EVENT(drex0-s0), + PPMU_EVENT(drex0-s1), + PPMU_EVENT(drex1-s0), + PPMU_EVENT(drex1-s1), + PPMU_EVENT(eagle), + PPMU_EVENT(kfc), + PPMU_EVENT(isp), + PPMU_EVENT(fimc), + PPMU_EVENT(gscl), + PPMU_EVENT(mscl), + PPMU_EVENT(fimd0x), + PPMU_EVENT(fimd1x), + { /* sentinel */ }, +}; + +static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) + if (!strcmp(edev->desc->name, ppmu_events[i].name)) + return ppmu_events[i].id; + + return -EINVAL; +} + +static int exynos_ppmu_disable(struct devfreq_event_dev *edev) +{ + struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + u32 pmnc; + + /* Disable all counters */ + __raw_writel(PPMU_CCNT_MASK | + PPMU_PMCNT0_MASK | + PPMU_PMCNT1_MASK | + PPMU_PMCNT2_MASK | + PPMU_PMCNT3_MASK, + info->ppmu.base + PPMU_CNTENC); + + /* Disable PPMU */ + pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); + pmnc &= ~PPMU_PMNC_ENABLE_MASK; + __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); + + return 0; +} + +static int exynos_ppmu_set_event(struct devfreq_event_dev *edev) +{ + struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + int id = exynos_ppmu_find_ppmu_id(edev); + u32 pmnc, cntens; + + if (id < 0) + return id; + + /* Enable specific counter */ + cntens = __raw_readl(info->ppmu.base + PPMU_CNTENS); + cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); + __raw_writel(cntens, info->ppmu.base + PPMU_CNTENS); + + /* Set the event of Read/Write data count */ + __raw_writel(PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT, + info->ppmu.base + PPMU_BEVTxSEL(id)); + + /* Reset cycle counter/performance counter and enable PPMU */ + pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); + pmnc &= ~(PPMU_PMNC_ENABLE_MASK + | PPMU_PMNC_COUNTER_RESET_MASK + | PPMU_PMNC_CC_RESET_MASK); + pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT); + pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); + pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); + __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); + + return 0; +} + +static int exynos_ppmu_get_event(struct devfreq_event_dev *edev, + struct devfreq_event_data *edata) +{ + struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + int id = exynos_ppmu_find_ppmu_id(edev); + u32 pmnc, cntenc; + + if (id < 0) + return -EINVAL; + + /* Disable PPMU */ + pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); + pmnc &= ~PPMU_PMNC_ENABLE_MASK; + __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); + + /* Read cycle count */ + edata->total_count = __raw_readl(info->ppmu.base + PPMU_CCNT); + + /* Read performance count */ + switch (id) { + case PPMU_PMNCNT0: + case PPMU_PMNCNT1: + case PPMU_PMNCNT2: + edata->load_count + = __raw_readl(info->ppmu.base + PPMU_PMNCT(id)); + break; + case PPMU_PMNCNT3: + edata->load_count = + ((__raw_readl(info->ppmu.base + PPMU_PMCNT3_HIGH) << 8) + | __raw_readl(info->ppmu.base + PPMU_PMCNT3_LOW)); + break; + default: + return -EINVAL; + } + + /* Disable specific counter */ + cntenc = __raw_readl(info->ppmu.base + PPMU_CNTENC); + cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); + __raw_writel(cntenc, info->ppmu.base + PPMU_CNTENC); + + dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name, + edata->load_count, edata->total_count); + + return 0; +} + +static struct devfreq_event_ops exynos_ppmu_ops = { + .disable = exynos_ppmu_disable, + .set_event = exynos_ppmu_set_event, + .get_event = exynos_ppmu_get_event, +}; + +static int of_get_devfreq_events(struct device_node *np, + struct exynos_ppmu *info) +{ + struct devfreq_event_desc *desc; + struct device *dev = info->dev; + struct device_node *events_np, *node; + int i, j, count; + + events_np = of_get_child_by_name(np, "events"); + if (!events_np) { + dev_err(dev, + "failed to get child node of devfreq-event devices\n"); + return -EINVAL; + } + + count = of_get_child_count(events_np); + desc = devm_kzalloc(dev, sizeof(*desc) * count, GFP_KERNEL); + if (!desc) + return -ENOMEM; + info->num_events = count; + + j = 0; + for_each_child_of_node(events_np, node) { + for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) { + if (!ppmu_events[i].name) + continue; + + if (!of_node_cmp(node->name, ppmu_events[i].name)) + break; + } + + if (i == ARRAY_SIZE(ppmu_events)) { + dev_warn(dev, + "don't know how to configure events : %s\n", + node->name); + continue; + } + + desc[j].ops = &exynos_ppmu_ops; + desc[j].driver_data = info; + + of_property_read_string(node, "event-name", &desc[j].name); + + j++; + + of_node_put(node); + } + info->desc = desc; + + of_node_put(events_np); + + return 0; +} + +static int exynos_ppmu_parse_dt(struct exynos_ppmu *info) +{ + struct device *dev = info->dev; + struct device_node *np = dev->of_node; + int ret = 0; + + if (!np) { + dev_err(dev, "failed to find devicetree node\n"); + return -EINVAL; + } + + /* Maps the memory mapped IO to control PPMU register */ + info->ppmu.base = of_iomap(np, 0); + if (IS_ERR_OR_NULL(info->ppmu.base)) { + dev_err(dev, "failed to map memory region\n"); + return -ENOMEM; + } + + info->ppmu.clk = devm_clk_get(dev, "ppmu"); + if (IS_ERR(info->ppmu.clk)) { + info->ppmu.clk = NULL; + dev_warn(dev, "cannot get PPMU clock\n"); + } + + ret = of_get_devfreq_events(np, info); + if (ret < 0) { + dev_err(dev, "failed to parse exynos ppmu dt node\n"); + goto err; + } + + return 0; + +err: + iounmap(info->ppmu.base); + + return ret; +} + +static int exynos_ppmu_probe(struct platform_device *pdev) +{ + struct exynos_ppmu *info; + struct devfreq_event_dev **edev; + struct devfreq_event_desc *desc; + int i, ret = 0, size; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + mutex_init(&info->lock); + info->dev = &pdev->dev; + + /* Parse dt data to get resource */ + ret = exynos_ppmu_parse_dt(info); + if (ret < 0) { + dev_err(&pdev->dev, + "failed to parse devicetree for resource\n"); + return ret; + } + desc = info->desc; + + size = sizeof(struct devfreq_event_dev *) * info->num_events; + info->edev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!info->edev) { + dev_err(&pdev->dev, + "failed to allocate memory devfreq-event devices\n"); + return -ENOMEM; + } + edev = info->edev; + platform_set_drvdata(pdev, info); + + for (i = 0; i < info->num_events; i++) { + edev[i] = devm_devfreq_event_add_edev(&pdev->dev, &desc[i]); + if (IS_ERR(edev)) { + ret = PTR_ERR(edev); + dev_err(&pdev->dev, + "failed to add devfreq-event device\n"); + goto err; + } + } + + clk_prepare_enable(info->ppmu.clk); + + return 0; +err: + iounmap(info->ppmu.base); + + return ret; +} + +static int exynos_ppmu_remove(struct platform_device *pdev) +{ + struct exynos_ppmu *info = platform_get_drvdata(pdev); + + clk_disable_unprepare(info->ppmu.clk); + iounmap(info->ppmu.base); + + return 0; +} + +static struct of_device_id exynos_ppmu_id_match[] = { + { .compatible = "samsung,exynos-ppmu", }, + { /* sentinel */ }, +}; + +static struct platform_driver exynos_ppmu_driver = { + .probe = exynos_ppmu_probe, + .remove = exynos_ppmu_remove, + .driver = { + .name = "exynos-ppmu", + .of_match_table = exynos_ppmu_id_match, + }, +}; +module_platform_driver(exynos_ppmu_driver); + +MODULE_DESCRIPTION("Exynos PPMU(Platform Performance Monitoring Unit) driver"); +MODULE_AUTHOR("Chanwoo Choi "); +MODULE_LICENSE("GPL"); diff --git a/drivers/devfreq/event/exynos-ppmu.h b/drivers/devfreq/event/exynos-ppmu.h new file mode 100644 index 000000000000..4e831d48c138 --- /dev/null +++ b/drivers/devfreq/event/exynos-ppmu.h @@ -0,0 +1,93 @@ +/* + * exynos_ppmu.h - EXYNOS PPMU header file + * + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Author : Chanwoo Choi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __EXYNOS_PPMU_H__ +#define __EXYNOS_PPMU_H__ + +enum ppmu_state { + PPMU_DISABLE = 0, + PPMU_ENABLE, +}; + +enum ppmu_counter { + PPMU_PMNCNT0 = 0, + PPMU_PMNCNT1, + PPMU_PMNCNT2, + PPMU_PMNCNT3, + + PPMU_PMNCNT_MAX, +}; + +enum ppmu_event_type { + PPMU_RO_BUSY_CYCLE_CNT = 0x0, + PPMU_WO_BUSY_CYCLE_CNT = 0x1, + PPMU_RW_BUSY_CYCLE_CNT = 0x2, + PPMU_RO_REQUEST_CNT = 0x3, + PPMU_WO_REQUEST_CNT = 0x4, + PPMU_RO_DATA_CNT = 0x5, + PPMU_WO_DATA_CNT = 0x6, + PPMU_RO_LATENCY = 0x12, + PPMU_WO_LATENCY = 0x16, +}; + +enum ppmu_reg { + /* PPC control register */ + PPMU_PMNC = 0x00, + PPMU_CNTENS = 0x10, + PPMU_CNTENC = 0x20, + PPMU_INTENS = 0x30, + PPMU_INTENC = 0x40, + PPMU_FLAG = 0x50, + + /* Cycle Counter and Performance Event Counter Register */ + PPMU_CCNT = 0x100, + PPMU_PMCNT0 = 0x110, + PPMU_PMCNT1 = 0x120, + PPMU_PMCNT2 = 0x130, + PPMU_PMCNT3_HIGH = 0x140, + PPMU_PMCNT3_LOW = 0x150, + + /* Bus Event Generator */ + PPMU_BEVT0SEL = 0x1000, + PPMU_BEVT1SEL = 0x1100, + PPMU_BEVT2SEL = 0x1200, + PPMU_BEVT3SEL = 0x1300, + PPMU_COUNTER_RESET = 0x1810, + PPMU_READ_OVERFLOW_CNT = 0x1810, + PPMU_READ_UNDERFLOW_CNT = 0x1814, + PPMU_WRITE_OVERFLOW_CNT = 0x1850, + PPMU_WRITE_UNDERFLOW_CNT = 0x1854, + PPMU_READ_PENDING_CNT = 0x1880, + PPMU_WRITE_PENDING_CNT = 0x1884 +}; + +/* PMNC register */ +#define PPMU_PMNC_CC_RESET_SHIFT 2 +#define PPMU_PMNC_COUNTER_RESET_SHIFT 1 +#define PPMU_PMNC_ENABLE_SHIFT 0 +#define PPMU_PMNC_START_MODE_MASK BIT(16) +#define PPMU_PMNC_CC_DIVIDER_MASK BIT(3) +#define PPMU_PMNC_CC_RESET_MASK BIT(2) +#define PPMU_PMNC_COUNTER_RESET_MASK BIT(1) +#define PPMU_PMNC_ENABLE_MASK BIT(0) + +/* CNTENS/CNTENC/INTENS/INTENC/FLAG register */ +#define PPMU_CCNT_MASK BIT(31) +#define PPMU_PMCNT3_MASK BIT(3) +#define PPMU_PMCNT2_MASK BIT(2) +#define PPMU_PMCNT1_MASK BIT(1) +#define PPMU_PMCNT0_MASK BIT(0) + +/* PPMU_PMNCTx/PPMU_BETxSEL registers */ +#define PPMU_PMNCT(x) (PPMU_PMCNT0 + (0x10 * x)) +#define PPMU_BEVTxSEL(x) (PPMU_BEVT0SEL + (0x100 * x)) + +#endif /* __EXYNOS_PPMU_H__ */ diff --git a/drivers/devfreq/tegra-devfreq.c b/drivers/devfreq/tegra-devfreq.c new file mode 100644 index 000000000000..34790961af5a --- /dev/null +++ b/drivers/devfreq/tegra-devfreq.c @@ -0,0 +1,718 @@ +/* + * A devfreq driver for NVIDIA Tegra SoCs + * + * Copyright (c) 2014 NVIDIA CORPORATION. All rights reserved. + * Copyright (C) 2014 Google, 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, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "governor.h" + +#define ACTMON_GLB_STATUS 0x0 +#define ACTMON_GLB_PERIOD_CTRL 0x4 + +#define ACTMON_DEV_CTRL 0x0 +#define ACTMON_DEV_CTRL_K_VAL_SHIFT 10 +#define ACTMON_DEV_CTRL_ENB_PERIODIC BIT(18) +#define ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN BIT(20) +#define ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN BIT(21) +#define ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_NUM_SHIFT 23 +#define ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_NUM_SHIFT 26 +#define ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN BIT(29) +#define ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN BIT(30) +#define ACTMON_DEV_CTRL_ENB BIT(31) + +#define ACTMON_DEV_UPPER_WMARK 0x4 +#define ACTMON_DEV_LOWER_WMARK 0x8 +#define ACTMON_DEV_INIT_AVG 0xc +#define ACTMON_DEV_AVG_UPPER_WMARK 0x10 +#define ACTMON_DEV_AVG_LOWER_WMARK 0x14 +#define ACTMON_DEV_COUNT_WEIGHT 0x18 +#define ACTMON_DEV_AVG_COUNT 0x20 +#define ACTMON_DEV_INTR_STATUS 0x24 + +#define ACTMON_INTR_STATUS_CLEAR 0xffffffff + +#define ACTMON_DEV_INTR_CONSECUTIVE_UPPER BIT(31) +#define ACTMON_DEV_INTR_CONSECUTIVE_LOWER BIT(30) + +#define ACTMON_ABOVE_WMARK_WINDOW 1 +#define ACTMON_BELOW_WMARK_WINDOW 3 +#define ACTMON_BOOST_FREQ_STEP 16000 + +/* activity counter is incremented every 256 memory transactions, and each + * transaction takes 4 EMC clocks for Tegra124; So the COUNT_WEIGHT is + * 4 * 256 = 1024. + */ +#define ACTMON_COUNT_WEIGHT 0x400 + +/* + * ACTMON_AVERAGE_WINDOW_LOG2: default value for @DEV_CTRL_K_VAL, which + * translates to 2 ^ (K_VAL + 1). ex: 2 ^ (6 + 1) = 128 + */ +#define ACTMON_AVERAGE_WINDOW_LOG2 6 +#define ACTMON_SAMPLING_PERIOD 12 /* ms */ +#define ACTMON_DEFAULT_AVG_BAND 6 /* 1/10 of % */ + +#define KHZ 1000 + +/* Assume that the bus is saturated if the utilization is 25% */ +#define BUS_SATURATION_RATIO 25 + +/** + * struct tegra_devfreq_device_config - configuration specific to an ACTMON + * device + * + * Coefficients and thresholds are in % + */ +struct tegra_devfreq_device_config { + u32 offset; + u32 irq_mask; + + unsigned int boost_up_coeff; + unsigned int boost_down_coeff; + unsigned int boost_up_threshold; + unsigned int boost_down_threshold; + u32 avg_dependency_threshold; +}; + +enum tegra_actmon_device { + MCALL = 0, + MCCPU, +}; + +static struct tegra_devfreq_device_config actmon_device_configs[] = { + { + /* MCALL */ + .offset = 0x1c0, + .irq_mask = 1 << 26, + .boost_up_coeff = 200, + .boost_down_coeff = 50, + .boost_up_threshold = 60, + .boost_down_threshold = 40, + }, + { + /* MCCPU */ + .offset = 0x200, + .irq_mask = 1 << 25, + .boost_up_coeff = 800, + .boost_down_coeff = 90, + .boost_up_threshold = 27, + .boost_down_threshold = 10, + .avg_dependency_threshold = 50000, + }, +}; + +/** + * struct tegra_devfreq_device - state specific to an ACTMON device + * + * Frequencies are in kHz. + */ +struct tegra_devfreq_device { + const struct tegra_devfreq_device_config *config; + + void __iomem *regs; + u32 avg_band_freq; + u32 avg_count; + + unsigned long target_freq; + unsigned long boost_freq; +}; + +struct tegra_devfreq { + struct devfreq *devfreq; + + struct platform_device *pdev; + struct reset_control *reset; + struct clk *clock; + void __iomem *regs; + + spinlock_t lock; + + struct clk *emc_clock; + unsigned long max_freq; + unsigned long cur_freq; + struct notifier_block rate_change_nb; + + struct tegra_devfreq_device devices[ARRAY_SIZE(actmon_device_configs)]; +}; + +struct tegra_actmon_emc_ratio { + unsigned long cpu_freq; + unsigned long emc_freq; +}; + +static struct tegra_actmon_emc_ratio actmon_emc_ratios[] = { + { 1400000, ULONG_MAX }, + { 1200000, 750000 }, + { 1100000, 600000 }, + { 1000000, 500000 }, + { 800000, 375000 }, + { 500000, 200000 }, + { 250000, 100000 }, +}; + +static unsigned long do_percent(unsigned long val, unsigned int pct) +{ + return val * pct / 100; +} + +static void tegra_devfreq_update_avg_wmark(struct tegra_devfreq_device *dev) +{ + u32 avg = dev->avg_count; + u32 band = dev->avg_band_freq * ACTMON_SAMPLING_PERIOD; + + writel(avg + band, dev->regs + ACTMON_DEV_AVG_UPPER_WMARK); + avg = max(avg, band); + writel(avg - band, dev->regs + ACTMON_DEV_AVG_LOWER_WMARK); +} + +static void tegra_devfreq_update_wmark(struct tegra_devfreq *tegra, + struct tegra_devfreq_device *dev) +{ + u32 val = tegra->cur_freq * ACTMON_SAMPLING_PERIOD; + + writel(do_percent(val, dev->config->boost_up_threshold), + dev->regs + ACTMON_DEV_UPPER_WMARK); + + writel(do_percent(val, dev->config->boost_down_threshold), + dev->regs + ACTMON_DEV_LOWER_WMARK); +} + +static void actmon_write_barrier(struct tegra_devfreq *tegra) +{ + /* ensure the update has reached the ACTMON */ + wmb(); + readl(tegra->regs + ACTMON_GLB_STATUS); +} + +static irqreturn_t actmon_isr(int irq, void *data) +{ + struct tegra_devfreq *tegra = data; + struct tegra_devfreq_device *dev = NULL; + unsigned long flags; + u32 val; + unsigned int i; + + val = readl(tegra->regs + ACTMON_GLB_STATUS); + + for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { + if (val & tegra->devices[i].config->irq_mask) { + dev = tegra->devices + i; + break; + } + } + + if (!dev) + return IRQ_NONE; + + spin_lock_irqsave(&tegra->lock, flags); + + dev->avg_count = readl(dev->regs + ACTMON_DEV_AVG_COUNT); + tegra_devfreq_update_avg_wmark(dev); + + val = readl(dev->regs + ACTMON_DEV_INTR_STATUS); + if (val & ACTMON_DEV_INTR_CONSECUTIVE_UPPER) { + val = readl(dev->regs + ACTMON_DEV_CTRL) | + ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN | + ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; + + /* + * new_boost = min(old_boost * up_coef + step, max_freq) + */ + dev->boost_freq = do_percent(dev->boost_freq, + dev->config->boost_up_coeff); + dev->boost_freq += ACTMON_BOOST_FREQ_STEP; + if (dev->boost_freq >= tegra->max_freq) { + dev->boost_freq = tegra->max_freq; + val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN; + } + writel(val, dev->regs + ACTMON_DEV_CTRL); + } else if (val & ACTMON_DEV_INTR_CONSECUTIVE_LOWER) { + val = readl(dev->regs + ACTMON_DEV_CTRL) | + ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN | + ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; + + /* + * new_boost = old_boost * down_coef + * or 0 if (old_boost * down_coef < step / 2) + */ + dev->boost_freq = do_percent(dev->boost_freq, + dev->config->boost_down_coeff); + if (dev->boost_freq < (ACTMON_BOOST_FREQ_STEP >> 1)) { + dev->boost_freq = 0; + val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; + } + writel(val, dev->regs + ACTMON_DEV_CTRL); + } + + if (dev->config->avg_dependency_threshold) { + val = readl(dev->regs + ACTMON_DEV_CTRL); + if (dev->avg_count >= dev->config->avg_dependency_threshold) + val |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; + else if (dev->boost_freq == 0) + val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN; + writel(val, dev->regs + ACTMON_DEV_CTRL); + } + + writel(ACTMON_INTR_STATUS_CLEAR, dev->regs + ACTMON_DEV_INTR_STATUS); + + actmon_write_barrier(tegra); + + spin_unlock_irqrestore(&tegra->lock, flags); + + return IRQ_WAKE_THREAD; +} + +static unsigned long actmon_cpu_to_emc_rate(struct tegra_devfreq *tegra, + unsigned long cpu_freq) +{ + unsigned int i; + struct tegra_actmon_emc_ratio *ratio = actmon_emc_ratios; + + for (i = 0; i < ARRAY_SIZE(actmon_emc_ratios); i++, ratio++) { + if (cpu_freq >= ratio->cpu_freq) { + if (ratio->emc_freq >= tegra->max_freq) + return tegra->max_freq; + else + return ratio->emc_freq; + } + } + + return 0; +} + +static void actmon_update_target(struct tegra_devfreq *tegra, + struct tegra_devfreq_device *dev) +{ + unsigned long cpu_freq = 0; + unsigned long static_cpu_emc_freq = 0; + unsigned int avg_sustain_coef; + unsigned long flags; + + if (dev->config->avg_dependency_threshold) { + cpu_freq = cpufreq_get(0); + static_cpu_emc_freq = actmon_cpu_to_emc_rate(tegra, cpu_freq); + } + + spin_lock_irqsave(&tegra->lock, flags); + + dev->target_freq = dev->avg_count / ACTMON_SAMPLING_PERIOD; + avg_sustain_coef = 100 * 100 / dev->config->boost_up_threshold; + dev->target_freq = do_percent(dev->target_freq, avg_sustain_coef); + dev->target_freq += dev->boost_freq; + + if (dev->avg_count >= dev->config->avg_dependency_threshold) + dev->target_freq = max(dev->target_freq, static_cpu_emc_freq); + + spin_unlock_irqrestore(&tegra->lock, flags); +} + +static irqreturn_t actmon_thread_isr(int irq, void *data) +{ + struct tegra_devfreq *tegra = data; + + mutex_lock(&tegra->devfreq->lock); + update_devfreq(tegra->devfreq); + mutex_unlock(&tegra->devfreq->lock); + + return IRQ_HANDLED; +} + +static int tegra_actmon_rate_notify_cb(struct notifier_block *nb, + unsigned long action, void *ptr) +{ + struct clk_notifier_data *data = ptr; + struct tegra_devfreq *tegra = container_of(nb, struct tegra_devfreq, + rate_change_nb); + unsigned int i; + unsigned long flags; + + spin_lock_irqsave(&tegra->lock, flags); + + switch (action) { + case POST_RATE_CHANGE: + tegra->cur_freq = data->new_rate / KHZ; + + for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) + tegra_devfreq_update_wmark(tegra, tegra->devices + i); + + actmon_write_barrier(tegra); + break; + case PRE_RATE_CHANGE: + /* fall through */ + case ABORT_RATE_CHANGE: + break; + }; + + spin_unlock_irqrestore(&tegra->lock, flags); + + return NOTIFY_OK; +} + +static void tegra_actmon_configure_device(struct tegra_devfreq *tegra, + struct tegra_devfreq_device *dev) +{ + u32 val; + + dev->avg_band_freq = tegra->max_freq * ACTMON_DEFAULT_AVG_BAND / KHZ; + dev->target_freq = tegra->cur_freq; + + dev->avg_count = tegra->cur_freq * ACTMON_SAMPLING_PERIOD; + writel(dev->avg_count, dev->regs + ACTMON_DEV_INIT_AVG); + + tegra_devfreq_update_avg_wmark(dev); + tegra_devfreq_update_wmark(tegra, dev); + + writel(ACTMON_COUNT_WEIGHT, dev->regs + ACTMON_DEV_COUNT_WEIGHT); + writel(ACTMON_INTR_STATUS_CLEAR, dev->regs + ACTMON_DEV_INTR_STATUS); + + val = 0; + val |= ACTMON_DEV_CTRL_ENB_PERIODIC | + ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN | + ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN; + val |= (ACTMON_AVERAGE_WINDOW_LOG2 - 1) + << ACTMON_DEV_CTRL_K_VAL_SHIFT; + val |= (ACTMON_BELOW_WMARK_WINDOW - 1) + << ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_NUM_SHIFT; + val |= (ACTMON_ABOVE_WMARK_WINDOW - 1) + << ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_NUM_SHIFT; + val |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN | + ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN; + + writel(val, dev->regs + ACTMON_DEV_CTRL); + + actmon_write_barrier(tegra); + + val = readl(dev->regs + ACTMON_DEV_CTRL); + val |= ACTMON_DEV_CTRL_ENB; + writel(val, dev->regs + ACTMON_DEV_CTRL); + + actmon_write_barrier(tegra); +} + +static int tegra_devfreq_suspend(struct device *dev) +{ + struct platform_device *pdev; + struct tegra_devfreq *tegra; + struct tegra_devfreq_device *actmon_dev; + unsigned int i; + u32 val; + + pdev = container_of(dev, struct platform_device, dev); + tegra = platform_get_drvdata(pdev); + + for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { + actmon_dev = &tegra->devices[i]; + + val = readl(actmon_dev->regs + ACTMON_DEV_CTRL); + val &= ~ACTMON_DEV_CTRL_ENB; + writel(val, actmon_dev->regs + ACTMON_DEV_CTRL); + + writel(ACTMON_INTR_STATUS_CLEAR, + actmon_dev->regs + ACTMON_DEV_INTR_STATUS); + + actmon_write_barrier(tegra); + } + + return 0; +} + +static int tegra_devfreq_resume(struct device *dev) +{ + struct platform_device *pdev; + struct tegra_devfreq *tegra; + struct tegra_devfreq_device *actmon_dev; + unsigned int i; + + pdev = container_of(dev, struct platform_device, dev); + tegra = platform_get_drvdata(pdev); + + for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { + actmon_dev = &tegra->devices[i]; + + tegra_actmon_configure_device(tegra, actmon_dev); + } + + return 0; +} + +static int tegra_devfreq_target(struct device *dev, unsigned long *freq, + u32 flags) +{ + struct platform_device *pdev; + struct tegra_devfreq *tegra; + struct dev_pm_opp *opp; + unsigned long rate = *freq * KHZ; + + pdev = container_of(dev, struct platform_device, dev); + tegra = platform_get_drvdata(pdev); + + rcu_read_lock(); + opp = devfreq_recommended_opp(dev, &rate, flags); + if (IS_ERR(opp)) { + rcu_read_unlock(); + dev_err(dev, "Failed to find opp for %lu KHz\n", *freq); + return PTR_ERR(opp); + } + rate = dev_pm_opp_get_freq(opp); + rcu_read_unlock(); + + /* TODO: Once we have per-user clk constraints, set a floor */ + clk_set_rate(tegra->emc_clock, rate); + + /* TODO: Set voltage as well */ + + return 0; +} + +static int tegra_devfreq_get_dev_status(struct device *dev, + struct devfreq_dev_status *stat) +{ + struct platform_device *pdev; + struct tegra_devfreq *tegra; + struct tegra_devfreq_device *actmon_dev; + + pdev = container_of(dev, struct platform_device, dev); + tegra = platform_get_drvdata(pdev); + + stat->current_frequency = tegra->cur_freq; + + /* To be used by the tegra governor */ + stat->private_data = tegra; + + /* The below are to be used by the other governors */ + + actmon_dev = &tegra->devices[MCALL]; + + /* Number of cycles spent on memory access */ + stat->busy_time = actmon_dev->avg_count; + + /* The bus can be considered to be saturated way before 100% */ + stat->busy_time *= 100 / BUS_SATURATION_RATIO; + + /* Number of cycles in a sampling period */ + stat->total_time = ACTMON_SAMPLING_PERIOD * tegra->cur_freq; + + return 0; +} + +static int tegra_devfreq_get_target(struct devfreq *devfreq, + unsigned long *freq) +{ + struct devfreq_dev_status stat; + struct tegra_devfreq *tegra; + struct tegra_devfreq_device *dev; + unsigned long target_freq = 0; + unsigned int i; + int err; + + err = devfreq->profile->get_dev_status(devfreq->dev.parent, &stat); + if (err) + return err; + + tegra = stat.private_data; + + for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { + dev = &tegra->devices[i]; + + actmon_update_target(tegra, dev); + + target_freq = max(target_freq, dev->target_freq); + } + + *freq = target_freq; + + return 0; +} + +static int tegra_devfreq_event_handler(struct devfreq *devfreq, + unsigned int event, void *data) +{ + return 0; +} + +static struct devfreq_governor tegra_devfreq_governor = { + .name = "tegra", + .get_target_freq = tegra_devfreq_get_target, + .event_handler = tegra_devfreq_event_handler, +}; + +static struct devfreq_dev_profile tegra_devfreq_profile = { + .polling_ms = 0, + .target = tegra_devfreq_target, + .get_dev_status = tegra_devfreq_get_dev_status, +}; + +static int tegra_devfreq_probe(struct platform_device *pdev) +{ + struct tegra_devfreq *tegra; + struct tegra_devfreq_device *dev; + struct resource *res; + unsigned long max_freq; + unsigned int i; + int irq; + int err; + + tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); + if (!tegra) + return -ENOMEM; + + spin_lock_init(&tegra->lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Failed to get regs resource\n"); + return -ENODEV; + } + + tegra->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(tegra->regs)) { + dev_err(&pdev->dev, "Failed to get IO memory\n"); + return PTR_ERR(tegra->regs); + } + + tegra->reset = devm_reset_control_get(&pdev->dev, "actmon"); + if (IS_ERR(tegra->reset)) { + dev_err(&pdev->dev, "Failed to get reset\n"); + return PTR_ERR(tegra->reset); + } + + tegra->clock = devm_clk_get(&pdev->dev, "actmon"); + if (IS_ERR(tegra->clock)) { + dev_err(&pdev->dev, "Failed to get actmon clock\n"); + return PTR_ERR(tegra->clock); + } + + tegra->emc_clock = devm_clk_get(&pdev->dev, "emc"); + if (IS_ERR(tegra->emc_clock)) { + dev_err(&pdev->dev, "Failed to get emc clock\n"); + return PTR_ERR(tegra->emc_clock); + } + + err = of_init_opp_table(&pdev->dev); + if (err) { + dev_err(&pdev->dev, "Failed to init operating point table\n"); + return err; + } + + tegra->rate_change_nb.notifier_call = tegra_actmon_rate_notify_cb; + err = clk_notifier_register(tegra->emc_clock, &tegra->rate_change_nb); + if (err) { + dev_err(&pdev->dev, + "Failed to register rate change notifier\n"); + return err; + } + + reset_control_assert(tegra->reset); + + err = clk_prepare_enable(tegra->clock); + if (err) { + reset_control_deassert(tegra->reset); + return err; + } + + reset_control_deassert(tegra->reset); + + max_freq = clk_round_rate(tegra->emc_clock, ULONG_MAX); + tegra->max_freq = max_freq / KHZ; + + clk_set_rate(tegra->emc_clock, max_freq); + + tegra->cur_freq = clk_get_rate(tegra->emc_clock) / KHZ; + + writel(ACTMON_SAMPLING_PERIOD - 1, + tegra->regs + ACTMON_GLB_PERIOD_CTRL); + + for (i = 0; i < ARRAY_SIZE(actmon_device_configs); i++) { + dev = tegra->devices + i; + dev->config = actmon_device_configs + i; + dev->regs = tegra->regs + dev->config->offset; + + tegra_actmon_configure_device(tegra, tegra->devices + i); + } + + err = devfreq_add_governor(&tegra_devfreq_governor); + if (err) { + dev_err(&pdev->dev, "Failed to add governor\n"); + return err; + } + + tegra_devfreq_profile.initial_freq = clk_get_rate(tegra->emc_clock); + tegra->devfreq = devm_devfreq_add_device(&pdev->dev, + &tegra_devfreq_profile, + "tegra", + NULL); + + irq = platform_get_irq(pdev, 0); + err = devm_request_threaded_irq(&pdev->dev, irq, actmon_isr, + actmon_thread_isr, IRQF_SHARED, + "tegra-devfreq", tegra); + if (err) { + dev_err(&pdev->dev, "Interrupt request failed\n"); + return err; + } + + platform_set_drvdata(pdev, tegra); + + return 0; +} + +static int tegra_devfreq_remove(struct platform_device *pdev) +{ + struct tegra_devfreq *tegra = platform_get_drvdata(pdev); + + clk_notifier_unregister(tegra->emc_clock, &tegra->rate_change_nb); + + clk_disable_unprepare(tegra->clock); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(tegra_devfreq_pm_ops, + tegra_devfreq_suspend, + tegra_devfreq_resume); + +static struct of_device_id tegra_devfreq_of_match[] = { + { .compatible = "nvidia,tegra124-actmon" }, + { }, +}; + +static struct platform_driver tegra_devfreq_driver = { + .probe = tegra_devfreq_probe, + .remove = tegra_devfreq_remove, + .driver = { + .name = "tegra-devfreq", + .owner = THIS_MODULE, + .of_match_table = tegra_devfreq_of_match, + .pm = &tegra_devfreq_pm_ops, + }, +}; +module_platform_driver(tegra_devfreq_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Tegra devfreq driver"); +MODULE_AUTHOR("Tomeu Vizoso "); +MODULE_DEVICE_TABLE(of, tegra_devfreq_of_match); diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c index de361a156b34..5a635646e05c 100644 --- a/drivers/dma/acpi-dma.c +++ b/drivers/dma/acpi-dma.c @@ -43,7 +43,7 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp, { const struct acpi_csrt_shared_info *si; struct list_head resource_list; - struct resource_list_entry *rentry; + struct resource_entry *rentry; resource_size_t mem = 0, irq = 0; int ret; @@ -56,10 +56,10 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp, return 0; list_for_each_entry(rentry, &resource_list, node) { - if (resource_type(&rentry->res) == IORESOURCE_MEM) - mem = rentry->res.start; - else if (resource_type(&rentry->res) == IORESOURCE_IRQ) - irq = rentry->res.start; + if (resource_type(rentry->res) == IORESOURCE_MEM) + mem = rentry->res->start; + else if (resource_type(rentry->res) == IORESOURCE_IRQ) + irq = rentry->res->start; } acpi_dev_free_resource_list(&resource_list); diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 49c265255a07..cb59619df23f 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -385,4 +385,11 @@ config EDAC_ALTERA_MC preloader must initialize the SDRAM before loading the kernel. +config EDAC_SYNOPSYS + tristate "Synopsys DDR Memory Controller" + depends on EDAC_MM_EDAC && ARCH_ZYNQ + help + Support for error detection and correction on the Synopsys DDR + memory controller. + endif # EDAC diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index d40c69a04df7..b255f362b1db 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -67,3 +67,4 @@ obj-$(CONFIG_EDAC_OCTEON_LMC) += octeon_edac-lmc.o obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o obj-$(CONFIG_EDAC_ALTERA_MC) += altera_edac.o +obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 670d2829c547..c84eecb191ef 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -157,7 +157,7 @@ struct dev_ch_attribute { }; #define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \ - struct dev_ch_attribute dev_attr_legacy_##_name = \ + static struct dev_ch_attribute dev_attr_legacy_##_name = \ { __ATTR(_name, _mode, _show, _store), (_var) } #define to_channel(k) (container_of(k, struct dev_ch_attribute, attr)->channel) @@ -850,20 +850,20 @@ static const struct file_operations debug_fake_inject_fops = { #endif /* default Control file */ -DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store); +static DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store); /* default Attribute files */ -DEVICE_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL); -DEVICE_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL); -DEVICE_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL); -DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL); -DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL); -DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL); -DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL); -DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL); +static DEVICE_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL); +static DEVICE_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL); +static DEVICE_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL); +static DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL); +static DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL); +static DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL); +static DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL); +static DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL); /* memory scrubber attribute file */ -DEVICE_ATTR(sdram_scrub_rate, 0, NULL, NULL); +static DEVICE_ATTR(sdram_scrub_rate, 0, NULL, NULL); static struct attribute *mci_attrs[] = { &dev_attr_reset_counters.attr, @@ -989,7 +989,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) err = bus_register(mci->bus); if (err < 0) - return err; + goto fail_free_name; /* get the /sys/devices/system/edac subsys reference */ mci->dev.type = &mci_attr_type; @@ -1005,9 +1005,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) err = device_add(&mci->dev); if (err < 0) { edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev)); - bus_unregister(mci->bus); - kfree(mci->bus->name); - return err; + goto fail_unregister_bus; } if (mci->set_sdram_scrub_rate || mci->get_sdram_scrub_rate) { @@ -1015,15 +1013,16 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) dev_attr_sdram_scrub_rate.attr.mode |= S_IRUGO; dev_attr_sdram_scrub_rate.show = &mci_sdram_scrub_rate_show; } + if (mci->set_sdram_scrub_rate) { dev_attr_sdram_scrub_rate.attr.mode |= S_IWUSR; dev_attr_sdram_scrub_rate.store = &mci_sdram_scrub_rate_store; } - err = device_create_file(&mci->dev, - &dev_attr_sdram_scrub_rate); + + err = device_create_file(&mci->dev, &dev_attr_sdram_scrub_rate); if (err) { edac_dbg(1, "failure: create sdram_scrub_rate\n"); - goto fail2; + goto fail_unregister_dev; } } /* @@ -1032,8 +1031,9 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) for (i = 0; i < mci->tot_dimms; i++) { struct dimm_info *dimm = mci->dimms[i]; /* Only expose populated DIMMs */ - if (dimm->nr_pages == 0) + if (!dimm->nr_pages) continue; + #ifdef CONFIG_EDAC_DEBUG edac_dbg(1, "creating dimm%d, located at ", i); if (edac_debug_level >= 1) { @@ -1048,14 +1048,14 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) err = edac_create_dimm_object(mci, dimm, i); if (err) { edac_dbg(1, "failure: create dimm %d obj\n", i); - goto fail; + goto fail_unregister_dimm; } } #ifdef CONFIG_EDAC_LEGACY_SYSFS err = edac_create_csrow_objects(mci); if (err < 0) - goto fail; + goto fail_unregister_dimm; #endif #ifdef CONFIG_EDAC_DEBUG @@ -1063,16 +1063,19 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) #endif return 0; -fail: +fail_unregister_dimm: for (i--; i >= 0; i--) { struct dimm_info *dimm = mci->dimms[i]; - if (dimm->nr_pages == 0) + if (!dimm->nr_pages) continue; + device_unregister(&dimm->dev); } -fail2: +fail_unregister_dev: device_unregister(&mci->dev); +fail_unregister_bus: bus_unregister(mci->bus); +fail_free_name: kfree(mci->bus->name); return err; } diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c index 6247d186177e..e9f8a393915a 100644 --- a/drivers/edac/i5100_edac.c +++ b/drivers/edac/i5100_edac.c @@ -279,11 +279,6 @@ static inline u32 i5100_recmema_rank(u32 a) return i5100_nrecmema_rank(a); } -static inline u32 i5100_recmema_dm_buf_id(u32 a) -{ - return i5100_nrecmema_dm_buf_id(a); -} - static inline u32 i5100_recmemb_cas(u32 a) { return i5100_nrecmemb_cas(a); diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c index 0bd91a802c67..f7681b553fd5 100644 --- a/drivers/edac/mce_amd_inj.c +++ b/drivers/edac/mce_amd_inj.c @@ -197,7 +197,7 @@ static int inj_bank_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(bank_fops, inj_bank_get, inj_bank_set, "%llu\n"); -struct dfs_node { +static struct dfs_node { char *name; struct dentry *d; const struct file_operations *fops; diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index ffb1a9a15ccd..1fa76a588af3 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -1,5 +1,5 @@ /* - * Freescale MPC85xx Memory Controller kenel module + * Freescale MPC85xx Memory Controller kernel module * * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc. * diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h index 8c6256436227..4498baf9ce05 100644 --- a/drivers/edac/mpc85xx_edac.h +++ b/drivers/edac/mpc85xx_edac.h @@ -1,5 +1,5 @@ /* - * Freescale MPC85xx Memory Controller kenel module + * Freescale MPC85xx Memory Controller kernel module * Author: Dave Jiang * * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c index 6366e880f978..0574e1bbe45c 100644 --- a/drivers/edac/mv64x60_edac.c +++ b/drivers/edac/mv64x60_edac.c @@ -789,7 +789,8 @@ static int mv64x60_mc_err_probe(struct platform_device *pdev) ctl = (ctl & 0xff00ffff) | 0x10000; out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL, ctl); - if (edac_mc_add_mc(mci)) { + res = edac_mc_add_mc(mci); + if (res) { edac_dbg(3, "failed edac_mc_add_mc()\n"); goto err; } diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c new file mode 100644 index 000000000000..1c9691535e13 --- /dev/null +++ b/drivers/edac/synopsys_edac.c @@ -0,0 +1,535 @@ +/* + * Synopsys DDR ECC Driver + * This driver is based on ppc4xx_edac.c drivers + * + * Copyright (C) 2012 - 2014 Xilinx, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This 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 + */ + +#include +#include +#include + +#include "edac_core.h" + +/* Number of cs_rows needed per memory controller */ +#define SYNPS_EDAC_NR_CSROWS 1 + +/* Number of channels per memory controller */ +#define SYNPS_EDAC_NR_CHANS 1 + +/* Granularity of reported error in bytes */ +#define SYNPS_EDAC_ERR_GRAIN 1 + +#define SYNPS_EDAC_MSG_SIZE 256 + +#define SYNPS_EDAC_MOD_STRING "synps_edac" +#define SYNPS_EDAC_MOD_VER "1" + +/* Synopsys DDR memory controller registers that are relevant to ECC */ +#define CTRL_OFST 0x0 +#define T_ZQ_OFST 0xA4 + +/* ECC control register */ +#define ECC_CTRL_OFST 0xC4 +/* ECC log register */ +#define CE_LOG_OFST 0xC8 +/* ECC address register */ +#define CE_ADDR_OFST 0xCC +/* ECC data[31:0] register */ +#define CE_DATA_31_0_OFST 0xD0 + +/* Uncorrectable error info registers */ +#define UE_LOG_OFST 0xDC +#define UE_ADDR_OFST 0xE0 +#define UE_DATA_31_0_OFST 0xE4 + +#define STAT_OFST 0xF0 +#define SCRUB_OFST 0xF4 + +/* Control register bit field definitions */ +#define CTRL_BW_MASK 0xC +#define CTRL_BW_SHIFT 2 + +#define DDRCTL_WDTH_16 1 +#define DDRCTL_WDTH_32 0 + +/* ZQ register bit field definitions */ +#define T_ZQ_DDRMODE_MASK 0x2 + +/* ECC control register bit field definitions */ +#define ECC_CTRL_CLR_CE_ERR 0x2 +#define ECC_CTRL_CLR_UE_ERR 0x1 + +/* ECC correctable/uncorrectable error log register definitions */ +#define LOG_VALID 0x1 +#define CE_LOG_BITPOS_MASK 0xFE +#define CE_LOG_BITPOS_SHIFT 1 + +/* ECC correctable/uncorrectable error address register definitions */ +#define ADDR_COL_MASK 0xFFF +#define ADDR_ROW_MASK 0xFFFF000 +#define ADDR_ROW_SHIFT 12 +#define ADDR_BANK_MASK 0x70000000 +#define ADDR_BANK_SHIFT 28 + +/* ECC statistic register definitions */ +#define STAT_UECNT_MASK 0xFF +#define STAT_CECNT_MASK 0xFF00 +#define STAT_CECNT_SHIFT 8 + +/* ECC scrub register definitions */ +#define SCRUB_MODE_MASK 0x7 +#define SCRUB_MODE_SECDED 0x4 + +/** + * struct ecc_error_info - ECC error log information + * @row: Row number + * @col: Column number + * @bank: Bank number + * @bitpos: Bit position + * @data: Data causing the error + */ +struct ecc_error_info { + u32 row; + u32 col; + u32 bank; + u32 bitpos; + u32 data; +}; + +/** + * struct synps_ecc_status - ECC status information to report + * @ce_cnt: Correctable error count + * @ue_cnt: Uncorrectable error count + * @ceinfo: Correctable error log information + * @ueinfo: Uncorrectable error log information + */ +struct synps_ecc_status { + u32 ce_cnt; + u32 ue_cnt; + struct ecc_error_info ceinfo; + struct ecc_error_info ueinfo; +}; + +/** + * struct synps_edac_priv - DDR memory controller private instance data + * @baseaddr: Base address of the DDR controller + * @message: Buffer for framing the event specific info + * @stat: ECC status information + * @ce_cnt: Correctable Error count + * @ue_cnt: Uncorrectable Error count + */ +struct synps_edac_priv { + void __iomem *baseaddr; + char message[SYNPS_EDAC_MSG_SIZE]; + struct synps_ecc_status stat; + u32 ce_cnt; + u32 ue_cnt; +}; + +/** + * synps_edac_geterror_info - Get the current ecc error info + * @base: Pointer to the base address of the ddr memory controller + * @p: Pointer to the synopsys ecc status structure + * + * Determines there is any ecc error or not + * + * Return: one if there is no error otherwise returns zero + */ +static int synps_edac_geterror_info(void __iomem *base, + struct synps_ecc_status *p) +{ + u32 regval, clearval = 0; + + regval = readl(base + STAT_OFST); + if (!regval) + return 1; + + p->ce_cnt = (regval & STAT_CECNT_MASK) >> STAT_CECNT_SHIFT; + p->ue_cnt = regval & STAT_UECNT_MASK; + + regval = readl(base + CE_LOG_OFST); + if (!(p->ce_cnt && (regval & LOG_VALID))) + goto ue_err; + + p->ceinfo.bitpos = (regval & CE_LOG_BITPOS_MASK) >> CE_LOG_BITPOS_SHIFT; + regval = readl(base + CE_ADDR_OFST); + p->ceinfo.row = (regval & ADDR_ROW_MASK) >> ADDR_ROW_SHIFT; + p->ceinfo.col = regval & ADDR_COL_MASK; + p->ceinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT; + p->ceinfo.data = readl(base + CE_DATA_31_0_OFST); + edac_dbg(3, "ce bit position: %d data: %d\n", p->ceinfo.bitpos, + p->ceinfo.data); + clearval = ECC_CTRL_CLR_CE_ERR; + +ue_err: + regval = readl(base + UE_LOG_OFST); + if (!(p->ue_cnt && (regval & LOG_VALID))) + goto out; + + regval = readl(base + UE_ADDR_OFST); + p->ueinfo.row = (regval & ADDR_ROW_MASK) >> ADDR_ROW_SHIFT; + p->ueinfo.col = regval & ADDR_COL_MASK; + p->ueinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT; + p->ueinfo.data = readl(base + UE_DATA_31_0_OFST); + clearval |= ECC_CTRL_CLR_UE_ERR; + +out: + writel(clearval, base + ECC_CTRL_OFST); + writel(0x0, base + ECC_CTRL_OFST); + + return 0; +} + +/** + * synps_edac_handle_error - Handle controller error types CE and UE + * @mci: Pointer to the edac memory controller instance + * @p: Pointer to the synopsys ecc status structure + * + * Handles the controller ECC correctable and un correctable error. + */ +static void synps_edac_handle_error(struct mem_ctl_info *mci, + struct synps_ecc_status *p) +{ + struct synps_edac_priv *priv = mci->pvt_info; + struct ecc_error_info *pinf; + + if (p->ce_cnt) { + pinf = &p->ceinfo; + snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, + "DDR ECC error type :%s Row %d Bank %d Col %d ", + "CE", pinf->row, pinf->bank, pinf->col); + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, + p->ce_cnt, 0, 0, 0, 0, 0, -1, + priv->message, ""); + } + + if (p->ue_cnt) { + pinf = &p->ueinfo; + snprintf(priv->message, SYNPS_EDAC_MSG_SIZE, + "DDR ECC error type :%s Row %d Bank %d Col %d ", + "UE", pinf->row, pinf->bank, pinf->col); + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, + p->ue_cnt, 0, 0, 0, 0, 0, -1, + priv->message, ""); + } + + memset(p, 0, sizeof(*p)); +} + +/** + * synps_edac_check - Check controller for ECC errors + * @mci: Pointer to the edac memory controller instance + * + * Used to check and post ECC errors. Called by the polling thread + */ +static void synps_edac_check(struct mem_ctl_info *mci) +{ + struct synps_edac_priv *priv = mci->pvt_info; + int status; + + status = synps_edac_geterror_info(priv->baseaddr, &priv->stat); + if (status) + return; + + priv->ce_cnt += priv->stat.ce_cnt; + priv->ue_cnt += priv->stat.ue_cnt; + synps_edac_handle_error(mci, &priv->stat); + + edac_dbg(3, "Total error count ce %d ue %d\n", + priv->ce_cnt, priv->ue_cnt); +} + +/** + * synps_edac_get_dtype - Return the controller memory width + * @base: Pointer to the ddr memory controller base address + * + * Get the EDAC device type width appropriate for the current controller + * configuration. + * + * Return: a device type width enumeration. + */ +static enum dev_type synps_edac_get_dtype(const void __iomem *base) +{ + enum dev_type dt; + u32 width; + + width = readl(base + CTRL_OFST); + width = (width & CTRL_BW_MASK) >> CTRL_BW_SHIFT; + + switch (width) { + case DDRCTL_WDTH_16: + dt = DEV_X2; + break; + case DDRCTL_WDTH_32: + dt = DEV_X4; + break; + default: + dt = DEV_UNKNOWN; + } + + return dt; +} + +/** + * synps_edac_get_eccstate - Return the controller ecc enable/disable status + * @base: Pointer to the ddr memory controller base address + * + * Get the ECC enable/disable status for the controller + * + * Return: a ecc status boolean i.e true/false - enabled/disabled. + */ +static bool synps_edac_get_eccstate(void __iomem *base) +{ + enum dev_type dt; + u32 ecctype; + bool state = false; + + dt = synps_edac_get_dtype(base); + if (dt == DEV_UNKNOWN) + return state; + + ecctype = readl(base + SCRUB_OFST) & SCRUB_MODE_MASK; + if ((ecctype == SCRUB_MODE_SECDED) && (dt == DEV_X2)) + state = true; + + return state; +} + +/** + * synps_edac_get_memsize - reads the size of the attached memory device + * + * Return: the memory size in bytes + */ +static u32 synps_edac_get_memsize(void) +{ + struct sysinfo inf; + + si_meminfo(&inf); + + return inf.totalram * inf.mem_unit; +} + +/** + * synps_edac_get_mtype - Returns controller memory type + * @base: pointer to the synopsys ecc status structure + * + * Get the EDAC memory type appropriate for the current controller + * configuration. + * + * Return: a memory type enumeration. + */ +static enum mem_type synps_edac_get_mtype(const void __iomem *base) +{ + enum mem_type mt; + u32 memtype; + + memtype = readl(base + T_ZQ_OFST); + + if (memtype & T_ZQ_DDRMODE_MASK) + mt = MEM_DDR3; + else + mt = MEM_DDR2; + + return mt; +} + +/** + * synps_edac_init_csrows - Initialize the cs row data + * @mci: Pointer to the edac memory controller instance + * + * Initializes the chip select rows associated with the EDAC memory + * controller instance + * + * Return: Unconditionally 0. + */ +static int synps_edac_init_csrows(struct mem_ctl_info *mci) +{ + struct csrow_info *csi; + struct dimm_info *dimm; + struct synps_edac_priv *priv = mci->pvt_info; + u32 size; + int row, j; + + for (row = 0; row < mci->nr_csrows; row++) { + csi = mci->csrows[row]; + size = synps_edac_get_memsize(); + + for (j = 0; j < csi->nr_channels; j++) { + dimm = csi->channels[j]->dimm; + dimm->edac_mode = EDAC_FLAG_SECDED; + dimm->mtype = synps_edac_get_mtype(priv->baseaddr); + dimm->nr_pages = (size >> PAGE_SHIFT) / csi->nr_channels; + dimm->grain = SYNPS_EDAC_ERR_GRAIN; + dimm->dtype = synps_edac_get_dtype(priv->baseaddr); + } + } + + return 0; +} + +/** + * synps_edac_mc_init - Initialize driver instance + * @mci: Pointer to the edac memory controller instance + * @pdev: Pointer to the platform_device struct + * + * Performs initialization of the EDAC memory controller instance and + * related driver-private data associated with the memory controller the + * instance is bound to. + * + * Return: Always zero. + */ +static int synps_edac_mc_init(struct mem_ctl_info *mci, + struct platform_device *pdev) +{ + int status; + struct synps_edac_priv *priv; + + mci->pdev = &pdev->dev; + priv = mci->pvt_info; + platform_set_drvdata(pdev, mci); + + /* Initialize controller capabilities and configuration */ + mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2; + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; + mci->scrub_cap = SCRUB_HW_SRC; + mci->scrub_mode = SCRUB_NONE; + + mci->edac_cap = EDAC_FLAG_SECDED; + mci->ctl_name = "synps_ddr_controller"; + mci->dev_name = SYNPS_EDAC_MOD_STRING; + mci->mod_name = SYNPS_EDAC_MOD_VER; + mci->mod_ver = "1"; + + edac_op_state = EDAC_OPSTATE_POLL; + mci->edac_check = synps_edac_check; + mci->ctl_page_to_phys = NULL; + + status = synps_edac_init_csrows(mci); + + return status; +} + +/** + * synps_edac_mc_probe - Check controller and bind driver + * @pdev: Pointer to the platform_device struct + * + * Probes a specific controller instance for binding with the driver. + * + * Return: 0 if the controller instance was successfully bound to the + * driver; otherwise, < 0 on error. + */ +static int synps_edac_mc_probe(struct platform_device *pdev) +{ + struct mem_ctl_info *mci; + struct edac_mc_layer layers[2]; + struct synps_edac_priv *priv; + int rc; + struct resource *res; + void __iomem *baseaddr; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + baseaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(baseaddr)) + return PTR_ERR(baseaddr); + + if (!synps_edac_get_eccstate(baseaddr)) { + edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n"); + return -ENXIO; + } + + layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; + layers[0].size = SYNPS_EDAC_NR_CSROWS; + layers[0].is_virt_csrow = true; + layers[1].type = EDAC_MC_LAYER_CHANNEL; + layers[1].size = SYNPS_EDAC_NR_CHANS; + layers[1].is_virt_csrow = false; + + mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, + sizeof(struct synps_edac_priv)); + if (!mci) { + edac_printk(KERN_ERR, EDAC_MC, + "Failed memory allocation for mc instance\n"); + return -ENOMEM; + } + + priv = mci->pvt_info; + priv->baseaddr = baseaddr; + rc = synps_edac_mc_init(mci, pdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_MC, + "Failed to initialize instance\n"); + goto free_edac_mc; + } + + rc = edac_mc_add_mc(mci); + if (rc) { + edac_printk(KERN_ERR, EDAC_MC, + "Failed to register with EDAC core\n"); + goto free_edac_mc; + } + + /* + * Start capturing the correctable and uncorrectable errors. A write of + * 0 starts the counters. + */ + writel(0x0, baseaddr + ECC_CTRL_OFST); + return rc; + +free_edac_mc: + edac_mc_free(mci); + + return rc; +} + +/** + * synps_edac_mc_remove - Unbind driver from controller + * @pdev: Pointer to the platform_device struct + * + * Return: Unconditionally 0 + */ +static int synps_edac_mc_remove(struct platform_device *pdev) +{ + struct mem_ctl_info *mci = platform_get_drvdata(pdev); + + edac_mc_del_mc(&pdev->dev); + edac_mc_free(mci); + + return 0; +} + +static struct of_device_id synps_edac_match[] = { + { .compatible = "xlnx,zynq-ddrc-a05", }, + { /* end of table */ } +}; + +MODULE_DEVICE_TABLE(of, synps_edac_match); + +static struct platform_driver synps_edac_mc_driver = { + .driver = { + .name = "synopsys-edac", + .of_match_table = synps_edac_match, + }, + .probe = synps_edac_mc_probe, + .remove = synps_edac_mc_remove, +}; + +module_platform_driver(synps_edac_mc_driver); + +MODULE_AUTHOR("Xilinx Inc"); +MODULE_DESCRIPTION("Synopsys DDR ECC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index f712d47f30d8..8de4da5c9ab6 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -12,11 +12,11 @@ config EFI_VARS Note that using this driver in concert with efibootmgr requires at least test release version 0.5.0-test3 or later, which is - available from Matt Domsch's website located at: + available from: Subsequent efibootmgr releases may be found at: - + config EFI_VARS_PSTORE tristate "Register efivars backend for pstore" diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 9035c1b74d58..3061bb8629dc 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -115,15 +115,24 @@ EFI_ATTR_SHOW(fw_vendor); EFI_ATTR_SHOW(runtime); EFI_ATTR_SHOW(config_table); +static ssize_t fw_platform_size_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", efi_enabled(EFI_64BIT) ? 64 : 32); +} + static struct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor); static struct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime); static struct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table); +static struct kobj_attribute efi_attr_fw_platform_size = + __ATTR_RO(fw_platform_size); static struct attribute *efi_subsys_attrs[] = { &efi_attr_systab.attr, &efi_attr_fw_vendor.attr, &efi_attr_runtime.attr, &efi_attr_config_table.attr, + &efi_attr_fw_platform_size.attr, NULL, }; @@ -272,15 +281,10 @@ static __init int match_config_table(efi_guid_t *guid, unsigned long table, efi_config_table_type_t *table_types) { - u8 str[EFI_VARIABLE_GUID_LEN + 1]; int i; if (table_types) { - efi_guid_unparse(guid, str); - for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) { - efi_guid_unparse(&table_types[i].guid, str); - if (!efi_guidcmp(*guid, table_types[i].guid)) { *(table_types[i].ptr) = table; pr_cont(" %s=0x%lx ", @@ -293,10 +297,49 @@ static __init int match_config_table(efi_guid_t *guid, return 0; } +int __init efi_config_parse_tables(void *config_tables, int count, int sz, + efi_config_table_type_t *arch_tables) +{ + void *tablep; + int i; + + tablep = config_tables; + pr_info(""); + for (i = 0; i < count; i++) { + efi_guid_t guid; + unsigned long table; + + if (efi_enabled(EFI_64BIT)) { + u64 table64; + guid = ((efi_config_table_64_t *)tablep)->guid; + table64 = ((efi_config_table_64_t *)tablep)->table; + table = table64; +#ifndef CONFIG_64BIT + if (table64 >> 32) { + pr_cont("\n"); + pr_err("Table located above 4GB, disabling EFI.\n"); + return -EINVAL; + } +#endif + } else { + guid = ((efi_config_table_32_t *)tablep)->guid; + table = ((efi_config_table_32_t *)tablep)->table; + } + + if (!match_config_table(&guid, table, common_tables)) + match_config_table(&guid, table, arch_tables); + + tablep += sz; + } + pr_cont("\n"); + set_bit(EFI_CONFIG_TABLES, &efi.flags); + return 0; +} + int __init efi_config_init(efi_config_table_type_t *arch_tables) { - void *config_tables, *tablep; - int i, sz; + void *config_tables; + int sz, ret; if (efi_enabled(EFI_64BIT)) sz = sizeof(efi_config_table_64_t); @@ -313,42 +356,11 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables) return -ENOMEM; } - tablep = config_tables; - pr_info(""); - for (i = 0; i < efi.systab->nr_tables; i++) { - efi_guid_t guid; - unsigned long table; + ret = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sz, + arch_tables); - if (efi_enabled(EFI_64BIT)) { - u64 table64; - guid = ((efi_config_table_64_t *)tablep)->guid; - table64 = ((efi_config_table_64_t *)tablep)->table; - table = table64; -#ifndef CONFIG_64BIT - if (table64 >> 32) { - pr_cont("\n"); - pr_err("Table located above 4GB, disabling EFI.\n"); - early_memunmap(config_tables, - efi.systab->nr_tables * sz); - return -EINVAL; - } -#endif - } else { - guid = ((efi_config_table_32_t *)tablep)->guid; - table = ((efi_config_table_32_t *)tablep)->table; - } - - if (!match_config_table(&guid, table, common_tables)) - match_config_table(&guid, table, arch_tables); - - tablep += sz; - } - pr_cont("\n"); early_memunmap(config_tables, efi.systab->nr_tables * sz); - - set_bit(EFI_CONFIG_TABLES, &efi.flags); - - return 0; + return ret; } #ifdef CONFIG_EFI_VARS_MODULE @@ -403,8 +415,7 @@ static int __init fdt_find_uefi_params(unsigned long node, const char *uname, u64 val; int i, len; - if (depth != 1 || - (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) + if (depth != 1 || strcmp(uname, "chosen") != 0) return 0; for (i = 0; i < ARRAY_SIZE(dt_params); i++) { diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index f256ecd8a176..7b2e0496e0c0 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c @@ -39,7 +39,7 @@ * fix locking per Peter Chubb's findings * * 25 Mar 2002 - Matt Domsch - * move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse() + * move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_to_str() * * 12 Feb 2002 - Matt Domsch * use list_for_each_safe when deleting vars. @@ -128,7 +128,7 @@ efivar_guid_read(struct efivar_entry *entry, char *buf) if (!entry || !buf) return 0; - efi_guid_unparse(&var->VendorGuid, str); + efi_guid_to_str(&var->VendorGuid, str); str += strlen(str); str += sprintf(str, "\n"); @@ -569,7 +569,7 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var) private variables from another's. */ *(short_name + strlen(short_name)) = '-'; - efi_guid_unparse(&new_var->var.VendorGuid, + efi_guid_to_str(&new_var->var.VendorGuid, short_name + strlen(short_name)); new_var->kobj.kset = efivars_kset; diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index b14bc2b9fb4d..8902f52e0998 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -24,3 +24,17 @@ lib-y := efi-stub-helper.o lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o CFLAGS_fdt.o += -I$(srctree)/scripts/dtc/libfdt/ + +# +# arm64 puts the stub in the kernel proper, which will unnecessarily retain all +# code indefinitely unless it is annotated as __init/__initdata/__initconst etc. +# So let's apply the __init annotations at the section level, by prefixing +# the section names directly. This will ensure that even all the inline string +# literals are covered. +# +extra-$(CONFIG_ARM64) := $(lib-y) +lib-$(CONFIG_ARM64) := $(patsubst %.o,%.init.o,$(lib-y)) + +OBJCOPYFLAGS := --prefix-alloc-sections=.init +$(obj)/%.init.o: $(obj)/%.o FORCE + $(call if_changed,objcopy) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index eb48a1a1a576..dcae482a9a17 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -17,10 +17,10 @@ #include "efistub.h" -static int __init efi_secureboot_enabled(efi_system_table_t *sys_table_arg) +static int efi_secureboot_enabled(efi_system_table_t *sys_table_arg) { - static efi_guid_t const var_guid __initconst = EFI_GLOBAL_VARIABLE_GUID; - static efi_char16_t const var_name[] __initconst = { + static efi_guid_t const var_guid = EFI_GLOBAL_VARIABLE_GUID; + static efi_char16_t const var_name[] = { 'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', 0 }; efi_get_variable_t *f_getvar = sys_table_arg->runtime->get_variable; @@ -164,7 +164,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table, * for both archictectures, with the arch-specific code provided in the * handle_kernel_image() function. */ -unsigned long __init efi_entry(void *handle, efi_system_table_t *sys_table, +unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, unsigned long *image_addr) { efi_loaded_image_t *image; @@ -295,3 +295,62 @@ fail_free_image: fail: return EFI_ERROR; } + +/* + * This is the base address at which to start allocating virtual memory ranges + * for UEFI Runtime Services. This is in the low TTBR0 range so that we can use + * any allocation we choose, and eliminate the risk of a conflict after kexec. + * The value chosen is the largest non-zero power of 2 suitable for this purpose + * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can + * be mapped efficiently. + */ +#define EFI_RT_VIRTUAL_BASE 0x40000000 + +/* + * efi_get_virtmap() - create a virtual mapping for the EFI memory map + * + * This function populates the virt_addr fields of all memory region descriptors + * in @memory_map whose EFI_MEMORY_RUNTIME attribute is set. Those descriptors + * are also copied to @runtime_map, and their total count is returned in @count. + */ +void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size, + unsigned long desc_size, efi_memory_desc_t *runtime_map, + int *count) +{ + u64 efi_virt_base = EFI_RT_VIRTUAL_BASE; + efi_memory_desc_t *out = runtime_map; + int l; + + for (l = 0; l < map_size; l += desc_size) { + efi_memory_desc_t *in = (void *)memory_map + l; + u64 paddr, size; + + if (!(in->attribute & EFI_MEMORY_RUNTIME)) + continue; + + /* + * Make the mapping compatible with 64k pages: this allows + * a 4k page size kernel to kexec a 64k page size kernel and + * vice versa. + */ + paddr = round_down(in->phys_addr, SZ_64K); + size = round_up(in->num_pages * EFI_PAGE_SIZE + + in->phys_addr - paddr, SZ_64K); + + /* + * Avoid wasting memory on PTEs by choosing a virtual base that + * is compatible with section mappings if this region has the + * appropriate size and physical alignment. (Sections are 2 MB + * on 4k granule kernels) + */ + if (IS_ALIGNED(in->phys_addr, SZ_2M) && size >= SZ_2M) + efi_virt_base = round_up(efi_virt_base, SZ_2M); + + in->virt_addr = efi_virt_base + in->phys_addr - paddr; + efi_virt_base += size; + + memcpy(out, in, desc_size); + out = (void *)out + desc_size; + ++*count; + } +} diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index a920fec8fe88..af5d63c7cc53 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -32,6 +32,15 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; +/* + * Allow the platform to override the allocation granularity: this allows + * systems that have the capability to run with a larger page size to deal + * with the allocations for initrd and fdt more efficiently. + */ +#ifndef EFI_ALLOC_ALIGN +#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE +#endif + struct file_info { efi_file_handle_t *handle; u64 size; @@ -66,25 +75,29 @@ efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, unsigned long key; u32 desc_version; - *map_size = sizeof(*m) * 32; -again: + *map_size = 0; + *desc_size = 0; + key = 0; + status = efi_call_early(get_memory_map, map_size, NULL, + &key, desc_size, &desc_version); + if (status != EFI_BUFFER_TOO_SMALL) + return EFI_LOAD_ERROR; + /* * Add an additional efi_memory_desc_t because we're doing an * allocation which may be in a new descriptor region. */ - *map_size += sizeof(*m); + *map_size += *desc_size; status = efi_call_early(allocate_pool, EFI_LOADER_DATA, *map_size, (void **)&m); if (status != EFI_SUCCESS) goto fail; - *desc_size = 0; - key = 0; status = efi_call_early(get_memory_map, map_size, m, &key, desc_size, &desc_version); if (status == EFI_BUFFER_TOO_SMALL) { efi_call_early(free_pool, m); - goto again; + return EFI_LOAD_ERROR; } if (status != EFI_SUCCESS) @@ -101,7 +114,7 @@ fail: } -unsigned long __init get_dram_base(efi_system_table_t *sys_table_arg) +unsigned long get_dram_base(efi_system_table_t *sys_table_arg) { efi_status_t status; unsigned long map_size; @@ -150,10 +163,10 @@ efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, * a specific address. We are doing page-based allocations, * so we must be aligned to a page. */ - if (align < EFI_PAGE_SIZE) - align = EFI_PAGE_SIZE; + if (align < EFI_ALLOC_ALIGN) + align = EFI_ALLOC_ALIGN; - nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; again: for (i = 0; i < map_size / desc_size; i++) { efi_memory_desc_t *desc; @@ -235,10 +248,10 @@ efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, * a specific address. We are doing page-based allocations, * so we must be aligned to a page. */ - if (align < EFI_PAGE_SIZE) - align = EFI_PAGE_SIZE; + if (align < EFI_ALLOC_ALIGN) + align = EFI_ALLOC_ALIGN; - nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; for (i = 0; i < map_size / desc_size; i++) { efi_memory_desc_t *desc; unsigned long m = (unsigned long)map; @@ -292,7 +305,7 @@ void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, if (!size) return; - nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; efi_call_early(free_pages, addr, nr_pages); } @@ -561,7 +574,7 @@ efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, * to the preferred address. If that fails, allocate as low * as possible while respecting the required alignment. */ - nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, nr_pages, &efi_addr); diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 304ab295ca1a..2be10984a67a 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -39,4 +39,8 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, void *get_fdt(efi_system_table_t *sys_table); +void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size, + unsigned long desc_size, efi_memory_desc_t *runtime_map, + int *count); + #endif diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index c846a9608cbd..91da56c4fd54 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -14,6 +14,8 @@ #include #include +#include "efistub.h" + efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, unsigned long orig_fdt_size, void *fdt, int new_fdt_size, char *cmdline_ptr, @@ -193,9 +195,26 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, unsigned long map_size, desc_size; u32 desc_ver; unsigned long mmap_key; - efi_memory_desc_t *memory_map; + efi_memory_desc_t *memory_map, *runtime_map; unsigned long new_fdt_size; efi_status_t status; + int runtime_entry_count = 0; + + /* + * Get a copy of the current memory map that we will use to prepare + * the input for SetVirtualAddressMap(). We don't have to worry about + * subsequent allocations adding entries, since they could not affect + * the number of EFI_MEMORY_RUNTIME regions. + */ + status = efi_get_memory_map(sys_table, &runtime_map, &map_size, + &desc_size, &desc_ver, &mmap_key); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table, "Unable to retrieve UEFI memory map.\n"); + return status; + } + + pr_efi(sys_table, + "Exiting boot services and installing virtual address map...\n"); /* * Estimate size of new FDT, and allocate memory for it. We @@ -248,12 +267,48 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, } } + /* + * Update the memory map with virtual addresses. The function will also + * populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME + * entries so that we can pass it straight into SetVirtualAddressMap() + */ + efi_get_virtmap(memory_map, map_size, desc_size, runtime_map, + &runtime_entry_count); + /* Now we are ready to exit_boot_services.*/ status = sys_table->boottime->exit_boot_services(handle, mmap_key); + if (status == EFI_SUCCESS) { + efi_set_virtual_address_map_t *svam; - if (status == EFI_SUCCESS) - return status; + /* Install the new virtual address map */ + svam = sys_table->runtime->set_virtual_address_map; + status = svam(runtime_entry_count * desc_size, desc_size, + desc_ver, runtime_map); + + /* + * We are beyond the point of no return here, so if the call to + * SetVirtualAddressMap() failed, we need to signal that to the + * incoming kernel but proceed normally otherwise. + */ + if (status != EFI_SUCCESS) { + int l; + + /* + * Set the virtual address field of all + * EFI_MEMORY_RUNTIME entries to 0. This will signal + * the incoming kernel that no virtual translation has + * been installed. + */ + for (l = 0; l < map_size; l += desc_size) { + efi_memory_desc_t *p = (void *)memory_map + l; + + if (p->attribute & EFI_MEMORY_RUNTIME) + p->virt_addr = 0; + } + } + return EFI_SUCCESS; + } pr_efi_err(sys_table, "Exit boot services failed.\n"); @@ -264,6 +319,7 @@ fail_free_new_fdt: efi_free(sys_table, new_fdt_size, *new_fdt_addr); fail: + sys_table->boottime->free_pool(runtime_map); return EFI_LOAD_ERROR; } diff --git a/drivers/firmware/efi/runtime-map.c b/drivers/firmware/efi/runtime-map.c index 018c29a26615..87b8e3b900d2 100644 --- a/drivers/firmware/efi/runtime-map.c +++ b/drivers/firmware/efi/runtime-map.c @@ -191,7 +191,7 @@ int __init efi_runtime_map_init(struct kobject *efi_kobj) return 0; out_add_entry: - for (j = i - 1; j > 0; j--) { + for (j = i - 1; j >= 0; j--) { entry = *(map_entries + j); kobject_put(&entry->kobj); } diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 633ec216e185..c1e2ca3d9a51 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -197,9 +197,16 @@ config GPIO_F7188X To compile this driver as a module, choose M here: the module will be called f7188x-gpio. +config GPIO_MB86S7X + bool "GPIO support for Fujitsu MB86S7x Platforms" + depends on ARCH_MB86S7X + help + Say yes here to support the GPIO controller in Fujitsu MB86S70 SoCs. + config GPIO_MOXART bool "MOXART GPIO support" depends on ARCH_MOXART + select GPIO_GENERIC help Select this option to enable GPIO driver for MOXA ART SoC devices. @@ -285,6 +292,7 @@ config GPIO_PXA config GPIO_RCAR tristate "Renesas R-Car GPIO" depends on ARM && (ARCH_SHMOBILE || COMPILE_TEST) + select GPIOLIB_IRQCHIP help Say yes here to support GPIO on Renesas R-Car SoCs. @@ -365,9 +373,17 @@ config GPIO_XGENE the generic flash controller's address and data pins. Say yes here to enable the GFC GPIO functionality. +config GPIO_XGENE_SB + tristate "APM X-Gene GPIO standby controller support" + depends on ARCH_XGENE && OF_GPIO + select GPIO_GENERIC + help + This driver supports the GPIO block within the APM X-Gene + Standby Domain. Say yes here to enable the GPIO functionality. + config GPIO_XILINX - bool "Xilinx GPIO support" - depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ + tristate "Xilinx GPIO support" + depends on OF_GPIO && (PPC || MICROBLAZE || ARCH_ZYNQ || X86) help Say yes here to support the Xilinx FPGA GPIO device @@ -394,25 +410,32 @@ config GPIO_VR41XX Say yes here to support the NEC VR4100 series General-purpose I/O Uint config GPIO_SCH - tristate "Intel SCH/TunnelCreek/Centerton GPIO" + tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO" depends on PCI && X86 select MFD_CORE select LPC_SCH help Say yes here to support GPIO interface on Intel Poulsbo SCH, - Intel Tunnel Creek processor or Intel Centerton processor. + Intel Tunnel Creek processor, Intel Centerton processor or + Intel Quark X1000 SoC. + The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are powered by the core power rail and are turned off during sleep modes (S3 and higher). The remaining four GPIOs are powered by the Intel SCH suspend power supply. These GPIOs remain active during S3. The suspend powered GPIOs can be used to wake the system from the Suspend-to-RAM state. + The Intel Tunnel Creek processor has 5 GPIOs powered by the core power rail and 9 from suspend power supply. + The Intel Centerton processor has a total of 30 GPIO pins. Twenty-one are powered by the core power rail and 9 from the suspend power supply. + The Intel Quark X1000 SoC has 2 GPIOs powered by the core + power well and 6 from the suspend power well. + config GPIO_ICH tristate "Intel ICH GPIO" depends on PCI && X86 @@ -450,6 +473,7 @@ config GPIO_VX855 config GPIO_GE_FPGA bool "GE FPGA based GPIO" depends on GE_FPGA + select GPIO_GENERIC help Support for common GPIO functionality provided on some GE Single Board Computers. @@ -519,6 +543,7 @@ config GPIO_MAX7300 config GPIO_MAX732X tristate "MAX7319, MAX7320-7327 I2C Port Expanders" depends on I2C + select IRQ_DOMAIN help Say yes here to support the MAX7319, MAX7320-7327 series of I2C Port Expanders. Each IO port on these chips has a fixed role of @@ -613,6 +638,7 @@ config GPIO_RC5T583 config GPIO_SX150X bool "Semtech SX150x I2C GPIO expander" depends on I2C=y + select GPIOLIB_IRQCHIP default n help Say yes here to provide support for Semtech SX150-series I2C @@ -624,6 +650,7 @@ config GPIO_SX150X config GPIO_STMPE bool "STMPE GPIOs" depends on MFD_STMPE + depends on OF_GPIO select GPIOLIB_IRQCHIP help This enables support for the GPIOs found on the STMPE I/O diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 81755f1305e6..bdda6a94d2cd 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o +obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o @@ -105,6 +106,7 @@ obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o +obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c index d3d2d1099f64..d00d81928fe8 100644 --- a/drivers/gpio/gpio-amd8111.c +++ b/drivers/gpio/gpio-amd8111.c @@ -213,6 +213,12 @@ found: goto out; } gp.pm = ioport_map(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE); + if (!gp.pm) { + dev_err(&pdev->dev, "Couldn't map io port into io memory\n"); + release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE); + err = -ENOMEM; + goto out; + } gp.pdev = pdev; gp.chip.dev = &pdev->dev; diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c index 55d4803d71b0..3d9e08f7e823 100644 --- a/drivers/gpio/gpio-crystalcove.c +++ b/drivers/gpio/gpio-crystalcove.c @@ -272,7 +272,7 @@ static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data) for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) { if (pending & BIT(gpio)) { virq = irq_find_mapping(cg->chip.irqdomain, gpio); - generic_handle_irq(virq); + handle_nested_irq(virq); } } diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c index ce3c1558cb0a..dbdb4de82c6d 100644 --- a/drivers/gpio/gpio-dln2.c +++ b/drivers/gpio/gpio-dln2.c @@ -396,6 +396,7 @@ static void dln2_gpio_event(struct platform_device *pdev, u16 echo, const void *data, int len) { int pin, irq; + const struct { __le16 count; __u8 type; diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index b4eb6a657d34..58faf04fce5d 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -469,15 +469,13 @@ dwapb_gpio_get_pdata_of(struct device *dev) if (nports == 0) return ERR_PTR(-ENODEV); - pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); - pdata->properties = kcalloc(nports, sizeof(*pp), GFP_KERNEL); - if (!pdata->properties) { - kfree(pdata); + pdata->properties = devm_kcalloc(dev, nports, sizeof(*pp), GFP_KERNEL); + if (!pdata->properties) return ERR_PTR(-ENOMEM); - } pdata->nports = nports; @@ -490,8 +488,6 @@ dwapb_gpio_get_pdata_of(struct device *dev) pp->idx >= DWAPB_MAX_PORTS) { dev_err(dev, "missing/invalid port index for %s\n", port_np->full_name); - kfree(pdata->properties); - kfree(pdata); return ERR_PTR(-EINVAL); } @@ -523,15 +519,6 @@ dwapb_gpio_get_pdata_of(struct device *dev) return pdata; } -static inline void dwapb_free_pdata_of(struct dwapb_platform_data *pdata) -{ - if (!IS_ENABLED(CONFIG_OF_GPIO) || !pdata) - return; - - kfree(pdata->properties); - kfree(pdata); -} - static int dwapb_gpio_probe(struct platform_device *pdev) { unsigned int i; @@ -540,40 +527,32 @@ static int dwapb_gpio_probe(struct platform_device *pdev) int err; struct device *dev = &pdev->dev; struct dwapb_platform_data *pdata = dev_get_platdata(dev); - bool is_pdata_alloc = !pdata; - if (is_pdata_alloc) { + if (!pdata) { pdata = dwapb_gpio_get_pdata_of(dev); if (IS_ERR(pdata)) return PTR_ERR(pdata); } - if (!pdata->nports) { - err = -ENODEV; - goto out_err; - } + if (!pdata->nports) + return -ENODEV; gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); - if (!gpio) { - err = -ENOMEM; - goto out_err; - } + if (!gpio) + return -ENOMEM; + gpio->dev = &pdev->dev; gpio->nr_ports = pdata->nports; gpio->ports = devm_kcalloc(&pdev->dev, gpio->nr_ports, sizeof(*gpio->ports), GFP_KERNEL); - if (!gpio->ports) { - err = -ENOMEM; - goto out_err; - } + if (!gpio->ports) + return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); gpio->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(gpio->regs)) { - err = PTR_ERR(gpio->regs); - goto out_err; - } + if (IS_ERR(gpio->regs)) + return PTR_ERR(gpio->regs); for (i = 0; i < gpio->nr_ports; i++) { err = dwapb_gpio_add_port(gpio, &pdata->properties[i], i); @@ -582,16 +561,12 @@ static int dwapb_gpio_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, gpio); - goto out_err; + return 0; out_unregister: dwapb_gpio_unregister(gpio); dwapb_irq_teardown(gpio); -out_err: - if (is_pdata_alloc) - dwapb_free_pdata_of(pdata); - return err; } diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c index aea5c2a53cc0..f9ac3f351753 100644 --- a/drivers/gpio/gpio-ge.c +++ b/drivers/gpio/gpio-ge.c @@ -19,9 +19,12 @@ #include #include +#include #include #include +#include #include +#include #define GEF_GPIO_DIRECT 0x00 #define GEF_GPIO_IN 0x04 @@ -33,53 +36,6 @@ #define GEF_GPIO_OVERRUN 0x1C #define GEF_GPIO_MODE 0x20 -static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - unsigned int data; - - data = ioread32be(mmchip->regs + GEF_GPIO_OUT); - if (value) - data = data | BIT(offset); - else - data = data & ~BIT(offset); - iowrite32be(data, mmchip->regs + GEF_GPIO_OUT); -} - -static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset) -{ - unsigned int data; - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); - data = data | BIT(offset); - iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); - - return 0; -} - -static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) -{ - unsigned int data; - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - /* Set value before switching to output */ - gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); - - data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); - data = data & ~BIT(offset); - iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); - - return 0; -} - -static int gef_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - return !!(ioread32be(mmchip->regs + GEF_GPIO_IN) & BIT(offset)); -} - static const struct of_device_id gef_gpio_ids[] = { { .compatible = "gef,sbc610-gpio", @@ -99,22 +55,50 @@ static int __init gef_gpio_probe(struct platform_device *pdev) { const struct of_device_id *of_id = of_match_device(gef_gpio_ids, &pdev->dev); - struct of_mm_gpio_chip *mmchip; + struct bgpio_chip *bgc; + void __iomem *regs; + int ret; - mmchip = devm_kzalloc(&pdev->dev, sizeof(*mmchip), GFP_KERNEL); - if (!mmchip) + bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL); + if (!bgc) return -ENOMEM; + regs = of_iomap(pdev->dev.of_node, 0); + if (!regs) + return -ENOMEM; + + ret = bgpio_init(bgc, &pdev->dev, 4, regs + GEF_GPIO_IN, + regs + GEF_GPIO_OUT, NULL, NULL, + regs + GEF_GPIO_DIRECT, BGPIOF_BIG_ENDIAN_BYTE_ORDER); + if (ret) { + dev_err(&pdev->dev, "bgpio_init failed\n"); + goto err0; + } + /* Setup pointers to chip functions */ - mmchip->gc.ngpio = (u16)(uintptr_t)of_id->data; - mmchip->gc.of_gpio_n_cells = 2; - mmchip->gc.direction_input = gef_gpio_dir_in; - mmchip->gc.direction_output = gef_gpio_dir_out; - mmchip->gc.get = gef_gpio_get; - mmchip->gc.set = gef_gpio_set; + bgc->gc.label = devm_kstrdup(&pdev->dev, pdev->dev.of_node->full_name, + GFP_KERNEL); + if (!bgc->gc.label) { + ret = -ENOMEM; + goto err0; + } + + bgc->gc.base = -1; + bgc->gc.ngpio = (u16)(uintptr_t)of_id->data; + bgc->gc.of_gpio_n_cells = 2; + bgc->gc.of_node = pdev->dev.of_node; /* This function adds a memory mapped GPIO chip */ - return of_mm_gpiochip_add(pdev->dev.of_node, mmchip); + ret = gpiochip_add(&bgc->gc); + if (ret) + goto err0; + + return 0; +err0: + iounmap(regs); + pr_err("%s: GPIO chip registration failed\n", + pdev->dev.of_node->full_name); + return ret; }; static struct platform_driver gef_gpio_driver = { diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 16f6115e5bdb..b92a690f5765 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -190,6 +190,79 @@ static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val) spin_unlock_irqrestore(&bgc->lock, flags); } +static void bgpio_multiple_get_masks(struct bgpio_chip *bgc, + unsigned long *mask, unsigned long *bits, + unsigned long *set_mask, + unsigned long *clear_mask) +{ + int i; + + *set_mask = 0; + *clear_mask = 0; + + for (i = 0; i < bgc->bits; i++) { + if (*mask == 0) + break; + if (__test_and_clear_bit(i, mask)) { + if (test_bit(i, bits)) + *set_mask |= bgc->pin2mask(bgc, i); + else + *clear_mask |= bgc->pin2mask(bgc, i); + } + } +} + +static void bgpio_set_multiple_single_reg(struct bgpio_chip *bgc, + unsigned long *mask, + unsigned long *bits, + void __iomem *reg) +{ + unsigned long flags; + unsigned long set_mask, clear_mask; + + spin_lock_irqsave(&bgc->lock, flags); + + bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask); + + bgc->data |= set_mask; + bgc->data &= ~clear_mask; + + bgc->write_reg(reg, bgc->data); + + spin_unlock_irqrestore(&bgc->lock, flags); +} + +static void bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_dat); +} + +static void bgpio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_set); +} + +static void bgpio_set_multiple_with_clear(struct gpio_chip *gc, + unsigned long *mask, + unsigned long *bits) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + unsigned long set_mask, clear_mask; + + bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask); + + if (set_mask) + bgc->write_reg(bgc->reg_set, set_mask); + if (clear_mask) + bgc->write_reg(bgc->reg_clr, clear_mask); +} + static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) { return 0; @@ -354,11 +427,14 @@ static int bgpio_setup_io(struct bgpio_chip *bgc, bgc->reg_set = set; bgc->reg_clr = clr; bgc->gc.set = bgpio_set_with_clear; + bgc->gc.set_multiple = bgpio_set_multiple_with_clear; } else if (set && !clr) { bgc->reg_set = set; bgc->gc.set = bgpio_set_set; + bgc->gc.set_multiple = bgpio_set_multiple_set; } else { bgc->gc.set = bgpio_set; + bgc->gc.set_multiple = bgpio_set_multiple; } bgc->gc.get = bgpio_get; diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 3a5a71050559..35a02770c8b0 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -121,7 +121,7 @@ static int grgpio_to_irq(struct gpio_chip *gc, unsigned offset) { struct grgpio_priv *priv = grgpio_gc_to_priv(gc); - if (offset > gc->ngpio) + if (offset >= gc->ngpio) return -ENXIO; if (priv->lirqs[offset].index < 0) diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 6c676225b886..a095b2393fe9 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -19,8 +19,10 @@ #include #include #include +#include #include #include +#include /* @@ -116,6 +118,22 @@ static const struct i2c_device_id max732x_id[] = { }; MODULE_DEVICE_TABLE(i2c, max732x_id); +#ifdef CONFIG_OF +static const struct of_device_id max732x_of_table[] = { + { .compatible = "maxim,max7319" }, + { .compatible = "maxim,max7320" }, + { .compatible = "maxim,max7321" }, + { .compatible = "maxim,max7322" }, + { .compatible = "maxim,max7323" }, + { .compatible = "maxim,max7324" }, + { .compatible = "maxim,max7325" }, + { .compatible = "maxim,max7326" }, + { .compatible = "maxim,max7327" }, + { } +}; +MODULE_DEVICE_TABLE(of, max732x_of_table); +#endif + struct max732x_chip { struct gpio_chip gpio_chip; @@ -132,16 +150,22 @@ struct max732x_chip { uint8_t reg_out[2]; #ifdef CONFIG_GPIO_MAX732X_IRQ - struct mutex irq_lock; - int irq_base; - uint8_t irq_mask; - uint8_t irq_mask_cur; - uint8_t irq_trig_raise; - uint8_t irq_trig_fall; - uint8_t irq_features; + struct irq_domain *irq_domain; + struct mutex irq_lock; + int irq_base; + uint8_t irq_mask; + uint8_t irq_mask_cur; + uint8_t irq_trig_raise; + uint8_t irq_trig_fall; + uint8_t irq_features; #endif }; +static inline struct max732x_chip *to_max732x(struct gpio_chip *gc) +{ + return container_of(gc, struct max732x_chip, gpio_chip); +} + static int max732x_writeb(struct max732x_chip *chip, int group_a, uint8_t val) { struct i2c_client *client; @@ -180,12 +204,10 @@ static inline int is_group_a(struct max732x_chip *chip, unsigned off) static int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off) { - struct max732x_chip *chip; + struct max732x_chip *chip = to_max732x(gc); uint8_t reg_val; int ret; - chip = container_of(gc, struct max732x_chip, gpio_chip); - ret = max732x_readb(chip, is_group_a(chip, off), ®_val); if (ret < 0) return 0; @@ -193,18 +215,17 @@ static int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off) return reg_val & (1u << (off & 0x7)); } -static void max732x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) +static void max732x_gpio_set_mask(struct gpio_chip *gc, unsigned off, int mask, + int val) { - struct max732x_chip *chip; - uint8_t reg_out, mask = 1u << (off & 0x7); + struct max732x_chip *chip = to_max732x(gc); + uint8_t reg_out; int ret; - chip = container_of(gc, struct max732x_chip, gpio_chip); - mutex_lock(&chip->lock); reg_out = (off > 7) ? chip->reg_out[1] : chip->reg_out[0]; - reg_out = (val) ? reg_out | mask : reg_out & ~mask; + reg_out = (reg_out & ~mask) | (val & mask); ret = max732x_writeb(chip, is_group_a(chip, off), reg_out); if (ret < 0) @@ -219,13 +240,31 @@ out: mutex_unlock(&chip->lock); } +static void max732x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) +{ + unsigned base = off & ~0x7; + uint8_t mask = 1u << (off & 0x7); + + max732x_gpio_set_mask(gc, base, mask, val << (off & 0x7)); +} + +static void max732x_gpio_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) +{ + unsigned mask_lo = mask[0] & 0xff; + unsigned mask_hi = (mask[0] >> 8) & 0xff; + + if (mask_lo) + max732x_gpio_set_mask(gc, 0, mask_lo, bits[0] & 0xff); + if (mask_hi) + max732x_gpio_set_mask(gc, 8, mask_hi, (bits[0] >> 8) & 0xff); +} + static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off) { - struct max732x_chip *chip; + struct max732x_chip *chip = to_max732x(gc); unsigned int mask = 1u << off; - chip = container_of(gc, struct max732x_chip, gpio_chip); - if ((mask & chip->dir_input) == 0) { dev_dbg(&chip->client->dev, "%s port %d is output only\n", chip->client->name, off); @@ -245,11 +284,9 @@ static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off) static int max732x_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val) { - struct max732x_chip *chip; + struct max732x_chip *chip = to_max732x(gc); unsigned int mask = 1u << off; - chip = container_of(gc, struct max732x_chip, gpio_chip); - if ((mask & chip->dir_output) == 0) { dev_dbg(&chip->client->dev, "%s port %d is input only\n", chip->client->name, off); @@ -321,24 +358,28 @@ static void max732x_irq_update_mask(struct max732x_chip *chip) static int max732x_gpio_to_irq(struct gpio_chip *gc, unsigned off) { - struct max732x_chip *chip; + struct max732x_chip *chip = to_max732x(gc); - chip = container_of(gc, struct max732x_chip, gpio_chip); - return chip->irq_base + off; + if (chip->irq_domain) { + return irq_create_mapping(chip->irq_domain, + chip->irq_base + off); + } else { + return -ENXIO; + } } static void max732x_irq_mask(struct irq_data *d) { struct max732x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask_cur &= ~(1 << (d->irq - chip->irq_base)); + chip->irq_mask_cur &= ~(1 << d->hwirq); } static void max732x_irq_unmask(struct irq_data *d) { struct max732x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask_cur |= 1 << (d->irq - chip->irq_base); + chip->irq_mask_cur |= 1 << d->hwirq; } static void max732x_irq_bus_lock(struct irq_data *d) @@ -352,15 +393,25 @@ static void max732x_irq_bus_lock(struct irq_data *d) static void max732x_irq_bus_sync_unlock(struct irq_data *d) { struct max732x_chip *chip = irq_data_get_irq_chip_data(d); + uint16_t new_irqs; + uint16_t level; max732x_irq_update_mask(chip); + + new_irqs = chip->irq_trig_fall | chip->irq_trig_raise; + while (new_irqs) { + level = __ffs(new_irqs); + max732x_gpio_direction_input(&chip->gpio_chip, level); + new_irqs &= ~(1 << level); + } + mutex_unlock(&chip->irq_lock); } static int max732x_irq_set_type(struct irq_data *d, unsigned int type) { struct max732x_chip *chip = irq_data_get_irq_chip_data(d); - uint16_t off = d->irq - chip->irq_base; + uint16_t off = d->hwirq; uint16_t mask = 1 << off; if (!(mask & chip->dir_input)) { @@ -385,7 +436,7 @@ static int max732x_irq_set_type(struct irq_data *d, unsigned int type) else chip->irq_trig_raise &= ~mask; - return max732x_gpio_direction_input(&chip->gpio_chip, off); + return 0; } static struct irq_chip max732x_irq_chip = { @@ -441,7 +492,7 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid) do { level = __ffs(pending); - handle_nested_irq(level + chip->irq_base); + handle_nested_irq(irq_find_mapping(chip->irq_domain, level)); pending &= ~(1 << level); } while (pending); @@ -449,6 +500,44 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid) return IRQ_HANDLED; } +static int max732x_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct max732x_chip *chip = h->host_data; + + if (!(chip->dir_input & (1 << hw))) { + dev_err(&chip->client->dev, + "Attempt to map output line as IRQ line: %lu\n", + hw); + return -EPERM; + } + + irq_set_chip_data(virq, chip); + irq_set_chip_and_handler(virq, &max732x_irq_chip, + handle_edge_irq); + irq_set_nested_thread(virq, 1); +#ifdef CONFIG_ARM + /* ARM needs us to explicitly flag the IRQ as valid + * and will set them noprobe when we do so. */ + set_irq_flags(virq, IRQF_VALID); +#else + irq_set_noprobe(virq); +#endif + + return 0; +} + +static struct irq_domain_ops max732x_irq_domain_ops = { + .map = max732x_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static void max732x_irq_teardown(struct max732x_chip *chip) +{ + if (chip->client->irq && chip->irq_domain) + irq_domain_remove(chip->irq_domain); +} + static int max732x_irq_setup(struct max732x_chip *chip, const struct i2c_device_id *id) { @@ -457,28 +546,19 @@ static int max732x_irq_setup(struct max732x_chip *chip, int has_irq = max732x_features[id->driver_data] >> 32; int ret; - if (pdata->irq_base && has_irq != INT_NONE) { - int lvl; - - chip->irq_base = pdata->irq_base; + if (((pdata && pdata->irq_base) || client->irq) + && has_irq != INT_NONE) { + if (pdata) + chip->irq_base = pdata->irq_base; chip->irq_features = has_irq; mutex_init(&chip->irq_lock); - for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { - int irq = lvl + chip->irq_base; - - if (!(chip->dir_input & (1 << lvl))) - continue; - - irq_set_chip_data(irq, chip); - irq_set_chip_and_handler(irq, &max732x_irq_chip, - handle_edge_irq); - irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif + chip->irq_domain = irq_domain_add_simple(client->dev.of_node, + chip->gpio_chip.ngpio, chip->irq_base, + &max732x_irq_domain_ops, chip); + if (!chip->irq_domain) { + dev_err(&client->dev, "Failed to create IRQ domain\n"); + return -ENOMEM; } ret = request_threaded_irq(client->irq, @@ -498,15 +578,10 @@ static int max732x_irq_setup(struct max732x_chip *chip, return 0; out_failed: - chip->irq_base = 0; + max732x_irq_teardown(chip); return ret; } -static void max732x_irq_teardown(struct max732x_chip *chip) -{ - if (chip->irq_base) - free_irq(chip->client->irq, chip); -} #else /* CONFIG_GPIO_MAX732X_IRQ */ static int max732x_irq_setup(struct max732x_chip *chip, const struct i2c_device_id *id) @@ -515,7 +590,7 @@ static int max732x_irq_setup(struct max732x_chip *chip, struct max732x_platform_data *pdata = dev_get_platdata(&client->dev); int has_irq = max732x_features[id->driver_data] >> 32; - if (pdata->irq_base && has_irq != INT_NONE) + if (((pdata && pdata->irq_base) || client->irq) && has_irq != INT_NONE) dev_warn(&client->dev, "interrupt support not compiled in\n"); return 0; @@ -562,6 +637,7 @@ static int max732x_setup_gpio(struct max732x_chip *chip, if (chip->dir_output) { gc->direction_output = max732x_gpio_direction_output; gc->set = max732x_gpio_set_value; + gc->set_multiple = max732x_gpio_set_multiple; } gc->get = max732x_gpio_get_value; gc->can_sleep = true; @@ -574,28 +650,47 @@ static int max732x_setup_gpio(struct max732x_chip *chip, return port; } +static struct max732x_platform_data *of_gpio_max732x(struct device *dev) +{ + struct max732x_platform_data *pdata; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->gpio_base = -1; + + return pdata; +} + static int max732x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max732x_platform_data *pdata; + struct device_node *node; struct max732x_chip *chip; struct i2c_client *c; uint16_t addr_a, addr_b; int ret, nr_port; pdata = dev_get_platdata(&client->dev); - if (pdata == NULL) { + node = client->dev.of_node; + + if (!pdata && node) + pdata = of_gpio_max732x(&client->dev); + + if (!pdata) { dev_dbg(&client->dev, "no platform data\n"); return -EINVAL; } - chip = devm_kzalloc(&client->dev, sizeof(struct max732x_chip), - GFP_KERNEL); + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->client = client; nr_port = max732x_setup_gpio(chip, id, pdata->gpio_base); + chip->gpio_chip.dev = &client->dev; addr_a = (client->addr & 0x0f) | 0x60; addr_b = (client->addr & 0x0f) | 0x50; @@ -643,7 +738,7 @@ static int max732x_probe(struct i2c_client *client, if (ret) goto out_failed; - if (pdata->setup) { + if (pdata && pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, chip->gpio_chip.ngpio, pdata->context); if (ret < 0) @@ -664,9 +759,10 @@ static int max732x_remove(struct i2c_client *client) { struct max732x_platform_data *pdata = dev_get_platdata(&client->dev); struct max732x_chip *chip = i2c_get_clientdata(client); - int ret; - if (pdata->teardown) { + if (pdata && pdata->teardown) { + int ret; + ret = pdata->teardown(client, chip->gpio_chip.base, chip->gpio_chip.ngpio, pdata->context); if (ret < 0) { @@ -689,8 +785,9 @@ static int max732x_remove(struct i2c_client *client) static struct i2c_driver max732x_driver = { .driver = { - .name = "max732x", - .owner = THIS_MODULE, + .name = "max732x", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max732x_of_table), }, .probe = max732x_probe, .remove = max732x_remove, diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c new file mode 100644 index 000000000000..21b1ce5abdfe --- /dev/null +++ b/drivers/gpio/gpio-mb86s7x.c @@ -0,0 +1,232 @@ +/* + * linux/drivers/gpio/gpio-mb86s7x.c + * + * Copyright (C) 2015 Fujitsu Semiconductor Limited + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Only first 8bits of a register correspond to each pin, + * so there are 4 registers for 32 pins. + */ +#define PDR(x) (0x0 + x / 8 * 4) +#define DDR(x) (0x10 + x / 8 * 4) +#define PFR(x) (0x20 + x / 8 * 4) + +#define OFFSET(x) BIT((x) % 8) + +struct mb86s70_gpio_chip { + struct gpio_chip gc; + void __iomem *base; + struct clk *clk; + spinlock_t lock; +}; + +static inline struct mb86s70_gpio_chip *chip_to_mb86s70(struct gpio_chip *gc) +{ + return container_of(gc, struct mb86s70_gpio_chip, gc); +} + +static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + PFR(gpio)); + val &= ~OFFSET(gpio); + writel(val, gchip->base + PFR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); + + return 0; +} + +static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned gpio) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + PFR(gpio)); + val |= OFFSET(gpio); + writel(val, gchip->base + PFR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); +} + +static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned gpio) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + unsigned char val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + DDR(gpio)); + val &= ~OFFSET(gpio); + writel(val, gchip->base + DDR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); + + return 0; +} + +static int mb86s70_gpio_direction_output(struct gpio_chip *gc, + unsigned gpio, int value) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + unsigned char val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + PDR(gpio)); + if (value) + val |= OFFSET(gpio); + else + val &= ~OFFSET(gpio); + writel(val, gchip->base + PDR(gpio)); + + val = readl(gchip->base + DDR(gpio)); + val |= OFFSET(gpio); + writel(val, gchip->base + DDR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); + + return 0; +} + +static int mb86s70_gpio_get(struct gpio_chip *gc, unsigned gpio) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + + return !!(readl(gchip->base + PDR(gpio)) & OFFSET(gpio)); +} + +static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value) +{ + struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); + unsigned long flags; + unsigned char val; + + spin_lock_irqsave(&gchip->lock, flags); + + val = readl(gchip->base + PDR(gpio)); + if (value) + val |= OFFSET(gpio); + else + val &= ~OFFSET(gpio); + writel(val, gchip->base + PDR(gpio)); + + spin_unlock_irqrestore(&gchip->lock, flags); +} + +static int mb86s70_gpio_probe(struct platform_device *pdev) +{ + struct mb86s70_gpio_chip *gchip; + struct resource *res; + int ret; + + gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL); + if (gchip == NULL) + return -ENOMEM; + + platform_set_drvdata(pdev, gchip); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gchip->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gchip->base)) + return PTR_ERR(gchip->base); + + gchip->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(gchip->clk)) + return PTR_ERR(gchip->clk); + + clk_prepare_enable(gchip->clk); + + spin_lock_init(&gchip->lock); + + gchip->gc.direction_output = mb86s70_gpio_direction_output; + gchip->gc.direction_input = mb86s70_gpio_direction_input; + gchip->gc.request = mb86s70_gpio_request; + gchip->gc.free = mb86s70_gpio_free; + gchip->gc.get = mb86s70_gpio_get; + gchip->gc.set = mb86s70_gpio_set; + gchip->gc.label = dev_name(&pdev->dev); + gchip->gc.ngpio = 32; + gchip->gc.owner = THIS_MODULE; + gchip->gc.dev = &pdev->dev; + gchip->gc.base = -1; + + platform_set_drvdata(pdev, gchip); + + ret = gpiochip_add(&gchip->gc); + if (ret) { + dev_err(&pdev->dev, "couldn't register gpio driver\n"); + clk_disable_unprepare(gchip->clk); + } + + return ret; +} + +static int mb86s70_gpio_remove(struct platform_device *pdev) +{ + struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev); + + gpiochip_remove(&gchip->gc); + clk_disable_unprepare(gchip->clk); + + return 0; +} + +static const struct of_device_id mb86s70_gpio_dt_ids[] = { + { .compatible = "fujitsu,mb86s70-gpio" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids); + +static struct platform_driver mb86s70_gpio_driver = { + .driver = { + .name = "mb86s70-gpio", + .of_match_table = mb86s70_gpio_dt_ids, + }, + .probe = mb86s70_gpio_probe, + .remove = mb86s70_gpio_remove, +}; + +static int __init mb86s70_gpio_init(void) +{ + return platform_driver_register(&mb86s70_gpio_driver); +} +module_init(mb86s70_gpio_init); + +MODULE_DESCRIPTION("MB86S7x GPIO Driver"); +MODULE_ALIAS("platform:mb86s70-gpio"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index da9c316059bc..eea5d7e578c9 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -801,9 +801,11 @@ static int mcp230xx_probe(struct i2c_client *client, client->irq = irq_of_parse_and_map(client->dev.of_node, 0); } else { pdata = dev_get_platdata(&client->dev); - if (!pdata || !gpio_is_valid(pdata->base)) { - dev_dbg(&client->dev, "invalid platform data\n"); - return -EINVAL; + if (!pdata) { + pdata = devm_kzalloc(&client->dev, + sizeof(struct mcp23s08_platform_data), + GFP_KERNEL); + pdata->base = -1; } } @@ -924,10 +926,11 @@ static int mcp23s08_probe(struct spi_device *spi) } else { type = spi_get_device_id(spi)->driver_data; pdata = dev_get_platdata(&spi->dev); - if (!pdata || !gpio_is_valid(pdata->base)) { - dev_dbg(&spi->dev, - "invalid or missing platform data\n"); - return -EINVAL; + if (!pdata) { + pdata = devm_kzalloc(&spi->dev, + sizeof(struct mcp23s08_platform_data), + GFP_KERNEL); + pdata->base = -1; } for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c index f228b1ce0ce0..f67ef2283d64 100644 --- a/drivers/gpio/gpio-mm-lantiq.c +++ b/drivers/gpio/gpio-mm-lantiq.c @@ -104,35 +104,34 @@ static void ltq_mm_save_regs(struct of_mm_gpio_chip *mm_gc) static int ltq_mm_probe(struct platform_device *pdev) { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct ltq_mm *chip; - const __be32 *shadow; - int ret = 0; + u32 shadow; - if (!res) { - dev_err(&pdev->dev, "failed to get memory resource\n"); - return -ENOENT; - } - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; + platform_set_drvdata(pdev, chip); + chip->mmchip.gc.ngpio = 16; - chip->mmchip.gc.label = "gpio-mm-ltq"; chip->mmchip.gc.direction_output = ltq_mm_dir_out; chip->mmchip.gc.set = ltq_mm_set; chip->mmchip.save_regs = ltq_mm_save_regs; /* store the shadow value if one was passed by the devicetree */ - shadow = of_get_property(pdev->dev.of_node, "lantiq,shadow", NULL); - if (shadow) - chip->shadow = be32_to_cpu(*shadow); + if (!of_property_read_u32(pdev->dev.of_node, "lantiq,shadow", &shadow)) + chip->shadow = shadow; - ret = of_mm_gpiochip_add(pdev->dev.of_node, &chip->mmchip); - if (ret) - kfree(chip); - return ret; + return of_mm_gpiochip_add(pdev->dev.of_node, &chip->mmchip); +} + +static int ltq_mm_remove(struct platform_device *pdev) +{ + struct ltq_mm *chip = platform_get_drvdata(pdev); + + of_mm_gpiochip_remove(&chip->mmchip); + + return 0; } static const struct of_device_id ltq_mm_match[] = { @@ -143,6 +142,7 @@ MODULE_DEVICE_TABLE(of, ltq_mm_match); static struct platform_driver ltq_mm_driver = { .probe = ltq_mm_probe, + .remove = ltq_mm_remove, .driver = { .name = "gpio-mm-ltq", .of_match_table = ltq_mm_match, @@ -155,3 +155,9 @@ static int __init ltq_mm_init(void) } subsys_initcall(ltq_mm_init); + +static void __exit ltq_mm_exit(void) +{ + platform_driver_unregister(<q_mm_driver); +} +module_exit(ltq_mm_exit); diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c index 31e2551ed903..c3ab46e595da 100644 --- a/drivers/gpio/gpio-moxart.c +++ b/drivers/gpio/gpio-moxart.c @@ -23,21 +23,12 @@ #include #include #include +#include #define GPIO_DATA_OUT 0x00 #define GPIO_DATA_IN 0x04 #define GPIO_PIN_DIRECTION 0x08 -struct moxart_gpio_chip { - struct gpio_chip gpio; - void __iomem *base; -}; - -static inline struct moxart_gpio_chip *to_moxart_gpio(struct gpio_chip *chip) -{ - return container_of(chip, struct moxart_gpio_chip, gpio); -} - static int moxart_gpio_request(struct gpio_chip *chip, unsigned offset) { return pinctrl_request_gpio(offset); @@ -48,90 +39,60 @@ static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset) pinctrl_free_gpio(offset); } -static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_DATA_OUT; - u32 reg = readl(ioaddr); - - if (value) - reg = reg | BIT(offset); - else - reg = reg & ~BIT(offset); - - writel(reg, ioaddr); -} - static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset) { - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - u32 ret = readl(gc->base + GPIO_PIN_DIRECTION); + struct bgpio_chip *bgc = to_bgpio_chip(chip); + u32 ret = bgc->read_reg(bgc->reg_dir); if (ret & BIT(offset)) - return !!(readl(gc->base + GPIO_DATA_OUT) & BIT(offset)); + return !!(bgc->read_reg(bgc->reg_set) & BIT(offset)); else - return !!(readl(gc->base + GPIO_DATA_IN) & BIT(offset)); + return !!(bgc->read_reg(bgc->reg_dat) & BIT(offset)); } -static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; - - writel(readl(ioaddr) & ~BIT(offset), ioaddr); - return 0; -} - -static int moxart_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; - - moxart_gpio_set(chip, offset, value); - writel(readl(ioaddr) | BIT(offset), ioaddr); - return 0; -} - -static struct gpio_chip moxart_template_chip = { - .label = "moxart-gpio", - .request = moxart_gpio_request, - .free = moxart_gpio_free, - .direction_input = moxart_gpio_direction_input, - .direction_output = moxart_gpio_direction_output, - .set = moxart_gpio_set, - .get = moxart_gpio_get, - .ngpio = 32, - .owner = THIS_MODULE, -}; - static int moxart_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res; - struct moxart_gpio_chip *mgc; + struct bgpio_chip *bgc; + void __iomem *base; int ret; - mgc = devm_kzalloc(dev, sizeof(*mgc), GFP_KERNEL); - if (!mgc) + bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL); + if (!bgc) return -ENOMEM; - mgc->gpio = moxart_template_chip; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mgc->base = devm_ioremap_resource(dev, res); - if (IS_ERR(mgc->base)) - return PTR_ERR(mgc->base); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); - mgc->gpio.dev = dev; + ret = bgpio_init(bgc, dev, 4, base + GPIO_DATA_IN, + base + GPIO_DATA_OUT, NULL, + base + GPIO_PIN_DIRECTION, NULL, 0); + if (ret) { + dev_err(&pdev->dev, "bgpio_init failed\n"); + return ret; + } - ret = gpiochip_add(&mgc->gpio); + bgc->gc.label = "moxart-gpio"; + bgc->gc.request = moxart_gpio_request; + bgc->gc.free = moxart_gpio_free; + bgc->gc.get = moxart_gpio_get; + bgc->data = bgc->read_reg(bgc->reg_set); + bgc->gc.base = 0; + bgc->gc.ngpio = 32; + bgc->gc.dev = dev; + bgc->gc.owner = THIS_MODULE; + + ret = gpiochip_add(&bgc->gc); if (ret) { dev_err(dev, "%s: gpiochip_add failed\n", dev->of_node->full_name); return ret; } - return 0; + return ret; } static const struct of_device_id moxart_gpio_match[] = { diff --git a/drivers/gpio/gpio-mpc5200.c b/drivers/gpio/gpio-mpc5200.c index 8ce6c9510035..4c542153e923 100644 --- a/drivers/gpio/gpio-mpc5200.c +++ b/drivers/gpio/gpio-mpc5200.c @@ -155,10 +155,12 @@ static int mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev) struct gpio_chip *gc; int ret; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&ofdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; + platform_set_drvdata(ofdev, chip); + gc = &chip->mmchip.gc; gc->ngpio = 8; @@ -181,7 +183,11 @@ static int mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev) static int mpc52xx_gpiochip_remove(struct platform_device *ofdev) { - return -EBUSY; + struct mpc52xx_gpiochip *chip = platform_get_drvdata(ofdev); + + of_mm_gpiochip_remove(&chip->mmchip); + + return 0; } static const struct of_device_id mpc52xx_wkup_gpiochip_match[] = { @@ -314,10 +320,12 @@ static int mpc52xx_simple_gpiochip_probe(struct platform_device *ofdev) struct mpc52xx_gpio __iomem *regs; int ret; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&ofdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; + platform_set_drvdata(ofdev, chip); + gc = &chip->mmchip.gc; gc->ngpio = 32; @@ -363,11 +371,16 @@ static int __init mpc52xx_gpio_init(void) return 0; } - /* Make sure we get initialised before anyone else tries to use us */ subsys_initcall(mpc52xx_gpio_init); -/* No exit call at the moment as we cannot unregister of gpio chips */ +static void __exit mpc52xx_gpio_exit(void) +{ + platform_driver_unregister(&mpc52xx_wkup_gpiochip_driver); + + platform_driver_unregister(&mpc52xx_simple_gpiochip_driver); +} +module_exit(mpc52xx_gpio_exit); MODULE_DESCRIPTION("Freescale MPC52xx gpio driver"); MODULE_AUTHOR("Sascha Hauer #include #include +#include #include #include #include @@ -39,6 +40,7 @@ struct mpc8xxx_gpio_chip { */ u32 data; struct irq_domain *irq; + unsigned int irqn; const void *of_dev_id_data; }; @@ -342,20 +344,20 @@ static struct of_device_id mpc8xxx_gpio_ids[] __initdata = { {} }; -static void __init mpc8xxx_add_controller(struct device_node *np) +static int mpc8xxx_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct mpc8xxx_gpio_chip *mpc8xxx_gc; struct of_mm_gpio_chip *mm_gc; struct gpio_chip *gc; const struct of_device_id *id; - unsigned hwirq; int ret; - mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL); - if (!mpc8xxx_gc) { - ret = -ENOMEM; - goto err; - } + mpc8xxx_gc = devm_kzalloc(&pdev->dev, sizeof(*mpc8xxx_gc), GFP_KERNEL); + if (!mpc8xxx_gc) + return -ENOMEM; + + platform_set_drvdata(pdev, mpc8xxx_gc); spin_lock_init(&mpc8xxx_gc->lock); @@ -375,16 +377,16 @@ static void __init mpc8xxx_add_controller(struct device_node *np) ret = of_mm_gpiochip_add(np, mm_gc); if (ret) - goto err; + return ret; - hwirq = irq_of_parse_and_map(np, 0); - if (hwirq == NO_IRQ) - goto skip_irq; + mpc8xxx_gc->irqn = irq_of_parse_and_map(np, 0); + if (mpc8xxx_gc->irqn == NO_IRQ) + return 0; mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS, &mpc8xxx_gpio_irq_ops, mpc8xxx_gc); if (!mpc8xxx_gc->irq) - goto skip_irq; + return 0; id = of_match_node(mpc8xxx_gpio_ids, np); if (id) @@ -394,27 +396,39 @@ static void __init mpc8xxx_add_controller(struct device_node *np) out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); out_be32(mm_gc->regs + GPIO_IMR, 0); - irq_set_handler_data(hwirq, mpc8xxx_gc); - irq_set_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade); - -skip_irq: - return; - -err: - pr_err("%s: registration failed with status %d\n", - np->full_name, ret); - kfree(mpc8xxx_gc); - - return; -} - -static int __init mpc8xxx_add_gpiochips(void) -{ - struct device_node *np; - - for_each_matching_node(np, mpc8xxx_gpio_ids) - mpc8xxx_add_controller(np); + irq_set_handler_data(mpc8xxx_gc->irqn, mpc8xxx_gc); + irq_set_chained_handler(mpc8xxx_gc->irqn, mpc8xxx_gpio_irq_cascade); return 0; } -arch_initcall(mpc8xxx_add_gpiochips); + +static int mpc8xxx_remove(struct platform_device *pdev) +{ + struct mpc8xxx_gpio_chip *mpc8xxx_gc = platform_get_drvdata(pdev); + + if (mpc8xxx_gc->irq) { + irq_set_handler_data(mpc8xxx_gc->irqn, NULL); + irq_set_chained_handler(mpc8xxx_gc->irqn, NULL); + irq_domain_remove(mpc8xxx_gc->irq); + } + + of_mm_gpiochip_remove(&mpc8xxx_gc->mm_gc); + + return 0; +} + +static struct platform_driver mpc8xxx_plat_driver = { + .probe = mpc8xxx_probe, + .remove = mpc8xxx_remove, + .driver = { + .name = "gpio-mpc8xxx", + .of_match_table = mpc8xxx_gpio_ids, + }, +}; + +static int __init mpc8xxx_init(void) +{ + return platform_driver_register(&mpc8xxx_plat_driver); +} + +arch_initcall(mpc8xxx_init); diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 7bc3e9b288f3..d0bc123c7975 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -59,7 +59,7 @@ #define GPIO_LEVEL_MASK_OFF 0x001c /* The MV78200 has per-CPU registers for edge mask and level mask */ -#define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18) +#define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18) #define GPIO_LEVEL_MASK_MV78200_OFF(cpu) ((cpu) ? 0x34 : 0x1C) /* The Armada XP has per-CPU registers for interrupt cause, interrupt @@ -69,11 +69,11 @@ #define GPIO_EDGE_MASK_ARMADAXP_OFF(cpu) (0x10 + (cpu) * 0x4) #define GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu) (0x20 + (cpu) * 0x4) -#define MVEBU_GPIO_SOC_VARIANT_ORION 0x1 -#define MVEBU_GPIO_SOC_VARIANT_MV78200 0x2 +#define MVEBU_GPIO_SOC_VARIANT_ORION 0x1 +#define MVEBU_GPIO_SOC_VARIANT_MV78200 0x2 #define MVEBU_GPIO_SOC_VARIANT_ARMADAXP 0x3 -#define MVEBU_MAX_GPIO_PER_BANK 32 +#define MVEBU_MAX_GPIO_PER_BANK 32 struct mvebu_gpio_chip { struct gpio_chip chip; @@ -82,9 +82,9 @@ struct mvebu_gpio_chip { void __iomem *percpu_membase; int irqbase; struct irq_domain *domain; - int soc_variant; + int soc_variant; - /* Used to preserve GPIO registers accross suspend/resume */ + /* Used to preserve GPIO registers across suspend/resume */ u32 out_reg; u32 io_conf_reg; u32 blink_en_reg; @@ -107,7 +107,8 @@ static inline void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip) return mvchip->membase + GPIO_BLINK_EN_OFF; } -static inline void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip) +static inline void __iomem * +mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_IO_CONF_OFF; } @@ -117,12 +118,14 @@ static inline void __iomem *mvebu_gpioreg_in_pol(struct mvebu_gpio_chip *mvchip) return mvchip->membase + GPIO_IN_POL_OFF; } -static inline void __iomem *mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip) +static inline void __iomem * +mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_DATA_IN_OFF; } -static inline void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip) +static inline void __iomem * +mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip) { int cpu; @@ -132,13 +135,15 @@ static inline void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvc return mvchip->membase + GPIO_EDGE_CAUSE_OFF; case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: cpu = smp_processor_id(); - return mvchip->percpu_membase + GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu); + return mvchip->percpu_membase + + GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu); default: BUG(); } } -static inline void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip) +static inline void __iomem * +mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip) { int cpu; @@ -150,7 +155,8 @@ static inline void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvch return mvchip->membase + GPIO_EDGE_MASK_MV78200_OFF(cpu); case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: cpu = smp_processor_id(); - return mvchip->percpu_membase + GPIO_EDGE_MASK_ARMADAXP_OFF(cpu); + return mvchip->percpu_membase + + GPIO_EDGE_MASK_ARMADAXP_OFF(cpu); default: BUG(); } @@ -168,7 +174,8 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip) return mvchip->membase + GPIO_LEVEL_MASK_MV78200_OFF(cpu); case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: cpu = smp_processor_id(); - return mvchip->percpu_membase + GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu); + return mvchip->percpu_membase + + GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu); default: BUG(); } @@ -364,22 +371,22 @@ static void mvebu_gpio_level_irq_unmask(struct irq_data *d) * value of the line or the opposite value. * * Level IRQ handlers: DATA_IN is used directly as cause register. - * Interrupt are masked by LEVEL_MASK registers. + * Interrupt are masked by LEVEL_MASK registers. * Edge IRQ handlers: Change in DATA_IN are latched in EDGE_CAUSE. - * Interrupt are masked by EDGE_MASK registers. + * Interrupt are masked by EDGE_MASK registers. * Both-edge handlers: Similar to regular Edge handlers, but also swaps - * the polarity to catch the next line transaction. - * This is a race condition that might not perfectly - * work on some use cases. + * the polarity to catch the next line transaction. + * This is a race condition that might not perfectly + * work on some use cases. * * Every eight GPIO lines are grouped (OR'ed) before going up to main * cause register. * - * EDGE cause mask - * data-in /--------| |-----| |----\ - * -----| |----- ---- to main cause reg - * X \----------------| |----/ - * polarity LEVEL mask + * EDGE cause mask + * data-in /--------| |-----| |----\ + * -----| |----- ---- to main cause reg + * X \----------------| |----/ + * polarity LEVEL mask * ****************************************************************************/ @@ -394,9 +401,8 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin = d->hwirq; u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & (1 << pin); - if (!u) { + if (!u) return -EINVAL; - } type &= IRQ_TYPE_SENSE_MASK; if (type == IRQ_TYPE_NONE) @@ -529,13 +535,13 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) (data_in ^ in_pol) & msk ? "hi" : "lo", in_pol & msk ? "lo" : "hi"); if (!((edg_msk | lvl_msk) & msk)) { - seq_printf(s, " disabled\n"); + seq_puts(s, " disabled\n"); continue; } if (edg_msk & msk) - seq_printf(s, " edge "); + seq_puts(s, " edge "); if (lvl_msk & msk) - seq_printf(s, " level"); + seq_puts(s, " level"); seq_printf(s, " (%s)\n", cause & msk ? "pending" : "clear "); } } @@ -546,15 +552,15 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) static const struct of_device_id mvebu_gpio_of_match[] = { { .compatible = "marvell,orion-gpio", - .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, + .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, }, { .compatible = "marvell,mv78200-gpio", - .data = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200, + .data = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200, }, { .compatible = "marvell,armadaxp-gpio", - .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP, + .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP, }, { /* sentinel */ @@ -661,6 +667,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) unsigned int ngpios; int soc_variant; int i, cpu, id; + int err; match = of_match_device(mvebu_gpio_of_match, &pdev->dev); if (match) @@ -668,7 +675,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) else soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; - mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL); + mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), + GFP_KERNEL); if (!mvchip) return -ENOMEM; @@ -767,8 +775,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) * interrupt handlers, with each handler dealing with 8 GPIO * pins. */ for (i = 0; i < 4; i++) { - int irq; - irq = platform_get_irq(pdev, i); + int irq = platform_get_irq(pdev, i); + if (irq < 0) continue; irq_set_handler_data(irq, mvchip); @@ -778,14 +786,16 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1); if (mvchip->irqbase < 0) { dev_err(&pdev->dev, "no irqs\n"); - return mvchip->irqbase; + err = mvchip->irqbase; + goto err_gpiochip_add; } gc = irq_alloc_generic_chip("mvebu_gpio_irq", 2, mvchip->irqbase, mvchip->membase, handle_level_irq); if (!gc) { dev_err(&pdev->dev, "Cannot allocate generic irq_chip\n"); - return -ENOMEM; + err = -ENOMEM; + goto err_gpiochip_add; } gc->private = mvchip; @@ -816,18 +826,26 @@ static int mvebu_gpio_probe(struct platform_device *pdev) if (!mvchip->domain) { dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n", mvchip->chip.label); - irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST, - IRQ_LEVEL | IRQ_NOPROBE); - kfree(gc); - return -ENODEV; + err = -ENODEV; + goto err_generic_chip; } return 0; + +err_generic_chip: + irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST, + IRQ_LEVEL | IRQ_NOPROBE); + kfree(gc); + +err_gpiochip_add: + gpiochip_remove(&mvchip->chip); + + return err; } static struct platform_driver mvebu_gpio_driver = { .driver = { - .name = "mvebu-gpio", + .name = "mvebu-gpio", .of_match_table = mvebu_gpio_of_match, }, .probe = mvebu_gpio_probe, diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 30646cfe0efa..f476ae2eb0b3 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -88,6 +88,8 @@ struct gpio_bank { #define BANK_USED(bank) (bank->mod_usage || bank->irq_usage) #define LINE_USED(line, offset) (line & (BIT(offset))) +static void omap_gpio_unmask_irq(struct irq_data *d); + static int omap_irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq) { return bank->chip.base + gpio_irq; @@ -477,6 +479,16 @@ static int omap_gpio_is_input(struct gpio_bank *bank, int mask) return readl_relaxed(reg) & mask; } +static void omap_gpio_init_irq(struct gpio_bank *bank, unsigned gpio, + unsigned offset) +{ + if (!LINE_USED(bank->mod_usage, offset)) { + omap_enable_gpio_module(bank, offset); + omap_set_gpio_direction(bank, offset, 1); + } + bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio)); +} + static int omap_gpio_irq_type(struct irq_data *d, unsigned type) { struct gpio_bank *bank = omap_irq_data_get_bank(d); @@ -506,15 +518,11 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) spin_lock_irqsave(&bank->lock, flags); offset = GPIO_INDEX(bank, gpio); retval = omap_set_gpio_triggering(bank, offset, type); - if (!LINE_USED(bank->mod_usage, offset)) { - omap_enable_gpio_module(bank, offset); - omap_set_gpio_direction(bank, offset, 1); - } else if (!omap_gpio_is_input(bank, BIT(offset))) { + omap_gpio_init_irq(bank, gpio, offset); + if (!omap_gpio_is_input(bank, BIT(offset))) { spin_unlock_irqrestore(&bank->lock, flags); return -EINVAL; } - - bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio)); spin_unlock_irqrestore(&bank->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) @@ -792,6 +800,24 @@ exit: pm_runtime_put(bank->dev); } +static unsigned int omap_gpio_irq_startup(struct irq_data *d) +{ + struct gpio_bank *bank = omap_irq_data_get_bank(d); + unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq); + unsigned long flags; + unsigned offset = GPIO_INDEX(bank, gpio); + + if (!BANK_USED(bank)) + pm_runtime_get_sync(bank->dev); + + spin_lock_irqsave(&bank->lock, flags); + omap_gpio_init_irq(bank, gpio, offset); + spin_unlock_irqrestore(&bank->lock, flags); + omap_gpio_unmask_irq(d); + + return 0; +} + static void omap_gpio_irq_shutdown(struct irq_data *d) { struct gpio_bank *bank = omap_irq_data_get_bank(d); @@ -1181,6 +1207,7 @@ static int omap_gpio_probe(struct platform_device *pdev) if (!irqc) return -ENOMEM; + irqc->irq_startup = omap_gpio_irq_startup, irqc->irq_shutdown = omap_gpio_irq_shutdown, irqc->irq_ack = omap_gpio_ack_irq, irqc->irq_mask = omap_gpio_mask_irq, diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index ad3feec0075e..2fdb04b6f101 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -27,8 +28,6 @@ #include #include -#include - /* * We handle the GPIOs by banks, each bank covers up to 32 GPIOs with * one set of registers. The register offsets are organized below: @@ -42,9 +41,12 @@ * BANK 4 - 0x0104 0x0110 0x011C 0x0128 0x0134 0x0140 0x014C * BANK 5 - 0x0108 0x0114 0x0120 0x012C 0x0138 0x0144 0x0150 * + * BANK 6 - 0x0200 0x020C 0x0218 0x0224 0x0230 0x023C 0x0248 + * * NOTE: * BANK 3 is only available on PXA27x and later processors. - * BANK 4 and 5 are only available on PXA935 + * BANK 4 and 5 are only available on PXA935, PXA1928 + * BANK 6 is only available on PXA1928 */ #define GPLR_OFFSET 0x00 @@ -57,7 +59,8 @@ #define GAFR_OFFSET 0x54 #define ED_MASK_OFFSET 0x9C /* GPIO edge detection for AP side */ -#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2)) +#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : ((n) > 5 ? 0x200 : 0x100) \ + + (((n) % 3) << 2)) int pxa_last_gpio; static int irq_base; @@ -93,6 +96,7 @@ enum pxa_gpio_type { PXA93X_GPIO, MMP_GPIO = 0x10, MMP2_GPIO, + PXA1928_GPIO, }; struct pxa_gpio_id { @@ -140,6 +144,11 @@ static struct pxa_gpio_id mmp2_id = { .gpio_nums = 192, }; +static struct pxa_gpio_id pxa1928_id = { + .type = PXA1928_GPIO, + .gpio_nums = 224, +}; + #define for_each_gpio_chip(i, c) \ for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++) @@ -487,6 +496,7 @@ static int pxa_gpio_nums(struct platform_device *pdev) case PXA93X_GPIO: case MMP_GPIO: case MMP2_GPIO: + case PXA1928_GPIO: gpio_type = pxa_id->type; count = pxa_id->gpio_nums - 1; break; @@ -506,6 +516,7 @@ static const struct of_device_id pxa_gpio_dt_ids[] = { { .compatible = "marvell,pxa93x-gpio", .data = &pxa93x_id, }, { .compatible = "marvell,mmp-gpio", .data = &mmp_id, }, { .compatible = "marvell,mmp2-gpio", .data = &mmp2_id, }, + { .compatible = "marvell,pxa1928-gpio", .data = &pxa1928_id, }, {} }; @@ -629,19 +640,18 @@ static int pxa_gpio_probe(struct platform_device *pdev) } if (!use_of) { -#ifdef CONFIG_ARCH_PXA - irq = gpio_to_irq(0); - irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, - handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler); - - irq = gpio_to_irq(1); - irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, - handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler); -#endif + if (irq0 > 0) { + irq = gpio_to_irq(0); + irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + if (irq1 > 0) { + irq = gpio_to_irq(1); + irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } for (irq = gpio_to_irq(gpio_offset); irq <= gpio_to_irq(pxa_last_gpio); irq++) { @@ -649,13 +659,13 @@ static int pxa_gpio_probe(struct platform_device *pdev) handle_edge_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - } else { - if (irq0 > 0) - irq_set_chained_handler(irq0, pxa_gpio_demux_handler); - if (irq1 > 0) - irq_set_chained_handler(irq1, pxa_gpio_demux_handler); } + if (irq0 > 0) + irq_set_chained_handler(irq0, pxa_gpio_demux_handler); + if (irq1 > 0) + irq_set_chained_handler(irq1, pxa_gpio_demux_handler); + irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler); return 0; } @@ -668,6 +678,7 @@ static const struct platform_device_id gpio_id_table[] = { { "pxa93x-gpio", (unsigned long)&pxa93x_id }, { "mmp-gpio", (unsigned long)&mmp_id }, { "mmp2-gpio", (unsigned long)&mmp2_id }, + { "pxa1928-gpio", (unsigned long)&pxa1928_id }, { }, }; diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 584484e3f1e3..c49522efa7b3 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -38,7 +37,6 @@ struct gpio_rcar_priv { struct platform_device *pdev; struct gpio_chip gpio_chip; struct irq_chip irq_chip; - struct irq_domain *irq_domain; }; #define IOINTSEL 0x00 @@ -82,14 +80,18 @@ static void gpio_rcar_modify_bit(struct gpio_rcar_priv *p, int offs, static void gpio_rcar_irq_disable(struct irq_data *d) { - struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv, + gpio_chip); gpio_rcar_write(p, INTMSK, ~BIT(irqd_to_hwirq(d))); } static void gpio_rcar_irq_enable(struct irq_data *d) { - struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv, + gpio_chip); gpio_rcar_write(p, MSKCLR, BIT(irqd_to_hwirq(d))); } @@ -131,7 +133,9 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type) { - struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv, + gpio_chip); unsigned int hwirq = irqd_to_hwirq(d); dev_dbg(&p->pdev->dev, "sense irq = %d, type = %d\n", hwirq, type); @@ -175,7 +179,8 @@ static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id) gpio_rcar_read(p, INTMSK))) { offset = __ffs(pending); gpio_rcar_write(p, INTCLR, BIT(offset)); - generic_handle_irq(irq_find_mapping(p->irq_domain, offset)); + generic_handle_irq(irq_find_mapping(p->gpio_chip.irqdomain, + offset)); irqs_handled++; } @@ -265,29 +270,6 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset, return 0; } -static int gpio_rcar_to_irq(struct gpio_chip *chip, unsigned offset) -{ - return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset); -} - -static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct gpio_rcar_priv *p = h->host_data; - - dev_dbg(&p->pdev->dev, "map hw irq = %d, irq = %d\n", (int)hwirq, irq); - - irq_set_chip_data(irq, h->host_data); - irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); /* kill me now */ - return 0; -} - -static struct irq_domain_ops gpio_rcar_irq_domain_ops = { - .map = gpio_rcar_irq_domain_map, - .xlate = irq_domain_xlate_twocell, -}; - struct gpio_rcar_info { bool has_both_edge_trigger; }; @@ -372,10 +354,8 @@ static int gpio_rcar_probe(struct platform_device *pdev) int ret; p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); - if (!p) { - ret = -ENOMEM; - goto err0; - } + if (!p) + return -ENOMEM; p->pdev = pdev; spin_lock_init(&p->lock); @@ -413,7 +393,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) gpio_chip->get = gpio_rcar_get; gpio_chip->direction_output = gpio_rcar_direction_output; gpio_chip->set = gpio_rcar_set; - gpio_chip->to_irq = gpio_rcar_to_irq; gpio_chip->label = name; gpio_chip->dev = dev; gpio_chip->owner = THIS_MODULE; @@ -428,16 +407,19 @@ static int gpio_rcar_probe(struct platform_device *pdev) irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; - p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, - p->config.number_of_pins, - p->config.irq_base, - &gpio_rcar_irq_domain_ops, p); - if (!p->irq_domain) { - ret = -ENXIO; - dev_err(dev, "cannot initialize irq domain\n"); + ret = gpiochip_add(gpio_chip); + if (ret) { + dev_err(dev, "failed to add GPIO controller\n"); goto err0; } + ret = gpiochip_irqchip_add(&p->gpio_chip, irq_chip, p->config.irq_base, + handle_level_irq, IRQ_TYPE_NONE); + if (ret) { + dev_err(dev, "cannot add irqchip\n"); + goto err1; + } + if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler, IRQF_SHARED, name, p)) { dev_err(dev, "failed to request IRQ\n"); @@ -445,17 +427,11 @@ static int gpio_rcar_probe(struct platform_device *pdev) goto err1; } - ret = gpiochip_add(gpio_chip); - if (ret) { - dev_err(dev, "failed to add GPIO controller\n"); - goto err1; - } - dev_info(dev, "driving %d GPIOs\n", p->config.number_of_pins); /* warn in case of mismatch if irq base is specified */ if (p->config.irq_base) { - ret = irq_find_mapping(p->irq_domain, 0); + ret = irq_find_mapping(p->gpio_chip.irqdomain, 0); if (p->config.irq_base != ret) dev_warn(dev, "irq base mismatch (%u/%u)\n", p->config.irq_base, ret); @@ -471,7 +447,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) return 0; err1: - irq_domain_remove(p->irq_domain); + gpiochip_remove(&p->gpio_chip); err0: pm_runtime_put(dev); pm_runtime_disable(dev); @@ -484,7 +460,6 @@ static int gpio_rcar_remove(struct platform_device *pdev) gpiochip_remove(&p->gpio_chip); - irq_domain_remove(p->irq_domain); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index a90be34e4d5c..bec397a60204 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -50,7 +51,7 @@ static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int static int sa1100_to_irq(struct gpio_chip *chip, unsigned offset) { - return offset < 11 ? (IRQ_GPIO0 + offset) : (IRQ_GPIO11 - 11 + offset); + return IRQ_GPIO0 + offset; } static struct gpio_chip sa1100_gpio_chip = { @@ -64,7 +65,203 @@ static struct gpio_chip sa1100_gpio_chip = { .ngpio = GPIO_MAX + 1, }; +/* + * SA1100 GPIO edge detection for IRQs: + * IRQs are generated on Falling-Edge, Rising-Edge, or both. + * Use this instead of directly setting GRER/GFER. + */ +static int GPIO_IRQ_rising_edge; +static int GPIO_IRQ_falling_edge; +static int GPIO_IRQ_mask; + +static int sa1100_gpio_type(struct irq_data *d, unsigned int type) +{ + unsigned int mask; + + mask = BIT(d->hwirq); + + if (type == IRQ_TYPE_PROBE) { + if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask) + return 0; + type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + } + + if (type & IRQ_TYPE_EDGE_RISING) + GPIO_IRQ_rising_edge |= mask; + else + GPIO_IRQ_rising_edge &= ~mask; + if (type & IRQ_TYPE_EDGE_FALLING) + GPIO_IRQ_falling_edge |= mask; + else + GPIO_IRQ_falling_edge &= ~mask; + + GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; + GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; + + return 0; +} + +/* + * GPIO IRQs must be acknowledged. + */ +static void sa1100_gpio_ack(struct irq_data *d) +{ + GEDR = BIT(d->hwirq); +} + +static void sa1100_gpio_mask(struct irq_data *d) +{ + unsigned int mask = BIT(d->hwirq); + + GPIO_IRQ_mask &= ~mask; + + GRER &= ~mask; + GFER &= ~mask; +} + +static void sa1100_gpio_unmask(struct irq_data *d) +{ + unsigned int mask = BIT(d->hwirq); + + GPIO_IRQ_mask |= mask; + + GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; + GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; +} + +static int sa1100_gpio_wake(struct irq_data *d, unsigned int on) +{ + if (on) + PWER |= BIT(d->hwirq); + else + PWER &= ~BIT(d->hwirq); + return 0; +} + +/* + * This is for GPIO IRQs + */ +static struct irq_chip sa1100_gpio_irq_chip = { + .name = "GPIO", + .irq_ack = sa1100_gpio_ack, + .irq_mask = sa1100_gpio_mask, + .irq_unmask = sa1100_gpio_unmask, + .irq_set_type = sa1100_gpio_type, + .irq_set_wake = sa1100_gpio_wake, +}; + +static int sa1100_gpio_irqdomain_map(struct irq_domain *d, + unsigned int irq, irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &sa1100_gpio_irq_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + + return 0; +} + +static struct irq_domain_ops sa1100_gpio_irqdomain_ops = { + .map = sa1100_gpio_irqdomain_map, + .xlate = irq_domain_xlate_onetwocell, +}; + +static struct irq_domain *sa1100_gpio_irqdomain; + +/* + * IRQ 0-11 (GPIO) handler. We enter here with the + * irq_controller_lock held, and IRQs disabled. Decode the IRQ + * and call the handler. + */ +static void +sa1100_gpio_handler(unsigned int irq, struct irq_desc *desc) +{ + unsigned int mask; + + mask = GEDR; + do { + /* + * clear down all currently active IRQ sources. + * We will be processing them all. + */ + GEDR = mask; + + irq = IRQ_GPIO0; + do { + if (mask & 1) + generic_handle_irq(irq); + mask >>= 1; + irq++; + } while (mask); + + mask = GEDR; + } while (mask); +} + +static int sa1100_gpio_suspend(void) +{ + /* + * Set the appropriate edges for wakeup. + */ + GRER = PWER & GPIO_IRQ_rising_edge; + GFER = PWER & GPIO_IRQ_falling_edge; + + /* + * Clear any pending GPIO interrupts. + */ + GEDR = GEDR; + + return 0; +} + +static void sa1100_gpio_resume(void) +{ + GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; + GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; +} + +static struct syscore_ops sa1100_gpio_syscore_ops = { + .suspend = sa1100_gpio_suspend, + .resume = sa1100_gpio_resume, +}; + +static int __init sa1100_gpio_init_devicefs(void) +{ + register_syscore_ops(&sa1100_gpio_syscore_ops); + return 0; +} + +device_initcall(sa1100_gpio_init_devicefs); + void __init sa1100_init_gpio(void) { + /* clear all GPIO edge detects */ + GFER = 0; + GRER = 0; + GEDR = -1; + gpiochip_add(&sa1100_gpio_chip); + + sa1100_gpio_irqdomain = irq_domain_add_simple(NULL, + 28, IRQ_GPIO0, + &sa1100_gpio_irqdomain_ops, NULL); + + /* + * Install handlers for GPIO 0-10 edge detect interrupts + */ + irq_set_chained_handler(IRQ_GPIO0_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO1_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO2_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO3_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO4_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO5_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO6_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO7_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO8_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO9_SC, sa1100_gpio_handler); + irq_set_chained_handler(IRQ_GPIO10_SC, sa1100_gpio_handler); + /* + * Install handler for GPIO 11-27 edge detect interrupts + */ + irq_set_chained_handler(IRQ_GPIO11_27, sa1100_gpio_handler); + } diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 0a0cf1307d2f..b72906f5b999 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -41,7 +41,7 @@ struct sch_gpio { unsigned short resume_base; }; -#define to_sch_gpio(c) container_of(c, struct sch_gpio, chip) +#define to_sch_gpio(gc) container_of(gc, struct sch_gpio, chip) static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio, unsigned reg) @@ -63,75 +63,59 @@ static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio) return gpio % 8; } -static void sch_gpio_enable(struct sch_gpio *sch, unsigned gpio) -{ - unsigned short offset, bit; - u8 enable; - - spin_lock(&sch->lock); - - offset = sch_gpio_offset(sch, gpio, GEN); - bit = sch_gpio_bit(sch, gpio); - - enable = inb(sch->iobase + offset); - if (!(enable & (1 << bit))) - outb(enable | (1 << bit), sch->iobase + offset); - - spin_unlock(&sch->lock); -} - -static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num) +static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg) { struct sch_gpio *sch = to_sch_gpio(gc); - u8 curr_dirs; unsigned short offset, bit; + u8 reg_val; + + offset = sch_gpio_offset(sch, gpio, reg); + bit = sch_gpio_bit(sch, gpio); + + reg_val = !!(inb(sch->iobase + offset) & BIT(bit)); + + return reg_val; +} + +static void sch_gpio_reg_set(struct gpio_chip *gc, unsigned gpio, unsigned reg, + int val) +{ + struct sch_gpio *sch = to_sch_gpio(gc); + unsigned short offset, bit; + u8 reg_val; + + offset = sch_gpio_offset(sch, gpio, reg); + bit = sch_gpio_bit(sch, gpio); + + reg_val = inb(sch->iobase + offset); + + if (val) + outb(reg_val | BIT(bit), sch->iobase + offset); + else + outb((reg_val & ~BIT(bit)), sch->iobase + offset); +} + +static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num) +{ + struct sch_gpio *sch = to_sch_gpio(gc); spin_lock(&sch->lock); - - offset = sch_gpio_offset(sch, gpio_num, GIO); - bit = sch_gpio_bit(sch, gpio_num); - - curr_dirs = inb(sch->iobase + offset); - - if (!(curr_dirs & (1 << bit))) - outb(curr_dirs | (1 << bit), sch->iobase + offset); - + sch_gpio_reg_set(gc, gpio_num, GIO, 1); spin_unlock(&sch->lock); return 0; } static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num) { - struct sch_gpio *sch = to_sch_gpio(gc); - int res; - unsigned short offset, bit; - - offset = sch_gpio_offset(sch, gpio_num, GLV); - bit = sch_gpio_bit(sch, gpio_num); - - res = !!(inb(sch->iobase + offset) & (1 << bit)); - - return res; + return sch_gpio_reg_get(gc, gpio_num, GLV); } static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val) { struct sch_gpio *sch = to_sch_gpio(gc); - u8 curr_vals; - unsigned short offset, bit; spin_lock(&sch->lock); - - offset = sch_gpio_offset(sch, gpio_num, GLV); - bit = sch_gpio_bit(sch, gpio_num); - - curr_vals = inb(sch->iobase + offset); - - if (val) - outb(curr_vals | (1 << bit), sch->iobase + offset); - else - outb((curr_vals & ~(1 << bit)), sch->iobase + offset); - + sch_gpio_reg_set(gc, gpio_num, GLV, val); spin_unlock(&sch->lock); } @@ -139,18 +123,9 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num, int val) { struct sch_gpio *sch = to_sch_gpio(gc); - u8 curr_dirs; - unsigned short offset, bit; spin_lock(&sch->lock); - - offset = sch_gpio_offset(sch, gpio_num, GIO); - bit = sch_gpio_bit(sch, gpio_num); - - curr_dirs = inb(sch->iobase + offset); - if (curr_dirs & (1 << bit)) - outb(curr_dirs & ~(1 << bit), sch->iobase + offset); - + sch_gpio_reg_set(gc, gpio_num, GIO, 0); spin_unlock(&sch->lock); /* @@ -209,13 +184,13 @@ static int sch_gpio_probe(struct platform_device *pdev) * GPIO7 is configured by the CMC as SLPIOVR * Enable GPIO[9:8] core powered gpios explicitly */ - sch_gpio_enable(sch, 8); - sch_gpio_enable(sch, 9); + sch_gpio_reg_set(&sch->chip, 8, GEN, 1); + sch_gpio_reg_set(&sch->chip, 9, GEN, 1); /* * SUS_GPIO[2:0] enabled by default * Enable SUS_GPIO3 resume powered gpio explicitly */ - sch_gpio_enable(sch, 13); + sch_gpio_reg_set(&sch->chip, 13, GEN, 1); break; case PCI_DEVICE_ID_INTEL_ITC_LPC: @@ -230,6 +205,12 @@ static int sch_gpio_probe(struct platform_device *pdev) sch->chip.ngpio = 30; break; + case PCI_DEVICE_ID_INTEL_QUARK_X1000_ILB: + sch->core_base = 0; + sch->resume_base = 2; + sch->chip.ngpio = 8; + break; + default: return -ENODEV; } diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 85c5b1974294..dabfb99dddef 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -30,7 +30,7 @@ struct stmpe_gpio { struct stmpe *stmpe; struct device *dev; struct mutex irq_lock; - unsigned norequest_mask; + u32 norequest_mask; /* Caches of interrupt control registers for bus_lock */ u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; @@ -340,13 +340,10 @@ static int stmpe_gpio_probe(struct platform_device *pdev) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); struct device_node *np = pdev->dev.of_node; - struct stmpe_gpio_platform_data *pdata; struct stmpe_gpio *stmpe_gpio; int ret; int irq = 0; - pdata = stmpe->pdata->gpio; - irq = platform_get_irq(pdev, 0); stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL); @@ -360,19 +357,14 @@ static int stmpe_gpio_probe(struct platform_device *pdev) stmpe_gpio->chip = template_chip; stmpe_gpio->chip.ngpio = stmpe->num_gpios; stmpe_gpio->chip.dev = &pdev->dev; -#ifdef CONFIG_OF stmpe_gpio->chip.of_node = np; -#endif stmpe_gpio->chip.base = -1; if (IS_ENABLED(CONFIG_DEBUG_FS)) stmpe_gpio->chip.dbg_show = stmpe_dbg_show; - if (pdata) - stmpe_gpio->norequest_mask = pdata->norequest_mask; - else if (np) - of_property_read_u32(np, "st,norequest-mask", - &stmpe_gpio->norequest_mask); + of_property_read_u32(np, "st,norequest-mask", + &stmpe_gpio->norequest_mask); if (irq < 0) dev_info(&pdev->dev, @@ -414,9 +406,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev) NULL); } - if (pdata && pdata->setup) - pdata->setup(stmpe, stmpe_gpio->chip.base); - platform_set_drvdata(pdev, stmpe_gpio); return 0; @@ -433,15 +422,9 @@ static int stmpe_gpio_remove(struct platform_device *pdev) { struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev); struct stmpe *stmpe = stmpe_gpio->stmpe; - struct stmpe_gpio_platform_data *pdata = stmpe->pdata->gpio; - - if (pdata && pdata->remove) - pdata->remove(stmpe, stmpe_gpio->chip.base); gpiochip_remove(&stmpe_gpio->chip); - stmpe_disable(stmpe, STMPE_BLOCK_GPIO); - kfree(stmpe_gpio); return 0; diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index bce6c6108f20..458d9d7952b8 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -23,23 +23,51 @@ #include #include #include +#include +#include +#include +#include +#include #define NO_UPDATE_PENDING -1 -struct sx150x_device_data { - u8 reg_pullup; - u8 reg_pulldn; +/* The chip models of sx150x */ +#define SX150X_456 0 +#define SX150X_789 1 + +struct sx150x_456_pri { + u8 reg_pld_mode; + u8 reg_pld_table0; + u8 reg_pld_table1; + u8 reg_pld_table2; + u8 reg_pld_table3; + u8 reg_pld_table4; + u8 reg_advance; +}; + +struct sx150x_789_pri { u8 reg_drain; u8 reg_polarity; + u8 reg_clock; + u8 reg_misc; + u8 reg_reset; + u8 ngpios; +}; + +struct sx150x_device_data { + u8 model; + u8 reg_pullup; + u8 reg_pulldn; u8 reg_dir; u8 reg_data; u8 reg_irq_mask; u8 reg_irq_src; u8 reg_sense; - u8 reg_clock; - u8 reg_misc; - u8 reg_reset; u8 ngpios; + union { + struct sx150x_456_pri x456; + struct sx150x_789_pri x789; + } pri; }; struct sx150x_chip { @@ -59,44 +87,79 @@ struct sx150x_chip { static const struct sx150x_device_data sx150x_devices[] = { [0] = { /* sx1508q */ - .reg_pullup = 0x03, - .reg_pulldn = 0x04, - .reg_drain = 0x05, - .reg_polarity = 0x06, - .reg_dir = 0x07, - .reg_data = 0x08, - .reg_irq_mask = 0x09, - .reg_irq_src = 0x0c, - .reg_sense = 0x0b, - .reg_clock = 0x0f, - .reg_misc = 0x10, - .reg_reset = 0x7d, - .ngpios = 8 + .model = SX150X_789, + .reg_pullup = 0x03, + .reg_pulldn = 0x04, + .reg_dir = 0x07, + .reg_data = 0x08, + .reg_irq_mask = 0x09, + .reg_irq_src = 0x0c, + .reg_sense = 0x0b, + .pri.x789 = { + .reg_drain = 0x05, + .reg_polarity = 0x06, + .reg_clock = 0x0f, + .reg_misc = 0x10, + .reg_reset = 0x7d, + }, + .ngpios = 8, }, [1] = { /* sx1509q */ - .reg_pullup = 0x07, - .reg_pulldn = 0x09, - .reg_drain = 0x0b, - .reg_polarity = 0x0d, - .reg_dir = 0x0f, - .reg_data = 0x11, - .reg_irq_mask = 0x13, - .reg_irq_src = 0x19, - .reg_sense = 0x17, - .reg_clock = 0x1e, - .reg_misc = 0x1f, - .reg_reset = 0x7d, - .ngpios = 16 + .model = SX150X_789, + .reg_pullup = 0x07, + .reg_pulldn = 0x09, + .reg_dir = 0x0f, + .reg_data = 0x11, + .reg_irq_mask = 0x13, + .reg_irq_src = 0x19, + .reg_sense = 0x17, + .pri.x789 = { + .reg_drain = 0x0b, + .reg_polarity = 0x0d, + .reg_clock = 0x1e, + .reg_misc = 0x1f, + .reg_reset = 0x7d, + }, + .ngpios = 16 + }, + [2] = { /* sx1506q */ + .model = SX150X_456, + .reg_pullup = 0x05, + .reg_pulldn = 0x07, + .reg_dir = 0x03, + .reg_data = 0x01, + .reg_irq_mask = 0x09, + .reg_irq_src = 0x0f, + .reg_sense = 0x0d, + .pri.x456 = { + .reg_pld_mode = 0x21, + .reg_pld_table0 = 0x23, + .reg_pld_table1 = 0x25, + .reg_pld_table2 = 0x27, + .reg_pld_table3 = 0x29, + .reg_pld_table4 = 0x2b, + .reg_advance = 0xad, + }, + .ngpios = 16 }, }; static const struct i2c_device_id sx150x_id[] = { {"sx1508q", 0}, {"sx1509q", 1}, + {"sx1506q", 2}, {} }; MODULE_DEVICE_TABLE(i2c, sx150x_id); +static const struct of_device_id sx150x_of_match[] = { + { .compatible = "semtech,sx1508q" }, + { .compatible = "semtech,sx1509q" }, + { .compatible = "semtech,sx1506q" }, + {}, +}; +MODULE_DEVICE_TABLE(of, sx150x_of_match); + static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val) { s32 err = i2c_smbus_write_byte_data(client, reg, val); @@ -191,7 +254,7 @@ static int sx150x_get_io(struct sx150x_chip *chip, unsigned offset) static void sx150x_set_oscio(struct sx150x_chip *chip, int val) { sx150x_i2c_write(chip->client, - chip->dev_cfg->reg_clock, + chip->dev_cfg->pri.x789.reg_clock, (val ? 0x1f : 0x10)); } @@ -293,27 +356,11 @@ static int sx150x_gpio_direction_output(struct gpio_chip *gc, return status; } -static int sx150x_gpio_to_irq(struct gpio_chip *gc, unsigned offset) -{ - struct sx150x_chip *chip; - - chip = container_of(gc, struct sx150x_chip, gpio_chip); - - if (offset >= chip->dev_cfg->ngpios) - return -EINVAL; - - if (chip->irq_base < 0) - return -EINVAL; - - return chip->irq_base + offset; -} - static void sx150x_irq_mask(struct irq_data *d) { struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); - unsigned n; + unsigned n = d->hwirq; - n = d->irq - chip->irq_base; chip->irq_masked |= (1 << n); chip->irq_update = n; } @@ -321,9 +368,8 @@ static void sx150x_irq_mask(struct irq_data *d) static void sx150x_irq_unmask(struct irq_data *d) { struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); - unsigned n; + unsigned n = d->hwirq; - n = d->irq - chip->irq_base; chip->irq_masked &= ~(1 << n); chip->irq_update = n; } @@ -336,7 +382,7 @@ static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type) if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) return -EINVAL; - n = d->irq - chip->irq_base; + n = d->hwirq; if (flow_type & IRQ_TYPE_EDGE_RISING) val |= 0x1; @@ -371,7 +417,9 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id) val); for (n = 0; n < 8; ++n) { if (val & (1 << n)) { - sub_irq = chip->irq_base + (i * 8) + n; + sub_irq = irq_find_mapping( + chip->gpio_chip.irqdomain, + (i * 8) + n); handle_nested_irq(sub_irq); ++nhandled; } @@ -401,7 +449,7 @@ static void sx150x_irq_bus_sync_unlock(struct irq_data *d) /* Avoid updates if nothing changed */ if (chip->dev_sense == chip->irq_sense && - chip->dev_sense == chip->irq_masked) + chip->dev_masked == chip->irq_masked) goto out; chip->dev_sense = chip->irq_sense; @@ -428,15 +476,19 @@ static void sx150x_init_chip(struct sx150x_chip *chip, chip->client = client; chip->dev_cfg = &sx150x_devices[driver_data]; + chip->gpio_chip.dev = &client->dev; chip->gpio_chip.label = client->name; chip->gpio_chip.direction_input = sx150x_gpio_direction_input; chip->gpio_chip.direction_output = sx150x_gpio_direction_output; chip->gpio_chip.get = sx150x_gpio_get; chip->gpio_chip.set = sx150x_gpio_set; - chip->gpio_chip.to_irq = sx150x_gpio_to_irq; chip->gpio_chip.base = pdata->gpio_base; chip->gpio_chip.can_sleep = true; chip->gpio_chip.ngpio = chip->dev_cfg->ngpios; +#ifdef CONFIG_OF_GPIO + chip->gpio_chip.of_node = client->dev.of_node; + chip->gpio_chip.of_gpio_n_cells = 2; +#endif if (pdata->oscio_is_gpo) ++chip->gpio_chip.ngpio; @@ -470,13 +522,13 @@ static int sx150x_reset(struct sx150x_chip *chip) int err; err = i2c_smbus_write_byte_data(chip->client, - chip->dev_cfg->reg_reset, + chip->dev_cfg->pri.x789.reg_reset, 0x12); if (err < 0) return err; err = i2c_smbus_write_byte_data(chip->client, - chip->dev_cfg->reg_reset, + chip->dev_cfg->pri.x789.reg_reset, 0x34); return err; } @@ -492,9 +544,14 @@ static int sx150x_init_hw(struct sx150x_chip *chip, return err; } - err = sx150x_i2c_write(chip->client, - chip->dev_cfg->reg_misc, - 0x01); + if (chip->dev_cfg->model == SX150X_789) + err = sx150x_i2c_write(chip->client, + chip->dev_cfg->pri.x789.reg_misc, + 0x01); + else + err = sx150x_i2c_write(chip->client, + chip->dev_cfg->pri.x456.reg_advance, + 0x04); if (err < 0) return err; @@ -508,15 +565,27 @@ static int sx150x_init_hw(struct sx150x_chip *chip, if (err < 0) return err; - err = sx150x_init_io(chip, chip->dev_cfg->reg_drain, - pdata->io_open_drain_ena); - if (err < 0) - return err; + if (chip->dev_cfg->model == SX150X_789) { + err = sx150x_init_io(chip, + chip->dev_cfg->pri.x789.reg_drain, + pdata->io_open_drain_ena); + if (err < 0) + return err; + + err = sx150x_init_io(chip, + chip->dev_cfg->pri.x789.reg_polarity, + pdata->io_polarity); + if (err < 0) + return err; + } else { + /* Set all pins to work in normal mode */ + err = sx150x_init_io(chip, + chip->dev_cfg->pri.x456.reg_pld_mode, + 0); + if (err < 0) + return err; + } - err = sx150x_init_io(chip, chip->dev_cfg->reg_polarity, - pdata->io_polarity); - if (err < 0) - return err; if (pdata->oscio_is_gpo) sx150x_set_oscio(chip, 0); @@ -529,31 +598,24 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip, int irq_base) { int err; - unsigned n; - unsigned irq; chip->irq_summary = irq_summary; chip->irq_base = irq_base; - for (n = 0; n < chip->dev_cfg->ngpios; ++n) { - irq = irq_base + n; - irq_set_chip_data(irq, chip); - irq_set_chip_and_handler(irq, &chip->irq_chip, handle_edge_irq); - irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif + /* Add gpio chip to irq subsystem */ + err = gpiochip_irqchip_add(&chip->gpio_chip, + &chip->irq_chip, chip->irq_base, + handle_edge_irq, IRQ_TYPE_EDGE_BOTH); + if (err) { + dev_err(&chip->client->dev, + "could not connect irqchip to gpiochip\n"); + return err; } err = devm_request_threaded_irq(&chip->client->dev, - irq_summary, - NULL, - sx150x_irq_thread_fn, - IRQF_SHARED | IRQF_TRIGGER_FALLING, - chip->irq_chip.name, - chip); + irq_summary, NULL, sx150x_irq_thread_fn, + IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_FALLING, + chip->irq_chip.name, chip); if (err < 0) { chip->irq_summary = -1; chip->irq_base = -1; @@ -562,17 +624,6 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip, return err; } -static void sx150x_remove_irq_chip(struct sx150x_chip *chip) -{ - unsigned n; - unsigned irq; - - for (n = 0; n < chip->dev_cfg->ngpios; ++n) { - irq = chip->irq_base + n; - irq_set_chip_and_handler(irq, NULL, NULL); - } -} - static int sx150x_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -626,16 +677,14 @@ static int sx150x_remove(struct i2c_client *client) chip = i2c_get_clientdata(client); gpiochip_remove(&chip->gpio_chip); - if (chip->irq_summary >= 0) - sx150x_remove_irq_chip(chip); - return 0; } static struct i2c_driver sx150x_driver = { .driver = { .name = "sx150x", - .owner = THIS_MODULE + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(sx150x_of_match), }, .probe = sx150x_probe, .remove = sx150x_remove, diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index abdcf58935f5..11aed2671065 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -232,16 +232,13 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) static int tc3589x_gpio_probe(struct platform_device *pdev) { struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); - struct tc3589x_gpio_platform_data *pdata; struct device_node *np = pdev->dev.of_node; struct tc3589x_gpio *tc3589x_gpio; int ret; int irq; - pdata = tc3589x->pdata->gpio; - - if (!(pdata || np)) { - dev_err(&pdev->dev, "No platform data or Device Tree found\n"); + if (!np) { + dev_err(&pdev->dev, "No Device Tree node found\n"); return -EINVAL; } @@ -305,9 +302,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) irq, NULL); - if (pdata && pdata->setup) - pdata->setup(tc3589x, tc3589x_gpio->chip.base); - platform_set_drvdata(pdev, tc3589x_gpio); return 0; @@ -316,11 +310,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) static int tc3589x_gpio_remove(struct platform_device *pdev) { struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev); - struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; - struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio; - - if (pdata && pdata->remove) - pdata->remove(tc3589x, tc3589x_gpio->chip.base); gpiochip_remove(&tc3589x_gpio->chip); diff --git a/drivers/gpio/gpio-tz1090-pdc.c b/drivers/gpio/gpio-tz1090-pdc.c index d7536226b847..ede7e403ffde 100644 --- a/drivers/gpio/gpio-tz1090-pdc.c +++ b/drivers/gpio/gpio-tz1090-pdc.c @@ -190,7 +190,7 @@ static int tz1090_pdc_gpio_probe(struct platform_device *pdev) /* Ioremap the registers */ priv->reg = devm_ioremap(&pdev->dev, res_regs->start, - res_regs->end - res_regs->start); + resource_size(res_regs)); if (!priv->reg) { dev_err(&pdev->dev, "unable to ioremap registers\n"); return -ENOMEM; diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c index e3024bbba447..445660adc898 100644 --- a/drivers/gpio/gpio-tz1090.c +++ b/drivers/gpio/gpio-tz1090.c @@ -573,7 +573,7 @@ static int tz1090_gpio_probe(struct platform_device *pdev) /* Ioremap the registers */ priv.reg = devm_ioremap(&pdev->dev, res_regs->start, - res_regs->end - res_regs->start); + resource_size(res_regs)); if (!priv.reg) { dev_err(&pdev->dev, "unable to ioremap registers\n"); return -ENOMEM; diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 4ee4cee832ec..971c73964ef1 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -278,7 +278,6 @@ static int vf610_gpio_probe(struct platform_device *pdev) static struct platform_driver vf610_gpio_driver = { .driver = { .name = "gpio-vf610", - .owner = THIS_MODULE, .of_match_table = vf610_gpio_dt_ids, }, .probe = vf610_gpio_probe, diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c index 9d21d2fcc327..57b470d5b39e 100644 --- a/drivers/gpio/gpio-vx855.c +++ b/drivers/gpio/gpio-vx855.c @@ -52,8 +52,6 @@ struct vx855_gpio { spinlock_t lock; u32 io_gpi; u32 io_gpo; - bool gpi_reserved; - bool gpo_reserved; }; /* resolve a GPIx into the corresponding bit position */ @@ -224,14 +222,13 @@ static int vx855gpio_probe(struct platform_device *pdev) struct resource *res_gpi; struct resource *res_gpo; struct vx855_gpio *vg; - int ret; res_gpi = platform_get_resource(pdev, IORESOURCE_IO, 0); res_gpo = platform_get_resource(pdev, IORESOURCE_IO, 1); if (!res_gpi || !res_gpo) return -EBUSY; - vg = kzalloc(sizeof(*vg), GFP_KERNEL); + vg = devm_kzalloc(&pdev->dev, sizeof(*vg), GFP_KERNEL); if (!vg) return -ENOMEM; @@ -250,56 +247,27 @@ static int vx855gpio_probe(struct platform_device *pdev) * succeed. Ignore and continue. */ - if (!request_region(res_gpi->start, resource_size(res_gpi), - MODULE_NAME "_gpi")) + if (!devm_request_region(&pdev->dev, res_gpi->start, + resource_size(res_gpi), MODULE_NAME "_gpi")) dev_warn(&pdev->dev, "GPI I/O resource busy, probably claimed by ACPI\n"); - else - vg->gpi_reserved = true; - if (!request_region(res_gpo->start, resource_size(res_gpo), - MODULE_NAME "_gpo")) + if (!devm_request_region(&pdev->dev, res_gpo->start, + resource_size(res_gpo), MODULE_NAME "_gpo")) dev_warn(&pdev->dev, "GPO I/O resource busy, probably claimed by ACPI\n"); - else - vg->gpo_reserved = true; vx855gpio_gpio_setup(vg); - ret = gpiochip_add(&vg->gpio); - if (ret) { - dev_err(&pdev->dev, "failed to register GPIOs\n"); - goto out_release; - } - - return 0; - -out_release: - if (vg->gpi_reserved) - release_region(res_gpi->start, resource_size(res_gpi)); - if (vg->gpo_reserved) - release_region(res_gpi->start, resource_size(res_gpo)); - kfree(vg); - return ret; + return gpiochip_add(&vg->gpio); } static int vx855gpio_remove(struct platform_device *pdev) { struct vx855_gpio *vg = platform_get_drvdata(pdev); - struct resource *res; gpiochip_remove(&vg->gpio); - if (vg->gpi_reserved) { - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - release_region(res->start, resource_size(res)); - } - if (vg->gpo_reserved) { - res = platform_get_resource(pdev, IORESOURCE_IO, 1); - release_region(res->start, resource_size(res)); - } - - kfree(vg); return 0; } diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c new file mode 100644 index 000000000000..b6a15c39293e --- /dev/null +++ b/drivers/gpio/gpio-xgene-sb.c @@ -0,0 +1,160 @@ +/* + * AppliedMicro X-Gene SoC GPIO-Standby Driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Author: Tin Huynh . + * Y Vo . + * + * 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, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#define XGENE_MAX_GPIO_DS 22 +#define XGENE_MAX_GPIO_DS_IRQ 6 + +#define GPIO_MASK(x) (1U << ((x) % 32)) + +#define MPA_GPIO_INT_LVL 0x0290 +#define MPA_GPIO_OE_ADDR 0x029c +#define MPA_GPIO_OUT_ADDR 0x02a0 +#define MPA_GPIO_IN_ADDR 0x02a4 +#define MPA_GPIO_SEL_LO 0x0294 + +/** + * struct xgene_gpio_sb - GPIO-Standby private data structure. + * @bgc: memory-mapped GPIO controllers. + * @irq: Mapping GPIO pins and interrupt number + * nirq: Number of GPIO pins that supports interrupt + */ +struct xgene_gpio_sb { + struct bgpio_chip bgc; + u32 *irq; + u32 nirq; +}; + +static inline struct xgene_gpio_sb *to_xgene_gpio_sb(struct gpio_chip *gc) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + return container_of(bgc, struct xgene_gpio_sb, bgc); +} + +static void xgene_gpio_set_bit(struct bgpio_chip *bgc, void __iomem *reg, u32 gpio, int val) +{ + u32 data; + + data = bgc->read_reg(reg); + if (val) + data |= GPIO_MASK(gpio); + else + data &= ~GPIO_MASK(gpio); + bgc->write_reg(reg, data); +} + +static int apm_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio) +{ + struct xgene_gpio_sb *priv = to_xgene_gpio_sb(gc); + + if (priv->irq[gpio]) + return priv->irq[gpio]; + + return -ENXIO; +} + +static int xgene_gpio_sb_probe(struct platform_device *pdev) +{ + struct xgene_gpio_sb *priv; + u32 ret, i; + u32 default_lines[] = {0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D}; + struct resource *res; + void __iomem *regs; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (!regs) + return PTR_ERR(regs); + + ret = bgpio_init(&priv->bgc, &pdev->dev, 4, + regs + MPA_GPIO_IN_ADDR, + regs + MPA_GPIO_OUT_ADDR, NULL, + regs + MPA_GPIO_OE_ADDR, NULL, 0); + if (ret) + return ret; + + priv->bgc.gc.to_irq = apm_gpio_sb_to_irq; + priv->bgc.gc.ngpio = XGENE_MAX_GPIO_DS; + + priv->nirq = XGENE_MAX_GPIO_DS_IRQ; + + priv->irq = devm_kzalloc(&pdev->dev, sizeof(u32) * XGENE_MAX_GPIO_DS, + GFP_KERNEL); + if (!priv->irq) + return -ENOMEM; + memset(priv->irq, 0, sizeof(u32) * XGENE_MAX_GPIO_DS); + + for (i = 0; i < priv->nirq; i++) { + priv->irq[default_lines[i]] = platform_get_irq(pdev, i); + xgene_gpio_set_bit(&priv->bgc, regs + MPA_GPIO_SEL_LO, + default_lines[i] * 2, 1); + xgene_gpio_set_bit(&priv->bgc, regs + MPA_GPIO_INT_LVL, i, 1); + } + + platform_set_drvdata(pdev, priv); + + ret = gpiochip_add(&priv->bgc.gc); + if (ret) + dev_err(&pdev->dev, "failed to register X-Gene GPIO Standby driver\n"); + else + dev_info(&pdev->dev, "X-Gene GPIO Standby driver registered\n"); + + return ret; +} + +static int xgene_gpio_sb_remove(struct platform_device *pdev) +{ + struct xgene_gpio_sb *priv = platform_get_drvdata(pdev); + + return bgpio_remove(&priv->bgc); +} + +static const struct of_device_id xgene_gpio_sb_of_match[] = { + {.compatible = "apm,xgene-gpio-sb", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xgene_gpio_sb_of_match); + +static struct platform_driver xgene_gpio_sb_driver = { + .driver = { + .name = "xgene-gpio-sb", + .of_match_table = xgene_gpio_sb_of_match, + }, + .probe = xgene_gpio_sb_probe, + .remove = xgene_gpio_sb_remove, +}; +module_platform_driver(xgene_gpio_sb_driver); + +MODULE_AUTHOR("AppliedMicro"); +MODULE_DESCRIPTION("APM X-Gene GPIO Standby driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index ba18b06c9a21..61243d177740 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -30,7 +30,7 @@ #define XGPIO_CHANNEL_OFFSET 0x8 /* Read/Write access to the GPIO registers */ -#ifdef CONFIG_ARCH_ZYNQ +#if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86) # define xgpio_readreg(offset) readl(offset) # define xgpio_writereg(offset, val) writel(val, offset) #else @@ -40,37 +40,66 @@ /** * struct xgpio_instance - Stores information about GPIO device - * struct of_mm_gpio_chip mmchip: OF GPIO chip for memory mapped banks - * gpio_state: GPIO state shadow register - * gpio_dir: GPIO direction shadow register - * offset: GPIO channel offset - * gpio_lock: Lock used for synchronization + * @mmchip: OF GPIO chip for memory mapped banks + * @gpio_state: GPIO state shadow register + * @gpio_dir: GPIO direction shadow register + * @gpio_lock: Lock used for synchronization + * @inited: True if the port has been inited */ struct xgpio_instance { struct of_mm_gpio_chip mmchip; - u32 gpio_state; - u32 gpio_dir; - u32 offset; - spinlock_t gpio_lock; + unsigned int gpio_width[2]; + u32 gpio_state[2]; + u32 gpio_dir[2]; + spinlock_t gpio_lock[2]; }; +static inline int xgpio_index(struct xgpio_instance *chip, int gpio) +{ + if (gpio >= chip->gpio_width[0]) + return 1; + + return 0; +} + +static inline int xgpio_regoffset(struct xgpio_instance *chip, int gpio) +{ + if (xgpio_index(chip, gpio)) + return XGPIO_CHANNEL_OFFSET; + + return 0; +} + +static inline int xgpio_offset(struct xgpio_instance *chip, int gpio) +{ + if (xgpio_index(chip, gpio)) + return gpio - chip->gpio_width[0]; + + return gpio; +} + /** * xgpio_get - Read the specified signal of the GPIO device. * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * - * This function reads the specified signal of the GPIO device. It returns 0 if - * the signal clear, 1 if signal is set or negative value on error. + * This function reads the specified signal of the GPIO device. + * + * Return: + * 0 if direction of GPIO signals is set as input otherwise it + * returns negative error value. */ static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); + u32 val; - void __iomem *regs = mm_gc->regs + chip->offset; + val = xgpio_readreg(mm_gc->regs + XGPIO_DATA_OFFSET + + xgpio_regoffset(chip, gpio)); - return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET) & BIT(gpio)); + return !!(val & BIT(xgpio_offset(chip, gpio))); } /** @@ -88,20 +117,21 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); - void __iomem *regs = mm_gc->regs; + int index = xgpio_index(chip, gpio); + int offset = xgpio_offset(chip, gpio); - spin_lock_irqsave(&chip->gpio_lock, flags); + spin_lock_irqsave(&chip->gpio_lock[index], flags); /* Write to GPIO signal and set its direction to output */ if (val) - chip->gpio_state |= BIT(gpio); + chip->gpio_state[index] |= BIT(offset); else - chip->gpio_state &= ~BIT(gpio); + chip->gpio_state[index] &= ~BIT(offset); - xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET, - chip->gpio_state); + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + + xgpio_regoffset(chip, gpio), chip->gpio_state[index]); - spin_unlock_irqrestore(&chip->gpio_lock, flags); + spin_unlock_irqrestore(&chip->gpio_lock[index], flags); } /** @@ -109,9 +139,9 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * - * This function sets the direction of specified GPIO signal as input. - * It returns 0 if direction of GPIO signals is set as input otherwise it - * returns negative error value. + * Return: + * 0 - if direction of GPIO signals is set as input + * otherwise it returns negative error value. */ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { @@ -119,15 +149,17 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); - void __iomem *regs = mm_gc->regs; + int index = xgpio_index(chip, gpio); + int offset = xgpio_offset(chip, gpio); - spin_lock_irqsave(&chip->gpio_lock, flags); + spin_lock_irqsave(&chip->gpio_lock[index], flags); /* Set the GPIO bit in shadow register and set direction as input */ - chip->gpio_dir |= BIT(gpio); - xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir); + chip->gpio_dir[index] |= BIT(offset); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + + xgpio_regoffset(chip, gpio), chip->gpio_dir[index]); - spin_unlock_irqrestore(&chip->gpio_lock, flags); + spin_unlock_irqrestore(&chip->gpio_lock[index], flags); return 0; } @@ -138,8 +170,10 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) * @gpio: GPIO signal number. * @val: Value to be written to specified signal. * - * This function sets the direction of specified GPIO signal as output. If all - * GPIO signals of GPIO chip is configured as input then it returns + * This function sets the direction of specified GPIO signal as output. + * + * Return: + * If all GPIO signals of GPIO chip is configured as input then it returns * error otherwise it returns 0. */ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) @@ -148,80 +182,128 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); - void __iomem *regs = mm_gc->regs; + int index = xgpio_index(chip, gpio); + int offset = xgpio_offset(chip, gpio); - spin_lock_irqsave(&chip->gpio_lock, flags); + spin_lock_irqsave(&chip->gpio_lock[index], flags); /* Write state of GPIO signal */ if (val) - chip->gpio_state |= BIT(gpio); + chip->gpio_state[index] |= BIT(offset); else - chip->gpio_state &= ~BIT(gpio); - xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET, - chip->gpio_state); + chip->gpio_state[index] &= ~BIT(offset); + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + + xgpio_regoffset(chip, gpio), chip->gpio_state[index]); /* Clear the GPIO bit in shadow register and set direction as output */ - chip->gpio_dir &= ~BIT(gpio); - xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir); + chip->gpio_dir[index] &= ~BIT(offset); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + + xgpio_regoffset(chip, gpio), chip->gpio_dir[index]); - spin_unlock_irqrestore(&chip->gpio_lock, flags); + spin_unlock_irqrestore(&chip->gpio_lock[index], flags); return 0; } /** * xgpio_save_regs - Set initial values of GPIO pins - * @mm_gc: pointer to memory mapped GPIO chip structure + * @mm_gc: Pointer to memory mapped GPIO chip structure */ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) { struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); - xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_DATA_OFFSET, - chip->gpio_state); - xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_TRI_OFFSET, - chip->gpio_dir); + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]); + + if (!chip->gpio_width[1]) + return; + + xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + XGPIO_TRI_OFFSET, + chip->gpio_state[1]); + xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + XGPIO_TRI_OFFSET, + chip->gpio_dir[1]); +} + +/** + * xgpio_remove - Remove method for the GPIO device. + * @pdev: pointer to the platform device + * + * This function remove gpiochips and frees all the allocated resources. + */ +static int xgpio_remove(struct platform_device *pdev) +{ + struct xgpio_instance *chip = platform_get_drvdata(pdev); + + of_mm_gpiochip_remove(&chip->mmchip); + + return 0; } /** * xgpio_of_probe - Probe method for the GPIO device. - * @np: pointer to device tree node + * @pdev: pointer to the platform device * - * This function probes the GPIO device in the device tree. It initializes the - * driver data structure. It returns 0, if the driver is bound to the GPIO - * device, or a negative value if there is an error. + * Return: + * It returns 0, if the driver is bound to the GPIO device, or + * a negative value if there is an error. */ -static int xgpio_of_probe(struct device_node *np) +static int xgpio_probe(struct platform_device *pdev) { struct xgpio_instance *chip; int status = 0; - const u32 *tree_info; - u32 ngpio; + struct device_node *np = pdev->dev.of_node; + u32 is_dual; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; - /* Update GPIO state shadow register with default value */ - of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state); + platform_set_drvdata(pdev, chip); - /* By default, all pins are inputs */ - chip->gpio_dir = 0xFFFFFFFF; + /* Update GPIO state shadow register with default value */ + of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state[0]); /* Update GPIO direction shadow register with default value */ - of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir); + if (of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir[0])) + chip->gpio_dir[0] = 0xFFFFFFFF; /* * Check device node and parent device node for device width * and assume default width of 32 */ - if (of_property_read_u32(np, "xlnx,gpio-width", &ngpio)) - ngpio = 32; - chip->mmchip.gc.ngpio = (u16)ngpio; + if (of_property_read_u32(np, "xlnx,gpio-width", &chip->gpio_width[0])) + chip->gpio_width[0] = 32; - spin_lock_init(&chip->gpio_lock); + spin_lock_init(&chip->gpio_lock[0]); + if (of_property_read_u32(np, "xlnx,is-dual", &is_dual)) + is_dual = 0; + + if (is_dual) { + /* Update GPIO state shadow register with default value */ + of_property_read_u32(np, "xlnx,dout-default-2", + &chip->gpio_state[1]); + + /* Update GPIO direction shadow register with default value */ + if (of_property_read_u32(np, "xlnx,tri-default-2", + &chip->gpio_dir[1])) + chip->gpio_dir[1] = 0xFFFFFFFF; + + /* + * Check device node and parent device node for device width + * and assume default width of 32 + */ + if (of_property_read_u32(np, "xlnx,gpio2-width", + &chip->gpio_width[1])) + chip->gpio_width[1] = 32; + + spin_lock_init(&chip->gpio_lock[1]); + } + + chip->mmchip.gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1]; + chip->mmchip.gc.dev = &pdev->dev; chip->mmchip.gc.direction_input = xgpio_dir_in; chip->mmchip.gc.direction_output = xgpio_dir_out; chip->mmchip.gc.get = xgpio_get; @@ -232,63 +314,11 @@ static int xgpio_of_probe(struct device_node *np) /* Call the OF gpio helper to setup and register the GPIO device */ status = of_mm_gpiochip_add(np, &chip->mmchip); if (status) { - kfree(chip); pr_err("%s: error in probe function with status %d\n", np->full_name, status); return status; } - pr_info("XGpio: %s: registered, base is %d\n", np->full_name, - chip->mmchip.gc.base); - - tree_info = of_get_property(np, "xlnx,is-dual", NULL); - if (tree_info && be32_to_cpup(tree_info)) { - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - /* Add dual channel offset */ - chip->offset = XGPIO_CHANNEL_OFFSET; - - /* Update GPIO state shadow register with default value */ - of_property_read_u32(np, "xlnx,dout-default-2", - &chip->gpio_state); - - /* By default, all pins are inputs */ - chip->gpio_dir = 0xFFFFFFFF; - - /* Update GPIO direction shadow register with default value */ - of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir); - - /* - * Check device node and parent device node for device width - * and assume default width of 32 - */ - if (of_property_read_u32(np, "xlnx,gpio2-width", &ngpio)) - ngpio = 32; - chip->mmchip.gc.ngpio = (u16)ngpio; - - spin_lock_init(&chip->gpio_lock); - - chip->mmchip.gc.direction_input = xgpio_dir_in; - chip->mmchip.gc.direction_output = xgpio_dir_out; - chip->mmchip.gc.get = xgpio_get; - chip->mmchip.gc.set = xgpio_set; - - chip->mmchip.save_regs = xgpio_save_regs; - - /* Call the OF gpio helper to setup and register the GPIO dev */ - status = of_mm_gpiochip_add(np, &chip->mmchip); - if (status) { - kfree(chip); - pr_err("%s: error in probe function with status %d\n", - np->full_name, status); - return status; - } - pr_info("XGpio: %s: dual channel registered, base is %d\n", - np->full_name, chip->mmchip.gc.base); - } - return 0; } @@ -297,19 +327,29 @@ static const struct of_device_id xgpio_of_match[] = { { /* end of list */ }, }; +MODULE_DEVICE_TABLE(of, xgpio_of_match); + +static struct platform_driver xgpio_plat_driver = { + .probe = xgpio_probe, + .remove = xgpio_remove, + .driver = { + .name = "gpio-xilinx", + .of_match_table = xgpio_of_match, + }, +}; + static int __init xgpio_init(void) { - struct device_node *np; - - for_each_matching_node(np, xgpio_of_match) - xgpio_of_probe(np); - - return 0; + return platform_driver_register(&xgpio_plat_driver); } -/* Make sure we get initialized before anyone else tries to use us */ subsys_initcall(xgpio_init); -/* No exit call at the moment as we cannot unregister of GPIO chips */ + +static void __exit xgpio_exit(void) +{ + platform_driver_unregister(&xgpio_plat_driver); +} +module_exit(xgpio_exit); MODULE_AUTHOR("Xilinx, Inc."); MODULE_DESCRIPTION("Xilinx GPIO driver"); diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c index f769cd53f4e4..6f02d7c4cc57 100644 --- a/drivers/gpio/gpio-zevio.c +++ b/drivers/gpio/gpio-zevio.c @@ -181,6 +181,8 @@ static int zevio_gpio_probe(struct platform_device *pdev) if (!controller) return -ENOMEM; + platform_set_drvdata(pdev, controller); + /* Copy our reference */ controller->chip.gc = zevio_gpio_chip; controller->chip.gc.dev = &pdev->dev; @@ -202,6 +204,15 @@ static int zevio_gpio_probe(struct platform_device *pdev) return 0; } +static int zevio_gpio_remove(struct platform_device *pdev) +{ + struct zevio_gpio *controller = platform_get_drvdata(pdev); + + of_mm_gpiochip_remove(&controller->chip); + + return 0; +} + static const struct of_device_id zevio_gpio_of_match[] = { { .compatible = "lsi,zevio-gpio", }, { }, @@ -215,6 +226,7 @@ static struct platform_driver zevio_gpio_driver = { .of_match_table = zevio_gpio_of_match, }, .probe = zevio_gpio_probe, + .remove = zevio_gpio_remove, }; module_platform_driver(zevio_gpio_driver); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 604dbe60bdee..8cad8e400b44 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -45,8 +45,14 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) return false; ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags); - if (ret < 0) - return false; + if (ret < 0) { + /* We've found the gpio chip, but the translation failed. + * Return true to stop looking and return the translation + * error via out_gpio + */ + gg_data->out_gpio = ERR_PTR(ret); + return true; + } gg_data->out_gpio = gpiochip_get_desc(gc, ret); return true; @@ -204,6 +210,23 @@ err0: } EXPORT_SYMBOL(of_mm_gpiochip_add); +/** + * of_mm_gpiochip_remove - Remove memory mapped GPIO chip (bank) + * @mm_gc: pointer to the of_mm_gpio_chip allocated structure + */ +void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc) +{ + struct gpio_chip *gc = &mm_gc->gc; + + if (!mm_gc) + return; + + gpiochip_remove(gc); + iounmap(mm_gc->regs); + kfree(gc->label); +} +EXPORT_SYMBOL(of_mm_gpiochip_remove); + #ifdef CONFIG_PINCTRL static void of_gpiochip_add_pin_range(struct gpio_chip *chip) { diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 2ac1800b58bb..7722ed53bd65 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -128,7 +128,7 @@ static ssize_t gpio_value_store(struct device *dev, return status; } -static const DEVICE_ATTR(value, 0644, +static DEVICE_ATTR(value, 0644, gpio_value_show, gpio_value_store); static irqreturn_t gpio_sysfs_irq(int irq, void *priv) @@ -353,17 +353,46 @@ static ssize_t gpio_active_low_store(struct device *dev, return status ? : size; } -static const DEVICE_ATTR(active_low, 0644, +static DEVICE_ATTR(active_low, 0644, gpio_active_low_show, gpio_active_low_store); -static const struct attribute *gpio_attrs[] = { +static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr, + int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct gpio_desc *desc = dev_get_drvdata(dev); + umode_t mode = attr->mode; + bool show_direction = test_bit(FLAG_SYSFS_DIR, &desc->flags); + + if (attr == &dev_attr_direction.attr) { + if (!show_direction) + mode = 0; + } else if (attr == &dev_attr_edge.attr) { + if (gpiod_to_irq(desc) < 0) + mode = 0; + if (!show_direction && test_bit(FLAG_IS_OUT, &desc->flags)) + mode = 0; + } + + return mode; +} + +static struct attribute *gpio_attrs[] = { + &dev_attr_direction.attr, + &dev_attr_edge.attr, &dev_attr_value.attr, &dev_attr_active_low.attr, NULL, }; -static const struct attribute_group gpio_attr_group = { - .attrs = (struct attribute **) gpio_attrs, +static const struct attribute_group gpio_group = { + .attrs = gpio_attrs, + .is_visible = gpio_is_visible, +}; + +static const struct attribute_group *gpio_groups[] = { + &gpio_group, + NULL }; /* @@ -400,16 +429,13 @@ static ssize_t chip_ngpio_show(struct device *dev, } static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL); -static const struct attribute *gpiochip_attrs[] = { +static struct attribute *gpiochip_attrs[] = { &dev_attr_base.attr, &dev_attr_label.attr, &dev_attr_ngpio.attr, NULL, }; - -static const struct attribute_group gpiochip_attr_group = { - .attrs = (struct attribute **) gpiochip_attrs, -}; +ATTRIBUTE_GROUPS(gpiochip); /* * /sys/class/gpio/export ... write-only @@ -556,45 +582,30 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) goto fail_unlock; } - if (!desc->chip->direction_input || !desc->chip->direction_output) - direction_may_change = false; + if (desc->chip->direction_input && desc->chip->direction_output && + direction_may_change) { + set_bit(FLAG_SYSFS_DIR, &desc->flags); + } + spin_unlock_irqrestore(&gpio_lock, flags); offset = gpio_chip_hwgpio(desc); if (desc->chip->names && desc->chip->names[offset]) ioname = desc->chip->names[offset]; - dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), - desc, ioname ? ioname : "gpio%u", - desc_to_gpio(desc)); + dev = device_create_with_groups(&gpio_class, desc->chip->dev, + MKDEV(0, 0), desc, gpio_groups, + ioname ? ioname : "gpio%u", + desc_to_gpio(desc)); if (IS_ERR(dev)) { status = PTR_ERR(dev); goto fail_unlock; } - status = sysfs_create_group(&dev->kobj, &gpio_attr_group); - if (status) - goto fail_unregister_device; - - if (direction_may_change) { - status = device_create_file(dev, &dev_attr_direction); - if (status) - goto fail_unregister_device; - } - - if (gpiod_to_irq(desc) >= 0 && (direction_may_change || - !test_bit(FLAG_IS_OUT, &desc->flags))) { - status = device_create_file(dev, &dev_attr_edge); - if (status) - goto fail_unregister_device; - } - set_bit(FLAG_EXPORT, &desc->flags); mutex_unlock(&sysfs_lock); return 0; -fail_unregister_device: - device_unregister(dev); fail_unlock: mutex_unlock(&sysfs_lock); gpiod_dbg(desc, "%s: status %d\n", __func__, status); @@ -637,6 +648,7 @@ int gpiod_export_link(struct device *dev, const char *name, if (tdev != NULL) { status = sysfs_create_link(&dev->kobj, &tdev->kobj, name); + put_device(tdev); } else { status = -ENODEV; } @@ -684,7 +696,7 @@ int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) } status = sysfs_set_active_low(desc, dev, value); - + put_device(dev); unlock: mutex_unlock(&sysfs_lock); @@ -718,6 +730,7 @@ void gpiod_unexport(struct gpio_desc *desc) dev = class_find_device(&gpio_class, NULL, desc, match_export); if (dev) { gpio_setup_irq(desc, dev, 0); + clear_bit(FLAG_SYSFS_DIR, &desc->flags); clear_bit(FLAG_EXPORT, &desc->flags); } else status = -ENODEV; @@ -750,13 +763,13 @@ int gpiochip_export(struct gpio_chip *chip) /* use chip->base for the ID; it's already known to be unique */ mutex_lock(&sysfs_lock); - dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip, - "gpiochip%d", chip->base); - if (!IS_ERR(dev)) { - status = sysfs_create_group(&dev->kobj, - &gpiochip_attr_group); - } else + dev = device_create_with_groups(&gpio_class, chip->dev, MKDEV(0, 0), + chip, gpiochip_groups, + "gpiochip%d", chip->base); + if (IS_ERR(dev)) status = PTR_ERR(dev); + else + status = 0; chip->exported = (status == 0); mutex_unlock(&sysfs_lock); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 487afe6f22fc..1ca9295b2c10 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -248,29 +248,30 @@ int gpiochip_add(struct gpio_chip *chip) base = gpiochip_find_base(chip->ngpio); if (base < 0) { status = base; - goto unlock; + spin_unlock_irqrestore(&gpio_lock, flags); + goto err_free_descs; } chip->base = base; } status = gpiochip_add_to_list(chip); + if (status) { + spin_unlock_irqrestore(&gpio_lock, flags); + goto err_free_descs; + } - if (status == 0) { - for (id = 0; id < chip->ngpio; id++) { - struct gpio_desc *desc = &descs[id]; - desc->chip = chip; + for (id = 0; id < chip->ngpio; id++) { + struct gpio_desc *desc = &descs[id]; - /* REVISIT: most hardware initializes GPIOs as - * inputs (often with pullups enabled) so power - * usage is minimized. Linux code should set the - * gpio direction first thing; but until it does, - * and in case chip->get_direction is not set, - * we may expose the wrong direction in sysfs. - */ - desc->flags = !chip->direction_input - ? (1 << FLAG_IS_OUT) - : 0; - } + desc->chip = chip; + + /* REVISIT: most hardware initializes GPIOs as inputs (often + * with pullups enabled) so power usage is minimized. Linux + * code should set the gpio direction first thing; but until + * it does, and in case chip->get_direction is not set, we may + * expose the wrong direction in sysfs. + */ + desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0; } chip->desc = descs; @@ -284,12 +285,9 @@ int gpiochip_add(struct gpio_chip *chip) of_gpiochip_add(chip); acpi_gpiochip_add(chip); - if (status) - goto fail; - status = gpiochip_export(chip); if (status) - goto fail; + goto err_remove_chip; pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__, chip->base, chip->base + chip->ngpio - 1, @@ -297,11 +295,15 @@ int gpiochip_add(struct gpio_chip *chip) return 0; -unlock: +err_remove_chip: + acpi_gpiochip_remove(chip); + of_gpiochip_remove(chip); + spin_lock_irqsave(&gpio_lock, flags); + list_del(&chip->list); spin_unlock_irqrestore(&gpio_lock, flags); -fail: - kfree(descs); chip->desc = NULL; +err_free_descs: + kfree(descs); /* failures here can mean systems won't boot... */ pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__, @@ -325,14 +327,15 @@ void gpiochip_remove(struct gpio_chip *chip) unsigned long flags; unsigned id; - acpi_gpiochip_remove(chip); - - spin_lock_irqsave(&gpio_lock, flags); + gpiochip_unexport(chip); gpiochip_irqchip_remove(chip); + + acpi_gpiochip_remove(chip); gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); + spin_lock_irqsave(&gpio_lock, flags); for (id = 0; id < chip->ngpio; id++) { if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n"); @@ -342,7 +345,6 @@ void gpiochip_remove(struct gpio_chip *chip) list_del(&chip->list); spin_unlock_irqrestore(&gpio_lock, flags); - gpiochip_unexport(chip); kfree(chip->desc); chip->desc = NULL; @@ -1657,7 +1659,7 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) { - static const char *suffixes[] = { "gpios", "gpio" }; + static const char * const suffixes[] = { "gpios", "gpio" }; char prop_name[32]; /* 32 is max size of property name */ enum of_gpio_flags of_flags; struct gpio_desc *desc; @@ -1665,9 +1667,11 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, for (i = 0; i < ARRAY_SIZE(suffixes); i++) { if (con_id) - snprintf(prop_name, 32, "%s-%s", con_id, suffixes[i]); + snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id, + suffixes[i]); else - snprintf(prop_name, 32, "%s", suffixes[i]); + snprintf(prop_name, sizeof(prop_name), "%s", + suffixes[i]); desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, &of_flags); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index e3a52113a541..550a5eafbd38 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -77,6 +77,7 @@ struct gpio_desc { #define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ #define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ +#define FLAG_SYSFS_DIR 10 /* show sysfs direction attribute */ #define ID_SHIFT 16 /* add new flags before this one */ diff --git a/drivers/gpu/drm/amd/amdkfd/Makefile b/drivers/gpu/drm/amd/amdkfd/Makefile index be6246de5091..307a309110e6 100644 --- a/drivers/gpu/drm/amd/amdkfd/Makefile +++ b/drivers/gpu/drm/amd/amdkfd/Makefile @@ -8,7 +8,6 @@ amdkfd-y := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \ kfd_pasid.o kfd_doorbell.o kfd_flat_memory.o \ kfd_process.o kfd_queue.o kfd_mqd_manager.o \ kfd_kernel_queue.o kfd_packet_manager.o \ - kfd_process_queue_manager.o kfd_device_queue_manager.o \ - kfd_interrupt.o + kfd_process_queue_manager.o kfd_device_queue_manager.o obj-$(CONFIG_HSA_AMD) += amdkfd.o diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 43884ebd4303..25bc47f3c1cf 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -26,6 +26,7 @@ #include #include "kfd_priv.h" #include "kfd_device_queue_manager.h" +#include "kfd_pm4_headers.h" #define MQD_SIZE_ALIGNED 768 @@ -169,9 +170,8 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, kfd->shared_resources = *gpu_resources; /* calculate max size of mqds needed for queues */ - size = max_num_of_processes * - max_num_of_queues_per_process * - kfd->device_info->mqd_size_aligned; + size = max_num_of_queues_per_device * + kfd->device_info->mqd_size_aligned; /* add another 512KB for all other allocations on gart */ size += 512 * 1024; @@ -192,13 +192,6 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, goto kfd_topology_add_device_error; } - if (kfd_interrupt_init(kfd)) { - dev_err(kfd_device, - "Error initializing interrupts for device (%x:%x)\n", - kfd->pdev->vendor, kfd->pdev->device); - goto kfd_interrupt_error; - } - if (!device_iommu_pasid_init(kfd)) { dev_err(kfd_device, "Error initializing iommuv2 for device (%x:%x)\n", @@ -237,8 +230,6 @@ dqm_start_error: device_queue_manager_error: amd_iommu_free_device(kfd->pdev); device_iommu_pasid_error: - kfd_interrupt_exit(kfd); -kfd_interrupt_error: kfd_topology_remove_device(kfd); kfd_topology_add_device_error: kfd2kgd->fini_sa_manager(kfd->kgd); @@ -254,7 +245,6 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd) if (kfd->init_complete) { device_queue_manager_uninit(kfd->dqm); amd_iommu_free_device(kfd->pdev); - kfd_interrupt_exit(kfd); kfd_topology_remove_device(kfd); } @@ -296,13 +286,5 @@ int kgd2kfd_resume(struct kfd_dev *kfd) /* This is called directly from KGD at ISR. */ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry) { - if (kfd->init_complete) { - spin_lock(&kfd->interrupt_lock); - - if (kfd->interrupts_active - && enqueue_ih_ring_entry(kfd, ih_ring_entry)) - schedule_work(&kfd->interrupt_work); - - spin_unlock(&kfd->interrupt_lock); - } + /* Process interrupts / schedule work as necessary */ } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 9c8961d22360..0fd592799d58 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -183,6 +183,13 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm, mutex_lock(&dqm->lock); + if (dqm->total_queue_count >= max_num_of_queues_per_device) { + pr_warn("amdkfd: Can't create new usermode queue because %d queues were already created\n", + dqm->total_queue_count); + mutex_unlock(&dqm->lock); + return -EPERM; + } + if (list_empty(&qpd->queues_list)) { retval = allocate_vmid(dqm, qpd, q); if (retval != 0) { @@ -207,6 +214,14 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm, list_add(&q->list, &qpd->queues_list); dqm->queue_count++; + /* + * Unconditionally increment this counter, regardless of the queue's + * type or whether the queue is active. + */ + dqm->total_queue_count++; + pr_debug("Total of %d queues are accountable so far\n", + dqm->total_queue_count); + mutex_unlock(&dqm->lock); return 0; } @@ -280,7 +295,7 @@ static int create_compute_queue_nocpsch(struct device_queue_manager *dqm, q->queue); retval = mqd->load_mqd(mqd, q->mqd, q->pipe, - q->queue, q->properties.write_ptr); + q->queue, (uint32_t __user *) q->properties.write_ptr); if (retval != 0) { deallocate_hqd(dqm, q); mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj); @@ -326,6 +341,15 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm, if (list_empty(&qpd->queues_list)) deallocate_vmid(dqm, qpd, q); dqm->queue_count--; + + /* + * Unconditionally decrement this counter, regardless of the queue's + * type + */ + dqm->total_queue_count--; + pr_debug("Total of %d queues are accountable so far\n", + dqm->total_queue_count); + out: mutex_unlock(&dqm->lock); return retval; @@ -541,10 +565,14 @@ static int init_pipelines(struct device_queue_manager *dqm, for (i = 0; i < pipes_num; i++) { inx = i + first_pipe; + /* + * HPD buffer on GTT is allocated by amdkfd, no need to waste + * space in GTT for pipelines we don't initialize + */ pipe_hpd_addr = dqm->pipelines_addr + i * CIK_HPD_EOP_BYTES; pr_debug("kfd: pipeline address %llX\n", pipe_hpd_addr); /* = log2(bytes/4)-1 */ - kfd2kgd->init_pipeline(dqm->dev->kgd, i, + kfd2kgd->init_pipeline(dqm->dev->kgd, inx, CIK_HPD_EOP_BYTES_LOG2 - 3, pipe_hpd_addr); } @@ -560,7 +588,7 @@ static int init_scheduler(struct device_queue_manager *dqm) pr_debug("kfd: In %s\n", __func__); - retval = init_pipelines(dqm, get_pipes_num(dqm), KFD_DQM_FIRST_PIPE); + retval = init_pipelines(dqm, get_pipes_num(dqm), get_first_pipe(dqm)); if (retval != 0) return retval; @@ -752,6 +780,21 @@ static int create_kernel_queue_cpsch(struct device_queue_manager *dqm, pr_debug("kfd: In func %s\n", __func__); mutex_lock(&dqm->lock); + if (dqm->total_queue_count >= max_num_of_queues_per_device) { + pr_warn("amdkfd: Can't create new kernel queue because %d queues were already created\n", + dqm->total_queue_count); + mutex_unlock(&dqm->lock); + return -EPERM; + } + + /* + * Unconditionally increment this counter, regardless of the queue's + * type or whether the queue is active. + */ + dqm->total_queue_count++; + pr_debug("Total of %d queues are accountable so far\n", + dqm->total_queue_count); + list_add(&kq->list, &qpd->priv_queue_list); dqm->queue_count++; qpd->is_debug = true; @@ -775,6 +818,13 @@ static void destroy_kernel_queue_cpsch(struct device_queue_manager *dqm, dqm->queue_count--; qpd->is_debug = false; execute_queues_cpsch(dqm, false); + /* + * Unconditionally decrement this counter, regardless of the queue's + * type. + */ + dqm->total_queue_count--; + pr_debug("Total of %d queues are accountable so far\n", + dqm->total_queue_count); mutex_unlock(&dqm->lock); } @@ -793,6 +843,13 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, mutex_lock(&dqm->lock); + if (dqm->total_queue_count >= max_num_of_queues_per_device) { + pr_warn("amdkfd: Can't create new usermode queue because %d queues were already created\n", + dqm->total_queue_count); + retval = -EPERM; + goto out; + } + mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_CP); if (mqd == NULL) { mutex_unlock(&dqm->lock); @@ -810,6 +867,15 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, retval = execute_queues_cpsch(dqm, false); } + /* + * Unconditionally increment this counter, regardless of the queue's + * type or whether the queue is active. + */ + dqm->total_queue_count++; + + pr_debug("Total of %d queues are accountable so far\n", + dqm->total_queue_count); + out: mutex_unlock(&dqm->lock); return retval; @@ -930,6 +996,14 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj); + /* + * Unconditionally decrement this counter, regardless of the queue's + * type + */ + dqm->total_queue_count--; + pr_debug("Total of %d queues are accountable so far\n", + dqm->total_queue_count); + mutex_unlock(&dqm->lock); return 0; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index c3f189e8ae35..52035bf0c1cb 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -130,6 +130,7 @@ struct device_queue_manager { struct list_head queues; unsigned int processes_count; unsigned int queue_count; + unsigned int total_queue_count; unsigned int next_pipe_to_allocate; unsigned int *allocated_queues; unsigned int vmid_bitmap; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c b/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c deleted file mode 100644 index 5b999095a1f7..000000000000 --- a/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2014 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. - */ - -/* - * KFD Interrupts. - * - * AMD GPUs deliver interrupts by pushing an interrupt description onto the - * interrupt ring and then sending an interrupt. KGD receives the interrupt - * in ISR and sends us a pointer to each new entry on the interrupt ring. - * - * We generally can't process interrupt-signaled events from ISR, so we call - * out to each interrupt client module (currently only the scheduler) to ask if - * each interrupt is interesting. If they return true, then it requires further - * processing so we copy it to an internal interrupt ring and call each - * interrupt client again from a work-queue. - * - * There's no acknowledgment for the interrupts we use. The hardware simply - * queues a new interrupt each time without waiting. - * - * The fixed-size internal queue means that it's possible for us to lose - * interrupts because we have no back-pressure to the hardware. - */ - -#include -#include -#include "kfd_priv.h" - -#define KFD_INTERRUPT_RING_SIZE 256 - -static void interrupt_wq(struct work_struct *); - -int kfd_interrupt_init(struct kfd_dev *kfd) -{ - void *interrupt_ring = kmalloc_array(KFD_INTERRUPT_RING_SIZE, - kfd->device_info->ih_ring_entry_size, - GFP_KERNEL); - if (!interrupt_ring) - return -ENOMEM; - - kfd->interrupt_ring = interrupt_ring; - kfd->interrupt_ring_size = - KFD_INTERRUPT_RING_SIZE * kfd->device_info->ih_ring_entry_size; - atomic_set(&kfd->interrupt_ring_wptr, 0); - atomic_set(&kfd->interrupt_ring_rptr, 0); - - spin_lock_init(&kfd->interrupt_lock); - - INIT_WORK(&kfd->interrupt_work, interrupt_wq); - - kfd->interrupts_active = true; - - /* - * After this function returns, the interrupt will be enabled. This - * barrier ensures that the interrupt running on a different processor - * sees all the above writes. - */ - smp_wmb(); - - return 0; -} - -void kfd_interrupt_exit(struct kfd_dev *kfd) -{ - /* - * Stop the interrupt handler from writing to the ring and scheduling - * workqueue items. The spinlock ensures that any interrupt running - * after we have unlocked sees interrupts_active = false. - */ - unsigned long flags; - - spin_lock_irqsave(&kfd->interrupt_lock, flags); - kfd->interrupts_active = false; - spin_unlock_irqrestore(&kfd->interrupt_lock, flags); - - /* - * Flush_scheduled_work ensures that there are no outstanding - * work-queue items that will access interrupt_ring. New work items - * can't be created because we stopped interrupt handling above. - */ - flush_scheduled_work(); - - kfree(kfd->interrupt_ring); -} - -/* - * This assumes that it can't be called concurrently with itself - * but only with dequeue_ih_ring_entry. - */ -bool enqueue_ih_ring_entry(struct kfd_dev *kfd, const void *ih_ring_entry) -{ - unsigned int rptr = atomic_read(&kfd->interrupt_ring_rptr); - unsigned int wptr = atomic_read(&kfd->interrupt_ring_wptr); - - if ((rptr - wptr) % kfd->interrupt_ring_size == - kfd->device_info->ih_ring_entry_size) { - /* This is very bad, the system is likely to hang. */ - dev_err_ratelimited(kfd_chardev(), - "Interrupt ring overflow, dropping interrupt.\n"); - return false; - } - - memcpy(kfd->interrupt_ring + wptr, ih_ring_entry, - kfd->device_info->ih_ring_entry_size); - - wptr = (wptr + kfd->device_info->ih_ring_entry_size) % - kfd->interrupt_ring_size; - smp_wmb(); /* Ensure memcpy'd data is visible before wptr update. */ - atomic_set(&kfd->interrupt_ring_wptr, wptr); - - return true; -} - -/* - * This assumes that it can't be called concurrently with itself - * but only with enqueue_ih_ring_entry. - */ -static bool dequeue_ih_ring_entry(struct kfd_dev *kfd, void *ih_ring_entry) -{ - /* - * Assume that wait queues have an implicit barrier, i.e. anything that - * happened in the ISR before it queued work is visible. - */ - - unsigned int wptr = atomic_read(&kfd->interrupt_ring_wptr); - unsigned int rptr = atomic_read(&kfd->interrupt_ring_rptr); - - if (rptr == wptr) - return false; - - memcpy(ih_ring_entry, kfd->interrupt_ring + rptr, - kfd->device_info->ih_ring_entry_size); - - rptr = (rptr + kfd->device_info->ih_ring_entry_size) % - kfd->interrupt_ring_size; - - /* - * Ensure the rptr write update is not visible until - * memcpy has finished reading. - */ - smp_mb(); - atomic_set(&kfd->interrupt_ring_rptr, rptr); - - return true; -} - -static void interrupt_wq(struct work_struct *work) -{ - struct kfd_dev *dev = container_of(work, struct kfd_dev, - interrupt_work); - - uint32_t ih_ring_entry[DIV_ROUND_UP( - dev->device_info->ih_ring_entry_size, - sizeof(uint32_t))]; - - while (dequeue_ih_ring_entry(dev, ih_ring_entry)) - ; -} diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_module.c b/drivers/gpu/drm/amd/amdkfd/kfd_module.c index 95d5af138e6e..1c385c23dd0b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_module.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_module.c @@ -50,15 +50,10 @@ module_param(sched_policy, int, 0444); MODULE_PARM_DESC(sched_policy, "Kernel cmdline parameter that defines the amdkfd scheduling policy"); -int max_num_of_processes = KFD_MAX_NUM_OF_PROCESSES_DEFAULT; -module_param(max_num_of_processes, int, 0444); -MODULE_PARM_DESC(max_num_of_processes, - "Kernel cmdline parameter that defines the amdkfd maximum number of supported processes"); - -int max_num_of_queues_per_process = KFD_MAX_NUM_OF_QUEUES_PER_PROCESS_DEFAULT; -module_param(max_num_of_queues_per_process, int, 0444); -MODULE_PARM_DESC(max_num_of_queues_per_process, - "Kernel cmdline parameter that defines the amdkfd maximum number of supported queues per process"); +int max_num_of_queues_per_device = KFD_MAX_NUM_OF_QUEUES_PER_DEVICE_DEFAULT; +module_param(max_num_of_queues_per_device, int, 0444); +MODULE_PARM_DESC(max_num_of_queues_per_device, + "Maximum number of supported queues per device (1 = Minimum, 4096 = default)"); bool kgd2kfd_init(unsigned interface_version, const struct kfd2kgd_calls *f2g, @@ -100,16 +95,10 @@ static int __init kfd_module_init(void) } /* Verify module parameters */ - if ((max_num_of_processes < 0) || - (max_num_of_processes > KFD_MAX_NUM_OF_PROCESSES)) { - pr_err("kfd: max_num_of_processes must be between 0 to KFD_MAX_NUM_OF_PROCESSES\n"); - return -1; - } - - if ((max_num_of_queues_per_process < 0) || - (max_num_of_queues_per_process > - KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)) { - pr_err("kfd: max_num_of_queues_per_process must be between 0 to KFD_MAX_NUM_OF_QUEUES_PER_PROCESS\n"); + if ((max_num_of_queues_per_device < 1) || + (max_num_of_queues_per_device > + KFD_MAX_NUM_OF_QUEUES_PER_DEVICE)) { + pr_err("kfd: max_num_of_queues_per_device must be between 1 to KFD_MAX_NUM_OF_QUEUES_PER_DEVICE\n"); return -1; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_pasid.c b/drivers/gpu/drm/amd/amdkfd/kfd_pasid.c index 4c25ef504f79..6cfe7f1f18cf 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_pasid.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_pasid.c @@ -30,7 +30,7 @@ static DEFINE_MUTEX(pasid_mutex); int kfd_pasid_init(void) { - pasid_limit = max_num_of_processes; + pasid_limit = KFD_MAX_NUM_OF_PROCESSES; pasid_bitmap = kcalloc(BITS_TO_LONGS(pasid_limit), sizeof(long), GFP_KERNEL); if (!pasid_bitmap) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index a5edb29507e3..96dc10e8904a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -52,20 +52,19 @@ #define kfd_alloc_struct(ptr_to_struct) \ ((typeof(ptr_to_struct)) kzalloc(sizeof(*ptr_to_struct), GFP_KERNEL)) -/* Kernel module parameter to specify maximum number of supported processes */ -extern int max_num_of_processes; - -#define KFD_MAX_NUM_OF_PROCESSES_DEFAULT 32 #define KFD_MAX_NUM_OF_PROCESSES 512 +#define KFD_MAX_NUM_OF_QUEUES_PER_PROCESS 1024 /* - * Kernel module parameter to specify maximum number of supported queues - * per process + * Kernel module parameter to specify maximum number of supported queues per + * device */ -extern int max_num_of_queues_per_process; +extern int max_num_of_queues_per_device; -#define KFD_MAX_NUM_OF_QUEUES_PER_PROCESS_DEFAULT 128 -#define KFD_MAX_NUM_OF_QUEUES_PER_PROCESS 1024 +#define KFD_MAX_NUM_OF_QUEUES_PER_DEVICE_DEFAULT 4096 +#define KFD_MAX_NUM_OF_QUEUES_PER_DEVICE \ + (KFD_MAX_NUM_OF_PROCESSES * \ + KFD_MAX_NUM_OF_QUEUES_PER_PROCESS) #define KFD_KERNEL_QUEUE_SIZE 2048 @@ -135,22 +134,10 @@ struct kfd_dev { struct kgd2kfd_shared_resources shared_resources; - void *interrupt_ring; - size_t interrupt_ring_size; - atomic_t interrupt_ring_rptr; - atomic_t interrupt_ring_wptr; - struct work_struct interrupt_work; - spinlock_t interrupt_lock; - /* QCM Device instance */ struct device_queue_manager *dqm; bool init_complete; - /* - * Interrupts of interest to KFD are copied - * from the HW ring into a SW ring. - */ - bool interrupts_active; }; /* KGD2KFD callbacks */ @@ -531,10 +518,7 @@ struct kfd_dev *kfd_device_by_pci_dev(const struct pci_dev *pdev); struct kfd_dev *kfd_topology_enum_kfd_devices(uint8_t idx); /* Interrupts */ -int kfd_interrupt_init(struct kfd_dev *dev); -void kfd_interrupt_exit(struct kfd_dev *dev); void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry); -bool enqueue_ih_ring_entry(struct kfd_dev *kfd, const void *ih_ring_entry); /* Power Management */ void kgd2kfd_suspend(struct kfd_dev *kfd); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 47526780d736..2fda1927bff7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -54,11 +54,11 @@ static int find_available_queue_slot(struct process_queue_manager *pqm, pr_debug("kfd: in %s\n", __func__); found = find_first_zero_bit(pqm->queue_slot_bitmap, - max_num_of_queues_per_process); + KFD_MAX_NUM_OF_QUEUES_PER_PROCESS); pr_debug("kfd: the new slot id %lu\n", found); - if (found >= max_num_of_queues_per_process) { + if (found >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS) { pr_info("amdkfd: Can not open more queues for process with pasid %d\n", pqm->process->pasid); return -ENOMEM; @@ -76,7 +76,7 @@ int pqm_init(struct process_queue_manager *pqm, struct kfd_process *p) INIT_LIST_HEAD(&pqm->queues); pqm->queue_slot_bitmap = - kzalloc(DIV_ROUND_UP(max_num_of_queues_per_process, + kzalloc(DIV_ROUND_UP(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS, BITS_PER_BYTE), GFP_KERNEL); if (pqm->queue_slot_bitmap == NULL) return -ENOMEM; @@ -203,6 +203,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, pqn->kq = NULL; retval = dev->dqm->create_queue(dev->dqm, q, &pdd->qpd, &q->properties.vmid); + pr_debug("DQM returned %d for create_queue\n", retval); print_queue(q); break; case KFD_QUEUE_TYPE_DIQ: @@ -222,7 +223,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, } if (retval != 0) { - pr_err("kfd: error dqm create queue\n"); + pr_debug("Error dqm create queue\n"); goto err_create_queue; } @@ -241,7 +242,10 @@ int pqm_create_queue(struct process_queue_manager *pqm, err_create_queue: kfree(pqn); err_allocate_pqn: + /* check if queues list is empty unregister process from device */ clear_bit(*qid, pqm->queue_slot_bitmap); + if (list_empty(&pqm->queues)) + dev->dqm->unregister_process(dev->dqm, &pdd->qpd); return retval; } @@ -311,7 +315,11 @@ int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid, BUG_ON(!pqm); pqn = get_queue_by_qid(pqm, qid); - BUG_ON(!pqn); + if (!pqn) { + pr_debug("amdkfd: No queue %d exists for update operation\n", + qid); + return -EFAULT; + } pqn->q->properties.queue_address = p->queue_address; pqn->q->properties.queue_size = p->queue_size; diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c index c2a1cba1e984..b9140032962d 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.c +++ b/drivers/gpu/drm/cirrus/cirrus_drv.c @@ -16,9 +16,12 @@ #include "cirrus_drv.h" int cirrus_modeset = -1; +int cirrus_bpp = 24; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, cirrus_modeset, int, 0400); +MODULE_PARM_DESC(bpp, "Max bits-per-pixel (default:24)"); +module_param_named(bpp, cirrus_bpp, int, 0400); /* * This is the generic driver code. This binds the driver to the drm core, diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h index 693a4565c4ff..705061537a27 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.h +++ b/drivers/gpu/drm/cirrus/cirrus_drv.h @@ -262,4 +262,7 @@ static inline void cirrus_bo_unreserve(struct cirrus_bo *bo) int cirrus_bo_push_sysram(struct cirrus_bo *bo); int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr); + +extern int cirrus_bpp; + #endif /* __CIRRUS_DRV_H__ */ diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index 4c2d68e9102d..e4b976658087 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -320,6 +320,8 @@ bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height, const int max_pitch = 0x1FF << 3; /* (4096 - 1) & ~111b bytes */ const int max_size = cdev->mc.vram_size; + if (bpp > cirrus_bpp) + return false; if (bpp > 32) return false; diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index 99d4a74ffeaf..61385f2298bf 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -501,8 +501,13 @@ static int cirrus_vga_get_modes(struct drm_connector *connector) int count; /* Just add a static list of modes */ - count = drm_add_modes_noedid(connector, 1280, 1024); - drm_set_preferred_mode(connector, 1024, 768); + if (cirrus_bpp <= 24) { + count = drm_add_modes_noedid(connector, 1280, 1024); + drm_set_preferred_mode(connector, 1024, 768); + } else { + count = drm_add_modes_noedid(connector, 800, 600); + drm_set_preferred_mode(connector, 800, 600); + } return count; } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 52ce26d6b4fb..dc386ebe5193 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -145,6 +145,31 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_ } EXPORT_SYMBOL(drm_fb_helper_add_one_connector); +static void remove_from_modeset(struct drm_mode_set *set, + struct drm_connector *connector) +{ + int i, j; + + for (i = 0; i < set->num_connectors; i++) { + if (set->connectors[i] == connector) + break; + } + + if (i == set->num_connectors) + return; + + for (j = i + 1; j < set->num_connectors; j++) { + set->connectors[j - 1] = set->connectors[j]; + } + set->num_connectors--; + + /* because i915 is pissy about this.. + * TODO maybe need to makes sure we set it back to !=NULL somewhere? + */ + if (set->num_connectors == 0) + set->fb = NULL; +} + int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector) { @@ -167,6 +192,11 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, } fb_helper->connector_count--; kfree(fb_helper_connector); + + /* also cleanup dangling references to the connector: */ + for (i = 0; i < fb_helper->crtc_count; i++) + remove_from_modeset(&fb_helper->crtc_info[i].mode_set, connector); + return 0; } EXPORT_SYMBOL(drm_fb_helper_remove_one_connector); @@ -741,7 +771,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) int i, j, rc = 0; int start; - drm_modeset_lock_all(dev); + if (__drm_modeset_lock_all(dev, !!oops_in_progress)) { + return -EBUSY; + } if (!drm_fb_helper_is_bound(fb_helper)) { drm_modeset_unlock_all(dev); return -EBUSY; @@ -915,7 +947,9 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, int ret = 0; int i; - drm_modeset_lock_all(dev); + if (__drm_modeset_lock_all(dev, !!oops_in_progress)) { + return -EBUSY; + } if (!drm_fb_helper_is_bound(fb_helper)) { drm_modeset_unlock_all(dev); return -EBUSY; diff --git a/drivers/gpu/drm/drm_vma_manager.c b/drivers/gpu/drm/drm_vma_manager.c index 63b471205072..68c1f32fb086 100644 --- a/drivers/gpu/drm/drm_vma_manager.c +++ b/drivers/gpu/drm/drm_vma_manager.c @@ -50,8 +50,7 @@ * * You must not use multiple offset managers on a single address_space. * Otherwise, mm-core will be unable to tear down memory mappings as the VM will - * no longer be linear. Please use VM_NONLINEAR in that case and implement your - * own offset managers. + * no longer be linear. * * This offset manager works on page-based addresses. That is, every argument * and return code (with the exception of drm_vma_node_offset_addr()) is given diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 121470a83d1a..1bcbe07cecfc 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -645,18 +645,6 @@ static int exynos_drm_init(void) if (!is_exynos) return -ENODEV; - /* - * Register device object only in case of Exynos SoC. - * - * Below codes resolves temporarily infinite loop issue incurred - * by Exynos drm driver when using multi-platform kernel. - * So these codes will be replaced with more generic way later. - */ - if (!of_machine_is_compatible("samsung,exynos3") && - !of_machine_is_compatible("samsung,exynos4") && - !of_machine_is_compatible("samsung,exynos5")) - return -ENODEV; - exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1, NULL, 0); if (IS_ERR(exynos_drm_pdev)) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 5765a161abdd..98051e8e855a 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1669,7 +1669,6 @@ static void hdmi_mode_apply(struct hdmi_context *hdata) static void hdmiphy_conf_reset(struct hdmi_context *hdata) { - u8 buffer[2]; u32 reg; clk_disable_unprepare(hdata->res.sclk_hdmi); @@ -1677,11 +1676,8 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata) clk_prepare_enable(hdata->res.sclk_hdmi); /* operation mode */ - buffer[0] = 0x1f; - buffer[1] = 0x00; - - if (hdata->hdmiphy_port) - i2c_master_send(hdata->hdmiphy_port, buffer, 2); + hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE, + HDMI_PHY_ENABLE_MODE_SET); if (hdata->type == HDMI_TYPE13) reg = HDMI_V13_PHY_RSTOUT; diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 820b76234ef4..064ed6597def 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1026,6 +1026,7 @@ static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos) static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr) { struct mixer_context *mixer_ctx = mgr_to_mixer(mgr); + int err; mutex_lock(&mixer_ctx->mixer_mutex); if (!mixer_ctx->powered) { @@ -1034,7 +1035,11 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr) } mutex_unlock(&mixer_ctx->mixer_mutex); - drm_vblank_get(mgr->crtc->dev, mixer_ctx->pipe); + err = drm_vblank_get(mgr->crtc->dev, mixer_ctx->pipe); + if (err < 0) { + DRM_DEBUG_KMS("failed to acquire vblank counter\n"); + return; + } atomic_set(&mixer_ctx->wait_vsync_event, 1); @@ -1262,8 +1267,6 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) return ret; } - pm_runtime_enable(dev); - return 0; } @@ -1272,8 +1275,6 @@ static void mixer_unbind(struct device *dev, struct device *master, void *data) struct mixer_context *ctx = dev_get_drvdata(dev); mixer_mgr_remove(&ctx->manager); - - pm_runtime_disable(dev); } static const struct component_ops mixer_component_ops = { diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index d4762799351d..a9041d1a8ff0 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -32,6 +32,8 @@ struct tda998x_priv { struct i2c_client *cec; struct i2c_client *hdmi; + struct mutex mutex; + struct delayed_work dwork; uint16_t rev; uint8_t current_page; int dpms; @@ -402,9 +404,10 @@ reg_read_range(struct tda998x_priv *priv, uint16_t reg, char *buf, int cnt) uint8_t addr = REG2ADDR(reg); int ret; + mutex_lock(&priv->mutex); ret = set_page(priv, reg); if (ret < 0) - return ret; + goto out; ret = i2c_master_send(client, &addr, sizeof(addr)); if (ret < 0) @@ -414,10 +417,12 @@ reg_read_range(struct tda998x_priv *priv, uint16_t reg, char *buf, int cnt) if (ret < 0) goto fail; - return ret; + goto out; fail: dev_err(&client->dev, "Error %d reading from 0x%x\n", ret, reg); +out: + mutex_unlock(&priv->mutex); return ret; } @@ -431,13 +436,16 @@ reg_write_range(struct tda998x_priv *priv, uint16_t reg, uint8_t *p, int cnt) buf[0] = REG2ADDR(reg); memcpy(&buf[1], p, cnt); + mutex_lock(&priv->mutex); ret = set_page(priv, reg); if (ret < 0) - return; + goto out; ret = i2c_master_send(client, buf, cnt + 1); if (ret < 0) dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg); +out: + mutex_unlock(&priv->mutex); } static int @@ -459,13 +467,16 @@ reg_write(struct tda998x_priv *priv, uint16_t reg, uint8_t val) uint8_t buf[] = {REG2ADDR(reg), val}; int ret; + mutex_lock(&priv->mutex); ret = set_page(priv, reg); if (ret < 0) - return; + goto out; ret = i2c_master_send(client, buf, sizeof(buf)); if (ret < 0) dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg); +out: + mutex_unlock(&priv->mutex); } static void @@ -475,13 +486,16 @@ reg_write16(struct tda998x_priv *priv, uint16_t reg, uint16_t val) uint8_t buf[] = {REG2ADDR(reg), val >> 8, val}; int ret; + mutex_lock(&priv->mutex); ret = set_page(priv, reg); if (ret < 0) - return; + goto out; ret = i2c_master_send(client, buf, sizeof(buf)); if (ret < 0) dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg); +out: + mutex_unlock(&priv->mutex); } static void @@ -536,6 +550,17 @@ tda998x_reset(struct tda998x_priv *priv) reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24); } +/* handle HDMI connect/disconnect */ +static void tda998x_hpd(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct tda998x_priv *priv = + container_of(dwork, struct tda998x_priv, dwork); + + if (priv->encoder && priv->encoder->dev) + drm_kms_helper_hotplug_event(priv->encoder->dev); +} + /* * only 2 interrupts may occur: screen plug/unplug and EDID read */ @@ -559,8 +584,7 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data) priv->wq_edid_wait = 0; wake_up(&priv->wq_edid); } else if (cec != 0) { /* HPD change */ - if (priv->encoder && priv->encoder->dev) - drm_helper_hpd_irq_event(priv->encoder->dev); + schedule_delayed_work(&priv->dwork, HZ/10); } return IRQ_HANDLED; } @@ -1170,8 +1194,10 @@ static void tda998x_destroy(struct tda998x_priv *priv) /* disable all IRQs and free the IRQ handler */ cec_write(priv, REG_CEC_RXSHPDINTENA, 0); reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); - if (priv->hdmi->irq) + if (priv->hdmi->irq) { free_irq(priv->hdmi->irq, priv); + cancel_delayed_work_sync(&priv->dwork); + } i2c_unregister_device(priv->cec); } @@ -1255,6 +1281,7 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) struct device_node *np = client->dev.of_node; u32 video; int rev_lo, rev_hi, ret; + unsigned short cec_addr; priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(2) | VIP_CNTRL_0_SWAP_B(3); priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1); @@ -1262,12 +1289,16 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) priv->current_page = 0xff; priv->hdmi = client; - priv->cec = i2c_new_dummy(client->adapter, 0x34); + /* CEC I2C address bound to TDA998x I2C addr by configuration pins */ + cec_addr = 0x34 + (client->addr & 0x03); + priv->cec = i2c_new_dummy(client->adapter, cec_addr); if (!priv->cec) return -ENODEV; priv->dpms = DRM_MODE_DPMS_OFF; + mutex_init(&priv->mutex); /* protect the page access */ + /* wake up the device: */ cec_write(priv, REG_CEC_ENAMODS, CEC_ENAMODS_EN_RXSENS | CEC_ENAMODS_EN_HDMI); @@ -1323,8 +1354,9 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) if (client->irq) { int irqf_trigger; - /* init read EDID waitqueue */ + /* init read EDID waitqueue and HDP work */ init_waitqueue_head(&priv->wq_edid); + INIT_DELAYED_WORK(&priv->dwork, tda998x_hpd); /* clear pending interrupts */ reg_read(priv, REG_INT_FLAGS_0); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index ecee3bcc8772..26b3199e0af2 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -830,6 +830,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_runtime_pm_enable(dev_priv); + i915_audio_component_init(dev_priv); + return 0; out_power_well: @@ -870,6 +872,8 @@ int i915_driver_unload(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret; + i915_audio_component_cleanup(dev_priv); + ret = i915_gem_suspend(dev); if (ret) { DRM_ERROR("failed to idle hardware: %d\n", ret); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 574057cd1d09..489b220af02b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -462,19 +462,13 @@ void intel_detect_pch(struct drm_device *dev) } else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_LPT; DRM_DEBUG_KMS("Found LynxPoint PCH\n"); - WARN_ON(!IS_HASWELL(dev)); - WARN_ON(IS_HSW_ULT(dev)); - } else if (IS_BROADWELL(dev)) { - dev_priv->pch_type = PCH_LPT; - dev_priv->pch_id = - INTEL_PCH_LPT_LP_DEVICE_ID_TYPE; - DRM_DEBUG_KMS("This is Broadwell, assuming " - "LynxPoint LP PCH\n"); + WARN_ON(!IS_HASWELL(dev) && !IS_BROADWELL(dev)); + WARN_ON(IS_HSW_ULT(dev) || IS_BDW_ULT(dev)); } else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_LPT; DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); - WARN_ON(!IS_HASWELL(dev)); - WARN_ON(!IS_HSW_ULT(dev)); + WARN_ON(!IS_HASWELL(dev) && !IS_BROADWELL(dev)); + WARN_ON(!IS_HSW_ULT(dev) && !IS_BDW_ULT(dev)); } else if (id == INTEL_PCH_SPT_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_SPT; DRM_DEBUG_KMS("Found SunrisePoint PCH\n"); @@ -940,8 +934,7 @@ static int i915_pm_suspend(struct device *dev) static int i915_pm_suspend_late(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_to_i915(dev)->dev; /* * We have a suspedn ordering issue with the snd-hda driver also @@ -960,8 +953,7 @@ static int i915_pm_suspend_late(struct device *dev) static int i915_pm_resume_early(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_to_i915(dev)->dev; if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; @@ -971,8 +963,7 @@ static int i915_pm_resume_early(struct device *dev) static int i915_pm_resume(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_to_i915(dev)->dev; if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e9f891c432f8..24cc36a9f3ff 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1698,6 +1698,9 @@ struct drm_i915_private { struct drm_property *broadcast_rgb_property; struct drm_property *force_audio_property; + /* hda/i915 audio component */ + bool audio_component_registered; + uint32_t hw_context_size; struct list_head context_list; @@ -1781,6 +1784,11 @@ static inline struct drm_i915_private *to_i915(const struct drm_device *dev) return dev->dev_private; } +static inline struct drm_i915_private *dev_to_i915(struct device *dev) +{ + return to_i915(dev_get_drvdata(dev)); +} + /* Iterate over initialised rings */ #define for_each_ring(ring__, dev_priv__, i__) \ for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \ @@ -2159,8 +2167,7 @@ struct drm_i915_cmd_table { #define IS_HSW_EARLY_SDV(dev) (IS_HASWELL(dev) && \ (INTEL_DEVID(dev) & 0xFF00) == 0x0C00) #define IS_BDW_ULT(dev) (IS_BROADWELL(dev) && \ - ((INTEL_DEVID(dev) & 0xf) == 0x2 || \ - (INTEL_DEVID(dev) & 0xf) == 0x6 || \ + ((INTEL_DEVID(dev) & 0xf) == 0x6 || \ (INTEL_DEVID(dev) & 0xf) == 0xe)) #define IS_BDW_GT3(dev) (IS_BROADWELL(dev) && \ (INTEL_DEVID(dev) & 0x00F0) == 0x0020) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c11603b4cf1d..5f614828d365 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3148,6 +3148,13 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg, u32 size = i915_gem_obj_ggtt_size(obj); uint64_t val; + /* Adjust fence size to match tiled area */ + if (obj->tiling_mode != I915_TILING_NONE) { + uint32_t row_size = obj->stride * + (obj->tiling_mode == I915_TILING_Y ? 32 : 8); + size = (size / row_size) * row_size; + } + val = (uint64_t)((i915_gem_obj_ggtt_offset(obj) + size - 4096) & 0xfffff000) << 32; val |= i915_gem_obj_ggtt_offset(obj) & 0xfffff000; @@ -4884,13 +4891,12 @@ i915_gem_init_hw(struct drm_device *dev) for (i = 0; i < NUM_L3_SLICES(dev); i++) i915_gem_l3_remap(&dev_priv->ring[RCS], i); - /* - * XXX: Contexts should only be initialized once. Doing a switch to the - * default context switch however is something we'd like to do after - * reset or thaw (the latter may not actually be necessary for HW, but - * goes with our code better). Context switching requires rings (for - * the do_switch), but before enabling PPGTT. So don't move this. - */ + ret = i915_ppgtt_init_hw(dev); + if (ret && ret != -EIO) { + DRM_ERROR("PPGTT enable failed %d\n", ret); + i915_gem_cleanup_ringbuffer(dev); + } + ret = i915_gem_context_enable(dev_priv); if (ret && ret != -EIO) { DRM_ERROR("Context enable failed %d\n", ret); @@ -4899,12 +4905,6 @@ i915_gem_init_hw(struct drm_device *dev) return ret; } - ret = i915_ppgtt_init_hw(dev); - if (ret && ret != -EIO) { - DRM_ERROR("PPGTT enable failed %d\n", ret); - i915_gem_cleanup_ringbuffer(dev); - } - return ret; } @@ -5155,7 +5155,7 @@ static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task) if (!mutex_is_locked(mutex)) return false; -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES) +#if defined(CONFIG_SMP) && !defined(CONFIG_DEBUG_MUTEXES) return mutex->owner == task; #else /* Since UP may be pre-empted, we cannot assume that we own the lock */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d0d3dfbe6d2a..b051a238baf9 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -292,6 +292,23 @@ void gen6_enable_rps_interrupts(struct drm_device *dev) spin_unlock_irq(&dev_priv->irq_lock); } +u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask) +{ + /* + * SNB,IVB can while VLV,CHV may hard hang on looping batchbuffer + * if GEN6_PM_UP_EI_EXPIRED is masked. + * + * TODO: verify if this can be reproduced on VLV,CHV. + */ + if (INTEL_INFO(dev_priv)->gen <= 7 && !IS_HASWELL(dev_priv)) + mask &= ~GEN6_PM_RP_UP_EI_EXPIRED; + + if (INTEL_INFO(dev_priv)->gen >= 8) + mask &= ~GEN8_PMINTR_REDIRECT_TO_NON_DISP; + + return mask; +} + void gen6_disable_rps_interrupts(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -304,8 +321,7 @@ void gen6_disable_rps_interrupts(struct drm_device *dev) spin_lock_irq(&dev_priv->irq_lock); - I915_WRITE(GEN6_PMINTRMSK, INTEL_INFO(dev_priv)->gen >= 8 ? - ~GEN8_PMINTR_REDIRECT_TO_NON_DISP : ~0); + I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0)); __gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events); I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) & diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 2c7ed5cb29c0..ee41b882e71a 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -22,6 +22,9 @@ */ #include +#include +#include +#include "intel_drv.h" #include #include @@ -461,3 +464,110 @@ void intel_init_audio(struct drm_device *dev) dev_priv->display.audio_codec_disable = ilk_audio_codec_disable; } } + +static void i915_audio_component_get_power(struct device *dev) +{ + intel_display_power_get(dev_to_i915(dev), POWER_DOMAIN_AUDIO); +} + +static void i915_audio_component_put_power(struct device *dev) +{ + intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO); +} + +/* Get CDCLK in kHz */ +static int i915_audio_component_get_cdclk_freq(struct device *dev) +{ + struct drm_i915_private *dev_priv = dev_to_i915(dev); + int ret; + + if (WARN_ON_ONCE(!HAS_DDI(dev_priv))) + return -ENODEV; + + intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO); + ret = intel_ddi_get_cdclk_freq(dev_priv); + intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); + + return ret; +} + +static const struct i915_audio_component_ops i915_audio_component_ops = { + .owner = THIS_MODULE, + .get_power = i915_audio_component_get_power, + .put_power = i915_audio_component_put_power, + .get_cdclk_freq = i915_audio_component_get_cdclk_freq, +}; + +static int i915_audio_component_bind(struct device *i915_dev, + struct device *hda_dev, void *data) +{ + struct i915_audio_component *acomp = data; + + if (WARN_ON(acomp->ops || acomp->dev)) + return -EEXIST; + + acomp->ops = &i915_audio_component_ops; + acomp->dev = i915_dev; + + return 0; +} + +static void i915_audio_component_unbind(struct device *i915_dev, + struct device *hda_dev, void *data) +{ + struct i915_audio_component *acomp = data; + + acomp->ops = NULL; + acomp->dev = NULL; +} + +static const struct component_ops i915_audio_component_bind_ops = { + .bind = i915_audio_component_bind, + .unbind = i915_audio_component_unbind, +}; + +/** + * i915_audio_component_init - initialize and register the audio component + * @dev_priv: i915 device instance + * + * This will register with the component framework a child component which + * will bind dynamically to the snd_hda_intel driver's corresponding master + * component when the latter is registered. During binding the child + * initializes an instance of struct i915_audio_component which it receives + * from the master. The master can then start to use the interface defined by + * this struct. Each side can break the binding at any point by deregistering + * its own component after which each side's component unbind callback is + * called. + * + * We ignore any error during registration and continue with reduced + * functionality (i.e. without HDMI audio). + */ +void i915_audio_component_init(struct drm_i915_private *dev_priv) +{ + int ret; + + ret = component_add(dev_priv->dev->dev, &i915_audio_component_bind_ops); + if (ret < 0) { + DRM_ERROR("failed to add audio component (%d)\n", ret); + /* continue with reduced functionality */ + return; + } + + dev_priv->audio_component_registered = true; +} + +/** + * i915_audio_component_cleanup - deregister the audio component + * @dev_priv: i915 device instance + * + * Deregisters the audio component, breaking any existing binding to the + * corresponding snd_hda_intel driver's master component. + */ +void i915_audio_component_cleanup(struct drm_i915_private *dev_priv) +{ + if (!dev_priv->audio_component_registered) + return; + + component_del(dev_priv->dev->dev, &i915_audio_component_bind_ops); + dev_priv->audio_component_registered = false; +} diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e2af1383b179..e7a16f119a29 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9815,7 +9815,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, if (obj->tiling_mode != work->old_fb_obj->tiling_mode) /* vlv: DISPLAY_FLIP fails to change tiling */ ring = NULL; - } else if (IS_IVYBRIDGE(dev)) { + } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { ring = &dev_priv->ring[BCS]; } else if (INTEL_INFO(dev)->gen >= 7) { ring = obj->ring; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 25fdbb16d4e0..29ba962d15e3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -794,6 +794,7 @@ void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); void gen6_reset_rps_interrupts(struct drm_device *dev); void gen6_enable_rps_interrupts(struct drm_device *dev); void gen6_disable_rps_interrupts(struct drm_device *dev); +u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask); void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv); void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv); static inline bool intel_irqs_enabled(struct drm_i915_private *dev_priv) @@ -872,6 +873,8 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire); void intel_init_audio(struct drm_device *dev); void intel_audio_codec_enable(struct intel_encoder *encoder); void intel_audio_codec_disable(struct intel_encoder *encoder); +void i915_audio_component_init(struct drm_i915_private *dev_priv); +void i915_audio_component_cleanup(struct drm_i915_private *dev_priv); /* intel_display.c */ const char *intel_output_name(int output); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 4d63839bd9b4..dfb783a8f2c3 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -962,7 +962,7 @@ void intel_panel_enable_backlight(struct intel_connector *connector) WARN_ON(panel->backlight.max == 0); - if (panel->backlight.level == 0) { + if (panel->backlight.level <= panel->backlight.min) { panel->backlight.level = panel->backlight.max; if (panel->backlight.device) panel->backlight.device->props.brightness = diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 964b28e3c630..bf814a64582a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4363,16 +4363,7 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val) mask |= dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED); mask &= dev_priv->pm_rps_events; - /* IVB and SNB hard hangs on looping batchbuffer - * if GEN6_PM_UP_EI_EXPIRED is masked. - */ - if (INTEL_INFO(dev_priv->dev)->gen <= 7 && !IS_HASWELL(dev_priv->dev)) - mask |= GEN6_PM_RP_UP_EI_EXPIRED; - - if (IS_GEN8(dev_priv->dev)) - mask |= GEN8_PMINTR_REDIRECT_TO_NON_DISP; - - return ~mask; + return gen6_sanitize_rps_pm_mask(dev_priv, ~mask); } /* gen6_set_rps is called to update the frequency request, but should also be @@ -4441,7 +4432,8 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv) return; /* Mask turbo interrupt so that they will not come in between */ - I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); + I915_WRITE(GEN6_PMINTRMSK, + gen6_sanitize_rps_pm_mask(dev_priv, ~0)); vlv_force_gfx_clock(dev_priv, true); diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index ac6da7102fbb..39ddf40171bf 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -31,7 +31,6 @@ #include "i915_drv.h" #include "intel_drv.h" -#include /** * DOC: runtime pm @@ -50,8 +49,6 @@ * present for a given platform. */ -static struct i915_power_domains *hsw_pwr; - #define for_each_power_well(i, power_well, domain_mask, power_domains) \ for (i = 0; \ i < (power_domains)->power_well_count && \ @@ -1071,10 +1068,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) */ if (IS_HASWELL(dev_priv->dev)) { set_power_wells(power_domains, hsw_power_wells); - hsw_pwr = power_domains; } else if (IS_BROADWELL(dev_priv->dev)) { set_power_wells(power_domains, bdw_power_wells); - hsw_pwr = power_domains; } else if (IS_CHERRYVIEW(dev_priv->dev)) { set_power_wells(power_domains, chv_power_wells); } else if (IS_VALLEYVIEW(dev_priv->dev)) { @@ -1118,8 +1113,6 @@ void intel_power_domains_fini(struct drm_i915_private *dev_priv) * the power well is not enabled, so just enable it in case * we're going to unload/reload. */ intel_display_set_init_power(dev_priv, true); - - hsw_pwr = NULL; } static void intel_power_domains_resume(struct drm_i915_private *dev_priv) @@ -1328,52 +1321,3 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv) pm_runtime_put_autosuspend(device); } -/* Display audio driver power well request */ -int i915_request_power_well(void) -{ - struct drm_i915_private *dev_priv; - - if (!hsw_pwr) - return -ENODEV; - - dev_priv = container_of(hsw_pwr, struct drm_i915_private, - power_domains); - intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO); - return 0; -} -EXPORT_SYMBOL_GPL(i915_request_power_well); - -/* Display audio driver power well release */ -int i915_release_power_well(void) -{ - struct drm_i915_private *dev_priv; - - if (!hsw_pwr) - return -ENODEV; - - dev_priv = container_of(hsw_pwr, struct drm_i915_private, - power_domains); - intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO); - return 0; -} -EXPORT_SYMBOL_GPL(i915_release_power_well); - -/* - * Private interface for the audio driver to get CDCLK in kHz. - * - * Caller must request power well using i915_request_power_well() prior to - * making the call. - */ -int i915_get_cdclk_freq(void) -{ - struct drm_i915_private *dev_priv; - - if (!hsw_pwr) - return -ENODEV; - - dev_priv = container_of(hsw_pwr, struct drm_i915_private, - power_domains); - - return intel_ddi_get_cdclk_freq(dev_priv); -} -EXPORT_SYMBOL_GPL(i915_get_cdclk_freq); diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 6dcde3798b45..64fdae558d36 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -6033,6 +6033,17 @@ void cik_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, radeon_ring_write(ring, 0); radeon_ring_write(ring, 1 << vm_id); + /* wait for the invalidate to complete */ + radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); + radeon_ring_write(ring, (WAIT_REG_MEM_OPERATION(0) | /* wait */ + WAIT_REG_MEM_FUNCTION(0) | /* always */ + WAIT_REG_MEM_ENGINE(0))); /* me */ + radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, 0); /* ref */ + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, 0x20); /* poll interval */ + /* compute doesn't have PFP */ if (usepfp) { /* sync PFP to ME, otherwise we might get invalid PFP reads */ diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c index dde5c7e29eb2..42cd0cffe210 100644 --- a/drivers/gpu/drm/radeon/cik_sdma.c +++ b/drivers/gpu/drm/radeon/cik_sdma.c @@ -816,7 +816,6 @@ void cik_sdma_vm_write_pages(struct radeon_device *rdev, for (; ndw > 0; ndw -= 2, --count, pe += 8) { if (flags & R600_PTE_SYSTEM) { value = radeon_vm_map_gart(rdev, addr); - value &= 0xFFFFFFFFFFFFF000ULL; } else if (flags & R600_PTE_VALID) { value = addr; } else { @@ -903,6 +902,9 @@ void cik_sdma_vm_pad_ib(struct radeon_ib *ib) void cik_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, unsigned vm_id, uint64_t pd_addr) { + u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(0) | + SDMA_POLL_REG_MEM_EXTRA_FUNC(0)); /* always */ + radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); if (vm_id < 8) { radeon_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2); @@ -943,5 +945,12 @@ void cik_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000)); radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); radeon_ring_write(ring, 1 << vm_id); + + radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits)); + radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, 0); /* reference */ + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, (0xfff << 16) | 10); /* retry count, poll interval */ } diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 360de9f1f491..aea48c89b241 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -2516,6 +2516,16 @@ void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, radeon_ring_write(ring, PACKET0(VM_INVALIDATE_REQUEST, 0)); radeon_ring_write(ring, 1 << vm_id); + /* wait for the invalidate to complete */ + radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); + radeon_ring_write(ring, (WAIT_REG_MEM_FUNCTION(0) | /* always */ + WAIT_REG_MEM_ENGINE(0))); /* me */ + radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, 0); /* ref */ + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, 0x20); /* poll interval */ + /* sync PFP to ME, otherwise we might get invalid PFP reads */ radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); radeon_ring_write(ring, 0x0); diff --git a/drivers/gpu/drm/radeon/ni_dma.c b/drivers/gpu/drm/radeon/ni_dma.c index 50f88611ff60..ce787a9f12c0 100644 --- a/drivers/gpu/drm/radeon/ni_dma.c +++ b/drivers/gpu/drm/radeon/ni_dma.c @@ -372,7 +372,6 @@ void cayman_dma_vm_write_pages(struct radeon_device *rdev, for (; ndw > 0; ndw -= 2, --count, pe += 8) { if (flags & R600_PTE_SYSTEM) { value = radeon_vm_map_gart(rdev, addr); - value &= 0xFFFFFFFFFFFFF000ULL; } else if (flags & R600_PTE_VALID) { value = addr; } else { @@ -463,5 +462,11 @@ void cayman_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0)); radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2)); radeon_ring_write(ring, 1 << vm_id); + + /* wait for invalidate to complete */ + radeon_ring_write(ring, DMA_SRBM_READ_PACKET); + radeon_ring_write(ring, (0xff << 20) | (VM_INVALIDATE_REQUEST >> 2)); + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, 0); /* value */ } diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h index 2e12e4d69253..ad7125486894 100644 --- a/drivers/gpu/drm/radeon/nid.h +++ b/drivers/gpu/drm/radeon/nid.h @@ -1133,6 +1133,23 @@ #define PACKET3_MEM_SEMAPHORE 0x39 #define PACKET3_MPEG_INDEX 0x3A #define PACKET3_WAIT_REG_MEM 0x3C +#define WAIT_REG_MEM_FUNCTION(x) ((x) << 0) + /* 0 - always + * 1 - < + * 2 - <= + * 3 - == + * 4 - != + * 5 - >= + * 6 - > + */ +#define WAIT_REG_MEM_MEM_SPACE(x) ((x) << 4) + /* 0 - reg + * 1 - mem + */ +#define WAIT_REG_MEM_ENGINE(x) ((x) << 8) + /* 0 - me + * 1 - pfp + */ #define PACKET3_MEM_WRITE 0x3D #define PACKET3_PFP_SYNC_ME 0x42 #define PACKET3_SURFACE_SYNC 0x43 @@ -1272,6 +1289,13 @@ (1 << 21) | \ (((n) & 0xFFFFF) << 0)) +#define DMA_SRBM_POLL_PACKET ((9 << 28) | \ + (1 << 27) | \ + (1 << 26)) + +#define DMA_SRBM_READ_PACKET ((9 << 28) | \ + (1 << 27)) + /* async DMA Packet types */ #define DMA_PACKET_WRITE 0x2 #define DMA_PACKET_COPY 0x3 diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 74f06d540591..279801ca5110 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -644,6 +644,7 @@ int r100_pci_gart_init(struct radeon_device *rdev) return r; rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush; + rdev->asic->gart.get_page_entry = &r100_pci_gart_get_page_entry; rdev->asic->gart.set_page = &r100_pci_gart_set_page; return radeon_gart_table_ram_alloc(rdev); } @@ -681,11 +682,16 @@ void r100_pci_gart_disable(struct radeon_device *rdev) WREG32(RADEON_AIC_HI_ADDR, 0); } +uint64_t r100_pci_gart_get_page_entry(uint64_t addr, uint32_t flags) +{ + return addr; +} + void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags) + uint64_t entry) { u32 *gtt = rdev->gart.ptr; - gtt[i] = cpu_to_le32(lower_32_bits(addr)); + gtt[i] = cpu_to_le32(lower_32_bits(entry)); } void r100_pci_gart_fini(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 064ad5569cca..08d68f3e13e9 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -73,11 +73,8 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev) #define R300_PTE_WRITEABLE (1 << 2) #define R300_PTE_READABLE (1 << 3) -void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags) +uint64_t rv370_pcie_gart_get_page_entry(uint64_t addr, uint32_t flags) { - void __iomem *ptr = rdev->gart.ptr; - addr = (lower_32_bits(addr) >> 8) | ((upper_32_bits(addr) & 0xff) << 24); if (flags & RADEON_GART_PAGE_READ) @@ -86,10 +83,18 @@ void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i, addr |= R300_PTE_WRITEABLE; if (!(flags & RADEON_GART_PAGE_SNOOP)) addr |= R300_PTE_UNSNOOPED; + return addr; +} + +void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i, + uint64_t entry) +{ + void __iomem *ptr = rdev->gart.ptr; + /* on x86 we want this to be CPU endian, on powerpc * on powerpc without HW swappers, it'll get swapped on way * into VRAM - so no need for cpu_to_le32 on VRAM tables */ - writel(addr, ((void __iomem *)ptr) + (i * 4)); + writel(entry, ((void __iomem *)ptr) + (i * 4)); } int rv370_pcie_gart_init(struct radeon_device *rdev) @@ -109,6 +114,7 @@ int rv370_pcie_gart_init(struct radeon_device *rdev) DRM_ERROR("Failed to register debugfs file for PCIE gart !\n"); rdev->gart.table_size = rdev->gart.num_gpu_pages * 4; rdev->asic->gart.tlb_flush = &rv370_pcie_gart_tlb_flush; + rdev->asic->gart.get_page_entry = &rv370_pcie_gart_get_page_entry; rdev->asic->gart.set_page = &rv370_pcie_gart_set_page; return radeon_gart_table_vram_alloc(rdev); } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 54529b837afa..3f2a8d3febca 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -242,6 +242,7 @@ bool radeon_get_bios(struct radeon_device *rdev); * Dummy page */ struct radeon_dummy_page { + uint64_t entry; struct page *page; dma_addr_t addr; }; @@ -645,7 +646,7 @@ struct radeon_gart { unsigned num_cpu_pages; unsigned table_size; struct page **pages; - dma_addr_t *pages_addr; + uint64_t *pages_entry; bool ready; }; @@ -1847,8 +1848,9 @@ struct radeon_asic { /* gart */ struct { void (*tlb_flush)(struct radeon_device *rdev); + uint64_t (*get_page_entry)(uint64_t addr, uint32_t flags); void (*set_page)(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); } gart; struct { int (*init)(struct radeon_device *rdev); @@ -2852,7 +2854,8 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v) #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state)) #define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev)) #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart.tlb_flush((rdev)) -#define radeon_gart_set_page(rdev, i, p, f) (rdev)->asic->gart.set_page((rdev), (i), (p), (f)) +#define radeon_gart_get_page_entry(a, f) (rdev)->asic->gart.get_page_entry((a), (f)) +#define radeon_gart_set_page(rdev, i, e) (rdev)->asic->gart.set_page((rdev), (i), (e)) #define radeon_asic_vm_init(rdev) (rdev)->asic->vm.init((rdev)) #define radeon_asic_vm_fini(rdev) (rdev)->asic->vm.fini((rdev)) #define radeon_asic_vm_copy_pages(rdev, ib, pe, src, count) ((rdev)->asic->vm.copy_pages((rdev), (ib), (pe), (src), (count))) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 850de57069be..ed0e10eee2dc 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -159,11 +159,13 @@ void radeon_agp_disable(struct radeon_device *rdev) DRM_INFO("Forcing AGP to PCIE mode\n"); rdev->flags |= RADEON_IS_PCIE; rdev->asic->gart.tlb_flush = &rv370_pcie_gart_tlb_flush; + rdev->asic->gart.get_page_entry = &rv370_pcie_gart_get_page_entry; rdev->asic->gart.set_page = &rv370_pcie_gart_set_page; } else { DRM_INFO("Forcing AGP to PCI mode\n"); rdev->flags |= RADEON_IS_PCI; rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush; + rdev->asic->gart.get_page_entry = &r100_pci_gart_get_page_entry; rdev->asic->gart.set_page = &r100_pci_gart_set_page; } rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024; @@ -199,6 +201,7 @@ static struct radeon_asic r100_asic = { .mc_wait_for_idle = &r100_mc_wait_for_idle, .gart = { .tlb_flush = &r100_pci_gart_tlb_flush, + .get_page_entry = &r100_pci_gart_get_page_entry, .set_page = &r100_pci_gart_set_page, }, .ring = { @@ -265,6 +268,7 @@ static struct radeon_asic r200_asic = { .mc_wait_for_idle = &r100_mc_wait_for_idle, .gart = { .tlb_flush = &r100_pci_gart_tlb_flush, + .get_page_entry = &r100_pci_gart_get_page_entry, .set_page = &r100_pci_gart_set_page, }, .ring = { @@ -333,6 +337,20 @@ static struct radeon_asic_ring r300_gfx_ring = { .set_wptr = &r100_gfx_set_wptr, }; +static struct radeon_asic_ring rv515_gfx_ring = { + .ib_execute = &r100_ring_ib_execute, + .emit_fence = &r300_fence_ring_emit, + .emit_semaphore = &r100_semaphore_ring_emit, + .cs_parse = &r300_cs_parse, + .ring_start = &rv515_ring_start, + .ring_test = &r100_ring_test, + .ib_test = &r100_ib_test, + .is_lockup = &r100_gpu_is_lockup, + .get_rptr = &r100_gfx_get_rptr, + .get_wptr = &r100_gfx_get_wptr, + .set_wptr = &r100_gfx_set_wptr, +}; + static struct radeon_asic r300_asic = { .init = &r300_init, .fini = &r300_fini, @@ -345,6 +363,7 @@ static struct radeon_asic r300_asic = { .mc_wait_for_idle = &r300_mc_wait_for_idle, .gart = { .tlb_flush = &r100_pci_gart_tlb_flush, + .get_page_entry = &r100_pci_gart_get_page_entry, .set_page = &r100_pci_gart_set_page, }, .ring = { @@ -411,6 +430,7 @@ static struct radeon_asic r300_asic_pcie = { .mc_wait_for_idle = &r300_mc_wait_for_idle, .gart = { .tlb_flush = &rv370_pcie_gart_tlb_flush, + .get_page_entry = &rv370_pcie_gart_get_page_entry, .set_page = &rv370_pcie_gart_set_page, }, .ring = { @@ -477,6 +497,7 @@ static struct radeon_asic r420_asic = { .mc_wait_for_idle = &r300_mc_wait_for_idle, .gart = { .tlb_flush = &rv370_pcie_gart_tlb_flush, + .get_page_entry = &rv370_pcie_gart_get_page_entry, .set_page = &rv370_pcie_gart_set_page, }, .ring = { @@ -543,6 +564,7 @@ static struct radeon_asic rs400_asic = { .mc_wait_for_idle = &rs400_mc_wait_for_idle, .gart = { .tlb_flush = &rs400_gart_tlb_flush, + .get_page_entry = &rs400_gart_get_page_entry, .set_page = &rs400_gart_set_page, }, .ring = { @@ -609,6 +631,7 @@ static struct radeon_asic rs600_asic = { .mc_wait_for_idle = &rs600_mc_wait_for_idle, .gart = { .tlb_flush = &rs600_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -677,6 +700,7 @@ static struct radeon_asic rs690_asic = { .mc_wait_for_idle = &rs690_mc_wait_for_idle, .gart = { .tlb_flush = &rs400_gart_tlb_flush, + .get_page_entry = &rs400_gart_get_page_entry, .set_page = &rs400_gart_set_page, }, .ring = { @@ -745,10 +769,11 @@ static struct radeon_asic rv515_asic = { .mc_wait_for_idle = &rv515_mc_wait_for_idle, .gart = { .tlb_flush = &rv370_pcie_gart_tlb_flush, + .get_page_entry = &rv370_pcie_gart_get_page_entry, .set_page = &rv370_pcie_gart_set_page, }, .ring = { - [RADEON_RING_TYPE_GFX_INDEX] = &r300_gfx_ring + [RADEON_RING_TYPE_GFX_INDEX] = &rv515_gfx_ring }, .irq = { .set = &rs600_irq_set, @@ -811,10 +836,11 @@ static struct radeon_asic r520_asic = { .mc_wait_for_idle = &r520_mc_wait_for_idle, .gart = { .tlb_flush = &rv370_pcie_gart_tlb_flush, + .get_page_entry = &rv370_pcie_gart_get_page_entry, .set_page = &rv370_pcie_gart_set_page, }, .ring = { - [RADEON_RING_TYPE_GFX_INDEX] = &r300_gfx_ring + [RADEON_RING_TYPE_GFX_INDEX] = &rv515_gfx_ring }, .irq = { .set = &rs600_irq_set, @@ -905,6 +931,7 @@ static struct radeon_asic r600_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &r600_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -990,6 +1017,7 @@ static struct radeon_asic rv6xx_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &r600_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1081,6 +1109,7 @@ static struct radeon_asic rs780_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &r600_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1185,6 +1214,7 @@ static struct radeon_asic rv770_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &r600_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1303,6 +1333,7 @@ static struct radeon_asic evergreen_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &evergreen_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1395,6 +1426,7 @@ static struct radeon_asic sumo_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &evergreen_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1486,6 +1518,7 @@ static struct radeon_asic btc_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &evergreen_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .ring = { @@ -1621,6 +1654,7 @@ static struct radeon_asic cayman_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &cayman_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { @@ -1724,6 +1758,7 @@ static struct radeon_asic trinity_asic = { .get_gpu_clock_counter = &r600_get_gpu_clock_counter, .gart = { .tlb_flush = &cayman_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { @@ -1857,6 +1892,7 @@ static struct radeon_asic si_asic = { .get_gpu_clock_counter = &si_get_gpu_clock_counter, .gart = { .tlb_flush = &si_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { @@ -2018,6 +2054,7 @@ static struct radeon_asic ci_asic = { .get_gpu_clock_counter = &cik_get_gpu_clock_counter, .gart = { .tlb_flush = &cik_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { @@ -2125,6 +2162,7 @@ static struct radeon_asic kv_asic = { .get_gpu_clock_counter = &cik_get_gpu_clock_counter, .gart = { .tlb_flush = &cik_pcie_gart_tlb_flush, + .get_page_entry = &rs600_gart_get_page_entry, .set_page = &rs600_gart_set_page, }, .vm = { diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 2a45d548d5ec..8d787d115653 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -67,8 +67,9 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp); int r100_asic_reset(struct radeon_device *rdev); u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc); void r100_pci_gart_tlb_flush(struct radeon_device *rdev); +uint64_t r100_pci_gart_get_page_entry(uint64_t addr, uint32_t flags); void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring); int r100_irq_set(struct radeon_device *rdev); int r100_irq_process(struct radeon_device *rdev); @@ -172,8 +173,9 @@ extern void r300_fence_ring_emit(struct radeon_device *rdev, struct radeon_fence *fence); extern int r300_cs_parse(struct radeon_cs_parser *p); extern void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev); +extern uint64_t rv370_pcie_gart_get_page_entry(uint64_t addr, uint32_t flags); extern void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); extern void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes); extern int rv370_get_pcie_lanes(struct radeon_device *rdev); extern void r300_set_reg_safe(struct radeon_device *rdev); @@ -208,8 +210,9 @@ extern void rs400_fini(struct radeon_device *rdev); extern int rs400_suspend(struct radeon_device *rdev); extern int rs400_resume(struct radeon_device *rdev); void rs400_gart_tlb_flush(struct radeon_device *rdev); +uint64_t rs400_gart_get_page_entry(uint64_t addr, uint32_t flags); void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); int rs400_gart_init(struct radeon_device *rdev); @@ -232,8 +235,9 @@ int rs600_irq_process(struct radeon_device *rdev); void rs600_irq_disable(struct radeon_device *rdev); u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc); void rs600_gart_tlb_flush(struct radeon_device *rdev); +uint64_t rs600_gart_get_page_entry(uint64_t addr, uint32_t flags); void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags); + uint64_t entry); uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void rs600_bandwidth_update(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c index 9e7f23dd14bd..87d5fb21cb61 100644 --- a/drivers/gpu/drm/radeon/radeon_benchmark.c +++ b/drivers/gpu/drm/radeon/radeon_benchmark.c @@ -34,7 +34,8 @@ static int radeon_benchmark_do_move(struct radeon_device *rdev, unsigned size, uint64_t saddr, uint64_t daddr, - int flag, int n) + int flag, int n, + struct reservation_object *resv) { unsigned long start_jiffies; unsigned long end_jiffies; @@ -47,12 +48,12 @@ static int radeon_benchmark_do_move(struct radeon_device *rdev, unsigned size, case RADEON_BENCHMARK_COPY_DMA: fence = radeon_copy_dma(rdev, saddr, daddr, size / RADEON_GPU_PAGE_SIZE, - NULL); + resv); break; case RADEON_BENCHMARK_COPY_BLIT: fence = radeon_copy_blit(rdev, saddr, daddr, size / RADEON_GPU_PAGE_SIZE, - NULL); + resv); break; default: DRM_ERROR("Unknown copy method\n"); @@ -120,7 +121,8 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size, if (rdev->asic->copy.dma) { time = radeon_benchmark_do_move(rdev, size, saddr, daddr, - RADEON_BENCHMARK_COPY_DMA, n); + RADEON_BENCHMARK_COPY_DMA, n, + dobj->tbo.resv); if (time < 0) goto out_cleanup; if (time > 0) @@ -130,7 +132,8 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size, if (rdev->asic->copy.blit) { time = radeon_benchmark_do_move(rdev, size, saddr, daddr, - RADEON_BENCHMARK_COPY_BLIT, n); + RADEON_BENCHMARK_COPY_BLIT, n, + dobj->tbo.resv); if (time < 0) goto out_cleanup; if (time > 0) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 0ec65168f331..bd7519fdd3f4 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -774,6 +774,8 @@ int radeon_dummy_page_init(struct radeon_device *rdev) rdev->dummy_page.page = NULL; return -ENOMEM; } + rdev->dummy_page.entry = radeon_gart_get_page_entry(rdev->dummy_page.addr, + RADEON_GART_PAGE_DUMMY); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 102116902a07..913fafa597ad 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -960,6 +960,9 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV && pll->flags & RADEON_PLL_USE_REF_DIV) ref_div_max = pll->reference_div; + else if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) + /* fix for problems on RS880 */ + ref_div_max = min(pll->max_ref_div, 7u); else ref_div_max = pll->max_ref_div; diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 84146d5901aa..5450fa95a47e 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -165,6 +165,19 @@ int radeon_gart_table_vram_pin(struct radeon_device *rdev) radeon_bo_unpin(rdev->gart.robj); radeon_bo_unreserve(rdev->gart.robj); rdev->gart.table_addr = gpu_addr; + + if (!r) { + int i; + + /* We might have dropped some GART table updates while it wasn't + * mapped, restore all entries + */ + for (i = 0; i < rdev->gart.num_gpu_pages; i++) + radeon_gart_set_page(rdev, i, rdev->gart.pages_entry[i]); + mb(); + radeon_gart_tlb_flush(rdev); + } + return r; } @@ -228,7 +241,6 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, unsigned t; unsigned p; int i, j; - u64 page_base; if (!rdev->gart.ready) { WARN(1, "trying to unbind memory from uninitialized GART !\n"); @@ -239,14 +251,12 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, for (i = 0; i < pages; i++, p++) { if (rdev->gart.pages[p]) { rdev->gart.pages[p] = NULL; - rdev->gart.pages_addr[p] = rdev->dummy_page.addr; - page_base = rdev->gart.pages_addr[p]; for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { + rdev->gart.pages_entry[t] = rdev->dummy_page.entry; if (rdev->gart.ptr) { - radeon_gart_set_page(rdev, t, page_base, - RADEON_GART_PAGE_DUMMY); + radeon_gart_set_page(rdev, t, + rdev->dummy_page.entry); } - page_base += RADEON_GPU_PAGE_SIZE; } } } @@ -274,7 +284,7 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, { unsigned t; unsigned p; - uint64_t page_base; + uint64_t page_base, page_entry; int i, j; if (!rdev->gart.ready) { @@ -285,14 +295,15 @@ 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++) { - rdev->gart.pages_addr[p] = dma_addr[i]; rdev->gart.pages[p] = pagelist[i]; - if (rdev->gart.ptr) { - page_base = rdev->gart.pages_addr[p]; - for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { - radeon_gart_set_page(rdev, t, page_base, flags); - page_base += RADEON_GPU_PAGE_SIZE; + page_base = dma_addr[i]; + for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { + page_entry = radeon_gart_get_page_entry(page_base, flags); + rdev->gart.pages_entry[t] = page_entry; + if (rdev->gart.ptr) { + radeon_gart_set_page(rdev, t, page_entry); } + page_base += RADEON_GPU_PAGE_SIZE; } } mb(); @@ -334,16 +345,15 @@ int radeon_gart_init(struct radeon_device *rdev) radeon_gart_fini(rdev); return -ENOMEM; } - rdev->gart.pages_addr = vzalloc(sizeof(dma_addr_t) * - rdev->gart.num_cpu_pages); - if (rdev->gart.pages_addr == NULL) { + rdev->gart.pages_entry = vmalloc(sizeof(uint64_t) * + rdev->gart.num_gpu_pages); + if (rdev->gart.pages_entry == NULL) { radeon_gart_fini(rdev); return -ENOMEM; } /* set GART entry to point to the dummy page by default */ - for (i = 0; i < rdev->gart.num_cpu_pages; i++) { - rdev->gart.pages_addr[i] = rdev->dummy_page.addr; - } + for (i = 0; i < rdev->gart.num_gpu_pages; i++) + rdev->gart.pages_entry[i] = rdev->dummy_page.entry; return 0; } @@ -356,15 +366,15 @@ int radeon_gart_init(struct radeon_device *rdev) */ void radeon_gart_fini(struct radeon_device *rdev) { - if (rdev->gart.pages && rdev->gart.pages_addr && rdev->gart.ready) { + if (rdev->gart.ready) { /* unbind pages */ radeon_gart_unbind(rdev, 0, rdev->gart.num_cpu_pages); } rdev->gart.ready = false; vfree(rdev->gart.pages); - vfree(rdev->gart.pages_addr); + vfree(rdev->gart.pages_entry); rdev->gart.pages = NULL; - rdev->gart.pages_addr = NULL; + rdev->gart.pages_entry = NULL; radeon_dummy_page_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index a46f73737994..ac3c1310b953 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -146,7 +146,8 @@ int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_pri struct radeon_bo_va *bo_va; int r; - if (rdev->family < CHIP_CAYMAN) { + if ((rdev->family < CHIP_CAYMAN) || + (!rdev->accel_working)) { return 0; } @@ -176,7 +177,8 @@ void radeon_gem_object_close(struct drm_gem_object *obj, struct radeon_bo_va *bo_va; int r; - if (rdev->family < CHIP_CAYMAN) { + if ((rdev->family < CHIP_CAYMAN) || + (!rdev->accel_working)) { return; } @@ -576,7 +578,7 @@ error_unreserve: error_free: drm_free_large(vm_bos); - if (r) + if (r && r != -ERESTARTSYS) DRM_ERROR("Couldn't update BO_VA (%d)\n", r); } diff --git a/drivers/gpu/drm/radeon/radeon_kfd.c b/drivers/gpu/drm/radeon/radeon_kfd.c index 8bf87f1203cc..bef9a0953284 100644 --- a/drivers/gpu/drm/radeon/radeon_kfd.c +++ b/drivers/gpu/drm/radeon/radeon_kfd.c @@ -436,7 +436,7 @@ static int kgd_init_memory(struct kgd_dev *kgd) static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id, uint32_t hpd_size, uint64_t hpd_gpu_addr) { - uint32_t mec = (++pipe_id / CIK_PIPE_PER_MEC) + 1; + uint32_t mec = (pipe_id / CIK_PIPE_PER_MEC) + 1; uint32_t pipe = (pipe_id % CIK_PIPE_PER_MEC); lock_srbm(kgd, mec, pipe, 0, 0); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 3cf9c1fa6475..686411e4e4f6 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -605,14 +605,14 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) return -ENOMEM; } - vm = &fpriv->vm; - r = radeon_vm_init(rdev, vm); - if (r) { - kfree(fpriv); - return r; - } - if (rdev->accel_working) { + vm = &fpriv->vm; + r = radeon_vm_init(rdev, vm); + if (r) { + kfree(fpriv); + return r; + } + r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); if (r) { radeon_vm_fini(rdev, vm); @@ -668,9 +668,9 @@ void radeon_driver_postclose_kms(struct drm_device *dev, radeon_vm_bo_rmv(rdev, vm->ib_bo_va); radeon_bo_unreserve(rdev->ring_tmp_bo.bo); } + radeon_vm_fini(rdev, vm); } - radeon_vm_fini(rdev, vm); kfree(fpriv); file_priv->driver_priv = NULL; } diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 32522cc940a1..f7da8fe96a66 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -1287,8 +1287,39 @@ dpm_failed: return ret; } +struct radeon_dpm_quirk { + u32 chip_vendor; + u32 chip_device; + u32 subsys_vendor; + u32 subsys_device; +}; + +/* cards with dpm stability problems */ +static struct radeon_dpm_quirk radeon_dpm_quirk_list[] = { + /* TURKS - https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1386534 */ + { PCI_VENDOR_ID_ATI, 0x6759, 0x1682, 0x3195 }, + /* TURKS - https://bugzilla.kernel.org/show_bug.cgi?id=83731 */ + { PCI_VENDOR_ID_ATI, 0x6840, 0x1179, 0xfb81 }, + { 0, 0, 0, 0 }, +}; + int radeon_pm_init(struct radeon_device *rdev) { + struct radeon_dpm_quirk *p = radeon_dpm_quirk_list; + bool disable_dpm = false; + + /* Apply dpm quirks */ + while (p && p->chip_device != 0) { + if (rdev->pdev->vendor == p->chip_vendor && + rdev->pdev->device == p->chip_device && + rdev->pdev->subsystem_vendor == p->subsys_vendor && + rdev->pdev->subsystem_device == p->subsys_device) { + disable_dpm = true; + break; + } + ++p; + } + /* enable dpm on rv6xx+ */ switch (rdev->family) { case CHIP_RV610: @@ -1344,6 +1375,8 @@ int radeon_pm_init(struct radeon_device *rdev) (!(rdev->flags & RADEON_IS_IGP)) && (!rdev->smc_fw)) rdev->pm.pm_method = PM_METHOD_PROFILE; + else if (disable_dpm && (radeon_dpm == -1)) + rdev->pm.pm_method = PM_METHOD_PROFILE; else if (radeon_dpm == 0) rdev->pm.pm_method = PM_METHOD_PROFILE; else diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index 07b506b41008..791818165c76 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c @@ -119,11 +119,11 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag) if (ring == R600_RING_TYPE_DMA_INDEX) fence = radeon_copy_dma(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, - NULL); + vram_obj->tbo.resv); else fence = radeon_copy_blit(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, - NULL); + vram_obj->tbo.resv); if (IS_ERR(fence)) { DRM_ERROR("Failed GTT->VRAM copy %d\n", i); r = PTR_ERR(fence); @@ -170,11 +170,11 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag) if (ring == R600_RING_TYPE_DMA_INDEX) fence = radeon_copy_dma(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, - NULL); + vram_obj->tbo.resv); else fence = radeon_copy_blit(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, - NULL); + vram_obj->tbo.resv); if (IS_ERR(fence)) { DRM_ERROR("Failed VRAM->GTT copy %d\n", i); r = PTR_ERR(fence); diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index cde48c42b30a..2a5a4a9e772d 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -587,10 +587,8 @@ uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr) uint64_t result; /* page table offset */ - result = rdev->gart.pages_addr[addr >> PAGE_SHIFT]; - - /* in case cpu page size != gpu page size*/ - result |= addr & (~PAGE_MASK); + result = rdev->gart.pages_entry[addr >> RADEON_GPU_PAGE_SHIFT]; + result &= ~RADEON_GPU_PAGE_MASK; return result; } @@ -745,9 +743,11 @@ static void radeon_vm_frag_ptes(struct radeon_device *rdev, */ /* NI is optimized for 256KB fragments, SI and newer for 64KB */ - uint64_t frag_flags = rdev->family == CHIP_CAYMAN ? + uint64_t frag_flags = ((rdev->family == CHIP_CAYMAN) || + (rdev->family == CHIP_ARUBA)) ? R600_PTE_FRAG_256KB : R600_PTE_FRAG_64KB; - uint64_t frag_align = rdev->family == CHIP_CAYMAN ? 0x200 : 0x80; + uint64_t frag_align = ((rdev->family == CHIP_CAYMAN) || + (rdev->family == CHIP_ARUBA)) ? 0x200 : 0x80; uint64_t frag_start = ALIGN(pe_start, frag_align); uint64_t frag_end = pe_end & ~(frag_align - 1); diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index c5799f16aa4b..34e3235f41d2 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -212,11 +212,9 @@ void rs400_gart_fini(struct radeon_device *rdev) #define RS400_PTE_WRITEABLE (1 << 2) #define RS400_PTE_READABLE (1 << 3) -void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags) +uint64_t rs400_gart_get_page_entry(uint64_t addr, uint32_t flags) { uint32_t entry; - u32 *gtt = rdev->gart.ptr; entry = (lower_32_bits(addr) & PAGE_MASK) | ((upper_32_bits(addr) & 0xff) << 4); @@ -226,8 +224,14 @@ void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, entry |= RS400_PTE_WRITEABLE; if (!(flags & RADEON_GART_PAGE_SNOOP)) entry |= RS400_PTE_UNSNOOPED; - entry = cpu_to_le32(entry); - gtt[i] = entry; + return entry; +} + +void rs400_gart_set_page(struct radeon_device *rdev, unsigned i, + uint64_t entry) +{ + u32 *gtt = rdev->gart.ptr; + gtt[i] = cpu_to_le32(lower_32_bits(entry)); } int rs400_mc_wait_for_idle(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 9acb1c3c005b..74bce91aecc1 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -625,11 +625,8 @@ static void rs600_gart_fini(struct radeon_device *rdev) radeon_gart_table_vram_free(rdev); } -void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, - uint64_t addr, uint32_t flags) +uint64_t rs600_gart_get_page_entry(uint64_t addr, uint32_t flags) { - void __iomem *ptr = (void *)rdev->gart.ptr; - addr = addr & 0xFFFFFFFFFFFFF000ULL; addr |= R600_PTE_SYSTEM; if (flags & RADEON_GART_PAGE_VALID) @@ -640,7 +637,14 @@ void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, addr |= R600_PTE_WRITEABLE; if (flags & RADEON_GART_PAGE_SNOOP) addr |= R600_PTE_SNOOPED; - writeq(addr, ptr + (i * 8)); + return addr; +} + +void rs600_gart_set_page(struct radeon_device *rdev, unsigned i, + uint64_t entry) +{ + void __iomem *ptr = (void *)rdev->gart.ptr; + writeq(entry, ptr + (i * 8)); } int rs600_irq_set(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 60df444bd075..5d89b874a1a2 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -5057,6 +5057,16 @@ void si_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, radeon_ring_write(ring, 0); radeon_ring_write(ring, 1 << vm_id); + /* wait for the invalidate to complete */ + radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); + radeon_ring_write(ring, (WAIT_REG_MEM_FUNCTION(0) | /* always */ + WAIT_REG_MEM_ENGINE(0))); /* me */ + radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, 0); /* ref */ + radeon_ring_write(ring, 0); /* mask */ + radeon_ring_write(ring, 0x20); /* poll interval */ + /* sync PFP to ME, otherwise we might get invalid PFP reads */ radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); radeon_ring_write(ring, 0x0); diff --git a/drivers/gpu/drm/radeon/si_dma.c b/drivers/gpu/drm/radeon/si_dma.c index f5cc777e1c5f..83207929fc62 100644 --- a/drivers/gpu/drm/radeon/si_dma.c +++ b/drivers/gpu/drm/radeon/si_dma.c @@ -123,7 +123,6 @@ void si_dma_vm_write_pages(struct radeon_device *rdev, for (; ndw > 0; ndw -= 2, --count, pe += 8) { if (flags & R600_PTE_SYSTEM) { value = radeon_vm_map_gart(rdev, addr); - value &= 0xFFFFFFFFFFFFF000ULL; } else if (flags & R600_PTE_VALID) { value = addr; } else { @@ -206,6 +205,14 @@ void si_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2)); radeon_ring_write(ring, 1 << vm_id); + + /* wait for invalidate to complete */ + radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_POLL_REG_MEM, 0, 0, 0, 0)); + radeon_ring_write(ring, VM_INVALIDATE_REQUEST); + radeon_ring_write(ring, 0xff << 16); /* retry */ + radeon_ring_write(ring, 1 << vm_id); /* mask */ + radeon_ring_write(ring, 0); /* value */ + radeon_ring_write(ring, (0 << 28) | 0x20); /* func(always) | poll interval */ } /** diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 32e354b8b0ab..eff8a6444956 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -2908,6 +2908,22 @@ static int si_init_smc_spll_table(struct radeon_device *rdev) return ret; } +struct si_dpm_quirk { + u32 chip_vendor; + u32 chip_device; + u32 subsys_vendor; + u32 subsys_device; + u32 max_sclk; + u32 max_mclk; +}; + +/* cards with dpm stability problems */ +static struct si_dpm_quirk si_dpm_quirk_list[] = { + /* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */ + { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 }, + { 0, 0, 0, 0 }, +}; + static void si_apply_state_adjust_rules(struct radeon_device *rdev, struct radeon_ps *rps) { @@ -2918,7 +2934,22 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, u32 mclk, sclk; u16 vddc, vddci; u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc; + u32 max_sclk = 0, max_mclk = 0; int i; + struct si_dpm_quirk *p = si_dpm_quirk_list; + + /* Apply dpm quirks */ + while (p && p->chip_device != 0) { + if (rdev->pdev->vendor == p->chip_vendor && + rdev->pdev->device == p->chip_device && + rdev->pdev->subsystem_vendor == p->subsys_vendor && + rdev->pdev->subsystem_device == p->subsys_device) { + max_sclk = p->max_sclk; + max_mclk = p->max_mclk; + break; + } + ++p; + } if ((rdev->pm.dpm.new_active_crtc_count > 1) || ni_dpm_vblank_too_short(rdev)) @@ -2972,6 +3003,14 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, if (ps->performance_levels[i].mclk > max_mclk_vddc) ps->performance_levels[i].mclk = max_mclk_vddc; } + if (max_mclk) { + if (ps->performance_levels[i].mclk > max_mclk) + ps->performance_levels[i].mclk = max_mclk; + } + if (max_sclk) { + if (ps->performance_levels[i].sclk > max_sclk) + ps->performance_levels[i].sclk = max_sclk; + } } /* XXX validate the min clocks required for display */ diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index 4069be89e585..84999242c747 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -1632,6 +1632,23 @@ #define PACKET3_MPEG_INDEX 0x3A #define PACKET3_COPY_DW 0x3B #define PACKET3_WAIT_REG_MEM 0x3C +#define WAIT_REG_MEM_FUNCTION(x) ((x) << 0) + /* 0 - always + * 1 - < + * 2 - <= + * 3 - == + * 4 - != + * 5 - >= + * 6 - > + */ +#define WAIT_REG_MEM_MEM_SPACE(x) ((x) << 4) + /* 0 - reg + * 1 - mem + */ +#define WAIT_REG_MEM_ENGINE(x) ((x) << 8) + /* 0 - me + * 1 - pfp + */ #define PACKET3_MEM_WRITE 0x3D #define PACKET3_COPY_DATA 0x40 #define PACKET3_CP_DMA 0x41 @@ -1835,6 +1852,7 @@ #define DMA_PACKET_TRAP 0x7 #define DMA_PACKET_SRBM_WRITE 0x9 #define DMA_PACKET_CONSTANT_FILL 0xd +#define DMA_PACKET_POLL_REG_MEM 0xe #define DMA_PACKET_NOP 0xf #define VCE_STATUS 0x20004 diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 7b5d22110f25..6c6b655defcf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -406,11 +406,9 @@ int vmw_3d_resource_inc(struct vmw_private *dev_priv, if (unlikely(ret != 0)) --dev_priv->num_3d_resources; } else if (unhide_svga) { - mutex_lock(&dev_priv->hw_mutex); vmw_write(dev_priv, SVGA_REG_ENABLE, vmw_read(dev_priv, SVGA_REG_ENABLE) & ~SVGA_REG_ENABLE_HIDE); - mutex_unlock(&dev_priv->hw_mutex); } mutex_unlock(&dev_priv->release_mutex); @@ -433,13 +431,10 @@ void vmw_3d_resource_dec(struct vmw_private *dev_priv, mutex_lock(&dev_priv->release_mutex); if (unlikely(--dev_priv->num_3d_resources == 0)) vmw_release_device(dev_priv); - else if (hide_svga) { - mutex_lock(&dev_priv->hw_mutex); + else if (hide_svga) vmw_write(dev_priv, SVGA_REG_ENABLE, vmw_read(dev_priv, SVGA_REG_ENABLE) | SVGA_REG_ENABLE_HIDE); - mutex_unlock(&dev_priv->hw_mutex); - } n3d = (int32_t) dev_priv->num_3d_resources; mutex_unlock(&dev_priv->release_mutex); @@ -600,12 +595,14 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->dev = dev; dev_priv->vmw_chipset = chipset; dev_priv->last_read_seqno = (uint32_t) -100; - mutex_init(&dev_priv->hw_mutex); mutex_init(&dev_priv->cmdbuf_mutex); mutex_init(&dev_priv->release_mutex); mutex_init(&dev_priv->binding_mutex); rwlock_init(&dev_priv->resource_lock); ttm_lock_init(&dev_priv->reservation_sem); + spin_lock_init(&dev_priv->hw_lock); + spin_lock_init(&dev_priv->waiter_lock); + spin_lock_init(&dev_priv->cap_lock); for (i = vmw_res_context; i < vmw_res_max; ++i) { idr_init(&dev_priv->res_idr[i]); @@ -626,14 +623,11 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->enable_fb = enable_fbdev; - mutex_lock(&dev_priv->hw_mutex); - vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2); svga_id = vmw_read(dev_priv, SVGA_REG_ID); if (svga_id != SVGA_ID_2) { ret = -ENOSYS; DRM_ERROR("Unsupported SVGA ID 0x%x\n", svga_id); - mutex_unlock(&dev_priv->hw_mutex); goto out_err0; } @@ -683,10 +677,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->prim_bb_mem = dev_priv->vram_size; ret = vmw_dma_masks(dev_priv); - if (unlikely(ret != 0)) { - mutex_unlock(&dev_priv->hw_mutex); + if (unlikely(ret != 0)) goto out_err0; - } /* * Limit back buffer size to VRAM size. Remove this once @@ -695,8 +687,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) if (dev_priv->prim_bb_mem > dev_priv->vram_size) dev_priv->prim_bb_mem = dev_priv->vram_size; - mutex_unlock(&dev_priv->hw_mutex); - vmw_print_capabilities(dev_priv->capabilities); if (dev_priv->capabilities & SVGA_CAP_GMR2) { @@ -1160,9 +1150,7 @@ static int vmw_master_set(struct drm_device *dev, if (unlikely(ret != 0)) return ret; vmw_kms_save_vga(dev_priv); - mutex_lock(&dev_priv->hw_mutex); vmw_write(dev_priv, SVGA_REG_TRACES, 0); - mutex_unlock(&dev_priv->hw_mutex); } if (active) { @@ -1196,9 +1184,7 @@ out_no_active_lock: if (!dev_priv->enable_fb) { vmw_kms_restore_vga(dev_priv); vmw_3d_resource_dec(dev_priv, true); - mutex_lock(&dev_priv->hw_mutex); vmw_write(dev_priv, SVGA_REG_TRACES, 1); - mutex_unlock(&dev_priv->hw_mutex); } return ret; } @@ -1233,9 +1219,7 @@ static void vmw_master_drop(struct drm_device *dev, DRM_ERROR("Unable to clean VRAM on master drop.\n"); vmw_kms_restore_vga(dev_priv); vmw_3d_resource_dec(dev_priv, true); - mutex_lock(&dev_priv->hw_mutex); vmw_write(dev_priv, SVGA_REG_TRACES, 1); - mutex_unlock(&dev_priv->hw_mutex); } dev_priv->active_master = &dev_priv->fbdev_master; @@ -1367,10 +1351,8 @@ static void vmw_pm_complete(struct device *kdev) struct drm_device *dev = pci_get_drvdata(pdev); struct vmw_private *dev_priv = vmw_priv(dev); - mutex_lock(&dev_priv->hw_mutex); vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2); (void) vmw_read(dev_priv, SVGA_REG_ID); - mutex_unlock(&dev_priv->hw_mutex); /** * Reclaim 3d reference held by fbdev and potentially diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 4ee799b43d5d..d26a6daa9719 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -399,7 +399,8 @@ struct vmw_private { uint32_t memory_size; bool has_gmr; bool has_mob; - struct mutex hw_mutex; + spinlock_t hw_lock; + spinlock_t cap_lock; /* * VGA registers. @@ -449,8 +450,9 @@ struct vmw_private { atomic_t marker_seq; wait_queue_head_t fence_queue; wait_queue_head_t fifo_queue; - int fence_queue_waiters; /* Protected by hw_mutex */ - int goal_queue_waiters; /* Protected by hw_mutex */ + spinlock_t waiter_lock; + int fence_queue_waiters; /* Protected by waiter_lock */ + int goal_queue_waiters; /* Protected by waiter_lock */ atomic_t fifo_queue_waiters; uint32_t last_read_seqno; spinlock_t irq_lock; @@ -553,20 +555,35 @@ static inline struct vmw_master *vmw_master(struct drm_master *master) return (struct vmw_master *) master->driver_priv; } +/* + * The locking here is fine-grained, so that it is performed once + * for every read- and write operation. This is of course costly, but we + * don't perform much register access in the timing critical paths anyway. + * Instead we have the extra benefit of being sure that we don't forget + * the hw lock around register accesses. + */ static inline void vmw_write(struct vmw_private *dev_priv, unsigned int offset, uint32_t value) { + unsigned long irq_flags; + + spin_lock_irqsave(&dev_priv->hw_lock, irq_flags); outl(offset, dev_priv->io_start + VMWGFX_INDEX_PORT); outl(value, dev_priv->io_start + VMWGFX_VALUE_PORT); + spin_unlock_irqrestore(&dev_priv->hw_lock, irq_flags); } static inline uint32_t vmw_read(struct vmw_private *dev_priv, unsigned int offset) { - uint32_t val; + unsigned long irq_flags; + u32 val; + spin_lock_irqsave(&dev_priv->hw_lock, irq_flags); outl(offset, dev_priv->io_start + VMWGFX_INDEX_PORT); val = inl(dev_priv->io_start + VMWGFX_VALUE_PORT); + spin_unlock_irqrestore(&dev_priv->hw_lock, irq_flags); + return val; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index b7594cb758af..945f1e0dad92 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -35,7 +35,7 @@ struct vmw_fence_manager { struct vmw_private *dev_priv; spinlock_t lock; struct list_head fence_list; - struct work_struct work, ping_work; + struct work_struct work; u32 user_fence_size; u32 fence_size; u32 event_fence_action_size; @@ -134,14 +134,6 @@ static const char *vmw_fence_get_timeline_name(struct fence *f) return "svga"; } -static void vmw_fence_ping_func(struct work_struct *work) -{ - struct vmw_fence_manager *fman = - container_of(work, struct vmw_fence_manager, ping_work); - - vmw_fifo_ping_host(fman->dev_priv, SVGA_SYNC_GENERIC); -} - static bool vmw_fence_enable_signaling(struct fence *f) { struct vmw_fence_obj *fence = @@ -155,11 +147,7 @@ static bool vmw_fence_enable_signaling(struct fence *f) if (seqno - fence->base.seqno < VMW_FENCE_WRAP) return false; - if (mutex_trylock(&dev_priv->hw_mutex)) { - vmw_fifo_ping_host_locked(dev_priv, SVGA_SYNC_GENERIC); - mutex_unlock(&dev_priv->hw_mutex); - } else - schedule_work(&fman->ping_work); + vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); return true; } @@ -305,7 +293,6 @@ struct vmw_fence_manager *vmw_fence_manager_init(struct vmw_private *dev_priv) INIT_LIST_HEAD(&fman->fence_list); INIT_LIST_HEAD(&fman->cleanup_list); INIT_WORK(&fman->work, &vmw_fence_work_func); - INIT_WORK(&fman->ping_work, &vmw_fence_ping_func); fman->fifo_down = true; fman->user_fence_size = ttm_round_pot(sizeof(struct vmw_user_fence)); fman->fence_size = ttm_round_pot(sizeof(struct vmw_fence_obj)); @@ -323,7 +310,6 @@ void vmw_fence_manager_takedown(struct vmw_fence_manager *fman) bool lists_empty; (void) cancel_work_sync(&fman->work); - (void) cancel_work_sync(&fman->ping_work); spin_lock_irqsave(&fman->lock, irq_flags); lists_empty = list_empty(&fman->fence_list) && diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 09e10aefcd8e..39f2b03888e7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -44,10 +44,10 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) if (!dev_priv->has_mob) return false; - mutex_lock(&dev_priv->hw_mutex); + spin_lock(&dev_priv->cap_lock); vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_3D); result = vmw_read(dev_priv, SVGA_REG_DEV_CAP); - mutex_unlock(&dev_priv->hw_mutex); + spin_unlock(&dev_priv->cap_lock); return (result != 0); } @@ -120,7 +120,6 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) DRM_INFO("height %d\n", vmw_read(dev_priv, SVGA_REG_HEIGHT)); DRM_INFO("bpp %d\n", vmw_read(dev_priv, SVGA_REG_BITS_PER_PIXEL)); - mutex_lock(&dev_priv->hw_mutex); dev_priv->enable_state = vmw_read(dev_priv, SVGA_REG_ENABLE); dev_priv->config_done_state = vmw_read(dev_priv, SVGA_REG_CONFIG_DONE); dev_priv->traces_state = vmw_read(dev_priv, SVGA_REG_TRACES); @@ -143,7 +142,6 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) mb(); vmw_write(dev_priv, SVGA_REG_CONFIG_DONE, 1); - mutex_unlock(&dev_priv->hw_mutex); max = ioread32(fifo_mem + SVGA_FIFO_MAX); min = ioread32(fifo_mem + SVGA_FIFO_MIN); @@ -160,31 +158,28 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) return vmw_fifo_send_fence(dev_priv, &dummy); } -void vmw_fifo_ping_host_locked(struct vmw_private *dev_priv, uint32_t reason) +void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason) { __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + static DEFINE_SPINLOCK(ping_lock); + unsigned long irq_flags; + /* + * The ping_lock is needed because we don't have an atomic + * test-and-set of the SVGA_FIFO_BUSY register. + */ + spin_lock_irqsave(&ping_lock, irq_flags); if (unlikely(ioread32(fifo_mem + SVGA_FIFO_BUSY) == 0)) { iowrite32(1, fifo_mem + SVGA_FIFO_BUSY); vmw_write(dev_priv, SVGA_REG_SYNC, reason); } -} - -void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason) -{ - mutex_lock(&dev_priv->hw_mutex); - - vmw_fifo_ping_host_locked(dev_priv, reason); - - mutex_unlock(&dev_priv->hw_mutex); + spin_unlock_irqrestore(&ping_lock, irq_flags); } void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) { __le32 __iomem *fifo_mem = dev_priv->mmio_virt; - mutex_lock(&dev_priv->hw_mutex); - vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC); while (vmw_read(dev_priv, SVGA_REG_BUSY) != 0) ; @@ -198,7 +193,6 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) vmw_write(dev_priv, SVGA_REG_TRACES, dev_priv->traces_state); - mutex_unlock(&dev_priv->hw_mutex); vmw_marker_queue_takedown(&fifo->marker_queue); if (likely(fifo->static_buffer != NULL)) { @@ -271,7 +265,7 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv, return vmw_fifo_wait_noirq(dev_priv, bytes, interruptible, timeout); - mutex_lock(&dev_priv->hw_mutex); + spin_lock(&dev_priv->waiter_lock); if (atomic_add_return(1, &dev_priv->fifo_queue_waiters) > 0) { spin_lock_irqsave(&dev_priv->irq_lock, irq_flags); outl(SVGA_IRQFLAG_FIFO_PROGRESS, @@ -280,7 +274,7 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv, vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags); } - mutex_unlock(&dev_priv->hw_mutex); + spin_unlock(&dev_priv->waiter_lock); if (interruptible) ret = wait_event_interruptible_timeout @@ -296,14 +290,14 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv, else if (likely(ret > 0)) ret = 0; - mutex_lock(&dev_priv->hw_mutex); + spin_lock(&dev_priv->waiter_lock); if (atomic_dec_and_test(&dev_priv->fifo_queue_waiters)) { spin_lock_irqsave(&dev_priv->irq_lock, irq_flags); dev_priv->irq_mask &= ~SVGA_IRQFLAG_FIFO_PROGRESS; vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags); } - mutex_unlock(&dev_priv->hw_mutex); + spin_unlock(&dev_priv->waiter_lock); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 37881ecf5d7a..69c8ce23123c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -135,13 +135,13 @@ static int vmw_fill_compat_cap(struct vmw_private *dev_priv, void *bounce, (pair_offset + max_size * sizeof(SVGA3dCapPair)) / sizeof(u32); compat_cap->header.type = SVGA3DCAPS_RECORD_DEVCAPS; - mutex_lock(&dev_priv->hw_mutex); + spin_lock(&dev_priv->cap_lock); for (i = 0; i < max_size; ++i) { vmw_write(dev_priv, SVGA_REG_DEV_CAP, i); compat_cap->pairs[i][0] = i; compat_cap->pairs[i][1] = vmw_read(dev_priv, SVGA_REG_DEV_CAP); } - mutex_unlock(&dev_priv->hw_mutex); + spin_unlock(&dev_priv->cap_lock); return 0; } @@ -191,12 +191,12 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data, if (num > SVGA3D_DEVCAP_MAX) num = SVGA3D_DEVCAP_MAX; - mutex_lock(&dev_priv->hw_mutex); + spin_lock(&dev_priv->cap_lock); for (i = 0; i < num; ++i) { vmw_write(dev_priv, SVGA_REG_DEV_CAP, i); *bounce32++ = vmw_read(dev_priv, SVGA_REG_DEV_CAP); } - mutex_unlock(&dev_priv->hw_mutex); + spin_unlock(&dev_priv->cap_lock); } else if (gb_objects) { ret = vmw_fill_compat_cap(dev_priv, bounce, size); if (unlikely(ret != 0)) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index 0c423766c441..9fe9827ee499 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c @@ -62,13 +62,8 @@ irqreturn_t vmw_irq_handler(int irq, void *arg) static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t seqno) { - uint32_t busy; - mutex_lock(&dev_priv->hw_mutex); - busy = vmw_read(dev_priv, SVGA_REG_BUSY); - mutex_unlock(&dev_priv->hw_mutex); - - return (busy == 0); + return (vmw_read(dev_priv, SVGA_REG_BUSY) == 0); } void vmw_update_seqno(struct vmw_private *dev_priv, @@ -184,7 +179,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, void vmw_seqno_waiter_add(struct vmw_private *dev_priv) { - mutex_lock(&dev_priv->hw_mutex); + spin_lock(&dev_priv->waiter_lock); if (dev_priv->fence_queue_waiters++ == 0) { unsigned long irq_flags; @@ -195,12 +190,12 @@ void vmw_seqno_waiter_add(struct vmw_private *dev_priv) vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags); } - mutex_unlock(&dev_priv->hw_mutex); + spin_unlock(&dev_priv->waiter_lock); } void vmw_seqno_waiter_remove(struct vmw_private *dev_priv) { - mutex_lock(&dev_priv->hw_mutex); + spin_lock(&dev_priv->waiter_lock); if (--dev_priv->fence_queue_waiters == 0) { unsigned long irq_flags; @@ -209,13 +204,13 @@ void vmw_seqno_waiter_remove(struct vmw_private *dev_priv) vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags); } - mutex_unlock(&dev_priv->hw_mutex); + spin_unlock(&dev_priv->waiter_lock); } void vmw_goal_waiter_add(struct vmw_private *dev_priv) { - mutex_lock(&dev_priv->hw_mutex); + spin_lock(&dev_priv->waiter_lock); if (dev_priv->goal_queue_waiters++ == 0) { unsigned long irq_flags; @@ -226,12 +221,12 @@ void vmw_goal_waiter_add(struct vmw_private *dev_priv) vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags); } - mutex_unlock(&dev_priv->hw_mutex); + spin_unlock(&dev_priv->waiter_lock); } void vmw_goal_waiter_remove(struct vmw_private *dev_priv) { - mutex_lock(&dev_priv->hw_mutex); + spin_lock(&dev_priv->waiter_lock); if (--dev_priv->goal_queue_waiters == 0) { unsigned long irq_flags; @@ -240,7 +235,7 @@ void vmw_goal_waiter_remove(struct vmw_private *dev_priv) vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags); } - mutex_unlock(&dev_priv->hw_mutex); + spin_unlock(&dev_priv->waiter_lock); } int vmw_wait_seqno(struct vmw_private *dev_priv, @@ -315,9 +310,7 @@ void vmw_irq_uninstall(struct drm_device *dev) if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) return; - mutex_lock(&dev_priv->hw_mutex); vmw_write(dev_priv, SVGA_REG_IRQMASK, 0); - mutex_unlock(&dev_priv->hw_mutex); status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 3725b521d931..8725b79e7847 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1828,9 +1828,7 @@ vmw_du_connector_detect(struct drm_connector *connector, bool force) struct vmw_private *dev_priv = vmw_priv(dev); struct vmw_display_unit *du = vmw_connector_to_du(connector); - mutex_lock(&dev_priv->hw_mutex); num_displays = vmw_read(dev_priv, SVGA_REG_NUM_DISPLAYS); - mutex_unlock(&dev_priv->hw_mutex); return ((vmw_connector_to_du(connector)->unit < num_displays && du->pref_active) ? diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index dfdc26970022..152b006833cd 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -147,6 +147,16 @@ config HID_BELKIN ---help--- Support for Belkin Flip KVM and Wireless keyboard. +config HID_BETOP_FF + tristate "Betop Production Inc. force feedback support" + depends on USB_HID + select INPUT_FF_MEMLESS + ---help--- + Say Y here if you want to enable force feedback support for devices by + BETOP Production Ltd. + Currently the following devices are known to be supported: + - BETOP 2185 PC & BFM MODE + config HID_CHERRY tristate "Cherry Cymotion keyboard" if EXPERT depends on HID @@ -389,7 +399,7 @@ config HID_LOGITECH_HIDPP Say Y if you want support for Logitech devices relying on the HID++ specification. Such devices are the various Logitech Touchpads (T650, T651, TK820), some mice (Zone Touch mouse), or even keyboards (Solar - Keayboard). + Keyboard). config LOGITECH_FF bool "Logitech force feedback support" diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index debd15b44b59..6f19958dfc38 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -2,10 +2,7 @@ # Makefile for the HID driver # hid-y := hid-core.o hid-input.o - -ifdef CONFIG_DEBUG_FS - hid-objs += hid-debug.o -endif +hid-$(CONFIG_DEBUG_FS) += hid-debug.o obj-$(CONFIG_HID) += hid.o obj-$(CONFIG_UHID) += uhid.o @@ -15,23 +12,13 @@ obj-$(CONFIG_HID_GENERIC) += hid-generic.o hid-$(CONFIG_HIDRAW) += hidraw.o hid-logitech-y := hid-lg.o -ifdef CONFIG_LOGITECH_FF - hid-logitech-y += hid-lgff.o -endif -ifdef CONFIG_LOGIRUMBLEPAD2_FF - hid-logitech-y += hid-lg2ff.o -endif -ifdef CONFIG_LOGIG940_FF - hid-logitech-y += hid-lg3ff.o -endif -ifdef CONFIG_LOGIWHEELS_FF - hid-logitech-y += hid-lg4ff.o -endif +hid-logitech-$(CONFIG_LOGITECH_FF) += hid-lgff.o +hid-logitech-$(CONFIG_LOGIRUMBLEPAD2_FF) += hid-lg2ff.o +hid-logitech-$(CONFIG_LOGIG940_FF) += hid-lg3ff.o +hid-logitech-$(CONFIG_LOGIWHEELS_FF) += hid-lg4ff.o hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o -ifdef CONFIG_DEBUG_FS - hid-wiimote-y += hid-wiimote-debug.o -endif +hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_ACRUX) += hid-axff.o @@ -39,6 +26,7 @@ obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o obj-$(CONFIG_HID_AUREAL) += hid-aureal.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o +obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CP2112) += hid-cp2112.o @@ -76,24 +64,12 @@ obj-$(CONFIG_HID_PENMOUNT) += hid-penmount.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o hid-picolcd-y += hid-picolcd_core.o -ifdef CONFIG_HID_PICOLCD_FB -hid-picolcd-y += hid-picolcd_fb.o -endif -ifdef CONFIG_HID_PICOLCD_BACKLIGHT -hid-picolcd-y += hid-picolcd_backlight.o -endif -ifdef CONFIG_HID_PICOLCD_LCD -hid-picolcd-y += hid-picolcd_lcd.o -endif -ifdef CONFIG_HID_PICOLCD_LEDS -hid-picolcd-y += hid-picolcd_leds.o -endif -ifdef CONFIG_HID_PICOLCD_CIR -hid-picolcd-y += hid-picolcd_cir.o -endif -ifdef CONFIG_DEBUG_FS -hid-picolcd-y += hid-picolcd_debugfs.o -endif +hid-picolcd-$(CONFIG_HID_PICOLCD_FB) += hid-picolcd_fb.o +hid-picolcd-$(CONFIG_HID_PICOLCD_BACKLIGHT) += hid-picolcd_backlight.o +hid-picolcd-$(CONFIG_HID_PICOLCD_LCD) += hid-picolcd_lcd.o +hid-picolcd-$(CONFIG_HID_PICOLCD_LEDS) += hid-picolcd_leds.o +hid-picolcd-$(CONFIG_HID_PICOLCD_CIR) += hid-picolcd_cir.o +hid-picolcd-$(CONFIG_DEBUG_FS) += hid-picolcd_debugfs.o obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o obj-$(CONFIG_HID_PRIMAX) += hid-primax.o diff --git a/drivers/hid/hid-betopff.c b/drivers/hid/hid-betopff.c new file mode 100644 index 000000000000..69cfc8dc6af1 --- /dev/null +++ b/drivers/hid/hid-betopff.c @@ -0,0 +1,160 @@ +/* + * Force feedback support for Betop based devices + * + * The devices are distributed under various names and the same USB device ID + * can be used in both adapters and actual game controllers. + * + * 0x11c2:0x2208 "BTP2185 BFM mode Joystick" + * - tested with BTP2185 BFM Mode. + * + * 0x11C0:0x5506 "BTP2185 PC mode Joystick" + * - tested with BTP2185 PC Mode. + * + * 0x8380:0x1850 "BTP2185 V2 PC mode USB Gamepad" + * - tested with BTP2185 PC Mode with another version. + * + * 0x20bc:0x5500 "BTP2185 V2 BFM mode Joystick" + * - tested with BTP2171s. + * Copyright (c) 2014 Huang Bo + */ + +/* + * 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 "hid-ids.h" + +struct betopff_device { + struct hid_report *report; +}; + +static int hid_betopff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct betopff_device *betopff = data; + __u16 left, right; + + left = effect->u.rumble.strong_magnitude; + right = effect->u.rumble.weak_magnitude; + + betopff->report->field[2]->value[0] = left / 256; + betopff->report->field[3]->value[0] = right / 256; + + hid_hw_request(hid, betopff->report, HID_REQ_SET_REPORT); + + return 0; +} + +static int betopff_init(struct hid_device *hid) +{ + struct betopff_device *betopff; + struct hid_report *report; + struct hid_input *hidinput = + list_first_entry(&hid->inputs, struct hid_input, list); + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct input_dev *dev = hidinput->input; + int field_count = 0; + int error; + int i, j; + + if (list_empty(report_list)) { + hid_err(hid, "no output reports found\n"); + return -ENODEV; + } + + report = list_first_entry(report_list, struct hid_report, list); + /* + * Actually there are 4 fields for 4 Bytes as below: + * ----------------------------------------- + * Byte0 Byte1 Byte2 Byte3 + * 0x00 0x00 left_motor right_motor + * ----------------------------------------- + * Do init them with default value. + */ + for (i = 0; i < report->maxfield; i++) { + for (j = 0; j < report->field[i]->report_count; j++) { + report->field[i]->value[j] = 0x00; + field_count++; + } + } + + if (field_count < 4) { + hid_err(hid, "not enough fields in the report: %d\n", + field_count); + return -ENODEV; + } + + betopff = kzalloc(sizeof(*betopff), GFP_KERNEL); + if (!betopff) + return -ENOMEM; + + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, betopff, hid_betopff_play); + if (error) { + kfree(betopff); + return error; + } + + betopff->report = report; + hid_hw_request(hid, betopff->report, HID_REQ_SET_REPORT); + + hid_info(hid, "Force feedback for betop devices by huangbo \n"); + + return 0; +} + +static int betop_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + if (id->driver_data) + hdev->quirks |= HID_QUIRK_MULTI_INPUT; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + goto err; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); + if (ret) { + hid_err(hdev, "hw start failed\n"); + goto err; + } + + betopff_init(hdev); + + return 0; +err: + return ret; +} + +static const struct hid_device_id betop_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) }, + { } +}; +MODULE_DEVICE_TABLE(hid, betop_devices); + +static struct hid_driver betop_driver = { + .name = "betop", + .id_table = betop_devices, + .probe = betop_probe, +}; +module_hid_driver(betop_driver); + +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8b638792cb43..db4fb6e1cc5b 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -698,15 +698,25 @@ static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage) static void hid_scan_collection(struct hid_parser *parser, unsigned type) { struct hid_device *hid = parser->device; + int i; if (((parser->global.usage_page << 16) == HID_UP_SENSOR) && type == HID_COLLECTION_PHYSICAL) hid->group = HID_GROUP_SENSOR_HUB; if (hid->vendor == USB_VENDOR_ID_MICROSOFT && - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 && + (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 || + hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3_JP) && hid->group == HID_GROUP_MULTITOUCH) hid->group = HID_GROUP_GENERIC; + + if ((parser->global.usage_page << 16) == HID_UP_GENDESK) + for (i = 0; i < parser->local.usage_index; i++) + if (parser->local.usage[i] == HID_GD_POINTER) + parser->scan_flags |= HID_SCAN_FLAG_GD_POINTER; + + if ((parser->global.usage_page << 16) >= HID_UP_MSVENDOR) + parser->scan_flags |= HID_SCAN_FLAG_VENDOR_SPECIFIC; } static int hid_scan_main(struct hid_parser *parser, struct hid_item *item) @@ -792,11 +802,14 @@ static int hid_scan_report(struct hid_device *hid) hid->group = HID_GROUP_WACOM; break; case USB_VENDOR_ID_SYNAPTICS: - if ((hid->group == HID_GROUP_GENERIC) && - (hid->bus != BUS_USB || hid->type == HID_TYPE_USBMOUSE)) - /* hid-rmi should only bind to the mouse interface of - * composite USB devices */ - hid->group = HID_GROUP_RMI; + if (hid->group == HID_GROUP_GENERIC) + if ((parser->scan_flags & HID_SCAN_FLAG_VENDOR_SPECIFIC) + && (parser->scan_flags & HID_SCAN_FLAG_GD_POINTER)) + /* + * hid-rmi should take care of them, + * not hid-generic + */ + hid->group = HID_GROUP_RMI; break; } @@ -1757,6 +1770,10 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) }, { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, @@ -1861,6 +1878,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, @@ -1971,6 +1989,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14) }, { } }; @@ -2328,6 +2347,7 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICK16F1454) }, { HID_USB_DEVICE(USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY) }, { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100) }, { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20) }, diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index 31fad641b744..6039f071fab1 100644 --- a/drivers/hid/hid-hyperv.c +++ b/drivers/hid/hid-hyperv.c @@ -381,7 +381,7 @@ static void mousevsc_on_channel_callback(void *context) static int mousevsc_connect_to_vsp(struct hv_device *device) { int ret = 0; - int t; + unsigned long t; struct mousevsc_dev *input_dev = hv_get_drvdata(device); struct mousevsc_prt_msg *request; struct mousevsc_prt_msg *response; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 9243359c1821..46edb4d3ed28 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -189,6 +189,11 @@ #define USB_VENDOR_ID_BERKSHIRE 0x0c98 #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 +#define USB_VENDOR_ID_BETOP_2185BFM 0x11c2 +#define USB_VENDOR_ID_BETOP_2185PC 0x11c0 +#define USB_VENDOR_ID_BETOP_2185V2PC 0x8380 +#define USB_VENDOR_ID_BETOP_2185V2BFM 0x20bc + #define USB_VENDOR_ID_BTC 0x046e #define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578 #define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577 @@ -638,6 +643,7 @@ #define USB_DEVICE_ID_PICKIT2 0x0033 #define USB_DEVICE_ID_PICOLCD 0xc002 #define USB_DEVICE_ID_PICOLCD_BOOTLOADER 0xf002 +#define USB_DEVICE_ID_PICK16F1454 0x0042 #define USB_VENDOR_ID_MICROSOFT 0x045e #define USB_DEVICE_ID_SIDEWINDER_GV 0x003b @@ -654,6 +660,7 @@ #define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 #define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 #define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07dc +#define USB_DEVICE_ID_MS_TYPE_COVER_3_JP 0x07dd #define USB_VENDOR_ID_MOJO 0x8282 #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 @@ -768,6 +775,9 @@ #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008 +#define USB_VENDOR_ID_RAZER 0x1532 +#define USB_DEVICE_ID_RAZER_BLADE_14 0x011D + #define USB_VENDOR_ID_REALTEK 0x0bda #define USB_DEVICE_ID_REALTEK_READER 0x0152 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 9505605b6e22..052869d0ab78 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -306,10 +306,13 @@ static enum power_supply_property hidinput_battery_props[] = { static const struct hid_device_id hid_battery_quirks[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, - USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), - HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, + USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), + HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, - USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), + USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), + HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO), @@ -1104,6 +1107,23 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; } + /* + * Ignore reports for absolute data if the data didn't change. This is + * not only an optimization but also fixes 'dead' key reports. Some + * RollOver implementations for localized keys (like BACKSLASH/PIPE; HID + * 0x31 and 0x32) report multiple keys, even though a localized keyboard + * can only have one of them physically available. The 'dead' keys + * report constant 0. As all map to the same keycode, they'd confuse + * the input layer. If we filter the 'dead' keys on the HID level, we + * skip the keycode translation and only forward real events. + */ + if (!(field->flags & (HID_MAIN_ITEM_RELATIVE | + HID_MAIN_ITEM_BUFFERED_BYTE)) && + (field->flags & HID_MAIN_ITEM_VARIABLE) && + usage->usage_index < field->maxusage && + value == field->value[usage->usage_index]) + return; + /* report the usage code as scancode if the key status has changed */ if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value) input_event(input, EV_MSC, MSC_SCAN, usage->hid); diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 4c55f4d95798..c4c3f0952521 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -38,6 +38,7 @@ struct lenovo_drvdata_tpkbd { struct lenovo_drvdata_cptkbd { bool fn_lock; + int sensitivity; }; #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) @@ -91,6 +92,38 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev, case 0x00fa: /* Fn-Esc: Fn-lock toggle */ map_key_clear(KEY_FN_ESC); return 1; + case 0x00fb: /* Middle mouse button (in native mode) */ + map_key_clear(BTN_MIDDLE); + return 1; + } + } + + /* Compatibility middle/wheel mappings should be ignored */ + if (usage->hid == HID_GD_WHEEL) + return -1; + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON && + (usage->hid & HID_USAGE) == 0x003) + return -1; + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER && + (usage->hid & HID_USAGE) == 0x238) + return -1; + + /* Map wheel emulation reports: 0xffa1 = USB, 0xff10 = BT */ + if ((usage->hid & HID_USAGE_PAGE) == 0xff100000 || + (usage->hid & HID_USAGE_PAGE) == 0xffa10000) { + field->flags |= HID_MAIN_ITEM_RELATIVE | HID_MAIN_ITEM_VARIABLE; + field->logical_minimum = -127; + field->logical_maximum = 127; + + switch (usage->hid & HID_USAGE) { + case 0x0000: + hid_map_usage(hi, usage, bit, max, EV_REL, 0x06); + return 1; + case 0x0001: + hid_map_usage(hi, usage, bit, max, EV_REL, 0x08); + return 1; + default: + return -1; } } @@ -145,6 +178,7 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev) struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock); + ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity); if (ret) hid_err(hdev, "Fn-lock setting failed: %d\n", ret); } @@ -179,13 +213,50 @@ static ssize_t attr_fn_lock_store_cptkbd(struct device *dev, return count; } +static ssize_t attr_sensitivity_show_cptkbd(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); + + return snprintf(buf, PAGE_SIZE, "%u\n", + cptkbd_data->sensitivity); +} + +static ssize_t attr_sensitivity_store_cptkbd(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); + int value; + + if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) + return -EINVAL; + + cptkbd_data->sensitivity = value; + lenovo_features_set_cptkbd(hdev); + + return count; +} + + static struct device_attribute dev_attr_fn_lock_cptkbd = __ATTR(fn_lock, S_IWUSR | S_IRUGO, attr_fn_lock_show_cptkbd, attr_fn_lock_store_cptkbd); +static struct device_attribute dev_attr_sensitivity_cptkbd = + __ATTR(sensitivity, S_IWUSR | S_IRUGO, + attr_sensitivity_show_cptkbd, + attr_sensitivity_store_cptkbd); + + static struct attribute *lenovo_attributes_cptkbd[] = { &dev_attr_fn_lock_cptkbd.attr, + &dev_attr_sensitivity_cptkbd.attr, NULL }; @@ -594,8 +665,14 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev) if (ret) hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret); - /* Turn Fn-Lock on by default */ + /* Switch middle button to native mode */ + ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01); + if (ret) + hid_warn(hdev, "Failed to switch middle button: %d\n", ret); + + /* Set keyboard settings to known state */ cptkbd_data->fn_lock = true; + cptkbd_data->sensitivity = 0x05; lenovo_features_set_cptkbd(hdev); ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd); diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 7835717bc020..db0dd9b17e53 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -49,10 +49,6 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range); static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range); -static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf); -static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); - -static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IROTH, lg4ff_range_show, lg4ff_range_store); struct lg4ff_device_entry { __u32 product_id; @@ -416,7 +412,8 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n } /* Read current range and display it in terminal */ -static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t range_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct hid_device *hid = to_hid_device(dev); struct lg4ff_device_entry *entry; @@ -441,7 +438,8 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att /* Set range to user specified value, call appropriate function * according to the type of the wheel */ -static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t range_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct hid_device *hid = to_hid_device(dev); struct lg4ff_device_entry *entry; @@ -472,6 +470,7 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at return count; } +static DEVICE_ATTR_RW(range); #ifdef CONFIG_LEDS_CLASS static void lg4ff_set_leds(struct hid_device *hid, __u8 leds) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index a93cefe0e522..e77658cd037c 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -89,6 +89,7 @@ struct hidpp_device { struct hid_device *hid_dev; struct mutex send_mutex; void *send_receive_buf; + char *name; /* will never be NULL and should not be freed */ wait_queue_head_t wait; bool answer_available; u8 protocol_major; @@ -105,6 +106,7 @@ struct hidpp_device { }; +/* HID++ 1.0 error codes */ #define HIDPP_ERROR 0x8f #define HIDPP_ERROR_SUCCESS 0x00 #define HIDPP_ERROR_INVALID_SUBID 0x01 @@ -119,6 +121,8 @@ struct hidpp_device { #define HIDPP_ERROR_REQUEST_UNAVAILABLE 0x0a #define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b #define HIDPP_ERROR_WRONG_PIN_CODE 0x0c +/* HID++ 2.0 error codes */ +#define HIDPP20_ERROR 0xff static void hidpp_connect_event(struct hidpp_device *hidpp_dev); @@ -192,9 +196,16 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp, } if (response->report_id == REPORT_ID_HIDPP_SHORT && - response->fap.feature_index == HIDPP_ERROR) { + response->rap.sub_id == HIDPP_ERROR) { + ret = response->rap.params[1]; + dbg_hid("%s:got hidpp error %02X\n", __func__, ret); + goto exit; + } + + if (response->report_id == REPORT_ID_HIDPP_LONG && + response->fap.feature_index == HIDPP20_ERROR) { ret = response->fap.params[1]; - dbg_hid("__hidpp_send_report got hidpp error %02X\n", ret); + dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); goto exit; } @@ -271,7 +282,8 @@ static inline bool hidpp_match_answer(struct hidpp_report *question, static inline bool hidpp_match_error(struct hidpp_report *question, struct hidpp_report *answer) { - return (answer->fap.feature_index == HIDPP_ERROR) && + return ((answer->rap.sub_id == HIDPP_ERROR) || + (answer->fap.feature_index == HIDPP20_ERROR)) && (answer->fap.funcindex_clientid == question->fap.feature_index) && (answer->fap.params[0] == question->fap.funcindex_clientid); } @@ -903,24 +915,24 @@ static int wtp_allocate(struct hid_device *hdev, const struct hid_device_id *id) return 0; }; -static void wtp_connect(struct hid_device *hdev, bool connected) +static int wtp_connect(struct hid_device *hdev, bool connected) { struct hidpp_device *hidpp = hid_get_drvdata(hdev); struct wtp_data *wd = hidpp->private_data; int ret; if (!connected) - return; + return 0; if (!wd->x_size) { ret = wtp_get_config(hidpp); if (ret) { hid_err(hdev, "Can not get wtp config: %d\n", ret); - return; + return ret; } } - hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index, + return hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index, true, true); } @@ -965,7 +977,7 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, /* * If the mutex is locked then we have a pending answer from a - * previoulsly sent command + * previously sent command. */ if (unlikely(mutex_is_locked(&hidpp->send_mutex))) { /* @@ -996,9 +1008,6 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, return 1; } - if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) - return wtp_raw_event(hidpp->hid_dev, data, size); - return 0; } @@ -1006,7 +1015,9 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { struct hidpp_device *hidpp = hid_get_drvdata(hdev); + int ret = 0; + /* Generic HID++ processing. */ switch (data[0]) { case REPORT_ID_HIDPP_LONG: if (size != HIDPP_REPORT_LONG_LENGTH) { @@ -1014,16 +1025,23 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, size); return 1; } - return hidpp_raw_hidpp_event(hidpp, data, size); + ret = hidpp_raw_hidpp_event(hidpp, data, size); + break; case REPORT_ID_HIDPP_SHORT: if (size != HIDPP_REPORT_SHORT_LENGTH) { hid_err(hdev, "received hid++ report of bad size (%d)", size); return 1; } - return hidpp_raw_hidpp_event(hidpp, data, size); + ret = hidpp_raw_hidpp_event(hidpp, data, size); + break; } + /* If no report is available for further processing, skip calling + * raw_event of subclasses. */ + if (ret != 0) + return ret; + if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) return wtp_raw_event(hdev, data, size); @@ -1070,6 +1088,7 @@ static void hidpp_input_close(struct input_dev *dev) static struct input_dev *hidpp_allocate_input(struct hid_device *hdev) { struct input_dev *input_dev = devm_input_allocate_device(&hdev->dev); + struct hidpp_device *hidpp = hid_get_drvdata(hdev); if (!input_dev) return NULL; @@ -1078,7 +1097,7 @@ static struct input_dev *hidpp_allocate_input(struct hid_device *hdev) input_dev->open = hidpp_input_open; input_dev->close = hidpp_input_close; - input_dev->name = hdev->name; + input_dev->name = hidpp->name; input_dev->phys = hdev->phys; input_dev->uniq = hdev->uniq; input_dev->id.bustype = hdev->bus; @@ -1098,8 +1117,11 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) struct input_dev *input; char *name, *devm_name; - if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) - wtp_connect(hdev, connected); + if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) { + ret = wtp_connect(hdev, connected); + if (ret) + return; + } if (!connected || hidpp->delayed_input) return; @@ -1117,22 +1139,28 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) hid_info(hdev, "HID++ %u.%u device connected.\n", hidpp->protocol_major, hidpp->protocol_minor); + if (!hidpp->name || hidpp->name == hdev->name) { + name = hidpp_get_device_name(hidpp); + if (!name) { + hid_err(hdev, + "unable to retrieve the name of the device"); + return; + } + + devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", name); + kfree(name); + if (!devm_name) + return; + + hidpp->name = devm_name; + } + input = hidpp_allocate_input(hdev); if (!input) { hid_err(hdev, "cannot allocate new input device: %d\n", ret); return; } - name = hidpp_get_device_name(hidpp); - if (!name) { - hid_err(hdev, "unable to retrieve the name of the device"); - } else { - devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", name); - if (devm_name) - input->name = devm_name; - kfree(name); - } - hidpp_populate_input(hidpp, input, false); ret = input_register_device(input); @@ -1155,6 +1183,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) return -ENOMEM; hidpp->hid_dev = hdev; + hidpp->name = hdev->name; hid_set_drvdata(hdev, hidpp); hidpp->quirks = id->driver_data; diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index cacda43f6a6f..fbaea6eb882e 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -276,6 +276,8 @@ static const struct hid_device_id ms_devices[] = { .driver_data = MS_DUPLICATE_USAGES }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), .driver_data = MS_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP), + .driver_data = MS_HIDINPUT }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT), .driver_data = MS_PRESENTER }, diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index b51200fe2f33..49d4fe4f5987 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -33,6 +33,10 @@ #define RMI_READ_DATA_PENDING BIT(1) #define RMI_STARTED BIT(2) +/* device flags */ +#define RMI_DEVICE BIT(0) +#define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1) + enum rmi_mode_type { RMI_MODE_OFF = 0, RMI_MODE_ATTN_REPORTS = 1, @@ -118,6 +122,8 @@ struct rmi_data { struct work_struct reset_work; struct hid_device *hdev; + + unsigned long device_flags; }; #define RMI_PAGE(addr) (((addr) >> 8) & 0xff) @@ -452,9 +458,32 @@ static int rmi_raw_event(struct hid_device *hdev, return rmi_read_data_event(hdev, data, size); case RMI_ATTN_REPORT_ID: return rmi_input_event(hdev, data, size); - case RMI_MOUSE_REPORT_ID: + default: + return 1; + } + + return 0; +} + +static int rmi_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + + if ((data->device_flags & RMI_DEVICE) && + (field->application == HID_GD_POINTER || + field->application == HID_GD_MOUSE)) { + if (data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) { + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) + return 0; + + if ((usage->hid == HID_GD_X || usage->hid == HID_GD_Y) + && !value) + return 1; + } + rmi_schedule_reset(hdev); - break; + return 1; } return 0; @@ -856,6 +885,9 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) if (ret) return; + if (!(data->device_flags & RMI_DEVICE)) + return; + /* Allow incoming hid reports */ hid_device_io_start(hdev); @@ -914,8 +946,38 @@ static int rmi_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - /* we want to make HID ignore the advertised HID collection */ - return -1; + struct rmi_data *data = hid_get_drvdata(hdev); + + /* + * we want to make HID ignore the advertised HID collection + * for RMI deivces + */ + if (data->device_flags & RMI_DEVICE) { + if ((data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) && + ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)) + return 0; + + return -1; + } + + return 0; +} + +static int rmi_check_valid_report_id(struct hid_device *hdev, unsigned type, + unsigned id, struct hid_report **report) +{ + int i; + + *report = hdev->report_enum[type].report_id_hash[id]; + if (*report) { + for (i = 0; i < (*report)->maxfield; i++) { + unsigned app = (*report)->field[i]->application; + if ((app & HID_USAGE_PAGE) >= HID_UP_MSVENDOR) + return 1; + } + } + + return 0; } static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) @@ -925,6 +987,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) size_t alloc_size; struct hid_report *input_report; struct hid_report *output_report; + struct hid_report *feature_report; data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL); if (!data) @@ -943,27 +1006,37 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } - input_report = hdev->report_enum[HID_INPUT_REPORT] - .report_id_hash[RMI_ATTN_REPORT_ID]; - if (!input_report) { - hid_err(hdev, "device does not have expected input report\n"); - ret = -ENODEV; - return ret; + if (id->driver_data) + data->device_flags = id->driver_data; + + /* + * Check for the RMI specific report ids. If they are misisng + * simply return and let the events be processed by hid-input + */ + if (!rmi_check_valid_report_id(hdev, HID_FEATURE_REPORT, + RMI_SET_RMI_MODE_REPORT_ID, &feature_report)) { + hid_dbg(hdev, "device does not have set mode feature report\n"); + goto start; } - data->input_report_size = (input_report->size >> 3) + 1 /* report id */; - - output_report = hdev->report_enum[HID_OUTPUT_REPORT] - .report_id_hash[RMI_WRITE_REPORT_ID]; - if (!output_report) { - hid_err(hdev, "device does not have expected output report\n"); - ret = -ENODEV; - return ret; + if (!rmi_check_valid_report_id(hdev, HID_INPUT_REPORT, + RMI_ATTN_REPORT_ID, &input_report)) { + hid_dbg(hdev, "device does not have attention input report\n"); + goto start; } - data->output_report_size = (output_report->size >> 3) - + 1 /* report id */; + data->input_report_size = hid_report_len(input_report); + if (!rmi_check_valid_report_id(hdev, HID_OUTPUT_REPORT, + RMI_WRITE_REPORT_ID, &output_report)) { + hid_dbg(hdev, + "device does not have rmi write output report\n"); + goto start; + } + + data->output_report_size = hid_report_len(output_report); + + data->device_flags |= RMI_DEVICE; alloc_size = data->output_report_size + data->input_report_size; data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL); @@ -978,13 +1051,15 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) mutex_init(&data->page_mutex); +start: ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { hid_err(hdev, "hw start failed\n"); return ret; } - if (!test_bit(RMI_STARTED, &data->flags)) + if ((data->device_flags & RMI_DEVICE) && + !test_bit(RMI_STARTED, &data->flags)) /* * The device maybe in the bootloader if rmi_input_configured * failed to find F11 in the PDT. Print an error, but don't @@ -1007,6 +1082,8 @@ static void rmi_remove(struct hid_device *hdev) } static const struct hid_device_id rmi_id[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14), + .driver_data = RMI_DEVICE_HAS_PHYS_BUTTONS }, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) }, { } }; @@ -1017,6 +1094,7 @@ static struct hid_driver rmi_driver = { .id_table = rmi_id, .probe = rmi_probe, .remove = rmi_remove, + .event = rmi_event, .raw_event = rmi_raw_event, .input_mapping = rmi_input_mapping, .input_configured = rmi_input_configured, diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile index db3cf31c6fa1..890f2914a8ff 100644 --- a/drivers/hid/usbhid/Makefile +++ b/drivers/hid/usbhid/Makefile @@ -2,17 +2,9 @@ # Makefile for the USB input drivers # -# Multipart objects. usbhid-y := hid-core.o hid-quirks.o - -# Optional parts of multipart objects. - -ifeq ($(CONFIG_USB_HIDDEV),y) - usbhid-y += hiddev.o -endif -ifeq ($(CONFIG_HID_PID),y) - usbhid-y += hid-pidff.o -endif +usbhid-$(CONFIG_USB_HIDDEV) += hiddev.o +usbhid-$(CONFIG_HID_PID) += hid-pidff.o obj-$(CONFIG_USB_HID) += usbhid.o obj-$(CONFIG_USB_KBD) += usbkbd.o diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 10b616702780..0b531c6a76a5 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -1252,6 +1252,8 @@ int hid_pidff_init(struct hid_device *hid) pidff->hid = hid; + hid_device_io_start(hid); + pidff_find_reports(hid, HID_OUTPUT_REPORT, pidff); pidff_find_reports(hid, HID_FEATURE_REPORT, pidff); @@ -1315,9 +1317,13 @@ int hid_pidff_init(struct hid_device *hid) hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula \n"); + hid_device_io_stop(hid); + return 0; fail: + hid_device_io_stop(hid); + kfree(pidff); return error; } diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index b27b3d33ebab..9be99a67bfe2 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -80,6 +80,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 654202941d30..f0568a7e6de9 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -173,10 +173,8 @@ static void wacom_usage_mapping(struct hid_device *hdev, { struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_features *features = &wacom->wacom_wac.features; - bool finger = (field->logical == HID_DG_FINGER) || - (field->physical == HID_DG_FINGER); - bool pen = (field->logical == HID_DG_STYLUS) || - (field->physical == HID_DG_STYLUS); + bool finger = WACOM_FINGER_FIELD(field); + bool pen = WACOM_PEN_FIELD(field); /* * Requiring Stylus Usage will ignore boot mouse @@ -405,6 +403,9 @@ static int wacom_query_tablet_data(struct hid_device *hdev, else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) { return wacom_set_device_mode(hdev, 18, 3, 2); } + else if (features->type == WACOM_27QHDT) { + return wacom_set_device_mode(hdev, 131, 3, 2); + } } else if (features->device_type == BTN_TOOL_PEN) { if (features->type <= BAMBOO_PT && features->type != WIRELESS) { return wacom_set_device_mode(hdev, 2, 2, 2); diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index ac7447c7b82e..1a6507999a65 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -15,7 +15,6 @@ #include "wacom_wac.h" #include "wacom.h" #include -#include /* resolution for penabled devices */ #define WACOM_PL_RES 20 @@ -444,9 +443,6 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) /* Enter report */ if ((data[1] & 0xfc) == 0xc0) { - if (features->quirks & WACOM_QUIRK_MULTI_INPUT) - wacom->shared->stylus_in_proximity = true; - /* serial number of the tool */ wacom->serial[idx] = ((data[3] & 0x0f) << 28) + (data[4] << 20) + (data[5] << 12) + @@ -535,24 +531,46 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) return 1; } + /* + * don't report events for invalid data + */ /* older I4 styli don't work with new Cintiqs */ - if (!((wacom->id[idx] >> 20) & 0x01) && - (features->type == WACOM_21UX2)) + if ((!((wacom->id[idx] >> 20) & 0x01) && + (features->type == WACOM_21UX2)) || + /* Only large Intuos support Lense Cursor */ + (wacom->tool[idx] == BTN_TOOL_LENS && + (features->type == INTUOS3 || + features->type == INTUOS3S || + features->type == INTUOS4 || + features->type == INTUOS4S || + features->type == INTUOS5 || + features->type == INTUOS5S || + features->type == INTUOSPM || + features->type == INTUOSPS)) || + /* Cintiq doesn't send data when RDY bit isn't set */ + (features->type == CINTIQ && !(data[1] & 0x40))) return 1; - /* Range Report */ - if ((data[1] & 0xfe) == 0x20) { + if (features->quirks & WACOM_QUIRK_MULTI_INPUT) + wacom->shared->stylus_in_proximity = true; + + /* in Range while exiting */ + if (((data[1] & 0xfe) == 0x20) && wacom->reporting_data) { input_report_key(input, BTN_TOUCH, 0); input_report_abs(input, ABS_PRESSURE, 0); input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max); - if (features->quirks & WACOM_QUIRK_MULTI_INPUT) - wacom->shared->stylus_in_proximity = true; + return 2; } /* Exit report */ if ((data[1] & 0xfe) == 0x80) { if (features->quirks & WACOM_QUIRK_MULTI_INPUT) wacom->shared->stylus_in_proximity = false; + wacom->reporting_data = false; + + /* don't report exit if we don't know the ID */ + if (!wacom->id[idx]) + return 1; /* * Reset all states otherwise we lose the initial states @@ -586,6 +604,11 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) wacom->id[idx] = 0; return 2; } + + /* don't report other events if we don't know the ID */ + if (!wacom->id[idx]) + return 1; + return 0; } @@ -633,6 +656,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) data[0] != WACOM_REPORT_INTUOSREAD && data[0] != WACOM_REPORT_INTUOSWRITE && data[0] != WACOM_REPORT_INTUOSPAD && + data[0] != WACOM_REPORT_CINTIQ && + data[0] != WACOM_REPORT_CINTIQPAD && data[0] != WACOM_REPORT_INTUOS5PAD) { dev_dbg(input->dev.parent, "%s: received unknown report #%d\n", __func__, data[0]); @@ -644,7 +669,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) idx = data[1] & 0x01; /* pad packets. Works as a second tool and is always in prox */ - if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) { + if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD || + data[0] == WACOM_REPORT_CINTIQPAD) { input = wacom->pad_input; if (features->type >= INTUOS4S && features->type <= INTUOS4L) { input_report_key(input, BTN_0, (data[2] & 0x01)); @@ -744,6 +770,14 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) } else { input_report_abs(input, ABS_MISC, 0); } + } else if (features->type == WACOM_27QHD) { + input_report_key(input, KEY_PROG1, data[2] & 0x01); + input_report_key(input, KEY_PROG2, data[2] & 0x02); + input_report_key(input, KEY_PROG3, data[2] & 0x04); + + input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4])); + input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6])); + input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8])); } else if (features->type == CINTIQ_HYBRID) { /* * Do not send hardware buttons under Android. They @@ -760,6 +794,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) input_report_key(input, BTN_7, (data[4] & 0x40)); /* Left */ input_report_key(input, BTN_8, (data[4] & 0x80)); /* Down */ input_report_key(input, BTN_0, (data[3] & 0x01)); /* Center */ + + if (data[4] | (data[3] & 0x01)) { + input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); + } else { + input_report_abs(input, ABS_MISC, 0); + } } else if (features->type >= INTUOS5S && features->type <= INTUOSPL) { int i; @@ -843,28 +883,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) if (result) return result - 1; - /* don't proceed if we don't know the ID */ - if (!wacom->id[idx]) - return 0; - - /* Only large Intuos support Lense Cursor */ - if (wacom->tool[idx] == BTN_TOOL_LENS && - (features->type == INTUOS3 || - features->type == INTUOS3S || - features->type == INTUOS4 || - features->type == INTUOS4S || - features->type == INTUOS5 || - features->type == INTUOS5S || - features->type == INTUOSPM || - features->type == INTUOSPS)) { - - return 0; - } - - /* Cintiq doesn't send data when RDY bit isn't set */ - if (features->type == CINTIQ && !(data[1] & 0x40)) - return 0; - if (features->type >= INTUOS3S) { input_report_abs(input, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1)); input_report_abs(input, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1)); @@ -951,6 +969,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) input_report_abs(input, ABS_MISC, wacom->id[idx]); /* report tool id */ input_report_key(input, wacom->tool[idx], 1); input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]); + wacom->reporting_data = true; return 1; } @@ -1019,8 +1038,20 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom) struct input_dev *input = wacom->input; unsigned char *data = wacom->data; int i; - int current_num_contacts = data[61]; + int current_num_contacts = 0; int contacts_to_send = 0; + int num_contacts_left = 4; /* maximum contacts per packet */ + int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET; + int y_offset = 2; + + if (wacom->features.type == WACOM_27QHDT) { + current_num_contacts = data[63]; + num_contacts_left = 10; + byte_per_packet = WACOM_BYTES_PER_QHDTHID_PACKET; + y_offset = 0; + } else { + current_num_contacts = data[61]; + } /* * First packet resets the counter since only the first @@ -1029,12 +1060,11 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom) if (current_num_contacts) wacom->num_contacts_left = current_num_contacts; - /* There are at most 4 contacts per packet */ - contacts_to_send = min(4, wacom->num_contacts_left); + contacts_to_send = min(num_contacts_left, wacom->num_contacts_left); for (i = 0; i < contacts_to_send; i++) { - int offset = (WACOM_BYTES_PER_24HDT_PACKET * i) + 1; - bool touch = data[offset] & 0x1 && !wacom->shared->stylus_in_proximity; + int offset = (byte_per_packet * i) + 1; + bool touch = (data[offset] & 0x1) && !wacom->shared->stylus_in_proximity; int slot = input_mt_get_slot_by_key(input, data[offset + 1]); if (slot < 0) @@ -1044,18 +1074,23 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom) if (touch) { int t_x = get_unaligned_le16(&data[offset + 2]); - int c_x = get_unaligned_le16(&data[offset + 4]); - int t_y = get_unaligned_le16(&data[offset + 6]); - int c_y = get_unaligned_le16(&data[offset + 8]); - int w = get_unaligned_le16(&data[offset + 10]); - int h = get_unaligned_le16(&data[offset + 12]); + int t_y = get_unaligned_le16(&data[offset + 4 + y_offset]); input_report_abs(input, ABS_MT_POSITION_X, t_x); input_report_abs(input, ABS_MT_POSITION_Y, t_y); - input_report_abs(input, ABS_MT_TOUCH_MAJOR, min(w,h)); - input_report_abs(input, ABS_MT_WIDTH_MAJOR, min(w, h) + int_dist(t_x, t_y, c_x, c_y)); - input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h)); - input_report_abs(input, ABS_MT_ORIENTATION, w > h); + + if (wacom->features.type != WACOM_27QHDT) { + int c_x = get_unaligned_le16(&data[offset + 4]); + int c_y = get_unaligned_le16(&data[offset + 8]); + int w = get_unaligned_le16(&data[offset + 10]); + int h = get_unaligned_le16(&data[offset + 12]); + + input_report_abs(input, ABS_MT_TOUCH_MAJOR, min(w,h)); + input_report_abs(input, ABS_MT_WIDTH_MAJOR, + min(w, h) + int_dist(t_x, t_y, c_x, c_y)); + input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h)); + input_report_abs(input, ABS_MT_ORIENTATION, w > h); + } } } input_mt_report_pointer_emulation(input, true); @@ -1064,6 +1099,7 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom) if (wacom->num_contacts_left <= 0) wacom->num_contacts_left = 0; + wacom->shared->touch_down = (wacom->num_contacts_left > 0); return 1; } @@ -1092,7 +1128,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom) for (i = 0; i < contacts_to_send; i++) { int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3; - bool touch = data[offset] & 0x1; + bool touch = (data[offset] & 0x1) && !wacom->shared->stylus_in_proximity; int id = get_unaligned_le16(&data[offset + 1]); int slot = input_mt_get_slot_by_key(input, id); @@ -1114,6 +1150,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom) if (wacom->num_contacts_left < 0) wacom->num_contacts_left = 0; + wacom->shared->touch_down = (wacom->num_contacts_left > 0); return 1; } @@ -1514,13 +1551,6 @@ static void wacom_wac_finger_report(struct hid_device *hdev, wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(hdev); } -#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ - ((f)->physical == HID_DG_STYLUS) || \ - ((f)->application == HID_DG_PEN)) -#define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \ - ((f)->physical == HID_DG_FINGER) || \ - ((f)->application == HID_DG_TOUCHSCREEN)) - void wacom_wac_usage_mapping(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage) { @@ -1891,6 +1921,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) case WACOM_21UX2: case WACOM_22HD: case WACOM_24HD: + case WACOM_27QHD: case DTK: case CINTIQ_HYBRID: sync = wacom_intuos_irq(wacom_wac); @@ -1901,6 +1932,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) break; case WACOM_24HDT: + case WACOM_27QHDT: sync = wacom_24hdt_irq(wacom_wac); break; @@ -2086,8 +2118,14 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, wacom_abs_set_axis(input_dev, wacom_wac); switch (features->type) { + case GRAPHIRE_BT: + __clear_bit(ABS_MISC, input_dev->absbit); + case WACOM_MO: case WACOM_G4: + input_set_abs_params(input_dev, ABS_DISTANCE, 0, + features->distance_max, + 0, 0); /* fall through */ case GRAPHIRE: @@ -2106,52 +2144,15 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, __set_bit(INPUT_PROP_POINTER, input_dev->propbit); break; - case GRAPHIRE_BT: - __clear_bit(ABS_MISC, input_dev->absbit); - input_set_abs_params(input_dev, ABS_DISTANCE, 0, - features->distance_max, - 0, 0); - - input_set_capability(input_dev, EV_REL, REL_WHEEL); - - __set_bit(BTN_LEFT, input_dev->keybit); - __set_bit(BTN_RIGHT, input_dev->keybit); - __set_bit(BTN_MIDDLE, input_dev->keybit); - - __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); - __set_bit(BTN_TOOL_PEN, input_dev->keybit); - __set_bit(BTN_TOOL_MOUSE, input_dev->keybit); - __set_bit(BTN_STYLUS, input_dev->keybit); - __set_bit(BTN_STYLUS2, input_dev->keybit); - - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - break; - + case WACOM_27QHD: case WACOM_24HD: - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - input_abs_set_res(input_dev, ABS_Z, 287); - input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0); - /* fall through */ - case DTK: - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - - wacom_setup_cintiq(wacom_wac); - break; - case WACOM_22HD: case WACOM_21UX2: case WACOM_BEE: case CINTIQ: - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - input_abs_set_res(input_dev, ABS_Z, 287); - - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - - wacom_setup_cintiq(wacom_wac); - break; - case WACOM_13HD: + case CINTIQ_HYBRID: input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); input_abs_set_res(input_dev, ABS_Z, 287); __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); @@ -2161,6 +2162,10 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, case INTUOS3: case INTUOS3L: case INTUOS3S: + case INTUOS4: + case INTUOS4WL: + case INTUOS4L: + case INTUOS4S: input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); input_abs_set_res(input_dev, ABS_Z, 287); /* fall through */ @@ -2199,17 +2204,6 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, } break; - case INTUOS4: - case INTUOS4WL: - case INTUOS4L: - case INTUOS4S: - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - input_abs_set_res(input_dev, ABS_Z, 287); - wacom_setup_intuos(wacom_wac); - - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - break; - case WACOM_24HDT: if (features->device_type == BTN_TOOL_FINGER) { input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0); @@ -2219,6 +2213,7 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, } /* fall through */ + case WACOM_27QHDT: case MTSCREEN: case MTTPC: case MTTPC_B: @@ -2305,14 +2300,6 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, 0, 0); } break; - - case CINTIQ_HYBRID: - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - input_abs_set_res(input_dev, ABS_Z, 287); - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - - wacom_setup_cintiq(wacom_wac); - break; } return 0; } @@ -2374,6 +2361,19 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0); break; + case WACOM_27QHD: + __set_bit(KEY_PROG1, input_dev->keybit); + __set_bit(KEY_PROG2, input_dev->keybit); + __set_bit(KEY_PROG3, input_dev->keybit); + input_set_abs_params(input_dev, ABS_X, -2048, 2048, 0, 0); + input_abs_set_res(input_dev, ABS_X, 1024); /* points/g */ + input_set_abs_params(input_dev, ABS_Y, -2048, 2048, 0, 0); + input_abs_set_res(input_dev, ABS_Y, 1024); + input_set_abs_params(input_dev, ABS_Z, -2048, 2048, 0, 0); + input_abs_set_res(input_dev, ABS_Z, 1024); + __set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit); + break; + case DTK: for (i = 0; i < 6; i++) __set_bit(BTN_0 + i, input_dev->keybit); @@ -2724,6 +2724,18 @@ static const struct wacom_features wacom_features_0xF6 = { "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */ .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10, .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; +static const struct wacom_features wacom_features_0x32A = + { "Wacom Cintiq 27QHD", 119740, 67520, 2047, + 63, WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; +static const struct wacom_features wacom_features_0x32B = + { "Wacom Cintiq 27QHD touch", 119740, 67520, 2047, 63, + WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, + .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32C }; +static const struct wacom_features wacom_features_0x32C = + { "Wacom Cintiq 27QHD touch", .type = WACOM_27QHDT, + .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32B, .touch_max = 10 }; static const struct wacom_features wacom_features_0x3F = { "Wacom Cintiq 21UX", 87200, 65600, 1023, 63, CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; @@ -3090,6 +3102,9 @@ const struct hid_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x315) }, { USB_DEVICE_WACOM(0x317) }, { USB_DEVICE_WACOM(0x323) }, + { USB_DEVICE_WACOM(0x32A) }, + { USB_DEVICE_WACOM(0x32B) }, + { USB_DEVICE_WACOM(0x32C) }, { USB_DEVICE_WACOM(0x32F) }, { USB_DEVICE_WACOM(0x4001) }, { USB_DEVICE_WACOM(0x4004) }, diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index bfad815cda8a..021ee1c1980a 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -10,9 +10,10 @@ #define WACOM_WAC_H #include +#include /* maximum packet length for USB devices */ -#define WACOM_PKGLEN_MAX 68 +#define WACOM_PKGLEN_MAX 192 #define WACOM_NAME_MAX 64 @@ -36,6 +37,7 @@ /* wacom data size per MT contact */ #define WACOM_BYTES_PER_MT_PACKET 11 #define WACOM_BYTES_PER_24HDT_PACKET 14 +#define WACOM_BYTES_PER_QHDTHID_PACKET 6 /* device IDs */ #define STYLUS_DEVICE_ID 0x02 @@ -57,6 +59,8 @@ #define WACOM_REPORT_TPCMT 13 #define WACOM_REPORT_TPCMT2 3 #define WACOM_REPORT_TPCHID 15 +#define WACOM_REPORT_CINTIQ 16 +#define WACOM_REPORT_CINTIQPAD 17 #define WACOM_REPORT_TPCST 16 #define WACOM_REPORT_DTUS 17 #define WACOM_REPORT_TPC1FGE 18 @@ -71,6 +75,14 @@ #define WACOM_QUIRK_MONITOR 0x0008 #define WACOM_QUIRK_BATTERY 0x0010 +#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ + ((f)->physical == HID_DG_STYLUS) || \ + ((f)->physical == HID_DG_PEN) || \ + ((f)->application == HID_DG_PEN)) +#define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \ + ((f)->physical == HID_DG_FINGER) || \ + ((f)->application == HID_DG_TOUCHSCREEN)) + enum { PENPARTNER = 0, GRAPHIRE, @@ -100,6 +112,7 @@ enum { WACOM_22HD, DTK, WACOM_24HD, + WACOM_27QHD, CINTIQ_HYBRID, CINTIQ, WACOM_BEE, @@ -108,6 +121,7 @@ enum { WIRELESS, BAMBOO_PT, WACOM_24HDT, + WACOM_27QHDT, TABLETPC, /* add new TPC below */ TABLETPCE, TABLETPC2FG, @@ -180,6 +194,7 @@ struct wacom_wac { int tool[2]; int id[2]; __u32 serial[2]; + bool reporting_data; struct wacom_features features; struct wacom_shared *shared; struct input_dev *input; diff --git a/drivers/hsi/clients/nokia-modem.c b/drivers/hsi/clients/nokia-modem.c index f0c21458962c..eb4dc63dbc93 100644 --- a/drivers/hsi/clients/nokia-modem.c +++ b/drivers/hsi/clients/nokia-modem.c @@ -162,6 +162,7 @@ static int nokia_modem_probe(struct device *dev) return -ENOMEM; } dev_set_drvdata(dev, modem); + modem->device = dev; irq = irq_of_parse_and_map(np, 0); if (!irq) { diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 4d6b26979fbd..bb3725b672cf 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -861,8 +861,8 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) break; case ACPI_RESOURCE_TYPE_ADDRESS64: - hyperv_mmio.start = res->data.address64.minimum; - hyperv_mmio.end = res->data.address64.maximum; + hyperv_mmio.start = res->data.address64.address.minimum; + hyperv_mmio.end = res->data.address64.address.maximum; break; } diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 6529c09c46f0..d931cbbed240 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -574,6 +574,16 @@ config SENSORS_IIO_HWMON for those channels specified in the map. This map can be provided either via platform data or the device tree bindings. +config SENSORS_I5500 + tristate "Intel 5500/5520/X58 temperature sensor" + depends on X86 && PCI + help + If you say yes here you get support for the temperature + sensor inside the Intel 5500, 5520 and X58 chipsets. + + This driver can also be built as a module. If so, the module + will be called i5500_temp. + config SENSORS_CORETEMP tristate "Intel Core/Core2/Atom temperature sensor" depends on X86 @@ -1379,6 +1389,7 @@ config SENSORS_ADS1015 config SENSORS_ADS7828 tristate "Texas Instruments ADS7828 and compatibles" depends on I2C + select REGMAP_I2C help If you say yes here you get support for Texas Instruments ADS7828 and ADS7830 8-channel A/D converters. ADS7828 resolution is 12-bit, while @@ -1420,8 +1431,8 @@ config SENSORS_INA2XX tristate "Texas Instruments INA219 and compatibles" depends on I2C help - If you say yes here you get support for INA219, INA220, INA226, and - INA230 power monitor chips. + If you say yes here you get support for INA219, INA220, INA226, + INA230, and INA231 power monitor chips. The INA2xx driver is configured for the default configuration of the part as described in the datasheet. diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 67280643bcf0..6c941472e707 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o obj-$(CONFIG_SENSORS_HTU21) += htu21.o obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o +obj-$(CONFIG_SENSORS_I5500) += i5500_temp.o obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o diff --git a/drivers/hwmon/abx500.c b/drivers/hwmon/abx500.c index 13875968c844..6cb89c0ebab6 100644 --- a/drivers/hwmon/abx500.c +++ b/drivers/hwmon/abx500.c @@ -221,7 +221,7 @@ static ssize_t show_min(struct device *dev, struct abx500_temp *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - return sprintf(buf, "%ld\n", data->min[attr->index]); + return sprintf(buf, "%lu\n", data->min[attr->index]); } static ssize_t show_max(struct device *dev, @@ -230,7 +230,7 @@ static ssize_t show_max(struct device *dev, struct abx500_temp *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - return sprintf(buf, "%ld\n", data->max[attr->index]); + return sprintf(buf, "%lu\n", data->max[attr->index]); } static ssize_t show_max_hyst(struct device *dev, @@ -239,7 +239,7 @@ static ssize_t show_max_hyst(struct device *dev, struct abx500_temp *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - return sprintf(buf, "%ld\n", data->max_hyst[attr->index]); + return sprintf(buf, "%lu\n", data->max_hyst[attr->index]); } static ssize_t show_min_alarm(struct device *dev, diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c index f4f9b219bf16..11955467fc0f 100644 --- a/drivers/hwmon/ad7314.c +++ b/drivers/hwmon/ad7314.c @@ -16,6 +16,7 @@ #include #include #include +#include /* * AD7314 temperature masks @@ -67,7 +68,7 @@ static ssize_t ad7314_show_temperature(struct device *dev, switch (spi_get_device_id(chip->spi_dev)->driver_data) { case ad7314: data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT; - data = (data << 6) >> 6; + data = sign_extend32(data, 9); return sprintf(buf, "%d\n", 250 * data); case adt7301: @@ -78,7 +79,7 @@ static ssize_t ad7314_show_temperature(struct device *dev, * register. 1lsb - 31.25 milli degrees centigrade */ data = ret & ADT7301_TEMP_MASK; - data = (data << 2) >> 2; + data = sign_extend32(data, 13); return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(data * 3125, 100)); diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c index 0625e50d7a6e..ad2b47e40345 100644 --- a/drivers/hwmon/adc128d818.c +++ b/drivers/hwmon/adc128d818.c @@ -27,6 +27,7 @@ #include #include #include +#include /* Addresses to scan * The chip also supports addresses 0x35..0x37. Don't scan those addresses @@ -189,7 +190,7 @@ static ssize_t adc128_show_temp(struct device *dev, if (IS_ERR(data)) return PTR_ERR(data); - temp = (data->temp[index] << 7) >> 7; /* sign extend */ + temp = sign_extend32(data->temp[index], 8); return sprintf(buf, "%d\n", temp * 500);/* 0.5 degrees C resolution */ } diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index a622d40eec17..bce4e9ff21bf 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -30,14 +30,12 @@ #include #include #include -#include #include -#include #include +#include #include /* The ADS7828 registers */ -#define ADS7828_NCH 8 /* 8 channels supported */ #define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */ #define ADS7828_CMD_PD1 0x04 /* Internal vref OFF && A/D ON */ #define ADS7828_CMD_PD3 0x0C /* Internal vref ON && A/D ON */ @@ -50,17 +48,9 @@ enum ads7828_chips { ads7828, ads7830 }; /* Client specific data */ struct ads7828_data { - struct i2c_client *client; - struct mutex update_lock; /* Mutex protecting updates */ - unsigned long last_updated; /* Last updated time (in jiffies) */ - u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH samples */ - bool valid; /* Validity flag */ - bool diff_input; /* Differential input */ - bool ext_vref; /* External voltage reference */ - unsigned int vref_mv; /* voltage reference value */ + struct regmap *regmap; u8 cmd_byte; /* Command byte without channel bits */ unsigned int lsb_resol; /* Resolution of the ADC sample LSB */ - s32 (*read_channel)(const struct i2c_client *client, u8 command); }; /* Command byte C2,C1,C0 - see datasheet */ @@ -69,42 +59,22 @@ static inline u8 ads7828_cmd_byte(u8 cmd, int ch) return cmd | (((ch >> 1) | (ch & 0x01) << 2) << 4); } -/* Update data for the device (all 8 channels) */ -static struct ads7828_data *ads7828_update_device(struct device *dev) -{ - struct ads7828_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - unsigned int ch; - dev_dbg(&client->dev, "Starting ads7828 update\n"); - - for (ch = 0; ch < ADS7828_NCH; ch++) { - u8 cmd = ads7828_cmd_byte(data->cmd_byte, ch); - data->adc_input[ch] = data->read_channel(client, cmd); - } - data->last_updated = jiffies; - data->valid = true; - } - - mutex_unlock(&data->update_lock); - - return data; -} - /* sysfs callback function */ static ssize_t ads7828_show_in(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ads7828_data *data = ads7828_update_device(dev); - unsigned int value = DIV_ROUND_CLOSEST(data->adc_input[attr->index] * - data->lsb_resol, 1000); + struct ads7828_data *data = dev_get_drvdata(dev); + u8 cmd = ads7828_cmd_byte(data->cmd_byte, attr->index); + unsigned int regval; + int err; - return sprintf(buf, "%d\n", value); + err = regmap_read(data->regmap, cmd, ®val); + if (err < 0) + return err; + + return sprintf(buf, "%d\n", + DIV_ROUND_CLOSEST(regval * data->lsb_resol, 1000)); } static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7828_show_in, NULL, 0); @@ -130,6 +100,16 @@ static struct attribute *ads7828_attrs[] = { ATTRIBUTE_GROUPS(ads7828); +static const struct regmap_config ads2828_regmap_config = { + .reg_bits = 8, + .val_bits = 16, +}; + +static const struct regmap_config ads2830_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + static int ads7828_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -137,42 +117,40 @@ static int ads7828_probe(struct i2c_client *client, struct ads7828_platform_data *pdata = dev_get_platdata(dev); struct ads7828_data *data; struct device *hwmon_dev; + unsigned int vref_mv = ADS7828_INT_VREF_MV; + bool diff_input = false; + bool ext_vref = false; data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL); if (!data) return -ENOMEM; if (pdata) { - data->diff_input = pdata->diff_input; - data->ext_vref = pdata->ext_vref; - if (data->ext_vref) - data->vref_mv = pdata->vref_mv; + diff_input = pdata->diff_input; + ext_vref = pdata->ext_vref; + if (ext_vref && pdata->vref_mv) + vref_mv = pdata->vref_mv; } - /* Bound Vref with min/max values if it was provided */ - if (data->vref_mv) - data->vref_mv = clamp_val(data->vref_mv, - ADS7828_EXT_VREF_MV_MIN, - ADS7828_EXT_VREF_MV_MAX); - else - data->vref_mv = ADS7828_INT_VREF_MV; + /* Bound Vref with min/max values */ + vref_mv = clamp_val(vref_mv, ADS7828_EXT_VREF_MV_MIN, + ADS7828_EXT_VREF_MV_MAX); /* ADS7828 uses 12-bit samples, while ADS7830 is 8-bit */ if (id->driver_data == ads7828) { - data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 4096); - data->read_channel = i2c_smbus_read_word_swapped; + data->lsb_resol = DIV_ROUND_CLOSEST(vref_mv * 1000, 4096); + data->regmap = devm_regmap_init_i2c(client, + &ads2828_regmap_config); } else { - data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 256); - data->read_channel = i2c_smbus_read_byte_data; + data->lsb_resol = DIV_ROUND_CLOSEST(vref_mv * 1000, 256); + data->regmap = devm_regmap_init_i2c(client, + &ads2830_regmap_config); } - data->cmd_byte = data->ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3; - if (!data->diff_input) + data->cmd_byte = ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3; + if (!diff_input) data->cmd_byte |= ADS7828_CMD_SD_SE; - data->client = client; - mutex_init(&data->update_lock); - hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, data, ads7828_groups); diff --git a/drivers/hwmon/i5500_temp.c b/drivers/hwmon/i5500_temp.c new file mode 100644 index 000000000000..3e3ccbf18b4e --- /dev/null +++ b/drivers/hwmon/i5500_temp.c @@ -0,0 +1,149 @@ +/* + * i5500_temp - Driver for Intel 5500/5520/X58 chipset thermal sensor + * + * Copyright (C) 2012, 2014 Jean Delvare + * + * 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 + +/* Register definitions from datasheet */ +#define REG_TSTHRCATA 0xE2 +#define REG_TSCTRL 0xE8 +#define REG_TSTHRRPEX 0xEB +#define REG_TSTHRLO 0xEC +#define REG_TSTHRHI 0xEE +#define REG_CTHINT 0xF0 +#define REG_TSFSC 0xF3 +#define REG_CTSTS 0xF4 +#define REG_TSTHRRQPI 0xF5 +#define REG_CTCTRL 0xF7 +#define REG_TSTIMER 0xF8 + +/* + * Sysfs stuff + */ + +/* Sensor resolution : 0.5 degree C */ +static ssize_t show_temp(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev->parent); + long temp; + u16 tsthrhi; + s8 tsfsc; + + pci_read_config_word(pdev, REG_TSTHRHI, &tsthrhi); + pci_read_config_byte(pdev, REG_TSFSC, &tsfsc); + temp = ((long)tsthrhi - tsfsc) * 500; + + return sprintf(buf, "%ld\n", temp); +} + +static ssize_t show_thresh(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev->parent); + int reg = to_sensor_dev_attr(devattr)->index; + long temp; + u16 tsthr; + + pci_read_config_word(pdev, reg, &tsthr); + temp = tsthr * 500; + + return sprintf(buf, "%ld\n", temp); +} + +static ssize_t show_alarm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev->parent); + int nr = to_sensor_dev_attr(devattr)->index; + u8 ctsts; + + pci_read_config_byte(pdev, REG_CTSTS, &ctsts); + return sprintf(buf, "%u\n", (unsigned int)ctsts & (1 << nr)); +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_thresh, NULL, 0xE2); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_thresh, NULL, 0xEC); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_thresh, NULL, 0xEE); +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1); + +static struct attribute *i5500_temp_attrs[] = { + &dev_attr_temp1_input.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + NULL +}; + +ATTRIBUTE_GROUPS(i5500_temp); + +static const struct pci_device_id i5500_temp_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3438) }, + { 0 }, +}; + +MODULE_DEVICE_TABLE(pci, i5500_temp_ids); + +static int i5500_temp_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int err; + struct device *hwmon_dev; + u32 tstimer; + s8 tsfsc; + + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Failed to enable device\n"); + return err; + } + + pci_read_config_byte(pdev, REG_TSFSC, &tsfsc); + pci_read_config_dword(pdev, REG_TSTIMER, &tstimer); + if (tsfsc == 0x7F && tstimer == 0x07D30D40) { + dev_notice(&pdev->dev, "Sensor seems to be disabled\n"); + return -ENODEV; + } + + hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, + "intel5500", NULL, + i5500_temp_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static struct pci_driver i5500_temp_driver = { + .name = "i5500_temp", + .id_table = i5500_temp_ids, + .probe = i5500_temp_probe, +}; + +module_pci_driver(i5500_temp_driver); + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("Intel 5500/5520/X58 chipset thermal sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index e01feba909c3..d1542b7d4bc3 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -51,7 +52,6 @@ #define INA226_ALERT_LIMIT 0x07 #define INA226_DIE_ID 0xFF - /* register count */ #define INA219_REGISTERS 6 #define INA226_REGISTERS 8 @@ -64,6 +64,24 @@ /* worst case is 68.10 ms (~14.6Hz, ina219) */ #define INA2XX_CONVERSION_RATE 15 +#define INA2XX_MAX_DELAY 69 /* worst case delay in ms */ + +#define INA2XX_RSHUNT_DEFAULT 10000 + +/* bit mask for reading the averaging setting in the configuration register */ +#define INA226_AVG_RD_MASK 0x0E00 + +#define INA226_READ_AVG(reg) (((reg) & INA226_AVG_RD_MASK) >> 9) +#define INA226_SHIFT_AVG(val) ((val) << 9) + +/* common attrs, ina226 attrs and NULL */ +#define INA2XX_MAX_ATTRIBUTE_GROUPS 3 + +/* + * Both bus voltage and shunt voltage conversion times for ina226 are set + * to 0b0100 on POR, which translates to 2200 microseconds in total. + */ +#define INA226_TOTAL_CONV_TIME_DEFAULT 2200 enum ina2xx_ids { ina219, ina226 }; @@ -81,11 +99,16 @@ struct ina2xx_data { struct i2c_client *client; const struct ina2xx_config *config; + long rshunt; + u16 curr_config; + struct mutex update_lock; bool valid; unsigned long last_updated; + int update_interval; /* in jiffies */ int kind; + const struct attribute_group *groups[INA2XX_MAX_ATTRIBUTE_GROUPS]; u16 regs[INA2XX_MAX_REGISTERS]; }; @@ -110,34 +133,156 @@ static const struct ina2xx_config ina2xx_config[] = { }, }; -static struct ina2xx_data *ina2xx_update_device(struct device *dev) +/* + * Available averaging rates for ina226. The indices correspond with + * the bit values expected by the chip (according to the ina226 datasheet, + * table 3 AVG bit settings, found at + * http://www.ti.com/lit/ds/symlink/ina226.pdf. + */ +static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 }; + +static int ina226_avg_bits(int avg) +{ + int i; + + /* Get the closest average from the tab. */ + for (i = 0; i < ARRAY_SIZE(ina226_avg_tab) - 1; i++) { + if (avg <= (ina226_avg_tab[i] + ina226_avg_tab[i + 1]) / 2) + break; + } + + return i; /* Return 0b0111 for values greater than 1024. */ +} + +static int ina226_reg_to_interval(u16 config) +{ + int avg = ina226_avg_tab[INA226_READ_AVG(config)]; + + /* + * Multiply the total conversion time by the number of averages. + * Return the result in milliseconds. + */ + return DIV_ROUND_CLOSEST(avg * INA226_TOTAL_CONV_TIME_DEFAULT, 1000); +} + +static u16 ina226_interval_to_reg(int interval, u16 config) +{ + int avg, avg_bits; + + avg = DIV_ROUND_CLOSEST(interval * 1000, + INA226_TOTAL_CONV_TIME_DEFAULT); + avg_bits = ina226_avg_bits(avg); + + return (config & ~INA226_AVG_RD_MASK) | INA226_SHIFT_AVG(avg_bits); +} + +static void ina226_set_update_interval(struct ina2xx_data *data) +{ + int ms; + + ms = ina226_reg_to_interval(data->curr_config); + data->update_interval = msecs_to_jiffies(ms); +} + +static int ina2xx_calibrate(struct ina2xx_data *data) +{ + u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor, + data->rshunt); + + return i2c_smbus_write_word_swapped(data->client, + INA2XX_CALIBRATION, val); +} + +/* + * Initialize the configuration and calibration registers. + */ +static int ina2xx_init(struct ina2xx_data *data) +{ + struct i2c_client *client = data->client; + int ret; + + /* device configuration */ + ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG, + data->curr_config); + if (ret < 0) + return ret; + + /* + * Set current LSB to 1mA, shunt is in uOhms + * (equation 13 in datasheet). + */ + return ina2xx_calibrate(data); +} + +static int ina2xx_do_update(struct device *dev) { struct ina2xx_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; + int i, rv, retry; + + dev_dbg(&client->dev, "Starting ina2xx update\n"); + + for (retry = 5; retry; retry--) { + /* Read all registers */ + for (i = 0; i < data->config->registers; i++) { + rv = i2c_smbus_read_word_swapped(client, i); + if (rv < 0) + return rv; + data->regs[i] = rv; + } + + /* + * If the current value in the calibration register is 0, the + * power and current registers will also remain at 0. In case + * the chip has been reset let's check the calibration + * register and reinitialize if needed. + */ + if (data->regs[INA2XX_CALIBRATION] == 0) { + dev_warn(dev, "chip not calibrated, reinitializing\n"); + + rv = ina2xx_init(data); + if (rv < 0) + return rv; + + /* + * Let's make sure the power and current registers + * have been updated before trying again. + */ + msleep(INA2XX_MAX_DELAY); + continue; + } + + data->last_updated = jiffies; + data->valid = 1; + + return 0; + } + + /* + * If we're here then although all write operations succeeded, the + * chip still returns 0 in the calibration register. Nothing more we + * can do here. + */ + dev_err(dev, "unable to reinitialize the chip\n"); + return -ENODEV; +} + +static struct ina2xx_data *ina2xx_update_device(struct device *dev) +{ + struct ina2xx_data *data = dev_get_drvdata(dev); struct ina2xx_data *ret = data; + unsigned long after; + int rv; mutex_lock(&data->update_lock); - if (time_after(jiffies, data->last_updated + - HZ / INA2XX_CONVERSION_RATE) || !data->valid) { - - int i; - - dev_dbg(&client->dev, "Starting ina2xx update\n"); - - /* Read all registers */ - for (i = 0; i < data->config->registers; i++) { - int rv = i2c_smbus_read_word_swapped(client, i); - if (rv < 0) { - ret = ERR_PTR(rv); - goto abort; - } - data->regs[i] = rv; - } - data->last_updated = jiffies; - data->valid = 1; + after = data->last_updated + data->update_interval; + if (time_after(jiffies, after) || !data->valid) { + rv = ina2xx_do_update(dev); + if (rv < 0) + ret = ERR_PTR(rv); } -abort: + mutex_unlock(&data->update_lock); return ret; } @@ -164,6 +309,10 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg) /* signed register, LSB=1mA (selected), in mA */ val = (s16)data->regs[reg]; break; + case INA2XX_CALIBRATION: + val = DIV_ROUND_CLOSEST(data->config->calibration_factor, + data->regs[reg]); + break; default: /* programmer goofed */ WARN_ON_ONCE(1); @@ -187,6 +336,85 @@ static ssize_t ina2xx_show_value(struct device *dev, ina2xx_get_value(data, attr->index)); } +static ssize_t ina2xx_set_shunt(struct device *dev, + struct device_attribute *da, + const char *buf, size_t count) +{ + struct ina2xx_data *data = ina2xx_update_device(dev); + unsigned long val; + int status; + + if (IS_ERR(data)) + return PTR_ERR(data); + + status = kstrtoul(buf, 10, &val); + if (status < 0) + return status; + + if (val == 0 || + /* Values greater than the calibration factor make no sense. */ + val > data->config->calibration_factor) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->rshunt = val; + status = ina2xx_calibrate(data); + mutex_unlock(&data->update_lock); + if (status < 0) + return status; + + return count; +} + +static ssize_t ina226_set_interval(struct device *dev, + struct device_attribute *da, + const char *buf, size_t count) +{ + struct ina2xx_data *data = dev_get_drvdata(dev); + unsigned long val; + int status; + + status = kstrtoul(buf, 10, &val); + if (status < 0) + return status; + + if (val > INT_MAX || val == 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->curr_config = ina226_interval_to_reg(val, + data->regs[INA2XX_CONFIG]); + status = i2c_smbus_write_word_swapped(data->client, + INA2XX_CONFIG, + data->curr_config); + + ina226_set_update_interval(data); + /* Make sure the next access re-reads all registers. */ + data->valid = 0; + mutex_unlock(&data->update_lock); + if (status < 0) + return status; + + return count; +} + +static ssize_t ina226_show_interval(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct ina2xx_data *data = ina2xx_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + /* + * We don't use data->update_interval here as we want to display + * the actual interval used by the chip and jiffies_to_msecs() + * doesn't seem to be accurate enough. + */ + return snprintf(buf, PAGE_SIZE, "%d\n", + ina226_reg_to_interval(data->regs[INA2XX_CONFIG])); +} + /* shunt voltage */ static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE); @@ -203,15 +431,37 @@ static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina2xx_show_value, NULL, static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL, INA2XX_POWER); +/* shunt resistance */ +static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR, + ina2xx_show_value, ina2xx_set_shunt, + INA2XX_CALIBRATION); + +/* update interval (ina226 only) */ +static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, + ina226_show_interval, ina226_set_interval, 0); + /* pointers to created device attributes */ static struct attribute *ina2xx_attrs[] = { &sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_curr1_input.dev_attr.attr, &sensor_dev_attr_power1_input.dev_attr.attr, + &sensor_dev_attr_shunt_resistor.dev_attr.attr, NULL, }; -ATTRIBUTE_GROUPS(ina2xx); + +static const struct attribute_group ina2xx_group = { + .attrs = ina2xx_attrs, +}; + +static struct attribute *ina226_attrs[] = { + &sensor_dev_attr_update_interval.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ina226_group = { + .attrs = ina226_attrs, +}; static int ina2xx_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -221,9 +471,8 @@ static int ina2xx_probe(struct i2c_client *client, struct device *dev = &client->dev; struct ina2xx_data *data; struct device *hwmon_dev; - long shunt = 10000; /* default shunt value 10mOhms */ u32 val; - int ret; + int ret, group = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) return -ENODEV; @@ -234,50 +483,52 @@ static int ina2xx_probe(struct i2c_client *client, if (dev_get_platdata(dev)) { pdata = dev_get_platdata(dev); - shunt = pdata->shunt_uohms; + data->rshunt = pdata->shunt_uohms; } else if (!of_property_read_u32(dev->of_node, "shunt-resistor", &val)) { - shunt = val; + data->rshunt = val; + } else { + data->rshunt = INA2XX_RSHUNT_DEFAULT; } - if (shunt <= 0) - return -ENODEV; - /* set the device type */ data->kind = id->driver_data; data->config = &ina2xx_config[data->kind]; - - /* device configuration */ - ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG, - data->config->config_default); - if (ret < 0) { - dev_err(dev, - "error writing to the config register: %d", ret); - return -ENODEV; - } + data->curr_config = data->config->config_default; + data->client = client; /* - * Set current LSB to 1mA, shunt is in uOhms - * (equation 13 in datasheet). + * Ina226 has a variable update_interval. For ina219 we + * use a constant value. */ - ret = i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION, - data->config->calibration_factor / shunt); + if (data->kind == ina226) + ina226_set_update_interval(data); + else + data->update_interval = HZ / INA2XX_CONVERSION_RATE; + + if (data->rshunt <= 0 || + data->rshunt > data->config->calibration_factor) + return -ENODEV; + + ret = ina2xx_init(data); if (ret < 0) { - dev_err(dev, - "error writing to the calibration register: %d", ret); + dev_err(dev, "error configuring the device: %d\n", ret); return -ENODEV; } - data->client = client; mutex_init(&data->update_lock); + data->groups[group++] = &ina2xx_group; + if (data->kind == ina226) + data->groups[group++] = &ina226_group; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, - data, ina2xx_groups); + data, data->groups); if (IS_ERR(hwmon_dev)) return PTR_ERR(hwmon_dev); dev_info(dev, "power monitor %s (Rshunt = %li uOhm)\n", - id->name, shunt); + id->name, data->rshunt); return 0; } @@ -287,6 +538,7 @@ static const struct i2c_device_id ina2xx_id[] = { { "ina220", ina219 }, { "ina226", ina226 }, { "ina230", ina226 }, + { "ina231", ina226 }, { } }; MODULE_DEVICE_TABLE(i2c, ina2xx_id); diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 388f8bcd898e..996bdfd5cf25 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -201,7 +201,7 @@ struct jc42_data { #define JC42_TEMP_MIN 0 #define JC42_TEMP_MAX 125000 -static u16 jc42_temp_to_reg(int temp, bool extended) +static u16 jc42_temp_to_reg(long temp, bool extended) { int ntemp = clamp_val(temp, extended ? JC42_TEMP_MIN_EXTENDED : @@ -213,11 +213,7 @@ static u16 jc42_temp_to_reg(int temp, bool extended) static int jc42_temp_from_reg(s16 reg) { - reg &= 0x1fff; - - /* sign extend register */ - if (reg & 0x1000) - reg |= 0xf000; + reg = sign_extend32(reg, 12); /* convert from 0.0625 to 0.001 resolution */ return reg * 125 / 2; @@ -308,15 +304,18 @@ static ssize_t set_temp_crit_hyst(struct device *dev, const char *buf, size_t count) { struct jc42_data *data = dev_get_drvdata(dev); - unsigned long val; + long val; int diff, hyst; int err; int ret = count; - if (kstrtoul(buf, 10, &val) < 0) + if (kstrtol(buf, 10, &val) < 0) return -EINVAL; + val = clamp_val(val, (data->extended ? JC42_TEMP_MIN_EXTENDED : + JC42_TEMP_MIN) - 6000, JC42_TEMP_MAX); diff = jc42_temp_from_reg(data->temp[t_crit]) - val; + hyst = 0; if (diff > 0) { if (diff < 2250) diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index ec5678289e4a..55765790907b 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -779,7 +779,7 @@ static bool nct7802_regmap_is_volatile(struct device *dev, unsigned int reg) return reg != REG_BANK && reg <= 0x20; } -static struct regmap_config nct7802_regmap_config = { +static const struct regmap_config nct7802_regmap_config = { .reg_bits = 8, .val_bits = 8, .cache_type = REGCACHE_RBTREE, diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index ba9f478f64ee..9da2735f1424 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -253,7 +253,7 @@ static int tmp102_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int tmp102_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -279,17 +279,10 @@ static int tmp102_resume(struct device *dev) config &= ~TMP102_CONF_SD; return i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, config); } - -static const struct dev_pm_ops tmp102_dev_pm_ops = { - .suspend = tmp102_suspend, - .resume = tmp102_resume, -}; - -#define TMP102_DEV_PM_OPS (&tmp102_dev_pm_ops) -#else -#define TMP102_DEV_PM_OPS NULL #endif /* CONFIG_PM */ +static SIMPLE_DEV_PM_OPS(tmp102_dev_pm_ops, tmp102_suspend, tmp102_resume); + static const struct i2c_device_id tmp102_id[] = { { "tmp102", 0 }, { } @@ -298,7 +291,7 @@ MODULE_DEVICE_TABLE(i2c, tmp102_id); static struct i2c_driver tmp102_driver = { .driver.name = DRIVER_NAME, - .driver.pm = TMP102_DEV_PM_OPS, + .driver.pm = &tmp102_dev_pm_ops, .probe = tmp102_probe, .remove = tmp102_remove, .id_table = tmp102_id, diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 31e8308ba899..ab838d9e28b6 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -881,6 +881,7 @@ config I2C_XLR config I2C_RCAR tristate "Renesas R-Car I2C Controller" depends on ARCH_SHMOBILE || COMPILE_TEST + select I2C_SLAVE help If you say yes to this option, support will be included for the R-Car I2C controller. diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index bff20a589621..958c8db4ec30 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -785,14 +785,16 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, int ret; pm_runtime_get_sync(&adap->dev); - clk_prepare_enable(i2c->clk); + ret = clk_enable(i2c->clk); + if (ret) + return ret; for (retry = 0; retry < adap->retries; retry++) { ret = s3c24xx_i2c_doxfer(i2c, msgs, num); if (ret != -EAGAIN) { - clk_disable_unprepare(i2c->clk); + clk_disable(i2c->clk); pm_runtime_put(&adap->dev); return ret; } @@ -802,7 +804,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, udelay(100); } - clk_disable_unprepare(i2c->clk); + clk_disable(i2c->clk); pm_runtime_put(&adap->dev); return -EREMOTEIO; } @@ -1197,7 +1199,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) clk_prepare_enable(i2c->clk); ret = s3c24xx_i2c_init(i2c); - clk_disable_unprepare(i2c->clk); + clk_disable(i2c->clk); if (ret != 0) { dev_err(&pdev->dev, "I2C controller init failed\n"); return ret; @@ -1210,6 +1212,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->irq = ret = platform_get_irq(pdev, 0); if (ret <= 0) { dev_err(&pdev->dev, "cannot find IRQ\n"); + clk_unprepare(i2c->clk); return ret; } @@ -1218,6 +1221,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (ret != 0) { dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); + clk_unprepare(i2c->clk); return ret; } } @@ -1225,6 +1229,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = s3c24xx_i2c_register_cpufreq(i2c); if (ret < 0) { dev_err(&pdev->dev, "failed to register cpufreq notifier\n"); + clk_unprepare(i2c->clk); return ret; } @@ -1241,6 +1246,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "failed to add bus to i2c core\n"); s3c24xx_i2c_deregister_cpufreq(i2c); + clk_unprepare(i2c->clk); return ret; } @@ -1262,6 +1268,8 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) { struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); + clk_unprepare(i2c->clk); + pm_runtime_disable(&i2c->adap.dev); pm_runtime_disable(&pdev->dev); @@ -1293,13 +1301,16 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); + int ret; if (!IS_ERR(i2c->sysreg)) regmap_write(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, i2c->sys_i2c_cfg); - clk_prepare_enable(i2c->clk); + ret = clk_enable(i2c->clk); + if (ret) + return ret; s3c24xx_i2c_init(i2c); - clk_disable_unprepare(i2c->clk); + clk_disable(i2c->clk); i2c->suspended = 0; return 0; diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 440d5dbc8b5f..007818b3e174 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -139,6 +139,7 @@ struct sh_mobile_i2c_data { int pos; int sr; bool send_stop; + bool stop_after_dma; struct resource *res; struct dma_chan *dma_tx; @@ -407,7 +408,7 @@ static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd) if (pd->pos == pd->msg->len) { /* Send stop if we haven't yet (DMA case) */ - if (pd->send_stop && (iic_rd(pd, ICCR) & ICCR_BBSY)) + if (pd->send_stop && pd->stop_after_dma) i2c_op(pd, OP_TX_STOP, 0); return 1; } @@ -449,6 +450,13 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd) real_pos = pd->pos - 2; if (pd->pos == pd->msg->len) { + if (pd->stop_after_dma) { + /* Simulate PIO end condition after DMA transfer */ + i2c_op(pd, OP_RX_STOP, 0); + pd->pos++; + break; + } + if (real_pos < 0) { i2c_op(pd, OP_RX_STOP, 0); break; @@ -536,6 +544,7 @@ static void sh_mobile_i2c_dma_callback(void *data) sh_mobile_i2c_dma_unmap(pd); pd->pos = pd->msg->len; + pd->stop_after_dma = true; iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE); } @@ -726,6 +735,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, bool do_start = pd->send_stop || !i; msg = &msgs[i]; pd->send_stop = i == num - 1 || msg->flags & I2C_M_STOP; + pd->stop_after_dma = false; err = start_ch(pd, msg, do_start); if (err) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 39d25a8cb1ad..e9eae57a2b50 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -2972,6 +2972,7 @@ trace: } EXPORT_SYMBOL(i2c_smbus_xfer); +#if IS_ENABLED(CONFIG_I2C_SLAVE) int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb) { int ret; @@ -3019,6 +3020,7 @@ int i2c_slave_unregister(struct i2c_client *client) return ret; } EXPORT_SYMBOL_GPL(i2c_slave_unregister); +#endif MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus main module"); diff --git a/drivers/i2c/i2c-slave-eeprom.c b/drivers/i2c/i2c-slave-eeprom.c index 6631400b5f02..cf9b09db092f 100644 --- a/drivers/i2c/i2c-slave-eeprom.c +++ b/drivers/i2c/i2c-slave-eeprom.c @@ -74,7 +74,7 @@ static ssize_t i2c_slave_eeprom_bin_read(struct file *filp, struct kobject *kobj struct eeprom_data *eeprom; unsigned long flags; - if (off + count >= attr->size) + if (off + count > attr->size) return -EFBIG; eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj)); @@ -92,7 +92,7 @@ static ssize_t i2c_slave_eeprom_bin_write(struct file *filp, struct kobject *kob struct eeprom_data *eeprom; unsigned long flags; - if (off + count >= attr->size) + if (off + count > attr->size) return -EFBIG; eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj)); diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index b730864731e8..adba23246474 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -86,19 +86,18 @@ static void tiadc_step_config(struct iio_dev *indio_dev) { struct tiadc_device *adc_dev = iio_priv(indio_dev); unsigned int stepconfig; - int i, steps; + int i, steps = 0; /* * There are 16 configurable steps and 8 analog input * lines available which are shared between Touchscreen and ADC. * - * Steps backwards i.e. from 16 towards 0 are used by ADC + * Steps forwards i.e. from 0 towards 16 are used by ADC * depending on number of input lines needed. * Channel would represent which analog input * needs to be given to ADC to digitalize data. */ - steps = TOTAL_STEPS - adc_dev->channels; if (iio_buffer_enabled(indio_dev)) stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1 | STEPCONFIG_MODE_SWCNT; diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index b716b0815644..643c08a025a5 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -258,6 +258,5 @@ IB_UVERBS_DECLARE_CMD(close_xrcd); IB_UVERBS_DECLARE_EX_CMD(create_flow); IB_UVERBS_DECLARE_EX_CMD(destroy_flow); -IB_UVERBS_DECLARE_EX_CMD(query_device); #endif /* UVERBS_H */ diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 532d8eba8b02..b7943ff16ed3 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -400,52 +400,6 @@ err: return ret; } -static void copy_query_dev_fields(struct ib_uverbs_file *file, - struct ib_uverbs_query_device_resp *resp, - struct ib_device_attr *attr) -{ - resp->fw_ver = attr->fw_ver; - resp->node_guid = file->device->ib_dev->node_guid; - resp->sys_image_guid = attr->sys_image_guid; - resp->max_mr_size = attr->max_mr_size; - resp->page_size_cap = attr->page_size_cap; - resp->vendor_id = attr->vendor_id; - resp->vendor_part_id = attr->vendor_part_id; - resp->hw_ver = attr->hw_ver; - resp->max_qp = attr->max_qp; - resp->max_qp_wr = attr->max_qp_wr; - resp->device_cap_flags = attr->device_cap_flags; - resp->max_sge = attr->max_sge; - resp->max_sge_rd = attr->max_sge_rd; - resp->max_cq = attr->max_cq; - resp->max_cqe = attr->max_cqe; - resp->max_mr = attr->max_mr; - resp->max_pd = attr->max_pd; - resp->max_qp_rd_atom = attr->max_qp_rd_atom; - resp->max_ee_rd_atom = attr->max_ee_rd_atom; - resp->max_res_rd_atom = attr->max_res_rd_atom; - resp->max_qp_init_rd_atom = attr->max_qp_init_rd_atom; - resp->max_ee_init_rd_atom = attr->max_ee_init_rd_atom; - resp->atomic_cap = attr->atomic_cap; - resp->max_ee = attr->max_ee; - resp->max_rdd = attr->max_rdd; - resp->max_mw = attr->max_mw; - resp->max_raw_ipv6_qp = attr->max_raw_ipv6_qp; - resp->max_raw_ethy_qp = attr->max_raw_ethy_qp; - resp->max_mcast_grp = attr->max_mcast_grp; - resp->max_mcast_qp_attach = attr->max_mcast_qp_attach; - resp->max_total_mcast_qp_attach = attr->max_total_mcast_qp_attach; - resp->max_ah = attr->max_ah; - resp->max_fmr = attr->max_fmr; - resp->max_map_per_fmr = attr->max_map_per_fmr; - resp->max_srq = attr->max_srq; - resp->max_srq_wr = attr->max_srq_wr; - resp->max_srq_sge = attr->max_srq_sge; - resp->max_pkeys = attr->max_pkeys; - resp->local_ca_ack_delay = attr->local_ca_ack_delay; - resp->phys_port_cnt = file->device->ib_dev->phys_port_cnt; -} - ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) @@ -466,7 +420,47 @@ ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file, return ret; memset(&resp, 0, sizeof resp); - copy_query_dev_fields(file, &resp, &attr); + + resp.fw_ver = attr.fw_ver; + resp.node_guid = file->device->ib_dev->node_guid; + resp.sys_image_guid = attr.sys_image_guid; + resp.max_mr_size = attr.max_mr_size; + resp.page_size_cap = attr.page_size_cap; + resp.vendor_id = attr.vendor_id; + resp.vendor_part_id = attr.vendor_part_id; + resp.hw_ver = attr.hw_ver; + resp.max_qp = attr.max_qp; + resp.max_qp_wr = attr.max_qp_wr; + resp.device_cap_flags = attr.device_cap_flags; + resp.max_sge = attr.max_sge; + resp.max_sge_rd = attr.max_sge_rd; + resp.max_cq = attr.max_cq; + resp.max_cqe = attr.max_cqe; + resp.max_mr = attr.max_mr; + resp.max_pd = attr.max_pd; + resp.max_qp_rd_atom = attr.max_qp_rd_atom; + resp.max_ee_rd_atom = attr.max_ee_rd_atom; + resp.max_res_rd_atom = attr.max_res_rd_atom; + resp.max_qp_init_rd_atom = attr.max_qp_init_rd_atom; + resp.max_ee_init_rd_atom = attr.max_ee_init_rd_atom; + resp.atomic_cap = attr.atomic_cap; + resp.max_ee = attr.max_ee; + resp.max_rdd = attr.max_rdd; + resp.max_mw = attr.max_mw; + resp.max_raw_ipv6_qp = attr.max_raw_ipv6_qp; + resp.max_raw_ethy_qp = attr.max_raw_ethy_qp; + resp.max_mcast_grp = attr.max_mcast_grp; + resp.max_mcast_qp_attach = attr.max_mcast_qp_attach; + resp.max_total_mcast_qp_attach = attr.max_total_mcast_qp_attach; + resp.max_ah = attr.max_ah; + resp.max_fmr = attr.max_fmr; + resp.max_map_per_fmr = attr.max_map_per_fmr; + resp.max_srq = attr.max_srq; + resp.max_srq_wr = attr.max_srq_wr; + resp.max_srq_sge = attr.max_srq_sge; + resp.max_pkeys = attr.max_pkeys; + resp.local_ca_ack_delay = attr.local_ca_ack_delay; + resp.phys_port_cnt = file->device->ib_dev->phys_port_cnt; if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) @@ -3293,52 +3287,3 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, return ret ? ret : in_len; } - -int ib_uverbs_ex_query_device(struct ib_uverbs_file *file, - struct ib_udata *ucore, - struct ib_udata *uhw) -{ - struct ib_uverbs_ex_query_device_resp resp; - struct ib_uverbs_ex_query_device cmd; - struct ib_device_attr attr; - struct ib_device *device; - int err; - - device = file->device->ib_dev; - if (ucore->inlen < sizeof(cmd)) - return -EINVAL; - - err = ib_copy_from_udata(&cmd, ucore, sizeof(cmd)); - if (err) - return err; - - if (cmd.reserved) - return -EINVAL; - - err = device->query_device(device, &attr); - if (err) - return err; - - memset(&resp, 0, sizeof(resp)); - copy_query_dev_fields(file, &resp.base, &attr); - resp.comp_mask = 0; - -#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING - if (cmd.comp_mask & IB_USER_VERBS_EX_QUERY_DEVICE_ODP) { - resp.odp_caps.general_caps = attr.odp_caps.general_caps; - resp.odp_caps.per_transport_caps.rc_odp_caps = - attr.odp_caps.per_transport_caps.rc_odp_caps; - resp.odp_caps.per_transport_caps.uc_odp_caps = - attr.odp_caps.per_transport_caps.uc_odp_caps; - resp.odp_caps.per_transport_caps.ud_odp_caps = - attr.odp_caps.per_transport_caps.ud_odp_caps; - resp.comp_mask |= IB_USER_VERBS_EX_QUERY_DEVICE_ODP; - } -#endif - - err = ib_copy_to_udata(ucore, &resp, sizeof(resp)); - if (err) - return err; - - return 0; -} diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index e6c23b9eab33..5db1a8cc388d 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -123,7 +123,6 @@ static int (*uverbs_ex_cmd_table[])(struct ib_uverbs_file *file, struct ib_udata *uhw) = { [IB_USER_VERBS_EX_CMD_CREATE_FLOW] = ib_uverbs_ex_create_flow, [IB_USER_VERBS_EX_CMD_DESTROY_FLOW] = ib_uverbs_ex_destroy_flow, - [IB_USER_VERBS_EX_CMD_QUERY_DEVICE] = ib_uverbs_ex_query_device }; static void ib_uverbs_add_one(struct ib_device *device); diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 9edc200b311d..57176ddd4c50 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -235,19 +235,19 @@ static void release_tid(struct c4iw_rdev *rdev, u32 hwtid, struct sk_buff *skb) static void set_emss(struct c4iw_ep *ep, u16 opt) { - ep->emss = ep->com.dev->rdev.lldi.mtus[GET_TCPOPT_MSS(opt)] - + ep->emss = ep->com.dev->rdev.lldi.mtus[TCPOPT_MSS_G(opt)] - ((AF_INET == ep->com.remote_addr.ss_family) ? sizeof(struct iphdr) : sizeof(struct ipv6hdr)) - sizeof(struct tcphdr); ep->mss = ep->emss; - if (GET_TCPOPT_TSTAMP(opt)) + if (TCPOPT_TSTAMP_G(opt)) ep->emss -= round_up(TCPOLEN_TIMESTAMP, 4); if (ep->emss < 128) ep->emss = 128; if (ep->emss & 7) PDBG("Warning: misaligned mtu idx %u mss %u emss=%u\n", - GET_TCPOPT_MSS(opt), ep->mss, ep->emss); - PDBG("%s mss_idx %u mss %u emss=%u\n", __func__, GET_TCPOPT_MSS(opt), + TCPOPT_MSS_G(opt), ep->mss, ep->emss); + PDBG("%s mss_idx %u mss %u emss=%u\n", __func__, TCPOPT_MSS_G(opt), ep->mss, ep->emss); } @@ -652,29 +652,29 @@ static int send_connect(struct c4iw_ep *ep) if (win > RCV_BUFSIZ_M) win = RCV_BUFSIZ_M; - opt0 = (nocong ? NO_CONG(1) : 0) | + opt0 = (nocong ? NO_CONG_F : 0) | KEEP_ALIVE_F | - DELACK(1) | + DELACK_F | WND_SCALE_V(wscale) | MSS_IDX_V(mtu_idx) | L2T_IDX_V(ep->l2t->idx) | TX_CHAN_V(ep->tx_chan) | SMAC_SEL_V(ep->smac_idx) | - DSCP(ep->tos) | + DSCP_V(ep->tos) | ULP_MODE_V(ULP_MODE_TCPDDP) | RCV_BUFSIZ_V(win); opt2 = RX_CHANNEL_V(0) | - CCTRL_ECN(enable_ecn) | + CCTRL_ECN_V(enable_ecn) | RSS_QUEUE_VALID_F | RSS_QUEUE_V(ep->rss_qid); if (enable_tcp_timestamps) - opt2 |= TSTAMPS_EN(1); + opt2 |= TSTAMPS_EN_F; if (enable_tcp_sack) - opt2 |= SACK_EN(1); + opt2 |= SACK_EN_F; if (wscale && enable_tcp_window_scaling) opt2 |= WND_SCALE_EN_F; if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) { opt2 |= T5_OPT_2_VALID_F; - opt2 |= V_CONG_CNTRL(CONG_ALG_TAHOE); + opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE); opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */ } t4_set_arp_err_handler(skb, ep, act_open_req_arp_failure); @@ -1042,7 +1042,7 @@ static int act_establish(struct c4iw_dev *dev, struct sk_buff *skb) struct c4iw_ep *ep; struct cpl_act_establish *req = cplhdr(skb); unsigned int tid = GET_TID(req); - unsigned int atid = GET_TID_TID(ntohl(req->tos_atid)); + unsigned int atid = TID_TID_G(ntohl(req->tos_atid)); struct tid_info *t = dev->rdev.lldi.tids; ep = lookup_atid(t, atid); @@ -1258,8 +1258,8 @@ static int update_rx_credits(struct c4iw_ep *ep, u32 credits) OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_RX_DATA_ACK, ep->hwtid)); req->credit_dack = cpu_to_be32(credits | RX_FORCE_ACK_F | - F_RX_DACK_CHANGE | - V_RX_DACK_MODE(dack_mode)); + RX_DACK_CHANGE_F | + RX_DACK_MODE_V(dack_mode)); set_wr_txq(skb, CPL_PRIORITY_ACK, ep->ctrlq_idx); c4iw_ofld_send(&ep->com.dev->rdev, skb); return credits; @@ -1751,7 +1751,7 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid) skb = get_skb(NULL, sizeof(*req), GFP_KERNEL); req = (struct fw_ofld_connection_wr *)__skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); - req->op_compl = htonl(V_WR_OP(FW_OFLD_CONNECTION_WR)); + req->op_compl = htonl(WR_OP_V(FW_OFLD_CONNECTION_WR)); req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16))); req->le.filter = cpu_to_be32(cxgb4_select_ntuple( ep->com.dev->rdev.lldi.ports[0], @@ -1782,27 +1782,27 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid) if (win > RCV_BUFSIZ_M) win = RCV_BUFSIZ_M; - req->tcb.opt0 = (__force __be64) (TCAM_BYPASS(1) | - (nocong ? NO_CONG(1) : 0) | + req->tcb.opt0 = (__force __be64) (TCAM_BYPASS_F | + (nocong ? NO_CONG_F : 0) | KEEP_ALIVE_F | - DELACK(1) | + DELACK_F | WND_SCALE_V(wscale) | MSS_IDX_V(mtu_idx) | L2T_IDX_V(ep->l2t->idx) | TX_CHAN_V(ep->tx_chan) | SMAC_SEL_V(ep->smac_idx) | - DSCP(ep->tos) | + DSCP_V(ep->tos) | ULP_MODE_V(ULP_MODE_TCPDDP) | RCV_BUFSIZ_V(win)); - req->tcb.opt2 = (__force __be32) (PACE(1) | - TX_QUEUE(ep->com.dev->rdev.lldi.tx_modq[ep->tx_chan]) | + req->tcb.opt2 = (__force __be32) (PACE_V(1) | + TX_QUEUE_V(ep->com.dev->rdev.lldi.tx_modq[ep->tx_chan]) | RX_CHANNEL_V(0) | - CCTRL_ECN(enable_ecn) | + CCTRL_ECN_V(enable_ecn) | RSS_QUEUE_VALID_F | RSS_QUEUE_V(ep->rss_qid)); if (enable_tcp_timestamps) - req->tcb.opt2 |= (__force __be32)TSTAMPS_EN(1); + req->tcb.opt2 |= (__force __be32)TSTAMPS_EN_F; if (enable_tcp_sack) - req->tcb.opt2 |= (__force __be32)SACK_EN(1); + req->tcb.opt2 |= (__force __be32)SACK_EN_F; if (wscale && enable_tcp_window_scaling) req->tcb.opt2 |= (__force __be32)WND_SCALE_EN_F; req->tcb.opt0 = cpu_to_be64((__force u64)req->tcb.opt0); @@ -2023,10 +2023,10 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb) { struct c4iw_ep *ep; struct cpl_act_open_rpl *rpl = cplhdr(skb); - unsigned int atid = GET_TID_TID(GET_AOPEN_ATID( - ntohl(rpl->atid_status))); + unsigned int atid = TID_TID_G(AOPEN_ATID_G( + ntohl(rpl->atid_status))); struct tid_info *t = dev->rdev.lldi.tids; - int status = GET_AOPEN_STATUS(ntohl(rpl->atid_status)); + int status = AOPEN_STATUS_G(ntohl(rpl->atid_status)); struct sockaddr_in *la; struct sockaddr_in *ra; struct sockaddr_in6 *la6; @@ -2064,7 +2064,7 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb) if (ep->com.local_addr.ss_family == AF_INET && dev->rdev.lldi.enable_fw_ofld_conn) { send_fw_act_open_req(ep, - GET_TID_TID(GET_AOPEN_ATID( + TID_TID_G(AOPEN_ATID_G( ntohl(rpl->atid_status)))); return 0; } @@ -2181,39 +2181,39 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb, win = ep->rcv_win >> 10; if (win > RCV_BUFSIZ_M) win = RCV_BUFSIZ_M; - opt0 = (nocong ? NO_CONG(1) : 0) | + opt0 = (nocong ? NO_CONG_F : 0) | KEEP_ALIVE_F | - DELACK(1) | + DELACK_F | WND_SCALE_V(wscale) | MSS_IDX_V(mtu_idx) | L2T_IDX_V(ep->l2t->idx) | TX_CHAN_V(ep->tx_chan) | SMAC_SEL_V(ep->smac_idx) | - DSCP(ep->tos >> 2) | + DSCP_V(ep->tos >> 2) | ULP_MODE_V(ULP_MODE_TCPDDP) | RCV_BUFSIZ_V(win); opt2 = RX_CHANNEL_V(0) | RSS_QUEUE_VALID_F | RSS_QUEUE_V(ep->rss_qid); if (enable_tcp_timestamps && req->tcpopt.tstamp) - opt2 |= TSTAMPS_EN(1); + opt2 |= TSTAMPS_EN_F; if (enable_tcp_sack && req->tcpopt.sack) - opt2 |= SACK_EN(1); + opt2 |= SACK_EN_F; if (wscale && enable_tcp_window_scaling) opt2 |= WND_SCALE_EN_F; if (enable_ecn) { const struct tcphdr *tcph; u32 hlen = ntohl(req->hdr_len); - tcph = (const void *)(req + 1) + G_ETH_HDR_LEN(hlen) + - G_IP_HDR_LEN(hlen); + tcph = (const void *)(req + 1) + ETH_HDR_LEN_G(hlen) + + IP_HDR_LEN_G(hlen); if (tcph->ece && tcph->cwr) - opt2 |= CCTRL_ECN(1); + opt2 |= CCTRL_ECN_V(1); } if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) { u32 isn = (prandom_u32() & ~7UL) - 1; opt2 |= T5_OPT_2_VALID_F; - opt2 |= V_CONG_CNTRL(CONG_ALG_TAHOE); + opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE); opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */ rpl5 = (void *)rpl; memset(&rpl5->iss, 0, roundup(sizeof(*rpl5)-sizeof(*rpl), 16)); @@ -2245,8 +2245,8 @@ static void get_4tuple(struct cpl_pass_accept_req *req, int *iptype, __u8 *local_ip, __u8 *peer_ip, __be16 *local_port, __be16 *peer_port) { - int eth_len = G_ETH_HDR_LEN(be32_to_cpu(req->hdr_len)); - int ip_len = G_IP_HDR_LEN(be32_to_cpu(req->hdr_len)); + int eth_len = ETH_HDR_LEN_G(be32_to_cpu(req->hdr_len)); + int ip_len = IP_HDR_LEN_G(be32_to_cpu(req->hdr_len)); struct iphdr *ip = (struct iphdr *)((u8 *)(req + 1) + eth_len); struct ipv6hdr *ip6 = (struct ipv6hdr *)((u8 *)(req + 1) + eth_len); struct tcphdr *tcp = (struct tcphdr *) @@ -2277,7 +2277,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) { struct c4iw_ep *child_ep = NULL, *parent_ep; struct cpl_pass_accept_req *req = cplhdr(skb); - unsigned int stid = GET_POPEN_TID(ntohl(req->tos_stid)); + unsigned int stid = PASS_OPEN_TID_G(ntohl(req->tos_stid)); struct tid_info *t = dev->rdev.lldi.tids; unsigned int hwtid = GET_TID(req); struct dst_entry *dst; @@ -2310,14 +2310,14 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) ntohs(peer_port), peer_mss); dst = find_route(dev, *(__be32 *)local_ip, *(__be32 *)peer_ip, local_port, peer_port, - GET_POPEN_TOS(ntohl(req->tos_stid))); + PASS_OPEN_TOS_G(ntohl(req->tos_stid))); } else { PDBG("%s parent ep %p hwtid %u laddr %pI6 raddr %pI6 lport %d rport %d peer_mss %d\n" , __func__, parent_ep, hwtid, local_ip, peer_ip, ntohs(local_port), ntohs(peer_port), peer_mss); dst = find_route6(dev, local_ip, peer_ip, local_port, peer_port, - PASS_OPEN_TOS(ntohl(req->tos_stid)), + PASS_OPEN_TOS_G(ntohl(req->tos_stid)), ((struct sockaddr_in6 *) &parent_ep->com.local_addr)->sin6_scope_id); } @@ -2375,7 +2375,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) } c4iw_get_ep(&parent_ep->com); child_ep->parent_ep = parent_ep; - child_ep->tos = GET_POPEN_TOS(ntohl(req->tos_stid)); + child_ep->tos = PASS_OPEN_TOS_G(ntohl(req->tos_stid)); child_ep->dst = dst; child_ep->hwtid = hwtid; @@ -3500,24 +3500,24 @@ static void build_cpl_pass_accept_req(struct sk_buff *skb, int stid , u8 tos) req = (struct cpl_pass_accept_req *)__skb_push(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); - req->l2info = cpu_to_be16(V_SYN_INTF(intf) | - V_SYN_MAC_IDX(G_RX_MACIDX( + req->l2info = cpu_to_be16(SYN_INTF_V(intf) | + SYN_MAC_IDX_V(RX_MACIDX_G( (__force int) htonl(l2info))) | - F_SYN_XACT_MATCH); + SYN_XACT_MATCH_F); eth_hdr_len = is_t4(dev->rdev.lldi.adapter_type) ? - G_RX_ETHHDR_LEN((__force int) htonl(l2info)) : - G_RX_T5_ETHHDR_LEN((__force int) htonl(l2info)); - req->hdr_len = cpu_to_be32(V_SYN_RX_CHAN(G_RX_CHAN( + RX_ETHHDR_LEN_G((__force int)htonl(l2info)) : + RX_T5_ETHHDR_LEN_G((__force int)htonl(l2info)); + req->hdr_len = cpu_to_be32(SYN_RX_CHAN_V(RX_CHAN_G( (__force int) htonl(l2info))) | - V_TCP_HDR_LEN(G_RX_TCPHDR_LEN( + TCP_HDR_LEN_V(RX_TCPHDR_LEN_G( (__force int) htons(hdr_len))) | - V_IP_HDR_LEN(G_RX_IPHDR_LEN( + IP_HDR_LEN_V(RX_IPHDR_LEN_G( (__force int) htons(hdr_len))) | - V_ETH_HDR_LEN(G_RX_ETHHDR_LEN(eth_hdr_len))); + ETH_HDR_LEN_V(RX_ETHHDR_LEN_G(eth_hdr_len))); req->vlan = (__force __be16) vlantag; req->len = (__force __be16) len; - req->tos_stid = cpu_to_be32(PASS_OPEN_TID(stid) | - PASS_OPEN_TOS(tos)); + req->tos_stid = cpu_to_be32(PASS_OPEN_TID_V(stid) | + PASS_OPEN_TOS_V(tos)); req->tcpopt.mss = htons(tmp_opt.mss_clamp); if (tmp_opt.wscale_ok) req->tcpopt.wsf = tmp_opt.snd_wscale; @@ -3542,7 +3542,7 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb, req_skb = alloc_skb(sizeof(struct fw_ofld_connection_wr), GFP_KERNEL); req = (struct fw_ofld_connection_wr *)__skb_put(req_skb, sizeof(*req)); memset(req, 0, sizeof(*req)); - req->op_compl = htonl(V_WR_OP(FW_OFLD_CONNECTION_WR) | FW_WR_COMPL_F); + req->op_compl = htonl(WR_OP_V(FW_OFLD_CONNECTION_WR) | FW_WR_COMPL_F); req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16))); req->le.version_cpl = htonl(FW_OFLD_CONNECTION_WR_CPL_F); req->le.filter = (__force __be32) filter; @@ -3556,7 +3556,7 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb, htonl(FW_OFLD_CONNECTION_WR_T_STATE_V(TCP_SYN_RECV) | FW_OFLD_CONNECTION_WR_RCV_SCALE_V(cpl->tcpopt.wsf) | FW_OFLD_CONNECTION_WR_ASTID_V( - GET_PASS_OPEN_TID(ntohl(cpl->tos_stid)))); + PASS_OPEN_TID_G(ntohl(cpl->tos_stid)))); /* * We store the qid in opt2 which will be used by the firmware @@ -3613,7 +3613,7 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb) struct neighbour *neigh; /* Drop all non-SYN packets */ - if (!(cpl->l2info & cpu_to_be32(F_RXF_SYN))) + if (!(cpl->l2info & cpu_to_be32(RXF_SYN_F))) goto reject; /* @@ -3635,8 +3635,8 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb) } eth_hdr_len = is_t4(dev->rdev.lldi.adapter_type) ? - G_RX_ETHHDR_LEN(htonl(cpl->l2info)) : - G_RX_T5_ETHHDR_LEN(htonl(cpl->l2info)); + RX_ETHHDR_LEN_G(htonl(cpl->l2info)) : + RX_T5_ETHHDR_LEN_G(htonl(cpl->l2info)); if (eth_hdr_len == ETH_HLEN) { eh = (struct ethhdr *)(req + 1); iph = (struct iphdr *)(eh + 1); diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index e9fd3a029296..ab7692ac2044 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -52,7 +52,7 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, memset(res_wr, 0, wr_len); res_wr->op_nres = cpu_to_be32( FW_WR_OP_V(FW_RI_RES_WR) | - V_FW_RI_RES_WR_NRES(1) | + FW_RI_RES_WR_NRES_V(1) | FW_WR_COMPL_F); res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16)); res_wr->cookie = (unsigned long) &wr_wait; @@ -122,7 +122,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, memset(res_wr, 0, wr_len); res_wr->op_nres = cpu_to_be32( FW_WR_OP_V(FW_RI_RES_WR) | - V_FW_RI_RES_WR_NRES(1) | + FW_RI_RES_WR_NRES_V(1) | FW_WR_COMPL_F); res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16)); res_wr->cookie = (unsigned long) &wr_wait; @@ -131,17 +131,17 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, res->u.cq.op = FW_RI_RES_OP_WRITE; res->u.cq.iqid = cpu_to_be32(cq->cqid); res->u.cq.iqandst_to_iqandstindex = cpu_to_be32( - V_FW_RI_RES_WR_IQANUS(0) | - V_FW_RI_RES_WR_IQANUD(1) | - F_FW_RI_RES_WR_IQANDST | - V_FW_RI_RES_WR_IQANDSTINDEX( + FW_RI_RES_WR_IQANUS_V(0) | + FW_RI_RES_WR_IQANUD_V(1) | + FW_RI_RES_WR_IQANDST_F | + FW_RI_RES_WR_IQANDSTINDEX_V( rdev->lldi.ciq_ids[cq->vector])); res->u.cq.iqdroprss_to_iqesize = cpu_to_be16( - F_FW_RI_RES_WR_IQDROPRSS | - V_FW_RI_RES_WR_IQPCIECH(2) | - V_FW_RI_RES_WR_IQINTCNTTHRESH(0) | - F_FW_RI_RES_WR_IQO | - V_FW_RI_RES_WR_IQESIZE(1)); + FW_RI_RES_WR_IQDROPRSS_F | + FW_RI_RES_WR_IQPCIECH_V(2) | + FW_RI_RES_WR_IQINTCNTTHRESH_V(0) | + FW_RI_RES_WR_IQO_F | + FW_RI_RES_WR_IQESIZE_V(1)); res->u.cq.iqsize = cpu_to_be16(cq->size); res->u.cq.iqaddr = cpu_to_be64(cq->dma_addr); @@ -182,12 +182,12 @@ static void insert_recv_cqe(struct t4_wq *wq, struct t4_cq *cq) PDBG("%s wq %p cq %p sw_cidx %u sw_pidx %u\n", __func__, wq, cq, cq->sw_cidx, cq->sw_pidx); memset(&cqe, 0, sizeof(cqe)); - cqe.header = cpu_to_be32(V_CQE_STATUS(T4_ERR_SWFLUSH) | - V_CQE_OPCODE(FW_RI_SEND) | - V_CQE_TYPE(0) | - V_CQE_SWCQE(1) | - V_CQE_QPID(wq->sq.qid)); - cqe.bits_type_ts = cpu_to_be64(V_CQE_GENBIT((u64)cq->gen)); + cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) | + CQE_OPCODE_V(FW_RI_SEND) | + CQE_TYPE_V(0) | + CQE_SWCQE_V(1) | + CQE_QPID_V(wq->sq.qid)); + cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen)); cq->sw_queue[cq->sw_pidx] = cqe; t4_swcq_produce(cq); } @@ -215,13 +215,13 @@ static void insert_sq_cqe(struct t4_wq *wq, struct t4_cq *cq, PDBG("%s wq %p cq %p sw_cidx %u sw_pidx %u\n", __func__, wq, cq, cq->sw_cidx, cq->sw_pidx); memset(&cqe, 0, sizeof(cqe)); - cqe.header = cpu_to_be32(V_CQE_STATUS(T4_ERR_SWFLUSH) | - V_CQE_OPCODE(swcqe->opcode) | - V_CQE_TYPE(1) | - V_CQE_SWCQE(1) | - V_CQE_QPID(wq->sq.qid)); + cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) | + CQE_OPCODE_V(swcqe->opcode) | + CQE_TYPE_V(1) | + CQE_SWCQE_V(1) | + CQE_QPID_V(wq->sq.qid)); CQE_WRID_SQ_IDX(&cqe) = swcqe->idx; - cqe.bits_type_ts = cpu_to_be64(V_CQE_GENBIT((u64)cq->gen)); + cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen)); cq->sw_queue[cq->sw_pidx] = cqe; t4_swcq_produce(cq); } @@ -284,7 +284,7 @@ static void flush_completed_wrs(struct t4_wq *wq, struct t4_cq *cq) */ PDBG("%s moving cqe into swcq sq idx %u cq idx %u\n", __func__, cidx, cq->sw_pidx); - swsqe->cqe.header |= htonl(V_CQE_SWCQE(1)); + swsqe->cqe.header |= htonl(CQE_SWCQE_V(1)); cq->sw_queue[cq->sw_pidx] = swsqe->cqe; t4_swcq_produce(cq); swsqe->flushed = 1; @@ -301,10 +301,10 @@ static void create_read_req_cqe(struct t4_wq *wq, struct t4_cqe *hw_cqe, { read_cqe->u.scqe.cidx = wq->sq.oldest_read->idx; read_cqe->len = htonl(wq->sq.oldest_read->read_len); - read_cqe->header = htonl(V_CQE_QPID(CQE_QPID(hw_cqe)) | - V_CQE_SWCQE(SW_CQE(hw_cqe)) | - V_CQE_OPCODE(FW_RI_READ_REQ) | - V_CQE_TYPE(1)); + read_cqe->header = htonl(CQE_QPID_V(CQE_QPID(hw_cqe)) | + CQE_SWCQE_V(SW_CQE(hw_cqe)) | + CQE_OPCODE_V(FW_RI_READ_REQ) | + CQE_TYPE_V(1)); read_cqe->bits_type_ts = hw_cqe->bits_type_ts; } @@ -400,7 +400,7 @@ void c4iw_flush_hw_cq(struct c4iw_cq *chp) } else { swcqe = &chp->cq.sw_queue[chp->cq.sw_pidx]; *swcqe = *hw_cqe; - swcqe->header |= cpu_to_be32(V_CQE_SWCQE(1)); + swcqe->header |= cpu_to_be32(CQE_SWCQE_V(1)); t4_swcq_produce(&chp->cq); } next_cqe: @@ -576,7 +576,7 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe, } if (unlikely((CQE_WRID_MSN(hw_cqe) != (wq->rq.msn)))) { t4_set_wq_in_error(wq); - hw_cqe->header |= htonl(V_CQE_STATUS(T4_ERR_MSN)); + hw_cqe->header |= htonl(CQE_STATUS_V(T4_ERR_MSN)); goto proc_cqe; } goto proc_cqe; diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index eb5df4e62703..aafdbcd84fc4 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -380,12 +380,12 @@ static int dump_stag(int id, void *p, void *data) "stag: idx 0x%x valid %d key 0x%x state %d pdid %d " "perm 0x%x ps %d len 0x%llx va 0x%llx\n", (u32)id<<8, - G_FW_RI_TPTE_VALID(ntohl(tpte.valid_to_pdid)), - G_FW_RI_TPTE_STAGKEY(ntohl(tpte.valid_to_pdid)), - G_FW_RI_TPTE_STAGSTATE(ntohl(tpte.valid_to_pdid)), - G_FW_RI_TPTE_PDID(ntohl(tpte.valid_to_pdid)), - G_FW_RI_TPTE_PERM(ntohl(tpte.locread_to_qpid)), - G_FW_RI_TPTE_PS(ntohl(tpte.locread_to_qpid)), + FW_RI_TPTE_VALID_G(ntohl(tpte.valid_to_pdid)), + FW_RI_TPTE_STAGKEY_G(ntohl(tpte.valid_to_pdid)), + FW_RI_TPTE_STAGSTATE_G(ntohl(tpte.valid_to_pdid)), + FW_RI_TPTE_PDID_G(ntohl(tpte.valid_to_pdid)), + FW_RI_TPTE_PERM_G(ntohl(tpte.locread_to_qpid)), + FW_RI_TPTE_PS_G(ntohl(tpte.locread_to_qpid)), ((u64)ntohl(tpte.len_hi) << 32) | ntohl(tpte.len_lo), ((u64)ntohl(tpte.va_hi) << 32) | ntohl(tpte.va_lo_fbo)); if (cc < space) diff --git a/drivers/infiniband/hw/cxgb4/ev.c b/drivers/infiniband/hw/cxgb4/ev.c index c9df0549f51d..794555dc86a5 100644 --- a/drivers/infiniband/hw/cxgb4/ev.c +++ b/drivers/infiniband/hw/cxgb4/ev.c @@ -50,12 +50,12 @@ static void print_tpte(struct c4iw_dev *dev, u32 stag) PDBG("stag idx 0x%x valid %d key 0x%x state %d pdid %d " "perm 0x%x ps %d len 0x%llx va 0x%llx\n", stag & 0xffffff00, - G_FW_RI_TPTE_VALID(ntohl(tpte.valid_to_pdid)), - G_FW_RI_TPTE_STAGKEY(ntohl(tpte.valid_to_pdid)), - G_FW_RI_TPTE_STAGSTATE(ntohl(tpte.valid_to_pdid)), - G_FW_RI_TPTE_PDID(ntohl(tpte.valid_to_pdid)), - G_FW_RI_TPTE_PERM(ntohl(tpte.locread_to_qpid)), - G_FW_RI_TPTE_PS(ntohl(tpte.locread_to_qpid)), + FW_RI_TPTE_VALID_G(ntohl(tpte.valid_to_pdid)), + FW_RI_TPTE_STAGKEY_G(ntohl(tpte.valid_to_pdid)), + FW_RI_TPTE_STAGSTATE_G(ntohl(tpte.valid_to_pdid)), + FW_RI_TPTE_PDID_G(ntohl(tpte.valid_to_pdid)), + FW_RI_TPTE_PERM_G(ntohl(tpte.locread_to_qpid)), + FW_RI_TPTE_PS_G(ntohl(tpte.locread_to_qpid)), ((u64)ntohl(tpte.len_hi) << 32) | ntohl(tpte.len_lo), ((u64)ntohl(tpte.va_hi) << 32) | ntohl(tpte.va_lo_fbo)); } diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c index cb43c2299ac0..6791fd16272c 100644 --- a/drivers/infiniband/hw/cxgb4/mem.c +++ b/drivers/infiniband/hw/cxgb4/mem.c @@ -86,14 +86,14 @@ static int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr, req->wr.wr_lo = wait ? (__force __be64)(unsigned long) &wr_wait : 0L; req->wr.wr_mid = cpu_to_be32(FW_WR_LEN16_V(DIV_ROUND_UP(wr_len, 16))); req->cmd = cpu_to_be32(ULPTX_CMD_V(ULP_TX_MEM_WRITE)); - req->cmd |= cpu_to_be32(V_T5_ULP_MEMIO_ORDER(1)); + req->cmd |= cpu_to_be32(T5_ULP_MEMIO_ORDER_V(1)); req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN_V(len>>5)); req->len16 = cpu_to_be32(DIV_ROUND_UP(wr_len-sizeof(req->wr), 16)); req->lock_addr = cpu_to_be32(ULP_MEMIO_ADDR_V(addr)); sgl = (struct ulptx_sgl *)(req + 1); sgl->cmd_nsge = cpu_to_be32(ULPTX_CMD_V(ULP_TX_SC_DSGL) | - ULPTX_NSGE(1)); + ULPTX_NSGE_V(1)); sgl->len0 = cpu_to_be32(len); sgl->addr0 = cpu_to_be64(data); @@ -286,17 +286,17 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry, if (reset_tpt_entry) memset(&tpt, 0, sizeof(tpt)); else { - tpt.valid_to_pdid = cpu_to_be32(F_FW_RI_TPTE_VALID | - V_FW_RI_TPTE_STAGKEY((*stag & M_FW_RI_TPTE_STAGKEY)) | - V_FW_RI_TPTE_STAGSTATE(stag_state) | - V_FW_RI_TPTE_STAGTYPE(type) | V_FW_RI_TPTE_PDID(pdid)); - tpt.locread_to_qpid = cpu_to_be32(V_FW_RI_TPTE_PERM(perm) | - (bind_enabled ? F_FW_RI_TPTE_MWBINDEN : 0) | - V_FW_RI_TPTE_ADDRTYPE((zbva ? FW_RI_ZERO_BASED_TO : + tpt.valid_to_pdid = cpu_to_be32(FW_RI_TPTE_VALID_F | + FW_RI_TPTE_STAGKEY_V((*stag & FW_RI_TPTE_STAGKEY_M)) | + FW_RI_TPTE_STAGSTATE_V(stag_state) | + FW_RI_TPTE_STAGTYPE_V(type) | FW_RI_TPTE_PDID_V(pdid)); + tpt.locread_to_qpid = cpu_to_be32(FW_RI_TPTE_PERM_V(perm) | + (bind_enabled ? FW_RI_TPTE_MWBINDEN_F : 0) | + FW_RI_TPTE_ADDRTYPE_V((zbva ? FW_RI_ZERO_BASED_TO : FW_RI_VA_BASED_TO))| - V_FW_RI_TPTE_PS(page_size)); + FW_RI_TPTE_PS_V(page_size)); tpt.nosnoop_pbladdr = !pbl_size ? 0 : cpu_to_be32( - V_FW_RI_TPTE_PBLADDR(PBL_OFF(rdev, pbl_addr)>>3)); + FW_RI_TPTE_PBLADDR_V(PBL_OFF(rdev, pbl_addr)>>3)); tpt.len_lo = cpu_to_be32((u32)(len & 0xffffffffUL)); tpt.va_hi = cpu_to_be32((u32)(to >> 32)); tpt.va_lo_fbo = cpu_to_be32((u32)(to & 0xffffffffUL)); diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index bb85d479e66e..15cae5a31018 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -272,7 +272,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, memset(res_wr, 0, wr_len); res_wr->op_nres = cpu_to_be32( FW_WR_OP_V(FW_RI_RES_WR) | - V_FW_RI_RES_WR_NRES(2) | + FW_RI_RES_WR_NRES_V(2) | FW_WR_COMPL_F); res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16)); res_wr->cookie = (unsigned long) &wr_wait; @@ -287,19 +287,19 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, rdev->hw_queue.t4_eq_status_entries; res->u.sqrq.fetchszm_to_iqid = cpu_to_be32( - 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) | - V_FW_RI_RES_WR_IQID(scq->cqid)); + FW_RI_RES_WR_HOSTFCMODE_V(0) | /* no host cidx updates */ + FW_RI_RES_WR_CPRIO_V(0) | /* don't keep in chip cache */ + FW_RI_RES_WR_PCIECHN_V(0) | /* set by uP at ri_init time */ + (t4_sq_onchip(&wq->sq) ? FW_RI_RES_WR_ONCHIP_F : 0) | + FW_RI_RES_WR_IQID_V(scq->cqid)); res->u.sqrq.dcaen_to_eqsize = cpu_to_be32( - V_FW_RI_RES_WR_DCAEN(0) | - V_FW_RI_RES_WR_DCACPU(0) | - V_FW_RI_RES_WR_FBMIN(2) | - V_FW_RI_RES_WR_FBMAX(2) | - V_FW_RI_RES_WR_CIDXFTHRESHO(0) | - V_FW_RI_RES_WR_CIDXFTHRESH(0) | - V_FW_RI_RES_WR_EQSIZE(eqsize)); + FW_RI_RES_WR_DCAEN_V(0) | + FW_RI_RES_WR_DCACPU_V(0) | + FW_RI_RES_WR_FBMIN_V(2) | + FW_RI_RES_WR_FBMAX_V(2) | + FW_RI_RES_WR_CIDXFTHRESHO_V(0) | + FW_RI_RES_WR_CIDXFTHRESH_V(0) | + FW_RI_RES_WR_EQSIZE_V(eqsize)); res->u.sqrq.eqid = cpu_to_be32(wq->sq.qid); res->u.sqrq.eqaddr = cpu_to_be64(wq->sq.dma_addr); res++; @@ -312,18 +312,18 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, eqsize = wq->rq.size * T4_RQ_NUM_SLOTS + rdev->hw_queue.t4_eq_status_entries; res->u.sqrq.fetchszm_to_iqid = cpu_to_be32( - 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 */ - V_FW_RI_RES_WR_IQID(rcq->cqid)); + FW_RI_RES_WR_HOSTFCMODE_V(0) | /* no host cidx updates */ + FW_RI_RES_WR_CPRIO_V(0) | /* don't keep in chip cache */ + FW_RI_RES_WR_PCIECHN_V(0) | /* set by uP at ri_init time */ + FW_RI_RES_WR_IQID_V(rcq->cqid)); res->u.sqrq.dcaen_to_eqsize = cpu_to_be32( - V_FW_RI_RES_WR_DCAEN(0) | - V_FW_RI_RES_WR_DCACPU(0) | - V_FW_RI_RES_WR_FBMIN(2) | - V_FW_RI_RES_WR_FBMAX(2) | - V_FW_RI_RES_WR_CIDXFTHRESHO(0) | - V_FW_RI_RES_WR_CIDXFTHRESH(0) | - V_FW_RI_RES_WR_EQSIZE(eqsize)); + FW_RI_RES_WR_DCAEN_V(0) | + FW_RI_RES_WR_DCACPU_V(0) | + FW_RI_RES_WR_FBMIN_V(2) | + FW_RI_RES_WR_FBMAX_V(2) | + FW_RI_RES_WR_CIDXFTHRESHO_V(0) | + FW_RI_RES_WR_CIDXFTHRESH_V(0) | + FW_RI_RES_WR_EQSIZE_V(eqsize)); res->u.sqrq.eqid = cpu_to_be32(wq->rq.qid); res->u.sqrq.eqaddr = cpu_to_be64(wq->rq.dma_addr); @@ -444,19 +444,19 @@ static int build_rdma_send(struct t4_sq *sq, union t4_wr *wqe, case IB_WR_SEND: if (wr->send_flags & IB_SEND_SOLICITED) wqe->send.sendop_pkd = cpu_to_be32( - V_FW_RI_SEND_WR_SENDOP(FW_RI_SEND_WITH_SE)); + FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_SE)); else wqe->send.sendop_pkd = cpu_to_be32( - V_FW_RI_SEND_WR_SENDOP(FW_RI_SEND)); + FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND)); wqe->send.stag_inv = 0; break; case IB_WR_SEND_WITH_INV: if (wr->send_flags & IB_SEND_SOLICITED) wqe->send.sendop_pkd = cpu_to_be32( - V_FW_RI_SEND_WR_SENDOP(FW_RI_SEND_WITH_SE_INV)); + FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_SE_INV)); else wqe->send.sendop_pkd = cpu_to_be32( - V_FW_RI_SEND_WR_SENDOP(FW_RI_SEND_WITH_INV)); + FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_INV)); wqe->send.stag_inv = cpu_to_be32(wr->ex.invalidate_rkey); break; @@ -1283,8 +1283,8 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp) wqe->u.init.type = FW_RI_TYPE_INIT; wqe->u.init.mpareqbit_p2ptype = - V_FW_RI_WR_MPAREQBIT(qhp->attr.mpa_attr.initiator) | - V_FW_RI_WR_P2PTYPE(qhp->attr.mpa_attr.p2p_type); + FW_RI_WR_MPAREQBIT_V(qhp->attr.mpa_attr.initiator) | + FW_RI_WR_P2PTYPE_V(qhp->attr.mpa_attr.p2p_type); wqe->u.init.mpa_attrs = FW_RI_MPA_IETF_ENABLE; if (qhp->attr.mpa_attr.recv_marker_enabled) wqe->u.init.mpa_attrs |= FW_RI_MPA_RX_MARKER_ENABLE; @@ -1776,7 +1776,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, if (mm5) { mm5->key = uresp.ma_sync_key; mm5->addr = (pci_resource_start(rhp->rdev.lldi.pdev, 0) - + A_PCIE_MA_SYNC) & PAGE_MASK; + + PCIE_MA_SYNC_A) & PAGE_MASK; mm5->len = PAGE_SIZE; insert_mmap(ucontext, mm5); } diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index c04e5134b30c..871cdcac7be2 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -41,7 +41,7 @@ #define T4_PAGESIZE_MASK 0xffff000 /* 4KB-128MB */ #define T4_STAG_UNSET 0xffffffff #define T4_FW_MAJ 0 -#define A_PCIE_MA_SYNC 0x30b4 +#define PCIE_MA_SYNC_A 0x30b4 struct t4_status_page { __be32 rsvd1; /* flit 0 - hw owns */ @@ -184,44 +184,44 @@ struct t4_cqe { /* macros for flit 0 of the cqe */ -#define S_CQE_QPID 12 -#define M_CQE_QPID 0xFFFFF -#define G_CQE_QPID(x) ((((x) >> S_CQE_QPID)) & M_CQE_QPID) -#define V_CQE_QPID(x) ((x)<> CQE_QPID_S)) & CQE_QPID_M) +#define CQE_QPID_V(x) ((x)<> S_CQE_SWCQE)) & M_CQE_SWCQE) -#define V_CQE_SWCQE(x) ((x)<> CQE_SWCQE_S)) & CQE_SWCQE_M) +#define CQE_SWCQE_V(x) ((x)<> S_CQE_STATUS)) & M_CQE_STATUS) -#define V_CQE_STATUS(x) ((x)<> CQE_STATUS_S)) & CQE_STATUS_M) +#define CQE_STATUS_V(x) ((x)<> S_CQE_TYPE)) & M_CQE_TYPE) -#define V_CQE_TYPE(x) ((x)<> CQE_TYPE_S)) & CQE_TYPE_M) +#define CQE_TYPE_V(x) ((x)<> S_CQE_OPCODE)) & M_CQE_OPCODE) -#define V_CQE_OPCODE(x) ((x)<> CQE_OPCODE_S)) & CQE_OPCODE_M) +#define CQE_OPCODE_V(x) ((x)<header))) -#define CQE_QPID(x) (G_CQE_QPID(be32_to_cpu((x)->header))) -#define CQE_TYPE(x) (G_CQE_TYPE(be32_to_cpu((x)->header))) +#define SW_CQE(x) (CQE_SWCQE_G(be32_to_cpu((x)->header))) +#define CQE_QPID(x) (CQE_QPID_G(be32_to_cpu((x)->header))) +#define CQE_TYPE(x) (CQE_TYPE_G(be32_to_cpu((x)->header))) #define SQ_TYPE(x) (CQE_TYPE((x))) #define RQ_TYPE(x) (!CQE_TYPE((x))) -#define CQE_STATUS(x) (G_CQE_STATUS(be32_to_cpu((x)->header))) -#define CQE_OPCODE(x) (G_CQE_OPCODE(be32_to_cpu((x)->header))) +#define CQE_STATUS(x) (CQE_STATUS_G(be32_to_cpu((x)->header))) +#define CQE_OPCODE(x) (CQE_OPCODE_G(be32_to_cpu((x)->header))) #define CQE_SEND_OPCODE(x)( \ - (G_CQE_OPCODE(be32_to_cpu((x)->header)) == FW_RI_SEND) || \ - (G_CQE_OPCODE(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_SE) || \ - (G_CQE_OPCODE(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_INV) || \ - (G_CQE_OPCODE(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_SE_INV)) + (CQE_OPCODE_G(be32_to_cpu((x)->header)) == FW_RI_SEND) || \ + (CQE_OPCODE_G(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_SE) || \ + (CQE_OPCODE_G(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_INV) || \ + (CQE_OPCODE_G(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_SE_INV)) #define CQE_LEN(x) (be32_to_cpu((x)->len)) @@ -237,25 +237,25 @@ struct t4_cqe { #define CQE_WRID_LOW(x) (be32_to_cpu((x)->u.gen.wrid_low)) /* macros for flit 3 of the cqe */ -#define S_CQE_GENBIT 63 -#define M_CQE_GENBIT 0x1 -#define G_CQE_GENBIT(x) (((x) >> S_CQE_GENBIT) & M_CQE_GENBIT) -#define V_CQE_GENBIT(x) ((x)<> CQE_GENBIT_S) & CQE_GENBIT_M) +#define CQE_GENBIT_V(x) ((x)<> S_CQE_OVFBIT)) & M_CQE_OVFBIT) +#define CQE_OVFBIT_S 62 +#define CQE_OVFBIT_M 0x1 +#define CQE_OVFBIT_G(x) ((((x) >> CQE_OVFBIT_S)) & CQE_OVFBIT_M) -#define S_CQE_IQTYPE 60 -#define M_CQE_IQTYPE 0x3 -#define G_CQE_IQTYPE(x) ((((x) >> S_CQE_IQTYPE)) & M_CQE_IQTYPE) +#define CQE_IQTYPE_S 60 +#define CQE_IQTYPE_M 0x3 +#define CQE_IQTYPE_G(x) ((((x) >> CQE_IQTYPE_S)) & CQE_IQTYPE_M) -#define M_CQE_TS 0x0fffffffffffffffULL -#define G_CQE_TS(x) ((x) & M_CQE_TS) +#define CQE_TS_M 0x0fffffffffffffffULL +#define CQE_TS_G(x) ((x) & CQE_TS_M) -#define CQE_OVFBIT(x) ((unsigned)G_CQE_OVFBIT(be64_to_cpu((x)->bits_type_ts))) -#define CQE_GENBIT(x) ((unsigned)G_CQE_GENBIT(be64_to_cpu((x)->bits_type_ts))) -#define CQE_TS(x) (G_CQE_TS(be64_to_cpu((x)->bits_type_ts))) +#define CQE_OVFBIT(x) ((unsigned)CQE_OVFBIT_G(be64_to_cpu((x)->bits_type_ts))) +#define CQE_GENBIT(x) ((unsigned)CQE_GENBIT_G(be64_to_cpu((x)->bits_type_ts))) +#define CQE_TS(x) (CQE_TS_G(be64_to_cpu((x)->bits_type_ts))) struct t4_swsqe { u64 wr_id; @@ -465,14 +465,14 @@ static inline void t4_ring_sq_db(struct t4_wq *wq, u16 inc, u8 t5, } else { PDBG("%s: DB wq->sq.pidx = %d\n", __func__, wq->sq.pidx); - writel(PIDX_T5(inc), wq->sq.udb); + writel(PIDX_T5_V(inc), wq->sq.udb); } /* Flush user doorbell area writes. */ wmb(); return; } - writel(QID(wq->sq.qid) | PIDX(inc), wq->db); + writel(QID_V(wq->sq.qid) | PIDX_V(inc), wq->db); } static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc, u8 t5, @@ -489,14 +489,14 @@ static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc, u8 t5, } else { PDBG("%s: DB wq->rq.pidx = %d\n", __func__, wq->rq.pidx); - writel(PIDX_T5(inc), wq->rq.udb); + writel(PIDX_T5_V(inc), wq->rq.udb); } /* Flush user doorbell area writes. */ wmb(); return; } - writel(QID(wq->rq.qid) | PIDX(inc), wq->db); + writel(QID_V(wq->rq.qid) | PIDX_V(inc), wq->db); } static inline int t4_wq_in_error(struct t4_wq *wq) @@ -561,14 +561,14 @@ static inline int t4_arm_cq(struct t4_cq *cq, int se) u32 val; set_bit(CQ_ARMED, &cq->flags); - while (cq->cidx_inc > CIDXINC_MASK) { - val = SEINTARM(0) | CIDXINC(CIDXINC_MASK) | TIMERREG(7) | - INGRESSQID(cq->cqid); + while (cq->cidx_inc > CIDXINC_M) { + val = SEINTARM_V(0) | CIDXINC_V(CIDXINC_M) | TIMERREG_V(7) | + INGRESSQID_V(cq->cqid); writel(val, cq->gts); - cq->cidx_inc -= CIDXINC_MASK; + cq->cidx_inc -= CIDXINC_M; } - val = SEINTARM(se) | CIDXINC(cq->cidx_inc) | TIMERREG(6) | - INGRESSQID(cq->cqid); + val = SEINTARM_V(se) | CIDXINC_V(cq->cidx_inc) | TIMERREG_V(6) | + INGRESSQID_V(cq->cqid); writel(val, cq->gts); cq->cidx_inc = 0; return 0; @@ -597,11 +597,11 @@ static inline void t4_swcq_consume(struct t4_cq *cq) static inline void t4_hwcq_consume(struct t4_cq *cq) { cq->bits_type_ts = cq->queue[cq->cidx].bits_type_ts; - if (++cq->cidx_inc == (cq->size >> 4) || cq->cidx_inc == CIDXINC_MASK) { + if (++cq->cidx_inc == (cq->size >> 4) || cq->cidx_inc == CIDXINC_M) { u32 val; - val = SEINTARM(0) | CIDXINC(cq->cidx_inc) | TIMERREG(7) | - INGRESSQID(cq->cqid); + val = SEINTARM_V(0) | CIDXINC_V(cq->cidx_inc) | TIMERREG_V(7) | + INGRESSQID_V(cq->cqid); writel(val, cq->gts); cq->cidx_inc = 0; } diff --git a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h index 5709e77faf7c..5e53327fc647 100644 --- a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h +++ b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h @@ -162,102 +162,102 @@ struct fw_ri_tpte { __be32 len_hi; }; -#define S_FW_RI_TPTE_VALID 31 -#define M_FW_RI_TPTE_VALID 0x1 -#define V_FW_RI_TPTE_VALID(x) ((x) << S_FW_RI_TPTE_VALID) -#define G_FW_RI_TPTE_VALID(x) \ - (((x) >> S_FW_RI_TPTE_VALID) & M_FW_RI_TPTE_VALID) -#define F_FW_RI_TPTE_VALID V_FW_RI_TPTE_VALID(1U) +#define FW_RI_TPTE_VALID_S 31 +#define FW_RI_TPTE_VALID_M 0x1 +#define FW_RI_TPTE_VALID_V(x) ((x) << FW_RI_TPTE_VALID_S) +#define FW_RI_TPTE_VALID_G(x) \ + (((x) >> FW_RI_TPTE_VALID_S) & FW_RI_TPTE_VALID_M) +#define FW_RI_TPTE_VALID_F FW_RI_TPTE_VALID_V(1U) -#define S_FW_RI_TPTE_STAGKEY 23 -#define M_FW_RI_TPTE_STAGKEY 0xff -#define V_FW_RI_TPTE_STAGKEY(x) ((x) << S_FW_RI_TPTE_STAGKEY) -#define G_FW_RI_TPTE_STAGKEY(x) \ - (((x) >> S_FW_RI_TPTE_STAGKEY) & M_FW_RI_TPTE_STAGKEY) +#define FW_RI_TPTE_STAGKEY_S 23 +#define FW_RI_TPTE_STAGKEY_M 0xff +#define FW_RI_TPTE_STAGKEY_V(x) ((x) << FW_RI_TPTE_STAGKEY_S) +#define FW_RI_TPTE_STAGKEY_G(x) \ + (((x) >> FW_RI_TPTE_STAGKEY_S) & FW_RI_TPTE_STAGKEY_M) -#define S_FW_RI_TPTE_STAGSTATE 22 -#define M_FW_RI_TPTE_STAGSTATE 0x1 -#define V_FW_RI_TPTE_STAGSTATE(x) ((x) << S_FW_RI_TPTE_STAGSTATE) -#define G_FW_RI_TPTE_STAGSTATE(x) \ - (((x) >> S_FW_RI_TPTE_STAGSTATE) & M_FW_RI_TPTE_STAGSTATE) -#define F_FW_RI_TPTE_STAGSTATE V_FW_RI_TPTE_STAGSTATE(1U) +#define FW_RI_TPTE_STAGSTATE_S 22 +#define FW_RI_TPTE_STAGSTATE_M 0x1 +#define FW_RI_TPTE_STAGSTATE_V(x) ((x) << FW_RI_TPTE_STAGSTATE_S) +#define FW_RI_TPTE_STAGSTATE_G(x) \ + (((x) >> FW_RI_TPTE_STAGSTATE_S) & FW_RI_TPTE_STAGSTATE_M) +#define FW_RI_TPTE_STAGSTATE_F FW_RI_TPTE_STAGSTATE_V(1U) -#define S_FW_RI_TPTE_STAGTYPE 20 -#define M_FW_RI_TPTE_STAGTYPE 0x3 -#define V_FW_RI_TPTE_STAGTYPE(x) ((x) << S_FW_RI_TPTE_STAGTYPE) -#define G_FW_RI_TPTE_STAGTYPE(x) \ - (((x) >> S_FW_RI_TPTE_STAGTYPE) & M_FW_RI_TPTE_STAGTYPE) +#define FW_RI_TPTE_STAGTYPE_S 20 +#define FW_RI_TPTE_STAGTYPE_M 0x3 +#define FW_RI_TPTE_STAGTYPE_V(x) ((x) << FW_RI_TPTE_STAGTYPE_S) +#define FW_RI_TPTE_STAGTYPE_G(x) \ + (((x) >> FW_RI_TPTE_STAGTYPE_S) & FW_RI_TPTE_STAGTYPE_M) -#define S_FW_RI_TPTE_PDID 0 -#define M_FW_RI_TPTE_PDID 0xfffff -#define V_FW_RI_TPTE_PDID(x) ((x) << S_FW_RI_TPTE_PDID) -#define G_FW_RI_TPTE_PDID(x) \ - (((x) >> S_FW_RI_TPTE_PDID) & M_FW_RI_TPTE_PDID) +#define FW_RI_TPTE_PDID_S 0 +#define FW_RI_TPTE_PDID_M 0xfffff +#define FW_RI_TPTE_PDID_V(x) ((x) << FW_RI_TPTE_PDID_S) +#define FW_RI_TPTE_PDID_G(x) \ + (((x) >> FW_RI_TPTE_PDID_S) & FW_RI_TPTE_PDID_M) -#define S_FW_RI_TPTE_PERM 28 -#define M_FW_RI_TPTE_PERM 0xf -#define V_FW_RI_TPTE_PERM(x) ((x) << S_FW_RI_TPTE_PERM) -#define G_FW_RI_TPTE_PERM(x) \ - (((x) >> S_FW_RI_TPTE_PERM) & M_FW_RI_TPTE_PERM) +#define FW_RI_TPTE_PERM_S 28 +#define FW_RI_TPTE_PERM_M 0xf +#define FW_RI_TPTE_PERM_V(x) ((x) << FW_RI_TPTE_PERM_S) +#define FW_RI_TPTE_PERM_G(x) \ + (((x) >> FW_RI_TPTE_PERM_S) & FW_RI_TPTE_PERM_M) -#define S_FW_RI_TPTE_REMINVDIS 27 -#define M_FW_RI_TPTE_REMINVDIS 0x1 -#define V_FW_RI_TPTE_REMINVDIS(x) ((x) << S_FW_RI_TPTE_REMINVDIS) -#define G_FW_RI_TPTE_REMINVDIS(x) \ - (((x) >> S_FW_RI_TPTE_REMINVDIS) & M_FW_RI_TPTE_REMINVDIS) -#define F_FW_RI_TPTE_REMINVDIS V_FW_RI_TPTE_REMINVDIS(1U) +#define FW_RI_TPTE_REMINVDIS_S 27 +#define FW_RI_TPTE_REMINVDIS_M 0x1 +#define FW_RI_TPTE_REMINVDIS_V(x) ((x) << FW_RI_TPTE_REMINVDIS_S) +#define FW_RI_TPTE_REMINVDIS_G(x) \ + (((x) >> FW_RI_TPTE_REMINVDIS_S) & FW_RI_TPTE_REMINVDIS_M) +#define FW_RI_TPTE_REMINVDIS_F FW_RI_TPTE_REMINVDIS_V(1U) -#define S_FW_RI_TPTE_ADDRTYPE 26 -#define M_FW_RI_TPTE_ADDRTYPE 1 -#define V_FW_RI_TPTE_ADDRTYPE(x) ((x) << S_FW_RI_TPTE_ADDRTYPE) -#define G_FW_RI_TPTE_ADDRTYPE(x) \ - (((x) >> S_FW_RI_TPTE_ADDRTYPE) & M_FW_RI_TPTE_ADDRTYPE) -#define F_FW_RI_TPTE_ADDRTYPE V_FW_RI_TPTE_ADDRTYPE(1U) +#define FW_RI_TPTE_ADDRTYPE_S 26 +#define FW_RI_TPTE_ADDRTYPE_M 1 +#define FW_RI_TPTE_ADDRTYPE_V(x) ((x) << FW_RI_TPTE_ADDRTYPE_S) +#define FW_RI_TPTE_ADDRTYPE_G(x) \ + (((x) >> FW_RI_TPTE_ADDRTYPE_S) & FW_RI_TPTE_ADDRTYPE_M) +#define FW_RI_TPTE_ADDRTYPE_F FW_RI_TPTE_ADDRTYPE_V(1U) -#define S_FW_RI_TPTE_MWBINDEN 25 -#define M_FW_RI_TPTE_MWBINDEN 0x1 -#define V_FW_RI_TPTE_MWBINDEN(x) ((x) << S_FW_RI_TPTE_MWBINDEN) -#define G_FW_RI_TPTE_MWBINDEN(x) \ - (((x) >> S_FW_RI_TPTE_MWBINDEN) & M_FW_RI_TPTE_MWBINDEN) -#define F_FW_RI_TPTE_MWBINDEN V_FW_RI_TPTE_MWBINDEN(1U) +#define FW_RI_TPTE_MWBINDEN_S 25 +#define FW_RI_TPTE_MWBINDEN_M 0x1 +#define FW_RI_TPTE_MWBINDEN_V(x) ((x) << FW_RI_TPTE_MWBINDEN_S) +#define FW_RI_TPTE_MWBINDEN_G(x) \ + (((x) >> FW_RI_TPTE_MWBINDEN_S) & FW_RI_TPTE_MWBINDEN_M) +#define FW_RI_TPTE_MWBINDEN_F FW_RI_TPTE_MWBINDEN_V(1U) -#define S_FW_RI_TPTE_PS 20 -#define M_FW_RI_TPTE_PS 0x1f -#define V_FW_RI_TPTE_PS(x) ((x) << S_FW_RI_TPTE_PS) -#define G_FW_RI_TPTE_PS(x) \ - (((x) >> S_FW_RI_TPTE_PS) & M_FW_RI_TPTE_PS) +#define FW_RI_TPTE_PS_S 20 +#define FW_RI_TPTE_PS_M 0x1f +#define FW_RI_TPTE_PS_V(x) ((x) << FW_RI_TPTE_PS_S) +#define FW_RI_TPTE_PS_G(x) \ + (((x) >> FW_RI_TPTE_PS_S) & FW_RI_TPTE_PS_M) -#define S_FW_RI_TPTE_QPID 0 -#define M_FW_RI_TPTE_QPID 0xfffff -#define V_FW_RI_TPTE_QPID(x) ((x) << S_FW_RI_TPTE_QPID) -#define G_FW_RI_TPTE_QPID(x) \ - (((x) >> S_FW_RI_TPTE_QPID) & M_FW_RI_TPTE_QPID) +#define FW_RI_TPTE_QPID_S 0 +#define FW_RI_TPTE_QPID_M 0xfffff +#define FW_RI_TPTE_QPID_V(x) ((x) << FW_RI_TPTE_QPID_S) +#define FW_RI_TPTE_QPID_G(x) \ + (((x) >> FW_RI_TPTE_QPID_S) & FW_RI_TPTE_QPID_M) -#define S_FW_RI_TPTE_NOSNOOP 30 -#define M_FW_RI_TPTE_NOSNOOP 0x1 -#define V_FW_RI_TPTE_NOSNOOP(x) ((x) << S_FW_RI_TPTE_NOSNOOP) -#define G_FW_RI_TPTE_NOSNOOP(x) \ - (((x) >> S_FW_RI_TPTE_NOSNOOP) & M_FW_RI_TPTE_NOSNOOP) -#define F_FW_RI_TPTE_NOSNOOP V_FW_RI_TPTE_NOSNOOP(1U) +#define FW_RI_TPTE_NOSNOOP_S 30 +#define FW_RI_TPTE_NOSNOOP_M 0x1 +#define FW_RI_TPTE_NOSNOOP_V(x) ((x) << FW_RI_TPTE_NOSNOOP_S) +#define FW_RI_TPTE_NOSNOOP_G(x) \ + (((x) >> FW_RI_TPTE_NOSNOOP_S) & FW_RI_TPTE_NOSNOOP_M) +#define FW_RI_TPTE_NOSNOOP_F FW_RI_TPTE_NOSNOOP_V(1U) -#define S_FW_RI_TPTE_PBLADDR 0 -#define M_FW_RI_TPTE_PBLADDR 0x1fffffff -#define V_FW_RI_TPTE_PBLADDR(x) ((x) << S_FW_RI_TPTE_PBLADDR) -#define G_FW_RI_TPTE_PBLADDR(x) \ - (((x) >> S_FW_RI_TPTE_PBLADDR) & M_FW_RI_TPTE_PBLADDR) +#define FW_RI_TPTE_PBLADDR_S 0 +#define FW_RI_TPTE_PBLADDR_M 0x1fffffff +#define FW_RI_TPTE_PBLADDR_V(x) ((x) << FW_RI_TPTE_PBLADDR_S) +#define FW_RI_TPTE_PBLADDR_G(x) \ + (((x) >> FW_RI_TPTE_PBLADDR_S) & FW_RI_TPTE_PBLADDR_M) -#define S_FW_RI_TPTE_DCA 24 -#define M_FW_RI_TPTE_DCA 0x1f -#define V_FW_RI_TPTE_DCA(x) ((x) << S_FW_RI_TPTE_DCA) -#define G_FW_RI_TPTE_DCA(x) \ - (((x) >> S_FW_RI_TPTE_DCA) & M_FW_RI_TPTE_DCA) +#define FW_RI_TPTE_DCA_S 24 +#define FW_RI_TPTE_DCA_M 0x1f +#define FW_RI_TPTE_DCA_V(x) ((x) << FW_RI_TPTE_DCA_S) +#define FW_RI_TPTE_DCA_G(x) \ + (((x) >> FW_RI_TPTE_DCA_S) & FW_RI_TPTE_DCA_M) -#define S_FW_RI_TPTE_MWBCNT_PSTAG 0 -#define M_FW_RI_TPTE_MWBCNT_PSTAG 0xffffff -#define V_FW_RI_TPTE_MWBCNT_PSTAT(x) \ - ((x) << S_FW_RI_TPTE_MWBCNT_PSTAG) -#define G_FW_RI_TPTE_MWBCNT_PSTAG(x) \ - (((x) >> S_FW_RI_TPTE_MWBCNT_PSTAG) & M_FW_RI_TPTE_MWBCNT_PSTAG) +#define FW_RI_TPTE_MWBCNT_PSTAG_S 0 +#define FW_RI_TPTE_MWBCNT_PSTAG_M 0xffffff +#define FW_RI_TPTE_MWBCNT_PSTAT_V(x) \ + ((x) << FW_RI_TPTE_MWBCNT_PSTAG_S) +#define FW_RI_TPTE_MWBCNT_PSTAG_G(x) \ + (((x) >> FW_RI_TPTE_MWBCNT_PSTAG_S) & FW_RI_TPTE_MWBCNT_PSTAG_M) enum fw_ri_res_type { FW_RI_RES_TYPE_SQ, @@ -308,222 +308,222 @@ struct fw_ri_res_wr { #endif }; -#define S_FW_RI_RES_WR_NRES 0 -#define M_FW_RI_RES_WR_NRES 0xff -#define V_FW_RI_RES_WR_NRES(x) ((x) << S_FW_RI_RES_WR_NRES) -#define G_FW_RI_RES_WR_NRES(x) \ - (((x) >> S_FW_RI_RES_WR_NRES) & M_FW_RI_RES_WR_NRES) +#define FW_RI_RES_WR_NRES_S 0 +#define FW_RI_RES_WR_NRES_M 0xff +#define FW_RI_RES_WR_NRES_V(x) ((x) << FW_RI_RES_WR_NRES_S) +#define FW_RI_RES_WR_NRES_G(x) \ + (((x) >> FW_RI_RES_WR_NRES_S) & FW_RI_RES_WR_NRES_M) -#define S_FW_RI_RES_WR_FETCHSZM 26 -#define M_FW_RI_RES_WR_FETCHSZM 0x1 -#define V_FW_RI_RES_WR_FETCHSZM(x) ((x) << S_FW_RI_RES_WR_FETCHSZM) -#define G_FW_RI_RES_WR_FETCHSZM(x) \ - (((x) >> S_FW_RI_RES_WR_FETCHSZM) & M_FW_RI_RES_WR_FETCHSZM) -#define F_FW_RI_RES_WR_FETCHSZM V_FW_RI_RES_WR_FETCHSZM(1U) +#define FW_RI_RES_WR_FETCHSZM_S 26 +#define FW_RI_RES_WR_FETCHSZM_M 0x1 +#define FW_RI_RES_WR_FETCHSZM_V(x) ((x) << FW_RI_RES_WR_FETCHSZM_S) +#define FW_RI_RES_WR_FETCHSZM_G(x) \ + (((x) >> FW_RI_RES_WR_FETCHSZM_S) & FW_RI_RES_WR_FETCHSZM_M) +#define FW_RI_RES_WR_FETCHSZM_F FW_RI_RES_WR_FETCHSZM_V(1U) -#define S_FW_RI_RES_WR_STATUSPGNS 25 -#define M_FW_RI_RES_WR_STATUSPGNS 0x1 -#define V_FW_RI_RES_WR_STATUSPGNS(x) ((x) << S_FW_RI_RES_WR_STATUSPGNS) -#define G_FW_RI_RES_WR_STATUSPGNS(x) \ - (((x) >> S_FW_RI_RES_WR_STATUSPGNS) & M_FW_RI_RES_WR_STATUSPGNS) -#define F_FW_RI_RES_WR_STATUSPGNS V_FW_RI_RES_WR_STATUSPGNS(1U) +#define FW_RI_RES_WR_STATUSPGNS_S 25 +#define FW_RI_RES_WR_STATUSPGNS_M 0x1 +#define FW_RI_RES_WR_STATUSPGNS_V(x) ((x) << FW_RI_RES_WR_STATUSPGNS_S) +#define FW_RI_RES_WR_STATUSPGNS_G(x) \ + (((x) >> FW_RI_RES_WR_STATUSPGNS_S) & FW_RI_RES_WR_STATUSPGNS_M) +#define FW_RI_RES_WR_STATUSPGNS_F FW_RI_RES_WR_STATUSPGNS_V(1U) -#define S_FW_RI_RES_WR_STATUSPGRO 24 -#define M_FW_RI_RES_WR_STATUSPGRO 0x1 -#define V_FW_RI_RES_WR_STATUSPGRO(x) ((x) << S_FW_RI_RES_WR_STATUSPGRO) -#define G_FW_RI_RES_WR_STATUSPGRO(x) \ - (((x) >> S_FW_RI_RES_WR_STATUSPGRO) & M_FW_RI_RES_WR_STATUSPGRO) -#define F_FW_RI_RES_WR_STATUSPGRO V_FW_RI_RES_WR_STATUSPGRO(1U) +#define FW_RI_RES_WR_STATUSPGRO_S 24 +#define FW_RI_RES_WR_STATUSPGRO_M 0x1 +#define FW_RI_RES_WR_STATUSPGRO_V(x) ((x) << FW_RI_RES_WR_STATUSPGRO_S) +#define FW_RI_RES_WR_STATUSPGRO_G(x) \ + (((x) >> FW_RI_RES_WR_STATUSPGRO_S) & FW_RI_RES_WR_STATUSPGRO_M) +#define FW_RI_RES_WR_STATUSPGRO_F FW_RI_RES_WR_STATUSPGRO_V(1U) -#define S_FW_RI_RES_WR_FETCHNS 23 -#define M_FW_RI_RES_WR_FETCHNS 0x1 -#define V_FW_RI_RES_WR_FETCHNS(x) ((x) << S_FW_RI_RES_WR_FETCHNS) -#define G_FW_RI_RES_WR_FETCHNS(x) \ - (((x) >> S_FW_RI_RES_WR_FETCHNS) & M_FW_RI_RES_WR_FETCHNS) -#define F_FW_RI_RES_WR_FETCHNS V_FW_RI_RES_WR_FETCHNS(1U) +#define FW_RI_RES_WR_FETCHNS_S 23 +#define FW_RI_RES_WR_FETCHNS_M 0x1 +#define FW_RI_RES_WR_FETCHNS_V(x) ((x) << FW_RI_RES_WR_FETCHNS_S) +#define FW_RI_RES_WR_FETCHNS_G(x) \ + (((x) >> FW_RI_RES_WR_FETCHNS_S) & FW_RI_RES_WR_FETCHNS_M) +#define FW_RI_RES_WR_FETCHNS_F FW_RI_RES_WR_FETCHNS_V(1U) -#define S_FW_RI_RES_WR_FETCHRO 22 -#define M_FW_RI_RES_WR_FETCHRO 0x1 -#define V_FW_RI_RES_WR_FETCHRO(x) ((x) << S_FW_RI_RES_WR_FETCHRO) -#define G_FW_RI_RES_WR_FETCHRO(x) \ - (((x) >> S_FW_RI_RES_WR_FETCHRO) & M_FW_RI_RES_WR_FETCHRO) -#define F_FW_RI_RES_WR_FETCHRO V_FW_RI_RES_WR_FETCHRO(1U) +#define FW_RI_RES_WR_FETCHRO_S 22 +#define FW_RI_RES_WR_FETCHRO_M 0x1 +#define FW_RI_RES_WR_FETCHRO_V(x) ((x) << FW_RI_RES_WR_FETCHRO_S) +#define FW_RI_RES_WR_FETCHRO_G(x) \ + (((x) >> FW_RI_RES_WR_FETCHRO_S) & FW_RI_RES_WR_FETCHRO_M) +#define FW_RI_RES_WR_FETCHRO_F FW_RI_RES_WR_FETCHRO_V(1U) -#define S_FW_RI_RES_WR_HOSTFCMODE 20 -#define M_FW_RI_RES_WR_HOSTFCMODE 0x3 -#define V_FW_RI_RES_WR_HOSTFCMODE(x) ((x) << S_FW_RI_RES_WR_HOSTFCMODE) -#define G_FW_RI_RES_WR_HOSTFCMODE(x) \ - (((x) >> S_FW_RI_RES_WR_HOSTFCMODE) & M_FW_RI_RES_WR_HOSTFCMODE) +#define FW_RI_RES_WR_HOSTFCMODE_S 20 +#define FW_RI_RES_WR_HOSTFCMODE_M 0x3 +#define FW_RI_RES_WR_HOSTFCMODE_V(x) ((x) << FW_RI_RES_WR_HOSTFCMODE_S) +#define FW_RI_RES_WR_HOSTFCMODE_G(x) \ + (((x) >> FW_RI_RES_WR_HOSTFCMODE_S) & FW_RI_RES_WR_HOSTFCMODE_M) -#define S_FW_RI_RES_WR_CPRIO 19 -#define M_FW_RI_RES_WR_CPRIO 0x1 -#define V_FW_RI_RES_WR_CPRIO(x) ((x) << S_FW_RI_RES_WR_CPRIO) -#define G_FW_RI_RES_WR_CPRIO(x) \ - (((x) >> S_FW_RI_RES_WR_CPRIO) & M_FW_RI_RES_WR_CPRIO) -#define F_FW_RI_RES_WR_CPRIO V_FW_RI_RES_WR_CPRIO(1U) +#define FW_RI_RES_WR_CPRIO_S 19 +#define FW_RI_RES_WR_CPRIO_M 0x1 +#define FW_RI_RES_WR_CPRIO_V(x) ((x) << FW_RI_RES_WR_CPRIO_S) +#define FW_RI_RES_WR_CPRIO_G(x) \ + (((x) >> FW_RI_RES_WR_CPRIO_S) & FW_RI_RES_WR_CPRIO_M) +#define FW_RI_RES_WR_CPRIO_F FW_RI_RES_WR_CPRIO_V(1U) -#define S_FW_RI_RES_WR_ONCHIP 18 -#define M_FW_RI_RES_WR_ONCHIP 0x1 -#define V_FW_RI_RES_WR_ONCHIP(x) ((x) << S_FW_RI_RES_WR_ONCHIP) -#define G_FW_RI_RES_WR_ONCHIP(x) \ - (((x) >> S_FW_RI_RES_WR_ONCHIP) & M_FW_RI_RES_WR_ONCHIP) -#define F_FW_RI_RES_WR_ONCHIP V_FW_RI_RES_WR_ONCHIP(1U) +#define FW_RI_RES_WR_ONCHIP_S 18 +#define FW_RI_RES_WR_ONCHIP_M 0x1 +#define FW_RI_RES_WR_ONCHIP_V(x) ((x) << FW_RI_RES_WR_ONCHIP_S) +#define FW_RI_RES_WR_ONCHIP_G(x) \ + (((x) >> FW_RI_RES_WR_ONCHIP_S) & FW_RI_RES_WR_ONCHIP_M) +#define FW_RI_RES_WR_ONCHIP_F FW_RI_RES_WR_ONCHIP_V(1U) -#define S_FW_RI_RES_WR_PCIECHN 16 -#define M_FW_RI_RES_WR_PCIECHN 0x3 -#define V_FW_RI_RES_WR_PCIECHN(x) ((x) << S_FW_RI_RES_WR_PCIECHN) -#define G_FW_RI_RES_WR_PCIECHN(x) \ - (((x) >> S_FW_RI_RES_WR_PCIECHN) & M_FW_RI_RES_WR_PCIECHN) +#define FW_RI_RES_WR_PCIECHN_S 16 +#define FW_RI_RES_WR_PCIECHN_M 0x3 +#define FW_RI_RES_WR_PCIECHN_V(x) ((x) << FW_RI_RES_WR_PCIECHN_S) +#define FW_RI_RES_WR_PCIECHN_G(x) \ + (((x) >> FW_RI_RES_WR_PCIECHN_S) & FW_RI_RES_WR_PCIECHN_M) -#define S_FW_RI_RES_WR_IQID 0 -#define M_FW_RI_RES_WR_IQID 0xffff -#define V_FW_RI_RES_WR_IQID(x) ((x) << S_FW_RI_RES_WR_IQID) -#define G_FW_RI_RES_WR_IQID(x) \ - (((x) >> S_FW_RI_RES_WR_IQID) & M_FW_RI_RES_WR_IQID) +#define FW_RI_RES_WR_IQID_S 0 +#define FW_RI_RES_WR_IQID_M 0xffff +#define FW_RI_RES_WR_IQID_V(x) ((x) << FW_RI_RES_WR_IQID_S) +#define FW_RI_RES_WR_IQID_G(x) \ + (((x) >> FW_RI_RES_WR_IQID_S) & FW_RI_RES_WR_IQID_M) -#define S_FW_RI_RES_WR_DCAEN 31 -#define M_FW_RI_RES_WR_DCAEN 0x1 -#define V_FW_RI_RES_WR_DCAEN(x) ((x) << S_FW_RI_RES_WR_DCAEN) -#define G_FW_RI_RES_WR_DCAEN(x) \ - (((x) >> S_FW_RI_RES_WR_DCAEN) & M_FW_RI_RES_WR_DCAEN) -#define F_FW_RI_RES_WR_DCAEN V_FW_RI_RES_WR_DCAEN(1U) +#define FW_RI_RES_WR_DCAEN_S 31 +#define FW_RI_RES_WR_DCAEN_M 0x1 +#define FW_RI_RES_WR_DCAEN_V(x) ((x) << FW_RI_RES_WR_DCAEN_S) +#define FW_RI_RES_WR_DCAEN_G(x) \ + (((x) >> FW_RI_RES_WR_DCAEN_S) & FW_RI_RES_WR_DCAEN_M) +#define FW_RI_RES_WR_DCAEN_F FW_RI_RES_WR_DCAEN_V(1U) -#define S_FW_RI_RES_WR_DCACPU 26 -#define M_FW_RI_RES_WR_DCACPU 0x1f -#define V_FW_RI_RES_WR_DCACPU(x) ((x) << S_FW_RI_RES_WR_DCACPU) -#define G_FW_RI_RES_WR_DCACPU(x) \ - (((x) >> S_FW_RI_RES_WR_DCACPU) & M_FW_RI_RES_WR_DCACPU) +#define FW_RI_RES_WR_DCACPU_S 26 +#define FW_RI_RES_WR_DCACPU_M 0x1f +#define FW_RI_RES_WR_DCACPU_V(x) ((x) << FW_RI_RES_WR_DCACPU_S) +#define FW_RI_RES_WR_DCACPU_G(x) \ + (((x) >> FW_RI_RES_WR_DCACPU_S) & FW_RI_RES_WR_DCACPU_M) -#define S_FW_RI_RES_WR_FBMIN 23 -#define M_FW_RI_RES_WR_FBMIN 0x7 -#define V_FW_RI_RES_WR_FBMIN(x) ((x) << S_FW_RI_RES_WR_FBMIN) -#define G_FW_RI_RES_WR_FBMIN(x) \ - (((x) >> S_FW_RI_RES_WR_FBMIN) & M_FW_RI_RES_WR_FBMIN) +#define FW_RI_RES_WR_FBMIN_S 23 +#define FW_RI_RES_WR_FBMIN_M 0x7 +#define FW_RI_RES_WR_FBMIN_V(x) ((x) << FW_RI_RES_WR_FBMIN_S) +#define FW_RI_RES_WR_FBMIN_G(x) \ + (((x) >> FW_RI_RES_WR_FBMIN_S) & FW_RI_RES_WR_FBMIN_M) -#define S_FW_RI_RES_WR_FBMAX 20 -#define M_FW_RI_RES_WR_FBMAX 0x7 -#define V_FW_RI_RES_WR_FBMAX(x) ((x) << S_FW_RI_RES_WR_FBMAX) -#define G_FW_RI_RES_WR_FBMAX(x) \ - (((x) >> S_FW_RI_RES_WR_FBMAX) & M_FW_RI_RES_WR_FBMAX) +#define FW_RI_RES_WR_FBMAX_S 20 +#define FW_RI_RES_WR_FBMAX_M 0x7 +#define FW_RI_RES_WR_FBMAX_V(x) ((x) << FW_RI_RES_WR_FBMAX_S) +#define FW_RI_RES_WR_FBMAX_G(x) \ + (((x) >> FW_RI_RES_WR_FBMAX_S) & FW_RI_RES_WR_FBMAX_M) -#define S_FW_RI_RES_WR_CIDXFTHRESHO 19 -#define M_FW_RI_RES_WR_CIDXFTHRESHO 0x1 -#define V_FW_RI_RES_WR_CIDXFTHRESHO(x) ((x) << S_FW_RI_RES_WR_CIDXFTHRESHO) -#define G_FW_RI_RES_WR_CIDXFTHRESHO(x) \ - (((x) >> S_FW_RI_RES_WR_CIDXFTHRESHO) & M_FW_RI_RES_WR_CIDXFTHRESHO) -#define F_FW_RI_RES_WR_CIDXFTHRESHO V_FW_RI_RES_WR_CIDXFTHRESHO(1U) +#define FW_RI_RES_WR_CIDXFTHRESHO_S 19 +#define FW_RI_RES_WR_CIDXFTHRESHO_M 0x1 +#define FW_RI_RES_WR_CIDXFTHRESHO_V(x) ((x) << FW_RI_RES_WR_CIDXFTHRESHO_S) +#define FW_RI_RES_WR_CIDXFTHRESHO_G(x) \ + (((x) >> FW_RI_RES_WR_CIDXFTHRESHO_S) & FW_RI_RES_WR_CIDXFTHRESHO_M) +#define FW_RI_RES_WR_CIDXFTHRESHO_F FW_RI_RES_WR_CIDXFTHRESHO_V(1U) -#define S_FW_RI_RES_WR_CIDXFTHRESH 16 -#define M_FW_RI_RES_WR_CIDXFTHRESH 0x7 -#define V_FW_RI_RES_WR_CIDXFTHRESH(x) ((x) << S_FW_RI_RES_WR_CIDXFTHRESH) -#define G_FW_RI_RES_WR_CIDXFTHRESH(x) \ - (((x) >> S_FW_RI_RES_WR_CIDXFTHRESH) & M_FW_RI_RES_WR_CIDXFTHRESH) +#define FW_RI_RES_WR_CIDXFTHRESH_S 16 +#define FW_RI_RES_WR_CIDXFTHRESH_M 0x7 +#define FW_RI_RES_WR_CIDXFTHRESH_V(x) ((x) << FW_RI_RES_WR_CIDXFTHRESH_S) +#define FW_RI_RES_WR_CIDXFTHRESH_G(x) \ + (((x) >> FW_RI_RES_WR_CIDXFTHRESH_S) & FW_RI_RES_WR_CIDXFTHRESH_M) -#define S_FW_RI_RES_WR_EQSIZE 0 -#define M_FW_RI_RES_WR_EQSIZE 0xffff -#define V_FW_RI_RES_WR_EQSIZE(x) ((x) << S_FW_RI_RES_WR_EQSIZE) -#define G_FW_RI_RES_WR_EQSIZE(x) \ - (((x) >> S_FW_RI_RES_WR_EQSIZE) & M_FW_RI_RES_WR_EQSIZE) +#define FW_RI_RES_WR_EQSIZE_S 0 +#define FW_RI_RES_WR_EQSIZE_M 0xffff +#define FW_RI_RES_WR_EQSIZE_V(x) ((x) << FW_RI_RES_WR_EQSIZE_S) +#define FW_RI_RES_WR_EQSIZE_G(x) \ + (((x) >> FW_RI_RES_WR_EQSIZE_S) & FW_RI_RES_WR_EQSIZE_M) -#define S_FW_RI_RES_WR_IQANDST 15 -#define M_FW_RI_RES_WR_IQANDST 0x1 -#define V_FW_RI_RES_WR_IQANDST(x) ((x) << S_FW_RI_RES_WR_IQANDST) -#define G_FW_RI_RES_WR_IQANDST(x) \ - (((x) >> S_FW_RI_RES_WR_IQANDST) & M_FW_RI_RES_WR_IQANDST) -#define F_FW_RI_RES_WR_IQANDST V_FW_RI_RES_WR_IQANDST(1U) +#define FW_RI_RES_WR_IQANDST_S 15 +#define FW_RI_RES_WR_IQANDST_M 0x1 +#define FW_RI_RES_WR_IQANDST_V(x) ((x) << FW_RI_RES_WR_IQANDST_S) +#define FW_RI_RES_WR_IQANDST_G(x) \ + (((x) >> FW_RI_RES_WR_IQANDST_S) & FW_RI_RES_WR_IQANDST_M) +#define FW_RI_RES_WR_IQANDST_F FW_RI_RES_WR_IQANDST_V(1U) -#define S_FW_RI_RES_WR_IQANUS 14 -#define M_FW_RI_RES_WR_IQANUS 0x1 -#define V_FW_RI_RES_WR_IQANUS(x) ((x) << S_FW_RI_RES_WR_IQANUS) -#define G_FW_RI_RES_WR_IQANUS(x) \ - (((x) >> S_FW_RI_RES_WR_IQANUS) & M_FW_RI_RES_WR_IQANUS) -#define F_FW_RI_RES_WR_IQANUS V_FW_RI_RES_WR_IQANUS(1U) +#define FW_RI_RES_WR_IQANUS_S 14 +#define FW_RI_RES_WR_IQANUS_M 0x1 +#define FW_RI_RES_WR_IQANUS_V(x) ((x) << FW_RI_RES_WR_IQANUS_S) +#define FW_RI_RES_WR_IQANUS_G(x) \ + (((x) >> FW_RI_RES_WR_IQANUS_S) & FW_RI_RES_WR_IQANUS_M) +#define FW_RI_RES_WR_IQANUS_F FW_RI_RES_WR_IQANUS_V(1U) -#define S_FW_RI_RES_WR_IQANUD 12 -#define M_FW_RI_RES_WR_IQANUD 0x3 -#define V_FW_RI_RES_WR_IQANUD(x) ((x) << S_FW_RI_RES_WR_IQANUD) -#define G_FW_RI_RES_WR_IQANUD(x) \ - (((x) >> S_FW_RI_RES_WR_IQANUD) & M_FW_RI_RES_WR_IQANUD) +#define FW_RI_RES_WR_IQANUD_S 12 +#define FW_RI_RES_WR_IQANUD_M 0x3 +#define FW_RI_RES_WR_IQANUD_V(x) ((x) << FW_RI_RES_WR_IQANUD_S) +#define FW_RI_RES_WR_IQANUD_G(x) \ + (((x) >> FW_RI_RES_WR_IQANUD_S) & FW_RI_RES_WR_IQANUD_M) -#define S_FW_RI_RES_WR_IQANDSTINDEX 0 -#define M_FW_RI_RES_WR_IQANDSTINDEX 0xfff -#define V_FW_RI_RES_WR_IQANDSTINDEX(x) ((x) << S_FW_RI_RES_WR_IQANDSTINDEX) -#define G_FW_RI_RES_WR_IQANDSTINDEX(x) \ - (((x) >> S_FW_RI_RES_WR_IQANDSTINDEX) & M_FW_RI_RES_WR_IQANDSTINDEX) +#define FW_RI_RES_WR_IQANDSTINDEX_S 0 +#define FW_RI_RES_WR_IQANDSTINDEX_M 0xfff +#define FW_RI_RES_WR_IQANDSTINDEX_V(x) ((x) << FW_RI_RES_WR_IQANDSTINDEX_S) +#define FW_RI_RES_WR_IQANDSTINDEX_G(x) \ + (((x) >> FW_RI_RES_WR_IQANDSTINDEX_S) & FW_RI_RES_WR_IQANDSTINDEX_M) -#define S_FW_RI_RES_WR_IQDROPRSS 15 -#define M_FW_RI_RES_WR_IQDROPRSS 0x1 -#define V_FW_RI_RES_WR_IQDROPRSS(x) ((x) << S_FW_RI_RES_WR_IQDROPRSS) -#define G_FW_RI_RES_WR_IQDROPRSS(x) \ - (((x) >> S_FW_RI_RES_WR_IQDROPRSS) & M_FW_RI_RES_WR_IQDROPRSS) -#define F_FW_RI_RES_WR_IQDROPRSS V_FW_RI_RES_WR_IQDROPRSS(1U) +#define FW_RI_RES_WR_IQDROPRSS_S 15 +#define FW_RI_RES_WR_IQDROPRSS_M 0x1 +#define FW_RI_RES_WR_IQDROPRSS_V(x) ((x) << FW_RI_RES_WR_IQDROPRSS_S) +#define FW_RI_RES_WR_IQDROPRSS_G(x) \ + (((x) >> FW_RI_RES_WR_IQDROPRSS_S) & FW_RI_RES_WR_IQDROPRSS_M) +#define FW_RI_RES_WR_IQDROPRSS_F FW_RI_RES_WR_IQDROPRSS_V(1U) -#define S_FW_RI_RES_WR_IQGTSMODE 14 -#define M_FW_RI_RES_WR_IQGTSMODE 0x1 -#define V_FW_RI_RES_WR_IQGTSMODE(x) ((x) << S_FW_RI_RES_WR_IQGTSMODE) -#define G_FW_RI_RES_WR_IQGTSMODE(x) \ - (((x) >> S_FW_RI_RES_WR_IQGTSMODE) & M_FW_RI_RES_WR_IQGTSMODE) -#define F_FW_RI_RES_WR_IQGTSMODE V_FW_RI_RES_WR_IQGTSMODE(1U) +#define FW_RI_RES_WR_IQGTSMODE_S 14 +#define FW_RI_RES_WR_IQGTSMODE_M 0x1 +#define FW_RI_RES_WR_IQGTSMODE_V(x) ((x) << FW_RI_RES_WR_IQGTSMODE_S) +#define FW_RI_RES_WR_IQGTSMODE_G(x) \ + (((x) >> FW_RI_RES_WR_IQGTSMODE_S) & FW_RI_RES_WR_IQGTSMODE_M) +#define FW_RI_RES_WR_IQGTSMODE_F FW_RI_RES_WR_IQGTSMODE_V(1U) -#define S_FW_RI_RES_WR_IQPCIECH 12 -#define M_FW_RI_RES_WR_IQPCIECH 0x3 -#define V_FW_RI_RES_WR_IQPCIECH(x) ((x) << S_FW_RI_RES_WR_IQPCIECH) -#define G_FW_RI_RES_WR_IQPCIECH(x) \ - (((x) >> S_FW_RI_RES_WR_IQPCIECH) & M_FW_RI_RES_WR_IQPCIECH) +#define FW_RI_RES_WR_IQPCIECH_S 12 +#define FW_RI_RES_WR_IQPCIECH_M 0x3 +#define FW_RI_RES_WR_IQPCIECH_V(x) ((x) << FW_RI_RES_WR_IQPCIECH_S) +#define FW_RI_RES_WR_IQPCIECH_G(x) \ + (((x) >> FW_RI_RES_WR_IQPCIECH_S) & FW_RI_RES_WR_IQPCIECH_M) -#define S_FW_RI_RES_WR_IQDCAEN 11 -#define M_FW_RI_RES_WR_IQDCAEN 0x1 -#define V_FW_RI_RES_WR_IQDCAEN(x) ((x) << S_FW_RI_RES_WR_IQDCAEN) -#define G_FW_RI_RES_WR_IQDCAEN(x) \ - (((x) >> S_FW_RI_RES_WR_IQDCAEN) & M_FW_RI_RES_WR_IQDCAEN) -#define F_FW_RI_RES_WR_IQDCAEN V_FW_RI_RES_WR_IQDCAEN(1U) +#define FW_RI_RES_WR_IQDCAEN_S 11 +#define FW_RI_RES_WR_IQDCAEN_M 0x1 +#define FW_RI_RES_WR_IQDCAEN_V(x) ((x) << FW_RI_RES_WR_IQDCAEN_S) +#define FW_RI_RES_WR_IQDCAEN_G(x) \ + (((x) >> FW_RI_RES_WR_IQDCAEN_S) & FW_RI_RES_WR_IQDCAEN_M) +#define FW_RI_RES_WR_IQDCAEN_F FW_RI_RES_WR_IQDCAEN_V(1U) -#define S_FW_RI_RES_WR_IQDCACPU 6 -#define M_FW_RI_RES_WR_IQDCACPU 0x1f -#define V_FW_RI_RES_WR_IQDCACPU(x) ((x) << S_FW_RI_RES_WR_IQDCACPU) -#define G_FW_RI_RES_WR_IQDCACPU(x) \ - (((x) >> S_FW_RI_RES_WR_IQDCACPU) & M_FW_RI_RES_WR_IQDCACPU) +#define FW_RI_RES_WR_IQDCACPU_S 6 +#define FW_RI_RES_WR_IQDCACPU_M 0x1f +#define FW_RI_RES_WR_IQDCACPU_V(x) ((x) << FW_RI_RES_WR_IQDCACPU_S) +#define FW_RI_RES_WR_IQDCACPU_G(x) \ + (((x) >> FW_RI_RES_WR_IQDCACPU_S) & FW_RI_RES_WR_IQDCACPU_M) -#define S_FW_RI_RES_WR_IQINTCNTTHRESH 4 -#define M_FW_RI_RES_WR_IQINTCNTTHRESH 0x3 -#define V_FW_RI_RES_WR_IQINTCNTTHRESH(x) \ - ((x) << S_FW_RI_RES_WR_IQINTCNTTHRESH) -#define G_FW_RI_RES_WR_IQINTCNTTHRESH(x) \ - (((x) >> S_FW_RI_RES_WR_IQINTCNTTHRESH) & M_FW_RI_RES_WR_IQINTCNTTHRESH) +#define FW_RI_RES_WR_IQINTCNTTHRESH_S 4 +#define FW_RI_RES_WR_IQINTCNTTHRESH_M 0x3 +#define FW_RI_RES_WR_IQINTCNTTHRESH_V(x) \ + ((x) << FW_RI_RES_WR_IQINTCNTTHRESH_S) +#define FW_RI_RES_WR_IQINTCNTTHRESH_G(x) \ + (((x) >> FW_RI_RES_WR_IQINTCNTTHRESH_S) & FW_RI_RES_WR_IQINTCNTTHRESH_M) -#define S_FW_RI_RES_WR_IQO 3 -#define M_FW_RI_RES_WR_IQO 0x1 -#define V_FW_RI_RES_WR_IQO(x) ((x) << S_FW_RI_RES_WR_IQO) -#define G_FW_RI_RES_WR_IQO(x) \ - (((x) >> S_FW_RI_RES_WR_IQO) & M_FW_RI_RES_WR_IQO) -#define F_FW_RI_RES_WR_IQO V_FW_RI_RES_WR_IQO(1U) +#define FW_RI_RES_WR_IQO_S 3 +#define FW_RI_RES_WR_IQO_M 0x1 +#define FW_RI_RES_WR_IQO_V(x) ((x) << FW_RI_RES_WR_IQO_S) +#define FW_RI_RES_WR_IQO_G(x) \ + (((x) >> FW_RI_RES_WR_IQO_S) & FW_RI_RES_WR_IQO_M) +#define FW_RI_RES_WR_IQO_F FW_RI_RES_WR_IQO_V(1U) -#define S_FW_RI_RES_WR_IQCPRIO 2 -#define M_FW_RI_RES_WR_IQCPRIO 0x1 -#define V_FW_RI_RES_WR_IQCPRIO(x) ((x) << S_FW_RI_RES_WR_IQCPRIO) -#define G_FW_RI_RES_WR_IQCPRIO(x) \ - (((x) >> S_FW_RI_RES_WR_IQCPRIO) & M_FW_RI_RES_WR_IQCPRIO) -#define F_FW_RI_RES_WR_IQCPRIO V_FW_RI_RES_WR_IQCPRIO(1U) +#define FW_RI_RES_WR_IQCPRIO_S 2 +#define FW_RI_RES_WR_IQCPRIO_M 0x1 +#define FW_RI_RES_WR_IQCPRIO_V(x) ((x) << FW_RI_RES_WR_IQCPRIO_S) +#define FW_RI_RES_WR_IQCPRIO_G(x) \ + (((x) >> FW_RI_RES_WR_IQCPRIO_S) & FW_RI_RES_WR_IQCPRIO_M) +#define FW_RI_RES_WR_IQCPRIO_F FW_RI_RES_WR_IQCPRIO_V(1U) -#define S_FW_RI_RES_WR_IQESIZE 0 -#define M_FW_RI_RES_WR_IQESIZE 0x3 -#define V_FW_RI_RES_WR_IQESIZE(x) ((x) << S_FW_RI_RES_WR_IQESIZE) -#define G_FW_RI_RES_WR_IQESIZE(x) \ - (((x) >> S_FW_RI_RES_WR_IQESIZE) & M_FW_RI_RES_WR_IQESIZE) +#define FW_RI_RES_WR_IQESIZE_S 0 +#define FW_RI_RES_WR_IQESIZE_M 0x3 +#define FW_RI_RES_WR_IQESIZE_V(x) ((x) << FW_RI_RES_WR_IQESIZE_S) +#define FW_RI_RES_WR_IQESIZE_G(x) \ + (((x) >> FW_RI_RES_WR_IQESIZE_S) & FW_RI_RES_WR_IQESIZE_M) -#define S_FW_RI_RES_WR_IQNS 31 -#define M_FW_RI_RES_WR_IQNS 0x1 -#define V_FW_RI_RES_WR_IQNS(x) ((x) << S_FW_RI_RES_WR_IQNS) -#define G_FW_RI_RES_WR_IQNS(x) \ - (((x) >> S_FW_RI_RES_WR_IQNS) & M_FW_RI_RES_WR_IQNS) -#define F_FW_RI_RES_WR_IQNS V_FW_RI_RES_WR_IQNS(1U) +#define FW_RI_RES_WR_IQNS_S 31 +#define FW_RI_RES_WR_IQNS_M 0x1 +#define FW_RI_RES_WR_IQNS_V(x) ((x) << FW_RI_RES_WR_IQNS_S) +#define FW_RI_RES_WR_IQNS_G(x) \ + (((x) >> FW_RI_RES_WR_IQNS_S) & FW_RI_RES_WR_IQNS_M) +#define FW_RI_RES_WR_IQNS_F FW_RI_RES_WR_IQNS_V(1U) -#define S_FW_RI_RES_WR_IQRO 30 -#define M_FW_RI_RES_WR_IQRO 0x1 -#define V_FW_RI_RES_WR_IQRO(x) ((x) << S_FW_RI_RES_WR_IQRO) -#define G_FW_RI_RES_WR_IQRO(x) \ - (((x) >> S_FW_RI_RES_WR_IQRO) & M_FW_RI_RES_WR_IQRO) -#define F_FW_RI_RES_WR_IQRO V_FW_RI_RES_WR_IQRO(1U) +#define FW_RI_RES_WR_IQRO_S 30 +#define FW_RI_RES_WR_IQRO_M 0x1 +#define FW_RI_RES_WR_IQRO_V(x) ((x) << FW_RI_RES_WR_IQRO_S) +#define FW_RI_RES_WR_IQRO_G(x) \ + (((x) >> FW_RI_RES_WR_IQRO_S) & FW_RI_RES_WR_IQRO_M) +#define FW_RI_RES_WR_IQRO_F FW_RI_RES_WR_IQRO_V(1U) struct fw_ri_rdma_write_wr { __u8 opcode; @@ -562,11 +562,11 @@ struct fw_ri_send_wr { #endif }; -#define S_FW_RI_SEND_WR_SENDOP 0 -#define M_FW_RI_SEND_WR_SENDOP 0xf -#define V_FW_RI_SEND_WR_SENDOP(x) ((x) << S_FW_RI_SEND_WR_SENDOP) -#define G_FW_RI_SEND_WR_SENDOP(x) \ - (((x) >> S_FW_RI_SEND_WR_SENDOP) & M_FW_RI_SEND_WR_SENDOP) +#define FW_RI_SEND_WR_SENDOP_S 0 +#define FW_RI_SEND_WR_SENDOP_M 0xf +#define FW_RI_SEND_WR_SENDOP_V(x) ((x) << FW_RI_SEND_WR_SENDOP_S) +#define FW_RI_SEND_WR_SENDOP_G(x) \ + (((x) >> FW_RI_SEND_WR_SENDOP_S) & FW_RI_SEND_WR_SENDOP_M) struct fw_ri_rdma_read_wr { __u8 opcode; @@ -612,25 +612,25 @@ struct fw_ri_bind_mw_wr { __be64 r4; }; -#define S_FW_RI_BIND_MW_WR_QPBINDE 6 -#define M_FW_RI_BIND_MW_WR_QPBINDE 0x1 -#define V_FW_RI_BIND_MW_WR_QPBINDE(x) ((x) << S_FW_RI_BIND_MW_WR_QPBINDE) -#define G_FW_RI_BIND_MW_WR_QPBINDE(x) \ - (((x) >> S_FW_RI_BIND_MW_WR_QPBINDE) & M_FW_RI_BIND_MW_WR_QPBINDE) -#define F_FW_RI_BIND_MW_WR_QPBINDE V_FW_RI_BIND_MW_WR_QPBINDE(1U) +#define FW_RI_BIND_MW_WR_QPBINDE_S 6 +#define FW_RI_BIND_MW_WR_QPBINDE_M 0x1 +#define FW_RI_BIND_MW_WR_QPBINDE_V(x) ((x) << FW_RI_BIND_MW_WR_QPBINDE_S) +#define FW_RI_BIND_MW_WR_QPBINDE_G(x) \ + (((x) >> FW_RI_BIND_MW_WR_QPBINDE_S) & FW_RI_BIND_MW_WR_QPBINDE_M) +#define FW_RI_BIND_MW_WR_QPBINDE_F FW_RI_BIND_MW_WR_QPBINDE_V(1U) -#define S_FW_RI_BIND_MW_WR_NS 5 -#define M_FW_RI_BIND_MW_WR_NS 0x1 -#define V_FW_RI_BIND_MW_WR_NS(x) ((x) << S_FW_RI_BIND_MW_WR_NS) -#define G_FW_RI_BIND_MW_WR_NS(x) \ - (((x) >> S_FW_RI_BIND_MW_WR_NS) & M_FW_RI_BIND_MW_WR_NS) -#define F_FW_RI_BIND_MW_WR_NS V_FW_RI_BIND_MW_WR_NS(1U) +#define FW_RI_BIND_MW_WR_NS_S 5 +#define FW_RI_BIND_MW_WR_NS_M 0x1 +#define FW_RI_BIND_MW_WR_NS_V(x) ((x) << FW_RI_BIND_MW_WR_NS_S) +#define FW_RI_BIND_MW_WR_NS_G(x) \ + (((x) >> FW_RI_BIND_MW_WR_NS_S) & FW_RI_BIND_MW_WR_NS_M) +#define FW_RI_BIND_MW_WR_NS_F FW_RI_BIND_MW_WR_NS_V(1U) -#define S_FW_RI_BIND_MW_WR_DCACPU 0 -#define M_FW_RI_BIND_MW_WR_DCACPU 0x1f -#define V_FW_RI_BIND_MW_WR_DCACPU(x) ((x) << S_FW_RI_BIND_MW_WR_DCACPU) -#define G_FW_RI_BIND_MW_WR_DCACPU(x) \ - (((x) >> S_FW_RI_BIND_MW_WR_DCACPU) & M_FW_RI_BIND_MW_WR_DCACPU) +#define FW_RI_BIND_MW_WR_DCACPU_S 0 +#define FW_RI_BIND_MW_WR_DCACPU_M 0x1f +#define FW_RI_BIND_MW_WR_DCACPU_V(x) ((x) << FW_RI_BIND_MW_WR_DCACPU_S) +#define FW_RI_BIND_MW_WR_DCACPU_G(x) \ + (((x) >> FW_RI_BIND_MW_WR_DCACPU_S) & FW_RI_BIND_MW_WR_DCACPU_M) struct fw_ri_fr_nsmr_wr { __u8 opcode; @@ -649,25 +649,25 @@ struct fw_ri_fr_nsmr_wr { __be32 va_lo_fbo; }; -#define S_FW_RI_FR_NSMR_WR_QPBINDE 6 -#define M_FW_RI_FR_NSMR_WR_QPBINDE 0x1 -#define V_FW_RI_FR_NSMR_WR_QPBINDE(x) ((x) << S_FW_RI_FR_NSMR_WR_QPBINDE) -#define G_FW_RI_FR_NSMR_WR_QPBINDE(x) \ - (((x) >> S_FW_RI_FR_NSMR_WR_QPBINDE) & M_FW_RI_FR_NSMR_WR_QPBINDE) -#define F_FW_RI_FR_NSMR_WR_QPBINDE V_FW_RI_FR_NSMR_WR_QPBINDE(1U) +#define FW_RI_FR_NSMR_WR_QPBINDE_S 6 +#define FW_RI_FR_NSMR_WR_QPBINDE_M 0x1 +#define FW_RI_FR_NSMR_WR_QPBINDE_V(x) ((x) << FW_RI_FR_NSMR_WR_QPBINDE_S) +#define FW_RI_FR_NSMR_WR_QPBINDE_G(x) \ + (((x) >> FW_RI_FR_NSMR_WR_QPBINDE_S) & FW_RI_FR_NSMR_WR_QPBINDE_M) +#define FW_RI_FR_NSMR_WR_QPBINDE_F FW_RI_FR_NSMR_WR_QPBINDE_V(1U) -#define S_FW_RI_FR_NSMR_WR_NS 5 -#define M_FW_RI_FR_NSMR_WR_NS 0x1 -#define V_FW_RI_FR_NSMR_WR_NS(x) ((x) << S_FW_RI_FR_NSMR_WR_NS) -#define G_FW_RI_FR_NSMR_WR_NS(x) \ - (((x) >> S_FW_RI_FR_NSMR_WR_NS) & M_FW_RI_FR_NSMR_WR_NS) -#define F_FW_RI_FR_NSMR_WR_NS V_FW_RI_FR_NSMR_WR_NS(1U) +#define FW_RI_FR_NSMR_WR_NS_S 5 +#define FW_RI_FR_NSMR_WR_NS_M 0x1 +#define FW_RI_FR_NSMR_WR_NS_V(x) ((x) << FW_RI_FR_NSMR_WR_NS_S) +#define FW_RI_FR_NSMR_WR_NS_G(x) \ + (((x) >> FW_RI_FR_NSMR_WR_NS_S) & FW_RI_FR_NSMR_WR_NS_M) +#define FW_RI_FR_NSMR_WR_NS_F FW_RI_FR_NSMR_WR_NS_V(1U) -#define S_FW_RI_FR_NSMR_WR_DCACPU 0 -#define M_FW_RI_FR_NSMR_WR_DCACPU 0x1f -#define V_FW_RI_FR_NSMR_WR_DCACPU(x) ((x) << S_FW_RI_FR_NSMR_WR_DCACPU) -#define G_FW_RI_FR_NSMR_WR_DCACPU(x) \ - (((x) >> S_FW_RI_FR_NSMR_WR_DCACPU) & M_FW_RI_FR_NSMR_WR_DCACPU) +#define FW_RI_FR_NSMR_WR_DCACPU_S 0 +#define FW_RI_FR_NSMR_WR_DCACPU_M 0x1f +#define FW_RI_FR_NSMR_WR_DCACPU_V(x) ((x) << FW_RI_FR_NSMR_WR_DCACPU_S) +#define FW_RI_FR_NSMR_WR_DCACPU_G(x) \ + (((x) >> FW_RI_FR_NSMR_WR_DCACPU_S) & FW_RI_FR_NSMR_WR_DCACPU_M) struct fw_ri_inv_lstag_wr { __u8 opcode; @@ -740,18 +740,18 @@ struct fw_ri_wr { } u; }; -#define S_FW_RI_WR_MPAREQBIT 7 -#define M_FW_RI_WR_MPAREQBIT 0x1 -#define V_FW_RI_WR_MPAREQBIT(x) ((x) << S_FW_RI_WR_MPAREQBIT) -#define G_FW_RI_WR_MPAREQBIT(x) \ - (((x) >> S_FW_RI_WR_MPAREQBIT) & M_FW_RI_WR_MPAREQBIT) -#define F_FW_RI_WR_MPAREQBIT V_FW_RI_WR_MPAREQBIT(1U) +#define FW_RI_WR_MPAREQBIT_S 7 +#define FW_RI_WR_MPAREQBIT_M 0x1 +#define FW_RI_WR_MPAREQBIT_V(x) ((x) << FW_RI_WR_MPAREQBIT_S) +#define FW_RI_WR_MPAREQBIT_G(x) \ + (((x) >> FW_RI_WR_MPAREQBIT_S) & FW_RI_WR_MPAREQBIT_M) +#define FW_RI_WR_MPAREQBIT_F FW_RI_WR_MPAREQBIT_V(1U) -#define S_FW_RI_WR_P2PTYPE 0 -#define M_FW_RI_WR_P2PTYPE 0xf -#define V_FW_RI_WR_P2PTYPE(x) ((x) << S_FW_RI_WR_P2PTYPE) -#define G_FW_RI_WR_P2PTYPE(x) \ - (((x) >> S_FW_RI_WR_P2PTYPE) & M_FW_RI_WR_P2PTYPE) +#define FW_RI_WR_P2PTYPE_S 0 +#define FW_RI_WR_P2PTYPE_M 0xf +#define FW_RI_WR_P2PTYPE_V(x) ((x) << FW_RI_WR_P2PTYPE_S) +#define FW_RI_WR_P2PTYPE_G(x) \ + (((x) >> FW_RI_WR_P2PTYPE_S) & FW_RI_WR_P2PTYPE_M) struct tcp_options { __be16 mss; @@ -783,58 +783,58 @@ struct cpl_pass_accept_req { }; /* cpl_pass_accept_req.hdr_len fields */ -#define S_SYN_RX_CHAN 0 -#define M_SYN_RX_CHAN 0xF -#define V_SYN_RX_CHAN(x) ((x) << S_SYN_RX_CHAN) -#define G_SYN_RX_CHAN(x) (((x) >> S_SYN_RX_CHAN) & M_SYN_RX_CHAN) +#define SYN_RX_CHAN_S 0 +#define SYN_RX_CHAN_M 0xF +#define SYN_RX_CHAN_V(x) ((x) << SYN_RX_CHAN_S) +#define SYN_RX_CHAN_G(x) (((x) >> SYN_RX_CHAN_S) & SYN_RX_CHAN_M) -#define S_TCP_HDR_LEN 10 -#define M_TCP_HDR_LEN 0x3F -#define V_TCP_HDR_LEN(x) ((x) << S_TCP_HDR_LEN) -#define G_TCP_HDR_LEN(x) (((x) >> S_TCP_HDR_LEN) & M_TCP_HDR_LEN) +#define TCP_HDR_LEN_S 10 +#define TCP_HDR_LEN_M 0x3F +#define TCP_HDR_LEN_V(x) ((x) << TCP_HDR_LEN_S) +#define TCP_HDR_LEN_G(x) (((x) >> TCP_HDR_LEN_S) & TCP_HDR_LEN_M) -#define S_IP_HDR_LEN 16 -#define M_IP_HDR_LEN 0x3FF -#define V_IP_HDR_LEN(x) ((x) << S_IP_HDR_LEN) -#define G_IP_HDR_LEN(x) (((x) >> S_IP_HDR_LEN) & M_IP_HDR_LEN) +#define IP_HDR_LEN_S 16 +#define IP_HDR_LEN_M 0x3FF +#define IP_HDR_LEN_V(x) ((x) << IP_HDR_LEN_S) +#define IP_HDR_LEN_G(x) (((x) >> IP_HDR_LEN_S) & IP_HDR_LEN_M) -#define S_ETH_HDR_LEN 26 -#define M_ETH_HDR_LEN 0x1F -#define V_ETH_HDR_LEN(x) ((x) << S_ETH_HDR_LEN) -#define G_ETH_HDR_LEN(x) (((x) >> S_ETH_HDR_LEN) & M_ETH_HDR_LEN) +#define ETH_HDR_LEN_S 26 +#define ETH_HDR_LEN_M 0x1F +#define ETH_HDR_LEN_V(x) ((x) << ETH_HDR_LEN_S) +#define ETH_HDR_LEN_G(x) (((x) >> ETH_HDR_LEN_S) & ETH_HDR_LEN_M) /* cpl_pass_accept_req.l2info fields */ -#define S_SYN_MAC_IDX 0 -#define M_SYN_MAC_IDX 0x1FF -#define V_SYN_MAC_IDX(x) ((x) << S_SYN_MAC_IDX) -#define G_SYN_MAC_IDX(x) (((x) >> S_SYN_MAC_IDX) & M_SYN_MAC_IDX) +#define SYN_MAC_IDX_S 0 +#define SYN_MAC_IDX_M 0x1FF +#define SYN_MAC_IDX_V(x) ((x) << SYN_MAC_IDX_S) +#define SYN_MAC_IDX_G(x) (((x) >> SYN_MAC_IDX_S) & SYN_MAC_IDX_M) -#define S_SYN_XACT_MATCH 9 -#define V_SYN_XACT_MATCH(x) ((x) << S_SYN_XACT_MATCH) -#define F_SYN_XACT_MATCH V_SYN_XACT_MATCH(1U) +#define SYN_XACT_MATCH_S 9 +#define SYN_XACT_MATCH_V(x) ((x) << SYN_XACT_MATCH_S) +#define SYN_XACT_MATCH_F SYN_XACT_MATCH_V(1U) -#define S_SYN_INTF 12 -#define M_SYN_INTF 0xF -#define V_SYN_INTF(x) ((x) << S_SYN_INTF) -#define G_SYN_INTF(x) (((x) >> S_SYN_INTF) & M_SYN_INTF) +#define SYN_INTF_S 12 +#define SYN_INTF_M 0xF +#define SYN_INTF_V(x) ((x) << SYN_INTF_S) +#define SYN_INTF_G(x) (((x) >> SYN_INTF_S) & SYN_INTF_M) struct ulptx_idata { __be32 cmd_more; __be32 len; }; -#define S_ULPTX_NSGE 0 -#define M_ULPTX_NSGE 0xFFFF -#define V_ULPTX_NSGE(x) ((x) << S_ULPTX_NSGE) +#define ULPTX_NSGE_S 0 +#define ULPTX_NSGE_M 0xFFFF +#define ULPTX_NSGE_V(x) ((x) << ULPTX_NSGE_S) -#define S_RX_DACK_MODE 29 -#define M_RX_DACK_MODE 0x3 -#define V_RX_DACK_MODE(x) ((x) << S_RX_DACK_MODE) -#define G_RX_DACK_MODE(x) (((x) >> S_RX_DACK_MODE) & M_RX_DACK_MODE) +#define RX_DACK_MODE_S 29 +#define RX_DACK_MODE_M 0x3 +#define RX_DACK_MODE_V(x) ((x) << RX_DACK_MODE_S) +#define RX_DACK_MODE_G(x) (((x) >> RX_DACK_MODE_S) & RX_DACK_MODE_M) -#define S_RX_DACK_CHANGE 31 -#define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE) -#define F_RX_DACK_CHANGE V_RX_DACK_CHANGE(1U) +#define RX_DACK_CHANGE_S 31 +#define RX_DACK_CHANGE_V(x) ((x) << RX_DACK_CHANGE_S) +#define RX_DACK_CHANGE_F RX_DACK_CHANGE_V(1U) enum { /* TCP congestion control algorithms */ CONG_ALG_RENO, @@ -843,10 +843,10 @@ enum { /* TCP congestion control algorithms */ CONG_ALG_HIGHSPEED }; -#define S_CONG_CNTRL 14 -#define M_CONG_CNTRL 0x3 -#define V_CONG_CNTRL(x) ((x) << S_CONG_CNTRL) -#define G_CONG_CNTRL(x) (((x) >> S_CONG_CNTRL) & M_CONG_CNTRL) +#define CONG_CNTRL_S 14 +#define CONG_CNTRL_M 0x3 +#define CONG_CNTRL_V(x) ((x) << CONG_CNTRL_S) +#define CONG_CNTRL_G(x) (((x) >> CONG_CNTRL_S) & CONG_CNTRL_M) #define CONG_CNTRL_VALID (1 << 18) diff --git a/drivers/infiniband/hw/mlx4/ah.c b/drivers/infiniband/hw/mlx4/ah.c index 2d8c3397774f..f50a546224ad 100644 --- a/drivers/infiniband/hw/mlx4/ah.c +++ b/drivers/infiniband/hw/mlx4/ah.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "mlx4_ib.h" diff --git a/drivers/infiniband/hw/mlx4/alias_GUID.c b/drivers/infiniband/hw/mlx4/alias_GUID.c index 0eb141c41416..a31e031afd87 100644 --- a/drivers/infiniband/hw/mlx4/alias_GUID.c +++ b/drivers/infiniband/hw/mlx4/alias_GUID.c @@ -154,7 +154,7 @@ void mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev, continue; slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ; - if (slave_id >= dev->dev->num_vfs + 1) + if (slave_id >= dev->dev->persist->num_vfs + 1) return; tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE]; form_cache_ag = get_cached_alias_guid(dev, port_num, diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index a3b70f6c4035..543ecdd8667b 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -188,6 +188,8 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector spin_lock_init(&cq->lock); cq->resize_buf = NULL; cq->resize_umem = NULL; + INIT_LIST_HEAD(&cq->send_qp_list); + INIT_LIST_HEAD(&cq->recv_qp_list); if (context) { struct mlx4_ib_create_cq ucmd; @@ -594,6 +596,55 @@ static int use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct return 0; } +static void mlx4_ib_qp_sw_comp(struct mlx4_ib_qp *qp, int num_entries, + struct ib_wc *wc, int *npolled, int is_send) +{ + struct mlx4_ib_wq *wq; + unsigned cur; + int i; + + wq = is_send ? &qp->sq : &qp->rq; + cur = wq->head - wq->tail; + + if (cur == 0) + return; + + for (i = 0; i < cur && *npolled < num_entries; i++) { + wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; + wc->status = IB_WC_WR_FLUSH_ERR; + wc->vendor_err = MLX4_CQE_SYNDROME_WR_FLUSH_ERR; + wq->tail++; + (*npolled)++; + wc->qp = &qp->ibqp; + wc++; + } +} + +static void mlx4_ib_poll_sw_comp(struct mlx4_ib_cq *cq, int num_entries, + struct ib_wc *wc, int *npolled) +{ + struct mlx4_ib_qp *qp; + + *npolled = 0; + /* Find uncompleted WQEs belonging to that cq and retrun + * simulated FLUSH_ERR completions + */ + list_for_each_entry(qp, &cq->send_qp_list, cq_send_list) { + mlx4_ib_qp_sw_comp(qp, num_entries, wc, npolled, 1); + if (*npolled >= num_entries) + goto out; + } + + list_for_each_entry(qp, &cq->recv_qp_list, cq_recv_list) { + mlx4_ib_qp_sw_comp(qp, num_entries, wc + *npolled, npolled, 0); + if (*npolled >= num_entries) + goto out; + } + +out: + return; +} + static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, struct mlx4_ib_qp **cur_qp, struct ib_wc *wc) @@ -836,8 +887,13 @@ int mlx4_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) unsigned long flags; int npolled; int err = 0; + struct mlx4_ib_dev *mdev = to_mdev(cq->ibcq.device); spin_lock_irqsave(&cq->lock, flags); + if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { + mlx4_ib_poll_sw_comp(cq, num_entries, wc, &npolled); + goto out; + } for (npolled = 0; npolled < num_entries; ++npolled) { err = mlx4_ib_poll_one(cq, &cur_qp, wc + npolled); @@ -847,6 +903,7 @@ int mlx4_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) mlx4_cq_set_ci(&cq->mcq); +out: spin_unlock_irqrestore(&cq->lock, flags); if (err == 0 || err == -EAGAIN) diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index 82a7dd87089b..c7619716c31d 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -1951,7 +1951,8 @@ static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev, ctx->ib_dev = &dev->ib_dev; for (i = 0; - i < min(dev->dev->caps.sqp_demux, (u16)(dev->dev->num_vfs + 1)); + i < min(dev->dev->caps.sqp_demux, + (u16)(dev->dev->persist->num_vfs + 1)); i++) { struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev->dev, i); diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 57ecc5b204f3..eb8e215f1613 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -198,7 +198,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) & 0xffffff; - props->vendor_part_id = dev->dev->pdev->device; + props->vendor_part_id = dev->dev->persist->pdev->device; props->hw_ver = be32_to_cpup((__be32 *) (out_mad->data + 32)); memcpy(&props->sys_image_guid, out_mad->data + 4, 8); @@ -351,6 +351,7 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port, enum ib_mtu tmp; struct mlx4_cmd_mailbox *mailbox; int err = 0; + int is_bonded = mlx4_is_bonded(mdev->dev); mailbox = mlx4_alloc_cmd_mailbox(mdev->dev); if (IS_ERR(mailbox)) @@ -374,8 +375,12 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port, props->state = IB_PORT_DOWN; props->phys_state = state_to_phys_state(props->state); props->active_mtu = IB_MTU_256; + if (is_bonded) + rtnl_lock(); /* required to get upper dev */ spin_lock_bh(&iboe->lock); ndev = iboe->netdevs[port - 1]; + if (ndev && is_bonded) + ndev = netdev_master_upper_dev_get(ndev); if (!ndev) goto out_unlock; @@ -387,6 +392,8 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port, props->phys_state = state_to_phys_state(props->state); out_unlock: spin_unlock_bh(&iboe->lock); + if (is_bonded) + rtnl_unlock(); out: mlx4_free_cmd_mailbox(mdev->dev, mailbox); return err; @@ -844,7 +851,7 @@ int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp, struct mlx4_ib_steering { struct list_head list; - u64 reg_id; + struct mlx4_flow_reg_id reg_id; union ib_gid gid; }; @@ -1114,7 +1121,8 @@ static int mlx4_ib_tunnel_steer_add(struct ib_qp *qp, struct ib_flow_attr *flow_ struct mlx4_dev *dev = to_mdev(qp->device)->dev; int err = 0; - if (dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) + if (dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN || + dev->caps.dmfs_high_steer_mode == MLX4_STEERING_DMFS_A0_STATIC) return 0; /* do nothing */ ib_flow = flow_attr + 1; @@ -1134,9 +1142,11 @@ static struct ib_flow *mlx4_ib_create_flow(struct ib_qp *qp, struct ib_flow_attr *flow_attr, int domain) { - int err = 0, i = 0; + int err = 0, i = 0, j = 0; struct mlx4_ib_flow *mflow; enum mlx4_net_trans_promisc_mode type[2]; + struct mlx4_dev *dev = (to_mdev(qp->device))->dev; + int is_bonded = mlx4_is_bonded(dev); memset(type, 0, sizeof(type)); @@ -1171,26 +1181,58 @@ static struct ib_flow *mlx4_ib_create_flow(struct ib_qp *qp, while (i < ARRAY_SIZE(type) && type[i]) { err = __mlx4_ib_create_flow(qp, flow_attr, domain, type[i], - &mflow->reg_id[i]); + &mflow->reg_id[i].id); if (err) goto err_create_flow; i++; + if (is_bonded) { + /* Application always sees one port so the mirror rule + * must be on port #2 + */ + flow_attr->port = 2; + err = __mlx4_ib_create_flow(qp, flow_attr, + domain, type[j], + &mflow->reg_id[j].mirror); + flow_attr->port = 1; + if (err) + goto err_create_flow; + j++; + } + } if (i < ARRAY_SIZE(type) && flow_attr->type == IB_FLOW_ATTR_NORMAL) { - err = mlx4_ib_tunnel_steer_add(qp, flow_attr, &mflow->reg_id[i]); + err = mlx4_ib_tunnel_steer_add(qp, flow_attr, + &mflow->reg_id[i].id); if (err) goto err_create_flow; i++; + if (is_bonded) { + flow_attr->port = 2; + err = mlx4_ib_tunnel_steer_add(qp, flow_attr, + &mflow->reg_id[j].mirror); + flow_attr->port = 1; + if (err) + goto err_create_flow; + j++; + } + /* function to create mirror rule */ } return &mflow->ibflow; err_create_flow: while (i) { - (void)__mlx4_ib_destroy_flow(to_mdev(qp->device)->dev, mflow->reg_id[i]); + (void)__mlx4_ib_destroy_flow(to_mdev(qp->device)->dev, + mflow->reg_id[i].id); i--; } + + while (j) { + (void)__mlx4_ib_destroy_flow(to_mdev(qp->device)->dev, + mflow->reg_id[j].mirror); + j--; + } err_free: kfree(mflow); return ERR_PTR(err); @@ -1203,10 +1245,16 @@ static int mlx4_ib_destroy_flow(struct ib_flow *flow_id) struct mlx4_ib_dev *mdev = to_mdev(flow_id->qp->device); struct mlx4_ib_flow *mflow = to_mflow(flow_id); - while (i < ARRAY_SIZE(mflow->reg_id) && mflow->reg_id[i]) { - err = __mlx4_ib_destroy_flow(mdev->dev, mflow->reg_id[i]); + while (i < ARRAY_SIZE(mflow->reg_id) && mflow->reg_id[i].id) { + err = __mlx4_ib_destroy_flow(mdev->dev, mflow->reg_id[i].id); if (err) ret = err; + if (mflow->reg_id[i].mirror) { + err = __mlx4_ib_destroy_flow(mdev->dev, + mflow->reg_id[i].mirror); + if (err) + ret = err; + } i++; } @@ -1218,11 +1266,12 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) { int err; struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); + struct mlx4_dev *dev = mdev->dev; struct mlx4_ib_qp *mqp = to_mqp(ibqp); - u64 reg_id; struct mlx4_ib_steering *ib_steering = NULL; enum mlx4_protocol prot = (gid->raw[1] == 0x0e) ? MLX4_PROT_IB_IPV4 : MLX4_PROT_IB_IPV6; + struct mlx4_flow_reg_id reg_id; if (mdev->dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) { @@ -1234,10 +1283,21 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, mqp->port, !!(mqp->flags & MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK), - prot, ®_id); + prot, ®_id.id); if (err) goto err_malloc; + reg_id.mirror = 0; + if (mlx4_is_bonded(dev)) { + err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, + (mqp->port == 1) ? 2 : 1, + !!(mqp->flags & + MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK), + prot, ®_id.mirror); + if (err) + goto err_add; + } + err = add_gid_entry(ibqp, gid); if (err) goto err_add; @@ -1253,7 +1313,10 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) err_add: mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, - prot, reg_id); + prot, reg_id.id); + if (reg_id.mirror) + mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, + prot, reg_id.mirror); err_malloc: kfree(ib_steering); @@ -1280,10 +1343,12 @@ static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) { int err; struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); + struct mlx4_dev *dev = mdev->dev; struct mlx4_ib_qp *mqp = to_mqp(ibqp); struct net_device *ndev; struct mlx4_ib_gid_entry *ge; - u64 reg_id = 0; + struct mlx4_flow_reg_id reg_id = {0, 0}; + enum mlx4_protocol prot = (gid->raw[1] == 0x0e) ? MLX4_PROT_IB_IPV4 : MLX4_PROT_IB_IPV6; @@ -1308,10 +1373,17 @@ static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) } err = mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, - prot, reg_id); + prot, reg_id.id); if (err) return err; + if (mlx4_is_bonded(dev)) { + err = mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, + prot, reg_id.mirror); + if (err) + return err; + } + mutex_lock(&mqp->mutex); ge = find_gid_entry(mqp, gid->raw); if (ge) { @@ -1375,7 +1447,7 @@ static ssize_t show_hca(struct device *device, struct device_attribute *attr, { struct mlx4_ib_dev *dev = container_of(device, struct mlx4_ib_dev, ib_dev.dev); - return sprintf(buf, "MT%d\n", dev->dev->pdev->device); + return sprintf(buf, "MT%d\n", dev->dev->persist->pdev->device); } static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr, @@ -1439,6 +1511,7 @@ static void update_gids_task(struct work_struct *work) union ib_gid *gids; int err; struct mlx4_dev *dev = gw->dev->dev; + int is_bonded = mlx4_is_bonded(dev); if (!gw->dev->ib_active) return; @@ -1458,7 +1531,10 @@ static void update_gids_task(struct work_struct *work) if (err) pr_warn("set port command failed\n"); else - mlx4_ib_dispatch_event(gw->dev, gw->port, IB_EVENT_GID_CHANGE); + if ((gw->port == 1) || !is_bonded) + mlx4_ib_dispatch_event(gw->dev, + is_bonded ? 1 : gw->port, + IB_EVENT_GID_CHANGE); mlx4_free_cmd_mailbox(dev, mailbox); kfree(gw); @@ -1874,7 +1950,8 @@ static void mlx4_ib_scan_netdevs(struct mlx4_ib_dev *ibdev, * don't want the bond IP based gids in the table since * flows that select port by gid may get the down port. */ - if (port_state == IB_PORT_DOWN) { + if (port_state == IB_PORT_DOWN && + !mlx4_is_bonded(ibdev->dev)) { reset_gid_table(ibdev, port); mlx4_ib_set_default_gid(ibdev, curr_netdev, @@ -1937,7 +2014,8 @@ static void init_pkeys(struct mlx4_ib_dev *ibdev) int i; if (mlx4_is_master(ibdev->dev)) { - for (slave = 0; slave <= ibdev->dev->num_vfs; ++slave) { + for (slave = 0; slave <= ibdev->dev->persist->num_vfs; + ++slave) { for (port = 1; port <= ibdev->dev->caps.num_ports; ++port) { for (i = 0; i < ibdev->dev->phys_caps.pkey_phys_table_len[port]; @@ -1994,7 +2072,7 @@ static void mlx4_ib_alloc_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev) mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) { for (j = 0; j < eq_per_port; j++) { snprintf(name, sizeof(name), "mlx4-ib-%d-%d@%s", - i, j, dev->pdev->bus->name); + i, j, dev->persist->pdev->bus->name); /* Set IRQ for specific name (per ring) */ if (mlx4_assign_eq(dev, name, NULL, &ibdev->eq_table[eq])) { @@ -2045,6 +2123,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) int err; struct mlx4_ib_iboe *iboe; int ib_num_ports = 0; + int num_req_counters; pr_info_once("%s", mlx4_ib_version); @@ -2058,7 +2137,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev); if (!ibdev) { - dev_err(&dev->pdev->dev, "Device struct alloc failed\n"); + dev_err(&dev->persist->pdev->dev, + "Device struct alloc failed\n"); return NULL; } @@ -2077,15 +2157,17 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) MLX4_INIT_DOORBELL_LOCK(&ibdev->uar_lock); ibdev->dev = dev; + ibdev->bond_next_port = 0; strlcpy(ibdev->ib_dev.name, "mlx4_%d", IB_DEVICE_NAME_MAX); ibdev->ib_dev.owner = THIS_MODULE; ibdev->ib_dev.node_type = RDMA_NODE_IB_CA; ibdev->ib_dev.local_dma_lkey = dev->caps.reserved_lkey; ibdev->num_ports = num_ports; - ibdev->ib_dev.phys_port_cnt = ibdev->num_ports; + ibdev->ib_dev.phys_port_cnt = mlx4_is_bonded(dev) ? + 1 : ibdev->num_ports; ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors; - ibdev->ib_dev.dma_device = &dev->pdev->dev; + ibdev->ib_dev.dma_device = &dev->persist->pdev->dev; if (dev->caps.userspace_caps) ibdev->ib_dev.uverbs_abi_ver = MLX4_IB_UVERBS_ABI_VERSION; @@ -2204,7 +2286,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) if (init_node_data(ibdev)) goto err_map; - for (i = 0; i < ibdev->num_ports; ++i) { + num_req_counters = mlx4_is_bonded(dev) ? 1 : ibdev->num_ports; + for (i = 0; i < num_req_counters; ++i) { mutex_init(&ibdev->qp1_proxy_lock[i]); if (mlx4_ib_port_link_layer(&ibdev->ib_dev, i + 1) == IB_LINK_LAYER_ETHERNET) { @@ -2215,12 +2298,18 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ibdev->counters[i] = -1; } } + if (mlx4_is_bonded(dev)) + for (i = 1; i < ibdev->num_ports ; ++i) + ibdev->counters[i] = ibdev->counters[0]; + mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) ib_num_ports++; spin_lock_init(&ibdev->sm_lock); mutex_init(&ibdev->cap_mask_mutex); + INIT_LIST_HEAD(&ibdev->qp_list); + spin_lock_init(&ibdev->reset_flow_resource_lock); if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED && ib_num_ports) { @@ -2236,7 +2325,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) sizeof(long), GFP_KERNEL); if (!ibdev->ib_uc_qpns_bitmap) { - dev_err(&dev->pdev->dev, "bit map alloc failed\n"); + dev_err(&dev->persist->pdev->dev, + "bit map alloc failed\n"); goto err_steer_qp_release; } @@ -2534,6 +2624,99 @@ out: return; } +static void mlx4_ib_handle_catas_error(struct mlx4_ib_dev *ibdev) +{ + struct mlx4_ib_qp *mqp; + unsigned long flags_qp; + unsigned long flags_cq; + struct mlx4_ib_cq *send_mcq, *recv_mcq; + struct list_head cq_notify_list; + struct mlx4_cq *mcq; + unsigned long flags; + + pr_warn("mlx4_ib_handle_catas_error was started\n"); + INIT_LIST_HEAD(&cq_notify_list); + + /* Go over qp list reside on that ibdev, sync with create/destroy qp.*/ + spin_lock_irqsave(&ibdev->reset_flow_resource_lock, flags); + + list_for_each_entry(mqp, &ibdev->qp_list, qps_list) { + spin_lock_irqsave(&mqp->sq.lock, flags_qp); + if (mqp->sq.tail != mqp->sq.head) { + send_mcq = to_mcq(mqp->ibqp.send_cq); + spin_lock_irqsave(&send_mcq->lock, flags_cq); + if (send_mcq->mcq.comp && + mqp->ibqp.send_cq->comp_handler) { + if (!send_mcq->mcq.reset_notify_added) { + send_mcq->mcq.reset_notify_added = 1; + list_add_tail(&send_mcq->mcq.reset_notify, + &cq_notify_list); + } + } + spin_unlock_irqrestore(&send_mcq->lock, flags_cq); + } + spin_unlock_irqrestore(&mqp->sq.lock, flags_qp); + /* Now, handle the QP's receive queue */ + spin_lock_irqsave(&mqp->rq.lock, flags_qp); + /* no handling is needed for SRQ */ + if (!mqp->ibqp.srq) { + if (mqp->rq.tail != mqp->rq.head) { + recv_mcq = to_mcq(mqp->ibqp.recv_cq); + spin_lock_irqsave(&recv_mcq->lock, flags_cq); + if (recv_mcq->mcq.comp && + mqp->ibqp.recv_cq->comp_handler) { + if (!recv_mcq->mcq.reset_notify_added) { + recv_mcq->mcq.reset_notify_added = 1; + list_add_tail(&recv_mcq->mcq.reset_notify, + &cq_notify_list); + } + } + spin_unlock_irqrestore(&recv_mcq->lock, + flags_cq); + } + } + spin_unlock_irqrestore(&mqp->rq.lock, flags_qp); + } + + list_for_each_entry(mcq, &cq_notify_list, reset_notify) { + mcq->comp(mcq); + } + spin_unlock_irqrestore(&ibdev->reset_flow_resource_lock, flags); + pr_warn("mlx4_ib_handle_catas_error ended\n"); +} + +static void handle_bonded_port_state_event(struct work_struct *work) +{ + struct ib_event_work *ew = + container_of(work, struct ib_event_work, work); + struct mlx4_ib_dev *ibdev = ew->ib_dev; + enum ib_port_state bonded_port_state = IB_PORT_NOP; + int i; + struct ib_event ibev; + + kfree(ew); + spin_lock_bh(&ibdev->iboe.lock); + for (i = 0; i < MLX4_MAX_PORTS; ++i) { + struct net_device *curr_netdev = ibdev->iboe.netdevs[i]; + + enum ib_port_state curr_port_state = + (netif_running(curr_netdev) && + netif_carrier_ok(curr_netdev)) ? + IB_PORT_ACTIVE : IB_PORT_DOWN; + + bonded_port_state = (bonded_port_state != IB_PORT_ACTIVE) ? + curr_port_state : IB_PORT_ACTIVE; + } + spin_unlock_bh(&ibdev->iboe.lock); + + ibev.device = &ibdev->ib_dev; + ibev.element.port_num = 1; + ibev.event = (bonded_port_state == IB_PORT_ACTIVE) ? + IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR; + + ib_dispatch_event(&ibev); +} + static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, enum mlx4_dev_event event, unsigned long param) { @@ -2543,6 +2726,18 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, struct ib_event_work *ew; int p = 0; + if (mlx4_is_bonded(dev) && + ((event == MLX4_DEV_EVENT_PORT_UP) || + (event == MLX4_DEV_EVENT_PORT_DOWN))) { + ew = kmalloc(sizeof(*ew), GFP_ATOMIC); + if (!ew) + return; + INIT_WORK(&ew->work, handle_bonded_port_state_event); + ew->ib_dev = ibdev; + queue_work(wq, &ew->work); + return; + } + if (event == MLX4_DEV_EVENT_PORT_MGMT_CHANGE) eqe = (struct mlx4_eqe *)param; else @@ -2569,6 +2764,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, case MLX4_DEV_EVENT_CATASTROPHIC_ERROR: ibdev->ib_active = false; ibev.event = IB_EVENT_DEVICE_FATAL; + mlx4_ib_handle_catas_error(ibdev); break; case MLX4_DEV_EVENT_PORT_MGMT_CHANGE: @@ -2603,7 +2799,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, } ibev.device = ibdev_ptr; - ibev.element.port_num = (u8) p; + ibev.element.port_num = mlx4_is_bonded(ibdev->dev) ? 1 : (u8)p; ib_dispatch_event(&ibev); } @@ -2612,7 +2808,8 @@ static struct mlx4_interface mlx4_ib_interface = { .add = mlx4_ib_add, .remove = mlx4_ib_remove, .event = mlx4_ib_event, - .protocol = MLX4_PROT_IB_IPV6 + .protocol = MLX4_PROT_IB_IPV6, + .flags = MLX4_INTFF_BONDING }; static int __init mlx4_ib_init(void) diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 6eb743f65f6f..f829fd935b79 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -110,6 +110,9 @@ struct mlx4_ib_cq { struct mutex resize_mutex; struct ib_umem *umem; struct ib_umem *resize_umem; + /* List of qps that it serves.*/ + struct list_head send_qp_list; + struct list_head recv_qp_list; }; struct mlx4_ib_mr { @@ -134,10 +137,17 @@ struct mlx4_ib_fmr { struct mlx4_fmr mfmr; }; +#define MAX_REGS_PER_FLOW 2 + +struct mlx4_flow_reg_id { + u64 id; + u64 mirror; +}; + struct mlx4_ib_flow { struct ib_flow ibflow; /* translating DMFS verbs sniffer rule to FW API requires two reg IDs */ - u64 reg_id[2]; + struct mlx4_flow_reg_id reg_id[MAX_REGS_PER_FLOW]; }; struct mlx4_ib_wq { @@ -293,6 +303,9 @@ struct mlx4_ib_qp { struct mlx4_roce_smac_vlan_info pri; struct mlx4_roce_smac_vlan_info alt; u64 reg_id; + struct list_head qps_list; + struct list_head cq_recv_list; + struct list_head cq_send_list; }; struct mlx4_ib_srq { @@ -527,6 +540,10 @@ struct mlx4_ib_dev { struct mlx4_ib_qp *qp1_proxy[MLX4_MAX_PORTS]; /* lock when destroying qp1_proxy and getting netdev events */ struct mutex qp1_proxy_lock[MLX4_MAX_PORTS]; + u8 bond_next_port; + /* protect resources needed as part of reset flow */ + spinlock_t reset_flow_resource_lock; + struct list_head qp_list; }; struct ib_event_work { @@ -622,6 +639,13 @@ static inline struct mlx4_ib_ah *to_mah(struct ib_ah *ibah) return container_of(ibah, struct mlx4_ib_ah, ibah); } +static inline u8 mlx4_ib_bond_next_port(struct mlx4_ib_dev *dev) +{ + dev->bond_next_port = (dev->bond_next_port + 1) % dev->num_ports; + + return dev->bond_next_port + 1; +} + int mlx4_ib_init_sriov(struct mlx4_ib_dev *dev); void mlx4_ib_close_sriov(struct mlx4_ib_dev *dev); diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index c36ccbd9a644..e0d271782d0a 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c @@ -401,7 +401,8 @@ struct ib_fast_reg_page_list *mlx4_ib_alloc_fast_reg_page_list(struct ib_device if (!mfrpl->ibfrpl.page_list) goto err_free; - mfrpl->mapped_page_list = dma_alloc_coherent(&dev->dev->pdev->dev, + mfrpl->mapped_page_list = dma_alloc_coherent(&dev->dev->persist-> + pdev->dev, size, &mfrpl->map, GFP_KERNEL); if (!mfrpl->mapped_page_list) @@ -423,7 +424,8 @@ void mlx4_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list) struct mlx4_ib_fast_reg_page_list *mfrpl = to_mfrpl(page_list); int size = page_list->max_page_list_len * sizeof (u64); - dma_free_coherent(&dev->dev->pdev->dev, size, mfrpl->mapped_page_list, + dma_free_coherent(&dev->dev->persist->pdev->dev, size, + mfrpl->mapped_page_list, mfrpl->map); kfree(mfrpl->ibfrpl.page_list); kfree(mfrpl); diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index cf000b7ad64f..dfc6ca128a7e 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -40,11 +40,17 @@ #include #include +#include #include #include "mlx4_ib.h" #include "user.h" +static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, + struct mlx4_ib_cq *recv_cq); +static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, + struct mlx4_ib_cq *recv_cq); + enum { MLX4_IB_ACK_REQ_FREQ = 8, }; @@ -93,17 +99,6 @@ enum { #ifndef ETH_ALEN #define ETH_ALEN 6 #endif -static inline u64 mlx4_mac_to_u64(u8 *addr) -{ - u64 mac = 0; - int i; - - for (i = 0; i < ETH_ALEN; i++) { - mac <<= 8; - mac |= addr[i]; - } - return mac; -} static const __be32 mlx4_ib_opcode[] = { [IB_WR_SEND] = cpu_to_be32(MLX4_OPCODE_SEND), @@ -628,6 +623,8 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, struct mlx4_ib_sqp *sqp; struct mlx4_ib_qp *qp; enum mlx4_ib_qp_type qp_type = (enum mlx4_ib_qp_type) init_attr->qp_type; + struct mlx4_ib_cq *mcq; + unsigned long flags; /* When tunneling special qps, we use a plain UD qp */ if (sqpn) { @@ -838,6 +835,24 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, qp->mqp.event = mlx4_ib_qp_event; if (!*caller_qp) *caller_qp = qp; + + spin_lock_irqsave(&dev->reset_flow_resource_lock, flags); + mlx4_ib_lock_cqs(to_mcq(init_attr->send_cq), + to_mcq(init_attr->recv_cq)); + /* Maintain device to QPs access, needed for further handling + * via reset flow + */ + list_add_tail(&qp->qps_list, &dev->qp_list); + /* Maintain CQ to QPs access, needed for further handling + * via reset flow + */ + mcq = to_mcq(init_attr->send_cq); + list_add_tail(&qp->cq_send_list, &mcq->send_qp_list); + mcq = to_mcq(init_attr->recv_cq); + list_add_tail(&qp->cq_recv_list, &mcq->recv_qp_list); + mlx4_ib_unlock_cqs(to_mcq(init_attr->send_cq), + to_mcq(init_attr->recv_cq)); + spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags); return 0; err_qpn: @@ -896,13 +911,13 @@ static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv __acquires(&send_cq->lock) __acquires(&recv_cq->lock) { if (send_cq == recv_cq) { - spin_lock_irq(&send_cq->lock); + spin_lock(&send_cq->lock); __acquire(&recv_cq->lock); } else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { - spin_lock_irq(&send_cq->lock); + spin_lock(&send_cq->lock); spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING); } else { - spin_lock_irq(&recv_cq->lock); + spin_lock(&recv_cq->lock); spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING); } } @@ -912,13 +927,13 @@ static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *re { if (send_cq == recv_cq) { __release(&recv_cq->lock); - spin_unlock_irq(&send_cq->lock); + spin_unlock(&send_cq->lock); } else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { spin_unlock(&recv_cq->lock); - spin_unlock_irq(&send_cq->lock); + spin_unlock(&send_cq->lock); } else { spin_unlock(&send_cq->lock); - spin_unlock_irq(&recv_cq->lock); + spin_unlock(&recv_cq->lock); } } @@ -963,6 +978,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, int is_user) { struct mlx4_ib_cq *send_cq, *recv_cq; + unsigned long flags; if (qp->state != IB_QPS_RESET) { if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state), @@ -994,8 +1010,13 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, get_cqs(qp, &send_cq, &recv_cq); + spin_lock_irqsave(&dev->reset_flow_resource_lock, flags); mlx4_ib_lock_cqs(send_cq, recv_cq); + /* del from lists under both locks above to protect reset flow paths */ + list_del(&qp->qps_list); + list_del(&qp->cq_send_list); + list_del(&qp->cq_recv_list); if (!is_user) { __mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn, qp->ibqp.srq ? to_msrq(qp->ibqp.srq): NULL); @@ -1006,6 +1027,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, mlx4_qp_remove(dev->dev, &qp->mqp); mlx4_ib_unlock_cqs(send_cq, recv_cq); + spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags); mlx4_qp_free(dev->dev, &qp->mqp); @@ -1915,6 +1937,22 @@ int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, goto out; } + if (mlx4_is_bonded(dev->dev) && (attr_mask & IB_QP_PORT)) { + if ((cur_state == IB_QPS_RESET) && (new_state == IB_QPS_INIT)) { + if ((ibqp->qp_type == IB_QPT_RC) || + (ibqp->qp_type == IB_QPT_UD) || + (ibqp->qp_type == IB_QPT_UC) || + (ibqp->qp_type == IB_QPT_RAW_PACKET) || + (ibqp->qp_type == IB_QPT_XRC_INI)) { + attr->port_num = mlx4_ib_bond_next_port(dev); + } + } else { + /* no sense in changing port_num + * when ports are bonded */ + attr_mask &= ~IB_QP_PORT; + } + } + if ((attr_mask & IB_QP_PORT) && (attr->port_num == 0 || attr->port_num > dev->num_ports)) { pr_debug("qpn 0x%x: invalid port number (%d) specified " @@ -1965,6 +2003,9 @@ int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, err = __mlx4_ib_modify_qp(ibqp, attr, attr_mask, cur_state, new_state); + if (mlx4_is_bonded(dev->dev) && (attr_mask & IB_QP_PORT)) + attr->port_num = 1; + out: mutex_unlock(&qp->mutex); return err; @@ -2609,8 +2650,15 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, __be32 uninitialized_var(lso_hdr_sz); __be32 blh; int i; + struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); spin_lock_irqsave(&qp->sq.lock, flags); + if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { + err = -EIO; + *bad_wr = wr; + nreq = 0; + goto out; + } ind = qp->sq_next_wqe; @@ -2908,10 +2956,18 @@ int mlx4_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, int ind; int max_gs; int i; + struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); max_gs = qp->rq.max_gs; spin_lock_irqsave(&qp->rq.lock, flags); + if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { + err = -EIO; + *bad_wr = wr; + nreq = 0; + goto out; + } + ind = qp->rq.head & (qp->rq.wqe_cnt - 1); for (nreq = 0; wr; ++nreq, wr = wr->next) { diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c index 62d9285300af..dce5dfe3a70e 100644 --- a/drivers/infiniband/hw/mlx4/srq.c +++ b/drivers/infiniband/hw/mlx4/srq.c @@ -316,8 +316,15 @@ int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, int err = 0; int nreq; int i; + struct mlx4_ib_dev *mdev = to_mdev(ibsrq->device); spin_lock_irqsave(&srq->lock, flags); + if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { + err = -EIO; + *bad_wr = wr; + nreq = 0; + goto out; + } for (nreq = 0; wr; ++nreq, wr = wr->next) { if (unlikely(wr->num_sge > srq->msrq.max_gs)) { @@ -362,6 +369,7 @@ int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, *srq->db.db = cpu_to_be32(srq->wqe_ctr); } +out: spin_unlock_irqrestore(&srq->lock, flags); diff --git a/drivers/infiniband/hw/mlx4/sysfs.c b/drivers/infiniband/hw/mlx4/sysfs.c index cb4c66e723b5..d10c2b8a5dad 100644 --- a/drivers/infiniband/hw/mlx4/sysfs.c +++ b/drivers/infiniband/hw/mlx4/sysfs.c @@ -375,7 +375,7 @@ static void get_name(struct mlx4_ib_dev *dev, char *name, int i, int max) char base_name[9]; /* pci_name format is: bus:dev:func -> xxxx:yy:zz.n */ - strlcpy(name, pci_name(dev->dev->pdev), max); + strlcpy(name, pci_name(dev->dev->persist->pdev), max); strncpy(base_name, name, 8); /*till xxxx:yy:*/ base_name[8] = '\0'; /* with no ARI only 3 last bits are used so when the fn is higher than 8 @@ -792,7 +792,7 @@ static int register_pkey_tree(struct mlx4_ib_dev *device) if (!mlx4_is_master(device->dev)) return 0; - for (i = 0; i <= device->dev->num_vfs; ++i) + for (i = 0; i <= device->dev->persist->num_vfs; ++i) register_one_pkey_tree(device, i); return 0; @@ -807,7 +807,7 @@ static void unregister_pkey_tree(struct mlx4_ib_dev *device) if (!mlx4_is_master(device->dev)) return; - for (slave = device->dev->num_vfs; slave >= 0; --slave) { + for (slave = device->dev->persist->num_vfs; slave >= 0; --slave) { list_for_each_entry_safe(p, t, &device->pkeys.pkey_port_list[slave], entry) { diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 8a87404e9c76..03bf81211a54 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1331,8 +1331,6 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) | (1ull << IB_USER_VERBS_CMD_CREATE_XSRQ) | (1ull << IB_USER_VERBS_CMD_OPEN_QP); - dev->ib_dev.uverbs_ex_cmd_mask = - (1ull << IB_USER_VERBS_EX_CMD_QUERY_DEVICE); dev->ib_dev.query_device = mlx5_ib_query_device; dev->ib_dev.query_port = mlx5_ib_query_port; diff --git a/drivers/infiniband/hw/mlx5/mem.c b/drivers/infiniband/hw/mlx5/mem.c index b56e4c5593ee..611a9fdf2f38 100644 --- a/drivers/infiniband/hw/mlx5/mem.c +++ b/drivers/infiniband/hw/mlx5/mem.c @@ -81,7 +81,7 @@ void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift, for (k = 0; k < len; k++) { if (!(i & mask)) { tmp = (unsigned long)pfn; - m = min(m, find_first_bit(&tmp, sizeof(tmp))); + m = min_t(unsigned long, m, find_first_bit(&tmp, sizeof(tmp))); skip = 1 << m; mask = skip - 1; base = pfn; diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 49eb5111d2cd..70acda91eb2a 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -373,11 +373,11 @@ static int nes_nic_send(struct sk_buff *skb, struct net_device *netdev) wqe_fragment_length = (__le16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX]; /* setup the VLAN tag if present */ - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { nes_debug(NES_DBG_NIC_TX, "%s: VLAN packet to send... VLAN = %08X\n", - netdev->name, vlan_tx_tag_get(skb)); + netdev->name, skb_vlan_tag_get(skb)); wqe_misc = NES_NIC_SQ_WQE_TAGVALUE_ENABLE; - wqe_fragment_length[0] = (__force __le16) vlan_tx_tag_get(skb); + wqe_fragment_length[0] = (__force __le16) skb_vlan_tag_get(skb); } else wqe_misc = 0; @@ -576,11 +576,12 @@ tso_sq_no_longer_full: wqe_fragment_length = (__le16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX]; /* setup the VLAN tag if present */ - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { nes_debug(NES_DBG_NIC_TX, "%s: VLAN packet to send... VLAN = %08X\n", - netdev->name, vlan_tx_tag_get(skb) ); + netdev->name, + skb_vlan_tag_get(skb)); wqe_misc = NES_NIC_SQ_WQE_TAGVALUE_ENABLE; - wqe_fragment_length[0] = (__force __le16) vlan_tx_tag_get(skb); + wqe_fragment_length[0] = (__force __le16) skb_vlan_tag_get(skb); } else wqe_misc = 0; diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 8ba80a6d3a46..d7562beb5423 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -98,15 +98,9 @@ enum { IPOIB_MCAST_FLAG_FOUND = 0, /* used in set_multicast_list */ IPOIB_MCAST_FLAG_SENDONLY = 1, - /* - * For IPOIB_MCAST_FLAG_BUSY - * When set, in flight join and mcast->mc is unreliable - * When clear and mcast->mc IS_ERR_OR_NULL, need to restart or - * haven't started yet - * When clear and mcast->mc is valid pointer, join was successful - */ - IPOIB_MCAST_FLAG_BUSY = 2, + IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */ IPOIB_MCAST_FLAG_ATTACHED = 3, + IPOIB_MCAST_JOIN_STARTED = 4, MAX_SEND_CQE = 16, IPOIB_CM_COPYBREAK = 256, @@ -323,7 +317,6 @@ struct ipoib_dev_priv { struct list_head multicast_list; struct rb_root multicast_tree; - struct workqueue_struct *wq; struct delayed_work mcast_task; struct work_struct carrier_on_task; struct work_struct flush_light; @@ -484,10 +477,10 @@ void ipoib_ib_dev_flush_heavy(struct work_struct *work); void ipoib_pkey_event(struct work_struct *work); void ipoib_ib_dev_cleanup(struct net_device *dev); -int ipoib_ib_dev_open(struct net_device *dev); +int ipoib_ib_dev_open(struct net_device *dev, int flush); int ipoib_ib_dev_up(struct net_device *dev); -int ipoib_ib_dev_down(struct net_device *dev); -int ipoib_ib_dev_stop(struct net_device *dev); +int ipoib_ib_dev_down(struct net_device *dev, int flush); +int ipoib_ib_dev_stop(struct net_device *dev, int flush); void ipoib_pkey_dev_check_presence(struct net_device *dev); int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port); @@ -499,7 +492,7 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb); void ipoib_mcast_restart_task(struct work_struct *work); int ipoib_mcast_start_thread(struct net_device *dev); -int ipoib_mcast_stop_thread(struct net_device *dev); +int ipoib_mcast_stop_thread(struct net_device *dev, int flush); void ipoib_mcast_dev_down(struct net_device *dev); void ipoib_mcast_dev_flush(struct net_device *dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 56959adb6c7d..933efcea0d03 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -474,7 +474,7 @@ static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even } spin_lock_irq(&priv->lock); - queue_delayed_work(priv->wq, + queue_delayed_work(ipoib_workqueue, &priv->cm.stale_task, IPOIB_CM_RX_DELAY); /* Add this entry to passive ids list head, but do not re-add it * if IB_EVENT_QP_LAST_WQE_REACHED has moved it to flush list. */ @@ -576,7 +576,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) spin_lock_irqsave(&priv->lock, flags); list_splice_init(&priv->cm.rx_drain_list, &priv->cm.rx_reap_list); ipoib_cm_start_rx_drain(priv); - queue_work(priv->wq, &priv->cm.rx_reap_task); + queue_work(ipoib_workqueue, &priv->cm.rx_reap_task); spin_unlock_irqrestore(&priv->lock, flags); } else ipoib_warn(priv, "cm recv completion event with wrid %d (> %d)\n", @@ -603,7 +603,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) spin_lock_irqsave(&priv->lock, flags); list_move(&p->list, &priv->cm.rx_reap_list); spin_unlock_irqrestore(&priv->lock, flags); - queue_work(priv->wq, &priv->cm.rx_reap_task); + queue_work(ipoib_workqueue, &priv->cm.rx_reap_task); } return; } @@ -827,7 +827,7 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) { list_move(&tx->list, &priv->cm.reap_list); - queue_work(priv->wq, &priv->cm.reap_task); + queue_work(ipoib_workqueue, &priv->cm.reap_task); } clear_bit(IPOIB_FLAG_OPER_UP, &tx->flags); @@ -1255,7 +1255,7 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id, if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) { list_move(&tx->list, &priv->cm.reap_list); - queue_work(priv->wq, &priv->cm.reap_task); + queue_work(ipoib_workqueue, &priv->cm.reap_task); } spin_unlock_irqrestore(&priv->lock, flags); @@ -1284,7 +1284,7 @@ struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path tx->dev = dev; list_add(&tx->list, &priv->cm.start_list); set_bit(IPOIB_FLAG_INITIALIZED, &tx->flags); - queue_work(priv->wq, &priv->cm.start_task); + queue_work(ipoib_workqueue, &priv->cm.start_task); return tx; } @@ -1295,7 +1295,7 @@ void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx) if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) { spin_lock_irqsave(&priv->lock, flags); list_move(&tx->list, &priv->cm.reap_list); - queue_work(priv->wq, &priv->cm.reap_task); + queue_work(ipoib_workqueue, &priv->cm.reap_task); ipoib_dbg(priv, "Reap connection for gid %pI6\n", tx->neigh->daddr + 4); tx->neigh = NULL; @@ -1417,7 +1417,7 @@ void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb, skb_queue_tail(&priv->cm.skb_queue, skb); if (e) - queue_work(priv->wq, &priv->cm.skb_task); + queue_work(ipoib_workqueue, &priv->cm.skb_task); } static void ipoib_cm_rx_reap(struct work_struct *work) @@ -1450,7 +1450,7 @@ static void ipoib_cm_stale_task(struct work_struct *work) } if (!list_empty(&priv->cm.passive_ids)) - queue_delayed_work(priv->wq, + queue_delayed_work(ipoib_workqueue, &priv->cm.stale_task, IPOIB_CM_RX_DELAY); spin_unlock_irq(&priv->lock); } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index fe65abb5150c..72626c348174 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -655,7 +655,7 @@ void ipoib_reap_ah(struct work_struct *work) __ipoib_reap_ah(dev); if (!test_bit(IPOIB_STOP_REAPER, &priv->flags)) - queue_delayed_work(priv->wq, &priv->ah_reap_task, + queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task, round_jiffies_relative(HZ)); } @@ -664,7 +664,7 @@ static void ipoib_ib_tx_timer_func(unsigned long ctx) drain_tx_cq((struct net_device *)ctx); } -int ipoib_ib_dev_open(struct net_device *dev) +int ipoib_ib_dev_open(struct net_device *dev, int flush) { struct ipoib_dev_priv *priv = netdev_priv(dev); int ret; @@ -696,7 +696,7 @@ int ipoib_ib_dev_open(struct net_device *dev) } clear_bit(IPOIB_STOP_REAPER, &priv->flags); - queue_delayed_work(priv->wq, &priv->ah_reap_task, + queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task, round_jiffies_relative(HZ)); if (!test_and_set_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) @@ -706,7 +706,7 @@ int ipoib_ib_dev_open(struct net_device *dev) dev_stop: if (!test_and_set_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) napi_enable(&priv->napi); - ipoib_ib_dev_stop(dev); + ipoib_ib_dev_stop(dev, flush); return -1; } @@ -738,7 +738,7 @@ int ipoib_ib_dev_up(struct net_device *dev) return ipoib_mcast_start_thread(dev); } -int ipoib_ib_dev_down(struct net_device *dev) +int ipoib_ib_dev_down(struct net_device *dev, int flush) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -747,7 +747,7 @@ int ipoib_ib_dev_down(struct net_device *dev) clear_bit(IPOIB_FLAG_OPER_UP, &priv->flags); netif_carrier_off(dev); - ipoib_mcast_stop_thread(dev); + ipoib_mcast_stop_thread(dev, flush); ipoib_mcast_dev_flush(dev); ipoib_flush_paths(dev); @@ -807,7 +807,7 @@ void ipoib_drain_cq(struct net_device *dev) local_bh_enable(); } -int ipoib_ib_dev_stop(struct net_device *dev) +int ipoib_ib_dev_stop(struct net_device *dev, int flush) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_qp_attr qp_attr; @@ -880,7 +880,8 @@ timeout: /* Wait for all AHs to be reaped */ set_bit(IPOIB_STOP_REAPER, &priv->flags); cancel_delayed_work(&priv->ah_reap_task); - flush_workqueue(priv->wq); + if (flush) + flush_workqueue(ipoib_workqueue); begin = jiffies; @@ -917,7 +918,7 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port) (unsigned long) dev); if (dev->flags & IFF_UP) { - if (ipoib_ib_dev_open(dev)) { + if (ipoib_ib_dev_open(dev, 1)) { ipoib_transport_dev_cleanup(dev); return -ENODEV; } @@ -1039,12 +1040,12 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, } if (level >= IPOIB_FLUSH_NORMAL) - ipoib_ib_dev_down(dev); + ipoib_ib_dev_down(dev, 0); if (level == IPOIB_FLUSH_HEAVY) { if (test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) - ipoib_ib_dev_stop(dev); - if (ipoib_ib_dev_open(dev) != 0) + ipoib_ib_dev_stop(dev, 0); + if (ipoib_ib_dev_open(dev, 0) != 0) return; if (netif_queue_stopped(dev)) netif_start_queue(dev); @@ -1096,7 +1097,7 @@ void ipoib_ib_dev_cleanup(struct net_device *dev) */ ipoib_flush_paths(dev); - ipoib_mcast_stop_thread(dev); + ipoib_mcast_stop_thread(dev, 1); ipoib_mcast_dev_flush(dev); ipoib_transport_dev_cleanup(dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 6bad17d4d588..58b5aa3b6f2d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -108,7 +108,7 @@ int ipoib_open(struct net_device *dev) set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); - if (ipoib_ib_dev_open(dev)) { + if (ipoib_ib_dev_open(dev, 1)) { if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) return 0; goto err_disable; @@ -139,7 +139,7 @@ int ipoib_open(struct net_device *dev) return 0; err_stop: - ipoib_ib_dev_stop(dev); + ipoib_ib_dev_stop(dev, 1); err_disable: clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); @@ -157,8 +157,8 @@ static int ipoib_stop(struct net_device *dev) netif_stop_queue(dev); - ipoib_ib_dev_down(dev); - ipoib_ib_dev_stop(dev); + ipoib_ib_dev_down(dev, 1); + ipoib_ib_dev_stop(dev, 0); if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { struct ipoib_dev_priv *cpriv; @@ -839,7 +839,7 @@ static void ipoib_set_mcast_list(struct net_device *dev) return; } - queue_work(priv->wq, &priv->restart_task); + queue_work(ipoib_workqueue, &priv->restart_task); } static u32 ipoib_addr_hash(struct ipoib_neigh_hash *htbl, u8 *daddr) @@ -954,7 +954,7 @@ static void ipoib_reap_neigh(struct work_struct *work) __ipoib_reap_neigh(priv); if (!test_bit(IPOIB_STOP_NEIGH_GC, &priv->flags)) - queue_delayed_work(priv->wq, &priv->neigh_reap_task, + queue_delayed_work(ipoib_workqueue, &priv->neigh_reap_task, arp_tbl.gc_interval); } @@ -1133,7 +1133,7 @@ static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv) /* start garbage collection */ clear_bit(IPOIB_STOP_NEIGH_GC, &priv->flags); - queue_delayed_work(priv->wq, &priv->neigh_reap_task, + queue_delayed_work(ipoib_workqueue, &priv->neigh_reap_task, arp_tbl.gc_interval); return 0; @@ -1262,13 +1262,15 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) { struct ipoib_dev_priv *priv = netdev_priv(dev); + if (ipoib_neigh_hash_init(priv) < 0) + goto out; /* Allocate RX/TX "rings" to hold queued skbs */ priv->rx_ring = kzalloc(ipoib_recvq_size * sizeof *priv->rx_ring, GFP_KERNEL); if (!priv->rx_ring) { printk(KERN_WARNING "%s: failed to allocate RX ring (%d entries)\n", ca->name, ipoib_recvq_size); - goto out; + goto out_neigh_hash_cleanup; } priv->tx_ring = vzalloc(ipoib_sendq_size * sizeof *priv->tx_ring); @@ -1283,24 +1285,16 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) if (ipoib_ib_dev_init(dev, ca, port)) goto out_tx_ring_cleanup; - /* - * Must be after ipoib_ib_dev_init so we can allocate a per - * device wq there and use it here - */ - if (ipoib_neigh_hash_init(priv) < 0) - goto out_dev_uninit; - return 0; -out_dev_uninit: - ipoib_ib_dev_cleanup(dev); - out_tx_ring_cleanup: vfree(priv->tx_ring); out_rx_ring_cleanup: kfree(priv->rx_ring); +out_neigh_hash_cleanup: + ipoib_neigh_hash_uninit(dev); out: return -ENOMEM; } @@ -1323,12 +1317,6 @@ void ipoib_dev_cleanup(struct net_device *dev) } unregister_netdevice_many(&head); - /* - * Must be before ipoib_ib_dev_cleanup or we delete an in use - * work queue - */ - ipoib_neigh_hash_uninit(dev); - ipoib_ib_dev_cleanup(dev); kfree(priv->rx_ring); @@ -1336,6 +1324,8 @@ void ipoib_dev_cleanup(struct net_device *dev) priv->rx_ring = NULL; priv->tx_ring = NULL; + + ipoib_neigh_hash_uninit(dev); } static const struct header_ops ipoib_header_ops = { @@ -1646,7 +1636,7 @@ register_failed: /* Stop GC if started before flush */ set_bit(IPOIB_STOP_NEIGH_GC, &priv->flags); cancel_delayed_work(&priv->neigh_reap_task); - flush_workqueue(priv->wq); + flush_workqueue(ipoib_workqueue); event_failed: ipoib_dev_cleanup(priv->dev); @@ -1717,7 +1707,7 @@ static void ipoib_remove_one(struct ib_device *device) /* Stop GC */ set_bit(IPOIB_STOP_NEIGH_GC, &priv->flags); cancel_delayed_work(&priv->neigh_reap_task); - flush_workqueue(priv->wq); + flush_workqueue(ipoib_workqueue); unregister_netdev(priv->dev); free_netdev(priv->dev); @@ -1758,13 +1748,8 @@ static int __init ipoib_init_module(void) * unregister_netdev() and linkwatch_event take the rtnl lock, * so flush_scheduled_work() can deadlock during device * removal. - * - * In addition, bringing one device up and another down at the - * same time can deadlock a single workqueue, so we have this - * global fallback workqueue, but we also attempt to open a - * per device workqueue each time we bring an interface up */ - ipoib_workqueue = create_singlethread_workqueue("ipoib_flush"); + ipoib_workqueue = create_singlethread_workqueue("ipoib"); if (!ipoib_workqueue) { ret = -ENOMEM; goto err_fs; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index bc50dd0d0e4d..ffb83b5f7e80 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -190,6 +190,12 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, spin_unlock_irq(&priv->lock); priv->tx_wr.wr.ud.remote_qkey = priv->qkey; set_qkey = 1; + + if (!ipoib_cm_admin_enabled(dev)) { + rtnl_lock(); + dev_set_mtu(dev, min(priv->mcast_mtu, priv->admin_mtu)); + rtnl_unlock(); + } } if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { @@ -271,27 +277,16 @@ ipoib_mcast_sendonly_join_complete(int status, struct ipoib_mcast *mcast = multicast->context; struct net_device *dev = mcast->dev; - /* - * We have to take the mutex to force mcast_sendonly_join to - * return from ib_sa_multicast_join and set mcast->mc to a - * valid value. Otherwise we were racing with ourselves in - * that we might fail here, but get a valid return from - * ib_sa_multicast_join after we had cleared mcast->mc here, - * resulting in mis-matched joins and leaves and a deadlock - */ - mutex_lock(&mcast_mutex); - /* We trap for port events ourselves. */ if (status == -ENETRESET) - goto out; + return 0; if (!status) status = ipoib_mcast_join_finish(mcast, &multicast->rec); if (status) { if (mcast->logcount++ < 20) - ipoib_dbg_mcast(netdev_priv(dev), "sendonly multicast " - "join failed for %pI6, status %d\n", + ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for %pI6, status %d\n", mcast->mcmember.mgid.raw, status); /* Flush out any queued packets */ @@ -301,15 +296,11 @@ ipoib_mcast_sendonly_join_complete(int status, dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue)); } netif_tx_unlock_bh(dev); + + /* Clear the busy flag so we try again */ + status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, + &mcast->flags); } -out: - clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); - if (status) - mcast->mc = NULL; - complete(&mcast->done); - if (status == -ENETRESET) - status = 0; - mutex_unlock(&mcast_mutex); return status; } @@ -327,14 +318,12 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) int ret = 0; if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) { - ipoib_dbg_mcast(priv, "device shutting down, no sendonly " - "multicast joins\n"); + ipoib_dbg_mcast(priv, "device shutting down, no multicast joins\n"); return -ENODEV; } - if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) { - ipoib_dbg_mcast(priv, "multicast entry busy, skipping " - "sendonly join\n"); + if (test_and_set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) { + ipoib_dbg_mcast(priv, "multicast entry busy, skipping\n"); return -EBUSY; } @@ -342,9 +331,6 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) rec.port_gid = priv->local_gid; rec.pkey = cpu_to_be16(priv->pkey); - mutex_lock(&mcast_mutex); - init_completion(&mcast->done); - set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port, &rec, IB_SA_MCMEMBER_REC_MGID | @@ -357,14 +343,12 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) if (IS_ERR(mcast->mc)) { ret = PTR_ERR(mcast->mc); clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); - complete(&mcast->done); - ipoib_warn(priv, "ib_sa_join_multicast for sendonly join " - "failed (ret = %d)\n", ret); + ipoib_warn(priv, "ib_sa_join_multicast failed (ret = %d)\n", + ret); } else { - ipoib_dbg_mcast(priv, "no multicast record for %pI6, starting " - "sendonly join\n", mcast->mcmember.mgid.raw); + ipoib_dbg_mcast(priv, "no multicast record for %pI6, starting join\n", + mcast->mcmember.mgid.raw); } - mutex_unlock(&mcast_mutex); return ret; } @@ -375,29 +359,18 @@ void ipoib_mcast_carrier_on_task(struct work_struct *work) carrier_on_task); struct ib_port_attr attr; + /* + * Take rtnl_lock to avoid racing with ipoib_stop() and + * turning the carrier back on while a device is being + * removed. + */ if (ib_query_port(priv->ca, priv->port, &attr) || attr.state != IB_PORT_ACTIVE) { ipoib_dbg(priv, "Keeping carrier off until IB port is active\n"); return; } - /* - * Take rtnl_lock to avoid racing with ipoib_stop() and - * turning the carrier back on while a device is being - * removed. However, ipoib_stop() will attempt to flush - * the workqueue while holding the rtnl lock, so loop - * on trylock until either we get the lock or we see - * FLAG_ADMIN_UP go away as that signals that we are bailing - * and can safely ignore the carrier on work. - */ - while (!rtnl_trylock()) { - if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) - return; - else - msleep(20); - } - if (!ipoib_cm_admin_enabled(priv->dev)) - dev_set_mtu(priv->dev, min(priv->mcast_mtu, priv->admin_mtu)); + rtnl_lock(); netif_carrier_on(priv->dev); rtnl_unlock(); } @@ -412,63 +385,60 @@ static int ipoib_mcast_join_complete(int status, ipoib_dbg_mcast(priv, "join completion for %pI6 (status %d)\n", mcast->mcmember.mgid.raw, status); - /* - * We have to take the mutex to force mcast_join to - * return from ib_sa_multicast_join and set mcast->mc to a - * valid value. Otherwise we were racing with ourselves in - * that we might fail here, but get a valid return from - * ib_sa_multicast_join after we had cleared mcast->mc here, - * resulting in mis-matched joins and leaves and a deadlock - */ - mutex_lock(&mcast_mutex); - /* We trap for port events ourselves. */ - if (status == -ENETRESET) + if (status == -ENETRESET) { + status = 0; goto out; + } if (!status) status = ipoib_mcast_join_finish(mcast, &multicast->rec); if (!status) { mcast->backoff = 1; + mutex_lock(&mcast_mutex); if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) - queue_delayed_work(priv->wq, &priv->mcast_task, 0); + queue_delayed_work(ipoib_workqueue, + &priv->mcast_task, 0); + mutex_unlock(&mcast_mutex); /* - * Defer carrier on work to priv->wq to avoid a + * Defer carrier on work to ipoib_workqueue to avoid a * deadlock on rtnl_lock here. */ if (mcast == priv->broadcast) - queue_work(priv->wq, &priv->carrier_on_task); - } else { - if (mcast->logcount++ < 20) { - if (status == -ETIMEDOUT || status == -EAGAIN) { - ipoib_dbg_mcast(priv, "multicast join failed for %pI6, status %d\n", - mcast->mcmember.mgid.raw, status); - } else { - ipoib_warn(priv, "multicast join failed for %pI6, status %d\n", - mcast->mcmember.mgid.raw, status); - } - } + queue_work(ipoib_workqueue, &priv->carrier_on_task); - mcast->backoff *= 2; - if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) - mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS; - } -out: - spin_lock_irq(&priv->lock); - clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); - if (status) - mcast->mc = NULL; - complete(&mcast->done); - if (status == -ENETRESET) status = 0; - if (status && test_bit(IPOIB_MCAST_RUN, &priv->flags)) - queue_delayed_work(priv->wq, &priv->mcast_task, + goto out; + } + + if (mcast->logcount++ < 20) { + if (status == -ETIMEDOUT || status == -EAGAIN) { + ipoib_dbg_mcast(priv, "multicast join failed for %pI6, status %d\n", + mcast->mcmember.mgid.raw, status); + } else { + ipoib_warn(priv, "multicast join failed for %pI6, status %d\n", + mcast->mcmember.mgid.raw, status); + } + } + + mcast->backoff *= 2; + if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) + mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS; + + /* Clear the busy flag so we try again */ + status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + + mutex_lock(&mcast_mutex); + spin_lock_irq(&priv->lock); + if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) + queue_delayed_work(ipoib_workqueue, &priv->mcast_task, mcast->backoff * HZ); spin_unlock_irq(&priv->lock); mutex_unlock(&mcast_mutex); - +out: + complete(&mcast->done); return status; } @@ -517,9 +487,10 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, rec.hop_limit = priv->broadcast->mcmember.hop_limit; } - mutex_lock(&mcast_mutex); - init_completion(&mcast->done); set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + init_completion(&mcast->done); + set_bit(IPOIB_MCAST_JOIN_STARTED, &mcast->flags); + mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port, &rec, comp_mask, GFP_KERNEL, ipoib_mcast_join_complete, mcast); @@ -533,11 +504,13 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS; + mutex_lock(&mcast_mutex); if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) - queue_delayed_work(priv->wq, &priv->mcast_task, + queue_delayed_work(ipoib_workqueue, + &priv->mcast_task, mcast->backoff * HZ); + mutex_unlock(&mcast_mutex); } - mutex_unlock(&mcast_mutex); } void ipoib_mcast_join_task(struct work_struct *work) @@ -574,8 +547,8 @@ void ipoib_mcast_join_task(struct work_struct *work) ipoib_warn(priv, "failed to allocate broadcast group\n"); mutex_lock(&mcast_mutex); if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) - queue_delayed_work(priv->wq, &priv->mcast_task, - HZ); + queue_delayed_work(ipoib_workqueue, + &priv->mcast_task, HZ); mutex_unlock(&mcast_mutex); return; } @@ -590,8 +563,7 @@ void ipoib_mcast_join_task(struct work_struct *work) } if (!test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { - if (IS_ERR_OR_NULL(priv->broadcast->mc) && - !test_bit(IPOIB_MCAST_FLAG_BUSY, &priv->broadcast->flags)) + if (!test_bit(IPOIB_MCAST_FLAG_BUSY, &priv->broadcast->flags)) ipoib_mcast_join(dev, priv->broadcast, 0); return; } @@ -599,33 +571,23 @@ void ipoib_mcast_join_task(struct work_struct *work) while (1) { struct ipoib_mcast *mcast = NULL; - /* - * Need the mutex so our flags are consistent, need the - * priv->lock so we don't race with list removals in either - * mcast_dev_flush or mcast_restart_task - */ - mutex_lock(&mcast_mutex); spin_lock_irq(&priv->lock); list_for_each_entry(mcast, &priv->multicast_list, list) { - if (IS_ERR_OR_NULL(mcast->mc) && - !test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags) && - !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { + if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags) + && !test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags) + && !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { /* Found the next unjoined group */ break; } } spin_unlock_irq(&priv->lock); - mutex_unlock(&mcast_mutex); if (&mcast->list == &priv->multicast_list) { /* All done */ break; } - if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) - ipoib_mcast_sendonly_join(mcast); - else - ipoib_mcast_join(dev, mcast, 1); + ipoib_mcast_join(dev, mcast, 1); return; } @@ -642,13 +604,13 @@ int ipoib_mcast_start_thread(struct net_device *dev) mutex_lock(&mcast_mutex); if (!test_and_set_bit(IPOIB_MCAST_RUN, &priv->flags)) - queue_delayed_work(priv->wq, &priv->mcast_task, 0); + queue_delayed_work(ipoib_workqueue, &priv->mcast_task, 0); mutex_unlock(&mcast_mutex); return 0; } -int ipoib_mcast_stop_thread(struct net_device *dev) +int ipoib_mcast_stop_thread(struct net_device *dev, int flush) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -659,7 +621,8 @@ int ipoib_mcast_stop_thread(struct net_device *dev) cancel_delayed_work(&priv->mcast_task); mutex_unlock(&mcast_mutex); - flush_workqueue(priv->wq); + if (flush) + flush_workqueue(ipoib_workqueue); return 0; } @@ -670,9 +633,6 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast) int ret = 0; if (test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) - ipoib_warn(priv, "ipoib_mcast_leave on an in-flight join\n"); - - if (!IS_ERR_OR_NULL(mcast->mc)) ib_sa_free_multicast(mcast->mc); if (test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { @@ -725,8 +685,6 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb) memcpy(mcast->mcmember.mgid.raw, mgid, sizeof (union ib_gid)); __ipoib_mcast_add(dev, mcast); list_add_tail(&mcast->list, &priv->multicast_list); - if (!test_and_set_bit(IPOIB_MCAST_RUN, &priv->flags)) - queue_delayed_work(priv->wq, &priv->mcast_task, 0); } if (!mcast->ah) { @@ -740,6 +698,8 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb) if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) ipoib_dbg_mcast(priv, "no address vector, " "but multicast join already started\n"); + else if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) + ipoib_mcast_sendonly_join(mcast); /* * If lookup completes between here and out:, don't @@ -799,12 +759,9 @@ void ipoib_mcast_dev_flush(struct net_device *dev) spin_unlock_irqrestore(&priv->lock, flags); - /* - * make sure the in-flight joins have finished before we attempt - * to leave - */ + /* seperate between the wait to the leave*/ list_for_each_entry_safe(mcast, tmcast, &remove_list, list) - if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) + if (test_bit(IPOIB_MCAST_JOIN_STARTED, &mcast->flags)) wait_for_completion(&mcast->done); list_for_each_entry_safe(mcast, tmcast, &remove_list, list) { @@ -837,6 +794,8 @@ void ipoib_mcast_restart_task(struct work_struct *work) ipoib_dbg_mcast(priv, "restarting multicast task\n"); + ipoib_mcast_stop_thread(dev, 0); + local_irq_save(flags); netif_addr_lock(dev); spin_lock(&priv->lock); @@ -921,38 +880,14 @@ void ipoib_mcast_restart_task(struct work_struct *work) netif_addr_unlock(dev); local_irq_restore(flags); - /* - * make sure the in-flight joins have finished before we attempt - * to leave - */ - list_for_each_entry_safe(mcast, tmcast, &remove_list, list) - if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) - wait_for_completion(&mcast->done); - - /* - * We have to cancel outside of the spinlock, but we have to - * take the rtnl lock or else we race with the removal of - * entries from the remove list in mcast_dev_flush as part - * of ipoib_stop(). We detect the drop of the ADMIN_UP flag - * to signal that we have hit this particular race, and we - * return since we know we don't need to do anything else - * anyway. - */ - while (!rtnl_trylock()) { - if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) - return; - else - msleep(20); - } + /* We have to cancel outside of the spinlock */ list_for_each_entry_safe(mcast, tmcast, &remove_list, list) { ipoib_mcast_leave(mcast->dev, mcast); ipoib_mcast_free(mcast); } - /* - * Restart our join task if needed - */ - ipoib_mcast_start_thread(dev); - rtnl_unlock(); + + if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) + ipoib_mcast_start_thread(dev); } #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index b72a753eb41d..c56d5d44c53b 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -145,20 +145,10 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) int ret, size; int i; - /* - * the various IPoIB tasks assume they will never race against - * themselves, so always use a single thread workqueue - */ - priv->wq = create_singlethread_workqueue("ipoib_wq"); - if (!priv->wq) { - printk(KERN_WARNING "ipoib: failed to allocate device WQ\n"); - return -ENODEV; - } - priv->pd = ib_alloc_pd(priv->ca); if (IS_ERR(priv->pd)) { printk(KERN_WARNING "%s: failed to allocate PD\n", ca->name); - goto out_free_wq; + return -ENODEV; } priv->mr = ib_get_dma_mr(priv->pd, IB_ACCESS_LOCAL_WRITE); @@ -252,10 +242,6 @@ out_free_mr: out_free_pd: ib_dealloc_pd(priv->pd); - -out_free_wq: - destroy_workqueue(priv->wq); - priv->wq = NULL; return -ENODEV; } @@ -284,12 +270,6 @@ void ipoib_transport_dev_cleanup(struct net_device *dev) if (ib_dealloc_pd(priv->pd)) ipoib_warn(priv, "ib_dealloc_pd failed\n"); - - if (priv->wq) { - flush_workqueue(priv->wq); - destroy_workqueue(priv->wq); - priv->wq = NULL; - } } void ipoib_event(struct ib_event_handler *handler, diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 18d4b2c8fe55..a18f41b89b6a 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -62,26 +62,6 @@ struct evdev_client { struct input_event buffer[]; }; -static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) -{ - switch (clkid) { - - case CLOCK_REALTIME: - client->clk_type = EV_CLK_REAL; - break; - case CLOCK_MONOTONIC: - client->clk_type = EV_CLK_MONO; - break; - case CLOCK_BOOTTIME: - client->clk_type = EV_CLK_BOOT; - break; - default: - return -EINVAL; - } - - return 0; -} - /* flush queued events of type @type, caller must hold client->buffer_lock */ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) { @@ -128,10 +108,8 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) client->head = head; } -/* queue SYN_DROPPED event */ -static void evdev_queue_syn_dropped(struct evdev_client *client) +static void __evdev_queue_syn_dropped(struct evdev_client *client) { - unsigned long flags; struct input_event ev; ktime_t time; @@ -146,8 +124,6 @@ static void evdev_queue_syn_dropped(struct evdev_client *client) ev.code = SYN_DROPPED; ev.value = 0; - spin_lock_irqsave(&client->buffer_lock, flags); - client->buffer[client->head++] = ev; client->head &= client->bufsize - 1; @@ -156,8 +132,53 @@ static void evdev_queue_syn_dropped(struct evdev_client *client) client->tail = (client->head - 1) & (client->bufsize - 1); client->packet_head = client->tail; } +} + +static void evdev_queue_syn_dropped(struct evdev_client *client) +{ + unsigned long flags; + + spin_lock_irqsave(&client->buffer_lock, flags); + __evdev_queue_syn_dropped(client); + spin_unlock_irqrestore(&client->buffer_lock, flags); +} + +static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) +{ + unsigned long flags; + + if (client->clk_type == clkid) + return 0; + + switch (clkid) { + + case CLOCK_REALTIME: + client->clk_type = EV_CLK_REAL; + break; + case CLOCK_MONOTONIC: + client->clk_type = EV_CLK_MONO; + break; + case CLOCK_BOOTTIME: + client->clk_type = EV_CLK_BOOT; + break; + default: + return -EINVAL; + } + + /* + * Flush pending events and queue SYN_DROPPED event, + * but only if the queue is not empty. + */ + spin_lock_irqsave(&client->buffer_lock, flags); + + if (client->head != client->tail) { + client->packet_head = client->head = client->tail; + __evdev_queue_syn_dropped(client); + } spin_unlock_irqrestore(&client->buffer_lock, flags); + + return 0; } static void __pass_event(struct evdev_client *client, diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index fbe29fcb15c5..cb150a1dbaff 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -293,7 +293,7 @@ void input_mt_sync_frame(struct input_dev *dev) } EXPORT_SYMBOL(input_mt_sync_frame); -static int adjust_dual(int *begin, int step, int *end, int eq) +static int adjust_dual(int *begin, int step, int *end, int eq, int mu) { int f, *p, s, c; @@ -311,9 +311,10 @@ static int adjust_dual(int *begin, int step, int *end, int eq) s = *p; c = (f + s + 1) / 2; - if (c == 0 || (c > 0 && !eq)) + if (c == 0 || (c > mu && (!eq || mu > 0))) return 0; - if (s < 0) + /* Improve convergence for positive matrices by penalizing overcovers */ + if (s < 0 && mu <= 0) c *= 2; for (p = begin; p != end; p += step) @@ -322,23 +323,24 @@ static int adjust_dual(int *begin, int step, int *end, int eq) return (c < s && s <= 0) || (f >= 0 && f < c); } -static void find_reduced_matrix(int *w, int nr, int nc, int nrc) +static void find_reduced_matrix(int *w, int nr, int nc, int nrc, int mu) { int i, k, sum; for (k = 0; k < nrc; k++) { for (i = 0; i < nr; i++) - adjust_dual(w + i, nr, w + i + nrc, nr <= nc); + adjust_dual(w + i, nr, w + i + nrc, nr <= nc, mu); sum = 0; for (i = 0; i < nrc; i += nr) - sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr); + sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr, mu); if (!sum) break; } } static int input_mt_set_matrix(struct input_mt *mt, - const struct input_mt_pos *pos, int num_pos) + const struct input_mt_pos *pos, int num_pos, + int mu) { const struct input_mt_pos *p; struct input_mt_slot *s; @@ -352,7 +354,7 @@ static int input_mt_set_matrix(struct input_mt *mt, y = input_mt_get_value(s, ABS_MT_POSITION_Y); for (p = pos; p != pos + num_pos; p++) { int dx = x - p->x, dy = y - p->y; - *w++ = dx * dx + dy * dy; + *w++ = dx * dx + dy * dy - mu; } } @@ -393,17 +395,24 @@ static void input_mt_set_slots(struct input_mt *mt, * @slots: the slot assignment to be filled * @pos: the position array to match * @num_pos: number of positions + * @dmax: maximum ABS_MT_POSITION displacement (zero for infinite) * * Performs a best match against the current contacts and returns * the slot assignment list. New contacts are assigned to unused * slots. * + * The assignments are balanced so that all coordinate displacements are + * below the euclidian distance dmax. If no such assignment can be found, + * some contacts are assigned to unused slots. + * * Returns zero on success, or negative error in case of failure. */ int input_mt_assign_slots(struct input_dev *dev, int *slots, - const struct input_mt_pos *pos, int num_pos) + const struct input_mt_pos *pos, int num_pos, + int dmax) { struct input_mt *mt = dev->mt; + int mu = 2 * dmax * dmax; int nrc; if (!mt || !mt->red) @@ -413,8 +422,8 @@ int input_mt_assign_slots(struct input_dev *dev, int *slots, if (num_pos < 1) return 0; - nrc = input_mt_set_matrix(mt, pos, num_pos); - find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc); + nrc = input_mt_set_matrix(mt, pos, num_pos, mu); + find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc, mu); input_mt_set_slots(mt, slots, num_pos); return 0; diff --git a/drivers/input/input.c b/drivers/input/input.c index 213e3a1903ee..cc357f1516a7 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -100,23 +100,24 @@ static unsigned int input_to_handler(struct input_handle *handle, struct input_value *end = vals; struct input_value *v; - for (v = vals; v != vals + count; v++) { - if (handler->filter && - handler->filter(handle, v->type, v->code, v->value)) - continue; - if (end != v) - *end = *v; - end++; + if (handler->filter) { + for (v = vals; v != vals + count; v++) { + if (handler->filter(handle, v->type, v->code, v->value)) + continue; + if (end != v) + *end = *v; + end++; + } + count = end - vals; } - count = end - vals; if (!count) return 0; if (handler->events) handler->events(handle, vals, count); else if (handler->event) - for (v = vals; v != end; v++) + for (v = vals; v != vals + count; v++) handler->event(handle, v->type, v->code, v->value); return count; @@ -143,8 +144,11 @@ static void input_pass_values(struct input_dev *dev, count = input_to_handler(handle, vals, count); } else { list_for_each_entry_rcu(handle, &dev->h_list, d_node) - if (handle->open) + if (handle->open) { count = input_to_handler(handle, vals, count); + if (!count) + break; + } } rcu_read_unlock(); @@ -152,12 +156,14 @@ static void input_pass_values(struct input_dev *dev, add_input_randomness(vals->type, vals->code, vals->value); /* trigger auto repeat for key events */ - for (v = vals; v != vals + count; v++) { - if (v->type == EV_KEY && v->value != 2) { - if (v->value) - input_start_autorepeat(dev, v->code); - else - input_stop_autorepeat(dev); + if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) { + for (v = vals; v != vals + count; v++) { + if (v->type == EV_KEY && v->value != 2) { + if (v->value) + input_start_autorepeat(dev, v->code); + else + input_stop_autorepeat(dev); + } } } } diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index a5d9b3f3c871..a89ba7cb96f1 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -568,6 +568,16 @@ config KEYBOARD_STMPE To compile this driver as a module, choose M here: the module will be called stmpe-keypad. +config KEYBOARD_SUN4I_LRADC + tristate "Allwinner sun4i low res adc attached tablet keys support" + depends on ARCH_SUNXI + help + This selects support for the Allwinner low res adc attached tablet + keys found on Allwinner sunxi SoCs. + + To compile this driver as a module, choose M here: the + module will be called sun4i-lradc-keys. + config KEYBOARD_DAVINCI tristate "TI DaVinci Key Scan" depends on ARCH_DAVINCI_DM365 diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index febafa527eb6..470767884bd8 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.o +obj-$(CONFIG_KEYBOARD_SUN4I_LRADC) += sun4i-lradc-keys.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c index 10bcd4ae5402..f1235831283d 100644 --- a/drivers/input/keyboard/atakbd.c +++ b/drivers/input/keyboard/atakbd.c @@ -170,7 +170,7 @@ static unsigned char atakbd_keycode[0x72] = { /* American layout */ [93] = KEY_KPASTERISK, [94] = KEY_KPPLUS, [95] = KEY_HELP, - [96] = KEY_BACKSLASH, /* FIXME: '<' */ + [96] = KEY_102ND, [97] = KEY_KPASTERISK, /* FIXME */ [98] = KEY_KPSLASH, [99] = KEY_KPLEFTPAREN, diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c index 4f59f0bab28f..f07461a64d85 100644 --- a/drivers/input/keyboard/cap11xx.c +++ b/drivers/input/keyboard/cap11xx.c @@ -370,7 +370,6 @@ static struct i2c_driver cap11xx_i2c_driver = { module_i2c_driver(cap11xx_i2c_driver); -MODULE_ALIAS("platform:cap11xx"); MODULE_DESCRIPTION("Microchip CAP11XX driver"); MODULE_AUTHOR("Daniel Mack "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index e53f232eda0e..2e855e6f3565 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -448,8 +448,7 @@ static int imx_keypad_probe(struct platform_device *pdev) return -ENOMEM; } - keypad = devm_kzalloc(&pdev->dev, sizeof(struct imx_keypad), - GFP_KERNEL); + keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL); if (!keypad) { dev_err(&pdev->dev, "not enough memory for driver data\n"); return -ENOMEM; diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index a90d6bdc499e..a89488aa1aa4 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -28,10 +29,6 @@ #include #include -#include -#include - -#include #include /* * Keypad Controller registers diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c new file mode 100644 index 000000000000..cc8f7ddcee53 --- /dev/null +++ b/drivers/input/keyboard/sun4i-lradc-keys.c @@ -0,0 +1,286 @@ +/* + * Allwinner sun4i low res adc attached tablet keys driver + * + * Copyright (C) 2014 Hans de Goede + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Allwinnner sunxi SoCs have a lradc which is specifically designed to have + * various (tablet) keys (ie home, back, search, etc). attached to it using + * a resistor network. This driver is for the keys on such boards. + * + * There are 2 channels, currently this driver only supports channel 0 since + * there are no boards known to use channel 1. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LRADC_CTRL 0x00 +#define LRADC_INTC 0x04 +#define LRADC_INTS 0x08 +#define LRADC_DATA0 0x0c +#define LRADC_DATA1 0x10 + +/* LRADC_CTRL bits */ +#define FIRST_CONVERT_DLY(x) ((x) << 24) /* 8 bits */ +#define CHAN_SELECT(x) ((x) << 22) /* 2 bits */ +#define CONTINUE_TIME_SEL(x) ((x) << 16) /* 4 bits */ +#define KEY_MODE_SEL(x) ((x) << 12) /* 2 bits */ +#define LEVELA_B_CNT(x) ((x) << 8) /* 4 bits */ +#define HOLD_EN(x) ((x) << 6) +#define LEVELB_VOL(x) ((x) << 4) /* 2 bits */ +#define SAMPLE_RATE(x) ((x) << 2) /* 2 bits */ +#define ENABLE(x) ((x) << 0) + +/* LRADC_INTC and LRADC_INTS bits */ +#define CHAN1_KEYUP_IRQ BIT(12) +#define CHAN1_ALRDY_HOLD_IRQ BIT(11) +#define CHAN1_HOLD_IRQ BIT(10) +#define CHAN1_KEYDOWN_IRQ BIT(9) +#define CHAN1_DATA_IRQ BIT(8) +#define CHAN0_KEYUP_IRQ BIT(4) +#define CHAN0_ALRDY_HOLD_IRQ BIT(3) +#define CHAN0_HOLD_IRQ BIT(2) +#define CHAN0_KEYDOWN_IRQ BIT(1) +#define CHAN0_DATA_IRQ BIT(0) + +struct sun4i_lradc_keymap { + u32 voltage; + u32 keycode; +}; + +struct sun4i_lradc_data { + struct device *dev; + struct input_dev *input; + void __iomem *base; + struct regulator *vref_supply; + struct sun4i_lradc_keymap *chan0_map; + u32 chan0_map_count; + u32 chan0_keycode; + u32 vref; +}; + +static irqreturn_t sun4i_lradc_irq(int irq, void *dev_id) +{ + struct sun4i_lradc_data *lradc = dev_id; + u32 i, ints, val, voltage, diff, keycode = 0, closest = 0xffffffff; + + ints = readl(lradc->base + LRADC_INTS); + + /* + * lradc supports only one keypress at a time, release does not give + * any info as to which key was released, so we cache the keycode. + */ + + if (ints & CHAN0_KEYUP_IRQ) { + input_report_key(lradc->input, lradc->chan0_keycode, 0); + lradc->chan0_keycode = 0; + } + + if ((ints & CHAN0_KEYDOWN_IRQ) && lradc->chan0_keycode == 0) { + val = readl(lradc->base + LRADC_DATA0) & 0x3f; + voltage = val * lradc->vref / 63; + + for (i = 0; i < lradc->chan0_map_count; i++) { + diff = abs(lradc->chan0_map[i].voltage - voltage); + if (diff < closest) { + closest = diff; + keycode = lradc->chan0_map[i].keycode; + } + } + + lradc->chan0_keycode = keycode; + input_report_key(lradc->input, lradc->chan0_keycode, 1); + } + + input_sync(lradc->input); + + writel(ints, lradc->base + LRADC_INTS); + + return IRQ_HANDLED; +} + +static int sun4i_lradc_open(struct input_dev *dev) +{ + struct sun4i_lradc_data *lradc = input_get_drvdata(dev); + int error; + + error = regulator_enable(lradc->vref_supply); + if (error) + return error; + + /* lradc Vref internally is divided by 2/3 */ + lradc->vref = regulator_get_voltage(lradc->vref_supply) * 2 / 3; + + /* + * Set sample time to 4 ms / 250 Hz. Wait 2 * 4 ms for key to + * stabilize on press, wait (1 + 1) * 4 ms for key release + */ + writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) | + SAMPLE_RATE(0) | ENABLE(1), lradc->base + LRADC_CTRL); + + writel(CHAN0_KEYUP_IRQ | CHAN0_KEYDOWN_IRQ, lradc->base + LRADC_INTC); + + return 0; +} + +static void sun4i_lradc_close(struct input_dev *dev) +{ + struct sun4i_lradc_data *lradc = input_get_drvdata(dev); + + /* Disable lradc, leave other settings unchanged */ + writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) | + SAMPLE_RATE(2), lradc->base + LRADC_CTRL); + writel(0, lradc->base + LRADC_INTC); + + regulator_disable(lradc->vref_supply); +} + +static int sun4i_lradc_load_dt_keymap(struct device *dev, + struct sun4i_lradc_data *lradc) +{ + struct device_node *np, *pp; + int i; + int error; + + np = dev->of_node; + if (!np) + return -EINVAL; + + lradc->chan0_map_count = of_get_child_count(np); + if (lradc->chan0_map_count == 0) { + dev_err(dev, "keymap is missing in device tree\n"); + return -EINVAL; + } + + lradc->chan0_map = devm_kmalloc_array(dev, lradc->chan0_map_count, + sizeof(struct sun4i_lradc_keymap), + GFP_KERNEL); + if (!lradc->chan0_map) + return -ENOMEM; + + i = 0; + for_each_child_of_node(np, pp) { + struct sun4i_lradc_keymap *map = &lradc->chan0_map[i]; + u32 channel; + + error = of_property_read_u32(pp, "channel", &channel); + if (error || channel != 0) { + dev_err(dev, "%s: Inval channel prop\n", pp->name); + return -EINVAL; + } + + error = of_property_read_u32(pp, "voltage", &map->voltage); + if (error) { + dev_err(dev, "%s: Inval voltage prop\n", pp->name); + return -EINVAL; + } + + error = of_property_read_u32(pp, "linux,code", &map->keycode); + if (error) { + dev_err(dev, "%s: Inval linux,code prop\n", pp->name); + return -EINVAL; + } + + i++; + } + + return 0; +} + +static int sun4i_lradc_probe(struct platform_device *pdev) +{ + struct sun4i_lradc_data *lradc; + struct device *dev = &pdev->dev; + int i; + int error; + + lradc = devm_kzalloc(dev, sizeof(struct sun4i_lradc_data), GFP_KERNEL); + if (!lradc) + return -ENOMEM; + + error = sun4i_lradc_load_dt_keymap(dev, lradc); + if (error) + return error; + + lradc->vref_supply = devm_regulator_get(dev, "vref"); + if (IS_ERR(lradc->vref_supply)) + return PTR_ERR(lradc->vref_supply); + + lradc->dev = dev; + lradc->input = devm_input_allocate_device(dev); + if (!lradc->input) + return -ENOMEM; + + lradc->input->name = pdev->name; + lradc->input->phys = "sun4i_lradc/input0"; + lradc->input->open = sun4i_lradc_open; + lradc->input->close = sun4i_lradc_close; + lradc->input->id.bustype = BUS_HOST; + lradc->input->id.vendor = 0x0001; + lradc->input->id.product = 0x0001; + lradc->input->id.version = 0x0100; + + __set_bit(EV_KEY, lradc->input->evbit); + for (i = 0; i < lradc->chan0_map_count; i++) + __set_bit(lradc->chan0_map[i].keycode, lradc->input->keybit); + + input_set_drvdata(lradc->input, lradc); + + lradc->base = devm_ioremap_resource(dev, + platform_get_resource(pdev, IORESOURCE_MEM, 0)); + if (IS_ERR(lradc->base)) + return PTR_ERR(lradc->base); + + error = devm_request_irq(dev, platform_get_irq(pdev, 0), + sun4i_lradc_irq, 0, + "sun4i-a10-lradc-keys", lradc); + if (error) + return error; + + error = input_register_device(lradc->input); + if (error) + return error; + + platform_set_drvdata(pdev, lradc); + return 0; +} + +static const struct of_device_id sun4i_lradc_of_match[] = { + { .compatible = "allwinner,sun4i-a10-lradc-keys", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sun4i_lradc_of_match); + +static struct platform_driver sun4i_lradc_driver = { + .driver = { + .name = "sun4i-a10-lradc-keys", + .of_match_table = of_match_ptr(sun4i_lradc_of_match), + }, + .probe = sun4i_lradc_probe, +}; + +module_platform_driver(sun4i_lradc_driver); + +MODULE_DESCRIPTION("Allwinner sun4i low res adc attached tablet keys driver"); +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 23297ab6163f..6deb8dae3205 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -93,6 +93,16 @@ config INPUT_BMA150 To compile this driver as a module, choose M here: the module will be called bma150. +config INPUT_E3X0_BUTTON + tristate "NI Ettus Research USRP E3x0 Button support." + default n + help + Say Y here to enable support for the NI Ettus Research + USRP E3x0 Button. + + To compile this driver as a module, choose M here: the + module will be called e3x0_button. + config INPUT_PCSPKR tristate "PC Speaker support" depends on PCSPKR_PLATFORM @@ -394,6 +404,18 @@ config INPUT_CM109 To compile this driver as a module, choose M here: the module will be called cm109. +config INPUT_REGULATOR_HAPTIC + tristate "Regulator haptics support" + depends on REGULATOR + select INPUT_FF_MEMLESS + help + This option enables device driver support for the haptic controlled + by a regulator. This driver supports ff-memless interface + from input framework. + + To compile this driver as a module, choose M here: the + module will be called regulator-haptic. + config INPUT_RETU_PWRBUTTON tristate "Retu Power button Driver" depends on MFD_RETU @@ -404,6 +426,27 @@ config INPUT_RETU_PWRBUTTON To compile this driver as a module, choose M here. The module will be called retu-pwrbutton. +config INPUT_TPS65218_PWRBUTTON + tristate "TPS65218 Power button driver" + depends on MFD_TPS65218 + help + Say Y here if you want to enable power buttong reporting for + the TPS65218 Power Management IC device. + + To compile this driver as a module, choose M here. The module will + be called tps65218-pwrbutton. + +config INPUT_AXP20X_PEK + tristate "X-Powers AXP20X power button driver" + depends on MFD_AXP20X + help + Say Y here if you want to enable power key reporting via the + AXP20X PMIC. + + To compile this driver as a module, choose M here. The module will + be called axp20x-pek. + + config INPUT_TWL4030_PWRBUTTON tristate "TWL4030 Power button Driver" depends on TWL4030_CORE diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 19c760361f80..403a1a54a76c 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o +obj-$(CONFIG_INPUT_E3X0_BUTTON) += e3x0-button.o obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o @@ -53,12 +54,15 @@ obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o obj-$(CONFIG_INPUT_POWERMATE) += powermate.o obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o +obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o +obj-$(CONFIG_INPUT_AXP20X_PEK) += axp20x-pek.o obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o +obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o obj-$(CONFIG_INPUT_TWL6040_VIBRA) += twl6040-vibra.o diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c new file mode 100644 index 000000000000..f1c844739cd7 --- /dev/null +++ b/drivers/input/misc/axp20x-pek.c @@ -0,0 +1,290 @@ +/* + * axp20x power button driver. + * + * Copyright (C) 2013 Carlo Caione + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AXP20X_PEK_STARTUP_MASK (0xc0) +#define AXP20X_PEK_SHUTDOWN_MASK (0x03) + +struct axp20x_pek { + struct axp20x_dev *axp20x; + struct input_dev *input; + int irq_dbr; + int irq_dbf; +}; + +struct axp20x_time { + unsigned int time; + unsigned int idx; +}; + +static const struct axp20x_time startup_time[] = { + { .time = 128, .idx = 0 }, + { .time = 1000, .idx = 2 }, + { .time = 3000, .idx = 1 }, + { .time = 2000, .idx = 3 }, +}; + +static const struct axp20x_time shutdown_time[] = { + { .time = 4000, .idx = 0 }, + { .time = 6000, .idx = 1 }, + { .time = 8000, .idx = 2 }, + { .time = 10000, .idx = 3 }, +}; + +struct axp20x_pek_ext_attr { + const struct axp20x_time *p_time; + unsigned int mask; +}; + +static struct axp20x_pek_ext_attr axp20x_pek_startup_ext_attr = { + .p_time = startup_time, + .mask = AXP20X_PEK_STARTUP_MASK, +}; + +static struct axp20x_pek_ext_attr axp20x_pek_shutdown_ext_attr = { + .p_time = shutdown_time, + .mask = AXP20X_PEK_SHUTDOWN_MASK, +}; + +static struct axp20x_pek_ext_attr *get_axp_ext_attr(struct device_attribute *attr) +{ + return container_of(attr, struct dev_ext_attribute, attr)->var; +} + +static ssize_t axp20x_show_ext_attr(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev); + struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr); + unsigned int val; + int ret, i; + + ret = regmap_read(axp20x_pek->axp20x->regmap, AXP20X_PEK_KEY, &val); + if (ret != 0) + return ret; + + val &= axp20x_ea->mask; + val >>= ffs(axp20x_ea->mask) - 1; + + for (i = 0; i < 4; i++) + if (val == axp20x_ea->p_time[i].idx) + val = axp20x_ea->p_time[i].time; + + return sprintf(buf, "%u\n", val); +} + +static ssize_t axp20x_store_ext_attr(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev); + struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr); + char val_str[20]; + size_t len; + int ret, i; + unsigned int val, idx = 0; + unsigned int best_err = UINT_MAX; + + val_str[sizeof(val_str) - 1] = '\0'; + strncpy(val_str, buf, sizeof(val_str) - 1); + len = strlen(val_str); + + if (len && val_str[len - 1] == '\n') + val_str[len - 1] = '\0'; + + ret = kstrtouint(val_str, 10, &val); + if (ret) + return ret; + + for (i = 3; i >= 0; i--) { + unsigned int err; + + err = abs(axp20x_ea->p_time[i].time - val); + if (err < best_err) { + best_err = err; + idx = axp20x_ea->p_time[i].idx; + } + + if (!err) + break; + } + + idx <<= ffs(axp20x_ea->mask) - 1; + ret = regmap_update_bits(axp20x_pek->axp20x->regmap, + AXP20X_PEK_KEY, + axp20x_ea->mask, idx); + if (ret != 0) + return -EINVAL; + + return count; +} + +static struct dev_ext_attribute axp20x_dev_attr_startup = { + .attr = __ATTR(startup, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr), + .var = &axp20x_pek_startup_ext_attr, +}; + +static struct dev_ext_attribute axp20x_dev_attr_shutdown = { + .attr = __ATTR(shutdown, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr), + .var = &axp20x_pek_shutdown_ext_attr, +}; + +static struct attribute *axp20x_attributes[] = { + &axp20x_dev_attr_startup.attr.attr, + &axp20x_dev_attr_shutdown.attr.attr, + NULL, +}; + +static const struct attribute_group axp20x_attribute_group = { + .attrs = axp20x_attributes, +}; + +static irqreturn_t axp20x_pek_irq(int irq, void *pwr) +{ + struct input_dev *idev = pwr; + struct axp20x_pek *axp20x_pek = input_get_drvdata(idev); + + if (irq == axp20x_pek->irq_dbr) + input_report_key(idev, KEY_POWER, true); + else if (irq == axp20x_pek->irq_dbf) + input_report_key(idev, KEY_POWER, false); + + input_sync(idev); + + return IRQ_HANDLED; +} + +static void axp20x_remove_sysfs_group(void *_data) +{ + struct device *dev = _data; + + sysfs_remove_group(&dev->kobj, &axp20x_attribute_group); +} + +static int axp20x_pek_probe(struct platform_device *pdev) +{ + struct axp20x_pek *axp20x_pek; + struct axp20x_dev *axp20x; + struct input_dev *idev; + int error; + + axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek), + GFP_KERNEL); + if (!axp20x_pek) + return -ENOMEM; + + axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent); + axp20x = axp20x_pek->axp20x; + + axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR"); + if (axp20x_pek->irq_dbr < 0) { + dev_err(&pdev->dev, "No IRQ for PEK_DBR, error=%d\n", + axp20x_pek->irq_dbr); + return axp20x_pek->irq_dbr; + } + axp20x_pek->irq_dbr = regmap_irq_get_virq(axp20x->regmap_irqc, + axp20x_pek->irq_dbr); + + axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF"); + if (axp20x_pek->irq_dbf < 0) { + dev_err(&pdev->dev, "No IRQ for PEK_DBF, error=%d\n", + axp20x_pek->irq_dbf); + return axp20x_pek->irq_dbf; + } + axp20x_pek->irq_dbf = regmap_irq_get_virq(axp20x->regmap_irqc, + axp20x_pek->irq_dbf); + + axp20x_pek->input = devm_input_allocate_device(&pdev->dev); + if (!axp20x_pek->input) + return -ENOMEM; + + idev = axp20x_pek->input; + + idev->name = "axp20x-pek"; + idev->phys = "m1kbd/input2"; + idev->dev.parent = &pdev->dev; + + input_set_capability(idev, EV_KEY, KEY_POWER); + + input_set_drvdata(idev, axp20x_pek); + + error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbr, + axp20x_pek_irq, 0, + "axp20x-pek-dbr", idev); + if (error < 0) { + dev_err(axp20x->dev, "Failed to request dbr IRQ#%d: %d\n", + axp20x_pek->irq_dbr, error); + return error; + } + + error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbf, + axp20x_pek_irq, 0, + "axp20x-pek-dbf", idev); + if (error < 0) { + dev_err(axp20x->dev, "Failed to request dbf IRQ#%d: %d\n", + axp20x_pek->irq_dbf, error); + return error; + } + + error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group); + if (error) { + dev_err(axp20x->dev, "Failed to create sysfs attributes: %d\n", + error); + return error; + } + + error = devm_add_action(&pdev->dev, + axp20x_remove_sysfs_group, &pdev->dev); + if (error) { + axp20x_remove_sysfs_group(&pdev->dev); + dev_err(&pdev->dev, "Failed to add sysfs cleanup action: %d\n", + error); + return error; + } + + error = input_register_device(idev); + if (error) { + dev_err(axp20x->dev, "Can't register input device: %d\n", + error); + return error; + } + + platform_set_drvdata(pdev, axp20x_pek); + + return 0; +} + +static struct platform_driver axp20x_pek_driver = { + .probe = axp20x_pek_probe, + .driver = { + .name = "axp20x-pek", + }, +}; +module_platform_driver(axp20x_pek_driver); + +MODULE_DESCRIPTION("axp20x Power Button"); +MODULE_AUTHOR("Carlo Caione "); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index a364e109ca7c..599578042ea0 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -733,7 +733,6 @@ static struct i2c_driver drv260x_driver = { }; module_i2c_driver(drv260x_driver); -MODULE_ALIAS("platform:drv260x-haptics"); MODULE_DESCRIPTION("TI DRV260x haptics driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Dan Murphy "); diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index a021744e608c..fc0fddf0896a 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -492,7 +492,6 @@ static struct i2c_driver drv2667_driver = { }; module_i2c_driver(drv2667_driver); -MODULE_ALIAS("platform:drv2667-haptics"); MODULE_DESCRIPTION("TI DRV2667 haptics driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Dan Murphy "); diff --git a/drivers/input/misc/e3x0-button.c b/drivers/input/misc/e3x0-button.c new file mode 100644 index 000000000000..13bfca8a7b16 --- /dev/null +++ b/drivers/input/misc/e3x0-button.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2014, National Instruments Corp. All rights reserved. + * + * Driver for NI Ettus Research USRP E3x0 Button Driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static irqreturn_t e3x0_button_release_handler(int irq, void *data) +{ + struct input_dev *idev = data; + + input_report_key(idev, KEY_POWER, 0); + input_sync(idev); + + return IRQ_HANDLED; +} + +static irqreturn_t e3x0_button_press_handler(int irq, void *data) +{ + struct input_dev *idev = data; + + input_report_key(idev, KEY_POWER, 1); + pm_wakeup_event(idev->dev.parent, 0); + input_sync(idev); + + return IRQ_HANDLED; +} + +static int __maybe_unused e3x0_button_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(platform_get_irq_byname(pdev, "press")); + + return 0; +} + +static int __maybe_unused e3x0_button_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(platform_get_irq_byname(pdev, "press")); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(e3x0_button_pm_ops, + e3x0_button_suspend, e3x0_button_resume); + +static int e3x0_button_probe(struct platform_device *pdev) +{ + struct input_dev *input; + int irq_press, irq_release; + int error; + + irq_press = platform_get_irq_byname(pdev, "press"); + if (irq_press < 0) { + dev_err(&pdev->dev, "No IRQ for 'press', error=%d\n", + irq_press); + return irq_press; + } + + irq_release = platform_get_irq_byname(pdev, "release"); + if (irq_release < 0) { + dev_err(&pdev->dev, "No IRQ for 'release', error=%d\n", + irq_release); + return irq_release; + } + + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return -ENOMEM; + + input->name = "NI Ettus Research USRP E3x0 Button Driver"; + input->phys = "e3x0_button/input0"; + input->dev.parent = &pdev->dev; + + input_set_capability(input, EV_KEY, KEY_POWER); + + error = devm_request_irq(&pdev->dev, irq_press, + e3x0_button_press_handler, 0, + "e3x0-button", input); + if (error) { + dev_err(&pdev->dev, "Failed to request 'press' IRQ#%d: %d\n", + irq_press, error); + return error; + } + + error = devm_request_irq(&pdev->dev, irq_release, + e3x0_button_release_handler, 0, + "e3x0-button", input); + if (error) { + dev_err(&pdev->dev, "Failed to request 'release' IRQ#%d: %d\n", + irq_release, error); + return error; + } + + error = input_register_device(input); + if (error) { + dev_err(&pdev->dev, "Can't register input device: %d\n", error); + return error; + } + + platform_set_drvdata(pdev, input); + device_init_wakeup(&pdev->dev, 1); + return 0; +} + +static int e3x0_button_remove(struct platform_device *pdev) +{ + device_init_wakeup(&pdev->dev, 0); + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id e3x0_button_match[] = { + { .compatible = "ettus,e3x0-button", }, + { } +}; +MODULE_DEVICE_TABLE(of, e3x0_button_match); +#endif + +static struct platform_driver e3x0_button_driver = { + .driver = { + .name = "e3x0-button", + .of_match_table = of_match_ptr(e3x0_button_match), + .pm = &e3x0_button_pm_ops, + }, + .probe = e3x0_button_probe, + .remove = e3x0_button_remove, +}; + +module_platform_driver(e3x0_button_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Moritz Fischer "); +MODULE_DESCRIPTION("NI Ettus Research USRP E3x0 Button driver"); +MODULE_ALIAS("platform:e3x0-button"); diff --git a/drivers/input/misc/regulator-haptic.c b/drivers/input/misc/regulator-haptic.c new file mode 100644 index 000000000000..132eb914ea3e --- /dev/null +++ b/drivers/input/misc/regulator-haptic.c @@ -0,0 +1,266 @@ +/* + * Regulator haptic driver + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Author: Jaewon Kim + * Author: Hyunhee Kim + * + * This 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 + +#define MAX_MAGNITUDE_SHIFT 16 + +struct regulator_haptic { + struct device *dev; + struct input_dev *input_dev; + struct regulator *regulator; + + struct work_struct work; + struct mutex mutex; + + bool active; + bool suspended; + + unsigned int max_volt; + unsigned int min_volt; + unsigned int magnitude; +}; + +static int regulator_haptic_toggle(struct regulator_haptic *haptic, bool on) +{ + int error; + + if (haptic->active != on) { + + error = on ? regulator_enable(haptic->regulator) : + regulator_disable(haptic->regulator); + if (error) { + dev_err(haptic->dev, + "failed to switch regulator %s: %d\n", + on ? "on" : "off", error); + return error; + } + + haptic->active = on; + } + + return 0; +} + +static int regulator_haptic_set_voltage(struct regulator_haptic *haptic, + unsigned int magnitude) +{ + u64 volt_mag_multi; + unsigned int intensity; + int error; + + volt_mag_multi = (u64)(haptic->max_volt - haptic->min_volt) * magnitude; + intensity = (unsigned int)(volt_mag_multi >> MAX_MAGNITUDE_SHIFT); + + error = regulator_set_voltage(haptic->regulator, + intensity + haptic->min_volt, + haptic->max_volt); + if (error) { + dev_err(haptic->dev, "cannot set regulator voltage to %d: %d\n", + intensity + haptic->min_volt, error); + return error; + } + + regulator_haptic_toggle(haptic, !!magnitude); + + return 0; +} + +static void regulator_haptic_work(struct work_struct *work) +{ + struct regulator_haptic *haptic = container_of(work, + struct regulator_haptic, work); + + mutex_lock(&haptic->mutex); + + if (!haptic->suspended) + regulator_haptic_set_voltage(haptic, haptic->magnitude); + + mutex_unlock(&haptic->mutex); +} + +static int regulator_haptic_play_effect(struct input_dev *input, void *data, + struct ff_effect *effect) +{ + struct regulator_haptic *haptic = input_get_drvdata(input); + + haptic->magnitude = effect->u.rumble.strong_magnitude; + if (!haptic->magnitude) + haptic->magnitude = effect->u.rumble.weak_magnitude; + + schedule_work(&haptic->work); + + return 0; +} + +static void regulator_haptic_close(struct input_dev *input) +{ + struct regulator_haptic *haptic = input_get_drvdata(input); + + cancel_work_sync(&haptic->work); + regulator_haptic_set_voltage(haptic, 0); +} + +static int __maybe_unused +regulator_haptic_parse_dt(struct device *dev, struct regulator_haptic *haptic) +{ + struct device_node *node; + int error; + + node = dev->of_node; + if(!node) { + dev_err(dev, "Missing dveice tree data\n"); + return -EINVAL; + } + + error = of_property_read_u32(node, "max-microvolt", &haptic->max_volt); + if (error) { + dev_err(dev, "cannot parse max-microvolt\n"); + return error; + } + + error = of_property_read_u32(node, "min-microvolt", &haptic->min_volt); + if (error) { + dev_err(dev, "cannot parse min-microvolt\n"); + return error; + } + + return 0; +} + +static int regulator_haptic_probe(struct platform_device *pdev) +{ + const struct regulator_haptic_data *pdata = dev_get_platdata(&pdev->dev); + struct regulator_haptic *haptic; + struct input_dev *input_dev; + int error; + + haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL); + if (!haptic) + return -ENOMEM; + + platform_set_drvdata(pdev, haptic); + haptic->dev = &pdev->dev; + mutex_init(&haptic->mutex); + INIT_WORK(&haptic->work, regulator_haptic_work); + + if (pdata) { + haptic->max_volt = pdata->max_volt; + haptic->min_volt = pdata->min_volt; + } else if (IS_ENABLED(CONFIG_OF)) { + error = regulator_haptic_parse_dt(&pdev->dev, haptic); + if (error) + return error; + } else { + dev_err(&pdev->dev, "Missing platform data\n"); + return -EINVAL; + } + + haptic->regulator = devm_regulator_get_exclusive(&pdev->dev, "haptic"); + if (IS_ERR(haptic->regulator)) { + dev_err(&pdev->dev, "failed to get regulator\n"); + return PTR_ERR(haptic->regulator); + } + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) + return -ENOMEM; + + haptic->input_dev = input_dev; + haptic->input_dev->name = "regulator-haptic"; + haptic->input_dev->dev.parent = &pdev->dev; + haptic->input_dev->close = regulator_haptic_close; + input_set_drvdata(haptic->input_dev, haptic); + input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE); + + error = input_ff_create_memless(input_dev, NULL, + regulator_haptic_play_effect); + if (error) { + dev_err(&pdev->dev, "failed to create force-feedback\n"); + return error; + } + + error = input_register_device(haptic->input_dev); + if (error) { + dev_err(&pdev->dev, "failed to register input device\n"); + return error; + } + + return 0; +} + +static int __maybe_unused regulator_haptic_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct regulator_haptic *haptic = platform_get_drvdata(pdev); + int error; + + error = mutex_lock_interruptible(&haptic->mutex); + if (error) + return error; + + regulator_haptic_set_voltage(haptic, 0); + + haptic->suspended = true; + + mutex_unlock(&haptic->mutex); + + return 0; +} + +static int __maybe_unused regulator_haptic_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct regulator_haptic *haptic = platform_get_drvdata(pdev); + unsigned int magnitude; + + mutex_lock(&haptic->mutex); + + haptic->suspended = false; + + magnitude = ACCESS_ONCE(haptic->magnitude); + if (magnitude) + regulator_haptic_set_voltage(haptic, magnitude); + + mutex_unlock(&haptic->mutex); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops, + regulator_haptic_suspend, regulator_haptic_resume); + +static struct of_device_id regulator_haptic_dt_match[] = { + { .compatible = "regulator-haptic" }, + { /* sentinel */ }, +}; + +static struct platform_driver regulator_haptic_driver = { + .probe = regulator_haptic_probe, + .driver = { + .name = "regulator-haptic", + .of_match_table = regulator_haptic_dt_match, + .pm = ®ulator_haptic_pm_ops, + }, +}; +module_platform_driver(regulator_haptic_driver); + +MODULE_AUTHOR("Jaewon Kim "); +MODULE_AUTHOR("Hyunhee Kim "); +MODULE_DESCRIPTION("Regulator haptic driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/tps65218-pwrbutton.c b/drivers/input/misc/tps65218-pwrbutton.c new file mode 100644 index 000000000000..54508dec4eb3 --- /dev/null +++ b/drivers/input/misc/tps65218-pwrbutton.c @@ -0,0 +1,126 @@ +/* + * Texas Instruments' TPS65218 Power Button Input Driver + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Felipe Balbi + * + * This 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct tps65218_pwrbutton { + struct device *dev; + struct tps65218 *tps; + struct input_dev *idev; +}; + +static irqreturn_t tps65218_pwr_irq(int irq, void *_pwr) +{ + struct tps65218_pwrbutton *pwr = _pwr; + unsigned int reg; + int error; + + error = tps65218_reg_read(pwr->tps, TPS65218_REG_STATUS, ®); + if (error) { + dev_err(pwr->dev, "can't read register: %d\n", error); + goto out; + } + + if (reg & TPS65218_STATUS_PB_STATE) { + input_report_key(pwr->idev, KEY_POWER, 1); + pm_wakeup_event(pwr->dev, 0); + } else { + input_report_key(pwr->idev, KEY_POWER, 0); + } + + input_sync(pwr->idev); + +out: + return IRQ_HANDLED; +} + +static int tps65218_pwron_probe(struct platform_device *pdev) +{ + struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct tps65218_pwrbutton *pwr; + struct input_dev *idev; + int error; + int irq; + + pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL); + if (!pwr) + return -ENOMEM; + + idev = devm_input_allocate_device(dev); + if (!idev) + return -ENOMEM; + + idev->name = "tps65218_pwrbutton"; + idev->phys = "tps65218_pwrbutton/input0"; + idev->dev.parent = dev; + idev->id.bustype = BUS_I2C; + + input_set_capability(idev, EV_KEY, KEY_POWER); + + pwr->tps = tps; + pwr->dev = dev; + pwr->idev = idev; + platform_set_drvdata(pdev, pwr); + device_init_wakeup(dev, true); + + irq = platform_get_irq(pdev, 0); + error = devm_request_threaded_irq(dev, irq, NULL, tps65218_pwr_irq, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "tps65218-pwrbutton", pwr); + if (error) { + dev_err(dev, "failed to request IRQ #%d: %d\n", + irq, error); + return error; + } + + error= input_register_device(idev); + if (error) { + dev_err(dev, "Can't register power button: %d\n", error); + return error; + } + + return 0; +} + +static struct of_device_id of_tps65218_pwr_match[] = { + { .compatible = "ti,tps65218-pwrbutton" }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_tps65218_pwr_match); + +static struct platform_driver tps65218_pwron_driver = { + .probe = tps65218_pwron_probe, + .driver = { + .name = "tps65218_pwrbutton", + .of_match_table = of_tps65218_pwr_match, + }, +}; +module_platform_driver(tps65218_pwron_driver); + +MODULE_DESCRIPTION("TPS65218 Power Button"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Felipe Balbi "); diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index d8b46b0f2dbe..4658b5d41dd7 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -105,19 +105,12 @@ config MOUSE_PS2_ELANTECH Say Y here if you have an Elantech PS/2 touchpad connected to your system. - Note that if you enable this driver you will need an updated - X.org Synaptics driver that does not require ABS_PRESSURE - reports from the touchpad (i.e. post 1.5.0 version). You can - grab a patch for the driver here: - - http://userweb.kernel.org/~dtor/synaptics-no-abspressure.patch - - If unsure, say N. - This driver exposes some configuration registers via sysfs entries. For further information, see . + If unsure, say N. + config MOUSE_PS2_SENTELIC bool "Sentelic Finger Sensing Pad PS/2 protocol extension" depends on MOUSE_PS2 @@ -146,6 +139,16 @@ config MOUSE_PS2_OLPC If unsure, say N. +config MOUSE_PS2_FOCALTECH + bool "FocalTech PS/2 mouse protocol extension" if EXPERT + default y + depends on MOUSE_PS2 + help + Say Y here if you have a FocalTech PS/2 TouchPad connected to + your system. + + If unsure, say Y. + config MOUSE_SERIAL tristate "Serial mouse" select SERIO @@ -206,6 +209,7 @@ config MOUSE_BCM5974 config MOUSE_CYAPA tristate "Cypress APA I2C Trackpad support" depends on I2C + select CRC_ITU_T help This driver adds support for Cypress All Points Addressable (APA) I2C Trackpads, including the ones used in 2012 Samsung Chromebooks. diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 560003dcac37..8a9c98e76d9c 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o -obj-$(CONFIG_MOUSE_CYAPA) += cyapa.o +obj-$(CONFIG_MOUSE_CYAPA) += cyapatp.o obj-$(CONFIG_MOUSE_ELAN_I2C) += elan_i2c.o obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o obj-$(CONFIG_MOUSE_INPORT) += inport.o @@ -24,6 +24,7 @@ obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o +cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o psmouse-objs := psmouse-base.o synaptics.o focaltech.o psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index d88d73d83552..f205b8be2ce4 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -435,7 +435,7 @@ static void alps_report_mt_data(struct psmouse *psmouse, int n) struct alps_fields *f = &priv->f; int i, slot[MAX_TOUCHES]; - input_mt_assign_slots(dev, slot, f->mt, n); + input_mt_assign_slots(dev, slot, f->mt, n, 0); for (i = 0; i < n; i++) alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y); @@ -475,6 +475,13 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse) struct input_dev *dev = priv->dev2; int x, y, z, left, right, middle; + /* It should be a DualPoint when received trackstick packet */ + if (!(priv->flags & ALPS_DUALPOINT)) { + psmouse_warn(psmouse, + "Rejected trackstick packet from non DualPoint device"); + return; + } + /* Sanity check packet */ if (!(packet[0] & 0x40)) { psmouse_dbg(psmouse, "Bad trackstick packet, discarding\n"); @@ -699,7 +706,8 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) alps_report_semi_mt_data(psmouse, fingers); - if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { + if ((priv->flags & ALPS_DUALPOINT) && + !(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { input_report_key(dev2, BTN_LEFT, f->ts_left); input_report_key(dev2, BTN_RIGHT, f->ts_right); input_report_key(dev2, BTN_MIDDLE, f->ts_middle); @@ -743,8 +751,11 @@ static void alps_process_packet_v6(struct psmouse *psmouse) */ if (packet[5] == 0x7F) { /* It should be a DualPoint when received Trackpoint packet */ - if (!(priv->flags & ALPS_DUALPOINT)) + if (!(priv->flags & ALPS_DUALPOINT)) { + psmouse_warn(psmouse, + "Rejected trackstick packet from non DualPoint device"); return; + } /* Trackpoint packet */ x = packet[1] | ((packet[3] & 0x20) << 2); @@ -1026,6 +1037,13 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse) struct input_dev *dev2 = priv->dev2; int x, y, z, left, right, middle; + /* It should be a DualPoint when received trackstick packet */ + if (!(priv->flags & ALPS_DUALPOINT)) { + psmouse_warn(psmouse, + "Rejected trackstick packet from non DualPoint device"); + return; + } + /* * b7 b6 b5 b4 b3 b2 b1 b0 * Byte0 0 1 0 0 1 0 0 0 @@ -2443,14 +2461,24 @@ int alps_init(struct psmouse *psmouse) dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE); } + if (priv->flags & ALPS_DUALPOINT) { + /* + * format of input device name is: "protocol vendor name" + * see function psmouse_switch_protocol() in psmouse-base.c + */ + dev2->name = "AlpsPS/2 ALPS DualPoint Stick"; + dev2->id.product = PSMOUSE_ALPS; + dev2->id.version = priv->proto_version; + } else { + dev2->name = "PS/2 ALPS Mouse"; + dev2->id.product = PSMOUSE_PS2; + dev2->id.version = 0x0000; + } + snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); dev2->phys = priv->phys; - dev2->name = (priv->flags & ALPS_DUALPOINT) ? - "DualPoint Stick" : "ALPS PS/2 Device"; dev2->id.bustype = BUS_I8042; dev2->id.vendor = 0x0002; - dev2->id.product = PSMOUSE_ALPS; - dev2->id.version = 0x0000; dev2->dev.parent = &psmouse->ps2dev.serio->dev; dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index c329cdb0b91a..b10709f04615 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -564,7 +564,7 @@ static int report_tp_state(struct bcm5974 *dev, int size) dev->index[n++] = &f[i]; } - input_mt_assign_slots(input, dev->slots, dev->pos, n); + input_mt_assign_slots(input, dev->slots, dev->pos, n, 0); for (i = 0; i < n; i++) report_finger_data(input, dev->slots[i], diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 1bece8cad46f..58f4f6fa4857 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -20,408 +20,131 @@ #include #include #include +#include #include +#include +#include +#include +#include "cyapa.h" -/* APA trackpad firmware generation */ -#define CYAPA_GEN3 0x03 /* support MT-protocol B with tracking ID. */ - -#define CYAPA_NAME "Cypress APA Trackpad (cyapa)" - -/* commands for read/write registers of Cypress trackpad */ -#define CYAPA_CMD_SOFT_RESET 0x00 -#define CYAPA_CMD_POWER_MODE 0x01 -#define CYAPA_CMD_DEV_STATUS 0x02 -#define CYAPA_CMD_GROUP_DATA 0x03 -#define CYAPA_CMD_GROUP_CMD 0x04 -#define CYAPA_CMD_GROUP_QUERY 0x05 -#define CYAPA_CMD_BL_STATUS 0x06 -#define CYAPA_CMD_BL_HEAD 0x07 -#define CYAPA_CMD_BL_CMD 0x08 -#define CYAPA_CMD_BL_DATA 0x09 -#define CYAPA_CMD_BL_ALL 0x0a -#define CYAPA_CMD_BLK_PRODUCT_ID 0x0b -#define CYAPA_CMD_BLK_HEAD 0x0c - -/* report data start reg offset address. */ -#define DATA_REG_START_OFFSET 0x0000 - -#define BL_HEAD_OFFSET 0x00 -#define BL_DATA_OFFSET 0x10 - -/* - * Operational Device Status Register - * - * bit 7: Valid interrupt source - * bit 6 - 4: Reserved - * bit 3 - 2: Power status - * bit 1 - 0: Device status - */ -#define REG_OP_STATUS 0x00 -#define OP_STATUS_SRC 0x80 -#define OP_STATUS_POWER 0x0c -#define OP_STATUS_DEV 0x03 -#define OP_STATUS_MASK (OP_STATUS_SRC | OP_STATUS_POWER | OP_STATUS_DEV) - -/* - * Operational Finger Count/Button Flags Register - * - * bit 7 - 4: Number of touched finger - * bit 3: Valid data - * bit 2: Middle Physical Button - * bit 1: Right Physical Button - * bit 0: Left physical Button - */ -#define REG_OP_DATA1 0x01 -#define OP_DATA_VALID 0x08 -#define OP_DATA_MIDDLE_BTN 0x04 -#define OP_DATA_RIGHT_BTN 0x02 -#define OP_DATA_LEFT_BTN 0x01 -#define OP_DATA_BTN_MASK (OP_DATA_MIDDLE_BTN | OP_DATA_RIGHT_BTN | \ - OP_DATA_LEFT_BTN) - -/* - * Bootloader Status Register - * - * bit 7: Busy - * bit 6 - 5: Reserved - * bit 4: Bootloader running - * bit 3 - 1: Reserved - * bit 0: Checksum valid - */ -#define REG_BL_STATUS 0x01 -#define BL_STATUS_BUSY 0x80 -#define BL_STATUS_RUNNING 0x10 -#define BL_STATUS_DATA_VALID 0x08 -#define BL_STATUS_CSUM_VALID 0x01 - -/* - * Bootloader Error Register - * - * bit 7: Invalid - * bit 6: Invalid security key - * bit 5: Bootloading - * bit 4: Command checksum - * bit 3: Flash protection error - * bit 2: Flash checksum error - * bit 1 - 0: Reserved - */ -#define REG_BL_ERROR 0x02 -#define BL_ERROR_INVALID 0x80 -#define BL_ERROR_INVALID_KEY 0x40 -#define BL_ERROR_BOOTLOADING 0x20 -#define BL_ERROR_CMD_CSUM 0x10 -#define BL_ERROR_FLASH_PROT 0x08 -#define BL_ERROR_FLASH_CSUM 0x04 - -#define BL_STATUS_SIZE 3 /* length of bootloader status registers */ -#define BLK_HEAD_BYTES 32 - -#define PRODUCT_ID_SIZE 16 -#define QUERY_DATA_SIZE 27 -#define REG_PROTOCOL_GEN_QUERY_OFFSET 20 - -#define REG_OFFSET_DATA_BASE 0x0000 -#define REG_OFFSET_COMMAND_BASE 0x0028 -#define REG_OFFSET_QUERY_BASE 0x002a - -#define CAPABILITY_LEFT_BTN_MASK (0x01 << 3) -#define CAPABILITY_RIGHT_BTN_MASK (0x01 << 4) -#define CAPABILITY_MIDDLE_BTN_MASK (0x01 << 5) -#define CAPABILITY_BTN_MASK (CAPABILITY_LEFT_BTN_MASK | \ - CAPABILITY_RIGHT_BTN_MASK | \ - CAPABILITY_MIDDLE_BTN_MASK) - -#define CYAPA_OFFSET_SOFT_RESET REG_OFFSET_COMMAND_BASE - -#define REG_OFFSET_POWER_MODE (REG_OFFSET_COMMAND_BASE + 1) - -#define PWR_MODE_MASK 0xfc -#define PWR_MODE_FULL_ACTIVE (0x3f << 2) -#define PWR_MODE_IDLE (0x05 << 2) /* default sleep time is 50 ms. */ -#define PWR_MODE_OFF (0x00 << 2) - -#define PWR_STATUS_MASK 0x0c -#define PWR_STATUS_ACTIVE (0x03 << 2) -#define PWR_STATUS_IDLE (0x02 << 2) -#define PWR_STATUS_OFF (0x00 << 2) - -/* - * CYAPA trackpad device states. - * Used in register 0x00, bit1-0, DeviceStatus field. - * Other values indicate device is in an abnormal state and must be reset. - */ -#define CYAPA_DEV_NORMAL 0x03 -#define CYAPA_DEV_BUSY 0x01 - -enum cyapa_state { - CYAPA_STATE_OP, - CYAPA_STATE_BL_IDLE, - CYAPA_STATE_BL_ACTIVE, - CYAPA_STATE_BL_BUSY, - CYAPA_STATE_NO_DEVICE, -}; - - -struct cyapa_touch { - /* - * high bits or x/y position value - * bit 7 - 4: high 4 bits of x position value - * bit 3 - 0: high 4 bits of y position value - */ - u8 xy_hi; - u8 x_lo; /* low 8 bits of x position value. */ - u8 y_lo; /* low 8 bits of y position value. */ - u8 pressure; - /* id range is 1 - 15. It is incremented with every new touch. */ - u8 id; -} __packed; - -/* The touch.id is used as the MT slot id, thus max MT slot is 15 */ -#define CYAPA_MAX_MT_SLOTS 15 - -struct cyapa_reg_data { - /* - * bit 0 - 1: device status - * bit 3 - 2: power mode - * bit 6 - 4: reserved - * bit 7: interrupt valid bit - */ - u8 device_status; - /* - * bit 7 - 4: number of fingers currently touching pad - * bit 3: valid data check bit - * bit 2: middle mechanism button state if exists - * bit 1: right mechanism button state if exists - * bit 0: left mechanism button state if exists - */ - u8 finger_btn; - /* CYAPA reports up to 5 touches per packet. */ - struct cyapa_touch touches[5]; -} __packed; - -/* The main device structure */ -struct cyapa { - enum cyapa_state state; - - struct i2c_client *client; - struct input_dev *input; - char phys[32]; /* device physical location */ - bool irq_wake; /* irq wake is enabled */ - bool smbus; - - /* read from query data region. */ - char product_id[16]; - u8 btn_capability; - u8 gen; - int max_abs_x; - int max_abs_y; - int physical_size_x; - int physical_size_y; -}; - -static const u8 bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07 }; -static const u8 bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07 }; - -struct cyapa_cmd_len { - u8 cmd; - u8 len; -}; #define CYAPA_ADAPTER_FUNC_NONE 0 #define CYAPA_ADAPTER_FUNC_I2C 1 #define CYAPA_ADAPTER_FUNC_SMBUS 2 #define CYAPA_ADAPTER_FUNC_BOTH 3 -/* - * macros for SMBus communication - */ -#define SMBUS_READ 0x01 -#define SMBUS_WRITE 0x00 -#define SMBUS_ENCODE_IDX(cmd, idx) ((cmd) | (((idx) & 0x03) << 1)) -#define SMBUS_ENCODE_RW(cmd, rw) ((cmd) | ((rw) & 0x01)) -#define SMBUS_BYTE_BLOCK_CMD_MASK 0x80 -#define SMBUS_GROUP_BLOCK_CMD_MASK 0x40 +#define CYAPA_FW_NAME "cyapa.bin" - /* for byte read/write command */ -#define CMD_RESET 0 -#define CMD_POWER_MODE 1 -#define CMD_DEV_STATUS 2 -#define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1) -#define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET) -#define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE) -#define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS) +const char product_id[] = "CYTRA"; - /* for group registers read/write command */ -#define REG_GROUP_DATA 0 -#define REG_GROUP_CMD 2 -#define REG_GROUP_QUERY 3 -#define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3)) -#define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA) -#define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD) -#define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY) +static int cyapa_reinitialize(struct cyapa *cyapa); - /* for register block read/write command */ -#define CMD_BL_STATUS 0 -#define CMD_BL_HEAD 1 -#define CMD_BL_CMD 2 -#define CMD_BL_DATA 3 -#define CMD_BL_ALL 4 -#define CMD_BLK_PRODUCT_ID 5 -#define CMD_BLK_HEAD 6 -#define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1)) +static inline bool cyapa_is_bootloader_mode(struct cyapa *cyapa) +{ + if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_BL) + return true; -/* register block read/write command in bootloader mode */ -#define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS) -#define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD) -#define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD) -#define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA) -#define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL) + if (cyapa->gen == CYAPA_GEN3 && + cyapa->state >= CYAPA_STATE_BL_BUSY && + cyapa->state <= CYAPA_STATE_BL_ACTIVE) + return true; -/* register block read/write command in operational mode */ -#define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID) -#define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD) + return false; +} -static const struct cyapa_cmd_len cyapa_i2c_cmds[] = { - { CYAPA_OFFSET_SOFT_RESET, 1 }, - { REG_OFFSET_COMMAND_BASE + 1, 1 }, - { REG_OFFSET_DATA_BASE, 1 }, - { REG_OFFSET_DATA_BASE, sizeof(struct cyapa_reg_data) }, - { REG_OFFSET_COMMAND_BASE, 0 }, - { REG_OFFSET_QUERY_BASE, QUERY_DATA_SIZE }, - { BL_HEAD_OFFSET, 3 }, - { BL_HEAD_OFFSET, 16 }, - { BL_HEAD_OFFSET, 16 }, - { BL_DATA_OFFSET, 16 }, - { BL_HEAD_OFFSET, 32 }, - { REG_OFFSET_QUERY_BASE, PRODUCT_ID_SIZE }, - { REG_OFFSET_DATA_BASE, 32 } -}; +static inline bool cyapa_is_operational_mode(struct cyapa *cyapa) +{ + if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_APP) + return true; -static const struct cyapa_cmd_len cyapa_smbus_cmds[] = { - { CYAPA_SMBUS_RESET, 1 }, - { CYAPA_SMBUS_POWER_MODE, 1 }, - { CYAPA_SMBUS_DEV_STATUS, 1 }, - { CYAPA_SMBUS_GROUP_DATA, sizeof(struct cyapa_reg_data) }, - { CYAPA_SMBUS_GROUP_CMD, 2 }, - { CYAPA_SMBUS_GROUP_QUERY, QUERY_DATA_SIZE }, - { CYAPA_SMBUS_BL_STATUS, 3 }, - { CYAPA_SMBUS_BL_HEAD, 16 }, - { CYAPA_SMBUS_BL_CMD, 16 }, - { CYAPA_SMBUS_BL_DATA, 16 }, - { CYAPA_SMBUS_BL_ALL, 32 }, - { CYAPA_SMBUS_BLK_PRODUCT_ID, PRODUCT_ID_SIZE }, - { CYAPA_SMBUS_BLK_HEAD, 16 }, -}; + if (cyapa->gen == CYAPA_GEN3 && cyapa->state == CYAPA_STATE_OP) + return true; -static ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len, + return false; +} + +/* Returns 0 on success, else negative errno on failure. */ +static ssize_t cyapa_i2c_read(struct cyapa *cyapa, u8 reg, size_t len, u8 *values) { - return i2c_smbus_read_i2c_block_data(cyapa->client, reg, len, values); -} - -static ssize_t cyapa_i2c_reg_write_block(struct cyapa *cyapa, u8 reg, - size_t len, const u8 *values) -{ - return i2c_smbus_write_i2c_block_data(cyapa->client, reg, len, values); -} - -/* - * cyapa_smbus_read_block - perform smbus block read command - * @cyapa - private data structure of the driver - * @cmd - the properly encoded smbus command - * @len - expected length of smbus command result - * @values - buffer to store smbus command result - * - * Returns negative errno, else the number of bytes written. - * - * Note: - * In trackpad device, the memory block allocated for I2C register map - * is 256 bytes, so the max read block for I2C bus is 256 bytes. - */ -static ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len, - u8 *values) -{ - ssize_t ret; - u8 index; - u8 smbus_cmd; - u8 *buf; struct i2c_client *client = cyapa->client; + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = values, + }, + }; + int ret; - if (!(SMBUS_BYTE_BLOCK_CMD_MASK & cmd)) - return -EINVAL; + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (SMBUS_GROUP_BLOCK_CMD_MASK & cmd) { - /* read specific block registers command. */ - smbus_cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ); - ret = i2c_smbus_read_block_data(client, smbus_cmd, values); - goto out; - } + if (ret != ARRAY_SIZE(msgs)) + return ret < 0 ? ret : -EIO; - ret = 0; - for (index = 0; index * I2C_SMBUS_BLOCK_MAX < len; index++) { - smbus_cmd = SMBUS_ENCODE_IDX(cmd, index); - smbus_cmd = SMBUS_ENCODE_RW(smbus_cmd, SMBUS_READ); - buf = values + I2C_SMBUS_BLOCK_MAX * index; - ret = i2c_smbus_read_block_data(client, smbus_cmd, buf); - if (ret < 0) - goto out; - } - -out: - return ret > 0 ? len : ret; + return 0; } -static s32 cyapa_read_byte(struct cyapa *cyapa, u8 cmd_idx) +/** + * cyapa_i2c_write - Execute i2c block data write operation + * @cyapa: Handle to this driver + * @ret: Offset of the data to written in the register map + * @len: number of bytes to write + * @values: Data to be written + * + * Return negative errno code on error; return zero when success. + */ +static int cyapa_i2c_write(struct cyapa *cyapa, u8 reg, + size_t len, const void *values) { - u8 cmd; + struct i2c_client *client = cyapa->client; + char buf[32]; + int ret; - if (cyapa->smbus) { - cmd = cyapa_smbus_cmds[cmd_idx].cmd; - cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ); - } else { - cmd = cyapa_i2c_cmds[cmd_idx].cmd; - } - return i2c_smbus_read_byte_data(cyapa->client, cmd); + if (len > sizeof(buf) - 1) + return -ENOMEM; + + buf[0] = reg; + memcpy(&buf[1], values, len); + + ret = i2c_master_send(client, buf, len + 1); + if (ret != len + 1) + return ret < 0 ? ret : -EIO; + + return 0; } -static s32 cyapa_write_byte(struct cyapa *cyapa, u8 cmd_idx, u8 value) +static u8 cyapa_check_adapter_functionality(struct i2c_client *client) { - u8 cmd; + u8 ret = CYAPA_ADAPTER_FUNC_NONE; - if (cyapa->smbus) { - cmd = cyapa_smbus_cmds[cmd_idx].cmd; - cmd = SMBUS_ENCODE_RW(cmd, SMBUS_WRITE); - } else { - cmd = cyapa_i2c_cmds[cmd_idx].cmd; - } - return i2c_smbus_write_byte_data(cyapa->client, cmd, value); -} - -static ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values) -{ - u8 cmd; - size_t len; - - if (cyapa->smbus) { - cmd = cyapa_smbus_cmds[cmd_idx].cmd; - len = cyapa_smbus_cmds[cmd_idx].len; - return cyapa_smbus_read_block(cyapa, cmd, len, values); - } else { - cmd = cyapa_i2c_cmds[cmd_idx].cmd; - len = cyapa_i2c_cmds[cmd_idx].len; - return cyapa_i2c_reg_read_block(cyapa, cmd, len, values); - } + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + ret |= CYAPA_ADAPTER_FUNC_I2C; + if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) + ret |= CYAPA_ADAPTER_FUNC_SMBUS; + return ret; } /* * Query device for its current operating state. - * */ static int cyapa_get_state(struct cyapa *cyapa) { u8 status[BL_STATUS_SIZE]; + u8 cmd[32]; + /* The i2c address of gen4 and gen5 trackpad device must be even. */ + bool even_addr = ((cyapa->client->addr & 0x0001) == 0); + bool smbus = false; + int retries = 2; int error; cyapa->state = CYAPA_STATE_NO_DEVICE; @@ -433,39 +156,74 @@ static int cyapa_get_state(struct cyapa *cyapa) * */ error = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, BL_STATUS_SIZE, - status); + status); /* * On smbus systems in OP mode, the i2c_reg_read will fail with * -ETIMEDOUT. In this case, try again using the smbus equivalent * command. This should return a BL_HEAD indicating CYAPA_STATE_OP. */ - if (cyapa->smbus && (error == -ETIMEDOUT || error == -ENXIO)) - error = cyapa_read_block(cyapa, CYAPA_CMD_BL_STATUS, status); + if (cyapa->smbus && (error == -ETIMEDOUT || error == -ENXIO)) { + if (!even_addr) + error = cyapa_read_block(cyapa, + CYAPA_CMD_BL_STATUS, status); + smbus = true; + } if (error != BL_STATUS_SIZE) goto error; - if ((status[REG_OP_STATUS] & OP_STATUS_SRC) == OP_STATUS_SRC) { - switch (status[REG_OP_STATUS] & OP_STATUS_DEV) { - case CYAPA_DEV_NORMAL: - case CYAPA_DEV_BUSY: - cyapa->state = CYAPA_STATE_OP; - break; - default: - error = -EAGAIN; - goto error; - } - } else { - if (status[REG_BL_STATUS] & BL_STATUS_BUSY) - cyapa->state = CYAPA_STATE_BL_BUSY; - else if (status[REG_BL_ERROR] & BL_ERROR_BOOTLOADING) - cyapa->state = CYAPA_STATE_BL_ACTIVE; - else - cyapa->state = CYAPA_STATE_BL_IDLE; - } + /* + * Detect trackpad protocol based on characteristic registers and bits. + */ + do { + cyapa->status[REG_OP_STATUS] = status[REG_OP_STATUS]; + cyapa->status[REG_BL_STATUS] = status[REG_BL_STATUS]; + cyapa->status[REG_BL_ERROR] = status[REG_BL_ERROR]; + if (cyapa->gen == CYAPA_GEN_UNKNOWN || + cyapa->gen == CYAPA_GEN3) { + error = cyapa_gen3_ops.state_parse(cyapa, + status, BL_STATUS_SIZE); + if (!error) + goto out_detected; + } + if ((cyapa->gen == CYAPA_GEN_UNKNOWN || + cyapa->gen == CYAPA_GEN5) && + !smbus && even_addr) { + error = cyapa_gen5_ops.state_parse(cyapa, + status, BL_STATUS_SIZE); + if (!error) + goto out_detected; + } + + /* + * Write 0x00 0x00 to trackpad device to force update its + * status, then redo the detection again. + */ + if (!smbus) { + cmd[0] = 0x00; + cmd[1] = 0x00; + error = cyapa_i2c_write(cyapa, 0, 2, cmd); + if (error) + goto error; + + msleep(50); + + error = cyapa_i2c_read(cyapa, BL_HEAD_OFFSET, + BL_STATUS_SIZE, status); + if (error) + goto error; + } + } while (--retries > 0 && !smbus); + + goto error; + +out_detected: + if (cyapa->state <= CYAPA_STATE_BL_BUSY) + return -EAGAIN; return 0; + error: return (error < 0) ? error : -EAGAIN; } @@ -482,145 +240,25 @@ error: * Returns: * 0 when the device eventually responds with a valid non-busy state. * -ETIMEDOUT if device never responds (too many -EAGAIN) - * < 0 other errors + * -EAGAIN if bootload is busy, or unknown state. + * < 0 other errors */ -static int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout) +int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout) { int error; int tries = timeout / 100; - error = cyapa_get_state(cyapa); - while ((error || cyapa->state >= CYAPA_STATE_BL_BUSY) && tries--) { - msleep(100); + do { error = cyapa_get_state(cyapa); - } + if (!error && cyapa->state > CYAPA_STATE_BL_BUSY) + return 0; + + msleep(100); + } while (tries--); + return (error == -EAGAIN || error == -ETIMEDOUT) ? -ETIMEDOUT : error; } -static int cyapa_bl_deactivate(struct cyapa *cyapa) -{ - int error; - - error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_deactivate), - bl_deactivate); - if (error) - return error; - - /* wait for bootloader to switch to idle state; should take < 100ms */ - msleep(100); - error = cyapa_poll_state(cyapa, 500); - if (error) - return error; - if (cyapa->state != CYAPA_STATE_BL_IDLE) - return -EAGAIN; - return 0; -} - -/* - * Exit bootloader - * - * Send bl_exit command, then wait 50 - 100 ms to let device transition to - * operational mode. If this is the first time the device's firmware is - * running, it can take up to 2 seconds to calibrate its sensors. So, poll - * the device's new state for up to 2 seconds. - * - * Returns: - * -EIO failure while reading from device - * -EAGAIN device is stuck in bootloader, b/c it has invalid firmware - * 0 device is supported and in operational mode - */ -static int cyapa_bl_exit(struct cyapa *cyapa) -{ - int error; - - error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_exit), bl_exit); - if (error) - return error; - - /* - * Wait for bootloader to exit, and operation mode to start. - * Normally, this takes at least 50 ms. - */ - usleep_range(50000, 100000); - /* - * In addition, when a device boots for the first time after being - * updated to new firmware, it must first calibrate its sensors, which - * can take up to an additional 2 seconds. - */ - error = cyapa_poll_state(cyapa, 2000); - if (error < 0) - return error; - if (cyapa->state != CYAPA_STATE_OP) - return -EAGAIN; - - return 0; -} - -/* - * Set device power mode - * - */ -static int cyapa_set_power_mode(struct cyapa *cyapa, u8 power_mode) -{ - struct device *dev = &cyapa->client->dev; - int ret; - u8 power; - - if (cyapa->state != CYAPA_STATE_OP) - return 0; - - ret = cyapa_read_byte(cyapa, CYAPA_CMD_POWER_MODE); - if (ret < 0) - return ret; - - power = ret & ~PWR_MODE_MASK; - power |= power_mode & PWR_MODE_MASK; - ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power); - if (ret < 0) { - dev_err(dev, "failed to set power_mode 0x%02x err = %d\n", - power_mode, ret); - return ret; - } - - return 0; -} - -static int cyapa_get_query_data(struct cyapa *cyapa) -{ - u8 query_data[QUERY_DATA_SIZE]; - int ret; - - if (cyapa->state != CYAPA_STATE_OP) - return -EBUSY; - - ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_QUERY, query_data); - if (ret < 0) - return ret; - if (ret != QUERY_DATA_SIZE) - return -EIO; - - memcpy(&cyapa->product_id[0], &query_data[0], 5); - cyapa->product_id[5] = '-'; - memcpy(&cyapa->product_id[6], &query_data[5], 6); - cyapa->product_id[12] = '-'; - memcpy(&cyapa->product_id[13], &query_data[11], 2); - cyapa->product_id[15] = '\0'; - - cyapa->btn_capability = query_data[19] & CAPABILITY_BTN_MASK; - - cyapa->gen = query_data[20] & 0x0f; - - cyapa->max_abs_x = ((query_data[21] & 0xf0) << 4) | query_data[22]; - cyapa->max_abs_y = ((query_data[21] & 0x0f) << 8) | query_data[23]; - - cyapa->physical_size_x = - ((query_data[24] & 0xf0) << 4) | query_data[25]; - cyapa->physical_size_y = - ((query_data[24] & 0x0f) << 8) | query_data[26]; - - return 0; -} - /* * Check if device is operational. * @@ -628,8 +266,10 @@ static int cyapa_get_query_data(struct cyapa *cyapa) * firmware supported by this driver. * * Returns: + * -ENODEV no device * -EBUSY no device or in bootloader * -EIO failure while reading from device + * -ETIMEDOUT timeout failure for bus idle or bus no response * -EAGAIN device is still in bootloader * if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware * -EINVAL device is in operational mode, but not supported by this driver @@ -637,122 +277,56 @@ static int cyapa_get_query_data(struct cyapa *cyapa) */ static int cyapa_check_is_operational(struct cyapa *cyapa) { - struct device *dev = &cyapa->client->dev; - static const char unique_str[] = "CYTRA"; int error; - error = cyapa_poll_state(cyapa, 2000); + error = cyapa_poll_state(cyapa, 4000); if (error) return error; - switch (cyapa->state) { - case CYAPA_STATE_BL_ACTIVE: - error = cyapa_bl_deactivate(cyapa); - if (error) - return error; - - /* Fallthrough state */ - case CYAPA_STATE_BL_IDLE: - error = cyapa_bl_exit(cyapa); - if (error) - return error; - - /* Fallthrough state */ - case CYAPA_STATE_OP: - error = cyapa_get_query_data(cyapa); - if (error) - return error; - - /* only support firmware protocol gen3 */ - if (cyapa->gen != CYAPA_GEN3) { - dev_err(dev, "unsupported protocol version (%d)", - cyapa->gen); - return -EINVAL; - } - - /* only support product ID starting with CYTRA */ - if (memcmp(cyapa->product_id, unique_str, - sizeof(unique_str) - 1) != 0) { - dev_err(dev, "unsupported product ID (%s)\n", - cyapa->product_id); - return -EINVAL; - } - return 0; + switch (cyapa->gen) { + case CYAPA_GEN5: + cyapa->ops = &cyapa_gen5_ops; + break; + case CYAPA_GEN3: + cyapa->ops = &cyapa_gen3_ops; + break; default: - return -EIO; + return -ENODEV; } - return 0; + + error = cyapa->ops->operational_check(cyapa); + if (!error && cyapa_is_operational_mode(cyapa)) + cyapa->operational = true; + else + cyapa->operational = false; + + return error; } -static irqreturn_t cyapa_irq(int irq, void *dev_id) + +/* + * Returns 0 on device detected, negative errno on no device detected. + * And when the device is detected and opertaional, it will be reset to + * full power active mode automatically. + */ +static int cyapa_detect(struct cyapa *cyapa) { - struct cyapa *cyapa = dev_id; struct device *dev = &cyapa->client->dev; - struct input_dev *input = cyapa->input; - struct cyapa_reg_data data; - int i; - int ret; - int num_fingers; + int error; - if (device_may_wakeup(dev)) - pm_wakeup_event(dev, 0); + error = cyapa_check_is_operational(cyapa); + if (error) { + if (error != -ETIMEDOUT && error != -ENODEV && + cyapa_is_bootloader_mode(cyapa)) { + dev_warn(dev, "device detected but not operational\n"); + return 0; + } - ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data); - if (ret != sizeof(data)) - goto out; - - if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC || - (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL || - (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) { - goto out; + dev_err(dev, "no device detected: %d\n", error); + return error; } - num_fingers = (data.finger_btn >> 4) & 0x0f; - for (i = 0; i < num_fingers; i++) { - const struct cyapa_touch *touch = &data.touches[i]; - /* Note: touch->id range is 1 to 15; slots are 0 to 14. */ - int slot = touch->id - 1; - - input_mt_slot(input, slot); - input_mt_report_slot_state(input, MT_TOOL_FINGER, true); - input_report_abs(input, ABS_MT_POSITION_X, - ((touch->xy_hi & 0xf0) << 4) | touch->x_lo); - input_report_abs(input, ABS_MT_POSITION_Y, - ((touch->xy_hi & 0x0f) << 8) | touch->y_lo); - input_report_abs(input, ABS_MT_PRESSURE, touch->pressure); - } - - input_mt_sync_frame(input); - - if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) - input_report_key(input, BTN_LEFT, - data.finger_btn & OP_DATA_LEFT_BTN); - - if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) - input_report_key(input, BTN_MIDDLE, - data.finger_btn & OP_DATA_MIDDLE_BTN); - - if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) - input_report_key(input, BTN_RIGHT, - data.finger_btn & OP_DATA_RIGHT_BTN); - - input_sync(input); - -out: - return IRQ_HANDLED; -} - -static u8 cyapa_check_adapter_functionality(struct i2c_client *client) -{ - u8 ret = CYAPA_ADAPTER_FUNC_NONE; - - if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - ret |= CYAPA_ADAPTER_FUNC_I2C; - if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) - ret |= CYAPA_ADAPTER_FUNC_SMBUS; - return ret; + return 0; } static int cyapa_open(struct input_dev *input) @@ -761,22 +335,57 @@ static int cyapa_open(struct input_dev *input) struct i2c_client *client = cyapa->client; int error; - error = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE); - if (error) { - dev_err(&client->dev, "set active power failed: %d\n", error); + error = mutex_lock_interruptible(&cyapa->state_sync_lock); + if (error) return error; + + if (cyapa->operational) { + /* + * though failed to set active power mode, + * but still may be able to work in lower scan rate + * when in operational mode. + */ + error = cyapa->ops->set_power_mode(cyapa, + PWR_MODE_FULL_ACTIVE, 0); + if (error) { + dev_warn(&client->dev, + "set active power failed: %d\n", error); + goto out; + } + } else { + error = cyapa_reinitialize(cyapa); + if (error || !cyapa->operational) { + error = error ? error : -EAGAIN; + goto out; + } } enable_irq(client->irq); - return 0; + if (!pm_runtime_enabled(&client->dev)) { + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + } +out: + mutex_unlock(&cyapa->state_sync_lock); + return error; } static void cyapa_close(struct input_dev *input) { struct cyapa *cyapa = input_get_drvdata(input); + struct i2c_client *client = cyapa->client; - disable_irq(cyapa->client->irq); - cyapa_set_power_mode(cyapa, PWR_MODE_OFF); + mutex_lock(&cyapa->state_sync_lock); + + disable_irq(client->irq); + if (pm_runtime_enabled(&client->dev)) + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + + if (cyapa->operational) + cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); + + mutex_unlock(&cyapa->state_sync_lock); } static int cyapa_create_input_dev(struct cyapa *cyapa) @@ -813,7 +422,28 @@ static int cyapa_create_input_dev(struct cyapa *cyapa) 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0, 0); - input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0); + input_set_abs_params(input, ABS_MT_PRESSURE, 0, cyapa->max_z, 0, 0); + if (cyapa->gen > CYAPA_GEN3) { + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0); + /* + * Orientation is the angle between the vertical axis and + * the major axis of the contact ellipse. + * The range is -127 to 127. + * the positive direction is clockwise form the vertical axis. + * If the ellipse of contact degenerates into a circle, + * orientation is reported as 0. + * + * Also, for Gen5 trackpad the accurate of this orientation + * value is value + (-30 ~ 30). + */ + input_set_abs_params(input, ABS_MT_ORIENTATION, + -127, 127, 0, 0); + } + if (cyapa->gen >= CYAPA_GEN5) { + input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 255, 0, 0); + } input_abs_set_res(input, ABS_MT_POSITION_X, cyapa->max_abs_x / cyapa->physical_size_x); @@ -838,16 +468,720 @@ static int cyapa_create_input_dev(struct cyapa *cyapa) return error; } + /* Register the device in input subsystem */ + error = input_register_device(input); + if (error) { + dev_err(dev, "failed to register input device: %d\n", error); + return error; + } + cyapa->input = input; return 0; } +static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa) +{ + struct input_dev *input = cyapa->input; + + if (!input || !input->users) { + /* + * When input is NULL, TP must be in deep sleep mode. + * In this mode, later non-power I2C command will always failed + * if not bring it out of deep sleep mode firstly, + * so must command TP to active mode here. + */ + if (!input || cyapa->operational) + cyapa->ops->set_power_mode(cyapa, + PWR_MODE_FULL_ACTIVE, 0); + /* Gen3 always using polling mode for command. */ + if (cyapa->gen >= CYAPA_GEN5) + enable_irq(cyapa->client->irq); + } +} + +static void cyapa_disable_irq_for_cmd(struct cyapa *cyapa) +{ + struct input_dev *input = cyapa->input; + + if (!input || !input->users) { + if (cyapa->gen >= CYAPA_GEN5) + disable_irq(cyapa->client->irq); + if (!input || cyapa->operational) + cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); + } +} + +/* + * cyapa_sleep_time_to_pwr_cmd and cyapa_pwr_cmd_to_sleep_time + * + * These are helper functions that convert to and from integer idle + * times and register settings to write to the PowerMode register. + * The trackpad supports between 20ms to 1000ms scan intervals. + * The time will be increased in increments of 10ms from 20ms to 100ms. + * From 100ms to 1000ms, time will be increased in increments of 20ms. + * + * When Idle_Time < 100, the format to convert Idle_Time to Idle_Command is: + * Idle_Command = Idle Time / 10; + * When Idle_Time >= 100, the format to convert Idle_Time to Idle_Command is: + * Idle_Command = Idle Time / 20 + 5; + */ +u8 cyapa_sleep_time_to_pwr_cmd(u16 sleep_time) +{ + u16 encoded_time; + + sleep_time = clamp_val(sleep_time, 20, 1000); + encoded_time = sleep_time < 100 ? sleep_time / 10 : sleep_time / 20 + 5; + return (encoded_time << 2) & PWR_MODE_MASK; +} + +u16 cyapa_pwr_cmd_to_sleep_time(u8 pwr_mode) +{ + u8 encoded_time = pwr_mode >> 2; + + return (encoded_time < 10) ? encoded_time * 10 + : (encoded_time - 5) * 20; +} + +/* 0 on driver initialize and detected successfully, negative on failure. */ +static int cyapa_initialize(struct cyapa *cyapa) +{ + int error = 0; + + cyapa->state = CYAPA_STATE_NO_DEVICE; + cyapa->gen = CYAPA_GEN_UNKNOWN; + mutex_init(&cyapa->state_sync_lock); + + /* + * Set to hard code default, they will be updated with trackpad set + * default values after probe and initialized. + */ + cyapa->suspend_power_mode = PWR_MODE_SLEEP; + cyapa->suspend_sleep_time = + cyapa_pwr_cmd_to_sleep_time(cyapa->suspend_power_mode); + + /* ops.initialize() is aimed to prepare for module communications. */ + error = cyapa_gen3_ops.initialize(cyapa); + if (!error) + error = cyapa_gen5_ops.initialize(cyapa); + if (error) + return error; + + error = cyapa_detect(cyapa); + if (error) + return error; + + /* Power down the device until we need it. */ + if (cyapa->operational) + cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); + + return 0; +} + +static int cyapa_reinitialize(struct cyapa *cyapa) +{ + struct device *dev = &cyapa->client->dev; + struct input_dev *input = cyapa->input; + int error; + + if (pm_runtime_enabled(dev)) + pm_runtime_disable(dev); + + /* Avoid command failures when TP was in OFF state. */ + if (cyapa->operational) + cyapa->ops->set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE, 0); + + error = cyapa_detect(cyapa); + if (error) + goto out; + + if (!input && cyapa->operational) { + error = cyapa_create_input_dev(cyapa); + if (error) { + dev_err(dev, "create input_dev instance failed: %d\n", + error); + goto out; + } + } + +out: + if (!input || !input->users) { + /* Reset to power OFF state to save power when no user open. */ + if (cyapa->operational) + cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); + } else if (!error && cyapa->operational) { + /* + * Make sure only enable runtime PM when device is + * in operational mode and input->users > 0. + */ + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + } + + return error; +} + +static irqreturn_t cyapa_irq(int irq, void *dev_id) +{ + struct cyapa *cyapa = dev_id; + struct device *dev = &cyapa->client->dev; + + pm_runtime_get_sync(dev); + if (device_may_wakeup(dev)) + pm_wakeup_event(dev, 0); + + /* Interrupt event maybe cuased by host command to trackpad device. */ + if (cyapa->ops->irq_cmd_handler(cyapa)) { + /* + * Interrupt event maybe from trackpad device input reporting. + */ + if (!cyapa->input) { + /* + * Still in probling or in firware image + * udpating or reading. + */ + cyapa->ops->sort_empty_output_data(cyapa, + NULL, NULL, NULL); + goto out; + } + + if (!cyapa->operational || cyapa->ops->irq_handler(cyapa)) { + if (!mutex_trylock(&cyapa->state_sync_lock)) { + cyapa->ops->sort_empty_output_data(cyapa, + NULL, NULL, NULL); + goto out; + } + cyapa_reinitialize(cyapa); + mutex_unlock(&cyapa->state_sync_lock); + } + } + +out: + pm_runtime_mark_last_busy(dev); + pm_runtime_put_sync_autosuspend(dev); + return IRQ_HANDLED; +} + +/* + ************************************************************** + * sysfs interface + ************************************************************** +*/ +#ifdef CONFIG_PM_SLEEP +static ssize_t cyapa_show_suspend_scanrate(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + u8 pwr_cmd = cyapa->suspend_power_mode; + u16 sleep_time; + int len; + int error; + + error = mutex_lock_interruptible(&cyapa->state_sync_lock); + if (error) + return error; + + pwr_cmd = cyapa->suspend_power_mode; + sleep_time = cyapa->suspend_sleep_time; + + mutex_unlock(&cyapa->state_sync_lock); + + switch (pwr_cmd) { + case PWR_MODE_BTN_ONLY: + len = scnprintf(buf, PAGE_SIZE, "%s\n", BTN_ONLY_MODE_NAME); + break; + + case PWR_MODE_OFF: + len = scnprintf(buf, PAGE_SIZE, "%s\n", OFF_MODE_NAME); + break; + + default: + len = scnprintf(buf, PAGE_SIZE, "%u\n", + cyapa->gen == CYAPA_GEN3 ? + cyapa_pwr_cmd_to_sleep_time(pwr_cmd) : + sleep_time); + break; + } + + return len; +} + +static ssize_t cyapa_update_suspend_scanrate(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + u16 sleep_time; + int error; + + error = mutex_lock_interruptible(&cyapa->state_sync_lock); + if (error) + return error; + + if (sysfs_streq(buf, BTN_ONLY_MODE_NAME)) { + cyapa->suspend_power_mode = PWR_MODE_BTN_ONLY; + } else if (sysfs_streq(buf, OFF_MODE_NAME)) { + cyapa->suspend_power_mode = PWR_MODE_OFF; + } else if (!kstrtou16(buf, 10, &sleep_time)) { + cyapa->suspend_sleep_time = max_t(u16, sleep_time, 1000); + cyapa->suspend_power_mode = + cyapa_sleep_time_to_pwr_cmd(cyapa->suspend_sleep_time); + } else { + count = -EINVAL; + } + + mutex_unlock(&cyapa->state_sync_lock); + + return count; +} + +static DEVICE_ATTR(suspend_scanrate_ms, S_IRUGO|S_IWUSR, + cyapa_show_suspend_scanrate, + cyapa_update_suspend_scanrate); + +static struct attribute *cyapa_power_wakeup_entries[] = { + &dev_attr_suspend_scanrate_ms.attr, + NULL, +}; + +static const struct attribute_group cyapa_power_wakeup_group = { + .name = power_group_name, + .attrs = cyapa_power_wakeup_entries, +}; + +static void cyapa_remove_power_wakeup_group(void *data) +{ + struct cyapa *cyapa = data; + + sysfs_unmerge_group(&cyapa->client->dev.kobj, + &cyapa_power_wakeup_group); +} + +static int cyapa_prepare_wakeup_controls(struct cyapa *cyapa) +{ + struct i2c_client *client = cyapa->client; + struct device *dev = &client->dev; + int error; + + if (device_can_wakeup(dev)) { + error = sysfs_merge_group(&client->dev.kobj, + &cyapa_power_wakeup_group); + if (error) { + dev_err(dev, "failed to add power wakeup group: %d\n", + error); + return error; + } + + error = devm_add_action(dev, + cyapa_remove_power_wakeup_group, cyapa); + if (error) { + cyapa_remove_power_wakeup_group(cyapa); + dev_err(dev, "failed to add power cleanup action: %d\n", + error); + return error; + } + } + + return 0; +} +#else +static inline int cyapa_prepare_wakeup_controls(struct cyapa *cyapa) +{ + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM +static ssize_t cyapa_show_rt_suspend_scanrate(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + u8 pwr_cmd; + u16 sleep_time; + int error; + + error = mutex_lock_interruptible(&cyapa->state_sync_lock); + if (error) + return error; + + pwr_cmd = cyapa->runtime_suspend_power_mode; + sleep_time = cyapa->runtime_suspend_sleep_time; + + mutex_unlock(&cyapa->state_sync_lock); + + return scnprintf(buf, PAGE_SIZE, "%u\n", + cyapa->gen == CYAPA_GEN3 ? + cyapa_pwr_cmd_to_sleep_time(pwr_cmd) : + sleep_time); +} + +static ssize_t cyapa_update_rt_suspend_scanrate(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + u16 time; + int error; + + if (buf == NULL || count == 0 || kstrtou16(buf, 10, &time)) { + dev_err(dev, "invalid runtime suspend scanrate ms parameter\n"); + return -EINVAL; + } + + /* + * When the suspend scanrate is changed, pm_runtime_get to resume + * a potentially suspended device, update to the new pwr_cmd + * and then pm_runtime_put to suspend into the new power mode. + */ + pm_runtime_get_sync(dev); + + error = mutex_lock_interruptible(&cyapa->state_sync_lock); + if (error) + return error; + + cyapa->runtime_suspend_sleep_time = max_t(u16, time, 1000); + cyapa->runtime_suspend_power_mode = + cyapa_sleep_time_to_pwr_cmd(cyapa->runtime_suspend_sleep_time); + + mutex_unlock(&cyapa->state_sync_lock); + + pm_runtime_put_sync_autosuspend(dev); + + return count; +} + +static DEVICE_ATTR(runtime_suspend_scanrate_ms, S_IRUGO|S_IWUSR, + cyapa_show_rt_suspend_scanrate, + cyapa_update_rt_suspend_scanrate); + +static struct attribute *cyapa_power_runtime_entries[] = { + &dev_attr_runtime_suspend_scanrate_ms.attr, + NULL, +}; + +static const struct attribute_group cyapa_power_runtime_group = { + .name = power_group_name, + .attrs = cyapa_power_runtime_entries, +}; + +static void cyapa_remove_power_runtime_group(void *data) +{ + struct cyapa *cyapa = data; + + sysfs_unmerge_group(&cyapa->client->dev.kobj, + &cyapa_power_runtime_group); +} + +static int cyapa_start_runtime(struct cyapa *cyapa) +{ + struct device *dev = &cyapa->client->dev; + int error; + + cyapa->runtime_suspend_power_mode = PWR_MODE_IDLE; + cyapa->runtime_suspend_sleep_time = + cyapa_pwr_cmd_to_sleep_time(cyapa->runtime_suspend_power_mode); + + error = sysfs_merge_group(&dev->kobj, &cyapa_power_runtime_group); + if (error) { + dev_err(dev, + "failed to create power runtime group: %d\n", error); + return error; + } + + error = devm_add_action(dev, cyapa_remove_power_runtime_group, cyapa); + if (error) { + cyapa_remove_power_runtime_group(cyapa); + dev_err(dev, + "failed to add power runtime cleanup action: %d\n", + error); + return error; + } + + /* runtime is enabled until device is operational and opened. */ + pm_runtime_set_suspended(dev); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_DELAY); + + return 0; +} +#else +static inline int cyapa_start_runtime(struct cyapa *cyapa) +{ + return 0; +} +#endif /* CONFIG_PM */ + +static ssize_t cyapa_show_fm_ver(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int error; + struct cyapa *cyapa = dev_get_drvdata(dev); + + error = mutex_lock_interruptible(&cyapa->state_sync_lock); + if (error) + return error; + error = scnprintf(buf, PAGE_SIZE, "%d.%d\n", cyapa->fw_maj_ver, + cyapa->fw_min_ver); + mutex_unlock(&cyapa->state_sync_lock); + return error; +} + +static ssize_t cyapa_show_product_id(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + int size; + int error; + + error = mutex_lock_interruptible(&cyapa->state_sync_lock); + if (error) + return error; + size = scnprintf(buf, PAGE_SIZE, "%s\n", cyapa->product_id); + mutex_unlock(&cyapa->state_sync_lock); + return size; +} + +static int cyapa_firmware(struct cyapa *cyapa, const char *fw_name) +{ + struct device *dev = &cyapa->client->dev; + const struct firmware *fw; + int error; + + error = request_firmware(&fw, fw_name, dev); + if (error) { + dev_err(dev, "Could not load firmware from %s: %d\n", + fw_name, error); + return error; + } + + error = cyapa->ops->check_fw(cyapa, fw); + if (error) { + dev_err(dev, "Invalid CYAPA firmware image: %s\n", + fw_name); + goto done; + } + + /* + * Resume the potentially suspended device because doing FW + * update on a device not in the FULL mode has a chance to + * fail. + */ + pm_runtime_get_sync(dev); + + /* Require IRQ support for firmware update commands. */ + cyapa_enable_irq_for_cmd(cyapa); + + error = cyapa->ops->bl_enter(cyapa); + if (error) { + dev_err(dev, "bl_enter failed, %d\n", error); + goto err_detect; + } + + error = cyapa->ops->bl_activate(cyapa); + if (error) { + dev_err(dev, "bl_activate failed, %d\n", error); + goto err_detect; + } + + error = cyapa->ops->bl_initiate(cyapa, fw); + if (error) { + dev_err(dev, "bl_initiate failed, %d\n", error); + goto err_detect; + } + + error = cyapa->ops->update_fw(cyapa, fw); + if (error) { + dev_err(dev, "update_fw failed, %d\n", error); + goto err_detect; + } + +err_detect: + cyapa_disable_irq_for_cmd(cyapa); + pm_runtime_put_noidle(dev); + +done: + release_firmware(fw); + return error; +} + +static ssize_t cyapa_update_fw_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + char fw_name[NAME_MAX]; + int ret, error; + + if (count >= NAME_MAX) { + dev_err(dev, "File name too long\n"); + return -EINVAL; + } + + memcpy(fw_name, buf, count); + if (fw_name[count - 1] == '\n') + fw_name[count - 1] = '\0'; + else + fw_name[count] = '\0'; + + if (cyapa->input) { + /* + * Force the input device to be registered after the firmware + * image is updated, so if the corresponding parameters updated + * in the new firmware image can taken effect immediately. + */ + input_unregister_device(cyapa->input); + cyapa->input = NULL; + } + + error = mutex_lock_interruptible(&cyapa->state_sync_lock); + if (error) { + /* + * Whatever, do reinitialize to try to recover TP state to + * previous state just as it entered fw update entrance. + */ + cyapa_reinitialize(cyapa); + return error; + } + + error = cyapa_firmware(cyapa, fw_name); + if (error) + dev_err(dev, "firmware update failed: %d\n", error); + else + dev_dbg(dev, "firmware update successfully done.\n"); + + /* + * Redetect trackpad device states because firmware update process + * will reset trackpad device into bootloader mode. + */ + ret = cyapa_reinitialize(cyapa); + if (ret) { + dev_err(dev, "failed to redetect after updated: %d\n", ret); + error = error ? error : ret; + } + + mutex_unlock(&cyapa->state_sync_lock); + + return error ? error : count; +} + +static ssize_t cyapa_calibrate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + int error; + + error = mutex_lock_interruptible(&cyapa->state_sync_lock); + if (error) + return error; + + if (cyapa->operational) { + cyapa_enable_irq_for_cmd(cyapa); + error = cyapa->ops->calibrate_store(dev, attr, buf, count); + cyapa_disable_irq_for_cmd(cyapa); + } else { + error = -EBUSY; /* Still running in bootloader mode. */ + } + + mutex_unlock(&cyapa->state_sync_lock); + return error < 0 ? error : count; +} + +static ssize_t cyapa_show_baseline(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + ssize_t error; + + error = mutex_lock_interruptible(&cyapa->state_sync_lock); + if (error) + return error; + + if (cyapa->operational) { + cyapa_enable_irq_for_cmd(cyapa); + error = cyapa->ops->show_baseline(dev, attr, buf); + cyapa_disable_irq_for_cmd(cyapa); + } else { + error = -EBUSY; /* Still running in bootloader mode. */ + } + + mutex_unlock(&cyapa->state_sync_lock); + return error; +} + +static char *cyapa_state_to_string(struct cyapa *cyapa) +{ + switch (cyapa->state) { + case CYAPA_STATE_BL_BUSY: + return "bootloader busy"; + case CYAPA_STATE_BL_IDLE: + return "bootloader idle"; + case CYAPA_STATE_BL_ACTIVE: + return "bootloader active"; + case CYAPA_STATE_GEN5_BL: + return "bootloader"; + case CYAPA_STATE_OP: + case CYAPA_STATE_GEN5_APP: + return "operational"; /* Normal valid state. */ + default: + return "invalid mode"; + } +} + +static ssize_t cyapa_show_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + int size; + int error; + + error = mutex_lock_interruptible(&cyapa->state_sync_lock); + if (error) + return error; + + size = scnprintf(buf, PAGE_SIZE, "gen%d %s\n", + cyapa->gen, cyapa_state_to_string(cyapa)); + + mutex_unlock(&cyapa->state_sync_lock); + return size; +} + +static DEVICE_ATTR(firmware_version, S_IRUGO, cyapa_show_fm_ver, NULL); +static DEVICE_ATTR(product_id, S_IRUGO, cyapa_show_product_id, NULL); +static DEVICE_ATTR(update_fw, S_IWUSR, NULL, cyapa_update_fw_store); +static DEVICE_ATTR(baseline, S_IRUGO, cyapa_show_baseline, NULL); +static DEVICE_ATTR(calibrate, S_IWUSR, NULL, cyapa_calibrate_store); +static DEVICE_ATTR(mode, S_IRUGO, cyapa_show_mode, NULL); + +static struct attribute *cyapa_sysfs_entries[] = { + &dev_attr_firmware_version.attr, + &dev_attr_product_id.attr, + &dev_attr_update_fw.attr, + &dev_attr_baseline.attr, + &dev_attr_calibrate.attr, + &dev_attr_mode.attr, + NULL, +}; + +static const struct attribute_group cyapa_sysfs_group = { + .attrs = cyapa_sysfs_entries, +}; + +static void cyapa_remove_sysfs_group(void *data) +{ + struct cyapa *cyapa = data; + + sysfs_remove_group(&cyapa->client->dev.kobj, &cyapa_sysfs_group); +} + static int cyapa_probe(struct i2c_client *client, const struct i2c_device_id *dev_id) { struct device *dev = &client->dev; struct cyapa *cyapa; u8 adapter_func; + union i2c_smbus_data dummy; int error; adapter_func = cyapa_check_adapter_functionality(client); @@ -856,38 +1190,54 @@ static int cyapa_probe(struct i2c_client *client, return -EIO; } + /* Make sure there is something at this address */ + if (i2c_smbus_xfer(client->adapter, client->addr, 0, + I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) + return -ENODEV; + cyapa = devm_kzalloc(dev, sizeof(struct cyapa), GFP_KERNEL); if (!cyapa) return -ENOMEM; - cyapa->gen = CYAPA_GEN3; - cyapa->client = client; - i2c_set_clientdata(client, cyapa); - sprintf(cyapa->phys, "i2c-%d-%04x/input0", client->adapter->nr, - client->addr); - /* i2c isn't supported, use smbus */ if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS) cyapa->smbus = true; - cyapa->state = CYAPA_STATE_NO_DEVICE; + cyapa->client = client; + i2c_set_clientdata(client, cyapa); + sprintf(cyapa->phys, "i2c-%d-%04x/input0", client->adapter->nr, + client->addr); - error = cyapa_check_is_operational(cyapa); + error = cyapa_initialize(cyapa); if (error) { - dev_err(dev, "device not operational, %d\n", error); + dev_err(dev, "failed to detect and initialize tp device.\n"); return error; } - /* Power down the device until we need it */ - error = cyapa_set_power_mode(cyapa, PWR_MODE_OFF); + error = sysfs_create_group(&client->dev.kobj, &cyapa_sysfs_group); if (error) { - dev_err(dev, "failed to quiesce the device: %d\n", error); + dev_err(dev, "failed to create sysfs entries: %d\n", error); return error; } - error = cyapa_create_input_dev(cyapa); - if (error) + error = devm_add_action(dev, cyapa_remove_sysfs_group, cyapa); + if (error) { + cyapa_remove_sysfs_group(cyapa); + dev_err(dev, "failed to add sysfs cleanup action: %d\n", error); return error; + } + + error = cyapa_prepare_wakeup_controls(cyapa); + if (error) { + dev_err(dev, "failed to prepare wakeup controls: %d\n", error); + return error; + } + + error = cyapa_start_runtime(cyapa); + if (error) { + dev_err(dev, "failed to start pm_runtime: %d\n", error); + return error; + } error = devm_request_threaded_irq(dev, client->irq, NULL, cyapa_irq, @@ -901,11 +1251,18 @@ static int cyapa_probe(struct i2c_client *client, /* Disable IRQ until the device is opened */ disable_irq(client->irq); - /* Register the device in input subsystem */ - error = input_register_device(cyapa->input); - if (error) { - dev_err(dev, "failed to register input device: %d\n", error); - return error; + /* + * Register the device in the input subsystem when it's operational. + * Otherwise, keep in this driver, so it can be be recovered or updated + * through the sysfs mode and update_fw interfaces by user or apps. + */ + if (cyapa->operational) { + error = cyapa_create_input_dev(cyapa); + if (error) { + dev_err(dev, "create input_dev instance failed: %d\n", + error); + return error; + } } return 0; @@ -915,32 +1272,40 @@ static int __maybe_unused cyapa_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct cyapa *cyapa = i2c_get_clientdata(client); - struct input_dev *input = cyapa->input; u8 power_mode; int error; - error = mutex_lock_interruptible(&input->mutex); + error = mutex_lock_interruptible(&cyapa->state_sync_lock); if (error) return error; + /* + * Runtime PM is enable only when device is in operational mode and + * users in use, so need check it before disable it to + * avoid unbalance warning. + */ + if (pm_runtime_enabled(dev)) + pm_runtime_disable(dev); disable_irq(client->irq); /* * Set trackpad device to idle mode if wakeup is allowed, * otherwise turn off. */ - power_mode = device_may_wakeup(dev) ? PWR_MODE_IDLE - : PWR_MODE_OFF; - error = cyapa_set_power_mode(cyapa, power_mode); - if (error) - dev_err(dev, "resume: set power mode to %d failed: %d\n", - power_mode, error); + if (cyapa->operational) { + power_mode = device_may_wakeup(dev) ? cyapa->suspend_power_mode + : PWR_MODE_OFF; + error = cyapa->ops->set_power_mode(cyapa, power_mode, + cyapa->suspend_sleep_time); + if (error) + dev_err(dev, "suspend set power mode failed: %d\n", + error); + } if (device_may_wakeup(dev)) cyapa->irq_wake = (enable_irq_wake(client->irq) == 0); - mutex_unlock(&input->mutex); - + mutex_unlock(&cyapa->state_sync_lock); return 0; } @@ -948,29 +1313,56 @@ static int __maybe_unused cyapa_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct cyapa *cyapa = i2c_get_clientdata(client); - struct input_dev *input = cyapa->input; - u8 power_mode; int error; - mutex_lock(&input->mutex); + mutex_lock(&cyapa->state_sync_lock); - if (device_may_wakeup(dev) && cyapa->irq_wake) + if (device_may_wakeup(dev) && cyapa->irq_wake) { disable_irq_wake(client->irq); + cyapa->irq_wake = false; + } - power_mode = input->users ? PWR_MODE_FULL_ACTIVE : PWR_MODE_OFF; - error = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE); + /* Update device states and runtime PM states. */ + error = cyapa_reinitialize(cyapa); if (error) - dev_warn(dev, "resume: set power mode to %d failed: %d\n", - power_mode, error); + dev_warn(dev, "failed to reinitialize TP device: %d\n", error); enable_irq(client->irq); - mutex_unlock(&input->mutex); + mutex_unlock(&cyapa->state_sync_lock); + return 0; +} + +static int __maybe_unused cyapa_runtime_suspend(struct device *dev) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + int error; + + error = cyapa->ops->set_power_mode(cyapa, + cyapa->runtime_suspend_power_mode, + cyapa->runtime_suspend_sleep_time); + if (error) + dev_warn(dev, "runtime suspend failed: %d\n", error); return 0; } -static SIMPLE_DEV_PM_OPS(cyapa_pm_ops, cyapa_suspend, cyapa_resume); +static int __maybe_unused cyapa_runtime_resume(struct device *dev) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + int error; + + error = cyapa->ops->set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE, 0); + if (error) + dev_warn(dev, "runtime resume failed: %d\n", error); + + return 0; +} + +static const struct dev_pm_ops cyapa_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(cyapa_suspend, cyapa_resume) + SET_RUNTIME_PM_OPS(cyapa_runtime_suspend, cyapa_runtime_resume, NULL) +}; static const struct i2c_device_id cyapa_id_table[] = { { "cyapa", 0 }, @@ -978,11 +1370,21 @@ static const struct i2c_device_id cyapa_id_table[] = { }; MODULE_DEVICE_TABLE(i2c, cyapa_id_table); +#ifdef CONFIG_ACPI +static const struct acpi_device_id cyapa_acpi_id[] = { + { "CYAP0000", 0 }, /* Gen3 trackpad with 0x67 I2C address. */ + { "CYAP0001", 0 }, /* Gen5 trackpad with 0x24 I2C address. */ + { } +}; +MODULE_DEVICE_TABLE(acpi, cyapa_acpi_id); +#endif + static struct i2c_driver cyapa_driver = { .driver = { .name = "cyapa", .owner = THIS_MODULE, .pm = &cyapa_pm_ops, + .acpi_match_table = ACPI_PTR(cyapa_acpi_id), }, .probe = cyapa_probe, diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h new file mode 100644 index 000000000000..adc9ed5dcb0e --- /dev/null +++ b/drivers/input/mouse/cyapa.h @@ -0,0 +1,301 @@ +/* + * Cypress APA trackpad with I2C interface + * + * Author: Dudley Du + * + * Copyright (C) 2014 Cypress 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 for + * more details. + */ + +#ifndef _CYAPA_H +#define _CYAPA_H + +#include + +/* APA trackpad firmware generation number. */ +#define CYAPA_GEN_UNKNOWN 0x00 /* unknown protocol. */ +#define CYAPA_GEN3 0x03 /* support MT-protocol B with tracking ID. */ +#define CYAPA_GEN5 0x05 /* support TrueTouch GEN5 trackpad device. */ + +#define CYAPA_NAME "Cypress APA Trackpad (cyapa)" + +/* + * Macros for SMBus communication + */ +#define SMBUS_READ 0x01 +#define SMBUS_WRITE 0x00 +#define SMBUS_ENCODE_IDX(cmd, idx) ((cmd) | (((idx) & 0x03) << 1)) +#define SMBUS_ENCODE_RW(cmd, rw) ((cmd) | ((rw) & 0x01)) +#define SMBUS_BYTE_BLOCK_CMD_MASK 0x80 +#define SMBUS_GROUP_BLOCK_CMD_MASK 0x40 + +/* Commands for read/write registers of Cypress trackpad */ +#define CYAPA_CMD_SOFT_RESET 0x00 +#define CYAPA_CMD_POWER_MODE 0x01 +#define CYAPA_CMD_DEV_STATUS 0x02 +#define CYAPA_CMD_GROUP_DATA 0x03 +#define CYAPA_CMD_GROUP_CMD 0x04 +#define CYAPA_CMD_GROUP_QUERY 0x05 +#define CYAPA_CMD_BL_STATUS 0x06 +#define CYAPA_CMD_BL_HEAD 0x07 +#define CYAPA_CMD_BL_CMD 0x08 +#define CYAPA_CMD_BL_DATA 0x09 +#define CYAPA_CMD_BL_ALL 0x0a +#define CYAPA_CMD_BLK_PRODUCT_ID 0x0b +#define CYAPA_CMD_BLK_HEAD 0x0c +#define CYAPA_CMD_MAX_BASELINE 0x0d +#define CYAPA_CMD_MIN_BASELINE 0x0e + +#define BL_HEAD_OFFSET 0x00 +#define BL_DATA_OFFSET 0x10 + +#define BL_STATUS_SIZE 3 /* Length of gen3 bootloader status registers */ +#define CYAPA_REG_MAP_SIZE 256 + +/* + * Gen3 Operational Device Status Register + * + * bit 7: Valid interrupt source + * bit 6 - 4: Reserved + * bit 3 - 2: Power status + * bit 1 - 0: Device status + */ +#define REG_OP_STATUS 0x00 +#define OP_STATUS_SRC 0x80 +#define OP_STATUS_POWER 0x0c +#define OP_STATUS_DEV 0x03 +#define OP_STATUS_MASK (OP_STATUS_SRC | OP_STATUS_POWER | OP_STATUS_DEV) + +/* + * Operational Finger Count/Button Flags Register + * + * bit 7 - 4: Number of touched finger + * bit 3: Valid data + * bit 2: Middle Physical Button + * bit 1: Right Physical Button + * bit 0: Left physical Button + */ +#define REG_OP_DATA1 0x01 +#define OP_DATA_VALID 0x08 +#define OP_DATA_MIDDLE_BTN 0x04 +#define OP_DATA_RIGHT_BTN 0x02 +#define OP_DATA_LEFT_BTN 0x01 +#define OP_DATA_BTN_MASK (OP_DATA_MIDDLE_BTN | OP_DATA_RIGHT_BTN | \ + OP_DATA_LEFT_BTN) + +/* + * Write-only command file register used to issue commands and + * parameters to the bootloader. + * The default value read from it is always 0x00. + */ +#define REG_BL_FILE 0x00 +#define BL_FILE 0x00 + +/* + * Bootloader Status Register + * + * bit 7: Busy + * bit 6 - 5: Reserved + * bit 4: Bootloader running + * bit 3 - 2: Reserved + * bit 1: Watchdog Reset + * bit 0: Checksum valid + */ +#define REG_BL_STATUS 0x01 +#define BL_STATUS_REV_6_5 0x60 +#define BL_STATUS_BUSY 0x80 +#define BL_STATUS_RUNNING 0x10 +#define BL_STATUS_REV_3_2 0x0c +#define BL_STATUS_WATCHDOG 0x02 +#define BL_STATUS_CSUM_VALID 0x01 +#define BL_STATUS_REV_MASK (BL_STATUS_WATCHDOG | BL_STATUS_REV_3_2 | \ + BL_STATUS_REV_6_5) + +/* + * Bootloader Error Register + * + * bit 7: Invalid + * bit 6: Invalid security key + * bit 5: Bootloading + * bit 4: Command checksum + * bit 3: Flash protection error + * bit 2: Flash checksum error + * bit 1 - 0: Reserved + */ +#define REG_BL_ERROR 0x02 +#define BL_ERROR_INVALID 0x80 +#define BL_ERROR_INVALID_KEY 0x40 +#define BL_ERROR_BOOTLOADING 0x20 +#define BL_ERROR_CMD_CSUM 0x10 +#define BL_ERROR_FLASH_PROT 0x08 +#define BL_ERROR_FLASH_CSUM 0x04 +#define BL_ERROR_RESERVED 0x03 +#define BL_ERROR_NO_ERR_IDLE 0x00 +#define BL_ERROR_NO_ERR_ACTIVE (BL_ERROR_BOOTLOADING) + +#define CAPABILITY_BTN_SHIFT 3 +#define CAPABILITY_LEFT_BTN_MASK (0x01 << 3) +#define CAPABILITY_RIGHT_BTN_MASK (0x01 << 4) +#define CAPABILITY_MIDDLE_BTN_MASK (0x01 << 5) +#define CAPABILITY_BTN_MASK (CAPABILITY_LEFT_BTN_MASK | \ + CAPABILITY_RIGHT_BTN_MASK | \ + CAPABILITY_MIDDLE_BTN_MASK) + +#define PWR_MODE_MASK 0xfc +#define PWR_MODE_FULL_ACTIVE (0x3f << 2) +#define PWR_MODE_IDLE (0x03 << 2) /* Default rt suspend scanrate: 30ms */ +#define PWR_MODE_SLEEP (0x05 << 2) /* Default suspend scanrate: 50ms */ +#define PWR_MODE_BTN_ONLY (0x01 << 2) +#define PWR_MODE_OFF (0x00 << 2) + +#define PWR_STATUS_MASK 0x0c +#define PWR_STATUS_ACTIVE (0x03 << 2) +#define PWR_STATUS_IDLE (0x02 << 2) +#define PWR_STATUS_BTN_ONLY (0x01 << 2) +#define PWR_STATUS_OFF (0x00 << 2) + +#define AUTOSUSPEND_DELAY 2000 /* unit : ms */ + +#define UNINIT_SLEEP_TIME 0xFFFF +#define UNINIT_PWR_MODE 0xFF + +#define BTN_ONLY_MODE_NAME "buttononly" +#define OFF_MODE_NAME "off" + +/* The touch.id is used as the MT slot id, thus max MT slot is 15 */ +#define CYAPA_MAX_MT_SLOTS 15 + +struct cyapa; + +typedef bool (*cb_sort)(struct cyapa *, u8 *, int); + +struct cyapa_dev_ops { + int (*check_fw)(struct cyapa *, const struct firmware *); + int (*bl_enter)(struct cyapa *); + int (*bl_activate)(struct cyapa *); + int (*bl_initiate)(struct cyapa *, const struct firmware *); + int (*update_fw)(struct cyapa *, const struct firmware *); + int (*bl_deactivate)(struct cyapa *); + + ssize_t (*show_baseline)(struct device *, + struct device_attribute *, char *); + ssize_t (*calibrate_store)(struct device *, + struct device_attribute *, const char *, size_t); + + int (*initialize)(struct cyapa *cyapa); + + int (*state_parse)(struct cyapa *cyapa, u8 *reg_status, int len); + int (*operational_check)(struct cyapa *cyapa); + + int (*irq_handler)(struct cyapa *); + bool (*irq_cmd_handler)(struct cyapa *); + int (*sort_empty_output_data)(struct cyapa *, + u8 *, int *, cb_sort); + + int (*set_power_mode)(struct cyapa *, u8, u16); +}; + +struct cyapa_gen5_cmd_states { + struct mutex cmd_lock; + struct completion cmd_ready; + atomic_t cmd_issued; + u8 in_progress_cmd; + bool is_irq_mode; + + cb_sort resp_sort_func; + u8 *resp_data; + int *resp_len; + + u8 irq_cmd_buf[CYAPA_REG_MAP_SIZE]; + u8 empty_buf[CYAPA_REG_MAP_SIZE]; +}; + +union cyapa_cmd_states { + struct cyapa_gen5_cmd_states gen5; +}; + +enum cyapa_state { + CYAPA_STATE_NO_DEVICE, + CYAPA_STATE_BL_BUSY, + CYAPA_STATE_BL_IDLE, + CYAPA_STATE_BL_ACTIVE, + CYAPA_STATE_OP, + CYAPA_STATE_GEN5_BL, + CYAPA_STATE_GEN5_APP, +}; + +/* The main device structure */ +struct cyapa { + enum cyapa_state state; + u8 status[BL_STATUS_SIZE]; + bool operational; /* true: ready for data reporting; false: not. */ + + struct i2c_client *client; + struct input_dev *input; + char phys[32]; /* Device physical location */ + bool irq_wake; /* Irq wake is enabled */ + bool smbus; + + /* power mode settings */ + u8 suspend_power_mode; + u16 suspend_sleep_time; + u8 runtime_suspend_power_mode; + u16 runtime_suspend_sleep_time; + u8 dev_pwr_mode; + u16 dev_sleep_time; + + /* Read from query data region. */ + char product_id[16]; + u8 fw_maj_ver; /* Firmware major version. */ + u8 fw_min_ver; /* Firmware minor version. */ + u8 btn_capability; + u8 gen; + int max_abs_x; + int max_abs_y; + int physical_size_x; + int physical_size_y; + + /* Used in ttsp and truetouch based trackpad devices. */ + u8 x_origin; /* X Axis Origin: 0 = left side; 1 = rigth side. */ + u8 y_origin; /* Y Axis Origin: 0 = top; 1 = bottom. */ + int electrodes_x; /* Number of electrodes on the X Axis*/ + int electrodes_y; /* Number of electrodes on the Y Axis*/ + int electrodes_rx; /* Number of Rx electrodes */ + int aligned_electrodes_rx; /* 4 aligned */ + int max_z; + + /* + * Used to synchronize the access or update the device state. + * And since update firmware and read firmware image process will take + * quite long time, maybe more than 10 seconds, so use mutex_lock + * to sync and wait other interface and detecting are done or ready. + */ + struct mutex state_sync_lock; + + const struct cyapa_dev_ops *ops; + + union cyapa_cmd_states cmd_states; +}; + + +ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len, + u8 *values); +ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len, + u8 *values); + +ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values); + +int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout); + +u8 cyapa_sleep_time_to_pwr_cmd(u16 sleep_time); +u16 cyapa_pwr_cmd_to_sleep_time(u8 pwr_mode); + + +extern const char product_id[]; +extern const struct cyapa_dev_ops cyapa_gen3_ops; +extern const struct cyapa_dev_ops cyapa_gen5_ops; + +#endif diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c new file mode 100644 index 000000000000..77e9d70a986b --- /dev/null +++ b/drivers/input/mouse/cyapa_gen3.c @@ -0,0 +1,1247 @@ +/* + * Cypress APA trackpad with I2C interface + * + * Author: Dudley Du + * Further cleanup and restructuring by: + * Daniel Kurtz + * Benson Leung + * + * Copyright (C) 2011-2014 Cypress Semiconductor, Inc. + * Copyright (C) 2011-2012 Google, 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 for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "cyapa.h" + + +#define GEN3_MAX_FINGERS 5 +#define GEN3_FINGER_NUM(x) (((x) >> 4) & 0x07) + +#define BLK_HEAD_BYTES 32 + +/* Macro for register map group offset. */ +#define PRODUCT_ID_SIZE 16 +#define QUERY_DATA_SIZE 27 +#define REG_PROTOCOL_GEN_QUERY_OFFSET 20 + +#define REG_OFFSET_DATA_BASE 0x0000 +#define REG_OFFSET_COMMAND_BASE 0x0028 +#define REG_OFFSET_QUERY_BASE 0x002a + +#define CYAPA_OFFSET_SOFT_RESET REG_OFFSET_COMMAND_BASE +#define OP_RECALIBRATION_MASK 0x80 +#define OP_REPORT_BASELINE_MASK 0x40 +#define REG_OFFSET_MAX_BASELINE 0x0026 +#define REG_OFFSET_MIN_BASELINE 0x0027 + +#define REG_OFFSET_POWER_MODE (REG_OFFSET_COMMAND_BASE + 1) +#define SET_POWER_MODE_DELAY 10000 /* Unit: us */ +#define SET_POWER_MODE_TRIES 5 + +#define GEN3_BL_CMD_CHECKSUM_SEED 0xff +#define GEN3_BL_CMD_INITIATE_BL 0x38 +#define GEN3_BL_CMD_WRITE_BLOCK 0x39 +#define GEN3_BL_CMD_VERIFY_BLOCK 0x3a +#define GEN3_BL_CMD_TERMINATE_BL 0x3b +#define GEN3_BL_CMD_LAUNCH_APP 0xa5 + +/* + * CYAPA trackpad device states. + * Used in register 0x00, bit1-0, DeviceStatus field. + * Other values indicate device is in an abnormal state and must be reset. + */ +#define CYAPA_DEV_NORMAL 0x03 +#define CYAPA_DEV_BUSY 0x01 + +#define CYAPA_FW_BLOCK_SIZE 64 +#define CYAPA_FW_READ_SIZE 16 +#define CYAPA_FW_HDR_START 0x0780 +#define CYAPA_FW_HDR_BLOCK_COUNT 2 +#define CYAPA_FW_HDR_BLOCK_START (CYAPA_FW_HDR_START / CYAPA_FW_BLOCK_SIZE) +#define CYAPA_FW_HDR_SIZE (CYAPA_FW_HDR_BLOCK_COUNT * \ + CYAPA_FW_BLOCK_SIZE) +#define CYAPA_FW_DATA_START 0x0800 +#define CYAPA_FW_DATA_BLOCK_COUNT 480 +#define CYAPA_FW_DATA_BLOCK_START (CYAPA_FW_DATA_START / CYAPA_FW_BLOCK_SIZE) +#define CYAPA_FW_DATA_SIZE (CYAPA_FW_DATA_BLOCK_COUNT * \ + CYAPA_FW_BLOCK_SIZE) +#define CYAPA_FW_SIZE (CYAPA_FW_HDR_SIZE + CYAPA_FW_DATA_SIZE) +#define CYAPA_CMD_LEN 16 + +#define GEN3_BL_IDLE_FW_MAJ_VER_OFFSET 0x0b +#define GEN3_BL_IDLE_FW_MIN_VER_OFFSET (GEN3_BL_IDLE_FW_MAJ_VER_OFFSET + 1) + + +struct cyapa_touch { + /* + * high bits or x/y position value + * bit 7 - 4: high 4 bits of x position value + * bit 3 - 0: high 4 bits of y position value + */ + u8 xy_hi; + u8 x_lo; /* low 8 bits of x position value. */ + u8 y_lo; /* low 8 bits of y position value. */ + u8 pressure; + /* id range is 1 - 15. It is incremented with every new touch. */ + u8 id; +} __packed; + +struct cyapa_reg_data { + /* + * bit 0 - 1: device status + * bit 3 - 2: power mode + * bit 6 - 4: reserved + * bit 7: interrupt valid bit + */ + u8 device_status; + /* + * bit 7 - 4: number of fingers currently touching pad + * bit 3: valid data check bit + * bit 2: middle mechanism button state if exists + * bit 1: right mechanism button state if exists + * bit 0: left mechanism button state if exists + */ + u8 finger_btn; + /* CYAPA reports up to 5 touches per packet. */ + struct cyapa_touch touches[5]; +} __packed; + +struct gen3_write_block_cmd { + u8 checksum_seed; /* Always be 0xff */ + u8 cmd_code; /* command code: 0x39 */ + u8 key[8]; /* 8-byte security key */ + __be16 block_num; + u8 block_data[CYAPA_FW_BLOCK_SIZE]; + u8 block_checksum; /* Calculated using bytes 12 - 75 */ + u8 cmd_checksum; /* Calculated using bytes 0-76 */ +} __packed; + +static const u8 security_key[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; +static const u8 bl_activate[] = { 0x00, 0xff, 0x38, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07 }; +static const u8 bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07 }; +static const u8 bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07 }; + + + /* for byte read/write command */ +#define CMD_RESET 0 +#define CMD_POWER_MODE 1 +#define CMD_DEV_STATUS 2 +#define CMD_REPORT_MAX_BASELINE 3 +#define CMD_REPORT_MIN_BASELINE 4 +#define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1) +#define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET) +#define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE) +#define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS) +#define CYAPA_SMBUS_MAX_BASELINE SMBUS_BYTE_CMD(CMD_REPORT_MAX_BASELINE) +#define CYAPA_SMBUS_MIN_BASELINE SMBUS_BYTE_CMD(CMD_REPORT_MIN_BASELINE) + + /* for group registers read/write command */ +#define REG_GROUP_DATA 0 +#define REG_GROUP_CMD 2 +#define REG_GROUP_QUERY 3 +#define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3)) +#define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA) +#define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD) +#define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY) + + /* for register block read/write command */ +#define CMD_BL_STATUS 0 +#define CMD_BL_HEAD 1 +#define CMD_BL_CMD 2 +#define CMD_BL_DATA 3 +#define CMD_BL_ALL 4 +#define CMD_BLK_PRODUCT_ID 5 +#define CMD_BLK_HEAD 6 +#define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1)) + +/* register block read/write command in bootloader mode */ +#define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS) +#define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD) +#define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD) +#define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA) +#define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL) + +/* register block read/write command in operational mode */ +#define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID) +#define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD) + + /* for byte read/write command */ +#define CMD_RESET 0 +#define CMD_POWER_MODE 1 +#define CMD_DEV_STATUS 2 +#define CMD_REPORT_MAX_BASELINE 3 +#define CMD_REPORT_MIN_BASELINE 4 +#define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1) +#define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET) +#define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE) +#define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS) +#define CYAPA_SMBUS_MAX_BASELINE SMBUS_BYTE_CMD(CMD_REPORT_MAX_BASELINE) +#define CYAPA_SMBUS_MIN_BASELINE SMBUS_BYTE_CMD(CMD_REPORT_MIN_BASELINE) + + /* for group registers read/write command */ +#define REG_GROUP_DATA 0 +#define REG_GROUP_CMD 2 +#define REG_GROUP_QUERY 3 +#define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3)) +#define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA) +#define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD) +#define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY) + + /* for register block read/write command */ +#define CMD_BL_STATUS 0 +#define CMD_BL_HEAD 1 +#define CMD_BL_CMD 2 +#define CMD_BL_DATA 3 +#define CMD_BL_ALL 4 +#define CMD_BLK_PRODUCT_ID 5 +#define CMD_BLK_HEAD 6 +#define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1)) + +/* register block read/write command in bootloader mode */ +#define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS) +#define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD) +#define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD) +#define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA) +#define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL) + +/* register block read/write command in operational mode */ +#define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID) +#define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD) + +struct cyapa_cmd_len { + u8 cmd; + u8 len; +}; + +/* maps generic CYAPA_CMD_* code to the I2C equivalent */ +static const struct cyapa_cmd_len cyapa_i2c_cmds[] = { + { CYAPA_OFFSET_SOFT_RESET, 1 }, /* CYAPA_CMD_SOFT_RESET */ + { REG_OFFSET_COMMAND_BASE + 1, 1 }, /* CYAPA_CMD_POWER_MODE */ + { REG_OFFSET_DATA_BASE, 1 }, /* CYAPA_CMD_DEV_STATUS */ + { REG_OFFSET_DATA_BASE, sizeof(struct cyapa_reg_data) }, + /* CYAPA_CMD_GROUP_DATA */ + { REG_OFFSET_COMMAND_BASE, 0 }, /* CYAPA_CMD_GROUP_CMD */ + { REG_OFFSET_QUERY_BASE, QUERY_DATA_SIZE }, /* CYAPA_CMD_GROUP_QUERY */ + { BL_HEAD_OFFSET, 3 }, /* CYAPA_CMD_BL_STATUS */ + { BL_HEAD_OFFSET, 16 }, /* CYAPA_CMD_BL_HEAD */ + { BL_HEAD_OFFSET, 16 }, /* CYAPA_CMD_BL_CMD */ + { BL_DATA_OFFSET, 16 }, /* CYAPA_CMD_BL_DATA */ + { BL_HEAD_OFFSET, 32 }, /* CYAPA_CMD_BL_ALL */ + { REG_OFFSET_QUERY_BASE, PRODUCT_ID_SIZE }, + /* CYAPA_CMD_BLK_PRODUCT_ID */ + { REG_OFFSET_DATA_BASE, 32 }, /* CYAPA_CMD_BLK_HEAD */ + { REG_OFFSET_MAX_BASELINE, 1 }, /* CYAPA_CMD_MAX_BASELINE */ + { REG_OFFSET_MIN_BASELINE, 1 }, /* CYAPA_CMD_MIN_BASELINE */ +}; + +static const struct cyapa_cmd_len cyapa_smbus_cmds[] = { + { CYAPA_SMBUS_RESET, 1 }, /* CYAPA_CMD_SOFT_RESET */ + { CYAPA_SMBUS_POWER_MODE, 1 }, /* CYAPA_CMD_POWER_MODE */ + { CYAPA_SMBUS_DEV_STATUS, 1 }, /* CYAPA_CMD_DEV_STATUS */ + { CYAPA_SMBUS_GROUP_DATA, sizeof(struct cyapa_reg_data) }, + /* CYAPA_CMD_GROUP_DATA */ + { CYAPA_SMBUS_GROUP_CMD, 2 }, /* CYAPA_CMD_GROUP_CMD */ + { CYAPA_SMBUS_GROUP_QUERY, QUERY_DATA_SIZE }, + /* CYAPA_CMD_GROUP_QUERY */ + { CYAPA_SMBUS_BL_STATUS, 3 }, /* CYAPA_CMD_BL_STATUS */ + { CYAPA_SMBUS_BL_HEAD, 16 }, /* CYAPA_CMD_BL_HEAD */ + { CYAPA_SMBUS_BL_CMD, 16 }, /* CYAPA_CMD_BL_CMD */ + { CYAPA_SMBUS_BL_DATA, 16 }, /* CYAPA_CMD_BL_DATA */ + { CYAPA_SMBUS_BL_ALL, 32 }, /* CYAPA_CMD_BL_ALL */ + { CYAPA_SMBUS_BLK_PRODUCT_ID, PRODUCT_ID_SIZE }, + /* CYAPA_CMD_BLK_PRODUCT_ID */ + { CYAPA_SMBUS_BLK_HEAD, 16 }, /* CYAPA_CMD_BLK_HEAD */ + { CYAPA_SMBUS_MAX_BASELINE, 1 }, /* CYAPA_CMD_MAX_BASELINE */ + { CYAPA_SMBUS_MIN_BASELINE, 1 }, /* CYAPA_CMD_MIN_BASELINE */ +}; + + +/* + * cyapa_smbus_read_block - perform smbus block read command + * @cyapa - private data structure of the driver + * @cmd - the properly encoded smbus command + * @len - expected length of smbus command result + * @values - buffer to store smbus command result + * + * Returns negative errno, else the number of bytes written. + * + * Note: + * In trackpad device, the memory block allocated for I2C register map + * is 256 bytes, so the max read block for I2C bus is 256 bytes. + */ +ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len, + u8 *values) +{ + ssize_t ret; + u8 index; + u8 smbus_cmd; + u8 *buf; + struct i2c_client *client = cyapa->client; + + if (!(SMBUS_BYTE_BLOCK_CMD_MASK & cmd)) + return -EINVAL; + + if (SMBUS_GROUP_BLOCK_CMD_MASK & cmd) { + /* read specific block registers command. */ + smbus_cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ); + ret = i2c_smbus_read_block_data(client, smbus_cmd, values); + goto out; + } + + ret = 0; + for (index = 0; index * I2C_SMBUS_BLOCK_MAX < len; index++) { + smbus_cmd = SMBUS_ENCODE_IDX(cmd, index); + smbus_cmd = SMBUS_ENCODE_RW(smbus_cmd, SMBUS_READ); + buf = values + I2C_SMBUS_BLOCK_MAX * index; + ret = i2c_smbus_read_block_data(client, smbus_cmd, buf); + if (ret < 0) + goto out; + } + +out: + return ret > 0 ? len : ret; +} + +static s32 cyapa_read_byte(struct cyapa *cyapa, u8 cmd_idx) +{ + u8 cmd; + + if (cyapa->smbus) { + cmd = cyapa_smbus_cmds[cmd_idx].cmd; + cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ); + } else { + cmd = cyapa_i2c_cmds[cmd_idx].cmd; + } + return i2c_smbus_read_byte_data(cyapa->client, cmd); +} + +static s32 cyapa_write_byte(struct cyapa *cyapa, u8 cmd_idx, u8 value) +{ + u8 cmd; + + if (cyapa->smbus) { + cmd = cyapa_smbus_cmds[cmd_idx].cmd; + cmd = SMBUS_ENCODE_RW(cmd, SMBUS_WRITE); + } else { + cmd = cyapa_i2c_cmds[cmd_idx].cmd; + } + return i2c_smbus_write_byte_data(cyapa->client, cmd, value); +} + +ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len, + u8 *values) +{ + return i2c_smbus_read_i2c_block_data(cyapa->client, reg, len, values); +} + +static ssize_t cyapa_i2c_reg_write_block(struct cyapa *cyapa, u8 reg, + size_t len, const u8 *values) +{ + return i2c_smbus_write_i2c_block_data(cyapa->client, reg, len, values); +} + +ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values) +{ + u8 cmd; + size_t len; + + if (cyapa->smbus) { + cmd = cyapa_smbus_cmds[cmd_idx].cmd; + len = cyapa_smbus_cmds[cmd_idx].len; + return cyapa_smbus_read_block(cyapa, cmd, len, values); + } + cmd = cyapa_i2c_cmds[cmd_idx].cmd; + len = cyapa_i2c_cmds[cmd_idx].len; + return cyapa_i2c_reg_read_block(cyapa, cmd, len, values); +} + +/* + * Determine the Gen3 trackpad device's current operating state. + * + */ +static int cyapa_gen3_state_parse(struct cyapa *cyapa, u8 *reg_data, int len) +{ + cyapa->state = CYAPA_STATE_NO_DEVICE; + + /* Parse based on Gen3 characteristic registers and bits */ + if (reg_data[REG_BL_FILE] == BL_FILE && + reg_data[REG_BL_ERROR] == BL_ERROR_NO_ERR_IDLE && + (reg_data[REG_BL_STATUS] == + (BL_STATUS_RUNNING | BL_STATUS_CSUM_VALID) || + reg_data[REG_BL_STATUS] == BL_STATUS_RUNNING)) { + /* + * Normal state after power on or reset, + * REG_BL_STATUS == 0x11, firmware image checksum is valid. + * REG_BL_STATUS == 0x10, firmware image checksum is invalid. + */ + cyapa->gen = CYAPA_GEN3; + cyapa->state = CYAPA_STATE_BL_IDLE; + } else if (reg_data[REG_BL_FILE] == BL_FILE && + (reg_data[REG_BL_STATUS] & BL_STATUS_RUNNING) == + BL_STATUS_RUNNING) { + cyapa->gen = CYAPA_GEN3; + if (reg_data[REG_BL_STATUS] & BL_STATUS_BUSY) { + cyapa->state = CYAPA_STATE_BL_BUSY; + } else { + if ((reg_data[REG_BL_ERROR] & BL_ERROR_BOOTLOADING) == + BL_ERROR_BOOTLOADING) + cyapa->state = CYAPA_STATE_BL_ACTIVE; + else + cyapa->state = CYAPA_STATE_BL_IDLE; + } + } else if ((reg_data[REG_OP_STATUS] & OP_STATUS_SRC) && + (reg_data[REG_OP_DATA1] & OP_DATA_VALID)) { + /* + * Normal state when running in operational mode, + * may also not in full power state or + * busying in command process. + */ + if (GEN3_FINGER_NUM(reg_data[REG_OP_DATA1]) <= + GEN3_MAX_FINGERS) { + /* Finger number data is valid. */ + cyapa->gen = CYAPA_GEN3; + cyapa->state = CYAPA_STATE_OP; + } + } else if (reg_data[REG_OP_STATUS] == 0x0C && + reg_data[REG_OP_DATA1] == 0x08) { + /* Op state when first two registers overwritten with 0x00 */ + cyapa->gen = CYAPA_GEN3; + cyapa->state = CYAPA_STATE_OP; + } else if (reg_data[REG_BL_STATUS] & + (BL_STATUS_RUNNING | BL_STATUS_BUSY)) { + cyapa->gen = CYAPA_GEN3; + cyapa->state = CYAPA_STATE_BL_BUSY; + } + + if (cyapa->gen == CYAPA_GEN3 && (cyapa->state == CYAPA_STATE_OP || + cyapa->state == CYAPA_STATE_BL_IDLE || + cyapa->state == CYAPA_STATE_BL_ACTIVE || + cyapa->state == CYAPA_STATE_BL_BUSY)) + return 0; + + return -EAGAIN; +} + +/* + * Enter bootloader by soft resetting the device. + * + * If device is already in the bootloader, the function just returns. + * Otherwise, reset the device; after reset, device enters bootloader idle + * state immediately. + * + * Returns: + * 0 on success + * -EAGAIN device was reset, but is not now in bootloader idle state + * < 0 if the device never responds within the timeout + */ +static int cyapa_gen3_bl_enter(struct cyapa *cyapa) +{ + int error; + int waiting_time; + + error = cyapa_poll_state(cyapa, 500); + if (error) + return error; + if (cyapa->state == CYAPA_STATE_BL_IDLE) { + /* Already in BL_IDLE. Skipping reset. */ + return 0; + } + + if (cyapa->state != CYAPA_STATE_OP) + return -EAGAIN; + + cyapa->operational = false; + cyapa->state = CYAPA_STATE_NO_DEVICE; + error = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET, 0x01); + if (error) + return -EIO; + + usleep_range(25000, 50000); + waiting_time = 2000; /* For some shipset, max waiting time is 1~2s. */ + do { + error = cyapa_poll_state(cyapa, 500); + if (error) { + if (error == -ETIMEDOUT) { + waiting_time -= 500; + continue; + } + return error; + } + + if ((cyapa->state == CYAPA_STATE_BL_IDLE) && + !(cyapa->status[REG_BL_STATUS] & BL_STATUS_WATCHDOG)) + break; + + msleep(100); + waiting_time -= 100; + } while (waiting_time > 0); + + if ((cyapa->state != CYAPA_STATE_BL_IDLE) || + (cyapa->status[REG_BL_STATUS] & BL_STATUS_WATCHDOG)) + return -EAGAIN; + + return 0; +} + +static int cyapa_gen3_bl_activate(struct cyapa *cyapa) +{ + int error; + + error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_activate), + bl_activate); + if (error) + return error; + + /* Wait for bootloader to activate; takes between 2 and 12 seconds */ + msleep(2000); + error = cyapa_poll_state(cyapa, 11000); + if (error) + return error; + if (cyapa->state != CYAPA_STATE_BL_ACTIVE) + return -EAGAIN; + + return 0; +} + +static int cyapa_gen3_bl_deactivate(struct cyapa *cyapa) +{ + int error; + + error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_deactivate), + bl_deactivate); + if (error) + return error; + + /* Wait for bootloader to switch to idle state; should take < 100ms */ + msleep(100); + error = cyapa_poll_state(cyapa, 500); + if (error) + return error; + if (cyapa->state != CYAPA_STATE_BL_IDLE) + return -EAGAIN; + return 0; +} + +/* + * Exit bootloader + * + * Send bl_exit command, then wait 50 - 100 ms to let device transition to + * operational mode. If this is the first time the device's firmware is + * running, it can take up to 2 seconds to calibrate its sensors. So, poll + * the device's new state for up to 2 seconds. + * + * Returns: + * -EIO failure while reading from device + * -EAGAIN device is stuck in bootloader, b/c it has invalid firmware + * 0 device is supported and in operational mode + */ +static int cyapa_gen3_bl_exit(struct cyapa *cyapa) +{ + int error; + + error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_exit), bl_exit); + if (error) + return error; + + /* + * Wait for bootloader to exit, and operation mode to start. + * Normally, this takes at least 50 ms. + */ + usleep_range(50000, 100000); + /* + * In addition, when a device boots for the first time after being + * updated to new firmware, it must first calibrate its sensors, which + * can take up to an additional 2 seconds. If the device power is + * running low, this may take even longer. + */ + error = cyapa_poll_state(cyapa, 4000); + if (error < 0) + return error; + if (cyapa->state != CYAPA_STATE_OP) + return -EAGAIN; + + return 0; +} + +static u16 cyapa_gen3_csum(const u8 *buf, size_t count) +{ + int i; + u16 csum = 0; + + for (i = 0; i < count; i++) + csum += buf[i]; + + return csum; +} + +/* + * Verify the integrity of a CYAPA firmware image file. + * + * The firmware image file is 30848 bytes, composed of 482 64-byte blocks. + * + * The first 2 blocks are the firmware header. + * The next 480 blocks are the firmware image. + * + * The first two bytes of the header hold the header checksum, computed by + * summing the other 126 bytes of the header. + * The last two bytes of the header hold the firmware image checksum, computed + * by summing the 30720 bytes of the image modulo 0xffff. + * + * Both checksums are stored little-endian. + */ +static int cyapa_gen3_check_fw(struct cyapa *cyapa, const struct firmware *fw) +{ + struct device *dev = &cyapa->client->dev; + u16 csum; + u16 csum_expected; + + /* Firmware must match exact 30848 bytes = 482 64-byte blocks. */ + if (fw->size != CYAPA_FW_SIZE) { + dev_err(dev, "invalid firmware size = %zu, expected %u.\n", + fw->size, CYAPA_FW_SIZE); + return -EINVAL; + } + + /* Verify header block */ + csum_expected = (fw->data[0] << 8) | fw->data[1]; + csum = cyapa_gen3_csum(&fw->data[2], CYAPA_FW_HDR_SIZE - 2); + if (csum != csum_expected) { + dev_err(dev, "%s %04x, expected: %04x\n", + "invalid firmware header checksum = ", + csum, csum_expected); + return -EINVAL; + } + + /* Verify firmware image */ + csum_expected = (fw->data[CYAPA_FW_HDR_SIZE - 2] << 8) | + fw->data[CYAPA_FW_HDR_SIZE - 1]; + csum = cyapa_gen3_csum(&fw->data[CYAPA_FW_HDR_SIZE], + CYAPA_FW_DATA_SIZE); + if (csum != csum_expected) { + dev_err(dev, "%s %04x, expected: %04x\n", + "invalid firmware header checksum = ", + csum, csum_expected); + return -EINVAL; + } + return 0; +} + +/* + * Write a |len| byte long buffer |buf| to the device, by chopping it up into a + * sequence of smaller |CYAPA_CMD_LEN|-length write commands. + * + * The data bytes for a write command are prepended with the 1-byte offset + * of the data relative to the start of |buf|. + */ +static int cyapa_gen3_write_buffer(struct cyapa *cyapa, + const u8 *buf, size_t len) +{ + int error; + size_t i; + unsigned char cmd[CYAPA_CMD_LEN + 1]; + size_t cmd_len; + + for (i = 0; i < len; i += CYAPA_CMD_LEN) { + const u8 *payload = &buf[i]; + + cmd_len = (len - i >= CYAPA_CMD_LEN) ? CYAPA_CMD_LEN : len - i; + cmd[0] = i; + memcpy(&cmd[1], payload, cmd_len); + + error = cyapa_i2c_reg_write_block(cyapa, 0, cmd_len + 1, cmd); + if (error) + return error; + } + return 0; +} + +/* + * A firmware block write command writes 64 bytes of data to a single flash + * page in the device. The 78-byte block write command has the format: + * <0xff> + * + * <0xff> - every command starts with 0xff + * - the write command value is 0x39 + * - write commands include an 8-byte key: { 00 01 02 03 04 05 06 07 } + * - Memory Block number (address / 64) (16-bit, big-endian) + * - 64 bytes of firmware image data + * - sum of 64 bytes, modulo 0xff + * - sum of 77 bytes, from 0xff to + * + * Each write command is split into 5 i2c write transactions of up to 16 bytes. + * Each transaction starts with an i2c register offset: (00, 10, 20, 30, 40). + */ +static int cyapa_gen3_write_fw_block(struct cyapa *cyapa, + u16 block, const u8 *data) +{ + int ret; + struct gen3_write_block_cmd write_block_cmd; + u8 status[BL_STATUS_SIZE]; + int tries; + u8 bl_status, bl_error; + + /* Set write command and security key bytes. */ + write_block_cmd.checksum_seed = GEN3_BL_CMD_CHECKSUM_SEED; + write_block_cmd.cmd_code = GEN3_BL_CMD_WRITE_BLOCK; + memcpy(write_block_cmd.key, security_key, sizeof(security_key)); + put_unaligned_be16(block, &write_block_cmd.block_num); + memcpy(write_block_cmd.block_data, data, CYAPA_FW_BLOCK_SIZE); + write_block_cmd.block_checksum = cyapa_gen3_csum( + write_block_cmd.block_data, CYAPA_FW_BLOCK_SIZE); + write_block_cmd.cmd_checksum = cyapa_gen3_csum((u8 *)&write_block_cmd, + sizeof(write_block_cmd) - 1); + + ret = cyapa_gen3_write_buffer(cyapa, (u8 *)&write_block_cmd, + sizeof(write_block_cmd)); + if (ret) + return ret; + + /* Wait for write to finish */ + tries = 11; /* Programming for one block can take about 100ms. */ + do { + usleep_range(10000, 20000); + + /* Check block write command result status. */ + ret = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, + BL_STATUS_SIZE, status); + if (ret != BL_STATUS_SIZE) + return (ret < 0) ? ret : -EIO; + } while ((status[REG_BL_STATUS] & BL_STATUS_BUSY) && --tries); + + /* Ignore WATCHDOG bit and reserved bits. */ + bl_status = status[REG_BL_STATUS] & ~BL_STATUS_REV_MASK; + bl_error = status[REG_BL_ERROR] & ~BL_ERROR_RESERVED; + + if (bl_status & BL_STATUS_BUSY) + ret = -ETIMEDOUT; + else if (bl_status != BL_STATUS_RUNNING || + bl_error != BL_ERROR_BOOTLOADING) + ret = -EIO; + else + ret = 0; + + return ret; +} + +static int cyapa_gen3_write_blocks(struct cyapa *cyapa, + size_t start_block, size_t block_count, + const u8 *image_data) +{ + int error; + int i; + + for (i = 0; i < block_count; i++) { + size_t block = start_block + i; + size_t addr = i * CYAPA_FW_BLOCK_SIZE; + const u8 *data = &image_data[addr]; + + error = cyapa_gen3_write_fw_block(cyapa, block, data); + if (error) + return error; + } + return 0; +} + +static int cyapa_gen3_do_fw_update(struct cyapa *cyapa, + const struct firmware *fw) +{ + struct device *dev = &cyapa->client->dev; + int error; + + /* First write data, starting at byte 128 of fw->data */ + error = cyapa_gen3_write_blocks(cyapa, + CYAPA_FW_DATA_BLOCK_START, CYAPA_FW_DATA_BLOCK_COUNT, + &fw->data[CYAPA_FW_HDR_BLOCK_COUNT * CYAPA_FW_BLOCK_SIZE]); + if (error) { + dev_err(dev, "FW update aborted, write image: %d\n", error); + return error; + } + + /* Then write checksum */ + error = cyapa_gen3_write_blocks(cyapa, + CYAPA_FW_HDR_BLOCK_START, CYAPA_FW_HDR_BLOCK_COUNT, + &fw->data[0]); + if (error) { + dev_err(dev, "FW update aborted, write checksum: %d\n", error); + return error; + } + + return 0; +} + +static ssize_t cyapa_gen3_do_calibrate(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + int tries; + int ret; + + ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS); + if (ret < 0) { + dev_err(dev, "Error reading dev status: %d\n", ret); + goto out; + } + if ((ret & CYAPA_DEV_NORMAL) != CYAPA_DEV_NORMAL) { + dev_warn(dev, "Trackpad device is busy, device state: 0x%02x\n", + ret); + ret = -EAGAIN; + goto out; + } + + ret = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET, + OP_RECALIBRATION_MASK); + if (ret < 0) { + dev_err(dev, "Failed to send calibrate command: %d\n", + ret); + goto out; + } + + tries = 20; /* max recalibration timeout 2s. */ + do { + /* + * For this recalibration, the max time will not exceed 2s. + * The average time is approximately 500 - 700 ms, and we + * will check the status every 100 - 200ms. + */ + usleep_range(100000, 200000); + + ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS); + if (ret < 0) { + dev_err(dev, "Error reading dev status: %d\n", + ret); + goto out; + } + if ((ret & CYAPA_DEV_NORMAL) == CYAPA_DEV_NORMAL) + break; + } while (--tries); + + if (tries == 0) { + dev_err(dev, "Failed to calibrate. Timeout.\n"); + ret = -ETIMEDOUT; + goto out; + } + dev_dbg(dev, "Calibration successful.\n"); + +out: + return ret < 0 ? ret : count; +} + +static ssize_t cyapa_gen3_show_baseline(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + int max_baseline, min_baseline; + int tries; + int ret; + + ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS); + if (ret < 0) { + dev_err(dev, "Error reading dev status. err = %d\n", ret); + goto out; + } + if ((ret & CYAPA_DEV_NORMAL) != CYAPA_DEV_NORMAL) { + dev_warn(dev, "Trackpad device is busy. device state = 0x%x\n", + ret); + ret = -EAGAIN; + goto out; + } + + ret = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET, + OP_REPORT_BASELINE_MASK); + if (ret < 0) { + dev_err(dev, "Failed to send report baseline command. %d\n", + ret); + goto out; + } + + tries = 3; /* Try for 30 to 60 ms */ + do { + usleep_range(10000, 20000); + + ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS); + if (ret < 0) { + dev_err(dev, "Error reading dev status. err = %d\n", + ret); + goto out; + } + if ((ret & CYAPA_DEV_NORMAL) == CYAPA_DEV_NORMAL) + break; + } while (--tries); + + if (tries == 0) { + dev_err(dev, "Device timed out going to Normal state.\n"); + ret = -ETIMEDOUT; + goto out; + } + + ret = cyapa_read_byte(cyapa, CYAPA_CMD_MAX_BASELINE); + if (ret < 0) { + dev_err(dev, "Failed to read max baseline. err = %d\n", ret); + goto out; + } + max_baseline = ret; + + ret = cyapa_read_byte(cyapa, CYAPA_CMD_MIN_BASELINE); + if (ret < 0) { + dev_err(dev, "Failed to read min baseline. err = %d\n", ret); + goto out; + } + min_baseline = ret; + + dev_dbg(dev, "Baseline report successful. Max: %d Min: %d\n", + max_baseline, min_baseline); + ret = scnprintf(buf, PAGE_SIZE, "%d %d\n", max_baseline, min_baseline); + +out: + return ret; +} + +/* + * cyapa_get_wait_time_for_pwr_cmd + * + * Compute the amount of time we need to wait after updating the touchpad + * power mode. The touchpad needs to consume the incoming power mode set + * command at the current clock rate. + */ + +static u16 cyapa_get_wait_time_for_pwr_cmd(u8 pwr_mode) +{ + switch (pwr_mode) { + case PWR_MODE_FULL_ACTIVE: return 20; + case PWR_MODE_BTN_ONLY: return 20; + case PWR_MODE_OFF: return 20; + default: return cyapa_pwr_cmd_to_sleep_time(pwr_mode) + 50; + } +} + +/* + * Set device power mode + * + * Write to the field to configure power state. Power states include : + * Full : Max scans and report rate. + * Idle : Report rate set by user specified time. + * ButtonOnly : No scans for fingers. When the button is triggered, + * a slave interrupt is asserted to notify host to wake up. + * Off : Only awake for i2c commands from host. No function for button + * or touch sensors. + * + * The power_mode command should conform to the following : + * Full : 0x3f + * Idle : Configurable from 20 to 1000ms. See note below for + * cyapa_sleep_time_to_pwr_cmd and cyapa_pwr_cmd_to_sleep_time + * ButtonOnly : 0x01 + * Off : 0x00 + * + * Device power mode can only be set when device is in operational mode. + */ +static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode, + u16 always_unused) +{ + int ret; + u8 power; + int tries; + u16 sleep_time; + + always_unused = 0; + if (cyapa->state != CYAPA_STATE_OP) + return 0; + + tries = SET_POWER_MODE_TRIES; + while (tries--) { + ret = cyapa_read_byte(cyapa, CYAPA_CMD_POWER_MODE); + if (ret >= 0) + break; + usleep_range(SET_POWER_MODE_DELAY, 2 * SET_POWER_MODE_DELAY); + } + if (ret < 0) + return ret; + + /* + * Return early if the power mode to set is the same as the current + * one. + */ + if ((ret & PWR_MODE_MASK) == power_mode) + return 0; + + sleep_time = cyapa_get_wait_time_for_pwr_cmd(ret & PWR_MODE_MASK); + power = ret; + power &= ~PWR_MODE_MASK; + power |= power_mode & PWR_MODE_MASK; + tries = SET_POWER_MODE_TRIES; + while (tries--) { + ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power); + if (!ret) + break; + usleep_range(SET_POWER_MODE_DELAY, 2 * SET_POWER_MODE_DELAY); + } + + /* + * Wait for the newly set power command to go in at the previous + * clock speed (scanrate) used by the touchpad firmware. Not + * doing so before issuing the next command may result in errors + * depending on the command's content. + */ + msleep(sleep_time); + return ret; +} + +static int cyapa_gen3_get_query_data(struct cyapa *cyapa) +{ + u8 query_data[QUERY_DATA_SIZE]; + int ret; + + if (cyapa->state != CYAPA_STATE_OP) + return -EBUSY; + + ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_QUERY, query_data); + if (ret != QUERY_DATA_SIZE) + return (ret < 0) ? ret : -EIO; + + memcpy(&cyapa->product_id[0], &query_data[0], 5); + cyapa->product_id[5] = '-'; + memcpy(&cyapa->product_id[6], &query_data[5], 6); + cyapa->product_id[12] = '-'; + memcpy(&cyapa->product_id[13], &query_data[11], 2); + cyapa->product_id[15] = '\0'; + + cyapa->fw_maj_ver = query_data[15]; + cyapa->fw_min_ver = query_data[16]; + + cyapa->btn_capability = query_data[19] & CAPABILITY_BTN_MASK; + + cyapa->gen = query_data[20] & 0x0f; + + cyapa->max_abs_x = ((query_data[21] & 0xf0) << 4) | query_data[22]; + cyapa->max_abs_y = ((query_data[21] & 0x0f) << 8) | query_data[23]; + + cyapa->physical_size_x = + ((query_data[24] & 0xf0) << 4) | query_data[25]; + cyapa->physical_size_y = + ((query_data[24] & 0x0f) << 8) | query_data[26]; + + cyapa->max_z = 255; + + return 0; +} + +static int cyapa_gen3_bl_query_data(struct cyapa *cyapa) +{ + u8 bl_data[CYAPA_CMD_LEN]; + int ret; + + ret = cyapa_i2c_reg_read_block(cyapa, 0, CYAPA_CMD_LEN, bl_data); + if (ret != CYAPA_CMD_LEN) + return (ret < 0) ? ret : -EIO; + + /* + * This value will be updated again when entered application mode. + * If TP failed to enter application mode, this fw version values + * can be used as a reference. + * This firmware version valid when fw image checksum is valid. + */ + if (bl_data[REG_BL_STATUS] == + (BL_STATUS_RUNNING | BL_STATUS_CSUM_VALID)) { + cyapa->fw_maj_ver = bl_data[GEN3_BL_IDLE_FW_MAJ_VER_OFFSET]; + cyapa->fw_min_ver = bl_data[GEN3_BL_IDLE_FW_MIN_VER_OFFSET]; + } + + return 0; +} + +/* + * Check if device is operational. + * + * An operational device is responding, has exited bootloader, and has + * firmware supported by this driver. + * + * Returns: + * -EBUSY no device or in bootloader + * -EIO failure while reading from device + * -EAGAIN device is still in bootloader + * if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware + * -EINVAL device is in operational mode, but not supported by this driver + * 0 device is supported + */ +static int cyapa_gen3_do_operational_check(struct cyapa *cyapa) +{ + struct device *dev = &cyapa->client->dev; + int error; + + switch (cyapa->state) { + case CYAPA_STATE_BL_ACTIVE: + error = cyapa_gen3_bl_deactivate(cyapa); + if (error) { + dev_err(dev, "failed to bl_deactivate: %d\n", error); + return error; + } + + /* Fallthrough state */ + case CYAPA_STATE_BL_IDLE: + /* Try to get firmware version in bootloader mode. */ + cyapa_gen3_bl_query_data(cyapa); + + error = cyapa_gen3_bl_exit(cyapa); + if (error) { + dev_err(dev, "failed to bl_exit: %d\n", error); + return error; + } + + /* Fallthrough state */ + case CYAPA_STATE_OP: + /* + * Reading query data before going back to the full mode + * may cause problems, so we set the power mode first here. + */ + error = cyapa_gen3_set_power_mode(cyapa, + PWR_MODE_FULL_ACTIVE, 0); + if (error) + dev_err(dev, "%s: set full power mode failed: %d\n", + __func__, error); + error = cyapa_gen3_get_query_data(cyapa); + if (error < 0) + return error; + + /* Only support firmware protocol gen3 */ + if (cyapa->gen != CYAPA_GEN3) { + dev_err(dev, "unsupported protocol version (%d)", + cyapa->gen); + return -EINVAL; + } + + /* Only support product ID starting with CYTRA */ + if (memcmp(cyapa->product_id, product_id, + strlen(product_id)) != 0) { + dev_err(dev, "unsupported product ID (%s)\n", + cyapa->product_id); + return -EINVAL; + } + + return 0; + + default: + return -EIO; + } + return 0; +} + +/* + * Return false, do not continue process + * Return true, continue process. + */ +static bool cyapa_gen3_irq_cmd_handler(struct cyapa *cyapa) +{ + /* Not gen3 irq command response, skip for continue. */ + if (cyapa->gen != CYAPA_GEN3) + return true; + + if (cyapa->operational) + return true; + + /* + * Driver in detecting or other interface function processing, + * so, stop cyapa_gen3_irq_handler to continue process to + * avoid unwanted to error detecting and processing. + * + * And also, avoid the periodicly accerted interrupts to be processed + * as touch inputs when gen3 failed to launch into application mode, + * which will cause gen3 stays in bootloader mode. + */ + return false; +} + +static int cyapa_gen3_irq_handler(struct cyapa *cyapa) +{ + struct input_dev *input = cyapa->input; + struct device *dev = &cyapa->client->dev; + struct cyapa_reg_data data; + int num_fingers; + int ret; + int i; + + ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data); + if (ret != sizeof(data)) { + dev_err(dev, "failed to read report data, (%d)\n", ret); + return -EINVAL; + } + + if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC || + (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL || + (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) { + dev_err(dev, "invalid device state bytes, %02x %02x\n", + data.device_status, data.finger_btn); + return -EINVAL; + } + + num_fingers = (data.finger_btn >> 4) & 0x0f; + for (i = 0; i < num_fingers; i++) { + const struct cyapa_touch *touch = &data.touches[i]; + /* Note: touch->id range is 1 to 15; slots are 0 to 14. */ + int slot = touch->id - 1; + + input_mt_slot(input, slot); + input_mt_report_slot_state(input, MT_TOOL_FINGER, true); + input_report_abs(input, ABS_MT_POSITION_X, + ((touch->xy_hi & 0xf0) << 4) | touch->x_lo); + input_report_abs(input, ABS_MT_POSITION_Y, + ((touch->xy_hi & 0x0f) << 8) | touch->y_lo); + input_report_abs(input, ABS_MT_PRESSURE, touch->pressure); + } + + input_mt_sync_frame(input); + + if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) + input_report_key(input, BTN_LEFT, + !!(data.finger_btn & OP_DATA_LEFT_BTN)); + if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) + input_report_key(input, BTN_MIDDLE, + !!(data.finger_btn & OP_DATA_MIDDLE_BTN)); + if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) + input_report_key(input, BTN_RIGHT, + !!(data.finger_btn & OP_DATA_RIGHT_BTN)); + input_sync(input); + + return 0; +} + +static int cyapa_gen3_initialize(struct cyapa *cyapa) { return 0; } +static int cyapa_gen3_bl_initiate(struct cyapa *cyapa, + const struct firmware *fw) { return 0; } +static int cyapa_gen3_empty_output_data(struct cyapa *cyapa, + u8 *buf, int *len, cb_sort func) { return 0; } + +const struct cyapa_dev_ops cyapa_gen3_ops = { + .check_fw = cyapa_gen3_check_fw, + .bl_enter = cyapa_gen3_bl_enter, + .bl_activate = cyapa_gen3_bl_activate, + .update_fw = cyapa_gen3_do_fw_update, + .bl_deactivate = cyapa_gen3_bl_deactivate, + .bl_initiate = cyapa_gen3_bl_initiate, + + .show_baseline = cyapa_gen3_show_baseline, + .calibrate_store = cyapa_gen3_do_calibrate, + + .initialize = cyapa_gen3_initialize, + + .state_parse = cyapa_gen3_state_parse, + .operational_check = cyapa_gen3_do_operational_check, + + .irq_handler = cyapa_gen3_irq_handler, + .irq_cmd_handler = cyapa_gen3_irq_cmd_handler, + .sort_empty_output_data = cyapa_gen3_empty_output_data, + .set_power_mode = cyapa_gen3_set_power_mode, +}; diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c new file mode 100644 index 000000000000..ddf5393a1180 --- /dev/null +++ b/drivers/input/mouse/cyapa_gen5.c @@ -0,0 +1,2777 @@ +/* + * Cypress APA trackpad with I2C interface + * + * Author: Dudley Du + * + * Copyright (C) 2014 Cypress 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 for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cyapa.h" + + +/* Macro of Gen5 */ +#define RECORD_EVENT_NONE 0 +#define RECORD_EVENT_TOUCHDOWN 1 +#define RECORD_EVENT_DISPLACE 2 +#define RECORD_EVENT_LIFTOFF 3 + +#define CYAPA_TSG_FLASH_MAP_BLOCK_SIZE 0x80 +#define CYAPA_TSG_IMG_FW_HDR_SIZE 13 +#define CYAPA_TSG_FW_ROW_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE) +#define CYAPA_TSG_IMG_START_ROW_NUM 0x002e +#define CYAPA_TSG_IMG_END_ROW_NUM 0x01fe +#define CYAPA_TSG_IMG_APP_INTEGRITY_ROW_NUM 0x01ff +#define CYAPA_TSG_IMG_MAX_RECORDS (CYAPA_TSG_IMG_END_ROW_NUM - \ + CYAPA_TSG_IMG_START_ROW_NUM + 1 + 1) +#define CYAPA_TSG_IMG_READ_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE / 2) +#define CYAPA_TSG_START_OF_APPLICATION 0x1700 +#define CYAPA_TSG_APP_INTEGRITY_SIZE 60 +#define CYAPA_TSG_FLASH_MAP_METADATA_SIZE 60 +#define CYAPA_TSG_BL_KEY_SIZE 8 + +#define CYAPA_TSG_MAX_CMD_SIZE 256 + +#define GEN5_BL_CMD_VERIFY_APP_INTEGRITY 0x31 +#define GEN5_BL_CMD_GET_BL_INFO 0x38 +#define GEN5_BL_CMD_PROGRAM_VERIFY_ROW 0x39 +#define GEN5_BL_CMD_LAUNCH_APP 0x3b +#define GEN5_BL_CMD_INITIATE_BL 0x48 + +#define GEN5_HID_DESCRIPTOR_ADDR 0x0001 +#define GEN5_REPORT_DESCRIPTOR_ADDR 0x0002 +#define GEN5_INPUT_REPORT_ADDR 0x0003 +#define GEN5_OUTPUT_REPORT_ADDR 0x0004 +#define GEN5_CMD_DATA_ADDR 0x0006 + +#define GEN5_TOUCH_REPORT_HEAD_SIZE 7 +#define GEN5_TOUCH_REPORT_MAX_SIZE 127 +#define GEN5_BTN_REPORT_HEAD_SIZE 6 +#define GEN5_BTN_REPORT_MAX_SIZE 14 +#define GEN5_WAKEUP_EVENT_SIZE 4 +#define GEN5_RAW_DATA_HEAD_SIZE 24 + +#define GEN5_BL_CMD_REPORT_ID 0x40 +#define GEN5_BL_RESP_REPORT_ID 0x30 +#define GEN5_APP_CMD_REPORT_ID 0x2f +#define GEN5_APP_RESP_REPORT_ID 0x1f + +#define GEN5_APP_DEEP_SLEEP_REPORT_ID 0xf0 +#define GEN5_DEEP_SLEEP_RESP_LENGTH 5 + +#define GEN5_CMD_GET_PARAMETER 0x05 +#define GEN5_CMD_SET_PARAMETER 0x06 +#define GEN5_PARAMETER_ACT_INTERVL_ID 0x4d +#define GEN5_PARAMETER_ACT_INTERVL_SIZE 1 +#define GEN5_PARAMETER_ACT_LFT_INTERVL_ID 0x4f +#define GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE 2 +#define GEN5_PARAMETER_LP_INTRVL_ID 0x4c +#define GEN5_PARAMETER_LP_INTRVL_SIZE 2 + +#define GEN5_PARAMETER_DISABLE_PIP_REPORT 0x08 + +#define GEN5_POWER_STATE_ACTIVE 0x01 +#define GEN5_POWER_STATE_LOOK_FOR_TOUCH 0x02 +#define GEN5_POWER_STATE_READY 0x03 +#define GEN5_POWER_STATE_IDLE 0x04 +#define GEN5_POWER_STATE_BTN_ONLY 0x05 +#define GEN5_POWER_STATE_OFF 0x06 + +#define GEN5_DEEP_SLEEP_STATE_MASK 0x03 +#define GEN5_DEEP_SLEEP_STATE_ON 0x00 +#define GEN5_DEEP_SLEEP_STATE_OFF 0x01 + +#define GEN5_DEEP_SLEEP_OPCODE 0x08 +#define GEN5_DEEP_SLEEP_OPCODE_MASK 0x0f + +#define GEN5_POWER_READY_MAX_INTRVL_TIME 50 /* Unit: ms */ +#define GEN5_POWER_IDLE_MAX_INTRVL_TIME 250 /* Unit: ms */ + +#define GEN5_CMD_REPORT_ID_OFFSET 4 + +#define GEN5_RESP_REPORT_ID_OFFSET 2 +#define GEN5_RESP_RSVD_OFFSET 3 +#define GEN5_RESP_RSVD_KEY 0x00 +#define GEN5_RESP_BL_SOP_OFFSET 4 +#define GEN5_SOP_KEY 0x01 /* Start of Packet */ +#define GEN5_EOP_KEY 0x17 /* End of Packet */ +#define GEN5_RESP_APP_CMD_OFFSET 4 +#define GET_GEN5_CMD_CODE(reg) ((reg) & 0x7f) + +#define VALID_CMD_RESP_HEADER(resp, cmd) \ + (((resp)[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID) && \ + ((resp)[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) && \ + (GET_GEN5_CMD_CODE((resp)[GEN5_RESP_APP_CMD_OFFSET]) == (cmd))) + +#define GEN5_MIN_BL_CMD_LENGTH 13 +#define GEN5_MIN_BL_RESP_LENGTH 11 +#define GEN5_MIN_APP_CMD_LENGTH 7 +#define GEN5_MIN_APP_RESP_LENGTH 5 +#define GEN5_UNSUPPORTED_CMD_RESP_LENGTH 6 + +#define GEN5_RESP_LENGTH_OFFSET 0x00 +#define GEN5_RESP_LENGTH_SIZE 2 + +#define GEN5_HID_DESCRIPTOR_SIZE 32 +#define GEN5_BL_HID_REPORT_ID 0xff +#define GEN5_APP_HID_REPORT_ID 0xf7 +#define GEN5_BL_MAX_OUTPUT_LENGTH 0x0100 +#define GEN5_APP_MAX_OUTPUT_LENGTH 0x00fe + +#define GEN5_BL_REPORT_DESCRIPTOR_SIZE 0x1d +#define GEN5_BL_REPORT_DESCRIPTOR_ID 0xfe +#define GEN5_APP_REPORT_DESCRIPTOR_SIZE 0xee +#define GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE 0xfa +#define GEN5_APP_REPORT_DESCRIPTOR_ID 0xf6 + +#define GEN5_TOUCH_REPORT_ID 0x01 +#define GEN5_BTN_REPORT_ID 0x03 +#define GEN5_WAKEUP_EVENT_REPORT_ID 0x04 +#define GEN5_OLD_PUSH_BTN_REPORT_ID 0x05 +#define GEN5_PUSH_BTN_REPORT_ID 0x06 + +#define GEN5_CMD_COMPLETE_SUCCESS(status) ((status) == 0x00) + +#define GEN5_BL_INITIATE_RESP_LEN 11 +#define GEN5_BL_FAIL_EXIT_RESP_LEN 11 +#define GEN5_BL_FAIL_EXIT_STATUS_CODE 0x0c +#define GEN5_BL_VERIFY_INTEGRITY_RESP_LEN 12 +#define GEN5_BL_INTEGRITY_CHEKC_PASS 0x00 +#define GEN5_BL_BLOCK_WRITE_RESP_LEN 11 +#define GEN5_BL_READ_APP_INFO_RESP_LEN 31 +#define GEN5_CMD_CALIBRATE 0x28 +#define CYAPA_SENSING_MODE_MUTUAL_CAP_FINE 0x00 +#define CYAPA_SENSING_MODE_SELF_CAP 0x02 + +#define GEN5_CMD_RETRIEVE_DATA_STRUCTURE 0x24 +#define GEN5_RETRIEVE_MUTUAL_PWC_DATA 0x00 +#define GEN5_RETRIEVE_SELF_CAP_PWC_DATA 0x01 + +#define GEN5_RETRIEVE_DATA_ELEMENT_SIZE_MASK 0x07 + +#define GEN5_CMD_EXECUTE_PANEL_SCAN 0x2a +#define GEN5_CMD_RETRIEVE_PANEL_SCAN 0x2b +#define GEN5_PANEL_SCAN_MUTUAL_RAW_DATA 0x00 +#define GEN5_PANEL_SCAN_MUTUAL_BASELINE 0x01 +#define GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT 0x02 +#define GEN5_PANEL_SCAN_SELF_RAW_DATA 0x03 +#define GEN5_PANEL_SCAN_SELF_BASELINE 0x04 +#define GEN5_PANEL_SCAN_SELF_DIFFCOUNT 0x05 + +/* The offset only valid for reterive PWC and panel scan commands */ +#define GEN5_RESP_DATA_STRUCTURE_OFFSET 10 +#define GEN5_PWC_DATA_ELEMENT_SIZE_MASK 0x07 + +#define GEN5_NUMBER_OF_TOUCH_OFFSET 5 +#define GEN5_NUMBER_OF_TOUCH_MASK 0x1f +#define GEN5_BUTTONS_OFFSET 5 +#define GEN5_BUTTONS_MASK 0x0f +#define GEN5_GET_EVENT_ID(reg) (((reg) >> 5) & 0x03) +#define GEN5_GET_TOUCH_ID(reg) ((reg) & 0x1f) + +#define GEN5_PRODUCT_FAMILY_MASK 0xf000 +#define GEN5_PRODUCT_FAMILY_TRACKPAD 0x1000 + +#define TSG_INVALID_CMD 0xff + +struct cyapa_gen5_touch_record { + /* + * Bit 7 - 3: reserved + * Bit 2 - 0: touch type; + * 0 : standard finger; + * 1 - 15 : reserved. + */ + u8 touch_type; + + /* + * Bit 7: indicates touch liftoff status. + * 0 : touch is currently on the panel. + * 1 : touch record indicates a liftoff. + * Bit 6 - 5: indicates an event associated with this touch instance + * 0 : no event + * 1 : touchdown + * 2 : significant displacement (> active distance) + * 3 : liftoff (record reports last known coordinates) + * Bit 4 - 0: An arbitrary ID tag associated with a finger + * to allow tracking a touch as it moves around the panel. + */ + u8 touch_tip_event_id; + + /* Bit 7 - 0 of X-axis coordinate of the touch in pixel. */ + u8 x_lo; + + /* Bit 15 - 8 of X-axis coordinate of the touch in pixel. */ + u8 x_hi; + + /* Bit 7 - 0 of Y-axis coordinate of the touch in pixel. */ + u8 y_lo; + + /* Bit 15 - 8 of Y-axis coordinate of the touch in pixel. */ + u8 y_hi; + + /* Touch intensity in counts, pressure value. */ + u8 z; + + /* + * The length of the major axis of the ellipse of contact between + * the finger and the panel (ABS_MT_TOUCH_MAJOR). + */ + u8 major_axis_len; + + /* + * The length of the minor axis of the ellipse of contact between + * the finger and the panel (ABS_MT_TOUCH_MINOR). + */ + u8 minor_axis_len; + + /* + * The length of the major axis of the approaching tool. + * (ABS_MT_WIDTH_MAJOR) + */ + u8 major_tool_len; + + /* + * The length of the minor axis of the approaching tool. + * (ABS_MT_WIDTH_MINOR) + */ + u8 minor_tool_len; + + /* + * The angle between the panel vertical axis and + * the major axis of the contact ellipse. This value is an 8-bit + * signed integer. The range is -127 to +127 (corresponding to + * -90 degree and +90 degree respectively). + * The positive direction is clockwise from the vertical axis. + * If the ellipse of contact degenerates into a circle, + * orientation is reported as 0. + */ + u8 orientation; +} __packed; + +struct cyapa_gen5_report_data { + u8 report_head[GEN5_TOUCH_REPORT_HEAD_SIZE]; + struct cyapa_gen5_touch_record touch_records[10]; +} __packed; + +struct cyapa_tsg_bin_image_head { + u8 head_size; /* Unit: bytes, including itself. */ + u8 ttda_driver_major_version; /* Reserved as 0. */ + u8 ttda_driver_minor_version; /* Reserved as 0. */ + u8 fw_major_version; + u8 fw_minor_version; + u8 fw_revision_control_number[8]; +} __packed; + +struct cyapa_tsg_bin_image_data_record { + u8 flash_array_id; + __be16 row_number; + /* The number of bytes of flash data contained in this record. */ + __be16 record_len; + /* The flash program data. */ + u8 record_data[CYAPA_TSG_FW_ROW_SIZE]; +} __packed; + +struct cyapa_tsg_bin_image { + struct cyapa_tsg_bin_image_head image_head; + struct cyapa_tsg_bin_image_data_record records[0]; +} __packed; + +struct gen5_bl_packet_start { + u8 sop; /* Start of packet, must be 01h */ + u8 cmd_code; + __le16 data_length; /* Size of data parameter start from data[0] */ +} __packed; + +struct gen5_bl_packet_end { + __le16 crc; + u8 eop; /* End of packet, must be 17h */ +} __packed; + +struct gen5_bl_cmd_head { + __le16 addr; /* Output report register address, must be 0004h */ + /* Size of packet not including output report register address */ + __le16 length; + u8 report_id; /* Bootloader output report id, must be 40h */ + u8 rsvd; /* Reserved, must be 0 */ + struct gen5_bl_packet_start packet_start; + u8 data[0]; /* Command data variable based on commands */ +} __packed; + +/* Initiate bootload command data structure. */ +struct gen5_bl_initiate_cmd_data { + /* Key must be "A5h 01h 02h 03h FFh FEh FDh 5Ah" */ + u8 key[CYAPA_TSG_BL_KEY_SIZE]; + u8 metadata_raw_parameter[CYAPA_TSG_FLASH_MAP_METADATA_SIZE]; + __le16 metadata_crc; +} __packed; + +struct gen5_bl_metadata_row_params { + __le16 size; + __le16 maximum_size; + __le32 app_start; + __le16 app_len; + __le16 app_crc; + __le32 app_entry; + __le32 upgrade_start; + __le16 upgrade_len; + __le16 entry_row_crc; + u8 padding[36]; /* Padding data must be 0 */ + __le16 metadata_crc; /* CRC starts at offset of 60 */ +} __packed; + +/* Bootload program and verify row command data structure */ +struct gen5_bl_flash_row_head { + u8 flash_array_id; + __le16 flash_row_id; + u8 flash_data[0]; +} __packed; + +struct gen5_app_cmd_head { + __le16 addr; /* Output report register address, must be 0004h */ + /* Size of packet not including output report register address */ + __le16 length; + u8 report_id; /* Application output report id, must be 2Fh */ + u8 rsvd; /* Reserved, must be 0 */ + /* + * Bit 7: reserved, must be 0. + * Bit 6-0: command code. + */ + u8 cmd_code; + u8 parameter_data[0]; /* Parameter data variable based on cmd_code */ +} __packed; + +/* Applicaton get/set parameter command data structure */ +struct gen5_app_set_parameter_data { + u8 parameter_id; + u8 parameter_size; + __le32 value; +} __packed; + +struct gen5_app_get_parameter_data { + u8 parameter_id; +} __packed; + +struct gen5_retrieve_panel_scan_data { + __le16 read_offset; + __le16 read_elements; + u8 data_id; +} __packed; + +/* Variables to record latest gen5 trackpad power states. */ +#define GEN5_DEV_SET_PWR_STATE(cyapa, s) ((cyapa)->dev_pwr_mode = (s)) +#define GEN5_DEV_GET_PWR_STATE(cyapa) ((cyapa)->dev_pwr_mode) +#define GEN5_DEV_SET_SLEEP_TIME(cyapa, t) ((cyapa)->dev_sleep_time = (t)) +#define GEN5_DEV_GET_SLEEP_TIME(cyapa) ((cyapa)->dev_sleep_time) +#define GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) \ + (((cyapa)->dev_sleep_time) == UNINIT_SLEEP_TIME) + + +static u8 cyapa_gen5_bl_cmd_key[] = { 0xa5, 0x01, 0x02, 0x03, + 0xff, 0xfe, 0xfd, 0x5a }; + +static int cyapa_gen5_initialize(struct cyapa *cyapa) +{ + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + + init_completion(&gen5_pip->cmd_ready); + atomic_set(&gen5_pip->cmd_issued, 0); + mutex_init(&gen5_pip->cmd_lock); + + gen5_pip->resp_sort_func = NULL; + gen5_pip->in_progress_cmd = TSG_INVALID_CMD; + gen5_pip->resp_data = NULL; + gen5_pip->resp_len = NULL; + + cyapa->dev_pwr_mode = UNINIT_PWR_MODE; + cyapa->dev_sleep_time = UNINIT_SLEEP_TIME; + + return 0; +} + +/* Return negative errno, or else the number of bytes read. */ +static ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size) +{ + int ret; + + if (size == 0) + return 0; + + if (!buf || size > CYAPA_REG_MAP_SIZE) + return -EINVAL; + + ret = i2c_master_recv(cyapa->client, buf, size); + + if (ret != size) + return (ret < 0) ? ret : -EIO; + + return size; +} + +/** + * Return a negative errno code else zero on success. + */ +static ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size) +{ + int ret; + + if (!buf || !size) + return -EINVAL; + + ret = i2c_master_send(cyapa->client, buf, size); + + if (ret != size) + return (ret < 0) ? ret : -EIO; + + return 0; +} + +/** + * This function is aimed to dump all not read data in Gen5 trackpad + * before send any command, otherwise, the interrupt line will be blocked. + */ +static int cyapa_empty_pip_output_data(struct cyapa *cyapa, + u8 *buf, int *len, cb_sort func) +{ + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + int length; + int report_count; + int empty_count; + int buf_len; + int error; + + buf_len = 0; + if (len) { + buf_len = (*len < CYAPA_REG_MAP_SIZE) ? + *len : CYAPA_REG_MAP_SIZE; + *len = 0; + } + + report_count = 8; /* max 7 pending data before command response data */ + empty_count = 0; + do { + /* + * Depending on testing in cyapa driver, there are max 5 "02 00" + * packets between two valid buffered data report in firmware. + * So in order to dump all buffered data out and + * make interrupt line release for reassert again, + * we must set the empty_count check value bigger than 5 to + * make it work. Otherwise, in some situation, + * the interrupt line may unable to reactive again, + * which will cause trackpad device unable to + * report data any more. + * for example, it may happen in EFT and ESD testing. + */ + if (empty_count > 5) + return 0; + + error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, + GEN5_RESP_LENGTH_SIZE); + if (error < 0) + return error; + + length = get_unaligned_le16(gen5_pip->empty_buf); + if (length == GEN5_RESP_LENGTH_SIZE) { + empty_count++; + continue; + } else if (length > CYAPA_REG_MAP_SIZE) { + /* Should not happen */ + return -EINVAL; + } else if (length == 0) { + /* Application or bootloader launch data polled out. */ + length = GEN5_RESP_LENGTH_SIZE; + if (buf && buf_len && func && + func(cyapa, gen5_pip->empty_buf, length)) { + length = min(buf_len, length); + memcpy(buf, gen5_pip->empty_buf, length); + *len = length; + /* Response found, success. */ + return 0; + } + continue; + } + + error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length); + if (error < 0) + return error; + + report_count--; + empty_count = 0; + length = get_unaligned_le16(gen5_pip->empty_buf); + if (length <= GEN5_RESP_LENGTH_SIZE) { + empty_count++; + } else if (buf && buf_len && func && + func(cyapa, gen5_pip->empty_buf, length)) { + length = min(buf_len, length); + memcpy(buf, gen5_pip->empty_buf, length); + *len = length; + /* Response found, success. */ + return 0; + } + + error = -EINVAL; + } while (report_count); + + return error; +} + +static int cyapa_do_i2c_pip_cmd_irq_sync( + struct cyapa *cyapa, + u8 *cmd, size_t cmd_len, + unsigned long timeout) +{ + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + int error; + + /* Wait for interrupt to set ready completion */ + init_completion(&gen5_pip->cmd_ready); + + atomic_inc(&gen5_pip->cmd_issued); + error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len); + if (error) { + atomic_dec(&gen5_pip->cmd_issued); + return (error < 0) ? error : -EIO; + } + + /* Wait for interrupt to indicate command is completed. */ + timeout = wait_for_completion_timeout(&gen5_pip->cmd_ready, + msecs_to_jiffies(timeout)); + if (timeout == 0) { + atomic_dec(&gen5_pip->cmd_issued); + return -ETIMEDOUT; + } + + return 0; +} + +static int cyapa_do_i2c_pip_cmd_polling( + struct cyapa *cyapa, + u8 *cmd, size_t cmd_len, + u8 *resp_data, int *resp_len, + unsigned long timeout, + cb_sort func) +{ + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + int tries; + int length; + int error; + + atomic_inc(&gen5_pip->cmd_issued); + error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len); + if (error) { + atomic_dec(&gen5_pip->cmd_issued); + return error < 0 ? error : -EIO; + } + + length = resp_len ? *resp_len : 0; + if (resp_data && resp_len && length != 0 && func) { + tries = timeout / 5; + do { + usleep_range(3000, 5000); + *resp_len = length; + error = cyapa_empty_pip_output_data(cyapa, + resp_data, resp_len, func); + if (error || *resp_len == 0) + continue; + else + break; + } while (--tries > 0); + if ((error || *resp_len == 0) || tries <= 0) + error = error ? error : -ETIMEDOUT; + } + + atomic_dec(&gen5_pip->cmd_issued); + return error; +} + +static int cyapa_i2c_pip_cmd_irq_sync( + struct cyapa *cyapa, + u8 *cmd, int cmd_len, + u8 *resp_data, int *resp_len, + unsigned long timeout, + cb_sort func, + bool irq_mode) +{ + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + int error; + + if (!cmd || !cmd_len) + return -EINVAL; + + /* Commands must be serialized. */ + error = mutex_lock_interruptible(&gen5_pip->cmd_lock); + if (error) + return error; + + gen5_pip->resp_sort_func = func; + gen5_pip->resp_data = resp_data; + gen5_pip->resp_len = resp_len; + + if (cmd_len >= GEN5_MIN_APP_CMD_LENGTH && + cmd[4] == GEN5_APP_CMD_REPORT_ID) { + /* Application command */ + gen5_pip->in_progress_cmd = cmd[6] & 0x7f; + } else if (cmd_len >= GEN5_MIN_BL_CMD_LENGTH && + cmd[4] == GEN5_BL_CMD_REPORT_ID) { + /* Bootloader command */ + gen5_pip->in_progress_cmd = cmd[7]; + } + + /* Send command data, wait and read output response data's length. */ + if (irq_mode) { + gen5_pip->is_irq_mode = true; + error = cyapa_do_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, + timeout); + if (error == -ETIMEDOUT && resp_data && + resp_len && *resp_len != 0 && func) { + /* + * For some old version, there was no interrupt for + * the command response data, so need to poll here + * to try to get the response data. + */ + error = cyapa_empty_pip_output_data(cyapa, + resp_data, resp_len, func); + if (error || *resp_len == 0) + error = error ? error : -ETIMEDOUT; + } + } else { + gen5_pip->is_irq_mode = false; + error = cyapa_do_i2c_pip_cmd_polling(cyapa, cmd, cmd_len, + resp_data, resp_len, timeout, func); + } + + gen5_pip->resp_sort_func = NULL; + gen5_pip->resp_data = NULL; + gen5_pip->resp_len = NULL; + gen5_pip->in_progress_cmd = TSG_INVALID_CMD; + + mutex_unlock(&gen5_pip->cmd_lock); + return error; +} + +static bool cyapa_gen5_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa, + u8 *data, int len) +{ + if (!data || len < GEN5_MIN_BL_RESP_LENGTH) + return false; + + /* Bootloader input report id 30h */ + if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_RESP_REPORT_ID && + data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY && + data[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY) + return true; + + return false; +} + +static bool cyapa_gen5_sort_tsg_pip_app_resp_data(struct cyapa *cyapa, + u8 *data, int len) +{ + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + int resp_len; + + if (!data || len < GEN5_MIN_APP_RESP_LENGTH) + return false; + + if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID && + data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) { + resp_len = get_unaligned_le16(&data[GEN5_RESP_LENGTH_OFFSET]); + if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == 0x00 && + resp_len == GEN5_UNSUPPORTED_CMD_RESP_LENGTH && + data[5] == gen5_pip->in_progress_cmd) { + /* Unsupported command code */ + return false; + } else if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == + gen5_pip->in_progress_cmd) { + /* Correct command response received */ + return true; + } + } + + return false; +} + +static bool cyapa_gen5_sort_application_launch_data(struct cyapa *cyapa, + u8 *buf, int len) +{ + if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE) + return false; + + /* + * After reset or power on, trackpad device always sets to 0x00 0x00 + * to indicate a reset or power on event. + */ + if (buf[0] == 0 && buf[1] == 0) + return true; + + return false; +} + +static bool cyapa_gen5_sort_hid_descriptor_data(struct cyapa *cyapa, + u8 *buf, int len) +{ + int resp_len; + int max_output_len; + + /* Check hid descriptor. */ + if (len != GEN5_HID_DESCRIPTOR_SIZE) + return false; + + resp_len = get_unaligned_le16(&buf[GEN5_RESP_LENGTH_OFFSET]); + max_output_len = get_unaligned_le16(&buf[16]); + if (resp_len == GEN5_HID_DESCRIPTOR_SIZE) { + if (buf[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_HID_REPORT_ID && + max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { + /* BL mode HID Descriptor */ + return true; + } else if ((buf[GEN5_RESP_REPORT_ID_OFFSET] == + GEN5_APP_HID_REPORT_ID) && + max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { + /* APP mode HID Descriptor */ + return true; + } + } + + return false; +} + +static bool cyapa_gen5_sort_deep_sleep_data(struct cyapa *cyapa, + u8 *buf, int len) +{ + if (len == GEN5_DEEP_SLEEP_RESP_LENGTH && + buf[GEN5_RESP_REPORT_ID_OFFSET] == + GEN5_APP_DEEP_SLEEP_REPORT_ID && + (buf[4] & GEN5_DEEP_SLEEP_OPCODE_MASK) == + GEN5_DEEP_SLEEP_OPCODE) + return true; + return false; +} + +static int gen5_idle_state_parse(struct cyapa *cyapa) +{ + u8 resp_data[GEN5_HID_DESCRIPTOR_SIZE]; + int max_output_len; + int length; + u8 cmd[2]; + int ret; + int error; + + /* + * Dump all buffered data firstly for the situation + * when the trackpad is just power on the cyapa go here. + */ + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + + memset(resp_data, 0, sizeof(resp_data)); + ret = cyapa_i2c_pip_read(cyapa, resp_data, 3); + if (ret != 3) + return ret < 0 ? ret : -EIO; + + length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]); + if (length == GEN5_RESP_LENGTH_SIZE) { + /* Normal state of Gen5 with no data to respose */ + cyapa->gen = CYAPA_GEN5; + + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + + /* Read description from trackpad device */ + cmd[0] = 0x01; + cmd[1] = 0x00; + length = GEN5_HID_DESCRIPTOR_SIZE; + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + cmd, GEN5_RESP_LENGTH_SIZE, + resp_data, &length, + 300, + cyapa_gen5_sort_hid_descriptor_data, + false); + if (error) + return error; + + length = get_unaligned_le16( + &resp_data[GEN5_RESP_LENGTH_OFFSET]); + max_output_len = get_unaligned_le16(&resp_data[16]); + if ((length == GEN5_HID_DESCRIPTOR_SIZE || + length == GEN5_RESP_LENGTH_SIZE) && + (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == + GEN5_BL_HID_REPORT_ID) && + max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { + /* BL mode HID Description read */ + cyapa->state = CYAPA_STATE_GEN5_BL; + } else if ((length == GEN5_HID_DESCRIPTOR_SIZE || + length == GEN5_RESP_LENGTH_SIZE) && + (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == + GEN5_APP_HID_REPORT_ID) && + max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { + /* APP mode HID Description read */ + cyapa->state = CYAPA_STATE_GEN5_APP; + } else { + /* Should not happen!!! */ + cyapa->state = CYAPA_STATE_NO_DEVICE; + } + } + + return 0; +} + +static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data) +{ + int length; + u8 resp_data[32]; + int max_output_len; + int ret; + + /* 0x20 0x00 0xF7 is Gen5 Application HID Description Header; + * 0x20 0x00 0xFF is Gen5 Booloader HID Description Header. + * + * Must read HID Description content through out, + * otherwise Gen5 trackpad cannot response next command + * or report any touch or button data. + */ + ret = cyapa_i2c_pip_read(cyapa, resp_data, + GEN5_HID_DESCRIPTOR_SIZE); + if (ret != GEN5_HID_DESCRIPTOR_SIZE) + return ret < 0 ? ret : -EIO; + length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]); + max_output_len = get_unaligned_le16(&resp_data[16]); + if (length == GEN5_RESP_LENGTH_SIZE) { + if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] == + GEN5_BL_HID_REPORT_ID) { + /* + * BL mode HID Description has been previously + * read out. + */ + cyapa->gen = CYAPA_GEN5; + cyapa->state = CYAPA_STATE_GEN5_BL; + } else { + /* + * APP mode HID Description has been previously + * read out. + */ + cyapa->gen = CYAPA_GEN5; + cyapa->state = CYAPA_STATE_GEN5_APP; + } + } else if (length == GEN5_HID_DESCRIPTOR_SIZE && + resp_data[2] == GEN5_BL_HID_REPORT_ID && + max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { + /* BL mode HID Description read. */ + cyapa->gen = CYAPA_GEN5; + cyapa->state = CYAPA_STATE_GEN5_BL; + } else if (length == GEN5_HID_DESCRIPTOR_SIZE && + (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == + GEN5_APP_HID_REPORT_ID) && + max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { + /* APP mode HID Description read. */ + cyapa->gen = CYAPA_GEN5; + cyapa->state = CYAPA_STATE_GEN5_APP; + } else { + /* Should not happen!!! */ + cyapa->state = CYAPA_STATE_NO_DEVICE; + } + + return 0; +} + +static int gen5_report_data_header_parse(struct cyapa *cyapa, u8 *reg_data) +{ + int length; + + length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); + switch (reg_data[GEN5_RESP_REPORT_ID_OFFSET]) { + case GEN5_TOUCH_REPORT_ID: + if (length < GEN5_TOUCH_REPORT_HEAD_SIZE || + length > GEN5_TOUCH_REPORT_MAX_SIZE) + return -EINVAL; + break; + case GEN5_BTN_REPORT_ID: + case GEN5_OLD_PUSH_BTN_REPORT_ID: + case GEN5_PUSH_BTN_REPORT_ID: + if (length < GEN5_BTN_REPORT_HEAD_SIZE || + length > GEN5_BTN_REPORT_MAX_SIZE) + return -EINVAL; + break; + case GEN5_WAKEUP_EVENT_REPORT_ID: + if (length != GEN5_WAKEUP_EVENT_SIZE) + return -EINVAL; + break; + default: + return -EINVAL; + } + + cyapa->gen = CYAPA_GEN5; + cyapa->state = CYAPA_STATE_GEN5_APP; + return 0; +} + +static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data) +{ + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + int length; + int ret; + + /* + * Must read report data through out, + * otherwise Gen5 trackpad cannot response next command + * or report any touch or button data. + */ + length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); + ret = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length); + if (ret != length) + return ret < 0 ? ret : -EIO; + + if (length == GEN5_RESP_LENGTH_SIZE) { + /* Previous command has read the data through out. */ + if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] == + GEN5_BL_RESP_REPORT_ID) { + /* Gen5 BL command response data detected */ + cyapa->gen = CYAPA_GEN5; + cyapa->state = CYAPA_STATE_GEN5_BL; + } else { + /* Gen5 APP command response data detected */ + cyapa->gen = CYAPA_GEN5; + cyapa->state = CYAPA_STATE_GEN5_APP; + } + } else if ((gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] == + GEN5_BL_RESP_REPORT_ID) && + (gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] == + GEN5_RESP_RSVD_KEY) && + (gen5_pip->empty_buf[GEN5_RESP_BL_SOP_OFFSET] == + GEN5_SOP_KEY) && + (gen5_pip->empty_buf[length - 1] == + GEN5_EOP_KEY)) { + /* Gen5 BL command response data detected */ + cyapa->gen = CYAPA_GEN5; + cyapa->state = CYAPA_STATE_GEN5_BL; + } else if (gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] == + GEN5_APP_RESP_REPORT_ID && + gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] == + GEN5_RESP_RSVD_KEY) { + /* Gen5 APP command response data detected */ + cyapa->gen = CYAPA_GEN5; + cyapa->state = CYAPA_STATE_GEN5_APP; + } else { + /* Should not happen!!! */ + cyapa->state = CYAPA_STATE_NO_DEVICE; + } + + return 0; +} + +static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len) +{ + int length; + + if (!reg_data || len < 3) + return -EINVAL; + + cyapa->state = CYAPA_STATE_NO_DEVICE; + + /* Parse based on Gen5 characteristic registers and bits */ + length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); + if (length == 0 || length == GEN5_RESP_LENGTH_SIZE) { + gen5_idle_state_parse(cyapa); + } else if (length == GEN5_HID_DESCRIPTOR_SIZE && + (reg_data[2] == GEN5_BL_HID_REPORT_ID || + reg_data[2] == GEN5_APP_HID_REPORT_ID)) { + gen5_hid_description_header_parse(cyapa, reg_data); + } else if ((length == GEN5_APP_REPORT_DESCRIPTOR_SIZE || + length == GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE) && + reg_data[2] == GEN5_APP_REPORT_DESCRIPTOR_ID) { + /* 0xEE 0x00 0xF6 is Gen5 APP report description header. */ + cyapa->gen = CYAPA_GEN5; + cyapa->state = CYAPA_STATE_GEN5_APP; + } else if (length == GEN5_BL_REPORT_DESCRIPTOR_SIZE && + reg_data[2] == GEN5_BL_REPORT_DESCRIPTOR_ID) { + /* 0x1D 0x00 0xFE is Gen5 BL report descriptior header. */ + cyapa->gen = CYAPA_GEN5; + cyapa->state = CYAPA_STATE_GEN5_BL; + } else if (reg_data[2] == GEN5_TOUCH_REPORT_ID || + reg_data[2] == GEN5_BTN_REPORT_ID || + reg_data[2] == GEN5_OLD_PUSH_BTN_REPORT_ID || + reg_data[2] == GEN5_PUSH_BTN_REPORT_ID || + reg_data[2] == GEN5_WAKEUP_EVENT_REPORT_ID) { + gen5_report_data_header_parse(cyapa, reg_data); + } else if (reg_data[2] == GEN5_BL_RESP_REPORT_ID || + reg_data[2] == GEN5_APP_RESP_REPORT_ID) { + gen5_cmd_resp_header_parse(cyapa, reg_data); + } + + if (cyapa->gen == CYAPA_GEN5) { + /* + * Must read the content (e.g.: report description and so on) + * from trackpad device throughout. Otherwise, + * Gen5 trackpad cannot response to next command or + * report any touch or button data later. + */ + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + + if (cyapa->state == CYAPA_STATE_GEN5_APP || + cyapa->state == CYAPA_STATE_GEN5_BL) + return 0; + } + + return -EAGAIN; +} + +static int cyapa_gen5_bl_initiate(struct cyapa *cyapa, + const struct firmware *fw) +{ + struct cyapa_tsg_bin_image *image; + struct gen5_bl_cmd_head *bl_cmd_head; + struct gen5_bl_packet_start *bl_packet_start; + struct gen5_bl_initiate_cmd_data *cmd_data; + struct gen5_bl_packet_end *bl_packet_end; + u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; + int cmd_len; + u16 cmd_data_len; + u16 cmd_crc = 0; + u16 meta_data_crc = 0; + u8 resp_data[11]; + int resp_len; + int records_num; + u8 *data; + int error; + + /* Try to dump all buffered report data before any send command. */ + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + + memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); + bl_cmd_head = (struct gen5_bl_cmd_head *)cmd; + cmd_data_len = CYAPA_TSG_BL_KEY_SIZE + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE; + cmd_len = sizeof(struct gen5_bl_cmd_head) + cmd_data_len + + sizeof(struct gen5_bl_packet_end); + + put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr); + put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length); + bl_cmd_head->report_id = GEN5_BL_CMD_REPORT_ID; + + bl_packet_start = &bl_cmd_head->packet_start; + bl_packet_start->sop = GEN5_SOP_KEY; + bl_packet_start->cmd_code = GEN5_BL_CMD_INITIATE_BL; + /* 8 key bytes and 128 bytes block size */ + put_unaligned_le16(cmd_data_len, &bl_packet_start->data_length); + + cmd_data = (struct gen5_bl_initiate_cmd_data *)bl_cmd_head->data; + memcpy(cmd_data->key, cyapa_gen5_bl_cmd_key, CYAPA_TSG_BL_KEY_SIZE); + + /* Copy 60 bytes Meta Data Row Parameters */ + image = (struct cyapa_tsg_bin_image *)fw->data; + records_num = (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) / + sizeof(struct cyapa_tsg_bin_image_data_record); + /* APP_INTEGRITY row is always the last row block */ + data = image->records[records_num - 1].record_data; + memcpy(cmd_data->metadata_raw_parameter, data, + CYAPA_TSG_FLASH_MAP_METADATA_SIZE); + + meta_data_crc = crc_itu_t(0xffff, cmd_data->metadata_raw_parameter, + CYAPA_TSG_FLASH_MAP_METADATA_SIZE); + put_unaligned_le16(meta_data_crc, &cmd_data->metadata_crc); + + bl_packet_end = (struct gen5_bl_packet_end *)(bl_cmd_head->data + + cmd_data_len); + cmd_crc = crc_itu_t(0xffff, (u8 *)bl_packet_start, + sizeof(struct gen5_bl_packet_start) + cmd_data_len); + put_unaligned_le16(cmd_crc, &bl_packet_end->crc); + bl_packet_end->eop = GEN5_EOP_KEY; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + cmd, cmd_len, + resp_data, &resp_len, 12000, + cyapa_gen5_sort_tsg_pip_bl_resp_data, true); + if (error || resp_len != GEN5_BL_INITIATE_RESP_LEN || + resp_data[2] != GEN5_BL_RESP_REPORT_ID || + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + return error ? error : -EAGAIN; + + return 0; +} + +static bool cyapa_gen5_sort_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len) +{ + if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE) + return false; + + if (buf[0] == 0 && buf[1] == 0) + return true; + + /* Exit bootloader failed for some reason. */ + if (len == GEN5_BL_FAIL_EXIT_RESP_LEN && + buf[GEN5_RESP_REPORT_ID_OFFSET] == + GEN5_BL_RESP_REPORT_ID && + buf[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY && + buf[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY && + buf[10] == GEN5_EOP_KEY) + return true; + + return false; +} + +static int cyapa_gen5_bl_exit(struct cyapa *cyapa) +{ + + u8 bl_gen5_bl_exit[] = { 0x04, 0x00, + 0x0B, 0x00, 0x40, 0x00, 0x01, 0x3b, 0x00, 0x00, + 0x20, 0xc7, 0x17 + }; + u8 resp_data[11]; + int resp_len; + int error; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + bl_gen5_bl_exit, sizeof(bl_gen5_bl_exit), + resp_data, &resp_len, + 5000, cyapa_gen5_sort_bl_exit_data, false); + if (error) + return error; + + if (resp_len == GEN5_BL_FAIL_EXIT_RESP_LEN || + resp_data[GEN5_RESP_REPORT_ID_OFFSET] == + GEN5_BL_RESP_REPORT_ID) + return -EAGAIN; + + if (resp_data[0] == 0x00 && resp_data[1] == 0x00) + return 0; + + return -ENODEV; +} + +static int cyapa_gen5_bl_enter(struct cyapa *cyapa) +{ + u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2F, 0x00, 0x01 }; + u8 resp_data[2]; + int resp_len; + int error; + + error = cyapa_poll_state(cyapa, 500); + if (error < 0) + return error; + if (cyapa->gen != CYAPA_GEN5) + return -EINVAL; + + /* Already in Gen5 BL. Skipping exit. */ + if (cyapa->state == CYAPA_STATE_GEN5_BL) + return 0; + + if (cyapa->state != CYAPA_STATE_GEN5_APP) + return -EAGAIN; + + /* Try to dump all buffered report data before any send command. */ + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + + /* + * Send bootloader enter command to trackpad device, + * after enter bootloader, the response data is two bytes of 0x00 0x00. + */ + resp_len = sizeof(resp_data); + memset(resp_data, 0, resp_len); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + cmd, sizeof(cmd), + resp_data, &resp_len, + 5000, cyapa_gen5_sort_application_launch_data, + true); + if (error || resp_data[0] != 0x00 || resp_data[1] != 0x00) + return error < 0 ? error : -EAGAIN; + + cyapa->operational = false; + cyapa->state = CYAPA_STATE_GEN5_BL; + return 0; +} + +static int cyapa_gen5_check_fw(struct cyapa *cyapa, const struct firmware *fw) +{ + struct device *dev = &cyapa->client->dev; + const struct cyapa_tsg_bin_image *image = (const void *)fw->data; + const struct cyapa_tsg_bin_image_data_record *app_integrity; + const struct gen5_bl_metadata_row_params *metadata; + size_t flash_records_count; + u32 fw_app_start, fw_upgrade_start; + u16 fw_app_len, fw_upgrade_len; + u16 app_crc; + u16 app_integrity_crc; + int record_index; + int i; + + flash_records_count = (fw->size - + sizeof(struct cyapa_tsg_bin_image_head)) / + sizeof(struct cyapa_tsg_bin_image_data_record); + + /* + * APP_INTEGRITY row is always the last row block, + * and the row id must be 0x01ff. + */ + app_integrity = &image->records[flash_records_count - 1]; + + if (app_integrity->flash_array_id != 0x00 || + get_unaligned_be16(&app_integrity->row_number) != 0x01ff) { + dev_err(dev, "%s: invalid app_integrity data.\n", __func__); + return -EINVAL; + } + + metadata = (const void *)app_integrity->record_data; + + /* Verify app_integrity crc */ + app_integrity_crc = crc_itu_t(0xffff, app_integrity->record_data, + CYAPA_TSG_APP_INTEGRITY_SIZE); + if (app_integrity_crc != get_unaligned_le16(&metadata->metadata_crc)) { + dev_err(dev, "%s: invalid app_integrity crc.\n", __func__); + return -EINVAL; + } + + fw_app_start = get_unaligned_le32(&metadata->app_start); + fw_app_len = get_unaligned_le16(&metadata->app_len); + fw_upgrade_start = get_unaligned_le32(&metadata->upgrade_start); + fw_upgrade_len = get_unaligned_le16(&metadata->upgrade_len); + + if (fw_app_start % CYAPA_TSG_FW_ROW_SIZE || + fw_app_len % CYAPA_TSG_FW_ROW_SIZE || + fw_upgrade_start % CYAPA_TSG_FW_ROW_SIZE || + fw_upgrade_len % CYAPA_TSG_FW_ROW_SIZE) { + dev_err(dev, "%s: invalid image alignment.\n", __func__); + return -EINVAL; + } + + /* + * Verify application image CRC + */ + record_index = fw_app_start / CYAPA_TSG_FW_ROW_SIZE - + CYAPA_TSG_IMG_START_ROW_NUM; + app_crc = 0xffffU; + for (i = 0; i < fw_app_len / CYAPA_TSG_FW_ROW_SIZE; i++) { + const u8 *data = image->records[record_index + i].record_data; + app_crc = crc_itu_t(app_crc, data, CYAPA_TSG_FW_ROW_SIZE); + } + + if (app_crc != get_unaligned_le16(&metadata->app_crc)) { + dev_err(dev, "%s: invalid firmware app crc check.\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int cyapa_gen5_write_fw_block(struct cyapa *cyapa, + struct cyapa_tsg_bin_image_data_record *flash_record) +{ + struct gen5_bl_cmd_head *bl_cmd_head; + struct gen5_bl_packet_start *bl_packet_start; + struct gen5_bl_flash_row_head *flash_row_head; + struct gen5_bl_packet_end *bl_packet_end; + u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; + u16 cmd_len; + u8 flash_array_id; + u16 flash_row_id; + u16 record_len; + u8 *record_data; + u16 data_len; + u16 crc; + u8 resp_data[11]; + int resp_len; + int error; + + flash_array_id = flash_record->flash_array_id; + flash_row_id = get_unaligned_be16(&flash_record->row_number); + record_len = get_unaligned_be16(&flash_record->record_len); + record_data = flash_record->record_data; + + memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); + bl_cmd_head = (struct gen5_bl_cmd_head *)cmd; + bl_packet_start = &bl_cmd_head->packet_start; + cmd_len = sizeof(struct gen5_bl_cmd_head) + + sizeof(struct gen5_bl_flash_row_head) + + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE + + sizeof(struct gen5_bl_packet_end); + + put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr); + /* Don't include 2 bytes register address */ + put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length); + bl_cmd_head->report_id = GEN5_BL_CMD_REPORT_ID; + bl_packet_start->sop = GEN5_SOP_KEY; + bl_packet_start->cmd_code = GEN5_BL_CMD_PROGRAM_VERIFY_ROW; + + /* 1 (Flash Array ID) + 2 (Flash Row ID) + 128 (flash data) */ + data_len = sizeof(struct gen5_bl_flash_row_head) + record_len; + put_unaligned_le16(data_len, &bl_packet_start->data_length); + + flash_row_head = (struct gen5_bl_flash_row_head *)bl_cmd_head->data; + flash_row_head->flash_array_id = flash_array_id; + put_unaligned_le16(flash_row_id, &flash_row_head->flash_row_id); + memcpy(flash_row_head->flash_data, record_data, record_len); + + bl_packet_end = (struct gen5_bl_packet_end *)(bl_cmd_head->data + + data_len); + crc = crc_itu_t(0xffff, (u8 *)bl_packet_start, + sizeof(struct gen5_bl_packet_start) + data_len); + put_unaligned_le16(crc, &bl_packet_end->crc); + bl_packet_end->eop = GEN5_EOP_KEY; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, + resp_data, &resp_len, + 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, true); + if (error || resp_len != GEN5_BL_BLOCK_WRITE_RESP_LEN || + resp_data[2] != GEN5_BL_RESP_REPORT_ID || + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + return error < 0 ? error : -EAGAIN; + + return 0; +} + +static int cyapa_gen5_do_fw_update(struct cyapa *cyapa, + const struct firmware *fw) +{ + struct device *dev = &cyapa->client->dev; + struct cyapa_tsg_bin_image_data_record *flash_record; + struct cyapa_tsg_bin_image *image = + (struct cyapa_tsg_bin_image *)fw->data; + int flash_records_count; + int i; + int error; + + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + + flash_records_count = + (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) / + sizeof(struct cyapa_tsg_bin_image_data_record); + /* + * The last flash row 0x01ff has been written through bl_initiate + * command, so DO NOT write flash 0x01ff to trackpad device. + */ + for (i = 0; i < (flash_records_count - 1); i++) { + flash_record = &image->records[i]; + error = cyapa_gen5_write_fw_block(cyapa, flash_record); + if (error) { + dev_err(dev, "%s: Gen5 FW update aborted: %d\n", + __func__, error); + return error; + } + } + + return 0; +} + +static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state) +{ + u8 cmd[8] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x08, 0x01 }; + u8 resp_data[6]; + int resp_len; + int error; + + cmd[7] = power_state; + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); + if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x08) || + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + return error < 0 ? error : -EINVAL; + + return 0; +} + +static int cyapa_gen5_set_interval_time(struct cyapa *cyapa, + u8 parameter_id, u16 interval_time) +{ + struct gen5_app_cmd_head *app_cmd_head; + struct gen5_app_set_parameter_data *parameter_data; + u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; + int cmd_len; + u8 resp_data[7]; + int resp_len; + u8 parameter_size; + int error; + + memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); + app_cmd_head = (struct gen5_app_cmd_head *)cmd; + parameter_data = (struct gen5_app_set_parameter_data *) + app_cmd_head->parameter_data; + cmd_len = sizeof(struct gen5_app_cmd_head) + + sizeof(struct gen5_app_set_parameter_data); + + switch (parameter_id) { + case GEN5_PARAMETER_ACT_INTERVL_ID: + parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE; + break; + case GEN5_PARAMETER_ACT_LFT_INTERVL_ID: + parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE; + break; + case GEN5_PARAMETER_LP_INTRVL_ID: + parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE; + break; + default: + return -EINVAL; + } + + put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); + /* + * Don't include unused parameter value bytes and + * 2 bytes register address. + */ + put_unaligned_le16(cmd_len - (4 - parameter_size) - 2, + &app_cmd_head->length); + app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER; + parameter_data->parameter_id = parameter_id; + parameter_data->parameter_size = parameter_size; + put_unaligned_le32((u32)interval_time, ¶meter_data->value); + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, + resp_data, &resp_len, + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); + if (error || resp_data[5] != parameter_id || + resp_data[6] != parameter_size || + !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER)) + return error < 0 ? error : -EINVAL; + + return 0; +} + +static int cyapa_gen5_get_interval_time(struct cyapa *cyapa, + u8 parameter_id, u16 *interval_time) +{ + struct gen5_app_cmd_head *app_cmd_head; + struct gen5_app_get_parameter_data *parameter_data; + u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; + int cmd_len; + u8 resp_data[11]; + int resp_len; + u8 parameter_size; + u16 mask, i; + int error; + + memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); + app_cmd_head = (struct gen5_app_cmd_head *)cmd; + parameter_data = (struct gen5_app_get_parameter_data *) + app_cmd_head->parameter_data; + cmd_len = sizeof(struct gen5_app_cmd_head) + + sizeof(struct gen5_app_get_parameter_data); + + *interval_time = 0; + switch (parameter_id) { + case GEN5_PARAMETER_ACT_INTERVL_ID: + parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE; + break; + case GEN5_PARAMETER_ACT_LFT_INTERVL_ID: + parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE; + break; + case GEN5_PARAMETER_LP_INTRVL_ID: + parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE; + break; + default: + return -EINVAL; + } + + put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr); + /* Don't include 2 bytes register address */ + put_unaligned_le16(cmd_len - 2, &app_cmd_head->length); + app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->cmd_code = GEN5_CMD_GET_PARAMETER; + parameter_data->parameter_id = parameter_id; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, + resp_data, &resp_len, + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); + if (error || resp_data[5] != parameter_id || resp_data[6] == 0 || + !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_GET_PARAMETER)) + return error < 0 ? error : -EINVAL; + + mask = 0; + for (i = 0; i < parameter_size; i++) + mask |= (0xff << (i * 8)); + *interval_time = get_unaligned_le16(&resp_data[7]) & mask; + + return 0; +} + +static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa) +{ + struct gen5_app_cmd_head *app_cmd_head; + u8 cmd[10]; + u8 resp_data[7]; + int resp_len; + int error; + + memset(cmd, 0, sizeof(cmd)); + app_cmd_head = (struct gen5_app_cmd_head *)cmd; + + put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr); + put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); + app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER; + app_cmd_head->parameter_data[0] = GEN5_PARAMETER_DISABLE_PIP_REPORT; + app_cmd_head->parameter_data[1] = 0x01; + app_cmd_head->parameter_data[2] = 0x01; + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); + if (error || resp_data[5] != GEN5_PARAMETER_DISABLE_PIP_REPORT || + !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER) || + resp_data[6] != 0x01) + return error < 0 ? error : -EINVAL; + + return 0; +} + +static int cyapa_gen5_deep_sleep(struct cyapa *cyapa, u8 state) +{ + u8 cmd[] = { 0x05, 0x00, 0x00, 0x08}; + u8 resp_data[5]; + int resp_len; + int error; + + cmd[2] = state & GEN5_DEEP_SLEEP_STATE_MASK; + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_gen5_sort_deep_sleep_data, false); + if (error || ((resp_data[3] & GEN5_DEEP_SLEEP_STATE_MASK) != state)) + return -EINVAL; + + return 0; +} + +static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, + u8 power_mode, u16 sleep_time) +{ + struct device *dev = &cyapa->client->dev; + u8 power_state; + int error; + + if (cyapa->state != CYAPA_STATE_GEN5_APP) + return 0; + + /* Dump all the report data before do power mode commmands. */ + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + + if (GEN5_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) { + /* + * Assume TP in deep sleep mode when driver is loaded, + * avoid driver unload and reload command IO issue caused by TP + * has been set into deep sleep mode when unloading. + */ + GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); + } + + if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) && + GEN5_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF) + if (cyapa_gen5_get_interval_time(cyapa, + GEN5_PARAMETER_LP_INTRVL_ID, + &cyapa->dev_sleep_time) != 0) + GEN5_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME); + + if (GEN5_DEV_GET_PWR_STATE(cyapa) == power_mode) { + if (power_mode == PWR_MODE_OFF || + power_mode == PWR_MODE_FULL_ACTIVE || + power_mode == PWR_MODE_BTN_ONLY || + GEN5_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) { + /* Has in correct power mode state, early return. */ + return 0; + } + } + + if (power_mode == PWR_MODE_OFF) { + error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_OFF); + if (error) { + dev_err(dev, "enter deep sleep fail: %d\n", error); + return error; + } + + GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); + return 0; + } + + /* + * When trackpad in power off mode, it cannot change to other power + * state directly, must be wake up from sleep firstly, then + * continue to do next power sate change. + */ + if (GEN5_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) { + error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_ON); + if (error) { + dev_err(dev, "deep sleep wake fail: %d\n", error); + return error; + } + } + + if (power_mode == PWR_MODE_FULL_ACTIVE) { + error = cyapa_gen5_change_power_state(cyapa, + GEN5_POWER_STATE_ACTIVE); + if (error) { + dev_err(dev, "change to active fail: %d\n", error); + return error; + } + + GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE); + } else if (power_mode == PWR_MODE_BTN_ONLY) { + error = cyapa_gen5_change_power_state(cyapa, + GEN5_POWER_STATE_BTN_ONLY); + if (error) { + dev_err(dev, "fail to button only mode: %d\n", error); + return error; + } + + GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY); + } else { + /* + * Continue to change power mode even failed to set + * interval time, it won't affect the power mode change. + * except the sleep interval time is not correct. + */ + if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) || + sleep_time != GEN5_DEV_GET_SLEEP_TIME(cyapa)) + if (cyapa_gen5_set_interval_time(cyapa, + GEN5_PARAMETER_LP_INTRVL_ID, + sleep_time) == 0) + GEN5_DEV_SET_SLEEP_TIME(cyapa, sleep_time); + + if (sleep_time <= GEN5_POWER_READY_MAX_INTRVL_TIME) + power_state = GEN5_POWER_STATE_READY; + else + power_state = GEN5_POWER_STATE_IDLE; + error = cyapa_gen5_change_power_state(cyapa, power_state); + if (error) { + dev_err(dev, "set power state to 0x%02x failed: %d\n", + power_state, error); + return error; + } + + /* + * Disable pip report for a little time, firmware will + * re-enable it automatically. It's used to fix the issue + * that trackpad unable to report signal to wake system up + * in the special situation that system is in suspending, and + * at the same time, user touch trackpad to wake system up. + * This function can avoid the data to be buffured when system + * is suspending which may cause interrput line unable to be + * asserted again. + */ + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + cyapa_gen5_disable_pip_report(cyapa); + + GEN5_DEV_SET_PWR_STATE(cyapa, + cyapa_sleep_time_to_pwr_cmd(sleep_time)); + } + + return 0; +} + +static int cyapa_gen5_resume_scanning(struct cyapa *cyapa) +{ + u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x04 }; + u8 resp_data[6]; + int resp_len; + int error; + + /* Try to dump all buffered data before doing command. */ + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); + if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x04)) + return -EINVAL; + + /* Try to dump all buffered data when resuming scanning. */ + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + + return 0; +} + +static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa) +{ + u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x03 }; + u8 resp_data[6]; + int resp_len; + int error; + + /* Try to dump all buffered data before doing command. */ + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); + if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x03)) + return -EINVAL; + + /* Try to dump all buffered data when suspending scanning. */ + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + + return 0; +} + +static int cyapa_gen5_calibrate_pwcs(struct cyapa *cyapa, + u8 calibrate_sensing_mode_type) +{ + struct gen5_app_cmd_head *app_cmd_head; + u8 cmd[8]; + u8 resp_data[6]; + int resp_len; + int error; + + /* Try to dump all buffered data before doing command. */ + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + + memset(cmd, 0, sizeof(cmd)); + app_cmd_head = (struct gen5_app_cmd_head *)cmd; + put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); + put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); + app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->cmd_code = GEN5_CMD_CALIBRATE; + app_cmd_head->parameter_data[0] = calibrate_sensing_mode_type; + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + cmd, sizeof(cmd), + resp_data, &resp_len, + 5000, cyapa_gen5_sort_tsg_pip_app_resp_data, true); + if (error || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_CALIBRATE) || + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + return error < 0 ? error : -EAGAIN; + + return 0; +} + +static ssize_t cyapa_gen5_do_calibrate(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + int error, calibrate_error; + + /* 1. Suspend Scanning*/ + error = cyapa_gen5_suspend_scanning(cyapa); + if (error) + return error; + + /* 2. Do mutual capacitance fine calibrate. */ + calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa, + CYAPA_SENSING_MODE_MUTUAL_CAP_FINE); + if (calibrate_error) + goto resume_scanning; + + /* 3. Do self capacitance calibrate. */ + calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa, + CYAPA_SENSING_MODE_SELF_CAP); + if (calibrate_error) + goto resume_scanning; + +resume_scanning: + /* 4. Resume Scanning*/ + error = cyapa_gen5_resume_scanning(cyapa); + if (error || calibrate_error) + return error ? error : calibrate_error; + + return count; +} + +static s32 twos_complement_to_s32(s32 value, int num_bits) +{ + if (value >> (num_bits - 1)) + value |= -1 << num_bits; + return value; +} + +static s32 cyapa_parse_structure_data(u8 data_format, u8 *buf, int buf_len) +{ + int data_size; + bool big_endian; + bool unsigned_type; + s32 value; + + data_size = (data_format & 0x07); + big_endian = ((data_format & 0x10) == 0x00); + unsigned_type = ((data_format & 0x20) == 0x00); + + if (buf_len < data_size) + return 0; + + switch (data_size) { + case 1: + value = buf[0]; + break; + case 2: + if (big_endian) + value = get_unaligned_be16(buf); + else + value = get_unaligned_le16(buf); + break; + case 4: + if (big_endian) + value = get_unaligned_be32(buf); + else + value = get_unaligned_le32(buf); + break; + default: + /* Should not happen, just as default case here. */ + value = 0; + break; + } + + if (!unsigned_type) + value = twos_complement_to_s32(value, data_size * 8); + + return value; +} + +static void cyapa_gen5_guess_electrodes(struct cyapa *cyapa, + int *electrodes_rx, int *electrodes_tx) +{ + if (cyapa->electrodes_rx != 0) { + *electrodes_rx = cyapa->electrodes_rx; + *electrodes_tx = (cyapa->electrodes_x == *electrodes_rx) ? + cyapa->electrodes_y : cyapa->electrodes_x; + } else { + *electrodes_tx = min(cyapa->electrodes_x, cyapa->electrodes_y); + *electrodes_rx = max(cyapa->electrodes_x, cyapa->electrodes_y); + } +} + +/* + * Read all the global mutual or self idac data or mutual or self local PWC + * data based on the @idac_data_type. + * If the input value of @data_size is 0, then means read global mutual or + * self idac data. For read global mutual idac data, @idac_max, @idac_min and + * @idac_ave are in order used to return the max value of global mutual idac + * data, the min value of global mutual idac and the average value of the + * global mutual idac data. For read global self idac data, @idac_max is used + * to return the global self cap idac data in Rx direction, @idac_min is used + * to return the global self cap idac data in Tx direction. @idac_ave is not + * used. + * If the input value of @data_size is not 0, than means read the mutual or + * self local PWC data. The @idac_max, @idac_min and @idac_ave are used to + * return the max, min and average value of the mutual or self local PWC data. + * Note, in order to raed mutual local PWC data, must read invoke this function + * to read the mutual global idac data firstly to set the correct Rx number + * value, otherwise, the read mutual idac and PWC data may not correct. + */ +static int cyapa_gen5_read_idac_data(struct cyapa *cyapa, + u8 cmd_code, u8 idac_data_type, int *data_size, + int *idac_max, int *idac_min, int *idac_ave) +{ + struct gen5_app_cmd_head *cmd_head; + u8 cmd[12]; + u8 resp_data[256]; + int resp_len; + int read_len; + int value; + u16 offset; + int read_elements; + bool read_global_idac; + int sum, count, max_element_cnt; + int tmp_max, tmp_min, tmp_ave, tmp_sum, tmp_count; + int electrodes_rx, electrodes_tx; + int i; + int error; + + if (cmd_code != GEN5_CMD_RETRIEVE_DATA_STRUCTURE || + (idac_data_type != GEN5_RETRIEVE_MUTUAL_PWC_DATA && + idac_data_type != GEN5_RETRIEVE_SELF_CAP_PWC_DATA) || + !data_size || !idac_max || !idac_min || !idac_ave) + return -EINVAL; + + *idac_max = INT_MIN; + *idac_min = INT_MAX; + sum = count = tmp_count = 0; + electrodes_rx = electrodes_tx = 0; + if (*data_size == 0) { + /* + * Read global idac values firstly. + * Currently, no idac data exceed 4 bytes. + */ + read_global_idac = true; + offset = 0; + *data_size = 4; + tmp_max = INT_MIN; + tmp_min = INT_MAX; + tmp_ave = tmp_sum = tmp_count = 0; + + if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) { + if (cyapa->aligned_electrodes_rx == 0) { + cyapa_gen5_guess_electrodes(cyapa, + &electrodes_rx, &electrodes_tx); + cyapa->aligned_electrodes_rx = + (electrodes_rx + 3) & ~3u; + } + max_element_cnt = + (cyapa->aligned_electrodes_rx + 7) & ~7u; + } else { + max_element_cnt = 2; + } + } else { + read_global_idac = false; + if (*data_size > 4) + *data_size = 4; + /* Calculate the start offset in bytes of local PWC data. */ + if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) { + offset = cyapa->aligned_electrodes_rx * (*data_size); + if (cyapa->electrodes_rx == cyapa->electrodes_x) + electrodes_tx = cyapa->electrodes_y; + else + electrodes_tx = cyapa->electrodes_x; + max_element_cnt = ((cyapa->aligned_electrodes_rx + 7) & + ~7u) * electrodes_tx; + } else if (idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) { + offset = 2; + max_element_cnt = cyapa->electrodes_x + + cyapa->electrodes_y; + max_element_cnt = (max_element_cnt + 3) & ~3u; + } + } + + memset(cmd, 0, sizeof(cmd)); + cmd_head = (struct gen5_app_cmd_head *)cmd; + put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &cmd_head->addr); + put_unaligned_le16(sizeof(cmd) - 2, &cmd_head->length); + cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + cmd_head->cmd_code = cmd_code; + do { + read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) / + (*data_size); + read_elements = min(read_elements, max_element_cnt - count); + read_len = read_elements * (*data_size); + + put_unaligned_le16(offset, &cmd_head->parameter_data[0]); + put_unaligned_le16(read_len, &cmd_head->parameter_data[2]); + cmd_head->parameter_data[4] = idac_data_type; + resp_len = GEN5_RESP_DATA_STRUCTURE_OFFSET + read_len; + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, + true); + if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET || + !VALID_CMD_RESP_HEADER(resp_data, cmd_code) || + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) || + resp_data[6] != idac_data_type) + return (error < 0) ? error : -EAGAIN; + read_len = get_unaligned_le16(&resp_data[7]); + if (read_len == 0) + break; + + *data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK); + if (read_len < *data_size) + return -EINVAL; + + if (read_global_idac && + idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) { + /* Rx's self global idac data. */ + *idac_max = cyapa_parse_structure_data( + resp_data[9], + &resp_data[GEN5_RESP_DATA_STRUCTURE_OFFSET], + *data_size); + /* Tx's self global idac data. */ + *idac_min = cyapa_parse_structure_data( + resp_data[9], + &resp_data[GEN5_RESP_DATA_STRUCTURE_OFFSET + + *data_size], + *data_size); + break; + } + + /* Read mutual global idac or local mutual/self PWC data. */ + offset += read_len; + for (i = 10; i < (read_len + GEN5_RESP_DATA_STRUCTURE_OFFSET); + i += *data_size) { + value = cyapa_parse_structure_data(resp_data[9], + &resp_data[i], *data_size); + *idac_min = min(value, *idac_min); + *idac_max = max(value, *idac_max); + + if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA && + tmp_count < cyapa->aligned_electrodes_rx && + read_global_idac) { + /* + * The value gap betwen global and local mutual + * idac data must bigger than 50%. + * Normally, global value bigger than 50, + * local values less than 10. + */ + if (!tmp_ave || value > tmp_ave / 2) { + tmp_min = min(value, tmp_min); + tmp_max = max(value, tmp_max); + tmp_sum += value; + tmp_count++; + + tmp_ave = tmp_sum / tmp_count; + } + } + + sum += value; + count++; + + if (count >= max_element_cnt) + goto out; + } + } while (true); + +out: + *idac_ave = count ? (sum / count) : 0; + + if (read_global_idac && + idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) { + if (tmp_count == 0) + return 0; + + if (tmp_count == cyapa->aligned_electrodes_rx) { + cyapa->electrodes_rx = cyapa->electrodes_rx ? + cyapa->electrodes_rx : electrodes_rx; + } else if (tmp_count == electrodes_rx) { + cyapa->electrodes_rx = cyapa->electrodes_rx ? + cyapa->electrodes_rx : electrodes_rx; + cyapa->aligned_electrodes_rx = electrodes_rx; + } else { + cyapa->electrodes_rx = cyapa->electrodes_rx ? + cyapa->electrodes_rx : electrodes_tx; + cyapa->aligned_electrodes_rx = tmp_count; + } + + *idac_min = tmp_min; + *idac_max = tmp_max; + *idac_ave = tmp_ave; + } + + return 0; +} + +static int cyapa_gen5_read_mutual_idac_data(struct cyapa *cyapa, + int *gidac_mutual_max, int *gidac_mutual_min, int *gidac_mutual_ave, + int *lidac_mutual_max, int *lidac_mutual_min, int *lidac_mutual_ave) +{ + int data_size; + int error; + + *gidac_mutual_max = *gidac_mutual_min = *gidac_mutual_ave = 0; + *lidac_mutual_max = *lidac_mutual_min = *lidac_mutual_ave = 0; + + data_size = 0; + error = cyapa_gen5_read_idac_data(cyapa, + GEN5_CMD_RETRIEVE_DATA_STRUCTURE, + GEN5_RETRIEVE_MUTUAL_PWC_DATA, + &data_size, + gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave); + if (error) + return error; + + error = cyapa_gen5_read_idac_data(cyapa, + GEN5_CMD_RETRIEVE_DATA_STRUCTURE, + GEN5_RETRIEVE_MUTUAL_PWC_DATA, + &data_size, + lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave); + return error; +} + +static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa, + int *gidac_self_rx, int *gidac_self_tx, + int *lidac_self_max, int *lidac_self_min, int *lidac_self_ave) +{ + int data_size; + int error; + + *gidac_self_rx = *gidac_self_tx = 0; + *lidac_self_max = *lidac_self_min = *lidac_self_ave = 0; + + data_size = 0; + error = cyapa_gen5_read_idac_data(cyapa, + GEN5_CMD_RETRIEVE_DATA_STRUCTURE, + GEN5_RETRIEVE_SELF_CAP_PWC_DATA, + &data_size, + lidac_self_max, lidac_self_min, lidac_self_ave); + if (error) + return error; + *gidac_self_rx = *lidac_self_max; + *gidac_self_tx = *lidac_self_min; + + error = cyapa_gen5_read_idac_data(cyapa, + GEN5_CMD_RETRIEVE_DATA_STRUCTURE, + GEN5_RETRIEVE_SELF_CAP_PWC_DATA, + &data_size, + lidac_self_max, lidac_self_min, lidac_self_ave); + return error; +} + +static ssize_t cyapa_gen5_execute_panel_scan(struct cyapa *cyapa) +{ + struct gen5_app_cmd_head *app_cmd_head; + u8 cmd[7]; + u8 resp_data[6]; + int resp_len; + int error; + + memset(cmd, 0, sizeof(cmd)); + app_cmd_head = (struct gen5_app_cmd_head *)cmd; + put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); + put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); + app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->cmd_code = GEN5_CMD_EXECUTE_PANEL_SCAN; + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); + if (error || resp_len != sizeof(resp_data) || + !VALID_CMD_RESP_HEADER(resp_data, + GEN5_CMD_EXECUTE_PANEL_SCAN) || + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + return error ? error : -EAGAIN; + + return 0; +} + +static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa, + u8 cmd_code, u8 raw_data_type, int raw_data_max_num, + int *raw_data_max, int *raw_data_min, int *raw_data_ave, + u8 *buffer) +{ + struct gen5_app_cmd_head *app_cmd_head; + struct gen5_retrieve_panel_scan_data *panel_sacn_data; + u8 cmd[12]; + u8 resp_data[256]; /* Max bytes can transfer one time. */ + int resp_len; + int read_elements; + int read_len; + u16 offset; + s32 value; + int sum, count; + int data_size; + s32 *intp; + int i; + int error; + + if (cmd_code != GEN5_CMD_RETRIEVE_PANEL_SCAN || + (raw_data_type > GEN5_PANEL_SCAN_SELF_DIFFCOUNT) || + !raw_data_max || !raw_data_min || !raw_data_ave) + return -EINVAL; + + intp = (s32 *)buffer; + *raw_data_max = INT_MIN; + *raw_data_min = INT_MAX; + sum = count = 0; + offset = 0; + /* Assume max element size is 4 currently. */ + read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) / 4; + read_len = read_elements * 4; + app_cmd_head = (struct gen5_app_cmd_head *)cmd; + put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); + put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); + app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->cmd_code = cmd_code; + panel_sacn_data = (struct gen5_retrieve_panel_scan_data *) + app_cmd_head->parameter_data; + do { + put_unaligned_le16(offset, &panel_sacn_data->read_offset); + put_unaligned_le16(read_elements, + &panel_sacn_data->read_elements); + panel_sacn_data->data_id = raw_data_type; + + resp_len = GEN5_RESP_DATA_STRUCTURE_OFFSET + read_len; + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); + if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET || + !VALID_CMD_RESP_HEADER(resp_data, cmd_code) || + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) || + resp_data[6] != raw_data_type) + return error ? error : -EAGAIN; + + read_elements = get_unaligned_le16(&resp_data[7]); + if (read_elements == 0) + break; + + data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK); + offset += read_elements; + if (read_elements) { + for (i = GEN5_RESP_DATA_STRUCTURE_OFFSET; + i < (read_elements * data_size + + GEN5_RESP_DATA_STRUCTURE_OFFSET); + i += data_size) { + value = cyapa_parse_structure_data(resp_data[9], + &resp_data[i], data_size); + *raw_data_min = min(value, *raw_data_min); + *raw_data_max = max(value, *raw_data_max); + + if (intp) + put_unaligned_le32(value, &intp[count]); + + sum += value; + count++; + + } + } + + if (count >= raw_data_max_num) + break; + + read_elements = (sizeof(resp_data) - + GEN5_RESP_DATA_STRUCTURE_OFFSET) / data_size; + read_len = read_elements * data_size; + } while (true); + + *raw_data_ave = count ? (sum / count) : 0; + + return 0; +} + +static ssize_t cyapa_gen5_show_baseline(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + int gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave; + int lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave; + int gidac_self_rx, gidac_self_tx; + int lidac_self_max, lidac_self_min, lidac_self_ave; + int raw_cap_mutual_max, raw_cap_mutual_min, raw_cap_mutual_ave; + int raw_cap_self_max, raw_cap_self_min, raw_cap_self_ave; + int mutual_diffdata_max, mutual_diffdata_min, mutual_diffdata_ave; + int self_diffdata_max, self_diffdata_min, self_diffdata_ave; + int mutual_baseline_max, mutual_baseline_min, mutual_baseline_ave; + int self_baseline_max, self_baseline_min, self_baseline_ave; + int error, resume_error; + int size; + + if (cyapa->state != CYAPA_STATE_GEN5_APP) + return -EBUSY; + + /* 1. Suspend Scanning*/ + error = cyapa_gen5_suspend_scanning(cyapa); + if (error) + return error; + + /* 2. Read global and local mutual IDAC data. */ + gidac_self_rx = gidac_self_tx = 0; + error = cyapa_gen5_read_mutual_idac_data(cyapa, + &gidac_mutual_max, &gidac_mutual_min, + &gidac_mutual_ave, &lidac_mutual_max, + &lidac_mutual_min, &lidac_mutual_ave); + if (error) + goto resume_scanning; + + /* 3. Read global and local self IDAC data. */ + error = cyapa_gen5_read_self_idac_data(cyapa, + &gidac_self_rx, &gidac_self_tx, + &lidac_self_max, &lidac_self_min, + &lidac_self_ave); + if (error) + goto resume_scanning; + + /* 4. Execuate panel scan. It must be executed before read data. */ + error = cyapa_gen5_execute_panel_scan(cyapa); + if (error) + goto resume_scanning; + + /* 5. Retrieve panel scan, mutual cap raw data. */ + error = cyapa_gen5_read_panel_scan_raw_data(cyapa, + GEN5_CMD_RETRIEVE_PANEL_SCAN, + GEN5_PANEL_SCAN_MUTUAL_RAW_DATA, + cyapa->electrodes_x * cyapa->electrodes_y, + &raw_cap_mutual_max, &raw_cap_mutual_min, + &raw_cap_mutual_ave, + NULL); + if (error) + goto resume_scanning; + + /* 6. Retrieve panel scan, self cap raw data. */ + error = cyapa_gen5_read_panel_scan_raw_data(cyapa, + GEN5_CMD_RETRIEVE_PANEL_SCAN, + GEN5_PANEL_SCAN_SELF_RAW_DATA, + cyapa->electrodes_x + cyapa->electrodes_y, + &raw_cap_self_max, &raw_cap_self_min, + &raw_cap_self_ave, + NULL); + if (error) + goto resume_scanning; + + /* 7. Retrieve panel scan, mutual cap diffcount raw data. */ + error = cyapa_gen5_read_panel_scan_raw_data(cyapa, + GEN5_CMD_RETRIEVE_PANEL_SCAN, + GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT, + cyapa->electrodes_x * cyapa->electrodes_y, + &mutual_diffdata_max, &mutual_diffdata_min, + &mutual_diffdata_ave, + NULL); + if (error) + goto resume_scanning; + + /* 8. Retrieve panel scan, self cap diffcount raw data. */ + error = cyapa_gen5_read_panel_scan_raw_data(cyapa, + GEN5_CMD_RETRIEVE_PANEL_SCAN, + GEN5_PANEL_SCAN_SELF_DIFFCOUNT, + cyapa->electrodes_x + cyapa->electrodes_y, + &self_diffdata_max, &self_diffdata_min, + &self_diffdata_ave, + NULL); + if (error) + goto resume_scanning; + + /* 9. Retrieve panel scan, mutual cap baseline raw data. */ + error = cyapa_gen5_read_panel_scan_raw_data(cyapa, + GEN5_CMD_RETRIEVE_PANEL_SCAN, + GEN5_PANEL_SCAN_MUTUAL_BASELINE, + cyapa->electrodes_x * cyapa->electrodes_y, + &mutual_baseline_max, &mutual_baseline_min, + &mutual_baseline_ave, + NULL); + if (error) + goto resume_scanning; + + /* 10. Retrieve panel scan, self cap baseline raw data. */ + error = cyapa_gen5_read_panel_scan_raw_data(cyapa, + GEN5_CMD_RETRIEVE_PANEL_SCAN, + GEN5_PANEL_SCAN_SELF_BASELINE, + cyapa->electrodes_x + cyapa->electrodes_y, + &self_baseline_max, &self_baseline_min, + &self_baseline_ave, + NULL); + if (error) + goto resume_scanning; + +resume_scanning: + /* 11. Resume Scanning*/ + resume_error = cyapa_gen5_resume_scanning(cyapa); + if (resume_error || error) + return resume_error ? resume_error : error; + + /* 12. Output data strings */ + size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d %d %d %d %d %d ", + gidac_mutual_min, gidac_mutual_max, gidac_mutual_ave, + lidac_mutual_min, lidac_mutual_max, lidac_mutual_ave, + gidac_self_rx, gidac_self_tx, + lidac_self_min, lidac_self_max, lidac_self_ave); + size += scnprintf(buf + size, PAGE_SIZE - size, + "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", + raw_cap_mutual_min, raw_cap_mutual_max, raw_cap_mutual_ave, + raw_cap_self_min, raw_cap_self_max, raw_cap_self_ave, + mutual_diffdata_min, mutual_diffdata_max, mutual_diffdata_ave, + self_diffdata_min, self_diffdata_max, self_diffdata_ave, + mutual_baseline_min, mutual_baseline_max, mutual_baseline_ave, + self_baseline_min, self_baseline_max, self_baseline_ave); + return size; +} + +static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa, + u8 *buf, int len) +{ + /* Check the report id and command code */ + if (VALID_CMD_RESP_HEADER(buf, 0x02)) + return true; + + return false; +} + +static int cyapa_gen5_bl_query_data(struct cyapa *cyapa) +{ + u8 bl_query_data_cmd[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00, + 0x01, 0x3c, 0x00, 0x00, 0xb0, 0x42, 0x17 + }; + u8 resp_data[GEN5_BL_READ_APP_INFO_RESP_LEN]; + int resp_len; + int error; + + resp_len = GEN5_BL_READ_APP_INFO_RESP_LEN; + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + bl_query_data_cmd, sizeof(bl_query_data_cmd), + resp_data, &resp_len, + 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, false); + if (error || resp_len != GEN5_BL_READ_APP_INFO_RESP_LEN || + !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + return error ? error : -EIO; + + memcpy(&cyapa->product_id[0], &resp_data[8], 5); + cyapa->product_id[5] = '-'; + memcpy(&cyapa->product_id[6], &resp_data[13], 6); + cyapa->product_id[12] = '-'; + memcpy(&cyapa->product_id[13], &resp_data[19], 2); + cyapa->product_id[15] = '\0'; + + cyapa->fw_maj_ver = resp_data[22]; + cyapa->fw_min_ver = resp_data[23]; + + return 0; +} + +static int cyapa_gen5_get_query_data(struct cyapa *cyapa) +{ + u8 get_system_information[] = { + 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x02 + }; + u8 resp_data[71]; + int resp_len; + u16 product_family; + int error; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + get_system_information, sizeof(get_system_information), + resp_data, &resp_len, + 2000, cyapa_gen5_sort_system_info_data, false); + if (error || resp_len < sizeof(resp_data)) + return error ? error : -EIO; + + product_family = get_unaligned_le16(&resp_data[7]); + if ((product_family & GEN5_PRODUCT_FAMILY_MASK) != + GEN5_PRODUCT_FAMILY_TRACKPAD) + return -EINVAL; + + cyapa->fw_maj_ver = resp_data[15]; + cyapa->fw_min_ver = resp_data[16]; + + cyapa->electrodes_x = resp_data[52]; + cyapa->electrodes_y = resp_data[53]; + + cyapa->physical_size_x = get_unaligned_le16(&resp_data[54]) / 100; + cyapa->physical_size_y = get_unaligned_le16(&resp_data[56]) / 100; + + cyapa->max_abs_x = get_unaligned_le16(&resp_data[58]); + cyapa->max_abs_y = get_unaligned_le16(&resp_data[60]); + + cyapa->max_z = get_unaligned_le16(&resp_data[62]); + + cyapa->x_origin = resp_data[64] & 0x01; + cyapa->y_origin = resp_data[65] & 0x01; + + cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK; + + memcpy(&cyapa->product_id[0], &resp_data[33], 5); + cyapa->product_id[5] = '-'; + memcpy(&cyapa->product_id[6], &resp_data[38], 6); + cyapa->product_id[12] = '-'; + memcpy(&cyapa->product_id[13], &resp_data[44], 2); + cyapa->product_id[15] = '\0'; + + if (!cyapa->electrodes_x || !cyapa->electrodes_y || + !cyapa->physical_size_x || !cyapa->physical_size_y || + !cyapa->max_abs_x || !cyapa->max_abs_y || !cyapa->max_z) + return -EINVAL; + + return 0; +} + +static int cyapa_gen5_do_operational_check(struct cyapa *cyapa) +{ + struct device *dev = &cyapa->client->dev; + int error; + + if (cyapa->gen != CYAPA_GEN5) + return -ENODEV; + + switch (cyapa->state) { + case CYAPA_STATE_GEN5_BL: + error = cyapa_gen5_bl_exit(cyapa); + if (error) { + /* Rry to update trackpad product information. */ + cyapa_gen5_bl_query_data(cyapa); + goto out; + } + + cyapa->state = CYAPA_STATE_GEN5_APP; + + case CYAPA_STATE_GEN5_APP: + /* + * If trackpad device in deep sleep mode, + * the app command will fail. + * So always try to reset trackpad device to full active when + * the device state is requeried. + */ + error = cyapa_gen5_set_power_mode(cyapa, + PWR_MODE_FULL_ACTIVE, 0); + if (error) + dev_warn(dev, "%s: failed to set power active mode.\n", + __func__); + + /* Get trackpad product information. */ + error = cyapa_gen5_get_query_data(cyapa); + if (error) + goto out; + /* Only support product ID starting with CYTRA */ + if (memcmp(cyapa->product_id, product_id, + strlen(product_id)) != 0) { + dev_err(dev, "%s: unknown product ID (%s)\n", + __func__, cyapa->product_id); + error = -EINVAL; + } + break; + default: + error = -EINVAL; + } + +out: + return error; +} + +/* + * Return false, do not continue process + * Return true, continue process. + */ +static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa) +{ + struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + int length; + + if (atomic_read(&gen5_pip->cmd_issued)) { + /* Polling command response data. */ + if (gen5_pip->is_irq_mode == false) + return false; + + /* + * Read out all none command response data. + * these output data may caused by user put finger on + * trackpad when host waiting the command response. + */ + cyapa_i2c_pip_read(cyapa, gen5_pip->irq_cmd_buf, + GEN5_RESP_LENGTH_SIZE); + length = get_unaligned_le16(gen5_pip->irq_cmd_buf); + length = (length <= GEN5_RESP_LENGTH_SIZE) ? + GEN5_RESP_LENGTH_SIZE : length; + if (length > GEN5_RESP_LENGTH_SIZE) + cyapa_i2c_pip_read(cyapa, + gen5_pip->irq_cmd_buf, length); + + if (!(gen5_pip->resp_sort_func && + gen5_pip->resp_sort_func(cyapa, + gen5_pip->irq_cmd_buf, length))) { + /* + * Cover the Gen5 V1 firmware issue. + * The issue is there is no interrut will be + * asserted to notityf host to read a command + * data out when always has finger touch on + * trackpad during the command is issued to + * trackad device. + * This issue has the scenario is that, + * user always has his fingers touched on + * trackpad device when booting/rebooting + * their chrome book. + */ + length = 0; + if (gen5_pip->resp_len) + length = *gen5_pip->resp_len; + cyapa_empty_pip_output_data(cyapa, + gen5_pip->resp_data, + &length, + gen5_pip->resp_sort_func); + if (gen5_pip->resp_len && length != 0) { + *gen5_pip->resp_len = length; + atomic_dec(&gen5_pip->cmd_issued); + complete(&gen5_pip->cmd_ready); + } + return false; + } + + if (gen5_pip->resp_data && gen5_pip->resp_len) { + *gen5_pip->resp_len = (*gen5_pip->resp_len < length) ? + *gen5_pip->resp_len : length; + memcpy(gen5_pip->resp_data, gen5_pip->irq_cmd_buf, + *gen5_pip->resp_len); + } + atomic_dec(&gen5_pip->cmd_issued); + complete(&gen5_pip->cmd_ready); + return false; + } + + return true; +} + +static void cyapa_gen5_report_buttons(struct cyapa *cyapa, + const struct cyapa_gen5_report_data *report_data) +{ + struct input_dev *input = cyapa->input; + u8 buttons = report_data->report_head[GEN5_BUTTONS_OFFSET]; + + buttons = (buttons << CAPABILITY_BTN_SHIFT) & CAPABILITY_BTN_MASK; + + if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) { + input_report_key(input, BTN_LEFT, + !!(buttons & CAPABILITY_LEFT_BTN_MASK)); + } + if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) { + input_report_key(input, BTN_MIDDLE, + !!(buttons & CAPABILITY_MIDDLE_BTN_MASK)); + } + if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) { + input_report_key(input, BTN_RIGHT, + !!(buttons & CAPABILITY_RIGHT_BTN_MASK)); + } + + input_sync(input); +} + +static void cyapa_gen5_report_slot_data(struct cyapa *cyapa, + const struct cyapa_gen5_touch_record *touch) +{ + struct input_dev *input = cyapa->input; + u8 event_id = GEN5_GET_EVENT_ID(touch->touch_tip_event_id); + int slot = GEN5_GET_TOUCH_ID(touch->touch_tip_event_id); + int x, y; + + if (event_id == RECORD_EVENT_LIFTOFF) + return; + + input_mt_slot(input, slot); + input_mt_report_slot_state(input, MT_TOOL_FINGER, true); + x = (touch->x_hi << 8) | touch->x_lo; + if (cyapa->x_origin) + x = cyapa->max_abs_x - x; + input_report_abs(input, ABS_MT_POSITION_X, x); + y = (touch->y_hi << 8) | touch->y_lo; + if (cyapa->y_origin) + y = cyapa->max_abs_y - y; + input_report_abs(input, ABS_MT_POSITION_Y, y); + input_report_abs(input, ABS_MT_PRESSURE, + touch->z); + input_report_abs(input, ABS_MT_TOUCH_MAJOR, + touch->major_axis_len); + input_report_abs(input, ABS_MT_TOUCH_MINOR, + touch->minor_axis_len); + + input_report_abs(input, ABS_MT_WIDTH_MAJOR, + touch->major_tool_len); + input_report_abs(input, ABS_MT_WIDTH_MINOR, + touch->minor_tool_len); + + input_report_abs(input, ABS_MT_ORIENTATION, + touch->orientation); +} + +static void cyapa_gen5_report_touches(struct cyapa *cyapa, + const struct cyapa_gen5_report_data *report_data) +{ + struct input_dev *input = cyapa->input; + unsigned int touch_num; + int i; + + touch_num = report_data->report_head[GEN5_NUMBER_OF_TOUCH_OFFSET] & + GEN5_NUMBER_OF_TOUCH_MASK; + + for (i = 0; i < touch_num; i++) + cyapa_gen5_report_slot_data(cyapa, + &report_data->touch_records[i]); + + input_mt_sync_frame(input); + input_sync(input); +} + +static int cyapa_gen5_irq_handler(struct cyapa *cyapa) +{ + struct device *dev = &cyapa->client->dev; + struct cyapa_gen5_report_data report_data; + int ret; + u8 report_id; + unsigned int report_len; + + if (cyapa->gen != CYAPA_GEN5 || + cyapa->state != CYAPA_STATE_GEN5_APP) { + dev_err(dev, "invalid device state, gen=%d, state=0x%02x\n", + cyapa->gen, cyapa->state); + return -EINVAL; + } + + ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, + GEN5_RESP_LENGTH_SIZE); + if (ret != GEN5_RESP_LENGTH_SIZE) { + dev_err(dev, "failed to read length bytes, (%d)\n", ret); + return -EINVAL; + } + + report_len = get_unaligned_le16( + &report_data.report_head[GEN5_RESP_LENGTH_OFFSET]); + if (report_len < GEN5_RESP_LENGTH_SIZE) { + /* Invliad length or internal reset happened. */ + dev_err(dev, "invalid report_len=%d. bytes: %02x %02x\n", + report_len, report_data.report_head[0], + report_data.report_head[1]); + return -EINVAL; + } + + /* Idle, no data for report. */ + if (report_len == GEN5_RESP_LENGTH_SIZE) + return 0; + + ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, report_len); + if (ret != report_len) { + dev_err(dev, "failed to read %d bytes report data, (%d)\n", + report_len, ret); + return -EINVAL; + } + + report_id = report_data.report_head[GEN5_RESP_REPORT_ID_OFFSET]; + if (report_id == GEN5_WAKEUP_EVENT_REPORT_ID && + report_len == GEN5_WAKEUP_EVENT_SIZE) { + /* + * Device wake event from deep sleep mode for touch. + * This interrupt event is used to wake system up. + */ + return 0; + } else if (report_id != GEN5_TOUCH_REPORT_ID && + report_id != GEN5_BTN_REPORT_ID && + report_id != GEN5_OLD_PUSH_BTN_REPORT_ID && + report_id != GEN5_PUSH_BTN_REPORT_ID) { + /* Running in BL mode or unknown response data read. */ + dev_err(dev, "invalid report_id=0x%02x\n", report_id); + return -EINVAL; + } + + if (report_id == GEN5_TOUCH_REPORT_ID && + (report_len < GEN5_TOUCH_REPORT_HEAD_SIZE || + report_len > GEN5_TOUCH_REPORT_MAX_SIZE)) { + /* Invalid report data length for finger packet. */ + dev_err(dev, "invalid touch packet length=%d\n", report_len); + return 0; + } + + if ((report_id == GEN5_BTN_REPORT_ID || + report_id == GEN5_OLD_PUSH_BTN_REPORT_ID || + report_id == GEN5_PUSH_BTN_REPORT_ID) && + (report_len < GEN5_BTN_REPORT_HEAD_SIZE || + report_len > GEN5_BTN_REPORT_MAX_SIZE)) { + /* Invalid report data length of button packet. */ + dev_err(dev, "invalid button packet length=%d\n", report_len); + return 0; + } + + if (report_id == GEN5_TOUCH_REPORT_ID) + cyapa_gen5_report_touches(cyapa, &report_data); + else + cyapa_gen5_report_buttons(cyapa, &report_data); + + return 0; +} + +static int cyapa_gen5_bl_activate(struct cyapa *cyapa) { return 0; } +static int cyapa_gen5_bl_deactivate(struct cyapa *cyapa) { return 0; } + +const struct cyapa_dev_ops cyapa_gen5_ops = { + .check_fw = cyapa_gen5_check_fw, + .bl_enter = cyapa_gen5_bl_enter, + .bl_initiate = cyapa_gen5_bl_initiate, + .update_fw = cyapa_gen5_do_fw_update, + .bl_activate = cyapa_gen5_bl_activate, + .bl_deactivate = cyapa_gen5_bl_deactivate, + + .show_baseline = cyapa_gen5_show_baseline, + .calibrate_store = cyapa_gen5_do_calibrate, + + .initialize = cyapa_gen5_initialize, + + .state_parse = cyapa_gen5_state_parse, + .operational_check = cyapa_gen5_do_operational_check, + + .irq_handler = cyapa_gen5_irq_handler, + .irq_cmd_handler = cyapa_gen5_irq_cmd_handler, + .sort_empty_output_data = cyapa_empty_pip_output_data, + .set_power_mode = cyapa_gen5_set_power_mode, +}; diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c index 8af34ffe208b..9118a1861a45 100644 --- a/drivers/input/mouse/cypress_ps2.c +++ b/drivers/input/mouse/cypress_ps2.c @@ -538,7 +538,7 @@ static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt) pos[i].y = contact->y; } - input_mt_assign_slots(input, slots, pos, n); + input_mt_assign_slots(input, slots, pos, n, 0); for (i = 0; i < n; i++) { contact = &report_data.contacts[i]; diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index 2e838626205f..e100c1b31597 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h @@ -4,7 +4,6 @@ * Copyright (c) 2013 ELAN Microelectronics Corp. * * Author: 林政維 (Duson Lin) - * Version: 1.5.5 * * Based on cyapa driver: * copyright (c) 2011-2012 Cypress Semiconductor, Inc. @@ -33,8 +32,9 @@ #define ETP_FW_IAP_PAGE_ERR (1 << 5) #define ETP_FW_IAP_INTF_ERR (1 << 4) #define ETP_FW_PAGE_SIZE 64 -#define ETP_FW_PAGE_COUNT 768 -#define ETP_FW_SIZE (ETP_FW_PAGE_SIZE * ETP_FW_PAGE_COUNT) +#define ETP_FW_VAILDPAGE_COUNT 768 +#define ETP_FW_SIGNATURE_SIZE 6 +#define ETP_FW_SIGNATURE_ADDRESS 0xBFFA struct i2c_client; struct completion; diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 0cb2be48d537..7ce8bfe22d7e 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -4,7 +4,7 @@ * Copyright (c) 2013 ELAN Microelectronics Corp. * * Author: 林政維 (Duson Lin) - * Version: 1.5.5 + * Version: 1.5.6 * * Based on cyapa driver: * copyright (c) 2011-2012 Cypress Semiconductor, Inc. @@ -40,7 +40,7 @@ #include "elan_i2c.h" #define DRIVER_NAME "elan_i2c" -#define ELAN_DRIVER_VERSION "1.5.5" +#define ELAN_DRIVER_VERSION "1.5.6" #define ETP_PRESSURE_OFFSET 25 #define ETP_MAX_PRESSURE 255 #define ETP_FWIDTH_REDUCE 90 @@ -312,7 +312,7 @@ static int __elan_update_firmware(struct elan_tp_data *data, iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]); boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE; - for (i = boot_page_count; i < ETP_FW_PAGE_COUNT; i++) { + for (i = boot_page_count; i < ETP_FW_VAILDPAGE_COUNT; i++) { u16 checksum = 0; const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE]; @@ -434,10 +434,11 @@ static ssize_t elan_sysfs_update_fw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct elan_tp_data *data = i2c_get_clientdata(client); + struct elan_tp_data *data = dev_get_drvdata(dev); const struct firmware *fw; int error; + const u8 *fw_signature; + static const u8 signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF}; error = request_firmware(&fw, ETP_FW_NAME, dev); if (error) { @@ -446,10 +447,12 @@ static ssize_t elan_sysfs_update_fw(struct device *dev, return error; } - /* Firmware must be exactly PAGE_NUM * PAGE_SIZE bytes */ - if (fw->size != ETP_FW_SIZE) { - dev_err(dev, "invalid firmware size = %zu, expected %d.\n", - fw->size, ETP_FW_SIZE); + /* Firmware file must match signature data */ + fw_signature = &fw->data[ETP_FW_SIGNATURE_ADDRESS]; + if (memcmp(fw_signature, signature, sizeof(signature)) != 0) { + dev_err(dev, "signature mismatch (expected %*ph, got %*ph)\n", + (int)sizeof(signature), signature, + (int)sizeof(signature), fw_signature); error = -EBADF; goto out_release_fw; } diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index 97d4937fc244..029941f861af 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -4,7 +4,6 @@ * Copyright (c) 2013 ELAN Microelectronics Corp. * * Author: 林政維 (Duson Lin) - * Version: 1.5.5 * * Based on cyapa driver: * copyright (c) 2011-2012 Cypress Semiconductor, Inc. diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index 359bf8583d54..06a2bcd1cda2 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -4,7 +4,6 @@ * Copyright (c) 2013 ELAN Microelectronics Corp. * * Author: 林政維 (Duson Lin) - * Version: 1.5.5 * * Based on cyapa driver: * copyright (c) 2011-2012 Cypress Semiconductor, Inc. @@ -71,7 +70,7 @@ static int elan_smbus_initialize(struct i2c_client *client) /* compare hello packet */ if (memcmp(values, check, ETP_SMBUS_HELLOPACKET_LEN)) { - dev_err(&client->dev, "hello packet fail [%*px]\n", + dev_err(&client->dev, "hello packet fail [%*ph]\n", ETP_SMBUS_HELLOPACKET_LEN, values); return -ENXIO; } diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index f2b978026407..6e22682c8255 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1097,6 +1097,8 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse, * Asus UX31 0x361f00 20, 15, 0e clickpad * Asus UX32VD 0x361f02 00, 15, 0e clickpad * Avatar AVIU-145A2 0x361f00 ? clickpad + * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons + * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**) * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*) @@ -1475,6 +1477,20 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = { DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H730"), }, }, + { + /* Fujitsu LIFEBOOK E554 does not work with crc_enabled == 0 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E554"), + }, + }, + { + /* Fujitsu LIFEBOOK E544 does not work with crc_enabled == 0 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E544"), + }, + }, #endif { } }; @@ -1520,6 +1536,8 @@ static int elantech_set_properties(struct elantech_data *etd) case 7: case 8: case 9: + case 10: + case 13: etd->hw_version = 4; break; default: diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c index f4d657ee1cc0..fca38ba63bbe 100644 --- a/drivers/input/mouse/focaltech.c +++ b/drivers/input/mouse/focaltech.c @@ -2,6 +2,7 @@ * Focaltech TouchPad PS/2 mouse driver * * Copyright (c) 2014 Red Hat Inc. + * Copyright (c) 2014 Mathias Gottschlag * * 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 @@ -13,15 +14,14 @@ * Hans de Goede */ -/* - * The Focaltech PS/2 touchpad protocol is unknown. This drivers deals with - * detection only, to avoid further detection attempts confusing the touchpad - * this way it at least works in PS/2 mouse compatibility mode. - */ #include #include +#include +#include +#include #include "psmouse.h" +#include "focaltech.h" static const char * const focaltech_pnp_ids[] = { "FLT0101", @@ -30,6 +30,12 @@ static const char * const focaltech_pnp_ids[] = { NULL }; +/* + * Even if the kernel is built without support for Focaltech PS/2 touchpads (or + * when the real driver fails to recognize the device), we still have to detect + * them in order to avoid further detection attempts confusing the touchpad. + * This way it at least works in PS/2 mouse compatibility mode. + */ int focaltech_detect(struct psmouse *psmouse, bool set_properties) { if (!psmouse_matches_pnp_id(psmouse, focaltech_pnp_ids)) @@ -37,16 +43,404 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties) if (set_properties) { psmouse->vendor = "FocalTech"; - psmouse->name = "FocalTech Touchpad in mouse emulation mode"; + psmouse->name = "FocalTech Touchpad"; } return 0; } -int focaltech_init(struct psmouse *psmouse) +static void focaltech_reset(struct psmouse *psmouse) { ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); psmouse_reset(psmouse); +} + +#ifdef CONFIG_MOUSE_PS2_FOCALTECH + +/* + * Packet types - the numbers are not consecutive, so we might be missing + * something here. + */ +#define FOC_TOUCH 0x3 /* bitmap of active fingers */ +#define FOC_ABS 0x6 /* absolute position of one finger */ +#define FOC_REL 0x9 /* relative position of 1-2 fingers */ + +#define FOC_MAX_FINGERS 5 + +#define FOC_MAX_X 2431 +#define FOC_MAX_Y 1663 + +/* + * Current state of a single finger on the touchpad. + */ +struct focaltech_finger_state { + /* The touchpad has generated a touch event for the finger */ + bool active; + + /* + * The touchpad has sent position data for the finger. The + * flag is 0 when the finger is not active, and there is a + * time between the first touch event for the finger and the + * following absolute position packet for the finger where the + * touchpad has declared the finger to be valid, but we do not + * have any valid position yet. + */ + bool valid; + + /* + * Absolute position (from the bottom left corner) of the + * finger. + */ + unsigned int x; + unsigned int y; +}; + +/* + * Description of the current state of the touchpad hardware. + */ +struct focaltech_hw_state { + /* + * The touchpad tracks the positions of the fingers for us, + * the array indices correspond to the finger indices returned + * in the report packages. + */ + struct focaltech_finger_state fingers[FOC_MAX_FINGERS]; + + /* True if the clickpad has been pressed. */ + bool pressed; +}; + +struct focaltech_data { + unsigned int x_max, y_max; + struct focaltech_hw_state state; +}; + +static void focaltech_report_state(struct psmouse *psmouse) +{ + struct focaltech_data *priv = psmouse->private; + struct focaltech_hw_state *state = &priv->state; + struct input_dev *dev = psmouse->dev; + int i; + + for (i = 0; i < FOC_MAX_FINGERS; i++) { + struct focaltech_finger_state *finger = &state->fingers[i]; + bool active = finger->active && finger->valid; + + input_mt_slot(dev, i); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); + if (active) { + input_report_abs(dev, ABS_MT_POSITION_X, finger->x); + input_report_abs(dev, ABS_MT_POSITION_Y, + FOC_MAX_Y - finger->y); + } + } + input_mt_report_pointer_emulation(dev, true); + + input_report_key(psmouse->dev, BTN_LEFT, state->pressed); + input_sync(psmouse->dev); +} + +static void focaltech_process_touch_packet(struct psmouse *psmouse, + unsigned char *packet) +{ + struct focaltech_data *priv = psmouse->private; + struct focaltech_hw_state *state = &priv->state; + unsigned char fingers = packet[1]; + int i; + + state->pressed = (packet[0] >> 4) & 1; + + /* the second byte contains a bitmap of all fingers touching the pad */ + for (i = 0; i < FOC_MAX_FINGERS; i++) { + state->fingers[i].active = fingers & 0x1; + if (!state->fingers[i].active) { + /* + * Even when the finger becomes active again, we still + * will have to wait for the first valid position. + */ + state->fingers[i].valid = false; + } + fingers >>= 1; + } +} + +static void focaltech_process_abs_packet(struct psmouse *psmouse, + unsigned char *packet) +{ + struct focaltech_data *priv = psmouse->private; + struct focaltech_hw_state *state = &priv->state; + unsigned int finger; + + finger = (packet[1] >> 4) - 1; + if (finger >= FOC_MAX_FINGERS) { + psmouse_err(psmouse, "Invalid finger in abs packet: %d\n", + finger); + return; + } + + state->pressed = (packet[0] >> 4) & 1; + + /* + * packet[5] contains some kind of tool size in the most + * significant nibble. 0xff is a special value (latching) that + * signals a large contact area. + */ + if (packet[5] == 0xff) { + state->fingers[finger].valid = false; + return; + } + + state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2]; + state->fingers[finger].y = (packet[3] << 8) | packet[4]; + state->fingers[finger].valid = true; +} + +static void focaltech_process_rel_packet(struct psmouse *psmouse, + unsigned char *packet) +{ + struct focaltech_data *priv = psmouse->private; + struct focaltech_hw_state *state = &priv->state; + int finger1, finger2; + + state->pressed = packet[0] >> 7; + finger1 = ((packet[0] >> 4) & 0x7) - 1; + if (finger1 < FOC_MAX_FINGERS) { + state->fingers[finger1].x += (char)packet[1]; + state->fingers[finger1].y += (char)packet[2]; + } else { + psmouse_err(psmouse, "First finger in rel packet invalid: %d\n", + finger1); + } + + /* + * If there is an odd number of fingers, the last relative + * packet only contains one finger. In this case, the second + * finger index in the packet is 0 (we subtract 1 in the lines + * above to create array indices, so the finger will overflow + * and be above FOC_MAX_FINGERS). + */ + finger2 = ((packet[3] >> 4) & 0x7) - 1; + if (finger2 < FOC_MAX_FINGERS) { + state->fingers[finger2].x += (char)packet[4]; + state->fingers[finger2].y += (char)packet[5]; + } +} + +static void focaltech_process_packet(struct psmouse *psmouse) +{ + unsigned char *packet = psmouse->packet; + + switch (packet[0] & 0xf) { + case FOC_TOUCH: + focaltech_process_touch_packet(psmouse, packet); + break; + + case FOC_ABS: + focaltech_process_abs_packet(psmouse, packet); + break; + + case FOC_REL: + focaltech_process_rel_packet(psmouse, packet); + break; + + default: + psmouse_err(psmouse, "Unknown packet type: %02x\n", packet[0]); + break; + } + + focaltech_report_state(psmouse); +} + +static psmouse_ret_t focaltech_process_byte(struct psmouse *psmouse) +{ + if (psmouse->pktcnt >= 6) { /* Full packet received */ + focaltech_process_packet(psmouse); + return PSMOUSE_FULL_PACKET; + } + + /* + * We might want to do some validation of the data here, but + * we do not know the protocol well enough + */ + return PSMOUSE_GOOD_DATA; +} + +static int focaltech_switch_protocol(struct psmouse *psmouse) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[3]; + + param[0] = 0; + if (ps2_command(ps2dev, param, 0x10f8)) + return -EIO; + + if (ps2_command(ps2dev, param, 0x10f8)) + return -EIO; + + if (ps2_command(ps2dev, param, 0x10f8)) + return -EIO; + + param[0] = 1; + if (ps2_command(ps2dev, param, 0x10f8)) + return -EIO; + + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) + return -EIO; + + if (ps2_command(ps2dev, param, PSMOUSE_CMD_ENABLE)) + return -EIO; return 0; } + +static void focaltech_disconnect(struct psmouse *psmouse) +{ + focaltech_reset(psmouse); + kfree(psmouse->private); + psmouse->private = NULL; +} + +static int focaltech_reconnect(struct psmouse *psmouse) +{ + int error; + + focaltech_reset(psmouse); + + error = focaltech_switch_protocol(psmouse); + if (error) { + psmouse_err(psmouse, "Unable to initialize the device\n"); + return error; + } + + return 0; +} + +static void focaltech_set_input_params(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + struct focaltech_data *priv = psmouse->private; + + /* + * Undo part of setup done for us by psmouse core since touchpad + * is not a relative device. + */ + __clear_bit(EV_REL, dev->evbit); + __clear_bit(REL_X, dev->relbit); + __clear_bit(REL_Y, dev->relbit); + __clear_bit(BTN_RIGHT, dev->keybit); + __clear_bit(BTN_MIDDLE, dev->keybit); + + /* + * Now set up our capabilities. + */ + __set_bit(EV_ABS, dev->evbit); + input_set_abs_params(dev, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0); + input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0); + input_mt_init_slots(dev, 5, INPUT_MT_POINTER); + __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); +} + +static int focaltech_read_register(struct ps2dev *ps2dev, int reg, + unsigned char *param) +{ + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) + return -EIO; + + param[0] = 0; + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -EIO; + + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -EIO; + + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -EIO; + + param[0] = reg; + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) + return -EIO; + + if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) + return -EIO; + + return 0; +} + +static int focaltech_read_size(struct psmouse *psmouse) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + struct focaltech_data *priv = psmouse->private; + char param[3]; + + if (focaltech_read_register(ps2dev, 2, param)) + return -EIO; + + /* not sure whether this is 100% correct */ + priv->x_max = (unsigned char)param[1] * 128; + priv->y_max = (unsigned char)param[2] * 128; + + return 0; +} +int focaltech_init(struct psmouse *psmouse) +{ + struct focaltech_data *priv; + int error; + + psmouse->private = priv = kzalloc(sizeof(struct focaltech_data), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + focaltech_reset(psmouse); + + error = focaltech_read_size(psmouse); + if (error) { + psmouse_err(psmouse, + "Unable to read the size of the touchpad\n"); + goto fail; + } + + error = focaltech_switch_protocol(psmouse); + if (error) { + psmouse_err(psmouse, "Unable to initialize the device\n"); + goto fail; + } + + focaltech_set_input_params(psmouse); + + psmouse->protocol_handler = focaltech_process_byte; + psmouse->pktsize = 6; + psmouse->disconnect = focaltech_disconnect; + psmouse->reconnect = focaltech_reconnect; + psmouse->cleanup = focaltech_reset; + /* resync is not supported yet */ + psmouse->resync_time = 0; + + return 0; + +fail: + focaltech_reset(psmouse); + kfree(priv); + return error; +} + +bool focaltech_supported(void) +{ + return true; +} + +#else /* CONFIG_MOUSE_PS2_FOCALTECH */ + +int focaltech_init(struct psmouse *psmouse) +{ + focaltech_reset(psmouse); + + return 0; +} + +bool focaltech_supported(void) +{ + return false; +} + +#endif /* CONFIG_MOUSE_PS2_FOCALTECH */ diff --git a/drivers/input/mouse/focaltech.h b/drivers/input/mouse/focaltech.h index 498650c61e28..71870a9b548a 100644 --- a/drivers/input/mouse/focaltech.h +++ b/drivers/input/mouse/focaltech.h @@ -2,6 +2,7 @@ * Focaltech TouchPad PS/2 mouse driver * * Copyright (c) 2014 Red Hat Inc. + * Copyright (c) 2014 Mathias Gottschlag * * 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 @@ -18,5 +19,6 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties); int focaltech_init(struct psmouse *psmouse); +bool focaltech_supported(void); #endif diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 95a3a6e2faf6..68469feda470 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -725,16 +725,19 @@ static int psmouse_extensions(struct psmouse *psmouse, /* Always check for focaltech, this is safe as it uses pnp-id matching */ if (psmouse_do_detect(focaltech_detect, psmouse, set_properties) == 0) { - if (!set_properties || focaltech_init(psmouse) == 0) { - /* - * Not supported yet, use bare protocol. - * Note that we need to also restrict - * psmouse_max_proto so that psmouse_initialize() - * does not try to reset rate and resolution, - * because even that upsets the device. - */ - psmouse_max_proto = PSMOUSE_PS2; - return PSMOUSE_PS2; + if (max_proto > PSMOUSE_IMEX) { + if (!set_properties || focaltech_init(psmouse) == 0) { + if (focaltech_supported()) + return PSMOUSE_FOCALTECH; + /* + * Note that we need to also restrict + * psmouse_max_proto so that psmouse_initialize() + * does not try to reset rate and resolution, + * because even that upsets the device. + */ + psmouse_max_proto = PSMOUSE_PS2; + return PSMOUSE_PS2; + } } } @@ -1063,6 +1066,15 @@ static const struct psmouse_protocol psmouse_protocols[] = { .alias = "cortps", .detect = cortron_detect, }, +#ifdef CONFIG_MOUSE_PS2_FOCALTECH + { + .type = PSMOUSE_FOCALTECH, + .name = "FocalTechPS/2", + .alias = "focaltech", + .detect = focaltech_detect, + .init = focaltech_init, + }, +#endif { .type = PSMOUSE_AUTO, .name = "auto", diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index f4cf664c7db3..c2ff137ecbdb 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -96,6 +96,7 @@ enum psmouse_type { PSMOUSE_FSP, PSMOUSE_SYNAPTICS_RELATIVE, PSMOUSE_CYPRESS, + PSMOUSE_FOCALTECH, PSMOUSE_AUTO /* This one should always be last */ }; diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index f9472920d986..7e705ee90b86 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -67,6 +67,9 @@ #define X_MAX_POSITIVE 8176 #define Y_MAX_POSITIVE 8176 +/* maximum ABS_MT_POSITION displacement (in mm) */ +#define DMAX 10 + /***************************************************************************** * Stuff we need even when we do not want native Synaptics support ****************************************************************************/ @@ -135,8 +138,9 @@ static const struct min_max_quirk min_max_pnpid_table[] = { 1232, 5710, 1156, 4696 }, { - (const char * const []){"LEN0034", "LEN0036", "LEN0039", - "LEN2002", "LEN2004", NULL}, + (const char * const []){"LEN0034", "LEN0036", "LEN0037", + "LEN0039", "LEN2002", "LEN2004", + NULL}, 1024, 5112, 2024, 4832 }, { @@ -165,7 +169,7 @@ static const char * const topbuttonpad_pnp_ids[] = { "LEN0034", /* T431s, L440, L540, T540, W540, X1 Carbon 2nd */ "LEN0035", /* X240 */ "LEN0036", /* T440 */ - "LEN0037", + "LEN0037", /* X1 Carbon 2nd */ "LEN0038", "LEN0039", /* T440s */ "LEN0041", @@ -574,14 +578,6 @@ static void synaptics_pt_create(struct psmouse *psmouse) * Functions to interpret the absolute mode packets ****************************************************************************/ -static void synaptics_mt_state_set(struct synaptics_mt_state *state, int count, - int sgm, int agm) -{ - state->count = count; - state->sgm = sgm; - state->agm = agm; -} - static void synaptics_parse_agm(const unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) @@ -600,16 +596,13 @@ static void synaptics_parse_agm(const unsigned char buf[], break; case 2: - /* AGM-CONTACT packet: (count, sgm, agm) */ - synaptics_mt_state_set(&agm->mt_state, buf[1], buf[2], buf[4]); + /* AGM-CONTACT packet: we are only interested in the count */ + priv->agm_count = buf[1]; break; default: break; } - - /* Record that at least one AGM has been received since last SGM */ - priv->agm_pending = true; } static bool is_forcepad; @@ -803,397 +796,13 @@ static void synaptics_report_buttons(struct psmouse *psmouse, input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i)); } -static void synaptics_report_slot(struct input_dev *dev, int slot, - const struct synaptics_hw_state *hw) -{ - input_mt_slot(dev, slot); - input_mt_report_slot_state(dev, MT_TOOL_FINGER, (hw != NULL)); - if (!hw) - return; - - input_report_abs(dev, ABS_MT_POSITION_X, hw->x); - input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(hw->y)); - input_report_abs(dev, ABS_MT_PRESSURE, hw->z); -} - static void synaptics_report_mt_data(struct psmouse *psmouse, - struct synaptics_mt_state *mt_state, - const struct synaptics_hw_state *sgm) + const struct synaptics_hw_state *sgm, + int num_fingers) { struct input_dev *dev = psmouse->dev; struct synaptics_data *priv = psmouse->private; - struct synaptics_hw_state *agm = &priv->agm; - struct synaptics_mt_state *old = &priv->mt_state; - - switch (mt_state->count) { - case 0: - synaptics_report_slot(dev, 0, NULL); - synaptics_report_slot(dev, 1, NULL); - break; - case 1: - if (mt_state->sgm == -1) { - synaptics_report_slot(dev, 0, NULL); - synaptics_report_slot(dev, 1, NULL); - } else if (mt_state->sgm == 0) { - synaptics_report_slot(dev, 0, sgm); - synaptics_report_slot(dev, 1, NULL); - } else { - synaptics_report_slot(dev, 0, NULL); - synaptics_report_slot(dev, 1, sgm); - } - break; - default: - /* - * If the finger slot contained in SGM is valid, and either - * hasn't changed, or is new, or the old SGM has now moved to - * AGM, then report SGM in MTB slot 0. - * Otherwise, empty MTB slot 0. - */ - if (mt_state->sgm != -1 && - (mt_state->sgm == old->sgm || - old->sgm == -1 || mt_state->agm == old->sgm)) - synaptics_report_slot(dev, 0, sgm); - else - synaptics_report_slot(dev, 0, NULL); - - /* - * If the finger slot contained in AGM is valid, and either - * hasn't changed, or is new, then report AGM in MTB slot 1. - * Otherwise, empty MTB slot 1. - * - * However, in the case where the AGM is new, make sure that - * that it is either the same as the old SGM, or there was no - * SGM. - * - * Otherwise, if the SGM was just 1, and the new AGM is 2, then - * the new AGM will keep the old SGM's tracking ID, which can - * cause apparent drumroll. This happens if in the following - * valid finger sequence: - * - * Action SGM AGM (MTB slot:Contact) - * 1. Touch contact 0 (0:0) - * 2. Touch contact 1 (0:0, 1:1) - * 3. Lift contact 0 (1:1) - * 4. Touch contacts 2,3 (0:2, 1:3) - * - * In step 4, contact 3, in AGM must not be given the same - * tracking ID as contact 1 had in step 3. To avoid this, - * the first agm with contact 3 is dropped and slot 1 is - * invalidated (tracking ID = -1). - */ - if (mt_state->agm != -1 && - (mt_state->agm == old->agm || - (old->agm == -1 && - (old->sgm == -1 || mt_state->agm == old->sgm)))) - synaptics_report_slot(dev, 1, agm); - else - synaptics_report_slot(dev, 1, NULL); - break; - } - - /* Don't use active slot count to generate BTN_TOOL events. */ - input_mt_report_pointer_emulation(dev, false); - - /* Send the number of fingers reported by touchpad itself. */ - input_mt_report_finger_count(dev, mt_state->count); - - synaptics_report_buttons(psmouse, sgm); - - input_sync(dev); -} - -/* Handle case where mt_state->count = 0 */ -static void synaptics_image_sensor_0f(struct synaptics_data *priv, - struct synaptics_mt_state *mt_state) -{ - synaptics_mt_state_set(mt_state, 0, -1, -1); - priv->mt_state_lost = false; -} - -/* Handle case where mt_state->count = 1 */ -static void synaptics_image_sensor_1f(struct synaptics_data *priv, - struct synaptics_mt_state *mt_state) -{ - struct synaptics_hw_state *agm = &priv->agm; - struct synaptics_mt_state *old = &priv->mt_state; - - /* - * If the last AGM was (0,0,0), and there is only one finger left, - * then we absolutely know that SGM contains slot 0, and all other - * fingers have been removed. - */ - if (priv->agm_pending && agm->z == 0) { - synaptics_mt_state_set(mt_state, 1, 0, -1); - priv->mt_state_lost = false; - return; - } - - switch (old->count) { - case 0: - synaptics_mt_state_set(mt_state, 1, 0, -1); - break; - case 1: - /* - * If mt_state_lost, then the previous transition was 3->1, - * and SGM now contains either slot 0 or 1, but we don't know - * which. So, we just assume that the SGM now contains slot 1. - * - * If pending AGM and either: - * (a) the previous SGM slot contains slot 0, or - * (b) there was no SGM slot - * then, the SGM now contains slot 1 - * - * Case (a) happens with very rapid "drum roll" gestures, where - * slot 0 finger is lifted and a new slot 1 finger touches - * within one reporting interval. - * - * Case (b) happens if initially two or more fingers tap - * briefly, and all but one lift before the end of the first - * reporting interval. - * - * (In both these cases, slot 0 will becomes empty, so SGM - * contains slot 1 with the new finger) - * - * Else, if there was no previous SGM, it now contains slot 0. - * - * Otherwise, SGM still contains the same slot. - */ - if (priv->mt_state_lost || - (priv->agm_pending && old->sgm <= 0)) - synaptics_mt_state_set(mt_state, 1, 1, -1); - else if (old->sgm == -1) - synaptics_mt_state_set(mt_state, 1, 0, -1); - break; - case 2: - /* - * If mt_state_lost, we don't know which finger SGM contains. - * - * So, report 1 finger, but with both slots empty. - * We will use slot 1 on subsequent 1->1 - */ - if (priv->mt_state_lost) { - synaptics_mt_state_set(mt_state, 1, -1, -1); - break; - } - /* - * Since the last AGM was NOT (0,0,0), it was the finger in - * slot 0 that has been removed. - * So, SGM now contains previous AGM's slot, and AGM is now - * empty. - */ - synaptics_mt_state_set(mt_state, 1, old->agm, -1); - break; - case 3: - /* - * Since last AGM was not (0,0,0), we don't know which finger - * is left. - * - * So, report 1 finger, but with both slots empty. - * We will use slot 1 on subsequent 1->1 - */ - synaptics_mt_state_set(mt_state, 1, -1, -1); - priv->mt_state_lost = true; - break; - case 4: - case 5: - /* mt_state was updated by AGM-CONTACT packet */ - break; - } -} - -/* Handle case where mt_state->count = 2 */ -static void synaptics_image_sensor_2f(struct synaptics_data *priv, - struct synaptics_mt_state *mt_state) -{ - struct synaptics_mt_state *old = &priv->mt_state; - - switch (old->count) { - case 0: - synaptics_mt_state_set(mt_state, 2, 0, 1); - break; - case 1: - /* - * If previous SGM contained slot 1 or higher, SGM now contains - * slot 0 (the newly touching finger) and AGM contains SGM's - * previous slot. - * - * Otherwise, SGM still contains slot 0 and AGM now contains - * slot 1. - */ - if (old->sgm >= 1) - synaptics_mt_state_set(mt_state, 2, 0, old->sgm); - else - synaptics_mt_state_set(mt_state, 2, 0, 1); - break; - case 2: - /* - * If mt_state_lost, SGM now contains either finger 1 or 2, but - * we don't know which. - * So, we just assume that the SGM contains slot 0 and AGM 1. - */ - if (priv->mt_state_lost) - synaptics_mt_state_set(mt_state, 2, 0, 1); - /* - * Otherwise, use the same mt_state, since it either hasn't - * changed, or was updated by a recently received AGM-CONTACT - * packet. - */ - break; - case 3: - /* - * 3->2 transitions have two unsolvable problems: - * 1) no indication is given which finger was removed - * 2) no way to tell if agm packet was for finger 3 - * before 3->2, or finger 2 after 3->2. - * - * So, report 2 fingers, but empty all slots. - * We will guess slots [0,1] on subsequent 2->2. - */ - synaptics_mt_state_set(mt_state, 2, -1, -1); - priv->mt_state_lost = true; - break; - case 4: - case 5: - /* mt_state was updated by AGM-CONTACT packet */ - break; - } -} - -/* Handle case where mt_state->count = 3 */ -static void synaptics_image_sensor_3f(struct synaptics_data *priv, - struct synaptics_mt_state *mt_state) -{ - struct synaptics_mt_state *old = &priv->mt_state; - - switch (old->count) { - case 0: - synaptics_mt_state_set(mt_state, 3, 0, 2); - break; - case 1: - /* - * If previous SGM contained slot 2 or higher, SGM now contains - * slot 0 (one of the newly touching fingers) and AGM contains - * SGM's previous slot. - * - * Otherwise, SGM now contains slot 0 and AGM contains slot 2. - */ - if (old->sgm >= 2) - synaptics_mt_state_set(mt_state, 3, 0, old->sgm); - else - synaptics_mt_state_set(mt_state, 3, 0, 2); - break; - case 2: - /* - * If the AGM previously contained slot 3 or higher, then the - * newly touching finger is in the lowest available slot. - * - * If SGM was previously 1 or higher, then the new SGM is - * now slot 0 (with a new finger), otherwise, the new finger - * is now in a hidden slot between 0 and AGM's slot. - * - * In all such cases, the SGM now contains slot 0, and the AGM - * continues to contain the same slot as before. - */ - if (old->agm >= 3) { - synaptics_mt_state_set(mt_state, 3, 0, old->agm); - break; - } - - /* - * After some 3->1 and all 3->2 transitions, we lose track - * of which slot is reported by SGM and AGM. - * - * For 2->3 in this state, report 3 fingers, but empty all - * slots, and we will guess (0,2) on a subsequent 0->3. - * - * To userspace, the resulting transition will look like: - * 2:[0,1] -> 3:[-1,-1] -> 3:[0,2] - */ - if (priv->mt_state_lost) { - synaptics_mt_state_set(mt_state, 3, -1, -1); - break; - } - - /* - * If the (SGM,AGM) really previously contained slots (0, 1), - * then we cannot know what slot was just reported by the AGM, - * because the 2->3 transition can occur either before or after - * the AGM packet. Thus, this most recent AGM could contain - * either the same old slot 1 or the new slot 2. - * Subsequent AGMs will be reporting slot 2. - * - * To userspace, the resulting transition will look like: - * 2:[0,1] -> 3:[0,-1] -> 3:[0,2] - */ - synaptics_mt_state_set(mt_state, 3, 0, -1); - break; - case 3: - /* - * If, for whatever reason, the previous agm was invalid, - * Assume SGM now contains slot 0, AGM now contains slot 2. - */ - if (old->agm <= 2) - synaptics_mt_state_set(mt_state, 3, 0, 2); - /* - * mt_state either hasn't changed, or was updated by a recently - * received AGM-CONTACT packet. - */ - break; - - case 4: - case 5: - /* mt_state was updated by AGM-CONTACT packet */ - break; - } -} - -/* Handle case where mt_state->count = 4, or = 5 */ -static void synaptics_image_sensor_45f(struct synaptics_data *priv, - struct synaptics_mt_state *mt_state) -{ - /* mt_state was updated correctly by AGM-CONTACT packet */ - priv->mt_state_lost = false; -} - -static void synaptics_image_sensor_process(struct psmouse *psmouse, - struct synaptics_hw_state *sgm) -{ - struct synaptics_data *priv = psmouse->private; - struct synaptics_hw_state *agm = &priv->agm; - struct synaptics_mt_state mt_state; - - /* Initialize using current mt_state (as updated by last agm) */ - mt_state = agm->mt_state; - - /* - * Update mt_state using the new finger count and current mt_state. - */ - if (sgm->z == 0) - synaptics_image_sensor_0f(priv, &mt_state); - else if (sgm->w >= 4) - synaptics_image_sensor_1f(priv, &mt_state); - else if (sgm->w == 0) - synaptics_image_sensor_2f(priv, &mt_state); - else if (sgm->w == 1 && mt_state.count <= 3) - synaptics_image_sensor_3f(priv, &mt_state); - else - synaptics_image_sensor_45f(priv, &mt_state); - - /* Send resulting input events to user space */ - synaptics_report_mt_data(psmouse, &mt_state, sgm); - - /* Store updated mt_state */ - priv->mt_state = agm->mt_state = mt_state; - priv->agm_pending = false; -} - -static void synaptics_profile_sensor_process(struct psmouse *psmouse, - struct synaptics_hw_state *sgm, - int num_fingers) -{ - struct input_dev *dev = psmouse->dev; - struct synaptics_data *priv = psmouse->private; - struct synaptics_hw_state *hw[2] = { sgm, &priv->agm }; + const struct synaptics_hw_state *hw[2] = { sgm, &priv->agm }; struct input_mt_pos pos[2]; int slot[2], nsemi, i; @@ -1204,7 +813,7 @@ static void synaptics_profile_sensor_process(struct psmouse *psmouse, pos[i].y = synaptics_invert_y(hw[i]->y); } - input_mt_assign_slots(dev, slot, pos, nsemi); + input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->x_res); for (i = 0; i < nsemi; i++) { input_mt_slot(dev, slot[i]); @@ -1215,7 +824,11 @@ static void synaptics_profile_sensor_process(struct psmouse *psmouse, } input_mt_drop_unused(dev); + + /* Don't use active slot count to generate BTN_TOOL events. */ input_mt_report_pointer_emulation(dev, false); + + /* Send the number of fingers reported by touchpad itself. */ input_mt_report_finger_count(dev, num_fingers); synaptics_report_buttons(psmouse, sgm); @@ -1223,6 +836,30 @@ static void synaptics_profile_sensor_process(struct psmouse *psmouse, input_sync(dev); } +static void synaptics_image_sensor_process(struct psmouse *psmouse, + struct synaptics_hw_state *sgm) +{ + struct synaptics_data *priv = psmouse->private; + int num_fingers; + + /* + * Update mt_state using the new finger count and current mt_state. + */ + if (sgm->z == 0) + num_fingers = 0; + else if (sgm->w >= 4) + num_fingers = 1; + else if (sgm->w == 0) + num_fingers = 2; + else if (sgm->w == 1) + num_fingers = priv->agm_count ? priv->agm_count : 3; + else + num_fingers = 4; + + /* Send resulting input events to user space */ + synaptics_report_mt_data(psmouse, sgm, num_fingers); +} + /* * called for each full received packet from the touchpad */ @@ -1287,7 +924,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) } if (cr48_profile_sensor) { - synaptics_profile_sensor_process(psmouse, &hw, num_fingers); + synaptics_report_mt_data(psmouse, &hw, num_fingers); return; } @@ -1444,7 +1081,7 @@ static void set_input_params(struct psmouse *psmouse, ABS_MT_POSITION_Y); /* Image sensors can report per-contact pressure */ input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); - input_mt_init_slots(dev, 2, INPUT_MT_POINTER); + input_mt_init_slots(dev, 2, INPUT_MT_POINTER | INPUT_MT_TRACK); /* Image sensors can signal 4 and 5 finger clicks */ __set_bit(BTN_TOOL_QUADTAP, dev->keybit); diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 1bd01f21783b..6faf9bb7c117 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -118,16 +118,6 @@ /* amount to fuzz position data when touchpad reports reduced filtering */ #define SYN_REDUCED_FILTER_FUZZ 8 -/* - * A structure to describe which internal touchpad finger slots are being - * reported in raw packets. - */ -struct synaptics_mt_state { - int count; /* num fingers being tracked */ - int sgm; /* which slot is reported by sgm pkt */ - int agm; /* which slot is reported by agm pkt*/ -}; - /* * A structure to describe the state of the touchpad hardware (buttons and pad) */ @@ -143,9 +133,6 @@ struct synaptics_hw_state { unsigned int down:1; unsigned char ext_buttons; signed char scroll; - - /* As reported in last AGM-CONTACT packets */ - struct synaptics_mt_state mt_state; }; struct synaptics_data { @@ -170,15 +157,12 @@ struct synaptics_data { struct serio *pt_port; /* Pass-through serio port */ - struct synaptics_mt_state mt_state; /* Current mt finger state */ - bool mt_state_lost; /* mt_state may be incorrect */ - /* * Last received Advanced Gesture Mode (AGM) packet. An AGM packet * contains position data for a second contact, at half resolution. */ struct synaptics_hw_state agm; - bool agm_pending; /* new AGM packet received */ + unsigned int agm_count; /* finger count reported by agm */ /* ForcePad handling */ unsigned long press_start; diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index bc2d47431bdc..77833d7a004b 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -281,4 +281,14 @@ config HYPERV_KEYBOARD To compile this driver as a module, choose M here: the module will be called hyperv_keyboard. +config SERIO_SUN4I_PS2 + tristate "Allwinner A10 PS/2 controller support" + depends on ARCH_SUNXI || COMPILE_TEST + help + This selects support for the PS/2 Host Controller on + Allwinner A10. + + To compile this driver as a module, choose M here: the + module will be called sun4i-ps2. + endif diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index 815d874fe724..c600089b7a34 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o obj-$(CONFIG_SERIO_APBPS2) += apbps2.o obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o obj-$(CONFIG_HYPERV_KEYBOARD) += hyperv-keyboard.o +obj-$(CONFIG_SERIO_SUN4I_PS2) += sun4i-ps2.o diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 8d9ba0c3827c..94ab494a6ade 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -40,7 +40,6 @@ MODULE_AUTHOR("Laurent Canet , Thibaut Varene , Helge Deller "); MODULE_DESCRIPTION("HP GSC PS2 port driver"); MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl); #define PFX "gscps2.c: " @@ -439,6 +438,7 @@ static struct parisc_device_id gscps2_device_tbl[] = { #endif { 0, } /* 0 terminated list */ }; +MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl); static struct parisc_driver parisc_ps2_driver = { .name = "gsc_ps2", diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index c66d1b53843e..c11556563ef0 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -151,6 +151,14 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "5a"), }, }, + { + /* Medion Akoya E7225 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Medion"), + DMI_MATCH(DMI_PRODUCT_NAME, "Akoya E7225"), + DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"), + }, + }, { /* Blue FB5601 */ .matches = { @@ -414,6 +422,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710"), }, }, + { + /* Acer Aspire 7738 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7738"), + }, + }, { /* Gericom Bellagio */ .matches = { @@ -745,6 +760,35 @@ static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = { { } }; +/* + * Some laptops need keyboard reset before probing for the trackpad to get + * it detected, initialised & finally work. + */ +static const struct dmi_system_id __initconst i8042_dmi_kbdreset_table[] = { + { + /* Gigabyte P35 v2 - Elantech touchpad */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), + DMI_MATCH(DMI_PRODUCT_NAME, "P35V2"), + }, + }, + { + /* Aorus branded Gigabyte X3 Plus - Elantech touchpad */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), + DMI_MATCH(DMI_PRODUCT_NAME, "X3"), + }, + }, + { + /* Gigabyte P34 - Elantech touchpad */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), + DMI_MATCH(DMI_PRODUCT_NAME, "P34"), + }, + }, + { } +}; + #endif /* CONFIG_X86 */ #ifdef CONFIG_PNP @@ -1040,6 +1084,9 @@ static int __init i8042_platform_init(void) if (dmi_check_system(i8042_dmi_dritek_table)) i8042_dritek = true; + if (dmi_check_system(i8042_dmi_kbdreset_table)) + i8042_kbdreset = true; + /* * A20 was already enabled during early kernel init. But some buggy * BIOSes (in MSI Laptops) require A20 to be enabled using 8042 to diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 924e4bf357fb..986a71c614b0 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -67,6 +67,10 @@ static bool i8042_notimeout; module_param_named(notimeout, i8042_notimeout, bool, 0); MODULE_PARM_DESC(notimeout, "Ignore timeouts signalled by i8042"); +static bool i8042_kbdreset; +module_param_named(kbdreset, i8042_kbdreset, bool, 0); +MODULE_PARM_DESC(kbdreset, "Reset device connected to KBD port"); + #ifdef CONFIG_X86 static bool i8042_dritek; module_param_named(dritek, i8042_dritek, bool, 0); @@ -789,6 +793,16 @@ static int __init i8042_check_aux(void) if (i8042_toggle_aux(true)) return -1; +/* + * Reset keyboard (needed on some laptops to successfully detect + * touchpad, e.g., some Gigabyte laptop models with Elantech + * touchpads). + */ + if (i8042_kbdreset) { + pr_warn("Attempting to reset device connected to KBD port\n"); + i8042_kbd_write(NULL, (unsigned char) 0xff); + } + /* * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and * used it for a PCI card or somethig else. diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c new file mode 100644 index 000000000000..04b96fe39339 --- /dev/null +++ b/drivers/input/serio/sun4i-ps2.c @@ -0,0 +1,340 @@ +/* + * Driver for Allwinner A10 PS2 host controller + * + * Author: Vishnu Patekar + * Aaron.maoye + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "sun4i-ps2" + +/* register offset definitions */ +#define PS2_REG_GCTL 0x00 /* PS2 Module Global Control Reg */ +#define PS2_REG_DATA 0x04 /* PS2 Module Data Reg */ +#define PS2_REG_LCTL 0x08 /* PS2 Module Line Control Reg */ +#define PS2_REG_LSTS 0x0C /* PS2 Module Line Status Reg */ +#define PS2_REG_FCTL 0x10 /* PS2 Module FIFO Control Reg */ +#define PS2_REG_FSTS 0x14 /* PS2 Module FIFO Status Reg */ +#define PS2_REG_CLKDR 0x18 /* PS2 Module Clock Divider Reg*/ + +/* PS2 GLOBAL CONTROL REGISTER PS2_GCTL */ +#define PS2_GCTL_INTFLAG BIT(4) +#define PS2_GCTL_INTEN BIT(3) +#define PS2_GCTL_RESET BIT(2) +#define PS2_GCTL_MASTER BIT(1) +#define PS2_GCTL_BUSEN BIT(0) + +/* PS2 LINE CONTROL REGISTER */ +#define PS2_LCTL_NOACK BIT(18) +#define PS2_LCTL_TXDTOEN BIT(8) +#define PS2_LCTL_STOPERREN BIT(3) +#define PS2_LCTL_ACKERREN BIT(2) +#define PS2_LCTL_PARERREN BIT(1) +#define PS2_LCTL_RXDTOEN BIT(0) + +/* PS2 LINE STATUS REGISTER */ +#define PS2_LSTS_TXTDO BIT(8) +#define PS2_LSTS_STOPERR BIT(3) +#define PS2_LSTS_ACKERR BIT(2) +#define PS2_LSTS_PARERR BIT(1) +#define PS2_LSTS_RXTDO BIT(0) + +#define PS2_LINE_ERROR_BIT \ + (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \ + PS2_LSTS_PARERR | PS2_LSTS_RXTDO) + +/* PS2 FIFO CONTROL REGISTER */ +#define PS2_FCTL_TXRST BIT(17) +#define PS2_FCTL_RXRST BIT(16) +#define PS2_FCTL_TXUFIEN BIT(10) +#define PS2_FCTL_TXOFIEN BIT(9) +#define PS2_FCTL_TXRDYIEN BIT(8) +#define PS2_FCTL_RXUFIEN BIT(2) +#define PS2_FCTL_RXOFIEN BIT(1) +#define PS2_FCTL_RXRDYIEN BIT(0) + +/* PS2 FIFO STATUS REGISTER */ +#define PS2_FSTS_TXUF BIT(10) +#define PS2_FSTS_TXOF BIT(9) +#define PS2_FSTS_TXRDY BIT(8) +#define PS2_FSTS_RXUF BIT(2) +#define PS2_FSTS_RXOF BIT(1) +#define PS2_FSTS_RXRDY BIT(0) + +#define PS2_FIFO_ERROR_BIT \ + (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF) + +#define PS2_SAMPLE_CLK 1000000 +#define PS2_SCLK 125000 + +struct sun4i_ps2data { + struct serio *serio; + struct device *dev; + + /* IO mapping base */ + void __iomem *reg_base; + + /* clock management */ + struct clk *clk; + + /* irq */ + spinlock_t lock; + int irq; +}; + +static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id) +{ + struct sun4i_ps2data *drvdata = dev_id; + u32 intr_status; + u32 fifo_status; + unsigned char byte; + unsigned int rxflags = 0; + u32 rval; + + spin_lock(&drvdata->lock); + + /* Get the PS/2 interrupts and clear them */ + intr_status = readl(drvdata->reg_base + PS2_REG_LSTS); + fifo_status = readl(drvdata->reg_base + PS2_REG_FSTS); + + /* Check line status register */ + if (intr_status & PS2_LINE_ERROR_BIT) { + rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0; + rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0; + rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0; + + rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | + PS2_LSTS_PARERR | PS2_LSTS_RXTDO; + writel(rval, drvdata->reg_base + PS2_REG_LSTS); + } + + /* Check FIFO status register */ + if (fifo_status & PS2_FIFO_ERROR_BIT) { + rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY | + PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY; + writel(rval, drvdata->reg_base + PS2_REG_FSTS); + } + + rval = (fifo_status >> 16) & 0x3; + while (rval--) { + byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff; + serio_interrupt(drvdata->serio, byte, rxflags); + } + + writel(intr_status, drvdata->reg_base + PS2_REG_LSTS); + writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS); + + spin_unlock(&drvdata->lock); + + return IRQ_HANDLED; +} + +static int sun4i_ps2_open(struct serio *serio) +{ + struct sun4i_ps2data *drvdata = serio->port_data; + u32 src_clk = 0; + u32 clk_scdf; + u32 clk_pcdf; + u32 rval; + unsigned long flags; + + /* Set line control and enable interrupt */ + rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN + | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN; + writel(rval, drvdata->reg_base + PS2_REG_LCTL); + + /* Reset FIFO */ + rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN + | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN + | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN; + + writel(rval, drvdata->reg_base + PS2_REG_FCTL); + + src_clk = clk_get_rate(drvdata->clk); + /* Set clock divider register */ + clk_scdf = src_clk / PS2_SAMPLE_CLK - 1; + clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1; + rval = (clk_scdf << 8) | clk_pcdf; + writel(rval, drvdata->reg_base + PS2_REG_CLKDR); + + /* Set global control register */ + rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER + | PS2_GCTL_BUSEN; + + spin_lock_irqsave(&drvdata->lock, flags); + writel(rval, drvdata->reg_base + PS2_REG_GCTL); + spin_unlock_irqrestore(&drvdata->lock, flags); + + return 0; +} + +static void sun4i_ps2_close(struct serio *serio) +{ + struct sun4i_ps2data *drvdata = serio->port_data; + u32 rval; + + /* Shut off the interrupt */ + rval = readl(drvdata->reg_base + PS2_REG_GCTL); + writel(rval & ~(PS2_GCTL_INTEN), drvdata->reg_base + PS2_REG_GCTL); + + synchronize_irq(drvdata->irq); +} + +static int sun4i_ps2_write(struct serio *serio, unsigned char val) +{ + unsigned long expire = jiffies + msecs_to_jiffies(10000); + struct sun4i_ps2data *drvdata = serio->port_data; + + do { + if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) { + writel(val, drvdata->reg_base + PS2_REG_DATA); + return 0; + } + } while (time_before(jiffies, expire)); + + return SERIO_TIMEOUT; +} + +static int sun4i_ps2_probe(struct platform_device *pdev) +{ + struct resource *res; /* IO mem resources */ + struct sun4i_ps2data *drvdata; + struct serio *serio; + struct device *dev = &pdev->dev; + unsigned int irq; + int error; + + drvdata = kzalloc(sizeof(struct sun4i_ps2data), GFP_KERNEL); + serio = kzalloc(sizeof(struct serio), GFP_KERNEL); + if (!drvdata || !serio) { + error = -ENOMEM; + goto err_free_mem; + } + + spin_lock_init(&drvdata->lock); + + /* IO */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "failed to locate registers\n"); + error = -ENXIO; + goto err_free_mem; + } + + drvdata->reg_base = ioremap(res->start, resource_size(res)); + if (!drvdata->reg_base) { + dev_err(dev, "failed to map registers\n"); + error = -ENOMEM; + goto err_free_mem; + } + + drvdata->clk = clk_get(dev, NULL); + if (IS_ERR(drvdata->clk)) { + error = PTR_ERR(drvdata->clk); + dev_err(dev, "couldn't get clock %d\n", error); + goto err_ioremap; + } + + error = clk_prepare_enable(drvdata->clk); + if (error) { + dev_err(dev, "failed to enable clock %d\n", error); + goto err_clk; + } + + serio->id.type = SERIO_8042; + serio->write = sun4i_ps2_write; + serio->open = sun4i_ps2_open; + serio->close = sun4i_ps2_close; + serio->port_data = drvdata; + serio->dev.parent = dev; + strlcpy(serio->name, dev_name(dev), sizeof(serio->name)); + strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys)); + + /* shutoff interrupt */ + writel(0, drvdata->reg_base + PS2_REG_GCTL); + + /* Get IRQ for the device */ + irq = platform_get_irq(pdev, 0); + if (!irq) { + dev_err(dev, "no IRQ found\n"); + error = -ENXIO; + goto err_disable_clk; + } + + drvdata->irq = irq; + drvdata->serio = serio; + drvdata->dev = dev; + + error = request_irq(drvdata->irq, sun4i_ps2_interrupt, 0, + DRIVER_NAME, drvdata); + if (error) { + dev_err(drvdata->dev, "failed to allocate interrupt %d: %d\n", + drvdata->irq, error); + goto err_disable_clk; + } + + serio_register_port(serio); + platform_set_drvdata(pdev, drvdata); + + return 0; /* success */ + +err_disable_clk: + clk_disable_unprepare(drvdata->clk); +err_clk: + clk_put(drvdata->clk); +err_ioremap: + iounmap(drvdata->reg_base); +err_free_mem: + kfree(serio); + kfree(drvdata); + return error; +} + +static int sun4i_ps2_remove(struct platform_device *pdev) +{ + struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev); + + serio_unregister_port(drvdata->serio); + + free_irq(drvdata->irq, drvdata); + + clk_disable_unprepare(drvdata->clk); + clk_put(drvdata->clk); + + iounmap(drvdata->reg_base); + + kfree(drvdata); + + return 0; +} + +static const struct of_device_id sun4i_ps2_match[] = { + { .compatible = "allwinner,sun4i-a10-ps2", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, sun4i_ps2_match); + +static struct platform_driver sun4i_ps2_driver = { + .probe = sun4i_ps2_probe, + .remove = sun4i_ps2_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = sun4i_ps2_match, + }, +}; +module_platform_driver(sun4i_ps2_driver); + +MODULE_AUTHOR("Vishnu Patekar "); +MODULE_AUTHOR("Aaron.maoye "); +MODULE_DESCRIPTION("Allwinner A10/Sun4i PS/2 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index 858045694e9d..3a7f3a4a4396 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -59,7 +59,7 @@ Scott Hill shill@gtcocalcomp.com #include #include #include - +#include #include @@ -614,7 +614,6 @@ static void gtco_urb_callback(struct urb *urbinfo) struct input_dev *inputdev; int rc; u32 val = 0; - s8 valsigned = 0; char le_buffer[2]; inputdev = device->inputdevice; @@ -665,20 +664,11 @@ static void gtco_urb_callback(struct urb *urbinfo) /* Fall thru */ case 4: /* Tilt */ + input_report_abs(inputdev, ABS_TILT_X, + sign_extend32(device->buffer[6], 6)); - /* Sign extend these 7 bit numbers. */ - if (device->buffer[6] & 0x40) - device->buffer[6] |= 0x80; - - if (device->buffer[7] & 0x40) - device->buffer[7] |= 0x80; - - - valsigned = (device->buffer[6]); - input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned); - - valsigned = (device->buffer[7]); - input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned); + input_report_abs(inputdev, ABS_TILT_Y, + sign_extend32(device->buffer[7], 6)); /* Fall thru */ case 2: diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index a510f7ef9b66..926c58e540c0 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -33,10 +33,8 @@ #include #include #include -#include #include #include -#include #include #include #include diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 4fb5537fdd42..2c2107147319 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -126,7 +126,7 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, pos[i].y = touch->y; } - input_mt_assign_slots(ts->input, slots, pos, n); + input_mt_assign_slots(ts->input, slots, pos, n, 0); } for (i = 0; i < n; i++) { diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index 28a06749ae42..b93a28b955fd 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -71,6 +72,9 @@ #define TP_ADC_SELECT(x) ((x) << 3) #define ADC_CHAN_SELECT(x) ((x) << 0) /* 3 bits */ +/* on sun6i, bits 3~6 are left shifted by 1 to 4~7 */ +#define SUN6I_TP_MODE_EN(x) ((x) << 5) + /* TP_CTRL2 bits */ #define TP_SENSITIVE_ADJUST(x) ((x) << 28) /* 4 bits */ #define TP_MODE_SELECT(x) ((x) << 26) /* 2 bits */ @@ -107,10 +111,13 @@ struct sun4i_ts_data { struct device *dev; struct input_dev *input; + struct thermal_zone_device *tz; void __iomem *base; unsigned int irq; bool ignore_fifo_data; int temp_data; + int temp_offset; + int temp_step; }; static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val) @@ -180,16 +187,38 @@ static void sun4i_ts_close(struct input_dev *dev) writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); } -static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, - char *buf) +static int sun4i_get_temp(const struct sun4i_ts_data *ts, long *temp) { - struct sun4i_ts_data *ts = dev_get_drvdata(dev); - /* No temp_data until the first irq */ if (ts->temp_data == -1) return -EAGAIN; - return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100); + *temp = (ts->temp_data - ts->temp_offset) * ts->temp_step; + + return 0; +} + +static int sun4i_get_tz_temp(void *data, long *temp) +{ + return sun4i_get_temp(data, temp); +} + +static struct thermal_zone_of_device_ops sun4i_ts_tz_ops = { + .get_temp = sun4i_get_tz_temp, +}; + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sun4i_ts_data *ts = dev_get_drvdata(dev); + long temp; + int error; + + error = sun4i_get_temp(ts, &temp); + if (error) + return error; + + return sprintf(buf, "%ld\n", temp); } static ssize_t show_temp_label(struct device *dev, @@ -215,6 +244,7 @@ static int sun4i_ts_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct device *hwmon; int error; + u32 reg; bool ts_attached; ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL); @@ -224,6 +254,25 @@ static int sun4i_ts_probe(struct platform_device *pdev) ts->dev = dev; ts->ignore_fifo_data = true; ts->temp_data = -1; + if (of_device_is_compatible(np, "allwinner,sun6i-a31-ts")) { + /* Allwinner SDK has temperature = -271 + (value / 6) (C) */ + ts->temp_offset = 1626; + ts->temp_step = 167; + } else { + /* + * The user manuals do not contain the formula for calculating + * the temperature. The formula used here is from the AXP209, + * which is designed by X-Powers, an affiliate of Allwinner: + * + * temperature = -144.7 + (value * 0.1) + * + * Allwinner does not have any documentation whatsoever for + * this hardware. Moreover, it is claimed that the sensor + * is inaccurate and cannot work properly. + */ + ts->temp_offset = 1447; + ts->temp_step = 100; + } ts_attached = of_property_read_bool(np, "allwinner,ts-attached"); if (ts_attached) { @@ -280,20 +329,34 @@ static int sun4i_ts_probe(struct platform_device *pdev) * Set stylus up debounce to aprox 10 ms, enable debounce, and * finally enable tp mode. */ - writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1), - ts->base + TP_CTRL1); + reg = STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1); + if (of_device_is_compatible(np, "allwinner,sun4i-a10-ts")) + reg |= TP_MODE_EN(1); + else + reg |= SUN6I_TP_MODE_EN(1); + writel(reg, ts->base + TP_CTRL1); + /* + * The thermal core does not register hwmon devices for DT-based + * thermal zone sensors, such as this one. + */ hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts", ts, sun4i_ts_groups); if (IS_ERR(hwmon)) return PTR_ERR(hwmon); + ts->tz = thermal_zone_of_sensor_register(ts->dev, 0, ts, + &sun4i_ts_tz_ops); + if (IS_ERR(ts->tz)) + ts->tz = NULL; + writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); if (ts_attached) { error = input_register_device(ts->input); if (error) { writel(0, ts->base + TP_INT_FIFOC); + thermal_zone_of_sensor_unregister(ts->dev, ts->tz); return error; } } @@ -310,6 +373,8 @@ static int sun4i_ts_remove(struct platform_device *pdev) if (ts->input) input_unregister_device(ts->input); + thermal_zone_of_sensor_unregister(ts->dev, ts->tz); + /* Deactivate all IRQs */ writel(0, ts->base + TP_INT_FIFOC); @@ -318,6 +383,7 @@ static int sun4i_ts_remove(struct platform_device *pdev) static const struct of_device_id sun4i_ts_of_match[] = { { .compatible = "allwinner,sun4i-a10-ts", }, + { .compatible = "allwinner,sun6i-a31-ts", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sun4i_ts_of_match); diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 004f1346a957..191a1b87895f 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -52,6 +53,7 @@ struct titsc { u32 bit_xp, bit_xn, bit_yp, bit_yn; u32 inp_xp, inp_xn, inp_yp, inp_yn; u32 step_mask; + u32 charge_delay; }; static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) @@ -121,7 +123,7 @@ static void titsc_step_config(struct titsc *ts_dev) { unsigned int config; int i; - int end_step; + int end_step, first_step, tsc_steps; u32 stepenable; config = STEPCONFIG_MODE_HWSYNC | @@ -140,9 +142,11 @@ static void titsc_step_config(struct titsc *ts_dev) break; } - /* 1 … coordinate_readouts is for X */ - end_step = ts_dev->coordinate_readouts; - for (i = 0; i < end_step; i++) { + tsc_steps = ts_dev->coordinate_readouts * 2 + 2; + first_step = TOTAL_STEPS - tsc_steps; + /* Steps 16 to 16-coordinate_readouts is for X */ + end_step = first_step + tsc_steps; + for (i = end_step - ts_dev->coordinate_readouts; i < end_step; i++) { titsc_writel(ts_dev, REG_STEPCONFIG(i), config); titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); } @@ -164,22 +168,20 @@ static void titsc_step_config(struct titsc *ts_dev) break; } - /* coordinate_readouts … coordinate_readouts * 2 is for Y */ - end_step = ts_dev->coordinate_readouts * 2; - for (i = ts_dev->coordinate_readouts; i < end_step; i++) { + /* 1 ... coordinate_readouts is for Y */ + end_step = first_step + ts_dev->coordinate_readouts; + for (i = first_step; i < end_step; i++) { titsc_writel(ts_dev, REG_STEPCONFIG(i), config); titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); } - /* Charge step configuration */ - config = ts_dev->bit_xp | ts_dev->bit_yn | - STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR | - STEPCHARGE_INM_AN1 | STEPCHARGE_INP(ts_dev->inp_yp); + /* Make CHARGECONFIG same as IDLECONFIG */ + config = titsc_readl(ts_dev, REG_IDLECONFIG); titsc_writel(ts_dev, REG_CHARGECONFIG, config); - titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY); + titsc_writel(ts_dev, REG_CHARGEDELAY, ts_dev->charge_delay); - /* coordinate_readouts * 2 … coordinate_readouts * 2 + 2 is for Z */ + /* coordinate_readouts + 1 ... coordinate_readouts + 2 is for Z */ config = STEPCONFIG_MODE_HWSYNC | STEPCONFIG_AVG_16 | ts_dev->bit_yp | ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM | @@ -194,73 +196,104 @@ static void titsc_step_config(struct titsc *ts_dev) titsc_writel(ts_dev, REG_STEPDELAY(end_step), STEPCONFIG_OPENDLY); - /* The steps1 … end and bit 0 for TS_Charge */ - stepenable = (1 << (end_step + 2)) - 1; + /* The steps end ... end - readouts * 2 + 2 and bit 0 for TS_Charge */ + stepenable = 1; + for (i = 0; i < tsc_steps; i++) + stepenable |= 1 << (first_step + i + 1); + ts_dev->step_mask = stepenable; am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask); } +static int titsc_cmp_coord(const void *a, const void *b) +{ + return *(int *)a - *(int *)b; +} + static void titsc_read_coordinates(struct titsc *ts_dev, u32 *x, u32 *y, u32 *z1, u32 *z2) { - unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT); - unsigned int prev_val_x = ~0, prev_val_y = ~0; - unsigned int prev_diff_x = ~0, prev_diff_y = ~0; - unsigned int read, diff; - unsigned int i, channel; + unsigned int yvals[7], xvals[7]; + unsigned int i, xsum = 0, ysum = 0; unsigned int creads = ts_dev->coordinate_readouts; - *z1 = *z2 = 0; - if (fifocount % (creads * 2 + 2)) - fifocount -= fifocount % (creads * 2 + 2); - /* - * Delta filter is used to remove large variations in sampled - * values from ADC. The filter tries to predict where the next - * coordinate could be. This is done by taking a previous - * coordinate and subtracting it form current one. Further the - * algorithm compares the difference with that of a present value, - * if true the value is reported to the sub system. - */ - for (i = 0; i < fifocount; i++) { - read = titsc_readl(ts_dev, REG_FIFO0); - - channel = (read & 0xf0000) >> 16; - read &= 0xfff; - if (channel < creads) { - diff = abs(read - prev_val_x); - if (diff < prev_diff_x) { - prev_diff_x = diff; - *x = read; - } - prev_val_x = read; - - } else if (channel < creads * 2) { - diff = abs(read - prev_val_y); - if (diff < prev_diff_y) { - prev_diff_y = diff; - *y = read; - } - prev_val_y = read; - - } else if (channel < creads * 2 + 1) { - *z1 = read; - - } else if (channel < creads * 2 + 2) { - *z2 = read; - } + for (i = 0; i < creads; i++) { + yvals[i] = titsc_readl(ts_dev, REG_FIFO0); + yvals[i] &= 0xfff; } + + *z1 = titsc_readl(ts_dev, REG_FIFO0); + *z1 &= 0xfff; + *z2 = titsc_readl(ts_dev, REG_FIFO0); + *z2 &= 0xfff; + + for (i = 0; i < creads; i++) { + xvals[i] = titsc_readl(ts_dev, REG_FIFO0); + xvals[i] &= 0xfff; + } + + /* + * If co-ordinates readouts is less than 4 then + * report the average. In case of 4 or more + * readouts, sort the co-ordinate samples, drop + * min and max values and report the average of + * remaining values. + */ + if (creads <= 3) { + for (i = 0; i < creads; i++) { + ysum += yvals[i]; + xsum += xvals[i]; + } + ysum /= creads; + xsum /= creads; + } else { + sort(yvals, creads, sizeof(unsigned int), + titsc_cmp_coord, NULL); + sort(xvals, creads, sizeof(unsigned int), + titsc_cmp_coord, NULL); + for (i = 1; i < creads - 1; i++) { + ysum += yvals[i]; + xsum += xvals[i]; + } + ysum /= creads - 2; + xsum /= creads - 2; + } + *y = ysum; + *x = xsum; } static irqreturn_t titsc_irq(int irq, void *dev) { struct titsc *ts_dev = dev; struct input_dev *input_dev = ts_dev->input; - unsigned int status, irqclr = 0; + unsigned int fsm, status, irqclr = 0; unsigned int x = 0, y = 0; unsigned int z1, z2, z; - unsigned int fsm; - status = titsc_readl(ts_dev, REG_IRQSTATUS); + status = titsc_readl(ts_dev, REG_RAWIRQSTATUS); + if (status & IRQENB_HW_PEN) { + ts_dev->pen_down = true; + titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00); + titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); + irqclr |= IRQENB_HW_PEN; + } + + if (status & IRQENB_PENUP) { + fsm = titsc_readl(ts_dev, REG_ADCFSM); + if (fsm == ADCFSM_STEPID) { + ts_dev->pen_down = false; + input_report_key(input_dev, BTN_TOUCH, 0); + input_report_abs(input_dev, ABS_PRESSURE, 0); + input_sync(input_dev); + } else { + ts_dev->pen_down = true; + } + irqclr |= IRQENB_PENUP; + } + + if (status & IRQENB_EOS) + irqclr |= IRQENB_EOS; + /* * ADC and touchscreen share the IRQ line. * FIFO1 interrupts are used by ADC. Handle FIFO0 IRQs here only @@ -291,37 +324,11 @@ static irqreturn_t titsc_irq(int irq, void *dev) } irqclr |= IRQENB_FIFO0THRES; } - - /* - * Time for sequencer to settle, to read - * correct state of the sequencer. - */ - udelay(SEQ_SETTLE); - - status = titsc_readl(ts_dev, REG_RAWIRQSTATUS); - if (status & IRQENB_PENUP) { - /* Pen up event */ - fsm = titsc_readl(ts_dev, REG_ADCFSM); - if (fsm == ADCFSM_STEPID) { - ts_dev->pen_down = false; - input_report_key(input_dev, BTN_TOUCH, 0); - input_report_abs(input_dev, ABS_PRESSURE, 0); - input_sync(input_dev); - } else { - ts_dev->pen_down = true; - } - irqclr |= IRQENB_PENUP; - } - - if (status & IRQENB_HW_PEN) { - - titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00); - titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); - } - if (irqclr) { titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); - am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask); + if (status & IRQENB_EOS) + am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, + ts_dev->step_mask); return IRQ_HANDLED; } return IRQ_NONE; @@ -368,6 +375,23 @@ static int titsc_parse_dt(struct platform_device *pdev, if (err < 0) return err; + if (ts_dev->coordinate_readouts <= 0) { + dev_warn(&pdev->dev, + "invalid co-ordinate readouts, resetting it to 5\n"); + ts_dev->coordinate_readouts = 5; + } + + err = of_property_read_u32(node, "ti,charge-delay", + &ts_dev->charge_delay); + /* + * If ti,charge-delay value is not specified, then use + * CHARGEDLY_OPENDLY as the default value. + */ + if (err < 0) { + ts_dev->charge_delay = CHARGEDLY_OPENDLY; + dev_warn(&pdev->dev, "ti,charge-delay not specified\n"); + } + return of_property_read_u32_array(node, "ti,wire-config", ts_dev->config_inp, ARRAY_SIZE(ts_dev->config_inp)); } @@ -411,6 +435,7 @@ static int titsc_probe(struct platform_device *pdev) } titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); + titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_EOS); err = titsc_config_wires(ts_dev); if (err) { dev_err(&pdev->dev, "wrong i/p wire configuration\n"); diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 325188eef1c1..baa0d9786f50 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -4,6 +4,7 @@ config IOMMU_API menuconfig IOMMU_SUPPORT bool "IOMMU Hardware Support" + depends on MMU default y ---help--- Say Y here if you want to compile device drivers for IO Memory @@ -13,13 +14,43 @@ menuconfig IOMMU_SUPPORT if IOMMU_SUPPORT +menu "Generic IOMMU Pagetable Support" + +# Selected by the actual pagetable implementations +config IOMMU_IO_PGTABLE + bool + +config IOMMU_IO_PGTABLE_LPAE + bool "ARMv7/v8 Long Descriptor Format" + select IOMMU_IO_PGTABLE + help + Enable support for the ARM long descriptor pagetable format. + This allocator supports 4K/2M/1G, 16K/32M and 64K/512M page + sizes at both stage-1 and stage-2, as well as address spaces + up to 48-bits in size. + +config IOMMU_IO_PGTABLE_LPAE_SELFTEST + bool "LPAE selftests" + depends on IOMMU_IO_PGTABLE_LPAE + help + Enable self-tests for LPAE page table allocator. This performs + a series of page-table consistency checks during boot. + + If unsure, say N here. + +endmenu + +config IOMMU_IOVA + bool + config OF_IOMMU def_bool y depends on OF && IOMMU_API config FSL_PAMU bool "Freescale IOMMU support" - depends on PPC_E500MC + depends on PPC32 + depends on PPC_E500MC || COMPILE_TEST select IOMMU_API select GENERIC_ALLOCATOR help @@ -30,7 +61,8 @@ config FSL_PAMU # MSM IOMMU support config MSM_IOMMU bool "MSM IOMMU Support" - depends on ARCH_MSM8X60 || ARCH_MSM8960 + depends on ARM + depends on ARCH_MSM8X60 || ARCH_MSM8960 || COMPILE_TEST select IOMMU_API help Support for the IOMMUs found on certain Qualcomm SOCs. @@ -91,6 +123,7 @@ config INTEL_IOMMU bool "Support for Intel IOMMU using DMA Remapping Devices" depends on PCI_MSI && ACPI && (X86 || IA64_GENERIC) select IOMMU_API + select IOMMU_IOVA select DMAR_TABLE help DMA remapping (DMAR) devices support enables independent address @@ -140,7 +173,8 @@ config IRQ_REMAP # OMAP IOMMU support config OMAP_IOMMU bool "OMAP IOMMU Support" - depends on ARCH_OMAP2PLUS + depends on ARM && MMU + depends on ARCH_OMAP2PLUS || COMPILE_TEST select IOMMU_API config OMAP_IOMMU_DEBUG @@ -187,7 +221,7 @@ config TEGRA_IOMMU_SMMU config EXYNOS_IOMMU bool "Exynos IOMMU Support" - depends on ARCH_EXYNOS && ARM + depends on ARCH_EXYNOS && ARM && MMU select IOMMU_API select ARM_DMA_USE_IOMMU help @@ -216,7 +250,7 @@ config SHMOBILE_IPMMU_TLB config SHMOBILE_IOMMU bool "IOMMU for Renesas IPMMU/IPMMUI" default n - depends on ARM + depends on ARM && MMU depends on ARCH_SHMOBILE || COMPILE_TEST select IOMMU_API select ARM_DMA_USE_IOMMU @@ -287,6 +321,7 @@ config IPMMU_VMSA depends on ARM_LPAE depends on ARCH_SHMOBILE || COMPILE_TEST select IOMMU_API + select IOMMU_IO_PGTABLE_LPAE select ARM_DMA_USE_IOMMU help Support for the Renesas VMSA-compatible IPMMU Renesas found in the @@ -304,13 +339,13 @@ config SPAPR_TCE_IOMMU config ARM_SMMU bool "ARM Ltd. System MMU (SMMU) Support" - depends on ARM64 || (ARM_LPAE && OF) + depends on (ARM64 || ARM) && MMU select IOMMU_API + select IOMMU_IO_PGTABLE_LPAE select ARM_DMA_USE_IOMMU if ARM help Support for implementations of the ARM System MMU architecture - versions 1 and 2. The driver supports both v7l and v8l table - formats with 4k and 64k page sizes. + versions 1 and 2. Say Y here if your SoC includes an IOMMU device implementing the ARM SMMU architecture. diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 7b976f294a69..080ffab4ed1c 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -1,13 +1,16 @@ obj-$(CONFIG_IOMMU_API) += iommu.o obj-$(CONFIG_IOMMU_API) += iommu-traces.o obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o +obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o +obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o +obj-$(CONFIG_IOMMU_IOVA) += iova.o obj-$(CONFIG_OF_IOMMU) += of_iommu.o obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o obj-$(CONFIG_ARM_SMMU) += arm-smmu.o obj-$(CONFIG_DMAR_TABLE) += dmar.o -obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o +obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 98024856df07..48882c126245 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2007-2010 Advanced Micro Devices, Inc. - * Author: Joerg Roedel + * Author: Joerg Roedel * Leo Duran * * This program is free software; you can redistribute it and/or modify it @@ -843,10 +843,10 @@ static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address, size_t size, u16 domid, int pde) { u64 pages; - int s; + bool s; pages = iommu_num_pages(address, size, PAGE_SIZE); - s = 0; + s = false; if (pages > 1) { /* @@ -854,7 +854,7 @@ static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address, * TLB entries for this domain */ address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS; - s = 1; + s = true; } address &= PAGE_MASK; @@ -874,10 +874,10 @@ static void build_inv_iotlb_pages(struct iommu_cmd *cmd, u16 devid, int qdep, u64 address, size_t size) { u64 pages; - int s; + bool s; pages = iommu_num_pages(address, size, PAGE_SIZE); - s = 0; + s = false; if (pages > 1) { /* @@ -885,7 +885,7 @@ static void build_inv_iotlb_pages(struct iommu_cmd *cmd, u16 devid, int qdep, * TLB entries for this domain */ address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS; - s = 1; + s = true; } address &= PAGE_MASK; @@ -4284,7 +4284,6 @@ static int alloc_hpet_msi(unsigned int irq, unsigned int id) } struct irq_remap_ops amd_iommu_irq_ops = { - .supported = amd_iommu_supported, .prepare = amd_iommu_prepare, .enable = amd_iommu_enable, .disable = amd_iommu_disable, diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index b0522f15730f..450ef5001a65 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2007-2010 Advanced Micro Devices, Inc. - * Author: Joerg Roedel + * Author: Joerg Roedel * Leo Duran * * This program is free software; you can redistribute it and/or modify it @@ -2014,9 +2014,6 @@ static bool detect_ivrs(void) /* Make sure ACS will be enabled during PCI probe */ pci_request_acs(); - if (!disable_irq_remap) - amd_iommu_irq_remap = true; - return true; } @@ -2123,12 +2120,14 @@ static int __init iommu_go_to_state(enum iommu_init_state state) #ifdef CONFIG_IRQ_REMAP int __init amd_iommu_prepare(void) { - return iommu_go_to_state(IOMMU_ACPI_FINISHED); -} + int ret; -int __init amd_iommu_supported(void) -{ - return amd_iommu_irq_remap ? 1 : 0; + amd_iommu_irq_remap = true; + + ret = iommu_go_to_state(IOMMU_ACPI_FINISHED); + if (ret) + return ret; + return amd_iommu_irq_remap ? 0 : -ENODEV; } int __init amd_iommu_enable(void) diff --git a/drivers/iommu/amd_iommu_proto.h b/drivers/iommu/amd_iommu_proto.h index 95ed6deae47f..72b0fd455e24 100644 --- a/drivers/iommu/amd_iommu_proto.h +++ b/drivers/iommu/amd_iommu_proto.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2009-2010 Advanced Micro Devices, Inc. - * Author: Joerg Roedel + * Author: Joerg Roedel * * This 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 @@ -33,7 +33,6 @@ extern void amd_iommu_init_notifier(void); extern void amd_iommu_init_api(void); /* Needed for interrupt remapping */ -extern int amd_iommu_supported(void); extern int amd_iommu_prepare(void); extern int amd_iommu_enable(void); extern void amd_iommu_disable(void); diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index cec51a8ba844..c4fffb710c58 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007-2010 Advanced Micro Devices, Inc. - * Author: Joerg Roedel + * Author: Joerg Roedel * Leo Duran * * This program is free software; you can redistribute it and/or modify it diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c index 90f70d0e1141..6d5a5c44453b 100644 --- a/drivers/iommu/amd_iommu_v2.c +++ b/drivers/iommu/amd_iommu_v2.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2010-2012 Advanced Micro Devices, Inc. - * Author: Joerg Roedel + * Author: Joerg Roedel * * This 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 @@ -31,7 +31,7 @@ #include "amd_iommu_proto.h" MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Joerg Roedel "); +MODULE_AUTHOR("Joerg Roedel "); #define MAX_DEVICES 0x10000 #define PRI_QUEUE_SIZE 512 @@ -151,18 +151,6 @@ static void put_device_state(struct device_state *dev_state) wake_up(&dev_state->wq); } -static void put_device_state_wait(struct device_state *dev_state) -{ - DEFINE_WAIT(wait); - - prepare_to_wait(&dev_state->wq, &wait, TASK_UNINTERRUPTIBLE); - if (!atomic_dec_and_test(&dev_state->count)) - schedule(); - finish_wait(&dev_state->wq, &wait); - - free_device_state(dev_state); -} - /* Must be called under dev_state->lock */ static struct pasid_state **__get_pasid_state_ptr(struct device_state *dev_state, int pasid, bool alloc) @@ -278,14 +266,7 @@ static void put_pasid_state(struct pasid_state *pasid_state) static void put_pasid_state_wait(struct pasid_state *pasid_state) { - DEFINE_WAIT(wait); - - prepare_to_wait(&pasid_state->wq, &wait, TASK_UNINTERRUPTIBLE); - - if (!atomic_dec_and_test(&pasid_state->count)) - schedule(); - - finish_wait(&pasid_state->wq, &wait); + wait_event(pasid_state->wq, !atomic_read(&pasid_state->count)); free_pasid_state(pasid_state); } @@ -851,7 +832,13 @@ void amd_iommu_free_device(struct pci_dev *pdev) /* Get rid of any remaining pasid states */ free_pasid_states(dev_state); - put_device_state_wait(dev_state); + put_device_state(dev_state); + /* + * Wait until the last reference is dropped before freeing + * the device state. + */ + wait_event(dev_state->wq, !atomic_read(&dev_state->count)); + free_device_state(dev_state); } EXPORT_SYMBOL(amd_iommu_free_device); @@ -921,7 +908,7 @@ static int __init amd_iommu_v2_init(void) { int ret; - pr_info("AMD IOMMUv2 driver by Joerg Roedel \n"); + pr_info("AMD IOMMUv2 driver by Joerg Roedel \n"); if (!amd_iommu_v2_supported()) { pr_info("AMD IOMMUv2 functionality not available on this system\n"); diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 6cd47b75286f..fc13dd56953e 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -23,8 +23,6 @@ * - Stream-matching and stream-indexing * - v7/v8 long-descriptor format * - Non-secure access to the SMMU - * - 4k and 64k pages, with contiguous pte hints. - * - Up to 48-bit addressing (dependent on VA_BITS) * - Context fault reporting */ @@ -36,7 +34,7 @@ #include #include #include -#include +#include #include #include #include @@ -46,7 +44,7 @@ #include -#include +#include "io-pgtable.h" /* Maximum number of stream IDs assigned to a single device */ #define MAX_MASTER_STREAMIDS MAX_PHANDLE_ARGS @@ -71,40 +69,6 @@ ((smmu->options & ARM_SMMU_OPT_SECURE_CFG_ACCESS) \ ? 0x400 : 0)) -/* Page table bits */ -#define ARM_SMMU_PTE_XN (((pteval_t)3) << 53) -#define ARM_SMMU_PTE_CONT (((pteval_t)1) << 52) -#define ARM_SMMU_PTE_AF (((pteval_t)1) << 10) -#define ARM_SMMU_PTE_SH_NS (((pteval_t)0) << 8) -#define ARM_SMMU_PTE_SH_OS (((pteval_t)2) << 8) -#define ARM_SMMU_PTE_SH_IS (((pteval_t)3) << 8) -#define ARM_SMMU_PTE_PAGE (((pteval_t)3) << 0) - -#if PAGE_SIZE == SZ_4K -#define ARM_SMMU_PTE_CONT_ENTRIES 16 -#elif PAGE_SIZE == SZ_64K -#define ARM_SMMU_PTE_CONT_ENTRIES 32 -#else -#define ARM_SMMU_PTE_CONT_ENTRIES 1 -#endif - -#define ARM_SMMU_PTE_CONT_SIZE (PAGE_SIZE * ARM_SMMU_PTE_CONT_ENTRIES) -#define ARM_SMMU_PTE_CONT_MASK (~(ARM_SMMU_PTE_CONT_SIZE - 1)) - -/* Stage-1 PTE */ -#define ARM_SMMU_PTE_AP_UNPRIV (((pteval_t)1) << 6) -#define ARM_SMMU_PTE_AP_RDONLY (((pteval_t)2) << 6) -#define ARM_SMMU_PTE_ATTRINDX_SHIFT 2 -#define ARM_SMMU_PTE_nG (((pteval_t)1) << 11) - -/* Stage-2 PTE */ -#define ARM_SMMU_PTE_HAP_FAULT (((pteval_t)0) << 6) -#define ARM_SMMU_PTE_HAP_READ (((pteval_t)1) << 6) -#define ARM_SMMU_PTE_HAP_WRITE (((pteval_t)2) << 6) -#define ARM_SMMU_PTE_MEMATTR_OIWB (((pteval_t)0xf) << 2) -#define ARM_SMMU_PTE_MEMATTR_NC (((pteval_t)0x5) << 2) -#define ARM_SMMU_PTE_MEMATTR_DEV (((pteval_t)0x1) << 2) - /* Configuration registers */ #define ARM_SMMU_GR0_sCR0 0x0 #define sCR0_CLIENTPD (1 << 0) @@ -132,17 +96,12 @@ #define ARM_SMMU_GR0_sGFSYNR0 0x50 #define ARM_SMMU_GR0_sGFSYNR1 0x54 #define ARM_SMMU_GR0_sGFSYNR2 0x58 -#define ARM_SMMU_GR0_PIDR0 0xfe0 -#define ARM_SMMU_GR0_PIDR1 0xfe4 -#define ARM_SMMU_GR0_PIDR2 0xfe8 #define ID0_S1TS (1 << 30) #define ID0_S2TS (1 << 29) #define ID0_NTS (1 << 28) #define ID0_SMS (1 << 27) -#define ID0_PTFS_SHIFT 24 -#define ID0_PTFS_MASK 0x2 -#define ID0_PTFS_V8_ONLY 0x2 +#define ID0_ATOSNS (1 << 26) #define ID0_CTTW (1 << 14) #define ID0_NUMIRPT_SHIFT 16 #define ID0_NUMIRPT_MASK 0xff @@ -169,11 +128,7 @@ #define ID2_PTFS_16K (1 << 13) #define ID2_PTFS_64K (1 << 14) -#define PIDR2_ARCH_SHIFT 4 -#define PIDR2_ARCH_MASK 0xf - /* Global TLB invalidation */ -#define ARM_SMMU_GR0_STLBIALL 0x60 #define ARM_SMMU_GR0_TLBIVMID 0x64 #define ARM_SMMU_GR0_TLBIALLNSNH 0x68 #define ARM_SMMU_GR0_TLBIALLH 0x6c @@ -231,13 +186,25 @@ #define ARM_SMMU_CB_TTBCR2 0x10 #define ARM_SMMU_CB_TTBR0_LO 0x20 #define ARM_SMMU_CB_TTBR0_HI 0x24 +#define ARM_SMMU_CB_TTBR1_LO 0x28 +#define ARM_SMMU_CB_TTBR1_HI 0x2c #define ARM_SMMU_CB_TTBCR 0x30 #define ARM_SMMU_CB_S1_MAIR0 0x38 +#define ARM_SMMU_CB_S1_MAIR1 0x3c +#define ARM_SMMU_CB_PAR_LO 0x50 +#define ARM_SMMU_CB_PAR_HI 0x54 #define ARM_SMMU_CB_FSR 0x58 #define ARM_SMMU_CB_FAR_LO 0x60 #define ARM_SMMU_CB_FAR_HI 0x64 #define ARM_SMMU_CB_FSYNR0 0x68 +#define ARM_SMMU_CB_S1_TLBIVA 0x600 #define ARM_SMMU_CB_S1_TLBIASID 0x610 +#define ARM_SMMU_CB_S1_TLBIVAL 0x620 +#define ARM_SMMU_CB_S2_TLBIIPAS2 0x630 +#define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638 +#define ARM_SMMU_CB_ATS1PR_LO 0x800 +#define ARM_SMMU_CB_ATS1PR_HI 0x804 +#define ARM_SMMU_CB_ATSR 0x8f0 #define SCTLR_S1_ASIDPNE (1 << 12) #define SCTLR_CFCFG (1 << 7) @@ -249,47 +216,16 @@ #define SCTLR_M (1 << 0) #define SCTLR_EAE_SBOP (SCTLR_AFE | SCTLR_TRE) +#define CB_PAR_F (1 << 0) + +#define ATSR_ACTIVE (1 << 0) + #define RESUME_RETRY (0 << 0) #define RESUME_TERMINATE (1 << 0) -#define TTBCR_EAE (1 << 31) - -#define TTBCR_PASIZE_SHIFT 16 -#define TTBCR_PASIZE_MASK 0x7 - -#define TTBCR_TG0_4K (0 << 14) -#define TTBCR_TG0_64K (1 << 14) - -#define TTBCR_SH0_SHIFT 12 -#define TTBCR_SH0_MASK 0x3 -#define TTBCR_SH_NS 0 -#define TTBCR_SH_OS 2 -#define TTBCR_SH_IS 3 - -#define TTBCR_ORGN0_SHIFT 10 -#define TTBCR_IRGN0_SHIFT 8 -#define TTBCR_RGN_MASK 0x3 -#define TTBCR_RGN_NC 0 -#define TTBCR_RGN_WBWA 1 -#define TTBCR_RGN_WT 2 -#define TTBCR_RGN_WB 3 - -#define TTBCR_SL0_SHIFT 6 -#define TTBCR_SL0_MASK 0x3 -#define TTBCR_SL0_LVL_2 0 -#define TTBCR_SL0_LVL_1 1 - -#define TTBCR_T1SZ_SHIFT 16 -#define TTBCR_T0SZ_SHIFT 0 -#define TTBCR_SZ_MASK 0xf - #define TTBCR2_SEP_SHIFT 15 #define TTBCR2_SEP_MASK 0x7 -#define TTBCR2_PASIZE_SHIFT 0 -#define TTBCR2_PASIZE_MASK 0x7 - -/* Common definitions for PASize and SEP fields */ #define TTBCR2_ADDR_32 0 #define TTBCR2_ADDR_36 1 #define TTBCR2_ADDR_40 2 @@ -297,16 +233,7 @@ #define TTBCR2_ADDR_44 4 #define TTBCR2_ADDR_48 5 -#define TTBRn_HI_ASID_SHIFT 16 - -#define MAIR_ATTR_SHIFT(n) ((n) << 3) -#define MAIR_ATTR_MASK 0xff -#define MAIR_ATTR_DEVICE 0x04 -#define MAIR_ATTR_NC 0x44 -#define MAIR_ATTR_WBRWA 0xff -#define MAIR_ATTR_IDX_NC 0 -#define MAIR_ATTR_IDX_CACHE 1 -#define MAIR_ATTR_IDX_DEV 2 +#define TTBRn_HI_ASID_SHIFT 16 #define FSR_MULTI (1 << 31) #define FSR_SS (1 << 30) @@ -366,6 +293,7 @@ struct arm_smmu_device { #define ARM_SMMU_FEAT_TRANS_S1 (1 << 2) #define ARM_SMMU_FEAT_TRANS_S2 (1 << 3) #define ARM_SMMU_FEAT_TRANS_NESTED (1 << 4) +#define ARM_SMMU_FEAT_TRANS_OPS (1 << 5) u32 features; #define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0) @@ -380,10 +308,9 @@ struct arm_smmu_device { u32 num_mapping_groups; DECLARE_BITMAP(smr_map, ARM_SMMU_MAX_SMRS); - unsigned long s1_input_size; - unsigned long s1_output_size; - unsigned long s2_input_size; - unsigned long s2_output_size; + unsigned long va_size; + unsigned long ipa_size; + unsigned long pa_size; u32 num_global_irqs; u32 num_context_irqs; @@ -397,7 +324,6 @@ struct arm_smmu_cfg { u8 cbndx; u8 irptndx; u32 cbar; - pgd_t *pgd; }; #define INVALID_IRPTNDX 0xff @@ -412,11 +338,15 @@ enum arm_smmu_domain_stage { struct arm_smmu_domain { struct arm_smmu_device *smmu; + struct io_pgtable_ops *pgtbl_ops; + spinlock_t pgtbl_lock; struct arm_smmu_cfg cfg; enum arm_smmu_domain_stage stage; - spinlock_t lock; + struct mutex init_mutex; /* Protects smmu pointer */ }; +static struct iommu_ops arm_smmu_ops; + static DEFINE_SPINLOCK(arm_smmu_devices_lock); static LIST_HEAD(arm_smmu_devices); @@ -597,7 +527,7 @@ static void __arm_smmu_free_bitmap(unsigned long *map, int idx) } /* Wait for any pending TLB invalidations to complete */ -static void arm_smmu_tlb_sync(struct arm_smmu_device *smmu) +static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu) { int count = 0; void __iomem *gr0_base = ARM_SMMU_GR0(smmu); @@ -615,12 +545,19 @@ static void arm_smmu_tlb_sync(struct arm_smmu_device *smmu) } } -static void arm_smmu_tlb_inv_context(struct arm_smmu_domain *smmu_domain) +static void arm_smmu_tlb_sync(void *cookie) { + struct arm_smmu_domain *smmu_domain = cookie; + __arm_smmu_tlb_sync(smmu_domain->smmu); +} + +static void arm_smmu_tlb_inv_context(void *cookie) +{ + struct arm_smmu_domain *smmu_domain = cookie; struct arm_smmu_cfg *cfg = &smmu_domain->cfg; struct arm_smmu_device *smmu = smmu_domain->smmu; - void __iomem *base = ARM_SMMU_GR0(smmu); bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS; + void __iomem *base; if (stage1) { base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); @@ -632,9 +569,76 @@ static void arm_smmu_tlb_inv_context(struct arm_smmu_domain *smmu_domain) base + ARM_SMMU_GR0_TLBIVMID); } - arm_smmu_tlb_sync(smmu); + __arm_smmu_tlb_sync(smmu); } +static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, + bool leaf, void *cookie) +{ + struct arm_smmu_domain *smmu_domain = cookie; + struct arm_smmu_cfg *cfg = &smmu_domain->cfg; + struct arm_smmu_device *smmu = smmu_domain->smmu; + bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS; + void __iomem *reg; + + if (stage1) { + reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); + reg += leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA; + + if (!IS_ENABLED(CONFIG_64BIT) || smmu->version == ARM_SMMU_V1) { + iova &= ~12UL; + iova |= ARM_SMMU_CB_ASID(cfg); + writel_relaxed(iova, reg); +#ifdef CONFIG_64BIT + } else { + iova >>= 12; + iova |= (u64)ARM_SMMU_CB_ASID(cfg) << 48; + writeq_relaxed(iova, reg); +#endif + } +#ifdef CONFIG_64BIT + } else if (smmu->version == ARM_SMMU_V2) { + reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); + reg += leaf ? ARM_SMMU_CB_S2_TLBIIPAS2L : + ARM_SMMU_CB_S2_TLBIIPAS2; + writeq_relaxed(iova >> 12, reg); +#endif + } else { + reg = ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_TLBIVMID; + writel_relaxed(ARM_SMMU_CB_VMID(cfg), reg); + } +} + +static void arm_smmu_flush_pgtable(void *addr, size_t size, void *cookie) +{ + struct arm_smmu_domain *smmu_domain = cookie; + struct arm_smmu_device *smmu = smmu_domain->smmu; + unsigned long offset = (unsigned long)addr & ~PAGE_MASK; + + + /* Ensure new page tables are visible to the hardware walker */ + if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) { + dsb(ishst); + } else { + /* + * If the SMMU can't walk tables in the CPU caches, treat them + * like non-coherent DMA since we need to flush the new entries + * all the way out to memory. There's no possibility of + * recursion here as the SMMU table walker will not be wired + * through another SMMU. + */ + dma_map_page(smmu->dev, virt_to_page(addr), offset, size, + DMA_TO_DEVICE); + } +} + +static struct iommu_gather_ops arm_smmu_gather_ops = { + .tlb_flush_all = arm_smmu_tlb_inv_context, + .tlb_add_flush = arm_smmu_tlb_inv_range_nosync, + .tlb_sync = arm_smmu_tlb_sync, + .flush_pgtable = arm_smmu_flush_pgtable, +}; + static irqreturn_t arm_smmu_context_fault(int irq, void *dev) { int flags, ret; @@ -712,29 +716,8 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev) return IRQ_HANDLED; } -static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr, - size_t size) -{ - unsigned long offset = (unsigned long)addr & ~PAGE_MASK; - - - /* Ensure new page tables are visible to the hardware walker */ - if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) { - dsb(ishst); - } else { - /* - * If the SMMU can't walk tables in the CPU caches, treat them - * like non-coherent DMA since we need to flush the new entries - * all the way out to memory. There's no possibility of - * recursion here as the SMMU table walker will not be wired - * through another SMMU. - */ - dma_map_page(smmu->dev, virt_to_page(addr), offset, size, - DMA_TO_DEVICE); - } -} - -static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain) +static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, + struct io_pgtable_cfg *pgtbl_cfg) { u32 reg; bool stage1; @@ -771,124 +754,68 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain) #else reg = CBA2R_RW64_32BIT; #endif - writel_relaxed(reg, - gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx)); - - /* TTBCR2 */ - switch (smmu->s1_input_size) { - case 32: - reg = (TTBCR2_ADDR_32 << TTBCR2_SEP_SHIFT); - break; - case 36: - reg = (TTBCR2_ADDR_36 << TTBCR2_SEP_SHIFT); - break; - case 39: - case 40: - reg = (TTBCR2_ADDR_40 << TTBCR2_SEP_SHIFT); - break; - case 42: - reg = (TTBCR2_ADDR_42 << TTBCR2_SEP_SHIFT); - break; - case 44: - reg = (TTBCR2_ADDR_44 << TTBCR2_SEP_SHIFT); - break; - case 48: - reg = (TTBCR2_ADDR_48 << TTBCR2_SEP_SHIFT); - break; - } - - switch (smmu->s1_output_size) { - case 32: - reg |= (TTBCR2_ADDR_32 << TTBCR2_PASIZE_SHIFT); - break; - case 36: - reg |= (TTBCR2_ADDR_36 << TTBCR2_PASIZE_SHIFT); - break; - case 39: - case 40: - reg |= (TTBCR2_ADDR_40 << TTBCR2_PASIZE_SHIFT); - break; - case 42: - reg |= (TTBCR2_ADDR_42 << TTBCR2_PASIZE_SHIFT); - break; - case 44: - reg |= (TTBCR2_ADDR_44 << TTBCR2_PASIZE_SHIFT); - break; - case 48: - reg |= (TTBCR2_ADDR_48 << TTBCR2_PASIZE_SHIFT); - break; - } - - if (stage1) - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR2); + writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx)); } - /* TTBR0 */ - arm_smmu_flush_pgtable(smmu, cfg->pgd, - PTRS_PER_PGD * sizeof(pgd_t)); - reg = __pa(cfg->pgd); - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); - reg = (phys_addr_t)__pa(cfg->pgd) >> 32; - if (stage1) + /* TTBRs */ + if (stage1) { + reg = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0]; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); + reg = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0] >> 32; reg |= ARM_SMMU_CB_ASID(cfg) << TTBRn_HI_ASID_SHIFT; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI); + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI); - /* - * TTBCR - * We use long descriptor, with inner-shareable WBWA tables in TTBR0. - */ - if (smmu->version > ARM_SMMU_V1) { - if (PAGE_SIZE == SZ_4K) - reg = TTBCR_TG0_4K; - else - reg = TTBCR_TG0_64K; + reg = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1]; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1_LO); + reg = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1] >> 32; + reg |= ARM_SMMU_CB_ASID(cfg) << TTBRn_HI_ASID_SHIFT; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1_HI); + } else { + reg = pgtbl_cfg->arm_lpae_s2_cfg.vttbr; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); + reg = pgtbl_cfg->arm_lpae_s2_cfg.vttbr >> 32; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI); + } - if (!stage1) { - reg |= (64 - smmu->s2_input_size) << TTBCR_T0SZ_SHIFT; - - switch (smmu->s2_output_size) { + /* TTBCR */ + if (stage1) { + reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR); + if (smmu->version > ARM_SMMU_V1) { + reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32; + switch (smmu->va_size) { case 32: - reg |= (TTBCR2_ADDR_32 << TTBCR_PASIZE_SHIFT); + reg |= (TTBCR2_ADDR_32 << TTBCR2_SEP_SHIFT); break; case 36: - reg |= (TTBCR2_ADDR_36 << TTBCR_PASIZE_SHIFT); + reg |= (TTBCR2_ADDR_36 << TTBCR2_SEP_SHIFT); break; case 40: - reg |= (TTBCR2_ADDR_40 << TTBCR_PASIZE_SHIFT); + reg |= (TTBCR2_ADDR_40 << TTBCR2_SEP_SHIFT); break; case 42: - reg |= (TTBCR2_ADDR_42 << TTBCR_PASIZE_SHIFT); + reg |= (TTBCR2_ADDR_42 << TTBCR2_SEP_SHIFT); break; case 44: - reg |= (TTBCR2_ADDR_44 << TTBCR_PASIZE_SHIFT); + reg |= (TTBCR2_ADDR_44 << TTBCR2_SEP_SHIFT); break; case 48: - reg |= (TTBCR2_ADDR_48 << TTBCR_PASIZE_SHIFT); + reg |= (TTBCR2_ADDR_48 << TTBCR2_SEP_SHIFT); break; } - } else { - reg |= (64 - smmu->s1_input_size) << TTBCR_T0SZ_SHIFT; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR2); } } else { - reg = 0; + reg = pgtbl_cfg->arm_lpae_s2_cfg.vtcr; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR); } - reg |= TTBCR_EAE | - (TTBCR_SH_IS << TTBCR_SH0_SHIFT) | - (TTBCR_RGN_WBWA << TTBCR_ORGN0_SHIFT) | - (TTBCR_RGN_WBWA << TTBCR_IRGN0_SHIFT); - - if (!stage1) - reg |= (TTBCR_SL0_LVL_1 << TTBCR_SL0_SHIFT); - - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR); - - /* MAIR0 (stage-1 only) */ + /* MAIRs (stage-1 only) */ if (stage1) { - reg = (MAIR_ATTR_NC << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_NC)) | - (MAIR_ATTR_WBRWA << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_CACHE)) | - (MAIR_ATTR_DEVICE << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_DEV)); + reg = pgtbl_cfg->arm_lpae_s1_cfg.mair[0]; writel_relaxed(reg, cb_base + ARM_SMMU_CB_S1_MAIR0); + reg = pgtbl_cfg->arm_lpae_s1_cfg.mair[1]; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_S1_MAIR1); } /* SCTLR */ @@ -905,11 +832,14 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, struct arm_smmu_device *smmu) { int irq, start, ret = 0; - unsigned long flags; + unsigned long ias, oas; + struct io_pgtable_ops *pgtbl_ops; + struct io_pgtable_cfg pgtbl_cfg; + enum io_pgtable_fmt fmt; struct arm_smmu_domain *smmu_domain = domain->priv; struct arm_smmu_cfg *cfg = &smmu_domain->cfg; - spin_lock_irqsave(&smmu_domain->lock, flags); + mutex_lock(&smmu_domain->init_mutex); if (smmu_domain->smmu) goto out_unlock; @@ -940,6 +870,12 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, case ARM_SMMU_DOMAIN_S1: cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS; start = smmu->num_s2_context_banks; + ias = smmu->va_size; + oas = smmu->ipa_size; + if (IS_ENABLED(CONFIG_64BIT)) + fmt = ARM_64_LPAE_S1; + else + fmt = ARM_32_LPAE_S1; break; case ARM_SMMU_DOMAIN_NESTED: /* @@ -949,6 +885,12 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, case ARM_SMMU_DOMAIN_S2: cfg->cbar = CBAR_TYPE_S2_TRANS; start = 0; + ias = smmu->ipa_size; + oas = smmu->pa_size; + if (IS_ENABLED(CONFIG_64BIT)) + fmt = ARM_64_LPAE_S2; + else + fmt = ARM_32_LPAE_S2; break; default: ret = -EINVAL; @@ -968,10 +910,30 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, cfg->irptndx = cfg->cbndx; } - ACCESS_ONCE(smmu_domain->smmu) = smmu; - arm_smmu_init_context_bank(smmu_domain); - spin_unlock_irqrestore(&smmu_domain->lock, flags); + pgtbl_cfg = (struct io_pgtable_cfg) { + .pgsize_bitmap = arm_smmu_ops.pgsize_bitmap, + .ias = ias, + .oas = oas, + .tlb = &arm_smmu_gather_ops, + }; + smmu_domain->smmu = smmu; + pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain); + if (!pgtbl_ops) { + ret = -ENOMEM; + goto out_clear_smmu; + } + + /* Update our support page sizes to reflect the page table format */ + arm_smmu_ops.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap; + + /* Initialise the context bank with our page table cfg */ + arm_smmu_init_context_bank(smmu_domain, &pgtbl_cfg); + + /* + * Request context fault interrupt. Do this last to avoid the + * handler seeing a half-initialised domain state. + */ irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx]; ret = request_irq(irq, arm_smmu_context_fault, IRQF_SHARED, "arm-smmu-context-fault", domain); @@ -981,10 +943,16 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, cfg->irptndx = INVALID_IRPTNDX; } + mutex_unlock(&smmu_domain->init_mutex); + + /* Publish page table ops for map/unmap */ + smmu_domain->pgtbl_ops = pgtbl_ops; return 0; +out_clear_smmu: + smmu_domain->smmu = NULL; out_unlock: - spin_unlock_irqrestore(&smmu_domain->lock, flags); + mutex_unlock(&smmu_domain->init_mutex); return ret; } @@ -999,23 +967,27 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain) if (!smmu) return; - /* Disable the context bank and nuke the TLB before freeing it. */ + /* + * Disable the context bank and free the page tables before freeing + * it. + */ cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR); - arm_smmu_tlb_inv_context(smmu_domain); if (cfg->irptndx != INVALID_IRPTNDX) { irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx]; free_irq(irq, domain); } + if (smmu_domain->pgtbl_ops) + free_io_pgtable_ops(smmu_domain->pgtbl_ops); + __arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx); } static int arm_smmu_domain_init(struct iommu_domain *domain) { struct arm_smmu_domain *smmu_domain; - pgd_t *pgd; /* * Allocate the domain and initialise some of its data structures. @@ -1026,81 +998,10 @@ static int arm_smmu_domain_init(struct iommu_domain *domain) if (!smmu_domain) return -ENOMEM; - pgd = kcalloc(PTRS_PER_PGD, sizeof(pgd_t), GFP_KERNEL); - if (!pgd) - goto out_free_domain; - smmu_domain->cfg.pgd = pgd; - - spin_lock_init(&smmu_domain->lock); + mutex_init(&smmu_domain->init_mutex); + spin_lock_init(&smmu_domain->pgtbl_lock); domain->priv = smmu_domain; return 0; - -out_free_domain: - kfree(smmu_domain); - return -ENOMEM; -} - -static void arm_smmu_free_ptes(pmd_t *pmd) -{ - pgtable_t table = pmd_pgtable(*pmd); - - __free_page(table); -} - -static void arm_smmu_free_pmds(pud_t *pud) -{ - int i; - pmd_t *pmd, *pmd_base = pmd_offset(pud, 0); - - pmd = pmd_base; - for (i = 0; i < PTRS_PER_PMD; ++i) { - if (pmd_none(*pmd)) - continue; - - arm_smmu_free_ptes(pmd); - pmd++; - } - - pmd_free(NULL, pmd_base); -} - -static void arm_smmu_free_puds(pgd_t *pgd) -{ - int i; - pud_t *pud, *pud_base = pud_offset(pgd, 0); - - pud = pud_base; - for (i = 0; i < PTRS_PER_PUD; ++i) { - if (pud_none(*pud)) - continue; - - arm_smmu_free_pmds(pud); - pud++; - } - - pud_free(NULL, pud_base); -} - -static void arm_smmu_free_pgtables(struct arm_smmu_domain *smmu_domain) -{ - int i; - struct arm_smmu_cfg *cfg = &smmu_domain->cfg; - pgd_t *pgd, *pgd_base = cfg->pgd; - - /* - * Recursively free the page tables for this domain. We don't - * care about speculative TLB filling because the tables should - * not be active in any context bank at this point (SCTLR.M is 0). - */ - pgd = pgd_base; - for (i = 0; i < PTRS_PER_PGD; ++i) { - if (pgd_none(*pgd)) - continue; - arm_smmu_free_puds(pgd); - pgd++; - } - - kfree(pgd_base); } static void arm_smmu_domain_destroy(struct iommu_domain *domain) @@ -1112,7 +1013,6 @@ static void arm_smmu_domain_destroy(struct iommu_domain *domain) * already been detached. */ arm_smmu_destroy_domain_context(domain); - arm_smmu_free_pgtables(smmu_domain); kfree(smmu_domain); } @@ -1244,7 +1144,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) { int ret; struct arm_smmu_domain *smmu_domain = domain->priv; - struct arm_smmu_device *smmu, *dom_smmu; + struct arm_smmu_device *smmu; struct arm_smmu_master_cfg *cfg; smmu = find_smmu_for_device(dev); @@ -1258,21 +1158,16 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) return -EEXIST; } + /* Ensure that the domain is finalised */ + ret = arm_smmu_init_domain_context(domain, smmu); + if (IS_ERR_VALUE(ret)) + return ret; + /* * Sanity check the domain. We don't support domains across * different SMMUs. */ - dom_smmu = ACCESS_ONCE(smmu_domain->smmu); - if (!dom_smmu) { - /* Now that we have a master, we can finalise the domain */ - ret = arm_smmu_init_domain_context(domain, smmu); - if (IS_ERR_VALUE(ret)) - return ret; - - dom_smmu = smmu_domain->smmu; - } - - if (dom_smmu != smmu) { + if (smmu_domain->smmu != smmu) { dev_err(dev, "cannot attach to SMMU %s whilst already attached to domain on SMMU %s\n", dev_name(smmu_domain->smmu->dev), dev_name(smmu->dev)); @@ -1303,293 +1198,103 @@ static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev) arm_smmu_domain_remove_master(smmu_domain, cfg); } -static bool arm_smmu_pte_is_contiguous_range(unsigned long addr, - unsigned long end) -{ - return !(addr & ~ARM_SMMU_PTE_CONT_MASK) && - (addr + ARM_SMMU_PTE_CONT_SIZE <= end); -} - -static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd, - unsigned long addr, unsigned long end, - unsigned long pfn, int prot, int stage) -{ - pte_t *pte, *start; - pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF; - - if (pmd_none(*pmd)) { - /* Allocate a new set of tables */ - pgtable_t table = alloc_page(GFP_ATOMIC|__GFP_ZERO); - - if (!table) - return -ENOMEM; - - arm_smmu_flush_pgtable(smmu, page_address(table), PAGE_SIZE); - pmd_populate(NULL, pmd, table); - arm_smmu_flush_pgtable(smmu, pmd, sizeof(*pmd)); - } - - if (stage == 1) { - pteval |= ARM_SMMU_PTE_AP_UNPRIV | ARM_SMMU_PTE_nG; - if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ)) - pteval |= ARM_SMMU_PTE_AP_RDONLY; - - if (prot & IOMMU_CACHE) - pteval |= (MAIR_ATTR_IDX_CACHE << - ARM_SMMU_PTE_ATTRINDX_SHIFT); - } else { - pteval |= ARM_SMMU_PTE_HAP_FAULT; - if (prot & IOMMU_READ) - pteval |= ARM_SMMU_PTE_HAP_READ; - if (prot & IOMMU_WRITE) - pteval |= ARM_SMMU_PTE_HAP_WRITE; - if (prot & IOMMU_CACHE) - pteval |= ARM_SMMU_PTE_MEMATTR_OIWB; - else - pteval |= ARM_SMMU_PTE_MEMATTR_NC; - } - - if (prot & IOMMU_NOEXEC) - pteval |= ARM_SMMU_PTE_XN; - - /* If no access, create a faulting entry to avoid TLB fills */ - if (!(prot & (IOMMU_READ | IOMMU_WRITE))) - pteval &= ~ARM_SMMU_PTE_PAGE; - - pteval |= ARM_SMMU_PTE_SH_IS; - start = pmd_page_vaddr(*pmd) + pte_index(addr); - pte = start; - - /* - * Install the page table entries. This is fairly complicated - * since we attempt to make use of the contiguous hint in the - * ptes where possible. The contiguous hint indicates a series - * of ARM_SMMU_PTE_CONT_ENTRIES ptes mapping a physically - * contiguous region with the following constraints: - * - * - The region start is aligned to ARM_SMMU_PTE_CONT_SIZE - * - Each pte in the region has the contiguous hint bit set - * - * This complicates unmapping (also handled by this code, when - * neither IOMMU_READ or IOMMU_WRITE are set) because it is - * possible, yet highly unlikely, that a client may unmap only - * part of a contiguous range. This requires clearing of the - * contiguous hint bits in the range before installing the new - * faulting entries. - * - * Note that re-mapping an address range without first unmapping - * it is not supported, so TLB invalidation is not required here - * and is instead performed at unmap and domain-init time. - */ - do { - int i = 1; - - pteval &= ~ARM_SMMU_PTE_CONT; - - if (arm_smmu_pte_is_contiguous_range(addr, end)) { - i = ARM_SMMU_PTE_CONT_ENTRIES; - pteval |= ARM_SMMU_PTE_CONT; - } else if (pte_val(*pte) & - (ARM_SMMU_PTE_CONT | ARM_SMMU_PTE_PAGE)) { - int j; - pte_t *cont_start; - unsigned long idx = pte_index(addr); - - idx &= ~(ARM_SMMU_PTE_CONT_ENTRIES - 1); - cont_start = pmd_page_vaddr(*pmd) + idx; - for (j = 0; j < ARM_SMMU_PTE_CONT_ENTRIES; ++j) - pte_val(*(cont_start + j)) &= - ~ARM_SMMU_PTE_CONT; - - arm_smmu_flush_pgtable(smmu, cont_start, - sizeof(*pte) * - ARM_SMMU_PTE_CONT_ENTRIES); - } - - do { - *pte = pfn_pte(pfn, __pgprot(pteval)); - } while (pte++, pfn++, addr += PAGE_SIZE, --i); - } while (addr != end); - - arm_smmu_flush_pgtable(smmu, start, sizeof(*pte) * (pte - start)); - return 0; -} - -static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud, - unsigned long addr, unsigned long end, - phys_addr_t phys, int prot, int stage) -{ - int ret; - pmd_t *pmd; - unsigned long next, pfn = __phys_to_pfn(phys); - -#ifndef __PAGETABLE_PMD_FOLDED - if (pud_none(*pud)) { - pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC); - if (!pmd) - return -ENOMEM; - - arm_smmu_flush_pgtable(smmu, pmd, PAGE_SIZE); - pud_populate(NULL, pud, pmd); - arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud)); - - pmd += pmd_index(addr); - } else -#endif - pmd = pmd_offset(pud, addr); - - do { - next = pmd_addr_end(addr, end); - ret = arm_smmu_alloc_init_pte(smmu, pmd, addr, next, pfn, - prot, stage); - phys += next - addr; - pfn = __phys_to_pfn(phys); - } while (pmd++, addr = next, addr < end); - - return ret; -} - -static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd, - unsigned long addr, unsigned long end, - phys_addr_t phys, int prot, int stage) -{ - int ret = 0; - pud_t *pud; - unsigned long next; - -#ifndef __PAGETABLE_PUD_FOLDED - if (pgd_none(*pgd)) { - pud = (pud_t *)get_zeroed_page(GFP_ATOMIC); - if (!pud) - return -ENOMEM; - - arm_smmu_flush_pgtable(smmu, pud, PAGE_SIZE); - pgd_populate(NULL, pgd, pud); - arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd)); - - pud += pud_index(addr); - } else -#endif - pud = pud_offset(pgd, addr); - - do { - next = pud_addr_end(addr, end); - ret = arm_smmu_alloc_init_pmd(smmu, pud, addr, next, phys, - prot, stage); - phys += next - addr; - } while (pud++, addr = next, addr < end); - - return ret; -} - -static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain, - unsigned long iova, phys_addr_t paddr, - size_t size, int prot) -{ - int ret, stage; - unsigned long end; - phys_addr_t input_mask, output_mask; - struct arm_smmu_device *smmu = smmu_domain->smmu; - struct arm_smmu_cfg *cfg = &smmu_domain->cfg; - pgd_t *pgd = cfg->pgd; - unsigned long flags; - - if (cfg->cbar == CBAR_TYPE_S2_TRANS) { - stage = 2; - input_mask = (1ULL << smmu->s2_input_size) - 1; - output_mask = (1ULL << smmu->s2_output_size) - 1; - } else { - stage = 1; - input_mask = (1ULL << smmu->s1_input_size) - 1; - output_mask = (1ULL << smmu->s1_output_size) - 1; - } - - if (!pgd) - return -EINVAL; - - if (size & ~PAGE_MASK) - return -EINVAL; - - if ((phys_addr_t)iova & ~input_mask) - return -ERANGE; - - if (paddr & ~output_mask) - return -ERANGE; - - spin_lock_irqsave(&smmu_domain->lock, flags); - pgd += pgd_index(iova); - end = iova + size; - do { - unsigned long next = pgd_addr_end(iova, end); - - ret = arm_smmu_alloc_init_pud(smmu, pgd, iova, next, paddr, - prot, stage); - if (ret) - goto out_unlock; - - paddr += next - iova; - iova = next; - } while (pgd++, iova != end); - -out_unlock: - spin_unlock_irqrestore(&smmu_domain->lock, flags); - - return ret; -} - static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t size, int prot) { + int ret; + unsigned long flags; struct arm_smmu_domain *smmu_domain = domain->priv; + struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops; - if (!smmu_domain) + if (!ops) return -ENODEV; - return arm_smmu_handle_mapping(smmu_domain, iova, paddr, size, prot); + spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags); + ret = ops->map(ops, iova, paddr, size, prot); + spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags); + return ret; } static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) { - int ret; + size_t ret; + unsigned long flags; struct arm_smmu_domain *smmu_domain = domain->priv; + struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops; - ret = arm_smmu_handle_mapping(smmu_domain, iova, 0, size, 0); - arm_smmu_tlb_inv_context(smmu_domain); - return ret ? 0 : size; + if (!ops) + return 0; + + spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags); + ret = ops->unmap(ops, iova, size); + spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags); + return ret; +} + +static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain, + dma_addr_t iova) +{ + struct arm_smmu_domain *smmu_domain = domain->priv; + struct arm_smmu_device *smmu = smmu_domain->smmu; + struct arm_smmu_cfg *cfg = &smmu_domain->cfg; + struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops; + struct device *dev = smmu->dev; + void __iomem *cb_base; + u32 tmp; + u64 phys; + + cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); + + if (smmu->version == 1) { + u32 reg = iova & ~0xfff; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_ATS1PR_LO); + } else { + u32 reg = iova & ~0xfff; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_ATS1PR_LO); + reg = ((u64)iova & ~0xfff) >> 32; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_ATS1PR_HI); + } + + if (readl_poll_timeout_atomic(cb_base + ARM_SMMU_CB_ATSR, tmp, + !(tmp & ATSR_ACTIVE), 5, 50)) { + dev_err(dev, + "iova to phys timed out on 0x%pad. Falling back to software table walk.\n", + &iova); + return ops->iova_to_phys(ops, iova); + } + + phys = readl_relaxed(cb_base + ARM_SMMU_CB_PAR_LO); + phys |= ((u64)readl_relaxed(cb_base + ARM_SMMU_CB_PAR_HI)) << 32; + + if (phys & CB_PAR_F) { + dev_err(dev, "translation fault!\n"); + dev_err(dev, "PAR = 0x%llx\n", phys); + return 0; + } + + return (phys & GENMASK_ULL(39, 12)) | (iova & 0xfff); } static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain, - dma_addr_t iova) + dma_addr_t iova) { - pgd_t *pgdp, pgd; - pud_t pud; - pmd_t pmd; - pte_t pte; + phys_addr_t ret; + unsigned long flags; struct arm_smmu_domain *smmu_domain = domain->priv; - struct arm_smmu_cfg *cfg = &smmu_domain->cfg; + struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops; - pgdp = cfg->pgd; - if (!pgdp) + if (!ops) return 0; - pgd = *(pgdp + pgd_index(iova)); - if (pgd_none(pgd)) - return 0; + spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags); + if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS) + ret = arm_smmu_iova_to_phys_hard(domain, iova); + else + ret = ops->iova_to_phys(ops, iova); + spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags); - pud = *pud_offset(&pgd, iova); - if (pud_none(pud)) - return 0; - - pmd = *pmd_offset(&pud, iova); - if (pmd_none(pmd)) - return 0; - - pte = *(pmd_page_vaddr(pmd) + pte_index(iova)); - if (pte_none(pte)) - return 0; - - return __pfn_to_phys(pte_pfn(pte)) | (iova & ~PAGE_MASK); + return ret; } static bool arm_smmu_capable(enum iommu_cap cap) @@ -1698,24 +1403,34 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain, static int arm_smmu_domain_set_attr(struct iommu_domain *domain, enum iommu_attr attr, void *data) { + int ret = 0; struct arm_smmu_domain *smmu_domain = domain->priv; + mutex_lock(&smmu_domain->init_mutex); + switch (attr) { case DOMAIN_ATTR_NESTING: - if (smmu_domain->smmu) - return -EPERM; + if (smmu_domain->smmu) { + ret = -EPERM; + goto out_unlock; + } + if (*(int *)data) smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED; else smmu_domain->stage = ARM_SMMU_DOMAIN_S1; - return 0; + break; default: - return -ENODEV; + ret = -ENODEV; } + +out_unlock: + mutex_unlock(&smmu_domain->init_mutex); + return ret; } -static const struct iommu_ops arm_smmu_ops = { +static struct iommu_ops arm_smmu_ops = { .capable = arm_smmu_capable, .domain_init = arm_smmu_domain_init, .domain_destroy = arm_smmu_domain_destroy, @@ -1729,9 +1444,7 @@ static const struct iommu_ops arm_smmu_ops = { .remove_device = arm_smmu_remove_device, .domain_get_attr = arm_smmu_domain_get_attr, .domain_set_attr = arm_smmu_domain_set_attr, - .pgsize_bitmap = (SECTION_SIZE | - ARM_SMMU_PTE_CONT_SIZE | - PAGE_SIZE), + .pgsize_bitmap = -1UL, /* Restricted during device attach */ }; static void arm_smmu_device_reset(struct arm_smmu_device *smmu) @@ -1760,7 +1473,6 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) } /* Invalidate the TLB, just in case */ - writel_relaxed(0, gr0_base + ARM_SMMU_GR0_STLBIALL); writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLH); writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLNSNH); @@ -1782,7 +1494,7 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) reg &= ~(sCR0_BSU_MASK << sCR0_BSU_SHIFT); /* Push the button */ - arm_smmu_tlb_sync(smmu); + __arm_smmu_tlb_sync(smmu); writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0); } @@ -1816,12 +1528,6 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) /* ID0 */ id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID0); -#ifndef CONFIG_64BIT - if (((id >> ID0_PTFS_SHIFT) & ID0_PTFS_MASK) == ID0_PTFS_V8_ONLY) { - dev_err(smmu->dev, "\tno v7 descriptor support!\n"); - return -ENODEV; - } -#endif /* Restrict available stages based on module parameter */ if (force_stage == 1) @@ -1850,6 +1556,11 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) return -ENODEV; } + if (smmu->version == 1 || (!(id & ID0_ATOSNS) && (id & ID0_S1TS))) { + smmu->features |= ARM_SMMU_FEAT_TRANS_OPS; + dev_notice(smmu->dev, "\taddress translation ops\n"); + } + if (id & ID0_CTTW) { smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK; dev_notice(smmu->dev, "\tcoherent table walk\n"); @@ -1894,16 +1605,14 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) smmu->pgshift = (id & ID1_PAGESIZE) ? 16 : 12; /* Check for size mismatch of SMMU address space from mapped region */ - size = 1 << - (((id >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1); + size = 1 << (((id >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1); size *= 2 << smmu->pgshift; if (smmu->size != size) dev_warn(smmu->dev, "SMMU address space size (0x%lx) differs from mapped region size (0x%lx)!\n", size, smmu->size); - smmu->num_s2_context_banks = (id >> ID1_NUMS2CB_SHIFT) & - ID1_NUMS2CB_MASK; + smmu->num_s2_context_banks = (id >> ID1_NUMS2CB_SHIFT) & ID1_NUMS2CB_MASK; smmu->num_context_banks = (id >> ID1_NUMCB_SHIFT) & ID1_NUMCB_MASK; if (smmu->num_s2_context_banks > smmu->num_context_banks) { dev_err(smmu->dev, "impossible number of S2 context banks!\n"); @@ -1915,46 +1624,40 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) /* ID2 */ id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID2); size = arm_smmu_id_size_to_bits((id >> ID2_IAS_SHIFT) & ID2_IAS_MASK); - smmu->s1_output_size = min_t(unsigned long, PHYS_MASK_SHIFT, size); + smmu->ipa_size = size; - /* Stage-2 input size limited due to pgd allocation (PTRS_PER_PGD) */ -#ifdef CONFIG_64BIT - smmu->s2_input_size = min_t(unsigned long, VA_BITS, size); -#else - smmu->s2_input_size = min(32UL, size); -#endif - - /* The stage-2 output mask is also applied for bypass */ + /* The output mask is also applied for bypass */ size = arm_smmu_id_size_to_bits((id >> ID2_OAS_SHIFT) & ID2_OAS_MASK); - smmu->s2_output_size = min_t(unsigned long, PHYS_MASK_SHIFT, size); + smmu->pa_size = size; if (smmu->version == ARM_SMMU_V1) { - smmu->s1_input_size = 32; + smmu->va_size = smmu->ipa_size; + size = SZ_4K | SZ_2M | SZ_1G; } else { -#ifdef CONFIG_64BIT size = (id >> ID2_UBS_SHIFT) & ID2_UBS_MASK; - size = min(VA_BITS, arm_smmu_id_size_to_bits(size)); -#else - size = 32; + smmu->va_size = arm_smmu_id_size_to_bits(size); +#ifndef CONFIG_64BIT + smmu->va_size = min(32UL, smmu->va_size); #endif - smmu->s1_input_size = size; - - if ((PAGE_SIZE == SZ_4K && !(id & ID2_PTFS_4K)) || - (PAGE_SIZE == SZ_64K && !(id & ID2_PTFS_64K)) || - (PAGE_SIZE != SZ_4K && PAGE_SIZE != SZ_64K)) { - dev_err(smmu->dev, "CPU page size 0x%lx unsupported\n", - PAGE_SIZE); - return -ENODEV; - } + size = 0; + if (id & ID2_PTFS_4K) + size |= SZ_4K | SZ_2M | SZ_1G; + if (id & ID2_PTFS_16K) + size |= SZ_16K | SZ_32M; + if (id & ID2_PTFS_64K) + size |= SZ_64K | SZ_512M; } + arm_smmu_ops.pgsize_bitmap &= size; + dev_notice(smmu->dev, "\tSupported page sizes: 0x%08lx\n", size); + if (smmu->features & ARM_SMMU_FEAT_TRANS_S1) dev_notice(smmu->dev, "\tStage-1: %lu-bit VA -> %lu-bit IPA\n", - smmu->s1_input_size, smmu->s1_output_size); + smmu->va_size, smmu->ipa_size); if (smmu->features & ARM_SMMU_FEAT_TRANS_S2) dev_notice(smmu->dev, "\tStage-2: %lu-bit IPA -> %lu-bit PA\n", - smmu->s2_input_size, smmu->s2_output_size); + smmu->ipa_size, smmu->pa_size); return 0; } diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c index 80ac68d884c5..abeedc9a78c2 100644 --- a/drivers/iommu/fsl_pamu.c +++ b/drivers/iommu/fsl_pamu.c @@ -18,23 +18,14 @@ #define pr_fmt(fmt) "fsl-pamu: %s: " fmt, __func__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "fsl_pamu.h" +#include +#include + +#include +#include + /* define indexes for each operation mapping scenario */ #define OMI_QMAN 0x00 #define OMI_FMAN 0x01 @@ -44,13 +35,13 @@ #define make64(high, low) (((u64)(high) << 32) | (low)) struct pamu_isr_data { - void __iomem *pamu_reg_base; /* Base address of PAMU regs*/ + void __iomem *pamu_reg_base; /* Base address of PAMU regs */ unsigned int count; /* The number of PAMUs */ }; static struct paace *ppaact; static struct paace *spaact; -static struct ome *omt; +static struct ome *omt __initdata; /* * Table for matching compatible strings, for device tree @@ -58,14 +49,13 @@ static struct ome *omt; * "fsl,qoriq-device-config-2.0" corresponds to T4 & B4 * SOCs. For the older SOCs "fsl,qoriq-device-config-1.0" * string would be used. -*/ -static const struct of_device_id guts_device_ids[] = { + */ +static const struct of_device_id guts_device_ids[] __initconst = { { .compatible = "fsl,qoriq-device-config-1.0", }, { .compatible = "fsl,qoriq-device-config-2.0", }, {} }; - /* * Table for matching compatible strings, for device tree * L3 cache controller node. @@ -73,7 +63,7 @@ static const struct of_device_id guts_device_ids[] = { * "fsl,b4860-l3-cache-controller" corresponds to B4 & * "fsl,p4080-l3-cache-controller" corresponds to other, * SOCs. -*/ + */ static const struct of_device_id l3_device_ids[] = { { .compatible = "fsl,t4240-l3-cache-controller", }, { .compatible = "fsl,b4860-l3-cache-controller", }, @@ -85,7 +75,7 @@ static const struct of_device_id l3_device_ids[] = { static u32 max_subwindow_count; /* Pool for fspi allocation */ -struct gen_pool *spaace_pool; +static struct gen_pool *spaace_pool; /** * pamu_get_max_subwin_cnt() - Return the maximum supported @@ -170,7 +160,7 @@ int pamu_disable_liodn(int liodn) static unsigned int map_addrspace_size_to_wse(phys_addr_t addrspace_size) { /* Bug if not a power of 2 */ - BUG_ON((addrspace_size & (addrspace_size - 1))); + BUG_ON(addrspace_size & (addrspace_size - 1)); /* window size is 2^(WSE+1) bytes */ return fls64(addrspace_size) - 2; @@ -179,8 +169,8 @@ static unsigned int map_addrspace_size_to_wse(phys_addr_t addrspace_size) /* Derive the PAACE window count encoding for the subwindow count */ static unsigned int map_subwindow_cnt_to_wce(u32 subwindow_cnt) { - /* window count is 2^(WCE+1) bytes */ - return __ffs(subwindow_cnt) - 1; + /* window count is 2^(WCE+1) bytes */ + return __ffs(subwindow_cnt) - 1; } /* @@ -241,7 +231,7 @@ static struct paace *pamu_get_spaace(struct paace *paace, u32 wnum) * If no SPAACE entry is available or the allocator can not reserve the required * number of contiguous entries function returns ULONG_MAX indicating a failure. * -*/ + */ static unsigned long pamu_get_fspi_and_allocate(u32 subwin_cnt) { unsigned long spaace_addr; @@ -288,9 +278,8 @@ int pamu_update_paace_stash(int liodn, u32 subwin, u32 value) } if (subwin) { paace = pamu_get_spaace(paace, subwin - 1); - if (!paace) { + if (!paace) return -ENOENT; - } } set_bf(paace->impl_attr, PAACE_IA_CID, value); @@ -311,14 +300,12 @@ int pamu_disable_spaace(int liodn, u32 subwin) } if (subwin) { paace = pamu_get_spaace(paace, subwin - 1); - if (!paace) { + if (!paace) return -ENOENT; - } - set_bf(paace->addr_bitfields, PAACE_AF_V, - PAACE_V_INVALID); + set_bf(paace->addr_bitfields, PAACE_AF_V, PAACE_V_INVALID); } else { set_bf(paace->addr_bitfields, PAACE_AF_AP, - PAACE_AP_PERMS_DENIED); + PAACE_AP_PERMS_DENIED); } mb(); @@ -326,7 +313,6 @@ int pamu_disable_spaace(int liodn, u32 subwin) return 0; } - /** * pamu_config_paace() - Sets up PPAACE entry for specified liodn * @@ -352,7 +338,8 @@ int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t win_size, unsigned long fspi; if ((win_size & (win_size - 1)) || win_size < PAMU_PAGE_SIZE) { - pr_debug("window size too small or not a power of two %llx\n", win_size); + pr_debug("window size too small or not a power of two %pa\n", + &win_size); return -EINVAL; } @@ -362,13 +349,12 @@ int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t win_size, } ppaace = pamu_get_ppaace(liodn); - if (!ppaace) { + if (!ppaace) return -ENOENT; - } /* window size is 2^(WSE+1) bytes */ set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE, - map_addrspace_size_to_wse(win_size)); + map_addrspace_size_to_wse(win_size)); pamu_init_ppaace(ppaace); @@ -442,7 +428,6 @@ int pamu_config_spaace(int liodn, u32 subwin_cnt, u32 subwin, { struct paace *paace; - /* setup sub-windows */ if (!subwin_cnt) { pr_debug("Invalid subwindow count\n"); @@ -510,11 +495,11 @@ int pamu_config_spaace(int liodn, u32 subwin_cnt, u32 subwin, } /** -* get_ome_index() - Returns the index in the operation mapping table -* for device. -* @*omi_index: pointer for storing the index value -* -*/ + * get_ome_index() - Returns the index in the operation mapping table + * for device. + * @*omi_index: pointer for storing the index value + * + */ void get_ome_index(u32 *omi_index, struct device *dev) { if (of_device_is_compatible(dev->of_node, "fsl,qman-portal")) @@ -544,9 +529,10 @@ u32 get_stash_id(u32 stash_dest_hint, u32 vcpu) if (stash_dest_hint == PAMU_ATTR_CACHE_L3) { node = of_find_matching_node(NULL, l3_device_ids); if (node) { - prop = of_get_property(node, "cache-stash-id", 0); + prop = of_get_property(node, "cache-stash-id", NULL); if (!prop) { - pr_debug("missing cache-stash-id at %s\n", node->full_name); + pr_debug("missing cache-stash-id at %s\n", + node->full_name); of_node_put(node); return ~(u32)0; } @@ -570,9 +556,10 @@ found_cpu_node: /* find the hwnode that represents the cache */ for (cache_level = PAMU_ATTR_CACHE_L1; (cache_level < PAMU_ATTR_CACHE_L3) && found; cache_level++) { if (stash_dest_hint == cache_level) { - prop = of_get_property(node, "cache-stash-id", 0); + prop = of_get_property(node, "cache-stash-id", NULL); if (!prop) { - pr_debug("missing cache-stash-id at %s\n", node->full_name); + pr_debug("missing cache-stash-id at %s\n", + node->full_name); of_node_put(node); return ~(u32)0; } @@ -580,10 +567,10 @@ found_cpu_node: return be32_to_cpup(prop); } - prop = of_get_property(node, "next-level-cache", 0); + prop = of_get_property(node, "next-level-cache", NULL); if (!prop) { pr_debug("can't find next-level-cache at %s\n", - node->full_name); + node->full_name); of_node_put(node); return ~(u32)0; /* can't traverse any further */ } @@ -598,7 +585,7 @@ found_cpu_node: } pr_debug("stash dest not found for %d on vcpu %d\n", - stash_dest_hint, vcpu); + stash_dest_hint, vcpu); return ~(u32)0; } @@ -612,7 +599,7 @@ found_cpu_node: * Memory accesses to QMAN and BMAN private memory need not be coherent, so * clear the PAACE entry coherency attribute for them. */ -static void setup_qbman_paace(struct paace *ppaace, int paace_type) +static void __init setup_qbman_paace(struct paace *ppaace, int paace_type) { switch (paace_type) { case QMAN_PAACE: @@ -626,7 +613,7 @@ static void setup_qbman_paace(struct paace *ppaace, int paace_type) case QMAN_PORTAL_PAACE: set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED); ppaace->op_encode.index_ot.omi = OMI_QMAN; - /*Set DQRR and Frame stashing for the L3 cache */ + /* Set DQRR and Frame stashing for the L3 cache */ set_bf(ppaace->impl_attr, PAACE_IA_CID, get_stash_id(PAMU_ATTR_CACHE_L3, 0)); break; case BMAN_PAACE: @@ -679,7 +666,7 @@ static void __init setup_omt(struct ome *omt) * Get the maximum number of PAACT table entries * and subwindows supported by PAMU */ -static void get_pamu_cap_values(unsigned long pamu_reg_base) +static void __init get_pamu_cap_values(unsigned long pamu_reg_base) { u32 pc_val; @@ -689,9 +676,9 @@ static void get_pamu_cap_values(unsigned long pamu_reg_base) } /* Setup PAMU registers pointing to PAACT, SPAACT and OMT */ -int setup_one_pamu(unsigned long pamu_reg_base, unsigned long pamu_reg_size, - phys_addr_t ppaact_phys, phys_addr_t spaact_phys, - phys_addr_t omt_phys) +static int __init setup_one_pamu(unsigned long pamu_reg_base, unsigned long pamu_reg_size, + phys_addr_t ppaact_phys, phys_addr_t spaact_phys, + phys_addr_t omt_phys) { u32 *pc; struct pamu_mmap_regs *pamu_regs; @@ -727,7 +714,7 @@ int setup_one_pamu(unsigned long pamu_reg_base, unsigned long pamu_reg_size, */ out_be32((u32 *)(pamu_reg_base + PAMU_PICS), - PAMU_ACCESS_VIOLATION_ENABLE); + PAMU_ACCESS_VIOLATION_ENABLE); out_be32(pc, PAMU_PC_PE | PAMU_PC_OCE | PAMU_PC_SPCC | PAMU_PC_PPCC); return 0; } @@ -757,9 +744,9 @@ static void __init setup_liodns(void) ppaace->wbah = 0; set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL, 0); set_bf(ppaace->impl_attr, PAACE_IA_ATM, - PAACE_ATM_NO_XLATE); + PAACE_ATM_NO_XLATE); set_bf(ppaace->addr_bitfields, PAACE_AF_AP, - PAACE_AP_PERMS_ALL); + PAACE_AP_PERMS_ALL); if (of_device_is_compatible(node, "fsl,qman-portal")) setup_qbman_paace(ppaace, QMAN_PORTAL_PAACE); if (of_device_is_compatible(node, "fsl,qman")) @@ -772,7 +759,7 @@ static void __init setup_liodns(void) } } -irqreturn_t pamu_av_isr(int irq, void *arg) +static irqreturn_t pamu_av_isr(int irq, void *arg) { struct pamu_isr_data *data = arg; phys_addr_t phys; @@ -792,14 +779,16 @@ irqreturn_t pamu_av_isr(int irq, void *arg) pr_emerg("POES2=%08x\n", in_be32(p + PAMU_POES2)); pr_emerg("AVS1=%08x\n", avs1); pr_emerg("AVS2=%08x\n", in_be32(p + PAMU_AVS2)); - pr_emerg("AVA=%016llx\n", make64(in_be32(p + PAMU_AVAH), - in_be32(p + PAMU_AVAL))); + pr_emerg("AVA=%016llx\n", + make64(in_be32(p + PAMU_AVAH), + in_be32(p + PAMU_AVAL))); pr_emerg("UDAD=%08x\n", in_be32(p + PAMU_UDAD)); - pr_emerg("POEA=%016llx\n", make64(in_be32(p + PAMU_POEAH), - in_be32(p + PAMU_POEAL))); + pr_emerg("POEA=%016llx\n", + make64(in_be32(p + PAMU_POEAH), + in_be32(p + PAMU_POEAL))); phys = make64(in_be32(p + PAMU_POEAH), - in_be32(p + PAMU_POEAL)); + in_be32(p + PAMU_POEAL)); /* Assume that POEA points to a PAACE */ if (phys) { @@ -807,11 +796,12 @@ irqreturn_t pamu_av_isr(int irq, void *arg) /* Only the first four words are relevant */ for (j = 0; j < 4; j++) - pr_emerg("PAACE[%u]=%08x\n", j, in_be32(paace + j)); + pr_emerg("PAACE[%u]=%08x\n", + j, in_be32(paace + j)); } /* clear access violation condition */ - out_be32((p + PAMU_AVS1), avs1 & PAMU_AV_MASK); + out_be32(p + PAMU_AVS1, avs1 & PAMU_AV_MASK); paace = pamu_get_ppaace(avs1 >> PAMU_AVS1_LIODN_SHIFT); BUG_ON(!paace); /* check if we got a violation for a disabled LIODN */ @@ -827,13 +817,13 @@ irqreturn_t pamu_av_isr(int irq, void *arg) /* Disable the LIODN */ ret = pamu_disable_liodn(avs1 >> PAMU_AVS1_LIODN_SHIFT); BUG_ON(ret); - pr_emerg("Disabling liodn %x\n", avs1 >> PAMU_AVS1_LIODN_SHIFT); + pr_emerg("Disabling liodn %x\n", + avs1 >> PAMU_AVS1_LIODN_SHIFT); } out_be32((p + PAMU_PICS), pics); } } - return IRQ_HANDLED; } @@ -952,7 +942,7 @@ static int __init create_csd(phys_addr_t phys, size_t size, u32 csd_port_id) } if (i == 0 || i == num_laws) { - /* This should never happen*/ + /* This should never happen */ ret = -ENOENT; goto error; } @@ -998,26 +988,27 @@ error: static const struct { u32 svr; u32 port_id; -} port_id_map[] = { - {0x82100010, 0xFF000000}, /* P2040 1.0 */ - {0x82100011, 0xFF000000}, /* P2040 1.1 */ - {0x82100110, 0xFF000000}, /* P2041 1.0 */ - {0x82100111, 0xFF000000}, /* P2041 1.1 */ - {0x82110310, 0xFF000000}, /* P3041 1.0 */ - {0x82110311, 0xFF000000}, /* P3041 1.1 */ - {0x82010020, 0xFFF80000}, /* P4040 2.0 */ - {0x82000020, 0xFFF80000}, /* P4080 2.0 */ - {0x82210010, 0xFC000000}, /* P5010 1.0 */ - {0x82210020, 0xFC000000}, /* P5010 2.0 */ - {0x82200010, 0xFC000000}, /* P5020 1.0 */ - {0x82050010, 0xFF800000}, /* P5021 1.0 */ - {0x82040010, 0xFF800000}, /* P5040 1.0 */ +} port_id_map[] __initconst = { + {(SVR_P2040 << 8) | 0x10, 0xFF000000}, /* P2040 1.0 */ + {(SVR_P2040 << 8) | 0x11, 0xFF000000}, /* P2040 1.1 */ + {(SVR_P2041 << 8) | 0x10, 0xFF000000}, /* P2041 1.0 */ + {(SVR_P2041 << 8) | 0x11, 0xFF000000}, /* P2041 1.1 */ + {(SVR_P3041 << 8) | 0x10, 0xFF000000}, /* P3041 1.0 */ + {(SVR_P3041 << 8) | 0x11, 0xFF000000}, /* P3041 1.1 */ + {(SVR_P4040 << 8) | 0x20, 0xFFF80000}, /* P4040 2.0 */ + {(SVR_P4080 << 8) | 0x20, 0xFFF80000}, /* P4080 2.0 */ + {(SVR_P5010 << 8) | 0x10, 0xFC000000}, /* P5010 1.0 */ + {(SVR_P5010 << 8) | 0x20, 0xFC000000}, /* P5010 2.0 */ + {(SVR_P5020 << 8) | 0x10, 0xFC000000}, /* P5020 1.0 */ + {(SVR_P5021 << 8) | 0x10, 0xFF800000}, /* P5021 1.0 */ + {(SVR_P5040 << 8) | 0x10, 0xFF800000}, /* P5040 1.0 */ }; #define SVR_SECURITY 0x80000 /* The Security (E) bit */ static int __init fsl_pamu_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; void __iomem *pamu_regs = NULL; struct ccsr_guts __iomem *guts_regs = NULL; u32 pamubypenr, pamu_counter; @@ -1042,22 +1033,21 @@ static int __init fsl_pamu_probe(struct platform_device *pdev) * NOTE : All PAMUs share the same LIODN tables. */ - pamu_regs = of_iomap(pdev->dev.of_node, 0); + pamu_regs = of_iomap(dev->of_node, 0); if (!pamu_regs) { - dev_err(&pdev->dev, "ioremap of PAMU node failed\n"); + dev_err(dev, "ioremap of PAMU node failed\n"); return -ENOMEM; } - of_get_address(pdev->dev.of_node, 0, &size, NULL); + of_get_address(dev->of_node, 0, &size, NULL); - irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + irq = irq_of_parse_and_map(dev->of_node, 0); if (irq == NO_IRQ) { - dev_warn(&pdev->dev, "no interrupts listed in PAMU node\n"); + dev_warn(dev, "no interrupts listed in PAMU node\n"); goto error; } - data = kzalloc(sizeof(struct pamu_isr_data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) { - dev_err(&pdev->dev, "PAMU isr data memory allocation failed\n"); ret = -ENOMEM; goto error; } @@ -1067,15 +1057,14 @@ static int __init fsl_pamu_probe(struct platform_device *pdev) /* The ISR needs access to the regs, so we won't iounmap them */ ret = request_irq(irq, pamu_av_isr, 0, "pamu", data); if (ret < 0) { - dev_err(&pdev->dev, "error %i installing ISR for irq %i\n", - ret, irq); + dev_err(dev, "error %i installing ISR for irq %i\n", ret, irq); goto error; } guts_node = of_find_matching_node(NULL, guts_device_ids); if (!guts_node) { - dev_err(&pdev->dev, "could not find GUTS node %s\n", - pdev->dev.of_node->full_name); + dev_err(dev, "could not find GUTS node %s\n", + dev->of_node->full_name); ret = -ENODEV; goto error; } @@ -1083,7 +1072,7 @@ static int __init fsl_pamu_probe(struct platform_device *pdev) guts_regs = of_iomap(guts_node, 0); of_node_put(guts_node); if (!guts_regs) { - dev_err(&pdev->dev, "ioremap of GUTS node failed\n"); + dev_err(dev, "ioremap of GUTS node failed\n"); ret = -ENODEV; goto error; } @@ -1103,7 +1092,7 @@ static int __init fsl_pamu_probe(struct platform_device *pdev) p = alloc_pages(GFP_KERNEL | __GFP_ZERO, order); if (!p) { - dev_err(&pdev->dev, "unable to allocate PAACT/SPAACT/OMT block\n"); + dev_err(dev, "unable to allocate PAACT/SPAACT/OMT block\n"); ret = -ENOMEM; goto error; } @@ -1113,7 +1102,7 @@ static int __init fsl_pamu_probe(struct platform_device *pdev) /* Make sure the memory is naturally aligned */ if (ppaact_phys & ((PAGE_SIZE << order) - 1)) { - dev_err(&pdev->dev, "PAACT/OMT block is unaligned\n"); + dev_err(dev, "PAACT/OMT block is unaligned\n"); ret = -ENOMEM; goto error; } @@ -1121,8 +1110,7 @@ static int __init fsl_pamu_probe(struct platform_device *pdev) spaact = (void *)ppaact + (PAGE_SIZE << get_order(PAACT_SIZE)); omt = (void *)spaact + (PAGE_SIZE << get_order(SPAACT_SIZE)); - dev_dbg(&pdev->dev, "ppaact virt=%p phys=0x%llx\n", ppaact, - (unsigned long long) ppaact_phys); + dev_dbg(dev, "ppaact virt=%p phys=%pa\n", ppaact, &ppaact_phys); /* Check to see if we need to implement the work-around on this SOC */ @@ -1130,21 +1118,19 @@ static int __init fsl_pamu_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(port_id_map); i++) { if (port_id_map[i].svr == (mfspr(SPRN_SVR) & ~SVR_SECURITY)) { csd_port_id = port_id_map[i].port_id; - dev_dbg(&pdev->dev, "found matching SVR %08x\n", + dev_dbg(dev, "found matching SVR %08x\n", port_id_map[i].svr); break; } } if (csd_port_id) { - dev_dbg(&pdev->dev, "creating coherency subdomain at address " - "0x%llx, size %zu, port id 0x%08x", ppaact_phys, - mem_size, csd_port_id); + dev_dbg(dev, "creating coherency subdomain at address %pa, size %zu, port id 0x%08x", + &ppaact_phys, mem_size, csd_port_id); ret = create_csd(ppaact_phys, mem_size, csd_port_id); if (ret) { - dev_err(&pdev->dev, "could not create coherence " - "subdomain\n"); + dev_err(dev, "could not create coherence subdomain\n"); return ret; } } @@ -1155,7 +1141,7 @@ static int __init fsl_pamu_probe(struct platform_device *pdev) spaace_pool = gen_pool_create(ilog2(sizeof(struct paace)), -1); if (!spaace_pool) { ret = -ENOMEM; - dev_err(&pdev->dev, "PAMU : failed to allocate spaace gen pool\n"); + dev_err(dev, "Failed to allocate spaace gen pool\n"); goto error; } @@ -1168,9 +1154,9 @@ static int __init fsl_pamu_probe(struct platform_device *pdev) for (pamu_reg_off = 0, pamu_counter = 0x80000000; pamu_reg_off < size; pamu_reg_off += PAMU_OFFSET, pamu_counter >>= 1) { - pamu_reg_base = (unsigned long) pamu_regs + pamu_reg_off; + pamu_reg_base = (unsigned long)pamu_regs + pamu_reg_off; setup_one_pamu(pamu_reg_base, pamu_reg_off, ppaact_phys, - spaact_phys, omt_phys); + spaact_phys, omt_phys); /* Disable PAMU bypass for this PAMU */ pamubypenr &= ~pamu_counter; } @@ -1182,7 +1168,7 @@ static int __init fsl_pamu_probe(struct platform_device *pdev) iounmap(guts_regs); - /* Enable DMA for the LIODNs in the device tree*/ + /* Enable DMA for the LIODNs in the device tree */ setup_liodns(); @@ -1214,17 +1200,7 @@ error: return ret; } -static const struct of_device_id fsl_of_pamu_ids[] = { - { - .compatible = "fsl,p4080-pamu", - }, - { - .compatible = "fsl,pamu", - }, - {}, -}; - -static struct platform_driver fsl_of_pamu_driver = { +static struct platform_driver fsl_of_pamu_driver __initdata = { .driver = { .name = "fsl-of-pamu", }, diff --git a/drivers/iommu/fsl_pamu.h b/drivers/iommu/fsl_pamu.h index 8fc1a125b16e..aab723f91f12 100644 --- a/drivers/iommu/fsl_pamu.h +++ b/drivers/iommu/fsl_pamu.h @@ -19,13 +19,15 @@ #ifndef __FSL_PAMU_H #define __FSL_PAMU_H +#include + #include /* Bit Field macros * v = bit field variable; m = mask, m##_SHIFT = shift, x = value to load */ -#define set_bf(v, m, x) (v = ((v) & ~(m)) | (((x) << (m##_SHIFT)) & (m))) -#define get_bf(v, m) (((v) & (m)) >> (m##_SHIFT)) +#define set_bf(v, m, x) (v = ((v) & ~(m)) | (((x) << m##_SHIFT) & (m))) +#define get_bf(v, m) (((v) & (m)) >> m##_SHIFT) /* PAMU CCSR space */ #define PAMU_PGC 0x00000000 /* Allows all peripheral accesses */ @@ -65,7 +67,7 @@ struct pamu_mmap_regs { #define PAMU_AVS1_GCV 0x2000 #define PAMU_AVS1_PDV 0x4000 #define PAMU_AV_MASK (PAMU_AVS1_AV | PAMU_AVS1_OTV | PAMU_AVS1_APV | PAMU_AVS1_WAV \ - | PAMU_AVS1_LAV | PAMU_AVS1_GCV | PAMU_AVS1_PDV) + | PAMU_AVS1_LAV | PAMU_AVS1_GCV | PAMU_AVS1_PDV) #define PAMU_AVS1_LIODN_SHIFT 16 #define PAMU_LAV_LIODN_NOT_IN_PPAACT 0x400 @@ -198,8 +200,7 @@ struct pamu_mmap_regs { #define PAACE_ATM_NO_XLATE 0x00 #define PAACE_ATM_WINDOW_XLATE 0x01 #define PAACE_ATM_PAGE_XLATE 0x02 -#define PAACE_ATM_WIN_PG_XLATE \ - (PAACE_ATM_WINDOW_XLATE | PAACE_ATM_PAGE_XLATE) +#define PAACE_ATM_WIN_PG_XLATE (PAACE_ATM_WINDOW_XLATE | PAACE_ATM_PAGE_XLATE) #define PAACE_OTM_NO_XLATE 0x00 #define PAACE_OTM_IMMEDIATE 0x01 #define PAACE_OTM_INDEXED 0x02 @@ -219,7 +220,7 @@ struct pamu_mmap_regs { #define PAACE_TCEF_FORMAT0_8B 0x00 #define PAACE_TCEF_FORMAT1_RSVD 0x01 /* - * Hard coded value for the PAACT size to accomodate + * Hard coded value for the PAACT size to accommodate * maximum LIODN value generated by u-boot. */ #define PAACE_NUMBER_ENTRIES 0x500 @@ -332,7 +333,7 @@ struct paace { #define NUM_MOE 128 struct ome { u8 moe[NUM_MOE]; -} __attribute__((packed)); +} __packed; #define PAACT_SIZE (sizeof(struct paace) * PAACE_NUMBER_ENTRIES) #define SPAACT_SIZE (sizeof(struct paace) * SPAACE_NUMBER_ENTRIES) diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c index c828f80d48b0..ceebd287b660 100644 --- a/drivers/iommu/fsl_pamu_domain.c +++ b/drivers/iommu/fsl_pamu_domain.c @@ -19,26 +19,10 @@ #define pr_fmt(fmt) "fsl-pamu-domain: %s: " fmt, __func__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - #include "fsl_pamu_domain.h" +#include + /* * Global spinlock that needs to be held while * configuring PAMU. @@ -51,23 +35,21 @@ static DEFINE_SPINLOCK(device_domain_lock); static int __init iommu_init_mempool(void) { - fsl_pamu_domain_cache = kmem_cache_create("fsl_pamu_domain", - sizeof(struct fsl_dma_domain), - 0, - SLAB_HWCACHE_ALIGN, - - NULL); + sizeof(struct fsl_dma_domain), + 0, + SLAB_HWCACHE_ALIGN, + NULL); if (!fsl_pamu_domain_cache) { pr_debug("Couldn't create fsl iommu_domain cache\n"); return -ENOMEM; } iommu_devinfo_cache = kmem_cache_create("iommu_devinfo", - sizeof(struct device_domain_info), - 0, - SLAB_HWCACHE_ALIGN, - NULL); + sizeof(struct device_domain_info), + 0, + SLAB_HWCACHE_ALIGN, + NULL); if (!iommu_devinfo_cache) { pr_debug("Couldn't create devinfo cache\n"); kmem_cache_destroy(fsl_pamu_domain_cache); @@ -80,8 +62,7 @@ static int __init iommu_init_mempool(void) static phys_addr_t get_phys_addr(struct fsl_dma_domain *dma_domain, dma_addr_t iova) { u32 win_cnt = dma_domain->win_cnt; - struct dma_window *win_ptr = - &dma_domain->win_arr[0]; + struct dma_window *win_ptr = &dma_domain->win_arr[0]; struct iommu_domain_geometry *geom; geom = &dma_domain->iommu_domain->geometry; @@ -103,22 +84,20 @@ static phys_addr_t get_phys_addr(struct fsl_dma_domain *dma_domain, dma_addr_t i } if (win_ptr->valid) - return (win_ptr->paddr + (iova & (win_ptr->size - 1))); + return win_ptr->paddr + (iova & (win_ptr->size - 1)); return 0; } static int map_subwins(int liodn, struct fsl_dma_domain *dma_domain) { - struct dma_window *sub_win_ptr = - &dma_domain->win_arr[0]; + struct dma_window *sub_win_ptr = &dma_domain->win_arr[0]; int i, ret; unsigned long rpn, flags; for (i = 0; i < dma_domain->win_cnt; i++) { if (sub_win_ptr[i].valid) { - rpn = sub_win_ptr[i].paddr >> - PAMU_PAGE_SHIFT; + rpn = sub_win_ptr[i].paddr >> PAMU_PAGE_SHIFT; spin_lock_irqsave(&iommu_lock, flags); ret = pamu_config_spaace(liodn, dma_domain->win_cnt, i, sub_win_ptr[i].size, @@ -130,7 +109,7 @@ static int map_subwins(int liodn, struct fsl_dma_domain *dma_domain) sub_win_ptr[i].prot); spin_unlock_irqrestore(&iommu_lock, flags); if (ret) { - pr_debug("PAMU SPAACE configuration failed for liodn %d\n", + pr_debug("SPAACE configuration failed for liodn %d\n", liodn); return ret; } @@ -156,8 +135,7 @@ static int map_win(int liodn, struct fsl_dma_domain *dma_domain) 0, wnd->prot); spin_unlock_irqrestore(&iommu_lock, flags); if (ret) - pr_debug("PAMU PAACE configuration failed for liodn %d\n", - liodn); + pr_debug("PAACE configuration failed for liodn %d\n", liodn); return ret; } @@ -169,7 +147,6 @@ static int map_liodn(int liodn, struct fsl_dma_domain *dma_domain) return map_subwins(liodn, dma_domain); else return map_win(liodn, dma_domain); - } /* Update window/subwindow mapping for the LIODN */ @@ -190,7 +167,8 @@ static int update_liodn(int liodn, struct fsl_dma_domain *dma_domain, u32 wnd_nr (wnd_nr > 0) ? 1 : 0, wnd->prot); if (ret) - pr_debug("Subwindow reconfiguration failed for liodn %d\n", liodn); + pr_debug("Subwindow reconfiguration failed for liodn %d\n", + liodn); } else { phys_addr_t wnd_addr; @@ -200,10 +178,11 @@ static int update_liodn(int liodn, struct fsl_dma_domain *dma_domain, u32 wnd_nr wnd->size, ~(u32)0, wnd->paddr >> PAMU_PAGE_SHIFT, - dma_domain->snoop_id, dma_domain->stash_id, - 0, wnd->prot); + dma_domain->snoop_id, dma_domain->stash_id, + 0, wnd->prot); if (ret) - pr_debug("Window reconfiguration failed for liodn %d\n", liodn); + pr_debug("Window reconfiguration failed for liodn %d\n", + liodn); } spin_unlock_irqrestore(&iommu_lock, flags); @@ -212,14 +191,15 @@ static int update_liodn(int liodn, struct fsl_dma_domain *dma_domain, u32 wnd_nr } static int update_liodn_stash(int liodn, struct fsl_dma_domain *dma_domain, - u32 val) + u32 val) { int ret = 0, i; unsigned long flags; spin_lock_irqsave(&iommu_lock, flags); if (!dma_domain->win_arr) { - pr_debug("Windows not configured, stash destination update failed for liodn %d\n", liodn); + pr_debug("Windows not configured, stash destination update failed for liodn %d\n", + liodn); spin_unlock_irqrestore(&iommu_lock, flags); return -EINVAL; } @@ -227,7 +207,8 @@ static int update_liodn_stash(int liodn, struct fsl_dma_domain *dma_domain, for (i = 0; i < dma_domain->win_cnt; i++) { ret = pamu_update_paace_stash(liodn, i, val); if (ret) { - pr_debug("Failed to update SPAACE %d field for liodn %d\n ", i, liodn); + pr_debug("Failed to update SPAACE %d field for liodn %d\n ", + i, liodn); spin_unlock_irqrestore(&iommu_lock, flags); return ret; } @@ -240,9 +221,9 @@ static int update_liodn_stash(int liodn, struct fsl_dma_domain *dma_domain, /* Set the geometry parameters for a LIODN */ static int pamu_set_liodn(int liodn, struct device *dev, - struct fsl_dma_domain *dma_domain, - struct iommu_domain_geometry *geom_attr, - u32 win_cnt) + struct fsl_dma_domain *dma_domain, + struct iommu_domain_geometry *geom_attr, + u32 win_cnt) { phys_addr_t window_addr, window_size; phys_addr_t subwin_size; @@ -268,7 +249,8 @@ static int pamu_set_liodn(int liodn, struct device *dev, dma_domain->stash_id, win_cnt, 0); spin_unlock_irqrestore(&iommu_lock, flags); if (ret) { - pr_debug("PAMU PAACE configuration failed for liodn %d, win_cnt =%d\n", liodn, win_cnt); + pr_debug("PAACE configuration failed for liodn %d, win_cnt =%d\n", + liodn, win_cnt); return ret; } @@ -285,7 +267,8 @@ static int pamu_set_liodn(int liodn, struct device *dev, 0, 0); spin_unlock_irqrestore(&iommu_lock, flags); if (ret) { - pr_debug("PAMU SPAACE configuration failed for liodn %d\n", liodn); + pr_debug("SPAACE configuration failed for liodn %d\n", + liodn); return ret; } } @@ -301,13 +284,13 @@ static int check_size(u64 size, dma_addr_t iova) * to PAMU page size. */ if ((size & (size - 1)) || size < PAMU_PAGE_SIZE) { - pr_debug("%s: size too small or not a power of two\n", __func__); + pr_debug("Size too small or not a power of two\n"); return -EINVAL; } - /* iova must be page size aligned*/ + /* iova must be page size aligned */ if (iova & (size - 1)) { - pr_debug("%s: address is not aligned with window size\n", __func__); + pr_debug("Address is not aligned with window size\n"); return -EINVAL; } @@ -396,16 +379,15 @@ static void attach_device(struct fsl_dma_domain *dma_domain, int liodn, struct d if (!dev->archdata.iommu_domain) dev->archdata.iommu_domain = info; spin_unlock_irqrestore(&device_domain_lock, flags); - } static phys_addr_t fsl_pamu_iova_to_phys(struct iommu_domain *domain, - dma_addr_t iova) + dma_addr_t iova) { struct fsl_dma_domain *dma_domain = domain->priv; - if ((iova < domain->geometry.aperture_start) || - iova > (domain->geometry.aperture_end)) + if (iova < domain->geometry.aperture_start || + iova > domain->geometry.aperture_end) return 0; return get_phys_addr(dma_domain, iova); @@ -460,7 +442,7 @@ static int pamu_set_domain_geometry(struct fsl_dma_domain *dma_domain, list_for_each_entry(info, &dma_domain->devices, link) { ret = pamu_set_liodn(info->liodn, info->dev, dma_domain, - geom_attr, win_cnt); + geom_attr, win_cnt); if (ret) break; } @@ -543,7 +525,6 @@ static void fsl_pamu_window_disable(struct iommu_domain *domain, u32 wnd_nr) } spin_unlock_irqrestore(&dma_domain->domain_lock, flags); - } static int fsl_pamu_window_enable(struct iommu_domain *domain, u32 wnd_nr, @@ -576,7 +557,7 @@ static int fsl_pamu_window_enable(struct iommu_domain *domain, u32 wnd_nr, win_size = dma_domain->geom_size >> ilog2(dma_domain->win_cnt); if (size > win_size) { - pr_debug("Invalid window size \n"); + pr_debug("Invalid window size\n"); spin_unlock_irqrestore(&dma_domain->domain_lock, flags); return -EINVAL; } @@ -622,8 +603,8 @@ static int fsl_pamu_window_enable(struct iommu_domain *domain, u32 wnd_nr, * and window mappings. */ static int handle_attach_device(struct fsl_dma_domain *dma_domain, - struct device *dev, const u32 *liodn, - int num) + struct device *dev, const u32 *liodn, + int num) { unsigned long flags; struct iommu_domain *domain = dma_domain->iommu_domain; @@ -632,11 +613,10 @@ static int handle_attach_device(struct fsl_dma_domain *dma_domain, spin_lock_irqsave(&dma_domain->domain_lock, flags); for (i = 0; i < num; i++) { - /* Ensure that LIODN value is valid */ if (liodn[i] >= PAACE_NUMBER_ENTRIES) { pr_debug("Invalid liodn %d, attach device failed for %s\n", - liodn[i], dev->of_node->full_name); + liodn[i], dev->of_node->full_name); ret = -EINVAL; break; } @@ -649,9 +629,9 @@ static int handle_attach_device(struct fsl_dma_domain *dma_domain, */ if (dma_domain->win_arr) { u32 win_cnt = dma_domain->win_cnt > 1 ? dma_domain->win_cnt : 0; + ret = pamu_set_liodn(liodn[i], dev, dma_domain, - &domain->geometry, - win_cnt); + &domain->geometry, win_cnt); if (ret) break; if (dma_domain->mapped) { @@ -698,19 +678,18 @@ static int fsl_pamu_attach_device(struct iommu_domain *domain, liodn = of_get_property(dev->of_node, "fsl,liodn", &len); if (liodn) { liodn_cnt = len / sizeof(u32); - ret = handle_attach_device(dma_domain, dev, - liodn, liodn_cnt); + ret = handle_attach_device(dma_domain, dev, liodn, liodn_cnt); } else { pr_debug("missing fsl,liodn property at %s\n", - dev->of_node->full_name); - ret = -EINVAL; + dev->of_node->full_name); + ret = -EINVAL; } return ret; } static void fsl_pamu_detach_device(struct iommu_domain *domain, - struct device *dev) + struct device *dev) { struct fsl_dma_domain *dma_domain = domain->priv; const u32 *prop; @@ -738,7 +717,7 @@ static void fsl_pamu_detach_device(struct iommu_domain *domain, detach_device(dev, dma_domain); else pr_debug("missing fsl,liodn property at %s\n", - dev->of_node->full_name); + dev->of_node->full_name); } static int configure_domain_geometry(struct iommu_domain *domain, void *data) @@ -754,10 +733,10 @@ static int configure_domain_geometry(struct iommu_domain *domain, void *data) * DMA outside of the geometry. */ if (check_size(geom_size, geom_attr->aperture_start) || - !geom_attr->force_aperture) { - pr_debug("Invalid PAMU geometry attributes\n"); - return -EINVAL; - } + !geom_attr->force_aperture) { + pr_debug("Invalid PAMU geometry attributes\n"); + return -EINVAL; + } spin_lock_irqsave(&dma_domain->domain_lock, flags); if (dma_domain->enabled) { @@ -786,7 +765,7 @@ static int configure_domain_stash(struct fsl_dma_domain *dma_domain, void *data) spin_lock_irqsave(&dma_domain->domain_lock, flags); memcpy(&dma_domain->dma_stash, stash_attr, - sizeof(struct pamu_stash_attribute)); + sizeof(struct pamu_stash_attribute)); dma_domain->stash_id = get_stash_id(stash_attr->cache, stash_attr->cpu); @@ -803,7 +782,7 @@ static int configure_domain_stash(struct fsl_dma_domain *dma_domain, void *data) return ret; } -/* Configure domain dma state i.e. enable/disable DMA*/ +/* Configure domain dma state i.e. enable/disable DMA */ static int configure_domain_dma_state(struct fsl_dma_domain *dma_domain, bool enable) { struct device_domain_info *info; @@ -819,8 +798,7 @@ static int configure_domain_dma_state(struct fsl_dma_domain *dma_domain, bool en } dma_domain->enabled = enable; - list_for_each_entry(info, &dma_domain->devices, - link) { + list_for_each_entry(info, &dma_domain->devices, link) { ret = (enable) ? pamu_enable_liodn(info->liodn) : pamu_disable_liodn(info->liodn); if (ret) @@ -833,12 +811,11 @@ static int configure_domain_dma_state(struct fsl_dma_domain *dma_domain, bool en } static int fsl_pamu_set_domain_attr(struct iommu_domain *domain, - enum iommu_attr attr_type, void *data) + enum iommu_attr attr_type, void *data) { struct fsl_dma_domain *dma_domain = domain->priv; int ret = 0; - switch (attr_type) { case DOMAIN_ATTR_GEOMETRY: ret = configure_domain_geometry(domain, data); @@ -853,22 +830,21 @@ static int fsl_pamu_set_domain_attr(struct iommu_domain *domain, pr_debug("Unsupported attribute type\n"); ret = -EINVAL; break; - }; + } return ret; } static int fsl_pamu_get_domain_attr(struct iommu_domain *domain, - enum iommu_attr attr_type, void *data) + enum iommu_attr attr_type, void *data) { struct fsl_dma_domain *dma_domain = domain->priv; int ret = 0; - switch (attr_type) { case DOMAIN_ATTR_FSL_PAMU_STASH: - memcpy((struct pamu_stash_attribute *) data, &dma_domain->dma_stash, - sizeof(struct pamu_stash_attribute)); + memcpy(data, &dma_domain->dma_stash, + sizeof(struct pamu_stash_attribute)); break; case DOMAIN_ATTR_FSL_PAMU_ENABLE: *(int *)data = dma_domain->enabled; @@ -880,7 +856,7 @@ static int fsl_pamu_get_domain_attr(struct iommu_domain *domain, pr_debug("Unsupported attribute type\n"); ret = -EINVAL; break; - }; + } return ret; } @@ -903,11 +879,8 @@ static bool check_pci_ctl_endpt_part(struct pci_controller *pci_ctl) /* Check the PCI controller version number by readding BRR1 register */ version = in_be32(pci_ctl->cfg_addr + (PCI_FSL_BRR1 >> 2)); version &= PCI_FSL_BRR1_VER; - /* If PCI controller version is >= 0x204 we can partition endpoints*/ - if (version >= 0x204) - return 1; - - return 0; + /* If PCI controller version is >= 0x204 we can partition endpoints */ + return version >= 0x204; } /* Get iommu group information from peer devices or devices on the parent bus */ @@ -968,8 +941,9 @@ static struct iommu_group *get_pci_device_group(struct pci_dev *pdev) if (pci_ctl->parent->iommu_group) { group = get_device_iommu_group(pci_ctl->parent); iommu_group_remove_device(pci_ctl->parent); - } else + } else { group = get_shared_pci_device_group(pdev); + } } if (!group) @@ -1055,11 +1029,12 @@ static int fsl_pamu_set_windows(struct iommu_domain *domain, u32 w_count) } ret = pamu_set_domain_geometry(dma_domain, &domain->geometry, - ((w_count > 1) ? w_count : 0)); + w_count > 1 ? w_count : 0); if (!ret) { kfree(dma_domain->win_arr); - dma_domain->win_arr = kzalloc(sizeof(struct dma_window) * - w_count, GFP_ATOMIC); + dma_domain->win_arr = kcalloc(w_count, + sizeof(*dma_domain->win_arr), + GFP_ATOMIC); if (!dma_domain->win_arr) { spin_unlock_irqrestore(&dma_domain->domain_lock, flags); return -ENOMEM; @@ -1095,7 +1070,7 @@ static const struct iommu_ops fsl_pamu_ops = { .remove_device = fsl_pamu_remove_device, }; -int pamu_domain_init(void) +int __init pamu_domain_init(void) { int ret = 0; diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 40dfbc0444c0..ae4c1a854e57 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -71,6 +71,9 @@ __DOMAIN_MAX_PFN(gaw), (unsigned long)-1)) #define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT) +/* IO virtual address start page frame number */ +#define IOVA_START_PFN (1) + #define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT) #define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32)) #define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64)) @@ -485,7 +488,6 @@ __setup("intel_iommu=", intel_iommu_setup); static struct kmem_cache *iommu_domain_cache; static struct kmem_cache *iommu_devinfo_cache; -static struct kmem_cache *iommu_iova_cache; static inline void *alloc_pgtable_page(int node) { @@ -523,16 +525,6 @@ static inline void free_devinfo_mem(void *vaddr) kmem_cache_free(iommu_devinfo_cache, vaddr); } -struct iova *alloc_iova_mem(void) -{ - return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC); -} - -void free_iova_mem(struct iova *iova) -{ - kmem_cache_free(iommu_iova_cache, iova); -} - static inline int domain_type_is_vm(struct dmar_domain *domain) { return domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE; @@ -1643,7 +1635,8 @@ static int dmar_init_reserved_ranges(void) struct iova *iova; int i; - init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN); + init_iova_domain(&reserved_iova_list, VTD_PAGE_SIZE, IOVA_START_PFN, + DMA_32BIT_PFN); lockdep_set_class(&reserved_iova_list.iova_rbtree_lock, &reserved_rbtree_key); @@ -1701,7 +1694,8 @@ static int domain_init(struct dmar_domain *domain, int guest_width) int adjust_width, agaw; unsigned long sagaw; - init_iova_domain(&domain->iovad, DMA_32BIT_PFN); + init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN, + DMA_32BIT_PFN); domain_reserve_special_ranges(domain); /* calculate AGAW */ @@ -3427,23 +3421,6 @@ static inline int iommu_devinfo_cache_init(void) return ret; } -static inline int iommu_iova_cache_init(void) -{ - int ret = 0; - - iommu_iova_cache = kmem_cache_create("iommu_iova", - sizeof(struct iova), - 0, - SLAB_HWCACHE_ALIGN, - NULL); - if (!iommu_iova_cache) { - printk(KERN_ERR "Couldn't create iova cache\n"); - ret = -ENOMEM; - } - - return ret; -} - static int __init iommu_init_mempool(void) { int ret; @@ -3461,7 +3438,7 @@ static int __init iommu_init_mempool(void) kmem_cache_destroy(iommu_domain_cache); domain_error: - kmem_cache_destroy(iommu_iova_cache); + iommu_iova_cache_destroy(); return -ENOMEM; } @@ -3470,8 +3447,7 @@ static void __init iommu_exit_mempool(void) { kmem_cache_destroy(iommu_devinfo_cache); kmem_cache_destroy(iommu_domain_cache); - kmem_cache_destroy(iommu_iova_cache); - + iommu_iova_cache_destroy(); } static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev) @@ -4342,7 +4318,8 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width) { int adjust_width; - init_iova_domain(&domain->iovad, DMA_32BIT_PFN); + init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN, + DMA_32BIT_PFN); domain_reserve_special_ranges(domain); /* calculate AGAW */ diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index a55b207b9425..14de1ab223c8 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -32,8 +32,9 @@ struct hpet_scope { }; #define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0) -#define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8) +#define IRTE_DEST(dest) ((eim_mode) ? dest : dest << 8) +static int __read_mostly eim_mode; static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; static struct hpet_scope ir_hpet[MAX_HPET_TBS]; @@ -481,11 +482,11 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu) if (iommu->ir_table) return 0; - ir_table = kzalloc(sizeof(struct ir_table), GFP_ATOMIC); + ir_table = kzalloc(sizeof(struct ir_table), GFP_KERNEL); if (!ir_table) return -ENOMEM; - pages = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO, + pages = alloc_pages_node(iommu->node, GFP_KERNEL | __GFP_ZERO, INTR_REMAP_PAGE_ORDER); if (!pages) { @@ -566,13 +567,27 @@ static int __init dmar_x2apic_optout(void) return dmar->flags & DMAR_X2APIC_OPT_OUT; } -static int __init intel_irq_remapping_supported(void) +static void __init intel_cleanup_irq_remapping(void) +{ + struct dmar_drhd_unit *drhd; + struct intel_iommu *iommu; + + for_each_iommu(iommu, drhd) { + if (ecap_ir_support(iommu->ecap)) { + iommu_disable_irq_remapping(iommu); + intel_teardown_irq_remapping(iommu); + } + } + + if (x2apic_supported()) + pr_warn("Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n"); +} + +static int __init intel_prepare_irq_remapping(void) { struct dmar_drhd_unit *drhd; struct intel_iommu *iommu; - if (disable_irq_remap) - return 0; if (irq_remap_broken) { printk(KERN_WARNING "This system BIOS has enabled interrupt remapping\n" @@ -581,38 +596,45 @@ static int __init intel_irq_remapping_supported(void) "interrupt remapping is being disabled. Please\n" "contact your BIOS vendor for an update\n"); add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); - disable_irq_remap = 1; - return 0; + return -ENODEV; } - if (!dmar_ir_support()) - return 0; + if (dmar_table_init() < 0) + return -ENODEV; + if (!dmar_ir_support()) + return -ENODEV; + + if (parse_ioapics_under_ir() != 1) { + printk(KERN_INFO "Not enabling interrupt remapping\n"); + goto error; + } + + /* First make sure all IOMMUs support IRQ remapping */ for_each_iommu(iommu, drhd) if (!ecap_ir_support(iommu->ecap)) - return 0; + goto error; - return 1; + /* Do the allocations early */ + for_each_iommu(iommu, drhd) + if (intel_setup_irq_remapping(iommu)) + goto error; + + return 0; + +error: + intel_cleanup_irq_remapping(); + return -ENODEV; } static int __init intel_enable_irq_remapping(void) { struct dmar_drhd_unit *drhd; struct intel_iommu *iommu; - bool x2apic_present; int setup = 0; int eim = 0; - x2apic_present = x2apic_supported(); - - if (parse_ioapics_under_ir() != 1) { - printk(KERN_INFO "Not enable interrupt remapping\n"); - goto error; - } - - if (x2apic_present) { - pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n"); - + if (x2apic_supported()) { eim = !dmar_x2apic_optout(); if (!eim) printk(KERN_WARNING @@ -646,16 +668,15 @@ static int __init intel_enable_irq_remapping(void) /* * check for the Interrupt-remapping support */ - for_each_iommu(iommu, drhd) { - if (!ecap_ir_support(iommu->ecap)) - continue; - + for_each_iommu(iommu, drhd) if (eim && !ecap_eim_support(iommu->ecap)) { printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, " " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap); - goto error; + eim = 0; } - } + eim_mode = eim; + if (eim) + pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n"); /* * Enable queued invalidation for all the DRHD's. @@ -675,12 +696,6 @@ static int __init intel_enable_irq_remapping(void) * Setup Interrupt-remapping for all the DRHD's now. */ for_each_iommu(iommu, drhd) { - if (!ecap_ir_support(iommu->ecap)) - continue; - - if (intel_setup_irq_remapping(iommu)) - goto error; - iommu_set_irq_remapping(iommu, eim); setup = 1; } @@ -702,15 +717,7 @@ static int __init intel_enable_irq_remapping(void) return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; error: - for_each_iommu(iommu, drhd) - if (ecap_ir_support(iommu->ecap)) { - iommu_disable_irq_remapping(iommu); - intel_teardown_irq_remapping(iommu); - } - - if (x2apic_present) - pr_warn("Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n"); - + intel_cleanup_irq_remapping(); return -1; } @@ -1199,8 +1206,7 @@ static int intel_alloc_hpet_msi(unsigned int irq, unsigned int id) } struct irq_remap_ops intel_irq_remap_ops = { - .supported = intel_irq_remapping_supported, - .prepare = dmar_table_init, + .prepare = intel_prepare_irq_remapping, .enable = intel_enable_irq_remapping, .disable = disable_irq_remapping, .reenable = reenable_irq_remapping, diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c new file mode 100644 index 000000000000..5a500edf00cc --- /dev/null +++ b/drivers/iommu/io-pgtable-arm.c @@ -0,0 +1,986 @@ +/* + * CPU-agnostic ARM page table allocator. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Copyright (C) 2014 ARM Limited + * + * Author: Will Deacon + */ + +#define pr_fmt(fmt) "arm-lpae io-pgtable: " fmt + +#include +#include +#include +#include +#include + +#include "io-pgtable.h" + +#define ARM_LPAE_MAX_ADDR_BITS 48 +#define ARM_LPAE_S2_MAX_CONCAT_PAGES 16 +#define ARM_LPAE_MAX_LEVELS 4 + +/* Struct accessors */ +#define io_pgtable_to_data(x) \ + container_of((x), struct arm_lpae_io_pgtable, iop) + +#define io_pgtable_ops_to_pgtable(x) \ + container_of((x), struct io_pgtable, ops) + +#define io_pgtable_ops_to_data(x) \ + io_pgtable_to_data(io_pgtable_ops_to_pgtable(x)) + +/* + * For consistency with the architecture, we always consider + * ARM_LPAE_MAX_LEVELS levels, with the walk starting at level n >=0 + */ +#define ARM_LPAE_START_LVL(d) (ARM_LPAE_MAX_LEVELS - (d)->levels) + +/* + * Calculate the right shift amount to get to the portion describing level l + * in a virtual address mapped by the pagetable in d. + */ +#define ARM_LPAE_LVL_SHIFT(l,d) \ + ((((d)->levels - ((l) - ARM_LPAE_START_LVL(d) + 1)) \ + * (d)->bits_per_level) + (d)->pg_shift) + +#define ARM_LPAE_PAGES_PER_PGD(d) ((d)->pgd_size >> (d)->pg_shift) + +/* + * Calculate the index at level l used to map virtual address a using the + * pagetable in d. + */ +#define ARM_LPAE_PGD_IDX(l,d) \ + ((l) == ARM_LPAE_START_LVL(d) ? ilog2(ARM_LPAE_PAGES_PER_PGD(d)) : 0) + +#define ARM_LPAE_LVL_IDX(a,l,d) \ + (((a) >> ARM_LPAE_LVL_SHIFT(l,d)) & \ + ((1 << ((d)->bits_per_level + ARM_LPAE_PGD_IDX(l,d))) - 1)) + +/* Calculate the block/page mapping size at level l for pagetable in d. */ +#define ARM_LPAE_BLOCK_SIZE(l,d) \ + (1 << (ilog2(sizeof(arm_lpae_iopte)) + \ + ((ARM_LPAE_MAX_LEVELS - (l)) * (d)->bits_per_level))) + +/* Page table bits */ +#define ARM_LPAE_PTE_TYPE_SHIFT 0 +#define ARM_LPAE_PTE_TYPE_MASK 0x3 + +#define ARM_LPAE_PTE_TYPE_BLOCK 1 +#define ARM_LPAE_PTE_TYPE_TABLE 3 +#define ARM_LPAE_PTE_TYPE_PAGE 3 + +#define ARM_LPAE_PTE_NSTABLE (((arm_lpae_iopte)1) << 63) +#define ARM_LPAE_PTE_XN (((arm_lpae_iopte)3) << 53) +#define ARM_LPAE_PTE_AF (((arm_lpae_iopte)1) << 10) +#define ARM_LPAE_PTE_SH_NS (((arm_lpae_iopte)0) << 8) +#define ARM_LPAE_PTE_SH_OS (((arm_lpae_iopte)2) << 8) +#define ARM_LPAE_PTE_SH_IS (((arm_lpae_iopte)3) << 8) +#define ARM_LPAE_PTE_NS (((arm_lpae_iopte)1) << 5) +#define ARM_LPAE_PTE_VALID (((arm_lpae_iopte)1) << 0) + +#define ARM_LPAE_PTE_ATTR_LO_MASK (((arm_lpae_iopte)0x3ff) << 2) +/* Ignore the contiguous bit for block splitting */ +#define ARM_LPAE_PTE_ATTR_HI_MASK (((arm_lpae_iopte)6) << 52) +#define ARM_LPAE_PTE_ATTR_MASK (ARM_LPAE_PTE_ATTR_LO_MASK | \ + ARM_LPAE_PTE_ATTR_HI_MASK) + +/* Stage-1 PTE */ +#define ARM_LPAE_PTE_AP_UNPRIV (((arm_lpae_iopte)1) << 6) +#define ARM_LPAE_PTE_AP_RDONLY (((arm_lpae_iopte)2) << 6) +#define ARM_LPAE_PTE_ATTRINDX_SHIFT 2 +#define ARM_LPAE_PTE_nG (((arm_lpae_iopte)1) << 11) + +/* Stage-2 PTE */ +#define ARM_LPAE_PTE_HAP_FAULT (((arm_lpae_iopte)0) << 6) +#define ARM_LPAE_PTE_HAP_READ (((arm_lpae_iopte)1) << 6) +#define ARM_LPAE_PTE_HAP_WRITE (((arm_lpae_iopte)2) << 6) +#define ARM_LPAE_PTE_MEMATTR_OIWB (((arm_lpae_iopte)0xf) << 2) +#define ARM_LPAE_PTE_MEMATTR_NC (((arm_lpae_iopte)0x5) << 2) +#define ARM_LPAE_PTE_MEMATTR_DEV (((arm_lpae_iopte)0x1) << 2) + +/* Register bits */ +#define ARM_32_LPAE_TCR_EAE (1 << 31) +#define ARM_64_LPAE_S2_TCR_RES1 (1 << 31) + +#define ARM_LPAE_TCR_TG0_4K (0 << 14) +#define ARM_LPAE_TCR_TG0_64K (1 << 14) +#define ARM_LPAE_TCR_TG0_16K (2 << 14) + +#define ARM_LPAE_TCR_SH0_SHIFT 12 +#define ARM_LPAE_TCR_SH0_MASK 0x3 +#define ARM_LPAE_TCR_SH_NS 0 +#define ARM_LPAE_TCR_SH_OS 2 +#define ARM_LPAE_TCR_SH_IS 3 + +#define ARM_LPAE_TCR_ORGN0_SHIFT 10 +#define ARM_LPAE_TCR_IRGN0_SHIFT 8 +#define ARM_LPAE_TCR_RGN_MASK 0x3 +#define ARM_LPAE_TCR_RGN_NC 0 +#define ARM_LPAE_TCR_RGN_WBWA 1 +#define ARM_LPAE_TCR_RGN_WT 2 +#define ARM_LPAE_TCR_RGN_WB 3 + +#define ARM_LPAE_TCR_SL0_SHIFT 6 +#define ARM_LPAE_TCR_SL0_MASK 0x3 + +#define ARM_LPAE_TCR_T0SZ_SHIFT 0 +#define ARM_LPAE_TCR_SZ_MASK 0xf + +#define ARM_LPAE_TCR_PS_SHIFT 16 +#define ARM_LPAE_TCR_PS_MASK 0x7 + +#define ARM_LPAE_TCR_IPS_SHIFT 32 +#define ARM_LPAE_TCR_IPS_MASK 0x7 + +#define ARM_LPAE_TCR_PS_32_BIT 0x0ULL +#define ARM_LPAE_TCR_PS_36_BIT 0x1ULL +#define ARM_LPAE_TCR_PS_40_BIT 0x2ULL +#define ARM_LPAE_TCR_PS_42_BIT 0x3ULL +#define ARM_LPAE_TCR_PS_44_BIT 0x4ULL +#define ARM_LPAE_TCR_PS_48_BIT 0x5ULL + +#define ARM_LPAE_MAIR_ATTR_SHIFT(n) ((n) << 3) +#define ARM_LPAE_MAIR_ATTR_MASK 0xff +#define ARM_LPAE_MAIR_ATTR_DEVICE 0x04 +#define ARM_LPAE_MAIR_ATTR_NC 0x44 +#define ARM_LPAE_MAIR_ATTR_WBRWA 0xff +#define ARM_LPAE_MAIR_ATTR_IDX_NC 0 +#define ARM_LPAE_MAIR_ATTR_IDX_CACHE 1 +#define ARM_LPAE_MAIR_ATTR_IDX_DEV 2 + +/* IOPTE accessors */ +#define iopte_deref(pte,d) \ + (__va((pte) & ((1ULL << ARM_LPAE_MAX_ADDR_BITS) - 1) \ + & ~((1ULL << (d)->pg_shift) - 1))) + +#define iopte_type(pte,l) \ + (((pte) >> ARM_LPAE_PTE_TYPE_SHIFT) & ARM_LPAE_PTE_TYPE_MASK) + +#define iopte_prot(pte) ((pte) & ARM_LPAE_PTE_ATTR_MASK) + +#define iopte_leaf(pte,l) \ + (l == (ARM_LPAE_MAX_LEVELS - 1) ? \ + (iopte_type(pte,l) == ARM_LPAE_PTE_TYPE_PAGE) : \ + (iopte_type(pte,l) == ARM_LPAE_PTE_TYPE_BLOCK)) + +#define iopte_to_pfn(pte,d) \ + (((pte) & ((1ULL << ARM_LPAE_MAX_ADDR_BITS) - 1)) >> (d)->pg_shift) + +#define pfn_to_iopte(pfn,d) \ + (((pfn) << (d)->pg_shift) & ((1ULL << ARM_LPAE_MAX_ADDR_BITS) - 1)) + +struct arm_lpae_io_pgtable { + struct io_pgtable iop; + + int levels; + size_t pgd_size; + unsigned long pg_shift; + unsigned long bits_per_level; + + void *pgd; +}; + +typedef u64 arm_lpae_iopte; + +static bool selftest_running = false; + +static int arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, + unsigned long iova, phys_addr_t paddr, + arm_lpae_iopte prot, int lvl, + arm_lpae_iopte *ptep) +{ + arm_lpae_iopte pte = prot; + + /* We require an unmap first */ + if (iopte_leaf(*ptep, lvl)) { + WARN_ON(!selftest_running); + return -EEXIST; + } + + if (data->iop.cfg.quirks & IO_PGTABLE_QUIRK_ARM_NS) + pte |= ARM_LPAE_PTE_NS; + + if (lvl == ARM_LPAE_MAX_LEVELS - 1) + pte |= ARM_LPAE_PTE_TYPE_PAGE; + else + pte |= ARM_LPAE_PTE_TYPE_BLOCK; + + pte |= ARM_LPAE_PTE_AF | ARM_LPAE_PTE_SH_IS; + pte |= pfn_to_iopte(paddr >> data->pg_shift, data); + + *ptep = pte; + data->iop.cfg.tlb->flush_pgtable(ptep, sizeof(*ptep), data->iop.cookie); + return 0; +} + +static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, + phys_addr_t paddr, size_t size, arm_lpae_iopte prot, + int lvl, arm_lpae_iopte *ptep) +{ + arm_lpae_iopte *cptep, pte; + void *cookie = data->iop.cookie; + size_t block_size = ARM_LPAE_BLOCK_SIZE(lvl, data); + + /* Find our entry at the current level */ + ptep += ARM_LPAE_LVL_IDX(iova, lvl, data); + + /* If we can install a leaf entry at this level, then do so */ + if (size == block_size && (size & data->iop.cfg.pgsize_bitmap)) + return arm_lpae_init_pte(data, iova, paddr, prot, lvl, ptep); + + /* We can't allocate tables at the final level */ + if (WARN_ON(lvl >= ARM_LPAE_MAX_LEVELS - 1)) + return -EINVAL; + + /* Grab a pointer to the next level */ + pte = *ptep; + if (!pte) { + cptep = alloc_pages_exact(1UL << data->pg_shift, + GFP_ATOMIC | __GFP_ZERO); + if (!cptep) + return -ENOMEM; + + data->iop.cfg.tlb->flush_pgtable(cptep, 1UL << data->pg_shift, + cookie); + pte = __pa(cptep) | ARM_LPAE_PTE_TYPE_TABLE; + if (data->iop.cfg.quirks & IO_PGTABLE_QUIRK_ARM_NS) + pte |= ARM_LPAE_PTE_NSTABLE; + *ptep = pte; + data->iop.cfg.tlb->flush_pgtable(ptep, sizeof(*ptep), cookie); + } else { + cptep = iopte_deref(pte, data); + } + + /* Rinse, repeat */ + return __arm_lpae_map(data, iova, paddr, size, prot, lvl + 1, cptep); +} + +static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data, + int prot) +{ + arm_lpae_iopte pte; + + if (data->iop.fmt == ARM_64_LPAE_S1 || + data->iop.fmt == ARM_32_LPAE_S1) { + pte = ARM_LPAE_PTE_AP_UNPRIV | ARM_LPAE_PTE_nG; + + if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ)) + pte |= ARM_LPAE_PTE_AP_RDONLY; + + if (prot & IOMMU_CACHE) + pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE + << ARM_LPAE_PTE_ATTRINDX_SHIFT); + } else { + pte = ARM_LPAE_PTE_HAP_FAULT; + if (prot & IOMMU_READ) + pte |= ARM_LPAE_PTE_HAP_READ; + if (prot & IOMMU_WRITE) + pte |= ARM_LPAE_PTE_HAP_WRITE; + if (prot & IOMMU_CACHE) + pte |= ARM_LPAE_PTE_MEMATTR_OIWB; + else + pte |= ARM_LPAE_PTE_MEMATTR_NC; + } + + if (prot & IOMMU_NOEXEC) + pte |= ARM_LPAE_PTE_XN; + + return pte; +} + +static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova, + phys_addr_t paddr, size_t size, int iommu_prot) +{ + struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); + arm_lpae_iopte *ptep = data->pgd; + int lvl = ARM_LPAE_START_LVL(data); + arm_lpae_iopte prot; + + /* If no access, then nothing to do */ + if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE))) + return 0; + + prot = arm_lpae_prot_to_pte(data, iommu_prot); + return __arm_lpae_map(data, iova, paddr, size, prot, lvl, ptep); +} + +static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl, + arm_lpae_iopte *ptep) +{ + arm_lpae_iopte *start, *end; + unsigned long table_size; + + /* Only leaf entries at the last level */ + if (lvl == ARM_LPAE_MAX_LEVELS - 1) + return; + + if (lvl == ARM_LPAE_START_LVL(data)) + table_size = data->pgd_size; + else + table_size = 1UL << data->pg_shift; + + start = ptep; + end = (void *)ptep + table_size; + + while (ptep != end) { + arm_lpae_iopte pte = *ptep++; + + if (!pte || iopte_leaf(pte, lvl)) + continue; + + __arm_lpae_free_pgtable(data, lvl + 1, iopte_deref(pte, data)); + } + + free_pages_exact(start, table_size); +} + +static void arm_lpae_free_pgtable(struct io_pgtable *iop) +{ + struct arm_lpae_io_pgtable *data = io_pgtable_to_data(iop); + + __arm_lpae_free_pgtable(data, ARM_LPAE_START_LVL(data), data->pgd); + kfree(data); +} + +static int arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data, + unsigned long iova, size_t size, + arm_lpae_iopte prot, int lvl, + arm_lpae_iopte *ptep, size_t blk_size) +{ + unsigned long blk_start, blk_end; + phys_addr_t blk_paddr; + arm_lpae_iopte table = 0; + void *cookie = data->iop.cookie; + const struct iommu_gather_ops *tlb = data->iop.cfg.tlb; + + blk_start = iova & ~(blk_size - 1); + blk_end = blk_start + blk_size; + blk_paddr = iopte_to_pfn(*ptep, data) << data->pg_shift; + + for (; blk_start < blk_end; blk_start += size, blk_paddr += size) { + arm_lpae_iopte *tablep; + + /* Unmap! */ + if (blk_start == iova) + continue; + + /* __arm_lpae_map expects a pointer to the start of the table */ + tablep = &table - ARM_LPAE_LVL_IDX(blk_start, lvl, data); + if (__arm_lpae_map(data, blk_start, blk_paddr, size, prot, lvl, + tablep) < 0) { + if (table) { + /* Free the table we allocated */ + tablep = iopte_deref(table, data); + __arm_lpae_free_pgtable(data, lvl + 1, tablep); + } + return 0; /* Bytes unmapped */ + } + } + + *ptep = table; + tlb->flush_pgtable(ptep, sizeof(*ptep), cookie); + iova &= ~(blk_size - 1); + tlb->tlb_add_flush(iova, blk_size, true, cookie); + return size; +} + +static int __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, + unsigned long iova, size_t size, int lvl, + arm_lpae_iopte *ptep) +{ + arm_lpae_iopte pte; + const struct iommu_gather_ops *tlb = data->iop.cfg.tlb; + void *cookie = data->iop.cookie; + size_t blk_size = ARM_LPAE_BLOCK_SIZE(lvl, data); + + ptep += ARM_LPAE_LVL_IDX(iova, lvl, data); + pte = *ptep; + + /* Something went horribly wrong and we ran out of page table */ + if (WARN_ON(!pte || (lvl == ARM_LPAE_MAX_LEVELS))) + return 0; + + /* If the size matches this level, we're in the right place */ + if (size == blk_size) { + *ptep = 0; + tlb->flush_pgtable(ptep, sizeof(*ptep), cookie); + + if (!iopte_leaf(pte, lvl)) { + /* Also flush any partial walks */ + tlb->tlb_add_flush(iova, size, false, cookie); + tlb->tlb_sync(data->iop.cookie); + ptep = iopte_deref(pte, data); + __arm_lpae_free_pgtable(data, lvl + 1, ptep); + } else { + tlb->tlb_add_flush(iova, size, true, cookie); + } + + return size; + } else if (iopte_leaf(pte, lvl)) { + /* + * Insert a table at the next level to map the old region, + * minus the part we want to unmap + */ + return arm_lpae_split_blk_unmap(data, iova, size, + iopte_prot(pte), lvl, ptep, + blk_size); + } + + /* Keep on walkin' */ + ptep = iopte_deref(pte, data); + return __arm_lpae_unmap(data, iova, size, lvl + 1, ptep); +} + +static int arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova, + size_t size) +{ + size_t unmapped; + struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); + struct io_pgtable *iop = &data->iop; + arm_lpae_iopte *ptep = data->pgd; + int lvl = ARM_LPAE_START_LVL(data); + + unmapped = __arm_lpae_unmap(data, iova, size, lvl, ptep); + if (unmapped) + iop->cfg.tlb->tlb_sync(iop->cookie); + + return unmapped; +} + +static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops, + unsigned long iova) +{ + struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); + arm_lpae_iopte pte, *ptep = data->pgd; + int lvl = ARM_LPAE_START_LVL(data); + + do { + /* Valid IOPTE pointer? */ + if (!ptep) + return 0; + + /* Grab the IOPTE we're interested in */ + pte = *(ptep + ARM_LPAE_LVL_IDX(iova, lvl, data)); + + /* Valid entry? */ + if (!pte) + return 0; + + /* Leaf entry? */ + if (iopte_leaf(pte,lvl)) + goto found_translation; + + /* Take it to the next level */ + ptep = iopte_deref(pte, data); + } while (++lvl < ARM_LPAE_MAX_LEVELS); + + /* Ran out of page tables to walk */ + return 0; + +found_translation: + iova &= ((1 << data->pg_shift) - 1); + return ((phys_addr_t)iopte_to_pfn(pte,data) << data->pg_shift) | iova; +} + +static void arm_lpae_restrict_pgsizes(struct io_pgtable_cfg *cfg) +{ + unsigned long granule; + + /* + * We need to restrict the supported page sizes to match the + * translation regime for a particular granule. Aim to match + * the CPU page size if possible, otherwise prefer smaller sizes. + * While we're at it, restrict the block sizes to match the + * chosen granule. + */ + if (cfg->pgsize_bitmap & PAGE_SIZE) + granule = PAGE_SIZE; + else if (cfg->pgsize_bitmap & ~PAGE_MASK) + granule = 1UL << __fls(cfg->pgsize_bitmap & ~PAGE_MASK); + else if (cfg->pgsize_bitmap & PAGE_MASK) + granule = 1UL << __ffs(cfg->pgsize_bitmap & PAGE_MASK); + else + granule = 0; + + switch (granule) { + case SZ_4K: + cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G); + break; + case SZ_16K: + cfg->pgsize_bitmap &= (SZ_16K | SZ_32M); + break; + case SZ_64K: + cfg->pgsize_bitmap &= (SZ_64K | SZ_512M); + break; + default: + cfg->pgsize_bitmap = 0; + } +} + +static struct arm_lpae_io_pgtable * +arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg) +{ + unsigned long va_bits, pgd_bits; + struct arm_lpae_io_pgtable *data; + + arm_lpae_restrict_pgsizes(cfg); + + if (!(cfg->pgsize_bitmap & (SZ_4K | SZ_16K | SZ_64K))) + return NULL; + + if (cfg->ias > ARM_LPAE_MAX_ADDR_BITS) + return NULL; + + if (cfg->oas > ARM_LPAE_MAX_ADDR_BITS) + return NULL; + + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return NULL; + + data->pg_shift = __ffs(cfg->pgsize_bitmap); + data->bits_per_level = data->pg_shift - ilog2(sizeof(arm_lpae_iopte)); + + va_bits = cfg->ias - data->pg_shift; + data->levels = DIV_ROUND_UP(va_bits, data->bits_per_level); + + /* Calculate the actual size of our pgd (without concatenation) */ + pgd_bits = va_bits - (data->bits_per_level * (data->levels - 1)); + data->pgd_size = 1UL << (pgd_bits + ilog2(sizeof(arm_lpae_iopte))); + + data->iop.ops = (struct io_pgtable_ops) { + .map = arm_lpae_map, + .unmap = arm_lpae_unmap, + .iova_to_phys = arm_lpae_iova_to_phys, + }; + + return data; +} + +static struct io_pgtable * +arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) +{ + u64 reg; + struct arm_lpae_io_pgtable *data = arm_lpae_alloc_pgtable(cfg); + + if (!data) + return NULL; + + /* TCR */ + reg = (ARM_LPAE_TCR_SH_IS << ARM_LPAE_TCR_SH0_SHIFT) | + (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) | + (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT); + + switch (1 << data->pg_shift) { + case SZ_4K: + reg |= ARM_LPAE_TCR_TG0_4K; + break; + case SZ_16K: + reg |= ARM_LPAE_TCR_TG0_16K; + break; + case SZ_64K: + reg |= ARM_LPAE_TCR_TG0_64K; + break; + } + + switch (cfg->oas) { + case 32: + reg |= (ARM_LPAE_TCR_PS_32_BIT << ARM_LPAE_TCR_IPS_SHIFT); + break; + case 36: + reg |= (ARM_LPAE_TCR_PS_36_BIT << ARM_LPAE_TCR_IPS_SHIFT); + break; + case 40: + reg |= (ARM_LPAE_TCR_PS_40_BIT << ARM_LPAE_TCR_IPS_SHIFT); + break; + case 42: + reg |= (ARM_LPAE_TCR_PS_42_BIT << ARM_LPAE_TCR_IPS_SHIFT); + break; + case 44: + reg |= (ARM_LPAE_TCR_PS_44_BIT << ARM_LPAE_TCR_IPS_SHIFT); + break; + case 48: + reg |= (ARM_LPAE_TCR_PS_48_BIT << ARM_LPAE_TCR_IPS_SHIFT); + break; + default: + goto out_free_data; + } + + reg |= (64ULL - cfg->ias) << ARM_LPAE_TCR_T0SZ_SHIFT; + cfg->arm_lpae_s1_cfg.tcr = reg; + + /* MAIRs */ + reg = (ARM_LPAE_MAIR_ATTR_NC + << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_NC)) | + (ARM_LPAE_MAIR_ATTR_WBRWA + << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_CACHE)) | + (ARM_LPAE_MAIR_ATTR_DEVICE + << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_DEV)); + + cfg->arm_lpae_s1_cfg.mair[0] = reg; + cfg->arm_lpae_s1_cfg.mair[1] = 0; + + /* Looking good; allocate a pgd */ + data->pgd = alloc_pages_exact(data->pgd_size, GFP_KERNEL | __GFP_ZERO); + if (!data->pgd) + goto out_free_data; + + cfg->tlb->flush_pgtable(data->pgd, data->pgd_size, cookie); + + /* TTBRs */ + cfg->arm_lpae_s1_cfg.ttbr[0] = virt_to_phys(data->pgd); + cfg->arm_lpae_s1_cfg.ttbr[1] = 0; + return &data->iop; + +out_free_data: + kfree(data); + return NULL; +} + +static struct io_pgtable * +arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) +{ + u64 reg, sl; + struct arm_lpae_io_pgtable *data = arm_lpae_alloc_pgtable(cfg); + + if (!data) + return NULL; + + /* + * Concatenate PGDs at level 1 if possible in order to reduce + * the depth of the stage-2 walk. + */ + if (data->levels == ARM_LPAE_MAX_LEVELS) { + unsigned long pgd_pages; + + pgd_pages = data->pgd_size >> ilog2(sizeof(arm_lpae_iopte)); + if (pgd_pages <= ARM_LPAE_S2_MAX_CONCAT_PAGES) { + data->pgd_size = pgd_pages << data->pg_shift; + data->levels--; + } + } + + /* VTCR */ + reg = ARM_64_LPAE_S2_TCR_RES1 | + (ARM_LPAE_TCR_SH_IS << ARM_LPAE_TCR_SH0_SHIFT) | + (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) | + (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT); + + sl = ARM_LPAE_START_LVL(data); + + switch (1 << data->pg_shift) { + case SZ_4K: + reg |= ARM_LPAE_TCR_TG0_4K; + sl++; /* SL0 format is different for 4K granule size */ + break; + case SZ_16K: + reg |= ARM_LPAE_TCR_TG0_16K; + break; + case SZ_64K: + reg |= ARM_LPAE_TCR_TG0_64K; + break; + } + + switch (cfg->oas) { + case 32: + reg |= (ARM_LPAE_TCR_PS_32_BIT << ARM_LPAE_TCR_PS_SHIFT); + break; + case 36: + reg |= (ARM_LPAE_TCR_PS_36_BIT << ARM_LPAE_TCR_PS_SHIFT); + break; + case 40: + reg |= (ARM_LPAE_TCR_PS_40_BIT << ARM_LPAE_TCR_PS_SHIFT); + break; + case 42: + reg |= (ARM_LPAE_TCR_PS_42_BIT << ARM_LPAE_TCR_PS_SHIFT); + break; + case 44: + reg |= (ARM_LPAE_TCR_PS_44_BIT << ARM_LPAE_TCR_PS_SHIFT); + break; + case 48: + reg |= (ARM_LPAE_TCR_PS_48_BIT << ARM_LPAE_TCR_PS_SHIFT); + break; + default: + goto out_free_data; + } + + reg |= (64ULL - cfg->ias) << ARM_LPAE_TCR_T0SZ_SHIFT; + reg |= (~sl & ARM_LPAE_TCR_SL0_MASK) << ARM_LPAE_TCR_SL0_SHIFT; + cfg->arm_lpae_s2_cfg.vtcr = reg; + + /* Allocate pgd pages */ + data->pgd = alloc_pages_exact(data->pgd_size, GFP_KERNEL | __GFP_ZERO); + if (!data->pgd) + goto out_free_data; + + cfg->tlb->flush_pgtable(data->pgd, data->pgd_size, cookie); + + /* VTTBR */ + cfg->arm_lpae_s2_cfg.vttbr = virt_to_phys(data->pgd); + return &data->iop; + +out_free_data: + kfree(data); + return NULL; +} + +static struct io_pgtable * +arm_32_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) +{ + struct io_pgtable *iop; + + if (cfg->ias > 32 || cfg->oas > 40) + return NULL; + + cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G); + iop = arm_64_lpae_alloc_pgtable_s1(cfg, cookie); + if (iop) { + cfg->arm_lpae_s1_cfg.tcr |= ARM_32_LPAE_TCR_EAE; + cfg->arm_lpae_s1_cfg.tcr &= 0xffffffff; + } + + return iop; +} + +static struct io_pgtable * +arm_32_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) +{ + struct io_pgtable *iop; + + if (cfg->ias > 40 || cfg->oas > 40) + return NULL; + + cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G); + iop = arm_64_lpae_alloc_pgtable_s2(cfg, cookie); + if (iop) + cfg->arm_lpae_s2_cfg.vtcr &= 0xffffffff; + + return iop; +} + +struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns = { + .alloc = arm_64_lpae_alloc_pgtable_s1, + .free = arm_lpae_free_pgtable, +}; + +struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s2_init_fns = { + .alloc = arm_64_lpae_alloc_pgtable_s2, + .free = arm_lpae_free_pgtable, +}; + +struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s1_init_fns = { + .alloc = arm_32_lpae_alloc_pgtable_s1, + .free = arm_lpae_free_pgtable, +}; + +struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s2_init_fns = { + .alloc = arm_32_lpae_alloc_pgtable_s2, + .free = arm_lpae_free_pgtable, +}; + +#ifdef CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST + +static struct io_pgtable_cfg *cfg_cookie; + +static void dummy_tlb_flush_all(void *cookie) +{ + WARN_ON(cookie != cfg_cookie); +} + +static void dummy_tlb_add_flush(unsigned long iova, size_t size, bool leaf, + void *cookie) +{ + WARN_ON(cookie != cfg_cookie); + WARN_ON(!(size & cfg_cookie->pgsize_bitmap)); +} + +static void dummy_tlb_sync(void *cookie) +{ + WARN_ON(cookie != cfg_cookie); +} + +static void dummy_flush_pgtable(void *ptr, size_t size, void *cookie) +{ + WARN_ON(cookie != cfg_cookie); +} + +static struct iommu_gather_ops dummy_tlb_ops __initdata = { + .tlb_flush_all = dummy_tlb_flush_all, + .tlb_add_flush = dummy_tlb_add_flush, + .tlb_sync = dummy_tlb_sync, + .flush_pgtable = dummy_flush_pgtable, +}; + +static void __init arm_lpae_dump_ops(struct io_pgtable_ops *ops) +{ + struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); + struct io_pgtable_cfg *cfg = &data->iop.cfg; + + pr_err("cfg: pgsize_bitmap 0x%lx, ias %u-bit\n", + cfg->pgsize_bitmap, cfg->ias); + pr_err("data: %d levels, 0x%zx pgd_size, %lu pg_shift, %lu bits_per_level, pgd @ %p\n", + data->levels, data->pgd_size, data->pg_shift, + data->bits_per_level, data->pgd); +} + +#define __FAIL(ops, i) ({ \ + WARN(1, "selftest: test failed for fmt idx %d\n", (i)); \ + arm_lpae_dump_ops(ops); \ + selftest_running = false; \ + -EFAULT; \ +}) + +static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) +{ + static const enum io_pgtable_fmt fmts[] = { + ARM_64_LPAE_S1, + ARM_64_LPAE_S2, + }; + + int i, j; + unsigned long iova; + size_t size; + struct io_pgtable_ops *ops; + + selftest_running = true; + + for (i = 0; i < ARRAY_SIZE(fmts); ++i) { + cfg_cookie = cfg; + ops = alloc_io_pgtable_ops(fmts[i], cfg, cfg); + if (!ops) { + pr_err("selftest: failed to allocate io pgtable ops\n"); + return -ENOMEM; + } + + /* + * Initial sanity checks. + * Empty page tables shouldn't provide any translations. + */ + if (ops->iova_to_phys(ops, 42)) + return __FAIL(ops, i); + + if (ops->iova_to_phys(ops, SZ_1G + 42)) + return __FAIL(ops, i); + + if (ops->iova_to_phys(ops, SZ_2G + 42)) + return __FAIL(ops, i); + + /* + * Distinct mappings of different granule sizes. + */ + iova = 0; + j = find_first_bit(&cfg->pgsize_bitmap, BITS_PER_LONG); + while (j != BITS_PER_LONG) { + size = 1UL << j; + + if (ops->map(ops, iova, iova, size, IOMMU_READ | + IOMMU_WRITE | + IOMMU_NOEXEC | + IOMMU_CACHE)) + return __FAIL(ops, i); + + /* Overlapping mappings */ + if (!ops->map(ops, iova, iova + size, size, + IOMMU_READ | IOMMU_NOEXEC)) + return __FAIL(ops, i); + + if (ops->iova_to_phys(ops, iova + 42) != (iova + 42)) + return __FAIL(ops, i); + + iova += SZ_1G; + j++; + j = find_next_bit(&cfg->pgsize_bitmap, BITS_PER_LONG, j); + } + + /* Partial unmap */ + size = 1UL << __ffs(cfg->pgsize_bitmap); + if (ops->unmap(ops, SZ_1G + size, size) != size) + return __FAIL(ops, i); + + /* Remap of partial unmap */ + if (ops->map(ops, SZ_1G + size, size, size, IOMMU_READ)) + return __FAIL(ops, i); + + if (ops->iova_to_phys(ops, SZ_1G + size + 42) != (size + 42)) + return __FAIL(ops, i); + + /* Full unmap */ + iova = 0; + j = find_first_bit(&cfg->pgsize_bitmap, BITS_PER_LONG); + while (j != BITS_PER_LONG) { + size = 1UL << j; + + if (ops->unmap(ops, iova, size) != size) + return __FAIL(ops, i); + + if (ops->iova_to_phys(ops, iova + 42)) + return __FAIL(ops, i); + + /* Remap full block */ + if (ops->map(ops, iova, iova, size, IOMMU_WRITE)) + return __FAIL(ops, i); + + if (ops->iova_to_phys(ops, iova + 42) != (iova + 42)) + return __FAIL(ops, i); + + iova += SZ_1G; + j++; + j = find_next_bit(&cfg->pgsize_bitmap, BITS_PER_LONG, j); + } + + free_io_pgtable_ops(ops); + } + + selftest_running = false; + return 0; +} + +static int __init arm_lpae_do_selftests(void) +{ + static const unsigned long pgsize[] = { + SZ_4K | SZ_2M | SZ_1G, + SZ_16K | SZ_32M, + SZ_64K | SZ_512M, + }; + + static const unsigned int ias[] = { + 32, 36, 40, 42, 44, 48, + }; + + int i, j, pass = 0, fail = 0; + struct io_pgtable_cfg cfg = { + .tlb = &dummy_tlb_ops, + .oas = 48, + }; + + for (i = 0; i < ARRAY_SIZE(pgsize); ++i) { + for (j = 0; j < ARRAY_SIZE(ias); ++j) { + cfg.pgsize_bitmap = pgsize[i]; + cfg.ias = ias[j]; + pr_info("selftest: pgsize_bitmap 0x%08lx, IAS %u\n", + pgsize[i], ias[j]); + if (arm_lpae_run_tests(&cfg)) + fail++; + else + pass++; + } + } + + pr_info("selftest: completed with %d PASS %d FAIL\n", pass, fail); + return fail ? -EFAULT : 0; +} +subsys_initcall(arm_lpae_do_selftests); +#endif diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c new file mode 100644 index 000000000000..6436fe24bc2f --- /dev/null +++ b/drivers/iommu/io-pgtable.c @@ -0,0 +1,82 @@ +/* + * Generic page table allocator for IOMMUs. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Copyright (C) 2014 ARM Limited + * + * Author: Will Deacon + */ + +#include +#include +#include + +#include "io-pgtable.h" + +extern struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s1_init_fns; +extern struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s2_init_fns; +extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns; +extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s2_init_fns; + +static const struct io_pgtable_init_fns * +io_pgtable_init_table[IO_PGTABLE_NUM_FMTS] = +{ +#ifdef CONFIG_IOMMU_IO_PGTABLE_LPAE + [ARM_32_LPAE_S1] = &io_pgtable_arm_32_lpae_s1_init_fns, + [ARM_32_LPAE_S2] = &io_pgtable_arm_32_lpae_s2_init_fns, + [ARM_64_LPAE_S1] = &io_pgtable_arm_64_lpae_s1_init_fns, + [ARM_64_LPAE_S2] = &io_pgtable_arm_64_lpae_s2_init_fns, +#endif +}; + +struct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt, + struct io_pgtable_cfg *cfg, + void *cookie) +{ + struct io_pgtable *iop; + const struct io_pgtable_init_fns *fns; + + if (fmt >= IO_PGTABLE_NUM_FMTS) + return NULL; + + fns = io_pgtable_init_table[fmt]; + if (!fns) + return NULL; + + iop = fns->alloc(cfg, cookie); + if (!iop) + return NULL; + + iop->fmt = fmt; + iop->cookie = cookie; + iop->cfg = *cfg; + + return &iop->ops; +} + +/* + * It is the IOMMU driver's responsibility to ensure that the page table + * is no longer accessible to the walker by this point. + */ +void free_io_pgtable_ops(struct io_pgtable_ops *ops) +{ + struct io_pgtable *iop; + + if (!ops) + return; + + iop = container_of(ops, struct io_pgtable, ops); + iop->cfg.tlb->tlb_flush_all(iop->cookie); + io_pgtable_init_table[iop->fmt]->free(iop); +} diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h new file mode 100644 index 000000000000..10e32f69c668 --- /dev/null +++ b/drivers/iommu/io-pgtable.h @@ -0,0 +1,143 @@ +#ifndef __IO_PGTABLE_H +#define __IO_PGTABLE_H + +/* + * Public API for use by IOMMU drivers + */ +enum io_pgtable_fmt { + ARM_32_LPAE_S1, + ARM_32_LPAE_S2, + ARM_64_LPAE_S1, + ARM_64_LPAE_S2, + IO_PGTABLE_NUM_FMTS, +}; + +/** + * struct iommu_gather_ops - IOMMU callbacks for TLB and page table management. + * + * @tlb_flush_all: Synchronously invalidate the entire TLB context. + * @tlb_add_flush: Queue up a TLB invalidation for a virtual address range. + * @tlb_sync: Ensure any queue TLB invalidation has taken effect. + * @flush_pgtable: Ensure page table updates are visible to the IOMMU. + * + * Note that these can all be called in atomic context and must therefore + * not block. + */ +struct iommu_gather_ops { + void (*tlb_flush_all)(void *cookie); + void (*tlb_add_flush)(unsigned long iova, size_t size, bool leaf, + void *cookie); + void (*tlb_sync)(void *cookie); + void (*flush_pgtable)(void *ptr, size_t size, void *cookie); +}; + +/** + * struct io_pgtable_cfg - Configuration data for a set of page tables. + * + * @quirks: A bitmap of hardware quirks that require some special + * action by the low-level page table allocator. + * @pgsize_bitmap: A bitmap of page sizes supported by this set of page + * tables. + * @ias: Input address (iova) size, in bits. + * @oas: Output address (paddr) size, in bits. + * @tlb: TLB management callbacks for this set of tables. + */ +struct io_pgtable_cfg { + #define IO_PGTABLE_QUIRK_ARM_NS (1 << 0) /* Set NS bit in PTEs */ + int quirks; + unsigned long pgsize_bitmap; + unsigned int ias; + unsigned int oas; + const struct iommu_gather_ops *tlb; + + /* Low-level data specific to the table format */ + union { + struct { + u64 ttbr[2]; + u64 tcr; + u64 mair[2]; + } arm_lpae_s1_cfg; + + struct { + u64 vttbr; + u64 vtcr; + } arm_lpae_s2_cfg; + }; +}; + +/** + * struct io_pgtable_ops - Page table manipulation API for IOMMU drivers. + * + * @map: Map a physically contiguous memory region. + * @unmap: Unmap a physically contiguous memory region. + * @iova_to_phys: Translate iova to physical address. + * + * These functions map directly onto the iommu_ops member functions with + * the same names. + */ +struct io_pgtable_ops { + int (*map)(struct io_pgtable_ops *ops, unsigned long iova, + phys_addr_t paddr, size_t size, int prot); + int (*unmap)(struct io_pgtable_ops *ops, unsigned long iova, + size_t size); + phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *ops, + unsigned long iova); +}; + +/** + * alloc_io_pgtable_ops() - Allocate a page table allocator for use by an IOMMU. + * + * @fmt: The page table format. + * @cfg: The page table configuration. This will be modified to represent + * the configuration actually provided by the allocator (e.g. the + * pgsize_bitmap may be restricted). + * @cookie: An opaque token provided by the IOMMU driver and passed back to + * the callback routines in cfg->tlb. + */ +struct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt, + struct io_pgtable_cfg *cfg, + void *cookie); + +/** + * free_io_pgtable_ops() - Free an io_pgtable_ops structure. The caller + * *must* ensure that the page table is no longer + * live, but the TLB can be dirty. + * + * @ops: The ops returned from alloc_io_pgtable_ops. + */ +void free_io_pgtable_ops(struct io_pgtable_ops *ops); + + +/* + * Internal structures for page table allocator implementations. + */ + +/** + * struct io_pgtable - Internal structure describing a set of page tables. + * + * @fmt: The page table format. + * @cookie: An opaque token provided by the IOMMU driver and passed back to + * any callback routines. + * @cfg: A copy of the page table configuration. + * @ops: The page table operations in use for this set of page tables. + */ +struct io_pgtable { + enum io_pgtable_fmt fmt; + void *cookie; + struct io_pgtable_cfg cfg; + struct io_pgtable_ops ops; +}; + +/** + * struct io_pgtable_init_fns - Alloc/free a set of page tables for a + * particular format. + * + * @alloc: Allocate a set of page tables described by cfg. + * @free: Free the page tables associated with iop. + */ +struct io_pgtable_init_fns { + struct io_pgtable *(*alloc)(struct io_pgtable_cfg *cfg, void *cookie); + void (*free)(struct io_pgtable *iop); +}; + +#endif /* __IO_PGTABLE_H */ diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index f7718d73e984..72e683df0731 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2007-2008 Advanced Micro Devices, Inc. - * Author: Joerg Roedel + * Author: Joerg Roedel * * This 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 @@ -1084,7 +1084,7 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, if (ret) iommu_unmap(domain, orig_iova, orig_size - size); else - trace_map(iova, paddr, size); + trace_map(orig_iova, paddr, orig_size); return ret; } @@ -1094,6 +1094,7 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) { size_t unmapped_page, unmapped = 0; unsigned int min_pagesz; + unsigned long orig_iova = iova; if (unlikely(domain->ops->unmap == NULL || domain->ops->pgsize_bitmap == 0UL)) @@ -1133,7 +1134,7 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) unmapped += unmapped_page; } - trace_unmap(iova, 0, size); + trace_unmap(orig_iova, size, unmapped); return unmapped; } EXPORT_SYMBOL_GPL(iommu_unmap); diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index f6b17e6af2fb..9dd8208312c2 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -18,13 +18,58 @@ */ #include +#include + +static struct kmem_cache *iommu_iova_cache; + +int iommu_iova_cache_init(void) +{ + int ret = 0; + + iommu_iova_cache = kmem_cache_create("iommu_iova", + sizeof(struct iova), + 0, + SLAB_HWCACHE_ALIGN, + NULL); + if (!iommu_iova_cache) { + pr_err("Couldn't create iova cache\n"); + ret = -ENOMEM; + } + + return ret; +} + +void iommu_iova_cache_destroy(void) +{ + kmem_cache_destroy(iommu_iova_cache); +} + +struct iova *alloc_iova_mem(void) +{ + return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC); +} + +void free_iova_mem(struct iova *iova) +{ + kmem_cache_free(iommu_iova_cache, iova); +} void -init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit) +init_iova_domain(struct iova_domain *iovad, unsigned long granule, + unsigned long start_pfn, unsigned long pfn_32bit) { + /* + * IOVA granularity will normally be equal to the smallest + * supported IOMMU page size; both *must* be capable of + * representing individual CPU pages exactly. + */ + BUG_ON((granule > PAGE_SIZE) || !is_power_of_2(granule)); + spin_lock_init(&iovad->iova_rbtree_lock); iovad->rbroot = RB_ROOT; iovad->cached32_node = NULL; + iovad->granule = granule; + iovad->start_pfn = start_pfn; iovad->dma_32bit_pfn = pfn_32bit; } @@ -127,7 +172,7 @@ move_left: if (!curr) { if (size_aligned) pad_size = iova_get_pad_size(size, limit_pfn); - if ((IOVA_START_PFN + size + pad_size) > limit_pfn) { + if ((iovad->start_pfn + size + pad_size) > limit_pfn) { spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); return -ENOMEM; } @@ -202,8 +247,8 @@ iova_insert_rbtree(struct rb_root *root, struct iova *iova) * @size: - size of page frames to allocate * @limit_pfn: - max limit address * @size_aligned: - set if size_aligned address range is required - * This function allocates an iova in the range limit_pfn to IOVA_START_PFN - * looking from limit_pfn instead from IOVA_START_PFN. If the size_aligned + * This function allocates an iova in the range iovad->start_pfn to limit_pfn, + * searching top-down from limit_pfn to iovad->start_pfn. If the size_aligned * flag is set then the allocated address iova->pfn_lo will be naturally * aligned on roundup_power_of_two(size). */ diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 748693192c20..10186cac7716 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -24,12 +24,13 @@ #include #include +#include "io-pgtable.h" + struct ipmmu_vmsa_device { struct device *dev; void __iomem *base; struct list_head list; - const struct ipmmu_vmsa_platform_data *pdata; unsigned int num_utlbs; struct dma_iommu_mapping *mapping; @@ -39,14 +40,17 @@ struct ipmmu_vmsa_domain { struct ipmmu_vmsa_device *mmu; struct iommu_domain *io_domain; + struct io_pgtable_cfg cfg; + struct io_pgtable_ops *iop; + unsigned int context_id; spinlock_t lock; /* Protects mappings */ - pgd_t *pgd; }; struct ipmmu_vmsa_archdata { struct ipmmu_vmsa_device *mmu; - unsigned int utlb; + unsigned int *utlbs; + unsigned int num_utlbs; }; static DEFINE_SPINLOCK(ipmmu_devices_lock); @@ -58,6 +62,8 @@ static LIST_HEAD(ipmmu_devices); * Registers Definition */ +#define IM_NS_ALIAS_OFFSET 0x800 + #define IM_CTX_SIZE 0x40 #define IMCTR 0x0000 @@ -170,52 +176,6 @@ static LIST_HEAD(ipmmu_devices); #define IMUASID_ASID0_MASK (0xff << 0) #define IMUASID_ASID0_SHIFT 0 -/* ----------------------------------------------------------------------------- - * Page Table Bits - */ - -/* - * VMSA states in section B3.6.3 "Control of Secure or Non-secure memory access, - * Long-descriptor format" that the NStable bit being set in a table descriptor - * will result in the NStable and NS bits of all child entries being ignored and - * considered as being set. The IPMMU seems not to comply with this, as it - * generates a secure access page fault if any of the NStable and NS bits isn't - * set when running in non-secure mode. - */ -#ifndef PMD_NSTABLE -#define PMD_NSTABLE (_AT(pmdval_t, 1) << 63) -#endif - -#define ARM_VMSA_PTE_XN (((pteval_t)3) << 53) -#define ARM_VMSA_PTE_CONT (((pteval_t)1) << 52) -#define ARM_VMSA_PTE_AF (((pteval_t)1) << 10) -#define ARM_VMSA_PTE_SH_NS (((pteval_t)0) << 8) -#define ARM_VMSA_PTE_SH_OS (((pteval_t)2) << 8) -#define ARM_VMSA_PTE_SH_IS (((pteval_t)3) << 8) -#define ARM_VMSA_PTE_SH_MASK (((pteval_t)3) << 8) -#define ARM_VMSA_PTE_NS (((pteval_t)1) << 5) -#define ARM_VMSA_PTE_PAGE (((pteval_t)3) << 0) - -/* Stage-1 PTE */ -#define ARM_VMSA_PTE_nG (((pteval_t)1) << 11) -#define ARM_VMSA_PTE_AP_UNPRIV (((pteval_t)1) << 6) -#define ARM_VMSA_PTE_AP_RDONLY (((pteval_t)2) << 6) -#define ARM_VMSA_PTE_AP_MASK (((pteval_t)3) << 6) -#define ARM_VMSA_PTE_ATTRINDX_MASK (((pteval_t)3) << 2) -#define ARM_VMSA_PTE_ATTRINDX_SHIFT 2 - -#define ARM_VMSA_PTE_ATTRS_MASK \ - (ARM_VMSA_PTE_XN | ARM_VMSA_PTE_CONT | ARM_VMSA_PTE_nG | \ - ARM_VMSA_PTE_AF | ARM_VMSA_PTE_SH_MASK | ARM_VMSA_PTE_AP_MASK | \ - ARM_VMSA_PTE_NS | ARM_VMSA_PTE_ATTRINDX_MASK) - -#define ARM_VMSA_PTE_CONT_ENTRIES 16 -#define ARM_VMSA_PTE_CONT_SIZE (PAGE_SIZE * ARM_VMSA_PTE_CONT_ENTRIES) - -#define IPMMU_PTRS_PER_PTE 512 -#define IPMMU_PTRS_PER_PMD 512 -#define IPMMU_PTRS_PER_PGD 4 - /* ----------------------------------------------------------------------------- * Read/Write Access */ @@ -305,18 +265,39 @@ static void ipmmu_utlb_disable(struct ipmmu_vmsa_domain *domain, ipmmu_write(mmu, IMUCTR(utlb), 0); } -static void ipmmu_flush_pgtable(struct ipmmu_vmsa_device *mmu, void *addr, - size_t size) +static void ipmmu_tlb_flush_all(void *cookie) { - unsigned long offset = (unsigned long)addr & ~PAGE_MASK; + struct ipmmu_vmsa_domain *domain = cookie; + + ipmmu_tlb_invalidate(domain); +} + +static void ipmmu_tlb_add_flush(unsigned long iova, size_t size, bool leaf, + void *cookie) +{ + /* The hardware doesn't support selective TLB flush. */ +} + +static void ipmmu_flush_pgtable(void *ptr, size_t size, void *cookie) +{ + unsigned long offset = (unsigned long)ptr & ~PAGE_MASK; + struct ipmmu_vmsa_domain *domain = cookie; /* * TODO: Add support for coherent walk through CCI with DVM and remove * cache handling. */ - dma_map_page(mmu->dev, virt_to_page(addr), offset, size, DMA_TO_DEVICE); + dma_map_page(domain->mmu->dev, virt_to_page(ptr), offset, size, + DMA_TO_DEVICE); } +static struct iommu_gather_ops ipmmu_gather_ops = { + .tlb_flush_all = ipmmu_tlb_flush_all, + .tlb_add_flush = ipmmu_tlb_add_flush, + .tlb_sync = ipmmu_tlb_flush_all, + .flush_pgtable = ipmmu_flush_pgtable, +}; + /* ----------------------------------------------------------------------------- * Domain/Context Management */ @@ -324,7 +305,28 @@ static void ipmmu_flush_pgtable(struct ipmmu_vmsa_device *mmu, void *addr, static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) { phys_addr_t ttbr; - u32 reg; + + /* + * Allocate the page table operations. + * + * VMSA states in section B3.6.3 "Control of Secure or Non-secure memory + * access, Long-descriptor format" that the NStable bit being set in a + * table descriptor will result in the NStable and NS bits of all child + * entries being ignored and considered as being set. The IPMMU seems + * not to comply with this, as it generates a secure access page fault + * if any of the NStable and NS bits isn't set when running in + * non-secure mode. + */ + domain->cfg.quirks = IO_PGTABLE_QUIRK_ARM_NS; + domain->cfg.pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K, + domain->cfg.ias = 32; + domain->cfg.oas = 40; + domain->cfg.tlb = &ipmmu_gather_ops; + + domain->iop = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &domain->cfg, + domain); + if (!domain->iop) + return -EINVAL; /* * TODO: When adding support for multiple contexts, find an unused @@ -333,9 +335,7 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) domain->context_id = 0; /* TTBR0 */ - ipmmu_flush_pgtable(domain->mmu, domain->pgd, - IPMMU_PTRS_PER_PGD * sizeof(*domain->pgd)); - ttbr = __pa(domain->pgd); + ttbr = domain->cfg.arm_lpae_s1_cfg.ttbr[0]; ipmmu_ctx_write(domain, IMTTLBR0, ttbr); ipmmu_ctx_write(domain, IMTTUBR0, ttbr >> 32); @@ -348,15 +348,8 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA | IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1); - /* - * MAIR0 - * We need three attributes only, non-cacheable, write-back read/write - * allocate and device memory. - */ - reg = (IMMAIR_ATTR_NC << IMMAIR_ATTR_SHIFT(IMMAIR_ATTR_IDX_NC)) - | (IMMAIR_ATTR_WBRWA << IMMAIR_ATTR_SHIFT(IMMAIR_ATTR_IDX_WBRWA)) - | (IMMAIR_ATTR_DEVICE << IMMAIR_ATTR_SHIFT(IMMAIR_ATTR_IDX_DEV)); - ipmmu_ctx_write(domain, IMMAIR0, reg); + /* MAIR0 */ + ipmmu_ctx_write(domain, IMMAIR0, domain->cfg.arm_lpae_s1_cfg.mair[0]); /* IMBUSCR */ ipmmu_ctx_write(domain, IMBUSCR, @@ -460,396 +453,6 @@ static irqreturn_t ipmmu_irq(int irq, void *dev) return ipmmu_domain_irq(domain); } -/* ----------------------------------------------------------------------------- - * Page Table Management - */ - -#define pud_pgtable(pud) pfn_to_page(__phys_to_pfn(pud_val(pud) & PHYS_MASK)) - -static void ipmmu_free_ptes(pmd_t *pmd) -{ - pgtable_t table = pmd_pgtable(*pmd); - __free_page(table); -} - -static void ipmmu_free_pmds(pud_t *pud) -{ - pmd_t *pmd = pmd_offset(pud, 0); - pgtable_t table; - unsigned int i; - - for (i = 0; i < IPMMU_PTRS_PER_PMD; ++i) { - if (!pmd_table(*pmd)) - continue; - - ipmmu_free_ptes(pmd); - pmd++; - } - - table = pud_pgtable(*pud); - __free_page(table); -} - -static void ipmmu_free_pgtables(struct ipmmu_vmsa_domain *domain) -{ - pgd_t *pgd, *pgd_base = domain->pgd; - unsigned int i; - - /* - * Recursively free the page tables for this domain. We don't care about - * speculative TLB filling, because the TLB will be nuked next time this - * context bank is re-allocated and no devices currently map to these - * tables. - */ - pgd = pgd_base; - for (i = 0; i < IPMMU_PTRS_PER_PGD; ++i) { - if (pgd_none(*pgd)) - continue; - ipmmu_free_pmds((pud_t *)pgd); - pgd++; - } - - kfree(pgd_base); -} - -/* - * We can't use the (pgd|pud|pmd|pte)_populate or the set_(pgd|pud|pmd|pte) - * functions as they would flush the CPU TLB. - */ - -static pte_t *ipmmu_alloc_pte(struct ipmmu_vmsa_device *mmu, pmd_t *pmd, - unsigned long iova) -{ - pte_t *pte; - - if (!pmd_none(*pmd)) - return pte_offset_kernel(pmd, iova); - - pte = (pte_t *)get_zeroed_page(GFP_ATOMIC); - if (!pte) - return NULL; - - ipmmu_flush_pgtable(mmu, pte, PAGE_SIZE); - *pmd = __pmd(__pa(pte) | PMD_NSTABLE | PMD_TYPE_TABLE); - ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd)); - - return pte + pte_index(iova); -} - -static pmd_t *ipmmu_alloc_pmd(struct ipmmu_vmsa_device *mmu, pgd_t *pgd, - unsigned long iova) -{ - pud_t *pud = (pud_t *)pgd; - pmd_t *pmd; - - if (!pud_none(*pud)) - return pmd_offset(pud, iova); - - pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC); - if (!pmd) - return NULL; - - ipmmu_flush_pgtable(mmu, pmd, PAGE_SIZE); - *pud = __pud(__pa(pmd) | PMD_NSTABLE | PMD_TYPE_TABLE); - ipmmu_flush_pgtable(mmu, pud, sizeof(*pud)); - - return pmd + pmd_index(iova); -} - -static u64 ipmmu_page_prot(unsigned int prot, u64 type) -{ - u64 pgprot = ARM_VMSA_PTE_nG | ARM_VMSA_PTE_AF - | ARM_VMSA_PTE_SH_IS | ARM_VMSA_PTE_AP_UNPRIV - | ARM_VMSA_PTE_NS | type; - - if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ)) - pgprot |= ARM_VMSA_PTE_AP_RDONLY; - - if (prot & IOMMU_CACHE) - pgprot |= IMMAIR_ATTR_IDX_WBRWA << ARM_VMSA_PTE_ATTRINDX_SHIFT; - - if (prot & IOMMU_NOEXEC) - pgprot |= ARM_VMSA_PTE_XN; - else if (!(prot & (IOMMU_READ | IOMMU_WRITE))) - /* If no access create a faulting entry to avoid TLB fills. */ - pgprot &= ~ARM_VMSA_PTE_PAGE; - - return pgprot; -} - -static int ipmmu_alloc_init_pte(struct ipmmu_vmsa_device *mmu, pmd_t *pmd, - unsigned long iova, unsigned long pfn, - size_t size, int prot) -{ - pteval_t pteval = ipmmu_page_prot(prot, ARM_VMSA_PTE_PAGE); - unsigned int num_ptes = 1; - pte_t *pte, *start; - unsigned int i; - - pte = ipmmu_alloc_pte(mmu, pmd, iova); - if (!pte) - return -ENOMEM; - - start = pte; - - /* - * Install the page table entries. We can be called both for a single - * page or for a block of 16 physically contiguous pages. In the latter - * case set the PTE contiguous hint. - */ - if (size == SZ_64K) { - pteval |= ARM_VMSA_PTE_CONT; - num_ptes = ARM_VMSA_PTE_CONT_ENTRIES; - } - - for (i = num_ptes; i; --i) - *pte++ = pfn_pte(pfn++, __pgprot(pteval)); - - ipmmu_flush_pgtable(mmu, start, sizeof(*pte) * num_ptes); - - return 0; -} - -static int ipmmu_alloc_init_pmd(struct ipmmu_vmsa_device *mmu, pmd_t *pmd, - unsigned long iova, unsigned long pfn, - int prot) -{ - pmdval_t pmdval = ipmmu_page_prot(prot, PMD_TYPE_SECT); - - *pmd = pfn_pmd(pfn, __pgprot(pmdval)); - ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd)); - - return 0; -} - -static int ipmmu_create_mapping(struct ipmmu_vmsa_domain *domain, - unsigned long iova, phys_addr_t paddr, - size_t size, int prot) -{ - struct ipmmu_vmsa_device *mmu = domain->mmu; - pgd_t *pgd = domain->pgd; - unsigned long flags; - unsigned long pfn; - pmd_t *pmd; - int ret; - - if (!pgd) - return -EINVAL; - - if (size & ~PAGE_MASK) - return -EINVAL; - - if (paddr & ~((1ULL << 40) - 1)) - return -ERANGE; - - pfn = __phys_to_pfn(paddr); - pgd += pgd_index(iova); - - /* Update the page tables. */ - spin_lock_irqsave(&domain->lock, flags); - - pmd = ipmmu_alloc_pmd(mmu, pgd, iova); - if (!pmd) { - ret = -ENOMEM; - goto done; - } - - switch (size) { - case SZ_2M: - ret = ipmmu_alloc_init_pmd(mmu, pmd, iova, pfn, prot); - break; - case SZ_64K: - case SZ_4K: - ret = ipmmu_alloc_init_pte(mmu, pmd, iova, pfn, size, prot); - break; - default: - ret = -EINVAL; - break; - } - -done: - spin_unlock_irqrestore(&domain->lock, flags); - - if (!ret) - ipmmu_tlb_invalidate(domain); - - return ret; -} - -static void ipmmu_clear_pud(struct ipmmu_vmsa_device *mmu, pud_t *pud) -{ - /* Free the page table. */ - pgtable_t table = pud_pgtable(*pud); - __free_page(table); - - /* Clear the PUD. */ - *pud = __pud(0); - ipmmu_flush_pgtable(mmu, pud, sizeof(*pud)); -} - -static void ipmmu_clear_pmd(struct ipmmu_vmsa_device *mmu, pud_t *pud, - pmd_t *pmd) -{ - unsigned int i; - - /* Free the page table. */ - if (pmd_table(*pmd)) { - pgtable_t table = pmd_pgtable(*pmd); - __free_page(table); - } - - /* Clear the PMD. */ - *pmd = __pmd(0); - ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd)); - - /* Check whether the PUD is still needed. */ - pmd = pmd_offset(pud, 0); - for (i = 0; i < IPMMU_PTRS_PER_PMD; ++i) { - if (!pmd_none(pmd[i])) - return; - } - - /* Clear the parent PUD. */ - ipmmu_clear_pud(mmu, pud); -} - -static void ipmmu_clear_pte(struct ipmmu_vmsa_device *mmu, pud_t *pud, - pmd_t *pmd, pte_t *pte, unsigned int num_ptes) -{ - unsigned int i; - - /* Clear the PTE. */ - for (i = num_ptes; i; --i) - pte[i-1] = __pte(0); - - ipmmu_flush_pgtable(mmu, pte, sizeof(*pte) * num_ptes); - - /* Check whether the PMD is still needed. */ - pte = pte_offset_kernel(pmd, 0); - for (i = 0; i < IPMMU_PTRS_PER_PTE; ++i) { - if (!pte_none(pte[i])) - return; - } - - /* Clear the parent PMD. */ - ipmmu_clear_pmd(mmu, pud, pmd); -} - -static int ipmmu_split_pmd(struct ipmmu_vmsa_device *mmu, pmd_t *pmd) -{ - pte_t *pte, *start; - pteval_t pteval; - unsigned long pfn; - unsigned int i; - - pte = (pte_t *)get_zeroed_page(GFP_ATOMIC); - if (!pte) - return -ENOMEM; - - /* Copy the PMD attributes. */ - pteval = (pmd_val(*pmd) & ARM_VMSA_PTE_ATTRS_MASK) - | ARM_VMSA_PTE_CONT | ARM_VMSA_PTE_PAGE; - - pfn = pmd_pfn(*pmd); - start = pte; - - for (i = IPMMU_PTRS_PER_PTE; i; --i) - *pte++ = pfn_pte(pfn++, __pgprot(pteval)); - - ipmmu_flush_pgtable(mmu, start, PAGE_SIZE); - *pmd = __pmd(__pa(start) | PMD_NSTABLE | PMD_TYPE_TABLE); - ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd)); - - return 0; -} - -static void ipmmu_split_pte(struct ipmmu_vmsa_device *mmu, pte_t *pte) -{ - unsigned int i; - - for (i = ARM_VMSA_PTE_CONT_ENTRIES; i; --i) - pte[i-1] = __pte(pte_val(*pte) & ~ARM_VMSA_PTE_CONT); - - ipmmu_flush_pgtable(mmu, pte, sizeof(*pte) * ARM_VMSA_PTE_CONT_ENTRIES); -} - -static int ipmmu_clear_mapping(struct ipmmu_vmsa_domain *domain, - unsigned long iova, size_t size) -{ - struct ipmmu_vmsa_device *mmu = domain->mmu; - unsigned long flags; - pgd_t *pgd = domain->pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - int ret = 0; - - if (!pgd) - return -EINVAL; - - if (size & ~PAGE_MASK) - return -EINVAL; - - pgd += pgd_index(iova); - pud = (pud_t *)pgd; - - spin_lock_irqsave(&domain->lock, flags); - - /* If there's no PUD or PMD we're done. */ - if (pud_none(*pud)) - goto done; - - pmd = pmd_offset(pud, iova); - if (pmd_none(*pmd)) - goto done; - - /* - * When freeing a 2MB block just clear the PMD. In the unlikely case the - * block is mapped as individual pages this will free the corresponding - * PTE page table. - */ - if (size == SZ_2M) { - ipmmu_clear_pmd(mmu, pud, pmd); - goto done; - } - - /* - * If the PMD has been mapped as a section remap it as pages to allow - * freeing individual pages. - */ - if (pmd_sect(*pmd)) - ipmmu_split_pmd(mmu, pmd); - - pte = pte_offset_kernel(pmd, iova); - - /* - * When freeing a 64kB block just clear the PTE entries. We don't have - * to care about the contiguous hint of the surrounding entries. - */ - if (size == SZ_64K) { - ipmmu_clear_pte(mmu, pud, pmd, pte, ARM_VMSA_PTE_CONT_ENTRIES); - goto done; - } - - /* - * If the PTE has been mapped with the contiguous hint set remap it and - * its surrounding PTEs to allow unmapping a single page. - */ - if (pte_val(*pte) & ARM_VMSA_PTE_CONT) - ipmmu_split_pte(mmu, pte); - - /* Clear the PTE. */ - ipmmu_clear_pte(mmu, pud, pmd, pte, 1); - -done: - spin_unlock_irqrestore(&domain->lock, flags); - - if (ret) - ipmmu_tlb_invalidate(domain); - - return 0; -} - /* ----------------------------------------------------------------------------- * IOMMU Operations */ @@ -864,12 +467,6 @@ static int ipmmu_domain_init(struct iommu_domain *io_domain) spin_lock_init(&domain->lock); - domain->pgd = kzalloc(IPMMU_PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL); - if (!domain->pgd) { - kfree(domain); - return -ENOMEM; - } - io_domain->priv = domain; domain->io_domain = io_domain; @@ -885,7 +482,7 @@ static void ipmmu_domain_destroy(struct iommu_domain *io_domain) * been detached. */ ipmmu_domain_destroy_context(domain); - ipmmu_free_pgtables(domain); + free_io_pgtable_ops(domain->iop); kfree(domain); } @@ -896,6 +493,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, struct ipmmu_vmsa_device *mmu = archdata->mmu; struct ipmmu_vmsa_domain *domain = io_domain->priv; unsigned long flags; + unsigned int i; int ret = 0; if (!mmu) { @@ -924,7 +522,8 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, if (ret < 0) return ret; - ipmmu_utlb_enable(domain, archdata->utlb); + for (i = 0; i < archdata->num_utlbs; ++i) + ipmmu_utlb_enable(domain, archdata->utlbs[i]); return 0; } @@ -934,8 +533,10 @@ static void ipmmu_detach_device(struct iommu_domain *io_domain, { struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; struct ipmmu_vmsa_domain *domain = io_domain->priv; + unsigned int i; - ipmmu_utlb_disable(domain, archdata->utlb); + for (i = 0; i < archdata->num_utlbs; ++i) + ipmmu_utlb_disable(domain, archdata->utlbs[i]); /* * TODO: Optimize by disabling the context when no device is attached. @@ -950,76 +551,61 @@ static int ipmmu_map(struct iommu_domain *io_domain, unsigned long iova, if (!domain) return -ENODEV; - return ipmmu_create_mapping(domain, iova, paddr, size, prot); + return domain->iop->map(domain->iop, iova, paddr, size, prot); } static size_t ipmmu_unmap(struct iommu_domain *io_domain, unsigned long iova, size_t size) { struct ipmmu_vmsa_domain *domain = io_domain->priv; - int ret; - ret = ipmmu_clear_mapping(domain, iova, size); - return ret ? 0 : size; + return domain->iop->unmap(domain->iop, iova, size); } static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain, dma_addr_t iova) { struct ipmmu_vmsa_domain *domain = io_domain->priv; - pgd_t pgd; - pud_t pud; - pmd_t pmd; - pte_t pte; /* TODO: Is locking needed ? */ - if (!domain->pgd) - return 0; - - pgd = *(domain->pgd + pgd_index(iova)); - if (pgd_none(pgd)) - return 0; - - pud = *pud_offset(&pgd, iova); - if (pud_none(pud)) - return 0; - - pmd = *pmd_offset(&pud, iova); - if (pmd_none(pmd)) - return 0; - - if (pmd_sect(pmd)) - return __pfn_to_phys(pmd_pfn(pmd)) | (iova & ~PMD_MASK); - - pte = *(pmd_page_vaddr(pmd) + pte_index(iova)); - if (pte_none(pte)) - return 0; - - return __pfn_to_phys(pte_pfn(pte)) | (iova & ~PAGE_MASK); + return domain->iop->iova_to_phys(domain->iop, iova); } -static int ipmmu_find_utlb(struct ipmmu_vmsa_device *mmu, struct device *dev) +static int ipmmu_find_utlbs(struct ipmmu_vmsa_device *mmu, struct device *dev, + unsigned int *utlbs, unsigned int num_utlbs) { - const struct ipmmu_vmsa_master *master = mmu->pdata->masters; - const char *devname = dev_name(dev); unsigned int i; - for (i = 0; i < mmu->pdata->num_masters; ++i, ++master) { - if (strcmp(master->name, devname) == 0) - return master->utlb; + for (i = 0; i < num_utlbs; ++i) { + struct of_phandle_args args; + int ret; + + ret = of_parse_phandle_with_args(dev->of_node, "iommus", + "#iommu-cells", i, &args); + if (ret < 0) + return ret; + + of_node_put(args.np); + + if (args.np != mmu->dev->of_node || args.args_count != 1) + return -EINVAL; + + utlbs[i] = args.args[0]; } - return -1; + return 0; } static int ipmmu_add_device(struct device *dev) { struct ipmmu_vmsa_archdata *archdata; struct ipmmu_vmsa_device *mmu; - struct iommu_group *group; - int utlb = -1; - int ret; + struct iommu_group *group = NULL; + unsigned int *utlbs; + unsigned int i; + int num_utlbs; + int ret = -ENODEV; if (dev->archdata.iommu) { dev_warn(dev, "IOMMU driver already assigned to device %s\n", @@ -1028,11 +614,21 @@ static int ipmmu_add_device(struct device *dev) } /* Find the master corresponding to the device. */ + + num_utlbs = of_count_phandle_with_args(dev->of_node, "iommus", + "#iommu-cells"); + if (num_utlbs < 0) + return -ENODEV; + + utlbs = kcalloc(num_utlbs, sizeof(*utlbs), GFP_KERNEL); + if (!utlbs) + return -ENOMEM; + spin_lock(&ipmmu_devices_lock); list_for_each_entry(mmu, &ipmmu_devices, list) { - utlb = ipmmu_find_utlb(mmu, dev); - if (utlb >= 0) { + ret = ipmmu_find_utlbs(mmu, dev, utlbs, num_utlbs); + if (!ret) { /* * TODO Take a reference to the MMU to protect * against device removal. @@ -1043,17 +639,22 @@ static int ipmmu_add_device(struct device *dev) spin_unlock(&ipmmu_devices_lock); - if (utlb < 0) + if (ret < 0) return -ENODEV; - if (utlb >= mmu->num_utlbs) - return -EINVAL; + for (i = 0; i < num_utlbs; ++i) { + if (utlbs[i] >= mmu->num_utlbs) { + ret = -EINVAL; + goto error; + } + } /* Create a device group and add the device to it. */ group = iommu_group_alloc(); if (IS_ERR(group)) { dev_err(dev, "Failed to allocate IOMMU group\n"); - return PTR_ERR(group); + ret = PTR_ERR(group); + goto error; } ret = iommu_group_add_device(group, dev); @@ -1061,7 +662,8 @@ static int ipmmu_add_device(struct device *dev) if (ret < 0) { dev_err(dev, "Failed to add device to IPMMU group\n"); - return ret; + group = NULL; + goto error; } archdata = kzalloc(sizeof(*archdata), GFP_KERNEL); @@ -1071,7 +673,8 @@ static int ipmmu_add_device(struct device *dev) } archdata->mmu = mmu; - archdata->utlb = utlb; + archdata->utlbs = utlbs; + archdata->num_utlbs = num_utlbs; dev->archdata.iommu = archdata; /* @@ -1090,7 +693,8 @@ static int ipmmu_add_device(struct device *dev) SZ_1G, SZ_2G); if (IS_ERR(mapping)) { dev_err(mmu->dev, "failed to create ARM IOMMU mapping\n"); - return PTR_ERR(mapping); + ret = PTR_ERR(mapping); + goto error; } mmu->mapping = mapping; @@ -1106,17 +710,29 @@ static int ipmmu_add_device(struct device *dev) return 0; error: + arm_iommu_release_mapping(mmu->mapping); + kfree(dev->archdata.iommu); + kfree(utlbs); + dev->archdata.iommu = NULL; - iommu_group_remove_device(dev); + + if (!IS_ERR_OR_NULL(group)) + iommu_group_remove_device(dev); + return ret; } static void ipmmu_remove_device(struct device *dev) { + struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; + arm_iommu_detach_device(dev); iommu_group_remove_device(dev); - kfree(dev->archdata.iommu); + + kfree(archdata->utlbs); + kfree(archdata); + dev->archdata.iommu = NULL; } @@ -1131,7 +747,7 @@ static const struct iommu_ops ipmmu_ops = { .iova_to_phys = ipmmu_iova_to_phys, .add_device = ipmmu_add_device, .remove_device = ipmmu_remove_device, - .pgsize_bitmap = SZ_2M | SZ_64K | SZ_4K, + .pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K, }; /* ----------------------------------------------------------------------------- @@ -1154,7 +770,7 @@ static int ipmmu_probe(struct platform_device *pdev) int irq; int ret; - if (!pdev->dev.platform_data) { + if (!IS_ENABLED(CONFIG_OF) && !pdev->dev.platform_data) { dev_err(&pdev->dev, "missing platform data\n"); return -EINVAL; } @@ -1166,7 +782,6 @@ static int ipmmu_probe(struct platform_device *pdev) } mmu->dev = &pdev->dev; - mmu->pdata = pdev->dev.platform_data; mmu->num_utlbs = 32; /* Map I/O memory and request IRQ. */ @@ -1175,6 +790,20 @@ static int ipmmu_probe(struct platform_device *pdev) if (IS_ERR(mmu->base)) return PTR_ERR(mmu->base); + /* + * The IPMMU has two register banks, for secure and non-secure modes. + * The bank mapped at the beginning of the IPMMU address space + * corresponds to the running mode of the CPU. When running in secure + * mode the non-secure register bank is also available at an offset. + * + * Secure mode operation isn't clearly documented and is thus currently + * not implemented in the driver. Furthermore, preliminary tests of + * non-secure operation with the main register bank were not successful. + * Offset the registers base unconditionally to point to the non-secure + * alias space for now. + */ + mmu->base += IM_NS_ALIAS_OFFSET; + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no IRQ found\n"); @@ -1220,9 +849,14 @@ static int ipmmu_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id ipmmu_of_ids[] = { + { .compatible = "renesas,ipmmu-vmsa", }, +}; + static struct platform_driver ipmmu_driver = { .driver = { .name = "ipmmu-vmsa", + .of_match_table = of_match_ptr(ipmmu_of_ids), }, .probe = ipmmu_probe, .remove = ipmmu_remove, diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 89c4846683be..390079ee1350 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -17,12 +17,11 @@ #include "irq_remapping.h" int irq_remapping_enabled; - -int disable_irq_remap; int irq_remap_broken; int disable_sourceid_checking; int no_x2apic_optout; +static int disable_irq_remap; static struct irq_remap_ops *remap_ops; static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec); @@ -194,45 +193,32 @@ static __init int setup_irqremap(char *str) } early_param("intremap", setup_irqremap); -void __init setup_irq_remapping_ops(void) -{ - remap_ops = &intel_irq_remap_ops; - -#ifdef CONFIG_AMD_IOMMU - if (amd_iommu_irq_ops.prepare() == 0) - remap_ops = &amd_iommu_irq_ops; -#endif -} - void set_irq_remapping_broken(void) { irq_remap_broken = 1; } -int irq_remapping_supported(void) -{ - if (disable_irq_remap) - return 0; - - if (!remap_ops || !remap_ops->supported) - return 0; - - return remap_ops->supported(); -} - int __init irq_remapping_prepare(void) { - if (!remap_ops || !remap_ops->prepare) - return -ENODEV; + if (disable_irq_remap) + return -ENOSYS; - return remap_ops->prepare(); + if (intel_irq_remap_ops.prepare() == 0) + remap_ops = &intel_irq_remap_ops; + else if (IS_ENABLED(CONFIG_AMD_IOMMU) && + amd_iommu_irq_ops.prepare() == 0) + remap_ops = &amd_iommu_irq_ops; + else + return -ENOSYS; + + return 0; } int __init irq_remapping_enable(void) { int ret; - if (!remap_ops || !remap_ops->enable) + if (!remap_ops->enable) return -ENODEV; ret = remap_ops->enable(); @@ -245,22 +231,16 @@ int __init irq_remapping_enable(void) void irq_remapping_disable(void) { - if (!irq_remapping_enabled || - !remap_ops || - !remap_ops->disable) - return; - - remap_ops->disable(); + if (irq_remapping_enabled && remap_ops->disable) + remap_ops->disable(); } int irq_remapping_reenable(int mode) { - if (!irq_remapping_enabled || - !remap_ops || - !remap_ops->reenable) - return 0; + if (irq_remapping_enabled && remap_ops->reenable) + return remap_ops->reenable(mode); - return remap_ops->reenable(mode); + return 0; } int __init irq_remap_enable_fault_handling(void) @@ -268,7 +248,7 @@ int __init irq_remap_enable_fault_handling(void) if (!irq_remapping_enabled) return 0; - if (!remap_ops || !remap_ops->enable_faulting) + if (!remap_ops->enable_faulting) return -ENODEV; return remap_ops->enable_faulting(); @@ -279,7 +259,7 @@ int setup_ioapic_remapped_entry(int irq, unsigned int destination, int vector, struct io_apic_irq_attr *attr) { - if (!remap_ops || !remap_ops->setup_ioapic_entry) + if (!remap_ops->setup_ioapic_entry) return -ENODEV; return remap_ops->setup_ioapic_entry(irq, entry, destination, @@ -289,8 +269,7 @@ int setup_ioapic_remapped_entry(int irq, static int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask, bool force) { - if (!config_enabled(CONFIG_SMP) || !remap_ops || - !remap_ops->set_affinity) + if (!config_enabled(CONFIG_SMP) || !remap_ops->set_affinity) return 0; return remap_ops->set_affinity(data, mask, force); @@ -300,10 +279,7 @@ void free_remapped_irq(int irq) { struct irq_cfg *cfg = irq_cfg(irq); - if (!remap_ops || !remap_ops->free_irq) - return; - - if (irq_remapped(cfg)) + if (irq_remapped(cfg) && remap_ops->free_irq) remap_ops->free_irq(irq); } @@ -315,13 +291,13 @@ void compose_remapped_msi_msg(struct pci_dev *pdev, if (!irq_remapped(cfg)) native_compose_msi_msg(pdev, irq, dest, msg, hpet_id); - else if (remap_ops && remap_ops->compose_msi_msg) + else if (remap_ops->compose_msi_msg) remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id); } static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) { - if (!remap_ops || !remap_ops->msi_alloc_irq) + if (!remap_ops->msi_alloc_irq) return -ENODEV; return remap_ops->msi_alloc_irq(pdev, irq, nvec); @@ -330,7 +306,7 @@ static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, int index, int sub_handle) { - if (!remap_ops || !remap_ops->msi_setup_irq) + if (!remap_ops->msi_setup_irq) return -ENODEV; return remap_ops->msi_setup_irq(pdev, irq, index, sub_handle); @@ -340,7 +316,7 @@ int setup_hpet_msi_remapped(unsigned int irq, unsigned int id) { int ret; - if (!remap_ops || !remap_ops->alloc_hpet_msi) + if (!remap_ops->alloc_hpet_msi) return -ENODEV; ret = remap_ops->alloc_hpet_msi(irq, id); diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h index fde250f86e60..7c70cc29ffe6 100644 --- a/drivers/iommu/irq_remapping.h +++ b/drivers/iommu/irq_remapping.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2012 Advanced Micro Devices, Inc. - * Author: Joerg Roedel + * Author: Joerg Roedel * * This 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 @@ -31,16 +31,12 @@ struct cpumask; struct pci_dev; struct msi_msg; -extern int disable_irq_remap; extern int irq_remap_broken; extern int disable_sourceid_checking; extern int no_x2apic_optout; extern int irq_remapping_enabled; struct irq_remap_ops { - /* Check whether Interrupt Remapping is supported */ - int (*supported)(void); - /* Initializes hardware and makes it ready for remapping interrupts */ int (*prepare)(void); @@ -89,7 +85,6 @@ extern struct irq_remap_ops amd_iommu_irq_ops; #else /* CONFIG_IRQ_REMAP */ #define irq_remapping_enabled 0 -#define disable_irq_remap 1 #define irq_remap_broken 0 #endif /* CONFIG_IRQ_REMAP */ diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index bbb7dcef02d3..f59f857b702e 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1126,7 +1126,7 @@ static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, return -EINVAL; } - dev_dbg(dev, "mapping da 0x%lx to pa 0x%x size 0x%x\n", da, pa, bytes); + dev_dbg(dev, "mapping da 0x%lx to pa %pa size 0x%x\n", da, &pa, bytes); iotlb_init_entry(&e, da, pa, omap_pgsz); diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index f722a0c466cf..c48da057dbb1 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -315,6 +315,7 @@ static const struct iommu_ops gart_iommu_ops = { .attach_dev = gart_iommu_attach_dev, .detach_dev = gart_iommu_detach_dev, .map = gart_iommu_map, + .map_sg = default_iommu_map_sg, .unmap = gart_iommu_unmap, .iova_to_phys = gart_iommu_iova_to_phys, .pgsize_bitmap = GART_IOMMU_PGSIZES, @@ -395,7 +396,7 @@ static int tegra_gart_probe(struct platform_device *pdev) do_gart_setup(gart, NULL); gart_handle = gart; - bus_set_iommu(&platform_bus_type, &gart_iommu_ops); + return 0; } diff --git a/drivers/irqchip/irq-atmel-aic-common.c b/drivers/irqchip/irq-atmel-aic-common.c index d111ac779c40..63cd031b2c28 100644 --- a/drivers/irqchip/irq-atmel-aic-common.c +++ b/drivers/irqchip/irq-atmel-aic-common.c @@ -28,7 +28,7 @@ #define AT91_AIC_IRQ_MIN_PRIORITY 0 #define AT91_AIC_IRQ_MAX_PRIORITY 7 -#define AT91_AIC_SRCTYPE GENMASK(7, 6) +#define AT91_AIC_SRCTYPE GENMASK(6, 5) #define AT91_AIC_SRCTYPE_LOW (0 << 5) #define AT91_AIC_SRCTYPE_FALLING (1 << 5) #define AT91_AIC_SRCTYPE_HIGH (2 << 5) @@ -74,7 +74,7 @@ int aic_common_set_type(struct irq_data *d, unsigned type, unsigned *val) return -EINVAL; } - *val &= AT91_AIC_SRCTYPE; + *val &= ~AT91_AIC_SRCTYPE; *val |= aic_type; return 0; diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 86e4684adeb1..d8996bdf0f61 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1053,7 +1053,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, * of two entries. No, the architecture doesn't let you * express an ITT with a single entry. */ - nr_ites = max(2, roundup_pow_of_two(nvecs)); + nr_ites = max(2UL, roundup_pow_of_two(nvecs)); sz = nr_ites * its->ite_size; sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1; itt = kmalloc(sz, GFP_KERNEL); diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index 29b8f21b74d0..6bc2deb73d53 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -381,7 +381,7 @@ hip04_of_init(struct device_node *node, struct device_node *parent) * It will be refined as each CPU probes its ID. */ for (i = 0; i < NR_HIP04_CPU_IF; i++) - hip04_cpu_map[i] = 0xff; + hip04_cpu_map[i] = 0xffff; /* * Find out how many interrupts are supported. diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 2b0468e3df6a..56b96c63dc4b 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -37,6 +37,7 @@ static struct irq_domain *gic_irq_domain; static int gic_shared_intrs; static int gic_vpes; static unsigned int gic_cpu_pin; +static unsigned int timer_cpu_pin; static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; static void __gic_irq_dispatch(void); @@ -616,6 +617,8 @@ static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq, gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val); break; case GIC_LOCAL_INT_TIMER: + /* CONFIG_MIPS_CMP workaround (see __gic_init) */ + val = GIC_MAP_TO_PIN_MSK | timer_cpu_pin; gic_write(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val); break; case GIC_LOCAL_INT_PERFCTR: @@ -713,12 +716,36 @@ static void __init __gic_init(unsigned long gic_base_addr, if (cpu_has_veic) { /* Always use vector 1 in EIC mode */ gic_cpu_pin = 0; + timer_cpu_pin = gic_cpu_pin; set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET, __gic_irq_dispatch); } else { gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET; irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec, gic_irq_dispatch); + /* + * With the CMP implementation of SMP (deprecated), other CPUs + * are started by the bootloader and put into a timer based + * waiting poll loop. We must not re-route those CPU's local + * timer interrupts as the wait instruction will never finish, + * so just handle whatever CPU interrupt it is routed to by + * default. + * + * This workaround should be removed when CMP support is + * dropped. + */ + if (IS_ENABLED(CONFIG_MIPS_CMP) && + gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) { + timer_cpu_pin = gic_read(GIC_REG(VPE_LOCAL, + GIC_VPE_TIMER_MAP)) & + GIC_MAP_MSK; + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + + GIC_CPU_PIN_OFFSET + + timer_cpu_pin, + gic_irq_dispatch); + } else { + timer_cpu_pin = gic_cpu_pin; + } } gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS + diff --git a/drivers/irqchip/irq-mtk-sysirq.c b/drivers/irqchip/irq-mtk-sysirq.c index 7e342df6a62f..0b0d2c00a2df 100644 --- a/drivers/irqchip/irq-mtk-sysirq.c +++ b/drivers/irqchip/irq-mtk-sysirq.c @@ -137,9 +137,9 @@ static int __init mtk_sysirq_of_init(struct device_node *node, return -ENOMEM; chip_data->intpol_base = of_io_request_and_map(node, 0, "intpol"); - if (!chip_data->intpol_base) { + if (IS_ERR(chip_data->intpol_base)) { pr_err("mtk_sysirq: unable to map sysirq register\n"); - ret = -ENOMEM; + ret = PTR_ERR(chip_data->intpol_base); goto out_free; } diff --git a/drivers/irqchip/irq-omap-intc.c b/drivers/irqchip/irq-omap-intc.c index 28718d3e8281..c03f140acbae 100644 --- a/drivers/irqchip/irq-omap-intc.c +++ b/drivers/irqchip/irq-omap-intc.c @@ -263,7 +263,7 @@ static int __init omap_init_irq_of(struct device_node *node) return ret; } -static int __init omap_init_irq_legacy(u32 base) +static int __init omap_init_irq_legacy(u32 base, struct device_node *node) { int j, irq_base; @@ -277,7 +277,7 @@ static int __init omap_init_irq_legacy(u32 base) irq_base = 0; } - domain = irq_domain_add_legacy(NULL, omap_nr_irqs, irq_base, 0, + domain = irq_domain_add_legacy(node, omap_nr_irqs, irq_base, 0, &irq_domain_simple_ops, NULL); omap_irq_soft_reset(); @@ -301,10 +301,26 @@ static int __init omap_init_irq(u32 base, struct device_node *node) { int ret; - if (node) + /* + * FIXME legacy OMAP DMA driver sitting under arch/arm/plat-omap/dma.c + * depends is still not ready for linear IRQ domains; because of that + * we need to temporarily "blacklist" OMAP2 and OMAP3 devices from using + * linear IRQ Domain until that driver is finally fixed. + */ + if (of_device_is_compatible(node, "ti,omap2-intc") || + of_device_is_compatible(node, "ti,omap3-intc")) { + struct resource res; + + if (of_address_to_resource(node, 0, &res)) + return -ENOMEM; + + base = res.start; + ret = omap_init_irq_legacy(base, node); + } else if (node) { ret = omap_init_irq_of(node); - else - ret = omap_init_irq_legacy(base); + } else { + ret = omap_init_irq_legacy(base, NULL); + } if (ret == 0) omap_irq_enable_protection(); diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index 0b380603a578..d7c286656a25 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -1474,7 +1474,7 @@ static byte connect_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, add_ai(plci, &parms[5]); sig_req(plci, REJECT, 0); } - else if (Reject == 1 || Reject > 9) + else if (Reject == 1 || Reject >= 9) { add_ai(plci, &parms[5]); sig_req(plci, HANGUP, 0); diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c index ccd7d851be26..a77eea594b69 100644 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c @@ -754,10 +754,10 @@ dbusy_timer_handler(struct isac_hw *isac) } static int -open_dchannel(struct isac_hw *isac, struct channel_req *rq) +open_dchannel_caller(struct isac_hw *isac, struct channel_req *rq, void *caller) { pr_debug("%s: %s dev(%d) open from %p\n", isac->name, __func__, - isac->dch.dev.id, __builtin_return_address(1)); + isac->dch.dev.id, caller); if (rq->protocol != ISDN_P_TE_S0) return -EINVAL; if (rq->adr.channel == 1) @@ -771,6 +771,12 @@ open_dchannel(struct isac_hw *isac, struct channel_req *rq) return 0; } +static int +open_dchannel(struct isac_hw *isac, struct channel_req *rq) +{ + return open_dchannel_caller(isac, rq, __builtin_return_address(0)); +} + static const char *ISACVer[] = {"2086/2186 V1.1", "2085 B1", "2085 B2", "2085 V2.3"}; @@ -1548,7 +1554,7 @@ ipac_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) case OPEN_CHANNEL: rq = arg; if (rq->protocol == ISDN_P_TE_S0) - err = open_dchannel(isac, rq); + err = open_dchannel_caller(isac, rq, __builtin_return_address(0)); else err = open_bchannel(ipac, rq); if (err) diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index de69f6828c76..741675525b53 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -1176,10 +1176,10 @@ w6692_l1callback(struct dchannel *dch, u32 cmd) } static int -open_dchannel(struct w6692_hw *card, struct channel_req *rq) +open_dchannel(struct w6692_hw *card, struct channel_req *rq, void *caller) { pr_debug("%s: %s dev(%d) open from %p\n", card->name, __func__, - card->dch.dev.id, __builtin_return_address(1)); + card->dch.dev.id, caller); if (rq->protocol != ISDN_P_TE_S0) return -EINVAL; if (rq->adr.channel == 1) @@ -1207,7 +1207,7 @@ w6692_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) case OPEN_CHANNEL: rq = arg; if (rq->protocol == ISDN_P_TE_S0) - err = open_dchannel(card, rq); + err = open_dchannel(card, rq, __builtin_return_address(0)); else err = open_bchannel(card, rq); if (err) diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c index fc9f9d03fa13..0e5d673871c0 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ b/drivers/isdn/hisax/hfc4s8s_l1.c @@ -224,20 +224,6 @@ fWrite_hfc8(hfc4s8s_hw *a, u_char c) outb(c, a->iobase); } -static inline void -Write_hfc16(hfc4s8s_hw *a, u_char b, u_short c) -{ - SetRegAddr(a, b); - outw(c, a->iobase); -} - -static inline void -Write_hfc32(hfc4s8s_hw *a, u_char b, u_long c) -{ - SetRegAddr(a, b); - outl(c, a->iobase); -} - static inline void fWrite_hfc32(hfc4s8s_hw *a, u_long c) { @@ -265,13 +251,6 @@ Read_hfc16(hfc4s8s_hw *a, u_char b) return (inw((volatile u_int) a->iobase)); } -static inline u_long -Read_hfc32(hfc4s8s_hw *a, u_char b) -{ - SetRegAddr(a, b); - return (inl((volatile u_int) a->iobase)); -} - static inline u_long fRead_hfc32(hfc4s8s_hw *a) { diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index 5a4da94aefb0..ef9c8e4f1fa2 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -59,7 +59,8 @@ isdnloop_bchan_send(isdnloop_card *card, int ch) isdn_ctrl cmd; while (card->sndcount[ch]) { - if ((skb = skb_dequeue(&card->bqueue[ch]))) { + skb = skb_dequeue(&card->bqueue[ch]); + if (skb) { len = skb->len; card->sndcount[ch] -= len; ack = *(skb->head); /* used as scratch area */ @@ -149,8 +150,7 @@ typedef struct isdnloop_stat { int action; } isdnloop_stat; /* *INDENT-OFF* */ -static isdnloop_stat isdnloop_stat_table[] = -{ +static isdnloop_stat isdnloop_stat_table[] = { {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */ {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */ {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */ @@ -317,7 +317,8 @@ isdnloop_polldchan(unsigned long data) u_char *p; isdn_ctrl cmd; - if ((skb = skb_dequeue(&card->dqueue))) + skb = skb_dequeue(&card->dqueue); + if (skb) avail = skb->len; else avail = 0; @@ -471,8 +472,8 @@ isdnloop_fake(isdnloop_card *card, char *s, int ch) { struct sk_buff *skb; int len = strlen(s) + ((ch >= 0) ? 3 : 0); - - if (!(skb = dev_alloc_skb(len))) { + skb = dev_alloc_skb(len); + if (!skb) { printk(KERN_WARNING "isdnloop: Out of memory in isdnloop_fake\n"); return 1; } @@ -483,8 +484,7 @@ isdnloop_fake(isdnloop_card *card, char *s, int ch) return 0; } /* *INDENT-OFF* */ -static isdnloop_stat isdnloop_cmd_table[] = -{ +static isdnloop_stat isdnloop_cmd_table[] = { {"BCON_R", 0, 1}, /* B-Channel connect */ {"BCON_I", 0, 17}, /* B-Channel connect ind */ {"BDIS_R", 0, 2}, /* B-Channel disconnect */ @@ -525,10 +525,8 @@ isdnloop_fake_err(isdnloop_card *card) isdnloop_fake(card, "NAK", -1); } -static u_char ctable_eu[] = -{0x00, 0x11, 0x01, 0x12}; -static u_char ctable_1t[] = -{0x00, 0x3b, 0x01, 0x3a}; +static u_char ctable_eu[] = {0x00, 0x11, 0x01, 0x12}; +static u_char ctable_1t[] = {0x00, 0x3b, 0x01, 0x3a}; /* * Assemble a simplified cause message depending on the @@ -554,9 +552,9 @@ isdnloop_unicause(isdnloop_card *card, int loc, int cau) sprintf(buf, "%02X44", ctable_1t[cau]); break; default: - return ("0000"); + return "0000"; } - return (buf); + return buf; } /* @@ -647,10 +645,8 @@ isdnloop_kill_ctimer(isdnloop_card *card, int ch) spin_unlock_irqrestore(&card->isdnloop_lock, flags); } -static u_char si2bit[] = -{0, 1, 0, 0, 0, 2, 0, 4, 0, 0}; -static u_char bit2si[] = -{1, 5, 7}; +static u_char si2bit[] = {0, 1, 0, 0, 0, 2, 0, 4, 0, 0}; +static u_char bit2si[] = {1, 5, 7}; /* * Try finding a listener for an outgoing call. @@ -754,17 +750,17 @@ isdnloop_vstphone(isdnloop_card *card, char *phone, int caller) if (caller) { for (i = 0; i < 2; i++) if (!(strcmp(card->s0num[i], phone))) - return (phone); - return (card->s0num[0]); + return phone; + return card->s0num[0]; } - return (phone); + return phone; break; case ISDN_PTYPE_1TR6: if (caller) { sprintf(nphone, "%s%c", card->s0num[0], phone[0]); - return (nphone); + return nphone; } else - return (&phone[strlen(phone) - 1]); + return &phone[strlen(phone) - 1]; break; } return ""; @@ -1148,14 +1144,14 @@ isdnloop_command(isdn_ctrl *c, isdnloop_card *card) case ISDNLOOP_IOCTL_STARTUP: if (!access_ok(VERIFY_READ, (void *) a, sizeof(isdnloop_sdef))) return -EFAULT; - return (isdnloop_start(card, (isdnloop_sdef *) a)); + return isdnloop_start(card, (isdnloop_sdef *) a); break; case ISDNLOOP_IOCTL_ADDCARD: if (copy_from_user((char *)&cdef, (char *)a, sizeof(cdef))) return -EFAULT; - return (isdnloop_addcard(cdef.id1)); + return isdnloop_addcard(cdef.id1); break; case ISDNLOOP_IOCTL_LEASEDCFG: if (a) { @@ -1377,7 +1373,7 @@ if_command(isdn_ctrl *c) isdnloop_card *card = isdnloop_findcard(c->driver); if (card) - return (isdnloop_command(c, card)); + return isdnloop_command(c, card); printk(KERN_ERR "isdnloop: if_command called with invalid driverId!\n"); return -ENODEV; @@ -1391,7 +1387,7 @@ if_writecmd(const u_char __user *buf, int len, int id, int channel) if (card) { if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) return -ENODEV; - return (isdnloop_writecmd(buf, len, 1, card)); + return isdnloop_writecmd(buf, len, 1, card); } printk(KERN_ERR "isdnloop: if_writecmd called with invalid driverId!\n"); @@ -1406,7 +1402,7 @@ if_readstatus(u_char __user *buf, int len, int id, int channel) if (card) { if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) return -ENODEV; - return (isdnloop_readstatus(buf, len, card)); + return isdnloop_readstatus(buf, len, card); } printk(KERN_ERR "isdnloop: if_readstatus called with invalid driverId!\n"); @@ -1423,7 +1419,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb) return -ENODEV; /* ack request stored in skb scratch area */ *(skb->head) = ack; - return (isdnloop_sendbuf(channel, skb, card)); + return isdnloop_sendbuf(channel, skb, card); } printk(KERN_ERR "isdnloop: if_sendbuf called with invalid driverId!\n"); @@ -1439,8 +1435,8 @@ isdnloop_initcard(char *id) { isdnloop_card *card; int i; - - if (!(card = kzalloc(sizeof(isdnloop_card), GFP_KERNEL))) { + card = kzalloc(sizeof(isdnloop_card), GFP_KERNEL); + if (!card) { printk(KERN_WARNING "isdnloop: (%s) Could not allocate card-struct.\n", id); return (isdnloop_card *) 0; @@ -1489,8 +1485,8 @@ static int isdnloop_addcard(char *id1) { isdnloop_card *card; - - if (!(card = isdnloop_initcard(id1))) { + card = isdnloop_initcard(id1); + if (!card) { return -EIO; } printk(KERN_INFO @@ -1503,7 +1499,7 @@ static int __init isdnloop_init(void) { if (isdnloop_id) - return (isdnloop_addcard(isdnloop_id)); + return isdnloop_addcard(isdnloop_id); return 0; } diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c index d6f19b168e8a..3597ef47b28a 100644 --- a/drivers/isdn/sc/init.c +++ b/drivers/isdn/sc/init.c @@ -30,7 +30,7 @@ static const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCo static unsigned int io[] = {0, 0, 0, 0}; static unsigned char irq[] = {0, 0, 0, 0}; static unsigned long ram[] = {0, 0, 0, 0}; -static bool do_reset = 0; +static bool do_reset; module_param_array(io, int, NULL, 0); module_param_array(irq, byte, NULL, 0); @@ -104,13 +104,12 @@ static int __init sc_init(void) io[b] + 0x400 * EXP_PAGE0); continue; } - } - else { + } else { /* * Yes, probe for I/O Base */ if (probe_exhasted) { - pr_debug("All probe addresses exhasted, skipping\n"); + pr_debug("All probe addresses exhausted, skipping\n"); continue; } pr_debug("Probing for I/O...\n"); @@ -169,8 +168,7 @@ static int __init sc_init(void) model = identify_board(ram[b], io[b]); release_region(ram[b], SRAM_PAGESIZE); } - } - else { + } else { /* * Yes, probe for free RAM and look for * a signature and id the board model @@ -187,7 +185,7 @@ static int __init sc_init(void) ram[b] = i; break; } - pr_debug(" Unidentifed or inaccessible\n"); + pr_debug(" Unidentified or inaccessible\n"); continue; } pr_debug(" request failed\n"); @@ -337,8 +335,7 @@ static int __init sc_init(void) sc_adapter[cinst]->interrupt = irq[b]; if (request_irq(sc_adapter[cinst]->interrupt, interrupt_handler, 0, interface->id, - (void *)(unsigned long) cinst)) - { + (void *)(unsigned long) cinst)) { kfree(sc_adapter[cinst]->channel); indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL); /* Fix me */ kfree(interface); diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index c04fed9eb15d..84325f267acf 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -45,4 +45,10 @@ config PCC states). Select this driver if your platform implements the PCC clients mentioned above. +config ALTERA_MBOX + tristate "Altera Mailbox" + help + An implementation of the Altera Mailbox soft core. It is used + to send message between processors. Say Y here if you want to use the + Altera mailbox support. endif diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index dd412c22208b..2e79231154cf 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -7,3 +7,5 @@ obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o obj-$(CONFIG_PCC) += pcc.o + +obj-$(CONFIG_ALTERA_MBOX) += mailbox-altera.o diff --git a/drivers/mailbox/mailbox-altera.c b/drivers/mailbox/mailbox-altera.c new file mode 100644 index 000000000000..a266265677d3 --- /dev/null +++ b/drivers/mailbox/mailbox-altera.c @@ -0,0 +1,388 @@ +/* + * Copyright Altera Corporation (C) 2013-2014. All rights reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "altera-mailbox" + +#define MAILBOX_CMD_REG 0x00 +#define MAILBOX_PTR_REG 0x04 +#define MAILBOX_STS_REG 0x08 +#define MAILBOX_INTMASK_REG 0x0C + +#define INT_PENDING_MSK 0x1 +#define INT_SPACE_MSK 0x2 + +#define STS_PENDING_MSK 0x1 +#define STS_FULL_MSK 0x2 +#define STS_FULL_OFT 0x1 + +#define MBOX_PENDING(status) (((status) & STS_PENDING_MSK)) +#define MBOX_FULL(status) (((status) & STS_FULL_MSK) >> STS_FULL_OFT) + +enum altera_mbox_msg { + MBOX_CMD = 0, + MBOX_PTR, +}; + +#define MBOX_POLLING_MS 5 /* polling interval 5ms */ + +struct altera_mbox { + bool is_sender; /* 1-sender, 0-receiver */ + bool intr_mode; + int irq; + void __iomem *mbox_base; + struct device *dev; + struct mbox_controller controller; + + /* If the controller supports only RX polling mode */ + struct timer_list rxpoll_timer; +}; + +static struct altera_mbox *mbox_chan_to_altera_mbox(struct mbox_chan *chan) +{ + if (!chan || !chan->con_priv) + return NULL; + + return (struct altera_mbox *)chan->con_priv; +} + +static inline int altera_mbox_full(struct altera_mbox *mbox) +{ + u32 status; + + status = readl_relaxed(mbox->mbox_base + MAILBOX_STS_REG); + return MBOX_FULL(status); +} + +static inline int altera_mbox_pending(struct altera_mbox *mbox) +{ + u32 status; + + status = readl_relaxed(mbox->mbox_base + MAILBOX_STS_REG); + return MBOX_PENDING(status); +} + +static void altera_mbox_rx_intmask(struct altera_mbox *mbox, bool enable) +{ + u32 mask; + + mask = readl_relaxed(mbox->mbox_base + MAILBOX_INTMASK_REG); + if (enable) + mask |= INT_PENDING_MSK; + else + mask &= ~INT_PENDING_MSK; + writel_relaxed(mask, mbox->mbox_base + MAILBOX_INTMASK_REG); +} + +static void altera_mbox_tx_intmask(struct altera_mbox *mbox, bool enable) +{ + u32 mask; + + mask = readl_relaxed(mbox->mbox_base + MAILBOX_INTMASK_REG); + if (enable) + mask |= INT_SPACE_MSK; + else + mask &= ~INT_SPACE_MSK; + writel_relaxed(mask, mbox->mbox_base + MAILBOX_INTMASK_REG); +} + +static bool altera_mbox_is_sender(struct altera_mbox *mbox) +{ + u32 reg; + /* Write a magic number to PTR register and read back this register. + * This register is read-write if it is a sender. + */ + #define MBOX_MAGIC 0xA5A5AA55 + writel_relaxed(MBOX_MAGIC, mbox->mbox_base + MAILBOX_PTR_REG); + reg = readl_relaxed(mbox->mbox_base + MAILBOX_PTR_REG); + if (reg == MBOX_MAGIC) { + /* Clear to 0 */ + writel_relaxed(0, mbox->mbox_base + MAILBOX_PTR_REG); + return true; + } + return false; +} + +static void altera_mbox_rx_data(struct mbox_chan *chan) +{ + struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); + u32 data[2]; + + if (altera_mbox_pending(mbox)) { + data[MBOX_PTR] = + readl_relaxed(mbox->mbox_base + MAILBOX_PTR_REG); + data[MBOX_CMD] = + readl_relaxed(mbox->mbox_base + MAILBOX_CMD_REG); + mbox_chan_received_data(chan, (void *)data); + } +} + +static void altera_mbox_poll_rx(unsigned long data) +{ + struct mbox_chan *chan = (struct mbox_chan *)data; + struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); + + altera_mbox_rx_data(chan); + + mod_timer(&mbox->rxpoll_timer, + jiffies + msecs_to_jiffies(MBOX_POLLING_MS)); +} + +static irqreturn_t altera_mbox_tx_interrupt(int irq, void *p) +{ + struct mbox_chan *chan = (struct mbox_chan *)p; + struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); + + altera_mbox_tx_intmask(mbox, false); + mbox_chan_txdone(chan, 0); + + return IRQ_HANDLED; +} + +static irqreturn_t altera_mbox_rx_interrupt(int irq, void *p) +{ + struct mbox_chan *chan = (struct mbox_chan *)p; + + altera_mbox_rx_data(chan); + return IRQ_HANDLED; +} + +static int altera_mbox_startup_sender(struct mbox_chan *chan) +{ + int ret; + struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); + + if (mbox->intr_mode) { + ret = request_irq(mbox->irq, altera_mbox_tx_interrupt, 0, + DRIVER_NAME, chan); + if (unlikely(ret)) { + dev_err(mbox->dev, + "failed to register mailbox interrupt:%d\n", + ret); + return ret; + } + } + + return 0; +} + +static int altera_mbox_startup_receiver(struct mbox_chan *chan) +{ + int ret; + struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); + + if (mbox->intr_mode) { + ret = request_irq(mbox->irq, altera_mbox_rx_interrupt, 0, + DRIVER_NAME, chan); + if (unlikely(ret)) { + mbox->intr_mode = false; + goto polling; /* use polling if failed */ + } + + altera_mbox_rx_intmask(mbox, true); + return 0; + } + +polling: + /* Setup polling timer */ + setup_timer(&mbox->rxpoll_timer, altera_mbox_poll_rx, + (unsigned long)chan); + mod_timer(&mbox->rxpoll_timer, + jiffies + msecs_to_jiffies(MBOX_POLLING_MS)); + + return 0; +} + +static int altera_mbox_send_data(struct mbox_chan *chan, void *data) +{ + struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); + u32 *udata = (u32 *)data; + + if (!mbox || !data) + return -EINVAL; + if (!mbox->is_sender) { + dev_warn(mbox->dev, + "failed to send. This is receiver mailbox.\n"); + return -EINVAL; + } + + if (altera_mbox_full(mbox)) + return -EBUSY; + + /* Enable interrupt before send */ + if (mbox->intr_mode) + altera_mbox_tx_intmask(mbox, true); + + /* Pointer register must write before command register */ + writel_relaxed(udata[MBOX_PTR], mbox->mbox_base + MAILBOX_PTR_REG); + writel_relaxed(udata[MBOX_CMD], mbox->mbox_base + MAILBOX_CMD_REG); + + return 0; +} + +static bool altera_mbox_last_tx_done(struct mbox_chan *chan) +{ + struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); + + /* Return false if mailbox is full */ + return altera_mbox_full(mbox) ? false : true; +} + +static bool altera_mbox_peek_data(struct mbox_chan *chan) +{ + struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); + + return altera_mbox_pending(mbox) ? true : false; +} + +static int altera_mbox_startup(struct mbox_chan *chan) +{ + struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); + int ret = 0; + + if (!mbox) + return -EINVAL; + + if (mbox->is_sender) + ret = altera_mbox_startup_sender(chan); + else + ret = altera_mbox_startup_receiver(chan); + + return ret; +} + +static void altera_mbox_shutdown(struct mbox_chan *chan) +{ + struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan); + + if (mbox->intr_mode) { + /* Unmask all interrupt masks */ + writel_relaxed(~0, mbox->mbox_base + MAILBOX_INTMASK_REG); + free_irq(mbox->irq, chan); + } else if (!mbox->is_sender) { + del_timer_sync(&mbox->rxpoll_timer); + } +} + +static struct mbox_chan_ops altera_mbox_ops = { + .send_data = altera_mbox_send_data, + .startup = altera_mbox_startup, + .shutdown = altera_mbox_shutdown, + .last_tx_done = altera_mbox_last_tx_done, + .peek_data = altera_mbox_peek_data, +}; + +static int altera_mbox_probe(struct platform_device *pdev) +{ + struct altera_mbox *mbox; + struct resource *regs; + struct mbox_chan *chans; + int ret; + + mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), + GFP_KERNEL); + if (!mbox) + return -ENOMEM; + + /* Allocated one channel */ + chans = devm_kzalloc(&pdev->dev, sizeof(*chans), GFP_KERNEL); + if (!chans) + return -ENOMEM; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + mbox->mbox_base = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(mbox->mbox_base)) + return PTR_ERR(mbox->mbox_base); + + /* Check is it a sender or receiver? */ + mbox->is_sender = altera_mbox_is_sender(mbox); + + mbox->irq = platform_get_irq(pdev, 0); + if (mbox->irq >= 0) + mbox->intr_mode = true; + + mbox->dev = &pdev->dev; + + /* Hardware supports only one channel. */ + chans[0].con_priv = mbox; + mbox->controller.dev = mbox->dev; + mbox->controller.num_chans = 1; + mbox->controller.chans = chans; + mbox->controller.ops = &altera_mbox_ops; + + if (mbox->is_sender) { + if (mbox->intr_mode) { + mbox->controller.txdone_irq = true; + } else { + mbox->controller.txdone_poll = true; + mbox->controller.txpoll_period = MBOX_POLLING_MS; + } + } + + ret = mbox_controller_register(&mbox->controller); + if (ret) { + dev_err(&pdev->dev, "Register mailbox failed\n"); + goto err; + } + + platform_set_drvdata(pdev, mbox); +err: + return ret; +} + +static int altera_mbox_remove(struct platform_device *pdev) +{ + struct altera_mbox *mbox = platform_get_drvdata(pdev); + + if (!mbox) + return -EINVAL; + + mbox_controller_unregister(&mbox->controller); + + return 0; +} + +static const struct of_device_id altera_mbox_match[] = { + { .compatible = "altr,mailbox-1.0" }, + { /* Sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, altera_mbox_match); + +static struct platform_driver altera_mbox_driver = { + .probe = altera_mbox_probe, + .remove = altera_mbox_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = altera_mbox_match, + }, +}; + +module_platform_driver(altera_mbox_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Altera mailbox specific functions"); +MODULE_AUTHOR("Ley Foon Tan "); +MODULE_ALIAS("platform:altera-mailbox"); diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 59aad4d5da53..19b491d2964f 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -87,7 +87,7 @@ static void msg_submit(struct mbox_chan *chan) exit: spin_unlock_irqrestore(&chan->lock, flags); - if (!err && chan->txdone_method == TXDONE_BY_POLL) + if (!err && (chan->txdone_method & TXDONE_BY_POLL)) poll_txdone((unsigned long)chan->mbox); } diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 6dbf6fcbdfaf..977c814cdf6f 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -386,16 +386,16 @@ static int __init pcc_init(void) ret = acpi_pcc_probe(); if (ret) { - pr_err("ACPI PCC probe failed.\n"); + pr_debug("ACPI PCC probe failed.\n"); return -ENODEV; } pcc_pdev = platform_create_bundle(&pcc_mbox_driver, pcc_mbox_probe, NULL, 0, NULL, 0); - if (!pcc_pdev) { - pr_err("Err creating PCC platform bundle\n"); - return -ENODEV; + if (IS_ERR(pcc_pdev)) { + pr_debug("Err creating PCC platform bundle\n"); + return PTR_ERR(pcc_pdev); } return 0; diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 5bdedf6df153..c355a226a024 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -5,6 +5,7 @@ menuconfig MD bool "Multiple devices driver support (RAID and LVM)" depends on BLOCK + select SRCU help Support multiple physical spindles through a single logical device. Required for RAID and logical volume management. diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index da3604e73e8a..3a5767968ba0 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -72,6 +72,19 @@ __acquires(bitmap->lock) /* this page has not been allocated yet */ spin_unlock_irq(&bitmap->lock); + /* It is possible that this is being called inside a + * prepare_to_wait/finish_wait loop from raid5c:make_request(). + * In general it is not permitted to sleep in that context as it + * can cause the loop to spin freely. + * That doesn't apply here as we can only reach this point + * once with any loop. + * When this function completes, either bp[page].map or + * bp[page].hijacked. In either case, this function will + * abort before getting to this point again. So there is + * no risk of a free-spin, and so it is safe to assert + * that sleeping here is allowed. + */ + sched_annotate_sleep(); mappage = kzalloc(PAGE_SIZE, GFP_NOIO); spin_lock_irq(&bitmap->lock); @@ -1606,7 +1619,9 @@ void bitmap_destroy(struct mddev *mddev) return; mutex_lock(&mddev->bitmap_info.mutex); + spin_lock(&mddev->lock); mddev->bitmap = NULL; /* disconnect from the md device */ + spin_unlock(&mddev->lock); mutex_unlock(&mddev->bitmap_info.mutex); if (mddev->thread) mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT; @@ -2196,11 +2211,13 @@ __ATTR(metadata, S_IRUGO|S_IWUSR, metadata_show, metadata_store); static ssize_t can_clear_show(struct mddev *mddev, char *page) { int len; + spin_lock(&mddev->lock); if (mddev->bitmap) len = sprintf(page, "%s\n", (mddev->bitmap->need_sync ? "false" : "true")); else len = sprintf(page, "\n"); + spin_unlock(&mddev->lock); return len; } @@ -2225,10 +2242,15 @@ __ATTR(can_clear, S_IRUGO|S_IWUSR, can_clear_show, can_clear_store); static ssize_t behind_writes_used_show(struct mddev *mddev, char *page) { + ssize_t ret; + spin_lock(&mddev->lock); if (mddev->bitmap == NULL) - return sprintf(page, "0\n"); - return sprintf(page, "%lu\n", - mddev->bitmap->behind_writes_used); + ret = sprintf(page, "0\n"); + else + ret = sprintf(page, "%lu\n", + mddev->bitmap->behind_writes_used); + spin_unlock(&mddev->lock); + return ret; } static ssize_t diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c index 9fc616c2755e..c1c010498a21 100644 --- a/drivers/md/dm-cache-metadata.c +++ b/drivers/md/dm-cache-metadata.c @@ -94,6 +94,9 @@ struct cache_disk_superblock { } __packed; struct dm_cache_metadata { + atomic_t ref_count; + struct list_head list; + struct block_device *bdev; struct dm_block_manager *bm; struct dm_space_map *metadata_sm; @@ -669,10 +672,10 @@ static void unpack_value(__le64 value_le, dm_oblock_t *block, unsigned *flags) /*----------------------------------------------------------------*/ -struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, - sector_t data_block_size, - bool may_format_device, - size_t policy_hint_size) +static struct dm_cache_metadata *metadata_open(struct block_device *bdev, + sector_t data_block_size, + bool may_format_device, + size_t policy_hint_size) { int r; struct dm_cache_metadata *cmd; @@ -680,9 +683,10 @@ struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { DMERR("could not allocate metadata struct"); - return NULL; + return ERR_PTR(-ENOMEM); } + atomic_set(&cmd->ref_count, 1); init_rwsem(&cmd->root_lock); cmd->bdev = bdev; cmd->data_block_size = data_block_size; @@ -705,10 +709,96 @@ struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, return cmd; } +/* + * We keep a little list of ref counted metadata objects to prevent two + * different target instances creating separate bufio instances. This is + * an issue if a table is reloaded before the suspend. + */ +static DEFINE_MUTEX(table_lock); +static LIST_HEAD(table); + +static struct dm_cache_metadata *lookup(struct block_device *bdev) +{ + struct dm_cache_metadata *cmd; + + list_for_each_entry(cmd, &table, list) + if (cmd->bdev == bdev) { + atomic_inc(&cmd->ref_count); + return cmd; + } + + return NULL; +} + +static struct dm_cache_metadata *lookup_or_open(struct block_device *bdev, + sector_t data_block_size, + bool may_format_device, + size_t policy_hint_size) +{ + struct dm_cache_metadata *cmd, *cmd2; + + mutex_lock(&table_lock); + cmd = lookup(bdev); + mutex_unlock(&table_lock); + + if (cmd) + return cmd; + + cmd = metadata_open(bdev, data_block_size, may_format_device, policy_hint_size); + if (!IS_ERR(cmd)) { + mutex_lock(&table_lock); + cmd2 = lookup(bdev); + if (cmd2) { + mutex_unlock(&table_lock); + __destroy_persistent_data_objects(cmd); + kfree(cmd); + return cmd2; + } + list_add(&cmd->list, &table); + mutex_unlock(&table_lock); + } + + return cmd; +} + +static bool same_params(struct dm_cache_metadata *cmd, sector_t data_block_size) +{ + if (cmd->data_block_size != data_block_size) { + DMERR("data_block_size (%llu) different from that in metadata (%llu)\n", + (unsigned long long) data_block_size, + (unsigned long long) cmd->data_block_size); + return false; + } + + return true; +} + +struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, + sector_t data_block_size, + bool may_format_device, + size_t policy_hint_size) +{ + struct dm_cache_metadata *cmd = lookup_or_open(bdev, data_block_size, + may_format_device, policy_hint_size); + + if (!IS_ERR(cmd) && !same_params(cmd, data_block_size)) { + dm_cache_metadata_close(cmd); + return ERR_PTR(-EINVAL); + } + + return cmd; +} + void dm_cache_metadata_close(struct dm_cache_metadata *cmd) { - __destroy_persistent_data_objects(cmd); - kfree(cmd); + if (atomic_dec_and_test(&cmd->ref_count)) { + mutex_lock(&table_lock); + list_del(&cmd->list); + mutex_unlock(&table_lock); + + __destroy_persistent_data_objects(cmd); + kfree(cmd); + } } /* diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 1e96d7889f51..e1650539cc2f 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -221,7 +221,13 @@ struct cache { struct list_head need_commit_migrations; sector_t migration_threshold; wait_queue_head_t migration_wait; - atomic_t nr_migrations; + atomic_t nr_allocated_migrations; + + /* + * The number of in flight migrations that are performing + * background io. eg, promotion, writeback. + */ + atomic_t nr_io_migrations; wait_queue_head_t quiescing_wait; atomic_t quiescing; @@ -258,7 +264,6 @@ struct cache { struct dm_deferred_set *all_io_ds; mempool_t *migration_pool; - struct dm_cache_migration *next_migration; struct dm_cache_policy *policy; unsigned policy_nr_args; @@ -350,10 +355,31 @@ static void free_prison_cell(struct cache *cache, struct dm_bio_prison_cell *cel dm_bio_prison_free_cell(cache->prison, cell); } +static struct dm_cache_migration *alloc_migration(struct cache *cache) +{ + struct dm_cache_migration *mg; + + mg = mempool_alloc(cache->migration_pool, GFP_NOWAIT); + if (mg) { + mg->cache = cache; + atomic_inc(&mg->cache->nr_allocated_migrations); + } + + return mg; +} + +static void free_migration(struct dm_cache_migration *mg) +{ + if (atomic_dec_and_test(&mg->cache->nr_allocated_migrations)) + wake_up(&mg->cache->migration_wait); + + mempool_free(mg, mg->cache->migration_pool); +} + static int prealloc_data_structs(struct cache *cache, struct prealloc *p) { if (!p->mg) { - p->mg = mempool_alloc(cache->migration_pool, GFP_NOWAIT); + p->mg = alloc_migration(cache); if (!p->mg) return -ENOMEM; } @@ -382,7 +408,7 @@ static void prealloc_free_structs(struct cache *cache, struct prealloc *p) free_prison_cell(cache, p->cell1); if (p->mg) - mempool_free(p->mg, cache->migration_pool); + free_migration(p->mg); } static struct dm_cache_migration *prealloc_get_migration(struct prealloc *p) @@ -854,24 +880,14 @@ static void remap_to_origin_then_cache(struct cache *cache, struct bio *bio, * Migration covers moving data from the origin device to the cache, or * vice versa. *--------------------------------------------------------------*/ -static void free_migration(struct dm_cache_migration *mg) +static void inc_io_migrations(struct cache *cache) { - mempool_free(mg, mg->cache->migration_pool); + atomic_inc(&cache->nr_io_migrations); } -static void inc_nr_migrations(struct cache *cache) +static void dec_io_migrations(struct cache *cache) { - atomic_inc(&cache->nr_migrations); -} - -static void dec_nr_migrations(struct cache *cache) -{ - atomic_dec(&cache->nr_migrations); - - /* - * Wake the worker in case we're suspending the target. - */ - wake_up(&cache->migration_wait); + atomic_dec(&cache->nr_io_migrations); } static void __cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell, @@ -894,11 +910,10 @@ static void cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell, wake_worker(cache); } -static void cleanup_migration(struct dm_cache_migration *mg) +static void free_io_migration(struct dm_cache_migration *mg) { - struct cache *cache = mg->cache; + dec_io_migrations(mg->cache); free_migration(mg); - dec_nr_migrations(cache); } static void migration_failure(struct dm_cache_migration *mg) @@ -923,7 +938,7 @@ static void migration_failure(struct dm_cache_migration *mg) cell_defer(cache, mg->new_ocell, true); } - cleanup_migration(mg); + free_io_migration(mg); } static void migration_success_pre_commit(struct dm_cache_migration *mg) @@ -934,7 +949,7 @@ static void migration_success_pre_commit(struct dm_cache_migration *mg) if (mg->writeback) { clear_dirty(cache, mg->old_oblock, mg->cblock); cell_defer(cache, mg->old_ocell, false); - cleanup_migration(mg); + free_io_migration(mg); return; } else if (mg->demote) { @@ -944,14 +959,14 @@ static void migration_success_pre_commit(struct dm_cache_migration *mg) mg->old_oblock); if (mg->promote) cell_defer(cache, mg->new_ocell, true); - cleanup_migration(mg); + free_io_migration(mg); return; } } else { if (dm_cache_insert_mapping(cache->cmd, mg->cblock, mg->new_oblock)) { DMWARN_LIMIT("promotion failed; couldn't update on disk metadata"); policy_remove_mapping(cache->policy, mg->new_oblock); - cleanup_migration(mg); + free_io_migration(mg); return; } } @@ -984,7 +999,7 @@ static void migration_success_post_commit(struct dm_cache_migration *mg) } else { if (mg->invalidate) policy_remove_mapping(cache->policy, mg->old_oblock); - cleanup_migration(mg); + free_io_migration(mg); } } else { @@ -999,7 +1014,7 @@ static void migration_success_post_commit(struct dm_cache_migration *mg) bio_endio(mg->new_ocell->holder, 0); cell_defer(cache, mg->new_ocell, false); } - cleanup_migration(mg); + free_io_migration(mg); } } @@ -1251,7 +1266,7 @@ static void promote(struct cache *cache, struct prealloc *structs, mg->new_ocell = cell; mg->start_jiffies = jiffies; - inc_nr_migrations(cache); + inc_io_migrations(cache); quiesce_migration(mg); } @@ -1275,7 +1290,7 @@ static void writeback(struct cache *cache, struct prealloc *structs, mg->new_ocell = NULL; mg->start_jiffies = jiffies; - inc_nr_migrations(cache); + inc_io_migrations(cache); quiesce_migration(mg); } @@ -1302,7 +1317,7 @@ static void demote_then_promote(struct cache *cache, struct prealloc *structs, mg->new_ocell = new_ocell; mg->start_jiffies = jiffies; - inc_nr_migrations(cache); + inc_io_migrations(cache); quiesce_migration(mg); } @@ -1330,7 +1345,7 @@ static void invalidate(struct cache *cache, struct prealloc *structs, mg->new_ocell = NULL; mg->start_jiffies = jiffies; - inc_nr_migrations(cache); + inc_io_migrations(cache); quiesce_migration(mg); } @@ -1412,7 +1427,7 @@ static void process_discard_bio(struct cache *cache, struct prealloc *structs, static bool spare_migration_bandwidth(struct cache *cache) { - sector_t current_volume = (atomic_read(&cache->nr_migrations) + 1) * + sector_t current_volume = (atomic_read(&cache->nr_io_migrations) + 1) * cache->sectors_per_block; return current_volume < cache->migration_threshold; } @@ -1764,7 +1779,7 @@ static void stop_quiescing(struct cache *cache) static void wait_for_migrations(struct cache *cache) { - wait_event(cache->migration_wait, !atomic_read(&cache->nr_migrations)); + wait_event(cache->migration_wait, !atomic_read(&cache->nr_allocated_migrations)); } static void stop_worker(struct cache *cache) @@ -1876,9 +1891,6 @@ static void destroy(struct cache *cache) { unsigned i; - if (cache->next_migration) - mempool_free(cache->next_migration, cache->migration_pool); - if (cache->migration_pool) mempool_destroy(cache->migration_pool); @@ -2424,7 +2436,8 @@ static int cache_create(struct cache_args *ca, struct cache **result) INIT_LIST_HEAD(&cache->quiesced_migrations); INIT_LIST_HEAD(&cache->completed_migrations); INIT_LIST_HEAD(&cache->need_commit_migrations); - atomic_set(&cache->nr_migrations, 0); + atomic_set(&cache->nr_allocated_migrations, 0); + atomic_set(&cache->nr_io_migrations, 0); init_waitqueue_head(&cache->migration_wait); init_waitqueue_head(&cache->quiescing_wait); @@ -2487,8 +2500,6 @@ static int cache_create(struct cache_args *ca, struct cache **result) goto bad; } - cache->next_migration = NULL; - cache->need_tick_bio = true; cache->sized = false; cache->invalidate = false; diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 07c0fa0fa284..777d9ba2acad 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -746,13 +746,7 @@ static int raid_is_congested(struct dm_target_callbacks *cb, int bits) { struct raid_set *rs = container_of(cb, struct raid_set, callbacks); - if (rs->raid_type->level == 1) - return md_raid1_congested(&rs->md, bits); - - if (rs->raid_type->level == 10) - return md_raid10_congested(&rs->md, bits); - - return md_raid5_congested(&rs->md, bits); + return mddev_congested(&rs->md, bits); } /* diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 493478989dbd..07705ee181e3 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -3385,6 +3385,12 @@ static int pool_message(struct dm_target *ti, unsigned argc, char **argv) struct pool_c *pt = ti->private; struct pool *pool = pt->pool; + if (get_pool_mode(pool) >= PM_READ_ONLY) { + DMERR("%s: unable to service pool target messages in READ_ONLY or FAIL mode", + dm_device_name(pool->pool_md)); + return -EINVAL; + } + if (!strcasecmp(argv[0], "create_thin")) r = process_create_thin_mesg(argc, argv, pool); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index b98cd9d84435..2caf5b374649 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -206,6 +206,9 @@ struct mapped_device { /* zero-length flush that will be cloned and submitted to targets */ struct bio flush_bio; + /* the number of internal suspends */ + unsigned internal_suspend_count; + struct dm_stats stats; }; @@ -2928,7 +2931,7 @@ static void __dm_internal_suspend(struct mapped_device *md, unsigned suspend_fla { struct dm_table *map = NULL; - if (dm_suspended_internally_md(md)) + if (md->internal_suspend_count++) return; /* nested internal suspend */ if (dm_suspended_md(md)) { @@ -2953,7 +2956,9 @@ static void __dm_internal_suspend(struct mapped_device *md, unsigned suspend_fla static void __dm_internal_resume(struct mapped_device *md) { - if (!dm_suspended_internally_md(md)) + BUG_ON(!md->internal_suspend_count); + + if (--md->internal_suspend_count) return; /* resume from nested internal suspend */ if (dm_suspended_md(md)) diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index e8b4574956c7..1277eb26b58a 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -332,13 +332,11 @@ static int run(struct mddev *mddev) return 0; } -static int stop(struct mddev *mddev) +static void faulty_free(struct mddev *mddev, void *priv) { - struct faulty_conf *conf = mddev->private; + struct faulty_conf *conf = priv; kfree(conf); - mddev->private = NULL; - return 0; } static struct md_personality faulty_personality = @@ -348,7 +346,7 @@ static struct md_personality faulty_personality = .owner = THIS_MODULE, .make_request = make_request, .run = run, - .stop = stop, + .free = faulty_free, .status = status, .check_reshape = reshape, .size = faulty_size, diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 64713b77df1c..fa7d577f3d12 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -34,7 +34,7 @@ static inline struct dev_info *which_dev(struct mddev *mddev, sector_t sector) lo = 0; hi = mddev->raid_disks - 1; - conf = rcu_dereference(mddev->private); + conf = mddev->private; /* * Binary Search @@ -60,18 +60,16 @@ static inline struct dev_info *which_dev(struct mddev *mddev, sector_t sector) * * Return amount of bytes we can take at this offset */ -static int linear_mergeable_bvec(struct request_queue *q, +static int linear_mergeable_bvec(struct mddev *mddev, struct bvec_merge_data *bvm, struct bio_vec *biovec) { - struct mddev *mddev = q->queuedata; struct dev_info *dev0; unsigned long maxsectors, bio_sectors = bvm->bi_size >> 9; sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); int maxbytes = biovec->bv_len; struct request_queue *subq; - rcu_read_lock(); dev0 = which_dev(mddev, sector); maxsectors = dev0->end_sector - sector; subq = bdev_get_queue(dev0->rdev->bdev); @@ -81,7 +79,6 @@ static int linear_mergeable_bvec(struct request_queue *q, maxbytes = min(maxbytes, subq->merge_bvec_fn(subq, bvm, biovec)); } - rcu_read_unlock(); if (maxsectors < bio_sectors) maxsectors = 0; @@ -97,24 +94,18 @@ static int linear_mergeable_bvec(struct request_queue *q, return maxsectors << 9; } -static int linear_congested(void *data, int bits) +static int linear_congested(struct mddev *mddev, int bits) { - struct mddev *mddev = data; struct linear_conf *conf; int i, ret = 0; - if (mddev_congested(mddev, bits)) - return 1; - - rcu_read_lock(); - conf = rcu_dereference(mddev->private); + conf = mddev->private; for (i = 0; i < mddev->raid_disks && !ret ; i++) { struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev); ret |= bdi_congested(&q->backing_dev_info, bits); } - rcu_read_unlock(); return ret; } @@ -123,12 +114,10 @@ static sector_t linear_size(struct mddev *mddev, sector_t sectors, int raid_disk struct linear_conf *conf; sector_t array_sectors; - rcu_read_lock(); - conf = rcu_dereference(mddev->private); + conf = mddev->private; WARN_ONCE(sectors || raid_disks, "%s does not support generic reshape\n", __func__); array_sectors = conf->array_sectors; - rcu_read_unlock(); return array_sectors; } @@ -217,10 +206,6 @@ static int linear_run (struct mddev *mddev) mddev->private = conf; md_set_array_sectors(mddev, linear_size(mddev, 0, 0)); - blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); - mddev->queue->backing_dev_info.congested_fn = linear_congested; - mddev->queue->backing_dev_info.congested_data = mddev; - ret = md_integrity_register(mddev); if (ret) { kfree(conf); @@ -252,38 +237,23 @@ static int linear_add(struct mddev *mddev, struct md_rdev *rdev) if (!newconf) return -ENOMEM; - oldconf = rcu_dereference_protected(mddev->private, - lockdep_is_held( - &mddev->reconfig_mutex)); + mddev_suspend(mddev); + oldconf = mddev->private; mddev->raid_disks++; - rcu_assign_pointer(mddev->private, newconf); + mddev->private = newconf; md_set_array_sectors(mddev, linear_size(mddev, 0, 0)); set_capacity(mddev->gendisk, mddev->array_sectors); + mddev_resume(mddev); revalidate_disk(mddev->gendisk); - kfree_rcu(oldconf, rcu); + kfree(oldconf); return 0; } -static int linear_stop (struct mddev *mddev) +static void linear_free(struct mddev *mddev, void *priv) { - struct linear_conf *conf = - rcu_dereference_protected(mddev->private, - lockdep_is_held( - &mddev->reconfig_mutex)); + struct linear_conf *conf = priv; - /* - * We do not require rcu protection here since - * we hold reconfig_mutex for both linear_add and - * linear_stop, so they cannot race. - * We should make sure any old 'conf's are properly - * freed though. - */ - rcu_barrier(); - blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ kfree(conf); - mddev->private = NULL; - - return 0; } static void linear_make_request(struct mddev *mddev, struct bio *bio) @@ -299,16 +269,12 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio) } do { - rcu_read_lock(); - tmp_dev = which_dev(mddev, bio->bi_iter.bi_sector); start_sector = tmp_dev->end_sector - tmp_dev->rdev->sectors; end_sector = tmp_dev->end_sector; data_offset = tmp_dev->rdev->data_offset; bio->bi_bdev = tmp_dev->rdev->bdev; - rcu_read_unlock(); - if (unlikely(bio->bi_iter.bi_sector >= end_sector || bio->bi_iter.bi_sector < start_sector)) goto out_of_bounds; @@ -355,6 +321,10 @@ static void linear_status (struct seq_file *seq, struct mddev *mddev) seq_printf(seq, " %dk rounding", mddev->chunk_sectors / 2); } +static void linear_quiesce(struct mddev *mddev, int state) +{ +} + static struct md_personality linear_personality = { .name = "linear", @@ -362,10 +332,13 @@ static struct md_personality linear_personality = .owner = THIS_MODULE, .make_request = linear_make_request, .run = linear_run, - .stop = linear_stop, + .free = linear_free, .status = linear_status, .hot_add_disk = linear_add, .size = linear_size, + .quiesce = linear_quiesce, + .congested = linear_congested, + .mergeable_bvec = linear_mergeable_bvec, }; static int __init linear_init (void) diff --git a/drivers/md/md.c b/drivers/md/md.c index 709755fb6d7b..c8d2bac4e28b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -72,6 +72,7 @@ static struct workqueue_struct *md_misc_wq; static int remove_and_add_spares(struct mddev *mddev, struct md_rdev *this); +static void mddev_detach(struct mddev *mddev); /* * Default number of read corrections we'll attempt on an rdev @@ -292,8 +293,8 @@ static void md_make_request(struct request_queue *q, struct bio *bio) /* mddev_suspend makes sure no new requests are submitted * to the device, and that any requests that have been submitted * are completely handled. - * Once ->stop is called and completes, the module will be completely - * unused. + * Once mddev_detach() is called and completes, the module will be + * completely unused. */ void mddev_suspend(struct mddev *mddev) { @@ -321,10 +322,47 @@ EXPORT_SYMBOL_GPL(mddev_resume); int mddev_congested(struct mddev *mddev, int bits) { - return mddev->suspended; -} -EXPORT_SYMBOL(mddev_congested); + struct md_personality *pers = mddev->pers; + int ret = 0; + rcu_read_lock(); + if (mddev->suspended) + ret = 1; + else if (pers && pers->congested) + ret = pers->congested(mddev, bits); + rcu_read_unlock(); + return ret; +} +EXPORT_SYMBOL_GPL(mddev_congested); +static int md_congested(void *data, int bits) +{ + struct mddev *mddev = data; + return mddev_congested(mddev, bits); +} + +static int md_mergeable_bvec(struct request_queue *q, + struct bvec_merge_data *bvm, + struct bio_vec *biovec) +{ + struct mddev *mddev = q->queuedata; + int ret; + rcu_read_lock(); + if (mddev->suspended) { + /* Must always allow one vec */ + if (bvm->bi_size == 0) + ret = biovec->bv_len; + else + ret = 0; + } else { + struct md_personality *pers = mddev->pers; + if (pers && pers->mergeable_bvec) + ret = pers->mergeable_bvec(mddev, bvm, biovec); + else + ret = biovec->bv_len; + } + rcu_read_unlock(); + return ret; +} /* * Generic flush handling for md */ @@ -397,12 +435,12 @@ static void md_submit_flush_data(struct work_struct *ws) void md_flush_request(struct mddev *mddev, struct bio *bio) { - spin_lock_irq(&mddev->write_lock); + spin_lock_irq(&mddev->lock); wait_event_lock_irq(mddev->sb_wait, !mddev->flush_bio, - mddev->write_lock); + mddev->lock); mddev->flush_bio = bio; - spin_unlock_irq(&mddev->write_lock); + spin_unlock_irq(&mddev->lock); INIT_WORK(&mddev->flush_work, submit_flushes); queue_work(md_wq, &mddev->flush_work); @@ -465,7 +503,7 @@ void mddev_init(struct mddev *mddev) atomic_set(&mddev->active, 1); atomic_set(&mddev->openers, 0); atomic_set(&mddev->active_io, 0); - spin_lock_init(&mddev->write_lock); + spin_lock_init(&mddev->lock); atomic_set(&mddev->flush_pending, 0); init_waitqueue_head(&mddev->sb_wait); init_waitqueue_head(&mddev->recovery_wait); @@ -552,32 +590,9 @@ static struct mddev *mddev_find(dev_t unit) goto retry; } -static inline int __must_check mddev_lock(struct mddev *mddev) -{ - return mutex_lock_interruptible(&mddev->reconfig_mutex); -} - -/* Sometimes we need to take the lock in a situation where - * failure due to interrupts is not acceptable. - */ -static inline void mddev_lock_nointr(struct mddev *mddev) -{ - mutex_lock(&mddev->reconfig_mutex); -} - -static inline int mddev_is_locked(struct mddev *mddev) -{ - return mutex_is_locked(&mddev->reconfig_mutex); -} - -static inline int mddev_trylock(struct mddev *mddev) -{ - return mutex_trylock(&mddev->reconfig_mutex); -} - static struct attribute_group md_redundancy_group; -static void mddev_unlock(struct mddev *mddev) +void mddev_unlock(struct mddev *mddev) { if (mddev->to_remove) { /* These cannot be removed under reconfig_mutex as @@ -619,6 +634,7 @@ static void mddev_unlock(struct mddev *mddev) md_wakeup_thread(mddev->thread); spin_unlock(&pers_lock); } +EXPORT_SYMBOL_GPL(mddev_unlock); static struct md_rdev *find_rdev_nr_rcu(struct mddev *mddev, int nr) { @@ -2230,7 +2246,7 @@ repeat: return; } - spin_lock_irq(&mddev->write_lock); + spin_lock(&mddev->lock); mddev->utime = get_seconds(); @@ -2287,7 +2303,7 @@ repeat: } sync_sbs(mddev, nospares); - spin_unlock_irq(&mddev->write_lock); + spin_unlock(&mddev->lock); pr_debug("md: updating %s RAID superblock on device (in sync %d)\n", mdname(mddev), mddev->in_sync); @@ -2326,15 +2342,15 @@ repeat: md_super_wait(mddev); /* if there was a failure, MD_CHANGE_DEVS was set, and we re-write super */ - spin_lock_irq(&mddev->write_lock); + spin_lock(&mddev->lock); if (mddev->in_sync != sync_req || test_bit(MD_CHANGE_DEVS, &mddev->flags)) { /* have to write it out again */ - spin_unlock_irq(&mddev->write_lock); + spin_unlock(&mddev->lock); goto repeat; } clear_bit(MD_CHANGE_PENDING, &mddev->flags); - spin_unlock_irq(&mddev->write_lock); + spin_unlock(&mddev->lock); wake_up(&mddev->sb_wait); if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) sysfs_notify(&mddev->kobj, NULL, "sync_completed"); @@ -2381,40 +2397,41 @@ state_show(struct md_rdev *rdev, char *page) { char *sep = ""; size_t len = 0; + unsigned long flags = ACCESS_ONCE(rdev->flags); - if (test_bit(Faulty, &rdev->flags) || + if (test_bit(Faulty, &flags) || rdev->badblocks.unacked_exist) { len+= sprintf(page+len, "%sfaulty",sep); sep = ","; } - if (test_bit(In_sync, &rdev->flags)) { + if (test_bit(In_sync, &flags)) { len += sprintf(page+len, "%sin_sync",sep); sep = ","; } - if (test_bit(WriteMostly, &rdev->flags)) { + if (test_bit(WriteMostly, &flags)) { len += sprintf(page+len, "%swrite_mostly",sep); sep = ","; } - if (test_bit(Blocked, &rdev->flags) || + if (test_bit(Blocked, &flags) || (rdev->badblocks.unacked_exist - && !test_bit(Faulty, &rdev->flags))) { + && !test_bit(Faulty, &flags))) { len += sprintf(page+len, "%sblocked", sep); sep = ","; } - if (!test_bit(Faulty, &rdev->flags) && - !test_bit(In_sync, &rdev->flags)) { + if (!test_bit(Faulty, &flags) && + !test_bit(In_sync, &flags)) { len += sprintf(page+len, "%sspare", sep); sep = ","; } - if (test_bit(WriteErrorSeen, &rdev->flags)) { + if (test_bit(WriteErrorSeen, &flags)) { len += sprintf(page+len, "%swrite_error", sep); sep = ","; } - if (test_bit(WantReplacement, &rdev->flags)) { + if (test_bit(WantReplacement, &flags)) { len += sprintf(page+len, "%swant_replacement", sep); sep = ","; } - if (test_bit(Replacement, &rdev->flags)) { + if (test_bit(Replacement, &flags)) { len += sprintf(page+len, "%sreplacement", sep); sep = ","; } @@ -2927,21 +2944,12 @@ rdev_attr_show(struct kobject *kobj, struct attribute *attr, char *page) { struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr); struct md_rdev *rdev = container_of(kobj, struct md_rdev, kobj); - struct mddev *mddev = rdev->mddev; - ssize_t rv; if (!entry->show) return -EIO; - - rv = mddev ? mddev_lock(mddev) : -EBUSY; - if (!rv) { - if (rdev->mddev == NULL) - rv = -EBUSY; - else - rv = entry->show(rdev, page); - mddev_unlock(mddev); - } - return rv; + if (!rdev->mddev) + return -EBUSY; + return entry->show(rdev, page); } static ssize_t @@ -3212,11 +3220,13 @@ safe_delay_store(struct mddev *mddev, const char *cbuf, size_t len) mddev->safemode_delay = 0; else { unsigned long old_delay = mddev->safemode_delay; - mddev->safemode_delay = (msec*HZ)/1000; - if (mddev->safemode_delay == 0) - mddev->safemode_delay = 1; - if (mddev->safemode_delay < old_delay || old_delay == 0) - md_safemode_timeout((unsigned long)mddev); + unsigned long new_delay = (msec*HZ)/1000; + + if (new_delay == 0) + new_delay = 1; + mddev->safemode_delay = new_delay; + if (new_delay < old_delay || old_delay == 0) + mod_timer(&mddev->safemode_timer, jiffies+1); } return len; } @@ -3226,41 +3236,52 @@ __ATTR(safe_mode_delay, S_IRUGO|S_IWUSR,safe_delay_show, safe_delay_store); static ssize_t level_show(struct mddev *mddev, char *page) { - struct md_personality *p = mddev->pers; + struct md_personality *p; + int ret; + spin_lock(&mddev->lock); + p = mddev->pers; if (p) - return sprintf(page, "%s\n", p->name); + ret = sprintf(page, "%s\n", p->name); else if (mddev->clevel[0]) - return sprintf(page, "%s\n", mddev->clevel); + ret = sprintf(page, "%s\n", mddev->clevel); else if (mddev->level != LEVEL_NONE) - return sprintf(page, "%d\n", mddev->level); + ret = sprintf(page, "%d\n", mddev->level); else - return 0; + ret = 0; + spin_unlock(&mddev->lock); + return ret; } static ssize_t level_store(struct mddev *mddev, const char *buf, size_t len) { char clevel[16]; - ssize_t rv = len; - struct md_personality *pers; + ssize_t rv; + size_t slen = len; + struct md_personality *pers, *oldpers; long level; - void *priv; + void *priv, *oldpriv; struct md_rdev *rdev; - if (mddev->pers == NULL) { - if (len == 0) - return 0; - if (len >= sizeof(mddev->clevel)) - return -ENOSPC; - strncpy(mddev->clevel, buf, len); - if (mddev->clevel[len-1] == '\n') - len--; - mddev->clevel[len] = 0; - mddev->level = LEVEL_NONE; + if (slen == 0 || slen >= sizeof(clevel)) + return -EINVAL; + + rv = mddev_lock(mddev); + if (rv) return rv; + + if (mddev->pers == NULL) { + strncpy(mddev->clevel, buf, slen); + if (mddev->clevel[slen-1] == '\n') + slen--; + mddev->clevel[slen] = 0; + mddev->level = LEVEL_NONE; + rv = len; + goto out_unlock; } + rv = -EROFS; if (mddev->ro) - return -EROFS; + goto out_unlock; /* request to change the personality. Need to ensure: * - array is not engaged in resync/recovery/reshape @@ -3268,25 +3289,25 @@ level_store(struct mddev *mddev, const char *buf, size_t len) * - new personality will access other array. */ + rv = -EBUSY; if (mddev->sync_thread || test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || mddev->reshape_position != MaxSector || mddev->sysfs_active) - return -EBUSY; + goto out_unlock; + rv = -EINVAL; if (!mddev->pers->quiesce) { printk(KERN_WARNING "md: %s: %s does not support online personality change\n", mdname(mddev), mddev->pers->name); - return -EINVAL; + goto out_unlock; } /* Now find the new personality */ - if (len == 0 || len >= sizeof(clevel)) - return -EINVAL; - strncpy(clevel, buf, len); - if (clevel[len-1] == '\n') - len--; - clevel[len] = 0; + strncpy(clevel, buf, slen); + if (clevel[slen-1] == '\n') + slen--; + clevel[slen] = 0; if (kstrtol(clevel, 10, &level)) level = LEVEL_NONE; @@ -3297,20 +3318,23 @@ level_store(struct mddev *mddev, const char *buf, size_t len) if (!pers || !try_module_get(pers->owner)) { spin_unlock(&pers_lock); printk(KERN_WARNING "md: personality %s not loaded\n", clevel); - return -EINVAL; + rv = -EINVAL; + goto out_unlock; } spin_unlock(&pers_lock); if (pers == mddev->pers) { /* Nothing to do! */ module_put(pers->owner); - return rv; + rv = len; + goto out_unlock; } if (!pers->takeover) { module_put(pers->owner); printk(KERN_WARNING "md: %s: %s does not support personality takeover\n", mdname(mddev), clevel); - return -EINVAL; + rv = -EINVAL; + goto out_unlock; } rdev_for_each(rdev, mddev) @@ -3330,30 +3354,29 @@ level_store(struct mddev *mddev, const char *buf, size_t len) module_put(pers->owner); printk(KERN_WARNING "md: %s: %s would not accept array\n", mdname(mddev), clevel); - return PTR_ERR(priv); + rv = PTR_ERR(priv); + goto out_unlock; } /* Looks like we have a winner */ mddev_suspend(mddev); - mddev->pers->stop(mddev); + mddev_detach(mddev); - if (mddev->pers->sync_request == NULL && - pers->sync_request != NULL) { - /* need to add the md_redundancy_group */ - if (sysfs_create_group(&mddev->kobj, &md_redundancy_group)) - printk(KERN_WARNING - "md: cannot register extra attributes for %s\n", - mdname(mddev)); - mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action"); - } - if (mddev->pers->sync_request != NULL && - pers->sync_request == NULL) { - /* need to remove the md_redundancy_group */ - if (mddev->to_remove == NULL) - mddev->to_remove = &md_redundancy_group; - } + spin_lock(&mddev->lock); + oldpers = mddev->pers; + oldpriv = mddev->private; + mddev->pers = pers; + mddev->private = priv; + strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel)); + mddev->level = mddev->new_level; + mddev->layout = mddev->new_layout; + mddev->chunk_sectors = mddev->new_chunk_sectors; + mddev->delta_disks = 0; + mddev->reshape_backwards = 0; + mddev->degraded = 0; + spin_unlock(&mddev->lock); - if (mddev->pers->sync_request == NULL && + if (oldpers->sync_request == NULL && mddev->external) { /* We are converting from a no-redundancy array * to a redundancy array and metadata is managed @@ -3367,6 +3390,24 @@ level_store(struct mddev *mddev, const char *buf, size_t len) mddev->safemode = 0; } + oldpers->free(mddev, oldpriv); + + if (oldpers->sync_request == NULL && + pers->sync_request != NULL) { + /* need to add the md_redundancy_group */ + if (sysfs_create_group(&mddev->kobj, &md_redundancy_group)) + printk(KERN_WARNING + "md: cannot register extra attributes for %s\n", + mdname(mddev)); + mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action"); + } + if (oldpers->sync_request != NULL && + pers->sync_request == NULL) { + /* need to remove the md_redundancy_group */ + if (mddev->to_remove == NULL) + mddev->to_remove = &md_redundancy_group; + } + rdev_for_each(rdev, mddev) { if (rdev->raid_disk < 0) continue; @@ -3392,17 +3433,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len) } } - module_put(mddev->pers->owner); - mddev->pers = pers; - mddev->private = priv; - strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel)); - mddev->level = mddev->new_level; - mddev->layout = mddev->new_layout; - mddev->chunk_sectors = mddev->new_chunk_sectors; - mddev->delta_disks = 0; - mddev->reshape_backwards = 0; - mddev->degraded = 0; - if (mddev->pers->sync_request == NULL) { + if (pers->sync_request == NULL) { /* this is now an array without redundancy, so * it must always be in_sync */ @@ -3417,6 +3448,9 @@ level_store(struct mddev *mddev, const char *buf, size_t len) md_update_sb(mddev, 1); sysfs_notify(&mddev->kobj, NULL, "level"); md_new_event(mddev); + rv = len; +out_unlock: + mddev_unlock(mddev); return rv; } @@ -3439,28 +3473,32 @@ layout_store(struct mddev *mddev, const char *buf, size_t len) { char *e; unsigned long n = simple_strtoul(buf, &e, 10); + int err; if (!*buf || (*e && *e != '\n')) return -EINVAL; + err = mddev_lock(mddev); + if (err) + return err; if (mddev->pers) { - int err; if (mddev->pers->check_reshape == NULL) - return -EBUSY; - if (mddev->ro) - return -EROFS; - mddev->new_layout = n; - err = mddev->pers->check_reshape(mddev); - if (err) { - mddev->new_layout = mddev->layout; - return err; + err = -EBUSY; + else if (mddev->ro) + err = -EROFS; + else { + mddev->new_layout = n; + err = mddev->pers->check_reshape(mddev); + if (err) + mddev->new_layout = mddev->layout; } } else { mddev->new_layout = n; if (mddev->reshape_position == MaxSector) mddev->layout = n; } - return len; + mddev_unlock(mddev); + return err ?: len; } static struct md_sysfs_entry md_layout = __ATTR(layout, S_IRUGO|S_IWUSR, layout_show, layout_store); @@ -3483,32 +3521,39 @@ static ssize_t raid_disks_store(struct mddev *mddev, const char *buf, size_t len) { char *e; - int rv = 0; + int err; unsigned long n = simple_strtoul(buf, &e, 10); if (!*buf || (*e && *e != '\n')) return -EINVAL; + err = mddev_lock(mddev); + if (err) + return err; if (mddev->pers) - rv = update_raid_disks(mddev, n); + err = update_raid_disks(mddev, n); else if (mddev->reshape_position != MaxSector) { struct md_rdev *rdev; int olddisks = mddev->raid_disks - mddev->delta_disks; + err = -EINVAL; rdev_for_each(rdev, mddev) { if (olddisks < n && rdev->data_offset < rdev->new_data_offset) - return -EINVAL; + goto out_unlock; if (olddisks > n && rdev->data_offset > rdev->new_data_offset) - return -EINVAL; + goto out_unlock; } + err = 0; mddev->delta_disks = n - olddisks; mddev->raid_disks = n; mddev->reshape_backwards = (mddev->delta_disks < 0); } else mddev->raid_disks = n; - return rv ? rv : len; +out_unlock: + mddev_unlock(mddev); + return err ? err : len; } static struct md_sysfs_entry md_raid_disks = __ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store); @@ -3527,30 +3572,34 @@ chunk_size_show(struct mddev *mddev, char *page) static ssize_t chunk_size_store(struct mddev *mddev, const char *buf, size_t len) { + int err; char *e; unsigned long n = simple_strtoul(buf, &e, 10); if (!*buf || (*e && *e != '\n')) return -EINVAL; + err = mddev_lock(mddev); + if (err) + return err; if (mddev->pers) { - int err; if (mddev->pers->check_reshape == NULL) - return -EBUSY; - if (mddev->ro) - return -EROFS; - mddev->new_chunk_sectors = n >> 9; - err = mddev->pers->check_reshape(mddev); - if (err) { - mddev->new_chunk_sectors = mddev->chunk_sectors; - return err; + err = -EBUSY; + else if (mddev->ro) + err = -EROFS; + else { + mddev->new_chunk_sectors = n >> 9; + err = mddev->pers->check_reshape(mddev); + if (err) + mddev->new_chunk_sectors = mddev->chunk_sectors; } } else { mddev->new_chunk_sectors = n >> 9; if (mddev->reshape_position == MaxSector) mddev->chunk_sectors = n >> 9; } - return len; + mddev_unlock(mddev); + return err ?: len; } static struct md_sysfs_entry md_chunk_size = __ATTR(chunk_size, S_IRUGO|S_IWUSR, chunk_size_show, chunk_size_store); @@ -3566,20 +3615,27 @@ resync_start_show(struct mddev *mddev, char *page) static ssize_t resync_start_store(struct mddev *mddev, const char *buf, size_t len) { + int err; char *e; unsigned long long n = simple_strtoull(buf, &e, 10); + err = mddev_lock(mddev); + if (err) + return err; if (mddev->pers && !test_bit(MD_RECOVERY_FROZEN, &mddev->recovery)) - return -EBUSY; - if (cmd_match(buf, "none")) + err = -EBUSY; + else if (cmd_match(buf, "none")) n = MaxSector; else if (!*buf || (*e && *e != '\n')) - return -EINVAL; + err = -EINVAL; - mddev->recovery_cp = n; - if (mddev->pers) - set_bit(MD_CHANGE_CLEAN, &mddev->flags); - return len; + if (!err) { + mddev->recovery_cp = n; + if (mddev->pers) + set_bit(MD_CHANGE_CLEAN, &mddev->flags); + } + mddev_unlock(mddev); + return err ?: len; } static struct md_sysfs_entry md_resync_start = __ATTR(resync_start, S_IRUGO|S_IWUSR, resync_start_show, resync_start_store); @@ -3677,8 +3733,39 @@ static int restart_array(struct mddev *mddev); static ssize_t array_state_store(struct mddev *mddev, const char *buf, size_t len) { - int err = -EINVAL; + int err; enum array_state st = match_word(buf, array_states); + + if (mddev->pers && (st == active || st == clean) && mddev->ro != 1) { + /* don't take reconfig_mutex when toggling between + * clean and active + */ + spin_lock(&mddev->lock); + if (st == active) { + restart_array(mddev); + clear_bit(MD_CHANGE_PENDING, &mddev->flags); + wake_up(&mddev->sb_wait); + err = 0; + } else /* st == clean */ { + restart_array(mddev); + if (atomic_read(&mddev->writes_pending) == 0) { + if (mddev->in_sync == 0) { + mddev->in_sync = 1; + if (mddev->safemode == 1) + mddev->safemode = 0; + set_bit(MD_CHANGE_CLEAN, &mddev->flags); + } + err = 0; + } else + err = -EBUSY; + } + spin_unlock(&mddev->lock); + return err; + } + err = mddev_lock(mddev); + if (err) + return err; + err = -EINVAL; switch(st) { case bad_word: break; @@ -3722,7 +3809,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) case clean: if (mddev->pers) { restart_array(mddev); - spin_lock_irq(&mddev->write_lock); + spin_lock(&mddev->lock); if (atomic_read(&mddev->writes_pending) == 0) { if (mddev->in_sync == 0) { mddev->in_sync = 1; @@ -3733,7 +3820,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) err = 0; } else err = -EBUSY; - spin_unlock_irq(&mddev->write_lock); + spin_unlock(&mddev->lock); } else err = -EINVAL; break; @@ -3754,14 +3841,14 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) /* these cannot be set */ break; } - if (err) - return err; - else { + + if (!err) { if (mddev->hold_active == UNTIL_IOCTL) mddev->hold_active = 0; sysfs_notify_dirent_safe(mddev->sysfs_state); - return len; } + mddev_unlock(mddev); + return err ?: len; } static struct md_sysfs_entry md_array_state = __ATTR(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store); @@ -3822,6 +3909,11 @@ new_dev_store(struct mddev *mddev, const char *buf, size_t len) minor != MINOR(dev)) return -EOVERFLOW; + flush_workqueue(md_misc_wq); + + err = mddev_lock(mddev); + if (err) + return err; if (mddev->persistent) { rdev = md_import_device(dev, mddev->major_version, mddev->minor_version); @@ -3845,6 +3937,7 @@ new_dev_store(struct mddev *mddev, const char *buf, size_t len) out: if (err) export_rdev(rdev); + mddev_unlock(mddev); return err ? err : len; } @@ -3856,7 +3949,11 @@ bitmap_store(struct mddev *mddev, const char *buf, size_t len) { char *end; unsigned long chunk, end_chunk; + int err; + err = mddev_lock(mddev); + if (err) + return err; if (!mddev->bitmap) goto out; /* buf should be ... or - ... (range) */ @@ -3874,6 +3971,7 @@ bitmap_store(struct mddev *mddev, const char *buf, size_t len) } bitmap_unplug(mddev->bitmap); /* flush the bits to disk */ out: + mddev_unlock(mddev); return len; } @@ -3901,6 +3999,9 @@ size_store(struct mddev *mddev, const char *buf, size_t len) if (err < 0) return err; + err = mddev_lock(mddev); + if (err) + return err; if (mddev->pers) { err = update_size(mddev, sectors); md_update_sb(mddev, 1); @@ -3911,6 +4012,7 @@ size_store(struct mddev *mddev, const char *buf, size_t len) else err = -ENOSPC; } + mddev_unlock(mddev); return err ? err : len; } @@ -3940,21 +4042,28 @@ metadata_store(struct mddev *mddev, const char *buf, size_t len) { int major, minor; char *e; + int err; /* Changing the details of 'external' metadata is * always permitted. Otherwise there must be * no devices attached to the array. */ + + err = mddev_lock(mddev); + if (err) + return err; + err = -EBUSY; if (mddev->external && strncmp(buf, "external:", 9) == 0) ; else if (!list_empty(&mddev->disks)) - return -EBUSY; + goto out_unlock; + err = 0; if (cmd_match(buf, "none")) { mddev->persistent = 0; mddev->external = 0; mddev->major_version = 0; mddev->minor_version = 90; - return len; + goto out_unlock; } if (strncmp(buf, "external:", 9) == 0) { size_t namelen = len-9; @@ -3968,22 +4077,27 @@ metadata_store(struct mddev *mddev, const char *buf, size_t len) mddev->external = 1; mddev->major_version = 0; mddev->minor_version = 90; - return len; + goto out_unlock; } major = simple_strtoul(buf, &e, 10); + err = -EINVAL; if (e==buf || *e != '.') - return -EINVAL; + goto out_unlock; buf = e+1; minor = simple_strtoul(buf, &e, 10); if (e==buf || (*e && *e != '\n') ) - return -EINVAL; + goto out_unlock; + err = -ENOENT; if (major >= ARRAY_SIZE(super_types) || super_types[major].name == NULL) - return -ENOENT; + goto out_unlock; mddev->major_version = major; mddev->minor_version = minor; mddev->persistent = 1; mddev->external = 0; - return len; + err = 0; +out_unlock: + mddev_unlock(mddev); + return err ?: len; } static struct md_sysfs_entry md_metadata = @@ -3993,20 +4107,21 @@ static ssize_t action_show(struct mddev *mddev, char *page) { char *type = "idle"; - if (test_bit(MD_RECOVERY_FROZEN, &mddev->recovery)) + unsigned long recovery = mddev->recovery; + if (test_bit(MD_RECOVERY_FROZEN, &recovery)) type = "frozen"; - else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || - (!mddev->ro && test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))) { - if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) + else if (test_bit(MD_RECOVERY_RUNNING, &recovery) || + (!mddev->ro && test_bit(MD_RECOVERY_NEEDED, &recovery))) { + if (test_bit(MD_RECOVERY_RESHAPE, &recovery)) type = "reshape"; - else if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { - if (!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) + else if (test_bit(MD_RECOVERY_SYNC, &recovery)) { + if (!test_bit(MD_RECOVERY_REQUESTED, &recovery)) type = "resync"; - else if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)) + else if (test_bit(MD_RECOVERY_CHECK, &recovery)) type = "check"; else type = "repair"; - } else if (test_bit(MD_RECOVERY_RECOVER, &mddev->recovery)) + } else if (test_bit(MD_RECOVERY_RECOVER, &recovery)) type = "recover"; } return sprintf(page, "%s\n", type); @@ -4027,7 +4142,10 @@ action_store(struct mddev *mddev, const char *page, size_t len) flush_workqueue(md_misc_wq); if (mddev->sync_thread) { set_bit(MD_RECOVERY_INTR, &mddev->recovery); - md_reap_sync_thread(mddev); + if (mddev_lock(mddev) == 0) { + md_reap_sync_thread(mddev); + mddev_unlock(mddev); + } } } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) @@ -4041,7 +4159,11 @@ action_store(struct mddev *mddev, const char *page, size_t len) int err; if (mddev->pers->start_reshape == NULL) return -EINVAL; - err = mddev->pers->start_reshape(mddev); + err = mddev_lock(mddev); + if (!err) { + err = mddev->pers->start_reshape(mddev); + mddev_unlock(mddev); + } if (err) return err; sysfs_notify(&mddev->kobj, NULL, "degraded"); @@ -4225,22 +4347,36 @@ static ssize_t min_sync_store(struct mddev *mddev, const char *buf, size_t len) { unsigned long long min; + int err; + int chunk; + if (kstrtoull(buf, 10, &min)) return -EINVAL; + + spin_lock(&mddev->lock); + err = -EINVAL; if (min > mddev->resync_max) - return -EINVAL; + goto out_unlock; + + err = -EBUSY; if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) - return -EBUSY; + goto out_unlock; /* Must be a multiple of chunk_size */ - if (mddev->chunk_sectors) { + chunk = mddev->chunk_sectors; + if (chunk) { sector_t temp = min; - if (sector_div(temp, mddev->chunk_sectors)) - return -EINVAL; + + err = -EINVAL; + if (sector_div(temp, chunk)) + goto out_unlock; } mddev->resync_min = min; + err = 0; - return len; +out_unlock: + spin_unlock(&mddev->lock); + return err ?: len; } static struct md_sysfs_entry md_min_sync = @@ -4258,29 +4394,42 @@ max_sync_show(struct mddev *mddev, char *page) static ssize_t max_sync_store(struct mddev *mddev, const char *buf, size_t len) { + int err; + spin_lock(&mddev->lock); if (strncmp(buf, "max", 3) == 0) mddev->resync_max = MaxSector; else { unsigned long long max; + int chunk; + + err = -EINVAL; if (kstrtoull(buf, 10, &max)) - return -EINVAL; + goto out_unlock; if (max < mddev->resync_min) - return -EINVAL; + goto out_unlock; + + err = -EBUSY; if (max < mddev->resync_max && mddev->ro == 0 && test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) - return -EBUSY; + goto out_unlock; /* Must be a multiple of chunk_size */ - if (mddev->chunk_sectors) { + chunk = mddev->chunk_sectors; + if (chunk) { sector_t temp = max; - if (sector_div(temp, mddev->chunk_sectors)) - return -EINVAL; + + err = -EINVAL; + if (sector_div(temp, chunk)) + goto out_unlock; } mddev->resync_max = max; } wake_up(&mddev->recovery_wait); - return len; + err = 0; +out_unlock: + spin_unlock(&mddev->lock); + return err ?: len; } static struct md_sysfs_entry md_max_sync = @@ -4297,14 +4446,20 @@ suspend_lo_store(struct mddev *mddev, const char *buf, size_t len) { char *e; unsigned long long new = simple_strtoull(buf, &e, 10); - unsigned long long old = mddev->suspend_lo; + unsigned long long old; + int err; - if (mddev->pers == NULL || - mddev->pers->quiesce == NULL) - return -EINVAL; if (buf == e || (*e && *e != '\n')) return -EINVAL; + err = mddev_lock(mddev); + if (err) + return err; + err = -EINVAL; + if (mddev->pers == NULL || + mddev->pers->quiesce == NULL) + goto unlock; + old = mddev->suspend_lo; mddev->suspend_lo = new; if (new >= old) /* Shrinking suspended region */ @@ -4314,7 +4469,10 @@ suspend_lo_store(struct mddev *mddev, const char *buf, size_t len) mddev->pers->quiesce(mddev, 1); mddev->pers->quiesce(mddev, 0); } - return len; + err = 0; +unlock: + mddev_unlock(mddev); + return err ?: len; } static struct md_sysfs_entry md_suspend_lo = __ATTR(suspend_lo, S_IRUGO|S_IWUSR, suspend_lo_show, suspend_lo_store); @@ -4330,14 +4488,20 @@ suspend_hi_store(struct mddev *mddev, const char *buf, size_t len) { char *e; unsigned long long new = simple_strtoull(buf, &e, 10); - unsigned long long old = mddev->suspend_hi; + unsigned long long old; + int err; - if (mddev->pers == NULL || - mddev->pers->quiesce == NULL) - return -EINVAL; if (buf == e || (*e && *e != '\n')) return -EINVAL; + err = mddev_lock(mddev); + if (err) + return err; + err = -EINVAL; + if (mddev->pers == NULL || + mddev->pers->quiesce == NULL) + goto unlock; + old = mddev->suspend_hi; mddev->suspend_hi = new; if (new <= old) /* Shrinking suspended region */ @@ -4347,7 +4511,10 @@ suspend_hi_store(struct mddev *mddev, const char *buf, size_t len) mddev->pers->quiesce(mddev, 1); mddev->pers->quiesce(mddev, 0); } - return len; + err = 0; +unlock: + mddev_unlock(mddev); + return err ?: len; } static struct md_sysfs_entry md_suspend_hi = __ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store); @@ -4367,11 +4534,17 @@ reshape_position_store(struct mddev *mddev, const char *buf, size_t len) { struct md_rdev *rdev; char *e; + int err; unsigned long long new = simple_strtoull(buf, &e, 10); - if (mddev->pers) - return -EBUSY; + if (buf == e || (*e && *e != '\n')) return -EINVAL; + err = mddev_lock(mddev); + if (err) + return err; + err = -EBUSY; + if (mddev->pers) + goto unlock; mddev->reshape_position = new; mddev->delta_disks = 0; mddev->reshape_backwards = 0; @@ -4380,7 +4553,10 @@ reshape_position_store(struct mddev *mddev, const char *buf, size_t len) mddev->new_chunk_sectors = mddev->chunk_sectors; rdev_for_each(rdev, mddev) rdev->new_data_offset = rdev->data_offset; - return len; + err = 0; +unlock: + mddev_unlock(mddev); + return err ?: len; } static struct md_sysfs_entry md_reshape_position = @@ -4398,6 +4574,8 @@ static ssize_t reshape_direction_store(struct mddev *mddev, const char *buf, size_t len) { int backwards = 0; + int err; + if (cmd_match(buf, "forwards")) backwards = 0; else if (cmd_match(buf, "backwards")) @@ -4407,16 +4585,19 @@ reshape_direction_store(struct mddev *mddev, const char *buf, size_t len) if (mddev->reshape_backwards == backwards) return len; + err = mddev_lock(mddev); + if (err) + return err; /* check if we are allowed to change */ if (mddev->delta_disks) - return -EBUSY; - - if (mddev->persistent && + err = -EBUSY; + else if (mddev->persistent && mddev->major_version == 0) - return -EINVAL; - - mddev->reshape_backwards = backwards; - return len; + err = -EINVAL; + else + mddev->reshape_backwards = backwards; + mddev_unlock(mddev); + return err ?: len; } static struct md_sysfs_entry md_reshape_direction = @@ -4437,6 +4618,11 @@ static ssize_t array_size_store(struct mddev *mddev, const char *buf, size_t len) { sector_t sectors; + int err; + + err = mddev_lock(mddev); + if (err) + return err; if (strncmp(buf, "default", 7) == 0) { if (mddev->pers) @@ -4447,19 +4633,22 @@ array_size_store(struct mddev *mddev, const char *buf, size_t len) mddev->external_size = 0; } else { if (strict_blocks_to_sectors(buf, §ors) < 0) - return -EINVAL; - if (mddev->pers && mddev->pers->size(mddev, 0, 0) < sectors) - return -E2BIG; - - mddev->external_size = 1; + err = -EINVAL; + else if (mddev->pers && mddev->pers->size(mddev, 0, 0) < sectors) + err = -E2BIG; + else + mddev->external_size = 1; } - mddev->array_sectors = sectors; - if (mddev->pers) { - set_capacity(mddev->gendisk, mddev->array_sectors); - revalidate_disk(mddev->gendisk); + if (!err) { + mddev->array_sectors = sectors; + if (mddev->pers) { + set_capacity(mddev->gendisk, mddev->array_sectors); + revalidate_disk(mddev->gendisk); + } } - return len; + mddev_unlock(mddev); + return err ?: len; } static struct md_sysfs_entry md_array_size = @@ -4523,11 +4712,7 @@ md_attr_show(struct kobject *kobj, struct attribute *attr, char *page) mddev_get(mddev); spin_unlock(&all_mddevs_lock); - rv = mddev_lock(mddev); - if (!rv) { - rv = entry->show(mddev, page); - mddev_unlock(mddev); - } + rv = entry->show(mddev, page); mddev_put(mddev); return rv; } @@ -4551,13 +4736,7 @@ md_attr_store(struct kobject *kobj, struct attribute *attr, } mddev_get(mddev); spin_unlock(&all_mddevs_lock); - if (entry->store == new_dev_store) - flush_workqueue(md_misc_wq); - rv = mddev_lock(mddev); - if (!rv) { - rv = entry->store(mddev, page, length); - mddev_unlock(mddev); - } + rv = entry->store(mddev, page, length); mddev_put(mddev); return rv; } @@ -4825,7 +5004,6 @@ int md_run(struct mddev *mddev) mddev->clevel); return -EINVAL; } - mddev->pers = pers; spin_unlock(&pers_lock); if (mddev->level != pers->level) { mddev->level = pers->level; @@ -4836,7 +5014,6 @@ int md_run(struct mddev *mddev) if (mddev->reshape_position != MaxSector && pers->start_reshape == NULL) { /* This personality cannot handle reshaping... */ - mddev->pers = NULL; module_put(pers->owner); return -EINVAL; } @@ -4880,35 +5057,38 @@ int md_run(struct mddev *mddev) if (start_readonly && mddev->ro == 0) mddev->ro = 2; /* read-only, but switch on first write */ - err = mddev->pers->run(mddev); + err = pers->run(mddev); if (err) printk(KERN_ERR "md: pers->run() failed ...\n"); - else if (mddev->pers->size(mddev, 0, 0) < mddev->array_sectors) { + else if (pers->size(mddev, 0, 0) < mddev->array_sectors) { WARN_ONCE(!mddev->external_size, "%s: default size too small," " but 'external_size' not in effect?\n", __func__); printk(KERN_ERR "md: invalid array_size %llu > default size %llu\n", (unsigned long long)mddev->array_sectors / 2, - (unsigned long long)mddev->pers->size(mddev, 0, 0) / 2); + (unsigned long long)pers->size(mddev, 0, 0) / 2); err = -EINVAL; - mddev->pers->stop(mddev); } - if (err == 0 && mddev->pers->sync_request && + if (err == 0 && pers->sync_request && (mddev->bitmap_info.file || mddev->bitmap_info.offset)) { err = bitmap_create(mddev); - if (err) { + if (err) printk(KERN_ERR "%s: failed to create bitmap (%d)\n", mdname(mddev), err); - mddev->pers->stop(mddev); - } } if (err) { - module_put(mddev->pers->owner); - mddev->pers = NULL; + mddev_detach(mddev); + pers->free(mddev, mddev->private); + module_put(pers->owner); bitmap_destroy(mddev); return err; } - if (mddev->pers->sync_request) { + if (mddev->queue) { + mddev->queue->backing_dev_info.congested_data = mddev; + mddev->queue->backing_dev_info.congested_fn = md_congested; + blk_queue_merge_bvec(mddev->queue, md_mergeable_bvec); + } + if (pers->sync_request) { if (mddev->kobj.sd && sysfs_create_group(&mddev->kobj, &md_redundancy_group)) printk(KERN_WARNING @@ -4927,7 +5107,10 @@ int md_run(struct mddev *mddev) mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */ mddev->in_sync = 1; smp_wmb(); + spin_lock(&mddev->lock); + mddev->pers = pers; mddev->ready = 1; + spin_unlock(&mddev->lock); rdev_for_each(rdev, mddev) if (rdev->raid_disk >= 0) if (sysfs_link_rdev(mddev, rdev)) @@ -5070,14 +5253,38 @@ void md_stop_writes(struct mddev *mddev) } EXPORT_SYMBOL_GPL(md_stop_writes); +static void mddev_detach(struct mddev *mddev) +{ + struct bitmap *bitmap = mddev->bitmap; + /* wait for behind writes to complete */ + if (bitmap && atomic_read(&bitmap->behind_writes) > 0) { + printk(KERN_INFO "md:%s: behind writes in progress - waiting to stop.\n", + mdname(mddev)); + /* need to kick something here to make sure I/O goes? */ + wait_event(bitmap->behind_wait, + atomic_read(&bitmap->behind_writes) == 0); + } + if (mddev->pers && mddev->pers->quiesce) { + mddev->pers->quiesce(mddev, 1); + mddev->pers->quiesce(mddev, 0); + } + md_unregister_thread(&mddev->thread); + if (mddev->queue) + blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ +} + static void __md_stop(struct mddev *mddev) { + struct md_personality *pers = mddev->pers; + mddev_detach(mddev); + spin_lock(&mddev->lock); mddev->ready = 0; - mddev->pers->stop(mddev); - if (mddev->pers->sync_request && mddev->to_remove == NULL) - mddev->to_remove = &md_redundancy_group; - module_put(mddev->pers->owner); mddev->pers = NULL; + spin_unlock(&mddev->lock); + pers->free(mddev, mddev->private); + if (pers->sync_request && mddev->to_remove == NULL) + mddev->to_remove = &md_redundancy_group; + module_put(pers->owner); clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); } @@ -5226,8 +5433,11 @@ static int do_md_stop(struct mddev *mddev, int mode, bitmap_destroy(mddev); if (mddev->bitmap_info.file) { - fput(mddev->bitmap_info.file); + struct file *f = mddev->bitmap_info.file; + spin_lock(&mddev->lock); mddev->bitmap_info.file = NULL; + spin_unlock(&mddev->lock); + fput(f); } mddev->bitmap_info.offset = 0; @@ -5436,37 +5646,31 @@ static int get_array_info(struct mddev *mddev, void __user *arg) static int get_bitmap_file(struct mddev *mddev, void __user * arg) { mdu_bitmap_file_t *file = NULL; /* too big for stack allocation */ - char *ptr, *buf = NULL; - int err = -ENOMEM; + char *ptr; + int err; file = kmalloc(sizeof(*file), GFP_NOIO); - if (!file) - goto out; + return -ENOMEM; - /* bitmap disabled, zero the first byte and copy out */ - if (!mddev->bitmap || !mddev->bitmap->storage.file) { - file->pathname[0] = '\0'; - goto copy_out; - } - - buf = kmalloc(sizeof(file->pathname), GFP_KERNEL); - if (!buf) - goto out; - - ptr = d_path(&mddev->bitmap->storage.file->f_path, - buf, sizeof(file->pathname)); - if (IS_ERR(ptr)) - goto out; - - strcpy(file->pathname, ptr); - -copy_out: err = 0; - if (copy_to_user(arg, file, sizeof(*file))) + spin_lock(&mddev->lock); + /* bitmap disabled, zero the first byte and copy out */ + if (!mddev->bitmap_info.file) + file->pathname[0] = '\0'; + else if ((ptr = d_path(&mddev->bitmap_info.file->f_path, + file->pathname, sizeof(file->pathname))), + IS_ERR(ptr)) + err = PTR_ERR(ptr); + else + memmove(file->pathname, ptr, + sizeof(file->pathname)-(ptr-file->pathname)); + spin_unlock(&mddev->lock); + + if (err == 0 && + copy_to_user(arg, file, sizeof(*file))) err = -EFAULT; -out: - kfree(buf); + kfree(file); return err; } @@ -5789,22 +5993,24 @@ static int set_bitmap_file(struct mddev *mddev, int fd) if (fd >= 0) { struct inode *inode; - if (mddev->bitmap) - return -EEXIST; /* cannot add when bitmap is present */ - mddev->bitmap_info.file = fget(fd); + struct file *f; - if (mddev->bitmap_info.file == NULL) { + if (mddev->bitmap || mddev->bitmap_info.file) + return -EEXIST; /* cannot add when bitmap is present */ + f = fget(fd); + + if (f == NULL) { printk(KERN_ERR "%s: error: failed to get bitmap file\n", mdname(mddev)); return -EBADF; } - inode = mddev->bitmap_info.file->f_mapping->host; + inode = f->f_mapping->host; if (!S_ISREG(inode->i_mode)) { printk(KERN_ERR "%s: error: bitmap file must be a regular file\n", mdname(mddev)); err = -EBADF; - } else if (!(mddev->bitmap_info.file->f_mode & FMODE_WRITE)) { + } else if (!(f->f_mode & FMODE_WRITE)) { printk(KERN_ERR "%s: error: bitmap file must open for write\n", mdname(mddev)); err = -EBADF; @@ -5814,10 +6020,10 @@ static int set_bitmap_file(struct mddev *mddev, int fd) err = -EBUSY; } if (err) { - fput(mddev->bitmap_info.file); - mddev->bitmap_info.file = NULL; + fput(f); return err; } + mddev->bitmap_info.file = f; mddev->bitmap_info.offset = 0; /* file overrides offset */ } else if (mddev->bitmap == NULL) return -ENOENT; /* cannot remove what isn't there */ @@ -5836,9 +6042,13 @@ static int set_bitmap_file(struct mddev *mddev, int fd) mddev->pers->quiesce(mddev, 0); } if (fd < 0) { - if (mddev->bitmap_info.file) - fput(mddev->bitmap_info.file); - mddev->bitmap_info.file = NULL; + struct file *f = mddev->bitmap_info.file; + if (f) { + spin_lock(&mddev->lock); + mddev->bitmap_info.file = NULL; + spin_unlock(&mddev->lock); + fput(f); + } } return err; @@ -6251,6 +6461,11 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, case SET_DISK_FAULTY: err = set_disk_faulty(mddev, new_decode_dev(arg)); goto out; + + case GET_BITMAP_FILE: + err = get_bitmap_file(mddev, argp); + goto out; + } if (cmd == ADD_NEW_DISK) @@ -6342,10 +6557,6 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, * Commands even a read-only array can execute: */ switch (cmd) { - case GET_BITMAP_FILE: - err = get_bitmap_file(mddev, argp); - goto unlock; - case RESTART_ARRAY_RW: err = restart_array(mddev); goto unlock; @@ -6873,9 +7084,7 @@ static int md_seq_show(struct seq_file *seq, void *v) return 0; } - if (mddev_lock(mddev) < 0) - return -EINTR; - + spin_lock(&mddev->lock); if (mddev->pers || mddev->raid_disks || !list_empty(&mddev->disks)) { seq_printf(seq, "%s : %sactive", mdname(mddev), mddev->pers ? "" : "in"); @@ -6888,7 +7097,8 @@ static int md_seq_show(struct seq_file *seq, void *v) } sectors = 0; - rdev_for_each(rdev, mddev) { + rcu_read_lock(); + rdev_for_each_rcu(rdev, mddev) { char b[BDEVNAME_SIZE]; seq_printf(seq, " %s[%d]", bdevname(rdev->bdev,b), rdev->desc_nr); @@ -6904,6 +7114,7 @@ static int md_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "(R)"); sectors += rdev->sectors; } + rcu_read_unlock(); if (!list_empty(&mddev->disks)) { if (mddev->pers) @@ -6946,7 +7157,7 @@ static int md_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "\n"); } - mddev_unlock(mddev); + spin_unlock(&mddev->lock); return 0; } @@ -7102,7 +7313,7 @@ void md_write_start(struct mddev *mddev, struct bio *bi) if (mddev->safemode == 1) mddev->safemode = 0; if (mddev->in_sync) { - spin_lock_irq(&mddev->write_lock); + spin_lock(&mddev->lock); if (mddev->in_sync) { mddev->in_sync = 0; set_bit(MD_CHANGE_CLEAN, &mddev->flags); @@ -7110,7 +7321,7 @@ void md_write_start(struct mddev *mddev, struct bio *bi) md_wakeup_thread(mddev->thread); did_change = 1; } - spin_unlock_irq(&mddev->write_lock); + spin_unlock(&mddev->lock); } if (did_change) sysfs_notify_dirent_safe(mddev->sysfs_state); @@ -7148,7 +7359,7 @@ int md_allow_write(struct mddev *mddev) if (!mddev->pers->sync_request) return 0; - spin_lock_irq(&mddev->write_lock); + spin_lock(&mddev->lock); if (mddev->in_sync) { mddev->in_sync = 0; set_bit(MD_CHANGE_CLEAN, &mddev->flags); @@ -7156,11 +7367,11 @@ int md_allow_write(struct mddev *mddev) if (mddev->safemode_delay && mddev->safemode == 0) mddev->safemode = 1; - spin_unlock_irq(&mddev->write_lock); + spin_unlock(&mddev->lock); md_update_sb(mddev, 0); sysfs_notify_dirent_safe(mddev->sysfs_state); } else - spin_unlock_irq(&mddev->write_lock); + spin_unlock(&mddev->lock); if (test_bit(MD_CHANGE_PENDING, &mddev->flags)) return -EAGAIN; @@ -7513,6 +7724,7 @@ void md_do_sync(struct md_thread *thread) skip: set_bit(MD_CHANGE_DEVS, &mddev->flags); + spin_lock(&mddev->lock); if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { /* We completed so min/max setting can be forgotten if used. */ if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) @@ -7521,6 +7733,8 @@ void md_do_sync(struct md_thread *thread) } else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) mddev->resync_min = mddev->curr_resync_completed; mddev->curr_resync = 0; + spin_unlock(&mddev->lock); + wake_up(&resync_wait); set_bit(MD_RECOVERY_DONE, &mddev->recovery); md_wakeup_thread(mddev->thread); @@ -7688,7 +7902,7 @@ void md_check_recovery(struct mddev *mddev) if (!mddev->external) { int did_change = 0; - spin_lock_irq(&mddev->write_lock); + spin_lock(&mddev->lock); if (mddev->safemode && !atomic_read(&mddev->writes_pending) && !mddev->in_sync && @@ -7699,7 +7913,7 @@ void md_check_recovery(struct mddev *mddev) } if (mddev->safemode == 1) mddev->safemode = 0; - spin_unlock_irq(&mddev->write_lock); + spin_unlock(&mddev->lock); if (did_change) sysfs_notify_dirent_safe(mddev->sysfs_state); } @@ -7721,7 +7935,9 @@ void md_check_recovery(struct mddev *mddev) * any transients in the value of "sync_action". */ mddev->curr_resync_completed = 0; + spin_lock(&mddev->lock); set_bit(MD_RECOVERY_RUNNING, &mddev->recovery); + spin_unlock(&mddev->lock); /* Clear some bits that don't mean anything, but * might be left set */ diff --git a/drivers/md/md.h b/drivers/md/md.h index 03cec5bdcaae..318ca8fd430f 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -386,7 +386,18 @@ struct mddev { struct work_struct del_work; /* used for delayed sysfs removal */ - spinlock_t write_lock; + /* "lock" protects: + * flush_bio transition from NULL to !NULL + * rdev superblocks, events + * clearing MD_CHANGE_* + * in_sync - and related safemode and MD_CHANGE changes + * pers (also protected by reconfig_mutex and pending IO). + * clearing ->bitmap + * clearing ->bitmap_info.file + * changing ->resync_{min,max} + * setting MD_RECOVERY_RUNNING (which interacts with resync_{min,max}) + */ + spinlock_t lock; wait_queue_head_t sb_wait; /* for waiting on superblock updates */ atomic_t pending_writes; /* number of active superblock writes */ @@ -439,13 +450,30 @@ struct mddev { void (*sync_super)(struct mddev *mddev, struct md_rdev *rdev); }; -static inline void rdev_dec_pending(struct md_rdev *rdev, struct mddev *mddev) +static inline int __must_check mddev_lock(struct mddev *mddev) { - int faulty = test_bit(Faulty, &rdev->flags); - if (atomic_dec_and_test(&rdev->nr_pending) && faulty) - set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + return mutex_lock_interruptible(&mddev->reconfig_mutex); } +/* Sometimes we need to take the lock in a situation where + * failure due to interrupts is not acceptable. + */ +static inline void mddev_lock_nointr(struct mddev *mddev) +{ + mutex_lock(&mddev->reconfig_mutex); +} + +static inline int mddev_is_locked(struct mddev *mddev) +{ + return mutex_is_locked(&mddev->reconfig_mutex); +} + +static inline int mddev_trylock(struct mddev *mddev) +{ + return mutex_trylock(&mddev->reconfig_mutex); +} +extern void mddev_unlock(struct mddev *mddev); + static inline void md_sync_acct(struct block_device *bdev, unsigned long nr_sectors) { atomic_add(nr_sectors, &bdev->bd_contains->bd_disk->sync_io); @@ -459,7 +487,7 @@ struct md_personality struct module *owner; void (*make_request)(struct mddev *mddev, struct bio *bio); int (*run)(struct mddev *mddev); - int (*stop)(struct mddev *mddev); + void (*free)(struct mddev *mddev, void *priv); void (*status)(struct seq_file *seq, struct mddev *mddev); /* error_handler must set ->faulty and clear ->in_sync * if appropriate, and should abort recovery if needed @@ -490,6 +518,13 @@ struct md_personality * array. */ void *(*takeover) (struct mddev *mddev); + /* congested implements bdi.congested_fn(). + * Will not be called while array is 'suspended' */ + int (*congested)(struct mddev *mddev, int bits); + /* mergeable_bvec is use to implement ->merge_bvec_fn */ + int (*mergeable_bvec)(struct mddev *mddev, + struct bvec_merge_data *bvm, + struct bio_vec *biovec); }; struct md_sysfs_entry { @@ -624,4 +659,14 @@ static inline int mddev_check_plugged(struct mddev *mddev) return !!blk_check_plugged(md_unplug, mddev, sizeof(struct blk_plug_cb)); } + +static inline void rdev_dec_pending(struct md_rdev *rdev, struct mddev *mddev) +{ + int faulty = test_bit(Faulty, &rdev->flags); + if (atomic_dec_and_test(&rdev->nr_pending) && faulty) { + set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + md_wakeup_thread(mddev->thread); + } +} + #endif /* _MD_MD_H */ diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 399272f9c042..ac3ede2bd00e 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -153,15 +153,11 @@ static void multipath_status (struct seq_file *seq, struct mddev *mddev) seq_printf (seq, "]"); } -static int multipath_congested(void *data, int bits) +static int multipath_congested(struct mddev *mddev, int bits) { - struct mddev *mddev = data; struct mpconf *conf = mddev->private; int i, ret = 0; - if (mddev_congested(mddev, bits)) - return 1; - rcu_read_lock(); for (i = 0; i < mddev->raid_disks ; i++) { struct md_rdev *rdev = rcu_dereference(conf->multipaths[i].rdev); @@ -403,7 +399,7 @@ static int multipath_run (struct mddev *mddev) /* * copy the already verified devices into our private MULTIPATH * bookkeeping area. [whatever we allocate in multipath_run(), - * should be freed in multipath_stop()] + * should be freed in multipath_free()] */ conf = kzalloc(sizeof(struct mpconf), GFP_KERNEL); @@ -489,9 +485,6 @@ static int multipath_run (struct mddev *mddev) */ md_set_array_sectors(mddev, multipath_size(mddev, 0, 0)); - mddev->queue->backing_dev_info.congested_fn = multipath_congested; - mddev->queue->backing_dev_info.congested_data = mddev; - if (md_integrity_register(mddev)) goto out_free_conf; @@ -507,17 +500,13 @@ out: return -EIO; } -static int multipath_stop (struct mddev *mddev) +static void multipath_free(struct mddev *mddev, void *priv) { - struct mpconf *conf = mddev->private; + struct mpconf *conf = priv; - md_unregister_thread(&mddev->thread); - blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ mempool_destroy(conf->pool); kfree(conf->multipaths); kfree(conf); - mddev->private = NULL; - return 0; } static struct md_personality multipath_personality = @@ -527,12 +516,13 @@ static struct md_personality multipath_personality = .owner = THIS_MODULE, .make_request = multipath_make_request, .run = multipath_run, - .stop = multipath_stop, + .free = multipath_free, .status = multipath_status, .error_handler = multipath_error, .hot_add_disk = multipath_add_disk, .hot_remove_disk= multipath_remove_disk, .size = multipath_size, + .congested = multipath_congested, }; static int __init multipath_init (void) diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index ba6b85de96d2..a13f738a7b39 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -25,17 +25,13 @@ #include "raid0.h" #include "raid5.h" -static int raid0_congested(void *data, int bits) +static int raid0_congested(struct mddev *mddev, int bits) { - struct mddev *mddev = data; struct r0conf *conf = mddev->private; struct md_rdev **devlist = conf->devlist; int raid_disks = conf->strip_zone[0].nb_dev; int i, ret = 0; - if (mddev_congested(mddev, bits)) - return 1; - for (i = 0; i < raid_disks && !ret ; i++) { struct request_queue *q = bdev_get_queue(devlist[i]->bdev); @@ -263,8 +259,6 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) mdname(mddev), (unsigned long long)smallest->sectors); } - mddev->queue->backing_dev_info.congested_fn = raid0_congested; - mddev->queue->backing_dev_info.congested_data = mddev; /* * now since we have the hard sector sizes, we can make sure @@ -356,17 +350,16 @@ static struct md_rdev *map_sector(struct mddev *mddev, struct strip_zone *zone, /** * raid0_mergeable_bvec -- tell bio layer if two requests can be merged - * @q: request queue + * @mddev: the md device * @bvm: properties of new bio * @biovec: the request that could be merged to it. * * Return amount of bytes we can accept at this offset */ -static int raid0_mergeable_bvec(struct request_queue *q, +static int raid0_mergeable_bvec(struct mddev *mddev, struct bvec_merge_data *bvm, struct bio_vec *biovec) { - struct mddev *mddev = q->queuedata; struct r0conf *conf = mddev->private; sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); sector_t sector_offset = sector; @@ -422,7 +415,7 @@ static sector_t raid0_size(struct mddev *mddev, sector_t sectors, int raid_disks return array_sectors; } -static int raid0_stop(struct mddev *mddev); +static void raid0_free(struct mddev *mddev, void *priv); static int raid0_run(struct mddev *mddev) { @@ -471,26 +464,22 @@ static int raid0_run(struct mddev *mddev) mddev->queue->backing_dev_info.ra_pages = 2* stripe; } - blk_queue_merge_bvec(mddev->queue, raid0_mergeable_bvec); dump_zones(mddev); ret = md_integrity_register(mddev); if (ret) - raid0_stop(mddev); + raid0_free(mddev, conf); return ret; } -static int raid0_stop(struct mddev *mddev) +static void raid0_free(struct mddev *mddev, void *priv) { - struct r0conf *conf = mddev->private; + struct r0conf *conf = priv; - blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ kfree(conf->strip_zone); kfree(conf->devlist); kfree(conf); - mddev->private = NULL; - return 0; } /* @@ -724,11 +713,13 @@ static struct md_personality raid0_personality= .owner = THIS_MODULE, .make_request = raid0_make_request, .run = raid0_run, - .stop = raid0_stop, + .free = raid0_free, .status = raid0_status, .size = raid0_size, .takeover = raid0_takeover, .quiesce = raid0_quiesce, + .congested = raid0_congested, + .mergeable_bvec = raid0_mergeable_bvec, }; static int __init raid0_init (void) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 40b35be34f8d..5dd0c2e59ab9 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -701,11 +701,10 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect return best_disk; } -static int raid1_mergeable_bvec(struct request_queue *q, +static int raid1_mergeable_bvec(struct mddev *mddev, struct bvec_merge_data *bvm, struct bio_vec *biovec) { - struct mddev *mddev = q->queuedata; struct r1conf *conf = mddev->private; sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); int max = biovec->bv_len; @@ -734,7 +733,7 @@ static int raid1_mergeable_bvec(struct request_queue *q, } -int md_raid1_congested(struct mddev *mddev, int bits) +static int raid1_congested(struct mddev *mddev, int bits) { struct r1conf *conf = mddev->private; int i, ret = 0; @@ -763,15 +762,6 @@ int md_raid1_congested(struct mddev *mddev, int bits) rcu_read_unlock(); return ret; } -EXPORT_SYMBOL_GPL(md_raid1_congested); - -static int raid1_congested(void *data, int bits) -{ - struct mddev *mddev = data; - - return mddev_congested(mddev, bits) || - md_raid1_congested(mddev, bits); -} static void flush_pending_writes(struct r1conf *conf) { @@ -2882,7 +2872,7 @@ static struct r1conf *setup_conf(struct mddev *mddev) return ERR_PTR(err); } -static int stop(struct mddev *mddev); +static void raid1_free(struct mddev *mddev, void *priv); static int run(struct mddev *mddev) { struct r1conf *conf; @@ -2904,7 +2894,7 @@ static int run(struct mddev *mddev) /* * copy the already verified devices into our private RAID1 * bookkeeping area. [whatever we allocate in run(), - * should be freed in stop()] + * should be freed in raid1_free()] */ if (mddev->private == NULL) conf = setup_conf(mddev); @@ -2955,10 +2945,6 @@ static int run(struct mddev *mddev) md_set_array_sectors(mddev, raid1_size(mddev, 0, 0)); if (mddev->queue) { - mddev->queue->backing_dev_info.congested_fn = raid1_congested; - mddev->queue->backing_dev_info.congested_data = mddev; - blk_queue_merge_bvec(mddev->queue, raid1_mergeable_bvec); - if (discard_supported) queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue); @@ -2968,37 +2954,23 @@ static int run(struct mddev *mddev) } ret = md_integrity_register(mddev); - if (ret) - stop(mddev); + if (ret) { + md_unregister_thread(&mddev->thread); + raid1_free(mddev, conf); + } return ret; } -static int stop(struct mddev *mddev) +static void raid1_free(struct mddev *mddev, void *priv) { - struct r1conf *conf = mddev->private; - struct bitmap *bitmap = mddev->bitmap; + struct r1conf *conf = priv; - /* wait for behind writes to complete */ - if (bitmap && atomic_read(&bitmap->behind_writes) > 0) { - printk(KERN_INFO "md/raid1:%s: behind writes in progress - waiting to stop.\n", - mdname(mddev)); - /* need to kick something here to make sure I/O goes? */ - wait_event(bitmap->behind_wait, - atomic_read(&bitmap->behind_writes) == 0); - } - - freeze_array(conf, 0); - unfreeze_array(conf); - - md_unregister_thread(&mddev->thread); if (conf->r1bio_pool) mempool_destroy(conf->r1bio_pool); kfree(conf->mirrors); safe_put_page(conf->tmppage); kfree(conf->poolinfo); kfree(conf); - mddev->private = NULL; - return 0; } static int raid1_resize(struct mddev *mddev, sector_t sectors) @@ -3181,7 +3153,7 @@ static struct md_personality raid1_personality = .owner = THIS_MODULE, .make_request = make_request, .run = run, - .stop = stop, + .free = raid1_free, .status = status, .error_handler = error, .hot_add_disk = raid1_add_disk, @@ -3193,6 +3165,8 @@ static struct md_personality raid1_personality = .check_reshape = raid1_reshape, .quiesce = raid1_quiesce, .takeover = raid1_takeover, + .congested = raid1_congested, + .mergeable_bvec = raid1_mergeable_bvec, }; static int __init raid_init(void) diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h index 33bda55ef9f7..14ebb288c1ef 100644 --- a/drivers/md/raid1.h +++ b/drivers/md/raid1.h @@ -170,7 +170,4 @@ struct r1bio { */ #define R1BIO_MadeGood 7 #define R1BIO_WriteError 8 - -extern int md_raid1_congested(struct mddev *mddev, int bits); - #endif diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 32e282f4c83c..b8d76b1fba64 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -674,7 +674,7 @@ static sector_t raid10_find_virt(struct r10conf *conf, sector_t sector, int dev) /** * raid10_mergeable_bvec -- tell bio layer if a two requests can be merged - * @q: request queue + * @mddev: the md device * @bvm: properties of new bio * @biovec: the request that could be merged to it. * @@ -682,11 +682,10 @@ static sector_t raid10_find_virt(struct r10conf *conf, sector_t sector, int dev) * This requires checking for end-of-chunk if near_copies != raid_disks, * and for subordinate merge_bvec_fns if merge_check_needed. */ -static int raid10_mergeable_bvec(struct request_queue *q, +static int raid10_mergeable_bvec(struct mddev *mddev, struct bvec_merge_data *bvm, struct bio_vec *biovec) { - struct mddev *mddev = q->queuedata; struct r10conf *conf = mddev->private; sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); int max; @@ -910,7 +909,7 @@ retry: return rdev; } -int md_raid10_congested(struct mddev *mddev, int bits) +static int raid10_congested(struct mddev *mddev, int bits) { struct r10conf *conf = mddev->private; int i, ret = 0; @@ -934,15 +933,6 @@ int md_raid10_congested(struct mddev *mddev, int bits) rcu_read_unlock(); return ret; } -EXPORT_SYMBOL_GPL(md_raid10_congested); - -static int raid10_congested(void *data, int bits) -{ - struct mddev *mddev = data; - - return mddev_congested(mddev, bits) || - md_raid10_congested(mddev, bits); -} static void flush_pending_writes(struct r10conf *conf) { @@ -3757,8 +3747,6 @@ static int run(struct mddev *mddev) if (mddev->queue) { int stripe = conf->geo.raid_disks * ((mddev->chunk_sectors << 9) / PAGE_SIZE); - mddev->queue->backing_dev_info.congested_fn = raid10_congested; - mddev->queue->backing_dev_info.congested_data = mddev; /* Calculate max read-ahead size. * We need to readahead at least twice a whole stripe.... @@ -3767,7 +3755,6 @@ static int run(struct mddev *mddev) stripe /= conf->geo.near_copies; if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) mddev->queue->backing_dev_info.ra_pages = 2 * stripe; - blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec); } if (md_integrity_register(mddev)) @@ -3811,17 +3798,9 @@ out: return -EIO; } -static int stop(struct mddev *mddev) +static void raid10_free(struct mddev *mddev, void *priv) { - struct r10conf *conf = mddev->private; - - raise_barrier(conf, 0); - lower_barrier(conf); - - md_unregister_thread(&mddev->thread); - if (mddev->queue) - /* the unplug fn references 'conf'*/ - blk_sync_queue(mddev->queue); + struct r10conf *conf = priv; if (conf->r10bio_pool) mempool_destroy(conf->r10bio_pool); @@ -3830,8 +3809,6 @@ static int stop(struct mddev *mddev) kfree(conf->mirrors_old); kfree(conf->mirrors_new); kfree(conf); - mddev->private = NULL; - return 0; } static void raid10_quiesce(struct mddev *mddev, int state) @@ -3895,7 +3872,7 @@ static int raid10_resize(struct mddev *mddev, sector_t sectors) return 0; } -static void *raid10_takeover_raid0(struct mddev *mddev) +static void *raid10_takeover_raid0(struct mddev *mddev, sector_t size, int devs) { struct md_rdev *rdev; struct r10conf *conf; @@ -3905,6 +3882,7 @@ static void *raid10_takeover_raid0(struct mddev *mddev) mdname(mddev)); return ERR_PTR(-EINVAL); } + sector_div(size, devs); /* Set new parameters */ mddev->new_level = 10; @@ -3915,12 +3893,15 @@ static void *raid10_takeover_raid0(struct mddev *mddev) mddev->raid_disks *= 2; /* make sure it will be not marked as dirty */ mddev->recovery_cp = MaxSector; + mddev->dev_sectors = size; conf = setup_conf(mddev); if (!IS_ERR(conf)) { rdev_for_each(rdev, mddev) - if (rdev->raid_disk >= 0) + if (rdev->raid_disk >= 0) { rdev->new_raid_disk = rdev->raid_disk * 2; + rdev->sectors = size; + } conf->barrier = 1; } @@ -3943,7 +3924,9 @@ static void *raid10_takeover(struct mddev *mddev) mdname(mddev)); return ERR_PTR(-EINVAL); } - return raid10_takeover_raid0(mddev); + return raid10_takeover_raid0(mddev, + raid0_conf->strip_zone->zone_end, + raid0_conf->strip_zone->nb_dev); } return ERR_PTR(-EINVAL); } @@ -4713,7 +4696,7 @@ static struct md_personality raid10_personality = .owner = THIS_MODULE, .make_request = make_request, .run = run, - .stop = stop, + .free = raid10_free, .status = status, .error_handler = error, .hot_add_disk = raid10_add_disk, @@ -4727,6 +4710,8 @@ static struct md_personality raid10_personality = .check_reshape = raid10_check_reshape, .start_reshape = raid10_start_reshape, .finish_reshape = raid10_finish_reshape, + .congested = raid10_congested, + .mergeable_bvec = raid10_mergeable_bvec, }; static int __init raid_init(void) diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h index 157d69e83ff4..5ee6473ddc2c 100644 --- a/drivers/md/raid10.h +++ b/drivers/md/raid10.h @@ -150,7 +150,4 @@ enum r10bio_state { */ R10BIO_Previous, }; - -extern int md_raid10_congested(struct mddev *mddev, int bits); - #endif diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index c1b0d52bfcb0..aa76865b804b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -296,12 +296,9 @@ static void do_release_stripe(struct r5conf *conf, struct stripe_head *sh, BUG_ON(atomic_read(&conf->active_stripes)==0); if (test_bit(STRIPE_HANDLE, &sh->state)) { if (test_bit(STRIPE_DELAYED, &sh->state) && - !test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) { + !test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) list_add_tail(&sh->lru, &conf->delayed_list); - if (atomic_read(&conf->preread_active_stripes) - < IO_THRESHOLD) - md_wakeup_thread(conf->mddev->thread); - } else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && + else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && sh->bm_seq - conf->seq_write > 0) list_add_tail(&sh->lru, &conf->bitmap_list); else { @@ -2898,31 +2895,102 @@ static int want_replace(struct stripe_head *sh, int disk_idx) * Returns 1 when no more member devices need to be checked, otherwise returns * 0 to tell the loop in handle_stripe_fill to continue */ -static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s, - int disk_idx, int disks) + +static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, + int disk_idx, int disks) { struct r5dev *dev = &sh->dev[disk_idx]; struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], &sh->dev[s->failed_num[1]] }; + int i; + + + if (test_bit(R5_LOCKED, &dev->flags) || + test_bit(R5_UPTODATE, &dev->flags)) + /* No point reading this as we already have it or have + * decided to get it. + */ + return 0; + + if (dev->toread || + (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags))) + /* We need this block to directly satisfy a request */ + return 1; + + if (s->syncing || s->expanding || + (s->replacing && want_replace(sh, disk_idx))) + /* When syncing, or expanding we read everything. + * When replacing, we need the replaced block. + */ + return 1; + + if ((s->failed >= 1 && fdev[0]->toread) || + (s->failed >= 2 && fdev[1]->toread)) + /* If we want to read from a failed device, then + * we need to actually read every other device. + */ + return 1; + + /* Sometimes neither read-modify-write nor reconstruct-write + * cycles can work. In those cases we read every block we + * can. Then the parity-update is certain to have enough to + * work with. + * This can only be a problem when we need to write something, + * and some device has failed. If either of those tests + * fail we need look no further. + */ + if (!s->failed || !s->to_write) + return 0; + + if (test_bit(R5_Insync, &dev->flags) && + !test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) + /* Pre-reads at not permitted until after short delay + * to gather multiple requests. However if this + * device is no Insync, the block could only be be computed + * and there is no need to delay that. + */ + return 0; + + for (i = 0; i < s->failed; i++) { + if (fdev[i]->towrite && + !test_bit(R5_UPTODATE, &fdev[i]->flags) && + !test_bit(R5_OVERWRITE, &fdev[i]->flags)) + /* If we have a partial write to a failed + * device, then we will need to reconstruct + * the content of that device, so all other + * devices must be read. + */ + return 1; + } + + /* If we are forced to do a reconstruct-write, either because + * the current RAID6 implementation only supports that, or + * or because parity cannot be trusted and we are currently + * recovering it, there is extra need to be careful. + * If one of the devices that we would need to read, because + * it is not being overwritten (and maybe not written at all) + * is missing/faulty, then we need to read everything we can. + */ + if (sh->raid_conf->level != 6 && + sh->sector < sh->raid_conf->mddev->recovery_cp) + /* reconstruct-write isn't being forced */ + return 0; + for (i = 0; i < s->failed; i++) { + if (!test_bit(R5_UPTODATE, &fdev[i]->flags) && + !test_bit(R5_OVERWRITE, &fdev[i]->flags)) + return 1; + } + + return 0; +} + +static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s, + int disk_idx, int disks) +{ + struct r5dev *dev = &sh->dev[disk_idx]; /* is the data in this block needed, and can we get it? */ - if (!test_bit(R5_LOCKED, &dev->flags) && - !test_bit(R5_UPTODATE, &dev->flags) && - (dev->toread || - (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) || - s->syncing || s->expanding || - (s->replacing && want_replace(sh, disk_idx)) || - (s->failed >= 1 && fdev[0]->toread) || - (s->failed >= 2 && fdev[1]->toread) || - (sh->raid_conf->level <= 5 && s->failed && fdev[0]->towrite && - (!test_bit(R5_Insync, &dev->flags) || test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) && - !test_bit(R5_OVERWRITE, &fdev[0]->flags)) || - ((sh->raid_conf->level == 6 || - sh->sector >= sh->raid_conf->mddev->recovery_cp) - && s->failed && s->to_write && - (s->to_write - s->non_overwrite < - sh->raid_conf->raid_disks - sh->raid_conf->max_degraded) && - (!test_bit(R5_Insync, &dev->flags) || test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))))) { + if (need_this_block(sh, s, disk_idx, disks)) { /* we would like to get this block, possibly by computing it, * otherwise read it if the backing disk is insync */ @@ -3195,6 +3263,11 @@ static void handle_stripe_dirtying(struct r5conf *conf, (unsigned long long)sh->sector, rcw, qread, test_bit(STRIPE_DELAYED, &sh->state)); } + + if (rcw > disks && rmw > disks && + !test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) + set_bit(STRIPE_DELAYED, &sh->state); + /* now if nothing is locked, and if we have enough data, * we can start a write request */ @@ -4076,7 +4149,7 @@ static void activate_bit_delay(struct r5conf *conf, } } -int md_raid5_congested(struct mddev *mddev, int bits) +static int raid5_congested(struct mddev *mddev, int bits) { struct r5conf *conf = mddev->private; @@ -4093,24 +4166,14 @@ int md_raid5_congested(struct mddev *mddev, int bits) return 0; } -EXPORT_SYMBOL_GPL(md_raid5_congested); - -static int raid5_congested(void *data, int bits) -{ - struct mddev *mddev = data; - - return mddev_congested(mddev, bits) || - md_raid5_congested(mddev, bits); -} /* We want read requests to align with chunks where possible, * but write requests don't need to. */ -static int raid5_mergeable_bvec(struct request_queue *q, +static int raid5_mergeable_bvec(struct mddev *mddev, struct bvec_merge_data *bvm, struct bio_vec *biovec) { - struct mddev *mddev = q->queuedata; sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); int max; unsigned int chunk_sectors = mddev->chunk_sectors; @@ -5291,11 +5354,14 @@ static void raid5d(struct md_thread *thread) static ssize_t raid5_show_stripe_cache_size(struct mddev *mddev, char *page) { - struct r5conf *conf = mddev->private; + struct r5conf *conf; + int ret = 0; + spin_lock(&mddev->lock); + conf = mddev->private; if (conf) - return sprintf(page, "%d\n", conf->max_nr_stripes); - else - return 0; + ret = sprintf(page, "%d\n", conf->max_nr_stripes); + spin_unlock(&mddev->lock); + return ret; } int @@ -5334,21 +5400,25 @@ EXPORT_SYMBOL(raid5_set_cache_size); static ssize_t raid5_store_stripe_cache_size(struct mddev *mddev, const char *page, size_t len) { - struct r5conf *conf = mddev->private; + struct r5conf *conf; unsigned long new; int err; if (len >= PAGE_SIZE) return -EINVAL; - if (!conf) - return -ENODEV; - if (kstrtoul(page, 10, &new)) return -EINVAL; - err = raid5_set_cache_size(mddev, new); + err = mddev_lock(mddev); if (err) return err; - return len; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else + err = raid5_set_cache_size(mddev, new); + mddev_unlock(mddev); + + return err ?: len; } static struct md_sysfs_entry @@ -5359,29 +5429,40 @@ raid5_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR, static ssize_t raid5_show_preread_threshold(struct mddev *mddev, char *page) { - struct r5conf *conf = mddev->private; + struct r5conf *conf; + int ret = 0; + spin_lock(&mddev->lock); + conf = mddev->private; if (conf) - return sprintf(page, "%d\n", conf->bypass_threshold); - else - return 0; + ret = sprintf(page, "%d\n", conf->bypass_threshold); + spin_unlock(&mddev->lock); + return ret; } static ssize_t raid5_store_preread_threshold(struct mddev *mddev, const char *page, size_t len) { - struct r5conf *conf = mddev->private; + struct r5conf *conf; unsigned long new; + int err; + if (len >= PAGE_SIZE) return -EINVAL; - if (!conf) - return -ENODEV; - if (kstrtoul(page, 10, &new)) return -EINVAL; - if (new > conf->max_nr_stripes) - return -EINVAL; - conf->bypass_threshold = new; - return len; + + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else if (new > conf->max_nr_stripes) + err = -EINVAL; + else + conf->bypass_threshold = new; + mddev_unlock(mddev); + return err ?: len; } static struct md_sysfs_entry @@ -5393,39 +5474,48 @@ raid5_preread_bypass_threshold = __ATTR(preread_bypass_threshold, static ssize_t raid5_show_skip_copy(struct mddev *mddev, char *page) { - struct r5conf *conf = mddev->private; + struct r5conf *conf; + int ret = 0; + spin_lock(&mddev->lock); + conf = mddev->private; if (conf) - return sprintf(page, "%d\n", conf->skip_copy); - else - return 0; + ret = sprintf(page, "%d\n", conf->skip_copy); + spin_unlock(&mddev->lock); + return ret; } static ssize_t raid5_store_skip_copy(struct mddev *mddev, const char *page, size_t len) { - struct r5conf *conf = mddev->private; + struct r5conf *conf; unsigned long new; + int err; + if (len >= PAGE_SIZE) return -EINVAL; - if (!conf) - return -ENODEV; - if (kstrtoul(page, 10, &new)) return -EINVAL; new = !!new; - if (new == conf->skip_copy) - return len; - mddev_suspend(mddev); - conf->skip_copy = new; - if (new) - mddev->queue->backing_dev_info.capabilities |= - BDI_CAP_STABLE_WRITES; - else - mddev->queue->backing_dev_info.capabilities &= - ~BDI_CAP_STABLE_WRITES; - mddev_resume(mddev); - return len; + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else if (new != conf->skip_copy) { + mddev_suspend(mddev); + conf->skip_copy = new; + if (new) + mddev->queue->backing_dev_info.capabilities |= + BDI_CAP_STABLE_WRITES; + else + mddev->queue->backing_dev_info.capabilities &= + ~BDI_CAP_STABLE_WRITES; + mddev_resume(mddev); + } + mddev_unlock(mddev); + return err ?: len; } static struct md_sysfs_entry @@ -5449,11 +5539,14 @@ raid5_stripecache_active = __ATTR_RO(stripe_cache_active); static ssize_t raid5_show_group_thread_cnt(struct mddev *mddev, char *page) { - struct r5conf *conf = mddev->private; + struct r5conf *conf; + int ret = 0; + spin_lock(&mddev->lock); + conf = mddev->private; if (conf) - return sprintf(page, "%d\n", conf->worker_cnt_per_group); - else - return 0; + ret = sprintf(page, "%d\n", conf->worker_cnt_per_group); + spin_unlock(&mddev->lock); + return ret; } static int alloc_thread_groups(struct r5conf *conf, int cnt, @@ -5463,7 +5556,7 @@ static int alloc_thread_groups(struct r5conf *conf, int cnt, static ssize_t raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len) { - struct r5conf *conf = mddev->private; + struct r5conf *conf; unsigned long new; int err; struct r5worker_group *new_groups, *old_groups; @@ -5471,41 +5564,41 @@ raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len) if (len >= PAGE_SIZE) return -EINVAL; - if (!conf) - return -ENODEV; - if (kstrtoul(page, 10, &new)) return -EINVAL; - if (new == conf->worker_cnt_per_group) - return len; - - mddev_suspend(mddev); - - old_groups = conf->worker_groups; - if (old_groups) - flush_workqueue(raid5_wq); - - err = alloc_thread_groups(conf, new, - &group_cnt, &worker_cnt_per_group, - &new_groups); - if (!err) { - spin_lock_irq(&conf->device_lock); - conf->group_cnt = group_cnt; - conf->worker_cnt_per_group = worker_cnt_per_group; - conf->worker_groups = new_groups; - spin_unlock_irq(&conf->device_lock); - - if (old_groups) - kfree(old_groups[0].workers); - kfree(old_groups); - } - - mddev_resume(mddev); - + err = mddev_lock(mddev); if (err) return err; - return len; + conf = mddev->private; + if (!conf) + err = -ENODEV; + else if (new != conf->worker_cnt_per_group) { + mddev_suspend(mddev); + + old_groups = conf->worker_groups; + if (old_groups) + flush_workqueue(raid5_wq); + + err = alloc_thread_groups(conf, new, + &group_cnt, &worker_cnt_per_group, + &new_groups); + if (!err) { + spin_lock_irq(&conf->device_lock); + conf->group_cnt = group_cnt; + conf->worker_cnt_per_group = worker_cnt_per_group; + conf->worker_groups = new_groups; + spin_unlock_irq(&conf->device_lock); + + if (old_groups) + kfree(old_groups[0].workers); + kfree(old_groups); + } + mddev_resume(mddev); + } + mddev_unlock(mddev); + + return err ?: len; } static struct md_sysfs_entry @@ -6173,11 +6266,6 @@ static int run(struct mddev *mddev) if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) mddev->queue->backing_dev_info.ra_pages = 2 * stripe; - blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec); - - mddev->queue->backing_dev_info.congested_data = mddev; - mddev->queue->backing_dev_info.congested_fn = raid5_congested; - chunk_size = mddev->chunk_sectors << 9; blk_queue_io_min(mddev->queue, chunk_size); blk_queue_io_opt(mddev->queue, chunk_size * @@ -6255,17 +6343,12 @@ abort: return -EIO; } -static int stop(struct mddev *mddev) +static void raid5_free(struct mddev *mddev, void *priv) { - struct r5conf *conf = mddev->private; + struct r5conf *conf = priv; - md_unregister_thread(&mddev->thread); - if (mddev->queue) - mddev->queue->backing_dev_info.congested_fn = NULL; free_conf(conf); - mddev->private = NULL; mddev->to_remove = &raid5_attrs_group; - return 0; } static void status(struct seq_file *seq, struct mddev *mddev) @@ -7039,7 +7122,7 @@ static struct md_personality raid6_personality = .owner = THIS_MODULE, .make_request = make_request, .run = run, - .stop = stop, + .free = raid5_free, .status = status, .error_handler = error, .hot_add_disk = raid5_add_disk, @@ -7053,6 +7136,8 @@ static struct md_personality raid6_personality = .finish_reshape = raid5_finish_reshape, .quiesce = raid5_quiesce, .takeover = raid6_takeover, + .congested = raid5_congested, + .mergeable_bvec = raid5_mergeable_bvec, }; static struct md_personality raid5_personality = { @@ -7061,7 +7146,7 @@ static struct md_personality raid5_personality = .owner = THIS_MODULE, .make_request = make_request, .run = run, - .stop = stop, + .free = raid5_free, .status = status, .error_handler = error, .hot_add_disk = raid5_add_disk, @@ -7075,6 +7160,8 @@ static struct md_personality raid5_personality = .finish_reshape = raid5_finish_reshape, .quiesce = raid5_quiesce, .takeover = raid5_takeover, + .congested = raid5_congested, + .mergeable_bvec = raid5_mergeable_bvec, }; static struct md_personality raid4_personality = @@ -7084,7 +7171,7 @@ static struct md_personality raid4_personality = .owner = THIS_MODULE, .make_request = make_request, .run = run, - .stop = stop, + .free = raid5_free, .status = status, .error_handler = error, .hot_add_disk = raid5_add_disk, @@ -7098,6 +7185,8 @@ static struct md_personality raid4_personality = .finish_reshape = raid5_finish_reshape, .quiesce = raid5_quiesce, .takeover = raid4_takeover, + .congested = raid5_congested, + .mergeable_bvec = raid5_mergeable_bvec, }; static int __init raid5_init(void) diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index d59f5ca743cd..983e18a83db1 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -558,7 +558,6 @@ static inline int algorithm_is_DDF(int layout) return layout >= 8 && layout <= 10; } -extern int md_raid5_congested(struct mddev *mddev, int bits); extern void md_raid5_kick_device(struct r5conf *conf); extern int raid5_set_cache_size(struct mddev *mddev, int size); #endif diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index b85f88c8ddbd..21154dd87b0b 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -8,10 +8,6 @@ comment "common driver options" config VIDEO_CX2341X tristate -config VIDEO_BTCX - depends on PCI - tristate - config VIDEO_TVEEPROM tristate depends on I2C diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index d208de3b7cc0..89b795df2cdd 100644 --- a/drivers/media/common/Makefile +++ b/drivers/media/common/Makefile @@ -1,5 +1,4 @@ obj-y += b2c2/ saa7146/ siano/ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o -obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o diff --git a/drivers/media/common/btcx-risc.h b/drivers/media/common/btcx-risc.h index f8bc6e8e7b51..03583ef90506 100644 --- a/drivers/media/common/btcx-risc.h +++ b/drivers/media/common/btcx-risc.h @@ -26,9 +26,3 @@ void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); void btcx_calc_skips(int line, int width, int *maxy, struct btcx_skiplist *skips, unsigned int *nskips, const struct v4l2_clip *clips, unsigned int nclips); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index e4041f074909..686d3277dad1 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -68,13 +68,6 @@ #include "dvb_demux.h" #include "dvb_net.h" -static int dvb_net_debug; -module_param(dvb_net_debug, int, 0444); -MODULE_PARM_DESC(dvb_net_debug, "enable debug messages"); - -#define dprintk(x...) do { if (dvb_net_debug) printk(x); } while (0) - - static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt ) { unsigned int j; @@ -90,36 +83,9 @@ static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt ) #ifdef ULE_DEBUG -#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" -#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5] - -#define isprint(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) - -static void hexdump( const unsigned char *buf, unsigned short len ) +static void hexdump(const unsigned char *buf, unsigned short len) { - char str[80], octet[10]; - int ofs, i, l; - - for (ofs = 0; ofs < len; ofs += 16) { - sprintf( str, "%03d: ", ofs ); - - for (i = 0; i < 16; i++) { - if ((i + ofs) < len) - sprintf( octet, "%02x ", buf[ofs + i] ); - else - strcpy( octet, " " ); - - strcat( str, octet ); - } - strcat( str, " " ); - l = strlen( str ); - - for (i = 0; (i < 16) && ((i + ofs) < len); i++) - str[l++] = isprint( buf[ofs + i] ) ? buf[ofs + i] : '.'; - - str[l] = '\0'; - printk( KERN_WARNING "%s\n", str ); - } + print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true); } #endif @@ -315,9 +281,9 @@ static int handle_ule_extensions( struct dvb_net_priv *p ) return l; /* Stop extension header processing and discard SNDU. */ total_ext_len += l; #ifdef ULE_DEBUG - dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, " - "l=%i, total_ext_len=%i\n", p->ule_next_hdr, - (int) p->ule_sndu_type, l, total_ext_len); + pr_debug("ule_next_hdr=%p, ule_sndu_type=%i, l=%i, total_ext_len=%i\n", + p->ule_next_hdr, (int)p->ule_sndu_type, + l, total_ext_len); #endif } while (p->ule_sndu_type < ETH_P_802_3_MIN); @@ -700,8 +666,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (drop) { #ifdef ULE_DEBUG - dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n", - MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr)); + netdev_dbg(dev, "Dropping SNDU: MAC destination address does not match: dest addr: %pM, dev addr: %pM\n", + priv->ule_skb->data, dev->dev_addr); #endif dev_kfree_skb(priv->ule_skb); goto sndu_done; @@ -964,8 +930,7 @@ static int dvb_net_filter_sec_set(struct net_device *dev, (*secfilter)->filter_mask[10] = mac_mask[1]; (*secfilter)->filter_mask[11]=mac_mask[0]; - dprintk("%s: filter mac=%pM\n", dev->name, mac); - dprintk("%s: filter mask=%pM\n", dev->name, mac_mask); + netdev_dbg(dev, "filter mac=%pM mask=%pM\n", mac, mac_mask); return 0; } @@ -977,7 +942,7 @@ static int dvb_net_feed_start(struct net_device *dev) struct dmx_demux *demux = priv->demux; unsigned char *mac = (unsigned char *) dev->dev_addr; - dprintk("%s: rx_mode %i\n", __func__, priv->rx_mode); + netdev_dbg(dev, "rx_mode %i\n", priv->rx_mode); mutex_lock(&priv->mutex); if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0]) printk("%s: BUG %d\n", __func__, __LINE__); @@ -987,7 +952,7 @@ static int dvb_net_feed_start(struct net_device *dev) priv->tsfeed = NULL; if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { - dprintk("%s: alloc secfeed\n", __func__); + netdev_dbg(dev, "alloc secfeed\n"); ret=demux->allocate_section_feed(demux, &priv->secfeed, dvb_net_sec_callback); if (ret<0) { @@ -1005,38 +970,38 @@ static int dvb_net_feed_start(struct net_device *dev) } if (priv->rx_mode != RX_MODE_PROMISC) { - dprintk("%s: set secfilter\n", __func__); + netdev_dbg(dev, "set secfilter\n"); dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_normal); } switch (priv->rx_mode) { case RX_MODE_MULTI: for (i = 0; i < priv->multi_num; i++) { - dprintk("%s: set multi_secfilter[%d]\n", __func__, i); + netdev_dbg(dev, "set multi_secfilter[%d]\n", i); dvb_net_filter_sec_set(dev, &priv->multi_secfilter[i], priv->multi_macs[i], mask_normal); } break; case RX_MODE_ALL_MULTI: priv->multi_num=1; - dprintk("%s: set multi_secfilter[0]\n", __func__); + netdev_dbg(dev, "set multi_secfilter[0]\n"); dvb_net_filter_sec_set(dev, &priv->multi_secfilter[0], mac_allmulti, mask_allmulti); break; case RX_MODE_PROMISC: priv->multi_num=0; - dprintk("%s: set secfilter\n", __func__); + netdev_dbg(dev, "set secfilter\n"); dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc); break; } - dprintk("%s: start filtering\n", __func__); + netdev_dbg(dev, "start filtering\n"); priv->secfeed->start_filtering(priv->secfeed); } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { struct timespec timeout = { 0, 10000000 }; // 10 msec /* we have payloads encapsulated in TS */ - dprintk("%s: alloc tsfeed\n", __func__); + netdev_dbg(dev, "alloc tsfeed\n"); ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback); if (ret < 0) { printk("%s: could not allocate ts feed\n", dev->name); @@ -1060,7 +1025,7 @@ static int dvb_net_feed_start(struct net_device *dev) goto error; } - dprintk("%s: start filtering\n", __func__); + netdev_dbg(dev, "start filtering\n"); priv->tsfeed->start_filtering(priv->tsfeed); } else ret = -EINVAL; @@ -1075,17 +1040,16 @@ static int dvb_net_feed_stop(struct net_device *dev) struct dvb_net_priv *priv = netdev_priv(dev); int i, ret = 0; - dprintk("%s\n", __func__); mutex_lock(&priv->mutex); if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { if (priv->secfeed) { if (priv->secfeed->is_filtering) { - dprintk("%s: stop secfeed\n", __func__); + netdev_dbg(dev, "stop secfeed\n"); priv->secfeed->stop_filtering(priv->secfeed); } if (priv->secfilter) { - dprintk("%s: release secfilter\n", __func__); + netdev_dbg(dev, "release secfilter\n"); priv->secfeed->release_filter(priv->secfeed, priv->secfilter); priv->secfilter=NULL; @@ -1093,8 +1057,8 @@ static int dvb_net_feed_stop(struct net_device *dev) for (i=0; imulti_num; i++) { if (priv->multi_secfilter[i]) { - dprintk("%s: release multi_filter[%d]\n", - __func__, i); + netdev_dbg(dev, "release multi_filter[%d]\n", + i); priv->secfeed->release_filter(priv->secfeed, priv->multi_secfilter[i]); priv->multi_secfilter[i] = NULL; @@ -1108,7 +1072,7 @@ static int dvb_net_feed_stop(struct net_device *dev) } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { if (priv->tsfeed) { if (priv->tsfeed->is_filtering) { - dprintk("%s: stop tsfeed\n", __func__); + netdev_dbg(dev, "stop tsfeed\n"); priv->tsfeed->stop_filtering(priv->tsfeed); } priv->demux->release_ts_feed(priv->demux, priv->tsfeed); @@ -1148,16 +1112,16 @@ static void wq_set_multicast_list (struct work_struct *work) netif_addr_lock_bh(dev); if (dev->flags & IFF_PROMISC) { - dprintk("%s: promiscuous mode\n", dev->name); + netdev_dbg(dev, "promiscuous mode\n"); priv->rx_mode = RX_MODE_PROMISC; } else if ((dev->flags & IFF_ALLMULTI)) { - dprintk("%s: allmulti mode\n", dev->name); + netdev_dbg(dev, "allmulti mode\n"); priv->rx_mode = RX_MODE_ALL_MULTI; } else if (!netdev_mc_empty(dev)) { struct netdev_hw_addr *ha; - dprintk("%s: set_mc_list, %d entries\n", - dev->name, netdev_mc_count(dev)); + netdev_dbg(dev, "set_mc_list, %d entries\n", + netdev_mc_count(dev)); priv->rx_mode = RX_MODE_MULTI; priv->multi_num = 0; diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 6c75418222e2..bb76727d924e 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -443,7 +443,8 @@ config DVB_CXD2820R config DVB_RTL2830 tristate "Realtek RTL2830 DVB-T" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && I2C_MUX + select REGMAP default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. @@ -451,6 +452,7 @@ config DVB_RTL2830 config DVB_RTL2832 tristate "Realtek RTL2832 DVB-T" depends on DVB_CORE && I2C && I2C_MUX + select REGMAP default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. diff --git a/drivers/media/dvb-frontends/au8522.h b/drivers/media/dvb-frontends/au8522.h index 83fe9a615619..612251958855 100644 --- a/drivers/media/dvb-frontends/au8522.h +++ b/drivers/media/dvb-frontends/au8522.h @@ -91,8 +91,3 @@ enum au8522_audio_input { }; #endif /* __AU8522_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 61e31f2d2f71..8c6663b6399d 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -1263,7 +1263,8 @@ static int dib8000_agc_startup(struct dvb_frontend *fe) struct dib8000_state *state = fe->demodulator_priv; enum frontend_tune_state *tune_state = &state->tune_state; int ret = 0; - u16 reg, upd_demod_gain_period = 0x8000; + u16 reg; + u32 upd_demod_gain_period = 0x8000; switch (*tune_state) { case CT_AGC_START: diff --git a/drivers/media/dvb-frontends/hd29l2.c b/drivers/media/dvb-frontends/hd29l2.c index d7b9d549156d..67c8e6df42e8 100644 --- a/drivers/media/dvb-frontends/hd29l2.c +++ b/drivers/media/dvb-frontends/hd29l2.c @@ -22,20 +22,24 @@ #include "hd29l2_priv.h" +#define HD29L2_MAX_LEN (3) + /* write multiple registers */ static int hd29l2_wr_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len) { int ret; - u8 buf[2 + len]; + u8 buf[2 + HD29L2_MAX_LEN]; struct i2c_msg msg[1] = { { .addr = priv->cfg.i2c_addr, .flags = 0, - .len = sizeof(buf), + .len = 2 + len, .buf = buf, } }; + if (len > HD29L2_MAX_LEN) + return -EINVAL; buf[0] = 0x00; buf[1] = reg; memcpy(&buf[2], val, len); @@ -118,7 +122,7 @@ static int hd29l2_wr_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 val, u8 mask) } /* read single register with mask */ -int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask) +static int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask) { int ret, i; u8 tmp; diff --git a/drivers/media/dvb-frontends/lg2160.c b/drivers/media/dvb-frontends/lg2160.c index 5fd14f840ab0..99efeba3c31a 100644 --- a/drivers/media/dvb-frontends/lg2160.c +++ b/drivers/media/dvb-frontends/lg2160.c @@ -1456,9 +1456,3 @@ MODULE_DESCRIPTION("LG Electronics LG216x ATSC/MH Demodulator Driver"); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); MODULE_VERSION("0.3"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/lgdt3305.c b/drivers/media/dvb-frontends/lgdt3305.c index 92c891a571ab..d08570af1c10 100644 --- a/drivers/media/dvb-frontends/lgdt3305.c +++ b/drivers/media/dvb-frontends/lgdt3305.c @@ -236,12 +236,13 @@ static inline int lgdt3305_mpeg_mode(struct lgdt3305_state *state, return lgdt3305_set_reg_bit(state, LGDT3305_TP_CTRL_1, 5, mode); } -static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state, - enum lgdt3305_tp_clock_edge edge, - enum lgdt3305_tp_valid_polarity valid) +static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state) { u8 val; int ret; + enum lgdt3305_tp_clock_edge edge = state->cfg->tpclk_edge; + enum lgdt3305_tp_clock_mode mode = state->cfg->tpclk_mode; + enum lgdt3305_tp_valid_polarity valid = state->cfg->tpvalid_polarity; lg_dbg("edge = %d, valid = %d\n", edge, valid); @@ -253,6 +254,8 @@ static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state, if (edge) val |= 0x08; + if (mode) + val |= 0x40; if (valid) val |= 0x01; @@ -740,9 +743,7 @@ static int lgdt3304_set_parameters(struct dvb_frontend *fe) goto fail; /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */ - ret = lgdt3305_mpeg_mode_polarity(state, - state->cfg->tpclk_edge, - state->cfg->tpvalid_polarity); + ret = lgdt3305_mpeg_mode_polarity(state); fail: return ret; } @@ -806,9 +807,7 @@ static int lgdt3305_set_parameters(struct dvb_frontend *fe) goto fail; /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */ - ret = lgdt3305_mpeg_mode_polarity(state, - state->cfg->tpclk_edge, - state->cfg->tpvalid_polarity); + ret = lgdt3305_mpeg_mode_polarity(state); fail: return ret; } @@ -1215,9 +1214,3 @@ MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver"); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); MODULE_VERSION("0.2"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/lgdt3305.h b/drivers/media/dvb-frontends/lgdt3305.h index d9ab556c1b27..9c03e530e01b 100644 --- a/drivers/media/dvb-frontends/lgdt3305.h +++ b/drivers/media/dvb-frontends/lgdt3305.h @@ -37,6 +37,11 @@ enum lgdt3305_tp_clock_edge { LGDT3305_TPCLK_FALLING_EDGE = 1, }; +enum lgdt3305_tp_clock_mode { + LGDT3305_TPCLK_GATED = 0, + LGDT3305_TPCLK_FIXED = 1, +}; + enum lgdt3305_tp_valid_polarity { LGDT3305_TP_VALID_LOW = 0, LGDT3305_TP_VALID_HIGH = 1, @@ -70,6 +75,7 @@ struct lgdt3305_config { enum lgdt3305_mpeg_mode mpeg_mode; enum lgdt3305_tp_clock_edge tpclk_edge; + enum lgdt3305_tp_clock_mode tpclk_mode; enum lgdt3305_tp_valid_polarity tpvalid_polarity; enum lgdt_demod_chip_type demod_chip; }; diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c index e046622df0e4..2e1a61893fc1 100644 --- a/drivers/media/dvb-frontends/lgdt330x.c +++ b/drivers/media/dvb-frontends/lgdt330x.c @@ -823,9 +823,3 @@ MODULE_AUTHOR("Wilson Michaels"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(lgdt330x_attach); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/lgdt330x.h b/drivers/media/dvb-frontends/lgdt330x.h index ca0eab562e1e..8bb332219fc4 100644 --- a/drivers/media/dvb-frontends/lgdt330x.h +++ b/drivers/media/dvb-frontends/lgdt330x.h @@ -65,9 +65,3 @@ static inline struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* #endif // CONFIG_DVB_LGDT330X #endif /* LGDT330X_H */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/lgdt330x_priv.h b/drivers/media/dvb-frontends/lgdt330x_priv.h index 38c76695abfe..1922f09a02d0 100644 --- a/drivers/media/dvb-frontends/lgdt330x_priv.h +++ b/drivers/media/dvb-frontends/lgdt330x_priv.h @@ -69,9 +69,3 @@ enum I2C_REG { }; #endif /* _LGDT330X_PRIV_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index e6f165a5b90d..8f54c39ca63f 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -22,10 +22,6 @@ #define NUM_LAYERS 3 -static int debug = 1; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); - enum mb86a20s_bandwidth { MB86A20S_13SEG = 0, MB86A20S_13SEG_PARTIAL = 1, diff --git a/drivers/media/dvb-frontends/mn88472.h b/drivers/media/dvb-frontends/mn88472.h index da4558bce60f..e4e0b80d3091 100644 --- a/drivers/media/dvb-frontends/mn88472.h +++ b/drivers/media/dvb-frontends/mn88472.h @@ -33,6 +33,12 @@ struct mn88472_config { * DVB frontend. */ struct dvb_frontend **fe; + + /* + * Xtal frequency. + * Hz + */ + u32 xtal; }; #endif diff --git a/drivers/media/dvb-frontends/nxt200x.h b/drivers/media/dvb-frontends/nxt200x.h index b518d545609e..e38d01fb6c2b 100644 --- a/drivers/media/dvb-frontends/nxt200x.h +++ b/drivers/media/dvb-frontends/nxt200x.h @@ -55,9 +55,3 @@ static inline struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* c #endif // CONFIG_DVB_NXT200X #endif /* NXT200X_H */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/or51132.c b/drivers/media/dvb-frontends/or51132.c index 5ef921823c15..cbbd259eacfe 100644 --- a/drivers/media/dvb-frontends/or51132.c +++ b/drivers/media/dvb-frontends/or51132.c @@ -623,9 +623,3 @@ MODULE_AUTHOR("Trent Piepho"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(or51132_attach); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/or51132.h b/drivers/media/dvb-frontends/or51132.h index 938958386cb1..cdb5be3c65d6 100644 --- a/drivers/media/dvb-frontends/or51132.h +++ b/drivers/media/dvb-frontends/or51132.h @@ -47,9 +47,3 @@ static inline struct dvb_frontend* or51132_attach(const struct or51132_config* c #endif // CONFIG_DVB_OR51132 #endif // OR51132_H - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c index 50e8b63e5169..e1b8df62bd59 100644 --- a/drivers/media/dvb-frontends/rtl2830.c +++ b/drivers/media/dvb-frontends/rtl2830.c @@ -13,261 +13,154 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU 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. - */ - - -/* - * Driver implements own I2C-adapter for tuner I2C access. That's since chip - * have unusual I2C-gate control which closes gate automatically after each - * I2C transfer. Using own I2C adapter we can workaround that. */ #include "rtl2830_priv.h" -/* Max transfer size done by I2C transfer functions */ -#define MAX_XFER_SIZE 64 - -/* write multiple hardware registers */ -static int rtl2830_wr(struct rtl2830_priv *priv, u8 reg, const u8 *val, int len) +/* Our regmap is bypassing I2C adapter lock, thus we do it! */ +static int rtl2830_bulk_write(struct i2c_client *client, unsigned int reg, + const void *val, size_t val_count) { + struct rtl2830_dev *dev = i2c_get_clientdata(client); int ret; - u8 buf[MAX_XFER_SIZE]; - struct i2c_msg msg[1] = { - { - .addr = priv->cfg.i2c_addr, - .flags = 0, - .len = 1 + len, - .buf = buf, - } - }; - if (1 + len > sizeof(buf)) { - dev_warn(&priv->i2c->dev, - "%s: i2c wr reg=%04x: len=%d is too big!\n", - KBUILD_MODNAME, reg, len); - return -EINVAL; - } - - buf[0] = reg; - memcpy(&buf[1], val, len); - - ret = i2c_transfer(priv->i2c, msg, 1); - if (ret == 1) { - ret = 0; - } else { - dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } + i2c_lock_adapter(client->adapter); + ret = regmap_bulk_write(dev->regmap, reg, val, val_count); + i2c_unlock_adapter(client->adapter); return ret; } -/* read multiple hardware registers */ -static int rtl2830_rd(struct rtl2830_priv *priv, u8 reg, u8 *val, int len) +static int rtl2830_update_bits(struct i2c_client *client, unsigned int reg, + unsigned int mask, unsigned int val) { + struct rtl2830_dev *dev = i2c_get_clientdata(client); int ret; - struct i2c_msg msg[2] = { - { - .addr = priv->cfg.i2c_addr, - .flags = 0, - .len = 1, - .buf = ®, - }, { - .addr = priv->cfg.i2c_addr, - .flags = I2C_M_RD, - .len = len, - .buf = val, - } - }; - ret = i2c_transfer(priv->i2c, msg, 2); - if (ret == 2) { - ret = 0; - } else { - dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } + i2c_lock_adapter(client->adapter); + ret = regmap_update_bits(dev->regmap, reg, mask, val); + i2c_unlock_adapter(client->adapter); return ret; } -/* write multiple registers */ -static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, const u8 *val, - int len) +static int rtl2830_bulk_read(struct i2c_client *client, unsigned int reg, + void *val, size_t val_count) { + struct rtl2830_dev *dev = i2c_get_clientdata(client); int ret; - u8 reg2 = (reg >> 0) & 0xff; - u8 page = (reg >> 8) & 0xff; - /* switch bank if needed */ - if (page != priv->page) { - ret = rtl2830_wr(priv, 0x00, &page, 1); - if (ret) - return ret; - - priv->page = page; - } - - return rtl2830_wr(priv, reg2, val, len); -} - -/* read multiple registers */ -static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len) -{ - int ret; - u8 reg2 = (reg >> 0) & 0xff; - u8 page = (reg >> 8) & 0xff; - - /* switch bank if needed */ - if (page != priv->page) { - ret = rtl2830_wr(priv, 0x00, &page, 1); - if (ret) - return ret; - - priv->page = page; - } - - return rtl2830_rd(priv, reg2, val, len); -} - -/* read single register */ -static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val) -{ - return rtl2830_rd_regs(priv, reg, val, 1); -} - -/* write single register with mask */ -static int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask) -{ - int ret; - u8 tmp; - - /* no need for read if whole reg is written */ - if (mask != 0xff) { - ret = rtl2830_rd_regs(priv, reg, &tmp, 1); - if (ret) - return ret; - - val &= mask; - tmp &= ~mask; - val |= tmp; - } - - return rtl2830_wr_regs(priv, reg, &val, 1); -} - -/* read single register with mask */ -static int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask) -{ - int ret, i; - u8 tmp; - - ret = rtl2830_rd_regs(priv, reg, &tmp, 1); - if (ret) - return ret; - - tmp &= mask; - - /* find position of the first bit */ - for (i = 0; i < 8; i++) { - if ((mask >> i) & 0x01) - break; - } - *val = tmp >> i; - - return 0; + i2c_lock_adapter(client->adapter); + ret = regmap_bulk_read(dev->regmap, reg, val, val_count); + i2c_unlock_adapter(client->adapter); + return ret; } static int rtl2830_init(struct dvb_frontend *fe) { - struct rtl2830_priv *priv = fe->demodulator_priv; + struct i2c_client *client = fe->demodulator_priv; + struct rtl2830_dev *dev = i2c_get_clientdata(client); + struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; int ret, i; struct rtl2830_reg_val_mask tab[] = { - { 0x00d, 0x01, 0x03 }, - { 0x00d, 0x10, 0x10 }, - { 0x104, 0x00, 0x1e }, - { 0x105, 0x80, 0x80 }, - { 0x110, 0x02, 0x03 }, - { 0x110, 0x08, 0x0c }, - { 0x17b, 0x00, 0x40 }, - { 0x17d, 0x05, 0x0f }, - { 0x17d, 0x50, 0xf0 }, - { 0x18c, 0x08, 0x0f }, - { 0x18d, 0x00, 0xc0 }, - { 0x188, 0x05, 0x0f }, - { 0x189, 0x00, 0xfc }, - { 0x2d5, 0x02, 0x02 }, - { 0x2f1, 0x02, 0x06 }, - { 0x2f1, 0x20, 0xf8 }, - { 0x16d, 0x00, 0x01 }, - { 0x1a6, 0x00, 0x80 }, - { 0x106, priv->cfg.vtop, 0x3f }, - { 0x107, priv->cfg.krf, 0x3f }, - { 0x112, 0x28, 0xff }, - { 0x103, priv->cfg.agc_targ_val, 0xff }, - { 0x00a, 0x02, 0x07 }, - { 0x140, 0x0c, 0x3c }, - { 0x140, 0x40, 0xc0 }, - { 0x15b, 0x05, 0x07 }, - { 0x15b, 0x28, 0x38 }, - { 0x15c, 0x05, 0x07 }, - { 0x15c, 0x28, 0x38 }, - { 0x115, priv->cfg.spec_inv, 0x01 }, - { 0x16f, 0x01, 0x07 }, - { 0x170, 0x18, 0x38 }, - { 0x172, 0x0f, 0x0f }, - { 0x173, 0x08, 0x38 }, - { 0x175, 0x01, 0x07 }, - { 0x176, 0x00, 0xc0 }, + {0x00d, 0x01, 0x03}, + {0x00d, 0x10, 0x10}, + {0x104, 0x00, 0x1e}, + {0x105, 0x80, 0x80}, + {0x110, 0x02, 0x03}, + {0x110, 0x08, 0x0c}, + {0x17b, 0x00, 0x40}, + {0x17d, 0x05, 0x0f}, + {0x17d, 0x50, 0xf0}, + {0x18c, 0x08, 0x0f}, + {0x18d, 0x00, 0xc0}, + {0x188, 0x05, 0x0f}, + {0x189, 0x00, 0xfc}, + {0x2d5, 0x02, 0x02}, + {0x2f1, 0x02, 0x06}, + {0x2f1, 0x20, 0xf8}, + {0x16d, 0x00, 0x01}, + {0x1a6, 0x00, 0x80}, + {0x106, dev->pdata->vtop, 0x3f}, + {0x107, dev->pdata->krf, 0x3f}, + {0x112, 0x28, 0xff}, + {0x103, dev->pdata->agc_targ_val, 0xff}, + {0x00a, 0x02, 0x07}, + {0x140, 0x0c, 0x3c}, + {0x140, 0x40, 0xc0}, + {0x15b, 0x05, 0x07}, + {0x15b, 0x28, 0x38}, + {0x15c, 0x05, 0x07}, + {0x15c, 0x28, 0x38}, + {0x115, dev->pdata->spec_inv, 0x01}, + {0x16f, 0x01, 0x07}, + {0x170, 0x18, 0x38}, + {0x172, 0x0f, 0x0f}, + {0x173, 0x08, 0x38}, + {0x175, 0x01, 0x07}, + {0x176, 0x00, 0xc0}, }; for (i = 0; i < ARRAY_SIZE(tab); i++) { - ret = rtl2830_wr_reg_mask(priv, tab[i].reg, tab[i].val, - tab[i].mask); + ret = rtl2830_update_bits(client, tab[i].reg, tab[i].mask, + tab[i].val); if (ret) goto err; } - ret = rtl2830_wr_regs(priv, 0x18f, "\x28\x00", 2); + ret = rtl2830_bulk_write(client, 0x18f, "\x28\x00", 2); if (ret) goto err; - ret = rtl2830_wr_regs(priv, 0x195, - "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8); + ret = rtl2830_bulk_write(client, 0x195, + "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8); if (ret) goto err; /* TODO: spec init */ /* soft reset */ - ret = rtl2830_wr_reg_mask(priv, 0x101, 0x04, 0x04); + ret = rtl2830_update_bits(client, 0x101, 0x04, 0x04); if (ret) goto err; - ret = rtl2830_wr_reg_mask(priv, 0x101, 0x00, 0x04); + ret = rtl2830_update_bits(client, 0x101, 0x04, 0x00); if (ret) goto err; - priv->sleeping = false; + /* init stats here in order signal app which stats are supported */ + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + /* start statistics polling */ + schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); + + dev->sleeping = false; return ret; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int rtl2830_sleep(struct dvb_frontend *fe) { - struct rtl2830_priv *priv = fe->demodulator_priv; - priv->sleeping = true; + struct i2c_client *client = fe->demodulator_priv; + struct rtl2830_dev *dev = i2c_get_clientdata(client); + + dev->sleeping = true; + /* stop statistics polling */ + cancel_delayed_work_sync(&dev->stat_work); + dev->fe_status = 0; + return 0; } static int rtl2830_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *s) + struct dvb_frontend_tune_settings *s) { s->min_delay_ms = 500; s->step_size = fe->ops.info.frequency_stepsize * 2; @@ -278,11 +171,12 @@ static int rtl2830_get_tune_settings(struct dvb_frontend *fe, static int rtl2830_set_frontend(struct dvb_frontend *fe) { - struct rtl2830_priv *priv = fe->demodulator_priv; + struct i2c_client *client = fe->demodulator_priv; + struct rtl2830_dev *dev = i2c_get_clientdata(client); struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; u64 num; - u8 buf[3], tmp; + u8 buf[3], u8tmp; u32 if_ctl, if_frequency; static const u8 bw_params1[3][34] = { { @@ -308,9 +202,8 @@ static int rtl2830_set_frontend(struct dvb_frontend *fe) {0xae, 0xba, 0xf3, 0x26, 0x66, 0x64}, /* 8 MHz */ }; - dev_dbg(&priv->i2c->dev, - "%s: frequency=%d bandwidth_hz=%d inversion=%d\n", - __func__, c->frequency, c->bandwidth_hz, c->inversion); + dev_dbg(&client->dev, "frequency=%u bandwidth_hz=%u inversion=%u\n", + c->frequency, c->bandwidth_hz, c->inversion); /* program tuner */ if (fe->ops.tuner_ops.set_params) @@ -327,11 +220,12 @@ static int rtl2830_set_frontend(struct dvb_frontend *fe) i = 2; break; default: - dev_dbg(&priv->i2c->dev, "%s: invalid bandwidth\n", __func__); + dev_err(&client->dev, "invalid bandwidth_hz %u\n", + c->bandwidth_hz); return -EINVAL; } - ret = rtl2830_wr_reg_mask(priv, 0x008, i << 1, 0x06); + ret = rtl2830_update_bits(client, 0x008, 0x06, i << 1); if (ret) goto err; @@ -340,70 +234,71 @@ static int rtl2830_set_frontend(struct dvb_frontend *fe) ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); else ret = -EINVAL; - - if (ret < 0) - goto err; - - num = if_frequency % priv->cfg.xtal; - num *= 0x400000; - num = div_u64(num, priv->cfg.xtal); - num = -num; - if_ctl = num & 0x3fffff; - dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d if_ctl=%08x\n", - __func__, if_frequency, if_ctl); - - ret = rtl2830_rd_reg_mask(priv, 0x119, &tmp, 0xc0); /* b[7:6] */ if (ret) goto err; - buf[0] = tmp << 6; - buf[0] |= (if_ctl >> 16) & 0x3f; + num = if_frequency % dev->pdata->clk; + num *= 0x400000; + num = div_u64(num, dev->pdata->clk); + num = -num; + if_ctl = num & 0x3fffff; + dev_dbg(&client->dev, "if_frequency=%d if_ctl=%08x\n", + if_frequency, if_ctl); + + buf[0] = (if_ctl >> 16) & 0x3f; buf[1] = (if_ctl >> 8) & 0xff; buf[2] = (if_ctl >> 0) & 0xff; - ret = rtl2830_wr_regs(priv, 0x119, buf, 3); + ret = rtl2830_bulk_read(client, 0x119, &u8tmp, 1); + if (ret) + goto err; + + buf[0] |= u8tmp & 0xc0; /* [7:6] */ + + ret = rtl2830_bulk_write(client, 0x119, buf, 3); if (ret) goto err; /* 1/2 split I2C write */ - ret = rtl2830_wr_regs(priv, 0x11c, &bw_params1[i][0], 17); + ret = rtl2830_bulk_write(client, 0x11c, &bw_params1[i][0], 17); if (ret) goto err; /* 2/2 split I2C write */ - ret = rtl2830_wr_regs(priv, 0x12d, &bw_params1[i][17], 17); + ret = rtl2830_bulk_write(client, 0x12d, &bw_params1[i][17], 17); if (ret) goto err; - ret = rtl2830_wr_regs(priv, 0x19d, bw_params2[i], 6); + ret = rtl2830_bulk_write(client, 0x19d, bw_params2[i], 6); if (ret) goto err; return ret; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int rtl2830_get_frontend(struct dvb_frontend *fe) { - struct rtl2830_priv *priv = fe->demodulator_priv; + struct i2c_client *client = fe->demodulator_priv; + struct rtl2830_dev *dev = i2c_get_clientdata(client); struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; u8 buf[3]; - if (priv->sleeping) + if (dev->sleeping) return 0; - ret = rtl2830_rd_regs(priv, 0x33c, buf, 2); + ret = rtl2830_bulk_read(client, 0x33c, buf, 2); if (ret) goto err; - ret = rtl2830_rd_reg(priv, 0x351, &buf[2]); + ret = rtl2830_bulk_read(client, 0x351, &buf[2], 1); if (ret) goto err; - dev_dbg(&priv->i2c->dev, "%s: TPS=%*ph\n", __func__, 3, buf); + dev_dbg(&client->dev, "TPS=%*ph\n", 3, buf); switch ((buf[0] >> 2) & 3) { case 0: @@ -493,244 +388,87 @@ static int rtl2830_get_frontend(struct dvb_frontend *fe) return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status) { - struct rtl2830_priv *priv = fe->demodulator_priv; + struct i2c_client *client = fe->demodulator_priv; + struct rtl2830_dev *dev = i2c_get_clientdata(client); int ret; - u8 tmp; + u8 u8tmp; + *status = 0; - if (priv->sleeping) + if (dev->sleeping) return 0; - ret = rtl2830_rd_reg_mask(priv, 0x351, &tmp, 0x78); /* [6:3] */ + ret = rtl2830_bulk_read(client, 0x351, &u8tmp, 1); if (ret) goto err; - if (tmp == 11) { + u8tmp = (u8tmp >> 3) & 0x0f; /* [6:3] */ + if (u8tmp == 11) { *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - } else if (tmp == 10) { + } else if (u8tmp == 10) { *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI; } + dev->fe_status = *status; + return ret; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr) { - struct rtl2830_priv *priv = fe->demodulator_priv; - int ret, hierarchy, constellation; - u8 buf[2], tmp; - u16 tmp16; -#define CONSTELLATION_NUM 3 -#define HIERARCHY_NUM 4 - static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = { - { 70705899, 70705899, 70705899, 70705899 }, - { 82433173, 82433173, 87483115, 94445660 }, - { 92888734, 92888734, 95487525, 99770748 }, - }; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; - if (priv->sleeping) - return 0; - - /* reports SNR in resolution of 0.1 dB */ - - ret = rtl2830_rd_reg(priv, 0x33c, &tmp); - if (ret) - goto err; - - constellation = (tmp >> 2) & 0x03; /* [3:2] */ - if (constellation > CONSTELLATION_NUM - 1) - goto err; - - hierarchy = (tmp >> 4) & 0x07; /* [6:4] */ - if (hierarchy > HIERARCHY_NUM - 1) - goto err; - - ret = rtl2830_rd_regs(priv, 0x40c, buf, 2); - if (ret) - goto err; - - tmp16 = buf[0] << 8 | buf[1]; - - if (tmp16) - *snr = (snr_constant[constellation][hierarchy] - - intlog10(tmp16)) / ((1 << 24) / 100); + if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) + *snr = div_s64(c->cnr.stat[0].svalue, 100); else *snr = 0; return 0; -err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - return ret; } static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber) { - struct rtl2830_priv *priv = fe->demodulator_priv; - int ret; - u8 buf[2]; + struct i2c_client *client = fe->demodulator_priv; + struct rtl2830_dev *dev = i2c_get_clientdata(client); - if (priv->sleeping) - return 0; - - ret = rtl2830_rd_regs(priv, 0x34e, buf, 2); - if (ret) - goto err; - - *ber = buf[0] << 8 | buf[1]; + *ber = (dev->post_bit_error - dev->post_bit_error_prev); + dev->post_bit_error_prev = dev->post_bit_error; return 0; -err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - return ret; } static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { *ucblocks = 0; + return 0; } static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { - struct rtl2830_priv *priv = fe->demodulator_priv; - int ret; - u8 buf[2]; - u16 if_agc_raw, if_agc; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; - if (priv->sleeping) - return 0; - - ret = rtl2830_rd_regs(priv, 0x359, buf, 2); - if (ret) - goto err; - - if_agc_raw = (buf[0] << 8 | buf[1]) & 0x3fff; - - if (if_agc_raw & (1 << 9)) - if_agc = -(~(if_agc_raw - 1) & 0x1ff); + if (c->strength.stat[0].scale == FE_SCALE_RELATIVE) + *strength = c->strength.stat[0].uvalue; else - if_agc = if_agc_raw; - - *strength = (u8) (55 - if_agc / 182); - *strength |= *strength << 8; + *strength = 0; return 0; -err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - return ret; } -static struct dvb_frontend_ops rtl2830_ops; - -static u32 rtl2830_tuner_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static int rtl2830_tuner_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msg[], int num) -{ - struct rtl2830_priv *priv = i2c_get_adapdata(i2c_adap); - int ret; - - /* open i2c-gate */ - ret = rtl2830_wr_reg_mask(priv, 0x101, 0x08, 0x08); - if (ret) - goto err; - - ret = i2c_transfer(priv->i2c, msg, num); - if (ret < 0) - dev_warn(&priv->i2c->dev, "%s: tuner i2c failed=%d\n", - KBUILD_MODNAME, ret); - - return ret; -err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static struct i2c_algorithm rtl2830_tuner_i2c_algo = { - .master_xfer = rtl2830_tuner_i2c_xfer, - .functionality = rtl2830_tuner_i2c_func, -}; - -struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(struct dvb_frontend *fe) -{ - struct rtl2830_priv *priv = fe->demodulator_priv; - return &priv->tuner_i2c_adapter; -} -EXPORT_SYMBOL(rtl2830_get_tuner_i2c_adapter); - -static void rtl2830_release(struct dvb_frontend *fe) -{ - struct rtl2830_priv *priv = fe->demodulator_priv; - - i2c_del_adapter(&priv->tuner_i2c_adapter); - kfree(priv); -} - -struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *cfg, - struct i2c_adapter *i2c) -{ - struct rtl2830_priv *priv = NULL; - int ret = 0; - u8 tmp; - - /* allocate memory for the internal state */ - priv = kzalloc(sizeof(struct rtl2830_priv), GFP_KERNEL); - if (priv == NULL) - goto err; - - /* setup the priv */ - priv->i2c = i2c; - memcpy(&priv->cfg, cfg, sizeof(struct rtl2830_config)); - - /* check if the demod is there */ - ret = rtl2830_rd_reg(priv, 0x000, &tmp); - if (ret) - goto err; - - /* create dvb_frontend */ - memcpy(&priv->fe.ops, &rtl2830_ops, sizeof(struct dvb_frontend_ops)); - priv->fe.demodulator_priv = priv; - - /* create tuner i2c adapter */ - strlcpy(priv->tuner_i2c_adapter.name, "RTL2830 tuner I2C adapter", - sizeof(priv->tuner_i2c_adapter.name)); - priv->tuner_i2c_adapter.algo = &rtl2830_tuner_i2c_algo; - priv->tuner_i2c_adapter.algo_data = NULL; - priv->tuner_i2c_adapter.dev.parent = &i2c->dev; - i2c_set_adapdata(&priv->tuner_i2c_adapter, priv); - if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) { - dev_err(&i2c->dev, - "%s: tuner i2c bus could not be initialized\n", - KBUILD_MODNAME); - goto err; - } - - priv->sleeping = true; - - return &priv->fe; -err: - dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); - kfree(priv); - return NULL; -} -EXPORT_SYMBOL(rtl2830_attach); - static struct dvb_frontend_ops rtl2830_ops = { - .delsys = { SYS_DVBT }, + .delsys = {SYS_DVBT}, .info = { .name = "Realtek RTL2830 (DVB-T)", .caps = FE_CAN_FEC_1_2 | @@ -750,8 +488,6 @@ static struct dvb_frontend_ops rtl2830_ops = { FE_CAN_MUTE_TS }, - .release = rtl2830_release, - .init = rtl2830_init, .sleep = rtl2830_sleep, @@ -767,6 +503,428 @@ static struct dvb_frontend_ops rtl2830_ops = { .read_signal_strength = rtl2830_read_signal_strength, }; +static void rtl2830_stat_work(struct work_struct *work) +{ + struct rtl2830_dev *dev = container_of(work, struct rtl2830_dev, stat_work.work); + struct i2c_client *client = dev->client; + struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; + int ret, tmp; + u8 u8tmp, buf[2]; + u16 u16tmp; + + dev_dbg(&client->dev, "\n"); + + /* signal strength */ + if (dev->fe_status & FE_HAS_SIGNAL) { + struct {signed int x:14; } s; + + /* read IF AGC */ + ret = rtl2830_bulk_read(client, 0x359, buf, 2); + if (ret) + goto err; + + u16tmp = buf[0] << 8 | buf[1] << 0; + u16tmp &= 0x3fff; /* [13:0] */ + tmp = s.x = u16tmp; /* 14-bit bin to 2 complement */ + u16tmp = clamp_val(-4 * tmp + 32767, 0x0000, 0xffff); + + dev_dbg(&client->dev, "IF AGC=%d\n", tmp); + + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + c->strength.stat[0].uvalue = u16tmp; + } else { + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* CNR */ + if (dev->fe_status & FE_HAS_VITERBI) { + unsigned hierarchy, constellation; + #define CONSTELLATION_NUM 3 + #define HIERARCHY_NUM 4 + static const u32 constant[CONSTELLATION_NUM][HIERARCHY_NUM] = { + {70705899, 70705899, 70705899, 70705899}, + {82433173, 82433173, 87483115, 94445660}, + {92888734, 92888734, 95487525, 99770748}, + }; + + ret = rtl2830_bulk_read(client, 0x33c, &u8tmp, 1); + if (ret) + goto err; + + constellation = (u8tmp >> 2) & 0x03; /* [3:2] */ + if (constellation > CONSTELLATION_NUM - 1) + goto err_schedule_delayed_work; + + hierarchy = (u8tmp >> 4) & 0x07; /* [6:4] */ + if (hierarchy > HIERARCHY_NUM - 1) + goto err_schedule_delayed_work; + + ret = rtl2830_bulk_read(client, 0x40c, buf, 2); + if (ret) + goto err; + + u16tmp = buf[0] << 8 | buf[1] << 0; + if (u16tmp) + tmp = (constant[constellation][hierarchy] - + intlog10(u16tmp)) / ((1 << 24) / 10000); + else + tmp = 0; + + dev_dbg(&client->dev, "CNR raw=%u\n", u16tmp); + + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = tmp; + } else { + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* BER */ + if (dev->fe_status & FE_HAS_LOCK) { + ret = rtl2830_bulk_read(client, 0x34e, buf, 2); + if (ret) + goto err; + + u16tmp = buf[0] << 8 | buf[1] << 0; + dev->post_bit_error += u16tmp; + dev->post_bit_count += 1000000; + + dev_dbg(&client->dev, "BER errors=%u total=1000000\n", u16tmp); + + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue = dev->post_bit_error; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue = dev->post_bit_count; + } else { + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + +err_schedule_delayed_work: + schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); + return; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); +} + +static int rtl2830_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct i2c_client *client = fe->demodulator_priv; + int ret; + u8 u8tmp; + + dev_dbg(&client->dev, "onoff=%d\n", onoff); + + /* enable / disable PID filter */ + if (onoff) + u8tmp = 0x80; + else + u8tmp = 0x00; + + ret = rtl2830_update_bits(client, 0x061, 0x80, u8tmp); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +static int rtl2830_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, int onoff) +{ + struct i2c_client *client = fe->demodulator_priv; + struct rtl2830_dev *dev = i2c_get_clientdata(client); + int ret; + u8 buf[4]; + + dev_dbg(&client->dev, "index=%d pid=%04x onoff=%d\n", + index, pid, onoff); + + /* skip invalid PIDs (0x2000) */ + if (pid > 0x1fff || index > 32) + return 0; + + if (onoff) + set_bit(index, &dev->filters); + else + clear_bit(index, &dev->filters); + + /* enable / disable PIDs */ + buf[0] = (dev->filters >> 0) & 0xff; + buf[1] = (dev->filters >> 8) & 0xff; + buf[2] = (dev->filters >> 16) & 0xff; + buf[3] = (dev->filters >> 24) & 0xff; + ret = rtl2830_bulk_write(client, 0x062, buf, 4); + if (ret) + goto err; + + /* add PID */ + buf[0] = (pid >> 8) & 0xff; + buf[1] = (pid >> 0) & 0xff; + ret = rtl2830_bulk_write(client, 0x066 + 2 * index, buf, 2); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +/* + * I2C gate/mux/repeater logic + * We must use unlocked __i2c_transfer() here (through regmap) because of I2C + * adapter lock is already taken by tuner driver. + * Gate is closed automatically after single I2C transfer. + */ +static int rtl2830_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) +{ + struct i2c_client *client = mux_priv; + struct rtl2830_dev *dev = i2c_get_clientdata(client); + int ret; + + dev_dbg(&client->dev, "\n"); + + /* open I2C repeater for 1 transfer, closes automatically */ + /* XXX: regmap_update_bits() does not lock I2C adapter */ + ret = regmap_update_bits(dev->regmap, 0x101, 0x08, 0x08); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +static struct dvb_frontend *rtl2830_get_dvb_frontend(struct i2c_client *client) +{ + struct rtl2830_dev *dev = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + return &dev->fe; +} + +static struct i2c_adapter *rtl2830_get_i2c_adapter(struct i2c_client *client) +{ + struct rtl2830_dev *dev = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + return dev->adapter; +} + +/* + * We implement own I2C access routines for regmap in order to get manual access + * to I2C adapter lock, which is needed for I2C mux adapter. + */ +static int rtl2830_regmap_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, size_t val_size) +{ + struct i2c_client *client = context; + int ret; + struct i2c_msg msg[2] = { + { + .addr = client->addr, + .flags = 0, + .len = reg_size, + .buf = (u8 *)reg_buf, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .len = val_size, + .buf = val_buf, + } + }; + + ret = __i2c_transfer(client->adapter, msg, 2); + if (ret != 2) { + dev_warn(&client->dev, "i2c reg read failed %d\n", ret); + if (ret >= 0) + ret = -EREMOTEIO; + return ret; + } + return 0; +} + +static int rtl2830_regmap_write(void *context, const void *data, size_t count) +{ + struct i2c_client *client = context; + int ret; + struct i2c_msg msg[1] = { + { + .addr = client->addr, + .flags = 0, + .len = count, + .buf = (u8 *)data, + } + }; + + ret = __i2c_transfer(client->adapter, msg, 1); + if (ret != 1) { + dev_warn(&client->dev, "i2c reg write failed %d\n", ret); + if (ret >= 0) + ret = -EREMOTEIO; + return ret; + } + return 0; +} + +static int rtl2830_regmap_gather_write(void *context, const void *reg, + size_t reg_len, const void *val, + size_t val_len) +{ + struct i2c_client *client = context; + int ret; + u8 buf[256]; + struct i2c_msg msg[1] = { + { + .addr = client->addr, + .flags = 0, + .len = 1 + val_len, + .buf = buf, + } + }; + + buf[0] = *(u8 const *)reg; + memcpy(&buf[1], val, val_len); + + ret = __i2c_transfer(client->adapter, msg, 1); + if (ret != 1) { + dev_warn(&client->dev, "i2c reg write failed %d\n", ret); + if (ret >= 0) + ret = -EREMOTEIO; + return ret; + } + return 0; +} + +static int rtl2830_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct rtl2830_platform_data *pdata = client->dev.platform_data; + struct rtl2830_dev *dev; + int ret; + u8 u8tmp; + static const struct regmap_bus regmap_bus = { + .read = rtl2830_regmap_read, + .write = rtl2830_regmap_write, + .gather_write = rtl2830_regmap_gather_write, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, + }; + static const struct regmap_range_cfg regmap_range_cfg[] = { + { + .selector_reg = 0x00, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = 0x100, + .range_min = 0 * 0x100, + .range_max = 5 * 0x100, + }, + }; + static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 5 * 0x100, + .ranges = regmap_range_cfg, + .num_ranges = ARRAY_SIZE(regmap_range_cfg), + }; + + dev_dbg(&client->dev, "\n"); + + if (pdata == NULL) { + ret = -EINVAL; + goto err; + } + + /* allocate memory for the internal state */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + ret = -ENOMEM; + goto err; + } + + /* setup the state */ + i2c_set_clientdata(client, dev); + dev->client = client; + dev->pdata = client->dev.platform_data; + dev->sleeping = true; + INIT_DELAYED_WORK(&dev->stat_work, rtl2830_stat_work); + dev->regmap = regmap_init(&client->dev, ®map_bus, client, + ®map_config); + if (IS_ERR(dev->regmap)) { + ret = PTR_ERR(dev->regmap); + goto err_kfree; + } + + /* check if the demod is there */ + ret = rtl2830_bulk_read(client, 0x000, &u8tmp, 1); + if (ret) + goto err_regmap_exit; + + /* create muxed i2c adapter for tuner */ + dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev, + client, 0, 0, 0, rtl2830_select, NULL); + if (dev->adapter == NULL) { + ret = -ENODEV; + goto err_regmap_exit; + } + + /* create dvb frontend */ + memcpy(&dev->fe.ops, &rtl2830_ops, sizeof(dev->fe.ops)); + dev->fe.demodulator_priv = client; + + /* setup callbacks */ + pdata->get_dvb_frontend = rtl2830_get_dvb_frontend; + pdata->get_i2c_adapter = rtl2830_get_i2c_adapter; + pdata->pid_filter = rtl2830_pid_filter; + pdata->pid_filter_ctrl = rtl2830_pid_filter_ctrl; + + dev_info(&client->dev, "Realtek RTL2830 successfully attached\n"); + + return 0; +err_regmap_exit: + regmap_exit(dev->regmap); +err_kfree: + kfree(dev); +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +static int rtl2830_remove(struct i2c_client *client) +{ + struct rtl2830_dev *dev = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + i2c_del_mux_adapter(dev->adapter); + regmap_exit(dev->regmap); + kfree(dev); + + return 0; +} + +static const struct i2c_device_id rtl2830_id_table[] = { + {"rtl2830", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, rtl2830_id_table); + +static struct i2c_driver rtl2830_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "rtl2830", + }, + .probe = rtl2830_probe, + .remove = rtl2830_remove, + .id_table = rtl2830_id_table, +}; + +module_i2c_driver(rtl2830_driver); + MODULE_AUTHOR("Antti Palosaari "); MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/rtl2830.h b/drivers/media/dvb-frontends/rtl2830.h index 3313847fb0be..0cde151e6608 100644 --- a/drivers/media/dvb-frontends/rtl2830.h +++ b/drivers/media/dvb-frontends/rtl2830.h @@ -13,78 +13,37 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef RTL2830_H #define RTL2830_H -#include #include -struct rtl2830_config { - /* - * Demodulator I2C address. - */ - u8 i2c_addr; +/** + * struct rtl2830_platform_data - Platform data for the rtl2830 driver + * @clk: Clock frequency (4000000, 16000000, 25000000, 28800000). + * @spec_inv: Spectrum inversion. + * @vtop: AGC take-over point. + * @krf: AGC ratio. + * @agc_targ_val: AGC. + * @get_dvb_frontend: Get DVB frontend. + * @get_i2c_adapter: Get I2C adapter. + * @pid_filter: Set PID to PID filter. + * @pid_filter_ctrl: Control PID filter. + */ - /* - * Xtal frequency. - * Hz - * 4000000, 16000000, 25000000, 28800000 - */ - u32 xtal; - - /* - * TS output mode. - */ - u8 ts_mode; - - /* - * Spectrum inversion. - */ +struct rtl2830_platform_data { + u32 clk; bool spec_inv; - - /* - */ u8 vtop; - - /* - */ u8 krf; - - /* - */ u8 agc_targ_val; + + struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); + struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *); + int (*pid_filter)(struct dvb_frontend *, u8, u16, int); + int (*pid_filter_ctrl)(struct dvb_frontend *, int); }; -#if IS_ENABLED(CONFIG_DVB_RTL2830) -extern struct dvb_frontend *rtl2830_attach( - const struct rtl2830_config *config, - struct i2c_adapter *i2c -); - -extern struct i2c_adapter *rtl2830_get_tuner_i2c_adapter( - struct dvb_frontend *fe -); -#else -static inline struct dvb_frontend *rtl2830_attach( - const struct rtl2830_config *config, - struct i2c_adapter *i2c -) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline struct i2c_adapter *rtl2830_get_tuner_i2c_adapter( - struct dvb_frontend *fe -) -{ - return NULL; -} -#endif - #endif /* RTL2830_H */ diff --git a/drivers/media/dvb-frontends/rtl2830_priv.h b/drivers/media/dvb-frontends/rtl2830_priv.h index fab10ecb3c3b..d50d5376c9c5 100644 --- a/drivers/media/dvb-frontends/rtl2830_priv.h +++ b/drivers/media/dvb-frontends/rtl2830_priv.h @@ -13,9 +13,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef RTL2830_PRIV_H @@ -24,16 +21,23 @@ #include "dvb_frontend.h" #include "dvb_math.h" #include "rtl2830.h" +#include +#include +#include -struct rtl2830_priv { - struct i2c_adapter *i2c; +struct rtl2830_dev { + struct rtl2830_platform_data *pdata; + struct i2c_client *client; + struct regmap *regmap; + struct i2c_adapter *adapter; struct dvb_frontend fe; - struct rtl2830_config cfg; - struct i2c_adapter tuner_i2c_adapter; - bool sleeping; - - u8 page; /* active register page */ + unsigned long filters; + struct delayed_work stat_work; + fe_status_t fe_status; + u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */ + u64 post_bit_error; + u64 post_bit_count; }; struct rtl2830_reg_val_mask { diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 9026e1aee163..5d2d8f45b4b6 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -2,6 +2,7 @@ * Realtek RTL2832 DVB-T demodulator driver * * Copyright (C) 2012 Thomas Mair + * Copyright (C) 2012-2014 Antti Palosaari * * 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 @@ -19,280 +20,191 @@ */ #include "rtl2832_priv.h" -#include "dvb_math.h" -#include -/* Max transfer size done by I2C transfer functions */ -#define MAX_XFER_SIZE 64 #define REG_MASK(b) (BIT(b + 1) - 1) static const struct rtl2832_reg_entry registers[] = { - [DVBT_SOFT_RST] = {0x1, 0x1, 2, 2}, - [DVBT_IIC_REPEAT] = {0x1, 0x1, 3, 3}, - [DVBT_TR_WAIT_MIN_8K] = {0x1, 0x88, 11, 2}, - [DVBT_RSD_BER_FAIL_VAL] = {0x1, 0x8f, 15, 0}, - [DVBT_EN_BK_TRK] = {0x1, 0xa6, 7, 7}, - [DVBT_AD_EN_REG] = {0x0, 0x8, 7, 7}, - [DVBT_AD_EN_REG1] = {0x0, 0x8, 6, 6}, - [DVBT_EN_BBIN] = {0x1, 0xb1, 0, 0}, - [DVBT_MGD_THD0] = {0x1, 0x95, 7, 0}, - [DVBT_MGD_THD1] = {0x1, 0x96, 7, 0}, - [DVBT_MGD_THD2] = {0x1, 0x97, 7, 0}, - [DVBT_MGD_THD3] = {0x1, 0x98, 7, 0}, - [DVBT_MGD_THD4] = {0x1, 0x99, 7, 0}, - [DVBT_MGD_THD5] = {0x1, 0x9a, 7, 0}, - [DVBT_MGD_THD6] = {0x1, 0x9b, 7, 0}, - [DVBT_MGD_THD7] = {0x1, 0x9c, 7, 0}, - [DVBT_EN_CACQ_NOTCH] = {0x1, 0x61, 4, 4}, - [DVBT_AD_AV_REF] = {0x0, 0x9, 6, 0}, - [DVBT_REG_PI] = {0x0, 0xa, 2, 0}, - [DVBT_PIP_ON] = {0x0, 0x21, 3, 3}, - [DVBT_SCALE1_B92] = {0x2, 0x92, 7, 0}, - [DVBT_SCALE1_B93] = {0x2, 0x93, 7, 0}, - [DVBT_SCALE1_BA7] = {0x2, 0xa7, 7, 0}, - [DVBT_SCALE1_BA9] = {0x2, 0xa9, 7, 0}, - [DVBT_SCALE1_BAA] = {0x2, 0xaa, 7, 0}, - [DVBT_SCALE1_BAB] = {0x2, 0xab, 7, 0}, - [DVBT_SCALE1_BAC] = {0x2, 0xac, 7, 0}, - [DVBT_SCALE1_BB0] = {0x2, 0xb0, 7, 0}, - [DVBT_SCALE1_BB1] = {0x2, 0xb1, 7, 0}, - [DVBT_KB_P1] = {0x1, 0x64, 3, 1}, - [DVBT_KB_P2] = {0x1, 0x64, 6, 4}, - [DVBT_KB_P3] = {0x1, 0x65, 2, 0}, - [DVBT_OPT_ADC_IQ] = {0x0, 0x6, 5, 4}, - [DVBT_AD_AVI] = {0x0, 0x9, 1, 0}, - [DVBT_AD_AVQ] = {0x0, 0x9, 3, 2}, - [DVBT_K1_CR_STEP12] = {0x2, 0xad, 9, 4}, - [DVBT_TRK_KS_P2] = {0x1, 0x6f, 2, 0}, - [DVBT_TRK_KS_I2] = {0x1, 0x70, 5, 3}, - [DVBT_TR_THD_SET2] = {0x1, 0x72, 3, 0}, - [DVBT_TRK_KC_P2] = {0x1, 0x73, 5, 3}, - [DVBT_TRK_KC_I2] = {0x1, 0x75, 2, 0}, - [DVBT_CR_THD_SET2] = {0x1, 0x76, 7, 6}, - [DVBT_PSET_IFFREQ] = {0x1, 0x19, 21, 0}, - [DVBT_SPEC_INV] = {0x1, 0x15, 0, 0}, - [DVBT_RSAMP_RATIO] = {0x1, 0x9f, 27, 2}, - [DVBT_CFREQ_OFF_RATIO] = {0x1, 0x9d, 23, 4}, - [DVBT_FSM_STAGE] = {0x3, 0x51, 6, 3}, - [DVBT_RX_CONSTEL] = {0x3, 0x3c, 3, 2}, - [DVBT_RX_HIER] = {0x3, 0x3c, 6, 4}, - [DVBT_RX_C_RATE_LP] = {0x3, 0x3d, 2, 0}, - [DVBT_RX_C_RATE_HP] = {0x3, 0x3d, 5, 3}, - [DVBT_GI_IDX] = {0x3, 0x51, 1, 0}, - [DVBT_FFT_MODE_IDX] = {0x3, 0x51, 2, 2}, - [DVBT_RSD_BER_EST] = {0x3, 0x4e, 15, 0}, - [DVBT_CE_EST_EVM] = {0x4, 0xc, 15, 0}, - [DVBT_RF_AGC_VAL] = {0x3, 0x5b, 13, 0}, - [DVBT_IF_AGC_VAL] = {0x3, 0x59, 13, 0}, - [DVBT_DAGC_VAL] = {0x3, 0x5, 7, 0}, - [DVBT_SFREQ_OFF] = {0x3, 0x18, 13, 0}, - [DVBT_CFREQ_OFF] = {0x3, 0x5f, 17, 0}, - [DVBT_POLAR_RF_AGC] = {0x0, 0xe, 1, 1}, - [DVBT_POLAR_IF_AGC] = {0x0, 0xe, 0, 0}, - [DVBT_AAGC_HOLD] = {0x1, 0x4, 5, 5}, - [DVBT_EN_RF_AGC] = {0x1, 0x4, 6, 6}, - [DVBT_EN_IF_AGC] = {0x1, 0x4, 7, 7}, - [DVBT_IF_AGC_MIN] = {0x1, 0x8, 7, 0}, - [DVBT_IF_AGC_MAX] = {0x1, 0x9, 7, 0}, - [DVBT_RF_AGC_MIN] = {0x1, 0xa, 7, 0}, - [DVBT_RF_AGC_MAX] = {0x1, 0xb, 7, 0}, - [DVBT_IF_AGC_MAN] = {0x1, 0xc, 6, 6}, - [DVBT_IF_AGC_MAN_VAL] = {0x1, 0xc, 13, 0}, - [DVBT_RF_AGC_MAN] = {0x1, 0xe, 6, 6}, - [DVBT_RF_AGC_MAN_VAL] = {0x1, 0xe, 13, 0}, - [DVBT_DAGC_TRG_VAL] = {0x1, 0x12, 7, 0}, - [DVBT_AGC_TARG_VAL_0] = {0x1, 0x2, 0, 0}, - [DVBT_AGC_TARG_VAL_8_1] = {0x1, 0x3, 7, 0}, - [DVBT_AAGC_LOOP_GAIN] = {0x1, 0xc7, 5, 1}, - [DVBT_LOOP_GAIN2_3_0] = {0x1, 0x4, 4, 1}, - [DVBT_LOOP_GAIN2_4] = {0x1, 0x5, 7, 7}, - [DVBT_LOOP_GAIN3] = {0x1, 0xc8, 4, 0}, - [DVBT_VTOP1] = {0x1, 0x6, 5, 0}, - [DVBT_VTOP2] = {0x1, 0xc9, 5, 0}, - [DVBT_VTOP3] = {0x1, 0xca, 5, 0}, - [DVBT_KRF1] = {0x1, 0xcb, 7, 0}, - [DVBT_KRF2] = {0x1, 0x7, 7, 0}, - [DVBT_KRF3] = {0x1, 0xcd, 7, 0}, - [DVBT_KRF4] = {0x1, 0xce, 7, 0}, - [DVBT_EN_GI_PGA] = {0x1, 0xe5, 0, 0}, - [DVBT_THD_LOCK_UP] = {0x1, 0xd9, 8, 0}, - [DVBT_THD_LOCK_DW] = {0x1, 0xdb, 8, 0}, - [DVBT_THD_UP1] = {0x1, 0xdd, 7, 0}, - [DVBT_THD_DW1] = {0x1, 0xde, 7, 0}, - [DVBT_INTER_CNT_LEN] = {0x1, 0xd8, 3, 0}, - [DVBT_GI_PGA_STATE] = {0x1, 0xe6, 3, 3}, - [DVBT_EN_AGC_PGA] = {0x1, 0xd7, 0, 0}, - [DVBT_CKOUTPAR] = {0x1, 0x7b, 5, 5}, - [DVBT_CKOUT_PWR] = {0x1, 0x7b, 6, 6}, - [DVBT_SYNC_DUR] = {0x1, 0x7b, 7, 7}, - [DVBT_ERR_DUR] = {0x1, 0x7c, 0, 0}, - [DVBT_SYNC_LVL] = {0x1, 0x7c, 1, 1}, - [DVBT_ERR_LVL] = {0x1, 0x7c, 2, 2}, - [DVBT_VAL_LVL] = {0x1, 0x7c, 3, 3}, - [DVBT_SERIAL] = {0x1, 0x7c, 4, 4}, - [DVBT_SER_LSB] = {0x1, 0x7c, 5, 5}, - [DVBT_CDIV_PH0] = {0x1, 0x7d, 3, 0}, - [DVBT_CDIV_PH1] = {0x1, 0x7d, 7, 4}, - [DVBT_MPEG_IO_OPT_2_2] = {0x0, 0x6, 7, 7}, - [DVBT_MPEG_IO_OPT_1_0] = {0x0, 0x7, 7, 6}, - [DVBT_CKOUTPAR_PIP] = {0x0, 0xb7, 4, 4}, - [DVBT_CKOUT_PWR_PIP] = {0x0, 0xb7, 3, 3}, - [DVBT_SYNC_LVL_PIP] = {0x0, 0xb7, 2, 2}, - [DVBT_ERR_LVL_PIP] = {0x0, 0xb7, 1, 1}, - [DVBT_VAL_LVL_PIP] = {0x0, 0xb7, 0, 0}, - [DVBT_CKOUTPAR_PID] = {0x0, 0xb9, 4, 4}, - [DVBT_CKOUT_PWR_PID] = {0x0, 0xb9, 3, 3}, - [DVBT_SYNC_LVL_PID] = {0x0, 0xb9, 2, 2}, - [DVBT_ERR_LVL_PID] = {0x0, 0xb9, 1, 1}, - [DVBT_VAL_LVL_PID] = {0x0, 0xb9, 0, 0}, - [DVBT_SM_PASS] = {0x1, 0x93, 11, 0}, - [DVBT_AD7_SETTING] = {0x0, 0x11, 15, 0}, - [DVBT_RSSI_R] = {0x3, 0x1, 6, 0}, - [DVBT_ACI_DET_IND] = {0x3, 0x12, 0, 0}, - [DVBT_REG_MON] = {0x0, 0xd, 1, 0}, - [DVBT_REG_MONSEL] = {0x0, 0xd, 2, 2}, - [DVBT_REG_GPE] = {0x0, 0xd, 7, 7}, - [DVBT_REG_GPO] = {0x0, 0x10, 0, 0}, - [DVBT_REG_4MSEL] = {0x0, 0x13, 0, 0}, + [DVBT_SOFT_RST] = {0x101, 2, 2}, + [DVBT_IIC_REPEAT] = {0x101, 3, 3}, + [DVBT_TR_WAIT_MIN_8K] = {0x188, 11, 2}, + [DVBT_RSD_BER_FAIL_VAL] = {0x18f, 15, 0}, + [DVBT_EN_BK_TRK] = {0x1a6, 7, 7}, + [DVBT_AD_EN_REG] = {0x008, 7, 7}, + [DVBT_AD_EN_REG1] = {0x008, 6, 6}, + [DVBT_EN_BBIN] = {0x1b1, 0, 0}, + [DVBT_MGD_THD0] = {0x195, 7, 0}, + [DVBT_MGD_THD1] = {0x196, 7, 0}, + [DVBT_MGD_THD2] = {0x197, 7, 0}, + [DVBT_MGD_THD3] = {0x198, 7, 0}, + [DVBT_MGD_THD4] = {0x199, 7, 0}, + [DVBT_MGD_THD5] = {0x19a, 7, 0}, + [DVBT_MGD_THD6] = {0x19b, 7, 0}, + [DVBT_MGD_THD7] = {0x19c, 7, 0}, + [DVBT_EN_CACQ_NOTCH] = {0x161, 4, 4}, + [DVBT_AD_AV_REF] = {0x009, 6, 0}, + [DVBT_REG_PI] = {0x00a, 2, 0}, + [DVBT_PIP_ON] = {0x021, 3, 3}, + [DVBT_SCALE1_B92] = {0x292, 7, 0}, + [DVBT_SCALE1_B93] = {0x293, 7, 0}, + [DVBT_SCALE1_BA7] = {0x2a7, 7, 0}, + [DVBT_SCALE1_BA9] = {0x2a9, 7, 0}, + [DVBT_SCALE1_BAA] = {0x2aa, 7, 0}, + [DVBT_SCALE1_BAB] = {0x2ab, 7, 0}, + [DVBT_SCALE1_BAC] = {0x2ac, 7, 0}, + [DVBT_SCALE1_BB0] = {0x2b0, 7, 0}, + [DVBT_SCALE1_BB1] = {0x2b1, 7, 0}, + [DVBT_KB_P1] = {0x164, 3, 1}, + [DVBT_KB_P2] = {0x164, 6, 4}, + [DVBT_KB_P3] = {0x165, 2, 0}, + [DVBT_OPT_ADC_IQ] = {0x006, 5, 4}, + [DVBT_AD_AVI] = {0x009, 1, 0}, + [DVBT_AD_AVQ] = {0x009, 3, 2}, + [DVBT_K1_CR_STEP12] = {0x2ad, 9, 4}, + [DVBT_TRK_KS_P2] = {0x16f, 2, 0}, + [DVBT_TRK_KS_I2] = {0x170, 5, 3}, + [DVBT_TR_THD_SET2] = {0x172, 3, 0}, + [DVBT_TRK_KC_P2] = {0x173, 5, 3}, + [DVBT_TRK_KC_I2] = {0x175, 2, 0}, + [DVBT_CR_THD_SET2] = {0x176, 7, 6}, + [DVBT_PSET_IFFREQ] = {0x119, 21, 0}, + [DVBT_SPEC_INV] = {0x115, 0, 0}, + [DVBT_RSAMP_RATIO] = {0x19f, 27, 2}, + [DVBT_CFREQ_OFF_RATIO] = {0x19d, 23, 4}, + [DVBT_FSM_STAGE] = {0x351, 6, 3}, + [DVBT_RX_CONSTEL] = {0x33c, 3, 2}, + [DVBT_RX_HIER] = {0x33c, 6, 4}, + [DVBT_RX_C_RATE_LP] = {0x33d, 2, 0}, + [DVBT_RX_C_RATE_HP] = {0x33d, 5, 3}, + [DVBT_GI_IDX] = {0x351, 1, 0}, + [DVBT_FFT_MODE_IDX] = {0x351, 2, 2}, + [DVBT_RSD_BER_EST] = {0x34e, 15, 0}, + [DVBT_CE_EST_EVM] = {0x40c, 15, 0}, + [DVBT_RF_AGC_VAL] = {0x35b, 13, 0}, + [DVBT_IF_AGC_VAL] = {0x359, 13, 0}, + [DVBT_DAGC_VAL] = {0x305, 7, 0}, + [DVBT_SFREQ_OFF] = {0x318, 13, 0}, + [DVBT_CFREQ_OFF] = {0x35f, 17, 0}, + [DVBT_POLAR_RF_AGC] = {0x00e, 1, 1}, + [DVBT_POLAR_IF_AGC] = {0x00e, 0, 0}, + [DVBT_AAGC_HOLD] = {0x104, 5, 5}, + [DVBT_EN_RF_AGC] = {0x104, 6, 6}, + [DVBT_EN_IF_AGC] = {0x104, 7, 7}, + [DVBT_IF_AGC_MIN] = {0x108, 7, 0}, + [DVBT_IF_AGC_MAX] = {0x109, 7, 0}, + [DVBT_RF_AGC_MIN] = {0x10a, 7, 0}, + [DVBT_RF_AGC_MAX] = {0x10b, 7, 0}, + [DVBT_IF_AGC_MAN] = {0x10c, 6, 6}, + [DVBT_IF_AGC_MAN_VAL] = {0x10c, 13, 0}, + [DVBT_RF_AGC_MAN] = {0x10e, 6, 6}, + [DVBT_RF_AGC_MAN_VAL] = {0x10e, 13, 0}, + [DVBT_DAGC_TRG_VAL] = {0x112, 7, 0}, + [DVBT_AGC_TARG_VAL_0] = {0x102, 0, 0}, + [DVBT_AGC_TARG_VAL_8_1] = {0x103, 7, 0}, + [DVBT_AAGC_LOOP_GAIN] = {0x1c7, 5, 1}, + [DVBT_LOOP_GAIN2_3_0] = {0x104, 4, 1}, + [DVBT_LOOP_GAIN2_4] = {0x105, 7, 7}, + [DVBT_LOOP_GAIN3] = {0x1c8, 4, 0}, + [DVBT_VTOP1] = {0x106, 5, 0}, + [DVBT_VTOP2] = {0x1c9, 5, 0}, + [DVBT_VTOP3] = {0x1ca, 5, 0}, + [DVBT_KRF1] = {0x1cb, 7, 0}, + [DVBT_KRF2] = {0x107, 7, 0}, + [DVBT_KRF3] = {0x1cd, 7, 0}, + [DVBT_KRF4] = {0x1ce, 7, 0}, + [DVBT_EN_GI_PGA] = {0x1e5, 0, 0}, + [DVBT_THD_LOCK_UP] = {0x1d9, 8, 0}, + [DVBT_THD_LOCK_DW] = {0x1db, 8, 0}, + [DVBT_THD_UP1] = {0x1dd, 7, 0}, + [DVBT_THD_DW1] = {0x1de, 7, 0}, + [DVBT_INTER_CNT_LEN] = {0x1d8, 3, 0}, + [DVBT_GI_PGA_STATE] = {0x1e6, 3, 3}, + [DVBT_EN_AGC_PGA] = {0x1d7, 0, 0}, + [DVBT_CKOUTPAR] = {0x17b, 5, 5}, + [DVBT_CKOUT_PWR] = {0x17b, 6, 6}, + [DVBT_SYNC_DUR] = {0x17b, 7, 7}, + [DVBT_ERR_DUR] = {0x17c, 0, 0}, + [DVBT_SYNC_LVL] = {0x17c, 1, 1}, + [DVBT_ERR_LVL] = {0x17c, 2, 2}, + [DVBT_VAL_LVL] = {0x17c, 3, 3}, + [DVBT_SERIAL] = {0x17c, 4, 4}, + [DVBT_SER_LSB] = {0x17c, 5, 5}, + [DVBT_CDIV_PH0] = {0x17d, 3, 0}, + [DVBT_CDIV_PH1] = {0x17d, 7, 4}, + [DVBT_MPEG_IO_OPT_2_2] = {0x006, 7, 7}, + [DVBT_MPEG_IO_OPT_1_0] = {0x007, 7, 6}, + [DVBT_CKOUTPAR_PIP] = {0x0b7, 4, 4}, + [DVBT_CKOUT_PWR_PIP] = {0x0b7, 3, 3}, + [DVBT_SYNC_LVL_PIP] = {0x0b7, 2, 2}, + [DVBT_ERR_LVL_PIP] = {0x0b7, 1, 1}, + [DVBT_VAL_LVL_PIP] = {0x0b7, 0, 0}, + [DVBT_CKOUTPAR_PID] = {0x0b9, 4, 4}, + [DVBT_CKOUT_PWR_PID] = {0x0b9, 3, 3}, + [DVBT_SYNC_LVL_PID] = {0x0b9, 2, 2}, + [DVBT_ERR_LVL_PID] = {0x0b9, 1, 1}, + [DVBT_VAL_LVL_PID] = {0x0b9, 0, 0}, + [DVBT_SM_PASS] = {0x193, 11, 0}, + [DVBT_AD7_SETTING] = {0x011, 15, 0}, + [DVBT_RSSI_R] = {0x301, 6, 0}, + [DVBT_ACI_DET_IND] = {0x312, 0, 0}, + [DVBT_REG_MON] = {0x00d, 1, 0}, + [DVBT_REG_MONSEL] = {0x00d, 2, 2}, + [DVBT_REG_GPE] = {0x00d, 7, 7}, + [DVBT_REG_GPO] = {0x010, 0, 0}, + [DVBT_REG_4MSEL] = {0x013, 0, 0}, }; -/* write multiple hardware registers */ -static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len) +/* Our regmap is bypassing I2C adapter lock, thus we do it! */ +static int rtl2832_bulk_write(struct i2c_client *client, unsigned int reg, + const void *val, size_t val_count) { + struct rtl2832_dev *dev = i2c_get_clientdata(client); int ret; - u8 buf[MAX_XFER_SIZE]; - struct i2c_msg msg[1] = { - { - .addr = priv->cfg.i2c_addr, - .flags = 0, - .len = 1 + len, - .buf = buf, - } - }; - if (1 + len > sizeof(buf)) { - dev_warn(&priv->i2c->dev, - "%s: i2c wr reg=%04x: len=%d is too big!\n", - KBUILD_MODNAME, reg, len); - return -EINVAL; - } - - buf[0] = reg; - memcpy(&buf[1], val, len); - - ret = i2c_transfer(priv->i2c_adapter, msg, 1); - if (ret == 1) { - ret = 0; - } else { - dev_warn(&priv->i2c->dev, - "%s: i2c wr failed=%d reg=%02x len=%d\n", - KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } + i2c_lock_adapter(client->adapter); + ret = regmap_bulk_write(dev->regmap, reg, val, val_count); + i2c_unlock_adapter(client->adapter); return ret; } -/* read multiple hardware registers */ -static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len) +static int rtl2832_update_bits(struct i2c_client *client, unsigned int reg, + unsigned int mask, unsigned int val) { + struct rtl2832_dev *dev = i2c_get_clientdata(client); int ret; - struct i2c_msg msg[2] = { - { - .addr = priv->cfg.i2c_addr, - .flags = 0, - .len = 1, - .buf = ®, - }, { - .addr = priv->cfg.i2c_addr, - .flags = I2C_M_RD, - .len = len, - .buf = val, - } - }; - ret = i2c_transfer(priv->i2c_adapter, msg, 2); - if (ret == 2) { - ret = 0; - } else { - dev_warn(&priv->i2c->dev, - "%s: i2c rd failed=%d reg=%02x len=%d\n", - KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } + i2c_lock_adapter(client->adapter); + ret = regmap_update_bits(dev->regmap, reg, mask, val); + i2c_unlock_adapter(client->adapter); return ret; } -/* write multiple registers */ -static int rtl2832_wr_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val, - int len) +static int rtl2832_bulk_read(struct i2c_client *client, unsigned int reg, + void *val, size_t val_count) { + struct rtl2832_dev *dev = i2c_get_clientdata(client); int ret; - /* switch bank if needed */ - if (page != priv->page) { - ret = rtl2832_wr(priv, 0x00, &page, 1); - if (ret) - return ret; - - priv->page = page; + i2c_lock_adapter(client->adapter); + ret = regmap_bulk_read(dev->regmap, reg, val, val_count); + i2c_unlock_adapter(client->adapter); + return ret; } -return rtl2832_wr(priv, reg, val, len); -} - -/* read multiple registers */ -static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val, - int len) +static int rtl2832_rd_demod_reg(struct rtl2832_dev *dev, int reg, u32 *val) { - int ret; - - /* switch bank if needed */ - if (page != priv->page) { - ret = rtl2832_wr(priv, 0x00, &page, 1); - if (ret) - return ret; - - priv->page = page; - } - - return rtl2832_rd(priv, reg, val, len); -} - -/* write single register */ -static int rtl2832_wr_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 val) -{ - return rtl2832_wr_regs(priv, reg, page, &val, 1); -} - -/* read single register */ -static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val) -{ - return rtl2832_rd_regs(priv, reg, page, val, 1); -} - -static int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val) -{ - int ret; - - u8 reg_start_addr; - u8 msb, lsb; - u8 page; - u8 reading[4]; - u32 reading_tmp; - int i; - - u8 len; - u32 mask; + struct i2c_client *client = dev->client; + int ret, i; + u16 reg_start_addr; + u8 msb, lsb, reading[4], len; + u32 reading_tmp, mask; reg_start_addr = registers[reg].start_address; msb = registers[reg].msb; lsb = registers[reg].lsb; - page = registers[reg].page; - len = (msb >> 3) + 1; mask = REG_MASK(msb - lsb); - ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len); + ret = rtl2832_bulk_read(client, reg_start_addr, reading, len); if (ret) goto err; @@ -302,40 +214,27 @@ static int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val) *val = (reading_tmp >> lsb) & mask; - return ret; - + return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; - } -static int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val) +static int rtl2832_wr_demod_reg(struct rtl2832_dev *dev, int reg, u32 val) { + struct i2c_client *client = dev->client; int ret, i; - u8 len; - u8 reg_start_addr; - u8 msb, lsb; - u8 page; - u32 mask; - - - u8 reading[4]; - u8 writing[4]; - u32 reading_tmp; - u32 writing_tmp; - + u16 reg_start_addr; + u8 msb, lsb, reading[4], writing[4], len; + u32 reading_tmp, writing_tmp, mask; reg_start_addr = registers[reg].start_address; msb = registers[reg].msb; lsb = registers[reg].lsb; - page = registers[reg].page; - len = (msb >> 3) + 1; mask = REG_MASK(msb - lsb); - - ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len); + ret = rtl2832_bulk_read(client, reg_start_addr, reading, len); if (ret) goto err; @@ -346,49 +245,23 @@ static int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val) writing_tmp = reading_tmp & ~(mask << lsb); writing_tmp |= ((val & mask) << lsb); - for (i = 0; i < len; i++) writing[i] = (writing_tmp >> ((len - 1 - i) * 8)) & 0xff; - ret = rtl2832_wr_regs(priv, reg_start_addr, page, &writing[0], len); + ret = rtl2832_bulk_write(client, reg_start_addr, writing, len); if (ret) goto err; - return ret; - + return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - return ret; - -} - -static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - int ret; - struct rtl2832_priv *priv = fe->demodulator_priv; - - dev_dbg(&priv->i2c->dev, "%s: enable=%d\n", __func__, enable); - - /* gate already open or close */ - if (priv->i2c_gate_state == enable) - return 0; - - ret = rtl2832_wr_demod_reg(priv, DVBT_IIC_REPEAT, (enable ? 0x1 : 0x0)); - if (ret) - goto err; - - priv->i2c_gate_state = enable; - - return ret; -err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } - static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq) { - struct rtl2832_priv *priv = fe->demodulator_priv; + struct rtl2832_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; int ret; u64 pset_iffreq; u8 en_bbin = (if_freq == 0 ? 0x1 : 0x0); @@ -397,30 +270,35 @@ static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq) * PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22) * / CrystalFreqHz) */ - - pset_iffreq = if_freq % priv->cfg.xtal; + pset_iffreq = if_freq % dev->pdata->clk; pset_iffreq *= 0x400000; - pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal); + pset_iffreq = div_u64(pset_iffreq, dev->pdata->clk); pset_iffreq = -pset_iffreq; pset_iffreq = pset_iffreq & 0x3fffff; - dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d pset_iffreq=%08x\n", - __func__, if_freq, (unsigned)pset_iffreq); + dev_dbg(&client->dev, "if_frequency=%d pset_iffreq=%08x\n", + if_freq, (unsigned)pset_iffreq); - ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin); + ret = rtl2832_wr_demod_reg(dev, DVBT_EN_BBIN, en_bbin); if (ret) - return ret; + goto err; - ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq); + ret = rtl2832_wr_demod_reg(dev, DVBT_PSET_IFFREQ, pset_iffreq); + if (ret) + goto err; + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int rtl2832_init(struct dvb_frontend *fe) { - struct rtl2832_priv *priv = fe->demodulator_priv; + struct rtl2832_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; + struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; const struct rtl2832_reg_value *init; int i, ret, len; - /* initialization values for the demodulator registers */ struct rtl2832_reg_value rtl2832_initial_regs[] = { {DVBT_AD_EN_REG, 0x1}, @@ -467,19 +345,19 @@ static int rtl2832_init(struct dvb_frontend *fe) {DVBT_CR_THD_SET2, 0x1}, }; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) { - ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs[i].reg, + ret = rtl2832_wr_demod_reg(dev, rtl2832_initial_regs[i].reg, rtl2832_initial_regs[i].value); if (ret) goto err; } /* load tuner specific settings */ - dev_dbg(&priv->i2c->dev, "%s: load settings for tuner=%02x\n", - __func__, priv->cfg.tuner); - switch (priv->cfg.tuner) { + dev_dbg(&client->dev, "load settings for tuner=%02x\n", + dev->pdata->tuner); + switch (dev->pdata->tuner) { case RTL2832_TUNER_FC0012: case RTL2832_TUNER_FC0013: len = ARRAY_SIZE(rtl2832_tuner_init_fc0012); @@ -504,51 +382,60 @@ static int rtl2832_init(struct dvb_frontend *fe) } for (i = 0; i < len; i++) { - ret = rtl2832_wr_demod_reg(priv, init[i].reg, init[i].value); + ret = rtl2832_wr_demod_reg(dev, init[i].reg, init[i].value); if (ret) goto err; } - /* - * r820t NIM code does a software reset here at the demod - - * may not be needed, as there's already a software reset at - * set_params() - */ -#if 1 - /* soft reset */ - ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1); - if (ret) - goto err; - - ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0); - if (ret) - goto err; -#endif - - priv->sleeping = false; - - return ret; + /* init stats here in order signal app which stats are supported */ + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + /* start statistics polling */ + schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); + dev->sleeping = false; + return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int rtl2832_sleep(struct dvb_frontend *fe) { - struct rtl2832_priv *priv = fe->demodulator_priv; + struct rtl2832_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; + int ret; + + dev_dbg(&client->dev, "\n"); + + dev->sleeping = true; + /* stop statistics polling */ + cancel_delayed_work_sync(&dev->stat_work); + dev->fe_status = 0; + + ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x1); + if (ret) + goto err; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); - priv->sleeping = true; return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; } static int rtl2832_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s) { - struct rtl2832_priv *priv = fe->demodulator_priv; + struct rtl2832_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); s->min_delay_ms = 1000; s->step_size = fe->ops.info.frequency_stepsize * 2; s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; @@ -557,7 +444,8 @@ static int rtl2832_get_tune_settings(struct dvb_frontend *fe, static int rtl2832_set_frontend(struct dvb_frontend *fe) { - struct rtl2832_priv *priv = fe->demodulator_priv; + struct rtl2832_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i, j; u64 bw_mode, num, num2; @@ -588,17 +476,15 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) }, }; - - dev_dbg(&priv->i2c->dev, - "%s: frequency=%d bandwidth_hz=%d inversion=%d\n", - __func__, c->frequency, c->bandwidth_hz, c->inversion); + dev_dbg(&client->dev, "frequency=%u bandwidth_hz=%u inversion=%u\n", + c->frequency, c->bandwidth_hz, c->inversion); /* program tuner */ if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe); /* PIP mode related */ - ret = rtl2832_wr_regs(priv, 0x92, 1, "\x00\x0f\xff", 3); + ret = rtl2832_bulk_write(client, 0x192, "\x00\x0f\xff", 3); if (ret) goto err; @@ -629,12 +515,14 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) bw_mode = 64000000; break; default: - dev_dbg(&priv->i2c->dev, "%s: invalid bandwidth\n", __func__); - return -EINVAL; + dev_err(&client->dev, "invalid bandwidth_hz %u\n", + c->bandwidth_hz); + ret = -EINVAL; + goto err; } for (j = 0; j < sizeof(bw_params[0]); j++) { - ret = rtl2832_wr_regs(priv, 0x1c+j, 1, &bw_params[i][j], 1); + ret = rtl2832_bulk_write(client, 0x11c + j, &bw_params[i][j], 1); if (ret) goto err; } @@ -643,11 +531,11 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) * RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22) * / ConstWithBandwidthMode) */ - num = priv->cfg.xtal * 7; + num = dev->pdata->clk * 7; num *= 0x400000; num = div_u64(num, bw_mode); resamp_ratio = num & 0x3ffffff; - ret = rtl2832_wr_demod_reg(priv, DVBT_RSAMP_RATIO, resamp_ratio); + ret = rtl2832_wr_demod_reg(dev, DVBT_RSAMP_RATIO, resamp_ratio); if (ret) goto err; @@ -656,48 +544,49 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) * / (CrystalFreqHz * 7)) */ num = bw_mode << 20; - num2 = priv->cfg.xtal * 7; + num2 = dev->pdata->clk * 7; num = div_u64(num, num2); num = -num; cfreq_off_ratio = num & 0xfffff; - ret = rtl2832_wr_demod_reg(priv, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio); + ret = rtl2832_wr_demod_reg(dev, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio); if (ret) goto err; /* soft reset */ - ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1); + ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x1); if (ret) goto err; - ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0); + ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x0); if (ret) goto err; - return ret; + return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int rtl2832_get_frontend(struct dvb_frontend *fe) { - struct rtl2832_priv *priv = fe->demodulator_priv; + struct rtl2832_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; u8 buf[3]; - if (priv->sleeping) + if (dev->sleeping) return 0; - ret = rtl2832_rd_regs(priv, 0x3c, 3, buf, 2); + ret = rtl2832_bulk_read(client, 0x33c, buf, 2); if (ret) goto err; - ret = rtl2832_rd_reg(priv, 0x51, 3, &buf[2]); + ret = rtl2832_bulk_read(client, 0x351, &buf[2], 1); if (ret) goto err; - dev_dbg(&priv->i2c->dev, "%s: TPS=%*ph\n", __func__, 3, buf); + dev_dbg(&client->dev, "TPS=%*ph\n", 3, buf); switch ((buf[0] >> 2) & 3) { case 0: @@ -787,361 +676,220 @@ static int rtl2832_get_frontend(struct dvb_frontend *fe) return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status) { - struct rtl2832_priv *priv = fe->demodulator_priv; + struct rtl2832_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; int ret; u32 tmp; - *status = 0; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); - if (priv->sleeping) + dev_dbg(&client->dev, "\n"); + + *status = 0; + if (dev->sleeping) return 0; - ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &tmp); + ret = rtl2832_rd_demod_reg(dev, DVBT_FSM_STAGE, &tmp); if (ret) goto err; if (tmp == 11) { *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - } - /* TODO find out if this is also true for rtl2832? */ - /*else if (tmp == 10) { + } else if (tmp == 10) { *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI; - }*/ + } - return ret; + dev->fe_status = *status; + return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr) { - struct rtl2832_priv *priv = fe->demodulator_priv; - int ret, hierarchy, constellation; - u8 buf[2], tmp; - u16 tmp16; -#define CONSTELLATION_NUM 3 -#define HIERARCHY_NUM 4 - static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = { - { 85387325, 85387325, 85387325, 85387325 }, - { 86676178, 86676178, 87167949, 87795660 }, - { 87659938, 87659938, 87885178, 88241743 }, - }; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; - /* reports SNR in resolution of 0.1 dB */ - - ret = rtl2832_rd_reg(priv, 0x3c, 3, &tmp); - if (ret) - goto err; - - constellation = (tmp >> 2) & 0x03; /* [3:2] */ - if (constellation > CONSTELLATION_NUM - 1) - goto err; - - hierarchy = (tmp >> 4) & 0x07; /* [6:4] */ - if (hierarchy > HIERARCHY_NUM - 1) - goto err; - - ret = rtl2832_rd_regs(priv, 0x0c, 4, buf, 2); - if (ret) - goto err; - - tmp16 = buf[0] << 8 | buf[1]; - - if (tmp16) - *snr = (snr_constant[constellation][hierarchy] - - intlog10(tmp16)) / ((1 << 24) / 100); + /* report SNR in resolution of 0.1 dB */ + if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) + *snr = div_s64(c->cnr.stat[0].svalue, 100); else *snr = 0; return 0; -err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - return ret; } static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber) { - struct rtl2832_priv *priv = fe->demodulator_priv; - int ret; - u8 buf[2]; + struct rtl2832_dev *dev = fe->demodulator_priv; - ret = rtl2832_rd_regs(priv, 0x4e, 3, buf, 2); - if (ret) - goto err; - - *ber = buf[0] << 8 | buf[1]; + *ber = (dev->post_bit_error - dev->post_bit_error_prev); + dev->post_bit_error_prev = dev->post_bit_error; return 0; -err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - return ret; } -static struct dvb_frontend_ops rtl2832_ops; - -static void rtl2832_release(struct dvb_frontend *fe) +static void rtl2832_stat_work(struct work_struct *work) { - struct rtl2832_priv *priv = fe->demodulator_priv; + struct rtl2832_dev *dev = container_of(work, struct rtl2832_dev, stat_work.work); + struct i2c_client *client = dev->client; + struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; + int ret, tmp; + u8 u8tmp, buf[2]; + u16 u16tmp; - dev_dbg(&priv->i2c->dev, "%s:\n", __func__); - cancel_delayed_work_sync(&priv->i2c_gate_work); - i2c_del_mux_adapter(priv->i2c_adapter_tuner); - i2c_del_mux_adapter(priv->i2c_adapter); - kfree(priv); + dev_dbg(&client->dev, "\n"); + + /* signal strength */ + if (dev->fe_status & FE_HAS_SIGNAL) { + /* read digital AGC */ + ret = rtl2832_bulk_read(client, 0x305, &u8tmp, 1); + if (ret) + goto err; + + dev_dbg(&client->dev, "digital agc=%02x", u8tmp); + + u8tmp = ~u8tmp; + u16tmp = u8tmp << 8 | u8tmp << 0; + + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + c->strength.stat[0].uvalue = u16tmp; + } else { + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* CNR */ + if (dev->fe_status & FE_HAS_VITERBI) { + unsigned hierarchy, constellation; + #define CONSTELLATION_NUM 3 + #define HIERARCHY_NUM 4 + static const u32 constant[CONSTELLATION_NUM][HIERARCHY_NUM] = { + {85387325, 85387325, 85387325, 85387325}, + {86676178, 86676178, 87167949, 87795660}, + {87659938, 87659938, 87885178, 88241743}, + }; + + ret = rtl2832_bulk_read(client, 0x33c, &u8tmp, 1); + if (ret) + goto err; + + constellation = (u8tmp >> 2) & 0x03; /* [3:2] */ + if (constellation > CONSTELLATION_NUM - 1) + goto err_schedule_delayed_work; + + hierarchy = (u8tmp >> 4) & 0x07; /* [6:4] */ + if (hierarchy > HIERARCHY_NUM - 1) + goto err_schedule_delayed_work; + + ret = rtl2832_bulk_read(client, 0x40c, buf, 2); + if (ret) + goto err; + + u16tmp = buf[0] << 8 | buf[1] << 0; + if (u16tmp) + tmp = (constant[constellation][hierarchy] - + intlog10(u16tmp)) / ((1 << 24) / 10000); + else + tmp = 0; + + dev_dbg(&client->dev, "cnr raw=%u\n", u16tmp); + + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = tmp; + } else { + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* BER */ + if (dev->fe_status & FE_HAS_LOCK) { + ret = rtl2832_bulk_read(client, 0x34e, buf, 2); + if (ret) + goto err; + + u16tmp = buf[0] << 8 | buf[1] << 0; + dev->post_bit_error += u16tmp; + dev->post_bit_count += 1000000; + + dev_dbg(&client->dev, "ber errors=%u total=1000000\n", u16tmp); + + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue = dev->post_bit_error; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue = dev->post_bit_count; + } else { + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + +err_schedule_delayed_work: + schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); + return; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); } /* - * Delay mechanism to avoid unneeded I2C gate open / close. Gate close is - * delayed here a little bit in order to see if there is sequence of I2C + * I2C gate/mux/repeater logic + * We must use unlocked __i2c_transfer() here (through regmap) because of I2C + * adapter lock is already taken by tuner driver. + * There is delay mechanism to avoid unneeded I2C gate open / close. Gate close + * is delayed here a little bit in order to see if there is sequence of I2C * messages sent to same I2C bus. - * We must use unlocked version of __i2c_transfer() in order to avoid deadlock - * as lock is already taken by calling muxed i2c_transfer(). */ static void rtl2832_i2c_gate_work(struct work_struct *work) { - struct rtl2832_priv *priv = container_of(work, - struct rtl2832_priv, i2c_gate_work.work); - struct i2c_adapter *adap = priv->i2c; + struct rtl2832_dev *dev = container_of(work, struct rtl2832_dev, i2c_gate_work.work); + struct i2c_client *client = dev->client; int ret; - u8 buf[2]; - struct i2c_msg msg[1] = { - { - .addr = priv->cfg.i2c_addr, - .flags = 0, - .len = sizeof(buf), - .buf = buf, - } - }; - /* select reg bank 1 */ - buf[0] = 0x00; - buf[1] = 0x01; - ret = __i2c_transfer(adap, msg, 1); - if (ret != 1) + /* close gate */ + ret = rtl2832_update_bits(dev->client, 0x101, 0x08, 0x00); + if (ret) goto err; - priv->page = 1; - - /* close I2C repeater gate */ - buf[0] = 0x01; - buf[1] = 0x10; - ret = __i2c_transfer(adap, msg, 1); - if (ret != 1) - goto err; - - priv->i2c_gate_state = false; - return; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - - return; + dev_dbg(&client->dev, "failed=%d\n", ret); } static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) { - struct rtl2832_priv *priv = mux_priv; + struct rtl2832_dev *dev = mux_priv; + struct i2c_client *client = dev->client; int ret; - u8 buf[2], val; - struct i2c_msg msg[1] = { - { - .addr = priv->cfg.i2c_addr, - .flags = 0, - .len = sizeof(buf), - .buf = buf, - } - }; - struct i2c_msg msg_rd[2] = { - { - .addr = priv->cfg.i2c_addr, - .flags = 0, - .len = 1, - .buf = "\x01", - }, { - .addr = priv->cfg.i2c_addr, - .flags = I2C_M_RD, - .len = 1, - .buf = &val, - } - }; /* terminate possible gate closing */ - cancel_delayed_work_sync(&priv->i2c_gate_work); + cancel_delayed_work(&dev->i2c_gate_work); - if (priv->i2c_gate_state == chan_id) - return 0; - - /* select reg bank 1 */ - buf[0] = 0x00; - buf[1] = 0x01; - ret = __i2c_transfer(adap, msg, 1); - if (ret != 1) + /* + * I2C adapter lock is already taken and due to that we will use + * regmap_update_bits() which does not lock again I2C adapter. + */ + ret = regmap_update_bits(dev->regmap, 0x101, 0x08, 0x08); + if (ret) goto err; - priv->page = 1; - - /* we must read that register, otherwise there will be errors */ - ret = __i2c_transfer(adap, msg_rd, 2); - if (ret != 2) - goto err; - - /* open or close I2C repeater gate */ - buf[0] = 0x01; - if (chan_id == 1) - buf[1] = 0x18; /* open */ - else - buf[1] = 0x10; /* close */ - - ret = __i2c_transfer(adap, msg, 1); - if (ret != 1) - goto err; - - priv->i2c_gate_state = chan_id; - return 0; err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - - return -EREMOTEIO; + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; } static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv, - u32 chan_id) + u32 chan_id) { - struct rtl2832_priv *priv = mux_priv; - schedule_delayed_work(&priv->i2c_gate_work, usecs_to_jiffies(100)); + struct rtl2832_dev *dev = mux_priv; + + schedule_delayed_work(&dev->i2c_gate_work, usecs_to_jiffies(100)); return 0; } -int rtl2832_enable_external_ts_if(struct dvb_frontend *fe) -{ - struct rtl2832_priv *priv = fe->demodulator_priv; - int ret; - - dev_dbg(&priv->i2c->dev, "%s: setting PIP mode\n", __func__); - - ret = rtl2832_wr_regs(priv, 0x0c, 1, "\x5f\xff", 2); - if (ret) - goto err; - - ret = rtl2832_wr_demod_reg(priv, DVBT_PIP_ON, 0x1); - if (ret) - goto err; - - ret = rtl2832_wr_reg(priv, 0xbc, 0, 0x18); - if (ret) - goto err; - - ret = rtl2832_wr_reg(priv, 0x22, 0, 0x01); - if (ret) - goto err; - - ret = rtl2832_wr_reg(priv, 0x26, 0, 0x1f); - if (ret) - goto err; - - ret = rtl2832_wr_reg(priv, 0x27, 0, 0xff); - if (ret) - goto err; - - ret = rtl2832_wr_regs(priv, 0x92, 1, "\x7f\xf7\xff", 3); - if (ret) - goto err; - - /* soft reset */ - ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1); - if (ret) - goto err; - - ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0); - if (ret) - goto err; - - return 0; -err: - dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); - return ret; - -} -EXPORT_SYMBOL(rtl2832_enable_external_ts_if); - -struct i2c_adapter *rtl2832_get_i2c_adapter(struct dvb_frontend *fe) -{ - struct rtl2832_priv *priv = fe->demodulator_priv; - return priv->i2c_adapter_tuner; -} -EXPORT_SYMBOL(rtl2832_get_i2c_adapter); - -struct i2c_adapter *rtl2832_get_private_i2c_adapter(struct dvb_frontend *fe) -{ - struct rtl2832_priv *priv = fe->demodulator_priv; - return priv->i2c_adapter; -} -EXPORT_SYMBOL(rtl2832_get_private_i2c_adapter); - -struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg, - struct i2c_adapter *i2c) -{ - struct rtl2832_priv *priv = NULL; - int ret = 0; - u8 tmp; - - dev_dbg(&i2c->dev, "%s:\n", __func__); - - /* allocate memory for the internal state */ - priv = kzalloc(sizeof(struct rtl2832_priv), GFP_KERNEL); - if (priv == NULL) - goto err; - - /* setup the priv */ - priv->i2c = i2c; - priv->tuner = cfg->tuner; - memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config)); - INIT_DELAYED_WORK(&priv->i2c_gate_work, rtl2832_i2c_gate_work); - - /* create muxed i2c adapter for demod itself */ - priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0, - rtl2832_select, NULL); - if (priv->i2c_adapter == NULL) - goto err; - - /* check if the demod is there */ - ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp); - if (ret) - goto err; - - /* create muxed i2c adapter for demod tuner bus */ - priv->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, priv, - 0, 1, 0, rtl2832_select, rtl2832_deselect); - if (priv->i2c_adapter_tuner == NULL) - goto err; - - /* create dvb_frontend */ - memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops)); - priv->fe.demodulator_priv = priv; - - /* TODO implement sleep mode */ - priv->sleeping = true; - - return &priv->fe; -err: - dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); - if (priv && priv->i2c_adapter) - i2c_del_mux_adapter(priv->i2c_adapter); - kfree(priv); - return NULL; -} -EXPORT_SYMBOL(rtl2832_attach); - static struct dvb_frontend_ops rtl2832_ops = { .delsys = { SYS_DVBT }, .info = { @@ -1166,8 +914,6 @@ static struct dvb_frontend_ops rtl2832_ops = { FE_CAN_MUTE_TS }, - .release = rtl2832_release, - .init = rtl2832_init, .sleep = rtl2832_sleep, @@ -1179,11 +925,403 @@ static struct dvb_frontend_ops rtl2832_ops = { .read_status = rtl2832_read_status, .read_snr = rtl2832_read_snr, .read_ber = rtl2832_read_ber, - - .i2c_gate_ctrl = rtl2832_i2c_gate_ctrl, }; +static bool rtl2832_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x305: + case 0x33c: + case 0x34e: + case 0x351: + case 0x40c ... 0x40d: + return true; + default: + break; + } + + return false; +} + +/* + * We implement own I2C access routines for regmap in order to get manual access + * to I2C adapter lock, which is needed for I2C mux adapter. + */ +static int rtl2832_regmap_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, size_t val_size) +{ + struct i2c_client *client = context; + int ret; + struct i2c_msg msg[2] = { + { + .addr = client->addr, + .flags = 0, + .len = reg_size, + .buf = (u8 *)reg_buf, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .len = val_size, + .buf = val_buf, + } + }; + + ret = __i2c_transfer(client->adapter, msg, 2); + if (ret != 2) { + dev_warn(&client->dev, "i2c reg read failed %d\n", ret); + if (ret >= 0) + ret = -EREMOTEIO; + return ret; + } + return 0; +} + +static int rtl2832_regmap_write(void *context, const void *data, size_t count) +{ + struct i2c_client *client = context; + int ret; + struct i2c_msg msg[1] = { + { + .addr = client->addr, + .flags = 0, + .len = count, + .buf = (u8 *)data, + } + }; + + ret = __i2c_transfer(client->adapter, msg, 1); + if (ret != 1) { + dev_warn(&client->dev, "i2c reg write failed %d\n", ret); + if (ret >= 0) + ret = -EREMOTEIO; + return ret; + } + return 0; +} + +static int rtl2832_regmap_gather_write(void *context, const void *reg, + size_t reg_len, const void *val, + size_t val_len) +{ + struct i2c_client *client = context; + int ret; + u8 buf[256]; + struct i2c_msg msg[1] = { + { + .addr = client->addr, + .flags = 0, + .len = 1 + val_len, + .buf = buf, + } + }; + + buf[0] = *(u8 const *)reg; + memcpy(&buf[1], val, val_len); + + ret = __i2c_transfer(client->adapter, msg, 1); + if (ret != 1) { + dev_warn(&client->dev, "i2c reg write failed %d\n", ret); + if (ret >= 0) + ret = -EREMOTEIO; + return ret; + } + return 0; +} + +/* + * FIXME: Hack. Implement own regmap locking in order to silence lockdep + * recursive lock warning. That happens when regmap I2C client calls I2C mux + * adapter, which leads demod I2C repeater enable via demod regmap. Operation + * takes two regmap locks recursively - but those are different regmap instances + * in a two different I2C drivers, so it is not deadlock. Proper fix is to make + * regmap aware of lockdep. + */ +static void rtl2832_regmap_lock(void *__dev) +{ + struct rtl2832_dev *dev = __dev; + struct i2c_client *client = dev->client; + + dev_dbg(&client->dev, "\n"); + mutex_lock(&dev->regmap_mutex); +} + +static void rtl2832_regmap_unlock(void *__dev) +{ + struct rtl2832_dev *dev = __dev; + struct i2c_client *client = dev->client; + + dev_dbg(&client->dev, "\n"); + mutex_unlock(&dev->regmap_mutex); +} + +static struct dvb_frontend *rtl2832_get_dvb_frontend(struct i2c_client *client) +{ + struct rtl2832_dev *dev = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + return &dev->fe; +} + +static struct i2c_adapter *rtl2832_get_i2c_adapter(struct i2c_client *client) +{ + struct rtl2832_dev *dev = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + return dev->i2c_adapter_tuner; +} + +static int rtl2832_enable_slave_ts(struct i2c_client *client) +{ + struct rtl2832_dev *dev = i2c_get_clientdata(client); + int ret; + + dev_dbg(&client->dev, "\n"); + + ret = rtl2832_bulk_write(client, 0x10c, "\x5f\xff", 2); + if (ret) + goto err; + + ret = rtl2832_wr_demod_reg(dev, DVBT_PIP_ON, 0x1); + if (ret) + goto err; + + ret = rtl2832_bulk_write(client, 0x0bc, "\x18", 1); + if (ret) + goto err; + + ret = rtl2832_bulk_write(client, 0x022, "\x01", 1); + if (ret) + goto err; + + ret = rtl2832_bulk_write(client, 0x026, "\x1f", 1); + if (ret) + goto err; + + ret = rtl2832_bulk_write(client, 0x027, "\xff", 1); + if (ret) + goto err; + + ret = rtl2832_bulk_write(client, 0x192, "\x7f\xf7\xff", 3); + if (ret) + goto err; + + /* soft reset */ + ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x1); + if (ret) + goto err; + + ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x0); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +static int rtl2832_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct rtl2832_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; + int ret; + u8 u8tmp; + + dev_dbg(&client->dev, "onoff=%d\n", onoff); + + /* enable / disable PID filter */ + if (onoff) + u8tmp = 0x80; + else + u8tmp = 0x00; + + ret = rtl2832_update_bits(client, 0x061, 0xc0, u8tmp); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +static int rtl2832_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, + int onoff) +{ + struct rtl2832_dev *dev = fe->demodulator_priv; + struct i2c_client *client = dev->client; + int ret; + u8 buf[4]; + + dev_dbg(&client->dev, "index=%d pid=%04x onoff=%d\n", + index, pid, onoff); + + /* skip invalid PIDs (0x2000) */ + if (pid > 0x1fff || index > 32) + return 0; + + if (onoff) + set_bit(index, &dev->filters); + else + clear_bit(index, &dev->filters); + + /* enable / disable PIDs */ + buf[0] = (dev->filters >> 0) & 0xff; + buf[1] = (dev->filters >> 8) & 0xff; + buf[2] = (dev->filters >> 16) & 0xff; + buf[3] = (dev->filters >> 24) & 0xff; + ret = rtl2832_bulk_write(client, 0x062, buf, 4); + if (ret) + goto err; + + /* add PID */ + buf[0] = (pid >> 8) & 0xff; + buf[1] = (pid >> 0) & 0xff; + ret = rtl2832_bulk_write(client, 0x066 + 2 * index, buf, 2); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +static int rtl2832_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct rtl2832_platform_data *pdata = client->dev.platform_data; + struct i2c_adapter *i2c = client->adapter; + struct rtl2832_dev *dev; + int ret; + u8 tmp; + static const struct regmap_bus regmap_bus = { + .read = rtl2832_regmap_read, + .write = rtl2832_regmap_write, + .gather_write = rtl2832_regmap_gather_write, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, + }; + static const struct regmap_range_cfg regmap_range_cfg[] = { + { + .selector_reg = 0x00, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = 0x100, + .range_min = 0 * 0x100, + .range_max = 5 * 0x100, + }, + }; + + dev_dbg(&client->dev, "\n"); + + /* allocate memory for the internal state */ + dev = kzalloc(sizeof(struct rtl2832_dev), GFP_KERNEL); + if (dev == NULL) { + ret = -ENOMEM; + goto err; + } + + /* setup the state */ + i2c_set_clientdata(client, dev); + dev->client = client; + dev->pdata = client->dev.platform_data; + dev->sleeping = true; + INIT_DELAYED_WORK(&dev->i2c_gate_work, rtl2832_i2c_gate_work); + INIT_DELAYED_WORK(&dev->stat_work, rtl2832_stat_work); + /* create regmap */ + mutex_init(&dev->regmap_mutex); + dev->regmap_config.reg_bits = 8, + dev->regmap_config.val_bits = 8, + dev->regmap_config.lock = rtl2832_regmap_lock, + dev->regmap_config.unlock = rtl2832_regmap_unlock, + dev->regmap_config.lock_arg = dev, + dev->regmap_config.volatile_reg = rtl2832_volatile_reg, + dev->regmap_config.max_register = 5 * 0x100, + dev->regmap_config.ranges = regmap_range_cfg, + dev->regmap_config.num_ranges = ARRAY_SIZE(regmap_range_cfg), + dev->regmap_config.cache_type = REGCACHE_RBTREE, + dev->regmap = regmap_init(&client->dev, ®map_bus, client, + &dev->regmap_config); + if (IS_ERR(dev->regmap)) { + ret = PTR_ERR(dev->regmap); + goto err_kfree; + } + + /* check if the demod is there */ + ret = rtl2832_bulk_read(client, 0x000, &tmp, 1); + if (ret) + goto err_regmap_exit; + + /* create muxed i2c adapter for demod tuner bus */ + dev->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, dev, + 0, 0, 0, rtl2832_select, rtl2832_deselect); + if (dev->i2c_adapter_tuner == NULL) { + ret = -ENODEV; + goto err_regmap_exit; + } + + /* create dvb_frontend */ + memcpy(&dev->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops)); + dev->fe.demodulator_priv = dev; + + /* setup callbacks */ + pdata->get_dvb_frontend = rtl2832_get_dvb_frontend; + pdata->get_i2c_adapter = rtl2832_get_i2c_adapter; + pdata->enable_slave_ts = rtl2832_enable_slave_ts; + pdata->pid_filter = rtl2832_pid_filter; + pdata->pid_filter_ctrl = rtl2832_pid_filter_ctrl; + pdata->bulk_read = rtl2832_bulk_read; + pdata->bulk_write = rtl2832_bulk_write; + pdata->update_bits = rtl2832_update_bits; + + dev_info(&client->dev, "Realtek RTL2832 successfully attached\n"); + return 0; +err_regmap_exit: + regmap_exit(dev->regmap); +err_kfree: + kfree(dev); +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +static int rtl2832_remove(struct i2c_client *client) +{ + struct rtl2832_dev *dev = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + cancel_delayed_work_sync(&dev->i2c_gate_work); + + i2c_del_mux_adapter(dev->i2c_adapter_tuner); + + regmap_exit(dev->regmap); + + kfree(dev); + + return 0; +} + +static const struct i2c_device_id rtl2832_id_table[] = { + {"rtl2832", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, rtl2832_id_table); + +static struct i2c_driver rtl2832_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "rtl2832", + }, + .probe = rtl2832_probe, + .remove = rtl2832_remove, + .id_table = rtl2832_id_table, +}; + +module_i2c_driver(rtl2832_driver); + MODULE_AUTHOR("Thomas Mair "); +MODULE_AUTHOR("Antti Palosaari "); MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION("0.5"); diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h index 5254c1dfc8de..a8e912e679a5 100644 --- a/drivers/media/dvb-frontends/rtl2832.h +++ b/drivers/media/dvb-frontends/rtl2832.h @@ -2,6 +2,7 @@ * Realtek RTL2832 DVB-T demodulator driver * * Copyright (C) 2012 Thomas Mair + * Copyright (C) 2012-2014 Antti Palosaari * * 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 @@ -21,86 +22,42 @@ #ifndef RTL2832_H #define RTL2832_H -#include #include +#include -struct rtl2832_config { - /* - * Demodulator I2C address. - */ - u8 i2c_addr; +/** + * struct rtl2832_platform_data - Platform data for the rtl2832 driver + * @clk: Clock frequency (4000000, 16000000, 25000000, 28800000). + * @tuner: Used tuner model. + * @get_dvb_frontend: Get DVB frontend. + * @get_i2c_adapter: Get I2C adapter. + * @enable_slave_ts: Enable slave TS IF. + * @pid_filter: Set PID to PID filter. + * @pid_filter_ctrl: Control PID filter. + */ +struct rtl2832_platform_data { + u32 clk; /* - * Xtal frequency. - * Hz - * 4000000, 16000000, 25000000, 28800000 - */ - u32 xtal; - - /* - * tuner - * XXX: This must be keep sync with dvb_usb_rtl28xxu demod driver. + * XXX: This list must be kept sync with dvb_usb_rtl28xxu USB IF driver. */ #define RTL2832_TUNER_TUA9001 0x24 #define RTL2832_TUNER_FC0012 0x26 #define RTL2832_TUNER_E4000 0x27 #define RTL2832_TUNER_FC0013 0x29 -#define RTL2832_TUNER_R820T 0x2a -#define RTL2832_TUNER_R828D 0x2b +#define RTL2832_TUNER_R820T 0x2a +#define RTL2832_TUNER_R828D 0x2b u8 tuner; + + struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); + struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *); + int (*enable_slave_ts)(struct i2c_client *); + int (*pid_filter)(struct dvb_frontend *, u8, u16, int); + int (*pid_filter_ctrl)(struct dvb_frontend *, int); +/* private: Register access for SDR module use only */ + int (*bulk_read)(struct i2c_client *, unsigned int, void *, size_t); + int (*bulk_write)(struct i2c_client *, unsigned int, const void *, size_t); + int (*update_bits)(struct i2c_client *, unsigned int, unsigned int, unsigned int); }; -#if IS_ENABLED(CONFIG_DVB_RTL2832) -struct dvb_frontend *rtl2832_attach( - const struct rtl2832_config *cfg, - struct i2c_adapter *i2c -); - -extern struct i2c_adapter *rtl2832_get_i2c_adapter( - struct dvb_frontend *fe -); - -extern struct i2c_adapter *rtl2832_get_private_i2c_adapter( - struct dvb_frontend *fe -); - -extern int rtl2832_enable_external_ts_if( - struct dvb_frontend *fe -); - -#else - -static inline struct dvb_frontend *rtl2832_attach( - const struct rtl2832_config *config, - struct i2c_adapter *i2c -) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline struct i2c_adapter *rtl2832_get_i2c_adapter( - struct dvb_frontend *fe -) -{ - return NULL; -} - -static inline struct i2c_adapter *rtl2832_get_private_i2c_adapter( - struct dvb_frontend *fe -) -{ - return NULL; -} - -static inline int rtl2832_enable_external_ts_if( - struct dvb_frontend *fe -) -{ - return -ENODEV; -} - -#endif - - #endif /* RTL2832_H */ diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h index ae469f032fe6..c3a922c37903 100644 --- a/drivers/media/dvb-frontends/rtl2832_priv.h +++ b/drivers/media/dvb-frontends/rtl2832_priv.h @@ -2,6 +2,7 @@ * Realtek RTL2832 DVB-T demodulator driver * * Copyright (C) 2012 Thomas Mair + * Copyright (C) 2012-2014 Antti Palosaari * * 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 @@ -21,28 +22,34 @@ #ifndef RTL2832_PRIV_H #define RTL2832_PRIV_H -#include "dvb_frontend.h" -#include "rtl2832.h" -#include +#include +#include +#include -struct rtl2832_priv { - struct i2c_adapter *i2c; - struct i2c_adapter *i2c_adapter; +#include "dvb_frontend.h" +#include "dvb_math.h" +#include "rtl2832.h" + +struct rtl2832_dev { + struct rtl2832_platform_data *pdata; + struct i2c_client *client; + struct mutex regmap_mutex; + struct regmap_config regmap_config; + struct regmap *regmap; struct i2c_adapter *i2c_adapter_tuner; struct dvb_frontend fe; - struct rtl2832_config cfg; - - bool i2c_gate_state; + struct delayed_work stat_work; + fe_status_t fe_status; + u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */ + u64 post_bit_error; + u64 post_bit_count; bool sleeping; - - u8 tuner; - u8 page; /* active register page */ struct delayed_work i2c_gate_work; + unsigned long filters; /* PID filter */ }; struct rtl2832_reg_entry { - u8 page; - u8 start_address; + u16 start_address; u8 msb; u8 lsb; }; @@ -52,7 +59,6 @@ struct rtl2832_reg_value { u32 value; }; - /* Demod register bit names */ enum DVBT_REG_BIT_NAME { DVBT_SOFT_RST, diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 2896b47c29d8..3ff8806ca584 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -22,7 +22,6 @@ * */ -#include "dvb_frontend.h" #include "rtl2832_sdr.h" #include "dvb_usb.h" @@ -32,6 +31,7 @@ #include #include +#include #include #include @@ -107,16 +107,12 @@ struct rtl2832_sdr_frame_buf { struct list_head list; }; -struct rtl2832_sdr_state { +struct rtl2832_sdr_dev { #define POWER_ON (1 << 1) #define URB_BUF (1 << 2) unsigned long flags; - const struct rtl2832_config *cfg; - struct dvb_frontend *fe; - struct dvb_usb_device *d; - struct i2c_adapter *i2c; - u8 bank; + struct platform_device *pdev; struct video_device vdev; struct v4l2_device v4l2_dev; @@ -160,200 +156,77 @@ struct rtl2832_sdr_state { unsigned long jiffies_next; }; -/* write multiple hardware registers */ -static int rtl2832_sdr_wr(struct rtl2832_sdr_state *s, u8 reg, const u8 *val, - int len) -{ - int ret; -#define MAX_WR_LEN 24 -#define MAX_WR_XFER_LEN (MAX_WR_LEN + 1) - u8 buf[MAX_WR_XFER_LEN]; - struct i2c_msg msg[1] = { - { - .addr = s->cfg->i2c_addr, - .flags = 0, - .len = 1 + len, - .buf = buf, - } - }; - - if (WARN_ON(len > MAX_WR_LEN)) - return -EINVAL; - - buf[0] = reg; - memcpy(&buf[1], val, len); - - ret = i2c_transfer(s->i2c, msg, 1); - if (ret == 1) { - ret = 0; - } else { - dev_err(&s->i2c->dev, - "%s: I2C wr failed=%d reg=%02x len=%d\n", - KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } - return ret; -} - -/* read multiple hardware registers */ -static int rtl2832_sdr_rd(struct rtl2832_sdr_state *s, u8 reg, u8 *val, int len) -{ - int ret; - struct i2c_msg msg[2] = { - { - .addr = s->cfg->i2c_addr, - .flags = 0, - .len = 1, - .buf = ®, - }, { - .addr = s->cfg->i2c_addr, - .flags = I2C_M_RD, - .len = len, - .buf = val, - } - }; - - ret = i2c_transfer(s->i2c, msg, 2); - if (ret == 2) { - ret = 0; - } else { - dev_err(&s->i2c->dev, - "%s: I2C rd failed=%d reg=%02x len=%d\n", - KBUILD_MODNAME, ret, reg, len); - ret = -EREMOTEIO; - } - return ret; -} - /* write multiple registers */ -static int rtl2832_sdr_wr_regs(struct rtl2832_sdr_state *s, u16 reg, +static int rtl2832_sdr_wr_regs(struct rtl2832_sdr_dev *dev, u16 reg, const u8 *val, int len) { - int ret; - u8 reg2 = (reg >> 0) & 0xff; - u8 bank = (reg >> 8) & 0xff; + struct platform_device *pdev = dev->pdev; + struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data; + struct i2c_client *client = pdata->i2c_client; - /* switch bank if needed */ - if (bank != s->bank) { - ret = rtl2832_sdr_wr(s, 0x00, &bank, 1); - if (ret) - return ret; - - s->bank = bank; - } - - return rtl2832_sdr_wr(s, reg2, val, len); + return pdata->bulk_write(client, reg, val, len); } +#if 0 /* read multiple registers */ -static int rtl2832_sdr_rd_regs(struct rtl2832_sdr_state *s, u16 reg, u8 *val, +static int rtl2832_sdr_rd_regs(struct rtl2832_sdr_dev *dev, u16 reg, u8 *val, int len) { - int ret; - u8 reg2 = (reg >> 0) & 0xff; - u8 bank = (reg >> 8) & 0xff; + struct platform_device *pdev = dev->pdev; + struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data; + struct i2c_client *client = pdata->i2c_client; - /* switch bank if needed */ - if (bank != s->bank) { - ret = rtl2832_sdr_wr(s, 0x00, &bank, 1); - if (ret) - return ret; - - s->bank = bank; - } - - return rtl2832_sdr_rd(s, reg2, val, len); + return pdata->bulk_read(client, reg, val, len); } +#endif /* write single register */ -static int rtl2832_sdr_wr_reg(struct rtl2832_sdr_state *s, u16 reg, u8 val) +static int rtl2832_sdr_wr_reg(struct rtl2832_sdr_dev *dev, u16 reg, u8 val) { - return rtl2832_sdr_wr_regs(s, reg, &val, 1); + return rtl2832_sdr_wr_regs(dev, reg, &val, 1); } -#if 0 -/* read single register */ -static int rtl2832_sdr_rd_reg(struct rtl2832_sdr_state *s, u16 reg, u8 *val) -{ - return rtl2832_sdr_rd_regs(s, reg, val, 1); -} -#endif - /* write single register with mask */ -static int rtl2832_sdr_wr_reg_mask(struct rtl2832_sdr_state *s, u16 reg, +static int rtl2832_sdr_wr_reg_mask(struct rtl2832_sdr_dev *dev, u16 reg, u8 val, u8 mask) { - int ret; - u8 tmp; + struct platform_device *pdev = dev->pdev; + struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data; + struct i2c_client *client = pdata->i2c_client; - /* no need for read if whole reg is written */ - if (mask != 0xff) { - ret = rtl2832_sdr_rd_regs(s, reg, &tmp, 1); - if (ret) - return ret; - - val &= mask; - tmp &= ~mask; - val |= tmp; - } - - return rtl2832_sdr_wr_regs(s, reg, &val, 1); + return pdata->update_bits(client, reg, mask, val); } -#if 0 -/* read single register with mask */ -static int rtl2832_sdr_rd_reg_mask(struct rtl2832_sdr_state *s, u16 reg, - u8 *val, u8 mask) -{ - int ret, i; - u8 tmp; - - ret = rtl2832_sdr_rd_regs(s, reg, &tmp, 1); - if (ret) - return ret; - - tmp &= mask; - - /* find position of the first bit */ - for (i = 0; i < 8; i++) { - if ((mask >> i) & 0x01) - break; - } - *val = tmp >> i; - - return 0; -} -#endif - /* Private functions */ static struct rtl2832_sdr_frame_buf *rtl2832_sdr_get_next_fill_buf( - struct rtl2832_sdr_state *s) + struct rtl2832_sdr_dev *dev) { unsigned long flags; struct rtl2832_sdr_frame_buf *buf = NULL; - spin_lock_irqsave(&s->queued_bufs_lock, flags); - if (list_empty(&s->queued_bufs)) + spin_lock_irqsave(&dev->queued_bufs_lock, flags); + if (list_empty(&dev->queued_bufs)) goto leave; - buf = list_entry(s->queued_bufs.next, + buf = list_entry(dev->queued_bufs.next, struct rtl2832_sdr_frame_buf, list); list_del(&buf->list); leave: - spin_unlock_irqrestore(&s->queued_bufs_lock, flags); + spin_unlock_irqrestore(&dev->queued_bufs_lock, flags); return buf; } -static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s, +static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_dev *dev, void *dst, const u8 *src, unsigned int src_len) { + struct platform_device *pdev = dev->pdev; unsigned int dst_len; - if (s->pixelformat == V4L2_SDR_FMT_CU8) { + if (dev->pixelformat == V4L2_SDR_FMT_CU8) { /* native stream, no need to convert */ memcpy(dst, src, src_len); dst_len = src_len; - } else if (s->pixelformat == V4L2_SDR_FMT_CU16LE) { + } else if (dev->pixelformat == V4L2_SDR_FMT_CU16LE) { /* convert u8 to u16 */ unsigned int i; u16 *u16dst = dst; @@ -366,22 +239,21 @@ static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s, } /* calculate sample rate and output it in 10 seconds intervals */ - if (unlikely(time_is_before_jiffies(s->jiffies_next))) { + if (unlikely(time_is_before_jiffies(dev->jiffies_next))) { #define MSECS 10000UL unsigned int msecs = jiffies_to_msecs(jiffies - - s->jiffies_next + msecs_to_jiffies(MSECS)); - unsigned int samples = s->sample - s->sample_measured; + dev->jiffies_next + msecs_to_jiffies(MSECS)); + unsigned int samples = dev->sample - dev->sample_measured; - s->jiffies_next = jiffies + msecs_to_jiffies(MSECS); - s->sample_measured = s->sample; - dev_dbg(&s->udev->dev, - "slen=%u samples=%u msecs=%u sample rate=%lu\n", - src_len, samples, msecs, - samples * 1000UL / msecs); + dev->jiffies_next = jiffies + msecs_to_jiffies(MSECS); + dev->sample_measured = dev->sample; + dev_dbg(&pdev->dev, + "slen=%u samples=%u msecs=%u sample rate=%lu\n", + src_len, samples, msecs, samples * 1000UL / msecs); } /* total number of I+Q pairs */ - s->sample += src_len / 2; + dev->sample += src_len / 2; return dst_len; } @@ -392,13 +264,13 @@ static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s, */ static void rtl2832_sdr_urb_complete(struct urb *urb) { - struct rtl2832_sdr_state *s = urb->context; + struct rtl2832_sdr_dev *dev = urb->context; + struct platform_device *pdev = dev->pdev; struct rtl2832_sdr_frame_buf *fbuf; - dev_dbg_ratelimited(&s->udev->dev, - "status=%d length=%d/%d errors=%d\n", - urb->status, urb->actual_length, - urb->transfer_buffer_length, urb->error_count); + dev_dbg_ratelimited(&pdev->dev, "status=%d length=%d/%d errors=%d\n", + urb->status, urb->actual_length, + urb->transfer_buffer_length, urb->error_count); switch (urb->status) { case 0: /* success */ @@ -409,8 +281,7 @@ static void rtl2832_sdr_urb_complete(struct urb *urb) case -ESHUTDOWN: return; default: /* error */ - dev_err_ratelimited(&s->udev->dev, "urb failed=%d\n", - urb->status); + dev_err_ratelimited(&pdev->dev, "urb failed=%d\n", urb->status); break; } @@ -418,204 +289,192 @@ static void rtl2832_sdr_urb_complete(struct urb *urb) void *ptr; unsigned int len; /* get free framebuffer */ - fbuf = rtl2832_sdr_get_next_fill_buf(s); + fbuf = rtl2832_sdr_get_next_fill_buf(dev); if (unlikely(fbuf == NULL)) { - s->vb_full++; - dev_notice_ratelimited(&s->udev->dev, - "videobuf is full, %d packets dropped\n", - s->vb_full); + dev->vb_full++; + dev_notice_ratelimited(&pdev->dev, + "videobuf is full, %d packets dropped\n", + dev->vb_full); goto skip; } /* fill framebuffer */ ptr = vb2_plane_vaddr(&fbuf->vb, 0); - len = rtl2832_sdr_convert_stream(s, ptr, urb->transfer_buffer, + len = rtl2832_sdr_convert_stream(dev, ptr, urb->transfer_buffer, urb->actual_length); vb2_set_plane_payload(&fbuf->vb, 0, len); v4l2_get_timestamp(&fbuf->vb.v4l2_buf.timestamp); - fbuf->vb.v4l2_buf.sequence = s->sequence++; + fbuf->vb.v4l2_buf.sequence = dev->sequence++; vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE); } skip: usb_submit_urb(urb, GFP_ATOMIC); } -static int rtl2832_sdr_kill_urbs(struct rtl2832_sdr_state *s) +static int rtl2832_sdr_kill_urbs(struct rtl2832_sdr_dev *dev) { + struct platform_device *pdev = dev->pdev; int i; - for (i = s->urbs_submitted - 1; i >= 0; i--) { - dev_dbg(&s->udev->dev, "kill urb=%d\n", i); + for (i = dev->urbs_submitted - 1; i >= 0; i--) { + dev_dbg(&pdev->dev, "kill urb=%d\n", i); /* stop the URB */ - usb_kill_urb(s->urb_list[i]); + usb_kill_urb(dev->urb_list[i]); } - s->urbs_submitted = 0; + dev->urbs_submitted = 0; return 0; } -static int rtl2832_sdr_submit_urbs(struct rtl2832_sdr_state *s) +static int rtl2832_sdr_submit_urbs(struct rtl2832_sdr_dev *dev) { + struct platform_device *pdev = dev->pdev; int i, ret; - for (i = 0; i < s->urbs_initialized; i++) { - dev_dbg(&s->udev->dev, "submit urb=%d\n", i); - ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC); + for (i = 0; i < dev->urbs_initialized; i++) { + dev_dbg(&pdev->dev, "submit urb=%d\n", i); + ret = usb_submit_urb(dev->urb_list[i], GFP_ATOMIC); if (ret) { - dev_err(&s->udev->dev, - "Could not submit urb no. %d - get them all back\n", - i); - rtl2832_sdr_kill_urbs(s); + dev_err(&pdev->dev, + "Could not submit urb no. %d - get them all back\n", + i); + rtl2832_sdr_kill_urbs(dev); return ret; } - s->urbs_submitted++; + dev->urbs_submitted++; } return 0; } -static int rtl2832_sdr_free_stream_bufs(struct rtl2832_sdr_state *s) +static int rtl2832_sdr_free_stream_bufs(struct rtl2832_sdr_dev *dev) { - if (s->flags & USB_STATE_URB_BUF) { - while (s->buf_num) { - s->buf_num--; - dev_dbg(&s->udev->dev, "free buf=%d\n", s->buf_num); - usb_free_coherent(s->udev, s->buf_size, - s->buf_list[s->buf_num], - s->dma_addr[s->buf_num]); + struct platform_device *pdev = dev->pdev; + + if (dev->flags & USB_STATE_URB_BUF) { + while (dev->buf_num) { + dev->buf_num--; + dev_dbg(&pdev->dev, "free buf=%d\n", dev->buf_num); + usb_free_coherent(dev->udev, dev->buf_size, + dev->buf_list[dev->buf_num], + dev->dma_addr[dev->buf_num]); } } - s->flags &= ~USB_STATE_URB_BUF; + dev->flags &= ~USB_STATE_URB_BUF; return 0; } -static int rtl2832_sdr_alloc_stream_bufs(struct rtl2832_sdr_state *s) +static int rtl2832_sdr_alloc_stream_bufs(struct rtl2832_sdr_dev *dev) { - s->buf_num = 0; - s->buf_size = BULK_BUFFER_SIZE; + struct platform_device *pdev = dev->pdev; - dev_dbg(&s->udev->dev, "all in all I will use %u bytes for streaming\n", - MAX_BULK_BUFS * BULK_BUFFER_SIZE); + dev->buf_num = 0; + dev->buf_size = BULK_BUFFER_SIZE; - for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) { - s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev, + dev_dbg(&pdev->dev, "all in all I will use %u bytes for streaming\n", + MAX_BULK_BUFS * BULK_BUFFER_SIZE); + + for (dev->buf_num = 0; dev->buf_num < MAX_BULK_BUFS; dev->buf_num++) { + dev->buf_list[dev->buf_num] = usb_alloc_coherent(dev->udev, BULK_BUFFER_SIZE, GFP_ATOMIC, - &s->dma_addr[s->buf_num]); - if (!s->buf_list[s->buf_num]) { - dev_dbg(&s->udev->dev, "alloc buf=%d failed\n", - s->buf_num); - rtl2832_sdr_free_stream_bufs(s); + &dev->dma_addr[dev->buf_num]); + if (!dev->buf_list[dev->buf_num]) { + dev_dbg(&pdev->dev, "alloc buf=%d failed\n", + dev->buf_num); + rtl2832_sdr_free_stream_bufs(dev); return -ENOMEM; } - dev_dbg(&s->udev->dev, "alloc buf=%d %p (dma %llu)\n", - s->buf_num, s->buf_list[s->buf_num], - (long long)s->dma_addr[s->buf_num]); - s->flags |= USB_STATE_URB_BUF; + dev_dbg(&pdev->dev, "alloc buf=%d %p (dma %llu)\n", + dev->buf_num, dev->buf_list[dev->buf_num], + (long long)dev->dma_addr[dev->buf_num]); + dev->flags |= USB_STATE_URB_BUF; } return 0; } -static int rtl2832_sdr_free_urbs(struct rtl2832_sdr_state *s) +static int rtl2832_sdr_free_urbs(struct rtl2832_sdr_dev *dev) { + struct platform_device *pdev = dev->pdev; int i; - rtl2832_sdr_kill_urbs(s); + rtl2832_sdr_kill_urbs(dev); - for (i = s->urbs_initialized - 1; i >= 0; i--) { - if (s->urb_list[i]) { - dev_dbg(&s->udev->dev, "free urb=%d\n", i); + for (i = dev->urbs_initialized - 1; i >= 0; i--) { + if (dev->urb_list[i]) { + dev_dbg(&pdev->dev, "free urb=%d\n", i); /* free the URBs */ - usb_free_urb(s->urb_list[i]); + usb_free_urb(dev->urb_list[i]); } } - s->urbs_initialized = 0; + dev->urbs_initialized = 0; return 0; } -static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s) +static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_dev *dev) { + struct platform_device *pdev = dev->pdev; int i, j; /* allocate the URBs */ for (i = 0; i < MAX_BULK_BUFS; i++) { - dev_dbg(&s->udev->dev, "alloc urb=%d\n", i); - s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); - if (!s->urb_list[i]) { - dev_dbg(&s->udev->dev, "failed\n"); + dev_dbg(&pdev->dev, "alloc urb=%d\n", i); + dev->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); + if (!dev->urb_list[i]) { + dev_dbg(&pdev->dev, "failed\n"); for (j = 0; j < i; j++) - usb_free_urb(s->urb_list[j]); + usb_free_urb(dev->urb_list[j]); return -ENOMEM; } - usb_fill_bulk_urb(s->urb_list[i], - s->udev, - usb_rcvbulkpipe(s->udev, 0x81), - s->buf_list[i], + usb_fill_bulk_urb(dev->urb_list[i], + dev->udev, + usb_rcvbulkpipe(dev->udev, 0x81), + dev->buf_list[i], BULK_BUFFER_SIZE, - rtl2832_sdr_urb_complete, s); + rtl2832_sdr_urb_complete, dev); - s->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; - s->urb_list[i]->transfer_dma = s->dma_addr[i]; - s->urbs_initialized++; + dev->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + dev->urb_list[i]->transfer_dma = dev->dma_addr[i]; + dev->urbs_initialized++; } return 0; } /* Must be called with vb_queue_lock hold */ -static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s) +static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_dev *dev) { + struct platform_device *pdev = dev->pdev; unsigned long flags; - dev_dbg(&s->udev->dev, "\n"); + dev_dbg(&pdev->dev, "\n"); - spin_lock_irqsave(&s->queued_bufs_lock, flags); - while (!list_empty(&s->queued_bufs)) { + spin_lock_irqsave(&dev->queued_bufs_lock, flags); + while (!list_empty(&dev->queued_bufs)) { struct rtl2832_sdr_frame_buf *buf; - buf = list_entry(s->queued_bufs.next, + buf = list_entry(dev->queued_bufs.next, struct rtl2832_sdr_frame_buf, list); list_del(&buf->list); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - spin_unlock_irqrestore(&s->queued_bufs_lock, flags); -} - -/* The user yanked out the cable... */ -static void rtl2832_sdr_release_sec(struct dvb_frontend *fe) -{ - struct rtl2832_sdr_state *s = fe->sec_priv; - - dev_dbg(&s->udev->dev, "\n"); - - mutex_lock(&s->vb_queue_lock); - mutex_lock(&s->v4l2_lock); - /* No need to keep the urbs around after disconnection */ - s->udev = NULL; - - v4l2_device_disconnect(&s->v4l2_dev); - video_unregister_device(&s->vdev); - mutex_unlock(&s->v4l2_lock); - mutex_unlock(&s->vb_queue_lock); - - v4l2_device_put(&s->v4l2_dev); - - fe->sec_priv = NULL; + spin_unlock_irqrestore(&dev->queued_bufs_lock, flags); } static int rtl2832_sdr_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct rtl2832_sdr_state *s = video_drvdata(file); + struct rtl2832_sdr_dev *dev = video_drvdata(file); + struct platform_device *pdev = dev->pdev; - dev_dbg(&s->udev->dev, "\n"); + dev_dbg(&pdev->dev, "\n"); strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); - strlcpy(cap->card, s->vdev.name, sizeof(cap->card)); - usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info)); + strlcpy(cap->card, dev->vdev.name, sizeof(cap->card)); + usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | V4L2_CAP_TUNER; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; @@ -627,26 +486,26 @@ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq); + struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq); + struct platform_device *pdev = dev->pdev; - dev_dbg(&s->udev->dev, "nbuffers=%d\n", *nbuffers); + dev_dbg(&pdev->dev, "nbuffers=%d\n", *nbuffers); /* Need at least 8 buffers */ if (vq->num_buffers + *nbuffers < 8) *nbuffers = 8 - vq->num_buffers; *nplanes = 1; - sizes[0] = PAGE_ALIGN(s->buffersize); - dev_dbg(&s->udev->dev, "nbuffers=%d sizes[0]=%d\n", - *nbuffers, sizes[0]); + sizes[0] = PAGE_ALIGN(dev->buffersize); + dev_dbg(&pdev->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]); return 0; } static int rtl2832_sdr_buf_prepare(struct vb2_buffer *vb) { - struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue); + struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vb->vb2_queue); /* Don't allow queing new buffers after device disconnection */ - if (!s->udev) + if (!dev->udev) return -ENODEV; return 0; @@ -654,46 +513,48 @@ static int rtl2832_sdr_buf_prepare(struct vb2_buffer *vb) static void rtl2832_sdr_buf_queue(struct vb2_buffer *vb) { - struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue); + struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vb->vb2_queue); struct rtl2832_sdr_frame_buf *buf = container_of(vb, struct rtl2832_sdr_frame_buf, vb); unsigned long flags; /* Check the device has not disconnected between prep and queuing */ - if (!s->udev) { + if (!dev->udev) { vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); return; } - spin_lock_irqsave(&s->queued_bufs_lock, flags); - list_add_tail(&buf->list, &s->queued_bufs); - spin_unlock_irqrestore(&s->queued_bufs_lock, flags); + spin_lock_irqsave(&dev->queued_bufs_lock, flags); + list_add_tail(&buf->list, &dev->queued_bufs); + spin_unlock_irqrestore(&dev->queued_bufs_lock, flags); } -static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s) +static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev) { - struct dvb_frontend *fe = s->fe; + struct platform_device *pdev = dev->pdev; + struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data; + struct dvb_frontend *fe = pdata->dvb_frontend; int ret; unsigned int f_sr, f_if; u8 buf[4], u8tmp1, u8tmp2; u64 u64tmp; u32 u32tmp; - dev_dbg(&s->udev->dev, "f_adc=%u\n", s->f_adc); + dev_dbg(&pdev->dev, "f_adc=%u\n", dev->f_adc); - if (!test_bit(POWER_ON, &s->flags)) + if (!test_bit(POWER_ON, &dev->flags)) return 0; - if (s->f_adc == 0) + if (dev->f_adc == 0) return 0; - f_sr = s->f_adc; + f_sr = dev->f_adc; - ret = rtl2832_sdr_wr_regs(s, 0x13e, "\x00\x00", 2); + ret = rtl2832_sdr_wr_regs(dev, 0x13e, "\x00\x00", 2); if (ret) goto err; - ret = rtl2832_sdr_wr_regs(s, 0x115, "\x00\x00\x00\x00", 4); + ret = rtl2832_sdr_wr_regs(dev, 0x115, "\x00\x00\x00\x00", 4); if (ret) goto err; @@ -707,19 +568,19 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s) goto err; /* program IF */ - u64tmp = f_if % s->cfg->xtal; + u64tmp = f_if % pdata->clk; u64tmp *= 0x400000; - u64tmp = div_u64(u64tmp, s->cfg->xtal); + u64tmp = div_u64(u64tmp, pdata->clk); u64tmp = -u64tmp; u32tmp = u64tmp & 0x3fffff; - dev_dbg(&s->udev->dev, "f_if=%u if_ctl=%08x\n", f_if, u32tmp); + dev_dbg(&pdev->dev, "f_if=%u if_ctl=%08x\n", f_if, u32tmp); buf[0] = (u32tmp >> 16) & 0xff; buf[1] = (u32tmp >> 8) & 0xff; buf[2] = (u32tmp >> 0) & 0xff; - ret = rtl2832_sdr_wr_regs(s, 0x119, buf, 3); + ret = rtl2832_sdr_wr_regs(dev, 0x119, buf, 3); if (ret) goto err; @@ -733,208 +594,212 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s) u8tmp2 = 0xcd; /* enable ADC I, ADC Q */ } - ret = rtl2832_sdr_wr_reg(s, 0x1b1, u8tmp1); + ret = rtl2832_sdr_wr_reg(dev, 0x1b1, u8tmp1); if (ret) goto err; - ret = rtl2832_sdr_wr_reg(s, 0x008, u8tmp2); + ret = rtl2832_sdr_wr_reg(dev, 0x008, u8tmp2); if (ret) goto err; - ret = rtl2832_sdr_wr_reg(s, 0x006, 0x80); + ret = rtl2832_sdr_wr_reg(dev, 0x006, 0x80); if (ret) goto err; /* program sampling rate (resampling down) */ - u32tmp = div_u64(s->cfg->xtal * 0x400000ULL, f_sr * 4U); + u32tmp = div_u64(pdata->clk * 0x400000ULL, f_sr * 4U); u32tmp <<= 2; buf[0] = (u32tmp >> 24) & 0xff; buf[1] = (u32tmp >> 16) & 0xff; buf[2] = (u32tmp >> 8) & 0xff; buf[3] = (u32tmp >> 0) & 0xff; - ret = rtl2832_sdr_wr_regs(s, 0x19f, buf, 4); + ret = rtl2832_sdr_wr_regs(dev, 0x19f, buf, 4); if (ret) goto err; /* low-pass filter */ - ret = rtl2832_sdr_wr_regs(s, 0x11c, + ret = rtl2832_sdr_wr_regs(dev, 0x11c, "\xca\xdc\xd7\xd8\xe0\xf2\x0e\x35\x06\x50\x9c\x0d\x71\x11\x14\x71\x74\x19\x41\xa5", 20); if (ret) goto err; - ret = rtl2832_sdr_wr_regs(s, 0x017, "\x11\x10", 2); + ret = rtl2832_sdr_wr_regs(dev, 0x017, "\x11\x10", 2); if (ret) goto err; /* mode */ - ret = rtl2832_sdr_wr_regs(s, 0x019, "\x05", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x019, "\x05", 1); if (ret) goto err; - ret = rtl2832_sdr_wr_regs(s, 0x01a, "\x1b\x16\x0d\x06\x01\xff", 6); + ret = rtl2832_sdr_wr_regs(dev, 0x01a, "\x1b\x16\x0d\x06\x01\xff", 6); if (ret) goto err; /* FSM */ - ret = rtl2832_sdr_wr_regs(s, 0x192, "\x00\xf0\x0f", 3); + ret = rtl2832_sdr_wr_regs(dev, 0x192, "\x00\xf0\x0f", 3); if (ret) goto err; /* PID filter */ - ret = rtl2832_sdr_wr_regs(s, 0x061, "\x60", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x061, "\x60", 1); if (ret) goto err; /* used RF tuner based settings */ - switch (s->cfg->tuner) { - case RTL2832_TUNER_E4000: - ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1); - ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1); - ret = rtl2832_sdr_wr_regs(s, 0x103, "\x5a", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x30", 1); - ret = rtl2832_sdr_wr_regs(s, 0x104, "\xd0", 1); - ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x18", 1); - ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1); - ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1); - ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1); - ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1); - ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1); - ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1); - ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1); - ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1); - ret = rtl2832_sdr_wr_regs(s, 0x011, "\xd4", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1e5, "\xf0", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1d9, "\x00", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1db, "\x00", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1dd, "\x14", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1de, "\xec", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1d8, "\x0c", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1e6, "\x02", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1d7, "\x09", 1); - ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x83", 1); - ret = rtl2832_sdr_wr_regs(s, 0x010, "\x49", 1); - ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x87", 1); - ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x85", 1); - ret = rtl2832_sdr_wr_regs(s, 0x013, "\x02", 1); + switch (pdata->tuner) { + case RTL2832_SDR_TUNER_E4000: + ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x5a", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x30", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xd0", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x18", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x80", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xd4", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1e5, "\xf0", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1d9, "\x00", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1db, "\x00", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1dd, "\x14", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1de, "\xec", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1d8, "\x0c", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1e6, "\x02", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1d7, "\x09", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x00d, "\x83", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x010, "\x49", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x00d, "\x87", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x00d, "\x85", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x013, "\x02", 1); break; - case RTL2832_TUNER_FC0012: - case RTL2832_TUNER_FC0013: - ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1); - ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1); - ret = rtl2832_sdr_wr_regs(s, 0x103, "\x5a", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x2c", 1); - ret = rtl2832_sdr_wr_regs(s, 0x104, "\xcc", 1); - ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x16", 1); - ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1); - ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1); - ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1); - ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1); - ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1); - ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1); - ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1); - ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1); - ret = rtl2832_sdr_wr_regs(s, 0x011, "\xe9\xbf", 2); - ret = rtl2832_sdr_wr_regs(s, 0x1e5, "\xf0", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1d9, "\x00", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1db, "\x00", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1dd, "\x11", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1de, "\xef", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1d8, "\x0c", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1e6, "\x02", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1d7, "\x09", 1); + case RTL2832_SDR_TUNER_FC0012: + case RTL2832_SDR_TUNER_FC0013: + ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x5a", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x2c", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xcc", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x16", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x80", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xe9\xbf", 2); + ret = rtl2832_sdr_wr_regs(dev, 0x1e5, "\xf0", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1d9, "\x00", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1db, "\x00", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1dd, "\x11", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1de, "\xef", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1d8, "\x0c", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1e6, "\x02", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1d7, "\x09", 1); break; - case RTL2832_TUNER_R820T: - ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1); - ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1); - ret = rtl2832_sdr_wr_regs(s, 0x115, "\x01", 1); - ret = rtl2832_sdr_wr_regs(s, 0x103, "\x80", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x24", 1); - ret = rtl2832_sdr_wr_regs(s, 0x104, "\xcc", 1); - ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x14", 1); - ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1); - ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1); - ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1); - ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1); - ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1); - ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1); - ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1); - ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1); - ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1); - ret = rtl2832_sdr_wr_regs(s, 0x011, "\xf4", 1); + case RTL2832_SDR_TUNER_R820T: + case RTL2832_SDR_TUNER_R828D: + ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x115, "\x01", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x80", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x24", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xcc", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x14", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x80", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xf4", 1); break; default: - dev_notice(&s->udev->dev, "Unsupported tuner\n"); + dev_notice(&pdev->dev, "Unsupported tuner\n"); } /* software reset */ - ret = rtl2832_sdr_wr_reg_mask(s, 0x101, 0x04, 0x04); + ret = rtl2832_sdr_wr_reg_mask(dev, 0x101, 0x04, 0x04); if (ret) goto err; - ret = rtl2832_sdr_wr_reg_mask(s, 0x101, 0x00, 0x04); + ret = rtl2832_sdr_wr_reg_mask(dev, 0x101, 0x00, 0x04); if (ret) goto err; err: return ret; }; -static void rtl2832_sdr_unset_adc(struct rtl2832_sdr_state *s) +static void rtl2832_sdr_unset_adc(struct rtl2832_sdr_dev *dev) { + struct platform_device *pdev = dev->pdev; int ret; - dev_dbg(&s->udev->dev, "\n"); + dev_dbg(&pdev->dev, "\n"); /* PID filter */ - ret = rtl2832_sdr_wr_regs(s, 0x061, "\xe0", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x061, "\xe0", 1); if (ret) goto err; /* mode */ - ret = rtl2832_sdr_wr_regs(s, 0x019, "\x20", 1); + ret = rtl2832_sdr_wr_regs(dev, 0x019, "\x20", 1); if (ret) goto err; - ret = rtl2832_sdr_wr_regs(s, 0x017, "\x11\x10", 2); + ret = rtl2832_sdr_wr_regs(dev, 0x017, "\x11\x10", 2); if (ret) goto err; /* FSM */ - ret = rtl2832_sdr_wr_regs(s, 0x192, "\x00\x0f\xff", 3); + ret = rtl2832_sdr_wr_regs(dev, 0x192, "\x00\x0f\xff", 3); if (ret) goto err; - ret = rtl2832_sdr_wr_regs(s, 0x13e, "\x40\x00", 2); + ret = rtl2832_sdr_wr_regs(dev, 0x13e, "\x40\x00", 2); if (ret) goto err; - ret = rtl2832_sdr_wr_regs(s, 0x115, "\x06\x3f\xce\xcc", 4); + ret = rtl2832_sdr_wr_regs(dev, 0x115, "\x06\x3f\xce\xcc", 4); if (ret) goto err; err: return; }; -static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s) +static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_dev *dev) { - struct dvb_frontend *fe = s->fe; + struct platform_device *pdev = dev->pdev; + struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data; + struct dvb_frontend *fe = pdata->dvb_frontend; struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct v4l2_ctrl *bandwidth_auto; struct v4l2_ctrl *bandwidth; @@ -942,29 +807,29 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s) /* * tuner RF (Hz) */ - if (s->f_tuner == 0) + if (dev->f_tuner == 0) return 0; /* * bandwidth (Hz) */ - bandwidth_auto = v4l2_ctrl_find(&s->hdl, + bandwidth_auto = v4l2_ctrl_find(&dev->hdl, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO); - bandwidth = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH); + bandwidth = v4l2_ctrl_find(&dev->hdl, V4L2_CID_RF_TUNER_BANDWIDTH); if (v4l2_ctrl_g_ctrl(bandwidth_auto)) { - c->bandwidth_hz = s->f_adc; - v4l2_ctrl_s_ctrl(bandwidth, s->f_adc); + c->bandwidth_hz = dev->f_adc; + v4l2_ctrl_s_ctrl(bandwidth, dev->f_adc); } else { c->bandwidth_hz = v4l2_ctrl_g_ctrl(bandwidth); } - c->frequency = s->f_tuner; + c->frequency = dev->f_tuner; c->delivery_system = SYS_DVBT; - dev_dbg(&s->udev->dev, "frequency=%u bandwidth=%d\n", - c->frequency, c->bandwidth_hz); + dev_dbg(&pdev->dev, "frequency=%u bandwidth=%d\n", + c->frequency, c->bandwidth_hz); - if (!test_bit(POWER_ON, &s->flags)) + if (!test_bit(POWER_ON, &dev->flags)) return 0; if (fe->ops.tuner_ops.set_params) @@ -973,11 +838,13 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s) return 0; }; -static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_state *s) +static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_dev *dev) { - struct dvb_frontend *fe = s->fe; + struct platform_device *pdev = dev->pdev; + struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data; + struct dvb_frontend *fe = pdata->dvb_frontend; - dev_dbg(&s->udev->dev, "\n"); + dev_dbg(&pdev->dev, "\n"); if (fe->ops.tuner_ops.init) fe->ops.tuner_ops.init(fe); @@ -985,11 +852,13 @@ static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_state *s) return 0; }; -static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_state *s) +static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_dev *dev) { - struct dvb_frontend *fe = s->fe; + struct platform_device *pdev = dev->pdev; + struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data; + struct dvb_frontend *fe = pdata->dvb_frontend; - dev_dbg(&s->udev->dev, "\n"); + dev_dbg(&pdev->dev, "\n"); if (fe->ops.tuner_ops.sleep) fe->ops.tuner_ops.sleep(fe); @@ -999,83 +868,89 @@ static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_state *s) static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count) { - struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq); + struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq); + struct platform_device *pdev = dev->pdev; + struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data; + struct dvb_usb_device *d = pdata->dvb_usb_device; int ret; - dev_dbg(&s->udev->dev, "\n"); + dev_dbg(&pdev->dev, "\n"); - if (!s->udev) + if (!dev->udev) return -ENODEV; - if (mutex_lock_interruptible(&s->v4l2_lock)) + if (mutex_lock_interruptible(&dev->v4l2_lock)) return -ERESTARTSYS; - if (s->d->props->power_ctrl) - s->d->props->power_ctrl(s->d, 1); + if (d->props->power_ctrl) + d->props->power_ctrl(d, 1); /* enable ADC */ - if (s->d->props->frontend_ctrl) - s->d->props->frontend_ctrl(s->fe, 1); + if (d->props->frontend_ctrl) + d->props->frontend_ctrl(pdata->dvb_frontend, 1); - set_bit(POWER_ON, &s->flags); + set_bit(POWER_ON, &dev->flags); - ret = rtl2832_sdr_set_tuner(s); + ret = rtl2832_sdr_set_tuner(dev); if (ret) goto err; - ret = rtl2832_sdr_set_tuner_freq(s); + ret = rtl2832_sdr_set_tuner_freq(dev); if (ret) goto err; - ret = rtl2832_sdr_set_adc(s); + ret = rtl2832_sdr_set_adc(dev); if (ret) goto err; - ret = rtl2832_sdr_alloc_stream_bufs(s); + ret = rtl2832_sdr_alloc_stream_bufs(dev); if (ret) goto err; - ret = rtl2832_sdr_alloc_urbs(s); + ret = rtl2832_sdr_alloc_urbs(dev); if (ret) goto err; - s->sequence = 0; + dev->sequence = 0; - ret = rtl2832_sdr_submit_urbs(s); + ret = rtl2832_sdr_submit_urbs(dev); if (ret) goto err; err: - mutex_unlock(&s->v4l2_lock); + mutex_unlock(&dev->v4l2_lock); return ret; } static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq) { - struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq); + struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq); + struct platform_device *pdev = dev->pdev; + struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data; + struct dvb_usb_device *d = pdata->dvb_usb_device; - dev_dbg(&s->udev->dev, "\n"); + dev_dbg(&pdev->dev, "\n"); - mutex_lock(&s->v4l2_lock); + mutex_lock(&dev->v4l2_lock); - rtl2832_sdr_kill_urbs(s); - rtl2832_sdr_free_urbs(s); - rtl2832_sdr_free_stream_bufs(s); - rtl2832_sdr_cleanup_queued_bufs(s); - rtl2832_sdr_unset_adc(s); - rtl2832_sdr_unset_tuner(s); + rtl2832_sdr_kill_urbs(dev); + rtl2832_sdr_free_urbs(dev); + rtl2832_sdr_free_stream_bufs(dev); + rtl2832_sdr_cleanup_queued_bufs(dev); + rtl2832_sdr_unset_adc(dev); + rtl2832_sdr_unset_tuner(dev); - clear_bit(POWER_ON, &s->flags); + clear_bit(POWER_ON, &dev->flags); /* disable ADC */ - if (s->d->props->frontend_ctrl) - s->d->props->frontend_ctrl(s->fe, 0); + if (d->props->frontend_ctrl) + d->props->frontend_ctrl(pdata->dvb_frontend, 0); - if (s->d->props->power_ctrl) - s->d->props->power_ctrl(s->d, 0); + if (d->props->power_ctrl) + d->props->power_ctrl(d, 0); - mutex_unlock(&s->v4l2_lock); + mutex_unlock(&dev->v4l2_lock); } static struct vb2_ops rtl2832_sdr_vb2_ops = { @@ -1091,9 +966,10 @@ static struct vb2_ops rtl2832_sdr_vb2_ops = { static int rtl2832_sdr_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct rtl2832_sdr_state *s = video_drvdata(file); + struct rtl2832_sdr_dev *dev = video_drvdata(file); + struct platform_device *pdev = dev->pdev; - dev_dbg(&s->udev->dev, "index=%d type=%d\n", v->index, v->type); + dev_dbg(&pdev->dev, "index=%d type=%d\n", v->index, v->type); if (v->index == 0) { strlcpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name)); @@ -1117,9 +993,10 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv, static int rtl2832_sdr_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *v) { - struct rtl2832_sdr_state *s = video_drvdata(file); + struct rtl2832_sdr_dev *dev = video_drvdata(file); + struct platform_device *pdev = dev->pdev; - dev_dbg(&s->udev->dev, "\n"); + dev_dbg(&pdev->dev, "\n"); if (v->index > 1) return -EINVAL; @@ -1129,10 +1006,11 @@ static int rtl2832_sdr_s_tuner(struct file *file, void *priv, static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv, struct v4l2_frequency_band *band) { - struct rtl2832_sdr_state *s = video_drvdata(file); + struct rtl2832_sdr_dev *dev = video_drvdata(file); + struct platform_device *pdev = dev->pdev; - dev_dbg(&s->udev->dev, "tuner=%d type=%d index=%d\n", - band->tuner, band->type, band->index); + dev_dbg(&pdev->dev, "tuner=%d type=%d index=%d\n", + band->tuner, band->type, band->index); if (band->tuner == 0) { if (band->index >= ARRAY_SIZE(bands_adc)) @@ -1154,17 +1032,17 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv, static int rtl2832_sdr_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct rtl2832_sdr_state *s = video_drvdata(file); + struct rtl2832_sdr_dev *dev = video_drvdata(file); + struct platform_device *pdev = dev->pdev; int ret = 0; - dev_dbg(&s->udev->dev, "tuner=%d type=%d\n", - f->tuner, f->type); + dev_dbg(&pdev->dev, "tuner=%d type=%d\n", f->tuner, f->type); if (f->tuner == 0) { - f->frequency = s->f_adc; + f->frequency = dev->f_adc; f->type = V4L2_TUNER_ADC; } else if (f->tuner == 1) { - f->frequency = s->f_tuner; + f->frequency = dev->f_tuner; f->type = V4L2_TUNER_RF; } else { return -EINVAL; @@ -1176,11 +1054,12 @@ static int rtl2832_sdr_g_frequency(struct file *file, void *priv, static int rtl2832_sdr_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { - struct rtl2832_sdr_state *s = video_drvdata(file); + struct rtl2832_sdr_dev *dev = video_drvdata(file); + struct platform_device *pdev = dev->pdev; int ret, band; - dev_dbg(&s->udev->dev, "tuner=%d type=%d frequency=%u\n", - f->tuner, f->type, f->frequency); + dev_dbg(&pdev->dev, "tuner=%d type=%d frequency=%u\n", + f->tuner, f->type, f->frequency); /* ADC band midpoints */ #define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2) @@ -1194,19 +1073,19 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv, else band = 2; - s->f_adc = clamp_t(unsigned int, f->frequency, + dev->f_adc = clamp_t(unsigned int, f->frequency, bands_adc[band].rangelow, bands_adc[band].rangehigh); - dev_dbg(&s->udev->dev, "ADC frequency=%u Hz\n", s->f_adc); - ret = rtl2832_sdr_set_adc(s); + dev_dbg(&pdev->dev, "ADC frequency=%u Hz\n", dev->f_adc); + ret = rtl2832_sdr_set_adc(dev); } else if (f->tuner == 1) { - s->f_tuner = clamp_t(unsigned int, f->frequency, + dev->f_tuner = clamp_t(unsigned int, f->frequency, bands_fm[0].rangelow, bands_fm[0].rangehigh); - dev_dbg(&s->udev->dev, "RF frequency=%u Hz\n", f->frequency); + dev_dbg(&pdev->dev, "RF frequency=%u Hz\n", f->frequency); - ret = rtl2832_sdr_set_tuner_freq(s); + ret = rtl2832_sdr_set_tuner_freq(dev); } else { ret = -EINVAL; } @@ -1217,11 +1096,12 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv, static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct rtl2832_sdr_state *s = video_drvdata(file); + struct rtl2832_sdr_dev *dev = video_drvdata(file); + struct platform_device *pdev = dev->pdev; - dev_dbg(&s->udev->dev, "\n"); + dev_dbg(&pdev->dev, "\n"); - if (f->index >= s->num_formats) + if (f->index >= dev->num_formats) return -EINVAL; strlcpy(f->description, formats[f->index].name, sizeof(f->description)); @@ -1233,12 +1113,13 @@ static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv, static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct rtl2832_sdr_state *s = video_drvdata(file); + struct rtl2832_sdr_dev *dev = video_drvdata(file); + struct platform_device *pdev = dev->pdev; - dev_dbg(&s->udev->dev, "\n"); + dev_dbg(&pdev->dev, "\n"); - f->fmt.sdr.pixelformat = s->pixelformat; - f->fmt.sdr.buffersize = s->buffersize; + f->fmt.sdr.pixelformat = dev->pixelformat; + f->fmt.sdr.buffersize = dev->buffersize; memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); @@ -1248,28 +1129,29 @@ static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv, static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct rtl2832_sdr_state *s = video_drvdata(file); - struct vb2_queue *q = &s->vb_queue; + struct rtl2832_sdr_dev *dev = video_drvdata(file); + struct platform_device *pdev = dev->pdev; + struct vb2_queue *q = &dev->vb_queue; int i; - dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n", - (char *)&f->fmt.sdr.pixelformat); + dev_dbg(&pdev->dev, "pixelformat fourcc %4.4s\n", + (char *)&f->fmt.sdr.pixelformat); if (vb2_is_busy(q)) return -EBUSY; memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); - for (i = 0; i < s->num_formats; i++) { + for (i = 0; i < dev->num_formats; i++) { if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { - s->pixelformat = formats[i].pixelformat; - s->buffersize = formats[i].buffersize; + dev->pixelformat = formats[i].pixelformat; + dev->buffersize = formats[i].buffersize; f->fmt.sdr.buffersize = formats[i].buffersize; return 0; } } - s->pixelformat = formats[0].pixelformat; - s->buffersize = formats[0].buffersize; + dev->pixelformat = formats[0].pixelformat; + dev->buffersize = formats[0].buffersize; f->fmt.sdr.pixelformat = formats[0].pixelformat; f->fmt.sdr.buffersize = formats[0].buffersize; @@ -1279,14 +1161,15 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv, static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct rtl2832_sdr_state *s = video_drvdata(file); + struct rtl2832_sdr_dev *dev = video_drvdata(file); + struct platform_device *pdev = dev->pdev; int i; - dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n", - (char *)&f->fmt.sdr.pixelformat); + dev_dbg(&pdev->dev, "pixelformat fourcc %4.4s\n", + (char *)&f->fmt.sdr.pixelformat); memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); - for (i = 0; i < s->num_formats; i++) { + for (i = 0; i < dev->num_formats; i++) { if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { f->fmt.sdr.buffersize = formats[i].buffersize; return 0; @@ -1348,37 +1231,38 @@ static struct video_device rtl2832_sdr_template = { static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl) { - struct rtl2832_sdr_state *s = - container_of(ctrl->handler, struct rtl2832_sdr_state, + struct rtl2832_sdr_dev *dev = + container_of(ctrl->handler, struct rtl2832_sdr_dev, hdl); - struct dvb_frontend *fe = s->fe; + struct platform_device *pdev = dev->pdev; + struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data; + struct dvb_frontend *fe = pdata->dvb_frontend; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - dev_dbg(&s->udev->dev, - "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n", - ctrl->id, ctrl->name, ctrl->val, - ctrl->minimum, ctrl->maximum, ctrl->step); + dev_dbg(&pdev->dev, "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n", + ctrl->id, ctrl->name, ctrl->val, ctrl->minimum, ctrl->maximum, + ctrl->step); switch (ctrl->id) { case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: case V4L2_CID_RF_TUNER_BANDWIDTH: /* TODO: these controls should be moved to tuner drivers */ - if (s->bandwidth_auto->val) { + if (dev->bandwidth_auto->val) { /* Round towards the closest legal value */ - s32 val = s->f_adc + div_u64(s->bandwidth->step, 2); + s32 val = dev->f_adc + div_u64(dev->bandwidth->step, 2); u32 offset; - val = clamp_t(s32, val, s->bandwidth->minimum, - s->bandwidth->maximum); - offset = val - s->bandwidth->minimum; - offset = s->bandwidth->step * - div_u64(offset, s->bandwidth->step); - s->bandwidth->val = s->bandwidth->minimum + offset; + val = clamp_t(s32, val, dev->bandwidth->minimum, + dev->bandwidth->maximum); + offset = val - dev->bandwidth->minimum; + offset = dev->bandwidth->step * + div_u64(offset, dev->bandwidth->step); + dev->bandwidth->val = dev->bandwidth->minimum + offset; } - c->bandwidth_hz = s->bandwidth->val; + c->bandwidth_hz = dev->bandwidth->val; - if (!test_bit(POWER_ON, &s->flags)) + if (!test_bit(POWER_ON, &dev->flags)) return 0; if (fe->ops.tuner_ops.set_params) @@ -1399,154 +1283,195 @@ static const struct v4l2_ctrl_ops rtl2832_sdr_ctrl_ops = { static void rtl2832_sdr_video_release(struct v4l2_device *v) { - struct rtl2832_sdr_state *s = - container_of(v, struct rtl2832_sdr_state, v4l2_dev); + struct rtl2832_sdr_dev *dev = + container_of(v, struct rtl2832_sdr_dev, v4l2_dev); + struct platform_device *pdev = dev->pdev; - v4l2_ctrl_handler_free(&s->hdl); - v4l2_device_unregister(&s->v4l2_dev); - kfree(s); + dev_dbg(&pdev->dev, "\n"); + + v4l2_ctrl_handler_free(&dev->hdl); + v4l2_device_unregister(&dev->v4l2_dev); + kfree(dev); } -struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, const struct rtl2832_config *cfg, - struct v4l2_subdev *sd) +/* Platform driver interface */ +static int rtl2832_sdr_probe(struct platform_device *pdev) { - int ret; - struct rtl2832_sdr_state *s; + struct rtl2832_sdr_dev *dev; + struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data; const struct v4l2_ctrl_ops *ops = &rtl2832_sdr_ctrl_ops; - struct dvb_usb_device *d = i2c_get_adapdata(i2c); + struct v4l2_subdev *subdev; + int ret; - s = kzalloc(sizeof(struct rtl2832_sdr_state), GFP_KERNEL); - if (s == NULL) { - dev_err(&d->udev->dev, - "Could not allocate memory for rtl2832_sdr_state\n"); - return NULL; + dev_dbg(&pdev->dev, "\n"); + + if (!pdata) { + dev_err(&pdev->dev, "Cannot proceed without platform data\n"); + ret = -EINVAL; + goto err; + } + if (!pdev->dev.parent->driver) { + dev_dbg(&pdev->dev, "No parent device\n"); + ret = -EINVAL; + goto err; + } + /* try to refcount host drv since we are the consumer */ + if (!try_module_get(pdev->dev.parent->driver->owner)) { + dev_err(&pdev->dev, "Refcount fail"); + ret = -EINVAL; + goto err; + } + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + ret = -ENOMEM; + goto err_module_put; } /* setup the state */ - s->fe = fe; - s->d = d; - s->udev = d->udev; - s->i2c = i2c; - s->cfg = cfg; - s->f_adc = bands_adc[0].rangelow; - s->f_tuner = bands_fm[0].rangelow; - s->pixelformat = formats[0].pixelformat; - s->buffersize = formats[0].buffersize; - s->num_formats = NUM_FORMATS; + subdev = pdata->v4l2_subdev; + dev->pdev = pdev; + dev->udev = pdata->dvb_usb_device->udev; + dev->f_adc = bands_adc[0].rangelow; + dev->f_tuner = bands_fm[0].rangelow; + dev->pixelformat = formats[0].pixelformat; + dev->buffersize = formats[0].buffersize; + dev->num_formats = NUM_FORMATS; if (!rtl2832_sdr_emulated_fmt) - s->num_formats -= 1; + dev->num_formats -= 1; - mutex_init(&s->v4l2_lock); - mutex_init(&s->vb_queue_lock); - spin_lock_init(&s->queued_bufs_lock); - INIT_LIST_HEAD(&s->queued_bufs); + mutex_init(&dev->v4l2_lock); + mutex_init(&dev->vb_queue_lock); + spin_lock_init(&dev->queued_bufs_lock); + INIT_LIST_HEAD(&dev->queued_bufs); /* Init videobuf2 queue structure */ - s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE; - s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; - s->vb_queue.drv_priv = s; - s->vb_queue.buf_struct_size = sizeof(struct rtl2832_sdr_frame_buf); - s->vb_queue.ops = &rtl2832_sdr_vb2_ops; - s->vb_queue.mem_ops = &vb2_vmalloc_memops; - s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - ret = vb2_queue_init(&s->vb_queue); + dev->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE; + dev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; + dev->vb_queue.drv_priv = dev; + dev->vb_queue.buf_struct_size = sizeof(struct rtl2832_sdr_frame_buf); + dev->vb_queue.ops = &rtl2832_sdr_vb2_ops; + dev->vb_queue.mem_ops = &vb2_vmalloc_memops; + dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + ret = vb2_queue_init(&dev->vb_queue); if (ret) { - dev_err(&s->udev->dev, "Could not initialize vb2 queue\n"); - goto err_free_mem; + dev_err(&pdev->dev, "Could not initialize vb2 queue\n"); + goto err_kfree; } /* Register controls */ - switch (s->cfg->tuner) { - case RTL2832_TUNER_E4000: - v4l2_ctrl_handler_init(&s->hdl, 9); - if (sd) - v4l2_ctrl_add_handler(&s->hdl, sd->ctrl_handler, NULL); + switch (pdata->tuner) { + case RTL2832_SDR_TUNER_E4000: + v4l2_ctrl_handler_init(&dev->hdl, 9); + if (subdev) + v4l2_ctrl_add_handler(&dev->hdl, subdev->ctrl_handler, NULL); break; - case RTL2832_TUNER_R820T: - v4l2_ctrl_handler_init(&s->hdl, 2); - s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, - V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, - 0, 1, 1, 1); - s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, - V4L2_CID_RF_TUNER_BANDWIDTH, - 0, 8000000, 100000, 0); - v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false); + case RTL2832_SDR_TUNER_R820T: + case RTL2832_SDR_TUNER_R828D: + v4l2_ctrl_handler_init(&dev->hdl, 2); + dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, ops, + V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, + 0, 1, 1, 1); + dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, ops, + V4L2_CID_RF_TUNER_BANDWIDTH, + 0, 8000000, 100000, 0); + v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false); break; - case RTL2832_TUNER_FC0012: - case RTL2832_TUNER_FC0013: - v4l2_ctrl_handler_init(&s->hdl, 2); - s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, - V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, - 0, 1, 1, 1); - s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, - V4L2_CID_RF_TUNER_BANDWIDTH, - 6000000, 8000000, 1000000, - 6000000); - v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false); + case RTL2832_SDR_TUNER_FC0012: + case RTL2832_SDR_TUNER_FC0013: + v4l2_ctrl_handler_init(&dev->hdl, 2); + dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, ops, + V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, + 0, 1, 1, 1); + dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, ops, + V4L2_CID_RF_TUNER_BANDWIDTH, + 6000000, 8000000, 1000000, + 6000000); + v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false); break; default: - v4l2_ctrl_handler_init(&s->hdl, 0); - dev_notice(&s->udev->dev, "%s: Unsupported tuner\n", - KBUILD_MODNAME); - goto err_free_controls; + v4l2_ctrl_handler_init(&dev->hdl, 0); + dev_err(&pdev->dev, "Unsupported tuner\n"); + goto err_v4l2_ctrl_handler_free; } - - if (s->hdl.error) { - ret = s->hdl.error; - dev_err(&s->udev->dev, "Could not initialize controls\n"); - goto err_free_controls; + if (dev->hdl.error) { + ret = dev->hdl.error; + dev_err(&pdev->dev, "Could not initialize controls\n"); + goto err_v4l2_ctrl_handler_free; } /* Init video_device structure */ - s->vdev = rtl2832_sdr_template; - s->vdev.queue = &s->vb_queue; - s->vdev.queue->lock = &s->vb_queue_lock; - video_set_drvdata(&s->vdev, s); + dev->vdev = rtl2832_sdr_template; + dev->vdev.queue = &dev->vb_queue; + dev->vdev.queue->lock = &dev->vb_queue_lock; + video_set_drvdata(&dev->vdev, dev); /* Register the v4l2_device structure */ - s->v4l2_dev.release = rtl2832_sdr_video_release; - ret = v4l2_device_register(&s->udev->dev, &s->v4l2_dev); + dev->v4l2_dev.release = rtl2832_sdr_video_release; + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) { - dev_err(&s->udev->dev, - "Failed to register v4l2-device (%d)\n", ret); - goto err_free_controls; + dev_err(&pdev->dev, "Failed to register v4l2-device %d\n", ret); + goto err_v4l2_ctrl_handler_free; } - s->v4l2_dev.ctrl_handler = &s->hdl; - s->vdev.v4l2_dev = &s->v4l2_dev; - s->vdev.lock = &s->v4l2_lock; - s->vdev.vfl_dir = VFL_DIR_RX; + dev->v4l2_dev.ctrl_handler = &dev->hdl; + dev->vdev.v4l2_dev = &dev->v4l2_dev; + dev->vdev.lock = &dev->v4l2_lock; + dev->vdev.vfl_dir = VFL_DIR_RX; - ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1); + ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1); if (ret) { - dev_err(&s->udev->dev, - "Failed to register as video device (%d)\n", - ret); - goto err_unregister_v4l2_dev; + dev_err(&pdev->dev, "Failed to register as video device %d\n", + ret); + goto err_v4l2_device_unregister; } - dev_info(&s->udev->dev, "Registered as %s\n", - video_device_node_name(&s->vdev)); - - fe->sec_priv = s; - fe->ops.release_sec = rtl2832_sdr_release_sec; - - dev_info(&s->i2c->dev, "%s: Realtek RTL2832 SDR attached\n", - KBUILD_MODNAME); - dev_notice(&s->udev->dev, - "%s: SDR API is still slightly experimental and functionality changes may follow\n", - KBUILD_MODNAME); - return fe; - -err_unregister_v4l2_dev: - v4l2_device_unregister(&s->v4l2_dev); -err_free_controls: - v4l2_ctrl_handler_free(&s->hdl); -err_free_mem: - kfree(s); - return NULL; + dev_info(&pdev->dev, "Registered as %s\n", + video_device_node_name(&dev->vdev)); + dev_info(&pdev->dev, "Realtek RTL2832 SDR attached\n"); + dev_notice(&pdev->dev, + "SDR API is still slightly experimental and functionality changes may follow\n"); + platform_set_drvdata(pdev, dev); + return 0; +err_v4l2_device_unregister: + v4l2_device_unregister(&dev->v4l2_dev); +err_v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(&dev->hdl); +err_kfree: + kfree(dev); +err_module_put: + module_put(pdev->dev.parent->driver->owner); +err: + return ret; } -EXPORT_SYMBOL(rtl2832_sdr_attach); + +static int rtl2832_sdr_remove(struct platform_device *pdev) +{ + struct rtl2832_sdr_dev *dev = platform_get_drvdata(pdev); + + dev_dbg(&pdev->dev, "\n"); + + mutex_lock(&dev->vb_queue_lock); + mutex_lock(&dev->v4l2_lock); + /* No need to keep the urbs around after disconnection */ + dev->udev = NULL; + v4l2_device_disconnect(&dev->v4l2_dev); + video_unregister_device(&dev->vdev); + mutex_unlock(&dev->v4l2_lock); + mutex_unlock(&dev->vb_queue_lock); + v4l2_device_put(&dev->v4l2_dev); + module_put(pdev->dev.parent->driver->owner); + + return 0; +} + +static struct platform_driver rtl2832_sdr_driver = { + .driver = { + .name = "rtl2832_sdr", + .owner = THIS_MODULE, + }, + .probe = rtl2832_sdr_probe, + .remove = rtl2832_sdr_remove, +}; +module_platform_driver(rtl2832_sdr_driver); MODULE_AUTHOR("Antti Palosaari "); MODULE_DESCRIPTION("Realtek RTL2832 SDR driver"); diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.h b/drivers/media/dvb-frontends/rtl2832_sdr.h index b865fadf184f..d2594768bff2 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.h +++ b/drivers/media/dvb-frontends/rtl2832_sdr.h @@ -20,35 +20,48 @@ * GNU Radio plugin "gr-kernel" for device usage will be on: * http://git.linuxtv.org/anttip/gr-kernel.git * - * TODO: - * Help is very highly welcome for these + all the others you could imagine: - * - move controls to V4L2 API - * - use libv4l2 for stream format conversions - * - gr-kernel: switch to v4l2_mmap (current read eats a lot of cpu) - * - SDRSharp support */ #ifndef RTL2832_SDR_H #define RTL2832_SDR_H -#include +#include #include +#include "dvb_frontend.h" -/* for config struct */ -#include "rtl2832.h" +/** + * struct rtl2832_sdr_platform_data - Platform data for the rtl2832_sdr driver + * @clk: Clock frequency (4000000, 16000000, 25000000, 28800000). + * @tuner: Used tuner model. + * @i2c_client: rtl2832 demod driver I2C client. + * @bulk_read: rtl2832 driver private I/O interface. + * @bulk_write: rtl2832 driver private I/O interface. + * @update_bits: rtl2832 driver private I/O interface. + * @dvb_frontend: rtl2832 DVB frontend. + * @v4l2_subdev: Tuner v4l2 controls. + * @dvb_usb_device: DVB USB interface for USB streaming. + */ -#if IS_ENABLED(CONFIG_DVB_RTL2832_SDR) -extern struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, const struct rtl2832_config *cfg, - struct v4l2_subdev *sd); -#else -static inline struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, const struct rtl2832_config *cfg, - struct v4l2_subdev *sd) -{ - dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif +struct rtl2832_sdr_platform_data { + u32 clk; + /* + * XXX: This list must be kept sync with dvb_usb_rtl28xxu USB IF driver. + */ +#define RTL2832_SDR_TUNER_TUA9001 0x24 +#define RTL2832_SDR_TUNER_FC0012 0x26 +#define RTL2832_SDR_TUNER_E4000 0x27 +#define RTL2832_SDR_TUNER_FC0013 0x29 +#define RTL2832_SDR_TUNER_R820T 0x2a +#define RTL2832_SDR_TUNER_R828D 0x2b + u8 tuner; + + struct i2c_client *i2c_client; + int (*bulk_read)(struct i2c_client *, unsigned int, void *, size_t); + int (*bulk_write)(struct i2c_client *, unsigned int, const void *, size_t); + int (*update_bits)(struct i2c_client *, unsigned int, unsigned int, unsigned int); + struct dvb_frontend *dvb_frontend; + struct v4l2_subdev *v4l2_subdev; + struct dvb_usb_device *dvb_usb_device; +}; #endif /* RTL2832_SDR_H */ diff --git a/drivers/media/dvb-frontends/s5h1409.c b/drivers/media/dvb-frontends/s5h1409.c index f71b06221e14..5ff474a7ff29 100644 --- a/drivers/media/dvb-frontends/s5h1409.c +++ b/drivers/media/dvb-frontends/s5h1409.c @@ -1021,9 +1021,3 @@ static struct dvb_frontend_ops s5h1409_ops = { MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver"); MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); - - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/dvb-frontends/s5h1409.h b/drivers/media/dvb-frontends/s5h1409.h index 63b1e0a34e4e..9e143f5c8107 100644 --- a/drivers/media/dvb-frontends/s5h1409.h +++ b/drivers/media/dvb-frontends/s5h1409.h @@ -81,8 +81,3 @@ static inline struct dvb_frontend *s5h1409_attach( #endif /* CONFIG_DVB_S5H1409 */ #endif /* __S5H1409_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/dvb-frontends/s5h1411.c b/drivers/media/dvb-frontends/s5h1411.c index 6cc4b7a9dd60..64f35fed7ae1 100644 --- a/drivers/media/dvb-frontends/s5h1411.c +++ b/drivers/media/dvb-frontends/s5h1411.c @@ -944,8 +944,3 @@ MODULE_PARM_DESC(debug, "Enable verbose debug messages"); MODULE_DESCRIPTION("Samsung S5H1411 QAM-B/ATSC Demodulator driver"); MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/dvb-frontends/s5h1411.h b/drivers/media/dvb-frontends/s5h1411.h index e4f56871f982..1d7deb615674 100644 --- a/drivers/media/dvb-frontends/s5h1411.h +++ b/drivers/media/dvb-frontends/s5h1411.h @@ -83,8 +83,3 @@ static inline struct dvb_frontend *s5h1411_attach( #endif /* CONFIG_DVB_S5H1411 */ #endif /* __S5H1411_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index ce9ab442b4b6..5db588ebfc24 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -19,16 +19,17 @@ static const struct dvb_frontend_ops si2168_ops; /* execute firmware command */ -static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd) +static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) { + struct si2168_dev *dev = i2c_get_clientdata(client); int ret; unsigned long timeout; - mutex_lock(&s->i2c_mutex); + mutex_lock(&dev->i2c_mutex); if (cmd->wlen) { /* write cmd and args for firmware */ - ret = i2c_master_send(s->client, cmd->args, cmd->wlen); + ret = i2c_master_send(client, cmd->args, cmd->wlen); if (ret < 0) { goto err_mutex_unlock; } else if (ret != cmd->wlen) { @@ -39,10 +40,10 @@ static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd) if (cmd->rlen) { /* wait cmd execution terminate */ - #define TIMEOUT 50 + #define TIMEOUT 70 timeout = jiffies + msecs_to_jiffies(TIMEOUT); while (!time_after(jiffies, timeout)) { - ret = i2c_master_recv(s->client, cmd->args, cmd->rlen); + ret = i2c_master_recv(client, cmd->args, cmd->rlen); if (ret < 0) { goto err_mutex_unlock; } else if (ret != cmd->rlen) { @@ -55,7 +56,7 @@ static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd) break; } - dev_dbg(&s->client->dev, "cmd execution took %d ms\n", + dev_dbg(&client->dev, "cmd execution took %d ms\n", jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - TIMEOUT)); @@ -65,29 +66,26 @@ static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd) } } - ret = 0; + mutex_unlock(&dev->i2c_mutex); + return 0; err_mutex_unlock: - mutex_unlock(&s->i2c_mutex); - if (ret) - goto err; - - return 0; -err: - dev_dbg(&s->client->dev, "failed=%d\n", ret); + mutex_unlock(&dev->i2c_mutex); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status) { - struct si2168 *s = fe->demodulator_priv; + struct i2c_client *client = fe->demodulator_priv; + struct si2168_dev *dev = i2c_get_clientdata(client); struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; struct si2168_cmd cmd; *status = 0; - if (!s->active) { + if (!dev->active) { ret = -EAGAIN; goto err; } @@ -113,21 +111,10 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status) goto err; } - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - /* - * Possible values seen, in order from strong signal to weak: - * 16 0001 0110 full lock - * 1e 0001 1110 partial lock - * 1a 0001 1010 partial lock - * 18 0001 1000 no lock - * - * [b3:b1] lock bits - * [b4] statistics ready? Set in a few secs after lock is gained. - */ - switch ((cmd.args[2] >> 1) & 0x03) { case 0x01: *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; @@ -138,7 +125,7 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status) break; } - s->fe_status = *status; + dev->fe_status = *status; if (*status & FE_HAS_LOCK) { c->cnr.len = 1; @@ -149,30 +136,31 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status) c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; } - dev_dbg(&s->client->dev, "status=%02x args=%*ph\n", + dev_dbg(&client->dev, "status=%02x args=%*ph\n", *status, cmd.rlen, cmd.args); return 0; err: - dev_dbg(&s->client->dev, "failed=%d\n", ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int si2168_set_frontend(struct dvb_frontend *fe) { - struct si2168 *s = fe->demodulator_priv; + struct i2c_client *client = fe->demodulator_priv; + struct si2168_dev *dev = i2c_get_clientdata(client); struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; struct si2168_cmd cmd; u8 bandwidth, delivery_system; - dev_dbg(&s->client->dev, - "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u, stream_id=%d\n", - c->delivery_system, c->modulation, - c->frequency, c->bandwidth_hz, c->symbol_rate, - c->inversion, c->stream_id); + dev_dbg(&client->dev, + "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u stream_id=%u\n", + c->delivery_system, c->modulation, c->frequency, + c->bandwidth_hz, c->symbol_rate, c->inversion, + c->stream_id); - if (!s->active) { + if (!dev->active) { ret = -EAGAIN; goto err; } @@ -192,7 +180,12 @@ static int si2168_set_frontend(struct dvb_frontend *fe) goto err; } - if (c->bandwidth_hz <= 5000000) + if (c->bandwidth_hz == 0) { + ret = -EINVAL; + goto err; + } else if (c->bandwidth_hz <= 2000000) + bandwidth = 0x02; + else if (c->bandwidth_hz <= 5000000) bandwidth = 0x05; else if (c->bandwidth_hz <= 6000000) bandwidth = 0x06; @@ -217,7 +210,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe) memcpy(cmd.args, "\x88\x02\x02\x02\x02", 5); cmd.wlen = 5; cmd.rlen = 5; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -230,7 +223,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe) memcpy(cmd.args, "\x89\x21\x06\x11\x89\x20", 6); cmd.wlen = 6; cmd.rlen = 3; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -241,7 +234,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe) cmd.args[2] = c->stream_id == NO_STREAM_ID_FILTER ? 0 : 1; cmd.wlen = 3; cmd.rlen = 1; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; } @@ -249,35 +242,35 @@ static int si2168_set_frontend(struct dvb_frontend *fe) memcpy(cmd.args, "\x51\x03", 2); cmd.wlen = 2; cmd.rlen = 12; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; memcpy(cmd.args, "\x12\x08\x04", 3); cmd.wlen = 3; cmd.rlen = 3; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; memcpy(cmd.args, "\x14\x00\x0c\x10\x12\x00", 6); cmd.wlen = 6; cmd.rlen = 4; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; memcpy(cmd.args, "\x14\x00\x06\x10\x24\x00", 6); cmd.wlen = 6; cmd.rlen = 4; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; memcpy(cmd.args, "\x14\x00\x07\x10\x00\x24", 6); cmd.wlen = 6; cmd.rlen = 4; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -285,18 +278,18 @@ static int si2168_set_frontend(struct dvb_frontend *fe) cmd.args[4] = delivery_system | bandwidth; cmd.wlen = 6; cmd.rlen = 4; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; /* set DVB-C symbol rate */ if (c->delivery_system == SYS_DVBC_ANNEX_A) { memcpy(cmd.args, "\x14\x00\x02\x11", 4); - cmd.args[4] = (c->symbol_rate / 1000) & 0xff; + cmd.args[4] = ((c->symbol_rate / 1000) >> 0) & 0xff; cmd.args[5] = ((c->symbol_rate / 1000) >> 8) & 0xff; cmd.wlen = 6; cmd.rlen = 4; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; } @@ -304,88 +297,88 @@ static int si2168_set_frontend(struct dvb_frontend *fe) memcpy(cmd.args, "\x14\x00\x0f\x10\x10\x00", 6); cmd.wlen = 6; cmd.rlen = 4; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x08", 6); - cmd.args[5] |= s->ts_clock_inv ? 0x00 : 0x10; + cmd.args[5] |= dev->ts_clock_inv ? 0x00 : 0x10; cmd.wlen = 6; cmd.rlen = 4; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x05", 6); - cmd.args[5] |= s->ts_clock_inv ? 0x00 : 0x10; + cmd.args[5] |= dev->ts_clock_inv ? 0x00 : 0x10; cmd.wlen = 6; cmd.rlen = 4; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; memcpy(cmd.args, "\x14\x00\x01\x12\x00\x00", 6); cmd.wlen = 6; cmd.rlen = 4; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; memcpy(cmd.args, "\x14\x00\x01\x03\x0c\x00", 6); cmd.wlen = 6; cmd.rlen = 4; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; memcpy(cmd.args, "\x85", 1); cmd.wlen = 1; cmd.rlen = 1; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - s->delivery_system = c->delivery_system; + dev->delivery_system = c->delivery_system; return 0; err: - dev_dbg(&s->client->dev, "failed=%d\n", ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int si2168_init(struct dvb_frontend *fe) { - struct si2168 *s = fe->demodulator_priv; + struct i2c_client *client = fe->demodulator_priv; + struct si2168_dev *dev = i2c_get_clientdata(client); int ret, len, remaining; - const struct firmware *fw = NULL; - u8 *fw_file; - const unsigned int i2c_wr_max = 8; + const struct firmware *fw; + const char *fw_name; struct si2168_cmd cmd; unsigned int chip_id; - dev_dbg(&s->client->dev, "\n"); + dev_dbg(&client->dev, "\n"); /* initialize */ memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13); cmd.wlen = 13; cmd.rlen = 0; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - if (s->fw_loaded) { + if (dev->fw_loaded) { /* resume */ memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8); cmd.wlen = 8; cmd.rlen = 1; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; memcpy(cmd.args, "\x85", 1); cmd.wlen = 1; cmd.rlen = 1; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -396,7 +389,7 @@ static int si2168_init(struct dvb_frontend *fe) memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8); cmd.wlen = 8; cmd.rlen = 1; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -404,7 +397,7 @@ static int si2168_init(struct dvb_frontend *fe) memcpy(cmd.args, "\x02", 1); cmd.wlen = 1; cmd.rlen = 13; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -417,50 +410,48 @@ static int si2168_init(struct dvb_frontend *fe) switch (chip_id) { case SI2168_A20: - fw_file = SI2168_A20_FIRMWARE; + fw_name = SI2168_A20_FIRMWARE; break; case SI2168_A30: - fw_file = SI2168_A30_FIRMWARE; + fw_name = SI2168_A30_FIRMWARE; break; case SI2168_B40: - fw_file = SI2168_B40_FIRMWARE; + fw_name = SI2168_B40_FIRMWARE; break; default: - dev_err(&s->client->dev, - "unknown chip version Si21%d-%c%c%c\n", + dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n", cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); ret = -EINVAL; goto err; } - /* cold state - try to download firmware */ - dev_info(&s->client->dev, "found a '%s' in cold state\n", - si2168_ops.info.name); + dev_info(&client->dev, "found a 'Silicon Labs Si21%d-%c%c%c'\n", + cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); /* request the firmware, this will block and timeout */ - ret = request_firmware(&fw, fw_file, &s->client->dev); + ret = request_firmware(&fw, fw_name, &client->dev); if (ret) { /* fallback mechanism to handle old name for Si2168 B40 fw */ if (chip_id == SI2168_B40) { - fw_file = SI2168_B40_FIRMWARE_FALLBACK; - ret = request_firmware(&fw, fw_file, &s->client->dev); + fw_name = SI2168_B40_FIRMWARE_FALLBACK; + ret = request_firmware(&fw, fw_name, &client->dev); } if (ret == 0) { - dev_notice(&s->client->dev, + dev_notice(&client->dev, "please install firmware file '%s'\n", SI2168_B40_FIRMWARE); } else { - dev_err(&s->client->dev, + dev_err(&client->dev, "firmware file '%s' not found\n", - fw_file); - goto error_fw_release; + fw_name); + goto err_release_firmware; } } - dev_info(&s->client->dev, "downloading firmware from file '%s'\n", - fw_file); + dev_info(&client->dev, "downloading firmware from file '%s'\n", + fw_name); if ((fw->size % 17 == 0) && (fw->data[0] > 5)) { /* firmware is in the new format */ @@ -469,41 +460,37 @@ static int si2168_init(struct dvb_frontend *fe) memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len); cmd.wlen = len; cmd.rlen = 1; - ret = si2168_cmd_execute(s, &cmd); - if (ret) { - dev_err(&s->client->dev, - "firmware download failed=%d\n", - ret); - goto error_fw_release; - } + ret = si2168_cmd_execute(client, &cmd); + if (ret) + break; } - } else { + } else if (fw->size % 8 == 0) { /* firmware is in the old format */ - for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) { - len = remaining; - if (len > i2c_wr_max) - len = i2c_wr_max; - + for (remaining = fw->size; remaining > 0; remaining -= 8) { + len = 8; memcpy(cmd.args, &fw->data[fw->size - remaining], len); cmd.wlen = len; cmd.rlen = 1; - ret = si2168_cmd_execute(s, &cmd); - if (ret) { - dev_err(&s->client->dev, - "firmware download failed=%d\n", - ret); - goto error_fw_release; - } + ret = si2168_cmd_execute(client, &cmd); + if (ret) + break; } + } else { + /* bad or unknown firmware format */ + ret = -EINVAL; + } + + if (ret) { + dev_err(&client->dev, "firmware download failed %d\n", ret); + goto err_release_firmware; } release_firmware(fw); - fw = NULL; memcpy(cmd.args, "\x01\x01", 2); cmd.wlen = 2; cmd.rlen = 1; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; @@ -511,58 +498,56 @@ static int si2168_init(struct dvb_frontend *fe) memcpy(cmd.args, "\x11", 1); cmd.wlen = 1; cmd.rlen = 10; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - dev_dbg(&s->client->dev, "firmware version: %c.%c.%d\n", + dev_info(&client->dev, "firmware version: %c.%c.%d\n", cmd.args[6], cmd.args[7], cmd.args[8]); /* set ts mode */ memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); - cmd.args[4] |= s->ts_mode; + cmd.args[4] |= dev->ts_mode; cmd.wlen = 6; cmd.rlen = 4; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; - s->fw_loaded = true; - - dev_info(&s->client->dev, "found a '%s' in warm state\n", - si2168_ops.info.name); + dev->fw_loaded = true; warm: - s->active = true; + dev->active = true; return 0; -error_fw_release: +err_release_firmware: release_firmware(fw); err: - dev_dbg(&s->client->dev, "failed=%d\n", ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int si2168_sleep(struct dvb_frontend *fe) { - struct si2168 *s = fe->demodulator_priv; + struct i2c_client *client = fe->demodulator_priv; + struct si2168_dev *dev = i2c_get_clientdata(client); int ret; struct si2168_cmd cmd; - dev_dbg(&s->client->dev, "\n"); + dev_dbg(&client->dev, "\n"); - s->active = false; + dev->active = false; memcpy(cmd.args, "\x13", 1); cmd.wlen = 1; cmd.rlen = 0; - ret = si2168_cmd_execute(s, &cmd); + ret = si2168_cmd_execute(client, &cmd); if (ret) goto err; return 0; err: - dev_dbg(&s->client->dev, "failed=%d\n", ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } @@ -581,21 +566,22 @@ static int si2168_get_tune_settings(struct dvb_frontend *fe, */ static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan) { - struct si2168 *s = mux_priv; + struct i2c_client *client = mux_priv; + struct si2168_dev *dev = i2c_get_clientdata(client); int ret; struct i2c_msg gate_open_msg = { - .addr = s->client->addr, + .addr = client->addr, .flags = 0, .len = 3, .buf = "\xc0\x0d\x01", }; - mutex_lock(&s->i2c_mutex); + mutex_lock(&dev->i2c_mutex); /* open tuner I2C gate */ - ret = __i2c_transfer(s->client->adapter, &gate_open_msg, 1); + ret = __i2c_transfer(client->adapter, &gate_open_msg, 1); if (ret != 1) { - dev_warn(&s->client->dev, "i2c write failed=%d\n", ret); + dev_warn(&client->dev, "i2c write failed=%d\n", ret); if (ret >= 0) ret = -EREMOTEIO; } else { @@ -607,26 +593,27 @@ static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan) static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan) { - struct si2168 *s = mux_priv; + struct i2c_client *client = mux_priv; + struct si2168_dev *dev = i2c_get_clientdata(client); int ret; struct i2c_msg gate_close_msg = { - .addr = s->client->addr, + .addr = client->addr, .flags = 0, .len = 3, .buf = "\xc0\x0d\x00", }; /* close tuner I2C gate */ - ret = __i2c_transfer(s->client->adapter, &gate_close_msg, 1); + ret = __i2c_transfer(client->adapter, &gate_close_msg, 1); if (ret != 1) { - dev_warn(&s->client->dev, "i2c write failed=%d\n", ret); + dev_warn(&client->dev, "i2c write failed=%d\n", ret); if (ret >= 0) ret = -EREMOTEIO; } else { ret = 0; } - mutex_unlock(&s->i2c_mutex); + mutex_unlock(&dev->i2c_mutex); return ret; } @@ -635,6 +622,8 @@ static const struct dvb_frontend_ops si2168_ops = { .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A}, .info = { .name = "Silicon Labs Si2168", + .symbol_rate_min = 1000000, + .symbol_rate_max = 7200000, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | @@ -670,71 +659,69 @@ static int si2168_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct si2168_config *config = client->dev.platform_data; - struct si2168 *s; + struct si2168_dev *dev; int ret; dev_dbg(&client->dev, "\n"); - s = kzalloc(sizeof(struct si2168), GFP_KERNEL); - if (!s) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { ret = -ENOMEM; dev_err(&client->dev, "kzalloc() failed\n"); goto err; } - s->client = client; - mutex_init(&s->i2c_mutex); + mutex_init(&dev->i2c_mutex); /* create mux i2c adapter for tuner */ - s->adapter = i2c_add_mux_adapter(client->adapter, &client->dev, s, - 0, 0, 0, si2168_select, si2168_deselect); - if (s->adapter == NULL) { + dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev, + client, 0, 0, 0, si2168_select, si2168_deselect); + if (dev->adapter == NULL) { ret = -ENODEV; - goto err; + goto err_kfree; } /* create dvb_frontend */ - memcpy(&s->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops)); - s->fe.demodulator_priv = s; + memcpy(&dev->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops)); + dev->fe.demodulator_priv = client; + *config->i2c_adapter = dev->adapter; + *config->fe = &dev->fe; + dev->ts_mode = config->ts_mode; + dev->ts_clock_inv = config->ts_clock_inv; + dev->fw_loaded = false; - *config->i2c_adapter = s->adapter; - *config->fe = &s->fe; - s->ts_mode = config->ts_mode; - s->ts_clock_inv = config->ts_clock_inv; - s->fw_loaded = false; + i2c_set_clientdata(client, dev); - i2c_set_clientdata(client, s); - - dev_info(&s->client->dev, - "Silicon Labs Si2168 successfully attached\n"); + dev_info(&client->dev, "Silicon Labs Si2168 successfully attached\n"); return 0; +err_kfree: + kfree(dev); err: - kfree(s); dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int si2168_remove(struct i2c_client *client) { - struct si2168 *s = i2c_get_clientdata(client); + struct si2168_dev *dev = i2c_get_clientdata(client); dev_dbg(&client->dev, "\n"); - i2c_del_mux_adapter(s->adapter); + i2c_del_mux_adapter(dev->adapter); - s->fe.ops.release = NULL; - s->fe.demodulator_priv = NULL; + dev->fe.ops.release = NULL; + dev->fe.demodulator_priv = NULL; - kfree(s); + kfree(dev); return 0; } -static const struct i2c_device_id si2168_id[] = { +static const struct i2c_device_id si2168_id_table[] = { {"si2168", 0}, {} }; -MODULE_DEVICE_TABLE(i2c, si2168_id); +MODULE_DEVICE_TABLE(i2c, si2168_id_table); static struct i2c_driver si2168_driver = { .driver = { @@ -743,7 +730,7 @@ static struct i2c_driver si2168_driver = { }, .probe = si2168_probe, .remove = si2168_remove, - .id_table = si2168_id, + .id_table = si2168_id_table, }; module_i2c_driver(si2168_driver); diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index 87bc12146667..70d702ae6f49 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -36,14 +36,12 @@ struct si2168_config { struct i2c_adapter **i2c_adapter; /* TS mode */ +#define SI2168_TS_PARALLEL 0x06 +#define SI2168_TS_SERIAL 0x03 u8 ts_mode; /* TS clock inverted */ bool ts_clock_inv; - }; -#define SI2168_TS_PARALLEL 0x06 -#define SI2168_TS_SERIAL 0x03 - #endif diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h index 60bc3349b6c3..aadd1367673f 100644 --- a/drivers/media/dvb-frontends/si2168_priv.h +++ b/drivers/media/dvb-frontends/si2168_priv.h @@ -28,8 +28,7 @@ #define SI2168_B40_FIRMWARE_FALLBACK "dvb-demod-si2168-02.fw" /* state struct */ -struct si2168 { - struct i2c_client *client; +struct si2168_dev { struct i2c_adapter *adapter; struct mutex i2c_mutex; struct dvb_frontend fe; diff --git a/drivers/media/dvb-frontends/stb0899_algo.c b/drivers/media/dvb-frontends/stb0899_algo.c index 93596e0e640b..3012f196e9bd 100644 --- a/drivers/media/dvb-frontends/stb0899_algo.c +++ b/drivers/media/dvb-frontends/stb0899_algo.c @@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include "stb0899_drv.h" #include "stb0899_priv.h" #include "stb0899_reg.h" @@ -1490,9 +1491,7 @@ enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state) /* Store signal parameters */ offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ); - /* sign extend 30 bit value before using it in calculations */ - if (offsetfreq & (1 << 29)) - offsetfreq |= -1 << 30; + offsetfreq = sign_extend32(offsetfreq, 29); offsetfreq = offsetfreq / ((1 << 30) / 1000); offsetfreq *= (internal->master_clk / 1000000); diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c index 19646fbb061d..c73899d3a53d 100644 --- a/drivers/media/dvb-frontends/stb0899_drv.c +++ b/drivers/media/dvb-frontends/stb0899_drv.c @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -691,7 +692,7 @@ static int stb0899_wait_diseqc_fifo_empty(struct stb0899_state *state, int timeo reg = stb0899_read_reg(state, STB0899_DISSTATUS); if (!STB0899_GETFIELD(FIFOFULL, reg)) break; - if ((jiffies - start) > timeout) { + if (time_after(jiffies, start + timeout)) { dprintk(state->verbose, FE_ERROR, 1, "timed out !!"); return -ETIMEDOUT; } @@ -733,7 +734,7 @@ static int stb0899_wait_diseqc_rxidle(struct stb0899_state *state, int timeout) while (!STB0899_GETFIELD(RXEND, reg)) { reg = stb0899_read_reg(state, STB0899_DISRX_ST0); - if (jiffies - start > timeout) { + if (time_after(jiffies, start + timeout)) { dprintk(state->verbose, FE_ERROR, 1, "timed out!!"); return -ETIMEDOUT; } @@ -782,7 +783,7 @@ static int stb0899_wait_diseqc_txidle(struct stb0899_state *state, int timeout) while (!STB0899_GETFIELD(TXIDLE, reg)) { reg = stb0899_read_reg(state, STB0899_DISSTATUS); - if (jiffies - start > timeout) { + if (time_after(jiffies, start + timeout)) { dprintk(state->verbose, FE_ERROR, 1, "timed out!!"); return -ETIMEDOUT; } diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c index b35d65c9cc05..dce22ce35d20 100644 --- a/drivers/media/dvb-frontends/tc90522.c +++ b/drivers/media/dvb-frontends/tc90522.c @@ -214,6 +214,7 @@ static int tc90522s_get_frontend(struct dvb_frontend *fe) state = fe->demodulator_priv; c = &fe->dtv_property_cache; c->delivery_system = SYS_ISDBS; + c->symbol_rate = 28860000; layers = 0; ret = reg_read(state, 0xe6, val, 5); diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 205d71364343..da58c9bb67c2 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -177,7 +177,7 @@ comment "Video decoders" config VIDEO_ADV7180 tristate "Analog Devices ADV7180 decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API ---help--- Support for the Analog Devices ADV7180 video decoder. @@ -196,7 +196,7 @@ config VIDEO_ADV7183 config VIDEO_ADV7604 tristate "Analog Devices ADV7604 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API ---help--- Support for the Analog Devices ADV7604 video decoder. @@ -208,7 +208,8 @@ config VIDEO_ADV7604 config VIDEO_ADV7842 tristate "Analog Devices ADV7842 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + select HDMI ---help--- Support for the Analog Devices ADV7842 video decoder. @@ -422,7 +423,7 @@ config VIDEO_ADV7393 config VIDEO_ADV7511 tristate "Analog Devices ADV7511 encoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API ---help--- Support for the Analog Devices ADV7511 video encoder. diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index bffe6eb528a3..b75878c27c2a 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -30,56 +30,60 @@ #include #include #include +#include -#define ADV7180_INPUT_CONTROL_REG 0x00 -#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM 0x00 -#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10 -#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM 0x20 -#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM 0x30 -#define ADV7180_INPUT_CONTROL_NTSC_J 0x40 -#define ADV7180_INPUT_CONTROL_NTSC_M 0x50 -#define ADV7180_INPUT_CONTROL_PAL60 0x60 -#define ADV7180_INPUT_CONTROL_NTSC_443 0x70 -#define ADV7180_INPUT_CONTROL_PAL_BG 0x80 -#define ADV7180_INPUT_CONTROL_PAL_N 0x90 -#define ADV7180_INPUT_CONTROL_PAL_M 0xa0 -#define ADV7180_INPUT_CONTROL_PAL_M_PED 0xb0 -#define ADV7180_INPUT_CONTROL_PAL_COMB_N 0xc0 -#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED 0xd0 -#define ADV7180_INPUT_CONTROL_PAL_SECAM 0xe0 -#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED 0xf0 +#define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM 0x0 +#define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM_PED 0x1 +#define ADV7180_STD_AD_PAL_N_NTSC_J_SECAM 0x2 +#define ADV7180_STD_AD_PAL_N_NTSC_M_SECAM 0x3 +#define ADV7180_STD_NTSC_J 0x4 +#define ADV7180_STD_NTSC_M 0x5 +#define ADV7180_STD_PAL60 0x6 +#define ADV7180_STD_NTSC_443 0x7 +#define ADV7180_STD_PAL_BG 0x8 +#define ADV7180_STD_PAL_N 0x9 +#define ADV7180_STD_PAL_M 0xa +#define ADV7180_STD_PAL_M_PED 0xb +#define ADV7180_STD_PAL_COMB_N 0xc +#define ADV7180_STD_PAL_COMB_N_PED 0xd +#define ADV7180_STD_PAL_SECAM 0xe +#define ADV7180_STD_PAL_SECAM_PED 0xf + +#define ADV7180_REG_INPUT_CONTROL 0x0000 #define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f -#define ADV7180_EXTENDED_OUTPUT_CONTROL_REG 0x04 +#define ADV7182_REG_INPUT_VIDSEL 0x0002 + +#define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004 #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5 -#define ADV7180_AUTODETECT_ENABLE_REG 0x07 +#define ADV7180_REG_AUTODETECT_ENABLE 0x07 #define ADV7180_AUTODETECT_DEFAULT 0x7f /* Contrast */ -#define ADV7180_CON_REG 0x08 /*Unsigned */ +#define ADV7180_REG_CON 0x0008 /*Unsigned */ #define ADV7180_CON_MIN 0 #define ADV7180_CON_DEF 128 #define ADV7180_CON_MAX 255 /* Brightness*/ -#define ADV7180_BRI_REG 0x0a /*Signed */ +#define ADV7180_REG_BRI 0x000a /*Signed */ #define ADV7180_BRI_MIN -128 #define ADV7180_BRI_DEF 0 #define ADV7180_BRI_MAX 127 /* Hue */ -#define ADV7180_HUE_REG 0x0b /*Signed, inverted */ +#define ADV7180_REG_HUE 0x000b /*Signed, inverted */ #define ADV7180_HUE_MIN -127 #define ADV7180_HUE_DEF 0 #define ADV7180_HUE_MAX 128 -#define ADV7180_ADI_CTRL_REG 0x0e -#define ADV7180_ADI_CTRL_IRQ_SPACE 0x20 +#define ADV7180_REG_CTRL 0x000e +#define ADV7180_CTRL_IRQ_SPACE 0x20 -#define ADV7180_PWR_MAN_REG 0x0f +#define ADV7180_REG_PWR_MAN 0x0f #define ADV7180_PWR_MAN_ON 0x04 #define ADV7180_PWR_MAN_OFF 0x24 #define ADV7180_PWR_MAN_RES 0x80 -#define ADV7180_STATUS1_REG 0x10 +#define ADV7180_REG_STATUS1 0x0010 #define ADV7180_STATUS1_IN_LOCK 0x01 #define ADV7180_STATUS1_AUTOD_MASK 0x70 #define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00 @@ -91,49 +95,161 @@ #define ADV7180_STATUS1_AUTOD_PAL_COMB 0x60 #define ADV7180_STATUS1_AUTOD_SECAM_525 0x70 -#define ADV7180_IDENT_REG 0x11 +#define ADV7180_REG_IDENT 0x0011 #define ADV7180_ID_7180 0x18 -#define ADV7180_ICONF1_ADI 0x40 +#define ADV7180_REG_ICONF1 0x0040 #define ADV7180_ICONF1_ACTIVE_LOW 0x01 #define ADV7180_ICONF1_PSYNC_ONLY 0x10 #define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0 /* Saturation */ -#define ADV7180_SD_SAT_CB_REG 0xe3 /*Unsigned */ -#define ADV7180_SD_SAT_CR_REG 0xe4 /*Unsigned */ +#define ADV7180_REG_SD_SAT_CB 0x00e3 /*Unsigned */ +#define ADV7180_REG_SD_SAT_CR 0x00e4 /*Unsigned */ #define ADV7180_SAT_MIN 0 #define ADV7180_SAT_DEF 128 #define ADV7180_SAT_MAX 255 #define ADV7180_IRQ1_LOCK 0x01 #define ADV7180_IRQ1_UNLOCK 0x02 -#define ADV7180_ISR1_ADI 0x42 -#define ADV7180_ICR1_ADI 0x43 -#define ADV7180_IMR1_ADI 0x44 -#define ADV7180_IMR2_ADI 0x48 +#define ADV7180_REG_ISR1 0x0042 +#define ADV7180_REG_ICR1 0x0043 +#define ADV7180_REG_IMR1 0x0044 +#define ADV7180_REG_IMR2 0x0048 #define ADV7180_IRQ3_AD_CHANGE 0x08 -#define ADV7180_ISR3_ADI 0x4A -#define ADV7180_ICR3_ADI 0x4B -#define ADV7180_IMR3_ADI 0x4C -#define ADV7180_IMR4_ADI 0x50 +#define ADV7180_REG_ISR3 0x004A +#define ADV7180_REG_ICR3 0x004B +#define ADV7180_REG_IMR3 0x004C +#define ADV7180_REG_IMR4 0x50 -#define ADV7180_NTSC_V_BIT_END_REG 0xE6 +#define ADV7180_REG_NTSC_V_BIT_END 0x00E6 #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F +#define ADV7180_REG_VPP_SLAVE_ADDR 0xFD +#define ADV7180_REG_CSI_SLAVE_ADDR 0xFE + +#define ADV7180_REG_FLCONTROL 0x40e0 +#define ADV7180_FLCONTROL_FL_ENABLE 0x1 + +#define ADV7180_CSI_REG_PWRDN 0x00 +#define ADV7180_CSI_PWRDN 0x80 + +#define ADV7180_INPUT_CVBS_AIN1 0x00 +#define ADV7180_INPUT_CVBS_AIN2 0x01 +#define ADV7180_INPUT_CVBS_AIN3 0x02 +#define ADV7180_INPUT_CVBS_AIN4 0x03 +#define ADV7180_INPUT_CVBS_AIN5 0x04 +#define ADV7180_INPUT_CVBS_AIN6 0x05 +#define ADV7180_INPUT_SVIDEO_AIN1_AIN2 0x06 +#define ADV7180_INPUT_SVIDEO_AIN3_AIN4 0x07 +#define ADV7180_INPUT_SVIDEO_AIN5_AIN6 0x08 +#define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09 +#define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a + +#define ADV7182_INPUT_CVBS_AIN1 0x00 +#define ADV7182_INPUT_CVBS_AIN2 0x01 +#define ADV7182_INPUT_CVBS_AIN3 0x02 +#define ADV7182_INPUT_CVBS_AIN4 0x03 +#define ADV7182_INPUT_CVBS_AIN5 0x04 +#define ADV7182_INPUT_CVBS_AIN6 0x05 +#define ADV7182_INPUT_CVBS_AIN7 0x06 +#define ADV7182_INPUT_CVBS_AIN8 0x07 +#define ADV7182_INPUT_SVIDEO_AIN1_AIN2 0x08 +#define ADV7182_INPUT_SVIDEO_AIN3_AIN4 0x09 +#define ADV7182_INPUT_SVIDEO_AIN5_AIN6 0x0a +#define ADV7182_INPUT_SVIDEO_AIN7_AIN8 0x0b +#define ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3 0x0c +#define ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0d +#define ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2 0x0e +#define ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4 0x0f +#define ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6 0x10 +#define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11 + +#define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44 +#define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42 + +#define V4L2_CID_ADV_FAST_SWITCH (V4L2_CID_USER_ADV7180_BASE + 0x00) + +struct adv7180_state; + +#define ADV7180_FLAG_RESET_POWERED BIT(0) +#define ADV7180_FLAG_V2 BIT(1) +#define ADV7180_FLAG_MIPI_CSI2 BIT(2) +#define ADV7180_FLAG_I2P BIT(3) + +struct adv7180_chip_info { + unsigned int flags; + unsigned int valid_input_mask; + int (*set_std)(struct adv7180_state *st, unsigned int std); + int (*select_input)(struct adv7180_state *st, unsigned int input); + int (*init)(struct adv7180_state *state); +}; + struct adv7180_state { struct v4l2_ctrl_handler ctrl_hdl; struct v4l2_subdev sd; + struct media_pad pad; struct mutex mutex; /* mutual excl. when accessing chip */ int irq; v4l2_std_id curr_norm; bool autodetect; bool powered; u8 input; + + struct i2c_client *client; + unsigned int register_page; + struct i2c_client *csi_client; + struct i2c_client *vpp_client; + const struct adv7180_chip_info *chip_info; + enum v4l2_field field; }; #define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \ struct adv7180_state, \ ctrl_hdl)->sd) +static int adv7180_select_page(struct adv7180_state *state, unsigned int page) +{ + if (state->register_page != page) { + i2c_smbus_write_byte_data(state->client, ADV7180_REG_CTRL, + page); + state->register_page = page; + } + + return 0; +} + +static int adv7180_write(struct adv7180_state *state, unsigned int reg, + unsigned int value) +{ + lockdep_assert_held(&state->mutex); + adv7180_select_page(state, reg >> 8); + return i2c_smbus_write_byte_data(state->client, reg & 0xff, value); +} + +static int adv7180_read(struct adv7180_state *state, unsigned int reg) +{ + lockdep_assert_held(&state->mutex); + adv7180_select_page(state, reg >> 8); + return i2c_smbus_read_byte_data(state->client, reg & 0xff); +} + +static int adv7180_csi_write(struct adv7180_state *state, unsigned int reg, + unsigned int value) +{ + return i2c_smbus_write_byte_data(state->csi_client, reg, value); +} + +static int adv7180_set_video_standard(struct adv7180_state *state, + unsigned int std) +{ + return state->chip_info->set_std(state, std); +} + +static int adv7180_vpp_write(struct adv7180_state *state, unsigned int reg, + unsigned int value) +{ + return i2c_smbus_write_byte_data(state->vpp_client, reg, value); +} + static v4l2_std_id adv7180_std_to_v4l2(u8 status1) { /* in case V4L2_IN_ST_NO_SIGNAL */ @@ -165,22 +281,22 @@ static v4l2_std_id adv7180_std_to_v4l2(u8 status1) static int v4l2_std_to_adv7180(v4l2_std_id std) { if (std == V4L2_STD_PAL_60) - return ADV7180_INPUT_CONTROL_PAL60; + return ADV7180_STD_PAL60; if (std == V4L2_STD_NTSC_443) - return ADV7180_INPUT_CONTROL_NTSC_443; + return ADV7180_STD_NTSC_443; if (std == V4L2_STD_PAL_N) - return ADV7180_INPUT_CONTROL_PAL_N; + return ADV7180_STD_PAL_N; if (std == V4L2_STD_PAL_M) - return ADV7180_INPUT_CONTROL_PAL_M; + return ADV7180_STD_PAL_M; if (std == V4L2_STD_PAL_Nc) - return ADV7180_INPUT_CONTROL_PAL_COMB_N; + return ADV7180_STD_PAL_COMB_N; if (std & V4L2_STD_PAL) - return ADV7180_INPUT_CONTROL_PAL_BG; + return ADV7180_STD_PAL_BG; if (std & V4L2_STD_NTSC) - return ADV7180_INPUT_CONTROL_NTSC_M; + return ADV7180_STD_NTSC_M; if (std & V4L2_STD_SECAM) - return ADV7180_INPUT_CONTROL_PAL_SECAM; + return ADV7180_STD_PAL_SECAM; return -EINVAL; } @@ -193,10 +309,10 @@ static u32 adv7180_status_to_v4l2(u8 status1) return 0; } -static int __adv7180_status(struct i2c_client *client, u32 *status, +static int __adv7180_status(struct adv7180_state *state, u32 *status, v4l2_std_id *std) { - int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG); + int status1 = adv7180_read(state, ADV7180_REG_STATUS1); if (status1 < 0) return status1; @@ -225,7 +341,7 @@ static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) if (!state->autodetect || state->irq > 0) *std = state->curr_norm; else - err = __adv7180_status(v4l2_get_subdevdata(sd), NULL, std); + err = __adv7180_status(state, NULL, std); mutex_unlock(&state->mutex); return err; @@ -236,26 +352,19 @@ static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input, { struct adv7180_state *state = to_state(sd); int ret = mutex_lock_interruptible(&state->mutex); - struct i2c_client *client = v4l2_get_subdevdata(sd); if (ret) return ret; - /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept - * all inputs and let the card driver take care of validation - */ - if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input) + if (input > 31 || !(BIT(input) & state->chip_info->valid_input_mask)) { + ret = -EINVAL; goto out; + } - ret = i2c_smbus_read_byte_data(client, ADV7180_INPUT_CONTROL_REG); + ret = state->chip_info->select_input(state, input); - if (ret < 0) - goto out; - - ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK; - ret = i2c_smbus_write_byte_data(client, - ADV7180_INPUT_CONTROL_REG, ret | input); - state->input = input; + if (ret == 0) + state->input = input; out: mutex_unlock(&state->mutex); return ret; @@ -268,74 +377,104 @@ static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status) if (ret) return ret; - ret = __adv7180_status(v4l2_get_subdevdata(sd), status, NULL); + ret = __adv7180_status(state, status, NULL); mutex_unlock(&state->mutex); return ret; } +static int adv7180_program_std(struct adv7180_state *state) +{ + int ret; + + if (state->autodetect) { + ret = adv7180_set_video_standard(state, + ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM); + if (ret < 0) + return ret; + + __adv7180_status(state, NULL, &state->curr_norm); + } else { + ret = v4l2_std_to_adv7180(state->curr_norm); + if (ret < 0) + return ret; + + ret = adv7180_set_video_standard(state, ret); + if (ret < 0) + return ret; + } + + return 0; +} + static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct adv7180_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = mutex_lock_interruptible(&state->mutex); + if (ret) return ret; /* all standards -> autodetect */ if (std == V4L2_STD_ALL) { - ret = - i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG, - ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM - | state->input); - if (ret < 0) - goto out; - - __adv7180_status(client, NULL, &state->curr_norm); state->autodetect = true; } else { + /* Make sure we can support this std */ ret = v4l2_std_to_adv7180(std); if (ret < 0) goto out; - ret = i2c_smbus_write_byte_data(client, - ADV7180_INPUT_CONTROL_REG, - ret | state->input); - if (ret < 0) - goto out; - state->curr_norm = std; state->autodetect = false; } - ret = 0; + + ret = adv7180_program_std(state); out: mutex_unlock(&state->mutex); return ret; } -static int adv7180_set_power(struct adv7180_state *state, - struct i2c_client *client, bool on) +static int adv7180_set_power(struct adv7180_state *state, bool on) { u8 val; + int ret; if (on) val = ADV7180_PWR_MAN_ON; else val = ADV7180_PWR_MAN_OFF; - return i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG, val); + ret = adv7180_write(state, ADV7180_REG_PWR_MAN, val); + if (ret) + return ret; + + if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { + if (on) { + adv7180_csi_write(state, 0xDE, 0x02); + adv7180_csi_write(state, 0xD2, 0xF7); + adv7180_csi_write(state, 0xD8, 0x65); + adv7180_csi_write(state, 0xE0, 0x09); + adv7180_csi_write(state, 0x2C, 0x00); + if (state->field == V4L2_FIELD_NONE) + adv7180_csi_write(state, 0x1D, 0x80); + adv7180_csi_write(state, 0x00, 0x00); + } else { + adv7180_csi_write(state, 0x00, 0x80); + } + } + + return 0; } static int adv7180_s_power(struct v4l2_subdev *sd, int on) { struct adv7180_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; ret = mutex_lock_interruptible(&state->mutex); if (ret) return ret; - ret = adv7180_set_power(state, client, on); + ret = adv7180_set_power(state, on); if (ret == 0) state->powered = on; @@ -347,7 +486,6 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = to_adv7180_sd(ctrl); struct adv7180_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = mutex_lock_interruptible(&state->mutex); int val; @@ -356,26 +494,36 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) val = ctrl->val; switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - ret = i2c_smbus_write_byte_data(client, ADV7180_BRI_REG, val); + ret = adv7180_write(state, ADV7180_REG_BRI, val); break; case V4L2_CID_HUE: /*Hue is inverted according to HSL chart */ - ret = i2c_smbus_write_byte_data(client, ADV7180_HUE_REG, -val); + ret = adv7180_write(state, ADV7180_REG_HUE, -val); break; case V4L2_CID_CONTRAST: - ret = i2c_smbus_write_byte_data(client, ADV7180_CON_REG, val); + ret = adv7180_write(state, ADV7180_REG_CON, val); break; case V4L2_CID_SATURATION: /* *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE *Let's not confuse the user, everybody understands saturation */ - ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CB_REG, - val); + ret = adv7180_write(state, ADV7180_REG_SD_SAT_CB, val); if (ret < 0) break; - ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CR_REG, - val); + ret = adv7180_write(state, ADV7180_REG_SD_SAT_CR, val); + break; + case V4L2_CID_ADV_FAST_SWITCH: + if (ctrl->val) { + /* ADI required write */ + adv7180_write(state, 0x80d9, 0x44); + adv7180_write(state, ADV7180_REG_FLCONTROL, + ADV7180_FLCONTROL_FL_ENABLE); + } else { + /* ADI required write */ + adv7180_write(state, 0x80d9, 0xc4); + adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00); + } break; default: ret = -EINVAL; @@ -389,6 +537,16 @@ static const struct v4l2_ctrl_ops adv7180_ctrl_ops = { .s_ctrl = adv7180_s_ctrl, }; +static const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = { + .ops = &adv7180_ctrl_ops, + .id = V4L2_CID_ADV_FAST_SWITCH, + .name = "Fast Switching", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, +}; + static int adv7180_init_controls(struct adv7180_state *state) { v4l2_ctrl_handler_init(&state->ctrl_hdl, 4); @@ -405,6 +563,8 @@ static int adv7180_init_controls(struct adv7180_state *state) v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, V4L2_CID_HUE, ADV7180_HUE_MIN, ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF); + v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL); + state->sd.ctrl_handler = &state->ctrl_hdl; if (state->ctrl_hdl.error) { int err = state->ctrl_hdl.error; @@ -421,13 +581,14 @@ static void adv7180_exit_controls(struct adv7180_state *state) v4l2_ctrl_handler_free(&state->ctrl_hdl); } -static int adv7180_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int adv7180_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) { - if (index > 0) + if (code->index != 0) return -EINVAL; - *code = MEDIA_BUS_FMT_YUYV8_2X8; + code->code = MEDIA_BUS_FMT_YUYV8_2X8; return 0; } @@ -439,23 +600,118 @@ static int adv7180_mbus_fmt(struct v4l2_subdev *sd, fmt->code = MEDIA_BUS_FMT_YUYV8_2X8; fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - fmt->field = V4L2_FIELD_INTERLACED; fmt->width = 720; fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576; return 0; } +static int adv7180_set_field_mode(struct adv7180_state *state) +{ + if (!(state->chip_info->flags & ADV7180_FLAG_I2P)) + return 0; + + if (state->field == V4L2_FIELD_NONE) { + if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { + adv7180_csi_write(state, 0x01, 0x20); + adv7180_csi_write(state, 0x02, 0x28); + adv7180_csi_write(state, 0x03, 0x38); + adv7180_csi_write(state, 0x04, 0x30); + adv7180_csi_write(state, 0x05, 0x30); + adv7180_csi_write(state, 0x06, 0x80); + adv7180_csi_write(state, 0x07, 0x70); + adv7180_csi_write(state, 0x08, 0x50); + } + adv7180_vpp_write(state, 0xa3, 0x00); + adv7180_vpp_write(state, 0x5b, 0x00); + adv7180_vpp_write(state, 0x55, 0x80); + } else { + if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { + adv7180_csi_write(state, 0x01, 0x18); + adv7180_csi_write(state, 0x02, 0x18); + adv7180_csi_write(state, 0x03, 0x30); + adv7180_csi_write(state, 0x04, 0x20); + adv7180_csi_write(state, 0x05, 0x28); + adv7180_csi_write(state, 0x06, 0x40); + adv7180_csi_write(state, 0x07, 0x58); + adv7180_csi_write(state, 0x08, 0x30); + } + adv7180_vpp_write(state, 0xa3, 0x70); + adv7180_vpp_write(state, 0x5b, 0x80); + adv7180_vpp_write(state, 0x55, 0x00); + } + + return 0; +} + +static int adv7180_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *format) +{ + struct adv7180_state *state = to_state(sd); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + format->format = *v4l2_subdev_get_try_format(fh, 0); + } else { + adv7180_mbus_fmt(sd, &format->format); + format->format.field = state->field; + } + + return 0; +} + +static int adv7180_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *format) +{ + struct adv7180_state *state = to_state(sd); + struct v4l2_mbus_framefmt *framefmt; + + switch (format->format.field) { + case V4L2_FIELD_NONE: + if (!(state->chip_info->flags & ADV7180_FLAG_I2P)) + format->format.field = V4L2_FIELD_INTERLACED; + break; + default: + format->format.field = V4L2_FIELD_INTERLACED; + break; + } + + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + framefmt = &format->format; + if (state->field != format->format.field) { + state->field = format->format.field; + adv7180_set_power(state, false); + adv7180_set_field_mode(state); + adv7180_set_power(state, true); + } + } else { + framefmt = v4l2_subdev_get_try_format(fh, 0); + *framefmt = format->format; + } + + return adv7180_mbus_fmt(sd, framefmt); +} + static int adv7180_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { - /* - * The ADV7180 sensor supports BT.601/656 output modes. - * The BT.656 is default and not yet configurable by s/w. - */ - cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | - V4L2_MBUS_DATA_ACTIVE_HIGH; - cfg->type = V4L2_MBUS_BT656; + struct adv7180_state *state = to_state(sd); + + if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { + cfg->type = V4L2_MBUS_CSI2; + cfg->flags = V4L2_MBUS_CSI2_1_LANE | + V4L2_MBUS_CSI2_CHANNEL_0 | + V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + } else { + /* + * The ADV7180 sensor supports BT.601/656 output modes. + * The BT.656 is default and not yet configurable by s/w. + */ + cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | + V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_BT656; + } return 0; } @@ -465,139 +721,439 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = { .querystd = adv7180_querystd, .g_input_status = adv7180_g_input_status, .s_routing = adv7180_s_routing, - .enum_mbus_fmt = adv7180_enum_mbus_fmt, - .try_mbus_fmt = adv7180_mbus_fmt, - .g_mbus_fmt = adv7180_mbus_fmt, - .s_mbus_fmt = adv7180_mbus_fmt, .g_mbus_config = adv7180_g_mbus_config, }; + static const struct v4l2_subdev_core_ops adv7180_core_ops = { .s_power = adv7180_s_power, }; +static const struct v4l2_subdev_pad_ops adv7180_pad_ops = { + .enum_mbus_code = adv7180_enum_mbus_code, + .set_fmt = adv7180_set_pad_format, + .get_fmt = adv7180_get_pad_format, +}; + static const struct v4l2_subdev_ops adv7180_ops = { .core = &adv7180_core_ops, .video = &adv7180_video_ops, + .pad = &adv7180_pad_ops, }; static irqreturn_t adv7180_irq(int irq, void *devid) { struct adv7180_state *state = devid; - struct i2c_client *client = v4l2_get_subdevdata(&state->sd); u8 isr3; mutex_lock(&state->mutex); - i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, - ADV7180_ADI_CTRL_IRQ_SPACE); - isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI); + isr3 = adv7180_read(state, ADV7180_REG_ISR3); /* clear */ - i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3); - i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, 0); + adv7180_write(state, ADV7180_REG_ICR3, isr3); if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect) - __adv7180_status(client, NULL, &state->curr_norm); + __adv7180_status(state, NULL, &state->curr_norm); mutex_unlock(&state->mutex); return IRQ_HANDLED; } -static int init_device(struct i2c_client *client, struct adv7180_state *state) +static int adv7180_init(struct adv7180_state *state) { int ret; - /* Initialize adv7180 */ - /* Enable autodetection */ - if (state->autodetect) { - ret = - i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG, - ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM - | state->input); - if (ret < 0) - return ret; - - ret = - i2c_smbus_write_byte_data(client, - ADV7180_AUTODETECT_ENABLE_REG, - ADV7180_AUTODETECT_DEFAULT); - if (ret < 0) - return ret; - } else { - ret = v4l2_std_to_adv7180(state->curr_norm); - if (ret < 0) - return ret; - - ret = - i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG, - ret | state->input); - if (ret < 0) - return ret; - - } /* ITU-R BT.656-4 compatible */ - ret = i2c_smbus_write_byte_data(client, - ADV7180_EXTENDED_OUTPUT_CONTROL_REG, + ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS); if (ret < 0) return ret; /* Manually set V bit end position in NTSC mode */ - ret = i2c_smbus_write_byte_data(client, - ADV7180_NTSC_V_BIT_END_REG, + return adv7180_write(state, ADV7180_REG_NTSC_V_BIT_END, ADV7180_NTSC_V_BIT_END_MANUAL_NVEND); +} + +static int adv7180_set_std(struct adv7180_state *state, unsigned int std) +{ + return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, + (std << 4) | state->input); +} + +static int adv7180_select_input(struct adv7180_state *state, unsigned int input) +{ + int ret; + + ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL); if (ret < 0) return ret; - /* read current norm */ - __adv7180_status(client, NULL, &state->curr_norm); + ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK; + ret |= input; + return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret); +} - /* register for interrupts */ - if (state->irq > 0) { - ret = request_threaded_irq(state->irq, NULL, adv7180_irq, - IRQF_ONESHOT, KBUILD_MODNAME, state); - if (ret) - return ret; +static int adv7182_init(struct adv7180_state *state) +{ + if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) + adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR, + ADV7180_DEFAULT_CSI_I2C_ADDR << 1); - ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, - ADV7180_ADI_CTRL_IRQ_SPACE); - if (ret < 0) - goto err; + if (state->chip_info->flags & ADV7180_FLAG_I2P) + adv7180_write(state, ADV7180_REG_VPP_SLAVE_ADDR, + ADV7180_DEFAULT_VPP_I2C_ADDR << 1); - /* config the Interrupt pin to be active low */ - ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI, - ADV7180_ICONF1_ACTIVE_LOW | - ADV7180_ICONF1_PSYNC_ONLY); - if (ret < 0) - goto err; + if (state->chip_info->flags & ADV7180_FLAG_V2) { + /* ADI recommended writes for improved video quality */ + adv7180_write(state, 0x0080, 0x51); + adv7180_write(state, 0x0081, 0x51); + adv7180_write(state, 0x0082, 0x68); + } - ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0); - if (ret < 0) - goto err; + /* ADI required writes */ + if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { + adv7180_write(state, 0x0003, 0x4e); + adv7180_write(state, 0x0004, 0x57); + adv7180_write(state, 0x001d, 0xc0); + } else { + if (state->chip_info->flags & ADV7180_FLAG_V2) + adv7180_write(state, 0x0004, 0x17); + else + adv7180_write(state, 0x0004, 0x07); + adv7180_write(state, 0x0003, 0x0c); + adv7180_write(state, 0x001d, 0x40); + } - ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0); - if (ret < 0) - goto err; + adv7180_write(state, 0x0013, 0x00); - /* enable AD change interrupts interrupts */ - ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI, - ADV7180_IRQ3_AD_CHANGE); - if (ret < 0) - goto err; + return 0; +} - ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0); - if (ret < 0) - goto err; +static int adv7182_set_std(struct adv7180_state *state, unsigned int std) +{ + return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL, std << 4); +} - ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, - 0); - if (ret < 0) - goto err; +enum adv7182_input_type { + ADV7182_INPUT_TYPE_CVBS, + ADV7182_INPUT_TYPE_DIFF_CVBS, + ADV7182_INPUT_TYPE_SVIDEO, + ADV7182_INPUT_TYPE_YPBPR, +}; + +static enum adv7182_input_type adv7182_get_input_type(unsigned int input) +{ + switch (input) { + case ADV7182_INPUT_CVBS_AIN1: + case ADV7182_INPUT_CVBS_AIN2: + case ADV7182_INPUT_CVBS_AIN3: + case ADV7182_INPUT_CVBS_AIN4: + case ADV7182_INPUT_CVBS_AIN5: + case ADV7182_INPUT_CVBS_AIN6: + case ADV7182_INPUT_CVBS_AIN7: + case ADV7182_INPUT_CVBS_AIN8: + return ADV7182_INPUT_TYPE_CVBS; + case ADV7182_INPUT_SVIDEO_AIN1_AIN2: + case ADV7182_INPUT_SVIDEO_AIN3_AIN4: + case ADV7182_INPUT_SVIDEO_AIN5_AIN6: + case ADV7182_INPUT_SVIDEO_AIN7_AIN8: + return ADV7182_INPUT_TYPE_SVIDEO; + case ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3: + case ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6: + return ADV7182_INPUT_TYPE_YPBPR; + case ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2: + case ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4: + case ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6: + case ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8: + return ADV7182_INPUT_TYPE_DIFF_CVBS; + default: /* Will never happen */ + return 0; + } +} + +/* ADI recommended writes to registers 0x52, 0x53, 0x54 */ +static unsigned int adv7182_lbias_settings[][3] = { + [ADV7182_INPUT_TYPE_CVBS] = { 0xCB, 0x4E, 0x80 }, + [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 }, + [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 }, + [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 }, +}; + +static unsigned int adv7280_lbias_settings[][3] = { + [ADV7182_INPUT_TYPE_CVBS] = { 0xCD, 0x4E, 0x80 }, + [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 }, + [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 }, + [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 }, +}; + +static int adv7182_select_input(struct adv7180_state *state, unsigned int input) +{ + enum adv7182_input_type input_type; + unsigned int *lbias; + unsigned int i; + int ret; + + ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, input); + if (ret) + return ret; + + /* Reset clamp circuitry - ADI recommended writes */ + adv7180_write(state, 0x809c, 0x00); + adv7180_write(state, 0x809c, 0xff); + + input_type = adv7182_get_input_type(input); + + switch (input_type) { + case ADV7182_INPUT_TYPE_CVBS: + case ADV7182_INPUT_TYPE_DIFF_CVBS: + /* ADI recommends to use the SH1 filter */ + adv7180_write(state, 0x0017, 0x41); + break; + default: + adv7180_write(state, 0x0017, 0x01); + break; + } + + if (state->chip_info->flags & ADV7180_FLAG_V2) + lbias = adv7280_lbias_settings[input_type]; + else + lbias = adv7182_lbias_settings[input_type]; + + for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++) + adv7180_write(state, 0x0052 + i, lbias[i]); + + if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) { + /* ADI required writes to make differential CVBS work */ + adv7180_write(state, 0x005f, 0xa8); + adv7180_write(state, 0x005a, 0x90); + adv7180_write(state, 0x0060, 0xb0); + adv7180_write(state, 0x80b6, 0x08); + adv7180_write(state, 0x80c0, 0xa0); + } else { + adv7180_write(state, 0x005f, 0xf0); + adv7180_write(state, 0x005a, 0xd0); + adv7180_write(state, 0x0060, 0x10); + adv7180_write(state, 0x80b6, 0x9c); + adv7180_write(state, 0x80c0, 0x00); } return 0; +} + +static const struct adv7180_chip_info adv7180_info = { + .flags = ADV7180_FLAG_RESET_POWERED, + /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept + * all inputs and let the card driver take care of validation + */ + .valid_input_mask = BIT(ADV7180_INPUT_CVBS_AIN1) | + BIT(ADV7180_INPUT_CVBS_AIN2) | + BIT(ADV7180_INPUT_CVBS_AIN3) | + BIT(ADV7180_INPUT_CVBS_AIN4) | + BIT(ADV7180_INPUT_CVBS_AIN5) | + BIT(ADV7180_INPUT_CVBS_AIN6) | + BIT(ADV7180_INPUT_SVIDEO_AIN1_AIN2) | + BIT(ADV7180_INPUT_SVIDEO_AIN3_AIN4) | + BIT(ADV7180_INPUT_SVIDEO_AIN5_AIN6) | + BIT(ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3) | + BIT(ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6), + .init = adv7180_init, + .set_std = adv7180_set_std, + .select_input = adv7180_select_input, +}; + +static const struct adv7180_chip_info adv7182_info = { + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | + BIT(ADV7182_INPUT_CVBS_AIN4) | + BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | + BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | + BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4), + .init = adv7182_init, + .set_std = adv7182_set_std, + .select_input = adv7182_select_input, +}; + +static const struct adv7180_chip_info adv7280_info = { + .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | + BIT(ADV7182_INPUT_CVBS_AIN4) | + BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | + BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | + BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3), + .init = adv7182_init, + .set_std = adv7182_set_std, + .select_input = adv7182_select_input, +}; + +static const struct adv7180_chip_info adv7280_m_info = { + .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | + BIT(ADV7182_INPUT_CVBS_AIN4) | + BIT(ADV7182_INPUT_CVBS_AIN5) | + BIT(ADV7182_INPUT_CVBS_AIN6) | + BIT(ADV7182_INPUT_CVBS_AIN7) | + BIT(ADV7182_INPUT_CVBS_AIN8) | + BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | + BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | + BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) | + BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | + BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | + BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6), + .init = adv7182_init, + .set_std = adv7182_set_std, + .select_input = adv7182_select_input, +}; + +static const struct adv7180_chip_info adv7281_info = { + .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN7) | + BIT(ADV7182_INPUT_CVBS_AIN8) | + BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | + BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), + .init = adv7182_init, + .set_std = adv7182_set_std, + .select_input = adv7182_select_input, +}; + +static const struct adv7180_chip_info adv7281_m_info = { + .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | + BIT(ADV7182_INPUT_CVBS_AIN4) | + BIT(ADV7182_INPUT_CVBS_AIN7) | + BIT(ADV7182_INPUT_CVBS_AIN8) | + BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | + BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | + BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | + BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), + .init = adv7182_init, + .set_std = adv7182_set_std, + .select_input = adv7182_select_input, +}; + +static const struct adv7180_chip_info adv7281_ma_info = { + .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | + BIT(ADV7182_INPUT_CVBS_AIN4) | + BIT(ADV7182_INPUT_CVBS_AIN5) | + BIT(ADV7182_INPUT_CVBS_AIN6) | + BIT(ADV7182_INPUT_CVBS_AIN7) | + BIT(ADV7182_INPUT_CVBS_AIN8) | + BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | + BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | + BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) | + BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | + BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | + BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), + .init = adv7182_init, + .set_std = adv7182_set_std, + .select_input = adv7182_select_input, +}; + +static const struct adv7180_chip_info adv7282_info = { + .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN7) | + BIT(ADV7182_INPUT_CVBS_AIN8) | + BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | + BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), + .init = adv7182_init, + .set_std = adv7182_set_std, + .select_input = adv7182_select_input, +}; + +static const struct adv7180_chip_info adv7282_m_info = { + .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, + .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | + BIT(ADV7182_INPUT_CVBS_AIN2) | + BIT(ADV7182_INPUT_CVBS_AIN3) | + BIT(ADV7182_INPUT_CVBS_AIN4) | + BIT(ADV7182_INPUT_CVBS_AIN7) | + BIT(ADV7182_INPUT_CVBS_AIN8) | + BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | + BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | + BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), + .init = adv7182_init, + .set_std = adv7182_set_std, + .select_input = adv7182_select_input, +}; + +static int init_device(struct adv7180_state *state) +{ + int ret; + + mutex_lock(&state->mutex); + + adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES); + usleep_range(2000, 10000); + + ret = state->chip_info->init(state); + if (ret) + goto out_unlock; + + ret = adv7180_program_std(state); + if (ret) + goto out_unlock; + + adv7180_set_field_mode(state); + + /* register for interrupts */ + if (state->irq > 0) { + /* config the Interrupt pin to be active low */ + ret = adv7180_write(state, ADV7180_REG_ICONF1, + ADV7180_ICONF1_ACTIVE_LOW | + ADV7180_ICONF1_PSYNC_ONLY); + if (ret < 0) + goto out_unlock; + + ret = adv7180_write(state, ADV7180_REG_IMR1, 0); + if (ret < 0) + goto out_unlock; + + ret = adv7180_write(state, ADV7180_REG_IMR2, 0); + if (ret < 0) + goto out_unlock; + + /* enable AD change interrupts interrupts */ + ret = adv7180_write(state, ADV7180_REG_IMR3, + ADV7180_IRQ3_AD_CHANGE); + if (ret < 0) + goto out_unlock; + + ret = adv7180_write(state, ADV7180_REG_IMR4, 0); + if (ret < 0) + goto out_unlock; + } + +out_unlock: + mutex_unlock(&state->mutex); -err: - free_irq(state->irq, state); return ret; } @@ -616,26 +1172,63 @@ static int adv7180_probe(struct i2c_client *client, client->addr, client->adapter->name); state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); - if (state == NULL) { - ret = -ENOMEM; - goto err; + if (state == NULL) + return -ENOMEM; + + state->client = client; + state->field = V4L2_FIELD_INTERLACED; + state->chip_info = (struct adv7180_chip_info *)id->driver_data; + + if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { + state->csi_client = i2c_new_dummy(client->adapter, + ADV7180_DEFAULT_CSI_I2C_ADDR); + if (!state->csi_client) + return -ENOMEM; + } + + if (state->chip_info->flags & ADV7180_FLAG_I2P) { + state->vpp_client = i2c_new_dummy(client->adapter, + ADV7180_DEFAULT_VPP_I2C_ADDR); + if (!state->vpp_client) { + ret = -ENOMEM; + goto err_unregister_csi_client; + } } state->irq = client->irq; mutex_init(&state->mutex); state->autodetect = true; - state->powered = true; + if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED) + state->powered = true; + else + state->powered = false; state->input = 0; sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &adv7180_ops); + sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ret = adv7180_init_controls(state); if (ret) - goto err_unreg_subdev; - ret = init_device(client, state); + goto err_unregister_vpp_client; + + state->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER; + ret = media_entity_init(&sd->entity, 1, &state->pad, 0); if (ret) goto err_free_ctrl; + ret = init_device(state); + if (ret) + goto err_media_entity_cleanup; + + if (state->irq) { + ret = request_threaded_irq(client->irq, NULL, adv7180_irq, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + KBUILD_MODNAME, state); + if (ret) + goto err_media_entity_cleanup; + } + ret = v4l2_async_register_subdev(sd); if (ret) goto err_free_irq; @@ -645,11 +1238,17 @@ static int adv7180_probe(struct i2c_client *client, err_free_irq: if (state->irq > 0) free_irq(client->irq, state); +err_media_entity_cleanup: + media_entity_cleanup(&sd->entity); err_free_ctrl: adv7180_exit_controls(state); -err_unreg_subdev: +err_unregister_vpp_client: + if (state->chip_info->flags & ADV7180_FLAG_I2P) + i2c_unregister_device(state->vpp_client); +err_unregister_csi_client: + if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) + i2c_unregister_device(state->csi_client); mutex_destroy(&state->mutex); -err: return ret; } @@ -663,15 +1262,32 @@ static int adv7180_remove(struct i2c_client *client) if (state->irq > 0) free_irq(client->irq, state); + media_entity_cleanup(&sd->entity); adv7180_exit_controls(state); + + if (state->chip_info->flags & ADV7180_FLAG_I2P) + i2c_unregister_device(state->vpp_client); + if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) + i2c_unregister_device(state->csi_client); + mutex_destroy(&state->mutex); + return 0; } static const struct i2c_device_id adv7180_id[] = { - {KBUILD_MODNAME, 0}, + { "adv7180", (kernel_ulong_t)&adv7180_info }, + { "adv7182", (kernel_ulong_t)&adv7182_info }, + { "adv7280", (kernel_ulong_t)&adv7280_info }, + { "adv7280-m", (kernel_ulong_t)&adv7280_m_info }, + { "adv7281", (kernel_ulong_t)&adv7281_info }, + { "adv7281-m", (kernel_ulong_t)&adv7281_m_info }, + { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info }, + { "adv7282", (kernel_ulong_t)&adv7282_info }, + { "adv7282-m", (kernel_ulong_t)&adv7282_m_info }, {}, }; +MODULE_DEVICE_TABLE(i2c, adv7180_id); #ifdef CONFIG_PM_SLEEP static int adv7180_suspend(struct device *dev) @@ -680,7 +1296,7 @@ static int adv7180_suspend(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct adv7180_state *state = to_state(sd); - return adv7180_set_power(state, client, false); + return adv7180_set_power(state, false); } static int adv7180_resume(struct device *dev) @@ -690,14 +1306,14 @@ static int adv7180_resume(struct device *dev) struct adv7180_state *state = to_state(sd); int ret; - if (state->powered) { - ret = adv7180_set_power(state, client, true); - if (ret) - return ret; - } - ret = init_device(client, state); + ret = init_device(state); if (ret < 0) return ret; + + ret = adv7180_set_power(state, state->powered); + if (ret) + return ret; + return 0; } @@ -708,8 +1324,6 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume); #define ADV7180_PM_OPS NULL #endif -MODULE_DEVICE_TABLE(i2c, adv7180_id); - static struct i2c_driver adv7180_driver = { .driver = { .owner = THIS_MODULE, diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index e43dd2e2a38a..d228b7c82310 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -333,21 +333,11 @@ static inline struct adv7604_state *to_state(struct v4l2_subdev *sd) return container_of(sd, struct adv7604_state, sd); } -static inline unsigned hblanking(const struct v4l2_bt_timings *t) -{ - return V4L2_DV_BT_BLANKING_WIDTH(t); -} - static inline unsigned htotal(const struct v4l2_bt_timings *t) { return V4L2_DV_BT_FRAME_WIDTH(t); } -static inline unsigned vblanking(const struct v4l2_bt_timings *t) -{ - return V4L2_DV_BT_BLANKING_HEIGHT(t); -} - static inline unsigned vtotal(const struct v4l2_bt_timings *t) { return V4L2_DV_BT_FRAME_HEIGHT(t); @@ -466,11 +456,6 @@ static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) return adv_smbus_write_byte_data(state, ADV7604_PAGE_CEC, reg, val); } -static inline int cec_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) -{ - return cec_write(sd, reg, (cec_read(sd, reg) & ~mask) | val); -} - static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); @@ -486,34 +471,6 @@ static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val) reg, val); } -static inline int esdp_read(struct v4l2_subdev *sd, u8 reg) -{ - struct adv7604_state *state = to_state(sd); - - return adv_smbus_read_byte_data(state, ADV7604_PAGE_ESDP, reg); -} - -static inline int esdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) -{ - struct adv7604_state *state = to_state(sd); - - return adv_smbus_write_byte_data(state, ADV7604_PAGE_ESDP, reg, val); -} - -static inline int dpp_read(struct v4l2_subdev *sd, u8 reg) -{ - struct adv7604_state *state = to_state(sd); - - return adv_smbus_read_byte_data(state, ADV7604_PAGE_DPP, reg); -} - -static inline int dpp_write(struct v4l2_subdev *sd, u8 reg, u8 val) -{ - struct adv7604_state *state = to_state(sd); - - return adv_smbus_write_byte_data(state, ADV7604_PAGE_DPP, reg, val); -} - static inline int afe_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); @@ -561,32 +518,6 @@ static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val) return adv_smbus_write_byte_data(state, ADV7604_PAGE_EDID, reg, val); } -static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val) -{ - struct adv7604_state *state = to_state(sd); - struct i2c_client *client = state->i2c_clients[ADV7604_PAGE_EDID]; - u8 msgbuf0[1] = { 0 }; - u8 msgbuf1[256]; - struct i2c_msg msg[2] = { - { - .addr = client->addr, - .len = 1, - .buf = msgbuf0 - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = len, - .buf = msgbuf1 - }, - }; - - if (i2c_transfer(client->adapter, msg, 2) < 0) - return -EIO; - memcpy(val, msgbuf1, len); - return 0; -} - static inline int edid_write_block(struct v4l2_subdev *sd, unsigned len, const u8 *val) { @@ -652,13 +583,6 @@ static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 return hdmi_write(sd, reg, (hdmi_read(sd, reg) & ~mask) | val); } -static inline int test_read(struct v4l2_subdev *sd, u8 reg) -{ - struct adv7604_state *state = to_state(sd); - - return adv_smbus_read_byte_data(state, ADV7604_PAGE_TEST, reg); -} - static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv7604_state *state = to_state(sd); diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 75d26dfd0939..7c215ee142c4 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -220,21 +221,11 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) return &container_of(ctrl->handler, struct adv7842_state, hdl)->sd; } -static inline unsigned hblanking(const struct v4l2_bt_timings *t) -{ - return V4L2_DV_BT_BLANKING_WIDTH(t); -} - static inline unsigned htotal(const struct v4l2_bt_timings *t) { return V4L2_DV_BT_FRAME_WIDTH(t); } -static inline unsigned vblanking(const struct v4l2_bt_timings *t) -{ - return V4L2_DV_BT_BLANKING_HEIGHT(t); -} - static inline unsigned vtotal(const struct v4l2_bt_timings *t) { return V4L2_DV_BT_FRAME_HEIGHT(t); @@ -2108,149 +2099,65 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e) return err; } -/*********** avi info frame CEA-861-E **************/ -/* TODO move to common library */ - -struct avi_info_frame { - uint8_t f17; - uint8_t y10; - uint8_t a0; - uint8_t b10; - uint8_t s10; - uint8_t c10; - uint8_t m10; - uint8_t r3210; - uint8_t itc; - uint8_t ec210; - uint8_t q10; - uint8_t sc10; - uint8_t f47; - uint8_t vic; - uint8_t yq10; - uint8_t cn10; - uint8_t pr3210; - uint16_t etb; - uint16_t sbb; - uint16_t elb; - uint16_t srb; +struct adv7842_cfg_read_infoframe { + const char *desc; + u8 present_mask; + u8 head_addr; + u8 payload_addr; }; -static const char *y10_txt[4] = { - "RGB", - "YCbCr 4:2:2", - "YCbCr 4:4:4", - "Future", -}; - -static const char *c10_txt[4] = { - "No Data", - "SMPTE 170M", - "ITU-R 709", - "Extended Colorimetry information valied", -}; - -static const char *itc_txt[2] = { - "No Data", - "IT content", -}; - -static const char *ec210_txt[8] = { - "xvYCC601", - "xvYCC709", - "sYCC601", - "AdobeYCC601", - "AdobeRGB", - "5 reserved", - "6 reserved", - "7 reserved", -}; - -static const char *q10_txt[4] = { - "Default", - "Limited Range", - "Full Range", - "Reserved", -}; - -static void parse_avi_infoframe(struct v4l2_subdev *sd, uint8_t *buf, - struct avi_info_frame *avi) -{ - avi->f17 = (buf[1] >> 7) & 0x1; - avi->y10 = (buf[1] >> 5) & 0x3; - avi->a0 = (buf[1] >> 4) & 0x1; - avi->b10 = (buf[1] >> 2) & 0x3; - avi->s10 = buf[1] & 0x3; - avi->c10 = (buf[2] >> 6) & 0x3; - avi->m10 = (buf[2] >> 4) & 0x3; - avi->r3210 = buf[2] & 0xf; - avi->itc = (buf[3] >> 7) & 0x1; - avi->ec210 = (buf[3] >> 4) & 0x7; - avi->q10 = (buf[3] >> 2) & 0x3; - avi->sc10 = buf[3] & 0x3; - avi->f47 = (buf[4] >> 7) & 0x1; - avi->vic = buf[4] & 0x7f; - avi->yq10 = (buf[5] >> 6) & 0x3; - avi->cn10 = (buf[5] >> 4) & 0x3; - avi->pr3210 = buf[5] & 0xf; - avi->etb = buf[6] + 256*buf[7]; - avi->sbb = buf[8] + 256*buf[9]; - avi->elb = buf[10] + 256*buf[11]; - avi->srb = buf[12] + 256*buf[13]; -} - -static void print_avi_infoframe(struct v4l2_subdev *sd) +static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infoframe *cri) { int i; - uint8_t buf[14]; - u8 avi_len; - u8 avi_ver; - struct avi_info_frame avi; + uint8_t buffer[32]; + union hdmi_infoframe frame; + u8 len; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct device *dev = &client->dev; + + if (!(io_read(sd, 0x60) & cri->present_mask)) { + v4l2_info(sd, "%s infoframe not received\n", cri->desc); + return; + } + + for (i = 0; i < 3; i++) + buffer[i] = infoframe_read(sd, cri->head_addr + i); + + len = buffer[2] + 1; + + if (len + 3 > sizeof(buffer)) { + v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len); + return; + } + + for (i = 0; i < len; i++) + buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i); + + if (hdmi_infoframe_unpack(&frame, buffer) < 0) { + v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); + return; + } + + hdmi_infoframe_log(KERN_INFO, dev, &frame); +} + +static void adv7842_log_infoframes(struct v4l2_subdev *sd) +{ + int i; + struct adv7842_cfg_read_infoframe cri[] = { + { "AVI", 0x01, 0xe0, 0x00 }, + { "Audio", 0x02, 0xe3, 0x1c }, + { "SDP", 0x04, 0xe6, 0x2a }, + { "Vendor", 0x10, 0xec, 0x54 } + }; if (!(hdmi_read(sd, 0x05) & 0x80)) { - v4l2_info(sd, "receive DVI-D signal (AVI infoframe not supported)\n"); - return; - } - if (!(io_read(sd, 0x60) & 0x01)) { - v4l2_info(sd, "AVI infoframe not received\n"); + v4l2_info(sd, "receive DVI-D signal, no infoframes\n"); return; } - if (io_read(sd, 0x88) & 0x10) { - v4l2_info(sd, "AVI infoframe checksum error has occurred earlier\n"); - io_write(sd, 0x8a, 0x10); /* clear AVI_INF_CKS_ERR_RAW */ - if (io_read(sd, 0x88) & 0x10) { - v4l2_info(sd, "AVI infoframe checksum error still present\n"); - io_write(sd, 0x8a, 0x10); /* clear AVI_INF_CKS_ERR_RAW */ - } - } - - avi_len = infoframe_read(sd, 0xe2); - avi_ver = infoframe_read(sd, 0xe1); - v4l2_info(sd, "AVI infoframe version %d (%d byte)\n", - avi_ver, avi_len); - - if (avi_ver != 0x02) - return; - - for (i = 0; i < 14; i++) - buf[i] = infoframe_read(sd, i); - - v4l2_info(sd, "\t%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], - buf[8], buf[9], buf[10], buf[11], buf[12], buf[13]); - - parse_avi_infoframe(sd, buf, &avi); - - if (avi.vic) - v4l2_info(sd, "\tVIC: %d\n", avi.vic); - if (avi.itc) - v4l2_info(sd, "\t%s\n", itc_txt[avi.itc]); - - if (avi.y10) - v4l2_info(sd, "\t%s %s\n", y10_txt[avi.y10], !avi.c10 ? "" : - (avi.c10 == 0x3 ? ec210_txt[avi.ec210] : c10_txt[avi.c10])); - else - v4l2_info(sd, "\t%s %s\n", y10_txt[avi.y10], q10_txt[avi.q10]); + for (i = 0; i < ARRAY_SIZE(cri); i++) + log_infoframe(sd, &cri[i]); } static const char * const prim_mode_txt[] = { @@ -2464,7 +2371,8 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "Deep color mode: %s\n", deep_color_mode_txt[hdmi_read(sd, 0x0b) >> 6]); - print_avi_infoframe(sd); + adv7842_log_infoframes(sd); + return 0; } diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c index 2820f7c38cba..6ed16e569bbf 100644 --- a/drivers/media/i2c/m5mols/m5mols_core.c +++ b/drivers/media/i2c/m5mols/m5mols_core.c @@ -125,9 +125,9 @@ static u32 m5mols_swap_byte(u8 *data, u8 length) if (length == 1) return *data; else if (length == 2) - return be16_to_cpu(*((u16 *)data)); + return be16_to_cpu(*((__be16 *)data)); else - return be32_to_cpu(*((u32 *)data)); + return be32_to_cpu(*((__be32 *)data)); } /** @@ -454,11 +454,6 @@ static int m5mols_get_version(struct v4l2_subdev *sd) return ret; } - ver->fw = be16_to_cpu(ver->fw); - ver->hw = be16_to_cpu(ver->hw); - ver->param = be16_to_cpu(ver->param); - ver->awb = be16_to_cpu(ver->awb); - v4l2_info(sd, "Manufacturer\t[%s]\n", is_manufacturer(info, REG_SAMSUNG_ELECTRO) ? "Samsung Electro-Machanics" : diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index 4d9c6bc34265..dcc68ec71732 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -904,11 +904,3 @@ static struct i2c_driver msp_driver = { }; module_i2c_driver(msp_driver); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c index 45b3fca188ca..76431223f0ff 100644 --- a/drivers/media/i2c/mt9m032.c +++ b/drivers/media/i2c/mt9m032.c @@ -422,22 +422,25 @@ done: return ret; } -static int mt9m032_get_pad_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9m032 *sensor = to_mt9m032(subdev); + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + mutex_lock(&sensor->lock); - crop->rect = *__mt9m032_get_pad_crop(sensor, fh, crop->which); + sel->r = *__mt9m032_get_pad_crop(sensor, fh, sel->which); mutex_unlock(&sensor->lock); return 0; } -static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9m032 *sensor = to_mt9m032(subdev); struct v4l2_mbus_framefmt *format; @@ -445,9 +448,12 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev, struct v4l2_rect rect; int ret = 0; + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + mutex_lock(&sensor->lock); - if (sensor->streaming && crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (sensor->streaming && sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { ret = -EBUSY; goto done; } @@ -455,13 +461,13 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev, /* Clamp the crop rectangle boundaries and align them to a multiple of 2 * pixels to ensure a GRBG Bayer pattern. */ - rect.left = clamp(ALIGN(crop->rect.left, 2), MT9M032_COLUMN_START_MIN, + rect.left = clamp(ALIGN(sel->r.left, 2), MT9M032_COLUMN_START_MIN, MT9M032_COLUMN_START_MAX); - rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN, + rect.top = clamp(ALIGN(sel->r.top, 2), MT9M032_ROW_START_MIN, MT9M032_ROW_START_MAX); - rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2), + rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), MT9M032_COLUMN_SIZE_MIN, MT9M032_COLUMN_SIZE_MAX); - rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2), + rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), MT9M032_ROW_SIZE_MIN, MT9M032_ROW_SIZE_MAX); rect.width = min_t(unsigned int, rect.width, @@ -469,21 +475,21 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9m032_get_pad_crop(sensor, fh, crop->which); + __crop = __mt9m032_get_pad_crop(sensor, fh, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - format = __mt9m032_get_pad_format(sensor, fh, crop->which); + format = __mt9m032_get_pad_format(sensor, fh, sel->which); format->width = rect.width; format->height = rect.height; } *__crop = rect; - crop->rect = rect; + sel->r = rect; - if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) ret = mt9m032_update_geom_timing(sensor); done: @@ -690,8 +696,8 @@ static const struct v4l2_subdev_pad_ops mt9m032_pad_ops = { .enum_frame_size = mt9m032_enum_frame_size, .get_fmt = mt9m032_get_pad_format, .set_fmt = mt9m032_set_pad_format, - .set_crop = mt9m032_set_pad_crop, - .get_crop = mt9m032_get_pad_crop, + .set_selection = mt9m032_set_pad_selection, + .get_selection = mt9m032_get_pad_selection, }; static const struct v4l2_subdev_ops mt9m032_ops = { diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index edb76bd33d16..e3acae9a2ec3 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -581,37 +581,42 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev, return 0; } -static int mt9p031_get_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9p031_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); - crop->rect = *__mt9p031_get_pad_crop(mt9p031, fh, crop->pad, - crop->which); + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + sel->r = *__mt9p031_get_pad_crop(mt9p031, fh, sel->pad, sel->which); return 0; } -static int mt9p031_set_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9p031_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); struct v4l2_mbus_framefmt *__format; struct v4l2_rect *__crop; struct v4l2_rect rect; + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + /* Clamp the crop rectangle boundaries and align them to a multiple of 2 * pixels to ensure a GRBG Bayer pattern. */ - rect.left = clamp(ALIGN(crop->rect.left, 2), MT9P031_COLUMN_START_MIN, + rect.left = clamp(ALIGN(sel->r.left, 2), MT9P031_COLUMN_START_MIN, MT9P031_COLUMN_START_MAX); - rect.top = clamp(ALIGN(crop->rect.top, 2), MT9P031_ROW_START_MIN, + rect.top = clamp(ALIGN(sel->r.top, 2), MT9P031_ROW_START_MIN, MT9P031_ROW_START_MAX); - rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2), + rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), MT9P031_WINDOW_WIDTH_MIN, MT9P031_WINDOW_WIDTH_MAX); - rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2), + rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), MT9P031_WINDOW_HEIGHT_MIN, MT9P031_WINDOW_HEIGHT_MAX); @@ -620,20 +625,20 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9P031_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9p031_get_pad_crop(mt9p031, fh, crop->pad, crop->which); + __crop = __mt9p031_get_pad_crop(mt9p031, fh, sel->pad, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - __format = __mt9p031_get_pad_format(mt9p031, fh, crop->pad, - crop->which); + __format = __mt9p031_get_pad_format(mt9p031, fh, sel->pad, + sel->which); __format->width = rect.width; __format->height = rect.height; } *__crop = rect; - crop->rect = rect; + sel->r = rect; return 0; } @@ -980,8 +985,8 @@ static struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = { .enum_frame_size = mt9p031_enum_frame_size, .get_fmt = mt9p031_get_format, .set_fmt = mt9p031_set_format, - .get_crop = mt9p031_get_crop, - .set_crop = mt9p031_set_crop, + .get_selection = mt9p031_get_selection, + .set_selection = mt9p031_set_selection, }; static struct v4l2_subdev_ops mt9p031_subdev_ops = { diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c index d9e9889b579f..f6ca636b538d 100644 --- a/drivers/media/i2c/mt9t001.c +++ b/drivers/media/i2c/mt9t001.c @@ -401,39 +401,44 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev, return 0; } -static int mt9t001_get_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9t001_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9t001 *mt9t001 = to_mt9t001(subdev); - crop->rect = *__mt9t001_get_pad_crop(mt9t001, fh, crop->pad, - crop->which); + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + sel->r = *__mt9t001_get_pad_crop(mt9t001, fh, sel->pad, sel->which); return 0; } -static int mt9t001_set_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9t001_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9t001 *mt9t001 = to_mt9t001(subdev); struct v4l2_mbus_framefmt *__format; struct v4l2_rect *__crop; struct v4l2_rect rect; + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + /* Clamp the crop rectangle boundaries and align them to a multiple of 2 * pixels. */ - rect.left = clamp(ALIGN(crop->rect.left, 2), + rect.left = clamp(ALIGN(sel->r.left, 2), MT9T001_COLUMN_START_MIN, MT9T001_COLUMN_START_MAX); - rect.top = clamp(ALIGN(crop->rect.top, 2), + rect.top = clamp(ALIGN(sel->r.top, 2), MT9T001_ROW_START_MIN, MT9T001_ROW_START_MAX); - rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2), + rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), MT9T001_WINDOW_WIDTH_MIN + 1, MT9T001_WINDOW_WIDTH_MAX + 1); - rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2), + rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), MT9T001_WINDOW_HEIGHT_MIN + 1, MT9T001_WINDOW_HEIGHT_MAX + 1); @@ -442,20 +447,20 @@ static int mt9t001_set_crop(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9T001_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9t001_get_pad_crop(mt9t001, fh, crop->pad, crop->which); + __crop = __mt9t001_get_pad_crop(mt9t001, fh, sel->pad, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - __format = __mt9t001_get_pad_format(mt9t001, fh, crop->pad, - crop->which); + __format = __mt9t001_get_pad_format(mt9t001, fh, sel->pad, + sel->which); __format->width = rect.width; __format->height = rect.height; } *__crop = rect; - crop->rect = rect; + sel->r = rect; return 0; } @@ -819,8 +824,8 @@ static struct v4l2_subdev_pad_ops mt9t001_subdev_pad_ops = { .enum_frame_size = mt9t001_enum_frame_size, .get_fmt = mt9t001_get_format, .set_fmt = mt9t001_set_format, - .get_crop = mt9t001_get_crop, - .set_crop = mt9t001_set_crop, + .get_selection = mt9t001_get_selection, + .set_selection = mt9t001_set_selection, }; static struct v4l2_subdev_ops mt9t001_subdev_ops = { diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 93687c1e4097..bd3f979a4d49 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -552,39 +552,44 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev, return 0; } -static int mt9v032_get_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9v032_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9v032 *mt9v032 = to_mt9v032(subdev); - crop->rect = *__mt9v032_get_pad_crop(mt9v032, fh, crop->pad, - crop->which); + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + sel->r = *__mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which); return 0; } -static int mt9v032_set_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int mt9v032_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct mt9v032 *mt9v032 = to_mt9v032(subdev); struct v4l2_mbus_framefmt *__format; struct v4l2_rect *__crop; struct v4l2_rect rect; + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + /* Clamp the crop rectangle boundaries and align them to a non multiple * of 2 pixels to ensure a GRBG Bayer pattern. */ - rect.left = clamp(ALIGN(crop->rect.left + 1, 2) - 1, + rect.left = clamp(ALIGN(sel->r.left + 1, 2) - 1, MT9V032_COLUMN_START_MIN, MT9V032_COLUMN_START_MAX); - rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1, + rect.top = clamp(ALIGN(sel->r.top + 1, 2) - 1, MT9V032_ROW_START_MIN, MT9V032_ROW_START_MAX); - rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2), + rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), MT9V032_WINDOW_WIDTH_MIN, MT9V032_WINDOW_WIDTH_MAX); - rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2), + rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), MT9V032_WINDOW_HEIGHT_MIN, MT9V032_WINDOW_HEIGHT_MAX); @@ -593,17 +598,17 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which); + __crop = __mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - __format = __mt9v032_get_pad_format(mt9v032, fh, crop->pad, - crop->which); + __format = __mt9v032_get_pad_format(mt9v032, fh, sel->pad, + sel->which); __format->width = rect.width; __format->height = rect.height; - if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { mt9v032->hratio = 1; mt9v032->vratio = 1; mt9v032_configure_pixel_rate(mt9v032); @@ -611,7 +616,7 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev, } *__crop = rect; - crop->rect = rect; + sel->r = rect; return 0; } @@ -844,8 +849,8 @@ static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = { .enum_frame_size = mt9v032_enum_frame_size, .get_fmt = mt9v032_get_format, .set_fmt = mt9v032_set_format, - .get_crop = mt9v032_get_crop, - .set_crop = mt9v032_set_crop, + .get_selection = mt9v032_get_selection, + .set_selection = mt9v032_set_selection, }; static struct v4l2_subdev_ops mt9v032_subdev_ops = { diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c index d1c50c9d43ae..70071314789e 100644 --- a/drivers/media/i2c/s5k4ecgx.c +++ b/drivers/media/i2c/s5k4ecgx.c @@ -220,7 +220,7 @@ static int s5k4ecgx_i2c_read(struct i2c_client *client, u16 addr, u16 *val) msg[1].buf = rbuf; ret = i2c_transfer(client->adapter, msg, 2); - *val = be16_to_cpu(*((u16 *)rbuf)); + *val = be16_to_cpu(*((__be16 *)rbuf)); v4l2_dbg(4, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val); @@ -341,7 +341,7 @@ static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd) v4l2_err(sd, "Failed to read firmware %s\n", S5K4ECGX_FIRMWARE); return err; } - regs_num = le32_to_cpu(get_unaligned_le32(fw->data)); + regs_num = get_unaligned_le32(fw->data); v4l2_dbg(3, debug, sd, "FW: %s size %zu register sets %d\n", S5K4ECGX_FIRMWARE, fw->size, regs_num); @@ -351,8 +351,7 @@ static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd) err = -EINVAL; goto fw_out; } - crc_file = le32_to_cpu(get_unaligned_le32(fw->data + - regs_num * FW_RECORD_SIZE)); + crc_file = get_unaligned_le32(fw->data + regs_num * FW_RECORD_SIZE); crc = crc32_le(~0, fw->data, regs_num * FW_RECORD_SIZE); if (crc != crc_file) { v4l2_err(sd, "FW: invalid crc (%#x:%#x)\n", crc, crc_file); @@ -361,9 +360,9 @@ static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd) } ptr = fw->data + FW_RECORD_SIZE; for (i = 1; i < regs_num; i++) { - addr = le32_to_cpu(get_unaligned_le32(ptr)); + addr = get_unaligned_le32(ptr); ptr += sizeof(u32); - val = le16_to_cpu(get_unaligned_le16(ptr)); + val = get_unaligned_le16(ptr); ptr += sizeof(u16); if (addr - addr_inc != 2) err = s5k4ecgx_write(client, addr, val); diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 60a74d8d38d5..a3d7d0391302 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -353,7 +353,7 @@ static struct v4l2_rect s5k5baf_cis_rect = { * */ static int s5k5baf_fw_parse(struct device *dev, struct s5k5baf_fw **fw, - size_t count, const u16 *data) + size_t count, const __le16 *data) { struct s5k5baf_fw *f; u16 *d, i, *end; @@ -421,6 +421,7 @@ static u16 s5k5baf_i2c_read(struct s5k5baf *state, u16 addr) { struct i2c_client *c = v4l2_get_subdevdata(&state->sd); __be16 w, r; + u16 res; struct i2c_msg msg[] = { { .addr = c->addr, .flags = 0, .len = 2, .buf = (u8 *)&w }, @@ -434,15 +435,15 @@ static u16 s5k5baf_i2c_read(struct s5k5baf *state, u16 addr) w = cpu_to_be16(addr); ret = i2c_transfer(c->adapter, msg, 2); - r = be16_to_cpu(r); + res = be16_to_cpu(r); - v4l2_dbg(3, debug, c, "i2c_read: 0x%04x : 0x%04x\n", addr, r); + v4l2_dbg(3, debug, c, "i2c_read: 0x%04x : 0x%04x\n", addr, res); if (ret != 2) { v4l2_err(c, "i2c_read: error during transfer (%d)\n", ret); state->error = ret; } - return r; + return res; } static void s5k5baf_i2c_write(struct s5k5baf *state, u16 addr, u16 val) @@ -1037,7 +1038,7 @@ static int s5k5baf_load_setfile(struct s5k5baf *state) } ret = s5k5baf_fw_parse(&c->dev, &state->fw, fw->size / 2, - (u16 *)fw->data); + (__le16 *)fw->data); release_firmware(fw); @@ -1793,7 +1794,7 @@ static const struct v4l2_subdev_ops s5k5baf_subdev_ops = { static int s5k5baf_configure_gpios(struct s5k5baf *state) { - static const char const *name[] = { "S5K5BAF_STBY", "S5K5BAF_RST" }; + static const char * const name[] = { "S5K5BAF_STBY", "S5K5BAF_RST" }; struct i2c_client *c = v4l2_get_subdevdata(&state->sd); struct s5k5baf_gpio *g = state->gpios; int ret, i; diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c index 2851581e0061..b1c583239dab 100644 --- a/drivers/media/i2c/s5k6aa.c +++ b/drivers/media/i2c/s5k6aa.c @@ -348,7 +348,7 @@ static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val) msg[1].buf = rbuf; ret = i2c_transfer(client->adapter, msg, 2); - *val = be16_to_cpu(*((u16 *)rbuf)); + *val = be16_to_cpu(*((__be16 *)rbuf)); v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val); @@ -1161,17 +1161,21 @@ static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return ret; } -static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int s5k6aa_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct s5k6aa *s5k6aa = to_s5k6aa(sd); struct v4l2_rect *rect; - memset(crop->reserved, 0, sizeof(crop->reserved)); + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + memset(sel->reserved, 0, sizeof(sel->reserved)); mutex_lock(&s5k6aa->lock); - rect = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which); - crop->rect = *rect; + rect = __s5k6aa_get_crop_rect(s5k6aa, fh, sel->which); + sel->r = *rect; mutex_unlock(&s5k6aa->lock); v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n", @@ -1180,35 +1184,39 @@ static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } -static int s5k6aa_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +static int s5k6aa_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct s5k6aa *s5k6aa = to_s5k6aa(sd); struct v4l2_mbus_framefmt *mf; unsigned int max_x, max_y; struct v4l2_rect *crop_r; - mutex_lock(&s5k6aa->lock); - crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which); + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; - if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + mutex_lock(&s5k6aa->lock); + crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, sel->which); + + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { mf = &s5k6aa->preset->mbus_fmt; s5k6aa->apply_crop = 1; } else { mf = v4l2_subdev_get_try_format(fh, 0); } - v4l_bound_align_image(&crop->rect.width, mf->width, + v4l_bound_align_image(&sel->r.width, mf->width, S5K6AA_WIN_WIDTH_MAX, 1, - &crop->rect.height, mf->height, + &sel->r.height, mf->height, S5K6AA_WIN_HEIGHT_MAX, 1, 0); - max_x = (S5K6AA_WIN_WIDTH_MAX - crop->rect.width) & ~1; - max_y = (S5K6AA_WIN_HEIGHT_MAX - crop->rect.height) & ~1; + max_x = (S5K6AA_WIN_WIDTH_MAX - sel->r.width) & ~1; + max_y = (S5K6AA_WIN_HEIGHT_MAX - sel->r.height) & ~1; - crop->rect.left = clamp_t(unsigned int, crop->rect.left, 0, max_x); - crop->rect.top = clamp_t(unsigned int, crop->rect.top, 0, max_y); + sel->r.left = clamp_t(unsigned int, sel->r.left, 0, max_x); + sel->r.top = clamp_t(unsigned int, sel->r.top, 0, max_y); - *crop_r = crop->rect; + *crop_r = sel->r; mutex_unlock(&s5k6aa->lock); @@ -1224,8 +1232,8 @@ static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = { .enum_frame_interval = s5k6aa_enum_frame_interval, .get_fmt = s5k6aa_get_fmt, .set_fmt = s5k6aa_set_fmt, - .get_crop = s5k6aa_get_crop, - .set_crop = s5k6aa_set_crop, + .get_selection = s5k6aa_get_selection, + .set_selection = s5k6aa_set_selection, }; static const struct v4l2_subdev_video_ops s5k6aa_video_ops = { diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c index e40d9027df3d..e3348db56c46 100644 --- a/drivers/media/i2c/smiapp-pll.c +++ b/drivers/media/i2c/smiapp-pll.c @@ -14,14 +14,9 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ +#include #include #include #include diff --git a/drivers/media/i2c/smiapp-pll.h b/drivers/media/i2c/smiapp-pll.h index e8f035a50c76..b98d143b64e1 100644 --- a/drivers/media/i2c/smiapp-pll.h +++ b/drivers/media/i2c/smiapp-pll.h @@ -14,19 +14,11 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 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 SMIAPP_PLL_H #define SMIAPP_PLL_H -#include - /* CSI-2 or CCP-2 */ #define SMIAPP_PLL_BUS_TYPE_CSI2 0x00 #define SMIAPP_PLL_BUS_TYPE_PARALLEL 0x01 diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 0df5070e73c7..d47eff5d3101 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -18,12 +18,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #include @@ -31,11 +25,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include "smiapp.h" @@ -523,14 +519,12 @@ static const struct v4l2_ctrl_ops smiapp_ctrl_ops = { static int smiapp_init_controls(struct smiapp_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned long *valid_link_freqs = &sensor->valid_link_freqs[ - sensor->csi_format->compressed - SMIAPP_COMPRESSED_BASE]; - unsigned int max, i; int rval; rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12); if (rval) return rval; + sensor->pixel_array->ctrl_handler.lock = &sensor->mutex; sensor->analog_gain = v4l2_ctrl_new_std( @@ -576,21 +570,11 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) ARRAY_SIZE(smiapp_test_patterns) - 1, 0, 0, smiapp_test_patterns); - for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) { - int max_value = (1 << sensor->csi_format->width) - 1; - sensor->test_data[i] = - v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, - &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i, - 0, max_value, 1, max_value); - } - if (sensor->pixel_array->ctrl_handler.error) { dev_err(&client->dev, "pixel array controls initialization failed (%d)\n", sensor->pixel_array->ctrl_handler.error); - rval = sensor->pixel_array->ctrl_handler.error; - goto error; + return sensor->pixel_array->ctrl_handler.error; } sensor->pixel_array->sd.ctrl_handler = @@ -600,16 +584,10 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0); if (rval) - goto error; + return rval; + sensor->src->ctrl_handler.lock = &sensor->mutex; - for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++); - - sensor->link_freq = v4l2_ctrl_new_int_menu( - &sensor->src->ctrl_handler, &smiapp_ctrl_ops, - V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs), - __ffs(*valid_link_freqs), sensor->platform_data->op_sys_clock); - sensor->pixel_rate_csi = v4l2_ctrl_new_std( &sensor->src->ctrl_handler, &smiapp_ctrl_ops, V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); @@ -618,20 +596,41 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) dev_err(&client->dev, "src controls initialization failed (%d)\n", sensor->src->ctrl_handler.error); - rval = sensor->src->ctrl_handler.error; - goto error; + return sensor->src->ctrl_handler.error; } - sensor->src->sd.ctrl_handler = - &sensor->src->ctrl_handler; + sensor->src->sd.ctrl_handler = &sensor->src->ctrl_handler; return 0; +} -error: - v4l2_ctrl_handler_free(&sensor->pixel_array->ctrl_handler); - v4l2_ctrl_handler_free(&sensor->src->ctrl_handler); +/* + * For controls that require information on available media bus codes + * and linke frequencies. + */ +static int smiapp_init_late_controls(struct smiapp_sensor *sensor) +{ + unsigned long *valid_link_freqs = &sensor->valid_link_freqs[ + sensor->csi_format->compressed - SMIAPP_COMPRESSED_BASE]; + unsigned int max, i; - return rval; + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) { + int max_value = (1 << sensor->csi_format->width) - 1; + + sensor->test_data[i] = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, + &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i, + 0, max_value, 1, max_value); + } + + for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++); + + sensor->link_freq = v4l2_ctrl_new_int_menu( + &sensor->src->ctrl_handler, &smiapp_ctrl_ops, + V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs), + __ffs(*valid_link_freqs), sensor->platform_data->op_sys_clock); + + return sensor->src->ctrl_handler.error; } static void smiapp_free_controls(struct smiapp_sensor *sensor) @@ -1487,7 +1486,7 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) if (rval < 0) goto out; - if ((sensor->flash_capability & + if ((sensor->limits[SMIAPP_LIMIT_FLASH_MODE_CAPABILITY] & (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE | SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) && sensor->platform_data->strobe_setup != NULL && @@ -2338,10 +2337,9 @@ static DEVICE_ATTR(ident, S_IRUGO, smiapp_sysfs_ident_read, NULL); * V4L2 subdev core operations */ -static int smiapp_identify_module(struct v4l2_subdev *subdev) +static int smiapp_identify_module(struct smiapp_sensor *sensor) { - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct smiapp_module_info *minfo = &sensor->minfo; unsigned int i; int rval = 0; @@ -2464,8 +2462,6 @@ static int smiapp_identify_module(struct v4l2_subdev *subdev) minfo->name, minfo->manufacturer_id, minfo->model_id, minfo->revision_number_major); - strlcpy(subdev->name, sensor->minfo.name, sizeof(subdev->name)); - return 0; } @@ -2473,13 +2469,71 @@ static const struct v4l2_subdev_ops smiapp_ops; static const struct v4l2_subdev_internal_ops smiapp_internal_ops; static const struct media_entity_operations smiapp_entity_ops; -static int smiapp_registered(struct v4l2_subdev *subdev) +static int smiapp_register_subdevs(struct smiapp_sensor *sensor) { - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + struct smiapp_subdev *ssds[] = { + sensor->scaler, + sensor->binner, + sensor->pixel_array, + }; + unsigned int i; + int rval; + + for (i = 0; i < SMIAPP_SUBDEVS - 1; i++) { + struct smiapp_subdev *this = ssds[i + 1]; + struct smiapp_subdev *last = ssds[i]; + + if (!last) + continue; + + rval = media_entity_init(&this->sd.entity, + this->npads, this->pads, 0); + if (rval) { + dev_err(&client->dev, + "media_entity_init failed\n"); + return rval; + } + + rval = media_entity_create_link(&this->sd.entity, + this->source_pad, + &last->sd.entity, + last->sink_pad, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (rval) { + dev_err(&client->dev, + "media_entity_create_link failed\n"); + return rval; + } + + rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, + &this->sd); + if (rval) { + dev_err(&client->dev, + "v4l2_device_register_subdev failed\n"); + return rval; + } + } + + return 0; +} + +static void smiapp_cleanup(struct smiapp_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + + device_remove_file(&client->dev, &dev_attr_nvm); + device_remove_file(&client->dev, &dev_attr_ident); + + smiapp_free_controls(sensor); +} + +static int smiapp_init(struct smiapp_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct smiapp_pll *pll = &sensor->pll; struct smiapp_subdev *last = NULL; - u32 tmp; unsigned int i; int rval; @@ -2490,7 +2544,7 @@ static int smiapp_registered(struct v4l2_subdev *subdev) } if (!sensor->platform_data->set_xclk) { - sensor->ext_clk = devm_clk_get(&client->dev, "ext_clk"); + sensor->ext_clk = devm_clk_get(&client->dev, NULL); if (IS_ERR(sensor->ext_clk)) { dev_err(&client->dev, "could not get clock\n"); return PTR_ERR(sensor->ext_clk); @@ -2522,7 +2576,7 @@ static int smiapp_registered(struct v4l2_subdev *subdev) if (rval) return -ENODEV; - rval = smiapp_identify_module(subdev); + rval = smiapp_identify_module(sensor); if (rval) { rval = -ENODEV; goto out_power_off; @@ -2602,13 +2656,13 @@ static int smiapp_registered(struct v4l2_subdev *subdev) if (sensor->nvm == NULL) { dev_err(&client->dev, "nvm buf allocation failed\n"); rval = -ENOMEM; - goto out_ident_release; + goto out_cleanup; } if (device_create_file(&client->dev, &dev_attr_nvm) != 0) { dev_err(&client->dev, "sysfs nvm entry failed\n"); rval = -EBUSY; - goto out_ident_release; + goto out_cleanup; } } @@ -2643,18 +2697,11 @@ static int smiapp_registered(struct v4l2_subdev *subdev) pll->bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; pll->csi2.lanes = sensor->platform_data->lanes; pll->ext_clk_freq_hz = sensor->platform_data->ext_clk; - pll->flags = smiapp_call_quirk(sensor, pll_flags); pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; /* Profile 0 sensors have no separate OP clock branch. */ if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; - rval = smiapp_get_mbus_formats(sensor); - if (rval) { - rval = -ENODEV; - goto out_nvm_release; - } - for (i = 0; i < SMIAPP_SUBDEVS; i++) { struct { struct smiapp_subdev *ssd; @@ -2711,34 +2758,6 @@ static int smiapp_registered(struct v4l2_subdev *subdev) this->sd.owner = THIS_MODULE; v4l2_set_subdevdata(&this->sd, client); - rval = media_entity_init(&this->sd.entity, - this->npads, this->pads, 0); - if (rval) { - dev_err(&client->dev, - "media_entity_init failed\n"); - goto out_nvm_release; - } - - rval = media_entity_create_link(&this->sd.entity, - this->source_pad, - &last->sd.entity, - last->sink_pad, - MEDIA_LNK_FL_ENABLED | - MEDIA_LNK_FL_IMMUTABLE); - if (rval) { - dev_err(&client->dev, - "media_entity_create_link failed\n"); - goto out_nvm_release; - } - - rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, - &this->sd); - if (rval) { - dev_err(&client->dev, - "v4l2_device_register_subdev failed\n"); - goto out_nvm_release; - } - last = this; } @@ -2750,40 +2769,66 @@ static int smiapp_registered(struct v4l2_subdev *subdev) smiapp_read_frame_fmt(sensor); rval = smiapp_init_controls(sensor); if (rval < 0) - goto out_nvm_release; + goto out_cleanup; + + rval = smiapp_call_quirk(sensor, init); + if (rval) + goto out_cleanup; + + rval = smiapp_get_mbus_formats(sensor); + if (rval) { + rval = -ENODEV; + goto out_cleanup; + } + + rval = smiapp_init_late_controls(sensor); + if (rval) { + rval = -ENODEV; + goto out_cleanup; + } mutex_lock(&sensor->mutex); rval = smiapp_update_mode(sensor); mutex_unlock(&sensor->mutex); if (rval) { dev_err(&client->dev, "update mode failed\n"); - goto out_nvm_release; + goto out_cleanup; } sensor->streaming = false; sensor->dev_init_done = true; - /* check flash capability */ - rval = smiapp_read(sensor, SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, &tmp); - sensor->flash_capability = tmp; - if (rval) - goto out_nvm_release; - smiapp_power_off(sensor); return 0; -out_nvm_release: - device_remove_file(&client->dev, &dev_attr_nvm); - -out_ident_release: - device_remove_file(&client->dev, &dev_attr_ident); +out_cleanup: + smiapp_cleanup(sensor); out_power_off: smiapp_power_off(sensor); return rval; } +static int smiapp_registered(struct v4l2_subdev *subdev) +{ + struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); + struct i2c_client *client = v4l2_get_subdevdata(subdev); + int rval; + + if (!client->dev.of_node) { + rval = smiapp_init(sensor); + if (rval) + return rval; + } + + rval = smiapp_register_subdevs(sensor); + if (rval) + smiapp_cleanup(sensor); + + return rval; +} + static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct smiapp_subdev *ssd = to_smiapp_subdev(sd); @@ -2927,19 +2972,125 @@ static int smiapp_resume(struct device *dev) #endif /* CONFIG_PM */ +static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev) +{ + struct smiapp_platform_data *pdata; + struct v4l2_of_endpoint bus_cfg; + struct device_node *ep; + struct property *prop; + __be32 *val; + uint32_t asize; +#ifdef CONFIG_OF + unsigned int i; +#endif + int rval; + + if (!dev->of_node) + return dev->platform_data; + + ep = of_graph_get_next_endpoint(dev->of_node, NULL); + if (!ep) + return NULL; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + rval = -ENOMEM; + goto out_err; + } + + v4l2_of_parse_endpoint(ep, &bus_cfg); + + switch (bus_cfg.bus_type) { + case V4L2_MBUS_CSI2: + pdata->csi_signalling_mode = SMIAPP_CSI_SIGNALLING_MODE_CSI2; + break; + /* FIXME: add CCP2 support. */ + default: + rval = -EINVAL; + goto out_err; + } + + pdata->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; + dev_dbg(dev, "lanes %u\n", pdata->lanes); + + /* xshutdown GPIO is optional */ + pdata->xshutdown = of_get_named_gpio(dev->of_node, "reset-gpios", 0); + + /* NVM size is not mandatory */ + of_property_read_u32(dev->of_node, "nokia,nvm-size", + &pdata->nvm_size); + + rval = of_property_read_u32(dev->of_node, "clock-frequency", + &pdata->ext_clk); + if (rval) { + dev_warn(dev, "can't get clock-frequency\n"); + goto out_err; + } + + dev_dbg(dev, "reset %d, nvm %d, clk %d, csi %d\n", pdata->xshutdown, + pdata->nvm_size, pdata->ext_clk, pdata->csi_signalling_mode); + + rval = of_get_property( + dev->of_node, "link-frequencies", &asize) ? 0 : -ENOENT; + if (rval) { + dev_warn(dev, "can't get link-frequencies array size\n"); + goto out_err; + } + + pdata->op_sys_clock = devm_kzalloc(dev, asize, GFP_KERNEL); + if (!pdata->op_sys_clock) { + rval = -ENOMEM; + goto out_err; + } + + asize /= sizeof(*pdata->op_sys_clock); + /* + * Read a 64-bit array --- this will be replaced with a + * of_property_read_u64_array() once it's merged. + */ + prop = of_find_property(dev->of_node, "link-frequencies", NULL); + if (!prop) + goto out_err; + if (!prop->value) + goto out_err; + if (asize * sizeof(*pdata->op_sys_clock) > prop->length) + goto out_err; + val = prop->value; + if (IS_ERR(val)) + goto out_err; + +#ifdef CONFIG_OF + for (i = 0; i < asize; i++) + pdata->op_sys_clock[i] = of_read_number(val + i * 2, 2); +#endif + + for (; asize > 0; asize--) + dev_dbg(dev, "freq %d: %lld\n", asize - 1, + pdata->op_sys_clock[asize - 1]); + + of_node_put(ep); + return pdata; + +out_err: + of_node_put(ep); + return NULL; +} + static int smiapp_probe(struct i2c_client *client, const struct i2c_device_id *devid) { struct smiapp_sensor *sensor; + struct smiapp_platform_data *pdata = smiapp_get_pdata(&client->dev); + int rval; - if (client->dev.platform_data == NULL) + if (pdata == NULL) return -ENODEV; sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); if (sensor == NULL) return -ENOMEM; - sensor->platform_data = client->dev.platform_data; + sensor->platform_data = pdata; mutex_init(&sensor->mutex); mutex_init(&sensor->power_mutex); sensor->src = &sensor->ssds[sensor->ssds_used]; @@ -2950,8 +3101,27 @@ static int smiapp_probe(struct i2c_client *client, sensor->src->sensor = sensor; sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE; - return media_entity_init(&sensor->src->sd.entity, 2, + rval = media_entity_init(&sensor->src->sd.entity, 2, sensor->src->pads, 0); + if (rval < 0) + return rval; + + if (client->dev.of_node) { + rval = smiapp_init(sensor); + if (rval) + goto out_media_entity_cleanup; + } + + rval = v4l2_async_register_subdev(&sensor->src->sd); + if (rval < 0) + goto out_media_entity_cleanup; + + return 0; + +out_media_entity_cleanup: + media_entity_cleanup(&sensor->src->sd.entity); + + return rval; } static int smiapp_remove(struct i2c_client *client) @@ -2960,6 +3130,8 @@ static int smiapp_remove(struct i2c_client *client) struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); unsigned int i; + v4l2_async_unregister_subdev(subdev); + if (sensor->power_count) { if (gpio_is_valid(sensor->platform_data->xshutdown)) gpio_set_value(sensor->platform_data->xshutdown, 0); @@ -2970,19 +3142,20 @@ static int smiapp_remove(struct i2c_client *client) sensor->power_count = 0; } - device_remove_file(&client->dev, &dev_attr_ident); - if (sensor->nvm) - device_remove_file(&client->dev, &dev_attr_nvm); - for (i = 0; i < sensor->ssds_used; i++) { v4l2_device_unregister_subdev(&sensor->ssds[i].sd); media_entity_cleanup(&sensor->ssds[i].sd.entity); } - smiapp_free_controls(sensor); + smiapp_cleanup(sensor); return 0; } +static const struct of_device_id smiapp_of_table[] = { + { .compatible = "nokia,smia" }, + { }, +}; + static const struct i2c_device_id smiapp_id_table[] = { { SMIAPP_NAME, 0 }, { }, @@ -2996,6 +3169,7 @@ static const struct dev_pm_ops smiapp_pm_ops = { static struct i2c_driver smiapp_i2c_driver = { .driver = { + .of_match_table = smiapp_of_table, .name = SMIAPP_NAME, .pm = &smiapp_pm_ops, }, diff --git a/drivers/media/i2c/smiapp/smiapp-limits.c b/drivers/media/i2c/smiapp/smiapp-limits.c index 847cb235e198..784b114d3f8b 100644 --- a/drivers/media/i2c/smiapp/smiapp-limits.c +++ b/drivers/media/i2c/smiapp/smiapp-limits.c @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #include "smiapp.h" diff --git a/drivers/media/i2c/smiapp/smiapp-limits.h b/drivers/media/i2c/smiapp/smiapp-limits.h index 343e9c3827fc..b20124862a14 100644 --- a/drivers/media/i2c/smiapp/smiapp-limits.h +++ b/drivers/media/i2c/smiapp/smiapp-limits.h @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 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 - * */ #define SMIAPP_LIMIT_ANALOGUE_GAIN_CAPABILITY 0 diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c index e0bee8752122..abf9ea7a0fb7 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.c +++ b/drivers/media/i2c/smiapp/smiapp-quirk.c @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #include @@ -220,9 +214,11 @@ static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor) return smiapp_write_8(sensor, 0x3328, 0x80); } -static unsigned long jt8ev1_pll_flags(struct smiapp_sensor *sensor) +static int jt8ev1_init(struct smiapp_sensor *sensor) { - return SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; + sensor->pll.flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; + + return 0; } const struct smiapp_quirk smiapp_jt8ev1_quirk = { @@ -230,7 +226,7 @@ const struct smiapp_quirk smiapp_jt8ev1_quirk = { .post_poweron = jt8ev1_post_poweron, .pre_streamon = jt8ev1_pre_streamon, .post_streamoff = jt8ev1_post_streamoff, - .pll_flags = jt8ev1_pll_flags, + .init = jt8ev1_init, }; static int tcm8500md_limits(struct smiapp_sensor *sensor) diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.h b/drivers/media/i2c/smiapp/smiapp-quirk.h index 46e9ea8bfa08..dac5566a2f7a 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.h +++ b/drivers/media/i2c/smiapp/smiapp-quirk.h @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 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 __SMIAPP_QUIRK__ @@ -35,6 +29,9 @@ struct smiapp_sensor; * @post_poweron: Called always after the sensor has been fully powered on. * @pre_streamon: Called just before streaming is enabled. * @post_streamon: Called right after stopping streaming. + * @pll_flags: Return flags for the PLL calculator. + * @init: Quirk initialisation, called the last in probe(). This is + * also appropriate for adding sensor specific controls, for instance. * @reg_access: Register access quirk. The quirk may divert the access * to another register, or no register at all. * @@ -53,6 +50,7 @@ struct smiapp_quirk { int (*pre_streamon)(struct smiapp_sensor *sensor); int (*post_streamoff)(struct smiapp_sensor *sensor); unsigned long (*pll_flags)(struct smiapp_sensor *sensor); + int (*init)(struct smiapp_sensor *sensor); int (*reg_access)(struct smiapp_sensor *sensor, bool write, u32 *reg, u32 *val); unsigned long flags; @@ -74,14 +72,14 @@ void smiapp_replace_limit(struct smiapp_sensor *sensor, .val = _val, \ } -#define smiapp_call_quirk(_sensor, _quirk, ...) \ - (_sensor->minfo.quirk && \ - _sensor->minfo.quirk->_quirk ? \ - _sensor->minfo.quirk->_quirk(_sensor, ##__VA_ARGS__) : 0) +#define smiapp_call_quirk(sensor, _quirk, ...) \ + ((sensor)->minfo.quirk && \ + (sensor)->minfo.quirk->_quirk ? \ + (sensor)->minfo.quirk->_quirk(sensor, ##__VA_ARGS__) : 0) -#define smiapp_needs_quirk(_sensor, _quirk) \ - (_sensor->minfo.quirk ? \ - _sensor->minfo.quirk->flags & _quirk : 0) +#define smiapp_needs_quirk(sensor, _quirk) \ + ((sensor)->minfo.quirk ? \ + (sensor)->minfo.quirk->flags & _quirk : 0) extern const struct smiapp_quirk smiapp_jt8ev1_quirk; extern const struct smiapp_quirk smiapp_imx125es_quirk; diff --git a/drivers/media/i2c/smiapp/smiapp-reg-defs.h b/drivers/media/i2c/smiapp/smiapp-reg-defs.h index c488ef028074..f928d4cc8e26 100644 --- a/drivers/media/i2c/smiapp/smiapp-reg-defs.h +++ b/drivers/media/i2c/smiapp/smiapp-reg-defs.h @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 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 - * */ #define SMIAPP_REG_MK_U8(r) ((SMIAPP_REG_8BIT << 16) | (r)) #define SMIAPP_REG_MK_U16(r) ((SMIAPP_REG_16BIT << 16) | (r)) diff --git a/drivers/media/i2c/smiapp/smiapp-reg.h b/drivers/media/i2c/smiapp/smiapp-reg.h index b0dcbb8fa5e2..4c8b40614969 100644 --- a/drivers/media/i2c/smiapp/smiapp-reg.h +++ b/drivers/media/i2c/smiapp/smiapp-reg.h @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 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 __SMIAPP_REG_H_ diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c index a2098007fb70..6b6c20b61397 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.c +++ b/drivers/media/i2c/smiapp/smiapp-regs.c @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * */ #include diff --git a/drivers/media/i2c/smiapp/smiapp-regs.h b/drivers/media/i2c/smiapp/smiapp-regs.h index 35521125a2cc..6dd0e499c845 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.h +++ b/drivers/media/i2c/smiapp/smiapp-regs.h @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 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 SMIAPP_REGS_H diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index f88f8ec344d3..ed010a8a49d7 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -14,12 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 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 __SMIAPP_PRIV_H_ @@ -222,7 +216,6 @@ struct smiapp_sensor { u8 scaling_mode; u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */ - u8 flash_capability; u8 frame_skip; int power_count; diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 6f2dd9093d94..1fdce2f6f880 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -25,6 +25,7 @@ #include #include #include +#include #define VAL_SET(x, mask, rshift, lshift) \ ((((x) >> rshift) & mask) << lshift) @@ -268,33 +269,10 @@ struct regval_list { u8 value; }; -/* Supported resolutions */ -enum ov2640_width { - W_QCIF = 176, - W_QVGA = 320, - W_CIF = 352, - W_VGA = 640, - W_SVGA = 800, - W_XGA = 1024, - W_SXGA = 1280, - W_UXGA = 1600, -}; - -enum ov2640_height { - H_QCIF = 144, - H_QVGA = 240, - H_CIF = 288, - H_VGA = 480, - H_SVGA = 600, - H_XGA = 768, - H_SXGA = 1024, - H_UXGA = 1200, -}; - struct ov2640_win_size { char *name; - enum ov2640_width width; - enum ov2640_height height; + u32 width; + u32 height; const struct regval_list *regs; }; @@ -495,17 +473,17 @@ static const struct regval_list ov2640_init_regs[] = { static const struct regval_list ov2640_size_change_preamble_regs[] = { { BANK_SEL, BANK_SEL_DSP }, { RESET, RESET_DVP }, - { HSIZE8, HSIZE8_SET(W_UXGA) }, - { VSIZE8, VSIZE8_SET(H_UXGA) }, + { HSIZE8, HSIZE8_SET(UXGA_WIDTH) }, + { VSIZE8, VSIZE8_SET(UXGA_HEIGHT) }, { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN }, - { HSIZE, HSIZE_SET(W_UXGA) }, - { VSIZE, VSIZE_SET(H_UXGA) }, + { HSIZE, HSIZE_SET(UXGA_WIDTH) }, + { VSIZE, VSIZE_SET(UXGA_HEIGHT) }, { XOFFL, XOFFL_SET(0) }, { YOFFL, YOFFL_SET(0) }, - { VHYX, VHYX_HSIZE_SET(W_UXGA) | VHYX_VSIZE_SET(H_UXGA) | + { VHYX, VHYX_HSIZE_SET(UXGA_WIDTH) | VHYX_VSIZE_SET(UXGA_HEIGHT) | VHYX_XOFF_SET(0) | VHYX_YOFF_SET(0)}, - { TEST, TEST_HSIZE_SET(W_UXGA) }, + { TEST, TEST_HSIZE_SET(UXGA_WIDTH) }, ENDMARKER, }; @@ -519,45 +497,45 @@ static const struct regval_list ov2640_size_change_preamble_regs[] = { { RESET, 0x00} static const struct regval_list ov2640_qcif_regs[] = { - PER_SIZE_REG_SEQ(W_QCIF, H_QCIF, 3, 3, 4), + PER_SIZE_REG_SEQ(QCIF_WIDTH, QCIF_HEIGHT, 3, 3, 4), ENDMARKER, }; static const struct regval_list ov2640_qvga_regs[] = { - PER_SIZE_REG_SEQ(W_QVGA, H_QVGA, 2, 2, 4), + PER_SIZE_REG_SEQ(QVGA_WIDTH, QVGA_HEIGHT, 2, 2, 4), ENDMARKER, }; static const struct regval_list ov2640_cif_regs[] = { - PER_SIZE_REG_SEQ(W_CIF, H_CIF, 2, 2, 8), + PER_SIZE_REG_SEQ(CIF_WIDTH, CIF_HEIGHT, 2, 2, 8), ENDMARKER, }; static const struct regval_list ov2640_vga_regs[] = { - PER_SIZE_REG_SEQ(W_VGA, H_VGA, 0, 0, 2), + PER_SIZE_REG_SEQ(VGA_WIDTH, VGA_HEIGHT, 0, 0, 2), ENDMARKER, }; static const struct regval_list ov2640_svga_regs[] = { - PER_SIZE_REG_SEQ(W_SVGA, H_SVGA, 1, 1, 2), + PER_SIZE_REG_SEQ(SVGA_WIDTH, SVGA_HEIGHT, 1, 1, 2), ENDMARKER, }; static const struct regval_list ov2640_xga_regs[] = { - PER_SIZE_REG_SEQ(W_XGA, H_XGA, 0, 0, 2), + PER_SIZE_REG_SEQ(XGA_WIDTH, XGA_HEIGHT, 0, 0, 2), { CTRLI, 0x00}, ENDMARKER, }; static const struct regval_list ov2640_sxga_regs[] = { - PER_SIZE_REG_SEQ(W_SXGA, H_SXGA, 0, 0, 2), + PER_SIZE_REG_SEQ(SXGA_WIDTH, SXGA_HEIGHT, 0, 0, 2), { CTRLI, 0x00}, { R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE }, ENDMARKER, }; static const struct regval_list ov2640_uxga_regs[] = { - PER_SIZE_REG_SEQ(W_UXGA, H_UXGA, 0, 0, 0), + PER_SIZE_REG_SEQ(UXGA_WIDTH, UXGA_HEIGHT, 0, 0, 0), { CTRLI, 0x00}, { R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE }, ENDMARKER, @@ -567,14 +545,14 @@ static const struct regval_list ov2640_uxga_regs[] = { {.name = n, .width = w , .height = h, .regs = r } static const struct ov2640_win_size ov2640_supported_win_sizes[] = { - OV2640_SIZE("QCIF", W_QCIF, H_QCIF, ov2640_qcif_regs), - OV2640_SIZE("QVGA", W_QVGA, H_QVGA, ov2640_qvga_regs), - OV2640_SIZE("CIF", W_CIF, H_CIF, ov2640_cif_regs), - OV2640_SIZE("VGA", W_VGA, H_VGA, ov2640_vga_regs), - OV2640_SIZE("SVGA", W_SVGA, H_SVGA, ov2640_svga_regs), - OV2640_SIZE("XGA", W_XGA, H_XGA, ov2640_xga_regs), - OV2640_SIZE("SXGA", W_SXGA, H_SXGA, ov2640_sxga_regs), - OV2640_SIZE("UXGA", W_UXGA, H_UXGA, ov2640_uxga_regs), + OV2640_SIZE("QCIF", QCIF_WIDTH, QCIF_HEIGHT, ov2640_qcif_regs), + OV2640_SIZE("QVGA", QVGA_WIDTH, QVGA_HEIGHT, ov2640_qvga_regs), + OV2640_SIZE("CIF", CIF_WIDTH, CIF_HEIGHT, ov2640_cif_regs), + OV2640_SIZE("VGA", VGA_WIDTH, VGA_HEIGHT, ov2640_vga_regs), + OV2640_SIZE("SVGA", SVGA_WIDTH, SVGA_HEIGHT, ov2640_svga_regs), + OV2640_SIZE("XGA", XGA_WIDTH, XGA_HEIGHT, ov2640_xga_regs), + OV2640_SIZE("SXGA", SXGA_WIDTH, SXGA_HEIGHT, ov2640_sxga_regs), + OV2640_SIZE("UXGA", UXGA_WIDTH, UXGA_HEIGHT, ov2640_uxga_regs), }; /* @@ -867,7 +845,7 @@ static int ov2640_g_fmt(struct v4l2_subdev *sd, struct ov2640_priv *priv = to_ov2640(client); if (!priv->win) { - u32 width = W_SVGA, height = H_SVGA; + u32 width = SVGA_WIDTH, height = SVGA_HEIGHT; priv->win = ov2640_select_win(&width, &height); priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8; } @@ -954,8 +932,8 @@ static int ov2640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { a->c.left = 0; a->c.top = 0; - a->c.width = W_UXGA; - a->c.height = H_UXGA; + a->c.width = UXGA_WIDTH; + a->c.height = UXGA_HEIGHT; a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; return 0; @@ -965,8 +943,8 @@ static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) { a->bounds.left = 0; a->bounds.top = 0; - a->bounds.width = W_UXGA; - a->bounds.height = H_UXGA; + a->bounds.width = UXGA_WIDTH; + a->bounds.height = UXGA_HEIGHT; a->defrect = a->bounds; a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; a->pixelaspect.numerator = 1; diff --git a/drivers/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c index 656d889c1c79..4ebd329d7b42 100644 --- a/drivers/media/i2c/ths8200.c +++ b/drivers/media/i2c/ths8200.c @@ -58,21 +58,11 @@ static inline struct ths8200_state *to_state(struct v4l2_subdev *sd) return container_of(sd, struct ths8200_state, sd); } -static inline unsigned hblanking(const struct v4l2_bt_timings *t) -{ - return V4L2_DV_BT_BLANKING_WIDTH(t); -} - static inline unsigned htotal(const struct v4l2_bt_timings *t) { return V4L2_DV_BT_FRAME_WIDTH(t); } -static inline unsigned vblanking(const struct v4l2_bt_timings *t) -{ - return V4L2_DV_BT_BLANKING_HEIGHT(t); -} - static inline unsigned vtotal(const struct v4l2_bt_timings *t) { return V4L2_DV_BT_FRAME_HEIGHT(t); diff --git a/drivers/media/mmc/siano/Kconfig b/drivers/media/mmc/siano/Kconfig index aa05ad3c1ccb..7693487e2f63 100644 --- a/drivers/media/mmc/siano/Kconfig +++ b/drivers/media/mmc/siano/Kconfig @@ -6,6 +6,8 @@ config SMS_SDIO_DRV tristate "Siano SMS1xxx based MDTV via SDIO interface" depends on DVB_CORE && HAS_DMA depends on MMC + depends on !RC_CORE || RC_CORE select MEDIA_COMMON_OPTIONS + select SMS_SIANO_MDTV ---help--- Choose if you would like to have Siano's support for SDIO interface diff --git a/drivers/media/pci/bt8xx/Kconfig b/drivers/media/pci/bt8xx/Kconfig index 61d09e010814..4a93f6ded100 100644 --- a/drivers/media/pci/bt8xx/Kconfig +++ b/drivers/media/pci/bt8xx/Kconfig @@ -2,15 +2,17 @@ config VIDEO_BT848 tristate "BT848 Video For Linux" depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 select I2C_ALGOBIT - select VIDEO_BTCX select VIDEOBUF_DMA_SG depends on RC_CORE + depends on MEDIA_RADIO_SUPPORT select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TVAUDIO if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TDA7432 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT + select RADIO_ADAPTERS + select RADIO_TEA575X ---help--- Support for BT848 based frame grabber/overlay boards. This includes the Miro, Hauppauge and STB boards. Please read the material in diff --git a/drivers/media/pci/bt8xx/Makefile b/drivers/media/pci/bt8xx/Makefile index f9fe7c4e7d53..2d4c3dd88be1 100644 --- a/drivers/media/pci/bt8xx/Makefile +++ b/drivers/media/pci/bt8xx/Makefile @@ -1,6 +1,6 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \ - bttv-input.o bttv-audio-hook.o + bttv-input.o bttv-audio-hook.o btcx-risc.o obj-$(CONFIG_VIDEO_BT848) += bttv.o obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o diff --git a/drivers/media/pci/bt8xx/bt878.c b/drivers/media/pci/bt8xx/bt878.c index 11765835d7b2..0939d399b774 100644 --- a/drivers/media/pci/bt8xx/bt878.c +++ b/drivers/media/pci/bt8xx/bt878.c @@ -590,9 +590,3 @@ module_init(bt878_init_module); module_exit(bt878_cleanup_module); MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/common/btcx-risc.c b/drivers/media/pci/bt8xx/btcx-risc.c similarity index 90% rename from drivers/media/common/btcx-risc.c rename to drivers/media/pci/bt8xx/btcx-risc.c index ac1b2687a20d..00f0880b6d66 100644 --- a/drivers/media/common/btcx-risc.c +++ b/drivers/media/pci/bt8xx/btcx-risc.c @@ -32,13 +32,9 @@ #include "btcx-risc.h" -MODULE_DESCRIPTION("some code shared by bttv and cx88xx drivers"); -MODULE_AUTHOR("Gerd Knorr"); -MODULE_LICENSE("GPL"); - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"debug messages, default is 0 (no)"); +static unsigned int btcx_debug; +module_param(btcx_debug, int, 0644); +MODULE_PARM_DESC(btcx_debug,"debug messages, default is 0 (no)"); /* ---------------------------------------------------------- */ /* allocate/free risc memory */ @@ -50,7 +46,7 @@ void btcx_riscmem_free(struct pci_dev *pci, { if (NULL == risc->cpu) return; - if (debug) { + if (btcx_debug) { memcnt--; printk("btcx: riscmem free [%d] dma=%lx\n", memcnt, (unsigned long)risc->dma); @@ -75,7 +71,7 @@ int btcx_riscmem_alloc(struct pci_dev *pci, risc->cpu = cpu; risc->dma = dma; risc->size = size; - if (debug) { + if (btcx_debug) { memcnt++; printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n", memcnt, (unsigned long)dma, cpu, size); @@ -141,7 +137,7 @@ btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int m dx = nx - win->left; win->left = nx; win->width = nw; - if (debug) + if (btcx_debug) printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n", win->width, win->height, win->left, win->top, dx); @@ -153,7 +149,7 @@ btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int m nw += mask+1; clips[i].c.left = nx; clips[i].c.width = nw; - if (debug) + if (btcx_debug) printk(KERN_DEBUG "btcx: clip align %dx%d+%d+%d\n", clips[i].c.width, clips[i].c.height, clips[i].c.left, clips[i].c.top); @@ -234,7 +230,7 @@ btcx_calc_skips(int line, int width, int *maxy, *nskips = skip; *maxy = maxline; - if (debug) { + if (btcx_debug) { printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline); for (skip = 0; skip < *nskips; skip++) { printk(" %d-%d",skips[skip].start,skips[skip].end); @@ -242,19 +238,3 @@ btcx_calc_skips(int line, int width, int *maxy, printk("\n"); } } - -/* ---------------------------------------------------------- */ - -EXPORT_SYMBOL(btcx_riscmem_alloc); -EXPORT_SYMBOL(btcx_riscmem_free); - -EXPORT_SYMBOL(btcx_screen_clips); -EXPORT_SYMBOL(btcx_align); -EXPORT_SYMBOL(btcx_sort_clips); -EXPORT_SYMBOL(btcx_calc_skips); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/btcx-risc.h b/drivers/media/pci/bt8xx/btcx-risc.h new file mode 100644 index 000000000000..1ed7a000160a --- /dev/null +++ b/drivers/media/pci/bt8xx/btcx-risc.h @@ -0,0 +1,26 @@ +struct btcx_riscmem { + unsigned int size; + __le32 *cpu; + __le32 *jmp; + dma_addr_t dma; +}; + +struct btcx_skiplist { + int start; + int end; +}; + +int btcx_riscmem_alloc(struct pci_dev *pci, + struct btcx_riscmem *risc, + unsigned int size); +void btcx_riscmem_free(struct pci_dev *pci, + struct btcx_riscmem *risc); + +int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, unsigned int n); +int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, + unsigned int n, int mask); +void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); +void btcx_calc_skips(int line, int width, int *maxy, + struct btcx_skiplist *skips, unsigned int *nskips, + const struct v4l2_clip *clips, unsigned int nclips); diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index 41055606b969..4654fb65ca21 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -84,8 +84,7 @@ static void gv800s_init(struct bttv *btv); static void td3116_muxsel(struct bttv *btv, unsigned int input); static int terratec_active_radio_upgrade(struct bttv *btv); -static int tea5757_read(struct bttv *btv); -static int tea5757_write(struct bttv *btv, int value); +static int tea575x_init(struct bttv *btv); static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256]); static int pvr_boot(struct bttv *btv); @@ -3085,12 +3084,12 @@ static void miro_pinnacle_gpio(struct bttv *btv) if (0 == (gpio & 0x20)) { btv->has_radio = 1; if (!miro_fmtuner[id]) { - btv->has_matchbox = 1; - btv->mbox_we = (1<<6); - btv->mbox_most = (1<<7); - btv->mbox_clk = (1<<8); - btv->mbox_data = (1<<9); - btv->mbox_mask = (1<<6)|(1<<7)|(1<<8)|(1<<9); + btv->has_tea575x = 1; + btv->tea_gpio.wren = 6; + btv->tea_gpio.most = 7; + btv->tea_gpio.clk = 8; + btv->tea_gpio.data = 9; + tea575x_init(btv); } } else { btv->has_radio = 0; @@ -3104,7 +3103,7 @@ static void miro_pinnacle_gpio(struct bttv *btv) pr_info("%d: miro: id=%d tuner=%d radio=%s stereo=%s\n", btv->c.nr, id+1, btv->tuner_type, !btv->has_radio ? "no" : - (btv->has_matchbox ? "matchbox" : "fmtuner"), + (btv->has_tea575x ? "tea575x" : "fmtuner"), (-1 == msp) ? "no" : "yes"); } else { /* new cards with microtune tuner */ @@ -3382,12 +3381,12 @@ void bttv_init_card2(struct bttv *btv) break; case BTTV_BOARD_VHX: btv->has_radio = 1; - btv->has_matchbox = 1; - btv->mbox_we = 0x20; - btv->mbox_most = 0; - btv->mbox_clk = 0x08; - btv->mbox_data = 0x10; - btv->mbox_mask = 0x38; + btv->has_tea575x = 1; + btv->tea_gpio.wren = 5; + btv->tea_gpio.most = 6; + btv->tea_gpio.clk = 3; + btv->tea_gpio.data = 4; + tea575x_init(btv); break; case BTTV_BOARD_VOBIS_BOOSTAR: case BTTV_BOARD_TERRATV: @@ -3745,33 +3744,112 @@ static void hauppauge_eeprom(struct bttv *btv) btv->radio_uses_msp_demodulator = 1; } +/* ----------------------------------------------------------------------- */ + +static void bttv_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) +{ + struct bttv *btv = tea->private_data; + struct bttv_tea575x_gpio gpio = btv->tea_gpio; + u16 val = 0; + + val |= (pins & TEA575X_DATA) ? (1 << gpio.data) : 0; + val |= (pins & TEA575X_CLK) ? (1 << gpio.clk) : 0; + val |= (pins & TEA575X_WREN) ? (1 << gpio.wren) : 0; + + gpio_bits((1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren), val); + if (btv->mbox_ior) { + /* IOW and CSEL active */ + gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); + udelay(5); + /* all inactive */ + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); + } +} + +static u8 bttv_tea575x_get_pins(struct snd_tea575x *tea) +{ + struct bttv *btv = tea->private_data; + struct bttv_tea575x_gpio gpio = btv->tea_gpio; + u8 ret = 0; + u16 val; + + if (btv->mbox_ior) { + /* IOR and CSEL active */ + gpio_bits(btv->mbox_ior | btv->mbox_csel, 0); + udelay(5); + } + val = gpio_read(); + if (btv->mbox_ior) { + /* all inactive */ + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); + } + + if (val & (1 << gpio.data)) + ret |= TEA575X_DATA; + if (val & (1 << gpio.most)) + ret |= TEA575X_MOST; + + return ret; +} + +static void bttv_tea575x_set_direction(struct snd_tea575x *tea, bool output) +{ + struct bttv *btv = tea->private_data; + struct bttv_tea575x_gpio gpio = btv->tea_gpio; + u32 mask = (1 << gpio.clk) | (1 << gpio.wren) | (1 << gpio.data) | + (1 << gpio.most); + + if (output) + gpio_inout(mask, (1 << gpio.data) | (1 << gpio.clk) | + (1 << gpio.wren)); + else + gpio_inout(mask, (1 << gpio.clk) | (1 << gpio.wren)); +} + +static struct snd_tea575x_ops bttv_tea_ops = { + .set_pins = bttv_tea575x_set_pins, + .get_pins = bttv_tea575x_get_pins, + .set_direction = bttv_tea575x_set_direction, +}; + +static int tea575x_init(struct bttv *btv) +{ + btv->tea.private_data = btv; + btv->tea.ops = &bttv_tea_ops; + if (!snd_tea575x_hw_init(&btv->tea)) { + pr_info("%d: detected TEA575x radio\n", btv->c.nr); + btv->tea.mute = false; + return 0; + } + + btv->has_tea575x = 0; + btv->has_radio = 0; + + return -ENODEV; +} + +/* ----------------------------------------------------------------------- */ + static int terratec_active_radio_upgrade(struct bttv *btv) { - int freq; - btv->has_radio = 1; - btv->has_matchbox = 1; - btv->mbox_we = 0x10; - btv->mbox_most = 0x20; - btv->mbox_clk = 0x08; - btv->mbox_data = 0x04; - btv->mbox_mask = 0x3c; + btv->has_tea575x = 1; + btv->tea_gpio.wren = 4; + btv->tea_gpio.most = 5; + btv->tea_gpio.clk = 3; + btv->tea_gpio.data = 2; btv->mbox_iow = 1 << 8; btv->mbox_ior = 1 << 9; btv->mbox_csel = 1 << 10; - freq=88000/62.5; - tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */ - if (0x1ed8 == tea5757_read(btv)) { + if (!tea575x_init(btv)) { pr_info("%d: Terratec Active Radio Upgrade found\n", btv->c.nr); - btv->has_radio = 1; - btv->has_saa6588 = 1; - btv->has_matchbox = 1; - } else { - btv->has_radio = 0; - btv->has_matchbox = 0; + btv->has_saa6588 = 1; } + return 0; } @@ -4292,181 +4370,6 @@ init_PCI8604PW(struct bttv *btv) } } - - -/* ----------------------------------------------------------------------- */ -/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports */ -/* - * Copyright (c) 1999 Csaba Halasz - * This code is placed under the terms of the GNU General Public License - * - * Brutally hacked by Dan Sheridan djs52 8/3/00 - */ - -static void bus_low(struct bttv *btv, int bit) -{ - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - } - - gpio_bits(bit,0); - udelay(5); - - if (btv->mbox_ior) { - gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); - udelay(5); - } -} - -static void bus_high(struct bttv *btv, int bit) -{ - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - } - - gpio_bits(bit,bit); - udelay(5); - - if (btv->mbox_ior) { - gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); - udelay(5); - } -} - -static int bus_in(struct bttv *btv, int bit) -{ - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - - gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); - udelay(5); - } - return gpio_read() & (bit); -} - -/* TEA5757 register bits */ -#define TEA_FREQ 0:14 -#define TEA_BUFFER 15:15 - -#define TEA_SIGNAL_STRENGTH 16:17 - -#define TEA_PORT1 18:18 -#define TEA_PORT0 19:19 - -#define TEA_BAND 20:21 -#define TEA_BAND_FM 0 -#define TEA_BAND_MW 1 -#define TEA_BAND_LW 2 -#define TEA_BAND_SW 3 - -#define TEA_MONO 22:22 -#define TEA_ALLOW_STEREO 0 -#define TEA_FORCE_MONO 1 - -#define TEA_SEARCH_DIRECTION 23:23 -#define TEA_SEARCH_DOWN 0 -#define TEA_SEARCH_UP 1 - -#define TEA_STATUS 24:24 -#define TEA_STATUS_TUNED 0 -#define TEA_STATUS_SEARCHING 1 - -/* Low-level stuff */ -static int tea5757_read(struct bttv *btv) -{ - unsigned long timeout; - int value = 0; - int i; - - /* better safe than sorry */ - gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we); - - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - } - - if (bttv_gpio) - bttv_gpio_tracking(btv,"tea5757 read"); - - bus_low(btv,btv->mbox_we); - bus_low(btv,btv->mbox_clk); - - udelay(10); - timeout= jiffies + msecs_to_jiffies(1000); - - /* wait for DATA line to go low; error if it doesn't */ - while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout)) - schedule(); - if (bus_in(btv,btv->mbox_data)) { - pr_warn("%d: tea5757: read timeout\n", btv->c.nr); - return -1; - } - - dprintk("%d: tea5757:", btv->c.nr); - for (i = 0; i < 24; i++) { - udelay(5); - bus_high(btv,btv->mbox_clk); - udelay(5); - dprintk_cont("%c", - bus_in(btv, btv->mbox_most) == 0 ? 'T' : '-'); - bus_low(btv,btv->mbox_clk); - value <<= 1; - value |= (bus_in(btv,btv->mbox_data) == 0)?0:1; /* MSB first */ - dprintk_cont("%c", - bus_in(btv, btv->mbox_most) == 0 ? 'S' : 'M'); - } - dprintk_cont("\n"); - dprintk("%d: tea5757: read 0x%X\n", btv->c.nr, value); - return value; -} - -static int tea5757_write(struct bttv *btv, int value) -{ - int i; - int reg = value; - - gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we | btv->mbox_data); - - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - } - if (bttv_gpio) - bttv_gpio_tracking(btv,"tea5757 write"); - - dprintk("%d: tea5757: write 0x%X\n", btv->c.nr, value); - bus_low(btv,btv->mbox_clk); - bus_high(btv,btv->mbox_we); - for (i = 0; i < 25; i++) { - if (reg & 0x1000000) - bus_high(btv,btv->mbox_data); - else - bus_low(btv,btv->mbox_data); - reg <<= 1; - bus_high(btv,btv->mbox_clk); - udelay(10); - bus_low(btv,btv->mbox_clk); - udelay(10); - } - bus_low(btv,btv->mbox_we); /* unmute !!! */ - return 0; -} - -void tea5757_set_freq(struct bttv *btv, unsigned short freq) -{ - dprintk("tea5757_set_freq %d\n",freq); - tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */ -} - /* RemoteVision MX (rv605) muxsel helper [Miguel Freitas] * * This is needed because rv605 don't use a normal multiplex, but a crosspoint @@ -5048,10 +4951,3 @@ int bttv_handle_chipset(struct bttv *btv) pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency); return 0; } - - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 4a8176c09fc9..4ec2a3c3f23c 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1874,8 +1874,10 @@ static void bttv_set_frequency(struct bttv *btv, const struct v4l2_frequency *f) if (new_freq.type == V4L2_TUNER_RADIO) { radio_enable(btv); btv->radio_freq = new_freq.frequency; - if (btv->has_matchbox) - tea5757_set_freq(btv, btv->radio_freq); + if (btv->has_tea575x) { + btv->tea.freq = btv->radio_freq; + snd_tea575x_set_freq(&btv->tea); + } } else { btv->tv_freq = new_freq.frequency; } @@ -2513,6 +2515,8 @@ static int bttv_querycap(struct file *file, void *priv, if (btv->has_saa6588) cap->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE; + if (btv->has_tea575x) + cap->device_caps |= V4L2_CAP_HW_FREQ_SEEK; } return 0; } @@ -3242,6 +3246,9 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) if (btv->audio_mode_gpio) btv->audio_mode_gpio(btv, t, 0); + if (btv->has_tea575x) + return snd_tea575x_g_tuner(&btv->tea, t); + return 0; } @@ -3259,6 +3266,30 @@ static int radio_s_tuner(struct file *file, void *priv, return 0; } +static int radio_s_hw_freq_seek(struct file *file, void *priv, + const struct v4l2_hw_freq_seek *a) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (btv->has_tea575x) + return snd_tea575x_s_hw_freq_seek(file, &btv->tea, a); + + return -ENOTTY; +} + +static int radio_enum_freq_bands(struct file *file, void *priv, + struct v4l2_frequency_band *band) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (btv->has_tea575x) + return snd_tea575x_enum_freq_bands(&btv->tea, band); + + return -ENOTTY; +} + static ssize_t radio_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { @@ -3316,6 +3347,8 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_s_tuner = radio_s_tuner, .vidioc_g_frequency = bttv_g_frequency, .vidioc_s_frequency = bttv_s_frequency, + .vidioc_s_hw_freq_seek = radio_s_hw_freq_seek, + .vidioc_enum_freq_bands = radio_enum_freq_bands, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; @@ -3884,7 +3917,6 @@ static struct video_device *vdev_init(struct bttv *btv, *vfd = *template; vfd->v4l2_dev = &btv->c.v4l2_dev; vfd->release = video_device_release; - vfd->debug = bttv_debug; video_set_drvdata(vfd, btv); snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", @@ -4429,9 +4461,3 @@ static void __exit bttv_cleanup_module(void) module_init(bttv_init_module); module_exit(bttv_cleanup_module); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttv-gpio.c b/drivers/media/pci/bt8xx/bttv-gpio.c index 3f364b7062b9..25b9916906d5 100644 --- a/drivers/media/pci/bt8xx/bttv-gpio.c +++ b/drivers/media/pci/bt8xx/bttv-gpio.c @@ -181,9 +181,3 @@ void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) btwrite(data,BT848_GPIO_DATA); spin_unlock_irqrestore(&btv->gpio_lock,flags); } - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttv-if.c b/drivers/media/pci/bt8xx/bttv-if.c index a6a540dc9e4b..538652e16a5c 100644 --- a/drivers/media/pci/bt8xx/bttv-if.c +++ b/drivers/media/pci/bt8xx/bttv-if.c @@ -113,9 +113,3 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) bttv_gpio_tracking(btv,"extern write"); return 0; } - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttv-risc.c b/drivers/media/pci/bt8xx/bttv-risc.c index 4d3f05a19af3..3859dde98be2 100644 --- a/drivers/media/pci/bt8xx/bttv-risc.c +++ b/drivers/media/pci/bt8xx/bttv-risc.c @@ -901,9 +901,3 @@ bttv_overlay_risc(struct bttv *btv, buf->vb.field = ov->field; return 0; } - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttv-vbi.c b/drivers/media/pci/bt8xx/bttv-vbi.c index b433267d9aa9..e77129c92fa0 100644 --- a/drivers/media/pci/bt8xx/bttv-vbi.c +++ b/drivers/media/pci/bt8xx/bttv-vbi.c @@ -450,10 +450,3 @@ void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm) /* See bttv_vbi_fmt_set(). */ f->end = tvnorm->vbistart[0] * 2 + 2; } - -/* ----------------------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttv.h b/drivers/media/pci/bt8xx/bttv.h index f08126244662..91301c3cad1e 100644 --- a/drivers/media/pci/bt8xx/bttv.h +++ b/drivers/media/pci/bt8xx/bttv.h @@ -378,8 +378,3 @@ extern void bttv_input_fini(struct bttv *dev); extern void bttv_input_irq(struct bttv *dev); #endif /* _BTTV_H_ */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index 9fe19488b30b..bc048c586b1f 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -42,6 +42,7 @@ #include #include #include +#include #include "bt848.h" #include "bttv.h" @@ -359,6 +360,10 @@ struct bttv_suspend_state { struct bttv_buffer *vbi; }; +struct bttv_tea575x_gpio { + u8 data, clk, wren, most; +}; + struct bttv { struct bttv_core c; @@ -445,12 +450,9 @@ struct bttv { /* miro/pinnacle + Aimslab VHX philips matchbox (tea5757 radio tuner) support */ - int has_matchbox; - int mbox_we; - int mbox_data; - int mbox_clk; - int mbox_most; - int mbox_mask; + int has_tea575x; + struct bttv_tea575x_gpio tea_gpio; + struct snd_tea575x tea; /* ISA stuff (Terratec Active Radio Upgrade) */ int mbox_ior; @@ -531,9 +533,3 @@ static inline unsigned int bttv_muxsel(const struct bttv *btv, #define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) #endif /* _BTTVP_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index f613314b360b..74d774e5227b 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -41,6 +41,7 @@ config VIDEO_CX23885 select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT ---help--- This is a video4linux driver for Conexant 23885 based diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index db99ca2613ba..f384f295676e 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -614,7 +614,7 @@ struct cx23885_board cx23885_boards[] = { .portb = CX23885_MPEG_DVB, }, [CX23885_BOARD_HAUPPAUGE_HVR4400] = { - .name = "Hauppauge WinTV-HVR4400", + .name = "Hauppauge WinTV-HVR4400/HVR5500", .porta = CX23885_ANALOG_VIDEO, .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, @@ -622,6 +622,10 @@ struct cx23885_board cx23885_boards[] = { .tuner_addr = 0x60, /* 0xc0 >> 1 */ .tuner_bus = 1, }, + [CX23885_BOARD_HAUPPAUGE_STARBURST] = { + .name = "Hauppauge WinTV Starburst", + .portb = CX23885_MPEG_DVB, + }, [CX23885_BOARD_AVERMEDIA_HC81R] = { .name = "AVerTV Hybrid Express Slim HC81R", .tuner_type = TUNER_XC2028, @@ -706,6 +710,11 @@ struct cx23885_board cx23885_boards[] = { .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_HAUPPAUGE_HVR5525] = { + .name = "Hauppauge WinTV-HVR5525", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -936,19 +945,19 @@ struct cx23885_subid cx23885_subids[] = { }, { .subvendor = 0x0070, .subdevice = 0xc108, - .card = CX23885_BOARD_HAUPPAUGE_HVR4400, + .card = CX23885_BOARD_HAUPPAUGE_HVR4400, /* Hauppauge WinTV HVR-4400 (Model 121xxx, Hybrid DVB-T/S2, IR) */ }, { .subvendor = 0x0070, .subdevice = 0xc138, - .card = CX23885_BOARD_HAUPPAUGE_HVR4400, + .card = CX23885_BOARD_HAUPPAUGE_HVR4400, /* Hauppauge WinTV HVR-5500 (Model 121xxx, Hybrid DVB-T/C/S2, IR) */ }, { .subvendor = 0x0070, .subdevice = 0xc12a, - .card = CX23885_BOARD_HAUPPAUGE_HVR4400, + .card = CX23885_BOARD_HAUPPAUGE_STARBURST, /* Hauppauge WinTV Starburst (Model 121x00, DVB-S2, IR) */ }, { .subvendor = 0x0070, .subdevice = 0xc1f8, - .card = CX23885_BOARD_HAUPPAUGE_HVR4400, + .card = CX23885_BOARD_HAUPPAUGE_HVR4400, /* Hauppauge WinTV HVR-5500 (Model 121xxx, Hybrid DVB-T/C/S2, IR) */ }, { .subvendor = 0x1461, .subdevice = 0xd939, @@ -989,6 +998,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x4254, .subdevice = 0x0982, .card = CX23885_BOARD_DVBSKY_T982, + }, { + .subvendor = 0x0070, + .subdevice = 0xf038, + .card = CX23885_BOARD_HAUPPAUGE_HVR5525, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -1161,6 +1174,8 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) case 85721: /* WinTV-HVR1290 (PCIe, OEM, RCA in, IR, Dual channel ATSC and Basic analog */ + case 150329: + /* WinTV-HVR5525 (PCIe, DVB-S/S2, DVB-T/T2/C) */ break; default: printk(KERN_WARNING "%s: warning: " @@ -1545,8 +1560,9 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ break; case CX23885_BOARD_HAUPPAUGE_HVR4400: + case CX23885_BOARD_HAUPPAUGE_STARBURST: /* GPIO-8 tda10071 demod reset */ - /* GPIO-9 si2165 demod reset */ + /* GPIO-9 si2165 demod reset (only HVR4400/HVR5500)*/ /* Put the parts into reset and back */ cx23885_gpio_enable(dev, GPIO_8 | GPIO_9, 1); @@ -1632,6 +1648,29 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) msleep(100); cx23885_gpio_set(dev, GPIO_2); break; + case CX23885_BOARD_HAUPPAUGE_HVR5525: + /* + * GPIO-00 IR_WIDE + * GPIO-02 wake# + * GPIO-03 VAUX Pres. + * GPIO-07 PROG# + * GPIO-08 SAT_RESN + * GPIO-09 TER_RESN + * GPIO-10 B2_SENSE + * GPIO-11 B1_SENSE + * GPIO-15 IR_LED_STATUS + * GPIO-19 IR_NARROW + * GPIO-20 Blauster1 + * ALTGPIO VAUX_SWITCH + * AUX_PLL_CLK : Blaster2 + */ + /* Put the parts into reset and back */ + cx23885_gpio_enable(dev, GPIO_8 | GPIO_9, 1); + cx23885_gpio_clear(dev, GPIO_8 | GPIO_9); + msleep(100); + cx23885_gpio_set(dev, GPIO_8 | GPIO_9); + msleep(100); + break; } } @@ -1872,7 +1911,9 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_HAUPPAUGE_HVR4400: + case CX23885_BOARD_HAUPPAUGE_STARBURST: case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE: + case CX23885_BOARD_HAUPPAUGE_HVR5525: if (dev->i2c_bus[0].i2c_rc == 0) hauppauge_eeprom(dev, eeprom+0xc0); break; @@ -1980,6 +2021,11 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; + case CX23885_BOARD_HAUPPAUGE_STARBURST: + ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; case CX23885_BOARD_DVBSKY_T9580: case CX23885_BOARD_DVBSKY_T982: ts1->gen_ctrl_val = 0x5; /* Parallel */ @@ -1997,6 +2043,14 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; + case CX23885_BOARD_HAUPPAUGE_HVR5525: + ts1->gen_ctrl_val = 0x5; /* Parallel */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 1d9d0f86ca8c..1ad49946d7fa 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -2049,11 +2049,11 @@ static void cx23885_finidev(struct pci_dev *pci_dev) cx23885_shutdown(dev); - pci_disable_device(pci_dev); - /* unregister stuff */ free_irq(pci_dev->irq, dev); + pci_disable_device(pci_dev); + cx23885_dev_unregister(dev); vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); v4l2_ctrl_handler_free(&dev->ctrl_handler); diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index c47d18270cfc..45fbe1e4d2d0 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -74,6 +74,7 @@ #include "sp2.h" #include "m88ds3103.h" #include "m88ts2022.h" +#include "m88rs6000t.h" static unsigned int debug; @@ -915,6 +916,16 @@ static const struct m88ds3103_config dvbsky_s952_portc_m88ds3103_config = { .agc = 0x99, }; +static const struct m88ds3103_config hauppauge_hvr5525_m88ds3103_config = { + .i2c_addr = 0x69, + .clock = 27000000, + .i2c_wr_max = 33, + .ts_mode = M88DS3103_TS_PARALLEL, + .ts_clk = 16000, + .ts_clk_pol = 1, + .agc = 0x99, +}; + static int netup_altera_fpga_rw(void *device, int flag, int data, int read) { struct cx23885_dev *dev = (struct cx23885_dev *)device; @@ -1058,6 +1069,116 @@ static struct dib7000p_config dib7070p_dib7000p_config = { .hostbus_diversity = 1, }; +static int dvb_register_ci_mac(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + struct i2c_client *client_ci = NULL; + struct vb2_dvb_frontend *fe0; + + fe0 = vb2_dvb_get_frontend(&port->frontends, 1); + if (!fe0) + return -EINVAL; + + switch (dev->board) { + case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: { + static struct netup_card_info cinfo; + + netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo); + memcpy(port->frontends.adapter.proposed_mac, + cinfo.port[port->nr - 1].mac, 6); + printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n", + port->nr, port->frontends.adapter.proposed_mac); + + netup_ci_init(port); + return 0; + } + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { + struct altera_ci_config netup_ci_cfg = { + .dev = dev,/* magic number to identify*/ + .adapter = &port->frontends.adapter,/* for CI */ + .demux = &fe0->dvb.demux,/* for hw pid filter */ + .fpga_rw = netup_altera_fpga_rw, + }; + + altera_ci_init(&netup_ci_cfg, port->nr); + return 0; + } + case CX23885_BOARD_TEVII_S470: { + u8 eeprom[256]; /* 24C02 i2c eeprom */ + + if (port->nr != 1) + return 0; + + /* Read entire EEPROM */ + dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); + printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0); + memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6); + return 0; + } + case CX23885_BOARD_DVBSKY_T9580: + case CX23885_BOARD_DVBSKY_S950: + case CX23885_BOARD_DVBSKY_S952: + case CX23885_BOARD_DVBSKY_T982: { + u8 eeprom[256]; /* 24C02 i2c eeprom */ + + if (port->nr > 2) + return 0; + + /* Read entire EEPROM */ + dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, + sizeof(eeprom)); + printk(KERN_INFO "%s port %d MAC address: %pM\n", + cx23885_boards[dev->board].name, port->nr, + eeprom + 0xc0 + (port->nr-1) * 8); + memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 + + (port->nr-1) * 8, 6); + return 0; + } + case CX23885_BOARD_DVBSKY_S950C: + case CX23885_BOARD_DVBSKY_T980C: + case CX23885_BOARD_TT_CT2_4500_CI: { + u8 eeprom[256]; /* 24C02 i2c eeprom */ + struct sp2_config sp2_config; + struct i2c_board_info info; + struct cx23885_i2c *i2c_bus2 = &dev->i2c_bus[1]; + + /* attach CI */ + memset(&sp2_config, 0, sizeof(sp2_config)); + sp2_config.dvb_adap = &port->frontends.adapter; + sp2_config.priv = port; + sp2_config.ci_control = cx23885_sp2_ci_ctrl; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "sp2", I2C_NAME_SIZE); + info.addr = 0x40; + info.platform_data = &sp2_config; + request_module(info.type); + client_ci = i2c_new_device(&i2c_bus2->i2c_adap, &info); + if (client_ci == NULL || client_ci->dev.driver == NULL) + return -ENODEV; + if (!try_module_get(client_ci->dev.driver->owner)) { + i2c_unregister_device(client_ci); + return -ENODEV; + } + port->i2c_client_ci = client_ci; + + if (port->nr != 1) + return 0; + + /* Read entire EEPROM */ + dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, + sizeof(eeprom)); + printk(KERN_INFO "%s MAC address: %pM\n", + cx23885_boards[dev->board].name, eeprom + 0xc0); + memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0, 6); + return 0; + } + } + return 0; +} + static int dvb_register(struct cx23885_tsport *port) { struct dib7000p_ops dib7000p_ops; @@ -1066,11 +1187,10 @@ static int dvb_register(struct cx23885_tsport *port) struct vb2_dvb_frontend *fe0, *fe1 = NULL; struct si2168_config si2168_config; struct si2157_config si2157_config; - struct sp2_config sp2_config; struct m88ts2022_config m88ts2022_config; struct i2c_board_info info; struct i2c_adapter *adapter; - struct i2c_client *client_demod = NULL, *client_tuner = NULL, *client_ci = NULL; + struct i2c_client *client_demod = NULL, *client_tuner = NULL; const struct m88ds3103_config *p_m88ds3103_config = NULL; int (*p_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage) = NULL; int mfe_shared = 0; /* bus not shared by default */ @@ -1710,6 +1830,17 @@ static int dvb_register(struct cx23885_tsport *port) break; } break; + case CX23885_BOARD_HAUPPAUGE_STARBURST: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(tda10071_attach, + &hauppauge_tda10071_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(a8293_attach, fe0->dvb.frontend, + &i2c_bus->i2c_adap, + &hauppauge_a8293_config); + } + break; case CX23885_BOARD_DVBSKY_T9580: case CX23885_BOARD_DVBSKY_S950: i2c_bus = &dev->i2c_bus[0]; @@ -1790,15 +1921,11 @@ static int dvb_register(struct cx23885_tsport *port) request_module(info.type); client_tuner = i2c_new_device(adapter, &info); if (client_tuner == NULL || - client_tuner->dev.driver == NULL) { - module_put(client_demod->dev.driver->owner); - i2c_unregister_device(client_demod); + client_tuner->dev.driver == NULL) goto frontend_detach; - } + if (!try_module_get(client_tuner->dev.driver->owner)) { i2c_unregister_device(client_tuner); - module_put(client_demod->dev.driver->owner); - i2c_unregister_device(client_demod); goto frontend_detach; } port->i2c_client_tuner = client_tuner; @@ -1821,8 +1948,7 @@ static int dvb_register(struct cx23885_tsport *port) info.platform_data = &si2168_config; request_module(info.type); client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info); - if (client_demod == NULL || - client_demod->dev.driver == NULL) + if (client_demod == NULL || client_demod->dev.driver == NULL) goto frontend_detach; if (!try_module_get(client_demod->dev.driver->owner)) { i2c_unregister_device(client_demod); @@ -1840,15 +1966,10 @@ static int dvb_register(struct cx23885_tsport *port) request_module(info.type); client_tuner = i2c_new_device(adapter, &info); if (client_tuner == NULL || - client_tuner->dev.driver == NULL) { - module_put(client_demod->dev.driver->owner); - i2c_unregister_device(client_demod); + client_tuner->dev.driver == NULL) goto frontend_detach; - } if (!try_module_get(client_tuner->dev.driver->owner)) { i2c_unregister_device(client_tuner); - module_put(client_demod->dev.driver->owner); - i2c_unregister_device(client_demod); goto frontend_detach; } port->i2c_client_tuner = client_tuner; @@ -1874,8 +1995,7 @@ static int dvb_register(struct cx23885_tsport *port) info.platform_data = &m88ts2022_config; request_module(info.type); client_tuner = i2c_new_device(adapter, &info); - if (client_tuner == NULL || - client_tuner->dev.driver == NULL) + if (client_tuner == NULL || client_tuner->dev.driver == NULL) goto frontend_detach; if (!try_module_get(client_tuner->dev.driver->owner)) { i2c_unregister_device(client_tuner); @@ -1921,8 +2041,7 @@ static int dvb_register(struct cx23885_tsport *port) info.platform_data = &m88ts2022_config; request_module(info.type); client_tuner = i2c_new_device(adapter, &info); - if (client_tuner == NULL || - client_tuner->dev.driver == NULL) + if (client_tuner == NULL || client_tuner->dev.driver == NULL) goto frontend_detach; if (!try_module_get(client_tuner->dev.driver->owner)) { i2c_unregister_device(client_tuner); @@ -1967,8 +2086,7 @@ static int dvb_register(struct cx23885_tsport *port) info.platform_data = &si2168_config; request_module(info.type); client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info); - if (client_demod == NULL || - client_demod->dev.driver == NULL) + if (client_demod == NULL || client_demod->dev.driver == NULL) goto frontend_detach; if (!try_module_get(client_demod->dev.driver->owner)) { i2c_unregister_device(client_demod); @@ -1986,20 +2104,101 @@ static int dvb_register(struct cx23885_tsport *port) request_module(info.type); client_tuner = i2c_new_device(adapter, &info); if (client_tuner == NULL || - client_tuner->dev.driver == NULL) { - module_put(client_demod->dev.driver->owner); - i2c_unregister_device(client_demod); + client_tuner->dev.driver == NULL) goto frontend_detach; - } if (!try_module_get(client_tuner->dev.driver->owner)) { i2c_unregister_device(client_tuner); - module_put(client_demod->dev.driver->owner); - i2c_unregister_device(client_demod); - port->i2c_client_demod = NULL; goto frontend_detach; } port->i2c_client_tuner = client_tuner; break; + case CX23885_BOARD_HAUPPAUGE_HVR5525: + switch (port->nr) { + struct m88rs6000t_config m88rs6000t_config; + + /* port b - satellite */ + case 1: + /* attach frontend */ + fe0->dvb.frontend = dvb_attach(m88ds3103_attach, + &hauppauge_hvr5525_m88ds3103_config, + &dev->i2c_bus[0].i2c_adap, &adapter); + if (fe0->dvb.frontend == NULL) + break; + + /* attach SEC */ + if (!dvb_attach(a8293_attach, fe0->dvb.frontend, + &dev->i2c_bus[0].i2c_adap, + &hauppauge_a8293_config)) + goto frontend_detach; + + /* attach tuner */ + memset(&m88rs6000t_config, 0, sizeof(m88rs6000t_config)); + m88rs6000t_config.fe = fe0->dvb.frontend; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "m88rs6000t", I2C_NAME_SIZE); + info.addr = 0x21; + info.platform_data = &m88rs6000t_config; + request_module("%s", info.type); + client_tuner = i2c_new_device(adapter, &info); + if (!client_tuner || !client_tuner->dev.driver) + goto frontend_detach; + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; + + /* delegate signal strength measurement to tuner */ + fe0->dvb.frontend->ops.read_signal_strength = + fe0->dvb.frontend->ops.tuner_ops.get_rf_strength; + break; + /* port c - terrestrial/cable */ + case 2: + /* attach frontend */ + memset(&si2168_config, 0, sizeof(si2168_config)); + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &fe0->dvb.frontend; + si2168_config.ts_mode = SI2168_TS_SERIAL; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + info.addr = 0x64; + info.platform_data = &si2168_config; + request_module("%s", info.type); + client_demod = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info); + if (!client_demod || !client_demod->dev.driver) + goto frontend_detach; + if (!try_module_get(client_demod->dev.driver->owner)) { + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_demod = client_demod; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = fe0->dvb.frontend; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &si2157_config; + request_module("%s", info.type); + client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info); + if (!client_tuner || !client_tuner->dev.driver) { + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + port->i2c_client_demod = NULL; + goto frontend_detach; + } + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + port->i2c_client_demod = NULL; + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; + break; + } + break; default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", @@ -2036,123 +2235,29 @@ static int dvb_register(struct cx23885_tsport *port) if (ret) goto frontend_detach; - /* init CI & MAC */ - switch (dev->board) { - case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: { - static struct netup_card_info cinfo; + ret = dvb_register_ci_mac(port); + if (ret) + goto frontend_detach; - netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo); - memcpy(port->frontends.adapter.proposed_mac, - cinfo.port[port->nr - 1].mac, 6); - printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n", - port->nr, port->frontends.adapter.proposed_mac); - - netup_ci_init(port); - break; - } - case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { - struct altera_ci_config netup_ci_cfg = { - .dev = dev,/* magic number to identify*/ - .adapter = &port->frontends.adapter,/* for CI */ - .demux = &fe0->dvb.demux,/* for hw pid filter */ - .fpga_rw = netup_altera_fpga_rw, - }; - - altera_ci_init(&netup_ci_cfg, port->nr); - break; - } - case CX23885_BOARD_TEVII_S470: { - u8 eeprom[256]; /* 24C02 i2c eeprom */ - - if (port->nr != 1) - break; - - /* Read entire EEPROM */ - dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); - printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0); - memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6); - break; - } - case CX23885_BOARD_DVBSKY_T9580: - case CX23885_BOARD_DVBSKY_S950: - case CX23885_BOARD_DVBSKY_S952: - case CX23885_BOARD_DVBSKY_T982: { - u8 eeprom[256]; /* 24C02 i2c eeprom */ - - if (port->nr > 2) - break; - - /* Read entire EEPROM */ - dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, - sizeof(eeprom)); - printk(KERN_INFO "%s port %d MAC address: %pM\n", - cx23885_boards[dev->board].name, port->nr, - eeprom + 0xc0 + (port->nr-1) * 8); - memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 + - (port->nr-1) * 8, 6); - break; - } - case CX23885_BOARD_DVBSKY_S950C: - case CX23885_BOARD_DVBSKY_T980C: - case CX23885_BOARD_TT_CT2_4500_CI: { - u8 eeprom[256]; /* 24C02 i2c eeprom */ - - /* attach CI */ - memset(&sp2_config, 0, sizeof(sp2_config)); - sp2_config.dvb_adap = &port->frontends.adapter; - sp2_config.priv = port; - sp2_config.ci_control = cx23885_sp2_ci_ctrl; - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "sp2", I2C_NAME_SIZE); - info.addr = 0x40; - info.platform_data = &sp2_config; - request_module(info.type); - client_ci = i2c_new_device(&i2c_bus2->i2c_adap, &info); - if (client_ci == NULL || - client_ci->dev.driver == NULL) { - if (client_tuner) { - module_put(client_tuner->dev.driver->owner); - i2c_unregister_device(client_tuner); - } - if (client_demod) { - module_put(client_demod->dev.driver->owner); - i2c_unregister_device(client_demod); - } - goto frontend_detach; - } - if (!try_module_get(client_ci->dev.driver->owner)) { - i2c_unregister_device(client_ci); - if (client_tuner) { - module_put(client_tuner->dev.driver->owner); - i2c_unregister_device(client_tuner); - } - if (client_demod) { - module_put(client_demod->dev.driver->owner); - i2c_unregister_device(client_demod); - } - goto frontend_detach; - } - port->i2c_client_ci = client_ci; - - if (port->nr != 1) - break; - - /* Read entire EEPROM */ - dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, - sizeof(eeprom)); - printk(KERN_INFO "%s MAC address: %pM\n", - cx23885_boards[dev->board].name, eeprom + 0xc0); - memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0, 6); - break; - } - } - - return ret; + return 0; frontend_detach: + /* remove I2C client for tuner */ + client_tuner = port->i2c_client_tuner; + if (client_tuner) { + module_put(client_tuner->dev.driver->owner); + i2c_unregister_device(client_tuner); + port->i2c_client_tuner = NULL; + } + + /* remove I2C client for demodulator */ + client_demod = port->i2c_client_demod; + if (client_demod) { + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + port->i2c_client_demod = NULL; + } + port->gate_ctrl = NULL; vb2_dvb_dealloc_frontends(&port->frontends); return -EINVAL; diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c index fd71306af6e2..1135ea3f6ce5 100644 --- a/drivers/media/pci/cx23885/cx23885-i2c.c +++ b/drivers/media/pci/cx23885/cx23885-i2c.c @@ -300,8 +300,8 @@ static void do_i2c_scan(char *name, struct i2c_client *c) rc = i2c_master_recv(c, &buf, 0); if (rc < 0) continue; - printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n", - name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + printk(KERN_INFO "%s: i2c scan: found device @ 0x%04x [%s]\n", + name, i, i2c_devs[i] ? i2c_devs[i] : "???"); } } diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index f55cd12da0fd..aeda8d3990ae 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -99,6 +99,8 @@ #define CX23885_BOARD_DVBSKY_S950 49 #define CX23885_BOARD_DVBSKY_S952 50 #define CX23885_BOARD_DVBSKY_T982 51 +#define CX23885_BOARD_HAUPPAUGE_HVR5525 52 +#define CX23885_BOARD_HAUPPAUGE_STARBURST 53 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 diff --git a/drivers/media/pci/cx25821/Kconfig b/drivers/media/pci/cx25821/Kconfig index 6439a847680c..1755d3d2feaa 100644 --- a/drivers/media/pci/cx25821/Kconfig +++ b/drivers/media/pci/cx25821/Kconfig @@ -2,8 +2,7 @@ config VIDEO_CX25821 tristate "Conexant cx25821 support" depends on VIDEO_DEV && PCI && I2C select I2C_ALGOBIT - select VIDEO_BTCX - select VIDEOBUF_DMA_SG + select VIDEOBUF2_DMA_SG ---help--- This is a video4linux driver for Conexant 25821 based TV cards. diff --git a/drivers/media/pci/cx25821/Makefile b/drivers/media/pci/cx25821/Makefile index fb76c3d3713a..c8f8598a2b86 100644 --- a/drivers/media/pci/cx25821/Makefile +++ b/drivers/media/pci/cx25821/Makefile @@ -1,9 +1,8 @@ cx25821-y := cx25821-core.o cx25821-cards.o cx25821-i2c.o \ cx25821-gpio.o cx25821-medusa-video.o \ - cx25821-video.o cx25821-video-upstream.o + cx25821-video.o obj-$(CONFIG_VIDEO_CX25821) += cx25821.o obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o ccflags-y += -Idrivers/media/i2c -ccflags-y += -Idrivers/media/common diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 2dd5bcaa7e53..24f964bcc53a 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -63,8 +63,11 @@ static int devno; struct cx25821_audio_buffer { unsigned int bpl; - struct btcx_riscmem risc; - struct videobuf_dmabuf dma; + struct cx25821_riscmem risc; + void *vaddr; + struct scatterlist *sglist; + int sglen; + int nr_pages; }; struct cx25821_audio_dev { @@ -87,8 +90,6 @@ struct cx25821_audio_dev { unsigned int period_size; unsigned int num_periods; - struct videobuf_dmabuf *dma_risc; - struct cx25821_audio_buffer *buf; struct snd_pcm_substream *substream; @@ -142,6 +143,83 @@ MODULE_PARM_DESC(debug, "enable debug messages"); #define PCI_MSK_AUD_EXT (1 << 4) #define PCI_MSK_AUD_INT (1 << 3) + +static int cx25821_alsa_dma_init(struct cx25821_audio_dev *chip, int nr_pages) +{ + struct cx25821_audio_buffer *buf = chip->buf; + struct page *pg; + int i; + + buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT); + if (NULL == buf->vaddr) { + dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages); + return -ENOMEM; + } + + dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", + (unsigned long)buf->vaddr, + nr_pages << PAGE_SHIFT); + + memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT); + buf->nr_pages = nr_pages; + + buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist)); + if (NULL == buf->sglist) + goto vzalloc_err; + + sg_init_table(buf->sglist, buf->nr_pages); + for (i = 0; i < buf->nr_pages; i++) { + pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE); + if (NULL == pg) + goto vmalloc_to_page_err; + sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0); + } + return 0; + +vmalloc_to_page_err: + vfree(buf->sglist); + buf->sglist = NULL; +vzalloc_err: + vfree(buf->vaddr); + buf->vaddr = NULL; + return -ENOMEM; +} + +static int cx25821_alsa_dma_map(struct cx25821_audio_dev *dev) +{ + struct cx25821_audio_buffer *buf = dev->buf; + + buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist, + buf->nr_pages, PCI_DMA_FROMDEVICE); + + if (0 == buf->sglen) { + pr_warn("%s: cx25821_alsa_map_sg failed\n", __func__); + return -ENOMEM; + } + return 0; +} + +static int cx25821_alsa_dma_unmap(struct cx25821_audio_dev *dev) +{ + struct cx25821_audio_buffer *buf = dev->buf; + + if (!buf->sglen) + return 0; + + dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE); + buf->sglen = 0; + return 0; +} + +static int cx25821_alsa_dma_free(struct cx25821_audio_buffer *buf) +{ + vfree(buf->sglist); + buf->sglist = NULL; + vfree(buf->vaddr); + buf->vaddr = NULL; + return 0; +} + /* * BOARD Specific: Sets audio DMA */ @@ -330,15 +408,17 @@ out: static int dsp_buffer_free(struct cx25821_audio_dev *chip) { + struct cx25821_riscmem *risc = &chip->buf->risc; + BUG_ON(!chip->dma_size); dprintk(2, "Freeing buffer\n"); - videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc); - videobuf_dma_free(chip->dma_risc); - btcx_riscmem_free(chip->pci, &chip->buf->risc); + cx25821_alsa_dma_unmap(chip); + cx25821_alsa_dma_free(chip->buf); + pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma); kfree(chip->buf); - chip->dma_risc = NULL; + chip->buf = NULL; chip->dma_size = 0; return 0; @@ -430,8 +510,6 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); - struct videobuf_dmabuf *dma; - struct cx25821_audio_buffer *buf; int ret; @@ -455,19 +533,18 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream, chip->period_size = AUDIO_LINE_SIZE; buf->bpl = chip->period_size; + chip->buf = buf; - dma = &buf->dma; - videobuf_dma_init(dma); - ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, + ret = cx25821_alsa_dma_init(chip, (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); if (ret < 0) goto error; - ret = videobuf_dma_map(&chip->pci->dev, dma); + ret = cx25821_alsa_dma_map(chip); if (ret < 0) goto error; - ret = cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist, + ret = cx25821_risc_databuffer_audio(chip->pci, &buf->risc, buf->sglist, chip->period_size, chip->num_periods, 1); if (ret < 0) { pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n"); @@ -479,16 +556,14 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream, buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - chip->buf = buf; - chip->dma_risc = dma; - - substream->runtime->dma_area = chip->dma_risc->vaddr; + substream->runtime->dma_area = chip->buf->vaddr; substream->runtime->dma_bytes = chip->dma_size; substream->runtime->dma_addr = 0; return 0; error: + chip->buf = NULL; kfree(buf); return ret; } diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 389fffd2f36f..559f8293c53a 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -874,10 +874,9 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) if (dev->pci->device != 0x8210) { pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n", __func__, dev->pci->device); - return -1; - } else { - pr_info("Athena Hardware device = 0x%02x\n", dev->pci->device); + return -ENODEV; } + pr_info("Athena Hardware device = 0x%02x\n", dev->pci->device); /* Apply a sensible clock frequency for the PCIe bridge */ dev->clk_freq = 28000000; @@ -966,11 +965,15 @@ void cx25821_dev_unregister(struct cx25821_dev *dev) release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0)); - for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; i++) { + for (i = 0; i < MAX_VID_CAP_CHANNEL_NUM - 1; i++) { if (i == SRAM_CH08) /* audio channel */ continue; + /* + * TODO: enable when video output is properly + * supported. if (i == SRAM_CH09 || i == SRAM_CH10) cx25821_free_mem_upstream(&dev->channels[i]); + */ cx25821_video_unregister(dev, i); } @@ -979,14 +982,41 @@ void cx25821_dev_unregister(struct cx25821_dev *dev) } EXPORT_SYMBOL(cx25821_dev_unregister); +int cx25821_riscmem_alloc(struct pci_dev *pci, + struct cx25821_riscmem *risc, + unsigned int size) +{ + __le32 *cpu; + dma_addr_t dma = 0; + + if (NULL != risc->cpu && risc->size < size) + pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); + if (NULL == risc->cpu) { + cpu = pci_zalloc_consistent(pci, size, &dma); + if (NULL == cpu) + return -ENOMEM; + risc->cpu = cpu; + risc->dma = dma; + risc->size = size; + } + return 0; +} +EXPORT_SYMBOL(cx25821_riscmem_alloc); + static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, - unsigned int lines) + unsigned int lines, bool jump) { struct scatterlist *sg; unsigned int line, todo; + if (jump) { + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(0); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + } + /* sync instruction */ if (sync_line != NO_SYNC_LINE) *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); @@ -1035,7 +1065,7 @@ static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist, return rp; } -int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, +int cx25821_risc_buffer(struct pci_dev *pci, struct cx25821_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines) @@ -1052,14 +1082,14 @@ int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, fields++; /* estimate risc mem: worst case is one write per page border + - one write per scan line + syncs + jump (all 2 dwords). Padding + one write per scan line + syncs + jump (all 3 dwords). Padding can cause next bpl to start close to a page border. First DMA region may be smaller than PAGE_SIZE */ /* write and jump need and extra dword */ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); - instructions += 2; - rc = btcx_riscmem_alloc(pci, risc, instructions * 12); + instructions += 5; + rc = cx25821_riscmem_alloc(pci, risc, instructions * 12); if (rc < 0) return rc; @@ -1069,17 +1099,17 @@ int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, if (UNSET != top_offset) { rp = cx25821_risc_field(rp, sglist, top_offset, 0, bpl, padding, - lines); + lines, true); } if (UNSET != bottom_offset) { rp = cx25821_risc_field(rp, sglist, bottom_offset, 0x200, bpl, - padding, lines); + padding, lines, UNSET == top_offset); } /* save pointer to jmp instruction address */ risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + BUG_ON((risc->jmp - risc->cpu + 3) * sizeof(*risc->cpu) > risc->size); return 0; } @@ -1146,7 +1176,7 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist, } int cx25821_risc_databuffer_audio(struct pci_dev *pci, - struct btcx_riscmem *risc, + struct cx25821_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, unsigned int lines, unsigned int lpi) @@ -1163,7 +1193,7 @@ int cx25821_risc_databuffer_audio(struct pci_dev *pci, instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; instructions += 1; - rc = btcx_riscmem_alloc(pci, risc, instructions * 12); + rc = cx25821_riscmem_alloc(pci, risc, instructions * 12); if (rc < 0) return rc; @@ -1179,40 +1209,14 @@ int cx25821_risc_databuffer_audio(struct pci_dev *pci, } EXPORT_SYMBOL(cx25821_risc_databuffer_audio); -int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value) +void cx25821_free_buffer(struct cx25821_dev *dev, struct cx25821_buffer *buf) { - __le32 *rp; - int rc; - - rc = btcx_riscmem_alloc(pci, risc, 4 * 16); - - if (rc < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - - *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ1); - *(rp++) = cpu_to_le32(reg); - *(rp++) = cpu_to_le32(value); - *(rp++) = cpu_to_le32(mask); - *(rp++) = cpu_to_le32(RISC_JUMP); - *(rp++) = cpu_to_le32(risc->dma); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - return 0; -} - -void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf) -{ - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - BUG_ON(in_interrupt()); - videobuf_waiton(q, &buf->vb, 0, 0); - videobuf_dma_unmap(q->dev, dma); - videobuf_dma_free(dma); - btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); - buf->vb.state = VIDEOBUF_NEEDS_INIT; + if (WARN_ON(buf->risc.size == 0)) + return; + pci_free_consistent(dev->pci, + buf->risc.size, buf->risc.cpu, buf->risc.dma); + memset(&buf->risc, 0, sizeof(buf->risc)); } static irqreturn_t cx25821_irq(int irq, void *dev_id) @@ -1297,14 +1301,15 @@ static int cx25821_initdev(struct pci_dev *pci_dev, goto fail_unregister_device; } + dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev); + if (IS_ERR(dev->alloc_ctx)) { + err = PTR_ERR(dev->alloc_ctx); + goto fail_unregister_pci; + } err = cx25821_dev_setup(dev); - if (err) { - if (err == -EBUSY) - goto fail_unregister_device; - else - goto fail_unregister_pci; - } + if (err) + goto fail_free_ctx; /* print pci info */ pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); @@ -1334,6 +1339,8 @@ fail_irq: pr_info("cx25821_initdev() can't get IRQ !\n"); cx25821_dev_unregister(dev); +fail_free_ctx: + vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); fail_unregister_pci: pci_disable_device(pci_dev); fail_unregister_device: @@ -1357,6 +1364,7 @@ static void cx25821_finidev(struct pci_dev *pci_dev) free_irq(pci_dev->irq, dev); cx25821_dev_unregister(dev); + vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); v4l2_device_unregister(v4l2_dev); kfree(dev); } diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 3a419f134584..7bc495e4ece2 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -3,7 +3,7 @@ * * Copyright (C) 2009 Conexant Systems Inc. * Authors , - * Based on Steven Toth cx23885 driver + * Based on Steven Toth cx25821 driver * Parts adapted/taken from Eduardo Moscoso Rubino * Copyright (C) 2009 Eduardo Moscoso Rubino * @@ -46,10 +46,6 @@ static unsigned int irq_debug; module_param(irq_debug, int, 0644); MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); -static unsigned int vid_limit = 16; -module_param(vid_limit, int, 0644); -MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); - #define FORMAT_FLAGS_PACKED 0x01 static const struct cx25821_fmt formats[] = { @@ -76,41 +72,6 @@ static const struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc) return NULL; } -void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, - u32 count) -{ - struct cx25821_buffer *buf; - int bc; - - for (bc = 0;; bc++) { - if (list_empty(&q->active)) { - dprintk(1, "bc=%d (=0: active empty)\n", bc); - break; - } - - buf = list_entry(q->active.next, struct cx25821_buffer, - vb.queue); - - /* count comes from the hw and it is 16bit wide -- - * this trick handles wrap-arounds correctly for - * up to 32767 buffers in flight... */ - if ((s16) (count - buf->count) < 0) - break; - - v4l2_get_timestamp(&buf->vb.ts); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - } - - if (list_empty(&q->active)) - del_timer(&q->timeout); - else - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - if (bc != 1) - pr_err("%s: %d buffers handled (should be 1)\n", __func__, bc); -} - int cx25821_start_video_dma(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, struct cx25821_buffer *buf, @@ -123,7 +84,6 @@ int cx25821_start_video_dma(struct cx25821_dev *dev, /* reset counter */ cx_write(channel->gpcnt_ctl, 3); - q->count = 1; /* enable irq */ cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << channel->i)); @@ -139,86 +99,8 @@ int cx25821_start_video_dma(struct cx25821_dev *dev, return 0; } -static int cx25821_restart_video_queue(struct cx25821_dev *dev, - struct cx25821_dmaqueue *q, - const struct sram_channel *channel) -{ - struct cx25821_buffer *buf, *prev; - struct list_head *item; - - if (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx25821_buffer, - vb.queue); - - cx25821_start_video_dma(dev, q, buf, channel); - - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx25821_buffer, vb.queue); - buf->count = q->count++; - } - - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - return 0; - } - - prev = NULL; - for (;;) { - if (list_empty(&q->queued)) - return 0; - - buf = list_entry(q->queued.next, struct cx25821_buffer, - vb.queue); - - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - cx25821_start_video_dma(dev, q, buf, channel); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_move_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ - } else { - return 0; - } - prev = buf; - } -} - -static void cx25821_vid_timeout(unsigned long data) -{ - struct cx25821_data *timeout_data = (struct cx25821_data *)data; - struct cx25821_dev *dev = timeout_data->dev; - const struct sram_channel *channel = timeout_data->channel; - struct cx25821_dmaqueue *q = &dev->channels[channel->i].dma_vidq; - struct cx25821_buffer *buf; - unsigned long flags; - - /* cx25821_sram_channel_dump(dev, channel); */ - cx_clear(channel->dma_ctl, 0x11); - - spin_lock_irqsave(&dev->slock, flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx25821_buffer, - vb.queue); - list_del(&buf->vb.queue); - - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - } - - cx25821_restart_video_queue(dev, q, channel); - spin_unlock_irqrestore(&dev->slock, flags); -} - int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) { - u32 count = 0; int handled = 0; u32 mask; const struct sram_channel *channel = dev->channels[chan_num].sram_channels; @@ -239,317 +121,201 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) /* risc1 y */ if (status & FLD_VID_DST_RISC1) { - spin_lock(&dev->slock); - count = cx_read(channel->gpcnt); - cx25821_video_wakeup(dev, &dev->channels[channel->i].dma_vidq, - count); - spin_unlock(&dev->slock); - handled++; - } + struct cx25821_dmaqueue *dmaq = + &dev->channels[channel->i].dma_vidq; + struct cx25821_buffer *buf; - /* risc2 y */ - if (status & 0x10) { - dprintk(2, "stopper video\n"); spin_lock(&dev->slock); - cx25821_restart_video_queue(dev, - &dev->channels[channel->i].dma_vidq, channel); + if (!list_empty(&dmaq->active)) { + buf = list_entry(dmaq->active.next, + struct cx25821_buffer, queue); + + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + buf->vb.v4l2_buf.sequence = dmaq->count++; + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); + } spin_unlock(&dev->slock); handled++; } return handled; } -static int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) +static int cx25821_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct cx25821_channel *chan = q->priv_data; + struct cx25821_channel *chan = q->drv_priv; + unsigned size = (chan->fmt->depth * chan->width * chan->height) >> 3; - *size = chan->fmt->depth * chan->width * chan->height >> 3; - - if (0 == *count) - *count = 32; - - if (*size * *count > vid_limit * 1024 * 1024) - *count = (vid_limit * 1024 * 1024) / *size; + if (fmt && fmt->fmt.pix.sizeimage < size) + return -EINVAL; + *num_planes = 1; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size; + alloc_ctxs[0] = chan->dev->alloc_ctx; return 0; } -static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) +static int cx25821_buffer_prepare(struct vb2_buffer *vb) { - struct cx25821_channel *chan = q->priv_data; + struct cx25821_channel *chan = vb->vb2_queue->drv_priv; struct cx25821_dev *dev = chan->dev; struct cx25821_buffer *buf = container_of(vb, struct cx25821_buffer, vb); - int rc, init_buffer = 0; + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); u32 line0_offset; - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); int bpl_local = LINE_SIZE_D1; + int ret; - BUG_ON(NULL == chan->fmt); - if (chan->width < 48 || chan->width > 720 || - chan->height < 32 || chan->height > 576) + if (chan->pixel_formats == PIXEL_FRMT_411) + buf->bpl = (chan->fmt->depth * chan->width) >> 3; + else + buf->bpl = (chan->fmt->depth >> 3) * chan->width; + + if (vb2_plane_size(vb, 0) < chan->height * buf->bpl) return -EINVAL; + vb2_set_plane_payload(vb, 0, chan->height * buf->bpl); + buf->vb.v4l2_buf.field = chan->field; - buf->vb.size = (chan->width * chan->height * chan->fmt->depth) >> 3; + if (chan->pixel_formats == PIXEL_FRMT_411) { + bpl_local = buf->bpl; + } else { + bpl_local = buf->bpl; /* Default */ - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - if (buf->fmt != chan->fmt || - buf->vb.width != chan->width || - buf->vb.height != chan->height || buf->vb.field != field) { - buf->fmt = chan->fmt; - buf->vb.width = chan->width; - buf->vb.height = chan->height; - buf->vb.field = field; - init_buffer = 1; - } - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - init_buffer = 1; - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) { - printk(KERN_DEBUG pr_fmt("videobuf_iolock failed!\n")); - goto fail; + if (chan->use_cif_resolution) { + if (dev->tvnorm & V4L2_STD_625_50) + bpl_local = 352 << 1; + else + bpl_local = chan->cif_width << 1; } } - dprintk(1, "init_buffer=%d\n", init_buffer); + switch (chan->field) { + case V4L2_FIELD_TOP: + ret = cx25821_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, 0, UNSET, + buf->bpl, 0, chan->height); + break; + case V4L2_FIELD_BOTTOM: + ret = cx25821_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, UNSET, 0, + buf->bpl, 0, chan->height); + break; + case V4L2_FIELD_INTERLACED: + /* All other formats are top field first */ + line0_offset = 0; + dprintk(1, "top field first\n"); - if (init_buffer) { - if (chan->pixel_formats == PIXEL_FRMT_411) - buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3; - else - buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width); - - if (chan->pixel_formats == PIXEL_FRMT_411) { - bpl_local = buf->bpl; - } else { - bpl_local = buf->bpl; /* Default */ - - if (chan->use_cif_resolution) { - if (dev->tvnorm & V4L2_STD_625_50) - bpl_local = 352 << 1; - else - bpl_local = chan->cif_width << 1; - } - } - - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, 0, UNSET, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_BOTTOM: - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, UNSET, 0, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_INTERLACED: - /* All other formats are top field first */ - line0_offset = 0; - dprintk(1, "top field first\n"); - - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, line0_offset, - bpl_local, bpl_local, bpl_local, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_TB: - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->bpl * (buf->vb.height >> 1), - buf->bpl, 0, buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_BT: - cx25821_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - buf->bpl * (buf->vb.height >> 1), 0, - buf->bpl, 0, buf->vb.height >> 1); - break; - default: - BUG(); - } + ret = cx25821_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, line0_offset, + bpl_local, bpl_local, bpl_local, + chan->height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + ret = cx25821_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + 0, buf->bpl * (chan->height >> 1), + buf->bpl, 0, chan->height >> 1); + break; + case V4L2_FIELD_SEQ_BT: + ret = cx25821_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + buf->bpl * (chan->height >> 1), 0, + buf->bpl, 0, chan->height >> 1); + break; + default: + WARN_ON(1); + ret = -EINVAL; + break; } dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - buf, buf->vb.i, chan->width, chan->height, chan->fmt->depth, - chan->fmt->name, (unsigned long)buf->risc.dma); + buf, buf->vb.v4l2_buf.index, chan->width, chan->height, + chan->fmt->depth, chan->fmt->name, + (unsigned long)buf->risc.dma); - buf->vb.state = VIDEOBUF_PREPARED; - - return 0; - -fail: - cx25821_free_buffer(q, buf); - return rc; + return ret; } -static void cx25821_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void cx25821_buffer_finish(struct vb2_buffer *vb) { struct cx25821_buffer *buf = container_of(vb, struct cx25821_buffer, vb); - - cx25821_free_buffer(q, buf); -} - -static int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cx25821_channel *chan = video_drvdata(file); - - return videobuf_mmap_mapper(&chan->vidq, vma); -} - - -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct cx25821_buffer *buf = - container_of(vb, struct cx25821_buffer, vb); - struct cx25821_buffer *prev; - struct cx25821_channel *chan = vq->priv_data; + struct cx25821_channel *chan = vb->vb2_queue->drv_priv; struct cx25821_dev *dev = chan->dev; + + cx25821_free_buffer(dev, buf); +} + +static void cx25821_buffer_queue(struct vb2_buffer *vb) +{ + struct cx25821_buffer *buf = + container_of(vb, struct cx25821_buffer, vb); + struct cx25821_channel *chan = vb->vb2_queue->drv_priv; + struct cx25821_dev *dev = chan->dev; + struct cx25821_buffer *prev; struct cx25821_dmaqueue *q = &dev->channels[chan->id].dma_vidq; - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); - buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12); + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]); - - if (!list_empty(&q->queued)) { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf, - buf->vb.i); - - } else if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue, &q->active); - cx25821_start_video_dma(dev, q, buf, chan->sram_channels); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n", - buf, buf->vb.i, buf->count, q->count); + if (list_empty(&q->active)) { + list_add_tail(&buf->queue, &q->active); } else { + buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(q->active.prev, struct cx25821_buffer, - vb.queue); - if (prev->vb.width == buf->vb.width - && prev->vb.height == buf->vb.height - && prev->fmt == buf->fmt) { - list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - - /* 64 bit bits 63-32 */ - prev->risc.jmp[2] = cpu_to_le32(0); - dprintk(2, "[%p/%d] buffer_queue - append to active, buf->count=%d\n", - buf, buf->vb.i, buf->count); - - } else { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf, - buf->vb.i); - } + queue); + list_add_tail(&buf->queue, &q->active); + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); } - - if (list_empty(&q->active)) - dprintk(2, "active queue empty!\n"); } -static struct videobuf_queue_ops cx25821_video_qops = { - .buf_setup = cx25821_buffer_setup, - .buf_prepare = cx25821_buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = cx25821_buffer_release, +static int cx25821_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct cx25821_channel *chan = q->drv_priv; + struct cx25821_dev *dev = chan->dev; + struct cx25821_dmaqueue *dmaq = &dev->channels[chan->id].dma_vidq; + struct cx25821_buffer *buf = list_entry(dmaq->active.next, + struct cx25821_buffer, queue); + + dmaq->count = 0; + cx25821_start_video_dma(dev, dmaq, buf, chan->sram_channels); + return 0; +} + +static void cx25821_stop_streaming(struct vb2_queue *q) +{ + struct cx25821_channel *chan = q->drv_priv; + struct cx25821_dev *dev = chan->dev; + struct cx25821_dmaqueue *dmaq = &dev->channels[chan->id].dma_vidq; + unsigned long flags; + + cx_write(chan->sram_channels->dma_ctl, 0); /* FIFO and RISC disable */ + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&dmaq->active)) { + struct cx25821_buffer *buf = list_entry(dmaq->active.next, + struct cx25821_buffer, queue); + + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&dev->slock, flags); +} + +static struct vb2_ops cx25821_video_qops = { + .queue_setup = cx25821_queue_setup, + .buf_prepare = cx25821_buffer_prepare, + .buf_finish = cx25821_buffer_finish, + .buf_queue = cx25821_buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = cx25821_start_streaming, + .stop_streaming = cx25821_stop_streaming, }; -static ssize_t video_read(struct file *file, char __user * data, size_t count, - loff_t *ppos) -{ - struct v4l2_fh *fh = file->private_data; - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - int err = 0; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - if (chan->streaming_fh && chan->streaming_fh != fh) { - err = -EBUSY; - goto unlock; - } - chan->streaming_fh = fh; - - err = videobuf_read_one(&chan->vidq, data, count, ppos, - file->f_flags & O_NONBLOCK); -unlock: - mutex_unlock(&dev->lock); - return err; -} - -static unsigned int video_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cx25821_channel *chan = video_drvdata(file); - unsigned long req_events = poll_requested_events(wait); - unsigned int res = v4l2_ctrl_poll(file, wait); - - if (req_events & (POLLIN | POLLRDNORM)) - res |= videobuf_poll_stream(file, &chan->vidq, wait); - return res; - - /* This doesn't belong in poll(). This can be done - * much better with vb2. We keep this code here as a - * reminder. - if ((res & POLLIN) && buf->vb.state == VIDEOBUF_DONE) { - struct cx25821_dev *dev = chan->dev; - - if (dev && chan->use_cif_resolution) { - u8 cam_id = *((char *)buf->vb.baddr + 3); - memcpy((char *)buf->vb.baddr, - (char *)buf->vb.baddr + (chan->width * 2), - (chan->width * 2)); - *((char *)buf->vb.baddr + 3) = cam_id; - } - } - */ -} - -static int video_release(struct file *file) -{ - struct cx25821_channel *chan = video_drvdata(file); - struct v4l2_fh *fh = file->private_data; - struct cx25821_dev *dev = chan->dev; - const struct sram_channel *sram_ch = - dev->channels[0].sram_channels; - - mutex_lock(&dev->lock); - /* stop the risc engine and fifo */ - cx_write(sram_ch->dma_ctl, 0); /* FIFO and RISC disable */ - - /* stop video capture */ - if (chan->streaming_fh == fh) { - videobuf_queue_cancel(&chan->vidq); - chan->streaming_fh = NULL; - } - - if (chan->vidq.read_buf) { - cx25821_buffer_release(&chan->vidq, chan->vidq.read_buf); - kfree(chan->vidq.read_buf); - } - - videobuf_mmap_free(&chan->vidq); - mutex_unlock(&dev->lock); - - return v4l2_fh_release(file); -} - /* VIDEO IOCTLS */ static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, @@ -571,7 +337,7 @@ static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.width = chan->width; f->fmt.pix.height = chan->height; - f->fmt.pix.field = chan->vidq.field; + f->fmt.pix.field = chan->field; f->fmt.pix.pixelformat = chan->fmt->fourcc; f->fmt.pix.bytesperline = (chan->width * chan->fmt->depth) >> 3; f->fmt.pix.sizeimage = chan->height * f->fmt.pix.bytesperline; @@ -632,7 +398,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, return err; chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); - chan->vidq.field = f->fmt.pix.field; + chan->field = f->fmt.pix.field; chan->width = f->fmt.pix.width; chan->height = f->fmt.pix.height; @@ -654,47 +420,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx25821_channel *chan = video_drvdata(file); - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (chan->streaming_fh && chan->streaming_fh != priv) - return -EBUSY; - chan->streaming_fh = priv; - - return videobuf_streamon(&chan->vidq); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx25821_channel *chan = video_drvdata(file); - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (chan->streaming_fh && chan->streaming_fh != priv) - return -EBUSY; - if (chan->streaming_fh == NULL) - return 0; - - chan->streaming_fh = NULL; - return videobuf_streamoff(&chan->vidq); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - int ret_val = 0; - struct cx25821_channel *chan = video_drvdata(file); - - ret_val = videobuf_dqbuf(&chan->vidq, p, file->f_flags & O_NONBLOCK); - p->sequence = chan->dma_vidq.count; - - return ret_val; -} - static int vidioc_log_status(struct file *file, void *priv) { struct cx25821_channel *chan = video_drvdata(file); @@ -729,29 +454,6 @@ static int cx25821_vidioc_querycap(struct file *file, void *priv, return 0; } -static int cx25821_vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct cx25821_channel *chan = video_drvdata(file); - - return videobuf_reqbufs(&chan->vidq, p); -} - -static int cx25821_vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx25821_channel *chan = video_drvdata(file); - - return videobuf_querybuf(&chan->vidq, p); -} - -static int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct cx25821_channel *chan = video_drvdata(file); - - return videobuf_qbuf(&chan->vidq, p); -} - static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms) { struct cx25821_channel *chan = video_drvdata(file); @@ -880,7 +582,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, return err; chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); - chan->vidq.field = f->fmt.pix.field; + chan->field = f->fmt.pix.field; chan->width = f->fmt.pix.width; chan->height = f->fmt.pix.height; if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P) @@ -890,52 +592,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, return 0; } -static ssize_t video_write(struct file *file, const char __user *data, size_t count, - loff_t *ppos) -{ - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - struct v4l2_fh *fh = file->private_data; - int err = 0; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - if (chan->streaming_fh && chan->streaming_fh != fh) { - err = -EBUSY; - goto unlock; - } - if (!chan->streaming_fh) { - err = cx25821_vidupstream_init(chan, chan->pixel_formats); - if (err) - goto unlock; - chan->streaming_fh = fh; - } - - err = cx25821_write_frame(chan, data, count); - count -= err; - *ppos += err; - -unlock: - mutex_unlock(&dev->lock); - return err; -} - -static int video_out_release(struct file *file) -{ - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - struct v4l2_fh *fh = file->private_data; - - mutex_lock(&dev->lock); - if (chan->streaming_fh == fh) { - cx25821_stop_upstream_video(chan); - chan->streaming_fh = NULL; - } - mutex_unlock(&dev->lock); - - return v4l2_fh_release(file); -} - static const struct v4l2_ctrl_ops cx25821_ctrl_ops = { .s_ctrl = cx25821_s_ctrl, }; @@ -943,11 +599,11 @@ static const struct v4l2_ctrl_ops cx25821_ctrl_ops = { static const struct v4l2_file_operations video_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, - .release = video_release, - .read = video_read, - .poll = video_poll, - .mmap = cx25821_video_mmap, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, }; static const struct v4l2_ioctl_ops video_ioctl_ops = { @@ -956,17 +612,19 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = cx25821_vidioc_reqbufs, - .vidioc_querybuf = cx25821_vidioc_querybuf, - .vidioc_qbuf = cx25821_vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_g_std = cx25821_vidioc_g_std, .vidioc_s_std = cx25821_vidioc_s_std, .vidioc_enum_input = cx25821_vidioc_enum_input, .vidioc_g_input = cx25821_vidioc_g_input, .vidioc_s_input = cx25821_vidioc_s_input, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, .vidioc_log_status = vidioc_log_status, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, @@ -984,9 +642,11 @@ static const struct video_device cx25821_video_device = { static const struct v4l2_file_operations video_out_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, - .write = video_write, - .release = video_out_release, + .release = vb2_fop_release, + .write = vb2_fop_write, + .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, }; static const struct v4l2_ioctl_ops video_out_ioctl_ops = { @@ -1019,9 +679,6 @@ void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) if (video_is_registered(&dev->channels[chan_num].vdev)) { video_unregister_device(&dev->channels[chan_num].vdev); v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl); - - btcx_riscmem_free(dev->pci, - &dev->channels[chan_num].dma_vidq.stopper); } } @@ -1035,10 +692,11 @@ int cx25821_video_register(struct cx25821_dev *dev) spin_lock_init(&dev->slock); - for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) { + for (i = 0; i < MAX_VID_CAP_CHANNEL_NUM - 1; ++i) { struct cx25821_channel *chan = &dev->channels[i]; struct video_device *vdev = &chan->vdev; struct v4l2_ctrl_handler *hdl = &chan->hdl; + struct vb2_queue *q; bool is_output = i > SRAM_CH08; if (i == SRAM_CH08) /* audio channel */ @@ -1066,11 +724,9 @@ int cx25821_video_register(struct cx25821_dev *dev) chan->out->chan = chan; } - cx25821_risc_stopper(dev->pci, &chan->dma_vidq.stopper, - chan->sram_channels->dma_ctl, 0x11, 0); - chan->sram_channels = &cx25821_sram_channels[i]; chan->width = 720; + chan->field = V4L2_FIELD_INTERLACED; if (dev->tvnorm & V4L2_STD_625_50) chan->height = 576; else @@ -1084,19 +740,27 @@ int cx25821_video_register(struct cx25821_dev *dev) cx_write(chan->sram_channels->int_stat, 0xffffffff); INIT_LIST_HEAD(&chan->dma_vidq.active); - INIT_LIST_HEAD(&chan->dma_vidq.queued); - chan->timeout_data.dev = dev; - chan->timeout_data.channel = &cx25821_sram_channels[i]; - chan->dma_vidq.timeout.function = cx25821_vid_timeout; - chan->dma_vidq.timeout.data = (unsigned long)&chan->timeout_data; - init_timer(&chan->dma_vidq.timeout); + q = &chan->vidq; - if (!is_output) - videobuf_queue_sg_init(&chan->vidq, &cx25821_video_qops, &dev->pci->dev, - &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer), - chan, &dev->lock); + q->type = is_output ? V4L2_BUF_TYPE_VIDEO_OUTPUT : + V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + q->io_modes |= is_output ? VB2_WRITE : VB2_READ; + q->gfp_flags = GFP_DMA32; + q->min_buffers_needed = 2; + q->drv_priv = chan; + q->buf_struct_size = sizeof(struct cx25821_buffer); + q->ops = &cx25821_video_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &dev->lock; + + if (!is_output) { + err = vb2_queue_init(q); + if (err < 0) + goto fail_unreg; + } /* register v4l devices */ *vdev = is_output ? cx25821_video_out_device : cx25821_video_device; @@ -1106,6 +770,7 @@ int cx25821_video_register(struct cx25821_dev *dev) else vdev->vfl_dir = VFL_DIR_TX; vdev->lock = &dev->lock; + vdev->queue = q; snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i); video_set_drvdata(vdev, chan); diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 90bdc196929f..d81a08a2df4f 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -34,9 +34,8 @@ #include #include #include -#include +#include -#include "btcx-risc.h" #include "cx25821-reg.h" #include "cx25821-medusa-reg.h" #include "cx25821-sram.h" @@ -89,6 +88,13 @@ #define CX25821_BOARD_CONEXANT_ATHENA10 1 #define MAX_VID_CHANNEL_NUM 12 + +/* + * Maximum capture-only channels. This can go away once video/audio output + * is fully supported in this driver. + */ +#define MAX_VID_CAP_CHANNEL_NUM 10 + #define VID_CHANNEL_NUM 8 struct cx25821_fmt { @@ -111,16 +117,23 @@ enum cx25821_src_sel_type { CX25821_SRC_SEL_PARALLEL_MPEG_VIDEO }; +struct cx25821_riscmem { + unsigned int size; + __le32 *cpu; + __le32 *jmp; + dma_addr_t dma; +}; + /* buffer for one video frame */ struct cx25821_buffer { /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; + struct vb2_buffer vb; + struct list_head queue; /* cx25821 specific */ unsigned int bpl; - struct btcx_riscmem risc; + struct cx25821_riscmem risc; const struct cx25821_fmt *fmt; - u32 count; }; enum port { @@ -159,17 +172,9 @@ struct cx25821_i2c { struct cx25821_dmaqueue { struct list_head active; - struct list_head queued; - struct timer_list timeout; - struct btcx_riscmem stopper; u32 count; }; -struct cx25821_data { - struct cx25821_dev *dev; - const struct sram_channel *channel; -}; - struct cx25821_dev; struct cx25821_channel; @@ -207,18 +212,17 @@ struct cx25821_video_out_data { struct cx25821_channel { unsigned id; struct cx25821_dev *dev; - struct v4l2_fh *streaming_fh; struct v4l2_ctrl_handler hdl; - struct cx25821_data timeout_data; struct video_device vdev; struct cx25821_dmaqueue dma_vidq; - struct videobuf_queue vidq; + struct vb2_queue vidq; const struct sram_channel *sram_channels; const struct cx25821_fmt *fmt; + unsigned field; unsigned int width, height; int pixel_formats; int use_cif_resolution; @@ -244,6 +248,7 @@ struct cx25821_dev { int hwrevision; /* used by cx25821-alsa */ struct snd_card *card; + void *alloc_ctx; u32 clk_freq; @@ -405,21 +410,22 @@ extern int cx25821_sram_channel_setup(struct cx25821_dev *dev, const struct sram_channel *ch, unsigned int bpl, u32 risc); -extern int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, +extern int cx25821_riscmem_alloc(struct pci_dev *pci, + struct cx25821_riscmem *risc, + unsigned int size); +extern int cx25821_risc_buffer(struct pci_dev *pci, struct cx25821_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines); extern int cx25821_risc_databuffer_audio(struct pci_dev *pci, - struct btcx_riscmem *risc, + struct cx25821_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, unsigned int lines, unsigned int lpi); -extern void cx25821_free_buffer(struct videobuf_queue *q, +extern void cx25821_free_buffer(struct cx25821_dev *dev, struct cx25821_buffer *buf); -extern int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); extern void cx25821_sram_channel_dump(struct cx25821_dev *dev, const struct sram_channel *ch); extern void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev, diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index d3c79d964f2c..b6be46e94289 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -1234,6 +1234,3 @@ static void __exit blackbird_fini(void) module_init(blackbird_init); module_exit(blackbird_fini); - -module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages [video]"); diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index dee177ed5fe9..c38d5a12e277 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -1091,10 +1091,3 @@ EXPORT_SYMBOL(cx88_core_put); EXPORT_SYMBOL(cx88_ir_start); EXPORT_SYMBOL(cx88_ir_stop); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index 5780e2f013b4..1b2ed238cdb6 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -1504,8 +1504,8 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(stv0288_attach, &tevii_tuner_earda_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61, &core->i2c_adap)) goto frontend_detach; core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index 1c1f69e6b0b9..a369b0840acf 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -833,10 +833,3 @@ EXPORT_SYMBOL(cx8802_start_dma); EXPORT_SYMBOL(cx8802_register_driver); EXPORT_SYMBOL(cx8802_unregister_driver); EXPORT_SYMBOL(cx8802_get_driver); -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff --git a/drivers/media/pci/cx88/cx88-tvaudio.c b/drivers/media/pci/cx88/cx88-tvaudio.c index 424fd97495dc..6bbce6ad6295 100644 --- a/drivers/media/pci/cx88/cx88-tvaudio.c +++ b/drivers/media/pci/cx88/cx88-tvaudio.c @@ -1050,10 +1050,3 @@ EXPORT_SYMBOL(cx88_newstation); EXPORT_SYMBOL(cx88_set_stereo); EXPORT_SYMBOL(cx88_get_stereo); EXPORT_SYMBOL(cx88_audio_thread); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off - */ diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c index ab6d5d25aa6f..e7d701777e53 100644 --- a/drivers/media/pci/ivtv/ivtv-irq.c +++ b/drivers/media/pci/ivtv/ivtv-irq.c @@ -357,7 +357,6 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; int y_done = 0; int bytes_written = 0; - unsigned long flags = 0; int idx = 0; IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); @@ -407,16 +406,21 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) /* Sync Hardware SG List of buffers */ ivtv_stream_sync_for_device(s); - if (lock) + if (lock) { + unsigned long flags = 0; + spin_lock_irqsave(&itv->dma_reg_lock, flags); - if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) { - ivtv_dma_dec_start(s); - } - else { - set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); - } - if (lock) + if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) + ivtv_dma_dec_start(s); + else + set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); spin_unlock_irqrestore(&itv->dma_reg_lock, flags); + } else { + if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) + ivtv_dma_dec_start(s); + else + set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); + } } static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s) diff --git a/drivers/media/pci/ivtv/ivtv-udma.c b/drivers/media/pci/ivtv/ivtv-udma.c index bee2329e0b2e..24152accc66c 100644 --- a/drivers/media/pci/ivtv/ivtv-udma.c +++ b/drivers/media/pci/ivtv/ivtv-udma.c @@ -124,10 +124,8 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, } /* Get user pages for DMA Xfer */ - down_read(¤t->mm->mmap_sem); - err = get_user_pages(current, current->mm, - user_dma.uaddr, user_dma.page_count, 0, 1, dma->map, NULL); - up_read(¤t->mm->mmap_sem); + err = get_user_pages_unlocked(current, current->mm, + user_dma.uaddr, user_dma.page_count, 0, 1, dma->map); if (user_dma.page_count != err) { IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n", diff --git a/drivers/media/pci/mantis/mantis_core.c b/drivers/media/pci/mantis/mantis_core.c index 684d9061fe2a..82220ea72dd3 100644 --- a/drivers/media/pci/mantis/mantis_core.c +++ b/drivers/media/pci/mantis/mantis_core.c @@ -56,29 +56,6 @@ static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) return 0; } -static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) -{ - int err; - - struct i2c_msg msg = { - .addr = 0x50, - .flags = 0, - .buf = data, - .len = length - }; - - err = i2c_transfer(&mantis->adapter, &msg, 1); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, - "ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >", - err, length, data[0], data[1]); - - return err; - } - - return 0; -} - static int get_mac_address(struct mantis_pci *mantis) { int err; diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 701b52f34689..99d09a7566d3 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1084,11 +1084,6 @@ static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl) /* ------------------------------------------------------------------ */ -static inline struct vb2_queue *saa7134_queue(struct file *file) -{ - return video_devdata(file)->queue; -} - static int video_open(struct file *file) { struct video_device *vdev = video_devdata(file); diff --git a/drivers/media/pci/smipcie/smipcie.c b/drivers/media/pci/smipcie/smipcie.c index f773350e67b9..36c8ed77309c 100644 --- a/drivers/media/pci/smipcie/smipcie.c +++ b/drivers/media/pci/smipcie/smipcie.c @@ -448,16 +448,19 @@ static void smi_port_exit(struct smi_port *port) port->enable = 0; } -static void smi_port_irq(struct smi_port *port, u32 int_status) +static int smi_port_irq(struct smi_port *port, u32 int_status) { u32 port_req_irq = port->_dmaInterruptCH0 | port->_dmaInterruptCH1; + int handled = 0; if (int_status & port_req_irq) { smi_port_disableInterrupt(port); port->_int_status = int_status; smi_port_clearInterrupt(port); tasklet_schedule(&port->tasklet); + handled = 1; } + return handled; } static irqreturn_t smi_irq_handler(int irq, void *dev_id) @@ -465,18 +468,19 @@ static irqreturn_t smi_irq_handler(int irq, void *dev_id) struct smi_dev *dev = dev_id; struct smi_port *port0 = &dev->ts_port[0]; struct smi_port *port1 = &dev->ts_port[1]; + int handled = 0; u32 intr_status = smi_read(MSI_INT_STATUS); /* ts0 interrupt.*/ if (dev->info->ts_0) - smi_port_irq(port0, intr_status); + handled += smi_port_irq(port0, intr_status); /* ts1 interrupt.*/ if (dev->info->ts_1) - smi_port_irq(port1, intr_status); + handled += smi_port_irq(port1, intr_status); - return IRQ_HANDLED; + return IRQ_RETVAL(handled); } static struct i2c_client *smi_add_i2c_client(struct i2c_adapter *adapter, diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c index 8cbe6b49f4c2..570d119ea18b 100644 --- a/drivers/media/pci/solo6x10/solo6x10-core.c +++ b/drivers/media/pci/solo6x10/solo6x10-core.c @@ -182,7 +182,7 @@ static ssize_t eeprom_store(struct device *dev, struct device_attribute *attr, { struct solo_dev *solo_dev = container_of(dev, struct solo_dev, dev); - unsigned short *p = (unsigned short *)buf; + u16 *p = (u16 *)buf; int i; if (count & 0x1) @@ -212,7 +212,7 @@ static ssize_t eeprom_show(struct device *dev, struct device_attribute *attr, { struct solo_dev *solo_dev = container_of(dev, struct solo_dev, dev); - unsigned short *p = (unsigned short *)buf; + u16 *p = (u16 *)buf; int count = (full_eeprom ? 128 : 64); int i; diff --git a/drivers/media/pci/solo6x10/solo6x10-eeprom.c b/drivers/media/pci/solo6x10/solo6x10-eeprom.c index da25ce4a6952..8e81186dc785 100644 --- a/drivers/media/pci/solo6x10/solo6x10-eeprom.c +++ b/drivers/media/pci/solo6x10/solo6x10-eeprom.c @@ -103,7 +103,7 @@ unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en) __be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc) { int read_cmd = loc | (EE_READ_CMD << ADDR_LEN); - unsigned short retval = 0; + u16 retval = 0; int i; solo_eeprom_cmd(solo_dev, read_cmd); diff --git a/drivers/media/pci/solo6x10/solo6x10-enc.c b/drivers/media/pci/solo6x10/solo6x10-enc.c index d19c0aef5abc..d28211bb9674 100644 --- a/drivers/media/pci/solo6x10/solo6x10-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-enc.c @@ -136,11 +136,11 @@ static void solo_capture_config(struct solo_dev *solo_dev) int solo_osd_print(struct solo_enc_dev *solo_enc) { struct solo_dev *solo_dev = solo_enc->solo_dev; - unsigned char *str = solo_enc->osd_text; + u8 *str = solo_enc->osd_text; u8 *buf = solo_enc->osd_buf; u32 reg; const struct font_desc *vga = find_font("VGA8x16"); - const unsigned char *vga_data; + const u8 *vga_data; int i, j; if (WARN_ON_ONCE(!vga)) @@ -154,7 +154,7 @@ int solo_osd_print(struct solo_enc_dev *solo_enc) } memset(buf, 0, SOLO_OSD_WRITE_SIZE); - vga_data = (const unsigned char *)vga->data; + vga_data = (const u8 *)vga->data; for (i = 0; *str; i++, str++) { for (j = 0; j < 16; j++) { diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index c7141f2e63bd..7ddc76709caa 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -56,8 +56,8 @@ struct solo_snd_pcm { int on; spinlock_t lock; - struct solo_dev *solo_dev; - unsigned char *g723_buf; + struct solo_dev *solo_dev; + u8 *g723_buf; dma_addr_t g723_dma; }; diff --git a/drivers/media/pci/solo6x10/solo6x10-jpeg.h b/drivers/media/pci/solo6x10/solo6x10-jpeg.h index 1c66a46da514..3c611bd3f2d8 100644 --- a/drivers/media/pci/solo6x10/solo6x10-jpeg.h +++ b/drivers/media/pci/solo6x10/solo6x10-jpeg.h @@ -21,7 +21,7 @@ #ifndef __SOLO6X10_JPEG_H #define __SOLO6X10_JPEG_H -static const unsigned char jpeg_header[] = { +static const u8 jpeg_header[] = { 0xff, 0xd8, 0xff, 0xfe, 0x00, 0x0d, 0x42, 0x6c, 0x75, 0x65, 0x63, 0x68, 0x65, 0x72, 0x72, 0x79, 0x20, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x20, 0x16, @@ -106,7 +106,7 @@ static const unsigned char jpeg_header[] = { /* This is the byte marker for the start of the DQT */ #define DQT_START 17 #define DQT_LEN 138 -static const unsigned char jpeg_dqt[4][DQT_LEN] = { +static const u8 jpeg_dqt[4][DQT_LEN] = { { 0xff, 0xdb, 0x00, 0x43, 0x00, 0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07, diff --git a/drivers/media/pci/solo6x10/solo6x10-tw28.c b/drivers/media/pci/solo6x10/solo6x10-tw28.c index edd0781ee4b5..0632d3f7c73c 100644 --- a/drivers/media/pci/solo6x10/solo6x10-tw28.c +++ b/drivers/media/pci/solo6x10/solo6x10-tw28.c @@ -510,7 +510,7 @@ static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr) #define FIRST_ACTIVE_LINE 0x0008 #define LAST_ACTIVE_LINE 0x0102 -static void saa712x_write_regs(struct solo_dev *dev, const uint8_t *vals, +static void saa712x_write_regs(struct solo_dev *dev, const u8 *vals, int start, int n) { for (; start < n; start++, vals++) { @@ -532,7 +532,7 @@ static void saa712x_write_regs(struct solo_dev *dev, const uint8_t *vals, static void saa712x_setup(struct solo_dev *dev) { const int reg_start = 0x26; - const uint8_t saa7128_regs_ntsc[] = { + const u8 saa7128_regs_ntsc[] = { /* :0x26 */ 0x0d, 0x00, /* :0x28 */ diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 6e933d383fa2..53fff5425c13 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -38,28 +38,28 @@ #define DMA_ALIGN 4096 /* 6010 M4V */ -static unsigned char vop_6010_ntsc_d1[] = { +static u8 vop_6010_ntsc_d1[] = { 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, 0x1f, 0x4c, 0x58, 0x10, 0xf0, 0x71, 0x18, 0x3f, }; -static unsigned char vop_6010_ntsc_cif[] = { +static u8 vop_6010_ntsc_cif[] = { 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, 0x1f, 0x4c, 0x2c, 0x10, 0x78, 0x51, 0x18, 0x3f, }; -static unsigned char vop_6010_pal_d1[] = { +static u8 vop_6010_pal_d1[] = { 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, 0x1f, 0x4c, 0x58, 0x11, 0x20, 0x71, 0x18, 0x3f, }; -static unsigned char vop_6010_pal_cif[] = { +static u8 vop_6010_pal_cif[] = { 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, @@ -67,25 +67,25 @@ static unsigned char vop_6010_pal_cif[] = { }; /* 6110 h.264 */ -static unsigned char vop_6110_ntsc_d1[] = { +static u8 vop_6110_ntsc_d1[] = { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, 0x9a, 0x74, 0x05, 0x81, 0xec, 0x80, 0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, }; -static unsigned char vop_6110_ntsc_cif[] = { +static u8 vop_6110_ntsc_cif[] = { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, 0x9a, 0x74, 0x0b, 0x0f, 0xc8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00, }; -static unsigned char vop_6110_pal_d1[] = { +static u8 vop_6110_pal_d1[] = { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, 0x9a, 0x74, 0x05, 0x80, 0x93, 0x20, 0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, }; -static unsigned char vop_6110_pal_cif[] = { +static u8 vop_6110_pal_cif[] = { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, 0x9a, 0x74, 0x0b, 0x04, 0xb2, 0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00, @@ -149,7 +149,7 @@ void solo_update_mode(struct solo_enc_dev *solo_enc) { struct solo_dev *solo_dev = solo_enc->solo_dev; int vop_len; - unsigned char *vop; + u8 *vop; solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0; solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1); @@ -239,8 +239,6 @@ static int solo_enc_on(struct solo_enc_dev *solo_enc) if (solo_enc->bw_weight > solo_dev->enc_bw_remain) return -EBUSY; solo_enc->sequence = 0; - solo_enc->motion_last_state = false; - solo_enc->frames_since_last_motion = 0; solo_dev->enc_bw_remain -= solo_enc->bw_weight; if (solo_enc->type == SOLO_ENC_TYPE_EXT) @@ -529,36 +527,12 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, } if (!ret) { - bool send_event = false; - vb->v4l2_buf.sequence = solo_enc->sequence++; vb->v4l2_buf.timestamp.tv_sec = vop_sec(vh); vb->v4l2_buf.timestamp.tv_usec = vop_usec(vh); /* Check for motion flags */ - if (solo_is_motion_on(solo_enc)) { - /* It takes a few frames for the hardware to detect - * motion. Once it does it clears the motion detection - * register and it takes again a few frames before - * motion is seen. This means in practice that when the - * motion field is 1, it will go back to 0 for the next - * frame. This leads to motion detection event being - * sent all the time, which is not what we want. - * Instead wait a few frames before deciding that the - * motion has halted. After some experimentation it - * turns out that waiting for 5 frames works well. - */ - if (enc_buf->motion == 0 && - solo_enc->motion_last_state && - solo_enc->frames_since_last_motion++ > 5) - send_event = true; - else if (enc_buf->motion) { - solo_enc->frames_since_last_motion = 0; - send_event = !solo_enc->motion_last_state; - } - } - - if (send_event) { + if (solo_is_motion_on(solo_enc) && enc_buf->motion) { struct v4l2_event ev = { .type = V4L2_EVENT_MOTION_DET, .u.motion_det = { @@ -568,8 +542,6 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, }, }; - solo_enc->motion_last_state = enc_buf->motion; - solo_enc->frames_since_last_motion = 0; v4l2_event_queue(solo_enc->vfd, &ev); } } diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h index bd8edfa319b8..1ca54b08b3aa 100644 --- a/drivers/media/pci/solo6x10/solo6x10.h +++ b/drivers/media/pci/solo6x10/solo6x10.h @@ -159,8 +159,6 @@ struct solo_enc_dev { u16 motion_thresh; bool motion_global; bool motion_enabled; - bool motion_last_state; - u8 frames_since_last_motion; u16 width; u16 height; @@ -170,9 +168,9 @@ struct solo_enc_dev { __aligned(4); /* VOP stuff */ - unsigned char vop[64]; + u8 vop[64]; int vop_len; - unsigned char jpeg_header[1024]; + u8 jpeg_header[1024]; int jpeg_len; u32 fmt; diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig index f6f30abc088b..e03587b1af71 100644 --- a/drivers/media/pci/sta2x11/Kconfig +++ b/drivers/media/pci/sta2x11/Kconfig @@ -5,6 +5,7 @@ config STA2X11_VIP select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT select VIDEOBUF2_DMA_CONTIG depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS + depends on VIDEO_V4L2_SUBDEV_API depends on I2C help Say Y for support for STA2X11 VIP (Video Input Port) capture diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index c1f0617a6973..45199a12b9d9 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -1219,11 +1219,14 @@ static int stop_ts_capture(struct av7110 *budget) static int start_ts_capture(struct av7110 *budget) { + unsigned y; + dprintk(2, "budget: %p\n", budget); if (budget->feeding1) return ++budget->feeding1; - memset(budget->grabbing, 0x00, TS_BUFLEN); + for (y = 0; y < TS_HEIGHT; y++) + memset(budget->grabbing + y * TS_WIDTH, 0x00, TS_WIDTH); budget->ttbp = 0; SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c index 37d02fe09137..23e05499b509 100644 --- a/drivers/media/pci/ttpci/budget-core.c +++ b/drivers/media/pci/ttpci/budget-core.c @@ -231,63 +231,59 @@ static void vpeirq(unsigned long data) } -int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, - int uselocks, int nobusyloop) +static int ttpci_budget_debiread_nolock(struct budget *budget, u32 config, + int addr, int count, int nobusyloop) { struct saa7146_dev *saa = budget->dev; - int result = 0; - unsigned long flags = 0; + int result; - if (count > 4 || count <= 0) - return 0; - - if (uselocks) - spin_lock_irqsave(&budget->debilock, flags); - - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); + result = saa7146_wait_for_debi_done(saa, nobusyloop); + if (result < 0) return result; - } saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); saa7146_write(saa, DEBI_CONFIG, config); saa7146_write(saa, DEBI_PAGE, 0); saa7146_write(saa, MC2, (2 << 16) | 2); - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); + result = saa7146_wait_for_debi_done(saa, nobusyloop); + if (result < 0) return result; - } result = saa7146_read(saa, DEBI_AD); result &= (0xffffffffUL >> ((4 - count) * 8)); - - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - return result; } -int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, - int count, u32 value, int uselocks, int nobusyloop) +int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, + int uselocks, int nobusyloop) { - struct saa7146_dev *saa = budget->dev; - unsigned long flags = 0; - int result; - if (count > 4 || count <= 0) return 0; - if (uselocks) - spin_lock_irqsave(&budget->debilock, flags); + if (uselocks) { + unsigned long flags; + int result; - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); + spin_lock_irqsave(&budget->debilock, flags); + result = ttpci_budget_debiread_nolock(budget, config, addr, + count, nobusyloop); + spin_unlock_irqrestore(&budget->debilock, flags); return result; } + return ttpci_budget_debiread_nolock(budget, config, addr, + count, nobusyloop); +} + +static int ttpci_budget_debiwrite_nolock(struct budget *budget, u32 config, + int addr, int count, u32 value, int nobusyloop) +{ + struct saa7146_dev *saa = budget->dev; + int result; + + result = saa7146_wait_for_debi_done(saa, nobusyloop); + if (result < 0) + return result; saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff)); saa7146_write(saa, DEBI_CONFIG, config); @@ -295,15 +291,28 @@ int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, saa7146_write(saa, DEBI_AD, value); saa7146_write(saa, MC2, (2 << 16) | 2); - if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); + result = saa7146_wait_for_debi_done(saa, nobusyloop); + return result < 0 ? result : 0; +} + +int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, + int count, u32 value, int uselocks, int nobusyloop) +{ + if (count > 4 || count <= 0) + return 0; + + if (uselocks) { + unsigned long flags; + int result; + + spin_lock_irqsave(&budget->debilock, flags); + result = ttpci_budget_debiwrite_nolock(budget, config, addr, + count, value, nobusyloop); + spin_unlock_irqrestore(&budget->debilock, flags); return result; } - - if (uselocks) - spin_unlock_irqrestore(&budget->debilock, flags); - return 0; + return ttpci_budget_debiwrite_nolock(budget, config, addr, + count, value, nobusyloop); } diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h index 7a7501bd165f..93f2335e004b 100644 --- a/drivers/media/pci/tw68/tw68.h +++ b/drivers/media/pci/tw68/tw68.h @@ -25,7 +25,6 @@ * GNU General Public License for more details. */ -#include #include #include #include diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 765bffb49a72..d9b872b9285a 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -56,10 +56,8 @@ config VIDEO_VIU config VIDEO_TIMBERDALE tristate "Support for timberdale Video In/LogiWIN" - depends on VIDEO_V4L2 && I2C && DMADEVICES - depends on MFD_TIMBERDALE || COMPILE_TEST - select DMA_ENGINE - select TIMB_DMA + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on (MFD_TIMBERDALE && TIMB_DMA) || COMPILE_TEST select VIDEO_ADV7180 select VIDEOBUF_DMA_CONTIG ---help--- @@ -118,6 +116,7 @@ config VIDEO_S3C_CAMIF source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" +source "drivers/media/platform/am437x/Kconfig" endif # V4L_PLATFORM_DRIVERS @@ -140,6 +139,7 @@ config VIDEO_CODA depends on HAS_DMA select SRAM select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV select GENERIC_ALLOCATOR ---help--- @@ -213,7 +213,6 @@ config VIDEO_SAMSUNG_EXYNOS_GSC config VIDEO_SH_VEU tristate "SuperH VEU mem2mem video processing driver" depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA - depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -223,7 +222,7 @@ config VIDEO_SH_VEU config VIDEO_RENESAS_VSP1 tristate "Renesas VSP1 Video Processing Engine" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA - depends on ARCH_SHMOBILE || COMPILE_TEST + depends on (ARCH_SHMOBILE && OF) || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG ---help--- This is a V4L2 driver for the Renesas VSP1 video processing engine. diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index a49936b8ce8a..3ec154742083 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -46,4 +46,6 @@ obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ obj-y += omap/ +obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ + ccflags-y += -I$(srctree)/drivers/media/i2c diff --git a/drivers/media/platform/am437x/Kconfig b/drivers/media/platform/am437x/Kconfig new file mode 100644 index 000000000000..7b023a76e32e --- /dev/null +++ b/drivers/media/platform/am437x/Kconfig @@ -0,0 +1,11 @@ +config VIDEO_AM437X_VPFE + tristate "TI AM437x VPFE video capture driver" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on SOC_AM43XX || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + help + Support for AM437x Video Processing Front End based Video + Capture Driver. + + To compile this driver as a module, choose M here. The module + will be called am437x-vpfe. diff --git a/drivers/media/platform/am437x/Makefile b/drivers/media/platform/am437x/Makefile new file mode 100644 index 000000000000..d11fff16f260 --- /dev/null +++ b/drivers/media/platform/am437x/Makefile @@ -0,0 +1,3 @@ +# Makefile for AM437x VPFE driver + +obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x-vpfe.o diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c new file mode 100644 index 000000000000..56a5cb0d2152 --- /dev/null +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -0,0 +1,2776 @@ +/* + * TI VPFE capture Driver + * + * Copyright (C) 2013 - 2014 Texas Instruments, Inc. + * + * Benoit Parrot + * Lad, Prabhakar + * + * 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 +#include +#include +#include + +#include +#include +#include +#include + +#include "am437x-vpfe.h" + +#define VPFE_MODULE_NAME "vpfe" +#define VPFE_VERSION "0.1.0" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level 0-8"); + +#define vpfe_dbg(level, dev, fmt, arg...) \ + v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ##arg) +#define vpfe_info(dev, fmt, arg...) \ + v4l2_info(&dev->v4l2_dev, fmt, ##arg) +#define vpfe_err(dev, fmt, arg...) \ + v4l2_err(&dev->v4l2_dev, fmt, ##arg) + +/* standard information */ +struct vpfe_standard { + v4l2_std_id std_id; + unsigned int width; + unsigned int height; + struct v4l2_fract pixelaspect; + int frame_format; +}; + +static const struct vpfe_standard vpfe_standards[] = { + {V4L2_STD_525_60, 720, 480, {11, 10}, 1}, + {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, +}; + +struct bus_format { + unsigned int width; + unsigned int bpp; +}; + +/* + * struct vpfe_fmt - VPFE media bus format information + * @name: V4L2 format description + * @code: V4L2 media bus format code + * @shifted: 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 + * @width: Bits per pixel (when transferred over a bus) + * @bpp: Bytes per pixel (when stored in memory) + * @supported: Indicates format supported by subdev + */ +struct vpfe_fmt { + const char *name; + u32 fourcc; + u32 code; + struct bus_format l; + struct bus_format s; + bool supported; + u32 index; +}; + +static struct vpfe_fmt formats[] = { + { + .name = "YUV 4:2:2 packed, YCbYCr", + .fourcc = V4L2_PIX_FMT_YUYV, + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .l.width = 10, + .l.bpp = 4, + .s.width = 8, + .s.bpp = 2, + .supported = false, + }, { + .name = "YUV 4:2:2 packed, CbYCrY", + .fourcc = V4L2_PIX_FMT_UYVY, + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .l.width = 10, + .l.bpp = 4, + .s.width = 8, + .s.bpp = 2, + .supported = false, + }, { + .name = "YUV 4:2:2 packed, YCrYCb", + .fourcc = V4L2_PIX_FMT_YVYU, + .code = MEDIA_BUS_FMT_YVYU8_2X8, + .l.width = 10, + .l.bpp = 4, + .s.width = 8, + .s.bpp = 2, + .supported = false, + }, { + .name = "YUV 4:2:2 packed, CrYCbY", + .fourcc = V4L2_PIX_FMT_VYUY, + .code = MEDIA_BUS_FMT_VYUY8_2X8, + .l.width = 10, + .l.bpp = 4, + .s.width = 8, + .s.bpp = 2, + .supported = false, + }, { + .name = "RAW8 BGGR", + .fourcc = V4L2_PIX_FMT_SBGGR8, + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .l.width = 10, + .l.bpp = 2, + .s.width = 8, + .s.bpp = 1, + .supported = false, + }, { + .name = "RAW8 GBRG", + .fourcc = V4L2_PIX_FMT_SGBRG8, + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .l.width = 10, + .l.bpp = 2, + .s.width = 8, + .s.bpp = 1, + .supported = false, + }, { + .name = "RAW8 GRBG", + .fourcc = V4L2_PIX_FMT_SGRBG8, + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .l.width = 10, + .l.bpp = 2, + .s.width = 8, + .s.bpp = 1, + .supported = false, + }, { + .name = "RAW8 RGGB", + .fourcc = V4L2_PIX_FMT_SRGGB8, + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .l.width = 10, + .l.bpp = 2, + .s.width = 8, + .s.bpp = 1, + .supported = false, + }, { + .name = "RGB565 (LE)", + .fourcc = V4L2_PIX_FMT_RGB565, + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .l.width = 10, + .l.bpp = 4, + .s.width = 8, + .s.bpp = 2, + .supported = false, + }, { + .name = "RGB565 (BE)", + .fourcc = V4L2_PIX_FMT_RGB565X, + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .l.width = 10, + .l.bpp = 4, + .s.width = 8, + .s.bpp = 2, + .supported = false, + }, +}; + +static int +__vpfe_get_format(struct vpfe_device *vpfe, + struct v4l2_format *format, unsigned int *bpp); + +static struct vpfe_fmt *find_format_by_code(unsigned int code) +{ + struct vpfe_fmt *fmt; + unsigned int k; + + for (k = 0; k < ARRAY_SIZE(formats); k++) { + fmt = &formats[k]; + if (fmt->code == code) + return fmt; + } + + return NULL; +} + +static struct vpfe_fmt *find_format_by_pix(unsigned int pixelformat) +{ + struct vpfe_fmt *fmt; + unsigned int k; + + for (k = 0; k < ARRAY_SIZE(formats); k++) { + fmt = &formats[k]; + if (fmt->fourcc == pixelformat) + return fmt; + } + + return NULL; +} + +static void +mbus_to_pix(struct vpfe_device *vpfe, + const struct v4l2_mbus_framefmt *mbus, + struct v4l2_pix_format *pix, unsigned int *bpp) +{ + struct vpfe_subdev_info *sdinfo = vpfe->current_subdev; + unsigned int bus_width = sdinfo->vpfe_param.bus_width; + struct vpfe_fmt *fmt; + + fmt = find_format_by_code(mbus->code); + if (WARN_ON(fmt == NULL)) { + pr_err("Invalid mbus code set\n"); + *bpp = 1; + return; + } + + memset(pix, 0, sizeof(*pix)); + v4l2_fill_pix_format(pix, mbus); + pix->pixelformat = fmt->fourcc; + *bpp = (bus_width == 10) ? fmt->l.bpp : fmt->s.bpp; + + /* pitch should be 32 bytes aligned */ + pix->bytesperline = ALIGN(pix->width * *bpp, 32); + pix->sizeimage = pix->bytesperline * pix->height; +} + +static void pix_to_mbus(struct vpfe_device *vpfe, + struct v4l2_pix_format *pix_fmt, + struct v4l2_mbus_framefmt *mbus_fmt) +{ + struct vpfe_fmt *fmt; + + fmt = find_format_by_pix(pix_fmt->pixelformat); + if (!fmt) { + /* default to first entry */ + vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n", + pix_fmt->pixelformat); + fmt = &formats[0]; + } + + memset(mbus_fmt, 0, sizeof(*mbus_fmt)); + v4l2_fill_mbus_format(mbus_fmt, pix_fmt, fmt->code); +} + +/* Print Four-character-code (FOURCC) */ +static char *print_fourcc(u32 fmt) +{ + static char code[5]; + + code[0] = (unsigned char)(fmt & 0xff); + code[1] = (unsigned char)((fmt >> 8) & 0xff); + code[2] = (unsigned char)((fmt >> 16) & 0xff); + code[3] = (unsigned char)((fmt >> 24) & 0xff); + code[4] = '\0'; + + return code; +} + +static int +cmp_v4l2_format(const struct v4l2_format *lhs, const struct v4l2_format *rhs) +{ + return lhs->type == rhs->type && + lhs->fmt.pix.width == rhs->fmt.pix.width && + lhs->fmt.pix.height == rhs->fmt.pix.height && + lhs->fmt.pix.pixelformat == rhs->fmt.pix.pixelformat && + lhs->fmt.pix.field == rhs->fmt.pix.field && + lhs->fmt.pix.colorspace == rhs->fmt.pix.colorspace && + lhs->fmt.pix.ycbcr_enc == rhs->fmt.pix.ycbcr_enc && + lhs->fmt.pix.quantization == rhs->fmt.pix.quantization; +} + +static inline u32 vpfe_reg_read(struct vpfe_ccdc *ccdc, u32 offset) +{ + return ioread32(ccdc->ccdc_cfg.base_addr + offset); +} + +static inline void vpfe_reg_write(struct vpfe_ccdc *ccdc, u32 val, u32 offset) +{ + iowrite32(val, ccdc->ccdc_cfg.base_addr + offset); +} + +static inline struct vpfe_device *to_vpfe(struct vpfe_ccdc *ccdc) +{ + return container_of(ccdc, struct vpfe_device, ccdc); +} + +static inline struct vpfe_cap_buffer *to_vpfe_buffer(struct vb2_buffer *vb) +{ + return container_of(vb, struct vpfe_cap_buffer, vb); +} + +static inline void vpfe_pcr_enable(struct vpfe_ccdc *ccdc, int flag) +{ + vpfe_reg_write(ccdc, !!flag, VPFE_PCR); +} + +static void vpfe_config_enable(struct vpfe_ccdc *ccdc, int flag) +{ + unsigned int cfg; + + if (!flag) { + cfg = vpfe_reg_read(ccdc, VPFE_CONFIG); + cfg &= ~(VPFE_CONFIG_EN_ENABLE << VPFE_CONFIG_EN_SHIFT); + } else { + cfg = VPFE_CONFIG_EN_ENABLE << VPFE_CONFIG_EN_SHIFT; + } + + vpfe_reg_write(ccdc, cfg, VPFE_CONFIG); +} + +static void vpfe_ccdc_setwin(struct vpfe_ccdc *ccdc, + struct v4l2_rect *image_win, + enum ccdc_frmfmt frm_fmt, + int bpp) +{ + int horz_start, horz_nr_pixels; + int vert_start, vert_nr_lines; + int val, mid_img; + + /* + * ppc - per pixel count. indicates how many pixels per cell + * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. + * raw capture this is 1 + */ + horz_start = image_win->left * bpp; + horz_nr_pixels = (image_win->width * bpp) - 1; + vpfe_reg_write(ccdc, (horz_start << VPFE_HORZ_INFO_SPH_SHIFT) | + horz_nr_pixels, VPFE_HORZ_INFO); + + vert_start = image_win->top; + + if (frm_fmt == CCDC_FRMFMT_INTERLACED) { + vert_nr_lines = (image_win->height >> 1) - 1; + vert_start >>= 1; + /* Since first line doesn't have any data */ + vert_start += 1; + /* configure VDINT0 */ + val = (vert_start << VPFE_VDINT_VDINT0_SHIFT); + } else { + /* Since first line doesn't have any data */ + vert_start += 1; + vert_nr_lines = image_win->height - 1; + /* + * configure VDINT0 and VDINT1. VDINT1 will be at half + * of image height + */ + mid_img = vert_start + (image_win->height / 2); + val = (vert_start << VPFE_VDINT_VDINT0_SHIFT) | + (mid_img & VPFE_VDINT_VDINT1_MASK); + } + + vpfe_reg_write(ccdc, val, VPFE_VDINT); + + vpfe_reg_write(ccdc, (vert_start << VPFE_VERT_START_SLV0_SHIFT) | + vert_start, VPFE_VERT_START); + vpfe_reg_write(ccdc, vert_nr_lines, VPFE_VERT_LINES); +} + +static void vpfe_reg_dump(struct vpfe_ccdc *ccdc) +{ + struct vpfe_device *vpfe = to_vpfe(ccdc); + + vpfe_dbg(3, vpfe, "ALAW: 0x%x\n", vpfe_reg_read(ccdc, VPFE_ALAW)); + vpfe_dbg(3, vpfe, "CLAMP: 0x%x\n", vpfe_reg_read(ccdc, VPFE_CLAMP)); + vpfe_dbg(3, vpfe, "DCSUB: 0x%x\n", vpfe_reg_read(ccdc, VPFE_DCSUB)); + vpfe_dbg(3, vpfe, "BLKCMP: 0x%x\n", vpfe_reg_read(ccdc, VPFE_BLKCMP)); + vpfe_dbg(3, vpfe, "COLPTN: 0x%x\n", vpfe_reg_read(ccdc, VPFE_COLPTN)); + vpfe_dbg(3, vpfe, "SDOFST: 0x%x\n", vpfe_reg_read(ccdc, VPFE_SDOFST)); + vpfe_dbg(3, vpfe, "SYN_MODE: 0x%x\n", + vpfe_reg_read(ccdc, VPFE_SYNMODE)); + vpfe_dbg(3, vpfe, "HSIZE_OFF: 0x%x\n", + vpfe_reg_read(ccdc, VPFE_HSIZE_OFF)); + vpfe_dbg(3, vpfe, "HORZ_INFO: 0x%x\n", + vpfe_reg_read(ccdc, VPFE_HORZ_INFO)); + vpfe_dbg(3, vpfe, "VERT_START: 0x%x\n", + vpfe_reg_read(ccdc, VPFE_VERT_START)); + vpfe_dbg(3, vpfe, "VERT_LINES: 0x%x\n", + vpfe_reg_read(ccdc, VPFE_VERT_LINES)); +} + +static int +vpfe_ccdc_validate_param(struct vpfe_ccdc *ccdc, + struct vpfe_ccdc_config_params_raw *ccdcparam) +{ + struct vpfe_device *vpfe = to_vpfe(ccdc); + u8 max_gamma, max_data; + + if (!ccdcparam->alaw.enable) + return 0; + + max_gamma = ccdc_gamma_width_max_bit(ccdcparam->alaw.gamma_wd); + max_data = ccdc_data_size_max_bit(ccdcparam->data_sz); + + if (ccdcparam->alaw.gamma_wd > VPFE_CCDC_GAMMA_BITS_09_0 || + ccdcparam->alaw.gamma_wd < VPFE_CCDC_GAMMA_BITS_15_6 || + max_gamma > max_data) { + vpfe_dbg(1, vpfe, "Invalid data line select\n"); + return -EINVAL; + } + + return 0; +} + +static void +vpfe_ccdc_update_raw_params(struct vpfe_ccdc *ccdc, + struct vpfe_ccdc_config_params_raw *raw_params) +{ + struct vpfe_ccdc_config_params_raw *config_params = + &ccdc->ccdc_cfg.bayer.config_params; + + config_params = raw_params; +} + +/* + * vpfe_ccdc_restore_defaults() + * This function will write defaults to all CCDC registers + */ +static void vpfe_ccdc_restore_defaults(struct vpfe_ccdc *ccdc) +{ + int i; + + /* Disable CCDC */ + vpfe_pcr_enable(ccdc, 0); + + /* set all registers to default value */ + for (i = 4; i <= 0x94; i += 4) + vpfe_reg_write(ccdc, 0, i); + + vpfe_reg_write(ccdc, VPFE_NO_CULLING, VPFE_CULLING); + vpfe_reg_write(ccdc, VPFE_CCDC_GAMMA_BITS_11_2, VPFE_ALAW); +} + +static int vpfe_ccdc_close(struct vpfe_ccdc *ccdc, struct device *dev) +{ + int dma_cntl, i, pcr; + + /* If the CCDC module is still busy wait for it to be done */ + for (i = 0; i < 10; i++) { + usleep_range(5000, 6000); + pcr = vpfe_reg_read(ccdc, VPFE_PCR); + if (!pcr) + break; + + /* make sure it it is disabled */ + vpfe_pcr_enable(ccdc, 0); + } + + /* Disable CCDC by resetting all register to default POR values */ + vpfe_ccdc_restore_defaults(ccdc); + + /* if DMA_CNTL overflow bit is set. Clear it + * It appears to take a while for this to become quiescent ~20ms + */ + for (i = 0; i < 10; i++) { + dma_cntl = vpfe_reg_read(ccdc, VPFE_DMA_CNTL); + if (!(dma_cntl & VPFE_DMA_CNTL_OVERFLOW)) + break; + + /* Clear the overflow bit */ + vpfe_reg_write(ccdc, dma_cntl, VPFE_DMA_CNTL); + usleep_range(5000, 6000); + } + + /* Disabled the module at the CONFIG level */ + vpfe_config_enable(ccdc, 0); + + pm_runtime_put_sync(dev); + + return 0; +} + +static int vpfe_ccdc_set_params(struct vpfe_ccdc *ccdc, void __user *params) +{ + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); + struct vpfe_ccdc_config_params_raw raw_params; + int x; + + if (ccdc->ccdc_cfg.if_type != VPFE_RAW_BAYER) + return -EINVAL; + + x = copy_from_user(&raw_params, params, sizeof(raw_params)); + if (x) { + vpfe_dbg(1, vpfe, + "vpfe_ccdc_set_params: error in copying ccdc params, %d\n", + x); + return -EFAULT; + } + + if (!vpfe_ccdc_validate_param(ccdc, &raw_params)) { + vpfe_ccdc_update_raw_params(ccdc, &raw_params); + return 0; + } + + return -EINVAL; +} + +/* + * vpfe_ccdc_config_ycbcr() + * This function will configure CCDC for YCbCr video capture + */ +static void vpfe_ccdc_config_ycbcr(struct vpfe_ccdc *ccdc) +{ + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); + struct ccdc_params_ycbcr *params = &ccdc->ccdc_cfg.ycbcr; + u32 syn_mode; + + vpfe_dbg(3, vpfe, "vpfe_ccdc_config_ycbcr:\n"); + /* + * first restore the CCDC registers to default values + * This is important since we assume default values to be set in + * a lot of registers that we didn't touch + */ + vpfe_ccdc_restore_defaults(ccdc); + + /* + * configure pixel format, frame format, configure video frame + * format, enable output to SDRAM, enable internal timing generator + * and 8bit pack mode + */ + syn_mode = (((params->pix_fmt & VPFE_SYN_MODE_INPMOD_MASK) << + VPFE_SYN_MODE_INPMOD_SHIFT) | + ((params->frm_fmt & VPFE_SYN_FLDMODE_MASK) << + VPFE_SYN_FLDMODE_SHIFT) | VPFE_VDHDEN_ENABLE | + VPFE_WEN_ENABLE | VPFE_DATA_PACK_ENABLE); + + /* setup BT.656 sync mode */ + if (params->bt656_enable) { + vpfe_reg_write(ccdc, VPFE_REC656IF_BT656_EN, VPFE_REC656IF); + + /* + * configure the FID, VD, HD pin polarity, + * fld,hd pol positive, vd negative, 8-bit data + */ + syn_mode |= VPFE_SYN_MODE_VD_POL_NEGATIVE; + if (ccdc->ccdc_cfg.if_type == VPFE_BT656_10BIT) + syn_mode |= VPFE_SYN_MODE_10BITS; + else + syn_mode |= VPFE_SYN_MODE_8BITS; + } else { + /* y/c external sync mode */ + syn_mode |= (((params->fid_pol & VPFE_FID_POL_MASK) << + VPFE_FID_POL_SHIFT) | + ((params->hd_pol & VPFE_HD_POL_MASK) << + VPFE_HD_POL_SHIFT) | + ((params->vd_pol & VPFE_VD_POL_MASK) << + VPFE_VD_POL_SHIFT)); + } + vpfe_reg_write(ccdc, syn_mode, VPFE_SYNMODE); + + /* configure video window */ + vpfe_ccdc_setwin(ccdc, ¶ms->win, + params->frm_fmt, params->bytesperpixel); + + /* + * configure the order of y cb cr in SDRAM, and disable latch + * internal register on vsync + */ + if (ccdc->ccdc_cfg.if_type == VPFE_BT656_10BIT) + vpfe_reg_write(ccdc, + (params->pix_order << VPFE_CCDCFG_Y8POS_SHIFT) | + VPFE_LATCH_ON_VSYNC_DISABLE | + VPFE_CCDCFG_BW656_10BIT, VPFE_CCDCFG); + else + vpfe_reg_write(ccdc, + (params->pix_order << VPFE_CCDCFG_Y8POS_SHIFT) | + VPFE_LATCH_ON_VSYNC_DISABLE, VPFE_CCDCFG); + + /* + * configure the horizontal line offset. This should be a + * on 32 byte boundary. So clear LSB 5 bits + */ + vpfe_reg_write(ccdc, params->bytesperline, VPFE_HSIZE_OFF); + + /* configure the memory line offset */ + if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) + /* two fields are interleaved in memory */ + vpfe_reg_write(ccdc, VPFE_SDOFST_FIELD_INTERLEAVED, + VPFE_SDOFST); +} + +static void +vpfe_ccdc_config_black_clamp(struct vpfe_ccdc *ccdc, + struct vpfe_ccdc_black_clamp *bclamp) +{ + u32 val; + + if (!bclamp->enable) { + /* configure DCSub */ + val = (bclamp->dc_sub) & VPFE_BLK_DC_SUB_MASK; + vpfe_reg_write(ccdc, val, VPFE_DCSUB); + vpfe_reg_write(ccdc, VPFE_CLAMP_DEFAULT_VAL, VPFE_CLAMP); + return; + } + /* + * Configure gain, Start pixel, No of line to be avg, + * No of pixel/line to be avg, & Enable the Black clamping + */ + val = ((bclamp->sgain & VPFE_BLK_SGAIN_MASK) | + ((bclamp->start_pixel & VPFE_BLK_ST_PXL_MASK) << + VPFE_BLK_ST_PXL_SHIFT) | + ((bclamp->sample_ln & VPFE_BLK_SAMPLE_LINE_MASK) << + VPFE_BLK_SAMPLE_LINE_SHIFT) | + ((bclamp->sample_pixel & VPFE_BLK_SAMPLE_LN_MASK) << + VPFE_BLK_SAMPLE_LN_SHIFT) | VPFE_BLK_CLAMP_ENABLE); + vpfe_reg_write(ccdc, val, VPFE_CLAMP); + /* If Black clamping is enable then make dcsub 0 */ + vpfe_reg_write(ccdc, VPFE_DCSUB_DEFAULT_VAL, VPFE_DCSUB); +} + +static void +vpfe_ccdc_config_black_compense(struct vpfe_ccdc *ccdc, + struct vpfe_ccdc_black_compensation *bcomp) +{ + u32 val; + + val = ((bcomp->b & VPFE_BLK_COMP_MASK) | + ((bcomp->gb & VPFE_BLK_COMP_MASK) << + VPFE_BLK_COMP_GB_COMP_SHIFT) | + ((bcomp->gr & VPFE_BLK_COMP_MASK) << + VPFE_BLK_COMP_GR_COMP_SHIFT) | + ((bcomp->r & VPFE_BLK_COMP_MASK) << + VPFE_BLK_COMP_R_COMP_SHIFT)); + vpfe_reg_write(ccdc, val, VPFE_BLKCMP); +} + +/* + * vpfe_ccdc_config_raw() + * This function will configure CCDC for Raw capture mode + */ +static void vpfe_ccdc_config_raw(struct vpfe_ccdc *ccdc) +{ + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); + struct vpfe_ccdc_config_params_raw *config_params = + &ccdc->ccdc_cfg.bayer.config_params; + struct ccdc_params_raw *params = &ccdc->ccdc_cfg.bayer; + unsigned int syn_mode; + unsigned int val; + + vpfe_dbg(3, vpfe, "vpfe_ccdc_config_raw:\n"); + + /* Reset CCDC */ + vpfe_ccdc_restore_defaults(ccdc); + + /* Disable latching function registers on VSYNC */ + vpfe_reg_write(ccdc, VPFE_LATCH_ON_VSYNC_DISABLE, VPFE_CCDCFG); + + /* + * Configure the vertical sync polarity(SYN_MODE.VDPOL), + * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity + * (SYN_MODE.FLDPOL), frame format(progressive or interlace), + * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output + * SDRAM, enable internal timing generator + */ + syn_mode = (((params->vd_pol & VPFE_VD_POL_MASK) << VPFE_VD_POL_SHIFT) | + ((params->hd_pol & VPFE_HD_POL_MASK) << VPFE_HD_POL_SHIFT) | + ((params->fid_pol & VPFE_FID_POL_MASK) << + VPFE_FID_POL_SHIFT) | ((params->frm_fmt & + VPFE_FRM_FMT_MASK) << VPFE_FRM_FMT_SHIFT) | + ((config_params->data_sz & VPFE_DATA_SZ_MASK) << + VPFE_DATA_SZ_SHIFT) | ((params->pix_fmt & + VPFE_PIX_FMT_MASK) << VPFE_PIX_FMT_SHIFT) | + VPFE_WEN_ENABLE | VPFE_VDHDEN_ENABLE); + + /* Enable and configure aLaw register if needed */ + if (config_params->alaw.enable) { + val = ((config_params->alaw.gamma_wd & + VPFE_ALAW_GAMMA_WD_MASK) | VPFE_ALAW_ENABLE); + vpfe_reg_write(ccdc, val, VPFE_ALAW); + vpfe_dbg(3, vpfe, "\nWriting 0x%x to ALAW...\n", val); + } + + /* Configure video window */ + vpfe_ccdc_setwin(ccdc, ¶ms->win, params->frm_fmt, + params->bytesperpixel); + + /* Configure Black Clamp */ + vpfe_ccdc_config_black_clamp(ccdc, &config_params->blk_clamp); + + /* Configure Black level compensation */ + vpfe_ccdc_config_black_compense(ccdc, &config_params->blk_comp); + + /* If data size is 8 bit then pack the data */ + if ((config_params->data_sz == VPFE_CCDC_DATA_8BITS) || + config_params->alaw.enable) + syn_mode |= VPFE_DATA_PACK_ENABLE; + + /* + * Configure Horizontal offset register. If pack 8 is enabled then + * 1 pixel will take 1 byte + */ + vpfe_reg_write(ccdc, params->bytesperline, VPFE_HSIZE_OFF); + + vpfe_dbg(3, vpfe, "Writing %d (%x) to HSIZE_OFF\n", + params->bytesperline, params->bytesperline); + + /* Set value for SDOFST */ + if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { + if (params->image_invert_enable) { + /* For interlace inverse mode */ + vpfe_reg_write(ccdc, VPFE_INTERLACED_IMAGE_INVERT, + VPFE_SDOFST); + } else { + /* For interlace non inverse mode */ + vpfe_reg_write(ccdc, VPFE_INTERLACED_NO_IMAGE_INVERT, + VPFE_SDOFST); + } + } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { + vpfe_reg_write(ccdc, VPFE_PROGRESSIVE_NO_IMAGE_INVERT, + VPFE_SDOFST); + } + + vpfe_reg_write(ccdc, syn_mode, VPFE_SYNMODE); + + vpfe_reg_dump(ccdc); +} + +static inline int +vpfe_ccdc_set_buftype(struct vpfe_ccdc *ccdc, + enum ccdc_buftype buf_type) +{ + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc->ccdc_cfg.bayer.buf_type = buf_type; + else + ccdc->ccdc_cfg.ycbcr.buf_type = buf_type; + + return 0; +} + +static inline enum ccdc_buftype vpfe_ccdc_get_buftype(struct vpfe_ccdc *ccdc) +{ + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc->ccdc_cfg.bayer.buf_type; + + return ccdc->ccdc_cfg.ycbcr.buf_type; +} + +static int vpfe_ccdc_set_pixel_format(struct vpfe_ccdc *ccdc, u32 pixfmt) +{ + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); + + vpfe_dbg(1, vpfe, "vpfe_ccdc_set_pixel_format: if_type: %d, pixfmt:%s\n", + ccdc->ccdc_cfg.if_type, print_fourcc(pixfmt)); + + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) { + ccdc->ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + /* + * Need to clear it in case it was left on + * after the last capture. + */ + ccdc->ccdc_cfg.bayer.config_params.alaw.enable = 0; + + switch (pixfmt) { + case V4L2_PIX_FMT_SBGGR8: + ccdc->ccdc_cfg.bayer.config_params.alaw.enable = 1; + break; + + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_RGB565X: + break; + + case V4L2_PIX_FMT_SBGGR16: + default: + return -EINVAL; + } + } else { + switch (pixfmt) { + case V4L2_PIX_FMT_YUYV: + ccdc->ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; + break; + + case V4L2_PIX_FMT_UYVY: + ccdc->ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + break; + + default: + return -EINVAL; + } + } + + return 0; +} + +static u32 vpfe_ccdc_get_pixel_format(struct vpfe_ccdc *ccdc) +{ + u32 pixfmt; + + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) { + pixfmt = V4L2_PIX_FMT_YUYV; + } else { + if (ccdc->ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) + pixfmt = V4L2_PIX_FMT_YUYV; + else + pixfmt = V4L2_PIX_FMT_UYVY; + } + + return pixfmt; +} + +static int +vpfe_ccdc_set_image_window(struct vpfe_ccdc *ccdc, + struct v4l2_rect *win, unsigned int bpp) +{ + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) { + ccdc->ccdc_cfg.bayer.win = *win; + ccdc->ccdc_cfg.bayer.bytesperpixel = bpp; + ccdc->ccdc_cfg.bayer.bytesperline = ALIGN(win->width * bpp, 32); + } else { + ccdc->ccdc_cfg.ycbcr.win = *win; + ccdc->ccdc_cfg.ycbcr.bytesperpixel = bpp; + ccdc->ccdc_cfg.ycbcr.bytesperline = ALIGN(win->width * bpp, 32); + } + + return 0; +} + +static inline void +vpfe_ccdc_get_image_window(struct vpfe_ccdc *ccdc, + struct v4l2_rect *win) +{ + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) + *win = ccdc->ccdc_cfg.bayer.win; + else + *win = ccdc->ccdc_cfg.ycbcr.win; +} + +static inline unsigned int vpfe_ccdc_get_line_length(struct vpfe_ccdc *ccdc) +{ + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc->ccdc_cfg.bayer.bytesperline; + + return ccdc->ccdc_cfg.ycbcr.bytesperline; +} + +static inline int +vpfe_ccdc_set_frame_format(struct vpfe_ccdc *ccdc, + enum ccdc_frmfmt frm_fmt) +{ + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) + ccdc->ccdc_cfg.bayer.frm_fmt = frm_fmt; + else + ccdc->ccdc_cfg.ycbcr.frm_fmt = frm_fmt; + + return 0; +} + +static inline enum ccdc_frmfmt +vpfe_ccdc_get_frame_format(struct vpfe_ccdc *ccdc) +{ + if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) + return ccdc->ccdc_cfg.bayer.frm_fmt; + + return ccdc->ccdc_cfg.ycbcr.frm_fmt; +} + +static inline int vpfe_ccdc_getfid(struct vpfe_ccdc *ccdc) +{ + return (vpfe_reg_read(ccdc, VPFE_SYNMODE) >> 15) & 1; +} + +static inline void vpfe_set_sdr_addr(struct vpfe_ccdc *ccdc, unsigned long addr) +{ + vpfe_reg_write(ccdc, addr & 0xffffffe0, VPFE_SDR_ADDR); +} + +static int vpfe_ccdc_set_hw_if_params(struct vpfe_ccdc *ccdc, + struct vpfe_hw_if_param *params) +{ + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); + + ccdc->ccdc_cfg.if_type = params->if_type; + + switch (params->if_type) { + case VPFE_BT656: + case VPFE_YCBCR_SYNC_16: + case VPFE_YCBCR_SYNC_8: + case VPFE_BT656_10BIT: + ccdc->ccdc_cfg.ycbcr.vd_pol = params->vdpol; + ccdc->ccdc_cfg.ycbcr.hd_pol = params->hdpol; + break; + + case VPFE_RAW_BAYER: + ccdc->ccdc_cfg.bayer.vd_pol = params->vdpol; + ccdc->ccdc_cfg.bayer.hd_pol = params->hdpol; + if (params->bus_width == 10) + ccdc->ccdc_cfg.bayer.config_params.data_sz = + VPFE_CCDC_DATA_10BITS; + else + ccdc->ccdc_cfg.bayer.config_params.data_sz = + VPFE_CCDC_DATA_8BITS; + vpfe_dbg(1, vpfe, "params.bus_width: %d\n", + params->bus_width); + vpfe_dbg(1, vpfe, "config_params.data_sz: %d\n", + ccdc->ccdc_cfg.bayer.config_params.data_sz); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static void vpfe_clear_intr(struct vpfe_ccdc *ccdc, int vdint) +{ + unsigned int vpfe_int_status; + + vpfe_int_status = vpfe_reg_read(ccdc, VPFE_IRQ_STS); + + switch (vdint) { + /* VD0 interrupt */ + case VPFE_VDINT0: + vpfe_int_status &= ~VPFE_VDINT0; + vpfe_int_status |= VPFE_VDINT0; + break; + + /* VD1 interrupt */ + case VPFE_VDINT1: + vpfe_int_status &= ~VPFE_VDINT1; + vpfe_int_status |= VPFE_VDINT1; + break; + + /* VD2 interrupt */ + case VPFE_VDINT2: + vpfe_int_status &= ~VPFE_VDINT2; + vpfe_int_status |= VPFE_VDINT2; + break; + + /* Clear all interrupts */ + default: + vpfe_int_status &= ~(VPFE_VDINT0 | + VPFE_VDINT1 | + VPFE_VDINT2); + vpfe_int_status |= (VPFE_VDINT0 | + VPFE_VDINT1 | + VPFE_VDINT2); + break; + } + /* Clear specific VDINT from the status register */ + vpfe_reg_write(ccdc, vpfe_int_status, VPFE_IRQ_STS); + + vpfe_int_status = vpfe_reg_read(ccdc, VPFE_IRQ_STS); + + /* Acknowledge that we are done with all interrupts */ + vpfe_reg_write(ccdc, 1, VPFE_IRQ_EOI); +} + +static void vpfe_ccdc_config_defaults(struct vpfe_ccdc *ccdc) +{ + ccdc->ccdc_cfg.if_type = VPFE_RAW_BAYER; + + ccdc->ccdc_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT; + ccdc->ccdc_cfg.ycbcr.frm_fmt = CCDC_FRMFMT_INTERLACED; + ccdc->ccdc_cfg.ycbcr.fid_pol = VPFE_PINPOL_POSITIVE; + ccdc->ccdc_cfg.ycbcr.vd_pol = VPFE_PINPOL_POSITIVE; + ccdc->ccdc_cfg.ycbcr.hd_pol = VPFE_PINPOL_POSITIVE; + ccdc->ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; + ccdc->ccdc_cfg.ycbcr.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED; + + ccdc->ccdc_cfg.ycbcr.win.left = 0; + ccdc->ccdc_cfg.ycbcr.win.top = 0; + ccdc->ccdc_cfg.ycbcr.win.width = 720; + ccdc->ccdc_cfg.ycbcr.win.height = 576; + ccdc->ccdc_cfg.ycbcr.bt656_enable = 1; + + ccdc->ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; + ccdc->ccdc_cfg.bayer.frm_fmt = CCDC_FRMFMT_PROGRESSIVE; + ccdc->ccdc_cfg.bayer.fid_pol = VPFE_PINPOL_POSITIVE; + ccdc->ccdc_cfg.bayer.vd_pol = VPFE_PINPOL_POSITIVE; + ccdc->ccdc_cfg.bayer.hd_pol = VPFE_PINPOL_POSITIVE; + + ccdc->ccdc_cfg.bayer.win.left = 0; + ccdc->ccdc_cfg.bayer.win.top = 0; + ccdc->ccdc_cfg.bayer.win.width = 800; + ccdc->ccdc_cfg.bayer.win.height = 600; + ccdc->ccdc_cfg.bayer.config_params.data_sz = VPFE_CCDC_DATA_8BITS; + ccdc->ccdc_cfg.bayer.config_params.alaw.gamma_wd = + VPFE_CCDC_GAMMA_BITS_09_0; +} + +/* + * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings + */ +static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe, + struct v4l2_format *f) +{ + struct v4l2_rect image_win; + enum ccdc_buftype buf_type; + enum ccdc_frmfmt frm_fmt; + + memset(f, 0, sizeof(*f)); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vpfe_ccdc_get_image_window(&vpfe->ccdc, &image_win); + f->fmt.pix.width = image_win.width; + f->fmt.pix.height = image_win.height; + f->fmt.pix.bytesperline = vpfe_ccdc_get_line_length(&vpfe->ccdc); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * + f->fmt.pix.height; + buf_type = vpfe_ccdc_get_buftype(&vpfe->ccdc); + f->fmt.pix.pixelformat = vpfe_ccdc_get_pixel_format(&vpfe->ccdc); + frm_fmt = vpfe_ccdc_get_frame_format(&vpfe->ccdc); + + if (frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { + f->fmt.pix.field = V4L2_FIELD_NONE; + } else if (frm_fmt == CCDC_FRMFMT_INTERLACED) { + if (buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + } else if (buf_type == CCDC_BUFTYPE_FLD_SEPARATED) { + f->fmt.pix.field = V4L2_FIELD_SEQ_TB; + } else { + vpfe_err(vpfe, "Invalid buf_type\n"); + return -EINVAL; + } + } else { + vpfe_err(vpfe, "Invalid frm_fmt\n"); + return -EINVAL; + } + return 0; +} + +static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe) +{ + enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; + int ret; + + vpfe_dbg(2, vpfe, "vpfe_config_ccdc_image_format\n"); + + vpfe_dbg(1, vpfe, "pixelformat: %s\n", + print_fourcc(vpfe->fmt.fmt.pix.pixelformat)); + + if (vpfe_ccdc_set_pixel_format(&vpfe->ccdc, + vpfe->fmt.fmt.pix.pixelformat) < 0) { + vpfe_err(vpfe, "couldn't set pix format in ccdc\n"); + return -EINVAL; + } + + /* configure the image window */ + vpfe_ccdc_set_image_window(&vpfe->ccdc, &vpfe->crop, vpfe->bpp); + + switch (vpfe->fmt.fmt.pix.field) { + case V4L2_FIELD_INTERLACED: + /* do nothing, since it is default */ + ret = vpfe_ccdc_set_buftype( + &vpfe->ccdc, + CCDC_BUFTYPE_FLD_INTERLEAVED); + break; + + case V4L2_FIELD_NONE: + frm_fmt = CCDC_FRMFMT_PROGRESSIVE; + /* buffer type only applicable for interlaced scan */ + break; + + case V4L2_FIELD_SEQ_TB: + ret = vpfe_ccdc_set_buftype( + &vpfe->ccdc, + CCDC_BUFTYPE_FLD_SEPARATED); + break; + + default: + return -EINVAL; + } + + if (ret) + return ret; + + return vpfe_ccdc_set_frame_format(&vpfe->ccdc, frm_fmt); +} + +/* + * vpfe_config_image_format() + * For a given standard, this functions sets up the default + * pix format & crop values in the vpfe device and ccdc. It first + * starts with defaults based values from the standard table. + * It then checks if sub device support g_mbus_fmt and then override the + * values based on that.Sets crop values to match with scan resolution + * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the + * values in ccdc + */ +static int vpfe_config_image_format(struct vpfe_device *vpfe, + v4l2_std_id std_id) +{ + struct v4l2_pix_format *pix = &vpfe->fmt.fmt.pix; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { + if (vpfe_standards[i].std_id & std_id) { + vpfe->std_info.active_pixels = + vpfe_standards[i].width; + vpfe->std_info.active_lines = + vpfe_standards[i].height; + vpfe->std_info.frame_format = + vpfe_standards[i].frame_format; + vpfe->std_index = i; + + break; + } + } + + if (i == ARRAY_SIZE(vpfe_standards)) { + vpfe_err(vpfe, "standard not supported\n"); + return -EINVAL; + } + + vpfe->crop.top = vpfe->crop.left = 0; + vpfe->crop.width = vpfe->std_info.active_pixels; + vpfe->crop.height = vpfe->std_info.active_lines; + pix->width = vpfe->crop.width; + pix->height = vpfe->crop.height; + pix->pixelformat = V4L2_PIX_FMT_YUYV; + + /* first field and frame format based on standard frame format */ + if (vpfe->std_info.frame_format) + pix->field = V4L2_FIELD_INTERLACED; + else + pix->field = V4L2_FIELD_NONE; + + ret = __vpfe_get_format(vpfe, &vpfe->fmt, &vpfe->bpp); + if (ret) + return ret; + + /* Update the crop window based on found values */ + vpfe->crop.width = pix->width; + vpfe->crop.height = pix->height; + + return vpfe_config_ccdc_image_format(vpfe); +} + +static int vpfe_initialize_device(struct vpfe_device *vpfe) +{ + struct vpfe_subdev_info *sdinfo; + int ret; + + sdinfo = &vpfe->cfg->sub_devs[0]; + sdinfo->sd = vpfe->sd[0]; + vpfe->current_input = 0; + vpfe->std_index = 0; + /* Configure the default format information */ + ret = vpfe_config_image_format(vpfe, + vpfe_standards[vpfe->std_index].std_id); + if (ret) + return ret; + + pm_runtime_get_sync(vpfe->pdev); + + vpfe_config_enable(&vpfe->ccdc, 1); + + vpfe_ccdc_restore_defaults(&vpfe->ccdc); + + /* Clear all VPFE interrupts */ + vpfe_clear_intr(&vpfe->ccdc, -1); + + return ret; +} + +/* + * vpfe_release : This function is based on the vb2_fop_release + * helper function. + * It has been augmented to handle module power management, + * by disabling/enabling h/w module fcntl clock when necessary. + */ +static int vpfe_release(struct file *file) +{ + struct vpfe_device *vpfe = video_drvdata(file); + int ret; + + mutex_lock(&vpfe->lock); + + if (v4l2_fh_is_singular_file(file)) + vpfe_ccdc_close(&vpfe->ccdc, vpfe->pdev); + ret = _vb2_fop_release(file, NULL); + + mutex_unlock(&vpfe->lock); + + return ret; +} + +/* + * vpfe_open : This function is based on the v4l2_fh_open helper function. + * It has been augmented to handle module power management, + * by disabling/enabling h/w module fcntl clock when necessary. + */ +static int vpfe_open(struct file *file) +{ + struct vpfe_device *vpfe = video_drvdata(file); + int ret; + + mutex_lock(&vpfe->lock); + + ret = v4l2_fh_open(file); + if (ret) { + vpfe_err(vpfe, "v4l2_fh_open failed\n"); + goto unlock; + } + + if (!v4l2_fh_is_singular_file(file)) + goto unlock; + + if (vpfe_initialize_device(vpfe)) { + v4l2_fh_release(file); + ret = -ENODEV; + } + +unlock: + mutex_unlock(&vpfe->lock); + return ret; +} + +/** + * vpfe_schedule_next_buffer: set next buffer address for capture + * @vpfe : ptr to vpfe device + * + * This function will get next buffer from the dma queue and + * set the buffer address in the vpfe register for capture. + * the buffer is marked active + * + * Assumes caller is holding vpfe->dma_queue_lock already + */ +static inline void vpfe_schedule_next_buffer(struct vpfe_device *vpfe) +{ + vpfe->next_frm = list_entry(vpfe->dma_queue.next, + struct vpfe_cap_buffer, list); + list_del(&vpfe->next_frm->list); + + vpfe_set_sdr_addr(&vpfe->ccdc, + vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb, 0)); +} + +static inline void vpfe_schedule_bottom_field(struct vpfe_device *vpfe) +{ + unsigned long addr; + + addr = vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb, 0) + + vpfe->field_off; + + vpfe_set_sdr_addr(&vpfe->ccdc, addr); +} + +/* + * vpfe_process_buffer_complete: process a completed buffer + * @vpfe : ptr to vpfe device + * + * This function time stamp the buffer and mark it as DONE. It also + * wake up any process waiting on the QUEUE and set the next buffer + * as current + */ +static inline void vpfe_process_buffer_complete(struct vpfe_device *vpfe) +{ + v4l2_get_timestamp(&vpfe->cur_frm->vb.v4l2_buf.timestamp); + vpfe->cur_frm->vb.v4l2_buf.field = vpfe->fmt.fmt.pix.field; + vpfe->cur_frm->vb.v4l2_buf.sequence = vpfe->sequence++; + vb2_buffer_done(&vpfe->cur_frm->vb, VB2_BUF_STATE_DONE); + vpfe->cur_frm = vpfe->next_frm; +} + +/* + * vpfe_isr : ISR handler for vpfe capture (VINT0) + * @irq: irq number + * @dev_id: dev_id ptr + * + * It changes status of the captured buffer, takes next buffer from the queue + * and sets its address in VPFE registers + */ +static irqreturn_t vpfe_isr(int irq, void *dev) +{ + struct vpfe_device *vpfe = (struct vpfe_device *)dev; + enum v4l2_field field; + int intr_status; + int fid; + + intr_status = vpfe_reg_read(&vpfe->ccdc, VPFE_IRQ_STS); + + if (intr_status & VPFE_VDINT0) { + field = vpfe->fmt.fmt.pix.field; + + if (field == V4L2_FIELD_NONE) { + /* handle progressive frame capture */ + if (vpfe->cur_frm != vpfe->next_frm) + vpfe_process_buffer_complete(vpfe); + goto next_intr; + } + + /* interlaced or TB capture check which field + we are in hardware */ + fid = vpfe_ccdc_getfid(&vpfe->ccdc); + + /* switch the software maintained field id */ + vpfe->field ^= 1; + if (fid == vpfe->field) { + /* we are in-sync here,continue */ + if (fid == 0) { + /* + * One frame is just being captured. If the + * next frame is available, release the + * current frame and move on + */ + if (vpfe->cur_frm != vpfe->next_frm) + vpfe_process_buffer_complete(vpfe); + /* + * based on whether the two fields are stored + * interleave or separately in memory, + * reconfigure the CCDC memory address + */ + if (field == V4L2_FIELD_SEQ_TB) + vpfe_schedule_bottom_field(vpfe); + + goto next_intr; + } + /* + * if one field is just being captured configure + * the next frame get the next frame from the empty + * queue if no frame is available hold on to the + * current buffer + */ + spin_lock(&vpfe->dma_queue_lock); + if (!list_empty(&vpfe->dma_queue) && + vpfe->cur_frm == vpfe->next_frm) + vpfe_schedule_next_buffer(vpfe); + spin_unlock(&vpfe->dma_queue_lock); + } else if (fid == 0) { + /* + * out of sync. Recover from any hardware out-of-sync. + * May loose one frame + */ + vpfe->field = fid; + } + } + +next_intr: + if (intr_status & VPFE_VDINT1) { + spin_lock(&vpfe->dma_queue_lock); + if (vpfe->fmt.fmt.pix.field == V4L2_FIELD_NONE && + !list_empty(&vpfe->dma_queue) && + vpfe->cur_frm == vpfe->next_frm) + vpfe_schedule_next_buffer(vpfe); + spin_unlock(&vpfe->dma_queue_lock); + } + + vpfe_clear_intr(&vpfe->ccdc, intr_status); + + return IRQ_HANDLED; +} + +static inline void vpfe_detach_irq(struct vpfe_device *vpfe) +{ + unsigned int intr = VPFE_VDINT0; + enum ccdc_frmfmt frame_format; + + frame_format = vpfe_ccdc_get_frame_format(&vpfe->ccdc); + if (frame_format == CCDC_FRMFMT_PROGRESSIVE) + intr |= VPFE_VDINT1; + + vpfe_reg_write(&vpfe->ccdc, intr, VPFE_IRQ_EN_CLR); +} + +static inline void vpfe_attach_irq(struct vpfe_device *vpfe) +{ + unsigned int intr = VPFE_VDINT0; + enum ccdc_frmfmt frame_format; + + frame_format = vpfe_ccdc_get_frame_format(&vpfe->ccdc); + if (frame_format == CCDC_FRMFMT_PROGRESSIVE) + intr |= VPFE_VDINT1; + + vpfe_reg_write(&vpfe->ccdc, intr, VPFE_IRQ_EN_SET); +} + +static int vpfe_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct vpfe_device *vpfe = video_drvdata(file); + + vpfe_dbg(2, vpfe, "vpfe_querycap\n"); + + strlcpy(cap->driver, VPFE_MODULE_NAME, sizeof(cap->driver)); + strlcpy(cap->card, "TI AM437x VPFE", sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", vpfe->v4l2_dev.name); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + + return 0; +} + +/* get the format set at output pad of the adjacent subdev */ +static int __vpfe_get_format(struct vpfe_device *vpfe, + struct v4l2_format *format, unsigned int *bpp) +{ + struct v4l2_mbus_framefmt mbus_fmt; + struct vpfe_subdev_info *sdinfo; + struct v4l2_subdev_format fmt; + int ret; + + sdinfo = vpfe->current_subdev; + if (!sdinfo->sd) + return -EINVAL; + + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + fmt.pad = 0; + + ret = v4l2_subdev_call(sdinfo->sd, pad, get_fmt, NULL, &fmt); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; + + if (!ret) { + v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); + mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp); + } else { + ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, + sdinfo->grp_id, + video, g_mbus_fmt, + &mbus_fmt); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; + v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt); + mbus_to_pix(vpfe, &mbus_fmt, &format->fmt.pix, bpp); + } + + format->type = vpfe->fmt.type; + + vpfe_dbg(1, vpfe, + "%s size %dx%d (%s) bytesperline = %d, size = %d, bpp = %d\n", + __func__, format->fmt.pix.width, format->fmt.pix.height, + print_fourcc(format->fmt.pix.pixelformat), + format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp); + + return 0; +} + +/* set the format at output pad of the adjacent subdev */ +static int __vpfe_set_format(struct vpfe_device *vpfe, + struct v4l2_format *format, unsigned int *bpp) +{ + struct v4l2_mbus_framefmt mbus_fmt; + struct vpfe_subdev_info *sdinfo; + struct v4l2_subdev_format fmt; + int ret; + + vpfe_dbg(2, vpfe, "__vpfe_set_format\n"); + + sdinfo = vpfe->current_subdev; + if (!sdinfo->sd) + return -EINVAL; + + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + fmt.pad = 0; + + pix_to_mbus(vpfe, &format->fmt.pix, &fmt.format); + + ret = v4l2_subdev_call(sdinfo->sd, pad, set_fmt, NULL, &fmt); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; + + if (!ret) { + v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); + mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp); + } else { + ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, + sdinfo->grp_id, + video, s_mbus_fmt, + &mbus_fmt); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + return ret; + + v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt); + mbus_to_pix(vpfe, &mbus_fmt, &format->fmt.pix, bpp); + } + + format->type = vpfe->fmt.type; + + vpfe_dbg(1, vpfe, + "%s size %dx%d (%s) bytesperline = %d, size = %d, bpp = %d\n", + __func__, format->fmt.pix.width, format->fmt.pix.height, + print_fourcc(format->fmt.pix.pixelformat), + format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp); + + return 0; +} + +static int vpfe_g_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpfe_device *vpfe = video_drvdata(file); + + vpfe_dbg(2, vpfe, "vpfe_g_fmt\n"); + + *fmt = vpfe->fmt; + + return 0; +} + +static int vpfe_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + struct vpfe_fmt *fmt = NULL; + unsigned int k; + + vpfe_dbg(2, vpfe, "vpfe_enum_format index:%d\n", + f->index); + + sdinfo = vpfe->current_subdev; + if (!sdinfo->sd) + return -EINVAL; + + if (f->index > ARRAY_SIZE(formats)) + return -EINVAL; + + for (k = 0; k < ARRAY_SIZE(formats); k++) { + if (formats[k].index == f->index) { + fmt = &formats[k]; + break; + } + } + if (!fmt) + return -EINVAL; + + strncpy(f->description, fmt->name, sizeof(f->description) - 1); + f->pixelformat = fmt->fourcc; + f->type = vpfe->fmt.type; + + vpfe_dbg(1, vpfe, "vpfe_enum_format: mbus index: %d code: %x pixelformat: %s [%s]\n", + f->index, fmt->code, print_fourcc(fmt->fourcc), fmt->name); + + return 0; +} + +static int vpfe_try_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpfe_device *vpfe = video_drvdata(file); + unsigned int bpp; + + vpfe_dbg(2, vpfe, "vpfe_try_fmt\n"); + + return __vpfe_get_format(vpfe, fmt, &bpp); +} + +static int vpfe_s_fmt(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct v4l2_format format; + unsigned int bpp; + int ret; + + vpfe_dbg(2, vpfe, "vpfe_s_fmt\n"); + + /* If streaming is started, return error */ + if (vb2_is_busy(&vpfe->buffer_queue)) { + vpfe_err(vpfe, "%s device busy\n", __func__); + return -EBUSY; + } + + ret = vpfe_try_fmt(file, priv, fmt); + if (ret) + return ret; + + + if (!cmp_v4l2_format(fmt, &format)) { + /* Sensor format is different from the requested format + * so we need to change it + */ + ret = __vpfe_set_format(vpfe, fmt, &bpp); + if (ret) + return ret; + } else /* Just make sure all of the fields are consistent */ + *fmt = format; + + /* First detach any IRQ if currently attached */ + vpfe_detach_irq(vpfe); + vpfe->fmt = *fmt; + vpfe->bpp = bpp; + + /* Update the crop window based on found values */ + vpfe->crop.width = fmt->fmt.pix.width; + vpfe->crop.height = fmt->fmt.pix.height; + + /* set image capture parameters in the ccdc */ + return vpfe_config_ccdc_image_format(vpfe); +} + +static int vpfe_enum_size(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct v4l2_subdev_frame_size_enum fse; + struct vpfe_subdev_info *sdinfo; + struct v4l2_mbus_framefmt mbus; + struct v4l2_pix_format pix; + struct vpfe_fmt *fmt; + int ret; + + vpfe_dbg(2, vpfe, "vpfe_enum_size\n"); + + /* check for valid format */ + fmt = find_format_by_pix(fsize->pixel_format); + if (!fmt) { + vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n", + fsize->pixel_format); + return -EINVAL; + } + + memset(fsize->reserved, 0x0, sizeof(fsize->reserved)); + + sdinfo = vpfe->current_subdev; + if (!sdinfo->sd) + return -EINVAL; + + memset(&pix, 0x0, sizeof(pix)); + /* Construct pix from parameter and use default for the rest */ + pix.pixelformat = fsize->pixel_format; + pix.width = 640; + pix.height = 480; + pix.colorspace = V4L2_COLORSPACE_SRGB; + pix.field = V4L2_FIELD_NONE; + pix_to_mbus(vpfe, &pix, &mbus); + + memset(&fse, 0x0, sizeof(fse)); + fse.index = fsize->index; + fse.pad = 0; + fse.code = mbus.code; + ret = v4l2_subdev_call(sdinfo->sd, pad, enum_frame_size, NULL, &fse); + if (ret) + return -EINVAL; + + vpfe_dbg(1, vpfe, "vpfe_enum_size: index: %d code: %x W:[%d,%d] H:[%d,%d]\n", + fse.index, fse.code, fse.min_width, fse.max_width, + fse.min_height, fse.max_height); + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = fse.max_width; + fsize->discrete.height = fse.max_height; + + vpfe_dbg(1, vpfe, "vpfe_enum_size: index: %d pixformat: %s size: %dx%d\n", + fsize->index, print_fourcc(fsize->pixel_format), + fsize->discrete.width, fsize->discrete.height); + + return 0; +} + +/* + * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a + * given app input index + */ +static int +vpfe_get_subdev_input_index(struct vpfe_device *vpfe, + int *subdev_index, + int *subdev_input_index, + int app_input_index) +{ + struct vpfe_config *cfg = vpfe->cfg; + struct vpfe_subdev_info *sdinfo; + int i, j = 0; + + for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { + sdinfo = &cfg->sub_devs[i]; + if (app_input_index < (j + 1)) { + *subdev_index = i; + *subdev_input_index = app_input_index - j; + return 0; + } + j++; + } + return -EINVAL; +} + +/* + * vpfe_get_app_input - Get app input index for a given subdev input index + * driver stores the input index of the current sub device and translate it + * when application request the current input + */ +static int vpfe_get_app_input_index(struct vpfe_device *vpfe, + int *app_input_index) +{ + struct vpfe_config *cfg = vpfe->cfg; + struct vpfe_subdev_info *sdinfo; + int i, j = 0; + + for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { + sdinfo = &cfg->sub_devs[i]; + if (!strcmp(sdinfo->name, vpfe->current_subdev->name)) { + if (vpfe->current_input >= 1) + return -1; + *app_input_index = j + vpfe->current_input; + return 0; + } + j++; + } + return -EINVAL; +} + +static int vpfe_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + int subdev, index; + + vpfe_dbg(2, vpfe, "vpfe_enum_input\n"); + + if (vpfe_get_subdev_input_index(vpfe, &subdev, &index, + inp->index) < 0) { + vpfe_dbg(1, vpfe, + "input information not found for the subdev\n"); + return -EINVAL; + } + sdinfo = &vpfe->cfg->sub_devs[subdev]; + *inp = sdinfo->inputs[index]; + + return 0; +} + +static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) +{ + struct vpfe_device *vpfe = video_drvdata(file); + + vpfe_dbg(2, vpfe, "vpfe_g_input\n"); + + return vpfe_get_app_input_index(vpfe, index); +} + +/* Assumes caller is holding vpfe_dev->lock */ +static int vpfe_set_input(struct vpfe_device *vpfe, unsigned int index) +{ + int subdev_index = 0, inp_index = 0; + struct vpfe_subdev_info *sdinfo; + struct vpfe_route *route; + u32 input, output; + int ret; + + vpfe_dbg(2, vpfe, "vpfe_set_input: index: %d\n", index); + + /* If streaming is started, return error */ + if (vb2_is_busy(&vpfe->buffer_queue)) { + vpfe_err(vpfe, "%s device busy\n", __func__); + return -EBUSY; + } + ret = vpfe_get_subdev_input_index(vpfe, + &subdev_index, + &inp_index, + index); + if (ret < 0) { + vpfe_err(vpfe, "invalid input index: %d\n", index); + goto get_out; + } + + sdinfo = &vpfe->cfg->sub_devs[subdev_index]; + sdinfo->sd = vpfe->sd[subdev_index]; + route = &sdinfo->routes[inp_index]; + if (route && sdinfo->can_route) { + input = route->input; + output = route->output; + if (sdinfo->sd) { + ret = v4l2_subdev_call(sdinfo->sd, video, + s_routing, input, output, 0); + if (ret) { + vpfe_err(vpfe, "s_routing failed\n"); + ret = -EINVAL; + goto get_out; + } + } + + } + + vpfe->current_subdev = sdinfo; + if (sdinfo->sd) + vpfe->v4l2_dev.ctrl_handler = sdinfo->sd->ctrl_handler; + vpfe->current_input = index; + vpfe->std_index = 0; + + /* set the bus/interface parameter for the sub device in ccdc */ + ret = vpfe_ccdc_set_hw_if_params(&vpfe->ccdc, &sdinfo->vpfe_param); + if (ret) + return ret; + + /* set the default image parameters in the device */ + return vpfe_config_image_format(vpfe, + vpfe_standards[vpfe->std_index].std_id); + +get_out: + return ret; +} + +static int vpfe_s_input(struct file *file, void *priv, unsigned int index) +{ + struct vpfe_device *vpfe = video_drvdata(file); + + vpfe_dbg(2, vpfe, + "vpfe_s_input: index: %d\n", index); + + return vpfe_set_input(vpfe, index); +} + +static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + + vpfe_dbg(2, vpfe, "vpfe_querystd\n"); + + sdinfo = vpfe->current_subdev; + if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD)) + return -ENODATA; + + /* Call querystd function of decoder device */ + return v4l2_device_call_until_err(&vpfe->v4l2_dev, sdinfo->grp_id, + video, querystd, std_id); +} + +static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + int ret; + + vpfe_dbg(2, vpfe, "vpfe_s_std\n"); + + sdinfo = vpfe->current_subdev; + if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD)) + return -ENODATA; + + /* If streaming is started, return error */ + if (vb2_is_busy(&vpfe->buffer_queue)) { + vpfe_err(vpfe, "%s device busy\n", __func__); + ret = -EBUSY; + return ret; + } + + ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, sdinfo->grp_id, + video, s_std, std_id); + if (ret < 0) { + vpfe_err(vpfe, "Failed to set standard\n"); + return ret; + } + ret = vpfe_config_image_format(vpfe, std_id); + + return ret; +} + +static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct vpfe_subdev_info *sdinfo; + + vpfe_dbg(2, vpfe, "vpfe_g_std\n"); + + sdinfo = vpfe->current_subdev; + if (sdinfo->inputs[0].capabilities != V4L2_IN_CAP_STD) + return -ENODATA; + + *std_id = vpfe_standards[vpfe->std_index].std_id; + + return 0; +} + +/* + * vpfe_calculate_offsets : This function calculates buffers offset + * for top and bottom field + */ +static void vpfe_calculate_offsets(struct vpfe_device *vpfe) +{ + struct v4l2_rect image_win; + + vpfe_dbg(2, vpfe, "vpfe_calculate_offsets\n"); + + vpfe_ccdc_get_image_window(&vpfe->ccdc, &image_win); + vpfe->field_off = image_win.height * image_win.width; +} + +/* + * vpfe_queue_setup - Callback function for buffer setup. + * @vq: vb2_queue ptr + * @fmt: v4l2 format + * @nbuffers: ptr to number of buffers requested by application + * @nplanes:: contains number of distinct video planes needed to hold a frame + * @sizes[]: contains the size (in bytes) of each plane. + * @alloc_ctxs: ptr to allocation context + * + * This callback function is called when reqbuf() is called to adjust + * the buffer count and buffer size + */ +static int vpfe_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct vpfe_device *vpfe = vb2_get_drv_priv(vq); + + if (fmt && fmt->fmt.pix.sizeimage < vpfe->fmt.fmt.pix.sizeimage) + return -EINVAL; + + if (vq->num_buffers + *nbuffers < 3) + *nbuffers = 3 - vq->num_buffers; + + *nplanes = 1; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : vpfe->fmt.fmt.pix.sizeimage; + alloc_ctxs[0] = vpfe->alloc_ctx; + + vpfe_dbg(1, vpfe, + "nbuffers=%d, size=%u\n", *nbuffers, sizes[0]); + + /* Calculate field offset */ + vpfe_calculate_offsets(vpfe); + + return 0; +} + +/* + * vpfe_buffer_prepare : callback function for buffer prepare + * @vb: ptr to vb2_buffer + * + * This is the callback function for buffer prepare when vb2_qbuf() + * function is called. The buffer is prepared and user space virtual address + * or user address is converted into physical address + */ +static int vpfe_buffer_prepare(struct vb2_buffer *vb) +{ + struct vpfe_device *vpfe = vb2_get_drv_priv(vb->vb2_queue); + + vb2_set_plane_payload(vb, 0, vpfe->fmt.fmt.pix.sizeimage); + + if (vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) + return -EINVAL; + + vb->v4l2_buf.field = vpfe->fmt.fmt.pix.field; + + return 0; +} + +/* + * vpfe_buffer_queue : Callback function to add buffer to DMA queue + * @vb: ptr to vb2_buffer + */ +static void vpfe_buffer_queue(struct vb2_buffer *vb) +{ + struct vpfe_device *vpfe = vb2_get_drv_priv(vb->vb2_queue); + struct vpfe_cap_buffer *buf = to_vpfe_buffer(vb); + unsigned long flags = 0; + + /* add the buffer to the DMA queue */ + spin_lock_irqsave(&vpfe->dma_queue_lock, flags); + list_add_tail(&buf->list, &vpfe->dma_queue); + spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); +} + +/* + * vpfe_start_streaming : Starts the DMA engine for streaming + * @vb: ptr to vb2_buffer + * @count: number of buffers + */ +static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct vpfe_device *vpfe = vb2_get_drv_priv(vq); + struct vpfe_cap_buffer *buf, *tmp; + struct vpfe_subdev_info *sdinfo; + unsigned long flags; + unsigned long addr; + int ret; + + spin_lock_irqsave(&vpfe->dma_queue_lock, flags); + + vpfe->field = 0; + vpfe->sequence = 0; + + sdinfo = vpfe->current_subdev; + + vpfe_attach_irq(vpfe); + + if (vpfe->ccdc.ccdc_cfg.if_type == VPFE_RAW_BAYER) + vpfe_ccdc_config_raw(&vpfe->ccdc); + else + vpfe_ccdc_config_ycbcr(&vpfe->ccdc); + + /* Get the next frame from the buffer queue */ + vpfe->next_frm = list_entry(vpfe->dma_queue.next, + struct vpfe_cap_buffer, list); + vpfe->cur_frm = vpfe->next_frm; + /* Remove buffer from the buffer queue */ + list_del(&vpfe->cur_frm->list); + spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); + + addr = vb2_dma_contig_plane_dma_addr(&vpfe->cur_frm->vb, 0); + + vpfe_set_sdr_addr(&vpfe->ccdc, (unsigned long)(addr)); + + vpfe_pcr_enable(&vpfe->ccdc, 1); + + ret = v4l2_subdev_call(sdinfo->sd, video, s_stream, 1); + if (ret < 0) { + vpfe_err(vpfe, "Error in attaching interrupt handle\n"); + goto err; + } + + return 0; + +err: + list_for_each_entry_safe(buf, tmp, &vpfe->dma_queue, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + } + + return ret; +} + +/* + * vpfe_stop_streaming : Stop the DMA engine + * @vq: ptr to vb2_queue + * + * This callback stops the DMA engine and any remaining buffers + * in the DMA queue are released. + */ +static void vpfe_stop_streaming(struct vb2_queue *vq) +{ + struct vpfe_device *vpfe = vb2_get_drv_priv(vq); + struct vpfe_subdev_info *sdinfo; + unsigned long flags; + int ret; + + vpfe_pcr_enable(&vpfe->ccdc, 0); + + vpfe_detach_irq(vpfe); + + sdinfo = vpfe->current_subdev; + ret = v4l2_subdev_call(sdinfo->sd, video, s_stream, 0); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + vpfe_dbg(1, vpfe, "stream off failed in subdev\n"); + + /* release all active buffers */ + spin_lock_irqsave(&vpfe->dma_queue_lock, flags); + if (vpfe->cur_frm == vpfe->next_frm) { + vb2_buffer_done(&vpfe->cur_frm->vb, VB2_BUF_STATE_ERROR); + } else { + if (vpfe->cur_frm != NULL) + vb2_buffer_done(&vpfe->cur_frm->vb, + VB2_BUF_STATE_ERROR); + if (vpfe->next_frm != NULL) + vb2_buffer_done(&vpfe->next_frm->vb, + VB2_BUF_STATE_ERROR); + } + + while (!list_empty(&vpfe->dma_queue)) { + vpfe->next_frm = list_entry(vpfe->dma_queue.next, + struct vpfe_cap_buffer, list); + list_del(&vpfe->next_frm->list); + vb2_buffer_done(&vpfe->next_frm->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); +} + +static int vpfe_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *crop) +{ + struct vpfe_device *vpfe = video_drvdata(file); + + vpfe_dbg(2, vpfe, "vpfe_cropcap\n"); + + if (vpfe->std_index >= ARRAY_SIZE(vpfe_standards)) + return -EINVAL; + + memset(crop, 0, sizeof(struct v4l2_cropcap)); + + crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + crop->defrect.width = vpfe_standards[vpfe->std_index].width; + crop->bounds.width = crop->defrect.width; + crop->defrect.height = vpfe_standards[vpfe->std_index].height; + crop->bounds.height = crop->defrect.height; + crop->pixelaspect = vpfe_standards[vpfe->std_index].pixelaspect; + + return 0; +} + +static int +vpfe_g_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpfe_device *vpfe = video_drvdata(file); + + switch (s->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + s->r.left = s->r.top = 0; + s->r.width = vpfe->crop.width; + s->r.height = vpfe->crop.height; + break; + + case V4L2_SEL_TGT_CROP: + s->r = vpfe->crop; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) +{ + if (a->left < b->left || a->top < b->top) + return 0; + + if (a->left + a->width > b->left + b->width) + return 0; + + if (a->top + a->height > b->top + b->height) + return 0; + + return 1; +} + +static int +vpfe_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vpfe_device *vpfe = video_drvdata(file); + struct v4l2_rect cr = vpfe->crop; + struct v4l2_rect r = s->r; + + /* If streaming is started, return error */ + if (vb2_is_busy(&vpfe->buffer_queue)) { + vpfe_err(vpfe, "%s device busy\n", __func__); + return -EBUSY; + } + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + s->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + v4l_bound_align_image(&r.width, 0, cr.width, 0, + &r.height, 0, cr.height, 0, 0); + + r.left = clamp_t(unsigned int, r.left, 0, cr.width - r.width); + r.top = clamp_t(unsigned int, r.top, 0, cr.height - r.height); + + if (s->flags & V4L2_SEL_FLAG_LE && !enclosed_rectangle(&r, &s->r)) + return -ERANGE; + + if (s->flags & V4L2_SEL_FLAG_GE && !enclosed_rectangle(&s->r, &r)) + return -ERANGE; + + s->r = vpfe->crop = r; + + vpfe_ccdc_set_image_window(&vpfe->ccdc, &r, vpfe->bpp); + vpfe->fmt.fmt.pix.width = r.width; + vpfe->fmt.fmt.pix.height = r.height; + vpfe->fmt.fmt.pix.bytesperline = vpfe_ccdc_get_line_length(&vpfe->ccdc); + vpfe->fmt.fmt.pix.sizeimage = vpfe->fmt.fmt.pix.bytesperline * + vpfe->fmt.fmt.pix.height; + + vpfe_dbg(1, vpfe, "cropped (%d,%d)/%dx%d of %dx%d\n", + r.left, r.top, r.width, r.height, cr.width, cr.height); + + return 0; +} + +static long vpfe_ioctl_default(struct file *file, void *priv, + bool valid_prio, unsigned int cmd, void *param) +{ + struct vpfe_device *vpfe = video_drvdata(file); + int ret; + + vpfe_dbg(2, vpfe, "vpfe_ioctl_default\n"); + + if (!valid_prio) { + vpfe_err(vpfe, "%s device busy\n", __func__); + return -EBUSY; + } + + /* If streaming is started, return error */ + if (vb2_is_busy(&vpfe->buffer_queue)) { + vpfe_err(vpfe, "%s device busy\n", __func__); + return -EBUSY; + } + + switch (cmd) { + case VIDIOC_AM437X_CCDC_CFG: + ret = vpfe_ccdc_set_params(&vpfe->ccdc, (void __user *)param); + if (ret) { + vpfe_dbg(2, vpfe, + "Error setting parameters in CCDC\n"); + return ret; + } + ret = vpfe_get_ccdc_image_format(vpfe, + &vpfe->fmt); + if (ret < 0) { + vpfe_dbg(2, vpfe, + "Invalid image format at CCDC\n"); + return ret; + } + break; + + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +static const struct vb2_ops vpfe_video_qops = { + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .queue_setup = vpfe_queue_setup, + .buf_prepare = vpfe_buffer_prepare, + .buf_queue = vpfe_buffer_queue, + .start_streaming = vpfe_start_streaming, + .stop_streaming = vpfe_stop_streaming, +}; + +/* vpfe capture driver file operations */ +static const struct v4l2_file_operations vpfe_fops = { + .owner = THIS_MODULE, + .open = vpfe_open, + .release = vpfe_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +/* vpfe capture ioctl operations */ +static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { + .vidioc_querycap = vpfe_querycap, + .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt, + .vidioc_g_fmt_vid_cap = vpfe_g_fmt, + .vidioc_s_fmt_vid_cap = vpfe_s_fmt, + .vidioc_try_fmt_vid_cap = vpfe_try_fmt, + + .vidioc_enum_framesizes = vpfe_enum_size, + + .vidioc_enum_input = vpfe_enum_input, + .vidioc_g_input = vpfe_g_input, + .vidioc_s_input = vpfe_s_input, + + .vidioc_querystd = vpfe_querystd, + .vidioc_s_std = vpfe_s_std, + .vidioc_g_std = vpfe_g_std, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_cropcap = vpfe_cropcap, + .vidioc_g_selection = vpfe_g_selection, + .vidioc_s_selection = vpfe_s_selection, + + .vidioc_default = vpfe_ioctl_default, +}; + +static int +vpfe_async_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct vpfe_device *vpfe = container_of(notifier->v4l2_dev, + struct vpfe_device, v4l2_dev); + struct v4l2_subdev_mbus_code_enum mbus_code; + struct vpfe_subdev_info *sdinfo; + bool found = false; + int i, j; + + vpfe_dbg(1, vpfe, "vpfe_async_bound\n"); + + for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { + sdinfo = &vpfe->cfg->sub_devs[i]; + + if (!strcmp(sdinfo->name, subdev->name)) { + vpfe->sd[i] = subdev; + vpfe_info(vpfe, + "v4l2 sub device %s registered\n", + subdev->name); + vpfe->sd[i]->grp_id = + sdinfo->grp_id; + /* update tvnorms from the sub devices */ + for (j = 0; j < 1; j++) + vpfe->video_dev->tvnorms |= + sdinfo->inputs[j].std; + + found = true; + break; + } + } + + if (!found) { + vpfe_info(vpfe, "sub device (%s) not matched\n", subdev->name); + return -EINVAL; + } + + /* setup the supported formats & indexes */ + for (j = 0, i = 0; ; ++j) { + struct vpfe_fmt *fmt; + int ret; + + memset(&mbus_code, 0, sizeof(mbus_code)); + mbus_code.index = j; + ret = v4l2_subdev_call(subdev, pad, enum_mbus_code, + NULL, &mbus_code); + if (ret) + break; + + fmt = find_format_by_code(mbus_code.code); + if (!fmt) + continue; + + fmt->supported = true; + fmt->index = i++; + } + + return 0; +} + +static int vpfe_probe_complete(struct vpfe_device *vpfe) +{ + struct video_device *vdev; + struct vb2_queue *q; + int err; + + spin_lock_init(&vpfe->dma_queue_lock); + mutex_init(&vpfe->lock); + + vpfe->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* set first sub device as current one */ + vpfe->current_subdev = &vpfe->cfg->sub_devs[0]; + vpfe->v4l2_dev.ctrl_handler = vpfe->sd[0]->ctrl_handler; + + err = vpfe_set_input(vpfe, 0); + if (err) + goto probe_out; + + /* Initialize videobuf2 queue as per the buffer type */ + vpfe->alloc_ctx = vb2_dma_contig_init_ctx(vpfe->pdev); + if (IS_ERR(vpfe->alloc_ctx)) { + vpfe_err(vpfe, "Failed to get the context\n"); + err = PTR_ERR(vpfe->alloc_ctx); + goto probe_out; + } + + q = &vpfe->buffer_queue; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + q->drv_priv = vpfe; + q->ops = &vpfe_video_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct vpfe_cap_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &vpfe->lock; + q->min_buffers_needed = 1; + + err = vb2_queue_init(q); + if (err) { + vpfe_err(vpfe, "vb2_queue_init() failed\n"); + vb2_dma_contig_cleanup_ctx(vpfe->alloc_ctx); + goto probe_out; + } + + INIT_LIST_HEAD(&vpfe->dma_queue); + + vdev = vpfe->video_dev; + strlcpy(vdev->name, VPFE_MODULE_NAME, sizeof(vdev->name)); + vdev->release = video_device_release; + vdev->fops = &vpfe_fops; + vdev->ioctl_ops = &vpfe_ioctl_ops; + vdev->v4l2_dev = &vpfe->v4l2_dev; + vdev->vfl_dir = VFL_DIR_RX; + vdev->queue = q; + vdev->lock = &vpfe->lock; + video_set_drvdata(vdev, vpfe); + err = video_register_device(vpfe->video_dev, VFL_TYPE_GRABBER, -1); + if (err) { + vpfe_err(vpfe, + "Unable to register video device.\n"); + goto probe_out; + } + + return 0; + +probe_out: + v4l2_device_unregister(&vpfe->v4l2_dev); + return err; +} + +static int vpfe_async_complete(struct v4l2_async_notifier *notifier) +{ + struct vpfe_device *vpfe = container_of(notifier->v4l2_dev, + struct vpfe_device, v4l2_dev); + + return vpfe_probe_complete(vpfe); +} + +static struct vpfe_config * +vpfe_get_pdata(struct platform_device *pdev) +{ + struct device_node *endpoint = NULL, *rem = NULL; + struct v4l2_of_endpoint bus_cfg; + struct vpfe_subdev_info *sdinfo; + struct vpfe_config *pdata; + unsigned int flags; + unsigned int i; + int err; + + dev_dbg(&pdev->dev, "vpfe_get_pdata\n"); + + if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node) + return pdev->dev.platform_data; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + for (i = 0; ; i++) { + endpoint = of_graph_get_next_endpoint(pdev->dev.of_node, + endpoint); + if (!endpoint) + break; + + sdinfo = &pdata->sub_devs[i]; + sdinfo->grp_id = 0; + + /* we only support camera */ + sdinfo->inputs[0].index = i; + strcpy(sdinfo->inputs[0].name, "Camera"); + sdinfo->inputs[0].type = V4L2_INPUT_TYPE_CAMERA; + sdinfo->inputs[0].std = V4L2_STD_ALL; + sdinfo->inputs[0].capabilities = V4L2_IN_CAP_STD; + + sdinfo->can_route = 0; + sdinfo->routes = NULL; + + of_property_read_u32(endpoint, "ti,am437x-vpfe-interface", + &sdinfo->vpfe_param.if_type); + if (sdinfo->vpfe_param.if_type < 0 || + sdinfo->vpfe_param.if_type > 4) { + sdinfo->vpfe_param.if_type = VPFE_RAW_BAYER; + } + + err = v4l2_of_parse_endpoint(endpoint, &bus_cfg); + if (err) { + dev_err(&pdev->dev, "Could not parse the endpoint\n"); + goto done; + } + + sdinfo->vpfe_param.bus_width = bus_cfg.bus.parallel.bus_width; + + if (sdinfo->vpfe_param.bus_width < 8 || + sdinfo->vpfe_param.bus_width > 16) { + dev_err(&pdev->dev, "Invalid bus width.\n"); + goto done; + } + + flags = bus_cfg.bus.parallel.flags; + + if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) + sdinfo->vpfe_param.hdpol = 1; + + if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) + sdinfo->vpfe_param.vdpol = 1; + + rem = of_graph_get_remote_port_parent(endpoint); + if (!rem) { + dev_err(&pdev->dev, "Remote device at %s not found\n", + endpoint->full_name); + goto done; + } + + strncpy(sdinfo->name, rem->name, sizeof(sdinfo->name)); + + pdata->asd[i] = devm_kzalloc(&pdev->dev, + sizeof(struct v4l2_async_subdev), + GFP_KERNEL); + pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_OF; + pdata->asd[i]->match.of.node = rem; + of_node_put(endpoint); + of_node_put(rem); + } + + of_node_put(endpoint); + return pdata; + +done: + of_node_put(endpoint); + of_node_put(rem); + return NULL; +} + +/* + * vpfe_probe : This function creates device entries by register + * itself to the V4L2 driver and initializes fields of each + * device objects + */ +static int vpfe_probe(struct platform_device *pdev) +{ + struct vpfe_config *vpfe_cfg = vpfe_get_pdata(pdev); + struct vpfe_device *vpfe; + struct vpfe_ccdc *ccdc; + struct resource *res; + int ret; + + if (!vpfe_cfg) { + dev_err(&pdev->dev, "No platform data\n"); + return -EINVAL; + } + + vpfe = devm_kzalloc(&pdev->dev, sizeof(*vpfe), GFP_KERNEL); + if (!vpfe) + return -ENOMEM; + + vpfe->pdev = &pdev->dev; + vpfe->cfg = vpfe_cfg; + ccdc = &vpfe->ccdc; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ccdc->ccdc_cfg.base_addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ccdc->ccdc_cfg.base_addr)) + return PTR_ERR(ccdc->ccdc_cfg.base_addr); + + vpfe->irq = platform_get_irq(pdev, 0); + if (vpfe->irq <= 0) { + dev_err(&pdev->dev, "No IRQ resource\n"); + return -ENODEV; + } + + ret = devm_request_irq(vpfe->pdev, vpfe->irq, vpfe_isr, 0, + "vpfe_capture0", vpfe); + if (ret) { + dev_err(&pdev->dev, "Unable to request interrupt\n"); + return -EINVAL; + } + + vpfe->video_dev = video_device_alloc(); + if (!vpfe->video_dev) { + dev_err(&pdev->dev, "Unable to allocate video device\n"); + return -ENOMEM; + } + + ret = v4l2_device_register(&pdev->dev, &vpfe->v4l2_dev); + if (ret) { + vpfe_err(vpfe, + "Unable to register v4l2 device.\n"); + goto probe_out_video_release; + } + + /* set the driver data in platform device */ + platform_set_drvdata(pdev, vpfe); + /* Enabling module functional clock */ + pm_runtime_enable(&pdev->dev); + + /* for now just enable it here instead of waiting for the open */ + pm_runtime_get_sync(&pdev->dev); + + vpfe_ccdc_config_defaults(ccdc); + + pm_runtime_put_sync(&pdev->dev); + + vpfe->sd = devm_kzalloc(&pdev->dev, sizeof(struct v4l2_subdev *) * + ARRAY_SIZE(vpfe->cfg->asd), GFP_KERNEL); + if (!vpfe->sd) { + ret = -ENOMEM; + goto probe_out_v4l2_unregister; + } + + vpfe->notifier.subdevs = vpfe->cfg->asd; + vpfe->notifier.num_subdevs = ARRAY_SIZE(vpfe->cfg->asd); + vpfe->notifier.bound = vpfe_async_bound; + vpfe->notifier.complete = vpfe_async_complete; + ret = v4l2_async_notifier_register(&vpfe->v4l2_dev, + &vpfe->notifier); + if (ret) { + vpfe_err(vpfe, "Error registering async notifier\n"); + ret = -EINVAL; + goto probe_out_v4l2_unregister; + } + + return 0; + +probe_out_v4l2_unregister: + v4l2_device_unregister(&vpfe->v4l2_dev); +probe_out_video_release: + if (!video_is_registered(vpfe->video_dev)) + video_device_release(vpfe->video_dev); + return ret; +} + +/* + * vpfe_remove : It un-register device from V4L2 driver + */ +static int vpfe_remove(struct platform_device *pdev) +{ + struct vpfe_device *vpfe = platform_get_drvdata(pdev); + + vpfe_dbg(2, vpfe, "vpfe_remove\n"); + + pm_runtime_disable(&pdev->dev); + + v4l2_async_notifier_unregister(&vpfe->notifier); + v4l2_device_unregister(&vpfe->v4l2_dev); + video_unregister_device(vpfe->video_dev); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP + +static void vpfe_save_context(struct vpfe_ccdc *ccdc) +{ + ccdc->ccdc_ctx[VPFE_PCR >> 2] = vpfe_reg_read(ccdc, VPFE_PCR); + ccdc->ccdc_ctx[VPFE_SYNMODE >> 2] = vpfe_reg_read(ccdc, VPFE_SYNMODE); + ccdc->ccdc_ctx[VPFE_SDOFST >> 2] = vpfe_reg_read(ccdc, VPFE_SDOFST); + ccdc->ccdc_ctx[VPFE_SDR_ADDR >> 2] = vpfe_reg_read(ccdc, VPFE_SDR_ADDR); + ccdc->ccdc_ctx[VPFE_CLAMP >> 2] = vpfe_reg_read(ccdc, VPFE_CLAMP); + ccdc->ccdc_ctx[VPFE_DCSUB >> 2] = vpfe_reg_read(ccdc, VPFE_DCSUB); + ccdc->ccdc_ctx[VPFE_COLPTN >> 2] = vpfe_reg_read(ccdc, VPFE_COLPTN); + ccdc->ccdc_ctx[VPFE_BLKCMP >> 2] = vpfe_reg_read(ccdc, VPFE_BLKCMP); + ccdc->ccdc_ctx[VPFE_VDINT >> 2] = vpfe_reg_read(ccdc, VPFE_VDINT); + ccdc->ccdc_ctx[VPFE_ALAW >> 2] = vpfe_reg_read(ccdc, VPFE_ALAW); + ccdc->ccdc_ctx[VPFE_REC656IF >> 2] = vpfe_reg_read(ccdc, VPFE_REC656IF); + ccdc->ccdc_ctx[VPFE_CCDCFG >> 2] = vpfe_reg_read(ccdc, VPFE_CCDCFG); + ccdc->ccdc_ctx[VPFE_CULLING >> 2] = vpfe_reg_read(ccdc, VPFE_CULLING); + ccdc->ccdc_ctx[VPFE_HD_VD_WID >> 2] = vpfe_reg_read(ccdc, + VPFE_HD_VD_WID); + ccdc->ccdc_ctx[VPFE_PIX_LINES >> 2] = vpfe_reg_read(ccdc, + VPFE_PIX_LINES); + ccdc->ccdc_ctx[VPFE_HORZ_INFO >> 2] = vpfe_reg_read(ccdc, + VPFE_HORZ_INFO); + ccdc->ccdc_ctx[VPFE_VERT_START >> 2] = vpfe_reg_read(ccdc, + VPFE_VERT_START); + ccdc->ccdc_ctx[VPFE_VERT_LINES >> 2] = vpfe_reg_read(ccdc, + VPFE_VERT_LINES); + ccdc->ccdc_ctx[VPFE_HSIZE_OFF >> 2] = vpfe_reg_read(ccdc, + VPFE_HSIZE_OFF); +} + +static int vpfe_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct vpfe_device *vpfe = platform_get_drvdata(pdev); + struct vpfe_ccdc *ccdc = &vpfe->ccdc; + + /* if streaming has not started we don't care */ + if (!vb2_start_streaming_called(&vpfe->buffer_queue)) + return 0; + + pm_runtime_get_sync(dev); + vpfe_config_enable(ccdc, 1); + + /* Save VPFE context */ + vpfe_save_context(ccdc); + + /* Disable CCDC */ + vpfe_pcr_enable(ccdc, 0); + vpfe_config_enable(ccdc, 0); + + /* Disable both master and slave clock */ + pm_runtime_put_sync(dev); + + /* Select sleep pin state */ + pinctrl_pm_select_sleep_state(dev); + + return 0; +} + +static void vpfe_restore_context(struct vpfe_ccdc *ccdc) +{ + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_SYNMODE >> 2], VPFE_SYNMODE); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_CULLING >> 2], VPFE_CULLING); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_SDOFST >> 2], VPFE_SDOFST); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_SDR_ADDR >> 2], VPFE_SDR_ADDR); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_CLAMP >> 2], VPFE_CLAMP); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_DCSUB >> 2], VPFE_DCSUB); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_COLPTN >> 2], VPFE_COLPTN); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_BLKCMP >> 2], VPFE_BLKCMP); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_VDINT >> 2], VPFE_VDINT); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_ALAW >> 2], VPFE_ALAW); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_REC656IF >> 2], VPFE_REC656IF); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_CCDCFG >> 2], VPFE_CCDCFG); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_PCR >> 2], VPFE_PCR); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_HD_VD_WID >> 2], + VPFE_HD_VD_WID); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_PIX_LINES >> 2], + VPFE_PIX_LINES); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_HORZ_INFO >> 2], + VPFE_HORZ_INFO); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_VERT_START >> 2], + VPFE_VERT_START); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_VERT_LINES >> 2], + VPFE_VERT_LINES); + vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_HSIZE_OFF >> 2], + VPFE_HSIZE_OFF); +} + +static int vpfe_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct vpfe_device *vpfe = platform_get_drvdata(pdev); + struct vpfe_ccdc *ccdc = &vpfe->ccdc; + + /* if streaming has not started we don't care */ + if (!vb2_start_streaming_called(&vpfe->buffer_queue)) + return 0; + + /* Enable both master and slave clock */ + pm_runtime_get_sync(dev); + vpfe_config_enable(ccdc, 1); + + /* Restore VPFE context */ + vpfe_restore_context(ccdc); + + vpfe_config_enable(ccdc, 0); + pm_runtime_put_sync(dev); + + /* Select default pin state */ + pinctrl_pm_select_default_state(dev); + + return 0; +} + +#endif + +static SIMPLE_DEV_PM_OPS(vpfe_pm_ops, vpfe_suspend, vpfe_resume); + +static const struct of_device_id vpfe_of_match[] = { + { .compatible = "ti,am437x-vpfe", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, vpfe_of_match); + +static struct platform_driver vpfe_driver = { + .probe = vpfe_probe, + .remove = vpfe_remove, + .driver = { + .name = VPFE_MODULE_NAME, + .pm = &vpfe_pm_ops, + .of_match_table = of_match_ptr(vpfe_of_match), + }, +}; + +module_platform_driver(vpfe_driver); + +MODULE_AUTHOR("Texas Instruments"); +MODULE_DESCRIPTION("TI AM437x VPFE driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(VPFE_VERSION); diff --git a/drivers/media/platform/am437x/am437x-vpfe.h b/drivers/media/platform/am437x/am437x-vpfe.h new file mode 100644 index 000000000000..0f557352313d --- /dev/null +++ b/drivers/media/platform/am437x/am437x-vpfe.h @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2013 - 2014 Texas Instruments, Inc. + * + * Benoit Parrot + * Lad, Prabhakar + * + * 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 AM437X_VPFE_H +#define AM437X_VPFE_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "am437x-vpfe_regs.h" + +enum vpfe_pin_pol { + VPFE_PINPOL_POSITIVE = 0, + VPFE_PINPOL_NEGATIVE, +}; + +enum vpfe_hw_if_type { + /* Raw Bayer */ + VPFE_RAW_BAYER = 0, + /* BT656 - 8 bit */ + VPFE_BT656, + /* BT656 - 10 bit */ + VPFE_BT656_10BIT, + /* YCbCr - 8 bit with external sync */ + VPFE_YCBCR_SYNC_8, + /* YCbCr - 16 bit with external sync */ + VPFE_YCBCR_SYNC_16, +}; + +/* interface description */ +struct vpfe_hw_if_param { + enum vpfe_hw_if_type if_type; + enum vpfe_pin_pol hdpol; + enum vpfe_pin_pol vdpol; + unsigned int bus_width; +}; + +#define VPFE_MAX_SUBDEV 1 +#define VPFE_MAX_INPUTS 1 + +struct vpfe_pixel_format { + struct v4l2_fmtdesc fmtdesc; + /* bytes per pixel */ + int bpp; +}; + +struct vpfe_std_info { + int active_pixels; + int active_lines; + /* current frame format */ + int frame_format; +}; + +struct vpfe_route { + u32 input; + u32 output; +}; + +struct vpfe_subdev_info { + char name[32]; + /* Sub device group id */ + int grp_id; + /* inputs available at the sub device */ + struct v4l2_input inputs[VPFE_MAX_INPUTS]; + /* Sub dev routing information for each input */ + struct vpfe_route *routes; + /* check if sub dev supports routing */ + int can_route; + /* ccdc bus/interface configuration */ + struct vpfe_hw_if_param vpfe_param; + struct v4l2_subdev *sd; +}; + +struct vpfe_config { + /* information about each subdev */ + struct vpfe_subdev_info sub_devs[VPFE_MAX_SUBDEV]; + /* Flat array, arranged in groups */ + struct v4l2_async_subdev *asd[VPFE_MAX_SUBDEV]; +}; + +struct vpfe_cap_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + +enum ccdc_pixfmt { + CCDC_PIXFMT_RAW = 0, + CCDC_PIXFMT_YCBCR_16BIT, + CCDC_PIXFMT_YCBCR_8BIT, +}; + +enum ccdc_frmfmt { + CCDC_FRMFMT_PROGRESSIVE = 0, + CCDC_FRMFMT_INTERLACED, +}; + +/* PIXEL ORDER IN MEMORY from LSB to MSB */ +/* only applicable for 8-bit input mode */ +enum ccdc_pixorder { + CCDC_PIXORDER_YCBYCR, + CCDC_PIXORDER_CBYCRY, +}; + +enum ccdc_buftype { + CCDC_BUFTYPE_FLD_INTERLEAVED, + CCDC_BUFTYPE_FLD_SEPARATED +}; + + +/* returns the highest bit used for the gamma */ +static inline u8 ccdc_gamma_width_max_bit(enum vpfe_ccdc_gamma_width width) +{ + return 15 - width; +} + +/* returns the highest bit used for this data size */ +static inline u8 ccdc_data_size_max_bit(enum vpfe_ccdc_data_size sz) +{ + return sz == VPFE_CCDC_DATA_8BITS ? 7 : 15 - sz; +} + +/* Structure for CCDC configuration parameters for raw capture mode */ +struct ccdc_params_raw { + /* pixel format */ + enum ccdc_pixfmt pix_fmt; + /* progressive or interlaced frame */ + enum ccdc_frmfmt frm_fmt; + struct v4l2_rect win; + /* Current Format Bytes Per Pixels */ + unsigned int bytesperpixel; + /* Current Format Bytes per Lines + * (Aligned to 32 bytes) used for HORZ_INFO + */ + unsigned int bytesperline; + /* field id polarity */ + enum vpfe_pin_pol fid_pol; + /* vertical sync polarity */ + enum vpfe_pin_pol vd_pol; + /* horizontal sync polarity */ + enum vpfe_pin_pol hd_pol; + /* interleaved or separated fields */ + enum ccdc_buftype buf_type; + /* + * enable to store the image in inverse + * order in memory(bottom to top) + */ + unsigned char image_invert_enable; + /* configurable parameters */ + struct vpfe_ccdc_config_params_raw config_params; +}; + +struct ccdc_params_ycbcr { + /* pixel format */ + enum ccdc_pixfmt pix_fmt; + /* progressive or interlaced frame */ + enum ccdc_frmfmt frm_fmt; + struct v4l2_rect win; + /* Current Format Bytes Per Pixels */ + unsigned int bytesperpixel; + /* Current Format Bytes per Lines + * (Aligned to 32 bytes) used for HORZ_INFO + */ + unsigned int bytesperline; + /* field id polarity */ + enum vpfe_pin_pol fid_pol; + /* vertical sync polarity */ + enum vpfe_pin_pol vd_pol; + /* horizontal sync polarity */ + enum vpfe_pin_pol hd_pol; + /* enable BT.656 embedded sync mode */ + int bt656_enable; + /* cb:y:cr:y or y:cb:y:cr in memory */ + enum ccdc_pixorder pix_order; + /* interleaved or separated fields */ + enum ccdc_buftype buf_type; +}; + +/* + * CCDC operational configuration + */ +struct ccdc_config { + /* CCDC interface type */ + enum vpfe_hw_if_type if_type; + /* Raw Bayer configuration */ + struct ccdc_params_raw bayer; + /* YCbCr configuration */ + struct ccdc_params_ycbcr ycbcr; + /* ccdc base address */ + void __iomem *base_addr; +}; + +struct vpfe_ccdc { + struct ccdc_config ccdc_cfg; + u32 ccdc_ctx[VPFE_REG_END / sizeof(u32)]; +}; + +struct vpfe_device { + /* V4l2 specific parameters */ + /* Identifies video device for this channel */ + struct video_device *video_dev; + /* sub devices */ + struct v4l2_subdev **sd; + /* vpfe cfg */ + struct vpfe_config *cfg; + /* V4l2 device */ + struct v4l2_device v4l2_dev; + /* parent device */ + struct device *pdev; + /* subdevice async Notifier */ + struct v4l2_async_notifier notifier; + /* Indicates id of the field which is being displayed */ + unsigned field; + unsigned sequence; + /* current interface type */ + struct vpfe_hw_if_param vpfe_if_params; + /* ptr to currently selected sub device */ + struct vpfe_subdev_info *current_subdev; + /* current input at the sub device */ + int current_input; + /* Keeps track of the information about the standard */ + struct vpfe_std_info std_info; + /* std index into std table */ + int std_index; + /* IRQs used when CCDC output to SDRAM */ + unsigned int irq; + /* Pointer pointing to current v4l2_buffer */ + struct vpfe_cap_buffer *cur_frm; + /* Pointer pointing to next v4l2_buffer */ + struct vpfe_cap_buffer *next_frm; + /* Used to store pixel format */ + struct v4l2_format fmt; + /* Used to store current bytes per pixel based on current format */ + unsigned int bpp; + /* + * used when IMP is chained to store the crop window which + * is different from the image window + */ + struct v4l2_rect crop; + /* Buffer queue used in video-buf */ + struct vb2_queue buffer_queue; + /* Allocator-specific contexts for each plane */ + struct vb2_alloc_ctx *alloc_ctx; + /* Queue of filled frames */ + struct list_head dma_queue; + /* IRQ lock for DMA queue */ + spinlock_t dma_queue_lock; + /* lock used to access this structure */ + struct mutex lock; + /* + * offset where second field starts from the starting of the + * buffer for field separated YCbCr formats + */ + u32 field_off; + struct vpfe_ccdc ccdc; +}; + +#endif /* AM437X_VPFE_H */ diff --git a/drivers/media/platform/am437x/am437x-vpfe_regs.h b/drivers/media/platform/am437x/am437x-vpfe_regs.h new file mode 100644 index 000000000000..4a0ed29723e8 --- /dev/null +++ b/drivers/media/platform/am437x/am437x-vpfe_regs.h @@ -0,0 +1,140 @@ +/* + * TI AM437x Image Sensor Interface Registers + * + * Copyright (C) 2013 - 2014 Texas Instruments, Inc. + * + * Benoit Parrot + * Lad, Prabhakar + * + * This 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef AM437X_VPFE_REGS_H +#define AM437X_VPFE_REGS_H + +/* VPFE module register offset */ +#define VPFE_REVISION 0x0 +#define VPFE_PCR 0x4 +#define VPFE_SYNMODE 0x8 +#define VPFE_HD_VD_WID 0xc +#define VPFE_PIX_LINES 0x10 +#define VPFE_HORZ_INFO 0x14 +#define VPFE_VERT_START 0x18 +#define VPFE_VERT_LINES 0x1c +#define VPFE_CULLING 0x20 +#define VPFE_HSIZE_OFF 0x24 +#define VPFE_SDOFST 0x28 +#define VPFE_SDR_ADDR 0x2c +#define VPFE_CLAMP 0x30 +#define VPFE_DCSUB 0x34 +#define VPFE_COLPTN 0x38 +#define VPFE_BLKCMP 0x3c +#define VPFE_VDINT 0x48 +#define VPFE_ALAW 0x4c +#define VPFE_REC656IF 0x50 +#define VPFE_CCDCFG 0x54 +#define VPFE_DMA_CNTL 0x98 +#define VPFE_SYSCONFIG 0x104 +#define VPFE_CONFIG 0x108 +#define VPFE_IRQ_EOI 0x110 +#define VPFE_IRQ_STS_RAW 0x114 +#define VPFE_IRQ_STS 0x118 +#define VPFE_IRQ_EN_SET 0x11c +#define VPFE_IRQ_EN_CLR 0x120 +#define VPFE_REG_END 0x124 + +/* Define bit fields within selected registers */ +#define VPFE_FID_POL_MASK 1 +#define VPFE_FID_POL_SHIFT 4 +#define VPFE_HD_POL_MASK 1 +#define VPFE_HD_POL_SHIFT 3 +#define VPFE_VD_POL_MASK 1 +#define VPFE_VD_POL_SHIFT 2 +#define VPFE_HSIZE_OFF_MASK 0xffffffe0 +#define VPFE_32BYTE_ALIGN_VAL 31 +#define VPFE_FRM_FMT_MASK 0x1 +#define VPFE_FRM_FMT_SHIFT 7 +#define VPFE_DATA_SZ_MASK 7 +#define VPFE_DATA_SZ_SHIFT 8 +#define VPFE_PIX_FMT_MASK 3 +#define VPFE_PIX_FMT_SHIFT 12 +#define VPFE_VP2SDR_DISABLE 0xfffbffff +#define VPFE_WEN_ENABLE (1 << 17) +#define VPFE_SDR2RSZ_DISABLE 0xfff7ffff +#define VPFE_VDHDEN_ENABLE (1 << 16) +#define VPFE_LPF_ENABLE (1 << 14) +#define VPFE_ALAW_ENABLE (1 << 3) +#define VPFE_ALAW_GAMMA_WD_MASK 7 +#define VPFE_BLK_CLAMP_ENABLE (1 << 31) +#define VPFE_BLK_SGAIN_MASK 0x1f +#define VPFE_BLK_ST_PXL_MASK 0x7fff +#define VPFE_BLK_ST_PXL_SHIFT 10 +#define VPFE_BLK_SAMPLE_LN_MASK 7 +#define VPFE_BLK_SAMPLE_LN_SHIFT 28 +#define VPFE_BLK_SAMPLE_LINE_MASK 7 +#define VPFE_BLK_SAMPLE_LINE_SHIFT 25 +#define VPFE_BLK_DC_SUB_MASK 0x03fff +#define VPFE_BLK_COMP_MASK 0xff +#define VPFE_BLK_COMP_GB_COMP_SHIFT 8 +#define VPFE_BLK_COMP_GR_COMP_SHIFT 16 +#define VPFE_BLK_COMP_R_COMP_SHIFT 24 +#define VPFE_LATCH_ON_VSYNC_DISABLE (1 << 15) +#define VPFE_DATA_PACK_ENABLE (1 << 11) +#define VPFE_HORZ_INFO_SPH_SHIFT 16 +#define VPFE_VERT_START_SLV0_SHIFT 16 +#define VPFE_VDINT_VDINT0_SHIFT 16 +#define VPFE_VDINT_VDINT1_MASK 0xffff +#define VPFE_PPC_RAW 1 +#define VPFE_DCSUB_DEFAULT_VAL 0 +#define VPFE_CLAMP_DEFAULT_VAL 0 +#define VPFE_COLPTN_VAL 0xbb11bb11 +#define VPFE_TWO_BYTES_PER_PIXEL 2 +#define VPFE_INTERLACED_IMAGE_INVERT 0x4b6d +#define VPFE_INTERLACED_NO_IMAGE_INVERT 0x0249 +#define VPFE_PROGRESSIVE_IMAGE_INVERT 0x4000 +#define VPFE_PROGRESSIVE_NO_IMAGE_INVERT 0 +#define VPFE_INTERLACED_HEIGHT_SHIFT 1 +#define VPFE_SYN_MODE_INPMOD_SHIFT 12 +#define VPFE_SYN_MODE_INPMOD_MASK 3 +#define VPFE_SYN_MODE_8BITS (7 << 8) +#define VPFE_SYN_MODE_10BITS (6 << 8) +#define VPFE_SYN_MODE_11BITS (5 << 8) +#define VPFE_SYN_MODE_12BITS (4 << 8) +#define VPFE_SYN_MODE_13BITS (3 << 8) +#define VPFE_SYN_MODE_14BITS (2 << 8) +#define VPFE_SYN_MODE_15BITS (1 << 8) +#define VPFE_SYN_MODE_16BITS (0 << 8) +#define VPFE_SYN_FLDMODE_MASK 1 +#define VPFE_SYN_FLDMODE_SHIFT 7 +#define VPFE_REC656IF_BT656_EN 3 +#define VPFE_SYN_MODE_VD_POL_NEGATIVE (1 << 2) +#define VPFE_CCDCFG_Y8POS_SHIFT 11 +#define VPFE_CCDCFG_BW656_10BIT (1 << 5) +#define VPFE_SDOFST_FIELD_INTERLEAVED 0x249 +#define VPFE_NO_CULLING 0xffff00ff +#define VPFE_VDINT0 (1 << 0) +#define VPFE_VDINT1 (1 << 1) +#define VPFE_VDINT2 (1 << 2) +#define VPFE_DMA_CNTL_OVERFLOW (1 << 31) + +#define VPFE_CONFIG_PCLK_INV_SHIFT 0 +#define VPFE_CONFIG_PCLK_INV_MASK 1 +#define VPFE_CONFIG_PCLK_INV_NOT_INV 0 +#define VPFE_CONFIG_PCLK_INV_INV 1 +#define VPFE_CONFIG_EN_SHIFT 1 +#define VPFE_CONFIG_EN_MASK 2 +#define VPFE_CONFIG_EN_DISABLE 0 +#define VPFE_CONFIG_EN_ENABLE 1 +#define VPFE_CONFIG_ST_SHIFT 2 +#define VPFE_CONFIG_ST_MASK 4 +#define VPFE_CONFIG_ST_OCP_ACTIVE 0 +#define VPFE_CONFIG_ST_OCP_STANDBY 1 + +#endif /* AM437X_VPFE_REGS_H */ diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index b4029ae293d3..856b542b35b9 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -718,6 +718,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) struct vb2_buffer *buf; int gamma, ret, value; u32 dst_fourcc; + int num_fb; u32 stride; q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); @@ -983,12 +984,14 @@ static int coda_start_encoding(struct coda_ctx *ctx) v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); goto out; } + num_fb = 2; stride = q_data_src->bytesperline; } else { ctx->num_internal_frames = 0; + num_fb = 0; stride = 0; } - coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); + coda_write(dev, num_fb, CODA_CMD_SET_FRAME_BUF_NUM); coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE); if (dev->devtype->product == CODA_7541) { @@ -1316,8 +1319,10 @@ static void coda_seq_end_work(struct work_struct *work) static void coda_bit_release(struct coda_ctx *ctx) { + mutex_lock(&ctx->buffer_mutex); coda_free_framebuffers(ctx); coda_free_context_buffers(ctx); + mutex_unlock(&ctx->buffer_mutex); } const struct coda_context_ops coda_bit_encode_ops = { @@ -1431,9 +1436,10 @@ static int __coda_start_decoding(struct coda_ctx *ctx) height = val & CODA7_PICHEIGHT_MASK; } - if (width > q_data_dst->width || height > q_data_dst->height) { + if (width > q_data_dst->bytesperline || height > q_data_dst->height) { v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n", - width, height, q_data_dst->width, q_data_dst->height); + width, height, q_data_dst->bytesperline, + q_data_dst->height); return -EINVAL; } @@ -1565,6 +1571,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) struct vb2_buffer *dst_buf; struct coda_dev *dev = ctx->dev; struct coda_q_data *q_data_dst; + struct coda_buffer_meta *meta; u32 reg_addr, reg_stride; dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); @@ -1643,12 +1650,12 @@ static int coda_prepare_decode(struct coda_ctx *ctx) coda_write(dev, ctx->iram_info.axi_sram_use, CODA7_REG_BIT_AXI_SRAM_USE); - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) { - struct coda_buffer_meta *meta; + meta = list_first_entry_or_null(&ctx->buffer_meta_list, + struct coda_buffer_meta, list); + + if (meta && ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) { /* If this is the last buffer in the bitstream, add padding */ - meta = list_first_entry(&ctx->buffer_meta_list, - struct coda_buffer_meta, list); if (meta->end == (ctx->bitstream_fifo.kfifo.in & ctx->bitstream_fifo.kfifo.mask)) { static unsigned char buf[512]; @@ -1665,6 +1672,9 @@ static int coda_prepare_decode(struct coda_ctx *ctx) coda_kfifo_sync_to_device_full(ctx); + /* Clear decode success flag */ + coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS); + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); return 0; @@ -1821,6 +1831,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) memset(&ctx->frame_metas[decoded_idx], 0, sizeof(struct coda_buffer_meta)); ctx->frame_metas[decoded_idx].sequence = val; + ctx->sequence_offset++; } mutex_unlock(&ctx->bitstream_mutex); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 39330a70f752..6f32e6d6b156 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "coda.h" @@ -180,6 +181,7 @@ struct coda_video_device { const char *name; enum coda_inst_type type; const struct coda_context_ops *ops; + bool direct; u32 src_formats[CODA_MAX_FORMATS]; u32 dst_formats[CODA_MAX_FORMATS]; }; @@ -468,6 +470,18 @@ static int coda_try_pixelformat(struct coda_ctx *ctx, struct v4l2_format *f) return 0; } +static unsigned int coda_estimate_sizeimage(struct coda_ctx *ctx, u32 sizeimage, + u32 width, u32 height) +{ + /* + * This is a rough estimate for sensible compressed buffer + * sizes (between 1 and 16 bits per pixel). This could be + * improved by better format specific worst case estimates. + */ + return round_up(clamp(sizeimage, width * height / 8, + width * height * 2), PAGE_SIZE); +} + static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, struct v4l2_format *f) { @@ -513,15 +527,10 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, case V4L2_PIX_FMT_H264: case V4L2_PIX_FMT_MPEG4: f->fmt.pix.bytesperline = 0; - /* - * This is a rough estimate for sensible compressed buffer - * sizes (between 1 and 16 bits per pixel). This could be - * improved by better format specific worst case estimates. - */ - f->fmt.pix.sizeimage = round_up(clamp(f->fmt.pix.sizeimage, - f->fmt.pix.width * f->fmt.pix.height / 8, - f->fmt.pix.width * f->fmt.pix.height * 2), - PAGE_SIZE); + f->fmt.pix.sizeimage = coda_estimate_sizeimage(ctx, + f->fmt.pix.sizeimage, + f->fmt.pix.width, + f->fmt.pix.height); break; default: BUG(); @@ -592,7 +601,11 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv, if (ret < 0) return ret; - if (!f->fmt.pix.colorspace) { + switch (f->fmt.pix.colorspace) { + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_JPEG: + break; + default: if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG) f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; else @@ -670,6 +683,7 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, ctx->colorspace = f->fmt.pix.colorspace; + memset(&f_cap, 0, sizeof(f_cap)); f_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; coda_g_fmt(file, priv, &f_cap); f_cap.fmt.pix.width = f->fmt.pix.width; @@ -908,7 +922,8 @@ static void coda_pic_run_work(struct work_struct *work) ctx->ops->finish_run(ctx); } - if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) + if ((ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) && + ctx->ops->seq_end_work) queue_work(dev->workqueue, &ctx->seq_end_work); mutex_unlock(&dev->coda_mutex); @@ -939,15 +954,43 @@ static int coda_job_ready(void *m2m_priv) return 0; } - if (ctx->hold || - ((ctx->inst_type == CODA_INST_DECODER) && - !v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && - (coda_get_bitstream_payload(ctx) < 512) && - !(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "%d: not ready: not enough bitstream data.\n", - ctx->idx); - return 0; + if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { + struct list_head *meta; + bool stream_end; + int num_metas; + int src_bufs; + + if (ctx->hold && !v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx)) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "%d: not ready: on hold for more buffers.\n", + ctx->idx); + return 0; + } + + stream_end = ctx->bit_stream_param & + CODA_BIT_STREAM_END_FLAG; + + num_metas = 0; + list_for_each(meta, &ctx->buffer_meta_list) + num_metas++; + + src_bufs = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx); + + if (!stream_end && (num_metas + src_bufs) < 2) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "%d: not ready: need 2 buffers available (%d, %d)\n", + ctx->idx, num_metas, src_bufs); + return 0; + } + + + if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && + !stream_end && (coda_get_bitstream_payload(ctx) < 512)) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "%d: not ready: not enough bitstream data (%d).\n", + ctx->idx, coda_get_bitstream_payload(ctx)); + return 0; + } } if (ctx->aborting) { @@ -1023,13 +1066,14 @@ static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type) static void set_default_params(struct coda_ctx *ctx) { - unsigned int max_w, max_h, size; + unsigned int max_w, max_h, usize, csize; ctx->codec = coda_find_codec(ctx->dev, ctx->cvd->src_formats[0], ctx->cvd->dst_formats[0]); max_w = min(ctx->codec->max_w, 1920U); max_h = min(ctx->codec->max_h, 1088U); - size = max_w * max_h * 3 / 2; + usize = max_w * max_h * 3 / 2; + csize = coda_estimate_sizeimage(ctx, usize, max_w, max_h); ctx->params.codec_mode = ctx->codec->mode; ctx->colorspace = V4L2_COLORSPACE_REC709; @@ -1044,14 +1088,14 @@ static void set_default_params(struct coda_ctx *ctx) ctx->q_data[V4L2_M2M_DST].height = max_h; if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) { ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w; - ctx->q_data[V4L2_M2M_SRC].sizeimage = size; + ctx->q_data[V4L2_M2M_SRC].sizeimage = usize; ctx->q_data[V4L2_M2M_DST].bytesperline = 0; - ctx->q_data[V4L2_M2M_DST].sizeimage = round_up(size, PAGE_SIZE); + ctx->q_data[V4L2_M2M_DST].sizeimage = csize; } else { ctx->q_data[V4L2_M2M_SRC].bytesperline = 0; - ctx->q_data[V4L2_M2M_SRC].sizeimage = round_up(size, PAGE_SIZE); + ctx->q_data[V4L2_M2M_SRC].sizeimage = csize; ctx->q_data[V4L2_M2M_DST].bytesperline = max_w; - ctx->q_data[V4L2_M2M_DST].sizeimage = size; + ctx->q_data[V4L2_M2M_DST].sizeimage = usize; } ctx->q_data[V4L2_M2M_SRC].rect.width = max_w; ctx->q_data[V4L2_M2M_SRC].rect.height = max_h; @@ -1080,6 +1124,7 @@ static int coda_queue_setup(struct vb2_queue *vq, *nplanes = 1; sizes[0] = size; + /* Set to vb2-dma-contig allocator context, ignored by vb2-vmalloc */ alloc_ctxs[0] = ctx->dev->alloc_ctx; v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, @@ -1109,6 +1154,7 @@ static int coda_buf_prepare(struct vb2_buffer *vb) static void coda_buf_queue(struct vb2_buffer *vb) { struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_queue *vq = vb->vb2_queue; struct coda_q_data *q_data; q_data = get_q_data(ctx, vb->vb2_queue->type); @@ -1117,8 +1163,7 @@ static void coda_buf_queue(struct vb2_buffer *vb) * In the decoder case, immediately try to copy the buffer into the * bitstream ringbuffer and mark it as ready to be dequeued. */ - if (ctx->inst_type == CODA_INST_DECODER && - vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + if (ctx->bitstream.size && vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { /* * For backwards compatibility, queuing an empty buffer marks * the stream end @@ -1218,7 +1263,7 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) return 0; /* Allow BIT decoder device_run with no new buffers queued */ - if (ctx->inst_type == CODA_INST_DECODER) + if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true); ctx->gopcounter = ctx->params.gop_size - 1; @@ -1271,7 +1316,7 @@ static void coda_stop_streaming(struct vb2_queue *q) coda_bit_stream_end_flag(ctx); - ctx->isequence = 0; + ctx->qsequence = 0; while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); @@ -1290,6 +1335,10 @@ static void coda_stop_streaming(struct vb2_queue *q) if (!ctx->streamon_out && !ctx->streamon_cap) { struct coda_buffer_meta *meta; + if (ctx->ops->seq_end_work) { + queue_work(dev->workqueue, &ctx->seq_end_work); + flush_work(&ctx->seq_end_work); + } mutex_lock(&ctx->bitstream_mutex); while (!list_empty(&ctx->buffer_meta_list)) { meta = list_first_entry(&ctx->buffer_meta_list, @@ -1300,6 +1349,7 @@ static void coda_stop_streaming(struct vb2_queue *q) mutex_unlock(&ctx->bitstream_mutex); kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); + ctx->initialized = 0; ctx->runcounter = 0; ctx->aborting = 0; } @@ -1521,8 +1571,8 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, int ret; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_DMABUF | VB2_MMAP; - src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; + src_vq->mem_ops = &vb2_vmalloc_memops; ret = coda_queue_init(priv, src_vq); if (ret) @@ -1577,9 +1627,11 @@ static int coda_open(struct file *file) ctx->cvd = to_coda_video_device(vdev); ctx->inst_type = ctx->cvd->type; ctx->ops = ctx->cvd->ops; + ctx->use_bit = !ctx->cvd->direct; init_completion(&ctx->completion); INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); - INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work); + if (ctx->ops->seq_end_work) + INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work); v4l2_fh_init(&ctx->fh, video_devdata(file)); file->private_data = &ctx->fh; v4l2_fh_add(&ctx->fh); @@ -1630,22 +1682,25 @@ static int coda_open(struct file *file) ctx->fh.ctrl_handler = &ctx->ctrls; - ret = coda_alloc_context_buf(ctx, &ctx->parabuf, - CODA_PARA_BUF_SIZE, "parabuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf"); - goto err_dma_alloc; + if (ctx->use_bit) { + ret = coda_alloc_context_buf(ctx, &ctx->parabuf, + CODA_PARA_BUF_SIZE, "parabuf"); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf"); + goto err_dma_alloc; + } } - - ctx->bitstream.size = CODA_MAX_FRAME_SIZE; - ctx->bitstream.vaddr = dma_alloc_writecombine( - &dev->plat_dev->dev, ctx->bitstream.size, - &ctx->bitstream.paddr, GFP_KERNEL); - if (!ctx->bitstream.vaddr) { - v4l2_err(&dev->v4l2_dev, - "failed to allocate bitstream ringbuffer"); - ret = -ENOMEM; - goto err_dma_writecombine; + if (ctx->use_bit && ctx->inst_type == CODA_INST_DECODER) { + ctx->bitstream.size = CODA_MAX_FRAME_SIZE; + ctx->bitstream.vaddr = dma_alloc_writecombine( + &dev->plat_dev->dev, ctx->bitstream.size, + &ctx->bitstream.paddr, GFP_KERNEL); + if (!ctx->bitstream.vaddr) { + v4l2_err(&dev->v4l2_dev, + "failed to allocate bitstream ringbuffer"); + ret = -ENOMEM; + goto err_dma_writecombine; + } } kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); @@ -1693,16 +1748,14 @@ static int coda_release(struct file *file) v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n", ctx); - debugfs_remove_recursive(ctx->debugfs_entry); - - if (ctx->inst_type == CODA_INST_DECODER) + if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) coda_bit_stream_end_flag(ctx); /* If this instance is running, call .job_abort and wait for it to end */ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); /* In case the instance was not running, we still need to call SEQ_END */ - if (ctx->initialized) { + if (ctx->initialized && ctx->ops->seq_end_work) { queue_work(dev->workqueue, &ctx->seq_end_work); flush_work(&ctx->seq_end_work); } @@ -1728,6 +1781,7 @@ static int coda_release(struct file *file) clear_bit(ctx->idx, &dev->instance_mask); if (ctx->ops->release) ctx->ops->release(ctx); + debugfs_remove_recursive(ctx->debugfs_entry); kfree(ctx); return 0; @@ -1844,10 +1898,11 @@ static int coda_register_device(struct coda_dev *dev, int i) { struct video_device *vfd = &dev->vfd[i]; - if (i > ARRAY_SIZE(dev->vfd)) + if (i >= dev->devtype->num_vdevs) return -EINVAL; - snprintf(vfd->name, sizeof(vfd->name), dev->devtype->vdevs[i]->name); + snprintf(vfd->name, sizeof(vfd->name), "%s", + dev->devtype->vdevs[i]->name); vfd->fops = &coda_fops; vfd->ioctl_ops = &coda_ioctl_ops; vfd->release = video_device_release_empty, @@ -2001,7 +2056,6 @@ static const struct coda_devtype coda_devdata[] = { static struct platform_device_id coda_platform_ids[] = { { .name = "coda-imx27", .driver_data = CODA_IMX27 }, - { .name = "coda-imx53", .driver_data = CODA_IMX53 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, coda_platform_ids); @@ -2142,6 +2196,7 @@ static int coda_probe(struct platform_device *pdev) if (!dev->iram.vaddr) { dev_warn(&pdev->dev, "unable to alloc iram\n"); } else { + memset(dev->iram.vaddr, 0, dev->iram.size); dev->iram.blob.data = dev->iram.vaddr; dev->iram.blob.size = dev->iram.size; dev->iram.dentry = debugfs_create_blob("iram", 0644, diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 5dd47e5f97c1..0c35cd5032ff 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -198,7 +198,6 @@ struct coda_ctx { int initialized; int streamon_out; int streamon_cap; - u32 isequence; u32 qsequence; u32 osequence; u32 sequence_offset; @@ -236,6 +235,7 @@ struct coda_ctx { u32 frame_mem_ctrl; int display_idx; struct dentry *debugfs_entry; + bool use_bit; }; extern int coda_debug; diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h index 8e015b8aa8fa..7d026241171b 100644 --- a/drivers/media/platform/coda/coda_regs.h +++ b/drivers/media/platform/coda/coda_regs.h @@ -304,9 +304,9 @@ #define CODA_RATECONTROL_AUTOSKIP_OFFSET 31 #define CODA_RATECONTROL_AUTOSKIP_MASK 0x01 #define CODA_RATECONTROL_INITIALDELAY_OFFSET 16 -#define CODA_RATECONTROL_INITIALDELAY_MASK 0x7f +#define CODA_RATECONTROL_INITIALDELAY_MASK 0x7fff #define CODA_RATECONTROL_BITRATE_OFFSET 1 -#define CODA_RATECONTROL_BITRATE_MASK 0x7f +#define CODA_RATECONTROL_BITRATE_MASK 0x7fff #define CODA_RATECONTROL_ENABLE_OFFSET 0 #define CODA_RATECONTROL_ENABLE_MASK 0x01 #define CODA_CMD_ENC_SEQ_RC_BUF_SIZE 0x1b0 diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig index d9e1ddb586b1..469e9d28cec0 100644 --- a/drivers/media/platform/davinci/Kconfig +++ b/drivers/media/platform/davinci/Kconfig @@ -1,6 +1,6 @@ config VIDEO_DAVINCI_VPIF_DISPLAY tristate "TI DaVinci VPIF V4L2-Display driver" - depends on VIDEO_DEV + depends on VIDEO_V4L2 depends on ARCH_DAVINCI || COMPILE_TEST depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG @@ -16,7 +16,7 @@ config VIDEO_DAVINCI_VPIF_DISPLAY config VIDEO_DAVINCI_VPIF_CAPTURE tristate "TI DaVinci VPIF video capture driver" - depends on VIDEO_DEV + depends on VIDEO_V4L2 depends on ARCH_DAVINCI || COMPILE_TEST depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG @@ -75,7 +75,7 @@ config VIDEO_DM365_ISIF config VIDEO_DAVINCI_VPBE_DISPLAY tristate "TI DaVinci VPBE V4L2-Display driver" - depends on ARCH_DAVINCI + depends on VIDEO_V4L2 && ARCH_DAVINCI depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h index 0abdb17fb19c..fa572aacdb3f 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/exynos-gsc/gsc-core.h @@ -466,18 +466,6 @@ static inline void gsc_hw_clear_irq(struct gsc_dev *dev, int irq) writel(cfg, dev->regs + GSC_IRQ); } -static inline void gsc_lock(struct vb2_queue *vq) -{ - struct gsc_ctx *ctx = vb2_get_drv_priv(vq); - mutex_lock(&ctx->gsc_dev->lock); -} - -static inline void gsc_unlock(struct vb2_queue *vq) -{ - struct gsc_ctx *ctx = vb2_get_drv_priv(vq); - mutex_unlock(&ctx->gsc_dev->lock); -} - static inline bool gsc_ctx_state_is_set(u32 mask, struct gsc_ctx *ctx) { unsigned long flags; diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index 74e1de637e8f..d5cffef2e227 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -267,8 +267,8 @@ static struct vb2_ops gsc_m2m_qops = { .queue_setup = gsc_m2m_queue_setup, .buf_prepare = gsc_m2m_buf_prepare, .buf_queue = gsc_m2m_buf_queue, - .wait_prepare = gsc_unlock, - .wait_finish = gsc_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .stop_streaming = gsc_m2m_stop_streaming, .start_streaming = gsc_m2m_start_streaming, }; @@ -590,6 +590,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->gsc_dev->lock; ret = vb2_queue_init(src_vq); if (ret) @@ -603,6 +604,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->gsc_dev->lock; return vb2_queue_init(dst_vq); } diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig index 6265d36adceb..4bf5bd1e90d6 100644 --- a/drivers/media/platform/marvell-ccic/Kconfig +++ b/drivers/media/platform/marvell-ccic/Kconfig @@ -5,6 +5,7 @@ config VIDEO_CAFE_CCIC select VIDEO_OV7670 select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_DMA_SG ---help--- This is a video4linux2 driver for the Marvell 88ALP01 integrated CMOS camera controller. This is the controller found on first- @@ -13,7 +14,7 @@ config VIDEO_CAFE_CCIC config VIDEO_MMP_CAMERA tristate "Marvell Armada 610 integrated camera controller support" depends on ARCH_MMP && I2C && VIDEO_V4L2 - depends on HAS_DMA + depends on HAS_DMA && BROKEN select VIDEO_OV7670 select I2C_GPIO select VIDEOBUF2_DMA_SG diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 193373ff268d..dd5b1415f974 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1913,7 +1913,6 @@ int mccic_register(struct mcam_camera *cam) mutex_lock(&cam->s_mutex); cam->vdev = mcam_v4l_template; - cam->vdev.debug = 0; cam->vdev.v4l2_dev = &cam->v4l2_dev; video_set_drvdata(&cam->vdev, cam); ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 51c2129bdcc6..deca80903c3a 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -220,6 +220,9 @@ static u32 isp_xclk_calc_divider(unsigned long *rate, unsigned long parent_rate) return ISPTCTRL_CTRL_DIV_BYPASS; } + if (*rate == 0) + *rate = 1; + divider = DIV_ROUND_CLOSEST(parent_rate, *rate); if (divider >= ISPTCTRL_CTRL_DIV_BYPASS) divider = ISPTCTRL_CTRL_DIV_BYPASS - 1; diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index b463fe172d16..3fe9047ef466 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -602,10 +602,13 @@ isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) strlcpy(cap->card, video->video.name, sizeof(cap->card)); strlcpy(cap->bus_info, "media", sizeof(cap->bus_info)); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT + | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; + if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; else - cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; return 0; } diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index aa40c8269ab8..54479d60cc0d 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -536,24 +536,12 @@ static void buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&camif->slock, flags); } -static void camif_lock(struct vb2_queue *vq) -{ - struct camif_vp *vp = vb2_get_drv_priv(vq); - mutex_lock(&vp->camif->lock); -} - -static void camif_unlock(struct vb2_queue *vq) -{ - struct camif_vp *vp = vb2_get_drv_priv(vq); - mutex_unlock(&vp->camif->lock); -} - static const struct vb2_ops s3c_camif_qops = { .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, - .wait_prepare = camif_unlock, - .wait_finish = camif_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; @@ -1161,6 +1149,7 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx) q->buf_struct_size = sizeof(struct camif_buffer); q->drv_priv = vp; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &vp->camif->lock; ret = vb2_queue_init(q); if (ret) diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 47ba8fbb0426..ec3e1248923d 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index fbfdf03b9054..8e44a59d8ec2 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -810,6 +810,7 @@ static int s5p_mfc_open(struct file *file) q = &ctx->vq_dst; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; q->drv_priv = &ctx->fh; + q->lock = &dev->mfc_mutex; if (vdev == dev->vfd_dec) { q->io_modes = VB2_MMAP; q->ops = get_dec_queue_ops(); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index c6c3452ccca1..aebe4fd7f03a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -813,7 +812,7 @@ static int vidioc_decoder_cmd(struct file *file, void *priv, unsigned long flags; switch (cmd->cmd) { - case V4L2_ENC_CMD_STOP: + case V4L2_DEC_CMD_STOP: if (cmd->flags != 0) return -EINVAL; @@ -944,22 +943,6 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, return 0; } -static void s5p_mfc_unlock(struct vb2_queue *q) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - - mutex_unlock(&dev->mfc_mutex); -} - -static void s5p_mfc_lock(struct vb2_queue *q) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - - mutex_lock(&dev->mfc_mutex); -} - static int s5p_mfc_buf_init(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; @@ -1107,8 +1090,8 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) static struct vb2_ops s5p_mfc_dec_qops = { .queue_setup = s5p_mfc_queue_setup, - .wait_prepare = s5p_mfc_unlock, - .wait_finish = s5p_mfc_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .buf_init = s5p_mfc_buf_init, .start_streaming = s5p_mfc_start_streaming, .stop_streaming = s5p_mfc_stop_streaming, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index bd64f1dcbdb5..e65993f4b901 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -1867,22 +1866,6 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, return 0; } -static void s5p_mfc_unlock(struct vb2_queue *q) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - - mutex_unlock(&dev->mfc_mutex); -} - -static void s5p_mfc_lock(struct vb2_queue *q) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - - mutex_lock(&dev->mfc_mutex); -} - static int s5p_mfc_buf_init(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; @@ -2052,8 +2035,8 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) static struct vb2_ops s5p_mfc_enc_qops = { .queue_setup = s5p_mfc_queue_setup, - .wait_prepare = s5p_mfc_unlock, - .wait_finish = s5p_mfc_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .buf_init = s5p_mfc_buf_init, .buf_prepare = s5p_mfc_buf_prepare, .start_streaming = s5p_mfc_start_streaming, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 9aea179943ce..d826c58b5d53 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -1340,11 +1340,7 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) /* FMO_ASO_CTRL - 0: Enable, 1: Disable */ reg |= (fmo_aso_ctrl << S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6); - /* When user sets desplay_delay to 0, - * It works as "display_delay enable" and delay set to 0. - * If user wants display_delay disable, It should be - * set to negative value. */ - if (ctx->display_delay >= 0) { + if (ctx->display_delay_enable) { reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6); writel(ctx->display_delay, mfc_regs->d_display_delay); } diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index b4d2696501e4..72d4f2e1efc0 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c @@ -926,22 +926,6 @@ static void buf_queue(struct vb2_buffer *vb) mxr_dbg(mdev, "queuing buffer\n"); } -static void wait_lock(struct vb2_queue *vq) -{ - struct mxr_layer *layer = vb2_get_drv_priv(vq); - - mxr_dbg(layer->mdev, "%s\n", __func__); - mutex_lock(&layer->mutex); -} - -static void wait_unlock(struct vb2_queue *vq) -{ - struct mxr_layer *layer = vb2_get_drv_priv(vq); - - mxr_dbg(layer->mdev, "%s\n", __func__); - mutex_unlock(&layer->mutex); -} - static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct mxr_layer *layer = vb2_get_drv_priv(vq); @@ -1040,8 +1024,8 @@ static void stop_streaming(struct vb2_queue *vq) static struct vb2_ops mxr_video_qops = { .queue_setup = queue_setup, .buf_queue = buf_queue, - .wait_prepare = wait_unlock, - .wait_finish = wait_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; @@ -1122,6 +1106,7 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev, .ops = &mxr_video_qops, .min_buffers_needed = 1, .mem_ops = &vb2_dma_contig_memops, + .lock = &layer->mutex, }; return layer; diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index aaa1f6f25a29..a901b6248557 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -242,20 +242,6 @@ static void sh_veu_job_abort(void *priv) veu->aborting = true; } -static void sh_veu_lock(void *priv) -{ - struct sh_veu_dev *veu = priv; - - mutex_lock(&veu->fop_lock); -} - -static void sh_veu_unlock(void *priv) -{ - struct sh_veu_dev *veu = priv; - - mutex_unlock(&veu->fop_lock); -} - static void sh_veu_process(struct sh_veu_dev *veu, struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf) @@ -950,36 +936,28 @@ static void sh_veu_buf_queue(struct vb2_buffer *vb) v4l2_m2m_buf_queue(veu->m2m_ctx, vb); } -static void sh_veu_wait_prepare(struct vb2_queue *q) -{ - sh_veu_unlock(vb2_get_drv_priv(q)); -} - -static void sh_veu_wait_finish(struct vb2_queue *q) -{ - sh_veu_lock(vb2_get_drv_priv(q)); -} - static const struct vb2_ops sh_veu_qops = { .queue_setup = sh_veu_queue_setup, .buf_prepare = sh_veu_buf_prepare, .buf_queue = sh_veu_buf_queue, - .wait_prepare = sh_veu_wait_prepare, - .wait_finish = sh_veu_wait_finish, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; static int sh_veu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) { + struct sh_veu_dev *veu = priv; int ret; memset(src_vq, 0, sizeof(*src_vq)); src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; src_vq->io_modes = VB2_MMAP | VB2_USERPTR; - src_vq->drv_priv = priv; + src_vq->drv_priv = veu; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &sh_veu_qops; src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->lock = &veu->fop_lock; ret = vb2_queue_init(src_vq); if (ret < 0) @@ -988,10 +966,11 @@ static int sh_veu_queue_init(void *priv, struct vb2_queue *src_vq, memset(dst_vq, 0, sizeof(*dst_vq)); dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; - dst_vq->drv_priv = priv; + dst_vq->drv_priv = veu; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &sh_veu_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->lock = &veu->fop_lock; return vb2_queue_init(dst_vq); } diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 8efe40337608..8526bf5c8429 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -455,8 +455,8 @@ static struct vb2_ops isi_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = soc_camera_unlock, - .wait_finish = soc_camera_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ @@ -465,6 +465,8 @@ static struct vb2_ops isi_video_qops = { static int isi_camera_init_videobuf(struct vb2_queue *q, struct soc_camera_device *icd) { + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; q->io_modes = VB2_MMAP; q->drv_priv = icd; @@ -472,6 +474,7 @@ static int isi_camera_init_videobuf(struct vb2_queue *q, q->ops = &isi_video_qops; q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &ici->host_lock; return vb2_queue_init(q); } @@ -760,8 +763,9 @@ static int isi_camera_querycap(struct soc_camera_host *ici, { strcpy(cap->driver, "atmel-isi"); strcpy(cap->card, "Atmel Image Sensor Interface"); - cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; } diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index ce72bd26a6ac..192377f55840 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -1256,7 +1256,8 @@ static int mx2_camera_querycap(struct soc_camera_host *ici, { /* cap->name is set by the friendly caller:-> */ strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index a60c3bb0e4cc..3435fd2ca8ec 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -435,14 +435,16 @@ static struct vb2_ops mx3_videobuf_ops = { .buf_queue = mx3_videobuf_queue, .buf_cleanup = mx3_videobuf_release, .buf_init = mx3_videobuf_init, - .wait_prepare = soc_camera_unlock, - .wait_finish = soc_camera_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .stop_streaming = mx3_stop_streaming, }; static int mx3_camera_init_videobuf(struct vb2_queue *q, struct soc_camera_device *icd) { + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; q->io_modes = VB2_MMAP | VB2_USERPTR; q->drv_priv = icd; @@ -450,6 +452,7 @@ static int mx3_camera_init_videobuf(struct vb2_queue *q, q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct mx3_camera_buffer); q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &ici->host_lock; return vb2_queue_init(q); } @@ -967,7 +970,8 @@ static int mx3_camera_querycap(struct soc_camera_host *ici, { /* cap->name is set by the firendly caller:-> */ strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c index e6b93281f246..16f65ecb70a3 100644 --- a/drivers/media/platform/soc_camera/omap1_camera.c +++ b/drivers/media/platform/soc_camera/omap1_camera.c @@ -1427,7 +1427,8 @@ static int omap1_cam_querycap(struct soc_camera_host *ici, { /* cap->name is set by the friendly caller:-> */ strlcpy(cap->card, "OMAP1 Camera", sizeof(cap->card)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index 951226af0eba..8d6e343fec0f 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -1576,7 +1576,8 @@ static int pxa_camera_querycap(struct soc_camera_host *ici, { /* cap->name is set by the firendly caller:-> */ strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 0c1f55648106..279ab9f6ae38 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -804,62 +804,26 @@ error: vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); } -static void rcar_vin_videobuf_release(struct vb2_buffer *vb) +/* + * Wait for capture to stop and all in-flight buffers to be finished with by + * the video hardware. This must be called under &priv->lock + * + */ +static void rcar_vin_wait_stop_streaming(struct rcar_vin_priv *priv) { - struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct rcar_vin_priv *priv = ici->priv; - unsigned int i; - int buf_in_use = 0; + while (priv->state != STOPPED) { + /* issue stop if running */ + if (priv->state == RUNNING) + rcar_vin_request_capture_stop(priv); - spin_lock_irq(&priv->lock); - - /* Is the buffer in use by the VIN hardware? */ - for (i = 0; i < MAX_BUFFER_NUM; i++) { - if (priv->queue_buf[i] == vb) { - buf_in_use = 1; - break; + /* wait until capturing has been stopped */ + if (priv->state == STOPPING) { + priv->request_to_stop = true; + spin_unlock_irq(&priv->lock); + wait_for_completion(&priv->capture_stop); + spin_lock_irq(&priv->lock); } } - - if (buf_in_use) { - while (priv->state != STOPPED) { - - /* issue stop if running */ - if (priv->state == RUNNING) - rcar_vin_request_capture_stop(priv); - - /* wait until capturing has been stopped */ - if (priv->state == STOPPING) { - priv->request_to_stop = true; - spin_unlock_irq(&priv->lock); - wait_for_completion(&priv->capture_stop); - spin_lock_irq(&priv->lock); - } - } - /* - * Capturing has now stopped. The buffer we have been asked - * to release could be any of the current buffers in use, so - * release all buffers that are in use by HW - */ - for (i = 0; i < MAX_BUFFER_NUM; i++) { - if (priv->queue_buf[i]) { - vb2_buffer_done(priv->queue_buf[i], - VB2_BUF_STATE_ERROR); - priv->queue_buf[i] = NULL; - } - } - } else { - list_del_init(to_buf_list(vb)); - } - - spin_unlock_irq(&priv->lock); -} - -static int rcar_vin_videobuf_init(struct vb2_buffer *vb) -{ - INIT_LIST_HEAD(to_buf_list(vb)); - return 0; } static void rcar_vin_stop_streaming(struct vb2_queue *vq) @@ -868,21 +832,34 @@ static void rcar_vin_stop_streaming(struct vb2_queue *vq) struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct rcar_vin_priv *priv = ici->priv; struct list_head *buf_head, *tmp; + int i; spin_lock_irq(&priv->lock); - list_for_each_safe(buf_head, tmp, &priv->capture) + rcar_vin_wait_stop_streaming(priv); + + for (i = 0; i < MAX_BUFFER_NUM; i++) { + if (priv->queue_buf[i]) { + vb2_buffer_done(priv->queue_buf[i], + VB2_BUF_STATE_ERROR); + priv->queue_buf[i] = NULL; + } + } + + list_for_each_safe(buf_head, tmp, &priv->capture) { + vb2_buffer_done(&list_entry(buf_head, + struct rcar_vin_buffer, list)->vb, + VB2_BUF_STATE_ERROR); list_del_init(buf_head); + } spin_unlock_irq(&priv->lock); } static struct vb2_ops rcar_vin_vb2_ops = { .queue_setup = rcar_vin_videobuf_setup, - .buf_init = rcar_vin_videobuf_init, - .buf_cleanup = rcar_vin_videobuf_release, .buf_queue = rcar_vin_videobuf_queue, .stop_streaming = rcar_vin_stop_streaming, - .wait_prepare = soc_camera_unlock, - .wait_finish = soc_camera_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; static irqreturn_t rcar_vin_irq(int irq, void *data) @@ -1799,13 +1776,17 @@ static int rcar_vin_querycap(struct soc_camera_host *ici, struct v4l2_capability *cap) { strlcpy(cap->card, "R_Car_VIN", sizeof(cap->card)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; } static int rcar_vin_init_videobuf2(struct vb2_queue *vq, struct soc_camera_device *icd) { + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vq->io_modes = VB2_MMAP | VB2_USERPTR; vq->drv_priv = icd; @@ -1813,6 +1794,7 @@ static int rcar_vin_init_videobuf2(struct vb2_queue *vq, vq->mem_ops = &vb2_dma_contig_memops; vq->buf_struct_size = sizeof(struct rcar_vin_buffer); vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vq->lock = &ici->host_lock; return vb2_queue_init(vq); } diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 8b27b3eb2b25..9ce202f53934 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -496,8 +496,8 @@ static struct vb2_ops sh_mobile_ceu_videobuf_ops = { .buf_queue = sh_mobile_ceu_videobuf_queue, .buf_cleanup = sh_mobile_ceu_videobuf_release, .buf_init = sh_mobile_ceu_videobuf_init, - .wait_prepare = soc_camera_unlock, - .wait_finish = soc_camera_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .stop_streaming = sh_mobile_ceu_stop_streaming, }; @@ -1652,13 +1652,17 @@ static int sh_mobile_ceu_querycap(struct soc_camera_host *ici, struct v4l2_capability *cap) { strlcpy(cap->card, "SuperH_Mobile_CEU", sizeof(cap->card)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; } static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q, struct soc_camera_device *icd) { + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; q->io_modes = VB2_MMAP | VB2_USERPTR; q->drv_priv = icd; @@ -1666,6 +1670,7 @@ static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q, q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct sh_mobile_ceu_buffer); q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &ici->host_lock; return vb2_queue_init(q); } diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index b3db51c82bde..cee7b56f8404 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -843,22 +843,6 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt) return res; } -void soc_camera_lock(struct vb2_queue *vq) -{ - struct soc_camera_device *icd = vb2_get_drv_priv(vq); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - mutex_lock(&ici->host_lock); -} -EXPORT_SYMBOL(soc_camera_lock); - -void soc_camera_unlock(struct vb2_queue *vq) -{ - struct soc_camera_device *icd = vb2_get_drv_priv(vq); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - mutex_unlock(&ici->host_lock); -} -EXPORT_SYMBOL(soc_camera_unlock); - static struct v4l2_file_operations soc_camera_fops = { .owner = THIS_MODULE, .open = soc_camera_open, @@ -1813,8 +1797,6 @@ eadddev: mutex_unlock(&ici->clk_lock); } eadd: - video_device_release(icd->vdev); - icd->vdev = NULL; if (icd->vdev) { video_device_release(icd->vdev); icd->vdev = NULL; diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index d628d1a7cf9e..c44760b705da 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -74,7 +75,7 @@ #define VPE_DEF_BUFS_PER_JOB 1 /* default one buffer per batch job */ /* - * each VPE context can need up to 3 config desciptors, 7 input descriptors, + * each VPE context can need up to 3 config descriptors, 7 input descriptors, * 3 output descriptors, and 10 control descriptors */ #define VPE_DESC_LIST_SIZE (10 * VPDMA_DTD_DESC_SIZE + \ @@ -373,7 +374,6 @@ struct vpe_dev { struct vpe_ctx { struct v4l2_fh fh; struct vpe_dev *dev; - struct v4l2_m2m_ctx *m2m_ctx; struct v4l2_ctrl_handler hdl; unsigned int field; /* current field */ @@ -887,10 +887,10 @@ static int job_ready(void *priv) if (ctx->deinterlacing && ctx->src_vbs[2] == NULL) needed += 2; /* need additional two most recent fields */ - if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < needed) + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < needed) return 0; - if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < needed) + if (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < needed) return 0; return 1; @@ -1100,15 +1100,15 @@ static void device_run(void *priv) struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; if (ctx->deinterlacing && ctx->src_vbs[2] == NULL) { - ctx->src_vbs[2] = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + ctx->src_vbs[2] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); WARN_ON(ctx->src_vbs[2] == NULL); - ctx->src_vbs[1] = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + ctx->src_vbs[1] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); WARN_ON(ctx->src_vbs[1] == NULL); } - ctx->src_vbs[0] = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + ctx->src_vbs[0] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); WARN_ON(ctx->src_vbs[0] == NULL); - ctx->dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + ctx->dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); WARN_ON(ctx->dst_vb == NULL); /* config descriptors */ @@ -1334,7 +1334,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) finished: vpe_dbg(ctx->dev, "finishing transaction\n"); ctx->bufs_completed = 0; - v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx); + v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx); handled: return IRQ_HANDLED; } @@ -1395,7 +1395,7 @@ static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) struct vpe_q_data *q_data; int i; - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); if (!vq) return -EINVAL; @@ -1527,7 +1527,7 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f) struct vb2_queue *vq; int i; - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); if (!vq) return -EINVAL; @@ -1739,52 +1739,6 @@ static int vpe_s_selection(struct file *file, void *fh, return set_srcdst_params(ctx); } -static int vpe_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) -{ - struct vpe_ctx *ctx = file2ctx(file); - - return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); -} - -static int vpe_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct vpe_ctx *ctx = file2ctx(file); - - return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); -} - -static int vpe_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct vpe_ctx *ctx = file2ctx(file); - - return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); -} - -static int vpe_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct vpe_ctx *ctx = file2ctx(file); - - return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); -} - -static int vpe_streamon(struct file *file, void *priv, enum v4l2_buf_type type) -{ - struct vpe_ctx *ctx = file2ctx(file); - - return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); -} - -static int vpe_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) -{ - struct vpe_ctx *ctx = file2ctx(file); - - vpe_dump_regs(ctx->dev); - vpdma_dump_regs(ctx->dev->vpdma); - - return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); -} - /* * defines number of buffers/frames a context can process with VPE before * switching to a different context. default value is 1 buffer per context @@ -1814,14 +1768,14 @@ static const struct v4l2_ctrl_ops vpe_ctrl_ops = { }; static const struct v4l2_ioctl_ops vpe_ioctl_ops = { - .vidioc_querycap = vpe_querycap, + .vidioc_querycap = vpe_querycap, - .vidioc_enum_fmt_vid_cap_mplane = vpe_enum_fmt, + .vidioc_enum_fmt_vid_cap_mplane = vpe_enum_fmt, .vidioc_g_fmt_vid_cap_mplane = vpe_g_fmt, .vidioc_try_fmt_vid_cap_mplane = vpe_try_fmt, .vidioc_s_fmt_vid_cap_mplane = vpe_s_fmt, - .vidioc_enum_fmt_vid_out_mplane = vpe_enum_fmt, + .vidioc_enum_fmt_vid_out_mplane = vpe_enum_fmt, .vidioc_g_fmt_vid_out_mplane = vpe_g_fmt, .vidioc_try_fmt_vid_out_mplane = vpe_try_fmt, .vidioc_s_fmt_vid_out_mplane = vpe_s_fmt, @@ -1829,16 +1783,15 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = { .vidioc_g_selection = vpe_g_selection, .vidioc_s_selection = vpe_s_selection, - .vidioc_reqbufs = vpe_reqbufs, - .vidioc_querybuf = vpe_querybuf, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, - .vidioc_qbuf = vpe_qbuf, - .vidioc_dqbuf = vpe_dqbuf, - - .vidioc_streamon = vpe_streamon, - .vidioc_streamoff = vpe_streamoff, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; /* @@ -1910,33 +1863,40 @@ static int vpe_buf_prepare(struct vb2_buffer *vb) static void vpe_buf_queue(struct vb2_buffer *vb) { struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); } -static void vpe_wait_prepare(struct vb2_queue *q) +static int vpe_start_streaming(struct vb2_queue *q, unsigned int count) { - struct vpe_ctx *ctx = vb2_get_drv_priv(q); - vpe_unlock(ctx); + /* currently we do nothing here */ + + return 0; } -static void vpe_wait_finish(struct vb2_queue *q) +static void vpe_stop_streaming(struct vb2_queue *q) { struct vpe_ctx *ctx = vb2_get_drv_priv(q); - vpe_lock(ctx); + + vpe_dump_regs(ctx->dev); + vpdma_dump_regs(ctx->dev->vpdma); } static struct vb2_ops vpe_qops = { .queue_setup = vpe_queue_setup, .buf_prepare = vpe_buf_prepare, .buf_queue = vpe_buf_queue, - .wait_prepare = vpe_wait_prepare, - .wait_finish = vpe_wait_finish, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = vpe_start_streaming, + .stop_streaming = vpe_stop_streaming, }; static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) { struct vpe_ctx *ctx = priv; + struct vpe_dev *dev = ctx->dev; int ret; memset(src_vq, 0, sizeof(*src_vq)); @@ -1947,6 +1907,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->ops = &vpe_qops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &dev->dev_mutex; ret = vb2_queue_init(src_vq); if (ret) @@ -1960,6 +1921,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->ops = &vpe_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &dev->dev_mutex; return vb2_queue_init(dst_vq); } @@ -1981,9 +1943,9 @@ static const struct v4l2_ctrl_config vpe_bufs_per_job = { static int vpe_open(struct file *file) { struct vpe_dev *dev = video_drvdata(file); - struct vpe_ctx *ctx = NULL; struct vpe_q_data *s_q_data; struct v4l2_ctrl_handler *hdl; + struct vpe_ctx *ctx; int ret; vpe_dbg(dev, "vpe_open\n"); @@ -2056,10 +2018,10 @@ static int vpe_open(struct file *file) if (ret) goto exit_fh; - ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); - if (IS_ERR(ctx->m2m_ctx)) { - ret = PTR_ERR(ctx->m2m_ctx); + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); goto exit_fh; } @@ -2078,7 +2040,7 @@ static int vpe_open(struct file *file) ctx->load_mmrs = true; vpe_dbg(dev, "created instance %p, m2m_ctx: %p\n", - ctx, ctx->m2m_ctx); + ctx, ctx->fh.m2m_ctx); mutex_unlock(&dev->dev_mutex); @@ -2116,7 +2078,7 @@ static int vpe_release(struct file *file) v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); - v4l2_m2m_ctx_release(ctx->m2m_ctx); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); kfree(ctx); @@ -2133,39 +2095,13 @@ static int vpe_release(struct file *file) return 0; } -static unsigned int vpe_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct vpe_ctx *ctx = file2ctx(file); - struct vpe_dev *dev = ctx->dev; - int ret; - - mutex_lock(&dev->dev_mutex); - ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); - mutex_unlock(&dev->dev_mutex); - return ret; -} - -static int vpe_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct vpe_ctx *ctx = file2ctx(file); - struct vpe_dev *dev = ctx->dev; - int ret; - - if (mutex_lock_interruptible(&dev->dev_mutex)) - return -ERESTARTSYS; - ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); - mutex_unlock(&dev->dev_mutex); - return ret; -} - static const struct v4l2_file_operations vpe_fops = { .owner = THIS_MODULE, .open = vpe_open, .release = vpe_release, - .poll = vpe_poll, + .poll = v4l2_m2m_fop_poll, .unlocked_ioctl = video_ioctl2, - .mmap = vpe_mmap, + .mmap = v4l2_m2m_fop_mmap, }; static struct video_device vpe_videodev = { @@ -2367,8 +2303,6 @@ static const struct of_device_id vpe_of_match[] = { }, {}, }; -#else -#define vpe_of_match NULL #endif static struct platform_driver vpe_pdrv = { @@ -2376,7 +2310,7 @@ static struct platform_driver vpe_pdrv = { .remove = vpe_remove, .driver = { .name = VPE_MODULE_NAME, - .of_match_table = vpe_of_match, + .of_match_table = of_match_ptr(vpe_of_match), }, }; diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index 857e7866e8bc..32a798f2d953 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -689,7 +689,7 @@ static const struct v4l2_ctrl_config vivid_ctrl_max_edid_blocks = { static const char * const vivid_ctrl_colorspace_strings[] = { "SMPTE 170M", - "REC 709", + "Rec. 709", "sRGB", "AdobeRGB", "BT.2020", @@ -716,7 +716,7 @@ static const char * const vivid_ctrl_ycbcr_enc_strings[] = { "xvYCC 601", "xvYCC 709", "sYCC", - "BT.2020 Non-Constant Luminance", + "BT.2020", "BT.2020 Constant Luminance", "SMPTE 240M", NULL, diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index fc9c6536ba02..34493f435d5a 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -352,13 +352,14 @@ static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b, { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) }, }; bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE; + unsigned y_offset = full ? 0 : 16; int lin_y, yc; switch (tpg->real_ycbcr_enc) { case V4L2_YCBCR_ENC_601: case V4L2_YCBCR_ENC_XV601: case V4L2_YCBCR_ENC_SYCC: - rgb2ycbcr(full ? bt601_full : bt601, r, g, b, 16, y, cb, cr); + rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr); break; case V4L2_YCBCR_ENC_BT2020: rgb2ycbcr(bt2020, r, g, b, 16, y, cb, cr); @@ -384,7 +385,7 @@ static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b, case V4L2_YCBCR_ENC_709: case V4L2_YCBCR_ENC_XV709: default: - rgb2ycbcr(full ? rec709_full : rec709, r, g, b, 0, y, cb, cr); + rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr); break; } } @@ -439,13 +440,14 @@ static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr, { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) }, }; bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE; + unsigned y_offset = full ? 0 : 16; int lin_r, lin_g, lin_b, lin_y; switch (tpg->real_ycbcr_enc) { case V4L2_YCBCR_ENC_601: case V4L2_YCBCR_ENC_XV601: case V4L2_YCBCR_ENC_SYCC: - ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, 16, r, g, b); + ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b); break; case V4L2_YCBCR_ENC_BT2020: ycbcr2rgb(bt2020, y, cb, cr, 16, r, g, b); @@ -480,7 +482,7 @@ static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr, case V4L2_YCBCR_ENC_709: case V4L2_YCBCR_ENC_XV709: default: - ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, 16, r, g, b); + ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b); break; } } diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h index 9dc463a40ed3..bd8b1c760b3f 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/drivers/media/platform/vivid/vivid-tpg.h @@ -20,7 +20,6 @@ #ifndef _VIVID_TPG_H_ #define _VIVID_TPG_H_ -#include #include #include #include diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 12467191dff4..989e96f7e360 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -40,9 +39,20 @@ struct vsp1_uds; #define VSP1_MAX_UDS 3 #define VSP1_MAX_WPF 4 +#define VSP1_HAS_LIF (1 << 0) +#define VSP1_HAS_LUT (1 << 1) +#define VSP1_HAS_SRU (1 << 2) + +struct vsp1_platform_data { + unsigned int features; + unsigned int rpf_count; + unsigned int uds_count; + unsigned int wpf_count; +}; + struct vsp1_device { struct device *dev; - struct vsp1_platform_data *pdata; + struct vsp1_platform_data pdata; void __iomem *mmio; struct clk *clock; diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c index b21f381a9862..401e2b77a0b6 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.c +++ b/drivers/media/platform/vsp1/vsp1_bru.c @@ -20,7 +20,7 @@ #include "vsp1_bru.h" #include "vsp1_rwpf.h" -#define BRU_MIN_SIZE 4U +#define BRU_MIN_SIZE 1U #define BRU_MAX_SIZE 8190U /* ----------------------------------------------------------------------------- diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 5eb16e87d53f..913485a90e97 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -40,7 +40,7 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data) irqreturn_t ret = IRQ_NONE; unsigned int i; - for (i = 0; i < vsp1->pdata->wpf_count; ++i) { + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { struct vsp1_rwpf *wpf = vsp1->wpf[i]; struct vsp1_pipeline *pipe; u32 status; @@ -181,7 +181,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities); - if (vsp1->pdata->features & VSP1_HAS_LIF) { + if (vsp1->pdata.features & VSP1_HAS_LIF) { vsp1->lif = vsp1_lif_create(vsp1); if (IS_ERR(vsp1->lif)) { ret = PTR_ERR(vsp1->lif); @@ -191,7 +191,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities); } - if (vsp1->pdata->features & VSP1_HAS_LUT) { + if (vsp1->pdata.features & VSP1_HAS_LUT) { vsp1->lut = vsp1_lut_create(vsp1); if (IS_ERR(vsp1->lut)) { ret = PTR_ERR(vsp1->lut); @@ -201,7 +201,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities); } - for (i = 0; i < vsp1->pdata->rpf_count; ++i) { + for (i = 0; i < vsp1->pdata.rpf_count; ++i) { struct vsp1_rwpf *rpf; rpf = vsp1_rpf_create(vsp1, i); @@ -214,7 +214,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&rpf->entity.list_dev, &vsp1->entities); } - if (vsp1->pdata->features & VSP1_HAS_SRU) { + if (vsp1->pdata.features & VSP1_HAS_SRU) { vsp1->sru = vsp1_sru_create(vsp1); if (IS_ERR(vsp1->sru)) { ret = PTR_ERR(vsp1->sru); @@ -224,7 +224,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities); } - for (i = 0; i < vsp1->pdata->uds_count; ++i) { + for (i = 0; i < vsp1->pdata.uds_count; ++i) { struct vsp1_uds *uds; uds = vsp1_uds_create(vsp1, i); @@ -237,7 +237,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&uds->entity.list_dev, &vsp1->entities); } - for (i = 0; i < vsp1->pdata->wpf_count; ++i) { + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { struct vsp1_rwpf *wpf; wpf = vsp1_wpf_create(vsp1, i); @@ -261,7 +261,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) goto done; } - if (vsp1->pdata->features & VSP1_HAS_LIF) { + if (vsp1->pdata.features & VSP1_HAS_LIF) { ret = media_entity_create_link( &vsp1->wpf[0]->entity.subdev.entity, RWPF_PAD_SOURCE, &vsp1->lif->entity.subdev.entity, LIF_PAD_SINK, 0); @@ -294,7 +294,7 @@ static int vsp1_device_init(struct vsp1_device *vsp1) /* Reset any channel that might be running. */ status = vsp1_read(vsp1, VI6_STATUS); - for (i = 0; i < vsp1->pdata->wpf_count; ++i) { + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { unsigned int timeout; if (!(status & VI6_STATUS_SYS_ACT(i))) @@ -318,10 +318,10 @@ static int vsp1_device_init(struct vsp1_device *vsp1) vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) | (8 << VI6_CLK_DCSWT_CSTRW_SHIFT)); - for (i = 0; i < vsp1->pdata->rpf_count; ++i) + for (i = 0; i < vsp1->pdata.rpf_count; ++i) vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED); - for (i = 0; i < vsp1->pdata->uds_count; ++i) + for (i = 0; i < vsp1->pdata.uds_count; ++i) vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED); vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED); @@ -428,47 +428,10 @@ static const struct dev_pm_ops vsp1_pm_ops = { * Platform Driver */ -static int vsp1_validate_platform_data(struct platform_device *pdev, - struct vsp1_platform_data *pdata) +static int vsp1_parse_dt(struct vsp1_device *vsp1) { - if (pdata == NULL) { - dev_err(&pdev->dev, "missing platform data\n"); - return -EINVAL; - } - - if (pdata->rpf_count <= 0 || pdata->rpf_count > VSP1_MAX_RPF) { - dev_err(&pdev->dev, "invalid number of RPF (%u)\n", - pdata->rpf_count); - return -EINVAL; - } - - if (pdata->uds_count <= 0 || pdata->uds_count > VSP1_MAX_UDS) { - dev_err(&pdev->dev, "invalid number of UDS (%u)\n", - pdata->uds_count); - return -EINVAL; - } - - if (pdata->wpf_count <= 0 || pdata->wpf_count > VSP1_MAX_WPF) { - dev_err(&pdev->dev, "invalid number of WPF (%u)\n", - pdata->wpf_count); - return -EINVAL; - } - - return 0; -} - -static struct vsp1_platform_data * -vsp1_get_platform_data(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct vsp1_platform_data *pdata; - - if (!IS_ENABLED(CONFIG_OF) || np == NULL) - return pdev->dev.platform_data; - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (pdata == NULL) - return NULL; + struct device_node *np = vsp1->dev->of_node; + struct vsp1_platform_data *pdata = &vsp1->pdata; if (of_property_read_bool(np, "renesas,has-lif")) pdata->features |= VSP1_HAS_LIF; @@ -481,7 +444,25 @@ vsp1_get_platform_data(struct platform_device *pdev) of_property_read_u32(np, "renesas,#uds", &pdata->uds_count); of_property_read_u32(np, "renesas,#wpf", &pdata->wpf_count); - return pdata; + if (pdata->rpf_count <= 0 || pdata->rpf_count > VSP1_MAX_RPF) { + dev_err(vsp1->dev, "invalid number of RPF (%u)\n", + pdata->rpf_count); + return -EINVAL; + } + + if (pdata->uds_count <= 0 || pdata->uds_count > VSP1_MAX_UDS) { + dev_err(vsp1->dev, "invalid number of UDS (%u)\n", + pdata->uds_count); + return -EINVAL; + } + + if (pdata->wpf_count <= 0 || pdata->wpf_count > VSP1_MAX_WPF) { + dev_err(vsp1->dev, "invalid number of WPF (%u)\n", + pdata->wpf_count); + return -EINVAL; + } + + return 0; } static int vsp1_probe(struct platform_device *pdev) @@ -499,11 +480,7 @@ static int vsp1_probe(struct platform_device *pdev) mutex_init(&vsp1->lock); INIT_LIST_HEAD(&vsp1->entities); - vsp1->pdata = vsp1_get_platform_data(pdev); - if (vsp1->pdata == NULL) - return -ENODEV; - - ret = vsp1_validate_platform_data(pdev, vsp1->pdata); + ret = vsp1_parse_dt(vsp1); if (ret < 0) return ret; diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index 80bedc554ee3..0bc0471746c9 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c @@ -26,11 +26,6 @@ * Device Access */ -static inline u32 vsp1_hsit_read(struct vsp1_hsit *hsit, u32 reg) -{ - return vsp1_read(hsit->entity.vsp1, reg); -} - static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data) { vsp1_write(hsit->entity.vsp1, reg, data); diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 55f163d32d15..da3c573e1efc 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -43,12 +43,12 @@ #define VI6_DISP_IRQ_ENB 0x0078 #define VI6_DISP_IRQ_ENB_DSTE (1 << 8) #define VI6_DISP_IRQ_ENB_MAEE (1 << 5) -#define VI6_DISP_IRQ_ENB_LNEE(n) (1 << ((n) + 4)) +#define VI6_DISP_IRQ_ENB_LNEE(n) (1 << (n)) #define VI6_DISP_IRQ_STA 0x007c #define VI6_DISP_IRQ_STA_DSE (1 << 8) #define VI6_DISP_IRQ_STA_MAE (1 << 5) -#define VI6_DISP_IRQ_STA_LNE(n) (1 << ((n) + 4)) +#define VI6_DISP_IRQ_STA_LNE(n) (1 << (n)) #define VI6_WPF_LINE_COUNT(n) (0x0084 + (n) * 4) #define VI6_WPF_LINE_COUNT_MASK (0x1fffff << 0) diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index d14d26b718ef..3294529a3108 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -106,11 +106,22 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable) + crop->left * fmtinfo->bpp[0] / 8; pstride = format->plane_fmt[0].bytesperline << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT; + + vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y, + rpf->buf_addr[0] + rpf->offsets[0]); + if (format->num_planes > 1) { rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline + crop->left * fmtinfo->bpp[1] / 8; pstride |= format->plane_fmt[1].bytesperline << VI6_RPF_SRCM_PSTRIDE_C_SHIFT; + + vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0, + rpf->buf_addr[1] + rpf->offsets[1]); + + if (format->num_planes > 2) + vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1, + rpf->buf_addr[2] + rpf->offsets[1]); } vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride); @@ -179,6 +190,13 @@ static void rpf_vdev_queue(struct vsp1_video *video, struct vsp1_video_buffer *buf) { struct vsp1_rwpf *rpf = container_of(video, struct vsp1_rwpf, video); + unsigned int i; + + for (i = 0; i < 3; ++i) + rpf->buf_addr[i] = buf->addr[i]; + + if (!vsp1_entity_is_streaming(&rpf->entity)) + return; vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y, buf->addr[0] + rpf->offsets[0]); diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index 28dd9e7b3838..2cf1f13d3bf9 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h @@ -39,6 +39,7 @@ struct vsp1_rwpf { struct v4l2_rect crop; unsigned int offsets[2]; + dma_addr_t buf_addr[3]; }; static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev) diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 6e057762c933..1d2b3a2f1573 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -92,19 +92,20 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) return 0; } - /* Sources. If the pipeline has a single input configure it as the - * master layer. Otherwise configure all inputs as sub-layers and - * select the virtual RPF as the master layer. + /* Sources. If the pipeline has a single input and BRU is not used, + * configure it as the master layer. Otherwise configure all + * inputs as sub-layers and select the virtual RPF as the master + * layer. */ for (i = 0; i < pipe->num_inputs; ++i) { struct vsp1_rwpf *input = pipe->inputs[i]; - srcrpf |= pipe->num_inputs == 1 + srcrpf |= (!pipe->bru && pipe->num_inputs == 1) ? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index) : VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index); } - if (pipe->num_inputs > 1) + if (pipe->bru || pipe->num_inputs > 1) srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST; vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf); @@ -280,7 +281,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) * except for the WPF0 source link if a LIF is present. */ flags = MEDIA_LNK_FL_ENABLED; - if (!(vsp1->pdata->features & VSP1_HAS_LIF) || index != 0) + if (!(vsp1->pdata.features & VSP1_HAS_LIF) || index != 0) flags |= MEDIA_LNK_FL_IMMUTABLE; ret = media_entity_create_link(&wpf->entity.subdev.entity, diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index a739ad492e7b..ea9308796741 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -129,11 +129,11 @@ static int rtrack_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) } else if (curvol < vol) { outb(0x98, isa->io); /* volume up + sigstr + on */ for (; curvol < vol; curvol++) - udelay(3000); + mdelay(3); } else if (curvol > vol) { outb(0x58, isa->io); /* volume down + sigstr + on */ for (; curvol > vol; curvol--) - udelay(3000); + mdelay(3); } outb(0xd8, isa->io); /* volume steady + sigstr + on */ rt->curvol = vol; diff --git a/drivers/media/radio/tea575x.c b/drivers/media/radio/tea575x.c index f1a0867789fe..43d1ea53cb66 100644 --- a/drivers/media/radio/tea575x.c +++ b/drivers/media/radio/tea575x.c @@ -247,10 +247,9 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_enum_freq_bands(struct file *file, void *priv, - struct v4l2_frequency_band *band) +int snd_tea575x_enum_freq_bands(struct snd_tea575x *tea, + struct v4l2_frequency_band *band) { - struct snd_tea575x *tea = video_drvdata(file); int index; if (band->tuner != 0) @@ -279,18 +278,25 @@ static int vidioc_enum_freq_bands(struct file *file, void *priv, return 0; } +EXPORT_SYMBOL(snd_tea575x_enum_freq_bands); -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) +static int vidioc_enum_freq_bands(struct file *file, void *priv, + struct v4l2_frequency_band *band) { struct snd_tea575x *tea = video_drvdata(file); + + return snd_tea575x_enum_freq_bands(tea, band); +} + +int snd_tea575x_g_tuner(struct snd_tea575x *tea, struct v4l2_tuner *v) +{ struct v4l2_frequency_band band_fm = { 0, }; if (v->index > 0) return -EINVAL; snd_tea575x_read(tea); - vidioc_enum_freq_bands(file, priv, &band_fm); + snd_tea575x_enum_freq_bands(tea, &band_fm); memset(v, 0, sizeof(*v)); strlcpy(v->name, tea->has_am ? "FM/AM" : "FM", sizeof(v->name)); @@ -304,6 +310,15 @@ static int vidioc_g_tuner(struct file *file, void *priv, v->signal = tea->tuned ? 0xffff : 0; return 0; } +EXPORT_SYMBOL(snd_tea575x_g_tuner); + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct snd_tea575x *tea = video_drvdata(file); + + return snd_tea575x_g_tuner(tea, v); +} static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *v) @@ -356,10 +371,9 @@ static int vidioc_s_frequency(struct file *file, void *priv, return 0; } -static int vidioc_s_hw_freq_seek(struct file *file, void *fh, - const struct v4l2_hw_freq_seek *a) +int snd_tea575x_s_hw_freq_seek(struct file *file, struct snd_tea575x *tea, + const struct v4l2_hw_freq_seek *a) { - struct snd_tea575x *tea = video_drvdata(file); unsigned long timeout; int i, spacing; @@ -442,6 +456,15 @@ static int vidioc_s_hw_freq_seek(struct file *file, void *fh, snd_tea575x_set_freq(tea); return -ENODATA; } +EXPORT_SYMBOL(snd_tea575x_s_hw_freq_seek); + +static int vidioc_s_hw_freq_seek(struct file *file, void *fh, + const struct v4l2_hw_freq_seek *a) +{ + struct snd_tea575x *tea = video_drvdata(file); + + return snd_tea575x_s_hw_freq_seek(file, tea, a); +} static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl) { diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c index 09632cb26cb6..cfaeb2417fbb 100644 --- a/drivers/media/radio/wl128x/fmdrv_rx.c +++ b/drivers/media/radio/wl128x/fmdrv_rx.c @@ -785,22 +785,6 @@ int fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) return 0; } -/* Returns current RDS operation mode */ -int fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode) -{ - if (fmdev->curr_fmmode != FM_MODE_RX) - return -EPERM; - - if (rds_mode == NULL) { - fmerr("Invalid memory\n"); - return -ENOMEM; - } - - *rds_mode = fmdev->rx.rds_mode; - - return 0; -} - /* Configures Alternate Frequency switch mode */ int fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) { diff --git a/drivers/media/radio/wl128x/fmdrv_rx.h b/drivers/media/radio/wl128x/fmdrv_rx.h index 32add81f8d87..23922188882f 100644 --- a/drivers/media/radio/wl128x/fmdrv_rx.h +++ b/drivers/media/radio/wl128x/fmdrv_rx.h @@ -40,7 +40,6 @@ void fm_rx_reset_station_info(struct fmdev *); int fm_rx_seek(struct fmdev *, u32, u32, u32); int fm_rx_get_rds_mode(struct fmdev *, u8 *); -int fm_rx_get_rds_system(struct fmdev *, u8 *); int fm_rx_get_mute_mode(struct fmdev *, u8 *); int fm_rx_get_volume(struct fmdev *, u16 *); int fm_rx_get_band_freq_range(struct fmdev *, diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig index 580715c7fc5e..a896d3c83a1c 100644 --- a/drivers/media/rc/img-ir/Kconfig +++ b/drivers/media/rc/img-ir/Kconfig @@ -60,3 +60,18 @@ config IR_IMG_SANYO help Say Y here to enable support for the Sanyo protocol (used by Sanyo, Aiwa, Chinon remotes) in the ImgTec infrared decoder block. + +config IR_IMG_RC5 + bool "Philips RC5 protocol support" + depends on IR_IMG_HW + help + Say Y here to enable support for the RC5 protocol in the ImgTec + infrared decoder block. + +config IR_IMG_RC6 + bool "Philips RC6 protocol support" + depends on IR_IMG_HW + help + Say Y here to enable support for the RC6 protocol in the ImgTec + infrared decoder block. + Note: This version only supports mode 0. diff --git a/drivers/media/rc/img-ir/Makefile b/drivers/media/rc/img-ir/Makefile index 92a459d99509..8e6d458e66ad 100644 --- a/drivers/media/rc/img-ir/Makefile +++ b/drivers/media/rc/img-ir/Makefile @@ -6,6 +6,8 @@ img-ir-$(CONFIG_IR_IMG_JVC) += img-ir-jvc.o img-ir-$(CONFIG_IR_IMG_SONY) += img-ir-sony.o img-ir-$(CONFIG_IR_IMG_SHARP) += img-ir-sharp.o img-ir-$(CONFIG_IR_IMG_SANYO) += img-ir-sanyo.o +img-ir-$(CONFIG_IR_IMG_RC5) += img-ir-rc5.o +img-ir-$(CONFIG_IR_IMG_RC6) += img-ir-rc6.o img-ir-objs := $(img-ir-y) obj-$(CONFIG_IR_IMG) += img-ir.o diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 2fd47c9bf5d8..7bb71bc9f534 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -41,6 +41,12 @@ static struct img_ir_decoder *img_ir_decoders[] = { #endif #ifdef CONFIG_IR_IMG_SANYO &img_ir_sanyo, +#endif +#ifdef CONFIG_IR_IMG_RC5 + &img_ir_rc5, +#endif +#ifdef CONFIG_IR_IMG_RC6 + &img_ir_rc6, #endif NULL }; @@ -52,6 +58,11 @@ static struct img_ir_decoder *img_ir_decoders[] = { #define IMG_IR_QUIRK_CODE_BROKEN 0x1 /* Decode is broken */ #define IMG_IR_QUIRK_CODE_LEN_INCR 0x2 /* Bit length needs increment */ +/* + * The decoder generates rapid interrupts without actually having + * received any new data after an incomplete IR code is decoded. + */ +#define IMG_IR_QUIRK_CODE_IRQ 0x4 /* functions for preprocessing timings, ensuring max is set */ @@ -542,6 +553,7 @@ static void img_ir_set_decoder(struct img_ir_priv *priv, */ spin_unlock_irq(&priv->lock); del_timer_sync(&hw->end_timer); + del_timer_sync(&hw->suspend_timer); spin_lock_irq(&priv->lock); hw->stopping = false; @@ -806,20 +818,24 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw) struct img_ir_priv_hw *hw = &priv->hw; const struct img_ir_decoder *dec = hw->decoder; int ret = IMG_IR_SCANCODE; - u32 scancode; - enum rc_type protocol = RC_TYPE_UNKNOWN; + struct img_ir_scancode_req request; + + request.protocol = RC_TYPE_UNKNOWN; + request.toggle = 0; if (dec->scancode) - ret = dec->scancode(len, raw, &protocol, &scancode, hw->enabled_protocols); + ret = dec->scancode(len, raw, hw->enabled_protocols, &request); else if (len >= 32) - scancode = (u32)raw; + request.scancode = (u32)raw; else if (len < 32) - scancode = (u32)raw & ((1 << len)-1); + request.scancode = (u32)raw & ((1 << len)-1); dev_dbg(priv->dev, "data (%u bits) = %#llx\n", len, (unsigned long long)raw); if (ret == IMG_IR_SCANCODE) { - dev_dbg(priv->dev, "decoded scan code %#x\n", scancode); - rc_keydown(hw->rdev, protocol, scancode, 0); + dev_dbg(priv->dev, "decoded scan code %#x, toggle %u\n", + request.scancode, request.toggle); + rc_keydown(hw->rdev, request.protocol, request.scancode, + request.toggle); img_ir_end_repeat(priv); } else if (ret == IMG_IR_REPEATCODE) { if (hw->mode == IMG_IR_M_REPEATING) { @@ -857,6 +873,29 @@ static void img_ir_end_timer(unsigned long arg) spin_unlock_irq(&priv->lock); } +/* + * Timer function to re-enable the current protocol after it had been + * cleared when invalid interrupts were generated due to a quirk in the + * img-ir decoder. + */ +static void img_ir_suspend_timer(unsigned long arg) +{ + struct img_ir_priv *priv = (struct img_ir_priv *)arg; + + spin_lock_irq(&priv->lock); + /* + * Don't overwrite enabled valid/match IRQs if they have already been + * changed by e.g. a filter change. + */ + if ((priv->hw.quirk_suspend_irq & IMG_IR_IRQ_EDGE) == + img_ir_read(priv, IMG_IR_IRQ_ENABLE)) + img_ir_write(priv, IMG_IR_IRQ_ENABLE, + priv->hw.quirk_suspend_irq); + /* enable */ + img_ir_write(priv, IMG_IR_CONTROL, priv->hw.reg_timings.ctrl); + spin_unlock_irq(&priv->lock); +} + #ifdef CONFIG_COMMON_CLK static void img_ir_change_frequency(struct img_ir_priv *priv, struct clk_notifier_data *change) @@ -922,15 +961,38 @@ void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status) if (!hw->decoder) return; + ct = hw->decoder->control.code_type; + ir_status = img_ir_read(priv, IMG_IR_STATUS); - if (!(ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2))) + if (!(ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2))) { + if (!(priv->hw.ct_quirks[ct] & IMG_IR_QUIRK_CODE_IRQ) || + hw->stopping) + return; + /* + * The below functionality is added as a work around to stop + * multiple Interrupts generated when an incomplete IR code is + * received by the decoder. + * The decoder generates rapid interrupts without actually + * having received any new data. After a single interrupt it's + * expected to clear up, but instead multiple interrupts are + * rapidly generated. only way to get out of this loop is to + * reset the control register after a short delay. + */ + img_ir_write(priv, IMG_IR_CONTROL, 0); + hw->quirk_suspend_irq = img_ir_read(priv, IMG_IR_IRQ_ENABLE); + img_ir_write(priv, IMG_IR_IRQ_ENABLE, + hw->quirk_suspend_irq & IMG_IR_IRQ_EDGE); + + /* Timer activated to re-enable the protocol. */ + mod_timer(&hw->suspend_timer, + jiffies + msecs_to_jiffies(5)); return; + } ir_status &= ~(IMG_IR_RXDVAL | IMG_IR_RXDVALD2); img_ir_write(priv, IMG_IR_STATUS, ir_status); len = (ir_status & IMG_IR_RXDLEN) >> IMG_IR_RXDLEN_SHIFT; /* some versions report wrong length for certain code types */ - ct = hw->decoder->control.code_type; if (hw->ct_quirks[ct] & IMG_IR_QUIRK_CODE_LEN_INCR) ++len; @@ -972,7 +1034,7 @@ static void img_ir_probe_hw_caps(struct img_ir_priv *priv) hw->ct_quirks[IMG_IR_CODETYPE_PULSELEN] |= IMG_IR_QUIRK_CODE_LEN_INCR; hw->ct_quirks[IMG_IR_CODETYPE_BIPHASE] - |= IMG_IR_QUIRK_CODE_BROKEN; + |= IMG_IR_QUIRK_CODE_IRQ; hw->ct_quirks[IMG_IR_CODETYPE_2BITPULSEPOS] |= IMG_IR_QUIRK_CODE_BROKEN; } @@ -991,6 +1053,8 @@ int img_ir_probe_hw(struct img_ir_priv *priv) /* Set up the end timer */ setup_timer(&hw->end_timer, img_ir_end_timer, (unsigned long)priv); + setup_timer(&hw->suspend_timer, img_ir_suspend_timer, + (unsigned long)priv); /* Register a clock notifier */ if (!IS_ERR(priv->clk)) { diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h index 5c2b216c5fe3..91a297731661 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.h +++ b/drivers/media/rc/img-ir/img-ir-hw.h @@ -132,6 +132,20 @@ struct img_ir_timing_regvals { #define IMG_IR_SCANCODE 0 /* new scancode */ #define IMG_IR_REPEATCODE 1 /* repeat the previous code */ +/** + * struct img_ir_scancode_req - Scancode request data. + * @protocol: Protocol code of received message (defaults to + * RC_TYPE_UNKNOWN). + * @scancode: Scan code of received message (must be written by + * handler if IMG_IR_SCANCODE is returned). + * @toggle: Toggle bit (defaults to 0). + */ +struct img_ir_scancode_req { + enum rc_type protocol; + u32 scancode; + u8 toggle; +}; + /** * struct img_ir_decoder - Decoder settings for an IR protocol. * @type: Protocol types bitmap. @@ -162,8 +176,8 @@ struct img_ir_decoder { struct img_ir_control control; /* scancode logic */ - int (*scancode)(int len, u64 raw, enum rc_type *protocol, - u32 *scancode, u64 enabled_protocols); + int (*scancode)(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request); int (*filter)(const struct rc_scancode_filter *in, struct img_ir_filter *out, u64 protocols); }; @@ -173,6 +187,8 @@ extern struct img_ir_decoder img_ir_jvc; extern struct img_ir_decoder img_ir_sony; extern struct img_ir_decoder img_ir_sharp; extern struct img_ir_decoder img_ir_sanyo; +extern struct img_ir_decoder img_ir_rc5; +extern struct img_ir_decoder img_ir_rc6; /** * struct img_ir_reg_timings - Reg values for decoder timings at clock rate. @@ -204,6 +220,7 @@ enum img_ir_mode { * @rdev: Remote control device * @clk_nb: Notifier block for clock notify events. * @end_timer: Timer until repeat timeout. + * @suspend_timer: Timer to re-enable protocol. * @decoder: Current decoder settings. * @enabled_protocols: Currently enabled protocols. * @clk_hz: Current core clock rate in Hz. @@ -214,12 +231,14 @@ enum img_ir_mode { * @stopping: Indicates that decoder is being taken down and timers * should not be restarted. * @suspend_irqen: Saved IRQ enable mask over suspend. + * @quirk_suspend_irq: Saved IRQ enable mask over quirk suspend timer. */ struct img_ir_priv_hw { unsigned int ct_quirks[4]; struct rc_dev *rdev; struct notifier_block clk_nb; struct timer_list end_timer; + struct timer_list suspend_timer; const struct img_ir_decoder *decoder; u64 enabled_protocols; unsigned long clk_hz; @@ -230,6 +249,7 @@ struct img_ir_priv_hw { enum img_ir_mode mode; bool stopping; u32 suspend_irqen; + u32 quirk_suspend_irq; }; static inline bool img_ir_hw_enabled(struct img_ir_priv_hw *hw) diff --git a/drivers/media/rc/img-ir/img-ir-jvc.c b/drivers/media/rc/img-ir/img-ir-jvc.c index a60dda8bf706..d3e2fc0bcfe1 100644 --- a/drivers/media/rc/img-ir/img-ir-jvc.c +++ b/drivers/media/rc/img-ir/img-ir-jvc.c @@ -12,8 +12,8 @@ #include "img-ir-hw.h" /* Convert JVC data to a scancode */ -static int img_ir_jvc_scancode(int len, u64 raw, enum rc_type *protocol, - u32 *scancode, u64 enabled_protocols) +static int img_ir_jvc_scancode(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request) { unsigned int cust, data; @@ -23,8 +23,8 @@ static int img_ir_jvc_scancode(int len, u64 raw, enum rc_type *protocol, cust = (raw >> 0) & 0xff; data = (raw >> 8) & 0xff; - *protocol = RC_TYPE_JVC; - *scancode = cust << 8 | data; + request->protocol = RC_TYPE_JVC; + request->scancode = cust << 8 | data; return IMG_IR_SCANCODE; } diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c index 739897549b5b..27a7ea8f1260 100644 --- a/drivers/media/rc/img-ir/img-ir-nec.c +++ b/drivers/media/rc/img-ir/img-ir-nec.c @@ -13,8 +13,8 @@ #include /* Convert NEC data to a scancode */ -static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol, - u32 *scancode, u64 enabled_protocols) +static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request) { unsigned int addr, addr_inv, data, data_inv; /* a repeat code has no data */ @@ -30,23 +30,23 @@ static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol, if ((data_inv ^ data) != 0xff) { /* 32-bit NEC (used by Apple and TiVo remotes) */ /* scan encoding: as transmitted, MSBit = first received bit */ - *scancode = bitrev8(addr) << 24 | - bitrev8(addr_inv) << 16 | - bitrev8(data) << 8 | - bitrev8(data_inv); + request->scancode = bitrev8(addr) << 24 | + bitrev8(addr_inv) << 16 | + bitrev8(data) << 8 | + bitrev8(data_inv); } else if ((addr_inv ^ addr) != 0xff) { /* Extended NEC */ /* scan encoding: AAaaDD */ - *scancode = addr << 16 | - addr_inv << 8 | - data; + request->scancode = addr << 16 | + addr_inv << 8 | + data; } else { /* Normal NEC */ /* scan encoding: AADD */ - *scancode = addr << 8 | - data; + request->scancode = addr << 8 | + data; } - *protocol = RC_TYPE_NEC; + request->protocol = RC_TYPE_NEC; return IMG_IR_SCANCODE; } diff --git a/drivers/media/rc/img-ir/img-ir-rc5.c b/drivers/media/rc/img-ir/img-ir-rc5.c new file mode 100644 index 000000000000..a8a28a377eee --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-rc5.c @@ -0,0 +1,88 @@ +/* + * ImgTec IR Decoder setup for Philips RC-5 protocol. + * + * Copyright 2012-2014 Imagination Technologies Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include "img-ir-hw.h" + +/* Convert RC5 data to a scancode */ +static int img_ir_rc5_scancode(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request) +{ + unsigned int addr, cmd, tgl, start; + + /* Quirk in the decoder shifts everything by 2 to the left. */ + raw >>= 2; + + start = (raw >> 13) & 0x01; + tgl = (raw >> 11) & 0x01; + addr = (raw >> 6) & 0x1f; + cmd = raw & 0x3f; + /* + * 12th bit is used to extend the command in extended RC5 and has + * no effect on standard RC5. + */ + cmd += ((raw >> 12) & 0x01) ? 0 : 0x40; + + if (!start) + return -EINVAL; + + request->protocol = RC_TYPE_RC5; + request->scancode = addr << 8 | cmd; + request->toggle = tgl; + return IMG_IR_SCANCODE; +} + +/* Convert RC5 scancode to RC5 data filter */ +static int img_ir_rc5_filter(const struct rc_scancode_filter *in, + struct img_ir_filter *out, u64 protocols) +{ + /* Not supported by the hw. */ + return -EINVAL; +} + +/* + * RC-5 decoder + * see http://www.sbprojects.com/knowledge/ir/rc5.php + */ +struct img_ir_decoder img_ir_rc5 = { + .type = RC_BIT_RC5, + .control = { + .bitoriend2 = 1, + .code_type = IMG_IR_CODETYPE_BIPHASE, + .decodend2 = 1, + }, + /* main timings */ + .tolerance = 16, + .unit = 888888, /* 1/36k*32=888.888microseconds */ + .timings = { + /* 10 symbol */ + .s10 = { + .pulse = { 1 }, + .space = { 1 }, + }, + + /* 11 symbol */ + .s11 = { + .pulse = { 1 }, + .space = { 1 }, + }, + + /* free time */ + .ft = { + .minlen = 14, + .maxlen = 14, + .ft_min = 5, + }, + }, + + /* scancode logic */ + .scancode = img_ir_rc5_scancode, + .filter = img_ir_rc5_filter, +}; diff --git a/drivers/media/rc/img-ir/img-ir-rc6.c b/drivers/media/rc/img-ir/img-ir-rc6.c new file mode 100644 index 000000000000..de1e27534968 --- /dev/null +++ b/drivers/media/rc/img-ir/img-ir-rc6.c @@ -0,0 +1,117 @@ +/* + * ImgTec IR Decoder setup for Philips RC-6 protocol. + * + * Copyright 2012-2014 Imagination Technologies Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include "img-ir-hw.h" + +/* Convert RC6 data to a scancode */ +static int img_ir_rc6_scancode(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request) +{ + unsigned int addr, cmd, mode, trl1, trl2; + + /* + * Due to a side effect of the decoder handling the double length + * Trailer bit, the header information is a bit scrambled, and the + * raw data is shifted incorrectly. + * This workaround effectively recovers the header bits. + * + * The Header field should look like this: + * + * StartBit ModeBit2 ModeBit1 ModeBit0 TrailerBit + * + * But what we get is: + * + * ModeBit2 ModeBit1 ModeBit0 TrailerBit1 TrailerBit2 + * + * The start bit is not important to recover the scancode. + */ + + raw >>= 27; + + trl1 = (raw >> 17) & 0x01; + trl2 = (raw >> 16) & 0x01; + + mode = (raw >> 18) & 0x07; + addr = (raw >> 8) & 0xff; + cmd = raw & 0xff; + + /* + * Due to the above explained irregularity the trailer bits cannot + * have the same value. + */ + if (trl1 == trl2) + return -EINVAL; + + /* Only mode 0 supported for now */ + if (mode) + return -EINVAL; + + request->protocol = RC_TYPE_RC6_0; + request->scancode = addr << 8 | cmd; + request->toggle = trl2; + return IMG_IR_SCANCODE; +} + +/* Convert RC6 scancode to RC6 data filter */ +static int img_ir_rc6_filter(const struct rc_scancode_filter *in, + struct img_ir_filter *out, u64 protocols) +{ + /* Not supported by the hw. */ + return -EINVAL; +} + +/* + * RC-6 decoder + * see http://www.sbprojects.com/knowledge/ir/rc6.php + */ +struct img_ir_decoder img_ir_rc6 = { + .type = RC_BIT_RC6_0, + .control = { + .bitorien = 1, + .code_type = IMG_IR_CODETYPE_BIPHASE, + .decoden = 1, + .decodinpol = 1, + }, + /* main timings */ + .tolerance = 20, + /* + * Due to a quirk in the img-ir decoder, default header values do + * not work, the values described below were extracted from + * successful RTL test cases. + */ + .timings = { + /* leader symbol */ + .ldr = { + .pulse = { 650 }, + .space = { 660 }, + }, + /* 0 symbol */ + .s00 = { + .pulse = { 370 }, + .space = { 370 }, + }, + /* 01 symbol */ + .s01 = { + .pulse = { 370 }, + .space = { 370 }, + }, + /* free time */ + .ft = { + .minlen = 21, + .maxlen = 21, + .ft_min = 2666, /* 2.666 ms */ + }, + }, + + /* scancode logic */ + .scancode = img_ir_rc6_scancode, + .filter = img_ir_rc6_filter, +}; diff --git a/drivers/media/rc/img-ir/img-ir-sanyo.c b/drivers/media/rc/img-ir/img-ir-sanyo.c index 6b0653ecdf5a..f394994ffc22 100644 --- a/drivers/media/rc/img-ir/img-ir-sanyo.c +++ b/drivers/media/rc/img-ir/img-ir-sanyo.c @@ -23,8 +23,8 @@ #include "img-ir-hw.h" /* Convert Sanyo data to a scancode */ -static int img_ir_sanyo_scancode(int len, u64 raw, enum rc_type *protocol, - u32 *scancode, u64 enabled_protocols) +static int img_ir_sanyo_scancode(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request) { unsigned int addr, addr_inv, data, data_inv; /* a repeat code has no data */ @@ -44,8 +44,8 @@ static int img_ir_sanyo_scancode(int len, u64 raw, enum rc_type *protocol, return -EINVAL; /* Normal Sanyo */ - *protocol = RC_TYPE_SANYO; - *scancode = addr << 8 | data; + request->protocol = RC_TYPE_SANYO; + request->scancode = addr << 8 | data; return IMG_IR_SCANCODE; } diff --git a/drivers/media/rc/img-ir/img-ir-sharp.c b/drivers/media/rc/img-ir/img-ir-sharp.c index 3300a38802ac..fe5acc4f030e 100644 --- a/drivers/media/rc/img-ir/img-ir-sharp.c +++ b/drivers/media/rc/img-ir/img-ir-sharp.c @@ -12,8 +12,8 @@ #include "img-ir-hw.h" /* Convert Sharp data to a scancode */ -static int img_ir_sharp_scancode(int len, u64 raw, enum rc_type *protocol, - u32 *scancode, u64 enabled_protocols) +static int img_ir_sharp_scancode(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request) { unsigned int addr, cmd, exp, chk; @@ -32,8 +32,8 @@ static int img_ir_sharp_scancode(int len, u64 raw, enum rc_type *protocol, /* probably the second half of the message */ return -EINVAL; - *protocol = RC_TYPE_SHARP; - *scancode = addr << 8 | cmd; + request->protocol = RC_TYPE_SHARP; + request->scancode = addr << 8 | cmd; return IMG_IR_SCANCODE; } diff --git a/drivers/media/rc/img-ir/img-ir-sony.c b/drivers/media/rc/img-ir/img-ir-sony.c index 3a0f17b0752c..7f7375f82ed6 100644 --- a/drivers/media/rc/img-ir/img-ir-sony.c +++ b/drivers/media/rc/img-ir/img-ir-sony.c @@ -12,8 +12,8 @@ #include "img-ir-hw.h" /* Convert Sony data to a scancode */ -static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol, - u32 *scancode, u64 enabled_protocols) +static int img_ir_sony_scancode(int len, u64 raw, u64 enabled_protocols, + struct img_ir_scancode_req *request) { unsigned int dev, subdev, func; @@ -25,7 +25,7 @@ static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol, raw >>= 7; dev = raw & 0x1f; /* next 5 bits */ subdev = 0; - *protocol = RC_TYPE_SONY12; + request->protocol = RC_TYPE_SONY12; break; case 15: if (!(enabled_protocols & RC_BIT_SONY15)) @@ -34,7 +34,7 @@ static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol, raw >>= 7; dev = raw & 0xff; /* next 8 bits */ subdev = 0; - *protocol = RC_TYPE_SONY15; + request->protocol = RC_TYPE_SONY15; break; case 20: if (!(enabled_protocols & RC_BIT_SONY20)) @@ -44,12 +44,12 @@ static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol, dev = raw & 0x1f; /* next 5 bits */ raw >>= 5; subdev = raw & 0xff; /* next 8 bits */ - *protocol = RC_TYPE_SONY20; + request->protocol = RC_TYPE_SONY20; break; default: return -EINVAL; } - *scancode = dev << 16 | subdev << 8 | func; + request->scancode = dev << 16 | subdev << 8 | func; return IMG_IR_SCANCODE; } diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 1e0545a67959..4de0e85af805 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -553,14 +553,14 @@ unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait) if (!ir->attached) return POLLERR; - poll_wait(file, &ir->buf->wait_poll, wait); + if (ir->buf) { + poll_wait(file, &ir->buf->wait_poll, wait); - if (ir->buf) if (lirc_buffer_empty(ir->buf)) ret = 0; else ret = POLLIN | POLLRDNORM; - else + } else ret = POLLERR; dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n", diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 86ffcd54339e..f8c5e47a30aa 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1021,16 +1021,16 @@ static ssize_t store_protocols(struct device *device, goto out; } - if (new_protocols == old_protocols) { - rc = len; - goto out; + if (new_protocols != old_protocols) { + *current_protocols = new_protocols; + IR_dprintk(1, "Protocols changed to 0x%llx\n", + (long long)new_protocols); } - *current_protocols = new_protocols; - IR_dprintk(1, "Protocols changed to 0x%llx\n", (long long)new_protocols); - /* - * If the protocol is changed the filter needs updating. + * If a protocol change was attempted the filter may need updating, even + * if the actual protocol mask hasn't changed (since the driver may have + * cleared the filter). * Try setting the same filter with the new protocol (if any). * Fall back to clearing the filter. */ diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index 340f7f51eed4..7830aef3db45 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #define SUNXI_IR_DEV "sunxi-ir" @@ -55,12 +56,12 @@ #define REG_RXINT_RAI_EN BIT(4) /* Rx FIFO available byte level */ -#define REG_RXINT_RAL(val) (((val) << 8) & (GENMASK(11, 8))) +#define REG_RXINT_RAL(val) ((val) << 8) /* Rx Interrupt Status */ #define SUNXI_IR_RXSTA_REG 0x30 /* RX FIFO Get Available Counter */ -#define REG_RXSTA_GET_AC(val) (((val) >> 8) & (GENMASK(5, 0))) +#define REG_RXSTA_GET_AC(val) (((val) >> 8) & (ir->fifo_size * 2 - 1)) /* Clear all interrupt status value */ #define REG_RXSTA_CLEARALL 0xff @@ -71,10 +72,6 @@ /* CIR_REG register idle threshold */ #define REG_CIR_ITHR(val) (((val) << 8) & (GENMASK(15, 8))) -/* Hardware supported fifo size */ -#define SUNXI_IR_FIFO_SIZE 16 -/* How many messages in FIFO trigger IRQ */ -#define TRIGGER_LEVEL 8 /* Required frequency for IR0 or IR1 clock in CIR mode */ #define SUNXI_IR_BASE_CLK 8000000 /* Frequency after IR internal divider */ @@ -93,8 +90,10 @@ struct sunxi_ir { struct rc_dev *rc; void __iomem *base; int irq; + int fifo_size; struct clk *clk; struct clk *apb_clk; + struct reset_control *rst; const char *map_name; }; @@ -113,11 +112,11 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id) /* clean all pending statuses */ writel(status | REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG); - if (status & REG_RXINT_RAI_EN) { + if (status & (REG_RXINT_RAI_EN | REG_RXINT_RPEI_EN)) { /* How many messages in fifo */ rc = REG_RXSTA_GET_AC(status); /* Sanity check */ - rc = rc > SUNXI_IR_FIFO_SIZE ? SUNXI_IR_FIFO_SIZE : rc; + rc = rc > ir->fifo_size ? ir->fifo_size : rc; /* If we have data */ for (cnt = 0; cnt < rc; cnt++) { /* for each bit in fifo */ @@ -154,6 +153,11 @@ static int sunxi_ir_probe(struct platform_device *pdev) if (!ir) return -ENOMEM; + if (of_device_is_compatible(dn, "allwinner,sun5i-a13-ir")) + ir->fifo_size = 64; + else + ir->fifo_size = 16; + /* Clock */ ir->apb_clk = devm_clk_get(dev, "apb"); if (IS_ERR(ir->apb_clk)) { @@ -166,15 +170,29 @@ static int sunxi_ir_probe(struct platform_device *pdev) return PTR_ERR(ir->clk); } + /* Reset (optional) */ + ir->rst = devm_reset_control_get_optional(dev, NULL); + if (IS_ERR(ir->rst)) { + ret = PTR_ERR(ir->rst); + if (ret == -EPROBE_DEFER) + return ret; + ir->rst = NULL; + } else { + ret = reset_control_deassert(ir->rst); + if (ret) + return ret; + } + ret = clk_set_rate(ir->clk, SUNXI_IR_BASE_CLK); if (ret) { dev_err(dev, "set ir base clock failed!\n"); - return ret; + goto exit_reset_assert; } if (clk_prepare_enable(ir->apb_clk)) { dev_err(dev, "try to enable apb_ir_clk failed\n"); - return -EINVAL; + ret = -EINVAL; + goto exit_reset_assert; } if (clk_prepare_enable(ir->clk)) { @@ -255,7 +273,7 @@ static int sunxi_ir_probe(struct platform_device *pdev) * level */ writel(REG_RXINT_ROI_EN | REG_RXINT_RPEI_EN | - REG_RXINT_RAI_EN | REG_RXINT_RAL(TRIGGER_LEVEL - 1), + REG_RXINT_RAI_EN | REG_RXINT_RAL(ir->fifo_size / 2 - 1), ir->base + SUNXI_IR_RXINT_REG); /* Enable IR Module */ @@ -271,6 +289,9 @@ exit_clkdisable_clk: clk_disable_unprepare(ir->clk); exit_clkdisable_apb_clk: clk_disable_unprepare(ir->apb_clk); +exit_reset_assert: + if (ir->rst) + reset_control_assert(ir->rst); return ret; } @@ -282,6 +303,8 @@ static int sunxi_ir_remove(struct platform_device *pdev) clk_disable_unprepare(ir->clk); clk_disable_unprepare(ir->apb_clk); + if (ir->rst) + reset_control_assert(ir->rst); spin_lock_irqsave(&ir->ir_lock, flags); /* disable IR IRQ */ @@ -298,6 +321,7 @@ static int sunxi_ir_remove(struct platform_device *pdev) static const struct of_device_id sunxi_ir_match[] = { { .compatible = "allwinner,sun4i-a10-ir", }, + { .compatible = "allwinner,sun5i-a13-ir", }, {}, }; diff --git a/drivers/media/tuners/mt20xx.c b/drivers/media/tuners/mt20xx.c index 0e74e97e0d1a..9e031040c13f 100644 --- a/drivers/media/tuners/mt20xx.c +++ b/drivers/media/tuners/mt20xx.c @@ -660,11 +660,3 @@ EXPORT_SYMBOL_GPL(microtune_attach); MODULE_DESCRIPTION("Microtune tuner driver"); MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/mt2131.c b/drivers/media/tuners/mt2131.c index f83b0c1ea6c8..6e2cdd2b6175 100644 --- a/drivers/media/tuners/mt2131.c +++ b/drivers/media/tuners/mt2131.c @@ -294,8 +294,3 @@ EXPORT_SYMBOL(mt2131_attach); MODULE_AUTHOR("Steven Toth"); MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/tuners/mt2131.h b/drivers/media/tuners/mt2131.h index 09ceaf68e47c..837c854b9c65 100644 --- a/drivers/media/tuners/mt2131.h +++ b/drivers/media/tuners/mt2131.h @@ -47,8 +47,3 @@ static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, #endif /* CONFIG_MEDIA_TUNER_MT2131 */ #endif /* __MT2131_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/tuners/mt2131_priv.h b/drivers/media/tuners/mt2131_priv.h index 62aeedf5c550..91283b599cb3 100644 --- a/drivers/media/tuners/mt2131_priv.h +++ b/drivers/media/tuners/mt2131_priv.h @@ -41,8 +41,3 @@ struct mt2131_priv { }; #endif /* __MT2131_PRIV_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/tuners/mxl5007t.c b/drivers/media/tuners/mxl5007t.c index 1810ad66888e..f4ae04c3328a 100644 --- a/drivers/media/tuners/mxl5007t.c +++ b/drivers/media/tuners/mxl5007t.c @@ -938,11 +938,3 @@ MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver"); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); MODULE_VERSION("0.2"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/mxl5007t.h b/drivers/media/tuners/mxl5007t.h index 37b0942e2385..ae7037d681c5 100644 --- a/drivers/media/tuners/mxl5007t.h +++ b/drivers/media/tuners/mxl5007t.h @@ -93,12 +93,3 @@ static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, #endif #endif /* __MXL5007T_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ - diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 2180de9d654a..fcf139dfdec6 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -19,16 +19,17 @@ static const struct dvb_tuner_ops si2157_ops; /* execute firmware command */ -static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd) +static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd) { + struct si2157_dev *dev = i2c_get_clientdata(client); int ret; unsigned long timeout; - mutex_lock(&s->i2c_mutex); + mutex_lock(&dev->i2c_mutex); if (cmd->wlen) { /* write cmd and args for firmware */ - ret = i2c_master_send(s->client, cmd->args, cmd->wlen); + ret = i2c_master_send(client, cmd->args, cmd->wlen); if (ret < 0) { goto err_mutex_unlock; } else if (ret != cmd->wlen) { @@ -42,7 +43,7 @@ static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd) #define TIMEOUT 80 timeout = jiffies + msecs_to_jiffies(TIMEOUT); while (!time_after(jiffies, timeout)) { - ret = i2c_master_recv(s->client, cmd->args, cmd->rlen); + ret = i2c_master_recv(client, cmd->args, cmd->rlen); if (ret < 0) { goto err_mutex_unlock; } else if (ret != cmd->rlen) { @@ -55,7 +56,7 @@ static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd) break; } - dev_dbg(&s->client->dev, "cmd execution took %d ms\n", + dev_dbg(&client->dev, "cmd execution took %d ms\n", jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - TIMEOUT)); @@ -65,35 +66,32 @@ static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd) } } - ret = 0; + mutex_unlock(&dev->i2c_mutex); + return 0; err_mutex_unlock: - mutex_unlock(&s->i2c_mutex); - if (ret) - goto err; - - return 0; -err: - dev_dbg(&s->client->dev, "failed=%d\n", ret); + mutex_unlock(&dev->i2c_mutex); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int si2157_init(struct dvb_frontend *fe) { - struct si2157 *s = fe->tuner_priv; + struct i2c_client *client = fe->tuner_priv; + struct si2157_dev *dev = i2c_get_clientdata(client); int ret, len, remaining; struct si2157_cmd cmd; - const struct firmware *fw = NULL; - u8 *fw_file; + const struct firmware *fw; + const char *fw_name; unsigned int chip_id; - dev_dbg(&s->client->dev, "\n"); + dev_dbg(&client->dev, "\n"); - if (s->fw_loaded) + if (dev->fw_loaded) goto warm; /* power up */ - if (s->chiptype == SI2157_CHIPTYPE_SI2146) { + if (dev->chiptype == SI2157_CHIPTYPE_SI2146) { memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9); cmd.wlen = 9; } else { @@ -101,7 +99,7 @@ static int si2157_init(struct dvb_frontend *fe) cmd.wlen = 15; } cmd.rlen = 1; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) goto err; @@ -109,7 +107,7 @@ static int si2157_init(struct dvb_frontend *fe) memcpy(cmd.args, "\x02", 1); cmd.wlen = 1; cmd.rlen = 13; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) goto err; @@ -125,121 +123,133 @@ static int si2157_init(struct dvb_frontend *fe) switch (chip_id) { case SI2158_A20: case SI2148_A20: - fw_file = SI2158_A20_FIRMWARE; + fw_name = SI2158_A20_FIRMWARE; break; case SI2157_A30: case SI2147_A30: case SI2146_A10: - goto skip_fw_download; + fw_name = NULL; + break; default: - dev_err(&s->client->dev, - "unknown chip version Si21%d-%c%c%c\n", + dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n", cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); ret = -EINVAL; goto err; } - /* cold state - try to download firmware */ - dev_info(&s->client->dev, "found a '%s' in cold state\n", - si2157_ops.info.name); + dev_info(&client->dev, "found a 'Silicon Labs Si21%d-%c%c%c'\n", + cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); + + if (fw_name == NULL) + goto skip_fw_download; /* request the firmware, this will block and timeout */ - ret = request_firmware(&fw, fw_file, &s->client->dev); + ret = request_firmware(&fw, fw_name, &client->dev); if (ret) { - dev_err(&s->client->dev, "firmware file '%s' not found\n", - fw_file); + dev_err(&client->dev, "firmware file '%s' not found\n", + fw_name); goto err; } /* firmware should be n chunks of 17 bytes */ if (fw->size % 17 != 0) { - dev_err(&s->client->dev, "firmware file '%s' is invalid\n", - fw_file); + dev_err(&client->dev, "firmware file '%s' is invalid\n", + fw_name); ret = -EINVAL; - goto fw_release_exit; + goto err_release_firmware; } - dev_info(&s->client->dev, "downloading firmware from file '%s'\n", - fw_file); + dev_info(&client->dev, "downloading firmware from file '%s'\n", + fw_name); for (remaining = fw->size; remaining > 0; remaining -= 17) { len = fw->data[fw->size - remaining]; memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len); cmd.wlen = len; cmd.rlen = 1; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) { - dev_err(&s->client->dev, - "firmware download failed=%d\n", + dev_err(&client->dev, "firmware download failed %d\n", ret); - goto fw_release_exit; + goto err_release_firmware; } } release_firmware(fw); - fw = NULL; skip_fw_download: /* reboot the tuner with new firmware? */ memcpy(cmd.args, "\x01\x01", 2); cmd.wlen = 2; cmd.rlen = 1; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) goto err; - s->fw_loaded = true; + /* query firmware version */ + memcpy(cmd.args, "\x11", 1); + cmd.wlen = 1; + cmd.rlen = 10; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + + dev_info(&client->dev, "firmware version: %c.%c.%d\n", + cmd.args[6], cmd.args[7], cmd.args[8]); + + dev->fw_loaded = true; warm: - s->active = true; + dev->active = true; return 0; -fw_release_exit: +err_release_firmware: release_firmware(fw); err: - dev_dbg(&s->client->dev, "failed=%d\n", ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int si2157_sleep(struct dvb_frontend *fe) { - struct si2157 *s = fe->tuner_priv; + struct i2c_client *client = fe->tuner_priv; + struct si2157_dev *dev = i2c_get_clientdata(client); int ret; struct si2157_cmd cmd; - dev_dbg(&s->client->dev, "\n"); + dev_dbg(&client->dev, "\n"); - s->active = false; + dev->active = false; /* standby */ memcpy(cmd.args, "\x16\x00", 2); cmd.wlen = 2; cmd.rlen = 1; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) goto err; return 0; err: - dev_dbg(&s->client->dev, "failed=%d\n", ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } static int si2157_set_params(struct dvb_frontend *fe) { - struct si2157 *s = fe->tuner_priv; + struct i2c_client *client = fe->tuner_priv; + struct si2157_dev *dev = i2c_get_clientdata(client); struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; struct si2157_cmd cmd; u8 bandwidth, delivery_system; - dev_dbg(&s->client->dev, + dev_dbg(&client->dev, "delivery_system=%d frequency=%u bandwidth_hz=%u\n", - c->delivery_system, c->frequency, - c->bandwidth_hz); + c->delivery_system, c->frequency, c->bandwidth_hz); - if (!s->active) { + if (!dev->active) { ret = -EAGAIN; goto err; } @@ -274,21 +284,21 @@ static int si2157_set_params(struct dvb_frontend *fe) memcpy(cmd.args, "\x14\x00\x03\x07\x00\x00", 6); cmd.args[4] = delivery_system | bandwidth; - if (s->inversion) + if (dev->inversion) cmd.args[5] = 0x01; cmd.wlen = 6; cmd.rlen = 4; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) goto err; - if (s->chiptype == SI2157_CHIPTYPE_SI2146) + if (dev->chiptype == SI2157_CHIPTYPE_SI2146) memcpy(cmd.args, "\x14\x00\x02\x07\x00\x01", 6); else memcpy(cmd.args, "\x14\x00\x02\x07\x01\x00", 6); cmd.wlen = 6; cmd.rlen = 4; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) goto err; @@ -300,13 +310,13 @@ static int si2157_set_params(struct dvb_frontend *fe) cmd.args[7] = (c->frequency >> 24) & 0xff; cmd.wlen = 8; cmd.rlen = 1; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) goto err; return 0; err: - dev_dbg(&s->client->dev, "failed=%d\n", ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } @@ -334,70 +344,67 @@ static int si2157_probe(struct i2c_client *client, { struct si2157_config *cfg = client->dev.platform_data; struct dvb_frontend *fe = cfg->fe; - struct si2157 *s; + struct si2157_dev *dev; struct si2157_cmd cmd; int ret; - s = kzalloc(sizeof(struct si2157), GFP_KERNEL); - if (!s) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { ret = -ENOMEM; dev_err(&client->dev, "kzalloc() failed\n"); goto err; } - s->client = client; - s->fe = cfg->fe; - s->inversion = cfg->inversion; - s->fw_loaded = false; - s->chiptype = (u8)id->driver_data; - mutex_init(&s->i2c_mutex); + i2c_set_clientdata(client, dev); + dev->fe = cfg->fe; + dev->inversion = cfg->inversion; + dev->fw_loaded = false; + dev->chiptype = (u8)id->driver_data; + mutex_init(&dev->i2c_mutex); /* check if the tuner is there */ cmd.wlen = 0; cmd.rlen = 1; - ret = si2157_cmd_execute(s, &cmd); + ret = si2157_cmd_execute(client, &cmd); if (ret) - goto err; + goto err_kfree; - fe->tuner_priv = s; - memcpy(&fe->ops.tuner_ops, &si2157_ops, - sizeof(struct dvb_tuner_ops)); + memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = client; - i2c_set_clientdata(client, s); - - dev_info(&s->client->dev, - "Silicon Labs %s successfully attached\n", - s->chiptype == SI2157_CHIPTYPE_SI2146 ? + dev_info(&client->dev, "Silicon Labs %s successfully attached\n", + dev->chiptype == SI2157_CHIPTYPE_SI2146 ? "Si2146" : "Si2147/2148/2157/2158"); return 0; + +err_kfree: + kfree(dev); err: dev_dbg(&client->dev, "failed=%d\n", ret); - kfree(s); - return ret; } static int si2157_remove(struct i2c_client *client) { - struct si2157 *s = i2c_get_clientdata(client); - struct dvb_frontend *fe = s->fe; + struct si2157_dev *dev = i2c_get_clientdata(client); + struct dvb_frontend *fe = dev->fe; dev_dbg(&client->dev, "\n"); memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); fe->tuner_priv = NULL; - kfree(s); + kfree(dev); return 0; } -static const struct i2c_device_id si2157_id[] = { - {"si2157", 0}, - {"si2146", 1}, +static const struct i2c_device_id si2157_id_table[] = { + {"si2157", SI2157_CHIPTYPE_SI2157}, + {"si2146", SI2157_CHIPTYPE_SI2146}, {} }; -MODULE_DEVICE_TABLE(i2c, si2157_id); +MODULE_DEVICE_TABLE(i2c, si2157_id_table); static struct i2c_driver si2157_driver = { .driver = { @@ -406,7 +413,7 @@ static struct i2c_driver si2157_driver = { }, .probe = si2157_probe, .remove = si2157_remove, - .id_table = si2157_id, + .id_table = si2157_id_table, }; module_i2c_driver(si2157_driver); diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index d6e07cdd2a07..7aa53bce5593 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -21,9 +21,8 @@ #include "si2157.h" /* state struct */ -struct si2157 { +struct si2157_dev { struct mutex i2c_mutex; - struct i2c_client *client; struct dvb_frontend *fe; bool active; bool fw_loaded; diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c index 4995b890c164..f8620741bb5f 100644 --- a/drivers/media/tuners/tda18271-fe.c +++ b/drivers/media/tuners/tda18271-fe.c @@ -1355,11 +1355,3 @@ MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); MODULE_VERSION("0.4"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda18271-maps.c b/drivers/media/tuners/tda18271-maps.c index b62e925f643f..1e89dd93c4bb 100644 --- a/drivers/media/tuners/tda18271-maps.c +++ b/drivers/media/tuners/tda18271-maps.c @@ -1305,11 +1305,3 @@ int tda18271_assign_map_layout(struct dvb_frontend *fe) return ret; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda18271-priv.h b/drivers/media/tuners/tda18271-priv.h index b36a7b754772..cc80f544af34 100644 --- a/drivers/media/tuners/tda18271-priv.h +++ b/drivers/media/tuners/tda18271-priv.h @@ -226,11 +226,3 @@ extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq); extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq); #endif /* __TDA18271_PRIV_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda827x.c b/drivers/media/tuners/tda827x.c index 73453a255cdc..edcb4a723aa1 100644 --- a/drivers/media/tuners/tda827x.c +++ b/drivers/media/tuners/tda827x.c @@ -907,11 +907,3 @@ MODULE_DESCRIPTION("DVB TDA827x driver"); MODULE_AUTHOR("Hartmut Hackmann "); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c index ab4106c17b4c..998e82bba9c0 100644 --- a/drivers/media/tuners/tda8290.c +++ b/drivers/media/tuners/tda8290.c @@ -881,11 +881,3 @@ EXPORT_SYMBOL_GPL(tda829x_probe); MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tda9887.c b/drivers/media/tuners/tda9887.c index 9823248d743f..56be6c29399b 100644 --- a/drivers/media/tuners/tda9887.c +++ b/drivers/media/tuners/tda9887.c @@ -707,11 +707,3 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, EXPORT_SYMBOL_GPL(tda9887_attach); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c index ca274c2d8c70..8e9ce144da9a 100644 --- a/drivers/media/tuners/tuner-simple.c +++ b/drivers/media/tuners/tuner-simple.c @@ -1148,11 +1148,3 @@ EXPORT_SYMBOL_GPL(simple_tuner_attach); MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver"); MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig index 1d410ac8f9a8..78b797e0b434 100644 --- a/drivers/media/usb/au0828/Kconfig +++ b/drivers/media/usb/au0828/Kconfig @@ -4,7 +4,7 @@ config VIDEO_AU0828 depends on I2C && INPUT && DVB_CORE && USB select I2C_ALGOBIT select VIDEO_TVEEPROM - select VIDEOBUF_VMALLOC + select VIDEOBUF2_VMALLOC select DVB_AU8522_DTV if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index da87f1cc31a9..edc27355f271 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -44,7 +44,7 @@ static void hvr950q_cs5340_audio(void *priv, int enable) struct au0828_board au0828_boards[] = { [AU0828_BOARD_UNKNOWN] = { .name = "Unknown board", - .tuner_type = UNSET, + .tuner_type = -1U, .tuner_addr = ADDR_UNSET, }, [AU0828_BOARD_HAUPPAUGE_HVR850] = { diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c index 932d24f42b24..f67247cf1a5a 100644 --- a/drivers/media/usb/au0828/au0828-vbi.c +++ b/drivers/media/usb/au0828/au0828-vbi.c @@ -28,111 +28,67 @@ #include #include -static unsigned int vbibufs = 5; -module_param(vbibufs, int, 0644); -MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); - /* ------------------------------------------------------------------ */ -static void -free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf) +static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct au0828_fh *fh = vq->priv_data; - struct au0828_dev *dev = fh->dev; - unsigned long flags = 0; - if (in_interrupt()) - BUG(); + struct au0828_dev *dev = vb2_get_drv_priv(vq); + unsigned long img_size = dev->vbi_width * dev->vbi_height * 2; + unsigned long size; - /* We used to wait for the buffer to finish here, but this didn't work - because, as we were keeping the state as VIDEOBUF_QUEUED, - videobuf_queue_cancel marked it as finished for us. - (Also, it could wedge forever if the hardware was misconfigured.) - - This should be safe; by the time we get here, the buffer isn't - queued anymore. If we ever start marking the buffers as - VIDEOBUF_ACTIVE, it won't be, though. - */ - spin_lock_irqsave(&dev->slock, flags); - if (dev->isoc_ctl.vbi_buf == buf) - dev->isoc_ctl.vbi_buf = NULL; - spin_unlock_irqrestore(&dev->slock, flags); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int -vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - struct au0828_fh *fh = q->priv_data; - struct au0828_dev *dev = fh->dev; - - *size = dev->vbi_width * dev->vbi_height * 2; - - if (0 == *count) - *count = vbibufs; - if (*count < 2) - *count = 2; - if (*count > 32) - *count = 32; - return 0; -} - -static int -vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct au0828_fh *fh = q->priv_data; - struct au0828_dev *dev = fh->dev; - struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb); - int rc = 0; - - buf->vb.size = dev->vbi_width * dev->vbi_height * 2; - - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + size = fmt ? (fmt->fmt.vbi.samples_per_line * + (fmt->fmt.vbi.count[0] + fmt->fmt.vbi.count[1])) : img_size; + if (size < img_size) return -EINVAL; - buf->vb.width = dev->vbi_width; - buf->vb.height = dev->vbi_height; - buf->vb.field = field; + *nplanes = 1; + sizes[0] = size; - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(q, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; return 0; +} -fail: - free_buffer(q, buf); - return rc; +static int vbi_buffer_prepare(struct vb2_buffer *vb) +{ + struct au0828_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb); + unsigned long size; + + size = dev->vbi_width * dev->vbi_height * 2; + + if (vb2_plane_size(vb, 0) < size) { + pr_err("%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + vb2_set_plane_payload(&buf->vb, 0, size); + + return 0; } static void -vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct au0828_buffer *buf = container_of(vb, - struct au0828_buffer, - vb); - struct au0828_fh *fh = vq->priv_data; - struct au0828_dev *dev = fh->dev; - struct au0828_dmaqueue *vbiq = &dev->vbiq; - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vbiq->active); -} - -static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +vbi_buffer_queue(struct vb2_buffer *vb) { + struct au0828_dev *dev = vb2_get_drv_priv(vb->vb2_queue); struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb); - free_buffer(q, buf); + struct au0828_dmaqueue *vbiq = &dev->vbiq; + unsigned long flags = 0; + + buf->mem = vb2_plane_vaddr(vb, 0); + buf->length = vb2_plane_size(vb, 0); + + spin_lock_irqsave(&dev->slock, flags); + list_add_tail(&buf->list, &vbiq->active); + spin_unlock_irqrestore(&dev->slock, flags); } -struct videobuf_queue_ops au0828_vbi_qops = { - .buf_setup = vbi_setup, - .buf_prepare = vbi_prepare, - .buf_queue = vbi_queue, - .buf_release = vbi_release, +struct vb2_ops au0828_vbi_qops = { + .queue_setup = vbi_queue_setup, + .buf_prepare = vbi_buffer_prepare, + .buf_queue = vbi_buffer_queue, + .start_streaming = au0828_start_analog_streaming, + .stop_streaming = au0828_stop_vbi_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 5f337b118bff..a27cb5fcdef8 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -22,7 +22,6 @@ /* Developer Notes: * - * VBI support is not yet working * The hardware scaler supported is unimplemented * AC97 audio support is unimplemented (only i2s audio mode) * @@ -219,9 +218,6 @@ static int au0828_init_isoc(struct au0828_dev *dev, int max_packets, au0828_isocdbg("au0828: called au0828_prepare_isoc\n"); - /* De-allocates all pending stuff */ - au0828_uninit_isoc(dev); - dev->isoc_ctl.isoc_copy = isoc_copy; dev->isoc_ctl.num_bufs = num_bufs; @@ -285,8 +281,6 @@ static int au0828_init_isoc(struct au0828_dev *dev, int max_packets, } } - init_waitqueue_head(&dma_q->wq); - /* submit urbs and enables IRQ */ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); @@ -309,16 +303,12 @@ static inline void buffer_filled(struct au0828_dev *dev, struct au0828_buffer *buf) { /* Advice that buffer was filled */ - au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); + au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field); - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - v4l2_get_timestamp(&buf->vb.ts); - - dev->isoc_ctl.buf = NULL; - - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); + buf->vb.v4l2_buf.sequence = dev->frame_count++; + buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); } static inline void vbi_buffer_filled(struct au0828_dev *dev, @@ -326,16 +316,12 @@ static inline void vbi_buffer_filled(struct au0828_dev *dev, struct au0828_buffer *buf) { /* Advice that buffer was filled */ - au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); + au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field); - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - v4l2_get_timestamp(&buf->vb.ts); - - dev->isoc_ctl.vbi_buf = NULL; - - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); + buf->vb.v4l2_buf.sequence = dev->vbi_frame_count++; + buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); } /* @@ -354,8 +340,8 @@ static void au0828_copy_video(struct au0828_dev *dev, if (len == 0) return; - if (dma_q->pos + len > buf->vb.size) - len = buf->vb.size - dma_q->pos; + if (dma_q->pos + len > buf->length) + len = buf->length - dma_q->pos; startread = p; remain = len; @@ -373,11 +359,11 @@ static void au0828_copy_video(struct au0828_dev *dev, lencopy = bytesperline - currlinedone; lencopy = lencopy > remain ? remain : lencopy; - if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) { + if ((char *)startwrite + lencopy > (char *)outp + buf->length) { au0828_isocdbg("Overflow of %zi bytes past buffer end (1)\n", ((char *)startwrite + lencopy) - - ((char *)outp + buf->vb.size)); - remain = (char *)outp + buf->vb.size - (char *)startwrite; + ((char *)outp + buf->length)); + remain = (char *)outp + buf->length - (char *)startwrite; lencopy = remain; } if (lencopy <= 0) @@ -395,11 +381,11 @@ static void au0828_copy_video(struct au0828_dev *dev, lencopy = bytesperline; if ((char *)startwrite + lencopy > (char *)outp + - buf->vb.size) { + buf->length) { au0828_isocdbg("Overflow %zi bytes past buf end (2)\n", ((char *)startwrite + lencopy) - - ((char *)outp + buf->vb.size)); - lencopy = remain = (char *)outp + buf->vb.size - + ((char *)outp + buf->length)); + lencopy = remain = (char *)outp + buf->length - (char *)startwrite; } if (lencopy <= 0) @@ -435,7 +421,11 @@ static inline void get_next_buf(struct au0828_dmaqueue *dma_q, } /* Get the next buffer */ - *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue); + *buf = list_entry(dma_q->active.next, struct au0828_buffer, list); + /* Cleans up buffer - Useful for testing for frame/URB loss */ + list_del(&(*buf)->list); + dma_q->pos = 0; + (*buf)->vb_buf = (*buf)->mem; dev->isoc_ctl.buf = *buf; return; @@ -473,8 +463,8 @@ static void au0828_copy_vbi(struct au0828_dev *dev, bytesperline = dev->vbi_width; - if (dma_q->pos + len > buf->vb.size) - len = buf->vb.size - dma_q->pos; + if (dma_q->pos + len > buf->length) + len = buf->length - dma_q->pos; startread = p; startwrite = outp + (dma_q->pos / 2); @@ -497,7 +487,6 @@ static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q, struct au0828_buffer **buf) { struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vbiq); - char *outp; if (list_empty(&dma_q->active)) { au0828_isocdbg("No active queue to serve\n"); @@ -507,13 +496,12 @@ static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q, } /* Get the next buffer */ - *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue); + *buf = list_entry(dma_q->active.next, struct au0828_buffer, list); /* Cleans up buffer - Useful for testing for frame/URB loss */ - outp = videobuf_to_vmalloc(&(*buf)->vb); - memset(outp, 0x00, (*buf)->vb.size); - + list_del(&(*buf)->list); + dma_q->pos = 0; + (*buf)->vb_buf = (*buf)->mem; dev->isoc_ctl.vbi_buf = *buf; - return; } @@ -549,11 +537,11 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb) buf = dev->isoc_ctl.buf; if (buf != NULL) - outp = videobuf_to_vmalloc(&buf->vb); + outp = vb2_plane_vaddr(&buf->vb, 0); vbi_buf = dev->isoc_ctl.vbi_buf; if (vbi_buf != NULL) - vbioutp = videobuf_to_vmalloc(&vbi_buf->vb); + vbioutp = vb2_plane_vaddr(&vbi_buf->vb, 0); for (i = 0; i < urb->number_of_packets; i++) { int status = urb->iso_frame_desc[i].status; @@ -593,8 +581,8 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb) if (vbi_buf == NULL) vbioutp = NULL; else - vbioutp = videobuf_to_vmalloc( - &vbi_buf->vb); + vbioutp = vb2_plane_vaddr( + &vbi_buf->vb, 0); /* Video */ if (buf != NULL) @@ -603,7 +591,7 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb) if (buf == NULL) outp = NULL; else - outp = videobuf_to_vmalloc(&buf->vb); + outp = vb2_plane_vaddr(&buf->vb, 0); /* As long as isoc traffic is arriving, keep resetting the timer */ @@ -657,130 +645,59 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb) return rc; } -static int -buffer_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct au0828_fh *fh = vq->priv_data; - *size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3; + struct au0828_dev *dev = vb2_get_drv_priv(vq); + unsigned long img_size = dev->height * dev->bytesperline; + unsigned long size; - if (0 == *count) - *count = AU0828_DEF_BUF; - - if (*count < AU0828_MIN_BUF) - *count = AU0828_MIN_BUF; - return 0; -} - -/* This is called *without* dev->slock held; please keep it that way */ -static void free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf) -{ - struct au0828_fh *fh = vq->priv_data; - struct au0828_dev *dev = fh->dev; - unsigned long flags = 0; - if (in_interrupt()) - BUG(); - - /* We used to wait for the buffer to finish here, but this didn't work - because, as we were keeping the state as VIDEOBUF_QUEUED, - videobuf_queue_cancel marked it as finished for us. - (Also, it could wedge forever if the hardware was misconfigured.) - - This should be safe; by the time we get here, the buffer isn't - queued anymore. If we ever start marking the buffers as - VIDEOBUF_ACTIVE, it won't be, though. - */ - spin_lock_irqsave(&dev->slock, flags); - if (dev->isoc_ctl.buf == buf) - dev->isoc_ctl.buf = NULL; - spin_unlock_irqrestore(&dev->slock, flags); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int -buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct au0828_fh *fh = vq->priv_data; - struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb); - struct au0828_dev *dev = fh->dev; - int rc = 0, urb_init = 0; - - buf->vb.size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3; - - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + size = fmt ? fmt->fmt.pix.sizeimage : img_size; + if (size < img_size) return -EINVAL; - buf->vb.width = dev->width; - buf->vb.height = dev->height; - buf->vb.field = field; + *nplanes = 1; + sizes[0] = size; - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) { - pr_info("videobuf_iolock failed\n"); - goto fail; - } - } - - if (!dev->isoc_ctl.num_bufs) - urb_init = 1; - - if (urb_init) { - rc = au0828_init_isoc(dev, AU0828_ISO_PACKETS_PER_URB, - AU0828_MAX_ISO_BUFS, dev->max_pkt_size, - au0828_isoc_copy); - if (rc < 0) { - pr_info("au0828_init_isoc failed\n"); - goto fail; - } - } - - buf->vb.state = VIDEOBUF_PREPARED; return 0; +} -fail: - free_buffer(vq, buf); - return rc; +static int +buffer_prepare(struct vb2_buffer *vb) +{ + struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb); + struct au0828_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + + buf->length = dev->height * dev->bytesperline; + + if (vb2_plane_size(vb, 0) < buf->length) { + pr_err("%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), buf->length); + return -EINVAL; + } + vb2_set_plane_payload(&buf->vb, 0, buf->length); + return 0; } static void -buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +buffer_queue(struct vb2_buffer *vb) { struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb); - struct au0828_fh *fh = vq->priv_data; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = vb2_get_drv_priv(vb->vb2_queue); struct au0828_dmaqueue *vidq = &dev->vidq; + unsigned long flags = 0; - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); + buf->mem = vb2_plane_vaddr(vb, 0); + buf->length = vb2_plane_size(vb, 0); + + spin_lock_irqsave(&dev->slock, flags); + list_add_tail(&buf->list, &vidq->active); + spin_unlock_irqrestore(&dev->slock, flags); } -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct au0828_buffer *buf = container_of(vb, - struct au0828_buffer, - vb); - - free_buffer(vq, buf); -} - -static struct videobuf_queue_ops au0828_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* ------------------------------------------------------------------ - V4L2 interface - ------------------------------------------------------------------*/ - static int au0828_i2s_init(struct au0828_dev *dev) { /* Enable i2s mode */ @@ -829,7 +746,7 @@ static int au0828_analog_stream_enable(struct au0828_dev *d) return 0; } -int au0828_analog_stream_disable(struct au0828_dev *d) +static int au0828_analog_stream_disable(struct au0828_dev *d) { dprintk(1, "au0828_analog_stream_disable called\n"); au0828_writereg(d, AU0828_SENSORCTRL_100, 0x0); @@ -862,13 +779,125 @@ static int au0828_stream_interrupt(struct au0828_dev *dev) return 0; } +int au0828_start_analog_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct au0828_dev *dev = vb2_get_drv_priv(vq); + int rc = 0; + + dprintk(1, "au0828_start_analog_streaming called %d\n", + dev->streaming_users); + + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + dev->frame_count = 0; + else + dev->vbi_frame_count = 0; + + if (dev->streaming_users == 0) { + /* If we were doing ac97 instead of i2s, it would go here...*/ + au0828_i2s_init(dev); + rc = au0828_init_isoc(dev, AU0828_ISO_PACKETS_PER_URB, + AU0828_MAX_ISO_BUFS, dev->max_pkt_size, + au0828_isoc_copy); + if (rc < 0) { + pr_info("au0828_init_isoc failed\n"); + return rc; + } + + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + v4l2_device_call_all(&dev->v4l2_dev, 0, video, + s_stream, 1); + dev->vid_timeout_running = 1; + mod_timer(&dev->vid_timeout, jiffies + (HZ / 10)); + } else if (vq->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + dev->vbi_timeout_running = 1; + mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10)); + } + } + dev->streaming_users++; + return rc; +} + +static void au0828_stop_streaming(struct vb2_queue *vq) +{ + struct au0828_dev *dev = vb2_get_drv_priv(vq); + struct au0828_dmaqueue *vidq = &dev->vidq; + unsigned long flags = 0; + + dprintk(1, "au0828_stop_streaming called %d\n", dev->streaming_users); + + if (dev->streaming_users-- == 1) + au0828_uninit_isoc(dev); + + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); + dev->vid_timeout_running = 0; + del_timer_sync(&dev->vid_timeout); + + spin_lock_irqsave(&dev->slock, flags); + if (dev->isoc_ctl.buf != NULL) { + vb2_buffer_done(&dev->isoc_ctl.buf->vb, VB2_BUF_STATE_ERROR); + dev->isoc_ctl.buf = NULL; + } + while (!list_empty(&vidq->active)) { + struct au0828_buffer *buf; + + buf = list_entry(vidq->active.next, struct au0828_buffer, list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + list_del(&buf->list); + } + spin_unlock_irqrestore(&dev->slock, flags); +} + +void au0828_stop_vbi_streaming(struct vb2_queue *vq) +{ + struct au0828_dev *dev = vb2_get_drv_priv(vq); + struct au0828_dmaqueue *vbiq = &dev->vbiq; + unsigned long flags = 0; + + dprintk(1, "au0828_stop_vbi_streaming called %d\n", + dev->streaming_users); + + if (dev->streaming_users-- == 1) + au0828_uninit_isoc(dev); + + spin_lock_irqsave(&dev->slock, flags); + if (dev->isoc_ctl.vbi_buf != NULL) { + vb2_buffer_done(&dev->isoc_ctl.vbi_buf->vb, + VB2_BUF_STATE_ERROR); + dev->isoc_ctl.vbi_buf = NULL; + } + while (!list_empty(&vbiq->active)) { + struct au0828_buffer *buf; + + buf = list_entry(vbiq->active.next, struct au0828_buffer, list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&dev->slock, flags); + + dev->vbi_timeout_running = 0; + del_timer_sync(&dev->vbi_timeout); +} + +static struct vb2_ops au0828_video_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .start_streaming = au0828_start_analog_streaming, + .stop_streaming = au0828_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +/* ------------------------------------------------------------------ + V4L2 interface + ------------------------------------------------------------------*/ /* - * au0828_release_resources + * au0828_analog_unregister * unregister v4l2 devices */ void au0828_analog_unregister(struct au0828_dev *dev) { - dprintk(1, "au0828_release_resources called\n"); + dprintk(1, "au0828_analog_unregister called\n"); mutex_lock(&au0828_sysfs_lock); if (dev->vdev) @@ -879,63 +908,6 @@ void au0828_analog_unregister(struct au0828_dev *dev) mutex_unlock(&au0828_sysfs_lock); } - -/* Usage lock check functions */ -static int res_get(struct au0828_fh *fh, unsigned int bit) -{ - struct au0828_dev *dev = fh->dev; - - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - /* is it free? */ - if (dev->resources & bit) { - /* no, someone else uses it */ - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->resources |= bit; - dprintk(1, "res: get %d\n", bit); - - return 1; -} - -static int res_check(struct au0828_fh *fh, unsigned int bit) -{ - return fh->resources & bit; -} - -static int res_locked(struct au0828_dev *dev, unsigned int bit) -{ - return dev->resources & bit; -} - -static void res_free(struct au0828_fh *fh, unsigned int bits) -{ - struct au0828_dev *dev = fh->dev; - - BUG_ON((fh->resources & bits) != bits); - - fh->resources &= ~bits; - dev->resources &= ~bits; - dprintk(1, "res: put %d\n", bits); -} - -static int get_ressource(struct au0828_fh *fh) -{ - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return AU0828_RESOURCE_VIDEO; - case V4L2_BUF_TYPE_VBI_CAPTURE: - return AU0828_RESOURCE_VBI; - default: - BUG(); - return 0; - } -} - /* This function ensures that video frames continue to be delivered even if the ITU-656 input isn't receiving any data (thereby preventing applications such as tvtime from hanging) */ @@ -951,8 +923,8 @@ static void au0828_vid_buffer_timeout(unsigned long data) buf = dev->isoc_ctl.buf; if (buf != NULL) { - vid_data = videobuf_to_vmalloc(&buf->vb); - memset(vid_data, 0x00, buf->vb.size); /* Blank green frame */ + vid_data = vb2_plane_vaddr(&buf->vb, 0); + memset(vid_data, 0x00, buf->length); /* Blank green frame */ buffer_filled(dev, dma_q, buf); } get_next_buf(dma_q, &buf); @@ -975,8 +947,8 @@ static void au0828_vbi_buffer_timeout(unsigned long data) buf = dev->isoc_ctl.vbi_buf; if (buf != NULL) { - vbi_data = videobuf_to_vmalloc(&buf->vb); - memset(vbi_data, 0x00, buf->vb.size); + vbi_data = vb2_plane_vaddr(&buf->vb, 0); + memset(vbi_data, 0x00, buf->length); vbi_buffer_filled(dev, dma_q, buf); } vbi_get_next_buf(dma_q, &buf); @@ -986,105 +958,65 @@ static void au0828_vbi_buffer_timeout(unsigned long data) spin_unlock_irqrestore(&dev->slock, flags); } - static int au0828_v4l2_open(struct file *filp) { - int ret = 0; - struct video_device *vdev = video_devdata(filp); struct au0828_dev *dev = video_drvdata(filp); - struct au0828_fh *fh; - int type; + int ret; - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - type = V4L2_BUF_TYPE_VBI_CAPTURE; - break; - default: - return -EINVAL; - } + dprintk(1, + "%s called std_set %d dev_state %d stream users %d users %d\n", + __func__, dev->std_set_in_tuner_core, dev->dev_state, + dev->streaming_users, dev->users); - fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL); - if (NULL == fh) { - dprintk(1, "Failed allocate au0828_fh struct!\n"); - return -ENOMEM; - } - - fh->type = type; - fh->dev = dev; - v4l2_fh_init(&fh->fh, vdev); - filp->private_data = fh; - - if (mutex_lock_interruptible(&dev->lock)) { - kfree(fh); + if (mutex_lock_interruptible(&dev->lock)) return -ERESTARTSYS; + + ret = v4l2_fh_open(filp); + if (ret) { + au0828_isocdbg("%s: v4l2_fh_open() returned error %d\n", + __func__, ret); + mutex_unlock(&dev->lock); + return ret; } + if (dev->users == 0) { au0828_analog_stream_enable(dev); au0828_analog_stream_reset(dev); - - /* If we were doing ac97 instead of i2s, it would go here...*/ - au0828_i2s_init(dev); - dev->stream_state = STREAM_OFF; dev->dev_state |= DEV_INITIALIZED; } - dev->users++; mutex_unlock(&dev->lock); - - videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops, - NULL, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct au0828_buffer), fh, - &dev->lock); - - /* VBI Setup */ - videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops, - NULL, &dev->slock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, - sizeof(struct au0828_buffer), fh, - &dev->lock); - v4l2_fh_add(&fh->fh); return ret; } static int au0828_v4l2_close(struct file *filp) { int ret; - struct au0828_fh *fh = filp->private_data; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(filp); + struct video_device *vdev = video_devdata(filp); + + dprintk(1, + "%s called std_set %d dev_state %d stream users %d users %d\n", + __func__, dev->std_set_in_tuner_core, dev->dev_state, + dev->streaming_users, dev->users); - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); mutex_lock(&dev->lock); - if (res_check(fh, AU0828_RESOURCE_VIDEO)) { + if (vdev->vfl_type == VFL_TYPE_GRABBER && dev->vid_timeout_running) { /* Cancel timeout thread in case they didn't call streamoff */ dev->vid_timeout_running = 0; del_timer_sync(&dev->vid_timeout); - - videobuf_stop(&fh->vb_vidq); - res_free(fh, AU0828_RESOURCE_VIDEO); - } - - if (res_check(fh, AU0828_RESOURCE_VBI)) { + } else if (vdev->vfl_type == VFL_TYPE_VBI && + dev->vbi_timeout_running) { /* Cancel timeout thread in case they didn't call streamoff */ dev->vbi_timeout_running = 0; del_timer_sync(&dev->vbi_timeout); - - videobuf_stop(&fh->vb_vbiq); - res_free(fh, AU0828_RESOURCE_VBI); } - if (dev->users == 1 && video_is_registered(video_devdata(filp))) { - au0828_analog_stream_disable(dev); - - au0828_uninit_isoc(dev); + if (dev->dev_state == DEV_DISCONNECTED) + goto end; + if (dev->users == 1) { /* Save some power by putting tuner to sleep */ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); dev->std_set_in_tuner_core = 0; @@ -1095,13 +1027,10 @@ static int au0828_v4l2_close(struct file *filp) if (ret < 0) pr_info("Au0828 can't set alternate to 0!\n"); } - mutex_unlock(&dev->lock); - - videobuf_mmap_free(&fh->vb_vidq); - videobuf_mmap_free(&fh->vb_vbiq); - kfree(fh); +end: + _vb2_fop_release(filp, NULL); dev->users--; - wake_up_interruptible_nr(&dev->open, 1); + mutex_unlock(&dev->lock); return 0; } @@ -1113,6 +1042,9 @@ static void au0828_init_tuner(struct au0828_dev *dev) .type = V4L2_TUNER_ANALOG_TV, }; + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); + if (dev->std_set_in_tuner_core) return; dev->std_set_in_tuner_core = 1; @@ -1125,98 +1057,6 @@ static void au0828_init_tuner(struct au0828_dev *dev) i2c_gate_ctrl(dev, 0); } -static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf, - size_t count, loff_t *pos) -{ - struct au0828_fh *fh = filp->private_data; - struct au0828_dev *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - au0828_init_tuner(dev); - mutex_unlock(&dev->lock); - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (res_locked(dev, AU0828_RESOURCE_VIDEO)) - return -EBUSY; - - return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, - filp->f_flags & O_NONBLOCK); - } - - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (!res_get(fh, AU0828_RESOURCE_VBI)) - return -EBUSY; - - if (dev->vbi_timeout_running == 0) { - /* Handle case where caller tries to read without - calling streamon first */ - dev->vbi_timeout_running = 1; - mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10)); - } - - return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0, - filp->f_flags & O_NONBLOCK); - } - - return 0; -} - -static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait) -{ - struct au0828_fh *fh = filp->private_data; - struct au0828_dev *dev = fh->dev; - unsigned long req_events = poll_requested_events(wait); - unsigned int res; - - if (check_dev(dev) < 0) - return POLLERR; - - res = v4l2_ctrl_poll(filp, wait); - if (!(req_events & (POLLIN | POLLRDNORM))) - return res; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - au0828_init_tuner(dev); - mutex_unlock(&dev->lock); - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (!res_get(fh, AU0828_RESOURCE_VIDEO)) - return POLLERR; - return res | videobuf_poll_stream(filp, &fh->vb_vidq, wait); - } - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (!res_get(fh, AU0828_RESOURCE_VBI)) - return POLLERR; - return res | videobuf_poll_stream(filp, &fh->vb_vbiq, wait); - } - return POLLERR; -} - -static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct au0828_fh *fh = filp->private_data; - struct au0828_dev *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); - else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma); - - return rc; -} - static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd, struct v4l2_format *format) { @@ -1268,13 +1108,14 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd, return 0; } - static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct video_device *vdev = video_devdata(file); - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); + + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); strlcpy(cap->driver, "au0828", sizeof(cap->driver)); strlcpy(cap->card, dev->board.name, sizeof(cap->card)); @@ -1300,6 +1141,8 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index) return -EINVAL; + dprintk(1, "%s called\n", __func__); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; strcpy(f->description, "Packed YUV2"); @@ -1312,8 +1155,10 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); + + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; @@ -1329,8 +1174,10 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); + + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); return au0828_set_format(dev, VIDIOC_TRY_FMT, f); } @@ -1338,15 +1185,17 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); int rc; + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); + rc = check_dev(dev); if (rc < 0) return rc; - if (videobuf_queue_is_busy(&fh->vb_vidq)) { + if (vb2_is_busy(&dev->vb_vidq)) { pr_info("%s queue busy\n", __func__); rc = -EBUSY; goto out; @@ -1359,8 +1208,16 @@ out: static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); + + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); + + if (norm == dev->std) + return 0; + + if (dev->streaming_users > 0) + return -EBUSY; dev->std = norm; @@ -1383,8 +1240,10 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); + + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); *norm = dev->std; return 0; @@ -1393,8 +1252,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *input) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); unsigned int tmp; static const char *inames[] = { @@ -1407,6 +1265,9 @@ static int vidioc_enum_input(struct file *file, void *priv, [AU0828_VMUX_DEBUG] = "tv debug" }; + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); + tmp = input->index; if (tmp >= AU0828_MAX_INPUT) @@ -1432,8 +1293,11 @@ static int vidioc_enum_input(struct file *file, void *priv, static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); + + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); + *i = dev->ctrl_input; return 0; } @@ -1442,6 +1306,9 @@ static void au0828_s_input(struct au0828_dev *dev, int index) { int i; + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); + switch (AUVI_INPUT(index).type) { case AU0828_VMUX_SVIDEO: dev->input_type = AU0828_VMUX_SVIDEO; @@ -1491,8 +1358,7 @@ static void au0828_s_input(struct au0828_dev *dev, int index) static int vidioc_s_input(struct file *file, void *priv, unsigned int index) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__, index); @@ -1510,6 +1376,8 @@ static int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *a) if (a->index > 1) return -EINVAL; + dprintk(1, "%s called\n", __func__); + if (a->index == 0) strcpy(a->name, "Television"); else @@ -1521,8 +1389,10 @@ static int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *a) static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); + + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); a->index = dev->ctrl_ainput; if (a->index == 0) @@ -1536,22 +1406,26 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); if (a->index != dev->ctrl_ainput) return -EINVAL; + + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); return 0; } static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); if (t->index != 0) return -EINVAL; + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); + strcpy(t->name, "Auvitek tuner"); au0828_init_tuner(dev); @@ -1564,12 +1438,14 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); if (t->index != 0) return -EINVAL; + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); + au0828_init_tuner(dev); i2c_gate_ctrl(dev, 1); v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); @@ -1585,11 +1461,12 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *freq) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); if (freq->tuner != 0) return -EINVAL; + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); freq->frequency = dev->ctrl_freq; return 0; } @@ -1597,13 +1474,15 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *freq) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); struct v4l2_frequency new_freq = *freq; if (freq->tuner != 0) return -EINVAL; + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); + au0828_init_tuner(dev); i2c_gate_ctrl(dev, 1); @@ -1625,8 +1504,10 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *format) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); + + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); format->fmt.vbi.samples_per_line = dev->vbi_width; format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; @@ -1646,12 +1527,14 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, static int vidioc_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cc) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); + cc->bounds.left = 0; cc->bounds.top = 0; cc->bounds.width = dev->width; @@ -1665,105 +1548,14 @@ static int vidioc_cropcap(struct file *file, void *priv, return 0; } -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - int rc = -EINVAL; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (unlikely(type != fh->type)) - return -EINVAL; - - dprintk(1, "vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n", - fh, type, fh->resources, dev->resources); - - if (unlikely(!res_get(fh, get_ressource(fh)))) - return -EBUSY; - - au0828_init_tuner(dev); - if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - au0828_analog_stream_enable(dev); - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1); - } - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - rc = videobuf_streamon(&fh->vb_vidq); - dev->vid_timeout_running = 1; - mod_timer(&dev->vid_timeout, jiffies + (HZ / 10)); - } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - rc = videobuf_streamon(&fh->vb_vbiq); - dev->vbi_timeout_running = 1; - mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10)); - } - - return rc; -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - int rc; - int i; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) - return -EINVAL; - if (type != fh->type) - return -EINVAL; - - dprintk(1, "vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n", - fh, type, fh->resources, dev->resources); - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev->vid_timeout_running = 0; - del_timer_sync(&dev->vid_timeout); - - au0828_analog_stream_disable(dev); - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); - rc = au0828_stream_interrupt(dev); - if (rc != 0) - return rc; - - for (i = 0; i < AU0828_MAX_INPUT; i++) { - if (AUVI_INPUT(i).audio_setup == NULL) - continue; - (AUVI_INPUT(i).audio_setup)(dev, 0); - } - - if (res_check(fh, AU0828_RESOURCE_VIDEO)) { - videobuf_streamoff(&fh->vb_vidq); - res_free(fh, AU0828_RESOURCE_VIDEO); - } - } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - dev->vbi_timeout_running = 0; - del_timer_sync(&dev->vbi_timeout); - - if (res_check(fh, AU0828_RESOURCE_VBI)) { - videobuf_streamoff(&fh->vb_vbiq); - res_free(fh, AU0828_RESOURCE_VBI); - } - } - - return 0; -} - #ifdef CONFIG_VIDEO_ADV_DEBUG static int vidioc_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); + + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); reg->val = au0828_read(dev, reg->reg); reg->size = 1; @@ -1773,8 +1565,10 @@ static int vidioc_g_register(struct file *file, void *priv, static int vidioc_s_register(struct file *file, void *priv, const struct v4l2_dbg_register *reg) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; + struct au0828_dev *dev = video_drvdata(file); + + dprintk(1, "%s called std_set %d dev_state %d\n", __func__, + dev->std_set_in_tuner_core, dev->dev_state); return au0828_writereg(dev, reg->reg, reg->val); } @@ -1784,93 +1578,13 @@ static int vidioc_log_status(struct file *file, void *fh) { struct video_device *vdev = video_devdata(file); + dprintk(1, "%s called\n", __func__); + v4l2_ctrl_log_status(file, fh); v4l2_device_call_all(vdev->v4l2_dev, 0, core, log_status); return 0; } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - rc = videobuf_reqbufs(&fh->vb_vidq, rb); - else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - rc = videobuf_reqbufs(&fh->vb_vbiq, rb); - - return rc; -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - rc = videobuf_querybuf(&fh->vb_vidq, b); - else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - rc = videobuf_querybuf(&fh->vb_vbiq, b); - - return rc; -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - rc = videobuf_qbuf(&fh->vb_vidq, b); - else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - rc = videobuf_qbuf(&fh->vb_vbiq, b); - - return rc; -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - /* Workaround for a bug in the au0828 hardware design that sometimes - results in the colorspace being inverted */ - if (dev->greenscreen_detected == 1) { - dprintk(1, "Detected green frame. Resetting stream...\n"); - au0828_analog_stream_reset(dev); - dev->greenscreen_detected = 0; - } - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - rc = videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK); - else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - rc = videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags & O_NONBLOCK); - - return rc; -} - void au0828_v4l2_suspend(struct au0828_dev *dev) { struct urb *urb; @@ -1938,9 +1652,9 @@ static struct v4l2_file_operations au0828_v4l_fops = { .owner = THIS_MODULE, .open = au0828_v4l2_open, .release = au0828_v4l2_close, - .read = au0828_v4l2_read, - .poll = au0828_v4l2_poll, - .mmap = au0828_v4l2_mmap, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, .unlocked_ioctl = video_ioctl2, }; @@ -1957,17 +1671,24 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, .vidioc_cropcap = vidioc_cropcap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_s_std = vidioc_s_std, .vidioc_g_std = vidioc_g_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, + + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, @@ -1988,6 +1709,42 @@ static const struct video_device au0828_video_template = { .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M, }; +static int au0828_vb2_setup(struct au0828_dev *dev) +{ + int rc; + struct vb2_queue *q; + + /* Setup Videobuf2 for Video capture */ + q = &dev->vb_vidq; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct au0828_buffer); + q->ops = &au0828_video_qops; + q->mem_ops = &vb2_vmalloc_memops; + + rc = vb2_queue_init(q); + if (rc < 0) + return rc; + + /* Setup Videobuf2 for VBI capture */ + q = &dev->vb_vbiq; + q->type = V4L2_BUF_TYPE_VBI_CAPTURE; + q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct au0828_buffer); + q->ops = &au0828_vbi_qops; + q->mem_ops = &vb2_vmalloc_memops; + + rc = vb2_queue_init(q); + if (rc < 0) + return rc; + + return 0; +} + /**************************************************************************/ int au0828_analog_register(struct au0828_dev *dev, @@ -2030,7 +1787,6 @@ int au0828_analog_register(struct au0828_dev *dev, } if (!(dev->isoc_in_endpointaddr)) { pr_info("Could not locate isoc endpoint\n"); - kfree(dev); return -ENODEV; } @@ -2039,17 +1795,12 @@ int au0828_analog_register(struct au0828_dev *dev, /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); INIT_LIST_HEAD(&dev->vbiq.active); - INIT_LIST_HEAD(&dev->vbiq.queued); - dev->vid_timeout.function = au0828_vid_buffer_timeout; - dev->vid_timeout.data = (unsigned long) dev; - init_timer(&dev->vid_timeout); - - dev->vbi_timeout.function = au0828_vbi_buffer_timeout; - dev->vbi_timeout.data = (unsigned long) dev; - init_timer(&dev->vbi_timeout); + setup_timer(&dev->vid_timeout, au0828_vid_buffer_timeout, + (unsigned long)dev); + setup_timer(&dev->vbi_timeout, au0828_vbi_buffer_timeout, + (unsigned long)dev); dev->width = NTSC_STD_W; dev->height = NTSC_STD_H; @@ -2078,18 +1829,34 @@ int au0828_analog_register(struct au0828_dev *dev, goto err_vdev; } + mutex_init(&dev->vb_queue_lock); + mutex_init(&dev->vb_vbi_queue_lock); + /* Fill the video capture device struct */ *dev->vdev = au0828_video_template; dev->vdev->v4l2_dev = &dev->v4l2_dev; dev->vdev->lock = &dev->lock; + dev->vdev->queue = &dev->vb_vidq; + dev->vdev->queue->lock = &dev->vb_queue_lock; strcpy(dev->vdev->name, "au0828a video"); /* Setup the VBI device */ *dev->vbi_dev = au0828_video_template; dev->vbi_dev->v4l2_dev = &dev->v4l2_dev; dev->vbi_dev->lock = &dev->lock; + dev->vbi_dev->queue = &dev->vb_vbiq; + dev->vbi_dev->queue->lock = &dev->vb_vbi_queue_lock; strcpy(dev->vbi_dev->name, "au0828a vbi"); + /* initialize videobuf2 stuff */ + retval = au0828_vb2_setup(dev); + if (retval != 0) { + dprintk(1, "unable to setup videobuf2 queues (error = %d).\n", + retval); + ret = -ENODEV; + goto err_vbi_dev; + } + /* Register the v4l2 device */ video_set_drvdata(dev->vdev, dev); retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1); @@ -2097,7 +1864,7 @@ int au0828_analog_register(struct au0828_dev *dev, dprintk(1, "unable to register video device (error = %d).\n", retval); ret = -ENODEV; - goto err_vbi_dev; + goto err_reg_vdev; } /* Register the vbi device */ @@ -2107,13 +1874,18 @@ int au0828_analog_register(struct au0828_dev *dev, dprintk(1, "unable to register vbi device (error = %d).\n", retval); ret = -ENODEV; - goto err_vbi_dev; + goto err_reg_vbi_dev; } dprintk(1, "%s completed!\n", __func__); return 0; +err_reg_vbi_dev: + video_unregister_device(dev->vdev); +err_reg_vdev: + vb2_queue_release(&dev->vb_vidq); + vb2_queue_release(&dev->vb_vbiq); err_vbi_dev: video_device_release(dev->vbi_dev); err_vdev: diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index 36815a369c68..eb1518742ae6 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -28,7 +28,7 @@ /* Analog */ #include -#include +#include #include #include #include @@ -126,17 +126,7 @@ enum au0828_dev_state { DEV_MISCONFIGURED = 0x04 }; -struct au0828_fh { - /* must be the first field of this struct! */ - struct v4l2_fh fh; - - struct au0828_dev *dev; - unsigned int resources; - - struct videobuf_queue vb_vidq; - struct videobuf_queue vb_vbiq; - enum v4l2_buf_type type; -}; +struct au0828_dev; struct au0828_usb_isoc_ctl { /* max packet size of isoc transaction */ @@ -177,21 +167,20 @@ struct au0828_usb_isoc_ctl { /* buffer for one video frame */ struct au0828_buffer { /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; + struct vb2_buffer vb; + struct list_head list; - struct list_head frame; + void *mem; + unsigned long length; int top_field; - int receiving; + /* pointer to vmalloc memory address in vb */ + char *vb_buf; }; struct au0828_dmaqueue { struct list_head active; - struct list_head queued; - - wait_queue_head_t wq; - /* Counters to control buffer fill */ - int pos; + int pos; }; struct au0828_dev { @@ -220,14 +209,26 @@ struct au0828_dev { struct au0828_rc *ir; #endif - int users; - unsigned int resources; /* resources in use */ struct video_device *vdev; struct video_device *vbi_dev; + + /* Videobuf2 */ + struct vb2_queue vb_vidq; + struct vb2_queue vb_vbiq; + struct mutex vb_queue_lock; + struct mutex vb_vbi_queue_lock; + + unsigned int frame_count; + unsigned int vbi_frame_count; + struct timer_list vid_timeout; int vid_timeout_running; struct timer_list vbi_timeout; int vbi_timeout_running; + + int users; + int streaming_users; + int width; int height; int vbi_width; @@ -242,7 +243,6 @@ struct au0828_dev { __u8 isoc_in_endpointaddr; u8 isoc_init_ok; int greenscreen_detected; - unsigned int frame_count; int ctrl_freq; int input_type; int std_set_in_tuner_core; @@ -277,6 +277,7 @@ struct au0828_dev { char *dig_transfer_buffer[URB_COUNT]; }; + /* ----------------------------------------------------------- */ #define au0828_read(dev, reg) au0828_readreg(dev, reg) #define au0828_write(dev, reg, value) au0828_writereg(dev, reg, value) @@ -309,13 +310,15 @@ extern int au0828_i2c_unregister(struct au0828_dev *dev); /* ----------------------------------------------------------- */ /* au0828-video.c */ -int au0828_analog_register(struct au0828_dev *dev, +extern int au0828_analog_register(struct au0828_dev *dev, struct usb_interface *interface); -int au0828_analog_stream_disable(struct au0828_dev *d); -void au0828_analog_unregister(struct au0828_dev *dev); +extern void au0828_analog_unregister(struct au0828_dev *dev); +extern int au0828_start_analog_streaming(struct vb2_queue *vq, + unsigned int count); +extern void au0828_stop_vbi_streaming(struct vb2_queue *vq); #ifdef CONFIG_VIDEO_AU0828_V4L2 -void au0828_v4l2_suspend(struct au0828_dev *dev); -void au0828_v4l2_resume(struct au0828_dev *dev); +extern void au0828_v4l2_suspend(struct au0828_dev *dev); +extern void au0828_v4l2_resume(struct au0828_dev *dev); #else static inline void au0828_v4l2_suspend(struct au0828_dev *dev) { }; static inline void au0828_v4l2_resume(struct au0828_dev *dev) { }; @@ -329,7 +332,7 @@ void au0828_dvb_suspend(struct au0828_dev *dev); void au0828_dvb_resume(struct au0828_dev *dev); /* au0828-vbi.c */ -extern struct videobuf_queue_ops au0828_vbi_qops; +extern struct vb2_ops au0828_vbi_qops; #define dprintk(level, fmt, arg...)\ do { if (au0828_debug & level)\ diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index ae05d591f228..da03733690bd 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -1403,7 +1403,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface, struct usb_interface_assoc_descriptor *assoc_desc; ifnum = interface->altsetting[0].desc.bInterfaceNumber; - udev = usb_get_dev(interface_to_usbdev(interface)); /* * Interface number 0 - IR interface (handled by mceusb driver) @@ -1424,11 +1423,13 @@ static int cx231xx_usb_probe(struct usb_interface *interface, } } while (test_and_set_bit(nr, &cx231xx_devused)); + udev = usb_get_dev(interface_to_usbdev(interface)); + /* allocate memory for our device state and initialize it */ dev = devm_kzalloc(&udev->dev, sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - clear_bit(nr, &cx231xx_devused); - return -ENOMEM; + retval = -ENOMEM; + goto err_if; } snprintf(dev->name, 29, "cx231xx #%d", nr); @@ -1582,7 +1583,7 @@ err_v4l2: usb_set_intfdata(interface, NULL); err_if: usb_put_dev(udev); - clear_bit(dev->devno, &cx231xx_devused); + clear_bit(nr, &cx231xx_devused); return retval; } diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 53ca12c1ff69..ecea76fe07f6 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -2062,7 +2062,6 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev, *vfd = *template; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; - vfd->debug = video_debug; vfd->lock = &dev->lock; snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index f9e262eb0db9..6d6f3ee812f6 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -532,15 +532,7 @@ struct cx231xx_video_mode { unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ u16 end_point_addr; }; -/* -struct cx23885_dmaqueue { - struct list_head active; - struct list_head queued; - struct timer_list timeout; - struct btcx_riscmem stopper; - u32 count; -}; -*/ + struct cx231xx_tsport { struct cx231xx *dev; diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index 14e111e13e54..41c6363dff08 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -354,6 +354,7 @@ struct dvb_usb_adapter { * @name: device name * @rc_map: name of rc codes table * @rc_polling_active: set when RC polling is active + * @intf: pointer to the device's struct usb_interface * @udev: pointer to the device's struct usb_device * @rc: remote controller configuration * @powered: indicated whether the device is power or not @@ -370,6 +371,7 @@ struct dvb_usb_device { const char *name; const char *rc_map; bool rc_polling_active; + struct usb_interface *intf; struct usb_device *udev; struct dvb_usb_rc rc; int powered; diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 1950f37df835..9913e0f59485 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -868,6 +868,7 @@ int dvb_usbv2_probe(struct usb_interface *intf, goto err; } + d->intf = intf; d->name = driver_info->name; d->rc_map = driver_info->rc_map; d->udev = udev; diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 994de53a574b..5de6f7c04d09 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -126,9 +126,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); struct lme2510_state { unsigned long int_urb_due; + fe_status_t lock_status; u8 id; u8 tuner_config; - u8 signal_lock; u8 signal_level; u8 signal_sn; u8 time_key; @@ -143,6 +143,12 @@ struct lme2510_state { void *buffer; struct urb *lme_urb; void *usb_buffer; + /* Frontend original calls */ + int (*fe_read_status)(struct dvb_frontend *, fe_status_t *); + int (*fe_read_signal_strength)(struct dvb_frontend *, u16 *); + int (*fe_read_snr)(struct dvb_frontend *, u16 *); + int (*fe_read_ber)(struct dvb_frontend *, u32 *); + int (*fe_read_ucblocks)(struct dvb_frontend *, u32 *); int (*fe_set_voltage)(struct dvb_frontend *, fe_sec_voltage_t); u8 dvb_usb_lme2510_firmware; }; @@ -258,6 +264,7 @@ static void lme2510_int_response(struct urb *lme_urb) static u8 *ibuf, *rbuf; int i = 0, offset; u32 key; + u8 signal_lock = 0; switch (lme_urb->status) { case 0: @@ -298,8 +305,7 @@ static void lme2510_int_response(struct urb *lme_urb) case 0xbb: switch (st->tuner_config) { case TUNER_LG: - if (ibuf[2] > 0) - st->signal_lock = ibuf[2]; + signal_lock = ibuf[2] & BIT(5); st->signal_level = ibuf[4]; st->signal_sn = ibuf[3]; st->time_key = ibuf[7]; @@ -308,29 +314,29 @@ static void lme2510_int_response(struct urb *lme_urb) case TUNER_S0194: /* Tweak for earlier firmware*/ if (ibuf[1] == 0x03) { - if (ibuf[2] > 1) - st->signal_lock = ibuf[2]; + signal_lock = ibuf[2] & BIT(4); st->signal_level = ibuf[3]; st->signal_sn = ibuf[4]; } else { st->signal_level = ibuf[4]; st->signal_sn = ibuf[5]; - st->signal_lock = - (st->signal_lock & 0xf7) + - ((ibuf[2] & 0x01) << 0x03); } break; case TUNER_RS2000: - if (ibuf[2] & 0x1) - st->signal_lock = 0xff; - else - st->signal_lock = 0x00; + signal_lock = ibuf[2] & 0xee; st->signal_level = ibuf[5]; st->signal_sn = ibuf[4]; st->time_key = ibuf[7]; default: break; } + + /* Interrupt will also throw just BIT 0 as lock */ + signal_lock |= ibuf[2] & BIT(0); + + if (!signal_lock) + st->lock_status &= ~FE_HAS_LOCK; + debug_data_snipet(5, "INT Remote data snipet in", ibuf); break; case 0xcc: @@ -344,15 +350,17 @@ static void lme2510_int_response(struct urb *lme_urb) usb_submit_urb(lme_urb, GFP_ATOMIC); - /* interrupt urb is due every 48 msecs while streaming - * add 12msecs for system lag */ - st->int_urb_due = jiffies + msecs_to_jiffies(60); + /* Interrupt urb is due every 48 msecs while streaming the buffer + * stores up to 4 periods if missed. Allow 200 msec for next interrupt. + */ + st->int_urb_due = jiffies + msecs_to_jiffies(200); } static int lme2510_int_read(struct dvb_usb_adapter *adap) { struct dvb_usb_device *d = adap_to_d(adap); struct lme2510_state *lme_int = adap_to_priv(adap); + struct usb_host_endpoint *ep; lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC); @@ -374,6 +382,12 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap) adap, 8); + /* Quirk of pipe reporting PIPE_BULK but behaves as interrupt */ + ep = usb_pipe_endpoint(d->udev, lme_int->lme_urb->pipe); + + if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK) + lme_int->lme_urb->pipe = usb_rcvbulkpipe(d->udev, 0xa), + lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC); @@ -449,170 +463,13 @@ static int lme2510_return_status(struct dvb_usb_device *d) static int lme2510_msg(struct dvb_usb_device *d, u8 *wbuf, int wlen, u8 *rbuf, int rlen) { - int ret = 0; struct lme2510_state *st = d->priv; - if (st->i2c_talk_onoff == 1) { + st->i2c_talk_onoff = 1; - ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - - switch (st->tuner_config) { - case TUNER_LG: - if (wbuf[2] == 0x1c) { - if (wbuf[3] == 0x0e) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x10)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - msleep(80); - } - } - break; - case TUNER_S7395: - if (wbuf[2] == 0xd0) { - if (wbuf[3] == 0x24) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x8)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - } - } - break; - case TUNER_S0194: - if (wbuf[2] == 0xd0) { - if (wbuf[3] == 0x1b) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x8)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - } - } - break; - case TUNER_RS2000: - default: - break; - } - } else { - /* TODO rewrite this section */ - switch (st->tuner_config) { - case TUNER_LG: - switch (wbuf[3]) { - case 0x0e: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x43: - rbuf[0] = 0x55; - rbuf[1] = st->signal_level; - break; - case 0x1c: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x15: - case 0x16: - case 0x17: - case 0x18: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - case TUNER_S7395: - switch (wbuf[3]) { - case 0x10: - rbuf[0] = 0x55; - rbuf[1] = (st->signal_level & 0x80) - ? 0 : (st->signal_level * 2); - break; - case 0x2d: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x24: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x2e: - case 0x26: - case 0x27: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - case TUNER_S0194: - switch (wbuf[3]) { - case 0x18: - rbuf[0] = 0x55; - rbuf[1] = (st->signal_level & 0x80) - ? 0 : (st->signal_level * 2); - break; - case 0x24: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x1b: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x19: - case 0x25: - case 0x1e: - case 0x1d: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - case TUNER_RS2000: - switch (wbuf[3]) { - case 0x8c: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - - /* If int_urb_due overdue - * set rbuf[1] to 0 to clear lock */ - if (time_after(jiffies, st->int_urb_due)) - rbuf[1] = 0; - - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - default: - break; - } - - deb_info(4, "I2C From Interrupt Message out(%02x) in(%02x)", - wbuf[3], rbuf[1]); - - } - - return ret; + return lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); } - static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { @@ -935,26 +792,8 @@ static struct stv0299_config sharp_z0194_config = { .set_symbol_rate = sharp_z0194a_set_symbol_rate, }; -static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe, - int caller) -{ - struct dvb_usb_adapter *adap = fe_to_adap(fe); - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *st = d->priv; - - mutex_lock(&d->i2c_mutex); - if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) { - st->i2c_talk_onoff = 0; - lme2510_stream_restart(d); - } - mutex_unlock(&d->i2c_mutex); - - return 0; -} - static struct m88rs2000_config m88rs2000_config = { - .demod_addr = 0x68, - .set_ts_params = dm04_rs2000_set_ts_param, + .demod_addr = 0x68 }; static struct ts2020_config ts2020_config = { @@ -998,27 +837,101 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, return (ret < 0) ? -ENODEV : 0; } -static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe, - u16 *strength) +static int dm04_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct dvb_usb_device *d = fe_to_d(fe); + struct lme2510_state *st = d->priv; + int ret = 0; + + if (st->i2c_talk_onoff) { + if (st->fe_read_status) { + ret = st->fe_read_status(fe, status); + if (ret < 0) + return ret; + } + + st->lock_status = *status; + + if (*status & FE_HAS_LOCK && st->stream_on) { + mutex_lock(&d->i2c_mutex); + + st->i2c_talk_onoff = 0; + ret = lme2510_stream_restart(d); + + mutex_unlock(&d->i2c_mutex); + } + + return ret; + } + + /* Timeout of interrupt reached on RS2000 */ + if (st->tuner_config == TUNER_RS2000 && + time_after(jiffies, st->int_urb_due)) + st->lock_status &= ~FE_HAS_LOCK; + + *status = st->lock_status; + + if (!(*status & FE_HAS_LOCK)) + st->i2c_talk_onoff = 1; + + return ret; +} + +static int dm04_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { struct lme2510_state *st = fe_to_priv(fe); - *strength = (u16)((u32)st->signal_level * 0xffff / 0xff); + if (st->fe_read_signal_strength && !st->stream_on) + return st->fe_read_signal_strength(fe, strength); + + switch (st->tuner_config) { + case TUNER_LG: + *strength = 0xff - st->signal_level; + *strength |= *strength << 8; + break; + /* fall through */ + case TUNER_S7395: + case TUNER_S0194: + *strength = 0xffff - (((st->signal_level * 2) << 8) * 5 / 4); + break; + case TUNER_RS2000: + *strength = (u16)((u32)st->signal_level * 0xffff / 0xff); + } return 0; } -static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr) +static int dm04_read_snr(struct dvb_frontend *fe, u16 *snr) { struct lme2510_state *st = fe_to_priv(fe); - *snr = (u16)((u32)st->signal_sn * 0xffff / 0x7f); + if (st->fe_read_snr && !st->stream_on) + return st->fe_read_snr(fe, snr); + + switch (st->tuner_config) { + case TUNER_LG: + *snr = 0xff - st->signal_sn; + *snr |= *snr << 8; + break; + /* fall through */ + case TUNER_S7395: + case TUNER_S0194: + *snr = (u16)((0xff - st->signal_sn - 0xa1) * 3) << 8; + break; + case TUNER_RS2000: + *snr = (u16)((u32)st->signal_sn * 0xffff / 0x7f); + } return 0; } static int dm04_read_ber(struct dvb_frontend *fe, u32 *ber) { + struct lme2510_state *st = fe_to_priv(fe); + + if (st->fe_read_ber && !st->stream_on) + return st->fe_read_ber(fe, ber); + *ber = 0; return 0; @@ -1026,6 +939,11 @@ static int dm04_read_ber(struct dvb_frontend *fe, u32 *ber) static int dm04_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { + struct lme2510_state *st = fe_to_priv(fe); + + if (st->fe_read_ucblocks && !st->stream_on) + return st->fe_read_ucblocks(fe, ucblocks); + *ucblocks = 0; return 0; @@ -1119,15 +1037,6 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) st->tuner_config = TUNER_RS2000; st->fe_set_voltage = adap->fe[0]->ops.set_voltage; - - adap->fe[0]->ops.read_signal_strength = - dm04_rs2000_read_signal_strength; - adap->fe[0]->ops.read_snr = - dm04_rs2000_read_snr; - adap->fe[0]->ops.read_ber = - dm04_read_ber; - adap->fe[0]->ops.read_ucblocks = - dm04_read_ucblocks; } break; } @@ -1146,7 +1055,19 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } + st->fe_read_status = adap->fe[0]->ops.read_status; + st->fe_read_signal_strength = adap->fe[0]->ops.read_signal_strength; + st->fe_read_snr = adap->fe[0]->ops.read_snr; + st->fe_read_ber = adap->fe[0]->ops.read_ber; + st->fe_read_ucblocks = adap->fe[0]->ops.read_ucblocks; + + adap->fe[0]->ops.read_status = dm04_read_status; + adap->fe[0]->ops.read_signal_strength = dm04_read_signal_strength; + adap->fe[0]->ops.read_snr = dm04_read_snr; + adap->fe[0]->ops.read_ber = dm04_read_ber; + adap->fe[0]->ops.read_ucblocks = dm04_read_ucblocks; adap->fe[0]->ops.set_voltage = dm04_lme2510_set_voltage; + ret = lme_name(adap); return ret; } @@ -1288,7 +1209,6 @@ static void *lme2510_exit_int(struct dvb_usb_device *d) if (st->usb_buffer != NULL) { st->i2c_talk_onoff = 1; - st->signal_lock = 0; st->signal_level = 0; st->signal_sn = 0; buffer = st->usb_buffer; diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c index 0a98d04c53e4..ecefa5c477fa 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c @@ -604,9 +604,3 @@ MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver"); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); MODULE_VERSION("0.1"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h index 2d4530f5be54..0bd83e52669c 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h @@ -47,9 +47,3 @@ struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, #endif /* CONFIG_DVB_USB_MXL111SF */ #endif /* __MXL111SF_DEMOD_H__ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c index a619410adde4..2180c13a6dcc 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c @@ -755,9 +755,3 @@ int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode) } return 0; } - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h index b85a5772d771..16fa4d4daf88 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h @@ -48,9 +48,3 @@ int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state, enum mxl111sf_mux_config pin_mux_config); #endif /* _DVB_USB_MXL111SF_GPIO_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c index a101d06eb143..283495c84ba3 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c @@ -842,9 +842,3 @@ int mxl111sf_i2c_xfer(struct i2c_adapter *adap, return i == num ? num : -EREMOTEIO; } - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h index 465762145ad2..c486fe02f018 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h @@ -27,9 +27,3 @@ int mxl111sf_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num); #endif /* _DVB_USB_MXL111SF_I2C_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c index f6b348024bec..5b0191178f9f 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c @@ -335,9 +335,3 @@ int mxl111sf_idac_config(struct mxl111sf_state *state, return ret; } - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h index 0643738de7de..25aa4a1ea755 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h @@ -45,9 +45,3 @@ int mxl111sf_idac_config(struct mxl111sf_state *state, u8 current_value, u8 hysteresis_value); #endif /* _DVB_USB_MXL111SF_PHY_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h index 89bf115e927e..1f4bfbcdbabb 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h @@ -171,9 +171,3 @@ #define V6_DIG_RF_PWR_MSB_REG 0x47 #endif /* _DVB_USB_MXL111SF_REG_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c index a8d2c7053674..444579be0b77 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c @@ -515,11 +515,3 @@ MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver"); MODULE_AUTHOR("Michael Krufky "); MODULE_LICENSE("GPL"); MODULE_VERSION("0.1"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h index 2046db22519e..e6caab21a197 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h @@ -77,12 +77,3 @@ struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, #endif #endif /* __MXL111SF_TUNER_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ - diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index c3447eaf1104..bec12b0e076b 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -1425,9 +1425,3 @@ MODULE_AUTHOR("Michael Krufky "); MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.h b/drivers/media/usb/dvb-usb-v2/mxl111sf.h index 8516c011b7cc..ee70df1f1e94 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.h @@ -152,9 +152,3 @@ extern int dvb_usb_mxl111sf_debug; }) #endif /* _DVB_USB_MXL111SF_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 896a225ee011..77dcfdf547ac 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -22,42 +22,6 @@ #include "rtl28xxu.h" -#include "rtl2830.h" -#include "rtl2832.h" -#include "rtl2832_sdr.h" -#include "mn88472.h" -#include "mn88473.h" - -#include "qt1010.h" -#include "mt2060.h" -#include "mxl5005s.h" -#include "fc0012.h" -#include "fc0013.h" -#include "e4000.h" -#include "fc2580.h" -#include "tua9001.h" -#include "r820t.h" - - -#ifdef CONFIG_MEDIA_ATTACH -#define dvb_attach_sdr(FUNCTION, ARGS...) ({ \ - void *__r = NULL; \ - typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ - if (__a) { \ - __r = (void *) __a(ARGS); \ - if (__r == NULL) \ - symbol_put(FUNCTION); \ - } \ - __r; \ -}) - -#else -#define dvb_attach_sdr(FUNCTION, ARGS...) ({ \ - FUNCTION(ARGS); \ -}) - -#endif - static int rtl28xxu_disable_rc; module_param_named(disable_rc, rtl28xxu_disable_rc, int, 0644); MODULE_PARM_DESC(disable_rc, "disable RTL2832U remote controller"); @@ -65,20 +29,14 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req) { + struct rtl28xxu_dev *dev = d->priv; int ret; unsigned int pipe; u8 requesttype; - u8 *buf; - - buf = kmalloc(req->size, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto err; - } if (req->index & CMD_WR_FLAG) { /* write */ - memcpy(buf, req->data, req->size); + memcpy(dev->buf, req->data, req->size); requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); pipe = usb_sndctrlpipe(d->udev, 0); } else { @@ -88,30 +46,23 @@ static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req) } ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value, - req->index, buf, req->size, 1000); - + req->index, dev->buf, req->size, 1000); dvb_usb_dbg_usb_control_msg(d->udev, 0, requesttype, req->value, - req->index, buf, req->size); - - if (ret > 0) - ret = 0; - - /* read request, copy returned data to return buf */ - if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) - memcpy(req->data, buf, req->size); - - kfree(buf); - - if (ret) + req->index, dev->buf, req->size); + if (ret < 0) goto err; - return ret; + /* read request, copy returned data to return buf */ + if (requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) + memcpy(req->data, dev->buf, req->size); + + return 0; err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } -static int rtl28xx_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) +static int rtl28xxu_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) { struct rtl28xxu_req req; @@ -129,7 +80,7 @@ static int rtl28xx_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) return rtl28xxu_ctrl_msg(d, &req); } -static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) +static int rtl28xxu_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) { struct rtl28xxu_req req; @@ -147,17 +98,17 @@ static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) return rtl28xxu_ctrl_msg(d, &req); } -static int rtl28xx_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val) +static int rtl28xxu_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val) { - return rtl28xx_wr_regs(d, reg, &val, 1); + return rtl28xxu_wr_regs(d, reg, &val, 1); } -static int rtl28xx_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val) +static int rtl28xxu_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val) { - return rtl2831_rd_regs(d, reg, val, 1); + return rtl28xxu_rd_regs(d, reg, val, 1); } -static int rtl28xx_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val, +static int rtl28xxu_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val, u8 mask) { int ret; @@ -165,7 +116,7 @@ static int rtl28xx_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val, /* no need for read if whole reg is written */ if (mask != 0xff) { - ret = rtl28xx_rd_reg(d, reg, &tmp); + ret = rtl28xxu_rd_reg(d, reg, &tmp); if (ret) return ret; @@ -174,7 +125,7 @@ static int rtl28xx_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val, val |= tmp; } - return rtl28xx_wr_reg(d, reg, val); + return rtl28xxu_wr_reg(d, reg, val); } /* I2C */ @@ -183,7 +134,7 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], { int ret; struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct rtl28xxu_priv *priv = d->priv; + struct rtl28xxu_dev *dev = d->priv; struct rtl28xxu_req req; /* @@ -220,7 +171,7 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], } else if (msg[0].addr == 0x10) { /* method 1 - integrated demod */ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); - req.index = CMD_DEMOD_RD | priv->page; + req.index = CMD_DEMOD_RD | dev->page; req.size = msg[1].len; req.data = &msg[1].buf[0]; ret = rtl28xxu_ctrl_msg(d, &req); @@ -256,12 +207,12 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], /* method 1 - integrated demod */ if (msg[0].buf[0] == 0x00) { /* save demod page for later demod access */ - priv->page = msg[0].buf[1]; + dev->page = msg[0].buf[1]; ret = 0; } else { req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); - req.index = CMD_DEMOD_WR | priv->page; + req.index = CMD_DEMOD_WR | dev->page; req.size = msg[0].len-1; req.data = &msg[0].buf[1]; ret = rtl28xxu_ctrl_msg(d, &req); @@ -303,7 +254,7 @@ static struct i2c_algorithm rtl28xxu_i2c_algo = { static int rtl2831u_read_config(struct dvb_usb_device *d) { - struct rtl28xxu_priv *priv = d_to_priv(d); + struct rtl28xxu_dev *dev = d_to_priv(d); int ret; u8 buf[1]; /* open RTL2831U/RTL2830 I2C gate */ @@ -312,7 +263,7 @@ static int rtl2831u_read_config(struct dvb_usb_device *d) struct rtl28xxu_req req_mt2060 = {0x00c0, CMD_I2C_RD, 1, buf}; struct rtl28xxu_req req_qt1010 = {0x0fc4, CMD_I2C_RD, 1, buf}; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + dev_dbg(&d->intf->dev, "\n"); /* * RTL2831U GPIOs @@ -323,12 +274,12 @@ static int rtl2831u_read_config(struct dvb_usb_device *d) */ /* GPIO direction */ - ret = rtl28xx_wr_reg(d, SYS_GPIO_DIR, 0x0a); + ret = rtl28xxu_wr_reg(d, SYS_GPIO_DIR, 0x0a); if (ret) goto err; /* enable as output GPIO0, GPIO2, GPIO4 */ - ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_EN, 0x15); + ret = rtl28xxu_wr_reg(d, SYS_GPIO_OUT_EN, 0x15); if (ret) goto err; @@ -340,7 +291,7 @@ static int rtl2831u_read_config(struct dvb_usb_device *d) /* demod needs some time to wake up */ msleep(20); - priv->tuner_name = "NONE"; + dev->tuner_name = "NONE"; /* open demod I2C gate */ ret = rtl28xxu_ctrl_msg(d, &req_gate_open); @@ -350,8 +301,8 @@ static int rtl2831u_read_config(struct dvb_usb_device *d) /* check QT1010 ID(?) register; reg=0f val=2c */ ret = rtl28xxu_ctrl_msg(d, &req_qt1010); if (ret == 0 && buf[0] == 0x2c) { - priv->tuner = TUNER_RTL2830_QT1010; - priv->tuner_name = "QT1010"; + dev->tuner = TUNER_RTL2830_QT1010; + dev->tuner_name = "QT1010"; goto found; } @@ -363,28 +314,28 @@ static int rtl2831u_read_config(struct dvb_usb_device *d) /* check MT2060 ID register; reg=00 val=63 */ ret = rtl28xxu_ctrl_msg(d, &req_mt2060); if (ret == 0 && buf[0] == 0x63) { - priv->tuner = TUNER_RTL2830_MT2060; - priv->tuner_name = "MT2060"; + dev->tuner = TUNER_RTL2830_MT2060; + dev->tuner_name = "MT2060"; goto found; } /* assume MXL5005S */ - priv->tuner = TUNER_RTL2830_MXL5005S; - priv->tuner_name = "MXL5005S"; + dev->tuner = TUNER_RTL2830_MXL5005S; + dev->tuner_name = "MXL5005S"; goto found; found: - dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name); + dev_dbg(&d->intf->dev, "tuner=%s\n", dev->tuner_name); return 0; err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } static int rtl2832u_read_config(struct dvb_usb_device *d) { - struct rtl28xxu_priv *priv = d_to_priv(d); + struct rtl28xxu_dev *dev = d_to_priv(d); int ret; u8 buf[2]; /* open RTL2832U/RTL2832 I2C gate */ @@ -407,14 +358,14 @@ static int rtl2832u_read_config(struct dvb_usb_device *d) struct rtl28xxu_req req_mn88472 = {0xff38, CMD_I2C_RD, 1, buf}; struct rtl28xxu_req req_mn88473 = {0xff38, CMD_I2C_RD, 1, buf}; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + dev_dbg(&d->intf->dev, "\n"); /* enable GPIO3 and GPIO6 as output */ - ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x40); + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x40); if (ret) goto err; - ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x48, 0x48); + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x48, 0x48); if (ret) goto err; @@ -428,134 +379,134 @@ static int rtl2832u_read_config(struct dvb_usb_device *d) if (ret) goto err; - priv->tuner_name = "NONE"; + dev->tuner_name = "NONE"; /* check FC0012 ID register; reg=00 val=a1 */ ret = rtl28xxu_ctrl_msg(d, &req_fc0012); if (ret == 0 && buf[0] == 0xa1) { - priv->tuner = TUNER_RTL2832_FC0012; - priv->tuner_name = "FC0012"; + dev->tuner = TUNER_RTL2832_FC0012; + dev->tuner_name = "FC0012"; goto tuner_found; } /* check FC0013 ID register; reg=00 val=a3 */ ret = rtl28xxu_ctrl_msg(d, &req_fc0013); if (ret == 0 && buf[0] == 0xa3) { - priv->tuner = TUNER_RTL2832_FC0013; - priv->tuner_name = "FC0013"; + dev->tuner = TUNER_RTL2832_FC0013; + dev->tuner_name = "FC0013"; goto tuner_found; } /* check MT2266 ID register; reg=00 val=85 */ ret = rtl28xxu_ctrl_msg(d, &req_mt2266); if (ret == 0 && buf[0] == 0x85) { - priv->tuner = TUNER_RTL2832_MT2266; - priv->tuner_name = "MT2266"; + dev->tuner = TUNER_RTL2832_MT2266; + dev->tuner_name = "MT2266"; goto tuner_found; } /* check FC2580 ID register; reg=01 val=56 */ ret = rtl28xxu_ctrl_msg(d, &req_fc2580); if (ret == 0 && buf[0] == 0x56) { - priv->tuner = TUNER_RTL2832_FC2580; - priv->tuner_name = "FC2580"; + dev->tuner = TUNER_RTL2832_FC2580; + dev->tuner_name = "FC2580"; goto tuner_found; } /* check MT2063 ID register; reg=00 val=9e || 9c */ ret = rtl28xxu_ctrl_msg(d, &req_mt2063); if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) { - priv->tuner = TUNER_RTL2832_MT2063; - priv->tuner_name = "MT2063"; + dev->tuner = TUNER_RTL2832_MT2063; + dev->tuner_name = "MT2063"; goto tuner_found; } /* check MAX3543 ID register; reg=00 val=38 */ ret = rtl28xxu_ctrl_msg(d, &req_max3543); if (ret == 0 && buf[0] == 0x38) { - priv->tuner = TUNER_RTL2832_MAX3543; - priv->tuner_name = "MAX3543"; + dev->tuner = TUNER_RTL2832_MAX3543; + dev->tuner_name = "MAX3543"; goto tuner_found; } /* check TUA9001 ID register; reg=7e val=2328 */ ret = rtl28xxu_ctrl_msg(d, &req_tua9001); if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) { - priv->tuner = TUNER_RTL2832_TUA9001; - priv->tuner_name = "TUA9001"; + dev->tuner = TUNER_RTL2832_TUA9001; + dev->tuner_name = "TUA9001"; goto tuner_found; } /* check MXL5007R ID register; reg=d9 val=14 */ ret = rtl28xxu_ctrl_msg(d, &req_mxl5007t); if (ret == 0 && buf[0] == 0x14) { - priv->tuner = TUNER_RTL2832_MXL5007T; - priv->tuner_name = "MXL5007T"; + dev->tuner = TUNER_RTL2832_MXL5007T; + dev->tuner_name = "MXL5007T"; goto tuner_found; } /* check E4000 ID register; reg=02 val=40 */ ret = rtl28xxu_ctrl_msg(d, &req_e4000); if (ret == 0 && buf[0] == 0x40) { - priv->tuner = TUNER_RTL2832_E4000; - priv->tuner_name = "E4000"; + dev->tuner = TUNER_RTL2832_E4000; + dev->tuner_name = "E4000"; goto tuner_found; } /* check TDA18272 ID register; reg=00 val=c760 */ ret = rtl28xxu_ctrl_msg(d, &req_tda18272); if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) { - priv->tuner = TUNER_RTL2832_TDA18272; - priv->tuner_name = "TDA18272"; + dev->tuner = TUNER_RTL2832_TDA18272; + dev->tuner_name = "TDA18272"; goto tuner_found; } /* check R820T ID register; reg=00 val=69 */ ret = rtl28xxu_ctrl_msg(d, &req_r820t); if (ret == 0 && buf[0] == 0x69) { - priv->tuner = TUNER_RTL2832_R820T; - priv->tuner_name = "R820T"; + dev->tuner = TUNER_RTL2832_R820T; + dev->tuner_name = "R820T"; goto tuner_found; } /* check R828D ID register; reg=00 val=69 */ ret = rtl28xxu_ctrl_msg(d, &req_r828d); if (ret == 0 && buf[0] == 0x69) { - priv->tuner = TUNER_RTL2832_R828D; - priv->tuner_name = "R828D"; + dev->tuner = TUNER_RTL2832_R828D; + dev->tuner_name = "R828D"; goto tuner_found; } tuner_found: - dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name); + dev_dbg(&d->intf->dev, "tuner=%s\n", dev->tuner_name); /* probe slave demod */ - if (priv->tuner == TUNER_RTL2832_R828D) { + if (dev->tuner == TUNER_RTL2832_R828D) { /* power on MN88472 demod on GPIO0 */ - ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x01, 0x01); + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x01, 0x01); if (ret) goto err; - ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x01); + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x01); if (ret) goto err; - ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x01, 0x01); + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x01, 0x01); if (ret) goto err; /* check MN88472 answers */ ret = rtl28xxu_ctrl_msg(d, &req_mn88472); if (ret == 0 && buf[0] == 0x02) { - dev_dbg(&d->udev->dev, "%s: MN88472 found\n", __func__); - priv->slave_demod = SLAVE_DEMOD_MN88472; + dev_dbg(&d->intf->dev, "MN88472 found\n"); + dev->slave_demod = SLAVE_DEMOD_MN88472; goto demod_found; } ret = rtl28xxu_ctrl_msg(d, &req_mn88473); if (ret == 0 && buf[0] == 0x03) { - dev_dbg(&d->udev->dev, "%s: MN88473 found\n", __func__); - priv->slave_demod = SLAVE_DEMOD_MN88473; + dev_dbg(&d->intf->dev, "MN88473 found\n"); + dev->slave_demod = SLAVE_DEMOD_MN88473; goto demod_found; } } @@ -568,14 +519,51 @@ demod_found: return 0; err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } -static const struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = { - .i2c_addr = 0x10, /* 0x20 */ - .xtal = 28800000, - .ts_mode = 0, +static int rtl28xxu_read_config(struct dvb_usb_device *d) +{ + struct rtl28xxu_dev *dev = d_to_priv(d); + + if (dev->chip_id == CHIP_ID_RTL2831U) + return rtl2831u_read_config(d); + else + return rtl2832u_read_config(d); +} + +static int rtl28xxu_identify_state(struct dvb_usb_device *d, const char **name) +{ + struct rtl28xxu_dev *dev = d_to_priv(d); + int ret; + struct rtl28xxu_req req_demod_i2c = {0x0020, CMD_I2C_DA_RD, 0, NULL}; + + dev_dbg(&d->intf->dev, "\n"); + + /* + * Detect chip type using I2C command that is not supported + * by old RTL2831U. + */ + ret = rtl28xxu_ctrl_msg(d, &req_demod_i2c); + if (ret == -EPIPE) { + dev->chip_id = CHIP_ID_RTL2831U; + } else if (ret == 0) { + dev->chip_id = CHIP_ID_RTL2832U; + } else { + dev_err(&d->intf->dev, "chip type detection failed %d\n", ret); + goto err; + } + dev_dbg(&d->intf->dev, "chip_id=%u\n", dev->chip_id); + + return WARM; +err: + dev_dbg(&d->intf->dev, "failed=%d\n", ret); + return ret; +} + +static const struct rtl2830_platform_data rtl2830_mt2060_platform_data = { + .clk = 28800000, .spec_inv = 1, .vtop = 0x20, .krf = 0x04, @@ -583,20 +571,16 @@ static const struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = { }; -static const struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = { - .i2c_addr = 0x10, /* 0x20 */ - .xtal = 28800000, - .ts_mode = 0, +static const struct rtl2830_platform_data rtl2830_qt1010_platform_data = { + .clk = 28800000, .spec_inv = 1, .vtop = 0x20, .krf = 0x04, .agc_targ_val = 0x2d, }; -static const struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = { - .i2c_addr = 0x10, /* 0x20 */ - .xtal = 28800000, - .ts_mode = 0, +static const struct rtl2830_platform_data rtl2830_mxl5005s_platform_data = { + .clk = 28800000, .spec_inv = 0, .vtop = 0x3f, .krf = 0x04, @@ -606,69 +590,81 @@ static const struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = { static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap) { struct dvb_usb_device *d = adap_to_d(adap); - struct rtl28xxu_priv *priv = d_to_priv(d); - const struct rtl2830_config *rtl2830_config; + struct rtl28xxu_dev *dev = d_to_priv(d); + struct rtl2830_platform_data *pdata = &dev->rtl2830_platform_data; + struct i2c_board_info board_info; + struct i2c_client *client; int ret; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + dev_dbg(&d->intf->dev, "\n"); - switch (priv->tuner) { + switch (dev->tuner) { case TUNER_RTL2830_QT1010: - rtl2830_config = &rtl28xxu_rtl2830_qt1010_config; + *pdata = rtl2830_qt1010_platform_data; break; case TUNER_RTL2830_MT2060: - rtl2830_config = &rtl28xxu_rtl2830_mt2060_config; + *pdata = rtl2830_mt2060_platform_data; break; case TUNER_RTL2830_MXL5005S: - rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config; + *pdata = rtl2830_mxl5005s_platform_data; break; default: - dev_err(&d->udev->dev, "%s: unknown tuner=%s\n", - KBUILD_MODNAME, priv->tuner_name); + dev_err(&d->intf->dev, "unknown tuner %s\n", dev->tuner_name); ret = -ENODEV; goto err; } /* attach demodulator */ - adap->fe[0] = dvb_attach(rtl2830_attach, rtl2830_config, &d->i2c_adap); - if (!adap->fe[0]) { + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "rtl2830", I2C_NAME_SIZE); + board_info.addr = 0x10; + board_info.platform_data = pdata; + request_module("%s", board_info.type); + client = i2c_new_device(&d->i2c_adap, &board_info); + if (client == NULL || client->dev.driver == NULL) { ret = -ENODEV; goto err; } + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + ret = -ENODEV; + goto err; + } + + adap->fe[0] = pdata->get_dvb_frontend(client); + dev->demod_i2c_adapter = pdata->get_i2c_adapter(client); + + dev->i2c_client_demod = client; + return 0; err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } -static const struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = { - .i2c_addr = 0x10, /* 0x20 */ - .xtal = 28800000, +static const struct rtl2832_platform_data rtl2832_fc0012_platform_data = { + .clk = 28800000, .tuner = TUNER_RTL2832_FC0012 }; -static const struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = { - .i2c_addr = 0x10, /* 0x20 */ - .xtal = 28800000, +static const struct rtl2832_platform_data rtl2832_fc0013_platform_data = { + .clk = 28800000, .tuner = TUNER_RTL2832_FC0013 }; -static const struct rtl2832_config rtl28xxu_rtl2832_tua9001_config = { - .i2c_addr = 0x10, /* 0x20 */ - .xtal = 28800000, +static const struct rtl2832_platform_data rtl2832_tua9001_platform_data = { + .clk = 28800000, .tuner = TUNER_RTL2832_TUA9001, }; -static const struct rtl2832_config rtl28xxu_rtl2832_e4000_config = { - .i2c_addr = 0x10, /* 0x20 */ - .xtal = 28800000, +static const struct rtl2832_platform_data rtl2832_e4000_platform_data = { + .clk = 28800000, .tuner = TUNER_RTL2832_E4000, }; -static const struct rtl2832_config rtl28xxu_rtl2832_r820t_config = { - .i2c_addr = 0x10, - .xtal = 28800000, +static const struct rtl2832_platform_data rtl2832_r820t_platform_data = { + .clk = 28800000, .tuner = TUNER_RTL2832_R820T, }; @@ -678,12 +674,12 @@ static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d, int ret; u8 val; - dev_dbg(&d->udev->dev, "%s: cmd=%d arg=%d\n", __func__, cmd, arg); + dev_dbg(&d->intf->dev, "cmd=%d arg=%d\n", cmd, arg); switch (cmd) { case FC_FE_CALLBACK_VHF_ENABLE: /* set output values */ - ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val); + ret = rtl28xxu_rd_reg(d, SYS_GPIO_OUT_VAL, &val); if (ret) goto err; @@ -693,7 +689,7 @@ static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d, val |= 0x40; /* set GPIO6 high */ - ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val); + ret = rtl28xxu_wr_reg(d, SYS_GPIO_OUT_VAL, val); if (ret) goto err; break; @@ -703,7 +699,7 @@ static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d, } return 0; err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } @@ -713,7 +709,7 @@ static int rtl2832u_tua9001_tuner_callback(struct dvb_usb_device *d, int ret; u8 val; - dev_dbg(&d->udev->dev, "%s: cmd=%d arg=%d\n", __func__, cmd, arg); + dev_dbg(&d->intf->dev, "cmd=%d arg=%d\n", cmd, arg); /* * CEN always enabled by hardware wiring @@ -728,7 +724,7 @@ static int rtl2832u_tua9001_tuner_callback(struct dvb_usb_device *d, else val = (0 << 4); - ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, val, 0x10); + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, val, 0x10); if (ret) goto err; break; @@ -738,7 +734,7 @@ static int rtl2832u_tua9001_tuner_callback(struct dvb_usb_device *d, else val = (0 << 1); - ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, val, 0x02); + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, val, 0x02); if (ret) goto err; break; @@ -746,40 +742,46 @@ static int rtl2832u_tua9001_tuner_callback(struct dvb_usb_device *d, return 0; err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } -static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) -{ - struct rtl28xxu_priv *priv = d->priv; - - switch (priv->tuner) { - case TUNER_RTL2832_FC0012: - return rtl2832u_fc0012_tuner_callback(d, cmd, arg); - case TUNER_RTL2832_TUA9001: - return rtl2832u_tua9001_tuner_callback(d, cmd, arg); - default: - break; - } - - return 0; -} - static int rtl2832u_frontend_callback(void *adapter_priv, int component, int cmd, int arg) { - struct i2c_adapter *adap = adapter_priv; - struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct i2c_adapter *adapter = adapter_priv; + struct device *parent = adapter->dev.parent; + struct i2c_adapter *parent_adapter; + struct dvb_usb_device *d; + struct rtl28xxu_dev *dev; - dev_dbg(&d->udev->dev, "%s: component=%d cmd=%d arg=%d\n", - __func__, component, cmd, arg); + /* + * All tuners are connected to demod muxed I2C adapter. We have to + * resolve its parent adapter in order to get handle for this driver + * private data. That is a bit hackish solution, GPIO or direct driver + * callback would be better... + */ + if (parent != NULL && parent->type == &i2c_adapter_type) + parent_adapter = to_i2c_adapter(parent); + else + return -EINVAL; + + d = i2c_get_adapdata(parent_adapter); + dev = d->priv; + + dev_dbg(&d->intf->dev, "component=%d cmd=%d arg=%d\n", + component, cmd, arg); switch (component) { case DVB_FRONTEND_COMPONENT_TUNER: - return rtl2832u_tuner_callback(d, cmd, arg); + switch (dev->tuner) { + case TUNER_RTL2832_FC0012: + return rtl2832u_fc0012_tuner_callback(d, cmd, arg); + case TUNER_RTL2832_TUA9001: + return rtl2832u_tua9001_tuner_callback(d, cmd, arg); + } default: - break; + return -EINVAL; } return 0; @@ -787,57 +789,70 @@ static int rtl2832u_frontend_callback(void *adapter_priv, int component, static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) { - int ret; struct dvb_usb_device *d = adap_to_d(adap); - struct rtl28xxu_priv *priv = d_to_priv(d); - const struct rtl2832_config *rtl2832_config; + struct rtl28xxu_dev *dev = d_to_priv(d); + struct rtl2832_platform_data *pdata = &dev->rtl2832_platform_data; + struct i2c_board_info board_info; + struct i2c_client *client; + int ret; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + dev_dbg(&d->intf->dev, "\n"); - switch (priv->tuner) { + switch (dev->tuner) { case TUNER_RTL2832_FC0012: - rtl2832_config = &rtl28xxu_rtl2832_fc0012_config; + *pdata = rtl2832_fc0012_platform_data; break; case TUNER_RTL2832_FC0013: - rtl2832_config = &rtl28xxu_rtl2832_fc0013_config; + *pdata = rtl2832_fc0013_platform_data; break; case TUNER_RTL2832_FC2580: /* FIXME: do not abuse fc0012 settings */ - rtl2832_config = &rtl28xxu_rtl2832_fc0012_config; + *pdata = rtl2832_fc0012_platform_data; break; case TUNER_RTL2832_TUA9001: - rtl2832_config = &rtl28xxu_rtl2832_tua9001_config; + *pdata = rtl2832_tua9001_platform_data; break; case TUNER_RTL2832_E4000: - rtl2832_config = &rtl28xxu_rtl2832_e4000_config; + *pdata = rtl2832_e4000_platform_data; break; case TUNER_RTL2832_R820T: case TUNER_RTL2832_R828D: - rtl2832_config = &rtl28xxu_rtl2832_r820t_config; + *pdata = rtl2832_r820t_platform_data; break; default: - dev_err(&d->udev->dev, "%s: unknown tuner=%s\n", - KBUILD_MODNAME, priv->tuner_name); + dev_err(&d->intf->dev, "unknown tuner %s\n", dev->tuner_name); ret = -ENODEV; goto err; } /* attach demodulator */ - adap->fe[0] = dvb_attach(rtl2832_attach, rtl2832_config, &d->i2c_adap); - if (!adap->fe[0]) { + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "rtl2832", I2C_NAME_SIZE); + board_info.addr = 0x10; + board_info.platform_data = pdata; + request_module("%s", board_info.type); + client = i2c_new_device(&d->i2c_adap, &board_info); + if (client == NULL || client->dev.driver == NULL) { ret = -ENODEV; goto err; } - /* RTL2832 I2C repeater */ - priv->demod_i2c_adapter = rtl2832_get_i2c_adapter(adap->fe[0]); + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + ret = -ENODEV; + goto err; + } + + adap->fe[0] = pdata->get_dvb_frontend(client); + dev->demod_i2c_adapter = pdata->get_i2c_adapter(client); + + dev->i2c_client_demod = client; /* set fe callback */ adap->fe[0]->callback = rtl2832u_frontend_callback; - if (priv->slave_demod) { + if (dev->slave_demod) { struct i2c_board_info info = {}; - struct i2c_client *client; /* * We continue on reduced mode, without DVB-T2/C, using master @@ -846,28 +861,29 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) ret = 0; /* attach slave demodulator */ - if (priv->slave_demod == SLAVE_DEMOD_MN88472) { + if (dev->slave_demod == SLAVE_DEMOD_MN88472) { struct mn88472_config mn88472_config = {}; mn88472_config.fe = &adap->fe[1]; mn88472_config.i2c_wr_max = 22, strlcpy(info.type, "mn88472", I2C_NAME_SIZE); + mn88472_config.xtal = 20500000; info.addr = 0x18; info.platform_data = &mn88472_config; request_module(info.type); - client = i2c_new_device(priv->demod_i2c_adapter, &info); + client = i2c_new_device(&d->i2c_adap, &info); if (client == NULL || client->dev.driver == NULL) { - priv->slave_demod = SLAVE_DEMOD_NONE; + dev->slave_demod = SLAVE_DEMOD_NONE; goto err_slave_demod_failed; } if (!try_module_get(client->dev.driver->owner)) { i2c_unregister_device(client); - priv->slave_demod = SLAVE_DEMOD_NONE; + dev->slave_demod = SLAVE_DEMOD_NONE; goto err_slave_demod_failed; } - priv->i2c_client_slave_demod = client; + dev->i2c_client_slave_demod = client; } else { struct mn88473_config mn88473_config = {}; @@ -877,29 +893,64 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) info.addr = 0x18; info.platform_data = &mn88473_config; request_module(info.type); - client = i2c_new_device(priv->demod_i2c_adapter, &info); + client = i2c_new_device(&d->i2c_adap, &info); if (client == NULL || client->dev.driver == NULL) { - priv->slave_demod = SLAVE_DEMOD_NONE; + dev->slave_demod = SLAVE_DEMOD_NONE; goto err_slave_demod_failed; } if (!try_module_get(client->dev.driver->owner)) { i2c_unregister_device(client); - priv->slave_demod = SLAVE_DEMOD_NONE; + dev->slave_demod = SLAVE_DEMOD_NONE; goto err_slave_demod_failed; } - priv->i2c_client_slave_demod = client; + dev->i2c_client_slave_demod = client; } } return 0; err_slave_demod_failed: err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } +static int rtl28xxu_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct rtl28xxu_dev *dev = adap_to_priv(adap); + + if (dev->chip_id == CHIP_ID_RTL2831U) + return rtl2831u_frontend_attach(adap); + else + return rtl2832u_frontend_attach(adap); +} + +static int rtl28xxu_frontend_detach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct rtl28xxu_dev *dev = d_to_priv(d); + struct i2c_client *client; + + dev_dbg(&d->intf->dev, "\n"); + + /* remove I2C slave demod */ + client = dev->i2c_client_slave_demod; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + /* remove I2C demod */ + client = dev->i2c_client_demod; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + return 0; +} + static struct qt1010_config rtl28xxu_qt1010_config = { .i2c_address = 0x62, /* 0xc4 */ }; @@ -930,33 +981,30 @@ static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap) { int ret; struct dvb_usb_device *d = adap_to_d(adap); - struct rtl28xxu_priv *priv = d_to_priv(d); - struct i2c_adapter *rtl2830_tuner_i2c; + struct rtl28xxu_dev *dev = d_to_priv(d); struct dvb_frontend *fe; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + dev_dbg(&d->intf->dev, "\n"); - /* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */ - rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe[0]); - - switch (priv->tuner) { + switch (dev->tuner) { case TUNER_RTL2830_QT1010: fe = dvb_attach(qt1010_attach, adap->fe[0], - rtl2830_tuner_i2c, &rtl28xxu_qt1010_config); + dev->demod_i2c_adapter, + &rtl28xxu_qt1010_config); break; case TUNER_RTL2830_MT2060: fe = dvb_attach(mt2060_attach, adap->fe[0], - rtl2830_tuner_i2c, &rtl28xxu_mt2060_config, - 1220); + dev->demod_i2c_adapter, + &rtl28xxu_mt2060_config, 1220); break; case TUNER_RTL2830_MXL5005S: fe = dvb_attach(mxl5005s_attach, adap->fe[0], - rtl2830_tuner_i2c, &rtl28xxu_mxl5005s_config); + dev->demod_i2c_adapter, + &rtl28xxu_mxl5005s_config); break; default: fe = NULL; - dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME, - priv->tuner); + dev_err(&d->intf->dev, "unknown tuner %d\n", dev->tuner); } if (fe == NULL) { @@ -966,7 +1014,7 @@ static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap) return 0; err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } @@ -1002,45 +1050,38 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) { int ret; struct dvb_usb_device *d = adap_to_d(adap); - struct rtl28xxu_priv *priv = d_to_priv(d); + struct rtl28xxu_dev *dev = d_to_priv(d); struct dvb_frontend *fe = NULL; struct i2c_board_info info; struct i2c_client *client; + struct v4l2_subdev *subdev = NULL; + struct platform_device *pdev; + struct rtl2832_sdr_platform_data pdata; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + dev_dbg(&d->intf->dev, "\n"); memset(&info, 0, sizeof(struct i2c_board_info)); + memset(&pdata, 0, sizeof(pdata)); - switch (priv->tuner) { + switch (dev->tuner) { case TUNER_RTL2832_FC0012: fe = dvb_attach(fc0012_attach, adap->fe[0], - &d->i2c_adap, &rtl2832u_fc0012_config); + dev->demod_i2c_adapter, &rtl2832u_fc0012_config); /* since fc0012 includs reading the signal strength delegate * that to the tuner driver */ adap->fe[0]->ops.read_signal_strength = adap->fe[0]->ops.tuner_ops.get_rf_strength; - - /* attach SDR */ - dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, - &rtl28xxu_rtl2832_fc0012_config, NULL); break; case TUNER_RTL2832_FC0013: fe = dvb_attach(fc0013_attach, adap->fe[0], - &d->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ); + dev->demod_i2c_adapter, 0xc6>>1, 0, FC_XTAL_28_8_MHZ); /* fc0013 also supports signal strength reading */ adap->fe[0]->ops.read_signal_strength = adap->fe[0]->ops.tuner_ops.get_rf_strength; - - /* attach SDR */ - dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, - &rtl28xxu_rtl2832_fc0013_config, NULL); break; case TUNER_RTL2832_E4000: { - struct v4l2_subdev *sd; - struct i2c_adapter *i2c_adap_internal = - rtl2832_get_private_i2c_adapter(adap->fe[0]); struct e4000_config e4000_config = { .fe = adap->fe[0], .clock = 28800000, @@ -1051,7 +1092,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) info.platform_data = &e4000_config; request_module(info.type); - client = i2c_new_device(priv->demod_i2c_adapter, &info); + client = i2c_new_device(dev->demod_i2c_adapter, &info); if (client == NULL || client->dev.driver == NULL) break; @@ -1060,157 +1101,183 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) break; } - priv->i2c_client_tuner = client; - sd = i2c_get_clientdata(client); - i2c_set_adapdata(i2c_adap_internal, d); - - /* attach SDR */ - dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], - i2c_adap_internal, - &rtl28xxu_rtl2832_e4000_config, sd); + dev->i2c_client_tuner = client; + subdev = i2c_get_clientdata(client); } break; case TUNER_RTL2832_FC2580: - fe = dvb_attach(fc2580_attach, adap->fe[0], &d->i2c_adap, + fe = dvb_attach(fc2580_attach, adap->fe[0], + dev->demod_i2c_adapter, &rtl2832u_fc2580_config); break; case TUNER_RTL2832_TUA9001: /* enable GPIO1 and GPIO4 as output */ - ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x12); + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x12); if (ret) goto err; - ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x12, 0x12); + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x12, 0x12); if (ret) goto err; - fe = dvb_attach(tua9001_attach, adap->fe[0], &d->i2c_adap, + fe = dvb_attach(tua9001_attach, adap->fe[0], + dev->demod_i2c_adapter, &rtl2832u_tua9001_config); break; case TUNER_RTL2832_R820T: - fe = dvb_attach(r820t_attach, adap->fe[0], &d->i2c_adap, + fe = dvb_attach(r820t_attach, adap->fe[0], + dev->demod_i2c_adapter, &rtl2832u_r820t_config); /* Use tuner to get the signal strength */ adap->fe[0]->ops.read_signal_strength = adap->fe[0]->ops.tuner_ops.get_rf_strength; - - /* attach SDR */ - dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, - &rtl28xxu_rtl2832_r820t_config, NULL); break; case TUNER_RTL2832_R828D: fe = dvb_attach(r820t_attach, adap->fe[0], - priv->demod_i2c_adapter, + dev->demod_i2c_adapter, &rtl2832u_r828d_config); adap->fe[0]->ops.read_signal_strength = adap->fe[0]->ops.tuner_ops.get_rf_strength; if (adap->fe[1]) { fe = dvb_attach(r820t_attach, adap->fe[1], - priv->demod_i2c_adapter, + dev->demod_i2c_adapter, &rtl2832u_r828d_config); adap->fe[1]->ops.read_signal_strength = adap->fe[1]->ops.tuner_ops.get_rf_strength; } - - /* attach SDR */ - dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, - &rtl28xxu_rtl2832_r820t_config, NULL); break; default: - dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME, - priv->tuner); + dev_err(&d->intf->dev, "unknown tuner %d\n", dev->tuner); } - - if (fe == NULL && priv->i2c_client_tuner == NULL) { + if (fe == NULL && dev->i2c_client_tuner == NULL) { ret = -ENODEV; goto err; } + /* register SDR */ + switch (dev->tuner) { + case TUNER_RTL2832_FC0012: + case TUNER_RTL2832_FC0013: + case TUNER_RTL2832_E4000: + case TUNER_RTL2832_R820T: + case TUNER_RTL2832_R828D: + pdata.clk = dev->rtl2832_platform_data.clk; + pdata.tuner = dev->tuner; + pdata.i2c_client = dev->i2c_client_demod; + pdata.bulk_read = dev->rtl2832_platform_data.bulk_read; + pdata.bulk_write = dev->rtl2832_platform_data.bulk_write; + pdata.update_bits = dev->rtl2832_platform_data.update_bits; + pdata.dvb_frontend = adap->fe[0]; + pdata.dvb_usb_device = d; + pdata.v4l2_subdev = subdev; + + request_module("%s", "rtl2832_sdr"); + pdev = platform_device_register_data(&d->intf->dev, + "rtl2832_sdr", + PLATFORM_DEVID_AUTO, + &pdata, sizeof(pdata)); + if (pdev == NULL || pdev->dev.driver == NULL) + break; + dev->platform_device_sdr = pdev; + break; + default: + dev_dbg(&d->intf->dev, "no SDR for tuner=%d\n", dev->tuner); + } + return 0; err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } +static int rtl28xxu_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct rtl28xxu_dev *dev = adap_to_priv(adap); + + if (dev->chip_id == CHIP_ID_RTL2831U) + return rtl2831u_tuner_attach(adap); + else + return rtl2832u_tuner_attach(adap); +} + +static int rtl28xxu_tuner_detach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap_to_d(adap); + struct rtl28xxu_dev *dev = d_to_priv(d); + struct i2c_client *client; + struct platform_device *pdev; + + dev_dbg(&d->intf->dev, "\n"); + + /* remove platform SDR */ + pdev = dev->platform_device_sdr; + if (pdev) + platform_device_unregister(pdev); + + /* remove I2C tuner */ + client = dev->i2c_client_tuner; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + return 0; +} + static int rtl28xxu_init(struct dvb_usb_device *d) { int ret; u8 val; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + dev_dbg(&d->intf->dev, "\n"); /* init USB endpoints */ - ret = rtl28xx_rd_reg(d, USB_SYSCTL_0, &val); + ret = rtl28xxu_rd_reg(d, USB_SYSCTL_0, &val); if (ret) goto err; /* enable DMA and Full Packet Mode*/ val |= 0x09; - ret = rtl28xx_wr_reg(d, USB_SYSCTL_0, val); + ret = rtl28xxu_wr_reg(d, USB_SYSCTL_0, val); if (ret) goto err; /* set EPA maximum packet size to 0x0200 */ - ret = rtl28xx_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4); + ret = rtl28xxu_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4); if (ret) goto err; /* change EPA FIFO length */ - ret = rtl28xx_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4); + ret = rtl28xxu_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4); if (ret) goto err; return ret; err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } -static void rtl28xxu_exit(struct dvb_usb_device *d) -{ - struct rtl28xxu_priv *priv = d->priv; - struct i2c_client *client; - - dev_dbg(&d->udev->dev, "%s:\n", __func__); - - /* remove I2C tuner */ - client = priv->i2c_client_tuner; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } - - /* remove I2C slave demod */ - client = priv->i2c_client_slave_demod; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } - - return; -} - static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff) { int ret; u8 gpio, sys0, epa_ctl[2]; - dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); + dev_dbg(&d->intf->dev, "onoff=%d\n", onoff); /* demod adc */ - ret = rtl28xx_rd_reg(d, SYS_SYS0, &sys0); + ret = rtl28xxu_rd_reg(d, SYS_SYS0, &sys0); if (ret) goto err; /* tuner power, read GPIOs */ - ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio); + ret = rtl28xxu_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio); if (ret) goto err; - dev_dbg(&d->udev->dev, "%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, - sys0, gpio); + dev_dbg(&d->intf->dev, "RD SYS0=%02x GPIO_OUT_VAL=%02x\n", sys0, gpio); if (onoff) { gpio |= 0x01; /* GPIO0 = 1 */ @@ -1229,21 +1296,20 @@ static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff) epa_ctl[1] = 0x02; /* set reset */ } - dev_dbg(&d->udev->dev, "%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, - sys0, gpio); + dev_dbg(&d->intf->dev, "WR SYS0=%02x GPIO_OUT_VAL=%02x\n", sys0, gpio); /* demod adc */ - ret = rtl28xx_wr_reg(d, SYS_SYS0, sys0); + ret = rtl28xxu_wr_reg(d, SYS_SYS0, sys0); if (ret) goto err; /* tuner power, write GPIOs */ - ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, gpio); + ret = rtl28xxu_wr_reg(d, SYS_GPIO_OUT_VAL, gpio); if (ret) goto err; /* streaming EP: stall & reset */ - ret = rtl28xx_wr_regs(d, USB_EPA_CTL, epa_ctl, 2); + ret = rtl28xxu_wr_regs(d, USB_EPA_CTL, epa_ctl, 2); if (ret) goto err; @@ -1252,7 +1318,7 @@ static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff) return ret; err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } @@ -1260,31 +1326,31 @@ static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff) { int ret; - dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); + dev_dbg(&d->intf->dev, "onoff=%d\n", onoff); if (onoff) { /* GPIO3=1, GPIO4=0 */ - ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x08, 0x18); + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x08, 0x18); if (ret) goto err; /* suspend? */ - ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL1, 0x00, 0x10); + ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL1, 0x00, 0x10); if (ret) goto err; /* enable PLL */ - ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x80, 0x80); + ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL, 0x80, 0x80); if (ret) goto err; /* disable reset */ - ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x20, 0x20); + ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL, 0x20, 0x20); if (ret) goto err; /* streaming EP: clear stall & reset */ - ret = rtl28xx_wr_regs(d, USB_EPA_CTL, "\x00\x00", 2); + ret = rtl28xxu_wr_regs(d, USB_EPA_CTL, "\x00\x00", 2); if (ret) goto err; @@ -1293,35 +1359,49 @@ static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff) goto err; } else { /* GPIO4=1 */ - ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x10, 0x10); + ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x10, 0x10); if (ret) goto err; /* disable PLL */ - ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x00, 0x80); + ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL, 0x00, 0x80); if (ret) goto err; /* streaming EP: set stall & reset */ - ret = rtl28xx_wr_regs(d, USB_EPA_CTL, "\x10\x02", 2); + ret = rtl28xxu_wr_regs(d, USB_EPA_CTL, "\x10\x02", 2); if (ret) goto err; } return ret; err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } -static int rtl2832u_frontend_ctrl(struct dvb_frontend *fe, int onoff) +static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + struct rtl28xxu_dev *dev = d_to_priv(d); + + if (dev->chip_id == CHIP_ID_RTL2831U) + return rtl2831u_power_ctrl(d, onoff); + else + return rtl2832u_power_ctrl(d, onoff); +} + +static int rtl28xxu_frontend_ctrl(struct dvb_frontend *fe, int onoff) { struct dvb_usb_device *d = fe_to_d(fe); - struct dvb_usb_adapter *adap = fe_to_adap(fe); + struct rtl28xxu_dev *dev = fe_to_priv(fe); + struct rtl2832_platform_data *pdata = &dev->rtl2832_platform_data; int ret; u8 val; - dev_dbg(&d->udev->dev, "%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); + dev_dbg(&d->intf->dev, "fe=%d onoff=%d\n", fe->id, onoff); + + if (dev->chip_id == CHIP_ID_RTL2831U) + return 0; /* control internal demod ADC */ if (fe->id == 0 && onoff) @@ -1329,20 +1409,20 @@ static int rtl2832u_frontend_ctrl(struct dvb_frontend *fe, int onoff) else val = 0x00; /* disable ADC */ - ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, val, 0x48); + ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL, val, 0x48); if (ret) goto err; /* bypass slave demod TS through master demod */ if (fe->id == 1 && onoff) { - ret = rtl2832_enable_external_ts_if(adap->fe[0]); + ret = pdata->enable_slave_ts(dev->i2c_client_demod); if (ret) goto err; } return 0; err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } @@ -1350,7 +1430,7 @@ err: static int rtl2831u_rc_query(struct dvb_usb_device *d) { int ret, i; - struct rtl28xxu_priv *priv = d->priv; + struct rtl28xxu_dev *dev = d->priv; u8 buf[5]; u32 rc_code; struct rtl28xxu_reg_val rc_nec_tab[] = { @@ -1371,17 +1451,17 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d) }; /* init remote controller */ - if (!priv->rc_active) { + if (!dev->rc_active) { for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) { - ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg, + ret = rtl28xxu_wr_reg(d, rc_nec_tab[i].reg, rc_nec_tab[i].val); if (ret) goto err; } - priv->rc_active = true; + dev->rc_active = true; } - ret = rtl2831_rd_regs(d, SYS_IRRC_RP, buf, 5); + ret = rtl28xxu_rd_regs(d, SYS_IRRC_RP, buf, 5); if (ret) goto err; @@ -1403,19 +1483,19 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d) rc_keydown(d->rc_dev, RC_TYPE_NEC, rc_code, 0); - ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1); + ret = rtl28xxu_wr_reg(d, SYS_IRRC_SR, 1); if (ret) goto err; /* repeated intentionally to avoid extra keypress */ - ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1); + ret = rtl28xxu_wr_reg(d, SYS_IRRC_SR, 1); if (ret) goto err; } return ret; err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } @@ -1433,7 +1513,7 @@ static int rtl2831u_get_rc_config(struct dvb_usb_device *d, static int rtl2832u_rc_query(struct dvb_usb_device *d) { int ret, i, len; - struct rtl28xxu_priv *priv = d->priv; + struct rtl28xxu_dev *dev = d->priv; struct ir_raw_event ev; u8 buf[128]; static const struct rtl28xxu_reg_val_mask refresh_tab[] = { @@ -1443,7 +1523,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d) }; /* init remote controller */ - if (!priv->rc_active) { + if (!dev->rc_active) { static const struct rtl28xxu_reg_val_mask init_tab[] = { {SYS_DEMOD_CTL1, 0x00, 0x04}, {SYS_DEMOD_CTL1, 0x00, 0x08}, @@ -1464,36 +1544,36 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d) }; for (i = 0; i < ARRAY_SIZE(init_tab); i++) { - ret = rtl28xx_wr_reg_mask(d, init_tab[i].reg, + ret = rtl28xxu_wr_reg_mask(d, init_tab[i].reg, init_tab[i].val, init_tab[i].mask); if (ret) goto err; } - priv->rc_active = true; + dev->rc_active = true; } - ret = rtl28xx_rd_reg(d, IR_RX_IF, &buf[0]); + ret = rtl28xxu_rd_reg(d, IR_RX_IF, &buf[0]); if (ret) goto err; if (buf[0] != 0x83) goto exit; - ret = rtl28xx_rd_reg(d, IR_RX_BC, &buf[0]); + ret = rtl28xxu_rd_reg(d, IR_RX_BC, &buf[0]); if (ret) goto err; len = buf[0]; /* read raw code from hw */ - ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len); + ret = rtl28xxu_rd_regs(d, IR_RX_BUF, buf, len); if (ret) goto err; /* let hw receive new code */ for (i = 0; i < ARRAY_SIZE(refresh_tab); i++) { - ret = rtl28xx_wr_reg_mask(d, refresh_tab[i].reg, + ret = rtl28xxu_wr_reg_mask(d, refresh_tab[i].reg, refresh_tab[i].val, refresh_tab[i].mask); if (ret) goto err; @@ -1514,7 +1594,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d) exit: return ret; err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&d->intf->dev, "failed=%d\n", ret); return ret; } @@ -1523,7 +1603,7 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d, { /* disable IR interrupts in order to avoid SDR sample loss */ if (rtl28xxu_disable_rc) - return rtl28xx_wr_reg(d, IR_RX_IE, 0x00); + return rtl28xxu_wr_reg(d, IR_RX_IE, 0x00); /* load empty to enable rc */ if (!rc->map_name) @@ -1535,52 +1615,80 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d, return 0; } + +static int rtl28xxu_get_rc_config(struct dvb_usb_device *d, + struct dvb_usb_rc *rc) +{ + struct rtl28xxu_dev *dev = d_to_priv(d); + + if (dev->chip_id == CHIP_ID_RTL2831U) + return rtl2831u_get_rc_config(d, rc); + else + return rtl2832u_get_rc_config(d, rc); +} #else -#define rtl2831u_get_rc_config NULL -#define rtl2832u_get_rc_config NULL +#define rtl28xxu_get_rc_config NULL #endif -static const struct dvb_usb_device_properties rtl2831u_props = { +static int rtl28xxu_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct rtl28xxu_dev *dev = adap_to_priv(adap); + + if (dev->chip_id == CHIP_ID_RTL2831U) { + struct rtl2830_platform_data *pdata = &dev->rtl2830_platform_data; + + return pdata->pid_filter_ctrl(adap->fe[0], onoff); + } else { + struct rtl2832_platform_data *pdata = &dev->rtl2832_platform_data; + + return pdata->pid_filter_ctrl(adap->fe[0], onoff); + } +} + +static int rtl28xxu_pid_filter(struct dvb_usb_adapter *adap, int index, + u16 pid, int onoff) +{ + struct rtl28xxu_dev *dev = adap_to_priv(adap); + + if (dev->chip_id == CHIP_ID_RTL2831U) { + struct rtl2830_platform_data *pdata = &dev->rtl2830_platform_data; + + return pdata->pid_filter(adap->fe[0], index, pid, onoff); + } else { + struct rtl2832_platform_data *pdata = &dev->rtl2832_platform_data; + + return pdata->pid_filter(adap->fe[0], index, pid, onoff); + } +} + +static const struct dvb_usb_device_properties rtl28xxu_props = { .driver_name = KBUILD_MODNAME, .owner = THIS_MODULE, .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct rtl28xxu_priv), + .size_of_priv = sizeof(struct rtl28xxu_dev), - .power_ctrl = rtl2831u_power_ctrl, + .identify_state = rtl28xxu_identify_state, + .power_ctrl = rtl28xxu_power_ctrl, + .frontend_ctrl = rtl28xxu_frontend_ctrl, .i2c_algo = &rtl28xxu_i2c_algo, - .read_config = rtl2831u_read_config, - .frontend_attach = rtl2831u_frontend_attach, - .tuner_attach = rtl2831u_tuner_attach, + .read_config = rtl28xxu_read_config, + .frontend_attach = rtl28xxu_frontend_attach, + .frontend_detach = rtl28xxu_frontend_detach, + .tuner_attach = rtl28xxu_tuner_attach, + .tuner_detach = rtl28xxu_tuner_detach, .init = rtl28xxu_init, - .get_rc_config = rtl2831u_get_rc_config, + .get_rc_config = rtl28xxu_get_rc_config, .num_adapters = 1, .adapter = { { - .stream = DVB_USB_STREAM_BULK(0x81, 6, 8 * 512), - }, - }, -}; + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, -static const struct dvb_usb_device_properties rtl2832u_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct rtl28xxu_priv), + .pid_filter_count = 32, + .pid_filter_ctrl = rtl28xxu_pid_filter_ctrl, + .pid_filter = rtl28xxu_pid_filter, - .power_ctrl = rtl2832u_power_ctrl, - .frontend_ctrl = rtl2832u_frontend_ctrl, - .i2c_algo = &rtl28xxu_i2c_algo, - .read_config = rtl2832u_read_config, - .frontend_attach = rtl2832u_frontend_attach, - .tuner_attach = rtl2832u_tuner_attach, - .init = rtl28xxu_init, - .exit = rtl28xxu_exit, - .get_rc_config = rtl2832u_get_rc_config, - - .num_adapters = 1, - .adapter = { - { .stream = DVB_USB_STREAM_BULK(0x81, 6, 8 * 512), }, }, @@ -1589,69 +1697,69 @@ static const struct dvb_usb_device_properties rtl2832u_props = { static const struct usb_device_id rtl28xxu_id_table[] = { /* RTL2831U devices: */ { DVB_USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U, - &rtl2831u_props, "Realtek RTL2831U reference design", NULL) }, + &rtl28xxu_props, "Realtek RTL2831U reference design", NULL) }, { DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT, - &rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) }, + &rtl28xxu_props, "Freecom USB2.0 DVB-T", NULL) }, { DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2, - &rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) }, + &rtl28xxu_props, "Freecom USB2.0 DVB-T", NULL) }, /* RTL2832U devices: */ { DVB_USB_DEVICE(USB_VID_REALTEK, 0x2832, - &rtl2832u_props, "Realtek RTL2832U reference design", NULL) }, + &rtl28xxu_props, "Realtek RTL2832U reference design", NULL) }, { DVB_USB_DEVICE(USB_VID_REALTEK, 0x2838, - &rtl2832u_props, "Realtek RTL2832U reference design", NULL) }, + &rtl28xxu_props, "Realtek RTL2832U reference design", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1, - &rtl2832u_props, "TerraTec Cinergy T Stick Black", RC_MAP_TERRATEC_SLIM) }, + &rtl28xxu_props, "TerraTec Cinergy T Stick Black", RC_MAP_TERRATEC_SLIM) }, { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_DELOCK_USB2_DVBT, - &rtl2832u_props, "G-Tek Electronics Group Lifeview LV5TDLX DVB-T", NULL) }, + &rtl28xxu_props, "G-Tek Electronics Group Lifeview LV5TDLX DVB-T", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK, - &rtl2832u_props, "TerraTec NOXON DAB Stick", NULL) }, + &rtl28xxu_props, "TerraTec NOXON DAB Stick", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV2, - &rtl2832u_props, "TerraTec NOXON DAB Stick (rev 2)", NULL) }, + &rtl28xxu_props, "TerraTec NOXON DAB Stick (rev 2)", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV3, - &rtl2832u_props, "TerraTec NOXON DAB Stick (rev 3)", NULL) }, + &rtl28xxu_props, "TerraTec NOXON DAB Stick (rev 3)", NULL) }, { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TREKSTOR_TERRES_2_0, - &rtl2832u_props, "Trekstor DVB-T Stick Terres 2.0", NULL) }, + &rtl28xxu_props, "Trekstor DVB-T Stick Terres 2.0", NULL) }, { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1101, - &rtl2832u_props, "Dexatek DK DVB-T Dongle", NULL) }, + &rtl28xxu_props, "Dexatek DK DVB-T Dongle", NULL) }, { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6680, - &rtl2832u_props, "DigitalNow Quad DVB-T Receiver", NULL) }, + &rtl28xxu_props, "DigitalNow Quad DVB-T Receiver", NULL) }, { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_MINID, - &rtl2832u_props, "Leadtek Winfast DTV Dongle Mini D", NULL) }, + &rtl28xxu_props, "Leadtek Winfast DTV Dongle Mini D", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d3, - &rtl2832u_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) }, + &rtl28xxu_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) }, { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1102, - &rtl2832u_props, "Dexatek DK mini DVB-T Dongle", NULL) }, + &rtl28xxu_props, "Dexatek DK mini DVB-T Dongle", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d7, - &rtl2832u_props, "TerraTec Cinergy T Stick+", NULL) }, + &rtl28xxu_props, "TerraTec Cinergy T Stick+", NULL) }, { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd3a8, - &rtl2832u_props, "ASUS My Cinema-U3100Mini Plus V2", NULL) }, + &rtl28xxu_props, "ASUS My Cinema-U3100Mini Plus V2", NULL) }, { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd393, - &rtl2832u_props, "GIGABYTE U7300", NULL) }, + &rtl28xxu_props, "GIGABYTE U7300", NULL) }, { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1104, - &rtl2832u_props, "MSI DIGIVOX Micro HD", NULL) }, + &rtl28xxu_props, "MSI DIGIVOX Micro HD", NULL) }, { DVB_USB_DEVICE(USB_VID_COMPRO, 0x0620, - &rtl2832u_props, "Compro VideoMate U620F", NULL) }, + &rtl28xxu_props, "Compro VideoMate U620F", NULL) }, { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394, - &rtl2832u_props, "MaxMedia HU394-T", NULL) }, + &rtl28xxu_props, "MaxMedia HU394-T", NULL) }, { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a03, - &rtl2832u_props, "Leadtek WinFast DTV Dongle mini", NULL) }, + &rtl28xxu_props, "Leadtek WinFast DTV Dongle mini", NULL) }, { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A, - &rtl2832u_props, "Crypto ReDi PC 50 A", NULL) }, + &rtl28xxu_props, "Crypto ReDi PC 50 A", NULL) }, { DVB_USB_DEVICE(USB_VID_KYE, 0x707f, - &rtl2832u_props, "Genius TVGo DVB-T03", NULL) }, + &rtl28xxu_props, "Genius TVGo DVB-T03", NULL) }, { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd395, - &rtl2832u_props, "Peak DVB-T USB", NULL) }, + &rtl28xxu_props, "Peak DVB-T USB", NULL) }, { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20_RTL2832U, - &rtl2832u_props, "Sveon STV20", NULL) }, + &rtl28xxu_props, "Sveon STV20", NULL) }, { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV21, - &rtl2832u_props, "Sveon STV21", NULL) }, + &rtl28xxu_props, "Sveon STV21", NULL) }, { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV27, - &rtl2832u_props, "Sveon STV27", NULL) }, + &rtl28xxu_props, "Sveon STV27", NULL) }, /* RTL2832P devices: */ { DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131, - &rtl2832u_props, "Astrometa DVB-T2", NULL) }, + &rtl28xxu_props, "Astrometa DVB-T2", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table); diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h index 3e3ea9d64a38..1b5d7ffb685e 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h @@ -22,8 +22,26 @@ #ifndef RTL28XXU_H #define RTL28XXU_H +#include + #include "dvb_usb.h" +#include "rtl2830.h" +#include "rtl2832.h" +#include "rtl2832_sdr.h" +#include "mn88472.h" +#include "mn88473.h" + +#include "qt1010.h" +#include "mt2060.h" +#include "mxl5005s.h" +#include "fc0012.h" +#include "fc0013.h" +#include "e4000.h" +#include "fc2580.h" +#include "tua9001.h" +#include "r820t.h" + /* * USB commands * (usb_control_msg() index parameter) @@ -50,19 +68,26 @@ #define CMD_I2C_DA_WR 0x0610 -struct rtl28xxu_priv { +struct rtl28xxu_dev { + u8 buf[28]; u8 chip_id; u8 tuner; char *tuner_name; u8 page; /* integrated demod active register page */ struct i2c_adapter *demod_i2c_adapter; bool rc_active; + struct i2c_client *i2c_client_demod; struct i2c_client *i2c_client_tuner; struct i2c_client *i2c_client_slave_demod; + struct platform_device *platform_device_sdr; #define SLAVE_DEMOD_NONE 0 #define SLAVE_DEMOD_MN88472 1 #define SLAVE_DEMOD_MN88473 2 unsigned int slave_demod:2; + union { + struct rtl2830_platform_data rtl2830_platform_data; + struct rtl2832_platform_data rtl2832_platform_data; + }; }; enum rtl28xxu_chip_id { diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 0f345b1f9014..f327c49d7e09 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -2232,7 +2232,7 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = { { "Mygica T230 DVB-T/T2/C", { NULL }, - { &cxusb_table[22], NULL }, + { &cxusb_table[20], NULL }, }, } }; diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index abf8ab2e02e5..eafc5c82467f 100644 --- a/drivers/media/usb/dvb-usb/m920x.c +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -1269,8 +1269,3 @@ MODULE_AUTHOR("Aapo Tahkola "); MODULE_DESCRIPTION("DVB Driver for ULI M920x"); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - */ diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 44ae1e0661e6..49a5f9532bd8 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -820,7 +820,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) if (urb_size > ep_size * npackets) npackets = DIV_ROUND_UP(urb_size, ep_size); - em28xx_info("Number of URBs: %d, with %d packets and %d size", + em28xx_info("Number of URBs: %d, with %d packets and %d size\n", num_urb, npackets, urb_size); /* Estimate the bytes per period */ @@ -981,7 +981,7 @@ static int em28xx_audio_fini(struct em28xx *dev) return 0; } - em28xx_info("Closing audio extension"); + em28xx_info("Closing audio extension\n"); if (dev->adev.sndcard) { snd_card_disconnect(dev->adev.sndcard); @@ -1005,7 +1005,7 @@ static int em28xx_audio_suspend(struct em28xx *dev) if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) return 0; - em28xx_info("Suspending audio extension"); + em28xx_info("Suspending audio extension\n"); em28xx_deinit_isoc_audio(dev); atomic_set(&dev->adev.stream_started, 0); return 0; @@ -1019,7 +1019,7 @@ static int em28xx_audio_resume(struct em28xx *dev) if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) return 0; - em28xx_info("Resuming audio extension"); + em28xx_info("Resuming audio extension\n"); /* Nothing to do other than schedule_work() ?? */ schedule_work(&dev->adev.wq_trigger); return 0; diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 86461a708abe..37456079f490 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -1125,7 +1125,7 @@ int em28xx_suspend_extension(struct em28xx *dev) { const struct em28xx_ops *ops = NULL; - em28xx_info("Suspending extensions"); + em28xx_info("Suspending extensions\n"); mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->suspend) @@ -1139,7 +1139,7 @@ int em28xx_resume_extension(struct em28xx *dev) { const struct em28xx_ops *ops = NULL; - em28xx_info("Resuming extensions"); + em28xx_info("Resuming extensions\n"); mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->resume) diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 9877b699c6bc..aee70d483264 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -1724,7 +1724,7 @@ static int em28xx_dvb_fini(struct em28xx *dev) if (!dev->dvb) return 0; - em28xx_info("Closing DVB extension"); + em28xx_info("Closing DVB extension\n"); dvb = dev->dvb; client = dvb->i2c_client_tuner; @@ -1775,17 +1775,17 @@ static int em28xx_dvb_suspend(struct em28xx *dev) if (!dev->board.has_dvb) return 0; - em28xx_info("Suspending DVB extension"); + em28xx_info("Suspending DVB extension\n"); if (dev->dvb) { struct em28xx_dvb *dvb = dev->dvb; if (dvb->fe[0]) { ret = dvb_frontend_suspend(dvb->fe[0]); - em28xx_info("fe0 suspend %d", ret); + em28xx_info("fe0 suspend %d\n", ret); } if (dvb->fe[1]) { dvb_frontend_suspend(dvb->fe[1]); - em28xx_info("fe1 suspend %d", ret); + em28xx_info("fe1 suspend %d\n", ret); } } @@ -1802,18 +1802,18 @@ static int em28xx_dvb_resume(struct em28xx *dev) if (!dev->board.has_dvb) return 0; - em28xx_info("Resuming DVB extension"); + em28xx_info("Resuming DVB extension\n"); if (dev->dvb) { struct em28xx_dvb *dvb = dev->dvb; if (dvb->fe[0]) { ret = dvb_frontend_resume(dvb->fe[0]); - em28xx_info("fe0 resume %d", ret); + em28xx_info("fe0 resume %d\n", ret); } if (dvb->fe[1]) { ret = dvb_frontend_resume(dvb->fe[1]); - em28xx_info("fe1 resume %d", ret); + em28xx_info("fe1 resume %d\n", ret); } } diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index d8dc03aadfbd..4007356d991d 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -654,8 +654,6 @@ next_button: if (dev->num_button_polling_addresses) { memset(dev->button_polling_last_values, 0, EM28XX_NUM_BUTTON_ADDRESSES_MAX); - INIT_DELAYED_WORK(&dev->buttons_query_work, - em28xx_query_buttons); schedule_delayed_work(&dev->buttons_query_work, msecs_to_jiffies(dev->button_polling_interval)); } @@ -689,6 +687,7 @@ static int em28xx_ir_init(struct em28xx *dev) } kref_get(&dev->ref); + INIT_DELAYED_WORK(&dev->buttons_query_work, em28xx_query_buttons); if (dev->board.buttons) em28xx_init_buttons(dev); @@ -833,7 +832,7 @@ static int em28xx_ir_fini(struct em28xx *dev) return 0; } - em28xx_info("Closing input extension"); + em28xx_info("Closing input extension\n"); em28xx_shutdown_buttons(dev); @@ -862,7 +861,7 @@ static int em28xx_ir_suspend(struct em28xx *dev) if (dev->is_audio_only) return 0; - em28xx_info("Suspending input extension"); + em28xx_info("Suspending input extension\n"); if (ir) cancel_delayed_work_sync(&ir->work); cancel_delayed_work_sync(&dev->buttons_query_work); @@ -879,7 +878,7 @@ static int em28xx_ir_resume(struct em28xx *dev) if (dev->is_audio_only) return 0; - em28xx_info("Resuming input extension"); + em28xx_info("Resuming input extension\n"); /* if suspend calls ir_raw_event_unregister(), the should call ir_raw_event_register() */ if (ir) diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index cf7f58b76292..9ecf65629b3d 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1958,7 +1958,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev) if (v4l2 == NULL) return 0; - em28xx_info("Closing video extension"); + em28xx_info("Closing video extension\n"); mutex_lock(&dev->lock); @@ -2007,7 +2007,7 @@ static int em28xx_v4l2_suspend(struct em28xx *dev) if (!dev->has_video) return 0; - em28xx_info("Suspending video extension"); + em28xx_info("Suspending video extension\n"); em28xx_stop_urbs(dev); return 0; } @@ -2020,7 +2020,7 @@ static int em28xx_v4l2_resume(struct em28xx *dev) if (!dev->has_video) return 0; - em28xx_info("Resuming video extension"); + em28xx_info("Resuming video extension\n"); /* what do we do here */ return 0; } @@ -2192,7 +2192,6 @@ static struct video_device *vfd = *template; vfd->v4l2_dev = &dev->v4l2->v4l2_dev; - vfd->debug = video_debug; vfd->lock = &dev->lock; if (dev->board.is_webcam) vfd->tvnorms = 0; diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig index eed10d782535..60af3b167f3b 100644 --- a/drivers/media/usb/gspca/Kconfig +++ b/drivers/media/usb/gspca/Kconfig @@ -395,6 +395,16 @@ config USB_GSPCA_TOPRO To compile this driver as a module, choose M here: the module will be called gspca_topro. +config USB_GSPCA_TOUPTEK + tristate "Touptek USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the ToupTek UCMOS + / AmScope MU series camera. + + To compile this driver as a module, choose M here: the + module will be called gspca_touptek. + config USB_GSPCA_TV8532 tristate "TV8532 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA diff --git a/drivers/media/usb/gspca/Makefile b/drivers/media/usb/gspca/Makefile index f46975e4c82d..9f5ccecb9c8a 100644 --- a/drivers/media/usb/gspca/Makefile +++ b/drivers/media/usb/gspca/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_USB_GSPCA_STK1135) += gspca_stk1135.o obj-$(CONFIG_USB_GSPCA_STV0680) += gspca_stv0680.o obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o obj-$(CONFIG_USB_GSPCA_TOPRO) += gspca_topro.o +obj-$(CONFIG_USB_GSPCA_TOUPTEK) += gspca_touptek.o obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o obj-$(CONFIG_USB_GSPCA_VICAM) += gspca_vicam.o @@ -86,6 +87,7 @@ gspca_stv0680-objs := stv0680.o gspca_sunplus-objs := sunplus.o gspca_t613-objs := t613.o gspca_topro-objs := topro.o +gspca_touptek-objs := touptek.o gspca_tv8532-objs := tv8532.o gspca_vc032x-objs := vc032x.o gspca_vicam-objs := vicam.o diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 43d65057a5fe..e54cee856a80 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1562,7 +1562,7 @@ static int vidioc_s_parm(struct file *filp, void *priv, struct v4l2_streamparm *parm) { struct gspca_dev *gspca_dev = video_drvdata(filp); - int n; + unsigned int n; n = parm->parm.capture.readbuffers; if (n == 0 || n >= GSPCA_MAX_FRAMES) diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index 90f0d637cd9d..a9c866d6d82d 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -12,6 +12,8 @@ * PS3 Eye camera enhanced by Richard Kaswy http://kaswy.free.fr * PS3 Eye camera - brightness, contrast, awb, agc, aec controls * added by Max Thrun + * PS3 Eye camera - FPS range extended by Joseph Howse + * http://nummist.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 @@ -116,7 +118,7 @@ static const struct v4l2_pix_format ov767x_mode[] = { .colorspace = V4L2_COLORSPACE_JPEG}, }; -static const u8 qvga_rates[] = {125, 100, 75, 60, 50, 40, 30}; +static const u8 qvga_rates[] = {187, 150, 137, 125, 100, 75, 60, 50, 37, 30}; static const u8 vga_rates[] = {60, 50, 40, 30, 15}; static const struct framerates ov772x_framerates[] = { @@ -769,12 +771,16 @@ static void set_frame_rate(struct gspca_dev *gspca_dev) {15, 0x03, 0x41, 0x04}, }; static const struct rate_s rate_1[] = { /* 320x240 */ +/* {205, 0x01, 0xc1, 0x02}, * 205 FPS: video is partly corrupt */ + {187, 0x01, 0x81, 0x02}, /* 187 FPS or below: video is valid */ + {150, 0x01, 0xc1, 0x04}, + {137, 0x02, 0xc1, 0x02}, {125, 0x02, 0x81, 0x02}, {100, 0x02, 0xc1, 0x04}, {75, 0x03, 0xc1, 0x04}, {60, 0x04, 0xc1, 0x04}, {50, 0x02, 0x41, 0x04}, - {40, 0x03, 0x41, 0x04}, + {37, 0x03, 0x41, 0x04}, {30, 0x04, 0x41, 0x04}, }; diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx.c b/drivers/media/usb/gspca/stv06xx/stv06xx.c index 49d209bbf9ee..6ac93d8db427 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c @@ -505,13 +505,13 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, { int ret = -EINVAL; - if (len == 1 && data[0] == 0x80) { + if (len == 1 && (data[0] == 0x80 || data[0] == 0x10)) { input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); input_sync(gspca_dev->input_dev); ret = 0; } - if (len == 1 && data[0] == 0x88) { + if (len == 1 && (data[0] == 0x88 || data[0] == 0x11)) { input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); input_sync(gspca_dev->input_dev); ret = 0; diff --git a/drivers/media/usb/gspca/touptek.c b/drivers/media/usb/gspca/touptek.c new file mode 100644 index 000000000000..7bac6bc96063 --- /dev/null +++ b/drivers/media/usb/gspca/touptek.c @@ -0,0 +1,731 @@ +/* + * ToupTek UCMOS / AmScope MU series camera driver + * TODO: contrast with ScopeTek / AmScope MDC cameras + * + * Copyright (C) 2012-2014 John McMaster + * + * Special thanks to Bushing for helping with the decrypt algorithm and + * Sean O'Sullivan / the Rensselaer Center for Open Source + * Software (RCOS) for helping me learn kernel development + * + * 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 + * 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 "gspca.h" + +#define MODULE_NAME "touptek" + +MODULE_AUTHOR("John McMaster"); +MODULE_DESCRIPTION("ToupTek UCMOS / Amscope MU microscope camera driver"); +MODULE_LICENSE("GPL"); + +/* + * Exposure reg is linear with exposure time + * Exposure (sec), E (reg) + * 0.000400, 0x0002 + * 0.001000, 0x0005 + * 0.005000, 0x0019 + * 0.020000, 0x0064 + * 0.080000, 0x0190 + * 0.400000, 0x07D0 + * 1.000000, 0x1388 + * 2.000000, 0x2710 + * + * Three gain stages + * 0x1000: master channel enable bit + * 0x007F: low gain bits + * 0x0080: medium gain bit + * 0x0100: high gain bit + * gain = enable * (1 + regH) * (1 + regM) * z * regL + * + * Gain implementation + * Want to do something similar to mt9v011.c's set_balance + * + * Gain does not vary with resolution (checked 640x480 vs 1600x1200) + * + * Constant derivation: + * + * Raw data: + * Gain, GTOP, B, R, GBOT + * 1.00, 0x105C, 0x1068, 0x10C8, 0x105C + * 1.20, 0x106E, 0x107E, 0x10D6, 0x106E + * 1.40, 0x10C0, 0x10CA, 0x10E5, 0x10C0 + * 1.60, 0x10C9, 0x10D4, 0x10F3, 0x10C9 + * 1.80, 0x10D2, 0x10DE, 0x11C1, 0x10D2 + * 2.00, 0x10DC, 0x10E9, 0x11C8, 0x10DC + * 2.20, 0x10E5, 0x10F3, 0x11CF, 0x10E5 + * 2.40, 0x10EE, 0x10FE, 0x11D7, 0x10EE + * 2.60, 0x10F7, 0x11C4, 0x11DE, 0x10F7 + * 2.80, 0x11C0, 0x11CA, 0x11E5, 0x11C0 + * 3.00, 0x11C5, 0x11CF, 0x11ED, 0x11C5 + * + * zR = 0.0069605943152454778 + * about 3/431 = 0.0069605568445475635 + * zB = 0.0095695970695970703 + * about 6/627 = 0.0095693779904306216 + * zG = 0.010889328063241107 + * about 6/551 = 0.010889292196007259 + * about 10 bits for constant + 7 bits for value => at least 17 bit + * intermediate with 32 bit ints should be fine for overflow etc + * Essentially gains are in range 0-0x001FF + * + * However, V4L expects a main gain channel + R and B balance + * To keep things simple for now saturate the values of balance is too high/low + * This isn't really ideal but easy way to fit the Linux model + * + * Converted using gain model turns out to be quite linear: + * Gain, GTOP, B, R, GBOT + * 1.00, 92, 104, 144, 92 + * 1.20, 110, 126, 172, 110 + * 1.40, 128, 148, 202, 128 + * 1.60, 146, 168, 230, 146 + * 1.80, 164, 188, 260, 164 + * 2.00, 184, 210, 288, 184 + * 2.20, 202, 230, 316, 202 + * 2.40, 220, 252, 348, 220 + * 2.60, 238, 272, 376, 238 + * 2.80, 256, 296, 404, 256 + * 3.00, 276, 316, 436, 276 + * + * Maximum gain is 0x7FF * 2 * 2 => 0x1FFC (8188) + * or about 13 effective bits of gain + * The highest the commercial driver goes in my setup 436 + * However, because could *maybe* damage circuits + * limit the gain until have a reason to go higher + * Solution: gain clipped and warning emitted + */ +#define GAIN_MAX 511 + +/* Frame sync is a short read */ +#define BULK_SIZE 0x4000 + +/* MT9E001 reg names to give a rough approximation */ +#define REG_COARSE_INTEGRATION_TIME_ 0x3012 +#define REG_GROUPED_PARAMETER_HOLD_ 0x3022 +#define REG_MODE_SELECT 0x0100 +#define REG_OP_SYS_CLK_DIV 0x030A +#define REG_VT_SYS_CLK_DIV 0x0302 +#define REG_PRE_PLL_CLK_DIV 0x0304 +#define REG_VT_PIX_CLK_DIV 0x0300 +#define REG_OP_PIX_CLK_DIV 0x0308 +#define REG_PLL_MULTIPLIER 0x0306 +#define REG_COARSE_INTEGRATION_TIME_ 0x3012 +#define REG_FRAME_LENGTH_LINES 0x0340 +#define REG_FRAME_LENGTH_LINES_ 0x300A +#define REG_GREEN1_GAIN 0x3056 +#define REG_GREEN2_GAIN 0x305C +#define REG_GROUPED_PARAMETER_HOLD 0x0104 +#define REG_LINE_LENGTH_PCK_ 0x300C +#define REG_MODE_SELECT 0x0100 +#define REG_PLL_MULTIPLIER 0x0306 +#define REG_READ_MODE 0x3040 +#define REG_BLUE_GAIN 0x3058 +#define REG_RED_GAIN 0x305A +#define REG_RESET_REGISTER 0x301A +#define REG_SCALE_M 0x0404 +#define REG_SCALING_MODE 0x0400 +#define REG_SOFTWARE_RESET 0x0103 +#define REG_X_ADDR_END 0x0348 +#define REG_X_ADDR_START 0x0344 +#define REG_X_ADDR_START 0x0344 +#define REG_X_OUTPUT_SIZE 0x034C +#define REG_Y_ADDR_END 0x034A +#define REG_Y_ADDR_START 0x0346 +#define REG_Y_OUTPUT_SIZE 0x034E + + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + /* How many bytes this frame */ + unsigned int this_f; + + /* + Device has separate gains for each Bayer quadrant + V4L supports master gain which is referenced to G1/G2 and supplies + individual balance controls for R/B + */ + struct v4l2_ctrl *blue; + struct v4l2_ctrl *red; +}; + +/* Used to simplify reg write error handling */ +struct cmd { + u16 value; + u16 index; +}; + +static const struct v4l2_pix_format vga_mode[] = { + {800, 600, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .bytesperline = 800, + .sizeimage = 800 * 600, + .colorspace = V4L2_COLORSPACE_SRGB}, + {1600, 1200, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .bytesperline = 1600, + .sizeimage = 1600 * 1200, + .colorspace = V4L2_COLORSPACE_SRGB}, + {3264, 2448, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .bytesperline = 3264, + .sizeimage = 3264 * 2448, + .colorspace = V4L2_COLORSPACE_SRGB}, +}; + +/* + * As theres no known frame sync, the only way to keep synced is to try hard + * to never miss any packets + */ +#if MAX_NURBS < 4 +#error "Not enough URBs in the gspca table" +#endif + +static int val_reply(struct gspca_dev *gspca_dev, const char *reply, int rc) +{ + if (rc < 0) { + PERR("reply has error %d", rc); + return -EIO; + } + if (rc != 1) { + PERR("Bad reply size %d", rc); + return -EIO; + } + if (reply[0] != 0x08) { + PERR("Bad reply 0x%02X", reply[0]); + return -EIO; + } + return 0; +} + +static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) +{ + char buff[1]; + int rc; + + PDEBUG(D_USBO, + "reg_w bReq=0x0B, bReqT=0xC0, wVal=0x%04X, wInd=0x%04X\n", + value, index); + rc = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), + 0x0B, 0xC0, value, index, buff, 1, 500); + PDEBUG(D_USBO, "rc=%d, ret={0x%02X}", rc, buff[0]); + if (rc < 0) { + PERR("Failed reg_w(0x0B, 0xC0, 0x%04X, 0x%04X) w/ rc %d\n", + value, index, rc); + gspca_dev->usb_err = rc; + return; + } + if (val_reply(gspca_dev, buff, rc)) { + PERR("Bad reply to reg_w(0x0B, 0xC0, 0x%04X, 0x%04X\n", + value, index); + gspca_dev->usb_err = -EIO; + } +} + +static void reg_w_buf(struct gspca_dev *gspca_dev, + const struct cmd *p, int l) +{ + do { + reg_w(gspca_dev, p->value, p->index); + p++; + } while (--l > 0); +} + +static void setexposure(struct gspca_dev *gspca_dev, s32 val) +{ + u16 value; + unsigned int w = gspca_dev->pixfmt.width; + + if (w == 800) + value = val * 5; + else if (w == 1600) + value = val * 3; + else if (w == 3264) + value = val * 3 / 2; + else { + PERR("Invalid width %u\n", w); + gspca_dev->usb_err = -EINVAL; + return; + } + PDEBUG(D_STREAM, "exposure: 0x%04X ms\n", value); + /* Wonder if theres a good reason for sending it twice */ + /* probably not but leave it in because...why not */ + reg_w(gspca_dev, value, REG_COARSE_INTEGRATION_TIME_); + reg_w(gspca_dev, value, REG_COARSE_INTEGRATION_TIME_); +} + +static int gainify(int in) +{ + /* + * TODO: check if there are any issues with corner cases + * 0x000 (0):0x07F (127): regL + * 0x080 (128) - 0x0FF (255): regM, regL + * 0x100 (256) - max: regH, regM, regL + */ + if (in <= 0x7F) + return 0x1000 | in; + else if (in <= 0xFF) + return 0x1080 | in / 2; + else + return 0x1180 | in / 4; +} + +static void setggain(struct gspca_dev *gspca_dev, u16 global_gain) +{ + u16 normalized; + + normalized = gainify(global_gain); + PDEBUG(D_STREAM, "gain G1/G2 (0x%04X): 0x%04X (src 0x%04X)\n", + REG_GREEN1_GAIN, + normalized, global_gain); + + reg_w(gspca_dev, normalized, REG_GREEN1_GAIN); + reg_w(gspca_dev, normalized, REG_GREEN2_GAIN); +} + +static void setbgain(struct gspca_dev *gspca_dev, + u16 gain, u16 global_gain) +{ + u16 normalized; + + normalized = global_gain + + ((u32)global_gain) * gain / GAIN_MAX; + if (normalized > GAIN_MAX) { + PDEBUG(D_STREAM, "Truncating blue 0x%04X w/ value 0x%04X\n", + GAIN_MAX, normalized); + normalized = GAIN_MAX; + } + normalized = gainify(normalized); + PDEBUG(D_STREAM, "gain B (0x%04X): 0x%04X w/ source 0x%04X\n", + REG_BLUE_GAIN, normalized, gain); + + reg_w(gspca_dev, normalized, REG_BLUE_GAIN); +} + +static void setrgain(struct gspca_dev *gspca_dev, + u16 gain, u16 global_gain) +{ + u16 normalized; + + normalized = global_gain + + ((u32)global_gain) * gain / GAIN_MAX; + if (normalized > GAIN_MAX) { + PDEBUG(D_STREAM, "Truncating gain 0x%04X w/ value 0x%04X\n", + GAIN_MAX, normalized); + normalized = GAIN_MAX; + } + normalized = gainify(normalized); + PDEBUG(D_STREAM, "gain R (0x%04X): 0x%04X w / source 0x%04X\n", + REG_RED_GAIN, normalized, gain); + + reg_w(gspca_dev, normalized, REG_RED_GAIN); +} + +static void configure_wh(struct gspca_dev *gspca_dev) +{ + unsigned int w = gspca_dev->pixfmt.width; + + PDEBUG(D_STREAM, "configure_wh\n"); + + if (w == 800) { + static const struct cmd reg_init_res[] = { + {0x0060, REG_X_ADDR_START}, + {0x0CD9, REG_X_ADDR_END}, + {0x0036, REG_Y_ADDR_START}, + {0x098F, REG_Y_ADDR_END}, + {0x07C7, REG_READ_MODE}, + }; + + reg_w_buf(gspca_dev, + reg_init_res, ARRAY_SIZE(reg_init_res)); + } else if (w == 1600) { + static const struct cmd reg_init_res[] = { + {0x009C, REG_X_ADDR_START}, + {0x0D19, REG_X_ADDR_END}, + {0x0068, REG_Y_ADDR_START}, + {0x09C5, REG_Y_ADDR_END}, + {0x06C3, REG_READ_MODE}, + }; + + reg_w_buf(gspca_dev, + reg_init_res, ARRAY_SIZE(reg_init_res)); + } else if (w == 3264) { + static const struct cmd reg_init_res[] = { + {0x00E8, REG_X_ADDR_START}, + {0x0DA7, REG_X_ADDR_END}, + {0x009E, REG_Y_ADDR_START}, + {0x0A2D, REG_Y_ADDR_END}, + {0x0241, REG_READ_MODE}, + }; + + reg_w_buf(gspca_dev, + reg_init_res, ARRAY_SIZE(reg_init_res)); + } else { + PERR("bad width %u\n", w); + gspca_dev->usb_err = -EINVAL; + return; + } + + reg_w(gspca_dev, 0x0000, REG_SCALING_MODE); + reg_w(gspca_dev, 0x0010, REG_SCALE_M); + reg_w(gspca_dev, w, REG_X_OUTPUT_SIZE); + reg_w(gspca_dev, gspca_dev->pixfmt.height, REG_Y_OUTPUT_SIZE); + + if (w == 800) { + reg_w(gspca_dev, 0x0384, REG_FRAME_LENGTH_LINES_); + reg_w(gspca_dev, 0x0960, REG_LINE_LENGTH_PCK_); + } else if (w == 1600) { + reg_w(gspca_dev, 0x0640, REG_FRAME_LENGTH_LINES_); + reg_w(gspca_dev, 0x0FA0, REG_LINE_LENGTH_PCK_); + } else if (w == 3264) { + reg_w(gspca_dev, 0x0B4B, REG_FRAME_LENGTH_LINES_); + reg_w(gspca_dev, 0x1F40, REG_LINE_LENGTH_PCK_); + } else { + PERR("bad width %u\n", w); + gspca_dev->usb_err = -EINVAL; + return; + } +} + +/* Packets that were encrypted, no idea if the grouping is significant */ +static void configure_encrypted(struct gspca_dev *gspca_dev) +{ + static const struct cmd reg_init_begin[] = { + {0x0100, REG_SOFTWARE_RESET}, + {0x0000, REG_MODE_SELECT}, + {0x0100, REG_GROUPED_PARAMETER_HOLD}, + {0x0004, REG_VT_PIX_CLK_DIV}, + {0x0001, REG_VT_SYS_CLK_DIV}, + {0x0008, REG_OP_PIX_CLK_DIV}, + {0x0001, REG_OP_SYS_CLK_DIV}, + {0x0004, REG_PRE_PLL_CLK_DIV}, + {0x0040, REG_PLL_MULTIPLIER}, + {0x0000, REG_GROUPED_PARAMETER_HOLD}, + {0x0100, REG_GROUPED_PARAMETER_HOLD}, + }; + static const struct cmd reg_init_end[] = { + {0x0000, REG_GROUPED_PARAMETER_HOLD}, + {0x0301, 0x31AE}, + {0x0805, 0x3064}, + {0x0071, 0x3170}, + {0x10DE, REG_RESET_REGISTER}, + {0x0000, REG_MODE_SELECT}, + {0x0010, REG_PLL_MULTIPLIER}, + {0x0100, REG_MODE_SELECT}, + }; + + PDEBUG(D_STREAM, "Encrypted begin, w = %u\n", gspca_dev->pixfmt.width); + reg_w_buf(gspca_dev, reg_init_begin, ARRAY_SIZE(reg_init_begin)); + configure_wh(gspca_dev); + reg_w_buf(gspca_dev, reg_init_end, ARRAY_SIZE(reg_init_end)); + reg_w(gspca_dev, 0x0100, REG_GROUPED_PARAMETER_HOLD); + reg_w(gspca_dev, 0x0000, REG_GROUPED_PARAMETER_HOLD); + + PDEBUG(D_STREAM, "Encrypted end\n"); +} + +static int configure(struct gspca_dev *gspca_dev) +{ + int rc; + uint8_t buff[4]; + + PDEBUG(D_STREAM, "configure()\n"); + + /* + * First driver sets a sort of encryption key + * A number of futur requests of this type have wValue and wIndex + * encrypted as follows: + * -Compute key = this wValue rotate left by 4 bits + * (decrypt.py rotates right because we are decrypting) + * -Later packets encrypt packets by XOR'ing with key + * XOR encrypt/decrypt is symmetrical + * wValue, and wIndex are encrypted + * bRequest is not and bRequestType is always 0xC0 + * This allows resyncing if key is unknown? + * By setting 0 we XOR with 0 and the shifting and XOR drops out + */ + rc = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), + 0x16, 0xC0, 0x0000, 0x0000, buff, 2, 500); + if (val_reply(gspca_dev, buff, rc)) { + PERR("failed key req"); + return -EIO; + } + + /* + * Next does some sort of 2 packet challenge / response + * evidence suggests its an Atmel I2C crypto part but nobody cares to + * look + * (to make sure its not cloned hardware?) + * Ignore: I want to work with their hardware, not clone it + * 16 bytes out challenge, requestType: 0x40 + * 16 bytes in response, requestType: 0xC0 + */ + + rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), + 0x01, 0x40, 0x0001, 0x000F, NULL, 0, 500); + if (rc < 0) { + PERR("failed to replay packet 176 w/ rc %d\n", rc); + return rc; + } + + rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), + 0x01, 0x40, 0x0000, 0x000F, NULL, 0, 500); + if (rc < 0) { + PERR("failed to replay packet 178 w/ rc %d\n", rc); + return rc; + } + + rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), + 0x01, 0x40, 0x0001, 0x000F, NULL, 0, 500); + if (rc < 0) { + PERR("failed to replay packet 180 w/ rc %d\n", rc); + return rc; + } + + /* + * Serial number? Doesn't seem to be required + * cam1: \xE6\x0D\x00\x00, cam2: \x70\x19\x00\x00 + * rc = usb_control_msg(gspca_dev->dev, + * usb_rcvctrlpipe(gspca_dev->dev, 0), + * 0x20, 0xC0, 0x0000, 0x0000, buff, 4, 500); + */ + + /* Large (EEPROM?) read, skip it since no idea what to do with it */ + gspca_dev->usb_err = 0; + configure_encrypted(gspca_dev); + if (gspca_dev->usb_err) + return gspca_dev->usb_err; + + /* Omitted this by accident, does not work without it */ + rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), + 0x01, 0x40, 0x0003, 0x000F, NULL, 0, 500); + if (rc < 0) { + PERR("failed to replay final packet w/ rc %d\n", rc); + return rc; + } + + PDEBUG(D_STREAM, "Configure complete\n"); + return 0; +} + +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + gspca_dev->cam.cam_mode = vga_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); + + /* Yes we want URBs and we want them now! */ + gspca_dev->cam.no_urb_create = 0; + gspca_dev->cam.bulk_nurbs = 4; + /* Largest size the windows driver uses */ + gspca_dev->cam.bulk_size = BULK_SIZE; + /* Def need to use bulk transfers */ + gspca_dev->cam.bulk = 1; + + return 0; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int rc; + + sd->this_f = 0; + + rc = configure(gspca_dev); + if (rc < 0) { + PERR("Failed configure"); + return rc; + } + /* First two frames have messed up gains + Drop them to avoid special cases in user apps? */ + return 0; +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (len != BULK_SIZE) { + /* can we finish a frame? */ + if (sd->this_f + len == gspca_dev->pixfmt.sizeimage) { + gspca_frame_add(gspca_dev, LAST_PACKET, data, len); + PDEBUG(D_FRAM, "finish frame sz %u/%u w/ len %u\n", + sd->this_f, gspca_dev->pixfmt.sizeimage, len); + /* lost some data, discard the frame */ + } else { + gspca_frame_add(gspca_dev, DISCARD_PACKET, NULL, 0); + PDEBUG(D_FRAM, "abort frame sz %u/%u w/ len %u\n", + sd->this_f, gspca_dev->pixfmt.sizeimage, len); + } + sd->this_f = 0; + } else { + if (sd->this_f == 0) + gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); + else + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + sd->this_f += len; + } +} + +static int sd_init(struct gspca_dev *gspca_dev) +{ + return 0; +} + +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *) gspca_dev; + + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + setexposure(gspca_dev, ctrl->val); + break; + case V4L2_CID_GAIN: + /* gspca_dev->gain automatically updated */ + setggain(gspca_dev, gspca_dev->gain->val); + break; + case V4L2_CID_BLUE_BALANCE: + sd->blue->val = ctrl->val; + setbgain(gspca_dev, sd->blue->val, gspca_dev->gain->val); + break; + case V4L2_CID_RED_BALANCE: + sd->red->val = ctrl->val; + setrgain(gspca_dev, sd->red->val, gspca_dev->gain->val); + break; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 4); + + gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + /* Mostly limited by URB timeouts */ + /* XXX: make dynamic based on frame rate? */ + V4L2_CID_EXPOSURE, 0, 800, 1, 350); + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 511, 1, 128); + sd->blue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 0, 1023, 1, 80); + sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 1023, 1, 295); + + if (hdl->error) { + PERR("Could not initialize controls\n"); + return hdl->error; + } + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .config = sd_config, + .init = sd_init, + .init_controls = sd_init_controls, + .start = sd_start, + .pkt_scan = sd_pkt_scan, +}; + +/* Table of supported USB devices */ +static const struct usb_device_id device_table[] = { + /* Commented out devices should be related */ + /* AS: AmScope, TT: ToupTek */ + /* { USB_DEVICE(0x0547, 0x6035) }, TT UCMOS00350KPA */ + /* { USB_DEVICE(0x0547, 0x6130) }, TT UCMOS01300KPA */ + /* { USB_DEVICE(0x0547, 0x6200) }, TT UCMOS02000KPA */ + /* { USB_DEVICE(0x0547, 0x6310) }, TT UCMOS03100KPA */ + /* { USB_DEVICE(0x0547, 0x6510) }, TT UCMOS05100KPA */ + /* { USB_DEVICE(0x0547, 0x6800) }, TT UCMOS08000KPA */ + /* { USB_DEVICE(0x0547, 0x6801) }, TT UCMOS08000KPB */ + { USB_DEVICE(0x0547, 0x6801) }, /* TT UCMOS08000KPB, AS MU800 */ + /* { USB_DEVICE(0x0547, 0x6900) }, TT UCMOS09000KPA */ + /* { USB_DEVICE(0x0547, 0x6901) }, TT UCMOS09000KPB */ + /* { USB_DEVICE(0x0547, 0x6010) }, TT UCMOS10000KPA */ + /* { USB_DEVICE(0x0547, 0x6014) }, TT UCMOS14000KPA */ + /* { USB_DEVICE(0x0547, 0x6131) }, TT UCMOS01300KMA */ + /* { USB_DEVICE(0x0547, 0x6511) }, TT UCMOS05100KMA */ + /* { USB_DEVICE(0x0547, 0x8080) }, TT UHCCD00800KPA */ + /* { USB_DEVICE(0x0547, 0x8140) }, TT UHCCD01400KPA */ + /* { USB_DEVICE(0x0547, 0x8141) }, TT EXCCD01400KPA */ + /* { USB_DEVICE(0x0547, 0x8200) }, TT UHCCD02000KPA */ + /* { USB_DEVICE(0x0547, 0x8201) }, TT UHCCD02000KPB */ + /* { USB_DEVICE(0x0547, 0x8310) }, TT UHCCD03100KPA */ + /* { USB_DEVICE(0x0547, 0x8500) }, TT UHCCD05000KPA */ + /* { USB_DEVICE(0x0547, 0x8510) }, TT UHCCD05100KPA */ + /* { USB_DEVICE(0x0547, 0x8600) }, TT UHCCD06000KPA */ + /* { USB_DEVICE(0x0547, 0x8800) }, TT UHCCD08000KPA */ + /* { USB_DEVICE(0x0547, 0x8315) }, TT UHCCD03150KPA */ + /* { USB_DEVICE(0x0547, 0x7800) }, TT UHCCD00800KMA */ + /* { USB_DEVICE(0x0547, 0x7140) }, TT UHCCD01400KMA */ + /* { USB_DEVICE(0x0547, 0x7141) }, TT UHCCD01400KMB */ + /* { USB_DEVICE(0x0547, 0x7200) }, TT UHCCD02000KMA */ + /* { USB_DEVICE(0x0547, 0x7315) }, TT UHCCD03150KMA */ + { } +}; +MODULE_DEVICE_TABLE(usb, device_table); + +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +static int __init sd_mod_init(void) +{ + int ret; + + ret = usb_register(&sd_driver); + if (ret < 0) + return ret; + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/usb/gspca/vc032x.c b/drivers/media/usb/gspca/vc032x.c index c00ac57de510..b4efb2fb36fa 100644 --- a/drivers/media/usb/gspca/vc032x.c +++ b/drivers/media/usb/gspca/vc032x.c @@ -68,12 +68,12 @@ enum sensors { static const struct v4l2_pix_format vc0321_mode[] = { {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, - .bytesperline = 320, + .bytesperline = 320 * 2, .sizeimage = 320 * 240 * 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, - .bytesperline = 640, + .bytesperline = 640 * 2, .sizeimage = 640 * 480 * 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, @@ -97,17 +97,17 @@ static const struct v4l2_pix_format vc0323_mode[] = { }; static const struct v4l2_pix_format bi_mode[] = { {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 320, + .bytesperline = 320 * 2, .sizeimage = 320 * 240 * 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 2}, {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 640, + .bytesperline = 640 * 2, .sizeimage = 640 * 480 * 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, {1280, 1024, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 1280, + .bytesperline = 1280 * 2, .sizeimage = 1280 * 1024 * 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, diff --git a/drivers/media/usb/pvrusb2/pvrusb2-audio.c b/drivers/media/usb/pvrusb2/pvrusb2-audio.c index cc06d5e4adcc..45276c628482 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-audio.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.c @@ -84,13 +84,3 @@ void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0); } } - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-audio.h b/drivers/media/usb/pvrusb2/pvrusb2-audio.h index e3e63d750891..27cefb5cb170 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-audio.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.h @@ -25,13 +25,3 @@ #include "pvrusb2-hdw-internal.h" void pvr2_msp3400_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *); #endif /* __PVRUSB2_AUDIO_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c index c8761c71c9d2..924fc4c6019a 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-context.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c @@ -418,14 +418,3 @@ struct pvr2_ioread *pvr2_channel_create_mpeg_stream( pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key)); return cp; } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.h b/drivers/media/usb/pvrusb2/pvrusb2-context.h index d657e53bbfa3..1c1d442d9ea3 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-context.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-context.h @@ -83,12 +83,3 @@ int pvr2_context_global_init(void); void pvr2_context_global_done(void); #endif /* __PVRUSB2_CONTEXT_H */ -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c index 88320900dbd4..f82f0f0f2c04 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c @@ -82,14 +82,3 @@ void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) sd->ops->audio->s_routing(sd, input, 0, 0); } } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h index 53ba548b72a7..86c17bee56f9 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h @@ -36,13 +36,3 @@ void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *); #endif /* __PVRUSB2_AUDIO_CS53L32A_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c index 7d5a7139a45a..958db170a048 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c @@ -596,14 +596,3 @@ int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr, } while(0); LOCK_GIVE(cptr->hdw->big_lock); return ret; } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h index 794ff90121c7..c175571868a3 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h @@ -110,13 +110,3 @@ int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *, unsigned int *len); #endif /* __PVRUSB2_CTRL_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c index c514d0b9ffdc..1a81aa70509b 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -152,15 +152,3 @@ void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) sd->ops->audio->s_routing(sd, (u32)aud_input, 0, 0); } } - - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h index e35c2322a08c..2eed7b7ee25e 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h @@ -40,13 +40,3 @@ void pvr2_cx25840_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *sd); #endif /* __PVRUSB2_CX2584X_V4L_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debug.h b/drivers/media/usb/pvrusb2/pvrusb2-debug.h index be79249f8628..4ef2ebcd97a5 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-debug.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-debug.h @@ -57,13 +57,3 @@ extern int pvrusb2_debug; #endif /* __PVRUSB2_HDW_INTERNAL_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c index 4279ebb811a1..e4022bcb155b 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c @@ -322,14 +322,3 @@ int pvr2_debugifc_docmd(struct pvr2_hdw *hdw,const char *buf, return 0; } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h index 2f8d46761cd0..a8dfc55f136f 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h @@ -40,13 +40,3 @@ int pvr2_debugifc_docmd(struct pvr2_hdw *, const char *buf_ptr,unsigned int buf_size); #endif /* __PVRUSB2_DEBUGIFC_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c index adc501d3c287..06c4c3dabcde 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c @@ -564,13 +564,3 @@ MODULE_FIRMWARE(PVR2_FIRMWARE_29xxx); MODULE_FIRMWARE(PVR2_FIRMWARE_24xxx); MODULE_FIRMWARE(PVR2_FIRMWARE_73xxx); MODULE_FIRMWARE(PVR2_FIRMWARE_75xxx); - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.h b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h index 273c8d4b3853..5aeefb6a991f 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h @@ -187,13 +187,3 @@ struct pvr2_device_desc { extern struct usb_device_id pvr2_device_table[]; #endif /* __PVRUSB2_HDW_INTERNAL_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c index 9515f3a68f8f..e1907cd0c3b7 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c @@ -152,13 +152,3 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw) return 0; } - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h index cca3216f94cc..f1e33c807f46 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h @@ -27,13 +27,3 @@ struct pvr2_hdw; int pvr2_eeprom_analyze(struct pvr2_hdw *); #endif /* __PVRUSB2_EEPROM_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c index f7702aeeda3f..593b3e9b6bfd 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c @@ -538,14 +538,3 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw) return status; } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.h b/drivers/media/usb/pvrusb2/pvrusb2-encoder.h index 232fefbcd1ac..a2bfb48f1ecd 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.h @@ -30,13 +30,3 @@ int pvr2_encoder_start(struct pvr2_hdw *); int pvr2_encoder_stop(struct pvr2_hdw *); #endif /* __PVRUSB2_ENCODER_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h index 614755ea2ea3..06a15a68bcfd 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h @@ -60,13 +60,3 @@ #define FX2CMD_ONAIR_DTV_POWER_OFF 0xa3u #endif /* _PVRUSB2_FX2_CMD_H_ */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h index 036952f2a3cb..1f9c02801cee 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h @@ -394,13 +394,3 @@ unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *); void pvr2_hdw_status_poll(struct pvr2_hdw *); #endif /* __PVRUSB2_HDW_INTERNAL_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index 2fd9b5e0e2a9..930593d7028d 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -2425,22 +2425,18 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, } if (!hdw) goto fail; - init_timer(&hdw->quiescent_timer); - hdw->quiescent_timer.data = (unsigned long)hdw; - hdw->quiescent_timer.function = pvr2_hdw_quiescent_timeout; + setup_timer(&hdw->quiescent_timer, pvr2_hdw_quiescent_timeout, + (unsigned long)hdw); - init_timer(&hdw->decoder_stabilization_timer); - hdw->decoder_stabilization_timer.data = (unsigned long)hdw; - hdw->decoder_stabilization_timer.function = - pvr2_hdw_decoder_stabilization_timeout; + setup_timer(&hdw->decoder_stabilization_timer, + pvr2_hdw_decoder_stabilization_timeout, + (unsigned long)hdw); - init_timer(&hdw->encoder_wait_timer); - hdw->encoder_wait_timer.data = (unsigned long)hdw; - hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout; + setup_timer(&hdw->encoder_wait_timer, pvr2_hdw_encoder_wait_timeout, + (unsigned long)hdw); - init_timer(&hdw->encoder_run_timer); - hdw->encoder_run_timer.data = (unsigned long)hdw; - hdw->encoder_run_timer.function = pvr2_hdw_encoder_run_timeout; + setup_timer(&hdw->encoder_run_timer, pvr2_hdw_encoder_run_timeout, + (unsigned long)hdw); hdw->master_state = PVR2_STATE_DEAD; @@ -3680,10 +3676,8 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, hdw->ctl_timeout_flag = 0; hdw->ctl_write_pend_flag = 0; hdw->ctl_read_pend_flag = 0; - init_timer(&timer); + setup_timer(&timer, pvr2_ctl_timeout, (unsigned long)hdw); timer.expires = jiffies + timeout; - timer.data = (unsigned long)hdw; - timer.function = pvr2_ctl_timeout; if (write_len) { hdw->cmd_debug_state = 2; @@ -4035,11 +4029,6 @@ int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw) } -int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *hdw) -{ - return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_OFF); -} - int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw) { @@ -4301,9 +4290,8 @@ static int state_eval_encoder_config(struct pvr2_hdw *hdw) the encoder. */ if (!hdw->state_encoder_waitok) { hdw->encoder_wait_timer.expires = - jiffies + - (HZ * TIME_MSEC_ENCODER_WAIT - / 1000); + jiffies + msecs_to_jiffies( + TIME_MSEC_ENCODER_WAIT); add_timer(&hdw->encoder_wait_timer); } } @@ -4426,8 +4414,8 @@ static int state_eval_encoder_run(struct pvr2_hdw *hdw) if (pvr2_encoder_start(hdw) < 0) return !0; hdw->state_encoder_run = !0; if (!hdw->state_encoder_runok) { - hdw->encoder_run_timer.expires = - jiffies + (HZ * TIME_MSEC_ENCODER_OK / 1000); + hdw->encoder_run_timer.expires = jiffies + + msecs_to_jiffies(TIME_MSEC_ENCODER_OK); add_timer(&hdw->encoder_run_timer); } } @@ -4518,9 +4506,8 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw) but before we did the pending check. */ if (!hdw->state_decoder_quiescent) { hdw->quiescent_timer.expires = - jiffies + - (HZ * TIME_MSEC_DECODER_WAIT - / 1000); + jiffies + msecs_to_jiffies( + TIME_MSEC_DECODER_WAIT); add_timer(&hdw->quiescent_timer); } } @@ -4544,9 +4531,8 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw) hdw->state_decoder_run = !0; if (hdw->decoder_client_id == PVR2_CLIENT_ID_SAA7115) { hdw->decoder_stabilization_timer.expires = - jiffies + - (HZ * TIME_MSEC_DECODER_STABILIZATION_WAIT / - 1000); + jiffies + msecs_to_jiffies( + TIME_MSEC_DECODER_STABILIZATION_WAIT); add_timer(&hdw->decoder_stabilization_timer); } else { hdw->state_decoder_ready = !0; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h index 41847076f51a..a82a00dd7329 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h @@ -271,9 +271,6 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *); /* Execute simple reset command */ int pvr2_hdw_cmd_powerup(struct pvr2_hdw *); -/* suspend */ -int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *); - /* Order decoder to reset */ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *); @@ -343,13 +340,3 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw); int pvr2_upload_firmware2(struct pvr2_hdw *hdw); #endif /* __PVRUSB2_HDW_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c index b5e929f1bf82..4baa9d632a4e 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c @@ -686,13 +686,3 @@ void pvr2_i2c_core_done(struct pvr2_hdw *hdw) hdw->i2c_linked = 0; } } - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h index 6a75769200bd..a10a3e8e9345 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h @@ -27,14 +27,3 @@ void pvr2_i2c_core_done(struct pvr2_hdw *); #endif /* __PVRUSB2_I2C_ADAPTER_H */ - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c index 1e354747de3f..0c08f22bdfce 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-io.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c @@ -682,14 +682,3 @@ int pvr2_buffer_get_id(struct pvr2_buffer *bp) { return bp->id; } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.h b/drivers/media/usb/pvrusb2/pvrusb2-io.h index afb7e87c0394..0c47c6a95ab2 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-io.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-io.h @@ -90,13 +90,3 @@ int pvr2_buffer_get_id(struct pvr2_buffer *); int pvr2_buffer_queue(struct pvr2_buffer *); #endif /* __PVRUSB2_IO_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c index bba6115c9ae8..cd995b54732e 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c @@ -499,14 +499,3 @@ int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt) cp,req_cnt,ret); return ret; } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ioread.h b/drivers/media/usb/pvrusb2/pvrusb2-ioread.h index 100e0780e1aa..0b1f0fbc3438 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ioread.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.h @@ -36,13 +36,3 @@ int pvr2_ioread_read(struct pvr2_ioread *,void __user *buf,unsigned int cnt); int pvr2_ioread_avail(struct pvr2_ioread *); #endif /* __PVRUSB2_IOREAD_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-main.c b/drivers/media/usb/pvrusb2/pvrusb2-main.c index c1d9bb61cd77..86be902a0049 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-main.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-main.c @@ -169,14 +169,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_VERSION("0.9.1"); - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.c b/drivers/media/usb/pvrusb2/pvrusb2-std.c index 453627b07833..9a596a3a4c27 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-std.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-std.c @@ -398,14 +398,3 @@ v4l2_std_id pvr2_std_get_usable(void) { return CSTD_ALL; } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.h b/drivers/media/usb/pvrusb2/pvrusb2-std.h index a35c53d0b320..ed4ec0474429 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-std.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-std.h @@ -47,13 +47,3 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, v4l2_std_id pvr2_std_get_usable(void); #endif /* __PVRUSB2_STD_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c index 6ef1335b2858..06fe63ced58c 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c @@ -848,14 +848,3 @@ static ssize_t debugcmd_store(struct device *class_dev, return count; } #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h index 6d875bfe7991..6f0579e1e07b 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h @@ -34,13 +34,3 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *, struct pvr2_sysfs_class *); #endif /* __PVRUSB2_SYSFS_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-util.h b/drivers/media/usb/pvrusb2/pvrusb2-util.h index 92b75544ee2e..5465bf9cd73e 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-util.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-util.h @@ -50,13 +50,3 @@ #endif /* __PVRUSB2_UTIL_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 1b158f1167ed..35e4ea530494 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -89,16 +89,6 @@ static int vbi_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1}; module_param_array(vbi_nr, int, NULL, 0444); MODULE_PARM_DESC(vbi_nr, "Offset for device's vbi dev minor"); -static struct v4l2_capability pvr_capability ={ - .driver = "pvrusb2", - .card = "Hauppauge WinTV pvr-usb2", - .bus_info = "usb", - .version = LINUX_VERSION_CODE, - .capabilities = (V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | - V4L2_CAP_READWRITE), -}; - static struct v4l2_fmtdesc pvr_fmtdesc [] = { { .index = 0, @@ -160,10 +150,22 @@ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability * struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; - memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); + strlcpy(cap->driver, "pvrusb2", sizeof(cap->driver)); strlcpy(cap->bus_info, pvr2_hdw_get_bus_info(hdw), sizeof(cap->bus_info)); strlcpy(cap->card, pvr2_hdw_get_desc(hdw), sizeof(cap->card)); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | + V4L2_CAP_AUDIO | V4L2_CAP_RADIO | + V4L2_CAP_READWRITE | V4L2_CAP_DEVICE_CAPS; + switch (fh->pdi->devbase.vfl_type) { + case VFL_TYPE_GRABBER: + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO; + break; + case VFL_TYPE_RADIO: + cap->device_caps = V4L2_CAP_RADIO; + break; + } + cap->device_caps |= V4L2_CAP_TUNER | V4L2_CAP_READWRITE; return 0; } @@ -1360,13 +1362,3 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp) pvr2_v4l2_destroy_no_lock(vp); return NULL; } - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h index 34c011a7b107..e455c9515841 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h @@ -27,13 +27,3 @@ struct pvr2_v4l2; struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *); #endif /* __PVRUSB2_V4L2_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c index 2e205c99eb96..139b39740534 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c @@ -101,14 +101,3 @@ void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) sd->ops->video->s_routing(sd, input, 0, 0); } } - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h index 3b0bd5db602b..dacf3ec7f9e1 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h @@ -36,13 +36,3 @@ void pvr2_saa7115_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *); #endif /* __PVRUSB2_VIDEO_V4L_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c index 3ac8d751a5c0..f1df94a2436f 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c @@ -56,15 +56,3 @@ void pvr2_wm8775_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) sd->ops->audio->s_routing(sd, input, 0, 0); } } - - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h index 0577bc7246fb..a4ee12e28d5c 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h @@ -40,13 +40,3 @@ void pvr2_wm8775_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *sd); #endif /* __PVRUSB2_WM8775_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2.h b/drivers/media/usb/pvrusb2/pvrusb2.h index 240de9b35661..95f98a87abb3 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2.h +++ b/drivers/media/usb/pvrusb2/pvrusb2.h @@ -30,13 +30,3 @@ #define PVR_NUM 20 #endif /* __PVRUSB2_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 15b754da4a2c..702267e208ba 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -508,7 +508,8 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev) } /* Must be called with vb_queue_lock hold */ -static void pwc_cleanup_queued_bufs(struct pwc_device *pdev) +static void pwc_cleanup_queued_bufs(struct pwc_device *pdev, + enum vb2_buffer_state state) { unsigned long flags = 0; @@ -519,7 +520,7 @@ static void pwc_cleanup_queued_bufs(struct pwc_device *pdev) buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf, list); list_del(&buf->list); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + vb2_buffer_done(&buf->vb, state); } spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags); } @@ -674,7 +675,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) pwc_set_leds(pdev, 0, 0); pwc_camera_power(pdev, 0); /* And cleanup any queued bufs!! */ - pwc_cleanup_queued_bufs(pdev); + pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED); } mutex_unlock(&pdev->v4l2_lock); @@ -692,7 +693,9 @@ static void stop_streaming(struct vb2_queue *vq) pwc_isoc_cleanup(pdev); } - pwc_cleanup_queued_bufs(pdev); + pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_ERROR); + if (pdev->fill_buf) + vb2_buffer_done(&pdev->fill_buf->vb, VB2_BUF_STATE_ERROR); mutex_unlock(&pdev->v4l2_lock); } @@ -1125,7 +1128,6 @@ static void usb_pwc_disconnect(struct usb_interface *intf) if (pdev->vb_queue.streaming) pwc_isoc_cleanup(pdev); pdev->udev = NULL; - pwc_cleanup_queued_bufs(pdev); v4l2_device_disconnect(&pdev->v4l2_dev); video_unregister_device(&pdev->vdev); diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index de55e96fed15..0f3c34d47ec3 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -2274,9 +2274,7 @@ static int s2255_probe(struct usb_interface *interface, dev_err(&interface->dev, "Could not find bulk-in endpoint\n"); goto errorEP; } - init_timer(&dev->timer); - dev->timer.function = s2255_timer; - dev->timer.data = (unsigned long)dev->fw_data; + setup_timer(&dev->timer, s2255_timer, (unsigned long)dev->fw_data); init_waitqueue_head(&dev->fw_data->wait_fw); for (i = 0; i < MAX_CHANNELS; i++) { struct s2255_vc *vc = &dev->vc[i]; diff --git a/drivers/media/usb/siano/Kconfig b/drivers/media/usb/siano/Kconfig index 5afbd9a4b55c..d37b742d4f7a 100644 --- a/drivers/media/usb/siano/Kconfig +++ b/drivers/media/usb/siano/Kconfig @@ -5,7 +5,9 @@ config SMS_USB_DRV tristate "Siano SMS1xxx based MDTV receiver" depends on DVB_CORE && HAS_DMA + depends on !RC_CORE || RC_CORE select MEDIA_COMMON_OPTIONS + select SMS_SIANO_MDTV ---help--- Choose if you would like to have Siano's support for USB interface diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index a47629108c1b..65a326c5128f 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -38,10 +38,6 @@ #include "stk1160.h" #include "stk1160-reg.h" -static unsigned int vidioc_debug; -module_param(vidioc_debug, int, 0644); -MODULE_PARM_DESC(vidioc_debug, "enable debug messages [vidioc]"); - static bool keep_buffers; module_param(keep_buffers, bool, 0644); MODULE_PARM_DESC(keep_buffers, "don't release buffers upon stop streaming"); @@ -659,7 +655,6 @@ int stk1160_video_register(struct stk1160 *dev) /* Initialize video_device with a template structure */ dev->vdev = v4l_template; - dev->vdev.debug = vidioc_debug; dev->vdev.queue = &dev->vb_vidq; /* diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 3588dc38db87..e08fa587332f 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -1262,7 +1262,6 @@ static int stk_register_video_device(struct stk_camera *dev) dev->vdev = stk_v4l_data; dev->vdev.lock = &dev->lock; - dev->vdev.debug = debug; dev->vdev.v4l2_dev = &dev->v4l2_dev; video_set_drvdata(&dev->vdev, dev); err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 793577fc4633..0f14d3ccc7b4 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -941,7 +941,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, fmt = format_by_fourcc(f->fmt.pix.pixelformat); if (NULL == fmt) { - dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)" + dprintk(dev, 2, "Fourcc format (0x%08x)" " invalid.\n", f->fmt.pix.pixelformat); return -EINVAL; } @@ -1622,7 +1622,6 @@ static struct video_device *vdev_init(struct tm6000_core *dev, *vfd = *template; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; - vfd->debug = tm6000_debug; vfd->lock = &dev->lock; snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); diff --git a/drivers/media/usb/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c index 302aa07c458f..44b0c28d69b6 100644 --- a/drivers/media/usb/usbvision/usbvision-core.c +++ b/drivers/media/usb/usbvision/usbvision-core.c @@ -2194,9 +2194,8 @@ static void usbvision_power_off_timer(unsigned long data) void usbvision_init_power_off_timer(struct usb_usbvision *usbvision) { - init_timer(&usbvision->power_off_timer); - usbvision->power_off_timer.data = (long)usbvision; - usbvision->power_off_timer.function = usbvision_power_off_timer; + setup_timer(&usbvision->power_off_timer, usbvision_power_off_timer, + (unsigned long)usbvision); } void usbvision_set_power_off_timer(struct usb_usbvision *usbvision) @@ -2502,11 +2501,3 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel) usbvision_set_audio(usbvision, audio[channel]); return 0; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/usbvision/usbvision-i2c.c b/drivers/media/usb/usbvision/usbvision-i2c.c index ba262a32bd3a..26dbcb1146af 100644 --- a/drivers/media/usb/usbvision/usbvision-i2c.c +++ b/drivers/media/usb/usbvision/usbvision-i2c.c @@ -445,11 +445,3 @@ static struct i2c_adapter i2c_adap_template = { .owner = THIS_MODULE, .name = "usbvision", }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index 693d5f409138..cd2fbf11e3b4 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -1716,11 +1716,3 @@ static void __exit usbvision_exit(void) module_init(usbvision_init); module_exit(usbvision_exit); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/usbvision/usbvision.h b/drivers/media/usb/usbvision/usbvision.h index a0c73cf1517c..77aeb1ed9a81 100644 --- a/drivers/media/usb/usbvision/usbvision.h +++ b/drivers/media/usb/usbvision/usbvision.h @@ -517,11 +517,3 @@ int usbvision_power_off(struct usb_usbvision *usbvision); int usbvision_power_on(struct usb_usbvision *usbvision); #endif /* __LINUX_USBVISION_H */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 6a4b0b8cd270..cf27006c29dc 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -137,6 +137,11 @@ static struct uvc_format_desc uvc_fmts[] = { .guid = UVC_GUID_FORMAT_RGBP, .fcc = V4L2_PIX_FMT_RGB565, }, + { + .name = "BGR 8:8:8 (BGR3)", + .guid = UVC_GUID_FORMAT_BGR3, + .fcc = V4L2_PIX_FMT_BGR24, + }, { .name = "H.264", .guid = UVC_GUID_FORMAT_H264, diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index cc960723b926..10c554e7655c 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -143,20 +143,6 @@ static void uvc_buffer_finish(struct vb2_buffer *vb) uvc_video_clock_update(stream, &vb->v4l2_buf, buf); } -static void uvc_wait_prepare(struct vb2_queue *vq) -{ - struct uvc_video_queue *queue = vb2_get_drv_priv(vq); - - mutex_unlock(&queue->mutex); -} - -static void uvc_wait_finish(struct vb2_queue *vq) -{ - struct uvc_video_queue *queue = vb2_get_drv_priv(vq); - - mutex_lock(&queue->mutex); -} - static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count) { struct uvc_video_queue *queue = vb2_get_drv_priv(vq); @@ -195,8 +181,8 @@ static struct vb2_ops uvc_queue_qops = { .buf_prepare = uvc_buffer_prepare, .buf_queue = uvc_buffer_queue, .buf_finish = uvc_buffer_finish, - .wait_prepare = uvc_wait_prepare, - .wait_finish = uvc_wait_finish, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .start_streaming = uvc_start_streaming, .stop_streaming = uvc_stop_streaming, }; @@ -214,6 +200,7 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, queue->queue.mem_ops = &vb2_vmalloc_memops; queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC | V4L2_BUF_FLAG_TSTAMP_SRC_SOE; + queue->queue.lock = &queue->mutex; ret = vb2_queue_init(&queue->queue); if (ret) return ret; diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 9c5cbcf16529..43e953f73e02 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -13,7 +13,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 9637e8b86949..20ccc9d315dc 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1734,13 +1734,13 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset) uvc_video_clock_reset(stream); + if (!uvc_queue_streaming(&stream->queue)) + return 0; + ret = uvc_commit_video(stream, &stream->ctrl); if (ret < 0) return ret; - if (!uvc_queue_streaming(&stream->queue)) - return 0; - return uvc_init_video(stream, GFP_NOIO); } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index f0a04b532ede..c63e5b55e143 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -109,6 +109,9 @@ #define UVC_GUID_FORMAT_RGBP \ { 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_BGR3 \ + { 0x7d, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, \ + 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} #define UVC_GUID_FORMAT_M420 \ { 'M', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 5c006277b8b1..ca850316d379 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -1454,8 +1454,6 @@ static int zr364xx_probe(struct usb_interface *intf, cam->vdev.v4l2_dev = &cam->v4l2_dev; cam->vdev.ctrl_handler = &cam->ctrl_handler; video_set_drvdata(&cam->vdev, cam); - if (debug) - cam->vdev.debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; cam->udev = udev; diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 9aa530a8bea9..86bb93fd7db8 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -47,15 +47,15 @@ static ssize_t index_show(struct device *cd, } static DEVICE_ATTR_RO(index); -static ssize_t debug_show(struct device *cd, +static ssize_t dev_debug_show(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vdev = to_video_device(cd); - return sprintf(buf, "%i\n", vdev->debug); + return sprintf(buf, "%i\n", vdev->dev_debug); } -static ssize_t debug_store(struct device *cd, struct device_attribute *attr, +static ssize_t dev_debug_store(struct device *cd, struct device_attribute *attr, const char *buf, size_t len) { struct video_device *vdev = to_video_device(cd); @@ -66,10 +66,10 @@ static ssize_t debug_store(struct device *cd, struct device_attribute *attr, if (res) return res; - vdev->debug = value; + vdev->dev_debug = value; return len; } -static DEVICE_ATTR_RW(debug); +static DEVICE_ATTR_RW(dev_debug); static ssize_t name_show(struct device *cd, struct device_attribute *attr, char *buf) @@ -82,7 +82,7 @@ static DEVICE_ATTR_RO(name); static struct attribute *video_device_attrs[] = { &dev_attr_name.attr, - &dev_attr_debug.attr, + &dev_attr_dev_debug.attr, &dev_attr_index.attr, NULL, }; @@ -304,7 +304,8 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf, return -EINVAL; if (video_is_registered(vdev)) ret = vdev->fops->read(filp, buf, sz, off); - if (vdev->debug) + if ((vdev->dev_debug & V4L2_DEV_DEBUG_FOP) && + (vdev->dev_debug & V4L2_DEV_DEBUG_STREAMING)) printk(KERN_DEBUG "%s: read: %zd (%d)\n", video_device_node_name(vdev), sz, ret); return ret; @@ -320,7 +321,8 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf, return -EINVAL; if (video_is_registered(vdev)) ret = vdev->fops->write(filp, buf, sz, off); - if (vdev->debug) + if ((vdev->dev_debug & V4L2_DEV_DEBUG_FOP) && + (vdev->dev_debug & V4L2_DEV_DEBUG_STREAMING)) printk(KERN_DEBUG "%s: write: %zd (%d)\n", video_device_node_name(vdev), sz, ret); return ret; @@ -335,7 +337,7 @@ static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll) return DEFAULT_POLLMASK; if (video_is_registered(vdev)) res = vdev->fops->poll(filp, poll); - if (vdev->debug > 2) + if (vdev->dev_debug & V4L2_DEV_DEBUG_POLL) printk(KERN_DEBUG "%s: poll: %08x\n", video_device_node_name(vdev), res); return res; @@ -404,7 +406,7 @@ static unsigned long v4l2_get_unmapped_area(struct file *filp, if (!video_is_registered(vdev)) return -ENODEV; ret = vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags); - if (vdev->debug) + if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) printk(KERN_DEBUG "%s: get_unmapped_area (%d)\n", video_device_node_name(vdev), ret); return ret; @@ -420,7 +422,7 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) return -ENODEV; if (video_is_registered(vdev)) ret = vdev->fops->mmap(filp, vm); - if (vdev->debug) + if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) printk(KERN_DEBUG "%s: mmap (%d)\n", video_device_node_name(vdev), ret); return ret; @@ -450,7 +452,7 @@ static int v4l2_open(struct inode *inode, struct file *filp) ret = -ENODEV; } - if (vdev->debug) + if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) printk(KERN_DEBUG "%s: open (%d)\n", video_device_node_name(vdev), ret); /* decrease the refcount in case of an error */ @@ -467,7 +469,7 @@ static int v4l2_release(struct inode *inode, struct file *filp) if (vdev->fops->release) ret = vdev->fops->release(filp); - if (vdev->debug) + if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) printk(KERN_DEBUG "%s: release\n", video_device_node_name(vdev)); @@ -1033,10 +1035,3 @@ MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab "); MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(VIDEO_MAJOR); - - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index faac2f4e0f3a..b08407225db1 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2339,7 +2339,7 @@ static long __video_do_ioctl(struct file *file, const struct v4l2_ioctl_info *info; void *fh = file->private_data; struct v4l2_fh *vfh = NULL; - int debug = vfd->debug; + int dev_debug = vfd->dev_debug; long ret = -ENOTTY; if (ops == NULL) { @@ -2388,11 +2388,15 @@ static long __video_do_ioctl(struct file *file, } done: - if (debug) { + if (dev_debug & (V4L2_DEV_DEBUG_IOCTL | V4L2_DEV_DEBUG_IOCTL_ARG)) { + if (!(dev_debug & V4L2_DEV_DEBUG_STREAMING) && + (cmd == VIDIOC_QBUF || cmd == VIDIOC_DQBUF)) + return ret; + v4l_printk_ioctl(video_device_node_name(vfd), cmd); if (ret < 0) pr_cont(": error %ld", ret); - if (debug == V4L2_DEBUG_IOCTL) + if (!(dev_debug & V4L2_DEV_DEBUG_IOCTL_ARG)) pr_cont("\n"); else if (_IOC_DIR(cmd) == _IOC_NONE) info->debug(arg, write_only); diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 543631c3557a..19a034e79be4 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -283,10 +283,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; - rval = v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop); - if (rval != -ENOIOCTLCMD) - return rval; - memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; @@ -308,10 +304,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; - rval = v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop); - if (rval != -ENOIOCTLCMD) - return rval; - memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index 3ff15f1c9d70..f669cedca8bd 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -145,12 +145,11 @@ struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf) } EXPORT_SYMBOL_GPL(videobuf_to_dma); -void videobuf_dma_init(struct videobuf_dmabuf *dma) +static void videobuf_dma_init(struct videobuf_dmabuf *dma) { memset(dma, 0, sizeof(*dma)); dma->magic = MAGIC_DMABUF; } -EXPORT_SYMBOL_GPL(videobuf_dma_init); static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, int direction, unsigned long data, unsigned long size) @@ -195,7 +194,7 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, return 0; } -int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, +static int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, unsigned long data, unsigned long size) { int ret; @@ -206,9 +205,8 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, return ret; } -EXPORT_SYMBOL_GPL(videobuf_dma_init_user); -int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, +static int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, int nr_pages) { int i; @@ -267,9 +265,8 @@ out_free_pages: return -ENOMEM; } -EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); -int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, +static int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, dma_addr_t addr, int nr_pages) { dprintk(1, "init overlay [%d pages @ bus 0x%lx]\n", @@ -284,9 +281,8 @@ int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, return 0; } -EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay); -int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma) +static int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma) { MAGIC_CHECK(dma->magic, MAGIC_DMABUF); BUG_ON(0 == dma->nr_pages); @@ -328,7 +324,6 @@ int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma) return 0; } -EXPORT_SYMBOL_GPL(videobuf_dma_map); int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma) { diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index d09a8916e940..bc08a829bc13 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -3146,27 +3146,26 @@ static int vb2_thread(void *data) prequeue--; } else { call_void_qop(q, wait_finish, q); - ret = vb2_internal_dqbuf(q, &fileio->b, 0); + if (!threadio->stop) + ret = vb2_internal_dqbuf(q, &fileio->b, 0); call_void_qop(q, wait_prepare, q); dprintk(5, "file io: vb2_dqbuf result: %d\n", ret); } - if (threadio->stop) - break; - if (ret) + if (ret || threadio->stop) break; try_to_freeze(); vb = q->bufs[fileio->b.index]; if (!(fileio->b.flags & V4L2_BUF_FLAG_ERROR)) - ret = threadio->fnc(vb, threadio->priv); - if (ret) - break; + if (threadio->fnc(vb, threadio->priv)) + break; call_void_qop(q, wait_finish, q); if (set_timestamp) v4l2_get_timestamp(&fileio->b.timestamp); - ret = vb2_internal_qbuf(q, &fileio->b); + if (!threadio->stop) + ret = vb2_internal_qbuf(q, &fileio->b); call_void_qop(q, wait_prepare, q); - if (ret) + if (ret || threadio->stop) break; } @@ -3235,11 +3234,11 @@ int vb2_thread_stop(struct vb2_queue *q) threadio->stop = true; vb2_internal_streamoff(q, q->type); call_void_qop(q, wait_prepare, q); + err = kthread_stop(threadio->thread); q->fileio = NULL; fileio->req.count = 0; vb2_reqbufs(q, &fileio->req); kfree(fileio); - err = kthread_stop(threadio->thread); threadio->thread = NULL; kfree(threadio); q->fileio = NULL; diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index fba944e50227..bcde88572429 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -95,7 +95,7 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr, if (vb2_get_contig_userptr(vaddr, size, &vma, &physp)) goto fail_pages_array_alloc; buf->vma = vma; - buf->vaddr = ioremap_nocache(physp, size); + buf->vaddr = (__force void *)ioremap_nocache(physp, size); if (!buf->vaddr) goto fail_pages_array_alloc; } else { @@ -155,7 +155,7 @@ static void vb2_vmalloc_put_userptr(void *buf_priv) kfree(buf->pages); } else { vb2_put_vma(buf->vma); - iounmap(buf->vaddr); + iounmap((__force void __iomem *)buf->vaddr); } kfree(buf); } @@ -211,6 +211,7 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma) return 0; } +#ifdef CONFIG_HAS_DMA /*********************************************/ /* DMABUF ops for exporters */ /*********************************************/ @@ -380,6 +381,8 @@ static struct dma_buf *vb2_vmalloc_get_dmabuf(void *buf_priv, unsigned long flag return dbuf; } +#endif /* CONFIG_HAS_DMA */ + /*********************************************/ /* callbacks for DMABUF buffers */ @@ -437,7 +440,9 @@ const struct vb2_mem_ops vb2_vmalloc_memops = { .put = vb2_vmalloc_put, .get_userptr = vb2_vmalloc_get_userptr, .put_userptr = vb2_vmalloc_put_userptr, +#ifdef CONFIG_HAS_DMA .get_dmabuf = vb2_vmalloc_get_dmabuf, +#endif .map_dmabuf = vb2_vmalloc_map_dmabuf, .unmap_dmabuf = vb2_vmalloc_unmap_dmabuf, .attach_dmabuf = vb2_vmalloc_attach_dmabuf, diff --git a/drivers/memory/fsl-corenet-cf.c b/drivers/memory/fsl-corenet-cf.c index fc7ab5a3561e..d708ded5457b 100644 --- a/drivers/memory/fsl-corenet-cf.c +++ b/drivers/memory/fsl-corenet-cf.c @@ -27,18 +27,29 @@ enum ccf_version { struct ccf_info { enum ccf_version version; int err_reg_offs; + bool has_brr; }; static const struct ccf_info ccf1_info = { .version = CCF1, .err_reg_offs = 0xa00, + .has_brr = false, }; static const struct ccf_info ccf2_info = { .version = CCF2, .err_reg_offs = 0xe40, + .has_brr = true, }; +/* + * This register is present but not documented, with different values for + * IP_ID, on other chips with fsl,corenet2-cf such as t4240 and b4860. + */ +#define CCF_BRR 0xbf8 +#define CCF_BRR_IPID 0xffff0000 +#define CCF_BRR_IPID_T1040 0x09310000 + static const struct of_device_id ccf_matches[] = { { .compatible = "fsl,corenet1-cf", @@ -66,6 +77,8 @@ struct ccf_err_regs { /* LAE/CV also valid for errdis and errinten */ #define ERRDET_LAE (1 << 0) /* Local Access Error */ #define ERRDET_CV (1 << 1) /* Coherency Violation */ +#define ERRDET_UTID (1 << 2) /* Unavailable Target ID (t1040) */ +#define ERRDET_MCST (1 << 3) /* Multicast Stash (t1040) */ #define ERRDET_CTYPE_SHIFT 26 /* Capture Type (ccf2 only) */ #define ERRDET_CTYPE_MASK (0x1f << ERRDET_CTYPE_SHIFT) #define ERRDET_CAP (1 << 31) /* Capture Valid (ccf2 only) */ @@ -84,6 +97,7 @@ struct ccf_private { struct device *dev; void __iomem *regs; struct ccf_err_regs __iomem *err_regs; + bool t1040; }; static irqreturn_t ccf_irq(int irq, void *dev_id) @@ -142,6 +156,12 @@ static irqreturn_t ccf_irq(int irq, void *dev_id) if (errdet & ERRDET_CV) dev_crit(ccf->dev, "Coherency Violation\n"); + if (errdet & ERRDET_UTID) + dev_crit(ccf->dev, "Unavailable Target ID\n"); + + if (errdet & ERRDET_MCST) + dev_crit(ccf->dev, "Multicast Stash\n"); + if (cap_valid) { dev_crit(ccf->dev, "address 0x%09llx, src id 0x%x\n", addr, src_id); @@ -157,6 +177,7 @@ static int ccf_probe(struct platform_device *pdev) struct ccf_private *ccf; struct resource *r; const struct of_device_id *match; + u32 errinten; int ret, irq; match = of_match_device(ccf_matches, &pdev->dev); @@ -183,6 +204,13 @@ static int ccf_probe(struct platform_device *pdev) ccf->info = match->data; ccf->err_regs = ccf->regs + ccf->info->err_reg_offs; + if (ccf->info->has_brr) { + u32 brr = ioread32be(ccf->regs + CCF_BRR); + + if ((brr & CCF_BRR_IPID) == CCF_BRR_IPID_T1040) + ccf->t1040 = true; + } + dev_set_drvdata(&pdev->dev, ccf); irq = platform_get_irq(pdev, 0); @@ -197,15 +225,19 @@ static int ccf_probe(struct platform_device *pdev) return ret; } + errinten = ERRDET_LAE | ERRDET_CV; + if (ccf->t1040) + errinten |= ERRDET_UTID | ERRDET_MCST; + switch (ccf->info->version) { case CCF1: /* On CCF1 this register enables rather than disables. */ - iowrite32be(ERRDET_LAE | ERRDET_CV, &ccf->err_regs->errdis); + iowrite32be(errinten, &ccf->err_regs->errdis); break; case CCF2: iowrite32be(0, &ccf->err_regs->errdis); - iowrite32be(ERRDET_LAE | ERRDET_CV, &ccf->err_regs->errinten); + iowrite32be(errinten, &ccf->err_regs->errinten); break; } diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c index 52a0c2f6264f..ae498b53ee40 100644 --- a/drivers/mfd/da9052-core.c +++ b/drivers/mfd/da9052-core.c @@ -554,7 +554,8 @@ int da9052_device_init(struct da9052 *da9052, u8 chip_id) return ret; } - ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info, + ret = mfd_add_devices(da9052->dev, PLATFORM_DEVID_AUTO, + da9052_subdev_info, ARRAY_SIZE(da9052_subdev_info), NULL, 0, NULL); if (ret) { dev_err(da9052->dev, "mfd_add_devices failed: %d\n", ret); diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c index dbdd0faeb6ce..210d1f85679e 100644 --- a/drivers/mfd/rtsx_usb.c +++ b/drivers/mfd/rtsx_usb.c @@ -681,21 +681,9 @@ static void rtsx_usb_disconnect(struct usb_interface *intf) #ifdef CONFIG_PM static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message) { - struct rtsx_ucr *ucr = - (struct rtsx_ucr *)usb_get_intfdata(intf); - dev_dbg(&intf->dev, "%s called with pm message 0x%04x\n", __func__, message.event); - /* - * Call to make sure LED is off during suspend to save more power. - * It is NOT a permanent state and could be turned on anytime later. - * Thus no need to call turn_on when resunming. - */ - mutex_lock(&ucr->dev_mutex); - rtsx_usb_turn_off_led(ucr); - mutex_unlock(&ucr->dev_mutex); - return 0; } diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c index 0d256cb002eb..d6b764349f9d 100644 --- a/drivers/mfd/tps65218.c +++ b/drivers/mfd/tps65218.c @@ -125,10 +125,21 @@ int tps65218_clear_bits(struct tps65218 *tps, unsigned int reg, } EXPORT_SYMBOL_GPL(tps65218_clear_bits); +static const struct regmap_range tps65218_yes_ranges[] = { + regmap_reg_range(TPS65218_REG_INT1, TPS65218_REG_INT2), + regmap_reg_range(TPS65218_REG_STATUS, TPS65218_REG_STATUS), +}; + +static const struct regmap_access_table tps65218_volatile_table = { + .yes_ranges = tps65218_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(tps65218_yes_ranges), +}; + static struct regmap_config tps65218_regmap_config = { .reg_bits = 8, .val_bits = 8, .cache_type = REGCACHE_RBTREE, + .volatile_table = &tps65218_volatile_table, }; static const struct regmap_irq tps65218_irqs[] = { @@ -193,6 +204,7 @@ static struct regmap_irq_chip tps65218_irq_chip = { .num_regs = 2, .mask_base = TPS65218_REG_INT_MASK1, + .status_base = TPS65218_REG_INT1, }; static const struct of_device_id of_tps65218_match_table[] = { diff --git a/drivers/misc/cxl/Makefile b/drivers/misc/cxl/Makefile index 165e98fef2c2..edb494d3ff27 100644 --- a/drivers/misc/cxl/Makefile +++ b/drivers/misc/cxl/Makefile @@ -1,3 +1,6 @@ -cxl-y += main.o file.o irq.o fault.o native.o context.o sysfs.o debugfs.o pci.o +cxl-y += main.o file.o irq.o fault.o native.o context.o sysfs.o debugfs.o pci.o trace.o obj-$(CONFIG_CXL) += cxl.o obj-$(CONFIG_CXL_BASE) += base.o + +# For tracepoints to include our trace.h from tracepoint infrastructure: +CFLAGS_trace.o := -I$(src) diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index 28078f8894a5..a1cee4767ec6 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -287,6 +287,13 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0}; #define CXL_PE_SOFTWARE_STATE_S (1ul << (31 - 30)) /* Suspend */ #define CXL_PE_SOFTWARE_STATE_T (1ul << (31 - 31)) /* Terminate */ +/****** CXL_PSL_RXCTL_An (Implementation Specific) ************************** + * Controls AFU Hang Pulse, which sets the timeout for the AFU to respond to + * the PSL for any response (except MMIO). Timeouts will occur between 1x to 2x + * of the hang pulse frequency. + */ +#define CXL_PSL_RXCTL_AFUHP_4S 0x7000000000000000ULL + /* SPA->sw_command_status */ #define CXL_SPA_SW_CMD_MASK 0xffff000000000000ULL #define CXL_SPA_SW_CMD_TERMINATE 0x0001000000000000ULL @@ -375,6 +382,10 @@ struct cxl_afu { int slice; int modes_supported; int current_mode; + int crs_num; + u64 crs_len; + u64 crs_offset; + struct list_head crs; enum prefault_modes prefault_mode; bool psa; bool pp_psa; @@ -481,6 +492,8 @@ void cxl_release_one_irq(struct cxl *adapter, int hwirq); int cxl_alloc_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter, unsigned int num); void cxl_release_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter); int cxl_setup_irq(struct cxl *adapter, unsigned int hwirq, unsigned int virq); +int cxl_update_image_control(struct cxl *adapter); +int cxl_reset(struct cxl *adapter); /* common == phyp + powernv */ struct cxl_process_element_common { @@ -542,6 +555,15 @@ static inline void __iomem *_cxl_p2n_addr(struct cxl_afu *afu, cxl_p2n_reg_t reg #define cxl_p2n_read(afu, reg) \ in_be64(_cxl_p2n_addr(afu, reg)) + +#define cxl_afu_cr_read64(afu, cr, off) \ + in_le64((afu)->afu_desc_mmio + (afu)->crs_offset + ((cr) * (afu)->crs_len) + (off)) +#define cxl_afu_cr_read32(afu, cr, off) \ + in_le32((afu)->afu_desc_mmio + (afu)->crs_offset + ((cr) * (afu)->crs_len) + (off)) +u16 cxl_afu_cr_read16(struct cxl_afu *afu, int cr, u64 off); +u8 cxl_afu_cr_read8(struct cxl_afu *afu, int cr, u64 off); + + struct cxl_calls { void (*cxl_slbia)(struct mm_struct *mm); struct module *owner; diff --git a/drivers/misc/cxl/fault.c b/drivers/misc/cxl/fault.c index f8684bca2d79..5286b8b704f5 100644 --- a/drivers/misc/cxl/fault.c +++ b/drivers/misc/cxl/fault.c @@ -20,6 +20,7 @@ #include #include "cxl.h" +#include "trace.h" static bool sste_matches(struct cxl_sste *sste, struct copro_slb *slb) { @@ -75,6 +76,7 @@ static void cxl_load_segment(struct cxl_context *ctx, struct copro_slb *slb) pr_devel("CXL Populating SST[%li]: %#llx %#llx\n", sste - ctx->sstp, slb->vsid, slb->esid); + trace_cxl_ste_write(ctx, sste - ctx->sstp, slb->esid, slb->vsid); sste->vsid_data = cpu_to_be64(slb->vsid); sste->esid_data = cpu_to_be64(slb->esid); @@ -116,6 +118,7 @@ static int cxl_handle_segment_miss(struct cxl_context *ctx, int rc; pr_devel("CXL interrupt: Segment fault pe: %i ea: %#llx\n", ctx->pe, ea); + trace_cxl_ste_miss(ctx, ea); if ((rc = cxl_fault_segment(ctx, mm, ea))) cxl_ack_ae(ctx); @@ -135,6 +138,8 @@ static void cxl_handle_page_fault(struct cxl_context *ctx, int result; unsigned long access, flags, inv_flags = 0; + trace_cxl_pte_miss(ctx, dsisr, dar); + if ((result = copro_handle_mm_fault(mm, dar, dsisr, &flt))) { pr_devel("copro_handle_mm_fault failed: %#x\n", result); return cxl_ack_ae(ctx); @@ -180,6 +185,12 @@ void cxl_handle_fault(struct work_struct *fault_work) return; } + /* Early return if the context is being / has been detached */ + if (ctx->status == CLOSED) { + cxl_ack_ae(ctx); + return; + } + pr_devel("CXL BOTTOM HALF handling fault for afu pe: %i. " "DSISR: %#llx DAR: %#llx\n", ctx->pe, dsisr, dar); diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c index b15d8113877c..2364bcadb9a9 100644 --- a/drivers/misc/cxl/file.c +++ b/drivers/misc/cxl/file.c @@ -23,6 +23,7 @@ #include #include "cxl.h" +#include "trace.h" #define CXL_NUM_MINORS 256 /* Total to reserve */ #define CXL_DEV_MINORS 13 /* 1 control + 4 AFUs * 3 (dedicated/master/shared) */ @@ -186,9 +187,13 @@ static long afu_ioctl_start_work(struct cxl_context *ctx, */ ctx->pid = get_pid(get_task_pid(current, PIDTYPE_PID)); + trace_cxl_attach(ctx, work.work_element_descriptor, work.num_interrupts, amr); + if ((rc = cxl_attach_process(ctx, false, work.work_element_descriptor, - amr))) + amr))) { + afu_release_irqs(ctx); goto out; + } ctx->status = STARTED; rc = 0; diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c index c294925f73ee..c8929c526691 100644 --- a/drivers/misc/cxl/irq.c +++ b/drivers/misc/cxl/irq.c @@ -17,6 +17,7 @@ #include #include "cxl.h" +#include "trace.h" /* XXX: This is implementation specific */ static irqreturn_t handle_psl_slice_error(struct cxl_context *ctx, u64 dsisr, u64 errstat) @@ -100,6 +101,8 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info) dsisr = irq_info->dsisr; dar = irq_info->dar; + trace_cxl_psl_irq(ctx, irq, dsisr, dar); + pr_devel("CXL interrupt %i for afu pe: %i DSISR: %#llx DAR: %#llx\n", irq, ctx->pe, dsisr, dar); if (dsisr & CXL_PSL_DSISR_An_DS) { @@ -167,6 +170,7 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info) } cxl_ack_irq(ctx, CXL_PSL_TFC_An_A, 0); + return IRQ_HANDLED; } if (dsisr & CXL_PSL_DSISR_An_OC) pr_devel("CXL interrupt: OS Context Warning\n"); @@ -237,6 +241,7 @@ static irqreturn_t cxl_irq_afu(int irq, void *data) return IRQ_HANDLED; } + trace_cxl_afu_irq(ctx, afu_irq, irq, hwirq); pr_devel("Received AFU interrupt %i for pe: %i (virq %i hwirq %lx)\n", afu_irq, ctx->pe, irq, hwirq); @@ -436,7 +441,7 @@ int afu_register_irqs(struct cxl_context *ctx, u32 count) */ INIT_LIST_HEAD(&ctx->irq_names); for (r = 1; r < CXL_IRQ_RANGES; r++) { - for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) { + for (i = 0; i < ctx->irqs.range[r]; i++) { irq_name = kmalloc(sizeof(struct cxl_irq_name), GFP_KERNEL); if (!irq_name) diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c index 4cde9b661642..8ccddceead66 100644 --- a/drivers/misc/cxl/main.c +++ b/drivers/misc/cxl/main.c @@ -23,6 +23,7 @@ #include #include "cxl.h" +#include "trace.h" static DEFINE_SPINLOCK(adapter_idr_lock); static DEFINE_IDR(cxl_adapter_idr); @@ -48,6 +49,7 @@ static inline void _cxl_slbia(struct cxl_context *ctx, struct mm_struct *mm) ctx->afu->adapter->adapter_num, ctx->afu->slice, ctx->pe); spin_lock_irqsave(&ctx->sste_lock, flags); + trace_cxl_slbia(ctx); memset(ctx->sstp, 0, ctx->sst_size); spin_unlock_irqrestore(&ctx->sste_lock, flags); mb(); diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index f2b37b41a0da..29185fc61276 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -18,24 +18,28 @@ #include #include "cxl.h" +#include "trace.h" static int afu_control(struct cxl_afu *afu, u64 command, u64 result, u64 mask, bool enabled) { u64 AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); + int rc = 0; spin_lock(&afu->afu_cntl_lock); pr_devel("AFU command starting: %llx\n", command); + trace_cxl_afu_ctrl(afu, command); + cxl_p2n_write(afu, CXL_AFU_Cntl_An, AFU_Cntl | command); AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); while ((AFU_Cntl & mask) != result) { if (time_after_eq(jiffies, timeout)) { dev_warn(&afu->dev, "WARNING: AFU control timed out!\n"); - spin_unlock(&afu->afu_cntl_lock); - return -EBUSY; + rc = -EBUSY; + goto out; } pr_devel_ratelimited("AFU control... (0x%.16llx)\n", AFU_Cntl | command); @@ -44,9 +48,11 @@ static int afu_control(struct cxl_afu *afu, u64 command, }; pr_devel("AFU command complete: %llx\n", command); afu->enabled = enabled; +out: + trace_cxl_afu_ctrl_done(afu, command, rc); spin_unlock(&afu->afu_cntl_lock); - return 0; + return rc; } static int afu_enable(struct cxl_afu *afu) @@ -91,6 +97,9 @@ int cxl_psl_purge(struct cxl_afu *afu) u64 dsisr, dar; u64 start, end; unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); + int rc = 0; + + trace_cxl_psl_ctrl(afu, CXL_PSL_SCNTL_An_Pc); pr_devel("PSL purge request\n"); @@ -107,7 +116,8 @@ int cxl_psl_purge(struct cxl_afu *afu) == CXL_PSL_SCNTL_An_Ps_Pending) { if (time_after_eq(jiffies, timeout)) { dev_warn(&afu->dev, "WARNING: PSL Purge timed out!\n"); - return -EBUSY; + rc = -EBUSY; + goto out; } dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An); pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%.16llx PSL_DSISR: 0x%.16llx\n", PSL_CNTL, dsisr); @@ -128,7 +138,9 @@ int cxl_psl_purge(struct cxl_afu *afu) cxl_p1n_write(afu, CXL_PSL_SCNTL_An, PSL_CNTL & ~CXL_PSL_SCNTL_An_Pc); - return 0; +out: + trace_cxl_psl_ctrl_done(afu, CXL_PSL_SCNTL_An_Pc, rc); + return rc; } static int spa_max_procs(int spa_size) @@ -185,6 +197,7 @@ static int alloc_spa(struct cxl_afu *afu) static void release_spa(struct cxl_afu *afu) { + cxl_p1n_write(afu, CXL_PSL_SPAP_An, 0); free_pages((unsigned long) afu->spa, afu->spa_order); } @@ -278,6 +291,9 @@ static int do_process_element_cmd(struct cxl_context *ctx, { u64 state; unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); + int rc = 0; + + trace_cxl_llcmd(ctx, cmd); WARN_ON(!ctx->afu->enabled); @@ -289,12 +305,14 @@ static int do_process_element_cmd(struct cxl_context *ctx, while (1) { if (time_after_eq(jiffies, timeout)) { dev_warn(&ctx->afu->dev, "WARNING: Process Element Command timed out!\n"); - return -EBUSY; + rc = -EBUSY; + goto out; } state = be64_to_cpup(ctx->afu->sw_command_status); if (state == ~0ULL) { pr_err("cxl: Error adding process element to AFU\n"); - return -1; + rc = -1; + goto out; } if ((state & (CXL_SPA_SW_CMD_MASK | CXL_SPA_SW_STATE_MASK | CXL_SPA_SW_LINK_MASK)) == (cmd | (cmd >> 16) | ctx->pe)) @@ -309,7 +327,9 @@ static int do_process_element_cmd(struct cxl_context *ctx, schedule(); } - return 0; +out: + trace_cxl_llcmd_done(ctx, cmd, rc); + return rc; } static int add_process_element(struct cxl_context *ctx) @@ -629,6 +649,8 @@ static inline int detach_process_native_afu_directed(struct cxl_context *ctx) int cxl_detach_process(struct cxl_context *ctx) { + trace_cxl_detach(ctx); + if (ctx->afu->current_mode == CXL_MODE_DEDICATED) return detach_process_native_dedicated(ctx); @@ -667,6 +689,7 @@ static void recover_psl_err(struct cxl_afu *afu, u64 errstat) int cxl_ack_irq(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask) { + trace_cxl_psl_irq_ack(ctx, tfc); if (tfc) cxl_p2n_write(ctx->afu, CXL_PSL_TFC_An, tfc); if (psl_reset_mask) diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 0f2cc9f8b4db..1ef01647265f 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -21,6 +21,7 @@ #include #include /* for struct pci_controller */ #include +#include #include "cxl.h" @@ -113,6 +114,24 @@ #define AFUD_EB_LEN(val) EXTRACT_PPC_BITS(val, 8, 63) #define AFUD_READ_EB_OFF(afu) AFUD_READ(afu, 0x48) +u16 cxl_afu_cr_read16(struct cxl_afu *afu, int cr, u64 off) +{ + u64 aligned_off = off & ~0x3L; + u32 val; + + val = cxl_afu_cr_read32(afu, cr, aligned_off); + return (val >> ((off & 0x2) * 8)) & 0xffff; +} + +u8 cxl_afu_cr_read8(struct cxl_afu *afu, int cr, u64 off) +{ + u64 aligned_off = off & ~0x3L; + u32 val; + + val = cxl_afu_cr_read32(afu, cr, aligned_off); + return (val >> ((off & 0x3) * 8)) & 0xff; +} + static DEFINE_PCI_DEVICE_TABLE(cxl_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0477), }, { PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x044b), }, @@ -316,7 +335,7 @@ static int init_implementation_adapter_regs(struct cxl *adapter, struct pci_dev u64 psl_dsnctl; u64 chipid; - if (!(np = pnv_pci_to_phb_node(dev))) + if (!(np = pnv_pci_get_phb_node(dev))) return -ENODEV; while (np && !(prop = of_get_property(np, "ibm,chip-id", NULL))) @@ -348,7 +367,7 @@ static int init_implementation_afu_regs(struct cxl_afu *afu) cxl_p1n_write(afu, CXL_PSL_COALLOC_A, 0xFF000000FEFEFEFEULL); /* for debugging with trace arrays */ cxl_p1n_write(afu, CXL_PSL_SLICE_TRACE, 0x0000FFFF00000000ULL); - cxl_p1n_write(afu, CXL_PSL_RXCTL_A, 0xF000000000000000ULL); + cxl_p1n_write(afu, CXL_PSL_RXCTL_A, CXL_PSL_RXCTL_AFUHP_4S); return 0; } @@ -361,6 +380,41 @@ int cxl_setup_irq(struct cxl *adapter, unsigned int hwirq, return pnv_cxl_ioda_msi_setup(dev, hwirq, virq); } +int cxl_update_image_control(struct cxl *adapter) +{ + struct pci_dev *dev = to_pci_dev(adapter->dev.parent); + int rc; + int vsec; + u8 image_state; + + if (!(vsec = find_cxl_vsec(dev))) { + dev_err(&dev->dev, "ABORTING: CXL VSEC not found!\n"); + return -ENODEV; + } + + if ((rc = CXL_READ_VSEC_IMAGE_STATE(dev, vsec, &image_state))) { + dev_err(&dev->dev, "failed to read image state: %i\n", rc); + return rc; + } + + if (adapter->perst_loads_image) + image_state |= CXL_VSEC_PERST_LOADS_IMAGE; + else + image_state &= ~CXL_VSEC_PERST_LOADS_IMAGE; + + if (adapter->perst_select_user) + image_state |= CXL_VSEC_PERST_SELECT_USER; + else + image_state &= ~CXL_VSEC_PERST_SELECT_USER; + + if ((rc = CXL_WRITE_VSEC_IMAGE_STATE(dev, vsec, image_state))) { + dev_err(&dev->dev, "failed to update image control: %i\n", rc); + return rc; + } + + return 0; +} + int cxl_alloc_one_irq(struct cxl *adapter) { struct pci_dev *dev = to_pci_dev(adapter->dev.parent); @@ -520,6 +574,7 @@ static int cxl_read_afu_descriptor(struct cxl_afu *afu) val = AFUD_READ_INFO(afu); afu->pp_irqs = AFUD_NUM_INTS_PER_PROC(val); afu->max_procs_virtualised = AFUD_NUM_PROCS(val); + afu->crs_num = AFUD_NUM_CRS(val); if (AFUD_AFU_DIRECTED(val)) afu->modes_supported |= CXL_MODE_DIRECTED; @@ -534,11 +589,17 @@ static int cxl_read_afu_descriptor(struct cxl_afu *afu) if ((afu->pp_psa = AFUD_PPPSA_PP(val))) afu->pp_offset = AFUD_READ_PPPSA_OFF(afu); + val = AFUD_READ_CR(afu); + afu->crs_len = AFUD_CR_LEN(val) * 256; + afu->crs_offset = AFUD_READ_CR_OFF(afu); + return 0; } static int cxl_afu_descriptor_looks_ok(struct cxl_afu *afu) { + int i; + if (afu->psa && afu->adapter->ps_size < (afu->pp_offset + afu->pp_size*afu->max_procs_virtualised)) { dev_err(&afu->dev, "per-process PSA can't fit inside the PSA!\n"); @@ -548,6 +609,13 @@ static int cxl_afu_descriptor_looks_ok(struct cxl_afu *afu) if (afu->pp_psa && (afu->pp_size < PAGE_SIZE)) dev_warn(&afu->dev, "AFU uses < PAGE_SIZE per-process PSA!"); + for (i = 0; i < afu->crs_num; i++) { + if ((cxl_afu_cr_read32(afu, i, 0) == 0)) { + dev_err(&afu->dev, "ABORTING: AFU configuration record %i is invalid\n", i); + return -EINVAL; + } + } + return 0; } @@ -706,6 +774,42 @@ static void cxl_remove_afu(struct cxl_afu *afu) device_unregister(&afu->dev); } +int cxl_reset(struct cxl *adapter) +{ + struct pci_dev *dev = to_pci_dev(adapter->dev.parent); + int rc; + int i; + u32 val; + + dev_info(&dev->dev, "CXL reset\n"); + + for (i = 0; i < adapter->slices; i++) + cxl_remove_afu(adapter->afu[i]); + + /* pcie_warm_reset requests a fundamental pci reset which includes a + * PERST assert/deassert. PERST triggers a loading of the image + * if "user" or "factory" is selected in sysfs */ + if ((rc = pci_set_pcie_reset_state(dev, pcie_warm_reset))) { + dev_err(&dev->dev, "cxl: pcie_warm_reset failed\n"); + return rc; + } + + /* the PERST done above fences the PHB. So, reset depends on EEH + * to unbind the driver, tell Sapphire to reinit the PHB, and rebind + * the driver. Do an mmio read explictly to ensure EEH notices the + * fenced PHB. Retry for a few seconds before giving up. */ + i = 0; + while (((val = mmio_read32be(adapter->p1_mmio)) != 0xffffffff) && + (i < 5)) { + msleep(500); + i++; + } + + if (val != 0xffffffff) + dev_err(&dev->dev, "cxl: PERST failed to trigger EEH\n"); + + return rc; +} static int cxl_map_adapter_regs(struct cxl *adapter, struct pci_dev *dev) { @@ -770,8 +874,8 @@ static int cxl_read_vsec(struct cxl *adapter, struct pci_dev *dev) CXL_READ_VSEC_BASE_IMAGE(dev, vsec, &adapter->base_image); CXL_READ_VSEC_IMAGE_STATE(dev, vsec, &image_state); adapter->user_image_loaded = !!(image_state & CXL_VSEC_USER_IMAGE_LOADED); - adapter->perst_loads_image = !!(image_state & CXL_VSEC_PERST_LOADS_IMAGE); - adapter->perst_select_user = !!(image_state & CXL_VSEC_PERST_SELECT_USER); + adapter->perst_loads_image = true; + adapter->perst_select_user = !!(image_state & CXL_VSEC_USER_IMAGE_LOADED); CXL_READ_VSEC_NAFUS(dev, vsec, &adapter->slices); CXL_READ_VSEC_AFU_DESC_OFF(dev, vsec, &afu_desc_off); @@ -879,6 +983,9 @@ static struct cxl *cxl_init_adapter(struct pci_dev *dev) if ((rc = cxl_vsec_looks_ok(adapter, dev))) goto err2; + if ((rc = cxl_update_image_control(adapter))) + goto err2; + if ((rc = cxl_map_adapter_regs(adapter, dev))) goto err2; @@ -888,9 +995,15 @@ static struct cxl *cxl_init_adapter(struct pci_dev *dev) if ((rc = init_implementation_adapter_regs(adapter, dev))) goto err3; - if ((rc = pnv_phb_to_cxl(dev))) + if ((rc = pnv_phb_to_cxl_mode(dev, OPAL_PHB_CAPI_MODE_CAPI))) goto err3; + /* If recovery happened, the last step is to turn on snooping. + * In the non-recovery case this has no effect */ + if ((rc = pnv_phb_to_cxl_mode(dev, OPAL_PHB_CAPI_MODE_SNOOP_ON))) { + goto err3; + } + if ((rc = cxl_register_psl_err_irq(adapter))) goto err3; diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c index 461bdbd5d483..d0c38c7bc0c4 100644 --- a/drivers/misc/cxl/sysfs.c +++ b/drivers/misc/cxl/sysfs.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "cxl.h" @@ -56,11 +57,68 @@ static ssize_t image_loaded_show(struct device *device, return scnprintf(buf, PAGE_SIZE, "factory\n"); } +static ssize_t reset_adapter_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cxl *adapter = to_cxl_adapter(device); + int rc; + int val; + + rc = sscanf(buf, "%i", &val); + if ((rc != 1) || (val != 1)) + return -EINVAL; + + if ((rc = cxl_reset(adapter))) + return rc; + return count; +} + +static ssize_t load_image_on_perst_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct cxl *adapter = to_cxl_adapter(device); + + if (!adapter->perst_loads_image) + return scnprintf(buf, PAGE_SIZE, "none\n"); + + if (adapter->perst_select_user) + return scnprintf(buf, PAGE_SIZE, "user\n"); + return scnprintf(buf, PAGE_SIZE, "factory\n"); +} + +static ssize_t load_image_on_perst_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cxl *adapter = to_cxl_adapter(device); + int rc; + + if (!strncmp(buf, "none", 4)) + adapter->perst_loads_image = false; + else if (!strncmp(buf, "user", 4)) { + adapter->perst_select_user = true; + adapter->perst_loads_image = true; + } else if (!strncmp(buf, "factory", 7)) { + adapter->perst_select_user = false; + adapter->perst_loads_image = true; + } else + return -EINVAL; + + if ((rc = cxl_update_image_control(adapter))) + return rc; + + return count; +} + static struct device_attribute adapter_attrs[] = { __ATTR_RO(caia_version), __ATTR_RO(psl_revision), __ATTR_RO(base_image), __ATTR_RO(image_loaded), + __ATTR_RW(load_image_on_perst), + __ATTR(reset, S_IWUSR, NULL, reset_adapter_store), }; @@ -310,8 +368,6 @@ static struct device_attribute afu_attrs[] = { __ATTR(reset, S_IWUSR, NULL, reset_store_afu), }; - - int cxl_sysfs_adapter_add(struct cxl *adapter) { int i, rc; @@ -334,31 +390,191 @@ void cxl_sysfs_adapter_remove(struct cxl *adapter) device_remove_file(&adapter->dev, &adapter_attrs[i]); } +struct afu_config_record { + struct kobject kobj; + struct bin_attribute config_attr; + struct list_head list; + int cr; + u16 device; + u16 vendor; + u32 class; +}; + +#define to_cr(obj) container_of(obj, struct afu_config_record, kobj) + +static ssize_t vendor_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct afu_config_record *cr = to_cr(kobj); + + return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->vendor); +} + +static ssize_t device_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct afu_config_record *cr = to_cr(kobj); + + return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->device); +} + +static ssize_t class_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct afu_config_record *cr = to_cr(kobj); + + return scnprintf(buf, PAGE_SIZE, "0x%.6x\n", cr->class); +} + +static ssize_t afu_read_config(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) +{ + struct afu_config_record *cr = to_cr(kobj); + struct cxl_afu *afu = to_cxl_afu(container_of(kobj->parent, struct device, kobj)); + + u64 i, j, val, size = afu->crs_len; + + if (off > size) + return 0; + if (off + count > size) + count = size - off; + + for (i = 0; i < count;) { + val = cxl_afu_cr_read64(afu, cr->cr, off & ~0x7); + for (j = off & 0x7; j < 8 && i < count; i++, j++, off++) + buf[i] = (val >> (j * 8)) & 0xff; + } + + return count; +} + +static struct kobj_attribute vendor_attribute = + __ATTR_RO(vendor); +static struct kobj_attribute device_attribute = + __ATTR_RO(device); +static struct kobj_attribute class_attribute = + __ATTR_RO(class); + +static struct attribute *afu_cr_attrs[] = { + &vendor_attribute.attr, + &device_attribute.attr, + &class_attribute.attr, + NULL, +}; + +static void release_afu_config_record(struct kobject *kobj) +{ + struct afu_config_record *cr = to_cr(kobj); + + kfree(cr); +} + +static struct kobj_type afu_config_record_type = { + .sysfs_ops = &kobj_sysfs_ops, + .release = release_afu_config_record, + .default_attrs = afu_cr_attrs, +}; + +static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx) +{ + struct afu_config_record *cr; + int rc; + + cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL); + if (!cr) + return ERR_PTR(-ENOMEM); + + cr->cr = cr_idx; + cr->device = cxl_afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID); + cr->vendor = cxl_afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID); + cr->class = cxl_afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION) >> 8; + + /* + * Export raw AFU PCIe like config record. For now this is read only by + * root - we can expand that later to be readable by non-root and maybe + * even writable provided we have a good use-case. Once we suport + * exposing AFUs through a virtual PHB they will get that for free from + * Linux' PCI infrastructure, but until then it's not clear that we + * need it for anything since the main use case is just identifying + * AFUs, which can be done via the vendor, device and class attributes. + */ + sysfs_bin_attr_init(&cr->config_attr); + cr->config_attr.attr.name = "config"; + cr->config_attr.attr.mode = S_IRUSR; + cr->config_attr.size = afu->crs_len; + cr->config_attr.read = afu_read_config; + + rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type, + &afu->dev.kobj, "cr%i", cr->cr); + if (rc) + goto err; + + rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr); + if (rc) + goto err1; + + rc = kobject_uevent(&cr->kobj, KOBJ_ADD); + if (rc) + goto err2; + + return cr; +err2: + sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); +err1: + kobject_put(&cr->kobj); + return ERR_PTR(rc); +err: + kfree(cr); + return ERR_PTR(rc); +} + +void cxl_sysfs_afu_remove(struct cxl_afu *afu) +{ + struct afu_config_record *cr, *tmp; + int i; + + for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) + device_remove_file(&afu->dev, &afu_attrs[i]); + + list_for_each_entry_safe(cr, tmp, &afu->crs, list) { + sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); + kobject_put(&cr->kobj); + } +} + int cxl_sysfs_afu_add(struct cxl_afu *afu) { + struct afu_config_record *cr; int i, rc; + INIT_LIST_HEAD(&afu->crs); + for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { if ((rc = device_create_file(&afu->dev, &afu_attrs[i]))) goto err; } + for (i = 0; i < afu->crs_num; i++) { + cr = cxl_sysfs_afu_new_cr(afu, i); + if (IS_ERR(cr)) { + rc = PTR_ERR(cr); + goto err1; + } + list_add(&cr->list, &afu->crs); + } + return 0; +err1: + cxl_sysfs_afu_remove(afu); + return rc; err: for (i--; i >= 0; i--) device_remove_file(&afu->dev, &afu_attrs[i]); return rc; } -void cxl_sysfs_afu_remove(struct cxl_afu *afu) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) - device_remove_file(&afu->dev, &afu_attrs[i]); -} - int cxl_sysfs_afu_m_add(struct cxl_afu *afu) { int i, rc; diff --git a/drivers/misc/cxl/trace.c b/drivers/misc/cxl/trace.c new file mode 100644 index 000000000000..c2b06d319e6e --- /dev/null +++ b/drivers/misc/cxl/trace.c @@ -0,0 +1,13 @@ +/* + * Copyright 2015 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 __CHECKER__ +#define CREATE_TRACE_POINTS +#include "trace.h" +#endif diff --git a/drivers/misc/cxl/trace.h b/drivers/misc/cxl/trace.h new file mode 100644 index 000000000000..ae434d87887e --- /dev/null +++ b/drivers/misc/cxl/trace.h @@ -0,0 +1,459 @@ +/* + * Copyright 2015 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. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM cxl + +#if !defined(_CXL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _CXL_TRACE_H + +#include + +#include "cxl.h" + +#define DSISR_FLAGS \ + { CXL_PSL_DSISR_An_DS, "DS" }, \ + { CXL_PSL_DSISR_An_DM, "DM" }, \ + { CXL_PSL_DSISR_An_ST, "ST" }, \ + { CXL_PSL_DSISR_An_UR, "UR" }, \ + { CXL_PSL_DSISR_An_PE, "PE" }, \ + { CXL_PSL_DSISR_An_AE, "AE" }, \ + { CXL_PSL_DSISR_An_OC, "OC" }, \ + { CXL_PSL_DSISR_An_M, "M" }, \ + { CXL_PSL_DSISR_An_P, "P" }, \ + { CXL_PSL_DSISR_An_A, "A" }, \ + { CXL_PSL_DSISR_An_S, "S" }, \ + { CXL_PSL_DSISR_An_K, "K" } + +#define TFC_FLAGS \ + { CXL_PSL_TFC_An_A, "A" }, \ + { CXL_PSL_TFC_An_C, "C" }, \ + { CXL_PSL_TFC_An_AE, "AE" }, \ + { CXL_PSL_TFC_An_R, "R" } + +#define LLCMD_NAMES \ + { CXL_SPA_SW_CMD_TERMINATE, "TERMINATE" }, \ + { CXL_SPA_SW_CMD_REMOVE, "REMOVE" }, \ + { CXL_SPA_SW_CMD_SUSPEND, "SUSPEND" }, \ + { CXL_SPA_SW_CMD_RESUME, "RESUME" }, \ + { CXL_SPA_SW_CMD_ADD, "ADD" }, \ + { CXL_SPA_SW_CMD_UPDATE, "UPDATE" } + +#define AFU_COMMANDS \ + { 0, "DISABLE" }, \ + { CXL_AFU_Cntl_An_E, "ENABLE" }, \ + { CXL_AFU_Cntl_An_RA, "RESET" } + +#define PSL_COMMANDS \ + { CXL_PSL_SCNTL_An_Pc, "PURGE" }, \ + { CXL_PSL_SCNTL_An_Sc, "SUSPEND" } + + +DECLARE_EVENT_CLASS(cxl_pe_class, + TP_PROTO(struct cxl_context *ctx), + + TP_ARGS(ctx), + + TP_STRUCT__entry( + __field(u8, card) + __field(u8, afu) + __field(u16, pe) + ), + + TP_fast_assign( + __entry->card = ctx->afu->adapter->adapter_num; + __entry->afu = ctx->afu->slice; + __entry->pe = ctx->pe; + ), + + TP_printk("afu%i.%i pe=%i", + __entry->card, + __entry->afu, + __entry->pe + ) +); + + +TRACE_EVENT(cxl_attach, + TP_PROTO(struct cxl_context *ctx, u64 wed, s16 num_interrupts, u64 amr), + + TP_ARGS(ctx, wed, num_interrupts, amr), + + TP_STRUCT__entry( + __field(u8, card) + __field(u8, afu) + __field(u16, pe) + __field(pid_t, pid) + __field(u64, wed) + __field(u64, amr) + __field(s16, num_interrupts) + ), + + TP_fast_assign( + __entry->card = ctx->afu->adapter->adapter_num; + __entry->afu = ctx->afu->slice; + __entry->pe = ctx->pe; + __entry->pid = pid_nr(ctx->pid); + __entry->wed = wed; + __entry->amr = amr; + __entry->num_interrupts = num_interrupts; + ), + + TP_printk("afu%i.%i pid=%i pe=%i wed=0x%.16llx irqs=%i amr=0x%llx", + __entry->card, + __entry->afu, + __entry->pid, + __entry->pe, + __entry->wed, + __entry->num_interrupts, + __entry->amr + ) +); + +DEFINE_EVENT(cxl_pe_class, cxl_detach, + TP_PROTO(struct cxl_context *ctx), + TP_ARGS(ctx) +); + +TRACE_EVENT(cxl_afu_irq, + TP_PROTO(struct cxl_context *ctx, int afu_irq, int virq, irq_hw_number_t hwirq), + + TP_ARGS(ctx, afu_irq, virq, hwirq), + + TP_STRUCT__entry( + __field(u8, card) + __field(u8, afu) + __field(u16, pe) + __field(u16, afu_irq) + __field(int, virq) + __field(irq_hw_number_t, hwirq) + ), + + TP_fast_assign( + __entry->card = ctx->afu->adapter->adapter_num; + __entry->afu = ctx->afu->slice; + __entry->pe = ctx->pe; + __entry->afu_irq = afu_irq; + __entry->virq = virq; + __entry->hwirq = hwirq; + ), + + TP_printk("afu%i.%i pe=%i afu_irq=%i virq=%i hwirq=0x%lx", + __entry->card, + __entry->afu, + __entry->pe, + __entry->afu_irq, + __entry->virq, + __entry->hwirq + ) +); + +TRACE_EVENT(cxl_psl_irq, + TP_PROTO(struct cxl_context *ctx, int irq, u64 dsisr, u64 dar), + + TP_ARGS(ctx, irq, dsisr, dar), + + TP_STRUCT__entry( + __field(u8, card) + __field(u8, afu) + __field(u16, pe) + __field(int, irq) + __field(u64, dsisr) + __field(u64, dar) + ), + + TP_fast_assign( + __entry->card = ctx->afu->adapter->adapter_num; + __entry->afu = ctx->afu->slice; + __entry->pe = ctx->pe; + __entry->irq = irq; + __entry->dsisr = dsisr; + __entry->dar = dar; + ), + + TP_printk("afu%i.%i pe=%i irq=%i dsisr=%s dar=0x%.16llx", + __entry->card, + __entry->afu, + __entry->pe, + __entry->irq, + __print_flags(__entry->dsisr, "|", DSISR_FLAGS), + __entry->dar + ) +); + +TRACE_EVENT(cxl_psl_irq_ack, + TP_PROTO(struct cxl_context *ctx, u64 tfc), + + TP_ARGS(ctx, tfc), + + TP_STRUCT__entry( + __field(u8, card) + __field(u8, afu) + __field(u16, pe) + __field(u64, tfc) + ), + + TP_fast_assign( + __entry->card = ctx->afu->adapter->adapter_num; + __entry->afu = ctx->afu->slice; + __entry->pe = ctx->pe; + __entry->tfc = tfc; + ), + + TP_printk("afu%i.%i pe=%i tfc=%s", + __entry->card, + __entry->afu, + __entry->pe, + __print_flags(__entry->tfc, "|", TFC_FLAGS) + ) +); + +TRACE_EVENT(cxl_ste_miss, + TP_PROTO(struct cxl_context *ctx, u64 dar), + + TP_ARGS(ctx, dar), + + TP_STRUCT__entry( + __field(u8, card) + __field(u8, afu) + __field(u16, pe) + __field(u64, dar) + ), + + TP_fast_assign( + __entry->card = ctx->afu->adapter->adapter_num; + __entry->afu = ctx->afu->slice; + __entry->pe = ctx->pe; + __entry->dar = dar; + ), + + TP_printk("afu%i.%i pe=%i dar=0x%.16llx", + __entry->card, + __entry->afu, + __entry->pe, + __entry->dar + ) +); + +TRACE_EVENT(cxl_ste_write, + TP_PROTO(struct cxl_context *ctx, unsigned int idx, u64 e, u64 v), + + TP_ARGS(ctx, idx, e, v), + + TP_STRUCT__entry( + __field(u8, card) + __field(u8, afu) + __field(u16, pe) + __field(unsigned int, idx) + __field(u64, e) + __field(u64, v) + ), + + TP_fast_assign( + __entry->card = ctx->afu->adapter->adapter_num; + __entry->afu = ctx->afu->slice; + __entry->pe = ctx->pe; + __entry->idx = idx; + __entry->e = e; + __entry->v = v; + ), + + TP_printk("afu%i.%i pe=%i SSTE[%i] E=0x%.16llx V=0x%.16llx", + __entry->card, + __entry->afu, + __entry->pe, + __entry->idx, + __entry->e, + __entry->v + ) +); + +TRACE_EVENT(cxl_pte_miss, + TP_PROTO(struct cxl_context *ctx, u64 dsisr, u64 dar), + + TP_ARGS(ctx, dsisr, dar), + + TP_STRUCT__entry( + __field(u8, card) + __field(u8, afu) + __field(u16, pe) + __field(u64, dsisr) + __field(u64, dar) + ), + + TP_fast_assign( + __entry->card = ctx->afu->adapter->adapter_num; + __entry->afu = ctx->afu->slice; + __entry->pe = ctx->pe; + __entry->dsisr = dsisr; + __entry->dar = dar; + ), + + TP_printk("afu%i.%i pe=%i dsisr=%s dar=0x%.16llx", + __entry->card, + __entry->afu, + __entry->pe, + __print_flags(__entry->dsisr, "|", DSISR_FLAGS), + __entry->dar + ) +); + +TRACE_EVENT(cxl_llcmd, + TP_PROTO(struct cxl_context *ctx, u64 cmd), + + TP_ARGS(ctx, cmd), + + TP_STRUCT__entry( + __field(u8, card) + __field(u8, afu) + __field(u16, pe) + __field(u64, cmd) + ), + + TP_fast_assign( + __entry->card = ctx->afu->adapter->adapter_num; + __entry->afu = ctx->afu->slice; + __entry->pe = ctx->pe; + __entry->cmd = cmd; + ), + + TP_printk("afu%i.%i pe=%i cmd=%s", + __entry->card, + __entry->afu, + __entry->pe, + __print_symbolic_u64(__entry->cmd, LLCMD_NAMES) + ) +); + +TRACE_EVENT(cxl_llcmd_done, + TP_PROTO(struct cxl_context *ctx, u64 cmd, int rc), + + TP_ARGS(ctx, cmd, rc), + + TP_STRUCT__entry( + __field(u8, card) + __field(u8, afu) + __field(u16, pe) + __field(u64, cmd) + __field(int, rc) + ), + + TP_fast_assign( + __entry->card = ctx->afu->adapter->adapter_num; + __entry->afu = ctx->afu->slice; + __entry->pe = ctx->pe; + __entry->rc = rc; + __entry->cmd = cmd; + ), + + TP_printk("afu%i.%i pe=%i cmd=%s rc=%i", + __entry->card, + __entry->afu, + __entry->pe, + __print_symbolic_u64(__entry->cmd, LLCMD_NAMES), + __entry->rc + ) +); + +DECLARE_EVENT_CLASS(cxl_afu_psl_ctrl, + TP_PROTO(struct cxl_afu *afu, u64 cmd), + + TP_ARGS(afu, cmd), + + TP_STRUCT__entry( + __field(u8, card) + __field(u8, afu) + __field(u64, cmd) + ), + + TP_fast_assign( + __entry->card = afu->adapter->adapter_num; + __entry->afu = afu->slice; + __entry->cmd = cmd; + ), + + TP_printk("afu%i.%i cmd=%s", + __entry->card, + __entry->afu, + __print_symbolic_u64(__entry->cmd, AFU_COMMANDS) + ) +); + +DECLARE_EVENT_CLASS(cxl_afu_psl_ctrl_done, + TP_PROTO(struct cxl_afu *afu, u64 cmd, int rc), + + TP_ARGS(afu, cmd, rc), + + TP_STRUCT__entry( + __field(u8, card) + __field(u8, afu) + __field(u64, cmd) + __field(int, rc) + ), + + TP_fast_assign( + __entry->card = afu->adapter->adapter_num; + __entry->afu = afu->slice; + __entry->rc = rc; + __entry->cmd = cmd; + ), + + TP_printk("afu%i.%i cmd=%s rc=%i", + __entry->card, + __entry->afu, + __print_symbolic_u64(__entry->cmd, AFU_COMMANDS), + __entry->rc + ) +); + +DEFINE_EVENT(cxl_afu_psl_ctrl, cxl_afu_ctrl, + TP_PROTO(struct cxl_afu *afu, u64 cmd), + TP_ARGS(afu, cmd) +); + +DEFINE_EVENT(cxl_afu_psl_ctrl_done, cxl_afu_ctrl_done, + TP_PROTO(struct cxl_afu *afu, u64 cmd, int rc), + TP_ARGS(afu, cmd, rc) +); + +DEFINE_EVENT_PRINT(cxl_afu_psl_ctrl, cxl_psl_ctrl, + TP_PROTO(struct cxl_afu *afu, u64 cmd), + TP_ARGS(afu, cmd), + + TP_printk("psl%i.%i cmd=%s", + __entry->card, + __entry->afu, + __print_symbolic_u64(__entry->cmd, PSL_COMMANDS) + ) +); + +DEFINE_EVENT_PRINT(cxl_afu_psl_ctrl_done, cxl_psl_ctrl_done, + TP_PROTO(struct cxl_afu *afu, u64 cmd, int rc), + TP_ARGS(afu, cmd, rc), + + TP_printk("psl%i.%i cmd=%s rc=%i", + __entry->card, + __entry->afu, + __print_symbolic_u64(__entry->cmd, PSL_COMMANDS), + __entry->rc + ) +); + +DEFINE_EVENT(cxl_pe_class, cxl_slbia, + TP_PROTO(struct cxl_context *ctx), + TP_ARGS(ctx) +); + +#endif /* _CXL_TRACE_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE trace +#include diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 180a5442fd4b..38552a31304a 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -145,8 +145,11 @@ enclosure_register(struct device *dev, const char *name, int components, if (err) goto err; - for (i = 0; i < components; i++) + for (i = 0; i < components; i++) { edev->component[i].number = -1; + edev->component[i].slot = -1; + edev->component[i].power_status = 1; + } mutex_lock(&container_list_lock); list_add_tail(&edev->node, &container_list); @@ -273,27 +276,26 @@ enclosure_component_find_by_name(struct enclosure_device *edev, static const struct attribute_group *enclosure_component_groups[]; /** - * enclosure_component_register - add a particular component to an enclosure + * enclosure_component_alloc - prepare a new enclosure component * @edev: the enclosure to add the component * @num: the device number * @type: the type of component being added * @name: an optional name to appear in sysfs (leave NULL if none) * - * Registers the component. The name is optional for enclosures that - * give their components a unique name. If not, leave the field NULL - * and a name will be assigned. + * The name is optional for enclosures that give their components a unique + * name. If not, leave the field NULL and a name will be assigned. * * Returns a pointer to the enclosure component or an error. */ struct enclosure_component * -enclosure_component_register(struct enclosure_device *edev, - unsigned int number, - enum enclosure_component_type type, - const char *name) +enclosure_component_alloc(struct enclosure_device *edev, + unsigned int number, + enum enclosure_component_type type, + const char *name) { struct enclosure_component *ecomp; struct device *cdev; - int err, i; + int i; char newname[COMPONENT_NAME_SIZE]; if (number >= edev->components) @@ -327,14 +329,30 @@ enclosure_component_register(struct enclosure_device *edev, cdev->release = enclosure_component_release; cdev->groups = enclosure_component_groups; + return ecomp; +} +EXPORT_SYMBOL_GPL(enclosure_component_alloc); + +/** + * enclosure_component_register - publishes an initialized enclosure component + * @ecomp: component to add + * + * Returns 0 on successful registration, releases the component otherwise + */ +int enclosure_component_register(struct enclosure_component *ecomp) +{ + struct device *cdev; + int err; + + cdev = &ecomp->cdev; err = device_register(cdev); if (err) { ecomp->number = -1; put_device(cdev); - return ERR_PTR(err); + return err; } - return ecomp; + return 0; } EXPORT_SYMBOL_GPL(enclosure_component_register); @@ -417,8 +435,21 @@ static ssize_t components_show(struct device *cdev, } static DEVICE_ATTR_RO(components); +static ssize_t id_show(struct device *cdev, + struct device_attribute *attr, + char *buf) +{ + struct enclosure_device *edev = to_enclosure_device(cdev); + + if (edev->cb->show_id) + return edev->cb->show_id(edev, buf); + return -EINVAL; +} +static DEVICE_ATTR_RO(id); + static struct attribute *enclosure_class_attrs[] = { &dev_attr_components.attr, + &dev_attr_id.attr, NULL, }; ATTRIBUTE_GROUPS(enclosure_class); @@ -553,6 +584,40 @@ static ssize_t set_component_locate(struct device *cdev, return count; } +static ssize_t get_component_power_status(struct device *cdev, + struct device_attribute *attr, + char *buf) +{ + struct enclosure_device *edev = to_enclosure_device(cdev->parent); + struct enclosure_component *ecomp = to_enclosure_component(cdev); + + if (edev->cb->get_power_status) + edev->cb->get_power_status(edev, ecomp); + return snprintf(buf, 40, "%s\n", ecomp->power_status ? "on" : "off"); +} + +static ssize_t set_component_power_status(struct device *cdev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct enclosure_device *edev = to_enclosure_device(cdev->parent); + struct enclosure_component *ecomp = to_enclosure_component(cdev); + int val; + + if (strncmp(buf, "on", 2) == 0 && + (buf[2] == '\n' || buf[2] == '\0')) + val = 1; + else if (strncmp(buf, "off", 3) == 0 && + (buf[3] == '\n' || buf[3] == '\0')) + val = 0; + else + return -EINVAL; + + if (edev->cb->set_power_status) + edev->cb->set_power_status(edev, ecomp, val); + return count; +} + static ssize_t get_component_type(struct device *cdev, struct device_attribute *attr, char *buf) { @@ -561,6 +626,20 @@ static ssize_t get_component_type(struct device *cdev, return snprintf(buf, 40, "%s\n", enclosure_type[ecomp->type]); } +static ssize_t get_component_slot(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct enclosure_component *ecomp = to_enclosure_component(cdev); + int slot; + + /* if the enclosure does not override then use 'number' as a stand-in */ + if (ecomp->slot >= 0) + slot = ecomp->slot; + else + slot = ecomp->number; + + return snprintf(buf, 40, "%d\n", slot); +} static DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault, set_component_fault); @@ -570,14 +649,19 @@ static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, get_component_active, set_component_active); static DEVICE_ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate, set_component_locate); +static DEVICE_ATTR(power_status, S_IRUGO | S_IWUSR, get_component_power_status, + set_component_power_status); static DEVICE_ATTR(type, S_IRUGO, get_component_type, NULL); +static DEVICE_ATTR(slot, S_IRUGO, get_component_slot, NULL); static struct attribute *enclosure_component_attrs[] = { &dev_attr_fault.attr, &dev_attr_status.attr, &dev_attr_active.attr, &dev_attr_locate.attr, + &dev_attr_power_status.attr, &dev_attr_type.attr, + &dev_attr_slot.attr, NULL }; ATTRIBUTE_GROUPS(enclosure_component); diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c index 7aaaf51e1596..35f19a683822 100644 --- a/drivers/misc/vmw_vmci/vmci_queue_pair.c +++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c @@ -370,12 +370,12 @@ static int __qp_memcpy_to_queue(struct vmci_queue *queue, to_copy = size - bytes_copied; if (is_iovec) { - struct iovec *iov = (struct iovec *)src; + struct msghdr *msg = (struct msghdr *)src; int err; /* The iovec will track bytes_copied internally. */ - err = memcpy_fromiovec((u8 *)va + page_offset, - iov, to_copy); + err = memcpy_from_msg((u8 *)va + page_offset, + msg, to_copy); if (err != 0) { if (kernel_if->host) kunmap(kernel_if->u.h.page[page_index]); @@ -580,7 +580,7 @@ static int qp_memcpy_from_queue(void *dest, */ static int qp_memcpy_to_queue_iov(struct vmci_queue *queue, u64 queue_offset, - const void *src, + const void *msg, size_t src_offset, size_t size) { @@ -588,7 +588,7 @@ static int qp_memcpy_to_queue_iov(struct vmci_queue *queue, * We ignore src_offset because src is really a struct iovec * and will * maintain offset internally. */ - return __qp_memcpy_to_queue(queue, queue_offset, src, size, true); + return __qp_memcpy_to_queue(queue, queue_offset, msg, size, true); } /* @@ -3223,13 +3223,13 @@ EXPORT_SYMBOL_GPL(vmci_qpair_peek); * of bytes enqueued or < 0 on error. */ ssize_t vmci_qpair_enquev(struct vmci_qp *qpair, - void *iov, + struct msghdr *msg, size_t iov_size, int buf_type) { ssize_t result; - if (!qpair || !iov) + if (!qpair) return VMCI_ERROR_INVALID_ARGS; qp_lock(qpair); @@ -3238,7 +3238,7 @@ ssize_t vmci_qpair_enquev(struct vmci_qp *qpair, result = qp_enqueue_locked(qpair->produce_q, qpair->consume_q, qpair->produce_q_size, - iov, iov_size, + msg, iov_size, qp_memcpy_to_queue_iov); if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY && diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 4409d79ed650..c69afb5e264e 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -2147,7 +2147,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, */ snprintf(md->disk->disk_name, sizeof(md->disk->disk_name), - "mmcblk%d%s", md->name_idx, subname ? subname : ""); + "mmcblk%u%s", md->name_idx, subname ? subname : ""); if (mmc_card_mmc(card)) blk_queue_logical_block_size(md->queue.queue, @@ -2193,7 +2193,6 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) { sector_t size; - struct mmc_blk_data *md; if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) { /* @@ -2209,9 +2208,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) size = card->csd.capacity << (card->csd.read_blkbits - 9); } - md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL, + return mmc_blk_alloc_req(card, &card->dev, size, false, NULL, MMC_BLK_DATA_AREA_MAIN); - return md; } static int mmc_blk_alloc_part(struct mmc_card *card, diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 0a7430f94d29..7dac4695163b 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -2342,20 +2342,16 @@ static int mmc_test_hw_reset(struct mmc_test_card *test) struct mmc_host *host = card->host; int err; - err = mmc_hw_reset_check(host); - if (!err) - return RESULT_OK; - - if (err == -ENOSYS) - return RESULT_FAIL; - - if (err != -EOPNOTSUPP) - return err; - - if (!mmc_can_reset(card)) + if (!mmc_card_mmc(card) || !mmc_can_reset(card)) return RESULT_UNSUP_CARD; - return RESULT_UNSUP_HOST; + err = mmc_hw_reset(host); + if (!err) + return RESULT_OK; + else if (err == -EOPNOTSUPP) + return RESULT_UNSUP_HOST; + + return RESULT_FAIL; } static const struct mmc_test_case mmc_test_cases[] = { diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 38ed210ce2f3..2c25138f28b7 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -8,5 +8,5 @@ mmc_core-y := core.o bus.o host.o \ sdio.o sdio_ops.o sdio_bus.o \ sdio_cis.o sdio_io.o sdio_irq.o \ quirks.o slot-gpio.o - +mmc_core-$(CONFIG_OF) += pwrseq.o pwrseq_simple.o pwrseq_emmc.o mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 86d271148528..c5ef10065a4a 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -321,6 +322,8 @@ int mmc_add_card(struct mmc_card *card) #endif mmc_init_context_info(card->host); + card->dev.of_node = mmc_of_find_child_device(card->host, 0); + ret = device_add(&card->dev); if (ret) return ret; @@ -349,6 +352,7 @@ void mmc_remove_card(struct mmc_card *card) mmc_hostname(card->host), card->rca); } device_del(&card->dev); + of_node_put(card->dev.of_node); } put_device(&card->dev); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 9584bffa8b22..23f10f72e5f3 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -40,6 +40,7 @@ #include "bus.h" #include "host.h" #include "sdio_bus.h" +#include "pwrseq.h" #include "mmc_ops.h" #include "sd_ops.h" @@ -185,13 +186,14 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) EXPORT_SYMBOL(mmc_request_done); -static void -mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) +static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { #ifdef CONFIG_MMC_DEBUG unsigned int i, sz; struct scatterlist *sg; #endif + if (mmc_card_removed(host->card)) + return -ENOMEDIUM; if (mrq->sbc) { pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n", @@ -251,6 +253,8 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) mmc_host_clk_hold(host); led_trigger_event(host->led, LED_FULL); host->ops->request(host, mrq); + + return 0; } /** @@ -271,7 +275,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) BUG_ON(!card); - if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card)) + if (!card->ext_csd.man_bkops_en || mmc_card_doing_bkops(card)) return; err = mmc_read_bkops_status(card); @@ -345,29 +349,34 @@ static void mmc_wait_done(struct mmc_request *mrq) */ static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq) { + int err; + mrq->done = mmc_wait_data_done; mrq->host = host; - if (mmc_card_removed(host->card)) { - mrq->cmd->error = -ENOMEDIUM; - mmc_wait_data_done(mrq); - return -ENOMEDIUM; - } - mmc_start_request(host, mrq); - return 0; + err = mmc_start_request(host, mrq); + if (err) { + mrq->cmd->error = err; + mmc_wait_data_done(mrq); + } + + return err; } static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) { + int err; + init_completion(&mrq->completion); mrq->done = mmc_wait_done; - if (mmc_card_removed(host->card)) { - mrq->cmd->error = -ENOMEDIUM; + + err = mmc_start_request(host, mrq); + if (err) { + mrq->cmd->error = err; complete(&mrq->completion); - return -ENOMEDIUM; } - mmc_start_request(host, mrq); - return 0; + + return err; } /* @@ -1077,6 +1086,30 @@ void mmc_set_ungated(struct mmc_host *host) } #endif +int mmc_execute_tuning(struct mmc_card *card) +{ + struct mmc_host *host = card->host; + u32 opcode; + int err; + + if (!host->ops->execute_tuning) + return 0; + + if (mmc_card_mmc(card)) + opcode = MMC_SEND_TUNING_BLOCK_HS200; + else + opcode = MMC_SEND_TUNING_BLOCK; + + mmc_host_clk_hold(host); + err = host->ops->execute_tuning(host, opcode); + mmc_host_clk_release(host); + + if (err) + pr_err("%s: tuning execution failed\n", mmc_hostname(host)); + + return err; +} + /* * Change the bus mode (open drain/push-pull) of a host. */ @@ -1232,6 +1265,34 @@ EXPORT_SYMBOL(mmc_of_parse_voltage); #endif /* CONFIG_OF */ +static int mmc_of_get_func_num(struct device_node *node) +{ + u32 reg; + int ret; + + ret = of_property_read_u32(node, "reg", ®); + if (ret < 0) + return ret; + + return reg; +} + +struct device_node *mmc_of_find_child_device(struct mmc_host *host, + unsigned func_num) +{ + struct device_node *node; + + if (!host->parent || !host->parent->of_node) + return NULL; + + for_each_child_of_node(host->parent->of_node, node) { + if (mmc_of_get_func_num(node) == func_num) + return node; + } + + return NULL; +} + #ifdef CONFIG_REGULATOR /** @@ -1555,6 +1616,8 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) mmc_host_clk_hold(host); + mmc_pwrseq_pre_power_on(host); + host->ios.vdd = fls(ocr) - 1; host->ios.power_mode = MMC_POWER_UP; /* Set initial state and call mmc_set_ios */ @@ -1574,6 +1637,8 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) */ mmc_delay(10); + mmc_pwrseq_post_power_on(host); + host->ios.clock = host->f_init; host->ios.power_mode = MMC_POWER_ON; @@ -1595,6 +1660,8 @@ void mmc_power_off(struct mmc_host *host) mmc_host_clk_hold(host); + mmc_pwrseq_power_off(host); + host->ios.clock = 0; host->ios.vdd = 0; @@ -2245,67 +2312,28 @@ static void mmc_hw_reset_for_init(struct mmc_host *host) mmc_host_clk_release(host); } -int mmc_can_reset(struct mmc_card *card) -{ - u8 rst_n_function; - - if (!mmc_card_mmc(card)) - return 0; - rst_n_function = card->ext_csd.rst_n_function; - if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED) - return 0; - return 1; -} -EXPORT_SYMBOL(mmc_can_reset); - -static int mmc_do_hw_reset(struct mmc_host *host, int check) -{ - struct mmc_card *card = host->card; - - if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) - return -EOPNOTSUPP; - - if (!card) - return -EINVAL; - - if (!mmc_can_reset(card)) - return -EOPNOTSUPP; - - mmc_host_clk_hold(host); - mmc_set_clock(host, host->f_init); - - host->ops->hw_reset(host); - - /* If the reset has happened, then a status command will fail */ - if (check) { - u32 status; - - if (!mmc_send_status(card, &status)) { - mmc_host_clk_release(host); - return -ENOSYS; - } - } - - /* Set initial state and call mmc_set_ios */ - mmc_set_initial_state(host); - - mmc_host_clk_release(host); - - return host->bus_ops->power_restore(host); -} - int mmc_hw_reset(struct mmc_host *host) { - return mmc_do_hw_reset(host, 0); + int ret; + + if (!host->card) + return -EINVAL; + + mmc_bus_get(host); + if (!host->bus_ops || host->bus_dead || !host->bus_ops->reset) { + mmc_bus_put(host); + return -EOPNOTSUPP; + } + + ret = host->bus_ops->reset(host); + mmc_bus_put(host); + + pr_warn("%s: tried to reset card\n", mmc_hostname(host)); + + return ret; } EXPORT_SYMBOL(mmc_hw_reset); -int mmc_hw_reset_check(struct mmc_host *host) -{ - return mmc_do_hw_reset(host, 1); -} -EXPORT_SYMBOL(mmc_hw_reset_check); - static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) { host->f_init = freq; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index d76597c65e3a..cfba3c05aab1 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -27,11 +27,15 @@ struct mmc_bus_ops { int (*power_restore)(struct mmc_host *); int (*alive)(struct mmc_host *); int (*shutdown)(struct mmc_host *); + int (*reset)(struct mmc_host *); }; void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); void mmc_detach_bus(struct mmc_host *host); +struct device_node *mmc_of_find_child_device(struct mmc_host *host, + unsigned func_num); + void mmc_init_erase(struct mmc_card *card); void mmc_set_chip_select(struct mmc_host *host, int mode); @@ -82,5 +86,8 @@ void mmc_add_card_debugfs(struct mmc_card *card); void mmc_remove_card_debugfs(struct mmc_card *card); void mmc_init_context_info(struct mmc_host *host); + +int mmc_execute_tuning(struct mmc_card *card); + #endif diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 270d58a4c43d..8be0df758e68 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -29,13 +29,20 @@ #include "core.h" #include "host.h" +#include "slot-gpio.h" +#include "pwrseq.h" #define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev) +static DEFINE_IDR(mmc_host_idr); +static DEFINE_SPINLOCK(mmc_host_lock); + static void mmc_host_classdev_release(struct device *dev) { struct mmc_host *host = cls_dev_to_mmc_host(dev); - mutex_destroy(&host->slot.lock); + spin_lock(&mmc_host_lock); + idr_remove(&mmc_host_idr, host->index); + spin_unlock(&mmc_host_lock); kfree(host); } @@ -54,9 +61,6 @@ void mmc_unregister_host_class(void) class_unregister(&mmc_host_class); } -static DEFINE_IDR(mmc_host_idr); -static DEFINE_SPINLOCK(mmc_host_lock); - #ifdef CONFIG_MMC_CLKGATE static ssize_t clkgate_delay_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -367,16 +371,10 @@ int mmc_of_parse(struct mmc_host *host) ret = mmc_gpiod_request_cd(host, "cd", 0, true, 0, &cd_gpio_invert); - if (ret) { - if (ret == -EPROBE_DEFER) - return ret; - if (ret != -ENOENT) { - dev_err(host->parent, - "Failed to request CD GPIO: %d\n", - ret); - } - } else + if (!ret) dev_info(host->parent, "Got CD GPIO\n"); + else if (ret != -ENOENT) + return ret; /* * There are two ways to flag that the CD line is inverted: @@ -397,16 +395,10 @@ int mmc_of_parse(struct mmc_host *host) ro_cap_invert = of_property_read_bool(np, "wp-inverted"); ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &ro_gpio_invert); - if (ret) { - if (ret == -EPROBE_DEFER) - goto out; - if (ret != -ENOENT) { - dev_err(host->parent, - "Failed to request WP GPIO: %d\n", - ret); - } - } else + if (!ret) dev_info(host->parent, "Got WP GPIO\n"); + else if (ret != -ENOENT) + return ret; /* See the comment on CD inversion above */ if (ro_cap_invert ^ ro_gpio_invert) @@ -457,11 +449,7 @@ int mmc_of_parse(struct mmc_host *host) host->dsr_req = 0; } - return 0; - -out: - mmc_gpio_free_cd(host); - return ret; + return mmc_pwrseq_alloc(host); } EXPORT_SYMBOL(mmc_of_parse); @@ -491,8 +479,10 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->index = err; spin_unlock(&mmc_host_lock); idr_preload_end(); - if (err < 0) - goto free; + if (err < 0) { + kfree(host); + return NULL; + } dev_set_name(&host->class_dev, "mmc%d", host->index); @@ -501,10 +491,12 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->class_dev.class = &mmc_host_class; device_initialize(&host->class_dev); - mmc_host_clk_init(host); + if (mmc_gpio_alloc(host)) { + put_device(&host->class_dev); + return NULL; + } - mutex_init(&host->slot.lock); - host->slot.cd_irq = -EINVAL; + mmc_host_clk_init(host); spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); @@ -525,10 +517,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->max_blk_count = PAGE_CACHE_SIZE / 512; return host; - -free: - kfree(host); - return NULL; } EXPORT_SYMBOL(mmc_alloc_host); @@ -601,10 +589,7 @@ EXPORT_SYMBOL(mmc_remove_host); */ void mmc_free_host(struct mmc_host *host) { - spin_lock(&mmc_host_lock); - idr_remove(&mmc_host_idr, host->index); - spin_unlock(&mmc_host_lock); - + mmc_pwrseq_free(host); put_device(&host->class_dev); } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 7466ce098e60..1d41e8541f38 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -483,11 +483,13 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) /* check whether the eMMC card supports BKOPS */ if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) { card->ext_csd.bkops = 1; - card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN]; + card->ext_csd.man_bkops_en = + (ext_csd[EXT_CSD_BKOPS_EN] & + EXT_CSD_MANUAL_BKOPS_MASK); card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS]; - if (!card->ext_csd.bkops_en) - pr_info("%s: BKOPS_EN bit is not set\n", + if (!card->ext_csd.man_bkops_en) + pr_info("%s: MAN_BKOPS_EN bit is not set\n", mmc_hostname(card->host)); } @@ -1155,38 +1157,6 @@ bus_speed: return err; } -const u8 tuning_blk_pattern_4bit[MMC_TUNING_BLK_PATTERN_4BIT_SIZE] = { - 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, - 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, - 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, - 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, - 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, - 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, - 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, - 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, -}; -EXPORT_SYMBOL(tuning_blk_pattern_4bit); - -const u8 tuning_blk_pattern_8bit[MMC_TUNING_BLK_PATTERN_8BIT_SIZE] = { - 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, - 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, - 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, - 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, - 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, - 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, - 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, - 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, - 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, - 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, - 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, - 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, - 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, - 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, - 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, - 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, -}; -EXPORT_SYMBOL(tuning_blk_pattern_8bit); - /* * Execute tuning sequence to seek the proper bus operating * conditions for HS200 and HS400, which sends CMD21 to the device. @@ -1194,7 +1164,6 @@ EXPORT_SYMBOL(tuning_blk_pattern_8bit); static int mmc_hs200_tuning(struct mmc_card *card) { struct mmc_host *host = card->host; - int err = 0; /* * Timing should be adjusted to the HS400 target @@ -1205,18 +1174,7 @@ static int mmc_hs200_tuning(struct mmc_card *card) if (host->ops->prepare_hs400_tuning) host->ops->prepare_hs400_tuning(host, &host->ios); - if (host->ops->execute_tuning) { - mmc_host_clk_hold(host); - err = host->ops->execute_tuning(host, - MMC_SEND_TUNING_BLOCK_HS200); - mmc_host_clk_release(host); - - if (err) - pr_err("%s: tuning execution failed\n", - mmc_hostname(host)); - } - - return err; + return mmc_execute_tuning(card); } /* @@ -1296,6 +1254,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); } + /* + * Call the optional HC's init_card function to handle quirks. + */ + if (host->ops->init_card) + host->ops->init_card(host, card); + /* * For native busses: set card RCA and quit open drain mode. */ @@ -1821,6 +1785,46 @@ static int mmc_power_restore(struct mmc_host *host) return ret; } +int mmc_can_reset(struct mmc_card *card) +{ + u8 rst_n_function; + + rst_n_function = card->ext_csd.rst_n_function; + if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED) + return 0; + return 1; +} +EXPORT_SYMBOL(mmc_can_reset); + +static int mmc_reset(struct mmc_host *host) +{ + struct mmc_card *card = host->card; + u32 status; + + if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) + return -EOPNOTSUPP; + + if (!mmc_can_reset(card)) + return -EOPNOTSUPP; + + mmc_host_clk_hold(host); + mmc_set_clock(host, host->f_init); + + host->ops->hw_reset(host); + + /* If the reset has happened, then a status command will fail */ + if (!mmc_send_status(card, &status)) { + mmc_host_clk_release(host); + return -ENOSYS; + } + + /* Set initial state and call mmc_set_ios */ + mmc_set_initial_state(host); + mmc_host_clk_release(host); + + return mmc_power_restore(host); +} + static const struct mmc_bus_ops mmc_ops = { .remove = mmc_remove, .detect = mmc_detect, @@ -1831,6 +1835,7 @@ static const struct mmc_bus_ops mmc_ops = { .power_restore = mmc_power_restore, .alive = mmc_alive, .shutdown = mmc_shutdown, + .reset = mmc_reset, }; /* diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 3b044c5b029c..0ea042dc7443 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -23,6 +23,36 @@ #define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ +static const u8 tuning_blk_pattern_4bit[] = { + 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, + 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, + 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, + 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, + 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, + 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, + 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, + 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, +}; + +static const u8 tuning_blk_pattern_8bit[] = { + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, + 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, + 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, + 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, + 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, + 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, + 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, + 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, + 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, + 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, + 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, + 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, + 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, +}; + static inline int __mmc_send_status(struct mmc_card *card, u32 *status, bool ignore_crc) { diff --git a/drivers/mmc/core/pwrseq.c b/drivers/mmc/core/pwrseq.c new file mode 100644 index 000000000000..862356123d78 --- /dev/null +++ b/drivers/mmc/core/pwrseq.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2014 Linaro Ltd + * + * Author: Ulf Hansson + * + * License terms: GNU General Public License (GPL) version 2 + * + * MMC power sequence management + */ +#include +#include +#include +#include +#include + +#include + +#include "pwrseq.h" + +struct mmc_pwrseq_match { + const char *compatible; + int (*alloc)(struct mmc_host *host, struct device *dev); +}; + +static struct mmc_pwrseq_match pwrseq_match[] = { + { + .compatible = "mmc-pwrseq-simple", + .alloc = mmc_pwrseq_simple_alloc, + }, { + .compatible = "mmc-pwrseq-emmc", + .alloc = mmc_pwrseq_emmc_alloc, + }, +}; + +static struct mmc_pwrseq_match *mmc_pwrseq_find(struct device_node *np) +{ + struct mmc_pwrseq_match *match = ERR_PTR(-ENODEV); + int i; + + for (i = 0; i < ARRAY_SIZE(pwrseq_match); i++) { + if (of_device_is_compatible(np, pwrseq_match[i].compatible)) { + match = &pwrseq_match[i]; + break; + } + } + + return match; +} + +int mmc_pwrseq_alloc(struct mmc_host *host) +{ + struct platform_device *pdev; + struct device_node *np; + struct mmc_pwrseq_match *match; + int ret = 0; + + np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0); + if (!np) + return 0; + + pdev = of_find_device_by_node(np); + if (!pdev) { + ret = -ENODEV; + goto err; + } + + match = mmc_pwrseq_find(np); + if (IS_ERR(match)) { + ret = PTR_ERR(match); + goto err; + } + + ret = match->alloc(host, &pdev->dev); + if (!ret) + dev_info(host->parent, "allocated mmc-pwrseq\n"); + +err: + of_node_put(np); + return ret; +} + +void mmc_pwrseq_pre_power_on(struct mmc_host *host) +{ + struct mmc_pwrseq *pwrseq = host->pwrseq; + + if (pwrseq && pwrseq->ops && pwrseq->ops->pre_power_on) + pwrseq->ops->pre_power_on(host); +} + +void mmc_pwrseq_post_power_on(struct mmc_host *host) +{ + struct mmc_pwrseq *pwrseq = host->pwrseq; + + if (pwrseq && pwrseq->ops && pwrseq->ops->post_power_on) + pwrseq->ops->post_power_on(host); +} + +void mmc_pwrseq_power_off(struct mmc_host *host) +{ + struct mmc_pwrseq *pwrseq = host->pwrseq; + + if (pwrseq && pwrseq->ops && pwrseq->ops->power_off) + pwrseq->ops->power_off(host); +} + +void mmc_pwrseq_free(struct mmc_host *host) +{ + struct mmc_pwrseq *pwrseq = host->pwrseq; + + if (pwrseq && pwrseq->ops && pwrseq->ops->free) + pwrseq->ops->free(host); +} diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h new file mode 100644 index 000000000000..aba3409e8d6e --- /dev/null +++ b/drivers/mmc/core/pwrseq.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014 Linaro Ltd + * + * Author: Ulf Hansson + * + * License terms: GNU General Public License (GPL) version 2 + */ +#ifndef _MMC_CORE_PWRSEQ_H +#define _MMC_CORE_PWRSEQ_H + +struct mmc_pwrseq_ops { + void (*pre_power_on)(struct mmc_host *host); + void (*post_power_on)(struct mmc_host *host); + void (*power_off)(struct mmc_host *host); + void (*free)(struct mmc_host *host); +}; + +struct mmc_pwrseq { + struct mmc_pwrseq_ops *ops; +}; + +#ifdef CONFIG_OF + +int mmc_pwrseq_alloc(struct mmc_host *host); +void mmc_pwrseq_pre_power_on(struct mmc_host *host); +void mmc_pwrseq_post_power_on(struct mmc_host *host); +void mmc_pwrseq_power_off(struct mmc_host *host); +void mmc_pwrseq_free(struct mmc_host *host); + +int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev); +int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev); + +#else + +static inline int mmc_pwrseq_alloc(struct mmc_host *host) { return 0; } +static inline void mmc_pwrseq_pre_power_on(struct mmc_host *host) {} +static inline void mmc_pwrseq_post_power_on(struct mmc_host *host) {} +static inline void mmc_pwrseq_power_off(struct mmc_host *host) {} +static inline void mmc_pwrseq_free(struct mmc_host *host) {} + +#endif + +#endif diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c new file mode 100644 index 000000000000..a2d545904fbf --- /dev/null +++ b/drivers/mmc/core/pwrseq_emmc.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2015, Samsung Electronics Co., Ltd. + * + * Author: Marek Szyprowski + * + * License terms: GNU General Public License (GPL) version 2 + * + * Simple eMMC hardware reset provider + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "pwrseq.h" + +struct mmc_pwrseq_emmc { + struct mmc_pwrseq pwrseq; + struct notifier_block reset_nb; + struct gpio_desc *reset_gpio; +}; + +static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq) +{ + gpiod_set_value(pwrseq->reset_gpio, 1); + udelay(1); + gpiod_set_value(pwrseq->reset_gpio, 0); + udelay(200); +} + +static void mmc_pwrseq_emmc_reset(struct mmc_host *host) +{ + struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq, + struct mmc_pwrseq_emmc, pwrseq); + + __mmc_pwrseq_emmc_reset(pwrseq); +} + +static void mmc_pwrseq_emmc_free(struct mmc_host *host) +{ + struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq, + struct mmc_pwrseq_emmc, pwrseq); + + unregister_restart_handler(&pwrseq->reset_nb); + gpiod_put(pwrseq->reset_gpio); + kfree(pwrseq); + host->pwrseq = NULL; +} + +static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = { + .post_power_on = mmc_pwrseq_emmc_reset, + .free = mmc_pwrseq_emmc_free, +}; + +static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + struct mmc_pwrseq_emmc *pwrseq = container_of(this, + struct mmc_pwrseq_emmc, reset_nb); + + __mmc_pwrseq_emmc_reset(pwrseq); + return NOTIFY_DONE; +} + +int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev) +{ + struct mmc_pwrseq_emmc *pwrseq; + int ret = 0; + + pwrseq = kzalloc(sizeof(struct mmc_pwrseq_emmc), GFP_KERNEL); + if (!pwrseq) + return -ENOMEM; + + pwrseq->reset_gpio = gpiod_get_index(dev, "reset", 0, GPIOD_OUT_LOW); + if (IS_ERR(pwrseq->reset_gpio)) { + ret = PTR_ERR(pwrseq->reset_gpio); + goto free; + } + + /* + * register reset handler to ensure emmc reset also from + * emergency_reboot(), priority 129 schedules it just before + * system reboot + */ + pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; + pwrseq->reset_nb.priority = 129; + register_restart_handler(&pwrseq->reset_nb); + + pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops; + host->pwrseq = &pwrseq->pwrseq; + + return 0; +free: + kfree(pwrseq); + return ret; +} diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c new file mode 100644 index 000000000000..e9f1d8d84613 --- /dev/null +++ b/drivers/mmc/core/pwrseq_simple.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2014 Linaro Ltd + * + * Author: Ulf Hansson + * + * License terms: GNU General Public License (GPL) version 2 + * + * Simple MMC power sequence management + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "pwrseq.h" + +struct mmc_pwrseq_simple { + struct mmc_pwrseq pwrseq; + bool clk_enabled; + struct clk *ext_clk; + int nr_gpios; + struct gpio_desc *reset_gpios[0]; +}; + +static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, + int value) +{ + int i; + + for (i = 0; i < pwrseq->nr_gpios; i++) + if (!IS_ERR(pwrseq->reset_gpios[i])) + gpiod_set_value_cansleep(pwrseq->reset_gpios[i], value); +} + +static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host) +{ + struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, + struct mmc_pwrseq_simple, pwrseq); + + if (!IS_ERR(pwrseq->ext_clk) && !pwrseq->clk_enabled) { + clk_prepare_enable(pwrseq->ext_clk); + pwrseq->clk_enabled = true; + } + + mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); +} + +static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host) +{ + struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, + struct mmc_pwrseq_simple, pwrseq); + + mmc_pwrseq_simple_set_gpios_value(pwrseq, 0); +} + +static void mmc_pwrseq_simple_power_off(struct mmc_host *host) +{ + struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, + struct mmc_pwrseq_simple, pwrseq); + + mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); + + if (!IS_ERR(pwrseq->ext_clk) && pwrseq->clk_enabled) { + clk_disable_unprepare(pwrseq->ext_clk); + pwrseq->clk_enabled = false; + } +} + +static void mmc_pwrseq_simple_free(struct mmc_host *host) +{ + struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, + struct mmc_pwrseq_simple, pwrseq); + int i; + + for (i = 0; i < pwrseq->nr_gpios; i++) + if (!IS_ERR(pwrseq->reset_gpios[i])) + gpiod_put(pwrseq->reset_gpios[i]); + + if (!IS_ERR(pwrseq->ext_clk)) + clk_put(pwrseq->ext_clk); + + kfree(pwrseq); + host->pwrseq = NULL; +} + +static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = { + .pre_power_on = mmc_pwrseq_simple_pre_power_on, + .post_power_on = mmc_pwrseq_simple_post_power_on, + .power_off = mmc_pwrseq_simple_power_off, + .free = mmc_pwrseq_simple_free, +}; + +int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev) +{ + struct mmc_pwrseq_simple *pwrseq; + int i, nr_gpios, ret = 0; + + nr_gpios = of_gpio_named_count(dev->of_node, "reset-gpios"); + if (nr_gpios < 0) + nr_gpios = 0; + + pwrseq = kzalloc(sizeof(struct mmc_pwrseq_simple) + nr_gpios * + sizeof(struct gpio_desc *), GFP_KERNEL); + if (!pwrseq) + return -ENOMEM; + + pwrseq->ext_clk = clk_get(dev, "ext_clock"); + if (IS_ERR(pwrseq->ext_clk) && + PTR_ERR(pwrseq->ext_clk) != -ENOENT) { + ret = PTR_ERR(pwrseq->ext_clk); + goto free; + } + + for (i = 0; i < nr_gpios; i++) { + pwrseq->reset_gpios[i] = gpiod_get_index(dev, "reset", i, + GPIOD_OUT_HIGH); + if (IS_ERR(pwrseq->reset_gpios[i]) && + PTR_ERR(pwrseq->reset_gpios[i]) != -ENOENT && + PTR_ERR(pwrseq->reset_gpios[i]) != -ENOSYS) { + ret = PTR_ERR(pwrseq->reset_gpios[i]); + + while (--i) + gpiod_put(pwrseq->reset_gpios[i]); + + goto clk_put; + } + } + + pwrseq->nr_gpios = nr_gpios; + pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops; + host->pwrseq = &pwrseq->pwrseq; + + return 0; +clk_put: + if (!IS_ERR(pwrseq->ext_clk)) + clk_put(pwrseq->ext_clk); +free: + kfree(pwrseq); + return ret; +} diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index d90a6de7901d..ad4d43eae99d 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -660,15 +660,10 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104. */ - if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning && - (card->sd_bus_speed == UHS_SDR50_BUS_SPEED || - card->sd_bus_speed == UHS_SDR104_BUS_SPEED)) { - mmc_host_clk_hold(card->host); - err = card->host->ops->execute_tuning(card->host, - MMC_SEND_TUNING_BLOCK); - mmc_host_clk_release(card->host); - } - + if (!mmc_host_is_spi(card->host) && + (card->sd_bus_speed == UHS_SDR50_BUS_SPEED || + card->sd_bus_speed == UHS_SDR104_BUS_SPEED)) + err = mmc_execute_tuning(card); out: kfree(status); @@ -932,6 +927,12 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); } + /* + * Call the optional HC's init_card function to handle quirks. + */ + if (host->ops->init_card) + host->ops->init_card(host, card); + /* * For native busses: get card RCA and quit open drain mode. */ @@ -1191,6 +1192,12 @@ static int mmc_sd_power_restore(struct mmc_host *host) return ret; } +static int mmc_sd_reset(struct mmc_host *host) +{ + mmc_power_cycle(host, host->card->ocr); + return mmc_sd_power_restore(host); +} + static const struct mmc_bus_ops mmc_sd_ops = { .remove = mmc_sd_remove, .detect = mmc_sd_detect, @@ -1201,6 +1208,7 @@ static const struct mmc_bus_ops mmc_sd_ops = { .power_restore = mmc_sd_power_restore, .alive = mmc_sd_alive, .shutdown = mmc_sd_suspend, + .reset = mmc_sd_reset, }; /* @@ -1271,4 +1279,3 @@ err: return err; } - diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index fd0750b5a634..ce6cc47206b0 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -567,17 +567,11 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card) * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104. */ - if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning && - ((card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) || - (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104))) { - mmc_host_clk_hold(card->host); - err = card->host->ops->execute_tuning(card->host, - MMC_SEND_TUNING_BLOCK); - mmc_host_clk_release(card->host); - } - + if (!mmc_host_is_spi(card->host) && + ((card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) || + (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104))) + err = mmc_execute_tuning(card); out: - return err; } diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 60885316afba..bee02e644d62 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -22,7 +22,9 @@ #include #include #include +#include +#include "core.h" #include "sdio_cis.h" #include "sdio_bus.h" @@ -295,6 +297,13 @@ static void sdio_acpi_set_handle(struct sdio_func *func) static inline void sdio_acpi_set_handle(struct sdio_func *func) {} #endif +static void sdio_set_of_node(struct sdio_func *func) +{ + struct mmc_host *host = func->card->host; + + func->dev.of_node = mmc_of_find_child_device(host, func->num); +} + /* * Register a new SDIO function with the driver model. */ @@ -304,6 +313,7 @@ int sdio_add_func(struct sdio_func *func) dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num); + sdio_set_of_node(func); sdio_acpi_set_handle(func); ret = device_add(&func->dev); if (ret == 0) { @@ -327,6 +337,7 @@ void sdio_remove_func(struct sdio_func *func) dev_pm_domain_detach(&func->dev, false); device_del(&func->dev); + of_node_put(func->dev.of_node); put_device(&func->dev); } diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 69bbf2adb329..27117ba47073 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -18,11 +18,14 @@ #include #include +#include "slot-gpio.h" + struct mmc_gpio { struct gpio_desc *ro_gpio; struct gpio_desc *cd_gpio; bool override_ro_active_level; bool override_cd_active_level; + irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id); char *ro_label; char cd_label[0]; }; @@ -38,32 +41,20 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) return IRQ_HANDLED; } -static int mmc_gpio_alloc(struct mmc_host *host) +int mmc_gpio_alloc(struct mmc_host *host) { size_t len = strlen(dev_name(host->parent)) + 4; - struct mmc_gpio *ctx; + struct mmc_gpio *ctx = devm_kzalloc(host->parent, + sizeof(*ctx) + 2 * len, GFP_KERNEL); - mutex_lock(&host->slot.lock); - - ctx = host->slot.handler_priv; - if (!ctx) { - /* - * devm_kzalloc() can be called after device_initialize(), even - * before device_add(), i.e., between mmc_alloc_host() and - * mmc_add_host() - */ - ctx = devm_kzalloc(&host->class_dev, sizeof(*ctx) + 2 * len, - GFP_KERNEL); - if (ctx) { - ctx->ro_label = ctx->cd_label + len; - snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent)); - snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent)); - host->slot.handler_priv = ctx; - } + if (ctx) { + ctx->ro_label = ctx->cd_label + len; + snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent)); + snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent)); + host->slot.handler_priv = ctx; + host->slot.cd_irq = -EINVAL; } - mutex_unlock(&host->slot.lock); - return ctx ? 0 : -ENOMEM; } @@ -103,29 +94,19 @@ EXPORT_SYMBOL(mmc_gpio_get_cd); * @gpio: gpio number requested * * As devm_* managed functions are used in mmc_gpio_request_ro(), client - * drivers do not need to explicitly call mmc_gpio_free_ro() for freeing up, - * if the requesting and freeing are only needed at probing and unbinding time - * for once. However, if client drivers do something special like runtime - * switching for write-protection, they are responsible for calling - * mmc_gpio_request_ro() and mmc_gpio_free_ro() as a pair on their own. + * drivers do not need to worry about freeing up memory. * * Returns zero on success, else an error. */ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio) { - struct mmc_gpio *ctx; + struct mmc_gpio *ctx = host->slot.handler_priv; int ret; if (!gpio_is_valid(gpio)) return -EINVAL; - ret = mmc_gpio_alloc(host); - if (ret < 0) - return ret; - - ctx = host->slot.handler_priv; - - ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN, + ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN, ctx->ro_label); if (ret < 0) return ret; @@ -156,8 +137,10 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host) irq = -EINVAL; if (irq >= 0) { - ret = devm_request_threaded_irq(&host->class_dev, irq, - NULL, mmc_gpio_cd_irqt, + if (!ctx->cd_gpio_isr) + ctx->cd_gpio_isr = mmc_gpio_cd_irqt; + ret = devm_request_threaded_irq(host->parent, irq, + NULL, ctx->cd_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ctx->cd_label, host); if (ret < 0) @@ -171,6 +154,19 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host) } EXPORT_SYMBOL(mmc_gpiod_request_cd_irq); +/* Register an alternate interrupt service routine for + * the card-detect GPIO. + */ +void mmc_gpio_set_cd_isr(struct mmc_host *host, + irqreturn_t (*isr)(int irq, void *dev_id)) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + + WARN_ON(ctx->cd_gpio_isr); + ctx->cd_gpio_isr = isr; +} +EXPORT_SYMBOL(mmc_gpio_set_cd_isr); + /** * mmc_gpio_request_cd - request a gpio for card-detection * @host: mmc host @@ -178,11 +174,7 @@ EXPORT_SYMBOL(mmc_gpiod_request_cd_irq); * @debounce: debounce time in microseconds * * As devm_* managed functions are used in mmc_gpio_request_cd(), client - * drivers do not need to explicitly call mmc_gpio_free_cd() for freeing up, - * if the requesting and freeing are only needed at probing and unbinding time - * for once. However, if client drivers do something special like runtime - * switching for card-detection, they are responsible for calling - * mmc_gpio_request_cd() and mmc_gpio_free_cd() as a pair on their own. + * drivers do not need to worry about freeing up memory. * * If GPIO debouncing is desired, set the debounce parameter to a non-zero * value. The caller is responsible for ensuring that the GPIO driver associated @@ -193,16 +185,10 @@ EXPORT_SYMBOL(mmc_gpiod_request_cd_irq); int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, unsigned int debounce) { - struct mmc_gpio *ctx; + struct mmc_gpio *ctx = host->slot.handler_priv; int ret; - ret = mmc_gpio_alloc(host); - if (ret < 0) - return ret; - - ctx = host->slot.handler_priv; - - ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN, + ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN, ctx->cd_label); if (ret < 0) /* @@ -225,55 +211,6 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, } EXPORT_SYMBOL(mmc_gpio_request_cd); -/** - * mmc_gpio_free_ro - free the write-protection gpio - * @host: mmc host - * - * It's provided only for cases that client drivers need to manually free - * up the write-protection gpio requested by mmc_gpio_request_ro(). - */ -void mmc_gpio_free_ro(struct mmc_host *host) -{ - struct mmc_gpio *ctx = host->slot.handler_priv; - int gpio; - - if (!ctx || !ctx->ro_gpio) - return; - - gpio = desc_to_gpio(ctx->ro_gpio); - ctx->ro_gpio = NULL; - - devm_gpio_free(&host->class_dev, gpio); -} -EXPORT_SYMBOL(mmc_gpio_free_ro); - -/** - * mmc_gpio_free_cd - free the card-detection gpio - * @host: mmc host - * - * It's provided only for cases that client drivers need to manually free - * up the card-detection gpio requested by mmc_gpio_request_cd(). - */ -void mmc_gpio_free_cd(struct mmc_host *host) -{ - struct mmc_gpio *ctx = host->slot.handler_priv; - int gpio; - - if (!ctx || !ctx->cd_gpio) - return; - - if (host->slot.cd_irq >= 0) { - devm_free_irq(&host->class_dev, host->slot.cd_irq, host); - host->slot.cd_irq = -EINVAL; - } - - gpio = desc_to_gpio(ctx->cd_gpio); - ctx->cd_gpio = NULL; - - devm_gpio_free(&host->class_dev, gpio); -} -EXPORT_SYMBOL(mmc_gpio_free_cd); - /** * mmc_gpiod_request_cd - request a gpio descriptor for card-detection * @host: mmc host @@ -285,8 +222,7 @@ EXPORT_SYMBOL(mmc_gpio_free_cd); * to NULL to ignore * * Use this function in place of mmc_gpio_request_cd() to use the GPIO - * descriptor API. Note that it is paired with mmc_gpiod_free_cd() not - * mmc_gpio_free_cd(). Note also that it must be called prior to mmc_add_host() + * descriptor API. Note that it must be called prior to mmc_add_host() * otherwise the caller must also call mmc_gpiod_request_cd_irq(). * * Returns zero on success, else an error. @@ -295,16 +231,10 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, unsigned int idx, bool override_active_level, unsigned int debounce, bool *gpio_invert) { - struct mmc_gpio *ctx; + struct mmc_gpio *ctx = host->slot.handler_priv; struct gpio_desc *desc; int ret; - ret = mmc_gpio_alloc(host); - if (ret < 0) - return ret; - - ctx = host->slot.handler_priv; - if (!con_id) con_id = ctx->cd_label; @@ -339,8 +269,7 @@ EXPORT_SYMBOL(mmc_gpiod_request_cd); * set to NULL to ignore * * Use this function in place of mmc_gpio_request_ro() to use the GPIO - * descriptor API. Note that it is paired with mmc_gpiod_free_ro() not - * mmc_gpio_free_ro(). + * descriptor API. * * Returns zero on success, else an error. */ @@ -348,16 +277,10 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, unsigned int idx, bool override_active_level, unsigned int debounce, bool *gpio_invert) { - struct mmc_gpio *ctx; + struct mmc_gpio *ctx = host->slot.handler_priv; struct gpio_desc *desc; int ret; - ret = mmc_gpio_alloc(host); - if (ret < 0) - return ret; - - ctx = host->slot.handler_priv; - if (!con_id) con_id = ctx->ro_label; @@ -380,28 +303,3 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, return 0; } EXPORT_SYMBOL(mmc_gpiod_request_ro); - -/** - * mmc_gpiod_free_cd - free the card-detection gpio descriptor - * @host: mmc host - * - * It's provided only for cases that client drivers need to manually free - * up the card-detection gpio requested by mmc_gpiod_request_cd(). - */ -void mmc_gpiod_free_cd(struct mmc_host *host) -{ - struct mmc_gpio *ctx = host->slot.handler_priv; - - if (!ctx || !ctx->cd_gpio) - return; - - if (host->slot.cd_irq >= 0) { - devm_free_irq(&host->class_dev, host->slot.cd_irq, host); - host->slot.cd_irq = -EINVAL; - } - - devm_gpiod_put(host->parent, ctx->cd_gpio); - - ctx->cd_gpio = NULL; -} -EXPORT_SYMBOL(mmc_gpiod_free_cd); diff --git a/drivers/mmc/core/slot-gpio.h b/drivers/mmc/core/slot-gpio.h new file mode 100644 index 000000000000..8c1854dc5d58 --- /dev/null +++ b/drivers/mmc/core/slot-gpio.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2014 Linaro Ltd + * + * Author: Ulf Hansson + * + * License terms: GNU General Public License (GPL) version 2 + */ +#ifndef _MMC_CORE_SLOTGPIO_H +#define _MMC_CORE_SLOTGPIO_H + +int mmc_gpio_alloc(struct mmc_host *host); + +#endif diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 2d6fbdd11803..61ac63a3776a 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -57,6 +57,7 @@ config MMC_SDHCI_IO_ACCESSORS config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER bool + depends on MMC_SDHCI select MMC_SDHCI_IO_ACCESSORS help This option is selected by drivers running on big endian hosts @@ -82,6 +83,7 @@ config MMC_SDHCI_PCI config MMC_RICOH_MMC bool "Ricoh MMC Controller Disabler" depends on MMC_SDHCI_PCI + default y help This adds a pci quirk to disable Ricoh MMC Controller. This proprietary controller is unnecessary because the SDHCI driver @@ -228,6 +230,7 @@ config MMC_SDHCI_PXAV3 tristate "Marvell MMP2 SD Host Controller support (PXAV3)" depends on CLKDEV_LOOKUP depends on MMC_SDHCI_PLTFM + depends on ARCH_MMP || COMPILE_TEST default CPU_MMP2 help This selects the Marvell(R) PXAV3 SD Host Controller. @@ -240,6 +243,7 @@ config MMC_SDHCI_PXAV2 tristate "Marvell PXA9XX SD Host Controller support (PXAV2)" depends on CLKDEV_LOOKUP depends on MMC_SDHCI_PLTFM + depends on ARCH_MMP || COMPILE_TEST default CPU_PXA910 help This selects the Marvell(R) PXAV2 SD Host Controller. @@ -292,6 +296,17 @@ config MMC_SDHCI_BCM2835 If unsure, say N. +config MMC_SDHCI_F_SDH30 + tristate "SDHCI support for Fujitsu Semiconductor F_SDH30" + depends on MMC_SDHCI_PLTFM + depends on OF + help + This selects the Secure Digital Host Controller Interface (SDHCI) + Needed by some Fujitsu SoC for MMC / SD / SDIO support. + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + config MMC_MOXART tristate "MOXART SD/MMC Host Controller support" depends on ARCH_MOXART && MMC diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index f7b0a77cf419..6a7cfe0de332 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o +obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 509365cb22c6..fe32948c6114 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -21,43 +21,7 @@ #include "dw_mmc.h" #include "dw_mmc-pltfm.h" - -#define NUM_PINS(x) (x + 2) - -#define SDMMC_CLKSEL 0x09C -#define SDMMC_CLKSEL64 0x0A8 -#define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0) -#define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16) -#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24) -#define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7) -#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \ - SDMMC_CLKSEL_CCLK_DRIVE(y) | \ - SDMMC_CLKSEL_CCLK_DIVIDER(z)) -#define SDMMC_CLKSEL_WAKEUP_INT BIT(11) - -#define EXYNOS4210_FIXED_CIU_CLK_DIV 2 -#define EXYNOS4412_FIXED_CIU_CLK_DIV 4 - -/* Block number in eMMC */ -#define DWMCI_BLOCK_NUM 0xFFFFFFFF - -#define SDMMC_EMMCP_BASE 0x1000 -#define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010) -#define SDMMC_MPSBEGIN0 (SDMMC_EMMCP_BASE + 0x0200) -#define SDMMC_MPSEND0 (SDMMC_EMMCP_BASE + 0x0204) -#define SDMMC_MPSCTRL0 (SDMMC_EMMCP_BASE + 0x020C) - -/* SMU control bits */ -#define DWMCI_MPSCTRL_SECURE_READ_BIT BIT(7) -#define DWMCI_MPSCTRL_SECURE_WRITE_BIT BIT(6) -#define DWMCI_MPSCTRL_NON_SECURE_READ_BIT BIT(5) -#define DWMCI_MPSCTRL_NON_SECURE_WRITE_BIT BIT(4) -#define DWMCI_MPSCTRL_USE_FUSE_KEY BIT(3) -#define DWMCI_MPSCTRL_ECB_MODE BIT(2) -#define DWMCI_MPSCTRL_ENCRYPTION BIT(1) -#define DWMCI_MPSCTRL_VALID BIT(0) - -#define EXYNOS_CCLKIN_MIN 50000000 /* unit: HZ */ +#include "dw_mmc-exynos.h" /* Variations in Exynos specific dw-mshc controller */ enum dw_mci_exynos_type { @@ -114,11 +78,11 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU || priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) { mci_writel(host, MPSBEGIN0, 0); - mci_writel(host, MPSEND0, DWMCI_BLOCK_NUM); - mci_writel(host, MPSCTRL0, DWMCI_MPSCTRL_SECURE_WRITE_BIT | - DWMCI_MPSCTRL_NON_SECURE_READ_BIT | - DWMCI_MPSCTRL_VALID | - DWMCI_MPSCTRL_NON_SECURE_WRITE_BIT); + mci_writel(host, MPSEND0, SDMMC_ENDING_SEC_NR_MAX); + mci_writel(host, MPSCTRL0, SDMMC_MPSCTRL_SECURE_WRITE_BIT | + SDMMC_MPSCTRL_NON_SECURE_READ_BIT | + SDMMC_MPSCTRL_VALID | + SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT); } return 0; @@ -127,9 +91,9 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) static int dw_mci_exynos_setup_clock(struct dw_mci *host) { struct dw_mci_exynos_priv_data *priv = host->priv; - unsigned long rate = clk_get_rate(host->ciu_clk); - host->bus_hz = rate / (priv->ciu_div + 1); + host->bus_hz /= (priv->ciu_div + 1); + return 0; } @@ -232,8 +196,11 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) mci_writel(host, CLKSEL, priv->sdr_timing); } - /* Don't care if wanted clock is zero */ - if (!wanted) + /* + * Don't care if wanted clock is zero or + * ciu clock is unavailable + */ + if (!wanted || IS_ERR(host->ciu_clk)) return; /* Guaranteed minimum frequency for cclkin */ @@ -263,10 +230,8 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host) int ret; priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(host->dev, "mem alloc failed for private data\n"); + if (!priv) return -ENOMEM; - } for (idx = 0; idx < ARRAY_SIZE(exynos_compat); idx++) { if (of_device_is_compatible(np, exynos_compat[idx].compatible)) @@ -375,64 +340,23 @@ out: return loc; } -static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode, - struct dw_mci_tuning_data *tuning_data) +static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot) { struct dw_mci *host = slot->host; struct mmc_host *mmc = slot->mmc; - const u8 *blk_pattern = tuning_data->blk_pattern; - u8 *blk_test; - unsigned int blksz = tuning_data->blksz; u8 start_smpl, smpl, candiates = 0; s8 found = -1; int ret = 0; - blk_test = kmalloc(blksz, GFP_KERNEL); - if (!blk_test) - return -ENOMEM; - start_smpl = dw_mci_exynos_get_clksmpl(host); do { - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_command stop = {0}; - struct mmc_data data = {0}; - struct scatterlist sg; - - cmd.opcode = opcode; - cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - - stop.opcode = MMC_STOP_TRANSMISSION; - stop.arg = 0; - stop.flags = MMC_RSP_R1B | MMC_CMD_AC; - - data.blksz = blksz; - data.blocks = 1; - data.flags = MMC_DATA_READ; - data.sg = &sg; - data.sg_len = 1; - - sg_init_one(&sg, blk_test, blksz); - mrq.cmd = &cmd; - mrq.stop = &stop; - mrq.data = &data; - host->mrq = &mrq; - mci_writel(host, TMOUT, ~0); smpl = dw_mci_exynos_move_next_clksmpl(host); - mmc_wait_for_req(mmc, &mrq); + if (!mmc_send_tuning(mmc)) + candiates |= (1 << smpl); - if (!cmd.error && !data.error) { - if (!memcmp(blk_pattern, blk_test, blksz)) - candiates |= (1 << smpl); - } else { - dev_dbg(host->dev, - "Tuning error: cmd.error:%d, data.error:%d\n", - cmd.error, data.error); - } } while (start_smpl != smpl); found = dw_mci_exynos_get_best_clksmpl(candiates); @@ -441,7 +365,6 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode, else ret = -EIO; - kfree(blk_test); return ret; } @@ -499,7 +422,7 @@ static const struct dev_pm_ops dw_mci_exynos_pmops = { static struct platform_driver dw_mci_exynos_pltfm_driver = { .probe = dw_mci_exynos_probe, - .remove = __exit_p(dw_mci_pltfm_remove), + .remove = dw_mci_pltfm_remove, .driver = { .name = "dwmmc_exynos", .of_match_table = dw_mci_exynos_match, diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h new file mode 100644 index 000000000000..7872ce586b55 --- /dev/null +++ b/drivers/mmc/host/dw_mmc-exynos.h @@ -0,0 +1,56 @@ +/* + * Exynos Specific Extensions for Synopsys DW Multimedia Card Interface driver + * + * Copyright (C) 2012-2014 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _DW_MMC_EXYNOS_H_ +#define _DW_MMC_EXYNOS_H_ + +/* Extended Register's Offset */ +#define SDMMC_CLKSEL 0x09C +#define SDMMC_CLKSEL64 0x0A8 + +/* CLKSEL register defines */ +#define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0) +#define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16) +#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24) +#define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7) +#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \ + SDMMC_CLKSEL_CCLK_DRIVE(y) | \ + SDMMC_CLKSEL_CCLK_DIVIDER(z)) +#define SDMMC_CLKSEL_WAKEUP_INT BIT(11) + +/* Protector Register */ +#define SDMMC_EMMCP_BASE 0x1000 +#define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010) +#define SDMMC_MPSBEGIN0 (SDMMC_EMMCP_BASE + 0x0200) +#define SDMMC_MPSEND0 (SDMMC_EMMCP_BASE + 0x0204) +#define SDMMC_MPSCTRL0 (SDMMC_EMMCP_BASE + 0x020C) + +/* SMU control defines */ +#define SDMMC_MPSCTRL_SECURE_READ_BIT BIT(7) +#define SDMMC_MPSCTRL_SECURE_WRITE_BIT BIT(6) +#define SDMMC_MPSCTRL_NON_SECURE_READ_BIT BIT(5) +#define SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT BIT(4) +#define SDMMC_MPSCTRL_USE_FUSE_KEY BIT(3) +#define SDMMC_MPSCTRL_ECB_MODE BIT(2) +#define SDMMC_MPSCTRL_ENCRYPTION BIT(1) +#define SDMMC_MPSCTRL_VALID BIT(0) + +/* Maximum number of Ending sector */ +#define SDMMC_ENDING_SEC_NR_MAX 0xFFFFFFFF + +/* Fixed clock divider */ +#define EXYNOS4210_FIXED_CIU_CLK_DIV 2 +#define EXYNOS4412_FIXED_CIU_CLK_DIV 4 + +/* Minimal required clock frequency for cclkin, unit: HZ */ +#define EXYNOS_CCLKIN_MIN 50000000 + +#endif /* _DW_MMC_EXYNOS_H_ */ diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index 5650ac488cf3..e2a726a503ee 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -133,7 +133,7 @@ static SIMPLE_DEV_PM_OPS(dw_mci_rockchip_pmops, static struct platform_driver dw_mci_rockchip_pltfm_driver = { .probe = dw_mci_rockchip_probe, - .remove = __exit_p(dw_mci_pltfm_remove), + .remove = dw_mci_pltfm_remove, .driver = { .name = "dwmmc_rockchip", .of_match_table = dw_mci_rockchip_match, diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 67c04518ec4c..4d2e3c2e1830 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -313,7 +314,9 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) if (cmdr == MMC_READ_SINGLE_BLOCK || cmdr == MMC_READ_MULTIPLE_BLOCK || cmdr == MMC_WRITE_BLOCK || - cmdr == MMC_WRITE_MULTIPLE_BLOCK) { + cmdr == MMC_WRITE_MULTIPLE_BLOCK || + cmdr == MMC_SEND_TUNING_BLOCK || + cmdr == MMC_SEND_TUNING_BLOCK_HS200) { stop->opcode = MMC_STOP_TRANSMISSION; stop->arg = 0; stop->flags = MMC_RSP_R1B | MMC_CMD_AC; @@ -758,6 +761,7 @@ disable: static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) { + unsigned long irqflags; int sg_len; u32 temp; @@ -794,9 +798,11 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) mci_writel(host, CTRL, temp); /* Disable RX/TX IRQs, let DMA handle it */ + spin_lock_irqsave(&host->irq_lock, irqflags); temp = mci_readl(host, INTMASK); temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR); mci_writel(host, INTMASK, temp); + spin_unlock_irqrestore(&host->irq_lock, irqflags); host->dma_ops->start(host, sg_len); @@ -805,6 +811,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) { + unsigned long irqflags; u32 temp; data->error = -EINPROGRESS; @@ -833,9 +840,12 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) host->part_buf_count = 0; mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR); + + spin_lock_irqsave(&host->irq_lock, irqflags); temp = mci_readl(host, INTMASK); temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR; mci_writel(host, INTMASK, temp); + spin_unlock_irqrestore(&host->irq_lock, irqflags); temp = mci_readl(host, CTRL); temp &= ~SDMMC_CTRL_DMA_ENABLE; @@ -926,7 +936,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) /* enable clock; only low power if no SDIO */ clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; - if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->sdio_id))) + if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; mci_writel(host, CLKENA, clk_en_a); @@ -1109,6 +1119,12 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) return; } } + set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); + regs = mci_readl(slot->host, PWREN); + regs |= (1 << slot->id); + mci_writel(slot->host, PWREN, regs); + break; + case MMC_POWER_ON: if (!IS_ERR(mmc->supply.vqmmc) && !slot->host->vqmmc_enabled) { ret = regulator_enable(mmc->supply.vqmmc); if (ret < 0) @@ -1117,10 +1133,6 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) else slot->host->vqmmc_enabled = true; } - set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); - regs = mci_readl(slot->host, PWREN); - regs |= (1 << slot->id); - mci_writel(slot->host, PWREN, regs); break; case MMC_POWER_OFF: if (!IS_ERR(mmc->supply.vmmc)) @@ -1245,27 +1257,37 @@ static int dw_mci_get_cd(struct mmc_host *mmc) return present; } -/* - * Disable lower power mode. - * - * Low power mode will stop the card clock when idle. According to the - * description of the CLKENA register we should disable low power mode - * for SDIO cards if we need SDIO interrupts to work. - * - * This function is fast if low power mode is already disabled. - */ -static void dw_mci_disable_low_power(struct dw_mci_slot *slot) +static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) { + struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci *host = slot->host; - u32 clk_en_a; - const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; - clk_en_a = mci_readl(host, CLKENA); + /* + * Low power mode will stop the card clock when idle. According to the + * description of the CLKENA register we should disable low power mode + * for SDIO cards if we need SDIO interrupts to work. + */ + if (mmc->caps & MMC_CAP_SDIO_IRQ) { + const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; + u32 clk_en_a_old; + u32 clk_en_a; - if (clk_en_a & clken_low_pwr) { - mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr); - mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | - SDMMC_CMD_PRV_DAT_WAIT, 0); + clk_en_a_old = mci_readl(host, CLKENA); + + if (card->type == MMC_TYPE_SDIO || + card->type == MMC_TYPE_SD_COMBO) { + set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); + clk_en_a = clk_en_a_old & ~clken_low_pwr; + } else { + clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); + clk_en_a = clk_en_a_old | clken_low_pwr; + } + + if (clk_en_a != clk_en_a_old) { + mci_writel(host, CLKENA, clk_en_a); + mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | + SDMMC_CMD_PRV_DAT_WAIT, 0); + } } } @@ -1273,25 +1295,20 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) { struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci *host = slot->host; + unsigned long irqflags; u32 int_mask; + spin_lock_irqsave(&host->irq_lock, irqflags); + /* Enable/disable Slot Specific SDIO interrupt */ int_mask = mci_readl(host, INTMASK); - if (enb) { - /* - * Turn off low power mode if it was enabled. This is a bit of - * a heavy operation and we disable / enable IRQs a lot, so - * we'll leave low power mode disabled and it will get - * re-enabled again in dw_mci_setup_bus(). - */ - dw_mci_disable_low_power(slot); + if (enb) + int_mask |= SDMMC_INT_SDIO(slot->sdio_id); + else + int_mask &= ~SDMMC_INT_SDIO(slot->sdio_id); + mci_writel(host, INTMASK, int_mask); - mci_writel(host, INTMASK, - (int_mask | SDMMC_INT_SDIO(slot->sdio_id))); - } else { - mci_writel(host, INTMASK, - (int_mask & ~SDMMC_INT_SDIO(slot->sdio_id))); - } + spin_unlock_irqrestore(&host->irq_lock, irqflags); } static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) @@ -1299,30 +1316,10 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci *host = slot->host; const struct dw_mci_drv_data *drv_data = host->drv_data; - struct dw_mci_tuning_data tuning_data; int err = -ENOSYS; - if (opcode == MMC_SEND_TUNING_BLOCK_HS200) { - if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) { - tuning_data.blk_pattern = tuning_blk_pattern_8bit; - tuning_data.blksz = sizeof(tuning_blk_pattern_8bit); - } else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) { - tuning_data.blk_pattern = tuning_blk_pattern_4bit; - tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); - } else { - return -EINVAL; - } - } else if (opcode == MMC_SEND_TUNING_BLOCK) { - tuning_data.blk_pattern = tuning_blk_pattern_4bit; - tuning_data.blksz = sizeof(tuning_blk_pattern_4bit); - } else { - dev_err(host->dev, - "Undefined command(%d) for tuning\n", opcode); - return -EINVAL; - } - if (drv_data && drv_data->execute_tuning) - err = drv_data->execute_tuning(slot, opcode, &tuning_data); + err = drv_data->execute_tuning(slot); return err; } @@ -1337,7 +1334,7 @@ static const struct mmc_host_ops dw_mci_ops = { .execute_tuning = dw_mci_execute_tuning, .card_busy = dw_mci_card_busy, .start_signal_voltage_switch = dw_mci_switch_voltage, - + .init_card = dw_mci_init_card, }; static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) @@ -2319,9 +2316,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) #ifdef CONFIG_MMC_DW_IDMAC mmc->max_segs = host->ring_size; mmc->max_blk_size = 65536; - mmc->max_blk_count = host->ring_size; mmc->max_seg_size = 0x1000; - mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count; + mmc->max_req_size = mmc->max_seg_size * host->ring_size; + mmc->max_blk_count = mmc->max_req_size / 512; #else mmc->max_segs = 64; mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */ @@ -2533,10 +2530,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) u32 clock_frequency; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(dev, "could not allocate memory for pdata\n"); + if (!pdata) return ERR_PTR(-ENOMEM); - } /* find out number of slots supported */ if (of_property_read_u32(dev->of_node, "num-slots", @@ -2660,6 +2655,7 @@ int dw_mci_probe(struct dw_mci *host) host->quirks = host->pdata->quirks; spin_lock_init(&host->lock); + spin_lock_init(&host->irq_lock); INIT_LIST_HEAD(&host->queue); /* diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 0d0f7a271d63..18c4afe683b8 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -244,15 +244,11 @@ struct dw_mci_slot { unsigned long flags; #define DW_MMC_CARD_PRESENT 0 #define DW_MMC_CARD_NEED_INIT 1 +#define DW_MMC_CARD_NO_LOW_PWR 2 int id; int sdio_id; }; -struct dw_mci_tuning_data { - const u8 *blk_pattern; - unsigned int blksz; -}; - /** * dw_mci driver data - dw-mshc implementation specific driver data. * @caps: mmc subsystem specified capabilities of the controller(s). @@ -274,7 +270,6 @@ struct dw_mci_drv_data { void (*prepare_command)(struct dw_mci *host, u32 *cmdr); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); int (*parse_dt)(struct dw_mci *host); - int (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode, - struct dw_mci_tuning_data *tuning_data); + int (*execute_tuning)(struct dw_mci_slot *slot); }; #endif /* _DW_MMC_H_ */ diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 8232e9a02d40..7fe16194ebc8 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -430,7 +430,6 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) static void mmci_dma_setup(struct mmci_host *host) { const char *rxname, *txname; - dma_cap_mask_t mask; struct variant_data *variant = host->variant; host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx"); @@ -439,10 +438,6 @@ static void mmci_dma_setup(struct mmci_host *host) /* initialize pre request cookie */ host->next_data.cookie = 1; - /* Try to acquire a generic DMA engine slave channel */ - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - /* * If only an RX channel is specified, the driver will * attempt to use it bidirectionally, however if it is @@ -1739,10 +1734,10 @@ static int mmci_probe(struct amba_device *dev, pm_runtime_set_autosuspend_delay(&dev->dev, 50); pm_runtime_use_autosuspend(&dev->dev); - pm_runtime_put(&dev->dev); mmc_add_host(mmc); + pm_runtime_put(&dev->dev); return 0; clk_disable: diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index f3e18d08e852..006f1862444b 100644 --- a/drivers/mmc/host/moxart-mmc.c +++ b/drivers/mmc/host/moxart-mmc.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -562,7 +563,6 @@ static int moxart_probe(struct platform_device *pdev) struct dma_slave_config cfg; struct clk *clk; void __iomem *reg_mmc; - dma_cap_mask_t mask; int irq, ret; u32 i; @@ -586,9 +586,8 @@ static int moxart_probe(struct platform_device *pdev) goto out; } - clk = of_clk_get(node, 0); + clk = devm_clk_get(dev, NULL); if (IS_ERR(clk)) { - dev_err(dev, "of_clk_get failed\n"); ret = PTR_ERR(clk); goto out; } @@ -599,10 +598,9 @@ static int moxart_probe(struct platform_device *pdev) goto out; } - mmc_of_parse(mmc); - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + ret = mmc_of_parse(mmc); + if (ret) + goto out; host = mmc_priv(mmc); host->mmc = mmc; @@ -611,8 +609,8 @@ static int moxart_probe(struct platform_device *pdev) host->timeout = msecs_to_jiffies(1000); host->sysclk = clk_get_rate(clk); host->fifo_width = readl(host->base + REG_FEATURE) << 2; - host->dma_chan_tx = of_dma_request_slave_channel(node, "tx"); - host->dma_chan_rx = of_dma_request_slave_channel(node, "rx"); + host->dma_chan_tx = dma_request_slave_channel_reason(dev, "tx"); + host->dma_chan_rx = dma_request_slave_channel_reason(dev, "rx"); spin_lock_init(&host->lock); @@ -622,6 +620,11 @@ static int moxart_probe(struct platform_device *pdev) mmc->ocr_avail = 0xffff00; /* Support 2.0v - 3.6v power. */ if (IS_ERR(host->dma_chan_tx) || IS_ERR(host->dma_chan_rx)) { + if (PTR_ERR(host->dma_chan_tx) == -EPROBE_DEFER || + PTR_ERR(host->dma_chan_rx) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto out; + } dev_dbg(dev, "PIO mode transfer enabled\n"); host->have_dma = false; } else { @@ -700,9 +703,6 @@ static int moxart_remove(struct platform_device *pdev) writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF, host->base + REG_CLOCK_CONTROL); } - - kfree(host); - return 0; } diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 4f8618f4522d..a448498e3af2 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -704,7 +703,6 @@ static int mvsd_probe(struct platform_device *pdev) const struct mbus_dram_target_info *dram; struct resource *r; int ret, irq; - struct pinctrl *pinctrl; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); @@ -721,10 +719,6 @@ static int mvsd_probe(struct platform_device *pdev) host->mmc = mmc; host->dev = &pdev->dev; - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) - dev_warn(&pdev->dev, "no pins associated\n"); - /* * Some non-DT platforms do not pass a clock, and the clock * frequency is passed through platform_data. On DT platforms, @@ -828,8 +822,6 @@ static int mvsd_probe(struct platform_device *pdev) out: if (mmc) { - mmc_gpio_free_cd(mmc); - mmc_gpio_free_ro(mmc); if (!IS_ERR(host->clk)) clk_disable_unprepare(host->clk); mmc_free_host(mmc); @@ -844,8 +836,6 @@ static int mvsd_remove(struct platform_device *pdev) struct mvsd_host *host = mmc_priv(mmc); - mmc_gpio_free_cd(mmc); - mmc_gpio_free_ro(mmc); mmc_remove_host(mmc); del_timer_sync(&host->timer); mvsd_power_down(host); diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 60c4ca97a727..a82411a2c024 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -677,8 +677,7 @@ static int mxs_mmc_probe(struct platform_device *pdev) return 0; out_free_dma: - if (ssp->dmach) - dma_release_channel(ssp->dmach); + dma_release_channel(ssp->dmach); out_clk_disable: clk_disable_unprepare(ssp->clk); out_mmc_free: diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 7c71dcdcba8b..f84cfb01716d 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -251,55 +252,24 @@ static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host); static int omap_hsmmc_card_detect(struct device *dev) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_hsmmc_platform_data *mmc = host->pdata; - /* NOTE: assumes card detect signal is active-low */ - return !gpio_get_value_cansleep(mmc->switch_pin); + return mmc_gpio_get_cd(host->mmc); } static int omap_hsmmc_get_wp(struct device *dev) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_hsmmc_platform_data *mmc = host->pdata; - /* NOTE: assumes write protect signal is active-high */ - return gpio_get_value_cansleep(mmc->gpio_wp); + return mmc_gpio_get_ro(host->mmc); } static int omap_hsmmc_get_cover_state(struct device *dev) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_hsmmc_platform_data *mmc = host->pdata; - /* NOTE: assumes card detect signal is active-low */ - return !gpio_get_value_cansleep(mmc->switch_pin); + return mmc_gpio_get_cd(host->mmc); } -#ifdef CONFIG_PM - -static int omap_hsmmc_suspend_cdirq(struct device *dev) -{ - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - - disable_irq(host->card_detect_irq); - return 0; -} - -static int omap_hsmmc_resume_cdirq(struct device *dev) -{ - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - - enable_irq(host->card_detect_irq); - return 0; -} - -#else - -#define omap_hsmmc_suspend_cdirq NULL -#define omap_hsmmc_resume_cdirq NULL - -#endif - #ifdef CONFIG_REGULATOR static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) @@ -464,7 +434,10 @@ static inline int omap_hsmmc_have_reg(void) #endif -static int omap_hsmmc_gpio_init(struct omap_hsmmc_host *host, +static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id); + +static int omap_hsmmc_gpio_init(struct mmc_host *mmc, + struct omap_hsmmc_host *host, struct omap_hsmmc_platform_data *pdata) { int ret; @@ -477,46 +450,24 @@ static int omap_hsmmc_gpio_init(struct omap_hsmmc_host *host, host->card_detect = omap_hsmmc_card_detect; host->card_detect_irq = gpio_to_irq(pdata->switch_pin); - ret = gpio_request(pdata->switch_pin, "mmc_cd"); + mmc_gpio_set_cd_isr(mmc, omap_hsmmc_detect); + ret = mmc_gpio_request_cd(mmc, pdata->switch_pin, 0); if (ret) return ret; - ret = gpio_direction_input(pdata->switch_pin); - if (ret) - goto err_free_sp; } else { pdata->switch_pin = -EINVAL; } if (gpio_is_valid(pdata->gpio_wp)) { host->get_ro = omap_hsmmc_get_wp; - ret = gpio_request(pdata->gpio_wp, "mmc_wp"); + ret = mmc_gpio_request_ro(mmc, pdata->gpio_wp); if (ret) - goto err_free_cd; - ret = gpio_direction_input(pdata->gpio_wp); - if (ret) - goto err_free_wp; + return ret; } else { pdata->gpio_wp = -EINVAL; } return 0; - -err_free_wp: - gpio_free(pdata->gpio_wp); -err_free_cd: - if (gpio_is_valid(pdata->switch_pin)) -err_free_sp: - gpio_free(pdata->switch_pin); - return ret; -} - -static void omap_hsmmc_gpio_free(struct omap_hsmmc_host *host, - struct omap_hsmmc_platform_data *pdata) -{ - if (gpio_is_valid(pdata->gpio_wp)) - gpio_free(pdata->gpio_wp); - if (gpio_is_valid(pdata->switch_pin)) - gpio_free(pdata->switch_pin); } /* @@ -1978,13 +1929,6 @@ static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev) { struct omap_hsmmc_platform_data *pdata; struct device_node *np = dev->of_node; - u32 bus_width, max_freq; - int cd_gpio, wp_gpio; - - cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); - wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); - if (cd_gpio == -EPROBE_DEFER || wp_gpio == -EPROBE_DEFER) - return ERR_PTR(-EPROBE_DEFER); pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -1993,34 +1937,20 @@ static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev) if (of_find_property(np, "ti,dual-volt", NULL)) pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT; - pdata->switch_pin = cd_gpio; - pdata->gpio_wp = wp_gpio; + pdata->switch_pin = -EINVAL; + pdata->gpio_wp = -EINVAL; if (of_find_property(np, "ti,non-removable", NULL)) { pdata->nonremovable = true; pdata->no_regulator_off_init = true; } - of_property_read_u32(np, "bus-width", &bus_width); - if (bus_width == 4) - pdata->caps |= MMC_CAP_4_BIT_DATA; - else if (bus_width == 8) - pdata->caps |= MMC_CAP_8_BIT_DATA; if (of_find_property(np, "ti,needs-special-reset", NULL)) pdata->features |= HSMMC_HAS_UPDATED_RESET; - if (!of_property_read_u32(np, "max-frequency", &max_freq)) - pdata->max_freq = max_freq; - if (of_find_property(np, "ti,needs-special-hs-handling", NULL)) pdata->features |= HSMMC_HAS_HSPE_SUPPORT; - if (of_find_property(np, "keep-power-in-suspend", NULL)) - pdata->pm_caps |= MMC_PM_KEEP_POWER; - - if (of_find_property(np, "enable-sdio-wakeup", NULL)) - pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; - return pdata; } #else @@ -2078,6 +2008,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev) goto err; } + ret = mmc_of_parse(mmc); + if (ret) + goto err1; + host = mmc_priv(mmc); host->mmc = mmc; host->pdata = pdata; @@ -2091,7 +2025,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) host->next_data.cookie = 1; host->pbias_enabled = 0; - ret = omap_hsmmc_gpio_init(host, pdata); + ret = omap_hsmmc_gpio_init(mmc, host, pdata); if (ret) goto err_gpio; @@ -2106,7 +2040,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (pdata->max_freq > 0) mmc->f_max = pdata->max_freq; - else + else if (mmc->f_max == 0) mmc->f_max = OMAP_MMC_MAX_CLOCK; spin_lock_init(&host->irq_lock); @@ -2160,7 +2094,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (mmc_pdata(host)->nonremovable) mmc->caps |= MMC_CAP_NONREMOVABLE; - mmc->pm_caps = mmc_pdata(host)->pm_caps; + mmc->pm_caps |= mmc_pdata(host)->pm_caps; omap_hsmmc_conf_bus_power(host); @@ -2222,22 +2156,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) mmc->ocr_avail = mmc_pdata(host)->ocr_mask; - /* Request IRQ for card detect */ - if (host->card_detect_irq) { - ret = devm_request_threaded_irq(&pdev->dev, - host->card_detect_irq, - NULL, omap_hsmmc_detect, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - mmc_hostname(mmc), host); - if (ret) { - dev_err(mmc_dev(host->mmc), - "Unable to grab MMC CD IRQ\n"); - goto err_irq_cd; - } - host->suspend = omap_hsmmc_suspend_cdirq; - host->resume = omap_hsmmc_resume_cdirq; - } - omap_hsmmc_disable_irq(host); /* @@ -2276,7 +2194,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) err_slot_name: mmc_remove_host(mmc); -err_irq_cd: if (host->use_reg) omap_hsmmc_reg_put(host); err_irq: @@ -2289,7 +2206,6 @@ err_irq: if (host->dbclk) clk_disable_unprepare(host->dbclk); err1: - omap_hsmmc_gpio_free(host, pdata); err_gpio: mmc_free_host(mmc); err: @@ -2315,32 +2231,12 @@ static int omap_hsmmc_remove(struct platform_device *pdev) if (host->dbclk) clk_disable_unprepare(host->dbclk); - omap_hsmmc_gpio_free(host, host->pdata); mmc_free_host(host->mmc); return 0; } #ifdef CONFIG_PM -static int omap_hsmmc_prepare(struct device *dev) -{ - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - - if (host->suspend) - return host->suspend(dev); - - return 0; -} - -static void omap_hsmmc_complete(struct device *dev) -{ - struct omap_hsmmc_host *host = dev_get_drvdata(dev); - - if (host->resume) - host->resume(dev); - -} - static int omap_hsmmc_suspend(struct device *dev) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); @@ -2398,8 +2294,6 @@ static int omap_hsmmc_resume(struct device *dev) } #else -#define omap_hsmmc_prepare NULL -#define omap_hsmmc_complete NULL #define omap_hsmmc_suspend NULL #define omap_hsmmc_resume NULL #endif @@ -2484,8 +2378,6 @@ static int omap_hsmmc_runtime_resume(struct device *dev) static struct dev_pm_ops omap_hsmmc_dev_pm_ops = { .suspend = omap_hsmmc_suspend, .resume = omap_hsmmc_resume, - .prepare = omap_hsmmc_prepare, - .complete = omap_hsmmc_complete, .runtime_suspend = omap_hsmmc_runtime_suspend, .runtime_resume = omap_hsmmc_runtime_resume, }; diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index c70b602f8f1e..1d3d6c4bfdc6 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -53,9 +54,9 @@ struct realtek_pci_sdmmc { #define SDMMC_POWER_ON 1 #define SDMMC_POWER_OFF 0 - unsigned int sg_count; + int sg_count; s32 cookie; - unsigned int cookie_sg_count; + int cookie_sg_count; bool using_cookie; }; @@ -71,30 +72,83 @@ static inline void sd_clear_error(struct realtek_pci_sdmmc *host) } #ifdef DEBUG +static void dump_reg_range(struct realtek_pci_sdmmc *host, u16 start, u16 end) +{ + u16 len = end - start + 1; + int i; + u8 data[8]; + + for (i = 0; i < len; i += 8) { + int j; + int n = min(8, len - i); + + memset(&data, 0, sizeof(data)); + for (j = 0; j < n; j++) + rtsx_pci_read_register(host->pcr, start + i + j, + data + j); + dev_dbg(sdmmc_dev(host), "0x%04X(%d): %8ph\n", + start + i, n, data); + } +} + static void sd_print_debug_regs(struct realtek_pci_sdmmc *host) { - struct rtsx_pcr *pcr = host->pcr; - u16 i; - u8 *ptr; - - /* Print SD host internal registers */ - rtsx_pci_init_cmd(pcr); - for (i = 0xFDA0; i <= 0xFDAE; i++) - rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); - for (i = 0xFD52; i <= 0xFD69; i++) - rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); - rtsx_pci_send_cmd(pcr, 100); - - ptr = rtsx_pci_get_cmd_data(pcr); - for (i = 0xFDA0; i <= 0xFDAE; i++) - dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); - for (i = 0xFD52; i <= 0xFD69; i++) - dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); + dump_reg_range(host, 0xFDA0, 0xFDB3); + dump_reg_range(host, 0xFD52, 0xFD69); } #else #define sd_print_debug_regs(host) #endif /* DEBUG */ +static inline int sd_get_cd_int(struct realtek_pci_sdmmc *host) +{ + return rtsx_pci_readl(host->pcr, RTSX_BIPR) & SD_EXIST; +} + +static void sd_cmd_set_sd_cmd(struct rtsx_pcr *pcr, struct mmc_command *cmd) +{ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0, 0xFF, + SD_CMD_START | cmd->opcode); + rtsx_pci_write_be32(pcr, SD_CMD1, cmd->arg); +} + +static void sd_cmd_set_data_len(struct rtsx_pcr *pcr, u16 blocks, u16 blksz) +{ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, blocks); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, blocks >> 8); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, blksz); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, blksz >> 8); +} + +static int sd_response_type(struct mmc_command *cmd) +{ + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + return SD_RSP_TYPE_R0; + case MMC_RSP_R1: + return SD_RSP_TYPE_R1; + case MMC_RSP_R1 & ~MMC_RSP_CRC: + return SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7; + case MMC_RSP_R1B: + return SD_RSP_TYPE_R1b; + case MMC_RSP_R2: + return SD_RSP_TYPE_R2; + case MMC_RSP_R3: + return SD_RSP_TYPE_R3; + default: + return -EINVAL; + } +} + +static int sd_status_index(int resp_type) +{ + if (resp_type == SD_RSP_TYPE_R0) + return 0; + else if (resp_type == SD_RSP_TYPE_R2) + return 16; + + return 5; +} /* * sd_pre_dma_transfer - do dma_map_sg() or using cookie * @@ -166,123 +220,6 @@ static void sdmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, data->host_cookie = 0; } -static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, - u8 *buf, int buf_len, int timeout) -{ - struct rtsx_pcr *pcr = host->pcr; - int err, i; - u8 trans_mode; - - dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__, cmd[0] - 0x40); - - if (!buf) - buf_len = 0; - - if ((cmd[0] & 0x3F) == MMC_SEND_TUNING_BLOCK) - trans_mode = SD_TM_AUTO_TUNING; - else - trans_mode = SD_TM_NORMAL_READ; - - rtsx_pci_init_cmd(pcr); - - for (i = 0; i < 5; i++) - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0 + i, 0xFF, cmd[i]); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, - 0xFF, (u8)(byte_cnt >> 8)); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, - SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | - SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); - if (trans_mode != SD_TM_AUTO_TUNING) - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, - 0xFF, trans_mode | SD_TRANSFER_START); - rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, - SD_TRANSFER_END, SD_TRANSFER_END); - - err = rtsx_pci_send_cmd(pcr, timeout); - if (err < 0) { - sd_print_debug_regs(host); - dev_dbg(sdmmc_dev(host), - "rtsx_pci_send_cmd fail (err = %d)\n", err); - return err; - } - - if (buf && buf_len) { - err = rtsx_pci_read_ppbuf(pcr, buf, buf_len); - if (err < 0) { - dev_dbg(sdmmc_dev(host), - "rtsx_pci_read_ppbuf fail (err = %d)\n", err); - return err; - } - } - - return 0; -} - -static int sd_write_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, - u8 *buf, int buf_len, int timeout) -{ - struct rtsx_pcr *pcr = host->pcr; - int err, i; - u8 trans_mode; - - if (!buf) - buf_len = 0; - - if (buf && buf_len) { - err = rtsx_pci_write_ppbuf(pcr, buf, buf_len); - if (err < 0) { - dev_dbg(sdmmc_dev(host), - "rtsx_pci_write_ppbuf fail (err = %d)\n", err); - return err; - } - } - - trans_mode = cmd ? SD_TM_AUTO_WRITE_2 : SD_TM_AUTO_WRITE_3; - rtsx_pci_init_cmd(pcr); - - if (cmd) { - dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d\n", __func__, - cmd[0] - 0x40); - - for (i = 0; i < 5; i++) - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD_CMD0 + i, 0xFF, cmd[i]); - } - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, - 0xFF, (u8)(byte_cnt >> 8)); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, - SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | - SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, - trans_mode | SD_TRANSFER_START); - rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, - SD_TRANSFER_END, SD_TRANSFER_END); - - err = rtsx_pci_send_cmd(pcr, timeout); - if (err < 0) { - sd_print_debug_regs(host); - dev_dbg(sdmmc_dev(host), - "rtsx_pci_send_cmd fail (err = %d)\n", err); - return err; - } - - return 0; -} - static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, struct mmc_command *cmd) { @@ -293,47 +230,18 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, int timeout = 100; int i; u8 *ptr; - int stat_idx = 0; - u8 rsp_type; - int rsp_len = 5; + int rsp_type; + int stat_idx; bool clock_toggled = false; dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", __func__, cmd_idx, arg); - /* Response type: - * R0 - * R1, R5, R6, R7 - * R1b - * R2 - * R3, R4 - */ - switch (mmc_resp_type(cmd)) { - case MMC_RSP_NONE: - rsp_type = SD_RSP_TYPE_R0; - rsp_len = 0; - break; - case MMC_RSP_R1: - rsp_type = SD_RSP_TYPE_R1; - break; - case MMC_RSP_R1 & ~MMC_RSP_CRC: - rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7; - break; - case MMC_RSP_R1B: - rsp_type = SD_RSP_TYPE_R1b; - break; - case MMC_RSP_R2: - rsp_type = SD_RSP_TYPE_R2; - rsp_len = 16; - break; - case MMC_RSP_R3: - rsp_type = SD_RSP_TYPE_R3; - break; - default: - dev_dbg(sdmmc_dev(host), "cmd->flag is not valid\n"); - err = -EINVAL; + rsp_type = sd_response_type(cmd); + if (rsp_type < 0) goto out; - } + + stat_idx = sd_status_index(rsp_type); if (rsp_type == SD_RSP_TYPE_R1b) timeout = 3000; @@ -348,13 +256,7 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, } rtsx_pci_init_cmd(pcr); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24)); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16)); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8)); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg); - + sd_cmd_set_sd_cmd(pcr, cmd); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); @@ -368,12 +270,10 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, /* Read data from ping-pong buffer */ for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++) rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); - stat_idx = 16; } else if (rsp_type != SD_RSP_TYPE_R0) { /* Read data from SD_CMDx registers */ for (i = SD_CMD0; i <= SD_CMD4; i++) rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); - stat_idx = 5; } rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0); @@ -438,71 +338,213 @@ out: SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); } -static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) +static int sd_read_data(struct realtek_pci_sdmmc *host, struct mmc_command *cmd, + u16 byte_cnt, u8 *buf, int buf_len, int timeout) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + u8 trans_mode; + + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", + __func__, cmd->opcode, cmd->arg); + + if (!buf) + buf_len = 0; + + if (cmd->opcode == MMC_SEND_TUNING_BLOCK) + trans_mode = SD_TM_AUTO_TUNING; + else + trans_mode = SD_TM_NORMAL_READ; + + rtsx_pci_init_cmd(pcr); + sd_cmd_set_sd_cmd(pcr, cmd); + sd_cmd_set_data_len(pcr, 1, byte_cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, + SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); + if (trans_mode != SD_TM_AUTO_TUNING) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, + 0xFF, trans_mode | SD_TRANSFER_START); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + + err = rtsx_pci_send_cmd(pcr, timeout); + if (err < 0) { + sd_print_debug_regs(host); + dev_dbg(sdmmc_dev(host), + "rtsx_pci_send_cmd fail (err = %d)\n", err); + return err; + } + + if (buf && buf_len) { + err = rtsx_pci_read_ppbuf(pcr, buf, buf_len); + if (err < 0) { + dev_dbg(sdmmc_dev(host), + "rtsx_pci_read_ppbuf fail (err = %d)\n", err); + return err; + } + } + + return 0; +} + +static int sd_write_data(struct realtek_pci_sdmmc *host, + struct mmc_command *cmd, u16 byte_cnt, u8 *buf, int buf_len, + int timeout) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", + __func__, cmd->opcode, cmd->arg); + + if (!buf) + buf_len = 0; + + sd_send_cmd_get_rsp(host, cmd); + if (cmd->error) + return cmd->error; + + if (buf && buf_len) { + err = rtsx_pci_write_ppbuf(pcr, buf, buf_len); + if (err < 0) { + dev_dbg(sdmmc_dev(host), + "rtsx_pci_write_ppbuf fail (err = %d)\n", err); + return err; + } + } + + rtsx_pci_init_cmd(pcr); + sd_cmd_set_data_len(pcr, 1, byte_cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, + SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, + SD_TRANSFER_START | SD_TM_AUTO_WRITE_3); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + + err = rtsx_pci_send_cmd(pcr, timeout); + if (err < 0) { + sd_print_debug_regs(host); + dev_dbg(sdmmc_dev(host), + "rtsx_pci_send_cmd fail (err = %d)\n", err); + return err; + } + + return 0; +} + +static int sd_read_long_data(struct realtek_pci_sdmmc *host, + struct mmc_request *mrq) { struct rtsx_pcr *pcr = host->pcr; struct mmc_host *mmc = host->mmc; struct mmc_card *card = mmc->card; + struct mmc_command *cmd = mrq->cmd; struct mmc_data *data = mrq->data; int uhs = mmc_card_uhs(card); - int read = (data->flags & MMC_DATA_READ) ? 1 : 0; - u8 cfg2, trans_mode; + u8 cfg2 = 0; int err; + int resp_type; size_t data_len = data->blksz * data->blocks; - if (read) { - cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | - SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0; - trans_mode = SD_TM_AUTO_READ_3; - } else { - cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | - SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0; - trans_mode = SD_TM_AUTO_WRITE_3; - } + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", + __func__, cmd->opcode, cmd->arg); + + resp_type = sd_response_type(cmd); + if (resp_type < 0) + return resp_type; if (!uhs) cfg2 |= SD_NO_CHECK_WAIT_CRC_TO; rtsx_pci_init_cmd(pcr); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, - 0xFF, (u8)data->blocks); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, - 0xFF, (u8)(data->blocks >> 8)); - + sd_cmd_set_sd_cmd(pcr, cmd); + sd_cmd_set_data_len(pcr, data->blocks, data->blksz); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, DMA_DONE_INT, DMA_DONE_INT); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC3, - 0xFF, (u8)(data_len >> 24)); + 0xFF, (u8)(data_len >> 24)); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC2, - 0xFF, (u8)(data_len >> 16)); + 0xFF, (u8)(data_len >> 16)); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC1, - 0xFF, (u8)(data_len >> 8)); + 0xFF, (u8)(data_len >> 8)); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC0, 0xFF, (u8)data_len); - if (read) { - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, - 0x03 | DMA_PACK_SIZE_MASK, - DMA_DIR_FROM_CARD | DMA_EN | DMA_512); - } else { - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, - 0x03 | DMA_PACK_SIZE_MASK, - DMA_DIR_TO_CARD | DMA_EN | DMA_512); - } - + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, + 0x03 | DMA_PACK_SIZE_MASK, + DMA_DIR_FROM_CARD | DMA_EN | DMA_512); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, cfg2); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, cfg2 | resp_type); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, - trans_mode | SD_TRANSFER_START); + SD_TRANSFER_START | SD_TM_AUTO_READ_2); rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, SD_TRANSFER_END, SD_TRANSFER_END); - rtsx_pci_send_cmd_no_wait(pcr); - err = rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, read, 10000); + err = rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, 1, 10000); + if (err < 0) { + sd_print_debug_regs(host); + sd_clear_error(host); + return err; + } + + return 0; +} + +static int sd_write_long_data(struct realtek_pci_sdmmc *host, + struct mmc_request *mrq) +{ + struct rtsx_pcr *pcr = host->pcr; + struct mmc_host *mmc = host->mmc; + struct mmc_card *card = mmc->card; + struct mmc_command *cmd = mrq->cmd; + struct mmc_data *data = mrq->data; + int uhs = mmc_card_uhs(card); + u8 cfg2; + int err; + size_t data_len = data->blksz * data->blocks; + + sd_send_cmd_get_rsp(host, cmd); + if (cmd->error) + return cmd->error; + + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", + __func__, cmd->opcode, cmd->arg); + + cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0; + + if (!uhs) + cfg2 |= SD_NO_CHECK_WAIT_CRC_TO; + + rtsx_pci_init_cmd(pcr); + sd_cmd_set_data_len(pcr, data->blocks, data->blksz); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, + DMA_DONE_INT, DMA_DONE_INT); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC3, + 0xFF, (u8)(data_len >> 24)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC2, + 0xFF, (u8)(data_len >> 16)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC1, + 0xFF, (u8)(data_len >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC0, 0xFF, (u8)data_len); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, + 0x03 | DMA_PACK_SIZE_MASK, + DMA_DIR_TO_CARD | DMA_EN | DMA_512); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, RING_BUFFER); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, cfg2); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, + SD_TRANSFER_START | SD_TM_AUTO_WRITE_3); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + rtsx_pci_send_cmd_no_wait(pcr); + err = rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, 0, 10000); if (err < 0) { sd_clear_error(host); return err; @@ -511,6 +553,23 @@ static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) return 0; } +static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) +{ + struct mmc_data *data = mrq->data; + + if (host->sg_count < 0) { + data->error = host->sg_count; + dev_dbg(sdmmc_dev(host), "%s: sg_count = %d is invalid\n", + __func__, host->sg_count); + return data->error; + } + + if (data->flags & MMC_DATA_READ) + return sd_read_long_data(host, mrq); + + return sd_write_long_data(host, mrq); +} + static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host) { rtsx_pci_write_register(host->pcr, SD_CFG1, @@ -528,10 +587,7 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host, { struct mmc_command *cmd = mrq->cmd; struct mmc_data *data = mrq->data; - u8 _cmd[5], *buf; - - _cmd[0] = 0x40 | (u8)cmd->opcode; - put_unaligned_be32(cmd->arg, (u32 *)(&_cmd[1])); + u8 *buf; buf = kzalloc(data->blksz, GFP_NOIO); if (!buf) { @@ -543,7 +599,7 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host, if (host->initial_mode) sd_disable_initial_mode(host); - cmd->error = sd_read_data(host, _cmd, (u16)data->blksz, buf, + cmd->error = sd_read_data(host, cmd, (u16)data->blksz, buf, data->blksz, 200); if (host->initial_mode) @@ -553,7 +609,7 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host, } else { sg_copy_to_buffer(data->sg, data->sg_len, buf, data->blksz); - cmd->error = sd_write_data(host, _cmd, (u16)data->blksz, buf, + cmd->error = sd_write_data(host, cmd, (u16)data->blksz, buf, data->blksz, 200); } @@ -653,14 +709,14 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host, u8 opcode, u8 sample_point) { int err; - u8 cmd[5] = {0}; + struct mmc_command cmd = {0}; err = sd_change_phase(host, sample_point, true); if (err < 0) return err; - cmd[0] = 0x40 | opcode; - err = sd_read_data(host, cmd, 0x40, NULL, 0, 100); + cmd.opcode = opcode; + err = sd_read_data(host, &cmd, 0x40, NULL, 0, 100); if (err < 0) { /* Wait till SD DATA IDLE */ sd_wait_data_idle(host); @@ -727,6 +783,12 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode) return 0; } +static inline int sdio_extblock_cmd(struct mmc_command *cmd, + struct mmc_data *data) +{ + return (cmd->opcode == SD_IO_RW_EXTENDED) && (data->blksz == 512); +} + static inline int sd_rw_cmd(struct mmc_command *cmd) { return mmc_op_multi(cmd->opcode) || @@ -748,7 +810,7 @@ static void sd_request(struct work_struct *work) unsigned int data_size = 0; int err; - if (host->eject) { + if (host->eject || !sd_get_cd_int(host)) { cmd->error = -ENOMEDIUM; goto finish; } @@ -776,17 +838,15 @@ static void sd_request(struct work_struct *work) if (mrq->data) data_size = data->blocks * data->blksz; - if (!data_size || sd_rw_cmd(cmd)) { + if (!data_size) { sd_send_cmd_get_rsp(host, cmd); + } else if (sd_rw_cmd(cmd) || sdio_extblock_cmd(cmd, data)) { + cmd->error = sd_rw_multi(host, mrq); + if (!host->using_cookie) + sdmmc_post_req(host->mmc, host->mrq, 0); - if (!cmd->error && data_size) { - sd_rw_multi(host, mrq); - if (!host->using_cookie) - sdmmc_post_req(host->mmc, host->mrq, 0); - - if (mmc_op_multi(cmd->opcode) && mrq->stop) - sd_send_cmd_get_rsp(host, mrq->stop); - } + if (mmc_op_multi(cmd->opcode) && mrq->stop) + sd_send_cmd_get_rsp(host, mrq->stop); } else { sd_normal_rw(host, mrq); } @@ -801,8 +861,10 @@ static void sd_request(struct work_struct *work) mutex_unlock(&pcr->pcr_mutex); finish: - if (cmd->error) - dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error); + if (cmd->error) { + dev_dbg(sdmmc_dev(host), "CMD %d 0x%08x error(%d)\n", + cmd->opcode, cmd->arg, cmd->error); + } mutex_lock(&host->host_mutex); host->mrq = NULL; @@ -820,7 +882,7 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) host->mrq = mrq; mutex_unlock(&host->host_mutex); - if (sd_rw_cmd(mrq->cmd)) + if (sd_rw_cmd(mrq->cmd) || sdio_extblock_cmd(mrq->cmd, data)) host->using_cookie = sd_pre_dma_transfer(host, data, false); queue_work(host->workq, &host->work); @@ -1066,7 +1128,7 @@ static int sdmmc_get_cd(struct mmc_host *mmc) u32 val; if (host->eject) - return -ENOMEDIUM; + return cd; mutex_lock(&pcr->pcr_mutex); @@ -1317,6 +1379,7 @@ static void rtsx_pci_sdmmc_card_event(struct platform_device *pdev) { struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); + host->cookie = -1; mmc_detect_change(host->mmc, 0); } @@ -1349,6 +1412,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) host->pcr = pcr; host->mmc = mmc; host->pdev = pdev; + host->cookie = -1; host->power_state = SDMMC_POWER_OFF; INIT_WORK(&host->work, sd_request); platform_set_drvdata(pdev, host); diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 970314e0aac8..a45ed39d062c 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -158,7 +158,7 @@ static int sdhci_acpi_emmc_probe_slot(struct platform_device *pdev, host = c->host; - /* Platform specific code during emmc proble slot goes here */ + /* Platform specific code during emmc probe slot goes here */ if (hid && uid && !strcmp(hid, "80860F14") && !strcmp(uid, "1") && sdhci_readl(host, SDHCI_CAPABILITIES) == 0x446cc8b2 && @@ -179,7 +179,7 @@ static int sdhci_acpi_sdio_probe_slot(struct platform_device *pdev, host = c->host; - /* Platform specific code during emmc proble slot goes here */ + /* Platform specific code during sdio probe slot goes here */ return 0; } @@ -195,7 +195,7 @@ static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev, host = c->host; - /* Platform specific code during emmc proble slot goes here */ + /* Platform specific code during sd probe slot goes here */ return 0; } @@ -448,18 +448,13 @@ static int sdhci_acpi_runtime_resume(struct device *dev) return sdhci_runtime_resume_host(c->host); } -static int sdhci_acpi_runtime_idle(struct device *dev) -{ - return 0; -} - #endif static const struct dev_pm_ops sdhci_acpi_pm_ops = { .suspend = sdhci_acpi_suspend, .resume = sdhci_acpi_resume, SET_RUNTIME_PM_OPS(sdhci_acpi_runtime_suspend, - sdhci_acpi_runtime_resume, sdhci_acpi_runtime_idle) + sdhci_acpi_runtime_resume, NULL) }; static struct platform_driver sdhci_acpi_driver = { diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c index e7e4fbdcbfe0..34bb8f92586e 100644 --- a/drivers/mmc/host/sdhci-bcm-kona.c +++ b/drivers/mmc/host/sdhci-bcm-kona.c @@ -254,7 +254,9 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev) kona_dev = sdhci_pltfm_priv(pltfm_priv); mutex_init(&kona_dev->write_lock); - mmc_of_parse(host->mmc); + ret = mmc_of_parse(host->mmc); + if (ret) + goto err_pltfm_free; if (!host->mmc->f_max) { dev_err(&pdev->dev, "Missing max-freq for SDHCI cfg\n"); diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index af1f7c0f9545..10ef8244a239 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -1080,10 +1080,10 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) goto disable_clk; pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, 50); pm_runtime_use_autosuspend(&pdev->dev); pm_suspend_ignore_children(&pdev->dev, 1); + pm_runtime_enable(&pdev->dev); return 0; @@ -1103,16 +1103,15 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev) struct pltfm_imx_data *imx_data = pltfm_host->priv; int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); + pm_runtime_get_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + sdhci_remove_host(host, dead); - pm_runtime_dont_use_autosuspend(&pdev->dev); - pm_runtime_disable(&pdev->dev); - - if (!IS_ENABLED(CONFIG_PM)) { - clk_disable_unprepare(imx_data->clk_per); - clk_disable_unprepare(imx_data->clk_ipg); - clk_disable_unprepare(imx_data->clk_ahb); - } + clk_disable_unprepare(imx_data->clk_per); + clk_disable_unprepare(imx_data->clk_ipg); + clk_disable_unprepare(imx_data->clk_ahb); sdhci_pltfm_free(pdev); diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 8872c85c63d4..17fe02ed6672 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -276,6 +276,14 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) ESDHC_CTRL_BUSWIDTH_MASK, ctrl); } +static void esdhc_reset(struct sdhci_host *host, u8 mask) +{ + sdhci_reset(host, mask); + + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); +} + static const struct sdhci_ops sdhci_esdhc_ops = { .read_l = esdhc_readl, .read_w = esdhc_readw, @@ -290,7 +298,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = { .platform_init = esdhc_of_platform_init, .adma_workaround = esdhci_of_adma_workaround, .set_bus_width = esdhc_pltfm_set_bus_width, - .reset = sdhci_reset, + .reset = esdhc_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, }; @@ -362,13 +370,19 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) } /* call to generic mmc_of_parse to support additional capabilities */ - mmc_of_parse(host->mmc); + ret = mmc_of_parse(host->mmc); + if (ret) + goto err; + mmc_of_parse_voltage(np, &host->ocr_mask); ret = sdhci_add_host(host); if (ret) - sdhci_pltfm_free(pdev); + goto err; + return 0; + err: + sdhci_pltfm_free(pdev); return ret; } diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 4f38554ce679..29eaff78238e 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -1367,11 +1367,6 @@ static int sdhci_pci_runtime_resume(struct device *dev) return 0; } -static int sdhci_pci_runtime_idle(struct device *dev) -{ - return 0; -} - #else /* CONFIG_PM */ #define sdhci_pci_suspend NULL @@ -1383,7 +1378,7 @@ static const struct dev_pm_ops sdhci_pci_pm_ops = { .suspend = sdhci_pci_suspend, .resume = sdhci_pci_resume, SET_RUNTIME_PM_OPS(sdhci_pci_runtime_suspend, - sdhci_pci_runtime_resume, sdhci_pci_runtime_idle) + sdhci_pci_runtime_resume, NULL) }; /*****************************************************************************\ diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index ca3424e7ef71..b5103a247bc1 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -62,6 +62,7 @@ struct sdhci_pxa { struct clk *clk_core; struct clk *clk_io; u8 power_mode; + void __iomem *sdio3_conf_reg; }; /* @@ -72,6 +73,14 @@ struct sdhci_pxa { #define SDHCI_WINDOW_BASE(i) (0x84 + ((i) << 3)) #define SDHCI_MAX_WIN_NUM 8 +/* + * Fields below belong to SDIO3 Configuration Register (third register + * region for the Armada 38x flavor) + */ + +#define SDIO3_CONF_CLK_INV BIT(0) +#define SDIO3_CONF_SD_FB_CLK BIT(2) + static int mv_conf_mbus_windows(struct platform_device *pdev, const struct mbus_dram_target_info *dram) { @@ -118,6 +127,51 @@ static int mv_conf_mbus_windows(struct platform_device *pdev, return 0; } +static int armada_38x_quirks(struct platform_device *pdev, + struct sdhci_host *host) +{ + struct device_node *np = pdev->dev.of_node; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_pxa *pxa = pltfm_host->priv; + struct resource *res; + + host->quirks |= SDHCI_QUIRK_MISSING_CAPS; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "conf-sdio3"); + if (res) { + pxa->sdio3_conf_reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pxa->sdio3_conf_reg)) + return PTR_ERR(pxa->sdio3_conf_reg); + } else { + /* + * According to erratum 'FE-2946959' both SDR50 and DDR50 + * modes require specific clock adjustments in SDIO3 + * Configuration register, if the adjustment is not done, + * remove them from the capabilities. + */ + host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); + host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); + + dev_warn(&pdev->dev, "conf-sdio3 register not found: disabling SDR50 and DDR50 modes.\nConsider updating your dtb\n"); + } + + /* + * According to erratum 'ERR-7878951' Armada 38x SDHCI + * controller has different capabilities than the ones shown + * in its registers + */ + host->caps = sdhci_readl(host, SDHCI_CAPABILITIES); + if (of_property_read_bool(np, "no-1-8-v")) { + host->caps &= ~SDHCI_CAN_VDD_180; + host->mmc->caps &= ~MMC_CAP_1_8V_DDR; + } else { + host->caps &= ~SDHCI_CAN_VDD_330; + } + host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_USE_SDR50_TUNING); + + return 0; +} + static void pxav3_reset(struct sdhci_host *host, u8 mask) { struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); @@ -194,6 +248,8 @@ static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode) static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_pxa *pxa = pltfm_host->priv; u16 ctrl_2; /* @@ -223,6 +279,24 @@ static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) break; } + /* + * Update SDIO3 Configuration register according to erratum + * FE-2946959 + */ + if (pxa->sdio3_conf_reg) { + u8 reg_val = readb(pxa->sdio3_conf_reg); + + if (uhs == MMC_TIMING_UHS_SDR50 || + uhs == MMC_TIMING_UHS_DDR50) { + reg_val &= ~SDIO3_CONF_CLK_INV; + reg_val |= SDIO3_CONF_SD_FB_CLK; + } else { + reg_val |= SDIO3_CONF_CLK_INV; + reg_val &= ~SDIO3_CONF_SD_FB_CLK; + } + writeb(reg_val, pxa->sdio3_conf_reg); + } + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); dev_dbg(mmc_dev(host->mmc), "%s uhs = %d, ctrl_2 = %04X\n", @@ -268,8 +342,8 @@ static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev) if (!pdata) return NULL; - of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles); - if (clk_delay_cycles > 0) + if (!of_property_read_u32(np, "mrvl,clk-delay-cycles", + &clk_delay_cycles)) pdata->clk_delay_cycles = clk_delay_cycles; return pdata; @@ -318,15 +392,18 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) if (!IS_ERR(pxa->clk_core)) clk_prepare_enable(pxa->clk_core); + /* enable 1/8V DDR capable */ + host->mmc->caps |= MMC_CAP_1_8V_DDR; + if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) { + ret = armada_38x_quirks(pdev, host); + if (ret < 0) + goto err_clk_get; ret = mv_conf_mbus_windows(pdev, mv_mbus_dram_info()); if (ret < 0) goto err_mbus_win; } - /* enable 1/8V DDR capable */ - host->mmc->caps |= MMC_CAP_1_8V_DDR; - match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev); if (match) { ret = mmc_of_parse(host->mmc); @@ -365,10 +442,11 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) } } - pm_runtime_enable(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS); pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); pm_suspend_ignore_children(&pdev->dev, 1); ret = sdhci_add_host(host); @@ -391,14 +469,13 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) return 0; err_add_host: - pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); err_of_parse: err_cd_req: err_mbus_win: clk_disable_unprepare(pxa->clk_io); - if (!IS_ERR(pxa->clk_core)) - clk_disable_unprepare(pxa->clk_core); + clk_disable_unprepare(pxa->clk_core); err_clk_get: sdhci_pltfm_free(pdev); return ret; @@ -411,12 +488,13 @@ static int sdhci_pxav3_remove(struct platform_device *pdev) struct sdhci_pxa *pxa = pltfm_host->priv; pm_runtime_get_sync(&pdev->dev); - sdhci_remove_host(host, 1); pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + + sdhci_remove_host(host, 1); clk_disable_unprepare(pxa->clk_io); - if (!IS_ERR(pxa->clk_core)) - clk_disable_unprepare(pxa->clk_core); + clk_disable_unprepare(pxa->clk_core); sdhci_pltfm_free(pdev); @@ -457,11 +535,11 @@ static int sdhci_pxav3_runtime_suspend(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pxa *pxa = pltfm_host->priv; - unsigned long flags; + int ret; - spin_lock_irqsave(&host->lock, flags); - host->runtime_suspended = true; - spin_unlock_irqrestore(&host->lock, flags); + ret = sdhci_runtime_suspend_host(host); + if (ret) + return ret; clk_disable_unprepare(pxa->clk_io); if (!IS_ERR(pxa->clk_core)) @@ -475,17 +553,12 @@ static int sdhci_pxav3_runtime_resume(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pxa *pxa = pltfm_host->priv; - unsigned long flags; clk_prepare_enable(pxa->clk_io); if (!IS_ERR(pxa->clk_core)) clk_prepare_enable(pxa->clk_core); - spin_lock_irqsave(&host->lock, flags); - host->runtime_suspended = false; - spin_unlock_irqrestore(&host->lock, flags); - - return 0; + return sdhci_runtime_resume_host(host); } #endif diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index c45b8932d843..c6d2dd7317c1 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -12,6 +12,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -312,7 +313,14 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_s3c_set_clock(host, clock); + /* Reset SD Clock Enable */ + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + spin_unlock_irq(&host->lock); ret = clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); + spin_lock_irq(&host->lock); if (ret != 0) { dev_err(dev, "%s: failed to set clock rate %uHz\n", mmc_hostname(host->mmc), clock); @@ -607,7 +615,9 @@ static int sdhci_s3c_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(&pdev->dev); pm_suspend_ignore_children(&pdev->dev, 1); - mmc_of_parse(host->mmc); + ret = mmc_of_parse(host->mmc); + if (ret) + goto err_req_regs; ret = sdhci_add_host(host); if (ret) { diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c index dd29d47c07aa..f6f82ec3618d 100644 --- a/drivers/mmc/host/sdhci-sirf.c +++ b/drivers/mmc/host/sdhci-sirf.c @@ -15,7 +15,9 @@ #include #include "sdhci-pltfm.h" +#define SDHCI_CLK_DELAY_SETTING 0x4C #define SDHCI_SIRF_8BITBUS BIT(3) +#define SIRF_TUNING_COUNT 128 struct sdhci_sirf_priv { struct clk *clk; @@ -49,7 +51,76 @@ static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width) sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } +static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + int tuning_seq_cnt = 3; + u8 phase, tuned_phases[SIRF_TUNING_COUNT]; + u8 tuned_phase_cnt = 0; + int rc, longest_range = 0; + int start = -1, end = 0, tuning_value = -1, range = 0; + u16 clock_setting; + struct mmc_host *mmc = host->mmc; + + clock_setting = sdhci_readw(host, SDHCI_CLK_DELAY_SETTING); + clock_setting &= ~0x3fff; + +retry: + phase = 0; + do { + sdhci_writel(host, + clock_setting | phase | (phase << 7) | (phase << 16), + SDHCI_CLK_DELAY_SETTING); + + if (!mmc_send_tuning(mmc)) { + /* Tuning is successful at this tuning point */ + tuned_phases[tuned_phase_cnt++] = phase; + dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", + mmc_hostname(mmc), phase); + if (start == -1) + start = phase; + end = phase; + range++; + if (phase == (SIRF_TUNING_COUNT - 1) + && range > longest_range) + tuning_value = (start + end) / 2; + } else { + dev_dbg(mmc_dev(mmc), "%s: Found bad phase = %d\n", + mmc_hostname(mmc), phase); + if (range > longest_range) { + tuning_value = (start + end) / 2; + longest_range = range; + } + start = -1; + end = range = 0; + } + } while (++phase < ARRAY_SIZE(tuned_phases)); + + if (tuned_phase_cnt && tuning_value > 0) { + /* + * Finally set the selected phase in delay + * line hw block. + */ + phase = tuning_value; + sdhci_writel(host, + clock_setting | phase | (phase << 7) | (phase << 16), + SDHCI_CLK_DELAY_SETTING); + + dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", + mmc_hostname(mmc), phase); + } else { + if (--tuning_seq_cnt) + goto retry; + /* Tuning failed */ + dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n", + mmc_hostname(mmc)); + rc = -EIO; + } + + return rc; +} + static struct sdhci_ops sdhci_sirf_ops = { + .platform_execute_tuning = sdhci_sirf_execute_tuning, .set_clock = sdhci_set_clock, .get_max_clock = sdhci_sirf_get_max_clk, .set_bus_width = sdhci_sirf_set_bus_width, @@ -138,9 +209,6 @@ static int sdhci_sirf_remove(struct platform_device *pdev) sdhci_pltfm_unregister(pdev); - if (gpio_is_valid(priv->gpio_cd)) - mmc_gpio_free_cd(host->mmc); - clk_disable_unprepare(priv->clk); return 0; } diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c index 328f348c7243..882b07e9667e 100644 --- a/drivers/mmc/host/sdhci-st.c +++ b/drivers/mmc/host/sdhci-st.c @@ -78,10 +78,9 @@ static int sdhci_st_probe(struct platform_device *pdev) } ret = mmc_of_parse(host->mmc); - if (ret) { dev_err(&pdev->dev, "Failed mmc_of_parse\n"); - return ret; + goto err_of; } clk_prepare_enable(clk); @@ -108,6 +107,7 @@ static int sdhci_st_probe(struct platform_device *pdev) err_out: clk_disable_unprepare(clk); +err_of: sdhci_pltfm_free(pdev); return ret; diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 59797106af93..f3778d58d1cd 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -41,6 +41,7 @@ #define NVQUIRK_DISABLE_SDR50 BIT(3) #define NVQUIRK_DISABLE_SDR104 BIT(4) #define NVQUIRK_DISABLE_DDR50 BIT(5) +#define NVQUIRK_SHADOW_XFER_MODE_REG BIT(6) struct sdhci_tegra_soc_data { const struct sdhci_pltfm_data *pdata; @@ -67,6 +68,31 @@ static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) return readw(host->ioaddr + reg); } +static void tegra_sdhci_writew(struct sdhci_host *host, u16 val, int reg) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = pltfm_host->priv; + const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; + + if (soc_data->nvquirks & NVQUIRK_SHADOW_XFER_MODE_REG) { + switch (reg) { + case SDHCI_TRANSFER_MODE: + /* + * Postpone this write, we must do it together with a + * command write that is down below. + */ + pltfm_host->xfer_mode_shadow = val; + return; + case SDHCI_COMMAND: + writel((val << 16) | pltfm_host->xfer_mode_shadow, + host->ioaddr + SDHCI_TRANSFER_MODE); + return; + } + } + + writew(val, host->ioaddr + reg); +} + static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -147,6 +173,7 @@ static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width) static const struct sdhci_ops tegra_sdhci_ops = { .get_ro = tegra_sdhci_get_ro, .read_w = tegra_sdhci_readw, + .write_w = tegra_sdhci_writew, .write_l = tegra_sdhci_writel, .set_clock = sdhci_set_clock, .set_bus_width = tegra_sdhci_set_bus_width, @@ -201,7 +228,8 @@ static struct sdhci_tegra_soc_data soc_data_tegra114 = { .pdata = &sdhci_tegra114_pdata, .nvquirks = NVQUIRK_DISABLE_SDR50 | NVQUIRK_DISABLE_DDR50 | - NVQUIRK_DISABLE_SDR104, + NVQUIRK_DISABLE_SDR104 | + NVQUIRK_SHADOW_XFER_MODE_REG, }; static const struct of_device_id sdhci_tegra_dt_match[] = { diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index f1a488ee432f..0ad412a4876f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -53,6 +53,9 @@ static void sdhci_finish_command(struct sdhci_host *); static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); static void sdhci_tuning_timer(unsigned long data); static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); +static int sdhci_pre_dma_transfer(struct sdhci_host *host, + struct mmc_data *data, + struct sdhci_host_next *next); #ifdef CONFIG_PM static int sdhci_runtime_pm_get(struct sdhci_host *host); @@ -505,9 +508,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, goto fail; BUG_ON(host->align_addr & host->align_mask); - host->sg_count = dma_map_sg(mmc_dev(host->mmc), - data->sg, data->sg_len, direction); - if (host->sg_count == 0) + host->sg_count = sdhci_pre_dma_transfer(host, data, NULL); + if (host->sg_count < 0) goto unmap_align; desc = host->adma_table; @@ -531,8 +533,6 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, if (offset) { if (data->flags & MMC_DATA_WRITE) { buffer = sdhci_kmap_atomic(sg, &flags); - WARN_ON(((long)buffer & (PAGE_SIZE - 1)) > - (PAGE_SIZE - offset)); memcpy(align, buffer, offset); sdhci_kunmap_atomic(buffer, &flags); } @@ -639,8 +639,6 @@ static void sdhci_adma_table_post(struct sdhci_host *host, (sg_dma_address(sg) & host->align_mask); buffer = sdhci_kmap_atomic(sg, &flags); - WARN_ON(((long)buffer & (PAGE_SIZE - 1)) > - (PAGE_SIZE - size)); memcpy(buffer, align, size); sdhci_kunmap_atomic(buffer, &flags); @@ -649,8 +647,9 @@ static void sdhci_adma_table_post(struct sdhci_host *host, } } - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, direction); + if (!data->host_cookie) + dma_unmap_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, direction); } static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) @@ -846,11 +845,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) } else { int sg_cnt; - sg_cnt = dma_map_sg(mmc_dev(host->mmc), - data->sg, data->sg_len, - (data->flags & MMC_DATA_READ) ? - DMA_FROM_DEVICE : - DMA_TO_DEVICE); + sg_cnt = sdhci_pre_dma_transfer(host, data, NULL); if (sg_cnt == 0) { /* * This only happens when someone fed @@ -909,7 +904,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) static void sdhci_set_transfer_mode(struct sdhci_host *host, struct mmc_command *cmd) { - u16 mode; + u16 mode = 0; struct mmc_data *data = cmd->data; if (data == NULL) { @@ -927,9 +922,11 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, WARN_ON(!host->data); - mode = SDHCI_TRNS_BLK_CNT_EN; + if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE)) + mode = SDHCI_TRNS_BLK_CNT_EN; + if (mmc_op_multi(cmd->opcode) || data->blocks > 1) { - mode |= SDHCI_TRNS_MULTI; + mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI; /* * If we are sending CMD23, CMD12 never gets sent * on successful completion (so no Auto-CMD12). @@ -963,8 +960,10 @@ static void sdhci_finish_data(struct sdhci_host *host) if (host->flags & SDHCI_USE_ADMA) sdhci_adma_table_post(host, data); else { - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, (data->flags & MMC_DATA_READ) ? + if (!data->host_cookie) + dma_unmap_sg(mmc_dev(host->mmc), + data->sg, data->sg_len, + (data->flags & MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } } @@ -1630,7 +1629,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) * signalling timeout and CRC errors even on CMD0. Resetting * it on each ios seems to solve the problem. */ - if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) + if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); mmiowb(); @@ -1832,6 +1831,10 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, ctrl |= SDHCI_CTRL_VDD_180; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + /* Some controller need to do more when switching */ + if (host->ops->voltage_switch) + host->ops->voltage_switch(host); + /* 1.8V regulator output should be stable within 5 ms */ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); if (ctrl & SDHCI_CTRL_VDD_180) @@ -1960,6 +1963,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); ctrl |= SDHCI_CTRL_EXEC_TUNING; + if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND) + ctrl |= SDHCI_CTRL_TUNED_CLK; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); /* @@ -2129,6 +2134,77 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable) } } +static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, + int err) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct mmc_data *data = mrq->data; + + if (host->flags & SDHCI_REQ_USE_DMA) { + if (data->host_cookie) + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + data->flags & MMC_DATA_WRITE ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + mrq->data->host_cookie = 0; + } +} + +static int sdhci_pre_dma_transfer(struct sdhci_host *host, + struct mmc_data *data, + struct sdhci_host_next *next) +{ + int sg_count; + + if (!next && data->host_cookie && + data->host_cookie != host->next_data.cookie) { + pr_debug(DRIVER_NAME "[%s] invalid cookie: %d, next-cookie %d\n", + __func__, data->host_cookie, host->next_data.cookie); + data->host_cookie = 0; + } + + /* Check if next job is already prepared */ + if (next || + (!next && data->host_cookie != host->next_data.cookie)) { + sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, + data->flags & MMC_DATA_WRITE ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + + } else { + sg_count = host->next_data.sg_count; + host->next_data.sg_count = 0; + } + + + if (sg_count == 0) + return -EINVAL; + + if (next) { + next->sg_count = sg_count; + data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie; + } else + host->sg_count = sg_count; + + return sg_count; +} + +static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, + bool is_first_req) +{ + struct sdhci_host *host = mmc_priv(mmc); + + if (mrq->data->host_cookie) { + mrq->data->host_cookie = 0; + return; + } + + if (host->flags & SDHCI_REQ_USE_DMA) + if (sdhci_pre_dma_transfer(host, + mrq->data, + &host->next_data) < 0) + mrq->data->host_cookie = 0; +} + static void sdhci_card_event(struct mmc_host *mmc) { struct sdhci_host *host = mmc_priv(mmc); @@ -2162,6 +2238,8 @@ static void sdhci_card_event(struct mmc_host *mmc) static const struct mmc_host_ops sdhci_ops = { .request = sdhci_request, + .post_req = sdhci_post_req, + .pre_req = sdhci_pre_req, .set_ios = sdhci_set_ios, .get_cd = sdhci_get_cd, .get_ro = sdhci_get_ro, @@ -2793,9 +2871,9 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) /* Force clock and power re-program */ host->pwr = 0; host->clock = 0; + sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios); sdhci_do_set_ios(host, &host->mmc->ios); - sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios); if ((host_flags & SDHCI_PV_ENABLED) && !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) { spin_lock_irqsave(&host->lock, flags); @@ -3019,6 +3097,7 @@ int sdhci_add_host(struct sdhci_host *host) host->max_clk = host->ops->get_max_clock(host); } + host->next_data.cookie = 1; /* * In case of Host Controller v3.00, find out whether clock * multiplier is supported. @@ -3338,9 +3417,9 @@ int sdhci_add_host(struct sdhci_host *host) setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); - if (host->version >= SDHCI_SPEC_300) { - init_waitqueue_head(&host->buf_ready_int); + init_waitqueue_head(&host->buf_ready_int); + if (host->version >= SDHCI_SPEC_300) { /* Initialize re-tuning timer */ init_timer(&host->tuning_timer); host->tuning_timer.data = (unsigned long)host; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 41a2c34299ed..0315e1844330 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -339,6 +339,7 @@ struct sdhci_ops { void (*adma_workaround)(struct sdhci_host *host, u32 intmask); void (*platform_init)(struct sdhci_host *host); void (*card_event)(struct sdhci_host *host); + void (*voltage_switch)(struct sdhci_host *host); }; #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c new file mode 100644 index 000000000000..2fe8b91481b3 --- /dev/null +++ b/drivers/mmc/host/sdhci_f_sdh30.c @@ -0,0 +1,237 @@ +/* + * linux/drivers/mmc/host/sdhci_f_sdh30.c + * + * Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd + * Vincent Yang + * Copyright (C) 2015 Linaro Ltd Andy Green + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + */ + +#include +#include +#include +#include + +#include "sdhci-pltfm.h" + +/* F_SDH30 extended Controller registers */ +#define F_SDH30_AHB_CONFIG 0x100 +#define F_SDH30_AHB_BIGED 0x00000040 +#define F_SDH30_BUSLOCK_DMA 0x00000020 +#define F_SDH30_BUSLOCK_EN 0x00000010 +#define F_SDH30_SIN 0x00000008 +#define F_SDH30_AHB_INCR_16 0x00000004 +#define F_SDH30_AHB_INCR_8 0x00000002 +#define F_SDH30_AHB_INCR_4 0x00000001 + +#define F_SDH30_TUNING_SETTING 0x108 +#define F_SDH30_CMD_CHK_DIS 0x00010000 + +#define F_SDH30_IO_CONTROL2 0x114 +#define F_SDH30_CRES_O_DN 0x00080000 +#define F_SDH30_MSEL_O_1_8 0x00040000 + +#define F_SDH30_ESD_CONTROL 0x124 +#define F_SDH30_EMMC_RST 0x00000002 +#define F_SDH30_EMMC_HS200 0x01000000 + +#define F_SDH30_CMD_DAT_DELAY 0x200 + +#define F_SDH30_MIN_CLOCK 400000 + +struct f_sdhost_priv { + struct clk *clk_iface; + struct clk *clk; + u32 vendor_hs200; + struct device *dev; +}; + +void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host) +{ + struct f_sdhost_priv *priv = sdhci_priv(host); + u32 ctrl = 0; + + usleep_range(2500, 3000); + ctrl = sdhci_readl(host, F_SDH30_IO_CONTROL2); + ctrl |= F_SDH30_CRES_O_DN; + sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2); + ctrl |= F_SDH30_MSEL_O_1_8; + sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2); + + ctrl &= ~F_SDH30_CRES_O_DN; + sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2); + usleep_range(2500, 3000); + + if (priv->vendor_hs200) { + dev_info(priv->dev, "%s: setting hs200\n", __func__); + ctrl = sdhci_readl(host, F_SDH30_ESD_CONTROL); + ctrl |= priv->vendor_hs200; + sdhci_writel(host, ctrl, F_SDH30_ESD_CONTROL); + } + + ctrl = sdhci_readl(host, F_SDH30_TUNING_SETTING); + ctrl |= F_SDH30_CMD_CHK_DIS; + sdhci_writel(host, ctrl, F_SDH30_TUNING_SETTING); +} + +unsigned int sdhci_f_sdh30_get_min_clock(struct sdhci_host *host) +{ + return F_SDH30_MIN_CLOCK; +} + +void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask) +{ + if (sdhci_readw(host, SDHCI_CLOCK_CONTROL) == 0) + sdhci_writew(host, 0xBC01, SDHCI_CLOCK_CONTROL); + + sdhci_reset(host, mask); +} + +static const struct sdhci_ops sdhci_f_sdh30_ops = { + .voltage_switch = sdhci_f_sdh30_soft_voltage_switch, + .get_min_clock = sdhci_f_sdh30_get_min_clock, + .reset = sdhci_f_sdh30_reset, + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +static int sdhci_f_sdh30_probe(struct platform_device *pdev) +{ + struct sdhci_host *host; + struct device *dev = &pdev->dev; + struct resource *res; + int irq, ctrl = 0, ret = 0; + struct f_sdhost_priv *priv; + u32 reg = 0; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "%s: no irq specified\n", __func__); + return irq; + } + + host = sdhci_alloc_host(dev, sizeof(struct sdhci_host) + + sizeof(struct f_sdhost_priv)); + if (IS_ERR(host)) + return PTR_ERR(host); + + priv = sdhci_priv(host); + priv->dev = dev; + + host->quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | + SDHCI_QUIRK_INVERTED_WRITE_PROTECT; + host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE | + SDHCI_QUIRK2_TUNING_WORK_AROUND; + + ret = mmc_of_parse(host->mmc); + if (ret) + goto err; + + platform_set_drvdata(pdev, host); + + sdhci_get_of_property(pdev); + host->hw_name = "f_sdh30"; + host->ops = &sdhci_f_sdh30_ops; + host->irq = irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + host->ioaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(host->ioaddr)) { + ret = PTR_ERR(host->ioaddr); + goto err; + } + + priv->clk_iface = devm_clk_get(&pdev->dev, "iface"); + if (IS_ERR(priv->clk_iface)) { + ret = PTR_ERR(priv->clk_iface); + goto err; + } + + ret = clk_prepare_enable(priv->clk_iface); + if (ret) + goto err; + + priv->clk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(priv->clk)) { + ret = PTR_ERR(priv->clk); + goto err_clk; + } + + ret = clk_prepare_enable(priv->clk); + if (ret) + goto err_clk; + + /* init vendor specific regs */ + ctrl = sdhci_readw(host, F_SDH30_AHB_CONFIG); + ctrl |= F_SDH30_SIN | F_SDH30_AHB_INCR_16 | F_SDH30_AHB_INCR_8 | + F_SDH30_AHB_INCR_4; + ctrl &= ~(F_SDH30_AHB_BIGED | F_SDH30_BUSLOCK_EN); + sdhci_writew(host, ctrl, F_SDH30_AHB_CONFIG); + + reg = sdhci_readl(host, F_SDH30_ESD_CONTROL); + sdhci_writel(host, reg & ~F_SDH30_EMMC_RST, F_SDH30_ESD_CONTROL); + msleep(20); + sdhci_writel(host, reg | F_SDH30_EMMC_RST, F_SDH30_ESD_CONTROL); + + reg = sdhci_readl(host, SDHCI_CAPABILITIES); + if (reg & SDHCI_CAN_DO_8BIT) + priv->vendor_hs200 = F_SDH30_EMMC_HS200; + + ret = sdhci_add_host(host); + if (ret) + goto err_add_host; + + return 0; + +err_add_host: + clk_disable_unprepare(priv->clk); +err_clk: + clk_disable_unprepare(priv->clk_iface); +err: + sdhci_free_host(host); + return ret; +} + +static int sdhci_f_sdh30_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct f_sdhost_priv *priv = sdhci_priv(host); + + sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) == + 0xffffffff); + + clk_disable_unprepare(priv->clk_iface); + clk_disable_unprepare(priv->clk); + + sdhci_free_host(host); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static const struct of_device_id f_sdh30_dt_ids[] = { + { .compatible = "fujitsu,mb86s70-sdhci-3.0" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, f_sdh30_dt_ids); + +static struct platform_driver sdhci_f_sdh30_driver = { + .driver = { + .name = "f_sdh30", + .of_match_table = f_sdh30_dt_ids, + .pm = SDHCI_PLTFM_PMOPS, + }, + .probe = sdhci_f_sdh30_probe, + .remove = sdhci_f_sdh30_remove, +}; + +module_platform_driver(sdhci_f_sdh30_driver); + +MODULE_DESCRIPTION("F_SDH30 SD Card Controller driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD."); +MODULE_ALIAS("platform:f_sdh30"); diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 00c8ebdf8ec7..6906a905cd54 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -35,10 +35,13 @@ #define EXT_ACC 0xe4 +#define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data) + struct sh_mobile_sdhi_of_data { unsigned long tmio_flags; unsigned long capabilities; unsigned long capabilities2; + enum dma_slave_buswidth dma_buswidth; dma_addr_t dma_rx_offset; }; @@ -58,6 +61,7 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_CLK_ACTUAL, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, + .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, .dma_rx_offset = 0x2000, }; @@ -84,16 +88,43 @@ struct sh_mobile_sdhi { struct tmio_mmc_dma dma_priv; }; +static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) +{ + u32 val; + + /* + * see also + * sh_mobile_sdhi_of_data :: dma_buswidth + */ + switch (sd_ctrl_read16(host, CTL_VERSION)) { + case 0x490C: + val = (width == 32) ? 0x0001 : 0x0000; + break; + case 0xCB0D: + val = (width == 32) ? 0x0000 : 0x0001; + break; + default: + /* nothing to do */ + return; + } + + sd_ctrl_write16(host, EXT_ACC, val); +} + static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct tmio_mmc_host *host = mmc_priv(mmc); - struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); + struct sh_mobile_sdhi *priv = host_to_priv(host); int ret = clk_prepare_enable(priv->clk); if (ret < 0) return ret; *f = clk_get_rate(priv->clk); + + /* enable 16bit data access on SDBUF as default */ + sh_mobile_sdhi_sdbuf_width(host, 16); + return 0; } @@ -101,7 +132,7 @@ static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct tmio_mmc_host *host = mmc_priv(mmc); - struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); + struct sh_mobile_sdhi *priv = host_to_priv(host); clk_disable_unprepare(priv->clk); } @@ -113,7 +144,7 @@ static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) udelay(1); if (!timeout) { - dev_warn(host->pdata->dev, "timeout waiting for SD bus idle\n"); + dev_warn(&host->pdev->dev, "timeout waiting for SD bus idle\n"); return -EBUSY; } @@ -156,14 +187,13 @@ static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card, return blk_size; } -static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev) +static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) { - mmc_detect_change(platform_get_drvdata(pdev), msecs_to_jiffies(100)); -} + sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0); -static const struct sh_mobile_sdhi_ops sdhi_ops = { - .cd_wakeup = sh_mobile_sdhi_cd_wakeup, -}; + /* enable 32bit access if DMA mode if possibile */ + sh_mobile_sdhi_sdbuf_width(host, enable ? 32 : 16); +} static int sh_mobile_sdhi_probe(struct platform_device *pdev) { @@ -177,7 +207,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) int irq, ret, i = 0; bool multiplexed_isr = true; struct tmio_mmc_dma *dma_priv; - u16 ver; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -192,26 +221,31 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) mmc_data = &priv->mmc_data; dma_priv = &priv->dma_priv; - if (p) { - if (p->init) { - ret = p->init(pdev, &sdhi_ops); - if (ret) - return ret; - } - } - priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { ret = PTR_ERR(priv->clk); dev_err(&pdev->dev, "cannot get clock: %d\n", ret); - goto eclkget; + goto eprobe; } - mmc_data->clk_enable = sh_mobile_sdhi_clk_enable; - mmc_data->clk_disable = sh_mobile_sdhi_clk_disable; + host = tmio_mmc_host_alloc(pdev); + if (!host) { + ret = -ENOMEM; + goto eprobe; + } + + host->dma = dma_priv; + host->write16_hook = sh_mobile_sdhi_write16_hook; + host->clk_enable = sh_mobile_sdhi_clk_enable; + host->clk_disable = sh_mobile_sdhi_clk_disable; + host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; + /* SD control register space size is 0x100, 0x200 for bus_shift=1 */ + if (resource_size(res) > 0x100) + host->bus_shift = 1; + else + host->bus_shift = 0; + mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; - mmc_data->write16_hook = sh_mobile_sdhi_write16_hook; - mmc_data->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; if (p) { mmc_data->flags = p->tmio_flags; mmc_data->ocr_mask = p->tmio_ocr_mask; @@ -231,11 +265,10 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) dma_priv->slave_id_rx = p->dma_slave_rx; } } - - dma_priv->alignment_shift = 1; /* 2-byte alignment */ dma_priv->filter = shdma_chan_filter; + dma_priv->enable = sh_mobile_sdhi_enable_dma; - mmc_data->dma = dma_priv; + mmc_data->alignment_shift = 1; /* 2-byte alignment */ /* * All SDHI blocks support 2-byte and larger block sizes in 4-bit @@ -258,33 +291,18 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) */ mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK; - /* - * All SDHI have DMA control register - */ - mmc_data->flags |= TMIO_MMC_HAVE_CTL_DMA_REG; - if (of_id && of_id->data) { const struct sh_mobile_sdhi_of_data *of_data = of_id->data; mmc_data->flags |= of_data->tmio_flags; mmc_data->capabilities |= of_data->capabilities; mmc_data->capabilities2 |= of_data->capabilities2; - dma_priv->dma_rx_offset = of_data->dma_rx_offset; + mmc_data->dma_rx_offset = of_data->dma_rx_offset; + dma_priv->dma_buswidth = of_data->dma_buswidth; } - /* SD control register space size is 0x100, 0x200 for bus_shift=1 */ - mmc_data->bus_shift = resource_size(res) >> 9; - - ret = tmio_mmc_host_probe(&host, pdev, mmc_data); + ret = tmio_mmc_host_probe(host, mmc_data); if (ret < 0) - goto eprobe; - - /* - * FIXME: - * this Workaround can be more clever method - */ - ver = sd_ctrl_read16(host, CTL_VERSION); - if (ver == 0xCB0D) - sd_ctrl_write16(host, EXT_ACC, 1); + goto efree; /* * Allow one or more specific (named) ISRs or @@ -351,10 +369,9 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) eirq: tmio_mmc_host_remove(host); +efree: + tmio_mmc_host_free(host); eprobe: -eclkget: - if (p && p->cleanup) - p->cleanup(pdev); return ret; } @@ -362,13 +379,9 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct tmio_mmc_host *host = mmc_priv(mmc); - struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; tmio_mmc_host_remove(host); - if (p && p->cleanup) - p->cleanup(pdev); - return 0; } diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 15cb8b7ffc34..6af0a28ba37d 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -252,7 +252,7 @@ static int sunxi_mmc_reset_host(struct sunxi_mmc_host *host) unsigned long expire = jiffies + msecs_to_jiffies(250); u32 rval; - mmc_writel(host, REG_CMDR, SDXC_HARDWARE_RESET); + mmc_writel(host, REG_GCTRL, SDXC_HARDWARE_RESET); do { rval = mmc_readl(host, REG_GCTRL); } while (time_before(jiffies, expire) && (rval & SDXC_HARDWARE_RESET)); @@ -310,7 +310,9 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host, } pdes[0].config |= SDXC_IDMAC_DES0_FD; - pdes[i - 1].config = SDXC_IDMAC_DES0_OWN | SDXC_IDMAC_DES0_LD; + pdes[i - 1].config |= SDXC_IDMAC_DES0_LD | SDXC_IDMAC_DES0_ER; + pdes[i - 1].config &= ~SDXC_IDMAC_DES0_DIC; + pdes[i - 1].buf_addr_ptr2 = 0; /* * Avoid the io-store starting the idmac hitting io-mem before the @@ -570,6 +572,15 @@ static irqreturn_t sunxi_mmc_handle_manual_stop(int irq, void *dev_id) } dev_err(mmc_dev(host->mmc), "data error, sending stop command\n"); + + /* + * We will never have more than one outstanding request, + * and we do not complete the request until after + * we've cleared host->manual_stop_mrq so we do not need to + * spin lock this function. + * Additionally we have wait states within this function + * so having it in a lock is a very bad idea. + */ sunxi_mmc_send_manual_stop(host, mrq); spin_lock_irqsave(&host->lock, iflags); @@ -616,7 +627,7 @@ static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en) static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, struct mmc_ios *ios) { - u32 rate, oclk_dly, rval, sclk_dly, src_clk; + u32 rate, oclk_dly, rval, sclk_dly; int ret; rate = clk_round_rate(host->clk_mmc, ios->clock); @@ -661,14 +672,6 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, sclk_dly = 4; } - src_clk = clk_get_rate(clk_get_parent(host->clk_mmc)); - if (src_clk >= 300000000 && src_clk <= 400000000) { - if (oclk_dly) - oclk_dly--; - if (sclk_dly) - sclk_dly--; - } - clk_sunxi_mmc_phase_control(host->clk_mmc, sclk_dly, oclk_dly); return sunxi_mmc_oclk_onoff(host, 1); @@ -766,6 +769,7 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) unsigned long iflags; u32 imask = SDXC_INTERRUPT_ERROR_BIT; u32 cmd_val = SDXC_START | (cmd->opcode & 0x3f); + bool wait_dma = host->wait_dma; int ret; /* Check for set_ios errors (should never happen) */ @@ -816,7 +820,7 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) if (cmd->data->flags & MMC_DATA_WRITE) cmd_val |= SDXC_WRITE; else - host->wait_dma = true; + wait_dma = true; } else { imask |= SDXC_COMMAND_DONE; } @@ -850,6 +854,7 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) } host->mrq = mrq; + host->wait_dma = wait_dma; mmc_writel(host, REG_IMASK, host->sdio_imask | imask); mmc_writel(host, REG_CARG, cmd->arg); mmc_writel(host, REG_CMDR, cmd_val); diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 2ca0afaab792..f746df493892 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -88,14 +88,19 @@ static int tmio_mmc_probe(struct platform_device *pdev) if (!res) return -EINVAL; - /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ - pdata->bus_shift = resource_size(res) >> 10; pdata->flags |= TMIO_MMC_HAVE_HIGH_REG; - ret = tmio_mmc_host_probe(&host, pdev, pdata); - if (ret) + host = tmio_mmc_host_alloc(pdev); + if (!host) goto cell_disable; + /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ + host->bus_shift = resource_size(res) >> 10; + + ret = tmio_mmc_host_probe(host, pdata); + if (ret) + goto host_free; + ret = request_irq(irq, tmio_mmc_irq, IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), host); if (ret) @@ -108,6 +113,8 @@ static int tmio_mmc_probe(struct platform_device *pdev) host_remove: tmio_mmc_host_remove(host); +host_free: + tmio_mmc_host_free(host); cell_disable: if (cell->disable) cell->disable(pdev); diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index a34ecbe1c1ad..fc3805ed69d1 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -16,6 +16,7 @@ #ifndef TMIO_MMC_H #define TMIO_MMC_H +#include #include #include #include @@ -39,6 +40,17 @@ #define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) struct tmio_mmc_data; +struct tmio_mmc_host; + +struct tmio_mmc_dma { + void *chan_priv_tx; + void *chan_priv_rx; + int slave_id_tx; + int slave_id_rx; + enum dma_slave_buswidth dma_buswidth; + bool (*filter)(struct dma_chan *chan, void *arg); + void (*enable)(struct tmio_mmc_host *host, bool enable); +}; struct tmio_mmc_host { void __iomem *ctl; @@ -56,9 +68,11 @@ struct tmio_mmc_host { struct scatterlist *sg_orig; unsigned int sg_len; unsigned int sg_off; + unsigned long bus_shift; struct platform_device *pdev; struct tmio_mmc_data *pdata; + struct tmio_mmc_dma *dma; /* DMA support */ bool force_pio; @@ -83,10 +97,17 @@ struct tmio_mmc_host { struct mutex ios_lock; /* protect set_ios() context */ bool native_hotplug; bool sdio_irq_enabled; + + int (*write16_hook)(struct tmio_mmc_host *host, int addr); + int (*clk_enable)(struct platform_device *pdev, unsigned int *f); + void (*clk_disable)(struct platform_device *pdev); + int (*multi_io_quirk)(struct mmc_card *card, + unsigned int direction, int blk_size); }; -int tmio_mmc_host_probe(struct tmio_mmc_host **host, - struct platform_device *pdev, +struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev); +void tmio_mmc_host_free(struct tmio_mmc_host *host); +int tmio_mmc_host_probe(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata); void tmio_mmc_host_remove(struct tmio_mmc_host *host); void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); @@ -151,19 +172,19 @@ int tmio_mmc_host_runtime_resume(struct device *dev); static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) { - return readw(host->ctl + (addr << host->pdata->bus_shift)); + return readw(host->ctl + (addr << host->bus_shift)); } static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr, u16 *buf, int count) { - readsw(host->ctl + (addr << host->pdata->bus_shift), buf, count); + readsw(host->ctl + (addr << host->bus_shift), buf, count); } static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) { - return readw(host->ctl + (addr << host->pdata->bus_shift)) | - readw(host->ctl + ((addr + 2) << host->pdata->bus_shift)) << 16; + return readw(host->ctl + (addr << host->bus_shift)) | + readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16; } static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val) @@ -171,21 +192,21 @@ static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val /* If there is a hook and it returns non-zero then there * is an error and the write should be skipped */ - if (host->pdata->write16_hook && host->pdata->write16_hook(host, addr)) + if (host->write16_hook && host->write16_hook(host, addr)) return; - writew(val, host->ctl + (addr << host->pdata->bus_shift)); + writew(val, host->ctl + (addr << host->bus_shift)); } static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, u16 *buf, int count) { - writesw(host->ctl + (addr << host->pdata->bus_shift), buf, count); + writesw(host->ctl + (addr << host->bus_shift), buf, count); } static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val) { - writew(val, host->ctl + (addr << host->pdata->bus_shift)); - writew(val >> 16, host->ctl + ((addr + 2) << host->pdata->bus_shift)); + writew(val, host->ctl + (addr << host->bus_shift)); + writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); } diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c index 7d077388b9eb..331bb618e398 100644 --- a/drivers/mmc/host/tmio_mmc_dma.c +++ b/drivers/mmc/host/tmio_mmc_dma.c @@ -28,8 +28,8 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) if (!host->chan_tx || !host->chan_rx) return; - if (host->pdata->flags & TMIO_MMC_HAVE_CTL_DMA_REG) - sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0); + if (host->dma->enable) + host->dma->enable(host, enable); } void tmio_mmc_abort_dma(struct tmio_mmc_host *host) @@ -49,11 +49,10 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_rx; - struct tmio_mmc_data *pdata = host->pdata; dma_cookie_t cookie; int ret, i; bool aligned = true, multiple = true; - unsigned int align = (1 << pdata->dma->alignment_shift) - 1; + unsigned int align = (1 << host->pdata->alignment_shift) - 1; for_each_sg(sg, sg_tmp, host->sg_len, i) { if (sg_tmp->offset & align) @@ -126,11 +125,10 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_tx; - struct tmio_mmc_data *pdata = host->pdata; dma_cookie_t cookie; int ret, i; bool aligned = true, multiple = true; - unsigned int align = (1 << pdata->dma->alignment_shift) - 1; + unsigned int align = (1 << host->pdata->alignment_shift) - 1; for_each_sg(sg, sg_tmp, host->sg_len, i) { if (sg_tmp->offset & align) @@ -262,8 +260,8 @@ out: void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata) { /* We can only either use DMA for both Tx and Rx or not use it at all */ - if (!pdata->dma || (!host->pdev->dev.of_node && - (!pdata->dma->chan_priv_tx || !pdata->dma->chan_priv_rx))) + if (!host->dma || (!host->pdev->dev.of_node && + (!host->dma->chan_priv_tx || !host->dma->chan_priv_rx))) return; if (!host->chan_tx && !host->chan_rx) { @@ -280,7 +278,7 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat dma_cap_set(DMA_SLAVE, mask); host->chan_tx = dma_request_slave_channel_compat(mask, - pdata->dma->filter, pdata->dma->chan_priv_tx, + host->dma->filter, host->dma->chan_priv_tx, &host->pdev->dev, "tx"); dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__, host->chan_tx); @@ -288,18 +286,20 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat if (!host->chan_tx) return; - if (pdata->dma->chan_priv_tx) - cfg.slave_id = pdata->dma->slave_id_tx; + if (host->dma->chan_priv_tx) + cfg.slave_id = host->dma->slave_id_tx; cfg.direction = DMA_MEM_TO_DEV; - cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->pdata->bus_shift); - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->bus_shift); + cfg.dst_addr_width = host->dma->dma_buswidth; + if (!cfg.dst_addr_width) + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; cfg.src_addr = 0; ret = dmaengine_slave_config(host->chan_tx, &cfg); if (ret < 0) goto ecfgtx; host->chan_rx = dma_request_slave_channel_compat(mask, - pdata->dma->filter, pdata->dma->chan_priv_rx, + host->dma->filter, host->dma->chan_priv_rx, &host->pdev->dev, "rx"); dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__, host->chan_rx); @@ -307,11 +307,13 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat if (!host->chan_rx) goto ereqrx; - if (pdata->dma->chan_priv_rx) - cfg.slave_id = pdata->dma->slave_id_rx; + if (host->dma->chan_priv_rx) + cfg.slave_id = host->dma->slave_id_rx; cfg.direction = DMA_DEV_TO_MEM; - cfg.src_addr = cfg.dst_addr + pdata->dma->dma_rx_offset; - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + cfg.src_addr = cfg.dst_addr + host->pdata->dma_rx_offset; + cfg.src_addr_width = host->dma->dma_buswidth; + if (!cfg.src_addr_width) + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; cfg.dst_addr = 0; ret = dmaengine_slave_config(host->chan_rx, &cfg); if (ret < 0) diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 250bf8c9f998..a31c3573d386 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -835,13 +835,12 @@ fail: static int tmio_mmc_clk_update(struct tmio_mmc_host *host) { struct mmc_host *mmc = host->mmc; - struct tmio_mmc_data *pdata = host->pdata; int ret; - if (!pdata->clk_enable) + if (!host->clk_enable) return -ENOTSUPP; - ret = pdata->clk_enable(host->pdev, &mmc->f_max); + ret = host->clk_enable(host->pdev, &mmc->f_max); if (!ret) mmc->f_min = mmc->f_max / 512; @@ -1005,10 +1004,9 @@ static int tmio_multi_io_quirk(struct mmc_card *card, unsigned int direction, int blk_size) { struct tmio_mmc_host *host = mmc_priv(card->host); - struct tmio_mmc_data *pdata = host->pdata; - if (pdata->multi_io_quirk) - return pdata->multi_io_quirk(card, direction, blk_size); + if (host->multi_io_quirk) + return host->multi_io_quirk(card, direction, blk_size); return blk_size; } @@ -1054,12 +1052,37 @@ static void tmio_mmc_of_parse(struct platform_device *pdev, pdata->flags |= TMIO_MMC_WRPROTECT_DISABLE; } -int tmio_mmc_host_probe(struct tmio_mmc_host **host, - struct platform_device *pdev, - struct tmio_mmc_data *pdata) +struct tmio_mmc_host* +tmio_mmc_host_alloc(struct platform_device *pdev) { - struct tmio_mmc_host *_host; + struct tmio_mmc_host *host; struct mmc_host *mmc; + + mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev); + if (!mmc) + return NULL; + + host = mmc_priv(mmc); + host->mmc = mmc; + host->pdev = pdev; + + return host; +} +EXPORT_SYMBOL(tmio_mmc_host_alloc); + +void tmio_mmc_host_free(struct tmio_mmc_host *host) +{ + mmc_free_host(host->mmc); + + host->mmc = NULL; +} +EXPORT_SYMBOL(tmio_mmc_host_free); + +int tmio_mmc_host_probe(struct tmio_mmc_host *_host, + struct tmio_mmc_data *pdata) +{ + struct platform_device *pdev = _host->pdev; + struct mmc_host *mmc = _host->mmc; struct resource *res_ctl; int ret; u32 irq_mask = TMIO_MASK_CMD; @@ -1067,25 +1090,17 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host, tmio_mmc_of_parse(pdev, pdata); if (!(pdata->flags & TMIO_MMC_HAS_IDLE_WAIT)) - pdata->write16_hook = NULL; + _host->write16_hook = NULL; res_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res_ctl) return -EINVAL; - mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev); - if (!mmc) - return -ENOMEM; - ret = mmc_of_parse(mmc); if (ret < 0) goto host_free; - pdata->dev = &pdev->dev; - _host = mmc_priv(mmc); _host->pdata = pdata; - _host->mmc = mmc; - _host->pdev = pdev; platform_set_drvdata(pdev, mmc); _host->set_pwr = pdata->set_pwr; @@ -1192,12 +1207,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host, mmc_gpiod_request_cd_irq(mmc); } - *host = _host; - return 0; host_free: - mmc_free_host(mmc); return ret; } @@ -1222,7 +1234,6 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) pm_runtime_disable(&pdev->dev); iounmap(host->ctl); - mmc_free_host(mmc); } EXPORT_SYMBOL(tmio_mmc_host_remove); @@ -1237,8 +1248,8 @@ int tmio_mmc_host_runtime_suspend(struct device *dev) if (host->clk_cache) tmio_mmc_clk_stop(host); - if (host->pdata->clk_disable) - host->pdata->clk_disable(host->pdev); + if (host->clk_disable) + host->clk_disable(host->pdev); return 0; } diff --git a/drivers/mmc/host/toshsd.c b/drivers/mmc/host/toshsd.c index 4666262edaca..e2cdd5fb1423 100644 --- a/drivers/mmc/host/toshsd.c +++ b/drivers/mmc/host/toshsd.c @@ -176,7 +176,8 @@ static irqreturn_t toshsd_thread_irq(int irq, void *dev_id) spin_lock_irqsave(&host->lock, flags); if (!sg_miter_next(sg_miter)) - return IRQ_HANDLED; + goto done; + buf = sg_miter->addr; /* Ensure we dont read more than one block. The chip will interrupt us @@ -198,6 +199,7 @@ static irqreturn_t toshsd_thread_irq(int irq, void *dev_id) sg_miter->consumed = count; sg_miter_stop(sg_miter); +done: spin_unlock_irqrestore(&host->lock, flags); return IRQ_HANDLED; @@ -699,18 +701,7 @@ static struct pci_driver toshsd_driver = { .driver.pm = &toshsd_pm_ops, }; -static int __init toshsd_drv_init(void) -{ - return pci_register_driver(&toshsd_driver); -} - -static void __exit toshsd_drv_exit(void) -{ - pci_unregister_driver(&toshsd_driver); -} - -module_init(toshsd_drv_init); -module_exit(toshsd_drv_exit); +module_pci_driver(toshsd_driver); MODULE_AUTHOR("Ondrej Zary, Richard Betts"); MODULE_DESCRIPTION("Toshiba PCI Secure Digital Host Controller Interface driver"); diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index 4262296c12fa..fbabbb82b354 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -659,7 +659,7 @@ static void __vub300_irqpoll_response(struct vub300_mmc_host *vub300) static void __do_poll(struct vub300_mmc_host *vub300) { /* cmd_mutex is held by vub300_pollwork_thread */ - long commretval; + unsigned long commretval; mod_timer(&vub300->inactivity_timer, jiffies + HZ); init_completion(&vub300->irqpoll_complete); send_irqpoll(vub300); @@ -671,8 +671,6 @@ static void __do_poll(struct vub300_mmc_host *vub300) vub300->usb_timed_out = 1; usb_kill_urb(vub300->command_out_urb); usb_kill_urb(vub300->command_res_urb); - } else if (commretval < 0) { - vub300_queue_poll_work(vub300, 1); } else { /* commretval > 0 */ __vub300_irqpoll_response(vub300); } diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 53563955931b..55fa27ecf4e1 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -49,7 +49,6 @@ static DEFINE_MUTEX(mtd_mutex); */ struct mtd_file_info { struct mtd_info *mtd; - struct inode *ino; enum mtd_file_modes mode; }; @@ -59,10 +58,6 @@ static loff_t mtdchar_lseek(struct file *file, loff_t offset, int orig) return fixed_size_llseek(file, offset, orig, mfi->mtd->size); } -static int count; -static struct vfsmount *mnt; -static struct file_system_type mtd_inodefs_type; - static int mtdchar_open(struct inode *inode, struct file *file) { int minor = iminor(inode); @@ -70,7 +65,6 @@ static int mtdchar_open(struct inode *inode, struct file *file) int ret = 0; struct mtd_info *mtd; struct mtd_file_info *mfi; - struct inode *mtd_ino; pr_debug("MTD_open\n"); @@ -78,10 +72,6 @@ static int mtdchar_open(struct inode *inode, struct file *file) if ((file->f_mode & FMODE_WRITE) && (minor & 1)) return -EACCES; - ret = simple_pin_fs(&mtd_inodefs_type, &mnt, &count); - if (ret) - return ret; - mutex_lock(&mtd_mutex); mtd = get_mtd_device(NULL, devnum); @@ -95,43 +85,26 @@ static int mtdchar_open(struct inode *inode, struct file *file) goto out1; } - mtd_ino = iget_locked(mnt->mnt_sb, devnum); - if (!mtd_ino) { - ret = -ENOMEM; - goto out1; - } - if (mtd_ino->i_state & I_NEW) { - mtd_ino->i_private = mtd; - mtd_ino->i_mode = S_IFCHR; - mtd_ino->i_data.backing_dev_info = mtd->backing_dev_info; - unlock_new_inode(mtd_ino); - } - file->f_mapping = mtd_ino->i_mapping; - /* You can't open it RW if it's not a writeable device */ if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) { ret = -EACCES; - goto out2; + goto out1; } mfi = kzalloc(sizeof(*mfi), GFP_KERNEL); if (!mfi) { ret = -ENOMEM; - goto out2; + goto out1; } - mfi->ino = mtd_ino; mfi->mtd = mtd; file->private_data = mfi; mutex_unlock(&mtd_mutex); return 0; -out2: - iput(mtd_ino); out1: put_mtd_device(mtd); out: mutex_unlock(&mtd_mutex); - simple_release_fs(&mnt, &count); return ret; } /* mtdchar_open */ @@ -148,12 +121,9 @@ static int mtdchar_close(struct inode *inode, struct file *file) if ((file->f_mode & FMODE_WRITE)) mtd_sync(mtd); - iput(mfi->ino); - put_mtd_device(mtd); file->private_data = NULL; kfree(mfi); - simple_release_fs(&mnt, &count); return 0; } /* mtdchar_close */ @@ -1117,6 +1087,13 @@ static unsigned long mtdchar_get_unmapped_area(struct file *file, ret = mtd_get_unmapped_area(mtd, len, offset, flags); return ret == -EOPNOTSUPP ? -ENODEV : ret; } + +static unsigned mtdchar_mmap_capabilities(struct file *file) +{ + struct mtd_file_info *mfi = file->private_data; + + return mtd_mmap_capabilities(mfi->mtd); +} #endif /* @@ -1160,27 +1137,10 @@ static const struct file_operations mtd_fops = { .mmap = mtdchar_mmap, #ifndef CONFIG_MMU .get_unmapped_area = mtdchar_get_unmapped_area, + .mmap_capabilities = mtdchar_mmap_capabilities, #endif }; -static const struct super_operations mtd_ops = { - .drop_inode = generic_delete_inode, - .statfs = simple_statfs, -}; - -static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_pseudo(fs_type, "mtd_inode:", &mtd_ops, NULL, MTD_INODE_FS_MAGIC); -} - -static struct file_system_type mtd_inodefs_type = { - .name = "mtd_inodefs", - .mount = mtd_inodefs_mount, - .kill_sb = kill_anon_super, -}; -MODULE_ALIAS_FS("mtd_inodefs"); - int __init init_mtdchar(void) { int ret; @@ -1193,23 +1153,11 @@ int __init init_mtdchar(void) return ret; } - ret = register_filesystem(&mtd_inodefs_type); - if (ret) { - pr_err("Can't register mtd_inodefs filesystem, error %d\n", - ret); - goto err_unregister_chdev; - } - - return ret; - -err_unregister_chdev: - __unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd"); return ret; } void __exit cleanup_mtdchar(void) { - unregister_filesystem(&mtd_inodefs_type); __unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd"); } diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index b9000563b9f4..eacc3aac7327 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -732,8 +732,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks; - concat->mtd.backing_dev_info = subdev[0]->backing_dev_info; - concat->subdev[0] = subdev[0]; for (i = 1; i < num_devs; i++) { @@ -761,14 +759,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c subdev[i]->flags & MTD_WRITEABLE; } - /* only permit direct mapping if the BDIs are all the same - * - copy-mapping is still permitted - */ - if (concat->mtd.backing_dev_info != - subdev[i]->backing_dev_info) - concat->mtd.backing_dev_info = - &default_backing_dev_info; - concat->mtd.size += subdev[i]->size; concat->mtd.ecc_stats.badblocks += subdev[i]->ecc_stats.badblocks; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 4c611871d7e6..0ec4d6ea1e4b 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -43,33 +43,7 @@ #include "mtdcore.h" -/* - * backing device capabilities for non-mappable devices (such as NAND flash) - * - permits private mappings, copies are taken of the data - */ -static struct backing_dev_info mtd_bdi_unmappable = { - .capabilities = BDI_CAP_MAP_COPY, -}; - -/* - * backing device capabilities for R/O mappable devices (such as ROM) - * - permits private mappings, copies are taken of the data - * - permits non-writable shared mappings - */ -static struct backing_dev_info mtd_bdi_ro_mappable = { - .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT | - BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP), -}; - -/* - * backing device capabilities for writable mappable devices (such as RAM) - * - permits private mappings, copies are taken of the data - * - permits non-writable shared mappings - */ -static struct backing_dev_info mtd_bdi_rw_mappable = { - .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT | - BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP | - BDI_CAP_WRITE_MAP), +static struct backing_dev_info mtd_bdi = { }; static int mtd_cls_suspend(struct device *dev, pm_message_t state); @@ -365,6 +339,23 @@ static struct device_type mtd_devtype = { .release = mtd_release, }; +#ifndef CONFIG_MMU +unsigned mtd_mmap_capabilities(struct mtd_info *mtd) +{ + switch (mtd->type) { + case MTD_RAM: + return NOMMU_MAP_COPY | NOMMU_MAP_DIRECT | NOMMU_MAP_EXEC | + NOMMU_MAP_READ | NOMMU_MAP_WRITE; + case MTD_ROM: + return NOMMU_MAP_COPY | NOMMU_MAP_DIRECT | NOMMU_MAP_EXEC | + NOMMU_MAP_READ; + default: + return NOMMU_MAP_COPY; + } +} +EXPORT_SYMBOL_GPL(mtd_mmap_capabilities); +#endif + /** * add_mtd_device - register an MTD device * @mtd: pointer to new MTD device info structure @@ -380,19 +371,7 @@ int add_mtd_device(struct mtd_info *mtd) struct mtd_notifier *not; int i, error; - if (!mtd->backing_dev_info) { - switch (mtd->type) { - case MTD_RAM: - mtd->backing_dev_info = &mtd_bdi_rw_mappable; - break; - case MTD_ROM: - mtd->backing_dev_info = &mtd_bdi_ro_mappable; - break; - default: - mtd->backing_dev_info = &mtd_bdi_unmappable; - break; - } - } + mtd->backing_dev_info = &mtd_bdi; BUG_ON(mtd->writesize == 0); mutex_lock(&mtd_table_mutex); @@ -1237,17 +1216,9 @@ static int __init init_mtd(void) if (ret) goto err_reg; - ret = mtd_bdi_init(&mtd_bdi_unmappable, "mtd-unmap"); + ret = mtd_bdi_init(&mtd_bdi, "mtd"); if (ret) - goto err_bdi1; - - ret = mtd_bdi_init(&mtd_bdi_ro_mappable, "mtd-romap"); - if (ret) - goto err_bdi2; - - ret = mtd_bdi_init(&mtd_bdi_rw_mappable, "mtd-rwmap"); - if (ret) - goto err_bdi3; + goto err_bdi; proc_mtd = proc_create("mtd", 0, NULL, &mtd_proc_ops); @@ -1260,11 +1231,7 @@ static int __init init_mtd(void) out_procfs: if (proc_mtd) remove_proc_entry("mtd", NULL); -err_bdi3: - bdi_destroy(&mtd_bdi_ro_mappable); -err_bdi2: - bdi_destroy(&mtd_bdi_unmappable); -err_bdi1: +err_bdi: class_unregister(&mtd_class); err_reg: pr_err("Error registering mtd class or bdi: %d\n", ret); @@ -1277,9 +1244,7 @@ static void __exit cleanup_mtd(void) if (proc_mtd) remove_proc_entry("mtd", NULL); class_unregister(&mtd_class); - bdi_destroy(&mtd_bdi_unmappable); - bdi_destroy(&mtd_bdi_ro_mappable); - bdi_destroy(&mtd_bdi_rw_mappable); + bdi_destroy(&mtd_bdi); } module_init(init_mtd); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index a3e3a7d074d5..e779de315ade 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -378,7 +378,6 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, slave->mtd.name = name; slave->mtd.owner = master->owner; - slave->mtd.backing_dev_info = master->backing_dev_info; /* NOTE: we don't arrange MTDs as a tree; it'd be error-prone * to have the same data be in two different partitions. diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index d6607ee9c855..84673ebcf428 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -197,6 +197,7 @@ config NETCONSOLE_DYNAMIC config NETPOLL def_bool NETCONSOLE + select SRCU config NET_POLL_CONTROLLER def_bool NETPOLL diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 6c99ff0b0bdd..945f532078e9 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -78,6 +78,9 @@ static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *i priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + ci = (struct com20020_pci_card_info *)id->driver_data; priv->ci = ci; diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 8baa87df1738..cfc4a9c1000a 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -467,11 +467,14 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port) /* set the partner sync. to on if the partner is sync, * and the port is matched */ - if ((port->sm_vars & AD_PORT_MATCHED) - && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) + if ((port->sm_vars & AD_PORT_MATCHED) && + (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) { partner->port_state |= AD_STATE_SYNCHRONIZATION; - else + pr_debug("%s partner sync=1\n", port->slave->dev->name); + } else { partner->port_state &= ~AD_STATE_SYNCHRONIZATION; + pr_debug("%s partner sync=0\n", port->slave->dev->name); + } } } @@ -726,6 +729,8 @@ static inline void __update_lacpdu_from_port(struct port *port) lacpdu->actor_port_priority = htons(port->actor_port_priority); lacpdu->actor_port = htons(port->actor_port_number); lacpdu->actor_state = port->actor_oper_port_state; + pr_debug("update lacpdu: %s, actor port state %x\n", + port->slave->dev->name, port->actor_oper_port_state); /* lacpdu->reserved_3_1 initialized * lacpdu->tlv_type_partner_info initialized @@ -898,7 +903,9 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) { - port->sm_mux_state = AD_MUX_COLLECTING_DISTRIBUTING; + if (port->aggregator->is_active) + port->sm_mux_state = + AD_MUX_COLLECTING_DISTRIBUTING; } else if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) { /* if UNSELECTED or STANDBY */ @@ -910,12 +917,16 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) */ __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); port->sm_mux_state = AD_MUX_DETACHED; + } else if (port->aggregator->is_active) { + port->actor_oper_port_state |= + AD_STATE_SYNCHRONIZATION; } break; case AD_MUX_COLLECTING_DISTRIBUTING: if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY) || - !(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION)) { + !(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) || + !(port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) { port->sm_mux_state = AD_MUX_ATTACHED; } else { /* if port state hasn't changed make @@ -937,8 +948,10 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) /* check if the state machine was changed */ if (port->sm_mux_state != last_state) { - pr_debug("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", - port->actor_port_number, last_state, + pr_debug("Mux Machine: Port=%d (%s), Last State=%d, Curr State=%d\n", + port->actor_port_number, + port->slave->dev->name, + last_state, port->sm_mux_state); switch (port->sm_mux_state) { case AD_MUX_DETACHED: @@ -953,7 +966,12 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0); break; case AD_MUX_ATTACHED: - port->actor_oper_port_state |= AD_STATE_SYNCHRONIZATION; + if (port->aggregator->is_active) + port->actor_oper_port_state |= + AD_STATE_SYNCHRONIZATION; + else + port->actor_oper_port_state &= + ~AD_STATE_SYNCHRONIZATION; port->actor_oper_port_state &= ~AD_STATE_COLLECTING; port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING; ad_disable_collecting_distributing(port, @@ -963,6 +981,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) case AD_MUX_COLLECTING_DISTRIBUTING: port->actor_oper_port_state |= AD_STATE_COLLECTING; port->actor_oper_port_state |= AD_STATE_DISTRIBUTING; + port->actor_oper_port_state |= AD_STATE_SYNCHRONIZATION; ad_enable_collecting_distributing(port, update_slave_arr); port->ntt = true; @@ -1044,8 +1063,10 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) /* check if the State machine was changed or new lacpdu arrived */ if ((port->sm_rx_state != last_state) || (lacpdu)) { - pr_debug("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", - port->actor_port_number, last_state, + pr_debug("Rx Machine: Port=%d (%s), Last State=%d, Curr State=%d\n", + port->actor_port_number, + port->slave->dev->name, + last_state, port->sm_rx_state); switch (port->sm_rx_state) { case AD_RX_INITIALIZE: @@ -1394,6 +1415,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) aggregator = __get_first_agg(port); ad_agg_selection_logic(aggregator, update_slave_arr); + + if (!port->aggregator->is_active) + port->actor_oper_port_state &= ~AD_STATE_SYNCHRONIZATION; } /* Decide if "agg" is a better choice for the new active aggregator that @@ -2195,8 +2219,10 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, switch (lacpdu->subtype) { case AD_TYPE_LACPDU: ret = RX_HANDLER_CONSUMED; - netdev_dbg(slave->bond->dev, "Received LACPDU on port %d\n", - port->actor_port_number); + netdev_dbg(slave->bond->dev, + "Received LACPDU on port %d slave %s\n", + port->actor_port_number, + slave->dev->name); /* Protect against concurrent state machines */ spin_lock(&slave->bond->mode_lock); ad_rx_machine(lacpdu, port); @@ -2288,7 +2314,10 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave) port->actor_admin_port_key &= ~AD_DUPLEX_KEY_MASKS; port->actor_oper_port_key = port->actor_admin_port_key |= __get_duplex(port); - netdev_dbg(slave->bond->dev, "Port %d changed duplex\n", port->actor_port_number); + netdev_dbg(slave->bond->dev, "Port %d slave %s changed duplex\n", + port->actor_port_number, slave->dev->name); + if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS) + port->sm_vars |= AD_PORT_LACP_ENABLED; /* there is no need to reselect a new aggregator, just signal the * state machines to reinitialize */ diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 0dceba1a2ba1..b979c265fc51 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -77,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -334,7 +335,7 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev, * * Returns zero if carrier state does not change, nonzero if it does. */ -static int bond_set_carrier(struct bonding *bond) +int bond_set_carrier(struct bonding *bond) { struct list_head *iter; struct slave *slave; @@ -789,7 +790,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) } new_active->delay = 0; - new_active->link = BOND_LINK_UP; + bond_set_slave_link_state(new_active, BOND_LINK_UP); if (BOND_MODE(bond) == BOND_MODE_8023AD) bond_3ad_handle_link_change(new_active, BOND_LINK_UP); @@ -979,7 +980,11 @@ static netdev_features_t bond_fix_features(struct net_device *dev, netdev_features_t mask; struct slave *slave; - mask = features; + /* If any slave has the offload feature flag set, + * set the offload flag on the bond. + */ + mask = features | NETIF_F_HW_SWITCH_OFFLOAD; + features &= ~NETIF_F_ONE_FOR_ALL; features |= NETIF_F_ALL_FOR_ALL; @@ -998,7 +1003,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev, NETIF_F_HIGHDMA | NETIF_F_LRO) #define BOND_ENC_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | NETIF_F_RXCSUM |\ - NETIF_F_TSO | NETIF_F_GSO_UDP_TUNNEL) + NETIF_F_TSO) static void bond_compute_features(struct bonding *bond) { @@ -1034,7 +1039,7 @@ static void bond_compute_features(struct bonding *bond) done: bond_dev->vlan_features = vlan_features; - bond_dev->hw_enc_features = enc_features; + bond_dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL; bond_dev->hard_header_len = max_hard_header_len; bond_dev->gso_max_segs = gso_max_segs; netif_set_gso_max_size(bond_dev, gso_max_size); @@ -1176,6 +1181,56 @@ static void bond_free_slave(struct slave *slave) kfree(slave); } +static void bond_fill_ifbond(struct bonding *bond, struct ifbond *info) +{ + info->bond_mode = BOND_MODE(bond); + info->miimon = bond->params.miimon; + info->num_slaves = bond->slave_cnt; +} + +static void bond_fill_ifslave(struct slave *slave, struct ifslave *info) +{ + strcpy(info->slave_name, slave->dev->name); + info->link = slave->link; + info->state = bond_slave_state(slave); + info->link_failure_count = slave->link_failure_count; +} + +static void bond_netdev_notify(struct net_device *dev, + struct netdev_bonding_info *info) +{ + rtnl_lock(); + netdev_bonding_info_change(dev, info); + rtnl_unlock(); +} + +static void bond_netdev_notify_work(struct work_struct *_work) +{ + struct netdev_notify_work *w = + container_of(_work, struct netdev_notify_work, work.work); + + bond_netdev_notify(w->dev, &w->bonding_info); + dev_put(w->dev); + kfree(w); +} + +void bond_queue_slave_event(struct slave *slave) +{ + struct bonding *bond = slave->bond; + struct netdev_notify_work *nnw = kzalloc(sizeof(*nnw), GFP_ATOMIC); + + if (!nnw) + return; + + dev_hold(slave->dev); + nnw->dev = slave->dev; + bond_fill_ifslave(slave, &nnw->bonding_info.slave); + bond_fill_ifbond(bond, &nnw->bonding_info.master); + INIT_DELAYED_WORK(&nnw->work, bond_netdev_notify_work); + + queue_delayed_work(slave->bond->wq, &nnw->work, 0); +} + /* enslave device to bond device */ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) { @@ -1439,19 +1494,22 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (bond->params.miimon) { if (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS) { if (bond->params.updelay) { - new_slave->link = BOND_LINK_BACK; + bond_set_slave_link_state(new_slave, + BOND_LINK_BACK); new_slave->delay = bond->params.updelay; } else { - new_slave->link = BOND_LINK_UP; + bond_set_slave_link_state(new_slave, + BOND_LINK_UP); } } else { - new_slave->link = BOND_LINK_DOWN; + bond_set_slave_link_state(new_slave, BOND_LINK_DOWN); } } else if (bond->params.arp_interval) { - new_slave->link = (netif_carrier_ok(slave_dev) ? - BOND_LINK_UP : BOND_LINK_DOWN); + bond_set_slave_link_state(new_slave, + (netif_carrier_ok(slave_dev) ? + BOND_LINK_UP : BOND_LINK_DOWN)); } else { - new_slave->link = BOND_LINK_UP; + bond_set_slave_link_state(new_slave, BOND_LINK_UP); } if (new_slave->link != BOND_LINK_DOWN) @@ -1567,6 +1625,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) new_slave->link != BOND_LINK_DOWN ? "an up" : "a down"); /* enslave is successful */ + bond_queue_slave_event(new_slave); return 0; /* Undo stages on error */ @@ -1816,11 +1875,7 @@ static int bond_release_and_destroy(struct net_device *bond_dev, static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) { struct bonding *bond = netdev_priv(bond_dev); - - info->bond_mode = BOND_MODE(bond); - info->miimon = bond->params.miimon; - info->num_slaves = bond->slave_cnt; - + bond_fill_ifbond(bond, info); return 0; } @@ -1834,10 +1889,7 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in bond_for_each_slave(bond, slave, iter) { if (i++ == (int)info->slave_id) { res = 0; - strcpy(info->slave_name, slave->dev->name); - info->link = slave->link; - info->state = bond_slave_state(slave); - info->link_failure_count = slave->link_failure_count; + bond_fill_ifslave(slave, info); break; } } @@ -1867,7 +1919,7 @@ static int bond_miimon_inspect(struct bonding *bond) if (link_state) continue; - slave->link = BOND_LINK_FAIL; + bond_set_slave_link_state(slave, BOND_LINK_FAIL); slave->delay = bond->params.downdelay; if (slave->delay) { netdev_info(bond->dev, "link status down for %sinterface %s, disabling it in %d ms\n", @@ -1882,7 +1934,7 @@ static int bond_miimon_inspect(struct bonding *bond) case BOND_LINK_FAIL: if (link_state) { /* recovered before downdelay expired */ - slave->link = BOND_LINK_UP; + bond_set_slave_link_state(slave, BOND_LINK_UP); slave->last_link_up = jiffies; netdev_info(bond->dev, "link status up again after %d ms for interface %s\n", (bond->params.downdelay - slave->delay) * @@ -1904,7 +1956,7 @@ static int bond_miimon_inspect(struct bonding *bond) if (!link_state) continue; - slave->link = BOND_LINK_BACK; + bond_set_slave_link_state(slave, BOND_LINK_BACK); slave->delay = bond->params.updelay; if (slave->delay) { @@ -1917,7 +1969,8 @@ static int bond_miimon_inspect(struct bonding *bond) /*FALLTHRU*/ case BOND_LINK_BACK: if (!link_state) { - slave->link = BOND_LINK_DOWN; + bond_set_slave_link_state(slave, + BOND_LINK_DOWN); netdev_info(bond->dev, "link status down again after %d ms for interface %s\n", (bond->params.updelay - slave->delay) * bond->params.miimon, @@ -1955,7 +2008,7 @@ static void bond_miimon_commit(struct bonding *bond) continue; case BOND_LINK_UP: - slave->link = BOND_LINK_UP; + bond_set_slave_link_state(slave, BOND_LINK_UP); slave->last_link_up = jiffies; primary = rtnl_dereference(bond->primary_slave); @@ -1995,7 +2048,7 @@ static void bond_miimon_commit(struct bonding *bond) if (slave->link_failure_count < UINT_MAX) slave->link_failure_count++; - slave->link = BOND_LINK_DOWN; + bond_set_slave_link_state(slave, BOND_LINK_DOWN); if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP || BOND_MODE(bond) == BOND_MODE_8023AD) @@ -2578,7 +2631,7 @@ static void bond_ab_arp_commit(struct bonding *bond) struct slave *current_arp_slave; current_arp_slave = rtnl_dereference(bond->current_arp_slave); - slave->link = BOND_LINK_UP; + bond_set_slave_link_state(slave, BOND_LINK_UP); if (current_arp_slave) { bond_set_slave_inactive_flags( current_arp_slave, @@ -2601,7 +2654,7 @@ static void bond_ab_arp_commit(struct bonding *bond) if (slave->link_failure_count < UINT_MAX) slave->link_failure_count++; - slave->link = BOND_LINK_DOWN; + bond_set_slave_link_state(slave, BOND_LINK_DOWN); bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW); @@ -2680,7 +2733,7 @@ static bool bond_ab_arp_probe(struct bonding *bond) * up when it is actually down */ if (!bond_slave_is_up(slave) && slave->link == BOND_LINK_UP) { - slave->link = BOND_LINK_DOWN; + bond_set_slave_link_state(slave, BOND_LINK_DOWN); if (slave->link_failure_count < UINT_MAX) slave->link_failure_count++; @@ -2700,7 +2753,7 @@ static bool bond_ab_arp_probe(struct bonding *bond) if (!new_slave) goto check_state; - new_slave->link = BOND_LINK_BACK; + bond_set_slave_link_state(new_slave, BOND_LINK_BACK); bond_set_slave_active_flags(new_slave, BOND_SLAVE_NOTIFY_LATER); bond_arp_send_all(bond, new_slave); new_slave->last_link_up = jiffies; @@ -3066,7 +3119,7 @@ static int bond_open(struct net_device *bond_dev) slave != rcu_access_pointer(bond->curr_active_slave)) { bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW); - } else { + } else if (BOND_MODE(bond) != BOND_MODE_8023AD) { bond_set_slave_active_flags(slave, BOND_SLAVE_NOTIFY_NOW); } @@ -3734,7 +3787,7 @@ out: * usable slave array is formed in the control path. The xmit function * just calculates hash and sends the packet out. */ -int bond_3ad_xor_xmit(struct sk_buff *skb, struct net_device *dev) +static int bond_3ad_xor_xmit(struct sk_buff *skb, struct net_device *dev) { struct bonding *bond = netdev_priv(dev); struct slave *slave; @@ -3952,6 +4005,8 @@ static const struct net_device_ops bond_netdev_ops = { .ndo_add_slave = bond_enslave, .ndo_del_slave = bond_release, .ndo_fix_features = bond_fix_features, + .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink, + .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink, }; static const struct device_type bond_type = { @@ -4010,7 +4065,7 @@ void bond_setup(struct net_device *bond_dev) NETIF_F_HW_VLAN_CTAG_FILTER; bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM); - bond_dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL; + bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL; bond_dev->features |= bond_dev->hw_features; } diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 1a61cc9b3402..4df28943d222 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -186,7 +186,7 @@ static const struct bond_opt_value bond_tlb_dynamic_lb_tbl[] = { { NULL, -1, 0} }; -static const struct bond_option bond_opts[] = { +static const struct bond_option bond_opts[BOND_OPT_LAST] = { [BOND_OPT_MODE] = { .id = BOND_OPT_MODE, .name = "mode", @@ -379,8 +379,7 @@ static const struct bond_option bond_opts[] = { .values = bond_tlb_dynamic_lb_tbl, .flags = BOND_OPTFLAG_IFDOWN, .set = bond_option_tlb_dynamic_lb_set, - }, - { } + } }; /* Searches for an option by name */ @@ -1182,6 +1181,7 @@ static int bond_option_min_links_set(struct bonding *bond, netdev_info(bond->dev, "Setting min links value to %llu\n", newval->value); bond->params.min_links = newval->value; + bond_set_carrier(bond); return 0; } diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c index 5e40a8b68cbe..b3b922adc0e4 100644 --- a/drivers/net/caif/caif_hsi.c +++ b/drivers/net/caif/caif_hsi.c @@ -1415,7 +1415,6 @@ static int caif_hsi_newlink(struct net *src_net, struct net_device *dev, cfhsi = netdev_priv(dev); cfhsi_netlink_parms(data, cfhsi); - dev_net_set(cfhsi->ndev, src_net); get_ops = symbol_get(cfhsi_get_ops); if (!get_ops) { diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index d0c2463b573f..eeb4b8b6b335 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -138,7 +138,6 @@ struct at91_devtype_data { struct at91_priv { struct can_priv can; /* must be the first member! */ - struct net_device *dev; struct napi_struct napi; void __iomem *reg_base; @@ -1350,7 +1349,6 @@ static int at91_can_probe(struct platform_device *pdev) priv->can.do_get_berr_counter = at91_get_berr_counter; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY; - priv->dev = dev; priv->reg_base = addr; priv->devtype_data = *devtype_data; priv->clk = clk; diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c index 417d50998e31..e7a6363e736b 100644 --- a/drivers/net/can/bfin_can.c +++ b/drivers/net/can/bfin_can.c @@ -352,6 +352,7 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status) netdev_dbg(dev, "bus-off mode interrupt\n"); state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; + priv->can.can_stats.bus_off++; can_bus_off(dev); } diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index f94a9fa60488..041525d2595c 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -615,6 +615,9 @@ static void c_can_stop(struct net_device *dev) c_can_irq_control(priv, false); + /* put ctrl to init on stop to end ongoing transmission */ + priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_INIT); + /* deactivate pins */ pinctrl_pm_select_sleep_state(dev->dev.parent); priv->can.state = CAN_STATE_STOPPED; @@ -866,7 +869,7 @@ static int c_can_handle_state_change(struct net_device *dev, case C_CAN_BUS_OFF: /* bus-off state */ priv->can.state = CAN_STATE_BUS_OFF; - can_bus_off(dev); + priv->can.can_stats.bus_off++; break; default: break; diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index f363972cd77d..e36d10520e24 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -103,27 +103,34 @@ static void c_can_hw_raminit_syscon(const struct c_can_priv *priv, bool enable) mask = 1 << raminit->bits.start | 1 << raminit->bits.done; regmap_read(raminit->syscon, raminit->reg, &ctrl); - /* We clear the done and start bit first. The start bit is + /* We clear the start bit first. The start bit is * looking at the 0 -> transition, but is not self clearing; - * And we clear the init done bit as well. * NOTE: DONE must be written with 1 to clear it. + * We can't clear the DONE bit here using regmap_update_bits() + * as it will bypass the write if initial condition is START:0 DONE:1 + * e.g. on DRA7 which needs START pulse. */ - ctrl &= ~(1 << raminit->bits.start); - ctrl |= 1 << raminit->bits.done; - regmap_write(raminit->syscon, raminit->reg, ctrl); + ctrl &= ~mask; /* START = 0, DONE = 0 */ + regmap_update_bits(raminit->syscon, raminit->reg, mask, ctrl); - ctrl &= ~(1 << raminit->bits.done); - c_can_hw_raminit_wait_syscon(priv, mask, ctrl); + /* check if START bit is 0. Ignore DONE bit for now + * as it can be either 0 or 1. + */ + c_can_hw_raminit_wait_syscon(priv, 1 << raminit->bits.start, ctrl); if (enable) { - /* Set start bit and wait for the done bit. */ + /* Clear DONE bit & set START bit. */ ctrl |= 1 << raminit->bits.start; - regmap_write(raminit->syscon, raminit->reg, ctrl); - + /* DONE must be written with 1 to clear it */ + ctrl |= 1 << raminit->bits.done; + regmap_update_bits(raminit->syscon, raminit->reg, mask, ctrl); + /* prevent further clearing of DONE bit */ + ctrl &= ~(1 << raminit->bits.done); /* clear START bit if start pulse is needed */ if (raminit->needs_pulse) { ctrl &= ~(1 << raminit->bits.start); - regmap_write(raminit->syscon, raminit->reg, ctrl); + regmap_update_bits(raminit->syscon, raminit->reg, + mask, ctrl); } ctrl |= 1 << raminit->bits.done; diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c index c486fe510f37..c11d44984036 100644 --- a/drivers/net/can/cc770/cc770.c +++ b/drivers/net/can/cc770/cc770.c @@ -535,6 +535,7 @@ static int cc770_err(struct net_device *dev, u8 status) cc770_write_reg(priv, control, CTRL_INI); cf->can_id |= CAN_ERR_BUSOFF; priv->can.state = CAN_STATE_BUS_OFF; + priv->can.can_stats.bus_off++; can_bus_off(dev); } else if (status & STAT_WARN) { cf->can_id |= CAN_ERR_CRTL; diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 3ec8f6f25e5f..3c82e02e3dae 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -289,9 +289,11 @@ static void can_update_state_error_stats(struct net_device *dev, priv->can_stats.error_passive++; break; case CAN_STATE_BUS_OFF: + priv->can_stats.bus_off++; + break; default: break; - }; + } } static int can_tx_state_to_frame(struct net_device *dev, enum can_state state) @@ -544,7 +546,6 @@ void can_bus_off(struct net_device *dev) netdev_dbg(dev, "bus-off\n"); netif_carrier_off(dev); - priv->can_stats.bus_off++; if (priv->restart_ms) mod_timer(&priv->restart_timer, @@ -807,10 +808,14 @@ static int can_changelink(struct net_device *dev, if (dev->flags & IFF_UP) return -EBUSY; cm = nla_data(data[IFLA_CAN_CTRLMODE]); - if (cm->flags & ~priv->ctrlmode_supported) + + /* check whether changed bits are allowed to be modified */ + if (cm->mask & ~priv->ctrlmode_supported) return -EOPNOTSUPP; + + /* clear bits to be modified and copy the flag values */ priv->ctrlmode &= ~cm->mask; - priv->ctrlmode |= cm->flags; + priv->ctrlmode |= (cm->flags & cm->mask); /* CAN_CTRLMODE_FD can only be set when driver supports FD */ if (priv->ctrlmode & CAN_CTRLMODE_FD) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index b1d583ba9674..80c46ad4cee4 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -247,7 +247,6 @@ struct flexcan_devtype_data { struct flexcan_priv { struct can_priv can; - struct net_device *dev; struct napi_struct napi; void __iomem *base; @@ -1220,7 +1219,6 @@ static int flexcan_probe(struct platform_device *pdev) CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_BERR_REPORTING; priv->base = base; - priv->dev = dev; priv->clk_ipg = clk_ipg; priv->clk_per = clk_per; priv->pdata = dev_get_platdata(&pdev->dev); diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 1b118394907f..4dd183a3643a 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -1008,6 +1008,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) if (status & SR_BS) { state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; + mod->can.can_stats.bus_off++; can_bus_off(dev); } else if (status & SR_ES) { if (rxerr >= 128 || txerr >= 128) @@ -1678,8 +1679,7 @@ static int ican3_get_berr_counter(const struct net_device *ndev, if (ret) return ret; - ret = wait_for_completion_timeout(&mod->buserror_comp, HZ); - if (ret == 0) { + if (!wait_for_completion_timeout(&mod->buserror_comp, HZ)) { netdev_info(mod->ndev, "%s timed out\n", __func__); return -ETIMEDOUT; } @@ -1704,8 +1704,7 @@ static ssize_t ican3_sysfs_show_term(struct device *dev, if (ret) return ret; - ret = wait_for_completion_timeout(&mod->termination_comp, HZ); - if (ret == 0) { + if (!wait_for_completion_timeout(&mod->termination_comp, HZ)) { netdev_info(mod->ndev, "%s timed out\n", __func__); return -ETIMEDOUT; } diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index d7bc462aafdc..2e04b3aeeb37 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -589,6 +589,7 @@ static int m_can_handle_state_change(struct net_device *dev, /* bus-off state */ priv->can.state = CAN_STATE_BUS_OFF; m_can_disable_all_interrupts(priv); + priv->can.can_stats.bus_off++; can_bus_off(dev); break; default: @@ -955,6 +956,11 @@ static struct net_device *alloc_m_can_dev(void) priv->can.data_bittiming_const = &m_can_data_bittiming_const; priv->can.do_set_mode = m_can_set_mode; priv->can.do_get_berr_counter = m_can_get_berr_counter; + + /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.1 */ + priv->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO; + + /* CAN_CTRLMODE_FD_NON_ISO can not be changed with M_CAN IP v3.0.1 */ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING | diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c index a67eb01f3028..e187ca783da0 100644 --- a/drivers/net/can/pch_can.c +++ b/drivers/net/can/pch_can.c @@ -505,6 +505,7 @@ static void pch_can_error(struct net_device *ndev, u32 status) pch_can_set_rx_all(priv, 0); state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; + priv->can.can_stats.bus_off++; can_bus_off(ndev); } diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c index 91cd48ca0efc..7deb80dcbe8c 100644 --- a/drivers/net/can/rcar_can.c +++ b/drivers/net/can/rcar_can.c @@ -331,6 +331,7 @@ static void rcar_can_error(struct net_device *ndev) priv->can.state = CAN_STATE_BUS_OFF; /* Clear interrupt condition */ writeb(~RCAR_CAN_EIFR_BOEIF, &priv->regs->eifr); + priv->can.can_stats.bus_off++; can_bus_off(ndev); if (skb) cf->can_id |= CAN_ERR_BUSOFF; diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c index 2bf98d862302..7621f91a8a20 100644 --- a/drivers/net/can/softing/softing_main.c +++ b/drivers/net/can/softing/softing_main.c @@ -261,6 +261,7 @@ static int softing_handle_1(struct softing *card) ++priv->can.can_stats.error_passive; else if (can_state == CAN_STATE_BUS_OFF) { /* this calls can_close_cleanup() */ + ++priv->can.can_stats.bus_off; can_bus_off(netdev); netif_stop_queue(netdev); } diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index c66d699640a9..bf63fee4e743 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -905,6 +905,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id) if (priv->can.state == CAN_STATE_BUS_OFF) { if (priv->can.restart_ms == 0) { priv->force_quit = 1; + priv->can.can_stats.bus_off++; can_bus_off(net); mcp251x_hw_sleep(spi); break; diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 9a07eafe554b..e95a9e1a889f 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -715,6 +715,7 @@ static int ti_hecc_error(struct net_device *ndev, int int_status, hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_CCR); /* Disable all interrupts in bus-off to avoid int hog */ hecc_write(priv, HECC_CANGIM, 0); + ++priv->can.can_stats.bus_off; can_bus_off(ndev); } diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig index a77db919363c..bcb272f6c68a 100644 --- a/drivers/net/can/usb/Kconfig +++ b/drivers/net/can/usb/Kconfig @@ -25,7 +25,7 @@ config CAN_KVASER_USB tristate "Kvaser CAN/USB interface" ---help--- This driver adds support for Kvaser CAN/USB devices like Kvaser - Leaf Light. + Leaf Light and Kvaser USBcan II. The driver provides support for the following devices: - Kvaser Leaf Light @@ -46,6 +46,12 @@ config CAN_KVASER_USB - Kvaser USBcan R - Kvaser Leaf Light v2 - Kvaser Mini PCI Express HS + - Kvaser USBcan II HS/HS + - Kvaser USBcan II HS/LS + - Kvaser USBcan Rugged ("USBcan Rev B") + - Kvaser Memorator HS/HS + - Kvaser Memorator HS/LS + - Scania VCI2 (if you have the Kvaser logo on top) If unsure, say N. @@ -53,10 +59,18 @@ config CAN_KVASER_USB module will be called kvaser_usb. config CAN_PEAK_USB - tristate "PEAK PCAN-USB/USB Pro interfaces" + tristate "PEAK PCAN-USB/USB Pro interfaces for CAN 2.0b/CAN-FD" ---help--- - This driver supports the PCAN-USB and PCAN-USB Pro adapters - from PEAK-System Technik (http://www.peak-system.com). + This driver supports the PEAK-System Technik USB adapters that enable + access to the CAN bus, with repect to the CAN 2.0b and/or CAN-FD + standards, that is: + + PCAN-USB single CAN 2.0b channel USB adapter + PCAN-USB Pro dual CAN 2.0b channels USB adapter + PCAN-USB FD single CAN-FD channel USB adapter + PCAN-USB Pro FD dual CAN-FD channels USB adapter + + (see also http://www.peak-system.com). config CAN_8DEV_USB tristate "8 devices USB2CAN interface" diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 29d3f0938eb8..9376f5e5b94e 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -347,6 +347,7 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg) dev->can.state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; + dev->can.can_stats.bus_off++; can_bus_off(dev->netdev); } else if (state & SJA1000_SR_ES) { dev->can.state = CAN_STATE_ERROR_WARNING; diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index c063a54ab8dd..bacca0bd89c1 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -250,6 +250,7 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv, case ESD_BUSSTATE_BUSOFF: priv->can.state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; + priv->can.can_stats.bus_off++; can_bus_off(priv->netdev); break; case ESD_BUSSTATE_WARN: diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 541fb7a05625..2928f7003041 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -6,10 +6,12 @@ * Parts of this driver are based on the following: * - Kvaser linux leaf driver (version 4.78) * - CAN driver for esd CAN-USB/2 + * - Kvaser linux usbcanII driver (version 5.3) * * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved. * Copyright (C) 2010 Matthias Fuchs , esd gmbh * Copyright (C) 2012 Olivier Sobrie + * Copyright (C) 2015 Valeo S.A. */ #include @@ -30,8 +32,9 @@ #define RX_BUFFER_SIZE 3072 #define CAN_USB_CLOCK 8000000 #define MAX_NET_DEVICES 3 +#define MAX_USBCAN_NET_DEVICES 2 -/* Kvaser USB devices */ +/* Kvaser Leaf USB devices */ #define KVASER_VENDOR_ID 0x0bfd #define USB_LEAF_DEVEL_PRODUCT_ID 10 #define USB_LEAF_LITE_PRODUCT_ID 11 @@ -56,6 +59,24 @@ #define USB_LEAF_LITE_V2_PRODUCT_ID 288 #define USB_MINI_PCIE_HS_PRODUCT_ID 289 +static inline bool kvaser_is_leaf(const struct usb_device_id *id) +{ + return id->idProduct >= USB_LEAF_DEVEL_PRODUCT_ID && + id->idProduct <= USB_MINI_PCIE_HS_PRODUCT_ID; +} + +/* Kvaser USBCan-II devices */ +#define USB_USBCAN_REVB_PRODUCT_ID 2 +#define USB_VCI2_PRODUCT_ID 3 +#define USB_USBCAN2_PRODUCT_ID 4 +#define USB_MEMORATOR_PRODUCT_ID 5 + +static inline bool kvaser_is_usbcan(const struct usb_device_id *id) +{ + return id->idProduct >= USB_USBCAN_REVB_PRODUCT_ID && + id->idProduct <= USB_MEMORATOR_PRODUCT_ID; +} + /* USB devices features */ #define KVASER_HAS_SILENT_MODE BIT(0) #define KVASER_HAS_TXRX_ERRORS BIT(1) @@ -73,7 +94,7 @@ #define MSG_FLAG_TX_ACK BIT(6) #define MSG_FLAG_TX_REQUEST BIT(7) -/* Can states */ +/* Can states (M16C CxSTRH register) */ #define M16C_STATE_BUS_RESET BIT(0) #define M16C_STATE_BUS_ERROR BIT(4) #define M16C_STATE_BUS_PASSIVE BIT(5) @@ -98,7 +119,11 @@ #define CMD_START_CHIP_REPLY 27 #define CMD_STOP_CHIP 28 #define CMD_STOP_CHIP_REPLY 29 -#define CMD_GET_CARD_INFO2 32 + +#define CMD_LEAF_GET_CARD_INFO2 32 +#define CMD_USBCAN_RESET_CLOCK 32 +#define CMD_USBCAN_CLOCK_OVERFLOW_EVENT 33 + #define CMD_GET_CARD_INFO 34 #define CMD_GET_CARD_INFO_REPLY 35 #define CMD_GET_SOFTWARE_INFO 38 @@ -108,8 +133,9 @@ #define CMD_RESET_ERROR_COUNTER 49 #define CMD_TX_ACKNOWLEDGE 50 #define CMD_CAN_ERROR_EVENT 51 -#define CMD_USB_THROTTLE 77 -#define CMD_LOG_MESSAGE 106 + +#define CMD_LEAF_USB_THROTTLE 77 +#define CMD_LEAF_LOG_MESSAGE 106 /* error factors */ #define M16C_EF_ACKE BIT(0) @@ -121,6 +147,14 @@ #define M16C_EF_RCVE BIT(6) #define M16C_EF_TRE BIT(7) +/* Only Leaf-based devices can report M16C error factors, + * thus define our own error status flags for USBCANII + */ +#define USBCAN_ERROR_STATE_NONE 0 +#define USBCAN_ERROR_STATE_TX_ERROR BIT(0) +#define USBCAN_ERROR_STATE_RX_ERROR BIT(1) +#define USBCAN_ERROR_STATE_BUSERROR BIT(2) + /* bittiming parameters */ #define KVASER_USB_TSEG1_MIN 1 #define KVASER_USB_TSEG1_MAX 16 @@ -137,9 +171,18 @@ #define KVASER_CTRL_MODE_SELFRECEPTION 3 #define KVASER_CTRL_MODE_OFF 4 -/* log message */ +/* Extended CAN identifier flag */ #define KVASER_EXTENDED_FRAME BIT(31) +/* Kvaser USB CAN dongles are divided into two major families: + * - Leaf: Based on Renesas M32C, running firmware labeled as 'filo' + * - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios' + */ +enum kvaser_usb_family { + KVASER_LEAF, + KVASER_USBCAN, +}; + struct kvaser_msg_simple { u8 tid; u8 channel; @@ -148,30 +191,55 @@ struct kvaser_msg_simple { struct kvaser_msg_cardinfo { u8 tid; u8 nchannels; - __le32 serial_number; - __le32 padding; + union { + struct { + __le32 serial_number; + __le32 padding; + } __packed leaf0; + struct { + __le32 serial_number_low; + __le32 serial_number_high; + } __packed usbcan0; + } __packed; __le32 clock_resolution; __le32 mfgdate; u8 ean[8]; u8 hw_revision; - u8 usb_hs_mode; - __le16 padding2; + union { + struct { + u8 usb_hs_mode; + } __packed leaf1; + struct { + u8 padding; + } __packed usbcan1; + } __packed; + __le16 padding; } __packed; struct kvaser_msg_cardinfo2 { u8 tid; - u8 channel; + u8 reserved; u8 pcb_id[24]; __le32 oem_unlock_code; } __packed; -struct kvaser_msg_softinfo { +struct leaf_msg_softinfo { u8 tid; - u8 channel; + u8 padding0; __le32 sw_options; __le32 fw_version; __le16 max_outstanding_tx; - __le16 padding[9]; + __le16 padding1[9]; +} __packed; + +struct usbcan_msg_softinfo { + u8 tid; + u8 fw_name[5]; + __le16 max_outstanding_tx; + u8 padding[6]; + __le32 fw_version; + __le16 checksum; + __le16 sw_options; } __packed; struct kvaser_msg_busparams { @@ -188,36 +256,86 @@ struct kvaser_msg_tx_can { u8 channel; u8 tid; u8 msg[14]; - u8 padding; - u8 flags; + union { + struct { + u8 padding; + u8 flags; + } __packed leaf; + struct { + u8 flags; + u8 padding; + } __packed usbcan; + } __packed; } __packed; -struct kvaser_msg_rx_can { +struct kvaser_msg_rx_can_header { u8 channel; u8 flag; +} __packed; + +struct leaf_msg_rx_can { + u8 channel; + u8 flag; + __le16 time[3]; u8 msg[14]; } __packed; -struct kvaser_msg_chip_state_event { +struct usbcan_msg_rx_can { + u8 channel; + u8 flag; + + u8 msg[14]; + __le16 time; +} __packed; + +struct leaf_msg_chip_state_event { u8 tid; u8 channel; + __le16 time[3]; u8 tx_errors_count; u8 rx_errors_count; + u8 status; u8 padding[3]; } __packed; -struct kvaser_msg_tx_acknowledge { +struct usbcan_msg_chip_state_event { + u8 tid; + u8 channel; + + u8 tx_errors_count; + u8 rx_errors_count; + __le16 time; + + u8 status; + u8 padding[3]; +} __packed; + +struct kvaser_msg_tx_acknowledge_header { u8 channel; u8 tid; +} __packed; + +struct leaf_msg_tx_acknowledge { + u8 channel; + u8 tid; + __le16 time[3]; u8 flags; u8 time_offset; } __packed; -struct kvaser_msg_error_event { +struct usbcan_msg_tx_acknowledge { + u8 channel; + u8 tid; + + __le16 time; + __le16 padding; +} __packed; + +struct leaf_msg_error_event { u8 tid; u8 flags; __le16 time[3]; @@ -229,6 +347,18 @@ struct kvaser_msg_error_event { u8 error_factor; } __packed; +struct usbcan_msg_error_event { + u8 tid; + u8 padding; + u8 tx_errors_count_ch0; + u8 rx_errors_count_ch0; + u8 tx_errors_count_ch1; + u8 rx_errors_count_ch1; + u8 status_ch0; + u8 status_ch1; + __le16 time; +} __packed; + struct kvaser_msg_ctrl_mode { u8 tid; u8 channel; @@ -243,7 +373,7 @@ struct kvaser_msg_flush_queue { u8 padding[3]; } __packed; -struct kvaser_msg_log_message { +struct leaf_msg_log_message { u8 channel; u8 flags; __le16 time[3]; @@ -260,19 +390,57 @@ struct kvaser_msg { struct kvaser_msg_simple simple; struct kvaser_msg_cardinfo cardinfo; struct kvaser_msg_cardinfo2 cardinfo2; - struct kvaser_msg_softinfo softinfo; struct kvaser_msg_busparams busparams; + + struct kvaser_msg_rx_can_header rx_can_header; + struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header; + + union { + struct leaf_msg_softinfo softinfo; + struct leaf_msg_rx_can rx_can; + struct leaf_msg_chip_state_event chip_state_event; + struct leaf_msg_tx_acknowledge tx_acknowledge; + struct leaf_msg_error_event error_event; + struct leaf_msg_log_message log_message; + } __packed leaf; + + union { + struct usbcan_msg_softinfo softinfo; + struct usbcan_msg_rx_can rx_can; + struct usbcan_msg_chip_state_event chip_state_event; + struct usbcan_msg_tx_acknowledge tx_acknowledge; + struct usbcan_msg_error_event error_event; + } __packed usbcan; + struct kvaser_msg_tx_can tx_can; - struct kvaser_msg_rx_can rx_can; - struct kvaser_msg_chip_state_event chip_state_event; - struct kvaser_msg_tx_acknowledge tx_acknowledge; - struct kvaser_msg_error_event error_event; struct kvaser_msg_ctrl_mode ctrl_mode; struct kvaser_msg_flush_queue flush_queue; - struct kvaser_msg_log_message log_message; } u; } __packed; +/* Summary of a kvaser error event, for a unified Leaf/Usbcan error + * handling. Some discrepancies between the two families exist: + * + * - USBCAN firmware does not report M16C "error factors" + * - USBCAN controllers has difficulties reporting if the raised error + * event is for ch0 or ch1. They leave such arbitration to the OS + * driver by letting it compare error counters with previous values + * and decide the error event's channel. Thus for USBCAN, the channel + * field is only advisory. + */ +struct kvaser_usb_error_summary { + u8 channel, status, txerr, rxerr; + union { + struct { + u8 error_factor; + } leaf; + struct { + u8 other_ch_status; + u8 error_state; + } usbcan; + }; +}; + struct kvaser_usb_tx_urb_context { struct kvaser_usb_net_priv *priv; u32 echo_index; @@ -288,6 +456,7 @@ struct kvaser_usb { u32 fw_version; unsigned int nchannels; + enum kvaser_usb_family family; bool rxinitdone; void *rxbuf[MAX_RX_URBS]; @@ -311,6 +480,7 @@ struct kvaser_usb_net_priv { }; static const struct usb_device_id kvaser_usb_table[] = { + /* Leaf family IDs */ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) }, { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) }, { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID), @@ -360,6 +530,17 @@ static const struct usb_device_id kvaser_usb_table[] = { .driver_info = KVASER_HAS_TXRX_ERRORS }, { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) }, { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) }, + + /* USBCANII family IDs */ + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { } }; MODULE_DEVICE_TABLE(usb, kvaser_usb_table); @@ -463,7 +644,14 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev) if (err) return err; - dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version); + switch (dev->family) { + case KVASER_LEAF: + dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version); + break; + case KVASER_USBCAN: + dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version); + break; + } return 0; } @@ -482,7 +670,9 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev) return err; dev->nchannels = msg.u.cardinfo.nchannels; - if (dev->nchannels > MAX_NET_DEVICES) + if ((dev->nchannels > MAX_NET_DEVICES) || + (dev->family == KVASER_USBCAN && + dev->nchannels > MAX_USBCAN_NET_DEVICES)) return -EINVAL; return 0; @@ -496,8 +686,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev, struct kvaser_usb_net_priv *priv; struct sk_buff *skb; struct can_frame *cf; - u8 channel = msg->u.tx_acknowledge.channel; - u8 tid = msg->u.tx_acknowledge.tid; + u8 channel, tid; + + channel = msg->u.tx_acknowledge_header.channel; + tid = msg->u.tx_acknowledge_header.tid; if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent, @@ -520,10 +712,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev, skb = alloc_can_err_skb(priv->netdev, &cf); if (skb) { cf->can_id |= CAN_ERR_RESTARTED; - netif_rx(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); } else { netdev_err(priv->netdev, "No memory left for err_skb\n"); @@ -587,7 +779,7 @@ static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv, usb_sndbulkpipe(dev->udev, dev->bulk_out->bEndpointAddress), buf, msg->len, - kvaser_usb_simple_msg_callback, priv); + kvaser_usb_simple_msg_callback, netdev); usb_anchor_urb(urb, &priv->tx_submitted); err = usb_submit_urb(urb, GFP_ATOMIC); @@ -615,44 +807,175 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) priv->tx_contexts[i].echo_index = MAX_TX_URBS; } -static void kvaser_usb_rx_error(const struct kvaser_usb *dev, - const struct kvaser_msg *msg) +static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *priv, + const struct kvaser_usb_error_summary *es, + struct can_frame *cf) { - struct can_frame *cf; + struct kvaser_usb *dev = priv->dev; + struct net_device_stats *stats = &priv->netdev->stats; + enum can_state cur_state, new_state, tx_state, rx_state; + + netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status); + + new_state = cur_state = priv->can.state; + + if (es->status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) + new_state = CAN_STATE_BUS_OFF; + else if (es->status & M16C_STATE_BUS_PASSIVE) + new_state = CAN_STATE_ERROR_PASSIVE; + else if (es->status & M16C_STATE_BUS_ERROR) { + /* Guard against spurious error events after a busoff */ + if (cur_state < CAN_STATE_BUS_OFF) { + if ((es->txerr >= 128) || (es->rxerr >= 128)) + new_state = CAN_STATE_ERROR_PASSIVE; + else if ((es->txerr >= 96) || (es->rxerr >= 96)) + new_state = CAN_STATE_ERROR_WARNING; + else if (cur_state > CAN_STATE_ERROR_ACTIVE) + new_state = CAN_STATE_ERROR_ACTIVE; + } + } + + if (!es->status) + new_state = CAN_STATE_ERROR_ACTIVE; + + if (new_state != cur_state) { + tx_state = (es->txerr >= es->rxerr) ? new_state : 0; + rx_state = (es->txerr <= es->rxerr) ? new_state : 0; + + can_change_state(priv->netdev, cf, tx_state, rx_state); + } + + if (priv->can.restart_ms && + (cur_state >= CAN_STATE_BUS_OFF) && + (new_state < CAN_STATE_BUS_OFF)) { + priv->can.can_stats.restarts++; + } + + switch (dev->family) { + case KVASER_LEAF: + if (es->leaf.error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + } + break; + case KVASER_USBCAN: + if (es->usbcan.error_state & USBCAN_ERROR_STATE_TX_ERROR) + stats->tx_errors++; + if (es->usbcan.error_state & USBCAN_ERROR_STATE_RX_ERROR) + stats->rx_errors++; + if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR) { + priv->can.can_stats.bus_error++; + } + break; + } + + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr; +} + +static void kvaser_usb_rx_error(const struct kvaser_usb *dev, + const struct kvaser_usb_error_summary *es) +{ + struct can_frame *cf, tmp_cf = { .can_id = CAN_ERR_FLAG, .can_dlc = CAN_ERR_DLC }; struct sk_buff *skb; struct net_device_stats *stats; struct kvaser_usb_net_priv *priv; - unsigned int new_state; - u8 channel, status, txerr, rxerr, error_factor; + enum can_state old_state, new_state; - switch (msg->id) { - case CMD_CAN_ERROR_EVENT: - channel = msg->u.error_event.channel; - status = msg->u.error_event.status; - txerr = msg->u.error_event.tx_errors_count; - rxerr = msg->u.error_event.rx_errors_count; - error_factor = msg->u.error_event.error_factor; - break; - case CMD_LOG_MESSAGE: - channel = msg->u.log_message.channel; - status = msg->u.log_message.data[0]; - txerr = msg->u.log_message.data[2]; - rxerr = msg->u.log_message.data[3]; - error_factor = msg->u.log_message.data[1]; - break; - case CMD_CHIP_STATE_EVENT: - channel = msg->u.chip_state_event.channel; - status = msg->u.chip_state_event.status; - txerr = msg->u.chip_state_event.tx_errors_count; - rxerr = msg->u.chip_state_event.rx_errors_count; - error_factor = 0; - break; - default: - dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n", - msg->id); + if (es->channel >= dev->nchannels) { + dev_err(dev->udev->dev.parent, + "Invalid channel number (%d)\n", es->channel); return; } + priv = dev->nets[es->channel]; + stats = &priv->netdev->stats; + + /* Update all of the can interface's state and error counters before + * trying any memory allocation that can actually fail with -ENOMEM. + * + * We send a temporary stack-allocated error can frame to + * can_change_state() for the very same reason. + * + * TODO: Split can_change_state() responsibility between updating the + * can interface's state and counters, and the setting up of can error + * frame ID and data to userspace. Remove stack allocation afterwards. + */ + old_state = priv->can.state; + kvaser_usb_rx_error_update_can_state(priv, es, &tmp_cf); + new_state = priv->can.state; + + skb = alloc_can_err_skb(priv->netdev, &cf); + if (!skb) { + stats->rx_dropped++; + return; + } + memcpy(cf, &tmp_cf, sizeof(*cf)); + + if (new_state != old_state) { + if (es->status & + (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) { + if (!priv->can.restart_ms) + kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP); + netif_carrier_off(priv->netdev); + } + + if (priv->can.restart_ms && + (old_state >= CAN_STATE_BUS_OFF) && + (new_state < CAN_STATE_BUS_OFF)) { + cf->can_id |= CAN_ERR_RESTARTED; + netif_carrier_on(priv->netdev); + } + } + + switch (dev->family) { + case KVASER_LEAF: + if (es->leaf.error_factor) { + cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; + + if (es->leaf.error_factor & M16C_EF_ACKE) + cf->data[3] |= (CAN_ERR_PROT_LOC_ACK); + if (es->leaf.error_factor & M16C_EF_CRCE) + cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | + CAN_ERR_PROT_LOC_CRC_DEL); + if (es->leaf.error_factor & M16C_EF_FORME) + cf->data[2] |= CAN_ERR_PROT_FORM; + if (es->leaf.error_factor & M16C_EF_STFE) + cf->data[2] |= CAN_ERR_PROT_STUFF; + if (es->leaf.error_factor & M16C_EF_BITE0) + cf->data[2] |= CAN_ERR_PROT_BIT0; + if (es->leaf.error_factor & M16C_EF_BITE1) + cf->data[2] |= CAN_ERR_PROT_BIT1; + if (es->leaf.error_factor & M16C_EF_TRE) + cf->data[2] |= CAN_ERR_PROT_TX; + } + break; + case KVASER_USBCAN: + if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR) { + cf->can_id |= CAN_ERR_BUSERROR; + } + break; + } + + cf->data[6] = es->txerr; + cf->data[7] = es->rxerr; + + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + netif_rx(skb); +} + +/* For USBCAN, report error to userspace iff the channels's errors counter + * has changed, or we're the only channel seeing a bus error state. + */ +static void kvaser_usbcan_conditionally_rx_error(const struct kvaser_usb *dev, + struct kvaser_usb_error_summary *es) +{ + struct kvaser_usb_net_priv *priv; + int channel; + bool report_error; + + channel = es->channel; if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent, "Invalid channel number (%d)\n", channel); @@ -660,120 +983,104 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } priv = dev->nets[channel]; - stats = &priv->netdev->stats; + report_error = false; - if (status & M16C_STATE_BUS_RESET) { - kvaser_usb_unlink_tx_urbs(priv); + if (es->txerr != priv->bec.txerr) { + es->usbcan.error_state |= USBCAN_ERROR_STATE_TX_ERROR; + report_error = true; + } + if (es->rxerr != priv->bec.rxerr) { + es->usbcan.error_state |= USBCAN_ERROR_STATE_RX_ERROR; + report_error = true; + } + if ((es->status & M16C_STATE_BUS_ERROR) && + !(es->usbcan.other_ch_status & M16C_STATE_BUS_ERROR)) { + es->usbcan.error_state |= USBCAN_ERROR_STATE_BUSERROR; + report_error = true; + } + + if (report_error) + kvaser_usb_rx_error(dev, es); +} + +static void kvaser_usbcan_rx_error(const struct kvaser_usb *dev, + const struct kvaser_msg *msg) +{ + struct kvaser_usb_error_summary es = { }; + + switch (msg->id) { + /* Sometimes errors are sent as unsolicited chip state events */ + case CMD_CHIP_STATE_EVENT: + es.channel = msg->u.usbcan.chip_state_event.channel; + es.status = msg->u.usbcan.chip_state_event.status; + es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count; + es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count; + kvaser_usbcan_conditionally_rx_error(dev, &es); + break; + + case CMD_CAN_ERROR_EVENT: + es.channel = 0; + es.status = msg->u.usbcan.error_event.status_ch0; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch1; + kvaser_usbcan_conditionally_rx_error(dev, &es); + + /* The USBCAN firmware supports up to 2 channels. + * Now that ch0 was checked, check if ch1 has any errors. + */ + if (dev->nchannels == MAX_USBCAN_NET_DEVICES) { + es.channel = 1; + es.status = msg->u.usbcan.error_event.status_ch1; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch1; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch1; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch0; + kvaser_usbcan_conditionally_rx_error(dev, &es); + } + break; + + default: + dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n", + msg->id); + } +} + +static void kvaser_leaf_rx_error(const struct kvaser_usb *dev, + const struct kvaser_msg *msg) +{ + struct kvaser_usb_error_summary es = { }; + + switch (msg->id) { + case CMD_CAN_ERROR_EVENT: + es.channel = msg->u.leaf.error_event.channel; + es.status = msg->u.leaf.error_event.status; + es.txerr = msg->u.leaf.error_event.tx_errors_count; + es.rxerr = msg->u.leaf.error_event.rx_errors_count; + es.leaf.error_factor = msg->u.leaf.error_event.error_factor; + break; + case CMD_LEAF_LOG_MESSAGE: + es.channel = msg->u.leaf.log_message.channel; + es.status = msg->u.leaf.log_message.data[0]; + es.txerr = msg->u.leaf.log_message.data[2]; + es.rxerr = msg->u.leaf.log_message.data[3]; + es.leaf.error_factor = msg->u.leaf.log_message.data[1]; + break; + case CMD_CHIP_STATE_EVENT: + es.channel = msg->u.leaf.chip_state_event.channel; + es.status = msg->u.leaf.chip_state_event.status; + es.txerr = msg->u.leaf.chip_state_event.tx_errors_count; + es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count; + es.leaf.error_factor = 0; + break; + default: + dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n", + msg->id); return; } - skb = alloc_can_err_skb(priv->netdev, &cf); - if (!skb) { - stats->rx_dropped++; - return; - } - - new_state = priv->can.state; - - netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status); - - if (status & M16C_STATE_BUS_OFF) { - cf->can_id |= CAN_ERR_BUSOFF; - - priv->can.can_stats.bus_off++; - if (!priv->can.restart_ms) - kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP); - - netif_carrier_off(priv->netdev); - - new_state = CAN_STATE_BUS_OFF; - } else if (status & M16C_STATE_BUS_PASSIVE) { - if (priv->can.state != CAN_STATE_ERROR_PASSIVE) { - cf->can_id |= CAN_ERR_CRTL; - - if (txerr || rxerr) - cf->data[1] = (txerr > rxerr) - ? CAN_ERR_CRTL_TX_PASSIVE - : CAN_ERR_CRTL_RX_PASSIVE; - else - cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE | - CAN_ERR_CRTL_RX_PASSIVE; - - priv->can.can_stats.error_passive++; - } - - new_state = CAN_STATE_ERROR_PASSIVE; - } - - if (status == M16C_STATE_BUS_ERROR) { - if ((priv->can.state < CAN_STATE_ERROR_WARNING) && - ((txerr >= 96) || (rxerr >= 96))) { - cf->can_id |= CAN_ERR_CRTL; - cf->data[1] = (txerr > rxerr) - ? CAN_ERR_CRTL_TX_WARNING - : CAN_ERR_CRTL_RX_WARNING; - - priv->can.can_stats.error_warning++; - new_state = CAN_STATE_ERROR_WARNING; - } else if (priv->can.state > CAN_STATE_ERROR_ACTIVE) { - cf->can_id |= CAN_ERR_PROT; - cf->data[2] = CAN_ERR_PROT_ACTIVE; - - new_state = CAN_STATE_ERROR_ACTIVE; - } - } - - if (!status) { - cf->can_id |= CAN_ERR_PROT; - cf->data[2] = CAN_ERR_PROT_ACTIVE; - - new_state = CAN_STATE_ERROR_ACTIVE; - } - - if (priv->can.restart_ms && - (priv->can.state >= CAN_STATE_BUS_OFF) && - (new_state < CAN_STATE_BUS_OFF)) { - cf->can_id |= CAN_ERR_RESTARTED; - netif_carrier_on(priv->netdev); - - priv->can.can_stats.restarts++; - } - - if (error_factor) { - priv->can.can_stats.bus_error++; - stats->rx_errors++; - - cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT; - - if (error_factor & M16C_EF_ACKE) - cf->data[3] |= (CAN_ERR_PROT_LOC_ACK); - if (error_factor & M16C_EF_CRCE) - cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | - CAN_ERR_PROT_LOC_CRC_DEL); - if (error_factor & M16C_EF_FORME) - cf->data[2] |= CAN_ERR_PROT_FORM; - if (error_factor & M16C_EF_STFE) - cf->data[2] |= CAN_ERR_PROT_STUFF; - if (error_factor & M16C_EF_BITE0) - cf->data[2] |= CAN_ERR_PROT_BIT0; - if (error_factor & M16C_EF_BITE1) - cf->data[2] |= CAN_ERR_PROT_BIT1; - if (error_factor & M16C_EF_TRE) - cf->data[2] |= CAN_ERR_PROT_TX; - } - - cf->data[6] = txerr; - cf->data[7] = rxerr; - - priv->bec.txerr = txerr; - priv->bec.rxerr = rxerr; - - priv->can.state = new_state; - - netif_rx(skb); - - stats->rx_packets++; - stats->rx_bytes += cf->can_dlc; + kvaser_usb_rx_error(dev, &es); } static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, @@ -783,16 +1090,19 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, struct sk_buff *skb; struct net_device_stats *stats = &priv->netdev->stats; - if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | + if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME | MSG_FLAG_NERR)) { netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n", - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); stats->rx_errors++; return; } - if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) { + if (msg->u.rx_can_header.flag & MSG_FLAG_OVERRUN) { + stats->rx_over_errors++; + stats->rx_errors++; + skb = alloc_can_err_skb(priv->netdev, &cf); if (!skb) { stats->rx_dropped++; @@ -802,13 +1112,9 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; - stats->rx_over_errors++; - stats->rx_errors++; - - netif_rx(skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); } } @@ -819,7 +1125,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, struct can_frame *cf; struct sk_buff *skb; struct net_device_stats *stats; - u8 channel = msg->u.rx_can.channel; + u8 channel = msg->u.rx_can_header.channel; + const u8 *rx_msg = NULL; /* GCC */ if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent, @@ -830,67 +1137,74 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, priv = dev->nets[channel]; stats = &priv->netdev->stats; - if ((msg->u.rx_can.flag & MSG_FLAG_ERROR_FRAME) && - (msg->id == CMD_LOG_MESSAGE)) { - kvaser_usb_rx_error(dev, msg); + if ((msg->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) && + (dev->family == KVASER_LEAF && msg->id == CMD_LEAF_LOG_MESSAGE)) { + kvaser_leaf_rx_error(dev, msg); return; - } else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | - MSG_FLAG_NERR | - MSG_FLAG_OVERRUN)) { + } else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME | + MSG_FLAG_NERR | + MSG_FLAG_OVERRUN)) { kvaser_usb_rx_can_err(priv, msg); return; - } else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) { + } else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME) { netdev_warn(priv->netdev, "Unhandled frame (flags: 0x%02x)", - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); return; } + switch (dev->family) { + case KVASER_LEAF: + rx_msg = msg->u.leaf.rx_can.msg; + break; + case KVASER_USBCAN: + rx_msg = msg->u.usbcan.rx_can.msg; + break; + } + skb = alloc_can_skb(priv->netdev, &cf); if (!skb) { stats->tx_dropped++; return; } - if (msg->id == CMD_LOG_MESSAGE) { - cf->can_id = le32_to_cpu(msg->u.log_message.id); + if (dev->family == KVASER_LEAF && msg->id == CMD_LEAF_LOG_MESSAGE) { + cf->can_id = le32_to_cpu(msg->u.leaf.log_message.id); if (cf->can_id & KVASER_EXTENDED_FRAME) cf->can_id &= CAN_EFF_MASK | CAN_EFF_FLAG; else cf->can_id &= CAN_SFF_MASK; - cf->can_dlc = get_can_dlc(msg->u.log_message.dlc); + cf->can_dlc = get_can_dlc(msg->u.leaf.log_message.dlc); - if (msg->u.log_message.flags & MSG_FLAG_REMOTE_FRAME) + if (msg->u.leaf.log_message.flags & MSG_FLAG_REMOTE_FRAME) cf->can_id |= CAN_RTR_FLAG; else - memcpy(cf->data, &msg->u.log_message.data, + memcpy(cf->data, &msg->u.leaf.log_message.data, cf->can_dlc); } else { - cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) | - (msg->u.rx_can.msg[1] & 0x3f); + cf->can_id = ((rx_msg[0] & 0x1f) << 6) | (rx_msg[1] & 0x3f); if (msg->id == CMD_RX_EXT_MESSAGE) { cf->can_id <<= 18; - cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) | - ((msg->u.rx_can.msg[3] & 0xff) << 6) | - (msg->u.rx_can.msg[4] & 0x3f); + cf->can_id |= ((rx_msg[2] & 0x0f) << 14) | + ((rx_msg[3] & 0xff) << 6) | + (rx_msg[4] & 0x3f); cf->can_id |= CAN_EFF_FLAG; } - cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]); + cf->can_dlc = get_can_dlc(rx_msg[5]); - if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME) + if (msg->u.rx_can_header.flag & MSG_FLAG_REMOTE_FRAME) cf->can_id |= CAN_RTR_FLAG; else - memcpy(cf->data, &msg->u.rx_can.msg[6], + memcpy(cf->data, &rx_msg[6], cf->can_dlc); } - netif_rx(skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + netif_rx(skb); } static void kvaser_usb_start_chip_reply(const struct kvaser_usb *dev, @@ -947,21 +1261,35 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev, case CMD_RX_STD_MESSAGE: case CMD_RX_EXT_MESSAGE: - case CMD_LOG_MESSAGE: + kvaser_usb_rx_can_msg(dev, msg); + break; + + case CMD_LEAF_LOG_MESSAGE: + if (dev->family != KVASER_LEAF) + goto warn; kvaser_usb_rx_can_msg(dev, msg); break; case CMD_CHIP_STATE_EVENT: case CMD_CAN_ERROR_EVENT: - kvaser_usb_rx_error(dev, msg); + if (dev->family == KVASER_LEAF) + kvaser_leaf_rx_error(dev, msg); + else + kvaser_usbcan_rx_error(dev, msg); break; case CMD_TX_ACKNOWLEDGE: kvaser_usb_tx_acknowledge(dev, msg); break; + /* Ignored messages */ + case CMD_USBCAN_CLOCK_OVERFLOW_EVENT: + if (dev->family != KVASER_USBCAN) + goto warn; + break; + default: - dev_warn(dev->udev->dev.parent, +warn: dev_warn(dev->udev->dev.parent, "Unhandled message (%d)\n", msg->id); break; } @@ -1181,7 +1509,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev) dev->rxbuf[i], dev->rxbuf_dma[i]); - for (i = 0; i < MAX_NET_DEVICES; i++) { + for (i = 0; i < dev->nchannels; i++) { struct kvaser_usb_net_priv *priv = dev->nets[i]; if (priv) @@ -1246,6 +1574,9 @@ static int kvaser_usb_close(struct net_device *netdev) if (err) netdev_warn(netdev, "Cannot stop device, error %d\n", err); + /* reset tx contexts */ + kvaser_usb_unlink_tx_urbs(priv); + priv->can.state = CAN_STATE_STOPPED; close_candev(priv->netdev); @@ -1286,6 +1617,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, struct kvaser_msg *msg; int i, err; int ret = NETDEV_TX_OK; + u8 *msg_tx_can_flags = NULL; /* GCC */ if (can_dropped_invalid_skb(netdev, skb)) return NETDEV_TX_OK; @@ -1294,20 +1626,32 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, if (!urb) { netdev_err(netdev, "No memory left for URBs\n"); stats->tx_dropped++; - goto nourbmem; + dev_kfree_skb(skb); + return NETDEV_TX_OK; } buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC); if (!buf) { stats->tx_dropped++; + dev_kfree_skb(skb); goto nobufmem; } msg = buf; msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can); - msg->u.tx_can.flags = 0; msg->u.tx_can.channel = priv->channel; + switch (dev->family) { + case KVASER_LEAF: + msg_tx_can_flags = &msg->u.tx_can.leaf.flags; + break; + case KVASER_USBCAN: + msg_tx_can_flags = &msg->u.tx_can.usbcan.flags; + break; + } + + *msg_tx_can_flags = 0; + if (cf->can_id & CAN_EFF_FLAG) { msg->id = CMD_TX_EXT_MESSAGE; msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f; @@ -1325,7 +1669,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc); if (cf->can_id & CAN_RTR_FLAG) - msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME; + *msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME; for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) { if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { @@ -1334,6 +1678,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, } } + /* This should never happen; it implies a flow control bug */ if (!context) { netdev_warn(netdev, "cannot find free context\n"); ret = NETDEV_TX_BUSY; @@ -1364,9 +1709,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, if (unlikely(err)) { can_free_echo_skb(netdev, context->echo_index); - skb = NULL; /* set to NULL to avoid double free in - * dev_kfree_skb(skb) */ - atomic_dec(&priv->active_tx_urbs); usb_unanchor_urb(urb); @@ -1388,8 +1730,6 @@ releasebuf: kfree(buf); nobufmem: usb_free_urb(urb); -nourbmem: - dev_kfree_skb(skb); return ret; } @@ -1502,6 +1842,10 @@ static int kvaser_usb_init_one(struct usb_interface *intf, struct kvaser_usb_net_priv *priv; int i, err; + err = kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, channel); + if (err) + return err; + netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS); if (!netdev) { dev_err(&intf->dev, "Cannot alloc candev\n"); @@ -1588,12 +1932,23 @@ static int kvaser_usb_probe(struct usb_interface *intf, { struct kvaser_usb *dev; int err = -ENOMEM; - int i; + int i, retry = 3; dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; + if (kvaser_is_leaf(id)) { + dev->family = KVASER_LEAF; + } else if (kvaser_is_usbcan(id)) { + dev->family = KVASER_USBCAN; + } else { + dev_err(&intf->dev, + "Product ID (%d) does not belong to any known Kvaser USB family", + id->idProduct); + return -ENODEV; + } + err = kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out); if (err) { dev_err(&intf->dev, "Cannot get usb endpoint(s)"); @@ -1606,10 +1961,15 @@ static int kvaser_usb_probe(struct usb_interface *intf, usb_set_intfdata(intf, dev); - for (i = 0; i < MAX_NET_DEVICES; i++) - kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i); + /* On some x86 laptops, plugging a Kvaser device again after + * an unplug makes the firmware always ignore the very first + * command. For such a case, provide some room for retries + * instead of completely exiting the driver. + */ + do { + err = kvaser_usb_get_software_info(dev); + } while (--retry && err == -ETIMEDOUT); - err = kvaser_usb_get_software_info(dev); if (err) { dev_err(&intf->dev, "Cannot get software infos, error %d\n", err); diff --git a/drivers/net/can/usb/peak_usb/Makefile b/drivers/net/can/usb/peak_usb/Makefile index 1aefbc88d643..1839e9ca62e7 100644 --- a/drivers/net/can/usb/peak_usb/Makefile +++ b/drivers/net/can/usb/peak_usb/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_CAN_PEAK_USB) += peak_usb.o -peak_usb-y = pcan_usb_core.o pcan_usb.o pcan_usb_pro.o +peak_usb-y = pcan_usb_core.o pcan_usb.o pcan_usb_pro.o pcan_usb_fd.o diff --git a/drivers/net/can/usb/peak_usb/pcan_ucan.h b/drivers/net/can/usb/peak_usb/pcan_ucan.h new file mode 100644 index 000000000000..1ba7c25002e1 --- /dev/null +++ b/drivers/net/can/usb/peak_usb/pcan_ucan.h @@ -0,0 +1,222 @@ +/* + * CAN driver for PEAK System micro-CAN based adapters + * + * Copyright (C) 2003-2011 PEAK System-Technik GmbH + * Copyright (C) 2011-2013 Stephane Grosjean + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#ifndef PUCAN_H +#define PUCAN_H + +/* uCAN commands opcodes list (low-order 10 bits) */ +#define PUCAN_CMD_NOP 0x000 +#define PUCAN_CMD_RESET_MODE 0x001 +#define PUCAN_CMD_NORMAL_MODE 0x002 +#define PUCAN_CMD_LISTEN_ONLY_MODE 0x003 +#define PUCAN_CMD_TIMING_SLOW 0x004 +#define PUCAN_CMD_TIMING_FAST 0x005 +#define PUCAN_CMD_FILTER_STD 0x008 +#define PUCAN_CMD_TX_ABORT 0x009 +#define PUCAN_CMD_WR_ERR_CNT 0x00a +#define PUCAN_CMD_RX_FRAME_ENABLE 0x00b +#define PUCAN_CMD_RX_FRAME_DISABLE 0x00c +#define PUCAN_CMD_END_OF_COLLECTION 0x3ff + +/* uCAN received messages list */ +#define PUCAN_MSG_CAN_RX 0x0001 +#define PUCAN_MSG_ERROR 0x0002 +#define PUCAN_MSG_STATUS 0x0003 +#define PUCAN_MSG_BUSLOAD 0x0004 +#define PUCAN_MSG_CAN_TX 0x1000 + +/* uCAN command common header */ +struct __packed pucan_command { + __le16 opcode_channel; + u16 args[3]; +}; + +/* uCAN TIMING_SLOW command fields */ +#define PUCAN_TSLOW_SJW_T(s, t) (((s) & 0xf) | ((!!(t)) << 7)) +#define PUCAN_TSLOW_TSEG2(t) ((t) & 0xf) +#define PUCAN_TSLOW_TSEG1(t) ((t) & 0x3f) +#define PUCAN_TSLOW_BRP(b) ((b) & 0x3ff) + +struct __packed pucan_timing_slow { + __le16 opcode_channel; + + u8 ewl; /* Error Warning limit */ + u8 sjw_t; /* Sync Jump Width + Triple sampling */ + u8 tseg2; /* Timing SEGment 2 */ + u8 tseg1; /* Timing SEGment 1 */ + + __le16 brp; /* BaudRate Prescaler */ +}; + +/* uCAN TIMING_FAST command fields */ +#define PUCAN_TFAST_SJW(s) ((s) & 0x3) +#define PUCAN_TFAST_TSEG2(t) ((t) & 0x7) +#define PUCAN_TFAST_TSEG1(t) ((t) & 0xf) +#define PUCAN_TFAST_BRP(b) ((b) & 0x3ff) + +struct __packed pucan_timing_fast { + __le16 opcode_channel; + + u8 unused; + u8 sjw; /* Sync Jump Width */ + u8 tseg2; /* Timing SEGment 2 */ + u8 tseg1; /* Timing SEGment 1 */ + + __le16 brp; /* BaudRate Prescaler */ +}; + +/* uCAN FILTER_STD command fields */ +#define PUCAN_FLTSTD_ROW_IDX_BITS 6 + +struct __packed pucan_filter_std { + __le16 opcode_channel; + + __le16 idx; + __le32 mask; /* CAN-ID bitmask in idx range */ +}; + +/* uCAN WR_ERR_CNT command fields */ +#define PUCAN_WRERRCNT_TE 0x4000 /* Tx error cntr write Enable */ +#define PUCAN_WRERRCNT_RE 0x8000 /* Rx error cntr write Enable */ + +struct __packed pucan_wr_err_cnt { + __le16 opcode_channel; + + __le16 sel_mask; + u8 tx_counter; /* Tx error counter new value */ + u8 rx_counter; /* Rx error counter new value */ + + u16 unused; +}; + +/* uCAN RX_FRAME_ENABLE command fields */ +#define PUCAN_FLTEXT_ERROR 0x0001 +#define PUCAN_FLTEXT_BUSLOAD 0x0002 + +struct __packed pucan_filter_ext { + __le16 opcode_channel; + + __le16 ext_mask; + u32 unused; +}; + +/* uCAN received messages global format */ +struct __packed pucan_msg { + __le16 size; + __le16 type; + __le32 ts_low; + __le32 ts_high; +}; + +/* uCAN flags for CAN/CANFD messages */ +#define PUCAN_MSG_SELF_RECEIVE 0x80 +#define PUCAN_MSG_ERROR_STATE_IND 0x40 /* error state indicator */ +#define PUCAN_MSG_BITRATE_SWITCH 0x20 /* bitrate switch */ +#define PUCAN_MSG_EXT_DATA_LEN 0x10 /* extended data length */ +#define PUCAN_MSG_SINGLE_SHOT 0x08 +#define PUCAN_MSG_LOOPED_BACK 0x04 +#define PUCAN_MSG_EXT_ID 0x02 +#define PUCAN_MSG_RTR 0x01 + +struct __packed pucan_rx_msg { + __le16 size; + __le16 type; + __le32 ts_low; + __le32 ts_high; + __le32 tag_low; + __le32 tag_high; + u8 channel_dlc; + u8 client; + __le16 flags; + __le32 can_id; + u8 d[0]; +}; + +/* uCAN error types */ +#define PUCAN_ERMSG_BIT_ERROR 0 +#define PUCAN_ERMSG_FORM_ERROR 1 +#define PUCAN_ERMSG_STUFF_ERROR 2 +#define PUCAN_ERMSG_OTHER_ERROR 3 +#define PUCAN_ERMSG_ERR_CNT_DEC 4 + +struct __packed pucan_error_msg { + __le16 size; + __le16 type; + __le32 ts_low; + __le32 ts_high; + u8 channel_type_d; + u8 code_g; + u8 tx_err_cnt; + u8 rx_err_cnt; +}; + +#define PUCAN_BUS_PASSIVE 0x20 +#define PUCAN_BUS_WARNING 0x40 +#define PUCAN_BUS_BUSOFF 0x80 + +struct __packed pucan_status_msg { + __le16 size; + __le16 type; + __le32 ts_low; + __le32 ts_high; + u8 channel_p_w_b; + u8 unused[3]; +}; + +/* uCAN transmitted message format */ +#define PUCAN_MSG_CHANNEL_DLC(c, d) (((c) & 0xf) | ((d) << 4)) + +struct __packed pucan_tx_msg { + __le16 size; + __le16 type; + __le32 tag_low; + __le32 tag_high; + u8 channel_dlc; + u8 client; + __le16 flags; + __le32 can_id; + u8 d[0]; +}; + +/* build the cmd opcode_channel field with respect to the correct endianness */ +static inline __le16 pucan_cmd_opcode_channel(struct peak_usb_device *dev, + int opcode) +{ + return cpu_to_le16(((dev->ctrl_idx) << 12) | ((opcode) & 0x3ff)); +} + +/* return the channel number part from any received message channel_dlc field */ +static inline int pucan_msg_get_channel(struct pucan_rx_msg *rm) +{ + return rm->channel_dlc & 0xf; +} + +/* return the dlc value from any received message channel_dlc field */ +static inline int pucan_msg_get_dlc(struct pucan_rx_msg *rm) +{ + return rm->channel_dlc >> 4; +} + +static inline int pucan_ermsg_get_channel(struct pucan_error_msg *em) +{ + return em->channel_type_d & 0x0f; +} + +static inline int pucan_stmsg_get_channel(struct pucan_status_msg *sm) +{ + return sm->channel_p_w_b & 0x0f; +} + +#endif diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 4e1659d07979..72427f21edff 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -488,6 +488,7 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n, switch (new_state) { case CAN_STATE_BUS_OFF: cf->can_id |= CAN_ERR_BUSOFF; + mc->pdev->dev.can.can_stats.bus_off++; can_bus_off(mc->netdev); break; @@ -854,10 +855,11 @@ static int pcan_usb_probe(struct usb_interface *intf) /* * describe the PCAN-USB adapter */ -struct peak_usb_adapter pcan_usb = { +const struct peak_usb_adapter pcan_usb = { .name = "PCAN-USB", .device_id = PCAN_USB_PRODUCT_ID, .ctrl_count = 1, + .ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY, .clock = { .freq = PCAN_USB_CRYSTAL_HZ / 2 , }, diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index c62f48a1161d..7921cff93a63 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -37,16 +37,19 @@ MODULE_LICENSE("GPL v2"); static struct usb_device_id peak_usb_table[] = { {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USB_PRODUCT_ID)}, {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPRO_PRODUCT_ID)}, + {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBFD_PRODUCT_ID)}, + {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPROFD_PRODUCT_ID)}, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, peak_usb_table); /* List of supported PCAN-USB adapters (NULL terminated list) */ -static struct peak_usb_adapter *peak_usb_adapters_list[] = { +static const struct peak_usb_adapter *const peak_usb_adapters_list[] = { &pcan_usb, &pcan_usb_pro, - NULL, + &pcan_usb_fd, + &pcan_usb_pro_fd, }; /* @@ -65,7 +68,7 @@ void pcan_dump_mem(char *prompt, void *p, int l) * initialize a time_ref object with usb adapter own settings */ void peak_usb_init_time_ref(struct peak_time_ref *time_ref, - struct peak_usb_adapter *adapter) + const struct peak_usb_adapter *adapter) { if (time_ref) { memset(time_ref, 0, sizeof(struct peak_time_ref)); @@ -164,6 +167,21 @@ void peak_usb_get_ts_tv(struct peak_time_ref *time_ref, u32 ts, } } +/* + * post received skb after having set any hw timestamp + */ +int peak_usb_netif_rx(struct sk_buff *skb, + struct peak_time_ref *time_ref, u32 ts_low, u32 ts_high) +{ + struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb); + struct timeval tv; + + peak_usb_get_ts_tv(time_ref, ts_low, &tv); + hwts->hwtstamp = timeval_to_ktime(tv); + + return netif_rx(skb); +} + /* * callback for bulk Rx urb */ @@ -253,7 +271,7 @@ static void peak_usb_write_bulk_callback(struct urb *urb) case 0: /* transmission complete */ netdev->stats.tx_packets++; - netdev->stats.tx_bytes += context->dlc; + netdev->stats.tx_bytes += context->data_len; /* prevent tx timeout */ netdev->trans_start = jiffies; @@ -289,7 +307,7 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb, struct peak_usb_device *dev = netdev_priv(netdev); struct peak_tx_urb_context *context = NULL; struct net_device_stats *stats = &netdev->stats; - struct can_frame *cf = (struct can_frame *)skb->data; + struct canfd_frame *cfd = (struct canfd_frame *)skb->data; struct urb *urb; u8 *obuf; int i, err; @@ -322,7 +340,9 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb, } context->echo_index = i; - context->dlc = cf->can_dlc; + + /* Note: this works with CANFD frames too */ + context->data_len = cfd->len; usb_anchor_urb(urb, &dev->tx_submitted); @@ -679,19 +699,43 @@ static int peak_usb_set_mode(struct net_device *netdev, enum can_mode mode) } /* - * candev callback used to set device bitrate. + * candev callback used to set device nominal/arbitration bitrate. */ static int peak_usb_set_bittiming(struct net_device *netdev) { struct peak_usb_device *dev = netdev_priv(netdev); - struct can_bittiming *bt = &dev->can.bittiming; + const struct peak_usb_adapter *pa = dev->adapter; - if (dev->adapter->dev_set_bittiming) { - int err = dev->adapter->dev_set_bittiming(dev, bt); + if (pa->dev_set_bittiming) { + struct can_bittiming *bt = &dev->can.bittiming; + int err = pa->dev_set_bittiming(dev, bt); if (err) netdev_info(netdev, "couldn't set bitrate (err %d)\n", - err); + err); + return err; + } + + return 0; +} + +/* + * candev callback used to set device data bitrate. + */ +static int peak_usb_set_data_bittiming(struct net_device *netdev) +{ + struct peak_usb_device *dev = netdev_priv(netdev); + const struct peak_usb_adapter *pa = dev->adapter; + + if (pa->dev_set_data_bittiming) { + struct can_bittiming *bt = &dev->can.data_bittiming; + int err = pa->dev_set_data_bittiming(dev, bt); + + if (err) + netdev_info(netdev, + "couldn't set data bitrate (err %d)\n", + err); + return err; } @@ -709,7 +753,7 @@ static const struct net_device_ops peak_usb_netdev_ops = { * create one device which is attached to CAN controller #ctrl_idx of the * usb adapter. */ -static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, +static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter, struct usb_interface *intf, int ctrl_idx) { struct usb_device *usb_dev = interface_to_usbdev(intf); @@ -750,9 +794,11 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter, dev->can.clock = peak_usb_adapter->clock; dev->can.bittiming_const = &peak_usb_adapter->bittiming_const; dev->can.do_set_bittiming = peak_usb_set_bittiming; + dev->can.data_bittiming_const = &peak_usb_adapter->data_bittiming_const; + dev->can.do_set_data_bittiming = peak_usb_set_data_bittiming; dev->can.do_set_mode = peak_usb_set_mode; - dev->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | - CAN_CTRLMODE_LISTENONLY; + dev->can.do_get_berr_counter = peak_usb_adapter->do_get_berr_counter; + dev->can.ctrlmode_supported = peak_usb_adapter->ctrlmode_supported; netdev->netdev_ops = &peak_usb_netdev_ops; @@ -857,17 +903,18 @@ static int peak_usb_probe(struct usb_interface *intf, { struct usb_device *usb_dev = interface_to_usbdev(intf); const u16 usb_id_product = le16_to_cpu(usb_dev->descriptor.idProduct); - struct peak_usb_adapter *peak_usb_adapter, **pp; + const struct peak_usb_adapter *peak_usb_adapter = NULL; int i, err = -ENOMEM; usb_dev = interface_to_usbdev(intf); /* get corresponding PCAN-USB adapter */ - for (pp = peak_usb_adapters_list; *pp; pp++) - if ((*pp)->device_id == usb_id_product) + for (i = 0; i < ARRAY_SIZE(peak_usb_adapters_list); i++) + if (peak_usb_adapters_list[i]->device_id == usb_id_product) { + peak_usb_adapter = peak_usb_adapters_list[i]; break; + } - peak_usb_adapter = *pp; if (!peak_usb_adapter) { /* should never come except device_id bad usage in this file */ pr_err("%s: didn't find device id. 0x%x in devices list\n", diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index 073b47ff8eee..9e624f05ad4d 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -25,6 +25,8 @@ /* supported device ids. */ #define PCAN_USB_PRODUCT_ID 0x000c #define PCAN_USBPRO_PRODUCT_ID 0x000d +#define PCAN_USBPROFD_PRODUCT_ID 0x0011 +#define PCAN_USBFD_PRODUCT_ID 0x0012 #define PCAN_USB_DRIVER_NAME "peak_usb" @@ -44,8 +46,10 @@ struct peak_usb_device; struct peak_usb_adapter { char *name; u32 device_id; + u32 ctrlmode_supported; struct can_clock clock; const struct can_bittiming_const bittiming_const; + const struct can_bittiming_const data_bittiming_const; unsigned int ctrl_count; int (*intf_probe)(struct usb_interface *intf); @@ -57,6 +61,8 @@ struct peak_usb_adapter { int (*dev_close)(struct peak_usb_device *dev); int (*dev_set_bittiming)(struct peak_usb_device *dev, struct can_bittiming *bt); + int (*dev_set_data_bittiming)(struct peak_usb_device *dev, + struct can_bittiming *bt); int (*dev_set_bus)(struct peak_usb_device *dev, u8 onoff); int (*dev_get_device_id)(struct peak_usb_device *dev, u32 *device_id); int (*dev_decode_buf)(struct peak_usb_device *dev, struct urb *urb); @@ -66,6 +72,8 @@ struct peak_usb_adapter { int (*dev_stop)(struct peak_usb_device *dev); int (*dev_restart_async)(struct peak_usb_device *dev, struct urb *urb, u8 *buf); + int (*do_get_berr_counter)(const struct net_device *netdev, + struct can_berr_counter *bec); u8 ep_msg_in; u8 ep_msg_out[PCAN_USB_MAX_CHANNEL]; u8 ts_used_bits; @@ -78,21 +86,23 @@ struct peak_usb_adapter { int sizeof_dev_private; }; -extern struct peak_usb_adapter pcan_usb; -extern struct peak_usb_adapter pcan_usb_pro; +extern const struct peak_usb_adapter pcan_usb; +extern const struct peak_usb_adapter pcan_usb_pro; +extern const struct peak_usb_adapter pcan_usb_fd; +extern const struct peak_usb_adapter pcan_usb_pro_fd; struct peak_time_ref { struct timeval tv_host_0, tv_host; u32 ts_dev_1, ts_dev_2; u64 ts_total; u32 tick_count; - struct peak_usb_adapter *adapter; + const struct peak_usb_adapter *adapter; }; struct peak_tx_urb_context { struct peak_usb_device *dev; u32 echo_index; - u8 dlc; + u8 data_len; struct urb *urb; }; @@ -102,7 +112,7 @@ struct peak_tx_urb_context { /* PEAK-System USB device */ struct peak_usb_device { struct can_priv can; - struct peak_usb_adapter *adapter; + const struct peak_usb_adapter *adapter; unsigned int ctrl_idx; u32 state; @@ -134,12 +144,14 @@ void pcan_dump_mem(char *prompt, void *p, int l); /* common timestamp management */ void peak_usb_init_time_ref(struct peak_time_ref *time_ref, - struct peak_usb_adapter *adapter); + const struct peak_usb_adapter *adapter); void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now); void peak_usb_set_ts_now(struct peak_time_ref *time_ref, u32 ts_now); void peak_usb_get_ts_tv(struct peak_time_ref *time_ref, u32 ts, struct timeval *tv); - +int peak_usb_netif_rx(struct sk_buff *skb, + struct peak_time_ref *time_ref, u32 ts_low, u32 ts_high); void peak_usb_async_complete(struct urb *urb); void peak_usb_restart_complete(struct peak_usb_device *dev); + #endif diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c new file mode 100644 index 000000000000..962c3f027383 --- /dev/null +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -0,0 +1,1095 @@ +/* + * CAN driver for PEAK System PCAN-USB FD / PCAN-USB Pro FD adapter + * + * Copyright (C) 2013-2014 Stephane Grosjean + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#include +#include +#include + +#include +#include +#include + +#include "pcan_usb_core.h" +#include "pcan_usb_pro.h" +#include "pcan_ucan.h" + +MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB FD adapter"); +MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB Pro FD adapter"); + +#define PCAN_USBPROFD_CHANNEL_COUNT 2 +#define PCAN_USBFD_CHANNEL_COUNT 1 + +/* PCAN-USB Pro FD adapter internal clock (Hz) */ +#define PCAN_UFD_CRYSTAL_HZ 80000000 + +#define PCAN_UFD_CMD_BUFFER_SIZE 512 +#define PCAN_UFD_LOSPD_PKT_SIZE 64 + +/* PCAN-USB Pro FD command timeout (ms.) */ +#define PCAN_UFD_CMD_TIMEOUT_MS 1000 + +/* PCAN-USB Pro FD rx/tx buffers size */ +#define PCAN_UFD_RX_BUFFER_SIZE 2048 +#define PCAN_UFD_TX_BUFFER_SIZE 512 + +/* read some versions info from the hw devcie */ +struct __packed pcan_ufd_fw_info { + __le16 size_of; /* sizeof this */ + __le16 type; /* type of this structure */ + u8 hw_type; /* Type of hardware (HW_TYPE_xxx) */ + u8 bl_version[3]; /* Bootloader version */ + u8 hw_version; /* Hardware version (PCB) */ + u8 fw_version[3]; /* Firmware version */ + __le32 dev_id[2]; /* "device id" per CAN */ + __le32 ser_no; /* S/N */ + __le32 flags; /* special functions */ +}; + +/* handle device specific info used by the netdevices */ +struct pcan_usb_fd_if { + struct peak_usb_device *dev[PCAN_USB_MAX_CHANNEL]; + struct pcan_ufd_fw_info fw_info; + struct peak_time_ref time_ref; + int cm_ignore_count; + int dev_opened_count; +}; + +/* device information */ +struct pcan_usb_fd_device { + struct peak_usb_device dev; + struct can_berr_counter bec; + struct pcan_usb_fd_if *usb_if; + u8 *cmd_buffer_addr; +}; + +/* Extended USB commands (non uCAN commands) */ + +/* Clock Modes command */ +#define PCAN_UFD_CMD_CLK_SET 0x80 + +#define PCAN_UFD_CLK_80MHZ 0x0 +#define PCAN_UFD_CLK_60MHZ 0x1 +#define PCAN_UFD_CLK_40MHZ 0x2 +#define PCAN_UFD_CLK_30MHZ 0x3 +#define PCAN_UFD_CLK_24MHZ 0x4 +#define PCAN_UFD_CLK_20MHZ 0x5 +#define PCAN_UFD_CLK_DEF PCAN_UFD_CLK_80MHZ + +struct __packed pcan_ufd_clock { + __le16 opcode_channel; + + u8 mode; + u8 unused[5]; +}; + +/* LED control command */ +#define PCAN_UFD_CMD_LED_SET 0x86 + +#define PCAN_UFD_LED_DEV 0x00 +#define PCAN_UFD_LED_FAST 0x01 +#define PCAN_UFD_LED_SLOW 0x02 +#define PCAN_UFD_LED_ON 0x03 +#define PCAN_UFD_LED_OFF 0x04 +#define PCAN_UFD_LED_DEF PCAN_UFD_LED_DEV + +struct __packed pcan_ufd_led { + __le16 opcode_channel; + + u8 mode; + u8 unused[5]; +}; + +/* Extended usage of uCAN commands CMD_RX_FRAME_xxxABLE for PCAN-USB Pro FD */ +#define PCAN_UFD_FLTEXT_CALIBRATION 0x8000 + +struct __packed pcan_ufd_filter_ext { + __le16 opcode_channel; + + __le16 ext_mask; + u16 unused; + __le16 usb_mask; +}; + +/* Extended usage of uCAN messages for PCAN-USB Pro FD */ +#define PCAN_UFD_MSG_CALIBRATION 0x100 + +struct __packed pcan_ufd_ts_msg { + __le16 size; + __le16 type; + __le32 ts_low; + __le32 ts_high; + __le16 usb_frame_index; + u16 unused; +}; + +#define PCAN_UFD_MSG_OVERRUN 0x101 + +#define PCAN_UFD_OVMSG_CHANNEL(o) ((o)->channel & 0xf) + +struct __packed pcan_ufd_ovr_msg { + __le16 size; + __le16 type; + __le32 ts_low; + __le32 ts_high; + u8 channel; + u8 unused[3]; +}; + +static inline int pufd_omsg_get_channel(struct pcan_ufd_ovr_msg *om) +{ + return om->channel & 0xf; +} + +/* Clock mode frequency values */ +static const u32 pcan_usb_fd_clk_freq[6] = { + [PCAN_UFD_CLK_80MHZ] = 80000000, + [PCAN_UFD_CLK_60MHZ] = 60000000, + [PCAN_UFD_CLK_40MHZ] = 40000000, + [PCAN_UFD_CLK_30MHZ] = 30000000, + [PCAN_UFD_CLK_24MHZ] = 24000000, + [PCAN_UFD_CLK_20MHZ] = 20000000 +}; + +/* return a device USB interface */ +static inline +struct pcan_usb_fd_if *pcan_usb_fd_dev_if(struct peak_usb_device *dev) +{ + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + return pdev->usb_if; +} + +/* return a device USB commands buffer */ +static inline void *pcan_usb_fd_cmd_buffer(struct peak_usb_device *dev) +{ + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + return pdev->cmd_buffer_addr; +} + +/* send PCAN-USB Pro FD commands synchronously */ +static int pcan_usb_fd_send_cmd(struct peak_usb_device *dev, void *cmd_tail) +{ + void *cmd_head = pcan_usb_fd_cmd_buffer(dev); + int err; + u8 *packet_ptr; + int i, n = 1, packet_len; + ptrdiff_t cmd_len; + + /* usb device unregistered? */ + if (!(dev->state & PCAN_USB_STATE_CONNECTED)) + return 0; + + /* if a packet is not filled completely by commands, the command list + * is terminated with an "end of collection" record. + */ + cmd_len = cmd_tail - cmd_head; + if (cmd_len <= (PCAN_UFD_CMD_BUFFER_SIZE - sizeof(u64))) { + memset(cmd_tail, 0xff, sizeof(u64)); + cmd_len += sizeof(u64); + } + + packet_ptr = cmd_head; + + /* firmware is not able to re-assemble 512 bytes buffer in full-speed */ + if ((dev->udev->speed != USB_SPEED_HIGH) && + (cmd_len > PCAN_UFD_LOSPD_PKT_SIZE)) { + packet_len = PCAN_UFD_LOSPD_PKT_SIZE; + n += cmd_len / packet_len; + } else { + packet_len = cmd_len; + } + + for (i = 0; i < n; i++) { + err = usb_bulk_msg(dev->udev, + usb_sndbulkpipe(dev->udev, + PCAN_USBPRO_EP_CMDOUT), + packet_ptr, packet_len, + NULL, PCAN_UFD_CMD_TIMEOUT_MS); + if (err) { + netdev_err(dev->netdev, + "sending command failure: %d\n", err); + break; + } + + packet_ptr += packet_len; + } + + return err; +} + +/* build the commands list in the given buffer, to enter operational mode */ +static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf) +{ + struct pucan_wr_err_cnt *prc; + struct pucan_command *cmd; + u8 *pc = buf; + + /* 1st, reset error counters: */ + prc = (struct pucan_wr_err_cnt *)pc; + prc->opcode_channel = pucan_cmd_opcode_channel(dev, + PUCAN_CMD_WR_ERR_CNT); + + /* select both counters */ + prc->sel_mask = cpu_to_le16(PUCAN_WRERRCNT_TE|PUCAN_WRERRCNT_RE); + + /* and reset their values */ + prc->tx_counter = 0; + prc->rx_counter = 0; + + /* moves the pointer forward */ + pc += sizeof(struct pucan_wr_err_cnt); + + /* next, go back to operational mode */ + cmd = (struct pucan_command *)pc; + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + (dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) ? + PUCAN_CMD_LISTEN_ONLY_MODE : + PUCAN_CMD_NORMAL_MODE); + pc += sizeof(struct pucan_command); + + return pc - buf; +} + +/* set CAN bus on/off */ +static int pcan_usb_fd_set_bus(struct peak_usb_device *dev, u8 onoff) +{ + u8 *pc = pcan_usb_fd_cmd_buffer(dev); + int l; + + if (onoff) { + /* build the cmds list to enter operational mode */ + l = pcan_usb_fd_build_restart_cmd(dev, pc); + } else { + struct pucan_command *cmd = (struct pucan_command *)pc; + + /* build cmd to go back to reset mode */ + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + PUCAN_CMD_RESET_MODE); + l = sizeof(struct pucan_command); + } + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, pc + l); +} + +/* set filtering masks: + * + * idx in range [0..63] selects a row #idx, all rows otherwise + * mask in range [0..0xffffffff] defines up to 32 CANIDs in the row(s) + * + * Each bit of this 64 x 32 bits array defines a CANID value: + * + * bit[i,j] = 1 implies that CANID=(i x 32)+j will be received, while + * bit[i,j] = 0 implies that CANID=(i x 32)+j will be discarded. + */ +static int pcan_usb_fd_set_filter_std(struct peak_usb_device *dev, int idx, + u32 mask) +{ + struct pucan_filter_std *cmd = pcan_usb_fd_cmd_buffer(dev); + int i, n; + + /* select all rows when idx is out of range [0..63] */ + if ((idx < 0) || (idx >= (1 << PUCAN_FLTSTD_ROW_IDX_BITS))) { + n = 1 << PUCAN_FLTSTD_ROW_IDX_BITS; + idx = 0; + + /* select the row (and only the row) otherwise */ + } else { + n = idx + 1; + } + + for (i = idx; i < n; i++, cmd++) { + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + PUCAN_CMD_FILTER_STD); + cmd->idx = cpu_to_le16(i); + cmd->mask = cpu_to_le32(mask); + } + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, cmd); +} + +/* set/unset notifications filter: + * + * onoff sets(1)/unset(0) notifications + * mask each bit defines a kind of notification to set/unset + */ +static int pcan_usb_fd_set_filter_ext(struct peak_usb_device *dev, + bool onoff, u16 ext_mask, u16 usb_mask) +{ + struct pcan_ufd_filter_ext *cmd = pcan_usb_fd_cmd_buffer(dev); + + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + (onoff) ? PUCAN_CMD_RX_FRAME_ENABLE : + PUCAN_CMD_RX_FRAME_DISABLE); + + cmd->ext_mask = cpu_to_le16(ext_mask); + cmd->usb_mask = cpu_to_le16(usb_mask); + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, ++cmd); +} + +/* setup LED control */ +static int pcan_usb_fd_set_can_led(struct peak_usb_device *dev, u8 led_mode) +{ + struct pcan_ufd_led *cmd = pcan_usb_fd_cmd_buffer(dev); + + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + PCAN_UFD_CMD_LED_SET); + cmd->mode = led_mode; + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, ++cmd); +} + +/* set CAN clock domain */ +static int pcan_usb_fd_set_clock_domain(struct peak_usb_device *dev, + u8 clk_mode) +{ + struct pcan_ufd_clock *cmd = pcan_usb_fd_cmd_buffer(dev); + + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + PCAN_UFD_CMD_CLK_SET); + cmd->mode = clk_mode; + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, ++cmd); +} + +/* set bittiming for CAN and CAN-FD header */ +static int pcan_usb_fd_set_bittiming_slow(struct peak_usb_device *dev, + struct can_bittiming *bt) +{ + struct pucan_timing_slow *cmd = pcan_usb_fd_cmd_buffer(dev); + + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + PUCAN_CMD_TIMING_SLOW); + cmd->sjw_t = PUCAN_TSLOW_SJW_T(bt->sjw - 1, + dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES); + + cmd->tseg2 = PUCAN_TSLOW_TSEG2(bt->phase_seg2 - 1); + cmd->tseg1 = PUCAN_TSLOW_TSEG1(bt->prop_seg + bt->phase_seg1 - 1); + cmd->brp = cpu_to_le16(PUCAN_TSLOW_BRP(bt->brp - 1)); + + cmd->ewl = 96; /* default */ + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, ++cmd); +} + +/* set CAN-FD bittiming for data */ +static int pcan_usb_fd_set_bittiming_fast(struct peak_usb_device *dev, + struct can_bittiming *bt) +{ + struct pucan_timing_fast *cmd = pcan_usb_fd_cmd_buffer(dev); + + cmd->opcode_channel = pucan_cmd_opcode_channel(dev, + PUCAN_CMD_TIMING_FAST); + cmd->sjw = PUCAN_TFAST_SJW(bt->sjw - 1); + cmd->tseg2 = PUCAN_TFAST_TSEG2(bt->phase_seg2 - 1); + cmd->tseg1 = PUCAN_TFAST_TSEG1(bt->prop_seg + bt->phase_seg1 - 1); + cmd->brp = cpu_to_le16(PUCAN_TFAST_BRP(bt->brp - 1)); + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, ++cmd); +} + +/* handle restart but in asynchronously way + * (uses PCAN-USB Pro code to complete asynchronous request) + */ +static int pcan_usb_fd_restart_async(struct peak_usb_device *dev, + struct urb *urb, u8 *buf) +{ + u8 *pc = buf; + + /* build the entire cmds list in the provided buffer, to go back into + * operational mode. + */ + pc += pcan_usb_fd_build_restart_cmd(dev, pc); + + /* add EOC */ + memset(pc, 0xff, sizeof(struct pucan_command)); + pc += sizeof(struct pucan_command); + + /* complete the URB */ + usb_fill_bulk_urb(urb, dev->udev, + usb_sndbulkpipe(dev->udev, PCAN_USBPRO_EP_CMDOUT), + buf, pc - buf, + pcan_usb_pro_restart_complete, dev); + + /* and submit it. */ + return usb_submit_urb(urb, GFP_ATOMIC); +} + +static int pcan_usb_fd_drv_loaded(struct peak_usb_device *dev, bool loaded) +{ + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + + pdev->cmd_buffer_addr[0] = 0; + pdev->cmd_buffer_addr[1] = !!loaded; + + return pcan_usb_pro_send_req(dev, + PCAN_USBPRO_REQ_FCT, + PCAN_USBPRO_FCT_DRVLD, + pdev->cmd_buffer_addr, + PCAN_USBPRO_FCT_DRVLD_REQ_LEN); +} + +static int pcan_usb_fd_decode_canmsg(struct pcan_usb_fd_if *usb_if, + struct pucan_msg *rx_msg) +{ + struct pucan_rx_msg *rm = (struct pucan_rx_msg *)rx_msg; + struct peak_usb_device *dev = usb_if->dev[pucan_msg_get_channel(rm)]; + struct net_device *netdev = dev->netdev; + struct canfd_frame *cfd; + struct sk_buff *skb; + const u16 rx_msg_flags = le16_to_cpu(rm->flags); + + if (rx_msg_flags & PUCAN_MSG_EXT_DATA_LEN) { + /* CANFD frame case */ + skb = alloc_canfd_skb(netdev, &cfd); + if (!skb) + return -ENOMEM; + + if (rx_msg_flags & PUCAN_MSG_BITRATE_SWITCH) + cfd->flags |= CANFD_BRS; + + if (rx_msg_flags & PUCAN_MSG_ERROR_STATE_IND) + cfd->flags |= CANFD_ESI; + + cfd->len = can_dlc2len(get_canfd_dlc(pucan_msg_get_dlc(rm))); + } else { + /* CAN 2.0 frame case */ + skb = alloc_can_skb(netdev, (struct can_frame **)&cfd); + if (!skb) + return -ENOMEM; + + cfd->len = get_can_dlc(pucan_msg_get_dlc(rm)); + } + + cfd->can_id = le32_to_cpu(rm->can_id); + + if (rx_msg_flags & PUCAN_MSG_EXT_ID) + cfd->can_id |= CAN_EFF_FLAG; + + if (rx_msg_flags & PUCAN_MSG_RTR) + cfd->can_id |= CAN_RTR_FLAG; + else + memcpy(cfd->data, rm->d, cfd->len); + + peak_usb_netif_rx(skb, &usb_if->time_ref, + le32_to_cpu(rm->ts_low), le32_to_cpu(rm->ts_high)); + + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += cfd->len; + + return 0; +} + +/* handle uCAN status message */ +static int pcan_usb_fd_decode_status(struct pcan_usb_fd_if *usb_if, + struct pucan_msg *rx_msg) +{ + struct pucan_status_msg *sm = (struct pucan_status_msg *)rx_msg; + struct peak_usb_device *dev = usb_if->dev[pucan_stmsg_get_channel(sm)]; + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + enum can_state new_state = CAN_STATE_ERROR_ACTIVE; + enum can_state rx_state, tx_state; + struct net_device *netdev = dev->netdev; + struct can_frame *cf; + struct sk_buff *skb; + + /* nothing should be sent while in BUS_OFF state */ + if (dev->can.state == CAN_STATE_BUS_OFF) + return 0; + + if (sm->channel_p_w_b & PUCAN_BUS_BUSOFF) { + new_state = CAN_STATE_BUS_OFF; + } else if (sm->channel_p_w_b & PUCAN_BUS_PASSIVE) { + new_state = CAN_STATE_ERROR_PASSIVE; + } else if (sm->channel_p_w_b & PUCAN_BUS_WARNING) { + new_state = CAN_STATE_ERROR_WARNING; + } else { + /* no error bit (so, no error skb, back to active state) */ + dev->can.state = CAN_STATE_ERROR_ACTIVE; + pdev->bec.txerr = 0; + pdev->bec.rxerr = 0; + return 0; + } + + /* state hasn't changed */ + if (new_state == dev->can.state) + return 0; + + /* handle bus state change */ + tx_state = (pdev->bec.txerr >= pdev->bec.rxerr) ? new_state : 0; + rx_state = (pdev->bec.txerr <= pdev->bec.rxerr) ? new_state : 0; + + /* allocate an skb to store the error frame */ + skb = alloc_can_err_skb(netdev, &cf); + if (skb) + can_change_state(netdev, cf, tx_state, rx_state); + + /* things must be done even in case of OOM */ + if (new_state == CAN_STATE_BUS_OFF) + can_bus_off(netdev); + + if (!skb) + return -ENOMEM; + + peak_usb_netif_rx(skb, &usb_if->time_ref, + le32_to_cpu(sm->ts_low), le32_to_cpu(sm->ts_high)); + + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += cf->can_dlc; + + return 0; +} + +/* handle uCAN error message */ +static int pcan_usb_fd_decode_error(struct pcan_usb_fd_if *usb_if, + struct pucan_msg *rx_msg) +{ + struct pucan_error_msg *er = (struct pucan_error_msg *)rx_msg; + struct peak_usb_device *dev = usb_if->dev[pucan_ermsg_get_channel(er)]; + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + + /* keep a trace of tx and rx error counters for later use */ + pdev->bec.txerr = er->tx_err_cnt; + pdev->bec.rxerr = er->rx_err_cnt; + + return 0; +} + +/* handle uCAN overrun message */ +static int pcan_usb_fd_decode_overrun(struct pcan_usb_fd_if *usb_if, + struct pucan_msg *rx_msg) +{ + struct pcan_ufd_ovr_msg *ov = (struct pcan_ufd_ovr_msg *)rx_msg; + struct peak_usb_device *dev = usb_if->dev[pufd_omsg_get_channel(ov)]; + struct net_device *netdev = dev->netdev; + struct can_frame *cf; + struct sk_buff *skb; + + /* allocate an skb to store the error frame */ + skb = alloc_can_err_skb(netdev, &cf); + if (!skb) + return -ENOMEM; + + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; + + peak_usb_netif_rx(skb, &usb_if->time_ref, + le32_to_cpu(ov->ts_low), le32_to_cpu(ov->ts_high)); + + netdev->stats.rx_over_errors++; + netdev->stats.rx_errors++; + + return 0; +} + +/* handle USB calibration message */ +static void pcan_usb_fd_decode_ts(struct pcan_usb_fd_if *usb_if, + struct pucan_msg *rx_msg) +{ + struct pcan_ufd_ts_msg *ts = (struct pcan_ufd_ts_msg *)rx_msg; + + /* should wait until clock is stabilized */ + if (usb_if->cm_ignore_count > 0) + usb_if->cm_ignore_count--; + else + peak_usb_set_ts_now(&usb_if->time_ref, le32_to_cpu(ts->ts_low)); +} + +/* callback for bulk IN urb */ +static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb) +{ + struct pcan_usb_fd_if *usb_if = pcan_usb_fd_dev_if(dev); + struct net_device *netdev = dev->netdev; + struct pucan_msg *rx_msg; + u8 *msg_ptr, *msg_end; + int err = 0; + + /* loop reading all the records from the incoming message */ + msg_ptr = urb->transfer_buffer; + msg_end = urb->transfer_buffer + urb->actual_length; + for (; msg_ptr < msg_end;) { + u16 rx_msg_type, rx_msg_size; + + rx_msg = (struct pucan_msg *)msg_ptr; + if (!rx_msg->size) { + /* null packet found: end of list */ + break; + } + + rx_msg_size = le16_to_cpu(rx_msg->size); + rx_msg_type = le16_to_cpu(rx_msg->type); + + /* check if the record goes out of current packet */ + if (msg_ptr + rx_msg_size > msg_end) { + netdev_err(netdev, + "got frag rec: should inc usb rx buf sze\n"); + err = -EBADMSG; + break; + } + + switch (rx_msg_type) { + case PUCAN_MSG_CAN_RX: + err = pcan_usb_fd_decode_canmsg(usb_if, rx_msg); + if (err < 0) + goto fail; + break; + + case PCAN_UFD_MSG_CALIBRATION: + pcan_usb_fd_decode_ts(usb_if, rx_msg); + break; + + case PUCAN_MSG_ERROR: + err = pcan_usb_fd_decode_error(usb_if, rx_msg); + if (err < 0) + goto fail; + break; + + case PUCAN_MSG_STATUS: + err = pcan_usb_fd_decode_status(usb_if, rx_msg); + if (err < 0) + goto fail; + break; + + case PCAN_UFD_MSG_OVERRUN: + err = pcan_usb_fd_decode_overrun(usb_if, rx_msg); + if (err < 0) + goto fail; + break; + + default: + netdev_err(netdev, + "unhandled msg type 0x%02x (%d): ignored\n", + rx_msg_type, rx_msg_type); + break; + } + + msg_ptr += rx_msg_size; + } + +fail: + if (err) + pcan_dump_mem("received msg", + urb->transfer_buffer, urb->actual_length); + return err; +} + +/* CAN/CANFD frames encoding callback */ +static int pcan_usb_fd_encode_msg(struct peak_usb_device *dev, + struct sk_buff *skb, u8 *obuf, size_t *size) +{ + struct pucan_tx_msg *tx_msg = (struct pucan_tx_msg *)obuf; + struct canfd_frame *cfd = (struct canfd_frame *)skb->data; + u16 tx_msg_size, tx_msg_flags; + u8 can_dlc; + + tx_msg_size = ALIGN(sizeof(struct pucan_tx_msg) + cfd->len, 4); + tx_msg->size = cpu_to_le16(tx_msg_size); + tx_msg->type = cpu_to_le16(PUCAN_MSG_CAN_TX); + + tx_msg_flags = 0; + if (cfd->can_id & CAN_EFF_FLAG) { + tx_msg_flags |= PUCAN_MSG_EXT_ID; + tx_msg->can_id = cpu_to_le32(cfd->can_id & CAN_EFF_MASK); + } else { + tx_msg->can_id = cpu_to_le32(cfd->can_id & CAN_SFF_MASK); + } + + if (can_is_canfd_skb(skb)) { + /* considering a CANFD frame */ + can_dlc = can_len2dlc(cfd->len); + + tx_msg_flags |= PUCAN_MSG_EXT_DATA_LEN; + + if (cfd->flags & CANFD_BRS) + tx_msg_flags |= PUCAN_MSG_BITRATE_SWITCH; + + if (cfd->flags & CANFD_ESI) + tx_msg_flags |= PUCAN_MSG_ERROR_STATE_IND; + } else { + /* CAND 2.0 frames */ + can_dlc = cfd->len; + + if (cfd->can_id & CAN_RTR_FLAG) + tx_msg_flags |= PUCAN_MSG_RTR; + } + + tx_msg->flags = cpu_to_le16(tx_msg_flags); + tx_msg->channel_dlc = PUCAN_MSG_CHANNEL_DLC(dev->ctrl_idx, can_dlc); + memcpy(tx_msg->d, cfd->data, cfd->len); + + /* add null size message to tag the end (messages are 32-bits aligned) + */ + tx_msg = (struct pucan_tx_msg *)(obuf + tx_msg_size); + + tx_msg->size = 0; + + /* set the whole size of the USB packet to send */ + *size = tx_msg_size + sizeof(u32); + + return 0; +} + +/* start the interface (last chance before set bus on) */ +static int pcan_usb_fd_start(struct peak_usb_device *dev) +{ + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + int err; + + /* set filter mode: all acceptance */ + err = pcan_usb_fd_set_filter_std(dev, -1, 0xffffffff); + if (err) + return err; + + /* opening first device: */ + if (pdev->usb_if->dev_opened_count == 0) { + /* reset time_ref */ + peak_usb_init_time_ref(&pdev->usb_if->time_ref, + &pcan_usb_pro_fd); + + /* enable USB calibration messages */ + err = pcan_usb_fd_set_filter_ext(dev, 1, + PUCAN_FLTEXT_ERROR, + PCAN_UFD_FLTEXT_CALIBRATION); + } + + pdev->usb_if->dev_opened_count++; + + /* reset cached error counters */ + pdev->bec.txerr = 0; + pdev->bec.rxerr = 0; + + return err; +} + +/* socket callback used to copy berr counters values receieved through USB */ +static int pcan_usb_fd_get_berr_counter(const struct net_device *netdev, + struct can_berr_counter *bec) +{ + struct peak_usb_device *dev = netdev_priv(netdev); + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + + *bec = pdev->bec; + + /* must return 0 */ + return 0; +} + +/* stop interface (last chance before set bus off) */ +static int pcan_usb_fd_stop(struct peak_usb_device *dev) +{ + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + + /* turn off special msgs for that interface if no other dev opened */ + if (pdev->usb_if->dev_opened_count == 1) + pcan_usb_fd_set_filter_ext(dev, 0, + PUCAN_FLTEXT_ERROR, + PCAN_UFD_FLTEXT_CALIBRATION); + pdev->usb_if->dev_opened_count--; + + return 0; +} + +/* called when probing, to initialize a device object */ +static int pcan_usb_fd_init(struct peak_usb_device *dev) +{ + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + int i, err = -ENOMEM; + + /* do this for 1st channel only */ + if (!dev->prev_siblings) { + /* allocate netdevices common structure attached to first one */ + pdev->usb_if = kzalloc(sizeof(*pdev->usb_if), GFP_KERNEL); + if (!pdev->usb_if) + goto err_out; + + /* allocate command buffer once for all for the interface */ + pdev->cmd_buffer_addr = kmalloc(PCAN_UFD_CMD_BUFFER_SIZE, + GFP_KERNEL); + if (!pdev->cmd_buffer_addr) + goto err_out_1; + + /* number of ts msgs to ignore before taking one into account */ + pdev->usb_if->cm_ignore_count = 5; + + err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO, + PCAN_USBPRO_INFO_FW, + &pdev->usb_if->fw_info, + sizeof(pdev->usb_if->fw_info)); + if (err) { + dev_err(dev->netdev->dev.parent, + "unable to read %s firmware info (err %d)\n", + dev->adapter->name, err); + goto err_out_2; + } + + /* explicit use of dev_xxx() instead of netdev_xxx() here: + * information displayed are related to the device itself, not + * to the canx (channel) device. + */ + dev_info(dev->netdev->dev.parent, + "PEAK-System %s v%u fw v%u.%u.%u (%u channels)\n", + dev->adapter->name, pdev->usb_if->fw_info.hw_version, + pdev->usb_if->fw_info.fw_version[0], + pdev->usb_if->fw_info.fw_version[1], + pdev->usb_if->fw_info.fw_version[2], + dev->adapter->ctrl_count); + + /* the currently supported hw is non-ISO */ + dev->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO; + + /* tell the hardware the can driver is running */ + err = pcan_usb_fd_drv_loaded(dev, 1); + if (err) { + dev_err(dev->netdev->dev.parent, + "unable to tell %s driver is loaded (err %d)\n", + dev->adapter->name, err); + goto err_out_2; + } + } else { + /* otherwise, simply copy previous sibling's values */ + struct pcan_usb_fd_device *ppdev = + container_of(dev->prev_siblings, + struct pcan_usb_fd_device, dev); + + pdev->usb_if = ppdev->usb_if; + pdev->cmd_buffer_addr = ppdev->cmd_buffer_addr; + } + + pdev->usb_if->dev[dev->ctrl_idx] = dev; + dev->device_number = + le32_to_cpu(pdev->usb_if->fw_info.dev_id[dev->ctrl_idx]); + + /* set clock domain */ + for (i = 0; i < ARRAY_SIZE(pcan_usb_fd_clk_freq); i++) + if (dev->adapter->clock.freq == pcan_usb_fd_clk_freq[i]) + break; + + if (i >= ARRAY_SIZE(pcan_usb_fd_clk_freq)) { + dev_warn(dev->netdev->dev.parent, + "incompatible clock frequencies\n"); + err = -EINVAL; + goto err_out_2; + } + + pcan_usb_fd_set_clock_domain(dev, i); + + /* set LED in default state (end of init phase) */ + pcan_usb_fd_set_can_led(dev, PCAN_UFD_LED_DEF); + + return 0; + +err_out_2: + kfree(pdev->cmd_buffer_addr); +err_out_1: + kfree(pdev->usb_if); +err_out: + return err; +} + +/* called when driver module is being unloaded */ +static void pcan_usb_fd_exit(struct peak_usb_device *dev) +{ + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + + /* when rmmod called before unplug and if down, should reset things + * before leaving + */ + if (dev->can.state != CAN_STATE_STOPPED) { + /* set bus off on the corresponding channel */ + pcan_usb_fd_set_bus(dev, 0); + } + + /* switch off corresponding CAN LEDs */ + pcan_usb_fd_set_can_led(dev, PCAN_UFD_LED_OFF); + + /* if channel #0 (only) */ + if (dev->ctrl_idx == 0) { + /* turn off calibration message if any device were opened */ + if (pdev->usb_if->dev_opened_count > 0) + pcan_usb_fd_set_filter_ext(dev, 0, + PUCAN_FLTEXT_ERROR, + PCAN_UFD_FLTEXT_CALIBRATION); + + /* tell USB adapter that the driver is being unloaded */ + pcan_usb_fd_drv_loaded(dev, 0); + } +} + +/* called when the USB adapter is unplugged */ +static void pcan_usb_fd_free(struct peak_usb_device *dev) +{ + /* last device: can free shared objects now */ + if (!dev->prev_siblings && !dev->next_siblings) { + struct pcan_usb_fd_device *pdev = + container_of(dev, struct pcan_usb_fd_device, dev); + + /* free commands buffer */ + kfree(pdev->cmd_buffer_addr); + + /* free usb interface object */ + kfree(pdev->usb_if); + } +} + +/* describes the PCAN-USB FD adapter */ +const struct peak_usb_adapter pcan_usb_fd = { + .name = "PCAN-USB FD", + .device_id = PCAN_USBFD_PRODUCT_ID, + .ctrl_count = PCAN_USBFD_CHANNEL_COUNT, + .ctrlmode_supported = CAN_CTRLMODE_FD | + CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY, + .clock = { + .freq = PCAN_UFD_CRYSTAL_HZ, + }, + .bittiming_const = { + .name = "pcan_usb_fd", + .tseg1_min = 1, + .tseg1_max = 64, + .tseg2_min = 1, + .tseg2_max = 16, + .sjw_max = 16, + .brp_min = 1, + .brp_max = 1024, + .brp_inc = 1, + }, + .data_bittiming_const = { + .name = "pcan_usb_fd", + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 1024, + .brp_inc = 1, + }, + + /* size of device private data */ + .sizeof_dev_private = sizeof(struct pcan_usb_fd_device), + + /* timestamps usage */ + .ts_used_bits = 32, + .ts_period = 1000000, /* calibration period in ts. */ + .us_per_ts_scale = 1, /* us = (ts * scale) >> shift */ + .us_per_ts_shift = 0, + + /* give here messages in/out endpoints */ + .ep_msg_in = PCAN_USBPRO_EP_MSGIN, + .ep_msg_out = {PCAN_USBPRO_EP_MSGOUT_0}, + + /* size of rx/tx usb buffers */ + .rx_buffer_size = PCAN_UFD_RX_BUFFER_SIZE, + .tx_buffer_size = PCAN_UFD_TX_BUFFER_SIZE, + + /* device callbacks */ + .intf_probe = pcan_usb_pro_probe, /* same as PCAN-USB Pro */ + .dev_init = pcan_usb_fd_init, + + .dev_exit = pcan_usb_fd_exit, + .dev_free = pcan_usb_fd_free, + .dev_set_bus = pcan_usb_fd_set_bus, + .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow, + .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast, + .dev_decode_buf = pcan_usb_fd_decode_buf, + .dev_start = pcan_usb_fd_start, + .dev_stop = pcan_usb_fd_stop, + .dev_restart_async = pcan_usb_fd_restart_async, + .dev_encode_msg = pcan_usb_fd_encode_msg, + + .do_get_berr_counter = pcan_usb_fd_get_berr_counter, +}; + +/* describes the PCAN-USB Pro FD adapter */ +const struct peak_usb_adapter pcan_usb_pro_fd = { + .name = "PCAN-USB Pro FD", + .device_id = PCAN_USBPROFD_PRODUCT_ID, + .ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT, + .ctrlmode_supported = CAN_CTRLMODE_FD | + CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY, + .clock = { + .freq = PCAN_UFD_CRYSTAL_HZ, + }, + .bittiming_const = { + .name = "pcan_usb_pro_fd", + .tseg1_min = 1, + .tseg1_max = 64, + .tseg2_min = 1, + .tseg2_max = 16, + .sjw_max = 16, + .brp_min = 1, + .brp_max = 1024, + .brp_inc = 1, + }, + .data_bittiming_const = { + .name = "pcan_usb_pro_fd", + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 1024, + .brp_inc = 1, + }, + + /* size of device private data */ + .sizeof_dev_private = sizeof(struct pcan_usb_fd_device), + + /* timestamps usage */ + .ts_used_bits = 32, + .ts_period = 1000000, /* calibration period in ts. */ + .us_per_ts_scale = 1, /* us = (ts * scale) >> shift */ + .us_per_ts_shift = 0, + + /* give here messages in/out endpoints */ + .ep_msg_in = PCAN_USBPRO_EP_MSGIN, + .ep_msg_out = {PCAN_USBPRO_EP_MSGOUT_0, PCAN_USBPRO_EP_MSGOUT_1}, + + /* size of rx/tx usb buffers */ + .rx_buffer_size = PCAN_UFD_RX_BUFFER_SIZE, + .tx_buffer_size = PCAN_UFD_TX_BUFFER_SIZE, + + /* device callbacks */ + .intf_probe = pcan_usb_pro_probe, /* same as PCAN-USB Pro */ + .dev_init = pcan_usb_fd_init, + + .dev_exit = pcan_usb_fd_exit, + .dev_free = pcan_usb_fd_free, + .dev_set_bus = pcan_usb_fd_set_bus, + .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow, + .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast, + .dev_decode_buf = pcan_usb_fd_decode_buf, + .dev_start = pcan_usb_fd_start, + .dev_stop = pcan_usb_fd_stop, + .dev_restart_async = pcan_usb_fd_restart_async, + .dev_encode_msg = pcan_usb_fd_encode_msg, + + .do_get_berr_counter = pcan_usb_fd_get_berr_counter, +}; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 4cfa3b8605b1..dec51717635e 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -27,14 +27,6 @@ MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB Pro adapter"); -/* PCAN-USB Pro Endpoints */ -#define PCAN_USBPRO_EP_CMDOUT 1 -#define PCAN_USBPRO_EP_CMDIN (PCAN_USBPRO_EP_CMDOUT | USB_DIR_IN) -#define PCAN_USBPRO_EP_MSGOUT_0 2 -#define PCAN_USBPRO_EP_MSGIN (PCAN_USBPRO_EP_MSGOUT_0 | USB_DIR_IN) -#define PCAN_USBPRO_EP_MSGOUT_1 3 -#define PCAN_USBPRO_EP_UNUSED (PCAN_USBPRO_EP_MSGOUT_1 | USB_DIR_IN) - #define PCAN_USBPRO_CHANNEL_COUNT 2 /* PCAN-USB Pro adapter internal clock (MHz) */ @@ -322,8 +314,8 @@ static int pcan_usb_pro_wait_rsp(struct peak_usb_device *dev, return (i >= PCAN_USBPRO_RSP_SUBMIT_MAX) ? -ERANGE : err; } -static int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id, - int req_value, void *req_addr, int req_size) +int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id, + int req_value, void *req_addr, int req_size) { int err; u8 req_type; @@ -475,7 +467,7 @@ static int pcan_usb_pro_set_bittiming(struct peak_usb_device *dev, return pcan_usb_pro_set_bitrate(dev, ccbt); } -static void pcan_usb_pro_restart_complete(struct urb *urb) +void pcan_usb_pro_restart_complete(struct urb *urb) { /* can delete usb resources */ peak_usb_async_complete(urb); @@ -634,6 +626,7 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if, switch (new_state) { case CAN_STATE_BUS_OFF: can_frame->can_id |= CAN_ERR_BUSOFF; + dev->can.can_stats.bus_off++; can_bus_off(netdev); break; @@ -977,7 +970,7 @@ static void pcan_usb_pro_free(struct peak_usb_device *dev) /* * probe function for new PCAN-USB Pro usb interface */ -static int pcan_usb_pro_probe(struct usb_interface *intf) +int pcan_usb_pro_probe(struct usb_interface *intf) { struct usb_host_interface *if_desc; int i; @@ -1011,10 +1004,11 @@ static int pcan_usb_pro_probe(struct usb_interface *intf) /* * describe the PCAN-USB Pro adapter */ -struct peak_usb_adapter pcan_usb_pro = { +const struct peak_usb_adapter pcan_usb_pro = { .name = "PCAN-USB Pro", .device_id = PCAN_USBPRO_PRODUCT_ID, .ctrl_count = PCAN_USBPRO_CHANNEL_COUNT, + .ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY, .clock = { .freq = PCAN_USBPRO_CRYSTAL_HZ, }, diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h index 837cee267132..a62f7ab8980f 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h @@ -27,6 +27,14 @@ #define PCAN_USBPRO_INFO_BL 0 #define PCAN_USBPRO_INFO_FW 1 +/* PCAN-USB Pro (FD) Endpoints */ +#define PCAN_USBPRO_EP_CMDOUT 1 +#define PCAN_USBPRO_EP_CMDIN (PCAN_USBPRO_EP_CMDOUT | USB_DIR_IN) +#define PCAN_USBPRO_EP_MSGOUT_0 2 +#define PCAN_USBPRO_EP_MSGIN (PCAN_USBPRO_EP_MSGOUT_0 | USB_DIR_IN) +#define PCAN_USBPRO_EP_MSGOUT_1 3 +#define PCAN_USBPRO_EP_UNUSED (PCAN_USBPRO_EP_MSGOUT_1 | USB_DIR_IN) + /* Vendor Request value for XXX_FCT */ #define PCAN_USBPRO_FCT_DRVLD 5 /* tell device driver is loaded */ #define PCAN_USBPRO_FCT_DRVLD_REQ_LEN 16 @@ -176,4 +184,9 @@ union pcan_usb_pro_rec { struct pcan_usb_pro_txmsg tx_msg; }; +int pcan_usb_pro_probe(struct usb_interface *intf); +int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id, + int req_value, void *req_addr, int req_size); +void pcan_usb_pro_restart_complete(struct urb *urb); + #endif diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index ef674ecb82f8..dd52c7a4c80d 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -377,6 +377,7 @@ static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv, case USB_8DEV_STATUSMSG_BUSOFF: priv->can.state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; + priv->can.can_stats.bus_off++; can_bus_off(priv->netdev); break; case USB_8DEV_STATUSMSG_OVERRUN: diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index feb29c4526f7..4daffb284931 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -233,6 +233,35 @@ static void bcm_sf2_eee_enable_set(struct dsa_switch *ds, int port, bool enable) core_writel(priv, reg, CORE_EEE_EN_CTRL); } +static void bcm_sf2_gphy_enable_set(struct dsa_switch *ds, bool enable) +{ + struct bcm_sf2_priv *priv = ds_to_priv(ds); + u32 reg; + + reg = reg_readl(priv, REG_SPHY_CNTRL); + if (enable) { + reg |= PHY_RESET; + reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS | CK25_DIS); + reg_writel(priv, reg, REG_SPHY_CNTRL); + udelay(21); + reg = reg_readl(priv, REG_SPHY_CNTRL); + reg &= ~PHY_RESET; + } else { + reg |= EXT_PWR_DOWN | IDDQ_BIAS | PHY_RESET; + reg_writel(priv, reg, REG_SPHY_CNTRL); + mdelay(1); + reg |= CK25_DIS; + } + reg_writel(priv, reg, REG_SPHY_CNTRL); + + /* Use PHY-driven LED signaling */ + if (!enable) { + reg = reg_readl(priv, REG_LED_CNTRL(0)); + reg |= SPDLNK_SRC_SEL; + reg_writel(priv, reg, REG_LED_CNTRL(0)); + } +} + static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, struct phy_device *phy) { @@ -248,6 +277,24 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port, /* Clear the Rx and Tx disable bits and set to no spanning tree */ core_writel(priv, 0, CORE_G_PCTL_PORT(port)); + /* Re-enable the GPHY and re-apply workarounds */ + if (port == 0 && priv->hw_params.num_gphy == 1) { + bcm_sf2_gphy_enable_set(ds, true); + if (phy) { + /* if phy_stop() has been called before, phy + * will be in halted state, and phy_start() + * will call resume. + * + * the resume path does not configure back + * autoneg settings, and since we hard reset + * the phy manually here, we need to reset the + * state machine also. + */ + phy->state = PHY_READY; + phy_init_hw(phy); + } + } + /* Enable port 7 interrupts to get notified */ if (port == 7) intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF)); @@ -281,6 +328,9 @@ static void bcm_sf2_port_disable(struct dsa_switch *ds, int port, intrl2_1_writel(priv, P_IRQ_MASK(P7_IRQ_OFF), INTRL2_CPU_CLEAR); } + if (port == 0 && priv->hw_params.num_gphy == 1) + bcm_sf2_gphy_enable_set(ds, false); + if (dsa_is_cpu_port(ds, port)) off = CORE_IMP_CTL; else @@ -400,6 +450,16 @@ static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv) return 0; } +static void bcm_sf2_intr_disable(struct bcm_sf2_priv *priv) +{ + intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); + intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); + intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); + intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); + intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); + intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); +} + static int bcm_sf2_sw_setup(struct dsa_switch *ds) { const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME; @@ -440,12 +500,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds) } /* Disable all interrupts and request them */ - intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); - intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); - intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); - intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); - intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); - intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); + bcm_sf2_intr_disable(priv); ret = request_irq(priv->irq0, bcm_sf2_switch_0_isr, 0, "switch_0", priv); @@ -747,12 +802,7 @@ static int bcm_sf2_sw_suspend(struct dsa_switch *ds) struct bcm_sf2_priv *priv = ds_to_priv(ds); unsigned int port; - intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); - intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); - intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); - intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); - intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); - intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); + bcm_sf2_intr_disable(priv); /* Disable all ports physically present including the IMP * port, the other ones have already been disabled during @@ -771,7 +821,6 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) { struct bcm_sf2_priv *priv = ds_to_priv(ds); unsigned int port; - u32 reg; int ret; ret = bcm_sf2_sw_rst(priv); @@ -780,17 +829,8 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) return ret; } - /* Reinitialize the single GPHY */ - if (priv->hw_params.num_gphy == 1) { - reg = reg_readl(priv, REG_SPHY_CNTRL); - reg |= PHY_RESET; - reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS); - reg_writel(priv, reg, REG_SPHY_CNTRL); - udelay(21); - reg = reg_readl(priv, REG_SPHY_CNTRL); - reg &= ~PHY_RESET; - reg_writel(priv, reg, REG_SPHY_CNTRL); - } + if (priv->hw_params.num_gphy == 1) + bcm_sf2_gphy_enable_set(ds, true); for (port = 0; port < DSA_MAX_PORTS; port++) { if ((1 << port) & ds->phys_port_mask) diff --git a/drivers/net/dsa/bcm_sf2_regs.h b/drivers/net/dsa/bcm_sf2_regs.h index 1bb49cb699ab..cabdfa5e217a 100644 --- a/drivers/net/dsa/bcm_sf2_regs.h +++ b/drivers/net/dsa/bcm_sf2_regs.h @@ -61,6 +61,10 @@ #define LPI_COUNT_SHIFT 9 #define LPI_COUNT_MASK 0x3F +#define REG_LED_CNTRL_BASE 0x90 +#define REG_LED_CNTRL(x) (REG_LED_CNTRL_BASE + (x) * 4) +#define SPDLNK_SRC_SEL (1 << 24) + /* Register set relative to 'INTRL2_0' and 'INTRL2_1' */ #define INTRL2_CPU_STATUS 0x00 #define INTRL2_CPU_SET 0x04 diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c index 1230f52aa70e..2540ef0142af 100644 --- a/drivers/net/dsa/mv88e6131.c +++ b/drivers/net/dsa/mv88e6131.c @@ -139,7 +139,8 @@ static int mv88e6131_setup_global(struct dsa_switch *ds) int nexthop; nexthop = 0x1f; - if (i != ds->index && i < ds->dst->pd->nr_chips) + if (ds->pd->rtable && + i != ds->index && i < ds->dst->pd->nr_chips) nexthop = ds->pd->rtable[i] & 0x1f; REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop); diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index 258d9ef5ef25..e13adc7b3dda 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -22,17 +22,14 @@ #include #include "mv88e6xxx.h" -static int mv88e6352_wait(struct dsa_switch *ds, int reg, u16 mask) +static int mv88e6352_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) { unsigned long timeout = jiffies + HZ / 10; while (time_before(jiffies, timeout)) { int ret; - ret = REG_READ(REG_GLOBAL2, reg); - if (ret < 0) - return ret; - + ret = REG_READ(reg, offset); if (!(ret & mask)) return 0; @@ -43,17 +40,17 @@ static int mv88e6352_wait(struct dsa_switch *ds, int reg, u16 mask) static inline int mv88e6352_phy_wait(struct dsa_switch *ds) { - return mv88e6352_wait(ds, 0x18, 0x8000); + return mv88e6352_wait(ds, REG_GLOBAL2, 0x18, 0x8000); } static inline int mv88e6352_eeprom_load_wait(struct dsa_switch *ds) { - return mv88e6352_wait(ds, 0x14, 0x0800); + return mv88e6352_wait(ds, REG_GLOBAL2, 0x14, 0x0800); } static inline int mv88e6352_eeprom_busy_wait(struct dsa_switch *ds) { - return mv88e6352_wait(ds, 0x14, 0x8000); + return mv88e6352_wait(ds, REG_GLOBAL2, 0x14, 0x8000); } static int __mv88e6352_phy_read(struct dsa_switch *ds, int addr, int regnum) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index cd6807c6b4ed..3e7e31a6abb7 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -85,6 +85,12 @@ int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg) ret = __mv88e6xxx_reg_read(bus, ds->pd->sw_addr, addr, reg); mutex_unlock(&ps->smi_mutex); + if (ret < 0) + return ret; + + dev_dbg(ds->master_dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", + addr, reg, ret); + return ret; } @@ -128,6 +134,9 @@ int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val) if (bus == NULL) return -EINVAL; + dev_dbg(ds->master_dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", + addr, reg, val); + mutex_lock(&ps->smi_mutex); ret = __mv88e6xxx_reg_write(bus, ds->pd->sw_addr, addr, reg, val); mutex_unlock(&ps->smi_mutex); diff --git a/drivers/net/ethernet/3com/typhoon.c b/drivers/net/ethernet/3com/typhoon.c index dede43f4ce09..8f8418d2ac4a 100644 --- a/drivers/net/ethernet/3com/typhoon.c +++ b/drivers/net/ethernet/3com/typhoon.c @@ -769,11 +769,11 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) first_txd->processFlags |= TYPHOON_TX_PF_IP_CHKSUM; } - if(vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { first_txd->processFlags |= TYPHOON_TX_PF_INSERT_VLAN | TYPHOON_TX_PF_VLAN_PRIORITY; first_txd->processFlags |= - cpu_to_le32(htons(vlan_tx_tag_get(skb)) << + cpu_to_le32(htons(skb_vlan_tag_get(skb)) << TYPHOON_TX_PF_VLAN_TAG_SHIFT); } diff --git a/drivers/net/ethernet/alteon/acenic.c b/drivers/net/ethernet/alteon/acenic.c index b68074803de3..b90a26b13fdf 100644 --- a/drivers/net/ethernet/alteon/acenic.c +++ b/drivers/net/ethernet/alteon/acenic.c @@ -2429,9 +2429,9 @@ restart: flagsize = (skb->len << 16) | (BD_FLG_END); if (skb->ip_summed == CHECKSUM_PARTIAL) flagsize |= BD_FLG_TCP_UDP_SUM; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { flagsize |= BD_FLG_VLAN_TAG; - vlan_tag = vlan_tx_tag_get(skb); + vlan_tag = skb_vlan_tag_get(skb); } desc = ap->tx_ring + idx; idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap); @@ -2450,9 +2450,9 @@ restart: flagsize = (skb_headlen(skb) << 16); if (skb->ip_summed == CHECKSUM_PARTIAL) flagsize |= BD_FLG_TCP_UDP_SUM; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { flagsize |= BD_FLG_VLAN_TAG; - vlan_tag = vlan_tx_tag_get(skb); + vlan_tag = skb_vlan_tag_get(skb); } ace_load_tx_bd(ap, ap->tx_ring + idx, mapping, flagsize, vlan_tag); diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index 7a5e4aa5415e..c638c85f3954 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -45,7 +45,7 @@ config AMD8111_ETH config LANCE tristate "AMD LANCE and PCnet (AT1500 and NE2100) support" - depends on ISA && ISA_DMA_API + depends on ISA && ISA_DMA_API && !ARM ---help--- If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from @@ -142,7 +142,7 @@ config PCMCIA_NMCLAN config NI65 tristate "NI6510 support" - depends on ISA && ISA_DMA_API + depends on ISA && ISA_DMA_API && !ARM ---help--- If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from @@ -179,7 +179,7 @@ config SUNLANCE config AMD_XGBE tristate "AMD 10GbE Ethernet driver" - depends on OF_NET && HAS_IOMEM + depends on (OF_NET || ACPI) && HAS_IOMEM select PHYLIB select AMD_XGBE_PHY select BITREVERSE diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index 841e6558db68..4c2ae2221780 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -1299,11 +1299,11 @@ static netdev_tx_t amd8111e_start_xmit(struct sk_buff *skb, lp->tx_ring[tx_index].tx_flags = 0; #if AMD8111E_VLAN_TAG_USED - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { lp->tx_ring[tx_index].tag_ctrl_cmd |= cpu_to_le16(TCC_VLAN_INSERT); lp->tx_ring[tx_index].tag_ctrl_info = - cpu_to_le16(vlan_tx_tag_get(skb)); + cpu_to_le16(skb_vlan_tag_get(skb)); } #endif diff --git a/drivers/net/ethernet/amd/atarilance.c b/drivers/net/ethernet/amd/atarilance.c index e07ce5ff2d48..b10964e8cb54 100644 --- a/drivers/net/ethernet/amd/atarilance.c +++ b/drivers/net/ethernet/amd/atarilance.c @@ -553,8 +553,8 @@ static unsigned long __init lance_probe1( struct net_device *dev, if (lp->cardtype == PAM_CARD || 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)) { + if (request_irq(IRQ_AUTO_5, lance_interrupt, 0, + "PAM,Riebl-ST Ethernet", dev)) { printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 ); return 0; } @@ -567,8 +567,8 @@ static unsigned long __init lance_probe1( struct net_device *dev, printk( "Lance: request for VME interrupt failed\n" ); return 0; } - if (request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO, - "Riebl-VME Ethernet", dev)) { + if (request_irq(irq, lance_interrupt, 0, "Riebl-VME Ethernet", + dev)) { printk( "Lance: request for irq %u failed\n", irq ); return 0; } diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c index 5b22764ba88d..27245efe9f50 100644 --- a/drivers/net/ethernet/amd/nmclan_cs.c +++ b/drivers/net/ethernet/amd/nmclan_cs.c @@ -952,6 +952,8 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) do { /* WARNING: MACE_IR is a READ/CLEAR port! */ status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR); + if (!(status & ~MACE_IMR_DEFAULT) && IntrCnt == MACE_MAX_IR_ITERATIONS) + return IRQ_NONE; pr_debug("mace_interrupt: irq 0x%X status 0x%X.\n", irq, status); diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c index e2e3aaf501a2..11d6e6561df1 100644 --- a/drivers/net/ethernet/amd/pcnet32.c +++ b/drivers/net/ethernet/amd/pcnet32.c @@ -2806,7 +2806,7 @@ static void pcnet32_check_media(struct net_device *dev, int verbose) /* * Check for loss of link and link establishment. - * Can not use mii_check_media because it does nothing if mode is forced. + * Could possibly be changed to use mii_check_media instead. */ static void pcnet32_watchdog(struct net_device *dev) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index 75b08c63d39f..29a09271b64a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -767,16 +767,17 @@ #define MTL_Q_RQOMR 0x40 #define MTL_Q_RQMPOCR 0x44 #define MTL_Q_RQDR 0x4c +#define MTL_Q_RQFCR 0x50 #define MTL_Q_IER 0x70 #define MTL_Q_ISR 0x74 /* MTL queue register entry bit positions and sizes */ +#define MTL_Q_RQFCR_RFA_INDEX 1 +#define MTL_Q_RQFCR_RFA_WIDTH 6 +#define MTL_Q_RQFCR_RFD_INDEX 17 +#define MTL_Q_RQFCR_RFD_WIDTH 6 #define MTL_Q_RQOMR_EHFC_INDEX 7 #define MTL_Q_RQOMR_EHFC_WIDTH 1 -#define MTL_Q_RQOMR_RFA_INDEX 8 -#define MTL_Q_RQOMR_RFA_WIDTH 3 -#define MTL_Q_RQOMR_RFD_INDEX 13 -#define MTL_Q_RQOMR_RFD_WIDTH 3 #define MTL_Q_RQOMR_RQS_INDEX 16 #define MTL_Q_RQOMR_RQS_WIDTH 9 #define MTL_Q_RQOMR_RSF_INDEX 5 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c index 76479d04b903..2c063b60db4b 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c @@ -328,7 +328,7 @@ void xgbe_debugfs_init(struct xgbe_prv_data *pdata) buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name); pdata->xgbe_debugfs = debugfs_create_dir(buf, NULL); - if (pdata->xgbe_debugfs == NULL) { + if (!pdata->xgbe_debugfs) { netdev_err(pdata->netdev, "debugfs_create_dir failed\n"); return; } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c index a50891f52197..d81fc6bd4759 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c @@ -422,7 +422,6 @@ static void xgbe_wrapper_rx_descriptor_init(struct xgbe_prv_data *pdata) ring->cur = 0; ring->dirty = 0; - memset(&ring->rx, 0, sizeof(ring->rx)); hw_if->rx_desc_init(channel); } @@ -621,35 +620,6 @@ err_out: return 0; } -static void xgbe_realloc_rx_buffer(struct xgbe_channel *channel) -{ - struct xgbe_prv_data *pdata = channel->pdata; - struct xgbe_hw_if *hw_if = &pdata->hw_if; - struct xgbe_ring *ring = channel->rx_ring; - struct xgbe_ring_data *rdata; - int i; - - DBGPR("-->xgbe_realloc_rx_buffer: rx_ring->rx.realloc_index = %u\n", - ring->rx.realloc_index); - - for (i = 0; i < ring->dirty; i++) { - rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index); - - /* Reset rdata values */ - xgbe_unmap_rdata(pdata, rdata); - - if (xgbe_map_rx_buffer(pdata, ring, rdata)) - break; - - hw_if->rx_desc_reset(rdata); - - ring->rx.realloc_index++; - } - ring->dirty = 0; - - DBGPR("<--xgbe_realloc_rx_buffer\n"); -} - void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *desc_if) { DBGPR("-->xgbe_init_function_ptrs_desc\n"); @@ -657,7 +627,7 @@ void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *desc_if) desc_if->alloc_ring_resources = xgbe_alloc_ring_resources; desc_if->free_ring_resources = xgbe_free_ring_resources; desc_if->map_tx_skb = xgbe_map_tx_skb; - desc_if->realloc_rx_buffer = xgbe_realloc_rx_buffer; + desc_if->map_rx_buffer = xgbe_map_rx_buffer; desc_if->unmap_rdata = xgbe_unmap_rdata; desc_if->wrapper_tx_desc_init = xgbe_wrapper_tx_descriptor_init; desc_if->wrapper_rx_desc_init = xgbe_wrapper_rx_descriptor_init; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 53f5f66ec2ee..400757b49872 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -115,6 +115,7 @@ */ #include +#include #include #include #include @@ -130,7 +131,7 @@ static unsigned int xgbe_usec_to_riwt(struct xgbe_prv_data *pdata, DBGPR("-->xgbe_usec_to_riwt\n"); - rate = clk_get_rate(pdata->sysclk); + rate = pdata->sysclk_rate; /* * Convert the input usec value to the watchdog timer value. Each @@ -153,7 +154,7 @@ static unsigned int xgbe_riwt_to_usec(struct xgbe_prv_data *pdata, DBGPR("-->xgbe_riwt_to_usec\n"); - rate = clk_get_rate(pdata->sysclk); + rate = pdata->sysclk_rate; /* * Convert the input watchdog timer value to the usec value. Each @@ -673,6 +674,9 @@ static void xgbe_enable_mac_interrupts(struct xgbe_prv_data *pdata) static int xgbe_set_gmii_speed(struct xgbe_prv_data *pdata) { + if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0x3) + return 0; + XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0x3); return 0; @@ -680,6 +684,9 @@ static int xgbe_set_gmii_speed(struct xgbe_prv_data *pdata) static int xgbe_set_gmii_2500_speed(struct xgbe_prv_data *pdata) { + if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0x2) + return 0; + XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0x2); return 0; @@ -687,6 +694,9 @@ static int xgbe_set_gmii_2500_speed(struct xgbe_prv_data *pdata) static int xgbe_set_xgmii_speed(struct xgbe_prv_data *pdata) { + if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0) + return 0; + XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0); return 0; @@ -881,6 +891,23 @@ static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad, else mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff); + /* If the PCS is changing modes, match the MAC speed to it */ + if (((mmd_address >> 16) == MDIO_MMD_PCS) && + ((mmd_address & 0xffff) == MDIO_CTRL2)) { + struct phy_device *phydev = pdata->phydev; + + if (mmd_data & MDIO_PCS_CTRL2_TYPE) { + /* KX mode */ + if (phydev->supported & SUPPORTED_1000baseKX_Full) + xgbe_set_gmii_speed(pdata); + else + xgbe_set_gmii_2500_speed(pdata); + } else { + /* KR mode */ + xgbe_set_xgmii_speed(pdata); + } + } + /* The PCS registers are accessed using mmio. The underlying APB3 * management interface uses indirect addressing to access the MMD * register sets. This requires accessing of the PCS register in two @@ -1359,6 +1386,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) unsigned int tso_context, vlan_context; unsigned int tx_set_ic; int start_index = ring->cur; + int cur_index = ring->cur; int i; DBGPR("-->xgbe_dev_xmit\n"); @@ -1401,7 +1429,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) else tx_set_ic = 0; - rdata = XGBE_GET_DESC_DATA(ring, ring->cur); + rdata = XGBE_GET_DESC_DATA(ring, cur_index); rdesc = rdata->rdesc; /* Create a context descriptor if this is a TSO packet */ @@ -1444,8 +1472,8 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) ring->tx.cur_vlan_ctag = packet->vlan_ctag; } - ring->cur++; - rdata = XGBE_GET_DESC_DATA(ring, ring->cur); + cur_index++; + rdata = XGBE_GET_DESC_DATA(ring, cur_index); rdesc = rdata->rdesc; } @@ -1473,7 +1501,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CTXT, 0); /* Set OWN bit if not the first descriptor */ - if (ring->cur != start_index) + if (cur_index != start_index) XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN, 1); if (tso) { @@ -1497,9 +1525,9 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) packet->length); } - for (i = ring->cur - start_index + 1; i < packet->rdesc_count; i++) { - ring->cur++; - rdata = XGBE_GET_DESC_DATA(ring, ring->cur); + for (i = cur_index - start_index + 1; i < packet->rdesc_count; i++) { + cur_index++; + rdata = XGBE_GET_DESC_DATA(ring, cur_index); rdesc = rdata->rdesc; /* Update buffer address */ @@ -1551,7 +1579,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel) /* Make sure ownership is written to the descriptor */ wmb(); - ring->cur++; + ring->cur = cur_index + 1; if (!packet->skb->xmit_more || netif_xmit_stopped(netdev_get_tx_queue(pdata->netdev, channel->queue_index))) @@ -2079,10 +2107,10 @@ static void xgbe_config_flow_control_threshold(struct xgbe_prv_data *pdata) for (i = 0; i < pdata->rx_q_count; i++) { /* Activate flow control when less than 4k left in fifo */ - XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RFA, 2); + XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQFCR, RFA, 2); /* De-activate flow control when more than 6k left in fifo */ - XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RFD, 4); + XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQFCR, RFD, 4); } } @@ -2107,6 +2135,23 @@ static void xgbe_config_jumbo_enable(struct xgbe_prv_data *pdata) XGMAC_IOWRITE_BITS(pdata, MAC_RCR, JE, val); } +static void xgbe_config_mac_speed(struct xgbe_prv_data *pdata) +{ + switch (pdata->phy_speed) { + case SPEED_10000: + xgbe_set_xgmii_speed(pdata); + break; + + case SPEED_2500: + xgbe_set_gmii_2500_speed(pdata); + break; + + case SPEED_1000: + xgbe_set_gmii_speed(pdata); + break; + } +} + static void xgbe_config_checksum_offload(struct xgbe_prv_data *pdata) { if (pdata->netdev->features & NETIF_F_RXCSUM) @@ -2757,6 +2802,7 @@ static int xgbe_init(struct xgbe_prv_data *pdata) xgbe_config_mac_address(pdata); xgbe_config_jumbo_enable(pdata); xgbe_config_flow_control(pdata); + xgbe_config_mac_speed(pdata); xgbe_config_checksum_offload(pdata); xgbe_config_vlan_support(pdata); xgbe_config_mmc(pdata); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 7bb5f07dbeef..b93d4404d975 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -225,6 +225,11 @@ static inline unsigned int xgbe_tx_avail_desc(struct xgbe_ring *ring) return (ring->rdesc_count - (ring->cur - ring->dirty)); } +static inline unsigned int xgbe_rx_dirty_desc(struct xgbe_ring *ring) +{ + return (ring->cur - ring->dirty); +} + static int xgbe_maybe_stop_tx_queue(struct xgbe_channel *channel, struct xgbe_ring *ring, unsigned int count) { @@ -337,12 +342,13 @@ static irqreturn_t xgbe_isr(int irq, void *data) dma_ch_isr = XGMAC_DMA_IOREAD(channel, DMA_CH_SR); DBGPR(" DMA_CH%u_ISR = %08x\n", i, dma_ch_isr); - /* If we get a TI or RI interrupt that means per channel DMA - * interrupts are not enabled, so we use the private data napi - * structure, not the per channel napi structure + /* The TI or RI interrupt bits may still be set even if using + * per channel DMA interrupts. Check to be sure those are not + * enabled before using the private data napi structure. */ - if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, TI) || - XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RI)) { + if (!pdata->per_channel_irq && + (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, TI) || + XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RI))) { if (napi_schedule_prep(&pdata->napi)) { /* Disable Tx and Rx interrupts */ xgbe_disable_rx_tx_ints(pdata); @@ -410,17 +416,13 @@ static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer) struct xgbe_channel *channel = container_of(timer, struct xgbe_channel, tx_timer); - struct xgbe_ring *ring = channel->tx_ring; struct xgbe_prv_data *pdata = channel->pdata; struct napi_struct *napi; - unsigned long flags; DBGPR("-->xgbe_tx_timer\n"); napi = (pdata->per_channel_irq) ? &channel->napi : &pdata->napi; - spin_lock_irqsave(&ring->lock, flags); - if (napi_schedule_prep(napi)) { /* Disable Tx and Rx interrupts */ if (pdata->per_channel_irq) @@ -434,8 +436,6 @@ static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer) channel->tx_timer_active = 0; - spin_unlock_irqrestore(&ring->lock, flags); - DBGPR("<--xgbe_tx_timer\n"); return HRTIMER_NORESTART; @@ -523,6 +523,7 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata) hw_feat->sph = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, SPHEN); hw_feat->tso = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, TSOEN); hw_feat->dma_debug = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, DBGMEMA); + hw_feat->rss = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, RSSEN); hw_feat->tc_cnt = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, NUMTC); hw_feat->hash_table_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, HASHTBLSZ); @@ -552,13 +553,14 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata) break; } - /* The Queue and Channel counts are zero based so increment them + /* The Queue, Channel and TC counts are zero based so increment them * to get the actual number */ hw_feat->rx_q_cnt++; hw_feat->tx_q_cnt++; hw_feat->rx_ch_cnt++; hw_feat->tx_ch_cnt++; + hw_feat->tc_cnt++; DBGPR("<--xgbe_get_all_hw_features\n"); } @@ -692,7 +694,7 @@ static void xgbe_adjust_link(struct net_device *netdev) struct phy_device *phydev = pdata->phydev; int new_state = 0; - if (phydev == NULL) + if (!phydev) return; if (phydev->link) { @@ -927,7 +929,7 @@ static void xgbe_stop(struct xgbe_prv_data *pdata) DBGPR("<--xgbe_stop\n"); } -static void xgbe_restart_dev(struct xgbe_prv_data *pdata, unsigned int reset) +static void xgbe_restart_dev(struct xgbe_prv_data *pdata) { struct xgbe_channel *channel; struct xgbe_hw_if *hw_if = &pdata->hw_if; @@ -950,9 +952,8 @@ static void xgbe_restart_dev(struct xgbe_prv_data *pdata, unsigned int reset) xgbe_free_tx_data(pdata); xgbe_free_rx_data(pdata); - /* Issue software reset to device if requested */ - if (reset) - hw_if->exit(pdata); + /* Issue software reset to device */ + hw_if->exit(pdata); xgbe_start(pdata); @@ -967,7 +968,7 @@ static void xgbe_restart(struct work_struct *work) rtnl_lock(); - xgbe_restart_dev(pdata, 1); + xgbe_restart_dev(pdata); rtnl_unlock(); } @@ -1165,8 +1166,8 @@ static void xgbe_prep_tx_tstamp(struct xgbe_prv_data *pdata, static void xgbe_prep_vlan(struct sk_buff *skb, struct xgbe_packet_data *packet) { - if (vlan_tx_tag_present(skb)) - packet->vlan_ctag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) + packet->vlan_ctag = skb_vlan_tag_get(skb); } static int xgbe_prep_tso(struct sk_buff *skb, struct xgbe_packet_data *packet) @@ -1247,9 +1248,9 @@ static void xgbe_packet_info(struct xgbe_prv_data *pdata, XGMAC_SET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, CSUM_ENABLE, 1); - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { /* VLAN requires an extra descriptor if tag is different */ - if (vlan_tx_tag_get(skb) != ring->tx.cur_vlan_ctag) + if (skb_vlan_tag_get(skb) != ring->tx.cur_vlan_ctag) /* We can share with the TSO context descriptor */ if (!context_desc) { context_desc = 1; @@ -1446,7 +1447,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) struct xgbe_ring *ring; struct xgbe_packet_data *packet; struct netdev_queue *txq; - unsigned long flags; int ret; DBGPR("-->xgbe_xmit: skb->len = %d\n", skb->len); @@ -1458,8 +1458,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) ret = NETDEV_TX_OK; - spin_lock_irqsave(&ring->lock, flags); - if (skb->len == 0) { netdev_err(netdev, "empty skb received from stack\n"); dev_kfree_skb_any(skb); @@ -1506,10 +1504,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) ret = NETDEV_TX_OK; tx_netdev_return: - spin_unlock_irqrestore(&ring->lock, flags); - - DBGPR("<--xgbe_xmit\n"); - return ret; } @@ -1587,7 +1581,7 @@ static int xgbe_change_mtu(struct net_device *netdev, int mtu) pdata->rx_buf_size = ret; netdev->mtu = mtu; - xgbe_restart_dev(pdata, 0); + xgbe_restart_dev(pdata); DBGPR("<--xgbe_change_mtu\n"); @@ -1776,15 +1770,28 @@ struct net_device_ops *xgbe_get_netdev_ops(void) static void xgbe_rx_refresh(struct xgbe_channel *channel) { struct xgbe_prv_data *pdata = channel->pdata; + struct xgbe_hw_if *hw_if = &pdata->hw_if; struct xgbe_desc_if *desc_if = &pdata->desc_if; struct xgbe_ring *ring = channel->rx_ring; struct xgbe_ring_data *rdata; - desc_if->realloc_rx_buffer(channel); + while (ring->dirty != ring->cur) { + rdata = XGBE_GET_DESC_DATA(ring, ring->dirty); + + /* Reset rdata values */ + desc_if->unmap_rdata(pdata, rdata); + + if (desc_if->map_rx_buffer(pdata, ring, rdata)) + break; + + hw_if->rx_desc_reset(rdata); + + ring->dirty++; + } /* Update the Rx Tail Pointer Register with address of * the last cleaned entry */ - rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index - 1); + rdata = XGBE_GET_DESC_DATA(ring, ring->dirty - 1); XGMAC_DMA_IOWRITE(channel, DMA_CH_RDTR_LO, lower_32_bits(rdata->rdesc_dma)); } @@ -1824,7 +1831,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) struct xgbe_ring_desc *rdesc; struct net_device *netdev = pdata->netdev; struct netdev_queue *txq; - unsigned long flags; int processed = 0; unsigned int tx_packets = 0, tx_bytes = 0; @@ -1836,8 +1842,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) txq = netdev_get_tx_queue(netdev, channel->queue_index); - spin_lock_irqsave(&ring->lock, flags); - while ((processed < XGBE_TX_DESC_MAX_PROC) && (ring->dirty != ring->cur)) { rdata = XGBE_GET_DESC_DATA(ring, ring->dirty); @@ -1868,7 +1872,7 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) } if (!processed) - goto unlock; + return 0; netdev_tx_completed_queue(txq, tx_packets, tx_bytes); @@ -1880,9 +1884,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel) DBGPR("<--xgbe_tx_poll: processed=%d\n", processed); -unlock: - spin_unlock_irqrestore(&ring->lock, flags); - return processed; } @@ -1934,7 +1935,7 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) read_again: rdata = XGBE_GET_DESC_DATA(ring, ring->cur); - if (ring->dirty > (XGBE_RX_DESC_CNT >> 3)) + if (xgbe_rx_dirty_desc(ring) > (XGBE_RX_DESC_CNT >> 3)) xgbe_rx_refresh(channel); if (hw_if->dev_read(channel)) @@ -1942,7 +1943,6 @@ read_again: received++; ring->cur++; - ring->dirty++; incomplete = XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index dbd3850b8b0a..32dd65137051 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -123,7 +123,10 @@ #include #include #include +#include #include +#include +#include #include "xgbe.h" #include "xgbe-common.h" @@ -148,6 +151,7 @@ static void xgbe_default_config(struct xgbe_prv_data *pdata) pdata->pause_autoneg = 1; pdata->tx_pause = 1; pdata->rx_pause = 1; + pdata->phy_speed = SPEED_UNKNOWN; pdata->power_down = 0; pdata->default_autoneg = AUTONEG_ENABLE; pdata->default_speed = SPEED_10000; @@ -161,6 +165,96 @@ static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata) xgbe_init_function_ptrs_desc(&pdata->desc_if); } +#ifdef CONFIG_ACPI +static int xgbe_acpi_support(struct xgbe_prv_data *pdata) +{ + struct acpi_device *adev = pdata->adev; + struct device *dev = pdata->dev; + u32 property; + acpi_handle handle; + acpi_status status; + unsigned long long data; + int cca; + int ret; + + /* Obtain the system clock setting */ + ret = device_property_read_u32(dev, XGBE_ACPI_DMA_FREQ, &property); + if (ret) { + dev_err(dev, "unable to obtain %s property\n", + XGBE_ACPI_DMA_FREQ); + return ret; + } + pdata->sysclk_rate = property; + + /* Obtain the PTP clock setting */ + ret = device_property_read_u32(dev, XGBE_ACPI_PTP_FREQ, &property); + if (ret) { + dev_err(dev, "unable to obtain %s property\n", + XGBE_ACPI_PTP_FREQ); + return ret; + } + pdata->ptpclk_rate = property; + + /* Retrieve the device cache coherency value */ + handle = adev->handle; + do { + status = acpi_evaluate_integer(handle, "_CCA", NULL, &data); + if (!ACPI_FAILURE(status)) { + cca = data; + break; + } + + status = acpi_get_parent(handle, &handle); + } while (!ACPI_FAILURE(status)); + + if (ACPI_FAILURE(status)) { + dev_err(dev, "error obtaining acpi coherency value\n"); + return -EINVAL; + } + pdata->coherent = !!cca; + + return 0; +} +#else /* CONFIG_ACPI */ +static int xgbe_acpi_support(struct xgbe_prv_data *pdata) +{ + return -EINVAL; +} +#endif /* CONFIG_ACPI */ + +#ifdef CONFIG_OF +static int xgbe_of_support(struct xgbe_prv_data *pdata) +{ + struct device *dev = pdata->dev; + + /* Obtain the system clock setting */ + pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK); + if (IS_ERR(pdata->sysclk)) { + dev_err(dev, "dma devm_clk_get failed\n"); + return PTR_ERR(pdata->sysclk); + } + pdata->sysclk_rate = clk_get_rate(pdata->sysclk); + + /* Obtain the PTP clock setting */ + pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK); + if (IS_ERR(pdata->ptpclk)) { + dev_err(dev, "ptp devm_clk_get failed\n"); + return PTR_ERR(pdata->ptpclk); + } + pdata->ptpclk_rate = clk_get_rate(pdata->ptpclk); + + /* Retrieve the device cache coherency value */ + pdata->coherent = of_dma_is_coherent(dev->of_node); + + return 0; +} +#else /* CONFIG_OF */ +static int xgbe_of_support(struct xgbe_prv_data *pdata) +{ + return -EINVAL; +} +#endif /*CONFIG_OF */ + static int xgbe_probe(struct platform_device *pdev) { struct xgbe_prv_data *pdata; @@ -169,7 +263,7 @@ static int xgbe_probe(struct platform_device *pdev) struct net_device *netdev; struct device *dev = &pdev->dev; struct resource *res; - const u8 *mac_addr; + const char *phy_mode; unsigned int i; int ret; @@ -186,6 +280,7 @@ static int xgbe_probe(struct platform_device *pdev) pdata = netdev_priv(netdev); pdata->netdev = netdev; pdata->pdev = pdev; + pdata->adev = ACPI_COMPANION(dev); pdata->dev = dev; platform_set_drvdata(pdev, netdev); @@ -194,6 +289,9 @@ static int xgbe_probe(struct platform_device *pdev) mutex_init(&pdata->rss_mutex); spin_lock_init(&pdata->tstamp_lock); + /* Check if we should use ACPI or DT */ + pdata->use_acpi = (!pdata->adev || acpi_disabled) ? 0 : 1; + /* Set and validate the number of descriptors for a ring */ BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT); pdata->tx_desc_count = XGBE_TX_DESC_CNT; @@ -212,22 +310,6 @@ static int xgbe_probe(struct platform_device *pdev) goto err_io; } - /* Obtain the system clock setting */ - pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK); - if (IS_ERR(pdata->sysclk)) { - dev_err(dev, "dma devm_clk_get failed\n"); - ret = PTR_ERR(pdata->sysclk); - goto err_io; - } - - /* Obtain the PTP clock setting */ - pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK); - if (IS_ERR(pdata->ptpclk)) { - dev_err(dev, "ptp devm_clk_get failed\n"); - ret = PTR_ERR(pdata->ptpclk); - goto err_io; - } - /* Obtain the mmio areas for the device */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pdata->xgmac_regs = devm_ioremap_resource(dev, res); @@ -247,16 +329,42 @@ static int xgbe_probe(struct platform_device *pdev) } DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs); - /* Set the DMA mask */ - if (!dev->dma_mask) - dev->dma_mask = &dev->coherent_dma_mask; - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); - if (ret) { - dev_err(dev, "dma_set_mask_and_coherent failed\n"); + /* Retrieve the MAC address */ + ret = device_property_read_u8_array(dev, XGBE_MAC_ADDR_PROPERTY, + pdata->mac_addr, + sizeof(pdata->mac_addr)); + if (ret || !is_valid_ether_addr(pdata->mac_addr)) { + dev_err(dev, "invalid %s property\n", XGBE_MAC_ADDR_PROPERTY); + if (!ret) + ret = -EINVAL; goto err_io; } - if (of_property_read_bool(dev->of_node, "dma-coherent")) { + /* Retrieve the PHY mode - it must be "xgmii" */ + ret = device_property_read_string(dev, XGBE_PHY_MODE_PROPERTY, + &phy_mode); + if (ret || strcmp(phy_mode, phy_modes(PHY_INTERFACE_MODE_XGMII))) { + dev_err(dev, "invalid %s property\n", XGBE_PHY_MODE_PROPERTY); + if (!ret) + ret = -EINVAL; + goto err_io; + } + pdata->phy_mode = PHY_INTERFACE_MODE_XGMII; + + /* Check for per channel interrupt support */ + if (device_property_present(dev, XGBE_DMA_IRQS_PROPERTY)) + pdata->per_channel_irq = 1; + + /* Obtain device settings unique to ACPI/OF */ + if (pdata->use_acpi) + ret = xgbe_acpi_support(pdata); + else + ret = xgbe_of_support(pdata); + if (ret) + goto err_io; + + /* Set the DMA coherency values */ + if (pdata->coherent) { pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; pdata->arcache = XGBE_DMA_OS_ARCACHE; pdata->awcache = XGBE_DMA_OS_AWCACHE; @@ -266,10 +374,16 @@ static int xgbe_probe(struct platform_device *pdev) pdata->awcache = XGBE_DMA_SYS_AWCACHE; } - /* Check for per channel interrupt support */ - if (of_property_read_bool(dev->of_node, XGBE_DMA_IRQS)) - pdata->per_channel_irq = 1; + /* Set the DMA mask */ + if (!dev->dma_mask) + dev->dma_mask = &dev->coherent_dma_mask; + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); + if (ret) { + dev_err(dev, "dma_set_mask_and_coherent failed\n"); + goto err_io; + } + /* Get the device interrupt */ ret = platform_get_irq(pdev, 0); if (ret < 0) { dev_err(dev, "platform_get_irq 0 failed\n"); @@ -279,6 +393,7 @@ static int xgbe_probe(struct platform_device *pdev) netdev->irq = pdata->dev_irq; netdev->base_addr = (unsigned long)pdata->xgmac_regs; + memcpy(netdev->dev_addr, pdata->mac_addr, netdev->addr_len); /* Set all the function pointers */ xgbe_init_all_fptrs(pdata); @@ -291,23 +406,6 @@ static int xgbe_probe(struct platform_device *pdev) /* Populate the hardware features */ xgbe_get_all_hw_features(pdata); - /* Retrieve the MAC address */ - mac_addr = of_get_mac_address(dev->of_node); - if (!mac_addr) { - dev_err(dev, "invalid mac address for this device\n"); - ret = -EINVAL; - goto err_io; - } - memcpy(netdev->dev_addr, mac_addr, netdev->addr_len); - - /* Retrieve the PHY mode - it must be "xgmii" */ - pdata->phy_mode = of_get_phy_mode(dev->of_node); - if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { - dev_err(dev, "invalid phy-mode specified for this device\n"); - ret = -EINVAL; - goto err_io; - } - /* Set default configuration data */ xgbe_default_config(pdata); @@ -491,18 +589,35 @@ static int xgbe_resume(struct device *dev) } #endif /* CONFIG_PM */ +#ifdef CONFIG_ACPI +static const struct acpi_device_id xgbe_acpi_match[] = { + { "AMDI8001", 0 }, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, xgbe_acpi_match); +#endif + +#ifdef CONFIG_OF static const struct of_device_id xgbe_of_match[] = { { .compatible = "amd,xgbe-seattle-v1a", }, {}, }; MODULE_DEVICE_TABLE(of, xgbe_of_match); +#endif + static SIMPLE_DEV_PM_OPS(xgbe_pm_ops, xgbe_suspend, xgbe_resume); static struct platform_driver xgbe_driver = { .driver = { .name = "amd-xgbe", +#ifdef CONFIG_ACPI + .acpi_match_table = xgbe_acpi_match, +#endif +#ifdef CONFIG_OF .of_match_table = xgbe_of_match, +#endif .pm = &xgbe_pm_ops, }, .probe = xgbe_probe, diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 363b210560f3..59e267f3f1b7 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -205,25 +205,16 @@ void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata) int xgbe_mdio_register(struct xgbe_prv_data *pdata) { - struct device_node *phy_node; struct mii_bus *mii; struct phy_device *phydev; int ret = 0; DBGPR("-->xgbe_mdio_register\n"); - /* Retrieve the phy-handle */ - phy_node = of_parse_phandle(pdata->dev->of_node, "phy-handle", 0); - if (!phy_node) { - dev_err(pdata->dev, "unable to parse phy-handle\n"); - return -EINVAL; - } - mii = mdiobus_alloc(); - if (mii == NULL) { + if (!mii) { dev_err(pdata->dev, "mdiobus_alloc failed\n"); - ret = -ENOMEM; - goto err_node_get; + return -ENOMEM; } /* Register on the MDIO bus (don't probe any PHYs) */ @@ -252,18 +243,19 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phydev->c45_ids.device_ids[MDIO_MMD_PCS])); - of_node_get(phy_node); - phydev->dev.of_node = phy_node; ret = phy_device_register(phydev); if (ret) { dev_err(pdata->dev, "phy_device_register failed\n"); - of_node_put(phy_node); + goto err_phy_device; + } + if (!phydev->dev.driver) { + dev_err(pdata->dev, "phy driver probe failed\n"); + ret = -EIO; goto err_phy_device; } /* Add a reference to the PHY driver so it can't be unloaded */ - pdata->phy_module = phydev->dev.driver ? - phydev->dev.driver->owner : NULL; + pdata->phy_module = phydev->dev.driver->owner; if (!try_module_get(pdata->phy_module)) { dev_err(pdata->dev, "try_module_get failed\n"); ret = -EIO; @@ -283,8 +275,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata) pdata->phydev = phydev; - of_node_put(phy_node); - DBGPHY_REGS(pdata); DBGPR("<--xgbe_mdio_register\n"); @@ -300,9 +290,6 @@ err_mdiobus_register: err_mdiobus_alloc: mdiobus_free(mii); -err_node_get: - of_node_put(phy_node); - return ret; } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c index a1bf9d1cdae1..f326178ef376 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c @@ -171,15 +171,9 @@ static int xgbe_adjtime(struct ptp_clock_info *info, s64 delta) struct xgbe_prv_data, ptp_clock_info); unsigned long flags; - u64 nsec; spin_lock_irqsave(&pdata->tstamp_lock, flags); - - nsec = timecounter_read(&pdata->tstamp_tc); - - nsec += delta; - timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec); - + timecounter_adjtime(&pdata->tstamp_tc, delta); spin_unlock_irqrestore(&pdata->tstamp_lock, flags); return 0; @@ -239,7 +233,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) snprintf(info->name, sizeof(info->name), "%s", netdev_name(pdata->netdev)); info->owner = THIS_MODULE; - info->max_adj = clk_get_rate(pdata->ptpclk); + info->max_adj = pdata->ptpclk_rate; info->adjfreq = xgbe_adjfreq; info->adjtime = xgbe_adjtime; info->gettime = xgbe_gettime; @@ -260,7 +254,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) */ dividend = 50000000; dividend <<= 32; - pdata->tstamp_addend = div_u64(dividend, clk_get_rate(pdata->ptpclk)); + pdata->tstamp_addend = div_u64(dividend, pdata->ptpclk_rate); /* Setup the timecounter */ cc->read = xgbe_cc_read; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index f9ec762ac3f0..13e8f95c077c 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -124,7 +124,7 @@ #include #include #include -#include +#include #include #include @@ -182,10 +182,18 @@ #define XGBE_PHY_NAME "amd_xgbe_phy" #define XGBE_PRTAD 0 +/* Common property names */ +#define XGBE_MAC_ADDR_PROPERTY "mac-address" +#define XGBE_PHY_MODE_PROPERTY "phy-mode" +#define XGBE_DMA_IRQS_PROPERTY "amd,per-channel-interrupt" + /* Device-tree clock names */ #define XGBE_DMA_CLOCK "dma_clk" #define XGBE_PTP_CLOCK "ptp_clk" -#define XGBE_DMA_IRQS "amd,per-channel-interrupt" + +/* ACPI property names */ +#define XGBE_ACPI_DMA_FREQ "amd,dma-freq" +#define XGBE_ACPI_PTP_FREQ "amd,ptp-freq" /* Timestamp support - values based on 50MHz PTP clock * 50MHz => 20 nsec @@ -361,8 +369,7 @@ struct xgbe_ring { * cur - Tx: index of descriptor to be used for current transfer * Rx: index of descriptor to check for packet availability * dirty - Tx: index of descriptor to check for transfer complete - * Rx: count of descriptors in which a packet has been received - * (used with skb_realloc_index to refresh the ring) + * Rx: index of descriptor to check for buffer reallocation */ unsigned int cur; unsigned int dirty; @@ -377,11 +384,6 @@ struct xgbe_ring { unsigned short cur_mss; unsigned short cur_vlan_ctag; } tx; - - struct { - unsigned int realloc_index; - unsigned int realloc_threshold; - } rx; }; } ____cacheline_aligned; @@ -596,7 +598,8 @@ struct xgbe_desc_if { int (*alloc_ring_resources)(struct xgbe_prv_data *); void (*free_ring_resources)(struct xgbe_prv_data *); int (*map_tx_skb)(struct xgbe_channel *, struct sk_buff *); - void (*realloc_rx_buffer)(struct xgbe_channel *); + int (*map_rx_buffer)(struct xgbe_prv_data *, struct xgbe_ring *, + struct xgbe_ring_data *); void (*unmap_rdata)(struct xgbe_prv_data *, struct xgbe_ring_data *); void (*wrapper_tx_desc_init)(struct xgbe_prv_data *); void (*wrapper_rx_desc_init)(struct xgbe_prv_data *); @@ -650,8 +653,12 @@ struct xgbe_hw_features { struct xgbe_prv_data { struct net_device *netdev; struct platform_device *pdev; + struct acpi_device *adev; struct device *dev; + /* ACPI or DT flag */ + unsigned int use_acpi; + /* XGMAC/XPCS related mmio registers */ void __iomem *xgmac_regs; /* XGMAC CSRs */ void __iomem *xpcs_regs; /* XPCS MMD registers */ @@ -672,6 +679,7 @@ struct xgbe_prv_data { struct xgbe_desc_if desc_if; /* AXI DMA settings */ + unsigned int coherent; unsigned int axdomain; unsigned int arcache; unsigned int awcache; @@ -739,6 +747,7 @@ struct xgbe_prv_data { unsigned int phy_rx_pause; /* Netdev related settings */ + unsigned char mac_addr[ETH_ALEN]; netdev_features_t netdev_features; struct napi_struct napi; struct xgbe_mmc_stats mmc_stats; @@ -748,7 +757,9 @@ struct xgbe_prv_data { /* Device clocks */ struct clk *sysclk; + unsigned long sysclk_rate; struct clk *ptpclk; + unsigned long ptpclk_rate; /* Timestamp support */ spinlock_t tstamp_lock; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 7ba83ffb08ac..869d97fcf781 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -593,10 +593,12 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata) if (!xgene_ring_mgr_init(pdata)) return -ENODEV; - clk_prepare_enable(pdata->clk); - clk_disable_unprepare(pdata->clk); - clk_prepare_enable(pdata->clk); - xgene_enet_ecc_init(pdata); + if (!efi_enabled(EFI_BOOT)) { + clk_prepare_enable(pdata->clk); + clk_disable_unprepare(pdata->clk); + clk_prepare_enable(pdata->clk); + xgene_enet_ecc_init(pdata); + } xgene_enet_config_ring_if_assoc(pdata); /* Enable auto-incr for scanning */ @@ -663,15 +665,20 @@ static int xgene_enet_phy_connect(struct net_device *ndev) struct phy_device *phy_dev; struct device *dev = &pdata->pdev->dev; - phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0); - if (!phy_np) { - netdev_dbg(ndev, "No phy-handle found\n"); - return -ENODEV; + if (dev->of_node) { + phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0); + if (!phy_np) { + netdev_dbg(ndev, "No phy-handle found in DT\n"); + return -ENODEV; + } + pdata->phy_dev = of_phy_find_device(phy_np); } - phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link, - 0, pdata->phy_mode); - if (!phy_dev) { + phy_dev = pdata->phy_dev; + + if (!phy_dev || + phy_connect_direct(ndev, phy_dev, &xgene_enet_adjust_link, + pdata->phy_mode)) { netdev_err(ndev, "Could not connect to PHY\n"); return -ENODEV; } @@ -681,32 +688,71 @@ static int xgene_enet_phy_connect(struct net_device *ndev) ~SUPPORTED_100baseT_Half & ~SUPPORTED_1000baseT_Half; phy_dev->advertising = phy_dev->supported; - pdata->phy_dev = phy_dev; return 0; } +static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata, + struct mii_bus *mdio) +{ + struct device *dev = &pdata->pdev->dev; + struct net_device *ndev = pdata->ndev; + struct phy_device *phy; + struct device_node *child_np; + struct device_node *mdio_np = NULL; + int ret; + u32 phy_id; + + if (dev->of_node) { + for_each_child_of_node(dev->of_node, child_np) { + if (of_device_is_compatible(child_np, + "apm,xgene-mdio")) { + mdio_np = child_np; + break; + } + } + + if (!mdio_np) { + netdev_dbg(ndev, "No mdio node in the dts\n"); + return -ENXIO; + } + + return of_mdiobus_register(mdio, mdio_np); + } + + /* Mask out all PHYs from auto probing. */ + mdio->phy_mask = ~0; + + /* Register the MDIO bus */ + ret = mdiobus_register(mdio); + if (ret) + return ret; + + ret = device_property_read_u32(dev, "phy-channel", &phy_id); + if (ret) + ret = device_property_read_u32(dev, "phy-addr", &phy_id); + if (ret) + return -EINVAL; + + phy = get_phy_device(mdio, phy_id, true); + if (!phy || IS_ERR(phy)) + return -EIO; + + ret = phy_device_register(phy); + if (ret) + phy_device_free(phy); + else + pdata->phy_dev = phy; + + return ret; +} + int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) { struct net_device *ndev = pdata->ndev; - struct device *dev = &pdata->pdev->dev; - struct device_node *child_np; - struct device_node *mdio_np = NULL; struct mii_bus *mdio_bus; int ret; - for_each_child_of_node(dev->of_node, child_np) { - if (of_device_is_compatible(child_np, "apm,xgene-mdio")) { - mdio_np = child_np; - break; - } - } - - if (!mdio_np) { - netdev_dbg(ndev, "No mdio node in the dts\n"); - return -ENXIO; - } - mdio_bus = mdiobus_alloc(); if (!mdio_bus) return -ENOMEM; @@ -720,7 +766,7 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) mdio_bus->priv = pdata; mdio_bus->parent = &ndev->dev; - ret = of_mdiobus_register(mdio_bus, mdio_np); + ret = xgene_mdiobus_register(pdata, mdio_bus); if (ret) { netdev_err(ndev, "Failed to register MDIO bus\n"); mdiobus_free(mdio_bus); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 83a50280bb70..44b15373d6b3 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -24,6 +24,10 @@ #include "xgene_enet_sgmac.h" #include "xgene_enet_xgmac.h" +#define RES_ENET_CSR 0 +#define RES_RING_CSR 1 +#define RES_RING_CMD 2 + static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool) { struct xgene_enet_raw_desc16 *raw_desc; @@ -369,6 +373,8 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring, if (unlikely(xgene_enet_is_desc_slot_empty(raw_desc))) break; + /* read fpqnum field after dataaddr field */ + dma_rmb(); if (is_rx_desc(raw_desc)) ret = xgene_enet_rx_frame(ring, raw_desc); else @@ -746,6 +752,41 @@ static const struct net_device_ops xgene_ndev_ops = { .ndo_set_mac_address = xgene_enet_set_mac_address, }; +static int xgene_get_mac_address(struct device *dev, + unsigned char *addr) +{ + int ret; + + ret = device_property_read_u8_array(dev, "local-mac-address", addr, 6); + if (ret) + ret = device_property_read_u8_array(dev, "mac-address", + addr, 6); + if (ret) + return -ENODEV; + + return ETH_ALEN; +} + +static int xgene_get_phy_mode(struct device *dev) +{ + int i, ret; + char *modestr; + + ret = device_property_read_string(dev, "phy-connection-type", + (const char **)&modestr); + if (ret) + ret = device_property_read_string(dev, "phy-mode", + (const char **)&modestr); + if (ret) + return -ENODEV; + + for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) { + if (!strcasecmp(modestr, phy_modes(i))) + return i; + } + return -ENODEV; +} + static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) { struct platform_device *pdev; @@ -753,32 +794,45 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) struct device *dev; struct resource *res; void __iomem *base_addr; - const char *mac; int ret; pdev = pdata->pdev; dev = &pdev->dev; ndev = pdata->ndev; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "enet_csr"); - pdata->base_addr = devm_ioremap_resource(dev, res); - if (IS_ERR(pdata->base_addr)) { + res = platform_get_resource(pdev, IORESOURCE_MEM, RES_ENET_CSR); + if (!res) { + dev_err(dev, "Resource enet_csr not defined\n"); + return -ENODEV; + } + pdata->base_addr = devm_ioremap(dev, res->start, resource_size(res)); + if (!pdata->base_addr) { dev_err(dev, "Unable to retrieve ENET Port CSR region\n"); - return PTR_ERR(pdata->base_addr); + return -ENOMEM; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_csr"); - pdata->ring_csr_addr = devm_ioremap_resource(dev, res); - if (IS_ERR(pdata->ring_csr_addr)) { + res = platform_get_resource(pdev, IORESOURCE_MEM, RES_RING_CSR); + if (!res) { + dev_err(dev, "Resource ring_csr not defined\n"); + return -ENODEV; + } + pdata->ring_csr_addr = devm_ioremap(dev, res->start, + resource_size(res)); + if (!pdata->ring_csr_addr) { dev_err(dev, "Unable to retrieve ENET Ring CSR region\n"); - return PTR_ERR(pdata->ring_csr_addr); + return -ENOMEM; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_cmd"); - pdata->ring_cmd_addr = devm_ioremap_resource(dev, res); - if (IS_ERR(pdata->ring_cmd_addr)) { + res = platform_get_resource(pdev, IORESOURCE_MEM, RES_RING_CMD); + if (!res) { + dev_err(dev, "Resource ring_cmd not defined\n"); + return -ENODEV; + } + pdata->ring_cmd_addr = devm_ioremap(dev, res->start, + resource_size(res)); + if (!pdata->ring_cmd_addr) { dev_err(dev, "Unable to retrieve ENET Ring command region\n"); - return PTR_ERR(pdata->ring_cmd_addr); + return -ENOMEM; } ret = platform_get_irq(pdev, 0); @@ -789,14 +843,12 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) } pdata->rx_irq = ret; - mac = of_get_mac_address(dev->of_node); - if (mac) - memcpy(ndev->dev_addr, mac, ndev->addr_len); - else + if (xgene_get_mac_address(dev, ndev->dev_addr) != ETH_ALEN) eth_hw_addr_random(ndev); + memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len); - pdata->phy_mode = of_get_phy_mode(pdev->dev.of_node); + pdata->phy_mode = xgene_get_phy_mode(dev); if (pdata->phy_mode < 0) { dev_err(dev, "Unable to get phy-connection-type\n"); return pdata->phy_mode; @@ -809,11 +861,9 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) } pdata->clk = devm_clk_get(&pdev->dev, NULL); - ret = IS_ERR(pdata->clk); if (IS_ERR(pdata->clk)) { - dev_err(&pdev->dev, "can't get clock\n"); - ret = PTR_ERR(pdata->clk); - return ret; + /* Firmware may have set up the clock already. */ + pdata->clk = NULL; } base_addr = pdata->base_addr; @@ -924,7 +974,7 @@ static int xgene_enet_probe(struct platform_device *pdev) goto err; } - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); if (ret) { netdev_err(ndev, "No usable DMA configuration\n"); goto err; @@ -972,17 +1022,26 @@ static int xgene_enet_remove(struct platform_device *pdev) return 0; } -static struct of_device_id xgene_enet_match[] = { +#ifdef CONFIG_ACPI +static const struct acpi_device_id xgene_enet_acpi_match[] = { + { "APMC0D05", }, + { } +}; +MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match); +#endif + +static struct of_device_id xgene_enet_of_match[] = { {.compatible = "apm,xgene-enet",}, {}, }; -MODULE_DEVICE_TABLE(of, xgene_enet_match); +MODULE_DEVICE_TABLE(of, xgene_enet_of_match); static struct platform_driver xgene_enet_driver = { .driver = { .name = "xgene-enet", - .of_match_table = xgene_enet_match, + .of_match_table = of_match_ptr(xgene_enet_of_match), + .acpi_match_table = ACPI_PTR(xgene_enet_acpi_match), }, .probe = xgene_enet_probe, .remove = xgene_enet_remove, diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index f9958fae6ffd..c2d465c3db66 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -22,7 +22,10 @@ #ifndef __XGENE_ENET_MAIN_H__ #define __XGENE_ENET_MAIN_H__ +#include #include +#include +#include #include #include #include diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index c9946c6c119e..587f63e87588 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -2235,8 +2235,8 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb, return NETDEV_TX_OK; } - if (unlikely(vlan_tx_tag_present(skb))) { - u16 vlan = vlan_tx_tag_get(skb); + if (unlikely(skb_vlan_tag_present(skb))) { + u16 vlan = skb_vlan_tag_get(skb); __le16 tag; vlan = cpu_to_le16(vlan); diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c index 2326579f9454..59a03a193e83 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c @@ -1892,8 +1892,8 @@ static netdev_tx_t atl1e_xmit_frame(struct sk_buff *skb, tpd = atl1e_get_tpd(adapter); - if (vlan_tx_tag_present(skb)) { - u16 vlan_tag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) { + u16 vlan_tag = skb_vlan_tag_get(skb); u16 atl1e_vlan_tag; tpd->word3 |= 1 << TPD_INS_VL_TAG_SHIFT; @@ -2373,9 +2373,8 @@ static int atl1e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netif_napi_add(netdev, &adapter->napi, atl1e_clean, 64); - init_timer(&adapter->phy_config_timer); - adapter->phy_config_timer.function = atl1e_phy_config; - adapter->phy_config_timer.data = (unsigned long) adapter; + setup_timer(&adapter->phy_config_timer, atl1e_phy_config, + (unsigned long)adapter); /* get user settings */ atl1e_check_options(adapter); diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c index 2c8f398aeda9..eca1d113fee1 100644 --- a/drivers/net/ethernet/atheros/atlx/atl1.c +++ b/drivers/net/ethernet/atheros/atlx/atl1.c @@ -2415,8 +2415,8 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb, (u16) atomic_read(&tpd_ring->next_to_use)); memset(ptpd, 0, sizeof(struct tx_packet_desc)); - if (vlan_tx_tag_present(skb)) { - vlan_tag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) { + vlan_tag = skb_vlan_tag_get(skb); vlan_tag = (vlan_tag << 4) | (vlan_tag >> 13) | ((vlan_tag >> 9) & 0x8); ptpd->word3 |= 1 << TPD_INS_VL_TAG_SHIFT; diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c index 84a09e8ddd9c..46a535318c7a 100644 --- a/drivers/net/ethernet/atheros/atlx/atl2.c +++ b/drivers/net/ethernet/atheros/atlx/atl2.c @@ -887,8 +887,8 @@ static netdev_tx_t atl2_xmit_frame(struct sk_buff *skb, offset = ((u32)(skb->len-copy_len + 3) & ~3); } #ifdef NETIF_F_HW_VLAN_CTAG_TX - if (vlan_tx_tag_present(skb)) { - u16 vlan_tag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) { + u16 vlan_tag = skb_vlan_tag_get(skb); vlan_tag = (vlan_tag << 4) | (vlan_tag >> 13) | ((vlan_tag >> 9) & 0x8); @@ -1436,13 +1436,11 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) atl2_check_options(adapter); - init_timer(&adapter->watchdog_timer); - adapter->watchdog_timer.function = atl2_watchdog; - adapter->watchdog_timer.data = (unsigned long) adapter; + setup_timer(&adapter->watchdog_timer, atl2_watchdog, + (unsigned long)adapter); - init_timer(&adapter->phy_config_timer); - adapter->phy_config_timer.function = atl2_phy_config; - adapter->phy_config_timer.data = (unsigned long) adapter; + setup_timer(&adapter->phy_config_timer, atl2_phy_config, + (unsigned long)adapter); INIT_WORK(&adapter->reset_task, atl2_reset_task); INIT_WORK(&adapter->link_chg_task, atl2_link_chg_task); diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 05c6af6c418f..3007d95fbb9f 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -1167,10 +1167,10 @@ static int bgmac_poll(struct napi_struct *napi, int weight) bgmac->int_status = 0; } - if (handled < weight) + if (handled < weight) { napi_complete(napi); - - bgmac_chip_intrs_on(bgmac); + bgmac_chip_intrs_on(bgmac); + } return handled; } @@ -1515,6 +1515,8 @@ static int bgmac_probe(struct bcma_device *core) if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM) bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n"); + netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT); + err = bgmac_mii_register(bgmac); if (err) { bgmac_err(bgmac, "Cannot register MDIO\n"); @@ -1529,8 +1531,6 @@ static int bgmac_probe(struct bcma_device *core) netif_carrier_off(net_dev); - netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT); - return 0; err_mii_unregister: @@ -1549,9 +1549,9 @@ static void bgmac_remove(struct bcma_device *core) { struct bgmac *bgmac = bcma_get_drvdata(core); - netif_napi_del(&bgmac->napi); unregister_netdev(bgmac->net_dev); bgmac_mii_unregister(bgmac); + netif_napi_del(&bgmac->napi); bgmac_dma_free(bgmac); bcma_set_drvdata(core, NULL); free_netdev(bgmac->net_dev); diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 823d01c5684c..02bf0b86995b 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -6597,9 +6597,9 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM; } - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { vlan_tag_flags |= - (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16)); + (TX_BD_FLAGS_VLAN_TAG | (skb_vlan_tag_get(skb) << 16)); } if ((mss = skb_shinfo(skb)->gso_size)) { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index c3a6072134f5..756053c028be 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -22,7 +22,7 @@ #include #include -#include +#include /* compilation time flags */ @@ -1138,12 +1138,8 @@ struct bnx2x_port { u32 link_config[LINK_CONFIG_SIZE]; u32 supported[LINK_CONFIG_SIZE]; -/* link settings - missing defines */ -#define SUPPORTED_2500baseX_Full (1 << 15) u32 advertising[LINK_CONFIG_SIZE]; -/* link settings - missing defines */ -#define ADVERTISED_2500baseX_Full (1 << 15) u32 phy_addr; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 1d1147c93d59..0a9faa134a9a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3175,7 +3175,7 @@ static int bnx2x_poll(struct napi_struct *napi, int budget) } #endif if (!bnx2x_fp_lock_napi(fp)) - return work_done; + return budget; for_each_cos_in_tx_queue(fp, cos) if (bnx2x_tx_queue_has_work(fp->txdata_ptr[cos])) @@ -3865,9 +3865,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) "sending pkt %u @%p next_idx %u bd %u @%p\n", pkt_prod, tx_buf, txdata->tx_pkt_prod, bd_prod, tx_start_bd); - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { tx_start_bd->vlan_or_ethertype = - cpu_to_le16(vlan_tx_tag_get(skb)); + cpu_to_le16(skb_vlan_tag_get(skb)); tx_start_bd->bd_flags.as_bitfield |= (X_ETH_OUTBAND_VLAN << ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT); } else { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 72eef9fc883e..7155e1d2c208 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -9169,7 +9169,7 @@ static void bnx2x_disable_ptp(struct bnx2x *bp) } /* Called during unload, to stop PTP-related stuff */ -void bnx2x_stop_ptp(struct bnx2x *bp) +static void bnx2x_stop_ptp(struct bnx2x *bp) { /* Cancel PTP work queue. Should be done after the Tx queues are * drained to prevent additional scheduling. @@ -13267,14 +13267,10 @@ static int bnx2x_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) static int bnx2x_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info); - u64 now; DP(BNX2X_MSG_PTP, "PTP adjtime called, delta = %llx\n", delta); - now = timecounter_read(&bp->timecounter); - now += delta; - /* Re-init the timecounter */ - timecounter_init(&bp->timecounter, &bp->cyclecounter, now); + timecounter_adjtime(&bp->timecounter, delta); return 0; } @@ -13322,7 +13318,7 @@ static int bnx2x_ptp_enable(struct ptp_clock_info *ptp, return -ENOTSUPP; } -void bnx2x_register_phc(struct bnx2x *bp) +static void bnx2x_register_phc(struct bnx2x *bp) { /* Fill the ptp_clock_info struct and register PTP clock*/ bp->ptp_clock_info.owner = THIS_MODULE; @@ -14614,7 +14610,7 @@ static void bnx2x_init_cyclecounter(struct bnx2x *bp) { memset(&bp->cyclecounter, 0, sizeof(bp->cyclecounter)); bp->cyclecounter.read = bnx2x_cyclecounter_read; - bp->cyclecounter.mask = CLOCKSOURCE_MASK(64); + bp->cyclecounter.mask = CYCLECOUNTER_MASK(64); bp->cyclecounter.shift = 1; bp->cyclecounter.mult = 1; } @@ -14639,7 +14635,7 @@ static int bnx2x_send_reset_timesync_ramrod(struct bnx2x *bp) return bnx2x_func_state_change(bp, &func_params); } -int bnx2x_enable_ptp_packets(struct bnx2x *bp) +static int bnx2x_enable_ptp_packets(struct bnx2x *bp) { struct bnx2x_queue_state_params q_params; int rc, i; diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 96bf01ba32dd..615a6dbde047 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -8008,9 +8008,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) !mss && skb->len > VLAN_ETH_FRAME_LEN) base_flags |= TXD_FLAG_JMB_PKT; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { base_flags |= TXD_FLAG_VLAN; - vlan = vlan_tx_tag_get(skb); + vlan = skb_vlan_tag_get(skb); } if ((unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) && @@ -11573,11 +11573,7 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq, tg3_flag_set(tp, INIT_COMPLETE); tg3_enable_ints(tp); - if (init) - tg3_ptp_init(tp); - else - tg3_ptp_resume(tp); - + tg3_ptp_resume(tp); tg3_full_unlock(tp); @@ -11698,13 +11694,6 @@ static int tg3_open(struct net_device *dev) pci_set_power_state(tp->pdev, PCI_D3hot); } - if (tg3_flag(tp, PTP_CAPABLE)) { - tp->ptp_clock = ptp_clock_register(&tp->ptp_info, - &tp->pdev->dev); - if (IS_ERR(tp->ptp_clock)) - tp->ptp_clock = NULL; - } - return err; } @@ -11718,8 +11707,6 @@ static int tg3_close(struct net_device *dev) return -EAGAIN; } - tg3_ptp_fini(tp); - tg3_stop(tp); /* Clear stats across close / open calls */ @@ -17897,6 +17884,14 @@ static int tg3_init_one(struct pci_dev *pdev, goto err_out_apeunmap; } + if (tg3_flag(tp, PTP_CAPABLE)) { + tg3_ptp_init(tp); + tp->ptp_clock = ptp_clock_register(&tp->ptp_info, + &tp->pdev->dev); + if (IS_ERR(tp->ptp_clock)) + tp->ptp_clock = NULL; + } + netdev_info(dev, "Tigon3 [partno(%s) rev %04x] (%s) MAC address %pM\n", tp->board_part_number, tg3_chip_rev_id(tp), @@ -17972,6 +17967,8 @@ static void tg3_remove_one(struct pci_dev *pdev) if (dev) { struct tg3 *tp = netdev_priv(dev); + tg3_ptp_fini(tp); + release_firmware(tp->fw); tg3_reset_task_cancel(tp); diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c index 323721838cf9..7714d7790089 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.c +++ b/drivers/net/ethernet/brocade/bna/bnad.c @@ -2824,8 +2824,8 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb, u32 gso_size; u16 vlan_tag = 0; - if (vlan_tx_tag_present(skb)) { - vlan_tag = (u16)vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) { + vlan_tag = (u16)skb_vlan_tag_get(skb); flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN); } if (test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags)) { diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 3767271c7667..ad76b8e35a00 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -1691,7 +1691,7 @@ static int hash_get_index(__u8 *addr) for (j = 0; j < 6; j++) { for (i = 0, bitval = 0; i < 8; i++) - bitval ^= hash_bit_value(i*6 + j, addr); + bitval ^= hash_bit_value(i * 6 + j, addr); hash_index |= (bitval << j); } @@ -1827,12 +1827,23 @@ static int macb_close(struct net_device *dev) static void gem_update_stats(struct macb *bp) { - u32 __iomem *reg = bp->regs + GEM_OTX; + int i; u32 *p = &bp->hw_stats.gem.tx_octets_31_0; - u32 *end = &bp->hw_stats.gem.rx_udp_checksum_errors + 1; - for (; p < end; p++, reg++) - *p += __raw_readl(reg); + for (i = 0; i < GEM_STATS_LEN; ++i, ++p) { + u32 offset = gem_statistics[i].offset; + u64 val = __raw_readl(bp->regs + offset); + + bp->ethtool_stats[i] += val; + *p += val; + + if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) { + /* Add GEM_OCTTXH, GEM_OCTRXH */ + val = __raw_readl(bp->regs + offset + 4); + bp->ethtool_stats[i] += ((u64)val) << 32; + *(++p) += val; + } + } } static struct net_device_stats *gem_get_stats(struct macb *bp) @@ -1873,6 +1884,39 @@ static struct net_device_stats *gem_get_stats(struct macb *bp) return nstat; } +static void gem_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct macb *bp; + + bp = netdev_priv(dev); + gem_update_stats(bp); + memcpy(data, &bp->ethtool_stats, sizeof(u64) * GEM_STATS_LEN); +} + +static int gem_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return GEM_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p) +{ + int i; + + switch (sset) { + case ETH_SS_STATS: + for (i = 0; i < GEM_STATS_LEN; i++, p += ETH_GSTRING_LEN) + memcpy(p, gem_statistics[i].stat_string, + ETH_GSTRING_LEN); + break; + } +} + struct net_device_stats *macb_get_stats(struct net_device *dev) { struct macb *bp = netdev_priv(dev); @@ -1991,6 +2035,18 @@ const struct ethtool_ops macb_ethtool_ops = { }; EXPORT_SYMBOL_GPL(macb_ethtool_ops); +static const struct ethtool_ops gem_ethtool_ops = { + .get_settings = macb_get_settings, + .set_settings = macb_set_settings, + .get_regs_len = macb_get_regs_len, + .get_regs = macb_get_regs, + .get_link = ethtool_op_get_link, + .get_ts_info = ethtool_op_get_ts_info, + .get_ethtool_stats = gem_get_ethtool_stats, + .get_strings = gem_get_ethtool_strings, + .get_sset_count = gem_get_sset_count, +}; + int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct macb *bp = netdev_priv(dev); @@ -2148,7 +2204,7 @@ static void macb_probe_queues(void __iomem *mem, (*num_queues)++; } -static int __init macb_probe(struct platform_device *pdev) +static int macb_probe(struct platform_device *pdev) { struct macb_platform_data *pdata; struct resource *regs; @@ -2278,7 +2334,6 @@ static int __init macb_probe(struct platform_device *pdev) dev->netdev_ops = &macb_netdev_ops; netif_napi_add(dev, &bp->napi, macb_poll, 64); - dev->ethtool_ops = &macb_ethtool_ops; dev->base_addr = regs->start; @@ -2292,12 +2347,14 @@ static int __init macb_probe(struct platform_device *pdev) bp->macbgem_ops.mog_free_rx_buffers = gem_free_rx_buffers; bp->macbgem_ops.mog_init_rings = gem_init_rings; bp->macbgem_ops.mog_rx = gem_rx; + dev->ethtool_ops = &gem_ethtool_ops; } else { bp->max_tx_length = MACB_MAX_TX_LEN; bp->macbgem_ops.mog_alloc_rx_buffers = macb_alloc_rx_buffers; bp->macbgem_ops.mog_free_rx_buffers = macb_free_rx_buffers; bp->macbgem_ops.mog_init_rings = macb_init_rings; bp->macbgem_ops.mog_rx = macb_rx; + dev->ethtool_ops = &macb_ethtool_ops; } /* Set features */ @@ -2386,7 +2443,7 @@ err_out: return err; } -static int __exit macb_remove(struct platform_device *pdev) +static int macb_remove(struct platform_device *pdev) { struct net_device *dev; struct macb *bp; @@ -2411,8 +2468,7 @@ static int __exit macb_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int macb_suspend(struct device *dev) +static int __maybe_unused macb_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct net_device *netdev = platform_get_drvdata(pdev); @@ -2429,7 +2485,7 @@ static int macb_suspend(struct device *dev) return 0; } -static int macb_resume(struct device *dev) +static int __maybe_unused macb_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct net_device *netdev = platform_get_drvdata(pdev); @@ -2444,12 +2500,12 @@ static int macb_resume(struct device *dev) return 0; } -#endif static SIMPLE_DEV_PM_OPS(macb_pm_ops, macb_suspend, macb_resume); static struct platform_driver macb_driver = { - .remove = __exit_p(macb_remove), + .probe = macb_probe, + .remove = macb_remove, .driver = { .name = "macb", .of_match_table = of_match_ptr(macb_dt_ids), @@ -2457,7 +2513,7 @@ static struct platform_driver macb_driver = { }, }; -module_platform_driver_probe(macb_driver, macb_probe); +module_platform_driver(macb_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cadence MACB/GEM Ethernet driver"); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 084191b6fad2..31dc080f2437 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -15,263 +15,309 @@ #define MACB_MAX_QUEUES 8 /* MACB register offsets */ -#define MACB_NCR 0x0000 -#define MACB_NCFGR 0x0004 -#define MACB_NSR 0x0008 -#define MACB_TAR 0x000c /* AT91RM9200 only */ -#define MACB_TCR 0x0010 /* AT91RM9200 only */ -#define MACB_TSR 0x0014 -#define MACB_RBQP 0x0018 -#define MACB_TBQP 0x001c -#define MACB_RSR 0x0020 -#define MACB_ISR 0x0024 -#define MACB_IER 0x0028 -#define MACB_IDR 0x002c -#define MACB_IMR 0x0030 -#define MACB_MAN 0x0034 -#define MACB_PTR 0x0038 -#define MACB_PFR 0x003c -#define MACB_FTO 0x0040 -#define MACB_SCF 0x0044 -#define MACB_MCF 0x0048 -#define MACB_FRO 0x004c -#define MACB_FCSE 0x0050 -#define MACB_ALE 0x0054 -#define MACB_DTF 0x0058 -#define MACB_LCOL 0x005c -#define MACB_EXCOL 0x0060 -#define MACB_TUND 0x0064 -#define MACB_CSE 0x0068 -#define MACB_RRE 0x006c -#define MACB_ROVR 0x0070 -#define MACB_RSE 0x0074 -#define MACB_ELE 0x0078 -#define MACB_RJA 0x007c -#define MACB_USF 0x0080 -#define MACB_STE 0x0084 -#define MACB_RLE 0x0088 -#define MACB_TPF 0x008c -#define MACB_HRB 0x0090 -#define MACB_HRT 0x0094 -#define MACB_SA1B 0x0098 -#define MACB_SA1T 0x009c -#define MACB_SA2B 0x00a0 -#define MACB_SA2T 0x00a4 -#define MACB_SA3B 0x00a8 -#define MACB_SA3T 0x00ac -#define MACB_SA4B 0x00b0 -#define MACB_SA4T 0x00b4 -#define MACB_TID 0x00b8 -#define MACB_TPQ 0x00bc -#define MACB_USRIO 0x00c0 -#define MACB_WOL 0x00c4 -#define MACB_MID 0x00fc +#define MACB_NCR 0x0000 /* Network Control */ +#define MACB_NCFGR 0x0004 /* Network Config */ +#define MACB_NSR 0x0008 /* Network Status */ +#define MACB_TAR 0x000c /* AT91RM9200 only */ +#define MACB_TCR 0x0010 /* AT91RM9200 only */ +#define MACB_TSR 0x0014 /* Transmit Status */ +#define MACB_RBQP 0x0018 /* RX Q Base Address */ +#define MACB_TBQP 0x001c /* TX Q Base Address */ +#define MACB_RSR 0x0020 /* Receive Status */ +#define MACB_ISR 0x0024 /* Interrupt Status */ +#define MACB_IER 0x0028 /* Interrupt Enable */ +#define MACB_IDR 0x002c /* Interrupt Disable */ +#define MACB_IMR 0x0030 /* Interrupt Mask */ +#define MACB_MAN 0x0034 /* PHY Maintenance */ +#define MACB_PTR 0x0038 +#define MACB_PFR 0x003c +#define MACB_FTO 0x0040 +#define MACB_SCF 0x0044 +#define MACB_MCF 0x0048 +#define MACB_FRO 0x004c +#define MACB_FCSE 0x0050 +#define MACB_ALE 0x0054 +#define MACB_DTF 0x0058 +#define MACB_LCOL 0x005c +#define MACB_EXCOL 0x0060 +#define MACB_TUND 0x0064 +#define MACB_CSE 0x0068 +#define MACB_RRE 0x006c +#define MACB_ROVR 0x0070 +#define MACB_RSE 0x0074 +#define MACB_ELE 0x0078 +#define MACB_RJA 0x007c +#define MACB_USF 0x0080 +#define MACB_STE 0x0084 +#define MACB_RLE 0x0088 +#define MACB_TPF 0x008c +#define MACB_HRB 0x0090 +#define MACB_HRT 0x0094 +#define MACB_SA1B 0x0098 +#define MACB_SA1T 0x009c +#define MACB_SA2B 0x00a0 +#define MACB_SA2T 0x00a4 +#define MACB_SA3B 0x00a8 +#define MACB_SA3T 0x00ac +#define MACB_SA4B 0x00b0 +#define MACB_SA4T 0x00b4 +#define MACB_TID 0x00b8 +#define MACB_TPQ 0x00bc +#define MACB_USRIO 0x00c0 +#define MACB_WOL 0x00c4 +#define MACB_MID 0x00fc /* GEM register offsets. */ -#define GEM_NCFGR 0x0004 -#define GEM_USRIO 0x000c -#define GEM_DMACFG 0x0010 -#define GEM_HRB 0x0080 -#define GEM_HRT 0x0084 -#define GEM_SA1B 0x0088 -#define GEM_SA1T 0x008C -#define GEM_SA2B 0x0090 -#define GEM_SA2T 0x0094 -#define GEM_SA3B 0x0098 -#define GEM_SA3T 0x009C -#define GEM_SA4B 0x00A0 -#define GEM_SA4T 0x00A4 -#define GEM_OTX 0x0100 -#define GEM_DCFG1 0x0280 -#define GEM_DCFG2 0x0284 -#define GEM_DCFG3 0x0288 -#define GEM_DCFG4 0x028c -#define GEM_DCFG5 0x0290 -#define GEM_DCFG6 0x0294 -#define GEM_DCFG7 0x0298 +#define GEM_NCFGR 0x0004 /* Network Config */ +#define GEM_USRIO 0x000c /* User IO */ +#define GEM_DMACFG 0x0010 /* DMA Configuration */ +#define GEM_HRB 0x0080 /* Hash Bottom */ +#define GEM_HRT 0x0084 /* Hash Top */ +#define GEM_SA1B 0x0088 /* Specific1 Bottom */ +#define GEM_SA1T 0x008C /* Specific1 Top */ +#define GEM_SA2B 0x0090 /* Specific2 Bottom */ +#define GEM_SA2T 0x0094 /* Specific2 Top */ +#define GEM_SA3B 0x0098 /* Specific3 Bottom */ +#define GEM_SA3T 0x009C /* Specific3 Top */ +#define GEM_SA4B 0x00A0 /* Specific4 Bottom */ +#define GEM_SA4T 0x00A4 /* Specific4 Top */ +#define GEM_OTX 0x0100 /* Octets transmitted */ +#define GEM_OCTTXL 0x0100 /* Octets transmitted [31:0] */ +#define GEM_OCTTXH 0x0104 /* Octets transmitted [47:32] */ +#define GEM_TXCNT 0x0108 /* Frames Transmitted counter */ +#define GEM_TXBCCNT 0x010c /* Broadcast Frames counter */ +#define GEM_TXMCCNT 0x0110 /* Multicast Frames counter */ +#define GEM_TXPAUSECNT 0x0114 /* Pause Frames Transmitted Counter */ +#define GEM_TX64CNT 0x0118 /* 64 byte Frames TX counter */ +#define GEM_TX65CNT 0x011c /* 65-127 byte Frames TX counter */ +#define GEM_TX128CNT 0x0120 /* 128-255 byte Frames TX counter */ +#define GEM_TX256CNT 0x0124 /* 256-511 byte Frames TX counter */ +#define GEM_TX512CNT 0x0128 /* 512-1023 byte Frames TX counter */ +#define GEM_TX1024CNT 0x012c /* 1024-1518 byte Frames TX counter */ +#define GEM_TX1519CNT 0x0130 /* 1519+ byte Frames TX counter */ +#define GEM_TXURUNCNT 0x0134 /* TX under run error counter */ +#define GEM_SNGLCOLLCNT 0x0138 /* Single Collision Frame Counter */ +#define GEM_MULTICOLLCNT 0x013c /* Multiple Collision Frame Counter */ +#define GEM_EXCESSCOLLCNT 0x0140 /* Excessive Collision Frame Counter */ +#define GEM_LATECOLLCNT 0x0144 /* Late Collision Frame Counter */ +#define GEM_TXDEFERCNT 0x0148 /* Deferred Transmission Frame Counter */ +#define GEM_TXCSENSECNT 0x014c /* Carrier Sense Error Counter */ +#define GEM_ORX 0x0150 /* Octets received */ +#define GEM_OCTRXL 0x0150 /* Octets received [31:0] */ +#define GEM_OCTRXH 0x0154 /* Octets received [47:32] */ +#define GEM_RXCNT 0x0158 /* Frames Received Counter */ +#define GEM_RXBROADCNT 0x015c /* Broadcast Frames Received Counter */ +#define GEM_RXMULTICNT 0x0160 /* Multicast Frames Received Counter */ +#define GEM_RXPAUSECNT 0x0164 /* Pause Frames Received Counter */ +#define GEM_RX64CNT 0x0168 /* 64 byte Frames RX Counter */ +#define GEM_RX65CNT 0x016c /* 65-127 byte Frames RX Counter */ +#define GEM_RX128CNT 0x0170 /* 128-255 byte Frames RX Counter */ +#define GEM_RX256CNT 0x0174 /* 256-511 byte Frames RX Counter */ +#define GEM_RX512CNT 0x0178 /* 512-1023 byte Frames RX Counter */ +#define GEM_RX1024CNT 0x017c /* 1024-1518 byte Frames RX Counter */ +#define GEM_RX1519CNT 0x0180 /* 1519+ byte Frames RX Counter */ +#define GEM_RXUNDRCNT 0x0184 /* Undersize Frames Received Counter */ +#define GEM_RXOVRCNT 0x0188 /* Oversize Frames Received Counter */ +#define GEM_RXJABCNT 0x018c /* Jabbers Received Counter */ +#define GEM_RXFCSCNT 0x0190 /* Frame Check Sequence Error Counter */ +#define GEM_RXLENGTHCNT 0x0194 /* Length Field Error Counter */ +#define GEM_RXSYMBCNT 0x0198 /* Symbol Error Counter */ +#define GEM_RXALIGNCNT 0x019c /* Alignment Error Counter */ +#define GEM_RXRESERRCNT 0x01a0 /* Receive Resource Error Counter */ +#define GEM_RXORCNT 0x01a4 /* Receive Overrun Counter */ +#define GEM_RXIPCCNT 0x01a8 /* IP header Checksum Error Counter */ +#define GEM_RXTCPCCNT 0x01ac /* TCP Checksum Error Counter */ +#define GEM_RXUDPCCNT 0x01b0 /* UDP Checksum Error Counter */ +#define GEM_DCFG1 0x0280 /* Design Config 1 */ +#define GEM_DCFG2 0x0284 /* Design Config 2 */ +#define GEM_DCFG3 0x0288 /* Design Config 3 */ +#define GEM_DCFG4 0x028c /* Design Config 4 */ +#define GEM_DCFG5 0x0290 /* Design Config 5 */ +#define GEM_DCFG6 0x0294 /* Design Config 6 */ +#define GEM_DCFG7 0x0298 /* Design Config 7 */ -#define GEM_ISR(hw_q) (0x0400 + ((hw_q) << 2)) -#define GEM_TBQP(hw_q) (0x0440 + ((hw_q) << 2)) -#define GEM_RBQP(hw_q) (0x0480 + ((hw_q) << 2)) -#define GEM_IER(hw_q) (0x0600 + ((hw_q) << 2)) -#define GEM_IDR(hw_q) (0x0620 + ((hw_q) << 2)) -#define GEM_IMR(hw_q) (0x0640 + ((hw_q) << 2)) +#define GEM_ISR(hw_q) (0x0400 + ((hw_q) << 2)) +#define GEM_TBQP(hw_q) (0x0440 + ((hw_q) << 2)) +#define GEM_RBQP(hw_q) (0x0480 + ((hw_q) << 2)) +#define GEM_IER(hw_q) (0x0600 + ((hw_q) << 2)) +#define GEM_IDR(hw_q) (0x0620 + ((hw_q) << 2)) +#define GEM_IMR(hw_q) (0x0640 + ((hw_q) << 2)) /* Bitfields in NCR */ -#define MACB_LB_OFFSET 0 -#define MACB_LB_SIZE 1 -#define MACB_LLB_OFFSET 1 -#define MACB_LLB_SIZE 1 -#define MACB_RE_OFFSET 2 -#define MACB_RE_SIZE 1 -#define MACB_TE_OFFSET 3 -#define MACB_TE_SIZE 1 -#define MACB_MPE_OFFSET 4 -#define MACB_MPE_SIZE 1 -#define MACB_CLRSTAT_OFFSET 5 -#define MACB_CLRSTAT_SIZE 1 -#define MACB_INCSTAT_OFFSET 6 -#define MACB_INCSTAT_SIZE 1 -#define MACB_WESTAT_OFFSET 7 -#define MACB_WESTAT_SIZE 1 -#define MACB_BP_OFFSET 8 -#define MACB_BP_SIZE 1 -#define MACB_TSTART_OFFSET 9 -#define MACB_TSTART_SIZE 1 -#define MACB_THALT_OFFSET 10 -#define MACB_THALT_SIZE 1 -#define MACB_NCR_TPF_OFFSET 11 -#define MACB_NCR_TPF_SIZE 1 -#define MACB_TZQ_OFFSET 12 -#define MACB_TZQ_SIZE 1 +#define MACB_LB_OFFSET 0 /* reserved */ +#define MACB_LB_SIZE 1 +#define MACB_LLB_OFFSET 1 /* Loop back local */ +#define MACB_LLB_SIZE 1 +#define MACB_RE_OFFSET 2 /* Receive enable */ +#define MACB_RE_SIZE 1 +#define MACB_TE_OFFSET 3 /* Transmit enable */ +#define MACB_TE_SIZE 1 +#define MACB_MPE_OFFSET 4 /* Management port enable */ +#define MACB_MPE_SIZE 1 +#define MACB_CLRSTAT_OFFSET 5 /* Clear stats regs */ +#define MACB_CLRSTAT_SIZE 1 +#define MACB_INCSTAT_OFFSET 6 /* Incremental stats regs */ +#define MACB_INCSTAT_SIZE 1 +#define MACB_WESTAT_OFFSET 7 /* Write enable stats regs */ +#define MACB_WESTAT_SIZE 1 +#define MACB_BP_OFFSET 8 /* Back pressure */ +#define MACB_BP_SIZE 1 +#define MACB_TSTART_OFFSET 9 /* Start transmission */ +#define MACB_TSTART_SIZE 1 +#define MACB_THALT_OFFSET 10 /* Transmit halt */ +#define MACB_THALT_SIZE 1 +#define MACB_NCR_TPF_OFFSET 11 /* Transmit pause frame */ +#define MACB_NCR_TPF_SIZE 1 +#define MACB_TZQ_OFFSET 12 /* Transmit zero quantum pause frame */ +#define MACB_TZQ_SIZE 1 /* Bitfields in NCFGR */ -#define MACB_SPD_OFFSET 0 -#define MACB_SPD_SIZE 1 -#define MACB_FD_OFFSET 1 -#define MACB_FD_SIZE 1 -#define MACB_BIT_RATE_OFFSET 2 -#define MACB_BIT_RATE_SIZE 1 -#define MACB_JFRAME_OFFSET 3 -#define MACB_JFRAME_SIZE 1 -#define MACB_CAF_OFFSET 4 -#define MACB_CAF_SIZE 1 -#define MACB_NBC_OFFSET 5 -#define MACB_NBC_SIZE 1 -#define MACB_NCFGR_MTI_OFFSET 6 -#define MACB_NCFGR_MTI_SIZE 1 -#define MACB_UNI_OFFSET 7 -#define MACB_UNI_SIZE 1 -#define MACB_BIG_OFFSET 8 -#define MACB_BIG_SIZE 1 -#define MACB_EAE_OFFSET 9 -#define MACB_EAE_SIZE 1 -#define MACB_CLK_OFFSET 10 -#define MACB_CLK_SIZE 2 -#define MACB_RTY_OFFSET 12 -#define MACB_RTY_SIZE 1 -#define MACB_PAE_OFFSET 13 -#define MACB_PAE_SIZE 1 -#define MACB_RM9200_RMII_OFFSET 13 /* AT91RM9200 only */ -#define MACB_RM9200_RMII_SIZE 1 /* AT91RM9200 only */ -#define MACB_RBOF_OFFSET 14 -#define MACB_RBOF_SIZE 2 -#define MACB_RLCE_OFFSET 16 -#define MACB_RLCE_SIZE 1 -#define MACB_DRFCS_OFFSET 17 -#define MACB_DRFCS_SIZE 1 -#define MACB_EFRHD_OFFSET 18 -#define MACB_EFRHD_SIZE 1 -#define MACB_IRXFCS_OFFSET 19 -#define MACB_IRXFCS_SIZE 1 +#define MACB_SPD_OFFSET 0 /* Speed */ +#define MACB_SPD_SIZE 1 +#define MACB_FD_OFFSET 1 /* Full duplex */ +#define MACB_FD_SIZE 1 +#define MACB_BIT_RATE_OFFSET 2 /* Discard non-VLAN frames */ +#define MACB_BIT_RATE_SIZE 1 +#define MACB_JFRAME_OFFSET 3 /* reserved */ +#define MACB_JFRAME_SIZE 1 +#define MACB_CAF_OFFSET 4 /* Copy all frames */ +#define MACB_CAF_SIZE 1 +#define MACB_NBC_OFFSET 5 /* No broadcast */ +#define MACB_NBC_SIZE 1 +#define MACB_NCFGR_MTI_OFFSET 6 /* Multicast hash enable */ +#define MACB_NCFGR_MTI_SIZE 1 +#define MACB_UNI_OFFSET 7 /* Unicast hash enable */ +#define MACB_UNI_SIZE 1 +#define MACB_BIG_OFFSET 8 /* Receive 1536 byte frames */ +#define MACB_BIG_SIZE 1 +#define MACB_EAE_OFFSET 9 /* External address match enable */ +#define MACB_EAE_SIZE 1 +#define MACB_CLK_OFFSET 10 +#define MACB_CLK_SIZE 2 +#define MACB_RTY_OFFSET 12 /* Retry test */ +#define MACB_RTY_SIZE 1 +#define MACB_PAE_OFFSET 13 /* Pause enable */ +#define MACB_PAE_SIZE 1 +#define MACB_RM9200_RMII_OFFSET 13 /* AT91RM9200 only */ +#define MACB_RM9200_RMII_SIZE 1 /* AT91RM9200 only */ +#define MACB_RBOF_OFFSET 14 /* Receive buffer offset */ +#define MACB_RBOF_SIZE 2 +#define MACB_RLCE_OFFSET 16 /* Length field error frame discard */ +#define MACB_RLCE_SIZE 1 +#define MACB_DRFCS_OFFSET 17 /* FCS remove */ +#define MACB_DRFCS_SIZE 1 +#define MACB_EFRHD_OFFSET 18 +#define MACB_EFRHD_SIZE 1 +#define MACB_IRXFCS_OFFSET 19 +#define MACB_IRXFCS_SIZE 1 /* GEM specific NCFGR bitfields. */ -#define GEM_GBE_OFFSET 10 -#define GEM_GBE_SIZE 1 -#define GEM_CLK_OFFSET 18 -#define GEM_CLK_SIZE 3 -#define GEM_DBW_OFFSET 21 -#define GEM_DBW_SIZE 2 -#define GEM_RXCOEN_OFFSET 24 -#define GEM_RXCOEN_SIZE 1 +#define GEM_GBE_OFFSET 10 /* Gigabit mode enable */ +#define GEM_GBE_SIZE 1 +#define GEM_CLK_OFFSET 18 /* MDC clock division */ +#define GEM_CLK_SIZE 3 +#define GEM_DBW_OFFSET 21 /* Data bus width */ +#define GEM_DBW_SIZE 2 +#define GEM_RXCOEN_OFFSET 24 +#define GEM_RXCOEN_SIZE 1 /* Constants for data bus width. */ -#define GEM_DBW32 0 -#define GEM_DBW64 1 -#define GEM_DBW128 2 +#define GEM_DBW32 0 /* 32 bit AMBA AHB data bus width */ +#define GEM_DBW64 1 /* 64 bit AMBA AHB data bus width */ +#define GEM_DBW128 2 /* 128 bit AMBA AHB data bus width */ /* Bitfields in DMACFG. */ -#define GEM_FBLDO_OFFSET 0 -#define GEM_FBLDO_SIZE 5 -#define GEM_ENDIA_OFFSET 7 -#define GEM_ENDIA_SIZE 1 -#define GEM_RXBMS_OFFSET 8 -#define GEM_RXBMS_SIZE 2 -#define GEM_TXPBMS_OFFSET 10 -#define GEM_TXPBMS_SIZE 1 -#define GEM_TXCOEN_OFFSET 11 -#define GEM_TXCOEN_SIZE 1 -#define GEM_RXBS_OFFSET 16 -#define GEM_RXBS_SIZE 8 -#define GEM_DDRP_OFFSET 24 -#define GEM_DDRP_SIZE 1 +#define GEM_FBLDO_OFFSET 0 /* fixed burst length for DMA */ +#define GEM_FBLDO_SIZE 5 +#define GEM_ENDIA_OFFSET 7 /* endian swap mode for packet data access */ +#define GEM_ENDIA_SIZE 1 +#define GEM_RXBMS_OFFSET 8 /* RX packet buffer memory size select */ +#define GEM_RXBMS_SIZE 2 +#define GEM_TXPBMS_OFFSET 10 /* TX packet buffer memory size select */ +#define GEM_TXPBMS_SIZE 1 +#define GEM_TXCOEN_OFFSET 11 /* TX IP/TCP/UDP checksum gen offload */ +#define GEM_TXCOEN_SIZE 1 +#define GEM_RXBS_OFFSET 16 /* DMA receive buffer size */ +#define GEM_RXBS_SIZE 8 +#define GEM_DDRP_OFFSET 24 /* disc_when_no_ahb */ +#define GEM_DDRP_SIZE 1 /* Bitfields in NSR */ -#define MACB_NSR_LINK_OFFSET 0 -#define MACB_NSR_LINK_SIZE 1 -#define MACB_MDIO_OFFSET 1 -#define MACB_MDIO_SIZE 1 -#define MACB_IDLE_OFFSET 2 -#define MACB_IDLE_SIZE 1 +#define MACB_NSR_LINK_OFFSET 0 /* pcs_link_state */ +#define MACB_NSR_LINK_SIZE 1 +#define MACB_MDIO_OFFSET 1 /* status of the mdio_in pin */ +#define MACB_MDIO_SIZE 1 +#define MACB_IDLE_OFFSET 2 /* The PHY management logic is idle */ +#define MACB_IDLE_SIZE 1 /* Bitfields in TSR */ -#define MACB_UBR_OFFSET 0 -#define MACB_UBR_SIZE 1 -#define MACB_COL_OFFSET 1 -#define MACB_COL_SIZE 1 -#define MACB_TSR_RLE_OFFSET 2 -#define MACB_TSR_RLE_SIZE 1 -#define MACB_TGO_OFFSET 3 -#define MACB_TGO_SIZE 1 -#define MACB_BEX_OFFSET 4 -#define MACB_BEX_SIZE 1 -#define MACB_RM9200_BNQ_OFFSET 4 /* AT91RM9200 only */ -#define MACB_RM9200_BNQ_SIZE 1 /* AT91RM9200 only */ -#define MACB_COMP_OFFSET 5 -#define MACB_COMP_SIZE 1 -#define MACB_UND_OFFSET 6 -#define MACB_UND_SIZE 1 +#define MACB_UBR_OFFSET 0 /* Used bit read */ +#define MACB_UBR_SIZE 1 +#define MACB_COL_OFFSET 1 /* Collision occurred */ +#define MACB_COL_SIZE 1 +#define MACB_TSR_RLE_OFFSET 2 /* Retry limit exceeded */ +#define MACB_TSR_RLE_SIZE 1 +#define MACB_TGO_OFFSET 3 /* Transmit go */ +#define MACB_TGO_SIZE 1 +#define MACB_BEX_OFFSET 4 /* TX frame corruption due to AHB error */ +#define MACB_BEX_SIZE 1 +#define MACB_RM9200_BNQ_OFFSET 4 /* AT91RM9200 only */ +#define MACB_RM9200_BNQ_SIZE 1 /* AT91RM9200 only */ +#define MACB_COMP_OFFSET 5 /* Trnasmit complete */ +#define MACB_COMP_SIZE 1 +#define MACB_UND_OFFSET 6 /* Trnasmit under run */ +#define MACB_UND_SIZE 1 /* Bitfields in RSR */ -#define MACB_BNA_OFFSET 0 -#define MACB_BNA_SIZE 1 -#define MACB_REC_OFFSET 1 -#define MACB_REC_SIZE 1 -#define MACB_OVR_OFFSET 2 -#define MACB_OVR_SIZE 1 +#define MACB_BNA_OFFSET 0 /* Buffer not available */ +#define MACB_BNA_SIZE 1 +#define MACB_REC_OFFSET 1 /* Frame received */ +#define MACB_REC_SIZE 1 +#define MACB_OVR_OFFSET 2 /* Receive overrun */ +#define MACB_OVR_SIZE 1 /* Bitfields in ISR/IER/IDR/IMR */ -#define MACB_MFD_OFFSET 0 -#define MACB_MFD_SIZE 1 -#define MACB_RCOMP_OFFSET 1 -#define MACB_RCOMP_SIZE 1 -#define MACB_RXUBR_OFFSET 2 -#define MACB_RXUBR_SIZE 1 -#define MACB_TXUBR_OFFSET 3 -#define MACB_TXUBR_SIZE 1 -#define MACB_ISR_TUND_OFFSET 4 -#define MACB_ISR_TUND_SIZE 1 -#define MACB_ISR_RLE_OFFSET 5 -#define MACB_ISR_RLE_SIZE 1 -#define MACB_TXERR_OFFSET 6 -#define MACB_TXERR_SIZE 1 -#define MACB_TCOMP_OFFSET 7 -#define MACB_TCOMP_SIZE 1 -#define MACB_ISR_LINK_OFFSET 9 -#define MACB_ISR_LINK_SIZE 1 -#define MACB_ISR_ROVR_OFFSET 10 -#define MACB_ISR_ROVR_SIZE 1 -#define MACB_HRESP_OFFSET 11 -#define MACB_HRESP_SIZE 1 -#define MACB_PFR_OFFSET 12 -#define MACB_PFR_SIZE 1 -#define MACB_PTZ_OFFSET 13 -#define MACB_PTZ_SIZE 1 +#define MACB_MFD_OFFSET 0 /* Management frame sent */ +#define MACB_MFD_SIZE 1 +#define MACB_RCOMP_OFFSET 1 /* Receive complete */ +#define MACB_RCOMP_SIZE 1 +#define MACB_RXUBR_OFFSET 2 /* RX used bit read */ +#define MACB_RXUBR_SIZE 1 +#define MACB_TXUBR_OFFSET 3 /* TX used bit read */ +#define MACB_TXUBR_SIZE 1 +#define MACB_ISR_TUND_OFFSET 4 /* Enable TX buffer under run interrupt */ +#define MACB_ISR_TUND_SIZE 1 +#define MACB_ISR_RLE_OFFSET 5 /* EN retry exceeded/late coll interrupt */ +#define MACB_ISR_RLE_SIZE 1 +#define MACB_TXERR_OFFSET 6 /* EN TX frame corrupt from error interrupt */ +#define MACB_TXERR_SIZE 1 +#define MACB_TCOMP_OFFSET 7 /* Enable transmit complete interrupt */ +#define MACB_TCOMP_SIZE 1 +#define MACB_ISR_LINK_OFFSET 9 /* Enable link change interrupt */ +#define MACB_ISR_LINK_SIZE 1 +#define MACB_ISR_ROVR_OFFSET 10 /* Enable receive overrun interrupt */ +#define MACB_ISR_ROVR_SIZE 1 +#define MACB_HRESP_OFFSET 11 /* Enable hrsep not OK interrupt */ +#define MACB_HRESP_SIZE 1 +#define MACB_PFR_OFFSET 12 /* Enable pause frame w/ quantum interrupt */ +#define MACB_PFR_SIZE 1 +#define MACB_PTZ_OFFSET 13 /* Enable pause time zero interrupt */ +#define MACB_PTZ_SIZE 1 /* Bitfields in MAN */ -#define MACB_DATA_OFFSET 0 -#define MACB_DATA_SIZE 16 -#define MACB_CODE_OFFSET 16 -#define MACB_CODE_SIZE 2 -#define MACB_REGA_OFFSET 18 -#define MACB_REGA_SIZE 5 -#define MACB_PHYA_OFFSET 23 -#define MACB_PHYA_SIZE 5 -#define MACB_RW_OFFSET 28 -#define MACB_RW_SIZE 2 -#define MACB_SOF_OFFSET 30 -#define MACB_SOF_SIZE 2 +#define MACB_DATA_OFFSET 0 /* data */ +#define MACB_DATA_SIZE 16 +#define MACB_CODE_OFFSET 16 /* Must be written to 10 */ +#define MACB_CODE_SIZE 2 +#define MACB_REGA_OFFSET 18 /* Register address */ +#define MACB_REGA_SIZE 5 +#define MACB_PHYA_OFFSET 23 /* PHY address */ +#define MACB_PHYA_SIZE 5 +#define MACB_RW_OFFSET 28 /* Operation. 10 is read. 01 is write. */ +#define MACB_RW_SIZE 2 +#define MACB_SOF_OFFSET 30 /* Must be written to 1 for Clause 22 */ +#define MACB_SOF_SIZE 2 /* Bitfields in USRIO (AVR32) */ #define MACB_MII_OFFSET 0 @@ -286,7 +332,7 @@ /* Bitfields in USRIO (AT91) */ #define MACB_RMII_OFFSET 0 #define MACB_RMII_SIZE 1 -#define GEM_RGMII_OFFSET 0 /* GEM gigabit mode */ +#define GEM_RGMII_OFFSET 0 /* GEM gigabit mode */ #define GEM_RGMII_SIZE 1 #define MACB_CLKEN_OFFSET 1 #define MACB_CLKEN_SIZE 1 @@ -389,8 +435,7 @@ #define queue_writel(queue, reg, value) \ __raw_writel((value), (queue)->bp->regs + (queue)->reg) -/* - * Conditional GEM/MACB macros. These perform the operation to the correct +/* Conditional GEM/MACB macros. These perform the operation to the correct * register dependent on whether the device is a GEM or a MACB. For registers * and bitfields that are common across both devices, use macb_{read,write}l * to avoid the cost of the conditional. @@ -413,8 +458,7 @@ __v; \ }) -/** - * struct macb_dma_desc - Hardware DMA descriptor +/* struct macb_dma_desc - Hardware DMA descriptor * @addr: DMA address of data buffer * @ctrl: Control and status bits */ @@ -503,8 +547,7 @@ struct macb_dma_desc { /* limit RX checksum offload to TCP and UDP packets */ #define GEM_RX_CSUM_CHECKED_MASK 2 -/** - * struct macb_tx_skb - data about an skb which is being transmitted +/* struct macb_tx_skb - data about an skb which is being transmitted * @skb: skb currently being transmitted, only set for the last buffer * of the frame * @mapping: DMA address of the skb's fragment buffer @@ -519,8 +562,7 @@ struct macb_tx_skb { bool mapped_as_page; }; -/* - * Hardware-collected statistics. Used when updating the network +/* Hardware-collected statistics. Used when updating the network * device stats by a periodic timer. */ struct macb_stats { @@ -595,6 +637,107 @@ struct gem_stats { u32 rx_udp_checksum_errors; }; +/* Describes the name and offset of an individual statistic register, as + * returned by `ethtool -S`. Also describes which net_device_stats statistics + * this register should contribute to. + */ +struct gem_statistic { + char stat_string[ETH_GSTRING_LEN]; + int offset; + u32 stat_bits; +}; + +/* Bitfield defs for net_device_stat statistics */ +#define GEM_NDS_RXERR_OFFSET 0 +#define GEM_NDS_RXLENERR_OFFSET 1 +#define GEM_NDS_RXOVERERR_OFFSET 2 +#define GEM_NDS_RXCRCERR_OFFSET 3 +#define GEM_NDS_RXFRAMEERR_OFFSET 4 +#define GEM_NDS_RXFIFOERR_OFFSET 5 +#define GEM_NDS_TXERR_OFFSET 6 +#define GEM_NDS_TXABORTEDERR_OFFSET 7 +#define GEM_NDS_TXCARRIERERR_OFFSET 8 +#define GEM_NDS_TXFIFOERR_OFFSET 9 +#define GEM_NDS_COLLISIONS_OFFSET 10 + +#define GEM_STAT_TITLE(name, title) GEM_STAT_TITLE_BITS(name, title, 0) +#define GEM_STAT_TITLE_BITS(name, title, bits) { \ + .stat_string = title, \ + .offset = GEM_##name, \ + .stat_bits = bits \ +} + +/* list of gem statistic registers. The names MUST match the + * corresponding GEM_* definitions. + */ +static const struct gem_statistic gem_statistics[] = { + GEM_STAT_TITLE(OCTTXL, "tx_octets"), /* OCTTXH combined with OCTTXL */ + GEM_STAT_TITLE(TXCNT, "tx_frames"), + GEM_STAT_TITLE(TXBCCNT, "tx_broadcast_frames"), + GEM_STAT_TITLE(TXMCCNT, "tx_multicast_frames"), + GEM_STAT_TITLE(TXPAUSECNT, "tx_pause_frames"), + GEM_STAT_TITLE(TX64CNT, "tx_64_byte_frames"), + GEM_STAT_TITLE(TX65CNT, "tx_65_127_byte_frames"), + GEM_STAT_TITLE(TX128CNT, "tx_128_255_byte_frames"), + GEM_STAT_TITLE(TX256CNT, "tx_256_511_byte_frames"), + GEM_STAT_TITLE(TX512CNT, "tx_512_1023_byte_frames"), + GEM_STAT_TITLE(TX1024CNT, "tx_1024_1518_byte_frames"), + GEM_STAT_TITLE(TX1519CNT, "tx_greater_than_1518_byte_frames"), + GEM_STAT_TITLE_BITS(TXURUNCNT, "tx_underrun", + GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_TXFIFOERR)), + GEM_STAT_TITLE_BITS(SNGLCOLLCNT, "tx_single_collision_frames", + GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_COLLISIONS)), + GEM_STAT_TITLE_BITS(MULTICOLLCNT, "tx_multiple_collision_frames", + GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_COLLISIONS)), + GEM_STAT_TITLE_BITS(EXCESSCOLLCNT, "tx_excessive_collisions", + GEM_BIT(NDS_TXERR)| + GEM_BIT(NDS_TXABORTEDERR)| + GEM_BIT(NDS_COLLISIONS)), + GEM_STAT_TITLE_BITS(LATECOLLCNT, "tx_late_collisions", + GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_COLLISIONS)), + GEM_STAT_TITLE(TXDEFERCNT, "tx_deferred_frames"), + GEM_STAT_TITLE_BITS(TXCSENSECNT, "tx_carrier_sense_errors", + GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_COLLISIONS)), + GEM_STAT_TITLE(OCTRXL, "rx_octets"), /* OCTRXH combined with OCTRXL */ + GEM_STAT_TITLE(RXCNT, "rx_frames"), + GEM_STAT_TITLE(RXBROADCNT, "rx_broadcast_frames"), + GEM_STAT_TITLE(RXMULTICNT, "rx_multicast_frames"), + GEM_STAT_TITLE(RXPAUSECNT, "rx_pause_frames"), + GEM_STAT_TITLE(RX64CNT, "rx_64_byte_frames"), + GEM_STAT_TITLE(RX65CNT, "rx_65_127_byte_frames"), + GEM_STAT_TITLE(RX128CNT, "rx_128_255_byte_frames"), + GEM_STAT_TITLE(RX256CNT, "rx_256_511_byte_frames"), + GEM_STAT_TITLE(RX512CNT, "rx_512_1023_byte_frames"), + GEM_STAT_TITLE(RX1024CNT, "rx_1024_1518_byte_frames"), + GEM_STAT_TITLE(RX1519CNT, "rx_greater_than_1518_byte_frames"), + GEM_STAT_TITLE_BITS(RXUNDRCNT, "rx_undersized_frames", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXLENERR)), + GEM_STAT_TITLE_BITS(RXOVRCNT, "rx_oversize_frames", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXLENERR)), + GEM_STAT_TITLE_BITS(RXJABCNT, "rx_jabbers", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXLENERR)), + GEM_STAT_TITLE_BITS(RXFCSCNT, "rx_frame_check_sequence_errors", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXCRCERR)), + GEM_STAT_TITLE_BITS(RXLENGTHCNT, "rx_length_field_frame_errors", + GEM_BIT(NDS_RXERR)), + GEM_STAT_TITLE_BITS(RXSYMBCNT, "rx_symbol_errors", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXFRAMEERR)), + GEM_STAT_TITLE_BITS(RXALIGNCNT, "rx_alignment_errors", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXOVERERR)), + GEM_STAT_TITLE_BITS(RXRESERRCNT, "rx_resource_errors", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXOVERERR)), + GEM_STAT_TITLE_BITS(RXORCNT, "rx_overruns", + GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXFIFOERR)), + GEM_STAT_TITLE_BITS(RXIPCCNT, "rx_ip_header_checksum_errors", + GEM_BIT(NDS_RXERR)), + GEM_STAT_TITLE_BITS(RXTCPCCNT, "rx_tcp_checksum_errors", + GEM_BIT(NDS_RXERR)), + GEM_STAT_TITLE_BITS(RXUDPCCNT, "rx_udp_checksum_errors", + GEM_BIT(NDS_RXERR)), +}; + +#define GEM_STATS_LEN ARRAY_SIZE(gem_statistics) + struct macb; struct macb_or_gem_ops { @@ -673,6 +816,8 @@ struct macb { dma_addr_t skb_physaddr; /* phys addr from pci_map_single */ int skb_length; /* saved skb length for pci_unmap_single */ unsigned int max_tx_length; + + u64 ethtool_stats[GEM_STATS_LEN]; }; extern const struct ethtool_ops macb_ethtool_ops; diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c index babe2a915b00..526ea74e82d9 100644 --- a/drivers/net/ethernet/chelsio/cxgb/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb/sge.c @@ -1860,9 +1860,9 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev) } cpl->iff = dev->if_port; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { cpl->vlan_valid = 1; - cpl->vlan = htons(vlan_tx_tag_get(skb)); + cpl->vlan = htons(skb_vlan_tag_get(skb)); st->vlan_insert++; } else cpl->vlan_valid = 0; diff --git a/drivers/net/ethernet/chelsio/cxgb3/mc5.c b/drivers/net/ethernet/chelsio/cxgb3/mc5.c index e13b7fe9d082..338301b11518 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/mc5.c +++ b/drivers/net/ethernet/chelsio/cxgb3/mc5.c @@ -97,14 +97,6 @@ static int mc5_cmd_write(struct adapter *adapter, u32 cmd) F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1); } -static inline void dbgi_wr_addr3(struct adapter *adapter, u32 v1, u32 v2, - u32 v3) -{ - t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, v1); - t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR1, v2); - t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR2, v3); -} - static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2, u32 v3) { @@ -113,14 +105,6 @@ static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2, t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3); } -static inline void dbgi_rd_rsp3(struct adapter *adapter, u32 *v1, u32 *v2, - u32 *v3) -{ - *v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0); - *v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1); - *v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2); -} - /* * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM * command cmd. The data to be written must have been set up by the caller. diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c index 3dfcf600fcc6..d6aa602f168d 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c @@ -1148,8 +1148,8 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, cpl->len = htonl(skb->len); cntrl = V_TXPKT_INTF(pi->port_id); - if (vlan_tx_tag_present(skb)) - cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(vlan_tx_tag_get(skb)); + if (skb_vlan_tag_present(skb)) + cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(skb_vlan_tag_get(skb)); tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size); if (tso_info) { @@ -1282,7 +1282,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) qs->port_stats[SGE_PSTAT_TX_CSUM]++; if (skb_shinfo(skb)->gso_size) qs->port_stats[SGE_PSTAT_TSO]++; - if (vlan_tx_tag_present(skb)) + if (skb_vlan_tag_present(skb)) qs->port_stats[SGE_PSTAT_VLANINS]++; /* diff --git a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c index c74a898fcd4f..184a8d545ac4 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c @@ -727,9 +727,9 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16); } - for (i = 0; i < 6; i++) - p->eth_base[i] = hex_to_bin(vpd.na_data[2 * i]) * 16 + - hex_to_bin(vpd.na_data[2 * i + 1]); + ret = hex2bin(p->eth_base, vpd.na_data, 6); + if (ret < 0) + return -EINVAL; return 0; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile index b85280775997..ae50cd72358c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/Makefile +++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile @@ -4,6 +4,6 @@ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o -cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o +cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c new file mode 100644 index 000000000000..9062a8434246 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c @@ -0,0 +1,317 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * Copyright (C) 2003-2014 Chelsio Communications. All rights reserved. + * + * Written by Deepak (deepak.s@chelsio.com) + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this + * release for licensing terms and conditions. + */ + +#include +#include +#include +#include +#include +#include "cxgb4.h" +#include "clip_tbl.h" + +static inline unsigned int ipv4_clip_hash(struct clip_tbl *c, const u32 *key) +{ + unsigned int clipt_size_half = c->clipt_size / 2; + + return jhash_1word(*key, 0) % clipt_size_half; +} + +static inline unsigned int ipv6_clip_hash(struct clip_tbl *d, const u32 *key) +{ + unsigned int clipt_size_half = d->clipt_size / 2; + u32 xor = key[0] ^ key[1] ^ key[2] ^ key[3]; + + return clipt_size_half + + (jhash_1word(xor, 0) % clipt_size_half); +} + +static unsigned int clip_addr_hash(struct clip_tbl *ctbl, const u32 *addr, + int addr_len) +{ + return addr_len == 4 ? ipv4_clip_hash(ctbl, addr) : + ipv6_clip_hash(ctbl, addr); +} + +static int clip6_get_mbox(const struct net_device *dev, + const struct in6_addr *lip) +{ + struct adapter *adap = netdev2adap(dev); + struct fw_clip_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) | + FW_CMD_REQUEST_F | FW_CMD_WRITE_F); + c.alloc_to_len16 = htonl(FW_CLIP_CMD_ALLOC_F | FW_LEN16(c)); + *(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr); + *(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8); + return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false); +} + +static int clip6_release_mbox(const struct net_device *dev, + const struct in6_addr *lip) +{ + struct adapter *adap = netdev2adap(dev); + struct fw_clip_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) | + FW_CMD_REQUEST_F | FW_CMD_READ_F); + c.alloc_to_len16 = htonl(FW_CLIP_CMD_FREE_F | FW_LEN16(c)); + *(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr); + *(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8); + return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false); +} + +int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6) +{ + struct adapter *adap = netdev2adap(dev); + struct clip_tbl *ctbl = adap->clipt; + struct clip_entry *ce, *cte; + u32 *addr = (u32 *)lip; + int hash; + int addr_len; + int ret = 0; + + if (!ctbl) + return 0; + + if (v6) + addr_len = 16; + else + addr_len = 4; + + hash = clip_addr_hash(ctbl, addr, addr_len); + + read_lock_bh(&ctbl->lock); + list_for_each_entry(cte, &ctbl->hash_list[hash], list) { + if (addr_len == cte->addr_len && + memcmp(lip, cte->addr, cte->addr_len) == 0) { + ce = cte; + read_unlock_bh(&ctbl->lock); + goto found; + } + } + read_unlock_bh(&ctbl->lock); + + write_lock_bh(&ctbl->lock); + if (!list_empty(&ctbl->ce_free_head)) { + ce = list_first_entry(&ctbl->ce_free_head, + struct clip_entry, list); + list_del(&ce->list); + INIT_LIST_HEAD(&ce->list); + spin_lock_init(&ce->lock); + atomic_set(&ce->refcnt, 0); + atomic_dec(&ctbl->nfree); + ce->addr_len = addr_len; + memcpy(ce->addr, lip, addr_len); + list_add_tail(&ce->list, &ctbl->hash_list[hash]); + if (v6) { + ret = clip6_get_mbox(dev, (const struct in6_addr *)lip); + if (ret) { + write_unlock_bh(&ctbl->lock); + return ret; + } + } + } else { + write_unlock_bh(&ctbl->lock); + return -ENOMEM; + } + write_unlock_bh(&ctbl->lock); +found: + atomic_inc(&ce->refcnt); + + return 0; +} +EXPORT_SYMBOL(cxgb4_clip_get); + +void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6) +{ + struct adapter *adap = netdev2adap(dev); + struct clip_tbl *ctbl = adap->clipt; + struct clip_entry *ce, *cte; + u32 *addr = (u32 *)lip; + int hash; + int addr_len; + + if (v6) + addr_len = 16; + else + addr_len = 4; + + hash = clip_addr_hash(ctbl, addr, addr_len); + + read_lock_bh(&ctbl->lock); + list_for_each_entry(cte, &ctbl->hash_list[hash], list) { + if (addr_len == cte->addr_len && + memcmp(lip, cte->addr, cte->addr_len) == 0) { + ce = cte; + read_unlock_bh(&ctbl->lock); + goto found; + } + } + read_unlock_bh(&ctbl->lock); + + return; +found: + write_lock_bh(&ctbl->lock); + spin_lock_bh(&ce->lock); + if (atomic_dec_and_test(&ce->refcnt)) { + list_del(&ce->list); + INIT_LIST_HEAD(&ce->list); + list_add_tail(&ce->list, &ctbl->ce_free_head); + atomic_inc(&ctbl->nfree); + if (v6) + clip6_release_mbox(dev, (const struct in6_addr *)lip); + } + spin_unlock_bh(&ce->lock); + write_unlock_bh(&ctbl->lock); +} +EXPORT_SYMBOL(cxgb4_clip_release); + +/* Retrieves IPv6 addresses from a root device (bond, vlan) associated with + * a physical device. + * The physical device reference is needed to send the actul CLIP command. + */ +static int cxgb4_update_dev_clip(struct net_device *root_dev, + struct net_device *dev) +{ + struct inet6_dev *idev = NULL; + struct inet6_ifaddr *ifa; + int ret = 0; + + idev = __in6_dev_get(root_dev); + if (!idev) + return ret; + + read_lock_bh(&idev->lock); + list_for_each_entry(ifa, &idev->addr_list, if_list) { + ret = cxgb4_clip_get(dev, (const u32 *)ifa->addr.s6_addr, 1); + if (ret < 0) + break; + } + read_unlock_bh(&idev->lock); + + return ret; +} + +int cxgb4_update_root_dev_clip(struct net_device *dev) +{ + struct net_device *root_dev = NULL; + int i, ret = 0; + + /* First populate the real net device's IPv6 addresses */ + ret = cxgb4_update_dev_clip(dev, dev); + if (ret) + return ret; + + /* Parse all bond and vlan devices layered on top of the physical dev */ + root_dev = netdev_master_upper_dev_get_rcu(dev); + if (root_dev) { + ret = cxgb4_update_dev_clip(root_dev, dev); + if (ret) + return ret; + } + + for (i = 0; i < VLAN_N_VID; i++) { + root_dev = __vlan_find_dev_deep_rcu(dev, htons(ETH_P_8021Q), i); + if (!root_dev) + continue; + + ret = cxgb4_update_dev_clip(root_dev, dev); + if (ret) + break; + } + + return ret; +} +EXPORT_SYMBOL(cxgb4_update_root_dev_clip); + +int clip_tbl_show(struct seq_file *seq, void *v) +{ + struct adapter *adapter = seq->private; + struct clip_tbl *ctbl = adapter->clipt; + struct clip_entry *ce; + char ip[60]; + int i; + + read_lock_bh(&ctbl->lock); + + seq_puts(seq, "IP Address Users\n"); + for (i = 0 ; i < ctbl->clipt_size; ++i) { + list_for_each_entry(ce, &ctbl->hash_list[i], list) { + ip[0] = '\0'; + if (ce->addr_len == 16) + sprintf(ip, "%pI6c", ce->addr); + else + sprintf(ip, "%pI4c", ce->addr); + seq_printf(seq, "%-25s %u\n", ip, + atomic_read(&ce->refcnt)); + } + } + seq_printf(seq, "Free clip entries : %d\n", atomic_read(&ctbl->nfree)); + + read_unlock_bh(&ctbl->lock); + + return 0; +} + +struct clip_tbl *t4_init_clip_tbl(unsigned int clipt_start, + unsigned int clipt_end) +{ + struct clip_entry *cl_list; + struct clip_tbl *ctbl; + unsigned int clipt_size; + int i; + + if (clipt_start >= clipt_end) + return NULL; + clipt_size = clipt_end - clipt_start + 1; + if (clipt_size < CLIPT_MIN_HASH_BUCKETS) + return NULL; + + ctbl = t4_alloc_mem(sizeof(*ctbl) + + clipt_size*sizeof(struct list_head)); + if (!ctbl) + return NULL; + + ctbl->clipt_start = clipt_start; + ctbl->clipt_size = clipt_size; + INIT_LIST_HEAD(&ctbl->ce_free_head); + + atomic_set(&ctbl->nfree, clipt_size); + rwlock_init(&ctbl->lock); + + for (i = 0; i < ctbl->clipt_size; ++i) + INIT_LIST_HEAD(&ctbl->hash_list[i]); + + cl_list = t4_alloc_mem(clipt_size*sizeof(struct clip_entry)); + ctbl->cl_list = (void *)cl_list; + + for (i = 0; i < clipt_size; i++) { + INIT_LIST_HEAD(&cl_list[i].list); + list_add_tail(&cl_list[i].list, &ctbl->ce_free_head); + } + + return ctbl; +} + +void t4_cleanup_clip_tbl(struct adapter *adap) +{ + struct clip_tbl *ctbl = adap->clipt; + + if (ctbl) { + if (ctbl->cl_list) + t4_free_mem(ctbl->cl_list); + t4_free_mem(ctbl); + } +} +EXPORT_SYMBOL(t4_cleanup_clip_tbl); diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h new file mode 100644 index 000000000000..2eaba0161cf8 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h @@ -0,0 +1,41 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * Copyright (C) 2003-2014 Chelsio Communications. All rights reserved. + * + * Written by Deepak (deepak.s@chelsio.com) + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this + * release for licensing terms and conditions. + */ + +struct clip_entry { + spinlock_t lock; /* Hold while modifying clip reference */ + atomic_t refcnt; + struct list_head list; + u32 addr[4]; + int addr_len; +}; + +struct clip_tbl { + unsigned int clipt_start; + unsigned int clipt_size; + rwlock_t lock; + atomic_t nfree; + struct list_head ce_free_head; + void *cl_list; + struct list_head hash_list[0]; +}; + +enum { + CLIPT_MIN_HASH_BUCKETS = 2, +}; + +struct clip_tbl *t4_init_clip_tbl(unsigned int clipt_start, + unsigned int clipt_end); +int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6); +void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6); +int clip_tbl_show(struct seq_file *seq, void *v); +int cxgb4_update_root_dev_clip(struct net_device *dev); +void t4_cleanup_clip_tbl(struct adapter *adap); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 5ab5c3133acd..d6cda17efe6e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -49,16 +49,6 @@ #include #include "cxgb4_uld.h" -#define T4FW_VERSION_MAJOR 0x01 -#define T4FW_VERSION_MINOR 0x0C -#define T4FW_VERSION_MICRO 0x19 -#define T4FW_VERSION_BUILD 0x00 - -#define T5FW_VERSION_MAJOR 0x01 -#define T5FW_VERSION_MINOR 0x0C -#define T5FW_VERSION_MICRO 0x19 -#define T5FW_VERSION_BUILD 0x00 - #define CH_WARN(adap, fmt, ...) dev_warn(adap->pdev_dev, fmt, ## __VA_ARGS__) enum { @@ -231,6 +221,7 @@ struct sge_params { struct tp_params { unsigned int ntxchan; /* # of Tx channels */ unsigned int tre; /* log2 of core clocks per TP tick */ + unsigned int la_mask; /* what events are recorded by TP LA */ unsigned short tx_modq_map; /* TX modulation scheduler queue to */ /* channel map */ @@ -290,11 +281,21 @@ enum chip_type { T5_LAST_REV = T5_A1, }; +struct devlog_params { + u32 memtype; /* which memory (EDC0, EDC1, MC) */ + u32 start; /* start of log in firmware memory */ + u32 size; /* size of log */ +}; + struct adapter_params { struct sge_params sge; struct tp_params tp; struct vpd_params vpd; struct pci_params pci; + struct devlog_params devlog; + enum pcie_memwin drv_memwin; + + unsigned int cim_la_size; unsigned int sf_size; /* serial flash size in bytes */ unsigned int sf_nsec; /* # of flash sectors */ @@ -476,6 +477,22 @@ struct sge_rspq { /* state for an SGE response queue */ struct adapter *adap; struct net_device *netdev; /* associated net device */ rspq_handler_t handler; +#ifdef CONFIG_NET_RX_BUSY_POLL +#define CXGB_POLL_STATE_IDLE 0 +#define CXGB_POLL_STATE_NAPI BIT(0) /* NAPI owns this poll */ +#define CXGB_POLL_STATE_POLL BIT(1) /* poll owns this poll */ +#define CXGB_POLL_STATE_NAPI_YIELD BIT(2) /* NAPI yielded this poll */ +#define CXGB_POLL_STATE_POLL_YIELD BIT(3) /* poll yielded this poll */ +#define CXGB_POLL_YIELD (CXGB_POLL_STATE_NAPI_YIELD | \ + CXGB_POLL_STATE_POLL_YIELD) +#define CXGB_POLL_LOCKED (CXGB_POLL_STATE_NAPI | \ + CXGB_POLL_STATE_POLL) +#define CXGB_POLL_USER_PEND (CXGB_POLL_STATE_POLL | \ + CXGB_POLL_STATE_POLL_YIELD) + unsigned int bpoll_state; + spinlock_t bpoll_lock; /* lock for busy poll */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ + }; struct sge_eth_stats { /* Ethernet queue statistics */ @@ -658,6 +675,9 @@ struct adapter { unsigned int l2t_start; unsigned int l2t_end; struct l2t_data *l2t; + unsigned int clipt_start; + unsigned int clipt_end; + struct clip_tbl *clipt; void *uld_handle[CXGB4_ULD_MAX]; struct list_head list_node; struct list_head rcu_node; @@ -877,6 +897,102 @@ static inline struct adapter *netdev2adap(const struct net_device *dev) return netdev2pinfo(dev)->adapter; } +#ifdef CONFIG_NET_RX_BUSY_POLL +static inline void cxgb_busy_poll_init_lock(struct sge_rspq *q) +{ + spin_lock_init(&q->bpoll_lock); + q->bpoll_state = CXGB_POLL_STATE_IDLE; +} + +static inline bool cxgb_poll_lock_napi(struct sge_rspq *q) +{ + bool rc = true; + + spin_lock(&q->bpoll_lock); + if (q->bpoll_state & CXGB_POLL_LOCKED) { + q->bpoll_state |= CXGB_POLL_STATE_NAPI_YIELD; + rc = false; + } else { + q->bpoll_state = CXGB_POLL_STATE_NAPI; + } + spin_unlock(&q->bpoll_lock); + return rc; +} + +static inline bool cxgb_poll_unlock_napi(struct sge_rspq *q) +{ + bool rc = false; + + spin_lock(&q->bpoll_lock); + if (q->bpoll_state & CXGB_POLL_STATE_POLL_YIELD) + rc = true; + q->bpoll_state = CXGB_POLL_STATE_IDLE; + spin_unlock(&q->bpoll_lock); + return rc; +} + +static inline bool cxgb_poll_lock_poll(struct sge_rspq *q) +{ + bool rc = true; + + spin_lock_bh(&q->bpoll_lock); + if (q->bpoll_state & CXGB_POLL_LOCKED) { + q->bpoll_state |= CXGB_POLL_STATE_POLL_YIELD; + rc = false; + } else { + q->bpoll_state |= CXGB_POLL_STATE_POLL; + } + spin_unlock_bh(&q->bpoll_lock); + return rc; +} + +static inline bool cxgb_poll_unlock_poll(struct sge_rspq *q) +{ + bool rc = false; + + spin_lock_bh(&q->bpoll_lock); + if (q->bpoll_state & CXGB_POLL_STATE_POLL_YIELD) + rc = true; + q->bpoll_state = CXGB_POLL_STATE_IDLE; + spin_unlock_bh(&q->bpoll_lock); + return rc; +} + +static inline bool cxgb_poll_busy_polling(struct sge_rspq *q) +{ + return q->bpoll_state & CXGB_POLL_USER_PEND; +} +#else +static inline void cxgb_busy_poll_init_lock(struct sge_rspq *q) +{ +} + +static inline bool cxgb_poll_lock_napi(struct sge_rspq *q) +{ + return true; +} + +static inline bool cxgb_poll_unlock_napi(struct sge_rspq *q) +{ + return false; +} + +static inline bool cxgb_poll_lock_poll(struct sge_rspq *q) +{ + return false; +} + +static inline bool cxgb_poll_unlock_poll(struct sge_rspq *q) +{ + return false; +} + +static inline bool cxgb_poll_busy_polling(struct sge_rspq *q) +{ + return false; +} +#endif /* CONFIG_NET_RX_BUSY_POLL */ + void t4_os_portmod_changed(const struct adapter *adap, int port_id); void t4_os_link_changed(struct adapter *adap, int port_id, int link_stat); @@ -905,6 +1021,7 @@ irqreturn_t t4_sge_intr_msix(int irq, void *cookie); int t4_sge_init(struct adapter *adap); void t4_sge_start(struct adapter *adap); void t4_sge_stop(struct adapter *adap); +int cxgb_busy_poll(struct napi_struct *napi); extern int dbfifo_int_thresh; #define for_each_port(adapter, iter) \ @@ -995,12 +1112,16 @@ static inline int t4_memory_write(struct adapter *adap, int mtype, u32 addr, int t4_seeprom_wp(struct adapter *adapter, bool enable); int get_vpd_params(struct adapter *adapter, struct vpd_params *p); +int t4_read_flash(struct adapter *adapter, unsigned int addr, + unsigned int nwords, u32 *data, int byte_oriented); int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size); +int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op); int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, const u8 *fw_data, unsigned int size, int force); unsigned int t4_flash_cfg_addr(struct adapter *adapter); int t4_get_fw_version(struct adapter *adapter, u32 *vers); int t4_get_tp_version(struct adapter *adapter, u32 *vers); +int t4_get_exprom_version(struct adapter *adapter, u32 *vers); int t4_prep_fw(struct adapter *adap, struct fw_info *fw_info, const u8 *fw_data, unsigned int fw_size, struct fw_hdr *card_fw, enum dev_state state, int *reset); @@ -1013,6 +1134,8 @@ int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter, u64 *pbar2_qoffset, unsigned int *pbar2_qid); +unsigned int qtimer_val(const struct adapter *adap, + const struct sge_rspq *q); int t4_init_sge_params(struct adapter *adapter); int t4_init_tp_params(struct adapter *adap); int t4_filter_field_shift(const struct adapter *adap, int filter_sel); @@ -1022,20 +1145,46 @@ int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid, int start, int n, const u16 *rspq, unsigned int nrspq); int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, unsigned int flags); +int t4_read_rss(struct adapter *adapter, u16 *entries); +void t4_read_rss_key(struct adapter *adapter, u32 *key); +void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx); +void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, + u32 *valp); +void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index, + u32 *vfl, u32 *vfh); +u32 t4_read_rss_pf_map(struct adapter *adapter); +u32 t4_read_rss_pf_mask(struct adapter *adapter); + int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); +void t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]); +void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]); +int t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, + size_t n); +int t4_read_cim_obq(struct adapter *adap, unsigned int qid, u32 *data, + size_t n); +int t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n, + unsigned int *valp); +int t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n, + const unsigned int *valp); +int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr); +void t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres); const char *t4_get_port_type_description(enum fw_port_type port_type); void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p); void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log); +void t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN]); void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr, unsigned int mask, unsigned int val); +void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr); void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, struct tp_tcp_stats *v6); void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, const unsigned short *alpha, const unsigned short *beta); +void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf); + void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid); void t4_wol_magic_enable(struct adapter *adap, unsigned int port, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c index a35d1ec6950e..6074680bc985 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -22,7 +22,7 @@ /* DCBx version control */ -char *dcb_ver_array[] = { +static const char * const dcb_ver_array[] = { "Unknown", "DCBx-CIN", "DCBx-CEE 1.01", @@ -428,7 +428,10 @@ static void cxgb4_getpgtccfg(struct net_device *dev, int tc, } *pgid = (be32_to_cpu(pcmd.u.dcb.pgid.pgid) >> (tc * 4)) & 0xf; - INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); + if (local) + INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id); + else + INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE; err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); if (err != FW_PORT_DCB_CFG_SUCCESS) { @@ -900,6 +903,88 @@ cxgb4_ieee_negotiation_complete(struct net_device *dev, (dcb->supported & DCB_CAP_DCBX_VER_IEEE)); } +static int cxgb4_ieee_read_ets(struct net_device *dev, struct ieee_ets *ets, + int local) +{ + struct port_info *pi = netdev2pinfo(dev); + struct port_dcb_info *dcb = &pi->dcb; + struct adapter *adap = pi->adapter; + uint32_t tc_info; + struct fw_port_cmd pcmd; + int i, bwg, err; + + if (!(dcb->msgs & (CXGB4_DCB_FW_PGID | CXGB4_DCB_FW_PGRATE))) + return 0; + + ets->ets_cap = dcb->pg_num_tcs_supported; + + if (local) { + ets->willing = 1; + INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id); + } else { + INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); + } + + pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID; + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err); + return err; + } + + tc_info = be32_to_cpu(pcmd.u.dcb.pgid.pgid); + + if (local) + INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id); + else + INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id); + + pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE; + err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd); + if (err != FW_PORT_DCB_CFG_SUCCESS) { + dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n", + -err); + return err; + } + + for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { + bwg = (tc_info >> ((7 - i) * 4)) & 0xF; + ets->prio_tc[i] = bwg; + ets->tc_tx_bw[i] = pcmd.u.dcb.pgrate.pgrate[i]; + ets->tc_rx_bw[i] = ets->tc_tx_bw[i]; + ets->tc_tsa[i] = pcmd.u.dcb.pgrate.tsa[i]; + } + + return 0; +} + +static int cxgb4_ieee_get_ets(struct net_device *dev, struct ieee_ets *ets) +{ + return cxgb4_ieee_read_ets(dev, ets, 1); +} + +/* We reuse this for peer PFC as well, as we can't have it enabled one way */ +static int cxgb4_ieee_get_pfc(struct net_device *dev, struct ieee_pfc *pfc) +{ + struct port_info *pi = netdev2pinfo(dev); + struct port_dcb_info *dcb = &pi->dcb; + + memset(pfc, 0, sizeof(struct ieee_pfc)); + + if (!(dcb->msgs & CXGB4_DCB_FW_PFC)) + return 0; + + pfc->pfc_cap = dcb->pfc_num_tcs_supported; + pfc->pfc_en = bitswap_1(dcb->pfcen); + + return 0; +} + +static int cxgb4_ieee_peer_ets(struct net_device *dev, struct ieee_ets *ets) +{ + return cxgb4_ieee_read_ets(dev, ets, 0); +} + /* Fill in the Application User Priority Map associated with the * specified Application. * Priority for IEEE dcb_app is an integer, with 0 being a valid value @@ -1106,14 +1191,23 @@ static int cxgb4_cee_peer_getpfc(struct net_device *dev, struct cee_pfc *pfc) struct port_info *pi = netdev2pinfo(dev); cxgb4_getnumtcs(dev, DCB_NUMTCS_ATTR_PFC, &(pfc->tcs_supported)); - pfc->pfc_en = pi->dcb.pfcen; + + /* Firmware sends this to us in a formwat that is a bit flipped version + * of spec, correct it before we send it to host. This is taken care of + * by bit shifting in other uses of pfcen + */ + pfc->pfc_en = bitswap_1(pi->dcb.pfcen); return 0; } const struct dcbnl_rtnl_ops cxgb4_dcb_ops = { + .ieee_getets = cxgb4_ieee_get_ets, + .ieee_getpfc = cxgb4_ieee_get_pfc, .ieee_getapp = cxgb4_ieee_getapp, .ieee_setapp = cxgb4_ieee_setapp, + .ieee_peer_getets = cxgb4_ieee_peer_ets, + .ieee_peer_getpfc = cxgb4_ieee_get_pfc, /* CEE std */ .getstate = cxgb4_getstate, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h index 31ce425616c9..ccf24d3dc982 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h @@ -136,6 +136,17 @@ void cxgb4_dcb_handle_fw_update(struct adapter *, const struct fw_port_cmd *); void cxgb4_dcb_set_caps(struct adapter *, const struct fw_port_cmd *); extern const struct dcbnl_rtnl_ops cxgb4_dcb_ops; +static inline __u8 bitswap_1(unsigned char val) +{ + return ((val & 0x80) >> 7) | + ((val & 0x40) >> 5) | + ((val & 0x20) >> 3) | + ((val & 0x10) >> 1) | + ((val & 0x08) << 1) | + ((val & 0x04) << 3) | + ((val & 0x02) << 5) | + ((val & 0x01) << 7); +} #define CXGB4_DCB_ENABLED true #else /* !CONFIG_CHELSIO_T4_DCB */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index c98a350d857e..d221f6b28fcd 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -36,13 +36,1867 @@ #include #include #include +#include #include "cxgb4.h" #include "t4_regs.h" +#include "t4_values.h" #include "t4fw_api.h" #include "cxgb4_debugfs.h" +#include "clip_tbl.h" #include "l2t.h" +/* generic seq_file support for showing a table of size rows x width. */ +static void *seq_tab_get_idx(struct seq_tab *tb, loff_t pos) +{ + pos -= tb->skip_first; + return pos >= tb->rows ? NULL : &tb->data[pos * tb->width]; +} + +static void *seq_tab_start(struct seq_file *seq, loff_t *pos) +{ + struct seq_tab *tb = seq->private; + + if (tb->skip_first && *pos == 0) + return SEQ_START_TOKEN; + + return seq_tab_get_idx(tb, *pos); +} + +static void *seq_tab_next(struct seq_file *seq, void *v, loff_t *pos) +{ + v = seq_tab_get_idx(seq->private, *pos + 1); + if (v) + ++*pos; + return v; +} + +static void seq_tab_stop(struct seq_file *seq, void *v) +{ +} + +static int seq_tab_show(struct seq_file *seq, void *v) +{ + const struct seq_tab *tb = seq->private; + + return tb->show(seq, v, ((char *)v - tb->data) / tb->width); +} + +static const struct seq_operations seq_tab_ops = { + .start = seq_tab_start, + .next = seq_tab_next, + .stop = seq_tab_stop, + .show = seq_tab_show +}; + +struct seq_tab *seq_open_tab(struct file *f, unsigned int rows, + unsigned int width, unsigned int have_header, + int (*show)(struct seq_file *seq, void *v, int i)) +{ + struct seq_tab *p; + + p = __seq_open_private(f, &seq_tab_ops, sizeof(*p) + rows * width); + if (p) { + p->show = show; + p->rows = rows; + p->width = width; + p->skip_first = have_header != 0; + } + return p; +} + +/* Trim the size of a seq_tab to the supplied number of rows. The operation is + * irreversible. + */ +static int seq_tab_trim(struct seq_tab *p, unsigned int new_rows) +{ + if (new_rows > p->rows) + return -EINVAL; + p->rows = new_rows; + return 0; +} + +static int cim_la_show(struct seq_file *seq, void *v, int idx) +{ + if (v == SEQ_START_TOKEN) + seq_puts(seq, "Status Data PC LS0Stat LS0Addr " + " LS0Data\n"); + else { + const u32 *p = v; + + seq_printf(seq, + " %02x %x%07x %x%07x %08x %08x %08x%08x%08x%08x\n", + (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, + p[1] & 0xf, p[2] >> 4, p[2] & 0xf, p[3], p[4], p[5], + p[6], p[7]); + } + return 0; +} + +static int cim_la_show_3in1(struct seq_file *seq, void *v, int idx) +{ + if (v == SEQ_START_TOKEN) { + seq_puts(seq, "Status Data PC\n"); + } else { + const u32 *p = v; + + seq_printf(seq, " %02x %08x %08x\n", p[5] & 0xff, p[6], + p[7]); + seq_printf(seq, " %02x %02x%06x %02x%06x\n", + (p[3] >> 8) & 0xff, p[3] & 0xff, p[4] >> 8, + p[4] & 0xff, p[5] >> 8); + seq_printf(seq, " %02x %x%07x %x%07x\n", (p[0] >> 4) & 0xff, + p[0] & 0xf, p[1] >> 4, p[1] & 0xf, p[2] >> 4); + } + return 0; +} + +static int cim_la_open(struct inode *inode, struct file *file) +{ + int ret; + unsigned int cfg; + struct seq_tab *p; + struct adapter *adap = inode->i_private; + + ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &cfg); + if (ret) + return ret; + + p = seq_open_tab(file, adap->params.cim_la_size / 8, 8 * sizeof(u32), 1, + cfg & UPDBGLACAPTPCONLY_F ? + cim_la_show_3in1 : cim_la_show); + if (!p) + return -ENOMEM; + + ret = t4_cim_read_la(adap, (u32 *)p->data, NULL); + if (ret) + seq_release_private(inode, file); + return ret; +} + +static const struct file_operations cim_la_fops = { + .owner = THIS_MODULE, + .open = cim_la_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + +static int cim_qcfg_show(struct seq_file *seq, void *v) +{ + static const char * const qname[] = { + "TP0", "TP1", "ULP", "SGE0", "SGE1", "NC-SI", + "ULP0", "ULP1", "ULP2", "ULP3", "SGE", "NC-SI", + "SGE0-RX", "SGE1-RX" + }; + + int i; + struct adapter *adap = seq->private; + u16 base[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; + u16 size[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; + u32 stat[(4 * (CIM_NUM_IBQ + CIM_NUM_OBQ_T5))]; + u16 thres[CIM_NUM_IBQ]; + u32 obq_wr_t4[2 * CIM_NUM_OBQ], *wr; + u32 obq_wr_t5[2 * CIM_NUM_OBQ_T5]; + u32 *p = stat; + int cim_num_obq = is_t4(adap->params.chip) ? + CIM_NUM_OBQ : CIM_NUM_OBQ_T5; + + i = t4_cim_read(adap, is_t4(adap->params.chip) ? UP_IBQ_0_RDADDR_A : + UP_IBQ_0_SHADOW_RDADDR_A, + ARRAY_SIZE(stat), stat); + if (!i) { + if (is_t4(adap->params.chip)) { + i = t4_cim_read(adap, UP_OBQ_0_REALADDR_A, + ARRAY_SIZE(obq_wr_t4), obq_wr_t4); + wr = obq_wr_t4; + } else { + i = t4_cim_read(adap, UP_OBQ_0_SHADOW_REALADDR_A, + ARRAY_SIZE(obq_wr_t5), obq_wr_t5); + wr = obq_wr_t5; + } + } + if (i) + return i; + + t4_read_cimq_cfg(adap, base, size, thres); + + seq_printf(seq, + " Queue Base Size Thres RdPtr WrPtr SOP EOP Avail\n"); + for (i = 0; i < CIM_NUM_IBQ; i++, p += 4) + seq_printf(seq, "%7s %5x %5u %5u %6x %4x %4u %4u %5u\n", + qname[i], base[i], size[i], thres[i], + IBQRDADDR_G(p[0]), IBQWRADDR_G(p[1]), + QUESOPCNT_G(p[3]), QUEEOPCNT_G(p[3]), + QUEREMFLITS_G(p[2]) * 16); + for ( ; i < CIM_NUM_IBQ + cim_num_obq; i++, p += 4, wr += 2) + seq_printf(seq, "%7s %5x %5u %12x %4x %4u %4u %5u\n", + qname[i], base[i], size[i], + QUERDADDR_G(p[0]) & 0x3fff, wr[0] - base[i], + QUESOPCNT_G(p[3]), QUEEOPCNT_G(p[3]), + QUEREMFLITS_G(p[2]) * 16); + return 0; +} + +static int cim_qcfg_open(struct inode *inode, struct file *file) +{ + return single_open(file, cim_qcfg_show, inode->i_private); +} + +static const struct file_operations cim_qcfg_fops = { + .owner = THIS_MODULE, + .open = cim_qcfg_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int cimq_show(struct seq_file *seq, void *v, int idx) +{ + const u32 *p = v; + + seq_printf(seq, "%#06x: %08x %08x %08x %08x\n", idx * 16, p[0], p[1], + p[2], p[3]); + return 0; +} + +static int cim_ibq_open(struct inode *inode, struct file *file) +{ + int ret; + struct seq_tab *p; + unsigned int qid = (uintptr_t)inode->i_private & 7; + struct adapter *adap = inode->i_private - qid; + + p = seq_open_tab(file, CIM_IBQ_SIZE, 4 * sizeof(u32), 0, cimq_show); + if (!p) + return -ENOMEM; + + ret = t4_read_cim_ibq(adap, qid, (u32 *)p->data, CIM_IBQ_SIZE * 4); + if (ret < 0) + seq_release_private(inode, file); + else + ret = 0; + return ret; +} + +static const struct file_operations cim_ibq_fops = { + .owner = THIS_MODULE, + .open = cim_ibq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + +static int cim_obq_open(struct inode *inode, struct file *file) +{ + int ret; + struct seq_tab *p; + unsigned int qid = (uintptr_t)inode->i_private & 7; + struct adapter *adap = inode->i_private - qid; + + p = seq_open_tab(file, 6 * CIM_OBQ_SIZE, 4 * sizeof(u32), 0, cimq_show); + if (!p) + return -ENOMEM; + + ret = t4_read_cim_obq(adap, qid, (u32 *)p->data, 6 * CIM_OBQ_SIZE * 4); + if (ret < 0) { + seq_release_private(inode, file); + } else { + seq_tab_trim(p, ret / 4); + ret = 0; + } + return ret; +} + +static const struct file_operations cim_obq_fops = { + .owner = THIS_MODULE, + .open = cim_obq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + +struct field_desc { + const char *name; + unsigned int start; + unsigned int width; +}; + +static void field_desc_show(struct seq_file *seq, u64 v, + const struct field_desc *p) +{ + char buf[32]; + int line_size = 0; + + while (p->name) { + u64 mask = (1ULL << p->width) - 1; + int len = scnprintf(buf, sizeof(buf), "%s: %llu", p->name, + ((unsigned long long)v >> p->start) & mask); + + if (line_size + len >= 79) { + line_size = 8; + seq_puts(seq, "\n "); + } + seq_printf(seq, "%s ", buf); + line_size += len + 1; + p++; + } + seq_putc(seq, '\n'); +} + +static struct field_desc tp_la0[] = { + { "RcfOpCodeOut", 60, 4 }, + { "State", 56, 4 }, + { "WcfState", 52, 4 }, + { "RcfOpcSrcOut", 50, 2 }, + { "CRxError", 49, 1 }, + { "ERxError", 48, 1 }, + { "SanityFailed", 47, 1 }, + { "SpuriousMsg", 46, 1 }, + { "FlushInputMsg", 45, 1 }, + { "FlushInputCpl", 44, 1 }, + { "RssUpBit", 43, 1 }, + { "RssFilterHit", 42, 1 }, + { "Tid", 32, 10 }, + { "InitTcb", 31, 1 }, + { "LineNumber", 24, 7 }, + { "Emsg", 23, 1 }, + { "EdataOut", 22, 1 }, + { "Cmsg", 21, 1 }, + { "CdataOut", 20, 1 }, + { "EreadPdu", 19, 1 }, + { "CreadPdu", 18, 1 }, + { "TunnelPkt", 17, 1 }, + { "RcfPeerFin", 16, 1 }, + { "RcfReasonOut", 12, 4 }, + { "TxCchannel", 10, 2 }, + { "RcfTxChannel", 8, 2 }, + { "RxEchannel", 6, 2 }, + { "RcfRxChannel", 5, 1 }, + { "RcfDataOutSrdy", 4, 1 }, + { "RxDvld", 3, 1 }, + { "RxOoDvld", 2, 1 }, + { "RxCongestion", 1, 1 }, + { "TxCongestion", 0, 1 }, + { NULL } +}; + +static int tp_la_show(struct seq_file *seq, void *v, int idx) +{ + const u64 *p = v; + + field_desc_show(seq, *p, tp_la0); + return 0; +} + +static int tp_la_show2(struct seq_file *seq, void *v, int idx) +{ + const u64 *p = v; + + if (idx) + seq_putc(seq, '\n'); + field_desc_show(seq, p[0], tp_la0); + if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) + field_desc_show(seq, p[1], tp_la0); + return 0; +} + +static int tp_la_show3(struct seq_file *seq, void *v, int idx) +{ + static struct field_desc tp_la1[] = { + { "CplCmdIn", 56, 8 }, + { "CplCmdOut", 48, 8 }, + { "ESynOut", 47, 1 }, + { "EAckOut", 46, 1 }, + { "EFinOut", 45, 1 }, + { "ERstOut", 44, 1 }, + { "SynIn", 43, 1 }, + { "AckIn", 42, 1 }, + { "FinIn", 41, 1 }, + { "RstIn", 40, 1 }, + { "DataIn", 39, 1 }, + { "DataInVld", 38, 1 }, + { "PadIn", 37, 1 }, + { "RxBufEmpty", 36, 1 }, + { "RxDdp", 35, 1 }, + { "RxFbCongestion", 34, 1 }, + { "TxFbCongestion", 33, 1 }, + { "TxPktSumSrdy", 32, 1 }, + { "RcfUlpType", 28, 4 }, + { "Eread", 27, 1 }, + { "Ebypass", 26, 1 }, + { "Esave", 25, 1 }, + { "Static0", 24, 1 }, + { "Cread", 23, 1 }, + { "Cbypass", 22, 1 }, + { "Csave", 21, 1 }, + { "CPktOut", 20, 1 }, + { "RxPagePoolFull", 18, 2 }, + { "RxLpbkPkt", 17, 1 }, + { "TxLpbkPkt", 16, 1 }, + { "RxVfValid", 15, 1 }, + { "SynLearned", 14, 1 }, + { "SetDelEntry", 13, 1 }, + { "SetInvEntry", 12, 1 }, + { "CpcmdDvld", 11, 1 }, + { "CpcmdSave", 10, 1 }, + { "RxPstructsFull", 8, 2 }, + { "EpcmdDvld", 7, 1 }, + { "EpcmdFlush", 6, 1 }, + { "EpcmdTrimPrefix", 5, 1 }, + { "EpcmdTrimPostfix", 4, 1 }, + { "ERssIp4Pkt", 3, 1 }, + { "ERssIp6Pkt", 2, 1 }, + { "ERssTcpUdpPkt", 1, 1 }, + { "ERssFceFipPkt", 0, 1 }, + { NULL } + }; + static struct field_desc tp_la2[] = { + { "CplCmdIn", 56, 8 }, + { "MpsVfVld", 55, 1 }, + { "MpsPf", 52, 3 }, + { "MpsVf", 44, 8 }, + { "SynIn", 43, 1 }, + { "AckIn", 42, 1 }, + { "FinIn", 41, 1 }, + { "RstIn", 40, 1 }, + { "DataIn", 39, 1 }, + { "DataInVld", 38, 1 }, + { "PadIn", 37, 1 }, + { "RxBufEmpty", 36, 1 }, + { "RxDdp", 35, 1 }, + { "RxFbCongestion", 34, 1 }, + { "TxFbCongestion", 33, 1 }, + { "TxPktSumSrdy", 32, 1 }, + { "RcfUlpType", 28, 4 }, + { "Eread", 27, 1 }, + { "Ebypass", 26, 1 }, + { "Esave", 25, 1 }, + { "Static0", 24, 1 }, + { "Cread", 23, 1 }, + { "Cbypass", 22, 1 }, + { "Csave", 21, 1 }, + { "CPktOut", 20, 1 }, + { "RxPagePoolFull", 18, 2 }, + { "RxLpbkPkt", 17, 1 }, + { "TxLpbkPkt", 16, 1 }, + { "RxVfValid", 15, 1 }, + { "SynLearned", 14, 1 }, + { "SetDelEntry", 13, 1 }, + { "SetInvEntry", 12, 1 }, + { "CpcmdDvld", 11, 1 }, + { "CpcmdSave", 10, 1 }, + { "RxPstructsFull", 8, 2 }, + { "EpcmdDvld", 7, 1 }, + { "EpcmdFlush", 6, 1 }, + { "EpcmdTrimPrefix", 5, 1 }, + { "EpcmdTrimPostfix", 4, 1 }, + { "ERssIp4Pkt", 3, 1 }, + { "ERssIp6Pkt", 2, 1 }, + { "ERssTcpUdpPkt", 1, 1 }, + { "ERssFceFipPkt", 0, 1 }, + { NULL } + }; + const u64 *p = v; + + if (idx) + seq_putc(seq, '\n'); + field_desc_show(seq, p[0], tp_la0); + if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) + field_desc_show(seq, p[1], (p[0] & BIT(17)) ? tp_la2 : tp_la1); + return 0; +} + +static int tp_la_open(struct inode *inode, struct file *file) +{ + struct seq_tab *p; + struct adapter *adap = inode->i_private; + + switch (DBGLAMODE_G(t4_read_reg(adap, TP_DBG_LA_CONFIG_A))) { + case 2: + p = seq_open_tab(file, TPLA_SIZE / 2, 2 * sizeof(u64), 0, + tp_la_show2); + break; + case 3: + p = seq_open_tab(file, TPLA_SIZE / 2, 2 * sizeof(u64), 0, + tp_la_show3); + break; + default: + p = seq_open_tab(file, TPLA_SIZE, sizeof(u64), 0, tp_la_show); + } + if (!p) + return -ENOMEM; + + t4_tp_read_la(adap, (u64 *)p->data, NULL); + return 0; +} + +static ssize_t tp_la_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + int err; + char s[32]; + unsigned long val; + size_t size = min(sizeof(s) - 1, count); + struct adapter *adap = FILE_DATA(file)->i_private; + + if (copy_from_user(s, buf, size)) + return -EFAULT; + s[size] = '\0'; + err = kstrtoul(s, 0, &val); + if (err) + return err; + if (val > 0xffff) + return -EINVAL; + adap->params.tp.la_mask = val << 16; + t4_set_reg_field(adap, TP_DBG_LA_CONFIG_A, 0xffff0000U, + adap->params.tp.la_mask); + return count; +} + +static const struct file_operations tp_la_fops = { + .owner = THIS_MODULE, + .open = tp_la_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, + .write = tp_la_write +}; + +static int ulprx_la_show(struct seq_file *seq, void *v, int idx) +{ + const u32 *p = v; + + if (v == SEQ_START_TOKEN) + seq_puts(seq, " Pcmd Type Message" + " Data\n"); + else + seq_printf(seq, "%08x%08x %4x %08x %08x%08x%08x%08x\n", + p[1], p[0], p[2], p[3], p[7], p[6], p[5], p[4]); + return 0; +} + +static int ulprx_la_open(struct inode *inode, struct file *file) +{ + struct seq_tab *p; + struct adapter *adap = inode->i_private; + + p = seq_open_tab(file, ULPRX_LA_SIZE, 8 * sizeof(u32), 1, + ulprx_la_show); + if (!p) + return -ENOMEM; + + t4_ulprx_read_la(adap, (u32 *)p->data); + return 0; +} + +static const struct file_operations ulprx_la_fops = { + .owner = THIS_MODULE, + .open = ulprx_la_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + +/* Show the PM memory stats. These stats include: + * + * TX: + * Read: memory read operation + * Write Bypass: cut-through + * Bypass + mem: cut-through and save copy + * + * RX: + * Read: memory read + * Write Bypass: cut-through + * Flush: payload trim or drop + */ +static int pm_stats_show(struct seq_file *seq, void *v) +{ + static const char * const tx_pm_stats[] = { + "Read:", "Write bypass:", "Write mem:", "Bypass + mem:" + }; + static const char * const rx_pm_stats[] = { + "Read:", "Write bypass:", "Write mem:", "Flush:" + }; + + int i; + u32 tx_cnt[PM_NSTATS], rx_cnt[PM_NSTATS]; + u64 tx_cyc[PM_NSTATS], rx_cyc[PM_NSTATS]; + struct adapter *adap = seq->private; + + t4_pmtx_get_stats(adap, tx_cnt, tx_cyc); + t4_pmrx_get_stats(adap, rx_cnt, rx_cyc); + + seq_printf(seq, "%13s %10s %20s\n", " ", "Tx pcmds", "Tx bytes"); + for (i = 0; i < PM_NSTATS - 1; i++) + seq_printf(seq, "%-13s %10u %20llu\n", + tx_pm_stats[i], tx_cnt[i], tx_cyc[i]); + + seq_printf(seq, "%13s %10s %20s\n", " ", "Rx pcmds", "Rx bytes"); + for (i = 0; i < PM_NSTATS - 1; i++) + seq_printf(seq, "%-13s %10u %20llu\n", + rx_pm_stats[i], rx_cnt[i], rx_cyc[i]); + return 0; +} + +static int pm_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, pm_stats_show, inode->i_private); +} + +static ssize_t pm_stats_clear(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + struct adapter *adap = FILE_DATA(file)->i_private; + + t4_write_reg(adap, PM_RX_STAT_CONFIG_A, 0); + t4_write_reg(adap, PM_TX_STAT_CONFIG_A, 0); + return count; +} + +static const struct file_operations pm_stats_debugfs_fops = { + .owner = THIS_MODULE, + .open = pm_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = pm_stats_clear +}; + +static int cctrl_tbl_show(struct seq_file *seq, void *v) +{ + static const char * const dec_fac[] = { + "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", + "0.9375" }; + + int i; + u16 incr[NMTUS][NCCTRL_WIN]; + struct adapter *adap = seq->private; + + t4_read_cong_tbl(adap, incr); + + for (i = 0; i < NCCTRL_WIN; ++i) { + seq_printf(seq, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i, + incr[0][i], incr[1][i], incr[2][i], incr[3][i], + incr[4][i], incr[5][i], incr[6][i], incr[7][i]); + seq_printf(seq, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n", + incr[8][i], incr[9][i], incr[10][i], incr[11][i], + incr[12][i], incr[13][i], incr[14][i], incr[15][i], + adap->params.a_wnd[i], + dec_fac[adap->params.b_wnd[i]]); + } + return 0; +} + +DEFINE_SIMPLE_DEBUGFS_FILE(cctrl_tbl); + +/* Format a value in a unit that differs from the value's native unit by the + * given factor. + */ +static char *unit_conv(char *buf, size_t len, unsigned int val, + unsigned int factor) +{ + unsigned int rem = val % factor; + + if (rem == 0) { + snprintf(buf, len, "%u", val / factor); + } else { + while (rem % 10 == 0) + rem /= 10; + snprintf(buf, len, "%u.%u", val / factor, rem); + } + return buf; +} + +static int clk_show(struct seq_file *seq, void *v) +{ + char buf[32]; + struct adapter *adap = seq->private; + unsigned int cclk_ps = 1000000000 / adap->params.vpd.cclk; /* in ps */ + u32 res = t4_read_reg(adap, TP_TIMER_RESOLUTION_A); + unsigned int tre = TIMERRESOLUTION_G(res); + unsigned int dack_re = DELAYEDACKRESOLUTION_G(res); + unsigned long long tp_tick_us = (cclk_ps << tre) / 1000000; /* in us */ + + seq_printf(seq, "Core clock period: %s ns\n", + unit_conv(buf, sizeof(buf), cclk_ps, 1000)); + seq_printf(seq, "TP timer tick: %s us\n", + unit_conv(buf, sizeof(buf), (cclk_ps << tre), 1000000)); + seq_printf(seq, "TCP timestamp tick: %s us\n", + unit_conv(buf, sizeof(buf), + (cclk_ps << TIMESTAMPRESOLUTION_G(res)), 1000000)); + seq_printf(seq, "DACK tick: %s us\n", + unit_conv(buf, sizeof(buf), (cclk_ps << dack_re), 1000000)); + seq_printf(seq, "DACK timer: %u us\n", + ((cclk_ps << dack_re) / 1000000) * + t4_read_reg(adap, TP_DACK_TIMER_A)); + seq_printf(seq, "Retransmit min: %llu us\n", + tp_tick_us * t4_read_reg(adap, TP_RXT_MIN_A)); + seq_printf(seq, "Retransmit max: %llu us\n", + tp_tick_us * t4_read_reg(adap, TP_RXT_MAX_A)); + seq_printf(seq, "Persist timer min: %llu us\n", + tp_tick_us * t4_read_reg(adap, TP_PERS_MIN_A)); + seq_printf(seq, "Persist timer max: %llu us\n", + tp_tick_us * t4_read_reg(adap, TP_PERS_MAX_A)); + seq_printf(seq, "Keepalive idle timer: %llu us\n", + tp_tick_us * t4_read_reg(adap, TP_KEEP_IDLE_A)); + seq_printf(seq, "Keepalive interval: %llu us\n", + tp_tick_us * t4_read_reg(adap, TP_KEEP_INTVL_A)); + seq_printf(seq, "Initial SRTT: %llu us\n", + tp_tick_us * INITSRTT_G(t4_read_reg(adap, TP_INIT_SRTT_A))); + seq_printf(seq, "FINWAIT2 timer: %llu us\n", + tp_tick_us * t4_read_reg(adap, TP_FINWAIT2_TIMER_A)); + + return 0; +} + +DEFINE_SIMPLE_DEBUGFS_FILE(clk); + +/* Firmware Device Log dump. */ +static const char * const devlog_level_strings[] = { + [FW_DEVLOG_LEVEL_EMERG] = "EMERG", + [FW_DEVLOG_LEVEL_CRIT] = "CRIT", + [FW_DEVLOG_LEVEL_ERR] = "ERR", + [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", + [FW_DEVLOG_LEVEL_INFO] = "INFO", + [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" +}; + +static const char * const devlog_facility_strings[] = { + [FW_DEVLOG_FACILITY_CORE] = "CORE", + [FW_DEVLOG_FACILITY_SCHED] = "SCHED", + [FW_DEVLOG_FACILITY_TIMER] = "TIMER", + [FW_DEVLOG_FACILITY_RES] = "RES", + [FW_DEVLOG_FACILITY_HW] = "HW", + [FW_DEVLOG_FACILITY_FLR] = "FLR", + [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", + [FW_DEVLOG_FACILITY_PHY] = "PHY", + [FW_DEVLOG_FACILITY_MAC] = "MAC", + [FW_DEVLOG_FACILITY_PORT] = "PORT", + [FW_DEVLOG_FACILITY_VI] = "VI", + [FW_DEVLOG_FACILITY_FILTER] = "FILTER", + [FW_DEVLOG_FACILITY_ACL] = "ACL", + [FW_DEVLOG_FACILITY_TM] = "TM", + [FW_DEVLOG_FACILITY_QFC] = "QFC", + [FW_DEVLOG_FACILITY_DCB] = "DCB", + [FW_DEVLOG_FACILITY_ETH] = "ETH", + [FW_DEVLOG_FACILITY_OFLD] = "OFLD", + [FW_DEVLOG_FACILITY_RI] = "RI", + [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", + [FW_DEVLOG_FACILITY_FCOE] = "FCOE", + [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", + [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE" +}; + +/* Information gathered by Device Log Open routine for the display routine. + */ +struct devlog_info { + unsigned int nentries; /* number of entries in log[] */ + unsigned int first; /* first [temporal] entry in log[] */ + struct fw_devlog_e log[0]; /* Firmware Device Log */ +}; + +/* Dump a Firmaware Device Log entry. + */ +static int devlog_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_printf(seq, "%10s %15s %8s %8s %s\n", + "Seq#", "Tstamp", "Level", "Facility", "Message"); + else { + struct devlog_info *dinfo = seq->private; + int fidx = (uintptr_t)v - 2; + unsigned long index; + struct fw_devlog_e *e; + + /* Get a pointer to the log entry to display. Skip unused log + * entries. + */ + index = dinfo->first + fidx; + if (index >= dinfo->nentries) + index -= dinfo->nentries; + e = &dinfo->log[index]; + if (e->timestamp == 0) + return 0; + + /* Print the message. This depends on the firmware using + * exactly the same formating strings as the kernel so we may + * eventually have to put a format interpreter in here ... + */ + seq_printf(seq, "%10d %15llu %8s %8s ", + e->seqno, e->timestamp, + (e->level < ARRAY_SIZE(devlog_level_strings) + ? devlog_level_strings[e->level] + : "UNKNOWN"), + (e->facility < ARRAY_SIZE(devlog_facility_strings) + ? devlog_facility_strings[e->facility] + : "UNKNOWN")); + seq_printf(seq, e->fmt, e->params[0], e->params[1], + e->params[2], e->params[3], e->params[4], + e->params[5], e->params[6], e->params[7]); + } + return 0; +} + +/* Sequential File Operations for Device Log. + */ +static inline void *devlog_get_idx(struct devlog_info *dinfo, loff_t pos) +{ + if (pos > dinfo->nentries) + return NULL; + + return (void *)(uintptr_t)(pos + 1); +} + +static void *devlog_start(struct seq_file *seq, loff_t *pos) +{ + struct devlog_info *dinfo = seq->private; + + return (*pos + ? devlog_get_idx(dinfo, *pos) + : SEQ_START_TOKEN); +} + +static void *devlog_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct devlog_info *dinfo = seq->private; + + (*pos)++; + return devlog_get_idx(dinfo, *pos); +} + +static void devlog_stop(struct seq_file *seq, void *v) +{ +} + +static const struct seq_operations devlog_seq_ops = { + .start = devlog_start, + .next = devlog_next, + .stop = devlog_stop, + .show = devlog_show +}; + +/* Set up for reading the firmware's device log. We read the entire log here + * and then display it incrementally in devlog_show(). + */ +static int devlog_open(struct inode *inode, struct file *file) +{ + struct adapter *adap = inode->i_private; + struct devlog_params *dparams = &adap->params.devlog; + struct devlog_info *dinfo; + unsigned int index; + u32 fseqno; + int ret; + + /* If we don't know where the log is we can't do anything. + */ + if (dparams->start == 0) + return -ENXIO; + + /* Allocate the space to read in the firmware's device log and set up + * for the iterated call to our display function. + */ + dinfo = __seq_open_private(file, &devlog_seq_ops, + sizeof(*dinfo) + dparams->size); + if (!dinfo) + return -ENOMEM; + + /* Record the basic log buffer information and read in the raw log. + */ + dinfo->nentries = (dparams->size / sizeof(struct fw_devlog_e)); + dinfo->first = 0; + spin_lock(&adap->win0_lock); + ret = t4_memory_rw(adap, adap->params.drv_memwin, dparams->memtype, + dparams->start, dparams->size, (__be32 *)dinfo->log, + T4_MEMORY_READ); + spin_unlock(&adap->win0_lock); + if (ret) { + seq_release_private(inode, file); + return ret; + } + + /* Translate log multi-byte integral elements into host native format + * and determine where the first entry in the log is. + */ + for (fseqno = ~((u32)0), index = 0; index < dinfo->nentries; index++) { + struct fw_devlog_e *e = &dinfo->log[index]; + int i; + __u32 seqno; + + if (e->timestamp == 0) + continue; + + e->timestamp = (__force __be64)be64_to_cpu(e->timestamp); + seqno = be32_to_cpu(e->seqno); + for (i = 0; i < 8; i++) + e->params[i] = + (__force __be32)be32_to_cpu(e->params[i]); + + if (seqno < fseqno) { + fseqno = seqno; + dinfo->first = index; + } + } + return 0; +} + +static const struct file_operations devlog_fops = { + .owner = THIS_MODULE, + .open = devlog_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + +static int mbox_show(struct seq_file *seq, void *v) +{ + static const char * const owner[] = { "none", "FW", "driver", + "unknown" }; + + int i; + unsigned int mbox = (uintptr_t)seq->private & 7; + struct adapter *adap = seq->private - mbox; + void __iomem *addr = adap->regs + PF_REG(mbox, CIM_PF_MAILBOX_DATA_A); + unsigned int ctrl_reg = (is_t4(adap->params.chip) + ? CIM_PF_MAILBOX_CTRL_A + : CIM_PF_MAILBOX_CTRL_SHADOW_COPY_A); + void __iomem *ctrl = adap->regs + PF_REG(mbox, ctrl_reg); + + i = MBOWNER_G(readl(ctrl)); + seq_printf(seq, "mailbox owned by %s\n\n", owner[i]); + + for (i = 0; i < MBOX_LEN; i += 8) + seq_printf(seq, "%016llx\n", + (unsigned long long)readq(addr + i)); + return 0; +} + +static int mbox_open(struct inode *inode, struct file *file) +{ + return single_open(file, mbox_show, inode->i_private); +} + +static ssize_t mbox_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + int i; + char c = '\n', s[256]; + unsigned long long data[8]; + const struct inode *ino; + unsigned int mbox; + struct adapter *adap; + void __iomem *addr; + void __iomem *ctrl; + + if (count > sizeof(s) - 1 || !count) + return -EINVAL; + if (copy_from_user(s, buf, count)) + return -EFAULT; + s[count] = '\0'; + + if (sscanf(s, "%llx %llx %llx %llx %llx %llx %llx %llx%c", &data[0], + &data[1], &data[2], &data[3], &data[4], &data[5], &data[6], + &data[7], &c) < 8 || c != '\n') + return -EINVAL; + + ino = FILE_DATA(file); + mbox = (uintptr_t)ino->i_private & 7; + adap = ino->i_private - mbox; + addr = adap->regs + PF_REG(mbox, CIM_PF_MAILBOX_DATA_A); + ctrl = addr + MBOX_LEN; + + if (MBOWNER_G(readl(ctrl)) != X_MBOWNER_PL) + return -EBUSY; + + for (i = 0; i < 8; i++) + writeq(data[i], addr + 8 * i); + + writel(MBMSGVALID_F | MBOWNER_V(X_MBOWNER_FW), ctrl); + return count; +} + +static const struct file_operations mbox_debugfs_fops = { + .owner = THIS_MODULE, + .open = mbox_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = mbox_write +}; + +static ssize_t flash_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + loff_t pos = *ppos; + loff_t avail = FILE_DATA(file)->i_size; + struct adapter *adap = file->private_data; + + if (pos < 0) + return -EINVAL; + if (pos >= avail) + return 0; + if (count > avail - pos) + count = avail - pos; + + while (count) { + size_t len; + int ret, ofst; + u8 data[256]; + + ofst = pos & 3; + len = min(count + ofst, sizeof(data)); + ret = t4_read_flash(adap, pos - ofst, (len + 3) / 4, + (u32 *)data, 1); + if (ret) + return ret; + + len -= ofst; + if (copy_to_user(buf, data + ofst, len)) + return -EFAULT; + + buf += len; + pos += len; + count -= len; + } + count = pos - *ppos; + *ppos = pos; + return count; +} + +static const struct file_operations flash_debugfs_fops = { + .owner = THIS_MODULE, + .open = mem_open, + .read = flash_read, +}; + +static inline void tcamxy2valmask(u64 x, u64 y, u8 *addr, u64 *mask) +{ + *mask = x | y; + y = (__force u64)cpu_to_be64(y); + memcpy(addr, (char *)&y + 2, ETH_ALEN); +} + +static int mps_tcam_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_puts(seq, "Idx Ethernet address Mask Vld Ports PF" + " VF Replication " + "P0 P1 P2 P3 ML\n"); + else { + u64 mask; + u8 addr[ETH_ALEN]; + struct adapter *adap = seq->private; + unsigned int idx = (uintptr_t)v - 2; + u64 tcamy = t4_read_reg64(adap, MPS_CLS_TCAM_Y_L(idx)); + u64 tcamx = t4_read_reg64(adap, MPS_CLS_TCAM_X_L(idx)); + u32 cls_lo = t4_read_reg(adap, MPS_CLS_SRAM_L(idx)); + u32 cls_hi = t4_read_reg(adap, MPS_CLS_SRAM_H(idx)); + u32 rplc[4] = {0, 0, 0, 0}; + + if (tcamx & tcamy) { + seq_printf(seq, "%3u -\n", idx); + goto out; + } + + if (cls_lo & REPLICATE_F) { + struct fw_ldst_cmd ldst_cmd; + int ret; + + memset(&ldst_cmd, 0, sizeof(ldst_cmd)); + ldst_cmd.op_to_addrspace = + htonl(FW_CMD_OP_V(FW_LDST_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_READ_F | + FW_LDST_CMD_ADDRSPACE_V( + FW_LDST_ADDRSPC_MPS)); + ldst_cmd.cycles_to_len16 = htonl(FW_LEN16(ldst_cmd)); + ldst_cmd.u.mps.fid_ctl = + htons(FW_LDST_CMD_FID_V(FW_LDST_MPS_RPLC) | + FW_LDST_CMD_CTL_V(idx)); + ret = t4_wr_mbox(adap, adap->mbox, &ldst_cmd, + sizeof(ldst_cmd), &ldst_cmd); + if (ret) + dev_warn(adap->pdev_dev, "Can't read MPS " + "replication map for idx %d: %d\n", + idx, -ret); + else { + rplc[0] = ntohl(ldst_cmd.u.mps.rplc31_0); + rplc[1] = ntohl(ldst_cmd.u.mps.rplc63_32); + rplc[2] = ntohl(ldst_cmd.u.mps.rplc95_64); + rplc[3] = ntohl(ldst_cmd.u.mps.rplc127_96); + } + } + + tcamxy2valmask(tcamx, tcamy, addr, &mask); + seq_printf(seq, "%3u %02x:%02x:%02x:%02x:%02x:%02x %012llx" + "%3c %#x%4u%4d", + idx, addr[0], addr[1], addr[2], addr[3], addr[4], + addr[5], (unsigned long long)mask, + (cls_lo & SRAM_VLD_F) ? 'Y' : 'N', PORTMAP_G(cls_hi), + PF_G(cls_lo), + (cls_lo & VF_VALID_F) ? VF_G(cls_lo) : -1); + if (cls_lo & REPLICATE_F) + seq_printf(seq, " %08x %08x %08x %08x", + rplc[3], rplc[2], rplc[1], rplc[0]); + else + seq_printf(seq, "%36c", ' '); + seq_printf(seq, "%4u%3u%3u%3u %#x\n", + SRAM_PRIO0_G(cls_lo), SRAM_PRIO1_G(cls_lo), + SRAM_PRIO2_G(cls_lo), SRAM_PRIO3_G(cls_lo), + (cls_lo >> MULTILISTEN0_S) & 0xf); + } +out: return 0; +} + +static inline void *mps_tcam_get_idx(struct seq_file *seq, loff_t pos) +{ + struct adapter *adap = seq->private; + int max_mac_addr = is_t4(adap->params.chip) ? + NUM_MPS_CLS_SRAM_L_INSTANCES : + NUM_MPS_T5_CLS_SRAM_L_INSTANCES; + return ((pos <= max_mac_addr) ? (void *)(uintptr_t)(pos + 1) : NULL); +} + +static void *mps_tcam_start(struct seq_file *seq, loff_t *pos) +{ + return *pos ? mps_tcam_get_idx(seq, *pos) : SEQ_START_TOKEN; +} + +static void *mps_tcam_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + return mps_tcam_get_idx(seq, *pos); +} + +static void mps_tcam_stop(struct seq_file *seq, void *v) +{ +} + +static const struct seq_operations mps_tcam_seq_ops = { + .start = mps_tcam_start, + .next = mps_tcam_next, + .stop = mps_tcam_stop, + .show = mps_tcam_show +}; + +static int mps_tcam_open(struct inode *inode, struct file *file) +{ + int res = seq_open(file, &mps_tcam_seq_ops); + + if (!res) { + struct seq_file *seq = file->private_data; + + seq->private = inode->i_private; + } + return res; +} + +static const struct file_operations mps_tcam_debugfs_fops = { + .owner = THIS_MODULE, + .open = mps_tcam_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* Display various sensor information. + */ +static int sensors_show(struct seq_file *seq, void *v) +{ + struct adapter *adap = seq->private; + u32 param[7], val[7]; + int ret; + + /* Note that if the sensors haven't been initialized and turned on + * we'll get values of 0, so treat those as "" ... + */ + param[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DIAG) | + FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_DIAG_TMP)); + param[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DIAG) | + FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_DIAG_VDD)); + ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, + param, val); + + if (ret < 0 || val[0] == 0) + seq_puts(seq, "Temperature: \n"); + else + seq_printf(seq, "Temperature: %dC\n", val[0]); + + if (ret < 0 || val[1] == 0) + seq_puts(seq, "Core VDD: \n"); + else + seq_printf(seq, "Core VDD: %dmV\n", val[1]); + + return 0; +} + +DEFINE_SIMPLE_DEBUGFS_FILE(sensors); + +#if IS_ENABLED(CONFIG_IPV6) +static int clip_tbl_open(struct inode *inode, struct file *file) +{ + return single_open(file, clip_tbl_show, inode->i_private); +} + +static const struct file_operations clip_tbl_debugfs_fops = { + .owner = THIS_MODULE, + .open = clip_tbl_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release +}; +#endif + +/*RSS Table. + */ + +static int rss_show(struct seq_file *seq, void *v, int idx) +{ + u16 *entry = v; + + seq_printf(seq, "%4d: %4u %4u %4u %4u %4u %4u %4u %4u\n", + idx * 8, entry[0], entry[1], entry[2], entry[3], entry[4], + entry[5], entry[6], entry[7]); + return 0; +} + +static int rss_open(struct inode *inode, struct file *file) +{ + int ret; + struct seq_tab *p; + struct adapter *adap = inode->i_private; + + p = seq_open_tab(file, RSS_NENTRIES / 8, 8 * sizeof(u16), 0, rss_show); + if (!p) + return -ENOMEM; + + ret = t4_read_rss(adap, (u16 *)p->data); + if (ret) + seq_release_private(inode, file); + + return ret; +} + +static const struct file_operations rss_debugfs_fops = { + .owner = THIS_MODULE, + .open = rss_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + +/* RSS Configuration. + */ + +/* Small utility function to return the strings "yes" or "no" if the supplied + * argument is non-zero. + */ +static const char *yesno(int x) +{ + static const char *yes = "yes"; + static const char *no = "no"; + + return x ? yes : no; +} + +static int rss_config_show(struct seq_file *seq, void *v) +{ + struct adapter *adapter = seq->private; + static const char * const keymode[] = { + "global", + "global and per-VF scramble", + "per-PF and per-VF scramble", + "per-VF and per-VF scramble", + }; + u32 rssconf; + + rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_A); + seq_printf(seq, "TP_RSS_CONFIG: %#x\n", rssconf); + seq_printf(seq, " Tnl4TupEnIpv6: %3s\n", yesno(rssconf & + TNL4TUPENIPV6_F)); + seq_printf(seq, " Tnl2TupEnIpv6: %3s\n", yesno(rssconf & + TNL2TUPENIPV6_F)); + seq_printf(seq, " Tnl4TupEnIpv4: %3s\n", yesno(rssconf & + TNL4TUPENIPV4_F)); + seq_printf(seq, " Tnl2TupEnIpv4: %3s\n", yesno(rssconf & + TNL2TUPENIPV4_F)); + seq_printf(seq, " TnlTcpSel: %3s\n", yesno(rssconf & TNLTCPSEL_F)); + seq_printf(seq, " TnlIp6Sel: %3s\n", yesno(rssconf & TNLIP6SEL_F)); + seq_printf(seq, " TnlVrtSel: %3s\n", yesno(rssconf & TNLVRTSEL_F)); + seq_printf(seq, " TnlMapEn: %3s\n", yesno(rssconf & TNLMAPEN_F)); + seq_printf(seq, " OfdHashSave: %3s\n", yesno(rssconf & + OFDHASHSAVE_F)); + seq_printf(seq, " OfdVrtSel: %3s\n", yesno(rssconf & OFDVRTSEL_F)); + seq_printf(seq, " OfdMapEn: %3s\n", yesno(rssconf & OFDMAPEN_F)); + seq_printf(seq, " OfdLkpEn: %3s\n", yesno(rssconf & OFDLKPEN_F)); + seq_printf(seq, " Syn4TupEnIpv6: %3s\n", yesno(rssconf & + SYN4TUPENIPV6_F)); + seq_printf(seq, " Syn2TupEnIpv6: %3s\n", yesno(rssconf & + SYN2TUPENIPV6_F)); + seq_printf(seq, " Syn4TupEnIpv4: %3s\n", yesno(rssconf & + SYN4TUPENIPV4_F)); + seq_printf(seq, " Syn2TupEnIpv4: %3s\n", yesno(rssconf & + SYN2TUPENIPV4_F)); + seq_printf(seq, " Syn4TupEnIpv6: %3s\n", yesno(rssconf & + SYN4TUPENIPV6_F)); + seq_printf(seq, " SynIp6Sel: %3s\n", yesno(rssconf & SYNIP6SEL_F)); + seq_printf(seq, " SynVrt6Sel: %3s\n", yesno(rssconf & SYNVRTSEL_F)); + seq_printf(seq, " SynMapEn: %3s\n", yesno(rssconf & SYNMAPEN_F)); + seq_printf(seq, " SynLkpEn: %3s\n", yesno(rssconf & SYNLKPEN_F)); + seq_printf(seq, " ChnEn: %3s\n", yesno(rssconf & + CHANNELENABLE_F)); + seq_printf(seq, " PrtEn: %3s\n", yesno(rssconf & + PORTENABLE_F)); + seq_printf(seq, " TnlAllLkp: %3s\n", yesno(rssconf & + TNLALLLOOKUP_F)); + seq_printf(seq, " VrtEn: %3s\n", yesno(rssconf & + VIRTENABLE_F)); + seq_printf(seq, " CngEn: %3s\n", yesno(rssconf & + CONGESTIONENABLE_F)); + seq_printf(seq, " HashToeplitz: %3s\n", yesno(rssconf & + HASHTOEPLITZ_F)); + seq_printf(seq, " Udp4En: %3s\n", yesno(rssconf & UDPENABLE_F)); + seq_printf(seq, " Disable: %3s\n", yesno(rssconf & DISABLE_F)); + + seq_puts(seq, "\n"); + + rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_TNL_A); + seq_printf(seq, "TP_RSS_CONFIG_TNL: %#x\n", rssconf); + seq_printf(seq, " MaskSize: %3d\n", MASKSIZE_G(rssconf)); + seq_printf(seq, " MaskFilter: %3d\n", MASKFILTER_G(rssconf)); + if (CHELSIO_CHIP_VERSION(adapter->params.chip) > CHELSIO_T5) { + seq_printf(seq, " HashAll: %3s\n", + yesno(rssconf & HASHALL_F)); + seq_printf(seq, " HashEth: %3s\n", + yesno(rssconf & HASHETH_F)); + } + seq_printf(seq, " UseWireCh: %3s\n", yesno(rssconf & USEWIRECH_F)); + + seq_puts(seq, "\n"); + + rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_OFD_A); + seq_printf(seq, "TP_RSS_CONFIG_OFD: %#x\n", rssconf); + seq_printf(seq, " MaskSize: %3d\n", MASKSIZE_G(rssconf)); + seq_printf(seq, " RRCplMapEn: %3s\n", yesno(rssconf & + RRCPLMAPEN_F)); + seq_printf(seq, " RRCplQueWidth: %3d\n", RRCPLQUEWIDTH_G(rssconf)); + + seq_puts(seq, "\n"); + + rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_SYN_A); + seq_printf(seq, "TP_RSS_CONFIG_SYN: %#x\n", rssconf); + seq_printf(seq, " MaskSize: %3d\n", MASKSIZE_G(rssconf)); + seq_printf(seq, " UseWireCh: %3s\n", yesno(rssconf & USEWIRECH_F)); + + seq_puts(seq, "\n"); + + rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_VRT_A); + seq_printf(seq, "TP_RSS_CONFIG_VRT: %#x\n", rssconf); + if (CHELSIO_CHIP_VERSION(adapter->params.chip) > CHELSIO_T5) { + seq_printf(seq, " KeyWrAddrX: %3d\n", + KEYWRADDRX_G(rssconf)); + seq_printf(seq, " KeyExtend: %3s\n", + yesno(rssconf & KEYEXTEND_F)); + } + seq_printf(seq, " VfRdRg: %3s\n", yesno(rssconf & VFRDRG_F)); + seq_printf(seq, " VfRdEn: %3s\n", yesno(rssconf & VFRDEN_F)); + seq_printf(seq, " VfPerrEn: %3s\n", yesno(rssconf & VFPERREN_F)); + seq_printf(seq, " KeyPerrEn: %3s\n", yesno(rssconf & KEYPERREN_F)); + seq_printf(seq, " DisVfVlan: %3s\n", yesno(rssconf & + DISABLEVLAN_F)); + seq_printf(seq, " EnUpSwt: %3s\n", yesno(rssconf & ENABLEUP0_F)); + seq_printf(seq, " HashDelay: %3d\n", HASHDELAY_G(rssconf)); + if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) + seq_printf(seq, " VfWrAddr: %3d\n", VFWRADDR_G(rssconf)); + seq_printf(seq, " KeyMode: %s\n", keymode[KEYMODE_G(rssconf)]); + seq_printf(seq, " VfWrEn: %3s\n", yesno(rssconf & VFWREN_F)); + seq_printf(seq, " KeyWrEn: %3s\n", yesno(rssconf & KEYWREN_F)); + seq_printf(seq, " KeyWrAddr: %3d\n", KEYWRADDR_G(rssconf)); + + seq_puts(seq, "\n"); + + rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_CNG_A); + seq_printf(seq, "TP_RSS_CONFIG_CNG: %#x\n", rssconf); + seq_printf(seq, " ChnCount3: %3s\n", yesno(rssconf & CHNCOUNT3_F)); + seq_printf(seq, " ChnCount2: %3s\n", yesno(rssconf & CHNCOUNT2_F)); + seq_printf(seq, " ChnCount1: %3s\n", yesno(rssconf & CHNCOUNT1_F)); + seq_printf(seq, " ChnCount0: %3s\n", yesno(rssconf & CHNCOUNT0_F)); + seq_printf(seq, " ChnUndFlow3: %3s\n", yesno(rssconf & + CHNUNDFLOW3_F)); + seq_printf(seq, " ChnUndFlow2: %3s\n", yesno(rssconf & + CHNUNDFLOW2_F)); + seq_printf(seq, " ChnUndFlow1: %3s\n", yesno(rssconf & + CHNUNDFLOW1_F)); + seq_printf(seq, " ChnUndFlow0: %3s\n", yesno(rssconf & + CHNUNDFLOW0_F)); + seq_printf(seq, " RstChn3: %3s\n", yesno(rssconf & RSTCHN3_F)); + seq_printf(seq, " RstChn2: %3s\n", yesno(rssconf & RSTCHN2_F)); + seq_printf(seq, " RstChn1: %3s\n", yesno(rssconf & RSTCHN1_F)); + seq_printf(seq, " RstChn0: %3s\n", yesno(rssconf & RSTCHN0_F)); + seq_printf(seq, " UpdVld: %3s\n", yesno(rssconf & UPDVLD_F)); + seq_printf(seq, " Xoff: %3s\n", yesno(rssconf & XOFF_F)); + seq_printf(seq, " UpdChn3: %3s\n", yesno(rssconf & UPDCHN3_F)); + seq_printf(seq, " UpdChn2: %3s\n", yesno(rssconf & UPDCHN2_F)); + seq_printf(seq, " UpdChn1: %3s\n", yesno(rssconf & UPDCHN1_F)); + seq_printf(seq, " UpdChn0: %3s\n", yesno(rssconf & UPDCHN0_F)); + seq_printf(seq, " Queue: %3d\n", QUEUE_G(rssconf)); + + return 0; +} + +DEFINE_SIMPLE_DEBUGFS_FILE(rss_config); + +/* RSS Secret Key. + */ + +static int rss_key_show(struct seq_file *seq, void *v) +{ + u32 key[10]; + + t4_read_rss_key(seq->private, key); + seq_printf(seq, "%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x\n", + key[9], key[8], key[7], key[6], key[5], key[4], key[3], + key[2], key[1], key[0]); + return 0; +} + +static int rss_key_open(struct inode *inode, struct file *file) +{ + return single_open(file, rss_key_show, inode->i_private); +} + +static ssize_t rss_key_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + int i, j; + u32 key[10]; + char s[100], *p; + struct adapter *adap = FILE_DATA(file)->i_private; + + if (count > sizeof(s) - 1) + return -EINVAL; + if (copy_from_user(s, buf, count)) + return -EFAULT; + for (i = count; i > 0 && isspace(s[i - 1]); i--) + ; + s[i] = '\0'; + + for (p = s, i = 9; i >= 0; i--) { + key[i] = 0; + for (j = 0; j < 8; j++, p++) { + if (!isxdigit(*p)) + return -EINVAL; + key[i] = (key[i] << 4) | hex2val(*p); + } + } + + t4_write_rss_key(adap, key, -1); + return count; +} + +static const struct file_operations rss_key_debugfs_fops = { + .owner = THIS_MODULE, + .open = rss_key_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = rss_key_write +}; + +/* PF RSS Configuration. + */ + +struct rss_pf_conf { + u32 rss_pf_map; + u32 rss_pf_mask; + u32 rss_pf_config; +}; + +static int rss_pf_config_show(struct seq_file *seq, void *v, int idx) +{ + struct rss_pf_conf *pfconf; + + if (v == SEQ_START_TOKEN) { + /* use the 0th entry to dump the PF Map Index Size */ + pfconf = seq->private + offsetof(struct seq_tab, data); + seq_printf(seq, "PF Map Index Size = %d\n\n", + LKPIDXSIZE_G(pfconf->rss_pf_map)); + + seq_puts(seq, " RSS PF VF Hash Tuple Enable Default\n"); + seq_puts(seq, " Enable IPF Mask Mask IPv6 IPv4 UDP Queue\n"); + seq_puts(seq, " PF Map Chn Prt Map Size Size Four Two Four Two Four Ch1 Ch0\n"); + } else { + #define G_PFnLKPIDX(map, n) \ + (((map) >> PF1LKPIDX_S*(n)) & PF0LKPIDX_M) + #define G_PFnMSKSIZE(mask, n) \ + (((mask) >> PF1MSKSIZE_S*(n)) & PF1MSKSIZE_M) + + pfconf = v; + seq_printf(seq, "%3d %3s %3s %3s %3d %3d %3d %3s %3s %3s %3s %3s %3d %3d\n", + idx, + yesno(pfconf->rss_pf_config & MAPENABLE_F), + yesno(pfconf->rss_pf_config & CHNENABLE_F), + yesno(pfconf->rss_pf_config & PRTENABLE_F), + G_PFnLKPIDX(pfconf->rss_pf_map, idx), + G_PFnMSKSIZE(pfconf->rss_pf_mask, idx), + IVFWIDTH_G(pfconf->rss_pf_config), + yesno(pfconf->rss_pf_config & IP6FOURTUPEN_F), + yesno(pfconf->rss_pf_config & IP6TWOTUPEN_F), + yesno(pfconf->rss_pf_config & IP4FOURTUPEN_F), + yesno(pfconf->rss_pf_config & IP4TWOTUPEN_F), + yesno(pfconf->rss_pf_config & UDPFOURTUPEN_F), + CH1DEFAULTQUEUE_G(pfconf->rss_pf_config), + CH0DEFAULTQUEUE_G(pfconf->rss_pf_config)); + + #undef G_PFnLKPIDX + #undef G_PFnMSKSIZE + } + return 0; +} + +static int rss_pf_config_open(struct inode *inode, struct file *file) +{ + struct adapter *adapter = inode->i_private; + struct seq_tab *p; + u32 rss_pf_map, rss_pf_mask; + struct rss_pf_conf *pfconf; + int pf; + + p = seq_open_tab(file, 8, sizeof(*pfconf), 1, rss_pf_config_show); + if (!p) + return -ENOMEM; + + pfconf = (struct rss_pf_conf *)p->data; + rss_pf_map = t4_read_rss_pf_map(adapter); + rss_pf_mask = t4_read_rss_pf_mask(adapter); + for (pf = 0; pf < 8; pf++) { + pfconf[pf].rss_pf_map = rss_pf_map; + pfconf[pf].rss_pf_mask = rss_pf_mask; + t4_read_rss_pf_config(adapter, pf, &pfconf[pf].rss_pf_config); + } + return 0; +} + +static const struct file_operations rss_pf_config_debugfs_fops = { + .owner = THIS_MODULE, + .open = rss_pf_config_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + +/* VF RSS Configuration. + */ + +struct rss_vf_conf { + u32 rss_vf_vfl; + u32 rss_vf_vfh; +}; + +static int rss_vf_config_show(struct seq_file *seq, void *v, int idx) +{ + if (v == SEQ_START_TOKEN) { + seq_puts(seq, " RSS Hash Tuple Enable\n"); + seq_puts(seq, " Enable IVF Dis Enb IPv6 IPv4 UDP Def Secret Key\n"); + seq_puts(seq, " VF Chn Prt Map VLAN uP Four Two Four Two Four Que Idx Hash\n"); + } else { + struct rss_vf_conf *vfconf = v; + + seq_printf(seq, "%3d %3s %3s %3d %3s %3s %3s %3s %3s %3s %3s %4d %3d %#10x\n", + idx, + yesno(vfconf->rss_vf_vfh & VFCHNEN_F), + yesno(vfconf->rss_vf_vfh & VFPRTEN_F), + VFLKPIDX_G(vfconf->rss_vf_vfh), + yesno(vfconf->rss_vf_vfh & VFVLNEX_F), + yesno(vfconf->rss_vf_vfh & VFUPEN_F), + yesno(vfconf->rss_vf_vfh & VFIP4FOURTUPEN_F), + yesno(vfconf->rss_vf_vfh & VFIP6TWOTUPEN_F), + yesno(vfconf->rss_vf_vfh & VFIP4FOURTUPEN_F), + yesno(vfconf->rss_vf_vfh & VFIP4TWOTUPEN_F), + yesno(vfconf->rss_vf_vfh & ENABLEUDPHASH_F), + DEFAULTQUEUE_G(vfconf->rss_vf_vfh), + KEYINDEX_G(vfconf->rss_vf_vfh), + vfconf->rss_vf_vfl); + } + return 0; +} + +static int rss_vf_config_open(struct inode *inode, struct file *file) +{ + struct adapter *adapter = inode->i_private; + struct seq_tab *p; + struct rss_vf_conf *vfconf; + int vf; + + p = seq_open_tab(file, 128, sizeof(*vfconf), 1, rss_vf_config_show); + if (!p) + return -ENOMEM; + + vfconf = (struct rss_vf_conf *)p->data; + for (vf = 0; vf < 128; vf++) { + t4_read_rss_vf_config(adapter, vf, &vfconf[vf].rss_vf_vfl, + &vfconf[vf].rss_vf_vfh); + } + return 0; +} + +static const struct file_operations rss_vf_config_debugfs_fops = { + .owner = THIS_MODULE, + .open = rss_vf_config_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private +}; + +/** + * ethqset2pinfo - return port_info of an Ethernet Queue Set + * @adap: the adapter + * @qset: Ethernet Queue Set + */ +static inline struct port_info *ethqset2pinfo(struct adapter *adap, int qset) +{ + int pidx; + + for_each_port(adap, pidx) { + struct port_info *pi = adap2pinfo(adap, pidx); + + if (qset >= pi->first_qset && + qset < pi->first_qset + pi->nqsets) + return pi; + } + + /* should never happen! */ + BUG_ON(1); + return NULL; +} + +static int sge_qinfo_show(struct seq_file *seq, void *v) +{ + struct adapter *adap = seq->private; + int eth_entries = DIV_ROUND_UP(adap->sge.ethqsets, 4); + int toe_entries = DIV_ROUND_UP(adap->sge.ofldqsets, 4); + int rdma_entries = DIV_ROUND_UP(adap->sge.rdmaqs, 4); + int ciq_entries = DIV_ROUND_UP(adap->sge.rdmaciqs, 4); + int ctrl_entries = DIV_ROUND_UP(MAX_CTRL_QUEUES, 4); + int i, r = (uintptr_t)v - 1; + int toe_idx = r - eth_entries; + int rdma_idx = toe_idx - toe_entries; + int ciq_idx = rdma_idx - rdma_entries; + int ctrl_idx = ciq_idx - ciq_entries; + int fq_idx = ctrl_idx - ctrl_entries; + + if (r) + seq_putc(seq, '\n'); + +#define S3(fmt_spec, s, v) \ +do { \ + seq_printf(seq, "%-12s", s); \ + for (i = 0; i < n; ++i) \ + seq_printf(seq, " %16" fmt_spec, v); \ + seq_putc(seq, '\n'); \ +} while (0) +#define S(s, v) S3("s", s, v) +#define T(s, v) S3("u", s, tx[i].v) +#define R(s, v) S3("u", s, rx[i].v) + + if (r < eth_entries) { + int base_qset = r * 4; + const struct sge_eth_rxq *rx = &adap->sge.ethrxq[base_qset]; + const struct sge_eth_txq *tx = &adap->sge.ethtxq[base_qset]; + int n = min(4, adap->sge.ethqsets - 4 * r); + + S("QType:", "Ethernet"); + S("Interface:", + rx[i].rspq.netdev ? rx[i].rspq.netdev->name : "N/A"); + T("TxQ ID:", q.cntxt_id); + T("TxQ size:", q.size); + T("TxQ inuse:", q.in_use); + T("TxQ CIDX:", q.cidx); + T("TxQ PIDX:", q.pidx); +#ifdef CONFIG_CHELSIO_T4_DCB + T("DCB Prio:", dcb_prio); + S3("u", "DCB PGID:", + (ethqset2pinfo(adap, base_qset + i)->dcb.pgid >> + 4*(7-tx[i].dcb_prio)) & 0xf); + S3("u", "DCB PFC:", + (ethqset2pinfo(adap, base_qset + i)->dcb.pfcen >> + 1*(7-tx[i].dcb_prio)) & 0x1); +#endif + R("RspQ ID:", rspq.abs_id); + R("RspQ size:", rspq.size); + R("RspQE size:", rspq.iqe_len); + R("RspQ CIDX:", rspq.cidx); + R("RspQ Gen:", rspq.gen); + S3("u", "Intr delay:", qtimer_val(adap, &rx[i].rspq)); + S3("u", "Intr pktcnt:", + adap->sge.counter_val[rx[i].rspq.pktcnt_idx]); + R("FL ID:", fl.cntxt_id); + R("FL size:", fl.size - 8); + R("FL pend:", fl.pend_cred); + R("FL avail:", fl.avail); + R("FL PIDX:", fl.pidx); + R("FL CIDX:", fl.cidx); + } else if (toe_idx < toe_entries) { + const struct sge_ofld_rxq *rx = &adap->sge.ofldrxq[toe_idx * 4]; + const struct sge_ofld_txq *tx = &adap->sge.ofldtxq[toe_idx * 4]; + int n = min(4, adap->sge.ofldqsets - 4 * toe_idx); + + S("QType:", "TOE"); + T("TxQ ID:", q.cntxt_id); + T("TxQ size:", q.size); + T("TxQ inuse:", q.in_use); + T("TxQ CIDX:", q.cidx); + T("TxQ PIDX:", q.pidx); + R("RspQ ID:", rspq.abs_id); + R("RspQ size:", rspq.size); + R("RspQE size:", rspq.iqe_len); + R("RspQ CIDX:", rspq.cidx); + R("RspQ Gen:", rspq.gen); + S3("u", "Intr delay:", qtimer_val(adap, &rx[i].rspq)); + S3("u", "Intr pktcnt:", + adap->sge.counter_val[rx[i].rspq.pktcnt_idx]); + R("FL ID:", fl.cntxt_id); + R("FL size:", fl.size - 8); + R("FL pend:", fl.pend_cred); + R("FL avail:", fl.avail); + R("FL PIDX:", fl.pidx); + R("FL CIDX:", fl.cidx); + } else if (rdma_idx < rdma_entries) { + const struct sge_ofld_rxq *rx = + &adap->sge.rdmarxq[rdma_idx * 4]; + int n = min(4, adap->sge.rdmaqs - 4 * rdma_idx); + + S("QType:", "RDMA-CPL"); + R("RspQ ID:", rspq.abs_id); + R("RspQ size:", rspq.size); + R("RspQE size:", rspq.iqe_len); + R("RspQ CIDX:", rspq.cidx); + R("RspQ Gen:", rspq.gen); + S3("u", "Intr delay:", qtimer_val(adap, &rx[i].rspq)); + S3("u", "Intr pktcnt:", + adap->sge.counter_val[rx[i].rspq.pktcnt_idx]); + R("FL ID:", fl.cntxt_id); + R("FL size:", fl.size - 8); + R("FL pend:", fl.pend_cred); + R("FL avail:", fl.avail); + R("FL PIDX:", fl.pidx); + R("FL CIDX:", fl.cidx); + } else if (ciq_idx < ciq_entries) { + const struct sge_ofld_rxq *rx = &adap->sge.rdmaciq[ciq_idx * 4]; + int n = min(4, adap->sge.rdmaciqs - 4 * ciq_idx); + + S("QType:", "RDMA-CIQ"); + R("RspQ ID:", rspq.abs_id); + R("RspQ size:", rspq.size); + R("RspQE size:", rspq.iqe_len); + R("RspQ CIDX:", rspq.cidx); + R("RspQ Gen:", rspq.gen); + S3("u", "Intr delay:", qtimer_val(adap, &rx[i].rspq)); + S3("u", "Intr pktcnt:", + adap->sge.counter_val[rx[i].rspq.pktcnt_idx]); + } else if (ctrl_idx < ctrl_entries) { + const struct sge_ctrl_txq *tx = &adap->sge.ctrlq[ctrl_idx * 4]; + int n = min(4, adap->params.nports - 4 * ctrl_idx); + + S("QType:", "Control"); + T("TxQ ID:", q.cntxt_id); + T("TxQ size:", q.size); + T("TxQ inuse:", q.in_use); + T("TxQ CIDX:", q.cidx); + T("TxQ PIDX:", q.pidx); + } else if (fq_idx == 0) { + const struct sge_rspq *evtq = &adap->sge.fw_evtq; + + seq_printf(seq, "%-12s %16s\n", "QType:", "FW event queue"); + seq_printf(seq, "%-12s %16u\n", "RspQ ID:", evtq->abs_id); + seq_printf(seq, "%-12s %16u\n", "RspQ size:", evtq->size); + seq_printf(seq, "%-12s %16u\n", "RspQE size:", evtq->iqe_len); + seq_printf(seq, "%-12s %16u\n", "RspQ CIDX:", evtq->cidx); + seq_printf(seq, "%-12s %16u\n", "RspQ Gen:", evtq->gen); + seq_printf(seq, "%-12s %16u\n", "Intr delay:", + qtimer_val(adap, evtq)); + seq_printf(seq, "%-12s %16u\n", "Intr pktcnt:", + adap->sge.counter_val[evtq->pktcnt_idx]); + } +#undef R +#undef T +#undef S +#undef S3 +return 0; +} + +static int sge_queue_entries(const struct adapter *adap) +{ + return DIV_ROUND_UP(adap->sge.ethqsets, 4) + + DIV_ROUND_UP(adap->sge.ofldqsets, 4) + + DIV_ROUND_UP(adap->sge.rdmaqs, 4) + + DIV_ROUND_UP(adap->sge.rdmaciqs, 4) + + DIV_ROUND_UP(MAX_CTRL_QUEUES, 4) + 1; +} + +static void *sge_queue_start(struct seq_file *seq, loff_t *pos) +{ + int entries = sge_queue_entries(seq->private); + + return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL; +} + +static void sge_queue_stop(struct seq_file *seq, void *v) +{ +} + +static void *sge_queue_next(struct seq_file *seq, void *v, loff_t *pos) +{ + int entries = sge_queue_entries(seq->private); + + ++*pos; + return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL; +} + +static const struct seq_operations sge_qinfo_seq_ops = { + .start = sge_queue_start, + .next = sge_queue_next, + .stop = sge_queue_stop, + .show = sge_qinfo_show +}; + +static int sge_qinfo_open(struct inode *inode, struct file *file) +{ + int res = seq_open(file, &sge_qinfo_seq_ops); + + if (!res) { + struct seq_file *seq = file->private_data; + + seq->private = inode->i_private; + } + return res; +} + +static const struct file_operations sge_qinfo_debugfs_fops = { + .owner = THIS_MODULE, + .open = sge_qinfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +int mem_open(struct inode *inode, struct file *file) +{ + unsigned int mem; + struct adapter *adap; + + file->private_data = inode->i_private; + + mem = (uintptr_t)file->private_data & 0x3; + adap = file->private_data - mem; + + (void)t4_fwcache(adap, FW_PARAM_DEV_FWCACHE_FLUSH); + + return 0; +} + static ssize_t mem_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -80,7 +1934,6 @@ static ssize_t mem_read(struct file *file, char __user *buf, size_t count, *ppos = pos + count; return count; } - static const struct file_operations mem_debugfs_fops = { .owner = THIS_MODULE, .open = simple_open, @@ -88,6 +1941,12 @@ static const struct file_operations mem_debugfs_fops = { .llseek = default_llseek, }; +static void set_debugfs_file_size(struct dentry *de, loff_t size) +{ + if (!IS_ERR(de) && de->d_inode) + de->d_inode->i_size = size; +} + static void add_debugfs_mem(struct adapter *adap, const char *name, unsigned int idx, unsigned int size_mb) { @@ -119,14 +1978,65 @@ int t4_setup_debugfs(struct adapter *adap) { int i; u32 size; + struct dentry *de; static struct t4_debugfs_entry t4_debugfs_files[] = { + { "cim_la", &cim_la_fops, S_IRUSR, 0 }, + { "cim_qcfg", &cim_qcfg_fops, S_IRUSR, 0 }, + { "clk", &clk_debugfs_fops, S_IRUSR, 0 }, + { "devlog", &devlog_fops, S_IRUSR, 0 }, + { "mbox0", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 0 }, + { "mbox1", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 1 }, + { "mbox2", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 2 }, + { "mbox3", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 3 }, + { "mbox4", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 4 }, + { "mbox5", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 5 }, + { "mbox6", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 6 }, + { "mbox7", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 7 }, { "l2t", &t4_l2t_fops, S_IRUSR, 0}, + { "mps_tcam", &mps_tcam_debugfs_fops, S_IRUSR, 0 }, + { "rss", &rss_debugfs_fops, S_IRUSR, 0 }, + { "rss_config", &rss_config_debugfs_fops, S_IRUSR, 0 }, + { "rss_key", &rss_key_debugfs_fops, S_IRUSR, 0 }, + { "rss_pf_config", &rss_pf_config_debugfs_fops, S_IRUSR, 0 }, + { "rss_vf_config", &rss_vf_config_debugfs_fops, S_IRUSR, 0 }, + { "sge_qinfo", &sge_qinfo_debugfs_fops, S_IRUSR, 0 }, + { "ibq_tp0", &cim_ibq_fops, S_IRUSR, 0 }, + { "ibq_tp1", &cim_ibq_fops, S_IRUSR, 1 }, + { "ibq_ulp", &cim_ibq_fops, S_IRUSR, 2 }, + { "ibq_sge0", &cim_ibq_fops, S_IRUSR, 3 }, + { "ibq_sge1", &cim_ibq_fops, S_IRUSR, 4 }, + { "ibq_ncsi", &cim_ibq_fops, S_IRUSR, 5 }, + { "obq_ulp0", &cim_obq_fops, S_IRUSR, 0 }, + { "obq_ulp1", &cim_obq_fops, S_IRUSR, 1 }, + { "obq_ulp2", &cim_obq_fops, S_IRUSR, 2 }, + { "obq_ulp3", &cim_obq_fops, S_IRUSR, 3 }, + { "obq_sge", &cim_obq_fops, S_IRUSR, 4 }, + { "obq_ncsi", &cim_obq_fops, S_IRUSR, 5 }, + { "tp_la", &tp_la_fops, S_IRUSR, 0 }, + { "ulprx_la", &ulprx_la_fops, S_IRUSR, 0 }, + { "sensors", &sensors_debugfs_fops, S_IRUSR, 0 }, + { "pm_stats", &pm_stats_debugfs_fops, S_IRUSR, 0 }, + { "cctrl", &cctrl_tbl_debugfs_fops, S_IRUSR, 0 }, +#if IS_ENABLED(CONFIG_IPV6) + { "clip_tbl", &clip_tbl_debugfs_fops, S_IRUSR, 0 }, +#endif + }; + + /* Debug FS nodes common to all T5 and later adapters. + */ + static struct t4_debugfs_entry t5_debugfs_files[] = { + { "obq_sge_rx_q0", &cim_obq_fops, S_IRUSR, 6 }, + { "obq_sge_rx_q1", &cim_obq_fops, S_IRUSR, 7 }, }; add_debugfs_files(adap, t4_debugfs_files, ARRAY_SIZE(t4_debugfs_files)); + if (!is_t4(adap->params.chip)) + add_debugfs_files(adap, + t5_debugfs_files, + ARRAY_SIZE(t5_debugfs_files)); i = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A); if (i & EDRAM0_ENABLE_F) { @@ -154,5 +2064,10 @@ int t4_setup_debugfs(struct adapter *adap) EXT_MEM1_SIZE_G(size)); } } + + de = debugfs_create_file("flash", S_IRUSR, adap->debugfs_root, adap, + &flash_debugfs_fops); + set_debugfs_file_size(de, adap->params.sf_size); + return 0; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h index a3d8867efd3d..b63cfee2d963 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h @@ -37,6 +37,21 @@ #include +#define FILE_DATA(_file) ((_file)->f_path.dentry->d_inode) + +#define DEFINE_SIMPLE_DEBUGFS_FILE(name) \ +static int name##_open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, name##_show, inode->i_private); \ +} \ +static const struct file_operations name##_debugfs_fops = { \ + .owner = THIS_MODULE, \ + .open = name##_open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release \ +} + struct t4_debugfs_entry { const char *name; const struct file_operations *ops; @@ -44,9 +59,27 @@ struct t4_debugfs_entry { unsigned char data; }; +struct seq_tab { + int (*show)(struct seq_file *seq, void *v, int idx); + unsigned int rows; /* # of entries */ + unsigned char width; /* size in bytes of each entry */ + unsigned char skip_first; /* whether the first line is a header */ + char data[0]; /* the table data */ +}; + +static inline unsigned int hex2val(char c) +{ + return isdigit(c) ? c - '0' : tolower(c) - 'a' + 10; +} + +struct seq_tab *seq_open_tab(struct file *f, unsigned int rows, + unsigned int width, unsigned int have_header, + int (*show)(struct seq_file *seq, void *v, int i)); + int t4_setup_debugfs(struct adapter *adap); void add_debugfs_files(struct adapter *adap, struct t4_debugfs_entry *files, unsigned int nfiles); +int mem_open(struct inode *inode, struct file *file); #endif diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index ccf3436024bc..a22cf932ca35 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -62,14 +62,18 @@ #include #include #include +#include #include #include "cxgb4.h" #include "t4_regs.h" +#include "t4_values.h" #include "t4_msg.h" #include "t4fw_api.h" +#include "t4fw_version.h" #include "cxgb4_dcb.h" #include "cxgb4_debugfs.h" +#include "clip_tbl.h" #include "l2t.h" #ifdef DRV_VERSION @@ -78,99 +82,6 @@ #define DRV_VERSION "2.0.0-ko" #define DRV_DESC "Chelsio T4/T5 Network Driver" -/* - * Max interrupt hold-off timer value in us. Queues fall back to this value - * under extreme memory pressure so it's largish to give the system time to - * recover. - */ -#define MAX_SGE_TIMERVAL 200U - -enum { - /* - * Physical Function provisioning constants. - */ - PFRES_NVI = 4, /* # of Virtual Interfaces */ - PFRES_NETHCTRL = 128, /* # of EQs used for ETH or CTRL Qs */ - PFRES_NIQFLINT = 128, /* # of ingress Qs/w Free List(s)/intr - */ - PFRES_NEQ = 256, /* # of egress queues */ - PFRES_NIQ = 0, /* # of ingress queues */ - PFRES_TC = 0, /* PCI-E traffic class */ - PFRES_NEXACTF = 128, /* # of exact MPS filters */ - - PFRES_R_CAPS = FW_CMD_CAP_PF, - PFRES_WX_CAPS = FW_CMD_CAP_PF, - -#ifdef CONFIG_PCI_IOV - /* - * Virtual Function provisioning constants. We need two extra Ingress - * Queues with Interrupt capability to serve as the VF's Firmware - * Event Queue and Forwarded Interrupt Queue (when using MSI mode) -- - * neither will have Free Lists associated with them). For each - * Ethernet/Control Egress Queue and for each Free List, we need an - * Egress Context. - */ - VFRES_NPORTS = 1, /* # of "ports" per VF */ - VFRES_NQSETS = 2, /* # of "Queue Sets" per VF */ - - VFRES_NVI = VFRES_NPORTS, /* # of Virtual Interfaces */ - VFRES_NETHCTRL = VFRES_NQSETS, /* # of EQs used for ETH or CTRL Qs */ - VFRES_NIQFLINT = VFRES_NQSETS+2,/* # of ingress Qs/w Free List(s)/intr */ - VFRES_NEQ = VFRES_NQSETS*2, /* # of egress queues */ - VFRES_NIQ = 0, /* # of non-fl/int ingress queues */ - VFRES_TC = 0, /* PCI-E traffic class */ - VFRES_NEXACTF = 16, /* # of exact MPS filters */ - - VFRES_R_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF|FW_CMD_CAP_PORT, - VFRES_WX_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF, -#endif -}; - -/* - * Provide a Port Access Rights Mask for the specified PF/VF. This is very - * static and likely not to be useful in the long run. We really need to - * implement some form of persistent configuration which the firmware - * controls. - */ -static unsigned int pfvfres_pmask(struct adapter *adapter, - unsigned int pf, unsigned int vf) -{ - unsigned int portn, portvec; - - /* - * Give PF's access to all of the ports. - */ - if (vf == 0) - return FW_PFVF_CMD_PMASK_M; - - /* - * For VFs, we'll assign them access to the ports based purely on the - * PF. We assign active ports in order, wrapping around if there are - * fewer active ports than PFs: e.g. active port[pf % nports]. - * Unfortunately the adapter's port_info structs haven't been - * initialized yet so we have to compute this. - */ - if (adapter->params.nports == 0) - return 0; - - portn = pf % adapter->params.nports; - portvec = adapter->params.portvec; - for (;;) { - /* - * Isolate the lowest set bit in the port vector. If we're at - * the port number that we want, return that as the pmask. - * otherwise mask that bit out of the port vector and - * decrement our port number ... - */ - unsigned int pmask = portvec ^ (portvec & (portvec-1)); - if (portn == 0) - return pmask; - portn--; - portvec &= ~pmask; - } - /*NOTREACHED*/ -} - enum { MAX_TXQ_ENTRIES = 16384, MAX_CTRL_TXQ_ENTRIES = 1024, @@ -263,7 +174,8 @@ MODULE_PARM_DESC(force_init, "Forcibly become Master PF and initialize adapter") static uint force_old_init; module_param(force_old_init, uint, 0644); -MODULE_PARM_DESC(force_old_init, "Force old initialization sequence"); +MODULE_PARM_DESC(force_old_init, "Force old initialization sequence, deprecated" + " parameter"); static int dflt_msg_enable = DFLT_MSG_ENABLE; @@ -292,13 +204,14 @@ static unsigned int intr_holdoff[SGE_NTIMERS - 1] = { 5, 10, 20, 50, 100 }; module_param_array(intr_holdoff, uint, NULL, 0644); MODULE_PARM_DESC(intr_holdoff, "values for queue interrupt hold-off timers " - "0..4 in microseconds"); + "0..4 in microseconds, deprecated parameter"); static unsigned int intr_cnt[SGE_NCOUNTERS - 1] = { 4, 8, 16 }; module_param_array(intr_cnt, uint, NULL, 0644); MODULE_PARM_DESC(intr_cnt, - "thresholds 1..3 for queue interrupt packet counters"); + "thresholds 1..3 for queue interrupt packet counters, " + "deprecated parameter"); /* * Normally we tell the chip to deliver Ingress Packets into our DMA buffers @@ -318,7 +231,8 @@ static bool vf_acls; #ifdef CONFIG_PCI_IOV module_param(vf_acls, bool, 0644); -MODULE_PARM_DESC(vf_acls, "if set enable virtualization L2 ACL enforcement"); +MODULE_PARM_DESC(vf_acls, "if set enable virtualization L2 ACL enforcement, " + "deprecated parameter"); /* Configure the number of PCI-E Virtual Function which are to be instantiated * on SR-IOV Capable Physical Functions. @@ -340,32 +254,11 @@ module_param(select_queue, int, 0644); MODULE_PARM_DESC(select_queue, "Select between kernel provided method of selecting or driver method of selecting TX queue. Default is kernel method."); -/* - * The filter TCAM has a fixed portion and a variable portion. The fixed - * portion can match on source/destination IP IPv4/IPv6 addresses and TCP/UDP - * ports. The variable portion is 36 bits which can include things like Exact - * Match MAC Index (9 bits), Ether Type (16 bits), IP Protocol (8 bits), - * [Inner] VLAN Tag (17 bits), etc. which, if all were somehow selected, would - * far exceed the 36-bit budget for this "compressed" header portion of the - * filter. Thus, we have a scarce resource which must be carefully managed. - * - * By default we set this up to mostly match the set of filter matching - * capabilities of T3 but with accommodations for some of T4's more - * interesting features: - * - * { IP Fragment (1), MPS Match Type (3), IP Protocol (8), - * [Inner] VLAN (17), Port (3), FCoE (1) } - */ -enum { - TP_VLAN_PRI_MAP_DEFAULT = HW_TPL_FR_MT_PR_IV_P_FC, - TP_VLAN_PRI_MAP_FIRST = FCOE_SHIFT, - TP_VLAN_PRI_MAP_LAST = FRAGMENTATION_SHIFT, -}; - -static unsigned int tp_vlan_pri_map = TP_VLAN_PRI_MAP_DEFAULT; +static unsigned int tp_vlan_pri_map = HW_TPL_FR_MT_PR_IV_P_FC; module_param(tp_vlan_pri_map, uint, 0644); -MODULE_PARM_DESC(tp_vlan_pri_map, "global compressed filter configuration"); +MODULE_PARM_DESC(tp_vlan_pri_map, "global compressed filter configuration, " + "deprecated parameter"); static struct dentry *cxgb4_debugfs_root; @@ -671,7 +564,7 @@ static void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl) if (idx >= adap->tids.ftid_base && nidx < (adap->tids.nftids + adap->tids.nsftids)) { idx = nidx; - ret = GET_TCB_COOKIE(rpl->cookie); + ret = TCB_COOKIE_G(rpl->cookie); f = &adap->tids.ftid_tab[idx]; if (ret == FW_FILTER_WR_FLT_DELETED) { @@ -723,7 +616,7 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp, if (likely(opcode == CPL_SGE_EGR_UPDATE)) { const struct cpl_sge_egr_update *p = (void *)rsp; - unsigned int qid = EGR_QID(ntohl(p->opcode_qid)); + unsigned int qid = EGR_QID_G(ntohl(p->opcode_qid)); struct sge_txq *txq; txq = q->adap->sge.egr_map[qid - q->adap->sge.egr_start]; @@ -833,11 +726,11 @@ static void disable_msi(struct adapter *adapter) static irqreturn_t t4_nondata_intr(int irq, void *cookie) { struct adapter *adap = cookie; + u32 v = t4_read_reg(adap, MYPF_REG(PL_PF_INT_CAUSE_A)); - u32 v = t4_read_reg(adap, MYPF_REG(PL_PF_INT_CAUSE)); - if (v & PFSW) { + if (v & PFSW_F) { adap->swintr = 1; - t4_write_reg(adap, MYPF_REG(PL_PF_INT_CAUSE), v); + t4_write_reg(adap, MYPF_REG(PL_PF_INT_CAUSE_A), v); } t4_slow_intr_handler(adap); return IRQ_HANDLED; @@ -1030,8 +923,14 @@ static void quiesce_rx(struct adapter *adap) for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) { struct sge_rspq *q = adap->sge.ingr_map[i]; - if (q && q->handler) + if (q && q->handler) { napi_disable(&q->napi); + local_bh_disable(); + while (!cxgb_poll_lock_napi(q)) + mdelay(1); + local_bh_enable(); + } + } } @@ -1047,12 +946,14 @@ static void enable_rx(struct adapter *adap) if (!q) continue; - if (q->handler) + if (q->handler) { + cxgb_busy_poll_init_lock(q); napi_enable(&q->napi); + } /* 0-increment GTS to start the timer and enable interrupts */ - t4_write_reg(adap, MYPF_REG(SGE_PF_GTS), - SEINTARM(q->intr_params) | - INGRESSQID(q->cntxt_id)); + t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A), + SEINTARM_V(q->intr_params) | + INGRESSQID_V(q->cntxt_id)); } } @@ -1176,10 +1077,10 @@ freeout: t4_free_sge_resources(adap); } t4_write_reg(adap, is_t4(adap->params.chip) ? - MPS_TRC_RSS_CONTROL : - MPS_T5_TRC_RSS_CONTROL, - RSSCONTROL(netdev2pinfo(adap->port[0])->tx_chan) | - QUEUENUMBER(s->ethrxq[0].rspq.abs_id)); + MPS_TRC_RSS_CONTROL_A : + MPS_T5_TRC_RSS_CONTROL_A, + RSSCONTROL_V(netdev2pinfo(adap->port[0])->tx_chan) | + QUEUENUMBER_V(s->ethrxq[0].rspq.abs_id)); return 0; } @@ -1518,6 +1419,7 @@ static int get_eeprom_len(struct net_device *dev) static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct adapter *adapter = netdev2adap(dev); + u32 exprom_vers; strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); strlcpy(info->version, DRV_VERSION, sizeof(info->version)); @@ -1535,6 +1437,14 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers), FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers), FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers)); + + if (!t4_get_exprom_version(adapter, &exprom_vers)) + snprintf(info->erom_version, sizeof(info->erom_version), + "%u.%u.%u.%u", + FW_HDR_FW_VER_MAJOR_G(exprom_vers), + FW_HDR_FW_VER_MINOR_G(exprom_vers), + FW_HDR_FW_VER_MICRO_G(exprom_vers), + FW_HDR_FW_VER_BUILD_G(exprom_vers)); } static void get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -1589,9 +1499,9 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats, collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data); data += sizeof(struct queue_port_stats) / sizeof(u64); if (!is_t4(adapter->params.chip)) { - t4_write_reg(adapter, SGE_STAT_CFG, STATSOURCE_T5(7)); - val1 = t4_read_reg(adapter, SGE_STAT_TOTAL); - val2 = t4_read_reg(adapter, SGE_STAT_MATCH); + t4_write_reg(adapter, SGE_STAT_CFG_A, STATSOURCE_T5_V(7)); + val1 = t4_read_reg(adapter, SGE_STAT_TOTAL_A); + val2 = t4_read_reg(adapter, SGE_STAT_MATCH_A); *data = val1 - val2; data++; *data = val2; @@ -2608,8 +2518,8 @@ static int closest_thres(const struct sge *s, int thres) /* * Return a queue's interrupt hold-off time in us. 0 means no timer. */ -static unsigned int qtimer_val(const struct adapter *adap, - const struct sge_rspq *q) +unsigned int qtimer_val(const struct adapter *adap, + const struct sge_rspq *q) { unsigned int idx = q->intr_params >> 1; @@ -3346,40 +3256,6 @@ static int tid_init(struct tid_info *t) return 0; } -int cxgb4_clip_get(const struct net_device *dev, - const struct in6_addr *lip) -{ - struct adapter *adap; - struct fw_clip_cmd c; - - adap = netdev2adap(dev); - memset(&c, 0, sizeof(c)); - c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) | - FW_CMD_REQUEST_F | FW_CMD_WRITE_F); - c.alloc_to_len16 = htonl(FW_CLIP_CMD_ALLOC_F | FW_LEN16(c)); - c.ip_hi = *(__be64 *)(lip->s6_addr); - c.ip_lo = *(__be64 *)(lip->s6_addr + 8); - return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false); -} -EXPORT_SYMBOL(cxgb4_clip_get); - -int cxgb4_clip_release(const struct net_device *dev, - const struct in6_addr *lip) -{ - struct adapter *adap; - struct fw_clip_cmd c; - - adap = netdev2adap(dev); - memset(&c, 0, sizeof(c)); - c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) | - FW_CMD_REQUEST_F | FW_CMD_READ_F); - c.alloc_to_len16 = htonl(FW_CLIP_CMD_FREE_F | FW_LEN16(c)); - c.ip_hi = *(__be64 *)(lip->s6_addr); - c.ip_lo = *(__be64 *)(lip->s6_addr + 8); - return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false); -} -EXPORT_SYMBOL(cxgb4_clip_release); - /** * cxgb4_create_server - create an IP server * @dev: the device @@ -3415,8 +3291,8 @@ int cxgb4_create_server(const struct net_device *dev, unsigned int stid, req->peer_ip = htonl(0); chan = rxq_to_chan(&adap->sge, queue); req->opt0 = cpu_to_be64(TX_CHAN_V(chan)); - req->opt1 = cpu_to_be64(CONN_POLICY_ASK | - SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue)); + req->opt1 = cpu_to_be64(CONN_POLICY_V(CPL_CONN_POLICY_ASK) | + SYN_RSS_ENABLE_F | SYN_RSS_QUEUE_V(queue)); ret = t4_mgmt_tx(adap, skb); return net_xmit_eval(ret); } @@ -3458,8 +3334,8 @@ int cxgb4_create_server6(const struct net_device *dev, unsigned int stid, req->peer_ip_lo = cpu_to_be64(0); chan = rxq_to_chan(&adap->sge, queue); req->opt0 = cpu_to_be64(TX_CHAN_V(chan)); - req->opt1 = cpu_to_be64(CONN_POLICY_ASK | - SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue)); + req->opt1 = cpu_to_be64(CONN_POLICY_V(CPL_CONN_POLICY_ASK) | + SYN_RSS_ENABLE_F | SYN_RSS_QUEUE_V(queue)); ret = t4_mgmt_tx(adap, skb); return net_xmit_eval(ret); } @@ -3482,8 +3358,8 @@ int cxgb4_remove_server(const struct net_device *dev, unsigned int stid, req = (struct cpl_close_listsvr_req *)__skb_put(skb, sizeof(*req)); INIT_TP_WR(req, 0); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, stid)); - req->reply_ctrl = htons(NO_REPLY(0) | (ipv6 ? LISTSVR_IPV6(1) : - LISTSVR_IPV6(0)) | QUEUENO(queue)); + req->reply_ctrl = htons(NO_REPLY_V(0) | (ipv6 ? LISTSVR_IPV6_V(1) : + LISTSVR_IPV6_V(0)) | QUEUENO_V(queue)); ret = t4_mgmt_tx(adap, skb); return net_xmit_eval(ret); } @@ -3600,14 +3476,14 @@ unsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo) struct adapter *adap = netdev2adap(dev); u32 v1, v2, lp_count, hp_count; - v1 = t4_read_reg(adap, A_SGE_DBFIFO_STATUS); - v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2); + v1 = t4_read_reg(adap, SGE_DBFIFO_STATUS_A); + v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2_A); if (is_t4(adap->params.chip)) { - lp_count = G_LP_COUNT(v1); - hp_count = G_HP_COUNT(v1); + lp_count = LP_COUNT_G(v1); + hp_count = HP_COUNT_G(v1); } else { - lp_count = G_LP_COUNT_T5(v1); - hp_count = G_HP_COUNT_T5(v2); + lp_count = LP_COUNT_T5_G(v1); + hp_count = HP_COUNT_T5_G(v2); } return lpfifo ? lp_count : hp_count; } @@ -3653,10 +3529,10 @@ void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask, { struct adapter *adap = netdev2adap(dev); - t4_write_reg(adap, ULP_RX_ISCSI_TAGMASK, tag_mask); - t4_write_reg(adap, ULP_RX_ISCSI_PSZ, HPZ0(pgsz_order[0]) | - HPZ1(pgsz_order[1]) | HPZ2(pgsz_order[2]) | - HPZ3(pgsz_order[3])); + t4_write_reg(adap, ULP_RX_ISCSI_TAGMASK_A, tag_mask); + t4_write_reg(adap, ULP_RX_ISCSI_PSZ_A, HPZ0_V(pgsz_order[0]) | + HPZ1_V(pgsz_order[1]) | HPZ2_V(pgsz_order[2]) | + HPZ3_V(pgsz_order[3])); } EXPORT_SYMBOL(cxgb4_iscsi_init); @@ -3666,14 +3542,14 @@ int cxgb4_flush_eq_cache(struct net_device *dev) int ret; ret = t4_fwaddrspace_write(adap, adap->mbox, - 0xe1000000 + A_SGE_CTXT_CMD, 0x20000000); + 0xe1000000 + SGE_CTXT_CMD_A, 0x20000000); return ret; } EXPORT_SYMBOL(cxgb4_flush_eq_cache); static int read_eq_indices(struct adapter *adap, u16 qid, u16 *pidx, u16 *cidx) { - u32 addr = t4_read_reg(adap, A_SGE_DBQ_CTXT_BADDR) + 24 * qid + 8; + u32 addr = t4_read_reg(adap, SGE_DBQ_CTXT_BADDR_A) + 24 * qid + 8; __be64 indices; int ret; @@ -3702,14 +3578,20 @@ int cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx, if (pidx != hw_pidx) { u16 delta; + u32 val; if (pidx >= hw_pidx) delta = pidx - hw_pidx; else delta = size - hw_pidx + pidx; + + if (is_t4(adap->params.chip)) + val = PIDX_V(delta); + else + val = PIDX_T5_V(delta); wmb(); - t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), - QID(qid) | PIDX(delta)); + t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), + QID_V(qid) | val); } out: return ret; @@ -3721,8 +3603,8 @@ void cxgb4_disable_db_coalescing(struct net_device *dev) struct adapter *adap; adap = netdev2adap(dev); - t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_NOCOALESCE, - F_NOCOALESCE); + t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, NOCOALESCE_F, + NOCOALESCE_F); } EXPORT_SYMBOL(cxgb4_disable_db_coalescing); @@ -3731,7 +3613,7 @@ void cxgb4_enable_db_coalescing(struct net_device *dev) struct adapter *adap; adap = netdev2adap(dev); - t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_NOCOALESCE, 0); + t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, NOCOALESCE_F, 0); } EXPORT_SYMBOL(cxgb4_enable_db_coalescing); @@ -3809,8 +3691,8 @@ u64 cxgb4_read_sge_timestamp(struct net_device *dev) struct adapter *adap; adap = netdev2adap(dev); - lo = t4_read_reg(adap, SGE_TIMESTAMP_LO); - hi = GET_TSVAL(t4_read_reg(adap, SGE_TIMESTAMP_HI)); + lo = t4_read_reg(adap, SGE_TIMESTAMP_LO_A); + hi = TSVAL_G(t4_read_reg(adap, SGE_TIMESTAMP_HI_A)); return ((u64)hi << 32) | (u64)lo; } @@ -3870,14 +3752,14 @@ static void drain_db_fifo(struct adapter *adap, int usecs) u32 v1, v2, lp_count, hp_count; do { - v1 = t4_read_reg(adap, A_SGE_DBFIFO_STATUS); - v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2); + v1 = t4_read_reg(adap, SGE_DBFIFO_STATUS_A); + v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2_A); if (is_t4(adap->params.chip)) { - lp_count = G_LP_COUNT(v1); - hp_count = G_HP_COUNT(v1); + lp_count = LP_COUNT_G(v1); + hp_count = HP_COUNT_G(v1); } else { - lp_count = G_LP_COUNT_T5(v1); - hp_count = G_HP_COUNT_T5(v2); + lp_count = LP_COUNT_T5_G(v1); + hp_count = HP_COUNT_T5_G(v2); } if (lp_count == 0 && hp_count == 0) @@ -3904,8 +3786,8 @@ static void enable_txq_db(struct adapter *adap, struct sge_txq *q) * are committed before we tell HW about them. */ wmb(); - t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), - QID(q->cntxt_id) | PIDX(q->db_pidx_inc)); + t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), + QID_V(q->cntxt_id) | PIDX_V(q->db_pidx_inc)); q->db_pidx_inc = 0; } q->db_disabled = 0; @@ -3952,9 +3834,9 @@ static void process_db_full(struct work_struct *work) drain_db_fifo(adap, dbfifo_drain_delay); enable_dbs(adap); notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY); - t4_set_reg_field(adap, SGE_INT_ENABLE3, - DBFIFO_HP_INT | DBFIFO_LP_INT, - DBFIFO_HP_INT | DBFIFO_LP_INT); + t4_set_reg_field(adap, SGE_INT_ENABLE3_A, + DBFIFO_HP_INT_F | DBFIFO_LP_INT_F, + DBFIFO_HP_INT_F | DBFIFO_LP_INT_F); } static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q) @@ -3968,14 +3850,20 @@ static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q) goto out; if (q->db_pidx != hw_pidx) { u16 delta; + u32 val; if (q->db_pidx >= hw_pidx) delta = q->db_pidx - hw_pidx; else delta = q->size - hw_pidx + q->db_pidx; + + if (is_t4(adap->params.chip)) + val = PIDX_V(delta); + else + val = PIDX_T5_V(delta); wmb(); - t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), - QID(q->cntxt_id) | PIDX(delta)); + t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), + QID_V(q->cntxt_id) | val); } out: q->db_disabled = 0; @@ -4024,14 +3912,14 @@ static void process_db_drop(struct work_struct *work) dev_err(adap->pdev_dev, "doorbell drop recovery: " "qid=%d, pidx_inc=%d\n", qid, pidx_inc); else - writel(PIDX_T5(pidx_inc) | QID(bar2_qid), + writel(PIDX_T5_V(pidx_inc) | QID_V(bar2_qid), adap->bar2 + bar2_qoffset + SGE_UDB_KDOORBELL); /* Re-enable BAR2 WC */ t4_set_reg_field(adap, 0x10b0, 1<<15, 1<<15); } - t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_DROPPED_DB, 0); + t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, DROPPED_DB_F, 0); } void t4_db_full(struct adapter *adap) @@ -4039,8 +3927,8 @@ void t4_db_full(struct adapter *adap) if (is_t4(adap->params.chip)) { disable_dbs(adap); notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL); - t4_set_reg_field(adap, SGE_INT_ENABLE3, - DBFIFO_HP_INT | DBFIFO_LP_INT, 0); + t4_set_reg_field(adap, SGE_INT_ENABLE3_A, + DBFIFO_HP_INT_F | DBFIFO_LP_INT_F, 0); queue_work(adap->workq, &adap->db_full_task); } } @@ -4081,7 +3969,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld) lli.nports = adap->params.nports; lli.wr_cred = adap->params.ofldq_wr_cred; lli.adapter_type = adap->params.chip; - lli.iscsi_iolen = MAXRXDATA_GET(t4_read_reg(adap, TP_PARA_REG2)); + lli.iscsi_iolen = MAXRXDATA_G(t4_read_reg(adap, TP_PARA_REG2_A)); lli.cclk_ps = 1000000000 / adap->params.vpd.cclk; lli.udb_density = 1 << adap->params.sge.eq_qpp; lli.ucq_density = 1 << adap->params.sge.iq_qpp; @@ -4089,8 +3977,8 @@ static void uld_attach(struct adapter *adap, unsigned int uld) /* MODQ_REQ_MAP sets queues 0-3 to chan 0-3 */ for (i = 0; i < NCHAN; i++) lli.tx_modq[i] = i; - lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS); - lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL); + lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS_A); + lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL_A); lli.fw_vers = adap->params.fw_vers; lli.dbfifo_int_thresh = dbfifo_int_thresh; lli.sge_ingpadboundary = adap->sge.fl_align; @@ -4220,148 +4108,61 @@ int cxgb4_unregister_uld(enum cxgb4_uld type) } EXPORT_SYMBOL(cxgb4_unregister_uld); -/* Check if netdev on which event is occured belongs to us or not. Return - * success (true) if it belongs otherwise failure (false). - * Called with rcu_read_lock() held. - */ #if IS_ENABLED(CONFIG_IPV6) -static bool cxgb4_netdev(const struct net_device *netdev) +static int cxgb4_inet6addr_handler(struct notifier_block *this, + unsigned long event, void *data) { + struct inet6_ifaddr *ifa = data; + struct net_device *event_dev = ifa->idev->dev; + const struct device *parent = NULL; +#if IS_ENABLED(CONFIG_BONDING) struct adapter *adap; - int i; +#endif + if (event_dev->priv_flags & IFF_802_1Q_VLAN) + event_dev = vlan_dev_real_dev(event_dev); +#if IS_ENABLED(CONFIG_BONDING) + if (event_dev->flags & IFF_MASTER) { + list_for_each_entry(adap, &adapter_list, list_node) { + switch (event) { + case NETDEV_UP: + cxgb4_clip_get(adap->port[0], + (const u32 *)ifa, 1); + break; + case NETDEV_DOWN: + cxgb4_clip_release(adap->port[0], + (const u32 *)ifa, 1); + break; + default: + break; + } + } + return NOTIFY_OK; + } +#endif - list_for_each_entry_rcu(adap, &adap_rcu_list, rcu_node) - for (i = 0; i < MAX_NPORTS; i++) - if (adap->port[i] == netdev) - return true; - return false; -} + if (event_dev) + parent = event_dev->dev.parent; -static int clip_add(struct net_device *event_dev, struct inet6_ifaddr *ifa, - unsigned long event) -{ - int ret = NOTIFY_DONE; - - rcu_read_lock(); - if (cxgb4_netdev(event_dev)) { + if (parent && parent->driver == &cxgb4_driver.driver) { switch (event) { case NETDEV_UP: - ret = cxgb4_clip_get(event_dev, &ifa->addr); - if (ret < 0) { - rcu_read_unlock(); - return ret; - } - ret = NOTIFY_OK; + cxgb4_clip_get(event_dev, (const u32 *)ifa, 1); break; case NETDEV_DOWN: - cxgb4_clip_release(event_dev, &ifa->addr); - ret = NOTIFY_OK; + cxgb4_clip_release(event_dev, (const u32 *)ifa, 1); break; default: break; } } - rcu_read_unlock(); - return ret; -} - -static int cxgb4_inet6addr_handler(struct notifier_block *this, - unsigned long event, void *data) -{ - struct inet6_ifaddr *ifa = data; - struct net_device *event_dev; - int ret = NOTIFY_DONE; - struct bonding *bond = netdev_priv(ifa->idev->dev); - struct list_head *iter; - struct slave *slave; - struct pci_dev *first_pdev = NULL; - - if (ifa->idev->dev->priv_flags & IFF_802_1Q_VLAN) { - event_dev = vlan_dev_real_dev(ifa->idev->dev); - ret = clip_add(event_dev, ifa, event); - } else if (ifa->idev->dev->flags & IFF_MASTER) { - /* It is possible that two different adapters are bonded in one - * bond. We need to find such different adapters and add clip - * in all of them only once. - */ - bond_for_each_slave(bond, slave, iter) { - if (!first_pdev) { - ret = clip_add(slave->dev, ifa, event); - /* If clip_add is success then only initialize - * first_pdev since it means it is our device - */ - if (ret == NOTIFY_OK) - first_pdev = to_pci_dev( - slave->dev->dev.parent); - } else if (first_pdev != - to_pci_dev(slave->dev->dev.parent)) - ret = clip_add(slave->dev, ifa, event); - } - } else - ret = clip_add(ifa->idev->dev, ifa, event); - - return ret; + return NOTIFY_OK; } +static bool inet6addr_registered; static struct notifier_block cxgb4_inet6addr_notifier = { .notifier_call = cxgb4_inet6addr_handler }; -/* Retrieves IPv6 addresses from a root device (bond, vlan) associated with - * a physical device. - * The physical device reference is needed to send the actul CLIP command. - */ -static int update_dev_clip(struct net_device *root_dev, struct net_device *dev) -{ - struct inet6_dev *idev = NULL; - struct inet6_ifaddr *ifa; - int ret = 0; - - idev = __in6_dev_get(root_dev); - if (!idev) - return ret; - - read_lock_bh(&idev->lock); - list_for_each_entry(ifa, &idev->addr_list, if_list) { - ret = cxgb4_clip_get(dev, &ifa->addr); - if (ret < 0) - break; - } - read_unlock_bh(&idev->lock); - - return ret; -} - -static int update_root_dev_clip(struct net_device *dev) -{ - struct net_device *root_dev = NULL; - int i, ret = 0; - - /* First populate the real net device's IPv6 addresses */ - ret = update_dev_clip(dev, dev); - if (ret) - return ret; - - /* Parse all bond and vlan devices layered on top of the physical dev */ - root_dev = netdev_master_upper_dev_get_rcu(dev); - if (root_dev) { - ret = update_dev_clip(root_dev, dev); - if (ret) - return ret; - } - - for (i = 0; i < VLAN_N_VID; i++) { - root_dev = __vlan_find_dev_deep_rcu(dev, htons(ETH_P_8021Q), i); - if (!root_dev) - continue; - - ret = update_dev_clip(root_dev, dev); - if (ret) - break; - } - return ret; -} - static void update_clip(const struct adapter *adap) { int i; @@ -4375,7 +4176,7 @@ static void update_clip(const struct adapter *adap) ret = 0; if (dev) - ret = update_root_dev_clip(dev); + ret = cxgb4_update_root_dev_clip(dev); if (ret < 0) break; @@ -4567,13 +4368,13 @@ int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid, f->fs.val.lip[i] = val[i]; f->fs.mask.lip[i] = ~0; } - if (adap->params.tp.vlan_pri_map & F_PORT) { + if (adap->params.tp.vlan_pri_map & PORT_F) { f->fs.val.iport = port; f->fs.mask.iport = mask; } } - if (adap->params.tp.vlan_pri_map & F_PROTOCOL) { + if (adap->params.tp.vlan_pri_map & PROTOCOL_F) { f->fs.val.proto = IPPROTO_TCP; f->fs.mask.proto = ~0; } @@ -4779,11 +4580,15 @@ static const struct net_device_ops cxgb4_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = cxgb_netpoll, #endif +#ifdef CONFIG_NET_RX_BUSY_POLL + .ndo_busy_poll = cxgb_busy_poll, +#endif + }; void t4_fatal_err(struct adapter *adap) { - t4_set_reg_field(adap, SGE_CONTROL, GLOBALENABLE, 0); + t4_set_reg_field(adap, SGE_CONTROL_A, GLOBALENABLE_F, 0); t4_intr_disable(adap); dev_alert(adap->pdev_dev, "encountered fatal error, adapter stopped\n"); } @@ -4858,16 +4663,16 @@ static void setup_memwin(struct adapter *adap) mem_win2_base = MEMWIN2_BASE_T5; mem_win2_aperture = MEMWIN2_APERTURE_T5; } - t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 0), - mem_win0_base | BIR(0) | - WINDOW(ilog2(MEMWIN0_APERTURE) - 10)); - t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 1), - mem_win1_base | BIR(0) | - WINDOW(ilog2(MEMWIN1_APERTURE) - 10)); - t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2), - mem_win2_base | BIR(0) | - WINDOW(ilog2(mem_win2_aperture) - 10)); - t4_read_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2)); + t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 0), + mem_win0_base | BIR_V(0) | + WINDOW_V(ilog2(MEMWIN0_APERTURE) - 10)); + t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 1), + mem_win1_base | BIR_V(0) | + WINDOW_V(ilog2(MEMWIN1_APERTURE) - 10)); + t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 2), + mem_win2_base | BIR_V(0) | + WINDOW_V(ilog2(mem_win2_aperture) - 10)); + t4_read_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 2)); } static void setup_memwin_rdma(struct adapter *adap) @@ -4881,13 +4686,13 @@ static void setup_memwin_rdma(struct adapter *adap) start += OCQ_WIN_OFFSET(adap->pdev, &adap->vres); sz_kb = roundup_pow_of_two(adap->vres.ocq.size) >> 10; t4_write_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 3), - start | BIR(1) | WINDOW(ilog2(sz_kb))); + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 3), + start | BIR_V(1) | WINDOW_V(ilog2(sz_kb))); t4_write_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, 3), + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, 3), adap->vres.ocq.start); t4_read_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, 3)); + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, 3)); } } @@ -4936,38 +4741,38 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c) t4_sge_init(adap); /* tweak some settings */ - t4_write_reg(adap, TP_SHIFT_CNT, 0x64f8849); - t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(PAGE_SHIFT - 12)); - t4_write_reg(adap, TP_PIO_ADDR, TP_INGRESS_CONFIG); - v = t4_read_reg(adap, TP_PIO_DATA); - t4_write_reg(adap, TP_PIO_DATA, v & ~CSUM_HAS_PSEUDO_HDR); + t4_write_reg(adap, TP_SHIFT_CNT_A, 0x64f8849); + t4_write_reg(adap, ULP_RX_TDDP_PSZ_A, HPZ0_V(PAGE_SHIFT - 12)); + t4_write_reg(adap, TP_PIO_ADDR_A, TP_INGRESS_CONFIG_A); + v = t4_read_reg(adap, TP_PIO_DATA_A); + t4_write_reg(adap, TP_PIO_DATA_A, v & ~CSUM_HAS_PSEUDO_HDR_F); /* first 4 Tx modulation queues point to consecutive Tx channels */ adap->params.tp.tx_modq_map = 0xE4; - t4_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP, - V_TX_MOD_QUEUE_REQ_MAP(adap->params.tp.tx_modq_map)); + t4_write_reg(adap, TP_TX_MOD_QUEUE_REQ_MAP_A, + TX_MOD_QUEUE_REQ_MAP_V(adap->params.tp.tx_modq_map)); /* associate each Tx modulation queue with consecutive Tx channels */ v = 0x84218421; - t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA, - &v, 1, A_TP_TX_SCHED_HDR); - t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA, - &v, 1, A_TP_TX_SCHED_FIFO); - t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA, - &v, 1, A_TP_TX_SCHED_PCMD); + t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, + &v, 1, TP_TX_SCHED_HDR_A); + t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, + &v, 1, TP_TX_SCHED_FIFO_A); + t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, + &v, 1, TP_TX_SCHED_PCMD_A); #define T4_TX_MODQ_10G_WEIGHT_DEFAULT 16 /* in KB units */ if (is_offload(adap)) { - t4_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, - V_TX_MODQ_WEIGHT0(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | - V_TX_MODQ_WEIGHT1(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | - V_TX_MODQ_WEIGHT2(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | - V_TX_MODQ_WEIGHT3(T4_TX_MODQ_10G_WEIGHT_DEFAULT)); - t4_write_reg(adap, A_TP_TX_MOD_CHANNEL_WEIGHT, - V_TX_MODQ_WEIGHT0(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | - V_TX_MODQ_WEIGHT1(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | - V_TX_MODQ_WEIGHT2(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | - V_TX_MODQ_WEIGHT3(T4_TX_MODQ_10G_WEIGHT_DEFAULT)); + t4_write_reg(adap, TP_TX_MOD_QUEUE_WEIGHT0_A, + TX_MODQ_WEIGHT0_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | + TX_MODQ_WEIGHT1_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | + TX_MODQ_WEIGHT2_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | + TX_MODQ_WEIGHT3_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT)); + t4_write_reg(adap, TP_TX_MOD_CHANNEL_WEIGHT_A, + TX_MODQ_WEIGHT0_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | + TX_MODQ_WEIGHT1_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | + TX_MODQ_WEIGHT2_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | + TX_MODQ_WEIGHT3_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT)); } /* get basic stuff going */ @@ -5013,16 +4818,16 @@ static int adap_init0_tweaks(struct adapter *adapter) rx_dma_offset); rx_dma_offset = 2; } - t4_set_reg_field(adapter, SGE_CONTROL, - PKTSHIFT_MASK, - PKTSHIFT(rx_dma_offset)); + t4_set_reg_field(adapter, SGE_CONTROL_A, + PKTSHIFT_V(PKTSHIFT_M), + PKTSHIFT_V(rx_dma_offset)); /* * Don't include the "IP Pseudo Header" in CPL_RX_PKT checksums: Linux * adds the pseudo header itself. */ - t4_tp_wr_bits_indirect(adapter, TP_INGRESS_CONFIG, - CSUM_HAS_PSEUDO_HDR, 0); + t4_tp_wr_bits_indirect(adapter, TP_INGRESS_CONFIG_A, + CSUM_HAS_PSEUDO_HDR_F, 0); return 0; } @@ -5046,7 +4851,7 @@ static int adap_init0_config(struct adapter *adapter, int reset) */ if (reset) { ret = t4_fw_reset(adapter, adapter->mbox, - PIORSTMODE | PIORST); + PIORSTMODE_F | PIORST_F); if (ret < 0) goto bye; } @@ -5212,12 +5017,9 @@ static int adap_init0_config(struct adapter *adapter, int reset) if (ret < 0) goto bye; - /* - * Return successfully and note that we're operating with parameters - * not supplied by the driver, rather than from hard-wired - * initialization constants burried in the driver. + /* Emit Firmware Configuration File information and return + * successfully. */ - adapter->flags |= USING_SOFT_PARAMS; dev_info(adapter->pdev_dev, "Successfully configured using Firmware "\ "Configuration File \"%s\", version %#x, computed checksum %#x\n", config_name, finiver, cfcsum); @@ -5235,249 +5037,6 @@ bye: return ret; } -/* - * Attempt to initialize the adapter via hard-coded, driver supplied - * parameters ... - */ -static int adap_init0_no_config(struct adapter *adapter, int reset) -{ - struct sge *s = &adapter->sge; - struct fw_caps_config_cmd caps_cmd; - u32 v; - int i, ret; - - /* - * Reset device if necessary - */ - if (reset) { - ret = t4_fw_reset(adapter, adapter->mbox, - PIORSTMODE | PIORST); - if (ret < 0) - goto bye; - } - - /* - * Get device capabilities and select which we'll be using. - */ - memset(&caps_cmd, 0, sizeof(caps_cmd)); - caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | - FW_CMD_REQUEST_F | FW_CMD_READ_F); - caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd)); - ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd), - &caps_cmd); - if (ret < 0) - goto bye; - - if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_VM)) { - if (!vf_acls) - caps_cmd.niccaps ^= htons(FW_CAPS_CONFIG_NIC_VM); - else - caps_cmd.niccaps = htons(FW_CAPS_CONFIG_NIC_VM); - } else if (vf_acls) { - dev_err(adapter->pdev_dev, "virtualization ACLs not supported"); - goto bye; - } - caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | - FW_CMD_REQUEST_F | FW_CMD_WRITE_F); - ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd), - NULL); - if (ret < 0) - goto bye; - - /* - * Tweak configuration based on system architecture, module - * parameters, etc. - */ - ret = adap_init0_tweaks(adapter); - if (ret < 0) - goto bye; - - /* - * Select RSS Global Mode we want to use. We use "Basic Virtual" - * mode which maps each Virtual Interface to its own section of - * the RSS Table and we turn on all map and hash enables ... - */ - adapter->flags |= RSS_TNLALLLOOKUP; - ret = t4_config_glbl_rss(adapter, adapter->mbox, - FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL, - FW_RSS_GLB_CONFIG_CMD_TNLMAPEN_F | - FW_RSS_GLB_CONFIG_CMD_HASHTOEPLITZ_F | - ((adapter->flags & RSS_TNLALLLOOKUP) ? - FW_RSS_GLB_CONFIG_CMD_TNLALLLKP_F : 0)); - if (ret < 0) - goto bye; - - /* - * Set up our own fundamental resource provisioning ... - */ - ret = t4_cfg_pfvf(adapter, adapter->mbox, adapter->fn, 0, - PFRES_NEQ, PFRES_NETHCTRL, - PFRES_NIQFLINT, PFRES_NIQ, - PFRES_TC, PFRES_NVI, - FW_PFVF_CMD_CMASK_M, - pfvfres_pmask(adapter, adapter->fn, 0), - PFRES_NEXACTF, - PFRES_R_CAPS, PFRES_WX_CAPS); - if (ret < 0) - goto bye; - - /* - * Perform low level SGE initialization. We need to do this before we - * send the firmware the INITIALIZE command because that will cause - * any other PF Drivers which are waiting for the Master - * Initialization to proceed forward. - */ - for (i = 0; i < SGE_NTIMERS - 1; i++) - s->timer_val[i] = min(intr_holdoff[i], MAX_SGE_TIMERVAL); - s->timer_val[SGE_NTIMERS - 1] = MAX_SGE_TIMERVAL; - s->counter_val[0] = 1; - for (i = 1; i < SGE_NCOUNTERS; i++) - s->counter_val[i] = min(intr_cnt[i - 1], - THRESHOLD_0_GET(THRESHOLD_0_MASK)); - t4_sge_init(adapter); - -#ifdef CONFIG_PCI_IOV - /* - * Provision resource limits for Virtual Functions. We currently - * grant them all the same static resource limits except for the Port - * Access Rights Mask which we're assigning based on the PF. All of - * the static provisioning stuff for both the PF and VF really needs - * to be managed in a persistent manner for each device which the - * firmware controls. - */ - { - int pf, vf; - - for (pf = 0; pf < ARRAY_SIZE(num_vf); pf++) { - if (num_vf[pf] <= 0) - continue; - - /* VF numbering starts at 1! */ - for (vf = 1; vf <= num_vf[pf]; vf++) { - ret = t4_cfg_pfvf(adapter, adapter->mbox, - pf, vf, - VFRES_NEQ, VFRES_NETHCTRL, - VFRES_NIQFLINT, VFRES_NIQ, - VFRES_TC, VFRES_NVI, - FW_PFVF_CMD_CMASK_M, - pfvfres_pmask( - adapter, pf, vf), - VFRES_NEXACTF, - VFRES_R_CAPS, VFRES_WX_CAPS); - if (ret < 0) - dev_warn(adapter->pdev_dev, - "failed to "\ - "provision pf/vf=%d/%d; " - "err=%d\n", pf, vf, ret); - } - } - } -#endif - - /* - * Set up the default filter mode. Later we'll want to implement this - * via a firmware command, etc. ... This needs to be done before the - * firmare initialization command ... If the selected set of fields - * isn't equal to the default value, we'll need to make sure that the - * field selections will fit in the 36-bit budget. - */ - if (tp_vlan_pri_map != TP_VLAN_PRI_MAP_DEFAULT) { - int j, bits = 0; - - for (j = TP_VLAN_PRI_MAP_FIRST; j <= TP_VLAN_PRI_MAP_LAST; j++) - switch (tp_vlan_pri_map & (1 << j)) { - case 0: - /* compressed filter field not enabled */ - break; - case FCOE_MASK: - bits += 1; - break; - case PORT_MASK: - bits += 3; - break; - case VNIC_ID_MASK: - bits += 17; - break; - case VLAN_MASK: - bits += 17; - break; - case TOS_MASK: - bits += 8; - break; - case PROTOCOL_MASK: - bits += 8; - break; - case ETHERTYPE_MASK: - bits += 16; - break; - case MACMATCH_MASK: - bits += 9; - break; - case MPSHITTYPE_MASK: - bits += 3; - break; - case FRAGMENTATION_MASK: - bits += 1; - break; - } - - if (bits > 36) { - dev_err(adapter->pdev_dev, - "tp_vlan_pri_map=%#x needs %d bits > 36;"\ - " using %#x\n", tp_vlan_pri_map, bits, - TP_VLAN_PRI_MAP_DEFAULT); - tp_vlan_pri_map = TP_VLAN_PRI_MAP_DEFAULT; - } - } - v = tp_vlan_pri_map; - t4_write_indirect(adapter, TP_PIO_ADDR, TP_PIO_DATA, - &v, 1, TP_VLAN_PRI_MAP); - - /* - * We need Five Tuple Lookup mode to be set in TP_GLOBAL_CONFIG order - * to support any of the compressed filter fields above. Newer - * versions of the firmware do this automatically but it doesn't hurt - * to set it here. Meanwhile, we do _not_ need to set Lookup Every - * Packet in TP_INGRESS_CONFIG to support matching non-TCP packets - * since the firmware automatically turns this on and off when we have - * a non-zero number of filters active (since it does have a - * performance impact). - */ - if (tp_vlan_pri_map) - t4_set_reg_field(adapter, TP_GLOBAL_CONFIG, - FIVETUPLELOOKUP_MASK, - FIVETUPLELOOKUP_MASK); - - /* - * Tweak some settings. - */ - t4_write_reg(adapter, TP_SHIFT_CNT, SYNSHIFTMAX(6) | - RXTSHIFTMAXR1(4) | RXTSHIFTMAXR2(15) | - PERSHIFTBACKOFFMAX(8) | PERSHIFTMAX(8) | - KEEPALIVEMAXR1(4) | KEEPALIVEMAXR2(9)); - - /* - * Get basic stuff going by issuing the Firmware Initialize command. - * Note that this _must_ be after all PFVF commands ... - */ - ret = t4_fw_initialize(adapter, adapter->mbox); - if (ret < 0) - goto bye; - - /* - * Return successfully! - */ - dev_info(adapter->pdev_dev, "Successfully configured using built-in "\ - "driver parameters\n"); - return 0; - - /* - * Something bad happened. Return the error ... - */ -bye: - return ret; -} - static struct fw_info fw_info_array[] = { { .chip = CHELSIO_T4, @@ -5529,6 +5088,8 @@ static int adap_init0(struct adapter *adap) enum dev_state state; u32 params[7], val[7]; struct fw_caps_config_cmd caps_cmd; + struct fw_devlog_cmd devlog_cmd; + u32 devlog_meminfo; int reset = 1; /* Contact FW, advertising Master capability */ @@ -5590,8 +5151,7 @@ static int adap_init0(struct adapter *adap) state, &reset); /* Cleaning up */ - if (fw != NULL) - release_firmware(fw); + release_firmware(fw); t4_free_mem(card_fw); if (ret < 0) @@ -5609,6 +5169,30 @@ static int adap_init0(struct adapter *adap) if (ret < 0) goto bye; + /* Read firmware device log parameters. We really need to find a way + * to get these parameters initialized with some default values (which + * are likely to be correct) for the case where we either don't + * attache to the firmware or it's crashed when we probe the adapter. + * That way we'll still be able to perform early firmware startup + * debugging ... If the request to get the Firmware's Device Log + * parameters fails, we'll live so we don't make that a fatal error. + */ + memset(&devlog_cmd, 0, sizeof(devlog_cmd)); + devlog_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_DEVLOG_CMD) | + FW_CMD_REQUEST_F | FW_CMD_READ_F); + devlog_cmd.retval_len16 = htonl(FW_LEN16(devlog_cmd)); + ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd), + &devlog_cmd); + if (ret == 0) { + devlog_meminfo = + ntohl(devlog_cmd.memtype_devlog_memaddr16_devlog); + adap->params.devlog.memtype = + FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(devlog_meminfo); + adap->params.devlog.start = + FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(devlog_meminfo) << 4; + adap->params.devlog.size = ntohl(devlog_cmd.memsize_devlog); + } + /* * Find out what ports are available to us. Note that we need to do * this before calling adap_init0_no_config() since it needs nports @@ -5624,88 +5208,58 @@ static int adap_init0(struct adapter *adap) adap->params.nports = hweight32(port_vec); adap->params.portvec = port_vec; - /* - * If the firmware is initialized already (and we're not forcing a - * master initialization), note that we're living with existing - * adapter parameters. Otherwise, it's time to try initializing the - * adapter ... + /* If the firmware is initialized already, emit a simply note to that + * effect. Otherwise, it's time to try initializing the adapter. */ if (state == DEV_STATE_INIT) { dev_info(adap->pdev_dev, "Coming up as %s: "\ "Adapter already initialized\n", adap->flags & MASTER_PF ? "MASTER" : "SLAVE"); - adap->flags |= USING_SOFT_PARAMS; } else { dev_info(adap->pdev_dev, "Coming up as MASTER: "\ "Initializing adapter\n"); - /* - * If the firmware doesn't support Configuration - * Files warn user and exit, + + /* Find out whether we're dealing with a version of the + * firmware which has configuration file support. */ - if (ret < 0) - dev_warn(adap->pdev_dev, "Firmware doesn't support " - "configuration file.\n"); - if (force_old_init) - ret = adap_init0_no_config(adap, reset); - else { - /* - * Find out whether we're dealing with a version of - * the firmware which has configuration file support. - */ - params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | - FW_PARAMS_PARAM_X_V( - FW_PARAMS_PARAM_DEV_CF)); - ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1, - params, val); + params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CF)); + ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1, + params, val); - /* - * If the firmware doesn't support Configuration - * Files, use the old Driver-based, hard-wired - * initialization. Otherwise, try using the - * Configuration File support and fall back to the - * Driver-based initialization if there's no - * Configuration File found. - */ - if (ret < 0) - ret = adap_init0_no_config(adap, reset); - else { - /* - * The firmware provides us with a memory - * buffer where we can load a Configuration - * File from the host if we want to override - * the Configuration File in flash. - */ + /* If the firmware doesn't support Configuration Files, + * return an error. + */ + if (ret < 0) { + dev_err(adap->pdev_dev, "firmware doesn't support " + "Firmware Configuration Files\n"); + goto bye; + } - ret = adap_init0_config(adap, reset); - if (ret == -ENOENT) { - dev_info(adap->pdev_dev, - "No Configuration File present " - "on adapter. Using hard-wired " - "configuration parameters.\n"); - ret = adap_init0_no_config(adap, reset); - } - } + /* The firmware provides us with a memory buffer where we can + * load a Configuration File from the host if we want to + * override the Configuration File in flash. + */ + ret = adap_init0_config(adap, reset); + if (ret == -ENOENT) { + dev_err(adap->pdev_dev, "no Configuration File " + "present on adapter.\n"); + goto bye; } if (ret < 0) { - dev_err(adap->pdev_dev, - "could not initialize adapter, error %d\n", - -ret); + dev_err(adap->pdev_dev, "could not initialize " + "adapter, error %d\n", -ret); goto bye; } } - /* - * If we're living with non-hard-coded parameters (either from a - * Firmware Configuration File or values programmed by a different PF - * Driver), give the SGE code a chance to pull in anything that it - * needs ... Note that this must be called after we retrieve our VPD - * parameters in order to know how to convert core ticks to seconds. + /* Give the SGE code a chance to pull in anything that it needs ... + * Note that this must be called after we retrieve our VPD parameters + * in order to know how to convert core ticks to seconds, etc. */ - if (adap->flags & USING_SOFT_PARAMS) { - ret = t4_sge_init(adap); - if (ret < 0) - goto bye; - } + ret = t4_sge_init(adap); + if (ret < 0) + goto bye; if (is_bypass_device(adap->pdev->device)) adap->params.bypass = 1; @@ -5739,6 +5293,14 @@ static int adap_init0(struct adapter *adap) adap->tids.nftids = val[4] - val[3] + 1; adap->sge.ingr_start = val[5]; + params[0] = FW_PARAM_PFVF(CLIP_START); + params[1] = FW_PARAM_PFVF(CLIP_END); + ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val); + if (ret < 0) + goto bye; + adap->clipt_start = val[0]; + adap->clipt_end = val[1]; + /* query params related to active filter region */ params[0] = FW_PARAM_PFVF(ACTIVE_FILTER_START); params[1] = FW_PARAM_PFVF(ACTIVE_FILTER_END); @@ -6401,7 +5963,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_unmap_bar0; /* We control everything through one PF */ - func = SOURCEPF_GET(readl(regs + PL_WHOAMI)); + func = SOURCEPF_G(readl(regs + PL_WHOAMI_A)); if (func != ent->driver_data) { iounmap(regs); pci_disable_device(pdev); @@ -6467,9 +6029,11 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!is_t4(adapter->params.chip)) { - s_qpp = QUEUESPERPAGEPF1 * adapter->fn; - qpp = 1 << QUEUESPERPAGEPF0_GET(t4_read_reg(adapter, - SGE_EGRESS_QUEUES_PER_PAGE_PF) >> s_qpp); + s_qpp = (QUEUESPERPAGEPF0_S + + (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * + adapter->fn); + qpp = 1 << QUEUESPERPAGEPF0_G(t4_read_reg(adapter, + SGE_EGRESS_QUEUES_PER_PAGE_PF_A) >> s_qpp); num_seg = PAGE_SIZE / SEGMENT_SIZE; /* Each segment size is 128B. Write coalescing is enabled only @@ -6557,6 +6121,18 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->params.offload = 0; } +#if IS_ENABLED(CONFIG_IPV6) + adapter->clipt = t4_init_clip_tbl(adapter->clipt_start, + adapter->clipt_end); + if (!adapter->clipt) { + /* We tolerate a lack of clip_table, giving up + * some functionality + */ + dev_warn(&pdev->dev, + "could not allocate Clip table, continuing\n"); + adapter->params.offload = 0; + } +#endif if (is_offload(adapter) && tid_init(&adapter->tids) < 0) { dev_warn(&pdev->dev, "could not allocate TID table, " "continuing\n"); @@ -6682,6 +6258,9 @@ static void remove_one(struct pci_dev *pdev) cxgb_down(adapter); free_some_resources(adapter); +#if IS_ENABLED(CONFIG_IPV6) + t4_cleanup_clip_tbl(adapter); +#endif iounmap(adapter->regs); if (!is_t4(adapter->params.chip)) iounmap(adapter->bar2); @@ -6720,7 +6299,10 @@ static int __init cxgb4_init_module(void) debugfs_remove(cxgb4_debugfs_root); #if IS_ENABLED(CONFIG_IPV6) - register_inet6addr_notifier(&cxgb4_inet6addr_notifier); + if (!inet6addr_registered) { + register_inet6addr_notifier(&cxgb4_inet6addr_notifier); + inet6addr_registered = true; + } #endif return ret; @@ -6729,7 +6311,10 @@ static int __init cxgb4_init_module(void) static void __exit cxgb4_cleanup_module(void) { #if IS_ENABLED(CONFIG_IPV6) - unregister_inet6addr_notifier(&cxgb4_inet6addr_notifier); + if (inet6addr_registered) { + unregister_inet6addr_notifier(&cxgb4_inet6addr_notifier); + inet6addr_registered = false; + } #endif pci_unregister_driver(&cxgb4_driver); debugfs_remove(cxgb4_debugfs_root); /* NULL ok */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index 152b4c4c7809..78ab4d406ce2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -173,9 +173,6 @@ int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid, unsigned char port, unsigned char mask); int cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid, unsigned int queue, bool ipv6); -int cxgb4_clip_get(const struct net_device *dev, const struct in6_addr *lip); -int cxgb4_clip_release(const struct net_device *dev, - const struct in6_addr *lip); static inline void set_wr_txq(struct sk_buff *skb, int prio, int queue) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index a047baa9fd04..252efc29321f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -46,6 +46,7 @@ #include "t4_msg.h" #include "t4fw_api.h" #include "t4_regs.h" +#include "t4_values.h" #define VLAN_NONE 0xfff @@ -150,8 +151,8 @@ static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync) OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx | (sync ? F_SYNC_WR : 0) | - TID_QID(adap->sge.fw_evtq.abs_id))); - req->params = htons(L2T_W_PORT(e->lport) | L2T_W_NOREPLY(!sync)); + TID_QID_V(adap->sge.fw_evtq.abs_id))); + req->params = htons(L2T_W_PORT_V(e->lport) | L2T_W_NOREPLY_V(!sync)); req->l2t_idx = htons(e->idx); req->vlan = htons(e->vlan); if (e->neigh && !(e->neigh->dev->flags & IFF_LOOPBACK)) @@ -425,7 +426,7 @@ u64 cxgb4_select_ntuple(struct net_device *dev, * in the Compressed Filter Tuple. */ if (tp->vlan_shift >= 0 && l2t->vlan != VLAN_NONE) - ntuple |= (u64)(F_FT_VLAN_VLD | l2t->vlan) << tp->vlan_shift; + ntuple |= (u64)(FT_VLAN_VLD_F | l2t->vlan) << tp->vlan_shift; if (tp->port_shift >= 0) ntuple |= (u64)l2t->lport << tp->port_shift; @@ -439,9 +440,9 @@ u64 cxgb4_select_ntuple(struct net_device *dev, u32 pf = FW_VIID_PFN_G(viid); u32 vld = FW_VIID_VIVLD_G(viid); - ntuple |= (u64)(V_FT_VNID_ID_VF(vf) | - V_FT_VNID_ID_PF(pf) | - V_FT_VNID_ID_VLD(vld)) << tp->vnic_shift; + ntuple |= (u64)(FT_VNID_ID_VF_V(vf) | + FT_VNID_ID_PF_V(pf) | + FT_VNID_ID_VLD_V(vld)) << tp->vnic_shift; } return ntuple; diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index ebf935a1e352..b4b9f6048fe7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -43,8 +43,12 @@ #include #include #include +#ifdef CONFIG_NET_RX_BUSY_POLL +#include +#endif /* CONFIG_NET_RX_BUSY_POLL */ #include "cxgb4.h" #include "t4_regs.h" +#include "t4_values.h" #include "t4_msg.h" #include "t4fw_api.h" @@ -521,10 +525,12 @@ static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) { u32 val; if (q->pend_cred >= 8) { - val = PIDX(q->pend_cred / 8); - if (!is_t4(adap->params.chip)) - val |= DBTYPE(1); - val |= DBPRIO(1); + if (is_t4(adap->params.chip)) + val = PIDX_V(q->pend_cred / 8); + else + val = PIDX_T5_V(q->pend_cred / 8) | + DBTYPE_F; + val |= DBPRIO_F; wmb(); /* If we don't have access to the new User Doorbell (T5+), use @@ -532,10 +538,10 @@ static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) * mechanism. */ if (unlikely(q->bar2_addr == NULL)) { - t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), - val | QID(q->cntxt_id)); + t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), + val | QID_V(q->cntxt_id)); } else { - writel(val | QID(q->bar2_qid), + writel(val | QID_V(q->bar2_qid), q->bar2_addr + SGE_UDB_KDOORBELL); /* This Write memory Barrier will force the write to @@ -818,7 +824,8 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *q, sgl->addr0 = cpu_to_be64(addr[1]); } - sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | ULPTX_NSGE(nfrags)); + sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | + ULPTX_NSGE_V(nfrags)); if (likely(--nfrags == 0)) return; /* @@ -884,7 +891,7 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n) * doorbell mechanism; otherwise use the new BAR2 mechanism. */ if (unlikely(q->bar2_addr == NULL)) { - u32 val = PIDX(n); + u32 val = PIDX_V(n); unsigned long flags; /* For T4 we need to participate in the Doorbell Recovery @@ -892,14 +899,14 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n) */ spin_lock_irqsave(&q->db_lock, flags); if (!q->db_disabled) - t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), - QID(q->cntxt_id) | val); + t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), + QID_V(q->cntxt_id) | val); else q->db_pidx_inc += n; q->db_pidx = q->pidx; spin_unlock_irqrestore(&q->db_lock, flags); } else { - u32 val = PIDX_T5(n); + u32 val = PIDX_T5_V(n); /* T4 and later chips share the same PIDX field offset within * the doorbell, but T5 and later shrank the field in order to @@ -907,7 +914,7 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n) * large in the first place (14 bits) so we just use the T5 * and later limits and warn if a Queue ID is too large. */ - WARN_ON(val & DBPRIO(1)); + WARN_ON(val & DBPRIO_F); /* If we're only writing a single TX Descriptor and we can use * Inferred QID registers, we can use the Write Combining @@ -923,7 +930,7 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n) (q->bar2_addr + SGE_UDB_WCDOORBELL), wr); } else { - writel(val | QID(q->bar2_qid), + writel(val | QID_V(q->bar2_qid), q->bar2_addr + SGE_UDB_KDOORBELL); } @@ -1150,9 +1157,9 @@ out_free: dev_kfree_skb_any(skb); cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS; } - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { q->vlan_ins++; - cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(vlan_tx_tag_get(skb)); + cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(skb_vlan_tag_get(skb)); } cpl->ctrl0 = htonl(TXPKT_OPCODE(CPL_TX_PKT_XT) | @@ -1716,6 +1723,7 @@ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl, skb->truesize += skb->data_len; skb->ip_summed = CHECKSUM_UNNECESSARY; skb_record_rx_queue(skb, rxq->rspq.idx); + skb_mark_napi_id(skb, &rxq->rspq.napi); if (rxq->rspq.netdev->features & NETIF_F_RXHASH) skb_set_hash(skb, (__force u32)pkt->rsshdr.hash_val, PKT_HASH_TYPE_L3); @@ -1758,7 +1766,8 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, pkt = (const struct cpl_rx_pkt *)rsp; csum_ok = pkt->csum_calc && !pkt->err_vec && (q->netdev->features & NETIF_F_RXCSUM); - if ((pkt->l2info & htonl(RXF_TCP)) && + if ((pkt->l2info & htonl(RXF_TCP_F)) && + !(cxgb_poll_busy_polling(q)) && (q->netdev->features & NETIF_F_GRO) && csum_ok && !pkt->ip_frag) { do_gro(rxq, si, pkt); return 0; @@ -1780,11 +1789,11 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, rxq->stats.pkts++; - if (csum_ok && (pkt->l2info & htonl(RXF_UDP | RXF_TCP))) { + if (csum_ok && (pkt->l2info & htonl(RXF_UDP_F | RXF_TCP_F))) { if (!pkt->ip_frag) { skb->ip_summed = CHECKSUM_UNNECESSARY; rxq->stats.rx_cso++; - } else if (pkt->l2info & htonl(RXF_IP)) { + } else if (pkt->l2info & htonl(RXF_IP_F)) { __sum16 c = (__force __sum16)pkt->csum; skb->csum = csum_unfold(c); skb->ip_summed = CHECKSUM_COMPLETE; @@ -1797,6 +1806,7 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(pkt->vlan)); rxq->stats.vlan_ex++; } + skb_mark_napi_id(skb, &q->napi); netif_receive_skb(skb); return 0; } @@ -1959,6 +1969,38 @@ static int process_responses(struct sge_rspq *q, int budget) return budget - budget_left; } +#ifdef CONFIG_NET_RX_BUSY_POLL +int cxgb_busy_poll(struct napi_struct *napi) +{ + struct sge_rspq *q = container_of(napi, struct sge_rspq, napi); + unsigned int params, work_done; + u32 val; + + if (!cxgb_poll_lock_poll(q)) + return LL_FLUSH_BUSY; + + work_done = process_responses(q, 4); + params = QINTR_TIMER_IDX(TIMERREG_COUNTER0_X) | QINTR_CNT_EN; + q->next_intr_params = params; + val = CIDXINC_V(work_done) | SEINTARM_V(params); + + /* If we don't have access to the new User GTS (T5+), use the old + * doorbell mechanism; otherwise use the new BAR2 mechanism. + */ + if (unlikely(!q->bar2_addr)) + t4_write_reg(q->adap, MYPF_REG(SGE_PF_GTS_A), + val | INGRESSQID_V((u32)q->cntxt_id)); + else { + writel(val | INGRESSQID_V(q->bar2_qid), + q->bar2_addr + SGE_UDB_GTS); + wmb(); + } + + cxgb_poll_unlock_poll(q); + return work_done; +} +#endif /* CONFIG_NET_RX_BUSY_POLL */ + /** * napi_rx_handler - the NAPI handler for Rx processing * @napi: the napi instance @@ -1974,9 +2016,13 @@ static int napi_rx_handler(struct napi_struct *napi, int budget) { unsigned int params; struct sge_rspq *q = container_of(napi, struct sge_rspq, napi); - int work_done = process_responses(q, budget); + int work_done; u32 val; + if (!cxgb_poll_lock_napi(q)) + return budget; + + work_done = process_responses(q, budget); if (likely(work_done < budget)) { int timer_index; @@ -2001,19 +2047,20 @@ static int napi_rx_handler(struct napi_struct *napi, int budget) } else params = QINTR_TIMER_IDX(7); - val = CIDXINC(work_done) | SEINTARM(params); + val = CIDXINC_V(work_done) | SEINTARM_V(params); /* If we don't have access to the new User GTS (T5+), use the old * doorbell mechanism; otherwise use the new BAR2 mechanism. */ if (unlikely(q->bar2_addr == NULL)) { - t4_write_reg(q->adap, MYPF_REG(SGE_PF_GTS), - val | INGRESSQID((u32)q->cntxt_id)); + t4_write_reg(q->adap, MYPF_REG(SGE_PF_GTS_A), + val | INGRESSQID_V((u32)q->cntxt_id)); } else { - writel(val | INGRESSQID(q->bar2_qid), + writel(val | INGRESSQID_V(q->bar2_qid), q->bar2_addr + SGE_UDB_GTS); wmb(); } + cxgb_poll_unlock_napi(q); return work_done; } @@ -2056,16 +2103,16 @@ static unsigned int process_intrq(struct adapter *adap) rspq_next(q); } - val = CIDXINC(credits) | SEINTARM(q->intr_params); + val = CIDXINC_V(credits) | SEINTARM_V(q->intr_params); /* If we don't have access to the new User GTS (T5+), use the old * doorbell mechanism; otherwise use the new BAR2 mechanism. */ if (unlikely(q->bar2_addr == NULL)) { - t4_write_reg(adap, MYPF_REG(SGE_PF_GTS), - val | INGRESSQID(q->cntxt_id)); + t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A), + val | INGRESSQID_V(q->cntxt_id)); } else { - writel(val | INGRESSQID(q->bar2_qid), + writel(val | INGRESSQID_V(q->bar2_qid), q->bar2_addr + SGE_UDB_GTS); wmb(); } @@ -2095,7 +2142,7 @@ static irqreturn_t t4_intr_intx(int irq, void *cookie) { struct adapter *adap = cookie; - t4_write_reg(adap, MYPF_REG(PCIE_PF_CLI), 0); + t4_write_reg(adap, MYPF_REG(PCIE_PF_CLI_A), 0); if (t4_slow_intr_handler(adap) | process_intrq(adap)) return IRQ_HANDLED; return IRQ_NONE; /* probably shared interrupt */ @@ -2142,9 +2189,9 @@ static void sge_rx_timer_cb(unsigned long data) } } - t4_write_reg(adap, SGE_DEBUG_INDEX, 13); - idma_same_state_cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH); - idma_same_state_cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW); + t4_write_reg(adap, SGE_DEBUG_INDEX_A, 13); + idma_same_state_cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH_A); + idma_same_state_cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW_A); for (i = 0; i < 2; i++) { u32 debug0, debug11; @@ -2188,12 +2235,12 @@ static void sge_rx_timer_cb(unsigned long data) /* Read and save the SGE IDMA State and Queue ID information. * We do this every time in case it changes across time ... */ - t4_write_reg(adap, SGE_DEBUG_INDEX, 0); - debug0 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW); + t4_write_reg(adap, SGE_DEBUG_INDEX_A, 0); + debug0 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW_A); s->idma_state[i] = (debug0 >> (i * 9)) & 0x3f; - t4_write_reg(adap, SGE_DEBUG_INDEX, 11); - debug11 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW); + t4_write_reg(adap, SGE_DEBUG_INDEX_A, 11); + debug11 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW_A); s->idma_qid[i] = (debug11 >> (i * 16)) & 0xffff; CH_WARN(adap, "SGE idma%u, queue%u, maybe stuck state%u %dsecs (debug0=%#x, debug11=%#x)\n", @@ -2337,6 +2384,7 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq, goto err; netif_napi_add(dev, &iq->napi, napi_rx_handler, 64); + napi_hash_add(&iq->napi); iq->cur_desc = iq->desc; iq->cidx = 0; iq->gen = 1; @@ -2594,6 +2642,7 @@ static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq, rq->cntxt_id, fl_id, 0xffff); dma_free_coherent(adap->pdev_dev, (rq->size + 1) * rq->iqe_len, rq->desc, rq->phys_addr); + napi_hash_del(&rq->napi); netif_napi_del(&rq->napi); rq->netdev = NULL; rq->cntxt_id = rq->abs_id = 0; @@ -2738,24 +2787,11 @@ void t4_sge_stop(struct adapter *adap) } /** - * t4_sge_init - initialize SGE + * t4_sge_init_soft - grab core SGE values needed by SGE code * @adap: the adapter * - * Performs SGE initialization needed every time after a chip reset. - * We do not initialize any of the queues here, instead the driver - * top-level must request them individually. - * - * Called in two different modes: - * - * 1. Perform actual hardware initialization and record hard-coded - * parameters which were used. This gets used when we're the - * Master PF and the Firmware Configuration File support didn't - * work for some reason. - * - * 2. We're not the Master PF or initialization was performed with - * a Firmware Configuration File. In this case we need to grab - * any of the SGE operating parameters that we need to have in - * order to do our job and make sure we can live with them ... + * We need to grab the SGE operating parameters that we need to have + * in order to do our job and make sure we can live with them. */ static int t4_sge_init_soft(struct adapter *adap) @@ -2770,8 +2806,8 @@ static int t4_sge_init_soft(struct adapter *adap) * process_responses() and that only packet data is going to the * Free Lists. */ - if ((t4_read_reg(adap, SGE_CONTROL) & RXPKTCPLMODE_MASK) != - RXPKTCPLMODE(X_RXPKTCPLMODE_SPLIT)) { + if ((t4_read_reg(adap, SGE_CONTROL_A) & RXPKTCPLMODE_F) != + RXPKTCPLMODE_V(RXPKTCPLMODE_SPLIT_X)) { dev_err(adap->pdev_dev, "bad SGE CPL MODE\n"); return -EINVAL; } @@ -2785,7 +2821,7 @@ static int t4_sge_init_soft(struct adapter *adap) * XXX meet our needs! */ #define READ_FL_BUF(x) \ - t4_read_reg(adap, SGE_FL_BUFFER_SIZE0+(x)*sizeof(u32)) + t4_read_reg(adap, SGE_FL_BUFFER_SIZE0_A+(x)*sizeof(u32)) fl_small_pg = READ_FL_BUF(RX_SMALL_PG_BUF); fl_large_pg = READ_FL_BUF(RX_LARGE_PG_BUF); @@ -2823,99 +2859,38 @@ static int t4_sge_init_soft(struct adapter *adap) * Retrieve our RX interrupt holdoff timer values and counter * threshold values from the SGE parameters. */ - timer_value_0_and_1 = t4_read_reg(adap, SGE_TIMER_VALUE_0_AND_1); - timer_value_2_and_3 = t4_read_reg(adap, SGE_TIMER_VALUE_2_AND_3); - timer_value_4_and_5 = t4_read_reg(adap, SGE_TIMER_VALUE_4_AND_5); + timer_value_0_and_1 = t4_read_reg(adap, SGE_TIMER_VALUE_0_AND_1_A); + timer_value_2_and_3 = t4_read_reg(adap, SGE_TIMER_VALUE_2_AND_3_A); + timer_value_4_and_5 = t4_read_reg(adap, SGE_TIMER_VALUE_4_AND_5_A); s->timer_val[0] = core_ticks_to_us(adap, - TIMERVALUE0_GET(timer_value_0_and_1)); + TIMERVALUE0_G(timer_value_0_and_1)); s->timer_val[1] = core_ticks_to_us(adap, - TIMERVALUE1_GET(timer_value_0_and_1)); + TIMERVALUE1_G(timer_value_0_and_1)); s->timer_val[2] = core_ticks_to_us(adap, - TIMERVALUE2_GET(timer_value_2_and_3)); + TIMERVALUE2_G(timer_value_2_and_3)); s->timer_val[3] = core_ticks_to_us(adap, - TIMERVALUE3_GET(timer_value_2_and_3)); + TIMERVALUE3_G(timer_value_2_and_3)); s->timer_val[4] = core_ticks_to_us(adap, - TIMERVALUE4_GET(timer_value_4_and_5)); + TIMERVALUE4_G(timer_value_4_and_5)); s->timer_val[5] = core_ticks_to_us(adap, - TIMERVALUE5_GET(timer_value_4_and_5)); + TIMERVALUE5_G(timer_value_4_and_5)); - ingress_rx_threshold = t4_read_reg(adap, SGE_INGRESS_RX_THRESHOLD); - s->counter_val[0] = THRESHOLD_0_GET(ingress_rx_threshold); - s->counter_val[1] = THRESHOLD_1_GET(ingress_rx_threshold); - s->counter_val[2] = THRESHOLD_2_GET(ingress_rx_threshold); - s->counter_val[3] = THRESHOLD_3_GET(ingress_rx_threshold); - - return 0; -} - -static int t4_sge_init_hard(struct adapter *adap) -{ - struct sge *s = &adap->sge; - - /* - * Set up our basic SGE mode to deliver CPL messages to our Ingress - * Queue and Packet Date to the Free List. - */ - t4_set_reg_field(adap, SGE_CONTROL, RXPKTCPLMODE_MASK, - RXPKTCPLMODE_MASK); - - /* - * Set up to drop DOORBELL writes when the DOORBELL FIFO overflows - * and generate an interrupt when this occurs so we can recover. - */ - if (is_t4(adap->params.chip)) { - t4_set_reg_field(adap, A_SGE_DBFIFO_STATUS, - V_HP_INT_THRESH(M_HP_INT_THRESH) | - V_LP_INT_THRESH(M_LP_INT_THRESH), - V_HP_INT_THRESH(dbfifo_int_thresh) | - V_LP_INT_THRESH(dbfifo_int_thresh)); - } else { - t4_set_reg_field(adap, A_SGE_DBFIFO_STATUS, - V_LP_INT_THRESH_T5(M_LP_INT_THRESH_T5), - V_LP_INT_THRESH_T5(dbfifo_int_thresh)); - t4_set_reg_field(adap, SGE_DBFIFO_STATUS2, - V_HP_INT_THRESH_T5(M_HP_INT_THRESH_T5), - V_HP_INT_THRESH_T5(dbfifo_int_thresh)); - } - t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_ENABLE_DROP, - F_ENABLE_DROP); - - /* - * SGE_FL_BUFFER_SIZE0 (RX_SMALL_PG_BUF) is set up by - * t4_fixup_host_params(). - */ - s->fl_pg_order = FL_PG_ORDER; - if (s->fl_pg_order) - t4_write_reg(adap, - SGE_FL_BUFFER_SIZE0+RX_LARGE_PG_BUF*sizeof(u32), - PAGE_SIZE << FL_PG_ORDER); - t4_write_reg(adap, SGE_FL_BUFFER_SIZE0+RX_SMALL_MTU_BUF*sizeof(u32), - FL_MTU_SMALL_BUFSIZE(adap)); - t4_write_reg(adap, SGE_FL_BUFFER_SIZE0+RX_LARGE_MTU_BUF*sizeof(u32), - FL_MTU_LARGE_BUFSIZE(adap)); - - /* - * Note that the SGE Ingress Packet Count Interrupt Threshold and - * Timer Holdoff values must be supplied by our caller. - */ - t4_write_reg(adap, SGE_INGRESS_RX_THRESHOLD, - THRESHOLD_0(s->counter_val[0]) | - THRESHOLD_1(s->counter_val[1]) | - THRESHOLD_2(s->counter_val[2]) | - THRESHOLD_3(s->counter_val[3])); - t4_write_reg(adap, SGE_TIMER_VALUE_0_AND_1, - TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[0])) | - TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[1]))); - t4_write_reg(adap, SGE_TIMER_VALUE_2_AND_3, - TIMERVALUE2(us_to_core_ticks(adap, s->timer_val[2])) | - TIMERVALUE3(us_to_core_ticks(adap, s->timer_val[3]))); - t4_write_reg(adap, SGE_TIMER_VALUE_4_AND_5, - TIMERVALUE4(us_to_core_ticks(adap, s->timer_val[4])) | - TIMERVALUE5(us_to_core_ticks(adap, s->timer_val[5]))); + ingress_rx_threshold = t4_read_reg(adap, SGE_INGRESS_RX_THRESHOLD_A); + s->counter_val[0] = THRESHOLD_0_G(ingress_rx_threshold); + s->counter_val[1] = THRESHOLD_1_G(ingress_rx_threshold); + s->counter_val[2] = THRESHOLD_2_G(ingress_rx_threshold); + s->counter_val[3] = THRESHOLD_3_G(ingress_rx_threshold); return 0; } +/** + * t4_sge_init - initialize SGE + * @adap: the adapter + * + * Perform low-level SGE code initialization needed every time after a + * chip reset. + */ int t4_sge_init(struct adapter *adap) { struct sge *s = &adap->sge; @@ -2927,9 +2902,9 @@ int t4_sge_init(struct adapter *adap) * Ingress Padding Boundary and Egress Status Page Size are set up by * t4_fixup_host_params(). */ - sge_control = t4_read_reg(adap, SGE_CONTROL); - s->pktshift = PKTSHIFT_GET(sge_control); - s->stat_len = (sge_control & EGRSTATUSPAGESIZE_MASK) ? 128 : 64; + sge_control = t4_read_reg(adap, SGE_CONTROL_A); + s->pktshift = PKTSHIFT_G(sge_control); + s->stat_len = (sge_control & EGRSTATUSPAGESIZE_F) ? 128 : 64; /* T4 uses a single control field to specify both the PCIe Padding and * Packing Boundary. T5 introduced the ability to specify these @@ -2937,8 +2912,8 @@ int t4_sge_init(struct adapter *adap) * within Packed Buffer Mode is the maximum of these two * specifications. */ - ingpadboundary = 1 << (INGPADBOUNDARY_GET(sge_control) + - X_INGPADBOUNDARY_SHIFT); + ingpadboundary = 1 << (INGPADBOUNDARY_G(sge_control) + + INGPADBOUNDARY_SHIFT_X); if (is_t4(adap->params.chip)) { s->fl_align = ingpadboundary; } else { @@ -2956,10 +2931,7 @@ int t4_sge_init(struct adapter *adap) s->fl_align = max(ingpadboundary, ingpackboundary); } - if (adap->flags & USING_SOFT_PARAMS) - ret = t4_sge_init_soft(adap); - else - ret = t4_sge_init_hard(adap); + ret = t4_sge_init_soft(adap); if (ret < 0) return ret; @@ -2975,11 +2947,11 @@ int t4_sge_init(struct adapter *adap) * buffers and a new field which only applies to Packed Mode Free List * buffers. */ - sge_conm_ctrl = t4_read_reg(adap, SGE_CONM_CTRL); + sge_conm_ctrl = t4_read_reg(adap, SGE_CONM_CTRL_A); if (is_t4(adap->params.chip)) - egress_threshold = EGRTHRESHOLD_GET(sge_conm_ctrl); + egress_threshold = EGRTHRESHOLD_G(sge_conm_ctrl); else - egress_threshold = EGRTHRESHOLDPACKING_GET(sge_conm_ctrl); + egress_threshold = EGRTHRESHOLDPACKING_G(sge_conm_ctrl); s->fl_starve_thres = 2*egress_threshold + 1; setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adap); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index c132d9030729..4d643b65265e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -35,6 +35,7 @@ #include #include "cxgb4.h" #include "t4_regs.h" +#include "t4_values.h" #include "t4fw_api.h" /** @@ -149,20 +150,20 @@ void t4_write_indirect(struct adapter *adap, unsigned int addr_reg, */ void t4_hw_pci_read_cfg4(struct adapter *adap, int reg, u32 *val) { - u32 req = ENABLE | FUNCTION(adap->fn) | reg; + u32 req = ENABLE_F | FUNCTION_V(adap->fn) | REGISTER_V(reg); if (is_t4(adap->params.chip)) - req |= F_LOCALCFG; + req |= LOCALCFG_F; - t4_write_reg(adap, PCIE_CFG_SPACE_REQ, req); - *val = t4_read_reg(adap, PCIE_CFG_SPACE_DATA); + t4_write_reg(adap, PCIE_CFG_SPACE_REQ_A, req); + *val = t4_read_reg(adap, PCIE_CFG_SPACE_DATA_A); /* Reset ENABLE to 0 so reads of PCIE_CFG_SPACE_DATA won't cause a * Configuration Space read. (None of the other fields matter when * ENABLE is 0 so a simple register write is easier than a * read-modify-write via t4_set_reg_field().) */ - t4_write_reg(adap, PCIE_CFG_SPACE_REQ, 0); + t4_write_reg(adap, PCIE_CFG_SPACE_REQ_A, 0); } /* @@ -187,8 +188,8 @@ static void t4_report_fw_error(struct adapter *adap) }; u32 pcie_fw; - pcie_fw = t4_read_reg(adap, MA_PCIE_FW); - if (pcie_fw & PCIE_FW_ERR) + pcie_fw = t4_read_reg(adap, PCIE_FW_A); + if (pcie_fw & PCIE_FW_ERR_F) dev_err(adap->pdev_dev, "Firmware reports adapter error: %s\n", reason[PCIE_FW_EVAL_G(pcie_fw)]); } @@ -264,8 +265,8 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, u64 res; int i, ms, delay_idx; const __be64 *p = cmd; - u32 data_reg = PF_REG(mbox, CIM_PF_MAILBOX_DATA); - u32 ctl_reg = PF_REG(mbox, CIM_PF_MAILBOX_CTRL); + u32 data_reg = PF_REG(mbox, CIM_PF_MAILBOX_DATA_A); + u32 ctl_reg = PF_REG(mbox, CIM_PF_MAILBOX_CTRL_A); if ((size & 15) || size > MBOX_LEN) return -EINVAL; @@ -277,9 +278,9 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, if (adap->pdev->error_state != pci_channel_io_normal) return -EIO; - v = MBOWNER_GET(t4_read_reg(adap, ctl_reg)); + v = MBOWNER_G(t4_read_reg(adap, ctl_reg)); for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++) - v = MBOWNER_GET(t4_read_reg(adap, ctl_reg)); + v = MBOWNER_G(t4_read_reg(adap, ctl_reg)); if (v != MBOX_OWNER_DRV) return v ? -EBUSY : -ETIMEDOUT; @@ -287,7 +288,7 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, for (i = 0; i < size; i += 8) t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p++)); - t4_write_reg(adap, ctl_reg, MBMSGVALID | MBOWNER(MBOX_OWNER_FW)); + t4_write_reg(adap, ctl_reg, MBMSGVALID_F | MBOWNER_V(MBOX_OWNER_FW)); t4_read_reg(adap, ctl_reg); /* flush write */ delay_idx = 0; @@ -303,8 +304,8 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, mdelay(ms); v = t4_read_reg(adap, ctl_reg); - if (MBOWNER_GET(v) == MBOX_OWNER_DRV) { - if (!(v & MBMSGVALID)) { + if (MBOWNER_G(v) == MBOX_OWNER_DRV) { + if (!(v & MBMSGVALID_F)) { t4_write_reg(adap, ctl_reg, 0); continue; } @@ -350,27 +351,27 @@ int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc) u32 mc_bist_status_rdata, mc_bist_data_pattern; if (is_t4(adap->params.chip)) { - mc_bist_cmd = MC_BIST_CMD; - mc_bist_cmd_addr = MC_BIST_CMD_ADDR; - mc_bist_cmd_len = MC_BIST_CMD_LEN; - mc_bist_status_rdata = MC_BIST_STATUS_RDATA; - mc_bist_data_pattern = MC_BIST_DATA_PATTERN; + mc_bist_cmd = MC_BIST_CMD_A; + mc_bist_cmd_addr = MC_BIST_CMD_ADDR_A; + mc_bist_cmd_len = MC_BIST_CMD_LEN_A; + mc_bist_status_rdata = MC_BIST_STATUS_RDATA_A; + mc_bist_data_pattern = MC_BIST_DATA_PATTERN_A; } else { - mc_bist_cmd = MC_REG(MC_P_BIST_CMD, idx); - mc_bist_cmd_addr = MC_REG(MC_P_BIST_CMD_ADDR, idx); - mc_bist_cmd_len = MC_REG(MC_P_BIST_CMD_LEN, idx); - mc_bist_status_rdata = MC_REG(MC_P_BIST_STATUS_RDATA, idx); - mc_bist_data_pattern = MC_REG(MC_P_BIST_DATA_PATTERN, idx); + mc_bist_cmd = MC_REG(MC_P_BIST_CMD_A, idx); + mc_bist_cmd_addr = MC_REG(MC_P_BIST_CMD_ADDR_A, idx); + mc_bist_cmd_len = MC_REG(MC_P_BIST_CMD_LEN_A, idx); + mc_bist_status_rdata = MC_REG(MC_P_BIST_STATUS_RDATA_A, idx); + mc_bist_data_pattern = MC_REG(MC_P_BIST_DATA_PATTERN_A, idx); } - if (t4_read_reg(adap, mc_bist_cmd) & START_BIST) + if (t4_read_reg(adap, mc_bist_cmd) & START_BIST_F) return -EBUSY; t4_write_reg(adap, mc_bist_cmd_addr, addr & ~0x3fU); t4_write_reg(adap, mc_bist_cmd_len, 64); t4_write_reg(adap, mc_bist_data_pattern, 0xc); - t4_write_reg(adap, mc_bist_cmd, BIST_OPCODE(1) | START_BIST | - BIST_CMD_GAP(1)); - i = t4_wait_op_done(adap, mc_bist_cmd, START_BIST, 0, 10, 1); + t4_write_reg(adap, mc_bist_cmd, BIST_OPCODE_V(1) | START_BIST_F | + BIST_CMD_GAP_V(1)); + i = t4_wait_op_done(adap, mc_bist_cmd, START_BIST_F, 0, 10, 1); if (i) return i; @@ -403,31 +404,31 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc) u32 edc_bist_cmd_data_pattern, edc_bist_status_rdata; if (is_t4(adap->params.chip)) { - edc_bist_cmd = EDC_REG(EDC_BIST_CMD, idx); - edc_bist_cmd_addr = EDC_REG(EDC_BIST_CMD_ADDR, idx); - edc_bist_cmd_len = EDC_REG(EDC_BIST_CMD_LEN, idx); - edc_bist_cmd_data_pattern = EDC_REG(EDC_BIST_DATA_PATTERN, - idx); - edc_bist_status_rdata = EDC_REG(EDC_BIST_STATUS_RDATA, + edc_bist_cmd = EDC_REG(EDC_BIST_CMD_A, idx); + edc_bist_cmd_addr = EDC_REG(EDC_BIST_CMD_ADDR_A, idx); + edc_bist_cmd_len = EDC_REG(EDC_BIST_CMD_LEN_A, idx); + edc_bist_cmd_data_pattern = EDC_REG(EDC_BIST_DATA_PATTERN_A, idx); + edc_bist_status_rdata = EDC_REG(EDC_BIST_STATUS_RDATA_A, + idx); } else { - edc_bist_cmd = EDC_REG_T5(EDC_H_BIST_CMD, idx); - edc_bist_cmd_addr = EDC_REG_T5(EDC_H_BIST_CMD_ADDR, idx); - edc_bist_cmd_len = EDC_REG_T5(EDC_H_BIST_CMD_LEN, idx); + edc_bist_cmd = EDC_REG_T5(EDC_H_BIST_CMD_A, idx); + edc_bist_cmd_addr = EDC_REG_T5(EDC_H_BIST_CMD_ADDR_A, idx); + edc_bist_cmd_len = EDC_REG_T5(EDC_H_BIST_CMD_LEN_A, idx); edc_bist_cmd_data_pattern = - EDC_REG_T5(EDC_H_BIST_DATA_PATTERN, idx); + EDC_REG_T5(EDC_H_BIST_DATA_PATTERN_A, idx); edc_bist_status_rdata = - EDC_REG_T5(EDC_H_BIST_STATUS_RDATA, idx); + EDC_REG_T5(EDC_H_BIST_STATUS_RDATA_A, idx); } - if (t4_read_reg(adap, edc_bist_cmd) & START_BIST) + if (t4_read_reg(adap, edc_bist_cmd) & START_BIST_F) return -EBUSY; t4_write_reg(adap, edc_bist_cmd_addr, addr & ~0x3fU); t4_write_reg(adap, edc_bist_cmd_len, 64); t4_write_reg(adap, edc_bist_cmd_data_pattern, 0xc); t4_write_reg(adap, edc_bist_cmd, - BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST); - i = t4_wait_op_done(adap, edc_bist_cmd, START_BIST, 0, 10, 1); + BIST_OPCODE_V(1) | BIST_CMD_GAP_V(1) | START_BIST_F); + i = t4_wait_op_done(adap, edc_bist_cmd, START_BIST_F, 0, 10, 1); if (i) return i; @@ -505,13 +506,13 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, * the address is relative to BAR0. */ mem_reg = t4_read_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, win)); - mem_aperture = 1 << (GET_WINDOW(mem_reg) + 10); - mem_base = GET_PCIEOFST(mem_reg) << 10; + mem_aperture = 1 << (WINDOW_G(mem_reg) + WINDOW_SHIFT_X); + mem_base = PCIEOFST_G(mem_reg) << PCIEOFST_SHIFT_X; if (is_t4(adap->params.chip)) mem_base -= adap->t4_bar0; - win_pf = is_t4(adap->params.chip) ? 0 : V_PFNUM(adap->fn); + win_pf = is_t4(adap->params.chip) ? 0 : PFNUM_V(adap->fn); /* Calculate our initial PCI-E Memory Window Position and Offset into * that Window. @@ -524,10 +525,10 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, * attempt to use the new value.) */ t4_write_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win), + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win), pos | win_pf); t4_read_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win)); + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win)); /* Transfer data to/from the adapter as long as there's an integral * number of 32-bit transfers to complete. @@ -552,11 +553,11 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, pos += mem_aperture; offset = 0; t4_write_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, - win), pos | win_pf); + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, + win), pos | win_pf); t4_read_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, - win)); + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, + win)); } } @@ -760,14 +761,13 @@ static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont, if (!byte_cnt || byte_cnt > 4) return -EINVAL; - if (t4_read_reg(adapter, SF_OP) & SF_BUSY) + if (t4_read_reg(adapter, SF_OP_A) & SF_BUSY_F) return -EBUSY; - cont = cont ? SF_CONT : 0; - lock = lock ? SF_LOCK : 0; - t4_write_reg(adapter, SF_OP, lock | cont | BYTECNT(byte_cnt - 1)); - ret = t4_wait_op_done(adapter, SF_OP, SF_BUSY, 0, SF_ATTEMPTS, 5); + t4_write_reg(adapter, SF_OP_A, SF_LOCK_V(lock) | + SF_CONT_V(cont) | BYTECNT_V(byte_cnt - 1)); + ret = t4_wait_op_done(adapter, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, 5); if (!ret) - *valp = t4_read_reg(adapter, SF_DATA); + *valp = t4_read_reg(adapter, SF_DATA_A); return ret; } @@ -788,14 +788,12 @@ static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont, { if (!byte_cnt || byte_cnt > 4) return -EINVAL; - if (t4_read_reg(adapter, SF_OP) & SF_BUSY) + if (t4_read_reg(adapter, SF_OP_A) & SF_BUSY_F) return -EBUSY; - cont = cont ? SF_CONT : 0; - lock = lock ? SF_LOCK : 0; - t4_write_reg(adapter, SF_DATA, val); - t4_write_reg(adapter, SF_OP, lock | - cont | BYTECNT(byte_cnt - 1) | OP_WR); - return t4_wait_op_done(adapter, SF_OP, SF_BUSY, 0, SF_ATTEMPTS, 5); + t4_write_reg(adapter, SF_DATA_A, val); + t4_write_reg(adapter, SF_OP_A, SF_LOCK_V(lock) | + SF_CONT_V(cont) | BYTECNT_V(byte_cnt - 1) | OP_V(1)); + return t4_wait_op_done(adapter, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, 5); } /** @@ -837,8 +835,8 @@ static int flash_wait_op(struct adapter *adapter, int attempts, int delay) * (i.e., big-endian), otherwise as 32-bit words in the platform's * natural endianess. */ -static int t4_read_flash(struct adapter *adapter, unsigned int addr, - unsigned int nwords, u32 *data, int byte_oriented) +int t4_read_flash(struct adapter *adapter, unsigned int addr, + unsigned int nwords, u32 *data, int byte_oriented) { int ret; @@ -854,7 +852,7 @@ static int t4_read_flash(struct adapter *adapter, unsigned int addr, for ( ; nwords; nwords--, data++) { ret = sf1_read(adapter, 4, nwords > 1, nwords == 1, data); if (nwords == 1) - t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ + t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */ if (ret) return ret; if (byte_oriented) @@ -902,7 +900,7 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr, if (ret) goto unlock; - t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ + t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */ /* Read the page to verify the write succeeded */ ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1); @@ -918,7 +916,7 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr, return 0; unlock: - t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ + t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */ return ret; } @@ -950,6 +948,43 @@ int t4_get_tp_version(struct adapter *adapter, u32 *vers) 1, vers, 0); } +/** + * t4_get_exprom_version - return the Expansion ROM version (if any) + * @adapter: the adapter + * @vers: where to place the version + * + * Reads the Expansion ROM header from FLASH and returns the version + * number (if present) through the @vers return value pointer. We return + * this in the Firmware Version Format since it's convenient. Return + * 0 on success, -ENOENT if no Expansion ROM is present. + */ +int t4_get_exprom_version(struct adapter *adap, u32 *vers) +{ + struct exprom_header { + unsigned char hdr_arr[16]; /* must start with 0x55aa */ + unsigned char hdr_ver[4]; /* Expansion ROM version */ + } *hdr; + u32 exprom_header_buf[DIV_ROUND_UP(sizeof(struct exprom_header), + sizeof(u32))]; + int ret; + + ret = t4_read_flash(adap, FLASH_EXP_ROM_START, + ARRAY_SIZE(exprom_header_buf), exprom_header_buf, + 0); + if (ret) + return ret; + + hdr = (struct exprom_header *)exprom_header_buf; + if (hdr->hdr_arr[0] != 0x55 || hdr->hdr_arr[1] != 0xaa) + return -ENOENT; + + *vers = (FW_HDR_FW_VER_MAJOR_V(hdr->hdr_ver[0]) | + FW_HDR_FW_VER_MINOR_V(hdr->hdr_ver[1]) | + FW_HDR_FW_VER_MICRO_V(hdr->hdr_ver[2]) | + FW_HDR_FW_VER_BUILD_V(hdr->hdr_ver[3])); + return 0; +} + /* Is the given firmware API compatible with the one the driver was compiled * with? */ @@ -1113,7 +1148,7 @@ static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end) } start++; } - t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ + t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */ return ret; } @@ -1241,6 +1276,45 @@ out: return ret; } +/** + * t4_fwcache - firmware cache operation + * @adap: the adapter + * @op : the operation (flush or flush and invalidate) + */ +int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op) +{ + struct fw_params_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = + cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) | + FW_CMD_REQUEST_F | FW_CMD_WRITE_F | + FW_PARAMS_CMD_PFN_V(adap->fn) | + FW_PARAMS_CMD_VFN_V(0)); + c.retval_len16 = cpu_to_be32(FW_LEN16(c)); + c.param[0].mnem = + cpu_to_be32(FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_FWCACHE)); + c.param[0].val = (__force __be32)op; + + return t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), NULL); +} + +void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf) +{ + unsigned int i, j; + + for (i = 0; i < 8; i++) { + u32 *p = la_buf + i; + + t4_write_reg(adap, ULP_RX_LA_CTL_A, i); + j = t4_read_reg(adap, ULP_RX_LA_WRPTR_A); + t4_write_reg(adap, ULP_RX_LA_RDPTR_A, j); + for (j = 0; j < ULPRX_LA_SIZE; j++, p += 8) + *p = t4_read_reg(adap, ULP_RX_LA_RDDATA_A); + } +} + #define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \ FW_PORT_CAP_ANEG) @@ -1365,95 +1439,97 @@ static int t4_handle_intr_status(struct adapter *adapter, unsigned int reg, static void pcie_intr_handler(struct adapter *adapter) { static const struct intr_info sysbus_intr_info[] = { - { RNPP, "RXNP array parity error", -1, 1 }, - { RPCP, "RXPC array parity error", -1, 1 }, - { RCIP, "RXCIF array parity error", -1, 1 }, - { RCCP, "Rx completions control array parity error", -1, 1 }, - { RFTP, "RXFT array parity error", -1, 1 }, + { RNPP_F, "RXNP array parity error", -1, 1 }, + { RPCP_F, "RXPC array parity error", -1, 1 }, + { RCIP_F, "RXCIF array parity error", -1, 1 }, + { RCCP_F, "Rx completions control array parity error", -1, 1 }, + { RFTP_F, "RXFT array parity error", -1, 1 }, { 0 } }; static const struct intr_info pcie_port_intr_info[] = { - { TPCP, "TXPC array parity error", -1, 1 }, - { TNPP, "TXNP array parity error", -1, 1 }, - { TFTP, "TXFT array parity error", -1, 1 }, - { TCAP, "TXCA array parity error", -1, 1 }, - { TCIP, "TXCIF array parity error", -1, 1 }, - { RCAP, "RXCA array parity error", -1, 1 }, - { OTDD, "outbound request TLP discarded", -1, 1 }, - { RDPE, "Rx data parity error", -1, 1 }, - { TDUE, "Tx uncorrectable data error", -1, 1 }, + { TPCP_F, "TXPC array parity error", -1, 1 }, + { TNPP_F, "TXNP array parity error", -1, 1 }, + { TFTP_F, "TXFT array parity error", -1, 1 }, + { TCAP_F, "TXCA array parity error", -1, 1 }, + { TCIP_F, "TXCIF array parity error", -1, 1 }, + { RCAP_F, "RXCA array parity error", -1, 1 }, + { OTDD_F, "outbound request TLP discarded", -1, 1 }, + { RDPE_F, "Rx data parity error", -1, 1 }, + { TDUE_F, "Tx uncorrectable data error", -1, 1 }, { 0 } }; static const struct intr_info pcie_intr_info[] = { - { MSIADDRLPERR, "MSI AddrL parity error", -1, 1 }, - { MSIADDRHPERR, "MSI AddrH parity error", -1, 1 }, - { MSIDATAPERR, "MSI data parity error", -1, 1 }, - { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 }, - { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 }, - { MSIXDATAPERR, "MSI-X data parity error", -1, 1 }, - { MSIXDIPERR, "MSI-X DI parity error", -1, 1 }, - { PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 }, - { PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 }, - { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 }, - { CCNTPERR, "PCI CMD channel count parity error", -1, 1 }, - { CREQPERR, "PCI CMD channel request parity error", -1, 1 }, - { CRSPPERR, "PCI CMD channel response parity error", -1, 1 }, - { DCNTPERR, "PCI DMA channel count parity error", -1, 1 }, - { DREQPERR, "PCI DMA channel request parity error", -1, 1 }, - { DRSPPERR, "PCI DMA channel response parity error", -1, 1 }, - { HCNTPERR, "PCI HMA channel count parity error", -1, 1 }, - { HREQPERR, "PCI HMA channel request parity error", -1, 1 }, - { HRSPPERR, "PCI HMA channel response parity error", -1, 1 }, - { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 }, - { FIDPERR, "PCI FID parity error", -1, 1 }, - { INTXCLRPERR, "PCI INTx clear parity error", -1, 1 }, - { MATAGPERR, "PCI MA tag parity error", -1, 1 }, - { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 }, - { RXCPLPERR, "PCI Rx completion parity error", -1, 1 }, - { RXWRPERR, "PCI Rx write parity error", -1, 1 }, - { RPLPERR, "PCI replay buffer parity error", -1, 1 }, - { PCIESINT, "PCI core secondary fault", -1, 1 }, - { PCIEPINT, "PCI core primary fault", -1, 1 }, - { UNXSPLCPLERR, "PCI unexpected split completion error", -1, 0 }, + { MSIADDRLPERR_F, "MSI AddrL parity error", -1, 1 }, + { MSIADDRHPERR_F, "MSI AddrH parity error", -1, 1 }, + { MSIDATAPERR_F, "MSI data parity error", -1, 1 }, + { MSIXADDRLPERR_F, "MSI-X AddrL parity error", -1, 1 }, + { MSIXADDRHPERR_F, "MSI-X AddrH parity error", -1, 1 }, + { MSIXDATAPERR_F, "MSI-X data parity error", -1, 1 }, + { MSIXDIPERR_F, "MSI-X DI parity error", -1, 1 }, + { PIOCPLPERR_F, "PCI PIO completion FIFO parity error", -1, 1 }, + { PIOREQPERR_F, "PCI PIO request FIFO parity error", -1, 1 }, + { TARTAGPERR_F, "PCI PCI target tag FIFO parity error", -1, 1 }, + { CCNTPERR_F, "PCI CMD channel count parity error", -1, 1 }, + { CREQPERR_F, "PCI CMD channel request parity error", -1, 1 }, + { CRSPPERR_F, "PCI CMD channel response parity error", -1, 1 }, + { DCNTPERR_F, "PCI DMA channel count parity error", -1, 1 }, + { DREQPERR_F, "PCI DMA channel request parity error", -1, 1 }, + { DRSPPERR_F, "PCI DMA channel response parity error", -1, 1 }, + { HCNTPERR_F, "PCI HMA channel count parity error", -1, 1 }, + { HREQPERR_F, "PCI HMA channel request parity error", -1, 1 }, + { HRSPPERR_F, "PCI HMA channel response parity error", -1, 1 }, + { CFGSNPPERR_F, "PCI config snoop FIFO parity error", -1, 1 }, + { FIDPERR_F, "PCI FID parity error", -1, 1 }, + { INTXCLRPERR_F, "PCI INTx clear parity error", -1, 1 }, + { MATAGPERR_F, "PCI MA tag parity error", -1, 1 }, + { PIOTAGPERR_F, "PCI PIO tag parity error", -1, 1 }, + { RXCPLPERR_F, "PCI Rx completion parity error", -1, 1 }, + { RXWRPERR_F, "PCI Rx write parity error", -1, 1 }, + { RPLPERR_F, "PCI replay buffer parity error", -1, 1 }, + { PCIESINT_F, "PCI core secondary fault", -1, 1 }, + { PCIEPINT_F, "PCI core primary fault", -1, 1 }, + { UNXSPLCPLERR_F, "PCI unexpected split completion error", + -1, 0 }, { 0 } }; static struct intr_info t5_pcie_intr_info[] = { - { MSTGRPPERR, "Master Response Read Queue parity error", + { MSTGRPPERR_F, "Master Response Read Queue parity error", -1, 1 }, - { MSTTIMEOUTPERR, "Master Timeout FIFO parity error", -1, 1 }, - { MSIXSTIPERR, "MSI-X STI SRAM parity error", -1, 1 }, - { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 }, - { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 }, - { MSIXDATAPERR, "MSI-X data parity error", -1, 1 }, - { MSIXDIPERR, "MSI-X DI parity error", -1, 1 }, - { PIOCPLGRPPERR, "PCI PIO completion Group FIFO parity error", + { MSTTIMEOUTPERR_F, "Master Timeout FIFO parity error", -1, 1 }, + { MSIXSTIPERR_F, "MSI-X STI SRAM parity error", -1, 1 }, + { MSIXADDRLPERR_F, "MSI-X AddrL parity error", -1, 1 }, + { MSIXADDRHPERR_F, "MSI-X AddrH parity error", -1, 1 }, + { MSIXDATAPERR_F, "MSI-X data parity error", -1, 1 }, + { MSIXDIPERR_F, "MSI-X DI parity error", -1, 1 }, + { PIOCPLGRPPERR_F, "PCI PIO completion Group FIFO parity error", -1, 1 }, - { PIOREQGRPPERR, "PCI PIO request Group FIFO parity error", + { PIOREQGRPPERR_F, "PCI PIO request Group FIFO parity error", -1, 1 }, - { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 }, - { MSTTAGQPERR, "PCI master tag queue parity error", -1, 1 }, - { CREQPERR, "PCI CMD channel request parity error", -1, 1 }, - { CRSPPERR, "PCI CMD channel response parity error", -1, 1 }, - { DREQWRPERR, "PCI DMA channel write request parity error", + { TARTAGPERR_F, "PCI PCI target tag FIFO parity error", -1, 1 }, + { MSTTAGQPERR_F, "PCI master tag queue parity error", -1, 1 }, + { CREQPERR_F, "PCI CMD channel request parity error", -1, 1 }, + { CRSPPERR_F, "PCI CMD channel response parity error", -1, 1 }, + { DREQWRPERR_F, "PCI DMA channel write request parity error", -1, 1 }, - { DREQPERR, "PCI DMA channel request parity error", -1, 1 }, - { DRSPPERR, "PCI DMA channel response parity error", -1, 1 }, - { HREQWRPERR, "PCI HMA channel count parity error", -1, 1 }, - { HREQPERR, "PCI HMA channel request parity error", -1, 1 }, - { HRSPPERR, "PCI HMA channel response parity error", -1, 1 }, - { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 }, - { FIDPERR, "PCI FID parity error", -1, 1 }, - { VFIDPERR, "PCI INTx clear parity error", -1, 1 }, - { MAGRPPERR, "PCI MA group FIFO parity error", -1, 1 }, - { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 }, - { IPRXHDRGRPPERR, "PCI IP Rx header group parity error", + { DREQPERR_F, "PCI DMA channel request parity error", -1, 1 }, + { DRSPPERR_F, "PCI DMA channel response parity error", -1, 1 }, + { HREQWRPERR_F, "PCI HMA channel count parity error", -1, 1 }, + { HREQPERR_F, "PCI HMA channel request parity error", -1, 1 }, + { HRSPPERR_F, "PCI HMA channel response parity error", -1, 1 }, + { CFGSNPPERR_F, "PCI config snoop FIFO parity error", -1, 1 }, + { FIDPERR_F, "PCI FID parity error", -1, 1 }, + { VFIDPERR_F, "PCI INTx clear parity error", -1, 1 }, + { MAGRPPERR_F, "PCI MA group FIFO parity error", -1, 1 }, + { PIOTAGPERR_F, "PCI PIO tag parity error", -1, 1 }, + { IPRXHDRGRPPERR_F, "PCI IP Rx header group parity error", -1, 1 }, - { IPRXDATAGRPPERR, "PCI IP Rx data group parity error", -1, 1 }, - { RPLPERR, "PCI IP replay buffer parity error", -1, 1 }, - { IPSOTPERR, "PCI IP SOT buffer parity error", -1, 1 }, - { TRGT1GRPPERR, "PCI TRGT1 group FIFOs parity error", -1, 1 }, - { READRSPERR, "Outbound read error", -1, 0 }, + { IPRXDATAGRPPERR_F, "PCI IP Rx data group parity error", + -1, 1 }, + { RPLPERR_F, "PCI IP replay buffer parity error", -1, 1 }, + { IPSOTPERR_F, "PCI IP SOT buffer parity error", -1, 1 }, + { TRGT1GRPPERR_F, "PCI TRGT1 group FIFOs parity error", -1, 1 }, + { READRSPERR_F, "Outbound read error", -1, 0 }, { 0 } }; @@ -1461,15 +1537,15 @@ static void pcie_intr_handler(struct adapter *adapter) if (is_t4(adapter->params.chip)) fat = t4_handle_intr_status(adapter, - PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS, - sysbus_intr_info) + + PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS_A, + sysbus_intr_info) + t4_handle_intr_status(adapter, - PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS, - pcie_port_intr_info) + - t4_handle_intr_status(adapter, PCIE_INT_CAUSE, + PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS_A, + pcie_port_intr_info) + + t4_handle_intr_status(adapter, PCIE_INT_CAUSE_A, pcie_intr_info); else - fat = t4_handle_intr_status(adapter, PCIE_INT_CAUSE, + fat = t4_handle_intr_status(adapter, PCIE_INT_CAUSE_A, t5_pcie_intr_info); if (fat) @@ -1483,11 +1559,11 @@ static void tp_intr_handler(struct adapter *adapter) { static const struct intr_info tp_intr_info[] = { { 0x3fffffff, "TP parity error", -1, 1 }, - { FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 }, + { FLMTXFLSTEMPTY_F, "TP out of Tx pages", -1, 1 }, { 0 } }; - if (t4_handle_intr_status(adapter, TP_INT_CAUSE, tp_intr_info)) + if (t4_handle_intr_status(adapter, TP_INT_CAUSE_A, tp_intr_info)) t4_fatal_err(adapter); } @@ -1499,102 +1575,107 @@ static void sge_intr_handler(struct adapter *adapter) u64 v; static const struct intr_info sge_intr_info[] = { - { ERR_CPL_EXCEED_IQE_SIZE, + { ERR_CPL_EXCEED_IQE_SIZE_F, "SGE received CPL exceeding IQE size", -1, 1 }, - { ERR_INVALID_CIDX_INC, + { ERR_INVALID_CIDX_INC_F, "SGE GTS CIDX increment too large", -1, 0 }, - { ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 }, - { DBFIFO_LP_INT, NULL, -1, 0, t4_db_full }, - { DBFIFO_HP_INT, NULL, -1, 0, t4_db_full }, - { ERR_DROPPED_DB, NULL, -1, 0, t4_db_dropped }, - { ERR_DATA_CPL_ON_HIGH_QID1 | ERR_DATA_CPL_ON_HIGH_QID0, + { ERR_CPL_OPCODE_0_F, "SGE received 0-length CPL", -1, 0 }, + { DBFIFO_LP_INT_F, NULL, -1, 0, t4_db_full }, + { DBFIFO_HP_INT_F, NULL, -1, 0, t4_db_full }, + { ERR_DROPPED_DB_F, NULL, -1, 0, t4_db_dropped }, + { ERR_DATA_CPL_ON_HIGH_QID1_F | ERR_DATA_CPL_ON_HIGH_QID0_F, "SGE IQID > 1023 received CPL for FL", -1, 0 }, - { ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1, + { ERR_BAD_DB_PIDX3_F, "SGE DBP 3 pidx increment too large", -1, 0 }, - { ERR_BAD_DB_PIDX2, "SGE DBP 2 pidx increment too large", -1, + { ERR_BAD_DB_PIDX2_F, "SGE DBP 2 pidx increment too large", -1, 0 }, - { ERR_BAD_DB_PIDX1, "SGE DBP 1 pidx increment too large", -1, + { ERR_BAD_DB_PIDX1_F, "SGE DBP 1 pidx increment too large", -1, 0 }, - { ERR_BAD_DB_PIDX0, "SGE DBP 0 pidx increment too large", -1, + { ERR_BAD_DB_PIDX0_F, "SGE DBP 0 pidx increment too large", -1, 0 }, - { ERR_ING_CTXT_PRIO, + { ERR_ING_CTXT_PRIO_F, "SGE too many priority ingress contexts", -1, 0 }, - { ERR_EGR_CTXT_PRIO, + { ERR_EGR_CTXT_PRIO_F, "SGE too many priority egress contexts", -1, 0 }, - { INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 }, - { EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 }, + { INGRESS_SIZE_ERR_F, "SGE illegal ingress QID", -1, 0 }, + { EGRESS_SIZE_ERR_F, "SGE illegal egress QID", -1, 0 }, { 0 } }; - v = (u64)t4_read_reg(adapter, SGE_INT_CAUSE1) | - ((u64)t4_read_reg(adapter, SGE_INT_CAUSE2) << 32); + v = (u64)t4_read_reg(adapter, SGE_INT_CAUSE1_A) | + ((u64)t4_read_reg(adapter, SGE_INT_CAUSE2_A) << 32); if (v) { dev_alert(adapter->pdev_dev, "SGE parity error (%#llx)\n", (unsigned long long)v); - t4_write_reg(adapter, SGE_INT_CAUSE1, v); - t4_write_reg(adapter, SGE_INT_CAUSE2, v >> 32); + t4_write_reg(adapter, SGE_INT_CAUSE1_A, v); + t4_write_reg(adapter, SGE_INT_CAUSE2_A, v >> 32); } - if (t4_handle_intr_status(adapter, SGE_INT_CAUSE3, sge_intr_info) || + if (t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A, sge_intr_info) || v != 0) t4_fatal_err(adapter); } +#define CIM_OBQ_INTR (OBQULP0PARERR_F | OBQULP1PARERR_F | OBQULP2PARERR_F |\ + OBQULP3PARERR_F | OBQSGEPARERR_F | OBQNCSIPARERR_F) +#define CIM_IBQ_INTR (IBQTP0PARERR_F | IBQTP1PARERR_F | IBQULPPARERR_F |\ + IBQSGEHIPARERR_F | IBQSGELOPARERR_F | IBQNCSIPARERR_F) + /* * CIM interrupt handler. */ static void cim_intr_handler(struct adapter *adapter) { static const struct intr_info cim_intr_info[] = { - { PREFDROPINT, "CIM control register prefetch drop", -1, 1 }, - { OBQPARERR, "CIM OBQ parity error", -1, 1 }, - { IBQPARERR, "CIM IBQ parity error", -1, 1 }, - { MBUPPARERR, "CIM mailbox uP parity error", -1, 1 }, - { MBHOSTPARERR, "CIM mailbox host parity error", -1, 1 }, - { TIEQINPARERRINT, "CIM TIEQ outgoing parity error", -1, 1 }, - { TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 }, + { PREFDROPINT_F, "CIM control register prefetch drop", -1, 1 }, + { CIM_OBQ_INTR, "CIM OBQ parity error", -1, 1 }, + { CIM_IBQ_INTR, "CIM IBQ parity error", -1, 1 }, + { MBUPPARERR_F, "CIM mailbox uP parity error", -1, 1 }, + { MBHOSTPARERR_F, "CIM mailbox host parity error", -1, 1 }, + { TIEQINPARERRINT_F, "CIM TIEQ outgoing parity error", -1, 1 }, + { TIEQOUTPARERRINT_F, "CIM TIEQ incoming parity error", -1, 1 }, { 0 } }; static const struct intr_info cim_upintr_info[] = { - { RSVDSPACEINT, "CIM reserved space access", -1, 1 }, - { ILLTRANSINT, "CIM illegal transaction", -1, 1 }, - { ILLWRINT, "CIM illegal write", -1, 1 }, - { ILLRDINT, "CIM illegal read", -1, 1 }, - { ILLRDBEINT, "CIM illegal read BE", -1, 1 }, - { ILLWRBEINT, "CIM illegal write BE", -1, 1 }, - { SGLRDBOOTINT, "CIM single read from boot space", -1, 1 }, - { SGLWRBOOTINT, "CIM single write to boot space", -1, 1 }, - { BLKWRBOOTINT, "CIM block write to boot space", -1, 1 }, - { SGLRDFLASHINT, "CIM single read from flash space", -1, 1 }, - { SGLWRFLASHINT, "CIM single write to flash space", -1, 1 }, - { BLKWRFLASHINT, "CIM block write to flash space", -1, 1 }, - { SGLRDEEPROMINT, "CIM single EEPROM read", -1, 1 }, - { SGLWREEPROMINT, "CIM single EEPROM write", -1, 1 }, - { BLKRDEEPROMINT, "CIM block EEPROM read", -1, 1 }, - { BLKWREEPROMINT, "CIM block EEPROM write", -1, 1 }, - { SGLRDCTLINT , "CIM single read from CTL space", -1, 1 }, - { SGLWRCTLINT , "CIM single write to CTL space", -1, 1 }, - { BLKRDCTLINT , "CIM block read from CTL space", -1, 1 }, - { BLKWRCTLINT , "CIM block write to CTL space", -1, 1 }, - { SGLRDPLINT , "CIM single read from PL space", -1, 1 }, - { SGLWRPLINT , "CIM single write to PL space", -1, 1 }, - { BLKRDPLINT , "CIM block read from PL space", -1, 1 }, - { BLKWRPLINT , "CIM block write to PL space", -1, 1 }, - { REQOVRLOOKUPINT , "CIM request FIFO overwrite", -1, 1 }, - { RSPOVRLOOKUPINT , "CIM response FIFO overwrite", -1, 1 }, - { TIMEOUTINT , "CIM PIF timeout", -1, 1 }, - { TIMEOUTMAINT , "CIM PIF MA timeout", -1, 1 }, + { RSVDSPACEINT_F, "CIM reserved space access", -1, 1 }, + { ILLTRANSINT_F, "CIM illegal transaction", -1, 1 }, + { ILLWRINT_F, "CIM illegal write", -1, 1 }, + { ILLRDINT_F, "CIM illegal read", -1, 1 }, + { ILLRDBEINT_F, "CIM illegal read BE", -1, 1 }, + { ILLWRBEINT_F, "CIM illegal write BE", -1, 1 }, + { SGLRDBOOTINT_F, "CIM single read from boot space", -1, 1 }, + { SGLWRBOOTINT_F, "CIM single write to boot space", -1, 1 }, + { BLKWRBOOTINT_F, "CIM block write to boot space", -1, 1 }, + { SGLRDFLASHINT_F, "CIM single read from flash space", -1, 1 }, + { SGLWRFLASHINT_F, "CIM single write to flash space", -1, 1 }, + { BLKWRFLASHINT_F, "CIM block write to flash space", -1, 1 }, + { SGLRDEEPROMINT_F, "CIM single EEPROM read", -1, 1 }, + { SGLWREEPROMINT_F, "CIM single EEPROM write", -1, 1 }, + { BLKRDEEPROMINT_F, "CIM block EEPROM read", -1, 1 }, + { BLKWREEPROMINT_F, "CIM block EEPROM write", -1, 1 }, + { SGLRDCTLINT_F, "CIM single read from CTL space", -1, 1 }, + { SGLWRCTLINT_F, "CIM single write to CTL space", -1, 1 }, + { BLKRDCTLINT_F, "CIM block read from CTL space", -1, 1 }, + { BLKWRCTLINT_F, "CIM block write to CTL space", -1, 1 }, + { SGLRDPLINT_F, "CIM single read from PL space", -1, 1 }, + { SGLWRPLINT_F, "CIM single write to PL space", -1, 1 }, + { BLKRDPLINT_F, "CIM block read from PL space", -1, 1 }, + { BLKWRPLINT_F, "CIM block write to PL space", -1, 1 }, + { REQOVRLOOKUPINT_F, "CIM request FIFO overwrite", -1, 1 }, + { RSPOVRLOOKUPINT_F, "CIM response FIFO overwrite", -1, 1 }, + { TIMEOUTINT_F, "CIM PIF timeout", -1, 1 }, + { TIMEOUTMAINT_F, "CIM PIF MA timeout", -1, 1 }, { 0 } }; int fat; - if (t4_read_reg(adapter, MA_PCIE_FW) & PCIE_FW_ERR) + if (t4_read_reg(adapter, PCIE_FW_A) & PCIE_FW_ERR_F) t4_report_fw_error(adapter); - fat = t4_handle_intr_status(adapter, CIM_HOST_INT_CAUSE, + fat = t4_handle_intr_status(adapter, CIM_HOST_INT_CAUSE_A, cim_intr_info) + - t4_handle_intr_status(adapter, CIM_HOST_UPACC_INT_CAUSE, + t4_handle_intr_status(adapter, CIM_HOST_UPACC_INT_CAUSE_A, cim_upintr_info); if (fat) t4_fatal_err(adapter); @@ -1611,7 +1692,7 @@ static void ulprx_intr_handler(struct adapter *adapter) { 0 } }; - if (t4_handle_intr_status(adapter, ULP_RX_INT_CAUSE, ulprx_intr_info)) + if (t4_handle_intr_status(adapter, ULP_RX_INT_CAUSE_A, ulprx_intr_info)) t4_fatal_err(adapter); } @@ -1621,19 +1702,19 @@ static void ulprx_intr_handler(struct adapter *adapter) static void ulptx_intr_handler(struct adapter *adapter) { static const struct intr_info ulptx_intr_info[] = { - { PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1, + { PBL_BOUND_ERR_CH3_F, "ULPTX channel 3 PBL out of bounds", -1, 0 }, - { PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1, + { PBL_BOUND_ERR_CH2_F, "ULPTX channel 2 PBL out of bounds", -1, 0 }, - { PBL_BOUND_ERR_CH1, "ULPTX channel 1 PBL out of bounds", -1, + { PBL_BOUND_ERR_CH1_F, "ULPTX channel 1 PBL out of bounds", -1, 0 }, - { PBL_BOUND_ERR_CH0, "ULPTX channel 0 PBL out of bounds", -1, + { PBL_BOUND_ERR_CH0_F, "ULPTX channel 0 PBL out of bounds", -1, 0 }, { 0xfffffff, "ULPTX parity error", -1, 1 }, { 0 } }; - if (t4_handle_intr_status(adapter, ULP_TX_INT_CAUSE, ulptx_intr_info)) + if (t4_handle_intr_status(adapter, ULP_TX_INT_CAUSE_A, ulptx_intr_info)) t4_fatal_err(adapter); } @@ -1643,19 +1724,20 @@ static void ulptx_intr_handler(struct adapter *adapter) static void pmtx_intr_handler(struct adapter *adapter) { static const struct intr_info pmtx_intr_info[] = { - { PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 }, - { PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 }, - { PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 }, - { ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 }, - { PMTX_FRAMING_ERROR, "PMTX framing error", -1, 1 }, - { OESPI_PAR_ERROR, "PMTX oespi parity error", -1, 1 }, - { DB_OPTIONS_PAR_ERROR, "PMTX db_options parity error", -1, 1 }, - { ICSPI_PAR_ERROR, "PMTX icspi parity error", -1, 1 }, - { C_PCMD_PAR_ERROR, "PMTX c_pcmd parity error", -1, 1}, + { PCMD_LEN_OVFL0_F, "PMTX channel 0 pcmd too large", -1, 1 }, + { PCMD_LEN_OVFL1_F, "PMTX channel 1 pcmd too large", -1, 1 }, + { PCMD_LEN_OVFL2_F, "PMTX channel 2 pcmd too large", -1, 1 }, + { ZERO_C_CMD_ERROR_F, "PMTX 0-length pcmd", -1, 1 }, + { PMTX_FRAMING_ERROR_F, "PMTX framing error", -1, 1 }, + { OESPI_PAR_ERROR_F, "PMTX oespi parity error", -1, 1 }, + { DB_OPTIONS_PAR_ERROR_F, "PMTX db_options parity error", + -1, 1 }, + { ICSPI_PAR_ERROR_F, "PMTX icspi parity error", -1, 1 }, + { PMTX_C_PCMD_PAR_ERROR_F, "PMTX c_pcmd parity error", -1, 1}, { 0 } }; - if (t4_handle_intr_status(adapter, PM_TX_INT_CAUSE, pmtx_intr_info)) + if (t4_handle_intr_status(adapter, PM_TX_INT_CAUSE_A, pmtx_intr_info)) t4_fatal_err(adapter); } @@ -1665,16 +1747,17 @@ static void pmtx_intr_handler(struct adapter *adapter) static void pmrx_intr_handler(struct adapter *adapter) { static const struct intr_info pmrx_intr_info[] = { - { ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 }, - { PMRX_FRAMING_ERROR, "PMRX framing error", -1, 1 }, - { OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 }, - { DB_OPTIONS_PAR_ERROR, "PMRX db_options parity error", -1, 1 }, - { IESPI_PAR_ERROR, "PMRX iespi parity error", -1, 1 }, - { E_PCMD_PAR_ERROR, "PMRX e_pcmd parity error", -1, 1}, + { ZERO_E_CMD_ERROR_F, "PMRX 0-length pcmd", -1, 1 }, + { PMRX_FRAMING_ERROR_F, "PMRX framing error", -1, 1 }, + { OCSPI_PAR_ERROR_F, "PMRX ocspi parity error", -1, 1 }, + { DB_OPTIONS_PAR_ERROR_F, "PMRX db_options parity error", + -1, 1 }, + { IESPI_PAR_ERROR_F, "PMRX iespi parity error", -1, 1 }, + { PMRX_E_PCMD_PAR_ERROR_F, "PMRX e_pcmd parity error", -1, 1}, { 0 } }; - if (t4_handle_intr_status(adapter, PM_RX_INT_CAUSE, pmrx_intr_info)) + if (t4_handle_intr_status(adapter, PM_RX_INT_CAUSE_A, pmrx_intr_info)) t4_fatal_err(adapter); } @@ -1684,16 +1767,16 @@ static void pmrx_intr_handler(struct adapter *adapter) static void cplsw_intr_handler(struct adapter *adapter) { static const struct intr_info cplsw_intr_info[] = { - { CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 }, - { CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 }, - { TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 }, - { SGE_FRAMING_ERROR, "CPLSW SGE framing error", -1, 1 }, - { CIM_FRAMING_ERROR, "CPLSW CIM framing error", -1, 1 }, - { ZERO_SWITCH_ERROR, "CPLSW no-switch error", -1, 1 }, + { CIM_OP_MAP_PERR_F, "CPLSW CIM op_map parity error", -1, 1 }, + { CIM_OVFL_ERROR_F, "CPLSW CIM overflow", -1, 1 }, + { TP_FRAMING_ERROR_F, "CPLSW TP framing error", -1, 1 }, + { SGE_FRAMING_ERROR_F, "CPLSW SGE framing error", -1, 1 }, + { CIM_FRAMING_ERROR_F, "CPLSW CIM framing error", -1, 1 }, + { ZERO_SWITCH_ERROR_F, "CPLSW no-switch error", -1, 1 }, { 0 } }; - if (t4_handle_intr_status(adapter, CPL_INTR_CAUSE, cplsw_intr_info)) + if (t4_handle_intr_status(adapter, CPL_INTR_CAUSE_A, cplsw_intr_info)) t4_fatal_err(adapter); } @@ -1703,15 +1786,15 @@ static void cplsw_intr_handler(struct adapter *adapter) static void le_intr_handler(struct adapter *adap) { static const struct intr_info le_intr_info[] = { - { LIPMISS, "LE LIP miss", -1, 0 }, - { LIP0, "LE 0 LIP error", -1, 0 }, - { PARITYERR, "LE parity error", -1, 1 }, - { UNKNOWNCMD, "LE unknown command", -1, 1 }, - { REQQPARERR, "LE request queue parity error", -1, 1 }, + { LIPMISS_F, "LE LIP miss", -1, 0 }, + { LIP0_F, "LE 0 LIP error", -1, 0 }, + { PARITYERR_F, "LE parity error", -1, 1 }, + { UNKNOWNCMD_F, "LE unknown command", -1, 1 }, + { REQQPARERR_F, "LE request queue parity error", -1, 1 }, { 0 } }; - if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE, le_intr_info)) + if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE_A, le_intr_info)) t4_fatal_err(adap); } @@ -1725,19 +1808,22 @@ static void mps_intr_handler(struct adapter *adapter) { 0 } }; static const struct intr_info mps_tx_intr_info[] = { - { TPFIFO, "MPS Tx TP FIFO parity error", -1, 1 }, - { NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 }, - { TXDATAFIFO, "MPS Tx data FIFO parity error", -1, 1 }, - { TXDESCFIFO, "MPS Tx desc FIFO parity error", -1, 1 }, - { BUBBLE, "MPS Tx underflow", -1, 1 }, - { SECNTERR, "MPS Tx SOP/EOP error", -1, 1 }, - { FRMERR, "MPS Tx framing error", -1, 1 }, + { TPFIFO_V(TPFIFO_M), "MPS Tx TP FIFO parity error", -1, 1 }, + { NCSIFIFO_F, "MPS Tx NC-SI FIFO parity error", -1, 1 }, + { TXDATAFIFO_V(TXDATAFIFO_M), "MPS Tx data FIFO parity error", + -1, 1 }, + { TXDESCFIFO_V(TXDESCFIFO_M), "MPS Tx desc FIFO parity error", + -1, 1 }, + { BUBBLE_F, "MPS Tx underflow", -1, 1 }, + { SECNTERR_F, "MPS Tx SOP/EOP error", -1, 1 }, + { FRMERR_F, "MPS Tx framing error", -1, 1 }, { 0 } }; static const struct intr_info mps_trc_intr_info[] = { - { FILTMEM, "MPS TRC filter parity error", -1, 1 }, - { PKTFIFO, "MPS TRC packet FIFO parity error", -1, 1 }, - { MISCPERR, "MPS TRC misc parity error", -1, 1 }, + { FILTMEM_V(FILTMEM_M), "MPS TRC filter parity error", -1, 1 }, + { PKTFIFO_V(PKTFIFO_M), "MPS TRC packet FIFO parity error", + -1, 1 }, + { MISCPERR_F, "MPS TRC misc parity error", -1, 1 }, { 0 } }; static const struct intr_info mps_stat_sram_intr_info[] = { @@ -1753,37 +1839,37 @@ static void mps_intr_handler(struct adapter *adapter) { 0 } }; static const struct intr_info mps_cls_intr_info[] = { - { MATCHSRAM, "MPS match SRAM parity error", -1, 1 }, - { MATCHTCAM, "MPS match TCAM parity error", -1, 1 }, - { HASHSRAM, "MPS hash SRAM parity error", -1, 1 }, + { MATCHSRAM_F, "MPS match SRAM parity error", -1, 1 }, + { MATCHTCAM_F, "MPS match TCAM parity error", -1, 1 }, + { HASHSRAM_F, "MPS hash SRAM parity error", -1, 1 }, { 0 } }; int fat; - fat = t4_handle_intr_status(adapter, MPS_RX_PERR_INT_CAUSE, + fat = t4_handle_intr_status(adapter, MPS_RX_PERR_INT_CAUSE_A, mps_rx_intr_info) + - t4_handle_intr_status(adapter, MPS_TX_INT_CAUSE, + t4_handle_intr_status(adapter, MPS_TX_INT_CAUSE_A, mps_tx_intr_info) + - t4_handle_intr_status(adapter, MPS_TRC_INT_CAUSE, + t4_handle_intr_status(adapter, MPS_TRC_INT_CAUSE_A, mps_trc_intr_info) + - t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_SRAM, + t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_SRAM_A, mps_stat_sram_intr_info) + - t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_TX_FIFO, + t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_TX_FIFO_A, mps_stat_tx_intr_info) + - t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_RX_FIFO, + t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_RX_FIFO_A, mps_stat_rx_intr_info) + - t4_handle_intr_status(adapter, MPS_CLS_INT_CAUSE, + t4_handle_intr_status(adapter, MPS_CLS_INT_CAUSE_A, mps_cls_intr_info); - t4_write_reg(adapter, MPS_INT_CAUSE, CLSINT | TRCINT | - RXINT | TXINT | STATINT); - t4_read_reg(adapter, MPS_INT_CAUSE); /* flush */ + t4_write_reg(adapter, MPS_INT_CAUSE_A, 0); + t4_read_reg(adapter, MPS_INT_CAUSE_A); /* flush */ if (fat) t4_fatal_err(adapter); } -#define MEM_INT_MASK (PERR_INT_CAUSE | ECC_CE_INT_CAUSE | ECC_UE_INT_CAUSE) +#define MEM_INT_MASK (PERR_INT_CAUSE_F | ECC_CE_INT_CAUSE_F | \ + ECC_UE_INT_CAUSE_F) /* * EDC/MC interrupt handler. @@ -1795,40 +1881,40 @@ static void mem_intr_handler(struct adapter *adapter, int idx) unsigned int addr, cnt_addr, v; if (idx <= MEM_EDC1) { - addr = EDC_REG(EDC_INT_CAUSE, idx); - cnt_addr = EDC_REG(EDC_ECC_STATUS, idx); + addr = EDC_REG(EDC_INT_CAUSE_A, idx); + cnt_addr = EDC_REG(EDC_ECC_STATUS_A, idx); } else if (idx == MEM_MC) { if (is_t4(adapter->params.chip)) { - addr = MC_INT_CAUSE; - cnt_addr = MC_ECC_STATUS; + addr = MC_INT_CAUSE_A; + cnt_addr = MC_ECC_STATUS_A; } else { - addr = MC_P_INT_CAUSE; - cnt_addr = MC_P_ECC_STATUS; + addr = MC_P_INT_CAUSE_A; + cnt_addr = MC_P_ECC_STATUS_A; } } else { - addr = MC_REG(MC_P_INT_CAUSE, 1); - cnt_addr = MC_REG(MC_P_ECC_STATUS, 1); + addr = MC_REG(MC_P_INT_CAUSE_A, 1); + cnt_addr = MC_REG(MC_P_ECC_STATUS_A, 1); } v = t4_read_reg(adapter, addr) & MEM_INT_MASK; - if (v & PERR_INT_CAUSE) + if (v & PERR_INT_CAUSE_F) dev_alert(adapter->pdev_dev, "%s FIFO parity error\n", name[idx]); - if (v & ECC_CE_INT_CAUSE) { - u32 cnt = ECC_CECNT_GET(t4_read_reg(adapter, cnt_addr)); + if (v & ECC_CE_INT_CAUSE_F) { + u32 cnt = ECC_CECNT_G(t4_read_reg(adapter, cnt_addr)); - t4_write_reg(adapter, cnt_addr, ECC_CECNT_MASK); + t4_write_reg(adapter, cnt_addr, ECC_CECNT_V(ECC_CECNT_M)); if (printk_ratelimit()) dev_warn(adapter->pdev_dev, "%u %s correctable ECC data error%s\n", cnt, name[idx], cnt > 1 ? "s" : ""); } - if (v & ECC_UE_INT_CAUSE) + if (v & ECC_UE_INT_CAUSE_F) dev_alert(adapter->pdev_dev, "%s uncorrectable ECC data error\n", name[idx]); t4_write_reg(adapter, addr, v); - if (v & (PERR_INT_CAUSE | ECC_UE_INT_CAUSE)) + if (v & (PERR_INT_CAUSE_F | ECC_UE_INT_CAUSE_F)) t4_fatal_err(adapter); } @@ -1837,26 +1923,26 @@ static void mem_intr_handler(struct adapter *adapter, int idx) */ static void ma_intr_handler(struct adapter *adap) { - u32 v, status = t4_read_reg(adap, MA_INT_CAUSE); + u32 v, status = t4_read_reg(adap, MA_INT_CAUSE_A); - if (status & MEM_PERR_INT_CAUSE) { + if (status & MEM_PERR_INT_CAUSE_F) { dev_alert(adap->pdev_dev, "MA parity error, parity status %#x\n", - t4_read_reg(adap, MA_PARITY_ERROR_STATUS)); + t4_read_reg(adap, MA_PARITY_ERROR_STATUS1_A)); if (is_t5(adap->params.chip)) dev_alert(adap->pdev_dev, "MA parity error, parity status %#x\n", t4_read_reg(adap, - MA_PARITY_ERROR_STATUS2)); + MA_PARITY_ERROR_STATUS2_A)); } - if (status & MEM_WRAP_INT_CAUSE) { - v = t4_read_reg(adap, MA_INT_WRAP_STATUS); + if (status & MEM_WRAP_INT_CAUSE_F) { + v = t4_read_reg(adap, MA_INT_WRAP_STATUS_A); dev_alert(adap->pdev_dev, "MA address wrap-around error by " "client %u to address %#x\n", - MEM_WRAP_CLIENT_NUM_GET(v), - MEM_WRAP_ADDRESS_GET(v) << 4); + MEM_WRAP_CLIENT_NUM_G(v), + MEM_WRAP_ADDRESS_G(v) << 4); } - t4_write_reg(adap, MA_INT_CAUSE, status); + t4_write_reg(adap, MA_INT_CAUSE_A, status); t4_fatal_err(adap); } @@ -1866,13 +1952,13 @@ static void ma_intr_handler(struct adapter *adap) static void smb_intr_handler(struct adapter *adap) { static const struct intr_info smb_intr_info[] = { - { MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 }, - { MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 }, - { SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 }, + { MSTTXFIFOPARINT_F, "SMB master Tx FIFO parity error", -1, 1 }, + { MSTRXFIFOPARINT_F, "SMB master Rx FIFO parity error", -1, 1 }, + { SLVFIFOPARINT_F, "SMB slave FIFO parity error", -1, 1 }, { 0 } }; - if (t4_handle_intr_status(adap, SMB_INT_CAUSE, smb_intr_info)) + if (t4_handle_intr_status(adap, SMB_INT_CAUSE_A, smb_intr_info)) t4_fatal_err(adap); } @@ -1882,14 +1968,14 @@ static void smb_intr_handler(struct adapter *adap) static void ncsi_intr_handler(struct adapter *adap) { static const struct intr_info ncsi_intr_info[] = { - { CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 }, - { MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 }, - { TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 }, - { RXFIFO_PRTY_ERR, "NC-SI Rx FIFO parity error", -1, 1 }, + { CIM_DM_PRTY_ERR_F, "NC-SI CIM parity error", -1, 1 }, + { MPS_DM_PRTY_ERR_F, "NC-SI MPS parity error", -1, 1 }, + { TXFIFO_PRTY_ERR_F, "NC-SI Tx FIFO parity error", -1, 1 }, + { RXFIFO_PRTY_ERR_F, "NC-SI Rx FIFO parity error", -1, 1 }, { 0 } }; - if (t4_handle_intr_status(adap, NCSI_INT_CAUSE, ncsi_intr_info)) + if (t4_handle_intr_status(adap, NCSI_INT_CAUSE_A, ncsi_intr_info)) t4_fatal_err(adap); } @@ -1901,23 +1987,23 @@ static void xgmac_intr_handler(struct adapter *adap, int port) u32 v, int_cause_reg; if (is_t4(adap->params.chip)) - int_cause_reg = PORT_REG(port, XGMAC_PORT_INT_CAUSE); + int_cause_reg = PORT_REG(port, XGMAC_PORT_INT_CAUSE_A); else - int_cause_reg = T5_PORT_REG(port, MAC_PORT_INT_CAUSE); + int_cause_reg = T5_PORT_REG(port, MAC_PORT_INT_CAUSE_A); v = t4_read_reg(adap, int_cause_reg); - v &= TXFIFO_PRTY_ERR | RXFIFO_PRTY_ERR; + v &= TXFIFO_PRTY_ERR_F | RXFIFO_PRTY_ERR_F; if (!v) return; - if (v & TXFIFO_PRTY_ERR) + if (v & TXFIFO_PRTY_ERR_F) dev_alert(adap->pdev_dev, "XGMAC %d Tx FIFO parity error\n", port); - if (v & RXFIFO_PRTY_ERR) + if (v & RXFIFO_PRTY_ERR_F) dev_alert(adap->pdev_dev, "XGMAC %d Rx FIFO parity error\n", port); - t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE), v); + t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE_A), v); t4_fatal_err(adap); } @@ -1927,19 +2013,19 @@ static void xgmac_intr_handler(struct adapter *adap, int port) static void pl_intr_handler(struct adapter *adap) { static const struct intr_info pl_intr_info[] = { - { FATALPERR, "T4 fatal parity error", -1, 1 }, - { PERRVFID, "PL VFID_MAP parity error", -1, 1 }, + { FATALPERR_F, "T4 fatal parity error", -1, 1 }, + { PERRVFID_F, "PL VFID_MAP parity error", -1, 1 }, { 0 } }; - if (t4_handle_intr_status(adap, PL_PL_INT_CAUSE, pl_intr_info)) + if (t4_handle_intr_status(adap, PL_PL_INT_CAUSE_A, pl_intr_info)) t4_fatal_err(adap); } -#define PF_INTR_MASK (PFSW) -#define GLBL_INTR_MASK (CIM | MPS | PL | PCIE | MC | EDC0 | \ - EDC1 | LE | TP | MA | PM_TX | PM_RX | ULP_RX | \ - CPL_SWITCH | SGE | ULP_TX) +#define PF_INTR_MASK (PFSW_F) +#define GLBL_INTR_MASK (CIM_F | MPS_F | PL_F | PCIE_F | MC_F | EDC0_F | \ + EDC1_F | LE_F | TP_F | MA_F | PM_TX_F | PM_RX_F | ULP_RX_F | \ + CPL_SWITCH_F | SGE_F | ULP_TX_F) /** * t4_slow_intr_handler - control path interrupt handler @@ -1951,60 +2037,60 @@ static void pl_intr_handler(struct adapter *adap) */ int t4_slow_intr_handler(struct adapter *adapter) { - u32 cause = t4_read_reg(adapter, PL_INT_CAUSE); + u32 cause = t4_read_reg(adapter, PL_INT_CAUSE_A); if (!(cause & GLBL_INTR_MASK)) return 0; - if (cause & CIM) + if (cause & CIM_F) cim_intr_handler(adapter); - if (cause & MPS) + if (cause & MPS_F) mps_intr_handler(adapter); - if (cause & NCSI) + if (cause & NCSI_F) ncsi_intr_handler(adapter); - if (cause & PL) + if (cause & PL_F) pl_intr_handler(adapter); - if (cause & SMB) + if (cause & SMB_F) smb_intr_handler(adapter); - if (cause & XGMAC0) + if (cause & XGMAC0_F) xgmac_intr_handler(adapter, 0); - if (cause & XGMAC1) + if (cause & XGMAC1_F) xgmac_intr_handler(adapter, 1); - if (cause & XGMAC_KR0) + if (cause & XGMAC_KR0_F) xgmac_intr_handler(adapter, 2); - if (cause & XGMAC_KR1) + if (cause & XGMAC_KR1_F) xgmac_intr_handler(adapter, 3); - if (cause & PCIE) + if (cause & PCIE_F) pcie_intr_handler(adapter); - if (cause & MC) + if (cause & MC_F) mem_intr_handler(adapter, MEM_MC); - if (!is_t4(adapter->params.chip) && (cause & MC1)) + if (!is_t4(adapter->params.chip) && (cause & MC1_S)) mem_intr_handler(adapter, MEM_MC1); - if (cause & EDC0) + if (cause & EDC0_F) mem_intr_handler(adapter, MEM_EDC0); - if (cause & EDC1) + if (cause & EDC1_F) mem_intr_handler(adapter, MEM_EDC1); - if (cause & LE) + if (cause & LE_F) le_intr_handler(adapter); - if (cause & TP) + if (cause & TP_F) tp_intr_handler(adapter); - if (cause & MA) + if (cause & MA_F) ma_intr_handler(adapter); - if (cause & PM_TX) + if (cause & PM_TX_F) pmtx_intr_handler(adapter); - if (cause & PM_RX) + if (cause & PM_RX_F) pmrx_intr_handler(adapter); - if (cause & ULP_RX) + if (cause & ULP_RX_F) ulprx_intr_handler(adapter); - if (cause & CPL_SWITCH) + if (cause & CPL_SWITCH_F) cplsw_intr_handler(adapter); - if (cause & SGE) + if (cause & SGE_F) sge_intr_handler(adapter); - if (cause & ULP_TX) + if (cause & ULP_TX_F) ulptx_intr_handler(adapter); /* Clear the interrupts just processed for which we are the master. */ - t4_write_reg(adapter, PL_INT_CAUSE, cause & GLBL_INTR_MASK); - (void) t4_read_reg(adapter, PL_INT_CAUSE); /* flush */ + t4_write_reg(adapter, PL_INT_CAUSE_A, cause & GLBL_INTR_MASK); + (void)t4_read_reg(adapter, PL_INT_CAUSE_A); /* flush */ return 1; } @@ -2023,19 +2109,19 @@ int t4_slow_intr_handler(struct adapter *adapter) */ void t4_intr_enable(struct adapter *adapter) { - u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI)); + u32 pf = SOURCEPF_G(t4_read_reg(adapter, PL_WHOAMI_A)); - t4_write_reg(adapter, SGE_INT_ENABLE3, ERR_CPL_EXCEED_IQE_SIZE | - ERR_INVALID_CIDX_INC | ERR_CPL_OPCODE_0 | - ERR_DROPPED_DB | ERR_DATA_CPL_ON_HIGH_QID1 | - ERR_DATA_CPL_ON_HIGH_QID0 | ERR_BAD_DB_PIDX3 | - ERR_BAD_DB_PIDX2 | ERR_BAD_DB_PIDX1 | - ERR_BAD_DB_PIDX0 | ERR_ING_CTXT_PRIO | - ERR_EGR_CTXT_PRIO | INGRESS_SIZE_ERR | - DBFIFO_HP_INT | DBFIFO_LP_INT | - EGRESS_SIZE_ERR); - t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), PF_INTR_MASK); - t4_set_reg_field(adapter, PL_INT_MAP0, 0, 1 << pf); + t4_write_reg(adapter, SGE_INT_ENABLE3_A, ERR_CPL_EXCEED_IQE_SIZE_F | + ERR_INVALID_CIDX_INC_F | ERR_CPL_OPCODE_0_F | + ERR_DROPPED_DB_F | ERR_DATA_CPL_ON_HIGH_QID1_F | + ERR_DATA_CPL_ON_HIGH_QID0_F | ERR_BAD_DB_PIDX3_F | + ERR_BAD_DB_PIDX2_F | ERR_BAD_DB_PIDX1_F | + ERR_BAD_DB_PIDX0_F | ERR_ING_CTXT_PRIO_F | + ERR_EGR_CTXT_PRIO_F | INGRESS_SIZE_ERR_F | + DBFIFO_HP_INT_F | DBFIFO_LP_INT_F | + EGRESS_SIZE_ERR_F); + t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE_A), PF_INTR_MASK); + t4_set_reg_field(adapter, PL_INT_MAP0_A, 0, 1 << pf); } /** @@ -2048,10 +2134,10 @@ void t4_intr_enable(struct adapter *adapter) */ void t4_intr_disable(struct adapter *adapter) { - u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI)); + u32 pf = SOURCEPF_G(t4_read_reg(adapter, PL_WHOAMI_A)); - t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), 0); - t4_set_reg_field(adapter, PL_INT_MAP0, 1 << pf, 0); + t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE_A), 0); + t4_set_reg_field(adapter, PL_INT_MAP0_A, 1 << pf, 0); } /** @@ -2166,6 +2252,147 @@ int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL); } +/* Read an RSS table row */ +static int rd_rss_row(struct adapter *adap, int row, u32 *val) +{ + t4_write_reg(adap, TP_RSS_LKP_TABLE_A, 0xfff00000 | row); + return t4_wait_op_done_val(adap, TP_RSS_LKP_TABLE_A, LKPTBLROWVLD_F, 1, + 5, 0, val); +} + +/** + * t4_read_rss - read the contents of the RSS mapping table + * @adapter: the adapter + * @map: holds the contents of the RSS mapping table + * + * Reads the contents of the RSS hash->queue mapping table. + */ +int t4_read_rss(struct adapter *adapter, u16 *map) +{ + u32 val; + int i, ret; + + for (i = 0; i < RSS_NENTRIES / 2; ++i) { + ret = rd_rss_row(adapter, i, &val); + if (ret) + return ret; + *map++ = LKPTBLQUEUE0_G(val); + *map++ = LKPTBLQUEUE1_G(val); + } + return 0; +} + +/** + * t4_read_rss_key - read the global RSS key + * @adap: the adapter + * @key: 10-entry array holding the 320-bit RSS key + * + * Reads the global 320-bit RSS key. + */ +void t4_read_rss_key(struct adapter *adap, u32 *key) +{ + t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10, + TP_RSS_SECRET_KEY0_A); +} + +/** + * t4_write_rss_key - program one of the RSS keys + * @adap: the adapter + * @key: 10-entry array holding the 320-bit RSS key + * @idx: which RSS key to write + * + * Writes one of the RSS keys with the given 320-bit value. If @idx is + * 0..15 the corresponding entry in the RSS key table is written, + * otherwise the global RSS key is written. + */ +void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx) +{ + t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10, + TP_RSS_SECRET_KEY0_A); + if (idx >= 0 && idx < 16) + t4_write_reg(adap, TP_RSS_CONFIG_VRT_A, + KEYWRADDR_V(idx) | KEYWREN_F); +} + +/** + * t4_read_rss_pf_config - read PF RSS Configuration Table + * @adapter: the adapter + * @index: the entry in the PF RSS table to read + * @valp: where to store the returned value + * + * Reads the PF RSS Configuration Table at the specified index and returns + * the value found there. + */ +void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, + u32 *valp) +{ + t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, + valp, 1, TP_RSS_PF0_CONFIG_A + index); +} + +/** + * t4_read_rss_vf_config - read VF RSS Configuration Table + * @adapter: the adapter + * @index: the entry in the VF RSS table to read + * @vfl: where to store the returned VFL + * @vfh: where to store the returned VFH + * + * Reads the VF RSS Configuration Table at the specified index and returns + * the (VFL, VFH) values found there. + */ +void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index, + u32 *vfl, u32 *vfh) +{ + u32 vrt, mask, data; + + mask = VFWRADDR_V(VFWRADDR_M); + data = VFWRADDR_V(index); + + /* Request that the index'th VF Table values be read into VFL/VFH. + */ + vrt = t4_read_reg(adapter, TP_RSS_CONFIG_VRT_A); + vrt &= ~(VFRDRG_F | VFWREN_F | KEYWREN_F | mask); + vrt |= data | VFRDEN_F; + t4_write_reg(adapter, TP_RSS_CONFIG_VRT_A, vrt); + + /* Grab the VFL/VFH values ... + */ + t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, + vfl, 1, TP_RSS_VFL_CONFIG_A); + t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, + vfh, 1, TP_RSS_VFH_CONFIG_A); +} + +/** + * t4_read_rss_pf_map - read PF RSS Map + * @adapter: the adapter + * + * Reads the PF RSS Map register and returns its value. + */ +u32 t4_read_rss_pf_map(struct adapter *adapter) +{ + u32 pfmap; + + t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, + &pfmap, 1, TP_RSS_PF_MAP_A); + return pfmap; +} + +/** + * t4_read_rss_pf_mask - read PF RSS Mask + * @adapter: the adapter + * + * Reads the PF RSS Mask register and returns its value. + */ +u32 t4_read_rss_pf_mask(struct adapter *adapter) +{ + u32 pfmask; + + t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, + &pfmask, 1, TP_RSS_PF_MSK_A); + return pfmask; +} + /** * t4_tp_get_tcp_stats - read TP's TCP MIB counters * @adap: the adapter @@ -2178,23 +2405,23 @@ int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, struct tp_tcp_stats *v6) { - u32 val[TP_MIB_TCP_RXT_SEG_LO - TP_MIB_TCP_OUT_RST + 1]; + u32 val[TP_MIB_TCP_RXT_SEG_LO_A - TP_MIB_TCP_OUT_RST_A + 1]; -#define STAT_IDX(x) ((TP_MIB_TCP_##x) - TP_MIB_TCP_OUT_RST) +#define STAT_IDX(x) ((TP_MIB_TCP_##x##_A) - TP_MIB_TCP_OUT_RST_A) #define STAT(x) val[STAT_IDX(x)] #define STAT64(x) (((u64)STAT(x##_HI) << 32) | STAT(x##_LO)) if (v4) { - t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, val, - ARRAY_SIZE(val), TP_MIB_TCP_OUT_RST); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val, + ARRAY_SIZE(val), TP_MIB_TCP_OUT_RST_A); v4->tcpOutRsts = STAT(OUT_RST); v4->tcpInSegs = STAT64(IN_SEG); v4->tcpOutSegs = STAT64(OUT_SEG); v4->tcpRetransSegs = STAT64(RXT_SEG); } if (v6) { - t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, val, - ARRAY_SIZE(val), TP_MIB_TCP_V6OUT_RST); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val, + ARRAY_SIZE(val), TP_MIB_TCP_V6OUT_RST_A); v6->tcpOutRsts = STAT(OUT_RST); v6->tcpInSegs = STAT64(IN_SEG); v6->tcpOutSegs = STAT64(OUT_SEG); @@ -2219,15 +2446,36 @@ void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log) int i; for (i = 0; i < NMTUS; ++i) { - t4_write_reg(adap, TP_MTU_TABLE, - MTUINDEX(0xff) | MTUVALUE(i)); - v = t4_read_reg(adap, TP_MTU_TABLE); - mtus[i] = MTUVALUE_GET(v); + t4_write_reg(adap, TP_MTU_TABLE_A, + MTUINDEX_V(0xff) | MTUVALUE_V(i)); + v = t4_read_reg(adap, TP_MTU_TABLE_A); + mtus[i] = MTUVALUE_G(v); if (mtu_log) - mtu_log[i] = MTUWIDTH_GET(v); + mtu_log[i] = MTUWIDTH_G(v); } } +/** + * t4_read_cong_tbl - reads the congestion control table + * @adap: the adapter + * @incr: where to store the alpha values + * + * Reads the additive increments programmed into the HW congestion + * control table. + */ +void t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN]) +{ + unsigned int mtu, w; + + for (mtu = 0; mtu < NMTUS; ++mtu) + for (w = 0; w < NCCTRL_WIN; ++w) { + t4_write_reg(adap, TP_CCTRL_TABLE_A, + ROWINDEX_V(0xffff) | (mtu << 5) | w); + incr[mtu][w] = (u16)t4_read_reg(adap, + TP_CCTRL_TABLE_A) & 0x1fff; + } +} + /** * t4_tp_wr_bits_indirect - set/clear bits in an indirect TP register * @adap: the adapter @@ -2240,9 +2488,9 @@ void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log) void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr, unsigned int mask, unsigned int val) { - t4_write_reg(adap, TP_PIO_ADDR, addr); - val |= t4_read_reg(adap, TP_PIO_DATA) & ~mask; - t4_write_reg(adap, TP_PIO_DATA, val); + t4_write_reg(adap, TP_PIO_ADDR_A, addr); + val |= t4_read_reg(adap, TP_PIO_DATA_A) & ~mask; + t4_write_reg(adap, TP_PIO_DATA_A, val); } /** @@ -2321,8 +2569,8 @@ void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, if (!(mtu & ((1 << log2) >> 2))) /* round */ log2--; - t4_write_reg(adap, TP_MTU_TABLE, MTUINDEX(i) | - MTUWIDTH(log2) | MTUVALUE(mtu)); + t4_write_reg(adap, TP_MTU_TABLE_A, MTUINDEX_V(i) | + MTUWIDTH_V(log2) | MTUVALUE_V(mtu)); for (w = 0; w < NCCTRL_WIN; ++w) { unsigned int inc; @@ -2330,12 +2578,66 @@ void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w], CC_MIN_INCR); - t4_write_reg(adap, TP_CCTRL_TABLE, (i << 21) | + t4_write_reg(adap, TP_CCTRL_TABLE_A, (i << 21) | (w << 16) | (beta[w] << 13) | inc); } } } +/** + * t4_pmtx_get_stats - returns the HW stats from PMTX + * @adap: the adapter + * @cnt: where to store the count statistics + * @cycles: where to store the cycle statistics + * + * Returns performance statistics from PMTX. + */ +void t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) +{ + int i; + u32 data[2]; + + for (i = 0; i < PM_NSTATS; i++) { + t4_write_reg(adap, PM_TX_STAT_CONFIG_A, i + 1); + cnt[i] = t4_read_reg(adap, PM_TX_STAT_COUNT_A); + if (is_t4(adap->params.chip)) { + cycles[i] = t4_read_reg64(adap, PM_TX_STAT_LSB_A); + } else { + t4_read_indirect(adap, PM_TX_DBG_CTRL_A, + PM_TX_DBG_DATA_A, data, 2, + PM_TX_DBG_STAT_MSB_A); + cycles[i] = (((u64)data[0] << 32) | data[1]); + } + } +} + +/** + * t4_pmrx_get_stats - returns the HW stats from PMRX + * @adap: the adapter + * @cnt: where to store the count statistics + * @cycles: where to store the cycle statistics + * + * Returns performance statistics from PMRX. + */ +void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) +{ + int i; + u32 data[2]; + + for (i = 0; i < PM_NSTATS; i++) { + t4_write_reg(adap, PM_RX_STAT_CONFIG_A, i + 1); + cnt[i] = t4_read_reg(adap, PM_RX_STAT_COUNT_A); + if (is_t4(adap->params.chip)) { + cycles[i] = t4_read_reg64(adap, PM_RX_STAT_LSB_A); + } else { + t4_read_indirect(adap, PM_RX_DBG_CTRL_A, + PM_RX_DBG_DATA_A, data, 2, + PM_RX_DBG_STAT_MSB_A); + cycles[i] = (((u64)data[0] << 32) | data[1]); + } + } +} + /** * get_mps_bg_map - return the buffer groups associated with a port * @adap: the adapter @@ -2347,7 +2649,7 @@ void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, */ static unsigned int get_mps_bg_map(struct adapter *adap, int idx) { - u32 n = NUMPORTS_GET(t4_read_reg(adap, MPS_CMN_CTL)); + u32 n = NUMPORTS_G(t4_read_reg(adap, MPS_CMN_CTL_A)); if (n == 0) return idx == 0 ? 0xf : 0; @@ -2485,11 +2787,11 @@ void t4_wol_magic_enable(struct adapter *adap, unsigned int port, if (is_t4(adap->params.chip)) { mag_id_reg_l = PORT_REG(port, XGMAC_PORT_MAGIC_MACID_LO); mag_id_reg_h = PORT_REG(port, XGMAC_PORT_MAGIC_MACID_HI); - port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2); + port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2_A); } else { mag_id_reg_l = T5_PORT_REG(port, MAC_PORT_MAGIC_MACID_LO); mag_id_reg_h = T5_PORT_REG(port, MAC_PORT_MAGIC_MACID_HI); - port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2); + port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2_A); } if (addr) { @@ -2499,8 +2801,8 @@ void t4_wol_magic_enable(struct adapter *adap, unsigned int port, t4_write_reg(adap, mag_id_reg_h, (addr[0] << 8) | addr[1]); } - t4_set_reg_field(adap, port_cfg_reg, MAGICEN, - addr ? MAGICEN : 0); + t4_set_reg_field(adap, port_cfg_reg, MAGICEN_F, + addr ? MAGICEN_F : 0); } /** @@ -2525,20 +2827,21 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map, u32 port_cfg_reg; if (is_t4(adap->params.chip)) - port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2); + port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2_A); else - port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2); + port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2_A); if (!enable) { - t4_set_reg_field(adap, port_cfg_reg, PATEN, 0); + t4_set_reg_field(adap, port_cfg_reg, PATEN_F, 0); return 0; } if (map > 0xff) return -EINVAL; #define EPIO_REG(name) \ - (is_t4(adap->params.chip) ? PORT_REG(port, XGMAC_PORT_EPIO_##name) : \ - T5_PORT_REG(port, MAC_PORT_EPIO_##name)) + (is_t4(adap->params.chip) ? \ + PORT_REG(port, XGMAC_PORT_EPIO_##name##_A) : \ + T5_PORT_REG(port, MAC_PORT_EPIO_##name##_A)) t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32); t4_write_reg(adap, EPIO_REG(DATA2), mask1); @@ -2550,21 +2853,21 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map, /* write byte masks */ t4_write_reg(adap, EPIO_REG(DATA0), mask0); - t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i) | EPIOWR); + t4_write_reg(adap, EPIO_REG(OP), ADDRESS_V(i) | EPIOWR_F); t4_read_reg(adap, EPIO_REG(OP)); /* flush */ - if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY) + if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY_F) return -ETIMEDOUT; /* write CRC */ t4_write_reg(adap, EPIO_REG(DATA0), crc); - t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i + 32) | EPIOWR); + t4_write_reg(adap, EPIO_REG(OP), ADDRESS_V(i + 32) | EPIOWR_F); t4_read_reg(adap, EPIO_REG(OP)); /* flush */ - if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY) + if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY_F) return -ETIMEDOUT; } #undef EPIO_REG - t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), 0, PATEN); + t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2_A), 0, PATEN_F); return 0; } @@ -2749,9 +3052,9 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state) "IDMA_FL_SEND_COMPLETION_TO_IMSG", }; static const u32 sge_regs[] = { - SGE_DEBUG_DATA_LOW_INDEX_2, - SGE_DEBUG_DATA_LOW_INDEX_3, - SGE_DEBUG_DATA_HIGH_INDEX_10, + SGE_DEBUG_DATA_LOW_INDEX_2_A, + SGE_DEBUG_DATA_LOW_INDEX_3_A, + SGE_DEBUG_DATA_HIGH_INDEX_10_A, }; const char **sge_idma_decode; int sge_idma_decode_nstates; @@ -2818,7 +3121,7 @@ retry: if (ret < 0) { if ((ret == -EBUSY || ret == -ETIMEDOUT) && retries-- > 0) goto retry; - if (t4_read_reg(adap, MA_PCIE_FW) & PCIE_FW_ERR) + if (t4_read_reg(adap, PCIE_FW_A) & PCIE_FW_ERR_F) t4_report_fw_error(adap); return ret; } @@ -2868,8 +3171,8 @@ retry: * timeout ... and then retry if we haven't exhausted * our retries ... */ - pcie_fw = t4_read_reg(adap, MA_PCIE_FW); - if (!(pcie_fw & (PCIE_FW_ERR|PCIE_FW_INIT))) { + pcie_fw = t4_read_reg(adap, PCIE_FW_A); + if (!(pcie_fw & (PCIE_FW_ERR_F|PCIE_FW_INIT_F))) { if (waiting <= 0) { if (retries-- > 0) goto retry; @@ -2884,9 +3187,9 @@ retry: * report errors preferentially. */ if (state) { - if (pcie_fw & PCIE_FW_ERR) + if (pcie_fw & PCIE_FW_ERR_F) *state = DEV_STATE_ERR; - else if (pcie_fw & PCIE_FW_INIT) + else if (pcie_fw & PCIE_FW_INIT_F) *state = DEV_STATE_INIT; } @@ -2896,7 +3199,7 @@ retry: * for our caller. */ if (master_mbox == PCIE_FW_MASTER_M && - (pcie_fw & PCIE_FW_MASTER_VLD)) + (pcie_fw & PCIE_FW_MASTER_VLD_F)) master_mbox = PCIE_FW_MASTER_G(pcie_fw); break; } @@ -2985,7 +3288,7 @@ static int t4_fw_halt(struct adapter *adap, unsigned int mbox, int force) memset(&c, 0, sizeof(c)); INIT_CMD(c, RESET, WRITE); - c.val = htonl(PIORST | PIORSTMODE); + c.val = htonl(PIORST_F | PIORSTMODE_F); c.halt_pkd = htonl(FW_RESET_CMD_HALT_F); ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); } @@ -3004,8 +3307,8 @@ static int t4_fw_halt(struct adapter *adap, unsigned int mbox, int force) * rather than a RESET ... if it's new enough to understand that ... */ if (ret == 0 || force) { - t4_set_reg_field(adap, CIM_BOOT_CFG, UPCRST, UPCRST); - t4_set_reg_field(adap, PCIE_FW, PCIE_FW_HALT_F, + t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, UPCRST_F); + t4_set_reg_field(adap, PCIE_FW_A, PCIE_FW_HALT_F, PCIE_FW_HALT_F); } @@ -3045,7 +3348,7 @@ static int t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset) * doing it automatically, we need to clear the PCIE_FW.HALT * bit. */ - t4_set_reg_field(adap, PCIE_FW, PCIE_FW_HALT_F, 0); + t4_set_reg_field(adap, PCIE_FW_A, PCIE_FW_HALT_F, 0); /* * If we've been given a valid mailbox, first try to get the @@ -3055,21 +3358,21 @@ static int t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset) * hitting the chip with a hammer. */ if (mbox <= PCIE_FW_MASTER_M) { - t4_set_reg_field(adap, CIM_BOOT_CFG, UPCRST, 0); + t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, 0); msleep(100); if (t4_fw_reset(adap, mbox, - PIORST | PIORSTMODE) == 0) + PIORST_F | PIORSTMODE_F) == 0) return 0; } - t4_write_reg(adap, PL_RST, PIORST | PIORSTMODE); + t4_write_reg(adap, PL_RST_A, PIORST_F | PIORSTMODE_F); msleep(2000); } else { int ms; - t4_set_reg_field(adap, CIM_BOOT_CFG, UPCRST, 0); + t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, 0); for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) { - if (!(t4_read_reg(adap, PCIE_FW) & PCIE_FW_HALT_F)) + if (!(t4_read_reg(adap, PCIE_FW_A) & PCIE_FW_HALT_F)) return 0; msleep(100); ms += 100; @@ -3148,22 +3451,23 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size, unsigned int fl_align = cache_line_size < 32 ? 32 : cache_line_size; unsigned int fl_align_log = fls(fl_align) - 1; - t4_write_reg(adap, SGE_HOST_PAGE_SIZE, - HOSTPAGESIZEPF0(sge_hps) | - HOSTPAGESIZEPF1(sge_hps) | - HOSTPAGESIZEPF2(sge_hps) | - HOSTPAGESIZEPF3(sge_hps) | - HOSTPAGESIZEPF4(sge_hps) | - HOSTPAGESIZEPF5(sge_hps) | - HOSTPAGESIZEPF6(sge_hps) | - HOSTPAGESIZEPF7(sge_hps)); + t4_write_reg(adap, SGE_HOST_PAGE_SIZE_A, + HOSTPAGESIZEPF0_V(sge_hps) | + HOSTPAGESIZEPF1_V(sge_hps) | + HOSTPAGESIZEPF2_V(sge_hps) | + HOSTPAGESIZEPF3_V(sge_hps) | + HOSTPAGESIZEPF4_V(sge_hps) | + HOSTPAGESIZEPF5_V(sge_hps) | + HOSTPAGESIZEPF6_V(sge_hps) | + HOSTPAGESIZEPF7_V(sge_hps)); if (is_t4(adap->params.chip)) { - t4_set_reg_field(adap, SGE_CONTROL, - INGPADBOUNDARY_MASK | - EGRSTATUSPAGESIZE_MASK, - INGPADBOUNDARY(fl_align_log - 5) | - EGRSTATUSPAGESIZE(stat_len != 64)); + t4_set_reg_field(adap, SGE_CONTROL_A, + INGPADBOUNDARY_V(INGPADBOUNDARY_M) | + EGRSTATUSPAGESIZE_F, + INGPADBOUNDARY_V(fl_align_log - + INGPADBOUNDARY_SHIFT_X) | + EGRSTATUSPAGESIZE_V(stat_len != 64)); } else { /* T5 introduced the separation of the Free List Padding and * Packing Boundaries. Thus, we can select a smaller Padding @@ -3193,15 +3497,15 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size, fl_align = 64; fl_align_log = 6; } - t4_set_reg_field(adap, SGE_CONTROL, - INGPADBOUNDARY_MASK | - EGRSTATUSPAGESIZE_MASK, - INGPADBOUNDARY(INGPCIEBOUNDARY_32B_X) | - EGRSTATUSPAGESIZE(stat_len != 64)); + t4_set_reg_field(adap, SGE_CONTROL_A, + INGPADBOUNDARY_V(INGPADBOUNDARY_M) | + EGRSTATUSPAGESIZE_F, + INGPADBOUNDARY_V(INGPCIEBOUNDARY_32B_X) | + EGRSTATUSPAGESIZE_V(stat_len != 64)); t4_set_reg_field(adap, SGE_CONTROL2_A, INGPACKBOUNDARY_V(INGPACKBOUNDARY_M), INGPACKBOUNDARY_V(fl_align_log - - INGPACKBOUNDARY_SHIFT_X)); + INGPACKBOUNDARY_SHIFT_X)); } /* * Adjust various SGE Free List Host Buffer Sizes. @@ -3224,15 +3528,15 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size, * Default Firmware Configuration File but we need to adjust it for * this host's cache line size. */ - t4_write_reg(adap, SGE_FL_BUFFER_SIZE0, page_size); - t4_write_reg(adap, SGE_FL_BUFFER_SIZE2, - (t4_read_reg(adap, SGE_FL_BUFFER_SIZE2) + fl_align-1) + t4_write_reg(adap, SGE_FL_BUFFER_SIZE0_A, page_size); + t4_write_reg(adap, SGE_FL_BUFFER_SIZE2_A, + (t4_read_reg(adap, SGE_FL_BUFFER_SIZE2_A) + fl_align-1) & ~(fl_align-1)); - t4_write_reg(adap, SGE_FL_BUFFER_SIZE3, - (t4_read_reg(adap, SGE_FL_BUFFER_SIZE3) + fl_align-1) + t4_write_reg(adap, SGE_FL_BUFFER_SIZE3_A, + (t4_read_reg(adap, SGE_FL_BUFFER_SIZE3_A) + fl_align-1) & ~(fl_align-1)); - t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(page_shift - 12)); + t4_write_reg(adap, ULP_RX_TDDP_PSZ_A, HPZ0_V(page_shift - 12)); return 0; } @@ -3917,12 +4221,12 @@ int t4_wait_dev_ready(void __iomem *regs) { u32 whoami; - whoami = readl(regs + PL_WHOAMI); + whoami = readl(regs + PL_WHOAMI_A); if (whoami != 0xffffffff && whoami != CIM_PF_NOACCESS) return 0; msleep(500); - whoami = readl(regs + PL_WHOAMI); + whoami = readl(regs + PL_WHOAMI_A); return (whoami != 0xffffffff && whoami != CIM_PF_NOACCESS ? 0 : -EIO); } @@ -3946,7 +4250,7 @@ static int get_flash_params(struct adapter *adap) ret = sf1_write(adap, 1, 1, 0, SF_RD_ID); if (!ret) ret = sf1_read(adap, 3, 0, 1, &info); - t4_write_reg(adap, SF_OP, 0); /* unlock SF */ + t4_write_reg(adap, SF_OP_A, 0); /* unlock SF */ if (ret) return ret; @@ -3969,7 +4273,7 @@ static int get_flash_params(struct adapter *adap) return -EINVAL; adap->params.sf_size = 1 << info; adap->params.sf_fw_start = - t4_read_reg(adap, CIM_BOOT_CFG) & BOOTADDR_MASK; + t4_read_reg(adap, CIM_BOOT_CFG_A) & BOOTADDR_M; if (adap->params.sf_size < FLASH_MIN_SIZE) dev_warn(adap->pdev_dev, "WARNING!!! FLASH size %#x < %#x!!!\n", @@ -3993,7 +4297,7 @@ int t4_prep_adapter(struct adapter *adapter) u32 pl_rev; get_pci_mode(adapter, &adapter->params.pci); - pl_rev = G_REV(t4_read_reg(adapter, PL_REV)); + pl_rev = REV_G(t4_read_reg(adapter, PL_REV_A)); ret = get_flash_params(adapter); if (ret < 0) { @@ -4019,6 +4323,7 @@ int t4_prep_adapter(struct adapter *adapter) return -EINVAL; } + adapter->params.cim_la_size = CIMLA_SIZE; init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); /* @@ -4133,7 +4438,7 @@ int t4_init_sge_params(struct adapter *adapter) /* Extract the SGE Page Size for our PF. */ - hps = t4_read_reg(adapter, SGE_HOST_PAGE_SIZE); + hps = t4_read_reg(adapter, SGE_HOST_PAGE_SIZE_A); s_hps = (HOSTPAGESIZEPF0_S + (HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * adapter->fn); sge_params->hps = ((hps >> s_hps) & HOSTPAGESIZEPF0_M); @@ -4142,10 +4447,10 @@ int t4_init_sge_params(struct adapter *adapter) */ s_qpp = (QUEUESPERPAGEPF0_S + (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * adapter->fn); - qpp = t4_read_reg(adapter, SGE_EGRESS_QUEUES_PER_PAGE_PF); - sge_params->eq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_MASK); - qpp = t4_read_reg(adapter, SGE_INGRESS_QUEUES_PER_PAGE_PF); - sge_params->iq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_MASK); + qpp = t4_read_reg(adapter, SGE_EGRESS_QUEUES_PER_PAGE_PF_A); + sge_params->eq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_M); + qpp = t4_read_reg(adapter, SGE_INGRESS_QUEUES_PER_PAGE_PF_A); + sge_params->iq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_M); return 0; } @@ -4161,9 +4466,9 @@ int t4_init_tp_params(struct adapter *adap) int chan; u32 v; - v = t4_read_reg(adap, TP_TIMER_RESOLUTION); - adap->params.tp.tre = TIMERRESOLUTION_GET(v); - adap->params.tp.dack_re = DELAYEDACKRESOLUTION_GET(v); + v = t4_read_reg(adap, TP_TIMER_RESOLUTION_A); + adap->params.tp.tre = TIMERRESOLUTION_G(v); + adap->params.tp.dack_re = DELAYEDACKRESOLUTION_G(v); /* MODQ_REQ_MAP defaults to setting queues 0-3 to chan 0-3 */ for (chan = 0; chan < NCHAN; chan++) @@ -4172,27 +4477,27 @@ int t4_init_tp_params(struct adapter *adap) /* Cache the adapter's Compressed Filter Mode and global Incress * Configuration. */ - t4_read_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA, + t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, &adap->params.tp.vlan_pri_map, 1, - TP_VLAN_PRI_MAP); - t4_read_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA, + TP_VLAN_PRI_MAP_A); + t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, &adap->params.tp.ingress_config, 1, - TP_INGRESS_CONFIG); + TP_INGRESS_CONFIG_A); /* Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field * shift positions of several elements of the Compressed Filter Tuple * for this adapter which we need frequently ... */ - adap->params.tp.vlan_shift = t4_filter_field_shift(adap, F_VLAN); - adap->params.tp.vnic_shift = t4_filter_field_shift(adap, F_VNIC_ID); - adap->params.tp.port_shift = t4_filter_field_shift(adap, F_PORT); + adap->params.tp.vlan_shift = t4_filter_field_shift(adap, VLAN_F); + adap->params.tp.vnic_shift = t4_filter_field_shift(adap, VNIC_ID_F); + adap->params.tp.port_shift = t4_filter_field_shift(adap, PORT_F); adap->params.tp.protocol_shift = t4_filter_field_shift(adap, - F_PROTOCOL); + PROTOCOL_F); /* If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID * represents the presense of an Outer VLAN instead of a VNIC ID. */ - if ((adap->params.tp.ingress_config & F_VNIC) == 0) + if ((adap->params.tp.ingress_config & VNIC_F) == 0) adap->params.tp.vnic_shift = -1; return 0; @@ -4218,35 +4523,35 @@ int t4_filter_field_shift(const struct adapter *adap, int filter_sel) for (sel = 1, field_shift = 0; sel < filter_sel; sel <<= 1) { switch (filter_mode & sel) { - case F_FCOE: - field_shift += W_FT_FCOE; + case FCOE_F: + field_shift += FT_FCOE_W; break; - case F_PORT: - field_shift += W_FT_PORT; + case PORT_F: + field_shift += FT_PORT_W; break; - case F_VNIC_ID: - field_shift += W_FT_VNIC_ID; + case VNIC_ID_F: + field_shift += FT_VNIC_ID_W; break; - case F_VLAN: - field_shift += W_FT_VLAN; + case VLAN_F: + field_shift += FT_VLAN_W; break; - case F_TOS: - field_shift += W_FT_TOS; + case TOS_F: + field_shift += FT_TOS_W; break; - case F_PROTOCOL: - field_shift += W_FT_PROTOCOL; + case PROTOCOL_F: + field_shift += FT_PROTOCOL_W; break; - case F_ETHERTYPE: - field_shift += W_FT_ETHERTYPE; + case ETHERTYPE_F: + field_shift += FT_ETHERTYPE_W; break; - case F_MACMATCH: - field_shift += W_FT_MACMATCH; + case MACMATCH_F: + field_shift += FT_MACMATCH_W; break; - case F_MPSHITTYPE: - field_shift += W_FT_MPSHITTYPE; + case MPSHITTYPE_F: + field_shift += FT_MPSHITTYPE_W; break; - case F_FRAGMENTATION: - field_shift += W_FT_FRAGMENTATION; + case FRAGMENTATION_F: + field_shift += FT_FRAGMENTATION_W; break; } } @@ -4311,3 +4616,289 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf) } return 0; } + +/** + * t4_read_cimq_cfg - read CIM queue configuration + * @adap: the adapter + * @base: holds the queue base addresses in bytes + * @size: holds the queue sizes in bytes + * @thres: holds the queue full thresholds in bytes + * + * Returns the current configuration of the CIM queues, starting with + * the IBQs, then the OBQs. + */ +void t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres) +{ + unsigned int i, v; + int cim_num_obq = is_t4(adap->params.chip) ? + CIM_NUM_OBQ : CIM_NUM_OBQ_T5; + + for (i = 0; i < CIM_NUM_IBQ; i++) { + t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, IBQSELECT_F | + QUENUMSELECT_V(i)); + v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A); + /* value is in 256-byte units */ + *base++ = CIMQBASE_G(v) * 256; + *size++ = CIMQSIZE_G(v) * 256; + *thres++ = QUEFULLTHRSH_G(v) * 8; /* 8-byte unit */ + } + for (i = 0; i < cim_num_obq; i++) { + t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, OBQSELECT_F | + QUENUMSELECT_V(i)); + v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A); + /* value is in 256-byte units */ + *base++ = CIMQBASE_G(v) * 256; + *size++ = CIMQSIZE_G(v) * 256; + } +} + +/** + * t4_read_cim_ibq - read the contents of a CIM inbound queue + * @adap: the adapter + * @qid: the queue index + * @data: where to store the queue contents + * @n: capacity of @data in 32-bit words + * + * Reads the contents of the selected CIM queue starting at address 0 up + * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on + * error and the number of 32-bit words actually read on success. + */ +int t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, size_t n) +{ + int i, err, attempts; + unsigned int addr; + const unsigned int nwords = CIM_IBQ_SIZE * 4; + + if (qid > 5 || (n & 3)) + return -EINVAL; + + addr = qid * nwords; + if (n > nwords) + n = nwords; + + /* It might take 3-10ms before the IBQ debug read access is allowed. + * Wait for 1 Sec with a delay of 1 usec. + */ + attempts = 1000000; + + for (i = 0; i < n; i++, addr++) { + t4_write_reg(adap, CIM_IBQ_DBG_CFG_A, IBQDBGADDR_V(addr) | + IBQDBGEN_F); + err = t4_wait_op_done(adap, CIM_IBQ_DBG_CFG_A, IBQDBGBUSY_F, 0, + attempts, 1); + if (err) + return err; + *data++ = t4_read_reg(adap, CIM_IBQ_DBG_DATA_A); + } + t4_write_reg(adap, CIM_IBQ_DBG_CFG_A, 0); + return i; +} + +/** + * t4_read_cim_obq - read the contents of a CIM outbound queue + * @adap: the adapter + * @qid: the queue index + * @data: where to store the queue contents + * @n: capacity of @data in 32-bit words + * + * Reads the contents of the selected CIM queue starting at address 0 up + * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on + * error and the number of 32-bit words actually read on success. + */ +int t4_read_cim_obq(struct adapter *adap, unsigned int qid, u32 *data, size_t n) +{ + int i, err; + unsigned int addr, v, nwords; + int cim_num_obq = is_t4(adap->params.chip) ? + CIM_NUM_OBQ : CIM_NUM_OBQ_T5; + + if ((qid > (cim_num_obq - 1)) || (n & 3)) + return -EINVAL; + + t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, OBQSELECT_F | + QUENUMSELECT_V(qid)); + v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A); + + addr = CIMQBASE_G(v) * 64; /* muliple of 256 -> muliple of 4 */ + nwords = CIMQSIZE_G(v) * 64; /* same */ + if (n > nwords) + n = nwords; + + for (i = 0; i < n; i++, addr++) { + t4_write_reg(adap, CIM_OBQ_DBG_CFG_A, OBQDBGADDR_V(addr) | + OBQDBGEN_F); + err = t4_wait_op_done(adap, CIM_OBQ_DBG_CFG_A, OBQDBGBUSY_F, 0, + 2, 1); + if (err) + return err; + *data++ = t4_read_reg(adap, CIM_OBQ_DBG_DATA_A); + } + t4_write_reg(adap, CIM_OBQ_DBG_CFG_A, 0); + return i; +} + +/** + * t4_cim_read - read a block from CIM internal address space + * @adap: the adapter + * @addr: the start address within the CIM address space + * @n: number of words to read + * @valp: where to store the result + * + * Reads a block of 4-byte words from the CIM intenal address space. + */ +int t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n, + unsigned int *valp) +{ + int ret = 0; + + if (t4_read_reg(adap, CIM_HOST_ACC_CTRL_A) & HOSTBUSY_F) + return -EBUSY; + + for ( ; !ret && n--; addr += 4) { + t4_write_reg(adap, CIM_HOST_ACC_CTRL_A, addr); + ret = t4_wait_op_done(adap, CIM_HOST_ACC_CTRL_A, HOSTBUSY_F, + 0, 5, 2); + if (!ret) + *valp++ = t4_read_reg(adap, CIM_HOST_ACC_DATA_A); + } + return ret; +} + +/** + * t4_cim_write - write a block into CIM internal address space + * @adap: the adapter + * @addr: the start address within the CIM address space + * @n: number of words to write + * @valp: set of values to write + * + * Writes a block of 4-byte words into the CIM intenal address space. + */ +int t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n, + const unsigned int *valp) +{ + int ret = 0; + + if (t4_read_reg(adap, CIM_HOST_ACC_CTRL_A) & HOSTBUSY_F) + return -EBUSY; + + for ( ; !ret && n--; addr += 4) { + t4_write_reg(adap, CIM_HOST_ACC_DATA_A, *valp++); + t4_write_reg(adap, CIM_HOST_ACC_CTRL_A, addr | HOSTWRITE_F); + ret = t4_wait_op_done(adap, CIM_HOST_ACC_CTRL_A, HOSTBUSY_F, + 0, 5, 2); + } + return ret; +} + +static int t4_cim_write1(struct adapter *adap, unsigned int addr, + unsigned int val) +{ + return t4_cim_write(adap, addr, 1, &val); +} + +/** + * t4_cim_read_la - read CIM LA capture buffer + * @adap: the adapter + * @la_buf: where to store the LA data + * @wrptr: the HW write pointer within the capture buffer + * + * Reads the contents of the CIM LA buffer with the most recent entry at + * the end of the returned data and with the entry at @wrptr first. + * We try to leave the LA in the running state we find it in. + */ +int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr) +{ + int i, ret; + unsigned int cfg, val, idx; + + ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &cfg); + if (ret) + return ret; + + if (cfg & UPDBGLAEN_F) { /* LA is running, freeze it */ + ret = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A, 0); + if (ret) + return ret; + } + + ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &val); + if (ret) + goto restart; + + idx = UPDBGLAWRPTR_G(val); + if (wrptr) + *wrptr = idx; + + for (i = 0; i < adap->params.cim_la_size; i++) { + ret = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A, + UPDBGLARDPTR_V(idx) | UPDBGLARDEN_F); + if (ret) + break; + ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &val); + if (ret) + break; + if (val & UPDBGLARDEN_F) { + ret = -ETIMEDOUT; + break; + } + ret = t4_cim_read(adap, UP_UP_DBG_LA_DATA_A, 1, &la_buf[i]); + if (ret) + break; + idx = (idx + 1) & UPDBGLARDPTR_M; + } +restart: + if (cfg & UPDBGLAEN_F) { + int r = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A, + cfg & ~UPDBGLARDEN_F); + if (!ret) + ret = r; + } + return ret; +} + +/** + * t4_tp_read_la - read TP LA capture buffer + * @adap: the adapter + * @la_buf: where to store the LA data + * @wrptr: the HW write pointer within the capture buffer + * + * Reads the contents of the TP LA buffer with the most recent entry at + * the end of the returned data and with the entry at @wrptr first. + * We leave the LA in the running state we find it in. + */ +void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr) +{ + bool last_incomplete; + unsigned int i, cfg, val, idx; + + cfg = t4_read_reg(adap, TP_DBG_LA_CONFIG_A) & 0xffff; + if (cfg & DBGLAENABLE_F) /* freeze LA */ + t4_write_reg(adap, TP_DBG_LA_CONFIG_A, + adap->params.tp.la_mask | (cfg ^ DBGLAENABLE_F)); + + val = t4_read_reg(adap, TP_DBG_LA_CONFIG_A); + idx = DBGLAWPTR_G(val); + last_incomplete = DBGLAMODE_G(val) >= 2 && (val & DBGLAWHLF_F) == 0; + if (last_incomplete) + idx = (idx + 1) & DBGLARPTR_M; + if (wrptr) + *wrptr = idx; + + val &= 0xffff; + val &= ~DBGLARPTR_V(DBGLARPTR_M); + val |= adap->params.tp.la_mask; + + for (i = 0; i < TPLA_SIZE; i++) { + t4_write_reg(adap, TP_DBG_LA_CONFIG_A, DBGLARPTR_V(idx) | val); + la_buf[i] = t4_read_reg64(adap, TP_DBG_LA_DATAL_A); + idx = (idx + 1) & DBGLARPTR_M; + } + + /* Wipe out last entry if it isn't valid */ + if (last_incomplete) + la_buf[TPLA_SIZE - 1] = ~0ULL; + + if (cfg & DBGLAENABLE_F) /* restore running state */ + t4_write_reg(adap, TP_DBG_LA_CONFIG_A, + cfg | adap->params.tp.la_mask); +} diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h index c19a90e7f7d1..380b15c0417a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h @@ -48,6 +48,7 @@ enum { NMTUS = 16, /* size of MTU table */ NCCTRL_WIN = 32, /* # of congestion control windows */ L2T_SIZE = 4096, /* # of L2T entries */ + PM_NSTATS = 5, /* # of PM stats */ MBOX_LEN = 64, /* mailbox size in bytes */ TRACE_LEN = 112, /* length of trace data and mask */ FILTER_OPT_LEN = 36, /* filter tuple width for optional components */ @@ -55,6 +56,17 @@ enum { WOL_PAT_LEN = 128, /* length of WoL patterns */ }; +enum { + CIM_NUM_IBQ = 6, /* # of CIM IBQs */ + CIM_NUM_OBQ = 6, /* # of CIM OBQs */ + CIM_NUM_OBQ_T5 = 8, /* # of CIM OBQs for T5 adapter */ + CIMLA_SIZE = 2048, /* # of 32-bit words in CIM LA */ + CIM_IBQ_SIZE = 128, /* # of 128-bit words in a CIM IBQ */ + CIM_OBQ_SIZE = 128, /* # of 128-bit words in a CIM OBQ */ + TPLA_SIZE = 128, /* # of 64-bit words in TP LA */ + ULPRX_LA_SIZE = 512, /* # of 256-bit words in ULP_RX LA */ +}; + enum { SF_PAGE_SIZE = 256, /* serial flash page size */ SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */ @@ -110,6 +122,18 @@ enum { SGE_INGPADBOUNDARY_SHIFT = 5,/* ingress queue pad boundary */ }; +/* PCI-e memory window access */ +enum pcie_memwin { + MEMWIN_NIC = 0, + MEMWIN_RSVD1 = 1, + MEMWIN_RSVD2 = 2, + MEMWIN_RDMA = 3, + MEMWIN_RSVD4 = 4, + MEMWIN_FOISCSI = 5, + MEMWIN_CSIOSTOR = 6, + MEMWIN_RSVD7 = 7, +}; + struct sge_qstat { /* data written to SGE queue status entries */ __be32 qid; __be16 cidx; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index 0f89f68948ab..0fb975e258b3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -123,6 +123,13 @@ enum CPL_error { CPL_ERR_IWARP_FLM = 50, }; +enum { + CPL_CONN_POLICY_AUTO = 0, + CPL_CONN_POLICY_ASK = 1, + CPL_CONN_POLICY_FILTER = 2, + CPL_CONN_POLICY_DENY = 3 +}; + enum { ULP_MODE_NONE = 0, ULP_MODE_ISCSI = 2, @@ -160,16 +167,28 @@ union opcode_tid { u8 opcode; }; -#define CPL_OPCODE(x) ((x) << 24) -#define G_CPL_OPCODE(x) (((x) >> 24) & 0xFF) -#define MK_OPCODE_TID(opcode, tid) (CPL_OPCODE(opcode) | (tid)) +#define CPL_OPCODE_S 24 +#define CPL_OPCODE_V(x) ((x) << CPL_OPCODE_S) +#define CPL_OPCODE_G(x) (((x) >> CPL_OPCODE_S) & 0xFF) +#define TID_G(x) ((x) & 0xFFFFFF) + +/* tid is assumed to be 24-bits */ +#define MK_OPCODE_TID(opcode, tid) (CPL_OPCODE_V(opcode) | (tid)) + #define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid) -#define GET_TID(cmd) (ntohl(OPCODE_TID(cmd)) & 0xFFFFFF) + +/* extract the TID from a CPL command */ +#define GET_TID(cmd) (TID_G(be32_to_cpu(OPCODE_TID(cmd)))) /* partitioning of TID fields that also carry a queue id */ -#define GET_TID_TID(x) ((x) & 0x3fff) -#define GET_TID_QID(x) (((x) >> 14) & 0x3ff) -#define TID_QID(x) ((x) << 14) +#define TID_TID_S 0 +#define TID_TID_M 0x3fff +#define TID_TID_G(x) (((x) >> TID_TID_S) & TID_TID_M) + +#define TID_QID_S 14 +#define TID_QID_M 0x3ff +#define TID_QID_V(x) ((x) << TID_QID_S) +#define TID_QID_G(x) (((x) >> TID_QID_S) & TID_QID_M) struct rss_header { u8 opcode; @@ -199,8 +218,8 @@ struct work_request_hdr { }; /* wr_hi fields */ -#define S_WR_OP 24 -#define V_WR_OP(x) ((__u64)(x) << S_WR_OP) +#define WR_OP_S 24 +#define WR_OP_V(x) ((__u64)(x) << WR_OP_S) #define WR_HDR struct work_request_hdr wr @@ -270,17 +289,42 @@ struct cpl_pass_open_req { __be32 local_ip; __be32 peer_ip; __be64 opt0; -#define NO_CONG(x) ((x) << 4) -#define DELACK(x) ((x) << 5) -#define DSCP(x) ((x) << 22) -#define TCAM_BYPASS(x) ((u64)(x) << 48) -#define NAGLE(x) ((u64)(x) << 49) __be64 opt1; -#define SYN_RSS_ENABLE (1 << 0) -#define SYN_RSS_QUEUE(x) ((x) << 2) -#define CONN_POLICY_ASK (1 << 22) }; +/* option 0 fields */ +#define NO_CONG_S 4 +#define NO_CONG_V(x) ((x) << NO_CONG_S) +#define NO_CONG_F NO_CONG_V(1U) + +#define DELACK_S 5 +#define DELACK_V(x) ((x) << DELACK_S) +#define DELACK_F DELACK_V(1U) + +#define DSCP_S 22 +#define DSCP_M 0x3F +#define DSCP_V(x) ((x) << DSCP_S) +#define DSCP_G(x) (((x) >> DSCP_S) & DSCP_M) + +#define TCAM_BYPASS_S 48 +#define TCAM_BYPASS_V(x) ((__u64)(x) << TCAM_BYPASS_S) +#define TCAM_BYPASS_F TCAM_BYPASS_V(1ULL) + +#define NAGLE_S 49 +#define NAGLE_V(x) ((__u64)(x) << NAGLE_S) +#define NAGLE_F NAGLE_V(1ULL) + +/* option 1 fields */ +#define SYN_RSS_ENABLE_S 0 +#define SYN_RSS_ENABLE_V(x) ((x) << SYN_RSS_ENABLE_S) +#define SYN_RSS_ENABLE_F SYN_RSS_ENABLE_V(1U) + +#define SYN_RSS_QUEUE_S 2 +#define SYN_RSS_QUEUE_V(x) ((x) << SYN_RSS_QUEUE_S) + +#define CONN_POLICY_S 22 +#define CONN_POLICY_V(x) ((x) << CONN_POLICY_S) + struct cpl_pass_open_req6 { WR_HDR; union opcode_tid ot; @@ -304,16 +348,37 @@ struct cpl_pass_accept_rpl { WR_HDR; union opcode_tid ot; __be32 opt2; -#define RX_COALESCE_VALID(x) ((x) << 11) -#define RX_COALESCE(x) ((x) << 12) -#define PACE(x) ((x) << 16) -#define TX_QUEUE(x) ((x) << 23) -#define CCTRL_ECN(x) ((x) << 27) -#define TSTAMPS_EN(x) ((x) << 29) -#define SACK_EN(x) ((x) << 30) __be64 opt0; }; +/* option 2 fields */ +#define RX_COALESCE_VALID_S 11 +#define RX_COALESCE_VALID_V(x) ((x) << RX_COALESCE_VALID_S) +#define RX_COALESCE_VALID_F RX_COALESCE_VALID_V(1U) + +#define RX_COALESCE_S 12 +#define RX_COALESCE_V(x) ((x) << RX_COALESCE_S) + +#define PACE_S 16 +#define PACE_V(x) ((x) << PACE_S) + +#define TX_QUEUE_S 23 +#define TX_QUEUE_M 0x7 +#define TX_QUEUE_V(x) ((x) << TX_QUEUE_S) +#define TX_QUEUE_G(x) (((x) >> TX_QUEUE_S) & TX_QUEUE_M) + +#define CCTRL_ECN_S 27 +#define CCTRL_ECN_V(x) ((x) << CCTRL_ECN_S) +#define CCTRL_ECN_F CCTRL_ECN_V(1U) + +#define TSTAMPS_EN_S 29 +#define TSTAMPS_EN_V(x) ((x) << TSTAMPS_EN_S) +#define TSTAMPS_EN_F TSTAMPS_EN_V(1U) + +#define SACK_EN_S 30 +#define SACK_EN_V(x) ((x) << SACK_EN_S) +#define SACK_EN_F SACK_EN_V(1U) + struct cpl_t5_pass_accept_rpl { WR_HDR; union opcode_tid ot; @@ -384,30 +449,61 @@ struct cpl_t5_act_open_req6 { struct cpl_act_open_rpl { union opcode_tid ot; __be32 atid_status; -#define GET_AOPEN_STATUS(x) ((x) & 0xff) -#define GET_AOPEN_ATID(x) (((x) >> 8) & 0xffffff) }; +/* cpl_act_open_rpl.atid_status fields */ +#define AOPEN_STATUS_S 0 +#define AOPEN_STATUS_M 0xFF +#define AOPEN_STATUS_G(x) (((x) >> AOPEN_STATUS_S) & AOPEN_STATUS_M) + +#define AOPEN_ATID_S 8 +#define AOPEN_ATID_M 0xFFFFFF +#define AOPEN_ATID_G(x) (((x) >> AOPEN_ATID_S) & AOPEN_ATID_M) + struct cpl_pass_establish { union opcode_tid ot; __be32 rsvd; __be32 tos_stid; -#define PASS_OPEN_TID(x) ((x) << 0) -#define PASS_OPEN_TOS(x) ((x) << 24) -#define GET_PASS_OPEN_TID(x) (((x) >> 0) & 0xFFFFFF) -#define GET_POPEN_TID(x) ((x) & 0xffffff) -#define GET_POPEN_TOS(x) (((x) >> 24) & 0xff) __be16 mac_idx; __be16 tcp_opt; -#define GET_TCPOPT_WSCALE_OK(x) (((x) >> 5) & 1) -#define GET_TCPOPT_SACK(x) (((x) >> 6) & 1) -#define GET_TCPOPT_TSTAMP(x) (((x) >> 7) & 1) -#define GET_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf) -#define GET_TCPOPT_MSS(x) (((x) >> 12) & 0xf) __be32 snd_isn; __be32 rcv_isn; }; +/* cpl_pass_establish.tos_stid fields */ +#define PASS_OPEN_TID_S 0 +#define PASS_OPEN_TID_M 0xFFFFFF +#define PASS_OPEN_TID_V(x) ((x) << PASS_OPEN_TID_S) +#define PASS_OPEN_TID_G(x) (((x) >> PASS_OPEN_TID_S) & PASS_OPEN_TID_M) + +#define PASS_OPEN_TOS_S 24 +#define PASS_OPEN_TOS_M 0xFF +#define PASS_OPEN_TOS_V(x) ((x) << PASS_OPEN_TOS_S) +#define PASS_OPEN_TOS_G(x) (((x) >> PASS_OPEN_TOS_S) & PASS_OPEN_TOS_M) + +/* cpl_pass_establish.tcp_opt fields (also applies to act_open_establish) */ +#define TCPOPT_WSCALE_OK_S 5 +#define TCPOPT_WSCALE_OK_M 0x1 +#define TCPOPT_WSCALE_OK_G(x) \ + (((x) >> TCPOPT_WSCALE_OK_S) & TCPOPT_WSCALE_OK_M) + +#define TCPOPT_SACK_S 6 +#define TCPOPT_SACK_M 0x1 +#define TCPOPT_SACK_G(x) (((x) >> TCPOPT_SACK_S) & TCPOPT_SACK_M) + +#define TCPOPT_TSTAMP_S 7 +#define TCPOPT_TSTAMP_M 0x1 +#define TCPOPT_TSTAMP_G(x) (((x) >> TCPOPT_TSTAMP_S) & TCPOPT_TSTAMP_M) + +#define TCPOPT_SND_WSCALE_S 8 +#define TCPOPT_SND_WSCALE_M 0xF +#define TCPOPT_SND_WSCALE_G(x) \ + (((x) >> TCPOPT_SND_WSCALE_S) & TCPOPT_SND_WSCALE_M) + +#define TCPOPT_MSS_S 12 +#define TCPOPT_MSS_M 0xF +#define TCPOPT_MSS_G(x) (((x) >> TCPOPT_MSS_S) & TCPOPT_MSS_M) + struct cpl_act_establish { union opcode_tid ot; __be32 rsvd; @@ -422,24 +518,39 @@ struct cpl_get_tcb { WR_HDR; union opcode_tid ot; __be16 reply_ctrl; -#define QUEUENO(x) ((x) << 0) -#define REPLY_CHAN(x) ((x) << 14) -#define NO_REPLY(x) ((x) << 15) __be16 cookie; }; +/* cpl_get_tcb.reply_ctrl fields */ +#define QUEUENO_S 0 +#define QUEUENO_V(x) ((x) << QUEUENO_S) + +#define REPLY_CHAN_S 14 +#define REPLY_CHAN_V(x) ((x) << REPLY_CHAN_S) +#define REPLY_CHAN_F REPLY_CHAN_V(1U) + +#define NO_REPLY_S 15 +#define NO_REPLY_V(x) ((x) << NO_REPLY_S) +#define NO_REPLY_F NO_REPLY_V(1U) + struct cpl_set_tcb_field { WR_HDR; union opcode_tid ot; __be16 reply_ctrl; __be16 word_cookie; -#define TCB_WORD(x) ((x) << 0) -#define TCB_COOKIE(x) ((x) << 5) -#define GET_TCB_COOKIE(x) (((x) >> 5) & 7) __be64 mask; __be64 val; }; +/* cpl_set_tcb_field.word_cookie fields */ +#define TCB_WORD_S 0 +#define TCB_WORD(x) ((x) << TCB_WORD_S) + +#define TCB_COOKIE_S 5 +#define TCB_COOKIE_M 0x7 +#define TCB_COOKIE_V(x) ((x) << TCB_COOKIE_S) +#define TCB_COOKIE_G(x) (((x) >> TCB_COOKIE_S) & TCB_COOKIE_M) + struct cpl_set_tcb_rpl { union opcode_tid ot; __be16 rsvd; @@ -466,10 +577,14 @@ struct cpl_close_listsvr_req { WR_HDR; union opcode_tid ot; __be16 reply_ctrl; -#define LISTSVR_IPV6(x) ((x) << 14) __be16 rsvd; }; +/* additional cpl_close_listsvr_req.reply_ctrl field */ +#define LISTSVR_IPV6_S 14 +#define LISTSVR_IPV6_V(x) ((x) << LISTSVR_IPV6_S) +#define LISTSVR_IPV6_F LISTSVR_IPV6_V(1U) + struct cpl_close_listsvr_rpl { union opcode_tid ot; u8 rsvd[3]; @@ -565,6 +680,34 @@ struct cpl_tx_pkt_lso_core { /* encapsulated CPL (TX_PKT, TX_PKT_XT or TX_DATA) follows here */ }; +/* cpl_tx_pkt_lso_core.lso_ctrl fields */ +#define LSO_TCPHDR_LEN_S 0 +#define LSO_TCPHDR_LEN_V(x) ((x) << LSO_TCPHDR_LEN_S) + +#define LSO_IPHDR_LEN_S 4 +#define LSO_IPHDR_LEN_V(x) ((x) << LSO_IPHDR_LEN_S) + +#define LSO_ETHHDR_LEN_S 16 +#define LSO_ETHHDR_LEN_V(x) ((x) << LSO_ETHHDR_LEN_S) + +#define LSO_IPV6_S 20 +#define LSO_IPV6_V(x) ((x) << LSO_IPV6_S) +#define LSO_IPV6_F LSO_IPV6_V(1U) + +#define LSO_LAST_SLICE_S 22 +#define LSO_LAST_SLICE_V(x) ((x) << LSO_LAST_SLICE_S) +#define LSO_LAST_SLICE_F LSO_LAST_SLICE_V(1U) + +#define LSO_FIRST_SLICE_S 23 +#define LSO_FIRST_SLICE_V(x) ((x) << LSO_FIRST_SLICE_S) +#define LSO_FIRST_SLICE_F LSO_FIRST_SLICE_V(1U) + +#define LSO_OPCODE_S 24 +#define LSO_OPCODE_V(x) ((x) << LSO_OPCODE_S) + +#define LSO_T5_XFER_SIZE_S 0 +#define LSO_T5_XFER_SIZE_V(x) ((x) << LSO_T5_XFER_SIZE_S) + struct cpl_tx_pkt_lso { WR_HDR; struct cpl_tx_pkt_lso_core c; @@ -574,8 +717,6 @@ struct cpl_tx_pkt_lso { struct cpl_iscsi_hdr { union opcode_tid ot; __be16 pdu_len_ddp; -#define ISCSI_PDU_LEN(x) ((x) & 0x7FFF) -#define ISCSI_DDP (1 << 15) __be16 len; __be32 seq; __be16 urg; @@ -583,6 +724,16 @@ struct cpl_iscsi_hdr { u8 status; }; +/* cpl_iscsi_hdr.pdu_len_ddp fields */ +#define ISCSI_PDU_LEN_S 0 +#define ISCSI_PDU_LEN_M 0x7FFF +#define ISCSI_PDU_LEN_V(x) ((x) << ISCSI_PDU_LEN_S) +#define ISCSI_PDU_LEN_G(x) (((x) >> ISCSI_PDU_LEN_S) & ISCSI_PDU_LEN_M) + +#define ISCSI_DDP_S 15 +#define ISCSI_DDP_V(x) ((x) << ISCSI_DDP_S) +#define ISCSI_DDP_F ISCSI_DDP_V(1U) + struct cpl_rx_data { union opcode_tid ot; __be16 rsvd; @@ -639,49 +790,61 @@ struct cpl_rx_pkt { __be16 vlan; __be16 len; __be32 l2info; -#define RXF_UDP (1 << 22) -#define RXF_TCP (1 << 23) -#define RXF_IP (1 << 24) -#define RXF_IP6 (1 << 25) __be16 hdr_len; __be16 err_vec; }; +#define RXF_UDP_S 22 +#define RXF_UDP_V(x) ((x) << RXF_UDP_S) +#define RXF_UDP_F RXF_UDP_V(1U) + +#define RXF_TCP_S 23 +#define RXF_TCP_V(x) ((x) << RXF_TCP_S) +#define RXF_TCP_F RXF_TCP_V(1U) + +#define RXF_IP_S 24 +#define RXF_IP_V(x) ((x) << RXF_IP_S) +#define RXF_IP_F RXF_IP_V(1U) + +#define RXF_IP6_S 25 +#define RXF_IP6_V(x) ((x) << RXF_IP6_S) +#define RXF_IP6_F RXF_IP6_V(1U) + /* rx_pkt.l2info fields */ -#define S_RX_ETHHDR_LEN 0 -#define M_RX_ETHHDR_LEN 0x1F -#define V_RX_ETHHDR_LEN(x) ((x) << S_RX_ETHHDR_LEN) -#define G_RX_ETHHDR_LEN(x) (((x) >> S_RX_ETHHDR_LEN) & M_RX_ETHHDR_LEN) +#define RX_ETHHDR_LEN_S 0 +#define RX_ETHHDR_LEN_M 0x1F +#define RX_ETHHDR_LEN_V(x) ((x) << RX_ETHHDR_LEN_S) +#define RX_ETHHDR_LEN_G(x) (((x) >> RX_ETHHDR_LEN_S) & RX_ETHHDR_LEN_M) -#define S_RX_T5_ETHHDR_LEN 0 -#define M_RX_T5_ETHHDR_LEN 0x3F -#define V_RX_T5_ETHHDR_LEN(x) ((x) << S_RX_T5_ETHHDR_LEN) -#define G_RX_T5_ETHHDR_LEN(x) (((x) >> S_RX_T5_ETHHDR_LEN) & M_RX_T5_ETHHDR_LEN) +#define RX_T5_ETHHDR_LEN_S 0 +#define RX_T5_ETHHDR_LEN_M 0x3F +#define RX_T5_ETHHDR_LEN_V(x) ((x) << RX_T5_ETHHDR_LEN_S) +#define RX_T5_ETHHDR_LEN_G(x) (((x) >> RX_T5_ETHHDR_LEN_S) & RX_T5_ETHHDR_LEN_M) -#define S_RX_MACIDX 8 -#define M_RX_MACIDX 0x1FF -#define V_RX_MACIDX(x) ((x) << S_RX_MACIDX) -#define G_RX_MACIDX(x) (((x) >> S_RX_MACIDX) & M_RX_MACIDX) +#define RX_MACIDX_S 8 +#define RX_MACIDX_M 0x1FF +#define RX_MACIDX_V(x) ((x) << RX_MACIDX_S) +#define RX_MACIDX_G(x) (((x) >> RX_MACIDX_S) & RX_MACIDX_M) -#define S_RXF_SYN 21 -#define V_RXF_SYN(x) ((x) << S_RXF_SYN) -#define F_RXF_SYN V_RXF_SYN(1U) +#define RXF_SYN_S 21 +#define RXF_SYN_V(x) ((x) << RXF_SYN_S) +#define RXF_SYN_F RXF_SYN_V(1U) -#define S_RX_CHAN 28 -#define M_RX_CHAN 0xF -#define V_RX_CHAN(x) ((x) << S_RX_CHAN) -#define G_RX_CHAN(x) (((x) >> S_RX_CHAN) & M_RX_CHAN) +#define RX_CHAN_S 28 +#define RX_CHAN_M 0xF +#define RX_CHAN_V(x) ((x) << RX_CHAN_S) +#define RX_CHAN_G(x) (((x) >> RX_CHAN_S) & RX_CHAN_M) /* rx_pkt.hdr_len fields */ -#define S_RX_TCPHDR_LEN 0 -#define M_RX_TCPHDR_LEN 0x3F -#define V_RX_TCPHDR_LEN(x) ((x) << S_RX_TCPHDR_LEN) -#define G_RX_TCPHDR_LEN(x) (((x) >> S_RX_TCPHDR_LEN) & M_RX_TCPHDR_LEN) +#define RX_TCPHDR_LEN_S 0 +#define RX_TCPHDR_LEN_M 0x3F +#define RX_TCPHDR_LEN_V(x) ((x) << RX_TCPHDR_LEN_S) +#define RX_TCPHDR_LEN_G(x) (((x) >> RX_TCPHDR_LEN_S) & RX_TCPHDR_LEN_M) -#define S_RX_IPHDR_LEN 6 -#define M_RX_IPHDR_LEN 0x3FF -#define V_RX_IPHDR_LEN(x) ((x) << S_RX_IPHDR_LEN) -#define G_RX_IPHDR_LEN(x) (((x) >> S_RX_IPHDR_LEN) & M_RX_IPHDR_LEN) +#define RX_IPHDR_LEN_S 6 +#define RX_IPHDR_LEN_M 0x3FF +#define RX_IPHDR_LEN_V(x) ((x) << RX_IPHDR_LEN_S) +#define RX_IPHDR_LEN_G(x) (((x) >> RX_IPHDR_LEN_S) & RX_IPHDR_LEN_M) struct cpl_trace_pkt { u8 opcode; @@ -730,14 +893,22 @@ struct cpl_l2t_write_req { WR_HDR; union opcode_tid ot; __be16 params; -#define L2T_W_INFO(x) ((x) << 2) -#define L2T_W_PORT(x) ((x) << 8) -#define L2T_W_NOREPLY(x) ((x) << 15) __be16 l2t_idx; __be16 vlan; u8 dst_mac[6]; }; +/* cpl_l2t_write_req.params fields */ +#define L2T_W_INFO_S 2 +#define L2T_W_INFO_V(x) ((x) << L2T_W_INFO_S) + +#define L2T_W_PORT_S 8 +#define L2T_W_PORT_V(x) ((x) << L2T_W_PORT_S) + +#define L2T_W_NOREPLY_S 15 +#define L2T_W_NOREPLY_V(x) ((x) << L2T_W_NOREPLY_S) +#define L2T_W_NOREPLY_F L2T_W_NOREPLY_V(1U) + struct cpl_l2t_write_rpl { union opcode_tid ot; u8 status; @@ -752,11 +923,15 @@ struct cpl_rdma_terminate { struct cpl_sge_egr_update { __be32 opcode_qid; -#define EGR_QID(x) ((x) & 0x1FFFF) __be16 cidx; __be16 pidx; }; +/* cpl_sge_egr_update.ot fields */ +#define EGR_QID_S 0 +#define EGR_QID_M 0x1FFFF +#define EGR_QID_G(x) (((x) >> EGR_QID_S) & EGR_QID_M) + /* cpl_fw*.type values */ enum { FW_TYPE_CMD_RPL = 0, @@ -849,22 +1024,30 @@ struct ulptx_sge_pair { struct ulptx_sgl { __be32 cmd_nsge; -#define ULPTX_NSGE(x) ((x) << 0) -#define ULPTX_MORE (1U << 23) __be32 len0; __be64 addr0; struct ulptx_sge_pair sge[0]; }; +#define ULPTX_NSGE_S 0 +#define ULPTX_NSGE_V(x) ((x) << ULPTX_NSGE_S) + +#define ULPTX_MORE_S 23 +#define ULPTX_MORE_V(x) ((x) << ULPTX_MORE_S) +#define ULPTX_MORE_F ULPTX_MORE_V(1U) + struct ulp_mem_io { WR_HDR; __be32 cmd; __be32 len16; /* command length */ __be32 dlen; /* data length in 32-byte units */ __be32 lock_addr; -#define ULP_MEMIO_LOCK(x) ((x) << 31) }; +#define ULP_MEMIO_LOCK_S 31 +#define ULP_MEMIO_LOCK_V(x) ((x) << ULP_MEMIO_LOCK_S) +#define ULP_MEMIO_LOCK_F ULP_MEMIO_LOCK_V(1U) + /* additional ulp_mem_io.cmd fields */ #define ULP_MEMIO_ORDER_S 23 #define ULP_MEMIO_ORDER_V(x) ((x) << ULP_MEMIO_ORDER_S) @@ -874,13 +1057,9 @@ struct ulp_mem_io { #define T5_ULP_MEMIO_IMM_V(x) ((x) << T5_ULP_MEMIO_IMM_S) #define T5_ULP_MEMIO_IMM_F T5_ULP_MEMIO_IMM_V(1U) -#define S_T5_ULP_MEMIO_IMM 23 -#define V_T5_ULP_MEMIO_IMM(x) ((x) << S_T5_ULP_MEMIO_IMM) -#define F_T5_ULP_MEMIO_IMM V_T5_ULP_MEMIO_IMM(1U) - -#define S_T5_ULP_MEMIO_ORDER 22 -#define V_T5_ULP_MEMIO_ORDER(x) ((x) << S_T5_ULP_MEMIO_ORDER) -#define F_T5_ULP_MEMIO_ORDER V_T5_ULP_MEMIO_ORDER(1U) +#define T5_ULP_MEMIO_ORDER_S 22 +#define T5_ULP_MEMIO_ORDER_V(x) ((x) << T5_ULP_MEMIO_ORDER_S) +#define T5_ULP_MEMIO_ORDER_F T5_ULP_MEMIO_ORDER_V(1U) /* ulp_mem_io.lock_addr fields */ #define ULP_MEMIO_ADDR_S 0 diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h index 9e4f95a91fb4..ddfb5b846045 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h @@ -153,6 +153,7 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN CH_PCI_ID_TABLE_FENTRY(0x5086), /* Custom 2x T580-CR */ CH_PCI_ID_TABLE_FENTRY(0x5087), /* Custom T580-CR */ CH_PCI_ID_TABLE_FENTRY(0x5088), /* Custom T570-CR */ + CH_PCI_ID_TABLE_FENTRY(0x5089), /* Custom T520-CR */ CH_PCI_DEVICE_ID_TABLE_DEFINE_END; #endif /* CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index d7bd34ee65bd..231a725f6d5d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -63,460 +63,779 @@ #define MC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4) #define EDC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4) -#define SGE_PF_KDOORBELL 0x0 -#define QID_MASK 0xffff8000U -#define QID_SHIFT 15 -#define QID(x) ((x) << QID_SHIFT) -#define DBPRIO(x) ((x) << 14) -#define DBTYPE(x) ((x) << 13) -#define PIDX_MASK 0x00003fffU -#define PIDX_SHIFT 0 -#define PIDX(x) ((x) << PIDX_SHIFT) -#define PIDX_SHIFT_T5 0 -#define PIDX_T5(x) ((x) << PIDX_SHIFT_T5) +#define SGE_PF_KDOORBELL_A 0x0 +#define QID_S 15 +#define QID_V(x) ((x) << QID_S) -#define SGE_TIMERREGS 6 -#define SGE_PF_GTS 0x4 -#define INGRESSQID_MASK 0xffff0000U -#define INGRESSQID_SHIFT 16 -#define INGRESSQID(x) ((x) << INGRESSQID_SHIFT) -#define TIMERREG_MASK 0x0000e000U -#define TIMERREG_SHIFT 13 -#define TIMERREG(x) ((x) << TIMERREG_SHIFT) -#define SEINTARM_MASK 0x00001000U -#define SEINTARM_SHIFT 12 -#define SEINTARM(x) ((x) << SEINTARM_SHIFT) -#define CIDXINC_MASK 0x00000fffU -#define CIDXINC_SHIFT 0 -#define CIDXINC(x) ((x) << CIDXINC_SHIFT) +#define DBPRIO_S 14 +#define DBPRIO_V(x) ((x) << DBPRIO_S) +#define DBPRIO_F DBPRIO_V(1U) -#define X_RXPKTCPLMODE_SPLIT 1 -#define X_INGPADBOUNDARY_SHIFT 5 +#define PIDX_S 0 +#define PIDX_V(x) ((x) << PIDX_S) -#define SGE_CONTROL 0x1008 -#define SGE_CONTROL2_A 0x1124 -#define DCASYSTYPE 0x00080000U -#define RXPKTCPLMODE_MASK 0x00040000U -#define RXPKTCPLMODE_SHIFT 18 -#define RXPKTCPLMODE(x) ((x) << RXPKTCPLMODE_SHIFT) -#define EGRSTATUSPAGESIZE_MASK 0x00020000U -#define EGRSTATUSPAGESIZE_SHIFT 17 -#define EGRSTATUSPAGESIZE(x) ((x) << EGRSTATUSPAGESIZE_SHIFT) -#define PKTSHIFT_MASK 0x00001c00U -#define PKTSHIFT_SHIFT 10 -#define PKTSHIFT(x) ((x) << PKTSHIFT_SHIFT) -#define PKTSHIFT_GET(x) (((x) & PKTSHIFT_MASK) >> PKTSHIFT_SHIFT) -#define INGPCIEBOUNDARY_32B_X 0 -#define INGPCIEBOUNDARY_MASK 0x00000380U -#define INGPCIEBOUNDARY_SHIFT 7 -#define INGPCIEBOUNDARY(x) ((x) << INGPCIEBOUNDARY_SHIFT) -#define INGPADBOUNDARY_MASK 0x00000070U -#define INGPADBOUNDARY_SHIFT 4 -#define INGPADBOUNDARY(x) ((x) << INGPADBOUNDARY_SHIFT) -#define INGPADBOUNDARY_GET(x) (((x) & INGPADBOUNDARY_MASK) \ - >> INGPADBOUNDARY_SHIFT) -#define INGPACKBOUNDARY_16B_X 0 -#define INGPACKBOUNDARY_SHIFT_X 5 +#define SGE_VF_KDOORBELL_A 0x0 + +#define DBTYPE_S 13 +#define DBTYPE_V(x) ((x) << DBTYPE_S) +#define DBTYPE_F DBTYPE_V(1U) + +#define PIDX_T5_S 0 +#define PIDX_T5_M 0x1fffU +#define PIDX_T5_V(x) ((x) << PIDX_T5_S) +#define PIDX_T5_G(x) (((x) >> PIDX_T5_S) & PIDX_T5_M) + +#define SGE_PF_GTS_A 0x4 + +#define INGRESSQID_S 16 +#define INGRESSQID_V(x) ((x) << INGRESSQID_S) + +#define TIMERREG_S 13 +#define TIMERREG_V(x) ((x) << TIMERREG_S) + +#define SEINTARM_S 12 +#define SEINTARM_V(x) ((x) << SEINTARM_S) + +#define CIDXINC_S 0 +#define CIDXINC_M 0xfffU +#define CIDXINC_V(x) ((x) << CIDXINC_S) + +#define SGE_CONTROL_A 0x1008 +#define SGE_CONTROL2_A 0x1124 + +#define RXPKTCPLMODE_S 18 +#define RXPKTCPLMODE_V(x) ((x) << RXPKTCPLMODE_S) +#define RXPKTCPLMODE_F RXPKTCPLMODE_V(1U) + +#define EGRSTATUSPAGESIZE_S 17 +#define EGRSTATUSPAGESIZE_V(x) ((x) << EGRSTATUSPAGESIZE_S) +#define EGRSTATUSPAGESIZE_F EGRSTATUSPAGESIZE_V(1U) + +#define PKTSHIFT_S 10 +#define PKTSHIFT_M 0x7U +#define PKTSHIFT_V(x) ((x) << PKTSHIFT_S) +#define PKTSHIFT_G(x) (((x) >> PKTSHIFT_S) & PKTSHIFT_M) + +#define INGPCIEBOUNDARY_S 7 +#define INGPCIEBOUNDARY_V(x) ((x) << INGPCIEBOUNDARY_S) + +#define INGPADBOUNDARY_S 4 +#define INGPADBOUNDARY_M 0x7U +#define INGPADBOUNDARY_V(x) ((x) << INGPADBOUNDARY_S) +#define INGPADBOUNDARY_G(x) (((x) >> INGPADBOUNDARY_S) & INGPADBOUNDARY_M) + +#define EGRPCIEBOUNDARY_S 1 +#define EGRPCIEBOUNDARY_V(x) ((x) << EGRPCIEBOUNDARY_S) #define INGPACKBOUNDARY_S 16 #define INGPACKBOUNDARY_M 0x7U #define INGPACKBOUNDARY_V(x) ((x) << INGPACKBOUNDARY_S) #define INGPACKBOUNDARY_G(x) (((x) >> INGPACKBOUNDARY_S) \ & INGPACKBOUNDARY_M) -#define EGRPCIEBOUNDARY_MASK 0x0000000eU -#define EGRPCIEBOUNDARY_SHIFT 1 -#define EGRPCIEBOUNDARY(x) ((x) << EGRPCIEBOUNDARY_SHIFT) -#define GLOBALENABLE 0x00000001U -#define SGE_HOST_PAGE_SIZE 0x100c +#define GLOBALENABLE_S 0 +#define GLOBALENABLE_V(x) ((x) << GLOBALENABLE_S) +#define GLOBALENABLE_F GLOBALENABLE_V(1U) -#define HOSTPAGESIZEPF7_MASK 0x0000000fU -#define HOSTPAGESIZEPF7_SHIFT 28 -#define HOSTPAGESIZEPF7(x) ((x) << HOSTPAGESIZEPF7_SHIFT) +#define SGE_HOST_PAGE_SIZE_A 0x100c -#define HOSTPAGESIZEPF6_MASK 0x0000000fU -#define HOSTPAGESIZEPF6_SHIFT 24 -#define HOSTPAGESIZEPF6(x) ((x) << HOSTPAGESIZEPF6_SHIFT) +#define HOSTPAGESIZEPF7_S 28 +#define HOSTPAGESIZEPF7_M 0xfU +#define HOSTPAGESIZEPF7_V(x) ((x) << HOSTPAGESIZEPF7_S) +#define HOSTPAGESIZEPF7_G(x) (((x) >> HOSTPAGESIZEPF7_S) & HOSTPAGESIZEPF7_M) -#define HOSTPAGESIZEPF5_MASK 0x0000000fU -#define HOSTPAGESIZEPF5_SHIFT 20 -#define HOSTPAGESIZEPF5(x) ((x) << HOSTPAGESIZEPF5_SHIFT) +#define HOSTPAGESIZEPF6_S 24 +#define HOSTPAGESIZEPF6_M 0xfU +#define HOSTPAGESIZEPF6_V(x) ((x) << HOSTPAGESIZEPF6_S) +#define HOSTPAGESIZEPF6_G(x) (((x) >> HOSTPAGESIZEPF6_S) & HOSTPAGESIZEPF6_M) -#define HOSTPAGESIZEPF4_MASK 0x0000000fU -#define HOSTPAGESIZEPF4_SHIFT 16 -#define HOSTPAGESIZEPF4(x) ((x) << HOSTPAGESIZEPF4_SHIFT) +#define HOSTPAGESIZEPF5_S 20 +#define HOSTPAGESIZEPF5_M 0xfU +#define HOSTPAGESIZEPF5_V(x) ((x) << HOSTPAGESIZEPF5_S) +#define HOSTPAGESIZEPF5_G(x) (((x) >> HOSTPAGESIZEPF5_S) & HOSTPAGESIZEPF5_M) -#define HOSTPAGESIZEPF3_MASK 0x0000000fU -#define HOSTPAGESIZEPF3_SHIFT 12 -#define HOSTPAGESIZEPF3(x) ((x) << HOSTPAGESIZEPF3_SHIFT) +#define HOSTPAGESIZEPF4_S 16 +#define HOSTPAGESIZEPF4_M 0xfU +#define HOSTPAGESIZEPF4_V(x) ((x) << HOSTPAGESIZEPF4_S) +#define HOSTPAGESIZEPF4_G(x) (((x) >> HOSTPAGESIZEPF4_S) & HOSTPAGESIZEPF4_M) -#define HOSTPAGESIZEPF2_MASK 0x0000000fU -#define HOSTPAGESIZEPF2_SHIFT 8 -#define HOSTPAGESIZEPF2(x) ((x) << HOSTPAGESIZEPF2_SHIFT) +#define HOSTPAGESIZEPF3_S 12 +#define HOSTPAGESIZEPF3_M 0xfU +#define HOSTPAGESIZEPF3_V(x) ((x) << HOSTPAGESIZEPF3_S) +#define HOSTPAGESIZEPF3_G(x) (((x) >> HOSTPAGESIZEPF3_S) & HOSTPAGESIZEPF3_M) -#define HOSTPAGESIZEPF1_M 0x0000000fU -#define HOSTPAGESIZEPF1_S 4 -#define HOSTPAGESIZEPF1(x) ((x) << HOSTPAGESIZEPF1_S) +#define HOSTPAGESIZEPF2_S 8 +#define HOSTPAGESIZEPF2_M 0xfU +#define HOSTPAGESIZEPF2_V(x) ((x) << HOSTPAGESIZEPF2_S) +#define HOSTPAGESIZEPF2_G(x) (((x) >> HOSTPAGESIZEPF2_S) & HOSTPAGESIZEPF2_M) -#define HOSTPAGESIZEPF0_M 0x0000000fU -#define HOSTPAGESIZEPF0_S 0 -#define HOSTPAGESIZEPF0(x) ((x) << HOSTPAGESIZEPF0_S) +#define HOSTPAGESIZEPF1_S 4 +#define HOSTPAGESIZEPF1_M 0xfU +#define HOSTPAGESIZEPF1_V(x) ((x) << HOSTPAGESIZEPF1_S) +#define HOSTPAGESIZEPF1_G(x) (((x) >> HOSTPAGESIZEPF1_S) & HOSTPAGESIZEPF1_M) -#define SGE_EGRESS_QUEUES_PER_PAGE_PF 0x1010 +#define HOSTPAGESIZEPF0_S 0 +#define HOSTPAGESIZEPF0_M 0xfU +#define HOSTPAGESIZEPF0_V(x) ((x) << HOSTPAGESIZEPF0_S) +#define HOSTPAGESIZEPF0_G(x) (((x) >> HOSTPAGESIZEPF0_S) & HOSTPAGESIZEPF0_M) + +#define SGE_EGRESS_QUEUES_PER_PAGE_PF_A 0x1010 #define SGE_EGRESS_QUEUES_PER_PAGE_VF_A 0x1014 #define QUEUESPERPAGEPF1_S 4 #define QUEUESPERPAGEPF0_S 0 -#define QUEUESPERPAGEPF0_MASK 0x0000000fU -#define QUEUESPERPAGEPF0_GET(x) ((x) & QUEUESPERPAGEPF0_MASK) +#define QUEUESPERPAGEPF0_M 0xfU +#define QUEUESPERPAGEPF0_V(x) ((x) << QUEUESPERPAGEPF0_S) +#define QUEUESPERPAGEPF0_G(x) (((x) >> QUEUESPERPAGEPF0_S) & QUEUESPERPAGEPF0_M) -#define QUEUESPERPAGEPF0 0 -#define QUEUESPERPAGEPF1 4 +#define SGE_INT_CAUSE1_A 0x1024 +#define SGE_INT_CAUSE2_A 0x1030 +#define SGE_INT_CAUSE3_A 0x103c -/* T5 and later support a new BAR2-based doorbell mechanism for Egress Queues. - * The User Doorbells are each 128 bytes in length with a Simple Doorbell at - * offsets 8x and a Write Combining single 64-byte Egress Queue Unit - * (X_IDXSIZE_UNIT) Gather Buffer interface at offset 64. For Ingress Queues, - * we have a Going To Sleep register at offsets 8x+4. - * - * As noted above, we have many instances of the Simple Doorbell and Going To - * Sleep registers at offsets 8x and 8x+4, respectively. We want to use a - * non-64-byte aligned offset for the Simple Doorbell in order to attempt to - * avoid buffering of the writes to the Simple Doorbell and we want to use a - * non-contiguous offset for the Going To Sleep writes in order to avoid - * possible combining between them. - */ -#define SGE_UDB_SIZE 128 -#define SGE_UDB_KDOORBELL 8 -#define SGE_UDB_GTS 20 -#define SGE_UDB_WCDOORBELL 64 +#define ERR_FLM_DBP_S 31 +#define ERR_FLM_DBP_V(x) ((x) << ERR_FLM_DBP_S) +#define ERR_FLM_DBP_F ERR_FLM_DBP_V(1U) -#define SGE_INT_CAUSE1 0x1024 -#define SGE_INT_CAUSE2 0x1030 -#define SGE_INT_CAUSE3 0x103c -#define ERR_FLM_DBP 0x80000000U -#define ERR_FLM_IDMA1 0x40000000U -#define ERR_FLM_IDMA0 0x20000000U -#define ERR_FLM_HINT 0x10000000U -#define ERR_PCIE_ERROR3 0x08000000U -#define ERR_PCIE_ERROR2 0x04000000U -#define ERR_PCIE_ERROR1 0x02000000U -#define ERR_PCIE_ERROR0 0x01000000U -#define ERR_TIMER_ABOVE_MAX_QID 0x00800000U -#define ERR_CPL_EXCEED_IQE_SIZE 0x00400000U -#define ERR_INVALID_CIDX_INC 0x00200000U -#define ERR_ITP_TIME_PAUSED 0x00100000U -#define ERR_CPL_OPCODE_0 0x00080000U -#define ERR_DROPPED_DB 0x00040000U -#define ERR_DATA_CPL_ON_HIGH_QID1 0x00020000U -#define ERR_DATA_CPL_ON_HIGH_QID0 0x00010000U -#define ERR_BAD_DB_PIDX3 0x00008000U -#define ERR_BAD_DB_PIDX2 0x00004000U -#define ERR_BAD_DB_PIDX1 0x00002000U -#define ERR_BAD_DB_PIDX0 0x00001000U -#define ERR_ING_PCIE_CHAN 0x00000800U -#define ERR_ING_CTXT_PRIO 0x00000400U -#define ERR_EGR_CTXT_PRIO 0x00000200U -#define DBFIFO_HP_INT 0x00000100U -#define DBFIFO_LP_INT 0x00000080U -#define REG_ADDRESS_ERR 0x00000040U -#define INGRESS_SIZE_ERR 0x00000020U -#define EGRESS_SIZE_ERR 0x00000010U -#define ERR_INV_CTXT3 0x00000008U -#define ERR_INV_CTXT2 0x00000004U -#define ERR_INV_CTXT1 0x00000002U -#define ERR_INV_CTXT0 0x00000001U +#define ERR_FLM_IDMA1_S 30 +#define ERR_FLM_IDMA1_V(x) ((x) << ERR_FLM_IDMA1_S) +#define ERR_FLM_IDMA1_F ERR_FLM_IDMA1_V(1U) -#define SGE_INT_ENABLE3 0x1040 -#define SGE_FL_BUFFER_SIZE0 0x1044 -#define SGE_FL_BUFFER_SIZE1 0x1048 -#define SGE_FL_BUFFER_SIZE2 0x104c -#define SGE_FL_BUFFER_SIZE3 0x1050 -#define SGE_FL_BUFFER_SIZE4 0x1054 -#define SGE_FL_BUFFER_SIZE5 0x1058 -#define SGE_FL_BUFFER_SIZE6 0x105c -#define SGE_FL_BUFFER_SIZE7 0x1060 -#define SGE_FL_BUFFER_SIZE8 0x1064 +#define ERR_FLM_IDMA0_S 29 +#define ERR_FLM_IDMA0_V(x) ((x) << ERR_FLM_IDMA0_S) +#define ERR_FLM_IDMA0_F ERR_FLM_IDMA0_V(1U) -#define SGE_INGRESS_RX_THRESHOLD 0x10a0 -#define THRESHOLD_0_MASK 0x3f000000U -#define THRESHOLD_0_SHIFT 24 -#define THRESHOLD_0(x) ((x) << THRESHOLD_0_SHIFT) -#define THRESHOLD_0_GET(x) (((x) & THRESHOLD_0_MASK) >> THRESHOLD_0_SHIFT) -#define THRESHOLD_1_MASK 0x003f0000U -#define THRESHOLD_1_SHIFT 16 -#define THRESHOLD_1(x) ((x) << THRESHOLD_1_SHIFT) -#define THRESHOLD_1_GET(x) (((x) & THRESHOLD_1_MASK) >> THRESHOLD_1_SHIFT) -#define THRESHOLD_2_MASK 0x00003f00U -#define THRESHOLD_2_SHIFT 8 -#define THRESHOLD_2(x) ((x) << THRESHOLD_2_SHIFT) -#define THRESHOLD_2_GET(x) (((x) & THRESHOLD_2_MASK) >> THRESHOLD_2_SHIFT) -#define THRESHOLD_3_MASK 0x0000003fU -#define THRESHOLD_3_SHIFT 0 -#define THRESHOLD_3(x) ((x) << THRESHOLD_3_SHIFT) -#define THRESHOLD_3_GET(x) (((x) & THRESHOLD_3_MASK) >> THRESHOLD_3_SHIFT) +#define ERR_FLM_HINT_S 28 +#define ERR_FLM_HINT_V(x) ((x) << ERR_FLM_HINT_S) +#define ERR_FLM_HINT_F ERR_FLM_HINT_V(1U) -#define SGE_CONM_CTRL 0x1094 -#define EGRTHRESHOLD_MASK 0x00003f00U -#define EGRTHRESHOLDshift 8 -#define EGRTHRESHOLD(x) ((x) << EGRTHRESHOLDshift) -#define EGRTHRESHOLD_GET(x) (((x) & EGRTHRESHOLD_MASK) >> EGRTHRESHOLDshift) +#define ERR_PCIE_ERROR3_S 27 +#define ERR_PCIE_ERROR3_V(x) ((x) << ERR_PCIE_ERROR3_S) +#define ERR_PCIE_ERROR3_F ERR_PCIE_ERROR3_V(1U) -#define EGRTHRESHOLDPACKING_MASK 0x3fU -#define EGRTHRESHOLDPACKING_SHIFT 14 -#define EGRTHRESHOLDPACKING(x) ((x) << EGRTHRESHOLDPACKING_SHIFT) -#define EGRTHRESHOLDPACKING_GET(x) (((x) >> EGRTHRESHOLDPACKING_SHIFT) & \ - EGRTHRESHOLDPACKING_MASK) +#define ERR_PCIE_ERROR2_S 26 +#define ERR_PCIE_ERROR2_V(x) ((x) << ERR_PCIE_ERROR2_S) +#define ERR_PCIE_ERROR2_F ERR_PCIE_ERROR2_V(1U) -#define SGE_DBFIFO_STATUS 0x10a4 -#define HP_INT_THRESH_SHIFT 28 -#define HP_INT_THRESH_MASK 0xfU -#define HP_INT_THRESH(x) ((x) << HP_INT_THRESH_SHIFT) -#define LP_INT_THRESH_SHIFT 12 -#define LP_INT_THRESH_MASK 0xfU -#define LP_INT_THRESH(x) ((x) << LP_INT_THRESH_SHIFT) +#define ERR_PCIE_ERROR1_S 25 +#define ERR_PCIE_ERROR1_V(x) ((x) << ERR_PCIE_ERROR1_S) +#define ERR_PCIE_ERROR1_F ERR_PCIE_ERROR1_V(1U) -#define SGE_DOORBELL_CONTROL 0x10a8 -#define ENABLE_DROP (1 << 13) +#define ERR_PCIE_ERROR0_S 24 +#define ERR_PCIE_ERROR0_V(x) ((x) << ERR_PCIE_ERROR0_S) +#define ERR_PCIE_ERROR0_F ERR_PCIE_ERROR0_V(1U) -#define S_NOCOALESCE 26 -#define V_NOCOALESCE(x) ((x) << S_NOCOALESCE) -#define F_NOCOALESCE V_NOCOALESCE(1U) +#define ERR_CPL_EXCEED_IQE_SIZE_S 22 +#define ERR_CPL_EXCEED_IQE_SIZE_V(x) ((x) << ERR_CPL_EXCEED_IQE_SIZE_S) +#define ERR_CPL_EXCEED_IQE_SIZE_F ERR_CPL_EXCEED_IQE_SIZE_V(1U) -#define SGE_TIMESTAMP_LO 0x1098 -#define SGE_TIMESTAMP_HI 0x109c -#define S_TSVAL 0 -#define M_TSVAL 0xfffffffU -#define GET_TSVAL(x) (((x) >> S_TSVAL) & M_TSVAL) +#define ERR_INVALID_CIDX_INC_S 21 +#define ERR_INVALID_CIDX_INC_V(x) ((x) << ERR_INVALID_CIDX_INC_S) +#define ERR_INVALID_CIDX_INC_F ERR_INVALID_CIDX_INC_V(1U) -#define SGE_TIMER_VALUE_0_AND_1 0x10b8 -#define TIMERVALUE0_MASK 0xffff0000U -#define TIMERVALUE0_SHIFT 16 -#define TIMERVALUE0(x) ((x) << TIMERVALUE0_SHIFT) -#define TIMERVALUE0_GET(x) (((x) & TIMERVALUE0_MASK) >> TIMERVALUE0_SHIFT) -#define TIMERVALUE1_MASK 0x0000ffffU -#define TIMERVALUE1_SHIFT 0 -#define TIMERVALUE1(x) ((x) << TIMERVALUE1_SHIFT) -#define TIMERVALUE1_GET(x) (((x) & TIMERVALUE1_MASK) >> TIMERVALUE1_SHIFT) +#define ERR_CPL_OPCODE_0_S 19 +#define ERR_CPL_OPCODE_0_V(x) ((x) << ERR_CPL_OPCODE_0_S) +#define ERR_CPL_OPCODE_0_F ERR_CPL_OPCODE_0_V(1U) -#define SGE_TIMER_VALUE_2_AND_3 0x10bc -#define TIMERVALUE2_MASK 0xffff0000U -#define TIMERVALUE2_SHIFT 16 -#define TIMERVALUE2(x) ((x) << TIMERVALUE2_SHIFT) -#define TIMERVALUE2_GET(x) (((x) & TIMERVALUE2_MASK) >> TIMERVALUE2_SHIFT) -#define TIMERVALUE3_MASK 0x0000ffffU -#define TIMERVALUE3_SHIFT 0 -#define TIMERVALUE3(x) ((x) << TIMERVALUE3_SHIFT) -#define TIMERVALUE3_GET(x) (((x) & TIMERVALUE3_MASK) >> TIMERVALUE3_SHIFT) +#define ERR_DROPPED_DB_S 18 +#define ERR_DROPPED_DB_V(x) ((x) << ERR_DROPPED_DB_S) +#define ERR_DROPPED_DB_F ERR_DROPPED_DB_V(1U) -#define SGE_TIMER_VALUE_4_AND_5 0x10c0 -#define TIMERVALUE4_MASK 0xffff0000U -#define TIMERVALUE4_SHIFT 16 -#define TIMERVALUE4(x) ((x) << TIMERVALUE4_SHIFT) -#define TIMERVALUE4_GET(x) (((x) & TIMERVALUE4_MASK) >> TIMERVALUE4_SHIFT) -#define TIMERVALUE5_MASK 0x0000ffffU -#define TIMERVALUE5_SHIFT 0 -#define TIMERVALUE5(x) ((x) << TIMERVALUE5_SHIFT) -#define TIMERVALUE5_GET(x) (((x) & TIMERVALUE5_MASK) >> TIMERVALUE5_SHIFT) +#define ERR_DATA_CPL_ON_HIGH_QID1_S 17 +#define ERR_DATA_CPL_ON_HIGH_QID1_V(x) ((x) << ERR_DATA_CPL_ON_HIGH_QID1_S) +#define ERR_DATA_CPL_ON_HIGH_QID1_F ERR_DATA_CPL_ON_HIGH_QID1_V(1U) -#define SGE_DEBUG_INDEX 0x10cc -#define SGE_DEBUG_DATA_HIGH 0x10d0 -#define SGE_DEBUG_DATA_LOW 0x10d4 -#define SGE_DEBUG_DATA_LOW_INDEX_2 0x12c8 -#define SGE_DEBUG_DATA_LOW_INDEX_3 0x12cc -#define SGE_DEBUG_DATA_HIGH_INDEX_10 0x12a8 -#define SGE_INGRESS_QUEUES_PER_PAGE_PF 0x10f4 +#define ERR_DATA_CPL_ON_HIGH_QID0_S 16 +#define ERR_DATA_CPL_ON_HIGH_QID0_V(x) ((x) << ERR_DATA_CPL_ON_HIGH_QID0_S) +#define ERR_DATA_CPL_ON_HIGH_QID0_F ERR_DATA_CPL_ON_HIGH_QID0_V(1U) + +#define ERR_BAD_DB_PIDX3_S 15 +#define ERR_BAD_DB_PIDX3_V(x) ((x) << ERR_BAD_DB_PIDX3_S) +#define ERR_BAD_DB_PIDX3_F ERR_BAD_DB_PIDX3_V(1U) + +#define ERR_BAD_DB_PIDX2_S 14 +#define ERR_BAD_DB_PIDX2_V(x) ((x) << ERR_BAD_DB_PIDX2_S) +#define ERR_BAD_DB_PIDX2_F ERR_BAD_DB_PIDX2_V(1U) + +#define ERR_BAD_DB_PIDX1_S 13 +#define ERR_BAD_DB_PIDX1_V(x) ((x) << ERR_BAD_DB_PIDX1_S) +#define ERR_BAD_DB_PIDX1_F ERR_BAD_DB_PIDX1_V(1U) + +#define ERR_BAD_DB_PIDX0_S 12 +#define ERR_BAD_DB_PIDX0_V(x) ((x) << ERR_BAD_DB_PIDX0_S) +#define ERR_BAD_DB_PIDX0_F ERR_BAD_DB_PIDX0_V(1U) + +#define ERR_ING_CTXT_PRIO_S 10 +#define ERR_ING_CTXT_PRIO_V(x) ((x) << ERR_ING_CTXT_PRIO_S) +#define ERR_ING_CTXT_PRIO_F ERR_ING_CTXT_PRIO_V(1U) + +#define ERR_EGR_CTXT_PRIO_S 9 +#define ERR_EGR_CTXT_PRIO_V(x) ((x) << ERR_EGR_CTXT_PRIO_S) +#define ERR_EGR_CTXT_PRIO_F ERR_EGR_CTXT_PRIO_V(1U) + +#define DBFIFO_HP_INT_S 8 +#define DBFIFO_HP_INT_V(x) ((x) << DBFIFO_HP_INT_S) +#define DBFIFO_HP_INT_F DBFIFO_HP_INT_V(1U) + +#define DBFIFO_LP_INT_S 7 +#define DBFIFO_LP_INT_V(x) ((x) << DBFIFO_LP_INT_S) +#define DBFIFO_LP_INT_F DBFIFO_LP_INT_V(1U) + +#define INGRESS_SIZE_ERR_S 5 +#define INGRESS_SIZE_ERR_V(x) ((x) << INGRESS_SIZE_ERR_S) +#define INGRESS_SIZE_ERR_F INGRESS_SIZE_ERR_V(1U) + +#define EGRESS_SIZE_ERR_S 4 +#define EGRESS_SIZE_ERR_V(x) ((x) << EGRESS_SIZE_ERR_S) +#define EGRESS_SIZE_ERR_F EGRESS_SIZE_ERR_V(1U) + +#define SGE_INT_ENABLE3_A 0x1040 +#define SGE_FL_BUFFER_SIZE0_A 0x1044 +#define SGE_FL_BUFFER_SIZE1_A 0x1048 +#define SGE_FL_BUFFER_SIZE2_A 0x104c +#define SGE_FL_BUFFER_SIZE3_A 0x1050 +#define SGE_FL_BUFFER_SIZE4_A 0x1054 +#define SGE_FL_BUFFER_SIZE5_A 0x1058 +#define SGE_FL_BUFFER_SIZE6_A 0x105c +#define SGE_FL_BUFFER_SIZE7_A 0x1060 +#define SGE_FL_BUFFER_SIZE8_A 0x1064 + +#define SGE_INGRESS_RX_THRESHOLD_A 0x10a0 + +#define THRESHOLD_0_S 24 +#define THRESHOLD_0_M 0x3fU +#define THRESHOLD_0_V(x) ((x) << THRESHOLD_0_S) +#define THRESHOLD_0_G(x) (((x) >> THRESHOLD_0_S) & THRESHOLD_0_M) + +#define THRESHOLD_1_S 16 +#define THRESHOLD_1_M 0x3fU +#define THRESHOLD_1_V(x) ((x) << THRESHOLD_1_S) +#define THRESHOLD_1_G(x) (((x) >> THRESHOLD_1_S) & THRESHOLD_1_M) + +#define THRESHOLD_2_S 8 +#define THRESHOLD_2_M 0x3fU +#define THRESHOLD_2_V(x) ((x) << THRESHOLD_2_S) +#define THRESHOLD_2_G(x) (((x) >> THRESHOLD_2_S) & THRESHOLD_2_M) + +#define THRESHOLD_3_S 0 +#define THRESHOLD_3_M 0x3fU +#define THRESHOLD_3_V(x) ((x) << THRESHOLD_3_S) +#define THRESHOLD_3_G(x) (((x) >> THRESHOLD_3_S) & THRESHOLD_3_M) + +#define SGE_CONM_CTRL_A 0x1094 + +#define EGRTHRESHOLD_S 8 +#define EGRTHRESHOLD_M 0x3fU +#define EGRTHRESHOLD_V(x) ((x) << EGRTHRESHOLD_S) +#define EGRTHRESHOLD_G(x) (((x) >> EGRTHRESHOLD_S) & EGRTHRESHOLD_M) + +#define EGRTHRESHOLDPACKING_S 14 +#define EGRTHRESHOLDPACKING_M 0x3fU +#define EGRTHRESHOLDPACKING_V(x) ((x) << EGRTHRESHOLDPACKING_S) +#define EGRTHRESHOLDPACKING_G(x) \ + (((x) >> EGRTHRESHOLDPACKING_S) & EGRTHRESHOLDPACKING_M) + +#define SGE_TIMESTAMP_LO_A 0x1098 +#define SGE_TIMESTAMP_HI_A 0x109c + +#define TSOP_S 28 +#define TSOP_M 0x3U +#define TSOP_V(x) ((x) << TSOP_S) +#define TSOP_G(x) (((x) >> TSOP_S) & TSOP_M) + +#define TSVAL_S 0 +#define TSVAL_M 0xfffffffU +#define TSVAL_V(x) ((x) << TSVAL_S) +#define TSVAL_G(x) (((x) >> TSVAL_S) & TSVAL_M) + +#define SGE_DBFIFO_STATUS_A 0x10a4 + +#define HP_INT_THRESH_S 28 +#define HP_INT_THRESH_M 0xfU +#define HP_INT_THRESH_V(x) ((x) << HP_INT_THRESH_S) + +#define LP_INT_THRESH_S 12 +#define LP_INT_THRESH_M 0xfU +#define LP_INT_THRESH_V(x) ((x) << LP_INT_THRESH_S) + +#define SGE_DOORBELL_CONTROL_A 0x10a8 + +#define NOCOALESCE_S 26 +#define NOCOALESCE_V(x) ((x) << NOCOALESCE_S) +#define NOCOALESCE_F NOCOALESCE_V(1U) + +#define ENABLE_DROP_S 13 +#define ENABLE_DROP_V(x) ((x) << ENABLE_DROP_S) +#define ENABLE_DROP_F ENABLE_DROP_V(1U) + +#define SGE_TIMER_VALUE_0_AND_1_A 0x10b8 + +#define TIMERVALUE0_S 16 +#define TIMERVALUE0_M 0xffffU +#define TIMERVALUE0_V(x) ((x) << TIMERVALUE0_S) +#define TIMERVALUE0_G(x) (((x) >> TIMERVALUE0_S) & TIMERVALUE0_M) + +#define TIMERVALUE1_S 0 +#define TIMERVALUE1_M 0xffffU +#define TIMERVALUE1_V(x) ((x) << TIMERVALUE1_S) +#define TIMERVALUE1_G(x) (((x) >> TIMERVALUE1_S) & TIMERVALUE1_M) + +#define SGE_TIMER_VALUE_2_AND_3_A 0x10bc + +#define TIMERVALUE2_S 16 +#define TIMERVALUE2_M 0xffffU +#define TIMERVALUE2_V(x) ((x) << TIMERVALUE2_S) +#define TIMERVALUE2_G(x) (((x) >> TIMERVALUE2_S) & TIMERVALUE2_M) + +#define TIMERVALUE3_S 0 +#define TIMERVALUE3_M 0xffffU +#define TIMERVALUE3_V(x) ((x) << TIMERVALUE3_S) +#define TIMERVALUE3_G(x) (((x) >> TIMERVALUE3_S) & TIMERVALUE3_M) + +#define SGE_TIMER_VALUE_4_AND_5_A 0x10c0 + +#define TIMERVALUE4_S 16 +#define TIMERVALUE4_M 0xffffU +#define TIMERVALUE4_V(x) ((x) << TIMERVALUE4_S) +#define TIMERVALUE4_G(x) (((x) >> TIMERVALUE4_S) & TIMERVALUE4_M) + +#define TIMERVALUE5_S 0 +#define TIMERVALUE5_M 0xffffU +#define TIMERVALUE5_V(x) ((x) << TIMERVALUE5_S) +#define TIMERVALUE5_G(x) (((x) >> TIMERVALUE5_S) & TIMERVALUE5_M) + +#define SGE_DEBUG_INDEX_A 0x10cc +#define SGE_DEBUG_DATA_HIGH_A 0x10d0 +#define SGE_DEBUG_DATA_LOW_A 0x10d4 + +#define SGE_DEBUG_DATA_LOW_INDEX_2_A 0x12c8 +#define SGE_DEBUG_DATA_LOW_INDEX_3_A 0x12cc +#define SGE_DEBUG_DATA_HIGH_INDEX_10_A 0x12a8 + +#define SGE_INGRESS_QUEUES_PER_PAGE_PF_A 0x10f4 #define SGE_INGRESS_QUEUES_PER_PAGE_VF_A 0x10f8 -#define S_HP_INT_THRESH 28 -#define M_HP_INT_THRESH 0xfU -#define V_HP_INT_THRESH(x) ((x) << S_HP_INT_THRESH) -#define S_LP_INT_THRESH_T5 18 -#define V_LP_INT_THRESH_T5(x) ((x) << S_LP_INT_THRESH_T5) -#define M_LP_COUNT_T5 0x3ffffU -#define G_LP_COUNT_T5(x) (((x) >> S_LP_COUNT) & M_LP_COUNT_T5) -#define M_HP_COUNT 0x7ffU -#define S_HP_COUNT 16 -#define G_HP_COUNT(x) (((x) >> S_HP_COUNT) & M_HP_COUNT) -#define S_LP_INT_THRESH 12 -#define M_LP_INT_THRESH 0xfU -#define M_LP_INT_THRESH_T5 0xfffU -#define V_LP_INT_THRESH(x) ((x) << S_LP_INT_THRESH) -#define M_LP_COUNT 0x7ffU -#define S_LP_COUNT 0 -#define G_LP_COUNT(x) (((x) >> S_LP_COUNT) & M_LP_COUNT) -#define A_SGE_DBFIFO_STATUS 0x10a4 +#define HP_INT_THRESH_S 28 +#define HP_INT_THRESH_M 0xfU +#define HP_INT_THRESH_V(x) ((x) << HP_INT_THRESH_S) -#define SGE_STAT_TOTAL 0x10e4 -#define SGE_STAT_MATCH 0x10e8 +#define HP_COUNT_S 16 +#define HP_COUNT_M 0x7ffU +#define HP_COUNT_G(x) (((x) >> HP_COUNT_S) & HP_COUNT_M) -#define SGE_STAT_CFG 0x10ec -#define S_STATSOURCE_T5 9 -#define STATSOURCE_T5(x) ((x) << S_STATSOURCE_T5) +#define LP_INT_THRESH_S 12 +#define LP_INT_THRESH_M 0xfU +#define LP_INT_THRESH_V(x) ((x) << LP_INT_THRESH_S) -#define SGE_DBFIFO_STATUS2 0x1118 -#define M_HP_COUNT_T5 0x3ffU -#define G_HP_COUNT_T5(x) ((x) & M_HP_COUNT_T5) -#define S_HP_INT_THRESH_T5 10 -#define M_HP_INT_THRESH_T5 0xfU -#define V_HP_INT_THRESH_T5(x) ((x) << S_HP_INT_THRESH_T5) +#define LP_COUNT_S 0 +#define LP_COUNT_M 0x7ffU +#define LP_COUNT_G(x) (((x) >> LP_COUNT_S) & LP_COUNT_M) -#define S_ENABLE_DROP 13 -#define V_ENABLE_DROP(x) ((x) << S_ENABLE_DROP) -#define F_ENABLE_DROP V_ENABLE_DROP(1U) -#define S_DROPPED_DB 0 -#define V_DROPPED_DB(x) ((x) << S_DROPPED_DB) -#define F_DROPPED_DB V_DROPPED_DB(1U) -#define A_SGE_DOORBELL_CONTROL 0x10a8 +#define LP_INT_THRESH_T5_S 18 +#define LP_INT_THRESH_T5_M 0xfffU +#define LP_INT_THRESH_T5_V(x) ((x) << LP_INT_THRESH_T5_S) -#define A_SGE_CTXT_CMD 0x11fc -#define A_SGE_DBQ_CTXT_BADDR 0x1084 +#define LP_COUNT_T5_S 0 +#define LP_COUNT_T5_M 0x3ffffU +#define LP_COUNT_T5_G(x) (((x) >> LP_COUNT_T5_S) & LP_COUNT_T5_M) -#define PCIE_PF_CFG 0x40 -#define AIVEC(x) ((x) << 4) -#define AIVEC_MASK 0x3ffU +#define SGE_DOORBELL_CONTROL_A 0x10a8 -#define PCIE_PF_CLI 0x44 -#define PCIE_INT_CAUSE 0x3004 -#define UNXSPLCPLERR 0x20000000U -#define PCIEPINT 0x10000000U -#define PCIESINT 0x08000000U -#define RPLPERR 0x04000000U -#define RXWRPERR 0x02000000U -#define RXCPLPERR 0x01000000U -#define PIOTAGPERR 0x00800000U -#define MATAGPERR 0x00400000U -#define INTXCLRPERR 0x00200000U -#define FIDPERR 0x00100000U -#define CFGSNPPERR 0x00080000U -#define HRSPPERR 0x00040000U -#define HREQPERR 0x00020000U -#define HCNTPERR 0x00010000U -#define DRSPPERR 0x00008000U -#define DREQPERR 0x00004000U -#define DCNTPERR 0x00002000U -#define CRSPPERR 0x00001000U -#define CREQPERR 0x00000800U -#define CCNTPERR 0x00000400U -#define TARTAGPERR 0x00000200U -#define PIOREQPERR 0x00000100U -#define PIOCPLPERR 0x00000080U -#define MSIXDIPERR 0x00000040U -#define MSIXDATAPERR 0x00000020U -#define MSIXADDRHPERR 0x00000010U -#define MSIXADDRLPERR 0x00000008U -#define MSIDATAPERR 0x00000004U -#define MSIADDRHPERR 0x00000002U -#define MSIADDRLPERR 0x00000001U +#define SGE_STAT_TOTAL_A 0x10e4 +#define SGE_STAT_MATCH_A 0x10e8 +#define SGE_STAT_CFG_A 0x10ec -#define READRSPERR 0x20000000U -#define TRGT1GRPPERR 0x10000000U -#define IPSOTPERR 0x08000000U -#define IPRXDATAGRPPERR 0x02000000U -#define IPRXHDRGRPPERR 0x01000000U -#define MAGRPPERR 0x00400000U -#define VFIDPERR 0x00200000U -#define HREQWRPERR 0x00010000U -#define DREQWRPERR 0x00002000U -#define MSTTAGQPERR 0x00000400U -#define PIOREQGRPPERR 0x00000100U -#define PIOCPLGRPPERR 0x00000080U -#define MSIXSTIPERR 0x00000004U -#define MSTTIMEOUTPERR 0x00000002U -#define MSTGRPPERR 0x00000001U +#define STATSOURCE_T5_S 9 +#define STATSOURCE_T5_V(x) ((x) << STATSOURCE_T5_S) -#define PCIE_NONFAT_ERR 0x3010 -#define PCIE_CFG_SPACE_REQ 0x3060 -#define PCIE_CFG_SPACE_DATA 0x3064 -#define PCIE_MEM_ACCESS_BASE_WIN 0x3068 -#define S_PCIEOFST 10 -#define M_PCIEOFST 0x3fffffU -#define GET_PCIEOFST(x) (((x) >> S_PCIEOFST) & M_PCIEOFST) -#define PCIEOFST_MASK 0xfffffc00U -#define BIR_MASK 0x00000300U -#define BIR_SHIFT 8 -#define BIR(x) ((x) << BIR_SHIFT) -#define WINDOW_MASK 0x000000ffU -#define WINDOW_SHIFT 0 -#define WINDOW(x) ((x) << WINDOW_SHIFT) -#define GET_WINDOW(x) (((x) >> WINDOW_SHIFT) & WINDOW_MASK) -#define PCIE_MEM_ACCESS_OFFSET 0x306c -#define ENABLE (1U << 30) -#define FUNCTION(x) ((x) << 12) -#define F_LOCALCFG (1U << 28) +#define SGE_DBFIFO_STATUS2_A 0x1118 -#define S_PFNUM 0 -#define V_PFNUM(x) ((x) << S_PFNUM) +#define HP_INT_THRESH_T5_S 10 +#define HP_INT_THRESH_T5_M 0xfU +#define HP_INT_THRESH_T5_V(x) ((x) << HP_INT_THRESH_T5_S) -#define PCIE_FW 0x30b8 -#define PCIE_FW_ERR 0x80000000U -#define PCIE_FW_INIT 0x40000000U -#define PCIE_FW_HALT 0x20000000U -#define PCIE_FW_MASTER_VLD 0x00008000U -#define PCIE_FW_MASTER(x) ((x) << 12) -#define PCIE_FW_MASTER_MASK 0x7 -#define PCIE_FW_MASTER_GET(x) (((x) >> 12) & PCIE_FW_MASTER_MASK) +#define HP_COUNT_T5_S 0 +#define HP_COUNT_T5_M 0x3ffU +#define HP_COUNT_T5_G(x) (((x) >> HP_COUNT_T5_S) & HP_COUNT_T5_M) -#define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS 0x5908 -#define RNPP 0x80000000U -#define RPCP 0x20000000U -#define RCIP 0x08000000U -#define RCCP 0x04000000U -#define RFTP 0x00800000U -#define PTRP 0x00100000U +#define ENABLE_DROP_S 13 +#define ENABLE_DROP_V(x) ((x) << ENABLE_DROP_S) +#define ENABLE_DROP_F ENABLE_DROP_V(1U) -#define PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS 0x59a4 -#define TPCP 0x40000000U -#define TNPP 0x20000000U -#define TFTP 0x10000000U -#define TCAP 0x08000000U -#define TCIP 0x04000000U -#define RCAP 0x02000000U -#define PLUP 0x00800000U -#define PLDN 0x00400000U -#define OTDD 0x00200000U -#define GTRP 0x00100000U -#define RDPE 0x00040000U -#define TDCE 0x00020000U -#define TDUE 0x00010000U +#define DROPPED_DB_S 0 +#define DROPPED_DB_V(x) ((x) << DROPPED_DB_S) +#define DROPPED_DB_F DROPPED_DB_V(1U) -#define MC_INT_CAUSE 0x7518 -#define MC_P_INT_CAUSE 0x41318 -#define ECC_UE_INT_CAUSE 0x00000004U -#define ECC_CE_INT_CAUSE 0x00000002U -#define PERR_INT_CAUSE 0x00000001U +#define SGE_CTXT_CMD_A 0x11fc +#define SGE_DBQ_CTXT_BADDR_A 0x1084 -#define MC_ECC_STATUS 0x751c -#define MC_P_ECC_STATUS 0x4131c -#define ECC_CECNT_MASK 0xffff0000U -#define ECC_CECNT_SHIFT 16 -#define ECC_CECNT(x) ((x) << ECC_CECNT_SHIFT) -#define ECC_CECNT_GET(x) (((x) & ECC_CECNT_MASK) >> ECC_CECNT_SHIFT) -#define ECC_UECNT_MASK 0x0000ffffU -#define ECC_UECNT_SHIFT 0 -#define ECC_UECNT(x) ((x) << ECC_UECNT_SHIFT) -#define ECC_UECNT_GET(x) (((x) & ECC_UECNT_MASK) >> ECC_UECNT_SHIFT) +/* registers for module PCIE */ +#define PCIE_PF_CFG_A 0x40 -#define MC_BIST_CMD 0x7600 -#define START_BIST 0x80000000U -#define BIST_CMD_GAP_MASK 0x0000ff00U -#define BIST_CMD_GAP_SHIFT 8 -#define BIST_CMD_GAP(x) ((x) << BIST_CMD_GAP_SHIFT) -#define BIST_OPCODE_MASK 0x00000003U -#define BIST_OPCODE_SHIFT 0 -#define BIST_OPCODE(x) ((x) << BIST_OPCODE_SHIFT) +#define AIVEC_S 4 +#define AIVEC_M 0x3ffU +#define AIVEC_V(x) ((x) << AIVEC_S) -#define MC_BIST_CMD_ADDR 0x7604 -#define MC_BIST_CMD_LEN 0x7608 -#define MC_BIST_DATA_PATTERN 0x760c -#define BIST_DATA_TYPE_MASK 0x0000000fU -#define BIST_DATA_TYPE_SHIFT 0 -#define BIST_DATA_TYPE(x) ((x) << BIST_DATA_TYPE_SHIFT) +#define PCIE_PF_CLI_A 0x44 +#define PCIE_INT_CAUSE_A 0x3004 -#define MC_BIST_STATUS_RDATA 0x7688 +#define UNXSPLCPLERR_S 29 +#define UNXSPLCPLERR_V(x) ((x) << UNXSPLCPLERR_S) +#define UNXSPLCPLERR_F UNXSPLCPLERR_V(1U) +#define PCIEPINT_S 28 +#define PCIEPINT_V(x) ((x) << PCIEPINT_S) +#define PCIEPINT_F PCIEPINT_V(1U) + +#define PCIESINT_S 27 +#define PCIESINT_V(x) ((x) << PCIESINT_S) +#define PCIESINT_F PCIESINT_V(1U) + +#define RPLPERR_S 26 +#define RPLPERR_V(x) ((x) << RPLPERR_S) +#define RPLPERR_F RPLPERR_V(1U) + +#define RXWRPERR_S 25 +#define RXWRPERR_V(x) ((x) << RXWRPERR_S) +#define RXWRPERR_F RXWRPERR_V(1U) + +#define RXCPLPERR_S 24 +#define RXCPLPERR_V(x) ((x) << RXCPLPERR_S) +#define RXCPLPERR_F RXCPLPERR_V(1U) + +#define PIOTAGPERR_S 23 +#define PIOTAGPERR_V(x) ((x) << PIOTAGPERR_S) +#define PIOTAGPERR_F PIOTAGPERR_V(1U) + +#define MATAGPERR_S 22 +#define MATAGPERR_V(x) ((x) << MATAGPERR_S) +#define MATAGPERR_F MATAGPERR_V(1U) + +#define INTXCLRPERR_S 21 +#define INTXCLRPERR_V(x) ((x) << INTXCLRPERR_S) +#define INTXCLRPERR_F INTXCLRPERR_V(1U) + +#define FIDPERR_S 20 +#define FIDPERR_V(x) ((x) << FIDPERR_S) +#define FIDPERR_F FIDPERR_V(1U) + +#define CFGSNPPERR_S 19 +#define CFGSNPPERR_V(x) ((x) << CFGSNPPERR_S) +#define CFGSNPPERR_F CFGSNPPERR_V(1U) + +#define HRSPPERR_S 18 +#define HRSPPERR_V(x) ((x) << HRSPPERR_S) +#define HRSPPERR_F HRSPPERR_V(1U) + +#define HREQPERR_S 17 +#define HREQPERR_V(x) ((x) << HREQPERR_S) +#define HREQPERR_F HREQPERR_V(1U) + +#define HCNTPERR_S 16 +#define HCNTPERR_V(x) ((x) << HCNTPERR_S) +#define HCNTPERR_F HCNTPERR_V(1U) + +#define DRSPPERR_S 15 +#define DRSPPERR_V(x) ((x) << DRSPPERR_S) +#define DRSPPERR_F DRSPPERR_V(1U) + +#define DREQPERR_S 14 +#define DREQPERR_V(x) ((x) << DREQPERR_S) +#define DREQPERR_F DREQPERR_V(1U) + +#define DCNTPERR_S 13 +#define DCNTPERR_V(x) ((x) << DCNTPERR_S) +#define DCNTPERR_F DCNTPERR_V(1U) + +#define CRSPPERR_S 12 +#define CRSPPERR_V(x) ((x) << CRSPPERR_S) +#define CRSPPERR_F CRSPPERR_V(1U) + +#define CREQPERR_S 11 +#define CREQPERR_V(x) ((x) << CREQPERR_S) +#define CREQPERR_F CREQPERR_V(1U) + +#define CCNTPERR_S 10 +#define CCNTPERR_V(x) ((x) << CCNTPERR_S) +#define CCNTPERR_F CCNTPERR_V(1U) + +#define TARTAGPERR_S 9 +#define TARTAGPERR_V(x) ((x) << TARTAGPERR_S) +#define TARTAGPERR_F TARTAGPERR_V(1U) + +#define PIOREQPERR_S 8 +#define PIOREQPERR_V(x) ((x) << PIOREQPERR_S) +#define PIOREQPERR_F PIOREQPERR_V(1U) + +#define PIOCPLPERR_S 7 +#define PIOCPLPERR_V(x) ((x) << PIOCPLPERR_S) +#define PIOCPLPERR_F PIOCPLPERR_V(1U) + +#define MSIXDIPERR_S 6 +#define MSIXDIPERR_V(x) ((x) << MSIXDIPERR_S) +#define MSIXDIPERR_F MSIXDIPERR_V(1U) + +#define MSIXDATAPERR_S 5 +#define MSIXDATAPERR_V(x) ((x) << MSIXDATAPERR_S) +#define MSIXDATAPERR_F MSIXDATAPERR_V(1U) + +#define MSIXADDRHPERR_S 4 +#define MSIXADDRHPERR_V(x) ((x) << MSIXADDRHPERR_S) +#define MSIXADDRHPERR_F MSIXADDRHPERR_V(1U) + +#define MSIXADDRLPERR_S 3 +#define MSIXADDRLPERR_V(x) ((x) << MSIXADDRLPERR_S) +#define MSIXADDRLPERR_F MSIXADDRLPERR_V(1U) + +#define MSIDATAPERR_S 2 +#define MSIDATAPERR_V(x) ((x) << MSIDATAPERR_S) +#define MSIDATAPERR_F MSIDATAPERR_V(1U) + +#define MSIADDRHPERR_S 1 +#define MSIADDRHPERR_V(x) ((x) << MSIADDRHPERR_S) +#define MSIADDRHPERR_F MSIADDRHPERR_V(1U) + +#define MSIADDRLPERR_S 0 +#define MSIADDRLPERR_V(x) ((x) << MSIADDRLPERR_S) +#define MSIADDRLPERR_F MSIADDRLPERR_V(1U) + +#define READRSPERR_S 29 +#define READRSPERR_V(x) ((x) << READRSPERR_S) +#define READRSPERR_F READRSPERR_V(1U) + +#define TRGT1GRPPERR_S 28 +#define TRGT1GRPPERR_V(x) ((x) << TRGT1GRPPERR_S) +#define TRGT1GRPPERR_F TRGT1GRPPERR_V(1U) + +#define IPSOTPERR_S 27 +#define IPSOTPERR_V(x) ((x) << IPSOTPERR_S) +#define IPSOTPERR_F IPSOTPERR_V(1U) + +#define IPRETRYPERR_S 26 +#define IPRETRYPERR_V(x) ((x) << IPRETRYPERR_S) +#define IPRETRYPERR_F IPRETRYPERR_V(1U) + +#define IPRXDATAGRPPERR_S 25 +#define IPRXDATAGRPPERR_V(x) ((x) << IPRXDATAGRPPERR_S) +#define IPRXDATAGRPPERR_F IPRXDATAGRPPERR_V(1U) + +#define IPRXHDRGRPPERR_S 24 +#define IPRXHDRGRPPERR_V(x) ((x) << IPRXHDRGRPPERR_S) +#define IPRXHDRGRPPERR_F IPRXHDRGRPPERR_V(1U) + +#define MAGRPPERR_S 22 +#define MAGRPPERR_V(x) ((x) << MAGRPPERR_S) +#define MAGRPPERR_F MAGRPPERR_V(1U) + +#define VFIDPERR_S 21 +#define VFIDPERR_V(x) ((x) << VFIDPERR_S) +#define VFIDPERR_F VFIDPERR_V(1U) + +#define HREQWRPERR_S 16 +#define HREQWRPERR_V(x) ((x) << HREQWRPERR_S) +#define HREQWRPERR_F HREQWRPERR_V(1U) + +#define DREQWRPERR_S 13 +#define DREQWRPERR_V(x) ((x) << DREQWRPERR_S) +#define DREQWRPERR_F DREQWRPERR_V(1U) + +#define CREQRDPERR_S 11 +#define CREQRDPERR_V(x) ((x) << CREQRDPERR_S) +#define CREQRDPERR_F CREQRDPERR_V(1U) + +#define MSTTAGQPERR_S 10 +#define MSTTAGQPERR_V(x) ((x) << MSTTAGQPERR_S) +#define MSTTAGQPERR_F MSTTAGQPERR_V(1U) + +#define PIOREQGRPPERR_S 8 +#define PIOREQGRPPERR_V(x) ((x) << PIOREQGRPPERR_S) +#define PIOREQGRPPERR_F PIOREQGRPPERR_V(1U) + +#define PIOCPLGRPPERR_S 7 +#define PIOCPLGRPPERR_V(x) ((x) << PIOCPLGRPPERR_S) +#define PIOCPLGRPPERR_F PIOCPLGRPPERR_V(1U) + +#define MSIXSTIPERR_S 2 +#define MSIXSTIPERR_V(x) ((x) << MSIXSTIPERR_S) +#define MSIXSTIPERR_F MSIXSTIPERR_V(1U) + +#define MSTTIMEOUTPERR_S 1 +#define MSTTIMEOUTPERR_V(x) ((x) << MSTTIMEOUTPERR_S) +#define MSTTIMEOUTPERR_F MSTTIMEOUTPERR_V(1U) + +#define MSTGRPPERR_S 0 +#define MSTGRPPERR_V(x) ((x) << MSTGRPPERR_S) +#define MSTGRPPERR_F MSTGRPPERR_V(1U) + +#define PCIE_NONFAT_ERR_A 0x3010 +#define PCIE_CFG_SPACE_REQ_A 0x3060 +#define PCIE_CFG_SPACE_DATA_A 0x3064 +#define PCIE_MEM_ACCESS_BASE_WIN_A 0x3068 + +#define PCIEOFST_S 10 +#define PCIEOFST_M 0x3fffffU +#define PCIEOFST_G(x) (((x) >> PCIEOFST_S) & PCIEOFST_M) + +#define BIR_S 8 +#define BIR_M 0x3U +#define BIR_V(x) ((x) << BIR_S) +#define BIR_G(x) (((x) >> BIR_S) & BIR_M) + +#define WINDOW_S 0 +#define WINDOW_M 0xffU +#define WINDOW_V(x) ((x) << WINDOW_S) +#define WINDOW_G(x) (((x) >> WINDOW_S) & WINDOW_M) + +#define PCIE_MEM_ACCESS_OFFSET_A 0x306c + +#define ENABLE_S 30 +#define ENABLE_V(x) ((x) << ENABLE_S) +#define ENABLE_F ENABLE_V(1U) + +#define LOCALCFG_S 28 +#define LOCALCFG_V(x) ((x) << LOCALCFG_S) +#define LOCALCFG_F LOCALCFG_V(1U) + +#define FUNCTION_S 12 +#define FUNCTION_V(x) ((x) << FUNCTION_S) + +#define REGISTER_S 0 +#define REGISTER_V(x) ((x) << REGISTER_S) + +#define PFNUM_S 0 +#define PFNUM_V(x) ((x) << PFNUM_S) + +#define PCIE_FW_A 0x30b8 + +#define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS_A 0x5908 + +#define RNPP_S 31 +#define RNPP_V(x) ((x) << RNPP_S) +#define RNPP_F RNPP_V(1U) + +#define RPCP_S 29 +#define RPCP_V(x) ((x) << RPCP_S) +#define RPCP_F RPCP_V(1U) + +#define RCIP_S 27 +#define RCIP_V(x) ((x) << RCIP_S) +#define RCIP_F RCIP_V(1U) + +#define RCCP_S 26 +#define RCCP_V(x) ((x) << RCCP_S) +#define RCCP_F RCCP_V(1U) + +#define RFTP_S 23 +#define RFTP_V(x) ((x) << RFTP_S) +#define RFTP_F RFTP_V(1U) + +#define PTRP_S 20 +#define PTRP_V(x) ((x) << PTRP_S) +#define PTRP_F PTRP_V(1U) + +#define PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS_A 0x59a4 + +#define TPCP_S 30 +#define TPCP_V(x) ((x) << TPCP_S) +#define TPCP_F TPCP_V(1U) + +#define TNPP_S 29 +#define TNPP_V(x) ((x) << TNPP_S) +#define TNPP_F TNPP_V(1U) + +#define TFTP_S 28 +#define TFTP_V(x) ((x) << TFTP_S) +#define TFTP_F TFTP_V(1U) + +#define TCAP_S 27 +#define TCAP_V(x) ((x) << TCAP_S) +#define TCAP_F TCAP_V(1U) + +#define TCIP_S 26 +#define TCIP_V(x) ((x) << TCIP_S) +#define TCIP_F TCIP_V(1U) + +#define RCAP_S 25 +#define RCAP_V(x) ((x) << RCAP_S) +#define RCAP_F RCAP_V(1U) + +#define PLUP_S 23 +#define PLUP_V(x) ((x) << PLUP_S) +#define PLUP_F PLUP_V(1U) + +#define PLDN_S 22 +#define PLDN_V(x) ((x) << PLDN_S) +#define PLDN_F PLDN_V(1U) + +#define OTDD_S 21 +#define OTDD_V(x) ((x) << OTDD_S) +#define OTDD_F OTDD_V(1U) + +#define GTRP_S 20 +#define GTRP_V(x) ((x) << GTRP_S) +#define GTRP_F GTRP_V(1U) + +#define RDPE_S 18 +#define RDPE_V(x) ((x) << RDPE_S) +#define RDPE_F RDPE_V(1U) + +#define TDCE_S 17 +#define TDCE_V(x) ((x) << TDCE_S) +#define TDCE_F TDCE_V(1U) + +#define TDUE_S 16 +#define TDUE_V(x) ((x) << TDUE_S) +#define TDUE_F TDUE_V(1U) + +/* registers for module MC */ +#define MC_INT_CAUSE_A 0x7518 +#define MC_P_INT_CAUSE_A 0x41318 + +#define ECC_UE_INT_CAUSE_S 2 +#define ECC_UE_INT_CAUSE_V(x) ((x) << ECC_UE_INT_CAUSE_S) +#define ECC_UE_INT_CAUSE_F ECC_UE_INT_CAUSE_V(1U) + +#define ECC_CE_INT_CAUSE_S 1 +#define ECC_CE_INT_CAUSE_V(x) ((x) << ECC_CE_INT_CAUSE_S) +#define ECC_CE_INT_CAUSE_F ECC_CE_INT_CAUSE_V(1U) + +#define PERR_INT_CAUSE_S 0 +#define PERR_INT_CAUSE_V(x) ((x) << PERR_INT_CAUSE_S) +#define PERR_INT_CAUSE_F PERR_INT_CAUSE_V(1U) + +#define MC_ECC_STATUS_A 0x751c +#define MC_P_ECC_STATUS_A 0x4131c + +#define ECC_CECNT_S 16 +#define ECC_CECNT_M 0xffffU +#define ECC_CECNT_V(x) ((x) << ECC_CECNT_S) +#define ECC_CECNT_G(x) (((x) >> ECC_CECNT_S) & ECC_CECNT_M) + +#define ECC_UECNT_S 0 +#define ECC_UECNT_M 0xffffU +#define ECC_UECNT_V(x) ((x) << ECC_UECNT_S) +#define ECC_UECNT_G(x) (((x) >> ECC_UECNT_S) & ECC_UECNT_M) + +#define MC_BIST_CMD_A 0x7600 + +#define START_BIST_S 31 +#define START_BIST_V(x) ((x) << START_BIST_S) +#define START_BIST_F START_BIST_V(1U) + +#define BIST_CMD_GAP_S 8 +#define BIST_CMD_GAP_V(x) ((x) << BIST_CMD_GAP_S) + +#define BIST_OPCODE_S 0 +#define BIST_OPCODE_V(x) ((x) << BIST_OPCODE_S) + +#define MC_BIST_CMD_ADDR_A 0x7604 +#define MC_BIST_CMD_LEN_A 0x7608 +#define MC_BIST_DATA_PATTERN_A 0x760c + +#define MC_BIST_STATUS_RDATA_A 0x7688 + +/* registers for module MA */ #define MA_EDRAM0_BAR_A 0x77c0 #define EDRAM0_SIZE_S 0 @@ -574,263 +893,608 @@ #define EXT_MEM0_ENABLE_V(x) ((x) << EXT_MEM0_ENABLE_S) #define EXT_MEM0_ENABLE_F EXT_MEM0_ENABLE_V(1U) -#define MA_INT_CAUSE 0x77e0 -#define MEM_PERR_INT_CAUSE 0x00000002U -#define MEM_WRAP_INT_CAUSE 0x00000001U +#define MA_INT_CAUSE_A 0x77e0 -#define MA_INT_WRAP_STATUS 0x77e4 -#define MEM_WRAP_ADDRESS_MASK 0xfffffff0U -#define MEM_WRAP_ADDRESS_SHIFT 4 -#define MEM_WRAP_ADDRESS_GET(x) (((x) & MEM_WRAP_ADDRESS_MASK) >> MEM_WRAP_ADDRESS_SHIFT) -#define MEM_WRAP_CLIENT_NUM_MASK 0x0000000fU -#define MEM_WRAP_CLIENT_NUM_SHIFT 0 -#define MEM_WRAP_CLIENT_NUM_GET(x) (((x) & MEM_WRAP_CLIENT_NUM_MASK) >> MEM_WRAP_CLIENT_NUM_SHIFT) -#define MA_PCIE_FW 0x30b8 -#define MA_PARITY_ERROR_STATUS 0x77f4 -#define MA_PARITY_ERROR_STATUS2 0x7804 +#define MEM_PERR_INT_CAUSE_S 1 +#define MEM_PERR_INT_CAUSE_V(x) ((x) << MEM_PERR_INT_CAUSE_S) +#define MEM_PERR_INT_CAUSE_F MEM_PERR_INT_CAUSE_V(1U) -#define EDC_0_BASE_ADDR 0x7900 +#define MEM_WRAP_INT_CAUSE_S 0 +#define MEM_WRAP_INT_CAUSE_V(x) ((x) << MEM_WRAP_INT_CAUSE_S) +#define MEM_WRAP_INT_CAUSE_F MEM_WRAP_INT_CAUSE_V(1U) -#define EDC_BIST_CMD 0x7904 -#define EDC_BIST_CMD_ADDR 0x7908 -#define EDC_BIST_CMD_LEN 0x790c -#define EDC_BIST_DATA_PATTERN 0x7910 -#define EDC_BIST_STATUS_RDATA 0x7928 -#define EDC_INT_CAUSE 0x7978 -#define ECC_UE_PAR 0x00000020U -#define ECC_CE_PAR 0x00000010U -#define PERR_PAR_CAUSE 0x00000008U +#define MA_INT_WRAP_STATUS_A 0x77e4 -#define EDC_ECC_STATUS 0x797c +#define MEM_WRAP_ADDRESS_S 4 +#define MEM_WRAP_ADDRESS_M 0xfffffffU +#define MEM_WRAP_ADDRESS_G(x) (((x) >> MEM_WRAP_ADDRESS_S) & MEM_WRAP_ADDRESS_M) -#define EDC_1_BASE_ADDR 0x7980 +#define MEM_WRAP_CLIENT_NUM_S 0 +#define MEM_WRAP_CLIENT_NUM_M 0xfU +#define MEM_WRAP_CLIENT_NUM_G(x) \ + (((x) >> MEM_WRAP_CLIENT_NUM_S) & MEM_WRAP_CLIENT_NUM_M) -#define CIM_BOOT_CFG 0x7b00 -#define BOOTADDR_MASK 0xffffff00U -#define UPCRST 0x1U +#define MA_PARITY_ERROR_STATUS_A 0x77f4 +#define MA_PARITY_ERROR_STATUS1_A 0x77f4 +#define MA_PARITY_ERROR_STATUS2_A 0x7804 -#define CIM_PF_MAILBOX_DATA 0x240 -#define CIM_PF_MAILBOX_CTRL 0x280 -#define MBMSGVALID 0x00000008U -#define MBINTREQ 0x00000004U -#define MBOWNER_MASK 0x00000003U -#define MBOWNER_SHIFT 0 -#define MBOWNER(x) ((x) << MBOWNER_SHIFT) -#define MBOWNER_GET(x) (((x) & MBOWNER_MASK) >> MBOWNER_SHIFT) +/* registers for module EDC_0 */ +#define EDC_0_BASE_ADDR 0x7900 -#define CIM_PF_HOST_INT_ENABLE 0x288 -#define MBMSGRDYINTEN(x) ((x) << 19) +#define EDC_BIST_CMD_A 0x7904 +#define EDC_BIST_CMD_ADDR_A 0x7908 +#define EDC_BIST_CMD_LEN_A 0x790c +#define EDC_BIST_DATA_PATTERN_A 0x7910 +#define EDC_BIST_STATUS_RDATA_A 0x7928 +#define EDC_INT_CAUSE_A 0x7978 -#define CIM_PF_HOST_INT_CAUSE 0x28c -#define MBMSGRDYINT 0x00080000U +#define ECC_UE_PAR_S 5 +#define ECC_UE_PAR_V(x) ((x) << ECC_UE_PAR_S) +#define ECC_UE_PAR_F ECC_UE_PAR_V(1U) -#define CIM_HOST_INT_CAUSE 0x7b2c -#define TIEQOUTPARERRINT 0x00100000U -#define TIEQINPARERRINT 0x00080000U -#define MBHOSTPARERR 0x00040000U -#define MBUPPARERR 0x00020000U -#define IBQPARERR 0x0001f800U -#define IBQTP0PARERR 0x00010000U -#define IBQTP1PARERR 0x00008000U -#define IBQULPPARERR 0x00004000U -#define IBQSGELOPARERR 0x00002000U -#define IBQSGEHIPARERR 0x00001000U -#define IBQNCSIPARERR 0x00000800U -#define OBQPARERR 0x000007e0U -#define OBQULP0PARERR 0x00000400U -#define OBQULP1PARERR 0x00000200U -#define OBQULP2PARERR 0x00000100U -#define OBQULP3PARERR 0x00000080U -#define OBQSGEPARERR 0x00000040U -#define OBQNCSIPARERR 0x00000020U -#define PREFDROPINT 0x00000002U -#define UPACCNONZERO 0x00000001U +#define ECC_CE_PAR_S 4 +#define ECC_CE_PAR_V(x) ((x) << ECC_CE_PAR_S) +#define ECC_CE_PAR_F ECC_CE_PAR_V(1U) -#define CIM_HOST_UPACC_INT_CAUSE 0x7b34 -#define EEPROMWRINT 0x40000000U -#define TIMEOUTMAINT 0x20000000U -#define TIMEOUTINT 0x10000000U -#define RSPOVRLOOKUPINT 0x08000000U -#define REQOVRLOOKUPINT 0x04000000U -#define BLKWRPLINT 0x02000000U -#define BLKRDPLINT 0x01000000U -#define SGLWRPLINT 0x00800000U -#define SGLRDPLINT 0x00400000U -#define BLKWRCTLINT 0x00200000U -#define BLKRDCTLINT 0x00100000U -#define SGLWRCTLINT 0x00080000U -#define SGLRDCTLINT 0x00040000U -#define BLKWREEPROMINT 0x00020000U -#define BLKRDEEPROMINT 0x00010000U -#define SGLWREEPROMINT 0x00008000U -#define SGLRDEEPROMINT 0x00004000U -#define BLKWRFLASHINT 0x00002000U -#define BLKRDFLASHINT 0x00001000U -#define SGLWRFLASHINT 0x00000800U -#define SGLRDFLASHINT 0x00000400U -#define BLKWRBOOTINT 0x00000200U -#define BLKRDBOOTINT 0x00000100U -#define SGLWRBOOTINT 0x00000080U -#define SGLRDBOOTINT 0x00000040U -#define ILLWRBEINT 0x00000020U -#define ILLRDBEINT 0x00000010U -#define ILLRDINT 0x00000008U -#define ILLWRINT 0x00000004U -#define ILLTRANSINT 0x00000002U -#define RSVDSPACEINT 0x00000001U +#define PERR_PAR_CAUSE_S 3 +#define PERR_PAR_CAUSE_V(x) ((x) << PERR_PAR_CAUSE_S) +#define PERR_PAR_CAUSE_F PERR_PAR_CAUSE_V(1U) -#define TP_OUT_CONFIG 0x7d04 -#define VLANEXTENABLE_MASK 0x0000f000U -#define VLANEXTENABLE_SHIFT 12 +#define EDC_ECC_STATUS_A 0x797c -#define TP_GLOBAL_CONFIG 0x7d08 -#define FIVETUPLELOOKUP_SHIFT 17 -#define FIVETUPLELOOKUP_MASK 0x00060000U -#define FIVETUPLELOOKUP(x) ((x) << FIVETUPLELOOKUP_SHIFT) -#define FIVETUPLELOOKUP_GET(x) (((x) & FIVETUPLELOOKUP_MASK) >> \ - FIVETUPLELOOKUP_SHIFT) +/* registers for module EDC_1 */ +#define EDC_1_BASE_ADDR 0x7980 -#define TP_PARA_REG2 0x7d68 -#define MAXRXDATA_MASK 0xffff0000U -#define MAXRXDATA_SHIFT 16 -#define MAXRXDATA_GET(x) (((x) & MAXRXDATA_MASK) >> MAXRXDATA_SHIFT) +/* registers for module CIM */ +#define CIM_BOOT_CFG_A 0x7b00 +#define CIM_PF_MAILBOX_CTRL_SHADOW_COPY_A 0x290 -#define TP_TIMER_RESOLUTION 0x7d90 -#define TIMERRESOLUTION_MASK 0x00ff0000U -#define TIMERRESOLUTION_SHIFT 16 -#define TIMERRESOLUTION_GET(x) (((x) & TIMERRESOLUTION_MASK) >> TIMERRESOLUTION_SHIFT) -#define DELAYEDACKRESOLUTION_MASK 0x000000ffU -#define DELAYEDACKRESOLUTION_SHIFT 0 -#define DELAYEDACKRESOLUTION_GET(x) \ - (((x) & DELAYEDACKRESOLUTION_MASK) >> DELAYEDACKRESOLUTION_SHIFT) +#define BOOTADDR_M 0xffffff00U -#define TP_SHIFT_CNT 0x7dc0 -#define SYNSHIFTMAX_SHIFT 24 -#define SYNSHIFTMAX_MASK 0xff000000U -#define SYNSHIFTMAX(x) ((x) << SYNSHIFTMAX_SHIFT) -#define SYNSHIFTMAX_GET(x) (((x) & SYNSHIFTMAX_MASK) >> \ - SYNSHIFTMAX_SHIFT) -#define RXTSHIFTMAXR1_SHIFT 20 -#define RXTSHIFTMAXR1_MASK 0x00f00000U -#define RXTSHIFTMAXR1(x) ((x) << RXTSHIFTMAXR1_SHIFT) -#define RXTSHIFTMAXR1_GET(x) (((x) & RXTSHIFTMAXR1_MASK) >> \ - RXTSHIFTMAXR1_SHIFT) -#define RXTSHIFTMAXR2_SHIFT 16 -#define RXTSHIFTMAXR2_MASK 0x000f0000U -#define RXTSHIFTMAXR2(x) ((x) << RXTSHIFTMAXR2_SHIFT) -#define RXTSHIFTMAXR2_GET(x) (((x) & RXTSHIFTMAXR2_MASK) >> \ - RXTSHIFTMAXR2_SHIFT) -#define PERSHIFTBACKOFFMAX_SHIFT 12 -#define PERSHIFTBACKOFFMAX_MASK 0x0000f000U -#define PERSHIFTBACKOFFMAX(x) ((x) << PERSHIFTBACKOFFMAX_SHIFT) -#define PERSHIFTBACKOFFMAX_GET(x) (((x) & PERSHIFTBACKOFFMAX_MASK) >> \ - PERSHIFTBACKOFFMAX_SHIFT) -#define PERSHIFTMAX_SHIFT 8 -#define PERSHIFTMAX_MASK 0x00000f00U -#define PERSHIFTMAX(x) ((x) << PERSHIFTMAX_SHIFT) -#define PERSHIFTMAX_GET(x) (((x) & PERSHIFTMAX_MASK) >> \ - PERSHIFTMAX_SHIFT) -#define KEEPALIVEMAXR1_SHIFT 4 -#define KEEPALIVEMAXR1_MASK 0x000000f0U -#define KEEPALIVEMAXR1(x) ((x) << KEEPALIVEMAXR1_SHIFT) -#define KEEPALIVEMAXR1_GET(x) (((x) & KEEPALIVEMAXR1_MASK) >> \ - KEEPALIVEMAXR1_SHIFT) -#define KEEPALIVEMAXR2_SHIFT 0 -#define KEEPALIVEMAXR2_MASK 0x0000000fU -#define KEEPALIVEMAXR2(x) ((x) << KEEPALIVEMAXR2_SHIFT) -#define KEEPALIVEMAXR2_GET(x) (((x) & KEEPALIVEMAXR2_MASK) >> \ - KEEPALIVEMAXR2_SHIFT) +#define UPCRST_S 0 +#define UPCRST_V(x) ((x) << UPCRST_S) +#define UPCRST_F UPCRST_V(1U) -#define TP_CCTRL_TABLE 0x7ddc -#define TP_MTU_TABLE 0x7de4 -#define MTUINDEX_MASK 0xff000000U -#define MTUINDEX_SHIFT 24 -#define MTUINDEX(x) ((x) << MTUINDEX_SHIFT) -#define MTUWIDTH_MASK 0x000f0000U -#define MTUWIDTH_SHIFT 16 -#define MTUWIDTH(x) ((x) << MTUWIDTH_SHIFT) -#define MTUWIDTH_GET(x) (((x) & MTUWIDTH_MASK) >> MTUWIDTH_SHIFT) -#define MTUVALUE_MASK 0x00003fffU -#define MTUVALUE_SHIFT 0 -#define MTUVALUE(x) ((x) << MTUVALUE_SHIFT) -#define MTUVALUE_GET(x) (((x) & MTUVALUE_MASK) >> MTUVALUE_SHIFT) +#define CIM_PF_MAILBOX_DATA_A 0x240 +#define CIM_PF_MAILBOX_CTRL_A 0x280 -#define TP_RSS_LKP_TABLE 0x7dec -#define LKPTBLROWVLD 0x80000000U -#define LKPTBLQUEUE1_MASK 0x000ffc00U -#define LKPTBLQUEUE1_SHIFT 10 -#define LKPTBLQUEUE1(x) ((x) << LKPTBLQUEUE1_SHIFT) -#define LKPTBLQUEUE1_GET(x) (((x) & LKPTBLQUEUE1_MASK) >> LKPTBLQUEUE1_SHIFT) -#define LKPTBLQUEUE0_MASK 0x000003ffU -#define LKPTBLQUEUE0_SHIFT 0 -#define LKPTBLQUEUE0(x) ((x) << LKPTBLQUEUE0_SHIFT) -#define LKPTBLQUEUE0_GET(x) (((x) & LKPTBLQUEUE0_MASK) >> LKPTBLQUEUE0_SHIFT) +#define MBMSGVALID_S 3 +#define MBMSGVALID_V(x) ((x) << MBMSGVALID_S) +#define MBMSGVALID_F MBMSGVALID_V(1U) -#define TP_PIO_ADDR 0x7e40 -#define TP_PIO_DATA 0x7e44 -#define TP_MIB_INDEX 0x7e50 -#define TP_MIB_DATA 0x7e54 -#define TP_INT_CAUSE 0x7e74 -#define FLMTXFLSTEMPTY 0x40000000U +#define MBINTREQ_S 2 +#define MBINTREQ_V(x) ((x) << MBINTREQ_S) +#define MBINTREQ_F MBINTREQ_V(1U) -#define TP_VLAN_PRI_MAP 0x140 -#define FRAGMENTATION_SHIFT 9 -#define FRAGMENTATION_MASK 0x00000200U -#define MPSHITTYPE_MASK 0x00000100U -#define MACMATCH_MASK 0x00000080U -#define ETHERTYPE_MASK 0x00000040U -#define PROTOCOL_MASK 0x00000020U -#define TOS_MASK 0x00000010U -#define VLAN_MASK 0x00000008U -#define VNIC_ID_MASK 0x00000004U -#define PORT_MASK 0x00000002U -#define FCOE_SHIFT 0 -#define FCOE_MASK 0x00000001U +#define MBOWNER_S 0 +#define MBOWNER_M 0x3U +#define MBOWNER_V(x) ((x) << MBOWNER_S) +#define MBOWNER_G(x) (((x) >> MBOWNER_S) & MBOWNER_M) -#define TP_INGRESS_CONFIG 0x141 -#define VNIC 0x00000800U -#define CSUM_HAS_PSEUDO_HDR 0x00000400U -#define RM_OVLAN 0x00000200U -#define LOOKUPEVERYPKT 0x00000100U +#define CIM_PF_HOST_INT_ENABLE_A 0x288 -#define TP_MIB_MAC_IN_ERR_0 0x0 -#define TP_MIB_TCP_OUT_RST 0xc -#define TP_MIB_TCP_IN_SEG_HI 0x10 -#define TP_MIB_TCP_IN_SEG_LO 0x11 -#define TP_MIB_TCP_OUT_SEG_HI 0x12 -#define TP_MIB_TCP_OUT_SEG_LO 0x13 -#define TP_MIB_TCP_RXT_SEG_HI 0x14 -#define TP_MIB_TCP_RXT_SEG_LO 0x15 -#define TP_MIB_TNL_CNG_DROP_0 0x18 -#define TP_MIB_TCP_V6IN_ERR_0 0x28 -#define TP_MIB_TCP_V6OUT_RST 0x2c -#define TP_MIB_OFD_ARP_DROP 0x36 -#define TP_MIB_TNL_DROP_0 0x44 -#define TP_MIB_OFD_VLN_DROP_0 0x58 +#define MBMSGRDYINTEN_S 19 +#define MBMSGRDYINTEN_V(x) ((x) << MBMSGRDYINTEN_S) +#define MBMSGRDYINTEN_F MBMSGRDYINTEN_V(1U) -#define ULP_TX_INT_CAUSE 0x8dcc -#define PBL_BOUND_ERR_CH3 0x80000000U -#define PBL_BOUND_ERR_CH2 0x40000000U -#define PBL_BOUND_ERR_CH1 0x20000000U -#define PBL_BOUND_ERR_CH0 0x10000000U +#define CIM_PF_HOST_INT_CAUSE_A 0x28c -#define PM_RX_INT_CAUSE 0x8fdc -#define ZERO_E_CMD_ERROR 0x00400000U -#define PMRX_FRAMING_ERROR 0x003ffff0U -#define OCSPI_PAR_ERROR 0x00000008U -#define DB_OPTIONS_PAR_ERROR 0x00000004U -#define IESPI_PAR_ERROR 0x00000002U -#define E_PCMD_PAR_ERROR 0x00000001U +#define MBMSGRDYINT_S 19 +#define MBMSGRDYINT_V(x) ((x) << MBMSGRDYINT_S) +#define MBMSGRDYINT_F MBMSGRDYINT_V(1U) -#define PM_TX_INT_CAUSE 0x8ffc -#define PCMD_LEN_OVFL0 0x80000000U -#define PCMD_LEN_OVFL1 0x40000000U -#define PCMD_LEN_OVFL2 0x20000000U -#define ZERO_C_CMD_ERROR 0x10000000U -#define PMTX_FRAMING_ERROR 0x0ffffff0U -#define OESPI_PAR_ERROR 0x00000008U -#define ICSPI_PAR_ERROR 0x00000002U -#define C_PCMD_PAR_ERROR 0x00000001U +#define CIM_HOST_INT_CAUSE_A 0x7b2c + +#define TIEQOUTPARERRINT_S 20 +#define TIEQOUTPARERRINT_V(x) ((x) << TIEQOUTPARERRINT_S) +#define TIEQOUTPARERRINT_F TIEQOUTPARERRINT_V(1U) + +#define TIEQINPARERRINT_S 19 +#define TIEQINPARERRINT_V(x) ((x) << TIEQINPARERRINT_S) +#define TIEQINPARERRINT_F TIEQINPARERRINT_V(1U) + +#define PREFDROPINT_S 1 +#define PREFDROPINT_V(x) ((x) << PREFDROPINT_S) +#define PREFDROPINT_F PREFDROPINT_V(1U) + +#define UPACCNONZERO_S 0 +#define UPACCNONZERO_V(x) ((x) << UPACCNONZERO_S) +#define UPACCNONZERO_F UPACCNONZERO_V(1U) + +#define MBHOSTPARERR_S 18 +#define MBHOSTPARERR_V(x) ((x) << MBHOSTPARERR_S) +#define MBHOSTPARERR_F MBHOSTPARERR_V(1U) + +#define MBUPPARERR_S 17 +#define MBUPPARERR_V(x) ((x) << MBUPPARERR_S) +#define MBUPPARERR_F MBUPPARERR_V(1U) + +#define IBQTP0PARERR_S 16 +#define IBQTP0PARERR_V(x) ((x) << IBQTP0PARERR_S) +#define IBQTP0PARERR_F IBQTP0PARERR_V(1U) + +#define IBQTP1PARERR_S 15 +#define IBQTP1PARERR_V(x) ((x) << IBQTP1PARERR_S) +#define IBQTP1PARERR_F IBQTP1PARERR_V(1U) + +#define IBQULPPARERR_S 14 +#define IBQULPPARERR_V(x) ((x) << IBQULPPARERR_S) +#define IBQULPPARERR_F IBQULPPARERR_V(1U) + +#define IBQSGELOPARERR_S 13 +#define IBQSGELOPARERR_V(x) ((x) << IBQSGELOPARERR_S) +#define IBQSGELOPARERR_F IBQSGELOPARERR_V(1U) + +#define IBQSGEHIPARERR_S 12 +#define IBQSGEHIPARERR_V(x) ((x) << IBQSGEHIPARERR_S) +#define IBQSGEHIPARERR_F IBQSGEHIPARERR_V(1U) + +#define IBQNCSIPARERR_S 11 +#define IBQNCSIPARERR_V(x) ((x) << IBQNCSIPARERR_S) +#define IBQNCSIPARERR_F IBQNCSIPARERR_V(1U) + +#define OBQULP0PARERR_S 10 +#define OBQULP0PARERR_V(x) ((x) << OBQULP0PARERR_S) +#define OBQULP0PARERR_F OBQULP0PARERR_V(1U) + +#define OBQULP1PARERR_S 9 +#define OBQULP1PARERR_V(x) ((x) << OBQULP1PARERR_S) +#define OBQULP1PARERR_F OBQULP1PARERR_V(1U) + +#define OBQULP2PARERR_S 8 +#define OBQULP2PARERR_V(x) ((x) << OBQULP2PARERR_S) +#define OBQULP2PARERR_F OBQULP2PARERR_V(1U) + +#define OBQULP3PARERR_S 7 +#define OBQULP3PARERR_V(x) ((x) << OBQULP3PARERR_S) +#define OBQULP3PARERR_F OBQULP3PARERR_V(1U) + +#define OBQSGEPARERR_S 6 +#define OBQSGEPARERR_V(x) ((x) << OBQSGEPARERR_S) +#define OBQSGEPARERR_F OBQSGEPARERR_V(1U) + +#define OBQNCSIPARERR_S 5 +#define OBQNCSIPARERR_V(x) ((x) << OBQNCSIPARERR_S) +#define OBQNCSIPARERR_F OBQNCSIPARERR_V(1U) + +#define CIM_HOST_UPACC_INT_CAUSE_A 0x7b34 + +#define EEPROMWRINT_S 30 +#define EEPROMWRINT_V(x) ((x) << EEPROMWRINT_S) +#define EEPROMWRINT_F EEPROMWRINT_V(1U) + +#define TIMEOUTMAINT_S 29 +#define TIMEOUTMAINT_V(x) ((x) << TIMEOUTMAINT_S) +#define TIMEOUTMAINT_F TIMEOUTMAINT_V(1U) + +#define TIMEOUTINT_S 28 +#define TIMEOUTINT_V(x) ((x) << TIMEOUTINT_S) +#define TIMEOUTINT_F TIMEOUTINT_V(1U) + +#define RSPOVRLOOKUPINT_S 27 +#define RSPOVRLOOKUPINT_V(x) ((x) << RSPOVRLOOKUPINT_S) +#define RSPOVRLOOKUPINT_F RSPOVRLOOKUPINT_V(1U) + +#define REQOVRLOOKUPINT_S 26 +#define REQOVRLOOKUPINT_V(x) ((x) << REQOVRLOOKUPINT_S) +#define REQOVRLOOKUPINT_F REQOVRLOOKUPINT_V(1U) + +#define BLKWRPLINT_S 25 +#define BLKWRPLINT_V(x) ((x) << BLKWRPLINT_S) +#define BLKWRPLINT_F BLKWRPLINT_V(1U) + +#define BLKRDPLINT_S 24 +#define BLKRDPLINT_V(x) ((x) << BLKRDPLINT_S) +#define BLKRDPLINT_F BLKRDPLINT_V(1U) + +#define SGLWRPLINT_S 23 +#define SGLWRPLINT_V(x) ((x) << SGLWRPLINT_S) +#define SGLWRPLINT_F SGLWRPLINT_V(1U) + +#define SGLRDPLINT_S 22 +#define SGLRDPLINT_V(x) ((x) << SGLRDPLINT_S) +#define SGLRDPLINT_F SGLRDPLINT_V(1U) + +#define BLKWRCTLINT_S 21 +#define BLKWRCTLINT_V(x) ((x) << BLKWRCTLINT_S) +#define BLKWRCTLINT_F BLKWRCTLINT_V(1U) + +#define BLKRDCTLINT_S 20 +#define BLKRDCTLINT_V(x) ((x) << BLKRDCTLINT_S) +#define BLKRDCTLINT_F BLKRDCTLINT_V(1U) + +#define SGLWRCTLINT_S 19 +#define SGLWRCTLINT_V(x) ((x) << SGLWRCTLINT_S) +#define SGLWRCTLINT_F SGLWRCTLINT_V(1U) + +#define SGLRDCTLINT_S 18 +#define SGLRDCTLINT_V(x) ((x) << SGLRDCTLINT_S) +#define SGLRDCTLINT_F SGLRDCTLINT_V(1U) + +#define BLKWREEPROMINT_S 17 +#define BLKWREEPROMINT_V(x) ((x) << BLKWREEPROMINT_S) +#define BLKWREEPROMINT_F BLKWREEPROMINT_V(1U) + +#define BLKRDEEPROMINT_S 16 +#define BLKRDEEPROMINT_V(x) ((x) << BLKRDEEPROMINT_S) +#define BLKRDEEPROMINT_F BLKRDEEPROMINT_V(1U) + +#define SGLWREEPROMINT_S 15 +#define SGLWREEPROMINT_V(x) ((x) << SGLWREEPROMINT_S) +#define SGLWREEPROMINT_F SGLWREEPROMINT_V(1U) + +#define SGLRDEEPROMINT_S 14 +#define SGLRDEEPROMINT_V(x) ((x) << SGLRDEEPROMINT_S) +#define SGLRDEEPROMINT_F SGLRDEEPROMINT_V(1U) + +#define BLKWRFLASHINT_S 13 +#define BLKWRFLASHINT_V(x) ((x) << BLKWRFLASHINT_S) +#define BLKWRFLASHINT_F BLKWRFLASHINT_V(1U) + +#define BLKRDFLASHINT_S 12 +#define BLKRDFLASHINT_V(x) ((x) << BLKRDFLASHINT_S) +#define BLKRDFLASHINT_F BLKRDFLASHINT_V(1U) + +#define SGLWRFLASHINT_S 11 +#define SGLWRFLASHINT_V(x) ((x) << SGLWRFLASHINT_S) +#define SGLWRFLASHINT_F SGLWRFLASHINT_V(1U) + +#define SGLRDFLASHINT_S 10 +#define SGLRDFLASHINT_V(x) ((x) << SGLRDFLASHINT_S) +#define SGLRDFLASHINT_F SGLRDFLASHINT_V(1U) + +#define BLKWRBOOTINT_S 9 +#define BLKWRBOOTINT_V(x) ((x) << BLKWRBOOTINT_S) +#define BLKWRBOOTINT_F BLKWRBOOTINT_V(1U) + +#define BLKRDBOOTINT_S 8 +#define BLKRDBOOTINT_V(x) ((x) << BLKRDBOOTINT_S) +#define BLKRDBOOTINT_F BLKRDBOOTINT_V(1U) + +#define SGLWRBOOTINT_S 7 +#define SGLWRBOOTINT_V(x) ((x) << SGLWRBOOTINT_S) +#define SGLWRBOOTINT_F SGLWRBOOTINT_V(1U) + +#define SGLRDBOOTINT_S 6 +#define SGLRDBOOTINT_V(x) ((x) << SGLRDBOOTINT_S) +#define SGLRDBOOTINT_F SGLRDBOOTINT_V(1U) + +#define ILLWRBEINT_S 5 +#define ILLWRBEINT_V(x) ((x) << ILLWRBEINT_S) +#define ILLWRBEINT_F ILLWRBEINT_V(1U) + +#define ILLRDBEINT_S 4 +#define ILLRDBEINT_V(x) ((x) << ILLRDBEINT_S) +#define ILLRDBEINT_F ILLRDBEINT_V(1U) + +#define ILLRDINT_S 3 +#define ILLRDINT_V(x) ((x) << ILLRDINT_S) +#define ILLRDINT_F ILLRDINT_V(1U) + +#define ILLWRINT_S 2 +#define ILLWRINT_V(x) ((x) << ILLWRINT_S) +#define ILLWRINT_F ILLWRINT_V(1U) + +#define ILLTRANSINT_S 1 +#define ILLTRANSINT_V(x) ((x) << ILLTRANSINT_S) +#define ILLTRANSINT_F ILLTRANSINT_V(1U) + +#define RSVDSPACEINT_S 0 +#define RSVDSPACEINT_V(x) ((x) << RSVDSPACEINT_S) +#define RSVDSPACEINT_F RSVDSPACEINT_V(1U) + +/* registers for module TP */ +#define DBGLAWHLF_S 23 +#define DBGLAWHLF_V(x) ((x) << DBGLAWHLF_S) +#define DBGLAWHLF_F DBGLAWHLF_V(1U) + +#define DBGLAWPTR_S 16 +#define DBGLAWPTR_M 0x7fU +#define DBGLAWPTR_G(x) (((x) >> DBGLAWPTR_S) & DBGLAWPTR_M) + +#define DBGLAENABLE_S 12 +#define DBGLAENABLE_V(x) ((x) << DBGLAENABLE_S) +#define DBGLAENABLE_F DBGLAENABLE_V(1U) + +#define DBGLARPTR_S 0 +#define DBGLARPTR_M 0x7fU +#define DBGLARPTR_V(x) ((x) << DBGLARPTR_S) + +#define TP_DBG_LA_DATAL_A 0x7ed8 +#define TP_DBG_LA_CONFIG_A 0x7ed4 +#define TP_OUT_CONFIG_A 0x7d04 +#define TP_GLOBAL_CONFIG_A 0x7d08 + +#define DBGLAMODE_S 14 +#define DBGLAMODE_M 0x3U +#define DBGLAMODE_G(x) (((x) >> DBGLAMODE_S) & DBGLAMODE_M) + +#define FIVETUPLELOOKUP_S 17 +#define FIVETUPLELOOKUP_M 0x3U +#define FIVETUPLELOOKUP_V(x) ((x) << FIVETUPLELOOKUP_S) +#define FIVETUPLELOOKUP_G(x) (((x) >> FIVETUPLELOOKUP_S) & FIVETUPLELOOKUP_M) + +#define TP_PARA_REG2_A 0x7d68 + +#define MAXRXDATA_S 16 +#define MAXRXDATA_M 0xffffU +#define MAXRXDATA_G(x) (((x) >> MAXRXDATA_S) & MAXRXDATA_M) + +#define TP_TIMER_RESOLUTION_A 0x7d90 + +#define TIMERRESOLUTION_S 16 +#define TIMERRESOLUTION_M 0xffU +#define TIMERRESOLUTION_G(x) (((x) >> TIMERRESOLUTION_S) & TIMERRESOLUTION_M) + +#define TIMESTAMPRESOLUTION_S 8 +#define TIMESTAMPRESOLUTION_M 0xffU +#define TIMESTAMPRESOLUTION_G(x) \ + (((x) >> TIMESTAMPRESOLUTION_S) & TIMESTAMPRESOLUTION_M) + +#define DELAYEDACKRESOLUTION_S 0 +#define DELAYEDACKRESOLUTION_M 0xffU +#define DELAYEDACKRESOLUTION_G(x) \ + (((x) >> DELAYEDACKRESOLUTION_S) & DELAYEDACKRESOLUTION_M) + +#define TP_SHIFT_CNT_A 0x7dc0 +#define TP_RXT_MIN_A 0x7d98 +#define TP_RXT_MAX_A 0x7d9c +#define TP_PERS_MIN_A 0x7da0 +#define TP_PERS_MAX_A 0x7da4 +#define TP_KEEP_IDLE_A 0x7da8 +#define TP_KEEP_INTVL_A 0x7dac +#define TP_INIT_SRTT_A 0x7db0 +#define TP_DACK_TIMER_A 0x7db4 +#define TP_FINWAIT2_TIMER_A 0x7db8 + +#define INITSRTT_S 0 +#define INITSRTT_M 0xffffU +#define INITSRTT_G(x) (((x) >> INITSRTT_S) & INITSRTT_M) + +#define PERSMAX_S 0 +#define PERSMAX_M 0x3fffffffU +#define PERSMAX_V(x) ((x) << PERSMAX_S) +#define PERSMAX_G(x) (((x) >> PERSMAX_S) & PERSMAX_M) + +#define SYNSHIFTMAX_S 24 +#define SYNSHIFTMAX_M 0xffU +#define SYNSHIFTMAX_V(x) ((x) << SYNSHIFTMAX_S) +#define SYNSHIFTMAX_G(x) (((x) >> SYNSHIFTMAX_S) & SYNSHIFTMAX_M) + +#define RXTSHIFTMAXR1_S 20 +#define RXTSHIFTMAXR1_M 0xfU +#define RXTSHIFTMAXR1_V(x) ((x) << RXTSHIFTMAXR1_S) +#define RXTSHIFTMAXR1_G(x) (((x) >> RXTSHIFTMAXR1_S) & RXTSHIFTMAXR1_M) + +#define RXTSHIFTMAXR2_S 16 +#define RXTSHIFTMAXR2_M 0xfU +#define RXTSHIFTMAXR2_V(x) ((x) << RXTSHIFTMAXR2_S) +#define RXTSHIFTMAXR2_G(x) (((x) >> RXTSHIFTMAXR2_S) & RXTSHIFTMAXR2_M) + +#define PERSHIFTBACKOFFMAX_S 12 +#define PERSHIFTBACKOFFMAX_M 0xfU +#define PERSHIFTBACKOFFMAX_V(x) ((x) << PERSHIFTBACKOFFMAX_S) +#define PERSHIFTBACKOFFMAX_G(x) \ + (((x) >> PERSHIFTBACKOFFMAX_S) & PERSHIFTBACKOFFMAX_M) + +#define PERSHIFTMAX_S 8 +#define PERSHIFTMAX_M 0xfU +#define PERSHIFTMAX_V(x) ((x) << PERSHIFTMAX_S) +#define PERSHIFTMAX_G(x) (((x) >> PERSHIFTMAX_S) & PERSHIFTMAX_M) + +#define KEEPALIVEMAXR1_S 4 +#define KEEPALIVEMAXR1_M 0xfU +#define KEEPALIVEMAXR1_V(x) ((x) << KEEPALIVEMAXR1_S) +#define KEEPALIVEMAXR1_G(x) (((x) >> KEEPALIVEMAXR1_S) & KEEPALIVEMAXR1_M) + +#define KEEPALIVEMAXR2_S 0 +#define KEEPALIVEMAXR2_M 0xfU +#define KEEPALIVEMAXR2_V(x) ((x) << KEEPALIVEMAXR2_S) +#define KEEPALIVEMAXR2_G(x) (((x) >> KEEPALIVEMAXR2_S) & KEEPALIVEMAXR2_M) + +#define ROWINDEX_S 16 +#define ROWINDEX_V(x) ((x) << ROWINDEX_S) + +#define TP_CCTRL_TABLE_A 0x7ddc +#define TP_MTU_TABLE_A 0x7de4 + +#define MTUINDEX_S 24 +#define MTUINDEX_V(x) ((x) << MTUINDEX_S) + +#define MTUWIDTH_S 16 +#define MTUWIDTH_M 0xfU +#define MTUWIDTH_V(x) ((x) << MTUWIDTH_S) +#define MTUWIDTH_G(x) (((x) >> MTUWIDTH_S) & MTUWIDTH_M) + +#define MTUVALUE_S 0 +#define MTUVALUE_M 0x3fffU +#define MTUVALUE_V(x) ((x) << MTUVALUE_S) +#define MTUVALUE_G(x) (((x) >> MTUVALUE_S) & MTUVALUE_M) + +#define TP_RSS_LKP_TABLE_A 0x7dec + +#define LKPTBLROWVLD_S 31 +#define LKPTBLROWVLD_V(x) ((x) << LKPTBLROWVLD_S) +#define LKPTBLROWVLD_F LKPTBLROWVLD_V(1U) + +#define LKPTBLQUEUE1_S 10 +#define LKPTBLQUEUE1_M 0x3ffU +#define LKPTBLQUEUE1_G(x) (((x) >> LKPTBLQUEUE1_S) & LKPTBLQUEUE1_M) + +#define LKPTBLQUEUE0_S 0 +#define LKPTBLQUEUE0_M 0x3ffU +#define LKPTBLQUEUE0_G(x) (((x) >> LKPTBLQUEUE0_S) & LKPTBLQUEUE0_M) + +#define TP_PIO_ADDR_A 0x7e40 +#define TP_PIO_DATA_A 0x7e44 +#define TP_MIB_INDEX_A 0x7e50 +#define TP_MIB_DATA_A 0x7e54 +#define TP_INT_CAUSE_A 0x7e74 + +#define FLMTXFLSTEMPTY_S 30 +#define FLMTXFLSTEMPTY_V(x) ((x) << FLMTXFLSTEMPTY_S) +#define FLMTXFLSTEMPTY_F FLMTXFLSTEMPTY_V(1U) + +#define TP_VLAN_PRI_MAP_A 0x140 + +#define FRAGMENTATION_S 9 +#define FRAGMENTATION_V(x) ((x) << FRAGMENTATION_S) +#define FRAGMENTATION_F FRAGMENTATION_V(1U) + +#define MPSHITTYPE_S 8 +#define MPSHITTYPE_V(x) ((x) << MPSHITTYPE_S) +#define MPSHITTYPE_F MPSHITTYPE_V(1U) + +#define MACMATCH_S 7 +#define MACMATCH_V(x) ((x) << MACMATCH_S) +#define MACMATCH_F MACMATCH_V(1U) + +#define ETHERTYPE_S 6 +#define ETHERTYPE_V(x) ((x) << ETHERTYPE_S) +#define ETHERTYPE_F ETHERTYPE_V(1U) + +#define PROTOCOL_S 5 +#define PROTOCOL_V(x) ((x) << PROTOCOL_S) +#define PROTOCOL_F PROTOCOL_V(1U) + +#define TOS_S 4 +#define TOS_V(x) ((x) << TOS_S) +#define TOS_F TOS_V(1U) + +#define VLAN_S 3 +#define VLAN_V(x) ((x) << VLAN_S) +#define VLAN_F VLAN_V(1U) + +#define VNIC_ID_S 2 +#define VNIC_ID_V(x) ((x) << VNIC_ID_S) +#define VNIC_ID_F VNIC_ID_V(1U) + +#define PORT_S 1 +#define PORT_V(x) ((x) << PORT_S) +#define PORT_F PORT_V(1U) + +#define FCOE_S 0 +#define FCOE_V(x) ((x) << FCOE_S) +#define FCOE_F FCOE_V(1U) + +#define FILTERMODE_S 15 +#define FILTERMODE_V(x) ((x) << FILTERMODE_S) +#define FILTERMODE_F FILTERMODE_V(1U) + +#define FCOEMASK_S 14 +#define FCOEMASK_V(x) ((x) << FCOEMASK_S) +#define FCOEMASK_F FCOEMASK_V(1U) + +#define TP_INGRESS_CONFIG_A 0x141 + +#define VNIC_S 11 +#define VNIC_V(x) ((x) << VNIC_S) +#define VNIC_F VNIC_V(1U) + +#define CSUM_HAS_PSEUDO_HDR_S 10 +#define CSUM_HAS_PSEUDO_HDR_V(x) ((x) << CSUM_HAS_PSEUDO_HDR_S) +#define CSUM_HAS_PSEUDO_HDR_F CSUM_HAS_PSEUDO_HDR_V(1U) + +#define TP_MIB_MAC_IN_ERR_0_A 0x0 +#define TP_MIB_TCP_OUT_RST_A 0xc +#define TP_MIB_TCP_IN_SEG_HI_A 0x10 +#define TP_MIB_TCP_IN_SEG_LO_A 0x11 +#define TP_MIB_TCP_OUT_SEG_HI_A 0x12 +#define TP_MIB_TCP_OUT_SEG_LO_A 0x13 +#define TP_MIB_TCP_RXT_SEG_HI_A 0x14 +#define TP_MIB_TCP_RXT_SEG_LO_A 0x15 +#define TP_MIB_TNL_CNG_DROP_0_A 0x18 +#define TP_MIB_TCP_V6IN_ERR_0_A 0x28 +#define TP_MIB_TCP_V6OUT_RST_A 0x2c +#define TP_MIB_OFD_ARP_DROP_A 0x36 +#define TP_MIB_TNL_DROP_0_A 0x44 +#define TP_MIB_OFD_VLN_DROP_0_A 0x58 + +#define ULP_TX_INT_CAUSE_A 0x8dcc + +#define PBL_BOUND_ERR_CH3_S 31 +#define PBL_BOUND_ERR_CH3_V(x) ((x) << PBL_BOUND_ERR_CH3_S) +#define PBL_BOUND_ERR_CH3_F PBL_BOUND_ERR_CH3_V(1U) + +#define PBL_BOUND_ERR_CH2_S 30 +#define PBL_BOUND_ERR_CH2_V(x) ((x) << PBL_BOUND_ERR_CH2_S) +#define PBL_BOUND_ERR_CH2_F PBL_BOUND_ERR_CH2_V(1U) + +#define PBL_BOUND_ERR_CH1_S 29 +#define PBL_BOUND_ERR_CH1_V(x) ((x) << PBL_BOUND_ERR_CH1_S) +#define PBL_BOUND_ERR_CH1_F PBL_BOUND_ERR_CH1_V(1U) + +#define PBL_BOUND_ERR_CH0_S 28 +#define PBL_BOUND_ERR_CH0_V(x) ((x) << PBL_BOUND_ERR_CH0_S) +#define PBL_BOUND_ERR_CH0_F PBL_BOUND_ERR_CH0_V(1U) + +#define PM_RX_INT_CAUSE_A 0x8fdc +#define PM_RX_STAT_CONFIG_A 0x8fc8 +#define PM_RX_STAT_COUNT_A 0x8fcc +#define PM_RX_STAT_LSB_A 0x8fd0 +#define PM_RX_DBG_CTRL_A 0x8fd0 +#define PM_RX_DBG_DATA_A 0x8fd4 +#define PM_RX_DBG_STAT_MSB_A 0x10013 + +#define PMRX_FRAMING_ERROR_F 0x003ffff0U + +#define ZERO_E_CMD_ERROR_S 22 +#define ZERO_E_CMD_ERROR_V(x) ((x) << ZERO_E_CMD_ERROR_S) +#define ZERO_E_CMD_ERROR_F ZERO_E_CMD_ERROR_V(1U) + +#define OCSPI_PAR_ERROR_S 3 +#define OCSPI_PAR_ERROR_V(x) ((x) << OCSPI_PAR_ERROR_S) +#define OCSPI_PAR_ERROR_F OCSPI_PAR_ERROR_V(1U) + +#define DB_OPTIONS_PAR_ERROR_S 2 +#define DB_OPTIONS_PAR_ERROR_V(x) ((x) << DB_OPTIONS_PAR_ERROR_S) +#define DB_OPTIONS_PAR_ERROR_F DB_OPTIONS_PAR_ERROR_V(1U) + +#define IESPI_PAR_ERROR_S 1 +#define IESPI_PAR_ERROR_V(x) ((x) << IESPI_PAR_ERROR_S) +#define IESPI_PAR_ERROR_F IESPI_PAR_ERROR_V(1U) + +#define PMRX_E_PCMD_PAR_ERROR_S 0 +#define PMRX_E_PCMD_PAR_ERROR_V(x) ((x) << PMRX_E_PCMD_PAR_ERROR_S) +#define PMRX_E_PCMD_PAR_ERROR_F PMRX_E_PCMD_PAR_ERROR_V(1U) + +#define PM_TX_INT_CAUSE_A 0x8ffc +#define PM_TX_STAT_CONFIG_A 0x8fe8 +#define PM_TX_STAT_COUNT_A 0x8fec +#define PM_TX_STAT_LSB_A 0x8ff0 +#define PM_TX_DBG_CTRL_A 0x8ff0 +#define PM_TX_DBG_DATA_A 0x8ff4 +#define PM_TX_DBG_STAT_MSB_A 0x1001a + +#define PCMD_LEN_OVFL0_S 31 +#define PCMD_LEN_OVFL0_V(x) ((x) << PCMD_LEN_OVFL0_S) +#define PCMD_LEN_OVFL0_F PCMD_LEN_OVFL0_V(1U) + +#define PCMD_LEN_OVFL1_S 30 +#define PCMD_LEN_OVFL1_V(x) ((x) << PCMD_LEN_OVFL1_S) +#define PCMD_LEN_OVFL1_F PCMD_LEN_OVFL1_V(1U) + +#define PCMD_LEN_OVFL2_S 29 +#define PCMD_LEN_OVFL2_V(x) ((x) << PCMD_LEN_OVFL2_S) +#define PCMD_LEN_OVFL2_F PCMD_LEN_OVFL2_V(1U) + +#define ZERO_C_CMD_ERROR_S 28 +#define ZERO_C_CMD_ERROR_V(x) ((x) << ZERO_C_CMD_ERROR_S) +#define ZERO_C_CMD_ERROR_F ZERO_C_CMD_ERROR_V(1U) + +#define PMTX_FRAMING_ERROR_F 0x0ffffff0U + +#define OESPI_PAR_ERROR_S 3 +#define OESPI_PAR_ERROR_V(x) ((x) << OESPI_PAR_ERROR_S) +#define OESPI_PAR_ERROR_F OESPI_PAR_ERROR_V(1U) + +#define ICSPI_PAR_ERROR_S 1 +#define ICSPI_PAR_ERROR_V(x) ((x) << ICSPI_PAR_ERROR_S) +#define ICSPI_PAR_ERROR_F ICSPI_PAR_ERROR_V(1U) + +#define PMTX_C_PCMD_PAR_ERROR_S 0 +#define PMTX_C_PCMD_PAR_ERROR_V(x) ((x) << PMTX_C_PCMD_PAR_ERROR_S) +#define PMTX_C_PCMD_PAR_ERROR_F PMTX_C_PCMD_PAR_ERROR_V(1U) #define MPS_PORT_STAT_TX_PORT_BYTES_L 0x400 #define MPS_PORT_STAT_TX_PORT_BYTES_H 0x404 @@ -959,41 +1623,57 @@ #define MPS_PORT_STAT_RX_PORT_PPP7_H 0x60c #define MPS_PORT_STAT_RX_PORT_LESS_64B_L 0x610 #define MPS_PORT_STAT_RX_PORT_LESS_64B_H 0x614 -#define MAC_PORT_CFG2 0x818 #define MAC_PORT_MAGIC_MACID_LO 0x824 #define MAC_PORT_MAGIC_MACID_HI 0x828 -#define MAC_PORT_EPIO_DATA0 0x8c0 -#define MAC_PORT_EPIO_DATA1 0x8c4 -#define MAC_PORT_EPIO_DATA2 0x8c8 -#define MAC_PORT_EPIO_DATA3 0x8cc -#define MAC_PORT_EPIO_OP 0x8d0 -#define MPS_CMN_CTL 0x9000 -#define NUMPORTS_MASK 0x00000003U -#define NUMPORTS_SHIFT 0 -#define NUMPORTS_GET(x) (((x) & NUMPORTS_MASK) >> NUMPORTS_SHIFT) +#define MAC_PORT_EPIO_DATA0_A 0x8c0 +#define MAC_PORT_EPIO_DATA1_A 0x8c4 +#define MAC_PORT_EPIO_DATA2_A 0x8c8 +#define MAC_PORT_EPIO_DATA3_A 0x8cc +#define MAC_PORT_EPIO_OP_A 0x8d0 -#define MPS_INT_CAUSE 0x9008 -#define STATINT 0x00000020U -#define TXINT 0x00000010U -#define RXINT 0x00000008U -#define TRCINT 0x00000004U -#define CLSINT 0x00000002U -#define PLINT 0x00000001U +#define MAC_PORT_CFG2_A 0x818 -#define MPS_TX_INT_CAUSE 0x9408 -#define PORTERR 0x00010000U -#define FRMERR 0x00008000U -#define SECNTERR 0x00004000U -#define BUBBLE 0x00002000U -#define TXDESCFIFO 0x00001e00U -#define TXDATAFIFO 0x000001e0U -#define NCSIFIFO 0x00000010U -#define TPFIFO 0x0000000fU +#define MPS_CMN_CTL_A 0x9000 -#define MPS_STAT_PERR_INT_CAUSE_SRAM 0x9614 -#define MPS_STAT_PERR_INT_CAUSE_TX_FIFO 0x9620 -#define MPS_STAT_PERR_INT_CAUSE_RX_FIFO 0x962c +#define NUMPORTS_S 0 +#define NUMPORTS_M 0x3U +#define NUMPORTS_G(x) (((x) >> NUMPORTS_S) & NUMPORTS_M) + +#define MPS_INT_CAUSE_A 0x9008 +#define MPS_TX_INT_CAUSE_A 0x9408 + +#define FRMERR_S 15 +#define FRMERR_V(x) ((x) << FRMERR_S) +#define FRMERR_F FRMERR_V(1U) + +#define SECNTERR_S 14 +#define SECNTERR_V(x) ((x) << SECNTERR_S) +#define SECNTERR_F SECNTERR_V(1U) + +#define BUBBLE_S 13 +#define BUBBLE_V(x) ((x) << BUBBLE_S) +#define BUBBLE_F BUBBLE_V(1U) + +#define TXDESCFIFO_S 9 +#define TXDESCFIFO_M 0xfU +#define TXDESCFIFO_V(x) ((x) << TXDESCFIFO_S) + +#define TXDATAFIFO_S 5 +#define TXDATAFIFO_M 0xfU +#define TXDATAFIFO_V(x) ((x) << TXDATAFIFO_S) + +#define NCSIFIFO_S 4 +#define NCSIFIFO_V(x) ((x) << NCSIFIFO_S) +#define NCSIFIFO_F NCSIFIFO_V(1U) + +#define TPFIFO_S 0 +#define TPFIFO_M 0xfU +#define TPFIFO_V(x) ((x) << TPFIFO_S) + +#define MPS_STAT_PERR_INT_CAUSE_SRAM_A 0x9614 +#define MPS_STAT_PERR_INT_CAUSE_TX_FIFO_A 0x9620 +#define MPS_STAT_PERR_INT_CAUSE_RX_FIFO_A 0x962c #define MPS_STAT_RX_BG_0_MAC_DROP_FRAME_L 0x9640 #define MPS_STAT_RX_BG_0_MAC_DROP_FRAME_H 0x9644 @@ -1027,294 +1707,851 @@ #define MPS_STAT_RX_BG_2_LB_TRUNC_FRAME_H 0x96b4 #define MPS_STAT_RX_BG_3_LB_TRUNC_FRAME_L 0x96b8 #define MPS_STAT_RX_BG_3_LB_TRUNC_FRAME_H 0x96bc -#define MPS_TRC_CFG 0x9800 -#define TRCFIFOEMPTY 0x00000010U -#define TRCIGNOREDROPINPUT 0x00000008U -#define TRCKEEPDUPLICATES 0x00000004U -#define TRCEN 0x00000002U -#define TRCMULTIFILTER 0x00000001U -#define MPS_TRC_RSS_CONTROL 0x9808 -#define MPS_T5_TRC_RSS_CONTROL 0xa00c -#define RSSCONTROL_MASK 0x00ff0000U -#define RSSCONTROL_SHIFT 16 -#define RSSCONTROL(x) ((x) << RSSCONTROL_SHIFT) -#define QUEUENUMBER_MASK 0x0000ffffU -#define QUEUENUMBER_SHIFT 0 -#define QUEUENUMBER(x) ((x) << QUEUENUMBER_SHIFT) +#define MPS_TRC_CFG_A 0x9800 -#define MPS_TRC_FILTER_MATCH_CTL_A 0x9810 -#define TFINVERTMATCH 0x01000000U -#define TFPKTTOOLARGE 0x00800000U -#define TFEN 0x00400000U -#define TFPORT_MASK 0x003c0000U -#define TFPORT_SHIFT 18 -#define TFPORT(x) ((x) << TFPORT_SHIFT) -#define TFPORT_GET(x) (((x) & TFPORT_MASK) >> TFPORT_SHIFT) -#define TFDROP 0x00020000U -#define TFSOPEOPERR 0x00010000U -#define TFLENGTH_MASK 0x00001f00U -#define TFLENGTH_SHIFT 8 -#define TFLENGTH(x) ((x) << TFLENGTH_SHIFT) -#define TFLENGTH_GET(x) (((x) & TFLENGTH_MASK) >> TFLENGTH_SHIFT) -#define TFOFFSET_MASK 0x0000001fU -#define TFOFFSET_SHIFT 0 -#define TFOFFSET(x) ((x) << TFOFFSET_SHIFT) -#define TFOFFSET_GET(x) (((x) & TFOFFSET_MASK) >> TFOFFSET_SHIFT) +#define TRCFIFOEMPTY_S 4 +#define TRCFIFOEMPTY_V(x) ((x) << TRCFIFOEMPTY_S) +#define TRCFIFOEMPTY_F TRCFIFOEMPTY_V(1U) -#define MPS_TRC_FILTER_MATCH_CTL_B 0x9820 -#define TFMINPKTSIZE_MASK 0x01ff0000U -#define TFMINPKTSIZE_SHIFT 16 -#define TFMINPKTSIZE(x) ((x) << TFMINPKTSIZE_SHIFT) -#define TFMINPKTSIZE_GET(x) (((x) & TFMINPKTSIZE_MASK) >> TFMINPKTSIZE_SHIFT) -#define TFCAPTUREMAX_MASK 0x00003fffU -#define TFCAPTUREMAX_SHIFT 0 -#define TFCAPTUREMAX(x) ((x) << TFCAPTUREMAX_SHIFT) -#define TFCAPTUREMAX_GET(x) (((x) & TFCAPTUREMAX_MASK) >> TFCAPTUREMAX_SHIFT) +#define TRCIGNOREDROPINPUT_S 3 +#define TRCIGNOREDROPINPUT_V(x) ((x) << TRCIGNOREDROPINPUT_S) +#define TRCIGNOREDROPINPUT_F TRCIGNOREDROPINPUT_V(1U) -#define MPS_TRC_INT_CAUSE 0x985c -#define MISCPERR 0x00000100U -#define PKTFIFO 0x000000f0U -#define FILTMEM 0x0000000fU +#define TRCKEEPDUPLICATES_S 2 +#define TRCKEEPDUPLICATES_V(x) ((x) << TRCKEEPDUPLICATES_S) +#define TRCKEEPDUPLICATES_F TRCKEEPDUPLICATES_V(1U) -#define MPS_TRC_FILTER0_MATCH 0x9c00 -#define MPS_TRC_FILTER0_DONT_CARE 0x9c80 -#define MPS_TRC_FILTER1_MATCH 0x9d00 -#define MPS_CLS_INT_CAUSE 0xd028 -#define PLERRENB 0x00000008U -#define HASHSRAM 0x00000004U -#define MATCHTCAM 0x00000002U -#define MATCHSRAM 0x00000001U +#define TRCEN_S 1 +#define TRCEN_V(x) ((x) << TRCEN_S) +#define TRCEN_F TRCEN_V(1U) -#define MPS_RX_PERR_INT_CAUSE 0x11074 +#define TRCMULTIFILTER_S 0 +#define TRCMULTIFILTER_V(x) ((x) << TRCMULTIFILTER_S) +#define TRCMULTIFILTER_F TRCMULTIFILTER_V(1U) -#define CPL_INTR_CAUSE 0x19054 -#define CIM_OP_MAP_PERR 0x00000020U -#define CIM_OVFL_ERROR 0x00000010U -#define TP_FRAMING_ERROR 0x00000008U -#define SGE_FRAMING_ERROR 0x00000004U -#define CIM_FRAMING_ERROR 0x00000002U -#define ZERO_SWITCH_ERROR 0x00000001U +#define MPS_TRC_RSS_CONTROL_A 0x9808 +#define MPS_T5_TRC_RSS_CONTROL_A 0xa00c -#define SMB_INT_CAUSE 0x19090 -#define MSTTXFIFOPARINT 0x00200000U -#define MSTRXFIFOPARINT 0x00100000U -#define SLVFIFOPARINT 0x00080000U +#define RSSCONTROL_S 16 +#define RSSCONTROL_V(x) ((x) << RSSCONTROL_S) -#define ULP_RX_INT_CAUSE 0x19158 -#define ULP_RX_ISCSI_TAGMASK 0x19164 -#define ULP_RX_ISCSI_PSZ 0x19168 -#define HPZ3_MASK 0x0f000000U -#define HPZ3_SHIFT 24 -#define HPZ3(x) ((x) << HPZ3_SHIFT) -#define HPZ2_MASK 0x000f0000U -#define HPZ2_SHIFT 16 -#define HPZ2(x) ((x) << HPZ2_SHIFT) -#define HPZ1_MASK 0x00000f00U -#define HPZ1_SHIFT 8 -#define HPZ1(x) ((x) << HPZ1_SHIFT) -#define HPZ0_MASK 0x0000000fU -#define HPZ0_SHIFT 0 -#define HPZ0(x) ((x) << HPZ0_SHIFT) +#define QUEUENUMBER_S 0 +#define QUEUENUMBER_V(x) ((x) << QUEUENUMBER_S) -#define ULP_RX_TDDP_PSZ 0x19178 +#define TP_RSS_CONFIG_A 0x7df0 -#define SF_DATA 0x193f8 -#define SF_OP 0x193fc -#define SF_BUSY 0x80000000U -#define SF_LOCK 0x00000010U -#define SF_CONT 0x00000008U -#define BYTECNT_MASK 0x00000006U -#define BYTECNT_SHIFT 1 -#define BYTECNT(x) ((x) << BYTECNT_SHIFT) -#define OP_WR 0x00000001U +#define TNL4TUPENIPV6_S 31 +#define TNL4TUPENIPV6_V(x) ((x) << TNL4TUPENIPV6_S) +#define TNL4TUPENIPV6_F TNL4TUPENIPV6_V(1U) -#define PL_PF_INT_CAUSE 0x3c0 -#define PFSW 0x00000008U -#define PFSGE 0x00000004U -#define PFCIM 0x00000002U -#define PFMPS 0x00000001U +#define TNL2TUPENIPV6_S 30 +#define TNL2TUPENIPV6_V(x) ((x) << TNL2TUPENIPV6_S) +#define TNL2TUPENIPV6_F TNL2TUPENIPV6_V(1U) -#define PL_PF_INT_ENABLE 0x3c4 -#define PL_PF_CTL 0x3c8 -#define SWINT 0x00000001U +#define TNL4TUPENIPV4_S 29 +#define TNL4TUPENIPV4_V(x) ((x) << TNL4TUPENIPV4_S) +#define TNL4TUPENIPV4_F TNL4TUPENIPV4_V(1U) -#define PL_WHOAMI 0x19400 -#define SOURCEPF_MASK 0x00000700U -#define SOURCEPF_SHIFT 8 -#define SOURCEPF(x) ((x) << SOURCEPF_SHIFT) -#define SOURCEPF_GET(x) (((x) & SOURCEPF_MASK) >> SOURCEPF_SHIFT) -#define ISVF 0x00000080U -#define VFID_MASK 0x0000007fU -#define VFID_SHIFT 0 -#define VFID(x) ((x) << VFID_SHIFT) -#define VFID_GET(x) (((x) & VFID_MASK) >> VFID_SHIFT) +#define TNL2TUPENIPV4_S 28 +#define TNL2TUPENIPV4_V(x) ((x) << TNL2TUPENIPV4_S) +#define TNL2TUPENIPV4_F TNL2TUPENIPV4_V(1U) -#define PL_INT_CAUSE 0x1940c -#define ULP_TX 0x08000000U -#define SGE 0x04000000U -#define HMA 0x02000000U -#define CPL_SWITCH 0x01000000U -#define ULP_RX 0x00800000U -#define PM_RX 0x00400000U -#define PM_TX 0x00200000U -#define MA 0x00100000U -#define TP 0x00080000U -#define LE 0x00040000U -#define EDC1 0x00020000U -#define EDC0 0x00010000U -#define MC 0x00008000U -#define PCIE 0x00004000U -#define PMU 0x00002000U -#define XGMAC_KR1 0x00001000U -#define XGMAC_KR0 0x00000800U -#define XGMAC1 0x00000400U -#define XGMAC0 0x00000200U -#define SMB 0x00000100U -#define SF 0x00000080U -#define PL 0x00000040U -#define NCSI 0x00000020U -#define MPS 0x00000010U -#define MI 0x00000008U -#define DBG 0x00000004U -#define I2CM 0x00000002U -#define CIM 0x00000001U +#define TNLTCPSEL_S 27 +#define TNLTCPSEL_V(x) ((x) << TNLTCPSEL_S) +#define TNLTCPSEL_F TNLTCPSEL_V(1U) -#define MC1 0x31 -#define PL_INT_ENABLE 0x19410 -#define PL_INT_MAP0 0x19414 -#define PL_RST 0x19428 -#define PIORST 0x00000002U -#define PIORSTMODE 0x00000001U +#define TNLIP6SEL_S 26 +#define TNLIP6SEL_V(x) ((x) << TNLIP6SEL_S) +#define TNLIP6SEL_F TNLIP6SEL_V(1U) -#define PL_PL_INT_CAUSE 0x19430 -#define FATALPERR 0x00000010U -#define PERRVFID 0x00000001U +#define TNLVRTSEL_S 25 +#define TNLVRTSEL_V(x) ((x) << TNLVRTSEL_S) +#define TNLVRTSEL_F TNLVRTSEL_V(1U) -#define PL_REV 0x1943c +#define TNLMAPEN_S 24 +#define TNLMAPEN_V(x) ((x) << TNLMAPEN_S) +#define TNLMAPEN_F TNLMAPEN_V(1U) -#define S_REV 0 -#define M_REV 0xfU -#define V_REV(x) ((x) << S_REV) -#define G_REV(x) (((x) >> S_REV) & M_REV) +#define OFDHASHSAVE_S 19 +#define OFDHASHSAVE_V(x) ((x) << OFDHASHSAVE_S) +#define OFDHASHSAVE_F OFDHASHSAVE_V(1U) -#define LE_DB_CONFIG 0x19c04 -#define HASHEN 0x00100000U +#define OFDVRTSEL_S 18 +#define OFDVRTSEL_V(x) ((x) << OFDVRTSEL_S) +#define OFDVRTSEL_F OFDVRTSEL_V(1U) -#define LE_DB_SERVER_INDEX 0x19c18 -#define LE_DB_ACT_CNT_IPV4 0x19c20 -#define LE_DB_ACT_CNT_IPV6 0x19c24 +#define OFDMAPEN_S 17 +#define OFDMAPEN_V(x) ((x) << OFDMAPEN_S) +#define OFDMAPEN_F OFDMAPEN_V(1U) -#define LE_DB_INT_CAUSE 0x19c3c -#define REQQPARERR 0x00010000U -#define UNKNOWNCMD 0x00008000U -#define PARITYERR 0x00000040U -#define LIPMISS 0x00000020U -#define LIP0 0x00000010U +#define OFDLKPEN_S 16 +#define OFDLKPEN_V(x) ((x) << OFDLKPEN_S) +#define OFDLKPEN_F OFDLKPEN_V(1U) -#define LE_DB_TID_HASHBASE 0x19df8 +#define SYN4TUPENIPV6_S 15 +#define SYN4TUPENIPV6_V(x) ((x) << SYN4TUPENIPV6_S) +#define SYN4TUPENIPV6_F SYN4TUPENIPV6_V(1U) -#define NCSI_INT_CAUSE 0x1a0d8 -#define CIM_DM_PRTY_ERR 0x00000100U -#define MPS_DM_PRTY_ERR 0x00000080U -#define TXFIFO_PRTY_ERR 0x00000002U -#define RXFIFO_PRTY_ERR 0x00000001U +#define SYN2TUPENIPV6_S 14 +#define SYN2TUPENIPV6_V(x) ((x) << SYN2TUPENIPV6_S) +#define SYN2TUPENIPV6_F SYN2TUPENIPV6_V(1U) -#define XGMAC_PORT_CFG2 0x1018 -#define PATEN 0x00040000U -#define MAGICEN 0x00020000U +#define SYN4TUPENIPV4_S 13 +#define SYN4TUPENIPV4_V(x) ((x) << SYN4TUPENIPV4_S) +#define SYN4TUPENIPV4_F SYN4TUPENIPV4_V(1U) + +#define SYN2TUPENIPV4_S 12 +#define SYN2TUPENIPV4_V(x) ((x) << SYN2TUPENIPV4_S) +#define SYN2TUPENIPV4_F SYN2TUPENIPV4_V(1U) + +#define SYNIP6SEL_S 11 +#define SYNIP6SEL_V(x) ((x) << SYNIP6SEL_S) +#define SYNIP6SEL_F SYNIP6SEL_V(1U) + +#define SYNVRTSEL_S 10 +#define SYNVRTSEL_V(x) ((x) << SYNVRTSEL_S) +#define SYNVRTSEL_F SYNVRTSEL_V(1U) + +#define SYNMAPEN_S 9 +#define SYNMAPEN_V(x) ((x) << SYNMAPEN_S) +#define SYNMAPEN_F SYNMAPEN_V(1U) + +#define SYNLKPEN_S 8 +#define SYNLKPEN_V(x) ((x) << SYNLKPEN_S) +#define SYNLKPEN_F SYNLKPEN_V(1U) + +#define CHANNELENABLE_S 7 +#define CHANNELENABLE_V(x) ((x) << CHANNELENABLE_S) +#define CHANNELENABLE_F CHANNELENABLE_V(1U) + +#define PORTENABLE_S 6 +#define PORTENABLE_V(x) ((x) << PORTENABLE_S) +#define PORTENABLE_F PORTENABLE_V(1U) + +#define TNLALLLOOKUP_S 5 +#define TNLALLLOOKUP_V(x) ((x) << TNLALLLOOKUP_S) +#define TNLALLLOOKUP_F TNLALLLOOKUP_V(1U) + +#define VIRTENABLE_S 4 +#define VIRTENABLE_V(x) ((x) << VIRTENABLE_S) +#define VIRTENABLE_F VIRTENABLE_V(1U) + +#define CONGESTIONENABLE_S 3 +#define CONGESTIONENABLE_V(x) ((x) << CONGESTIONENABLE_S) +#define CONGESTIONENABLE_F CONGESTIONENABLE_V(1U) + +#define HASHTOEPLITZ_S 2 +#define HASHTOEPLITZ_V(x) ((x) << HASHTOEPLITZ_S) +#define HASHTOEPLITZ_F HASHTOEPLITZ_V(1U) + +#define UDPENABLE_S 1 +#define UDPENABLE_V(x) ((x) << UDPENABLE_S) +#define UDPENABLE_F UDPENABLE_V(1U) + +#define DISABLE_S 0 +#define DISABLE_V(x) ((x) << DISABLE_S) +#define DISABLE_F DISABLE_V(1U) + +#define TP_RSS_CONFIG_TNL_A 0x7df4 + +#define MASKSIZE_S 28 +#define MASKSIZE_M 0xfU +#define MASKSIZE_V(x) ((x) << MASKSIZE_S) +#define MASKSIZE_G(x) (((x) >> MASKSIZE_S) & MASKSIZE_M) + +#define MASKFILTER_S 16 +#define MASKFILTER_M 0x7ffU +#define MASKFILTER_V(x) ((x) << MASKFILTER_S) +#define MASKFILTER_G(x) (((x) >> MASKFILTER_S) & MASKFILTER_M) + +#define USEWIRECH_S 0 +#define USEWIRECH_V(x) ((x) << USEWIRECH_S) +#define USEWIRECH_F USEWIRECH_V(1U) + +#define HASHALL_S 2 +#define HASHALL_V(x) ((x) << HASHALL_S) +#define HASHALL_F HASHALL_V(1U) + +#define HASHETH_S 1 +#define HASHETH_V(x) ((x) << HASHETH_S) +#define HASHETH_F HASHETH_V(1U) + +#define TP_RSS_CONFIG_OFD_A 0x7df8 + +#define RRCPLMAPEN_S 20 +#define RRCPLMAPEN_V(x) ((x) << RRCPLMAPEN_S) +#define RRCPLMAPEN_F RRCPLMAPEN_V(1U) + +#define RRCPLQUEWIDTH_S 16 +#define RRCPLQUEWIDTH_M 0xfU +#define RRCPLQUEWIDTH_V(x) ((x) << RRCPLQUEWIDTH_S) +#define RRCPLQUEWIDTH_G(x) (((x) >> RRCPLQUEWIDTH_S) & RRCPLQUEWIDTH_M) + +#define TP_RSS_CONFIG_SYN_A 0x7dfc +#define TP_RSS_CONFIG_VRT_A 0x7e00 + +#define VFRDRG_S 25 +#define VFRDRG_V(x) ((x) << VFRDRG_S) +#define VFRDRG_F VFRDRG_V(1U) + +#define VFRDEN_S 24 +#define VFRDEN_V(x) ((x) << VFRDEN_S) +#define VFRDEN_F VFRDEN_V(1U) + +#define VFPERREN_S 23 +#define VFPERREN_V(x) ((x) << VFPERREN_S) +#define VFPERREN_F VFPERREN_V(1U) + +#define KEYPERREN_S 22 +#define KEYPERREN_V(x) ((x) << KEYPERREN_S) +#define KEYPERREN_F KEYPERREN_V(1U) + +#define DISABLEVLAN_S 21 +#define DISABLEVLAN_V(x) ((x) << DISABLEVLAN_S) +#define DISABLEVLAN_F DISABLEVLAN_V(1U) + +#define ENABLEUP0_S 20 +#define ENABLEUP0_V(x) ((x) << ENABLEUP0_S) +#define ENABLEUP0_F ENABLEUP0_V(1U) + +#define HASHDELAY_S 16 +#define HASHDELAY_M 0xfU +#define HASHDELAY_V(x) ((x) << HASHDELAY_S) +#define HASHDELAY_G(x) (((x) >> HASHDELAY_S) & HASHDELAY_M) + +#define VFWRADDR_S 8 +#define VFWRADDR_M 0x7fU +#define VFWRADDR_V(x) ((x) << VFWRADDR_S) +#define VFWRADDR_G(x) (((x) >> VFWRADDR_S) & VFWRADDR_M) + +#define KEYMODE_S 6 +#define KEYMODE_M 0x3U +#define KEYMODE_V(x) ((x) << KEYMODE_S) +#define KEYMODE_G(x) (((x) >> KEYMODE_S) & KEYMODE_M) + +#define VFWREN_S 5 +#define VFWREN_V(x) ((x) << VFWREN_S) +#define VFWREN_F VFWREN_V(1U) + +#define KEYWREN_S 4 +#define KEYWREN_V(x) ((x) << KEYWREN_S) +#define KEYWREN_F KEYWREN_V(1U) + +#define KEYWRADDR_S 0 +#define KEYWRADDR_M 0xfU +#define KEYWRADDR_V(x) ((x) << KEYWRADDR_S) +#define KEYWRADDR_G(x) (((x) >> KEYWRADDR_S) & KEYWRADDR_M) + +#define KEYWRADDRX_S 30 +#define KEYWRADDRX_M 0x3U +#define KEYWRADDRX_V(x) ((x) << KEYWRADDRX_S) +#define KEYWRADDRX_G(x) (((x) >> KEYWRADDRX_S) & KEYWRADDRX_M) + +#define KEYEXTEND_S 26 +#define KEYEXTEND_V(x) ((x) << KEYEXTEND_S) +#define KEYEXTEND_F KEYEXTEND_V(1U) + +#define LKPIDXSIZE_S 24 +#define LKPIDXSIZE_M 0x3U +#define LKPIDXSIZE_V(x) ((x) << LKPIDXSIZE_S) +#define LKPIDXSIZE_G(x) (((x) >> LKPIDXSIZE_S) & LKPIDXSIZE_M) + +#define TP_RSS_VFL_CONFIG_A 0x3a +#define TP_RSS_VFH_CONFIG_A 0x3b + +#define ENABLEUDPHASH_S 31 +#define ENABLEUDPHASH_V(x) ((x) << ENABLEUDPHASH_S) +#define ENABLEUDPHASH_F ENABLEUDPHASH_V(1U) + +#define VFUPEN_S 30 +#define VFUPEN_V(x) ((x) << VFUPEN_S) +#define VFUPEN_F VFUPEN_V(1U) + +#define VFVLNEX_S 28 +#define VFVLNEX_V(x) ((x) << VFVLNEX_S) +#define VFVLNEX_F VFVLNEX_V(1U) + +#define VFPRTEN_S 27 +#define VFPRTEN_V(x) ((x) << VFPRTEN_S) +#define VFPRTEN_F VFPRTEN_V(1U) + +#define VFCHNEN_S 26 +#define VFCHNEN_V(x) ((x) << VFCHNEN_S) +#define VFCHNEN_F VFCHNEN_V(1U) + +#define DEFAULTQUEUE_S 16 +#define DEFAULTQUEUE_M 0x3ffU +#define DEFAULTQUEUE_G(x) (((x) >> DEFAULTQUEUE_S) & DEFAULTQUEUE_M) + +#define VFIP6TWOTUPEN_S 6 +#define VFIP6TWOTUPEN_V(x) ((x) << VFIP6TWOTUPEN_S) +#define VFIP6TWOTUPEN_F VFIP6TWOTUPEN_V(1U) + +#define VFIP4FOURTUPEN_S 5 +#define VFIP4FOURTUPEN_V(x) ((x) << VFIP4FOURTUPEN_S) +#define VFIP4FOURTUPEN_F VFIP4FOURTUPEN_V(1U) + +#define VFIP4TWOTUPEN_S 4 +#define VFIP4TWOTUPEN_V(x) ((x) << VFIP4TWOTUPEN_S) +#define VFIP4TWOTUPEN_F VFIP4TWOTUPEN_V(1U) + +#define KEYINDEX_S 0 +#define KEYINDEX_M 0xfU +#define KEYINDEX_G(x) (((x) >> KEYINDEX_S) & KEYINDEX_M) + +#define MAPENABLE_S 31 +#define MAPENABLE_V(x) ((x) << MAPENABLE_S) +#define MAPENABLE_F MAPENABLE_V(1U) + +#define CHNENABLE_S 30 +#define CHNENABLE_V(x) ((x) << CHNENABLE_S) +#define CHNENABLE_F CHNENABLE_V(1U) + +#define PRTENABLE_S 29 +#define PRTENABLE_V(x) ((x) << PRTENABLE_S) +#define PRTENABLE_F PRTENABLE_V(1U) + +#define UDPFOURTUPEN_S 28 +#define UDPFOURTUPEN_V(x) ((x) << UDPFOURTUPEN_S) +#define UDPFOURTUPEN_F UDPFOURTUPEN_V(1U) + +#define IP6FOURTUPEN_S 27 +#define IP6FOURTUPEN_V(x) ((x) << IP6FOURTUPEN_S) +#define IP6FOURTUPEN_F IP6FOURTUPEN_V(1U) + +#define IP6TWOTUPEN_S 26 +#define IP6TWOTUPEN_V(x) ((x) << IP6TWOTUPEN_S) +#define IP6TWOTUPEN_F IP6TWOTUPEN_V(1U) + +#define IP4FOURTUPEN_S 25 +#define IP4FOURTUPEN_V(x) ((x) << IP4FOURTUPEN_S) +#define IP4FOURTUPEN_F IP4FOURTUPEN_V(1U) + +#define IP4TWOTUPEN_S 24 +#define IP4TWOTUPEN_V(x) ((x) << IP4TWOTUPEN_S) +#define IP4TWOTUPEN_F IP4TWOTUPEN_V(1U) + +#define IVFWIDTH_S 20 +#define IVFWIDTH_M 0xfU +#define IVFWIDTH_V(x) ((x) << IVFWIDTH_S) +#define IVFWIDTH_G(x) (((x) >> IVFWIDTH_S) & IVFWIDTH_M) + +#define CH1DEFAULTQUEUE_S 10 +#define CH1DEFAULTQUEUE_M 0x3ffU +#define CH1DEFAULTQUEUE_V(x) ((x) << CH1DEFAULTQUEUE_S) +#define CH1DEFAULTQUEUE_G(x) (((x) >> CH1DEFAULTQUEUE_S) & CH1DEFAULTQUEUE_M) + +#define CH0DEFAULTQUEUE_S 0 +#define CH0DEFAULTQUEUE_M 0x3ffU +#define CH0DEFAULTQUEUE_V(x) ((x) << CH0DEFAULTQUEUE_S) +#define CH0DEFAULTQUEUE_G(x) (((x) >> CH0DEFAULTQUEUE_S) & CH0DEFAULTQUEUE_M) + +#define VFLKPIDX_S 8 +#define VFLKPIDX_M 0xffU +#define VFLKPIDX_G(x) (((x) >> VFLKPIDX_S) & VFLKPIDX_M) + +#define TP_RSS_CONFIG_CNG_A 0x7e04 +#define TP_RSS_SECRET_KEY0_A 0x40 +#define TP_RSS_PF0_CONFIG_A 0x30 +#define TP_RSS_PF_MAP_A 0x38 +#define TP_RSS_PF_MSK_A 0x39 + +#define PF1LKPIDX_S 3 + +#define PF0LKPIDX_M 0x7U + +#define PF1MSKSIZE_S 4 +#define PF1MSKSIZE_M 0xfU + +#define CHNCOUNT3_S 31 +#define CHNCOUNT3_V(x) ((x) << CHNCOUNT3_S) +#define CHNCOUNT3_F CHNCOUNT3_V(1U) + +#define CHNCOUNT2_S 30 +#define CHNCOUNT2_V(x) ((x) << CHNCOUNT2_S) +#define CHNCOUNT2_F CHNCOUNT2_V(1U) + +#define CHNCOUNT1_S 29 +#define CHNCOUNT1_V(x) ((x) << CHNCOUNT1_S) +#define CHNCOUNT1_F CHNCOUNT1_V(1U) + +#define CHNCOUNT0_S 28 +#define CHNCOUNT0_V(x) ((x) << CHNCOUNT0_S) +#define CHNCOUNT0_F CHNCOUNT0_V(1U) + +#define CHNUNDFLOW3_S 27 +#define CHNUNDFLOW3_V(x) ((x) << CHNUNDFLOW3_S) +#define CHNUNDFLOW3_F CHNUNDFLOW3_V(1U) + +#define CHNUNDFLOW2_S 26 +#define CHNUNDFLOW2_V(x) ((x) << CHNUNDFLOW2_S) +#define CHNUNDFLOW2_F CHNUNDFLOW2_V(1U) + +#define CHNUNDFLOW1_S 25 +#define CHNUNDFLOW1_V(x) ((x) << CHNUNDFLOW1_S) +#define CHNUNDFLOW1_F CHNUNDFLOW1_V(1U) + +#define CHNUNDFLOW0_S 24 +#define CHNUNDFLOW0_V(x) ((x) << CHNUNDFLOW0_S) +#define CHNUNDFLOW0_F CHNUNDFLOW0_V(1U) + +#define RSTCHN3_S 19 +#define RSTCHN3_V(x) ((x) << RSTCHN3_S) +#define RSTCHN3_F RSTCHN3_V(1U) + +#define RSTCHN2_S 18 +#define RSTCHN2_V(x) ((x) << RSTCHN2_S) +#define RSTCHN2_F RSTCHN2_V(1U) + +#define RSTCHN1_S 17 +#define RSTCHN1_V(x) ((x) << RSTCHN1_S) +#define RSTCHN1_F RSTCHN1_V(1U) + +#define RSTCHN0_S 16 +#define RSTCHN0_V(x) ((x) << RSTCHN0_S) +#define RSTCHN0_F RSTCHN0_V(1U) + +#define UPDVLD_S 15 +#define UPDVLD_V(x) ((x) << UPDVLD_S) +#define UPDVLD_F UPDVLD_V(1U) + +#define XOFF_S 14 +#define XOFF_V(x) ((x) << XOFF_S) +#define XOFF_F XOFF_V(1U) + +#define UPDCHN3_S 13 +#define UPDCHN3_V(x) ((x) << UPDCHN3_S) +#define UPDCHN3_F UPDCHN3_V(1U) + +#define UPDCHN2_S 12 +#define UPDCHN2_V(x) ((x) << UPDCHN2_S) +#define UPDCHN2_F UPDCHN2_V(1U) + +#define UPDCHN1_S 11 +#define UPDCHN1_V(x) ((x) << UPDCHN1_S) +#define UPDCHN1_F UPDCHN1_V(1U) + +#define UPDCHN0_S 10 +#define UPDCHN0_V(x) ((x) << UPDCHN0_S) +#define UPDCHN0_F UPDCHN0_V(1U) + +#define QUEUE_S 0 +#define QUEUE_M 0x3ffU +#define QUEUE_V(x) ((x) << QUEUE_S) +#define QUEUE_G(x) (((x) >> QUEUE_S) & QUEUE_M) + +#define MPS_TRC_INT_CAUSE_A 0x985c + +#define MISCPERR_S 8 +#define MISCPERR_V(x) ((x) << MISCPERR_S) +#define MISCPERR_F MISCPERR_V(1U) + +#define PKTFIFO_S 4 +#define PKTFIFO_M 0xfU +#define PKTFIFO_V(x) ((x) << PKTFIFO_S) + +#define FILTMEM_S 0 +#define FILTMEM_M 0xfU +#define FILTMEM_V(x) ((x) << FILTMEM_S) + +#define MPS_CLS_INT_CAUSE_A 0xd028 + +#define HASHSRAM_S 2 +#define HASHSRAM_V(x) ((x) << HASHSRAM_S) +#define HASHSRAM_F HASHSRAM_V(1U) + +#define MATCHTCAM_S 1 +#define MATCHTCAM_V(x) ((x) << MATCHTCAM_S) +#define MATCHTCAM_F MATCHTCAM_V(1U) + +#define MATCHSRAM_S 0 +#define MATCHSRAM_V(x) ((x) << MATCHSRAM_S) +#define MATCHSRAM_F MATCHSRAM_V(1U) + +#define MPS_RX_PERR_INT_CAUSE_A 0x11074 + +#define MPS_CLS_TCAM_Y_L_A 0xf000 +#define MPS_CLS_TCAM_X_L_A 0xf008 + +#define MPS_CLS_TCAM_Y_L(idx) (MPS_CLS_TCAM_Y_L_A + (idx) * 16) +#define NUM_MPS_CLS_TCAM_Y_L_INSTANCES 512 + +#define MPS_CLS_TCAM_X_L(idx) (MPS_CLS_TCAM_X_L_A + (idx) * 16) +#define NUM_MPS_CLS_TCAM_X_L_INSTANCES 512 + +#define MPS_CLS_SRAM_L_A 0xe000 +#define MPS_CLS_SRAM_H_A 0xe004 + +#define MPS_CLS_SRAM_L(idx) (MPS_CLS_SRAM_L_A + (idx) * 8) +#define NUM_MPS_CLS_SRAM_L_INSTANCES 336 + +#define MPS_CLS_SRAM_H(idx) (MPS_CLS_SRAM_H_A + (idx) * 8) +#define NUM_MPS_CLS_SRAM_H_INSTANCES 336 + +#define MULTILISTEN0_S 25 + +#define REPLICATE_S 11 +#define REPLICATE_V(x) ((x) << REPLICATE_S) +#define REPLICATE_F REPLICATE_V(1U) + +#define PF_S 8 +#define PF_M 0x7U +#define PF_G(x) (((x) >> PF_S) & PF_M) + +#define VF_VALID_S 7 +#define VF_VALID_V(x) ((x) << VF_VALID_S) +#define VF_VALID_F VF_VALID_V(1U) + +#define VF_S 0 +#define VF_M 0x7fU +#define VF_G(x) (((x) >> VF_S) & VF_M) + +#define SRAM_PRIO3_S 22 +#define SRAM_PRIO3_M 0x7U +#define SRAM_PRIO3_G(x) (((x) >> SRAM_PRIO3_S) & SRAM_PRIO3_M) + +#define SRAM_PRIO2_S 19 +#define SRAM_PRIO2_M 0x7U +#define SRAM_PRIO2_G(x) (((x) >> SRAM_PRIO2_S) & SRAM_PRIO2_M) + +#define SRAM_PRIO1_S 16 +#define SRAM_PRIO1_M 0x7U +#define SRAM_PRIO1_G(x) (((x) >> SRAM_PRIO1_S) & SRAM_PRIO1_M) + +#define SRAM_PRIO0_S 13 +#define SRAM_PRIO0_M 0x7U +#define SRAM_PRIO0_G(x) (((x) >> SRAM_PRIO0_S) & SRAM_PRIO0_M) + +#define SRAM_VLD_S 12 +#define SRAM_VLD_V(x) ((x) << SRAM_VLD_S) +#define SRAM_VLD_F SRAM_VLD_V(1U) + +#define PORTMAP_S 0 +#define PORTMAP_M 0xfU +#define PORTMAP_G(x) (((x) >> PORTMAP_S) & PORTMAP_M) + +#define CPL_INTR_CAUSE_A 0x19054 + +#define CIM_OP_MAP_PERR_S 5 +#define CIM_OP_MAP_PERR_V(x) ((x) << CIM_OP_MAP_PERR_S) +#define CIM_OP_MAP_PERR_F CIM_OP_MAP_PERR_V(1U) + +#define CIM_OVFL_ERROR_S 4 +#define CIM_OVFL_ERROR_V(x) ((x) << CIM_OVFL_ERROR_S) +#define CIM_OVFL_ERROR_F CIM_OVFL_ERROR_V(1U) + +#define TP_FRAMING_ERROR_S 3 +#define TP_FRAMING_ERROR_V(x) ((x) << TP_FRAMING_ERROR_S) +#define TP_FRAMING_ERROR_F TP_FRAMING_ERROR_V(1U) + +#define SGE_FRAMING_ERROR_S 2 +#define SGE_FRAMING_ERROR_V(x) ((x) << SGE_FRAMING_ERROR_S) +#define SGE_FRAMING_ERROR_F SGE_FRAMING_ERROR_V(1U) + +#define CIM_FRAMING_ERROR_S 1 +#define CIM_FRAMING_ERROR_V(x) ((x) << CIM_FRAMING_ERROR_S) +#define CIM_FRAMING_ERROR_F CIM_FRAMING_ERROR_V(1U) + +#define ZERO_SWITCH_ERROR_S 0 +#define ZERO_SWITCH_ERROR_V(x) ((x) << ZERO_SWITCH_ERROR_S) +#define ZERO_SWITCH_ERROR_F ZERO_SWITCH_ERROR_V(1U) + +#define SMB_INT_CAUSE_A 0x19090 + +#define MSTTXFIFOPARINT_S 21 +#define MSTTXFIFOPARINT_V(x) ((x) << MSTTXFIFOPARINT_S) +#define MSTTXFIFOPARINT_F MSTTXFIFOPARINT_V(1U) + +#define MSTRXFIFOPARINT_S 20 +#define MSTRXFIFOPARINT_V(x) ((x) << MSTRXFIFOPARINT_S) +#define MSTRXFIFOPARINT_F MSTRXFIFOPARINT_V(1U) + +#define SLVFIFOPARINT_S 19 +#define SLVFIFOPARINT_V(x) ((x) << SLVFIFOPARINT_S) +#define SLVFIFOPARINT_F SLVFIFOPARINT_V(1U) + +#define ULP_RX_INT_CAUSE_A 0x19158 +#define ULP_RX_ISCSI_TAGMASK_A 0x19164 +#define ULP_RX_ISCSI_PSZ_A 0x19168 +#define ULP_RX_LA_CTL_A 0x1923c +#define ULP_RX_LA_RDPTR_A 0x19240 +#define ULP_RX_LA_RDDATA_A 0x19244 +#define ULP_RX_LA_WRPTR_A 0x19248 + +#define HPZ3_S 24 +#define HPZ3_V(x) ((x) << HPZ3_S) + +#define HPZ2_S 16 +#define HPZ2_V(x) ((x) << HPZ2_S) + +#define HPZ1_S 8 +#define HPZ1_V(x) ((x) << HPZ1_S) + +#define HPZ0_S 0 +#define HPZ0_V(x) ((x) << HPZ0_S) + +#define ULP_RX_TDDP_PSZ_A 0x19178 + +/* registers for module SF */ +#define SF_DATA_A 0x193f8 +#define SF_OP_A 0x193fc + +#define SF_BUSY_S 31 +#define SF_BUSY_V(x) ((x) << SF_BUSY_S) +#define SF_BUSY_F SF_BUSY_V(1U) + +#define SF_LOCK_S 4 +#define SF_LOCK_V(x) ((x) << SF_LOCK_S) +#define SF_LOCK_F SF_LOCK_V(1U) + +#define SF_CONT_S 3 +#define SF_CONT_V(x) ((x) << SF_CONT_S) +#define SF_CONT_F SF_CONT_V(1U) + +#define BYTECNT_S 1 +#define BYTECNT_V(x) ((x) << BYTECNT_S) + +#define OP_S 0 +#define OP_V(x) ((x) << OP_S) +#define OP_F OP_V(1U) + +#define PL_PF_INT_CAUSE_A 0x3c0 + +#define PFSW_S 3 +#define PFSW_V(x) ((x) << PFSW_S) +#define PFSW_F PFSW_V(1U) + +#define PFCIM_S 1 +#define PFCIM_V(x) ((x) << PFCIM_S) +#define PFCIM_F PFCIM_V(1U) + +#define PL_PF_INT_ENABLE_A 0x3c4 +#define PL_PF_CTL_A 0x3c8 + +#define PL_WHOAMI_A 0x19400 + +#define SOURCEPF_S 8 +#define SOURCEPF_M 0x7U +#define SOURCEPF_G(x) (((x) >> SOURCEPF_S) & SOURCEPF_M) + +#define PL_INT_CAUSE_A 0x1940c + +#define ULP_TX_S 27 +#define ULP_TX_V(x) ((x) << ULP_TX_S) +#define ULP_TX_F ULP_TX_V(1U) + +#define SGE_S 26 +#define SGE_V(x) ((x) << SGE_S) +#define SGE_F SGE_V(1U) + +#define CPL_SWITCH_S 24 +#define CPL_SWITCH_V(x) ((x) << CPL_SWITCH_S) +#define CPL_SWITCH_F CPL_SWITCH_V(1U) + +#define ULP_RX_S 23 +#define ULP_RX_V(x) ((x) << ULP_RX_S) +#define ULP_RX_F ULP_RX_V(1U) + +#define PM_RX_S 22 +#define PM_RX_V(x) ((x) << PM_RX_S) +#define PM_RX_F PM_RX_V(1U) + +#define PM_TX_S 21 +#define PM_TX_V(x) ((x) << PM_TX_S) +#define PM_TX_F PM_TX_V(1U) + +#define MA_S 20 +#define MA_V(x) ((x) << MA_S) +#define MA_F MA_V(1U) + +#define TP_S 19 +#define TP_V(x) ((x) << TP_S) +#define TP_F TP_V(1U) + +#define LE_S 18 +#define LE_V(x) ((x) << LE_S) +#define LE_F LE_V(1U) + +#define EDC1_S 17 +#define EDC1_V(x) ((x) << EDC1_S) +#define EDC1_F EDC1_V(1U) + +#define EDC0_S 16 +#define EDC0_V(x) ((x) << EDC0_S) +#define EDC0_F EDC0_V(1U) + +#define MC_S 15 +#define MC_V(x) ((x) << MC_S) +#define MC_F MC_V(1U) + +#define PCIE_S 14 +#define PCIE_V(x) ((x) << PCIE_S) +#define PCIE_F PCIE_V(1U) + +#define XGMAC_KR1_S 12 +#define XGMAC_KR1_V(x) ((x) << XGMAC_KR1_S) +#define XGMAC_KR1_F XGMAC_KR1_V(1U) + +#define XGMAC_KR0_S 11 +#define XGMAC_KR0_V(x) ((x) << XGMAC_KR0_S) +#define XGMAC_KR0_F XGMAC_KR0_V(1U) + +#define XGMAC1_S 10 +#define XGMAC1_V(x) ((x) << XGMAC1_S) +#define XGMAC1_F XGMAC1_V(1U) + +#define XGMAC0_S 9 +#define XGMAC0_V(x) ((x) << XGMAC0_S) +#define XGMAC0_F XGMAC0_V(1U) + +#define SMB_S 8 +#define SMB_V(x) ((x) << SMB_S) +#define SMB_F SMB_V(1U) + +#define SF_S 7 +#define SF_V(x) ((x) << SF_S) +#define SF_F SF_V(1U) + +#define PL_S 6 +#define PL_V(x) ((x) << PL_S) +#define PL_F PL_V(1U) + +#define NCSI_S 5 +#define NCSI_V(x) ((x) << NCSI_S) +#define NCSI_F NCSI_V(1U) + +#define MPS_S 4 +#define MPS_V(x) ((x) << MPS_S) +#define MPS_F MPS_V(1U) + +#define CIM_S 0 +#define CIM_V(x) ((x) << CIM_S) +#define CIM_F CIM_V(1U) + +#define MC1_S 31 + +#define PL_INT_ENABLE_A 0x19410 +#define PL_INT_MAP0_A 0x19414 +#define PL_RST_A 0x19428 + +#define PIORST_S 1 +#define PIORST_V(x) ((x) << PIORST_S) +#define PIORST_F PIORST_V(1U) + +#define PIORSTMODE_S 0 +#define PIORSTMODE_V(x) ((x) << PIORSTMODE_S) +#define PIORSTMODE_F PIORSTMODE_V(1U) + +#define PL_PL_INT_CAUSE_A 0x19430 + +#define FATALPERR_S 4 +#define FATALPERR_V(x) ((x) << FATALPERR_S) +#define FATALPERR_F FATALPERR_V(1U) + +#define PERRVFID_S 0 +#define PERRVFID_V(x) ((x) << PERRVFID_S) +#define PERRVFID_F PERRVFID_V(1U) + +#define PL_REV_A 0x1943c + +#define REV_S 0 +#define REV_M 0xfU +#define REV_V(x) ((x) << REV_S) +#define REV_G(x) (((x) >> REV_S) & REV_M) + +#define LE_DB_INT_CAUSE_A 0x19c3c + +#define REQQPARERR_S 16 +#define REQQPARERR_V(x) ((x) << REQQPARERR_S) +#define REQQPARERR_F REQQPARERR_V(1U) + +#define UNKNOWNCMD_S 15 +#define UNKNOWNCMD_V(x) ((x) << UNKNOWNCMD_S) +#define UNKNOWNCMD_F UNKNOWNCMD_V(1U) + +#define PARITYERR_S 6 +#define PARITYERR_V(x) ((x) << PARITYERR_S) +#define PARITYERR_F PARITYERR_V(1U) + +#define LIPMISS_S 5 +#define LIPMISS_V(x) ((x) << LIPMISS_S) +#define LIPMISS_F LIPMISS_V(1U) + +#define LIP0_S 4 +#define LIP0_V(x) ((x) << LIP0_S) +#define LIP0_F LIP0_V(1U) + +#define NCSI_INT_CAUSE_A 0x1a0d8 + +#define CIM_DM_PRTY_ERR_S 8 +#define CIM_DM_PRTY_ERR_V(x) ((x) << CIM_DM_PRTY_ERR_S) +#define CIM_DM_PRTY_ERR_F CIM_DM_PRTY_ERR_V(1U) + +#define MPS_DM_PRTY_ERR_S 7 +#define MPS_DM_PRTY_ERR_V(x) ((x) << MPS_DM_PRTY_ERR_S) +#define MPS_DM_PRTY_ERR_F MPS_DM_PRTY_ERR_V(1U) + +#define TXFIFO_PRTY_ERR_S 1 +#define TXFIFO_PRTY_ERR_V(x) ((x) << TXFIFO_PRTY_ERR_S) +#define TXFIFO_PRTY_ERR_F TXFIFO_PRTY_ERR_V(1U) + +#define RXFIFO_PRTY_ERR_S 0 +#define RXFIFO_PRTY_ERR_V(x) ((x) << RXFIFO_PRTY_ERR_S) +#define RXFIFO_PRTY_ERR_F RXFIFO_PRTY_ERR_V(1U) + +#define XGMAC_PORT_CFG2_A 0x1018 + +#define PATEN_S 18 +#define PATEN_V(x) ((x) << PATEN_S) +#define PATEN_F PATEN_V(1U) + +#define MAGICEN_S 17 +#define MAGICEN_V(x) ((x) << MAGICEN_S) +#define MAGICEN_F MAGICEN_V(1U) #define XGMAC_PORT_MAGIC_MACID_LO 0x1024 #define XGMAC_PORT_MAGIC_MACID_HI 0x1028 -#define XGMAC_PORT_EPIO_DATA0 0x10c0 -#define XGMAC_PORT_EPIO_DATA1 0x10c4 -#define XGMAC_PORT_EPIO_DATA2 0x10c8 -#define XGMAC_PORT_EPIO_DATA3 0x10cc -#define XGMAC_PORT_EPIO_OP 0x10d0 -#define EPIOWR 0x00000100U -#define ADDRESS_MASK 0x000000ffU -#define ADDRESS_SHIFT 0 -#define ADDRESS(x) ((x) << ADDRESS_SHIFT) +#define XGMAC_PORT_EPIO_DATA0_A 0x10c0 +#define XGMAC_PORT_EPIO_DATA1_A 0x10c4 +#define XGMAC_PORT_EPIO_DATA2_A 0x10c8 +#define XGMAC_PORT_EPIO_DATA3_A 0x10cc +#define XGMAC_PORT_EPIO_OP_A 0x10d0 -#define MAC_PORT_INT_CAUSE 0x8dc -#define XGMAC_PORT_INT_CAUSE 0x10dc +#define EPIOWR_S 8 +#define EPIOWR_V(x) ((x) << EPIOWR_S) +#define EPIOWR_F EPIOWR_V(1U) -#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x7e28 +#define ADDRESS_S 0 +#define ADDRESS_V(x) ((x) << ADDRESS_S) -#define A_TP_TX_MOD_CHANNEL_WEIGHT 0x7e34 +#define MAC_PORT_INT_CAUSE_A 0x8dc +#define XGMAC_PORT_INT_CAUSE_A 0x10dc -#define S_TX_MOD_QUEUE_REQ_MAP 0 -#define M_TX_MOD_QUEUE_REQ_MAP 0xffffU -#define V_TX_MOD_QUEUE_REQ_MAP(x) ((x) << S_TX_MOD_QUEUE_REQ_MAP) +#define TP_TX_MOD_QUEUE_REQ_MAP_A 0x7e28 -#define A_TP_TX_MOD_QUEUE_WEIGHT0 0x7e30 +#define TP_TX_MOD_QUEUE_WEIGHT0_A 0x7e30 +#define TP_TX_MOD_CHANNEL_WEIGHT_A 0x7e34 -#define S_TX_MODQ_WEIGHT3 24 -#define M_TX_MODQ_WEIGHT3 0xffU -#define V_TX_MODQ_WEIGHT3(x) ((x) << S_TX_MODQ_WEIGHT3) +#define TX_MOD_QUEUE_REQ_MAP_S 0 +#define TX_MOD_QUEUE_REQ_MAP_V(x) ((x) << TX_MOD_QUEUE_REQ_MAP_S) -#define S_TX_MODQ_WEIGHT2 16 -#define M_TX_MODQ_WEIGHT2 0xffU -#define V_TX_MODQ_WEIGHT2(x) ((x) << S_TX_MODQ_WEIGHT2) +#define TX_MODQ_WEIGHT3_S 24 +#define TX_MODQ_WEIGHT3_V(x) ((x) << TX_MODQ_WEIGHT3_S) -#define S_TX_MODQ_WEIGHT1 8 -#define M_TX_MODQ_WEIGHT1 0xffU -#define V_TX_MODQ_WEIGHT1(x) ((x) << S_TX_MODQ_WEIGHT1) +#define TX_MODQ_WEIGHT2_S 16 +#define TX_MODQ_WEIGHT2_V(x) ((x) << TX_MODQ_WEIGHT2_S) -#define S_TX_MODQ_WEIGHT0 0 -#define M_TX_MODQ_WEIGHT0 0xffU -#define V_TX_MODQ_WEIGHT0(x) ((x) << S_TX_MODQ_WEIGHT0) +#define TX_MODQ_WEIGHT1_S 8 +#define TX_MODQ_WEIGHT1_V(x) ((x) << TX_MODQ_WEIGHT1_S) -#define A_TP_TX_SCHED_HDR 0x23 +#define TX_MODQ_WEIGHT0_S 0 +#define TX_MODQ_WEIGHT0_V(x) ((x) << TX_MODQ_WEIGHT0_S) -#define A_TP_TX_SCHED_FIFO 0x24 - -#define A_TP_TX_SCHED_PCMD 0x25 - -#define S_VNIC 11 -#define V_VNIC(x) ((x) << S_VNIC) -#define F_VNIC V_VNIC(1U) - -#define S_FRAGMENTATION 9 -#define V_FRAGMENTATION(x) ((x) << S_FRAGMENTATION) -#define F_FRAGMENTATION V_FRAGMENTATION(1U) - -#define S_MPSHITTYPE 8 -#define V_MPSHITTYPE(x) ((x) << S_MPSHITTYPE) -#define F_MPSHITTYPE V_MPSHITTYPE(1U) - -#define S_MACMATCH 7 -#define V_MACMATCH(x) ((x) << S_MACMATCH) -#define F_MACMATCH V_MACMATCH(1U) - -#define S_ETHERTYPE 6 -#define V_ETHERTYPE(x) ((x) << S_ETHERTYPE) -#define F_ETHERTYPE V_ETHERTYPE(1U) - -#define S_PROTOCOL 5 -#define V_PROTOCOL(x) ((x) << S_PROTOCOL) -#define F_PROTOCOL V_PROTOCOL(1U) - -#define S_TOS 4 -#define V_TOS(x) ((x) << S_TOS) -#define F_TOS V_TOS(1U) - -#define S_VLAN 3 -#define V_VLAN(x) ((x) << S_VLAN) -#define F_VLAN V_VLAN(1U) - -#define S_VNIC_ID 2 -#define V_VNIC_ID(x) ((x) << S_VNIC_ID) -#define F_VNIC_ID V_VNIC_ID(1U) - -#define S_PORT 1 -#define V_PORT(x) ((x) << S_PORT) -#define F_PORT V_PORT(1U) - -#define S_FCOE 0 -#define V_FCOE(x) ((x) << S_FCOE) -#define F_FCOE V_FCOE(1U) +#define TP_TX_SCHED_HDR_A 0x23 +#define TP_TX_SCHED_FIFO_A 0x24 +#define TP_TX_SCHED_PCMD_A 0x25 #define NUM_MPS_CLS_SRAM_L_INSTANCES 336 #define NUM_MPS_T5_CLS_SRAM_L_INSTANCES 512 @@ -1329,62 +2566,149 @@ #define MC_STRIDE (MC_1_BASE_ADDR - MC_0_BASE_ADDR) #define MC_REG(reg, idx) (reg + MC_STRIDE * idx) -#define MC_P_BIST_CMD 0x41400 -#define MC_P_BIST_CMD_ADDR 0x41404 -#define MC_P_BIST_CMD_LEN 0x41408 -#define MC_P_BIST_DATA_PATTERN 0x4140c -#define MC_P_BIST_STATUS_RDATA 0x41488 -#define EDC_T50_BASE_ADDR 0x50000 -#define EDC_H_BIST_CMD 0x50004 -#define EDC_H_BIST_CMD_ADDR 0x50008 -#define EDC_H_BIST_CMD_LEN 0x5000c -#define EDC_H_BIST_DATA_PATTERN 0x50010 -#define EDC_H_BIST_STATUS_RDATA 0x50028 +#define MC_P_BIST_CMD_A 0x41400 +#define MC_P_BIST_CMD_ADDR_A 0x41404 +#define MC_P_BIST_CMD_LEN_A 0x41408 +#define MC_P_BIST_DATA_PATTERN_A 0x4140c +#define MC_P_BIST_STATUS_RDATA_A 0x41488 + +#define EDC_T50_BASE_ADDR 0x50000 + +#define EDC_H_BIST_CMD_A 0x50004 +#define EDC_H_BIST_CMD_ADDR_A 0x50008 +#define EDC_H_BIST_CMD_LEN_A 0x5000c +#define EDC_H_BIST_DATA_PATTERN_A 0x50010 +#define EDC_H_BIST_STATUS_RDATA_A 0x50028 + +#define EDC_T51_BASE_ADDR 0x50800 -#define EDC_T51_BASE_ADDR 0x50800 #define EDC_STRIDE_T5 (EDC_T51_BASE_ADDR - EDC_T50_BASE_ADDR) #define EDC_REG_T5(reg, idx) (reg + EDC_STRIDE_T5 * idx) -#define A_PL_VF_REV 0x4 -#define A_PL_VF_WHOAMI 0x0 -#define A_PL_VF_REVISION 0x8 +#define PL_VF_REV_A 0x4 +#define PL_VF_WHOAMI_A 0x0 +#define PL_VF_REVISION_A 0x8 -#define S_CHIPID 4 -#define M_CHIPID 0xfU -#define V_CHIPID(x) ((x) << S_CHIPID) -#define G_CHIPID(x) (((x) >> S_CHIPID) & M_CHIPID) +/* registers for module CIM */ +#define CIM_HOST_ACC_CTRL_A 0x7b50 +#define CIM_HOST_ACC_DATA_A 0x7b54 +#define UP_UP_DBG_LA_CFG_A 0x140 +#define UP_UP_DBG_LA_DATA_A 0x144 -/* TP_VLAN_PRI_MAP controls which subset of fields will be present in the - * Compressed Filter Tuple for LE filters. Each bit set in TP_VLAN_PRI_MAP - * selects for a particular field being present. These fields, when present - * in the Compressed Filter Tuple, have the following widths in bits. - */ -#define W_FT_FCOE 1 -#define W_FT_PORT 3 -#define W_FT_VNIC_ID 17 -#define W_FT_VLAN 17 -#define W_FT_TOS 8 -#define W_FT_PROTOCOL 8 -#define W_FT_ETHERTYPE 16 -#define W_FT_MACMATCH 9 -#define W_FT_MPSHITTYPE 3 -#define W_FT_FRAGMENTATION 1 +#define HOSTBUSY_S 17 +#define HOSTBUSY_V(x) ((x) << HOSTBUSY_S) +#define HOSTBUSY_F HOSTBUSY_V(1U) -/* Some of the Compressed Filter Tuple fields have internal structure. These - * bit shifts/masks describe those structures. All shifts are relative to the - * base position of the fields within the Compressed Filter Tuple - */ -#define S_FT_VLAN_VLD 16 -#define V_FT_VLAN_VLD(x) ((x) << S_FT_VLAN_VLD) -#define F_FT_VLAN_VLD V_FT_VLAN_VLD(1U) +#define HOSTWRITE_S 16 +#define HOSTWRITE_V(x) ((x) << HOSTWRITE_S) +#define HOSTWRITE_F HOSTWRITE_V(1U) -#define S_FT_VNID_ID_VF 0 -#define V_FT_VNID_ID_VF(x) ((x) << S_FT_VNID_ID_VF) +#define CIM_IBQ_DBG_CFG_A 0x7b60 -#define S_FT_VNID_ID_PF 7 -#define V_FT_VNID_ID_PF(x) ((x) << S_FT_VNID_ID_PF) +#define IBQDBGADDR_S 16 +#define IBQDBGADDR_M 0xfffU +#define IBQDBGADDR_V(x) ((x) << IBQDBGADDR_S) +#define IBQDBGADDR_G(x) (((x) >> IBQDBGADDR_S) & IBQDBGADDR_M) -#define S_FT_VNID_ID_VLD 16 -#define V_FT_VNID_ID_VLD(x) ((x) << S_FT_VNID_ID_VLD) +#define IBQDBGBUSY_S 1 +#define IBQDBGBUSY_V(x) ((x) << IBQDBGBUSY_S) +#define IBQDBGBUSY_F IBQDBGBUSY_V(1U) + +#define IBQDBGEN_S 0 +#define IBQDBGEN_V(x) ((x) << IBQDBGEN_S) +#define IBQDBGEN_F IBQDBGEN_V(1U) + +#define CIM_OBQ_DBG_CFG_A 0x7b64 + +#define OBQDBGADDR_S 16 +#define OBQDBGADDR_M 0xfffU +#define OBQDBGADDR_V(x) ((x) << OBQDBGADDR_S) +#define OBQDBGADDR_G(x) (((x) >> OBQDBGADDR_S) & OBQDBGADDR_M) + +#define OBQDBGBUSY_S 1 +#define OBQDBGBUSY_V(x) ((x) << OBQDBGBUSY_S) +#define OBQDBGBUSY_F OBQDBGBUSY_V(1U) + +#define OBQDBGEN_S 0 +#define OBQDBGEN_V(x) ((x) << OBQDBGEN_S) +#define OBQDBGEN_F OBQDBGEN_V(1U) + +#define CIM_IBQ_DBG_DATA_A 0x7b68 +#define CIM_OBQ_DBG_DATA_A 0x7b6c + +#define UPDBGLARDEN_S 1 +#define UPDBGLARDEN_V(x) ((x) << UPDBGLARDEN_S) +#define UPDBGLARDEN_F UPDBGLARDEN_V(1U) + +#define UPDBGLAEN_S 0 +#define UPDBGLAEN_V(x) ((x) << UPDBGLAEN_S) +#define UPDBGLAEN_F UPDBGLAEN_V(1U) + +#define UPDBGLARDPTR_S 2 +#define UPDBGLARDPTR_M 0xfffU +#define UPDBGLARDPTR_V(x) ((x) << UPDBGLARDPTR_S) + +#define UPDBGLAWRPTR_S 16 +#define UPDBGLAWRPTR_M 0xfffU +#define UPDBGLAWRPTR_G(x) (((x) >> UPDBGLAWRPTR_S) & UPDBGLAWRPTR_M) + +#define UPDBGLACAPTPCONLY_S 30 +#define UPDBGLACAPTPCONLY_V(x) ((x) << UPDBGLACAPTPCONLY_S) +#define UPDBGLACAPTPCONLY_F UPDBGLACAPTPCONLY_V(1U) + +#define CIM_QUEUE_CONFIG_REF_A 0x7b48 +#define CIM_QUEUE_CONFIG_CTRL_A 0x7b4c + +#define CIMQSIZE_S 24 +#define CIMQSIZE_M 0x3fU +#define CIMQSIZE_G(x) (((x) >> CIMQSIZE_S) & CIMQSIZE_M) + +#define CIMQBASE_S 16 +#define CIMQBASE_M 0x3fU +#define CIMQBASE_G(x) (((x) >> CIMQBASE_S) & CIMQBASE_M) + +#define QUEFULLTHRSH_S 0 +#define QUEFULLTHRSH_M 0x1ffU +#define QUEFULLTHRSH_G(x) (((x) >> QUEFULLTHRSH_S) & QUEFULLTHRSH_M) + +#define UP_IBQ_0_RDADDR_A 0x10 +#define UP_IBQ_0_SHADOW_RDADDR_A 0x280 +#define UP_OBQ_0_REALADDR_A 0x104 +#define UP_OBQ_0_SHADOW_REALADDR_A 0x394 + +#define IBQRDADDR_S 0 +#define IBQRDADDR_M 0x1fffU +#define IBQRDADDR_G(x) (((x) >> IBQRDADDR_S) & IBQRDADDR_M) + +#define IBQWRADDR_S 0 +#define IBQWRADDR_M 0x1fffU +#define IBQWRADDR_G(x) (((x) >> IBQWRADDR_S) & IBQWRADDR_M) + +#define QUERDADDR_S 0 +#define QUERDADDR_M 0x7fffU +#define QUERDADDR_G(x) (((x) >> QUERDADDR_S) & QUERDADDR_M) + +#define QUEREMFLITS_S 0 +#define QUEREMFLITS_M 0x7ffU +#define QUEREMFLITS_G(x) (((x) >> QUEREMFLITS_S) & QUEREMFLITS_M) + +#define QUEEOPCNT_S 16 +#define QUEEOPCNT_M 0xfffU +#define QUEEOPCNT_G(x) (((x) >> QUEEOPCNT_S) & QUEEOPCNT_M) + +#define QUESOPCNT_S 0 +#define QUESOPCNT_M 0xfffU +#define QUESOPCNT_G(x) (((x) >> QUESOPCNT_S) & QUESOPCNT_M) + +#define OBQSELECT_S 4 +#define OBQSELECT_V(x) ((x) << OBQSELECT_S) +#define OBQSELECT_F OBQSELECT_V(1U) + +#define IBQSELECT_S 3 +#define IBQSELECT_V(x) ((x) << IBQSELECT_S) +#define IBQSELECT_F IBQSELECT_V(1U) + +#define QUENUMSELECT_S 0 +#define QUENUMSELECT_V(x) ((x) << QUENUMSELECT_S) #endif /* __T4_REGS_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h new file mode 100644 index 000000000000..19b2dcf6acde --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h @@ -0,0 +1,124 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __T4_VALUES_H__ +#define __T4_VALUES_H__ + +/* This file contains definitions for various T4 register value hardware + * constants. The types of values encoded here are predominantly those for + * register fields which control "modal" behavior. For the most part, we do + * not include definitions for register fields which are simple numeric + * metrics, etc. + */ + +/* SGE register field values. + */ + +/* CONTROL1 register */ +#define RXPKTCPLMODE_SPLIT_X 1 + +#define INGPCIEBOUNDARY_SHIFT_X 5 +#define INGPCIEBOUNDARY_32B_X 0 + +#define INGPADBOUNDARY_SHIFT_X 5 + +/* CONTROL2 register */ +#define INGPACKBOUNDARY_SHIFT_X 5 +#define INGPACKBOUNDARY_16B_X 0 + +/* GTS register */ +#define SGE_TIMERREGS 6 +#define TIMERREG_COUNTER0_X 0 + +/* T5 and later support a new BAR2-based doorbell mechanism for Egress Queues. + * The User Doorbells are each 128 bytes in length with a Simple Doorbell at + * offsets 8x and a Write Combining single 64-byte Egress Queue Unit + * (IDXSIZE_UNIT_X) Gather Buffer interface at offset 64. For Ingress Queues, + * we have a Going To Sleep register at offsets 8x+4. + * + * As noted above, we have many instances of the Simple Doorbell and Going To + * Sleep registers at offsets 8x and 8x+4, respectively. We want to use a + * non-64-byte aligned offset for the Simple Doorbell in order to attempt to + * avoid buffering of the writes to the Simple Doorbell and we want to use a + * non-contiguous offset for the Going To Sleep writes in order to avoid + * possible combining between them. + */ +#define SGE_UDB_SIZE 128 +#define SGE_UDB_KDOORBELL 8 +#define SGE_UDB_GTS 20 +#define SGE_UDB_WCDOORBELL 64 + +/* CIM register field values. + */ +#define X_MBOWNER_FW 1 +#define X_MBOWNER_PL 2 + +/* PCI-E definitions */ +#define WINDOW_SHIFT_X 10 +#define PCIEOFST_SHIFT_X 10 + +/* TP_VLAN_PRI_MAP controls which subset of fields will be present in the + * Compressed Filter Tuple for LE filters. Each bit set in TP_VLAN_PRI_MAP + * selects for a particular field being present. These fields, when present + * in the Compressed Filter Tuple, have the following widths in bits. + */ +#define FT_FCOE_W 1 +#define FT_PORT_W 3 +#define FT_VNIC_ID_W 17 +#define FT_VLAN_W 17 +#define FT_TOS_W 8 +#define FT_PROTOCOL_W 8 +#define FT_ETHERTYPE_W 16 +#define FT_MACMATCH_W 9 +#define FT_MPSHITTYPE_W 3 +#define FT_FRAGMENTATION_W 1 + +/* Some of the Compressed Filter Tuple fields have internal structure. These + * bit shifts/masks describe those structures. All shifts are relative to the + * base position of the fields within the Compressed Filter Tuple + */ +#define FT_VLAN_VLD_S 16 +#define FT_VLAN_VLD_V(x) ((x) << FT_VLAN_VLD_S) +#define FT_VLAN_VLD_F FT_VLAN_VLD_V(1U) + +#define FT_VNID_ID_VF_S 0 +#define FT_VNID_ID_VF_V(x) ((x) << FT_VNID_ID_VF_S) + +#define FT_VNID_ID_PF_S 7 +#define FT_VNID_ID_PF_V(x) ((x) << FT_VNID_ID_PF_S) + +#define FT_VNID_ID_VLD_S 16 +#define FT_VNID_ID_VLD_V(x) ((x) << FT_VNID_ID_VLD_S) + +#endif /* __T4_VALUES_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 7c0aec85137a..9b353a88cbda 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -673,6 +673,7 @@ enum fw_cmd_opcodes { FW_RSS_IND_TBL_CMD = 0x20, FW_RSS_GLB_CONFIG_CMD = 0x22, FW_RSS_VI_CONFIG_CMD = 0x23, + FW_DEVLOG_CMD = 0x25, FW_CLIP_CMD = 0x28, FW_LASTC2E_CMD = 0x40, FW_ERROR_CMD = 0x80, @@ -1058,9 +1059,11 @@ enum fw_params_param_dev { FW_PARAMS_PARAM_DEV_FWREV = 0x0B, FW_PARAMS_PARAM_DEV_TPREV = 0x0C, FW_PARAMS_PARAM_DEV_CF = 0x0D, + FW_PARAMS_PARAM_DEV_DIAG = 0x11, FW_PARAMS_PARAM_DEV_MAXORDIRD_QP = 0x13, /* max supported QP IRD/ORD */ FW_PARAMS_PARAM_DEV_MAXIRD_ADAPTER = 0x14, /* max supported adap IRD */ FW_PARAMS_PARAM_DEV_ULPTX_MEMWRITE_DSGL = 0x17, + FW_PARAMS_PARAM_DEV_FWCACHE = 0x18, }; /* @@ -1120,6 +1123,16 @@ enum fw_params_param_dmaq { FW_PARAMS_PARAM_DMAQ_EQ_DCBPRIO_ETH = 0x13, }; +enum fw_params_param_dev_diag { + FW_PARAM_DEV_DIAG_TMP = 0x00, + FW_PARAM_DEV_DIAG_VDD = 0x01, +}; + +enum fw_params_param_dev_fwcache { + FW_PARAM_DEV_FWCACHE_FLUSH = 0x00, + FW_PARAM_DEV_FWCACHE_FLUSHINV = 0x01, +}; + #define FW_PARAMS_MNEM_S 24 #define FW_PARAMS_MNEM_V(x) ((x) << FW_PARAMS_MNEM_S) @@ -3005,21 +3018,29 @@ enum fw_hdr_chip { #define FW_HDR_FW_VER_MAJOR_S 24 #define FW_HDR_FW_VER_MAJOR_M 0xff +#define FW_HDR_FW_VER_MAJOR_V(x) \ + ((x) << FW_HDR_FW_VER_MAJOR_S) #define FW_HDR_FW_VER_MAJOR_G(x) \ (((x) >> FW_HDR_FW_VER_MAJOR_S) & FW_HDR_FW_VER_MAJOR_M) #define FW_HDR_FW_VER_MINOR_S 16 #define FW_HDR_FW_VER_MINOR_M 0xff +#define FW_HDR_FW_VER_MINOR_V(x) \ + ((x) << FW_HDR_FW_VER_MINOR_S) #define FW_HDR_FW_VER_MINOR_G(x) \ (((x) >> FW_HDR_FW_VER_MINOR_S) & FW_HDR_FW_VER_MINOR_M) #define FW_HDR_FW_VER_MICRO_S 8 #define FW_HDR_FW_VER_MICRO_M 0xff +#define FW_HDR_FW_VER_MICRO_V(x) \ + ((x) << FW_HDR_FW_VER_MICRO_S) #define FW_HDR_FW_VER_MICRO_G(x) \ (((x) >> FW_HDR_FW_VER_MICRO_S) & FW_HDR_FW_VER_MICRO_M) #define FW_HDR_FW_VER_BUILD_S 0 #define FW_HDR_FW_VER_BUILD_M 0xff +#define FW_HDR_FW_VER_BUILD_V(x) \ + ((x) << FW_HDR_FW_VER_BUILD_S) #define FW_HDR_FW_VER_BUILD_G(x) \ (((x) >> FW_HDR_FW_VER_BUILD_S) & FW_HDR_FW_VER_BUILD_M) @@ -3038,4 +3059,84 @@ enum fw_hdr_flags { FW_HDR_FLAGS_RESET_HALT = 0x00000001, }; +/* length of the formatting string */ +#define FW_DEVLOG_FMT_LEN 192 + +/* maximum number of the formatting string parameters */ +#define FW_DEVLOG_FMT_PARAMS_NUM 8 + +/* priority levels */ +enum fw_devlog_level { + FW_DEVLOG_LEVEL_EMERG = 0x0, + FW_DEVLOG_LEVEL_CRIT = 0x1, + FW_DEVLOG_LEVEL_ERR = 0x2, + FW_DEVLOG_LEVEL_NOTICE = 0x3, + FW_DEVLOG_LEVEL_INFO = 0x4, + FW_DEVLOG_LEVEL_DEBUG = 0x5, + FW_DEVLOG_LEVEL_MAX = 0x5, +}; + +/* facilities that may send a log message */ +enum fw_devlog_facility { + FW_DEVLOG_FACILITY_CORE = 0x00, + FW_DEVLOG_FACILITY_CF = 0x01, + FW_DEVLOG_FACILITY_SCHED = 0x02, + FW_DEVLOG_FACILITY_TIMER = 0x04, + FW_DEVLOG_FACILITY_RES = 0x06, + FW_DEVLOG_FACILITY_HW = 0x08, + FW_DEVLOG_FACILITY_FLR = 0x10, + FW_DEVLOG_FACILITY_DMAQ = 0x12, + FW_DEVLOG_FACILITY_PHY = 0x14, + FW_DEVLOG_FACILITY_MAC = 0x16, + FW_DEVLOG_FACILITY_PORT = 0x18, + FW_DEVLOG_FACILITY_VI = 0x1A, + FW_DEVLOG_FACILITY_FILTER = 0x1C, + FW_DEVLOG_FACILITY_ACL = 0x1E, + FW_DEVLOG_FACILITY_TM = 0x20, + FW_DEVLOG_FACILITY_QFC = 0x22, + FW_DEVLOG_FACILITY_DCB = 0x24, + FW_DEVLOG_FACILITY_ETH = 0x26, + FW_DEVLOG_FACILITY_OFLD = 0x28, + FW_DEVLOG_FACILITY_RI = 0x2A, + FW_DEVLOG_FACILITY_ISCSI = 0x2C, + FW_DEVLOG_FACILITY_FCOE = 0x2E, + FW_DEVLOG_FACILITY_FOISCSI = 0x30, + FW_DEVLOG_FACILITY_FOFCOE = 0x32, + FW_DEVLOG_FACILITY_MAX = 0x32, +}; + +/* log message format */ +struct fw_devlog_e { + __be64 timestamp; + __be32 seqno; + __be16 reserved1; + __u8 level; + __u8 facility; + __u8 fmt[FW_DEVLOG_FMT_LEN]; + __be32 params[FW_DEVLOG_FMT_PARAMS_NUM]; + __be32 reserved3[4]; +}; + +struct fw_devlog_cmd { + __be32 op_to_write; + __be32 retval_len16; + __u8 level; + __u8 r2[7]; + __be32 memtype_devlog_memaddr16_devlog; + __be32 memsize_devlog; + __be32 r3[2]; +}; + +#define FW_DEVLOG_CMD_MEMTYPE_DEVLOG_S 28 +#define FW_DEVLOG_CMD_MEMTYPE_DEVLOG_M 0xf +#define FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(x) \ + (((x) >> FW_DEVLOG_CMD_MEMTYPE_DEVLOG_S) & \ + FW_DEVLOG_CMD_MEMTYPE_DEVLOG_M) + +#define FW_DEVLOG_CMD_MEMADDR16_DEVLOG_S 0 +#define FW_DEVLOG_CMD_MEMADDR16_DEVLOG_M 0xfffffff +#define FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(x) \ + (((x) >> FW_DEVLOG_CMD_MEMADDR16_DEVLOG_S) & \ + FW_DEVLOG_CMD_MEMADDR16_DEVLOG_M) + #endif /* _T4FW_INTERFACE_H_ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h new file mode 100644 index 000000000000..e2bd3f747858 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h @@ -0,0 +1,48 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __T4FW_VERSION_H__ +#define __T4FW_VERSION_H__ + +#define T4FW_VERSION_MAJOR 0x01 +#define T4FW_VERSION_MINOR 0x0C +#define T4FW_VERSION_MICRO 0x19 +#define T4FW_VERSION_BUILD 0x00 + +#define T5FW_VERSION_MAJOR 0x01 +#define T5FW_VERSION_MINOR 0x0C +#define T5FW_VERSION_MICRO 0x19 +#define T5FW_VERSION_BUILD 0x00 + +#endif diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index a936ee8958c7..122e2964e63b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -380,9 +380,9 @@ static void qenable(struct sge_rspq *rspq) * enable interrupts. */ t4_write_reg(rspq->adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, - CIDXINC(0) | - SEINTARM(rspq->intr_params) | - INGRESSQID(rspq->cntxt_id)); + CIDXINC_V(0) | + SEINTARM_V(rspq->intr_params) | + INGRESSQID_V(rspq->cntxt_id)); } /* @@ -403,9 +403,9 @@ static void enable_rx(struct adapter *adapter) */ if (adapter->flags & USING_MSI) t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, - CIDXINC(0) | - SEINTARM(s->intrq.intr_params) | - INGRESSQID(s->intrq.cntxt_id)); + CIDXINC_V(0) | + SEINTARM_V(s->intrq.intr_params) | + INGRESSQID_V(s->intrq.cntxt_id)); } @@ -450,7 +450,7 @@ static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp, /* FW can send EGR_UPDATEs encapsulated in a CPL_FW4_MSG. */ const struct cpl_sge_egr_update *p = (void *)(rsp + 3); - opcode = G_CPL_OPCODE(ntohl(p->opcode_qid)); + opcode = CPL_OPCODE_G(ntohl(p->opcode_qid)); if (opcode != CPL_SGE_EGR_UPDATE) { dev_err(adapter->pdev_dev, "unexpected FW4/CPL %#x on FW event queue\n" , opcode); @@ -471,7 +471,7 @@ static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp, * free TX Queue Descriptors ... */ const struct cpl_sge_egr_update *p = cpl; - unsigned int qid = EGR_QID(be32_to_cpu(p->opcode_qid)); + unsigned int qid = EGR_QID_G(be32_to_cpu(p->opcode_qid)); struct sge *s = &adapter->sge; struct sge_txq *tq; struct sge_eth_txq *txq; @@ -1673,7 +1673,7 @@ static void cxgb4vf_get_regs(struct net_device *dev, reg_block_dump(adapter, regbuf, T4VF_PL_BASE_ADDR + T4VF_MOD_MAP_PL_FIRST, T4VF_PL_BASE_ADDR + (is_t4(adapter->params.chip) - ? A_PL_VF_WHOAMI : A_PL_VF_REVISION)); + ? PL_VF_WHOAMI_A : PL_VF_REVISION_A)); reg_block_dump(adapter, regbuf, T4VF_CIM_BASE_ADDR + T4VF_MOD_MAP_CIM_FIRST, T4VF_CIM_BASE_ADDR + T4VF_MOD_MAP_CIM_LAST); @@ -2294,26 +2294,22 @@ static int adap_init0(struct adapter *adapter) * threshold values from the SGE parameters. */ s->timer_val[0] = core_ticks_to_us(adapter, - TIMERVALUE0_GET(sge_params->sge_timer_value_0_and_1)); + TIMERVALUE0_G(sge_params->sge_timer_value_0_and_1)); s->timer_val[1] = core_ticks_to_us(adapter, - TIMERVALUE1_GET(sge_params->sge_timer_value_0_and_1)); + TIMERVALUE1_G(sge_params->sge_timer_value_0_and_1)); s->timer_val[2] = core_ticks_to_us(adapter, - TIMERVALUE0_GET(sge_params->sge_timer_value_2_and_3)); + TIMERVALUE0_G(sge_params->sge_timer_value_2_and_3)); s->timer_val[3] = core_ticks_to_us(adapter, - TIMERVALUE1_GET(sge_params->sge_timer_value_2_and_3)); + TIMERVALUE1_G(sge_params->sge_timer_value_2_and_3)); s->timer_val[4] = core_ticks_to_us(adapter, - TIMERVALUE0_GET(sge_params->sge_timer_value_4_and_5)); + TIMERVALUE0_G(sge_params->sge_timer_value_4_and_5)); s->timer_val[5] = core_ticks_to_us(adapter, - TIMERVALUE1_GET(sge_params->sge_timer_value_4_and_5)); + TIMERVALUE1_G(sge_params->sge_timer_value_4_and_5)); - s->counter_val[0] = - THRESHOLD_0_GET(sge_params->sge_ingress_rx_threshold); - s->counter_val[1] = - THRESHOLD_1_GET(sge_params->sge_ingress_rx_threshold); - s->counter_val[2] = - THRESHOLD_2_GET(sge_params->sge_ingress_rx_threshold); - s->counter_val[3] = - THRESHOLD_3_GET(sge_params->sge_ingress_rx_threshold); + s->counter_val[0] = THRESHOLD_0_G(sge_params->sge_ingress_rx_threshold); + s->counter_val[1] = THRESHOLD_1_G(sge_params->sge_ingress_rx_threshold); + s->counter_val[2] = THRESHOLD_2_G(sge_params->sge_ingress_rx_threshold); + s->counter_val[3] = THRESHOLD_3_G(sge_params->sge_ingress_rx_threshold); /* * Grab our Virtual Interface resource allocation, extract the diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index f7fd1317d996..0545f0de1c52 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -47,6 +47,7 @@ #include "t4vf_defs.h" #include "../cxgb4/t4_regs.h" +#include "../cxgb4/t4_values.h" #include "../cxgb4/t4fw_api.h" #include "../cxgb4/t4_msg.h" @@ -531,11 +532,11 @@ static inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl) */ if (fl->pend_cred >= FL_PER_EQ_UNIT) { if (is_t4(adapter->params.chip)) - val = PIDX(fl->pend_cred / FL_PER_EQ_UNIT); + val = PIDX_V(fl->pend_cred / FL_PER_EQ_UNIT); else - val = PIDX_T5(fl->pend_cred / FL_PER_EQ_UNIT) | - DBTYPE(1); - val |= DBPRIO(1); + val = PIDX_T5_V(fl->pend_cred / FL_PER_EQ_UNIT) | + DBTYPE_F; + val |= DBPRIO_F; /* Make sure all memory writes to the Free List queue are * committed before we tell the hardware about them. @@ -549,9 +550,9 @@ static inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl) if (unlikely(fl->bar2_addr == NULL)) { t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL, - QID(fl->cntxt_id) | val); + QID_V(fl->cntxt_id) | val); } else { - writel(val | QID(fl->bar2_qid), + writel(val | QID_V(fl->bar2_qid), fl->bar2_addr + SGE_UDB_KDOORBELL); /* This Write memory Barrier will force the write to @@ -925,7 +926,7 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *tq, } sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | - ULPTX_NSGE(nfrags)); + ULPTX_NSGE_V(nfrags)); if (likely(--nfrags == 0)) return; /* @@ -979,12 +980,12 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq, * doorbell mechanism; otherwise use the new BAR2 mechanism. */ if (unlikely(tq->bar2_addr == NULL)) { - u32 val = PIDX(n); + u32 val = PIDX_V(n); t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL, - QID(tq->cntxt_id) | val); + QID_V(tq->cntxt_id) | val); } else { - u32 val = PIDX_T5(n); + u32 val = PIDX_T5_V(n); /* T4 and later chips share the same PIDX field offset within * the doorbell, but T5 and later shrank the field in order to @@ -992,7 +993,7 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq, * large in the first place (14 bits) so we just use the T5 * and later limits and warn if a Queue ID is too large. */ - WARN_ON(val & DBPRIO(1)); + WARN_ON(val & DBPRIO_F); /* If we're only writing a single Egress Unit and the BAR2 * Queue ID is 0, we can use the Write Combining Doorbell @@ -1023,7 +1024,7 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq, count--; } } else - writel(val | QID(tq->bar2_qid), + writel(val | QID_V(tq->bar2_qid), tq->bar2_addr + SGE_UDB_KDOORBELL); /* This Write Memory Barrier will force the write to the User @@ -1325,9 +1326,9 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev) * If there's a VLAN tag present, add that to the list of things to * do in this Work Request. */ - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { txq->vlan_ins++; - cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(vlan_tx_tag_get(skb)); + cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(skb_vlan_tag_get(skb)); } /* @@ -1603,7 +1604,7 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp, * If this is a good TCP packet and we have Generic Receive Offload * enabled, handle the packet in the GRO path. */ - if ((pkt->l2info & cpu_to_be32(RXF_TCP)) && + if ((pkt->l2info & cpu_to_be32(RXF_TCP_F)) && (rspq->netdev->features & NETIF_F_GRO) && csum_ok && !pkt->ip_frag) { do_gro(rxq, gl, pkt); @@ -1625,7 +1626,7 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp, rxq->stats.pkts++; if (csum_ok && !pkt->err_vec && - (be32_to_cpu(pkt->l2info) & (RXF_UDP|RXF_TCP))) { + (be32_to_cpu(pkt->l2info) & (RXF_UDP_F | RXF_TCP_F))) { if (!pkt->ip_frag) skb->ip_summed = CHECKSUM_UNNECESSARY; else { @@ -1875,13 +1876,13 @@ static int napi_rx_handler(struct napi_struct *napi, int budget) if (unlikely(work_done == 0)) rspq->unhandled_irqs++; - val = CIDXINC(work_done) | SEINTARM(intr_params); + val = CIDXINC_V(work_done) | SEINTARM_V(intr_params); if (is_t4(rspq->adapter->params.chip)) { t4_write_reg(rspq->adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, - val | INGRESSQID((u32)rspq->cntxt_id)); + val | INGRESSQID_V((u32)rspq->cntxt_id)); } else { - writel(val | INGRESSQID(rspq->bar2_qid), + writel(val | INGRESSQID_V(rspq->bar2_qid), rspq->bar2_addr + SGE_UDB_GTS); wmb(); } @@ -1975,12 +1976,12 @@ static unsigned int process_intrq(struct adapter *adapter) rspq_next(intrq); } - val = CIDXINC(work_done) | SEINTARM(intrq->intr_params); + val = CIDXINC_V(work_done) | SEINTARM_V(intrq->intr_params); if (is_t4(adapter->params.chip)) t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, - val | INGRESSQID(intrq->cntxt_id)); + val | INGRESSQID_V(intrq->cntxt_id)); else { - writel(val | INGRESSQID(intrq->bar2_qid), + writel(val | INGRESSQID_V(intrq->bar2_qid), intrq->bar2_addr + SGE_UDB_GTS); wmb(); } @@ -2583,7 +2584,7 @@ int t4vf_sge_init(struct adapter *adapter) fl0, fl1); return -EINVAL; } - if ((sge_params->sge_control & RXPKTCPLMODE_MASK) == 0) { + if ((sge_params->sge_control & RXPKTCPLMODE_F) == 0) { dev_err(adapter->pdev_dev, "bad SGE CPL MODE\n"); return -EINVAL; } @@ -2593,9 +2594,9 @@ int t4vf_sge_init(struct adapter *adapter) */ if (fl1) s->fl_pg_order = ilog2(fl1) - PAGE_SHIFT; - s->stat_len = ((sge_params->sge_control & EGRSTATUSPAGESIZE_MASK) + s->stat_len = ((sge_params->sge_control & EGRSTATUSPAGESIZE_F) ? 128 : 64); - s->pktshift = PKTSHIFT_GET(sge_params->sge_control); + s->pktshift = PKTSHIFT_G(sge_params->sge_control); /* T4 uses a single control field to specify both the PCIe Padding and * Packing Boundary. T5 introduced the ability to specify these @@ -2607,8 +2608,8 @@ int t4vf_sge_init(struct adapter *adapter) * end doing this because it would initialize the Padding Boundary and * leave the Packing Boundary initialized to 0 (16 bytes).) */ - ingpadboundary = 1 << (INGPADBOUNDARY_GET(sge_params->sge_control) + - X_INGPADBOUNDARY_SHIFT); + ingpadboundary = 1 << (INGPADBOUNDARY_G(sge_params->sge_control) + + INGPADBOUNDARY_SHIFT_X); if (is_t4(adapter->params.chip)) { s->fl_align = ingpadboundary; } else { @@ -2633,7 +2634,7 @@ int t4vf_sge_init(struct adapter *adapter) * Congestion Threshold is in units of 2 Free List pointers.) */ s->fl_starve_thres - = EGRTHRESHOLD_GET(sge_params->sge_congestion_control)*2 + 1; + = EGRTHRESHOLD_G(sge_params->sge_congestion_control)*2 + 1; /* * Set up tasklet timers. diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h index c7b127d93767..b516b12b1884 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h @@ -64,8 +64,8 @@ * Mailbox Data in the fixed CIM PF map and the programmable VF map must * match. However, it's a useful convention ... */ -#if T4VF_MBDATA_BASE_ADDR != CIM_PF_MAILBOX_DATA -#error T4VF_MBDATA_BASE_ADDR must match CIM_PF_MAILBOX_DATA! +#if T4VF_MBDATA_BASE_ADDR != CIM_PF_MAILBOX_DATA_A +#error T4VF_MBDATA_BASE_ADDR must match CIM_PF_MAILBOX_DATA_A! #endif /* diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c index 60426cf890a7..1b5506df35b1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c @@ -39,6 +39,7 @@ #include "t4vf_defs.h" #include "../cxgb4/t4_regs.h" +#include "../cxgb4/t4_values.h" #include "../cxgb4/t4fw_api.h" /* @@ -137,9 +138,9 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size, * Loop trying to get ownership of the mailbox. Return an error * if we can't gain ownership. */ - v = MBOWNER_GET(t4_read_reg(adapter, mbox_ctl)); + v = MBOWNER_G(t4_read_reg(adapter, mbox_ctl)); for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++) - v = MBOWNER_GET(t4_read_reg(adapter, mbox_ctl)); + v = MBOWNER_G(t4_read_reg(adapter, mbox_ctl)); if (v != MBOX_OWNER_DRV) return v == MBOX_OWNER_FW ? -EBUSY : -ETIMEDOUT; @@ -161,7 +162,7 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size, t4_read_reg(adapter, mbox_data); /* flush write */ t4_write_reg(adapter, mbox_ctl, - MBMSGVALID | MBOWNER(MBOX_OWNER_FW)); + MBMSGVALID_F | MBOWNER_V(MBOX_OWNER_FW)); t4_read_reg(adapter, mbox_ctl); /* flush write */ /* @@ -183,14 +184,14 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size, * If we're the owner, see if this is the reply we wanted. */ v = t4_read_reg(adapter, mbox_ctl); - if (MBOWNER_GET(v) == MBOX_OWNER_DRV) { + if (MBOWNER_G(v) == MBOX_OWNER_DRV) { /* * If the Message Valid bit isn't on, revoke ownership * of the mailbox and continue waiting for our reply. */ - if ((v & MBMSGVALID) == 0) { + if ((v & MBMSGVALID_F) == 0) { t4_write_reg(adapter, mbox_ctl, - MBOWNER(MBOX_OWNER_NONE)); + MBOWNER_V(MBOX_OWNER_NONE)); continue; } @@ -216,7 +217,7 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size, & FW_CMD_REQUEST_F) != 0); } t4_write_reg(adapter, mbox_ctl, - MBOWNER(MBOX_OWNER_NONE)); + MBOWNER_V(MBOX_OWNER_NONE)); return -FW_CMD_RETVAL_G(v); } } @@ -530,19 +531,19 @@ int t4vf_get_sge_params(struct adapter *adapter) int v; params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_CONTROL)); + FW_PARAMS_PARAM_XYZ_V(SGE_CONTROL_A)); params[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_HOST_PAGE_SIZE)); + FW_PARAMS_PARAM_XYZ_V(SGE_HOST_PAGE_SIZE_A)); params[2] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE0)); + FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE0_A)); params[3] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE1)); + FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE1_A)); params[4] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_0_AND_1)); + FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_0_AND_1_A)); params[5] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_2_AND_3)); + FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_2_AND_3_A)); params[6] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_4_AND_5)); + FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_4_AND_5_A)); v = t4vf_query_params(adapter, 7, params, vals); if (v) return v; @@ -578,9 +579,9 @@ int t4vf_get_sge_params(struct adapter *adapter) } params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_INGRESS_RX_THRESHOLD)); + FW_PARAMS_PARAM_XYZ_V(SGE_INGRESS_RX_THRESHOLD_A)); params[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ_V(SGE_CONM_CTRL)); + FW_PARAMS_PARAM_XYZ_V(SGE_CONM_CTRL_A)); v = t4vf_query_params(adapter, 2, params, vals); if (v) return v; @@ -617,8 +618,8 @@ int t4vf_get_sge_params(struct adapter *adapter) * the driver can just use it. */ whoami = t4_read_reg(adapter, - T4VF_PL_BASE_ADDR + A_PL_VF_WHOAMI); - pf = SOURCEPF_GET(whoami); + T4VF_PL_BASE_ADDR + PL_VF_WHOAMI_A); + pf = SOURCEPF_G(whoami); s_hps = (HOSTPAGESIZEPF0_S + (HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * pf); @@ -630,10 +631,10 @@ int t4vf_get_sge_params(struct adapter *adapter) (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * pf); sge_params->sge_vf_eq_qpp = ((sge_params->sge_egress_queues_per_page >> s_qpp) - & QUEUESPERPAGEPF0_MASK); + & QUEUESPERPAGEPF0_M); sge_params->sge_vf_iq_qpp = ((sge_params->sge_ingress_queues_per_page >> s_qpp) - & QUEUESPERPAGEPF0_MASK); + & QUEUESPERPAGEPF0_M); } return 0; @@ -1592,7 +1593,7 @@ int t4vf_prep_adapter(struct adapter *adapter) break; case CHELSIO_T5: - chipid = G_REV(t4_read_reg(adapter, A_PL_VF_REV)); + chipid = REV_G(t4_read_reg(adapter, PL_VF_REV_A)); adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T5, chipid); break; } diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig index 7403dff8f14a..905ac5f5d9a6 100644 --- a/drivers/net/ethernet/cirrus/Kconfig +++ b/drivers/net/ethernet/cirrus/Kconfig @@ -32,7 +32,8 @@ config CS89x0 will be called cs89x0. config CS89x0_PLATFORM - bool "CS89x0 platform driver support" + bool "CS89x0 platform driver support" if HAS_IOPORT_MAP + default !HAS_IOPORT_MAP depends on CS89x0 help Say Y to compile the cs89x0 driver as a platform driver. This diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c index 3a12c096ea1c..de9f7c97d916 100644 --- a/drivers/net/ethernet/cirrus/ep93xx_eth.c +++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c @@ -475,8 +475,7 @@ static void ep93xx_free_buffers(struct ep93xx_priv *ep) if (d) dma_unmap_single(dev, d, PKT_BUF_SIZE, DMA_FROM_DEVICE); - if (ep->rx_buf[i] != NULL) - kfree(ep->rx_buf[i]); + kfree(ep->rx_buf[i]); } for (i = 0; i < TX_QUEUE_ENTRIES; i++) { @@ -486,8 +485,7 @@ static void ep93xx_free_buffers(struct ep93xx_priv *ep) if (d) dma_unmap_single(dev, d, PKT_BUF_SIZE, DMA_TO_DEVICE); - if (ep->tx_buf[i] != NULL) - kfree(ep->tx_buf[i]); + kfree(ep->tx_buf[i]); } dma_free_coherent(dev, sizeof(struct ep93xx_descs), ep->descs, diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index 25c4d88853d8..84b6a2b46aec 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -33,7 +33,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" -#define DRV_VERSION "2.1.1.67" +#define DRV_VERSION "2.1.1.83" #define DRV_COPYRIGHT "Copyright 2008-2013 Cisco Systems, Inc" #define ENIC_BARS_MAX 6 @@ -188,6 +188,7 @@ struct enic { struct enic_rfs_flw_tbl rfs_h; u32 rx_copybreak; u8 rss_key[ENIC_RSS_LEN]; + struct vnic_gen_stats gen_stats; }; static inline struct device *enic_get_dev(struct enic *enic) @@ -242,6 +243,19 @@ static inline unsigned int enic_msix_notify_intr(struct enic *enic) return enic->rq_count + enic->wq_count + 1; } +static inline int enic_dma_map_check(struct enic *enic, dma_addr_t dma_addr) +{ + if (unlikely(pci_dma_mapping_error(enic->pdev, dma_addr))) { + net_warn_ratelimited("%s: PCI dma mapping failed!\n", + enic->netdev->name); + enic->gen_stats.dma_map_error++; + + return -ENOMEM; + } + + return 0; +} + void enic_reset_addr_lists(struct enic *enic); int enic_sriov_enabled(struct enic *enic); int enic_is_valid_vf(struct enic *enic, int vf); diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.c b/drivers/net/ethernet/cisco/enic/enic_dev.c index 87ddc44b590e..f8d2a6a34282 100644 --- a/drivers/net/ethernet/cisco/enic/enic_dev.c +++ b/drivers/net/ethernet/cisco/enic/enic_dev.c @@ -177,40 +177,6 @@ int enic_dev_intr_coal_timer_info(struct enic *enic) return err; } -int enic_vnic_dev_deinit(struct enic *enic) -{ - int err; - - spin_lock_bh(&enic->devcmd_lock); - err = vnic_dev_deinit(enic->vdev); - spin_unlock_bh(&enic->devcmd_lock); - - return err; -} - -int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp) -{ - int err; - - spin_lock_bh(&enic->devcmd_lock); - err = vnic_dev_init_prov2(enic->vdev, - (u8 *)vp, vic_provinfo_size(vp)); - spin_unlock_bh(&enic->devcmd_lock); - - return err; -} - -int enic_dev_deinit_done(struct enic *enic, int *status) -{ - int err; - - spin_lock_bh(&enic->devcmd_lock); - err = vnic_dev_deinit_done(enic->vdev, status); - spin_unlock_bh(&enic->devcmd_lock); - - return err; -} - /* rtnl lock is held */ int enic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid) { @@ -237,28 +203,6 @@ int enic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid) return err; } -int enic_dev_enable2(struct enic *enic, int active) -{ - int err; - - spin_lock_bh(&enic->devcmd_lock); - err = vnic_dev_enable2(enic->vdev, active); - spin_unlock_bh(&enic->devcmd_lock); - - return err; -} - -int enic_dev_enable2_done(struct enic *enic, int *status) -{ - int err; - - spin_lock_bh(&enic->devcmd_lock); - err = vnic_dev_enable2_done(enic->vdev, status); - spin_unlock_bh(&enic->devcmd_lock); - - return err; -} - int enic_dev_status_to_errno(int devcmd_status) { switch (devcmd_status) { diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.h b/drivers/net/ethernet/cisco/enic/enic_dev.h index 10bb970b2f35..f5bb058b3f96 100644 --- a/drivers/net/ethernet/cisco/enic/enic_dev.h +++ b/drivers/net/ethernet/cisco/enic/enic_dev.h @@ -55,11 +55,6 @@ 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_dev_intr_coal_timer_info(struct enic *enic); -int enic_vnic_dev_deinit(struct enic *enic); -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/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c index eba1eb846d34..28d9ca675a27 100644 --- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c +++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c @@ -24,6 +24,7 @@ #include "enic_dev.h" #include "enic_clsf.h" #include "vnic_rss.h" +#include "vnic_stats.h" struct enic_stat { char name[ETH_GSTRING_LEN]; @@ -40,6 +41,11 @@ struct enic_stat { .index = offsetof(struct vnic_rx_stats, stat) / sizeof(u64) \ } +#define ENIC_GEN_STAT(stat) { \ + .name = #stat, \ + .index = offsetof(struct vnic_gen_stats, stat) / sizeof(u64)\ +} + static const struct enic_stat enic_tx_stats[] = { ENIC_TX_STAT(tx_frames_ok), ENIC_TX_STAT(tx_unicast_frames_ok), @@ -78,10 +84,15 @@ static const struct enic_stat enic_rx_stats[] = { ENIC_RX_STAT(rx_frames_to_max), }; +static const struct enic_stat enic_gen_stats[] = { + ENIC_GEN_STAT(dma_map_error), +}; + static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats); static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats); +static const unsigned int enic_n_gen_stats = ARRAY_SIZE(enic_gen_stats); -void enic_intr_coal_set_rx(struct enic *enic, u32 timer) +static void enic_intr_coal_set_rx(struct enic *enic, u32 timer) { int i; int intr; @@ -146,6 +157,10 @@ static void enic_get_strings(struct net_device *netdev, u32 stringset, memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN); data += ETH_GSTRING_LEN; } + for (i = 0; i < enic_n_gen_stats; i++) { + memcpy(data, enic_gen_stats[i].name, ETH_GSTRING_LEN); + data += ETH_GSTRING_LEN; + } break; } } @@ -154,7 +169,7 @@ static int enic_get_sset_count(struct net_device *netdev, int sset) { switch (sset) { case ETH_SS_STATS: - return enic_n_tx_stats + enic_n_rx_stats; + return enic_n_tx_stats + enic_n_rx_stats + enic_n_gen_stats; default: return -EOPNOTSUPP; } @@ -173,6 +188,8 @@ static void enic_get_ethtool_stats(struct net_device *netdev, *(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].index]; for (i = 0; i < enic_n_rx_stats; i++) *(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].index]; + for (i = 0; i < enic_n_gen_stats; i++) + *(data++) = ((u64 *)&enic->gen_stats)[enic_gen_stats[i].index]; } static u32 enic_get_msglevel(struct net_device *netdev) diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index b29e027c476e..9cbe038a388e 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -45,6 +45,7 @@ #ifdef CONFIG_NET_RX_BUSY_POLL #include #endif +#include #include "cq_enet_desc.h" #include "vnic_dev.h" @@ -88,7 +89,7 @@ MODULE_DEVICE_TABLE(pci, enic_id_table); * coalescing timer values * {rx_rate in Mbps, mapping percentage of the range} */ -struct enic_intr_mod_table mod_table[ENIC_MAX_COALESCE_TIMERS + 1] = { +static struct enic_intr_mod_table mod_table[ENIC_MAX_COALESCE_TIMERS + 1] = { {4000, 0}, {4400, 10}, {5060, 20}, @@ -105,7 +106,7 @@ struct enic_intr_mod_table mod_table[ENIC_MAX_COALESCE_TIMERS + 1] = { /* This table helps the driver to pick different ranges for rx coalescing * timer depending on the link speed. */ -struct enic_intr_mod_range mod_range[ENIC_MAX_LINK_SPEEDS] = { +static struct enic_intr_mod_range mod_range[ENIC_MAX_LINK_SPEEDS] = { {0, 0}, /* 0 - 4 Gbps */ {0, 3}, /* 4 - 10 Gbps */ {3, 6}, /* 10 - 40 Gbps */ @@ -351,80 +352,94 @@ static irqreturn_t enic_isr_msix_notify(int irq, void *data) return IRQ_HANDLED; } -static inline void enic_queue_wq_skb_cont(struct enic *enic, - struct vnic_wq *wq, struct sk_buff *skb, - unsigned int len_left, int loopback) +static int enic_queue_wq_skb_cont(struct enic *enic, struct vnic_wq *wq, + struct sk_buff *skb, unsigned int len_left, + int loopback) { const skb_frag_t *frag; + dma_addr_t dma_addr; /* Queue additional data fragments */ for (frag = skb_shinfo(skb)->frags; len_left; frag++) { len_left -= skb_frag_size(frag); - enic_queue_wq_desc_cont(wq, skb, - skb_frag_dma_map(&enic->pdev->dev, - frag, 0, skb_frag_size(frag), - DMA_TO_DEVICE), - skb_frag_size(frag), - (len_left == 0), /* EOP? */ - loopback); + dma_addr = skb_frag_dma_map(&enic->pdev->dev, frag, 0, + skb_frag_size(frag), + DMA_TO_DEVICE); + if (unlikely(enic_dma_map_check(enic, dma_addr))) + return -ENOMEM; + enic_queue_wq_desc_cont(wq, skb, dma_addr, skb_frag_size(frag), + (len_left == 0), /* EOP? */ + loopback); } + + return 0; } -static inline void enic_queue_wq_skb_vlan(struct enic *enic, - struct vnic_wq *wq, struct sk_buff *skb, - int vlan_tag_insert, unsigned int vlan_tag, int loopback) +static int enic_queue_wq_skb_vlan(struct enic *enic, struct vnic_wq *wq, + struct sk_buff *skb, int vlan_tag_insert, + unsigned int vlan_tag, int loopback) { unsigned int head_len = skb_headlen(skb); unsigned int len_left = skb->len - head_len; int eop = (len_left == 0); + dma_addr_t dma_addr; + int err = 0; + + dma_addr = pci_map_single(enic->pdev, skb->data, head_len, + PCI_DMA_TODEVICE); + if (unlikely(enic_dma_map_check(enic, dma_addr))) + return -ENOMEM; /* Queue the main skb fragment. The fragments are no larger * than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less * than WQ_ENET_MAX_DESC_LEN length. So only one descriptor * per fragment is queued. */ - enic_queue_wq_desc(wq, skb, - pci_map_single(enic->pdev, skb->data, - head_len, PCI_DMA_TODEVICE), - head_len, - vlan_tag_insert, vlan_tag, - eop, loopback); + enic_queue_wq_desc(wq, skb, dma_addr, head_len, vlan_tag_insert, + vlan_tag, eop, loopback); if (!eop) - enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback); + err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback); + + return err; } -static inline void enic_queue_wq_skb_csum_l4(struct enic *enic, - struct vnic_wq *wq, struct sk_buff *skb, - int vlan_tag_insert, unsigned int vlan_tag, int loopback) +static int enic_queue_wq_skb_csum_l4(struct enic *enic, struct vnic_wq *wq, + struct sk_buff *skb, int vlan_tag_insert, + unsigned int vlan_tag, int loopback) { unsigned int head_len = skb_headlen(skb); unsigned int len_left = skb->len - head_len; unsigned int hdr_len = skb_checksum_start_offset(skb); unsigned int csum_offset = hdr_len + skb->csum_offset; int eop = (len_left == 0); + dma_addr_t dma_addr; + int err = 0; + + dma_addr = pci_map_single(enic->pdev, skb->data, head_len, + PCI_DMA_TODEVICE); + if (unlikely(enic_dma_map_check(enic, dma_addr))) + return -ENOMEM; /* Queue the main skb fragment. The fragments are no larger * than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less * than WQ_ENET_MAX_DESC_LEN length. So only one descriptor * per fragment is queued. */ - enic_queue_wq_desc_csum_l4(wq, skb, - pci_map_single(enic->pdev, skb->data, - head_len, PCI_DMA_TODEVICE), - head_len, - csum_offset, - hdr_len, - vlan_tag_insert, vlan_tag, - eop, loopback); + enic_queue_wq_desc_csum_l4(wq, skb, dma_addr, head_len, csum_offset, + hdr_len, vlan_tag_insert, vlan_tag, eop, + loopback); if (!eop) - enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback); + err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback); + + return err; } -static inline void enic_queue_wq_skb_tso(struct enic *enic, - struct vnic_wq *wq, struct sk_buff *skb, unsigned int mss, - int vlan_tag_insert, unsigned int vlan_tag, int loopback) +static int enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq, + struct sk_buff *skb, unsigned int mss, + int vlan_tag_insert, unsigned int vlan_tag, + int loopback) { unsigned int frag_len_left = skb_headlen(skb); unsigned int len_left = skb->len - frag_len_left; @@ -454,20 +469,19 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic, */ while (frag_len_left) { len = min(frag_len_left, (unsigned int)WQ_ENET_MAX_DESC_LEN); - dma_addr = pci_map_single(enic->pdev, skb->data + offset, - len, PCI_DMA_TODEVICE); - enic_queue_wq_desc_tso(wq, skb, - dma_addr, - len, - mss, hdr_len, - vlan_tag_insert, vlan_tag, - eop && (len == frag_len_left), loopback); + dma_addr = pci_map_single(enic->pdev, skb->data + offset, len, + PCI_DMA_TODEVICE); + if (unlikely(enic_dma_map_check(enic, dma_addr))) + return -ENOMEM; + enic_queue_wq_desc_tso(wq, skb, dma_addr, len, mss, hdr_len, + vlan_tag_insert, vlan_tag, + eop && (len == frag_len_left), loopback); frag_len_left -= len; offset += len; } if (eop) - return; + return 0; /* Queue WQ_ENET_MAX_DESC_LEN length descriptors * for additional data fragments @@ -483,16 +497,18 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic, dma_addr = skb_frag_dma_map(&enic->pdev->dev, frag, offset, len, DMA_TO_DEVICE); - enic_queue_wq_desc_cont(wq, skb, - dma_addr, - len, - (len_left == 0) && - (len == frag_len_left), /* EOP? */ - loopback); + if (unlikely(enic_dma_map_check(enic, dma_addr))) + return -ENOMEM; + enic_queue_wq_desc_cont(wq, skb, dma_addr, len, + (len_left == 0) && + (len == frag_len_left),/*EOP*/ + loopback); frag_len_left -= len; offset += len; } } + + return 0; } static inline void enic_queue_wq_skb(struct enic *enic, @@ -502,25 +518,42 @@ static inline void enic_queue_wq_skb(struct enic *enic, unsigned int vlan_tag = 0; int vlan_tag_insert = 0; int loopback = 0; + int err; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { /* VLAN tag from trunking driver */ vlan_tag_insert = 1; - vlan_tag = vlan_tx_tag_get(skb); + vlan_tag = skb_vlan_tag_get(skb); } else if (enic->loop_enable) { vlan_tag = enic->loop_tag; loopback = 1; } if (mss) - enic_queue_wq_skb_tso(enic, wq, skb, mss, - vlan_tag_insert, vlan_tag, loopback); + err = enic_queue_wq_skb_tso(enic, wq, skb, mss, + vlan_tag_insert, vlan_tag, + loopback); else if (skb->ip_summed == CHECKSUM_PARTIAL) - enic_queue_wq_skb_csum_l4(enic, wq, skb, - vlan_tag_insert, vlan_tag, loopback); + err = enic_queue_wq_skb_csum_l4(enic, wq, skb, vlan_tag_insert, + vlan_tag, loopback); else - enic_queue_wq_skb_vlan(enic, wq, skb, - vlan_tag_insert, vlan_tag, loopback); + err = enic_queue_wq_skb_vlan(enic, wq, skb, vlan_tag_insert, + vlan_tag, loopback); + if (unlikely(err)) { + struct vnic_wq_buf *buf; + + buf = wq->to_use->prev; + /* while not EOP of previous pkt && queue not empty. + * For all non EOP bufs, os_buf is NULL. + */ + while (!buf->os_buf && (buf->next != wq->to_clean)) { + enic_free_wq_buf(wq, buf); + wq->ring.desc_avail++; + buf = buf->prev; + } + wq->to_use = buf->next; + dev_kfree_skb(skb); + } } /* netif_tx_lock held, process context with BHs disabled, or BH */ @@ -950,8 +983,12 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq) if (!skb) return -ENOMEM; - dma_addr = pci_map_single(enic->pdev, skb->data, - len, PCI_DMA_FROMDEVICE); + dma_addr = pci_map_single(enic->pdev, skb->data, len, + PCI_DMA_FROMDEVICE); + if (unlikely(enic_dma_map_check(enic, dma_addr))) { + dev_kfree_skb(skb); + return -ENOMEM; + } enic_queue_rq_desc(rq, skb, os_buf_index, dma_addr, len); @@ -1266,7 +1303,7 @@ static void enic_set_rx_cpu_rmap(struct enic *enic) #endif /* CONFIG_RFS_ACCEL */ #ifdef CONFIG_NET_RX_BUSY_POLL -int enic_busy_poll(struct napi_struct *napi) +static int enic_busy_poll(struct napi_struct *napi) { struct net_device *netdev = napi->dev; struct enic *enic = netdev_priv(netdev); @@ -1335,7 +1372,7 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget) int err; if (!enic_poll_lock_napi(&enic->rq[rq])) - return work_done; + return budget; /* Service RQ */ @@ -2231,6 +2268,18 @@ static void enic_dev_deinit(struct enic *enic) enic_clear_intr_mode(enic); } +static void enic_kdump_kernel_config(struct enic *enic) +{ + if (is_kdump_kernel()) { + dev_info(enic_get_dev(enic), "Running from within kdump kernel. Using minimal resources\n"); + enic->rq_count = 1; + enic->wq_count = 1; + enic->config.rq_desc_count = ENIC_MIN_RQ_DESCS; + enic->config.wq_desc_count = ENIC_MIN_WQ_DESCS; + enic->config.mtu = min_t(u16, 1500, enic->config.mtu); + } +} + static int enic_dev_init(struct enic *enic) { struct device *dev = enic_get_dev(enic); @@ -2260,6 +2309,10 @@ static int enic_dev_init(struct enic *enic) enic_get_res_counts(enic); + /* modify resource count if we are in kdump_kernel + */ + enic_kdump_kernel_config(enic); + /* Set interrupt mode based on resource counts and system * capabilities */ diff --git a/drivers/net/ethernet/cisco/enic/vnic_stats.h b/drivers/net/ethernet/cisco/enic/vnic_stats.h index 77750ec93954..74c81ed6fdab 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_stats.h +++ b/drivers/net/ethernet/cisco/enic/vnic_stats.h @@ -62,6 +62,11 @@ struct vnic_rx_stats { u64 rsvd[16]; }; +/* Generic statistics */ +struct vnic_gen_stats { + u64 dma_map_error; +}; + struct vnic_stats { struct vnic_tx_stats tx; struct vnic_rx_stats rx; diff --git a/drivers/net/ethernet/cisco/enic/vnic_wq.c b/drivers/net/ethernet/cisco/enic/vnic_wq.c index 3e6b8d54dafc..b5a1c937fad2 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_wq.c +++ b/drivers/net/ethernet/cisco/enic/vnic_wq.c @@ -47,11 +47,14 @@ static int vnic_wq_alloc_bufs(struct vnic_wq *wq) wq->ring.desc_size * buf->index; if (buf->index + 1 == count) { buf->next = wq->bufs[0]; + buf->next->prev = buf; break; } else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES(count)) { buf->next = wq->bufs[i + 1]; + buf->next->prev = buf; } else { buf->next = buf + 1; + buf->next->prev = buf; buf++; } } diff --git a/drivers/net/ethernet/cisco/enic/vnic_wq.h b/drivers/net/ethernet/cisco/enic/vnic_wq.h index 816f1ad6072f..296154351823 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_wq.h +++ b/drivers/net/ethernet/cisco/enic/vnic_wq.h @@ -62,6 +62,7 @@ struct vnic_wq_buf { uint8_t cq_entry; /* Gets completion event from hw */ uint8_t desc_skip_cnt; /* Num descs to occupy */ uint8_t compressed_send; /* Both hdr and payload in one desc */ + struct vnic_wq_buf *prev; }; /* Break the vnic_wq_buf allocations into blocks of 32/64 entries */ diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index ef0bb58750e6..c0a7813603c3 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -36,6 +36,9 @@ #include #include #include +#include +#include +#include #include #include @@ -1426,11 +1429,48 @@ dm9000_probe(struct platform_device *pdev) struct dm9000_plat_data *pdata = dev_get_platdata(&pdev->dev); struct board_info *db; /* Point a board information structure */ struct net_device *ndev; + struct device *dev = &pdev->dev; const unsigned char *mac_src; int ret = 0; int iosize; int i; u32 id_val; + int reset_gpios; + enum of_gpio_flags flags; + struct regulator *power; + + power = devm_regulator_get(dev, "vcc"); + if (IS_ERR(power)) { + if (PTR_ERR(power) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_dbg(dev, "no regulator provided\n"); + } else { + ret = regulator_enable(power); + if (ret != 0) { + dev_err(dev, + "Failed to enable power regulator: %d\n", ret); + return ret; + } + dev_dbg(dev, "regulator enabled\n"); + } + + reset_gpios = of_get_named_gpio_flags(dev->of_node, "reset-gpios", 0, + &flags); + if (gpio_is_valid(reset_gpios)) { + ret = devm_gpio_request_one(dev, reset_gpios, flags, + "dm9000_reset"); + if (ret) { + dev_err(dev, "failed to request reset gpio %d: %d\n", + reset_gpios, ret); + return -ENODEV; + } + + /* According to manual PWRST# Low Period Min 1ms */ + msleep(2); + gpio_set_value(reset_gpios, 1); + /* Needs 3ms to read eeprom when PWRST is deasserted */ + msleep(4); + } if (!pdata) { pdata = dm9000_parse_dt(&pdev->dev); diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c index 6aa887e0e1cb..9beb3d34d4ba 100644 --- a/drivers/net/ethernet/dec/tulip/winbond-840.c +++ b/drivers/net/ethernet/dec/tulip/winbond-840.c @@ -904,7 +904,7 @@ static void init_registers(struct net_device *dev) } #elif defined(__powerpc__) || defined(__i386__) || defined(__alpha__) || defined(__ia64__) || defined(__x86_64__) i |= 0xE000; -#elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC) +#elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC) || defined(CONFIG_ARM) i |= 0x4800; #else #warning Processor architecture undefined diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 712e7f8e1df7..27de37aa90af 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -59,26 +59,6 @@ #define OC_SUBSYS_DEVICE_ID3 0xE612 #define OC_SUBSYS_DEVICE_ID4 0xE652 -static inline char *nic_name(struct pci_dev *pdev) -{ - switch (pdev->device) { - case OC_DEVICE_ID1: - return OC_NAME; - 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; - case OC_DEVICE_ID5: - case OC_DEVICE_ID6: - return OC_NAME_SH; - default: - return BE_NAME; - } -} - /* Number of bytes of an RX frame that are copied to skb->data */ #define BE_HDR_LEN ((u16) 64) /* allocate extra space to allow tunneling decapsulation without head reallocation */ @@ -243,7 +223,6 @@ struct be_tx_stats { u64 tx_bytes; u64 tx_pkts; u64 tx_reqs; - u64 tx_wrbs; u64 tx_compl; ulong tx_jiffies; u32 tx_stops; @@ -266,6 +245,9 @@ struct be_tx_obj { /* Remember the skbs that were transmitted */ struct sk_buff *sent_skb_list[TX_Q_LEN]; struct be_tx_stats stats; + u16 pend_wrb_cnt; /* Number of WRBs yet to be given to HW */ + u16 last_req_wrb_cnt; /* wrb cnt of the last req in the Q */ + u16 last_req_hdr; /* index of the last req's hdr-wrb */ } ____cacheline_aligned_in_smp; /* Struct to remember the pages posted for rx frags */ @@ -379,15 +361,14 @@ enum vf_state { ASSIGNED = 1 }; -#define BE_FLAGS_LINK_STATUS_INIT 1 -#define BE_FLAGS_SRIOV_ENABLED (1 << 2) -#define BE_FLAGS_WORKER_SCHEDULED (1 << 3) -#define BE_FLAGS_VLAN_PROMISC (1 << 4) -#define BE_FLAGS_MCAST_PROMISC (1 << 5) -#define BE_FLAGS_NAPI_ENABLED (1 << 9) -#define BE_FLAGS_QNQ_ASYNC_EVT_RCVD (1 << 11) -#define BE_FLAGS_VXLAN_OFFLOADS (1 << 12) -#define BE_FLAGS_SETUP_DONE (1 << 13) +#define BE_FLAGS_LINK_STATUS_INIT BIT(1) +#define BE_FLAGS_SRIOV_ENABLED BIT(2) +#define BE_FLAGS_WORKER_SCHEDULED BIT(3) +#define BE_FLAGS_NAPI_ENABLED BIT(6) +#define BE_FLAGS_QNQ_ASYNC_EVT_RCVD BIT(7) +#define BE_FLAGS_VXLAN_OFFLOADS BIT(8) +#define BE_FLAGS_SETUP_DONE BIT(9) +#define BE_FLAGS_EVT_INCOMPATIBLE_SFP BIT(10) #define BE_UC_PMAC_COUNT 30 #define BE_VF_UC_PMAC_COUNT 2 @@ -397,6 +378,8 @@ enum vf_state { #define LANCER_DELETE_FW_DUMP 0x2 struct phy_info { +/* From SFF-8472 spec */ +#define SFP_VENDOR_NAME_LEN 17 u8 transceiver; u8 autoneg; u8 fc_autoneg; @@ -410,6 +393,8 @@ struct phy_info { u32 advertising; u32 supported; u8 cable_type; + u8 vendor_name[SFP_VENDOR_NAME_LEN]; + u8 vendor_pn[SFP_VENDOR_NAME_LEN]; }; struct be_resources { @@ -467,8 +452,6 @@ struct be_adapter { struct be_drv_stats drv_stats; struct be_aic_obj aic_obj[MAX_EVT_QS]; - u16 vlans_added; - unsigned long vids[BITS_TO_LONGS(VLAN_N_VID)]; u8 vlan_prio_bmap; /* Available Priority BitMap */ u16 recommended_prio; /* Recommended Priority */ struct be_dma_mem rx_filter; /* Cmd DMA mem for rx-filter */ @@ -484,8 +467,15 @@ struct be_adapter { /* Ethtool knobs and info */ char fw_ver[FW_VER_LEN]; char fw_on_flash[FW_VER_LEN]; + + /* IFACE filtering fields */ int if_handle; /* Used to configure filtering */ + u32 if_flags; /* Interface filtering flags */ u32 *pmac_id; /* MAC addr handle used by BE card */ + u32 uc_macs; /* Count of secondary UC MAC programmed */ + unsigned long vids[BITS_TO_LONGS(VLAN_N_VID)]; + u16 vlans_added; + u32 beacon_state; /* for set_phys_id */ bool eeh_error; @@ -493,7 +483,7 @@ struct be_adapter { bool hw_error; u32 port_num; - bool promiscuous; + char port_name; u8 mc_type; u32 function_mode; u32 function_caps; @@ -526,7 +516,6 @@ struct be_adapter { struct phy_info phy; u8 wol_cap; bool wol_en; - u32 uc_macs; /* Count of secondary UC MAC programmed */ u16 asic_rev; u16 qnq_vid; u32 msg_enable; @@ -732,19 +721,6 @@ static inline bool is_ipv4_pkt(struct sk_buff *skb) return skb->protocol == htons(ETH_P_IP) && ip_hdr(skb)->version == 4; } -static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) -{ - u32 addr; - - addr = jhash(adapter->netdev->dev_addr, ETH_ALEN, 0); - - mac[5] = (u8)(addr & 0xFF); - mac[4] = (u8)((addr >> 8) & 0xFF); - mac[3] = (u8)((addr >> 16) & 0xFF); - /* Use the OUI from the current MAC address */ - memcpy(mac, adapter->netdev->dev_addr, 3); -} - static inline bool be_multi_rxq(const struct be_adapter *adapter) { return adapter->num_rx_qs > 1; @@ -767,129 +743,6 @@ static inline void be_clear_all_error(struct be_adapter *adapter) adapter->fw_timeout = false; } -static inline bool be_is_wol_excluded(struct be_adapter *adapter) -{ - struct pci_dev *pdev = adapter->pdev; - - if (!be_physfn(adapter)) - return true; - - switch (pdev->subsystem_device) { - case OC_SUBSYS_DEVICE_ID1: - case OC_SUBSYS_DEVICE_ID2: - case OC_SUBSYS_DEVICE_ID3: - case OC_SUBSYS_DEVICE_ID4: - return true; - default: - return false; - } -} - -static inline int qnq_async_evt_rcvd(struct be_adapter *adapter) -{ - return adapter->flags & BE_FLAGS_QNQ_ASYNC_EVT_RCVD; -} - -#ifdef CONFIG_NET_RX_BUSY_POLL -static inline bool be_lock_napi(struct be_eq_obj *eqo) -{ - bool status = true; - - spin_lock(&eqo->lock); /* BH is already disabled */ - if (eqo->state & BE_EQ_LOCKED) { - WARN_ON(eqo->state & BE_EQ_NAPI); - eqo->state |= BE_EQ_NAPI_YIELD; - status = false; - } else { - eqo->state = BE_EQ_NAPI; - } - spin_unlock(&eqo->lock); - return status; -} - -static inline void be_unlock_napi(struct be_eq_obj *eqo) -{ - spin_lock(&eqo->lock); /* BH is already disabled */ - - WARN_ON(eqo->state & (BE_EQ_POLL | BE_EQ_NAPI_YIELD)); - eqo->state = BE_EQ_IDLE; - - spin_unlock(&eqo->lock); -} - -static inline bool be_lock_busy_poll(struct be_eq_obj *eqo) -{ - bool status = true; - - spin_lock_bh(&eqo->lock); - if (eqo->state & BE_EQ_LOCKED) { - eqo->state |= BE_EQ_POLL_YIELD; - status = false; - } else { - eqo->state |= BE_EQ_POLL; - } - spin_unlock_bh(&eqo->lock); - return status; -} - -static inline void be_unlock_busy_poll(struct be_eq_obj *eqo) -{ - spin_lock_bh(&eqo->lock); - - WARN_ON(eqo->state & (BE_EQ_NAPI)); - eqo->state = BE_EQ_IDLE; - - spin_unlock_bh(&eqo->lock); -} - -static inline void be_enable_busy_poll(struct be_eq_obj *eqo) -{ - spin_lock_init(&eqo->lock); - eqo->state = BE_EQ_IDLE; -} - -static inline void be_disable_busy_poll(struct be_eq_obj *eqo) -{ - local_bh_disable(); - - /* It's enough to just acquire napi lock on the eqo to stop - * be_busy_poll() from processing any queueus. - */ - while (!be_lock_napi(eqo)) - mdelay(1); - - local_bh_enable(); -} - -#else /* CONFIG_NET_RX_BUSY_POLL */ - -static inline bool be_lock_napi(struct be_eq_obj *eqo) -{ - return true; -} - -static inline void be_unlock_napi(struct be_eq_obj *eqo) -{ -} - -static inline bool be_lock_busy_poll(struct be_eq_obj *eqo) -{ - return false; -} - -static inline void be_unlock_busy_poll(struct be_eq_obj *eqo) -{ -} - -static inline void be_enable_busy_poll(struct be_eq_obj *eqo) -{ -} - -static inline void be_disable_busy_poll(struct be_eq_obj *eqo) -{ -} -#endif /* CONFIG_NET_RX_BUSY_POLL */ - void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped); void be_link_status_update(struct be_adapter *adapter, u8 link_status); @@ -898,16 +751,6 @@ int be_load_fw(struct be_adapter *adapter, u8 *func); bool be_is_wol_supported(struct be_adapter *adapter); bool be_pause_supported(struct be_adapter *adapter); u32 be_get_fw_log_level(struct be_adapter *adapter); - -static inline int fw_major_num(const char *fw_ver) -{ - int fw_major = 0; - - sscanf(fw_ver, "%d.", &fw_major); - - return fw_major; -} - int be_update_queues(struct be_adapter *adapter); int be_poll(struct napi_struct *napi, int budget); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index fead5c65a4f0..36916cfa70f9 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -19,6 +19,22 @@ #include "be.h" #include "be_cmds.h" +static char *be_port_misconfig_evt_desc[] = { + "A valid SFP module detected", + "Optics faulted/ incorrectly installed/ not installed.", + "Optics of two types installed.", + "Incompatible optics.", + "Unknown port SFP status" +}; + +static char *be_port_misconfig_remedy_desc[] = { + "", + "Reseat optics. If issue not resolved, replace", + "Remove one optic or install matching pair of optics", + "Replace with compatible optics for card to function", + "" +}; + static struct be_cmd_priv_map cmd_priv_map[] = { { OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, @@ -249,6 +265,29 @@ static void be_async_link_state_process(struct be_adapter *adapter, evt->port_link_status & LINK_STATUS_MASK); } +static void be_async_port_misconfig_event_process(struct be_adapter *adapter, + struct be_mcc_compl *compl) +{ + struct be_async_event_misconfig_port *evt = + (struct be_async_event_misconfig_port *)compl; + u32 sfp_mismatch_evt = le32_to_cpu(evt->event_data_word1); + struct device *dev = &adapter->pdev->dev; + u8 port_misconfig_evt; + + port_misconfig_evt = + ((sfp_mismatch_evt >> (adapter->hba_port_num * 8)) & 0xff); + + /* Log an error message that would allow a user to determine + * whether the SFPs have an issue + */ + dev_info(dev, "Port %c: %s %s", adapter->port_name, + be_port_misconfig_evt_desc[port_misconfig_evt], + be_port_misconfig_remedy_desc[port_misconfig_evt]); + + if (port_misconfig_evt == INCOMPATIBLE_SFP) + adapter->flags |= BE_FLAGS_EVT_INCOMPATIBLE_SFP; +} + /* Grp5 CoS Priority evt */ static void be_async_grp5_cos_priority_process(struct be_adapter *adapter, struct be_mcc_compl *compl) @@ -334,6 +373,16 @@ static void be_async_dbg_evt_process(struct be_adapter *adapter, } } +static void be_async_sliport_evt_process(struct be_adapter *adapter, + struct be_mcc_compl *cmp) +{ + u8 event_type = (cmp->flags >> ASYNC_EVENT_TYPE_SHIFT) & + ASYNC_EVENT_TYPE_MASK; + + if (event_type == ASYNC_EVENT_PORT_MISCONFIG) + be_async_port_misconfig_event_process(adapter, cmp); +} + static inline bool is_link_state_evt(u32 flags) { return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) == @@ -352,6 +401,12 @@ static inline bool is_dbg_evt(u32 flags) ASYNC_EVENT_CODE_QNQ; } +static inline bool is_sliport_evt(u32 flags) +{ + return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) == + ASYNC_EVENT_CODE_SLIPORT; +} + static void be_mcc_event_process(struct be_adapter *adapter, struct be_mcc_compl *compl) { @@ -361,6 +416,8 @@ static void be_mcc_event_process(struct be_adapter *adapter, be_async_grp5_evt_process(adapter, compl); else if (is_dbg_evt(compl->flags)) be_async_dbg_evt_process(adapter, compl); + else if (is_sliport_evt(compl->flags)) + be_async_sliport_evt_process(adapter, compl); } static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter) @@ -573,7 +630,7 @@ static int lancer_wait_ready(struct be_adapter *adapter) { #define SLIPORT_READY_TIMEOUT 30 u32 sliport_status; - int status = 0, i; + int i; for (i = 0; i < SLIPORT_READY_TIMEOUT; i++) { sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); @@ -584,9 +641,9 @@ static int lancer_wait_ready(struct be_adapter *adapter) } if (i == SLIPORT_READY_TIMEOUT) - status = -1; + return sliport_status ? : -1; - return status; + return 0; } static bool lancer_provisioning_error(struct be_adapter *adapter) @@ -624,7 +681,7 @@ int lancer_test_and_set_rdy_state(struct be_adapter *adapter) iowrite32(SLI_PORT_CONTROL_IP_MASK, adapter->db + SLIPORT_CONTROL_OFFSET); - /* check adapter has corrected the error */ + /* check if adapter has corrected the error */ status = lancer_wait_ready(adapter); sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); @@ -655,7 +712,11 @@ int be_fw_wait_ready(struct be_adapter *adapter) if (lancer_chip(adapter)) { status = lancer_wait_ready(adapter); - return status; + if (status) { + stage = status; + goto err; + } + return 0; } do { @@ -671,7 +732,8 @@ int be_fw_wait_ready(struct be_adapter *adapter) timeout += 2; } while (timeout < 60); - dev_err(dev, "POST timeout; stage=0x%x\n", stage); +err: + dev_err(dev, "POST timeout; stage=%#x\n", stage); return -1; } @@ -1166,9 +1228,15 @@ static int be_cmd_mccq_ext_create(struct be_adapter *adapter, ctxt, 1); } - /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */ - req->async_event_bitmap[0] = cpu_to_le32(0x00000022); - req->async_event_bitmap[0] |= cpu_to_le32(1 << ASYNC_EVENT_CODE_QNQ); + /* Subscribe to Link State, Sliport Event and Group 5 Events + * (bits 1, 5 and 17 set) + */ + req->async_event_bitmap[0] = + cpu_to_le32(BIT(ASYNC_EVENT_CODE_LINK_STATE) | + BIT(ASYNC_EVENT_CODE_GRP_5) | + BIT(ASYNC_EVENT_CODE_QNQ) | + BIT(ASYNC_EVENT_CODE_SLIPORT)); + be_dws_cpu_to_le(ctxt, sizeof(req->context)); be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); @@ -1881,7 +1949,7 @@ err: return status; } -int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) +static int __be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) { struct be_mcc_wrb *wrb; struct be_dma_mem *mem = &adapter->rx_filter; @@ -1901,31 +1969,13 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) wrb, mem); req->if_id = cpu_to_le32(adapter->if_handle); - if (flags & IFF_PROMISC) { - req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS | - BE_IF_FLAGS_VLAN_PROMISCUOUS | - BE_IF_FLAGS_MCAST_PROMISCUOUS); - if (value == ON) - req->if_flags = - cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS | - BE_IF_FLAGS_VLAN_PROMISCUOUS | - BE_IF_FLAGS_MCAST_PROMISCUOUS); - } else if (flags & IFF_ALLMULTI) { - req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS); - req->if_flags = cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS); - } else if (flags & BE_FLAGS_VLAN_PROMISC) { - req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS); + req->if_flags_mask = cpu_to_le32(flags); + req->if_flags = (value == ON) ? req->if_flags_mask : 0; - if (value == ON) - req->if_flags = - cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS); - } else { + if (flags & BE_IF_FLAGS_MULTICAST) { struct netdev_hw_addr *ha; int i = 0; - req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_MULTICAST); - req->if_flags = cpu_to_le32(BE_IF_FLAGS_MULTICAST); - /* Reset mcast promisc mode if already set by setting mask * and not setting flags field */ @@ -1937,24 +1987,26 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) memcpy(req->mcast_mac[i++].byte, ha->addr, ETH_ALEN); } - if ((req->if_flags_mask & cpu_to_le32(be_if_cap_flags(adapter))) != - req->if_flags_mask) { - dev_warn(&adapter->pdev->dev, - "Cannot set rx filter flags 0x%x\n", - req->if_flags_mask); - dev_warn(&adapter->pdev->dev, - "Interface is capable of 0x%x flags only\n", - be_if_cap_flags(adapter)); - } - req->if_flags_mask &= cpu_to_le32(be_if_cap_flags(adapter)); - status = be_mcc_notify_wait(adapter); - err: spin_unlock_bh(&adapter->mcc_lock); return status; } +int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) +{ + struct device *dev = &adapter->pdev->dev; + + if ((flags & be_if_cap_flags(adapter)) != flags) { + dev_warn(dev, "Cannot set rx filter flags 0x%x\n", flags); + dev_warn(dev, "Interface is capable of 0x%x flags only\n", + be_if_cap_flags(adapter)); + } + flags &= be_if_cap_flags(adapter); + + return __be_cmd_rx_filter(adapter, flags, value); +} + /* Uses synchrounous mcc */ int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc) { @@ -2355,6 +2407,24 @@ int be_cmd_query_cable_type(struct be_adapter *adapter) return status; } +int be_cmd_query_sfp_info(struct be_adapter *adapter) +{ + u8 page_data[PAGE_DATA_LEN]; + int status; + + status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, + page_data); + if (!status) { + strlcpy(adapter->phy.vendor_name, page_data + + SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1); + strlcpy(adapter->phy.vendor_pn, + page_data + SFP_VENDOR_PN_OFFSET, + SFP_VENDOR_NAME_LEN - 1); + } + + return status; +} + int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name) { struct lancer_cmd_req_delete_object *req; @@ -2431,7 +2501,8 @@ err_unlock: } int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, - u32 flash_type, u32 flash_opcode, u32 buf_size) + u32 flash_type, u32 flash_opcode, u32 img_offset, + u32 buf_size) { struct be_mcc_wrb *wrb; struct be_cmd_write_flashrom *req; @@ -2452,6 +2523,9 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, cmd); req->params.op_type = cpu_to_le32(flash_type); + if (flash_type == OPTYPE_OFFSET_SPECIFIED) + req->params.offset = cpu_to_le32(img_offset); + req->params.op_code = cpu_to_le32(flash_opcode); req->params.data_buf_size = cpu_to_le32(buf_size); @@ -2472,10 +2546,10 @@ err_unlock: } int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, - u16 optype, int offset) + u16 img_optype, u32 img_offset, u32 crc_offset) { - struct be_mcc_wrb *wrb; struct be_cmd_read_flash_crc *req; + struct be_mcc_wrb *wrb; int status; spin_lock_bh(&adapter->mcc_lock); @@ -2491,9 +2565,13 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, OPCODE_COMMON_READ_FLASHROM, sizeof(*req), wrb, NULL); - req->params.op_type = cpu_to_le32(optype); + req->params.op_type = cpu_to_le32(img_optype); + if (img_optype == OPTYPE_OFFSET_SPECIFIED) + req->params.offset = cpu_to_le32(img_offset + crc_offset); + else + req->params.offset = cpu_to_le32(crc_offset); + req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT); - req->params.offset = cpu_to_le32(offset); req->params.data_buf_size = cpu_to_le32(0x4); status = be_mcc_notify_wait(adapter); @@ -2742,7 +2820,7 @@ err: return status; } -int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain) +static int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain) { struct be_mcc_wrb *wrb; struct be_cmd_req_set_qos *req; @@ -3236,6 +3314,24 @@ err: return status; } +static bool be_is_wol_excluded(struct be_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + + if (!be_physfn(adapter)) + return true; + + switch (pdev->subsystem_device) { + case OC_SUBSYS_DEVICE_ID1: + case OC_SUBSYS_DEVICE_ID2: + case OC_SUBSYS_DEVICE_ID3: + case OC_SUBSYS_DEVICE_ID4: + return true; + default: + return false; + } +} + int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) { struct be_mcc_wrb *wrb; @@ -3422,42 +3518,34 @@ err: return status; } -int be_cmd_query_port_name(struct be_adapter *adapter, u8 *port_name) +int be_cmd_query_port_name(struct be_adapter *adapter) { - struct be_mcc_wrb *wrb; struct be_cmd_req_get_port_name *req; + struct be_mcc_wrb *wrb; int status; - if (!lancer_chip(adapter)) { - *port_name = adapter->hba_port_num + '0'; - return 0; - } - - spin_lock_bh(&adapter->mcc_lock); - - wrb = wrb_from_mccq(adapter); - if (!wrb) { - status = -EBUSY; - goto err; - } + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_PORT_NAME, sizeof(*req), wrb, NULL); - req->hdr.version = 1; + if (!BEx_chip(adapter)) + req->hdr.version = 1; - status = be_mcc_notify_wait(adapter); + status = be_mbox_notify_wait(adapter); if (!status) { struct be_cmd_resp_get_port_name *resp = embedded_payload(wrb); - *port_name = resp->port_name[adapter->hba_port_num]; + adapter->port_name = resp->port_name[adapter->hba_port_num]; } else { - *port_name = adapter->hba_port_num + '0'; + adapter->port_name = adapter->hba_port_num + '0'; } -err: - spin_unlock_bh(&adapter->mcc_lock); + + mutex_unlock(&adapter->mbox_lock); return status; } @@ -3751,6 +3839,7 @@ int be_cmd_config_qos(struct be_adapter *adapter, u32 max_rate, u16 link_speed, be_reset_nic_desc(&nic_desc); nic_desc.pf_num = adapter->pf_number; nic_desc.vf_num = domain; + nic_desc.bw_min = 0; if (lancer_chip(adapter)) { nic_desc.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V0; nic_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V0; @@ -4092,7 +4181,7 @@ int be_cmd_set_logical_link_config(struct be_adapter *adapter, int status; if (BEx_chip(adapter) || lancer_chip(adapter)) - return 0; + return -EOPNOTSUPP; spin_lock_bh(&adapter->mcc_lock); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index eb5085d6794f..db761e8e42a3 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -44,10 +44,10 @@ struct be_mcc_wrb { } payload; }; -#define CQE_FLAGS_VALID_MASK (1 << 31) -#define CQE_FLAGS_ASYNC_MASK (1 << 30) -#define CQE_FLAGS_COMPLETED_MASK (1 << 28) -#define CQE_FLAGS_CONSUMED_MASK (1 << 27) +#define CQE_FLAGS_VALID_MASK BIT(31) +#define CQE_FLAGS_ASYNC_MASK BIT(30) +#define CQE_FLAGS_COMPLETED_MASK BIT(28) +#define CQE_FLAGS_CONSUMED_MASK BIT(27) /* Completion Status */ enum mcc_base_status { @@ -102,6 +102,8 @@ struct be_mcc_compl { #define ASYNC_EVENT_PVID_STATE 0x3 #define ASYNC_EVENT_CODE_QNQ 0x6 #define ASYNC_DEBUG_EVENT_TYPE_QNQ 1 +#define ASYNC_EVENT_CODE_SLIPORT 0x11 +#define ASYNC_EVENT_PORT_MISCONFIG 0x9 enum { LINK_DOWN = 0x0, @@ -169,6 +171,15 @@ struct be_async_event_qnq { u32 flags; } __packed; +#define INCOMPATIBLE_SFP 0x3 +/* async event indicating misconfigured port */ +struct be_async_event_misconfig_port { + u32 event_data_word1; + u32 event_data_word2; + u32 rsvd0; + u32 flags; +} __packed; + struct be_mcc_mailbox { struct be_mcc_wrb wrb; struct be_mcc_compl compl; @@ -586,6 +597,10 @@ enum be_if_flags { BE_IF_FLAGS_PASS_L3L4_ERRORS | BE_IF_FLAGS_MULTICAST |\ BE_IF_FLAGS_UNTAGGED) +#define BE_IF_FLAGS_ALL_PROMISCUOUS (BE_IF_FLAGS_PROMISCUOUS | \ + BE_IF_FLAGS_VLAN_PROMISCUOUS |\ + BE_IF_FLAGS_MCAST_PROMISCUOUS) + /* An RX interface is an object with one or more MAC addresses and * filtering capabilities. */ struct be_cmd_req_if_create { @@ -1024,6 +1039,8 @@ enum { #define SFP_PLUS_SFF_8472_COMP 0x5E #define SFP_PLUS_CABLE_TYPE_OFFSET 0x8 #define SFP_PLUS_COPPER_CABLE 0x4 +#define SFP_VENDOR_NAME_OFFSET 0x14 +#define SFP_VENDOR_PN_OFFSET 0x28 #define PAGE_DATA_LEN 256 struct be_cmd_resp_port_type { @@ -1091,6 +1108,10 @@ struct be_cmd_req_query_fw_cfg { u32 rsvd[31]; }; +/* ASIC revisions */ +#define ASIC_REV_B0 0x10 +#define ASIC_REV_P2 0x11 + struct be_cmd_resp_query_fw_cfg { struct be_cmd_resp_hdr hdr; u32 be_config_number; @@ -1161,7 +1182,173 @@ struct be_cmd_resp_get_beacon_state { u8 rsvd0[3]; } __packed; +/* Flashrom related descriptors */ +#define MAX_FLASH_COMP 32 + +#define OPTYPE_ISCSI_ACTIVE 0 +#define OPTYPE_REDBOOT 1 +#define OPTYPE_BIOS 2 +#define OPTYPE_PXE_BIOS 3 +#define OPTYPE_OFFSET_SPECIFIED 7 +#define OPTYPE_FCOE_BIOS 8 +#define OPTYPE_ISCSI_BACKUP 9 +#define OPTYPE_FCOE_FW_ACTIVE 10 +#define OPTYPE_FCOE_FW_BACKUP 11 +#define OPTYPE_NCSI_FW 13 +#define OPTYPE_REDBOOT_DIR 18 +#define OPTYPE_REDBOOT_CONFIG 19 +#define OPTYPE_SH_PHY_FW 21 +#define OPTYPE_FLASHISM_JUMPVECTOR 22 +#define OPTYPE_UFI_DIR 23 +#define OPTYPE_PHY_FW 99 + +#define FLASH_BIOS_IMAGE_MAX_SIZE_g2 262144 /* Max OPTION ROM image sz */ +#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g2 262144 /* Max Redboot image sz */ +#define FLASH_IMAGE_MAX_SIZE_g2 1310720 /* Max firmware image size */ + +#define FLASH_NCSI_IMAGE_MAX_SIZE_g3 262144 +#define FLASH_PHY_FW_IMAGE_MAX_SIZE_g3 262144 +#define FLASH_BIOS_IMAGE_MAX_SIZE_g3 524288 /* Max OPTION ROM image sz */ +#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g3 1048576 /* Max Redboot image sz */ +#define FLASH_IMAGE_MAX_SIZE_g3 2097152 /* Max firmware image size */ + +/* Offsets for components on Flash. */ +#define FLASH_REDBOOT_START_g2 0 +#define FLASH_FCoE_BIOS_START_g2 524288 +#define FLASH_iSCSI_PRIMARY_IMAGE_START_g2 1048576 +#define FLASH_iSCSI_BACKUP_IMAGE_START_g2 2359296 +#define FLASH_FCoE_PRIMARY_IMAGE_START_g2 3670016 +#define FLASH_FCoE_BACKUP_IMAGE_START_g2 4980736 +#define FLASH_iSCSI_BIOS_START_g2 7340032 +#define FLASH_PXE_BIOS_START_g2 7864320 + +#define FLASH_REDBOOT_START_g3 262144 +#define FLASH_PHY_FW_START_g3 1310720 +#define FLASH_iSCSI_PRIMARY_IMAGE_START_g3 2097152 +#define FLASH_iSCSI_BACKUP_IMAGE_START_g3 4194304 +#define FLASH_FCoE_PRIMARY_IMAGE_START_g3 6291456 +#define FLASH_FCoE_BACKUP_IMAGE_START_g3 8388608 +#define FLASH_iSCSI_BIOS_START_g3 12582912 +#define FLASH_PXE_BIOS_START_g3 13107200 +#define FLASH_FCoE_BIOS_START_g3 13631488 +#define FLASH_NCSI_START_g3 15990784 + +#define IMAGE_NCSI 16 +#define IMAGE_OPTION_ROM_PXE 32 +#define IMAGE_OPTION_ROM_FCoE 33 +#define IMAGE_OPTION_ROM_ISCSI 34 +#define IMAGE_FLASHISM_JUMPVECTOR 48 +#define IMAGE_FIRMWARE_iSCSI 160 +#define IMAGE_FIRMWARE_FCoE 162 +#define IMAGE_FIRMWARE_BACKUP_iSCSI 176 +#define IMAGE_FIRMWARE_BACKUP_FCoE 178 +#define IMAGE_FIRMWARE_PHY 192 +#define IMAGE_REDBOOT_DIR 208 +#define IMAGE_REDBOOT_CONFIG 209 +#define IMAGE_UFI_DIR 210 +#define IMAGE_BOOT_CODE 224 + +struct controller_id { + u32 vendor; + u32 device; + u32 subvendor; + u32 subdevice; +}; + +struct flash_comp { + unsigned long offset; + int optype; + int size; + int img_type; +}; + +struct image_hdr { + u32 imageid; + u32 imageoffset; + u32 imagelength; + u32 image_checksum; + u8 image_version[32]; +}; + +struct flash_file_hdr_g2 { + u8 sign[32]; + u32 cksum; + u32 antidote; + struct controller_id cont_id; + u32 file_len; + u32 chunk_num; + u32 total_chunks; + u32 num_imgs; + u8 build[24]; +}; + +/* First letter of the build version of the image */ +#define BLD_STR_UFI_TYPE_BE2 '2' +#define BLD_STR_UFI_TYPE_BE3 '3' +#define BLD_STR_UFI_TYPE_SH '4' + +struct flash_file_hdr_g3 { + u8 sign[52]; + u8 ufi_version[4]; + u32 file_len; + u32 cksum; + u32 antidote; + u32 num_imgs; + u8 build[24]; + u8 asic_type_rev; + u8 rsvd[31]; +}; + +struct flash_section_hdr { + u32 format_rev; + u32 cksum; + u32 antidote; + u32 num_images; + u8 id_string[128]; + u32 rsvd[4]; +} __packed; + +struct flash_section_hdr_g2 { + u32 format_rev; + u32 cksum; + u32 antidote; + u32 build_num; + u8 id_string[128]; + u32 rsvd[8]; +} __packed; + +struct flash_section_entry { + u32 type; + u32 offset; + u32 pad_size; + u32 image_size; + u32 cksum; + u32 entry_point; + u16 optype; + u16 rsvd0; + u32 rsvd1; + u8 ver_data[32]; +} __packed; + +struct flash_section_info { + u8 cookie[32]; + struct flash_section_hdr fsec_hdr; + struct flash_section_entry fsec_entry[32]; +} __packed; + +struct flash_section_info_g2 { + u8 cookie[32]; + struct flash_section_hdr_g2 fsec_hdr; + struct flash_section_entry fsec_entry[32]; +} __packed; + /****************** Firmware Flash ******************/ +#define FLASHROM_OPER_FLASH 1 +#define FLASHROM_OPER_SAVE 2 +#define FLASHROM_OPER_REPORT 4 +#define FLASHROM_OPER_PHY_FLASH 9 +#define FLASHROM_OPER_PHY_SAVE 10 + struct flashrom_params { u32 op_code; u32 op_type; @@ -1366,6 +1553,7 @@ enum { PHY_TYPE_QSFP, PHY_TYPE_KR4_40GB, PHY_TYPE_KR2_20GB, + PHY_TYPE_TN_8022, PHY_TYPE_DISABLED = 255 }; @@ -1429,6 +1617,20 @@ struct be_cmd_req_set_qos { }; /*********************** Controller Attributes ***********************/ +struct mgmt_hba_attribs { + u32 rsvd0[24]; + u8 controller_model_number[32]; + u32 rsvd1[79]; + u8 rsvd2[3]; + u8 phy_port; + u32 rsvd3[13]; +} __packed; + +struct mgmt_controller_attrib { + struct mgmt_hba_attribs hba_attribs; + u32 rsvd0[10]; +} __packed; + struct be_cmd_req_cntl_attribs { struct be_cmd_req_hdr hdr; }; @@ -2070,8 +2272,10 @@ int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, int be_cmd_read_port_transceiver_data(struct be_adapter *adapter, u8 page_num, u8 *data); int be_cmd_query_cable_type(struct be_adapter *adapter); +int be_cmd_query_sfp_info(struct be_adapter *adapter); int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, - u32 flash_oper, u32 flash_opcode, u32 buf_size); + u32 flash_oper, u32 flash_opcode, u32 img_offset, + u32 buf_size); 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, @@ -2081,7 +2285,7 @@ int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 *data_read, u32 *eof, u8 *addn_status); int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name); int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, - u16 optype, int offset); + u16 img_optype, u32 img_offset, u32 crc_offset); int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, struct be_dma_mem *nonemb_cmd); int be_cmd_fw_init(struct be_adapter *adapter); @@ -2136,7 +2340,7 @@ int lancer_initiate_dump(struct be_adapter *adapter); int lancer_delete_dump(struct be_adapter *adapter); bool dump_present(struct be_adapter *adapter); int lancer_test_and_set_rdy_state(struct be_adapter *adapter); -int be_cmd_query_port_name(struct be_adapter *adapter, u8 *port_name); +int be_cmd_query_port_name(struct be_adapter *adapter); int be_cmd_get_func_config(struct be_adapter *adapter, struct be_resources *res); int be_cmd_get_profile_config(struct be_adapter *adapter, diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 73a500ccbf69..4d2de4700769 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -193,8 +193,6 @@ static const struct be_ethtool_stat et_tx_stats[] = { {DRVSTAT_TX_INFO(tx_pkts)}, /* Number of skbs queued for trasmission by the driver */ {DRVSTAT_TX_INFO(tx_reqs)}, - /* Number of TX work request blocks DMAed to HW */ - {DRVSTAT_TX_INFO(tx_wrbs)}, /* Number of times the TX queue was stopped due to lack * of spaces in the TXQ. */ @@ -707,15 +705,17 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) if (ecmd->autoneg != adapter->phy.fc_autoneg) return -EINVAL; + + status = be_cmd_set_flow_control(adapter, ecmd->tx_pause, + ecmd->rx_pause); + if (status) { + dev_warn(&adapter->pdev->dev, "Pause param set failed\n"); + return be_cmd_status(status); + } + adapter->tx_fc = ecmd->tx_pause; adapter->rx_fc = ecmd->rx_pause; - - status = be_cmd_set_flow_control(adapter, - adapter->tx_fc, adapter->rx_fc); - if (status) - dev_warn(&adapter->pdev->dev, "Pause param set failed\n"); - - return be_cmd_status(status); + return 0; } static int be_set_phys_id(struct net_device *netdev, diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h index 295ee0835ba0..48840889db62 100644 --- a/drivers/net/ethernet/emulex/benet/be_hw.h +++ b/drivers/net/ethernet/emulex/benet/be_hw.h @@ -75,7 +75,7 @@ * atomically without having to arbitrate for the PCI Interrupt Disable bit * with the OS. */ -#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */ +#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK BIT(29) /* bit 29 */ /********* PCI Function Capability *********/ #define BE_FUNCTION_CAPS_RSS 0x2 @@ -171,94 +171,6 @@ #define RETRIEVE_FAT 0 #define QUERY_FAT 1 -/* Flashrom related descriptors */ -#define MAX_FLASH_COMP 32 -#define IMAGE_TYPE_FIRMWARE 160 -#define IMAGE_TYPE_BOOTCODE 224 -#define IMAGE_TYPE_OPTIONROM 32 - -#define NUM_FLASHDIR_ENTRIES 32 - -#define OPTYPE_ISCSI_ACTIVE 0 -#define OPTYPE_REDBOOT 1 -#define OPTYPE_BIOS 2 -#define OPTYPE_PXE_BIOS 3 -#define OPTYPE_FCOE_BIOS 8 -#define OPTYPE_ISCSI_BACKUP 9 -#define OPTYPE_FCOE_FW_ACTIVE 10 -#define OPTYPE_FCOE_FW_BACKUP 11 -#define OPTYPE_NCSI_FW 13 -#define OPTYPE_REDBOOT_DIR 18 -#define OPTYPE_REDBOOT_CONFIG 19 -#define OPTYPE_SH_PHY_FW 21 -#define OPTYPE_FLASHISM_JUMPVECTOR 22 -#define OPTYPE_UFI_DIR 23 -#define OPTYPE_PHY_FW 99 -#define TN_8022 13 - -#define FLASHROM_OPER_PHY_FLASH 9 -#define FLASHROM_OPER_PHY_SAVE 10 -#define FLASHROM_OPER_FLASH 1 -#define FLASHROM_OPER_SAVE 2 -#define FLASHROM_OPER_REPORT 4 - -#define FLASH_IMAGE_MAX_SIZE_g2 (1310720) /* Max firmware image size */ -#define FLASH_BIOS_IMAGE_MAX_SIZE_g2 (262144) /* Max OPTION ROM image sz */ -#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g2 (262144) /* Max Redboot image sz */ -#define FLASH_IMAGE_MAX_SIZE_g3 (2097152) /* Max firmware image size */ -#define FLASH_BIOS_IMAGE_MAX_SIZE_g3 (524288) /* Max OPTION ROM image sz */ -#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g3 (1048576) /* Max Redboot image sz */ -#define FLASH_NCSI_IMAGE_MAX_SIZE_g3 (262144) -#define FLASH_PHY_FW_IMAGE_MAX_SIZE_g3 262144 - -#define FLASH_NCSI_MAGIC (0x16032009) -#define FLASH_NCSI_DISABLED (0) -#define FLASH_NCSI_ENABLED (1) - -#define FLASH_NCSI_BITFILE_HDR_OFFSET (0x600000) - -/* Offsets for components on Flash. */ -#define FLASH_iSCSI_PRIMARY_IMAGE_START_g2 (1048576) -#define FLASH_iSCSI_BACKUP_IMAGE_START_g2 (2359296) -#define FLASH_FCoE_PRIMARY_IMAGE_START_g2 (3670016) -#define FLASH_FCoE_BACKUP_IMAGE_START_g2 (4980736) -#define FLASH_iSCSI_BIOS_START_g2 (7340032) -#define FLASH_PXE_BIOS_START_g2 (7864320) -#define FLASH_FCoE_BIOS_START_g2 (524288) -#define FLASH_REDBOOT_START_g2 (0) - -#define FLASH_NCSI_START_g3 (15990784) -#define FLASH_iSCSI_PRIMARY_IMAGE_START_g3 (2097152) -#define FLASH_iSCSI_BACKUP_IMAGE_START_g3 (4194304) -#define FLASH_FCoE_PRIMARY_IMAGE_START_g3 (6291456) -#define FLASH_FCoE_BACKUP_IMAGE_START_g3 (8388608) -#define FLASH_iSCSI_BIOS_START_g3 (12582912) -#define FLASH_PXE_BIOS_START_g3 (13107200) -#define FLASH_FCoE_BIOS_START_g3 (13631488) -#define FLASH_REDBOOT_START_g3 (262144) -#define FLASH_PHY_FW_START_g3 1310720 - -#define IMAGE_NCSI 16 -#define IMAGE_OPTION_ROM_PXE 32 -#define IMAGE_OPTION_ROM_FCoE 33 -#define IMAGE_OPTION_ROM_ISCSI 34 -#define IMAGE_FLASHISM_JUMPVECTOR 48 -#define IMAGE_FLASH_ISM 49 -#define IMAGE_JUMP_VECTOR 50 -#define IMAGE_FIRMWARE_iSCSI 160 -#define IMAGE_FIRMWARE_COMP_iSCSI 161 -#define IMAGE_FIRMWARE_FCoE 162 -#define IMAGE_FIRMWARE_COMP_FCoE 163 -#define IMAGE_FIRMWARE_BACKUP_iSCSI 176 -#define IMAGE_FIRMWARE_BACKUP_COMP_iSCSI 177 -#define IMAGE_FIRMWARE_BACKUP_FCoE 178 -#define IMAGE_FIRMWARE_BACKUP_COMP_FCoE 179 -#define IMAGE_FIRMWARE_PHY 192 -#define IMAGE_REDBOOT_DIR 208 -#define IMAGE_REDBOOT_CONFIG 209 -#define IMAGE_UFI_DIR 210 -#define IMAGE_BOOT_CODE 224 - /************* Rx Packet Type Encoding **************/ #define BE_UNICAST_PACKET 0 #define BE_MULTICAST_PACKET 1 @@ -281,10 +193,10 @@ struct be_eq_entry { /* TX Queue Descriptor */ #define ETH_WRB_FRAG_LEN_MASK 0xFFFF struct be_eth_wrb { - u32 frag_pa_hi; /* dword 0 */ - u32 frag_pa_lo; /* dword 1 */ - u32 rsvd0; /* dword 2 */ - u32 frag_len; /* dword 3: bits 0 - 15 */ + __le32 frag_pa_hi; /* dword 0 */ + __le32 frag_pa_lo; /* dword 1 */ + u32 rsvd0; /* dword 2 */ + __le32 frag_len; /* dword 3: bits 0 - 15 */ } __packed; /* Pseudo amap definition for eth_hdr_wrb in which each bit of the @@ -311,8 +223,13 @@ struct amap_eth_hdr_wrb { u8 vlan_tag[16]; } __packed; +#define TX_HDR_WRB_COMPL 1 /* word 2 */ +#define TX_HDR_WRB_EVT BIT(1) /* word 2 */ +#define TX_HDR_WRB_NUM_SHIFT 13 /* word 2: bits 13:17 */ +#define TX_HDR_WRB_NUM_MASK 0x1F /* word 2: bits 13:17 */ + struct be_eth_hdr_wrb { - u32 dw[4]; + __le32 dw[4]; }; /********* Tx Compl Status Encoding *********/ @@ -435,138 +352,3 @@ struct amap_eth_rx_compl_v1 { struct be_eth_rx_compl { u32 dw[4]; }; - -struct mgmt_hba_attribs { - u8 flashrom_version_string[32]; - u8 manufacturer_name[32]; - u32 supported_modes; - u32 rsvd0[3]; - u8 ncsi_ver_string[12]; - u32 default_extended_timeout; - u8 controller_model_number[32]; - u8 controller_description[64]; - u8 controller_serial_number[32]; - u8 ip_version_string[32]; - u8 firmware_version_string[32]; - u8 bios_version_string[32]; - u8 redboot_version_string[32]; - u8 driver_version_string[32]; - u8 fw_on_flash_version_string[32]; - u32 functionalities_supported; - u16 max_cdblength; - u8 asic_revision; - u8 generational_guid[16]; - u8 hba_port_count; - u16 default_link_down_timeout; - u8 iscsi_ver_min_max; - u8 multifunction_device; - u8 cache_valid; - u8 hba_status; - u8 max_domains_supported; - u8 phy_port; - u32 firmware_post_status; - u32 hba_mtu[8]; - u32 rsvd1[4]; -}; - -struct mgmt_controller_attrib { - struct mgmt_hba_attribs hba_attribs; - u16 pci_vendor_id; - u16 pci_device_id; - u16 pci_sub_vendor_id; - u16 pci_sub_system_id; - u8 pci_bus_number; - u8 pci_device_number; - u8 pci_function_number; - u8 interface_type; - u64 unique_identifier; - u32 rsvd0[5]; -}; - -struct controller_id { - u32 vendor; - u32 device; - u32 subvendor; - u32 subdevice; -}; - -struct flash_comp { - unsigned long offset; - int optype; - int size; - int img_type; -}; - -struct image_hdr { - u32 imageid; - u32 imageoffset; - u32 imagelength; - u32 image_checksum; - u8 image_version[32]; -}; -struct flash_file_hdr_g2 { - u8 sign[32]; - u32 cksum; - u32 antidote; - struct controller_id cont_id; - u32 file_len; - u32 chunk_num; - u32 total_chunks; - u32 num_imgs; - u8 build[24]; -}; - -struct flash_file_hdr_g3 { - u8 sign[52]; - u8 ufi_version[4]; - u32 file_len; - u32 cksum; - u32 antidote; - u32 num_imgs; - u8 build[24]; - u8 asic_type_rev; - u8 rsvd[31]; -}; - -struct flash_section_hdr { - u32 format_rev; - u32 cksum; - u32 antidote; - u32 num_images; - u8 id_string[128]; - u32 rsvd[4]; -} __packed; - -struct flash_section_hdr_g2 { - u32 format_rev; - u32 cksum; - u32 antidote; - u32 build_num; - u8 id_string[128]; - u32 rsvd[8]; -} __packed; - -struct flash_section_entry { - u32 type; - u32 offset; - u32 pad_size; - u32 image_size; - u32 cksum; - u32 entry_point; - u16 optype; - u16 rsvd0; - u32 rsvd1; - u8 ver_data[32]; -} __packed; - -struct flash_section_info { - u8 cookie[32]; - struct flash_section_hdr fsec_hdr; - struct flash_section_entry fsec_entry[32]; -} __packed; - -struct flash_section_info_g2 { - u8 cookie[32]; - struct flash_section_hdr_g2 fsec_hdr; - struct flash_section_entry fsec_entry[32]; -} __packed; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 41a0a5498da7..932b93a14965 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -662,48 +662,40 @@ void be_link_status_update(struct be_adapter *adapter, u8 link_status) netif_carrier_off(netdev); } -static void be_tx_stats_update(struct be_tx_obj *txo, - u32 wrb_cnt, u32 copied, u32 gso_segs, - bool stopped) +static void be_tx_stats_update(struct be_tx_obj *txo, struct sk_buff *skb) { struct be_tx_stats *stats = tx_stats(txo); u64_stats_update_begin(&stats->sync); stats->tx_reqs++; - stats->tx_wrbs += wrb_cnt; - stats->tx_bytes += copied; - stats->tx_pkts += (gso_segs ? gso_segs : 1); - if (stopped) - stats->tx_stops++; + stats->tx_bytes += skb->len; + stats->tx_pkts += (skb_shinfo(skb)->gso_segs ? : 1); u64_stats_update_end(&stats->sync); } -/* Determine number of WRB entries needed to xmit data in an skb */ -static u32 wrb_cnt_for_skb(struct be_adapter *adapter, struct sk_buff *skb, - bool *dummy) +/* Returns number of WRBs needed for the skb */ +static u32 skb_wrb_cnt(struct sk_buff *skb) { - int cnt = (skb->len > skb->data_len); - - cnt += skb_shinfo(skb)->nr_frags; - - /* to account for hdr wrb */ - cnt++; - if (lancer_chip(adapter) || !(cnt & 1)) { - *dummy = false; - } else { - /* add a dummy to make it an even num */ - cnt++; - *dummy = true; - } - BUG_ON(cnt > BE_MAX_TX_FRAG_COUNT); - return cnt; + /* +1 for the header wrb */ + return 1 + (skb_headlen(skb) ? 1 : 0) + skb_shinfo(skb)->nr_frags; } static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len) { - wrb->frag_pa_hi = upper_32_bits(addr); - wrb->frag_pa_lo = addr & 0xFFFFFFFF; - wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK; + wrb->frag_pa_hi = cpu_to_le32(upper_32_bits(addr)); + wrb->frag_pa_lo = cpu_to_le32(lower_32_bits(addr)); + wrb->frag_len = cpu_to_le32(len & ETH_WRB_FRAG_LEN_MASK); + wrb->rsvd0 = 0; +} + +/* A dummy wrb is just all zeros. Using a separate routine for dummy-wrb + * to avoid the swap and shift/mask operations in wrb_fill(). + */ +static inline void wrb_fill_dummy(struct be_eth_wrb *wrb) +{ + wrb->frag_pa_hi = 0; + wrb->frag_pa_lo = 0; + wrb->frag_len = 0; wrb->rsvd0 = 0; } @@ -713,7 +705,7 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter, u8 vlan_prio; u16 vlan_tag; - vlan_tag = vlan_tx_tag_get(skb); + vlan_tag = skb_vlan_tag_get(skb); vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; /* If vlan priority provided by OS is NOT in available bmap */ if (!(adapter->vlan_prio_bmap & (1 << vlan_prio))) @@ -764,52 +756,57 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, SET_TX_WRB_HDR_BITS(udpcs, hdr, 1); } - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { SET_TX_WRB_HDR_BITS(vlan, hdr, 1); vlan_tag = be_get_tx_vlan_tag(adapter, skb); SET_TX_WRB_HDR_BITS(vlan_tag, hdr, vlan_tag); } - /* To skip HW VLAN tagging: evt = 1, compl = 0 */ - SET_TX_WRB_HDR_BITS(complete, hdr, !skip_hw_vlan); - SET_TX_WRB_HDR_BITS(event, hdr, 1); SET_TX_WRB_HDR_BITS(num_wrb, hdr, wrb_cnt); SET_TX_WRB_HDR_BITS(len, hdr, len); + + /* Hack to skip HW VLAN tagging needs evt = 1, compl = 0 + * When this hack is not needed, the evt bit is set while ringing DB + */ + if (skip_hw_vlan) + SET_TX_WRB_HDR_BITS(event, hdr, 1); } static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb, bool unmap_single) { dma_addr_t dma; + u32 frag_len = le32_to_cpu(wrb->frag_len); - be_dws_le_to_cpu(wrb, sizeof(*wrb)); - dma = (u64)wrb->frag_pa_hi << 32 | (u64)wrb->frag_pa_lo; - if (wrb->frag_len) { + dma = (u64)le32_to_cpu(wrb->frag_pa_hi) << 32 | + (u64)le32_to_cpu(wrb->frag_pa_lo); + if (frag_len) { if (unmap_single) - dma_unmap_single(dev, dma, wrb->frag_len, - DMA_TO_DEVICE); + dma_unmap_single(dev, dma, frag_len, DMA_TO_DEVICE); else - dma_unmap_page(dev, dma, wrb->frag_len, DMA_TO_DEVICE); + dma_unmap_page(dev, dma, frag_len, DMA_TO_DEVICE); } } -static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq, - struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb, - bool skip_hw_vlan) +/* Returns the number of WRBs used up by the skb */ +static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo, + struct sk_buff *skb, bool skip_hw_vlan) { - dma_addr_t busaddr; - int i, copied = 0; + u32 i, copied = 0, wrb_cnt = skb_wrb_cnt(skb); struct device *dev = &adapter->pdev->dev; - struct sk_buff *first_skb = skb; - struct be_eth_wrb *wrb; + struct be_queue_info *txq = &txo->q; struct be_eth_hdr_wrb *hdr; bool map_single = false; - u16 map_head; + struct be_eth_wrb *wrb; + dma_addr_t busaddr; + u16 head = txq->head; hdr = queue_head_node(txq); + wrb_fill_hdr(adapter, hdr, skb, wrb_cnt, skb->len, skip_hw_vlan); + be_dws_cpu_to_le(hdr, sizeof(*hdr)); + queue_head_inc(txq); - map_head = txq->head; if (skb->len > skb->data_len) { int len = skb_headlen(skb); @@ -820,7 +817,6 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq, map_single = true; wrb = queue_head_node(txq); wrb_fill(wrb, busaddr, len); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); queue_head_inc(txq); copied += len; } @@ -834,35 +830,44 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq, goto dma_err; wrb = queue_head_node(txq); wrb_fill(wrb, busaddr, skb_frag_size(frag)); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); queue_head_inc(txq); copied += skb_frag_size(frag); } - if (dummy_wrb) { - wrb = queue_head_node(txq); - wrb_fill(wrb, 0, 0); - be_dws_cpu_to_le(wrb, sizeof(*wrb)); - queue_head_inc(txq); - } + BUG_ON(txo->sent_skb_list[head]); + txo->sent_skb_list[head] = skb; + txo->last_req_hdr = head; + atomic_add(wrb_cnt, &txq->used); + txo->last_req_wrb_cnt = wrb_cnt; + txo->pend_wrb_cnt += wrb_cnt; - wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied, skip_hw_vlan); - be_dws_cpu_to_le(hdr, sizeof(*hdr)); + be_tx_stats_update(txo, skb); + return wrb_cnt; - return copied; dma_err: - txq->head = map_head; + /* Bring the queue back to the state it was in before this + * routine was invoked. + */ + txq->head = head; + /* skip the first wrb (hdr); it's not mapped */ + queue_head_inc(txq); while (copied) { wrb = queue_head_node(txq); unmap_tx_frag(dev, wrb, map_single); map_single = false; - copied -= wrb->frag_len; + copied -= le32_to_cpu(wrb->frag_len); adapter->drv_stats.dma_map_errors++; queue_head_inc(txq); } + txq->head = head; return 0; } +static inline int qnq_async_evt_rcvd(struct be_adapter *adapter) +{ + return adapter->flags & BE_FLAGS_QNQ_ASYNC_EVT_RCVD; +} + static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, struct sk_buff *skb, bool *skip_hw_vlan) @@ -873,7 +878,7 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, if (unlikely(!skb)) return skb; - if (vlan_tx_tag_present(skb)) + if (skb_vlan_tag_present(skb)) vlan_tag = be_get_tx_vlan_tag(adapter, skb); if (qnq_async_evt_rcvd(adapter) && adapter->pvid) { @@ -932,7 +937,7 @@ static bool be_ipv6_exthdr_check(struct sk_buff *skb) static int be_vlan_tag_tx_chk(struct be_adapter *adapter, struct sk_buff *skb) { - return vlan_tx_tag_present(skb) || adapter->pvid || adapter->qnq_vid; + return skb_vlan_tag_present(skb) || adapter->pvid || adapter->qnq_vid; } static int be_ipv6_tx_stall_chk(struct be_adapter *adapter, struct sk_buff *skb) @@ -955,7 +960,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ? VLAN_ETH_HLEN : ETH_HLEN; if (skb->len <= 60 && - (lancer_chip(adapter) || vlan_tx_tag_present(skb)) && + (lancer_chip(adapter) || skb_vlan_tag_present(skb)) && is_ipv4_pkt(skb)) { ip = (struct iphdr *)ip_hdr(skb); pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len)); @@ -973,7 +978,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, * Manually insert VLAN in pkt. */ if (skb->ip_summed != CHECKSUM_PARTIAL && - vlan_tx_tag_present(skb)) { + skb_vlan_tag_present(skb)) { skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan); if (unlikely(!skb)) goto err; @@ -1030,52 +1035,64 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, return skb; } +static void be_xmit_flush(struct be_adapter *adapter, struct be_tx_obj *txo) +{ + struct be_queue_info *txq = &txo->q; + struct be_eth_hdr_wrb *hdr = queue_index_node(txq, txo->last_req_hdr); + + /* Mark the last request eventable if it hasn't been marked already */ + if (!(hdr->dw[2] & cpu_to_le32(TX_HDR_WRB_EVT))) + hdr->dw[2] |= cpu_to_le32(TX_HDR_WRB_EVT | TX_HDR_WRB_COMPL); + + /* compose a dummy wrb if there are odd set of wrbs to notify */ + if (!lancer_chip(adapter) && (txo->pend_wrb_cnt & 1)) { + wrb_fill_dummy(queue_head_node(txq)); + queue_head_inc(txq); + atomic_inc(&txq->used); + txo->pend_wrb_cnt++; + hdr->dw[2] &= ~cpu_to_le32(TX_HDR_WRB_NUM_MASK << + TX_HDR_WRB_NUM_SHIFT); + hdr->dw[2] |= cpu_to_le32((txo->last_req_wrb_cnt + 1) << + TX_HDR_WRB_NUM_SHIFT); + } + be_txq_notify(adapter, txo, txo->pend_wrb_cnt); + txo->pend_wrb_cnt = 0; +} + static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) { + bool skip_hw_vlan = false, flush = !skb->xmit_more; struct be_adapter *adapter = netdev_priv(netdev); - struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)]; + u16 q_idx = skb_get_queue_mapping(skb); + struct be_tx_obj *txo = &adapter->tx_obj[q_idx]; struct be_queue_info *txq = &txo->q; - bool dummy_wrb, stopped = false; - u32 wrb_cnt = 0, copied = 0; - bool skip_hw_vlan = false; - u32 start = txq->head; + u16 wrb_cnt; skb = be_xmit_workarounds(adapter, skb, &skip_hw_vlan); - if (!skb) { - tx_stats(txo)->tx_drv_drops++; - return NETDEV_TX_OK; - } + if (unlikely(!skb)) + goto drop; - wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb); - - copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb, - skip_hw_vlan); - if (copied) { - int gso_segs = skb_shinfo(skb)->gso_segs; - - /* record the sent skb in the sent_skb table */ - BUG_ON(txo->sent_skb_list[start]); - txo->sent_skb_list[start] = skb; - - /* Ensure txq has space for the next skb; Else stop the queue - * *BEFORE* ringing the tx doorbell, so that we serialze the - * tx compls of the current transmit which'll wake up the queue - */ - atomic_add(wrb_cnt, &txq->used); - if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >= - txq->len) { - netif_stop_subqueue(netdev, skb_get_queue_mapping(skb)); - stopped = true; - } - - be_txq_notify(adapter, txo, wrb_cnt); - - be_tx_stats_update(txo, wrb_cnt, copied, gso_segs, stopped); - } else { - txq->head = start; - tx_stats(txo)->tx_drv_drops++; + wrb_cnt = be_xmit_enqueue(adapter, txo, skb, skip_hw_vlan); + if (unlikely(!wrb_cnt)) { dev_kfree_skb_any(skb); + goto drop; } + + if ((atomic_read(&txq->used) + BE_MAX_TX_FRAG_COUNT) >= txq->len) { + netif_stop_subqueue(netdev, q_idx); + tx_stats(txo)->tx_stops++; + } + + if (flush || __netif_subqueue_stopped(netdev, q_idx)) + be_xmit_flush(adapter, txo); + + return NETDEV_TX_OK; +drop: + tx_stats(txo)->tx_drv_drops++; + /* Flush the already enqueued tx requests */ + if (flush && txo->pend_wrb_cnt) + be_xmit_flush(adapter, txo); + return NETDEV_TX_OK; } @@ -1096,6 +1113,43 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu) return 0; } +static inline bool be_in_all_promisc(struct be_adapter *adapter) +{ + return (adapter->if_flags & BE_IF_FLAGS_ALL_PROMISCUOUS) == + BE_IF_FLAGS_ALL_PROMISCUOUS; +} + +static int be_set_vlan_promisc(struct be_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + int status; + + if (adapter->if_flags & BE_IF_FLAGS_VLAN_PROMISCUOUS) + return 0; + + status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_VLAN_PROMISCUOUS, ON); + if (!status) { + dev_info(dev, "Enabled VLAN promiscuous mode\n"); + adapter->if_flags |= BE_IF_FLAGS_VLAN_PROMISCUOUS; + } else { + dev_err(dev, "Failed to enable VLAN promiscuous mode\n"); + } + return status; +} + +static int be_clear_vlan_promisc(struct be_adapter *adapter) +{ + struct device *dev = &adapter->pdev->dev; + int status; + + status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_VLAN_PROMISCUOUS, OFF); + if (!status) { + dev_info(dev, "Disabling VLAN promiscuous mode\n"); + adapter->if_flags &= ~BE_IF_FLAGS_VLAN_PROMISCUOUS; + } + return status; +} + /* * A max of 64 (BE_NUM_VLANS_SUPPORTED) vlans can be configured in BE. * If the user configures more, place BE in vlan promiscuous mode. @@ -1108,11 +1162,11 @@ static int be_vid_config(struct be_adapter *adapter) int status = 0; /* No need to further configure vids if in promiscuous mode */ - if (adapter->promiscuous) + if (be_in_all_promisc(adapter)) return 0; if (adapter->vlans_added > be_max_vlans(adapter)) - goto set_vlan_promisc; + return be_set_vlan_promisc(adapter); /* Construct VLAN Table to give to HW */ for_each_set_bit(i, adapter->vids, VLAN_N_VID) @@ -1120,36 +1174,14 @@ static int be_vid_config(struct be_adapter *adapter) status = be_cmd_vlan_config(adapter, adapter->if_handle, vids, num); if (status) { + dev_err(dev, "Setting HW VLAN filtering failed\n"); /* Set to VLAN promisc mode as setting VLAN filter failed */ if (addl_status(status) == MCC_ADDL_STATUS_INSUFFICIENT_RESOURCES) - goto set_vlan_promisc; - dev_err(dev, "Setting HW VLAN filtering failed\n"); - } else { - if (adapter->flags & BE_FLAGS_VLAN_PROMISC) { - /* hw VLAN filtering re-enabled. */ - status = be_cmd_rx_filter(adapter, - BE_FLAGS_VLAN_PROMISC, OFF); - if (!status) { - dev_info(dev, - "Disabling VLAN Promiscuous mode\n"); - adapter->flags &= ~BE_FLAGS_VLAN_PROMISC; - } - } + return be_set_vlan_promisc(adapter); + } else if (adapter->if_flags & BE_IF_FLAGS_VLAN_PROMISCUOUS) { + status = be_clear_vlan_promisc(adapter); } - - return status; - -set_vlan_promisc: - if (adapter->flags & BE_FLAGS_VLAN_PROMISC) - return 0; - - status = be_cmd_rx_filter(adapter, BE_FLAGS_VLAN_PROMISC, ON); - if (!status) { - dev_info(dev, "Enable VLAN Promiscuous mode\n"); - adapter->flags |= BE_FLAGS_VLAN_PROMISC; - } else - dev_err(dev, "Failed to enable VLAN Promiscuous mode\n"); return status; } @@ -1191,79 +1223,99 @@ static int be_vlan_rem_vid(struct net_device *netdev, __be16 proto, u16 vid) return be_vid_config(adapter); } -static void be_clear_promisc(struct be_adapter *adapter) +static void be_clear_all_promisc(struct be_adapter *adapter) { - adapter->promiscuous = false; - adapter->flags &= ~(BE_FLAGS_VLAN_PROMISC | BE_FLAGS_MCAST_PROMISC); + be_cmd_rx_filter(adapter, BE_IF_FLAGS_ALL_PROMISCUOUS, OFF); + adapter->if_flags &= ~BE_IF_FLAGS_ALL_PROMISCUOUS; +} - be_cmd_rx_filter(adapter, IFF_PROMISC, OFF); +static void be_set_all_promisc(struct be_adapter *adapter) +{ + be_cmd_rx_filter(adapter, BE_IF_FLAGS_ALL_PROMISCUOUS, ON); + adapter->if_flags |= BE_IF_FLAGS_ALL_PROMISCUOUS; +} + +static void be_set_mc_promisc(struct be_adapter *adapter) +{ + int status; + + if (adapter->if_flags & BE_IF_FLAGS_MCAST_PROMISCUOUS) + return; + + status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_MCAST_PROMISCUOUS, ON); + if (!status) + adapter->if_flags |= BE_IF_FLAGS_MCAST_PROMISCUOUS; +} + +static void be_set_mc_list(struct be_adapter *adapter) +{ + int status; + + status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_MULTICAST, ON); + if (!status) + adapter->if_flags &= ~BE_IF_FLAGS_MCAST_PROMISCUOUS; + else + be_set_mc_promisc(adapter); +} + +static void be_set_uc_list(struct be_adapter *adapter) +{ + struct netdev_hw_addr *ha; + int i = 1; /* First slot is claimed by the Primary MAC */ + + for (; adapter->uc_macs > 0; adapter->uc_macs--, i++) + be_cmd_pmac_del(adapter, adapter->if_handle, + adapter->pmac_id[i], 0); + + if (netdev_uc_count(adapter->netdev) > be_max_uc(adapter)) { + be_set_all_promisc(adapter); + return; + } + + netdev_for_each_uc_addr(ha, adapter->netdev) { + adapter->uc_macs++; /* First slot is for Primary MAC */ + be_cmd_pmac_add(adapter, (u8 *)ha->addr, adapter->if_handle, + &adapter->pmac_id[adapter->uc_macs], 0); + } +} + +static void be_clear_uc_list(struct be_adapter *adapter) +{ + int i; + + for (i = 1; i < (adapter->uc_macs + 1); i++) + be_cmd_pmac_del(adapter, adapter->if_handle, + adapter->pmac_id[i], 0); + adapter->uc_macs = 0; } static void be_set_rx_mode(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); - int status; if (netdev->flags & IFF_PROMISC) { - be_cmd_rx_filter(adapter, IFF_PROMISC, ON); - adapter->promiscuous = true; - goto done; + be_set_all_promisc(adapter); + return; } - /* BE was previously in promiscuous mode; disable it */ - if (adapter->promiscuous) { - be_clear_promisc(adapter); + /* Interface was previously in promiscuous mode; disable it */ + if (be_in_all_promisc(adapter)) { + be_clear_all_promisc(adapter); if (adapter->vlans_added) be_vid_config(adapter); } /* Enable multicast promisc if num configured exceeds what we support */ if (netdev->flags & IFF_ALLMULTI || - netdev_mc_count(netdev) > be_max_mc(adapter)) - goto set_mcast_promisc; - - if (netdev_uc_count(netdev) != adapter->uc_macs) { - struct netdev_hw_addr *ha; - int i = 1; /* First slot is claimed by the Primary MAC */ - - for (; adapter->uc_macs > 0; adapter->uc_macs--, i++) { - be_cmd_pmac_del(adapter, adapter->if_handle, - adapter->pmac_id[i], 0); - } - - if (netdev_uc_count(netdev) > be_max_uc(adapter)) { - be_cmd_rx_filter(adapter, IFF_PROMISC, ON); - adapter->promiscuous = true; - goto done; - } - - netdev_for_each_uc_addr(ha, adapter->netdev) { - adapter->uc_macs++; /* First slot is for Primary MAC */ - be_cmd_pmac_add(adapter, (u8 *)ha->addr, - adapter->if_handle, - &adapter->pmac_id[adapter->uc_macs], 0); - } - } - - status = be_cmd_rx_filter(adapter, IFF_MULTICAST, ON); - if (!status) { - if (adapter->flags & BE_FLAGS_MCAST_PROMISC) - adapter->flags &= ~BE_FLAGS_MCAST_PROMISC; - goto done; - } - -set_mcast_promisc: - if (adapter->flags & BE_FLAGS_MCAST_PROMISC) + netdev_mc_count(netdev) > be_max_mc(adapter)) { + be_set_mc_promisc(adapter); return; + } - /* Set to MCAST promisc mode if setting MULTICAST address fails - * or if num configured exceeds what we support - */ - status = be_cmd_rx_filter(adapter, IFF_ALLMULTI, ON); - if (!status) - adapter->flags |= BE_FLAGS_MCAST_PROMISC; -done: - return; + if (netdev_uc_count(netdev) != adapter->uc_macs) + be_set_uc_list(adapter); + + be_set_mc_list(adapter); } static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) @@ -1959,32 +2011,34 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq) static u16 be_tx_compl_process(struct be_adapter *adapter, struct be_tx_obj *txo, u16 last_index) { - struct be_queue_info *txq = &txo->q; - struct be_eth_wrb *wrb; struct sk_buff **sent_skbs = txo->sent_skb_list; - struct sk_buff *sent_skb; - u16 cur_index, num_wrbs = 1; /* account for hdr wrb */ - bool unmap_skb_hdr = true; - - sent_skb = sent_skbs[txq->tail]; - BUG_ON(!sent_skb); - sent_skbs[txq->tail] = NULL; - - /* skip header wrb */ - queue_tail_inc(txq); + struct be_queue_info *txq = &txo->q; + u16 frag_index, num_wrbs = 0; + struct sk_buff *skb = NULL; + bool unmap_skb_hdr = false; + struct be_eth_wrb *wrb; do { - cur_index = txq->tail; + if (sent_skbs[txq->tail]) { + /* Free skb from prev req */ + if (skb) + dev_consume_skb_any(skb); + skb = sent_skbs[txq->tail]; + sent_skbs[txq->tail] = NULL; + queue_tail_inc(txq); /* skip hdr wrb */ + num_wrbs++; + unmap_skb_hdr = true; + } wrb = queue_tail_node(txq); + frag_index = txq->tail; unmap_tx_frag(&adapter->pdev->dev, wrb, - (unmap_skb_hdr && skb_headlen(sent_skb))); + (unmap_skb_hdr && skb_headlen(skb))); unmap_skb_hdr = false; - - num_wrbs++; queue_tail_inc(txq); - } while (cur_index != last_index); + num_wrbs++; + } while (frag_index != last_index); + dev_consume_skb_any(skb); - dev_consume_skb_any(sent_skb); return num_wrbs; } @@ -2068,12 +2122,11 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo) static void be_tx_compl_clean(struct be_adapter *adapter) { + u16 end_idx, notified_idx, cmpl = 0, timeo = 0, num_wrbs = 0; + struct device *dev = &adapter->pdev->dev; struct be_tx_obj *txo; struct be_queue_info *txq; struct be_eth_tx_compl *txcp; - u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0; - struct sk_buff *sent_skb; - bool dummy_wrb; int i, pending_txqs; /* Stop polling for compls when HW has been silent for 10ms */ @@ -2095,7 +2148,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter) atomic_sub(num_wrbs, &txq->used); timeo = 0; } - if (atomic_read(&txq->used) == 0) + if (atomic_read(&txq->used) == txo->pend_wrb_cnt) pending_txqs--; } @@ -2105,21 +2158,29 @@ static void be_tx_compl_clean(struct be_adapter *adapter) mdelay(1); } while (true); + /* Free enqueued TX that was never notified to HW */ for_all_tx_queues(adapter, txo, i) { txq = &txo->q; - if (atomic_read(&txq->used)) - dev_err(&adapter->pdev->dev, "%d pending tx-compls\n", - atomic_read(&txq->used)); - /* free posted tx for which compls will never arrive */ - while (atomic_read(&txq->used)) { - sent_skb = txo->sent_skb_list[txq->tail]; + if (atomic_read(&txq->used)) { + dev_info(dev, "txq%d: cleaning %d pending tx-wrbs\n", + i, atomic_read(&txq->used)); + notified_idx = txq->tail; end_idx = txq->tail; - num_wrbs = wrb_cnt_for_skb(adapter, sent_skb, - &dummy_wrb); - index_adv(&end_idx, num_wrbs - 1, txq->len); + index_adv(&end_idx, atomic_read(&txq->used) - 1, + txq->len); + /* Use the tx-compl process logic to handle requests + * that were not sent to the HW. + */ num_wrbs = be_tx_compl_process(adapter, txo, end_idx); atomic_sub(num_wrbs, &txq->used); + BUG_ON(atomic_read(&txq->used)); + txo->pend_wrb_cnt = 0; + /* Since hw was never notified of these requests, + * reset TXQ indices + */ + txq->head = notified_idx; + txq->tail = notified_idx; } } } @@ -2514,6 +2575,106 @@ static void be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo, } } +#ifdef CONFIG_NET_RX_BUSY_POLL +static inline bool be_lock_napi(struct be_eq_obj *eqo) +{ + bool status = true; + + spin_lock(&eqo->lock); /* BH is already disabled */ + if (eqo->state & BE_EQ_LOCKED) { + WARN_ON(eqo->state & BE_EQ_NAPI); + eqo->state |= BE_EQ_NAPI_YIELD; + status = false; + } else { + eqo->state = BE_EQ_NAPI; + } + spin_unlock(&eqo->lock); + return status; +} + +static inline void be_unlock_napi(struct be_eq_obj *eqo) +{ + spin_lock(&eqo->lock); /* BH is already disabled */ + + WARN_ON(eqo->state & (BE_EQ_POLL | BE_EQ_NAPI_YIELD)); + eqo->state = BE_EQ_IDLE; + + spin_unlock(&eqo->lock); +} + +static inline bool be_lock_busy_poll(struct be_eq_obj *eqo) +{ + bool status = true; + + spin_lock_bh(&eqo->lock); + if (eqo->state & BE_EQ_LOCKED) { + eqo->state |= BE_EQ_POLL_YIELD; + status = false; + } else { + eqo->state |= BE_EQ_POLL; + } + spin_unlock_bh(&eqo->lock); + return status; +} + +static inline void be_unlock_busy_poll(struct be_eq_obj *eqo) +{ + spin_lock_bh(&eqo->lock); + + WARN_ON(eqo->state & (BE_EQ_NAPI)); + eqo->state = BE_EQ_IDLE; + + spin_unlock_bh(&eqo->lock); +} + +static inline void be_enable_busy_poll(struct be_eq_obj *eqo) +{ + spin_lock_init(&eqo->lock); + eqo->state = BE_EQ_IDLE; +} + +static inline void be_disable_busy_poll(struct be_eq_obj *eqo) +{ + local_bh_disable(); + + /* It's enough to just acquire napi lock on the eqo to stop + * be_busy_poll() from processing any queueus. + */ + while (!be_lock_napi(eqo)) + mdelay(1); + + local_bh_enable(); +} + +#else /* CONFIG_NET_RX_BUSY_POLL */ + +static inline bool be_lock_napi(struct be_eq_obj *eqo) +{ + return true; +} + +static inline void be_unlock_napi(struct be_eq_obj *eqo) +{ +} + +static inline bool be_lock_busy_poll(struct be_eq_obj *eqo) +{ + return false; +} + +static inline void be_unlock_busy_poll(struct be_eq_obj *eqo) +{ +} + +static inline void be_enable_busy_poll(struct be_eq_obj *eqo) +{ +} + +static inline void be_disable_busy_poll(struct be_eq_obj *eqo) +{ +} +#endif /* CONFIG_NET_RX_BUSY_POLL */ + int be_poll(struct napi_struct *napi, int budget) { struct be_eq_obj *eqo = container_of(napi, struct be_eq_obj, napi); @@ -2833,11 +2994,7 @@ static int be_close(struct net_device *netdev) be_tx_compl_clean(adapter); be_rx_qs_destroy(adapter); - - for (i = 1; i < (adapter->uc_macs + 1); i++) - be_cmd_pmac_del(adapter, adapter->if_handle, - adapter->pmac_id[i], 0); - adapter->uc_macs = 0; + be_clear_uc_list(adapter); for_all_evt_queues(adapter, eqo, i) { if (msix_enabled(adapter)) @@ -3008,6 +3165,19 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable) return status; } +static void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) +{ + u32 addr; + + addr = jhash(adapter->netdev->dev_addr, ETH_ALEN, 0); + + mac[5] = (u8)(addr & 0xFF); + mac[4] = (u8)((addr >> 8) & 0xFF); + mac[3] = (u8)((addr >> 16) & 0xFF); + /* Use the OUI from the current MAC address */ + memcpy(mac, adapter->netdev->dev_addr, 3); +} + /* * Generate a seed MAC address from the PF MAC Address using jhash. * MAC Address for VFs are assigned incrementally starting from the seed. @@ -3108,14 +3278,9 @@ static void be_cancel_worker(struct be_adapter *adapter) static void be_mac_clear(struct be_adapter *adapter) { - int i; - if (adapter->pmac_id) { - for (i = 0; i < (adapter->uc_macs + 1); i++) - be_cmd_pmac_del(adapter, adapter->if_handle, - adapter->pmac_id[i], 0); - adapter->uc_macs = 0; - + be_cmd_pmac_del(adapter, adapter->if_handle, + adapter->pmac_id[0], 0); kfree(adapter->pmac_id); adapter->pmac_id = NULL; } @@ -3171,13 +3336,32 @@ static int be_clear(struct be_adapter *adapter) return 0; } +static int be_if_create(struct be_adapter *adapter, u32 *if_handle, + u32 cap_flags, u32 vf) +{ + u32 en_flags; + int status; + + en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | + BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS | + BE_IF_FLAGS_RSS; + + en_flags &= cap_flags; + + status = be_cmd_if_create(adapter, cap_flags, en_flags, + if_handle, vf); + + return status; +} + static int be_vfs_if_create(struct be_adapter *adapter) { struct be_resources res = {0}; struct be_vf_cfg *vf_cfg; - u32 cap_flags, en_flags, vf; - int status = 0; + u32 cap_flags, vf; + int status; + /* If a FW profile exists, then cap_flags are updated */ cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_MULTICAST; @@ -3189,18 +3373,13 @@ static int be_vfs_if_create(struct be_adapter *adapter) cap_flags = res.if_cap_flags; } - /* If a FW profile exists, then cap_flags are updated */ - en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED | - BE_IF_FLAGS_BROADCAST | - BE_IF_FLAGS_MULTICAST); - status = - be_cmd_if_create(adapter, cap_flags, en_flags, - &vf_cfg->if_handle, vf + 1); + status = be_if_create(adapter, &vf_cfg->if_handle, + cap_flags, vf + 1); if (status) - goto err; + return status; } -err: - return status; + + return 0; } static int be_vf_setup_init(struct be_adapter *adapter) @@ -3385,7 +3564,7 @@ static void be_setup_init(struct be_adapter *adapter) adapter->phy.link_speed = -1; adapter->if_handle = -1; adapter->be3_native = false; - adapter->promiscuous = false; + adapter->if_flags = 0; if (be_physfn(adapter)) adapter->cmd_privileges = MAX_PRIVILEGES; else @@ -3512,7 +3691,9 @@ static int be_get_config(struct be_adapter *adapter) if (status) return status; - if (be_physfn(adapter)) { + be_cmd_query_port_name(adapter); + + if (be_physfn(adapter)) { status = be_cmd_get_active_profile(adapter, &profile_id); if (!status) dev_info(&adapter->pdev->dev, @@ -3638,10 +3819,20 @@ int be_update_queues(struct be_adapter *adapter) return status; } +static inline int fw_major_num(const char *fw_ver) +{ + int fw_major = 0, i; + + i = sscanf(fw_ver, "%d.", &fw_major); + if (i != 1) + return 0; + + return fw_major; +} + static int be_setup(struct be_adapter *adapter) { struct device *dev = &adapter->pdev->dev; - u32 tx_fc, rx_fc, en_flags; int status; be_setup_init(adapter); @@ -3657,13 +3848,8 @@ static int be_setup(struct be_adapter *adapter) if (status) goto err; - en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | - BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS; - if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) - en_flags |= BE_IF_FLAGS_RSS; - en_flags = en_flags & be_if_cap_flags(adapter); - status = be_cmd_if_create(adapter, be_if_cap_flags(adapter), en_flags, - &adapter->if_handle, 0); + status = be_if_create(adapter, &adapter->if_handle, + be_if_cap_flags(adapter), 0); if (status) goto err; @@ -3696,11 +3882,14 @@ static int be_setup(struct be_adapter *adapter) be_cmd_get_acpi_wol_cap(adapter); - be_cmd_get_flow_control(adapter, &tx_fc, &rx_fc); + status = be_cmd_set_flow_control(adapter, adapter->tx_fc, + adapter->rx_fc); + if (status) + be_cmd_get_flow_control(adapter, &adapter->tx_fc, + &adapter->rx_fc); - if (rx_fc != adapter->rx_fc || tx_fc != adapter->tx_fc) - be_cmd_set_flow_control(adapter, adapter->tx_fc, - adapter->rx_fc); + dev_info(&adapter->pdev->dev, "HW Flow control - TX:%d RX:%d\n", + adapter->tx_fc, adapter->rx_fc); if (be_physfn(adapter)) be_cmd_set_logical_link_config(adapter, @@ -3739,7 +3928,7 @@ static char flash_cookie[2][16] = {"*** SE FLAS", "H DIRECTORY *** "}; static bool phy_flashing_required(struct be_adapter *adapter) { - return (adapter->phy.phy_type == TN_8022 && + return (adapter->phy.phy_type == PHY_TYPE_TN_8022 && adapter->phy.interface_type == PHY_TYPE_BASET_10GB); } @@ -3790,7 +3979,8 @@ static int be_check_flash_crc(struct be_adapter *adapter, const u8 *p, int status; u8 crc[4]; - status = be_cmd_get_flash_crc(adapter, crc, img_optype, img_size - 4); + status = be_cmd_get_flash_crc(adapter, crc, img_optype, img_offset, + img_size - 4); if (status) return status; @@ -3806,13 +3996,13 @@ static int be_check_flash_crc(struct be_adapter *adapter, const u8 *p, } static int be_flash(struct be_adapter *adapter, const u8 *img, - struct be_dma_mem *flash_cmd, int optype, int img_size) + struct be_dma_mem *flash_cmd, int optype, int img_size, + u32 img_offset) { + u32 flash_op, num_bytes, total_bytes = img_size, bytes_sent = 0; struct be_cmd_write_flashrom *req = flash_cmd->va; - u32 total_bytes, flash_op, num_bytes; int status; - total_bytes = img_size; while (total_bytes) { num_bytes = min_t(u32, 32*1024, total_bytes); @@ -3833,12 +4023,15 @@ static int be_flash(struct be_adapter *adapter, const u8 *img, memcpy(req->data_buf, img, num_bytes); img += num_bytes; status = be_cmd_write_flashrom(adapter, flash_cmd, optype, - flash_op, num_bytes); + flash_op, img_offset + + bytes_sent, num_bytes); if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST && optype == OPTYPE_PHY_FW) break; else if (status) return status; + + bytes_sent += num_bytes; } return 0; } @@ -3906,6 +4099,7 @@ static int be_flash_BEx(struct be_adapter *adapter, pflashcomp = gen2_flash_types; filehdr_size = sizeof(struct flash_file_hdr_g2); num_comp = ARRAY_SIZE(gen2_flash_types); + img_hdrs_size = 0; } /* Get flash section info*/ @@ -3950,7 +4144,7 @@ static int be_flash_BEx(struct be_adapter *adapter, return -1; status = be_flash(adapter, p, flash_cmd, pflashcomp[i].optype, - pflashcomp[i].size); + pflashcomp[i].size, 0); if (status) { dev_err(dev, "Flashing section type 0x%x failed\n", pflashcomp[i].img_type); @@ -4017,12 +4211,12 @@ static int be_flash_skyhawk(struct be_adapter *adapter, struct be_dma_mem *flash_cmd, int num_of_images) { int img_hdrs_size = num_of_images * sizeof(struct image_hdr); + bool crc_match, old_fw_img, flash_offset_support = true; struct device *dev = &adapter->pdev->dev; struct flash_section_info *fsec = NULL; u32 img_offset, img_size, img_type; + u16 img_optype, flash_optype; int status, i, filehdr_size; - bool crc_match, old_fw_img; - u16 img_optype; const u8 *p; filehdr_size = sizeof(struct flash_file_hdr_g3); @@ -4032,6 +4226,7 @@ static int be_flash_skyhawk(struct be_adapter *adapter, return -EINVAL; } +retry_flash: for (i = 0; i < le32_to_cpu(fsec->fsec_hdr.num_images); i++) { img_offset = le32_to_cpu(fsec->fsec_entry[i].offset); img_size = le32_to_cpu(fsec->fsec_entry[i].pad_size); @@ -4041,6 +4236,12 @@ static int be_flash_skyhawk(struct be_adapter *adapter, if (img_optype == 0xFFFF) continue; + + if (flash_offset_support) + flash_optype = OPTYPE_OFFSET_SPECIFIED; + else + flash_optype = img_optype; + /* Don't bother verifying CRC if an old FW image is being * flashed */ @@ -4049,16 +4250,26 @@ static int be_flash_skyhawk(struct be_adapter *adapter, status = be_check_flash_crc(adapter, fw->data, img_offset, img_size, filehdr_size + - img_hdrs_size, img_optype, + img_hdrs_size, flash_optype, &crc_match); - /* The current FW image on the card does not recognize the new - * FLASH op_type. The FW download is partially complete. - * Reboot the server now to enable FW image to recognize the - * new FLASH op_type. To complete the remaining process, - * download the same FW again after the reboot. - */ if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST || base_status(status) == MCC_STATUS_ILLEGAL_FIELD) { + /* The current FW image on the card does not support + * OFFSET based flashing. Retry using older mechanism + * of OPTYPE based flashing + */ + if (flash_optype == OPTYPE_OFFSET_SPECIFIED) { + flash_offset_support = false; + goto retry_flash; + } + + /* The current FW image on the card does not recognize + * the new FLASH op_type. The FW download is partially + * complete. Reboot the server now to enable FW image + * to recognize the new FLASH op_type. To complete the + * remaining process, download the same FW again after + * the reboot. + */ dev_err(dev, "Flash incomplete. Reset the server\n"); dev_err(dev, "Download FW image again after reset\n"); return -EAGAIN; @@ -4076,7 +4287,19 @@ flash: if (p + img_size > fw->data + fw->size) return -1; - status = be_flash(adapter, p, flash_cmd, img_optype, img_size); + status = be_flash(adapter, p, flash_cmd, flash_optype, img_size, + img_offset); + + /* The current FW image on the card does not support OFFSET + * based flashing. Retry using older mechanism of OPTYPE based + * flashing + */ + if (base_status(status) == MCC_STATUS_ILLEGAL_FIELD && + flash_optype == OPTYPE_OFFSET_SPECIFIED) { + flash_offset_support = false; + goto retry_flash; + } + /* For old FW images ignore ILLEGAL_FIELD error or errors on * UFI_DIR region */ @@ -4179,98 +4402,105 @@ static int lancer_fw_download(struct be_adapter *adapter, return 0; } -#define UFI_TYPE2 2 -#define UFI_TYPE3 3 -#define UFI_TYPE3R 10 -#define UFI_TYPE4 4 +#define BE2_UFI 2 +#define BE3_UFI 3 +#define BE3R_UFI 10 +#define SH_UFI 4 +#define SH_P2_UFI 11 + static int be_get_ufi_type(struct be_adapter *adapter, struct flash_file_hdr_g3 *fhdr) { - if (!fhdr) - goto be_get_ufi_exit; + if (!fhdr) { + dev_err(&adapter->pdev->dev, "Invalid FW UFI file"); + return -1; + } - if (skyhawk_chip(adapter) && fhdr->build[0] == '4') - return UFI_TYPE4; - else if (BE3_chip(adapter) && fhdr->build[0] == '3') { - if (fhdr->asic_type_rev == 0x10) - return UFI_TYPE3R; - else - return UFI_TYPE3; - } else if (BE2_chip(adapter) && fhdr->build[0] == '2') - return UFI_TYPE2; + /* First letter of the build version is used to identify + * which chip this image file is meant for. + */ + switch (fhdr->build[0]) { + case BLD_STR_UFI_TYPE_SH: + return (fhdr->asic_type_rev == ASIC_REV_P2) ? SH_P2_UFI : + SH_UFI; + case BLD_STR_UFI_TYPE_BE3: + return (fhdr->asic_type_rev == ASIC_REV_B0) ? BE3R_UFI : + BE3_UFI; + case BLD_STR_UFI_TYPE_BE2: + return BE2_UFI; + default: + return -1; + } +} -be_get_ufi_exit: - dev_err(&adapter->pdev->dev, - "UFI and Interface are not compatible for flashing\n"); - return -1; +/* Check if the flash image file is compatible with the adapter that + * is being flashed. + * BE3 chips with asic-rev B0 must be flashed only with BE3R_UFI type. + * Skyhawk chips with asic-rev P2 must be flashed only with SH_P2_UFI type. + */ +static bool be_check_ufi_compatibility(struct be_adapter *adapter, + struct flash_file_hdr_g3 *fhdr) +{ + int ufi_type = be_get_ufi_type(adapter, fhdr); + + switch (ufi_type) { + case SH_P2_UFI: + return skyhawk_chip(adapter); + case SH_UFI: + return (skyhawk_chip(adapter) && + adapter->asic_rev < ASIC_REV_P2); + case BE3R_UFI: + return BE3_chip(adapter); + case BE3_UFI: + return (BE3_chip(adapter) && adapter->asic_rev < ASIC_REV_B0); + case BE2_UFI: + return BE2_chip(adapter); + default: + return false; + } } static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw) { + struct device *dev = &adapter->pdev->dev; struct flash_file_hdr_g3 *fhdr3; - struct image_hdr *img_hdr_ptr = NULL; + struct image_hdr *img_hdr_ptr; + int status = 0, i, num_imgs; struct be_dma_mem flash_cmd; - const u8 *p; - int status = 0, i = 0, num_imgs = 0, ufi_type = 0; - flash_cmd.size = sizeof(struct be_cmd_write_flashrom); - flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size, - &flash_cmd.dma, GFP_KERNEL); - if (!flash_cmd.va) { - status = -ENOMEM; - goto be_fw_exit; + fhdr3 = (struct flash_file_hdr_g3 *)fw->data; + if (!be_check_ufi_compatibility(adapter, fhdr3)) { + dev_err(dev, "Flash image is not compatible with adapter\n"); + return -EINVAL; } - p = fw->data; - fhdr3 = (struct flash_file_hdr_g3 *)p; - - ufi_type = be_get_ufi_type(adapter, fhdr3); + flash_cmd.size = sizeof(struct be_cmd_write_flashrom); + flash_cmd.va = dma_alloc_coherent(dev, flash_cmd.size, &flash_cmd.dma, + GFP_KERNEL); + if (!flash_cmd.va) + return -ENOMEM; num_imgs = le32_to_cpu(fhdr3->num_imgs); for (i = 0; i < num_imgs; i++) { img_hdr_ptr = (struct image_hdr *)(fw->data + (sizeof(struct flash_file_hdr_g3) + i * sizeof(struct image_hdr))); - if (le32_to_cpu(img_hdr_ptr->imageid) == 1) { - switch (ufi_type) { - case UFI_TYPE4: - status = be_flash_skyhawk(adapter, fw, - &flash_cmd, num_imgs); - break; - case UFI_TYPE3R: - status = be_flash_BEx(adapter, fw, &flash_cmd, - num_imgs); - break; - case UFI_TYPE3: - /* Do not flash this ufi on BE3-R cards */ - if (adapter->asic_rev < 0x10) - status = be_flash_BEx(adapter, fw, - &flash_cmd, - num_imgs); - else { - status = -EINVAL; - dev_err(&adapter->pdev->dev, - "Can't load BE3 UFI on BE3R\n"); - } - } - } + if (!BE2_chip(adapter) && + le32_to_cpu(img_hdr_ptr->imageid) != 1) + continue; + + if (skyhawk_chip(adapter)) + status = be_flash_skyhawk(adapter, fw, &flash_cmd, + num_imgs); + else + status = be_flash_BEx(adapter, fw, &flash_cmd, + num_imgs); } - if (ufi_type == UFI_TYPE2) - status = be_flash_BEx(adapter, fw, &flash_cmd, 0); - else if (ufi_type == -1) - status = -EINVAL; + dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma); + if (!status) + dev_info(dev, "Firmware flashed successfully\n"); - 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\n"); - goto be_fw_exit; - } - - dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n"); - -be_fw_exit: return status; } @@ -4304,7 +4534,8 @@ fw_exit: return status; } -static int be_ndo_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh) +static int be_ndo_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, + u16 flags) { struct be_adapter *adapter = netdev_priv(dev); struct nlattr *attr, *br_spec; @@ -4383,8 +4614,9 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, * distinguish various types of transports (VxLAN, GRE, NVGRE ..). So, offload * is expected to work across all types of IP tunnels once exported. Skyhawk * supports offloads for either VxLAN or NVGRE, exclusively. So we export VxLAN - * offloads in hw_enc_features only when a VxLAN port is added. Note this only - * ensures that other tunnels work fine while VxLAN offloads are not enabled. + * offloads in hw_enc_features only when a VxLAN port is added. If other (non + * VxLAN) tunnels are configured while VxLAN offloads are enabled, offloads for + * those other tunnels are unexported on the fly through ndo_features_check(). * * Skyhawk supports VxLAN offloads only for one UDP dport. So, if the stack * adds more than one port, disable offloads and don't re-enable them again @@ -4463,7 +4695,41 @@ static netdev_features_t be_features_check(struct sk_buff *skb, struct net_device *dev, netdev_features_t features) { - return vxlan_features_check(skb, features); + struct be_adapter *adapter = netdev_priv(dev); + u8 l4_hdr = 0; + + /* The code below restricts offload features for some tunneled packets. + * Offload features for normal (non tunnel) packets are unchanged. + */ + if (!skb->encapsulation || + !(adapter->flags & BE_FLAGS_VXLAN_OFFLOADS)) + return features; + + /* It's an encapsulated packet and VxLAN offloads are enabled. We + * should disable tunnel offload features if it's not a VxLAN packet, + * as tunnel offloads have been enabled only for VxLAN. This is done to + * allow other tunneled traffic like GRE work fine while VxLAN + * offloads are configured in Skyhawk-R. + */ + switch (vlan_get_protocol(skb)) { + case htons(ETH_P_IP): + l4_hdr = ip_hdr(skb)->protocol; + break; + case htons(ETH_P_IPV6): + l4_hdr = ipv6_hdr(skb)->nexthdr; + break; + default: + return features; + } + + if (l4_hdr != IPPROTO_UDP || + skb->inner_protocol_type != ENCAP_TYPE_ETHER || + skb->inner_protocol != htons(ETH_P_TEB) || + skb_inner_mac_header(skb) - skb_transport_header(skb) != + sizeof(struct udphdr) + sizeof(struct vxlanhdr)) + return features & ~(NETIF_F_ALL_CSUM | NETIF_F_GSO_MASK); + + return features; } #endif @@ -4797,6 +5063,20 @@ static void be_func_recovery_task(struct work_struct *work) msecs_to_jiffies(1000)); } +static void be_log_sfp_info(struct be_adapter *adapter) +{ + int status; + + status = be_cmd_query_sfp_info(adapter); + if (!status) { + dev_err(&adapter->pdev->dev, + "Unqualified SFP+ detected on %c from %s part no: %s", + adapter->port_name, adapter->phy.vendor_name, + adapter->phy.vendor_pn); + } + adapter->flags &= ~BE_FLAGS_EVT_INCOMPATIBLE_SFP; +} + static void be_worker(struct work_struct *work) { struct be_adapter *adapter = @@ -4835,6 +5115,9 @@ static void be_worker(struct work_struct *work) be_eqd_update(adapter); + if (adapter->flags & BE_FLAGS_EVT_INCOMPATIBLE_SFP) + be_log_sfp_info(adapter); + reschedule: adapter->work_counter++; schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); @@ -4881,12 +5164,31 @@ static inline char *func_name(struct be_adapter *adapter) return be_physfn(adapter) ? "PF" : "VF"; } +static inline char *nic_name(struct pci_dev *pdev) +{ + switch (pdev->device) { + case OC_DEVICE_ID1: + return OC_NAME; + 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; + case OC_DEVICE_ID5: + case OC_DEVICE_ID6: + return OC_NAME_SH; + default: + return BE_NAME; + } +} + static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) { - int status = 0; struct be_adapter *adapter; struct net_device *netdev; - char port_name; + int status = 0; dev_info(&pdev->dev, "%s version is %s\n", DRV_NAME, DRV_VER); @@ -4980,10 +5282,8 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) schedule_delayed_work(&adapter->func_recovery_work, msecs_to_jiffies(1000)); - be_cmd_query_port_name(adapter, &port_name); - dev_info(&pdev->dev, "%s: %s %s port %c\n", nic_name(pdev), - func_name(adapter), mc_name(adapter), port_name); + func_name(adapter), mc_name(adapter), adapter->port_name); return 0; @@ -5048,6 +5348,10 @@ static int be_resume(struct pci_dev *pdev) if (status) return status; + status = be_cmd_reset_function(adapter); + if (status) + return status; + be_intr_set(adapter, true); /* tell fw we're ready to fire cmds */ status = be_cmd_fw_init(adapter); diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index 270308315d43..ba84c4a9ce32 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig @@ -69,7 +69,8 @@ config FSL_XGMAC_MDIO select PHYLIB select OF_MDIO ---help--- - This driver supports the MDIO bus on the Fman 10G Ethernet MACs. + This driver supports the MDIO bus on the Fman 10G Ethernet MACs, and + on the FMan mEMAC (which supports both Clauses 22 and 45) config UCC_GETH tristate "Freescale QE Gigabit Ethernet" diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 40132929daf7..a86af8a7485d 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -16,6 +16,7 @@ #include #include #include +#include #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ defined(CONFIG_M520x) || defined(CONFIG_M532x) || \ @@ -356,6 +357,7 @@ struct bufdesc_ex { #define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */ #define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ #define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ +#define FEC_ENET_WAKEUP ((uint)0x00020000) /* Wakeup request */ #define FEC_ENET_TXF (FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2) #define FEC_ENET_RXF (FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2) #define FEC_ENET_TS_AVAIL ((uint)0x00010000) @@ -513,6 +515,7 @@ struct fec_enet_private { int irq[FEC_IRQ_NUM]; bool bufdesc_ex; int pause_flag; + int wol_flag; u32 quirks; struct napi_struct napi; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index bba87775419d..9bb6220663b2 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -188,6 +188,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_MMFR_RA(v) ((v & 0x1f) << 18) #define FEC_MMFR_TA (2 << 16) #define FEC_MMFR_DATA(v) (v & 0xffff) +/* FEC ECR bits definition */ +#define FEC_ECR_MAGICEN (1 << 2) +#define FEC_ECR_SLEEP (1 << 3) #define FEC_MII_TIMEOUT 30000 /* us */ @@ -196,6 +199,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_PAUSE_FLAG_AUTONEG 0x1 #define FEC_PAUSE_FLAG_ENABLE 0x2 +#define FEC_WOL_HAS_MAGIC_PACKET (0x1 << 0) +#define FEC_WOL_FLAG_ENABLE (0x1 << 1) +#define FEC_WOL_FLAG_SLEEP_ON (0x1 << 2) #define COPYBREAK_DEFAULT 256 @@ -1090,7 +1096,9 @@ static void fec_stop(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); + struct fec_platform_data *pdata = fep->pdev->dev.platform_data; u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8); + u32 val; /* We cannot expect a graceful transmit stop without link !!! */ if (fep->link) { @@ -1104,17 +1112,28 @@ fec_stop(struct net_device *ndev) * For i.MX6SX SOC, enet use AXI bus, we use disable MAC * instead of reset MAC itself. */ - if (fep->quirks & FEC_QUIRK_HAS_AVB) { - writel(0, fep->hwp + FEC_ECNTRL); + if (!(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) { + if (fep->quirks & FEC_QUIRK_HAS_AVB) { + writel(0, fep->hwp + FEC_ECNTRL); + } else { + writel(1, fep->hwp + FEC_ECNTRL); + udelay(10); + } + writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); } else { - writel(1, fep->hwp + FEC_ECNTRL); - udelay(10); + writel(FEC_DEFAULT_IMASK | FEC_ENET_WAKEUP, fep->hwp + FEC_IMASK); + val = readl(fep->hwp + FEC_ECNTRL); + val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP); + writel(val, fep->hwp + FEC_ECNTRL); + + if (pdata && pdata->sleep_mode_enable) + pdata->sleep_mode_enable(true); } writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); - writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); /* We have to keep ENET enabled to have MII interrupt stay working */ - if (fep->quirks & FEC_QUIRK_ENET_MAC) { + if (fep->quirks & FEC_QUIRK_ENET_MAC && + !(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) { writel(2, fep->hwp + FEC_ECNTRL); writel(rmii_mode, fep->hwp + FEC_R_CNTRL); } @@ -1170,12 +1189,13 @@ static void fec_enet_tx_queue(struct net_device *ndev, u16 queue_id) { struct fec_enet_private *fep; - struct bufdesc *bdp; + struct bufdesc *bdp, *bdp_t; unsigned short status; struct sk_buff *skb; struct fec_enet_priv_tx_q *txq; struct netdev_queue *nq; int index = 0; + int i, bdnum; int entries_free; fep = netdev_priv(ndev); @@ -1196,18 +1216,29 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id) if (bdp == txq->cur_tx) break; - index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep); - + bdp_t = bdp; + bdnum = 1; + index = fec_enet_get_bd_index(txq->tx_bd_base, bdp_t, fep); skb = txq->tx_skbuff[index]; - txq->tx_skbuff[index] = NULL; - if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr)) - dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, - bdp->cbd_datlen, DMA_TO_DEVICE); - bdp->cbd_bufaddr = 0; - if (!skb) { - bdp = fec_enet_get_nextdesc(bdp, fep, queue_id); - continue; + while (!skb) { + bdp_t = fec_enet_get_nextdesc(bdp_t, fep, queue_id); + index = fec_enet_get_bd_index(txq->tx_bd_base, bdp_t, fep); + skb = txq->tx_skbuff[index]; + bdnum++; } + if (skb_shinfo(skb)->nr_frags && + (status = bdp_t->cbd_sc) & BD_ENET_TX_READY) + break; + + for (i = 0; i < bdnum; i++) { + if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr)) + dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, + bdp->cbd_datlen, DMA_TO_DEVICE); + bdp->cbd_bufaddr = 0; + if (i < bdnum - 1) + bdp = fec_enet_get_nextdesc(bdp, fep, queue_id); + } + txq->tx_skbuff[index] = NULL; /* Check for errors. */ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | @@ -2428,6 +2459,44 @@ static int fec_enet_set_tunable(struct net_device *netdev, return ret; } +static void +fec_enet_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + + if (fep->wol_flag & FEC_WOL_HAS_MAGIC_PACKET) { + wol->supported = WAKE_MAGIC; + wol->wolopts = fep->wol_flag & FEC_WOL_FLAG_ENABLE ? WAKE_MAGIC : 0; + } else { + wol->supported = wol->wolopts = 0; + } +} + +static int +fec_enet_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + + if (!(fep->wol_flag & FEC_WOL_HAS_MAGIC_PACKET)) + return -EINVAL; + + if (wol->wolopts & ~WAKE_MAGIC) + return -EINVAL; + + device_set_wakeup_enable(&ndev->dev, wol->wolopts & WAKE_MAGIC); + if (device_may_wakeup(&ndev->dev)) { + fep->wol_flag |= FEC_WOL_FLAG_ENABLE; + if (fep->irq[0] > 0) + enable_irq_wake(fep->irq[0]); + } else { + fep->wol_flag &= (~FEC_WOL_FLAG_ENABLE); + if (fep->irq[0] > 0) + disable_irq_wake(fep->irq[0]); + } + + return 0; +} + static const struct ethtool_ops fec_enet_ethtool_ops = { .get_settings = fec_enet_get_settings, .set_settings = fec_enet_set_settings, @@ -2446,6 +2515,8 @@ static const struct ethtool_ops fec_enet_ethtool_ops = { .get_ts_info = fec_enet_get_ts_info, .get_tunable = fec_enet_get_tunable, .set_tunable = fec_enet_set_tunable, + .get_wol = fec_enet_get_wol, + .set_wol = fec_enet_set_wol, }; static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) @@ -2525,12 +2596,9 @@ static void fec_enet_free_queue(struct net_device *ndev) } for (i = 0; i < fep->num_rx_queues; i++) - if (fep->rx_queue[i]) - kfree(fep->rx_queue[i]); - + kfree(fep->rx_queue[i]); for (i = 0; i < fep->num_tx_queues; i++) - if (fep->tx_queue[i]) - kfree(fep->tx_queue[i]); + kfree(fep->tx_queue[i]); } static int fec_enet_alloc_queue(struct net_device *ndev) @@ -2706,6 +2774,9 @@ fec_enet_open(struct net_device *ndev) phy_start(fep->phy_dev); netif_tx_start_all_queues(ndev); + device_set_wakeup_enable(&ndev->dev, fep->wol_flag & + FEC_WOL_FLAG_ENABLE); + return 0; err_enet_mii_probe: @@ -3155,6 +3226,9 @@ fec_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); + if (of_get_property(np, "fsl,magic-packet", NULL)) + fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET; + phy_node = of_parse_phandle(np, "phy-handle", 0); if (!phy_node && of_phy_is_fixed_link(np)) { ret = of_phy_register_fixed_link(np); @@ -3249,6 +3323,8 @@ fec_probe(struct platform_device *pdev) 0, pdev->name, ndev); if (ret) goto failed_irq; + + fep->irq[i] = irq; } init_completion(&fep->mdio_done); @@ -3265,6 +3341,9 @@ fec_probe(struct platform_device *pdev) if (ret) goto failed_register; + device_init_wakeup(&ndev->dev, fep->wol_flag & + FEC_WOL_HAS_MAGIC_PACKET); + if (fep->bufdesc_ex && fep->ptp_clock) netdev_info(ndev, "registered PHC device %d\n", fep->dev_id); @@ -3318,6 +3397,8 @@ static int __maybe_unused fec_suspend(struct device *dev) rtnl_lock(); if (netif_running(ndev)) { + if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) + fep->wol_flag |= FEC_WOL_FLAG_SLEEP_ON; phy_stop(fep->phy_dev); napi_disable(&fep->napi); netif_tx_lock_bh(ndev); @@ -3325,11 +3406,12 @@ static int __maybe_unused fec_suspend(struct device *dev) netif_tx_unlock_bh(ndev); fec_stop(ndev); fec_enet_clk_enable(ndev, false); - pinctrl_pm_select_sleep_state(&fep->pdev->dev); + if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) + pinctrl_pm_select_sleep_state(&fep->pdev->dev); } rtnl_unlock(); - if (fep->reg_phy) + if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) regulator_disable(fep->reg_phy); /* SOC supply clock to phy, when clock is disabled, phy link down @@ -3345,9 +3427,11 @@ static int __maybe_unused fec_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct fec_enet_private *fep = netdev_priv(ndev); + struct fec_platform_data *pdata = fep->pdev->dev.platform_data; int ret; + int val; - if (fep->reg_phy) { + if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) { ret = regulator_enable(fep->reg_phy); if (ret) return ret; @@ -3355,12 +3439,21 @@ static int __maybe_unused fec_resume(struct device *dev) rtnl_lock(); if (netif_running(ndev)) { - pinctrl_pm_select_default_state(&fep->pdev->dev); ret = fec_enet_clk_enable(ndev, true); if (ret) { rtnl_unlock(); goto failed_clk; } + if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) { + if (pdata && pdata->sleep_mode_enable) + pdata->sleep_mode_enable(false); + val = readl(fep->hwp + FEC_ECNTRL); + val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP); + writel(val, fep->hwp + FEC_ECNTRL); + fep->wol_flag &= ~FEC_WOL_FLAG_SLEEP_ON; + } else { + pinctrl_pm_select_default_state(&fep->pdev->dev); + } fec_restart(ndev); netif_tx_lock_bh(ndev); netif_device_attach(ndev); diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index 992c8c3db553..1f9cf2345266 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -374,23 +374,9 @@ static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) struct fec_enet_private *fep = container_of(ptp, struct fec_enet_private, ptp_caps); unsigned long flags; - u64 now; - u32 counter; spin_lock_irqsave(&fep->tmreg_lock, flags); - - now = timecounter_read(&fep->tc); - now += delta; - - /* Get the timer value based on adjusted timestamp. - * Update the counter with the masked value. - */ - counter = now & fep->cc.mask; - writel(counter, fep->hwp + FEC_ATIME); - - /* reset the timecounter */ - timecounter_init(&fep->tc, &fep->cc, now); - + timecounter_adjtime(&fep->tc, delta); spin_unlock_irqrestore(&fep->tmreg_lock, flags); return 0; diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c index 9e2bcb807923..a17628769a1f 100644 --- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c +++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c @@ -278,14 +278,20 @@ static int fs_enet_tx_napi(struct napi_struct *napi, int budget) fep->stats.collisions++; /* unmap */ - dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), - skb->len, DMA_TO_DEVICE); + if (fep->mapped_as_page[dirtyidx]) + dma_unmap_page(fep->dev, CBDR_BUFADDR(bdp), + CBDR_DATLEN(bdp), DMA_TO_DEVICE); + else + dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), + CBDR_DATLEN(bdp), DMA_TO_DEVICE); /* * Free the sk buffer associated with this last transmit. */ - dev_kfree_skb(skb); - fep->tx_skbuff[dirtyidx] = NULL; + if (skb) { + dev_kfree_skb(skb); + fep->tx_skbuff[dirtyidx] = NULL; + } /* * Update pointer to next buffer descriptor to be transmitted. @@ -299,7 +305,7 @@ static int fs_enet_tx_napi(struct napi_struct *napi, int budget) * Since we have freed up a buffer, the ring is no longer * full. */ - if (!fep->tx_free++) + if (++fep->tx_free >= MAX_SKB_FRAGS) do_wake = 1; has_tx_work = 1; } @@ -509,6 +515,9 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) cbd_t __iomem *bdp; int curidx; u16 sc; + int nr_frags = skb_shinfo(skb)->nr_frags; + skb_frag_t *frag; + int len; #ifdef CONFIG_FS_ENET_MPC5121_FEC if (((unsigned long)skb->data) & 0x3) { @@ -530,7 +539,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) */ bdp = fep->cur_tx; - if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { + if (fep->tx_free <= nr_frags || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { netif_stop_queue(dev); spin_unlock(&fep->tx_lock); @@ -543,35 +552,42 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) } curidx = bdp - fep->tx_bd_base; - /* - * Clear all of the status flags. - */ - CBDC_SC(bdp, BD_ENET_TX_STATS); - - /* - * Save skb pointer. - */ - fep->tx_skbuff[curidx] = skb; - - fep->stats.tx_bytes += skb->len; + len = skb->len; + fep->stats.tx_bytes += len; + if (nr_frags) + len -= skb->data_len; + fep->tx_free -= nr_frags + 1; /* * Push the data cache so the CPM does not get stale memory data. */ CBDW_BUFADDR(bdp, dma_map_single(fep->dev, - skb->data, skb->len, DMA_TO_DEVICE)); - CBDW_DATLEN(bdp, skb->len); + skb->data, len, DMA_TO_DEVICE)); + CBDW_DATLEN(bdp, len); - /* - * If this was the last BD in the ring, start at the beginning again. - */ - if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) - fep->cur_tx++; - else - fep->cur_tx = fep->tx_bd_base; + fep->mapped_as_page[curidx] = 0; + frag = skb_shinfo(skb)->frags; + while (nr_frags) { + CBDC_SC(bdp, + BD_ENET_TX_STATS | BD_ENET_TX_LAST | BD_ENET_TX_TC); + CBDS_SC(bdp, BD_ENET_TX_READY); - if (!--fep->tx_free) - netif_stop_queue(dev); + if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) + bdp++, curidx++; + else + bdp = fep->tx_bd_base, curidx = 0; + + len = skb_frag_size(frag); + CBDW_BUFADDR(bdp, skb_frag_dma_map(fep->dev, frag, 0, len, + DMA_TO_DEVICE)); + CBDW_DATLEN(bdp, len); + + fep->tx_skbuff[curidx] = NULL; + fep->mapped_as_page[curidx] = 1; + + frag++; + nr_frags--; + } /* Trigger transmission start */ sc = BD_ENET_TX_READY | BD_ENET_TX_INTR | @@ -582,8 +598,22 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) * yay for hw reuse :) */ if (skb->len <= 60) sc |= BD_ENET_TX_PAD; + CBDC_SC(bdp, BD_ENET_TX_STATS); CBDS_SC(bdp, sc); + /* Save skb pointer. */ + fep->tx_skbuff[curidx] = skb; + + /* If this was the last BD in the ring, start at the beginning again. */ + if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) + bdp++; + else + bdp = fep->tx_bd_base; + fep->cur_tx = bdp; + + if (fep->tx_free < MAX_SKB_FRAGS) + netif_stop_queue(dev); + skb_tx_timestamp(skb); (*fep->ops->tx_kickstart)(dev); @@ -917,7 +947,7 @@ static int fs_enet_probe(struct platform_device *ofdev) } fpi->rx_ring = 32; - fpi->tx_ring = 32; + fpi->tx_ring = 64; fpi->rx_copybreak = 240; fpi->napi_weight = 17; fpi->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0); @@ -955,7 +985,8 @@ static int fs_enet_probe(struct platform_device *ofdev) privsize = sizeof(*fep) + sizeof(struct sk_buff **) * - (fpi->rx_ring + fpi->tx_ring); + (fpi->rx_ring + fpi->tx_ring) + + sizeof(char) * fpi->tx_ring; ndev = alloc_etherdev(privsize); if (!ndev) { @@ -978,6 +1009,8 @@ static int fs_enet_probe(struct platform_device *ofdev) fep->rx_skbuff = (struct sk_buff **)&fep[1]; fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; + fep->mapped_as_page = (char *)(fep->rx_skbuff + fpi->rx_ring + + fpi->tx_ring); spin_lock_init(&fep->lock); spin_lock_init(&fep->tx_lock); @@ -1007,6 +1040,8 @@ static int fs_enet_probe(struct platform_device *ofdev) netif_carrier_off(ndev); + ndev->features |= NETIF_F_SG; + ret = register_netdev(ndev); if (ret) goto out_free_bd; diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet.h b/drivers/net/ethernet/freescale/fs_enet/fs_enet.h index 3a4b49e0e717..f184d8f952e2 100644 --- a/drivers/net/ethernet/freescale/fs_enet/fs_enet.h +++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet.h @@ -134,6 +134,7 @@ struct fs_enet_private { void __iomem *ring_base; struct sk_buff **rx_skbuff; struct sk_buff **tx_skbuff; + char *mapped_as_page; cbd_t __iomem *rx_bd_base; /* Address of Rx and Tx buffers. */ cbd_t __iomem *tx_bd_base; cbd_t __iomem *dirty_tx; /* ring entries to be free()ed. */ diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 5645342f5b28..43df78882e48 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -116,7 +116,8 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); static void gfar_reset_task(struct work_struct *work); static void gfar_timeout(struct net_device *dev); static int gfar_close(struct net_device *dev); -struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr); +static struct sk_buff *gfar_new_skb(struct net_device *dev, + dma_addr_t *bufaddr); static int gfar_set_mac_address(struct net_device *dev); static int gfar_change_mtu(struct net_device *dev, int new_mtu); static irqreturn_t gfar_error(int irq, void *dev_id); @@ -176,7 +177,7 @@ static int gfar_init_bds(struct net_device *ndev) struct gfar_priv_rx_q *rx_queue = NULL; struct txbd8 *txbdp; struct rxbd8 *rxbdp; - u32 *rfbptr; + u32 __iomem *rfbptr; int i, j; dma_addr_t bufaddr; @@ -554,7 +555,7 @@ static void gfar_ints_enable(struct gfar_private *priv) } } -void lock_tx_qs(struct gfar_private *priv) +static void lock_tx_qs(struct gfar_private *priv) { int i; @@ -562,7 +563,7 @@ void lock_tx_qs(struct gfar_private *priv) spin_lock(&priv->tx_queue[i]->txlock); } -void unlock_tx_qs(struct gfar_private *priv) +static void unlock_tx_qs(struct gfar_private *priv) { int i; @@ -763,7 +764,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) u32 *tx_queues, *rx_queues; unsigned short mode, poll_mode; - if (!np || !of_device_is_available(np)) + if (!np) return -ENODEV; if (of_device_is_compatible(np, "fsl,etsec2")) { @@ -2169,7 +2170,7 @@ static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb, void inline gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb) { fcb->flags |= TXFCB_VLN; - fcb->vlctl = vlan_tx_tag_get(skb); + fcb->vlctl = skb_vlan_tag_get(skb); } static inline struct txbd8 *skip_txbd(struct txbd8 *bdp, int stride, @@ -2229,7 +2230,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) regs = tx_queue->grp->regs; do_csum = (CHECKSUM_PARTIAL == skb->ip_summed); - do_vlan = vlan_tx_tag_present(skb); + do_vlan = skb_vlan_tag_present(skb); do_tstamp = (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en; @@ -2671,7 +2672,7 @@ static struct sk_buff *gfar_alloc_skb(struct net_device *dev) return skb; } -struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr) +static struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr) { struct gfar_private *priv = netdev_priv(dev); struct sk_buff *skb; diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index b581b8823a2a..9e1802400c23 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -1039,7 +1039,7 @@ struct gfar_priv_rx_q { /* RX Coalescing values */ unsigned char rxcoalescing; unsigned long rxic; - u32 *rfbptr; + u32 __iomem *rfbptr; }; enum gfar_irqinfo_id { diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index 3e1a9c1a67a9..fda12fb32ec7 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -1586,7 +1586,7 @@ static int gfar_write_filer_table(struct gfar_private *priv, return -EBUSY; /* Fill regular entries */ - for (; i < MAX_FILER_IDX - 1 && (tab->fe[i].ctrl | tab->fe[i].ctrl); + for (; i < MAX_FILER_IDX - 1 && (tab->fe[i].ctrl | tab->fe[i].prop); i++) gfar_write_filer(priv, i, tab->fe[i].ctrl, tab->fe[i].prop); /* Fill the rest with fall-troughs */ diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index 6e7db66069aa..3a83bc2c613c 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -32,18 +32,19 @@ struct tgec_mdio_controller { __be32 mdio_addr; /* MDIO address */ } __packed; +#define MDIO_STAT_ENC BIT(6) #define MDIO_STAT_CLKDIV(x) (((x>>1) & 0xff) << 8) -#define MDIO_STAT_BSY (1 << 0) -#define MDIO_STAT_RD_ER (1 << 1) +#define MDIO_STAT_BSY BIT(0) +#define MDIO_STAT_RD_ER BIT(1) #define MDIO_CTL_DEV_ADDR(x) (x & 0x1f) #define MDIO_CTL_PORT_ADDR(x) ((x & 0x1f) << 5) -#define MDIO_CTL_PRE_DIS (1 << 10) -#define MDIO_CTL_SCAN_EN (1 << 11) -#define MDIO_CTL_POST_INC (1 << 14) -#define MDIO_CTL_READ (1 << 15) +#define MDIO_CTL_PRE_DIS BIT(10) +#define MDIO_CTL_SCAN_EN BIT(11) +#define MDIO_CTL_POST_INC BIT(14) +#define MDIO_CTL_READ BIT(15) #define MDIO_DATA(x) (x & 0xffff) -#define MDIO_DATA_BSY (1 << 31) +#define MDIO_DATA_BSY BIT(31) /* * Wait until the MDIO bus is free @@ -51,12 +52,16 @@ struct tgec_mdio_controller { static int xgmac_wait_until_free(struct device *dev, struct tgec_mdio_controller __iomem *regs) { - uint32_t status; + unsigned int timeout; /* Wait till the bus is free */ - status = spin_event_timeout( - !((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY), TIMEOUT, 0); - if (!status) { + timeout = TIMEOUT; + while ((ioread32be(®s->mdio_stat) & MDIO_STAT_BSY) && timeout) { + cpu_relax(); + timeout--; + } + + if (!timeout) { dev_err(dev, "timeout waiting for bus to be free\n"); return -ETIMEDOUT; } @@ -70,12 +75,16 @@ static int xgmac_wait_until_free(struct device *dev, static int xgmac_wait_until_done(struct device *dev, struct tgec_mdio_controller __iomem *regs) { - uint32_t status; + unsigned int timeout; /* Wait till the MDIO write is complete */ - status = spin_event_timeout( - !((in_be32(®s->mdio_data)) & MDIO_DATA_BSY), TIMEOUT, 0); - if (!status) { + timeout = TIMEOUT; + while ((ioread32be(®s->mdio_data) & MDIO_DATA_BSY) && timeout) { + cpu_relax(); + timeout--; + } + + if (!timeout) { dev_err(dev, "timeout waiting for operation to complete\n"); return -ETIMEDOUT; } @@ -91,29 +100,42 @@ static int xgmac_wait_until_done(struct device *dev, static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) { struct tgec_mdio_controller __iomem *regs = bus->priv; - uint16_t dev_addr = regnum >> 16; + uint16_t dev_addr; + u32 mdio_ctl, mdio_stat; int ret; - /* Setup the MII Mgmt clock speed */ - out_be32(®s->mdio_stat, MDIO_STAT_CLKDIV(100)); + mdio_stat = ioread32be(®s->mdio_stat); + if (regnum & MII_ADDR_C45) { + /* Clause 45 (ie 10G) */ + dev_addr = (regnum >> 16) & 0x1f; + mdio_stat |= MDIO_STAT_ENC; + } else { + /* Clause 22 (ie 1G) */ + dev_addr = regnum & 0x1f; + mdio_stat &= ~MDIO_STAT_ENC; + } + + iowrite32be(mdio_stat, ®s->mdio_stat); ret = xgmac_wait_until_free(&bus->dev, regs); if (ret) return ret; /* Set the port and dev addr */ - out_be32(®s->mdio_ctl, - MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr)); + mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); + iowrite32be(mdio_ctl, ®s->mdio_ctl); /* Set the register address */ - out_be32(®s->mdio_addr, regnum & 0xffff); + if (regnum & MII_ADDR_C45) { + iowrite32be(regnum & 0xffff, ®s->mdio_addr); - ret = xgmac_wait_until_free(&bus->dev, regs); - if (ret) - return ret; + ret = xgmac_wait_until_free(&bus->dev, regs); + if (ret) + return ret; + } /* Write the value to the register */ - out_be32(®s->mdio_data, MDIO_DATA(value)); + iowrite32be(MDIO_DATA(value), ®s->mdio_data); ret = xgmac_wait_until_done(&bus->dev, regs); if (ret) @@ -130,13 +152,22 @@ static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 val static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) { struct tgec_mdio_controller __iomem *regs = bus->priv; - uint16_t dev_addr = regnum >> 16; + uint16_t dev_addr; + uint32_t mdio_stat; uint32_t mdio_ctl; uint16_t value; int ret; - /* Setup the MII Mgmt clock speed */ - out_be32(®s->mdio_stat, MDIO_STAT_CLKDIV(100)); + mdio_stat = ioread32be(®s->mdio_stat); + if (regnum & MII_ADDR_C45) { + dev_addr = (regnum >> 16) & 0x1f; + mdio_stat |= MDIO_STAT_ENC; + } else { + dev_addr = regnum & 0x1f; + mdio_stat &= ~MDIO_STAT_ENC; + } + + iowrite32be(mdio_stat, ®s->mdio_stat); ret = xgmac_wait_until_free(&bus->dev, regs); if (ret) @@ -144,54 +175,38 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) /* Set the Port and Device Addrs */ mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); - out_be32(®s->mdio_ctl, mdio_ctl); + iowrite32be(mdio_ctl, ®s->mdio_ctl); /* Set the register address */ - out_be32(®s->mdio_addr, regnum & 0xffff); + if (regnum & MII_ADDR_C45) { + iowrite32be(regnum & 0xffff, ®s->mdio_addr); - ret = xgmac_wait_until_free(&bus->dev, regs); - if (ret) - return ret; + ret = xgmac_wait_until_free(&bus->dev, regs); + if (ret) + return ret; + } /* Initiate the read */ - out_be32(®s->mdio_ctl, mdio_ctl | MDIO_CTL_READ); + iowrite32be(mdio_ctl | MDIO_CTL_READ, ®s->mdio_ctl); ret = xgmac_wait_until_done(&bus->dev, regs); if (ret) return ret; /* Return all Fs if nothing was there */ - if (in_be32(®s->mdio_stat) & MDIO_STAT_RD_ER) { + if (ioread32be(®s->mdio_stat) & MDIO_STAT_RD_ER) { dev_err(&bus->dev, "Error while reading PHY%d reg at %d.%hhu\n", phy_id, dev_addr, regnum); return 0xffff; } - value = in_be32(®s->mdio_data) & 0xffff; + value = ioread32be(®s->mdio_data) & 0xffff; dev_dbg(&bus->dev, "read %04x\n", value); return value; } -/* Reset the MIIM registers, and wait for the bus to free */ -static int xgmac_mdio_reset(struct mii_bus *bus) -{ - struct tgec_mdio_controller __iomem *regs = bus->priv; - int ret; - - mutex_lock(&bus->mdio_lock); - - /* Setup the MII Mgmt clock speed */ - out_be32(®s->mdio_stat, MDIO_STAT_CLKDIV(100)); - - ret = xgmac_wait_until_free(&bus->dev, regs); - - mutex_unlock(&bus->mdio_lock); - - return ret; -} - static int xgmac_mdio_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -205,15 +220,13 @@ static int xgmac_mdio_probe(struct platform_device *pdev) return ret; } - bus = mdiobus_alloc_size(PHY_MAX_ADDR * sizeof(int)); + bus = mdiobus_alloc(); if (!bus) return -ENOMEM; bus->name = "Freescale XGMAC MDIO Bus"; bus->read = xgmac_mdio_read; bus->write = xgmac_mdio_write; - bus->reset = xgmac_mdio_reset; - bus->irq = bus->priv; bus->parent = &pdev->dev; snprintf(bus->id, MII_BUS_ID_SIZE, "%llx", (unsigned long long)res.start); @@ -258,6 +271,9 @@ static struct of_device_id xgmac_mdio_match[] = { { .compatible = "fsl,fman-xmdio", }, + { + .compatible = "fsl,fman-memac-mdio", + }, {}, }; MODULE_DEVICE_TABLE(of, xgmac_mdio_match); diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig index e9421731b05e..a54d89791311 100644 --- a/drivers/net/ethernet/hisilicon/Kconfig +++ b/drivers/net/ethernet/hisilicon/Kconfig @@ -24,4 +24,13 @@ config HIX5HD2_GMAC help This selects the hix5hd2 mac family network device. +config HIP04_ETH + tristate "HISILICON P04 Ethernet support" + select PHYLIB + select MARVELL_PHY + select MFD_SYSCON + ---help--- + If you wish to compile a kernel for a hardware with hisilicon p04 SoC and + want to use the internal ethernet then you should answer Y to this. + endif # NET_VENDOR_HISILICON diff --git a/drivers/net/ethernet/hisilicon/Makefile b/drivers/net/ethernet/hisilicon/Makefile index 9175e84622d4..6c14540a4dc5 100644 --- a/drivers/net/ethernet/hisilicon/Makefile +++ b/drivers/net/ethernet/hisilicon/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_HIX5HD2_GMAC) += hix5hd2_gmac.o +obj-$(CONFIG_HIP04_ETH) += hip04_mdio.o hip04_eth.o diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c new file mode 100644 index 000000000000..b72d238695d7 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -0,0 +1,971 @@ + +/* Copyright (c) 2014 Linaro Ltd. + * Copyright (c) 2014 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PPE_CFG_RX_ADDR 0x100 +#define PPE_CFG_POOL_GRP 0x300 +#define PPE_CFG_RX_BUF_SIZE 0x400 +#define PPE_CFG_RX_FIFO_SIZE 0x500 +#define PPE_CURR_BUF_CNT 0xa200 + +#define GE_DUPLEX_TYPE 0x08 +#define GE_MAX_FRM_SIZE_REG 0x3c +#define GE_PORT_MODE 0x40 +#define GE_PORT_EN 0x44 +#define GE_SHORT_RUNTS_THR_REG 0x50 +#define GE_TX_LOCAL_PAGE_REG 0x5c +#define GE_TRANSMIT_CONTROL_REG 0x60 +#define GE_CF_CRC_STRIP_REG 0x1b0 +#define GE_MODE_CHANGE_REG 0x1b4 +#define GE_RECV_CONTROL_REG 0x1e0 +#define GE_STATION_MAC_ADDRESS 0x210 +#define PPE_CFG_CPU_ADD_ADDR 0x580 +#define PPE_CFG_MAX_FRAME_LEN_REG 0x408 +#define PPE_CFG_BUS_CTRL_REG 0x424 +#define PPE_CFG_RX_CTRL_REG 0x428 +#define PPE_CFG_RX_PKT_MODE_REG 0x438 +#define PPE_CFG_QOS_VMID_GEN 0x500 +#define PPE_CFG_RX_PKT_INT 0x538 +#define PPE_INTEN 0x600 +#define PPE_INTSTS 0x608 +#define PPE_RINT 0x604 +#define PPE_CFG_STS_MODE 0x700 +#define PPE_HIS_RX_PKT_CNT 0x804 + +/* REG_INTERRUPT */ +#define RCV_INT BIT(10) +#define RCV_NOBUF BIT(8) +#define RCV_DROP BIT(7) +#define TX_DROP BIT(6) +#define DEF_INT_ERR (RCV_NOBUF | RCV_DROP | TX_DROP) +#define DEF_INT_MASK (RCV_INT | DEF_INT_ERR) + +/* TX descriptor config */ +#define TX_FREE_MEM BIT(0) +#define TX_READ_ALLOC_L3 BIT(1) +#define TX_FINISH_CACHE_INV BIT(2) +#define TX_CLEAR_WB BIT(4) +#define TX_L3_CHECKSUM BIT(5) +#define TX_LOOP_BACK BIT(11) + +/* RX error */ +#define RX_PKT_DROP BIT(0) +#define RX_L2_ERR BIT(1) +#define RX_PKT_ERR (RX_PKT_DROP | RX_L2_ERR) + +#define SGMII_SPEED_1000 0x08 +#define SGMII_SPEED_100 0x07 +#define SGMII_SPEED_10 0x06 +#define MII_SPEED_100 0x01 +#define MII_SPEED_10 0x00 + +#define GE_DUPLEX_FULL BIT(0) +#define GE_DUPLEX_HALF 0x00 +#define GE_MODE_CHANGE_EN BIT(0) + +#define GE_TX_AUTO_NEG BIT(5) +#define GE_TX_ADD_CRC BIT(6) +#define GE_TX_SHORT_PAD_THROUGH BIT(7) + +#define GE_RX_STRIP_CRC BIT(0) +#define GE_RX_STRIP_PAD BIT(3) +#define GE_RX_PAD_EN BIT(4) + +#define GE_AUTO_NEG_CTL BIT(0) + +#define GE_RX_INT_THRESHOLD BIT(6) +#define GE_RX_TIMEOUT 0x04 + +#define GE_RX_PORT_EN BIT(1) +#define GE_TX_PORT_EN BIT(2) + +#define PPE_CFG_STS_RX_PKT_CNT_RC BIT(12) + +#define PPE_CFG_RX_PKT_ALIGN BIT(18) +#define PPE_CFG_QOS_VMID_MODE BIT(14) +#define PPE_CFG_QOS_VMID_GRP_SHIFT 8 + +#define PPE_CFG_RX_FIFO_FSFU BIT(11) +#define PPE_CFG_RX_DEPTH_SHIFT 16 +#define PPE_CFG_RX_START_SHIFT 0 +#define PPE_CFG_RX_CTRL_ALIGN_SHIFT 11 + +#define PPE_CFG_BUS_LOCAL_REL BIT(14) +#define PPE_CFG_BUS_BIG_ENDIEN BIT(0) + +#define RX_DESC_NUM 128 +#define TX_DESC_NUM 256 +#define TX_NEXT(N) (((N) + 1) & (TX_DESC_NUM-1)) +#define RX_NEXT(N) (((N) + 1) & (RX_DESC_NUM-1)) + +#define GMAC_PPE_RX_PKT_MAX_LEN 379 +#define GMAC_MAX_PKT_LEN 1516 +#define GMAC_MIN_PKT_LEN 31 +#define RX_BUF_SIZE 1600 +#define RESET_TIMEOUT 1000 +#define TX_TIMEOUT (6 * HZ) + +#define DRV_NAME "hip04-ether" +#define DRV_VERSION "v1.0" + +#define HIP04_MAX_TX_COALESCE_USECS 200 +#define HIP04_MIN_TX_COALESCE_USECS 100 +#define HIP04_MAX_TX_COALESCE_FRAMES 200 +#define HIP04_MIN_TX_COALESCE_FRAMES 100 + +struct tx_desc { + u32 send_addr; + u32 send_size; + u32 next_addr; + u32 cfg; + u32 wb_addr; +} __aligned(64); + +struct rx_desc { + u16 reserved_16; + u16 pkt_len; + u32 reserve1[3]; + u32 pkt_err; + u32 reserve2[4]; +}; + +struct hip04_priv { + void __iomem *base; + int phy_mode; + int chan; + unsigned int port; + unsigned int speed; + unsigned int duplex; + unsigned int reg_inten; + + struct napi_struct napi; + struct net_device *ndev; + + struct tx_desc *tx_desc; + dma_addr_t tx_desc_dma; + struct sk_buff *tx_skb[TX_DESC_NUM]; + dma_addr_t tx_phys[TX_DESC_NUM]; + unsigned int tx_head; + + int tx_coalesce_frames; + int tx_coalesce_usecs; + struct hrtimer tx_coalesce_timer; + + unsigned char *rx_buf[RX_DESC_NUM]; + dma_addr_t rx_phys[RX_DESC_NUM]; + unsigned int rx_head; + unsigned int rx_buf_size; + + struct device_node *phy_node; + struct phy_device *phy; + struct regmap *map; + struct work_struct tx_timeout_task; + + /* written only by tx cleanup */ + unsigned int tx_tail ____cacheline_aligned_in_smp; +}; + +static inline unsigned int tx_count(unsigned int head, unsigned int tail) +{ + return (head - tail) % (TX_DESC_NUM - 1); +} + +static void hip04_config_port(struct net_device *ndev, u32 speed, u32 duplex) +{ + struct hip04_priv *priv = netdev_priv(ndev); + u32 val; + + priv->speed = speed; + priv->duplex = duplex; + + switch (priv->phy_mode) { + case PHY_INTERFACE_MODE_SGMII: + if (speed == SPEED_1000) + val = SGMII_SPEED_1000; + else if (speed == SPEED_100) + val = SGMII_SPEED_100; + else + val = SGMII_SPEED_10; + break; + case PHY_INTERFACE_MODE_MII: + if (speed == SPEED_100) + val = MII_SPEED_100; + else + val = MII_SPEED_10; + break; + default: + netdev_warn(ndev, "not supported mode\n"); + val = MII_SPEED_10; + break; + } + writel_relaxed(val, priv->base + GE_PORT_MODE); + + val = duplex ? GE_DUPLEX_FULL : GE_DUPLEX_HALF; + writel_relaxed(val, priv->base + GE_DUPLEX_TYPE); + + val = GE_MODE_CHANGE_EN; + writel_relaxed(val, priv->base + GE_MODE_CHANGE_REG); +} + +static void hip04_reset_ppe(struct hip04_priv *priv) +{ + u32 val, tmp, timeout = 0; + + do { + regmap_read(priv->map, priv->port * 4 + PPE_CURR_BUF_CNT, &val); + regmap_read(priv->map, priv->port * 4 + PPE_CFG_RX_ADDR, &tmp); + if (timeout++ > RESET_TIMEOUT) + break; + } while (val & 0xfff); +} + +static void hip04_config_fifo(struct hip04_priv *priv) +{ + u32 val; + + val = readl_relaxed(priv->base + PPE_CFG_STS_MODE); + val |= PPE_CFG_STS_RX_PKT_CNT_RC; + writel_relaxed(val, priv->base + PPE_CFG_STS_MODE); + + val = BIT(priv->port); + regmap_write(priv->map, priv->port * 4 + PPE_CFG_POOL_GRP, val); + + val = priv->port << PPE_CFG_QOS_VMID_GRP_SHIFT; + val |= PPE_CFG_QOS_VMID_MODE; + writel_relaxed(val, priv->base + PPE_CFG_QOS_VMID_GEN); + + val = RX_BUF_SIZE; + regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_BUF_SIZE, val); + + val = RX_DESC_NUM << PPE_CFG_RX_DEPTH_SHIFT; + val |= PPE_CFG_RX_FIFO_FSFU; + val |= priv->chan << PPE_CFG_RX_START_SHIFT; + regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_FIFO_SIZE, val); + + val = NET_IP_ALIGN << PPE_CFG_RX_CTRL_ALIGN_SHIFT; + writel_relaxed(val, priv->base + PPE_CFG_RX_CTRL_REG); + + val = PPE_CFG_RX_PKT_ALIGN; + writel_relaxed(val, priv->base + PPE_CFG_RX_PKT_MODE_REG); + + val = PPE_CFG_BUS_LOCAL_REL | PPE_CFG_BUS_BIG_ENDIEN; + writel_relaxed(val, priv->base + PPE_CFG_BUS_CTRL_REG); + + val = GMAC_PPE_RX_PKT_MAX_LEN; + writel_relaxed(val, priv->base + PPE_CFG_MAX_FRAME_LEN_REG); + + val = GMAC_MAX_PKT_LEN; + writel_relaxed(val, priv->base + GE_MAX_FRM_SIZE_REG); + + val = GMAC_MIN_PKT_LEN; + writel_relaxed(val, priv->base + GE_SHORT_RUNTS_THR_REG); + + val = readl_relaxed(priv->base + GE_TRANSMIT_CONTROL_REG); + val |= GE_TX_AUTO_NEG | GE_TX_ADD_CRC | GE_TX_SHORT_PAD_THROUGH; + writel_relaxed(val, priv->base + GE_TRANSMIT_CONTROL_REG); + + val = GE_RX_STRIP_CRC; + writel_relaxed(val, priv->base + GE_CF_CRC_STRIP_REG); + + val = readl_relaxed(priv->base + GE_RECV_CONTROL_REG); + val |= GE_RX_STRIP_PAD | GE_RX_PAD_EN; + writel_relaxed(val, priv->base + GE_RECV_CONTROL_REG); + + val = GE_AUTO_NEG_CTL; + writel_relaxed(val, priv->base + GE_TX_LOCAL_PAGE_REG); +} + +static void hip04_mac_enable(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + u32 val; + + /* enable tx & rx */ + val = readl_relaxed(priv->base + GE_PORT_EN); + val |= GE_RX_PORT_EN | GE_TX_PORT_EN; + writel_relaxed(val, priv->base + GE_PORT_EN); + + /* clear rx int */ + val = RCV_INT; + writel_relaxed(val, priv->base + PPE_RINT); + + /* config recv int */ + val = GE_RX_INT_THRESHOLD | GE_RX_TIMEOUT; + writel_relaxed(val, priv->base + PPE_CFG_RX_PKT_INT); + + /* enable interrupt */ + priv->reg_inten = DEF_INT_MASK; + writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); +} + +static void hip04_mac_disable(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + u32 val; + + /* disable int */ + priv->reg_inten &= ~(DEF_INT_MASK); + writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); + + /* disable tx & rx */ + val = readl_relaxed(priv->base + GE_PORT_EN); + val &= ~(GE_RX_PORT_EN | GE_TX_PORT_EN); + writel_relaxed(val, priv->base + GE_PORT_EN); +} + +static void hip04_set_xmit_desc(struct hip04_priv *priv, dma_addr_t phys) +{ + writel(phys, priv->base + PPE_CFG_CPU_ADD_ADDR); +} + +static void hip04_set_recv_desc(struct hip04_priv *priv, dma_addr_t phys) +{ + regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_ADDR, phys); +} + +static u32 hip04_recv_cnt(struct hip04_priv *priv) +{ + return readl(priv->base + PPE_HIS_RX_PKT_CNT); +} + +static void hip04_update_mac_address(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + + writel_relaxed(((ndev->dev_addr[0] << 8) | (ndev->dev_addr[1])), + priv->base + GE_STATION_MAC_ADDRESS); + writel_relaxed(((ndev->dev_addr[2] << 24) | (ndev->dev_addr[3] << 16) | + (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5])), + priv->base + GE_STATION_MAC_ADDRESS + 4); +} + +static int hip04_set_mac_address(struct net_device *ndev, void *addr) +{ + eth_mac_addr(ndev, addr); + hip04_update_mac_address(ndev); + return 0; +} + +static int hip04_tx_reclaim(struct net_device *ndev, bool force) +{ + struct hip04_priv *priv = netdev_priv(ndev); + unsigned tx_tail = priv->tx_tail; + struct tx_desc *desc; + unsigned int bytes_compl = 0, pkts_compl = 0; + unsigned int count; + + smp_rmb(); + count = tx_count(ACCESS_ONCE(priv->tx_head), tx_tail); + if (count == 0) + goto out; + + while (count) { + desc = &priv->tx_desc[tx_tail]; + if (desc->send_addr != 0) { + if (force) + desc->send_addr = 0; + else + break; + } + + if (priv->tx_phys[tx_tail]) { + dma_unmap_single(&ndev->dev, priv->tx_phys[tx_tail], + priv->tx_skb[tx_tail]->len, + DMA_TO_DEVICE); + priv->tx_phys[tx_tail] = 0; + } + pkts_compl++; + bytes_compl += priv->tx_skb[tx_tail]->len; + dev_kfree_skb(priv->tx_skb[tx_tail]); + priv->tx_skb[tx_tail] = NULL; + tx_tail = TX_NEXT(tx_tail); + count--; + } + + priv->tx_tail = tx_tail; + smp_wmb(); /* Ensure tx_tail visible to xmit */ + +out: + if (pkts_compl || bytes_compl) + netdev_completed_queue(ndev, pkts_compl, bytes_compl); + + if (unlikely(netif_queue_stopped(ndev)) && (count < (TX_DESC_NUM - 1))) + netif_wake_queue(ndev); + + return count; +} + +static int hip04_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + unsigned int tx_head = priv->tx_head, count; + struct tx_desc *desc = &priv->tx_desc[tx_head]; + dma_addr_t phys; + + smp_rmb(); + count = tx_count(tx_head, ACCESS_ONCE(priv->tx_tail)); + if (count == (TX_DESC_NUM - 1)) { + netif_stop_queue(ndev); + return NETDEV_TX_BUSY; + } + + phys = dma_map_single(&ndev->dev, skb->data, skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(&ndev->dev, phys)) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + priv->tx_skb[tx_head] = skb; + priv->tx_phys[tx_head] = phys; + desc->send_addr = cpu_to_be32(phys); + desc->send_size = cpu_to_be32(skb->len); + desc->cfg = cpu_to_be32(TX_CLEAR_WB | TX_FINISH_CACHE_INV); + phys = priv->tx_desc_dma + tx_head * sizeof(struct tx_desc); + desc->wb_addr = cpu_to_be32(phys); + skb_tx_timestamp(skb); + + hip04_set_xmit_desc(priv, phys); + priv->tx_head = TX_NEXT(tx_head); + count++; + netdev_sent_queue(ndev, skb->len); + + stats->tx_bytes += skb->len; + stats->tx_packets++; + + /* Ensure tx_head update visible to tx reclaim */ + smp_wmb(); + + /* queue is getting full, better start cleaning up now */ + if (count >= priv->tx_coalesce_frames) { + if (napi_schedule_prep(&priv->napi)) { + /* disable rx interrupt and timer */ + priv->reg_inten &= ~(RCV_INT); + writel_relaxed(DEF_INT_MASK & ~RCV_INT, + priv->base + PPE_INTEN); + hrtimer_cancel(&priv->tx_coalesce_timer); + __napi_schedule(&priv->napi); + } + } else if (!hrtimer_is_queued(&priv->tx_coalesce_timer)) { + /* cleanup not pending yet, start a new timer */ + hrtimer_start_expires(&priv->tx_coalesce_timer, + HRTIMER_MODE_REL); + } + + return NETDEV_TX_OK; +} + +static int hip04_rx_poll(struct napi_struct *napi, int budget) +{ + struct hip04_priv *priv = container_of(napi, struct hip04_priv, napi); + struct net_device *ndev = priv->ndev; + struct net_device_stats *stats = &ndev->stats; + unsigned int cnt = hip04_recv_cnt(priv); + struct rx_desc *desc; + struct sk_buff *skb; + unsigned char *buf; + bool last = false; + dma_addr_t phys; + int rx = 0; + int tx_remaining; + u16 len; + u32 err; + + while (cnt && !last) { + buf = priv->rx_buf[priv->rx_head]; + skb = build_skb(buf, priv->rx_buf_size); + if (unlikely(!skb)) + net_dbg_ratelimited("build_skb failed\n"); + + dma_unmap_single(&ndev->dev, priv->rx_phys[priv->rx_head], + RX_BUF_SIZE, DMA_FROM_DEVICE); + priv->rx_phys[priv->rx_head] = 0; + + desc = (struct rx_desc *)skb->data; + len = be16_to_cpu(desc->pkt_len); + err = be32_to_cpu(desc->pkt_err); + + if (0 == len) { + dev_kfree_skb_any(skb); + last = true; + } else if ((err & RX_PKT_ERR) || (len >= GMAC_MAX_PKT_LEN)) { + dev_kfree_skb_any(skb); + stats->rx_dropped++; + stats->rx_errors++; + } else { + skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, ndev); + napi_gro_receive(&priv->napi, skb); + stats->rx_packets++; + stats->rx_bytes += len; + rx++; + } + + buf = netdev_alloc_frag(priv->rx_buf_size); + if (!buf) + goto done; + phys = dma_map_single(&ndev->dev, buf, + RX_BUF_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(&ndev->dev, phys)) + goto done; + priv->rx_buf[priv->rx_head] = buf; + priv->rx_phys[priv->rx_head] = phys; + hip04_set_recv_desc(priv, phys); + + priv->rx_head = RX_NEXT(priv->rx_head); + if (rx >= budget) + goto done; + + if (--cnt == 0) + cnt = hip04_recv_cnt(priv); + } + + if (!(priv->reg_inten & RCV_INT)) { + /* enable rx interrupt */ + priv->reg_inten |= RCV_INT; + writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN); + } + napi_complete(napi); +done: + /* clean up tx descriptors and start a new timer if necessary */ + tx_remaining = hip04_tx_reclaim(ndev, false); + if (rx < budget && tx_remaining) + hrtimer_start_expires(&priv->tx_coalesce_timer, HRTIMER_MODE_REL); + + return rx; +} + +static irqreturn_t hip04_mac_interrupt(int irq, void *dev_id) +{ + struct net_device *ndev = (struct net_device *)dev_id; + struct hip04_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + u32 ists = readl_relaxed(priv->base + PPE_INTSTS); + + if (!ists) + return IRQ_NONE; + + writel_relaxed(DEF_INT_MASK, priv->base + PPE_RINT); + + if (unlikely(ists & DEF_INT_ERR)) { + if (ists & (RCV_NOBUF | RCV_DROP)) { + stats->rx_errors++; + stats->rx_dropped++; + netdev_err(ndev, "rx drop\n"); + } + if (ists & TX_DROP) { + stats->tx_dropped++; + netdev_err(ndev, "tx drop\n"); + } + } + + if (ists & RCV_INT && napi_schedule_prep(&priv->napi)) { + /* disable rx interrupt */ + priv->reg_inten &= ~(RCV_INT); + writel_relaxed(DEF_INT_MASK & ~RCV_INT, priv->base + PPE_INTEN); + hrtimer_cancel(&priv->tx_coalesce_timer); + __napi_schedule(&priv->napi); + } + + return IRQ_HANDLED; +} + +enum hrtimer_restart tx_done(struct hrtimer *hrtimer) +{ + struct hip04_priv *priv; + + priv = container_of(hrtimer, struct hip04_priv, tx_coalesce_timer); + + if (napi_schedule_prep(&priv->napi)) { + /* disable rx interrupt */ + priv->reg_inten &= ~(RCV_INT); + writel_relaxed(DEF_INT_MASK & ~RCV_INT, priv->base + PPE_INTEN); + __napi_schedule(&priv->napi); + } + + return HRTIMER_NORESTART; +} + +static void hip04_adjust_link(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + struct phy_device *phy = priv->phy; + + if ((priv->speed != phy->speed) || (priv->duplex != phy->duplex)) { + hip04_config_port(ndev, phy->speed, phy->duplex); + phy_print_status(phy); + } +} + +static int hip04_mac_open(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + int i; + + priv->rx_head = 0; + priv->tx_head = 0; + priv->tx_tail = 0; + hip04_reset_ppe(priv); + + for (i = 0; i < RX_DESC_NUM; i++) { + dma_addr_t phys; + + phys = dma_map_single(&ndev->dev, priv->rx_buf[i], + RX_BUF_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(&ndev->dev, phys)) + return -EIO; + + priv->rx_phys[i] = phys; + hip04_set_recv_desc(priv, phys); + } + + if (priv->phy) + phy_start(priv->phy); + + netdev_reset_queue(ndev); + netif_start_queue(ndev); + hip04_mac_enable(ndev); + napi_enable(&priv->napi); + + return 0; +} + +static int hip04_mac_stop(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + int i; + + napi_disable(&priv->napi); + netif_stop_queue(ndev); + hip04_mac_disable(ndev); + hip04_tx_reclaim(ndev, true); + hip04_reset_ppe(priv); + + if (priv->phy) + phy_stop(priv->phy); + + for (i = 0; i < RX_DESC_NUM; i++) { + if (priv->rx_phys[i]) { + dma_unmap_single(&ndev->dev, priv->rx_phys[i], + RX_BUF_SIZE, DMA_FROM_DEVICE); + priv->rx_phys[i] = 0; + } + } + + return 0; +} + +static void hip04_timeout(struct net_device *ndev) +{ + struct hip04_priv *priv = netdev_priv(ndev); + + schedule_work(&priv->tx_timeout_task); +} + +static void hip04_tx_timeout_task(struct work_struct *work) +{ + struct hip04_priv *priv; + + priv = container_of(work, struct hip04_priv, tx_timeout_task); + hip04_mac_stop(priv->ndev); + hip04_mac_open(priv->ndev); +} + +static struct net_device_stats *hip04_get_stats(struct net_device *ndev) +{ + return &ndev->stats; +} + +static int hip04_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct hip04_priv *priv = netdev_priv(netdev); + + ec->tx_coalesce_usecs = priv->tx_coalesce_usecs; + ec->tx_max_coalesced_frames = priv->tx_coalesce_frames; + + return 0; +} + +static int hip04_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct hip04_priv *priv = netdev_priv(netdev); + + /* Check not supported parameters */ + if ((ec->rx_max_coalesced_frames) || (ec->rx_coalesce_usecs_irq) || + (ec->rx_max_coalesced_frames_irq) || (ec->tx_coalesce_usecs_irq) || + (ec->use_adaptive_rx_coalesce) || (ec->use_adaptive_tx_coalesce) || + (ec->pkt_rate_low) || (ec->rx_coalesce_usecs_low) || + (ec->rx_max_coalesced_frames_low) || (ec->tx_coalesce_usecs_high) || + (ec->tx_max_coalesced_frames_low) || (ec->pkt_rate_high) || + (ec->tx_coalesce_usecs_low) || (ec->rx_coalesce_usecs_high) || + (ec->rx_max_coalesced_frames_high) || (ec->rx_coalesce_usecs) || + (ec->tx_max_coalesced_frames_irq) || + (ec->stats_block_coalesce_usecs) || + (ec->tx_max_coalesced_frames_high) || (ec->rate_sample_interval)) + return -EOPNOTSUPP; + + if ((ec->tx_coalesce_usecs > HIP04_MAX_TX_COALESCE_USECS || + ec->tx_coalesce_usecs < HIP04_MIN_TX_COALESCE_USECS) || + (ec->tx_max_coalesced_frames > HIP04_MAX_TX_COALESCE_FRAMES || + ec->tx_max_coalesced_frames < HIP04_MIN_TX_COALESCE_FRAMES)) + return -EINVAL; + + priv->tx_coalesce_usecs = ec->tx_coalesce_usecs; + priv->tx_coalesce_frames = ec->tx_max_coalesced_frames; + + return 0; +} + +static void hip04_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); + strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version)); +} + +static struct ethtool_ops hip04_ethtool_ops = { + .get_coalesce = hip04_get_coalesce, + .set_coalesce = hip04_set_coalesce, + .get_drvinfo = hip04_get_drvinfo, +}; + +static struct net_device_ops hip04_netdev_ops = { + .ndo_open = hip04_mac_open, + .ndo_stop = hip04_mac_stop, + .ndo_get_stats = hip04_get_stats, + .ndo_start_xmit = hip04_mac_start_xmit, + .ndo_set_mac_address = hip04_set_mac_address, + .ndo_tx_timeout = hip04_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +}; + +static int hip04_alloc_ring(struct net_device *ndev, struct device *d) +{ + struct hip04_priv *priv = netdev_priv(ndev); + int i; + + priv->tx_desc = dma_alloc_coherent(d, + TX_DESC_NUM * sizeof(struct tx_desc), + &priv->tx_desc_dma, GFP_KERNEL); + if (!priv->tx_desc) + return -ENOMEM; + + priv->rx_buf_size = RX_BUF_SIZE + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + for (i = 0; i < RX_DESC_NUM; i++) { + priv->rx_buf[i] = netdev_alloc_frag(priv->rx_buf_size); + if (!priv->rx_buf[i]) + return -ENOMEM; + } + + return 0; +} + +static void hip04_free_ring(struct net_device *ndev, struct device *d) +{ + struct hip04_priv *priv = netdev_priv(ndev); + int i; + + for (i = 0; i < RX_DESC_NUM; i++) + if (priv->rx_buf[i]) + put_page(virt_to_head_page(priv->rx_buf[i])); + + for (i = 0; i < TX_DESC_NUM; i++) + if (priv->tx_skb[i]) + dev_kfree_skb_any(priv->tx_skb[i]); + + dma_free_coherent(d, TX_DESC_NUM * sizeof(struct tx_desc), + priv->tx_desc, priv->tx_desc_dma); +} + +static int hip04_mac_probe(struct platform_device *pdev) +{ + struct device *d = &pdev->dev; + struct device_node *node = d->of_node; + struct of_phandle_args arg; + struct net_device *ndev; + struct hip04_priv *priv; + struct resource *res; + unsigned int irq; + ktime_t txtime; + int ret; + + ndev = alloc_etherdev(sizeof(struct hip04_priv)); + if (!ndev) + return -ENOMEM; + + priv = netdev_priv(ndev); + priv->ndev = ndev; + platform_set_drvdata(pdev, ndev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(d, res); + if (IS_ERR(priv->base)) { + ret = PTR_ERR(priv->base); + goto init_fail; + } + + ret = of_parse_phandle_with_fixed_args(node, "port-handle", 2, 0, &arg); + if (ret < 0) { + dev_warn(d, "no port-handle\n"); + goto init_fail; + } + + priv->port = arg.args[0]; + priv->chan = arg.args[1] * RX_DESC_NUM; + + hrtimer_init(&priv->tx_coalesce_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + + /* BQL will try to keep the TX queue as short as possible, but it can't + * be faster than tx_coalesce_usecs, so we need a fast timeout here, + * but also long enough to gather up enough frames to ensure we don't + * get more interrupts than necessary. + * 200us is enough for 16 frames of 1500 bytes at gigabit ethernet rate + */ + priv->tx_coalesce_frames = TX_DESC_NUM * 3 / 4; + priv->tx_coalesce_usecs = 200; + /* allow timer to fire after half the time at the earliest */ + txtime = ktime_set(0, priv->tx_coalesce_usecs * NSEC_PER_USEC / 2); + hrtimer_set_expires_range(&priv->tx_coalesce_timer, txtime, txtime); + priv->tx_coalesce_timer.function = tx_done; + + priv->map = syscon_node_to_regmap(arg.np); + if (IS_ERR(priv->map)) { + dev_warn(d, "no syscon hisilicon,hip04-ppe\n"); + ret = PTR_ERR(priv->map); + goto init_fail; + } + + priv->phy_mode = of_get_phy_mode(node); + if (priv->phy_mode < 0) { + dev_warn(d, "not find phy-mode\n"); + ret = -EINVAL; + goto init_fail; + } + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + ret = -EINVAL; + goto init_fail; + } + + ret = devm_request_irq(d, irq, hip04_mac_interrupt, + 0, pdev->name, ndev); + if (ret) { + netdev_err(ndev, "devm_request_irq failed\n"); + goto init_fail; + } + + priv->phy_node = of_parse_phandle(node, "phy-handle", 0); + if (priv->phy_node) { + priv->phy = of_phy_connect(ndev, priv->phy_node, + &hip04_adjust_link, + 0, priv->phy_mode); + if (!priv->phy) { + ret = -EPROBE_DEFER; + goto init_fail; + } + } + + INIT_WORK(&priv->tx_timeout_task, hip04_tx_timeout_task); + + ether_setup(ndev); + ndev->netdev_ops = &hip04_netdev_ops; + ndev->ethtool_ops = &hip04_ethtool_ops; + ndev->watchdog_timeo = TX_TIMEOUT; + ndev->priv_flags |= IFF_UNICAST_FLT; + ndev->irq = irq; + netif_napi_add(ndev, &priv->napi, hip04_rx_poll, NAPI_POLL_WEIGHT); + SET_NETDEV_DEV(ndev, &pdev->dev); + + hip04_reset_ppe(priv); + if (priv->phy_mode == PHY_INTERFACE_MODE_MII) + hip04_config_port(ndev, SPEED_100, DUPLEX_FULL); + + hip04_config_fifo(priv); + random_ether_addr(ndev->dev_addr); + hip04_update_mac_address(ndev); + + ret = hip04_alloc_ring(ndev, d); + if (ret) { + netdev_err(ndev, "alloc ring fail\n"); + goto alloc_fail; + } + + ret = register_netdev(ndev); + if (ret) { + free_netdev(ndev); + goto alloc_fail; + } + + return 0; + +alloc_fail: + hip04_free_ring(ndev, d); +init_fail: + of_node_put(priv->phy_node); + free_netdev(ndev); + return ret; +} + +static int hip04_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct hip04_priv *priv = netdev_priv(ndev); + struct device *d = &pdev->dev; + + if (priv->phy) + phy_disconnect(priv->phy); + + hip04_free_ring(ndev, d); + unregister_netdev(ndev); + free_irq(ndev->irq, ndev); + of_node_put(priv->phy_node); + cancel_work_sync(&priv->tx_timeout_task); + free_netdev(ndev); + + return 0; +} + +static const struct of_device_id hip04_mac_match[] = { + { .compatible = "hisilicon,hip04-mac" }, + { } +}; + +MODULE_DEVICE_TABLE(of, hip04_mac_match); + +static struct platform_driver hip04_mac_driver = { + .probe = hip04_mac_probe, + .remove = hip04_remove, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = hip04_mac_match, + }, +}; +module_platform_driver(hip04_mac_driver); + +MODULE_DESCRIPTION("HISILICON P04 Ethernet driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/hisilicon/hip04_mdio.c b/drivers/net/ethernet/hisilicon/hip04_mdio.c new file mode 100644 index 000000000000..b3bac25db99c --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hip04_mdio.c @@ -0,0 +1,186 @@ +/* Copyright (c) 2014 Linaro Ltd. + * Copyright (c) 2014 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#define MDIO_CMD_REG 0x0 +#define MDIO_ADDR_REG 0x4 +#define MDIO_WDATA_REG 0x8 +#define MDIO_RDATA_REG 0xc +#define MDIO_STA_REG 0x10 + +#define MDIO_START BIT(14) +#define MDIO_R_VALID BIT(1) +#define MDIO_READ (BIT(12) | BIT(11) | MDIO_START) +#define MDIO_WRITE (BIT(12) | BIT(10) | MDIO_START) + +struct hip04_mdio_priv { + void __iomem *base; +}; + +#define WAIT_TIMEOUT 10 +static int hip04_mdio_wait_ready(struct mii_bus *bus) +{ + struct hip04_mdio_priv *priv = bus->priv; + int i; + + for (i = 0; readl_relaxed(priv->base + MDIO_CMD_REG) & MDIO_START; i++) { + if (i == WAIT_TIMEOUT) + return -ETIMEDOUT; + msleep(20); + } + + return 0; +} + +static int hip04_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct hip04_mdio_priv *priv = bus->priv; + u32 val; + int ret; + + ret = hip04_mdio_wait_ready(bus); + if (ret < 0) + goto out; + + val = regnum | (mii_id << 5) | MDIO_READ; + writel_relaxed(val, priv->base + MDIO_CMD_REG); + + ret = hip04_mdio_wait_ready(bus); + if (ret < 0) + goto out; + + val = readl_relaxed(priv->base + MDIO_STA_REG); + if (val & MDIO_R_VALID) { + dev_err(bus->parent, "SMI bus read not valid\n"); + ret = -ENODEV; + goto out; + } + + val = readl_relaxed(priv->base + MDIO_RDATA_REG); + ret = val & 0xFFFF; +out: + return ret; +} + +static int hip04_mdio_write(struct mii_bus *bus, int mii_id, + int regnum, u16 value) +{ + struct hip04_mdio_priv *priv = bus->priv; + u32 val; + int ret; + + ret = hip04_mdio_wait_ready(bus); + if (ret < 0) + goto out; + + writel_relaxed(value, priv->base + MDIO_WDATA_REG); + val = regnum | (mii_id << 5) | MDIO_WRITE; + writel_relaxed(val, priv->base + MDIO_CMD_REG); +out: + return ret; +} + +static int hip04_mdio_reset(struct mii_bus *bus) +{ + int temp, i; + + for (i = 0; i < PHY_MAX_ADDR; i++) { + hip04_mdio_write(bus, i, 22, 0); + temp = hip04_mdio_read(bus, i, MII_BMCR); + if (temp < 0) + continue; + + temp |= BMCR_RESET; + if (hip04_mdio_write(bus, i, MII_BMCR, temp) < 0) + continue; + } + + mdelay(500); + return 0; +} + +static int hip04_mdio_probe(struct platform_device *pdev) +{ + struct resource *r; + struct mii_bus *bus; + struct hip04_mdio_priv *priv; + int ret; + + bus = mdiobus_alloc_size(sizeof(struct hip04_mdio_priv)); + if (!bus) { + dev_err(&pdev->dev, "Cannot allocate MDIO bus\n"); + return -ENOMEM; + } + + bus->name = "hip04_mdio_bus"; + bus->read = hip04_mdio_read; + bus->write = hip04_mdio_write; + bus->reset = hip04_mdio_reset; + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev)); + bus->parent = &pdev->dev; + priv = bus->priv; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(priv->base)) { + ret = PTR_ERR(priv->base); + goto out_mdio; + } + + ret = of_mdiobus_register(bus, pdev->dev.of_node); + if (ret < 0) { + dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret); + goto out_mdio; + } + + platform_set_drvdata(pdev, bus); + + return 0; + +out_mdio: + mdiobus_free(bus); + return ret; +} + +static int hip04_mdio_remove(struct platform_device *pdev) +{ + struct mii_bus *bus = platform_get_drvdata(pdev); + + mdiobus_unregister(bus); + mdiobus_free(bus); + + return 0; +} + +static const struct of_device_id hip04_mdio_match[] = { + { .compatible = "hisilicon,hip04-mdio" }, + { } +}; +MODULE_DEVICE_TABLE(of, hip04_mdio_match); + +static struct platform_driver hip04_mdio_driver = { + .probe = hip04_mdio_probe, + .remove = hip04_mdio_remove, + .driver = { + .name = "hip04-mdio", + .owner = THIS_MODULE, + .of_match_table = hip04_mdio_match, + }, +}; + +module_platform_driver(hip04_mdio_driver); + +MODULE_DESCRIPTION("HISILICON P04 MDIO interface driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:hip04-mdio"); diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c index 566b17db135a..e8a1adb7a962 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c @@ -2064,9 +2064,9 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) memset(swqe, 0, SWQE_HEADER_SIZE); atomic_dec(&pr->swqe_avail); - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { swqe->tx_control |= EHEA_SWQE_VLAN_INSERT; - swqe->vlan_tag = vlan_tx_tag_get(skb); + swqe->vlan_tag = skb_vlan_tag_get(skb); } pr->tx_packets++; diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c index 9388a83818f2..162762d1a12c 100644 --- a/drivers/net/ethernet/ibm/emac/core.c +++ b/drivers/net/ethernet/ibm/emac/core.c @@ -2367,7 +2367,7 @@ static int emac_wait_deps(struct emac_instance *dev) err = emac_check_deps(dev, deps) ? 0 : -ENODEV; for (i = 0; i < EMAC_DEP_COUNT; i++) { of_node_put(deps[i].node); - if (err && deps[i].ofdev) + if (err) of_dev_put(deps[i].ofdev); } if (err == 0) { diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 4d61ef50b465..f4ff465584a0 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -192,6 +192,17 @@ config IXGBE To compile this driver as a module, choose M here. The module will be called ixgbe. +config IXGBE_VXLAN + bool "Virtual eXtensible Local Area Network Support" + default n + depends on IXGBE && VXLAN && !(IXGBE=y && VXLAN=m) + ---help--- + This allows one to create VXLAN virtual interfaces that provide + Layer 2 Networks over Layer 3 Networks. VXLAN is often used + to tunnel virtual network infrastructure in virtualized environments. + Say Y here if you want to use Virtual eXtensible Local Area Network + (VXLAN) in the driver. + config IXGBE_HWMON bool "Intel(R) 10GbE PCI Express adapters HWMON support" default y diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c index b691eb4f6376..4270ad2d4ddf 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c @@ -24,6 +24,7 @@ /* ethtool support for e1000 */ #include "e1000.h" +#include #include enum {NETDEV_STATS, E1000_STATS}; @@ -1460,7 +1461,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter) ret_val = 13; /* ret_val is the same as mis-compare */ break; } - if (jiffies >= (time + 2)) { + if (time_after_eq(jiffies, time + 2)) { ret_val = 14; /* error code for time out error */ break; } diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 83140cbb5f01..7f997d36948f 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -2977,7 +2977,6 @@ static void e1000_tx_queue(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, int tx_flags, int count) { - struct e1000_hw *hw = &adapter->hw; struct e1000_tx_desc *tx_desc = NULL; struct e1000_tx_buffer *buffer_info; u32 txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; @@ -3031,11 +3030,6 @@ static void e1000_tx_queue(struct e1000_adapter *adapter, wmb(); tx_ring->next_to_use = i; - writel(i, hw->hw_addr + tx_ring->tdt); - /* we need this if more than one processor can write to our tail - * at a time, it synchronizes IO on IA64/Altix systems - */ - mmiowb(); } /* 82547 workaround to avoid controller hang in half-duplex environment. @@ -3226,9 +3220,10 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, return NETDEV_TX_BUSY; } - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { tx_flags |= E1000_TX_FLAGS_VLAN; - tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); + tx_flags |= (skb_vlan_tag_get(skb) << + E1000_TX_FLAGS_VLAN_SHIFT); } first = tx_ring->next_to_use; @@ -3263,6 +3258,15 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, /* Make sure there is space in the ring for the next send. */ e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2); + if (!skb->xmit_more || + netif_xmit_stopped(netdev_get_tx_queue(netdev, 0))) { + writel(tx_ring->next_to_use, hw->hw_addr + tx_ring->tdt); + /* we need this if more than one processor can write to + * our tail at a time, it synchronizes IO on IA64/Altix + * systems + */ + mmiowb(); + } } else { dev_kfree_skb_any(skb); tx_ring->buffer_info[first].time_stamp = 0; diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 7785240a0da1..9416e5a7e0c8 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index e14fd85f64eb..1e8c40fd5c3d 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -4189,7 +4189,7 @@ static int e1000_sw_init(struct e1000_adapter *adapter) /* Setup hardware time stamping cyclecounter */ if (adapter->flags & FLAG_HAS_HW_TIMESTAMP) { adapter->cc.read = e1000e_cyclecounter_read; - adapter->cc.mask = CLOCKSOURCE_MASK(64); + adapter->cc.mask = CYCLECOUNTER_MASK(64); adapter->cc.mult = 1; /* cc.shift set in e1000e_get_base_tininca() */ @@ -5444,16 +5444,6 @@ static void e1000_tx_queue(struct e1000_ring *tx_ring, int tx_flags, int count) wmb(); tx_ring->next_to_use = i; - - if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) - e1000e_update_tdt_wa(tx_ring, i); - else - writel(i, tx_ring->tail); - - /* we need this if more than one processor can write to our tail - * at a time, it synchronizes IO on IA64/Altix systems - */ - mmiowb(); } #define MINIMUM_DHCP_PACKET_SIZE 282 @@ -5463,8 +5453,8 @@ static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct e1000_hw *hw = &adapter->hw; u16 length, offset; - if (vlan_tx_tag_present(skb) && - !((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) && + if (skb_vlan_tag_present(skb) && + !((skb_vlan_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) && (adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN))) return 0; @@ -5603,9 +5593,10 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, if (e1000_maybe_stop_tx(tx_ring, count + 2)) return NETDEV_TX_BUSY; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { tx_flags |= E1000_TX_FLAGS_VLAN; - tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); + tx_flags |= (skb_vlan_tag_get(skb) << + E1000_TX_FLAGS_VLAN_SHIFT); } first = tx_ring->next_to_use; @@ -5635,8 +5626,9 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, count = e1000_tx_map(tx_ring, skb, first, adapter->tx_fifo_limit, nr_frags); if (count) { - if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && - !adapter->tx_hwtstamp_skb)) { + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && + (adapter->flags & FLAG_HAS_HW_TIMESTAMP) && + !adapter->tx_hwtstamp_skb) { skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; tx_flags |= E1000_TX_FLAGS_HWTSTAMP; adapter->tx_hwtstamp_skb = skb_get(skb); @@ -5653,6 +5645,21 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, (MAX_SKB_FRAGS * DIV_ROUND_UP(PAGE_SIZE, adapter->tx_fifo_limit) + 2)); + + if (!skb->xmit_more || + netif_xmit_stopped(netdev_get_tx_queue(netdev, 0))) { + if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) + e1000e_update_tdt_wa(tx_ring, + tx_ring->next_to_use); + else + writel(tx_ring->next_to_use, tx_ring->tail); + + /* we need this if more than one processor can write + * to our tail at a time, it synchronizes IO on + *IA64/Altix systems + */ + mmiowb(); + } } else { dev_kfree_skb_any(skb); tx_ring->buffer_info[first].time_stamp = 0; diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c index fb1a914a3ad4..978ef9c4a043 100644 --- a/drivers/net/ethernet/intel/e1000e/ptp.c +++ b/drivers/net/ethernet/intel/e1000e/ptp.c @@ -90,12 +90,9 @@ static int e1000e_phc_adjtime(struct ptp_clock_info *ptp, s64 delta) struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter, ptp_clock_info); unsigned long flags; - s64 now; spin_lock_irqsave(&adapter->systim_lock, flags); - now = timecounter_read(&adapter->tc); - now += delta; - timecounter_init(&adapter->tc, &adapter->cc, now); + timecounter_adjtime(&adapter->tc, delta); spin_unlock_irqrestore(&adapter->systim_lock, flags); return 0; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index eb088b129bc7..84ab9eea2768 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -97,7 +97,6 @@ static bool fm10k_alloc_mapped_page(struct fm10k_ring *rx_ring, */ if (dma_mapping_error(rx_ring->dev, dma)) { __free_page(page); - bi->page = NULL; rx_ring->rx_stats.alloc_failed++; return false; @@ -147,8 +146,8 @@ void fm10k_alloc_rx_buffers(struct fm10k_ring *rx_ring, u16 cleaned_count) i -= rx_ring->count; } - /* clear the hdr_addr for the next_to_use descriptor */ - rx_desc->q.hdr_addr = 0; + /* clear the status bits for the next_to_use descriptor */ + rx_desc->d.staterr = 0; cleaned_count--; } while (cleaned_count); @@ -194,7 +193,7 @@ static void fm10k_reuse_rx_page(struct fm10k_ring *rx_ring, rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0; /* transfer page from old buffer to new buffer */ - memcpy(new_buff, old_buff, sizeof(struct fm10k_rx_buffer)); + *new_buff = *old_buff; /* sync the buffer for use by the device */ dma_sync_single_range_for_device(rx_ring->dev, old_buff->dma, @@ -203,12 +202,17 @@ static void fm10k_reuse_rx_page(struct fm10k_ring *rx_ring, DMA_FROM_DEVICE); } +static inline bool fm10k_page_is_reserved(struct page *page) +{ + return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc; +} + static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer, struct page *page, unsigned int truesize) { /* avoid re-using remote pages */ - if (unlikely(page_to_nid(page) != numa_mem_id())) + if (unlikely(fm10k_page_is_reserved(page))) return false; #if (PAGE_SIZE < 8192) @@ -218,22 +222,19 @@ static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer, /* flip page offset to other buffer */ rx_buffer->page_offset ^= FM10K_RX_BUFSZ; - - /* Even if we own the page, we are not allowed to use atomic_set() - * This would break get_page_unless_zero() users. - */ - atomic_inc(&page->_count); #else /* move offset up to the next cache line */ rx_buffer->page_offset += truesize; if (rx_buffer->page_offset > (PAGE_SIZE - FM10K_RX_BUFSZ)) return false; - - /* bump ref count on page before it is given to the stack */ - get_page(page); #endif + /* Even if we own the page, we are not allowed to use atomic_set() + * This would break get_page_unless_zero() users. + */ + atomic_inc(&page->_count); + return true; } @@ -270,12 +271,12 @@ static bool fm10k_add_rx_frag(struct fm10k_ring *rx_ring, memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long))); - /* we can reuse buffer as-is, just make sure it is local */ - if (likely(page_to_nid(page) == numa_mem_id())) + /* page is not reserved, we can reuse buffer as-is */ + if (likely(!fm10k_page_is_reserved(page))) return true; /* this page cannot be reused so discard it */ - put_page(page); + __free_page(page); return false; } @@ -293,7 +294,6 @@ static struct sk_buff *fm10k_fetch_rx_buffer(struct fm10k_ring *rx_ring, struct page *page; rx_buffer = &rx_ring->rx_buffer[rx_ring->next_to_clean]; - page = rx_buffer->page; prefetchw(page); @@ -727,6 +727,12 @@ static __be16 fm10k_tx_encap_offload(struct sk_buff *skb) struct ethhdr *eth_hdr; u8 l4_hdr = 0; +/* fm10k supports 184 octets of outer+inner headers. Minus 20 for inner L4. */ +#define FM10K_MAX_ENCAP_TRANSPORT_OFFSET 164 + if (skb_inner_transport_header(skb) - skb_mac_header(skb) > + FM10K_MAX_ENCAP_TRANSPORT_OFFSET) + return 0; + switch (vlan_get_protocol(skb)) { case htons(ETH_P_IP): l4_hdr = ip_hdr(skb)->protocol; @@ -965,8 +971,8 @@ static void fm10k_tx_map(struct fm10k_ring *tx_ring, tx_desc = FM10K_TX_DESC(tx_ring, i); /* add HW VLAN tag */ - if (vlan_tx_tag_present(skb)) - tx_desc->vlan = cpu_to_le16(vlan_tx_tag_get(skb)); + if (skb_vlan_tag_present(skb)) + tx_desc->vlan = cpu_to_le16(skb_vlan_tag_get(skb)); else tx_desc->vlan = 0; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c b/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c index 14a4ea795c01..9f5457c9e627 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c @@ -1194,12 +1194,11 @@ static s32 fm10k_mbx_process_disconnect(struct fm10k_hw *hw, { const enum fm10k_mbx_state state = mbx->state; const u32 *hdr = &mbx->mbx_hdr; - u16 head, tail; + u16 head; s32 err; - /* we will need to pull all of the fields for verification */ + /* we will need to pull the header field for verification */ head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD); - tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL); /* We should not be receiving disconnect if Rx is incomplete */ if (mbx->pushed) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index 8811364b91cb..cfde8bac1aeb 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -609,7 +609,7 @@ static netdev_tx_t fm10k_xmit_frame(struct sk_buff *skb, struct net_device *dev) int err; if ((skb->protocol == htons(ETH_P_8021Q)) && - !vlan_tx_tag_present(skb)) { + !skb_vlan_tag_present(skb)) { /* FM10K only supports hardware tagging, any tags in frame * are considered 2nd level or "outer" tags */ @@ -1414,13 +1414,12 @@ struct net_device *fm10k_alloc_netdev(void) dev->vlan_features |= dev->features; /* configure tunnel offloads */ - dev->hw_enc_features = NETIF_F_IP_CSUM | - NETIF_F_TSO | - NETIF_F_TSO6 | - NETIF_F_TSO_ECN | - NETIF_F_GSO_UDP_TUNNEL | - NETIF_F_IPV6_CSUM | - NETIF_F_SG; + dev->hw_enc_features |= NETIF_F_IP_CSUM | + NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_TSO_ECN | + NETIF_F_GSO_UDP_TUNNEL | + NETIF_F_IPV6_CSUM; /* we want to leave these both on as we cannot disable VLAN tag * insertion or stripping on the hardware since it is contained diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c index 275423d4f777..7e4711958e46 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c @@ -330,13 +330,10 @@ static s32 fm10k_update_xc_addr_pf(struct fm10k_hw *hw, u16 glort, struct fm10k_mac_update mac_update; u32 msg[5]; - /* if glort is not valid return error */ - if (!fm10k_glort_valid_pf(hw, glort)) + /* if glort or vlan are not valid return error */ + if (!fm10k_glort_valid_pf(hw, glort) || vid >= FM10K_VLAN_TABLE_VID_MAX) return FM10K_ERR_PARAM; - /* drop upper 4 bits of VLAN ID */ - vid = (vid << 4) >> 4; - /* record fields */ mac_update.mac_lower = cpu_to_le32(((u32)mac[2] << 24) | ((u32)mac[3] << 16) | diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c b/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c index 7822809436a3..d966044e017a 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c @@ -57,7 +57,6 @@ void fm10k_ts_tx_enqueue(struct fm10k_intfc *interface, struct sk_buff *skb) struct sk_buff_head *list = &interface->ts_tx_skb_queue; struct sk_buff *clone; unsigned long flags; - __le16 dglort; /* create clone for us to return on the Tx path */ clone = skb_clone_sk(skb); @@ -65,8 +64,6 @@ void fm10k_ts_tx_enqueue(struct fm10k_intfc *interface, struct sk_buff *skb) return; FM10K_CB(clone)->ts_tx_timeout = jiffies + FM10K_TS_TX_TIMEOUT; - dglort = FM10K_CB(clone)->fi.w.dglort; - spin_lock_irqsave(&list->lock, flags); /* attempt to locate any buffers with the same dglort, diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_type.h b/drivers/net/ethernet/intel/fm10k/fm10k_type.h index 280296f29154..7c6d9d5a8ae5 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_type.h +++ b/drivers/net/ethernet/intel/fm10k/fm10k_type.h @@ -354,7 +354,7 @@ struct fm10k_hw; /* Define timeouts for resets and disables */ #define FM10K_QUEUE_DISABLE_TIMEOUT 100 -#define FM10K_RESET_TIMEOUT 100 +#define FM10K_RESET_TIMEOUT 150 /* VF registers */ #define FM10K_VFCTRL 0x00000 diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index fc50f6461b13..2b65cdcad6ba 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -87,11 +87,12 @@ #define I40E_MINIMUM_FCOE 1 /* minimum number of QPs for FCoE */ #endif /* I40E_FCOE */ #define I40E_MAX_AQ_BUF_SIZE 4096 -#define I40E_AQ_LEN 128 -#define I40E_AQ_WORK_LIMIT 16 +#define I40E_AQ_LEN 256 +#define I40E_AQ_WORK_LIMIT 32 #define I40E_MAX_USER_PRIORITY 8 #define I40E_DEFAULT_MSG_ENABLE 4 #define I40E_QUEUE_WAIT_RETRY_LIMIT 10 +#define I40E_INT_NAME_STR_LEN (IFNAMSIZ + 9) #define I40E_NVM_VERSION_LO_SHIFT 0 #define I40E_NVM_VERSION_LO_MASK (0xff << I40E_NVM_VERSION_LO_SHIFT) @@ -147,6 +148,7 @@ enum i40e_state_t { __I40E_FD_FLUSH_REQUESTED, __I40E_RESET_FAILED, __I40E_PORT_TX_SUSPENDED, + __I40E_VF_DISABLE, }; enum i40e_interrupt_policy { @@ -268,7 +270,7 @@ struct i40e_pf { u16 rx_itr_default; u16 tx_itr_default; u16 msg_enable; - char misc_int_name[IFNAMSIZ + 9]; + char int_name[I40E_INT_NAME_STR_LEN]; u16 adminq_work_limit; /* num of admin receive queue desc to process */ unsigned long service_timer_period; unsigned long service_timer_previous; @@ -524,7 +526,7 @@ struct i40e_q_vector { cpumask_t affinity_mask; struct rcu_head rcu; /* to avoid race with update stats on free */ - char name[IFNAMSIZ + 9]; + char name[I40E_INT_NAME_STR_LEN]; } ____cacheline_internodealigned_in_smp; /* lan device */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h index 564d0b0192f7..de17b6fbcc4e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.h @@ -148,7 +148,7 @@ static inline int i40e_aq_rc_to_posix(u32 aq_ret, u16 aq_rc) /* general information */ #define I40E_AQ_LARGE_BUF 512 -#define I40E_ASQ_CMD_TIMEOUT 100 /* msecs */ +#define I40E_ASQ_CMD_TIMEOUT 250 /* msecs */ void i40e_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, u16 opcode); diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index 8835aeeff23e..929e3d72a01e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -256,6 +256,8 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_lldp_stop = 0x0A05, i40e_aqc_opc_lldp_start = 0x0A06, i40e_aqc_opc_get_cee_dcb_cfg = 0x0A07, + i40e_aqc_opc_lldp_set_local_mib = 0x0A08, + i40e_aqc_opc_lldp_stop_start_spec_agent = 0x0A09, /* Tunnel commands */ i40e_aqc_opc_add_udp_tunnel = 0x0B00, @@ -268,6 +270,8 @@ enum i40e_admin_queue_opc { /* OEM commands */ i40e_aqc_opc_oem_parameter_change = 0xFE00, i40e_aqc_opc_oem_device_status_change = 0xFE01, + i40e_aqc_opc_oem_ocsd_initialize = 0xFE02, + i40e_aqc_opc_oem_ocbb_initialize = 0xFE03, /* debug commands */ i40e_aqc_opc_debug_get_deviceid = 0xFF00, @@ -276,7 +280,6 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_debug_write_reg = 0xFF04, i40e_aqc_opc_debug_modify_reg = 0xFF07, i40e_aqc_opc_debug_dump_internals = 0xFF08, - i40e_aqc_opc_debug_modify_internals = 0xFF09, }; /* command structures and indirect data structures */ @@ -410,6 +413,7 @@ struct i40e_aqc_list_capabilities_element_resp { #define I40E_AQ_CAP_ID_VSI 0x0017 #define I40E_AQ_CAP_ID_DCB 0x0018 #define I40E_AQ_CAP_ID_FCOE 0x0021 +#define I40E_AQ_CAP_ID_ISCSI 0x0022 #define I40E_AQ_CAP_ID_RSS 0x0040 #define I40E_AQ_CAP_ID_RXQ 0x0041 #define I40E_AQ_CAP_ID_TXQ 0x0042 @@ -454,8 +458,11 @@ struct i40e_aqc_arp_proxy_data { __le32 pfpm_proxyfc; __le32 ip_addr; u8 mac_addr[6]; + u8 reserved[2]; }; +I40E_CHECK_STRUCT_LEN(0x14, i40e_aqc_arp_proxy_data); + /* Set NS Proxy Table Entry Command (indirect 0x0105) */ struct i40e_aqc_ns_proxy_data { __le16 table_idx_mac_addr_0; @@ -481,6 +488,8 @@ struct i40e_aqc_ns_proxy_data { u8 ipv6_addr_1[16]; }; +I40E_CHECK_STRUCT_LEN(0x3c, i40e_aqc_ns_proxy_data); + /* Manage LAA Command (0x0106) - obsolete */ struct i40e_aqc_mng_laa { __le16 command_flags; @@ -491,6 +500,8 @@ struct i40e_aqc_mng_laa { u8 reserved2[6]; }; +I40E_CHECK_CMD_LENGTH(i40e_aqc_mng_laa); + /* Manage MAC Address Read Command (indirect 0x0107) */ struct i40e_aqc_mac_address_read { __le16 command_flags; @@ -562,6 +573,8 @@ struct i40e_aqc_get_switch_config_header_resp { u8 reserved[12]; }; +I40E_CHECK_CMD_LENGTH(i40e_aqc_get_switch_config_header_resp); + struct i40e_aqc_switch_config_element_resp { u8 element_type; #define I40E_AQ_SW_ELEM_TYPE_MAC 1 @@ -587,6 +600,8 @@ struct i40e_aqc_switch_config_element_resp { __le16 element_info; }; +I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_config_element_resp); + /* Get Switch Configuration (indirect 0x0200) * an array of elements are returned in the response buffer * the first in the array is the header, remainder are elements @@ -596,6 +611,8 @@ struct i40e_aqc_get_switch_config_resp { struct i40e_aqc_switch_config_element_resp element[1]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_get_switch_config_resp); + /* Add Statistics (direct 0x0201) * Remove Statistics (direct 0x0202) */ @@ -661,6 +678,8 @@ struct i40e_aqc_switch_resource_alloc_element_resp { u8 reserved2[6]; }; +I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp); + /* Add VSI (indirect 0x0210) * this indirect command uses struct i40e_aqc_vsi_properties_data * as the indirect buffer (128 bytes) @@ -1092,6 +1111,8 @@ struct i40e_aqc_remove_tag { u8 reserved[12]; }; +I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_tag); + /* Add multicast E-Tag (direct 0x0257) * del multicast E-Tag (direct 0x0258) only uses pv_seid and etag fields * and no external data @@ -1207,7 +1228,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data { } ipaddr; __le16 flags; #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT 0 -#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \ +#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \ I40E_AQC_ADD_CLOUD_FILTER_SHIFT) /* 0x0000 reserved */ #define I40E_AQC_ADD_CLOUD_FILTER_OIP 0x0001 @@ -1240,7 +1261,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data { u8 reserved[4]; __le16 queue_number; #define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT 0 -#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x3F << \ +#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x7FF << \ I40E_AQC_ADD_CLOUD_QUEUE_SHIFT) u8 reserved2[14]; /* response section */ @@ -1359,6 +1380,8 @@ struct i40e_aqc_configure_vsi_ets_sla_bw_data { u8 reserved1[28]; }; +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_configure_vsi_ets_sla_bw_data); + /* Configure VSI Bandwidth Allocation per Traffic Type (indirect 0x0407) * responds with i40e_aqc_qs_handles_resp */ @@ -1370,6 +1393,8 @@ struct i40e_aqc_configure_vsi_tc_bw_data { __le16 qs_handles[8]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_vsi_tc_bw_data); + /* Query vsi bw configuration (indirect 0x0408) */ struct i40e_aqc_query_vsi_bw_config_resp { u8 tc_valid_bits; @@ -1383,6 +1408,8 @@ struct i40e_aqc_query_vsi_bw_config_resp { u8 reserved3[23]; }; +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_vsi_bw_config_resp); + /* Query VSI Bandwidth Allocation per Traffic Type (indirect 0x040A) */ struct i40e_aqc_query_vsi_ets_sla_config_resp { u8 tc_valid_bits; @@ -1394,6 +1421,8 @@ struct i40e_aqc_query_vsi_ets_sla_config_resp { __le16 tc_bw_max[2]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_vsi_ets_sla_config_resp); + /* Configure Switching Component Bandwidth Limit (direct 0x0410) */ struct i40e_aqc_configure_switching_comp_bw_limit { __le16 seid; @@ -1421,6 +1450,8 @@ struct i40e_aqc_configure_switching_comp_ets_data { u8 reserved2[96]; }; +I40E_CHECK_STRUCT_LEN(0x80, i40e_aqc_configure_switching_comp_ets_data); + /* Configure Switching Component Bandwidth Limits per Tc (indirect 0x0416) */ struct i40e_aqc_configure_switching_comp_ets_bw_limit_data { u8 tc_valid_bits; @@ -1432,6 +1463,9 @@ struct i40e_aqc_configure_switching_comp_ets_bw_limit_data { u8 reserved1[28]; }; +I40E_CHECK_STRUCT_LEN(0x40, + i40e_aqc_configure_switching_comp_ets_bw_limit_data); + /* Configure Switching Component Bandwidth Allocation per Tc * (indirect 0x0417) */ @@ -1443,6 +1477,8 @@ struct i40e_aqc_configure_switching_comp_bw_config_data { u8 reserved1[20]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_switching_comp_bw_config_data); + /* Query Switching Component Configuration (indirect 0x0418) */ struct i40e_aqc_query_switching_comp_ets_config_resp { u8 tc_valid_bits; @@ -1453,6 +1489,8 @@ struct i40e_aqc_query_switching_comp_ets_config_resp { u8 reserved2[23]; }; +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_switching_comp_ets_config_resp); + /* Query PhysicalPort ETS Configuration (indirect 0x0419) */ struct i40e_aqc_query_port_ets_config_resp { u8 reserved[4]; @@ -1468,6 +1506,8 @@ struct i40e_aqc_query_port_ets_config_resp { u8 reserved3[32]; }; +I40E_CHECK_STRUCT_LEN(0x44, i40e_aqc_query_port_ets_config_resp); + /* Query Switching Component Bandwidth Allocation per Traffic Type * (indirect 0x041A) */ @@ -1482,6 +1522,8 @@ struct i40e_aqc_query_switching_comp_bw_config_resp { __le16 tc_bw_max[2]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_switching_comp_bw_config_resp); + /* Suspend/resume port TX traffic * (direct 0x041B and 0x041C) uses the generic SEID struct */ @@ -1495,6 +1537,8 @@ struct i40e_aqc_configure_partition_bw_data { u8 max_bw[16]; /* bandwidth limit */ }; +I40E_CHECK_STRUCT_LEN(0x22, i40e_aqc_configure_partition_bw_data); + /* Get and set the active HMC resource profile and status. * (direct 0x0500) and (direct 0x0501) */ @@ -1577,6 +1621,8 @@ struct i40e_aqc_module_desc { u8 reserved2[8]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_module_desc); + struct i40e_aq_get_phy_abilities_resp { __le32 phy_type; /* bitmap using the above enum for offsets */ u8 link_speed; /* bitmap using the above enum bit patterns */ @@ -1605,6 +1651,8 @@ struct i40e_aq_get_phy_abilities_resp { struct i40e_aqc_module_desc qualified_module[I40E_AQ_PHY_MAX_QMS]; }; +I40E_CHECK_STRUCT_LEN(0x218, i40e_aq_get_phy_abilities_resp); + /* Set PHY Config (direct 0x0601) */ struct i40e_aq_set_phy_config { /* same bits as above in all */ __le32 phy_type; @@ -1788,12 +1836,12 @@ I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_update); /* NVM Config Read (indirect 0x0704) */ struct i40e_aqc_nvm_config_read { __le16 cmd_flags; -#define ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1 -#define ANVM_READ_SINGLE_FEATURE 0 -#define ANVM_READ_MULTIPLE_FEATURES 1 +#define I40E_AQ_ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1 +#define I40E_AQ_ANVM_READ_SINGLE_FEATURE 0 +#define I40E_AQ_ANVM_READ_MULTIPLE_FEATURES 1 __le16 element_count; - __le16 element_id; /* Feature/field ID */ - u8 reserved[2]; + __le16 element_id; /* Feature/field ID */ + __le16 element_id_msw; /* MSWord of field ID */ __le32 address_high; __le32 address_low; }; @@ -1811,21 +1859,32 @@ struct i40e_aqc_nvm_config_write { I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_config_write); +/* Used for 0x0704 as well as for 0x0705 commands */ +#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT 1 +#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_MASK \ + (1 << I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT) +#define I40E_AQ_ANVM_FEATURE 0 +#define I40E_AQ_ANVM_IMMEDIATE_FIELD (1 << FEATURE_OR_IMMEDIATE_SHIFT) struct i40e_aqc_nvm_config_data_feature { __le16 feature_id; - __le16 instance_id; +#define I40E_AQ_ANVM_FEATURE_OPTION_OEM_ONLY 0x01 +#define I40E_AQ_ANVM_FEATURE_OPTION_DWORD_MAP 0x08 +#define I40E_AQ_ANVM_FEATURE_OPTION_POR_CSR 0x10 __le16 feature_options; __le16 feature_selection; }; +I40E_CHECK_STRUCT_LEN(0x6, i40e_aqc_nvm_config_data_feature); + struct i40e_aqc_nvm_config_data_immediate_field { -#define ANVM_FEATURE_OR_IMMEDIATE_MASK 0x2 - __le16 field_id; - __le16 instance_id; + __le32 field_id; + __le32 field_value; __le16 field_options; - __le16 field_value; + __le16 reserved; }; +I40E_CHECK_STRUCT_LEN(0xc, i40e_aqc_nvm_config_data_immediate_field); + /* Send to PF command (indirect 0x0801) id is only used by PF * Send to VF command (indirect 0x0802) id is only used by PF * Send to Peer PF command (indirect 0x0803) @@ -2026,12 +2085,54 @@ struct i40e_aqc_get_cee_dcb_cfg_resp { u8 oper_tc_bw[8]; u8 oper_pfc_en; __le16 oper_app_prio; +#define I40E_AQC_CEE_APP_FCOE_SHIFT 0x0 +#define I40E_AQC_CEE_APP_FCOE_MASK (0x7 << I40E_AQC_CEE_APP_FCOE_SHIFT) +#define I40E_AQC_CEE_APP_ISCSI_SHIFT 0x3 +#define I40E_AQC_CEE_APP_ISCSI_MASK (0x7 << I40E_AQC_CEE_APP_ISCSI_SHIFT) +#define I40E_AQC_CEE_APP_FIP_SHIFT 0x8 +#define I40E_AQC_CEE_APP_FIP_MASK (0x7 << I40E_AQC_CEE_APP_FIP_SHIFT) +#define I40E_AQC_CEE_APP_FIP_MASK (0x7 << I40E_AQC_CEE_APP_FIP_SHIFT) __le32 tlv_status; +#define I40E_AQC_CEE_PG_STATUS_SHIFT 0x0 +#define I40E_AQC_CEE_PG_STATUS_MASK (0x7 << I40E_AQC_CEE_PG_STATUS_SHIFT) +#define I40E_AQC_CEE_PFC_STATUS_SHIFT 0x3 +#define I40E_AQC_CEE_PFC_STATUS_MASK (0x7 << I40E_AQC_CEE_PFC_STATUS_SHIFT) +#define I40E_AQC_CEE_APP_STATUS_SHIFT 0x8 +#define I40E_AQC_CEE_APP_STATUS_MASK (0x7 << I40E_AQC_CEE_APP_STATUS_SHIFT) u8 reserved[12]; }; I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_get_cee_dcb_cfg_resp); +/* Set Local LLDP MIB (indirect 0x0A08) + * Used to replace the local MIB of a given LLDP agent. e.g. DCBx + */ +struct i40e_aqc_lldp_set_local_mib { +#define SET_LOCAL_MIB_AC_TYPE_DCBX_SHIFT 0 +#define SET_LOCAL_MIB_AC_TYPE_DCBX_MASK (1 << SET_LOCAL_MIB_AC_TYPE_DCBX_SHIFT) + u8 type; + u8 reserved0; + __le16 length; + u8 reserved1[4]; + __le32 address_high; + __le32 address_low; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_set_local_mib); + +/* Stop/Start LLDP Agent (direct 0x0A09) + * Used for stopping/starting specific LLDP agent. e.g. DCBx + */ +struct i40e_aqc_lldp_stop_start_specific_agent { +#define I40E_AQC_START_SPECIFIC_AGENT_SHIFT 0 +#define I40E_AQC_START_SPECIFIC_AGENT_MASK \ + (1 << I40E_AQC_START_SPECIFIC_AGENT_SHIFT) + u8 command; + u8 reserved[15]; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_stop_start_specific_agent); + /* Add Udp Tunnel command and completion (direct 0x0B00) */ struct i40e_aqc_add_udp_tunnel { __le16 udp_port; @@ -2106,7 +2207,8 @@ struct i40e_aqc_oem_param_change { #define I40E_AQ_OEM_PARAM_TYPE_BW_CTL 1 #define I40E_AQ_OEM_PARAM_MAC 2 __le32 param_value1; - u8 param_value2[8]; + __le16 param_value2; + u8 reserved[6]; }; I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_param_change); @@ -2120,6 +2222,28 @@ struct i40e_aqc_oem_state_change { I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_state_change); +/* Initialize OCSD (0xFE02, direct) */ +struct i40e_aqc_opc_oem_ocsd_initialize { + u8 type_status; + u8 reserved1[3]; + __le32 ocsd_memory_block_addr_high; + __le32 ocsd_memory_block_addr_low; + __le32 requested_update_interval; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocsd_initialize); + +/* Initialize OCBB (0xFE03, direct) */ +struct i40e_aqc_opc_oem_ocbb_initialize { + u8 type_status; + u8 reserved1[3]; + __le32 ocbb_memory_block_addr_high; + __le32 ocbb_memory_block_addr_low; + u8 reserved2[4]; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocbb_initialize); + /* debug commands */ /* get device id (0xFF00) uses the generic structure */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 3d741ee99a2c..11a9ffebf8d8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -741,6 +741,65 @@ i40e_status i40e_get_san_mac_addr(struct i40e_hw *hw, u8 *mac_addr) } #endif +/** + * i40e_read_pba_string - Reads part number string from EEPROM + * @hw: pointer to hardware structure + * @pba_num: stores the part number string from the EEPROM + * @pba_num_size: part number string buffer length + * + * Reads the part number string from the EEPROM. + **/ +i40e_status i40e_read_pba_string(struct i40e_hw *hw, u8 *pba_num, + u32 pba_num_size) +{ + i40e_status status = 0; + u16 pba_word = 0; + u16 pba_size = 0; + u16 pba_ptr = 0; + u16 i = 0; + + status = i40e_read_nvm_word(hw, I40E_SR_PBA_FLAGS, &pba_word); + if (status || (pba_word != 0xFAFA)) { + hw_dbg(hw, "Failed to read PBA flags or flag is invalid.\n"); + return status; + } + + status = i40e_read_nvm_word(hw, I40E_SR_PBA_BLOCK_PTR, &pba_ptr); + if (status) { + hw_dbg(hw, "Failed to read PBA Block pointer.\n"); + return status; + } + + status = i40e_read_nvm_word(hw, pba_ptr, &pba_size); + if (status) { + hw_dbg(hw, "Failed to read PBA Block size.\n"); + return status; + } + + /* Subtract one to get PBA word count (PBA Size word is included in + * total size) + */ + pba_size--; + if (pba_num_size < (((u32)pba_size * 2) + 1)) { + hw_dbg(hw, "Buffer to small for PBA data.\n"); + return I40E_ERR_PARAM; + } + + for (i = 0; i < pba_size; i++) { + status = i40e_read_nvm_word(hw, (pba_ptr + 1) + i, &pba_word); + if (status) { + hw_dbg(hw, "Failed to read PBA Block word %d.\n", i); + return status; + } + + pba_num[(i * 2)] = (pba_word >> 8) & 0xFF; + pba_num[(i * 2) + 1] = pba_word & 0xFF; + } + pba_num[(pba_size * 2)] = '\0'; + + return status; +} + /** * i40e_get_media_type - Gets media type * @hw: pointer to the hardware structure @@ -1083,8 +1142,10 @@ void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink) if (mode == I40E_LINK_ACTIVITY) blink = false; - gpio_val |= (blink ? 1 : 0) << - I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT; + if (blink) + gpio_val |= (1 << I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT); + else + gpio_val &= ~(1 << I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT); wr32(hw, I40E_GLGEN_GPIO_CTL(i), gpio_val); break; @@ -2034,6 +2095,43 @@ i40e_status i40e_aq_send_msg_to_vf(struct i40e_hw *hw, u16 vfid, return status; } +/** + * i40e_aq_debug_read_register + * @hw: pointer to the hw struct + * @reg_addr: register address + * @reg_val: register value + * @cmd_details: pointer to command details structure or NULL + * + * Read the register using the admin queue commands + **/ +i40e_status i40e_aq_debug_read_register(struct i40e_hw *hw, + u32 reg_addr, u64 *reg_val, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + struct i40e_aqc_debug_reg_read_write *cmd_resp = + (struct i40e_aqc_debug_reg_read_write *)&desc.params.raw; + i40e_status status; + + if (reg_val == NULL) + return I40E_ERR_PARAM; + + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_debug_read_reg); + + cmd_resp->address = cpu_to_le32(reg_addr); + + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); + + if (!status) { + *reg_val = ((u64)cmd_resp->value_high << 32) | + (u64)cmd_resp->value_low; + *reg_val = le64_to_cpu(*reg_val); + } + + return status; +} + /** * i40e_aq_debug_write_register * @hw: pointer to the hw struct @@ -2264,6 +2362,7 @@ i40e_aq_erase_nvm_exit: #define I40E_DEV_FUNC_CAP_VSI 0x17 #define I40E_DEV_FUNC_CAP_DCB 0x18 #define I40E_DEV_FUNC_CAP_FCOE 0x21 +#define I40E_DEV_FUNC_CAP_ISCSI 0x22 #define I40E_DEV_FUNC_CAP_RSS 0x40 #define I40E_DEV_FUNC_CAP_RX_QUEUES 0x41 #define I40E_DEV_FUNC_CAP_TX_QUEUES 0x42 @@ -2292,6 +2391,7 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, enum i40e_admin_queue_opc list_type_opc) { struct i40e_aqc_list_capabilities_element_resp *cap; + u32 valid_functions, num_functions; u32 number, logical_id, phys_id; struct i40e_hw_capabilities *p; u32 i = 0; @@ -2362,6 +2462,10 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, if (number == 1) p->fcoe = true; break; + case I40E_DEV_FUNC_CAP_ISCSI: + if (number == 1) + p->iscsi = true; + break; case I40E_DEV_FUNC_CAP_RSS: p->rss = true; p->rss_table_size = number; @@ -2427,6 +2531,34 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, if (p->npar_enable || p->mfp_mode_1) p->fcoe = false; + /* count the enabled ports (aka the "not disabled" ports) */ + hw->num_ports = 0; + for (i = 0; i < 4; i++) { + u32 port_cfg_reg = I40E_PRTGEN_CNF + (4 * i); + u64 port_cfg = 0; + + /* use AQ read to get the physical register offset instead + * of the port relative offset + */ + i40e_aq_debug_read_register(hw, port_cfg_reg, &port_cfg, NULL); + if (!(port_cfg & I40E_PRTGEN_CNF_PORT_DIS_MASK)) + hw->num_ports++; + } + + valid_functions = p->valid_functions; + num_functions = 0; + while (valid_functions) { + if (valid_functions & 1) + num_functions++; + valid_functions >>= 1; + } + + /* partition id is 1-based, and functions are evenly spread + * across the ports as partitions + */ + hw->partition_id = (hw->pf_id / hw->num_ports) + 1; + hw->num_partitions = num_functions / hw->num_ports; + /* additional HW specific goodies that might * someday be HW version specific */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index cb0de455683e..61236f983971 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1890,7 +1890,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp, dev_info(&pf->pdev->dev, " dump desc tx []\n"); dev_info(&pf->pdev->dev, " dump desc rx []\n"); dev_info(&pf->pdev->dev, " dump desc aq\n"); - dev_info(&pf->pdev->dev, " dump stats\n"); dev_info(&pf->pdev->dev, " dump reset stats\n"); dev_info(&pf->pdev->dev, " msg_enable [level]\n"); dev_info(&pf->pdev->dev, " read \n"); diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 951e8767fc50..b8230dc205ec 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -218,6 +218,16 @@ static const char i40e_gstrings_test[][ETH_GSTRING_LEN] = { #define I40E_TEST_LEN (sizeof(i40e_gstrings_test) / ETH_GSTRING_LEN) +/** + * i40e_partition_setting_complaint - generic complaint for MFP restriction + * @pf: the PF struct + **/ +static void i40e_partition_setting_complaint(struct i40e_pf *pf) +{ + dev_info(&pf->pdev->dev, + "The link settings are allowed to be changed only from the first partition of a given port. Please switch to the first partition in order to change the setting.\n"); +} + /** * i40e_get_settings - Get Link Speed and Duplex settings * @netdev: network interface device structure @@ -485,6 +495,14 @@ static int i40e_set_settings(struct net_device *netdev, u8 autoneg; u32 advertise; + /* Changing port settings is not supported if this isn't the + * port's controlling PF + */ + if (hw->partition_id != 1) { + i40e_partition_setting_complaint(pf); + return -EOPNOTSUPP; + } + if (vsi != pf->vsi[pf->lan_vsi]) return -EOPNOTSUPP; @@ -687,6 +705,14 @@ static int i40e_set_pauseparam(struct net_device *netdev, u8 aq_failures; int err = 0; + /* Changing the port's flow control is not supported if this isn't the + * port's controlling PF + */ + if (hw->partition_id != 1) { + i40e_partition_setting_complaint(pf); + return -EOPNOTSUPP; + } + if (vsi != pf->vsi[pf->lan_vsi]) return -EOPNOTSUPP; @@ -1503,7 +1529,7 @@ static void i40e_get_wol(struct net_device *netdev, /* NVM bit on means WoL disabled for the port */ i40e_read_nvm_word(hw, I40E_SR_NVM_WAKE_ON_LAN, &wol_nvm_bits); - if ((1 << hw->port) & wol_nvm_bits) { + if ((1 << hw->port) & wol_nvm_bits || hw->partition_id != 1) { wol->supported = 0; wol->wolopts = 0; } else { @@ -1512,13 +1538,28 @@ static void i40e_get_wol(struct net_device *netdev, } } +/** + * i40e_set_wol - set the WakeOnLAN configuration + * @netdev: the netdev in question + * @wol: the ethtool WoL setting data + **/ static int i40e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_pf *pf = np->vsi->back; + struct i40e_vsi *vsi = np->vsi; struct i40e_hw *hw = &pf->hw; u16 wol_nvm_bits; + /* WoL not supported if this isn't the controlling PF on the port */ + if (hw->partition_id != 1) { + i40e_partition_setting_complaint(pf); + return -EOPNOTSUPP; + } + + if (vsi != pf->vsi[pf->lan_vsi]) + return -EOPNOTSUPP; + /* NVM bit on means WoL disabled for the port */ i40e_read_nvm_word(hw, I40E_SR_NVM_WAKE_ON_LAN, &wol_nvm_bits); if (((1 << hw->port) & wol_nvm_bits)) diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c index a8b8bd95108d..27c206e62da7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c @@ -38,15 +38,6 @@ #include "i40e.h" #include "i40e_fcoe.h" -/** - * i40e_rx_is_fip - returns true if the rx packet type is FIP - * @ptype: the packet type field from rx descriptor write-back - **/ -static inline bool i40e_rx_is_fip(u16 ptype) -{ - return ptype == I40E_RX_PTYPE_L2_FIP_PAY2; -} - /** * i40e_rx_is_fcoe - returns true if the rx packet type is FCoE * @ptype: the packet type field from rx descriptor write-back @@ -404,6 +395,7 @@ int i40e_fcoe_vsi_init(struct i40e_vsi *vsi, struct i40e_vsi_context *ctxt) I40E_AQ_VSI_PROP_INGRESS_UP_VALID | I40E_AQ_VSI_PROP_EGRESS_UP_VALID)); + info->switch_id = cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB); enabled_tc = i40e_get_fcoe_tc_map(pf); i40e_vsi_setup_queue_map(vsi, ctxt, enabled_tc, true); @@ -1511,12 +1503,16 @@ void i40e_fcoe_config_netdev(struct net_device *netdev, struct i40e_vsi *vsi) strlcpy(netdev->name, "fcoe%d", IFNAMSIZ-1); netdev->mtu = FCOE_MTU; SET_NETDEV_DEV(netdev, &pf->pdev->dev); + /* set different dev_port value 1 for FCoE netdev than the default + * zero dev_port value for PF netdev, this helps biosdevname user + * tool to differentiate them correctly while both attached to the + * same PCI function. + */ + netdev->dev_port = 1; i40e_add_filter(vsi, hw->mac.san_addr, 0, false, false); i40e_add_filter(vsi, (u8[6]) FC_FCOE_FLOGI_MAC, 0, false, false); i40e_add_filter(vsi, FIP_ALL_FCOE_MACS, 0, false, false); i40e_add_filter(vsi, FIP_ALL_ENODE_MACS, 0, false, false); - i40e_add_filter(vsi, FIP_ALL_VN2VN_MACS, 0, false, false); - i40e_add_filter(vsi, FIP_ALL_P2P_MACS, 0, false, false); /* use san mac */ ether_addr_copy(netdev->dev_addr, hw->mac.san_addr); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index a5f2660d552d..cbe281be1c9f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -39,7 +39,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 1 #define DRV_VERSION_MINOR 2 -#define DRV_VERSION_BUILD 2 +#define DRV_VERSION_BUILD 6 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN @@ -2819,8 +2819,9 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi) * i40e_enable_misc_int_causes - enable the non-queue interrupts * @hw: ptr to the hardware info **/ -static void i40e_enable_misc_int_causes(struct i40e_hw *hw) +static void i40e_enable_misc_int_causes(struct i40e_pf *pf) { + struct i40e_hw *hw = &pf->hw; u32 val; /* clear things first */ @@ -2832,11 +2833,13 @@ static void i40e_enable_misc_int_causes(struct i40e_hw *hw) I40E_PFINT_ICR0_ENA_GRST_MASK | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK | I40E_PFINT_ICR0_ENA_GPIO_MASK | - I40E_PFINT_ICR0_ENA_TIMESYNC_MASK | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK | I40E_PFINT_ICR0_ENA_VFLR_MASK | I40E_PFINT_ICR0_ENA_ADMINQ_MASK; + if (pf->flags & I40E_FLAG_PTP) + val |= I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; + wr32(hw, I40E_PFINT_ICR0_ENA, val); /* SW_ITR_IDX = 0, but don't change INTENA */ @@ -2866,7 +2869,7 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi) q_vector->tx.latency_range = I40E_LOW_LATENCY; wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.itr); - i40e_enable_misc_int_causes(hw); + i40e_enable_misc_int_causes(pf); /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */ wr32(hw, I40E_PFINT_LNKLST0, 0); @@ -2937,7 +2940,7 @@ void i40e_irq_dynamic_enable(struct i40e_vsi *vsi, int vector) /** * i40e_irq_dynamic_disable - Disable default interrupt generation settings * @vsi: pointer to a vsi - * @vector: enable a particular Hw Interrupt vector + * @vector: disable a particular Hw Interrupt vector **/ void i40e_irq_dynamic_disable(struct i40e_vsi *vsi, int vector) { @@ -3402,10 +3405,10 @@ static int i40e_vsi_request_irq(struct i40e_vsi *vsi, char *basename) err = i40e_vsi_request_irq_msix(vsi, basename); else if (pf->flags & I40E_FLAG_MSI_ENABLED) err = request_irq(pf->pdev->irq, i40e_intr, 0, - pf->misc_int_name, pf); + pf->int_name, pf); else err = request_irq(pf->pdev->irq, i40e_intr, IRQF_SHARED, - pf->misc_int_name, pf); + pf->int_name, pf); if (err) dev_info(&pf->pdev->dev, "request_irq failed, Error %d\n", err); @@ -3998,6 +4001,35 @@ static int i40e_pf_wait_txq_disabled(struct i40e_pf *pf) } #endif +/** + * i40e_get_iscsi_tc_map - Return TC map for iSCSI APP + * @pf: pointer to pf + * + * Get TC map for ISCSI PF type that will include iSCSI TC + * and LAN TC. + **/ +static u8 i40e_get_iscsi_tc_map(struct i40e_pf *pf) +{ + struct i40e_dcb_app_priority_table app; + struct i40e_hw *hw = &pf->hw; + u8 enabled_tc = 1; /* TC0 is always enabled */ + u8 tc, i; + /* Get the iSCSI APP TLV */ + struct i40e_dcbx_config *dcbcfg = &hw->local_dcbx_config; + + for (i = 0; i < dcbcfg->numapps; i++) { + app = dcbcfg->app[i]; + if (app.selector == I40E_APP_SEL_TCPIP && + app.protocolid == I40E_APP_PROTOID_ISCSI) { + tc = dcbcfg->etscfg.prioritytable[app.priority]; + enabled_tc |= (1 << tc); + break; + } + } + + return enabled_tc; +} + /** * i40e_dcb_get_num_tc - Get the number of TCs from DCBx config * @dcbcfg: the corresponding DCBx configuration structure @@ -4061,18 +4093,23 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf) if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) return 1; - /* MFP mode return count of enabled TCs for this PF */ - if (pf->flags & I40E_FLAG_MFP_ENABLED) { - enabled_tc = pf->hw.func_caps.enabled_tcmap; - for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (enabled_tc & (1 << i)) - num_tc++; - } - return num_tc; - } - /* SFP mode will be enabled for all TCs on port */ - return i40e_dcb_get_num_tc(dcbcfg); + if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) + return i40e_dcb_get_num_tc(dcbcfg); + + /* MFP mode return count of enabled TCs for this PF */ + if (pf->hw.func_caps.iscsi) + enabled_tc = i40e_get_iscsi_tc_map(pf); + else + enabled_tc = pf->hw.func_caps.enabled_tcmap; + + /* At least have TC0 */ + enabled_tc = (enabled_tc ? enabled_tc : 0x1); + for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { + if (enabled_tc & (1 << i)) + num_tc++; + } + return num_tc; } /** @@ -4110,12 +4147,15 @@ static u8 i40e_pf_get_tc_map(struct i40e_pf *pf) if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) return i40e_pf_get_default_tc(pf); - /* MFP mode will have enabled TCs set by FW */ - if (pf->flags & I40E_FLAG_MFP_ENABLED) - return pf->hw.func_caps.enabled_tcmap; - /* SFP mode we want PF to be enabled for all TCs */ - return i40e_dcb_get_enabled_tc(&pf->hw.local_dcbx_config); + if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) + return i40e_dcb_get_enabled_tc(&pf->hw.local_dcbx_config); + + /* MPF enabled and iSCSI PF type */ + if (pf->hw.func_caps.iscsi) + return i40e_get_iscsi_tc_map(pf); + else + return pf->hw.func_caps.enabled_tcmap; } /** @@ -4505,9 +4545,6 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf) struct i40e_hw *hw = &pf->hw; int err = 0; - if (pf->hw.func_caps.npar_enable) - goto out; - /* Get the initial DCB configuration */ err = i40e_init_dcb(hw); if (!err) { @@ -4533,7 +4570,8 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf) "DCBX offload is supported for this PF.\n"); } } else { - dev_info(&pf->pdev->dev, "AQ Querying DCB configuration failed: %d\n", + dev_info(&pf->pdev->dev, + "AQ Querying DCB configuration failed: aq_err %d\n", pf->hw.aq.asq_last_status); } @@ -4557,6 +4595,15 @@ static void i40e_print_link_message(struct i40e_vsi *vsi, bool isup) return; } + /* Warn user if link speed on NPAR enabled partition is not at + * least 10GB + */ + if (vsi->back->hw.func_caps.npar_enable && + (vsi->back->hw.phy.link_info.link_speed == I40E_LINK_SPEED_1GB || + vsi->back->hw.phy.link_info.link_speed == I40E_LINK_SPEED_100MB)) + netdev_warn(vsi->netdev, + "The partition detected link speed that is less than 10Gbps\n"); + switch (vsi->back->hw.phy.link_info.link_speed) { case I40E_LINK_SPEED_40GB: strlcpy(speed, "40 Gbps", SPEED_SIZE); @@ -4836,7 +4883,7 @@ static int i40e_open(struct net_device *netdev) int i40e_vsi_open(struct i40e_vsi *vsi) { struct i40e_pf *pf = vsi->back; - char int_name[IFNAMSIZ]; + char int_name[I40E_INT_NAME_STR_LEN]; int err; /* allocate descriptors */ @@ -4870,7 +4917,7 @@ int i40e_vsi_open(struct i40e_vsi *vsi) goto err_set_queues; } else if (vsi->type == I40E_VSI_FDIR) { - snprintf(int_name, sizeof(int_name) - 1, "%s-%s-fdir", + snprintf(int_name, sizeof(int_name) - 1, "%s-%s:fdir", dev_driver_string(&pf->pdev->dev), dev_name(&pf->pdev->dev)); err = i40e_vsi_request_irq(vsi, int_name); @@ -5494,14 +5541,18 @@ static void i40e_link_event(struct i40e_pf *pf) { bool new_link, old_link; struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi]; + u8 new_link_speed, old_link_speed; /* set this to force the get_link_status call to refresh state */ pf->hw.phy.get_link_info = true; old_link = (pf->hw.phy.link_info_old.link_info & I40E_AQ_LINK_UP); new_link = i40e_get_link_status(&pf->hw); + old_link_speed = pf->hw.phy.link_info_old.link_speed; + new_link_speed = pf->hw.phy.link_info.link_speed; if (new_link == old_link && + new_link_speed == old_link_speed && (test_bit(__I40E_DOWN, &vsi->state) || new_link == netif_carrier_ok(vsi->netdev))) return; @@ -6175,8 +6226,9 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) #ifdef CONFIG_I40E_DCB ret = i40e_init_pf_dcb(pf); if (ret) { - dev_info(&pf->pdev->dev, "init_pf_dcb failed: %d\n", ret); - goto end_core_reset; + dev_info(&pf->pdev->dev, "DCB init failed %d, disabled\n", ret); + pf->flags &= ~I40E_FLAG_DCB_CAPABLE; + /* Continue without DCB enabled */ } #endif /* CONFIG_I40E_DCB */ #ifdef I40E_FCOE @@ -6881,17 +6933,17 @@ static int i40e_init_msix(struct i40e_pf *pf) if (pf->flags & I40E_FLAG_FD_SB_ENABLED) other_vecs++; + /* Scale down if necessary, and the rings will share vectors */ + pf->num_lan_msix = min_t(int, pf->num_lan_msix, + (hw->func_caps.num_msix_vectors - other_vecs)); + v_budget = pf->num_lan_msix + other_vecs; + #ifdef I40E_FCOE if (pf->flags & I40E_FLAG_FCOE_ENABLED) { pf->num_fcoe_msix = pf->num_fcoe_qps; v_budget += pf->num_fcoe_msix; } - #endif - /* Scale down if necessary, and the rings will share vectors */ - pf->num_lan_msix = min_t(int, pf->num_lan_msix, - (hw->func_caps.num_msix_vectors - other_vecs)); - v_budget = pf->num_lan_msix + other_vecs; pf->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry), GFP_KERNEL); @@ -7113,16 +7165,16 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf) */ if (!test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state)) { err = request_irq(pf->msix_entries[0].vector, - i40e_intr, 0, pf->misc_int_name, pf); + i40e_intr, 0, pf->int_name, pf); if (err) { dev_info(&pf->pdev->dev, "request_irq for %s failed: %d\n", - pf->misc_int_name, err); + pf->int_name, err); return -EFAULT; } } - i40e_enable_misc_int_causes(hw); + i40e_enable_misc_int_causes(pf); /* associate no queues to the misc vector */ wr32(hw, I40E_PFINT_LNKLST0, I40E_QUEUE_END_OF_LIST); @@ -7306,7 +7358,7 @@ static int i40e_sw_init(struct i40e_pf *pf) #endif /* I40E_FCOE */ #ifdef CONFIG_PCI_IOV - if (pf->hw.func_caps.num_vfs) { + if (pf->hw.func_caps.num_vfs && pf->hw.partition_id == 1) { pf->num_vf_qps = I40E_DEFAULT_QUEUES_PER_VF; pf->flags |= I40E_FLAG_SRIOV_ENABLED; pf->num_req_vfs = min_t(int, @@ -7766,7 +7818,8 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) enabled_tc = i40e_pf_get_tc_map(pf); /* MFP mode setup queue map and update VSI */ - if (pf->flags & I40E_FLAG_MFP_ENABLED) { + if ((pf->flags & I40E_FLAG_MFP_ENABLED) && + !(pf->hw.func_caps.iscsi)) { /* NIC type PF */ memset(&ctxt, 0, sizeof(ctxt)); ctxt.seid = pf->main_vsi_seid; ctxt.pf_num = pf->hw.pf_id; @@ -7787,6 +7840,8 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) /* Default/Main VSI is only enabled for TC0 * reconfigure it to enable all TCs that are * available on the port in SFP mode. + * For MFP case the iSCSI PF would use this + * flow to enable LAN+iSCSI TC. */ ret = i40e_vsi_config_tc(vsi, enabled_tc); if (ret) { @@ -9164,7 +9219,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw->aq.asq_buf_size = I40E_MAX_AQ_BUF_SIZE; pf->adminq_work_limit = I40E_AQ_WORK_LIMIT; - snprintf(pf->misc_int_name, sizeof(pf->misc_int_name) - 1, + snprintf(pf->int_name, sizeof(pf->int_name) - 1, "%s-%s:misc", dev_driver_string(&pf->pdev->dev), dev_name(&pdev->dev)); @@ -9227,6 +9282,16 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_configure_lan_hmc; } + /* Disable LLDP for NICs that have firmware versions lower than v4.3. + * Ignore error return codes because if it was already disabled via + * hardware settings this will fail + */ + if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) || + (pf->hw.aq.fw_maj_ver < 4)) { + dev_info(&pdev->dev, "Stopping firmware LLDP agent.\n"); + i40e_aq_stop_lldp(hw, true, NULL); + } + i40e_get_mac_addr(hw, hw->mac.addr); if (!is_valid_ether_addr(hw->mac.addr)) { dev_info(&pdev->dev, "invalid MAC address %pM\n", hw->mac.addr); @@ -9256,7 +9321,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #ifdef CONFIG_I40E_DCB err = i40e_init_pf_dcb(pf); if (err) { - dev_info(&pdev->dev, "init_pf_dcb failed: %d\n", err); + dev_info(&pdev->dev, "DCB init failed %d, disabled\n", err); pf->flags &= ~I40E_FLAG_DCB_CAPABLE; /* Continue without DCB enabled */ } @@ -9671,6 +9736,8 @@ static int i40e_suspend(struct pci_dev *pdev, pm_message_t state) set_bit(__I40E_SUSPENDED, &pf->state); set_bit(__I40E_DOWN, &pf->state); + del_timer_sync(&pf->service_timer); + cancel_work_sync(&pf->service_task); rtnl_lock(); i40e_prep_for_reset(pf); rtnl_unlock(); diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 2fb4306597e8..68e852a96680 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -71,6 +71,9 @@ i40e_status i40e_aq_get_firmware_version(struct i40e_hw *hw, i40e_status i40e_aq_debug_write_register(struct i40e_hw *hw, u32 reg_addr, u64 reg_val, struct i40e_asq_cmd_details *cmd_details); +i40e_status i40e_aq_debug_read_register(struct i40e_hw *hw, + u32 reg_addr, u64 *reg_val, + struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_phy_debug(struct i40e_hw *hw, u8 cmd_flags, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_default_vsi(struct i40e_hw *hw, u16 vsi_id, @@ -245,6 +248,8 @@ void i40e_clear_pxe_mode(struct i40e_hw *hw); bool i40e_get_link_status(struct i40e_hw *hw); i40e_status i40e_get_mac_addr(struct i40e_hw *hw, u8 *mac_addr); i40e_status i40e_get_port_mac_addr(struct i40e_hw *hw, u8 *mac_addr); +i40e_status i40e_read_pba_string(struct i40e_hw *hw, u8 *pba_num, + u32 pba_num_size); i40e_status i40e_validate_mac_addr(u8 *mac_addr); void i40e_pre_tx_queue_cfg(struct i40e_hw *hw, u32 queue, bool enable); #ifdef I40E_FCOE diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 6d1ec926aa37..fabcfa1b45b2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -247,7 +247,12 @@ void i40e_ptp_rx_hang(struct i40e_vsi *vsi) u32 prttsyn_stat; int n; - if (!(pf->flags & I40E_FLAG_PTP)) + /* Since we cannot turn off the Rx timestamp logic if the device is + * configured for Tx timestamping, we check if Rx timestamping is + * configured. We don't want to spuriously warn about Rx timestamp + * hangs if we don't care about the timestamps. + */ + if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx) return; prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1); @@ -305,6 +310,13 @@ void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf) u32 hi, lo; u64 ns; + if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx) + return; + + /* don't attempt to timestamp if we don't have an skb */ + if (!pf->ptp_tx_skb) + return; + lo = rd32(hw, I40E_PRTTSYN_TXTIME_L); hi = rd32(hw, I40E_PRTTSYN_TXTIME_H); @@ -338,7 +350,7 @@ void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index) /* Since we cannot turn off the Rx timestamp logic if the device is * doing Tx timestamping, check if Rx timestamping is configured. */ - if (!pf->ptp_rx) + if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx) return; hw = &pf->hw; @@ -467,7 +479,12 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, switch (config->rx_filter) { case HWTSTAMP_FILTER_NONE: pf->ptp_rx = false; - tsyntype = 0; + /* We set the type to V1, but do not enable UDP packet + * recognition. In this way, we should be as close to + * disabling PTP Rx timestamps as possible since V1 packets + * are always UDP, since L2 packets are a V2 feature. + */ + tsyntype = I40E_PRTTSYN_CTL1_TSYNTYPE_V1; break; case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: @@ -521,17 +538,18 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, regval &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; wr32(hw, I40E_PFINT_ICR0_ENA, regval); - /* There is no simple on/off switch for Rx. To "disable" Rx support, - * ignore any received timestamps, rather than turn off the clock. + /* Although there is no simple on/off switch for Rx, we "disable" Rx + * timestamps by setting to V1 only mode and clear the UDP + * recognition. This ought to disable all PTP Rx timestamps as V1 + * packets are always over UDP. Note that software is configured to + * ignore Rx timestamps via the pf->ptp_rx flag. */ - if (pf->ptp_rx) { - regval = rd32(hw, I40E_PRTTSYN_CTL1); - /* clear everything but the enable bit */ - regval &= I40E_PRTTSYN_CTL1_TSYNENA_MASK; - /* now enable bits for desired Rx timestamps */ - regval |= tsyntype; - wr32(hw, I40E_PRTTSYN_CTL1, regval); - } + regval = rd32(hw, I40E_PRTTSYN_CTL1); + /* clear everything but the enable bit */ + regval &= I40E_PRTTSYN_CTL1_TSYNENA_MASK; + /* now enable bits for desired Rx timestamps */ + regval |= tsyntype; + wr32(hw, I40E_PRTTSYN_CTL1, regval); return 0; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index cecb340898fe..2206d2d36f0f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -836,8 +836,8 @@ static void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) { u32 val = I40E_PFINT_DYN_CTLN_INTENA_MASK | I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK | - I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK - /* allow 00 to be written to the index */; + I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK; + /* allow 00 to be written to the index */ wr32(&vsi->back->hw, I40E_PFINT_DYN_CTLN(q_vector->v_idx + vsi->base_vector - 1), @@ -1098,6 +1098,8 @@ int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring) if (!rx_ring->rx_bi) goto err; + u64_stats_init(&rx_ring->syncp); + /* Round up to nearest 4K */ rx_ring->size = ring_is_16byte_desc_enabled(rx_ring) ? rx_ring->count * sizeof(union i40e_16byte_rx_desc) @@ -1815,8 +1817,8 @@ static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb, u32 tx_flags = 0; /* if we have a HW VLAN tag being added, default to the HW one */ - if (vlan_tx_tag_present(skb)) { - tx_flags |= vlan_tx_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT; + if (skb_vlan_tag_present(skb)) { + tx_flags |= skb_vlan_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT; tx_flags |= I40E_TX_FLAGS_HW_VLAN; /* else if it is a SW VLAN, check the next protocol and store the tag */ } else if (protocol == htons(ETH_P_8021Q)) { @@ -1939,6 +1941,9 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb, * we are not already transmitting a packet to be timestamped */ pf = i40e_netdev_to_pf(tx_ring->netdev); + if (!(pf->flags & I40E_FLAG_PTP)) + return 0; + if (pf->ptp_tx && !test_and_set_bit_lock(__I40E_PTP_TX_IN_PROGRESS, &pf->state)) { skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index c1f2eb963357..e9901ef06a63 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -211,6 +211,7 @@ struct i40e_hw_capabilities { bool evb_802_1_qbh; /* Bridge Port Extension */ bool dcb; bool fcoe; + bool iscsi; /* Indicates iSCSI enabled */ bool mfp_mode_1; bool mgmt_cem; bool ieee_1588; @@ -431,7 +432,7 @@ struct i40e_hw { u8 __iomem *hw_addr; void *back; - /* function pointer structs */ + /* subsystem structs */ struct i40e_phy_info phy; struct i40e_mac_info mac; struct i40e_bus_info bus; @@ -458,6 +459,11 @@ struct i40e_hw { u8 pf_id; u16 main_vsi_seid; + /* for multi-function MACs */ + u16 partition_id; + u16 num_partitions; + u16 num_ports; + /* Closest numa node to the device */ u16 numa_node; @@ -1135,6 +1141,8 @@ struct i40e_hw_port_stats { /* Checksum and Shadow RAM pointers */ #define I40E_SR_NVM_CONTROL_WORD 0x00 #define I40E_SR_EMP_MODULE_PTR 0x0F +#define I40E_SR_PBA_FLAGS 0x15 +#define I40E_SR_PBA_BLOCK_PTR 0x16 #define I40E_SR_NVM_IMAGE_VERSION 0x18 #define I40E_SR_NVM_WAKE_ON_LAN 0x19 #define I40E_SR_ALTERNATE_SAN_MAC_ADDRESS_PTR 0x27 diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 5bae89550657..40f042af4131 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -647,6 +647,9 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr) int i; u32 reg; + if (test_and_set_bit(__I40E_VF_DISABLE, &pf->state)) + return; + /* warn the VF */ clear_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states); @@ -668,13 +671,13 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr) /* poll VPGEN_VFRSTAT reg to make sure * that reset is complete */ - for (i = 0; i < 100; i++) { - /* vf reset requires driver to first reset the - * vf and then poll the status register to make sure - * that the requested op was completed - * successfully + for (i = 0; i < 10; i++) { + /* VF reset requires driver to first reset the VF and then + * poll the status register to make sure that the reset + * completed successfully. Due to internal HW FIFO flushes, + * we must wait 10ms before the register will be valid. */ - usleep_range(10, 20); + usleep_range(10000, 20000); reg = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_id)); if (reg & I40E_VPGEN_VFRSTAT_VFRD_MASK) { rsd = true; @@ -706,6 +709,7 @@ complete_reset: /* tell the VF the reset is done */ wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE); i40e_flush(hw); + clear_bit(__I40E_VF_DISABLE, &pf->state); } /** @@ -790,11 +794,18 @@ void i40e_free_vfs(struct i40e_pf *pf) if (!pf->vf) return; + while (test_and_set_bit(__I40E_VF_DISABLE, &pf->state)) + usleep_range(1000, 2000); - /* Disable interrupt 0 so we don't try to handle the VFLR. */ - i40e_irq_dynamic_disable_icr0(pf); + /* Disable IOV before freeing resources. This lets any VF drivers + * running in the host get themselves cleaned up before we yank + * the carpet out from underneath their feet. + */ + if (!pci_vfs_assigned(pf->pdev)) + pci_disable_sriov(pf->pdev); + + msleep(20); /* let any messages in transit get finished up */ - mdelay(10); /* let any messages in transit get finished up */ /* free up vf resources */ tmp = pf->num_alloc_vfs; pf->num_alloc_vfs = 0; @@ -813,7 +824,6 @@ void i40e_free_vfs(struct i40e_pf *pf) * before this function ever gets called. */ if (!pci_vfs_assigned(pf->pdev)) { - pci_disable_sriov(pf->pdev); /* Acknowledge VFLR for all VFS. Without this, VFs will fail to * work correctly when SR-IOV gets re-enabled. */ @@ -827,9 +837,7 @@ void i40e_free_vfs(struct i40e_pf *pf) dev_warn(&pf->pdev->dev, "unable to disable SR-IOV because VFs are assigned.\n"); } - - /* Re-enable interrupt 0. */ - i40e_irq_dynamic_enable_icr0(pf); + clear_bit(__I40E_VF_DISABLE, &pf->state); } #ifdef CONFIG_PCI_IOV diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h index 6c31bf22c2c3..60f04e96a80e 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h @@ -148,7 +148,7 @@ static inline int i40e_aq_rc_to_posix(u32 aq_ret, u16 aq_rc) /* general information */ #define I40E_AQ_LARGE_BUF 512 -#define I40E_ASQ_CMD_TIMEOUT 100 /* msecs */ +#define I40E_ASQ_CMD_TIMEOUT 250 /* msecs */ void i40evf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc, u16 opcode); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h index ff1b16370da9..e715bccfb5d2 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h @@ -268,6 +268,8 @@ enum i40e_admin_queue_opc { /* OEM commands */ i40e_aqc_opc_oem_parameter_change = 0xFE00, i40e_aqc_opc_oem_device_status_change = 0xFE01, + i40e_aqc_opc_oem_ocsd_initialize = 0xFE02, + i40e_aqc_opc_oem_ocbb_initialize = 0xFE03, /* debug commands */ i40e_aqc_opc_debug_get_deviceid = 0xFF00, @@ -276,7 +278,6 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_debug_write_reg = 0xFF04, i40e_aqc_opc_debug_modify_reg = 0xFF07, i40e_aqc_opc_debug_dump_internals = 0xFF08, - i40e_aqc_opc_debug_modify_internals = 0xFF09, }; /* command structures and indirect data structures */ @@ -410,6 +411,7 @@ struct i40e_aqc_list_capabilities_element_resp { #define I40E_AQ_CAP_ID_VSI 0x0017 #define I40E_AQ_CAP_ID_DCB 0x0018 #define I40E_AQ_CAP_ID_FCOE 0x0021 +#define I40E_AQ_CAP_ID_ISCSI 0x0022 #define I40E_AQ_CAP_ID_RSS 0x0040 #define I40E_AQ_CAP_ID_RXQ 0x0041 #define I40E_AQ_CAP_ID_TXQ 0x0042 @@ -454,8 +456,11 @@ struct i40e_aqc_arp_proxy_data { __le32 pfpm_proxyfc; __le32 ip_addr; u8 mac_addr[6]; + u8 reserved[2]; }; +I40E_CHECK_STRUCT_LEN(0x14, i40e_aqc_arp_proxy_data); + /* Set NS Proxy Table Entry Command (indirect 0x0105) */ struct i40e_aqc_ns_proxy_data { __le16 table_idx_mac_addr_0; @@ -481,6 +486,8 @@ struct i40e_aqc_ns_proxy_data { u8 ipv6_addr_1[16]; }; +I40E_CHECK_STRUCT_LEN(0x3c, i40e_aqc_ns_proxy_data); + /* Manage LAA Command (0x0106) - obsolete */ struct i40e_aqc_mng_laa { __le16 command_flags; @@ -491,6 +498,8 @@ struct i40e_aqc_mng_laa { u8 reserved2[6]; }; +I40E_CHECK_CMD_LENGTH(i40e_aqc_mng_laa); + /* Manage MAC Address Read Command (indirect 0x0107) */ struct i40e_aqc_mac_address_read { __le16 command_flags; @@ -562,6 +571,8 @@ struct i40e_aqc_get_switch_config_header_resp { u8 reserved[12]; }; +I40E_CHECK_CMD_LENGTH(i40e_aqc_get_switch_config_header_resp); + struct i40e_aqc_switch_config_element_resp { u8 element_type; #define I40E_AQ_SW_ELEM_TYPE_MAC 1 @@ -587,6 +598,8 @@ struct i40e_aqc_switch_config_element_resp { __le16 element_info; }; +I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_config_element_resp); + /* Get Switch Configuration (indirect 0x0200) * an array of elements are returned in the response buffer * the first in the array is the header, remainder are elements @@ -596,6 +609,8 @@ struct i40e_aqc_get_switch_config_resp { struct i40e_aqc_switch_config_element_resp element[1]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_get_switch_config_resp); + /* Add Statistics (direct 0x0201) * Remove Statistics (direct 0x0202) */ @@ -661,6 +676,8 @@ struct i40e_aqc_switch_resource_alloc_element_resp { u8 reserved2[6]; }; +I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp); + /* Add VSI (indirect 0x0210) * this indirect command uses struct i40e_aqc_vsi_properties_data * as the indirect buffer (128 bytes) @@ -1092,6 +1109,8 @@ struct i40e_aqc_remove_tag { u8 reserved[12]; }; +I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_tag); + /* Add multicast E-Tag (direct 0x0257) * del multicast E-Tag (direct 0x0258) only uses pv_seid and etag fields * and no external data @@ -1207,7 +1226,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data { } ipaddr; __le16 flags; #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT 0 -#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \ +#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \ I40E_AQC_ADD_CLOUD_FILTER_SHIFT) /* 0x0000 reserved */ #define I40E_AQC_ADD_CLOUD_FILTER_OIP 0x0001 @@ -1240,7 +1259,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data { u8 reserved[4]; __le16 queue_number; #define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT 0 -#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x3F << \ +#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x7FF << \ I40E_AQC_ADD_CLOUD_QUEUE_SHIFT) u8 reserved2[14]; /* response section */ @@ -1359,6 +1378,8 @@ struct i40e_aqc_configure_vsi_ets_sla_bw_data { u8 reserved1[28]; }; +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_configure_vsi_ets_sla_bw_data); + /* Configure VSI Bandwidth Allocation per Traffic Type (indirect 0x0407) * responds with i40e_aqc_qs_handles_resp */ @@ -1370,6 +1391,8 @@ struct i40e_aqc_configure_vsi_tc_bw_data { __le16 qs_handles[8]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_vsi_tc_bw_data); + /* Query vsi bw configuration (indirect 0x0408) */ struct i40e_aqc_query_vsi_bw_config_resp { u8 tc_valid_bits; @@ -1383,6 +1406,8 @@ struct i40e_aqc_query_vsi_bw_config_resp { u8 reserved3[23]; }; +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_vsi_bw_config_resp); + /* Query VSI Bandwidth Allocation per Traffic Type (indirect 0x040A) */ struct i40e_aqc_query_vsi_ets_sla_config_resp { u8 tc_valid_bits; @@ -1394,6 +1419,8 @@ struct i40e_aqc_query_vsi_ets_sla_config_resp { __le16 tc_bw_max[2]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_vsi_ets_sla_config_resp); + /* Configure Switching Component Bandwidth Limit (direct 0x0410) */ struct i40e_aqc_configure_switching_comp_bw_limit { __le16 seid; @@ -1421,6 +1448,8 @@ struct i40e_aqc_configure_switching_comp_ets_data { u8 reserved2[96]; }; +I40E_CHECK_STRUCT_LEN(0x80, i40e_aqc_configure_switching_comp_ets_data); + /* Configure Switching Component Bandwidth Limits per Tc (indirect 0x0416) */ struct i40e_aqc_configure_switching_comp_ets_bw_limit_data { u8 tc_valid_bits; @@ -1432,6 +1461,9 @@ struct i40e_aqc_configure_switching_comp_ets_bw_limit_data { u8 reserved1[28]; }; +I40E_CHECK_STRUCT_LEN(0x40, + i40e_aqc_configure_switching_comp_ets_bw_limit_data); + /* Configure Switching Component Bandwidth Allocation per Tc * (indirect 0x0417) */ @@ -1443,6 +1475,8 @@ struct i40e_aqc_configure_switching_comp_bw_config_data { u8 reserved1[20]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_switching_comp_bw_config_data); + /* Query Switching Component Configuration (indirect 0x0418) */ struct i40e_aqc_query_switching_comp_ets_config_resp { u8 tc_valid_bits; @@ -1453,6 +1487,8 @@ struct i40e_aqc_query_switching_comp_ets_config_resp { u8 reserved2[23]; }; +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_switching_comp_ets_config_resp); + /* Query PhysicalPort ETS Configuration (indirect 0x0419) */ struct i40e_aqc_query_port_ets_config_resp { u8 reserved[4]; @@ -1468,6 +1504,8 @@ struct i40e_aqc_query_port_ets_config_resp { u8 reserved3[32]; }; +I40E_CHECK_STRUCT_LEN(0x44, i40e_aqc_query_port_ets_config_resp); + /* Query Switching Component Bandwidth Allocation per Traffic Type * (indirect 0x041A) */ @@ -1482,6 +1520,8 @@ struct i40e_aqc_query_switching_comp_bw_config_resp { __le16 tc_bw_max[2]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_switching_comp_bw_config_resp); + /* Suspend/resume port TX traffic * (direct 0x041B and 0x041C) uses the generic SEID struct */ @@ -1495,6 +1535,8 @@ struct i40e_aqc_configure_partition_bw_data { u8 max_bw[16]; /* bandwidth limit */ }; +I40E_CHECK_STRUCT_LEN(0x22, i40e_aqc_configure_partition_bw_data); + /* Get and set the active HMC resource profile and status. * (direct 0x0500) and (direct 0x0501) */ @@ -1577,6 +1619,8 @@ struct i40e_aqc_module_desc { u8 reserved2[8]; }; +I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_module_desc); + struct i40e_aq_get_phy_abilities_resp { __le32 phy_type; /* bitmap using the above enum for offsets */ u8 link_speed; /* bitmap using the above enum bit patterns */ @@ -1605,6 +1649,8 @@ struct i40e_aq_get_phy_abilities_resp { struct i40e_aqc_module_desc qualified_module[I40E_AQ_PHY_MAX_QMS]; }; +I40E_CHECK_STRUCT_LEN(0x218, i40e_aq_get_phy_abilities_resp); + /* Set PHY Config (direct 0x0601) */ struct i40e_aq_set_phy_config { /* same bits as above in all */ __le32 phy_type; @@ -1788,12 +1834,12 @@ I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_update); /* NVM Config Read (indirect 0x0704) */ struct i40e_aqc_nvm_config_read { __le16 cmd_flags; -#define ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1 -#define ANVM_READ_SINGLE_FEATURE 0 -#define ANVM_READ_MULTIPLE_FEATURES 1 +#define I40E_AQ_ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1 +#define I40E_AQ_ANVM_READ_SINGLE_FEATURE 0 +#define I40E_AQ_ANVM_READ_MULTIPLE_FEATURES 1 __le16 element_count; - __le16 element_id; /* Feature/field ID */ - u8 reserved[2]; + __le16 element_id; /* Feature/field ID */ + __le16 element_id_msw; /* MSWord of field ID */ __le32 address_high; __le32 address_low; }; @@ -1811,21 +1857,32 @@ struct i40e_aqc_nvm_config_write { I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_config_write); +/* Used for 0x0704 as well as for 0x0705 commands */ +#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT 1 +#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_MASK \ + (1 << I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT) +#define I40E_AQ_ANVM_FEATURE 0 +#define I40E_AQ_ANVM_IMMEDIATE_FIELD (1 << FEATURE_OR_IMMEDIATE_SHIFT) struct i40e_aqc_nvm_config_data_feature { __le16 feature_id; - __le16 instance_id; +#define I40E_AQ_ANVM_FEATURE_OPTION_OEM_ONLY 0x01 +#define I40E_AQ_ANVM_FEATURE_OPTION_DWORD_MAP 0x08 +#define I40E_AQ_ANVM_FEATURE_OPTION_POR_CSR 0x10 __le16 feature_options; __le16 feature_selection; }; +I40E_CHECK_STRUCT_LEN(0x6, i40e_aqc_nvm_config_data_feature); + struct i40e_aqc_nvm_config_data_immediate_field { -#define ANVM_FEATURE_OR_IMMEDIATE_MASK 0x2 - __le16 field_id; - __le16 instance_id; + __le32 field_id; + __le32 field_value; __le16 field_options; - __le16 field_value; + __le16 reserved; }; +I40E_CHECK_STRUCT_LEN(0xc, i40e_aqc_nvm_config_data_immediate_field); + /* Send to PF command (indirect 0x0801) id is only used by PF * Send to VF command (indirect 0x0802) id is only used by PF * Send to Peer PF command (indirect 0x0803) @@ -2082,7 +2139,8 @@ struct i40e_aqc_oem_param_change { #define I40E_AQ_OEM_PARAM_TYPE_BW_CTL 1 #define I40E_AQ_OEM_PARAM_MAC 2 __le32 param_value1; - u8 param_value2[8]; + __le16 param_value2; + u8 reserved[6]; }; I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_param_change); @@ -2096,6 +2154,28 @@ struct i40e_aqc_oem_state_change { I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_state_change); +/* Initialize OCSD (0xFE02, direct) */ +struct i40e_aqc_opc_oem_ocsd_initialize { + u8 type_status; + u8 reserved1[3]; + __le32 ocsd_memory_block_addr_high; + __le32 ocsd_memory_block_addr_low; + __le32 requested_update_interval; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocsd_initialize); + +/* Initialize OCBB (0xFE03, direct) */ +struct i40e_aqc_opc_oem_ocbb_initialize { + u8 type_status; + u8 reserved1[3]; + __le32 ocbb_memory_block_addr_high; + __le32 ocbb_memory_block_addr_low; + u8 reserved2[4]; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocbb_initialize); + /* debug commands */ /* get device id (0xFF00) uses the generic structure */ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 04c7c1557a0c..29004382f462 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -192,6 +192,8 @@ static inline u32 i40e_get_head(struct i40e_ring *tx_ring) return le32_to_cpu(*(volatile __le32 *)head); } +#define WB_STRIDE 0x3 + /** * i40e_clean_tx_irq - Reclaim resources after transmit completes * @tx_ring: tx ring to clean @@ -293,6 +295,14 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) tx_ring->q_vector->tx.total_bytes += total_bytes; tx_ring->q_vector->tx.total_packets += total_packets; + if (budget && + !((i & WB_STRIDE) == WB_STRIDE) && + !test_bit(__I40E_DOWN, &tx_ring->vsi->state) && + (I40E_DESC_UNUSED(tx_ring) != tx_ring->count)) + tx_ring->arm_wb = true; + else + tx_ring->arm_wb = false; + if (check_for_tx_hang(tx_ring) && i40e_check_tx_hang(tx_ring)) { /* schedule immediate reset if we believe we hung */ dev_info(tx_ring->dev, "Detected Tx Unit Hang\n" @@ -343,6 +353,24 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) return budget > 0; } +/** + * i40e_force_wb -Arm hardware to do a wb on noncache aligned descriptors + * @vsi: the VSI we care about + * @q_vector: the vector on which to force writeback + * + **/ +static void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) +{ + u32 val = I40E_VFINT_DYN_CTLN_INTENA_MASK | + I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK | + I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK; + /* allow 00 to be written to the index */ + + wr32(&vsi->back->hw, + I40E_VFINT_DYN_CTLN1(q_vector->v_idx + vsi->base_vector - 1), + val); +} + /** * i40e_set_new_dynamic_itr - Find new ITR level * @rc: structure containing ring performance data @@ -568,6 +596,8 @@ int i40evf_setup_rx_descriptors(struct i40e_ring *rx_ring) if (!rx_ring->rx_bi) goto err; + u64_stats_init(&rx_ring->syncp); + /* Round up to nearest 4K */ rx_ring->size = ring_is_16byte_desc_enabled(rx_ring) ? rx_ring->count * sizeof(union i40e_16byte_rx_desc) @@ -1065,6 +1095,7 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget) struct i40e_vsi *vsi = q_vector->vsi; struct i40e_ring *ring; bool clean_complete = true; + bool arm_wb = false; int budget_per_ring; if (test_bit(__I40E_DOWN, &vsi->state)) { @@ -1075,8 +1106,10 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget) /* Since the actual Tx work is minimal, we can give the Tx a larger * budget and be more aggressive about cleaning up the Tx descriptors. */ - i40e_for_each_ring(ring, q_vector->tx) + i40e_for_each_ring(ring, q_vector->tx) { clean_complete &= i40e_clean_tx_irq(ring, vsi->work_limit); + arm_wb |= ring->arm_wb; + } /* We attempt to distribute budget to each Rx queue fairly, but don't * allow the budget to go below 1 because that would exit polling early. @@ -1087,8 +1120,11 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget) clean_complete &= i40e_clean_rx_irq(ring, budget_per_ring); /* If work not completed, return budget and polling will return */ - if (!clean_complete) + if (!clean_complete) { + if (arm_wb) + i40e_force_wb(vsi, q_vector); return budget; + } /* Work is done so exit the polling mode and re-enable the interrupt */ napi_complete(napi); @@ -1122,8 +1158,8 @@ static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb, u32 tx_flags = 0; /* if we have a HW VLAN tag being added, default to the HW one */ - if (vlan_tx_tag_present(skb)) { - tx_flags |= vlan_tx_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT; + if (skb_vlan_tag_present(skb)) { + tx_flags |= skb_vlan_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT; tx_flags |= I40E_TX_FLAGS_HW_VLAN; /* else if it is a SW VLAN, check the next protocol and store the tag */ } else if (protocol == htons(ETH_P_8021Q)) { diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h index c7f29626eada..4e15903b2b6d 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h @@ -238,6 +238,7 @@ struct i40e_ring { u8 atr_count; bool ring_active; /* is ring online or not */ + bool arm_wb; /* do something to arm write back */ /* stats structs */ struct i40e_queue_stats stats; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 68aec11f6523..3d0fdaab5cc8 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -211,6 +211,7 @@ struct i40e_hw_capabilities { bool evb_802_1_qbh; /* Bridge Port Extension */ bool dcb; bool fcoe; + bool iscsi; /* Indicates iSCSI enabled */ bool mfp_mode_1; bool mgmt_cem; bool ieee_1588; @@ -425,7 +426,7 @@ struct i40e_hw { u8 __iomem *hw_addr; void *back; - /* function pointer structs */ + /* subsystem structs */ struct i40e_phy_info phy; struct i40e_mac_info mac; struct i40e_bus_info bus; @@ -452,6 +453,11 @@ struct i40e_hw { u8 pf_id; u16 main_vsi_seid; + /* for multi-function MACs */ + u16 partition_id; + u16 num_partitions; + u16 num_ports; + /* Closest numa node to the device */ u16 numa_node; diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index cabaf599f562..8d8c201c63c1 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -36,7 +36,7 @@ char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710/X710 Virtual Function Network Driver"; -#define DRV_VERSION "1.0.6" +#define DRV_VERSION "1.2.0" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = "Copyright (c) 2013 - 2014 Intel Corporation."; @@ -313,10 +313,6 @@ static irqreturn_t i40evf_msix_aq(int irq, void *data) val = val | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; wr32(hw, I40E_VFINT_DYN_CTL01, val); - /* re-enable interrupt causes */ - wr32(hw, I40E_VFINT_ICR0_ENA1, ena_mask); - wr32(hw, I40E_VFINT_DYN_CTL01, I40E_VFINT_DYN_CTL01_INTENA_MASK); - /* schedule work on the private workqueue */ schedule_work(&adapter->adminq_task); @@ -946,30 +942,6 @@ static int i40evf_up_complete(struct i40evf_adapter *adapter) return 0; } -/** - * i40evf_clean_all_rx_rings - Free Rx Buffers for all queues - * @adapter: board private structure - **/ -static void i40evf_clean_all_rx_rings(struct i40evf_adapter *adapter) -{ - int i; - - for (i = 0; i < adapter->num_active_queues; i++) - i40evf_clean_rx_ring(adapter->rx_rings[i]); -} - -/** - * i40evf_clean_all_tx_rings - Free Tx Buffers for all queues - * @adapter: board private structure - **/ -static void i40evf_clean_all_tx_rings(struct i40evf_adapter *adapter) -{ - int i; - - for (i = 0; i < adapter->num_active_queues; i++) - i40evf_clean_tx_ring(adapter->tx_rings[i]); -} - /** * i40e_down - Shutdown the connection processing * @adapter: board private structure @@ -982,6 +954,12 @@ void i40evf_down(struct i40evf_adapter *adapter) if (adapter->state == __I40EVF_DOWN) return; + while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, + &adapter->crit_section)) + usleep_range(500, 1000); + + i40evf_irq_disable(adapter); + /* remove all MAC filters */ list_for_each_entry(f, &adapter->mac_filter_list, list) { f->remove = true; @@ -992,25 +970,27 @@ void i40evf_down(struct i40evf_adapter *adapter) } if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) && adapter->state != __I40EVF_RESETTING) { - adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; + /* cancel any current operation */ + adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->aq_pending = 0; + /* Schedule operations to close down the HW. Don't wait + * here for this to complete. The watchdog is still running + * and it will take care of this. + */ + adapter->aq_required = I40EVF_FLAG_AQ_DEL_MAC_FILTER; adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER; - /* disable receives */ adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES; - mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); - msleep(20); } netif_tx_disable(netdev); netif_tx_stop_all_queues(netdev); - i40evf_irq_disable(adapter); - i40evf_napi_disable_all(adapter); - netif_carrier_off(netdev); + msleep(20); - i40evf_clean_all_tx_rings(adapter); - i40evf_clean_all_rx_rings(adapter); + netif_carrier_off(netdev); + clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); } /** @@ -1356,8 +1336,13 @@ static void i40evf_watchdog_task(struct work_struct *work) /* Process admin queue tasks. After init, everything gets done * here so we don't race on the admin queue. */ - if (adapter->aq_pending) + if (adapter->aq_pending) { + if (!i40evf_asq_done(hw)) { + dev_dbg(&adapter->pdev->dev, "Admin queue timeout\n"); + i40evf_send_api_ver(adapter); + } goto watchdog_done; + } if (adapter->aq_required & I40EVF_FLAG_AQ_MAP_VECTORS) { i40evf_map_queues(adapter); @@ -1401,11 +1386,14 @@ static void i40evf_watchdog_task(struct work_struct *work) if (adapter->state == __I40EVF_RUNNING) i40evf_request_stats(adapter); - - i40evf_irq_enable(adapter, true); - i40evf_fire_sw_int(adapter, 0xFF); - watchdog_done: + if (adapter->state == __I40EVF_RUNNING) { + i40evf_irq_enable_queues(adapter, ~0); + i40evf_fire_sw_int(adapter, 0xFF); + } else { + i40evf_fire_sw_int(adapter, 0x1); + } + clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); restart_watchdog: if (adapter->state == __I40EVF_REMOVE) @@ -1633,17 +1621,17 @@ static void i40evf_adminq_task(struct work_struct *work) u16 pending; if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) - return; + goto out; event.buf_len = I40EVF_MAX_AQ_BUF_SIZE; event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL); if (!event.msg_buf) - return; + goto out; v_msg = (struct i40e_virtchnl_msg *)&event.desc; do { ret = i40evf_clean_arq_element(hw, &event, &pending); - if (ret) + if (ret || !v_msg->v_opcode) break; /* No event to process or error cleaning ARQ */ i40evf_virtchnl_completion(adapter, v_msg->v_opcode, @@ -1688,10 +1676,10 @@ static void i40evf_adminq_task(struct work_struct *work) if (oldval != val) wr32(hw, hw->aq.asq.len, val); + kfree(event.msg_buf); +out: /* re-enable Admin queue interrupt cause */ i40evf_misc_irq_enable(adapter); - - kfree(event.msg_buf); } /** @@ -2053,12 +2041,8 @@ static void i40evf_init_task(struct work_struct *work) /* aq msg sent, awaiting reply */ err = i40evf_verify_api_ver(adapter); if (err) { - dev_info(&pdev->dev, "Unable to verify API version (%d), retrying\n", - err); - if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) { - dev_info(&pdev->dev, "Resending request\n"); + if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) err = i40evf_send_api_ver(adapter); - } goto err; } err = i40evf_send_vf_config_msg(adapter); @@ -2081,7 +2065,6 @@ static void i40evf_init_task(struct work_struct *work) } err = i40evf_get_vf_config(adapter); if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) { - dev_info(&pdev->dev, "Resending VF config request\n"); err = i40evf_send_vf_config_msg(adapter); goto err; } @@ -2230,12 +2213,18 @@ err: static void i40evf_shutdown(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); + struct i40evf_adapter *adapter = netdev_priv(netdev); netif_device_detach(netdev); if (netif_running(netdev)) i40evf_close(netdev); + /* Prevent the watchdog from running. */ + adapter->state = __I40EVF_REMOVE; + adapter->aq_required = 0; + adapter->aq_pending = 0; + #ifdef CONFIG_PM pci_save_state(pdev); @@ -2448,7 +2437,18 @@ static void i40evf_remove(struct pci_dev *pdev) unregister_netdev(netdev); adapter->netdev_registered = false; } + + /* Shut down all the garbage mashers on the detention level */ adapter->state = __I40EVF_REMOVE; + adapter->aq_required = 0; + adapter->aq_pending = 0; + i40evf_request_reset(adapter); + msleep(20); + /* If the FW isn't responding, kick it once, but only once. */ + if (!i40evf_asq_done(hw)) { + i40evf_request_reset(adapter); + msleep(20); + } if (adapter->msix_entries) { i40evf_misc_irq_disable(adapter); @@ -2477,6 +2477,10 @@ static void i40evf_remove(struct pci_dev *pdev) list_del(&f->list); kfree(f); } + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { + list_del(&f->list); + kfree(f); + } free_netdev(netdev); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 5fde5a7f4591..3f0c85ecbca6 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -715,14 +715,14 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, } return; } - if (v_opcode != adapter->current_op) - dev_info(&adapter->pdev->dev, "Pending op is %d, received %d\n", - adapter->current_op, v_opcode); if (v_retval) { dev_err(&adapter->pdev->dev, "%s: PF returned error %d to our request %d\n", __func__, v_retval, v_opcode); } switch (v_opcode) { + case I40E_VIRTCHNL_OP_VERSION: + /* no action, but also not an error */ + break; case I40E_VIRTCHNL_OP_GET_STATS: { struct i40e_eth_stats *stats = (struct i40e_eth_stats *)msg; diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 82d891e183b1..c2bd4f98a837 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -29,7 +29,7 @@ #include "e1000_mac.h" #include "e1000_82575.h" -#include +#include #include #include #include @@ -343,6 +343,9 @@ struct hwmon_buff { }; #endif +#define IGB_N_EXTTS 2 +#define IGB_N_PEROUT 2 +#define IGB_N_SDP 4 #define IGB_RETA_SIZE 128 /* board specific private data structure */ @@ -439,6 +442,12 @@ struct igb_adapter { u32 tx_hwtstamp_timeouts; u32 rx_hwtstamp_cleared; + struct ptp_pin_desc sdp_config[IGB_N_SDP]; + struct { + struct timespec start; + struct timespec period; + } perout[IGB_N_PEROUT]; + char fw_version[32]; #ifdef CONFIG_IGB_HWMON struct hwmon_buff *igb_hwmon_buff; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index ff59897a9463..f366b3b96d03 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -5035,9 +5035,9 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, skb_tx_timestamp(skb); - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { tx_flags |= IGB_TX_FLAGS_VLAN; - tx_flags |= (vlan_tx_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT); + tx_flags |= (skb_vlan_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT); } /* record initial flags and protocol */ @@ -5384,6 +5384,80 @@ void igb_update_stats(struct igb_adapter *adapter, } } +static void igb_tsync_interrupt(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct ptp_clock_event event; + struct timespec ts; + u32 ack = 0, tsauxc, sec, nsec, tsicr = rd32(E1000_TSICR); + + if (tsicr & TSINTR_SYS_WRAP) { + event.type = PTP_CLOCK_PPS; + if (adapter->ptp_caps.pps) + ptp_clock_event(adapter->ptp_clock, &event); + else + dev_err(&adapter->pdev->dev, "unexpected SYS WRAP"); + ack |= TSINTR_SYS_WRAP; + } + + if (tsicr & E1000_TSICR_TXTS) { + /* retrieve hardware timestamp */ + schedule_work(&adapter->ptp_tx_work); + ack |= E1000_TSICR_TXTS; + } + + if (tsicr & TSINTR_TT0) { + spin_lock(&adapter->tmreg_lock); + ts = timespec_add(adapter->perout[0].start, + adapter->perout[0].period); + wr32(E1000_TRGTTIML0, ts.tv_nsec); + wr32(E1000_TRGTTIMH0, ts.tv_sec); + tsauxc = rd32(E1000_TSAUXC); + tsauxc |= TSAUXC_EN_TT0; + wr32(E1000_TSAUXC, tsauxc); + adapter->perout[0].start = ts; + spin_unlock(&adapter->tmreg_lock); + ack |= TSINTR_TT0; + } + + if (tsicr & TSINTR_TT1) { + spin_lock(&adapter->tmreg_lock); + ts = timespec_add(adapter->perout[1].start, + adapter->perout[1].period); + wr32(E1000_TRGTTIML1, ts.tv_nsec); + wr32(E1000_TRGTTIMH1, ts.tv_sec); + tsauxc = rd32(E1000_TSAUXC); + tsauxc |= TSAUXC_EN_TT1; + wr32(E1000_TSAUXC, tsauxc); + adapter->perout[1].start = ts; + spin_unlock(&adapter->tmreg_lock); + ack |= TSINTR_TT1; + } + + if (tsicr & TSINTR_AUTT0) { + nsec = rd32(E1000_AUXSTMPL0); + sec = rd32(E1000_AUXSTMPH0); + event.type = PTP_CLOCK_EXTTS; + event.index = 0; + event.timestamp = sec * 1000000000ULL + nsec; + ptp_clock_event(adapter->ptp_clock, &event); + ack |= TSINTR_AUTT0; + } + + if (tsicr & TSINTR_AUTT1) { + nsec = rd32(E1000_AUXSTMPL1); + sec = rd32(E1000_AUXSTMPH1); + event.type = PTP_CLOCK_EXTTS; + event.index = 1; + event.timestamp = sec * 1000000000ULL + nsec; + ptp_clock_event(adapter->ptp_clock, &event); + ack |= TSINTR_AUTT1; + } + + /* acknowledge the interrupts */ + wr32(E1000_TSICR, ack); +} + static irqreturn_t igb_msix_other(int irq, void *data) { struct igb_adapter *adapter = data; @@ -5415,16 +5489,8 @@ static irqreturn_t igb_msix_other(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (icr & E1000_ICR_TS) { - u32 tsicr = rd32(E1000_TSICR); - - if (tsicr & E1000_TSICR_TXTS) { - /* acknowledge the interrupt */ - wr32(E1000_TSICR, E1000_TSICR_TXTS); - /* retrieve hardware timestamp */ - schedule_work(&adapter->ptp_tx_work); - } - } + if (icr & E1000_ICR_TS) + igb_tsync_interrupt(adapter); wr32(E1000_EIMS, adapter->eims_other); @@ -6011,8 +6077,12 @@ static void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf) adapter->vf_data[vf].flags |= IGB_VF_FLAG_CTS; /* reply to reset with ack and vf mac address */ - msgbuf[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_ACK; - memcpy(addr, vf_mac, ETH_ALEN); + if (!is_zero_ether_addr(vf_mac)) { + msgbuf[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_ACK; + memcpy(addr, vf_mac, ETH_ALEN); + } else { + msgbuf[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_NACK; + } igb_write_mbx(hw, msgbuf, 3, vf); } @@ -6203,16 +6273,8 @@ static irqreturn_t igb_intr_msi(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (icr & E1000_ICR_TS) { - u32 tsicr = rd32(E1000_TSICR); - - if (tsicr & E1000_TSICR_TXTS) { - /* acknowledge the interrupt */ - wr32(E1000_TSICR, E1000_TSICR_TXTS); - /* retrieve hardware timestamp */ - schedule_work(&adapter->ptp_tx_work); - } - } + if (icr & E1000_ICR_TS) + igb_tsync_interrupt(adapter); napi_schedule(&q_vector->napi); @@ -6257,16 +6319,8 @@ static irqreturn_t igb_intr(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (icr & E1000_ICR_TS) { - u32 tsicr = rd32(E1000_TSICR); - - if (tsicr & E1000_TSICR_TXTS) { - /* acknowledge the interrupt */ - wr32(E1000_TSICR, E1000_TSICR_TXTS); - /* retrieve hardware timestamp */ - schedule_work(&adapter->ptp_tx_work); - } - } + if (icr & E1000_ICR_TS) + igb_tsync_interrupt(adapter); napi_schedule(&q_vector->napi); @@ -6527,15 +6581,17 @@ static void igb_reuse_rx_page(struct igb_ring *rx_ring, DMA_FROM_DEVICE); } +static inline bool igb_page_is_reserved(struct page *page) +{ + return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc; +} + static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer, struct page *page, unsigned int truesize) { /* avoid re-using remote pages */ - if (unlikely(page_to_nid(page) != numa_node_id())) - return false; - - if (unlikely(page->pfmemalloc)) + if (unlikely(igb_page_is_reserved(page))) return false; #if (PAGE_SIZE < 8192) @@ -6545,22 +6601,19 @@ static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer, /* flip page offset to other buffer */ rx_buffer->page_offset ^= IGB_RX_BUFSZ; - - /* Even if we own the page, we are not allowed to use atomic_set() - * This would break get_page_unless_zero() users. - */ - atomic_inc(&page->_count); #else /* move offset up to the next cache line */ rx_buffer->page_offset += truesize; if (rx_buffer->page_offset > (PAGE_SIZE - IGB_RX_BUFSZ)) return false; - - /* bump ref count on page before it is given to the stack */ - get_page(page); #endif + /* Even if we own the page, we are not allowed to use atomic_set() + * This would break get_page_unless_zero() users. + */ + atomic_inc(&page->_count); + return true; } @@ -6603,13 +6656,12 @@ static bool igb_add_rx_frag(struct igb_ring *rx_ring, memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long))); - /* we can reuse buffer as-is, just make sure it is local */ - if (likely((page_to_nid(page) == numa_node_id()) && - !page->pfmemalloc)) + /* page is not reserved, we can reuse buffer as-is */ + if (likely(!igb_page_is_reserved(page))) return true; /* this page cannot be reused so discard it */ - put_page(page); + __free_page(page); return false; } @@ -6627,7 +6679,6 @@ static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring, struct page *page; rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean]; - page = rx_buffer->page; prefetchw(page); @@ -7042,8 +7093,8 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count) i -= rx_ring->count; } - /* clear the hdr_addr for the next_to_use descriptor */ - rx_desc->read.hdr_addr = 0; + /* clear the status bits for the next_to_use descriptor */ + rx_desc->wb.upper.status_error = 0; cleaned_count--; } while (cleaned_count); diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 794c139f0cc0..d20fc8ed11f1 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -256,14 +256,9 @@ static int igb_ptp_adjtime_82576(struct ptp_clock_info *ptp, s64 delta) struct igb_adapter *igb = container_of(ptp, struct igb_adapter, ptp_caps); unsigned long flags; - s64 now; spin_lock_irqsave(&igb->tmreg_lock, flags); - - now = timecounter_read(&igb->tc); - now += delta; - timecounter_init(&igb->tc, &igb->cc, now); - + timecounter_adjtime(&igb->tc, delta); spin_unlock_irqrestore(&igb->tmreg_lock, flags); return 0; @@ -360,12 +355,239 @@ static int igb_ptp_settime_i210(struct ptp_clock_info *ptp, return 0; } +static void igb_pin_direction(int pin, int input, u32 *ctrl, u32 *ctrl_ext) +{ + u32 *ptr = pin < 2 ? ctrl : ctrl_ext; + u32 mask[IGB_N_SDP] = { + E1000_CTRL_SDP0_DIR, + E1000_CTRL_SDP1_DIR, + E1000_CTRL_EXT_SDP2_DIR, + E1000_CTRL_EXT_SDP3_DIR, + }; + + if (input) + *ptr &= ~mask[pin]; + else + *ptr |= mask[pin]; +} + +static void igb_pin_extts(struct igb_adapter *igb, int chan, int pin) +{ + struct e1000_hw *hw = &igb->hw; + u32 aux0_sel_sdp[IGB_N_SDP] = { + AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3, + }; + u32 aux1_sel_sdp[IGB_N_SDP] = { + AUX1_SEL_SDP0, AUX1_SEL_SDP1, AUX1_SEL_SDP2, AUX1_SEL_SDP3, + }; + u32 ts_sdp_en[IGB_N_SDP] = { + TS_SDP0_EN, TS_SDP1_EN, TS_SDP2_EN, TS_SDP3_EN, + }; + u32 ctrl, ctrl_ext, tssdp = 0; + + ctrl = rd32(E1000_CTRL); + ctrl_ext = rd32(E1000_CTRL_EXT); + tssdp = rd32(E1000_TSSDP); + + igb_pin_direction(pin, 1, &ctrl, &ctrl_ext); + + /* Make sure this pin is not enabled as an output. */ + tssdp &= ~ts_sdp_en[pin]; + + if (chan == 1) { + tssdp &= ~AUX1_SEL_SDP3; + tssdp |= aux1_sel_sdp[pin] | AUX1_TS_SDP_EN; + } else { + tssdp &= ~AUX0_SEL_SDP3; + tssdp |= aux0_sel_sdp[pin] | AUX0_TS_SDP_EN; + } + + wr32(E1000_TSSDP, tssdp); + wr32(E1000_CTRL, ctrl); + wr32(E1000_CTRL_EXT, ctrl_ext); +} + +static void igb_pin_perout(struct igb_adapter *igb, int chan, int pin) +{ + struct e1000_hw *hw = &igb->hw; + u32 aux0_sel_sdp[IGB_N_SDP] = { + AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3, + }; + u32 aux1_sel_sdp[IGB_N_SDP] = { + AUX1_SEL_SDP0, AUX1_SEL_SDP1, AUX1_SEL_SDP2, AUX1_SEL_SDP3, + }; + u32 ts_sdp_en[IGB_N_SDP] = { + TS_SDP0_EN, TS_SDP1_EN, TS_SDP2_EN, TS_SDP3_EN, + }; + u32 ts_sdp_sel_tt0[IGB_N_SDP] = { + TS_SDP0_SEL_TT0, TS_SDP1_SEL_TT0, + TS_SDP2_SEL_TT0, TS_SDP3_SEL_TT0, + }; + u32 ts_sdp_sel_tt1[IGB_N_SDP] = { + TS_SDP0_SEL_TT1, TS_SDP1_SEL_TT1, + TS_SDP2_SEL_TT1, TS_SDP3_SEL_TT1, + }; + u32 ts_sdp_sel_clr[IGB_N_SDP] = { + TS_SDP0_SEL_FC1, TS_SDP1_SEL_FC1, + TS_SDP2_SEL_FC1, TS_SDP3_SEL_FC1, + }; + u32 ctrl, ctrl_ext, tssdp = 0; + + ctrl = rd32(E1000_CTRL); + ctrl_ext = rd32(E1000_CTRL_EXT); + tssdp = rd32(E1000_TSSDP); + + igb_pin_direction(pin, 0, &ctrl, &ctrl_ext); + + /* Make sure this pin is not enabled as an input. */ + if ((tssdp & AUX0_SEL_SDP3) == aux0_sel_sdp[pin]) + tssdp &= ~AUX0_TS_SDP_EN; + + if ((tssdp & AUX1_SEL_SDP3) == aux1_sel_sdp[pin]) + tssdp &= ~AUX1_TS_SDP_EN; + + tssdp &= ~ts_sdp_sel_clr[pin]; + if (chan == 1) + tssdp |= ts_sdp_sel_tt1[pin]; + else + tssdp |= ts_sdp_sel_tt0[pin]; + + tssdp |= ts_sdp_en[pin]; + + wr32(E1000_TSSDP, tssdp); + wr32(E1000_CTRL, ctrl); + wr32(E1000_CTRL_EXT, ctrl_ext); +} + +static int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct igb_adapter *igb = + container_of(ptp, struct igb_adapter, ptp_caps); + struct e1000_hw *hw = &igb->hw; + u32 tsauxc, tsim, tsauxc_mask, tsim_mask, trgttiml, trgttimh; + unsigned long flags; + struct timespec ts; + int pin; + s64 ns; + + switch (rq->type) { + case PTP_CLK_REQ_EXTTS: + if (on) { + pin = ptp_find_pin(igb->ptp_clock, PTP_PF_EXTTS, + rq->extts.index); + if (pin < 0) + return -EBUSY; + } + if (rq->extts.index == 1) { + tsauxc_mask = TSAUXC_EN_TS1; + tsim_mask = TSINTR_AUTT1; + } else { + tsauxc_mask = TSAUXC_EN_TS0; + tsim_mask = TSINTR_AUTT0; + } + spin_lock_irqsave(&igb->tmreg_lock, flags); + tsauxc = rd32(E1000_TSAUXC); + tsim = rd32(E1000_TSIM); + if (on) { + igb_pin_extts(igb, rq->extts.index, pin); + tsauxc |= tsauxc_mask; + tsim |= tsim_mask; + } else { + tsauxc &= ~tsauxc_mask; + tsim &= ~tsim_mask; + } + wr32(E1000_TSAUXC, tsauxc); + wr32(E1000_TSIM, tsim); + spin_unlock_irqrestore(&igb->tmreg_lock, flags); + return 0; + + case PTP_CLK_REQ_PEROUT: + if (on) { + pin = ptp_find_pin(igb->ptp_clock, PTP_PF_PEROUT, + rq->perout.index); + if (pin < 0) + return -EBUSY; + } + ts.tv_sec = rq->perout.period.sec; + ts.tv_nsec = rq->perout.period.nsec; + ns = timespec_to_ns(&ts); + ns = ns >> 1; + if (on && ns < 500000LL) { + /* 2k interrupts per second is an awful lot. */ + return -EINVAL; + } + ts = ns_to_timespec(ns); + if (rq->perout.index == 1) { + tsauxc_mask = TSAUXC_EN_TT1; + tsim_mask = TSINTR_TT1; + trgttiml = E1000_TRGTTIML1; + trgttimh = E1000_TRGTTIMH1; + } else { + tsauxc_mask = TSAUXC_EN_TT0; + tsim_mask = TSINTR_TT0; + trgttiml = E1000_TRGTTIML0; + trgttimh = E1000_TRGTTIMH0; + } + spin_lock_irqsave(&igb->tmreg_lock, flags); + tsauxc = rd32(E1000_TSAUXC); + tsim = rd32(E1000_TSIM); + if (on) { + int i = rq->perout.index; + + igb_pin_perout(igb, i, pin); + igb->perout[i].start.tv_sec = rq->perout.start.sec; + igb->perout[i].start.tv_nsec = rq->perout.start.nsec; + igb->perout[i].period.tv_sec = ts.tv_sec; + igb->perout[i].period.tv_nsec = ts.tv_nsec; + wr32(trgttiml, rq->perout.start.sec); + wr32(trgttimh, rq->perout.start.nsec); + tsauxc |= tsauxc_mask; + tsim |= tsim_mask; + } else { + tsauxc &= ~tsauxc_mask; + tsim &= ~tsim_mask; + } + wr32(E1000_TSAUXC, tsauxc); + wr32(E1000_TSIM, tsim); + spin_unlock_irqrestore(&igb->tmreg_lock, flags); + return 0; + + case PTP_CLK_REQ_PPS: + spin_lock_irqsave(&igb->tmreg_lock, flags); + tsim = rd32(E1000_TSIM); + if (on) + tsim |= TSINTR_SYS_WRAP; + else + tsim &= ~TSINTR_SYS_WRAP; + wr32(E1000_TSIM, tsim); + spin_unlock_irqrestore(&igb->tmreg_lock, flags); + return 0; + } + + return -EOPNOTSUPP; +} + static int igb_ptp_feature_enable(struct ptp_clock_info *ptp, struct ptp_clock_request *rq, int on) { return -EOPNOTSUPP; } +static int igb_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin, + enum ptp_pin_function func, unsigned int chan) +{ + switch (func) { + case PTP_PF_NONE: + case PTP_PF_EXTTS: + case PTP_PF_PEROUT: + break; + case PTP_PF_PHYSYNC: + return -1; + } + return 0; +} + /** * igb_ptp_tx_work * @work: pointer to work struct @@ -756,6 +978,7 @@ void igb_ptp_init(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; + int i; switch (hw->mac.type) { case e1000_82576: @@ -770,7 +993,7 @@ void igb_ptp_init(struct igb_adapter *adapter) adapter->ptp_caps.settime = igb_ptp_settime_82576; adapter->ptp_caps.enable = igb_ptp_feature_enable; adapter->cc.read = igb_ptp_read_82576; - adapter->cc.mask = CLOCKSOURCE_MASK(64); + adapter->cc.mask = CYCLECOUNTER_MASK(64); adapter->cc.mult = 1; adapter->cc.shift = IGB_82576_TSYNC_SHIFT; /* Dial the nominal frequency. */ @@ -790,7 +1013,7 @@ void igb_ptp_init(struct igb_adapter *adapter) adapter->ptp_caps.settime = igb_ptp_settime_82576; adapter->ptp_caps.enable = igb_ptp_feature_enable; adapter->cc.read = igb_ptp_read_82580; - adapter->cc.mask = CLOCKSOURCE_MASK(IGB_NBITS_82580); + adapter->cc.mask = CYCLECOUNTER_MASK(IGB_NBITS_82580); adapter->cc.mult = 1; adapter->cc.shift = 0; /* Enable the timer functions by clearing bit 31. */ @@ -798,16 +1021,27 @@ void igb_ptp_init(struct igb_adapter *adapter) break; case e1000_i210: case e1000_i211: + for (i = 0; i < IGB_N_SDP; i++) { + struct ptp_pin_desc *ppd = &adapter->sdp_config[i]; + + snprintf(ppd->name, sizeof(ppd->name), "SDP%d", i); + ppd->index = i; + ppd->func = PTP_PF_NONE; + } snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); adapter->ptp_caps.owner = THIS_MODULE; adapter->ptp_caps.max_adj = 62499999; - adapter->ptp_caps.n_ext_ts = 0; - adapter->ptp_caps.pps = 0; + adapter->ptp_caps.n_ext_ts = IGB_N_EXTTS; + adapter->ptp_caps.n_per_out = IGB_N_PEROUT; + adapter->ptp_caps.n_pins = IGB_N_SDP; + adapter->ptp_caps.pps = 1; + adapter->ptp_caps.pin_config = adapter->sdp_config; adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580; adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210; adapter->ptp_caps.gettime = igb_ptp_gettime_i210; adapter->ptp_caps.settime = igb_ptp_settime_i210; - adapter->ptp_caps.enable = igb_ptp_feature_enable; + adapter->ptp_caps.enable = igb_ptp_feature_enable_i210; + adapter->ptp_caps.verify = igb_ptp_verify_pin; /* Enable the timer functions by clearing bit 31. */ wr32(E1000_TSAUXC, 0x0); break; @@ -905,6 +1139,7 @@ void igb_ptp_stop(struct igb_adapter *adapter) void igb_ptp_reset(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; + unsigned long flags; if (!(adapter->flags & IGB_FLAG_PTP)) return; @@ -912,6 +1147,8 @@ void igb_ptp_reset(struct igb_adapter *adapter) /* reset the tstamp_config */ igb_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config); + spin_lock_irqsave(&adapter->tmreg_lock, flags); + switch (adapter->hw.mac.type) { case e1000_82576: /* Dial the nominal frequency. */ @@ -922,23 +1159,25 @@ void igb_ptp_reset(struct igb_adapter *adapter) case e1000_i350: case e1000_i210: case e1000_i211: - /* Enable the timer functions and interrupts. */ wr32(E1000_TSAUXC, 0x0); + wr32(E1000_TSSDP, 0x0); wr32(E1000_TSIM, TSYNC_INTERRUPTS); wr32(E1000_IMS, E1000_IMS_TS); break; default: /* No work to do. */ - return; + goto out; } /* Re-initialize the timer. */ if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) { struct timespec ts = ktime_to_timespec(ktime_get_real()); - igb_ptp_settime_i210(&adapter->ptp_caps, &ts); + igb_ptp_write_i210(adapter, &ts); } else { timecounter_init(&adapter->tc, &adapter->cc, ktime_to_ns(ktime_get_real())); } +out: + spin_unlock_irqrestore(&adapter->tmreg_lock, flags); } diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index 63c807c9b21c..ebf9d4a42fdd 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -1907,7 +1907,8 @@ static void igbvf_watchdog_task(struct work_struct *work) static int igbvf_tso(struct igbvf_adapter *adapter, struct igbvf_ring *tx_ring, - struct sk_buff *skb, u32 tx_flags, u8 *hdr_len) + struct sk_buff *skb, u32 tx_flags, u8 *hdr_len, + __be16 protocol) { struct e1000_adv_tx_context_desc *context_desc; struct igbvf_buffer *buffer_info; @@ -1927,7 +1928,7 @@ static int igbvf_tso(struct igbvf_adapter *adapter, l4len = tcp_hdrlen(skb); *hdr_len += l4len; - if (skb->protocol == htons(ETH_P_IP)) { + if (protocol == htons(ETH_P_IP)) { struct iphdr *iph = ip_hdr(skb); iph->tot_len = 0; iph->check = 0; @@ -1958,7 +1959,7 @@ static int igbvf_tso(struct igbvf_adapter *adapter, /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT); - if (skb->protocol == htons(ETH_P_IP)) + if (protocol == htons(ETH_P_IP)) tu_cmd |= E1000_ADVTXD_TUCMD_IPV4; tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP; @@ -1984,7 +1985,8 @@ static int igbvf_tso(struct igbvf_adapter *adapter, static inline bool igbvf_tx_csum(struct igbvf_adapter *adapter, struct igbvf_ring *tx_ring, - struct sk_buff *skb, u32 tx_flags) + struct sk_buff *skb, u32 tx_flags, + __be16 protocol) { struct e1000_adv_tx_context_desc *context_desc; unsigned int i; @@ -2011,7 +2013,7 @@ static inline bool igbvf_tx_csum(struct igbvf_adapter *adapter, tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT); if (skb->ip_summed == CHECKSUM_PARTIAL) { - switch (skb->protocol) { + switch (protocol) { case htons(ETH_P_IP): tu_cmd |= E1000_ADVTXD_TUCMD_IPV4; if (ip_hdr(skb)->protocol == IPPROTO_TCP) @@ -2211,6 +2213,7 @@ static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb, u8 hdr_len = 0; int count = 0; int tso = 0; + __be16 protocol = vlan_get_protocol(skb); if (test_bit(__IGBVF_DOWN, &adapter->state)) { dev_kfree_skb_any(skb); @@ -2234,18 +2237,19 @@ static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb, return NETDEV_TX_BUSY; } - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { tx_flags |= IGBVF_TX_FLAGS_VLAN; - tx_flags |= (vlan_tx_tag_get(skb) << IGBVF_TX_FLAGS_VLAN_SHIFT); + tx_flags |= (skb_vlan_tag_get(skb) << + IGBVF_TX_FLAGS_VLAN_SHIFT); } - if (skb->protocol == htons(ETH_P_IP)) + if (protocol == htons(ETH_P_IP)) tx_flags |= IGBVF_TX_FLAGS_IPV4; first = tx_ring->next_to_use; tso = skb_is_gso(skb) ? - igbvf_tso(adapter, tx_ring, skb, tx_flags, &hdr_len) : 0; + igbvf_tso(adapter, tx_ring, skb, tx_flags, &hdr_len, protocol) : 0; if (unlikely(tso < 0)) { dev_kfree_skb_any(skb); return NETDEV_TX_OK; @@ -2253,7 +2257,7 @@ static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb, if (tso) tx_flags |= IGBVF_TX_FLAGS_TSO; - else if (igbvf_tx_csum(adapter, tx_ring, skb, tx_flags) && + else if (igbvf_tx_csum(adapter, tx_ring, skb, tx_flags, protocol) && (skb->ip_summed == CHECKSUM_PARTIAL)) tx_flags |= IGBVF_TX_FLAGS_CSUM; diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c index aa87605b144a..11a1bdbe3fd9 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c @@ -1532,9 +1532,9 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) DESC_NEEDED))) return NETDEV_TX_BUSY; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { tx_flags |= IXGB_TX_FLAGS_VLAN; - vlan_id = vlan_tx_tag_get(skb); + vlan_id = skb_vlan_tag_get(skb); } first = adapter->tx_ring.next_to_use; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index b6137be43920..7dcbbec09a70 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include @@ -76,6 +76,8 @@ #define IXGBE_MAX_RXD 4096 #define IXGBE_MIN_RXD 64 +#define IXGBE_ETH_P_LLDP 0x88CC + /* flow control */ #define IXGBE_MIN_FCRTL 0x40 #define IXGBE_MAX_FCRTL 0x7FF80 @@ -753,6 +755,7 @@ struct ixgbe_adapter { u32 timer_event_accumulator; u32 vferr_refcount; struct ixgbe_mac_addr *mac_table; + u16 vxlan_port; struct kobject *info_kobj; #ifdef CONFIG_IXGBE_HWMON struct hwmon_buff *ixgbe_hwmon_buff; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 2ed2c7de2304..70cc4c5c0a01 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -50,6 +50,7 @@ #include #include #include +#include #ifdef CONFIG_OF #include @@ -1396,12 +1397,23 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring, union ixgbe_adv_rx_desc *rx_desc, struct sk_buff *skb) { + __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info; + __le16 hdr_info = rx_desc->wb.lower.lo_dword.hs_rss.hdr_info; + bool encap_pkt = false; + skb_checksum_none_assert(skb); /* Rx csum disabled */ if (!(ring->netdev->features & NETIF_F_RXCSUM)) return; + if ((pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_VXLAN)) && + (hdr_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_TUNNEL >> 16))) { + encap_pkt = true; + skb->encapsulation = 1; + skb->ip_summed = CHECKSUM_NONE; + } + /* if IP and error */ if (ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_IPCS) && ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_IPE)) { @@ -1413,8 +1425,6 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring, return; if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_TCPE)) { - __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info; - /* * 82599 errata, UDP frames with a 0 checksum can be marked as * checksum errors. @@ -1429,6 +1439,17 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring, /* It must be a TCP or UDP packet with a valid checksum */ skb->ip_summed = CHECKSUM_UNNECESSARY; + if (encap_pkt) { + if (!ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_OUTERIPCS)) + return; + + if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_OUTERIPER)) { + ring->rx_stats.csum_err++; + return; + } + /* If we checked the outer header let the stack know */ + skb->csum_level = 1; + } } static bool ixgbe_alloc_mapped_page(struct ixgbe_ring *rx_ring, @@ -3564,10 +3585,24 @@ static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter) /* Enable MAC Anti-Spoofing */ hw->mac.ops.set_mac_anti_spoofing(hw, (adapter->num_vfs != 0), adapter->num_vfs); + + /* Ensure LLDP is set for Ethertype Antispoofing if we will be + * calling set_ethertype_anti_spoofing for each VF in loop below + */ + if (hw->mac.ops.set_ethertype_anti_spoofing) + IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_LLDP), + (IXGBE_ETQF_FILTER_EN | /* enable filter */ + IXGBE_ETQF_TX_ANTISPOOF | /* tx antispoof */ + IXGBE_ETH_P_LLDP)); /* LLDP eth type */ + /* For VFs that have spoof checking turned off */ for (i = 0; i < adapter->num_vfs; i++) { if (!adapter->vfinfo[i].spoofchk_enabled) ixgbe_ndo_set_vf_spoofchk(adapter->netdev, i, false); + + /* enable ethertype anti spoofing if hw supports it */ + if (hw->mac.ops.set_ethertype_anti_spoofing) + hw->mac.ops.set_ethertype_anti_spoofing(hw, true, i); } } @@ -5627,6 +5662,10 @@ static int ixgbe_open(struct net_device *netdev) ixgbe_up_complete(adapter); +#if IS_ENABLED(CONFIG_IXGBE_VXLAN) + vxlan_get_rx_port(netdev); + +#endif return 0; err_set_queues: @@ -7217,8 +7256,8 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, first->gso_segs = 1; /* if we have a HW VLAN tag being added default to the HW one */ - if (vlan_tx_tag_present(skb)) { - tx_flags |= vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT; + if (skb_vlan_tag_present(skb)) { + tx_flags |= skb_vlan_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT; tx_flags |= IXGBE_TX_FLAGS_HW_VLAN; /* else if it is a SW VLAN check the next protocol and store the tag */ } else if (protocol == htons(ETH_P_8021Q)) { @@ -7227,11 +7266,11 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, if (!vhdr) goto out_drop; - protocol = vhdr->h_vlan_encapsulated_proto; tx_flags |= ntohs(vhdr->h_vlan_TCI) << IXGBE_TX_FLAGS_VLAN_SHIFT; tx_flags |= IXGBE_TX_FLAGS_SW_VLAN; } + protocol = vlan_get_protocol(skb); if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && adapter->ptp_clock && @@ -7771,6 +7810,64 @@ static int ixgbe_set_features(struct net_device *netdev, return 0; } +/** + * ixgbe_add_vxlan_port - Get notifications about VXLAN ports that come up + * @dev: The port's netdev + * @sa_family: Socket Family that VXLAN is notifiying us about + * @port: New UDP port number that VXLAN started listening to + **/ +static void ixgbe_add_vxlan_port(struct net_device *dev, sa_family_t sa_family, + __be16 port) +{ + struct ixgbe_adapter *adapter = netdev_priv(dev); + struct ixgbe_hw *hw = &adapter->hw; + u16 new_port = ntohs(port); + + if (sa_family == AF_INET6) + return; + + if (adapter->vxlan_port == new_port) { + netdev_info(dev, "Port %d already offloaded\n", new_port); + return; + } + + if (adapter->vxlan_port) { + netdev_info(dev, + "Hit Max num of UDP ports, not adding port %d\n", + new_port); + return; + } + + adapter->vxlan_port = new_port; + IXGBE_WRITE_REG(hw, IXGBE_VXLANCTRL, new_port); +} + +/** + * ixgbe_del_vxlan_port - Get notifications about VXLAN ports that go away + * @dev: The port's netdev + * @sa_family: Socket Family that VXLAN is notifying us about + * @port: UDP port number that VXLAN stopped listening to + **/ +static void ixgbe_del_vxlan_port(struct net_device *dev, sa_family_t sa_family, + __be16 port) +{ + struct ixgbe_adapter *adapter = netdev_priv(dev); + struct ixgbe_hw *hw = &adapter->hw; + u16 new_port = ntohs(port); + + if (sa_family == AF_INET6) + return; + + if (adapter->vxlan_port != new_port) { + netdev_info(dev, "Port %d was not found, not deleting\n", + new_port); + return; + } + + adapter->vxlan_port = 0; + IXGBE_WRITE_REG(hw, IXGBE_VXLANCTRL, 0); +} + static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, @@ -7786,7 +7883,7 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], } static int ixgbe_ndo_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh) + struct nlmsghdr *nlh, u16 flags) { struct ixgbe_adapter *adapter = netdev_priv(dev); struct nlattr *attr, *br_spec; @@ -7982,6 +8079,8 @@ static const struct net_device_ops ixgbe_netdev_ops = { .ndo_bridge_getlink = ixgbe_ndo_bridge_getlink, .ndo_dfwd_add_station = ixgbe_fwd_add, .ndo_dfwd_del_station = ixgbe_fwd_del, + .ndo_add_vxlan_port = ixgbe_add_vxlan_port, + .ndo_del_vxlan_port = ixgbe_del_vxlan_port, }; /** @@ -8339,6 +8438,15 @@ skip_sriov: netdev->priv_flags |= IFF_UNICAST_FLT; netdev->priv_flags |= IFF_SUPP_NOFCS; + switch (adapter->hw.mac.type) { + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: + netdev->hw_enc_features |= NETIF_F_RXCSUM; + break; + default: + break; + } + #ifdef CONFIG_IXGBE_DCB netdev->dcbnl_ops = &dcbnl_ops; #endif diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index 5fd4b5271f9a..79c00f57d3e7 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -261,18 +261,9 @@ static int ixgbe_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) struct ixgbe_adapter *adapter = container_of(ptp, struct ixgbe_adapter, ptp_caps); unsigned long flags; - u64 now; spin_lock_irqsave(&adapter->tmreg_lock, flags); - - now = timecounter_read(&adapter->tc); - now += delta; - - /* reset the timecounter */ - timecounter_init(&adapter->tc, - &adapter->cc, - now); - + timecounter_adjtime(&adapter->tc, delta); spin_unlock_irqrestore(&adapter->tmreg_lock, flags); ixgbe_ptp_setup_sdp(adapter); @@ -802,7 +793,7 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter) memset(&adapter->cc, 0, sizeof(adapter->cc)); adapter->cc.read = ixgbe_ptp_read; - adapter->cc.mask = CLOCKSOURCE_MASK(64); + adapter->cc.mask = CYCLECOUNTER_MASK(64); adapter->cc.shift = shift; adapter->cc.mult = 1; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index c76ba90ecc6e..7f37fe7269a7 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -101,9 +101,6 @@ static int __ixgbe_enable_sriov(struct ixgbe_adapter *adapter) adapter->dcb_cfg.num_tcs.pfc_tcs = 1; } - /* We do not support RSS w/ SR-IOV */ - adapter->ring_feature[RING_F_RSS].limit = 1; - /* Disable RSC when in SR-IOV mode */ adapter->flags2 &= ~(IXGBE_FLAG2_RSC_CAPABLE | IXGBE_FLAG2_RSC_ENABLED); @@ -1097,14 +1094,12 @@ static int ixgbe_enable_port_vlan(struct ixgbe_adapter *adapter, int vf, u16 vlan, u8 qos) { struct ixgbe_hw *hw = &adapter->hw; - int err = 0; + int err; - if (adapter->vfinfo[vf].pf_vlan) - err = ixgbe_set_vf_vlan(adapter, false, - adapter->vfinfo[vf].pf_vlan, - vf); + err = ixgbe_set_vf_vlan(adapter, true, vlan, vf); if (err) goto out; + ixgbe_set_vmvir(adapter, vlan, qos, vf); ixgbe_set_vmolr(hw, vf, false); if (adapter->vfinfo[vf].spoofchk_enabled) @@ -1143,6 +1138,11 @@ static int ixgbe_disable_port_vlan(struct ixgbe_adapter *adapter, int vf) hw->mac.ops.set_vlan_anti_spoofing(hw, false, vf); if (adapter->vfinfo[vf].vlan_count) adapter->vfinfo[vf].vlan_count--; + + /* disable hide VLAN on X550 */ + if (hw->mac.type >= ixgbe_mac_X550) + ixgbe_write_qde(adapter, vf, IXGBE_QDE_ENABLE); + adapter->vfinfo[vf].pf_vlan = 0; adapter->vfinfo[vf].pf_qos = 0; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index d101b25dc4b6..fc5ecee56ca8 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -378,6 +378,8 @@ struct ixgbe_thermal_sensor_data { #define IXGBE_SPOOF_MACAS_MASK 0xFF #define IXGBE_SPOOF_VLANAS_MASK 0xFF00 #define IXGBE_SPOOF_VLANAS_SHIFT 8 +#define IXGBE_SPOOF_ETHERTYPEAS 0xFF000000 +#define IXGBE_SPOOF_ETHERTYPEAS_SHIFT 16 #define IXGBE_PFVFSPOOF_REG_COUNT 8 #define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4)) /* 16 of these (0-15) */ @@ -399,6 +401,7 @@ struct ixgbe_thermal_sensor_data { #define IXGBE_WUPL 0x05900 #define IXGBE_WUPM 0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */ +#define IXGBE_VXLANCTRL 0x0000507C /* Rx filter VXLAN UDPPORT Register */ #define IXGBE_FHFT(_n) (0x09000 + ((_n) * 0x100)) /* Flex host filter table */ #define IXGBE_FHFT_EXT(_n) (0x09800 + ((_n) * 0x100)) /* Ext Flexible Host * Filter Table */ @@ -1540,6 +1543,7 @@ enum { #define IXGBE_MAX_ETQF_FILTERS 8 #define IXGBE_ETQF_FCOE 0x08000000 /* bit 27 */ #define IXGBE_ETQF_BCN 0x10000000 /* bit 28 */ +#define IXGBE_ETQF_TX_ANTISPOOF 0x20000000 /* bit 29 */ #define IXGBE_ETQF_1588 0x40000000 /* bit 30 */ #define IXGBE_ETQF_FILTER_EN 0x80000000 /* bit 31 */ #define IXGBE_ETQF_POOL_ENABLE (1 << 26) /* bit 26 */ @@ -1565,6 +1569,9 @@ enum { #define IXGBE_ETQF_FILTER_FCOE 2 #define IXGBE_ETQF_FILTER_1588 3 #define IXGBE_ETQF_FILTER_FIP 4 +#define IXGBE_ETQF_FILTER_LLDP 5 +#define IXGBE_ETQF_FILTER_LACP 6 + /* VLAN Control Bit Masks */ #define IXGBE_VLNCTRL_VET 0x0000FFFF /* bits 0-15 */ #define IXGBE_VLNCTRL_CFI 0x10000000 /* bit 28 */ @@ -2122,6 +2129,7 @@ enum { #define IXGBE_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ #define IXGBE_RXD_STAT_PIF 0x80 /* passed in-exact filter */ #define IXGBE_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */ +#define IXGBE_RXD_STAT_OUTERIPCS 0x100 /* Cloud IP xsum calculated */ #define IXGBE_RXD_STAT_VEXT 0x200 /* 1st VLAN found */ #define IXGBE_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */ #define IXGBE_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */ @@ -2139,6 +2147,7 @@ enum { #define IXGBE_RXD_ERR_IPE 0x80 /* IP Checksum Error */ #define IXGBE_RXDADV_ERR_MASK 0xfff00000 /* RDESC.ERRORS mask */ #define IXGBE_RXDADV_ERR_SHIFT 20 /* RDESC.ERRORS shift */ +#define IXGBE_RXDADV_ERR_OUTERIPER 0x04000000 /* CRC IP Header error */ #define IXGBE_RXDADV_ERR_FCEOFE 0x80000000 /* FCoEFe/IPE */ #define IXGBE_RXDADV_ERR_FCERR 0x00700000 /* FCERR/FDIRERR */ #define IXGBE_RXDADV_ERR_FDIR_LEN 0x00100000 /* FDIR Length error */ @@ -2227,6 +2236,8 @@ enum { #define IXGBE_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */ #define IXGBE_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */ #define IXGBE_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */ +#define IXGBE_RXDADV_PKTTYPE_VXLAN 0x00000800 /* VXLAN hdr present */ +#define IXGBE_RXDADV_PKTTYPE_TUNNEL 0x00010000 /* Tunnel type */ #define IXGBE_RXDADV_PKTTYPE_IPSEC_ESP 0x00001000 /* IPSec ESP */ #define IXGBE_RXDADV_PKTTYPE_IPSEC_AH 0x00002000 /* IPSec AH */ #define IXGBE_RXDADV_PKTTYPE_LINKSEC 0x00004000 /* LinkSec Encap */ @@ -3056,6 +3067,7 @@ struct ixgbe_mac_operations { s32 (*set_fw_drv_ver)(struct ixgbe_hw *, u8, u8, u8, u8); s32 (*get_thermal_sensor_data)(struct ixgbe_hw *); s32 (*init_thermal_sensor_thresh)(struct ixgbe_hw *hw); + void (*set_ethertype_anti_spoofing)(struct ixgbe_hw *, bool, int); /* DMA Coalescing */ s32 (*dmac_config)(struct ixgbe_hw *hw); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index ba54ff07b438..49395420c9b3 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -55,9 +55,6 @@ s32 ixgbe_get_invariants_X540(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; - /* Call PHY identify routine to get the phy type */ - ixgbe_identify_phy_generic(hw); - mac->mcft_size = IXGBE_X540_MC_TBL_SIZE; mac->vft_size = IXGBE_X540_VFT_TBL_SIZE; mac->num_rar_entries = IXGBE_X540_RAR_ENTRIES; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index ffdd1231f419..50bf81908dd6 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -80,7 +80,7 @@ static s32 ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr, * Initializes the EEPROM parameters ixgbe_eeprom_info within the * ixgbe_hw struct in order to set up EEPROM access. **/ -s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw) +static s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw) { struct ixgbe_eeprom_info *eeprom = &hw->eeprom; u32 eec; @@ -110,8 +110,8 @@ s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw) * @device_type: 3 bit device type * @phy_data: Pointer to read data from the register **/ -s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, - u32 device_type, u32 *data) +static s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u32 *data) { u32 i, command, error; @@ -158,7 +158,8 @@ s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, * * Reads a 16 bit word from the EEPROM using the hostif. **/ -s32 ixgbe_read_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) +static s32 ixgbe_read_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, + u16 *data) { s32 status; struct ixgbe_hic_read_shadow_ram buffer; @@ -193,8 +194,8 @@ s32 ixgbe_read_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) * * Reads a 16 bit word(s) from the EEPROM using the hostif. **/ -s32 ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw, - u16 offset, u16 words, u16 *data) +static s32 ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw, + u16 offset, u16 words, u16 *data) { struct ixgbe_hic_read_shadow_ram buffer; u32 current_word = 0; @@ -331,7 +332,8 @@ static s32 ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, u16 ptr, * * Returns a negative error code on error, or the 16-bit checksum **/ -s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, u32 buffer_size) +static s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, + u32 buffer_size) { u16 eeprom_ptrs[IXGBE_EEPROM_LAST_WORD + 1]; u16 *local_buffer; @@ -407,7 +409,7 @@ s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, u32 buffer_size) * * Returns a negative error code on error, or the 16-bit checksum **/ -s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw) +static s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw) { return ixgbe_calc_checksum_X550(hw, NULL, 0); } @@ -419,7 +421,7 @@ s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw) * * Reads a 16 bit word from the EEPROM using the hostif. **/ -s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) +static s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) { s32 status = 0; @@ -440,7 +442,8 @@ s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data) * Performs checksum calculation and validates the EEPROM checksum. If the * caller does not need checksum_val, the value can be NULL. **/ -s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, u16 *checksum_val) +static s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, + u16 *checksum_val) { s32 status; u16 checksum; @@ -489,7 +492,8 @@ s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, u16 *checksum_val) * * Write a 16 bit word to the EEPROM using the hostif. **/ -s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 data) +static s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, + u16 data) { s32 status; struct ixgbe_hic_write_shadow_ram buffer; @@ -517,7 +521,7 @@ s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 data) * * Write a 16 bit word to the EEPROM using the hostif. **/ -s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data) +static s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data) { s32 status = 0; @@ -537,7 +541,7 @@ s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data) * * Issue a shadow RAM dump to FW to copy EEPROM from shadow RAM to the flash. **/ -s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw) +static s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw) { s32 status = 0; union ixgbe_hic_hdr2 buffer; @@ -560,7 +564,7 @@ s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw) * checksum and updates the EEPROM and instructs the hardware to update * the flash. **/ -s32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw) +static s32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw) { s32 status; u16 checksum = 0; @@ -600,8 +604,9 @@ s32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw) * * Write a 16 bit word(s) to the EEPROM using the hostif. **/ -s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw, - u16 offset, u16 words, u16 *data) +static s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw, + u16 offset, u16 words, + u16 *data) { s32 status = 0; u32 i = 0; @@ -630,7 +635,7 @@ s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw, /** ixgbe_init_mac_link_ops_X550em - init mac link function pointers * @hw: pointer to hardware structure **/ -void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw) +static void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; @@ -647,7 +652,7 @@ void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw) /** ixgbe_setup_sfp_modules_X550em - Setup SFP module * @hw: pointer to hardware structure */ -s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw) +static s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw) { bool setup_linear; u16 reg_slice, edc_mode; @@ -703,9 +708,9 @@ s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw) * @speed: pointer to link speed * @autoneg: true when autoneg or autotry is enabled **/ -s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw, - ixgbe_link_speed *speed, - bool *autoneg) +static s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *autoneg) { /* SFP */ if (hw->phy.media_type == ixgbe_media_type_fiber) { @@ -740,8 +745,8 @@ s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw, * @device_type: 3 bit device type * @data: Data to write to the register **/ -s32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, - u32 device_type, u32 data) +static s32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u32 data) { u32 i, command, error; @@ -904,7 +909,7 @@ static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed) * * Configures the integrated KX4 PHY. **/ -s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw) +static s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw) { s32 status; u32 reg_val; @@ -942,7 +947,7 @@ s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw) * * Configures the integrated KR PHY. **/ -s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw) +static s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw) { s32 status; u32 reg_val; @@ -987,7 +992,7 @@ s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw) * A return of a non-zero value indicates an error, and the base driver should * not report link up. **/ -s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw) +static s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw) { u32 status; u16 lasi, autoneg_status, speed; @@ -1049,7 +1054,7 @@ s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw) * set during init_shared_code because the PHY/SFP type was * not known. Perform the SFP init if necessary. **/ -s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) +static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) { struct ixgbe_phy_info *phy = &hw->phy; s32 ret_val; @@ -1102,7 +1107,7 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) * Returns the media type (fiber, copper, backplane) * */ -enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw) +static enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw) { enum ixgbe_media_type media_type; @@ -1129,7 +1134,7 @@ enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw) /** ixgbe_init_ext_t_x550em - Start (unstall) the external Base T PHY. ** @hw: pointer to hardware structure **/ -s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw) +static s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw) { u32 status; u16 reg; @@ -1202,7 +1207,7 @@ s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw) ** and clears all interrupts, perform a PHY reset, and perform a link (MAC) ** reset. **/ -s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw) +static s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw) { ixgbe_link_speed link_speed; s32 status; @@ -1295,6 +1300,28 @@ mac_reset_top: return status; } +/** ixgbe_set_ethertype_anti_spoofing_X550 - Enable/Disable Ethertype + * anti-spoofing + * @hw: pointer to hardware structure + * @enable: enable or disable switch for Ethertype anti-spoofing + * @vf: Virtual Function pool - VF Pool to set for Ethertype anti-spoofing + **/ +void ixgbe_set_ethertype_anti_spoofing_X550(struct ixgbe_hw *hw, bool enable, + int vf) +{ + int vf_target_reg = vf >> 3; + int vf_target_shift = vf % 8 + IXGBE_SPOOF_ETHERTYPEAS_SHIFT; + u32 pfvfspoof; + + pfvfspoof = IXGBE_READ_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg)); + if (enable) + pfvfspoof |= (1 << vf_target_shift); + else + pfvfspoof &= ~(1 << vf_target_shift); + + IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof); +} + #define X550_COMMON_MAC \ .init_hw = &ixgbe_init_hw_generic, \ .start_hw = &ixgbe_start_hw_X540, \ @@ -1329,6 +1356,8 @@ mac_reset_top: .init_uta_tables = &ixgbe_init_uta_tables_generic, \ .set_mac_anti_spoofing = &ixgbe_set_mac_anti_spoofing, \ .set_vlan_anti_spoofing = &ixgbe_set_vlan_anti_spoofing, \ + .set_ethertype_anti_spoofing = \ + &ixgbe_set_ethertype_anti_spoofing_X550, \ .acquire_swfw_sync = &ixgbe_acquire_swfw_sync_X540, \ .release_swfw_sync = &ixgbe_release_swfw_sync_X540, \ .disable_rx_buff = &ixgbe_disable_rx_buff_generic, \ @@ -1345,7 +1374,6 @@ static struct ixgbe_mac_operations mac_ops_X550 = { .get_san_mac_addr = &ixgbe_get_san_mac_addr_generic, .get_wwn_prefix = &ixgbe_get_wwn_prefix_generic, .setup_link = &ixgbe_setup_mac_link_X540, - .set_rxpba = &ixgbe_set_rxpba_generic, .get_link_capabilities = &ixgbe_get_copper_link_capabilities_generic, .setup_sfp = NULL, }; diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index 8c44ab25f3fa..3a9b356dff01 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -43,6 +43,13 @@ #define BP_EXTENDED_STATS #endif +#define IXGBE_MAX_TXD_PWR 14 +#define IXGBE_MAX_DATA_PER_TXD BIT(IXGBE_MAX_TXD_PWR) + +/* Tx Descriptors needed, worst case */ +#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IXGBE_MAX_DATA_PER_TXD) +#define DESC_NEEDED (MAX_SKB_FRAGS + 4) + /* wrapper around a pointer to a socket buffer, * so a DMA handle can be stored along with the buffer */ struct ixgbevf_tx_buffer { @@ -85,6 +92,18 @@ struct ixgbevf_rx_queue_stats { u64 csum_err; }; +enum ixgbevf_ring_state_t { + __IXGBEVF_TX_DETECT_HANG, + __IXGBEVF_HANG_CHECK_ARMED, +}; + +#define check_for_tx_hang(ring) \ + test_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state) +#define set_check_for_tx_hang(ring) \ + set_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state) +#define clear_check_for_tx_hang(ring) \ + clear_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state) + struct ixgbevf_ring { struct ixgbevf_ring *next; struct net_device *netdev; @@ -101,7 +120,7 @@ struct ixgbevf_ring { struct ixgbevf_tx_buffer *tx_buffer_info; struct ixgbevf_rx_buffer *rx_buffer_info; }; - + unsigned long state; struct ixgbevf_stats stats; struct u64_stats_sync syncp; union { @@ -124,6 +143,7 @@ struct ixgbevf_ring { #define MAX_RX_QUEUES IXGBE_VF_MAX_RX_QUEUES #define MAX_TX_QUEUES IXGBE_VF_MAX_TX_QUEUES +#define IXGBEVF_MAX_RSS_QUEUES 2 #define IXGBEVF_DEFAULT_TXD 1024 #define IXGBEVF_DEFAULT_RXD 512 @@ -347,8 +367,6 @@ struct ixgbevf_adapter { /* this field must be first, see ixgbevf_process_skb_fields */ unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; - struct timer_list watchdog_timer; - struct work_struct reset_task; struct ixgbevf_q_vector *q_vector[MAX_MSIX_Q_VECTORS]; /* Interrupt Throttle Rate */ @@ -378,8 +396,7 @@ struct ixgbevf_adapter { * thus the additional *_CAPABLE flags. */ u32 flags; -#define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1) - +#define IXGBEVF_FLAG_RESET_REQUESTED (u32)(1) #define IXGBEVF_FLAG_QUEUE_RESET_REQUESTED (u32)(1 << 2) struct msix_entry *msix_entries; @@ -415,9 +432,11 @@ struct ixgbevf_adapter { u32 link_speed; bool link_up; - spinlock_t mbx_lock; + struct timer_list service_timer; + struct work_struct service_task; - struct work_struct watchdog_task; + spinlock_t mbx_lock; + unsigned long last_reset; }; enum ixbgevf_state_t { @@ -426,7 +445,8 @@ enum ixbgevf_state_t { __IXGBEVF_DOWN, __IXGBEVF_DISABLED, __IXGBEVF_REMOVING, - __IXGBEVF_WORK_INIT, + __IXGBEVF_SERVICE_SCHED, + __IXGBEVF_SERVICE_INITED, }; enum ixgbevf_boards { diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 62a0d8e0f17d..4186981e562d 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -98,6 +98,23 @@ static int debug = -1; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +static void ixgbevf_service_event_schedule(struct ixgbevf_adapter *adapter) +{ + if (!test_bit(__IXGBEVF_DOWN, &adapter->state) && + !test_bit(__IXGBEVF_REMOVING, &adapter->state) && + !test_and_set_bit(__IXGBEVF_SERVICE_SCHED, &adapter->state)) + schedule_work(&adapter->service_task); +} + +static void ixgbevf_service_event_complete(struct ixgbevf_adapter *adapter) +{ + BUG_ON(!test_bit(__IXGBEVF_SERVICE_SCHED, &adapter->state)); + + /* flush memory to make sure state is correct before next watchdog */ + smp_mb__before_atomic(); + clear_bit(__IXGBEVF_SERVICE_SCHED, &adapter->state); +} + /* forward decls */ static void ixgbevf_queue_reset_subtask(struct ixgbevf_adapter *adapter); static void ixgbevf_set_itr(struct ixgbevf_q_vector *q_vector); @@ -111,8 +128,8 @@ static void ixgbevf_remove_adapter(struct ixgbe_hw *hw) return; hw->hw_addr = NULL; dev_err(&adapter->pdev->dev, "Adapter removed\n"); - if (test_bit(__IXGBEVF_WORK_INIT, &adapter->state)) - schedule_work(&adapter->watchdog_task); + if (test_bit(__IXGBEVF_SERVICE_INITED, &adapter->state)) + ixgbevf_service_event_schedule(adapter); } static void ixgbevf_check_remove(struct ixgbe_hw *hw, u32 reg) @@ -199,14 +216,72 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring, /* tx_buffer must be completely set up in the transmit path */ } -#define IXGBE_MAX_TXD_PWR 14 -#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR) +static u64 ixgbevf_get_tx_completed(struct ixgbevf_ring *ring) +{ + return ring->stats.packets; +} -/* Tx Descriptors needed, worst case */ -#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IXGBE_MAX_DATA_PER_TXD) -#define DESC_NEEDED (MAX_SKB_FRAGS + 4) +static u32 ixgbevf_get_tx_pending(struct ixgbevf_ring *ring) +{ + struct ixgbevf_adapter *adapter = netdev_priv(ring->netdev); + struct ixgbe_hw *hw = &adapter->hw; -static void ixgbevf_tx_timeout(struct net_device *netdev); + u32 head = IXGBE_READ_REG(hw, IXGBE_VFTDH(ring->reg_idx)); + u32 tail = IXGBE_READ_REG(hw, IXGBE_VFTDT(ring->reg_idx)); + + if (head != tail) + return (head < tail) ? + tail - head : (tail + ring->count - head); + + return 0; +} + +static inline bool ixgbevf_check_tx_hang(struct ixgbevf_ring *tx_ring) +{ + u32 tx_done = ixgbevf_get_tx_completed(tx_ring); + u32 tx_done_old = tx_ring->tx_stats.tx_done_old; + u32 tx_pending = ixgbevf_get_tx_pending(tx_ring); + + clear_check_for_tx_hang(tx_ring); + + /* Check for a hung queue, but be thorough. This verifies + * that a transmit has been completed since the previous + * check AND there is at least one packet pending. The + * ARMED bit is set to indicate a potential hang. + */ + if ((tx_done_old == tx_done) && tx_pending) { + /* make sure it is true for two checks in a row */ + return test_and_set_bit(__IXGBEVF_HANG_CHECK_ARMED, + &tx_ring->state); + } + /* reset the countdown */ + clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &tx_ring->state); + + /* update completed stats and continue */ + tx_ring->tx_stats.tx_done_old = tx_done; + + return false; +} + +static void ixgbevf_tx_timeout_reset(struct ixgbevf_adapter *adapter) +{ + /* Do the reset outside of interrupt context */ + if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) { + adapter->flags |= IXGBEVF_FLAG_RESET_REQUESTED; + ixgbevf_service_event_schedule(adapter); + } +} + +/** + * ixgbevf_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + **/ +static void ixgbevf_tx_timeout(struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + + ixgbevf_tx_timeout_reset(adapter); +} /** * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes @@ -311,6 +386,37 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector, q_vector->tx.total_bytes += total_bytes; q_vector->tx.total_packets += total_packets; + if (check_for_tx_hang(tx_ring) && ixgbevf_check_tx_hang(tx_ring)) { + struct ixgbe_hw *hw = &adapter->hw; + union ixgbe_adv_tx_desc *eop_desc; + + eop_desc = tx_ring->tx_buffer_info[i].next_to_watch; + + pr_err("Detected Tx Unit Hang\n" + " Tx Queue <%d>\n" + " TDH, TDT <%x>, <%x>\n" + " next_to_use <%x>\n" + " next_to_clean <%x>\n" + "tx_buffer_info[next_to_clean]\n" + " next_to_watch <%p>\n" + " eop_desc->wb.status <%x>\n" + " time_stamp <%lx>\n" + " jiffies <%lx>\n", + tx_ring->queue_index, + IXGBE_READ_REG(hw, IXGBE_VFTDH(tx_ring->reg_idx)), + IXGBE_READ_REG(hw, IXGBE_VFTDT(tx_ring->reg_idx)), + tx_ring->next_to_use, i, + eop_desc, (eop_desc ? eop_desc->wb.status : 0), + tx_ring->tx_buffer_info[i].time_stamp, jiffies); + + netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index); + + /* schedule immediate reset if we believe we hung */ + ixgbevf_tx_timeout_reset(adapter); + + return true; + } + #define TX_WAKE_THRESHOLD (DESC_NEEDED * 2) if (unlikely(total_packets && netif_carrier_ok(tx_ring->netdev) && (ixgbevf_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD))) { @@ -1158,9 +1264,7 @@ static irqreturn_t ixgbevf_msix_other(int irq, void *data) hw->mac.get_link_status = 1; - if (!test_bit(__IXGBEVF_DOWN, &adapter->state) && - !test_bit(__IXGBEVF_REMOVING, &adapter->state)) - mod_timer(&adapter->watchdog_timer, jiffies); + ixgbevf_service_event_schedule(adapter); IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, adapter->eims_other); @@ -1479,6 +1583,8 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter, txdctl |= (1 << 8) | /* HTHRESH = 1 */ 32; /* PTHRESH = 32 */ + clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state); + IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl); /* poll to verify queue is enabled */ @@ -1584,6 +1690,39 @@ static void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter, reg_idx); } +static void ixgbevf_setup_vfmrqc(struct ixgbevf_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 vfmrqc = 0, vfreta = 0; + u32 rss_key[10]; + u16 rss_i = adapter->num_rx_queues; + int i, j; + + /* Fill out hash function seeds */ + netdev_rss_key_fill(rss_key, sizeof(rss_key)); + for (i = 0; i < 10; i++) + IXGBE_WRITE_REG(hw, IXGBE_VFRSSRK(i), rss_key[i]); + + /* Fill out redirection table */ + for (i = 0, j = 0; i < 64; i++, j++) { + if (j == rss_i) + j = 0; + vfreta = (vfreta << 8) | (j * 0x1); + if ((i & 3) == 3) + IXGBE_WRITE_REG(hw, IXGBE_VFRETA(i >> 2), vfreta); + } + + /* Perform hash on these packet types */ + vfmrqc |= IXGBE_VFMRQC_RSS_FIELD_IPV4 | + IXGBE_VFMRQC_RSS_FIELD_IPV4_TCP | + IXGBE_VFMRQC_RSS_FIELD_IPV6 | + IXGBE_VFMRQC_RSS_FIELD_IPV6_TCP; + + vfmrqc |= IXGBE_VFMRQC_RSSEN; + + IXGBE_WRITE_REG(hw, IXGBE_VFMRQC, vfmrqc); +} + static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter, struct ixgbevf_ring *ring) { @@ -1640,6 +1779,8 @@ static void ixgbevf_configure_rx(struct ixgbevf_adapter *adapter) struct net_device *netdev = adapter->netdev; ixgbevf_setup_psrtype(adapter); + if (hw->mac.type >= ixgbe_mac_X550_vf) + ixgbevf_setup_vfmrqc(adapter); /* notify the PF of our intent to use this size of frame */ ixgbevf_rlpml_set_vf(hw, netdev->mtu + ETH_HLEN + ETH_FCS_LEN); @@ -1794,7 +1935,8 @@ static int ixgbevf_configure_dcb(struct ixgbevf_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; unsigned int def_q = 0; unsigned int num_tcs = 0; - unsigned int num_rx_queues = 1; + unsigned int num_rx_queues = adapter->num_rx_queues; + unsigned int num_tx_queues = adapter->num_tx_queues; int err; spin_lock_bh(&adapter->mbx_lock); @@ -1808,6 +1950,9 @@ static int ixgbevf_configure_dcb(struct ixgbevf_adapter *adapter) return err; if (num_tcs > 1) { + /* we need only one Tx queue */ + num_tx_queues = 1; + /* update default Tx ring register index */ adapter->tx_ring[0]->reg_idx = def_q; @@ -1816,7 +1961,8 @@ static int ixgbevf_configure_dcb(struct ixgbevf_adapter *adapter) } /* if we have a bad config abort request queue reset */ - if (adapter->num_rx_queues != num_rx_queues) { + if ((adapter->num_rx_queues != num_rx_queues) || + (adapter->num_tx_queues != num_tx_queues)) { /* force mailbox timeout to prevent further messages */ hw->mbx.timeout = 0; @@ -1917,6 +2063,10 @@ static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter) clear_bit(__IXGBEVF_DOWN, &adapter->state); ixgbevf_napi_enable_all(adapter); + /* clear any pending interrupts, may auto mask */ + IXGBE_READ_REG(hw, IXGBE_VTEICR); + ixgbevf_irq_enable(adapter); + /* enable transmits */ netif_tx_start_all_queues(netdev); @@ -1924,21 +2074,14 @@ static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter) ixgbevf_init_last_counter_stats(adapter); hw->mac.get_link_status = 1; - mod_timer(&adapter->watchdog_timer, jiffies); + mod_timer(&adapter->service_timer, jiffies); } void ixgbevf_up(struct ixgbevf_adapter *adapter) { - struct ixgbe_hw *hw = &adapter->hw; - ixgbevf_configure(adapter); ixgbevf_up_complete(adapter); - - /* clear any pending interrupts, may auto mask */ - IXGBE_READ_REG(hw, IXGBE_VTEICR); - - ixgbevf_irq_enable(adapter); } /** @@ -2045,22 +2188,19 @@ void ixgbevf_down(struct ixgbevf_adapter *adapter) for (i = 0; i < adapter->num_rx_queues; i++) ixgbevf_disable_rx_queue(adapter, adapter->rx_ring[i]); - netif_tx_disable(netdev); - - msleep(10); + 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); + ixgbevf_irq_disable(adapter); ixgbevf_napi_disable_all(adapter); - del_timer_sync(&adapter->watchdog_timer); - /* can't call flush scheduled work here because it can deadlock - * if linkwatch_event tries to acquire the rtnl_lock which we are - * holding */ - while (adapter->flags & IXGBE_FLAG_IN_WATCHDOG_TASK) - msleep(1); + del_timer_sync(&adapter->service_timer); /* disable transmits in the hardware now that interrupts are off */ for (i = 0; i < adapter->num_tx_queues; i++) { @@ -2070,8 +2210,6 @@ void ixgbevf_down(struct ixgbevf_adapter *adapter) IXGBE_TXDCTL_SWFLSH); } - netif_carrier_off(netdev); - if (!pci_channel_offline(adapter->pdev)) ixgbevf_reset(adapter); @@ -2110,6 +2248,8 @@ void ixgbevf_reset(struct ixgbevf_adapter *adapter) memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len); } + + adapter->last_reset = jiffies; } static int ixgbevf_acquire_msix_vectors(struct ixgbevf_adapter *adapter, @@ -2181,8 +2321,19 @@ static void ixgbevf_set_num_queues(struct ixgbevf_adapter *adapter) return; /* we need as many queues as traffic classes */ - if (num_tcs > 1) + if (num_tcs > 1) { adapter->num_rx_queues = num_tcs; + } else { + u16 rss = min_t(u16, num_online_cpus(), IXGBEVF_MAX_RSS_QUEUES); + + switch (hw->api_version) { + case ixgbe_mbox_api_11: + adapter->num_rx_queues = rss; + adapter->num_tx_queues = rss; + default: + break; + } + } } /** @@ -2552,7 +2703,8 @@ void ixgbevf_update_stats(struct ixgbevf_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; int i; - if (!adapter->link_up) + if (test_bit(__IXGBEVF_DOWN, &adapter->state) || + test_bit(__IXGBEVF_RESETTING, &adapter->state)) return; UPDATE_VF_COUNTER_32bit(IXGBE_VFGPRC, adapter->stats.last_vfgprc, @@ -2576,57 +2728,28 @@ void ixgbevf_update_stats(struct ixgbevf_adapter *adapter) } /** - * ixgbevf_watchdog - Timer Call-back + * ixgbevf_service_timer - Timer Call-back * @data: pointer to adapter cast into an unsigned long **/ -static void ixgbevf_watchdog(unsigned long data) +static void ixgbevf_service_timer(unsigned long data) { struct ixgbevf_adapter *adapter = (struct ixgbevf_adapter *)data; - struct ixgbe_hw *hw = &adapter->hw; - u32 eics = 0; - int i; - /* - * Do the watchdog outside of interrupt context due to the lovely - * delays that some of the newer hardware requires - */ + /* Reset the timer */ + mod_timer(&adapter->service_timer, (HZ * 2) + jiffies); - if (test_bit(__IXGBEVF_DOWN, &adapter->state)) - goto watchdog_short_circuit; - - /* get one bit for every active tx/rx interrupt vector */ - for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { - struct ixgbevf_q_vector *qv = adapter->q_vector[i]; - if (qv->rx.ring || qv->tx.ring) - eics |= 1 << i; - } - - IXGBE_WRITE_REG(hw, IXGBE_VTEICS, eics); - -watchdog_short_circuit: - schedule_work(&adapter->watchdog_task); + ixgbevf_service_event_schedule(adapter); } -/** - * ixgbevf_tx_timeout - Respond to a Tx Hang - * @netdev: network interface device structure - **/ -static void ixgbevf_tx_timeout(struct net_device *netdev) +static void ixgbevf_reset_subtask(struct ixgbevf_adapter *adapter) { - struct ixgbevf_adapter *adapter = netdev_priv(netdev); + if (!(adapter->flags & IXGBEVF_FLAG_RESET_REQUESTED)) + return; - /* Do the reset outside of interrupt context */ - schedule_work(&adapter->reset_task); -} - -static void ixgbevf_reset_task(struct work_struct *work) -{ - struct ixgbevf_adapter *adapter; - adapter = container_of(work, struct ixgbevf_adapter, reset_task); + adapter->flags &= ~IXGBEVF_FLAG_RESET_REQUESTED; /* If we're already down or resetting, just bail */ if (test_bit(__IXGBEVF_DOWN, &adapter->state) || - test_bit(__IXGBEVF_REMOVING, &adapter->state) || test_bit(__IXGBEVF_RESETTING, &adapter->state)) return; @@ -2635,20 +2758,146 @@ static void ixgbevf_reset_task(struct work_struct *work) ixgbevf_reinit_locked(adapter); } -/** - * ixgbevf_watchdog_task - worker thread to bring link up - * @work: pointer to work_struct containing our data - **/ -static void ixgbevf_watchdog_task(struct work_struct *work) +/* ixgbevf_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 occurring. Secondly it sets the + * bits needed to check for TX hangs. As a result we should immediately + * determine if a hang has occurred. + */ +static void ixgbevf_check_hang_subtask(struct ixgbevf_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 eics = 0; + int i; + + /* If we're down or resetting, just bail */ + if (test_bit(__IXGBEVF_DOWN, &adapter->state) || + test_bit(__IXGBEVF_RESETTING, &adapter->state)) + return; + + /* 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]); + } + + /* get one bit for every active tx/rx interrupt vector */ + for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { + struct ixgbevf_q_vector *qv = adapter->q_vector[i]; + + if (qv->rx.ring || qv->tx.ring) + eics |= 1 << i; + } + + /* Cause software interrupt to ensure rings are cleaned */ + IXGBE_WRITE_REG(hw, IXGBE_VTEICS, eics); +} + +/** + * ixgbevf_watchdog_update_link - update the link status + * @adapter - pointer to the device adapter structure + **/ +static void ixgbevf_watchdog_update_link(struct ixgbevf_adapter *adapter) { - struct ixgbevf_adapter *adapter = container_of(work, - struct ixgbevf_adapter, - watchdog_task); - struct net_device *netdev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; u32 link_speed = adapter->link_speed; bool link_up = adapter->link_up; - s32 need_reset; + s32 err; + + spin_lock_bh(&adapter->mbx_lock); + + err = hw->mac.ops.check_link(hw, &link_speed, &link_up, false); + + spin_unlock_bh(&adapter->mbx_lock); + + /* if check for link returns error we will need to reset */ + if (err && time_after(jiffies, adapter->last_reset + (10 * HZ))) { + adapter->flags |= IXGBEVF_FLAG_RESET_REQUESTED; + link_up = false; + } + + adapter->link_up = link_up; + adapter->link_speed = link_speed; +} + +/** + * ixgbevf_watchdog_link_is_up - update netif_carrier status and + * print link up message + * @adapter - pointer to the device adapter structure + **/ +static void ixgbevf_watchdog_link_is_up(struct ixgbevf_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + /* only continue if link was previously down */ + if (netif_carrier_ok(netdev)) + return; + + dev_info(&adapter->pdev->dev, "NIC Link is Up %s\n", + (adapter->link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? + "10 Gbps" : + (adapter->link_speed == IXGBE_LINK_SPEED_1GB_FULL) ? + "1 Gbps" : + (adapter->link_speed == IXGBE_LINK_SPEED_100_FULL) ? + "100 Mbps" : + "unknown speed"); + + netif_carrier_on(netdev); +} + +/** + * ixgbevf_watchdog_link_is_down - update netif_carrier status and + * print link down message + * @adapter - pointer to the adapter structure + **/ +static void ixgbevf_watchdog_link_is_down(struct ixgbevf_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + adapter->link_speed = 0; + + /* only continue if link was up previously */ + if (!netif_carrier_ok(netdev)) + return; + + dev_info(&adapter->pdev->dev, "NIC Link is Down\n"); + + netif_carrier_off(netdev); +} + +/** + * ixgbevf_watchdog_subtask - worker thread to bring link up + * @work: pointer to work_struct containing our data + **/ +static void ixgbevf_watchdog_subtask(struct ixgbevf_adapter *adapter) +{ + /* if interface is down do nothing */ + if (test_bit(__IXGBEVF_DOWN, &adapter->state) || + test_bit(__IXGBEVF_RESETTING, &adapter->state)) + return; + + ixgbevf_watchdog_update_link(adapter); + + if (adapter->link_up) + ixgbevf_watchdog_link_is_up(adapter); + else + ixgbevf_watchdog_link_is_down(adapter); + + ixgbevf_update_stats(adapter); +} + +/** + * ixgbevf_service_task - manages and runs subtasks + * @work: pointer to work_struct containing our data + **/ +static void ixgbevf_service_task(struct work_struct *work) +{ + struct ixgbevf_adapter *adapter = container_of(work, + struct ixgbevf_adapter, + service_task); + struct ixgbe_hw *hw = &adapter->hw; if (IXGBE_REMOVED(hw->hw_addr)) { if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) { @@ -2658,73 +2907,13 @@ static void ixgbevf_watchdog_task(struct work_struct *work) } return; } + ixgbevf_queue_reset_subtask(adapter); + ixgbevf_reset_subtask(adapter); + ixgbevf_watchdog_subtask(adapter); + ixgbevf_check_hang_subtask(adapter); - adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; - - /* - * Always check the link on the watchdog because we have - * no LSC interrupt - */ - spin_lock_bh(&adapter->mbx_lock); - - need_reset = hw->mac.ops.check_link(hw, &link_speed, &link_up, false); - - spin_unlock_bh(&adapter->mbx_lock); - - if (need_reset) { - adapter->link_up = link_up; - adapter->link_speed = link_speed; - netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); - schedule_work(&adapter->reset_task); - goto pf_has_reset; - } - adapter->link_up = link_up; - adapter->link_speed = link_speed; - - if (link_up) { - if (!netif_carrier_ok(netdev)) { - char *link_speed_string; - switch (link_speed) { - case IXGBE_LINK_SPEED_10GB_FULL: - link_speed_string = "10 Gbps"; - break; - case IXGBE_LINK_SPEED_1GB_FULL: - link_speed_string = "1 Gbps"; - break; - case IXGBE_LINK_SPEED_100_FULL: - link_speed_string = "100 Mbps"; - break; - default: - link_speed_string = "unknown speed"; - break; - } - dev_info(&adapter->pdev->dev, - "NIC Link is Up, %s\n", link_speed_string); - netif_carrier_on(netdev); - netif_tx_wake_all_queues(netdev); - } - } else { - adapter->link_up = false; - adapter->link_speed = 0; - if (netif_carrier_ok(netdev)) { - dev_info(&adapter->pdev->dev, "NIC Link is Down\n"); - netif_carrier_off(netdev); - netif_tx_stop_all_queues(netdev); - } - } - - ixgbevf_update_stats(adapter); - -pf_has_reset: - /* Reset the timer */ - if (!test_bit(__IXGBEVF_DOWN, &adapter->state) && - !test_bit(__IXGBEVF_REMOVING, &adapter->state)) - mod_timer(&adapter->watchdog_timer, - round_jiffies(jiffies + (2 * HZ))); - - adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK; + ixgbevf_service_event_complete(adapter); } /** @@ -2944,10 +3133,6 @@ static int ixgbevf_open(struct net_device *netdev) if (!adapter->num_msix_vectors) return -ENOMEM; - /* disallow open during test */ - if (test_bit(__IXGBEVF_TESTING, &adapter->state)) - return -EBUSY; - if (hw->adapter_stopped) { ixgbevf_reset(adapter); /* if adapter is still stopped then PF isn't up and @@ -2960,6 +3145,12 @@ static int ixgbevf_open(struct net_device *netdev) } } + /* disallow open during test */ + if (test_bit(__IXGBEVF_TESTING, &adapter->state)) + return -EBUSY; + + netif_carrier_off(netdev); + /* allocate transmit descriptors */ err = ixgbevf_setup_all_tx_resources(adapter); if (err) @@ -2979,15 +3170,11 @@ static int ixgbevf_open(struct net_device *netdev) */ ixgbevf_map_rings_to_vectors(adapter); - ixgbevf_up_complete(adapter); - - /* clear any pending interrupts, may auto mask */ - IXGBE_READ_REG(hw, IXGBE_VTEICR); err = ixgbevf_request_irq(adapter); if (err) goto err_req_irq; - ixgbevf_irq_enable(adapter); + ixgbevf_up_complete(adapter); return 0; @@ -3099,7 +3286,7 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring, /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_TCP; - if (skb->protocol == htons(ETH_P_IP)) { + if (first->protocol == htons(ETH_P_IP)) { struct iphdr *iph = ip_hdr(skb); iph->tot_len = 0; iph->check = 0; @@ -3156,7 +3343,7 @@ static void ixgbevf_tx_csum(struct ixgbevf_ring *tx_ring, if (skb->ip_summed == CHECKSUM_PARTIAL) { u8 l4_hdr = 0; - switch (skb->protocol) { + switch (first->protocol) { case htons(ETH_P_IP): vlan_macip_lens |= skb_network_header_len(skb); type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4; @@ -3452,8 +3639,8 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) first->bytecount = skb->len; first->gso_segs = 1; - if (vlan_tx_tag_present(skb)) { - tx_flags |= vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) { + tx_flags |= skb_vlan_tag_get(skb); tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; tx_flags |= IXGBE_TX_FLAGS_VLAN; } @@ -3822,28 +4009,28 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER; - netdev->vlan_features |= NETIF_F_TSO; - netdev->vlan_features |= NETIF_F_TSO6; - netdev->vlan_features |= NETIF_F_IP_CSUM; - netdev->vlan_features |= NETIF_F_IPV6_CSUM; - netdev->vlan_features |= NETIF_F_SG; + netdev->vlan_features |= NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM | + NETIF_F_SG; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; netdev->priv_flags |= IFF_UNICAST_FLT; - init_timer(&adapter->watchdog_timer); - adapter->watchdog_timer.function = ixgbevf_watchdog; - adapter->watchdog_timer.data = (unsigned long)adapter; - if (IXGBE_REMOVED(hw->hw_addr)) { err = -EIO; goto err_sw_init; } - INIT_WORK(&adapter->reset_task, ixgbevf_reset_task); - INIT_WORK(&adapter->watchdog_task, ixgbevf_watchdog_task); - set_bit(__IXGBEVF_WORK_INIT, &adapter->state); + + setup_timer(&adapter->service_timer, &ixgbevf_service_timer, + (unsigned long)adapter); + + INIT_WORK(&adapter->service_task, ixgbevf_service_task); + set_bit(__IXGBEVF_SERVICE_INITED, &adapter->state); + clear_bit(__IXGBEVF_SERVICE_SCHED, &adapter->state); err = ixgbevf_init_interrupt_scheme(adapter); if (err) @@ -3917,11 +4104,7 @@ static void ixgbevf_remove(struct pci_dev *pdev) adapter = netdev_priv(netdev); set_bit(__IXGBEVF_REMOVING, &adapter->state); - - del_timer_sync(&adapter->watchdog_timer); - - cancel_work_sync(&adapter->reset_task); - cancel_work_sync(&adapter->watchdog_task); + cancel_work_sync(&adapter->service_task); if (netdev->reg_state == NETREG_REGISTERED) unregister_netdev(netdev); @@ -3955,7 +4138,7 @@ static pci_ers_result_t ixgbevf_io_error_detected(struct pci_dev *pdev, struct net_device *netdev = pci_get_drvdata(pdev); struct ixgbevf_adapter *adapter = netdev_priv(netdev); - if (!test_bit(__IXGBEVF_WORK_INIT, &adapter->state)) + if (!test_bit(__IXGBEVF_SERVICE_INITED, &adapter->state)) return PCI_ERS_RESULT_DISCONNECT; rtnl_lock(); diff --git a/drivers/net/ethernet/intel/ixgbevf/regs.h b/drivers/net/ethernet/intel/ixgbevf/regs.h index 09dd8f698bea..3e712fd6e695 100644 --- a/drivers/net/ethernet/intel/ixgbevf/regs.h +++ b/drivers/net/ethernet/intel/ixgbevf/regs.h @@ -69,6 +69,16 @@ #define IXGBE_VFGOTC_LSB 0x02020 #define IXGBE_VFGOTC_MSB 0x02024 #define IXGBE_VFMPRC 0x01034 +#define IXGBE_VFMRQC 0x3000 +#define IXGBE_VFRSSRK(x) (0x3100 + ((x) * 4)) +#define IXGBE_VFRETA(x) (0x3200 + ((x) * 4)) + +/* VFMRQC bits */ +#define IXGBE_VFMRQC_RSSEN 0x00000001 /* RSS Enable */ +#define IXGBE_VFMRQC_RSS_FIELD_IPV4_TCP 0x00010000 +#define IXGBE_VFMRQC_RSS_FIELD_IPV4 0x00020000 +#define IXGBE_VFMRQC_RSS_FIELD_IPV6 0x00100000 +#define IXGBE_VFMRQC_RSS_FIELD_IPV6_TCP 0x00200000 #define IXGBE_WRITE_FLUSH(a) (IXGBE_READ_REG(a, IXGBE_VFSTATUS)) diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index 44ce7d88f554..6e9a792097d3 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -2154,9 +2154,9 @@ jme_tx_csum(struct jme_adapter *jme, struct sk_buff *skb, u8 *flags) static inline void jme_tx_vlan(struct sk_buff *skb, __le16 *vlan, u8 *flags) { - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { *flags |= TXFLAG_TAGON; - *vlan = cpu_to_le16(vlan_tx_tag_get(skb)); + *vlan = cpu_to_le16(skb_vlan_tag_get(skb)); } } diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index a62fc38f045e..1c75829eb166 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -192,6 +192,10 @@ static char mv643xx_eth_driver_version[] = "1.4"; #define IS_TSO_HEADER(txq, addr) \ ((addr >= txq->tso_hdrs_dma) && \ (addr < txq->tso_hdrs_dma + txq->tx_ring_size * TSO_HEADER_SIZE)) + +#define DESC_DMA_MAP_SINGLE 0 +#define DESC_DMA_MAP_PAGE 1 + /* * RX/TX descriptors. */ @@ -362,6 +366,7 @@ struct tx_queue { dma_addr_t tso_hdrs_dma; struct tx_desc *tx_desc_area; + char *tx_desc_mapping; /* array to track the type of the dma mapping */ dma_addr_t tx_desc_dma; int tx_desc_area_size; @@ -750,6 +755,7 @@ txq_put_data_tso(struct net_device *dev, struct tx_queue *txq, if (txq->tx_curr_desc == txq->tx_ring_size) txq->tx_curr_desc = 0; desc = &txq->tx_desc_area[tx_index]; + txq->tx_desc_mapping[tx_index] = DESC_DMA_MAP_SINGLE; desc->l4i_chk = 0; desc->byte_cnt = length; @@ -879,14 +885,13 @@ static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb) skb_frag_t *this_frag; int tx_index; struct tx_desc *desc; - void *addr; this_frag = &skb_shinfo(skb)->frags[frag]; - addr = page_address(this_frag->page.p) + this_frag->page_offset; tx_index = txq->tx_curr_desc++; if (txq->tx_curr_desc == txq->tx_ring_size) txq->tx_curr_desc = 0; desc = &txq->tx_desc_area[tx_index]; + txq->tx_desc_mapping[tx_index] = DESC_DMA_MAP_PAGE; /* * The last fragment will generate an interrupt @@ -902,8 +907,9 @@ static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb) desc->l4i_chk = 0; desc->byte_cnt = skb_frag_size(this_frag); - desc->buf_ptr = dma_map_single(mp->dev->dev.parent, addr, - desc->byte_cnt, DMA_TO_DEVICE); + desc->buf_ptr = skb_frag_dma_map(mp->dev->dev.parent, + this_frag, 0, desc->byte_cnt, + DMA_TO_DEVICE); } } @@ -936,6 +942,7 @@ static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb, if (txq->tx_curr_desc == txq->tx_ring_size) txq->tx_curr_desc = 0; desc = &txq->tx_desc_area[tx_index]; + txq->tx_desc_mapping[tx_index] = DESC_DMA_MAP_SINGLE; if (nr_frags) { txq_submit_frag_skb(txq, skb); @@ -1047,9 +1054,12 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force) int tx_index; struct tx_desc *desc; u32 cmd_sts; + char desc_dma_map; tx_index = txq->tx_used_desc; desc = &txq->tx_desc_area[tx_index]; + desc_dma_map = txq->tx_desc_mapping[tx_index]; + cmd_sts = desc->cmd_sts; if (cmd_sts & BUFFER_OWNED_BY_DMA) { @@ -1065,9 +1075,19 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force) reclaimed++; txq->tx_desc_count--; - if (!IS_TSO_HEADER(txq, desc->buf_ptr)) - dma_unmap_single(mp->dev->dev.parent, desc->buf_ptr, - desc->byte_cnt, DMA_TO_DEVICE); + if (!IS_TSO_HEADER(txq, desc->buf_ptr)) { + + if (desc_dma_map == DESC_DMA_MAP_PAGE) + dma_unmap_page(mp->dev->dev.parent, + desc->buf_ptr, + desc->byte_cnt, + DMA_TO_DEVICE); + else + dma_unmap_single(mp->dev->dev.parent, + desc->buf_ptr, + desc->byte_cnt, + DMA_TO_DEVICE); + } if (cmd_sts & TX_ENABLE_INTERRUPT) { struct sk_buff *skb = __skb_dequeue(&txq->tx_skb); @@ -1996,6 +2016,7 @@ static int txq_init(struct mv643xx_eth_private *mp, int index) struct tx_queue *txq = mp->txq + index; struct tx_desc *tx_desc; int size; + int ret; int i; txq->index = index; @@ -2048,18 +2069,34 @@ static int txq_init(struct mv643xx_eth_private *mp, int index) nexti * sizeof(struct tx_desc); } + txq->tx_desc_mapping = kcalloc(txq->tx_ring_size, sizeof(char), + GFP_KERNEL); + if (!txq->tx_desc_mapping) { + ret = -ENOMEM; + goto err_free_desc_area; + } + /* Allocate DMA buffers for TSO MAC/IP/TCP headers */ txq->tso_hdrs = dma_alloc_coherent(mp->dev->dev.parent, txq->tx_ring_size * TSO_HEADER_SIZE, &txq->tso_hdrs_dma, GFP_KERNEL); if (txq->tso_hdrs == NULL) { - dma_free_coherent(mp->dev->dev.parent, txq->tx_desc_area_size, - txq->tx_desc_area, txq->tx_desc_dma); - return -ENOMEM; + ret = -ENOMEM; + goto err_free_desc_mapping; } skb_queue_head_init(&txq->tx_skb); return 0; + +err_free_desc_mapping: + kfree(txq->tx_desc_mapping); +err_free_desc_area: + if (index == 0 && size <= mp->tx_desc_sram_size) + iounmap(txq->tx_desc_area); + else + dma_free_coherent(mp->dev->dev.parent, txq->tx_desc_area_size, + txq->tx_desc_area, txq->tx_desc_dma); + return ret; } static void txq_deinit(struct tx_queue *txq) @@ -2077,6 +2114,8 @@ static void txq_deinit(struct tx_queue *txq) else dma_free_coherent(mp->dev->dev.parent, txq->tx_desc_area_size, txq->tx_desc_area, txq->tx_desc_dma); + kfree(txq->tx_desc_mapping); + if (txq->tso_hdrs) dma_free_coherent(mp->dev->dev.parent, txq->tx_ring_size * TSO_HEADER_SIZE, diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index 867a6a3ef81f..d9f4498832a1 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -1895,14 +1895,14 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb, ctrl = 0; /* Add VLAN tag, can piggyback on LRGLEN or ADDR64 */ - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { if (!le) { le = get_tx_le(sky2, &slot); le->addr = 0; le->opcode = OP_VLAN|HW_OWNER; } else le->opcode |= OP_VLAN; - le->length = cpu_to_be16(vlan_tx_tag_get(skb)); + le->length = cpu_to_be16(skb_vlan_tag_get(skb)); ctrl |= INS_VLAN; } @@ -2594,7 +2594,7 @@ static struct sk_buff *sky2_receive(struct net_device *dev, sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending; prefetch(sky2->rx_ring + sky2->rx_next); - if (vlan_tx_tag_present(re->skb)) + if (skb_vlan_tag_present(re->skb)) count -= VLAN_HLEN; /* Account for vlan tag */ /* This chip has hardware problems that generates bogus status. diff --git a/drivers/net/ethernet/mellanox/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c index 963dd7e6d547..0c51c69f802f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c @@ -592,7 +592,7 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, buf->nbufs = 1; buf->npages = 1; buf->page_shift = get_order(size) + PAGE_SHIFT; - buf->direct.buf = dma_alloc_coherent(&dev->pdev->dev, + buf->direct.buf = dma_alloc_coherent(&dev->persist->pdev->dev, size, &t, gfp); if (!buf->direct.buf) return -ENOMEM; @@ -619,7 +619,8 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, for (i = 0; i < buf->nbufs; ++i) { buf->page_list[i].buf = - dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, + dma_alloc_coherent(&dev->persist->pdev->dev, + PAGE_SIZE, &t, gfp); if (!buf->page_list[i].buf) goto err_free; @@ -657,15 +658,17 @@ void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf) int i; if (buf->nbufs == 1) - dma_free_coherent(&dev->pdev->dev, size, buf->direct.buf, + dma_free_coherent(&dev->persist->pdev->dev, size, + buf->direct.buf, buf->direct.map); else { - if (BITS_PER_LONG == 64 && buf->direct.buf) + if (BITS_PER_LONG == 64) vunmap(buf->direct.buf); for (i = 0; i < buf->nbufs; ++i) if (buf->page_list[i].buf) - dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + dma_free_coherent(&dev->persist->pdev->dev, + PAGE_SIZE, buf->page_list[i].buf, buf->page_list[i].map); kfree(buf->page_list); @@ -738,7 +741,7 @@ int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order, gfp_t gfp if (!mlx4_alloc_db_from_pgdir(pgdir, db, order)) goto out; - pgdir = mlx4_alloc_db_pgdir(&(dev->pdev->dev), gfp); + pgdir = mlx4_alloc_db_pgdir(&dev->persist->pdev->dev, gfp); if (!pgdir) { ret = -ENOMEM; goto out; @@ -775,7 +778,7 @@ void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db) set_bit(i, db->u.pgdir->bits[o]); if (bitmap_full(db->u.pgdir->order1, MLX4_DB_PER_PAGE / 2)) { - dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, + dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, db->u.pgdir->db_page, db->u.pgdir->db_dma); list_del(&db->u.pgdir->list); kfree(db->u.pgdir); diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c index 9c656fe4983d..715de8affcc9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/catas.c +++ b/drivers/net/ethernet/mellanox/mlx4/catas.c @@ -40,16 +40,177 @@ enum { MLX4_CATAS_POLL_INTERVAL = 5 * HZ, }; -static DEFINE_SPINLOCK(catas_lock); -static LIST_HEAD(catas_list); -static struct work_struct catas_work; -static int internal_err_reset = 1; -module_param(internal_err_reset, int, 0644); +int mlx4_internal_err_reset = 1; +module_param_named(internal_err_reset, mlx4_internal_err_reset, int, 0644); MODULE_PARM_DESC(internal_err_reset, - "Reset device on internal errors if non-zero" - " (default 1, in SRIOV mode default is 0)"); + "Reset device on internal errors if non-zero (default 1)"); + +static int read_vendor_id(struct mlx4_dev *dev) +{ + u16 vendor_id = 0; + int ret; + + ret = pci_read_config_word(dev->persist->pdev, 0, &vendor_id); + if (ret) { + mlx4_err(dev, "Failed to read vendor ID, ret=%d\n", ret); + return ret; + } + + if (vendor_id == 0xffff) { + mlx4_err(dev, "PCI can't be accessed to read vendor id\n"); + return -EINVAL; + } + + return 0; +} + +static int mlx4_reset_master(struct mlx4_dev *dev) +{ + int err = 0; + + if (mlx4_is_master(dev)) + mlx4_report_internal_err_comm_event(dev); + + if (!pci_channel_offline(dev->persist->pdev)) { + err = read_vendor_id(dev); + /* If PCI can't be accessed to read vendor ID we assume that its + * link was disabled and chip was already reset. + */ + if (err) + return 0; + + err = mlx4_reset(dev); + if (err) + mlx4_err(dev, "Fail to reset HCA\n"); + } + + return err; +} + +static int mlx4_reset_slave(struct mlx4_dev *dev) +{ +#define COM_CHAN_RST_REQ_OFFSET 0x10 +#define COM_CHAN_RST_ACK_OFFSET 0x08 + + u32 comm_flags; + u32 rst_req; + u32 rst_ack; + unsigned long end; + struct mlx4_priv *priv = mlx4_priv(dev); + + if (pci_channel_offline(dev->persist->pdev)) + return 0; + + comm_flags = swab32(readl((__iomem char *)priv->mfunc.comm + + MLX4_COMM_CHAN_FLAGS)); + if (comm_flags == 0xffffffff) { + mlx4_err(dev, "VF reset is not needed\n"); + return 0; + } + + if (!(dev->caps.vf_caps & MLX4_VF_CAP_FLAG_RESET)) { + mlx4_err(dev, "VF reset is not supported\n"); + return -EOPNOTSUPP; + } + + rst_req = (comm_flags & (u32)(1 << COM_CHAN_RST_REQ_OFFSET)) >> + COM_CHAN_RST_REQ_OFFSET; + rst_ack = (comm_flags & (u32)(1 << COM_CHAN_RST_ACK_OFFSET)) >> + COM_CHAN_RST_ACK_OFFSET; + if (rst_req != rst_ack) { + mlx4_err(dev, "Communication channel isn't sync, fail to send reset\n"); + return -EIO; + } + + rst_req ^= 1; + mlx4_warn(dev, "VF is sending reset request to Firmware\n"); + comm_flags = rst_req << COM_CHAN_RST_REQ_OFFSET; + __raw_writel((__force u32)cpu_to_be32(comm_flags), + (__iomem char *)priv->mfunc.comm + MLX4_COMM_CHAN_FLAGS); + /* Make sure that our comm channel write doesn't + * get mixed in with writes from another CPU. + */ + mmiowb(); + + end = msecs_to_jiffies(MLX4_COMM_TIME) + jiffies; + while (time_before(jiffies, end)) { + comm_flags = swab32(readl((__iomem char *)priv->mfunc.comm + + MLX4_COMM_CHAN_FLAGS)); + rst_ack = (comm_flags & (u32)(1 << COM_CHAN_RST_ACK_OFFSET)) >> + COM_CHAN_RST_ACK_OFFSET; + + /* Reading rst_req again since the communication channel can + * be reset at any time by the PF and all its bits will be + * set to zero. + */ + rst_req = (comm_flags & (u32)(1 << COM_CHAN_RST_REQ_OFFSET)) >> + COM_CHAN_RST_REQ_OFFSET; + + if (rst_ack == rst_req) { + mlx4_warn(dev, "VF Reset succeed\n"); + return 0; + } + cond_resched(); + } + mlx4_err(dev, "Fail to send reset over the communication channel\n"); + return -ETIMEDOUT; +} + +static int mlx4_comm_internal_err(u32 slave_read) +{ + return (u32)COMM_CHAN_EVENT_INTERNAL_ERR == + (slave_read & (u32)COMM_CHAN_EVENT_INTERNAL_ERR) ? 1 : 0; +} + +void mlx4_enter_error_state(struct mlx4_dev_persistent *persist) +{ + int err; + struct mlx4_dev *dev; + + if (!mlx4_internal_err_reset) + return; + + mutex_lock(&persist->device_state_mutex); + if (persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) + goto out; + + dev = persist->dev; + mlx4_err(dev, "device is going to be reset\n"); + if (mlx4_is_slave(dev)) + err = mlx4_reset_slave(dev); + else + err = mlx4_reset_master(dev); + BUG_ON(err != 0); + + dev->persist->state |= MLX4_DEVICE_STATE_INTERNAL_ERROR; + mlx4_err(dev, "device was reset successfully\n"); + mutex_unlock(&persist->device_state_mutex); + + /* At that step HW was already reset, now notify clients */ + mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0); + mlx4_cmd_wake_completions(dev); + return; + +out: + mutex_unlock(&persist->device_state_mutex); +} + +static void mlx4_handle_error_state(struct mlx4_dev_persistent *persist) +{ + int err = 0; + + mlx4_enter_error_state(persist); + mutex_lock(&persist->interface_state_mutex); + if (persist->interface_state & MLX4_INTERFACE_STATE_UP && + !(persist->interface_state & MLX4_INTERFACE_STATE_DELETION)) { + err = mlx4_restart_one(persist->pdev); + mlx4_info(persist->dev, "mlx4_restart_one was ended, ret=%d\n", + err); + } + mutex_unlock(&persist->interface_state_mutex); +} static void dump_err_buf(struct mlx4_dev *dev) { @@ -67,58 +228,40 @@ static void poll_catas(unsigned long dev_ptr) { struct mlx4_dev *dev = (struct mlx4_dev *) dev_ptr; struct mlx4_priv *priv = mlx4_priv(dev); + u32 slave_read; - if (readl(priv->catas_err.map)) { - /* If the device is off-line, we cannot try to recover it */ - if (pci_channel_offline(dev->pdev)) - mod_timer(&priv->catas_err.timer, - round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL)); - else { - dump_err_buf(dev); - mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0); - - if (internal_err_reset) { - spin_lock(&catas_lock); - list_add(&priv->catas_err.list, &catas_list); - spin_unlock(&catas_lock); - - queue_work(mlx4_wq, &catas_work); - } + if (mlx4_is_slave(dev)) { + slave_read = swab32(readl(&priv->mfunc.comm->slave_read)); + if (mlx4_comm_internal_err(slave_read)) { + mlx4_warn(dev, "Internal error detected on the communication channel\n"); + goto internal_err; } - } else - mod_timer(&priv->catas_err.timer, - round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL)); + } else if (readl(priv->catas_err.map)) { + dump_err_buf(dev); + goto internal_err; + } + + if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { + mlx4_warn(dev, "Internal error mark was detected on device\n"); + goto internal_err; + } + + mod_timer(&priv->catas_err.timer, + round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL)); + return; + +internal_err: + if (mlx4_internal_err_reset) + queue_work(dev->persist->catas_wq, &dev->persist->catas_work); } static void catas_reset(struct work_struct *work) { - struct mlx4_priv *priv, *tmppriv; - struct mlx4_dev *dev; + struct mlx4_dev_persistent *persist = + container_of(work, struct mlx4_dev_persistent, + catas_work); - LIST_HEAD(tlist); - int ret; - - spin_lock_irq(&catas_lock); - list_splice_init(&catas_list, &tlist); - spin_unlock_irq(&catas_lock); - - list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) { - struct pci_dev *pdev = priv->dev.pdev; - - /* If the device is off-line, we cannot reset it */ - if (pci_channel_offline(pdev)) - continue; - - ret = mlx4_restart_one(priv->dev.pdev); - /* 'priv' now is not valid */ - if (ret) - pr_err("mlx4 %s: Reset failed (%d)\n", - pci_name(pdev), ret); - else { - dev = pci_get_drvdata(pdev); - mlx4_dbg(dev, "Reset succeeded\n"); - } - } + mlx4_handle_error_state(persist); } void mlx4_start_catas_poll(struct mlx4_dev *dev) @@ -126,22 +269,21 @@ void mlx4_start_catas_poll(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); phys_addr_t addr; - /*If we are in SRIOV the default of the module param must be 0*/ - if (mlx4_is_mfunc(dev)) - internal_err_reset = 0; - INIT_LIST_HEAD(&priv->catas_err.list); init_timer(&priv->catas_err.timer); priv->catas_err.map = NULL; - addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) + - priv->fw.catas_offset; + if (!mlx4_is_slave(dev)) { + addr = pci_resource_start(dev->persist->pdev, + priv->fw.catas_bar) + + priv->fw.catas_offset; - priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4); - if (!priv->catas_err.map) { - mlx4_warn(dev, "Failed to map internal error buffer at 0x%llx\n", - (unsigned long long) addr); - return; + priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4); + if (!priv->catas_err.map) { + mlx4_warn(dev, "Failed to map internal error buffer at 0x%llx\n", + (unsigned long long)addr); + return; + } } priv->catas_err.timer.data = (unsigned long) dev; @@ -157,15 +299,29 @@ void mlx4_stop_catas_poll(struct mlx4_dev *dev) del_timer_sync(&priv->catas_err.timer); - if (priv->catas_err.map) + if (priv->catas_err.map) { iounmap(priv->catas_err.map); + priv->catas_err.map = NULL; + } - spin_lock_irq(&catas_lock); - list_del(&priv->catas_err.list); - spin_unlock_irq(&catas_lock); + if (dev->persist->interface_state & MLX4_INTERFACE_STATE_DELETION) + flush_workqueue(dev->persist->catas_wq); } -void __init mlx4_catas_init(void) +int mlx4_catas_init(struct mlx4_dev *dev) { - INIT_WORK(&catas_work, catas_reset); + INIT_WORK(&dev->persist->catas_work, catas_reset); + dev->persist->catas_wq = create_singlethread_workqueue("mlx4_health"); + if (!dev->persist->catas_wq) + return -ENOMEM; + + return 0; +} + +void mlx4_catas_end(struct mlx4_dev *dev) +{ + if (dev->persist->catas_wq) { + destroy_workqueue(dev->persist->catas_wq); + dev->persist->catas_wq = NULL; + } } diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 5c93d1451c44..a681d7c0bb9f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -182,6 +183,72 @@ static u8 mlx4_errno_to_status(int errno) } } +static int mlx4_internal_err_ret_value(struct mlx4_dev *dev, u16 op, + u8 op_modifier) +{ + switch (op) { + case MLX4_CMD_UNMAP_ICM: + case MLX4_CMD_UNMAP_ICM_AUX: + case MLX4_CMD_UNMAP_FA: + case MLX4_CMD_2RST_QP: + case MLX4_CMD_HW2SW_EQ: + case MLX4_CMD_HW2SW_CQ: + case MLX4_CMD_HW2SW_SRQ: + case MLX4_CMD_HW2SW_MPT: + case MLX4_CMD_CLOSE_HCA: + case MLX4_QP_FLOW_STEERING_DETACH: + case MLX4_CMD_FREE_RES: + case MLX4_CMD_CLOSE_PORT: + return CMD_STAT_OK; + + case MLX4_CMD_QP_ATTACH: + /* On Detach case return success */ + if (op_modifier == 0) + return CMD_STAT_OK; + return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); + + default: + return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); + } +} + +static int mlx4_closing_cmd_fatal_error(u16 op, u8 fw_status) +{ + /* Any error during the closing commands below is considered fatal */ + if (op == MLX4_CMD_CLOSE_HCA || + op == MLX4_CMD_HW2SW_EQ || + op == MLX4_CMD_HW2SW_CQ || + op == MLX4_CMD_2RST_QP || + op == MLX4_CMD_HW2SW_SRQ || + op == MLX4_CMD_SYNC_TPT || + op == MLX4_CMD_UNMAP_ICM || + op == MLX4_CMD_UNMAP_ICM_AUX || + op == MLX4_CMD_UNMAP_FA) + return 1; + /* Error on MLX4_CMD_HW2SW_MPT is fatal except when fw status equals + * CMD_STAT_REG_BOUND. + * This status indicates that memory region has memory windows bound to it + * which may result from invalid user space usage and is not fatal. + */ + if (op == MLX4_CMD_HW2SW_MPT && fw_status != CMD_STAT_REG_BOUND) + return 1; + return 0; +} + +static int mlx4_cmd_reset_flow(struct mlx4_dev *dev, u16 op, u8 op_modifier, + int err) +{ + /* Only if reset flow is really active return code is based on + * command, otherwise current error code is returned. + */ + if (mlx4_internal_err_reset) { + mlx4_enter_error_state(dev->persist); + err = mlx4_internal_err_ret_value(dev, op, op_modifier); + } + + return err; +} + static int comm_pending(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -190,16 +257,30 @@ static int comm_pending(struct mlx4_dev *dev) return (swab32(status) >> 31) != priv->cmd.comm_toggle; } -static void mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param) +static int mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param) { struct mlx4_priv *priv = mlx4_priv(dev); u32 val; + /* To avoid writing to unknown addresses after the device state was + * changed to internal error and the function was rest, + * check the INTERNAL_ERROR flag which is updated under + * device_state_mutex lock. + */ + mutex_lock(&dev->persist->device_state_mutex); + + if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { + mutex_unlock(&dev->persist->device_state_mutex); + return -EIO; + } + priv->cmd.comm_toggle ^= 1; val = param | (cmd << 16) | (priv->cmd.comm_toggle << 31); __raw_writel((__force u32) cpu_to_be32(val), &priv->mfunc.comm->slave_write); mmiowb(); + mutex_unlock(&dev->persist->device_state_mutex); + return 0; } static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param, @@ -219,7 +300,13 @@ static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param, /* Write command */ down(&priv->cmd.poll_sem); - mlx4_comm_cmd_post(dev, cmd, param); + if (mlx4_comm_cmd_post(dev, cmd, param)) { + /* Only in case the device state is INTERNAL_ERROR, + * mlx4_comm_cmd_post returns with an error + */ + err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); + goto out; + } end = msecs_to_jiffies(timeout) + jiffies; while (comm_pending(dev) && time_before(jiffies, end)) @@ -231,18 +318,23 @@ static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param, * is MLX4_DELAY_RESET_SLAVE*/ if ((MLX4_COMM_CMD_RESET == cmd)) { err = MLX4_DELAY_RESET_SLAVE; + goto out; } else { - mlx4_warn(dev, "Communication channel timed out\n"); - err = -ETIMEDOUT; + mlx4_warn(dev, "Communication channel command 0x%x timed out\n", + cmd); + err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); } } + if (err) + mlx4_enter_error_state(dev->persist); +out: up(&priv->cmd.poll_sem); return err; } -static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op, - u16 param, unsigned long timeout) +static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 vhcr_cmd, + u16 param, u16 op, unsigned long timeout) { struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; struct mlx4_cmd_context *context; @@ -258,34 +350,49 @@ static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op, cmd->free_head = context->next; spin_unlock(&cmd->context_lock); - init_completion(&context->done); + reinit_completion(&context->done); - mlx4_comm_cmd_post(dev, op, param); + if (mlx4_comm_cmd_post(dev, vhcr_cmd, param)) { + /* Only in case the device state is INTERNAL_ERROR, + * mlx4_comm_cmd_post returns with an error + */ + err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); + goto out; + } if (!wait_for_completion_timeout(&context->done, msecs_to_jiffies(timeout))) { - mlx4_warn(dev, "communication channel command 0x%x timed out\n", - op); - err = -EBUSY; - goto out; + mlx4_warn(dev, "communication channel command 0x%x (op=0x%x) timed out\n", + vhcr_cmd, op); + goto out_reset; } err = context->result; if (err && context->fw_status != CMD_STAT_MULTI_FUNC_REQ) { mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", - op, context->fw_status); - goto out; + vhcr_cmd, context->fw_status); + if (mlx4_closing_cmd_fatal_error(op, context->fw_status)) + goto out_reset; } -out: /* wait for comm channel ready * this is necessary for prevention the race * when switching between event to polling mode + * Skipping this section in case the device is in FATAL_ERROR state, + * In this state, no commands are sent via the comm channel until + * the device has returned from reset. */ - end = msecs_to_jiffies(timeout) + jiffies; - while (comm_pending(dev) && time_before(jiffies, end)) - cond_resched(); + if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) { + end = msecs_to_jiffies(timeout) + jiffies; + while (comm_pending(dev) && time_before(jiffies, end)) + cond_resched(); + } + goto out; +out_reset: + err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); + mlx4_enter_error_state(dev->persist); +out: spin_lock(&cmd->context_lock); context->next = cmd->free_head; cmd->free_head = context - cmd->context; @@ -296,10 +403,13 @@ out: } int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, - unsigned long timeout) + u16 op, unsigned long timeout) { + if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) + return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); + if (mlx4_priv(dev)->cmd.use_events) - return mlx4_comm_cmd_wait(dev, cmd, param, timeout); + return mlx4_comm_cmd_wait(dev, cmd, param, op, timeout); return mlx4_comm_cmd_poll(dev, cmd, param, timeout); } @@ -307,7 +417,7 @@ static int cmd_pending(struct mlx4_dev *dev) { u32 status; - if (pci_channel_offline(dev->pdev)) + if (pci_channel_offline(dev->persist->pdev)) return -EIO; status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); @@ -323,17 +433,21 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, { struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; u32 __iomem *hcr = cmd->hcr; - int ret = -EAGAIN; + int ret = -EIO; unsigned long end; - mutex_lock(&cmd->hcr_mutex); - - if (pci_channel_offline(dev->pdev)) { + mutex_lock(&dev->persist->device_state_mutex); + /* To avoid writing to unknown addresses after the device state was + * changed to internal error and the chip was reset, + * check the INTERNAL_ERROR flag which is updated under + * device_state_mutex lock. + */ + if (pci_channel_offline(dev->persist->pdev) || + (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) { /* * Device is going through error recovery * and cannot accept commands. */ - ret = -EIO; goto out; } @@ -342,12 +456,11 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); while (cmd_pending(dev)) { - if (pci_channel_offline(dev->pdev)) { + if (pci_channel_offline(dev->persist->pdev)) { /* * Device is going through error recovery * and cannot accept commands. */ - ret = -EIO; goto out; } @@ -391,7 +504,11 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, ret = 0; out: - mutex_unlock(&cmd->hcr_mutex); + if (ret) + mlx4_warn(dev, "Could not post command 0x%x: ret=%d, in_param=0x%llx, in_mod=0x%x, op_mod=0x%x\n", + op, ret, in_param, in_modifier, op_modifier); + mutex_unlock(&dev->persist->device_state_mutex); + return ret; } @@ -428,8 +545,11 @@ static int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, } ret = mlx4_status_to_errno(vhcr->status); } + if (ret && + dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) + ret = mlx4_internal_err_ret_value(dev, op, op_modifier); } else { - ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0, + ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0, op, MLX4_COMM_TIME + timeout); if (!ret) { if (out_is_imm) { @@ -443,9 +563,14 @@ static int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, } } ret = mlx4_status_to_errno(vhcr->status); - } else - mlx4_err(dev, "failed execution of VHCR_POST command opcode 0x%x\n", - op); + } else { + if (dev->persist->state & + MLX4_DEVICE_STATE_INTERNAL_ERROR) + ret = mlx4_internal_err_ret_value(dev, op, + op_modifier); + else + mlx4_err(dev, "failed execution of VHCR_POST command opcode 0x%x\n", op); + } } mutex_unlock(&priv->cmd.slave_cmd_mutex); @@ -464,12 +589,12 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, down(&priv->cmd.poll_sem); - if (pci_channel_offline(dev->pdev)) { + if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { /* * Device is going through error recovery * and cannot accept commands. */ - err = -EIO; + err = mlx4_internal_err_ret_value(dev, op, op_modifier); goto out; } @@ -483,16 +608,21 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); if (err) - goto out; + goto out_reset; end = msecs_to_jiffies(timeout) + jiffies; while (cmd_pending(dev) && time_before(jiffies, end)) { - if (pci_channel_offline(dev->pdev)) { + if (pci_channel_offline(dev->persist->pdev)) { /* * Device is going through error recovery * and cannot accept commands. */ err = -EIO; + goto out_reset; + } + + if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { + err = mlx4_internal_err_ret_value(dev, op, op_modifier); goto out; } @@ -502,8 +632,8 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, if (cmd_pending(dev)) { mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n", op); - err = -ETIMEDOUT; - goto out; + err = -EIO; + goto out_reset; } if (out_is_imm) @@ -515,10 +645,17 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, stat = be32_to_cpu((__force __be32) __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24; err = mlx4_status_to_errno(stat); - if (err) + if (err) { mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", op, stat); + if (mlx4_closing_cmd_fatal_error(op, stat)) + goto out_reset; + goto out; + } +out_reset: + if (err) + err = mlx4_cmd_reset_flow(dev, op, op_modifier, err); out: up(&priv->cmd.poll_sem); return err; @@ -565,17 +702,19 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, goto out; } - init_completion(&context->done); + reinit_completion(&context->done); - mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, - in_modifier, op_modifier, op, context->token, 1); + err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, + in_modifier, op_modifier, op, context->token, 1); + if (err) + goto out_reset; if (!wait_for_completion_timeout(&context->done, msecs_to_jiffies(timeout))) { mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n", op); - err = -EBUSY; - goto out; + err = -EIO; + goto out_reset; } err = context->result; @@ -592,12 +731,20 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, else mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", op, context->fw_status); + if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) + err = mlx4_internal_err_ret_value(dev, op, op_modifier); + else if (mlx4_closing_cmd_fatal_error(op, context->fw_status)) + goto out_reset; + goto out; } if (out_is_imm) *out_param = context->out_param; +out_reset: + if (err) + err = mlx4_cmd_reset_flow(dev, op, op_modifier, err); out: spin_lock(&cmd->context_lock); context->next = cmd->free_head; @@ -612,10 +759,13 @@ int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, int out_is_imm, u32 in_modifier, u8 op_modifier, u16 op, unsigned long timeout, int native) { - if (pci_channel_offline(dev->pdev)) - return -EIO; + if (pci_channel_offline(dev->persist->pdev)) + return mlx4_cmd_reset_flow(dev, op, op_modifier, -EIO); if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) { + if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) + return mlx4_internal_err_ret_value(dev, op, + op_modifier); if (mlx4_priv(dev)->cmd.use_events) return mlx4_cmd_wait(dev, in_param, out_param, out_is_imm, in_modifier, @@ -631,7 +781,7 @@ int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, EXPORT_SYMBOL_GPL(__mlx4_cmd); -static int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev) +int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev) { return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_ARM_COMM_CHANNEL, MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); @@ -751,7 +901,9 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave, index = be32_to_cpu(smp->attr_mod); if (port < 1 || port > dev->caps.num_ports) return -EINVAL; - table = kcalloc(dev->caps.pkey_table_len[port], sizeof *table, GFP_KERNEL); + table = kcalloc((dev->caps.pkey_table_len[port] / 32) + 1, + sizeof(*table) * 32, GFP_KERNEL); + if (!table) return -ENOMEM; /* need to get the full pkey table because the paravirtualized @@ -1071,7 +1223,7 @@ static struct mlx4_cmd_info cmd_info[] = { { .opcode = MLX4_CMD_HW2SW_EQ, .has_inbox = false, - .has_outbox = true, + .has_outbox = false, .out_is_imm = false, .encode_slave_id = true, .verify = NULL, @@ -1431,6 +1583,15 @@ static struct mlx4_cmd_info cmd_info[] = { .verify = NULL, .wrapper = mlx4_CMD_EPERM_wrapper }, + { + .opcode = MLX4_CMD_VIRT_PORT_MAP, + .has_inbox = false, + .has_outbox = false, + .out_is_imm = false, + .encode_slave_id = false, + .verify = NULL, + .wrapper = mlx4_CMD_EPERM_wrapper + }, }; static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, @@ -1460,8 +1621,10 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, ALIGN(sizeof(struct mlx4_vhcr_cmd), MLX4_ACCESS_MEM_ALIGN), 1); if (ret) { - mlx4_err(dev, "%s: Failed reading vhcr ret: 0x%x\n", - __func__, ret); + if (!(dev->persist->state & + MLX4_DEVICE_STATE_INTERNAL_ERROR)) + mlx4_err(dev, "%s: Failed reading vhcr ret: 0x%x\n", + __func__, ret); kfree(vhcr); return ret; } @@ -1500,11 +1663,14 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, goto out_status; } - if (mlx4_ACCESS_MEM(dev, inbox->dma, slave, - vhcr->in_param, - MLX4_MAILBOX_SIZE, 1)) { - mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n", - __func__, cmd->opcode); + ret = mlx4_ACCESS_MEM(dev, inbox->dma, slave, + vhcr->in_param, + MLX4_MAILBOX_SIZE, 1); + if (ret) { + if (!(dev->persist->state & + MLX4_DEVICE_STATE_INTERNAL_ERROR)) + mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n", + __func__, cmd->opcode); vhcr_cmd->status = CMD_STAT_INTERNAL_ERR; goto out_status; } @@ -1552,8 +1718,9 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, } if (err) { - mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with error:%d, status %d\n", - vhcr->op, slave, vhcr->errno, err); + if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) + mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with error:%d, status %d\n", + vhcr->op, slave, vhcr->errno, err); vhcr_cmd->status = mlx4_errno_to_status(err); goto out_status; } @@ -1568,7 +1735,9 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave, /* If we failed to write back the outbox after the *command was successfully executed, we must fail this * slave, as it is now in undefined state */ - mlx4_err(dev, "%s:Failed writing outbox\n", __func__); + if (!(dev->persist->state & + MLX4_DEVICE_STATE_INTERNAL_ERROR)) + mlx4_err(dev, "%s:Failed writing outbox\n", __func__); goto out; } } @@ -1847,8 +2016,11 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, break; case MLX4_COMM_CMD_VHCR_POST: if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) && - (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) + (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) { + mlx4_warn(dev, "slave:%d is out of sync, cmd=0x%x, last command=0x%x, reset is needed\n", + slave, cmd, slave_state[slave].last_cmd); goto reset_slave; + } mutex_lock(&priv->cmd.slave_cmd_mutex); if (mlx4_master_process_vhcr(dev, slave, NULL)) { @@ -1882,7 +2054,18 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, reset_slave: /* cleanup any slave resources */ - mlx4_delete_all_resources_for_slave(dev, slave); + if (dev->persist->interface_state & MLX4_INTERFACE_STATE_UP) + mlx4_delete_all_resources_for_slave(dev, slave); + + if (cmd != MLX4_COMM_CMD_RESET) { + mlx4_warn(dev, "Turn on internal error to force reset, slave=%d, cmd=0x%x\n", + slave, cmd); + /* Turn on internal error letting slave reset itself immeditaly, + * otherwise it might take till timeout on command is passed + */ + reply |= ((u32)COMM_CHAN_EVENT_INTERNAL_ERR); + } + spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); if (!slave_state[slave].is_slave_going_down) slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET; @@ -1958,17 +2141,28 @@ void mlx4_master_comm_channel(struct work_struct *work) static int sync_toggles(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); - int wr_toggle; - int rd_toggle; + u32 wr_toggle; + u32 rd_toggle; unsigned long end; - wr_toggle = swab32(readl(&priv->mfunc.comm->slave_write)) >> 31; - end = jiffies + msecs_to_jiffies(5000); + wr_toggle = swab32(readl(&priv->mfunc.comm->slave_write)); + if (wr_toggle == 0xffffffff) + end = jiffies + msecs_to_jiffies(30000); + else + end = jiffies + msecs_to_jiffies(5000); while (time_before(jiffies, end)) { - rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read)) >> 31; - if (rd_toggle == wr_toggle) { - priv->cmd.comm_toggle = rd_toggle; + rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read)); + if (wr_toggle == 0xffffffff || rd_toggle == 0xffffffff) { + /* PCI might be offline */ + msleep(100); + wr_toggle = swab32(readl(&priv->mfunc.comm-> + slave_write)); + continue; + } + + if (rd_toggle >> 31 == wr_toggle >> 31) { + priv->cmd.comm_toggle = rd_toggle >> 31; return 0; } @@ -1997,11 +2191,12 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) if (mlx4_is_master(dev)) priv->mfunc.comm = - ioremap(pci_resource_start(dev->pdev, priv->fw.comm_bar) + + ioremap(pci_resource_start(dev->persist->pdev, + priv->fw.comm_bar) + priv->fw.comm_base, MLX4_COMM_PAGESIZE); else priv->mfunc.comm = - ioremap(pci_resource_start(dev->pdev, 2) + + ioremap(pci_resource_start(dev->persist->pdev, 2) + MLX4_SLAVE_COMM_BASE, MLX4_COMM_PAGESIZE); if (!priv->mfunc.comm) { mlx4_err(dev, "Couldn't map communication vector\n"); @@ -2073,13 +2268,6 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) if (mlx4_init_resource_tracker(dev)) goto err_thread; - err = mlx4_ARM_COMM_CHANNEL(dev); - if (err) { - mlx4_err(dev, " Failed to arm comm channel eq: %x\n", - err); - goto err_resource; - } - } else { err = sync_toggles(dev); if (err) { @@ -2089,8 +2277,6 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) } return 0; -err_resource: - mlx4_free_resource_tracker(dev, RES_TR_FREE_ALL); err_thread: flush_workqueue(priv->mfunc.master.comm_wq); destroy_workqueue(priv->mfunc.master.comm_wq); @@ -2107,9 +2293,9 @@ err_comm_admin: err_comm: iounmap(priv->mfunc.comm); err_vhcr: - dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, - priv->mfunc.vhcr, - priv->mfunc.vhcr_dma); + dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, + priv->mfunc.vhcr, + priv->mfunc.vhcr_dma); priv->mfunc.vhcr = NULL; return -ENOMEM; } @@ -2120,7 +2306,6 @@ int mlx4_cmd_init(struct mlx4_dev *dev) int flags = 0; if (!priv->cmd.initialized) { - mutex_init(&priv->cmd.hcr_mutex); mutex_init(&priv->cmd.slave_cmd_mutex); sema_init(&priv->cmd.poll_sem, 1); priv->cmd.use_events = 0; @@ -2130,8 +2315,8 @@ int mlx4_cmd_init(struct mlx4_dev *dev) } if (!mlx4_is_slave(dev) && !priv->cmd.hcr) { - priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) + - MLX4_HCR_BASE, MLX4_HCR_SIZE); + priv->cmd.hcr = ioremap(pci_resource_start(dev->persist->pdev, + 0) + MLX4_HCR_BASE, MLX4_HCR_SIZE); if (!priv->cmd.hcr) { mlx4_err(dev, "Couldn't map command register\n"); goto err; @@ -2140,7 +2325,8 @@ int mlx4_cmd_init(struct mlx4_dev *dev) } if (mlx4_is_mfunc(dev) && !priv->mfunc.vhcr) { - priv->mfunc.vhcr = dma_alloc_coherent(&(dev->pdev->dev), PAGE_SIZE, + priv->mfunc.vhcr = dma_alloc_coherent(&dev->persist->pdev->dev, + PAGE_SIZE, &priv->mfunc.vhcr_dma, GFP_KERNEL); if (!priv->mfunc.vhcr) @@ -2150,7 +2336,8 @@ int mlx4_cmd_init(struct mlx4_dev *dev) } if (!priv->cmd.pool) { - priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev, + priv->cmd.pool = pci_pool_create("mlx4_cmd", + dev->persist->pdev, MLX4_MAILBOX_SIZE, MLX4_MAILBOX_SIZE, 0); if (!priv->cmd.pool) @@ -2166,6 +2353,27 @@ err: return -ENOMEM; } +void mlx4_report_internal_err_comm_event(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int slave; + u32 slave_read; + + /* Report an internal error event to all + * communication channels. + */ + for (slave = 0; slave < dev->num_slaves; slave++) { + slave_read = swab32(readl(&priv->mfunc.comm[slave].slave_read)); + slave_read |= (u32)COMM_CHAN_EVENT_INTERNAL_ERR; + __raw_writel((__force u32)cpu_to_be32(slave_read), + &priv->mfunc.comm[slave].slave_read); + /* Make sure that our comm channel write doesn't + * get mixed in with writes from another CPU. + */ + mmiowb(); + } +} + void mlx4_multi_func_cleanup(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -2181,6 +2389,7 @@ void mlx4_multi_func_cleanup(struct mlx4_dev *dev) kfree(priv->mfunc.master.slave_state); kfree(priv->mfunc.master.vf_admin); kfree(priv->mfunc.master.vf_oper); + dev->num_slaves = 0; } iounmap(priv->mfunc.comm); @@ -2202,7 +2411,7 @@ void mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask) } if (mlx4_is_mfunc(dev) && priv->mfunc.vhcr && (cleanup_mask & MLX4_CMD_CLEANUP_VHCR)) { - dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, + dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, priv->mfunc.vhcr, priv->mfunc.vhcr_dma); priv->mfunc.vhcr = NULL; } @@ -2229,6 +2438,11 @@ int mlx4_cmd_use_events(struct mlx4_dev *dev) for (i = 0; i < priv->cmd.max_cmds; ++i) { priv->cmd.context[i].token = i; priv->cmd.context[i].next = i + 1; + /* To support fatal error flow, initialize all + * cmd contexts to allow simulating completions + * with complete() at any time. + */ + init_completion(&priv->cmd.context[i].done); } priv->cmd.context[priv->cmd.max_cmds - 1].next = -1; @@ -2306,8 +2520,9 @@ u32 mlx4_comm_get_version(void) static int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf) { - if ((vf < 0) || (vf >= dev->num_vfs)) { - mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n", vf, dev->num_vfs); + if ((vf < 0) || (vf >= dev->persist->num_vfs)) { + mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n", + vf, dev->persist->num_vfs); return -EINVAL; } @@ -2316,7 +2531,7 @@ static int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf) int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave) { - if (slave < 1 || slave > dev->num_vfs) { + if (slave < 1 || slave > dev->persist->num_vfs) { mlx4_err(dev, "Bad slave number:%d (number of activated slaves: %lu)\n", slave, dev->num_slaves); @@ -2325,6 +2540,25 @@ int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave) return slave - 1; } +void mlx4_cmd_wake_completions(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cmd_context *context; + int i; + + spin_lock(&priv->cmd.context_lock); + if (priv->cmd.context) { + for (i = 0; i < priv->cmd.max_cmds; ++i) { + context = &priv->cmd.context[i]; + context->fw_status = CMD_STAT_INTERNAL_ERR; + context->result = + mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR); + complete(&context->done); + } + } + spin_unlock(&priv->cmd.context_lock); +} + struct mlx4_active_ports mlx4_get_active_ports(struct mlx4_dev *dev, int slave) { struct mlx4_active_ports actv_ports; @@ -2388,7 +2622,7 @@ struct mlx4_slaves_pport mlx4_phys_to_slaves_pport(struct mlx4_dev *dev, if (port <= 0 || port > dev->caps.num_ports) return slaves_pport; - for (i = 0; i < dev->num_vfs + 1; i++) { + for (i = 0; i < dev->persist->num_vfs + 1; i++) { struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, i); if (test_bit(port - 1, actv_ports.ports)) @@ -2408,7 +2642,7 @@ struct mlx4_slaves_pport mlx4_phys_to_slaves_pport_actv( bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX); - for (i = 0; i < dev->num_vfs + 1; i++) { + for (i = 0; i < dev->persist->num_vfs + 1; i++) { struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, i); if (bitmap_equal(crit_ports->ports, actv_ports.ports, diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c index 999014413b1a..90b5309cdb5c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c @@ -32,6 +32,7 @@ */ #include +#include #include "mlx4_en.h" @@ -147,12 +148,9 @@ static int mlx4_en_phc_adjtime(struct ptp_clock_info *ptp, s64 delta) struct mlx4_en_dev *mdev = container_of(ptp, struct mlx4_en_dev, ptp_clock_info); unsigned long flags; - s64 now; write_lock_irqsave(&mdev->clock_lock, flags); - now = timecounter_read(&mdev->clock); - now += delta; - timecounter_init(&mdev->clock, &mdev->cycles, now); + timecounter_adjtime(&mdev->clock, delta); write_unlock_irqrestore(&mdev->clock_lock, flags); return 0; @@ -243,7 +241,7 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev) { struct mlx4_dev *dev = mdev->dev; unsigned long flags; - u64 ns; + u64 ns, zero = 0; rwlock_init(&mdev->clock_lock); @@ -268,7 +266,7 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev) /* Calculate period in seconds to call the overflow watchdog - to make * sure counter is checked at least once every wrap around. */ - ns = cyclecounter_cyc2ns(&mdev->cycles, mdev->cycles.mask); + ns = cyclecounter_cyc2ns(&mdev->cycles, mdev->cycles.mask, zero, &zero); do_div(ns, NSEC_PER_SEC / 2 / HZ); mdev->overflow_period = ns; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c index 82322b1c8411..22da4d0d0f05 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c @@ -70,10 +70,10 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv, /* Allocate HW buffers on provided NUMA node. * dev->numa_node is used in mtt range allocation flow. */ - set_dev_node(&mdev->dev->pdev->dev, node); + set_dev_node(&mdev->dev->persist->pdev->dev, node); err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres, cq->buf_size, 2 * PAGE_SIZE); - set_dev_node(&mdev->dev->pdev->dev, mdev->dev->numa_node); + set_dev_node(&mdev->dev->persist->pdev->dev, mdev->dev->numa_node); if (err) goto err_cq; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 90e0f045a6bc..a7b58ba8492b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -92,7 +92,7 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) (u16) (mdev->dev->caps.fw_ver >> 32), (u16) ((mdev->dev->caps.fw_ver >> 16) & 0xffff), (u16) (mdev->dev->caps.fw_ver & 0xffff)); - strlcpy(drvinfo->bus_info, pci_name(mdev->dev->pdev), + strlcpy(drvinfo->bus_info, pci_name(mdev->dev->persist->pdev), sizeof(drvinfo->bus_info)); drvinfo->n_stats = 0; drvinfo->regdump_len = 0; @@ -770,22 +770,20 @@ static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return 0; } - proto_admin = cpu_to_be32(ptys_adv); - if (speed >= 0 && speed != priv->port_state.link_speed) - /* If speed was set then speed decides :-) */ - proto_admin = speed_set_ptys_admin(priv, speed, - ptys_reg.eth_proto_cap); + proto_admin = cmd->autoneg == AUTONEG_ENABLE ? + cpu_to_be32(ptys_adv) : + speed_set_ptys_admin(priv, speed, + ptys_reg.eth_proto_cap); proto_admin &= ptys_reg.eth_proto_cap; - - if (proto_admin == ptys_reg.eth_proto_admin) - return 0; /* Nothing to change */ - if (!proto_admin) { en_warn(priv, "Not supported link mode(s) requested, check supported link modes.\n"); return -EINVAL; /* nothing to change due to bad input */ } + if (proto_admin == ptys_reg.eth_proto_admin) + return 0; /* Nothing to change */ + en_dbg(DRV, priv, "mlx4_ACCESS_PTYS_REG SET: ptys_reg.eth_proto_admin = 0x%x\n", be32_to_cpu(proto_admin)); @@ -798,9 +796,9 @@ static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return ret; } - en_warn(priv, "Port link mode changed, restarting port...\n"); mutex_lock(&priv->mdev->state_lock); if (priv->port_up) { + en_warn(priv, "Port link mode changed, restarting port...\n"); mlx4_en_stop_port(dev, 1); if (mlx4_en_start_port(dev)) en_err(priv, "Failed restarting port %d\n", priv->port); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index 9f16f754137b..58d5a07d0ff4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -214,6 +214,8 @@ static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr) iounmap(mdev->uar_map); mlx4_uar_free(dev, &mdev->priv_uar); mlx4_pd_free(dev, mdev->priv_pdn); + if (mdev->nb.notifier_call) + unregister_netdevice_notifier(&mdev->nb); kfree(mdev); } @@ -241,8 +243,8 @@ static void *mlx4_en_add(struct mlx4_dev *dev) spin_lock_init(&mdev->uar_lock); mdev->dev = dev; - mdev->dma_device = &(dev->pdev->dev); - mdev->pdev = dev->pdev; + mdev->dma_device = &dev->persist->pdev->dev; + mdev->pdev = dev->persist->pdev; mdev->device_up = false; mdev->LSO_support = !!(dev->caps.flags & (1 << 15)); @@ -298,6 +300,12 @@ static void *mlx4_en_add(struct mlx4_dev *dev) if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) mdev->pndev[i] = NULL; } + /* register notifier */ + mdev->nb.notifier_call = mlx4_en_netdev_event; + if (register_netdevice_notifier(&mdev->nb)) { + mdev->nb.notifier_call = NULL; + mlx4_err(mdev, "Failed to create notifier\n"); + } return mdev; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index d0d6dc1b8e46..2a210c4efb89 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -475,7 +475,8 @@ static int mlx4_en_tunnel_steer_add(struct mlx4_en_priv *priv, unsigned char *ad { int err; - if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) + if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN || + priv->mdev->dev->caps.dmfs_high_steer_mode == MLX4_STEERING_DMFS_A0_STATIC) return 0; /* do nothing */ err = mlx4_tunnel_steer_add(priv->mdev->dev, addr, priv->port, qpn, @@ -2061,6 +2062,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev) /* Detach the netdev so tasks would not attempt to access it */ mutex_lock(&mdev->state_lock); mdev->pndev[priv->port] = NULL; + mdev->upper[priv->port] = NULL; mutex_unlock(&mdev->state_lock); mlx4_en_free_resources(priv); @@ -2200,6 +2202,10 @@ static int mlx4_en_set_features(struct net_device *netdev, return ret; } + if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_CTAG_TX)) + en_info(priv, "Turn %s TX vlan strip offload\n", + (features & NETIF_F_HW_VLAN_CTAG_TX) ? "ON" : "OFF"); + if (features & NETIF_F_LOOPBACK) priv->ctrl_flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK); else @@ -2440,6 +2446,180 @@ static const struct net_device_ops mlx4_netdev_ops_master = { #endif }; +struct mlx4_en_bond { + struct work_struct work; + struct mlx4_en_priv *priv; + int is_bonded; + struct mlx4_port_map port_map; +}; + +static void mlx4_en_bond_work(struct work_struct *work) +{ + struct mlx4_en_bond *bond = container_of(work, + struct mlx4_en_bond, + work); + int err = 0; + struct mlx4_dev *dev = bond->priv->mdev->dev; + + if (bond->is_bonded) { + if (!mlx4_is_bonded(dev)) { + err = mlx4_bond(dev); + if (err) + en_err(bond->priv, "Fail to bond device\n"); + } + if (!err) { + err = mlx4_port_map_set(dev, &bond->port_map); + if (err) + en_err(bond->priv, "Fail to set port map [%d][%d]: %d\n", + bond->port_map.port1, + bond->port_map.port2, + err); + } + } else if (mlx4_is_bonded(dev)) { + err = mlx4_unbond(dev); + if (err) + en_err(bond->priv, "Fail to unbond device\n"); + } + dev_put(bond->priv->dev); + kfree(bond); +} + +static int mlx4_en_queue_bond_work(struct mlx4_en_priv *priv, int is_bonded, + u8 v2p_p1, u8 v2p_p2) +{ + struct mlx4_en_bond *bond = NULL; + + bond = kzalloc(sizeof(*bond), GFP_ATOMIC); + if (!bond) + return -ENOMEM; + + INIT_WORK(&bond->work, mlx4_en_bond_work); + bond->priv = priv; + bond->is_bonded = is_bonded; + bond->port_map.port1 = v2p_p1; + bond->port_map.port2 = v2p_p2; + dev_hold(priv->dev); + queue_work(priv->mdev->workqueue, &bond->work); + return 0; +} + +int mlx4_en_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *ndev = netdev_notifier_info_to_dev(ptr); + u8 port = 0; + struct mlx4_en_dev *mdev; + struct mlx4_dev *dev; + int i, num_eth_ports = 0; + bool do_bond = true; + struct mlx4_en_priv *priv; + u8 v2p_port1 = 0; + u8 v2p_port2 = 0; + + if (!net_eq(dev_net(ndev), &init_net)) + return NOTIFY_DONE; + + mdev = container_of(this, struct mlx4_en_dev, nb); + dev = mdev->dev; + + /* Go into this mode only when two network devices set on two ports + * of the same mlx4 device are slaves of the same bonding master + */ + mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { + ++num_eth_ports; + if (!port && (mdev->pndev[i] == ndev)) + port = i; + mdev->upper[i] = mdev->pndev[i] ? + netdev_master_upper_dev_get(mdev->pndev[i]) : NULL; + /* condition not met: network device is a slave */ + if (!mdev->upper[i]) + do_bond = false; + if (num_eth_ports < 2) + continue; + /* condition not met: same master */ + if (mdev->upper[i] != mdev->upper[i-1]) + do_bond = false; + } + /* condition not met: 2 salves */ + do_bond = (num_eth_ports == 2) ? do_bond : false; + + /* handle only events that come with enough info */ + if ((do_bond && (event != NETDEV_BONDING_INFO)) || !port) + return NOTIFY_DONE; + + priv = netdev_priv(ndev); + if (do_bond) { + struct netdev_notifier_bonding_info *notifier_info = ptr; + struct netdev_bonding_info *bonding_info = + ¬ifier_info->bonding_info; + + /* required mode 1, 2 or 4 */ + if ((bonding_info->master.bond_mode != BOND_MODE_ACTIVEBACKUP) && + (bonding_info->master.bond_mode != BOND_MODE_XOR) && + (bonding_info->master.bond_mode != BOND_MODE_8023AD)) + do_bond = false; + + /* require exactly 2 slaves */ + if (bonding_info->master.num_slaves != 2) + do_bond = false; + + /* calc v2p */ + if (do_bond) { + if (bonding_info->master.bond_mode == + BOND_MODE_ACTIVEBACKUP) { + /* in active-backup mode virtual ports are + * mapped to the physical port of the active + * slave */ + if (bonding_info->slave.state == + BOND_STATE_BACKUP) { + if (port == 1) { + v2p_port1 = 2; + v2p_port2 = 2; + } else { + v2p_port1 = 1; + v2p_port2 = 1; + } + } else { /* BOND_STATE_ACTIVE */ + if (port == 1) { + v2p_port1 = 1; + v2p_port2 = 1; + } else { + v2p_port1 = 2; + v2p_port2 = 2; + } + } + } else { /* Active-Active */ + /* in active-active mode a virtual port is + * mapped to the native physical port if and only + * if the physical port is up */ + __s8 link = bonding_info->slave.link; + + if (port == 1) + v2p_port2 = 2; + else + v2p_port1 = 1; + if ((link == BOND_LINK_UP) || + (link == BOND_LINK_FAIL)) { + if (port == 1) + v2p_port1 = 1; + else + v2p_port2 = 2; + } else { /* BOND_LINK_DOWN || BOND_LINK_BACK */ + if (port == 1) + v2p_port1 = 2; + else + v2p_port2 = 1; + } + } + } + } + + mlx4_en_queue_bond_work(priv, do_bond, + v2p_port1, v2p_port2); + + return NOTIFY_DONE; +} + int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, struct mlx4_en_port_profile *prof) { @@ -2457,7 +2637,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, netif_set_real_num_tx_queues(dev, prof->tx_ring_num); netif_set_real_num_rx_queues(dev, prof->rx_ring_num); - SET_NETDEV_DEV(dev, &mdev->dev->pdev->dev); + SET_NETDEV_DEV(dev, &mdev->dev->persist->pdev->dev); dev->dev_port = port - 1; /* @@ -2622,6 +2802,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, } mdev->pndev[port] = dev; + mdev->upper[port] = NULL; netif_carrier_off(dev); mlx4_en_set_default_moderation(priv); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_resources.c b/drivers/net/ethernet/mellanox/mlx4/en_resources.c index f1a5500ff72d..34f2fdf4fe5d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_resources.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_resources.c @@ -50,10 +50,14 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, context->mtu_msgmax = 0xff; if (!is_tx && !rss) context->rq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4); - if (is_tx) + if (is_tx) { context->sq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4); - else + if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_REMAP) + context->params2 |= MLX4_QP_BIT_FPP; + + } else { context->sq_size_stride = ilog2(TXBB_SIZE) - 4; + } context->usr_page = cpu_to_be32(mdev->priv_uar.index); context->local_qpn = cpu_to_be32(qpn); context->pri_path.ackto = 1 & 0x07; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index a0474eb94aa3..698d60de1255 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -162,6 +162,10 @@ static int mlx4_en_init_allocator(struct mlx4_en_priv *priv, if (mlx4_alloc_pages(priv, &ring->page_alloc[i], frag_info, GFP_KERNEL | __GFP_COLD)) goto out; + + en_dbg(DRV, priv, " frag %d allocator: - size:%d frags:%d\n", + i, ring->page_alloc[i].page_size, + atomic_read(&ring->page_alloc[i].page->_count)); } return 0; @@ -387,10 +391,10 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, ring->rx_info, tmp); /* Allocate HW buffers on provided NUMA node */ - set_dev_node(&mdev->dev->pdev->dev, node); + set_dev_node(&mdev->dev->persist->pdev->dev, node); err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, ring->buf_size, 2 * PAGE_SIZE); - set_dev_node(&mdev->dev->pdev->dev, mdev->dev->numa_node); + set_dev_node(&mdev->dev->persist->pdev->dev, mdev->dev->numa_node); if (err) goto err_info; @@ -1059,8 +1063,9 @@ void mlx4_en_calc_rx_buf(struct net_device *dev) (eff_mtu > buf_size + frag_sizes[i]) ? frag_sizes[i] : eff_mtu - buf_size; priv->frag_info[i].frag_prefix_size = buf_size; - priv->frag_info[i].frag_stride = ALIGN(frag_sizes[i], - SMP_CACHE_BYTES); + priv->frag_info[i].frag_stride = + ALIGN(priv->frag_info[i].frag_size, + SMP_CACHE_BYTES); buf_size += priv->frag_info[i].frag_size; i++; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index e3357bf523df..55f9f5c5344e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -91,10 +91,10 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, ring->buf_size = ALIGN(size * ring->stride, MLX4_EN_PAGE_SIZE); /* Allocate HW buffers on provided NUMA node */ - set_dev_node(&mdev->dev->pdev->dev, node); + set_dev_node(&mdev->dev->persist->pdev->dev, node); err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, ring->buf_size, 2 * PAGE_SIZE); - set_dev_node(&mdev->dev->pdev->dev, mdev->dev->numa_node); + set_dev_node(&mdev->dev->persist->pdev->dev, mdev->dev->numa_node); if (err) { en_err(priv, "Failed allocating hwq resources\n"); goto err_bounce; @@ -682,8 +682,8 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb, if (dev->num_tc) return skb_tx_hash(dev, skb); - if (vlan_tx_tag_present(skb)) - up = vlan_tx_tag_get(skb) >> VLAN_PRIO_SHIFT; + if (skb_vlan_tag_present(skb)) + up = skb_vlan_tag_get(skb) >> VLAN_PRIO_SHIFT; return fallback(dev, skb) % rings_p_up + up * rings_p_up; } @@ -742,8 +742,8 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_drop; } - if (vlan_tx_tag_present(skb)) - vlan_tag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) + vlan_tag = skb_vlan_tag_get(skb); netdev_txq_bql_enqueue_prefetchw(ring->tx_queue); @@ -930,7 +930,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) real_size = (real_size / 16) & 0x3f; if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && - !vlan_tx_tag_present(skb) && send_doorbell) { + !skb_vlan_tag_present(skb) && send_doorbell) { tx_desc->ctrl.bf_qpn = ring->doorbell_qpn | cpu_to_be32(real_size); @@ -952,7 +952,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) } else { tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag); tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN * - !!vlan_tx_tag_present(skb); + !!skb_vlan_tag_present(skb); tx_desc->ctrl.fence_size = real_size; /* Ensure new descriptor hits memory diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 3d275fbaf0eb..264bc15c1ff2 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -88,6 +88,8 @@ static u64 get_async_ev_mask(struct mlx4_dev *dev) u64 async_ev_mask = MLX4_ASYNC_EVENT_MASK; if (dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV) async_ev_mask |= (1ull << MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT); + if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT) + async_ev_mask |= (1ull << MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT); return async_ev_mask; } @@ -237,7 +239,7 @@ int mlx4_gen_guid_change_eqe(struct mlx4_dev *dev, int slave, u8 port) struct mlx4_eqe eqe; /*don't send if we don't have the that slave */ - if (dev->num_vfs < slave) + if (dev->persist->num_vfs < slave) return 0; memset(&eqe, 0, sizeof eqe); @@ -255,7 +257,7 @@ int mlx4_gen_port_state_change_eqe(struct mlx4_dev *dev, int slave, u8 port, struct mlx4_eqe eqe; /*don't send if we don't have the that slave */ - if (dev->num_vfs < slave) + if (dev->persist->num_vfs < slave) return 0; memset(&eqe, 0, sizeof eqe); @@ -310,7 +312,7 @@ static void set_all_slave_state(struct mlx4_dev *dev, u8 port, int event) struct mlx4_slaves_pport slaves_pport = mlx4_phys_to_slaves_pport(dev, port); - for (i = 0; i < dev->num_vfs + 1; i++) + for (i = 0; i < dev->persist->num_vfs + 1; i++) if (test_bit(i, slaves_pport.slaves)) set_and_calc_slave_port_state(dev, i, port, event, &gen_event); @@ -429,8 +431,14 @@ void mlx4_master_handle_slave_flr(struct work_struct *work) if (MLX4_COMM_CMD_FLR == slave_state[i].last_cmd) { mlx4_dbg(dev, "mlx4_handle_slave_flr: clean slave: %d\n", i); - - mlx4_delete_all_resources_for_slave(dev, i); + /* In case of 'Reset flow' FLR can be generated for + * a slave before mlx4_load_one is done. + * make sure interface is up before trying to delete + * slave resources which weren't allocated yet. + */ + if (dev->persist->interface_state & + MLX4_INTERFACE_STATE_UP) + mlx4_delete_all_resources_for_slave(dev, i); /*return the slave to running mode*/ spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); slave_state[i].last_cmd = MLX4_COMM_CMD_RESET; @@ -560,7 +568,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) mlx4_priv(dev)->sense.do_sense_port[port] = 1; if (!mlx4_is_master(dev)) break; - for (i = 0; i < dev->num_vfs + 1; i++) { + for (i = 0; i < dev->persist->num_vfs + 1; + i++) { if (!test_bit(i, slaves_port.slaves)) continue; if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) { @@ -596,7 +605,9 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) if (!mlx4_is_master(dev)) break; if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) - for (i = 0; i < dev->num_vfs + 1; i++) { + for (i = 0; + i < dev->persist->num_vfs + 1; + i++) { if (!test_bit(i, slaves_port.slaves)) continue; if (i == mlx4_master_func_num(dev)) @@ -727,6 +738,26 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) (unsigned long) eqe); break; + case MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT: + switch (eqe->subtype) { + case MLX4_RECOVERABLE_ERROR_EVENT_SUBTYPE_BAD_CABLE: + mlx4_warn(dev, "Bad cable detected on port %u\n", + eqe->event.bad_cable.port); + break; + case MLX4_RECOVERABLE_ERROR_EVENT_SUBTYPE_UNSUPPORTED_CABLE: + mlx4_warn(dev, "Unsupported cable detected\n"); + break; + default: + mlx4_dbg(dev, + "Unhandled recoverable error event detected: %02x(%02x) on EQ %d at index %u. owner=%x, nent=0x%x, ownership=%s\n", + eqe->type, eqe->subtype, eq->eqn, + eq->cons_index, eqe->owner, eq->nent, + !!(eqe->owner & 0x80) ^ + !!(eq->cons_index & eq->nent) ? "HW" : "SW"); + break; + } + break; + case MLX4_EVENT_TYPE_EEC_CATAS_ERROR: case MLX4_EVENT_TYPE_ECC_DETECT: default: @@ -837,12 +868,10 @@ static int mlx4_SW2HW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, MLX4_CMD_WRAPPED); } -static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - int eq_num) +static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, int eq_num) { - return mlx4_cmd_box(dev, 0, mailbox->dma, eq_num, - 0, MLX4_CMD_HW2SW_EQ, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); + return mlx4_cmd(dev, 0, eq_num, 1, MLX4_CMD_HW2SW_EQ, + MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); } static int mlx4_num_eq_uar(struct mlx4_dev *dev) @@ -865,7 +894,7 @@ static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) if (!priv->eq_table.uar_map[index]) { priv->eq_table.uar_map[index] = - ioremap(pci_resource_start(dev->pdev, 2) + + ioremap(pci_resource_start(dev->persist->pdev, 2) + ((eq->eqn / 4) << PAGE_SHIFT), PAGE_SIZE); if (!priv->eq_table.uar_map[index]) { @@ -928,8 +957,10 @@ static int mlx4_create_eq(struct mlx4_dev *dev, int nent, eq_context = mailbox->buf; for (i = 0; i < npages; ++i) { - eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev, - PAGE_SIZE, &t, GFP_KERNEL); + eq->page_list[i].buf = dma_alloc_coherent(&dev->persist-> + pdev->dev, + PAGE_SIZE, &t, + GFP_KERNEL); if (!eq->page_list[i].buf) goto err_out_free_pages; @@ -995,7 +1026,7 @@ err_out_free_eq: err_out_free_pages: for (i = 0; i < npages; ++i) if (eq->page_list[i].buf) - dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, eq->page_list[i].buf, eq->page_list[i].map); @@ -1013,7 +1044,6 @@ static void mlx4_free_eq(struct mlx4_dev *dev, struct mlx4_eq *eq) { struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_cmd_mailbox *mailbox; int err; int i; /* CX3 is capable of extending the CQE/EQE from 32 to 64 bytes, with @@ -1021,36 +1051,21 @@ static void mlx4_free_eq(struct mlx4_dev *dev, */ int npages = PAGE_ALIGN(dev->caps.eqe_size * eq->nent) / PAGE_SIZE; - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return; - - err = mlx4_HW2SW_EQ(dev, mailbox, eq->eqn); + err = mlx4_HW2SW_EQ(dev, eq->eqn); if (err) mlx4_warn(dev, "HW2SW_EQ failed (%d)\n", err); - if (0) { - mlx4_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn); - for (i = 0; i < sizeof (struct mlx4_eq_context) / 4; ++i) { - if (i % 4 == 0) - pr_cont("[%02x] ", i * 4); - pr_cont(" %08x", be32_to_cpup(mailbox->buf + i * 4)); - if ((i + 1) % 4 == 0) - pr_cont("\n"); - } - } synchronize_irq(eq->irq); tasklet_disable(&eq->tasklet_ctx.task); mlx4_mtt_cleanup(dev, &eq->mtt); for (i = 0; i < npages; ++i) - dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, - eq->page_list[i].buf, - eq->page_list[i].map); + dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE, + eq->page_list[i].buf, + eq->page_list[i].map); kfree(eq->page_list); mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn, MLX4_USE_RR); - mlx4_free_cmd_mailbox(dev, mailbox); } static void mlx4_free_irqs(struct mlx4_dev *dev) @@ -1060,7 +1075,7 @@ static void mlx4_free_irqs(struct mlx4_dev *dev) int i, vec; if (eq_table->have_irq) - free_irq(dev->pdev->irq, dev); + free_irq(dev->persist->pdev->irq, dev); for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) if (eq_table->eq[i].have_irq) { @@ -1089,7 +1104,8 @@ static int mlx4_map_clr_int(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); - priv->clr_base = ioremap(pci_resource_start(dev->pdev, priv->fw.clr_int_bar) + + priv->clr_base = ioremap(pci_resource_start(dev->persist->pdev, + priv->fw.clr_int_bar) + priv->fw.clr_int_base, MLX4_CLR_INT_SIZE); if (!priv->clr_base) { mlx4_err(dev, "Couldn't map interrupt clear register, aborting\n"); @@ -1212,13 +1228,13 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) i * MLX4_IRQNAME_SIZE, MLX4_IRQNAME_SIZE, "mlx4-comp-%d@pci:%s", i, - pci_name(dev->pdev)); + pci_name(dev->persist->pdev)); } else { snprintf(priv->eq_table.irq_names + i * MLX4_IRQNAME_SIZE, MLX4_IRQNAME_SIZE, "mlx4-async@pci:%s", - pci_name(dev->pdev)); + pci_name(dev->persist->pdev)); } eq_name = priv->eq_table.irq_names + @@ -1235,8 +1251,8 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) snprintf(priv->eq_table.irq_names, MLX4_IRQNAME_SIZE, DRV_NAME "@pci:%s", - pci_name(dev->pdev)); - err = request_irq(dev->pdev->irq, mlx4_interrupt, + pci_name(dev->persist->pdev)); + err = request_irq(dev->persist->pdev->irq, mlx4_interrupt, IRQF_SHARED, priv->eq_table.irq_names, dev); if (err) goto err_out_async; diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 982861d1df44..5a21e5dc94cb 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -84,13 +84,10 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags) [ 1] = "UC transport", [ 2] = "UD transport", [ 3] = "XRC transport", - [ 4] = "reliable multicast", - [ 5] = "FCoIB support", [ 6] = "SRQ support", [ 7] = "IPoIB checksum offload", [ 8] = "P_Key violation counter", [ 9] = "Q_Key violation counter", - [10] = "VMM", [12] = "Dual Port Different Protocol (DPDP) support", [15] = "Big LSO headers", [16] = "MW support", @@ -99,12 +96,11 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags) [19] = "Raw multicast support", [20] = "Address vector port checking support", [21] = "UD multicast support", - [24] = "Demand paging support", - [25] = "Router support", [30] = "IBoE support", [32] = "Unicast loopback support", [34] = "FCS header control", - [38] = "Wake On LAN support", + [37] = "Wake On LAN (port1) support", + [38] = "Wake On LAN (port2) support", [40] = "UDP RSS support", [41] = "Unicast VEP steering support", [42] = "Multicast VEP steering support", @@ -145,7 +141,9 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) [16] = "CONFIG DEV support", [17] = "Asymmetric EQs support", [18] = "More than 80 VFs support", - [19] = "Performance optimized for limited rule configuration flow steering support" + [19] = "Performance optimized for limited rule configuration flow steering support", + [20] = "Recoverable error events support", + [21] = "Port Remap support" }; int i; @@ -259,6 +257,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, #define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP 0x28 #define QUERY_FUNC_CAP_MAX_EQ_OFFSET 0x2c #define QUERY_FUNC_CAP_RESERVED_EQ_OFFSET 0x30 +#define QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET 0x48 #define QUERY_FUNC_CAP_QP_QUOTA_OFFSET 0x50 #define QUERY_FUNC_CAP_CQ_QUOTA_OFFSET 0x54 @@ -273,6 +272,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, #define QUERY_FUNC_CAP_FLAG_RDMA 0x40 #define QUERY_FUNC_CAP_FLAG_ETH 0x80 #define QUERY_FUNC_CAP_FLAG_QUOTAS 0x10 +#define QUERY_FUNC_CAP_FLAG_RESD_LKEY 0x08 #define QUERY_FUNC_CAP_FLAG_VALID_MAILBOX 0x04 #define QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG (1UL << 31) @@ -344,9 +344,12 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, } else if (vhcr->op_modifier == 0) { struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave); - /* enable rdma and ethernet interfaces, and new quota locations */ + /* enable rdma and ethernet interfaces, new quota locations, + * and reserved lkey + */ field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA | - QUERY_FUNC_CAP_FLAG_QUOTAS | QUERY_FUNC_CAP_FLAG_VALID_MAILBOX); + QUERY_FUNC_CAP_FLAG_QUOTAS | QUERY_FUNC_CAP_FLAG_VALID_MAILBOX | + QUERY_FUNC_CAP_FLAG_RESD_LKEY); MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET); field = min( @@ -411,6 +414,9 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, size = QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG | QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG; MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET); + + size = dev->caps.reserved_lkey + ((slave << 8) & 0xFF00); + MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET); } else err = -EINVAL; @@ -503,6 +509,13 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port, MLX4_GET(size, outbox, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET); func_cap->reserved_eq = size & 0xFFFFFF; + if (func_cap->flags & QUERY_FUNC_CAP_FLAG_RESD_LKEY) { + MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET); + func_cap->reserved_lkey = size; + } else { + func_cap->reserved_lkey = 0; + } + func_cap->extra_flags = 0; /* Mailbox data from 0x6c and onward should only be treated if @@ -851,6 +864,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_EQE_STRIDE; MLX4_GET(dev_cap->bmme_flags, outbox, QUERY_DEV_CAP_BMME_FLAGS_OFFSET); + if (dev_cap->bmme_flags & MLX4_FLAG_PORT_REMAP) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_PORT_REMAP; MLX4_GET(field, outbox, QUERY_DEV_CAP_CONFIG_DEV_OFFSET); if (field & 0x20) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_CONFIG_DEV; @@ -859,6 +874,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) MLX4_GET(field32, outbox, QUERY_DEV_CAP_ETH_BACKPL_OFFSET); if (field32 & (1 << 0)) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP; + if (field32 & (1 << 7)) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT; MLX4_GET(field, outbox, QUERY_DEV_CAP_FW_REASSIGN_MAC); if (field & 1<<6) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_REASSIGN_MAC_EN; @@ -1106,9 +1123,10 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave, field &= 0x7f; MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_BF_OFFSET); - /* For guests, disable mw type 2 */ + /* For guests, disable mw type 2 and port remap*/ MLX4_GET(bmme_flags, outbox->buf, QUERY_DEV_CAP_BMME_FLAGS_OFFSET); bmme_flags &= ~MLX4_BMME_FLAG_TYPE_2_WIN; + bmme_flags &= ~MLX4_FLAG_PORT_REMAP; MLX4_PUT(outbox->buf, bmme_flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET); /* turn off device-managed steering capability if not enabled */ @@ -1562,6 +1580,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) #define INIT_HCA_VXLAN_OFFSET 0x0c #define INIT_HCA_CACHELINE_SZ_OFFSET 0x0e #define INIT_HCA_FLAGS_OFFSET 0x014 +#define INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET 0x018 #define INIT_HCA_QPC_OFFSET 0x020 #define INIT_HCA_QPC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x10) #define INIT_HCA_LOG_QP_OFFSET (INIT_HCA_QPC_OFFSET + 0x17) @@ -1668,6 +1687,9 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_LARGE_CQE; } + if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT) + *(inbox + INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET / 4) |= cpu_to_be32(1 << 31); + /* QPC/EEC/CQC/EQC/RDMARC attributes */ MLX4_PUT(inbox, param->qpc_base, INIT_HCA_QPC_BASE_OFFSET); @@ -1752,8 +1774,8 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) MLX4_PUT(inbox, parser_params, INIT_HCA_VXLAN_OFFSET); } - err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 10000, - MLX4_CMD_NATIVE); + err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, + MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); if (err) mlx4_err(dev, "INIT_HCA returns %d\n", err); @@ -1879,6 +1901,36 @@ out: return err; } +static int mlx4_hca_core_clock_update(struct mlx4_dev *dev) +{ + struct mlx4_cmd_mailbox *mailbox; + __be32 *outbox; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + mlx4_warn(dev, "hca_core_clock mailbox allocation failed\n"); + return PTR_ERR(mailbox); + } + outbox = mailbox->buf; + + err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, + MLX4_CMD_QUERY_HCA, + MLX4_CMD_TIME_CLASS_B, + !mlx4_is_slave(dev)); + if (err) { + mlx4_warn(dev, "hca_core_clock update failed\n"); + goto out; + } + + MLX4_GET(dev->caps.hca_core_clock, outbox, QUERY_HCA_CORE_CLOCK_OFFSET); + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + + return err; +} + /* for IB-type ports only in SRIOV mode. Checks that both proxy QP0 * and real QP0 are active, so that the paravirtualized QP0 is ready * to operate */ @@ -1983,6 +2035,9 @@ int mlx4_INIT_PORT(struct mlx4_dev *dev, int port) err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); + if (!err) + mlx4_hca_core_clock_update(dev); + return err; } EXPORT_SYMBOL_GPL(mlx4_INIT_PORT); @@ -2007,7 +2062,7 @@ int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave, if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) { if (priv->mfunc.master.init_port_ref[port] == 1) { err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, - 1000, MLX4_CMD_NATIVE); + MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); if (err) return err; } @@ -2018,7 +2073,7 @@ int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave, if (!priv->mfunc.master.qp0_state[port].qp0_active && priv->mfunc.master.qp0_state[port].port_active) { err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, - 1000, MLX4_CMD_NATIVE); + MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); if (err) return err; priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port); @@ -2033,15 +2088,15 @@ int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave, int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port) { - return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, 1000, - MLX4_CMD_WRAPPED); + return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, + MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); } EXPORT_SYMBOL_GPL(mlx4_CLOSE_PORT); int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic) { - return mlx4_cmd(dev, 0, 0, panic, MLX4_CMD_CLOSE_HCA, 1000, - MLX4_CMD_NATIVE); + return mlx4_cmd(dev, 0, 0, panic, MLX4_CMD_CLOSE_HCA, + MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); } struct mlx4_config_dev { @@ -2049,13 +2104,16 @@ struct mlx4_config_dev { __be32 rsvd1[3]; __be16 vxlan_udp_dport; __be16 rsvd2; - __be32 rsvd3[27]; - __be16 rsvd4; - u8 rsvd5; + __be32 rsvd3; + __be32 roce_flags; + __be32 rsvd4[25]; + __be16 rsvd5; + u8 rsvd6; u8 rx_checksum_val; }; #define MLX4_VXLAN_UDP_DPORT (1 << 0) +#define MLX4_DISABLE_RX_PORT BIT(18) static int mlx4_CONFIG_DEV_set(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev) { @@ -2111,7 +2169,7 @@ static const u8 config_dev_csum_flags[] = { int mlx4_config_dev_retrieval(struct mlx4_dev *dev, struct mlx4_config_dev_params *params) { - struct mlx4_config_dev config_dev; + struct mlx4_config_dev config_dev = {0}; int err; u8 csum_mask; @@ -2158,6 +2216,45 @@ int mlx4_config_vxlan_port(struct mlx4_dev *dev, __be16 udp_port) } EXPORT_SYMBOL_GPL(mlx4_config_vxlan_port); +#define CONFIG_DISABLE_RX_PORT BIT(15) +int mlx4_disable_rx_port_check(struct mlx4_dev *dev, bool dis) +{ + struct mlx4_config_dev config_dev; + + memset(&config_dev, 0, sizeof(config_dev)); + config_dev.update_flags = cpu_to_be32(MLX4_DISABLE_RX_PORT); + if (dis) + config_dev.roce_flags = + cpu_to_be32(CONFIG_DISABLE_RX_PORT); + + return mlx4_CONFIG_DEV_set(dev, &config_dev); +} + +int mlx4_virt2phy_port_map(struct mlx4_dev *dev, u32 port1, u32 port2) +{ + struct mlx4_cmd_mailbox *mailbox; + struct { + __be32 v_port1; + __be32 v_port2; + } *v2p; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return -ENOMEM; + + v2p = mailbox->buf; + v2p->v_port1 = cpu_to_be32(port1); + v2p->v_port2 = cpu_to_be32(port2); + + err = mlx4_cmd(dev, mailbox->dma, 0, + MLX4_SET_PORT_VIRT2PHY, MLX4_CMD_VIRT_PORT_MAP, + MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages) { @@ -2180,7 +2277,8 @@ int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages) int mlx4_NOP(struct mlx4_dev *dev) { /* Input modifier of 0x1f means "finish as soon as possible." */ - return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100, MLX4_CMD_NATIVE); + return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, MLX4_CMD_TIME_CLASS_A, + MLX4_CMD_NATIVE); } int mlx4_get_phys_port_id(struct mlx4_dev *dev) diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h index 62562b60fa87..f44f7f6017ed 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.h +++ b/drivers/net/ethernet/mellanox/mlx4/fw.h @@ -147,6 +147,7 @@ struct mlx4_func_cap { u32 qp0_proxy_qpn; u32 qp1_tunnel_qpn; u32 qp1_proxy_qpn; + u32 reserved_lkey; u8 physical_port; u8 port_flags; u8 flags1; diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c index 97c9b1db1d27..2a9dd460a95f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/icm.c +++ b/drivers/net/ethernet/mellanox/mlx4/icm.c @@ -56,7 +56,7 @@ static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chu int i; if (chunk->nsg > 0) - pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages, + pci_unmap_sg(dev->persist->pdev, chunk->mem, chunk->npages, PCI_DMA_BIDIRECTIONAL); for (i = 0; i < chunk->npages; ++i) @@ -69,7 +69,8 @@ static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk * int i; for (i = 0; i < chunk->npages; ++i) - dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length, + dma_free_coherent(&dev->persist->pdev->dev, + chunk->mem[i].length, lowmem_page_address(sg_page(&chunk->mem[i])), sg_dma_address(&chunk->mem[i])); } @@ -173,7 +174,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, --cur_order; if (coherent) - ret = mlx4_alloc_icm_coherent(&dev->pdev->dev, + ret = mlx4_alloc_icm_coherent(&dev->persist->pdev->dev, &chunk->mem[chunk->npages], cur_order, gfp_mask); else @@ -193,7 +194,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, if (coherent) ++chunk->nsg; else if (chunk->npages == MLX4_ICM_CHUNK_LEN) { - chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, + chunk->nsg = pci_map_sg(dev->persist->pdev, chunk->mem, chunk->npages, PCI_DMA_BIDIRECTIONAL); @@ -208,7 +209,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, } if (!coherent && chunk) { - chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, + chunk->nsg = pci_map_sg(dev->persist->pdev, chunk->mem, chunk->npages, PCI_DMA_BIDIRECTIONAL); diff --git a/drivers/net/ethernet/mellanox/mlx4/intf.c b/drivers/net/ethernet/mellanox/mlx4/intf.c index 116895ac8b35..6fce58718837 100644 --- a/drivers/net/ethernet/mellanox/mlx4/intf.c +++ b/drivers/net/ethernet/mellanox/mlx4/intf.c @@ -33,11 +33,13 @@ #include #include +#include #include "mlx4.h" struct mlx4_device_context { struct list_head list; + struct list_head bond_list; struct mlx4_interface *intf; void *context; }; @@ -115,6 +117,58 @@ void mlx4_unregister_interface(struct mlx4_interface *intf) } EXPORT_SYMBOL_GPL(mlx4_unregister_interface); +int mlx4_do_bond(struct mlx4_dev *dev, bool enable) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_device_context *dev_ctx = NULL, *temp_dev_ctx; + unsigned long flags; + int ret; + LIST_HEAD(bond_list); + + if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_REMAP)) + return -ENOTSUPP; + + ret = mlx4_disable_rx_port_check(dev, enable); + if (ret) { + mlx4_err(dev, "Fail to %s rx port check\n", + enable ? "enable" : "disable"); + return ret; + } + if (enable) { + dev->flags |= MLX4_FLAG_BONDED; + } else { + ret = mlx4_virt2phy_port_map(dev, 1, 2); + if (ret) { + mlx4_err(dev, "Fail to reset port map\n"); + return ret; + } + dev->flags &= ~MLX4_FLAG_BONDED; + } + + spin_lock_irqsave(&priv->ctx_lock, flags); + list_for_each_entry_safe(dev_ctx, temp_dev_ctx, &priv->ctx_list, list) { + if (dev_ctx->intf->flags & MLX4_INTFF_BONDING) { + list_add_tail(&dev_ctx->bond_list, &bond_list); + list_del(&dev_ctx->list); + } + } + spin_unlock_irqrestore(&priv->ctx_lock, flags); + + list_for_each_entry(dev_ctx, &bond_list, bond_list) { + dev_ctx->intf->remove(dev, dev_ctx->context); + dev_ctx->context = dev_ctx->intf->add(dev); + + spin_lock_irqsave(&priv->ctx_lock, flags); + list_add_tail(&dev_ctx->list, &priv->ctx_list); + spin_unlock_irqrestore(&priv->ctx_lock, flags); + + mlx4_dbg(dev, "Inrerface for protocol %d restarted with when bonded mode is %s\n", + dev_ctx->intf->protocol, enable ? + "enabled" : "disabled"); + } + return 0; +} + void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type, unsigned long param) { @@ -138,13 +192,13 @@ int mlx4_register_device(struct mlx4_dev *dev) mutex_lock(&intf_mutex); + dev->persist->interface_state |= MLX4_INTERFACE_STATE_UP; list_add_tail(&priv->dev_list, &dev_list); list_for_each_entry(intf, &intf_list, list) mlx4_add_device(intf, priv); mutex_unlock(&intf_mutex); - if (!mlx4_is_slave(dev)) - mlx4_start_catas_poll(dev); + mlx4_start_catas_poll(dev); return 0; } @@ -154,14 +208,14 @@ void mlx4_unregister_device(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_interface *intf; - if (!mlx4_is_slave(dev)) - mlx4_stop_catas_poll(dev); + mlx4_stop_catas_poll(dev); mutex_lock(&intf_mutex); list_for_each_entry(intf, &intf_list, list) mlx4_remove_device(intf, priv); list_del(&priv->dev_list); + dev->persist->interface_state &= ~MLX4_INTERFACE_STATE_UP; mutex_unlock(&intf_mutex); } diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 03e9eb0dc761..7e487223489a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -108,6 +108,8 @@ MODULE_PARM_DESC(enable_64b_cqe_eqe, MLX4_FUNC_CAP_EQE_CQE_STRIDE | \ MLX4_FUNC_CAP_DMFS_A0_STATIC) +#define RESET_PERSIST_MASK_FLAGS (MLX4_FLAG_SRIOV) + static char mlx4_version[] = DRV_NAME ": Mellanox ConnectX core driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; @@ -249,7 +251,8 @@ static void mlx4_enable_cqe_eqe_stride(struct mlx4_dev *dev) if (mlx4_is_master(dev)) dev_cap->function_caps |= MLX4_FUNC_CAP_EQE_CQE_STRIDE; } else { - mlx4_dbg(dev, "Disabling CQE stride cacheLine unsupported\n"); + if (cache_line_size() != 32 && cache_line_size() != 64) + mlx4_dbg(dev, "Disabling CQE stride, cacheLine size unsupported\n"); dev_cap->flags2 &= ~MLX4_DEV_CAP_FLAG2_CQE_STRIDE; dev_cap->flags2 &= ~MLX4_DEV_CAP_FLAG2_EQE_STRIDE; } @@ -318,10 +321,11 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) return -ENODEV; } - if (dev_cap->uar_size > pci_resource_len(dev->pdev, 2)) { + if (dev_cap->uar_size > pci_resource_len(dev->persist->pdev, 2)) { mlx4_err(dev, "HCA reported UAR size of 0x%x bigger than PCI resource 2 size of 0x%llx, aborting\n", dev_cap->uar_size, - (unsigned long long) pci_resource_len(dev->pdev, 2)); + (unsigned long long) + pci_resource_len(dev->persist->pdev, 2)); return -ENODEV; } @@ -541,8 +545,10 @@ static int mlx4_get_pcie_dev_link_caps(struct mlx4_dev *dev, *speed = PCI_SPEED_UNKNOWN; *width = PCIE_LNK_WIDTH_UNKNOWN; - err1 = pcie_capability_read_dword(dev->pdev, PCI_EXP_LNKCAP, &lnkcap1); - err2 = pcie_capability_read_dword(dev->pdev, PCI_EXP_LNKCAP2, &lnkcap2); + err1 = pcie_capability_read_dword(dev->persist->pdev, PCI_EXP_LNKCAP, + &lnkcap1); + err2 = pcie_capability_read_dword(dev->persist->pdev, PCI_EXP_LNKCAP2, + &lnkcap2); if (!err2 && lnkcap2) { /* PCIe r3.0-compliant */ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB) *speed = PCIE_SPEED_8_0GT; @@ -587,7 +593,7 @@ static void mlx4_check_pcie_caps(struct mlx4_dev *dev) return; } - err = pcie_get_minimum_link(dev->pdev, &speed, &width); + err = pcie_get_minimum_link(dev->persist->pdev, &speed, &width); if (err || speed == PCI_SPEED_UNKNOWN || width == PCIE_LNK_WIDTH_UNKNOWN) { mlx4_warn(dev, @@ -792,6 +798,7 @@ static int mlx4_slave_cap(struct mlx4_dev *dev) dev->caps.num_mpts = 1 << hca_param.log_mpt_sz; dev->caps.num_eqs = func_cap.max_eq; dev->caps.reserved_eqs = func_cap.reserved_eq; + dev->caps.reserved_lkey = func_cap.reserved_lkey; dev->caps.num_pds = MLX4_NUM_PDS; dev->caps.num_mgms = 0; dev->caps.num_amgms = 0; @@ -837,10 +844,12 @@ static int mlx4_slave_cap(struct mlx4_dev *dev) if (dev->caps.uar_page_size * (dev->caps.num_uars - dev->caps.reserved_uars) > - pci_resource_len(dev->pdev, 2)) { + pci_resource_len(dev->persist->pdev, + 2)) { mlx4_err(dev, "HCA reported UAR region size of 0x%x bigger than PCI resource 2 size of 0x%llx, aborting\n", dev->caps.uar_page_size * dev->caps.num_uars, - (unsigned long long) pci_resource_len(dev->pdev, 2)); + (unsigned long long) + pci_resource_len(dev->persist->pdev, 2)); goto err_mem; } @@ -1152,6 +1161,91 @@ err_set_port: return err ? err : count; } +int mlx4_bond(struct mlx4_dev *dev) +{ + int ret = 0; + struct mlx4_priv *priv = mlx4_priv(dev); + + mutex_lock(&priv->bond_mutex); + + if (!mlx4_is_bonded(dev)) + ret = mlx4_do_bond(dev, true); + else + ret = 0; + + mutex_unlock(&priv->bond_mutex); + if (ret) + mlx4_err(dev, "Failed to bond device: %d\n", ret); + else + mlx4_dbg(dev, "Device is bonded\n"); + return ret; +} +EXPORT_SYMBOL_GPL(mlx4_bond); + +int mlx4_unbond(struct mlx4_dev *dev) +{ + int ret = 0; + struct mlx4_priv *priv = mlx4_priv(dev); + + mutex_lock(&priv->bond_mutex); + + if (mlx4_is_bonded(dev)) + ret = mlx4_do_bond(dev, false); + + mutex_unlock(&priv->bond_mutex); + if (ret) + mlx4_err(dev, "Failed to unbond device: %d\n", ret); + else + mlx4_dbg(dev, "Device is unbonded\n"); + return ret; +} +EXPORT_SYMBOL_GPL(mlx4_unbond); + + +int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p) +{ + u8 port1 = v2p->port1; + u8 port2 = v2p->port2; + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + + if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_REMAP)) + return -ENOTSUPP; + + mutex_lock(&priv->bond_mutex); + + /* zero means keep current mapping for this port */ + if (port1 == 0) + port1 = priv->v2p.port1; + if (port2 == 0) + port2 = priv->v2p.port2; + + if ((port1 < 1) || (port1 > MLX4_MAX_PORTS) || + (port2 < 1) || (port2 > MLX4_MAX_PORTS) || + (port1 == 2 && port2 == 1)) { + /* besides boundary checks cross mapping makes + * no sense and therefore not allowed */ + err = -EINVAL; + } else if ((port1 == priv->v2p.port1) && + (port2 == priv->v2p.port2)) { + err = 0; + } else { + err = mlx4_virt2phy_port_map(dev, port1, port2); + if (!err) { + mlx4_dbg(dev, "port map changed: [%d][%d]\n", + port1, port2); + priv->v2p.port1 = port1; + priv->v2p.port2 = port2; + } else { + mlx4_err(dev, "Failed to change port mape: %d\n", err); + } + } + + mutex_unlock(&priv->bond_mutex); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_port_map_set); + static int mlx4_load_fw(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -1477,7 +1571,8 @@ static void mlx4_slave_exit(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); mutex_lock(&priv->cmd.slave_cmd_mutex); - if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_TIME)) + if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_CMD_NA_OP, + MLX4_COMM_TIME)) mlx4_warn(dev, "Failed to close slave function\n"); mutex_unlock(&priv->cmd.slave_cmd_mutex); } @@ -1492,9 +1587,9 @@ static int map_bf_area(struct mlx4_dev *dev) if (!dev->caps.bf_reg_size) return -ENXIO; - bf_start = pci_resource_start(dev->pdev, 2) + + bf_start = pci_resource_start(dev->persist->pdev, 2) + (dev->caps.num_uars << PAGE_SHIFT); - bf_len = pci_resource_len(dev->pdev, 2) - + bf_len = pci_resource_len(dev->persist->pdev, 2) - (dev->caps.num_uars << PAGE_SHIFT); priv->bf_mapping = io_mapping_create_wc(bf_start, bf_len); if (!priv->bf_mapping) @@ -1536,7 +1631,8 @@ static int map_internal_clock(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); priv->clock_mapping = - ioremap(pci_resource_start(dev->pdev, priv->fw.clock_bar) + + ioremap(pci_resource_start(dev->persist->pdev, + priv->fw.clock_bar) + priv->fw.clock_offset, MLX4_CLOCK_SIZE); if (!priv->clock_mapping) @@ -1573,6 +1669,50 @@ static void mlx4_close_fw(struct mlx4_dev *dev) } } +static int mlx4_comm_check_offline(struct mlx4_dev *dev) +{ +#define COMM_CHAN_OFFLINE_OFFSET 0x09 + + u32 comm_flags; + u32 offline_bit; + unsigned long end; + struct mlx4_priv *priv = mlx4_priv(dev); + + end = msecs_to_jiffies(MLX4_COMM_OFFLINE_TIME_OUT) + jiffies; + while (time_before(jiffies, end)) { + comm_flags = swab32(readl((__iomem char *)priv->mfunc.comm + + MLX4_COMM_CHAN_FLAGS)); + offline_bit = (comm_flags & + (u32)(1 << COMM_CHAN_OFFLINE_OFFSET)); + if (!offline_bit) + return 0; + /* There are cases as part of AER/Reset flow that PF needs + * around 100 msec to load. We therefore sleep for 100 msec + * to allow other tasks to make use of that CPU during this + * time interval. + */ + msleep(100); + } + mlx4_err(dev, "Communication channel is offline.\n"); + return -EIO; +} + +static void mlx4_reset_vf_support(struct mlx4_dev *dev) +{ +#define COMM_CHAN_RST_OFFSET 0x1e + + struct mlx4_priv *priv = mlx4_priv(dev); + u32 comm_rst; + u32 comm_caps; + + comm_caps = swab32(readl((__iomem char *)priv->mfunc.comm + + MLX4_COMM_CHAN_CAPS)); + comm_rst = (comm_caps & (u32)(1 << COMM_CHAN_RST_OFFSET)); + + if (comm_rst) + dev->caps.vf_caps |= MLX4_VF_CAP_FLAG_RESET; +} + static int mlx4_init_slave(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -1588,9 +1728,15 @@ static int mlx4_init_slave(struct mlx4_dev *dev) mutex_lock(&priv->cmd.slave_cmd_mutex); priv->cmd.max_cmds = 1; + if (mlx4_comm_check_offline(dev)) { + mlx4_err(dev, "PF is not responsive, skipping initialization\n"); + goto err_offline; + } + + mlx4_reset_vf_support(dev); mlx4_warn(dev, "Sending reset\n"); ret_from_reset = mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, - MLX4_COMM_TIME); + MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME); /* if we are in the middle of flr the slave will try * NUM_OF_RESET_RETRIES times before leaving.*/ if (ret_from_reset) { @@ -1615,22 +1761,24 @@ static int mlx4_init_slave(struct mlx4_dev *dev) mlx4_warn(dev, "Sending vhcr0\n"); if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR0, dma >> 48, - MLX4_COMM_TIME)) + MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME)) goto err; if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR1, dma >> 32, - MLX4_COMM_TIME)) + MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME)) goto err; if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR2, dma >> 16, - MLX4_COMM_TIME)) + MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME)) goto err; - if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_EN, dma, MLX4_COMM_TIME)) + if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_EN, dma, + MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME)) goto err; mutex_unlock(&priv->cmd.slave_cmd_mutex); return 0; err: - mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, 0); + mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_CMD_NA_OP, 0); +err_offline: mutex_unlock(&priv->cmd.slave_cmd_mutex); return -EIO; } @@ -1705,7 +1853,8 @@ static void choose_steering_mode(struct mlx4_dev *dev, if (mlx4_log_num_mgm_entry_size <= 0 && dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_FS_EN && (!mlx4_is_mfunc(dev) || - (dev_cap->fs_max_num_qp_per_entry >= (dev->num_vfs + 1))) && + (dev_cap->fs_max_num_qp_per_entry >= + (dev->persist->num_vfs + 1))) && choose_log_fs_mgm_entry_size(dev_cap->fs_max_num_qp_per_entry) >= MLX4_MIN_MGM_LOG_ENTRY_SIZE) { dev->oper_log_mgm_entry_size = @@ -1744,8 +1893,7 @@ static void choose_tunnel_offload_mode(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) { if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED && - dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS && - dev->caps.dmfs_high_steer_mode != MLX4_STEERING_DMFS_A0_STATIC) + dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS) dev->caps.tunnel_offload_mode = MLX4_TUNNEL_OFFLOAD_MODE_VXLAN; else dev->caps.tunnel_offload_mode = MLX4_TUNNEL_OFFLOAD_MODE_NONE; @@ -2288,7 +2436,8 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) for (i = 0; i < nreq; ++i) entries[i].entry = i; - nreq = pci_enable_msix_range(dev->pdev, entries, 2, nreq); + nreq = pci_enable_msix_range(dev->persist->pdev, entries, 2, + nreq); if (nreq < 0) { kfree(entries); @@ -2316,7 +2465,7 @@ no_msi: dev->caps.comp_pool = 0; for (i = 0; i < 2; ++i) - priv->eq_table.eq[i].irq = dev->pdev->irq; + priv->eq_table.eq[i].irq = dev->persist->pdev->irq; } static int mlx4_init_port_info(struct mlx4_dev *dev, int port) @@ -2344,7 +2493,7 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port) info->port_attr.show = show_port_type; sysfs_attr_init(&info->port_attr.attr); - err = device_create_file(&dev->pdev->dev, &info->port_attr); + err = device_create_file(&dev->persist->pdev->dev, &info->port_attr); if (err) { mlx4_err(dev, "Failed to create file for port %d\n", port); info->port = -1; @@ -2361,10 +2510,12 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port) info->port_mtu_attr.show = show_port_ib_mtu; sysfs_attr_init(&info->port_mtu_attr.attr); - err = device_create_file(&dev->pdev->dev, &info->port_mtu_attr); + err = device_create_file(&dev->persist->pdev->dev, + &info->port_mtu_attr); if (err) { mlx4_err(dev, "Failed to create mtu file for port %d\n", port); - device_remove_file(&info->dev->pdev->dev, &info->port_attr); + device_remove_file(&info->dev->persist->pdev->dev, + &info->port_attr); info->port = -1; } @@ -2376,8 +2527,9 @@ static void mlx4_cleanup_port_info(struct mlx4_port_info *info) if (info->port < 0) return; - device_remove_file(&info->dev->pdev->dev, &info->port_attr); - device_remove_file(&info->dev->pdev->dev, &info->port_mtu_attr); + device_remove_file(&info->dev->persist->pdev->dev, &info->port_attr); + device_remove_file(&info->dev->persist->pdev->dev, + &info->port_mtu_attr); } static int mlx4_init_steering(struct mlx4_dev *dev) @@ -2444,10 +2596,11 @@ static int mlx4_get_ownership(struct mlx4_dev *dev) void __iomem *owner; u32 ret; - if (pci_channel_offline(dev->pdev)) + if (pci_channel_offline(dev->persist->pdev)) return -EIO; - owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE, + owner = ioremap(pci_resource_start(dev->persist->pdev, 0) + + MLX4_OWNER_BASE, MLX4_OWNER_SIZE); if (!owner) { mlx4_err(dev, "Failed to obtain ownership bit\n"); @@ -2463,10 +2616,11 @@ static void mlx4_free_ownership(struct mlx4_dev *dev) { void __iomem *owner; - if (pci_channel_offline(dev->pdev)) + if (pci_channel_offline(dev->persist->pdev)) return; - owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE, + owner = ioremap(pci_resource_start(dev->persist->pdev, 0) + + MLX4_OWNER_BASE, MLX4_OWNER_SIZE); if (!owner) { mlx4_err(dev, "Failed to obtain ownership bit\n"); @@ -2481,11 +2635,19 @@ static void mlx4_free_ownership(struct mlx4_dev *dev) !!((flags) & MLX4_FLAG_MASTER)) static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev, - u8 total_vfs, int existing_vfs) + u8 total_vfs, int existing_vfs, int reset_flow) { u64 dev_flags = dev->flags; int err = 0; + if (reset_flow) { + dev->dev_vfs = kcalloc(total_vfs, sizeof(*dev->dev_vfs), + GFP_KERNEL); + if (!dev->dev_vfs) + goto free_mem; + return dev_flags; + } + atomic_inc(&pf_loading); if (dev->flags & MLX4_FLAG_SRIOV) { if (existing_vfs != total_vfs) { @@ -2514,13 +2676,14 @@ static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev, dev_flags |= MLX4_FLAG_SRIOV | MLX4_FLAG_MASTER; dev_flags &= ~MLX4_FLAG_SLAVE; - dev->num_vfs = total_vfs; + dev->persist->num_vfs = total_vfs; } return dev_flags; disable_sriov: atomic_dec(&pf_loading); - dev->num_vfs = 0; +free_mem: + dev->persist->num_vfs = 0; kfree(dev->dev_vfs); return dev_flags & ~MLX4_FLAG_MASTER; } @@ -2544,7 +2707,8 @@ static int mlx4_check_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap } static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data, - int total_vfs, int *nvfs, struct mlx4_priv *priv) + int total_vfs, int *nvfs, struct mlx4_priv *priv, + int reset_flow) { struct mlx4_dev *dev; unsigned sum = 0; @@ -2560,6 +2724,7 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data, spin_lock_init(&priv->ctx_lock); mutex_init(&priv->port_mutex); + mutex_init(&priv->bond_mutex); INIT_LIST_HEAD(&priv->pgdir_list); mutex_init(&priv->pgdir_mutex); @@ -2607,10 +2772,15 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data, existing_vfs = pci_num_vf(pdev); if (existing_vfs) dev->flags |= MLX4_FLAG_SRIOV; - dev->num_vfs = total_vfs; + dev->persist->num_vfs = total_vfs; } } + /* on load remove any previous indication of internal error, + * device is up. + */ + dev->persist->state = MLX4_DEVICE_STATE_UP; + slave_start: err = mlx4_cmd_init(dev); if (err) { @@ -2661,8 +2831,10 @@ slave_start: goto err_fw; if (!(dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS)) { - u64 dev_flags = mlx4_enable_sriov(dev, pdev, total_vfs, - existing_vfs); + u64 dev_flags = mlx4_enable_sriov(dev, pdev, + total_vfs, + existing_vfs, + reset_flow); mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_ALL); dev->flags = dev_flags; @@ -2704,7 +2876,7 @@ slave_start: if (dev->flags & MLX4_FLAG_SRIOV) { if (!existing_vfs) pci_disable_sriov(pdev); - if (mlx4_is_master(dev)) + if (mlx4_is_master(dev) && !reset_flow) atomic_dec(&pf_loading); dev->flags &= ~MLX4_FLAG_SRIOV; } @@ -2718,7 +2890,8 @@ slave_start: } if (mlx4_is_master(dev) && (dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS)) { - u64 dev_flags = mlx4_enable_sriov(dev, pdev, total_vfs, existing_vfs); + u64 dev_flags = mlx4_enable_sriov(dev, pdev, total_vfs, + existing_vfs, reset_flow); if ((dev->flags ^ dev_flags) & (MLX4_FLAG_MASTER | MLX4_FLAG_SLAVE)) { mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_VHCR); @@ -2771,12 +2944,14 @@ slave_start: dev->caps.num_ports); goto err_close; } - memcpy(dev->nvfs, nvfs, sizeof(dev->nvfs)); + memcpy(dev->persist->nvfs, nvfs, sizeof(dev->persist->nvfs)); - for (i = 0; i < sizeof(dev->nvfs)/sizeof(dev->nvfs[0]); i++) { + for (i = 0; + i < sizeof(dev->persist->nvfs)/ + sizeof(dev->persist->nvfs[0]); i++) { unsigned j; - for (j = 0; j < dev->nvfs[i]; ++sum, ++j) { + for (j = 0; j < dev->persist->nvfs[i]; ++sum, ++j) { dev->dev_vfs[sum].min_port = i < 2 ? i + 1 : 1; dev->dev_vfs[sum].n_ports = i < 2 ? 1 : dev->caps.num_ports; @@ -2828,6 +3003,17 @@ slave_start: goto err_steer; mlx4_init_quotas(dev); + /* When PF resources are ready arm its comm channel to enable + * getting commands + */ + if (mlx4_is_master(dev)) { + err = mlx4_ARM_COMM_CHANNEL(dev); + if (err) { + mlx4_err(dev, " Failed to arm comm channel eq: %x\n", + err); + goto err_steer; + } + } for (port = 1; port <= dev->caps.num_ports; port++) { err = mlx4_init_port_info(dev, port); @@ -2835,6 +3021,9 @@ slave_start: goto err_port; } + priv->v2p.port1 = 1; + priv->v2p.port2 = 2; + err = mlx4_register_device(dev); if (err) goto err_port; @@ -2846,7 +3035,7 @@ slave_start: priv->removed = 0; - if (mlx4_is_master(dev) && dev->num_vfs) + if (mlx4_is_master(dev) && dev->persist->num_vfs && !reset_flow) atomic_dec(&pf_loading); kfree(dev_cap); @@ -2880,8 +3069,10 @@ err_free_eq: mlx4_free_eq_table(dev); err_master_mfunc: - if (mlx4_is_master(dev)) + if (mlx4_is_master(dev)) { + mlx4_free_resource_tracker(dev, RES_TR_FREE_STRUCTS_ONLY); mlx4_multi_func_cleanup(dev); + } if (mlx4_is_slave(dev)) { kfree(dev->caps.qp0_qkey); @@ -2905,10 +3096,12 @@ err_cmd: mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_ALL); err_sriov: - if (dev->flags & MLX4_FLAG_SRIOV && !existing_vfs) + if (dev->flags & MLX4_FLAG_SRIOV && !existing_vfs) { pci_disable_sriov(pdev); + dev->flags &= ~MLX4_FLAG_SRIOV; + } - if (mlx4_is_master(dev) && dev->num_vfs) + if (mlx4_is_master(dev) && dev->persist->num_vfs && !reset_flow) atomic_dec(&pf_loading); kfree(priv->dev.dev_vfs); @@ -3049,11 +3242,19 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data, } } - err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv); + err = mlx4_catas_init(&priv->dev); if (err) goto err_release_regions; + + err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv, 0); + if (err) + goto err_catas; + return 0; +err_catas: + mlx4_catas_end(&priv->dev); + err_release_regions: pci_release_regions(pdev); @@ -3076,38 +3277,60 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return -ENOMEM; dev = &priv->dev; - dev->pdev = pdev; - pci_set_drvdata(pdev, dev); + dev->persist = kzalloc(sizeof(*dev->persist), GFP_KERNEL); + if (!dev->persist) { + kfree(priv); + return -ENOMEM; + } + dev->persist->pdev = pdev; + dev->persist->dev = dev; + pci_set_drvdata(pdev, dev->persist); priv->pci_dev_data = id->driver_data; + mutex_init(&dev->persist->device_state_mutex); + mutex_init(&dev->persist->interface_state_mutex); ret = __mlx4_init_one(pdev, id->driver_data, priv); - if (ret) + if (ret) { + kfree(dev->persist); kfree(priv); + } else { + pci_save_state(pdev); + } return ret; } +static void mlx4_clean_dev(struct mlx4_dev *dev) +{ + struct mlx4_dev_persistent *persist = dev->persist; + struct mlx4_priv *priv = mlx4_priv(dev); + unsigned long flags = (dev->flags & RESET_PERSIST_MASK_FLAGS); + + memset(priv, 0, sizeof(*priv)); + priv->dev.persist = persist; + priv->dev.flags = flags; +} + static void mlx4_unload_one(struct pci_dev *pdev) { - struct mlx4_dev *dev = pci_get_drvdata(pdev); + struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); + struct mlx4_dev *dev = persist->dev; struct mlx4_priv *priv = mlx4_priv(dev); int pci_dev_data; - int p; - int active_vfs = 0; + int p, i; if (priv->removed) return; + /* saving current ports type for further use */ + for (i = 0; i < dev->caps.num_ports; i++) { + dev->persist->curr_port_type[i] = dev->caps.port_type[i + 1]; + dev->persist->curr_port_poss_type[i] = dev->caps. + possible_type[i + 1]; + } + pci_dev_data = priv->pci_dev_data; - /* Disabling SR-IOV is not allowed while there are active vf's */ - if (mlx4_is_master(dev)) { - active_vfs = mlx4_how_many_lives_vf(dev); - if (active_vfs) { - pr_warn("Removing PF when there are active VF's !!\n"); - pr_warn("Will not disable SR-IOV.\n"); - } - } mlx4_stop_sense(dev); mlx4_unregister_device(dev); @@ -3151,12 +3374,6 @@ static void mlx4_unload_one(struct pci_dev *pdev) if (dev->flags & MLX4_FLAG_MSI_X) pci_disable_msix(pdev); - if (dev->flags & MLX4_FLAG_SRIOV && !active_vfs) { - mlx4_warn(dev, "Disabling SR-IOV\n"); - pci_disable_sriov(pdev); - dev->flags &= ~MLX4_FLAG_SRIOV; - dev->num_vfs = 0; - } if (!mlx4_is_slave(dev)) mlx4_free_ownership(dev); @@ -3168,42 +3385,96 @@ static void mlx4_unload_one(struct pci_dev *pdev) kfree(dev->caps.qp1_proxy); kfree(dev->dev_vfs); - memset(priv, 0, sizeof(*priv)); + mlx4_clean_dev(dev); priv->pci_dev_data = pci_dev_data; priv->removed = 1; } static void mlx4_remove_one(struct pci_dev *pdev) { - struct mlx4_dev *dev = pci_get_drvdata(pdev); + struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); + struct mlx4_dev *dev = persist->dev; struct mlx4_priv *priv = mlx4_priv(dev); + int active_vfs = 0; + + mutex_lock(&persist->interface_state_mutex); + persist->interface_state |= MLX4_INTERFACE_STATE_DELETION; + mutex_unlock(&persist->interface_state_mutex); + + /* Disabling SR-IOV is not allowed while there are active vf's */ + if (mlx4_is_master(dev) && dev->flags & MLX4_FLAG_SRIOV) { + active_vfs = mlx4_how_many_lives_vf(dev); + if (active_vfs) { + pr_warn("Removing PF when there are active VF's !!\n"); + pr_warn("Will not disable SR-IOV.\n"); + } + } + + /* device marked to be under deletion running now without the lock + * letting other tasks to be terminated + */ + if (persist->interface_state & MLX4_INTERFACE_STATE_UP) + mlx4_unload_one(pdev); + else + mlx4_info(dev, "%s: interface is down\n", __func__); + mlx4_catas_end(dev); + if (dev->flags & MLX4_FLAG_SRIOV && !active_vfs) { + mlx4_warn(dev, "Disabling SR-IOV\n"); + pci_disable_sriov(pdev); + } - mlx4_unload_one(pdev); pci_release_regions(pdev); pci_disable_device(pdev); + kfree(dev->persist); kfree(priv); pci_set_drvdata(pdev, NULL); } +static int restore_current_port_types(struct mlx4_dev *dev, + enum mlx4_port_type *types, + enum mlx4_port_type *poss_types) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err, i; + + mlx4_stop_sense(dev); + + mutex_lock(&priv->port_mutex); + for (i = 0; i < dev->caps.num_ports; i++) + dev->caps.possible_type[i + 1] = poss_types[i]; + err = mlx4_change_port_types(dev, types); + mlx4_start_sense(dev); + mutex_unlock(&priv->port_mutex); + + return err; +} + int mlx4_restart_one(struct pci_dev *pdev) { - struct mlx4_dev *dev = pci_get_drvdata(pdev); + struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); + struct mlx4_dev *dev = persist->dev; struct mlx4_priv *priv = mlx4_priv(dev); int nvfs[MLX4_MAX_PORTS + 1] = {0, 0, 0}; int pci_dev_data, err, total_vfs; pci_dev_data = priv->pci_dev_data; - total_vfs = dev->num_vfs; - memcpy(nvfs, dev->nvfs, sizeof(dev->nvfs)); + total_vfs = dev->persist->num_vfs; + memcpy(nvfs, dev->persist->nvfs, sizeof(dev->persist->nvfs)); mlx4_unload_one(pdev); - err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv); + err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv, 1); if (err) { mlx4_err(dev, "%s: ERROR: mlx4_load_one failed, pci_name=%s, err=%d\n", __func__, pci_name(pdev), err); return err; } + err = restore_current_port_types(dev, dev->persist->curr_port_type, + dev->persist->curr_port_poss_type); + if (err) + mlx4_err(dev, "could not restore original port types (%d)\n", + err); + return err; } @@ -3258,23 +3529,79 @@ MODULE_DEVICE_TABLE(pci, mlx4_pci_table); static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev, pci_channel_state_t state) { - mlx4_unload_one(pdev); + struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); - return state == pci_channel_io_perm_failure ? - PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; + mlx4_err(persist->dev, "mlx4_pci_err_detected was called\n"); + mlx4_enter_error_state(persist); + + mutex_lock(&persist->interface_state_mutex); + if (persist->interface_state & MLX4_INTERFACE_STATE_UP) + mlx4_unload_one(pdev); + + mutex_unlock(&persist->interface_state_mutex); + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + + pci_disable_device(pdev); + return PCI_ERS_RESULT_NEED_RESET; } static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev) { - struct mlx4_dev *dev = pci_get_drvdata(pdev); + struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); + struct mlx4_dev *dev = persist->dev; struct mlx4_priv *priv = mlx4_priv(dev); int ret; + int nvfs[MLX4_MAX_PORTS + 1] = {0, 0, 0}; + int total_vfs; - ret = __mlx4_init_one(pdev, priv->pci_dev_data, priv); + mlx4_err(dev, "mlx4_pci_slot_reset was called\n"); + ret = pci_enable_device(pdev); + if (ret) { + mlx4_err(dev, "Can not re-enable device, ret=%d\n", ret); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_set_master(pdev); + pci_restore_state(pdev); + pci_save_state(pdev); + + total_vfs = dev->persist->num_vfs; + memcpy(nvfs, dev->persist->nvfs, sizeof(dev->persist->nvfs)); + + mutex_lock(&persist->interface_state_mutex); + if (!(persist->interface_state & MLX4_INTERFACE_STATE_UP)) { + ret = mlx4_load_one(pdev, priv->pci_dev_data, total_vfs, nvfs, + priv, 1); + if (ret) { + mlx4_err(dev, "%s: mlx4_load_one failed, ret=%d\n", + __func__, ret); + goto end; + } + + ret = restore_current_port_types(dev, dev->persist-> + curr_port_type, dev->persist-> + curr_port_poss_type); + if (ret) + mlx4_err(dev, "could not restore original port types (%d)\n", ret); + } +end: + mutex_unlock(&persist->interface_state_mutex); return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; } +static void mlx4_shutdown(struct pci_dev *pdev) +{ + struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev); + + mlx4_info(persist->dev, "mlx4_shutdown was called\n"); + mutex_lock(&persist->interface_state_mutex); + if (persist->interface_state & MLX4_INTERFACE_STATE_UP) + mlx4_unload_one(pdev); + mutex_unlock(&persist->interface_state_mutex); +} + static const struct pci_error_handlers mlx4_err_handler = { .error_detected = mlx4_pci_err_detected, .slot_reset = mlx4_pci_slot_reset, @@ -3284,7 +3611,7 @@ static struct pci_driver mlx4_driver = { .name = DRV_NAME, .id_table = mlx4_pci_table, .probe = mlx4_init_one, - .shutdown = mlx4_unload_one, + .shutdown = mlx4_shutdown, .remove = mlx4_remove_one, .err_handler = &mlx4_err_handler, }; @@ -3336,7 +3663,6 @@ static int __init mlx4_init(void) if (mlx4_verify_params()) return -EINVAL; - mlx4_catas_init(); mlx4_wq = create_singlethread_workqueue("mlx4"); if (!mlx4_wq) diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index a3867e7ef885..bd9ea0d01aae 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -1318,6 +1318,9 @@ out: mutex_unlock(&priv->mcg_table.mutex); mlx4_free_cmd_mailbox(dev, mailbox); + if (err && dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) + /* In case device is under an error, return success as a closing command */ + err = 0; return err; } @@ -1347,6 +1350,9 @@ static int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp, MLX4_CMD_WRAPPED); mlx4_free_cmd_mailbox(dev, mailbox); + if (err && !attach && + dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) + err = 0; return err; } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index bdd4eea2247c..1409d0cd6143 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -85,7 +85,9 @@ enum { MLX4_CLR_INT_SIZE = 0x00008, MLX4_SLAVE_COMM_BASE = 0x0, MLX4_COMM_PAGESIZE = 0x1000, - MLX4_CLOCK_SIZE = 0x00008 + MLX4_CLOCK_SIZE = 0x00008, + MLX4_COMM_CHAN_CAPS = 0x8, + MLX4_COMM_CHAN_FLAGS = 0xc }; enum { @@ -120,6 +122,10 @@ enum mlx4_mpt_state { }; #define MLX4_COMM_TIME 10000 +#define MLX4_COMM_OFFLINE_TIME_OUT 30000 +#define MLX4_COMM_CMD_NA_OP 0x0 + + enum { MLX4_COMM_CMD_RESET, MLX4_COMM_CMD_VHCR0, @@ -190,6 +196,7 @@ struct mlx4_vhcr { struct mlx4_vhcr_cmd { __be64 in_param; __be32 in_modifier; + u32 reserved1; __be64 out_param; __be16 token; u16 reserved; @@ -221,21 +228,24 @@ extern int mlx4_debug_level; #define mlx4_dbg(mdev, format, ...) \ do { \ if (mlx4_debug_level) \ - dev_printk(KERN_DEBUG, &(mdev)->pdev->dev, format, \ + dev_printk(KERN_DEBUG, \ + &(mdev)->persist->pdev->dev, format, \ ##__VA_ARGS__); \ } while (0) #define mlx4_err(mdev, format, ...) \ - dev_err(&(mdev)->pdev->dev, format, ##__VA_ARGS__) + dev_err(&(mdev)->persist->pdev->dev, format, ##__VA_ARGS__) #define mlx4_info(mdev, format, ...) \ - dev_info(&(mdev)->pdev->dev, format, ##__VA_ARGS__) + dev_info(&(mdev)->persist->pdev->dev, format, ##__VA_ARGS__) #define mlx4_warn(mdev, format, ...) \ - dev_warn(&(mdev)->pdev->dev, format, ##__VA_ARGS__) + dev_warn(&(mdev)->persist->pdev->dev, format, ##__VA_ARGS__) extern int mlx4_log_num_mgm_entry_size; extern int log_mtts_per_seg; +extern int mlx4_internal_err_reset; -#define MLX4_MAX_NUM_SLAVES (MLX4_MAX_NUM_PF + MLX4_MAX_NUM_VF) +#define MLX4_MAX_NUM_SLAVES (min(MLX4_MAX_NUM_PF + MLX4_MAX_NUM_VF, \ + MLX4_MFUNC_MAX)) #define ALL_SLAVES 0xff struct mlx4_bitmap { @@ -606,7 +616,6 @@ struct mlx4_mgm { struct mlx4_cmd { struct pci_pool *pool; void __iomem *hcr; - struct mutex hcr_mutex; struct mutex slave_cmd_mutex; struct semaphore poll_sem; struct semaphore event_sem; @@ -877,6 +886,8 @@ struct mlx4_priv { int reserved_mtts; int fs_hash_mode; u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS]; + struct mlx4_port_map v2p; /* cached port mapping configuration */ + struct mutex bond_mutex; /* for bond mode */ __be64 slave_node_guids[MLX4_MFUNC_MAX]; atomic_t opreq_count; @@ -994,7 +1005,8 @@ void __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn); void mlx4_start_catas_poll(struct mlx4_dev *dev); void mlx4_stop_catas_poll(struct mlx4_dev *dev); -void mlx4_catas_init(void); +int mlx4_catas_init(struct mlx4_dev *dev); +void mlx4_catas_end(struct mlx4_dev *dev); int mlx4_restart_one(struct pci_dev *pdev); int mlx4_register_device(struct mlx4_dev *dev); void mlx4_unregister_device(struct mlx4_dev *dev); @@ -1160,13 +1172,14 @@ enum { int mlx4_cmd_init(struct mlx4_dev *dev); void mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask); int mlx4_multi_func_init(struct mlx4_dev *dev); +int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev); void mlx4_multi_func_cleanup(struct mlx4_dev *dev); void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param); int mlx4_cmd_use_events(struct mlx4_dev *dev); void mlx4_cmd_use_polling(struct mlx4_dev *dev); int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, - unsigned long timeout); + u16 op, unsigned long timeout); void mlx4_cq_tasklet_cb(unsigned long data); void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn); @@ -1176,7 +1189,7 @@ void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type); void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type); -void mlx4_handle_catas_err(struct mlx4_dev *dev); +void mlx4_enter_error_state(struct mlx4_dev_persistent *persist); int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, enum mlx4_port_type *type); @@ -1354,6 +1367,7 @@ int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port); /* Returns the VF index of slave */ int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave); int mlx4_config_mad_demux(struct mlx4_dev *dev); +int mlx4_do_bond(struct mlx4_dev *dev, bool enable); enum mlx4_zone_flags { MLX4_ZONE_ALLOW_ALLOC_FROM_LOWER_PRIO = 1UL << 0, diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 944a112dff37..2a8268e6be15 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -390,6 +390,7 @@ struct mlx4_en_dev { struct pci_dev *pdev; struct mutex state_lock; struct net_device *pndev[MLX4_MAX_PORTS + 1]; + struct net_device *upper[MLX4_MAX_PORTS + 1]; u32 port_cnt; bool device_up; struct mlx4_en_profile profile; @@ -410,6 +411,7 @@ struct mlx4_en_dev { unsigned long overflow_period; struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_clock_info; + struct notifier_block nb; }; @@ -845,6 +847,9 @@ int mlx4_en_reset_config(struct net_device *dev, struct hwtstamp_config ts_config, netdev_features_t new_features); +int mlx4_en_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr); + /* * Functions for time stamping */ diff --git a/drivers/net/ethernet/mellanox/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c index 7094a9c70fd5..78f51e103880 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mr.c +++ b/drivers/net/ethernet/mellanox/mlx4/mr.c @@ -598,14 +598,11 @@ int mlx4_mr_rereg_mem_write(struct mlx4_dev *dev, struct mlx4_mr *mr, if (err) return err; - mpt_entry->start = cpu_to_be64(mr->iova); - mpt_entry->length = cpu_to_be64(mr->size); - mpt_entry->entity_size = cpu_to_be32(mr->mtt.page_shift); - - mpt_entry->pd_flags &= cpu_to_be32(MLX4_MPT_PD_MASK | - MLX4_MPT_PD_FLAG_EN_INV); - mpt_entry->flags &= cpu_to_be32(MLX4_MPT_FLAG_FREE | - MLX4_MPT_FLAG_SW_OWNS); + mpt_entry->start = cpu_to_be64(iova); + mpt_entry->length = cpu_to_be64(size); + mpt_entry->entity_size = cpu_to_be32(page_shift); + mpt_entry->flags &= ~(cpu_to_be32(MLX4_MPT_FLAG_FREE | + MLX4_MPT_FLAG_SW_OWNS)); if (mr->mtt.order < 0) { mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_PHYSICAL); mpt_entry->mtt_addr = 0; @@ -708,13 +705,13 @@ static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt, if (!mtts) return -ENOMEM; - dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle, + dma_sync_single_for_cpu(&dev->persist->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE); for (i = 0; i < npages; ++i) mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); - dma_sync_single_for_device(&dev->pdev->dev, dma_handle, + dma_sync_single_for_device(&dev->persist->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE); return 0; @@ -1020,13 +1017,13 @@ int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list /* Make sure MPT status is visible before writing MTT entries */ wmb(); - dma_sync_single_for_cpu(&dev->pdev->dev, fmr->dma_handle, + dma_sync_single_for_cpu(&dev->persist->pdev->dev, fmr->dma_handle, npages * sizeof(u64), DMA_TO_DEVICE); for (i = 0; i < npages; ++i) fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); - dma_sync_single_for_device(&dev->pdev->dev, fmr->dma_handle, + dma_sync_single_for_device(&dev->persist->pdev->dev, fmr->dma_handle, npages * sizeof(u64), DMA_TO_DEVICE); fmr->mpt->key = cpu_to_be32(key); @@ -1155,7 +1152,7 @@ EXPORT_SYMBOL_GPL(mlx4_fmr_free); int mlx4_SYNC_TPT(struct mlx4_dev *dev) { - return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000, - MLX4_CMD_NATIVE); + return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, + MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); } EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT); diff --git a/drivers/net/ethernet/mellanox/mlx4/pd.c b/drivers/net/ethernet/mellanox/mlx4/pd.c index 74216071201f..609c59dc854e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/pd.c +++ b/drivers/net/ethernet/mellanox/mlx4/pd.c @@ -151,11 +151,13 @@ int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar) return -ENOMEM; if (mlx4_is_slave(dev)) - offset = uar->index % ((int) pci_resource_len(dev->pdev, 2) / + offset = uar->index % ((int)pci_resource_len(dev->persist->pdev, + 2) / dev->caps.uar_page_size); else offset = uar->index; - uar->pfn = (pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + offset; + uar->pfn = (pci_resource_start(dev->persist->pdev, 2) >> PAGE_SHIFT) + + offset; uar->map = NULL; return 0; } @@ -212,7 +214,6 @@ int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf, int node) list_add(&uar->bf_list, &priv->bf_list); } - bf->uar = uar; idx = ffz(uar->free_bf_bmap); uar->free_bf_bmap |= 1 << idx; bf->uar = uar; diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index 30eb1ead0fe6..9f268f05290a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -553,9 +553,9 @@ int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port) slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( dev, &exclusive_ports); slave_gid -= bitmap_weight(slaves_pport_actv.slaves, - dev->num_vfs + 1); + dev->persist->num_vfs + 1); } - vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1; + vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1; if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs)) return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1; return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs; @@ -590,10 +590,10 @@ int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port) slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( dev, &exclusive_ports); slave_gid -= bitmap_weight(slaves_pport_actv.slaves, - dev->num_vfs + 1); + dev->persist->num_vfs + 1); } gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; - vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1; + vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1; if (slave_gid <= gids % vfs) return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1); @@ -644,7 +644,7 @@ void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave) int num_eth_ports, err; int i; - if (slave < 0 || slave > dev->num_vfs) + if (slave < 0 || slave > dev->persist->num_vfs) return; actv_ports = mlx4_get_active_ports(dev, slave); @@ -1214,7 +1214,8 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, return -EINVAL; slaves_pport = mlx4_phys_to_slaves_pport(dev, port); - num_vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1; + num_vfs = bitmap_weight(slaves_pport.slaves, + dev->persist->num_vfs + 1) - 1; for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid, @@ -1258,7 +1259,7 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, dev, &exclusive_ports); num_vfs_before += bitmap_weight( slaves_pport_actv.slaves, - dev->num_vfs + 1); + dev->persist->num_vfs + 1); } /* candidate_slave_gid isn't necessarily the correct slave, but @@ -1288,7 +1289,7 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, dev, &exclusive_ports); slave_gid += bitmap_weight( slaves_pport_actv.slaves, - dev->num_vfs + 1); + dev->persist->num_vfs + 1); } } *slave_id = slave_gid; diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 1586ecce13c7..2bb8553bd905 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -882,6 +882,8 @@ int mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt, for (i = 0; i < ARRAY_SIZE(states) - 1; i++) { context->flags &= cpu_to_be32(~(0xf << 28)); context->flags |= cpu_to_be32(states[i + 1] << 28); + if (states[i + 1] != MLX4_QP_STATE_RTR) + context->params2 &= ~MLX4_QP_BIT_FPP; err = mlx4_qp_modify(dev, mtt, states[i], states[i + 1], context, 0, 0, qp); if (err) { diff --git a/drivers/net/ethernet/mellanox/mlx4/reset.c b/drivers/net/ethernet/mellanox/mlx4/reset.c index ea1c6d092145..0076d88587ca 100644 --- a/drivers/net/ethernet/mellanox/mlx4/reset.c +++ b/drivers/net/ethernet/mellanox/mlx4/reset.c @@ -76,19 +76,21 @@ int mlx4_reset(struct mlx4_dev *dev) goto out; } - pcie_cap = pci_pcie_cap(dev->pdev); + pcie_cap = pci_pcie_cap(dev->persist->pdev); for (i = 0; i < 64; ++i) { if (i == 22 || i == 23) continue; - if (pci_read_config_dword(dev->pdev, i * 4, hca_header + i)) { + if (pci_read_config_dword(dev->persist->pdev, i * 4, + hca_header + i)) { err = -ENODEV; mlx4_err(dev, "Couldn't save HCA PCI header, aborting\n"); goto out; } } - reset = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_RESET_BASE, + reset = ioremap(pci_resource_start(dev->persist->pdev, 0) + + MLX4_RESET_BASE, MLX4_RESET_SIZE); if (!reset) { err = -ENOMEM; @@ -122,8 +124,8 @@ int mlx4_reset(struct mlx4_dev *dev) end = jiffies + MLX4_RESET_TIMEOUT_JIFFIES; do { - if (!pci_read_config_word(dev->pdev, PCI_VENDOR_ID, &vendor) && - vendor != 0xffff) + if (!pci_read_config_word(dev->persist->pdev, PCI_VENDOR_ID, + &vendor) && vendor != 0xffff) break; msleep(1); @@ -138,14 +140,16 @@ int mlx4_reset(struct mlx4_dev *dev) /* Now restore the PCI headers */ if (pcie_cap) { devctl = hca_header[(pcie_cap + PCI_EXP_DEVCTL) / 4]; - if (pcie_capability_write_word(dev->pdev, PCI_EXP_DEVCTL, + if (pcie_capability_write_word(dev->persist->pdev, + PCI_EXP_DEVCTL, devctl)) { err = -ENODEV; mlx4_err(dev, "Couldn't restore HCA PCI Express Device Control register, aborting\n"); goto out; } linkctl = hca_header[(pcie_cap + PCI_EXP_LNKCTL) / 4]; - if (pcie_capability_write_word(dev->pdev, PCI_EXP_LNKCTL, + if (pcie_capability_write_word(dev->persist->pdev, + PCI_EXP_LNKCTL, linkctl)) { err = -ENODEV; mlx4_err(dev, "Couldn't restore HCA PCI Express Link control register, aborting\n"); @@ -157,7 +161,8 @@ int mlx4_reset(struct mlx4_dev *dev) if (i * 4 == PCI_COMMAND) continue; - if (pci_write_config_dword(dev->pdev, i * 4, hca_header[i])) { + if (pci_write_config_dword(dev->persist->pdev, i * 4, + hca_header[i])) { err = -ENODEV; mlx4_err(dev, "Couldn't restore HCA reg %x, aborting\n", i); @@ -165,7 +170,7 @@ int mlx4_reset(struct mlx4_dev *dev) } } - if (pci_write_config_dword(dev->pdev, PCI_COMMAND, + if (pci_write_config_dword(dev->persist->pdev, PCI_COMMAND, hca_header[PCI_COMMAND / 4])) { err = -ENODEV; mlx4_err(dev, "Couldn't restore HCA COMMAND, aborting\n"); diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 4efbd1eca611..486e3d26cd4a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -309,12 +309,13 @@ static inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave, int allocated, free, reserved, guaranteed, from_free; int from_rsvd; - if (slave > dev->num_vfs) + if (slave > dev->persist->num_vfs) return -EINVAL; spin_lock(&res_alloc->alloc_lock); allocated = (port > 0) ? - res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] : + res_alloc->allocated[(port - 1) * + (dev->persist->num_vfs + 1) + slave] : res_alloc->allocated[slave]; free = (port > 0) ? res_alloc->res_port_free[port - 1] : res_alloc->res_free; @@ -352,7 +353,8 @@ static inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave, if (!err) { /* grant the request */ if (port > 0) { - res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] += count; + res_alloc->allocated[(port - 1) * + (dev->persist->num_vfs + 1) + slave] += count; res_alloc->res_port_free[port - 1] -= count; res_alloc->res_port_rsvd[port - 1] -= from_rsvd; } else { @@ -376,13 +378,14 @@ static inline void mlx4_release_resource(struct mlx4_dev *dev, int slave, &priv->mfunc.master.res_tracker.res_alloc[res_type]; int allocated, guaranteed, from_rsvd; - if (slave > dev->num_vfs) + if (slave > dev->persist->num_vfs) return; spin_lock(&res_alloc->alloc_lock); allocated = (port > 0) ? - res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] : + res_alloc->allocated[(port - 1) * + (dev->persist->num_vfs + 1) + slave] : res_alloc->allocated[slave]; guaranteed = res_alloc->guaranteed[slave]; @@ -397,7 +400,8 @@ static inline void mlx4_release_resource(struct mlx4_dev *dev, int slave, } if (port > 0) { - res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] -= count; + res_alloc->allocated[(port - 1) * + (dev->persist->num_vfs + 1) + slave] -= count; res_alloc->res_port_free[port - 1] += count; res_alloc->res_port_rsvd[port - 1] += from_rsvd; } else { @@ -415,7 +419,8 @@ static inline void initialize_res_quotas(struct mlx4_dev *dev, enum mlx4_resource res_type, int vf, int num_instances) { - res_alloc->guaranteed[vf] = num_instances / (2 * (dev->num_vfs + 1)); + res_alloc->guaranteed[vf] = num_instances / + (2 * (dev->persist->num_vfs + 1)); res_alloc->quota[vf] = (num_instances / 2) + res_alloc->guaranteed[vf]; if (vf == mlx4_master_func_num(dev)) { res_alloc->res_free = num_instances; @@ -486,21 +491,26 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev) for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) { struct resource_allocator *res_alloc = &priv->mfunc.master.res_tracker.res_alloc[i]; - res_alloc->quota = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); - res_alloc->guaranteed = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); + res_alloc->quota = kmalloc((dev->persist->num_vfs + 1) * + sizeof(int), GFP_KERNEL); + res_alloc->guaranteed = kmalloc((dev->persist->num_vfs + 1) * + sizeof(int), GFP_KERNEL); if (i == RES_MAC || i == RES_VLAN) res_alloc->allocated = kzalloc(MLX4_MAX_PORTS * - (dev->num_vfs + 1) * sizeof(int), - GFP_KERNEL); + (dev->persist->num_vfs + + 1) * + sizeof(int), GFP_KERNEL); else - res_alloc->allocated = kzalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL); + res_alloc->allocated = kzalloc((dev->persist-> + num_vfs + 1) * + sizeof(int), GFP_KERNEL); if (!res_alloc->quota || !res_alloc->guaranteed || !res_alloc->allocated) goto no_mem_err; spin_lock_init(&res_alloc->alloc_lock); - for (t = 0; t < dev->num_vfs + 1; t++) { + for (t = 0; t < dev->persist->num_vfs + 1; t++) { struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, t); switch (i) { @@ -2531,7 +2541,7 @@ int mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave, /* Make sure that the PD bits related to the slave id are zeros. */ pd = mr_get_pd(inbox->buf); pd_slave = (pd >> 17) & 0x7f; - if (pd_slave != 0 && pd_slave != slave) { + if (pd_slave != 0 && --pd_slave != slave) { err = -EPERM; goto ex_abort; } @@ -2934,6 +2944,9 @@ static int verify_qp_parameters(struct mlx4_dev *dev, qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; optpar = be32_to_cpu(*(__be32 *) inbox->buf); + if (slave != mlx4_master_func_num(dev)) + qp_ctx->params2 &= ~MLX4_QP_BIT_FPP; + switch (qp_type) { case MLX4_QP_ST_RC: case MLX4_QP_ST_XRC: @@ -4667,7 +4680,6 @@ static void rem_slave_eqs(struct mlx4_dev *dev, int slave) int state; LIST_HEAD(tlist); int eqn; - struct mlx4_cmd_mailbox *mailbox; err = move_all_busy(dev, slave, RES_EQ); if (err) @@ -4693,20 +4705,13 @@ static void rem_slave_eqs(struct mlx4_dev *dev, int slave) break; case RES_EQ_HW: - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - cond_resched(); - continue; - } - err = mlx4_cmd_box(dev, slave, 0, - eqn & 0xff, 0, - MLX4_CMD_HW2SW_EQ, - MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_NATIVE); + err = mlx4_cmd(dev, slave, eqn & 0xff, + 1, MLX4_CMD_HW2SW_EQ, + MLX4_CMD_TIME_CLASS_A, + MLX4_CMD_NATIVE); if (err) mlx4_dbg(dev, "rem_slave_eqs: failed to move slave %d eqs %d to SW ownership\n", slave, eqn); - mlx4_free_cmd_mailbox(dev, mailbox); atomic_dec(&eq->mtt->ref_count); state = RES_EQ_RESERVED; break; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c index 56779c1c7811..201ca6d76ce5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c @@ -121,7 +121,7 @@ void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf) dma_free_coherent(&dev->pdev->dev, buf->size, buf->direct.buf, buf->direct.map); else { - if (BITS_PER_LONG == 64 && buf->direct.buf) + if (BITS_PER_LONG == 64) vunmap(buf->direct.buf); for (i = 0; i < buf->nbufs; i++) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c index 10e1f1a18255..4878025e231c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c @@ -300,11 +300,11 @@ static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp, param = qp->pid; break; case QP_STATE: - param = (u64)mlx5_qp_state_str(be32_to_cpu(ctx->flags) >> 28); + param = (unsigned long)mlx5_qp_state_str(be32_to_cpu(ctx->flags) >> 28); *is_str = 1; break; case QP_XPORT: - param = (u64)mlx5_qp_type_str((be32_to_cpu(ctx->flags) >> 16) & 0xff); + param = (unsigned long)mlx5_qp_type_str((be32_to_cpu(ctx->flags) >> 16) & 0xff); *is_str = 1; break; case QP_MTU: @@ -464,7 +464,7 @@ static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count, if (is_str) - ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)field); + ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)(unsigned long)field); else ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 3f4525619a07..d6651937d899 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -903,12 +903,12 @@ static void remove_one(struct pci_dev *pdev) } static const struct pci_device_id mlx5_core_pci_table[] = { - { PCI_VDEVICE(MELLANOX, 4113) }, /* Connect-IB */ - { PCI_VDEVICE(MELLANOX, 4114) }, /* Connect-IB VF */ - { PCI_VDEVICE(MELLANOX, 4115) }, /* ConnectX-4 */ - { PCI_VDEVICE(MELLANOX, 4116) }, /* ConnectX-4 VF */ - { PCI_VDEVICE(MELLANOX, 4117) }, /* ConnectX-4LX */ - { PCI_VDEVICE(MELLANOX, 4118) }, /* ConnectX-4LX VF */ + { PCI_VDEVICE(MELLANOX, 0x1011) }, /* Connect-IB */ + { PCI_VDEVICE(MELLANOX, 0x1012) }, /* Connect-IB VF */ + { PCI_VDEVICE(MELLANOX, 0x1013) }, /* ConnectX-4 */ + { PCI_VDEVICE(MELLANOX, 0x1014) }, /* ConnectX-4 VF */ + { PCI_VDEVICE(MELLANOX, 0x1015) }, /* ConnectX-4LX */ + { PCI_VDEVICE(MELLANOX, 0x1016) }, /* ConnectX-4LX VF */ { 0, } }; diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index 2fa6ae026e4f..10988fbf47eb 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c @@ -4342,9 +4342,7 @@ static void ksz_init_timer(struct ksz_timer_info *info, int period, { info->max = 0; info->period = period; - init_timer(&info->timer); - info->timer.function = function; - info->timer.data = (unsigned long) data; + setup_timer(&info->timer, function, (unsigned long)data); } static void ksz_update_timer(struct ksz_timer_info *info) diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c index 71af98bb72cb..1412f5af05ec 100644 --- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c @@ -4226,8 +4226,7 @@ static void myri10ge_remove(struct pci_dev *pdev) mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span); #endif myri10ge_free_slices(mgp); - if (mgp->msix_vectors != NULL) - kfree(mgp->msix_vectors); + kfree(mgp->msix_vectors); dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd), mgp->cmd, mgp->cmd_bus); diff --git a/drivers/net/ethernet/natsemi/ns83820.c b/drivers/net/ethernet/natsemi/ns83820.c index 2552e550a78c..eb807b0dc72a 100644 --- a/drivers/net/ethernet/natsemi/ns83820.c +++ b/drivers/net/ethernet/natsemi/ns83820.c @@ -1122,12 +1122,12 @@ again: } #ifdef NS83820_VLAN_ACCEL_SUPPORT - if(vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { /* fetch the vlan tag info out of the * ancillary data if the vlan code * is using hw vlan acceleration */ - short tag = vlan_tx_tag_get(skb); + short tag = skb_vlan_tag_get(skb); extsts |= (EXTSTS_VPKT | htons(tag)); } #endif diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index f5e4b820128b..a4cdf2f8041a 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -4045,8 +4045,8 @@ static netdev_tx_t s2io_xmit(struct sk_buff *skb, struct net_device *dev) } queue = 0; - if (vlan_tx_tag_present(skb)) - vlan_tag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) + vlan_tag = skb_vlan_tag_get(skb); if (sp->config.tx_steering_type == TX_DEFAULT_STEERING) { if (skb->protocol == htons(ETH_P_IP)) { struct iphdr *ip; @@ -6987,7 +6987,9 @@ static int s2io_add_isr(struct s2io_nic *sp) if (sp->s2io_entries[i].in_use == MSIX_FLG) { if (sp->s2io_entries[i].type == MSIX_RING_TYPE) { - sprintf(sp->desc[i], "%s:MSI-X-%d-RX", + snprintf(sp->desc[i], + sizeof(sp->desc[i]), + "%s:MSI-X-%d-RX", dev->name, i); err = request_irq(sp->entries[i].vector, s2io_msix_ring_handle, @@ -6996,7 +6998,9 @@ static int s2io_add_isr(struct s2io_nic *sp) sp->s2io_entries[i].arg); } else if (sp->s2io_entries[i].type == MSIX_ALARM_TYPE) { - sprintf(sp->desc[i], "%s:MSI-X-%d-TX", + snprintf(sp->desc[i], + sizeof(sp->desc[i]), + "%s:MSI-X-%d-TX", dev->name, i); err = request_irq(sp->entries[i].vector, s2io_msix_fifo_handle, @@ -8154,7 +8158,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) "%s: UDP Fragmentation Offload(UFO) enabled\n", dev->name); /* Initialize device name */ - sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name); + snprintf(sp->name, sizeof(sp->name), "%s Neterion %s", dev->name, + sp->product_name); if (vlan_tag_strip) sp->vlan_strip_flag = 1; diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.c b/drivers/net/ethernet/neterion/vxge/vxge-config.c index 2bbd01fcb9b0..6223930a8155 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-config.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-config.c @@ -4637,7 +4637,7 @@ static void __vxge_hw_vp_terminate(struct __vxge_hw_device *hldev, u32 vp_id) vpath->ringh = NULL; vpath->fifoh = NULL; memset(&vpath->vpath_handles, 0, sizeof(struct list_head)); - vpath->stats_block = 0; + vpath->stats_block = NULL; vpath->hw_stats = NULL; vpath->hw_stats_sav = NULL; vpath->sw_stats = NULL; diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c index cc0485e3c621..50d5604833ed 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -890,8 +890,8 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev) dev->name, __func__, __LINE__, fifo_hw, dtr, dtr_priv); - if (vlan_tx_tag_present(skb)) { - u16 vlan_tag = vlan_tx_tag_get(skb); + if (skb_vlan_tag_present(skb)) { + u16 vlan_tag = skb_vlan_tag_get(skb); vxge_hw_fifo_txdl_vlan_set(dtr, vlan_tag); } diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index f39cae620f61..a41bb5e6b954 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -2462,9 +2462,9 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0; /* vlan tag */ - if (vlan_tx_tag_present(skb)) + if (skb_vlan_tag_present(skb)) start_tx->txvlan = cpu_to_le32(NV_TX3_VLAN_TAG_PRESENT | - vlan_tx_tag_get(skb)); + skb_vlan_tag_get(skb)); else start_tx->txvlan = 0; diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index 613037584d08..e0c31e3947d1 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -176,9 +176,7 @@ netxen_alloc_sds_rings(struct netxen_recv_context *recv_ctx, int count) static void netxen_free_sds_rings(struct netxen_recv_context *recv_ctx) { - if (recv_ctx->sds_rings != NULL) - kfree(recv_ctx->sds_rings); - + kfree(recv_ctx->sds_rings); recv_ctx->sds_rings = NULL; } @@ -1893,9 +1891,9 @@ netxen_tso_check(struct net_device *netdev, protocol = vh->h_vlan_encapsulated_proto; flags = FLAGS_VLAN_TAGGED; - } else if (vlan_tx_tag_present(skb)) { + } else if (skb_vlan_tag_present(skb)) { flags = FLAGS_VLAN_OOB; - vid = vlan_tx_tag_get(skb); + vid = skb_vlan_tag_get(skb); netxen_set_tx_vlan_tci(first_desc, vid); vlan_oob = 1; } @@ -2388,7 +2386,10 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget) work_done = netxen_process_rcv_ring(sds_ring, budget); - if ((work_done < budget) && tx_complete) { + if (!tx_complete) + work_done = budget; + + if (work_done < budget) { napi_complete(&sds_ring->napi); if (test_bit(__NX_DEV_UP, &adapter->state)) netxen_nic_enable_int(sds_ring); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 18e5de72e9b4..d4b5085a21fa 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "qlcnic.h" @@ -320,8 +321,8 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, if (protocol == ETH_P_8021Q) { vh = (struct vlan_ethhdr *)skb->data; vlan_id = ntohs(vh->h_vlan_TCI); - } else if (vlan_tx_tag_present(skb)) { - vlan_id = vlan_tx_tag_get(skb); + } else if (skb_vlan_tag_present(skb)) { + vlan_id = skb_vlan_tag_get(skb); } } @@ -472,9 +473,9 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter, flags = QLCNIC_FLAGS_VLAN_TAGGED; vlan_tci = ntohs(vh->h_vlan_TCI); protocol = ntohs(vh->h_vlan_encapsulated_proto); - } else if (vlan_tx_tag_present(skb)) { + } else if (skb_vlan_tag_present(skb)) { flags = QLCNIC_FLAGS_VLAN_OOB; - vlan_tci = vlan_tx_tag_get(skb); + vlan_tci = skb_vlan_tag_get(skb); } if (unlikely(adapter->tx_pvid)) { if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED)) @@ -967,7 +968,12 @@ static int qlcnic_poll(struct napi_struct *napi, int budget) tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, budget); work_done = qlcnic_process_rcv_ring(sds_ring, budget); - if ((work_done < budget) && tx_complete) { + + /* Check if we need a repoll */ + if (!tx_complete) + work_done = budget; + + if (work_done < budget) { napi_complete(&sds_ring->napi); if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) { qlcnic_enable_sds_intr(adapter, sds_ring); @@ -992,6 +998,9 @@ static int qlcnic_tx_poll(struct napi_struct *napi, int budget) napi_complete(&tx_ring->napi); if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) qlcnic_enable_tx_intr(adapter, tx_ring); + } else { + /* As qlcnic_process_cmd_ring() returned 0, we need a repoll*/ + work_done = budget; } return work_done; @@ -1465,14 +1474,14 @@ void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, static void dump_skb(struct sk_buff *skb, struct qlcnic_adapter *adapter) { - int i; - unsigned char *data = skb->data; + if (adapter->ahw->msg_enable & NETIF_MSG_DRV) { + char prefix[30]; - pr_info(KERN_INFO "\n"); - for (i = 0; i < skb->len; i++) { - QLCDB(adapter, DRV, "%02x ", data[i]); - if ((i & 0x0f) == 8) - pr_info(KERN_INFO "\n"); + scnprintf(prefix, sizeof(prefix), "%s: %s: ", + dev_name(&adapter->pdev->dev), __func__); + + print_hex_dump_debug(prefix, DUMP_PREFIX_NONE, 16, 1, + skb->data, skb->len, true); } } @@ -1950,7 +1959,12 @@ static int qlcnic_83xx_msix_sriov_vf_poll(struct napi_struct *napi, int budget) tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, budget); work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget); - if ((work_done < budget) && tx_complete) { + + /* Check if we need a repoll */ + if (!tx_complete) + work_done = budget; + + if (work_done < budget) { napi_complete(&sds_ring->napi); qlcnic_enable_sds_intr(adapter, sds_ring); } @@ -1973,7 +1987,12 @@ static int qlcnic_83xx_poll(struct napi_struct *napi, int budget) tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, budget); work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget); - if ((work_done < budget) && tx_complete) { + + /* Check if we need a repoll */ + if (!tx_complete) + work_done = budget; + + if (work_done < budget) { napi_complete(&sds_ring->napi); qlcnic_enable_sds_intr(adapter, sds_ring); } @@ -1995,6 +2014,9 @@ static int qlcnic_83xx_msix_tx_poll(struct napi_struct *napi, int budget) napi_complete(&tx_ring->napi); if (test_bit(__QLCNIC_DEV_UP , &adapter->state)) qlcnic_enable_tx_intr(adapter, tx_ring); + } else { + /* need a repoll */ + work_done = budget; } return work_done; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 2528c3fb6b90..a430a34a4434 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -294,9 +294,7 @@ int qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count) void qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx) { - if (recv_ctx->sds_rings != NULL) - kfree(recv_ctx->sds_rings); - + kfree(recv_ctx->sds_rings); recv_ctx->sds_rings = NULL; } @@ -1257,8 +1255,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) if (ahw->op_mode != QLCNIC_NON_PRIV_FUNC) { if (fw_dump->tmpl_hdr == NULL || adapter->fw_version > prev_fw_version) { - if (fw_dump->tmpl_hdr) - vfree(fw_dump->tmpl_hdr); + vfree(fw_dump->tmpl_hdr); if (!qlcnic_fw_cmd_get_minidump_temp(adapter)) dev_info(&pdev->dev, "Supports FW dump capability\n"); @@ -2374,13 +2371,12 @@ void qlcnic_free_tx_rings(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->drv_tx_rings; ring++) { tx_ring = &adapter->tx_ring[ring]; - if (tx_ring && tx_ring->cmd_buf_arr != NULL) { + if (tx_ring) { vfree(tx_ring->cmd_buf_arr); tx_ring->cmd_buf_arr = NULL; } } - if (adapter->tx_ring != NULL) - kfree(adapter->tx_ring); + kfree(adapter->tx_ring); } int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter, @@ -2758,13 +2754,9 @@ static void qlcnic_remove(struct pci_dev *pdev) } qlcnic_dcb_free(adapter->dcb); - qlcnic_detach(adapter); - - if (adapter->npars != NULL) - kfree(adapter->npars); - if (adapter->eswitch != NULL) - kfree(adapter->eswitch); + kfree(adapter->npars); + kfree(adapter->eswitch); if (qlcnic_82xx_check(adapter)) qlcnic_clr_all_drv_state(adapter, 0); @@ -2932,13 +2924,13 @@ void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter) static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter) { - if (adapter->fhash.fmax && adapter->fhash.fhead) + if (adapter->fhash.fmax) kfree(adapter->fhash.fhead); adapter->fhash.fhead = NULL; adapter->fhash.fmax = 0; - if (adapter->rx_fhash.fmax && adapter->rx_fhash.fhead) + if (adapter->rx_fhash.fmax) kfree(adapter->rx_fhash.fhead); adapter->rx_fhash.fmax = 0; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index c9f57fb84b9e..332bb8a3f430 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c @@ -1407,8 +1407,7 @@ void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *adapter) current_version = qlcnic_83xx_get_fw_version(adapter); if (fw_dump->tmpl_hdr == NULL || current_version > prev_version) { - if (fw_dump->tmpl_hdr) - vfree(fw_dump->tmpl_hdr); + vfree(fw_dump->tmpl_hdr); if (!qlcnic_fw_cmd_get_minidump_temp(adapter)) dev_info(&pdev->dev, "Supports FW dump capability\n"); } diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index 6c904a6cad2a..8011ef3e7707 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -2351,23 +2351,29 @@ static int qlge_update_hw_vlan_features(struct net_device *ndev, { struct ql_adapter *qdev = netdev_priv(ndev); int status = 0; + bool need_restart = netif_running(ndev); - status = ql_adapter_down(qdev); - if (status) { - netif_err(qdev, link, qdev->ndev, - "Failed to bring down the adapter\n"); - return status; + if (need_restart) { + status = ql_adapter_down(qdev); + if (status) { + netif_err(qdev, link, qdev->ndev, + "Failed to bring down the adapter\n"); + return status; + } } /* update the features with resent change */ ndev->features = features; - status = ql_adapter_up(qdev); - if (status) { - netif_err(qdev, link, qdev->ndev, - "Failed to bring up the adapter\n"); - return status; + if (need_restart) { + status = ql_adapter_up(qdev); + if (status) { + netif_err(qdev, link, qdev->ndev, + "Failed to bring up the adapter\n"); + return status; + } } + return status; } @@ -2660,11 +2666,11 @@ static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev) mac_iocb_ptr->frame_len = cpu_to_le16((u16) skb->len); - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { netif_printk(qdev, tx_queued, KERN_DEBUG, qdev->ndev, - "Adding a vlan tag %d.\n", vlan_tx_tag_get(skb)); + "Adding a vlan tag %d.\n", skb_vlan_tag_get(skb)); mac_iocb_ptr->flags3 |= OB_MAC_IOCB_V; - mac_iocb_ptr->vlan_tci = cpu_to_le16(vlan_tx_tag_get(skb)); + mac_iocb_ptr->vlan_tci = cpu_to_le16(skb_vlan_tag_get(skb)); } tso = ql_tso(skb, (struct ob_mac_tso_iocb_req *)mac_iocb_ptr); if (tso < 0) { diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 9c31e46d1eee..d79e33b3c191 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -708,8 +708,8 @@ static void cp_tx (struct cp_private *cp) static inline u32 cp_tx_vlan_tag(struct sk_buff *skb) { - return vlan_tx_tag_present(skb) ? - TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00; + return skb_vlan_tag_present(skb) ? + TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00; } static void unwind_tx_frag_mapping(struct cp_private *cp, struct sk_buff *skb, diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 14a1c5cec3a5..ad0020af2193 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -2073,8 +2073,8 @@ static int rtl8169_set_features(struct net_device *dev, static inline u32 rtl8169_tx_vlan_tag(struct sk_buff *skb) { - return (vlan_tx_tag_present(skb)) ? - TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00; + return (skb_vlan_tag_present(skb)) ? + TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00; } static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb) @@ -4915,7 +4915,7 @@ static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp) RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0); RTL_W8(Config4, RTL_R8(Config4) | Jumbo_En1); - rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT); + rtl_tx_performance_tweak(tp->pci_dev, PCI_EXP_DEVCTL_READRQ_512B); } static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp) @@ -4948,7 +4948,7 @@ static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp) RTL_W8(MaxTxPacketSize, 0x3f); RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0); RTL_W8(Config4, RTL_R8(Config4) | 0x01); - rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT); + rtl_tx_performance_tweak(tp->pci_dev, PCI_EXP_DEVCTL_READRQ_512B); } static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp) @@ -4964,7 +4964,7 @@ static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp) static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp) { rtl_tx_performance_tweak(tp->pci_dev, - (0x2 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN); + PCI_EXP_DEVCTL_READRQ_512B | PCI_EXP_DEVCTL_NOSNOOP_EN); } static void r8168b_0_hw_jumbo_disable(struct rtl8169_private *tp) @@ -7049,6 +7049,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, u32 status, len; u32 opts[2]; int frags; + bool stop_queue; if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) { netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n"); @@ -7105,11 +7106,16 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, tp->cur_tx += frags + 1; - RTL_W8(TxPoll, NPQ); + stop_queue = !TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS); - mmiowb(); + if (!skb->xmit_more || stop_queue || + netif_xmit_stopped(netdev_get_tx_queue(dev, 0))) { + RTL_W8(TxPoll, NPQ); - if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) { + mmiowb(); + } + + if (stop_queue) { /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must * not miss a ring update when it notices a stopped queue. */ diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 37583a9d8853..4da8bd263997 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -396,6 +396,9 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = { [TSU_ADRL31] = 0x01fc, }; +static void sh_eth_rcv_snd_disable(struct net_device *ndev); +static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev); + static bool sh_eth_is_gether(struct sh_eth_private *mdp) { return mdp->reg_offset == sh_eth_offset_gigabit; @@ -498,6 +501,8 @@ static struct sh_eth_cpu_data r8a779x_data = { EESR_ECI, .fdr_value = 0x00000f0f, + .trscer_err_mask = DESC_I_RINT8, + .apr = 1, .mpr = 1, .tpauser = 1, @@ -538,8 +543,6 @@ static struct sh_eth_cpu_data sh7724_data = { EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI, - .trscer_err_mask = DESC_I_RINT8, - .apr = 1, .mpr = 1, .tpauser = 1, @@ -594,7 +597,7 @@ static struct sh_eth_cpu_data sh7757_data = { static void sh_eth_chip_reset_giga(struct net_device *ndev) { int i; - unsigned long mahr[2], malr[2]; + u32 mahr[2], malr[2]; /* save MAHR and MALR */ for (i = 0; i < 2; i++) { @@ -988,7 +991,7 @@ static void read_mac_address(struct net_device *ndev, unsigned char *mac) } } -static unsigned long sh_eth_get_edtrr_trns(struct sh_eth_private *mdp) +static u32 sh_eth_get_edtrr_trns(struct sh_eth_private *mdp) { if (sh_eth_is_gether(mdp) || sh_eth_is_rz_fast_ether(mdp)) return EDTRR_TRNS_GETHER; @@ -1120,6 +1123,7 @@ static void sh_eth_ring_format(struct net_device *ndev) int rx_ringsize = sizeof(*rxdesc) * mdp->num_rx_ring; int tx_ringsize = sizeof(*txdesc) * mdp->num_tx_ring; int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN - 1; + dma_addr_t dma_addr; mdp->cur_rx = 0; mdp->cur_tx = 0; @@ -1133,7 +1137,6 @@ static void sh_eth_ring_format(struct net_device *ndev) /* skb */ mdp->rx_skbuff[i] = NULL; skb = netdev_alloc_skb(ndev, skbuff_size); - mdp->rx_skbuff[i] = skb; if (skb == NULL) break; sh_eth_set_receive_align(skb); @@ -1142,9 +1145,15 @@ static void sh_eth_ring_format(struct net_device *ndev) rxdesc = &mdp->rx_ring[i]; /* The size of the buffer is a multiple of 16 bytes. */ rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16); - dma_map_single(&ndev->dev, skb->data, rxdesc->buffer_length, - DMA_FROM_DEVICE); - rxdesc->addr = virt_to_phys(skb->data); + dma_addr = dma_map_single(&ndev->dev, skb->data, + rxdesc->buffer_length, + DMA_FROM_DEVICE); + if (dma_mapping_error(&ndev->dev, dma_addr)) { + kfree_skb(skb); + break; + } + mdp->rx_skbuff[i] = skb; + rxdesc->addr = dma_addr; rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP); /* Rx descriptor address set */ @@ -1316,8 +1325,10 @@ static int sh_eth_dev_init(struct net_device *ndev, bool start) RFLR); sh_eth_write(ndev, sh_eth_read(ndev, EESR), EESR); - if (start) + if (start) { + mdp->irq_enabled = true; sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR); + } /* PAUSE Prohibition */ val = (sh_eth_read(ndev, ECMR) & ECMR_DM) | @@ -1356,6 +1367,33 @@ static int sh_eth_dev_init(struct net_device *ndev, bool start) return ret; } +static void sh_eth_dev_exit(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + int i; + + /* Deactivate all TX descriptors, so DMA should stop at next + * packet boundary if it's currently running + */ + for (i = 0; i < mdp->num_tx_ring; i++) + mdp->tx_ring[i].status &= ~cpu_to_edmac(mdp, TD_TACT); + + /* Disable TX FIFO egress to MAC */ + sh_eth_rcv_snd_disable(ndev); + + /* Stop RX DMA at next packet boundary */ + sh_eth_write(ndev, 0, EDRRR); + + /* Aside from TX DMA, we can't tell when the hardware is + * really stopped, so we need to reset to make sure. + * Before doing that, wait for long enough to *probably* + * finish transmitting the last packet and poll stats. + */ + msleep(2); /* max frame time at 10 Mbps < 1250 us */ + sh_eth_get_stats(ndev); + sh_eth_reset(ndev); +} + /* free Tx skb function */ static int sh_eth_txfree(struct net_device *ndev) { @@ -1400,6 +1438,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) u16 pkt_len = 0; u32 desc_status; int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN - 1; + dma_addr_t dma_addr; boguscnt = min(boguscnt, *quota); limit = boguscnt; @@ -1447,9 +1486,9 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) mdp->rx_skbuff[entry] = NULL; if (mdp->cd->rpadir) skb_reserve(skb, NET_IP_ALIGN); - dma_sync_single_for_cpu(&ndev->dev, rxdesc->addr, - ALIGN(mdp->rx_buf_sz, 16), - DMA_FROM_DEVICE); + dma_unmap_single(&ndev->dev, rxdesc->addr, + ALIGN(mdp->rx_buf_sz, 16), + DMA_FROM_DEVICE); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, ndev); netif_receive_skb(skb); @@ -1469,15 +1508,20 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) if (mdp->rx_skbuff[entry] == NULL) { skb = netdev_alloc_skb(ndev, skbuff_size); - mdp->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ sh_eth_set_receive_align(skb); - dma_map_single(&ndev->dev, skb->data, - rxdesc->buffer_length, DMA_FROM_DEVICE); + dma_addr = dma_map_single(&ndev->dev, skb->data, + rxdesc->buffer_length, + DMA_FROM_DEVICE); + if (dma_mapping_error(&ndev->dev, dma_addr)) { + kfree_skb(skb); + break; + } + mdp->rx_skbuff[entry] = skb; skb_checksum_none_assert(skb); - rxdesc->addr = virt_to_phys(skb->data); + rxdesc->addr = dma_addr; } if (entry >= mdp->num_rx_ring - 1) rxdesc->status |= @@ -1521,7 +1565,7 @@ static void sh_eth_rcv_snd_enable(struct net_device *ndev) } /* error control function */ -static void sh_eth_error(struct net_device *ndev, int intr_status) +static void sh_eth_error(struct net_device *ndev, u32 intr_status) { struct sh_eth_private *mdp = netdev_priv(ndev); u32 felic_stat; @@ -1573,7 +1617,6 @@ ignore_link: if (intr_status & EESR_RFRMER) { /* Receive Frame Overflow int */ ndev->stats.rx_frame_errors++; - netif_err(mdp, rx_err, ndev, "Receive Abort\n"); } } @@ -1592,13 +1635,11 @@ ignore_link: if (intr_status & EESR_RDE) { /* Receive Descriptor Empty int */ ndev->stats.rx_over_errors++; - netif_err(mdp, rx_err, ndev, "Receive Descriptor Empty\n"); } if (intr_status & EESR_RFE) { /* Receive FIFO Overflow int */ ndev->stats.rx_fifo_errors++; - netif_err(mdp, rx_err, ndev, "Receive FIFO Overflow\n"); } if (!mdp->cd->no_ade && (intr_status & EESR_ADE)) { @@ -1637,7 +1678,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) struct sh_eth_private *mdp = netdev_priv(ndev); struct sh_eth_cpu_data *cd = mdp->cd; irqreturn_t ret = IRQ_NONE; - unsigned long intr_status, intr_enable; + u32 intr_status, intr_enable; spin_lock(&mdp->lock); @@ -1653,7 +1694,12 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) if (intr_status & (EESR_RX_CHECK | cd->tx_check | cd->eesr_err_check)) ret = IRQ_HANDLED; else - goto other_irq; + goto out; + + if (!likely(mdp->irq_enabled)) { + sh_eth_write(ndev, 0, EESIPR); + goto out; + } if (intr_status & EESR_RX_CHECK) { if (napi_schedule_prep(&mdp->napi)) { @@ -1663,7 +1709,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) __napi_schedule(&mdp->napi); } else { netdev_warn(ndev, - "ignoring interrupt, status 0x%08lx, mask 0x%08lx.\n", + "ignoring interrupt, status 0x%08x, mask 0x%08x.\n", intr_status, intr_enable); } } @@ -1684,7 +1730,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) sh_eth_error(ndev, intr_status); } -other_irq: +out: spin_unlock(&mdp->lock); return ret; @@ -1696,7 +1742,7 @@ static int sh_eth_poll(struct napi_struct *napi, int budget) napi); struct net_device *ndev = napi->dev; int quota = budget; - unsigned long intr_status; + u32 intr_status; for (;;) { intr_status = sh_eth_read(ndev, EESR); @@ -1712,7 +1758,8 @@ static int sh_eth_poll(struct napi_struct *napi, int budget) napi_complete(napi); /* Reenable Rx interrupts */ - sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR); + if (mdp->irq_enabled) + sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR); out: return budget - quota; } @@ -1827,6 +1874,9 @@ static int sh_eth_get_settings(struct net_device *ndev, unsigned long flags; int ret; + if (!mdp->phydev) + return -ENODEV; + spin_lock_irqsave(&mdp->lock, flags); ret = phy_ethtool_gset(mdp->phydev, ecmd); spin_unlock_irqrestore(&mdp->lock, flags); @@ -1841,6 +1891,9 @@ static int sh_eth_set_settings(struct net_device *ndev, unsigned long flags; int ret; + if (!mdp->phydev) + return -ENODEV; + spin_lock_irqsave(&mdp->lock, flags); /* disable tx and rx */ @@ -1875,6 +1928,9 @@ static int sh_eth_nway_reset(struct net_device *ndev) unsigned long flags; int ret; + if (!mdp->phydev) + return -ENODEV; + spin_lock_irqsave(&mdp->lock, flags); ret = phy_start_aneg(mdp->phydev); spin_unlock_irqrestore(&mdp->lock, flags); @@ -1959,40 +2015,50 @@ static int sh_eth_set_ringparam(struct net_device *ndev, return -EINVAL; if (netif_running(ndev)) { + netif_device_detach(ndev); netif_tx_disable(ndev); - /* Disable interrupts by clearing the interrupt mask. */ - sh_eth_write(ndev, 0x0000, EESIPR); - /* Stop the chip's Tx and Rx processes. */ - sh_eth_write(ndev, 0, EDTRR); - sh_eth_write(ndev, 0, EDRRR); - synchronize_irq(ndev->irq); - } - /* Free all the skbuffs in the Rx queue. */ - sh_eth_ring_free(ndev); - /* Free DMA buffer */ - sh_eth_free_dma_buffer(mdp); + /* Serialise with the interrupt handler and NAPI, then + * disable interrupts. We have to clear the + * irq_enabled flag first to ensure that interrupts + * won't be re-enabled. + */ + mdp->irq_enabled = false; + synchronize_irq(ndev->irq); + napi_synchronize(&mdp->napi); + sh_eth_write(ndev, 0x0000, EESIPR); + + sh_eth_dev_exit(ndev); + + /* Free all the skbuffs in the Rx queue. */ + sh_eth_ring_free(ndev); + /* Free DMA buffer */ + sh_eth_free_dma_buffer(mdp); + } /* Set new parameters */ mdp->num_rx_ring = ring->rx_pending; mdp->num_tx_ring = ring->tx_pending; - ret = sh_eth_ring_init(ndev); - if (ret < 0) { - netdev_err(ndev, "%s: sh_eth_ring_init failed.\n", __func__); - return ret; - } - ret = sh_eth_dev_init(ndev, false); - if (ret < 0) { - netdev_err(ndev, "%s: sh_eth_dev_init failed.\n", __func__); - return ret; - } - if (netif_running(ndev)) { + ret = sh_eth_ring_init(ndev); + if (ret < 0) { + netdev_err(ndev, "%s: sh_eth_ring_init failed.\n", + __func__); + return ret; + } + ret = sh_eth_dev_init(ndev, false); + if (ret < 0) { + netdev_err(ndev, "%s: sh_eth_dev_init failed.\n", + __func__); + return ret; + } + + mdp->irq_enabled = true; sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR); /* Setting the Rx mode will start the Rx process. */ sh_eth_write(ndev, EDRRR_R, EDRRR); - netif_wake_queue(ndev); + netif_device_attach(ndev); } return 0; @@ -2067,7 +2133,7 @@ static void sh_eth_tx_timeout(struct net_device *ndev) netif_err(mdp, timer, ndev, "transmit timed out, status %8.8x, resetting...\n", - (int)sh_eth_read(ndev, EESR)); + sh_eth_read(ndev, EESR)); /* tx_errors count up */ ndev->stats.tx_errors++; @@ -2108,6 +2174,9 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) } spin_unlock_irqrestore(&mdp->lock, flags); + if (skb_padto(skb, ETH_ZLEN)) + return NETDEV_TX_OK; + entry = mdp->cur_tx % mdp->num_tx_ring; mdp->tx_skbuff[entry] = skb; txdesc = &mdp->tx_ring[entry]; @@ -2117,10 +2186,11 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) skb->len + 2); txdesc->addr = dma_map_single(&ndev->dev, skb->data, skb->len, DMA_TO_DEVICE); - if (skb->len < ETH_ZLEN) - txdesc->buffer_length = ETH_ZLEN; - else - txdesc->buffer_length = skb->len; + if (dma_mapping_error(&ndev->dev, txdesc->addr)) { + kfree_skb(skb); + return NETDEV_TX_OK; + } + txdesc->buffer_length = skb->len; if (entry >= mdp->num_tx_ring - 1) txdesc->status |= cpu_to_edmac(mdp, TD_TACT | TD_TDLE); @@ -2172,24 +2242,26 @@ static int sh_eth_close(struct net_device *ndev) netif_stop_queue(ndev); - /* Disable interrupts by clearing the interrupt mask. */ + /* Serialise with the interrupt handler and NAPI, then disable + * interrupts. We have to clear the irq_enabled flag first to + * ensure that interrupts won't be re-enabled. + */ + mdp->irq_enabled = false; + synchronize_irq(ndev->irq); + napi_disable(&mdp->napi); sh_eth_write(ndev, 0x0000, EESIPR); - /* Stop the chip's Tx and Rx processes. */ - sh_eth_write(ndev, 0, EDTRR); - sh_eth_write(ndev, 0, EDRRR); + sh_eth_dev_exit(ndev); - sh_eth_get_stats(ndev); /* PHY Disconnect */ if (mdp->phydev) { phy_stop(mdp->phydev); phy_disconnect(mdp->phydev); + mdp->phydev = NULL; } free_irq(ndev->irq, ndev); - napi_disable(&mdp->napi); - /* Free all the skbuffs in the Rx queue. */ sh_eth_ring_free(ndev); @@ -2417,7 +2489,7 @@ static int sh_eth_tsu_purge_all(struct net_device *ndev) struct sh_eth_private *mdp = netdev_priv(ndev); int i, ret; - if (unlikely(!mdp->cd->tsu)) + if (!mdp->cd->tsu) return 0; for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++) { @@ -2440,7 +2512,7 @@ static void sh_eth_tsu_purge_mcast(struct net_device *ndev) void *reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0); int i; - if (unlikely(!mdp->cd->tsu)) + if (!mdp->cd->tsu) return; for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++, reg_offset += 8) { @@ -2450,8 +2522,8 @@ static void sh_eth_tsu_purge_mcast(struct net_device *ndev) } } -/* Multicast reception directions set */ -static void sh_eth_set_multicast_list(struct net_device *ndev) +/* Update promiscuous flag and multicast filter */ +static void sh_eth_set_rx_mode(struct net_device *ndev) { struct sh_eth_private *mdp = netdev_priv(ndev); u32 ecmr_bits; @@ -2462,7 +2534,9 @@ static void sh_eth_set_multicast_list(struct net_device *ndev) /* Initial condition is MCT = 1, PRM = 0. * Depending on ndev->flags, set PRM or clear MCT */ - ecmr_bits = (sh_eth_read(ndev, ECMR) & ~ECMR_PRM) | ECMR_MCT; + ecmr_bits = sh_eth_read(ndev, ECMR) & ~ECMR_PRM; + if (mdp->cd->tsu) + ecmr_bits |= ECMR_MCT; if (!(ndev->flags & IFF_MULTICAST)) { sh_eth_tsu_purge_mcast(ndev); @@ -2491,9 +2565,6 @@ static void sh_eth_set_multicast_list(struct net_device *ndev) } } } - } else { - /* Normal, unicast/broadcast-only mode. */ - ecmr_bits = (ecmr_bits & ~ECMR_PRM) | ECMR_MCT; } /* update the ethernet mode */ @@ -2701,6 +2772,7 @@ static const struct net_device_ops sh_eth_netdev_ops = { .ndo_stop = sh_eth_close, .ndo_start_xmit = sh_eth_start_xmit, .ndo_get_stats = sh_eth_get_stats, + .ndo_set_rx_mode = sh_eth_set_rx_mode, .ndo_tx_timeout = sh_eth_tx_timeout, .ndo_do_ioctl = sh_eth_do_ioctl, .ndo_validate_addr = eth_validate_addr, @@ -2713,7 +2785,7 @@ static const struct net_device_ops sh_eth_netdev_ops_tsu = { .ndo_stop = sh_eth_close, .ndo_start_xmit = sh_eth_start_xmit, .ndo_get_stats = sh_eth_get_stats, - .ndo_set_rx_mode = sh_eth_set_multicast_list, + .ndo_set_rx_mode = sh_eth_set_rx_mode, .ndo_vlan_rx_add_vid = sh_eth_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = sh_eth_vlan_rx_kill_vid, .ndo_tx_timeout = sh_eth_tx_timeout, @@ -2947,6 +3019,36 @@ static int sh_eth_drv_remove(struct platform_device *pdev) } #ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP +static int sh_eth_suspend(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + int ret = 0; + + if (netif_running(ndev)) { + netif_device_detach(ndev); + ret = sh_eth_close(ndev); + } + + return ret; +} + +static int sh_eth_resume(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + int ret = 0; + + if (netif_running(ndev)) { + ret = sh_eth_open(ndev); + if (ret < 0) + return ret; + netif_device_attach(ndev); + } + + return ret; +} +#endif + static int sh_eth_runtime_nop(struct device *dev) { /* Runtime PM callback shared between ->runtime_suspend() @@ -2960,8 +3062,8 @@ static int sh_eth_runtime_nop(struct device *dev) } static const struct dev_pm_ops sh_eth_dev_pm_ops = { - .runtime_suspend = sh_eth_runtime_nop, - .runtime_resume = sh_eth_runtime_nop, + SET_SYSTEM_SLEEP_PM_OPS(sh_eth_suspend, sh_eth_resume) + SET_RUNTIME_PM_OPS(sh_eth_runtime_nop, sh_eth_runtime_nop, NULL) }; #define SH_ETH_PM_OPS (&sh_eth_dev_pm_ops) #else diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index 71f5de1171bd..259d03f353e1 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -459,21 +459,21 @@ struct sh_eth_cpu_data { /* mandatory initialize value */ int register_type; - unsigned long eesipr_value; + u32 eesipr_value; /* optional initialize value */ - unsigned long ecsr_value; - unsigned long ecsipr_value; - unsigned long fdr_value; - unsigned long fcftr_value; - unsigned long rpadir_value; + u32 ecsr_value; + u32 ecsipr_value; + u32 fdr_value; + u32 fcftr_value; + u32 rpadir_value; /* interrupt checking mask */ - unsigned long tx_check; - unsigned long eesr_err_check; + u32 tx_check; + u32 eesr_err_check; /* Error mask */ - unsigned long trscer_err_mask; + u32 trscer_err_mask; /* hardware features */ unsigned long irq_flags; /* IRQ configuration flags */ @@ -513,6 +513,7 @@ struct sh_eth_private { u32 rx_buf_sz; /* Based on MTU+slack. */ int edmac_endian; struct napi_struct napi; + bool irq_enabled; /* MII transceiver section. */ u32 phy_id; /* PHY ID */ struct mii_bus *mii_bus; /* MDIO bus control */ @@ -542,7 +543,7 @@ static inline void sh_eth_soft_swap(char *src, int len) #endif } -static inline void sh_eth_write(struct net_device *ndev, unsigned long data, +static inline void sh_eth_write(struct net_device *ndev, u32 data, int enum_index) { struct sh_eth_private *mdp = netdev_priv(ndev); @@ -550,8 +551,7 @@ static inline void sh_eth_write(struct net_device *ndev, unsigned long data, iowrite32(data, mdp->addr + mdp->reg_offset[enum_index]); } -static inline unsigned long sh_eth_read(struct net_device *ndev, - int enum_index) +static inline u32 sh_eth_read(struct net_device *ndev, int enum_index) { struct sh_eth_private *mdp = netdev_priv(ndev); @@ -564,14 +564,13 @@ static inline void *sh_eth_tsu_get_offset(struct sh_eth_private *mdp, return mdp->tsu_addr + mdp->reg_offset[enum_index]; } -static inline void sh_eth_tsu_write(struct sh_eth_private *mdp, - unsigned long data, int enum_index) +static inline void sh_eth_tsu_write(struct sh_eth_private *mdp, u32 data, + int enum_index) { iowrite32(data, mdp->tsu_addr + mdp->reg_offset[enum_index]); } -static inline unsigned long sh_eth_tsu_read(struct sh_eth_private *mdp, - int enum_index) +static inline u32 sh_eth_tsu_read(struct sh_eth_private *mdp, int enum_index) { return ioread32(mdp->tsu_addr + mdp->reg_offset[enum_index]); } diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 2f398fa4b9e6..34389b6aa67c 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -806,13 +806,13 @@ static bool rocker_desc_gen(struct rocker_desc_info *desc_info) static void *rocker_desc_cookie_ptr_get(struct rocker_desc_info *desc_info) { - return (void *) desc_info->desc->cookie; + return (void *)(uintptr_t)desc_info->desc->cookie; } static void rocker_desc_cookie_ptr_set(struct rocker_desc_info *desc_info, void *ptr) { - desc_info->desc->cookie = (long) ptr; + desc_info->desc->cookie = (uintptr_t) ptr; } static struct rocker_desc_info * @@ -3026,11 +3026,17 @@ static void rocker_port_fdb_learn_work(struct work_struct *work) container_of(work, struct rocker_fdb_learn_work, work); bool removing = (lw->flags & ROCKER_OP_FLAG_REMOVE); bool learned = (lw->flags & ROCKER_OP_FLAG_LEARNED); + struct netdev_switch_notifier_fdb_info info; + + info.addr = lw->addr; + info.vid = lw->vid; if (learned && removing) - br_fdb_external_learn_del(lw->dev, lw->addr, lw->vid); + call_netdev_switch_notifiers(NETDEV_SWITCH_FDB_DEL, + lw->dev, &info.info); else if (learned && !removing) - br_fdb_external_learn_add(lw->dev, lw->addr, lw->vid); + call_netdev_switch_notifiers(NETDEV_SWITCH_FDB_ADD, + lw->dev, &info.info); kfree(work); } @@ -3565,6 +3571,8 @@ nest_cancel: rocker_tlv_nest_cancel(desc_info, frags); out: dev_kfree_skb(skb); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; } @@ -3668,7 +3676,8 @@ static int rocker_fdb_fill_info(struct sk_buff *skb, if (vid && nla_put_u16(skb, NDA_VLAN, vid)) goto nla_put_failure; - return nlmsg_end(skb, nlh); + nlmsg_end(skb, nlh); + return 0; nla_put_failure: nlmsg_cancel(skb, nlh); @@ -3713,7 +3722,7 @@ skip: } static int rocker_port_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh) + struct nlmsghdr *nlh, u16 flags) { struct rocker_port *rocker_port = netdev_priv(dev); struct nlattr *protinfo; @@ -3824,11 +3833,145 @@ static void rocker_port_get_drvinfo(struct net_device *dev, strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version)); } +static struct rocker_port_stats { + char str[ETH_GSTRING_LEN]; + int type; +} rocker_port_stats[] = { + { "rx_packets", ROCKER_TLV_CMD_PORT_STATS_RX_PKTS, }, + { "rx_bytes", ROCKER_TLV_CMD_PORT_STATS_RX_BYTES, }, + { "rx_dropped", ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, }, + { "rx_errors", ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS, }, + + { "tx_packets", ROCKER_TLV_CMD_PORT_STATS_TX_PKTS, }, + { "tx_bytes", ROCKER_TLV_CMD_PORT_STATS_TX_BYTES, }, + { "tx_dropped", ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, }, + { "tx_errors", ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS, }, +}; + +#define ROCKER_PORT_STATS_LEN ARRAY_SIZE(rocker_port_stats) + +static void rocker_port_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) { + memcpy(p, rocker_port_stats[i].str, ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static int +rocker_cmd_get_port_stats_prep(struct rocker *rocker, + struct rocker_port *rocker_port, + struct rocker_desc_info *desc_info, + void *priv) +{ + struct rocker_tlv *cmd_stats; + + if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, + ROCKER_TLV_CMD_TYPE_GET_PORT_STATS)) + return -EMSGSIZE; + + cmd_stats = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO); + if (!cmd_stats) + return -EMSGSIZE; + + if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_STATS_LPORT, + rocker_port->lport)) + return -EMSGSIZE; + + rocker_tlv_nest_end(desc_info, cmd_stats); + + return 0; +} + +static int +rocker_cmd_get_port_stats_ethtool_proc(struct rocker *rocker, + struct rocker_port *rocker_port, + struct rocker_desc_info *desc_info, + void *priv) +{ + struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1]; + struct rocker_tlv *stats_attrs[ROCKER_TLV_CMD_PORT_STATS_MAX + 1]; + struct rocker_tlv *pattr; + u32 lport; + u64 *data = priv; + int i; + + rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info); + + if (!attrs[ROCKER_TLV_CMD_INFO]) + return -EIO; + + rocker_tlv_parse_nested(stats_attrs, ROCKER_TLV_CMD_PORT_STATS_MAX, + attrs[ROCKER_TLV_CMD_INFO]); + + if (!stats_attrs[ROCKER_TLV_CMD_PORT_STATS_LPORT]) + return -EIO; + + lport = rocker_tlv_get_u32(stats_attrs[ROCKER_TLV_CMD_PORT_STATS_LPORT]); + if (lport != rocker_port->lport) + return -EIO; + + for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) { + pattr = stats_attrs[rocker_port_stats[i].type]; + if (!pattr) + continue; + + data[i] = rocker_tlv_get_u64(pattr); + } + + return 0; +} + +static int rocker_cmd_get_port_stats_ethtool(struct rocker_port *rocker_port, + void *priv) +{ + return rocker_cmd_exec(rocker_port->rocker, rocker_port, + rocker_cmd_get_port_stats_prep, NULL, + rocker_cmd_get_port_stats_ethtool_proc, + priv, false); +} + +static void rocker_port_get_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct rocker_port *rocker_port = netdev_priv(dev); + + if (rocker_cmd_get_port_stats_ethtool(rocker_port, data) != 0) { + int i; + + for (i = 0; i < ARRAY_SIZE(rocker_port_stats); ++i) + data[i] = 0; + } + + return; +} + +static int rocker_port_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ROCKER_PORT_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + static const struct ethtool_ops rocker_port_ethtool_ops = { .get_settings = rocker_port_get_settings, .set_settings = rocker_port_set_settings, .get_drvinfo = rocker_port_get_drvinfo, .get_link = ethtool_op_get_link, + .get_strings = rocker_port_get_strings, + .get_ethtool_stats = rocker_port_get_stats, + .get_sset_count = rocker_port_get_sset_count, }; /***************** @@ -3850,12 +3993,22 @@ static int rocker_port_poll_tx(struct napi_struct *napi, int budget) /* Cleanup tx descriptors */ while ((desc_info = rocker_desc_tail_get(&rocker_port->tx_ring))) { + struct sk_buff *skb; + err = rocker_desc_err(desc_info); if (err && net_ratelimit()) netdev_err(rocker_port->dev, "tx desc received with err %d\n", err); rocker_tx_desc_frags_unmap(rocker_port, desc_info); - dev_kfree_skb_any(rocker_desc_cookie_ptr_get(desc_info)); + + skb = rocker_desc_cookie_ptr_get(desc_info); + if (err == 0) { + rocker_port->dev->stats.tx_packets++; + rocker_port->dev->stats.tx_bytes += skb->len; + } else + rocker_port->dev->stats.tx_errors++; + + dev_kfree_skb_any(skb); credits++; } @@ -3888,6 +4041,10 @@ static int rocker_port_rx_proc(struct rocker *rocker, rx_len = rocker_tlv_get_u16(attrs[ROCKER_TLV_RX_FRAG_LEN]); skb_put(skb, rx_len); skb->protocol = eth_type_trans(skb, rocker_port->dev); + + rocker_port->dev->stats.rx_packets++; + rocker_port->dev->stats.rx_bytes += skb->len; + netif_receive_skb(skb); return rocker_dma_rx_ring_skb_alloc(rocker, rocker_port, desc_info); @@ -3921,6 +4078,9 @@ static int rocker_port_poll_rx(struct napi_struct *napi, int budget) netdev_err(rocker_port->dev, "rx processing failed with err %d\n", err); } + if (err) + rocker_port->dev->stats.rx_errors++; + rocker_desc_gen_clear(desc_info); rocker_desc_head_set(rocker, &rocker_port->rx_ring, desc_info); credits++; @@ -4004,7 +4164,8 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) NAPI_POLL_WEIGHT); rocker_carrier_init(rocker_port); - dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; + dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | + NETIF_F_HW_SWITCH_OFFLOAD; err = register_netdev(dev); if (err) { diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h index 8d2865ba634c..a5bc432feada 100644 --- a/drivers/net/ethernet/rocker/rocker.h +++ b/drivers/net/ethernet/rocker/rocker.h @@ -127,6 +127,9 @@ enum { ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL, ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS, + ROCKER_TLV_CMD_TYPE_CLEAR_PORT_STATS, + ROCKER_TLV_CMD_TYPE_GET_PORT_STATS, + __ROCKER_TLV_CMD_TYPE_MAX, ROCKER_TLV_CMD_TYPE_MAX = __ROCKER_TLV_CMD_TYPE_MAX - 1, }; @@ -146,6 +149,24 @@ enum { __ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1, }; +enum { + ROCKER_TLV_CMD_PORT_STATS_UNSPEC, + ROCKER_TLV_CMD_PORT_STATS_LPORT, /* u32 */ + + ROCKER_TLV_CMD_PORT_STATS_RX_PKTS, /* u64 */ + ROCKER_TLV_CMD_PORT_STATS_RX_BYTES, /* u64 */ + ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, /* u64 */ + ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS, /* u64 */ + + ROCKER_TLV_CMD_PORT_STATS_TX_PKTS, /* u64 */ + ROCKER_TLV_CMD_PORT_STATS_TX_BYTES, /* u64 */ + ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, /* u64 */ + ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS, /* u64 */ + + __ROCKER_TLV_CMD_PORT_STATS_MAX, + ROCKER_TLV_CMD_PORT_STATS_MAX = __ROCKER_TLV_CMD_PORT_STATS_MAX - 1, +}; + enum rocker_port_mode { ROCKER_PORT_MODE_OF_DPA, }; diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index 698494481d18..c8a01ee4d25e 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -133,9 +133,8 @@ bool sxgbe_eee_init(struct sxgbe_priv_data * const priv) return false; priv->eee_active = 1; - init_timer(&priv->eee_ctrl_timer); - priv->eee_ctrl_timer.function = sxgbe_eee_ctrl_timer; - priv->eee_ctrl_timer.data = (unsigned long)priv; + setup_timer(&priv->eee_ctrl_timer, sxgbe_eee_ctrl_timer, + (unsigned long)priv); priv->eee_ctrl_timer.expires = SXGBE_LPI_TIMER(eee_timer); add_timer(&priv->eee_ctrl_timer); @@ -365,6 +364,26 @@ static int sxgbe_init_rx_buffers(struct net_device *dev, return 0; } + +/** + * sxgbe_free_rx_buffers - free what sxgbe_init_rx_buffers() allocated + * @dev: net device structure + * @rx_ring: ring to be freed + * @rx_rsize: ring size + * Description: this function initializes the DMA RX descriptor + */ +static void sxgbe_free_rx_buffers(struct net_device *dev, + struct sxgbe_rx_norm_desc *p, int i, + unsigned int dma_buf_sz, + struct sxgbe_rx_queue *rx_ring) +{ + struct sxgbe_priv_data *priv = netdev_priv(dev); + + kfree_skb(rx_ring->rx_skbuff[i]); + dma_unmap_single(priv->device, rx_ring->rx_skbuff_dma[i], + dma_buf_sz, DMA_FROM_DEVICE); +} + /** * init_tx_ring - init the TX descriptor ring * @dev: net device structure @@ -457,7 +476,7 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no, /* RX ring is not allcoated */ if (rx_ring == NULL) { netdev_err(dev, "No memory for RX queue\n"); - goto error; + return -ENOMEM; } /* assign queue number */ @@ -469,18 +488,22 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no, &rx_ring->dma_rx_phy, GFP_KERNEL); if (rx_ring->dma_rx == NULL) - goto error; + return -ENOMEM; /* allocate memory for RX skbuff array */ rx_ring->rx_skbuff_dma = kmalloc_array(rx_rsize, sizeof(dma_addr_t), GFP_KERNEL); - if (rx_ring->rx_skbuff_dma == NULL) - goto dmamem_err; + if (!rx_ring->rx_skbuff_dma) { + ret = -ENOMEM; + goto err_free_dma_rx; + } rx_ring->rx_skbuff = kmalloc_array(rx_rsize, sizeof(struct sk_buff *), GFP_KERNEL); - if (rx_ring->rx_skbuff == NULL) - goto rxbuff_err; + if (!rx_ring->rx_skbuff) { + ret = -ENOMEM; + goto err_free_skbuff_dma; + } /* initialise the buffers */ for (desc_index = 0; desc_index < rx_rsize; desc_index++) { @@ -489,7 +512,7 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no, ret = sxgbe_init_rx_buffers(dev, p, desc_index, bfsize, rx_ring); if (ret) - goto err_init_rx_buffers; + goto err_free_rx_buffers; } /* initalise counters */ @@ -499,18 +522,22 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no, return 0; -err_init_rx_buffers: - while (--desc_index >= 0) - free_rx_ring(priv->device, rx_ring, desc_index); +err_free_rx_buffers: + while (--desc_index >= 0) { + struct sxgbe_rx_norm_desc *p; + + p = rx_ring->dma_rx + desc_index; + sxgbe_free_rx_buffers(dev, p, desc_index, bfsize, rx_ring); + } kfree(rx_ring->rx_skbuff); -rxbuff_err: +err_free_skbuff_dma: kfree(rx_ring->rx_skbuff_dma); -dmamem_err: +err_free_dma_rx: dma_free_coherent(priv->device, rx_rsize * sizeof(struct sxgbe_rx_norm_desc), rx_ring->dma_rx, rx_ring->dma_rx_phy); -error: - return -ENOMEM; + + return ret; } /** * free_tx_ring - free the TX descriptor ring @@ -1009,10 +1036,9 @@ static void sxgbe_tx_init_coalesce(struct sxgbe_priv_data *priv) struct sxgbe_tx_queue *p = priv->txq[queue_num]; p->tx_coal_frames = SXGBE_TX_FRAMES; p->tx_coal_timer = SXGBE_COAL_TX_TIMER; - init_timer(&p->txtimer); + setup_timer(&p->txtimer, sxgbe_tx_timer, + (unsigned long)&priv->txq[queue_num]); p->txtimer.expires = SXGBE_COAL_TIMER(p->tx_coal_timer); - p->txtimer.data = (unsigned long)&priv->txq[queue_num]; - p->txtimer.function = sxgbe_tx_timer; add_timer(&p->txtimer); } } @@ -1274,7 +1300,7 @@ static netdev_tx_t sxgbe_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb_is_gso(skb) && tqueue->prev_mss != cur_mss)) ctxt_desc_req = 1; - if (unlikely(vlan_tx_tag_present(skb) || + if (unlikely(skb_vlan_tag_present(skb) || ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && tqueue->hwts_tx_en))) ctxt_desc_req = 1; diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c index 866560ea9e18..b02eed12bfc5 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c @@ -108,10 +108,6 @@ static int sxgbe_platform_probe(struct platform_device *pdev) } } - /* Get MAC address if available (DT) */ - if (mac) - ether_addr_copy(priv->dev->dev_addr, mac); - priv = sxgbe_drv_probe(&(pdev->dev), plat_dat, addr); if (!priv) { pr_err("%s: main driver probe failed\n", __func__); @@ -125,6 +121,10 @@ static int sxgbe_platform_probe(struct platform_device *pdev) goto err_drv_remove; } + /* Get MAC address if available (DT) */ + if (mac) + ether_addr_copy(priv->dev->dev_addr, mac); + /* Get the TX/RX IRQ numbers */ for (i = 0, chan = 1; i < SXGBE_TX_QUEUES; i++) { priv->txq[i]->irq_no = irq_of_parse_and_map(node, chan++); diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig index 9468e64e6007..3e97a8b43147 100644 --- a/drivers/net/ethernet/smsc/Kconfig +++ b/drivers/net/ethernet/smsc/Kconfig @@ -5,8 +5,9 @@ config NET_VENDOR_SMSC bool "SMC (SMSC)/Western Digital devices" default y - depends on ARM || ISA || MAC || ARM64 || MIPS || M32R || SUPERH || \ - BLACKFIN || MN10300 || COLDFIRE || XTENSA || NIOS2 || PCI || PCMCIA + depends on ARM || ARM64 || ATARI_ETHERNAT || BLACKFIN || COLDFIRE || \ + ISA || M32R || MAC || MIPS || MN10300 || NIOS2 || PCI || \ + PCMCIA || SUPERH || XTENSA ---help--- If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from @@ -38,8 +39,9 @@ config SMC91X tristate "SMC 91C9x/91C1xxx support" select CRC32 select MII - depends on (ARM || M32R || SUPERH || MIPS || BLACKFIN || \ - MN10300 || COLDFIRE || ARM64 || XTENSA || NIOS2) && (!OF || GPIOLIB) + depends on !OF || GPIOLIB + depends on ARM || ARM64 || ATARI_ETHERNAT || BLACKFIN || COLDFIRE || \ + M32R || MIPS || MN10300 || NIOS2 || SUPERH || XTENSA ---help--- This is a driver for SMC's 91x series of Ethernet chipsets, including the SMC91C94 and the SMC91C111. Say Y if you want it diff --git a/drivers/net/ethernet/smsc/smc91x.h b/drivers/net/ethernet/smsc/smc91x.h index 2a38dacbbd27..be67baf5f677 100644 --- a/drivers/net/ethernet/smsc/smc91x.h +++ b/drivers/net/ethernet/smsc/smc91x.h @@ -216,6 +216,27 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #include +#elif defined(CONFIG_ATARI) + +#define SMC_CAN_USE_8BIT 1 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 1 +#define SMC_NOWAIT 1 + +#define SMC_inb(a, r) readb((a) + (r)) +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_inl(a, r) readl((a) + (r)) +#define SMC_outb(v, a, r) writeb(v, (a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_outl(v, a, r) writel(v, (a) + (r)) +#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) +#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) +#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) +#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) + +#define RPC_LSA_DEFAULT RPC_LED_100_10 +#define RPC_LSB_DEFAULT RPC_LED_TX_RX + #elif defined(CONFIG_ARCH_MSM) #define SMC_CAN_USE_8BIT 0 diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index ac4d5629d905..73c2715a27f3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.o \ - dwmac-sti.o dwmac-socfpga.o + dwmac-sti.o dwmac-socfpga.o dwmac-rk.o obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o stmmac-pci-objs:= stmmac_pci.o diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c new file mode 100644 index 000000000000..6249a4ec08f0 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -0,0 +1,437 @@ +/** + * dwmac-rk.c - Rockchip RK3288 DWMAC specific glue layer + * + * Copyright (C) 2014 Chen-Zhi (Roger Chen) + * + * Chen-Zhi (Roger Chen) + * + * 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 + +struct rk_priv_data { + struct platform_device *pdev; + int phy_iface; + struct regulator *regulator; + + bool clk_enabled; + bool clock_input; + + struct clk *clk_mac; + struct clk *clk_mac_pll; + struct clk *gmac_clkin; + struct clk *mac_clk_rx; + struct clk *mac_clk_tx; + struct clk *clk_mac_ref; + struct clk *clk_mac_refout; + struct clk *aclk_mac; + struct clk *pclk_mac; + + int tx_delay; + int rx_delay; + + struct regmap *grf; +}; + +#define HIWORD_UPDATE(val, mask, shift) \ + ((val) << (shift) | (mask) << ((shift) + 16)) + +#define GRF_BIT(nr) (BIT(nr) | BIT(nr+16)) +#define GRF_CLR_BIT(nr) (BIT(nr+16)) + +#define RK3288_GRF_SOC_CON1 0x0248 +#define RK3288_GRF_SOC_CON3 0x0250 +#define RK3288_GRF_GPIO3D_E 0x01ec +#define RK3288_GRF_GPIO4A_E 0x01f0 +#define RK3288_GRF_GPIO4B_E 0x01f4 + +/*RK3288_GRF_SOC_CON1*/ +#define GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(6) | GRF_CLR_BIT(7) | GRF_CLR_BIT(8)) +#define GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | GRF_BIT(8)) +#define GMAC_FLOW_CTRL GRF_BIT(9) +#define GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9) +#define GMAC_SPEED_10M GRF_CLR_BIT(10) +#define GMAC_SPEED_100M GRF_BIT(10) +#define GMAC_RMII_CLK_25M GRF_BIT(11) +#define GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11) +#define GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13)) +#define GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13)) +#define GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13)) +#define GMAC_RMII_MODE GRF_BIT(14) +#define GMAC_RMII_MODE_CLR GRF_CLR_BIT(14) + +/*RK3288_GRF_SOC_CON3*/ +#define GMAC_TXCLK_DLY_ENABLE GRF_BIT(14) +#define GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14) +#define GMAC_RXCLK_DLY_ENABLE GRF_BIT(15) +#define GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15) +#define GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7) +#define GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) + +static void set_to_rgmii(struct rk_priv_data *bsp_priv, + int tx_delay, int rx_delay) +{ + struct device *dev = &bsp_priv->pdev->dev; + + if (IS_ERR(bsp_priv->grf)) { + dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); + return; + } + + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, + GMAC_PHY_INTF_SEL_RGMII | GMAC_RMII_MODE_CLR); + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3, + GMAC_RXCLK_DLY_ENABLE | GMAC_TXCLK_DLY_ENABLE | + GMAC_CLK_RX_DL_CFG(rx_delay) | + GMAC_CLK_TX_DL_CFG(tx_delay)); +} + +static void set_to_rmii(struct rk_priv_data *bsp_priv) +{ + struct device *dev = &bsp_priv->pdev->dev; + + if (IS_ERR(bsp_priv->grf)) { + dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); + return; + } + + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, + GMAC_PHY_INTF_SEL_RMII | GMAC_RMII_MODE); +} + +static void set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) +{ + struct device *dev = &bsp_priv->pdev->dev; + + if (IS_ERR(bsp_priv->grf)) { + dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); + return; + } + + if (speed == 10) + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_2_5M); + else if (speed == 100) + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_25M); + else if (speed == 1000) + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_125M); + else + dev_err(dev, "unknown speed value for RGMII! speed=%d", speed); +} + +static void set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) +{ + struct device *dev = &bsp_priv->pdev->dev; + + if (IS_ERR(bsp_priv->grf)) { + dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); + return; + } + + if (speed == 10) { + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, + GMAC_RMII_CLK_2_5M | GMAC_SPEED_10M); + } else if (speed == 100) { + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, + GMAC_RMII_CLK_25M | GMAC_SPEED_100M); + } else { + dev_err(dev, "unknown speed value for RMII! speed=%d", speed); + } +} + +static int gmac_clk_init(struct rk_priv_data *bsp_priv) +{ + struct device *dev = &bsp_priv->pdev->dev; + + bsp_priv->clk_enabled = false; + + bsp_priv->mac_clk_rx = devm_clk_get(dev, "mac_clk_rx"); + if (IS_ERR(bsp_priv->mac_clk_rx)) + dev_err(dev, "%s: cannot get clock %s\n", + __func__, "mac_clk_rx"); + + bsp_priv->mac_clk_tx = devm_clk_get(dev, "mac_clk_tx"); + if (IS_ERR(bsp_priv->mac_clk_tx)) + dev_err(dev, "%s: cannot get clock %s\n", + __func__, "mac_clk_tx"); + + bsp_priv->aclk_mac = devm_clk_get(dev, "aclk_mac"); + if (IS_ERR(bsp_priv->aclk_mac)) + dev_err(dev, "%s: cannot get clock %s\n", + __func__, "aclk_mac"); + + bsp_priv->pclk_mac = devm_clk_get(dev, "pclk_mac"); + if (IS_ERR(bsp_priv->pclk_mac)) + dev_err(dev, "%s: cannot get clock %s\n", + __func__, "pclk_mac"); + + bsp_priv->clk_mac = devm_clk_get(dev, "stmmaceth"); + if (IS_ERR(bsp_priv->clk_mac)) + dev_err(dev, "%s: cannot get clock %s\n", + __func__, "stmmaceth"); + + if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) { + bsp_priv->clk_mac_ref = devm_clk_get(dev, "clk_mac_ref"); + if (IS_ERR(bsp_priv->clk_mac_ref)) + dev_err(dev, "%s: cannot get clock %s\n", + __func__, "clk_mac_ref"); + + if (!bsp_priv->clock_input) { + bsp_priv->clk_mac_refout = + devm_clk_get(dev, "clk_mac_refout"); + if (IS_ERR(bsp_priv->clk_mac_refout)) + dev_err(dev, "%s: cannot get clock %s\n", + __func__, "clk_mac_refout"); + } + } + + if (bsp_priv->clock_input) { + dev_info(dev, "%s: clock input from PHY\n", __func__); + } else { + if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) + clk_set_rate(bsp_priv->clk_mac_pll, 50000000); + } + + return 0; +} + +static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable) +{ + int phy_iface = phy_iface = bsp_priv->phy_iface; + + if (enable) { + if (!bsp_priv->clk_enabled) { + if (phy_iface == PHY_INTERFACE_MODE_RMII) { + if (!IS_ERR(bsp_priv->mac_clk_rx)) + clk_prepare_enable( + bsp_priv->mac_clk_rx); + + if (!IS_ERR(bsp_priv->clk_mac_ref)) + clk_prepare_enable( + bsp_priv->clk_mac_ref); + + if (!IS_ERR(bsp_priv->clk_mac_refout)) + clk_prepare_enable( + bsp_priv->clk_mac_refout); + } + + if (!IS_ERR(bsp_priv->aclk_mac)) + clk_prepare_enable(bsp_priv->aclk_mac); + + if (!IS_ERR(bsp_priv->pclk_mac)) + clk_prepare_enable(bsp_priv->pclk_mac); + + if (!IS_ERR(bsp_priv->mac_clk_tx)) + clk_prepare_enable(bsp_priv->mac_clk_tx); + + /** + * if (!IS_ERR(bsp_priv->clk_mac)) + * clk_prepare_enable(bsp_priv->clk_mac); + */ + mdelay(5); + bsp_priv->clk_enabled = true; + } + } else { + if (bsp_priv->clk_enabled) { + if (phy_iface == PHY_INTERFACE_MODE_RMII) { + if (!IS_ERR(bsp_priv->mac_clk_rx)) + clk_disable_unprepare( + bsp_priv->mac_clk_rx); + + if (!IS_ERR(bsp_priv->clk_mac_ref)) + clk_disable_unprepare( + bsp_priv->clk_mac_ref); + + if (!IS_ERR(bsp_priv->clk_mac_refout)) + clk_disable_unprepare( + bsp_priv->clk_mac_refout); + } + + if (!IS_ERR(bsp_priv->aclk_mac)) + clk_disable_unprepare(bsp_priv->aclk_mac); + + if (!IS_ERR(bsp_priv->pclk_mac)) + clk_disable_unprepare(bsp_priv->pclk_mac); + + if (!IS_ERR(bsp_priv->mac_clk_tx)) + clk_disable_unprepare(bsp_priv->mac_clk_tx); + /** + * if (!IS_ERR(bsp_priv->clk_mac)) + * clk_disable_unprepare(bsp_priv->clk_mac); + */ + bsp_priv->clk_enabled = false; + } + } + + return 0; +} + +static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable) +{ + struct regulator *ldo = bsp_priv->regulator; + int ret; + struct device *dev = &bsp_priv->pdev->dev; + + if (!ldo) { + dev_err(dev, "%s: no regulator found\n", __func__); + return -1; + } + + if (enable) { + ret = regulator_enable(ldo); + if (ret) + dev_err(dev, "%s: fail to enable phy-supply\n", + __func__); + } else { + ret = regulator_disable(ldo); + if (ret) + dev_err(dev, "%s: fail to disable phy-supply\n", + __func__); + } + + return 0; +} + +static void *rk_gmac_setup(struct platform_device *pdev) +{ + struct rk_priv_data *bsp_priv; + struct device *dev = &pdev->dev; + int ret; + const char *strings = NULL; + int value; + + bsp_priv = devm_kzalloc(dev, sizeof(*bsp_priv), GFP_KERNEL); + if (!bsp_priv) + return ERR_PTR(-ENOMEM); + + bsp_priv->phy_iface = of_get_phy_mode(dev->of_node); + + bsp_priv->regulator = devm_regulator_get_optional(dev, "phy"); + if (IS_ERR(bsp_priv->regulator)) { + if (PTR_ERR(bsp_priv->regulator) == -EPROBE_DEFER) { + dev_err(dev, "phy regulator is not available yet, deferred probing\n"); + return ERR_PTR(-EPROBE_DEFER); + } + dev_err(dev, "no regulator found\n"); + bsp_priv->regulator = NULL; + } + + ret = of_property_read_string(dev->of_node, "clock_in_out", &strings); + if (ret) { + dev_err(dev, "%s: Can not read property: clock_in_out.\n", + __func__); + bsp_priv->clock_input = true; + } else { + dev_info(dev, "%s: clock input or output? (%s).\n", + __func__, strings); + if (!strcmp(strings, "input")) + bsp_priv->clock_input = true; + else + bsp_priv->clock_input = false; + } + + ret = of_property_read_u32(dev->of_node, "tx_delay", &value); + if (ret) { + bsp_priv->tx_delay = 0x30; + dev_err(dev, "%s: Can not read property: tx_delay.", __func__); + dev_err(dev, "%s: set tx_delay to 0x%x\n", + __func__, bsp_priv->tx_delay); + } else { + dev_info(dev, "%s: TX delay(0x%x).\n", __func__, value); + bsp_priv->tx_delay = value; + } + + ret = of_property_read_u32(dev->of_node, "rx_delay", &value); + if (ret) { + bsp_priv->rx_delay = 0x10; + dev_err(dev, "%s: Can not read property: rx_delay.", __func__); + dev_err(dev, "%s: set rx_delay to 0x%x\n", + __func__, bsp_priv->rx_delay); + } else { + dev_info(dev, "%s: RX delay(0x%x).\n", __func__, value); + bsp_priv->rx_delay = value; + } + + bsp_priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node, + "rockchip,grf"); + bsp_priv->pdev = pdev; + + /*rmii or rgmii*/ + if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) { + dev_info(dev, "%s: init for RGMII\n", __func__); + set_to_rgmii(bsp_priv, bsp_priv->tx_delay, bsp_priv->rx_delay); + } else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) { + dev_info(dev, "%s: init for RMII\n", __func__); + set_to_rmii(bsp_priv); + } else { + dev_err(dev, "%s: NO interface defined!\n", __func__); + } + + gmac_clk_init(bsp_priv); + + return bsp_priv; +} + +static int rk_gmac_init(struct platform_device *pdev, void *priv) +{ + struct rk_priv_data *bsp_priv = priv; + int ret; + + ret = phy_power_on(bsp_priv, true); + if (ret) + return ret; + + ret = gmac_clk_enable(bsp_priv, true); + if (ret) + return ret; + + return 0; +} + +static void rk_gmac_exit(struct platform_device *pdev, void *priv) +{ + struct rk_priv_data *gmac = priv; + + phy_power_on(gmac, false); + gmac_clk_enable(gmac, false); +} + +static void rk_fix_speed(void *priv, unsigned int speed) +{ + struct rk_priv_data *bsp_priv = priv; + struct device *dev = &bsp_priv->pdev->dev; + + if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) + set_rgmii_speed(bsp_priv, speed); + else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) + set_rmii_speed(bsp_priv, speed); + else + dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface); +} + +const struct stmmac_of_data rk3288_gmac_data = { + .has_gmac = 1, + .fix_mac_speed = rk_fix_speed, + .setup = rk_gmac_setup, + .init = rk_gmac_init, + .exit = rk_gmac_exit, +}; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index 056b358b4a72..bb6e2dc61bec 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -122,7 +122,7 @@ struct sti_dwmac { bool ext_phyclk; /* Clock from external PHY */ u32 tx_retime_src; /* TXCLK Retiming*/ struct clk *clk; /* PHY clock */ - int ctrl_reg; /* GMAC glue-logic control register */ + u32 ctrl_reg; /* GMAC glue-logic control register */ int clk_sel_reg; /* GMAC ext clk selection register */ struct device *dev; struct regmap *regmap; @@ -285,11 +285,6 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, if (!np) return -EINVAL; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-ethconf"); - if (!res) - return -ENODATA; - dwmac->ctrl_reg = res->start; - /* clk selection from extra syscfg register */ dwmac->clk_sel_reg = -ENXIO; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-clkconf"); @@ -300,6 +295,12 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, if (IS_ERR(regmap)) return PTR_ERR(regmap); + err = of_property_read_u32_index(np, "st,syscon", 1, &dwmac->ctrl_reg); + if (err) { + dev_err(dev, "Can't get sysconfig ctrl offset (%d)\n", err); + return err; + } + dwmac->dev = dev; dwmac->interface = of_get_phy_mode(np); dwmac->regmap = regmap; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 8c6b7c1651e5..55e89b3838f1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1097,6 +1097,7 @@ static int init_dma_desc_rings(struct net_device *dev, gfp_t flags) priv->dirty_tx = 0; priv->cur_tx = 0; + netdev_reset_queue(priv->dev); stmmac_clear_descriptors(priv); @@ -1287,7 +1288,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) * that needs to not insert csum in the TDES. */ priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE); - tc = SF_DMA_MODE; + priv->xstats.threshold = SF_DMA_MODE; } else priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE); } @@ -1300,6 +1301,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) static void stmmac_tx_clean(struct stmmac_priv *priv) { unsigned int txsize = priv->dma_tx_size; + unsigned int bytes_compl = 0, pkts_compl = 0; spin_lock(&priv->tx_lock); @@ -1356,6 +1358,8 @@ static void stmmac_tx_clean(struct stmmac_priv *priv) priv->hw->mode->clean_desc3(priv, p); if (likely(skb != NULL)) { + pkts_compl++; + bytes_compl += skb->len; dev_consume_skb_any(skb); priv->tx_skbuff[entry] = NULL; } @@ -1364,6 +1368,9 @@ static void stmmac_tx_clean(struct stmmac_priv *priv) priv->dirty_tx++; } + + netdev_completed_queue(priv->dev, pkts_compl, bytes_compl); + if (unlikely(netif_queue_stopped(priv->dev) && stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv))) { netif_tx_lock(priv->dev); @@ -1418,6 +1425,7 @@ static void stmmac_tx_err(struct stmmac_priv *priv) (i == txsize - 1)); priv->dirty_tx = 0; priv->cur_tx = 0; + netdev_reset_queue(priv->dev); priv->hw->dma->start_tx(priv->ioaddr); priv->dev->stats.tx_errors++; @@ -1444,9 +1452,14 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv) } if (unlikely(status & tx_hard_error_bump_tc)) { /* Try to bump up the dma threshold on this failure */ - if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) { + if (unlikely(priv->xstats.threshold != SF_DMA_MODE) && + (tc <= 256)) { tc += 64; - priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE); + if (priv->plat->force_thresh_dma_mode) + priv->hw->dma->dma_mode(priv->ioaddr, tc, tc); + else + priv->hw->dma->dma_mode(priv->ioaddr, tc, + SF_DMA_MODE); priv->xstats.threshold = tc; } } else if (unlikely(status == tx_hard_error)) @@ -2050,6 +2063,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) if (!priv->hwts_tx_en) skb_tx_timestamp(skb); + netdev_sent_queue(dev, skb->len); priv->hw->dma->enable_dma_transmission(priv->ioaddr); spin_unlock(&priv->tx_lock); @@ -2742,7 +2756,11 @@ static int stmmac_hw_init(struct stmmac_priv *priv) priv->plat->enh_desc = priv->dma_cap.enh_desc; priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up; - priv->plat->tx_coe = priv->dma_cap.tx_coe; + /* TXCOE doesn't work in thresh DMA mode */ + if (priv->plat->force_thresh_dma_mode) + priv->plat->tx_coe = 0; + else + priv->plat->tx_coe = priv->dma_cap.tx_coe; if (priv->dma_cap.rx_coe_type2) priv->plat->rx_coe = STMMAC_RX_COE_TYPE2; @@ -2778,6 +2796,9 @@ static int stmmac_hw_init(struct stmmac_priv *priv) * @addr: iobase memory address * Description: this is the main probe function used to * call the alloc_etherdev, allocate the priv structure. + * Return: + * on success the new private structure is returned, otherwise the error + * pointer. */ struct stmmac_priv *stmmac_dvr_probe(struct device *device, struct plat_stmmacenet_data *plat_dat, @@ -2789,7 +2810,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, ndev = alloc_etherdev(sizeof(struct stmmac_priv)); if (!ndev) - return NULL; + return ERR_PTR(-ENOMEM); SET_NETDEV_DEV(ndev, device); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 054520d67de4..3bca908716e2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -24,8 +24,50 @@ *******************************************************************************/ #include +#include + #include "stmmac.h" +/* + * This struct is used to associate PCI Function of MAC controller on a board, + * discovered via DMI, with the address of PHY connected to the MAC. The + * negative value of the address means that MAC controller is not connected + * with PHY. + */ +struct stmmac_pci_dmi_data { + const char *name; + unsigned int func; + int phy_addr; +}; + +struct stmmac_pci_info { + struct pci_dev *pdev; + int (*setup)(struct plat_stmmacenet_data *plat, + struct stmmac_pci_info *info); + struct stmmac_pci_dmi_data *dmi; +}; + +static int stmmac_pci_find_phy_addr(struct stmmac_pci_info *info) +{ + const char *name = dmi_get_system_info(DMI_BOARD_NAME); + unsigned int func = PCI_FUNC(info->pdev->devfn); + struct stmmac_pci_dmi_data *dmi; + + /* + * Galileo boards with old firmware don't support DMI. We always return + * 1 here, so at least first found MAC controller would be probed. + */ + if (!name) + return 1; + + for (dmi = info->dmi; dmi->name && *dmi->name; dmi++) { + if (!strcmp(dmi->name, name) && dmi->func == func) + return dmi->phy_addr; + } + + return -ENODEV; +} + static void stmmac_default_data(struct plat_stmmacenet_data *plat) { plat->bus_id = 1; @@ -48,6 +90,62 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat) plat->unicast_filter_entries = 1; } +static int quark_default_data(struct plat_stmmacenet_data *plat, + struct stmmac_pci_info *info) +{ + struct pci_dev *pdev = info->pdev; + int ret; + + /* + * Refuse to load the driver and register net device if MAC controller + * does not connect to any PHY interface. + */ + ret = stmmac_pci_find_phy_addr(info); + if (ret < 0) + return ret; + + plat->bus_id = PCI_DEVID(pdev->bus->number, pdev->devfn); + plat->phy_addr = ret; + plat->interface = PHY_INTERFACE_MODE_RMII; + plat->clk_csr = 2; + plat->has_gmac = 1; + plat->force_sf_dma_mode = 1; + + plat->mdio_bus_data->phy_reset = NULL; + plat->mdio_bus_data->phy_mask = 0; + + plat->dma_cfg->pbl = 16; + plat->dma_cfg->burst_len = DMA_AXI_BLEN_256; + plat->dma_cfg->fixed_burst = 1; + + /* Set default value for multicast hash bins */ + plat->multicast_filter_bins = HASH_TABLE_SIZE; + + /* Set default value for unicast filter entries */ + plat->unicast_filter_entries = 1; + + return 0; +} + +static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = { + { + .name = "Galileo", + .func = 6, + .phy_addr = 1, + }, + { + .name = "GalileoGen2", + .func = 6, + .phy_addr = 1, + }, + {} +}; + +static struct stmmac_pci_info quark_pci_info = { + .setup = quark_default_data, + .dmi = quark_pci_dmi_data, +}; + /** * stmmac_pci_probe * @@ -63,6 +161,7 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat) static int stmmac_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct stmmac_pci_info *info = (struct stmmac_pci_info *)id->driver_data; struct plat_stmmacenet_data *plat; struct stmmac_priv *priv; int i; @@ -103,7 +202,17 @@ static int stmmac_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); - stmmac_default_data(plat); + if (info) { + info->pdev = pdev; + if (info->setup) { + ret = info->setup(plat, info); + if (ret) + return ret; + } + } else + stmmac_default_data(plat); + + pci_enable_msi(pdev); priv = stmmac_dvr_probe(&pdev->dev, plat, pcim_iomap_table(pdev)[i]); if (IS_ERR(priv)) { @@ -155,11 +264,13 @@ static int stmmac_pci_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume); #define STMMAC_VENDOR_ID 0x700 +#define STMMAC_QUARK_ID 0x0937 #define STMMAC_DEVICE_ID 0x1108 static const struct pci_device_id stmmac_id_table[] = { {PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)}, {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_MAC)}, + {PCI_VDEVICE(INTEL, STMMAC_QUARK_ID), (kernel_ulong_t)&quark_pci_info}, {} }; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 3039de2465ba..fb846ebba1d9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -33,6 +33,7 @@ static const struct of_device_id stmmac_dt_ids[] = { /* SoC specific glue layers should come before generic bindings */ + { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_gmac_data}, { .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data}, { .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data}, { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data}, @@ -234,6 +235,9 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, of_property_read_bool(np, "snps,fixed-burst"); dma_cfg->mixed_burst = of_property_read_bool(np, "snps,mixed-burst"); + of_property_read_u32(np, "snps,burst_len", &dma_cfg->burst_len); + if (dma_cfg->burst_len < 0 || dma_cfg->burst_len > 256) + dma_cfg->burst_len = 0; } plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode"); if (plat->force_thresh_dma_mode) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index 25dd1f7ace02..093eb99e5ffd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -24,5 +24,6 @@ extern const struct stmmac_of_data sun7i_gmac_data; extern const struct stmmac_of_data stih4xx_dwmac_data; extern const struct stmmac_of_data stid127_dwmac_data; extern const struct stmmac_of_data socfpga_gmac_data; +extern const struct stmmac_of_data rk3288_gmac_data; #endif /* __STMMAC_PLATFORM_H__ */ diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c index 0c6416213837..4b51f903fb73 100644 --- a/drivers/net/ethernet/sun/niu.c +++ b/drivers/net/ethernet/sun/niu.c @@ -3341,8 +3341,7 @@ static int niu_rbr_add_page(struct niu *np, struct rx_ring_info *rp, niu_hash_page(rp, page, addr); if (rp->rbr_blocks_per_page > 1) - atomic_add(rp->rbr_blocks_per_page - 1, - &compound_head(page)->_count); + atomic_add(rp->rbr_blocks_per_page - 1, &page->_count); for (i = 0; i < rp->rbr_blocks_per_page; i++) { __le32 *rbr = &rp->rbr[start_index + i]; diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index d2835bf7b4fb..2b10b85d8a08 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -50,6 +50,7 @@ MODULE_VERSION(DRV_MODULE_VERSION); #define VNET_MAX_RETRIES 10 static int __vnet_tx_trigger(struct vnet_port *port, u32 start); +static void vnet_port_reset(struct vnet_port *port); /* Ordered from largest major to lowest */ static struct vio_version vnet_versions[] = { @@ -351,10 +352,15 @@ static int vnet_rx_one(struct vnet_port *port, struct vio_net_desc *desc) unsigned int len = desc->size; unsigned int copy_len; struct sk_buff *skb; + int maxlen; int err; err = -EMSGSIZE; - if (unlikely(len < ETH_ZLEN || len > port->rmtu)) { + if (port->tso && port->tsolen > port->rmtu) + maxlen = port->tsolen; + else + maxlen = port->rmtu; + if (unlikely(len < ETH_ZLEN || len > maxlen)) { dev->stats.rx_length_errors++; goto out_dropped; } @@ -731,9 +737,7 @@ ldc_ctrl: vio_link_state_change(vio, event); if (event == LDC_EVENT_RESET) { - port->rmtu = 0; - port->tso = true; - port->tsolen = 0; + vnet_port_reset(port); vio_port_up(vio); } port->rx_event = 0; @@ -929,36 +933,36 @@ static struct sk_buff *vnet_clean_tx_ring(struct vnet_port *port, *pending = 0; - txi = dr->prod-1; - if (txi < 0) - txi = VNET_TX_RING_SIZE-1; - + txi = dr->prod; for (i = 0; i < VNET_TX_RING_SIZE; ++i) { struct vio_net_desc *d; - d = vio_dring_entry(dr, txi); - - if (d->hdr.state == VIO_DESC_DONE) { - if (port->tx_bufs[txi].skb) { - BUG_ON(port->tx_bufs[txi].skb->next); - - port->tx_bufs[txi].skb->next = skb; - skb = port->tx_bufs[txi].skb; - port->tx_bufs[txi].skb = NULL; - - ldc_unmap(port->vio.lp, - port->tx_bufs[txi].cookies, - port->tx_bufs[txi].ncookies); - } - d->hdr.state = VIO_DESC_FREE; - } else if (d->hdr.state == VIO_DESC_READY) { - (*pending)++; - } else if (d->hdr.state == VIO_DESC_FREE) { - break; - } --txi; if (txi < 0) txi = VNET_TX_RING_SIZE-1; + + d = vio_dring_entry(dr, txi); + + if (d->hdr.state == VIO_DESC_READY) { + (*pending)++; + continue; + } + if (port->tx_bufs[txi].skb) { + if (d->hdr.state != VIO_DESC_DONE) + pr_notice("invalid ring buffer state %d\n", + d->hdr.state); + BUG_ON(port->tx_bufs[txi].skb->next); + + port->tx_bufs[txi].skb->next = skb; + skb = port->tx_bufs[txi].skb; + port->tx_bufs[txi].skb = NULL; + + ldc_unmap(port->vio.lp, + port->tx_bufs[txi].cookies, + port->tx_bufs[txi].ncookies); + } else if (d->hdr.state == VIO_DESC_FREE) + break; + d->hdr.state = VIO_DESC_FREE; } return skb; } @@ -1119,6 +1123,7 @@ static inline struct sk_buff *vnet_skb_shape(struct sk_buff *skb, int ncookies) skb_shinfo(nskb)->gso_size = skb_shinfo(skb)->gso_size; skb_shinfo(nskb)->gso_type = skb_shinfo(skb)->gso_type; } + nskb->queue_mapping = skb->queue_mapping; dev_kfree_skb(skb); skb = nskb; } @@ -1632,16 +1637,9 @@ static void vnet_port_free_tx_bufs(struct vnet_port *port) int i; dr = &port->vio.drings[VIO_DRIVER_TX_RING]; - if (dr->base) { - ldc_free_exp_dring(port->vio.lp, dr->base, - (dr->entry_size * dr->num_entries), - dr->cookies, dr->ncookies); - dr->base = NULL; - dr->entry_size = 0; - dr->num_entries = 0; - dr->pending = 0; - dr->ncookies = 0; - } + + if (dr->base == NULL) + return; for (i = 0; i < VNET_TX_RING_SIZE; i++) { struct vio_net_desc *d; @@ -1651,8 +1649,6 @@ static void vnet_port_free_tx_bufs(struct vnet_port *port) continue; d = vio_dring_entry(dr, i); - if (d->hdr.state == VIO_DESC_READY) - pr_warn("active transmit buffers freed\n"); ldc_unmap(port->vio.lp, port->tx_bufs[i].cookies, @@ -1661,6 +1657,23 @@ static void vnet_port_free_tx_bufs(struct vnet_port *port) port->tx_bufs[i].skb = NULL; d->hdr.state = VIO_DESC_FREE; } + ldc_free_exp_dring(port->vio.lp, dr->base, + (dr->entry_size * dr->num_entries), + dr->cookies, dr->ncookies); + dr->base = NULL; + dr->entry_size = 0; + dr->num_entries = 0; + dr->pending = 0; + dr->ncookies = 0; +} + +static void vnet_port_reset(struct vnet_port *port) +{ + del_timer(&port->clean_timer); + vnet_port_free_tx_bufs(port); + port->rmtu = 0; + port->tso = true; + port->tsolen = 0; } static int vnet_port_alloc_tx_ring(struct vnet_port *port) diff --git a/drivers/net/ethernet/tehuti/tehuti.c b/drivers/net/ethernet/tehuti/tehuti.c index 6ab36d9ff2ab..a9cac8413e49 100644 --- a/drivers/net/ethernet/tehuti/tehuti.c +++ b/drivers/net/ethernet/tehuti/tehuti.c @@ -1650,9 +1650,9 @@ static netdev_tx_t bdx_tx_transmit(struct sk_buff *skb, txd_mss); } - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { /*Cut VLAN ID to 12 bits */ - txd_vlan_id = vlan_tx_tag_get(skb) & BITS_MASK(12); + txd_vlan_id = skb_vlan_tag_get(skb) & BITS_MASK(12); txd_vtag = 1; } diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index 605dd909bcc3..3bc992cd70b7 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -56,12 +56,18 @@ config TI_CPSW_PHY_SEL This driver supports configuring of the phy mode connected to the CPSW. +config TI_CPSW_ALE + tristate "TI CPSW ALE Support" + ---help--- + This driver supports TI's CPSW ALE module. + config TI_CPSW tristate "TI CPSW Switch Support" depends on ARCH_DAVINCI || ARCH_OMAP2PLUS select TI_DAVINCI_CPDMA select TI_DAVINCI_MDIO select TI_CPSW_PHY_SEL + select TI_CPSW_ALE select MFD_SYSCON select REGMAP ---help--- @@ -79,6 +85,25 @@ config TI_CPTS the CPSW Ethernet Switch. The unit can time stamp PTP UDP/IPv4 and Layer 2 packets, and the driver offers a PTP Hardware Clock. +config TI_KEYSTONE_NETCP + tristate "TI Keystone NETCP Core Support" + select TI_CPSW_ALE + depends on OF + depends on KEYSTONE_NAVIGATOR_DMA && KEYSTONE_NAVIGATOR_QMSS + ---help--- + This driver supports TI's Keystone NETCP Core. + + To compile this driver as a module, choose M here: the module + will be called keystone_netcp. + +config TI_KEYSTONE_NETCP_ETHSS + depends on TI_KEYSTONE_NETCP + tristate "TI Keystone NETCP Ethernet subsystem Support" + ---help--- + + To compile this driver as a module, choose M here: the module + will be called keystone_netcp_ethss. + config TLAN tristate "TI ThunderLAN support" depends on (PCI || EISA) diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index 9cfaab8152be..d420d9413e4a 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -2,11 +2,20 @@ # Makefile for the TI network device drivers. # +obj-$(CONFIG_TI_CPSW) += cpsw-common.o +obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o + obj-$(CONFIG_TLAN) += tlan.o obj-$(CONFIG_CPMAC) += cpmac.o obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o obj-$(CONFIG_TI_DAVINCI_MDIO) += davinci_mdio.o obj-$(CONFIG_TI_DAVINCI_CPDMA) += davinci_cpdma.o obj-$(CONFIG_TI_CPSW_PHY_SEL) += cpsw-phy-sel.o +obj-$(CONFIG_TI_CPSW_ALE) += cpsw_ale.o obj-$(CONFIG_TI_CPSW) += ti_cpsw.o -ti_cpsw-y := cpsw_ale.o cpsw.o cpts.o +ti_cpsw-y := cpsw.o cpts.o + +obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o +keystone_netcp-y := netcp_core.o +obj-$(CONFIG_TI_KEYSTONE_NETCP_ETHSS) += keystone_netcp_ethss.o +keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o diff --git a/drivers/net/ethernet/ti/cpsw-common.c b/drivers/net/ethernet/ti/cpsw-common.c new file mode 100644 index 000000000000..f59509486113 --- /dev/null +++ b/drivers/net/ethernet/ti/cpsw-common.c @@ -0,0 +1,55 @@ +/* + * 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 "cpsw.h" + +#define AM33XX_CTRL_MAC_LO_REG(offset, id) ((offset) + 0x8 * (id)) +#define AM33XX_CTRL_MAC_HI_REG(offset, id) ((offset) + 0x8 * (id) + 0x4) + +int cpsw_am33xx_cm_get_macid(struct device *dev, u16 offset, int slave, + u8 *mac_addr) +{ + u32 macid_lo; + u32 macid_hi; + struct regmap *syscon; + + syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); + if (IS_ERR(syscon)) { + if (PTR_ERR(syscon) == -ENODEV) + return 0; + return PTR_ERR(syscon); + } + + regmap_read(syscon, AM33XX_CTRL_MAC_LO_REG(offset, slave), + &macid_lo); + regmap_read(syscon, AM33XX_CTRL_MAC_HI_REG(offset, slave), + &macid_hi); + + mac_addr[5] = (macid_lo >> 8) & 0xff; + mac_addr[4] = macid_lo & 0xff; + mac_addr[3] = (macid_hi >> 24) & 0xff; + mac_addr[2] = (macid_hi >> 16) & 0xff; + mac_addr[1] = (macid_hi >> 8) & 0xff; + mac_addr[0] = macid_hi & 0xff; + + return 0; +} +EXPORT_SYMBOL_GPL(cpsw_am33xx_cm_get_macid); + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 64d1cef4cda1..7d8dd0d2182e 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include @@ -761,17 +759,25 @@ requeue: dev_kfree_skb_any(new_skb); } -static irqreturn_t cpsw_interrupt(int irq, void *dev_id) +static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) { struct cpsw_priv *priv = dev_id; - int value = irq - priv->irqs_table[0]; - /* NOTICE: Ending IRQ here. The trick with the 'value' variable above - * is to make sure we will always write the correct value to the EOI - * register. Namely 0 for RX_THRESH Interrupt, 1 for RX Interrupt, 2 - * for TX Interrupt and 3 for MISC Interrupt. - */ - cpdma_ctlr_eoi(priv->dma, value); + cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX); + cpdma_chan_process(priv->txch, 128); + + priv = cpsw_get_slave_priv(priv, 1); + if (priv) + cpdma_chan_process(priv->txch, 128); + + return IRQ_HANDLED; +} + +static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) +{ + struct cpsw_priv *priv = dev_id; + + cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); cpsw_intr_disable(priv); if (priv->irq_enabled == true) { @@ -1624,7 +1630,8 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev) cpsw_intr_disable(priv); cpdma_ctlr_int_ctrl(priv->dma, false); - cpsw_interrupt(ndev->irq, priv); + cpsw_rx_interrupt(priv->irqs_table[0], priv); + cpsw_tx_interrupt(priv->irqs_table[1], priv); cpdma_ctlr_int_ctrl(priv->dma, true); cpsw_intr_enable(priv); } @@ -1634,16 +1641,24 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv, unsigned short vid) { int ret; - int unreg_mcast_mask; + int unreg_mcast_mask = 0; + u32 port_mask; - if (priv->ndev->flags & IFF_ALLMULTI) - unreg_mcast_mask = ALE_ALL_PORTS; - else - unreg_mcast_mask = ALE_PORT_1 | ALE_PORT_2; + if (priv->data.dual_emac) { + port_mask = (1 << (priv->emac_port + 1)) | ALE_PORT_HOST; - ret = cpsw_ale_add_vlan(priv->ale, vid, - ALE_ALL_PORTS << priv->host_port, - 0, ALE_ALL_PORTS << priv->host_port, + if (priv->ndev->flags & IFF_ALLMULTI) + unreg_mcast_mask = port_mask; + } else { + port_mask = ALE_ALL_PORTS; + + if (priv->ndev->flags & IFF_ALLMULTI) + unreg_mcast_mask = ALE_ALL_PORTS; + else + unreg_mcast_mask = ALE_PORT_1 | ALE_PORT_2; + } + + ret = cpsw_ale_add_vlan(priv->ale, vid, port_mask, 0, port_mask, unreg_mcast_mask << priv->host_port); if (ret != 0) return ret; @@ -1654,8 +1669,7 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv, goto clean_vid; ret = cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, - ALE_ALL_PORTS << priv->host_port, - ALE_VLAN, vid, 0); + port_mask, ALE_VLAN, vid, 0); if (ret != 0) goto clean_vlan_ucast; return 0; @@ -1676,6 +1690,19 @@ static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev, if (vid == priv->data.default_vlan) return 0; + if (priv->data.dual_emac) { + /* In dual EMAC, reserved VLAN id should not be used for + * creating VLAN interfaces as this can break the dual + * EMAC port separation + */ + int i; + + for (i = 0; i < priv->data.slaves; i++) { + if (vid == priv->slaves[i].port_vlan) + return -EINVAL; + } + } + dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid); return cpsw_add_vlan_ale_entry(priv, vid); } @@ -1689,6 +1716,15 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, if (vid == priv->data.default_vlan) return 0; + if (priv->data.dual_emac) { + int i; + + for (i = 0; i < priv->data.slaves; i++) { + if (vid == priv->slaves[i].port_vlan) + return -EINVAL; + } + } + dev_info(priv->dev, "removing vlanid %d from vlan filter\n", vid); ret = cpsw_ale_del_vlan(priv->ale, vid, 0); if (ret != 0) @@ -1898,36 +1934,6 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv, slave->port_vlan = data->dual_emac_res_vlan; } -#define AM33XX_CTRL_MAC_LO_REG(id) (0x630 + 0x8 * id) -#define AM33XX_CTRL_MAC_HI_REG(id) (0x630 + 0x8 * id + 0x4) - -static int cpsw_am33xx_cm_get_macid(struct device *dev, int slave, - u8 *mac_addr) -{ - u32 macid_lo; - u32 macid_hi; - struct regmap *syscon; - - syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); - if (IS_ERR(syscon)) { - if (PTR_ERR(syscon) == -ENODEV) - return 0; - return PTR_ERR(syscon); - } - - regmap_read(syscon, AM33XX_CTRL_MAC_LO_REG(slave), &macid_lo); - regmap_read(syscon, AM33XX_CTRL_MAC_HI_REG(slave), &macid_hi); - - mac_addr[5] = (macid_lo >> 8) & 0xff; - mac_addr[4] = macid_lo & 0xff; - mac_addr[3] = (macid_hi >> 24) & 0xff; - mac_addr[2] = (macid_hi >> 16) & 0xff; - mac_addr[1] = (macid_hi >> 8) & 0xff; - mac_addr[0] = macid_hi & 0xff; - - return 0; -} - static int cpsw_probe_dt(struct cpsw_platform_data *data, struct platform_device *pdev) { @@ -2052,7 +2058,8 @@ no_phy_slave: memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN); } else { if (of_machine_is_compatible("ti,am33xx")) { - ret = cpsw_am33xx_cm_get_macid(&pdev->dev, i, + ret = cpsw_am33xx_cm_get_macid(&pdev->dev, + 0x630, i, slave_data->mac_addr); if (ret) return ret; @@ -2163,7 +2170,8 @@ static int cpsw_probe(struct platform_device *pdev) void __iomem *ss_regs; struct resource *res, *ss_res; u32 slave_offset, sliver_offset, slave_size; - int ret = 0, i, k = 0; + int ret = 0, i; + int irq; ndev = alloc_etherdev(sizeof(struct cpsw_priv)); if (!ndev) { @@ -2345,31 +2353,47 @@ static int cpsw_probe(struct platform_device *pdev) goto clean_dma_ret; } - ndev->irq = platform_get_irq(pdev, 0); + ndev->irq = platform_get_irq(pdev, 1); if (ndev->irq < 0) { dev_err(priv->dev, "error getting irq resource\n"); ret = -ENOENT; goto clean_ale_ret; } - while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) { - if (k >= ARRAY_SIZE(priv->irqs_table)) { - ret = -EINVAL; - goto clean_ale_ret; - } + /* Grab RX and TX IRQs. Note that we also have RX_THRESHOLD and + * MISC IRQs which are always kept disabled with this driver so + * we will not request them. + * + * If anyone wants to implement support for those, make sure to + * first request and append them to irqs_table array. + */ - ret = devm_request_irq(&pdev->dev, res->start, cpsw_interrupt, - 0, dev_name(&pdev->dev), priv); - if (ret < 0) { - dev_err(priv->dev, "error attaching irq (%d)\n", ret); - goto clean_ale_ret; - } + /* RX IRQ */ + irq = platform_get_irq(pdev, 1); + if (irq < 0) + goto clean_ale_ret; - priv->irqs_table[k] = res->start; - k++; + priv->irqs_table[0] = irq; + ret = devm_request_irq(&pdev->dev, irq, cpsw_rx_interrupt, + 0, dev_name(&pdev->dev), priv); + if (ret < 0) { + dev_err(priv->dev, "error attaching irq (%d)\n", ret); + goto clean_ale_ret; } - priv->num_irqs = k; + /* TX IRQ */ + irq = platform_get_irq(pdev, 2); + if (irq < 0) + goto clean_ale_ret; + + priv->irqs_table[1] = irq; + ret = devm_request_irq(&pdev->dev, irq, cpsw_tx_interrupt, + 0, dev_name(&pdev->dev), priv); + if (ret < 0) { + dev_err(priv->dev, "error attaching irq (%d)\n", ret); + goto clean_ale_ret; + } + priv->num_irqs = 2; ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; diff --git a/drivers/net/ethernet/ti/cpsw.h b/drivers/net/ethernet/ti/cpsw.h index 1b710674630c..ca90efafd156 100644 --- a/drivers/net/ethernet/ti/cpsw.h +++ b/drivers/net/ethernet/ti/cpsw.h @@ -41,5 +41,7 @@ struct cpsw_platform_data { }; void cpsw_phy_sel(struct device *dev, phy_interface_t phy_mode, int slave); +int cpsw_am33xx_cm_get_macid(struct device *dev, u16 offset, int slave, + u8 *mac_addr); #endif /* __CPSW_H__ */ diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 5246b3a18ff8..6e927b4583aa 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -13,6 +13,7 @@ * GNU General Public License for more details. */ #include +#include #include #include #include @@ -146,7 +147,7 @@ static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry) return idx; } -int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid) +static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid) { u32 ale_entry[ALE_ENTRY_WORDS]; int type, idx; @@ -167,7 +168,7 @@ int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid) return -ENOENT; } -int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid) +static int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid) { u32 ale_entry[ALE_ENTRY_WORDS]; int type, idx; @@ -265,6 +266,7 @@ int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid) } return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_flush_multicast); static void cpsw_ale_flush_ucast(struct cpsw_ale *ale, u32 *ale_entry, int port_mask) @@ -297,6 +299,7 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask) } return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_flush); static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry, int flags, u16 vid) @@ -334,6 +337,7 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_add_ucast); int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags, u16 vid) @@ -349,6 +353,7 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_del_ucast); int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, int flags, u16 vid, int mcast_state) @@ -380,6 +385,7 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_add_mcast); int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, int flags, u16 vid) @@ -401,6 +407,7 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_del_mcast); int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, int reg_mcast, int unreg_mcast) @@ -430,6 +437,7 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_add_vlan); int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) { @@ -450,6 +458,7 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_del_vlan); void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti) { @@ -479,6 +488,7 @@ void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti) cpsw_ale_write(ale, idx, ale_entry); } } +EXPORT_SYMBOL_GPL(cpsw_ale_set_allmulti); struct ale_control_info { const char *name; @@ -704,6 +714,7 @@ int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control, return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_control_set); int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) { @@ -727,6 +738,7 @@ int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) tmp = __raw_readl(ale->params.ale_regs + offset) >> shift; return tmp & BITMASK(info->bits); } +EXPORT_SYMBOL_GPL(cpsw_ale_control_get); static void cpsw_ale_timer(unsigned long arg) { @@ -750,6 +762,7 @@ int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout) } return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_set_ageout); void cpsw_ale_start(struct cpsw_ale *ale) { @@ -769,11 +782,13 @@ void cpsw_ale_start(struct cpsw_ale *ale) add_timer(&ale->timer); } } +EXPORT_SYMBOL_GPL(cpsw_ale_start); void cpsw_ale_stop(struct cpsw_ale *ale) { del_timer_sync(&ale->timer); } +EXPORT_SYMBOL_GPL(cpsw_ale_stop); struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) { @@ -788,6 +803,7 @@ struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) return ale; } +EXPORT_SYMBOL_GPL(cpsw_ale_create); int cpsw_ale_destroy(struct cpsw_ale *ale) { @@ -797,6 +813,7 @@ int cpsw_ale_destroy(struct cpsw_ale *ale) kfree(ale); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_destroy); void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) { @@ -807,3 +824,8 @@ void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) data += ALE_ENTRY_WORDS; } } +EXPORT_SYMBOL_GPL(cpsw_ale_dump); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TI CPSW ALE driver"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c index 4a4388b813ac..fbe42cb107ec 100644 --- a/drivers/net/ethernet/ti/cpts.c +++ b/drivers/net/ethernet/ti/cpts.c @@ -157,14 +157,11 @@ static int cpts_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) static int cpts_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { - s64 now; unsigned long flags; struct cpts *cpts = container_of(ptp, struct cpts, info); spin_lock_irqsave(&cpts->lock, flags); - now = timecounter_read(&cpts->tc); - now += delta; - timecounter_init(&cpts->tc, &cpts->cc, now); + timecounter_adjtime(&cpts->tc, delta); spin_unlock_irqrestore(&cpts->lock, flags); return 0; diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h index 1a581ef7eee8..69a46b92c7d6 100644 --- a/drivers/net/ethernet/ti/cpts.h +++ b/drivers/net/ethernet/ti/cpts.h @@ -27,6 +27,7 @@ #include #include #include +#include struct cpsw_cpts { u32 idver; /* Identification and version */ diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index ea712512c7d1..aeebc0a7bf47 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -62,12 +63,15 @@ #include #include #include +#include #include #include +#include #include #include +#include "cpsw.h" #include "davinci_cpdma.h" static int debug_level; @@ -343,9 +347,7 @@ struct emac_priv { u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS]; u32 rx_addr_type; const char *phy_id; -#ifdef CONFIG_OF struct device_node *phy_node; -#endif struct phy_device *phydev; spinlock_t lock; /*platform specific members*/ @@ -922,6 +924,16 @@ static void emac_int_disable(struct emac_priv *priv) if (priv->int_disable) priv->int_disable(); + /* NOTE: Rx Threshold and Misc interrupts are not enabled */ + + /* ack rxen only then a new pulse will be generated */ + emac_write(EMAC_DM646X_MACEOIVECTOR, + EMAC_DM646X_MAC_EOI_C0_RXEN); + + /* ack txen- only then a new pulse will be generated */ + emac_write(EMAC_DM646X_MACEOIVECTOR, + EMAC_DM646X_MAC_EOI_C0_TXEN); + local_irq_restore(flags); } else { @@ -951,15 +963,6 @@ static void emac_int_enable(struct emac_priv *priv) * register */ /* NOTE: Rx Threshold and Misc interrupts are not enabled */ - - /* ack rxen only then a new pulse will be generated */ - emac_write(EMAC_DM646X_MACEOIVECTOR, - EMAC_DM646X_MAC_EOI_C0_RXEN); - - /* ack txen- only then a new pulse will be generated */ - emac_write(EMAC_DM646X_MACEOIVECTOR, - EMAC_DM646X_MAC_EOI_C0_TXEN); - } else { /* Set DM644x control registers for interrupt control */ emac_ctrl_write(EMAC_CTRL_EWCTL, 0x1); @@ -1537,7 +1540,13 @@ static int emac_dev_open(struct net_device *ndev) int i = 0; struct emac_priv *priv = netdev_priv(ndev); - pm_runtime_get(&priv->pdev->dev); + ret = pm_runtime_get_sync(&priv->pdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(&priv->pdev->dev); + dev_err(&priv->pdev->dev, "%s: failed to get_sync(%d)\n", + __func__, ret); + return ret; + } netif_carrier_off(ndev); for (cnt = 0; cnt < ETH_ALEN; cnt++) @@ -1596,8 +1605,20 @@ static int emac_dev_open(struct net_device *ndev) cpdma_ctlr_start(priv->dma); priv->phydev = NULL; + + if (priv->phy_node) { + priv->phydev = of_phy_connect(ndev, priv->phy_node, + &emac_adjust_link, 0, 0); + if (!priv->phydev) { + dev_err(emac_dev, "could not connect to phy %s\n", + priv->phy_node->full_name); + ret = -ENODEV; + goto err; + } + } + /* use the first phy on the bus if pdata did not give us a phy id */ - if (!priv->phy_id) { + if (!priv->phydev && !priv->phy_id) { struct device *phy; phy = bus_find_device(&mdio_bus_type, NULL, NULL, @@ -1606,7 +1627,7 @@ static int emac_dev_open(struct net_device *ndev) priv->phy_id = dev_name(phy); } - if (priv->phy_id && *priv->phy_id) { + if (!priv->phydev && priv->phy_id && *priv->phy_id) { priv->phydev = phy_connect(ndev, priv->phy_id, &emac_adjust_link, PHY_INTERFACE_MODE_MII); @@ -1627,7 +1648,9 @@ static int emac_dev_open(struct net_device *ndev) "(mii_bus:phy_addr=%s, id=%x)\n", priv->phydev->drv->name, dev_name(&priv->phydev->dev), priv->phydev->phy_id); - } else { + } + + if (!priv->phydev) { /* No PHY , fix the link, speed and duplex settings */ dev_notice(emac_dev, "no phy, defaulting to 100/full\n"); priv->link = 1; @@ -1724,6 +1747,15 @@ static struct net_device_stats *emac_dev_getnetstats(struct net_device *ndev) struct emac_priv *priv = netdev_priv(ndev); u32 mac_control; u32 stats_clear_mask; + int err; + + err = pm_runtime_get_sync(&priv->pdev->dev); + if (err < 0) { + pm_runtime_put_noidle(&priv->pdev->dev); + dev_err(&priv->pdev->dev, "%s: failed to get_sync(%d)\n", + __func__, err); + return &ndev->stats; + } /* update emac hardware stats and reset the registers*/ @@ -1766,6 +1798,8 @@ static struct net_device_stats *emac_dev_getnetstats(struct net_device *ndev) ndev->stats.tx_fifo_errors += emac_read(EMAC_TXUNDERRUN); emac_write(EMAC_TXUNDERRUN, stats_clear_mask); + pm_runtime_put(&priv->pdev->dev); + return &ndev->stats; } @@ -1807,7 +1841,7 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv) if (!is_valid_ether_addr(pdata->mac_addr)) { mac_addr = of_get_mac_address(np); if (mac_addr) - memcpy(pdata->mac_addr, mac_addr, ETH_ALEN); + ether_addr_copy(pdata->mac_addr, mac_addr); } of_property_read_u32(np, "ti,davinci-ctrl-reg-offset", @@ -1848,6 +1882,53 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv) return pdata; } +static int davinci_emac_3517_get_macid(struct device *dev, u16 offset, + int slave, u8 *mac_addr) +{ + u32 macid_lsb; + u32 macid_msb; + struct regmap *syscon; + + syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); + if (IS_ERR(syscon)) { + if (PTR_ERR(syscon) == -ENODEV) + return 0; + return PTR_ERR(syscon); + } + + regmap_read(syscon, offset, &macid_lsb); + regmap_read(syscon, offset + 4, &macid_msb); + + mac_addr[0] = (macid_msb >> 16) & 0xff; + mac_addr[1] = (macid_msb >> 8) & 0xff; + mac_addr[2] = macid_msb & 0xff; + mac_addr[3] = (macid_lsb >> 16) & 0xff; + mac_addr[4] = (macid_lsb >> 8) & 0xff; + mac_addr[5] = macid_lsb & 0xff; + + return 0; +} + +static int davinci_emac_try_get_mac(struct platform_device *pdev, + int instance, u8 *mac_addr) +{ + int error = -EINVAL; + + if (!pdev->dev.of_node) + return error; + + if (of_device_is_compatible(pdev->dev.of_node, "ti,am3517-emac")) + error = davinci_emac_3517_get_macid(&pdev->dev, 0x110, + 0, mac_addr); + else if (of_device_is_compatible(pdev->dev.of_node, + "ti,dm816-emac")) + error = cpsw_am33xx_cm_get_macid(&pdev->dev, 0x30, + instance, + mac_addr); + + return error; +} + /** * davinci_emac_probe - EMAC device probe * @pdev: The DaVinci EMAC device that we are removing @@ -1859,7 +1940,7 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv) static int davinci_emac_probe(struct platform_device *pdev) { int rc = 0; - struct resource *res; + struct resource *res, *res_ctrl; struct net_device *ndev; struct emac_priv *priv; unsigned long hw_ram_addr; @@ -1876,6 +1957,7 @@ static int davinci_emac_probe(struct platform_device *pdev) return -EBUSY; } emac_bus_frequency = clk_get_rate(emac_clk); + devm_clk_put(&pdev->dev, emac_clk); /* TODO: Probe PHY here if possible */ @@ -1917,11 +1999,20 @@ static int davinci_emac_probe(struct platform_device *pdev) rc = PTR_ERR(priv->remap_addr); goto no_pdata; } + + res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res_ctrl) { + priv->ctrl_base = + devm_ioremap_resource(&pdev->dev, res_ctrl); + if (IS_ERR(priv->ctrl_base)) + goto no_pdata; + } else { + priv->ctrl_base = priv->remap_addr + pdata->ctrl_mod_reg_offset; + } + priv->emac_base = priv->remap_addr + pdata->ctrl_reg_offset; ndev->base_addr = (unsigned long)priv->remap_addr; - priv->ctrl_base = priv->remap_addr + pdata->ctrl_mod_reg_offset; - hw_ram_addr = pdata->hw_ram_addr; if (!hw_ram_addr) hw_ram_addr = (u32 __force)res->start + pdata->ctrl_ram_offset; @@ -1968,6 +2059,10 @@ static int davinci_emac_probe(struct platform_device *pdev) } ndev->irq = res->start; + rc = davinci_emac_try_get_mac(pdev, res_ctrl ? 0 : 1, priv->mac_addr); + if (!rc) + ether_addr_copy(ndev->dev_addr, priv->mac_addr); + if (!is_valid_ether_addr(priv->mac_addr)) { /* Use random MAC if none passed */ eth_hw_addr_random(ndev); @@ -1980,12 +2075,22 @@ static int davinci_emac_probe(struct platform_device *pdev) ndev->ethtool_ops = ðtool_ops; netif_napi_add(ndev, &priv->napi, emac_poll, EMAC_POLL_WEIGHT); + pm_runtime_enable(&pdev->dev); + rc = pm_runtime_get_sync(&pdev->dev); + if (rc < 0) { + pm_runtime_put_noidle(&pdev->dev); + dev_err(&pdev->dev, "%s: failed to get_sync(%d)\n", + __func__, rc); + goto no_cpdma_chan; + } + /* register the network device */ SET_NETDEV_DEV(ndev, &pdev->dev); rc = register_netdev(ndev); if (rc) { dev_err(&pdev->dev, "error in register_netdev\n"); rc = -ENODEV; + pm_runtime_put(&pdev->dev); goto no_cpdma_chan; } @@ -1995,9 +2100,7 @@ static int davinci_emac_probe(struct platform_device *pdev) "(regs: %p, irq: %d)\n", (void *)priv->emac_base_phys, ndev->irq); } - - pm_runtime_enable(&pdev->dev); - pm_runtime_resume(&pdev->dev); + pm_runtime_put(&pdev->dev); return 0; @@ -2071,9 +2174,14 @@ static const struct emac_platform_data am3517_emac_data = { .hw_ram_addr = 0x01e20000, }; +static const struct emac_platform_data dm816_emac_data = { + .version = EMAC_VERSION_2, +}; + static const struct of_device_id davinci_emac_of_match[] = { {.compatible = "ti,davinci-dm6467-emac", }, {.compatible = "ti,am3517-emac", .data = &am3517_emac_data, }, + {.compatible = "ti,dm816-emac", .data = &dm816_emac_data, }, {}, }; MODULE_DEVICE_TABLE(of, davinci_emac_of_match); diff --git a/drivers/net/ethernet/ti/netcp.h b/drivers/net/ethernet/ti/netcp.h new file mode 100644 index 000000000000..906e9bc412f5 --- /dev/null +++ b/drivers/net/ethernet/ti/netcp.h @@ -0,0 +1,229 @@ +/* + * NetCP driver local header + * + * Copyright (C) 2014 Texas Instruments Incorporated + * Authors: Sandeep Nair + * Sandeep Paulraj + * Cyril Chemparathy + * Santosh Shilimkar + * Wingman Kwok + * Murali Karicheri + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __NETCP_H__ +#define __NETCP_H__ + +#include +#include + +/* Maximum Ethernet frame size supported by Keystone switch */ +#define NETCP_MAX_FRAME_SIZE 9504 + +#define SGMII_LINK_MAC_MAC_AUTONEG 0 +#define SGMII_LINK_MAC_PHY 1 +#define SGMII_LINK_MAC_MAC_FORCED 2 +#define SGMII_LINK_MAC_FIBER 3 +#define SGMII_LINK_MAC_PHY_NO_MDIO 4 +#define XGMII_LINK_MAC_PHY 10 +#define XGMII_LINK_MAC_MAC_FORCED 11 + +struct netcp_device; + +struct netcp_tx_pipe { + struct netcp_device *netcp_device; + void *dma_queue; + unsigned int dma_queue_id; + u8 dma_psflags; + void *dma_channel; + const char *dma_chan_name; +}; + +#define ADDR_NEW BIT(0) +#define ADDR_VALID BIT(1) + +enum netcp_addr_type { + ADDR_ANY, + ADDR_DEV, + ADDR_UCAST, + ADDR_MCAST, + ADDR_BCAST +}; + +struct netcp_addr { + struct netcp_intf *netcp; + unsigned char addr[ETH_ALEN]; + enum netcp_addr_type type; + unsigned int flags; + struct list_head node; +}; + +struct netcp_intf { + struct device *dev; + struct device *ndev_dev; + struct net_device *ndev; + bool big_endian; + unsigned int tx_compl_qid; + void *tx_pool; + struct list_head txhook_list_head; + unsigned int tx_pause_threshold; + void *tx_compl_q; + + unsigned int tx_resume_threshold; + void *rx_queue; + void *rx_pool; + struct list_head rxhook_list_head; + unsigned int rx_queue_id; + void *rx_fdq[KNAV_DMA_FDQ_PER_CHAN]; + u32 rx_buffer_sizes[KNAV_DMA_FDQ_PER_CHAN]; + struct napi_struct rx_napi; + struct napi_struct tx_napi; + + void *rx_channel; + const char *dma_chan_name; + u32 rx_pool_size; + u32 rx_pool_region_id; + u32 tx_pool_size; + u32 tx_pool_region_id; + struct list_head module_head; + struct list_head interface_list; + struct list_head addr_list; + bool netdev_registered; + bool primary_module_attached; + + /* Lock used for protecting Rx/Tx hook list management */ + spinlock_t lock; + struct netcp_device *netcp_device; + struct device_node *node_interface; + + /* DMA configuration data */ + u32 msg_enable; + u32 rx_queue_depths[KNAV_DMA_FDQ_PER_CHAN]; +}; + +#define NETCP_PSDATA_LEN KNAV_DMA_NUM_PS_WORDS +struct netcp_packet { + struct sk_buff *skb; + u32 *epib; + u32 *psdata; + unsigned int psdata_len; + struct netcp_intf *netcp; + struct netcp_tx_pipe *tx_pipe; + bool rxtstamp_complete; + void *ts_context; + + int (*txtstamp_complete)(void *ctx, struct netcp_packet *pkt); +}; + +static inline u32 *netcp_push_psdata(struct netcp_packet *p_info, + unsigned int bytes) +{ + u32 *buf; + unsigned int words; + + if ((bytes & 0x03) != 0) + return NULL; + words = bytes >> 2; + + if ((p_info->psdata_len + words) > NETCP_PSDATA_LEN) + return NULL; + + p_info->psdata_len += words; + buf = &p_info->psdata[NETCP_PSDATA_LEN - p_info->psdata_len]; + return buf; +} + +static inline int netcp_align_psdata(struct netcp_packet *p_info, + unsigned int byte_align) +{ + int padding; + + switch (byte_align) { + case 0: + padding = -EINVAL; + break; + case 1: + case 2: + case 4: + padding = 0; + break; + case 8: + padding = (p_info->psdata_len << 2) % 8; + break; + case 16: + padding = (p_info->psdata_len << 2) % 16; + break; + default: + padding = (p_info->psdata_len << 2) % byte_align; + break; + } + return padding; +} + +struct netcp_module { + const char *name; + struct module *owner; + bool primary; + + /* probe/remove: called once per NETCP instance */ + int (*probe)(struct netcp_device *netcp_device, + struct device *device, struct device_node *node, + void **inst_priv); + int (*remove)(struct netcp_device *netcp_device, void *inst_priv); + + /* attach/release: called once per network interface */ + int (*attach)(void *inst_priv, struct net_device *ndev, + struct device_node *node, void **intf_priv); + int (*release)(void *intf_priv); + int (*open)(void *intf_priv, struct net_device *ndev); + int (*close)(void *intf_priv, struct net_device *ndev); + int (*add_addr)(void *intf_priv, struct netcp_addr *naddr); + int (*del_addr)(void *intf_priv, struct netcp_addr *naddr); + int (*add_vid)(void *intf_priv, int vid); + int (*del_vid)(void *intf_priv, int vid); + int (*ioctl)(void *intf_priv, struct ifreq *req, int cmd); + + /* used internally */ + struct list_head module_list; + struct list_head interface_list; +}; + +int netcp_register_module(struct netcp_module *module); +void netcp_unregister_module(struct netcp_module *module); +void *netcp_module_get_intf_data(struct netcp_module *module, + struct netcp_intf *intf); + +int netcp_txpipe_init(struct netcp_tx_pipe *tx_pipe, + struct netcp_device *netcp_device, + const char *dma_chan_name, unsigned int dma_queue_id); +int netcp_txpipe_open(struct netcp_tx_pipe *tx_pipe); +int netcp_txpipe_close(struct netcp_tx_pipe *tx_pipe); + +typedef int netcp_hook_rtn(int order, void *data, struct netcp_packet *packet); +int netcp_register_txhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data); +int netcp_unregister_txhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data); +int netcp_register_rxhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data); +int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data); +void *netcp_device_find_module(struct netcp_device *netcp_device, + const char *name); + +/* SGMII functions */ +int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port); +int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port); +int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface); + +/* XGBE SERDES init functions */ +int netcp_xgbe_serdes_init(void __iomem *serdes_regs, void __iomem *xgbe_regs); + +#endif /* __NETCP_H__ */ diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c new file mode 100644 index 000000000000..a31a8c3c8e7c --- /dev/null +++ b/drivers/net/ethernet/ti/netcp_core.c @@ -0,0 +1,2149 @@ +/* + * Keystone NetCP Core driver + * + * Copyright (C) 2014 Texas Instruments Incorporated + * Authors: Sandeep Nair + * Sandeep Paulraj + * Cyril Chemparathy + * Santosh Shilimkar + * Murali Karicheri + * Wingman Kwok + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "netcp.h" + +#define NETCP_SOP_OFFSET (NET_IP_ALIGN + NET_SKB_PAD) +#define NETCP_NAPI_WEIGHT 64 +#define NETCP_TX_TIMEOUT (5 * HZ) +#define NETCP_MIN_PACKET_SIZE ETH_ZLEN +#define NETCP_MAX_MCAST_ADDR 16 + +#define NETCP_EFUSE_REG_INDEX 0 + +#define NETCP_MOD_PROBE_SKIPPED 1 +#define NETCP_MOD_PROBE_FAILED 2 + +#define NETCP_DEBUG (NETIF_MSG_HW | NETIF_MSG_WOL | \ + NETIF_MSG_DRV | NETIF_MSG_LINK | \ + NETIF_MSG_IFUP | NETIF_MSG_INTR | \ + NETIF_MSG_PROBE | NETIF_MSG_TIMER | \ + NETIF_MSG_IFDOWN | NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR | NETIF_MSG_TX_DONE | \ + NETIF_MSG_PKTDATA | NETIF_MSG_TX_QUEUED | \ + NETIF_MSG_RX_STATUS) + +#define knav_queue_get_id(q) knav_queue_device_control(q, \ + KNAV_QUEUE_GET_ID, (unsigned long)NULL) + +#define knav_queue_enable_notify(q) knav_queue_device_control(q, \ + KNAV_QUEUE_ENABLE_NOTIFY, \ + (unsigned long)NULL) + +#define knav_queue_disable_notify(q) knav_queue_device_control(q, \ + KNAV_QUEUE_DISABLE_NOTIFY, \ + (unsigned long)NULL) + +#define knav_queue_get_count(q) knav_queue_device_control(q, \ + KNAV_QUEUE_GET_COUNT, (unsigned long)NULL) + +#define for_each_netcp_module(module) \ + list_for_each_entry(module, &netcp_modules, module_list) + +#define for_each_netcp_device_module(netcp_device, inst_modpriv) \ + list_for_each_entry(inst_modpriv, \ + &((netcp_device)->modpriv_head), inst_list) + +#define for_each_module(netcp, intf_modpriv) \ + list_for_each_entry(intf_modpriv, &netcp->module_head, intf_list) + +/* Module management structures */ +struct netcp_device { + struct list_head device_list; + struct list_head interface_head; + struct list_head modpriv_head; + struct device *device; +}; + +struct netcp_inst_modpriv { + struct netcp_device *netcp_device; + struct netcp_module *netcp_module; + struct list_head inst_list; + void *module_priv; +}; + +struct netcp_intf_modpriv { + struct netcp_intf *netcp_priv; + struct netcp_module *netcp_module; + struct list_head intf_list; + void *module_priv; +}; + +static LIST_HEAD(netcp_devices); +static LIST_HEAD(netcp_modules); +static DEFINE_MUTEX(netcp_modules_lock); + +static int netcp_debug_level = -1; +module_param(netcp_debug_level, int, 0); +MODULE_PARM_DESC(netcp_debug_level, "Netcp debug level (NETIF_MSG bits) (0=none,...,16=all)"); + +/* Helper functions - Get/Set */ +static void get_pkt_info(u32 *buff, u32 *buff_len, u32 *ndesc, + struct knav_dma_desc *desc) +{ + *buff_len = desc->buff_len; + *buff = desc->buff; + *ndesc = desc->next_desc; +} + +static void get_pad_info(u32 *pad0, u32 *pad1, struct knav_dma_desc *desc) +{ + *pad0 = desc->pad[0]; + *pad1 = desc->pad[1]; +} + +static void get_org_pkt_info(u32 *buff, u32 *buff_len, + struct knav_dma_desc *desc) +{ + *buff = desc->orig_buff; + *buff_len = desc->orig_len; +} + +static void get_words(u32 *words, int num_words, u32 *desc) +{ + int i; + + for (i = 0; i < num_words; i++) + words[i] = desc[i]; +} + +static void set_pkt_info(u32 buff, u32 buff_len, u32 ndesc, + struct knav_dma_desc *desc) +{ + desc->buff_len = buff_len; + desc->buff = buff; + desc->next_desc = ndesc; +} + +static void set_desc_info(u32 desc_info, u32 pkt_info, + struct knav_dma_desc *desc) +{ + desc->desc_info = desc_info; + desc->packet_info = pkt_info; +} + +static void set_pad_info(u32 pad0, u32 pad1, struct knav_dma_desc *desc) +{ + desc->pad[0] = pad0; + desc->pad[1] = pad1; +} + +static void set_org_pkt_info(u32 buff, u32 buff_len, + struct knav_dma_desc *desc) +{ + desc->orig_buff = buff; + desc->orig_len = buff_len; +} + +static void set_words(u32 *words, int num_words, u32 *desc) +{ + int i; + + for (i = 0; i < num_words; i++) + desc[i] = words[i]; +} + +/* Read the e-fuse value as 32 bit values to be endian independent */ +static int emac_arch_get_mac_addr(char *x, void __iomem *efuse_mac) +{ + unsigned int addr0, addr1; + + addr1 = readl(efuse_mac + 4); + addr0 = readl(efuse_mac); + + x[0] = (addr1 & 0x0000ff00) >> 8; + x[1] = addr1 & 0x000000ff; + x[2] = (addr0 & 0xff000000) >> 24; + x[3] = (addr0 & 0x00ff0000) >> 16; + x[4] = (addr0 & 0x0000ff00) >> 8; + x[5] = addr0 & 0x000000ff; + + return 0; +} + +static const char *netcp_node_name(struct device_node *node) +{ + const char *name; + + if (of_property_read_string(node, "label", &name) < 0) + name = node->name; + if (!name) + name = "unknown"; + return name; +} + +/* Module management routines */ +static int netcp_register_interface(struct netcp_intf *netcp) +{ + int ret; + + ret = register_netdev(netcp->ndev); + if (!ret) + netcp->netdev_registered = true; + return ret; +} + +static int netcp_module_probe(struct netcp_device *netcp_device, + struct netcp_module *module) +{ + struct device *dev = netcp_device->device; + struct device_node *devices, *interface, *node = dev->of_node; + struct device_node *child; + struct netcp_inst_modpriv *inst_modpriv; + struct netcp_intf *netcp_intf; + struct netcp_module *tmp; + bool primary_module_registered = false; + int ret; + + /* Find this module in the sub-tree for this device */ + devices = of_get_child_by_name(node, "netcp-devices"); + if (!devices) { + dev_err(dev, "could not find netcp-devices node\n"); + return NETCP_MOD_PROBE_SKIPPED; + } + + for_each_available_child_of_node(devices, child) { + const char *name = netcp_node_name(child); + + if (!strcasecmp(module->name, name)) + break; + } + + of_node_put(devices); + /* If module not used for this device, skip it */ + if (!child) { + dev_warn(dev, "module(%s) not used for device\n", module->name); + return NETCP_MOD_PROBE_SKIPPED; + } + + inst_modpriv = devm_kzalloc(dev, sizeof(*inst_modpriv), GFP_KERNEL); + if (!inst_modpriv) { + of_node_put(child); + return -ENOMEM; + } + + inst_modpriv->netcp_device = netcp_device; + inst_modpriv->netcp_module = module; + list_add_tail(&inst_modpriv->inst_list, &netcp_device->modpriv_head); + + ret = module->probe(netcp_device, dev, child, + &inst_modpriv->module_priv); + of_node_put(child); + if (ret) { + dev_err(dev, "Probe of module(%s) failed with %d\n", + module->name, ret); + list_del(&inst_modpriv->inst_list); + devm_kfree(dev, inst_modpriv); + return NETCP_MOD_PROBE_FAILED; + } + + /* Attach modules only if the primary module is probed */ + for_each_netcp_module(tmp) { + if (tmp->primary) + primary_module_registered = true; + } + + if (!primary_module_registered) + return 0; + + /* Attach module to interfaces */ + list_for_each_entry(netcp_intf, &netcp_device->interface_head, + interface_list) { + struct netcp_intf_modpriv *intf_modpriv; + + /* If interface not registered then register now */ + if (!netcp_intf->netdev_registered) + ret = netcp_register_interface(netcp_intf); + + if (ret) + return -ENODEV; + + intf_modpriv = devm_kzalloc(dev, sizeof(*intf_modpriv), + GFP_KERNEL); + if (!intf_modpriv) + return -ENOMEM; + + interface = of_parse_phandle(netcp_intf->node_interface, + module->name, 0); + + intf_modpriv->netcp_priv = netcp_intf; + intf_modpriv->netcp_module = module; + list_add_tail(&intf_modpriv->intf_list, + &netcp_intf->module_head); + + ret = module->attach(inst_modpriv->module_priv, + netcp_intf->ndev, interface, + &intf_modpriv->module_priv); + of_node_put(interface); + if (ret) { + dev_dbg(dev, "Attach of module %s declined with %d\n", + module->name, ret); + list_del(&intf_modpriv->intf_list); + devm_kfree(dev, intf_modpriv); + continue; + } + } + return 0; +} + +int netcp_register_module(struct netcp_module *module) +{ + struct netcp_device *netcp_device; + struct netcp_module *tmp; + int ret; + + if (!module->name) { + WARN(1, "error registering netcp module: no name\n"); + return -EINVAL; + } + + if (!module->probe) { + WARN(1, "error registering netcp module: no probe\n"); + return -EINVAL; + } + + mutex_lock(&netcp_modules_lock); + + for_each_netcp_module(tmp) { + if (!strcasecmp(tmp->name, module->name)) { + mutex_unlock(&netcp_modules_lock); + return -EEXIST; + } + } + list_add_tail(&module->module_list, &netcp_modules); + + list_for_each_entry(netcp_device, &netcp_devices, device_list) { + ret = netcp_module_probe(netcp_device, module); + if (ret < 0) + goto fail; + } + + mutex_unlock(&netcp_modules_lock); + return 0; + +fail: + mutex_unlock(&netcp_modules_lock); + netcp_unregister_module(module); + return ret; +} +EXPORT_SYMBOL_GPL(netcp_register_module); + +static void netcp_release_module(struct netcp_device *netcp_device, + struct netcp_module *module) +{ + struct netcp_inst_modpriv *inst_modpriv, *inst_tmp; + struct netcp_intf *netcp_intf, *netcp_tmp; + struct device *dev = netcp_device->device; + + /* Release the module from each interface */ + list_for_each_entry_safe(netcp_intf, netcp_tmp, + &netcp_device->interface_head, + interface_list) { + struct netcp_intf_modpriv *intf_modpriv, *intf_tmp; + + list_for_each_entry_safe(intf_modpriv, intf_tmp, + &netcp_intf->module_head, + intf_list) { + if (intf_modpriv->netcp_module == module) { + module->release(intf_modpriv->module_priv); + list_del(&intf_modpriv->intf_list); + devm_kfree(dev, intf_modpriv); + break; + } + } + } + + /* Remove the module from each instance */ + list_for_each_entry_safe(inst_modpriv, inst_tmp, + &netcp_device->modpriv_head, inst_list) { + if (inst_modpriv->netcp_module == module) { + module->remove(netcp_device, + inst_modpriv->module_priv); + list_del(&inst_modpriv->inst_list); + devm_kfree(dev, inst_modpriv); + break; + } + } +} + +void netcp_unregister_module(struct netcp_module *module) +{ + struct netcp_device *netcp_device; + struct netcp_module *module_tmp; + + mutex_lock(&netcp_modules_lock); + + list_for_each_entry(netcp_device, &netcp_devices, device_list) { + netcp_release_module(netcp_device, module); + } + + /* Remove the module from the module list */ + for_each_netcp_module(module_tmp) { + if (module == module_tmp) { + list_del(&module->module_list); + break; + } + } + + mutex_unlock(&netcp_modules_lock); +} +EXPORT_SYMBOL_GPL(netcp_unregister_module); + +void *netcp_module_get_intf_data(struct netcp_module *module, + struct netcp_intf *intf) +{ + struct netcp_intf_modpriv *intf_modpriv; + + list_for_each_entry(intf_modpriv, &intf->module_head, intf_list) + if (intf_modpriv->netcp_module == module) + return intf_modpriv->module_priv; + return NULL; +} +EXPORT_SYMBOL_GPL(netcp_module_get_intf_data); + +/* Module TX and RX Hook management */ +struct netcp_hook_list { + struct list_head list; + netcp_hook_rtn *hook_rtn; + void *hook_data; + int order; +}; + +int netcp_register_txhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data) +{ + struct netcp_hook_list *entry; + struct netcp_hook_list *next; + unsigned long flags; + + entry = devm_kzalloc(netcp_priv->dev, sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + entry->hook_rtn = hook_rtn; + entry->hook_data = hook_data; + entry->order = order; + + spin_lock_irqsave(&netcp_priv->lock, flags); + list_for_each_entry(next, &netcp_priv->txhook_list_head, list) { + if (next->order > order) + break; + } + __list_add(&entry->list, next->list.prev, &next->list); + spin_unlock_irqrestore(&netcp_priv->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(netcp_register_txhook); + +int netcp_unregister_txhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data) +{ + struct netcp_hook_list *next, *n; + unsigned long flags; + + spin_lock_irqsave(&netcp_priv->lock, flags); + list_for_each_entry_safe(next, n, &netcp_priv->txhook_list_head, list) { + if ((next->order == order) && + (next->hook_rtn == hook_rtn) && + (next->hook_data == hook_data)) { + list_del(&next->list); + spin_unlock_irqrestore(&netcp_priv->lock, flags); + devm_kfree(netcp_priv->dev, next); + return 0; + } + } + spin_unlock_irqrestore(&netcp_priv->lock, flags); + return -ENOENT; +} +EXPORT_SYMBOL_GPL(netcp_unregister_txhook); + +int netcp_register_rxhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data) +{ + struct netcp_hook_list *entry; + struct netcp_hook_list *next; + unsigned long flags; + + entry = devm_kzalloc(netcp_priv->dev, sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + entry->hook_rtn = hook_rtn; + entry->hook_data = hook_data; + entry->order = order; + + spin_lock_irqsave(&netcp_priv->lock, flags); + list_for_each_entry(next, &netcp_priv->rxhook_list_head, list) { + if (next->order > order) + break; + } + __list_add(&entry->list, next->list.prev, &next->list); + spin_unlock_irqrestore(&netcp_priv->lock, flags); + + return 0; +} + +int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order, + netcp_hook_rtn *hook_rtn, void *hook_data) +{ + struct netcp_hook_list *next, *n; + unsigned long flags; + + spin_lock_irqsave(&netcp_priv->lock, flags); + list_for_each_entry_safe(next, n, &netcp_priv->rxhook_list_head, list) { + if ((next->order == order) && + (next->hook_rtn == hook_rtn) && + (next->hook_data == hook_data)) { + list_del(&next->list); + spin_unlock_irqrestore(&netcp_priv->lock, flags); + devm_kfree(netcp_priv->dev, next); + return 0; + } + } + spin_unlock_irqrestore(&netcp_priv->lock, flags); + + return -ENOENT; +} + +static void netcp_frag_free(bool is_frag, void *ptr) +{ + if (is_frag) + put_page(virt_to_head_page(ptr)); + else + kfree(ptr); +} + +static void netcp_free_rx_desc_chain(struct netcp_intf *netcp, + struct knav_dma_desc *desc) +{ + struct knav_dma_desc *ndesc; + dma_addr_t dma_desc, dma_buf; + unsigned int buf_len, dma_sz = sizeof(*ndesc); + void *buf_ptr; + u32 tmp; + + get_words(&dma_desc, 1, &desc->next_desc); + + while (dma_desc) { + ndesc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz); + if (unlikely(!ndesc)) { + dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n"); + break; + } + get_pkt_info(&dma_buf, &tmp, &dma_desc, ndesc); + get_pad_info((u32 *)&buf_ptr, &tmp, ndesc); + dma_unmap_page(netcp->dev, dma_buf, PAGE_SIZE, DMA_FROM_DEVICE); + __free_page(buf_ptr); + knav_pool_desc_put(netcp->rx_pool, desc); + } + + get_pad_info((u32 *)&buf_ptr, &buf_len, desc); + if (buf_ptr) + netcp_frag_free(buf_len <= PAGE_SIZE, buf_ptr); + knav_pool_desc_put(netcp->rx_pool, desc); +} + +static void netcp_empty_rx_queue(struct netcp_intf *netcp) +{ + struct knav_dma_desc *desc; + unsigned int dma_sz; + dma_addr_t dma; + + for (; ;) { + dma = knav_queue_pop(netcp->rx_queue, &dma_sz); + if (!dma) + break; + + desc = knav_pool_desc_unmap(netcp->rx_pool, dma, dma_sz); + if (unlikely(!desc)) { + dev_err(netcp->ndev_dev, "%s: failed to unmap Rx desc\n", + __func__); + netcp->ndev->stats.rx_errors++; + continue; + } + netcp_free_rx_desc_chain(netcp, desc); + netcp->ndev->stats.rx_dropped++; + } +} + +static int netcp_process_one_rx_packet(struct netcp_intf *netcp) +{ + unsigned int dma_sz, buf_len, org_buf_len; + struct knav_dma_desc *desc, *ndesc; + unsigned int pkt_sz = 0, accum_sz; + struct netcp_hook_list *rx_hook; + dma_addr_t dma_desc, dma_buff; + struct netcp_packet p_info; + struct sk_buff *skb; + void *org_buf_ptr; + u32 tmp; + + dma_desc = knav_queue_pop(netcp->rx_queue, &dma_sz); + if (!dma_desc) + return -1; + + desc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz); + if (unlikely(!desc)) { + dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n"); + return 0; + } + + get_pkt_info(&dma_buff, &buf_len, &dma_desc, desc); + get_pad_info((u32 *)&org_buf_ptr, &org_buf_len, desc); + + if (unlikely(!org_buf_ptr)) { + dev_err(netcp->ndev_dev, "NULL bufptr in desc\n"); + goto free_desc; + } + + pkt_sz &= KNAV_DMA_DESC_PKT_LEN_MASK; + accum_sz = buf_len; + dma_unmap_single(netcp->dev, dma_buff, buf_len, DMA_FROM_DEVICE); + + /* Build a new sk_buff for the primary buffer */ + skb = build_skb(org_buf_ptr, org_buf_len); + if (unlikely(!skb)) { + dev_err(netcp->ndev_dev, "build_skb() failed\n"); + goto free_desc; + } + + /* update data, tail and len */ + skb_reserve(skb, NETCP_SOP_OFFSET); + __skb_put(skb, buf_len); + + /* Fill in the page fragment list */ + while (dma_desc) { + struct page *page; + + ndesc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz); + if (unlikely(!ndesc)) { + dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n"); + goto free_desc; + } + + get_pkt_info(&dma_buff, &buf_len, &dma_desc, ndesc); + get_pad_info((u32 *)&page, &tmp, ndesc); + + if (likely(dma_buff && buf_len && page)) { + dma_unmap_page(netcp->dev, dma_buff, PAGE_SIZE, + DMA_FROM_DEVICE); + } else { + dev_err(netcp->ndev_dev, "Bad Rx desc dma_buff(%p), len(%d), page(%p)\n", + (void *)dma_buff, buf_len, page); + goto free_desc; + } + + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, + offset_in_page(dma_buff), buf_len, PAGE_SIZE); + accum_sz += buf_len; + + /* Free the descriptor */ + knav_pool_desc_put(netcp->rx_pool, ndesc); + } + + /* Free the primary descriptor */ + knav_pool_desc_put(netcp->rx_pool, desc); + + /* check for packet len and warn */ + if (unlikely(pkt_sz != accum_sz)) + dev_dbg(netcp->ndev_dev, "mismatch in packet size(%d) & sum of fragments(%d)\n", + pkt_sz, accum_sz); + + /* Remove ethernet FCS from the packet */ + __pskb_trim(skb, skb->len - ETH_FCS_LEN); + + /* Call each of the RX hooks */ + p_info.skb = skb; + p_info.rxtstamp_complete = false; + list_for_each_entry(rx_hook, &netcp->rxhook_list_head, list) { + int ret; + + ret = rx_hook->hook_rtn(rx_hook->order, rx_hook->hook_data, + &p_info); + if (unlikely(ret)) { + dev_err(netcp->ndev_dev, "RX hook %d failed: %d\n", + rx_hook->order, ret); + netcp->ndev->stats.rx_errors++; + dev_kfree_skb(skb); + return 0; + } + } + + netcp->ndev->last_rx = jiffies; + netcp->ndev->stats.rx_packets++; + netcp->ndev->stats.rx_bytes += skb->len; + + /* push skb up the stack */ + skb->protocol = eth_type_trans(skb, netcp->ndev); + netif_receive_skb(skb); + return 0; + +free_desc: + netcp_free_rx_desc_chain(netcp, desc); + netcp->ndev->stats.rx_errors++; + return 0; +} + +static int netcp_process_rx_packets(struct netcp_intf *netcp, + unsigned int budget) +{ + int i; + + for (i = 0; (i < budget) && !netcp_process_one_rx_packet(netcp); i++) + ; + return i; +} + +/* Release descriptors and attached buffers from Rx FDQ */ +static void netcp_free_rx_buf(struct netcp_intf *netcp, int fdq) +{ + struct knav_dma_desc *desc; + unsigned int buf_len, dma_sz; + dma_addr_t dma; + void *buf_ptr; + u32 tmp; + + /* Allocate descriptor */ + while ((dma = knav_queue_pop(netcp->rx_fdq[fdq], &dma_sz))) { + desc = knav_pool_desc_unmap(netcp->rx_pool, dma, dma_sz); + if (unlikely(!desc)) { + dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n"); + continue; + } + + get_org_pkt_info(&dma, &buf_len, desc); + get_pad_info((u32 *)&buf_ptr, &tmp, desc); + + if (unlikely(!dma)) { + dev_err(netcp->ndev_dev, "NULL orig_buff in desc\n"); + knav_pool_desc_put(netcp->rx_pool, desc); + continue; + } + + if (unlikely(!buf_ptr)) { + dev_err(netcp->ndev_dev, "NULL bufptr in desc\n"); + knav_pool_desc_put(netcp->rx_pool, desc); + continue; + } + + if (fdq == 0) { + dma_unmap_single(netcp->dev, dma, buf_len, + DMA_FROM_DEVICE); + netcp_frag_free((buf_len <= PAGE_SIZE), buf_ptr); + } else { + dma_unmap_page(netcp->dev, dma, buf_len, + DMA_FROM_DEVICE); + __free_page(buf_ptr); + } + + knav_pool_desc_put(netcp->rx_pool, desc); + } +} + +static void netcp_rxpool_free(struct netcp_intf *netcp) +{ + int i; + + for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && + !IS_ERR_OR_NULL(netcp->rx_fdq[i]); i++) + netcp_free_rx_buf(netcp, i); + + if (knav_pool_count(netcp->rx_pool) != netcp->rx_pool_size) + dev_err(netcp->ndev_dev, "Lost Rx (%d) descriptors\n", + netcp->rx_pool_size - knav_pool_count(netcp->rx_pool)); + + knav_pool_destroy(netcp->rx_pool); + netcp->rx_pool = NULL; +} + +static void netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq) +{ + struct knav_dma_desc *hwdesc; + unsigned int buf_len, dma_sz; + u32 desc_info, pkt_info; + struct page *page; + dma_addr_t dma; + void *bufptr; + u32 pad[2]; + + /* Allocate descriptor */ + hwdesc = knav_pool_desc_get(netcp->rx_pool); + if (IS_ERR_OR_NULL(hwdesc)) { + dev_dbg(netcp->ndev_dev, "out of rx pool desc\n"); + return; + } + + if (likely(fdq == 0)) { + unsigned int primary_buf_len; + /* Allocate a primary receive queue entry */ + buf_len = netcp->rx_buffer_sizes[0] + NETCP_SOP_OFFSET; + primary_buf_len = SKB_DATA_ALIGN(buf_len) + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + + if (primary_buf_len <= PAGE_SIZE) { + bufptr = netdev_alloc_frag(primary_buf_len); + pad[1] = primary_buf_len; + } else { + bufptr = kmalloc(primary_buf_len, GFP_ATOMIC | + GFP_DMA32 | __GFP_COLD); + pad[1] = 0; + } + + if (unlikely(!bufptr)) { + dev_warn_ratelimited(netcp->ndev_dev, "Primary RX buffer alloc failed\n"); + goto fail; + } + dma = dma_map_single(netcp->dev, bufptr, buf_len, + DMA_TO_DEVICE); + pad[0] = (u32)bufptr; + + } else { + /* Allocate a secondary receive queue entry */ + page = alloc_page(GFP_ATOMIC | GFP_DMA32 | __GFP_COLD); + if (unlikely(!page)) { + dev_warn_ratelimited(netcp->ndev_dev, "Secondary page alloc failed\n"); + goto fail; + } + buf_len = PAGE_SIZE; + dma = dma_map_page(netcp->dev, page, 0, buf_len, DMA_TO_DEVICE); + pad[0] = (u32)page; + pad[1] = 0; + } + + desc_info = KNAV_DMA_DESC_PS_INFO_IN_DESC; + desc_info |= buf_len & KNAV_DMA_DESC_PKT_LEN_MASK; + pkt_info = KNAV_DMA_DESC_HAS_EPIB; + pkt_info |= KNAV_DMA_NUM_PS_WORDS << KNAV_DMA_DESC_PSLEN_SHIFT; + pkt_info |= (netcp->rx_queue_id & KNAV_DMA_DESC_RETQ_MASK) << + KNAV_DMA_DESC_RETQ_SHIFT; + set_org_pkt_info(dma, buf_len, hwdesc); + set_pad_info(pad[0], pad[1], hwdesc); + set_desc_info(desc_info, pkt_info, hwdesc); + + /* Push to FDQs */ + knav_pool_desc_map(netcp->rx_pool, hwdesc, sizeof(*hwdesc), &dma, + &dma_sz); + knav_queue_push(netcp->rx_fdq[fdq], dma, sizeof(*hwdesc), 0); + return; + +fail: + knav_pool_desc_put(netcp->rx_pool, hwdesc); +} + +/* Refill Rx FDQ with descriptors & attached buffers */ +static void netcp_rxpool_refill(struct netcp_intf *netcp) +{ + u32 fdq_deficit[KNAV_DMA_FDQ_PER_CHAN] = {0}; + int i; + + /* Calculate the FDQ deficit and refill */ + for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && netcp->rx_fdq[i]; i++) { + fdq_deficit[i] = netcp->rx_queue_depths[i] - + knav_queue_get_count(netcp->rx_fdq[i]); + + while (fdq_deficit[i]--) + netcp_allocate_rx_buf(netcp, i); + } /* end for fdqs */ +} + +/* NAPI poll */ +static int netcp_rx_poll(struct napi_struct *napi, int budget) +{ + struct netcp_intf *netcp = container_of(napi, struct netcp_intf, + rx_napi); + unsigned int packets; + + packets = netcp_process_rx_packets(netcp, budget); + + if (packets < budget) { + napi_complete(&netcp->rx_napi); + knav_queue_enable_notify(netcp->rx_queue); + } + + netcp_rxpool_refill(netcp); + return packets; +} + +static void netcp_rx_notify(void *arg) +{ + struct netcp_intf *netcp = arg; + + knav_queue_disable_notify(netcp->rx_queue); + napi_schedule(&netcp->rx_napi); +} + +static void netcp_free_tx_desc_chain(struct netcp_intf *netcp, + struct knav_dma_desc *desc, + unsigned int desc_sz) +{ + struct knav_dma_desc *ndesc = desc; + dma_addr_t dma_desc, dma_buf; + unsigned int buf_len; + + while (ndesc) { + get_pkt_info(&dma_buf, &buf_len, &dma_desc, ndesc); + + if (dma_buf && buf_len) + dma_unmap_single(netcp->dev, dma_buf, buf_len, + DMA_TO_DEVICE); + else + dev_warn(netcp->ndev_dev, "bad Tx desc buf(%p), len(%d)\n", + (void *)dma_buf, buf_len); + + knav_pool_desc_put(netcp->tx_pool, ndesc); + ndesc = NULL; + if (dma_desc) { + ndesc = knav_pool_desc_unmap(netcp->tx_pool, dma_desc, + desc_sz); + if (!ndesc) + dev_err(netcp->ndev_dev, "failed to unmap Tx desc\n"); + } + } +} + +static int netcp_process_tx_compl_packets(struct netcp_intf *netcp, + unsigned int budget) +{ + struct knav_dma_desc *desc; + struct sk_buff *skb; + unsigned int dma_sz; + dma_addr_t dma; + int pkts = 0; + u32 tmp; + + while (budget--) { + dma = knav_queue_pop(netcp->tx_compl_q, &dma_sz); + if (!dma) + break; + desc = knav_pool_desc_unmap(netcp->tx_pool, dma, dma_sz); + if (unlikely(!desc)) { + dev_err(netcp->ndev_dev, "failed to unmap Tx desc\n"); + netcp->ndev->stats.tx_errors++; + continue; + } + + get_pad_info((u32 *)&skb, &tmp, desc); + netcp_free_tx_desc_chain(netcp, desc, dma_sz); + if (!skb) { + dev_err(netcp->ndev_dev, "No skb in Tx desc\n"); + netcp->ndev->stats.tx_errors++; + continue; + } + + if (netif_subqueue_stopped(netcp->ndev, skb) && + netif_running(netcp->ndev) && + (knav_pool_count(netcp->tx_pool) > + netcp->tx_resume_threshold)) { + u16 subqueue = skb_get_queue_mapping(skb); + + netif_wake_subqueue(netcp->ndev, subqueue); + } + + netcp->ndev->stats.tx_packets++; + netcp->ndev->stats.tx_bytes += skb->len; + dev_kfree_skb(skb); + pkts++; + } + return pkts; +} + +static int netcp_tx_poll(struct napi_struct *napi, int budget) +{ + int packets; + struct netcp_intf *netcp = container_of(napi, struct netcp_intf, + tx_napi); + + packets = netcp_process_tx_compl_packets(netcp, budget); + if (packets < budget) { + napi_complete(&netcp->tx_napi); + knav_queue_enable_notify(netcp->tx_compl_q); + } + + return packets; +} + +static void netcp_tx_notify(void *arg) +{ + struct netcp_intf *netcp = arg; + + knav_queue_disable_notify(netcp->tx_compl_q); + napi_schedule(&netcp->tx_napi); +} + +static struct knav_dma_desc* +netcp_tx_map_skb(struct sk_buff *skb, struct netcp_intf *netcp) +{ + struct knav_dma_desc *desc, *ndesc, *pdesc; + unsigned int pkt_len = skb_headlen(skb); + struct device *dev = netcp->dev; + dma_addr_t dma_addr; + unsigned int dma_sz; + int i; + + /* Map the linear buffer */ + dma_addr = dma_map_single(dev, skb->data, pkt_len, DMA_TO_DEVICE); + if (unlikely(!dma_addr)) { + dev_err(netcp->ndev_dev, "Failed to map skb buffer\n"); + return NULL; + } + + desc = knav_pool_desc_get(netcp->tx_pool); + if (unlikely(IS_ERR_OR_NULL(desc))) { + dev_err(netcp->ndev_dev, "out of TX desc\n"); + dma_unmap_single(dev, dma_addr, pkt_len, DMA_TO_DEVICE); + return NULL; + } + + set_pkt_info(dma_addr, pkt_len, 0, desc); + if (skb_is_nonlinear(skb)) { + prefetchw(skb_shinfo(skb)); + } else { + desc->next_desc = 0; + goto upd_pkt_len; + } + + pdesc = desc; + + /* Handle the case where skb is fragmented in pages */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + struct page *page = skb_frag_page(frag); + u32 page_offset = frag->page_offset; + u32 buf_len = skb_frag_size(frag); + dma_addr_t desc_dma; + u32 pkt_info; + + dma_addr = dma_map_page(dev, page, page_offset, buf_len, + DMA_TO_DEVICE); + if (unlikely(!dma_addr)) { + dev_err(netcp->ndev_dev, "Failed to map skb page\n"); + goto free_descs; + } + + ndesc = knav_pool_desc_get(netcp->tx_pool); + if (unlikely(IS_ERR_OR_NULL(ndesc))) { + dev_err(netcp->ndev_dev, "out of TX desc for frags\n"); + dma_unmap_page(dev, dma_addr, buf_len, DMA_TO_DEVICE); + goto free_descs; + } + + desc_dma = knav_pool_desc_virt_to_dma(netcp->tx_pool, + (void *)ndesc); + pkt_info = + (netcp->tx_compl_qid & KNAV_DMA_DESC_RETQ_MASK) << + KNAV_DMA_DESC_RETQ_SHIFT; + set_pkt_info(dma_addr, buf_len, 0, ndesc); + set_words(&desc_dma, 1, &pdesc->next_desc); + pkt_len += buf_len; + if (pdesc != desc) + knav_pool_desc_map(netcp->tx_pool, pdesc, + sizeof(*pdesc), &desc_dma, &dma_sz); + pdesc = ndesc; + } + if (pdesc != desc) + knav_pool_desc_map(netcp->tx_pool, pdesc, sizeof(*pdesc), + &dma_addr, &dma_sz); + + /* frag list based linkage is not supported for now. */ + if (skb_shinfo(skb)->frag_list) { + dev_err_ratelimited(netcp->ndev_dev, "NETIF_F_FRAGLIST not supported\n"); + goto free_descs; + } + +upd_pkt_len: + WARN_ON(pkt_len != skb->len); + + pkt_len &= KNAV_DMA_DESC_PKT_LEN_MASK; + set_words(&pkt_len, 1, &desc->desc_info); + return desc; + +free_descs: + netcp_free_tx_desc_chain(netcp, desc, sizeof(*desc)); + return NULL; +} + +static int netcp_tx_submit_skb(struct netcp_intf *netcp, + struct sk_buff *skb, + struct knav_dma_desc *desc) +{ + struct netcp_tx_pipe *tx_pipe = NULL; + struct netcp_hook_list *tx_hook; + struct netcp_packet p_info; + u32 packet_info = 0; + unsigned int dma_sz; + dma_addr_t dma; + int ret = 0; + + p_info.netcp = netcp; + p_info.skb = skb; + p_info.tx_pipe = NULL; + p_info.psdata_len = 0; + p_info.ts_context = NULL; + p_info.txtstamp_complete = NULL; + p_info.epib = desc->epib; + p_info.psdata = desc->psdata; + memset(p_info.epib, 0, KNAV_DMA_NUM_EPIB_WORDS * sizeof(u32)); + + /* Find out where to inject the packet for transmission */ + list_for_each_entry(tx_hook, &netcp->txhook_list_head, list) { + ret = tx_hook->hook_rtn(tx_hook->order, tx_hook->hook_data, + &p_info); + if (unlikely(ret != 0)) { + dev_err(netcp->ndev_dev, "TX hook %d rejected the packet with reason(%d)\n", + tx_hook->order, ret); + ret = (ret < 0) ? ret : NETDEV_TX_OK; + goto out; + } + } + + /* Make sure some TX hook claimed the packet */ + tx_pipe = p_info.tx_pipe; + if (!tx_pipe) { + dev_err(netcp->ndev_dev, "No TX hook claimed the packet!\n"); + ret = -ENXIO; + goto out; + } + + /* update descriptor */ + if (p_info.psdata_len) { + u32 *psdata = p_info.psdata; + + memmove(p_info.psdata, p_info.psdata + p_info.psdata_len, + p_info.psdata_len); + set_words(psdata, p_info.psdata_len, psdata); + packet_info |= + (p_info.psdata_len & KNAV_DMA_DESC_PSLEN_MASK) << + KNAV_DMA_DESC_PSLEN_SHIFT; + } + + packet_info |= KNAV_DMA_DESC_HAS_EPIB | + ((netcp->tx_compl_qid & KNAV_DMA_DESC_RETQ_MASK) << + KNAV_DMA_DESC_RETQ_SHIFT) | + ((tx_pipe->dma_psflags & KNAV_DMA_DESC_PSFLAG_MASK) << + KNAV_DMA_DESC_PSFLAG_SHIFT); + + set_words(&packet_info, 1, &desc->packet_info); + set_words((u32 *)&skb, 1, &desc->pad[0]); + + /* submit packet descriptor */ + ret = knav_pool_desc_map(netcp->tx_pool, desc, sizeof(*desc), &dma, + &dma_sz); + if (unlikely(ret)) { + dev_err(netcp->ndev_dev, "%s() failed to map desc\n", __func__); + ret = -ENOMEM; + goto out; + } + skb_tx_timestamp(skb); + knav_queue_push(tx_pipe->dma_queue, dma, dma_sz, 0); + +out: + return ret; +} + +/* Submit the packet */ +static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + int subqueue = skb_get_queue_mapping(skb); + struct knav_dma_desc *desc; + int desc_count, ret = 0; + + if (unlikely(skb->len <= 0)) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + if (unlikely(skb->len < NETCP_MIN_PACKET_SIZE)) { + ret = skb_padto(skb, NETCP_MIN_PACKET_SIZE); + if (ret < 0) { + /* If we get here, the skb has already been dropped */ + dev_warn(netcp->ndev_dev, "padding failed (%d), packet dropped\n", + ret); + ndev->stats.tx_dropped++; + return ret; + } + skb->len = NETCP_MIN_PACKET_SIZE; + } + + desc = netcp_tx_map_skb(skb, netcp); + if (unlikely(!desc)) { + netif_stop_subqueue(ndev, subqueue); + ret = -ENOBUFS; + goto drop; + } + + ret = netcp_tx_submit_skb(netcp, skb, desc); + if (ret) + goto drop; + + ndev->trans_start = jiffies; + + /* Check Tx pool count & stop subqueue if needed */ + desc_count = knav_pool_count(netcp->tx_pool); + if (desc_count < netcp->tx_pause_threshold) { + dev_dbg(netcp->ndev_dev, "pausing tx, count(%d)\n", desc_count); + netif_stop_subqueue(ndev, subqueue); + } + return NETDEV_TX_OK; + +drop: + ndev->stats.tx_dropped++; + if (desc) + netcp_free_tx_desc_chain(netcp, desc, sizeof(*desc)); + dev_kfree_skb(skb); + return ret; +} + +int netcp_txpipe_close(struct netcp_tx_pipe *tx_pipe) +{ + if (tx_pipe->dma_channel) { + knav_dma_close_channel(tx_pipe->dma_channel); + tx_pipe->dma_channel = NULL; + } + return 0; +} +EXPORT_SYMBOL_GPL(netcp_txpipe_close); + +int netcp_txpipe_open(struct netcp_tx_pipe *tx_pipe) +{ + struct device *dev = tx_pipe->netcp_device->device; + struct knav_dma_cfg config; + int ret = 0; + u8 name[16]; + + memset(&config, 0, sizeof(config)); + config.direction = DMA_MEM_TO_DEV; + config.u.tx.filt_einfo = false; + config.u.tx.filt_pswords = false; + config.u.tx.priority = DMA_PRIO_MED_L; + + tx_pipe->dma_channel = knav_dma_open_channel(dev, + tx_pipe->dma_chan_name, &config); + if (IS_ERR_OR_NULL(tx_pipe->dma_channel)) { + dev_err(dev, "failed opening tx chan(%s)\n", + tx_pipe->dma_chan_name); + goto err; + } + + snprintf(name, sizeof(name), "tx-pipe-%s", dev_name(dev)); + tx_pipe->dma_queue = knav_queue_open(name, tx_pipe->dma_queue_id, + KNAV_QUEUE_SHARED); + if (IS_ERR(tx_pipe->dma_queue)) { + dev_err(dev, "Could not open DMA queue for channel \"%s\": %d\n", + name, ret); + ret = PTR_ERR(tx_pipe->dma_queue); + goto err; + } + + dev_dbg(dev, "opened tx pipe %s\n", name); + return 0; + +err: + if (!IS_ERR_OR_NULL(tx_pipe->dma_channel)) + knav_dma_close_channel(tx_pipe->dma_channel); + tx_pipe->dma_channel = NULL; + return ret; +} +EXPORT_SYMBOL_GPL(netcp_txpipe_open); + +int netcp_txpipe_init(struct netcp_tx_pipe *tx_pipe, + struct netcp_device *netcp_device, + const char *dma_chan_name, unsigned int dma_queue_id) +{ + memset(tx_pipe, 0, sizeof(*tx_pipe)); + tx_pipe->netcp_device = netcp_device; + tx_pipe->dma_chan_name = dma_chan_name; + tx_pipe->dma_queue_id = dma_queue_id; + return 0; +} +EXPORT_SYMBOL_GPL(netcp_txpipe_init); + +static struct netcp_addr *netcp_addr_find(struct netcp_intf *netcp, + const u8 *addr, + enum netcp_addr_type type) +{ + struct netcp_addr *naddr; + + list_for_each_entry(naddr, &netcp->addr_list, node) { + if (naddr->type != type) + continue; + if (addr && memcmp(addr, naddr->addr, ETH_ALEN)) + continue; + return naddr; + } + + return NULL; +} + +static struct netcp_addr *netcp_addr_add(struct netcp_intf *netcp, + const u8 *addr, + enum netcp_addr_type type) +{ + struct netcp_addr *naddr; + + naddr = devm_kmalloc(netcp->dev, sizeof(*naddr), GFP_ATOMIC); + if (!naddr) + return NULL; + + naddr->type = type; + naddr->flags = 0; + naddr->netcp = netcp; + if (addr) + ether_addr_copy(naddr->addr, addr); + else + memset(naddr->addr, 0, ETH_ALEN); + list_add_tail(&naddr->node, &netcp->addr_list); + + return naddr; +} + +static void netcp_addr_del(struct netcp_intf *netcp, struct netcp_addr *naddr) +{ + list_del(&naddr->node); + devm_kfree(netcp->dev, naddr); +} + +static void netcp_addr_clear_mark(struct netcp_intf *netcp) +{ + struct netcp_addr *naddr; + + list_for_each_entry(naddr, &netcp->addr_list, node) + naddr->flags = 0; +} + +static void netcp_addr_add_mark(struct netcp_intf *netcp, const u8 *addr, + enum netcp_addr_type type) +{ + struct netcp_addr *naddr; + + naddr = netcp_addr_find(netcp, addr, type); + if (naddr) { + naddr->flags |= ADDR_VALID; + return; + } + + naddr = netcp_addr_add(netcp, addr, type); + if (!WARN_ON(!naddr)) + naddr->flags |= ADDR_NEW; +} + +static void netcp_addr_sweep_del(struct netcp_intf *netcp) +{ + struct netcp_addr *naddr, *tmp; + struct netcp_intf_modpriv *priv; + struct netcp_module *module; + int error; + + list_for_each_entry_safe(naddr, tmp, &netcp->addr_list, node) { + if (naddr->flags & (ADDR_VALID | ADDR_NEW)) + continue; + dev_dbg(netcp->ndev_dev, "deleting address %pM, type %x\n", + naddr->addr, naddr->type); + mutex_lock(&netcp_modules_lock); + for_each_module(netcp, priv) { + module = priv->netcp_module; + if (!module->del_addr) + continue; + error = module->del_addr(priv->module_priv, + naddr); + WARN_ON(error); + } + mutex_unlock(&netcp_modules_lock); + netcp_addr_del(netcp, naddr); + } +} + +static void netcp_addr_sweep_add(struct netcp_intf *netcp) +{ + struct netcp_addr *naddr, *tmp; + struct netcp_intf_modpriv *priv; + struct netcp_module *module; + int error; + + list_for_each_entry_safe(naddr, tmp, &netcp->addr_list, node) { + if (!(naddr->flags & ADDR_NEW)) + continue; + dev_dbg(netcp->ndev_dev, "adding address %pM, type %x\n", + naddr->addr, naddr->type); + mutex_lock(&netcp_modules_lock); + for_each_module(netcp, priv) { + module = priv->netcp_module; + if (!module->add_addr) + continue; + error = module->add_addr(priv->module_priv, naddr); + WARN_ON(error); + } + mutex_unlock(&netcp_modules_lock); + } +} + +static void netcp_set_rx_mode(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct netdev_hw_addr *ndev_addr; + bool promisc; + + promisc = (ndev->flags & IFF_PROMISC || + ndev->flags & IFF_ALLMULTI || + netdev_mc_count(ndev) > NETCP_MAX_MCAST_ADDR); + + /* first clear all marks */ + netcp_addr_clear_mark(netcp); + + /* next add new entries, mark existing ones */ + netcp_addr_add_mark(netcp, ndev->broadcast, ADDR_BCAST); + for_each_dev_addr(ndev, ndev_addr) + netcp_addr_add_mark(netcp, ndev_addr->addr, ADDR_DEV); + netdev_for_each_uc_addr(ndev_addr, ndev) + netcp_addr_add_mark(netcp, ndev_addr->addr, ADDR_UCAST); + netdev_for_each_mc_addr(ndev_addr, ndev) + netcp_addr_add_mark(netcp, ndev_addr->addr, ADDR_MCAST); + + if (promisc) + netcp_addr_add_mark(netcp, NULL, ADDR_ANY); + + /* finally sweep and callout into modules */ + netcp_addr_sweep_del(netcp); + netcp_addr_sweep_add(netcp); +} + +static void netcp_free_navigator_resources(struct netcp_intf *netcp) +{ + int i; + + if (netcp->rx_channel) { + knav_dma_close_channel(netcp->rx_channel); + netcp->rx_channel = NULL; + } + + if (!IS_ERR_OR_NULL(netcp->rx_pool)) + netcp_rxpool_free(netcp); + + if (!IS_ERR_OR_NULL(netcp->rx_queue)) { + knav_queue_close(netcp->rx_queue); + netcp->rx_queue = NULL; + } + + for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && + !IS_ERR_OR_NULL(netcp->rx_fdq[i]) ; ++i) { + knav_queue_close(netcp->rx_fdq[i]); + netcp->rx_fdq[i] = NULL; + } + + if (!IS_ERR_OR_NULL(netcp->tx_compl_q)) { + knav_queue_close(netcp->tx_compl_q); + netcp->tx_compl_q = NULL; + } + + if (!IS_ERR_OR_NULL(netcp->tx_pool)) { + knav_pool_destroy(netcp->tx_pool); + netcp->tx_pool = NULL; + } +} + +static int netcp_setup_navigator_resources(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct knav_queue_notify_config notify_cfg; + struct knav_dma_cfg config; + u32 last_fdq = 0; + u8 name[16]; + int ret; + int i; + + /* Create Rx/Tx descriptor pools */ + snprintf(name, sizeof(name), "rx-pool-%s", ndev->name); + netcp->rx_pool = knav_pool_create(name, netcp->rx_pool_size, + netcp->rx_pool_region_id); + if (IS_ERR_OR_NULL(netcp->rx_pool)) { + dev_err(netcp->ndev_dev, "Couldn't create rx pool\n"); + ret = PTR_ERR(netcp->rx_pool); + goto fail; + } + + snprintf(name, sizeof(name), "tx-pool-%s", ndev->name); + netcp->tx_pool = knav_pool_create(name, netcp->tx_pool_size, + netcp->tx_pool_region_id); + if (IS_ERR_OR_NULL(netcp->tx_pool)) { + dev_err(netcp->ndev_dev, "Couldn't create tx pool\n"); + ret = PTR_ERR(netcp->tx_pool); + goto fail; + } + + /* open Tx completion queue */ + snprintf(name, sizeof(name), "tx-compl-%s", ndev->name); + netcp->tx_compl_q = knav_queue_open(name, netcp->tx_compl_qid, 0); + if (IS_ERR_OR_NULL(netcp->tx_compl_q)) { + ret = PTR_ERR(netcp->tx_compl_q); + goto fail; + } + netcp->tx_compl_qid = knav_queue_get_id(netcp->tx_compl_q); + + /* Set notification for Tx completion */ + notify_cfg.fn = netcp_tx_notify; + notify_cfg.fn_arg = netcp; + ret = knav_queue_device_control(netcp->tx_compl_q, + KNAV_QUEUE_SET_NOTIFIER, + (unsigned long)¬ify_cfg); + if (ret) + goto fail; + + knav_queue_disable_notify(netcp->tx_compl_q); + + /* open Rx completion queue */ + snprintf(name, sizeof(name), "rx-compl-%s", ndev->name); + netcp->rx_queue = knav_queue_open(name, netcp->rx_queue_id, 0); + if (IS_ERR_OR_NULL(netcp->rx_queue)) { + ret = PTR_ERR(netcp->rx_queue); + goto fail; + } + netcp->rx_queue_id = knav_queue_get_id(netcp->rx_queue); + + /* Set notification for Rx completion */ + notify_cfg.fn = netcp_rx_notify; + notify_cfg.fn_arg = netcp; + ret = knav_queue_device_control(netcp->rx_queue, + KNAV_QUEUE_SET_NOTIFIER, + (unsigned long)¬ify_cfg); + if (ret) + goto fail; + + knav_queue_disable_notify(netcp->rx_queue); + + /* open Rx FDQs */ + for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && + netcp->rx_queue_depths[i] && netcp->rx_buffer_sizes[i]; ++i) { + snprintf(name, sizeof(name), "rx-fdq-%s-%d", ndev->name, i); + netcp->rx_fdq[i] = knav_queue_open(name, KNAV_QUEUE_GP, 0); + if (IS_ERR_OR_NULL(netcp->rx_fdq[i])) { + ret = PTR_ERR(netcp->rx_fdq[i]); + goto fail; + } + } + + memset(&config, 0, sizeof(config)); + config.direction = DMA_DEV_TO_MEM; + config.u.rx.einfo_present = true; + config.u.rx.psinfo_present = true; + config.u.rx.err_mode = DMA_DROP; + config.u.rx.desc_type = DMA_DESC_HOST; + config.u.rx.psinfo_at_sop = false; + config.u.rx.sop_offset = NETCP_SOP_OFFSET; + config.u.rx.dst_q = netcp->rx_queue_id; + config.u.rx.thresh = DMA_THRESH_NONE; + + for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN; ++i) { + if (netcp->rx_fdq[i]) + last_fdq = knav_queue_get_id(netcp->rx_fdq[i]); + config.u.rx.fdq[i] = last_fdq; + } + + netcp->rx_channel = knav_dma_open_channel(netcp->netcp_device->device, + netcp->dma_chan_name, &config); + if (IS_ERR_OR_NULL(netcp->rx_channel)) { + dev_err(netcp->ndev_dev, "failed opening rx chan(%s\n", + netcp->dma_chan_name); + goto fail; + } + + dev_dbg(netcp->ndev_dev, "opened RX channel: %p\n", netcp->rx_channel); + return 0; + +fail: + netcp_free_navigator_resources(netcp); + return ret; +} + +/* Open the device */ +static int netcp_ndo_open(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct netcp_intf_modpriv *intf_modpriv; + struct netcp_module *module; + int ret; + + netif_carrier_off(ndev); + ret = netcp_setup_navigator_resources(ndev); + if (ret) { + dev_err(netcp->ndev_dev, "Failed to setup navigator resources\n"); + goto fail; + } + + mutex_lock(&netcp_modules_lock); + for_each_module(netcp, intf_modpriv) { + module = intf_modpriv->netcp_module; + if (module->open) { + ret = module->open(intf_modpriv->module_priv, ndev); + if (ret != 0) { + dev_err(netcp->ndev_dev, "module open failed\n"); + goto fail_open; + } + } + } + mutex_unlock(&netcp_modules_lock); + + netcp_rxpool_refill(netcp); + napi_enable(&netcp->rx_napi); + napi_enable(&netcp->tx_napi); + knav_queue_enable_notify(netcp->tx_compl_q); + knav_queue_enable_notify(netcp->rx_queue); + netif_tx_wake_all_queues(ndev); + dev_dbg(netcp->ndev_dev, "netcp device %s opened\n", ndev->name); + return 0; + +fail_open: + for_each_module(netcp, intf_modpriv) { + module = intf_modpriv->netcp_module; + if (module->close) + module->close(intf_modpriv->module_priv, ndev); + } + mutex_unlock(&netcp_modules_lock); + +fail: + netcp_free_navigator_resources(netcp); + return ret; +} + +/* Close the device */ +static int netcp_ndo_stop(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct netcp_intf_modpriv *intf_modpriv; + struct netcp_module *module; + int err = 0; + + netif_tx_stop_all_queues(ndev); + netif_carrier_off(ndev); + netcp_addr_clear_mark(netcp); + netcp_addr_sweep_del(netcp); + knav_queue_disable_notify(netcp->rx_queue); + knav_queue_disable_notify(netcp->tx_compl_q); + napi_disable(&netcp->rx_napi); + napi_disable(&netcp->tx_napi); + + mutex_lock(&netcp_modules_lock); + for_each_module(netcp, intf_modpriv) { + module = intf_modpriv->netcp_module; + if (module->close) { + err = module->close(intf_modpriv->module_priv, ndev); + if (err != 0) + dev_err(netcp->ndev_dev, "Close failed\n"); + } + } + mutex_unlock(&netcp_modules_lock); + + /* Recycle Rx descriptors from completion queue */ + netcp_empty_rx_queue(netcp); + + /* Recycle Tx descriptors from completion queue */ + netcp_process_tx_compl_packets(netcp, netcp->tx_pool_size); + + if (knav_pool_count(netcp->tx_pool) != netcp->tx_pool_size) + dev_err(netcp->ndev_dev, "Lost (%d) Tx descs\n", + netcp->tx_pool_size - knav_pool_count(netcp->tx_pool)); + + netcp_free_navigator_resources(netcp); + dev_dbg(netcp->ndev_dev, "netcp device %s stopped\n", ndev->name); + return 0; +} + +static int netcp_ndo_ioctl(struct net_device *ndev, + struct ifreq *req, int cmd) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct netcp_intf_modpriv *intf_modpriv; + struct netcp_module *module; + int ret = -1, err = -EOPNOTSUPP; + + if (!netif_running(ndev)) + return -EINVAL; + + mutex_lock(&netcp_modules_lock); + for_each_module(netcp, intf_modpriv) { + module = intf_modpriv->netcp_module; + if (!module->ioctl) + continue; + + err = module->ioctl(intf_modpriv->module_priv, req, cmd); + if ((err < 0) && (err != -EOPNOTSUPP)) { + ret = err; + goto out; + } + if (err == 0) + ret = err; + } + +out: + mutex_unlock(&netcp_modules_lock); + return (ret == 0) ? 0 : err; +} + +static int netcp_ndo_change_mtu(struct net_device *ndev, int new_mtu) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + + /* MTU < 68 is an error for IPv4 traffic */ + if ((new_mtu < 68) || + (new_mtu > (NETCP_MAX_FRAME_SIZE - ETH_HLEN - ETH_FCS_LEN))) { + dev_err(netcp->ndev_dev, "Invalid mtu size = %d\n", new_mtu); + return -EINVAL; + } + + ndev->mtu = new_mtu; + return 0; +} + +static void netcp_ndo_tx_timeout(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + unsigned int descs = knav_pool_count(netcp->tx_pool); + + dev_err(netcp->ndev_dev, "transmit timed out tx descs(%d)\n", descs); + netcp_process_tx_compl_packets(netcp, netcp->tx_pool_size); + ndev->trans_start = jiffies; + netif_tx_wake_all_queues(ndev); +} + +static int netcp_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct netcp_intf_modpriv *intf_modpriv; + struct netcp_module *module; + int err = 0; + + dev_dbg(netcp->ndev_dev, "adding rx vlan id: %d\n", vid); + + mutex_lock(&netcp_modules_lock); + for_each_module(netcp, intf_modpriv) { + module = intf_modpriv->netcp_module; + if ((module->add_vid) && (vid != 0)) { + err = module->add_vid(intf_modpriv->module_priv, vid); + if (err != 0) { + dev_err(netcp->ndev_dev, "Could not add vlan id = %d\n", + vid); + break; + } + } + } + mutex_unlock(&netcp_modules_lock); + return err; +} + +static int netcp_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct netcp_intf_modpriv *intf_modpriv; + struct netcp_module *module; + int err = 0; + + dev_dbg(netcp->ndev_dev, "removing rx vlan id: %d\n", vid); + + mutex_lock(&netcp_modules_lock); + for_each_module(netcp, intf_modpriv) { + module = intf_modpriv->netcp_module; + if (module->del_vid) { + err = module->del_vid(intf_modpriv->module_priv, vid); + if (err != 0) { + dev_err(netcp->ndev_dev, "Could not delete vlan id = %d\n", + vid); + break; + } + } + } + mutex_unlock(&netcp_modules_lock); + return err; +} + +static u16 netcp_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv, + select_queue_fallback_t fallback) +{ + return 0; +} + +static int netcp_setup_tc(struct net_device *dev, u8 num_tc) +{ + int i; + + /* setup tc must be called under rtnl lock */ + ASSERT_RTNL(); + + /* Sanity-check the number of traffic classes requested */ + if ((dev->real_num_tx_queues <= 1) || + (dev->real_num_tx_queues < num_tc)) + return -EINVAL; + + /* Configure traffic class to queue mappings */ + if (num_tc) { + netdev_set_num_tc(dev, num_tc); + for (i = 0; i < num_tc; i++) + netdev_set_tc_queue(dev, i, 1, i); + } else { + netdev_reset_tc(dev); + } + + return 0; +} + +static const struct net_device_ops netcp_netdev_ops = { + .ndo_open = netcp_ndo_open, + .ndo_stop = netcp_ndo_stop, + .ndo_start_xmit = netcp_ndo_start_xmit, + .ndo_set_rx_mode = netcp_set_rx_mode, + .ndo_do_ioctl = netcp_ndo_ioctl, + .ndo_change_mtu = netcp_ndo_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_vlan_rx_add_vid = netcp_rx_add_vid, + .ndo_vlan_rx_kill_vid = netcp_rx_kill_vid, + .ndo_tx_timeout = netcp_ndo_tx_timeout, + .ndo_select_queue = netcp_select_queue, + .ndo_setup_tc = netcp_setup_tc, +}; + +static int netcp_create_interface(struct netcp_device *netcp_device, + struct device_node *node_interface) +{ + struct device *dev = netcp_device->device; + struct device_node *node = dev->of_node; + struct netcp_intf *netcp; + struct net_device *ndev; + resource_size_t size; + struct resource res; + void __iomem *efuse = NULL; + u32 efuse_mac = 0; + const void *mac_addr; + u8 efuse_mac_addr[6]; + u32 temp[2]; + int ret = 0; + + ndev = alloc_etherdev_mqs(sizeof(*netcp), 1, 1); + if (!ndev) { + dev_err(dev, "Error allocating netdev\n"); + return -ENOMEM; + } + + ndev->features |= NETIF_F_SG; + ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; + ndev->hw_features = ndev->features; + ndev->vlan_features |= NETIF_F_SG; + + netcp = netdev_priv(ndev); + spin_lock_init(&netcp->lock); + INIT_LIST_HEAD(&netcp->module_head); + INIT_LIST_HEAD(&netcp->txhook_list_head); + INIT_LIST_HEAD(&netcp->rxhook_list_head); + INIT_LIST_HEAD(&netcp->addr_list); + netcp->netcp_device = netcp_device; + netcp->dev = netcp_device->device; + netcp->ndev = ndev; + netcp->ndev_dev = &ndev->dev; + netcp->msg_enable = netif_msg_init(netcp_debug_level, NETCP_DEBUG); + netcp->tx_pause_threshold = MAX_SKB_FRAGS; + netcp->tx_resume_threshold = netcp->tx_pause_threshold; + netcp->node_interface = node_interface; + + ret = of_property_read_u32(node_interface, "efuse-mac", &efuse_mac); + if (efuse_mac) { + if (of_address_to_resource(node, NETCP_EFUSE_REG_INDEX, &res)) { + dev_err(dev, "could not find efuse-mac reg resource\n"); + ret = -ENODEV; + goto quit; + } + size = resource_size(&res); + + if (!devm_request_mem_region(dev, res.start, size, + dev_name(dev))) { + dev_err(dev, "could not reserve resource\n"); + ret = -ENOMEM; + goto quit; + } + + efuse = devm_ioremap_nocache(dev, res.start, size); + if (!efuse) { + dev_err(dev, "could not map resource\n"); + devm_release_mem_region(dev, res.start, size); + ret = -ENOMEM; + goto quit; + } + + emac_arch_get_mac_addr(efuse_mac_addr, efuse); + if (is_valid_ether_addr(efuse_mac_addr)) + ether_addr_copy(ndev->dev_addr, efuse_mac_addr); + else + random_ether_addr(ndev->dev_addr); + + devm_iounmap(dev, efuse); + devm_release_mem_region(dev, res.start, size); + } else { + mac_addr = of_get_mac_address(node_interface); + if (mac_addr) + ether_addr_copy(ndev->dev_addr, mac_addr); + else + random_ether_addr(ndev->dev_addr); + } + + ret = of_property_read_string(node_interface, "rx-channel", + &netcp->dma_chan_name); + if (ret < 0) { + dev_err(dev, "missing \"rx-channel\" parameter\n"); + ret = -ENODEV; + goto quit; + } + + ret = of_property_read_u32(node_interface, "rx-queue", + &netcp->rx_queue_id); + if (ret < 0) { + dev_warn(dev, "missing \"rx-queue\" parameter\n"); + netcp->rx_queue_id = KNAV_QUEUE_QPEND; + } + + ret = of_property_read_u32_array(node_interface, "rx-queue-depth", + netcp->rx_queue_depths, + KNAV_DMA_FDQ_PER_CHAN); + if (ret < 0) { + dev_err(dev, "missing \"rx-queue-depth\" parameter\n"); + netcp->rx_queue_depths[0] = 128; + } + + ret = of_property_read_u32_array(node_interface, "rx-buffer-size", + netcp->rx_buffer_sizes, + KNAV_DMA_FDQ_PER_CHAN); + if (ret) { + dev_err(dev, "missing \"rx-buffer-size\" parameter\n"); + netcp->rx_buffer_sizes[0] = 1536; + } + + ret = of_property_read_u32_array(node_interface, "rx-pool", temp, 2); + if (ret < 0) { + dev_err(dev, "missing \"rx-pool\" parameter\n"); + ret = -ENODEV; + goto quit; + } + netcp->rx_pool_size = temp[0]; + netcp->rx_pool_region_id = temp[1]; + + ret = of_property_read_u32_array(node_interface, "tx-pool", temp, 2); + if (ret < 0) { + dev_err(dev, "missing \"tx-pool\" parameter\n"); + ret = -ENODEV; + goto quit; + } + netcp->tx_pool_size = temp[0]; + netcp->tx_pool_region_id = temp[1]; + + if (netcp->tx_pool_size < MAX_SKB_FRAGS) { + dev_err(dev, "tx-pool size too small, must be atleast(%ld)\n", + MAX_SKB_FRAGS); + ret = -ENODEV; + goto quit; + } + + ret = of_property_read_u32(node_interface, "tx-completion-queue", + &netcp->tx_compl_qid); + if (ret < 0) { + dev_warn(dev, "missing \"tx-completion-queue\" parameter\n"); + netcp->tx_compl_qid = KNAV_QUEUE_QPEND; + } + + /* NAPI register */ + netif_napi_add(ndev, &netcp->rx_napi, netcp_rx_poll, NETCP_NAPI_WEIGHT); + netif_napi_add(ndev, &netcp->tx_napi, netcp_tx_poll, NETCP_NAPI_WEIGHT); + + /* Register the network device */ + ndev->dev_id = 0; + ndev->watchdog_timeo = NETCP_TX_TIMEOUT; + ndev->netdev_ops = &netcp_netdev_ops; + SET_NETDEV_DEV(ndev, dev); + + list_add_tail(&netcp->interface_list, &netcp_device->interface_head); + return 0; + +quit: + free_netdev(ndev); + return ret; +} + +static void netcp_delete_interface(struct netcp_device *netcp_device, + struct net_device *ndev) +{ + struct netcp_intf_modpriv *intf_modpriv, *tmp; + struct netcp_intf *netcp = netdev_priv(ndev); + struct netcp_module *module; + + dev_dbg(netcp_device->device, "Removing interface \"%s\"\n", + ndev->name); + + /* Notify each of the modules that the interface is going away */ + list_for_each_entry_safe(intf_modpriv, tmp, &netcp->module_head, + intf_list) { + module = intf_modpriv->netcp_module; + dev_dbg(netcp_device->device, "Releasing module \"%s\"\n", + module->name); + if (module->release) + module->release(intf_modpriv->module_priv); + list_del(&intf_modpriv->intf_list); + kfree(intf_modpriv); + } + WARN(!list_empty(&netcp->module_head), "%s interface module list is not empty!\n", + ndev->name); + + list_del(&netcp->interface_list); + + of_node_put(netcp->node_interface); + unregister_netdev(ndev); + netif_napi_del(&netcp->rx_napi); + free_netdev(ndev); +} + +static int netcp_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct netcp_intf *netcp_intf, *netcp_tmp; + struct device_node *child, *interfaces; + struct netcp_device *netcp_device; + struct device *dev = &pdev->dev; + struct netcp_module *module; + int ret; + + if (!node) { + dev_err(dev, "could not find device info\n"); + return -ENODEV; + } + + /* Allocate a new NETCP device instance */ + netcp_device = devm_kzalloc(dev, sizeof(*netcp_device), GFP_KERNEL); + if (!netcp_device) + return -ENOMEM; + + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + dev_err(dev, "Failed to enable NETCP power-domain\n"); + pm_runtime_disable(&pdev->dev); + return ret; + } + + /* Initialize the NETCP device instance */ + INIT_LIST_HEAD(&netcp_device->interface_head); + INIT_LIST_HEAD(&netcp_device->modpriv_head); + netcp_device->device = dev; + platform_set_drvdata(pdev, netcp_device); + + /* create interfaces */ + interfaces = of_get_child_by_name(node, "netcp-interfaces"); + if (!interfaces) { + dev_err(dev, "could not find netcp-interfaces node\n"); + ret = -ENODEV; + goto probe_quit; + } + + for_each_available_child_of_node(interfaces, child) { + ret = netcp_create_interface(netcp_device, child); + if (ret) { + dev_err(dev, "could not create interface(%s)\n", + child->name); + goto probe_quit_interface; + } + } + + /* Add the device instance to the list */ + list_add_tail(&netcp_device->device_list, &netcp_devices); + + /* Probe & attach any modules already registered */ + mutex_lock(&netcp_modules_lock); + for_each_netcp_module(module) { + ret = netcp_module_probe(netcp_device, module); + if (ret < 0) + dev_err(dev, "module(%s) probe failed\n", module->name); + } + mutex_unlock(&netcp_modules_lock); + return 0; + +probe_quit_interface: + list_for_each_entry_safe(netcp_intf, netcp_tmp, + &netcp_device->interface_head, + interface_list) { + netcp_delete_interface(netcp_device, netcp_intf->ndev); + } + +probe_quit: + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + platform_set_drvdata(pdev, NULL); + return ret; +} + +static int netcp_remove(struct platform_device *pdev) +{ + struct netcp_device *netcp_device = platform_get_drvdata(pdev); + struct netcp_inst_modpriv *inst_modpriv, *tmp; + struct netcp_module *module; + + list_for_each_entry_safe(inst_modpriv, tmp, &netcp_device->modpriv_head, + inst_list) { + module = inst_modpriv->netcp_module; + dev_dbg(&pdev->dev, "Removing module \"%s\"\n", module->name); + module->remove(netcp_device, inst_modpriv->module_priv); + list_del(&inst_modpriv->inst_list); + kfree(inst_modpriv); + } + WARN(!list_empty(&netcp_device->interface_head), "%s interface list not empty!\n", + pdev->name); + + devm_kfree(&pdev->dev, netcp_device); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct of_device_id of_match[] = { + { .compatible = "ti,netcp-1.0", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_match); + +static struct platform_driver netcp_driver = { + .driver = { + .name = "netcp-1.0", + .owner = THIS_MODULE, + .of_match_table = of_match, + }, + .probe = netcp_probe, + .remove = netcp_remove, +}; +module_platform_driver(netcp_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TI NETCP driver for Keystone SOCs"); +MODULE_AUTHOR("Sandeep Nair + * Sandeep Paulraj + * Cyril Chemparathy + * Santosh Shilimkar + * Wingman Kwok + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include "cpsw_ale.h" +#include "netcp.h" + +#define NETCP_DRIVER_NAME "TI KeyStone Ethernet Driver" +#define NETCP_DRIVER_VERSION "v1.0" + +#define GBE_IDENT(reg) ((reg >> 16) & 0xffff) +#define GBE_MAJOR_VERSION(reg) (reg >> 8 & 0x7) +#define GBE_MINOR_VERSION(reg) (reg & 0xff) +#define GBE_RTL_VERSION(reg) ((reg >> 11) & 0x1f) + +/* 1G Ethernet SS defines */ +#define GBE_MODULE_NAME "netcp-gbe" +#define GBE_SS_VERSION_14 0x4ed21104 + +#define GBE13_SGMII_MODULE_OFFSET 0x100 +#define GBE13_SGMII34_MODULE_OFFSET 0x400 +#define GBE13_SWITCH_MODULE_OFFSET 0x800 +#define GBE13_HOST_PORT_OFFSET 0x834 +#define GBE13_SLAVE_PORT_OFFSET 0x860 +#define GBE13_EMAC_OFFSET 0x900 +#define GBE13_SLAVE_PORT2_OFFSET 0xa00 +#define GBE13_HW_STATS_OFFSET 0xb00 +#define GBE13_ALE_OFFSET 0xe00 +#define GBE13_HOST_PORT_NUM 0 +#define GBE13_NUM_SLAVES 4 +#define GBE13_NUM_ALE_PORTS (GBE13_NUM_SLAVES + 1) +#define GBE13_NUM_ALE_ENTRIES 1024 + +/* 10G Ethernet SS defines */ +#define XGBE_MODULE_NAME "netcp-xgbe" +#define XGBE_SS_VERSION_10 0x4ee42100 + +#define XGBE_SERDES_REG_INDEX 1 +#define XGBE10_SGMII_MODULE_OFFSET 0x100 +#define XGBE10_SWITCH_MODULE_OFFSET 0x1000 +#define XGBE10_HOST_PORT_OFFSET 0x1034 +#define XGBE10_SLAVE_PORT_OFFSET 0x1064 +#define XGBE10_EMAC_OFFSET 0x1400 +#define XGBE10_ALE_OFFSET 0x1700 +#define XGBE10_HW_STATS_OFFSET 0x1800 +#define XGBE10_HOST_PORT_NUM 0 +#define XGBE10_NUM_SLAVES 2 +#define XGBE10_NUM_ALE_PORTS (XGBE10_NUM_SLAVES + 1) +#define XGBE10_NUM_ALE_ENTRIES 1024 + +#define GBE_TIMER_INTERVAL (HZ / 2) + +/* Soft reset register values */ +#define SOFT_RESET_MASK BIT(0) +#define SOFT_RESET BIT(0) +#define DEVICE_EMACSL_RESET_POLL_COUNT 100 +#define GMACSL_RET_WARN_RESET_INCOMPLETE -2 + +#define MACSL_RX_ENABLE_CSF BIT(23) +#define MACSL_ENABLE_EXT_CTL BIT(18) +#define MACSL_XGMII_ENABLE BIT(13) +#define MACSL_XGIG_MODE BIT(8) +#define MACSL_GIG_MODE BIT(7) +#define MACSL_GMII_ENABLE BIT(5) +#define MACSL_FULLDUPLEX BIT(0) + +#define GBE_CTL_P0_ENABLE BIT(2) +#define GBE_REG_VAL_STAT_ENABLE_ALL 0xff +#define XGBE_REG_VAL_STAT_ENABLE_ALL 0xf +#define GBE_STATS_CD_SEL BIT(28) + +#define GBE_PORT_MASK(x) (BIT(x) - 1) +#define GBE_MASK_NO_PORTS 0 + +#define GBE_DEF_1G_MAC_CONTROL \ + (MACSL_GIG_MODE | MACSL_GMII_ENABLE | \ + MACSL_ENABLE_EXT_CTL | MACSL_RX_ENABLE_CSF) + +#define GBE_DEF_10G_MAC_CONTROL \ + (MACSL_XGIG_MODE | MACSL_XGMII_ENABLE | \ + MACSL_ENABLE_EXT_CTL | MACSL_RX_ENABLE_CSF) + +#define GBE_STATSA_MODULE 0 +#define GBE_STATSB_MODULE 1 +#define GBE_STATSC_MODULE 2 +#define GBE_STATSD_MODULE 3 + +#define XGBE_STATS0_MODULE 0 +#define XGBE_STATS1_MODULE 1 +#define XGBE_STATS2_MODULE 2 + +#define MAX_SLAVES GBE13_NUM_SLAVES +/* s: 0-based slave_port */ +#define SGMII_BASE(s) \ + (((s) < 2) ? gbe_dev->sgmii_port_regs : gbe_dev->sgmii_port34_regs) + +#define GBE_TX_QUEUE 648 +#define GBE_TXHOOK_ORDER 0 +#define GBE_DEFAULT_ALE_AGEOUT 30 +#define SLAVE_LINK_IS_XGMII(s) ((s)->link_interface >= XGMII_LINK_MAC_PHY) +#define NETCP_LINK_STATE_INVALID -1 + +#define GBE_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \ + offsetof(struct gbe##_##rb, rn) +#define XGBE_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \ + offsetof(struct xgbe##_##rb, rn) +#define GBE_REG_ADDR(p, rb, rn) (p->rb + p->rb##_ofs.rn) + +struct xgbe_ss_regs { + u32 id_ver; + u32 synce_count; + u32 synce_mux; + u32 control; +}; + +struct xgbe_switch_regs { + u32 id_ver; + u32 control; + u32 emcontrol; + u32 stat_port_en; + u32 ptype; + u32 soft_idle; + u32 thru_rate; + u32 gap_thresh; + u32 tx_start_wds; + u32 flow_control; + u32 cppi_thresh; +}; + +struct xgbe_port_regs { + u32 blk_cnt; + u32 port_vlan; + u32 tx_pri_map; + u32 sa_lo; + u32 sa_hi; + u32 ts_ctl; + u32 ts_seq_ltype; + u32 ts_vlan; + u32 ts_ctl_ltype2; + u32 ts_ctl2; + u32 control; +}; + +struct xgbe_host_port_regs { + u32 blk_cnt; + u32 port_vlan; + u32 tx_pri_map; + u32 src_id; + u32 rx_pri_map; + u32 rx_maxlen; +}; + +struct xgbe_emac_regs { + u32 id_ver; + u32 mac_control; + u32 mac_status; + u32 soft_reset; + u32 rx_maxlen; + u32 __reserved_0; + u32 rx_pause; + u32 tx_pause; + u32 em_control; + u32 __reserved_1; + u32 tx_gap; + u32 rsvd[4]; +}; + +struct xgbe_host_hw_stats { + u32 rx_good_frames; + u32 rx_broadcast_frames; + u32 rx_multicast_frames; + u32 __rsvd_0[3]; + u32 rx_oversized_frames; + u32 __rsvd_1; + u32 rx_undersized_frames; + u32 __rsvd_2; + u32 overrun_type4; + u32 overrun_type5; + u32 rx_bytes; + u32 tx_good_frames; + u32 tx_broadcast_frames; + u32 tx_multicast_frames; + u32 __rsvd_3[9]; + u32 tx_bytes; + u32 tx_64byte_frames; + u32 tx_65_to_127byte_frames; + u32 tx_128_to_255byte_frames; + u32 tx_256_to_511byte_frames; + u32 tx_512_to_1023byte_frames; + u32 tx_1024byte_frames; + u32 net_bytes; + u32 rx_sof_overruns; + u32 rx_mof_overruns; + u32 rx_dma_overruns; +}; + +struct xgbe_hw_stats { + u32 rx_good_frames; + u32 rx_broadcast_frames; + u32 rx_multicast_frames; + u32 rx_pause_frames; + u32 rx_crc_errors; + u32 rx_align_code_errors; + u32 rx_oversized_frames; + u32 rx_jabber_frames; + u32 rx_undersized_frames; + u32 rx_fragments; + u32 overrun_type4; + u32 overrun_type5; + u32 rx_bytes; + u32 tx_good_frames; + u32 tx_broadcast_frames; + u32 tx_multicast_frames; + u32 tx_pause_frames; + u32 tx_deferred_frames; + u32 tx_collision_frames; + u32 tx_single_coll_frames; + u32 tx_mult_coll_frames; + u32 tx_excessive_collisions; + u32 tx_late_collisions; + u32 tx_underrun; + u32 tx_carrier_sense_errors; + u32 tx_bytes; + u32 tx_64byte_frames; + u32 tx_65_to_127byte_frames; + u32 tx_128_to_255byte_frames; + u32 tx_256_to_511byte_frames; + u32 tx_512_to_1023byte_frames; + u32 tx_1024byte_frames; + u32 net_bytes; + u32 rx_sof_overruns; + u32 rx_mof_overruns; + u32 rx_dma_overruns; +}; + +#define XGBE10_NUM_STAT_ENTRIES (sizeof(struct xgbe_hw_stats)/sizeof(u32)) + +struct gbe_ss_regs { + u32 id_ver; + u32 synce_count; + u32 synce_mux; +}; + +struct gbe_ss_regs_ofs { + u16 id_ver; + u16 control; +}; + +struct gbe_switch_regs { + u32 id_ver; + u32 control; + u32 soft_reset; + u32 stat_port_en; + u32 ptype; + u32 soft_idle; + u32 thru_rate; + u32 gap_thresh; + u32 tx_start_wds; + u32 flow_control; +}; + +struct gbe_switch_regs_ofs { + u16 id_ver; + u16 control; + u16 soft_reset; + u16 emcontrol; + u16 stat_port_en; + u16 ptype; + u16 flow_control; +}; + +struct gbe_port_regs { + u32 max_blks; + u32 blk_cnt; + u32 port_vlan; + u32 tx_pri_map; + u32 sa_lo; + u32 sa_hi; + u32 ts_ctl; + u32 ts_seq_ltype; + u32 ts_vlan; + u32 ts_ctl_ltype2; + u32 ts_ctl2; +}; + +struct gbe_port_regs_ofs { + u16 port_vlan; + u16 tx_pri_map; + u16 sa_lo; + u16 sa_hi; + u16 ts_ctl; + u16 ts_seq_ltype; + u16 ts_vlan; + u16 ts_ctl_ltype2; + u16 ts_ctl2; +}; + +struct gbe_host_port_regs { + u32 src_id; + u32 port_vlan; + u32 rx_pri_map; + u32 rx_maxlen; +}; + +struct gbe_host_port_regs_ofs { + u16 port_vlan; + u16 tx_pri_map; + u16 rx_maxlen; +}; + +struct gbe_emac_regs { + u32 id_ver; + u32 mac_control; + u32 mac_status; + u32 soft_reset; + u32 rx_maxlen; + u32 __reserved_0; + u32 rx_pause; + u32 tx_pause; + u32 __reserved_1; + u32 rx_pri_map; + u32 rsvd[6]; +}; + +struct gbe_emac_regs_ofs { + u16 mac_control; + u16 soft_reset; + u16 rx_maxlen; +}; + +struct gbe_hw_stats { + u32 rx_good_frames; + u32 rx_broadcast_frames; + u32 rx_multicast_frames; + u32 rx_pause_frames; + u32 rx_crc_errors; + u32 rx_align_code_errors; + u32 rx_oversized_frames; + u32 rx_jabber_frames; + u32 rx_undersized_frames; + u32 rx_fragments; + u32 __pad_0[2]; + u32 rx_bytes; + u32 tx_good_frames; + u32 tx_broadcast_frames; + u32 tx_multicast_frames; + u32 tx_pause_frames; + u32 tx_deferred_frames; + u32 tx_collision_frames; + u32 tx_single_coll_frames; + u32 tx_mult_coll_frames; + u32 tx_excessive_collisions; + u32 tx_late_collisions; + u32 tx_underrun; + u32 tx_carrier_sense_errors; + u32 tx_bytes; + u32 tx_64byte_frames; + u32 tx_65_to_127byte_frames; + u32 tx_128_to_255byte_frames; + u32 tx_256_to_511byte_frames; + u32 tx_512_to_1023byte_frames; + u32 tx_1024byte_frames; + u32 net_bytes; + u32 rx_sof_overruns; + u32 rx_mof_overruns; + u32 rx_dma_overruns; +}; + +#define GBE13_NUM_HW_STAT_ENTRIES (sizeof(struct gbe_hw_stats)/sizeof(u32)) +#define GBE13_NUM_HW_STATS_MOD 2 +#define XGBE10_NUM_HW_STATS_MOD 3 +#define GBE_MAX_HW_STAT_MODS 3 +#define GBE_HW_STATS_REG_MAP_SZ 0x100 + +struct gbe_slave { + void __iomem *port_regs; + void __iomem *emac_regs; + struct gbe_port_regs_ofs port_regs_ofs; + struct gbe_emac_regs_ofs emac_regs_ofs; + int slave_num; /* 0 based logical number */ + int port_num; /* actual port number */ + atomic_t link_state; + bool open; + struct phy_device *phy; + u32 link_interface; + u32 mac_control; + u8 phy_port_t; + struct device_node *phy_node; + struct list_head slave_list; +}; + +struct gbe_priv { + struct device *dev; + struct netcp_device *netcp_device; + struct timer_list timer; + u32 num_slaves; + u32 ale_entries; + u32 ale_ports; + bool enable_ale; + struct netcp_tx_pipe tx_pipe; + + int host_port; + u32 rx_packet_max; + u32 ss_version; + + void __iomem *ss_regs; + void __iomem *switch_regs; + void __iomem *host_port_regs; + void __iomem *ale_reg; + void __iomem *sgmii_port_regs; + void __iomem *sgmii_port34_regs; + void __iomem *xgbe_serdes_regs; + void __iomem *hw_stats_regs[GBE_MAX_HW_STAT_MODS]; + + struct gbe_ss_regs_ofs ss_regs_ofs; + struct gbe_switch_regs_ofs switch_regs_ofs; + struct gbe_host_port_regs_ofs host_port_regs_ofs; + + struct cpsw_ale *ale; + unsigned int tx_queue_id; + const char *dma_chan_name; + + struct list_head gbe_intf_head; + struct list_head secondary_slaves; + struct net_device *dummy_ndev; + + u64 *hw_stats; + const struct netcp_ethtool_stat *et_stats; + int num_et_stats; + /* Lock for updating the hwstats */ + spinlock_t hw_stats_lock; +}; + +struct gbe_intf { + struct net_device *ndev; + struct device *dev; + struct gbe_priv *gbe_dev; + struct netcp_tx_pipe tx_pipe; + struct gbe_slave *slave; + struct list_head gbe_intf_list; + unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; +}; + +static struct netcp_module gbe_module; +static struct netcp_module xgbe_module; + +/* Statistic management */ +struct netcp_ethtool_stat { + char desc[ETH_GSTRING_LEN]; + int type; + u32 size; + int offset; +}; + +#define GBE_STATSA_INFO(field) "GBE_A:"#field, GBE_STATSA_MODULE,\ + FIELD_SIZEOF(struct gbe_hw_stats, field), \ + offsetof(struct gbe_hw_stats, field) + +#define GBE_STATSB_INFO(field) "GBE_B:"#field, GBE_STATSB_MODULE,\ + FIELD_SIZEOF(struct gbe_hw_stats, field), \ + offsetof(struct gbe_hw_stats, field) + +#define GBE_STATSC_INFO(field) "GBE_C:"#field, GBE_STATSC_MODULE,\ + FIELD_SIZEOF(struct gbe_hw_stats, field), \ + offsetof(struct gbe_hw_stats, field) + +#define GBE_STATSD_INFO(field) "GBE_D:"#field, GBE_STATSD_MODULE,\ + FIELD_SIZEOF(struct gbe_hw_stats, field), \ + offsetof(struct gbe_hw_stats, field) + +static const struct netcp_ethtool_stat gbe13_et_stats[] = { + /* GBE module A */ + {GBE_STATSA_INFO(rx_good_frames)}, + {GBE_STATSA_INFO(rx_broadcast_frames)}, + {GBE_STATSA_INFO(rx_multicast_frames)}, + {GBE_STATSA_INFO(rx_pause_frames)}, + {GBE_STATSA_INFO(rx_crc_errors)}, + {GBE_STATSA_INFO(rx_align_code_errors)}, + {GBE_STATSA_INFO(rx_oversized_frames)}, + {GBE_STATSA_INFO(rx_jabber_frames)}, + {GBE_STATSA_INFO(rx_undersized_frames)}, + {GBE_STATSA_INFO(rx_fragments)}, + {GBE_STATSA_INFO(rx_bytes)}, + {GBE_STATSA_INFO(tx_good_frames)}, + {GBE_STATSA_INFO(tx_broadcast_frames)}, + {GBE_STATSA_INFO(tx_multicast_frames)}, + {GBE_STATSA_INFO(tx_pause_frames)}, + {GBE_STATSA_INFO(tx_deferred_frames)}, + {GBE_STATSA_INFO(tx_collision_frames)}, + {GBE_STATSA_INFO(tx_single_coll_frames)}, + {GBE_STATSA_INFO(tx_mult_coll_frames)}, + {GBE_STATSA_INFO(tx_excessive_collisions)}, + {GBE_STATSA_INFO(tx_late_collisions)}, + {GBE_STATSA_INFO(tx_underrun)}, + {GBE_STATSA_INFO(tx_carrier_sense_errors)}, + {GBE_STATSA_INFO(tx_bytes)}, + {GBE_STATSA_INFO(tx_64byte_frames)}, + {GBE_STATSA_INFO(tx_65_to_127byte_frames)}, + {GBE_STATSA_INFO(tx_128_to_255byte_frames)}, + {GBE_STATSA_INFO(tx_256_to_511byte_frames)}, + {GBE_STATSA_INFO(tx_512_to_1023byte_frames)}, + {GBE_STATSA_INFO(tx_1024byte_frames)}, + {GBE_STATSA_INFO(net_bytes)}, + {GBE_STATSA_INFO(rx_sof_overruns)}, + {GBE_STATSA_INFO(rx_mof_overruns)}, + {GBE_STATSA_INFO(rx_dma_overruns)}, + /* GBE module B */ + {GBE_STATSB_INFO(rx_good_frames)}, + {GBE_STATSB_INFO(rx_broadcast_frames)}, + {GBE_STATSB_INFO(rx_multicast_frames)}, + {GBE_STATSB_INFO(rx_pause_frames)}, + {GBE_STATSB_INFO(rx_crc_errors)}, + {GBE_STATSB_INFO(rx_align_code_errors)}, + {GBE_STATSB_INFO(rx_oversized_frames)}, + {GBE_STATSB_INFO(rx_jabber_frames)}, + {GBE_STATSB_INFO(rx_undersized_frames)}, + {GBE_STATSB_INFO(rx_fragments)}, + {GBE_STATSB_INFO(rx_bytes)}, + {GBE_STATSB_INFO(tx_good_frames)}, + {GBE_STATSB_INFO(tx_broadcast_frames)}, + {GBE_STATSB_INFO(tx_multicast_frames)}, + {GBE_STATSB_INFO(tx_pause_frames)}, + {GBE_STATSB_INFO(tx_deferred_frames)}, + {GBE_STATSB_INFO(tx_collision_frames)}, + {GBE_STATSB_INFO(tx_single_coll_frames)}, + {GBE_STATSB_INFO(tx_mult_coll_frames)}, + {GBE_STATSB_INFO(tx_excessive_collisions)}, + {GBE_STATSB_INFO(tx_late_collisions)}, + {GBE_STATSB_INFO(tx_underrun)}, + {GBE_STATSB_INFO(tx_carrier_sense_errors)}, + {GBE_STATSB_INFO(tx_bytes)}, + {GBE_STATSB_INFO(tx_64byte_frames)}, + {GBE_STATSB_INFO(tx_65_to_127byte_frames)}, + {GBE_STATSB_INFO(tx_128_to_255byte_frames)}, + {GBE_STATSB_INFO(tx_256_to_511byte_frames)}, + {GBE_STATSB_INFO(tx_512_to_1023byte_frames)}, + {GBE_STATSB_INFO(tx_1024byte_frames)}, + {GBE_STATSB_INFO(net_bytes)}, + {GBE_STATSB_INFO(rx_sof_overruns)}, + {GBE_STATSB_INFO(rx_mof_overruns)}, + {GBE_STATSB_INFO(rx_dma_overruns)}, + /* GBE module C */ + {GBE_STATSC_INFO(rx_good_frames)}, + {GBE_STATSC_INFO(rx_broadcast_frames)}, + {GBE_STATSC_INFO(rx_multicast_frames)}, + {GBE_STATSC_INFO(rx_pause_frames)}, + {GBE_STATSC_INFO(rx_crc_errors)}, + {GBE_STATSC_INFO(rx_align_code_errors)}, + {GBE_STATSC_INFO(rx_oversized_frames)}, + {GBE_STATSC_INFO(rx_jabber_frames)}, + {GBE_STATSC_INFO(rx_undersized_frames)}, + {GBE_STATSC_INFO(rx_fragments)}, + {GBE_STATSC_INFO(rx_bytes)}, + {GBE_STATSC_INFO(tx_good_frames)}, + {GBE_STATSC_INFO(tx_broadcast_frames)}, + {GBE_STATSC_INFO(tx_multicast_frames)}, + {GBE_STATSC_INFO(tx_pause_frames)}, + {GBE_STATSC_INFO(tx_deferred_frames)}, + {GBE_STATSC_INFO(tx_collision_frames)}, + {GBE_STATSC_INFO(tx_single_coll_frames)}, + {GBE_STATSC_INFO(tx_mult_coll_frames)}, + {GBE_STATSC_INFO(tx_excessive_collisions)}, + {GBE_STATSC_INFO(tx_late_collisions)}, + {GBE_STATSC_INFO(tx_underrun)}, + {GBE_STATSC_INFO(tx_carrier_sense_errors)}, + {GBE_STATSC_INFO(tx_bytes)}, + {GBE_STATSC_INFO(tx_64byte_frames)}, + {GBE_STATSC_INFO(tx_65_to_127byte_frames)}, + {GBE_STATSC_INFO(tx_128_to_255byte_frames)}, + {GBE_STATSC_INFO(tx_256_to_511byte_frames)}, + {GBE_STATSC_INFO(tx_512_to_1023byte_frames)}, + {GBE_STATSC_INFO(tx_1024byte_frames)}, + {GBE_STATSC_INFO(net_bytes)}, + {GBE_STATSC_INFO(rx_sof_overruns)}, + {GBE_STATSC_INFO(rx_mof_overruns)}, + {GBE_STATSC_INFO(rx_dma_overruns)}, + /* GBE module D */ + {GBE_STATSD_INFO(rx_good_frames)}, + {GBE_STATSD_INFO(rx_broadcast_frames)}, + {GBE_STATSD_INFO(rx_multicast_frames)}, + {GBE_STATSD_INFO(rx_pause_frames)}, + {GBE_STATSD_INFO(rx_crc_errors)}, + {GBE_STATSD_INFO(rx_align_code_errors)}, + {GBE_STATSD_INFO(rx_oversized_frames)}, + {GBE_STATSD_INFO(rx_jabber_frames)}, + {GBE_STATSD_INFO(rx_undersized_frames)}, + {GBE_STATSD_INFO(rx_fragments)}, + {GBE_STATSD_INFO(rx_bytes)}, + {GBE_STATSD_INFO(tx_good_frames)}, + {GBE_STATSD_INFO(tx_broadcast_frames)}, + {GBE_STATSD_INFO(tx_multicast_frames)}, + {GBE_STATSD_INFO(tx_pause_frames)}, + {GBE_STATSD_INFO(tx_deferred_frames)}, + {GBE_STATSD_INFO(tx_collision_frames)}, + {GBE_STATSD_INFO(tx_single_coll_frames)}, + {GBE_STATSD_INFO(tx_mult_coll_frames)}, + {GBE_STATSD_INFO(tx_excessive_collisions)}, + {GBE_STATSD_INFO(tx_late_collisions)}, + {GBE_STATSD_INFO(tx_underrun)}, + {GBE_STATSD_INFO(tx_carrier_sense_errors)}, + {GBE_STATSD_INFO(tx_bytes)}, + {GBE_STATSD_INFO(tx_64byte_frames)}, + {GBE_STATSD_INFO(tx_65_to_127byte_frames)}, + {GBE_STATSD_INFO(tx_128_to_255byte_frames)}, + {GBE_STATSD_INFO(tx_256_to_511byte_frames)}, + {GBE_STATSD_INFO(tx_512_to_1023byte_frames)}, + {GBE_STATSD_INFO(tx_1024byte_frames)}, + {GBE_STATSD_INFO(net_bytes)}, + {GBE_STATSD_INFO(rx_sof_overruns)}, + {GBE_STATSD_INFO(rx_mof_overruns)}, + {GBE_STATSD_INFO(rx_dma_overruns)}, +}; + +#define XGBE_STATS0_INFO(field) "GBE_0:"#field, XGBE_STATS0_MODULE, \ + FIELD_SIZEOF(struct xgbe_hw_stats, field), \ + offsetof(struct xgbe_hw_stats, field) + +#define XGBE_STATS1_INFO(field) "GBE_1:"#field, XGBE_STATS1_MODULE, \ + FIELD_SIZEOF(struct xgbe_hw_stats, field), \ + offsetof(struct xgbe_hw_stats, field) + +#define XGBE_STATS2_INFO(field) "GBE_2:"#field, XGBE_STATS2_MODULE, \ + FIELD_SIZEOF(struct xgbe_hw_stats, field), \ + offsetof(struct xgbe_hw_stats, field) + +static const struct netcp_ethtool_stat xgbe10_et_stats[] = { + /* GBE module 0 */ + {XGBE_STATS0_INFO(rx_good_frames)}, + {XGBE_STATS0_INFO(rx_broadcast_frames)}, + {XGBE_STATS0_INFO(rx_multicast_frames)}, + {XGBE_STATS0_INFO(rx_oversized_frames)}, + {XGBE_STATS0_INFO(rx_undersized_frames)}, + {XGBE_STATS0_INFO(overrun_type4)}, + {XGBE_STATS0_INFO(overrun_type5)}, + {XGBE_STATS0_INFO(rx_bytes)}, + {XGBE_STATS0_INFO(tx_good_frames)}, + {XGBE_STATS0_INFO(tx_broadcast_frames)}, + {XGBE_STATS0_INFO(tx_multicast_frames)}, + {XGBE_STATS0_INFO(tx_bytes)}, + {XGBE_STATS0_INFO(tx_64byte_frames)}, + {XGBE_STATS0_INFO(tx_65_to_127byte_frames)}, + {XGBE_STATS0_INFO(tx_128_to_255byte_frames)}, + {XGBE_STATS0_INFO(tx_256_to_511byte_frames)}, + {XGBE_STATS0_INFO(tx_512_to_1023byte_frames)}, + {XGBE_STATS0_INFO(tx_1024byte_frames)}, + {XGBE_STATS0_INFO(net_bytes)}, + {XGBE_STATS0_INFO(rx_sof_overruns)}, + {XGBE_STATS0_INFO(rx_mof_overruns)}, + {XGBE_STATS0_INFO(rx_dma_overruns)}, + /* XGBE module 1 */ + {XGBE_STATS1_INFO(rx_good_frames)}, + {XGBE_STATS1_INFO(rx_broadcast_frames)}, + {XGBE_STATS1_INFO(rx_multicast_frames)}, + {XGBE_STATS1_INFO(rx_pause_frames)}, + {XGBE_STATS1_INFO(rx_crc_errors)}, + {XGBE_STATS1_INFO(rx_align_code_errors)}, + {XGBE_STATS1_INFO(rx_oversized_frames)}, + {XGBE_STATS1_INFO(rx_jabber_frames)}, + {XGBE_STATS1_INFO(rx_undersized_frames)}, + {XGBE_STATS1_INFO(rx_fragments)}, + {XGBE_STATS1_INFO(overrun_type4)}, + {XGBE_STATS1_INFO(overrun_type5)}, + {XGBE_STATS1_INFO(rx_bytes)}, + {XGBE_STATS1_INFO(tx_good_frames)}, + {XGBE_STATS1_INFO(tx_broadcast_frames)}, + {XGBE_STATS1_INFO(tx_multicast_frames)}, + {XGBE_STATS1_INFO(tx_pause_frames)}, + {XGBE_STATS1_INFO(tx_deferred_frames)}, + {XGBE_STATS1_INFO(tx_collision_frames)}, + {XGBE_STATS1_INFO(tx_single_coll_frames)}, + {XGBE_STATS1_INFO(tx_mult_coll_frames)}, + {XGBE_STATS1_INFO(tx_excessive_collisions)}, + {XGBE_STATS1_INFO(tx_late_collisions)}, + {XGBE_STATS1_INFO(tx_underrun)}, + {XGBE_STATS1_INFO(tx_carrier_sense_errors)}, + {XGBE_STATS1_INFO(tx_bytes)}, + {XGBE_STATS1_INFO(tx_64byte_frames)}, + {XGBE_STATS1_INFO(tx_65_to_127byte_frames)}, + {XGBE_STATS1_INFO(tx_128_to_255byte_frames)}, + {XGBE_STATS1_INFO(tx_256_to_511byte_frames)}, + {XGBE_STATS1_INFO(tx_512_to_1023byte_frames)}, + {XGBE_STATS1_INFO(tx_1024byte_frames)}, + {XGBE_STATS1_INFO(net_bytes)}, + {XGBE_STATS1_INFO(rx_sof_overruns)}, + {XGBE_STATS1_INFO(rx_mof_overruns)}, + {XGBE_STATS1_INFO(rx_dma_overruns)}, + /* XGBE module 2 */ + {XGBE_STATS2_INFO(rx_good_frames)}, + {XGBE_STATS2_INFO(rx_broadcast_frames)}, + {XGBE_STATS2_INFO(rx_multicast_frames)}, + {XGBE_STATS2_INFO(rx_pause_frames)}, + {XGBE_STATS2_INFO(rx_crc_errors)}, + {XGBE_STATS2_INFO(rx_align_code_errors)}, + {XGBE_STATS2_INFO(rx_oversized_frames)}, + {XGBE_STATS2_INFO(rx_jabber_frames)}, + {XGBE_STATS2_INFO(rx_undersized_frames)}, + {XGBE_STATS2_INFO(rx_fragments)}, + {XGBE_STATS2_INFO(overrun_type4)}, + {XGBE_STATS2_INFO(overrun_type5)}, + {XGBE_STATS2_INFO(rx_bytes)}, + {XGBE_STATS2_INFO(tx_good_frames)}, + {XGBE_STATS2_INFO(tx_broadcast_frames)}, + {XGBE_STATS2_INFO(tx_multicast_frames)}, + {XGBE_STATS2_INFO(tx_pause_frames)}, + {XGBE_STATS2_INFO(tx_deferred_frames)}, + {XGBE_STATS2_INFO(tx_collision_frames)}, + {XGBE_STATS2_INFO(tx_single_coll_frames)}, + {XGBE_STATS2_INFO(tx_mult_coll_frames)}, + {XGBE_STATS2_INFO(tx_excessive_collisions)}, + {XGBE_STATS2_INFO(tx_late_collisions)}, + {XGBE_STATS2_INFO(tx_underrun)}, + {XGBE_STATS2_INFO(tx_carrier_sense_errors)}, + {XGBE_STATS2_INFO(tx_bytes)}, + {XGBE_STATS2_INFO(tx_64byte_frames)}, + {XGBE_STATS2_INFO(tx_65_to_127byte_frames)}, + {XGBE_STATS2_INFO(tx_128_to_255byte_frames)}, + {XGBE_STATS2_INFO(tx_256_to_511byte_frames)}, + {XGBE_STATS2_INFO(tx_512_to_1023byte_frames)}, + {XGBE_STATS2_INFO(tx_1024byte_frames)}, + {XGBE_STATS2_INFO(net_bytes)}, + {XGBE_STATS2_INFO(rx_sof_overruns)}, + {XGBE_STATS2_INFO(rx_mof_overruns)}, + {XGBE_STATS2_INFO(rx_dma_overruns)}, +}; + +#define for_each_intf(i, priv) \ + list_for_each_entry((i), &(priv)->gbe_intf_head, gbe_intf_list) + +#define for_each_sec_slave(slave, priv) \ + list_for_each_entry((slave), &(priv)->secondary_slaves, slave_list) + +#define first_sec_slave(priv) \ + list_first_entry(&priv->secondary_slaves, \ + struct gbe_slave, slave_list) + +static void keystone_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + strncpy(info->driver, NETCP_DRIVER_NAME, sizeof(info->driver)); + strncpy(info->version, NETCP_DRIVER_VERSION, sizeof(info->version)); +} + +static u32 keystone_get_msglevel(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + + return netcp->msg_enable; +} + +static void keystone_set_msglevel(struct net_device *ndev, u32 value) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + + netcp->msg_enable = value; +} + +static void keystone_get_stat_strings(struct net_device *ndev, + uint32_t stringset, uint8_t *data) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct gbe_intf *gbe_intf; + struct gbe_priv *gbe_dev; + int i; + + gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + if (!gbe_intf) + return; + gbe_dev = gbe_intf->gbe_dev; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < gbe_dev->num_et_stats; i++) { + memcpy(data, gbe_dev->et_stats[i].desc, + ETH_GSTRING_LEN); + data += ETH_GSTRING_LEN; + } + break; + case ETH_SS_TEST: + break; + } +} + +static int keystone_get_sset_count(struct net_device *ndev, int stringset) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct gbe_intf *gbe_intf; + struct gbe_priv *gbe_dev; + + gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + if (!gbe_intf) + return -EINVAL; + gbe_dev = gbe_intf->gbe_dev; + + switch (stringset) { + case ETH_SS_TEST: + return 0; + case ETH_SS_STATS: + return gbe_dev->num_et_stats; + default: + return -EINVAL; + } +} + +static void gbe_update_stats(struct gbe_priv *gbe_dev, uint64_t *data) +{ + void __iomem *base = NULL; + u32 __iomem *p; + u32 tmp = 0; + int i; + + for (i = 0; i < gbe_dev->num_et_stats; i++) { + base = gbe_dev->hw_stats_regs[gbe_dev->et_stats[i].type]; + p = base + gbe_dev->et_stats[i].offset; + tmp = readl(p); + gbe_dev->hw_stats[i] = gbe_dev->hw_stats[i] + tmp; + if (data) + data[i] = gbe_dev->hw_stats[i]; + /* write-to-decrement: + * new register value = old register value - write value + */ + writel(tmp, p); + } +} + +static void gbe_update_stats_ver14(struct gbe_priv *gbe_dev, uint64_t *data) +{ + void __iomem *gbe_statsa = gbe_dev->hw_stats_regs[0]; + void __iomem *gbe_statsb = gbe_dev->hw_stats_regs[1]; + u64 *hw_stats = &gbe_dev->hw_stats[0]; + void __iomem *base = NULL; + u32 __iomem *p; + u32 tmp = 0, val, pair_size = (gbe_dev->num_et_stats / 2); + int i, j, pair; + + for (pair = 0; pair < 2; pair++) { + val = readl(GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en)); + + if (pair == 0) + val &= ~GBE_STATS_CD_SEL; + else + val |= GBE_STATS_CD_SEL; + + /* make the stat modules visible */ + writel(val, GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en)); + + for (i = 0; i < pair_size; i++) { + j = pair * pair_size + i; + switch (gbe_dev->et_stats[j].type) { + case GBE_STATSA_MODULE: + case GBE_STATSC_MODULE: + base = gbe_statsa; + break; + case GBE_STATSB_MODULE: + case GBE_STATSD_MODULE: + base = gbe_statsb; + break; + } + + p = base + gbe_dev->et_stats[j].offset; + tmp = readl(p); + hw_stats[j] += tmp; + if (data) + data[j] = hw_stats[j]; + /* write-to-decrement: + * new register value = old register value - write value + */ + writel(tmp, p); + } + } +} + +static void keystone_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *stats, + uint64_t *data) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct gbe_intf *gbe_intf; + struct gbe_priv *gbe_dev; + + gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + if (!gbe_intf) + return; + + gbe_dev = gbe_intf->gbe_dev; + spin_lock_bh(&gbe_dev->hw_stats_lock); + if (gbe_dev->ss_version == GBE_SS_VERSION_14) + gbe_update_stats_ver14(gbe_dev, data); + else + gbe_update_stats(gbe_dev, data); + spin_unlock_bh(&gbe_dev->hw_stats_lock); +} + +static int keystone_get_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct phy_device *phy = ndev->phydev; + struct gbe_intf *gbe_intf; + int ret; + + if (!phy) + return -EINVAL; + + gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + if (!gbe_intf) + return -EINVAL; + + if (!gbe_intf->slave) + return -EINVAL; + + ret = phy_ethtool_gset(phy, cmd); + if (!ret) + cmd->port = gbe_intf->slave->phy_port_t; + + return ret; +} + +static int keystone_set_settings(struct net_device *ndev, + struct ethtool_cmd *cmd) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct phy_device *phy = ndev->phydev; + struct gbe_intf *gbe_intf; + u32 features = cmd->advertising & cmd->supported; + + if (!phy) + return -EINVAL; + + gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + if (!gbe_intf) + return -EINVAL; + + if (!gbe_intf->slave) + return -EINVAL; + + if (cmd->port != gbe_intf->slave->phy_port_t) { + if ((cmd->port == PORT_TP) && !(features & ADVERTISED_TP)) + return -EINVAL; + + if ((cmd->port == PORT_AUI) && !(features & ADVERTISED_AUI)) + return -EINVAL; + + if ((cmd->port == PORT_BNC) && !(features & ADVERTISED_BNC)) + return -EINVAL; + + if ((cmd->port == PORT_MII) && !(features & ADVERTISED_MII)) + return -EINVAL; + + if ((cmd->port == PORT_FIBRE) && !(features & ADVERTISED_FIBRE)) + return -EINVAL; + } + + gbe_intf->slave->phy_port_t = cmd->port; + return phy_ethtool_sset(phy, cmd); +} + +static const struct ethtool_ops keystone_ethtool_ops = { + .get_drvinfo = keystone_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_msglevel = keystone_get_msglevel, + .set_msglevel = keystone_set_msglevel, + .get_strings = keystone_get_stat_strings, + .get_sset_count = keystone_get_sset_count, + .get_ethtool_stats = keystone_get_ethtool_stats, + .get_settings = keystone_get_settings, + .set_settings = keystone_set_settings, +}; + +#define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \ + ((mac)[2] << 16) | ((mac)[3] << 24)) +#define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8)) + +static void gbe_set_slave_mac(struct gbe_slave *slave, + struct gbe_intf *gbe_intf) +{ + struct net_device *ndev = gbe_intf->ndev; + + writel(mac_hi(ndev->dev_addr), GBE_REG_ADDR(slave, port_regs, sa_hi)); + writel(mac_lo(ndev->dev_addr), GBE_REG_ADDR(slave, port_regs, sa_lo)); +} + +static int gbe_get_slave_port(struct gbe_priv *priv, u32 slave_num) +{ + if (priv->host_port == 0) + return slave_num + 1; + + return slave_num; +} + +static void netcp_ethss_link_state_action(struct gbe_priv *gbe_dev, + struct net_device *ndev, + struct gbe_slave *slave, + int up) +{ + struct phy_device *phy = slave->phy; + u32 mac_control = 0; + + if (up) { + mac_control = slave->mac_control; + if (phy && (phy->speed == SPEED_1000)) { + mac_control |= MACSL_GIG_MODE; + mac_control &= ~MACSL_XGIG_MODE; + } else if (phy && (phy->speed == SPEED_10000)) { + mac_control |= MACSL_XGIG_MODE; + mac_control &= ~MACSL_GIG_MODE; + } + + writel(mac_control, GBE_REG_ADDR(slave, emac_regs, + mac_control)); + + cpsw_ale_control_set(gbe_dev->ale, slave->port_num, + ALE_PORT_STATE, + ALE_PORT_STATE_FORWARD); + + if (ndev && slave->open) + netif_carrier_on(ndev); + } else { + writel(mac_control, GBE_REG_ADDR(slave, emac_regs, + mac_control)); + cpsw_ale_control_set(gbe_dev->ale, slave->port_num, + ALE_PORT_STATE, + ALE_PORT_STATE_DISABLE); + if (ndev) + netif_carrier_off(ndev); + } + + if (phy) + phy_print_status(phy); +} + +static bool gbe_phy_link_status(struct gbe_slave *slave) +{ + return !slave->phy || slave->phy->link; +} + +static void netcp_ethss_update_link_state(struct gbe_priv *gbe_dev, + struct gbe_slave *slave, + struct net_device *ndev) +{ + int sp = slave->slave_num; + int phy_link_state, sgmii_link_state = 1, link_state; + + if (!slave->open) + return; + + if (!SLAVE_LINK_IS_XGMII(slave)) + sgmii_link_state = netcp_sgmii_get_port_link(SGMII_BASE(sp), + sp); + phy_link_state = gbe_phy_link_status(slave); + link_state = phy_link_state & sgmii_link_state; + + if (atomic_xchg(&slave->link_state, link_state) != link_state) + netcp_ethss_link_state_action(gbe_dev, ndev, slave, + link_state); +} + +static void xgbe_adjust_link(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct gbe_intf *gbe_intf; + + gbe_intf = netcp_module_get_intf_data(&xgbe_module, netcp); + if (!gbe_intf) + return; + + netcp_ethss_update_link_state(gbe_intf->gbe_dev, gbe_intf->slave, + ndev); +} + +static void gbe_adjust_link(struct net_device *ndev) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct gbe_intf *gbe_intf; + + gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + if (!gbe_intf) + return; + + netcp_ethss_update_link_state(gbe_intf->gbe_dev, gbe_intf->slave, + ndev); +} + +static void gbe_adjust_link_sec_slaves(struct net_device *ndev) +{ + struct gbe_priv *gbe_dev = netdev_priv(ndev); + struct gbe_slave *slave; + + for_each_sec_slave(slave, gbe_dev) + netcp_ethss_update_link_state(gbe_dev, slave, NULL); +} + +/* Reset EMAC + * Soft reset is set and polled until clear, or until a timeout occurs + */ +static int gbe_port_reset(struct gbe_slave *slave) +{ + u32 i, v; + + /* Set the soft reset bit */ + writel(SOFT_RESET, GBE_REG_ADDR(slave, emac_regs, soft_reset)); + + /* Wait for the bit to clear */ + for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) { + v = readl(GBE_REG_ADDR(slave, emac_regs, soft_reset)); + if ((v & SOFT_RESET_MASK) != SOFT_RESET) + return 0; + } + + /* Timeout on the reset */ + return GMACSL_RET_WARN_RESET_INCOMPLETE; +} + +/* Configure EMAC */ +static void gbe_port_config(struct gbe_priv *gbe_dev, struct gbe_slave *slave, + int max_rx_len) +{ + u32 xgmii_mode; + + if (max_rx_len > NETCP_MAX_FRAME_SIZE) + max_rx_len = NETCP_MAX_FRAME_SIZE; + + /* Enable correct MII mode at SS level */ + if ((gbe_dev->ss_version == XGBE_SS_VERSION_10) && + (slave->link_interface >= XGMII_LINK_MAC_PHY)) { + xgmii_mode = readl(GBE_REG_ADDR(gbe_dev, ss_regs, control)); + xgmii_mode |= (1 << slave->slave_num); + writel(xgmii_mode, GBE_REG_ADDR(gbe_dev, ss_regs, control)); + } + + writel(max_rx_len, GBE_REG_ADDR(slave, emac_regs, rx_maxlen)); + writel(slave->mac_control, GBE_REG_ADDR(slave, emac_regs, mac_control)); +} + +static void gbe_slave_stop(struct gbe_intf *intf) +{ + struct gbe_priv *gbe_dev = intf->gbe_dev; + struct gbe_slave *slave = intf->slave; + + gbe_port_reset(slave); + /* Disable forwarding */ + cpsw_ale_control_set(gbe_dev->ale, slave->port_num, + ALE_PORT_STATE, ALE_PORT_STATE_DISABLE); + cpsw_ale_del_mcast(gbe_dev->ale, intf->ndev->broadcast, + 1 << slave->port_num, 0, 0); + + if (!slave->phy) + return; + + phy_stop(slave->phy); + phy_disconnect(slave->phy); + slave->phy = NULL; +} + +static void gbe_sgmii_config(struct gbe_priv *priv, struct gbe_slave *slave) +{ + void __iomem *sgmii_port_regs; + + sgmii_port_regs = priv->sgmii_port_regs; + if ((priv->ss_version == GBE_SS_VERSION_14) && (slave->slave_num >= 2)) + sgmii_port_regs = priv->sgmii_port34_regs; + + if (!SLAVE_LINK_IS_XGMII(slave)) { + netcp_sgmii_reset(sgmii_port_regs, slave->slave_num); + netcp_sgmii_config(sgmii_port_regs, slave->slave_num, + slave->link_interface); + } +} + +static int gbe_slave_open(struct gbe_intf *gbe_intf) +{ + struct gbe_priv *priv = gbe_intf->gbe_dev; + struct gbe_slave *slave = gbe_intf->slave; + phy_interface_t phy_mode; + bool has_phy = false; + + void (*hndlr)(struct net_device *) = gbe_adjust_link; + + gbe_sgmii_config(priv, slave); + gbe_port_reset(slave); + gbe_port_config(priv, slave, priv->rx_packet_max); + gbe_set_slave_mac(slave, gbe_intf); + /* enable forwarding */ + cpsw_ale_control_set(priv->ale, slave->port_num, + ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); + cpsw_ale_add_mcast(priv->ale, gbe_intf->ndev->broadcast, + 1 << slave->port_num, 0, 0, ALE_MCAST_FWD_2); + + if (slave->link_interface == SGMII_LINK_MAC_PHY) { + has_phy = true; + phy_mode = PHY_INTERFACE_MODE_SGMII; + slave->phy_port_t = PORT_MII; + } else if (slave->link_interface == XGMII_LINK_MAC_PHY) { + has_phy = true; + phy_mode = PHY_INTERFACE_MODE_NA; + slave->phy_port_t = PORT_FIBRE; + } + + if (has_phy) { + if (priv->ss_version == XGBE_SS_VERSION_10) + hndlr = xgbe_adjust_link; + + slave->phy = of_phy_connect(gbe_intf->ndev, + slave->phy_node, + hndlr, 0, + phy_mode); + if (!slave->phy) { + dev_err(priv->dev, "phy not found on slave %d\n", + slave->slave_num); + return -ENODEV; + } + dev_dbg(priv->dev, "phy found: id is: 0x%s\n", + dev_name(&slave->phy->dev)); + phy_start(slave->phy); + phy_read_status(slave->phy); + } + return 0; +} + +static void gbe_init_host_port(struct gbe_priv *priv) +{ + int bypass_en = 1; + /* Max length register */ + writel(NETCP_MAX_FRAME_SIZE, GBE_REG_ADDR(priv, host_port_regs, + rx_maxlen)); + + cpsw_ale_start(priv->ale); + + if (priv->enable_ale) + bypass_en = 0; + + cpsw_ale_control_set(priv->ale, 0, ALE_BYPASS, bypass_en); + + cpsw_ale_control_set(priv->ale, 0, ALE_NO_PORT_VLAN, 1); + + cpsw_ale_control_set(priv->ale, priv->host_port, + ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); + + cpsw_ale_control_set(priv->ale, 0, + ALE_PORT_UNKNOWN_VLAN_MEMBER, + GBE_PORT_MASK(priv->ale_ports)); + + cpsw_ale_control_set(priv->ale, 0, + ALE_PORT_UNKNOWN_MCAST_FLOOD, + GBE_PORT_MASK(priv->ale_ports - 1)); + + cpsw_ale_control_set(priv->ale, 0, + ALE_PORT_UNKNOWN_REG_MCAST_FLOOD, + GBE_PORT_MASK(priv->ale_ports)); + + cpsw_ale_control_set(priv->ale, 0, + ALE_PORT_UNTAGGED_EGRESS, + GBE_PORT_MASK(priv->ale_ports)); +} + +static void gbe_add_mcast_addr(struct gbe_intf *gbe_intf, u8 *addr) +{ + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + u16 vlan_id; + + cpsw_ale_add_mcast(gbe_dev->ale, addr, + GBE_PORT_MASK(gbe_dev->ale_ports), 0, 0, + ALE_MCAST_FWD_2); + for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID) { + cpsw_ale_add_mcast(gbe_dev->ale, addr, + GBE_PORT_MASK(gbe_dev->ale_ports), + ALE_VLAN, vlan_id, ALE_MCAST_FWD_2); + } +} + +static void gbe_add_ucast_addr(struct gbe_intf *gbe_intf, u8 *addr) +{ + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + u16 vlan_id; + + cpsw_ale_add_ucast(gbe_dev->ale, addr, gbe_dev->host_port, 0, 0); + + for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID) + cpsw_ale_add_ucast(gbe_dev->ale, addr, gbe_dev->host_port, + ALE_VLAN, vlan_id); +} + +static void gbe_del_mcast_addr(struct gbe_intf *gbe_intf, u8 *addr) +{ + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + u16 vlan_id; + + cpsw_ale_del_mcast(gbe_dev->ale, addr, 0, 0, 0); + + for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID) { + cpsw_ale_del_mcast(gbe_dev->ale, addr, 0, ALE_VLAN, vlan_id); + } +} + +static void gbe_del_ucast_addr(struct gbe_intf *gbe_intf, u8 *addr) +{ + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + u16 vlan_id; + + cpsw_ale_del_ucast(gbe_dev->ale, addr, gbe_dev->host_port, 0, 0); + + for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID) { + cpsw_ale_del_ucast(gbe_dev->ale, addr, gbe_dev->host_port, + ALE_VLAN, vlan_id); + } +} + +static int gbe_add_addr(void *intf_priv, struct netcp_addr *naddr) +{ + struct gbe_intf *gbe_intf = intf_priv; + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + + dev_dbg(gbe_dev->dev, "ethss adding address %pM, type %d\n", + naddr->addr, naddr->type); + + switch (naddr->type) { + case ADDR_MCAST: + case ADDR_BCAST: + gbe_add_mcast_addr(gbe_intf, naddr->addr); + break; + case ADDR_UCAST: + case ADDR_DEV: + gbe_add_ucast_addr(gbe_intf, naddr->addr); + break; + case ADDR_ANY: + /* nothing to do for promiscuous */ + default: + break; + } + + return 0; +} + +static int gbe_del_addr(void *intf_priv, struct netcp_addr *naddr) +{ + struct gbe_intf *gbe_intf = intf_priv; + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + + dev_dbg(gbe_dev->dev, "ethss deleting address %pM, type %d\n", + naddr->addr, naddr->type); + + switch (naddr->type) { + case ADDR_MCAST: + case ADDR_BCAST: + gbe_del_mcast_addr(gbe_intf, naddr->addr); + break; + case ADDR_UCAST: + case ADDR_DEV: + gbe_del_ucast_addr(gbe_intf, naddr->addr); + break; + case ADDR_ANY: + /* nothing to do for promiscuous */ + default: + break; + } + + return 0; +} + +static int gbe_add_vid(void *intf_priv, int vid) +{ + struct gbe_intf *gbe_intf = intf_priv; + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + + set_bit(vid, gbe_intf->active_vlans); + + cpsw_ale_add_vlan(gbe_dev->ale, vid, + GBE_PORT_MASK(gbe_dev->ale_ports), + GBE_MASK_NO_PORTS, + GBE_PORT_MASK(gbe_dev->ale_ports), + GBE_PORT_MASK(gbe_dev->ale_ports - 1)); + + return 0; +} + +static int gbe_del_vid(void *intf_priv, int vid) +{ + struct gbe_intf *gbe_intf = intf_priv; + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + + cpsw_ale_del_vlan(gbe_dev->ale, vid, 0); + clear_bit(vid, gbe_intf->active_vlans); + return 0; +} + +static int gbe_ioctl(void *intf_priv, struct ifreq *req, int cmd) +{ + struct gbe_intf *gbe_intf = intf_priv; + struct phy_device *phy = gbe_intf->slave->phy; + int ret = -EOPNOTSUPP; + + if (phy) + ret = phy_mii_ioctl(phy, req, cmd); + + return ret; +} + +static void netcp_ethss_timer(unsigned long arg) +{ + struct gbe_priv *gbe_dev = (struct gbe_priv *)arg; + struct gbe_intf *gbe_intf; + struct gbe_slave *slave; + + /* Check & update SGMII link state of interfaces */ + for_each_intf(gbe_intf, gbe_dev) { + if (!gbe_intf->slave->open) + continue; + netcp_ethss_update_link_state(gbe_dev, gbe_intf->slave, + gbe_intf->ndev); + } + + /* Check & update SGMII link state of secondary ports */ + for_each_sec_slave(slave, gbe_dev) { + netcp_ethss_update_link_state(gbe_dev, slave, NULL); + } + + spin_lock_bh(&gbe_dev->hw_stats_lock); + + if (gbe_dev->ss_version == GBE_SS_VERSION_14) + gbe_update_stats_ver14(gbe_dev, NULL); + else + gbe_update_stats(gbe_dev, NULL); + + spin_unlock_bh(&gbe_dev->hw_stats_lock); + + gbe_dev->timer.expires = jiffies + GBE_TIMER_INTERVAL; + add_timer(&gbe_dev->timer); +} + +static int gbe_tx_hook(int order, void *data, struct netcp_packet *p_info) +{ + struct gbe_intf *gbe_intf = data; + + p_info->tx_pipe = &gbe_intf->tx_pipe; + return 0; +} + +static int gbe_open(void *intf_priv, struct net_device *ndev) +{ + struct gbe_intf *gbe_intf = intf_priv; + struct gbe_priv *gbe_dev = gbe_intf->gbe_dev; + struct netcp_intf *netcp = netdev_priv(ndev); + struct gbe_slave *slave = gbe_intf->slave; + int port_num = slave->port_num; + u32 reg; + int ret; + + reg = readl(GBE_REG_ADDR(gbe_dev, switch_regs, id_ver)); + dev_dbg(gbe_dev->dev, "initializing gbe version %d.%d (%d) GBE identification value 0x%x\n", + GBE_MAJOR_VERSION(reg), GBE_MINOR_VERSION(reg), + GBE_RTL_VERSION(reg), GBE_IDENT(reg)); + + if (gbe_dev->enable_ale) + gbe_intf->tx_pipe.dma_psflags = 0; + else + gbe_intf->tx_pipe.dma_psflags = port_num; + + dev_dbg(gbe_dev->dev, "opened TX channel %s: %p with psflags %d\n", + gbe_intf->tx_pipe.dma_chan_name, + gbe_intf->tx_pipe.dma_channel, + gbe_intf->tx_pipe.dma_psflags); + + gbe_slave_stop(gbe_intf); + + /* disable priority elevation and enable statistics on all ports */ + writel(0, GBE_REG_ADDR(gbe_dev, switch_regs, ptype)); + + /* Control register */ + writel(GBE_CTL_P0_ENABLE, GBE_REG_ADDR(gbe_dev, switch_regs, control)); + + /* All statistics enabled and STAT AB visible by default */ + writel(GBE_REG_VAL_STAT_ENABLE_ALL, GBE_REG_ADDR(gbe_dev, switch_regs, + stat_port_en)); + + ret = gbe_slave_open(gbe_intf); + if (ret) + goto fail; + + netcp_register_txhook(netcp, GBE_TXHOOK_ORDER, gbe_tx_hook, + gbe_intf); + + slave->open = true; + netcp_ethss_update_link_state(gbe_dev, slave, ndev); + return 0; + +fail: + gbe_slave_stop(gbe_intf); + return ret; +} + +static int gbe_close(void *intf_priv, struct net_device *ndev) +{ + struct gbe_intf *gbe_intf = intf_priv; + struct netcp_intf *netcp = netdev_priv(ndev); + + gbe_slave_stop(gbe_intf); + netcp_unregister_txhook(netcp, GBE_TXHOOK_ORDER, gbe_tx_hook, + gbe_intf); + + gbe_intf->slave->open = false; + atomic_set(&gbe_intf->slave->link_state, NETCP_LINK_STATE_INVALID); + return 0; +} + +static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, + struct device_node *node) +{ + int port_reg_num; + u32 port_reg_ofs, emac_reg_ofs; + + if (of_property_read_u32(node, "slave-port", &slave->slave_num)) { + dev_err(gbe_dev->dev, "missing slave-port parameter\n"); + return -EINVAL; + } + + if (of_property_read_u32(node, "link-interface", + &slave->link_interface)) { + dev_warn(gbe_dev->dev, + "missing link-interface value defaulting to 1G mac-phy link\n"); + slave->link_interface = SGMII_LINK_MAC_PHY; + } + + slave->open = false; + slave->phy_node = of_parse_phandle(node, "phy-handle", 0); + slave->port_num = gbe_get_slave_port(gbe_dev, slave->slave_num); + + if (slave->link_interface >= XGMII_LINK_MAC_PHY) + slave->mac_control = GBE_DEF_10G_MAC_CONTROL; + else + slave->mac_control = GBE_DEF_1G_MAC_CONTROL; + + /* Emac regs memmap are contiguous but port regs are not */ + port_reg_num = slave->slave_num; + if (gbe_dev->ss_version == GBE_SS_VERSION_14) { + if (slave->slave_num > 1) { + port_reg_ofs = GBE13_SLAVE_PORT2_OFFSET; + port_reg_num -= 2; + } else { + port_reg_ofs = GBE13_SLAVE_PORT_OFFSET; + } + } else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) { + port_reg_ofs = XGBE10_SLAVE_PORT_OFFSET; + } else { + dev_err(gbe_dev->dev, "unknown ethss(0x%x)\n", + gbe_dev->ss_version); + return -EINVAL; + } + + if (gbe_dev->ss_version == GBE_SS_VERSION_14) + emac_reg_ofs = GBE13_EMAC_OFFSET; + else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) + emac_reg_ofs = XGBE10_EMAC_OFFSET; + + slave->port_regs = gbe_dev->ss_regs + port_reg_ofs + + (0x30 * port_reg_num); + slave->emac_regs = gbe_dev->ss_regs + emac_reg_ofs + + (0x40 * slave->slave_num); + + if (gbe_dev->ss_version == GBE_SS_VERSION_14) { + /* Initialize slave port register offsets */ + GBE_SET_REG_OFS(slave, port_regs, port_vlan); + GBE_SET_REG_OFS(slave, port_regs, tx_pri_map); + GBE_SET_REG_OFS(slave, port_regs, sa_lo); + GBE_SET_REG_OFS(slave, port_regs, sa_hi); + GBE_SET_REG_OFS(slave, port_regs, ts_ctl); + GBE_SET_REG_OFS(slave, port_regs, ts_seq_ltype); + GBE_SET_REG_OFS(slave, port_regs, ts_vlan); + GBE_SET_REG_OFS(slave, port_regs, ts_ctl_ltype2); + GBE_SET_REG_OFS(slave, port_regs, ts_ctl2); + + /* Initialize EMAC register offsets */ + GBE_SET_REG_OFS(slave, emac_regs, mac_control); + GBE_SET_REG_OFS(slave, emac_regs, soft_reset); + GBE_SET_REG_OFS(slave, emac_regs, rx_maxlen); + + } else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) { + /* Initialize slave port register offsets */ + XGBE_SET_REG_OFS(slave, port_regs, port_vlan); + XGBE_SET_REG_OFS(slave, port_regs, tx_pri_map); + XGBE_SET_REG_OFS(slave, port_regs, sa_lo); + XGBE_SET_REG_OFS(slave, port_regs, sa_hi); + XGBE_SET_REG_OFS(slave, port_regs, ts_ctl); + XGBE_SET_REG_OFS(slave, port_regs, ts_seq_ltype); + XGBE_SET_REG_OFS(slave, port_regs, ts_vlan); + XGBE_SET_REG_OFS(slave, port_regs, ts_ctl_ltype2); + XGBE_SET_REG_OFS(slave, port_regs, ts_ctl2); + + /* Initialize EMAC register offsets */ + XGBE_SET_REG_OFS(slave, emac_regs, mac_control); + XGBE_SET_REG_OFS(slave, emac_regs, soft_reset); + XGBE_SET_REG_OFS(slave, emac_regs, rx_maxlen); + } + + atomic_set(&slave->link_state, NETCP_LINK_STATE_INVALID); + return 0; +} + +static void init_secondary_ports(struct gbe_priv *gbe_dev, + struct device_node *node) +{ + struct device *dev = gbe_dev->dev; + phy_interface_t phy_mode; + struct gbe_priv **priv; + struct device_node *port; + struct gbe_slave *slave; + bool mac_phy_link = false; + + for_each_child_of_node(node, port) { + slave = devm_kzalloc(dev, sizeof(*slave), GFP_KERNEL); + if (!slave) { + dev_err(dev, + "memomry alloc failed for secondary port(%s), skipping...\n", + port->name); + continue; + } + + if (init_slave(gbe_dev, slave, port)) { + dev_err(dev, + "Failed to initialize secondary port(%s), skipping...\n", + port->name); + devm_kfree(dev, slave); + continue; + } + + gbe_sgmii_config(gbe_dev, slave); + gbe_port_reset(slave); + gbe_port_config(gbe_dev, slave, gbe_dev->rx_packet_max); + list_add_tail(&slave->slave_list, &gbe_dev->secondary_slaves); + gbe_dev->num_slaves++; + if ((slave->link_interface == SGMII_LINK_MAC_PHY) || + (slave->link_interface == XGMII_LINK_MAC_PHY)) + mac_phy_link = true; + + slave->open = true; + } + + /* of_phy_connect() is needed only for MAC-PHY interface */ + if (!mac_phy_link) + return; + + /* Allocate dummy netdev device for attaching to phy device */ + gbe_dev->dummy_ndev = alloc_netdev(sizeof(gbe_dev), "dummy", + NET_NAME_UNKNOWN, ether_setup); + if (!gbe_dev->dummy_ndev) { + dev_err(dev, + "Failed to allocate dummy netdev for secondary ports, skipping phy_connect()...\n"); + return; + } + priv = netdev_priv(gbe_dev->dummy_ndev); + *priv = gbe_dev; + + if (slave->link_interface == SGMII_LINK_MAC_PHY) { + phy_mode = PHY_INTERFACE_MODE_SGMII; + slave->phy_port_t = PORT_MII; + } else { + phy_mode = PHY_INTERFACE_MODE_NA; + slave->phy_port_t = PORT_FIBRE; + } + + for_each_sec_slave(slave, gbe_dev) { + if ((slave->link_interface != SGMII_LINK_MAC_PHY) && + (slave->link_interface != XGMII_LINK_MAC_PHY)) + continue; + slave->phy = + of_phy_connect(gbe_dev->dummy_ndev, + slave->phy_node, + gbe_adjust_link_sec_slaves, + 0, phy_mode); + if (!slave->phy) { + dev_err(dev, "phy not found for slave %d\n", + slave->slave_num); + slave->phy = NULL; + } else { + dev_dbg(dev, "phy found: id is: 0x%s\n", + dev_name(&slave->phy->dev)); + phy_start(slave->phy); + phy_read_status(slave->phy); + } + } +} + +static void free_secondary_ports(struct gbe_priv *gbe_dev) +{ + struct gbe_slave *slave; + + for (;;) { + slave = first_sec_slave(gbe_dev); + if (!slave) + break; + if (slave->phy) + phy_disconnect(slave->phy); + list_del(&slave->slave_list); + } + if (gbe_dev->dummy_ndev) + free_netdev(gbe_dev->dummy_ndev); +} + +static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, + struct device_node *node) +{ + struct resource res; + void __iomem *regs; + int ret, i; + + ret = of_address_to_resource(node, 0, &res); + if (ret) { + dev_err(gbe_dev->dev, "Can't translate of node(%s) address for xgbe subsystem regs\n", + node->name); + return ret; + } + + regs = devm_ioremap_resource(gbe_dev->dev, &res); + if (IS_ERR(regs)) { + dev_err(gbe_dev->dev, "Failed to map xgbe register base\n"); + return PTR_ERR(regs); + } + gbe_dev->ss_regs = regs; + + ret = of_address_to_resource(node, XGBE_SERDES_REG_INDEX, &res); + if (ret) { + dev_err(gbe_dev->dev, "Can't translate of node(%s) address for xgbe serdes regs\n", + node->name); + return ret; + } + + regs = devm_ioremap_resource(gbe_dev->dev, &res); + if (IS_ERR(regs)) { + dev_err(gbe_dev->dev, "Failed to map xgbe serdes register base\n"); + return PTR_ERR(regs); + } + gbe_dev->xgbe_serdes_regs = regs; + + gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, + XGBE10_NUM_STAT_ENTRIES * + (XGBE10_NUM_SLAVES + 1) * sizeof(u64), + GFP_KERNEL); + if (!gbe_dev->hw_stats) { + dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); + return -ENOMEM; + } + + gbe_dev->ss_version = XGBE_SS_VERSION_10; + gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + + XGBE10_SGMII_MODULE_OFFSET; + gbe_dev->switch_regs = gbe_dev->ss_regs + XGBE10_SWITCH_MODULE_OFFSET; + gbe_dev->host_port_regs = gbe_dev->ss_regs + XGBE10_HOST_PORT_OFFSET; + + for (i = 0; i < XGBE10_NUM_HW_STATS_MOD; i++) + gbe_dev->hw_stats_regs[i] = gbe_dev->ss_regs + + XGBE10_HW_STATS_OFFSET + (GBE_HW_STATS_REG_MAP_SZ * i); + + gbe_dev->ale_reg = gbe_dev->ss_regs + XGBE10_ALE_OFFSET; + gbe_dev->ale_ports = XGBE10_NUM_ALE_PORTS; + gbe_dev->host_port = XGBE10_HOST_PORT_NUM; + gbe_dev->ale_entries = XGBE10_NUM_ALE_ENTRIES; + gbe_dev->et_stats = xgbe10_et_stats; + gbe_dev->num_et_stats = ARRAY_SIZE(xgbe10_et_stats); + + /* Subsystem registers */ + XGBE_SET_REG_OFS(gbe_dev, ss_regs, id_ver); + XGBE_SET_REG_OFS(gbe_dev, ss_regs, control); + + /* Switch module registers */ + XGBE_SET_REG_OFS(gbe_dev, switch_regs, id_ver); + XGBE_SET_REG_OFS(gbe_dev, switch_regs, control); + XGBE_SET_REG_OFS(gbe_dev, switch_regs, ptype); + XGBE_SET_REG_OFS(gbe_dev, switch_regs, stat_port_en); + XGBE_SET_REG_OFS(gbe_dev, switch_regs, flow_control); + + /* Host port registers */ + XGBE_SET_REG_OFS(gbe_dev, host_port_regs, port_vlan); + XGBE_SET_REG_OFS(gbe_dev, host_port_regs, tx_pri_map); + XGBE_SET_REG_OFS(gbe_dev, host_port_regs, rx_maxlen); + return 0; +} + +static int get_gbe_resource_version(struct gbe_priv *gbe_dev, + struct device_node *node) +{ + struct resource res; + void __iomem *regs; + int ret; + + ret = of_address_to_resource(node, 0, &res); + if (ret) { + dev_err(gbe_dev->dev, "Can't translate of node(%s) address\n", + node->name); + return ret; + } + + regs = devm_ioremap_resource(gbe_dev->dev, &res); + if (IS_ERR(regs)) { + dev_err(gbe_dev->dev, "Failed to map gbe register base\n"); + return PTR_ERR(regs); + } + gbe_dev->ss_regs = regs; + gbe_dev->ss_version = readl(gbe_dev->ss_regs); + return 0; +} + +static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, + struct device_node *node) +{ + void __iomem *regs; + int i; + + gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, + GBE13_NUM_HW_STAT_ENTRIES * + GBE13_NUM_SLAVES * sizeof(u64), + GFP_KERNEL); + if (!gbe_dev->hw_stats) { + dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); + return -ENOMEM; + } + + regs = gbe_dev->ss_regs; + gbe_dev->sgmii_port_regs = regs + GBE13_SGMII_MODULE_OFFSET; + gbe_dev->sgmii_port34_regs = regs + GBE13_SGMII34_MODULE_OFFSET; + gbe_dev->switch_regs = regs + GBE13_SWITCH_MODULE_OFFSET; + gbe_dev->host_port_regs = regs + GBE13_HOST_PORT_OFFSET; + + for (i = 0; i < GBE13_NUM_HW_STATS_MOD; i++) + gbe_dev->hw_stats_regs[i] = regs + GBE13_HW_STATS_OFFSET + + (GBE_HW_STATS_REG_MAP_SZ * i); + + gbe_dev->ale_reg = regs + GBE13_ALE_OFFSET; + gbe_dev->ale_ports = GBE13_NUM_ALE_PORTS; + gbe_dev->host_port = GBE13_HOST_PORT_NUM; + gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES; + gbe_dev->et_stats = gbe13_et_stats; + gbe_dev->num_et_stats = ARRAY_SIZE(gbe13_et_stats); + + /* Subsystem registers */ + GBE_SET_REG_OFS(gbe_dev, ss_regs, id_ver); + + /* Switch module registers */ + GBE_SET_REG_OFS(gbe_dev, switch_regs, id_ver); + GBE_SET_REG_OFS(gbe_dev, switch_regs, control); + GBE_SET_REG_OFS(gbe_dev, switch_regs, soft_reset); + GBE_SET_REG_OFS(gbe_dev, switch_regs, stat_port_en); + GBE_SET_REG_OFS(gbe_dev, switch_regs, ptype); + GBE_SET_REG_OFS(gbe_dev, switch_regs, flow_control); + + /* Host port registers */ + GBE_SET_REG_OFS(gbe_dev, host_port_regs, port_vlan); + GBE_SET_REG_OFS(gbe_dev, host_port_regs, rx_maxlen); + return 0; +} + +static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, + struct device_node *node, void **inst_priv) +{ + struct device_node *interfaces, *interface; + struct device_node *secondary_ports; + struct cpsw_ale_params ale_params; + struct gbe_priv *gbe_dev; + u32 slave_num; + int ret = 0; + + if (!node) { + dev_err(dev, "device tree info unavailable\n"); + return -ENODEV; + } + + gbe_dev = devm_kzalloc(dev, sizeof(struct gbe_priv), GFP_KERNEL); + if (!gbe_dev) + return -ENOMEM; + + gbe_dev->dev = dev; + gbe_dev->netcp_device = netcp_device; + gbe_dev->rx_packet_max = NETCP_MAX_FRAME_SIZE; + + /* init the hw stats lock */ + spin_lock_init(&gbe_dev->hw_stats_lock); + + if (of_find_property(node, "enable-ale", NULL)) { + gbe_dev->enable_ale = true; + dev_info(dev, "ALE enabled\n"); + } else { + gbe_dev->enable_ale = false; + dev_dbg(dev, "ALE bypass enabled*\n"); + } + + ret = of_property_read_u32(node, "tx-queue", + &gbe_dev->tx_queue_id); + if (ret < 0) { + dev_err(dev, "missing tx_queue parameter\n"); + gbe_dev->tx_queue_id = GBE_TX_QUEUE; + } + + ret = of_property_read_string(node, "tx-channel", + &gbe_dev->dma_chan_name); + if (ret < 0) { + dev_err(dev, "missing \"tx-channel\" parameter\n"); + ret = -ENODEV; + goto quit; + } + + if (!strcmp(node->name, "gbe")) { + ret = get_gbe_resource_version(gbe_dev, node); + if (ret) + goto quit; + + ret = set_gbe_ethss14_priv(gbe_dev, node); + if (ret) + goto quit; + } else if (!strcmp(node->name, "xgbe")) { + ret = set_xgbe_ethss10_priv(gbe_dev, node); + if (ret) + goto quit; + ret = netcp_xgbe_serdes_init(gbe_dev->xgbe_serdes_regs, + gbe_dev->ss_regs); + if (ret) + goto quit; + } else { + dev_err(dev, "unknown GBE node(%s)\n", node->name); + ret = -ENODEV; + goto quit; + } + + interfaces = of_get_child_by_name(node, "interfaces"); + if (!interfaces) + dev_err(dev, "could not find interfaces\n"); + + ret = netcp_txpipe_init(&gbe_dev->tx_pipe, netcp_device, + gbe_dev->dma_chan_name, gbe_dev->tx_queue_id); + if (ret) + goto quit; + + ret = netcp_txpipe_open(&gbe_dev->tx_pipe); + if (ret) + goto quit; + + /* Create network interfaces */ + INIT_LIST_HEAD(&gbe_dev->gbe_intf_head); + for_each_child_of_node(interfaces, interface) { + ret = of_property_read_u32(interface, "slave-port", &slave_num); + if (ret) { + dev_err(dev, "missing slave-port parameter, skipping interface configuration for %s\n", + interface->name); + continue; + } + gbe_dev->num_slaves++; + } + + if (!gbe_dev->num_slaves) + dev_warn(dev, "No network interface configured\n"); + + /* Initialize Secondary slave ports */ + secondary_ports = of_get_child_by_name(node, "secondary-slave-ports"); + INIT_LIST_HEAD(&gbe_dev->secondary_slaves); + if (secondary_ports) + init_secondary_ports(gbe_dev, secondary_ports); + of_node_put(secondary_ports); + + if (!gbe_dev->num_slaves) { + dev_err(dev, "No network interface or secondary ports configured\n"); + ret = -ENODEV; + goto quit; + } + + memset(&ale_params, 0, sizeof(ale_params)); + ale_params.dev = gbe_dev->dev; + ale_params.ale_regs = gbe_dev->ale_reg; + ale_params.ale_ageout = GBE_DEFAULT_ALE_AGEOUT; + ale_params.ale_entries = gbe_dev->ale_entries; + ale_params.ale_ports = gbe_dev->ale_ports; + + gbe_dev->ale = cpsw_ale_create(&ale_params); + if (!gbe_dev->ale) { + dev_err(gbe_dev->dev, "error initializing ale engine\n"); + ret = -ENODEV; + goto quit; + } else { + dev_dbg(gbe_dev->dev, "Created a gbe ale engine\n"); + } + + /* initialize host port */ + gbe_init_host_port(gbe_dev); + + init_timer(&gbe_dev->timer); + gbe_dev->timer.data = (unsigned long)gbe_dev; + gbe_dev->timer.function = netcp_ethss_timer; + gbe_dev->timer.expires = jiffies + GBE_TIMER_INTERVAL; + add_timer(&gbe_dev->timer); + *inst_priv = gbe_dev; + return 0; + +quit: + if (gbe_dev->hw_stats) + devm_kfree(dev, gbe_dev->hw_stats); + cpsw_ale_destroy(gbe_dev->ale); + if (gbe_dev->ss_regs) + devm_iounmap(dev, gbe_dev->ss_regs); + of_node_put(interfaces); + devm_kfree(dev, gbe_dev); + return ret; +} + +static int gbe_attach(void *inst_priv, struct net_device *ndev, + struct device_node *node, void **intf_priv) +{ + struct gbe_priv *gbe_dev = inst_priv; + struct gbe_intf *gbe_intf; + int ret; + + if (!node) { + dev_err(gbe_dev->dev, "interface node not available\n"); + return -ENODEV; + } + + gbe_intf = devm_kzalloc(gbe_dev->dev, sizeof(*gbe_intf), GFP_KERNEL); + if (!gbe_intf) + return -ENOMEM; + + gbe_intf->ndev = ndev; + gbe_intf->dev = gbe_dev->dev; + gbe_intf->gbe_dev = gbe_dev; + + gbe_intf->slave = devm_kzalloc(gbe_dev->dev, + sizeof(*gbe_intf->slave), + GFP_KERNEL); + if (!gbe_intf->slave) { + ret = -ENOMEM; + goto fail; + } + + if (init_slave(gbe_dev, gbe_intf->slave, node)) { + ret = -ENODEV; + goto fail; + } + + gbe_intf->tx_pipe = gbe_dev->tx_pipe; + ndev->ethtool_ops = &keystone_ethtool_ops; + list_add_tail(&gbe_intf->gbe_intf_list, &gbe_dev->gbe_intf_head); + *intf_priv = gbe_intf; + return 0; + +fail: + if (gbe_intf->slave) + devm_kfree(gbe_dev->dev, gbe_intf->slave); + if (gbe_intf) + devm_kfree(gbe_dev->dev, gbe_intf); + return ret; +} + +static int gbe_release(void *intf_priv) +{ + struct gbe_intf *gbe_intf = intf_priv; + + gbe_intf->ndev->ethtool_ops = NULL; + list_del(&gbe_intf->gbe_intf_list); + devm_kfree(gbe_intf->dev, gbe_intf->slave); + devm_kfree(gbe_intf->dev, gbe_intf); + return 0; +} + +static int gbe_remove(struct netcp_device *netcp_device, void *inst_priv) +{ + struct gbe_priv *gbe_dev = inst_priv; + + del_timer_sync(&gbe_dev->timer); + cpsw_ale_stop(gbe_dev->ale); + cpsw_ale_destroy(gbe_dev->ale); + netcp_txpipe_close(&gbe_dev->tx_pipe); + free_secondary_ports(gbe_dev); + + if (!list_empty(&gbe_dev->gbe_intf_head)) + dev_alert(gbe_dev->dev, "unreleased ethss interfaces present\n"); + + devm_kfree(gbe_dev->dev, gbe_dev->hw_stats); + devm_iounmap(gbe_dev->dev, gbe_dev->ss_regs); + memset(gbe_dev, 0x00, sizeof(*gbe_dev)); + devm_kfree(gbe_dev->dev, gbe_dev); + return 0; +} + +static struct netcp_module gbe_module = { + .name = GBE_MODULE_NAME, + .owner = THIS_MODULE, + .primary = true, + .probe = gbe_probe, + .open = gbe_open, + .close = gbe_close, + .remove = gbe_remove, + .attach = gbe_attach, + .release = gbe_release, + .add_addr = gbe_add_addr, + .del_addr = gbe_del_addr, + .add_vid = gbe_add_vid, + .del_vid = gbe_del_vid, + .ioctl = gbe_ioctl, +}; + +static struct netcp_module xgbe_module = { + .name = XGBE_MODULE_NAME, + .owner = THIS_MODULE, + .primary = true, + .probe = gbe_probe, + .open = gbe_open, + .close = gbe_close, + .remove = gbe_remove, + .attach = gbe_attach, + .release = gbe_release, + .add_addr = gbe_add_addr, + .del_addr = gbe_del_addr, + .add_vid = gbe_add_vid, + .del_vid = gbe_del_vid, + .ioctl = gbe_ioctl, +}; + +static int __init keystone_gbe_init(void) +{ + int ret; + + ret = netcp_register_module(&gbe_module); + if (ret) + return ret; + + ret = netcp_register_module(&xgbe_module); + if (ret) + return ret; + + return 0; +} +module_init(keystone_gbe_init); + +static void __exit keystone_gbe_exit(void) +{ + netcp_unregister_module(&gbe_module); + netcp_unregister_module(&xgbe_module); +} +module_exit(keystone_gbe_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TI NETCP ETHSS driver for Keystone SOCs"); +MODULE_AUTHOR("Sandeep Nair + * Sandeep Paulraj + * Wingman Kwok + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "netcp.h" + +#define SGMII_REG_STATUS_LOCK BIT(4) +#define SGMII_REG_STATUS_LINK BIT(0) +#define SGMII_REG_STATUS_AUTONEG BIT(2) +#define SGMII_REG_CONTROL_AUTONEG BIT(0) + +#define SGMII23_OFFSET(x) ((x - 2) * 0x100) +#define SGMII_OFFSET(x) ((x <= 1) ? (x * 0x100) : (SGMII23_OFFSET(x))) + +/* SGMII registers */ +#define SGMII_SRESET_REG(x) (SGMII_OFFSET(x) + 0x004) +#define SGMII_CTL_REG(x) (SGMII_OFFSET(x) + 0x010) +#define SGMII_STATUS_REG(x) (SGMII_OFFSET(x) + 0x014) +#define SGMII_MRADV_REG(x) (SGMII_OFFSET(x) + 0x018) + +static void sgmii_write_reg(void __iomem *base, int reg, u32 val) +{ + writel(val, base + reg); +} + +static u32 sgmii_read_reg(void __iomem *base, int reg) +{ + return readl(base + reg); +} + +static void sgmii_write_reg_bit(void __iomem *base, int reg, u32 val) +{ + writel((readl(base + reg) | val), base + reg); +} + +/* port is 0 based */ +int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port) +{ + /* Soft reset */ + sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port), 0x1); + while (sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) != 0x0) + ; + return 0; +} + +int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port) +{ + u32 status = 0, link = 0; + + status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); + if ((status & SGMII_REG_STATUS_LINK) != 0) + link = 1; + return link; +} + +int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface) +{ + unsigned int i, status, mask; + u32 mr_adv_ability; + u32 control; + + switch (interface) { + case SGMII_LINK_MAC_MAC_AUTONEG: + mr_adv_ability = 0x9801; + control = 0x21; + break; + + case SGMII_LINK_MAC_PHY: + case SGMII_LINK_MAC_PHY_NO_MDIO: + mr_adv_ability = 1; + control = 1; + break; + + case SGMII_LINK_MAC_MAC_FORCED: + mr_adv_ability = 0x9801; + control = 0x20; + break; + + case SGMII_LINK_MAC_FIBER: + mr_adv_ability = 0x20; + control = 0x1; + break; + + default: + WARN_ONCE(1, "Invalid sgmii interface: %d\n", interface); + return -EINVAL; + } + + sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), 0); + + /* Wait for the SerDes pll to lock */ + for (i = 0; i < 1000; i++) { + usleep_range(1000, 2000); + status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); + if ((status & SGMII_REG_STATUS_LOCK) != 0) + break; + } + + if ((status & SGMII_REG_STATUS_LOCK) == 0) + pr_err("serdes PLL not locked\n"); + + sgmii_write_reg(sgmii_ofs, SGMII_MRADV_REG(port), mr_adv_ability); + sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), control); + + mask = SGMII_REG_STATUS_LINK; + if (control & SGMII_REG_CONTROL_AUTONEG) + mask |= SGMII_REG_STATUS_AUTONEG; + + for (i = 0; i < 1000; i++) { + usleep_range(200, 500); + status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); + if ((status & mask) == mask) + break; + } + + return 0; +} diff --git a/drivers/net/ethernet/ti/netcp_xgbepcsr.c b/drivers/net/ethernet/ti/netcp_xgbepcsr.c new file mode 100644 index 000000000000..33571acc52b6 --- /dev/null +++ b/drivers/net/ethernet/ti/netcp_xgbepcsr.c @@ -0,0 +1,501 @@ +/* + * XGE PCSR module initialisation + * + * Copyright (C) 2014 Texas Instruments Incorporated + * Authors: Sandeep Nair + * WingMan Kwok + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "netcp.h" + +/* XGBE registers */ +#define XGBE_CTRL_OFFSET 0x0c +#define XGBE_SGMII_1_OFFSET 0x0114 +#define XGBE_SGMII_2_OFFSET 0x0214 + +/* PCS-R registers */ +#define PCSR_CPU_CTRL_OFFSET 0x1fd0 +#define POR_EN BIT(29) + +#define reg_rmw(addr, value, mask) \ + writel(((readl(addr) & (~(mask))) | \ + (value & (mask))), (addr)) + +/* bit mask of width w at offset s */ +#define MASK_WID_SH(w, s) (((1 << w) - 1) << s) + +/* shift value v to offset s */ +#define VAL_SH(v, s) (v << s) + +#define PHY_A(serdes) 0 + +struct serdes_cfg { + u32 ofs; + u32 val; + u32 mask; +}; + +static struct serdes_cfg cfg_phyb_1p25g_156p25mhz_cmu0[] = { + {0x0000, 0x00800002, 0x00ff00ff}, + {0x0014, 0x00003838, 0x0000ffff}, + {0x0060, 0x1c44e438, 0xffffffff}, + {0x0064, 0x00c18400, 0x00ffffff}, + {0x0068, 0x17078200, 0xffffff00}, + {0x006c, 0x00000014, 0x000000ff}, + {0x0078, 0x0000c000, 0x0000ff00}, + {0x0000, 0x00000003, 0x000000ff}, +}; + +static struct serdes_cfg cfg_phyb_10p3125g_156p25mhz_cmu1[] = { + {0x0c00, 0x00030002, 0x00ff00ff}, + {0x0c14, 0x00005252, 0x0000ffff}, + {0x0c28, 0x80000000, 0xff000000}, + {0x0c2c, 0x000000f6, 0x000000ff}, + {0x0c3c, 0x04000405, 0xff00ffff}, + {0x0c40, 0xc0800000, 0xffff0000}, + {0x0c44, 0x5a202062, 0xffffffff}, + {0x0c48, 0x40040424, 0xffffffff}, + {0x0c4c, 0x00004002, 0x0000ffff}, + {0x0c50, 0x19001c00, 0xff00ff00}, + {0x0c54, 0x00002100, 0x0000ff00}, + {0x0c58, 0x00000060, 0x000000ff}, + {0x0c60, 0x80131e7c, 0xffffffff}, + {0x0c64, 0x8400cb02, 0xff00ffff}, + {0x0c68, 0x17078200, 0xffffff00}, + {0x0c6c, 0x00000016, 0x000000ff}, + {0x0c74, 0x00000400, 0x0000ff00}, + {0x0c78, 0x0000c000, 0x0000ff00}, + {0x0c00, 0x00000003, 0x000000ff}, +}; + +static struct serdes_cfg cfg_phyb_10p3125g_16bit_lane[] = { + {0x0204, 0x00000080, 0x000000ff}, + {0x0208, 0x0000920d, 0x0000ffff}, + {0x0204, 0xfc000000, 0xff000000}, + {0x0208, 0x00009104, 0x0000ffff}, + {0x0210, 0x1a000000, 0xff000000}, + {0x0214, 0x00006b58, 0x00ffffff}, + {0x0218, 0x75800084, 0xffff00ff}, + {0x022c, 0x00300000, 0x00ff0000}, + {0x0230, 0x00003800, 0x0000ff00}, + {0x024c, 0x008f0000, 0x00ff0000}, + {0x0250, 0x30000000, 0xff000000}, + {0x0260, 0x00000002, 0x000000ff}, + {0x0264, 0x00000057, 0x000000ff}, + {0x0268, 0x00575700, 0x00ffff00}, + {0x0278, 0xff000000, 0xff000000}, + {0x0280, 0x00500050, 0x00ff00ff}, + {0x0284, 0x00001f15, 0x0000ffff}, + {0x028c, 0x00006f00, 0x0000ff00}, + {0x0294, 0x00000000, 0xffffff00}, + {0x0298, 0x00002640, 0xff00ffff}, + {0x029c, 0x00000003, 0x000000ff}, + {0x02a4, 0x00000f13, 0x0000ffff}, + {0x02a8, 0x0001b600, 0x00ffff00}, + {0x0380, 0x00000030, 0x000000ff}, + {0x03c0, 0x00000200, 0x0000ff00}, + {0x03cc, 0x00000018, 0x000000ff}, + {0x03cc, 0x00000000, 0x000000ff}, +}; + +static struct serdes_cfg cfg_phyb_10p3125g_comlane[] = { + {0x0a00, 0x00000800, 0x0000ff00}, + {0x0a84, 0x00000000, 0x000000ff}, + {0x0a8c, 0x00130000, 0x00ff0000}, + {0x0a90, 0x77a00000, 0xffff0000}, + {0x0a94, 0x00007777, 0x0000ffff}, + {0x0b08, 0x000f0000, 0xffff0000}, + {0x0b0c, 0x000f0000, 0x00ffffff}, + {0x0b10, 0xbe000000, 0xff000000}, + {0x0b14, 0x000000ff, 0x000000ff}, + {0x0b18, 0x00000014, 0x000000ff}, + {0x0b5c, 0x981b0000, 0xffff0000}, + {0x0b64, 0x00001100, 0x0000ff00}, + {0x0b78, 0x00000c00, 0x0000ff00}, + {0x0abc, 0xff000000, 0xff000000}, + {0x0ac0, 0x0000008b, 0x000000ff}, +}; + +static struct serdes_cfg cfg_cm_c1_c2[] = { + {0x0208, 0x00000000, 0x00000f00}, + {0x0208, 0x00000000, 0x0000001f}, + {0x0204, 0x00000000, 0x00040000}, + {0x0208, 0x000000a0, 0x000000e0}, +}; + +static void netcp_xgbe_serdes_cmu_init(void __iomem *serdes_regs) +{ + int i; + + /* cmu0 setup */ + for (i = 0; i < ARRAY_SIZE(cfg_phyb_1p25g_156p25mhz_cmu0); i++) { + reg_rmw(serdes_regs + cfg_phyb_1p25g_156p25mhz_cmu0[i].ofs, + cfg_phyb_1p25g_156p25mhz_cmu0[i].val, + cfg_phyb_1p25g_156p25mhz_cmu0[i].mask); + } + + /* cmu1 setup */ + for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_156p25mhz_cmu1); i++) { + reg_rmw(serdes_regs + cfg_phyb_10p3125g_156p25mhz_cmu1[i].ofs, + cfg_phyb_10p3125g_156p25mhz_cmu1[i].val, + cfg_phyb_10p3125g_156p25mhz_cmu1[i].mask); + } +} + +/* lane is 0 based */ +static void netcp_xgbe_serdes_lane_config( + void __iomem *serdes_regs, int lane) +{ + int i; + + /* lane setup */ + for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_16bit_lane); i++) { + reg_rmw(serdes_regs + + cfg_phyb_10p3125g_16bit_lane[i].ofs + + (0x200 * lane), + cfg_phyb_10p3125g_16bit_lane[i].val, + cfg_phyb_10p3125g_16bit_lane[i].mask); + } + + /* disable auto negotiation*/ + reg_rmw(serdes_regs + (0x200 * lane) + 0x0380, + 0x00000000, 0x00000010); + + /* disable link training */ + reg_rmw(serdes_regs + (0x200 * lane) + 0x03c0, + 0x00000000, 0x00000200); +} + +static void netcp_xgbe_serdes_com_enable(void __iomem *serdes_regs) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_comlane); i++) { + reg_rmw(serdes_regs + cfg_phyb_10p3125g_comlane[i].ofs, + cfg_phyb_10p3125g_comlane[i].val, + cfg_phyb_10p3125g_comlane[i].mask); + } +} + +static void netcp_xgbe_serdes_lane_enable( + void __iomem *serdes_regs, int lane) +{ + /* Set Lane Control Rate */ + writel(0xe0e9e038, serdes_regs + 0x1fe0 + (4 * lane)); +} + +static void netcp_xgbe_serdes_phyb_rst_clr(void __iomem *serdes_regs) +{ + reg_rmw(serdes_regs + 0x0a00, 0x0000001f, 0x000000ff); +} + +static void netcp_xgbe_serdes_pll_disable(void __iomem *serdes_regs) +{ + writel(0x88000000, serdes_regs + 0x1ff4); +} + +static void netcp_xgbe_serdes_pll_enable(void __iomem *serdes_regs) +{ + netcp_xgbe_serdes_phyb_rst_clr(serdes_regs); + writel(0xee000000, serdes_regs + 0x1ff4); +} + +static int netcp_xgbe_wait_pll_locked(void __iomem *sw_regs) +{ + unsigned long timeout; + int ret = 0; + u32 val_1, val_0; + + timeout = jiffies + msecs_to_jiffies(500); + do { + val_0 = (readl(sw_regs + XGBE_SGMII_1_OFFSET) & BIT(4)); + val_1 = (readl(sw_regs + XGBE_SGMII_2_OFFSET) & BIT(4)); + + if (val_1 && val_0) + return 0; + + if (time_after(jiffies, timeout)) { + ret = -ETIMEDOUT; + break; + } + + cpu_relax(); + } while (true); + + pr_err("XGBE serdes not locked: time out.\n"); + return ret; +} + +static void netcp_xgbe_serdes_enable_xgmii_port(void __iomem *sw_regs) +{ + writel(0x03, sw_regs + XGBE_CTRL_OFFSET); +} + +static u32 netcp_xgbe_serdes_read_tbus_val(void __iomem *serdes_regs) +{ + u32 tmp; + + if (PHY_A(serdes_regs)) { + tmp = (readl(serdes_regs + 0x0ec) >> 24) & 0x0ff; + tmp |= ((readl(serdes_regs + 0x0fc) >> 16) & 0x00f00); + } else { + tmp = (readl(serdes_regs + 0x0f8) >> 16) & 0x0fff; + } + + return tmp; +} + +static void netcp_xgbe_serdes_write_tbus_addr(void __iomem *serdes_regs, + int select, int ofs) +{ + if (PHY_A(serdes_regs)) { + reg_rmw(serdes_regs + 0x0008, ((select << 5) + ofs) << 24, + ~0x00ffffff); + return; + } + + /* For 2 lane Phy-B, lane0 is actually lane1 */ + switch (select) { + case 1: + select = 2; + break; + case 2: + select = 3; + break; + default: + return; + } + + reg_rmw(serdes_regs + 0x00fc, ((select << 8) + ofs) << 16, ~0xf800ffff); +} + +static u32 netcp_xgbe_serdes_read_select_tbus(void __iomem *serdes_regs, + int select, int ofs) +{ + /* Set tbus address */ + netcp_xgbe_serdes_write_tbus_addr(serdes_regs, select, ofs); + /* Get TBUS Value */ + return netcp_xgbe_serdes_read_tbus_val(serdes_regs); +} + +static void netcp_xgbe_serdes_reset_cdr(void __iomem *serdes_regs, + void __iomem *sig_detect_reg, int lane) +{ + u32 tmp, dlpf, tbus; + + /*Get the DLPF values */ + tmp = netcp_xgbe_serdes_read_select_tbus( + serdes_regs, lane + 1, 5); + + dlpf = tmp >> 2; + + if (dlpf < 400 || dlpf > 700) { + reg_rmw(sig_detect_reg, VAL_SH(2, 1), MASK_WID_SH(2, 1)); + mdelay(1); + reg_rmw(sig_detect_reg, VAL_SH(0, 1), MASK_WID_SH(2, 1)); + } else { + tbus = netcp_xgbe_serdes_read_select_tbus(serdes_regs, lane + + 1, 0xe); + + pr_debug("XGBE: CDR centered, DLPF: %4d,%d,%d.\n", + tmp >> 2, tmp & 3, (tbus >> 2) & 3); + } +} + +/* Call every 100 ms */ +static int netcp_xgbe_check_link_status(void __iomem *serdes_regs, + void __iomem *sw_regs, u32 lanes, + u32 *current_state, u32 *lane_down) +{ + void __iomem *pcsr_base = sw_regs + 0x0600; + void __iomem *sig_detect_reg; + u32 pcsr_rx_stat, blk_lock, blk_errs; + int loss, i, status = 1; + + for (i = 0; i < lanes; i++) { + /* Get the Loss bit */ + loss = readl(serdes_regs + 0x1fc0 + 0x20 + (i * 0x04)) & 0x1; + + /* Get Block Errors and Block Lock bits */ + pcsr_rx_stat = readl(pcsr_base + 0x0c + (i * 0x80)); + blk_lock = (pcsr_rx_stat >> 30) & 0x1; + blk_errs = (pcsr_rx_stat >> 16) & 0x0ff; + + /* Get Signal Detect Overlay Address */ + sig_detect_reg = serdes_regs + (i * 0x200) + 0x200 + 0x04; + + /* If Block errors maxed out, attempt recovery! */ + if (blk_errs == 0x0ff) + blk_lock = 0; + + switch (current_state[i]) { + case 0: + /* if good link lock the signal detect ON! */ + if (!loss && blk_lock) { + pr_debug("XGBE PCSR Linked Lane: %d\n", i); + reg_rmw(sig_detect_reg, VAL_SH(3, 1), + MASK_WID_SH(2, 1)); + current_state[i] = 1; + } else if (!blk_lock) { + /* if no lock, then reset CDR */ + pr_debug("XGBE PCSR Recover Lane: %d\n", i); + netcp_xgbe_serdes_reset_cdr(serdes_regs, + sig_detect_reg, i); + } + break; + + case 1: + if (!blk_lock) { + /* Link Lost? */ + lane_down[i] = 1; + current_state[i] = 2; + } + break; + + case 2: + if (blk_lock) + /* Nope just noise */ + current_state[i] = 1; + else { + /* Lost the block lock, reset CDR if it is + * not centered and go back to sync state + */ + netcp_xgbe_serdes_reset_cdr(serdes_regs, + sig_detect_reg, i); + current_state[i] = 0; + } + break; + + default: + pr_err("XGBE: unknown current_state[%d] %d\n", + i, current_state[i]); + break; + } + + if (blk_errs > 0) { + /* Reset the Error counts! */ + reg_rmw(pcsr_base + 0x08 + (i * 0x80), VAL_SH(0x19, 0), + MASK_WID_SH(8, 0)); + + reg_rmw(pcsr_base + 0x08 + (i * 0x80), VAL_SH(0x00, 0), + MASK_WID_SH(8, 0)); + } + + status &= (current_state[i] == 1); + } + + return status; +} + +static int netcp_xgbe_serdes_check_lane(void __iomem *serdes_regs, + void __iomem *sw_regs) +{ + u32 current_state[2] = {0, 0}; + int retries = 0, link_up; + u32 lane_down[2]; + + do { + lane_down[0] = 0; + lane_down[1] = 0; + + link_up = netcp_xgbe_check_link_status(serdes_regs, sw_regs, 2, + current_state, + lane_down); + + /* if we did not get link up then wait 100ms before calling + * it again + */ + if (link_up) + break; + + if (lane_down[0]) + pr_debug("XGBE: detected link down on lane 0\n"); + + if (lane_down[1]) + pr_debug("XGBE: detected link down on lane 1\n"); + + if (++retries > 1) { + pr_debug("XGBE: timeout waiting for serdes link up\n"); + return -ETIMEDOUT; + } + mdelay(100); + } while (!link_up); + + pr_debug("XGBE: PCSR link is up\n"); + return 0; +} + +static void netcp_xgbe_serdes_setup_cm_c1_c2(void __iomem *serdes_regs, + int lane, int cm, int c1, int c2) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cfg_cm_c1_c2); i++) { + reg_rmw(serdes_regs + cfg_cm_c1_c2[i].ofs + (0x200 * lane), + cfg_cm_c1_c2[i].val, + cfg_cm_c1_c2[i].mask); + } +} + +static void netcp_xgbe_reset_serdes(void __iomem *serdes_regs) +{ + /* Toggle the POR_EN bit in CONFIG.CPU_CTRL */ + /* enable POR_EN bit */ + reg_rmw(serdes_regs + PCSR_CPU_CTRL_OFFSET, POR_EN, POR_EN); + usleep_range(10, 100); + + /* disable POR_EN bit */ + reg_rmw(serdes_regs + PCSR_CPU_CTRL_OFFSET, 0, POR_EN); + usleep_range(10, 100); +} + +static int netcp_xgbe_serdes_config(void __iomem *serdes_regs, + void __iomem *sw_regs) +{ + u32 ret, i; + + netcp_xgbe_serdes_pll_disable(serdes_regs); + netcp_xgbe_serdes_cmu_init(serdes_regs); + + for (i = 0; i < 2; i++) + netcp_xgbe_serdes_lane_config(serdes_regs, i); + + netcp_xgbe_serdes_com_enable(serdes_regs); + /* This is EVM + RTM-BOC specific */ + for (i = 0; i < 2; i++) + netcp_xgbe_serdes_setup_cm_c1_c2(serdes_regs, i, 0, 0, 5); + + netcp_xgbe_serdes_pll_enable(serdes_regs); + for (i = 0; i < 2; i++) + netcp_xgbe_serdes_lane_enable(serdes_regs, i); + + /* SB PLL Status Poll */ + ret = netcp_xgbe_wait_pll_locked(sw_regs); + if (ret) + return ret; + + netcp_xgbe_serdes_enable_xgmii_port(sw_regs); + netcp_xgbe_serdes_check_lane(serdes_regs, sw_regs); + return ret; +} + +int netcp_xgbe_serdes_init(void __iomem *serdes_regs, void __iomem *xgbe_regs) +{ + u32 val; + + /* read COMLANE bits 4:0 */ + val = readl(serdes_regs + 0xa00); + if (val & 0x1f) { + pr_debug("XGBE: serdes already in operation - reset\n"); + netcp_xgbe_reset_serdes(serdes_regs); + } + return netcp_xgbe_serdes_config(serdes_regs, xgbe_regs); +} diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c index f2ff0074aac9..691ec936e88d 100644 --- a/drivers/net/ethernet/ti/tlan.c +++ b/drivers/net/ethernet/ti/tlan.c @@ -2540,7 +2540,7 @@ static void tlan_phy_power_down(struct net_device *dev) * This is abitrary. It is intended to make sure the * transceiver settles. */ - tlan_set_timer(dev, (HZ/20), TLAN_TIMER_PHY_PUP); + tlan_set_timer(dev, msecs_to_jiffies(50), TLAN_TIMER_PHY_PUP); } @@ -2561,7 +2561,7 @@ static void tlan_phy_power_up(struct net_device *dev) * transceiver. The TLAN docs say both 50 ms and * 500 ms, so do the longer, just in case. */ - tlan_set_timer(dev, (HZ/20), TLAN_TIMER_PHY_RESET); + tlan_set_timer(dev, msecs_to_jiffies(500), TLAN_TIMER_PHY_RESET); } @@ -2593,7 +2593,7 @@ static void tlan_phy_reset(struct net_device *dev) * I don't remember why I wait this long. * I've changed this to 50ms, as it seems long enough. */ - tlan_set_timer(dev, (HZ/20), TLAN_TIMER_PHY_START_LINK); + tlan_set_timer(dev, msecs_to_jiffies(50), TLAN_TIMER_PHY_START_LINK); } @@ -2658,7 +2658,7 @@ static void tlan_phy_start_link(struct net_device *dev) data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; tlan_dio_write16(dev->base_addr, TLAN_NET_CONFIG, data); - tlan_set_timer(dev, (40*HZ/1000), TLAN_TIMER_PHY_PDOWN); + tlan_set_timer(dev, msecs_to_jiffies(40), TLAN_TIMER_PHY_PDOWN); return; } else if (priv->phy_num == 0) { control = 0; @@ -2725,7 +2725,7 @@ static void tlan_phy_finish_auto_neg(struct net_device *dev) (priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10) && (priv->phy_num != 0)) { priv->phy_num = 0; - tlan_set_timer(dev, (400*HZ/1000), TLAN_TIMER_PHY_PDOWN); + tlan_set_timer(dev, msecs_to_jiffies(400), TLAN_TIMER_PHY_PDOWN); return; } @@ -2744,7 +2744,7 @@ static void tlan_phy_finish_auto_neg(struct net_device *dev) /* Wait for 100 ms. No reason in partiticular. */ - tlan_set_timer(dev, (HZ/10), TLAN_TIMER_FINISH_RESET); + tlan_set_timer(dev, msecs_to_jiffies(100), TLAN_TIMER_FINISH_RESET); } @@ -2796,7 +2796,7 @@ static void tlan_phy_monitor(unsigned long data) /* set to external PHY */ priv->phy_num = 1; /* restart autonegotiation */ - tlan_set_timer(dev, 4 * HZ / 10, + tlan_set_timer(dev, msecs_to_jiffies(400), TLAN_TIMER_PHY_PDOWN); return; } diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index a191afc23b56..17e276651601 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -1326,7 +1326,8 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; - mii_check_media(&rp->mii_if, netif_msg_link(rp), init_media); + if (!rp->mii_if.force_media) + mii_check_media(&rp->mii_if, netif_msg_link(rp), init_media); if (rp->mii_if.full_duplex) iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1FDuplex, @@ -1781,8 +1782,8 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb, rp->tx_ring[entry].desc_length = cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); - if (unlikely(vlan_tx_tag_present(skb))) { - u16 vid_pcp = vlan_tx_tag_get(skb); + if (unlikely(skb_vlan_tag_present(skb))) { + u16 vid_pcp = skb_vlan_tag_get(skb); /* drop CFI/DEI bit, register needs VID and PCP */ vid_pcp = (vid_pcp & VLAN_VID_MASK) | @@ -1803,7 +1804,7 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb, /* Non-x86 Todo: explicitly flush cache lines here. */ - if (vlan_tx_tag_present(skb)) + if (skb_vlan_tag_present(skb)) /* Tx queues are bits 7-0 (first Tx queue: bit 7) */ BYTE_REG_BITS_ON(1 << 7, ioaddr + TQWake); diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c index 282f83a63b67..c20206f83cc1 100644 --- a/drivers/net/ethernet/via/via-velocity.c +++ b/drivers/net/ethernet/via/via-velocity.c @@ -2611,8 +2611,8 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16; - if (vlan_tx_tag_present(skb)) { - td_ptr->tdesc1.vlan = cpu_to_le16(vlan_tx_tag_get(skb)); + if (skb_vlan_tag_present(skb)) { + td_ptr->tdesc1.vlan = cpu_to_le16(skb_vlan_tag_get(skb)); td_ptr->tdesc1.TCR |= TCR0_VETAG; } diff --git a/drivers/net/fddi/skfp/smt.c b/drivers/net/fddi/skfp/smt.c index 9edada85ed02..cd78b7cacc75 100644 --- a/drivers/net/fddi/skfp/smt.c +++ b/drivers/net/fddi/skfp/smt.c @@ -1736,18 +1736,6 @@ char *addr_to_string(struct fddi_addr *addr) } #endif -#ifdef AM29K -int smt_ifconfig(int argc, char *argv[]) -{ - if (argc >= 2 && !strcmp(argv[0],"opt_bypass") && - !strcmp(argv[1],"yes")) { - smc->mib.fddiSMTBypassPresent = 1 ; - return 0; - } - return amdfddi_config(0, argc, argv); -} -#endif - /* * return static mac index */ diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 9f49c0129a78..208eb05446ba 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -217,7 +217,7 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device) static int netvsc_init_buf(struct hv_device *device) { int ret = 0; - int t; + unsigned long t; struct netvsc_device *net_device; struct nvsp_message *init_packet; struct net_device *ndev; @@ -409,7 +409,8 @@ static int negotiate_nvsp_ver(struct hv_device *device, struct nvsp_message *init_packet, u32 nvsp_ver) { - int ret, t; + int ret; + unsigned long t; memset(init_packet, 0, sizeof(struct nvsp_message)); init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT; @@ -684,9 +685,9 @@ static u32 netvsc_get_next_send_section(struct netvsc_device *net_device) return ret_val; } -u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device, - unsigned int section_index, - struct hv_netvsc_packet *packet) +static u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device, + unsigned int section_index, + struct hv_netvsc_packet *packet) { char *start = net_device->send_buf; char *dest = (start + (section_index * net_device->send_section_size)); @@ -716,7 +717,7 @@ int netvsc_send(struct hv_device *device, u64 req_id; unsigned int section_index = NETVSC_INVALID_INDEX; u32 msg_size = 0; - struct sk_buff *skb; + struct sk_buff *skb = NULL; u16 q_idx = packet->q_idx; @@ -743,8 +744,6 @@ int netvsc_send(struct hv_device *device, packet); skb = (struct sk_buff *) (unsigned long)packet->send_completion_tid; - if (skb) - dev_kfree_skb_any(skb); packet->page_buf_cnt = 0; } } @@ -810,6 +809,13 @@ int netvsc_send(struct hv_device *device, packet, ret); } + if (ret != 0) { + if (section_index != NETVSC_INVALID_INDEX) + netvsc_free_send_slot(net_device, section_index); + } else if (skb) { + dev_kfree_skb_any(skb); + } + return ret; } diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index ec0c40a8f653..7816d98bdddc 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -470,7 +470,7 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, struct rndis_query_request *query; struct rndis_query_complete *query_complete; int ret = 0; - int t; + unsigned long t; if (!result) return -EINVAL; @@ -560,7 +560,8 @@ int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac) char macstr[2*ETH_ALEN+1]; u32 extlen = sizeof(struct rndis_config_parameter_info) + 2*NWADR_STRLEN + 4*ETH_ALEN; - int ret, t; + int ret; + unsigned long t; request = get_rndis_request(rdev, RNDIS_MSG_SET, RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen); @@ -623,7 +624,8 @@ cleanup: return ret; } -int rndis_filter_set_offload_params(struct hv_device *hdev, +static int +rndis_filter_set_offload_params(struct hv_device *hdev, struct ndis_offload_params *req_offloads) { struct netvsc_device *nvdev = hv_get_drvdata(hdev); @@ -634,7 +636,8 @@ int rndis_filter_set_offload_params(struct hv_device *hdev, struct ndis_offload_params *offload_params; struct rndis_set_complete *set_complete; u32 extlen = sizeof(struct ndis_offload_params); - int ret, t; + int ret; + unsigned long t; u32 vsp_version = nvdev->nvsp_version; if (vsp_version <= NVSP_PROTOCOL_VERSION_4) { @@ -697,7 +700,7 @@ u8 netvsc_hash_key[HASH_KEYLEN] = { 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa }; -int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue) +static int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue) { struct net_device *ndev = rdev->net_dev->ndev; struct rndis_request *request; @@ -708,7 +711,8 @@ int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue) struct ndis_recv_scale_param *rssp; u32 *itab; u8 *keyp; - int i, t, ret; + int i, ret; + unsigned long t; request = get_rndis_request( rdev, RNDIS_MSG_SET, @@ -792,7 +796,8 @@ int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) struct rndis_set_request *set; struct rndis_set_complete *set_complete; u32 status; - int ret, t; + int ret; + unsigned long t; struct net_device *ndev; ndev = dev->net_dev->ndev; @@ -848,7 +853,8 @@ static int rndis_filter_init_device(struct rndis_device *dev) struct rndis_initialize_request *init; struct rndis_initialize_complete *init_complete; u32 status; - int ret, t; + int ret; + unsigned long t; request = get_rndis_request(dev, RNDIS_MSG_INIT, RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); @@ -998,7 +1004,7 @@ int rndis_filter_device_add(struct hv_device *dev, struct netvsc_device_info *device_info = additional_info; struct ndis_offload_params offloads; struct nvsp_message *init_packet; - int t; + unsigned long t; struct ndis_recv_scale_cap rsscap; u32 rsscap_size = sizeof(struct ndis_recv_scale_cap); u32 mtu, size; diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 1c0135620c62..7b051eacb7f1 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -427,7 +427,7 @@ at86rf230_reg_precious(struct device *dev, unsigned int reg) } } -static struct regmap_config at86rf230_regmap_spi_config = { +static const struct regmap_config at86rf230_regmap_spi_config = { .reg_bits = 8, .val_bits = 8, .write_flag_mask = CMD_REG | CMD_WRITE, @@ -450,7 +450,7 @@ at86rf230_async_error_recover(void *context) ieee802154_wake_queue(lp->hw); } -static void +static inline void at86rf230_async_error(struct at86rf230_local *lp, struct at86rf230_state_change *ctx, int rc) { @@ -524,7 +524,6 @@ at86rf230_async_state_assert(void *context) } } - dev_warn(&lp->spi->dev, "unexcept state change from 0x%02x to 0x%02x. Actual state: 0x%02x\n", ctx->from_state, ctx->to_state, trx_state); } @@ -655,7 +654,7 @@ at86rf230_async_state_change_start(void *context) if (ctx->irq_enable) enable_irq(lp->spi->irq); - at86rf230_async_error(lp, &lp->state, rc); + at86rf230_async_error(lp, ctx, rc); } } @@ -715,10 +714,7 @@ at86rf230_tx_complete(void *context) enable_irq(lp->spi->irq); - if (lp->max_frame_retries <= 0) - ieee802154_xmit_complete(lp->hw, skb, true); - else - ieee802154_xmit_complete(lp->hw, skb, false); + ieee802154_xmit_complete(lp->hw, skb, !lp->tx_aret); } static void @@ -753,16 +749,13 @@ at86rf230_tx_trac_check(void *context) * to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver * state to TX_ON. */ - if (trac) { + if (trac) at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, at86rf230_tx_trac_error, true); - return; - } - - at86rf230_tx_on(context); + else + at86rf230_tx_on(context); } - static void at86rf230_tx_trac_status(void *context) { @@ -1082,7 +1075,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, u16 addr = le16_to_cpu(filt->short_addr); dev_vdbg(&lp->spi->dev, - "at86rf230_set_hw_addr_filt called for saddr\n"); + "at86rf230_set_hw_addr_filt called for saddr\n"); __at86rf230_write(lp, RG_SHORT_ADDR_0, addr); __at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8); } @@ -1091,7 +1084,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, u16 pan = le16_to_cpu(filt->pan_id); dev_vdbg(&lp->spi->dev, - "at86rf230_set_hw_addr_filt called for pan id\n"); + "at86rf230_set_hw_addr_filt called for pan id\n"); __at86rf230_write(lp, RG_PAN_ID_0, pan); __at86rf230_write(lp, RG_PAN_ID_1, pan >> 8); } @@ -1101,14 +1094,14 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, memcpy(addr, &filt->ieee_addr, 8); dev_vdbg(&lp->spi->dev, - "at86rf230_set_hw_addr_filt called for IEEE addr\n"); + "at86rf230_set_hw_addr_filt called for IEEE addr\n"); for (i = 0; i < 8; i++) __at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]); } if (changed & IEEE802154_AFILT_PANC_CHANGED) { dev_vdbg(&lp->spi->dev, - "at86rf230_set_hw_addr_filt called for panc change\n"); + "at86rf230_set_hw_addr_filt called for panc change\n"); if (filt->pan_coord) at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 1); else @@ -1146,11 +1139,37 @@ at86rf230_set_lbt(struct ieee802154_hw *hw, bool on) } static int -at86rf230_set_cca_mode(struct ieee802154_hw *hw, u8 mode) +at86rf230_set_cca_mode(struct ieee802154_hw *hw, + const struct wpan_phy_cca *cca) { struct at86rf230_local *lp = hw->priv; + u8 val; - return at86rf230_write_subreg(lp, SR_CCA_MODE, mode); + /* mapping 802.15.4 to driver spec */ + switch (cca->mode) { + case NL802154_CCA_ENERGY: + val = 1; + break; + case NL802154_CCA_CARRIER: + val = 2; + break; + case NL802154_CCA_ENERGY_CARRIER: + switch (cca->opt) { + case NL802154_CCA_OPT_ENERGY_CARRIER_AND: + val = 3; + break; + case NL802154_CCA_OPT_ENERGY_CARRIER_OR: + val = 0; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + return at86rf230_write_subreg(lp, SR_CCA_MODE, val); } static int @@ -1400,7 +1419,7 @@ at86rf230_detect_device(struct at86rf230_local *lp) if (rc) return rc; - rc = __at86rf230_read(lp, RG_PART_NUM, &version); + rc = __at86rf230_read(lp, RG_VERSION_NUM, &version); if (rc) return rc; @@ -1410,11 +1429,12 @@ at86rf230_detect_device(struct at86rf230_local *lp) return -EINVAL; } - lp->hw->extra_tx_headroom = 0; lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AACK | IEEE802154_HW_TXPOWER | IEEE802154_HW_ARET | IEEE802154_HW_AFILT | IEEE802154_HW_PROMISCUOUS; + lp->hw->phy->cca.mode = NL802154_CCA_ENERGY; + switch (part) { case 2: chip = "at86rf230"; @@ -1429,16 +1449,12 @@ at86rf230_detect_device(struct at86rf230_local *lp) break; case 7: chip = "at86rf212"; - if (version == 1) { - lp->data = &at86rf212_data; - lp->hw->flags |= IEEE802154_HW_LBT; - lp->hw->phy->channels_supported[0] = 0x00007FF; - lp->hw->phy->channels_supported[2] = 0x00007FF; - lp->hw->phy->current_channel = 5; - lp->hw->phy->symbol_duration = 25; - } else { - rc = -ENOTSUPP; - } + lp->data = &at86rf212_data; + lp->hw->flags |= IEEE802154_HW_LBT; + lp->hw->phy->channels_supported[0] = 0x00007FF; + lp->hw->phy->channels_supported[2] = 0x00007FF; + lp->hw->phy->current_channel = 5; + lp->hw->phy->symbol_duration = 25; break; case 11: chip = "at86rf233"; @@ -1448,7 +1464,7 @@ at86rf230_detect_device(struct at86rf230_local *lp) lp->hw->phy->symbol_duration = 16; break; default: - chip = "unkown"; + chip = "unknown"; rc = -ENOTSUPP; break; } diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index f9df9fa86d5f..181b349b060e 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -45,9 +44,9 @@ #define CC2520_FREG_MASK 0x3F /* status byte values */ -#define CC2520_STATUS_XOSC32M_STABLE (1 << 7) -#define CC2520_STATUS_RSSI_VALID (1 << 6) -#define CC2520_STATUS_TX_UNDERFLOW (1 << 3) +#define CC2520_STATUS_XOSC32M_STABLE BIT(7) +#define CC2520_STATUS_RSSI_VALID BIT(6) +#define CC2520_STATUS_TX_UNDERFLOW BIT(3) /* IEEE-802.15.4 defined constants (2.4 GHz logical channels) */ #define CC2520_MINCHANNEL 11 @@ -513,7 +512,6 @@ err_tx: return rc; } - static int cc2520_rx(struct cc2520_private *priv) { u8 len = 0, lqi = 0, bytes = 1; @@ -551,14 +549,14 @@ cc2520_ed(struct ieee802154_hw *hw, u8 *level) u8 rssi; int ret; - ret = cc2520_read_register(priv , CC2520_RSSISTAT, &status); + ret = cc2520_read_register(priv, CC2520_RSSISTAT, &status); if (ret) return ret; if (status != RSSI_VALID) return -EINVAL; - ret = cc2520_read_register(priv , CC2520_RSSI, &rssi); + ret = cc2520_read_register(priv, CC2520_RSSI, &rssi); if (ret) return ret; @@ -652,6 +650,7 @@ static int cc2520_register(struct cc2520_private *priv) priv->hw->parent = &priv->spi->dev; priv->hw->extra_tx_headroom = 0; priv->hw->vif_data_size = sizeof(*priv); + ieee802154_random_extended_addr(&priv->hw->phy->perm_extended_addr); /* We do support only 2.4 Ghz */ priv->hw->phy->channels_supported[0] = 0x7FFF800; @@ -842,24 +841,15 @@ done: static int cc2520_probe(struct spi_device *spi) { struct cc2520_private *priv; - struct pinctrl *pinctrl; struct cc2520_platform_data *pdata; int ret; - priv = devm_kzalloc(&spi->dev, - sizeof(struct cc2520_private), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_ret; - } + priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; spi_set_drvdata(spi, priv); - pinctrl = devm_pinctrl_get_select_default(&spi->dev); - if (IS_ERR(pinctrl)) - dev_warn(&spi->dev, - "pinctrl pins are not configured\n"); - pdata = cc2520_get_platform_data(spi); if (!pdata) { dev_err(&spi->dev, "no platform data\n"); @@ -870,10 +860,8 @@ static int cc2520_probe(struct spi_device *spi) priv->buf = devm_kzalloc(&spi->dev, SPI_COMMAND_BUFFER, GFP_KERNEL); - if (!priv->buf) { - ret = -ENOMEM; - goto err_ret; - } + if (!priv->buf) + return -ENOMEM; mutex_init(&priv->buffer_mutex); INIT_WORK(&priv->fifop_irqwork, cc2520_fifop_irqwork); @@ -947,7 +935,6 @@ static int cc2520_probe(struct spi_device *spi) if (ret) goto err_hw_init; - gpio_set_value(pdata->vreg, HIGH); usleep_range(100, 150); @@ -991,8 +978,6 @@ static int cc2520_probe(struct spi_device *spi) err_hw_init: mutex_destroy(&priv->buffer_mutex); flush_work(&priv->fifop_irqwork); - -err_ret: return ret; } diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index a200fa16beae..fba2dfd910f7 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -289,7 +289,7 @@ static int mrf24j40_read_rx_buf(struct mrf24j40 *devrec, goto out; /* Range check the RX FIFO length, accounting for the one-byte - * length field at the begining. */ + * length field at the beginning. */ if (rx_len > RX_FIFO_SIZE-1) { dev_err(printdev(devrec), "Invalid length read from device. Performing short read.\n"); rx_len = RX_FIFO_SIZE-1; @@ -323,7 +323,7 @@ static int mrf24j40_read_rx_buf(struct mrf24j40 *devrec, #ifdef DEBUG print_hex_dump(KERN_DEBUG, "mrf24j40 rx: ", - DUMP_PREFIX_OFFSET, 16, 1, data, *len, 0); + DUMP_PREFIX_OFFSET, 16, 1, data, *len, 0); pr_debug("mrf24j40 rx: lqi: %02hhx rssi: %02hhx\n", lqi_rssi[0], lqi_rssi[1]); #endif @@ -521,7 +521,7 @@ static int mrf24j40_filter(struct ieee802154_hw *hw, */ dev_dbg(printdev(devrec), "Set Pan Coord to %s\n", - filt->pan_coord ? "on" : "off"); + filt->pan_coord ? "on" : "off"); } return 0; diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index a14d87783245..2a175006028b 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -9,7 +9,7 @@ #include "ipvlan.h" -static u32 ipvlan_jhash_secret; +static u32 ipvlan_jhash_secret __read_mostly; void ipvlan_init_secret(void) { @@ -377,9 +377,11 @@ static int ipvlan_process_v6_outbound(struct sk_buff *skb) }; dst = ip6_route_output(dev_net(dev), NULL, &fl6); - if (IS_ERR(dst)) + if (dst->error) { + ret = dst->error; + dst_release(dst); goto err; - + } skb_dst_drop(skb); skb_dst_set(skb, dst); err = ip6_local_out(skb); diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 58f98f4de773..58ae11a14bb6 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -1462,17 +1462,12 @@ static netdev_tx_t ali_ircc_fir_hard_xmit(struct sk_buff *skb, if (mtt) { /* Check how much time we have used already */ - do_gettimeofday(&self->now); - - diff = self->now.tv_usec - self->stamp.tv_usec; + diff = ktime_us_delta(ktime_get(), self->stamp); /* self->stamp is set from ali_ircc_dma_receive_complete() */ pr_debug("%s(), ******* diff = %d *******\n", __func__, diff); - - if (diff < 0) - diff += 1000000; - + /* Check if the mtt is larger than the time we have * already used by all the protocol processing */ @@ -1884,7 +1879,7 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) * reduce the min turn time a bit since we will know * how much time we have used for protocol processing */ - do_gettimeofday(&self->stamp); + self->stamp = ktime_get(); skb = dev_alloc_skb(len+1); if (skb == NULL) diff --git a/drivers/net/irda/ali-ircc.h b/drivers/net/irda/ali-ircc.h index 0c8edb41bd0a..c2d9747a5108 100644 --- a/drivers/net/irda/ali-ircc.h +++ b/drivers/net/irda/ali-ircc.h @@ -22,7 +22,7 @@ #ifndef ALI_IRCC_H #define ALI_IRCC_H -#include +#include #include #include @@ -209,8 +209,7 @@ struct ali_ircc_cb { unsigned char rcvFramesOverflow; - struct timeval stamp; - struct timeval now; + ktime_t stamp; spinlock_t lock; /* For serializing operations */ diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index e151205281e2..44e4f386a5dc 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -163,8 +162,6 @@ struct au1k_private { iobuff_t rx_buff; struct net_device *netdev; - struct timeval stamp; - struct timeval now; struct qos_info qos; struct irlap_cb *irlap; diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 48b2f9a321b7..f6c916312577 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -495,18 +495,12 @@ static netdev_tx_t irda_usb_hard_xmit(struct sk_buff *skb, mtt = irda_get_mtt(skb); if (mtt) { int diff; - do_gettimeofday(&self->now); - diff = self->now.tv_usec - self->stamp.tv_usec; + diff = ktime_us_delta(ktime_get(), self->stamp); #ifdef IU_USB_MIN_RTT /* Factor in USB delays -> Get rid of udelay() that * would be lost in the noise - Jean II */ diff += IU_USB_MIN_RTT; #endif /* IU_USB_MIN_RTT */ - /* If the usec counter did wraparound, the diff will - * go negative (tv_usec is a long), so we need to - * correct it by one second. Jean II */ - if (diff < 0) - diff += 1000000; /* Check if the mtt is larger than the time we have * already used by all the protocol processing @@ -869,7 +863,7 @@ static void irda_usb_receive(struct urb *urb) * reduce the min turn time a bit since we will know * how much time we have used for protocol processing */ - do_gettimeofday(&self->stamp); + self->stamp = ktime_get(); /* Check if we need to copy the data to a new skb or not. * For most frames, we use ZeroCopy and pass the already diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h index 58ddb5214916..8ac389fa9348 100644 --- a/drivers/net/irda/irda-usb.h +++ b/drivers/net/irda/irda-usb.h @@ -29,7 +29,7 @@ * *****************************************************************************/ -#include +#include #include #include /* struct irlap_cb */ @@ -157,8 +157,7 @@ struct irda_usb_cb { char *speed_buff; /* Buffer for speed changes */ char *tx_buff; - struct timeval stamp; - struct timeval now; + ktime_t stamp; spinlock_t lock; /* For serializing Tx operations */ diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index e638893e98a9..fb5d162ec7d2 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -114,7 +114,6 @@ struct kingsun_cb { (usually 8) */ iobuff_t rx_buff; /* receive unwrap state machine */ - struct timeval rx_time; spinlock_t lock; int receiving; @@ -235,7 +234,6 @@ static void kingsun_rcv_irq(struct urb *urb) &kingsun->netdev->stats, &kingsun->rx_buff, bytes[i]); } - do_gettimeofday(&kingsun->rx_time); kingsun->receiving = (kingsun->rx_buff.state != OUTSIDE_FRAME) ? 1 : 0; @@ -273,7 +271,6 @@ static int kingsun_net_open(struct net_device *netdev) skb_reserve(kingsun->rx_buff.skb, 1); kingsun->rx_buff.head = kingsun->rx_buff.skb->data; - do_gettimeofday(&kingsun->rx_time); kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!kingsun->rx_urb) diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c index e6b3804edacd..8e6e0edf2440 100644 --- a/drivers/net/irda/ks959-sir.c +++ b/drivers/net/irda/ks959-sir.c @@ -187,7 +187,6 @@ struct ks959_cb { __u8 *rx_buf; __u8 rx_variable_xormask; iobuff_t rx_unwrap_buff; - struct timeval rx_time; struct usb_ctrlrequest *speed_setuprequest; struct urb *speed_urb; @@ -476,7 +475,6 @@ static void ks959_rcv_irq(struct urb *urb) bytes[i]); } } - do_gettimeofday(&kingsun->rx_time); kingsun->receiving = (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0; } @@ -514,7 +512,6 @@ static int ks959_net_open(struct net_device *netdev) skb_reserve(kingsun->rx_unwrap_buff.skb, 1); kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data; - do_gettimeofday(&kingsun->rx_time); kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!kingsun->rx_urb) diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index e4d678fbeb2f..bca6a1e72d1d 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -722,7 +722,6 @@ static int mcs_net_open(struct net_device *netdev) skb_reserve(mcs->rx_buff.skb, 1); mcs->rx_buff.head = mcs->rx_buff.skb->data; - do_gettimeofday(&mcs->rx_time); /* * Now that everything should be initialized properly, @@ -799,7 +798,6 @@ static void mcs_receive_irq(struct urb *urb) mcs_unwrap_fir(mcs, urb->transfer_buffer, urb->actual_length); } - do_gettimeofday(&mcs->rx_time); } ret = usb_submit_urb(urb, GFP_ATOMIC); diff --git a/drivers/net/irda/mcs7780.h b/drivers/net/irda/mcs7780.h index b10689b2887c..a6e8f7dbafc9 100644 --- a/drivers/net/irda/mcs7780.h +++ b/drivers/net/irda/mcs7780.h @@ -116,7 +116,6 @@ struct mcs_cb { __u8 *fifo_status; iobuff_t rx_buff; /* receive unwrap state machine */ - struct timeval rx_time; spinlock_t lock; int receiving; diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index e7317b104bfb..dc0dbd8dd0b5 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -1501,10 +1501,7 @@ static netdev_tx_t nsc_ircc_hard_xmit_fir(struct sk_buff *skb, mtt = irda_get_mtt(skb); if (mtt) { /* Check how much time we have used already */ - do_gettimeofday(&self->now); - diff = self->now.tv_usec - self->stamp.tv_usec; - if (diff < 0) - diff += 1000000; + diff = ktime_us_delta(ktime_get(), self->stamp); /* Check if the mtt is larger than the time we have * already used by all the protocol processing @@ -1867,7 +1864,7 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) * reduce the min turn time a bit since we will know * how much time we have used for protocol processing */ - do_gettimeofday(&self->stamp); + self->stamp = ktime_get(); skb = dev_alloc_skb(len+1); if (skb == NULL) { diff --git a/drivers/net/irda/nsc-ircc.h b/drivers/net/irda/nsc-ircc.h index 32fa58211fad..7be5acb56532 100644 --- a/drivers/net/irda/nsc-ircc.h +++ b/drivers/net/irda/nsc-ircc.h @@ -28,7 +28,7 @@ #ifndef NSC_IRCC_H #define NSC_IRCC_H -#include +#include #include #include @@ -263,8 +263,7 @@ struct nsc_ircc_cb { __u8 ier; /* Interrupt enable register */ - struct timeval stamp; - struct timeval now; + ktime_t stamp; spinlock_t lock; /* For serializing operations */ diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 7b17fa2114e1..b6e44ff4e373 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -38,7 +38,7 @@ #include #include -#include +#include static int power_level = 3; static int tx_lpm; diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index dd1bd1060ec9..83cc48a01802 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -174,7 +175,7 @@ struct stir_cb { __u8 *fifo_status; iobuff_t rx_buff; /* receive unwrap state machine */ - struct timeval rx_time; + ktime_t rx_time; int receiving; struct urb *rx_urb; }; @@ -650,15 +651,12 @@ static int fifo_txwait(struct stir_cb *stir, int space) static void turnaround_delay(const struct stir_cb *stir, long us) { long ticks; - struct timeval now; if (us <= 0) return; - do_gettimeofday(&now); - if (now.tv_sec - stir->rx_time.tv_sec > 0) - us -= USEC_PER_SEC; - us -= now.tv_usec - stir->rx_time.tv_usec; + us -= ktime_us_delta(ktime_get(), stir->rx_time); + if (us < 10) return; @@ -823,8 +821,8 @@ static void stir_rcv_irq(struct urb *urb) pr_debug("receive %d\n", urb->actual_length); unwrap_chars(stir, urb->transfer_buffer, urb->actual_length); - - do_gettimeofday(&stir->rx_time); + + stir->rx_time = ktime_get(); } /* kernel thread is stopping receiver don't resubmit */ @@ -876,7 +874,7 @@ static int stir_net_open(struct net_device *netdev) skb_reserve(stir->rx_buff.skb, 1); stir->rx_buff.head = stir->rx_buff.skb->data; - do_gettimeofday(&stir->rx_time); + stir->rx_time = ktime_get(); stir->rx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!stir->rx_urb) diff --git a/drivers/net/irda/via-ircc.h b/drivers/net/irda/via-ircc.h index 7ce820ecc361..ac1525573398 100644 --- a/drivers/net/irda/via-ircc.h +++ b/drivers/net/irda/via-ircc.h @@ -29,7 +29,6 @@ this program; if not, see . ********************************************************************/ #ifndef via_IRCC_H #define via_IRCC_H -#include #include #include #include @@ -106,9 +105,6 @@ struct via_ircc_cb { __u8 ier; /* Interrupt enable register */ - struct timeval stamp; - struct timeval now; - spinlock_t lock; /* For serializing operations */ __u32 flags; /* Interface flags */ diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index ac39d9f33d5f..a0849f49bbec 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -33,6 +33,7 @@ MODULE_LICENSE("GPL"); /********************************************************/ #include +#include #include #include #include @@ -40,9 +41,9 @@ MODULE_LICENSE("GPL"); #include #include #include -#include #include #include +#include #include #include #include @@ -180,8 +181,7 @@ static void vlsi_proc_ndev(struct seq_file *seq, struct net_device *ndev) vlsi_irda_dev_t *idev = netdev_priv(ndev); u8 byte; u16 word; - unsigned delta1, delta2; - struct timeval now; + s32 sec, usec; unsigned iobase = ndev->base_addr; seq_printf(seq, "\n%s link state: %s / %s / %s / %s\n", ndev->name, @@ -277,17 +277,9 @@ static void vlsi_proc_ndev(struct seq_file *seq, struct net_device *ndev) seq_printf(seq, "\nsw-state:\n"); seq_printf(seq, "IrPHY setup: %d baud - %s encoding\n", idev->baud, (idev->mode==IFF_SIR)?"SIR":((idev->mode==IFF_MIR)?"MIR":"FIR")); - do_gettimeofday(&now); - if (now.tv_usec >= idev->last_rx.tv_usec) { - delta2 = now.tv_usec - idev->last_rx.tv_usec; - delta1 = 0; - } - else { - delta2 = 1000000 + now.tv_usec - idev->last_rx.tv_usec; - delta1 = 1; - } - seq_printf(seq, "last rx: %lu.%06u sec\n", - now.tv_sec - idev->last_rx.tv_sec - delta1, delta2); + sec = div_s64_rem(ktime_us_delta(ktime_get(), idev->last_rx), + USEC_PER_SEC, &usec); + seq_printf(seq, "last rx: %ul.%06u sec\n", sec, usec); seq_printf(seq, "RX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu", ndev->stats.rx_packets, ndev->stats.rx_bytes, ndev->stats.rx_errors, @@ -661,7 +653,7 @@ static void vlsi_rx_interrupt(struct net_device *ndev) } } - do_gettimeofday(&idev->last_rx); /* remember "now" for later mtt delay */ + idev->last_rx = ktime_get(); /* remember "now" for later mtt delay */ vlsi_fill_rx(r); @@ -858,9 +850,8 @@ static netdev_tx_t vlsi_hard_start_xmit(struct sk_buff *skb, unsigned iobase = ndev->base_addr; u8 status; u16 config; - int mtt; + int mtt, diff; int len, speed; - struct timeval now, ready; char *msg = NULL; speed = irda_get_next_speed(skb); @@ -940,21 +931,10 @@ static netdev_tx_t vlsi_hard_start_xmit(struct sk_buff *skb, spin_unlock_irqrestore(&idev->lock, flags); if ((mtt = irda_get_mtt(skb)) > 0) { - - ready.tv_usec = idev->last_rx.tv_usec + mtt; - ready.tv_sec = idev->last_rx.tv_sec; - if (ready.tv_usec >= 1000000) { - ready.tv_usec -= 1000000; - ready.tv_sec++; /* IrLAP 1.1: mtt always < 1 sec */ - } - for(;;) { - do_gettimeofday(&now); - if (now.tv_sec > ready.tv_sec || - (now.tv_sec==ready.tv_sec && now.tv_usec>=ready.tv_usec)) - break; - udelay(100); + diff = ktime_us_delta(ktime_get(), idev->last_rx); + if (mtt > diff) + udelay(mtt - diff); /* must not sleep here - called under netif_tx_lock! */ - } } /* tx buffer already owned by CPU due to pci_dma_sync_single_for_cpu() @@ -1333,7 +1313,7 @@ static int vlsi_start_hw(vlsi_irda_dev_t *idev) vlsi_fill_rx(idev->rx_ring); - do_gettimeofday(&idev->last_rx); /* first mtt may start from now on */ + idev->last_rx = ktime_get(); /* first mtt may start from now on */ outw(0, iobase+VLSI_PIO_PROMPT); /* kick hw state machine */ @@ -1520,7 +1500,7 @@ static int vlsi_open(struct net_device *ndev) if (!idev->irlap) goto errout_free_ring; - do_gettimeofday(&idev->last_rx); /* first mtt may start from now on */ + idev->last_rx = ktime_get(); /* first mtt may start from now on */ idev->new_baud = 9600; /* start with IrPHY using 9600(SIR) mode */ diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h index f9119c6d2a09..f9db2ce4c5c6 100644 --- a/drivers/net/irda/vlsi_ir.h +++ b/drivers/net/irda/vlsi_ir.h @@ -723,7 +723,7 @@ typedef struct vlsi_irda_dev { void *virtaddr; struct vlsi_ring *tx_ring, *rx_ring; - struct timeval last_rx; + ktime_t last_rx; spinlock_t lock; struct mutex mtx; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 612e0731142d..1df38bdae2ee 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1471,11 +1471,17 @@ int macvlan_link_register(struct rtnl_link_ops *ops) }; EXPORT_SYMBOL_GPL(macvlan_link_register); +static struct net *macvlan_get_link_net(const struct net_device *dev) +{ + return dev_net(macvlan_dev_real_dev(dev)); +} + static struct rtnl_link_ops macvlan_link_ops = { .kind = "macvlan", .setup = macvlan_setup, .newlink = macvlan_newlink, .dellink = macvlan_dellink, + .get_link_net = macvlan_get_link_net, }; static int macvlan_device_event(struct notifier_block *unused, diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 7df221788cd4..e40fdfccc9c1 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -81,7 +80,7 @@ static struct cdev macvtap_cdev; static const struct proto_ops macvtap_socket_ops; #define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \ - NETIF_F_TSO6) + NETIF_F_TSO6 | NETIF_F_UFO) #define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO) #define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG) @@ -586,11 +585,7 @@ static int macvtap_skb_from_vnet_hdr(struct macvtap_queue *q, gso_type = SKB_GSO_TCPV6; break; case VIRTIO_NET_HDR_GSO_UDP: - pr_warn_once("macvtap: %s: using disabled UFO feature; please fix this program\n", - current->comm); gso_type = SKB_GSO_UDP; - if (skb->protocol == htons(ETH_P_IPV6)) - ipv6_proxy_select_ident(skb); break; default: return -EINVAL; @@ -636,6 +631,8 @@ static void macvtap_skb_to_vnet_hdr(struct macvtap_queue *q, vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; else if (sinfo->gso_type & SKB_GSO_TCPV6) vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; + else if (sinfo->gso_type & SKB_GSO_UDP) + vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP; else BUG(); if (sinfo->gso_type & SKB_GSO_TCP_ECN) @@ -645,7 +642,7 @@ static void macvtap_skb_to_vnet_hdr(struct macvtap_queue *q, if (skb->ip_summed == CHECKSUM_PARTIAL) { vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; - if (vlan_tx_tag_present(skb)) + if (skb_vlan_tag_present(skb)) vnet_hdr->csum_start = cpu_to_macvtap16(q, skb_checksum_start_offset(skb) + VLAN_HLEN); else @@ -821,13 +818,13 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, total = vnet_hdr_len; total += skb->len; - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { struct { __be16 h_vlan_proto; __be16 h_vlan_TCI; } veth; veth.h_vlan_proto = skb->vlan_proto; - veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); + veth.h_vlan_TCI = htons(skb_vlan_tag_get(skb)); vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto); total += VLAN_HLEN; @@ -965,6 +962,9 @@ static int set_offload(struct macvtap_queue *q, unsigned long arg) if (arg & TUN_F_TSO6) feature_mask |= NETIF_F_TSO6; } + + if (arg & TUN_F_UFO) + feature_mask |= NETIF_F_UFO; } /* tun/tap driver inverts the usage for TSO offloads, where @@ -975,7 +975,7 @@ static int set_offload(struct macvtap_queue *q, unsigned long arg) * When user space turns off TSO, we turn off GSO/LRO so that * user-space will not receive TSO frames. */ - if (feature_mask & (NETIF_F_TSO | NETIF_F_TSO6)) + if (feature_mask & (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_UFO)) features |= RX_OFFLOADS; else features &= ~RX_OFFLOADS; @@ -1090,7 +1090,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, case TUNSETOFFLOAD: /* let the user check for future flags */ if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | - TUN_F_TSO_ECN)) + TUN_F_TSO_ECN | TUN_F_UFO)) return -EINVAL; rtnl_lock(); diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 4a99c3919037..993570b1e2ae 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -302,7 +302,7 @@ void mii_check_link (struct mii_if_info *mii) } /** - * mii_check_media - check the MII interface for a duplex change + * mii_check_media - check the MII interface for a carrier/speed/duplex change * @mii: the MII interface * @ok_to_print: OK to print link up/down messages * @init_media: OK to save duplex mode in @mii @@ -318,10 +318,6 @@ unsigned int mii_check_media (struct mii_if_info *mii, int advertise, lpa, media, duplex; int lpa2 = 0; - /* if forced media, go no further */ - if (mii->force_media) - return 0; /* duplex did not change */ - /* check current and old link status */ old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0; new_carrier = (unsigned int) mii_link_ok(mii); @@ -345,6 +341,12 @@ unsigned int mii_check_media (struct mii_if_info *mii, */ netif_carrier_on(mii->dev); + if (mii->force_media) { + if (ok_to_print) + netdev_info(mii->dev, "link up\n"); + return 0; /* duplex did not change */ + } + /* get MII advertise and LPA values */ if ((!init_media) && (mii->advertising)) advertise = mii->advertising; diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index a3c251b79f38..16adbc481772 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -26,7 +26,7 @@ config AMD_PHY config AMD_XGBE_PHY tristate "Driver for the AMD 10GbE (amd-xgbe) PHYs" - depends on OF && HAS_IOMEM + depends on (OF || ACPI) && HAS_IOMEM ---help--- Currently supports the AMD 10GbE PHY diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index 903dc3dc9ea7..9e3af54c9010 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,9 @@ #include #include #include +#include +#include +#include MODULE_AUTHOR("Tom Lendacky "); MODULE_LICENSE("Dual BSD/GPL"); @@ -84,22 +88,43 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define XGBE_PHY_MASK 0xfffffff0 #define XGBE_PHY_SPEEDSET_PROPERTY "amd,speed-set" +#define XGBE_PHY_BLWC_PROPERTY "amd,serdes-blwc" +#define XGBE_PHY_CDR_RATE_PROPERTY "amd,serdes-cdr-rate" +#define XGBE_PHY_PQ_SKEW_PROPERTY "amd,serdes-pq-skew" +#define XGBE_PHY_TX_AMP_PROPERTY "amd,serdes-tx-amp" + +#define XGBE_PHY_SPEEDS 3 +#define XGBE_PHY_SPEED_1000 0 +#define XGBE_PHY_SPEED_2500 1 +#define XGBE_PHY_SPEED_10000 2 #define XGBE_AN_INT_CMPLT 0x01 #define XGBE_AN_INC_LINK 0x02 #define XGBE_AN_PG_RCV 0x04 +#define XGBE_AN_INT_MASK 0x07 #define XNP_MCF_NULL_MESSAGE 0x001 -#define XNP_ACK_PROCESSED (1 << 12) -#define XNP_MP_FORMATTED (1 << 13) -#define XNP_NP_EXCHANGE (1 << 15) +#define XNP_ACK_PROCESSED BIT(12) +#define XNP_MP_FORMATTED BIT(13) +#define XNP_NP_EXCHANGE BIT(15) #define XGBE_PHY_RATECHANGE_COUNT 500 +#define XGBE_PHY_KR_TRAINING_START 0x01 +#define XGBE_PHY_KR_TRAINING_ENABLE 0x02 + +#define XGBE_PHY_FEC_ENABLE 0x01 +#define XGBE_PHY_FEC_FORWARD 0x02 +#define XGBE_PHY_FEC_MASK 0x03 + #ifndef MDIO_PMA_10GBR_PMD_CTRL #define MDIO_PMA_10GBR_PMD_CTRL 0x0096 #endif +#ifndef MDIO_PMA_10GBR_FEC_ABILITY +#define MDIO_PMA_10GBR_FEC_ABILITY 0x00aa +#endif + #ifndef MDIO_PMA_10GBR_FEC_CTRL #define MDIO_PMA_10GBR_FEC_CTRL 0x00ab #endif @@ -108,6 +133,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define MDIO_AN_XNP 0x0016 #endif +#ifndef MDIO_AN_LPX +#define MDIO_AN_LPX 0x0019 +#endif + #ifndef MDIO_AN_INTMASK #define MDIO_AN_INTMASK 0x8001 #endif @@ -116,18 +145,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define MDIO_AN_INT 0x8002 #endif -#ifndef MDIO_AN_KR_CTRL -#define MDIO_AN_KR_CTRL 0x8003 -#endif - #ifndef MDIO_CTRL1_SPEED1G #define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100) #endif -#ifndef MDIO_KR_CTRL_PDETECT -#define MDIO_KR_CTRL_PDETECT 0x01 -#endif - /* SerDes integration register offsets */ #define SIR0_KR_RT_1 0x002c #define SIR0_STATUS 0x0040 @@ -140,10 +161,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define SIR0_STATUS_RX_READY_WIDTH 1 #define SIR0_STATUS_TX_READY_INDEX 8 #define SIR0_STATUS_TX_READY_WIDTH 1 +#define SIR1_SPEED_CDR_RATE_INDEX 12 +#define SIR1_SPEED_CDR_RATE_WIDTH 4 #define SIR1_SPEED_DATARATE_INDEX 4 #define SIR1_SPEED_DATARATE_WIDTH 2 -#define SIR1_SPEED_PI_SPD_SEL_INDEX 12 -#define SIR1_SPEED_PI_SPD_SEL_WIDTH 4 #define SIR1_SPEED_PLLSEL_INDEX 3 #define SIR1_SPEED_PLLSEL_WIDTH 1 #define SIR1_SPEED_RATECHANGE_INDEX 6 @@ -153,20 +174,26 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define SIR1_SPEED_WORDMODE_INDEX 0 #define SIR1_SPEED_WORDMODE_WIDTH 3 +#define SPEED_10000_BLWC 0 #define SPEED_10000_CDR 0x7 #define SPEED_10000_PLL 0x1 +#define SPEED_10000_PQ 0x1e #define SPEED_10000_RATE 0x0 #define SPEED_10000_TXAMP 0xa #define SPEED_10000_WORD 0x7 +#define SPEED_2500_BLWC 1 #define SPEED_2500_CDR 0x2 #define SPEED_2500_PLL 0x0 +#define SPEED_2500_PQ 0xa #define SPEED_2500_RATE 0x1 #define SPEED_2500_TXAMP 0xf #define SPEED_2500_WORD 0x1 +#define SPEED_1000_BLWC 1 #define SPEED_1000_CDR 0x2 #define SPEED_1000_PLL 0x0 +#define SPEED_1000_PQ 0xa #define SPEED_1000_RATE 0x3 #define SPEED_1000_TXAMP 0xf #define SPEED_1000_WORD 0x1 @@ -181,15 +208,6 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define RXTX_REG114_PQ_REG_INDEX 9 #define RXTX_REG114_PQ_REG_WIDTH 7 -#define RXTX_10000_BLWC 0 -#define RXTX_10000_PQ 0x1e - -#define RXTX_2500_BLWC 1 -#define RXTX_2500_PQ 0xa - -#define RXTX_1000_BLWC 1 -#define RXTX_1000_PQ 0xa - /* Bit setting and getting macros * The get macro will extract the current bit field value from within * the variable @@ -291,23 +309,44 @@ do { \ XRXTX_IOWRITE((_priv), _reg, reg_val); \ } while (0) +static const u32 amd_xgbe_phy_serdes_blwc[] = { + SPEED_1000_BLWC, + SPEED_2500_BLWC, + SPEED_10000_BLWC, +}; + +static const u32 amd_xgbe_phy_serdes_cdr_rate[] = { + SPEED_1000_CDR, + SPEED_2500_CDR, + SPEED_10000_CDR, +}; + +static const u32 amd_xgbe_phy_serdes_pq_skew[] = { + SPEED_1000_PQ, + SPEED_2500_PQ, + SPEED_10000_PQ, +}; + +static const u32 amd_xgbe_phy_serdes_tx_amp[] = { + SPEED_1000_TXAMP, + SPEED_2500_TXAMP, + SPEED_10000_TXAMP, +}; + enum amd_xgbe_phy_an { AMD_XGBE_AN_READY = 0, - AMD_XGBE_AN_START, - AMD_XGBE_AN_EVENT, AMD_XGBE_AN_PAGE_RECEIVED, AMD_XGBE_AN_INCOMPAT_LINK, AMD_XGBE_AN_COMPLETE, AMD_XGBE_AN_NO_LINK, - AMD_XGBE_AN_EXIT, AMD_XGBE_AN_ERROR, }; enum amd_xgbe_phy_rx { - AMD_XGBE_RX_READY = 0, - AMD_XGBE_RX_BPA, + AMD_XGBE_RX_BPA = 0, AMD_XGBE_RX_XNP, AMD_XGBE_RX_COMPLETE, + AMD_XGBE_RX_ERROR, }; enum amd_xgbe_phy_mode { @@ -316,12 +355,13 @@ enum amd_xgbe_phy_mode { }; enum amd_xgbe_phy_speedset { - AMD_XGBE_PHY_SPEEDSET_1000_10000, + AMD_XGBE_PHY_SPEEDSET_1000_10000 = 0, AMD_XGBE_PHY_SPEEDSET_2500_10000, }; struct amd_xgbe_phy_priv { struct platform_device *pdev; + struct acpi_device *adev; struct device *dev; struct phy_device *phydev; @@ -336,10 +376,24 @@ struct amd_xgbe_phy_priv { void __iomem *sir0_regs; /* SerDes integration registers (1/2) */ void __iomem *sir1_regs; /* SerDes integration registers (2/2) */ - /* Maintain link status for re-starting auto-negotiation */ - unsigned int link; + int an_irq; + char an_irq_name[IFNAMSIZ + 32]; + struct work_struct an_irq_work; + unsigned int an_irq_allocated; + unsigned int speed_set; + /* SerDes UEFI configurable settings. + * Switching between modes/speeds requires new values for some + * SerDes settings. The values can be supplied as device + * properties in array format. The first array entry is for + * 1GbE, second for 2.5GbE and third for 10GbE + */ + u32 serdes_blwc[XGBE_PHY_SPEEDS]; + u32 serdes_cdr_rate[XGBE_PHY_SPEEDS]; + u32 serdes_pq_skew[XGBE_PHY_SPEEDS]; + u32 serdes_tx_amp[XGBE_PHY_SPEEDS]; + /* Auto-negotiation state machine support */ struct mutex an_mutex; enum amd_xgbe_phy_an an_result; @@ -348,7 +402,11 @@ struct amd_xgbe_phy_priv { enum amd_xgbe_phy_rx kx_state; struct work_struct an_work; struct workqueue_struct *an_workqueue; + unsigned int an_supported; unsigned int parallel_detect; + unsigned int fec_ability; + + unsigned int lpm_ctrl; /* CTRL1 for resume */ }; static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev) @@ -359,7 +417,7 @@ static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev) if (ret < 0) return ret; - ret |= 0x02; + ret |= XGBE_PHY_KR_TRAINING_ENABLE; phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); return 0; @@ -373,7 +431,7 @@ static int amd_xgbe_an_disable_kr_training(struct phy_device *phydev) if (ret < 0) return ret; - ret &= ~0x02; + ret &= ~XGBE_PHY_KR_TRAINING_ENABLE; phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); return 0; @@ -466,12 +524,16 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_10000_RATE); XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_10000_WORD); - XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_10000_TXAMP); XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_10000_PLL); - XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_10000_CDR); - XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_10000_BLWC); - XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_10000_PQ); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE, + priv->serdes_cdr_rate[XGBE_PHY_SPEED_10000]); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, + priv->serdes_tx_amp[XGBE_PHY_SPEED_10000]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, + priv->serdes_blwc[XGBE_PHY_SPEED_10000]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, + priv->serdes_pq_skew[XGBE_PHY_SPEED_10000]); amd_xgbe_phy_serdes_complete_ratechange(phydev); @@ -514,12 +576,16 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev) XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_2500_RATE); XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_2500_WORD); - XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_2500_TXAMP); XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_2500_PLL); - XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_2500_CDR); - XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_2500_BLWC); - XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_2500_PQ); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE, + priv->serdes_cdr_rate[XGBE_PHY_SPEED_2500]); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, + priv->serdes_tx_amp[XGBE_PHY_SPEED_2500]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, + priv->serdes_blwc[XGBE_PHY_SPEED_2500]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, + priv->serdes_pq_skew[XGBE_PHY_SPEED_2500]); amd_xgbe_phy_serdes_complete_ratechange(phydev); @@ -562,12 +628,16 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev) XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_1000_RATE); XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_1000_WORD); - XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_1000_TXAMP); XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_1000_PLL); - XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_1000_CDR); - XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_1000_BLWC); - XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_1000_PQ); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE, + priv->serdes_cdr_rate[XGBE_PHY_SPEED_1000]); + XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, + priv->serdes_tx_amp[XGBE_PHY_SPEED_1000]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, + priv->serdes_blwc[XGBE_PHY_SPEED_1000]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, + priv->serdes_pq_skew[XGBE_PHY_SPEED_1000]); amd_xgbe_phy_serdes_complete_ratechange(phydev); @@ -635,6 +705,38 @@ static int amd_xgbe_phy_set_mode(struct phy_device *phydev, return ret; } +static int amd_xgbe_phy_set_an(struct phy_device *phydev, bool enable, + bool restart) +{ + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); + if (ret < 0) + return ret; + + ret &= ~MDIO_AN_CTRL1_ENABLE; + + if (enable) + ret |= MDIO_AN_CTRL1_ENABLE; + + if (restart) + ret |= MDIO_AN_CTRL1_RESTART; + + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret); + + return 0; +} + +static int amd_xgbe_phy_restart_an(struct phy_device *phydev) +{ + return amd_xgbe_phy_set_an(phydev, true, true); +} + +static int amd_xgbe_phy_disable_an(struct phy_device *phydev) +{ + return amd_xgbe_phy_set_an(phydev, false, false); +} + static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, enum amd_xgbe_phy_rx *state) { @@ -645,7 +747,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, /* If we're not in KR mode then we're done */ if (!amd_xgbe_phy_in_kr_mode(phydev)) - return AMD_XGBE_AN_EVENT; + return AMD_XGBE_AN_PAGE_RECEIVED; /* Enable/Disable FEC */ ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); @@ -660,10 +762,9 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, if (ret < 0) return AMD_XGBE_AN_ERROR; + ret &= ~XGBE_PHY_FEC_MASK; if ((ad_reg & 0xc000) && (lp_reg & 0xc000)) - ret |= 0x01; - else - ret &= ~0x01; + ret |= priv->fec_ability; phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL, ret); @@ -672,14 +773,17 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, if (ret < 0) return AMD_XGBE_AN_ERROR; - XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1); + if (ret & XGBE_PHY_KR_TRAINING_ENABLE) { + XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1); - ret |= 0x01; - phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); + ret |= XGBE_PHY_KR_TRAINING_START; + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, + ret); - XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0); + XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0); + } - return AMD_XGBE_AN_EVENT; + return AMD_XGBE_AN_PAGE_RECEIVED; } static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev, @@ -696,7 +800,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev, phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0); phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP, msg); - return AMD_XGBE_AN_EVENT; + return AMD_XGBE_AN_PAGE_RECEIVED; } static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev, @@ -735,11 +839,11 @@ static enum amd_xgbe_phy_an amd_xgbe_an_rx_xnp(struct phy_device *phydev, int ad_reg, lp_reg; /* Check Extended Next Page support */ - ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); + ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP); if (ad_reg < 0) return AMD_XGBE_AN_ERROR; - lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA); + lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPX); if (lp_reg < 0) return AMD_XGBE_AN_ERROR; @@ -748,116 +852,6 @@ static enum amd_xgbe_phy_an amd_xgbe_an_rx_xnp(struct phy_device *phydev, amd_xgbe_an_tx_training(phydev, state); } -static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev) -{ - struct amd_xgbe_phy_priv *priv = phydev->priv; - int ret; - - /* Be sure we aren't looping trying to negotiate */ - if (amd_xgbe_phy_in_kr_mode(phydev)) { - if (priv->kr_state != AMD_XGBE_RX_READY) - return AMD_XGBE_AN_NO_LINK; - priv->kr_state = AMD_XGBE_RX_BPA; - } else { - if (priv->kx_state != AMD_XGBE_RX_READY) - return AMD_XGBE_AN_NO_LINK; - priv->kx_state = AMD_XGBE_RX_BPA; - } - - /* Set up Advertisement register 3 first */ - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); - if (ret < 0) - return AMD_XGBE_AN_ERROR; - - if (phydev->supported & SUPPORTED_10000baseR_FEC) - ret |= 0xc000; - else - ret &= ~0xc000; - - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, ret); - - /* Set up Advertisement register 2 next */ - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); - if (ret < 0) - return AMD_XGBE_AN_ERROR; - - if (phydev->supported & SUPPORTED_10000baseKR_Full) - ret |= 0x80; - else - ret &= ~0x80; - - if ((phydev->supported & SUPPORTED_1000baseKX_Full) || - (phydev->supported & SUPPORTED_2500baseX_Full)) - ret |= 0x20; - else - ret &= ~0x20; - - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, ret); - - /* Set up Advertisement register 1 last */ - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); - if (ret < 0) - return AMD_XGBE_AN_ERROR; - - if (phydev->supported & SUPPORTED_Pause) - ret |= 0x400; - else - ret &= ~0x400; - - if (phydev->supported & SUPPORTED_Asym_Pause) - ret |= 0x800; - else - ret &= ~0x800; - - /* We don't intend to perform XNP */ - ret &= ~XNP_NP_EXCHANGE; - - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, ret); - - /* Enable and start auto-negotiation */ - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); - - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL); - if (ret < 0) - return AMD_XGBE_AN_ERROR; - - ret |= MDIO_KR_CTRL_PDETECT; - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL, ret); - - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); - if (ret < 0) - return AMD_XGBE_AN_ERROR; - - ret |= MDIO_AN_CTRL1_ENABLE; - ret |= MDIO_AN_CTRL1_RESTART; - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret); - - return AMD_XGBE_AN_EVENT; -} - -static enum amd_xgbe_phy_an amd_xgbe_an_event(struct phy_device *phydev) -{ - enum amd_xgbe_phy_an new_state; - int ret; - - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT); - if (ret < 0) - return AMD_XGBE_AN_ERROR; - - new_state = AMD_XGBE_AN_EVENT; - if (ret & XGBE_AN_PG_RCV) - new_state = AMD_XGBE_AN_PAGE_RECEIVED; - else if (ret & XGBE_AN_INC_LINK) - new_state = AMD_XGBE_AN_INCOMPAT_LINK; - else if (ret & XGBE_AN_INT_CMPLT) - new_state = AMD_XGBE_AN_COMPLETE; - - if (new_state != AMD_XGBE_AN_EVENT) - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); - - return new_state; -} - static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv = phydev->priv; @@ -885,13 +879,67 @@ static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev) static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev) { + struct amd_xgbe_phy_priv *priv = phydev->priv; int ret; + /* Be sure we aren't looping trying to negotiate */ + if (amd_xgbe_phy_in_kr_mode(phydev)) { + priv->kr_state = AMD_XGBE_RX_ERROR; + + if (!(phydev->supported & SUPPORTED_1000baseKX_Full) && + !(phydev->supported & SUPPORTED_2500baseX_Full)) + return AMD_XGBE_AN_NO_LINK; + + if (priv->kx_state != AMD_XGBE_RX_BPA) + return AMD_XGBE_AN_NO_LINK; + } else { + priv->kx_state = AMD_XGBE_RX_ERROR; + + if (!(phydev->supported & SUPPORTED_10000baseKR_Full)) + return AMD_XGBE_AN_NO_LINK; + + if (priv->kr_state != AMD_XGBE_RX_BPA) + return AMD_XGBE_AN_NO_LINK; + } + + ret = amd_xgbe_phy_disable_an(phydev); + if (ret) + return AMD_XGBE_AN_ERROR; + ret = amd_xgbe_phy_switch_mode(phydev); if (ret) return AMD_XGBE_AN_ERROR; - return AMD_XGBE_AN_START; + ret = amd_xgbe_phy_restart_an(phydev); + if (ret) + return AMD_XGBE_AN_ERROR; + + return AMD_XGBE_AN_INCOMPAT_LINK; +} + +static irqreturn_t amd_xgbe_an_isr(int irq, void *data) +{ + struct amd_xgbe_phy_priv *priv = (struct amd_xgbe_phy_priv *)data; + + /* Interrupt reason must be read and cleared outside of IRQ context */ + disable_irq_nosync(priv->an_irq); + + queue_work(priv->an_workqueue, &priv->an_irq_work); + + return IRQ_HANDLED; +} + +static void amd_xgbe_an_irq_work(struct work_struct *work) +{ + struct amd_xgbe_phy_priv *priv = container_of(work, + struct amd_xgbe_phy_priv, + an_irq_work); + + /* Avoid a race between enabling the IRQ and exiting the work by + * waiting for the work to finish and then queueing it + */ + flush_work(&priv->an_work); + queue_work(priv->an_workqueue, &priv->an_work); } static void amd_xgbe_an_state_machine(struct work_struct *work) @@ -900,76 +948,161 @@ static void amd_xgbe_an_state_machine(struct work_struct *work) struct amd_xgbe_phy_priv, an_work); struct phy_device *phydev = priv->phydev; - enum amd_xgbe_phy_an cur_state; - int sleep; - unsigned int an_supported = 0; + enum amd_xgbe_phy_an cur_state = priv->an_state; + int int_reg, int_mask; - /* Start in KX mode */ - if (amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX)) + mutex_lock(&priv->an_mutex); + + /* Read the interrupt */ + int_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT); + if (!int_reg) + goto out; + +next_int: + if (int_reg < 0) { priv->an_state = AMD_XGBE_AN_ERROR; - - while (1) { - mutex_lock(&priv->an_mutex); - - cur_state = priv->an_state; - - switch (priv->an_state) { - case AMD_XGBE_AN_START: - an_supported = 0; - priv->parallel_detect = 0; - priv->an_state = amd_xgbe_an_start(phydev); - break; - - case AMD_XGBE_AN_EVENT: - priv->an_state = amd_xgbe_an_event(phydev); - break; - - case AMD_XGBE_AN_PAGE_RECEIVED: - priv->an_state = amd_xgbe_an_page_received(phydev); - an_supported++; - break; - - case AMD_XGBE_AN_INCOMPAT_LINK: - priv->an_state = amd_xgbe_an_incompat_link(phydev); - break; - - case AMD_XGBE_AN_COMPLETE: - priv->parallel_detect = an_supported ? 0 : 1; - netdev_info(phydev->attached_dev, "%s successful\n", - an_supported ? "Auto negotiation" - : "Parallel detection"); - /* fall through */ - - case AMD_XGBE_AN_NO_LINK: - case AMD_XGBE_AN_EXIT: - goto exit_unlock; - - default: - priv->an_state = AMD_XGBE_AN_ERROR; - } - - if (priv->an_state == AMD_XGBE_AN_ERROR) { - netdev_err(phydev->attached_dev, - "error during auto-negotiation, state=%u\n", - cur_state); - goto exit_unlock; - } - - sleep = (priv->an_state == AMD_XGBE_AN_EVENT) ? 1 : 0; - - mutex_unlock(&priv->an_mutex); - - if (sleep) - usleep_range(20, 50); + int_mask = XGBE_AN_INT_MASK; + } else if (int_reg & XGBE_AN_PG_RCV) { + priv->an_state = AMD_XGBE_AN_PAGE_RECEIVED; + int_mask = XGBE_AN_PG_RCV; + } else if (int_reg & XGBE_AN_INC_LINK) { + priv->an_state = AMD_XGBE_AN_INCOMPAT_LINK; + int_mask = XGBE_AN_INC_LINK; + } else if (int_reg & XGBE_AN_INT_CMPLT) { + priv->an_state = AMD_XGBE_AN_COMPLETE; + int_mask = XGBE_AN_INT_CMPLT; + } else { + priv->an_state = AMD_XGBE_AN_ERROR; + int_mask = 0; } -exit_unlock: + /* Clear the interrupt to be processed */ + int_reg &= ~int_mask; + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, int_reg); + priv->an_result = priv->an_state; - priv->an_state = AMD_XGBE_AN_READY; + +again: + cur_state = priv->an_state; + + switch (priv->an_state) { + case AMD_XGBE_AN_READY: + priv->an_supported = 0; + break; + + case AMD_XGBE_AN_PAGE_RECEIVED: + priv->an_state = amd_xgbe_an_page_received(phydev); + priv->an_supported++; + break; + + case AMD_XGBE_AN_INCOMPAT_LINK: + priv->an_supported = 0; + priv->parallel_detect = 0; + priv->an_state = amd_xgbe_an_incompat_link(phydev); + break; + + case AMD_XGBE_AN_COMPLETE: + priv->parallel_detect = priv->an_supported ? 0 : 1; + netdev_dbg(phydev->attached_dev, "%s successful\n", + priv->an_supported ? "Auto negotiation" + : "Parallel detection"); + break; + + case AMD_XGBE_AN_NO_LINK: + break; + + default: + priv->an_state = AMD_XGBE_AN_ERROR; + } + + if (priv->an_state == AMD_XGBE_AN_NO_LINK) { + int_reg = 0; + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); + } else if (priv->an_state == AMD_XGBE_AN_ERROR) { + netdev_err(phydev->attached_dev, + "error during auto-negotiation, state=%u\n", + cur_state); + + int_reg = 0; + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); + } + + if (priv->an_state >= AMD_XGBE_AN_COMPLETE) { + priv->an_result = priv->an_state; + priv->an_state = AMD_XGBE_AN_READY; + priv->kr_state = AMD_XGBE_RX_BPA; + priv->kx_state = AMD_XGBE_RX_BPA; + } + + if (cur_state != priv->an_state) + goto again; + + if (int_reg) + goto next_int; + +out: + enable_irq(priv->an_irq); mutex_unlock(&priv->an_mutex); } +static int amd_xgbe_an_init(struct phy_device *phydev) +{ + int ret; + + /* Set up Advertisement register 3 first */ + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); + if (ret < 0) + return ret; + + if (phydev->supported & SUPPORTED_10000baseR_FEC) + ret |= 0xc000; + else + ret &= ~0xc000; + + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, ret); + + /* Set up Advertisement register 2 next */ + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); + if (ret < 0) + return ret; + + if (phydev->supported & SUPPORTED_10000baseKR_Full) + ret |= 0x80; + else + ret &= ~0x80; + + if ((phydev->supported & SUPPORTED_1000baseKX_Full) || + (phydev->supported & SUPPORTED_2500baseX_Full)) + ret |= 0x20; + else + ret &= ~0x20; + + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, ret); + + /* Set up Advertisement register 1 last */ + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); + if (ret < 0) + return ret; + + if (phydev->supported & SUPPORTED_Pause) + ret |= 0x400; + else + ret &= ~0x400; + + if (phydev->supported & SUPPORTED_Asym_Pause) + ret |= 0x800; + else + ret &= ~0x800; + + /* We don't intend to perform XNP */ + ret &= ~XNP_NP_EXCHANGE; + + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, ret); + + return 0; +} + static int amd_xgbe_phy_soft_reset(struct phy_device *phydev) { int count, ret; @@ -992,20 +1125,57 @@ static int amd_xgbe_phy_soft_reset(struct phy_device *phydev) if (ret & MDIO_CTRL1_RESET) return -ETIMEDOUT; - /* Make sure the XPCS and SerDes are in compatible states */ - return amd_xgbe_phy_xgmii_mode(phydev); + /* Disable auto-negotiation for now */ + ret = amd_xgbe_phy_disable_an(phydev); + if (ret < 0) + return ret; + + /* Clear auto-negotiation interrupts */ + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); + + return 0; } static int amd_xgbe_phy_config_init(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv = phydev->priv; + struct net_device *netdev = phydev->attached_dev; + int ret; + + if (!priv->an_irq_allocated) { + /* Allocate the auto-negotiation workqueue and interrupt */ + snprintf(priv->an_irq_name, sizeof(priv->an_irq_name) - 1, + "%s-pcs", netdev_name(netdev)); + + priv->an_workqueue = + create_singlethread_workqueue(priv->an_irq_name); + if (!priv->an_workqueue) { + netdev_err(netdev, "phy workqueue creation failed\n"); + return -ENOMEM; + } + + ret = devm_request_irq(priv->dev, priv->an_irq, + amd_xgbe_an_isr, 0, priv->an_irq_name, + priv); + if (ret) { + netdev_err(netdev, "phy irq request failed\n"); + destroy_workqueue(priv->an_workqueue); + return ret; + } + + priv->an_irq_allocated = 1; + } + + ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_ABILITY); + if (ret < 0) + return ret; + priv->fec_ability = ret & XGBE_PHY_FEC_MASK; /* Initialize supported features */ phydev->supported = SUPPORTED_Autoneg; phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; phydev->supported |= SUPPORTED_Backplane; - phydev->supported |= SUPPORTED_10000baseKR_Full | - SUPPORTED_10000baseR_FEC; + phydev->supported |= SUPPORTED_10000baseKR_Full; switch (priv->speed_set) { case AMD_XGBE_PHY_SPEEDSET_1000_10000: phydev->supported |= SUPPORTED_1000baseKX_Full; @@ -1014,11 +1184,33 @@ static int amd_xgbe_phy_config_init(struct phy_device *phydev) phydev->supported |= SUPPORTED_2500baseX_Full; break; } + + if (priv->fec_ability & XGBE_PHY_FEC_ENABLE) + phydev->supported |= SUPPORTED_10000baseR_FEC; + phydev->advertising = phydev->supported; - /* Turn off and clear interrupts */ - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); + /* Set initial mode - call the mode setting routines + * directly to insure we are properly configured + */ + if (phydev->supported & SUPPORTED_10000baseKR_Full) + ret = amd_xgbe_phy_xgmii_mode(phydev); + else if (phydev->supported & SUPPORTED_1000baseKX_Full) + ret = amd_xgbe_phy_gmii_mode(phydev); + else if (phydev->supported & SUPPORTED_2500baseX_Full) + ret = amd_xgbe_phy_gmii_2500_mode(phydev); + else + ret = -EINVAL; + if (ret < 0) + return ret; + + /* Set up advertisement registers based on current settings */ + ret = amd_xgbe_an_init(phydev); + if (ret) + return ret; + + /* Enable auto-negotiation interrupts */ + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07); return 0; } @@ -1028,25 +1220,19 @@ static int amd_xgbe_phy_setup_forced(struct phy_device *phydev) int ret; /* Disable auto-negotiation */ - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); + ret = amd_xgbe_phy_disable_an(phydev); if (ret < 0) return ret; - ret &= ~MDIO_AN_CTRL1_ENABLE; - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret); - /* Validate/Set specified speed */ switch (phydev->speed) { case SPEED_10000: - ret = amd_xgbe_phy_xgmii_mode(phydev); + ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR); break; case SPEED_2500: - ret = amd_xgbe_phy_gmii_2500_mode(phydev); - break; - case SPEED_1000: - ret = amd_xgbe_phy_gmii_mode(phydev); + ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX); break; default: @@ -1066,10 +1252,11 @@ static int amd_xgbe_phy_setup_forced(struct phy_device *phydev) return 0; } -static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) +static int __amd_xgbe_phy_config_aneg(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv = phydev->priv; u32 mmd_mask = phydev->c45_ids.devices_in_package; + int ret; if (phydev->autoneg != AUTONEG_ENABLE) return amd_xgbe_phy_setup_forced(phydev); @@ -1078,56 +1265,79 @@ static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) if (!(mmd_mask & MDIO_DEVS_AN)) return -EINVAL; - /* Start/Restart the auto-negotiation state machine */ - mutex_lock(&priv->an_mutex); + /* Disable auto-negotiation interrupt */ + disable_irq(priv->an_irq); + + /* Start auto-negotiation in a supported mode */ + if (phydev->supported & SUPPORTED_10000baseKR_Full) + ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR); + else if ((phydev->supported & SUPPORTED_1000baseKX_Full) || + (phydev->supported & SUPPORTED_2500baseX_Full)) + ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX); + else + ret = -EINVAL; + if (ret < 0) { + enable_irq(priv->an_irq); + return ret; + } + + /* Disable and stop any in progress auto-negotiation */ + ret = amd_xgbe_phy_disable_an(phydev); + if (ret < 0) + return ret; + + /* Clear any auto-negotitation interrupts */ + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); + priv->an_result = AMD_XGBE_AN_READY; - priv->an_state = AMD_XGBE_AN_START; - priv->kr_state = AMD_XGBE_RX_READY; - priv->kx_state = AMD_XGBE_RX_READY; + priv->an_state = AMD_XGBE_AN_READY; + priv->kr_state = AMD_XGBE_RX_BPA; + priv->kx_state = AMD_XGBE_RX_BPA; + + /* Re-enable auto-negotiation interrupt */ + enable_irq(priv->an_irq); + + /* Set up advertisement registers based on current settings */ + ret = amd_xgbe_an_init(phydev); + if (ret) + return ret; + + /* Enable and start auto-negotiation */ + return amd_xgbe_phy_restart_an(phydev); +} + +static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) +{ + struct amd_xgbe_phy_priv *priv = phydev->priv; + int ret; + + mutex_lock(&priv->an_mutex); + + ret = __amd_xgbe_phy_config_aneg(phydev); + mutex_unlock(&priv->an_mutex); - queue_work(priv->an_workqueue, &priv->an_work); - - return 0; + return ret; } static int amd_xgbe_phy_aneg_done(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv = phydev->priv; - enum amd_xgbe_phy_an state; - mutex_lock(&priv->an_mutex); - state = priv->an_result; - mutex_unlock(&priv->an_mutex); - - return (state == AMD_XGBE_AN_COMPLETE); + return (priv->an_result == AMD_XGBE_AN_COMPLETE); } static int amd_xgbe_phy_update_link(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv = phydev->priv; - enum amd_xgbe_phy_an state; - unsigned int check_again, autoneg; int ret; /* If we're doing auto-negotiation don't report link down */ - mutex_lock(&priv->an_mutex); - state = priv->an_state; - mutex_unlock(&priv->an_mutex); - - if (state != AMD_XGBE_AN_READY) { + if (priv->an_state != AMD_XGBE_AN_READY) { phydev->link = 1; return 0; } - /* Since the device can be in the wrong mode when a link is - * (re-)established (cable connected after the interface is - * up, etc.), the link status may report no link. If there - * is no link, try switching modes and checking the status - * again if auto negotiation is enabled. - */ - check_again = (phydev->autoneg == AUTONEG_ENABLE) ? 1 : 0; -again: /* Link status is latched low, so read once to clear * and then read again to get current state */ @@ -1141,25 +1351,6 @@ again: phydev->link = (ret & MDIO_STAT1_LSTATUS) ? 1 : 0; - if (!phydev->link) { - if (check_again) { - ret = amd_xgbe_phy_switch_mode(phydev); - if (ret < 0) - return ret; - check_again = 0; - goto again; - } - } - - autoneg = (phydev->link && !priv->link) ? 1 : 0; - priv->link = phydev->link; - if (autoneg) { - /* Link is (back) up, re-start auto-negotiation */ - ret = amd_xgbe_phy_config_aneg(phydev); - if (ret < 0) - return ret; - } - return 0; } @@ -1249,6 +1440,7 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev) static int amd_xgbe_phy_suspend(struct phy_device *phydev) { + struct amd_xgbe_phy_priv *priv = phydev->priv; int ret; mutex_lock(&phydev->lock); @@ -1257,6 +1449,8 @@ static int amd_xgbe_phy_suspend(struct phy_device *phydev) if (ret < 0) goto unlock; + priv->lpm_ctrl = ret; + ret |= MDIO_CTRL1_LPOWER; phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); @@ -1270,69 +1464,106 @@ unlock: static int amd_xgbe_phy_resume(struct phy_device *phydev) { - int ret; + struct amd_xgbe_phy_priv *priv = phydev->priv; mutex_lock(&phydev->lock); - ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); - if (ret < 0) - goto unlock; + priv->lpm_ctrl &= ~MDIO_CTRL1_LPOWER; + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, priv->lpm_ctrl); - ret &= ~MDIO_CTRL1_LPOWER; - phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); - - ret = 0; - -unlock: mutex_unlock(&phydev->lock); - return ret; + return 0; +} + +static unsigned int amd_xgbe_phy_resource_count(struct platform_device *pdev, + unsigned int type) +{ + unsigned int count; + int i; + + for (i = 0, count = 0; i < pdev->num_resources; i++) { + struct resource *r = &pdev->resource[i]; + + if (type == resource_type(r)) + count++; + } + + return count; } static int amd_xgbe_phy_probe(struct phy_device *phydev) { struct amd_xgbe_phy_priv *priv; - struct platform_device *pdev; - struct device *dev; - char *wq_name; - const __be32 *property; - unsigned int speed_set; + struct platform_device *phy_pdev; + struct device *dev, *phy_dev; + unsigned int phy_resnum, phy_irqnum; int ret; - if (!phydev->dev.of_node) + if (!phydev->bus || !phydev->bus->parent) return -EINVAL; - pdev = of_find_device_by_node(phydev->dev.of_node); - if (!pdev) - return -EINVAL; - dev = &pdev->dev; - - wq_name = kasprintf(GFP_KERNEL, "%s-amd-xgbe-phy", phydev->bus->name); - if (!wq_name) { - ret = -ENOMEM; - goto err_pdev; - } + dev = phydev->bus->parent; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_name; - } + if (!priv) + return -ENOMEM; - priv->pdev = pdev; + priv->pdev = to_platform_device(dev); + priv->adev = ACPI_COMPANION(dev); priv->dev = dev; priv->phydev = phydev; + mutex_init(&priv->an_mutex); + INIT_WORK(&priv->an_irq_work, amd_xgbe_an_irq_work); + INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine); + + if (!priv->adev || acpi_disabled) { + struct device_node *bus_node; + struct device_node *phy_node; + + bus_node = priv->dev->of_node; + phy_node = of_parse_phandle(bus_node, "phy-handle", 0); + if (!phy_node) { + dev_err(dev, "unable to parse phy-handle\n"); + ret = -EINVAL; + goto err_priv; + } + + phy_pdev = of_find_device_by_node(phy_node); + of_node_put(phy_node); + + if (!phy_pdev) { + dev_err(dev, "unable to obtain phy device\n"); + ret = -EINVAL; + goto err_priv; + } + + phy_resnum = 0; + phy_irqnum = 0; + } else { + /* In ACPI, the XGBE and PHY resources are the grouped + * together with the PHY resources at the end + */ + phy_pdev = priv->pdev; + phy_resnum = amd_xgbe_phy_resource_count(phy_pdev, + IORESOURCE_MEM) - 3; + phy_irqnum = amd_xgbe_phy_resource_count(phy_pdev, + IORESOURCE_IRQ) - 1; + } + phy_dev = &phy_pdev->dev; /* Get the device mmio areas */ - priv->rxtx_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->rxtx_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, + phy_resnum++); priv->rxtx_regs = devm_ioremap_resource(dev, priv->rxtx_res); if (IS_ERR(priv->rxtx_regs)) { dev_err(dev, "rxtx ioremap failed\n"); ret = PTR_ERR(priv->rxtx_regs); - goto err_priv; + goto err_put; } - priv->sir0_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + priv->sir0_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, + phy_resnum++); priv->sir0_regs = devm_ioremap_resource(dev, priv->sir0_res); if (IS_ERR(priv->sir0_regs)) { dev_err(dev, "sir0 ioremap failed\n"); @@ -1340,7 +1571,8 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) goto err_rxtx; } - priv->sir1_res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + priv->sir1_res = platform_get_resource(phy_pdev, IORESOURCE_MEM, + phy_resnum++); priv->sir1_regs = devm_ioremap_resource(dev, priv->sir1_res); if (IS_ERR(priv->sir1_regs)) { dev_err(dev, "sir1 ioremap failed\n"); @@ -1348,40 +1580,98 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) goto err_sir0; } - /* Get the device speed set property */ - speed_set = 0; - property = of_get_property(dev->of_node, XGBE_PHY_SPEEDSET_PROPERTY, - NULL); - if (property) - speed_set = be32_to_cpu(*property); + /* Get the auto-negotiation interrupt */ + ret = platform_get_irq(phy_pdev, phy_irqnum); + if (ret < 0) { + dev_err(dev, "platform_get_irq failed\n"); + goto err_sir1; + } + priv->an_irq = ret; - switch (speed_set) { - case 0: - priv->speed_set = AMD_XGBE_PHY_SPEEDSET_1000_10000; - break; - case 1: - priv->speed_set = AMD_XGBE_PHY_SPEEDSET_2500_10000; + /* Get the device speed set property */ + ret = device_property_read_u32(phy_dev, XGBE_PHY_SPEEDSET_PROPERTY, + &priv->speed_set); + if (ret) { + dev_err(dev, "invalid %s property\n", + XGBE_PHY_SPEEDSET_PROPERTY); + goto err_sir1; + } + + switch (priv->speed_set) { + case AMD_XGBE_PHY_SPEEDSET_1000_10000: + case AMD_XGBE_PHY_SPEEDSET_2500_10000: break; default: - dev_err(dev, "invalid amd,speed-set property\n"); + dev_err(dev, "invalid %s property\n", + XGBE_PHY_SPEEDSET_PROPERTY); ret = -EINVAL; goto err_sir1; } - priv->link = 1; + if (device_property_present(phy_dev, XGBE_PHY_BLWC_PROPERTY)) { + ret = device_property_read_u32_array(phy_dev, + XGBE_PHY_BLWC_PROPERTY, + priv->serdes_blwc, + XGBE_PHY_SPEEDS); + if (ret) { + dev_err(dev, "invalid %s property\n", + XGBE_PHY_BLWC_PROPERTY); + goto err_sir1; + } + } else { + memcpy(priv->serdes_blwc, amd_xgbe_phy_serdes_blwc, + sizeof(priv->serdes_blwc)); + } - mutex_init(&priv->an_mutex); - INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine); - priv->an_workqueue = create_singlethread_workqueue(wq_name); - if (!priv->an_workqueue) { - ret = -ENOMEM; - goto err_sir1; + if (device_property_present(phy_dev, XGBE_PHY_CDR_RATE_PROPERTY)) { + ret = device_property_read_u32_array(phy_dev, + XGBE_PHY_CDR_RATE_PROPERTY, + priv->serdes_cdr_rate, + XGBE_PHY_SPEEDS); + if (ret) { + dev_err(dev, "invalid %s property\n", + XGBE_PHY_CDR_RATE_PROPERTY); + goto err_sir1; + } + } else { + memcpy(priv->serdes_cdr_rate, amd_xgbe_phy_serdes_cdr_rate, + sizeof(priv->serdes_cdr_rate)); + } + + if (device_property_present(phy_dev, XGBE_PHY_PQ_SKEW_PROPERTY)) { + ret = device_property_read_u32_array(phy_dev, + XGBE_PHY_PQ_SKEW_PROPERTY, + priv->serdes_pq_skew, + XGBE_PHY_SPEEDS); + if (ret) { + dev_err(dev, "invalid %s property\n", + XGBE_PHY_PQ_SKEW_PROPERTY); + goto err_sir1; + } + } else { + memcpy(priv->serdes_pq_skew, amd_xgbe_phy_serdes_pq_skew, + sizeof(priv->serdes_pq_skew)); + } + + if (device_property_present(phy_dev, XGBE_PHY_TX_AMP_PROPERTY)) { + ret = device_property_read_u32_array(phy_dev, + XGBE_PHY_TX_AMP_PROPERTY, + priv->serdes_tx_amp, + XGBE_PHY_SPEEDS); + if (ret) { + dev_err(dev, "invalid %s property\n", + XGBE_PHY_TX_AMP_PROPERTY); + goto err_sir1; + } + } else { + memcpy(priv->serdes_tx_amp, amd_xgbe_phy_serdes_tx_amp, + sizeof(priv->serdes_tx_amp)); } phydev->priv = priv; - kfree(wq_name); - of_dev_put(pdev); + if (!priv->adev || acpi_disabled) + platform_device_put(phy_pdev); return 0; @@ -1400,15 +1690,13 @@ err_rxtx: devm_release_mem_region(dev, priv->rxtx_res->start, resource_size(priv->rxtx_res)); +err_put: + if (!priv->adev || acpi_disabled) + platform_device_put(phy_pdev); + err_priv: devm_kfree(dev, priv); -err_name: - kfree(wq_name); - -err_pdev: - of_dev_put(pdev); - return ret; } @@ -1417,13 +1705,12 @@ static void amd_xgbe_phy_remove(struct phy_device *phydev) struct amd_xgbe_phy_priv *priv = phydev->priv; struct device *dev = priv->dev; - /* Stop any in process auto-negotiation */ - mutex_lock(&priv->an_mutex); - priv->an_state = AMD_XGBE_AN_EXIT; - mutex_unlock(&priv->an_mutex); + if (priv->an_irq_allocated) { + devm_free_irq(dev, priv->an_irq, priv); - flush_workqueue(priv->an_workqueue); - destroy_workqueue(priv->an_workqueue); + flush_workqueue(priv->an_workqueue); + destroy_workqueue(priv->an_workqueue); + } /* Release resources */ devm_iounmap(dev, priv->sir1_regs); diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index 3ad0e6e16c39..a08a3c78ba97 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -168,7 +168,7 @@ int fixed_phy_set_link_update(struct phy_device *phydev, struct fixed_mdio_bus *fmb = &platform_fmb; struct fixed_phy *fp; - if (!link_update || !phydev || !phydev->bus) + if (!phydev || !phydev->bus) return -EINVAL; list_for_each_entry(fp, &fmb->phys, node) { diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 50051f271b10..095ef3fe369a 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -443,9 +443,13 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) if (!drv || !phydrv->suspend) return false; - /* PHY not attached? May suspend. */ + /* PHY not attached? May suspend if the PHY has not already been + * suspended as part of a prior call to phy_disconnect() -> + * phy_detach() -> phy_suspend() because the parent netdev might be the + * MDIO bus driver and clock gated at this point. + */ if (!netdev) - return true; + return !phydev->suspended; /* Don't suspend PHY if the attched netdev parent may wakeup. * The parent may point to a PCI device, as in tg3 driver. @@ -465,7 +469,6 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) static int mdio_bus_suspend(struct device *dev) { - struct phy_driver *phydrv = to_phy_driver(dev->driver); struct phy_device *phydev = to_phy_device(dev); /* We must stop the state machine manually, otherwise it stops out of @@ -479,19 +482,18 @@ static int mdio_bus_suspend(struct device *dev) if (!mdio_bus_phy_may_suspend(phydev)) return 0; - return phydrv->suspend(phydev); + return phy_suspend(phydev); } static int mdio_bus_resume(struct device *dev) { - struct phy_driver *phydrv = to_phy_driver(dev->driver); struct phy_device *phydev = to_phy_device(dev); int ret; if (!mdio_bus_phy_may_suspend(phydev)) goto no_resume; - ret = phydrv->resume(phydev); + ret = phy_resume(phydev); if (ret < 0) return ret; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 767cd110f496..cdcac6aa4260 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -439,6 +439,9 @@ int phy_start_aneg(struct phy_device *phydev) if (AUTONEG_DISABLE == phydev->autoneg) phy_sanitize_settings(phydev); + /* Invalidate LP advertising flags */ + phydev->lp_advertising = 0; + err = phydev->drv->config_aneg(phydev); if (err < 0) goto out_unlock; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 3fc91e89f5a5..bdfe51fc3a65 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -699,6 +699,7 @@ int phy_suspend(struct phy_device *phydev) { struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver); struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; + int ret = 0; /* If the device has WOL enabled, we cannot suspend the PHY */ phy_ethtool_get_wol(phydev, &wol); @@ -706,18 +707,31 @@ int phy_suspend(struct phy_device *phydev) return -EBUSY; if (phydrv->suspend) - return phydrv->suspend(phydev); - return 0; + ret = phydrv->suspend(phydev); + + if (ret) + return ret; + + phydev->suspended = true; + + return ret; } EXPORT_SYMBOL(phy_suspend); int phy_resume(struct phy_device *phydev) { struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver); + int ret = 0; if (phydrv->resume) - return phydrv->resume(phydev); - return 0; + ret = phydrv->resume(phydev); + + if (ret) + return ret; + + phydev->suspended = false; + + return ret; } EXPORT_SYMBOL(phy_resume); diff --git a/drivers/net/ppp/ppp_deflate.c b/drivers/net/ppp/ppp_deflate.c index 602c625d95d5..b5edc7f96a39 100644 --- a/drivers/net/ppp/ppp_deflate.c +++ b/drivers/net/ppp/ppp_deflate.c @@ -246,7 +246,7 @@ static int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf, /* * See if we managed to reduce the size of the packet. */ - if (olen < isize) { + if (olen < isize && olen <= osize) { state->stats.comp_bytes += olen; state->stats.comp_packets++; } else { diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index f7ff493f1e73..0e62274e884a 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -176,7 +177,6 @@ static int __team_option_inst_add(struct team *team, struct team_option *option, static int __team_option_inst_add_option(struct team *team, struct team_option *option) { - struct team_port *port; int err; if (!option->per_port) { @@ -184,12 +184,6 @@ static int __team_option_inst_add_option(struct team *team, if (err) goto inst_del_option; } - - list_for_each_entry(port, &team->port_list, list) { - err = __team_option_inst_add(team, option, port); - if (err) - goto inst_del_option; - } return 0; inst_del_option: @@ -1932,7 +1926,7 @@ static netdev_features_t team_fix_features(struct net_device *dev, struct team *team = netdev_priv(dev); netdev_features_t mask; - mask = features; + mask = features | NETIF_F_HW_SWITCH_OFFLOAD; features &= ~NETIF_F_ONE_FOR_ALL; features |= NETIF_F_ALL_FOR_ALL; @@ -1982,6 +1976,8 @@ static const struct net_device_ops team_netdev_ops = { .ndo_del_slave = team_del_slave, .ndo_fix_features = team_fix_features, .ndo_change_carrier = team_change_carrier, + .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink, + .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink, }; /*********************** diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 8c8dc16839a7..857dca47bf80 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -65,7 +65,6 @@ #include #include #include -#include #include #include #include @@ -124,10 +123,9 @@ struct tap_filter { unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN]; }; -/* DEFAULT_MAX_NUM_RSS_QUEUES were chosen to let the rx/tx queues allocated for - * the netdevice to be fit in one page. So we can make sure the success of - * memory allocation. TODO: increase the limit. */ -#define MAX_TAP_QUEUES DEFAULT_MAX_NUM_RSS_QUEUES +/* MAX_TAP_QUEUES 256 is chosen to allow rx/tx queues to be equal + * to max number of VCPUs in guest. */ +#define MAX_TAP_QUEUES 256 #define MAX_TAP_FLOWS 4096 #define TUN_FLOW_EXPIRE (3 * HZ) @@ -187,7 +185,7 @@ struct tun_struct { struct net_device *dev; netdev_features_t set_features; #define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \ - NETIF_F_TSO6) + NETIF_F_TSO6|NETIF_F_UFO) int vnet_hdr_sz; int sndbuf; @@ -258,7 +256,6 @@ static void tun_flow_delete(struct tun_struct *tun, struct tun_flow_entry *e) { tun_debug(KERN_INFO, tun, "delete flow: hash %u index %u\n", e->rxhash, e->queue_index); - sock_rps_reset_flow_hash(e->rps_rxhash); hlist_del_rcu(&e->hash_link); kfree_rcu(e, rcu); --tun->flow_count; @@ -375,10 +372,8 @@ unlock: */ static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash) { - if (unlikely(e->rps_rxhash != hash)) { - sock_rps_reset_flow_hash(e->rps_rxhash); + if (unlikely(e->rps_rxhash != hash)) e->rps_rxhash = hash; - } } /* We try to identify a flow through its rxhash first. The reason that @@ -1167,8 +1162,6 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, break; } - skb_reset_network_header(skb); - if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) { pr_debug("GSO!\n"); switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { @@ -1179,20 +1172,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; break; case VIRTIO_NET_HDR_GSO_UDP: - { - static bool warned; - - if (!warned) { - warned = true; - netdev_warn(tun->dev, - "%s: using disabled UFO feature; please fix this program\n", - current->comm); - } skb_shinfo(skb)->gso_type = SKB_GSO_UDP; - if (skb->protocol == htons(ETH_P_IPV6)) - ipv6_proxy_select_ident(skb); break; - } default: tun->dev->stats.rx_frame_errors++; kfree_skb(skb); @@ -1221,6 +1202,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; } + skb_reset_network_header(skb); skb_probe_transport_header(skb, 0); rxhash = skb_get_hash(skb); @@ -1261,7 +1243,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, int vlan_hlen = 0; int vnet_hdr_sz = 0; - if (vlan_tx_tag_present(skb)) + if (skb_vlan_tag_present(skb)) vlan_hlen = VLAN_HLEN; if (tun->flags & IFF_VNET_HDR) @@ -1298,6 +1280,8 @@ static ssize_t tun_put_user(struct tun_struct *tun, gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4; else if (sinfo->gso_type & SKB_GSO_TCPV6) gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6; + else if (sinfo->gso_type & SKB_GSO_UDP) + gso.gso_type = VIRTIO_NET_HDR_GSO_UDP; else { pr_err("unexpected GSO type: " "0x%x, gso_size %d, hdr_len %d\n", @@ -1338,7 +1322,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, } veth; veth.h_vlan_proto = skb->vlan_proto; - veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); + veth.h_vlan_TCI = htons(skb_vlan_tag_get(skb)); vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto); @@ -1380,7 +1364,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, skb = __skb_recv_datagram(tfile->socket.sk, noblock ? MSG_DONTWAIT : 0, &peeked, &off, &err); if (!skb) - return 0; + return err; ret = tun_put_user(tun, tfile, skb, to); if (unlikely(ret < 0)) @@ -1501,7 +1485,7 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock, goto out; } ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT); - if (ret > total_len) { + if (ret > (ssize_t)total_len) { m->msg_flags |= MSG_TRUNC; ret = flags & MSG_TRUNC ? ret : total_len; } @@ -1566,6 +1550,17 @@ static DEVICE_ATTR(tun_flags, 0444, tun_show_flags, NULL); static DEVICE_ATTR(owner, 0444, tun_show_owner, NULL); static DEVICE_ATTR(group, 0444, tun_show_group, NULL); +static struct attribute *tun_dev_attrs[] = { + &dev_attr_tun_flags.attr, + &dev_attr_owner.attr, + &dev_attr_group.attr, + NULL +}; + +static const struct attribute_group tun_attr_group = { + .attrs = tun_dev_attrs +}; + static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) { struct tun_struct *tun; @@ -1646,6 +1641,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) dev_net_set(dev, net); dev->rtnl_link_ops = &tun_link_ops; dev->ifindex = tfile->ifindex; + dev->sysfs_groups[0] = &tun_attr_group; tun = netdev_priv(dev); tun->dev = dev; @@ -1681,11 +1677,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) err = register_netdevice(tun->dev); if (err < 0) goto err_detach; - - if (device_create_file(&tun->dev->dev, &dev_attr_tun_flags) || - device_create_file(&tun->dev->dev, &dev_attr_owner) || - device_create_file(&tun->dev->dev, &dev_attr_group)) - pr_err("Failed to create tun sysfs files\n"); } netif_carrier_on(tun->dev); @@ -1746,6 +1737,11 @@ static int set_offload(struct tun_struct *tun, unsigned long arg) features |= NETIF_F_TSO6; arg &= ~(TUN_F_TSO4|TUN_F_TSO6); } + + if (arg & TUN_F_UFO) { + features |= NETIF_F_UFO; + arg &= ~TUN_F_UFO; + } } /* This gives the user a way to test for new features in future by diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 9c5aa922a9f4..6b8efcabb816 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -58,7 +58,6 @@ #include #include #include -#include #include #include #include @@ -154,6 +153,7 @@ struct hso_net { struct hso_device *parent; struct net_device *net; struct rfkill *rfkill; + char name[24]; struct usb_endpoint_descriptor *in_endp; struct usb_endpoint_descriptor *out_endp; @@ -274,7 +274,6 @@ struct hso_device { u8 usb_gone; struct work_struct async_get_intf; struct work_struct async_put_intf; - struct work_struct reset_device; struct usb_device *usb; struct usb_interface *interface; @@ -340,7 +339,6 @@ static void async_put_intf(struct work_struct *data); static int hso_put_activity(struct hso_device *hso_dev); static int hso_get_activity(struct hso_device *hso_dev); static void tiocmget_intr_callback(struct urb *urb); -static void reset_device(struct work_struct *data); /*****************************************************************************/ /* Helping functions */ /*****************************************************************************/ @@ -533,6 +531,13 @@ static ssize_t hso_sysfs_show_porttype(struct device *dev, } static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL); +static struct attribute *hso_serial_dev_attrs[] = { + &dev_attr_hsotype.attr, + NULL +}; + +ATTRIBUTE_GROUPS(hso_serial_dev); + static int hso_urb_to_index(struct hso_serial *serial, struct urb *urb) { int idx; @@ -696,7 +701,7 @@ static void handle_usb_error(int status, const char *function, case -ETIMEDOUT: explanation = "protocol error"; if (hso_dev) - schedule_work(&hso_dev->reset_device); + usb_queue_reset_device(hso_dev->interface); break; default: explanation = "unknown status"; @@ -1271,7 +1276,6 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) goto err_out; D1("Opening %d", serial->minor); - kref_get(&serial->parent->ref); /* setup */ tty->driver_data = serial; @@ -1290,7 +1294,8 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) if (result) { hso_stop_serial_device(serial->parent); serial->port.count--; - kref_put(&serial->parent->ref, hso_serial_ref_free); + } else { + kref_get(&serial->parent->ref); } } else { D1("Port was already open"); @@ -1340,8 +1345,6 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) usb_autopm_put_interface(serial->parent->interface); mutex_unlock(&serial->parent->mutex); - - kref_put(&serial->parent->ref, hso_serial_ref_free); } /* close the requested serial port */ @@ -1392,6 +1395,16 @@ static int hso_serial_write_room(struct tty_struct *tty) return room; } +static void hso_serial_cleanup(struct tty_struct *tty) +{ + struct hso_serial *serial = tty->driver_data; + + if (!serial) + return; + + kref_put(&serial->parent->ref, hso_serial_ref_free); +} + /* setup the term */ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) { @@ -2198,8 +2211,8 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) for (i = 0; i < serial->num_rx_urbs; i++) { if (serial->rx_urb[i]) { - usb_kill_urb(serial->rx_urb[i]); - serial->rx_urb_filled[i] = 0; + usb_kill_urb(serial->rx_urb[i]); + serial->rx_urb_filled[i] = 0; } } serial->curr_rx_urb_idx = 0; @@ -2228,15 +2241,15 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) return 0; } +static void hso_serial_tty_unregister(struct hso_serial *serial) +{ + tty_unregister_device(tty_drv, serial->minor); +} + static void hso_serial_common_free(struct hso_serial *serial) { int i; - if (serial->parent->dev) - device_remove_file(serial->parent->dev, &dev_attr_hsotype); - - tty_unregister_device(tty_drv, serial->minor); - for (i = 0; i < serial->num_rx_urbs; i++) { /* unlink and free RX URB */ usb_free_urb(serial->rx_urb[i]); @@ -2246,6 +2259,7 @@ static void hso_serial_common_free(struct hso_serial *serial) /* unlink and free TX URB */ usb_free_urb(serial->tx_urb); + kfree(serial->tx_buffer); kfree(serial->tx_data); tty_port_destroy(&serial->port); } @@ -2264,11 +2278,10 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, goto exit; /* register our minor number */ - serial->parent->dev = tty_port_register_device(&serial->port, tty_drv, - minor, &serial->parent->interface->dev); + serial->parent->dev = tty_port_register_device_attr(&serial->port, + tty_drv, minor, &serial->parent->interface->dev, + serial->parent, hso_serial_dev_groups); dev = serial->parent->dev; - dev_set_drvdata(dev, serial->parent); - i = device_create_file(dev, &dev_attr_hsotype); /* fill in specific data for later use */ serial->minor = minor; @@ -2316,6 +2329,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, return 0; exit: + hso_serial_tty_unregister(serial); hso_serial_common_free(serial); return -1; } @@ -2338,7 +2352,6 @@ static struct hso_device *hso_create_device(struct usb_interface *intf, INIT_WORK(&hso_dev->async_get_intf, async_get_intf); INIT_WORK(&hso_dev->async_put_intf, async_put_intf); - INIT_WORK(&hso_dev->reset_device, reset_device); return hso_dev; } @@ -2459,27 +2472,21 @@ static void hso_create_rfkill(struct hso_device *hso_dev, { struct hso_net *hso_net = dev2net(hso_dev); struct device *dev = &hso_net->net->dev; - char *rfkn; + static u32 rfkill_counter; - rfkn = kzalloc(20, GFP_KERNEL); - if (!rfkn) - dev_err(dev, "%s - Out of memory\n", __func__); + snprintf(hso_net->name, sizeof(hso_net->name), "hso-%d", + rfkill_counter++); - snprintf(rfkn, 20, "hso-%d", - interface->altsetting->desc.bInterfaceNumber); - - hso_net->rfkill = rfkill_alloc(rfkn, + hso_net->rfkill = rfkill_alloc(hso_net->name, &interface_to_usbdev(interface)->dev, RFKILL_TYPE_WWAN, &hso_rfkill_ops, hso_dev); if (!hso_net->rfkill) { dev_err(dev, "%s - Out of memory\n", __func__); - kfree(rfkn); return; } if (rfkill_register(hso_net->rfkill) < 0) { rfkill_destroy(hso_net->rfkill); - kfree(rfkn); hso_net->rfkill = NULL; dev_err(dev, "%s - Failed to register rfkill\n", __func__); return; @@ -2594,7 +2601,6 @@ static void hso_free_serial_device(struct hso_device *hso_dev) if (!serial) return; - set_serial_by_index(serial->minor, NULL); hso_serial_common_free(serial); @@ -2684,6 +2690,7 @@ static struct hso_device *hso_create_bulk_serial_device( return hso_dev; exit2: + hso_serial_tty_unregister(serial); hso_serial_common_free(serial); exit: hso_free_tiomget(serial); @@ -3083,26 +3090,6 @@ out: return result; } -static void reset_device(struct work_struct *data) -{ - struct hso_device *hso_dev = - container_of(data, struct hso_device, reset_device); - struct usb_device *usb = hso_dev->usb; - int result; - - if (hso_dev->usb_gone) { - D1("No reset during disconnect\n"); - } else { - result = usb_lock_device_for_reset(usb, hso_dev->interface); - if (result < 0) - D1("unable to lock device for reset: %d\n", result); - else { - usb_reset_device(usb); - usb_unlock_device(usb); - } - } -} - static void hso_serial_ref_free(struct kref *ref) { struct hso_device *hso_dev = container_of(ref, struct hso_device, ref); @@ -3112,18 +3099,22 @@ static void hso_serial_ref_free(struct kref *ref) static void hso_free_interface(struct usb_interface *interface) { - struct hso_serial *hso_dev; + struct hso_serial *serial; int i; for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { if (serial_table[i] && (serial_table[i]->interface == interface)) { - hso_dev = dev2ser(serial_table[i]); - tty_port_tty_hangup(&hso_dev->port, false); - mutex_lock(&hso_dev->parent->mutex); - hso_dev->parent->usb_gone = 1; - mutex_unlock(&hso_dev->parent->mutex); + serial = dev2ser(serial_table[i]); + tty_port_tty_hangup(&serial->port, false); + mutex_lock(&serial->parent->mutex); + serial->parent->usb_gone = 1; + mutex_unlock(&serial->parent->mutex); + cancel_work_sync(&serial_table[i]->async_put_intf); + cancel_work_sync(&serial_table[i]->async_get_intf); + hso_serial_tty_unregister(serial); kref_put(&serial_table[i]->ref, hso_serial_ref_free); + set_serial_by_index(i, NULL); } } @@ -3215,6 +3206,7 @@ static const struct tty_operations hso_serial_ops = { .close = hso_serial_close, .write = hso_serial_write, .write_room = hso_serial_write_room, + .cleanup = hso_serial_cleanup, .ioctl = hso_serial_ioctl, .set_termios = hso_serial_set_termios, .chars_in_buffer = hso_serial_chars_in_buffer, diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 57ec23e8ccfa..5980ac6c48dd 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -27,7 +27,7 @@ #include /* Version Information */ -#define DRIVER_VERSION "v1.07.0 (2014/10/09)" +#define DRIVER_VERSION "v1.08.0 (2015/01/13)" #define DRIVER_AUTHOR "Realtek linux nic maintainers " #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" #define MODULENAME "r8152" @@ -448,6 +448,7 @@ enum rtl_register_content { #define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN) #define RTL8153_RMS RTL8153_MAX_PACKET #define RTL8152_TX_TIMEOUT (5 * HZ) +#define RTL8152_NAPI_WEIGHT 64 /* rtl8152 flags */ enum rtl8152_flags { @@ -457,7 +458,7 @@ enum rtl8152_flags { RTL8152_LINK_CHG, SELECTIVE_SUSPEND, PHY_RESET, - SCHEDULE_TASKLET, + SCHEDULE_NAPI, }; /* Define these values to match your device */ @@ -488,16 +489,16 @@ struct rx_desc { #define RX_LEN_MASK 0x7fff __le32 opts2; -#define RD_UDP_CS (1 << 23) -#define RD_TCP_CS (1 << 22) -#define RD_IPV6_CS (1 << 20) -#define RD_IPV4_CS (1 << 19) +#define RD_UDP_CS BIT(23) +#define RD_TCP_CS BIT(22) +#define RD_IPV6_CS BIT(20) +#define RD_IPV4_CS BIT(19) __le32 opts3; -#define IPF (1 << 23) /* IP checksum fail */ -#define UDPF (1 << 22) /* UDP checksum fail */ -#define TCPF (1 << 21) /* TCP checksum fail */ -#define RX_VLAN_TAG (1 << 16) +#define IPF BIT(23) /* IP checksum fail */ +#define UDPF BIT(22) /* UDP checksum fail */ +#define TCPF BIT(21) /* TCP checksum fail */ +#define RX_VLAN_TAG BIT(16) __le32 opts4; __le32 opts5; @@ -506,24 +507,24 @@ struct rx_desc { struct tx_desc { __le32 opts1; -#define TX_FS (1 << 31) /* First segment of a packet */ -#define TX_LS (1 << 30) /* Final segment of a packet */ -#define GTSENDV4 (1 << 28) -#define GTSENDV6 (1 << 27) +#define TX_FS BIT(31) /* First segment of a packet */ +#define TX_LS BIT(30) /* Final segment of a packet */ +#define GTSENDV4 BIT(28) +#define GTSENDV6 BIT(27) #define GTTCPHO_SHIFT 18 #define GTTCPHO_MAX 0x7fU #define TX_LEN_MAX 0x3ffffU __le32 opts2; -#define UDP_CS (1 << 31) /* Calculate UDP/IP checksum */ -#define TCP_CS (1 << 30) /* Calculate TCP/IP checksum */ -#define IPV4_CS (1 << 29) /* Calculate IPv4 checksum */ -#define IPV6_CS (1 << 28) /* Calculate IPv6 checksum */ +#define UDP_CS BIT(31) /* Calculate UDP/IP checksum */ +#define TCP_CS BIT(30) /* Calculate TCP/IP checksum */ +#define IPV4_CS BIT(29) /* Calculate IPv4 checksum */ +#define IPV6_CS BIT(28) /* Calculate IPv6 checksum */ #define MSS_SHIFT 17 #define MSS_MAX 0x7ffU #define TCPHO_SHIFT 17 #define TCPHO_MAX 0x7ffU -#define TX_VLAN_TAG (1 << 16) +#define TX_VLAN_TAG BIT(16) }; struct r8152; @@ -549,14 +550,14 @@ struct tx_agg { struct r8152 { unsigned long flags; struct usb_device *udev; - struct tasklet_struct tl; + struct napi_struct napi; struct usb_interface *intf; struct net_device *netdev; struct urb *intr_urb; struct tx_agg tx_info[RTL8152_MAX_TX]; struct rx_agg rx_info[RTL8152_MAX_RX]; struct list_head rx_done, tx_free; - struct sk_buff_head tx_queue; + struct sk_buff_head tx_queue, rx_queue; spinlock_t rx_lock, tx_lock; struct delayed_work schedule; struct mii_if_info mii; @@ -580,7 +581,6 @@ struct r8152 { u16 ocp_base; u8 *intr_buff; u8 version; - u8 speed; }; enum rtl_version { @@ -833,9 +833,6 @@ static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data) index &= ~3; } - generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - - data |= __le32_to_cpu(tmp) & ~mask; tmp = __cpu_to_le32(data); generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); @@ -874,9 +871,6 @@ static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data) index &= ~3; } - generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - - data |= __le32_to_cpu(tmp) & ~mask; tmp = __cpu_to_le32(data); generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); @@ -926,12 +920,6 @@ static void sram_write(struct r8152 *tp, u16 addr, u16 data) ocp_reg_write(tp, OCP_SRAM_DATA, data); } -static u16 sram_read(struct r8152 *tp, u16 addr) -{ - ocp_reg_write(tp, OCP_SRAM_ADDR, addr); - return ocp_reg_read(tp, OCP_SRAM_DATA); -} - static int read_mii_word(struct net_device *netdev, int phy_id, int reg) { struct r8152 *tp = netdev_priv(netdev); @@ -1062,7 +1050,7 @@ static void read_bulk_callback(struct urb *urb) spin_lock(&tp->rx_lock); list_add_tail(&agg->list, &tp->rx_done); spin_unlock(&tp->rx_lock); - tasklet_schedule(&tp->tl); + napi_schedule(&tp->napi); return; case -ESHUTDOWN: set_bit(RTL8152_UNPLUG, &tp->flags); @@ -1126,7 +1114,7 @@ static void write_bulk_callback(struct urb *urb) return; if (!skb_queue_empty(&tp->tx_queue)) - tasklet_schedule(&tp->tl); + napi_schedule(&tp->napi); } static void intr_callback(struct urb *urb) @@ -1168,12 +1156,12 @@ static void intr_callback(struct urb *urb) d = urb->transfer_buffer; if (INTR_LINK & __le16_to_cpu(d[0])) { - if (!(tp->speed & LINK_STATUS)) { + if (!netif_carrier_ok(tp->netdev)) { set_bit(RTL8152_LINK_CHG, &tp->flags); schedule_delayed_work(&tp->schedule, 0); } } else { - if (tp->speed & LINK_STATUS) { + if (netif_carrier_ok(tp->netdev)) { set_bit(RTL8152_LINK_CHG, &tp->flags); schedule_delayed_work(&tp->schedule, 0); } @@ -1245,6 +1233,7 @@ static int alloc_all_mem(struct r8152 *tp) spin_lock_init(&tp->tx_lock); INIT_LIST_HEAD(&tp->tx_free); skb_queue_head_init(&tp->tx_queue); + skb_queue_head_init(&tp->rx_queue); for (i = 0; i < RTL8152_MAX_RX; i++) { buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node); @@ -1341,18 +1330,6 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp) return agg; } -static inline __be16 get_protocol(struct sk_buff *skb) -{ - __be16 protocol; - - if (skb->protocol == htons(ETH_P_8021Q)) - protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; - else - protocol = skb->protocol; - - return protocol; -} - /* r8152_csum_workaround() * The hw limites the value the transport offset. When the offset is out of the * range, calculate the checksum by sw. @@ -1421,10 +1398,10 @@ static int msdn_giant_send_check(struct sk_buff *skb) static inline void rtl_tx_vlan_tag(struct tx_desc *desc, struct sk_buff *skb) { - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { u32 opts2; - opts2 = TX_VLAN_TAG | swab16(vlan_tx_tag_get(skb)); + opts2 = TX_VLAN_TAG | swab16(skb_vlan_tag_get(skb)); desc->opts2 |= cpu_to_le32(opts2); } } @@ -1458,7 +1435,7 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, goto unavailable; } - switch (get_protocol(skb)) { + switch (vlan_get_protocol(skb)) { case htons(ETH_P_IP): opts1 |= GTSENDV4; break; @@ -1489,7 +1466,7 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, goto unavailable; } - switch (get_protocol(skb)) { + switch (vlan_get_protocol(skb)) { case htons(ETH_P_IP): opts2 |= IPV4_CS; ip_protocol = ip_hdr(skb)->protocol; @@ -1649,13 +1626,32 @@ return_result: return checksum; } -static void rx_bottom(struct r8152 *tp) +static int rx_bottom(struct r8152 *tp, int budget) { unsigned long flags; struct list_head *cursor, *next, rx_queue; + int ret = 0, work_done = 0; + + if (!skb_queue_empty(&tp->rx_queue)) { + while (work_done < budget) { + struct sk_buff *skb = __skb_dequeue(&tp->rx_queue); + struct net_device *netdev = tp->netdev; + struct net_device_stats *stats = &netdev->stats; + unsigned int pkt_len; + + if (!skb) + break; + + pkt_len = skb->len; + napi_gro_receive(&tp->napi, skb); + work_done++; + stats->rx_packets++; + stats->rx_bytes += pkt_len; + } + } if (list_empty(&tp->rx_done)) - return; + goto out1; INIT_LIST_HEAD(&rx_queue); spin_lock_irqsave(&tp->rx_lock, flags); @@ -1708,9 +1704,14 @@ static void rx_bottom(struct r8152 *tp) skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, netdev); rtl_rx_vlan_tag(rx_desc, skb); - netif_receive_skb(skb); - stats->rx_packets++; - stats->rx_bytes += pkt_len; + if (work_done < budget) { + napi_gro_receive(&tp->napi, skb); + work_done++; + stats->rx_packets++; + stats->rx_bytes += pkt_len; + } else { + __skb_queue_tail(&tp->rx_queue, skb); + } find_next_rx: rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE); @@ -1720,8 +1721,22 @@ find_next_rx: } submit: - r8152_submit_rx(tp, agg, GFP_ATOMIC); + if (!ret) { + ret = r8152_submit_rx(tp, agg, GFP_ATOMIC); + } else { + urb->actual_length = 0; + list_add_tail(&agg->list, next); + } } + + if (!list_empty(&rx_queue)) { + spin_lock_irqsave(&tp->rx_lock, flags); + list_splice_tail(&rx_queue, &tp->rx_done); + spin_unlock_irqrestore(&tp->rx_lock, flags); + } + +out1: + return work_done; } static void tx_bottom(struct r8152 *tp) @@ -1761,12 +1776,8 @@ static void tx_bottom(struct r8152 *tp) } while (res == 0); } -static void bottom_half(unsigned long data) +static void bottom_half(struct r8152 *tp) { - struct r8152 *tp; - - tp = (struct r8152 *)data; - if (test_bit(RTL8152_UNPLUG, &tp->flags)) return; @@ -1778,17 +1789,38 @@ static void bottom_half(unsigned long data) if (!netif_carrier_ok(tp->netdev)) return; - clear_bit(SCHEDULE_TASKLET, &tp->flags); + clear_bit(SCHEDULE_NAPI, &tp->flags); - rx_bottom(tp); tx_bottom(tp); } +static int r8152_poll(struct napi_struct *napi, int budget) +{ + struct r8152 *tp = container_of(napi, struct r8152, napi); + int work_done; + + work_done = rx_bottom(tp, budget); + bottom_half(tp); + + if (work_done < budget) { + napi_complete(napi); + if (!list_empty(&tp->rx_done)) + napi_schedule(napi); + } + + return work_done; +} + static int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) { int ret; + /* The rx would be stopped, so skip submitting */ + if (test_bit(RTL8152_UNPLUG, &tp->flags) || + !test_bit(WORK_ENABLE, &tp->flags) || !netif_carrier_ok(tp->netdev)) + return 0; + usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1), agg->head, agg_buf_sz, (usb_complete_t)read_bulk_callback, agg); @@ -1805,7 +1837,11 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) spin_lock_irqsave(&tp->rx_lock, flags); list_add_tail(&agg->list, &tp->rx_done); spin_unlock_irqrestore(&tp->rx_lock, flags); - tasklet_schedule(&tp->tl); + + netif_err(tp, rx_err, tp->netdev, + "Couldn't submit rx[%p], ret = %d\n", agg, ret); + + napi_schedule(&tp->napi); } return ret; @@ -1845,7 +1881,7 @@ static void rtl8152_set_rx_mode(struct net_device *netdev) { struct r8152 *tp = netdev_priv(netdev); - if (tp->speed & LINK_STATUS) { + if (netif_carrier_ok(netdev)) { set_bit(RTL8152_SET_RX_MODE, &tp->flags); schedule_delayed_work(&tp->schedule, 0); } @@ -1924,11 +1960,11 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, if (!list_empty(&tp->tx_free)) { if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - set_bit(SCHEDULE_TASKLET, &tp->flags); + set_bit(SCHEDULE_NAPI, &tp->flags); schedule_delayed_work(&tp->schedule, 0); } else { usb_mark_last_busy(tp->udev); - tasklet_schedule(&tp->tl); + napi_schedule(&tp->napi); } } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen) { netif_stop_queue(netdev); @@ -2007,6 +2043,7 @@ static int rtl_start_rx(struct r8152 *tp) { int i, ret = 0; + napi_disable(&tp->napi); INIT_LIST_HEAD(&tp->rx_done); for (i = 0; i < RTL8152_MAX_RX; i++) { INIT_LIST_HEAD(&tp->rx_info[i].list); @@ -2014,6 +2051,7 @@ static int rtl_start_rx(struct r8152 *tp) if (ret) break; } + napi_enable(&tp->napi); if (ret && ++i < RTL8152_MAX_RX) { struct list_head rx_queue; @@ -2044,6 +2082,9 @@ static int rtl_stop_rx(struct r8152 *tp) for (i = 0; i < RTL8152_MAX_RX; i++) usb_kill_urb(tp->rx_info[i].urb); + while (!skb_queue_empty(&tp->rx_queue)) + dev_kfree_skb(__skb_dequeue(&tp->rx_queue)); + return 0; } @@ -2059,7 +2100,7 @@ static int rtl_enable(struct r8152 *tp) rxdy_gated_en(tp, false); - return rtl_start_rx(tp); + return 0; } static int rtl8152_enable(struct r8152 *tp) @@ -2518,24 +2559,18 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) data = ocp_reg_read(tp, OCP_POWER_CFG); data |= EN_10M_PLLOFF; ocp_reg_write(tp, OCP_POWER_CFG, data); - data = sram_read(tp, SRAM_IMPEDANCE); - data &= ~RX_DRIVING_MASK; - sram_write(tp, SRAM_IMPEDANCE, data); + sram_write(tp, SRAM_IMPEDANCE, 0x0b13); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); ocp_data |= PFM_PWM_SWITCH; ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); - data = sram_read(tp, SRAM_LPF_CFG); - data |= LPF_AUTO_TUNE; - sram_write(tp, SRAM_LPF_CFG, data); + /* Enable LPF corner auto tune */ + sram_write(tp, SRAM_LPF_CFG, 0xf70f); - data = sram_read(tp, SRAM_10M_AMP1); - data |= GDAC_IB_UPALL; - sram_write(tp, SRAM_10M_AMP1, data); - data = sram_read(tp, SRAM_10M_AMP2); - data |= AMP_DN; - sram_write(tp, SRAM_10M_AMP2, data); + /* Adjust 10M Amplitude */ + sram_write(tp, SRAM_10M_AMP1, 0x00af); + sram_write(tp, SRAM_10M_AMP2, 0x0208); set_bit(PHY_RESET, &tp->flags); } @@ -2870,20 +2905,20 @@ static void set_carrier(struct r8152 *tp) speed = rtl8152_get_speed(tp); if (speed & LINK_STATUS) { - if (!(tp->speed & LINK_STATUS)) { + if (!netif_carrier_ok(netdev)) { tp->rtl_ops.enable(tp); set_bit(RTL8152_SET_RX_MODE, &tp->flags); netif_carrier_on(netdev); + rtl_start_rx(tp); } } else { - if (tp->speed & LINK_STATUS) { + if (netif_carrier_ok(netdev)) { netif_carrier_off(netdev); - tasklet_disable(&tp->tl); + napi_disable(&tp->napi); tp->rtl_ops.disable(tp); - tasklet_enable(&tp->tl); + napi_enable(&tp->napi); } } - tp->speed = speed; } static void rtl_work_func_t(struct work_struct *work) @@ -2913,10 +2948,11 @@ static void rtl_work_func_t(struct work_struct *work) if (test_bit(RTL8152_SET_RX_MODE, &tp->flags)) _rtl8152_set_rx_mode(tp->netdev); - if (test_bit(SCHEDULE_TASKLET, &tp->flags) && - (tp->speed & LINK_STATUS)) { - clear_bit(SCHEDULE_TASKLET, &tp->flags); - tasklet_schedule(&tp->tl); + /* don't schedule napi before linking */ + if (test_bit(SCHEDULE_NAPI, &tp->flags) && + netif_carrier_ok(tp->netdev)) { + clear_bit(SCHEDULE_NAPI, &tp->flags); + napi_schedule(&tp->napi); } if (test_bit(PHY_RESET, &tp->flags)) @@ -2937,8 +2973,7 @@ static int rtl8152_open(struct net_device *netdev) if (res) goto out; - /* set speed to 0 to avoid autoresume try to submit rx */ - tp->speed = 0; + netif_carrier_off(netdev); res = usb_autopm_get_interface(tp->intf); if (res < 0) { @@ -2955,7 +2990,7 @@ static int rtl8152_open(struct net_device *netdev) cancel_delayed_work_sync(&tp->schedule); /* disable the tx/rx, if the workqueue has enabled them. */ - if (tp->speed & LINK_STATUS) + if (netif_carrier_ok(netdev)) tp->rtl_ops.disable(tp); } @@ -2964,7 +2999,6 @@ static int rtl8152_open(struct net_device *netdev) rtl8152_set_speed(tp, AUTONEG_ENABLE, tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL); - tp->speed = 0; netif_carrier_off(netdev); netif_start_queue(netdev); set_bit(WORK_ENABLE, &tp->flags); @@ -2977,7 +3011,7 @@ static int rtl8152_open(struct net_device *netdev) res); free_all_mem(tp); } else { - tasklet_enable(&tp->tl); + napi_enable(&tp->napi); } mutex_unlock(&tp->control); @@ -2993,15 +3027,16 @@ static int rtl8152_close(struct net_device *netdev) struct r8152 *tp = netdev_priv(netdev); int res = 0; - tasklet_disable(&tp->tl); + napi_disable(&tp->napi); clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); cancel_delayed_work_sync(&tp->schedule); netif_stop_queue(netdev); res = usb_autopm_get_interface(tp->intf); - if (res < 0) { + if (res < 0 || test_bit(RTL8152_UNPLUG, &tp->flags)) { rtl_drop_queued_tx(tp); + rtl_stop_rx(tp); } else { mutex_lock(&tp->control); @@ -3205,10 +3240,10 @@ static void r8153_init(struct r8152 *tp) ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL); ocp_data &= ~LPM_TIMER_MASK; - if (tp->udev->speed == USB_SPEED_SUPER) - ocp_data |= LPM_TIMER_500US; - else + if (tp->version == RTL_VER_04 && tp->udev->speed != USB_SPEED_SUPER) ocp_data |= LPM_TIMER_500MS; + else + ocp_data |= LPM_TIMER_500US; ocp_write_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL, ocp_data); ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2); @@ -3257,7 +3292,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) { clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); - tasklet_disable(&tp->tl); + napi_disable(&tp->napi); if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { rtl_stop_rx(tp); rtl_runtime_suspend_enable(tp, true); @@ -3265,7 +3300,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) cancel_delayed_work_sync(&tp->schedule); tp->rtl_ops.down(tp); } - tasklet_enable(&tp->tl); + napi_enable(&tp->napi); } out1: mutex_unlock(&tp->control); @@ -3289,7 +3324,7 @@ static int rtl8152_resume(struct usb_interface *intf) rtl_runtime_suspend_enable(tp, false); clear_bit(SELECTIVE_SUSPEND, &tp->flags); set_bit(WORK_ENABLE, &tp->flags); - if (tp->speed & LINK_STATUS) + if (netif_carrier_ok(tp->netdev)) rtl_start_rx(tp); } else { tp->rtl_ops.up(tp); @@ -3297,7 +3332,6 @@ static int rtl8152_resume(struct usb_interface *intf) tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL); - tp->speed = 0; netif_carrier_off(tp->netdev); set_bit(WORK_ENABLE, &tp->flags); } @@ -3849,7 +3883,6 @@ static int rtl8152_probe(struct usb_interface *intf, if (ret) goto out; - tasklet_init(&tp->tl, bottom_half, (unsigned long)tp); mutex_init(&tp->control); INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t); @@ -3863,8 +3896,7 @@ static int rtl8152_probe(struct usb_interface *intf, netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM | NETIF_F_TSO6 | - NETIF_F_HW_VLAN_CTAG_RX | - NETIF_F_HW_VLAN_CTAG_TX; + NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX; netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM | NETIF_F_TSO6; @@ -3885,6 +3917,7 @@ static int rtl8152_probe(struct usb_interface *intf, set_ethernet_addr(tp); usb_set_intfdata(intf, tp); + netif_napi_add(netdev, &tp->napi, r8152_poll, RTL8152_NAPI_WEIGHT); ret = register_netdev(netdev); if (ret != 0) { @@ -3898,15 +3931,13 @@ static int rtl8152_probe(struct usb_interface *intf, else device_set_wakeup_enable(&udev->dev, false); - tasklet_disable(&tp->tl); - netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION); return 0; out1: + netif_napi_del(&tp->napi); usb_set_intfdata(intf, NULL); - tasklet_kill(&tp->tl); out: free_netdev(netdev); return ret; @@ -3923,7 +3954,7 @@ static void rtl8152_disconnect(struct usb_interface *intf) if (udev->state == USB_STATE_NOTATTACHED) set_bit(RTL8152_UNPLUG, &tp->flags); - tasklet_kill(&tp->tl); + netif_napi_del(&tp->napi); unregister_netdev(tp->netdev); tp->rtl_ops.unload(tp); free_netdev(tp->netdev); diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c index 99b69af14274..4a1e9c489f1f 100644 --- a/drivers/net/usb/sr9700.c +++ b/drivers/net/usb/sr9700.c @@ -77,7 +77,7 @@ static int wait_phy_eeprom_ready(struct usbnet *dev, int phy) int ret; udelay(1); - ret = sr_read_reg(dev, EPCR, &tmp); + ret = sr_read_reg(dev, SR_EPCR, &tmp); if (ret < 0) return ret; @@ -98,15 +98,15 @@ static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, mutex_lock(&dev->phy_mutex); - sr_write_reg(dev, EPAR, phy ? (reg | EPAR_PHY_ADR) : reg); - sr_write_reg(dev, EPCR, phy ? (EPCR_EPOS | EPCR_ERPRR) : EPCR_ERPRR); + sr_write_reg(dev, SR_EPAR, phy ? (reg | EPAR_PHY_ADR) : reg); + sr_write_reg(dev, SR_EPCR, phy ? (EPCR_EPOS | EPCR_ERPRR) : EPCR_ERPRR); ret = wait_phy_eeprom_ready(dev, phy); if (ret < 0) goto out_unlock; - sr_write_reg(dev, EPCR, 0x0); - ret = sr_read(dev, EPDR, 2, value); + sr_write_reg(dev, SR_EPCR, 0x0); + ret = sr_read(dev, SR_EPDR, 2, value); netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n", phy, reg, *value, ret); @@ -123,19 +123,19 @@ static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, mutex_lock(&dev->phy_mutex); - ret = sr_write(dev, EPDR, 2, &value); + ret = sr_write(dev, SR_EPDR, 2, &value); if (ret < 0) goto out_unlock; - sr_write_reg(dev, EPAR, phy ? (reg | EPAR_PHY_ADR) : reg); - sr_write_reg(dev, EPCR, phy ? (EPCR_WEP | EPCR_EPOS | EPCR_ERPRW) : + sr_write_reg(dev, SR_EPAR, phy ? (reg | EPAR_PHY_ADR) : reg); + sr_write_reg(dev, SR_EPCR, phy ? (EPCR_WEP | EPCR_EPOS | EPCR_ERPRW) : (EPCR_WEP | EPCR_ERPRW)); ret = wait_phy_eeprom_ready(dev, phy); if (ret < 0) goto out_unlock; - sr_write_reg(dev, EPCR, 0x0); + sr_write_reg(dev, SR_EPCR, 0x0); out_unlock: mutex_unlock(&dev->phy_mutex); @@ -188,7 +188,7 @@ static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc) if (loc == MII_BMSR) { u8 value; - sr_read_reg(dev, NSR, &value); + sr_read_reg(dev, SR_NSR, &value); if (value & NSR_LINKST) rc = 1; } @@ -228,7 +228,7 @@ static u32 sr9700_get_link(struct net_device *netdev) int rc = 0; /* Get the Link Status directly */ - sr_read_reg(dev, NSR, &value); + sr_read_reg(dev, SR_NSR, &value); if (value & NSR_LINKST) rc = 1; @@ -281,8 +281,8 @@ static void sr9700_set_multicast(struct net_device *netdev) } } - sr_write_async(dev, MAR, SR_MCAST_SIZE, hashes); - sr_write_reg_async(dev, RCR, rx_ctl); + sr_write_async(dev, SR_MAR, SR_MCAST_SIZE, hashes); + sr_write_reg_async(dev, SR_RCR, rx_ctl); } static int sr9700_set_mac_address(struct net_device *netdev, void *p) @@ -297,7 +297,7 @@ static int sr9700_set_mac_address(struct net_device *netdev, void *p) } memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); - sr_write_async(dev, PAR, 6, netdev->dev_addr); + sr_write_async(dev, SR_PAR, 6, netdev->dev_addr); return 0; } @@ -340,7 +340,7 @@ static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf) mii->phy_id_mask = 0x1f; mii->reg_num_mask = 0x1f; - sr_write_reg(dev, NCR, NCR_RST); + sr_write_reg(dev, SR_NCR, NCR_RST); udelay(20); /* read MAC @@ -348,17 +348,17 @@ static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf) * EEPROM automatically to PAR. In case there is no EEPROM externally, * a default MAC address is stored in PAR for making chip work properly. */ - if (sr_read(dev, PAR, ETH_ALEN, netdev->dev_addr) < 0) { + if (sr_read(dev, SR_PAR, ETH_ALEN, netdev->dev_addr) < 0) { netdev_err(netdev, "Error reading MAC address\n"); ret = -ENODEV; goto out; } /* power up and reset phy */ - sr_write_reg(dev, PRR, PRR_PHY_RST); + sr_write_reg(dev, SR_PRR, PRR_PHY_RST); /* at least 10ms, here 20ms for safe */ mdelay(20); - sr_write_reg(dev, PRR, 0); + sr_write_reg(dev, SR_PRR, 0); /* at least 1ms, here 2ms for reading right register */ udelay(2 * 1000); diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h index fd687c575e74..258b030277e7 100644 --- a/drivers/net/usb/sr9700.h +++ b/drivers/net/usb/sr9700.h @@ -14,13 +14,13 @@ /* sr9700 spec. register table on Linux platform */ /* Network Control Reg */ -#define NCR 0x00 +#define SR_NCR 0x00 #define NCR_RST (1 << 0) #define NCR_LBK (3 << 1) #define NCR_FDX (1 << 3) #define NCR_WAKEEN (1 << 6) /* Network Status Reg */ -#define NSR 0x01 +#define SR_NSR 0x01 #define NSR_RXRDY (1 << 0) #define NSR_RXOV (1 << 1) #define NSR_TX1END (1 << 2) @@ -30,7 +30,7 @@ #define NSR_LINKST (1 << 6) #define NSR_SPEED (1 << 7) /* Tx Control Reg */ -#define TCR 0x02 +#define SR_TCR 0x02 #define TCR_CRC_DIS (1 << 1) #define TCR_PAD_DIS (1 << 2) #define TCR_LC_CARE (1 << 3) @@ -38,7 +38,7 @@ #define TCR_EXCECM (1 << 5) #define TCR_LF_EN (1 << 6) /* Tx Status Reg for Packet Index 1 */ -#define TSR1 0x03 +#define SR_TSR1 0x03 #define TSR1_EC (1 << 2) #define TSR1_COL (1 << 3) #define TSR1_LC (1 << 4) @@ -46,7 +46,7 @@ #define TSR1_LOC (1 << 6) #define TSR1_TLF (1 << 7) /* Tx Status Reg for Packet Index 2 */ -#define TSR2 0x04 +#define SR_TSR2 0x04 #define TSR2_EC (1 << 2) #define TSR2_COL (1 << 3) #define TSR2_LC (1 << 4) @@ -54,7 +54,7 @@ #define TSR2_LOC (1 << 6) #define TSR2_TLF (1 << 7) /* Rx Control Reg*/ -#define RCR 0x05 +#define SR_RCR 0x05 #define RCR_RXEN (1 << 0) #define RCR_PRMSC (1 << 1) #define RCR_RUNT (1 << 2) @@ -62,87 +62,87 @@ #define RCR_DIS_CRC (1 << 4) #define RCR_DIS_LONG (1 << 5) /* Rx Status Reg */ -#define RSR 0x06 +#define SR_RSR 0x06 #define RSR_AE (1 << 2) #define RSR_MF (1 << 6) #define RSR_RF (1 << 7) /* Rx Overflow Counter Reg */ -#define ROCR 0x07 +#define SR_ROCR 0x07 #define ROCR_ROC (0x7F << 0) #define ROCR_RXFU (1 << 7) /* Back Pressure Threshold Reg */ -#define BPTR 0x08 +#define SR_BPTR 0x08 #define BPTR_JPT (0x0F << 0) #define BPTR_BPHW (0x0F << 4) /* Flow Control Threshold Reg */ -#define FCTR 0x09 +#define SR_FCTR 0x09 #define FCTR_LWOT (0x0F << 0) #define FCTR_HWOT (0x0F << 4) /* rx/tx Flow Control Reg */ -#define FCR 0x0A +#define SR_FCR 0x0A #define FCR_FLCE (1 << 0) #define FCR_BKPA (1 << 4) #define FCR_TXPEN (1 << 5) #define FCR_TXPF (1 << 6) #define FCR_TXP0 (1 << 7) /* Eeprom & Phy Control Reg */ -#define EPCR 0x0B +#define SR_EPCR 0x0B #define EPCR_ERRE (1 << 0) #define EPCR_ERPRW (1 << 1) #define EPCR_ERPRR (1 << 2) #define EPCR_EPOS (1 << 3) #define EPCR_WEP (1 << 4) /* Eeprom & Phy Address Reg */ -#define EPAR 0x0C +#define SR_EPAR 0x0C #define EPAR_EROA (0x3F << 0) #define EPAR_PHY_ADR_MASK (0x03 << 6) #define EPAR_PHY_ADR (0x01 << 6) /* Eeprom & Phy Data Reg */ -#define EPDR 0x0D /* 0x0D ~ 0x0E for Data Reg Low & High */ +#define SR_EPDR 0x0D /* 0x0D ~ 0x0E for Data Reg Low & High */ /* Wakeup Control Reg */ -#define WCR 0x0F +#define SR_WCR 0x0F #define WCR_MAGICST (1 << 0) #define WCR_LINKST (1 << 2) #define WCR_MAGICEN (1 << 3) #define WCR_LINKEN (1 << 5) /* Physical Address Reg */ -#define PAR 0x10 /* 0x10 ~ 0x15 6 bytes for PAR */ +#define SR_PAR 0x10 /* 0x10 ~ 0x15 6 bytes for PAR */ /* Multicast Address Reg */ -#define MAR 0x16 /* 0x16 ~ 0x1D 8 bytes for MAR */ +#define SR_MAR 0x16 /* 0x16 ~ 0x1D 8 bytes for MAR */ /* 0x1e unused */ /* Phy Reset Reg */ -#define PRR 0x1F +#define SR_PRR 0x1F #define PRR_PHY_RST (1 << 0) /* Tx sdram Write Pointer Address Low */ -#define TWPAL 0x20 +#define SR_TWPAL 0x20 /* Tx sdram Write Pointer Address High */ -#define TWPAH 0x21 +#define SR_TWPAH 0x21 /* Tx sdram Read Pointer Address Low */ -#define TRPAL 0x22 +#define SR_TRPAL 0x22 /* Tx sdram Read Pointer Address High */ -#define TRPAH 0x23 +#define SR_TRPAH 0x23 /* Rx sdram Write Pointer Address Low */ -#define RWPAL 0x24 +#define SR_RWPAL 0x24 /* Rx sdram Write Pointer Address High */ -#define RWPAH 0x25 +#define SR_RWPAH 0x25 /* Rx sdram Read Pointer Address Low */ -#define RRPAL 0x26 +#define SR_RRPAL 0x26 /* Rx sdram Read Pointer Address High */ -#define RRPAH 0x27 +#define SR_RRPAH 0x27 /* Vendor ID register */ -#define VID 0x28 /* 0x28 ~ 0x29 2 bytes for VID */ +#define SR_VID 0x28 /* 0x28 ~ 0x29 2 bytes for VID */ /* Product ID register */ -#define PID 0x2A /* 0x2A ~ 0x2B 2 bytes for PID */ +#define SR_PID 0x2A /* 0x2A ~ 0x2B 2 bytes for PID */ /* CHIP Revision register */ -#define CHIPR 0x2C +#define SR_CHIPR 0x2C /* 0x2D --> 0xEF unused */ /* USB Device Address */ -#define USBDA 0xF0 +#define SR_USBDA 0xF0 #define USBDA_USBFA (0x7F << 0) /* RX packet Counter Reg */ -#define RXC 0xF1 +#define SR_RXC 0xF1 /* Tx packet Counter & USB Status Reg */ -#define TXC_USBS 0xF2 +#define SR_TXC_USBS 0xF2 #define TXC_USBS_TXC0 (1 << 0) #define TXC_USBS_TXC1 (1 << 1) #define TXC_USBS_TXC2 (1 << 2) @@ -150,7 +150,7 @@ #define TXC_USBS_SUSFLAG (1 << 6) #define TXC_USBS_RXFAULT (1 << 7) /* USB Control register */ -#define USBC 0xF4 +#define SR_USBC 0xF4 #define USBC_EP3NAK (1 << 4) #define USBC_EP3ACK (1 << 5) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 3a6770a65d78..449835f4331e 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -160,20 +160,19 @@ EXPORT_SYMBOL_GPL(usbnet_get_endpoints); int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress) { - int tmp, i; + int tmp = -1, ret; unsigned char buf [13]; - tmp = usb_string(dev->udev, iMACAddress, buf, sizeof buf); - if (tmp != 12) { + ret = usb_string(dev->udev, iMACAddress, buf, sizeof buf); + if (ret == 12) + tmp = hex2bin(dev->net->dev_addr, buf, 6); + if (tmp < 0) { dev_dbg(&dev->udev->dev, "bad MAC string %d fetch, %d\n", iMACAddress, tmp); - if (tmp >= 0) - tmp = -EINVAL; - return tmp; + if (ret >= 0) + ret = -EINVAL; + return ret; } - for (i = tmp = 0; i < 6; i++, tmp += 2) - dev->net->dev_addr [i] = - (hex_to_bin(buf[tmp]) << 4) + hex_to_bin(buf[tmp + 1]); return 0; } EXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr); diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 8ad596573d17..4cca36ebc4fb 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -469,6 +469,14 @@ static const struct nla_policy veth_policy[VETH_INFO_MAX + 1] = { [VETH_INFO_PEER] = { .len = sizeof(struct ifinfomsg) }, }; +static struct net *veth_get_link_net(const struct net_device *dev) +{ + struct veth_priv *priv = netdev_priv(dev); + struct net_device *peer = rtnl_dereference(priv->peer); + + return peer ? dev_net(peer) : dev_net(dev); +} + static struct rtnl_link_ops veth_link_ops = { .kind = DRV_NAME, .priv_size = sizeof(struct veth_priv), @@ -478,6 +486,7 @@ static struct rtnl_link_ops veth_link_ops = { .dellink = veth_dellink, .policy = veth_policy, .maxtype = VETH_INFO_MAX, + .get_link_net = veth_get_link_net, }; /* diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 5ca97713bfb3..110a2cf67244 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -490,17 +490,8 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq, skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; break; case VIRTIO_NET_HDR_GSO_UDP: - { - static bool warned; - - if (!warned) { - warned = true; - netdev_warn(dev, - "host using disabled UFO feature; please fix it\n"); - } skb_shinfo(skb)->gso_type = SKB_GSO_UDP; break; - } case VIRTIO_NET_HDR_GSO_TCPV6: skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; break; @@ -888,6 +879,8 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4; else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV6; + else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP) + hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_UDP; else BUG(); if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN) @@ -925,6 +918,9 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) /* Free up any pending old buffers before queueing new ones. */ free_old_xmit_skbs(sq); + /* timestamp packet in software */ + skb_tx_timestamp(skb); + /* Try to transmit */ err = xmit_skb(sq, skb); @@ -1376,6 +1372,7 @@ static const struct ethtool_ops virtnet_ethtool_ops = { .get_ringparam = virtnet_get_ringparam, .set_channels = virtnet_set_channels, .get_channels = virtnet_get_channels, + .get_ts_info = ethtool_op_get_ts_info, }; #define MIN_MTU 68 @@ -1748,7 +1745,7 @@ static int virtnet_probe(struct virtio_device *vdev) 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 + dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO | NETIF_F_TSO_ECN | NETIF_F_TSO6; } /* Individual feature bits: what can host handle? */ @@ -1758,9 +1755,13 @@ static int virtnet_probe(struct virtio_device *vdev) 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; + + dev->features |= NETIF_F_GSO_ROBUST; if (gso) - dev->features |= dev->hw_features & NETIF_F_ALL_TSO; + dev->features |= dev->hw_features & (NETIF_F_ALL_TSO|NETIF_F_UFO); /* (!csum && gso) case will be fixed by register_netdev() */ } if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM)) @@ -1798,7 +1799,8 @@ static int virtnet_probe(struct virtio_device *vdev) /* If we can receive ANY GSO packets, we must allocate large ones. */ if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) || virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) || - virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN)) + virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) || + virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO)) vi->big_packets = true; if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) @@ -1994,9 +1996,9 @@ static struct virtio_device_id id_table[] = { static unsigned int features[] = { VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC, - VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6, + VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, - VIRTIO_NET_F_GUEST_ECN, + VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO, VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h index 4d84912c99ba..3718d024f638 100644 --- a/drivers/net/vmxnet3/vmxnet3_defs.h +++ b/drivers/net/vmxnet3/vmxnet3_defs.h @@ -342,6 +342,7 @@ union Vmxnet3_GenericDesc { #define VMXNET3_TX_RING_MAX_SIZE 4096 #define VMXNET3_TC_RING_MAX_SIZE 4096 #define VMXNET3_RX_RING_MAX_SIZE 4096 +#define VMXNET3_RX_RING2_MAX_SIZE 2048 #define VMXNET3_RC_RING_MAX_SIZE 8192 /* a list of reasons for queue stop */ @@ -392,7 +393,7 @@ struct Vmxnet3_DriverInfo { }; -#define VMXNET3_REV1_MAGIC 0xbabefee1 +#define VMXNET3_REV1_MAGIC 3133079265u /* * QueueDescPA must be 128 bytes aligned. It points to an array of diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index afd295348ddb..294214c15292 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1038,9 +1038,9 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq, le32_add_cpu(&tq->shared->txNumDeferred, 1); } - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { gdesc->txd.ti = 1; - gdesc->txd.tci = vlan_tx_tag_get(skb); + gdesc->txd.tci = skb_vlan_tag_get(skb); } /* finally flips the GEN bit of the SOP desc. */ @@ -2505,6 +2505,9 @@ vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter) ring0_size = min_t(u32, ring0_size, VMXNET3_RX_RING_MAX_SIZE / sz * sz); ring1_size = adapter->rx_queue[0].rx_ring[1].size; + ring1_size = (ring1_size + sz - 1) / sz * sz; + ring1_size = min_t(u32, ring1_size, VMXNET3_RX_RING2_MAX_SIZE / + sz * sz); comp_size = ring0_size + ring1_size; for (i = 0; i < adapter->num_rx_queues; i++) { @@ -2585,7 +2588,7 @@ vmxnet3_open(struct net_device *netdev) err = vmxnet3_create_queues(adapter, adapter->tx_ring_size, adapter->rx_ring_size, - VMXNET3_DEF_RX_RING_SIZE); + adapter->rx_ring2_size); if (err) goto queue_err; @@ -2964,6 +2967,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, adapter->tx_ring_size = VMXNET3_DEF_TX_RING_SIZE; adapter->rx_ring_size = VMXNET3_DEF_RX_RING_SIZE; + adapter->rx_ring2_size = VMXNET3_DEF_RX_RING2_SIZE; spin_lock_init(&adapter->cmd_lock); adapter->adapter_pa = dma_map_single(&adapter->pdev->dev, adapter, @@ -3286,27 +3290,15 @@ skip_arp: static int vmxnet3_resume(struct device *device) { - int err, i = 0; + int err; unsigned long flags; struct pci_dev *pdev = to_pci_dev(device); struct net_device *netdev = pci_get_drvdata(pdev); struct vmxnet3_adapter *adapter = netdev_priv(netdev); - struct Vmxnet3_PMConf *pmConf; if (!netif_running(netdev)) return 0; - /* Destroy wake-up filters. */ - pmConf = adapter->pm_conf; - memset(pmConf, 0, sizeof(*pmConf)); - - adapter->shared->devRead.pmConfDesc.confVer = cpu_to_le32(1); - adapter->shared->devRead.pmConfDesc.confLen = cpu_to_le32(sizeof( - *pmConf)); - adapter->shared->devRead.pmConfDesc.confPA = - cpu_to_le64(adapter->pm_conf_pa); - - netif_device_attach(netdev); pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); err = pci_enable_device_mem(pdev); @@ -3315,15 +3307,31 @@ vmxnet3_resume(struct device *device) pci_enable_wake(pdev, PCI_D0, 0); + vmxnet3_alloc_intr_resources(adapter); + + /* During hibernate and suspend, device has to be reinitialized as the + * device state need not be preserved. + */ + + /* Need not check adapter state as other reset tasks cannot run during + * device resume. + */ spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, - VMXNET3_CMD_UPDATE_PMCFG); + VMXNET3_CMD_QUIESCE_DEV); spin_unlock_irqrestore(&adapter->cmd_lock, flags); - vmxnet3_alloc_intr_resources(adapter); - vmxnet3_request_irqs(adapter); - for (i = 0; i < adapter->num_rx_queues; i++) - napi_enable(&adapter->rx_queue[i].napi); - vmxnet3_enable_all_intrs(adapter); + vmxnet3_tq_cleanup_all(adapter); + vmxnet3_rq_cleanup_all(adapter); + + vmxnet3_reset_dev(adapter); + err = vmxnet3_activate_dev(adapter); + if (err != 0) { + netdev_err(netdev, + "failed to re-activate on resume, error: %d", err); + vmxnet3_force_close(adapter); + return err; + } + netif_device_attach(netdev); return 0; } @@ -3331,6 +3339,8 @@ vmxnet3_resume(struct device *device) static const struct dev_pm_ops vmxnet3_pm_ops = { .suspend = vmxnet3_suspend, .resume = vmxnet3_resume, + .freeze = vmxnet3_suspend, + .restore = vmxnet3_resume, }; #endif diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index b7b53329d575..4c8a944d58b4 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -323,7 +323,7 @@ vmxnet3_get_ethtool_stats(struct net_device *netdev, vmxnet3_tq_driver_stats[i].offset); } - for (j = 0; j < adapter->num_tx_queues; j++) { + for (j = 0; j < adapter->num_rx_queues; j++) { base = (u8 *)&adapter->rqd_start[j].stats; *buf++ = (u64) j; for (i = 1; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) @@ -447,12 +447,12 @@ vmxnet3_get_ringparam(struct net_device *netdev, param->rx_max_pending = VMXNET3_RX_RING_MAX_SIZE; param->tx_max_pending = VMXNET3_TX_RING_MAX_SIZE; param->rx_mini_max_pending = 0; - param->rx_jumbo_max_pending = 0; + param->rx_jumbo_max_pending = VMXNET3_RX_RING2_MAX_SIZE; param->rx_pending = adapter->rx_ring_size; param->tx_pending = adapter->tx_ring_size; param->rx_mini_pending = 0; - param->rx_jumbo_pending = 0; + param->rx_jumbo_pending = adapter->rx_ring2_size; } @@ -461,7 +461,7 @@ vmxnet3_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *param) { struct vmxnet3_adapter *adapter = netdev_priv(netdev); - u32 new_tx_ring_size, new_rx_ring_size; + u32 new_tx_ring_size, new_rx_ring_size, new_rx_ring2_size; u32 sz; int err = 0; @@ -473,6 +473,10 @@ vmxnet3_set_ringparam(struct net_device *netdev, VMXNET3_RX_RING_MAX_SIZE) return -EINVAL; + if (param->rx_jumbo_pending == 0 || + param->rx_jumbo_pending > VMXNET3_RX_RING2_MAX_SIZE) + return -EINVAL; + /* if adapter not yet initialized, do nothing */ if (adapter->rx_buf_per_pkt == 0) { netdev_err(netdev, "adapter not completely initialized, " @@ -500,8 +504,15 @@ vmxnet3_set_ringparam(struct net_device *netdev, sz) != 0) return -EINVAL; - if (new_tx_ring_size == adapter->tx_queue[0].tx_ring.size && - new_rx_ring_size == adapter->rx_queue[0].rx_ring[0].size) { + /* ring2 has to be a multiple of VMXNET3_RING_SIZE_ALIGN */ + new_rx_ring2_size = (param->rx_jumbo_pending + VMXNET3_RING_SIZE_MASK) & + ~VMXNET3_RING_SIZE_MASK; + new_rx_ring2_size = min_t(u32, new_rx_ring2_size, + VMXNET3_RX_RING2_MAX_SIZE); + + if (new_tx_ring_size == adapter->tx_ring_size && + new_rx_ring_size == adapter->rx_ring_size && + new_rx_ring2_size == adapter->rx_ring2_size) { return 0; } @@ -522,7 +533,7 @@ vmxnet3_set_ringparam(struct net_device *netdev, vmxnet3_rq_destroy_all(adapter); err = vmxnet3_create_queues(adapter, new_tx_ring_size, - new_rx_ring_size, VMXNET3_DEF_RX_RING_SIZE); + new_rx_ring_size, new_rx_ring2_size); if (err) { /* failed, most likely because of OOM, try default @@ -530,11 +541,12 @@ vmxnet3_set_ringparam(struct net_device *netdev, netdev_err(netdev, "failed to apply new sizes, " "try the default ones\n"); new_rx_ring_size = VMXNET3_DEF_RX_RING_SIZE; + new_rx_ring2_size = VMXNET3_DEF_RX_RING2_SIZE; new_tx_ring_size = VMXNET3_DEF_TX_RING_SIZE; err = vmxnet3_create_queues(adapter, new_tx_ring_size, new_rx_ring_size, - VMXNET3_DEF_RX_RING_SIZE); + new_rx_ring2_size); if (err) { netdev_err(netdev, "failed to create queues " "with default sizes. Closing it\n"); @@ -549,6 +561,7 @@ vmxnet3_set_ringparam(struct net_device *netdev, } adapter->tx_ring_size = new_tx_ring_size; adapter->rx_ring_size = new_rx_ring_size; + adapter->rx_ring2_size = new_rx_ring2_size; out: clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state); diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index 5f0199f6c31e..cd71c77f78f2 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -69,10 +69,10 @@ /* * Version numbers */ -#define VMXNET3_DRIVER_VERSION_STRING "1.2.1.0-k" +#define VMXNET3_DRIVER_VERSION_STRING "1.3.4.0-k" /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM 0x01020100 +#define VMXNET3_DRIVER_VERSION_NUM 0x01030400 #if defined(CONFIG_PCI_MSI) /* RSS only makes sense if MSI-X is supported. */ @@ -352,6 +352,7 @@ struct vmxnet3_adapter { /* Ring sizes */ u32 tx_ring_size; u32 rx_ring_size; + u32 rx_ring2_size; struct work_struct work; @@ -384,6 +385,7 @@ struct vmxnet3_adapter { /* must be a multiple of VMXNET3_RING_SIZE_ALIGN */ #define VMXNET3_DEF_TX_RING_SIZE 512 #define VMXNET3_DEF_RX_RING_SIZE 256 +#define VMXNET3_DEF_RX_RING2_SIZE 128 #define VMXNET3_MAX_ETH_HDR_SIZE 22 #define VMXNET3_MAX_SKB_BUF_SIZE (3*1024) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 7fbd89fbe107..0e57e862c399 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -61,12 +61,6 @@ #define FDB_AGE_DEFAULT 300 /* 5 min */ #define FDB_AGE_INTERVAL (10 * HZ) /* rescan interval */ -#define VXLAN_N_VID (1u << 24) -#define VXLAN_VID_MASK (VXLAN_N_VID - 1) -#define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr)) - -#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */ - /* UDP port for VXLAN traffic. * The IANA assigned port is 4789, but the Linux default is 8472 * for compatibility with early adopters. @@ -269,15 +263,20 @@ static inline struct vxlan_rdst *first_remote_rtnl(struct vxlan_fdb *fdb) return list_first_entry(&fdb->remotes, struct vxlan_rdst, list); } -/* Find VXLAN socket based on network namespace, address family and UDP port */ -static struct vxlan_sock *vxlan_find_sock(struct net *net, - sa_family_t family, __be16 port) +/* Find VXLAN socket based on network namespace, address family and UDP port + * and enabled unshareable flags. + */ +static struct vxlan_sock *vxlan_find_sock(struct net *net, sa_family_t family, + __be16 port, u32 flags) { struct vxlan_sock *vs; + flags &= VXLAN_F_RCV_FLAGS; + hlist_for_each_entry_rcu(vs, vs_head(net, port), hlist) { if (inet_sk(vs->sock->sk)->inet_sport == port && - inet_sk(vs->sock->sk)->sk.sk_family == family) + inet_sk(vs->sock->sk)->sk.sk_family == family && + vs->flags == flags) return vs; } return NULL; @@ -297,11 +296,12 @@ static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, u32 id) /* Look up VNI in a per net namespace table */ static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id, - sa_family_t family, __be16 port) + sa_family_t family, __be16 port, + u32 flags) { struct vxlan_sock *vs; - vs = vxlan_find_sock(net, family, port); + vs = vxlan_find_sock(net, family, port, flags); if (!vs) return NULL; @@ -340,6 +340,11 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, ndm->ndm_flags = fdb->flags; ndm->ndm_type = RTN_UNICAST; + if (!net_eq(dev_net(vxlan->dev), vxlan->net) && + nla_put_s32(skb, NDA_LINK_NETNSID, + peernet2id(dev_net(vxlan->dev), vxlan->net))) + goto nla_put_failure; + if (send_eth && nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->eth_addr)) goto nla_put_failure; @@ -364,7 +369,8 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci)) goto nla_put_failure; - return nlmsg_end(skb, nlh); + nlmsg_end(skb, nlh); + return 0; nla_put_failure: nlmsg_cancel(skb, nlh); @@ -379,6 +385,7 @@ static inline size_t vxlan_nlmsg_size(void) + nla_total_size(sizeof(__be16)) /* NDA_PORT */ + nla_total_size(sizeof(__be32)) /* NDA_VNI */ + nla_total_size(sizeof(__u32)) /* NDA_IFINDEX */ + + nla_total_size(sizeof(__s32)) /* NDA_LINK_NETNSID */ + nla_total_size(sizeof(struct nda_cacheinfo)); } @@ -545,15 +552,51 @@ static int vxlan_fdb_append(struct vxlan_fdb *f, return 1; } -static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff *skb) +static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb, + unsigned int off, + struct vxlanhdr *vh, size_t hdrlen, + u32 data) +{ + size_t start, offset, plen; + + if (skb->remcsum_offload) + return vh; + + if (!NAPI_GRO_CB(skb)->csum_valid) + return NULL; + + start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT; + offset = start + ((data & VXLAN_RCO_UDP) ? + offsetof(struct udphdr, check) : + offsetof(struct tcphdr, check)); + + plen = hdrlen + offset + sizeof(u16); + + /* Pull checksum that will be written */ + if (skb_gro_header_hard(skb, off + plen)) { + vh = skb_gro_header_slow(skb, off + plen, off); + if (!vh) + return NULL; + } + + skb_gro_remcsum_process(skb, (void *)vh + hdrlen, start, offset); + + skb->remcsum_offload = 1; + + return vh; +} + +static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, + struct sk_buff *skb, + struct udp_offload *uoff) { struct sk_buff *p, **pp = NULL; struct vxlanhdr *vh, *vh2; - struct ethhdr *eh, *eh2; - unsigned int hlen, off_vx, off_eth; - const struct packet_offload *ptype; - __be16 type; + unsigned int hlen, off_vx; int flush = 1; + struct vxlan_sock *vs = container_of(uoff, struct vxlan_sock, + udp_offloads); + u32 flags; off_vx = skb_gro_offset(skb); hlen = off_vx + sizeof(*vh); @@ -563,15 +606,17 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff if (unlikely(!vh)) goto out; } + skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */ skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr)); - off_eth = skb_gro_offset(skb); - hlen = off_eth + sizeof(*eh); - eh = skb_gro_header_fast(skb, off_eth); - if (skb_gro_header_hard(skb, hlen)) { - eh = skb_gro_header_slow(skb, hlen, off_eth); - if (unlikely(!eh)) + flags = ntohl(vh->vx_flags); + + if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) { + vh = vxlan_gro_remcsum(skb, off_vx, vh, sizeof(struct vxlanhdr), + ntohl(vh->vx_vni)); + + if (!vh) goto out; } @@ -582,54 +627,27 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff continue; vh2 = (struct vxlanhdr *)(p->data + off_vx); - eh2 = (struct ethhdr *)(p->data + off_eth); - if (vh->vx_vni != vh2->vx_vni || compare_ether_header(eh, eh2)) { + if (vh->vx_flags != vh2->vx_flags || + vh->vx_vni != vh2->vx_vni) { NAPI_GRO_CB(p)->same_flow = 0; continue; } } - type = eh->h_proto; + pp = eth_gro_receive(head, skb); - rcu_read_lock(); - ptype = gro_find_receive_by_type(type); - if (ptype == NULL) { - flush = 1; - goto out_unlock; - } - - skb_gro_pull(skb, sizeof(*eh)); /* pull inner eth header */ - skb_gro_postpull_rcsum(skb, eh, sizeof(*eh)); - pp = ptype->callbacks.gro_receive(head, skb); - -out_unlock: - rcu_read_unlock(); out: NAPI_GRO_CB(skb)->flush |= flush; return pp; } -static int vxlan_gro_complete(struct sk_buff *skb, int nhoff) +static int vxlan_gro_complete(struct sk_buff *skb, int nhoff, + struct udp_offload *uoff) { - struct ethhdr *eh; - struct packet_offload *ptype; - __be16 type; - int vxlan_len = sizeof(struct vxlanhdr) + sizeof(struct ethhdr); - int err = -ENOSYS; - udp_tunnel_gro_complete(skb, nhoff); - eh = (struct ethhdr *)(skb->data + nhoff + sizeof(struct vxlanhdr)); - type = eh->h_proto; - - rcu_read_lock(); - ptype = gro_find_complete_by_type(type); - if (ptype != NULL) - err = ptype->callbacks.gro_complete(skb, nhoff + vxlan_len); - - rcu_read_unlock(); - return err; + return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr)); } /* Notify netdevs that UDP port started listening */ @@ -991,7 +1009,7 @@ static bool vxlan_snoop(struct net_device *dev, if (net_ratelimit()) netdev_info(dev, "%pM migrated from %pIS to %pIS\n", - src_mac, &rdst->remote_ip, &src_ip); + src_mac, &rdst->remote_ip.sa, &src_ip->sa); rdst->remote_ip = *src_ip; f->updated = jiffies; @@ -1131,33 +1149,107 @@ static void vxlan_igmp_leave(struct work_struct *work) dev_put(vxlan->dev); } +static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh, + size_t hdrlen, u32 data) +{ + size_t start, offset, plen; + + if (skb->remcsum_offload) { + /* Already processed in GRO path */ + skb->remcsum_offload = 0; + return vh; + } + + start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT; + offset = start + ((data & VXLAN_RCO_UDP) ? + offsetof(struct udphdr, check) : + offsetof(struct tcphdr, check)); + + plen = hdrlen + offset + sizeof(u16); + + if (!pskb_may_pull(skb, plen)) + return NULL; + + vh = (struct vxlanhdr *)(udp_hdr(skb) + 1); + + skb_remcsum_process(skb, (void *)vh + hdrlen, start, offset); + + return vh; +} + /* Callback from net/ipv4/udp.c to receive packets */ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) { struct vxlan_sock *vs; struct vxlanhdr *vxh; + u32 flags, vni; + struct vxlan_metadata md = {0}; /* Need Vxlan and inner Ethernet header to be present */ if (!pskb_may_pull(skb, VXLAN_HLEN)) goto error; - /* Return packets with reserved bits set */ vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1); - if (vxh->vx_flags != htonl(VXLAN_FLAGS) || - (vxh->vx_vni & htonl(0xff))) { - netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n", - ntohl(vxh->vx_flags), ntohl(vxh->vx_vni)); - goto error; + flags = ntohl(vxh->vx_flags); + vni = ntohl(vxh->vx_vni); + + if (flags & VXLAN_HF_VNI) { + flags &= ~VXLAN_HF_VNI; + } else { + /* VNI flag always required to be set */ + goto bad_flags; } if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB))) goto drop; + vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1); vs = rcu_dereference_sk_user_data(sk); if (!vs) goto drop; - vs->rcv(vs, skb, vxh->vx_vni); + if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) { + vxh = vxlan_remcsum(skb, vxh, sizeof(struct vxlanhdr), vni); + if (!vxh) + goto drop; + + flags &= ~VXLAN_HF_RCO; + vni &= VXLAN_VID_MASK; + } + + /* For backwards compatibility, only allow reserved fields to be + * used by VXLAN extensions if explicitly requested. + */ + if ((flags & VXLAN_HF_GBP) && (vs->flags & VXLAN_F_GBP)) { + struct vxlanhdr_gbp *gbp; + + gbp = (struct vxlanhdr_gbp *)vxh; + md.gbp = ntohs(gbp->policy_id); + + if (gbp->dont_learn) + md.gbp |= VXLAN_GBP_DONT_LEARN; + + if (gbp->policy_applied) + md.gbp |= VXLAN_GBP_POLICY_APPLIED; + + flags &= ~VXLAN_GBP_USED_BITS; + } + + if (flags || (vni & ~VXLAN_VID_MASK)) { + /* If there are any unprocessed flags remaining treat + * this as a malformed packet. This behavior diverges from + * VXLAN RFC (RFC7348) which stipulates that bits in reserved + * in reserved fields are to be ignored. The approach here + * maintains compatbility with previous stack code, and also + * is more robust and provides a little more security in + * adding extensions to VXLAN. + */ + + goto bad_flags; + } + + md.vni = vxh->vx_vni; + vs->rcv(vs, skb, &md); return 0; drop: @@ -1165,13 +1257,17 @@ drop: kfree_skb(skb); return 0; +bad_flags: + netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n", + ntohl(vxh->vx_flags), ntohl(vxh->vx_vni)); + error: /* Return non vxlan pkt */ return 1; } -static void vxlan_rcv(struct vxlan_sock *vs, - struct sk_buff *skb, __be32 vx_vni) +static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, + struct vxlan_metadata *md) { struct iphdr *oip = NULL; struct ipv6hdr *oip6 = NULL; @@ -1182,7 +1278,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, int err = 0; union vxlan_addr *remote_ip; - vni = ntohl(vx_vni) >> 8; + vni = ntohl(md->vni) >> 8; /* Is this VNI defined? */ vxlan = vxlan_vs_find_vni(vs, vni); if (!vxlan) @@ -1216,6 +1312,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, goto drop; skb_reset_network_header(skb); + skb->mark = md->gbp; if (oip6) err = IP6_ECN_decapsulate(oip6, skb); @@ -1565,20 +1662,54 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) return false; } +static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags, + struct vxlan_metadata *md) +{ + struct vxlanhdr_gbp *gbp; + + if (!md->gbp) + return; + + gbp = (struct vxlanhdr_gbp *)vxh; + vxh->vx_flags |= htonl(VXLAN_HF_GBP); + + if (md->gbp & VXLAN_GBP_DONT_LEARN) + gbp->dont_learn = 1; + + if (md->gbp & VXLAN_GBP_POLICY_APPLIED) + gbp->policy_applied = 1; + + gbp->policy_id = htons(md->gbp & VXLAN_GBP_ID_MASK); +} + #if IS_ENABLED(CONFIG_IPV6) -static int vxlan6_xmit_skb(struct vxlan_sock *vs, - struct dst_entry *dst, struct sk_buff *skb, +static int vxlan6_xmit_skb(struct dst_entry *dst, struct sk_buff *skb, struct net_device *dev, struct in6_addr *saddr, struct in6_addr *daddr, __u8 prio, __u8 ttl, - __be16 src_port, __be16 dst_port, __be32 vni, - bool xnet) + __be16 src_port, __be16 dst_port, + struct vxlan_metadata *md, bool xnet, u32 vxflags) { struct vxlanhdr *vxh; int min_headroom; int err; - bool udp_sum = !udp_get_no_check6_tx(vs->sock->sk); + bool udp_sum = !(vxflags & VXLAN_F_UDP_ZERO_CSUM6_TX); + int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; + u16 hdrlen = sizeof(struct vxlanhdr); - skb = udp_tunnel_handle_offloads(skb, udp_sum); + if ((vxflags & VXLAN_F_REMCSUM_TX) && + skb->ip_summed == CHECKSUM_PARTIAL) { + int csum_start = skb_checksum_start_offset(skb); + + if (csum_start <= VXLAN_MAX_REMCSUM_START && + !(csum_start & VXLAN_RCO_SHIFT_MASK) && + (skb->csum_offset == offsetof(struct udphdr, check) || + skb->csum_offset == offsetof(struct tcphdr, check))) { + udp_sum = false; + type |= SKB_GSO_TUNNEL_REMCSUM; + } + } + + skb = iptunnel_handle_offloads(skb, udp_sum, type); if (IS_ERR(skb)) { err = -EINVAL; goto err; @@ -1588,7 +1719,7 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len + VXLAN_HLEN + sizeof(struct ipv6hdr) - + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0); + + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0); /* Need space for new headers (invalidates iph ptr) */ err = skb_cow_head(skb, min_headroom); @@ -1604,13 +1735,33 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, } vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); - vxh->vx_flags = htonl(VXLAN_FLAGS); - vxh->vx_vni = vni; + vxh->vx_flags = htonl(VXLAN_HF_VNI); + vxh->vx_vni = md->vni; + + if (type & SKB_GSO_TUNNEL_REMCSUM) { + u32 data = (skb_checksum_start_offset(skb) - hdrlen) >> + VXLAN_RCO_SHIFT; + + if (skb->csum_offset == offsetof(struct udphdr, check)) + data |= VXLAN_RCO_UDP; + + vxh->vx_vni |= htonl(data); + vxh->vx_flags |= htonl(VXLAN_HF_RCO); + + if (!skb_is_gso(skb)) { + skb->ip_summed = CHECKSUM_NONE; + skb->encapsulation = 0; + } + } + + if (vxflags & VXLAN_F_GBP) + vxlan_build_gbp_hdr(vxh, vxflags, md); skb_set_inner_protocol(skb, htons(ETH_P_TEB)); - udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio, - ttl, src_port, dst_port); + udp_tunnel6_xmit_skb(dst, skb, dev, saddr, daddr, prio, + ttl, src_port, dst_port, + !!(vxflags & VXLAN_F_UDP_ZERO_CSUM6_TX)); return 0; err: dst_release(dst); @@ -1618,23 +1769,38 @@ err: } #endif -int vxlan_xmit_skb(struct vxlan_sock *vs, - struct rtable *rt, struct sk_buff *skb, +int vxlan_xmit_skb(struct rtable *rt, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, - __be16 src_port, __be16 dst_port, __be32 vni, bool xnet) + __be16 src_port, __be16 dst_port, + struct vxlan_metadata *md, bool xnet, u32 vxflags) { struct vxlanhdr *vxh; int min_headroom; int err; - bool udp_sum = !vs->sock->sk->sk_no_check_tx; + bool udp_sum = !!(vxflags & VXLAN_F_UDP_CSUM); + int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; + u16 hdrlen = sizeof(struct vxlanhdr); - skb = udp_tunnel_handle_offloads(skb, udp_sum); + if ((vxflags & VXLAN_F_REMCSUM_TX) && + skb->ip_summed == CHECKSUM_PARTIAL) { + int csum_start = skb_checksum_start_offset(skb); + + if (csum_start <= VXLAN_MAX_REMCSUM_START && + !(csum_start & VXLAN_RCO_SHIFT_MASK) && + (skb->csum_offset == offsetof(struct udphdr, check) || + skb->csum_offset == offsetof(struct tcphdr, check))) { + udp_sum = false; + type |= SKB_GSO_TUNNEL_REMCSUM; + } + } + + skb = iptunnel_handle_offloads(skb, udp_sum, type); if (IS_ERR(skb)) return PTR_ERR(skb); min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len + VXLAN_HLEN + sizeof(struct iphdr) - + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0); + + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0); /* Need space for new headers (invalidates iph ptr) */ err = skb_cow_head(skb, min_headroom); @@ -1648,13 +1814,33 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, return -ENOMEM; vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); - vxh->vx_flags = htonl(VXLAN_FLAGS); - vxh->vx_vni = vni; + vxh->vx_flags = htonl(VXLAN_HF_VNI); + vxh->vx_vni = md->vni; + + if (type & SKB_GSO_TUNNEL_REMCSUM) { + u32 data = (skb_checksum_start_offset(skb) - hdrlen) >> + VXLAN_RCO_SHIFT; + + if (skb->csum_offset == offsetof(struct udphdr, check)) + data |= VXLAN_RCO_UDP; + + vxh->vx_vni |= htonl(data); + vxh->vx_flags |= htonl(VXLAN_HF_RCO); + + if (!skb_is_gso(skb)) { + skb->ip_summed = CHECKSUM_NONE; + skb->encapsulation = 0; + } + } + + if (vxflags & VXLAN_F_GBP) + vxlan_build_gbp_hdr(vxh, vxflags, md); skb_set_inner_protocol(skb, htons(ETH_P_TEB)); - return udp_tunnel_xmit_skb(vs->sock, rt, skb, src, dst, tos, - ttl, df, src_port, dst_port, xnet); + return udp_tunnel_xmit_skb(rt, skb, src, dst, tos, + ttl, df, src_port, dst_port, xnet, + !(vxflags & VXLAN_F_UDP_CSUM)); } EXPORT_SYMBOL_GPL(vxlan_xmit_skb); @@ -1711,6 +1897,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, const struct iphdr *old_iph; struct flowi4 fl4; union vxlan_addr *dst; + struct vxlan_metadata md; __be16 src_port = 0, dst_port; u32 vni; __be16 df = 0; @@ -1772,7 +1959,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, ip_rt_put(rt); dst_vxlan = vxlan_find_vni(vxlan->net, vni, - dst->sa.sa_family, dst_port); + dst->sa.sa_family, dst_port, + vxlan->flags); if (!dst_vxlan) goto tx_error; vxlan_encap_bypass(skb, vxlan, dst_vxlan); @@ -1781,12 +1969,14 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + md.vni = htonl(vni << 8); + md.gbp = skb->mark; - err = vxlan_xmit_skb(vxlan->vn_sock, rt, skb, - fl4.saddr, dst->sin.sin_addr.s_addr, - tos, ttl, df, src_port, dst_port, - htonl(vni << 8), - !net_eq(vxlan->net, dev_net(vxlan->dev))); + err = vxlan_xmit_skb(rt, skb, fl4.saddr, + dst->sin.sin_addr.s_addr, tos, ttl, df, + src_port, dst_port, &md, + !net_eq(vxlan->net, dev_net(vxlan->dev)), + vxlan->flags); if (err < 0) { /* skb is already freed. */ skb = NULL; @@ -1830,7 +2020,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, dst_release(ndst); dst_vxlan = vxlan_find_vni(vxlan->net, vni, - dst->sa.sa_family, dst_port); + dst->sa.sa_family, dst_port, + vxlan->flags); if (!dst_vxlan) goto tx_error; vxlan_encap_bypass(skb, vxlan, dst_vxlan); @@ -1838,11 +2029,13 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, } ttl = ttl ? : ip6_dst_hoplimit(ndst); + md.vni = htonl(vni << 8); + md.gbp = skb->mark; - err = vxlan6_xmit_skb(vxlan->vn_sock, ndst, skb, - dev, &fl6.saddr, &fl6.daddr, 0, ttl, - src_port, dst_port, htonl(vni << 8), - !net_eq(vxlan->net, dev_net(vxlan->dev))); + err = vxlan6_xmit_skb(ndst, skb, dev, &fl6.saddr, &fl6.daddr, + 0, ttl, src_port, dst_port, &md, + !net_eq(vxlan->net, dev_net(vxlan->dev)), + vxlan->flags); #endif } @@ -1998,7 +2191,7 @@ static int vxlan_init(struct net_device *dev) spin_lock(&vn->sock_lock); vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET, - vxlan->dst_port); + vxlan->dst_port, vxlan->flags); if (vs && atomic_add_unless(&vs->refcnt, 1, 0)) { /* If we have a socket with same port already, reuse it */ vxlan_vs_add_dev(vs, vxlan); @@ -2242,6 +2435,9 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_UDP_CSUM] = { .type = NLA_U8 }, [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 }, [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 }, + [IFLA_VXLAN_REMCSUM_TX] = { .type = NLA_U8 }, + [IFLA_VXLAN_REMCSUM_RX] = { .type = NLA_U8 }, + [IFLA_VXLAN_GBP] = { .type = NLA_FLAG, }, }; static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -2311,15 +2507,11 @@ static struct socket *vxlan_create_sock(struct net *net, bool ipv6, if (ipv6) { udp_conf.family = AF_INET6; - udp_conf.use_udp6_tx_checksums = - !(flags & VXLAN_F_UDP_ZERO_CSUM6_TX); udp_conf.use_udp6_rx_checksums = !(flags & VXLAN_F_UDP_ZERO_CSUM6_RX); } else { udp_conf.family = AF_INET; udp_conf.local_ip.s_addr = INADDR_ANY; - udp_conf.use_udp_checksums = - !!(flags & VXLAN_F_UDP_CSUM); } udp_conf.local_udp_port = port; @@ -2363,6 +2555,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port, atomic_set(&vs->refcnt, 1); vs->rcv = rcv; vs->data = data; + vs->flags = (flags & VXLAN_F_RCV_FLAGS); /* Initialize the vxlan udp offloads structure */ vs->udp_offloads.port = port; @@ -2401,7 +2594,7 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, return vs; spin_lock(&vn->sock_lock); - vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port); + vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port, flags); if (vs && ((vs->rcv != rcv) || !atomic_add_unless(&vs->refcnt, 1, 0))) vs = ERR_PTR(-EBUSY); @@ -2432,10 +2625,10 @@ static void vxlan_sock_work(struct work_struct *work) dev_put(vxlan->dev); } -static int vxlan_newlink(struct net *net, struct net_device *dev, +static int vxlan_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { - struct vxlan_net *vn = net_generic(net, vxlan_net_id); + struct vxlan_net *vn = net_generic(src_net, vxlan_net_id); struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_rdst *dst = &vxlan->default_dst; __u32 vni; @@ -2445,7 +2638,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, if (!data[IFLA_VXLAN_ID]) return -EINVAL; - vxlan->net = dev_net(dev); + vxlan->net = src_net; vni = nla_get_u32(data[IFLA_VXLAN_ID]); dst->remote_vni = vni; @@ -2481,7 +2674,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, if (data[IFLA_VXLAN_LINK] && (dst->remote_ifindex = nla_get_u32(data[IFLA_VXLAN_LINK]))) { struct net_device *lowerdev - = __dev_get_by_index(net, dst->remote_ifindex); + = __dev_get_by_index(src_net, dst->remote_ifindex); if (!lowerdev) { pr_info("ifindex %d does not exist\n", dst->remote_ifindex); @@ -2557,8 +2750,19 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX])) vxlan->flags |= VXLAN_F_UDP_ZERO_CSUM6_RX; - if (vxlan_find_vni(net, vni, use_ipv6 ? AF_INET6 : AF_INET, - vxlan->dst_port)) { + if (data[IFLA_VXLAN_REMCSUM_TX] && + nla_get_u8(data[IFLA_VXLAN_REMCSUM_TX])) + vxlan->flags |= VXLAN_F_REMCSUM_TX; + + if (data[IFLA_VXLAN_REMCSUM_RX] && + nla_get_u8(data[IFLA_VXLAN_REMCSUM_RX])) + vxlan->flags |= VXLAN_F_REMCSUM_RX; + + if (data[IFLA_VXLAN_GBP]) + vxlan->flags |= VXLAN_F_GBP; + + if (vxlan_find_vni(src_net, vni, use_ipv6 ? AF_INET6 : AF_INET, + vxlan->dst_port, vxlan->flags)) { pr_info("duplicate VNI %u\n", vni); return -EEXIST; } @@ -2625,6 +2829,8 @@ static size_t vxlan_get_size(const struct net_device *dev) nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_CSUM */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_TX */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_RX */ + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_TX */ + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_RX */ 0; } @@ -2690,18 +2896,33 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) || nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, - !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_RX))) + !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) || + nla_put_u8(skb, IFLA_VXLAN_REMCSUM_TX, + !!(vxlan->flags & VXLAN_F_REMCSUM_TX)) || + nla_put_u8(skb, IFLA_VXLAN_REMCSUM_RX, + !!(vxlan->flags & VXLAN_F_REMCSUM_RX))) goto nla_put_failure; if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports)) goto nla_put_failure; + if (vxlan->flags & VXLAN_F_GBP && + nla_put_flag(skb, IFLA_VXLAN_GBP)) + goto nla_put_failure; + return 0; nla_put_failure: return -EMSGSIZE; } +static struct net *vxlan_get_link_net(const struct net_device *dev) +{ + struct vxlan_dev *vxlan = netdev_priv(dev); + + return vxlan->net; +} + static struct rtnl_link_ops vxlan_link_ops __read_mostly = { .kind = "vxlan", .maxtype = IFLA_VXLAN_MAX, @@ -2713,6 +2934,7 @@ static struct rtnl_link_ops vxlan_link_ops __read_mostly = { .dellink = vxlan_dellink, .get_size = vxlan_get_size, .fill_info = vxlan_fill_info, + .get_link_net = vxlan_get_link_net, }; static void vxlan_handle_lowerdev_unregister(struct vxlan_net *vn, diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 94e234975c61..a2fdd15f285a 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -25,7 +25,7 @@ if WAN # There is no way to detect a comtrol sv11 - force it modular for now. config HOSTESS_SV11 tristate "Comtrol Hostess SV-11 support" - depends on ISA && m && ISA_DMA_API && INET && HDLC + depends on ISA && m && ISA_DMA_API && INET && HDLC && VIRT_TO_BUS help Driver for Comtrol Hostess SV-11 network card which operates on low speed synchronous serial links at up to @@ -37,7 +37,7 @@ config HOSTESS_SV11 # The COSA/SRP driver has not been tested as non-modular yet. config COSA tristate "COSA/SRP sync serial boards support" - depends on ISA && m && ISA_DMA_API && HDLC + depends on ISA && m && ISA_DMA_API && HDLC && VIRT_TO_BUS ---help--- Driver for COSA and SRP synchronous serial boards. @@ -87,7 +87,7 @@ config LANMEDIA # There is no way to detect a Sealevel board. Force it modular config SEALEVEL_4021 tristate "Sealevel Systems 4021 support" - depends on ISA && m && ISA_DMA_API && INET && HDLC + depends on ISA && m && ISA_DMA_API && INET && HDLC && VIRT_TO_BUS help This is a driver for the Sealevel Systems ACB 56 serial I/O adapter. diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 17fcaabb2687..f07a61899545 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1837,6 +1837,7 @@ static int adm8211_probe(struct pci_dev *pdev, if (!priv->map) { printk(KERN_ERR "%s (adm8211): Cannot map device memory\n", pci_name(pdev)); + err = -ENOMEM; goto err_free_dev; } diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index ccba4fea7269..1eebe2ea3dfb 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -64,6 +64,7 @@ enum ath_op_flags { ATH_OP_HW_RESET, ATH_OP_SCANNING, ATH_OP_MULTI_CHANNEL, + ATH_OP_WOW_ENABLED, }; enum ath_bus_type { diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 8b1b1adb477a..f4dbb3e93bf8 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -8,11 +8,15 @@ ath10k_core-y += mac.o \ htt_tx.o \ txrx.o \ wmi.o \ - bmi.o + wmi-tlv.o \ + bmi.o \ + hw.o ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o +ath10k_core-$(CONFIG_THERMAL) += thermal.o +ath10k_core-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o ath10k_pci-y += pci.o \ diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index a156e6e48708..e508c65b6ba8 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -803,7 +803,7 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar) int ce_id; for (ce_id = 0; ce_id < CE_COUNT; ce_id++) { - u32 ctrl_addr = ath10k_ce_base_address(ce_id); + u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id); ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr); ath10k_ce_error_intr_disable(ar, ctrl_addr); @@ -832,7 +832,7 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar, struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; struct ath10k_ce_ring *src_ring = ce_state->src_ring; - u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id); + u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id); nentries = roundup_pow_of_two(attr->src_nentries); @@ -869,7 +869,7 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; - u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id); + u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id); nentries = roundup_pow_of_two(attr->dest_nentries); @@ -1051,7 +1051,7 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id) { - u32 ctrl_addr = ath10k_ce_base_address(ce_id); + u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id); ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, 0); ath10k_ce_src_ring_size_set(ar, ctrl_addr, 0); @@ -1061,7 +1061,7 @@ static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id) static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id) { - u32 ctrl_addr = ath10k_ce_base_address(ce_id); + u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id); ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, 0); ath10k_ce_dest_ring_size_set(ar, ctrl_addr, 0); @@ -1093,10 +1093,12 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC > (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); + BUILD_BUG_ON(2*TARGET_TLV_NUM_MSDU_DESC > + (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); ce_state->ar = ar; ce_state->id = ce_id; - ce_state->ctrl_addr = ath10k_ce_base_address(ce_id); + ce_state->ctrl_addr = ath10k_ce_base_address(ar, ce_id); ce_state->attr_flags = attr->flags; ce_state->src_sz_max = attr->src_sz_max; diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 617a151e8ce4..c18647b87f71 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -394,7 +394,7 @@ struct ce_attr { #define DST_WATERMARK_HIGH_RESET 0 #define DST_WATERMARK_ADDRESS 0x0050 -static inline u32 ath10k_ce_base_address(unsigned int ce_id) +static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) { return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id; } diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 7762061a1944..310e12bc078a 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -17,6 +17,7 @@ #include #include +#include #include "core.h" #include "mac.h" @@ -27,20 +28,18 @@ #include "debug.h" #include "htt.h" #include "testmode.h" +#include "wmi-ops.h" unsigned int ath10k_debug_mask; static bool uart_print; -static unsigned int ath10k_p2p; static bool skip_otp; module_param_named(debug_mask, ath10k_debug_mask, uint, 0644); module_param(uart_print, bool, 0644); -module_param_named(p2p, ath10k_p2p, uint, 0644); module_param(skip_otp, bool, 0644); MODULE_PARM_DESC(debug_mask, "Debugging mask"); MODULE_PARM_DESC(uart_print, "Uart target debugging"); -MODULE_PARM_DESC(p2p, "Enable ath10k P2P support"); MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); static const struct ath10k_hw_params ath10k_hw_params_list[] = { @@ -48,11 +47,57 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .id = QCA988X_HW_2_0_VERSION, .name = "qca988x hw2.0", .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, + .uart_pin = 7, .fw = { .dir = QCA988X_HW_2_0_FW_DIR, .fw = QCA988X_HW_2_0_FW_FILE, .otp = QCA988X_HW_2_0_OTP_FILE, .board = QCA988X_HW_2_0_BOARD_DATA_FILE, + .board_size = QCA988X_BOARD_DATA_SZ, + .board_ext_size = QCA988X_BOARD_EXT_DATA_SZ, + }, + }, + { + .id = QCA6174_HW_2_1_VERSION, + .name = "qca6174 hw2.1", + .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, + .uart_pin = 6, + .fw = { + .dir = QCA6174_HW_2_1_FW_DIR, + .fw = QCA6174_HW_2_1_FW_FILE, + .otp = QCA6174_HW_2_1_OTP_FILE, + .board = QCA6174_HW_2_1_BOARD_DATA_FILE, + .board_size = QCA6174_BOARD_DATA_SZ, + .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, + }, + }, + { + .id = QCA6174_HW_3_0_VERSION, + .name = "qca6174 hw3.0", + .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, + .uart_pin = 6, + .fw = { + .dir = QCA6174_HW_3_0_FW_DIR, + .fw = QCA6174_HW_3_0_FW_FILE, + .otp = QCA6174_HW_3_0_OTP_FILE, + .board = QCA6174_HW_3_0_BOARD_DATA_FILE, + .board_size = QCA6174_BOARD_DATA_SZ, + .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, + }, + }, + { + .id = QCA6174_HW_3_2_VERSION, + .name = "qca6174 hw3.2", + .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, + .uart_pin = 6, + .fw = { + /* uses same binaries as hw3.0 */ + .dir = QCA6174_HW_3_0_FW_DIR, + .fw = QCA6174_HW_3_0_FW_FILE, + .otp = QCA6174_HW_3_0_OTP_FILE, + .board = QCA6174_HW_3_0_BOARD_DATA_FILE, + .board_size = QCA6174_BOARD_DATA_SZ, + .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, }, }, }; @@ -146,8 +191,8 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data, size_t data_len) { - u32 board_data_size = QCA988X_BOARD_DATA_SZ; - u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ; + u32 board_data_size = ar->hw_params.fw.board_size; + u32 board_ext_data_size = ar->hw_params.fw.board_ext_size; u32 board_ext_data_addr; int ret; @@ -193,7 +238,7 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data, static int ath10k_download_board_data(struct ath10k *ar, const void *data, size_t data_len) { - u32 board_data_size = QCA988X_BOARD_DATA_SZ; + u32 board_data_size = ar->hw_params.fw.board_size; u32 address; int ret; @@ -249,6 +294,63 @@ static int ath10k_download_cal_file(struct ath10k *ar) return 0; } +static int ath10k_download_cal_dt(struct ath10k *ar) +{ + struct device_node *node; + int data_len; + void *data; + int ret; + + node = ar->dev->of_node; + if (!node) + /* Device Tree is optional, don't print any warnings if + * there's no node for ath10k. + */ + return -ENOENT; + + if (!of_get_property(node, "qcom,ath10k-calibration-data", + &data_len)) { + /* The calibration data node is optional */ + return -ENOENT; + } + + if (data_len != QCA988X_CAL_DATA_LEN) { + ath10k_warn(ar, "invalid calibration data length in DT: %d\n", + data_len); + ret = -EMSGSIZE; + goto out; + } + + data = kmalloc(data_len, GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto out; + } + + ret = of_property_read_u8_array(node, "qcom,ath10k-calibration-data", + data, data_len); + if (ret) { + ath10k_warn(ar, "failed to read calibration data from DT: %d\n", + ret); + goto out_free; + } + + ret = ath10k_download_board_data(ar, data, data_len); + if (ret) { + ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n", + ret); + goto out_free; + } + + ret = 0; + +out_free: + kfree(data); + +out: + return ret; +} + static int ath10k_download_and_run_otp(struct ath10k *ar) { u32 result, address = ar->hw_params.patch_load_addr; @@ -447,7 +549,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) int ie_id, i, index, bit, ret; struct ath10k_fw_ie *hdr; const u8 *data; - __le32 *timestamp; + __le32 *timestamp, *version; /* first fetch the firmware file (firmware-*.bin) */ ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name); @@ -562,6 +664,17 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) ar->otp_len = ie_len; break; + case ATH10K_FW_IE_WMI_OP_VERSION: + if (ie_len != sizeof(u32)) + break; + + version = (__le32 *)data; + + ar->wmi.op_version = le32_to_cpup(version); + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie wmi op version %d\n", + ar->wmi.op_version); + break; default: ath10k_warn(ar, "Unknown FW IE: %u\n", le32_to_cpu(hdr->id)); @@ -582,13 +695,6 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) goto err; } - if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) && - !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well"); - ret = -EINVAL; - goto err; - } - /* now fetch the board file */ if (ar->hw_params.fw.board == NULL) { ath10k_err(ar, "board data file not defined"); @@ -624,6 +730,13 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) /* calibration file is optional, don't check for any errors */ ath10k_fetch_cal_file(ar); + ar->fw_api = 4; + ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); + + ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API4_FILE); + if (ret == 0) + goto success; + ar->fw_api = 3; ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); @@ -662,7 +775,17 @@ static int ath10k_download_cal_data(struct ath10k *ar) } ath10k_dbg(ar, ATH10K_DBG_BOOT, - "boot did not find a calibration file, try OTP next: %d\n", + "boot did not find a calibration file, try DT next: %d\n", + ret); + + ret = ath10k_download_cal_dt(ar); + if (ret == 0) { + ar->cal_mode = ATH10K_CAL_MODE_DT; + goto done; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot did not find DT entry, try OTP next: %d\n", ret); ret = ath10k_download_and_run_otp(ar); @@ -696,7 +819,7 @@ static int ath10k_init_uart(struct ath10k *ar) if (!uart_print) return 0; - ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7); + ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, ar->hw_params.uart_pin); if (ret) { ath10k_warn(ar, "could not enable UART prints (%d)\n", ret); return ret; @@ -764,6 +887,7 @@ static void ath10k_core_restart(struct work_struct *work) complete_all(&ar->offchan_tx_completed); complete_all(&ar->install_key_done); complete_all(&ar->vdev_setup_done); + complete_all(&ar->thermal.wmi_sync); wake_up(&ar->htt.empty_tx_wq); wake_up(&ar->wmi.tx_credits_wq); wake_up(&ar->peer_mapping_wq); @@ -799,15 +923,63 @@ static void ath10k_core_restart(struct work_struct *work) mutex_unlock(&ar->conf_mutex); } -static void ath10k_core_init_max_sta_count(struct ath10k *ar) +static int ath10k_core_init_firmware_features(struct ath10k *ar) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - ar->max_num_peers = TARGET_10X_NUM_PEERS; - ar->max_num_stations = TARGET_10X_NUM_STATIONS; - } else { + if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) && + !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well"); + return -EINVAL; + } + + if (ar->wmi.op_version >= ATH10K_FW_WMI_OP_VERSION_MAX) { + ath10k_err(ar, "unsupported WMI OP version (max %d): %d\n", + ATH10K_FW_WMI_OP_VERSION_MAX, ar->wmi.op_version); + return -EINVAL; + } + + /* Backwards compatibility for firmwares without + * ATH10K_FW_IE_WMI_OP_VERSION. + */ + if (ar->wmi.op_version == ATH10K_FW_WMI_OP_VERSION_UNSET) { + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, + ar->fw_features)) + ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_2; + else + ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1; + } else { + ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_MAIN; + } + } + + switch (ar->wmi.op_version) { + case ATH10K_FW_WMI_OP_VERSION_MAIN: ar->max_num_peers = TARGET_NUM_PEERS; ar->max_num_stations = TARGET_NUM_STATIONS; + ar->max_num_vdevs = TARGET_NUM_VDEVS; + ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC; + break; + case ATH10K_FW_WMI_OP_VERSION_10_1: + case ATH10K_FW_WMI_OP_VERSION_10_2: + case ATH10K_FW_WMI_OP_VERSION_10_2_4: + ar->max_num_peers = TARGET_10X_NUM_PEERS; + ar->max_num_stations = TARGET_10X_NUM_STATIONS; + ar->max_num_vdevs = TARGET_10X_NUM_VDEVS; + ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; + break; + case ATH10K_FW_WMI_OP_VERSION_TLV: + ar->max_num_peers = TARGET_TLV_NUM_PEERS; + ar->max_num_stations = TARGET_TLV_NUM_STATIONS; + ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS; + ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC; + break; + case ATH10K_FW_WMI_OP_VERSION_UNSET: + case ATH10K_FW_WMI_OP_VERSION_MAX: + WARN_ON(1); + return -EINVAL; } + + return 0; } int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) @@ -932,6 +1104,18 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) goto err_hif_stop; } + /* If firmware indicates Full Rx Reorder support it must be used in a + * slightly different manner. Let HTT code know. + */ + ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER, + ar->wmi.svc_map)); + + status = ath10k_htt_rx_ring_refill(ar); + if (status) { + ath10k_err(ar, "failed to refill htt rx ring: %d\n", status); + goto err_hif_stop; + } + /* we don't care about HTT in UTF mode */ if (mode == ATH10K_FIRMWARE_MODE_NORMAL) { status = ath10k_htt_setup(&ar->htt); @@ -945,10 +1129,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) if (status) goto err_hif_stop; - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - ar->free_vdev_map = (1LL << TARGET_10X_NUM_VDEVS) - 1; - else - ar->free_vdev_map = (1LL << TARGET_NUM_VDEVS) - 1; + ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1; INIT_LIST_HEAD(&ar->arvifs); @@ -1025,8 +1206,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ret = ath10k_bmi_get_target_info(ar, &target_info); if (ret) { ath10k_err(ar, "could not get target info (%d)\n", ret); - ath10k_hif_power_down(ar); - return ret; + goto err_power_down; } ar->target_version = target_info.version; @@ -1035,28 +1215,28 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ret = ath10k_init_hw_params(ar); if (ret) { ath10k_err(ar, "could not get hw params (%d)\n", ret); - ath10k_hif_power_down(ar); - return ret; + goto err_power_down; } ret = ath10k_core_fetch_firmware_files(ar); if (ret) { ath10k_err(ar, "could not fetch firmware files (%d)\n", ret); - ath10k_hif_power_down(ar); - return ret; + goto err_power_down; } - ath10k_core_init_max_sta_count(ar); + ret = ath10k_core_init_firmware_features(ar); + if (ret) { + ath10k_err(ar, "fatal problem with firmware features: %d\n", + ret); + goto err_free_firmware_files; + } mutex_lock(&ar->conf_mutex); ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); if (ret) { ath10k_err(ar, "could not init core (%d)\n", ret); - ath10k_core_free_firmware_files(ar); - ath10k_hif_power_down(ar); - mutex_unlock(&ar->conf_mutex); - return ret; + goto err_unlock; } ath10k_print_driver_info(ar); @@ -1066,34 +1246,17 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ath10k_hif_power_down(ar); return 0; -} -static int ath10k_core_check_chip_id(struct ath10k *ar) -{ - u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV); +err_unlock: + mutex_unlock(&ar->conf_mutex); - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n", - ar->chip_id, hw_revision); +err_free_firmware_files: + ath10k_core_free_firmware_files(ar); - /* Check that we are not using hw1.0 (some of them have same pci id - * as hw2.0) before doing anything else as ath10k crashes horribly - * due to missing hw1.0 workarounds. */ - switch (hw_revision) { - case QCA988X_HW_1_0_CHIP_ID_REV: - ath10k_err(ar, "ERROR: qca988x hw1.0 is not supported\n"); - return -EOPNOTSUPP; +err_power_down: + ath10k_hif_power_down(ar); - case QCA988X_HW_2_0_CHIP_ID_REV: - /* known hardware revision, continue normally */ - return 0; - - default: - ath10k_warn(ar, "Warning: hardware revision unknown (0x%x), expect problems\n", - ar->chip_id); - return 0; - } - - return 0; + return ret; } static void ath10k_core_register_work(struct work_struct *work) @@ -1125,9 +1288,18 @@ static void ath10k_core_register_work(struct work_struct *work) goto err_debug_destroy; } + status = ath10k_thermal_register(ar); + if (status) { + ath10k_err(ar, "could not register thermal device: %d\n", + status); + goto err_spectral_destroy; + } + set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags); return; +err_spectral_destroy: + ath10k_spectral_destroy(ar); err_debug_destroy: ath10k_debug_destroy(ar); err_unregister_mac: @@ -1143,16 +1315,7 @@ err: int ath10k_core_register(struct ath10k *ar, u32 chip_id) { - int status; - ar->chip_id = chip_id; - - status = ath10k_core_check_chip_id(ar); - if (status) { - ath10k_err(ar, "Unsupported chip id 0x%08x\n", ar->chip_id); - return status; - } - queue_work(ar->workqueue, &ar->register_work); return 0; @@ -1166,6 +1329,7 @@ void ath10k_core_unregister(struct ath10k *ar) if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags)) return; + ath10k_thermal_unregister(ar); /* Stop spectral before unregistering from mac80211 to remove the * relayfs debugfs file cleanly. Otherwise the parent debugfs tree * would be already be free'd recursively, leading to a double free. @@ -1187,6 +1351,7 @@ EXPORT_SYMBOL(ath10k_core_unregister); struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, enum ath10k_bus bus, + enum ath10k_hw_rev hw_rev, const struct ath10k_hif_ops *hif_ops) { struct ath10k *ar; @@ -1198,13 +1363,25 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ar->ath_common.priv = ar; ar->ath_common.hw = ar->hw; - - ar->p2p = !!ath10k_p2p; ar->dev = dev; - + ar->hw_rev = hw_rev; ar->hif.ops = hif_ops; ar->hif.bus = bus; + switch (hw_rev) { + case ATH10K_HW_QCA988X: + ar->regs = &qca988x_regs; + break; + case ATH10K_HW_QCA6174: + ar->regs = &qca6174_regs; + break; + default: + ath10k_err(ar, "unsupported core hardware revision %d\n", + hw_rev); + ret = -ENOTSUPP; + goto err_free_mac; + } + init_completion(&ar->scan.started); init_completion(&ar->scan.completed); init_completion(&ar->scan.on_channel); @@ -1212,6 +1389,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, init_completion(&ar->install_key_done); init_completion(&ar->vdev_setup_done); + init_completion(&ar->thermal.wmi_sync); INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 514c219263a5..d60e46fe6d19 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -34,6 +34,7 @@ #include "../regd.h" #include "../dfs_pattern_detector.h" #include "spectral.h" +#include "thermal.h" #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -96,6 +97,11 @@ struct ath10k_skb_cb { } bcn; } __packed; +struct ath10k_skb_rxcb { + dma_addr_t paddr; + struct hlist_node hlist; +}; + static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) { BUILD_BUG_ON(sizeof(struct ath10k_skb_cb) > @@ -103,6 +109,15 @@ static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb) return (struct ath10k_skb_cb *)&IEEE80211_SKB_CB(skb)->driver_data; } +static inline struct ath10k_skb_rxcb *ATH10K_SKB_RXCB(struct sk_buff *skb) +{ + BUILD_BUG_ON(sizeof(struct ath10k_skb_rxcb) > sizeof(skb->cb)); + return (struct ath10k_skb_rxcb *)skb->cb; +} + +#define ATH10K_RXCB_SKB(rxcb) \ + container_of((void *)rxcb, struct sk_buff, cb) + static inline u32 host_interest_item_address(u32 item_offset) { return QCA988X_HOST_INTEREST_ADDRESS + item_offset; @@ -120,6 +135,7 @@ struct ath10k_mem_chunk { }; struct ath10k_wmi { + enum ath10k_fw_wmi_op_version op_version; enum ath10k_htc_ep_id eid; struct completion service_ready; struct completion unified_ready; @@ -128,6 +144,7 @@ struct ath10k_wmi { struct wmi_cmd_map *cmd; struct wmi_vdev_param_map *vdev_param; struct wmi_pdev_param_map *pdev_param; + const struct wmi_ops *ops; u32 num_mem_chunks; struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS]; @@ -236,10 +253,21 @@ struct ath10k_sta { u32 smps; struct work_struct update_wk; + +#ifdef CONFIG_MAC80211_DEBUGFS + /* protected by conf_mutex */ + bool aggr_mode; +#endif }; #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) +enum ath10k_beacon_state { + ATH10K_BEACON_SCHEDULED = 0, + ATH10K_BEACON_SENDING, + ATH10K_BEACON_SENT, +}; + struct ath10k_vif { struct list_head list; @@ -250,7 +278,7 @@ struct ath10k_vif { u32 dtim_period; struct sk_buff *beacon; /* protected by data_lock */ - bool beacon_sent; + enum ath10k_beacon_state beacon_state; void *beacon_buf; dma_addr_t beacon_paddr; @@ -263,10 +291,8 @@ struct ath10k_vif { u32 aid; u8 bssid[ETH_ALEN]; - struct work_struct wep_key_work; struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1]; - u8 def_wep_key_idx; - u8 def_wep_key_newidx; + s8 def_wep_key_idx; u16 tx_seq_no; @@ -293,6 +319,7 @@ struct ath10k_vif { bool use_cts_prot; int num_legacy_stations; int txpower; + struct wmi_wmm_params_all_arg wmm_params; }; struct ath10k_vif_iter { @@ -323,8 +350,10 @@ struct ath10k_debug { /* protected by conf_mutex */ u32 fw_dbglog_mask; + u32 fw_dbglog_level; u32 pktlog_filter; u32 reg_addr; + u32 nf_cal_period; u8 htt_max_amsdu; u8 htt_max_ampdu; @@ -369,7 +398,7 @@ enum ath10k_fw_features { /* wmi_mgmt_rx_hdr contains extra RSSI information */ ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0, - /* firmware from 10X branch */ + /* Firmware from 10X branch. Deprecated, don't use in new code. */ ATH10K_FW_FEATURE_WMI_10X = 1, /* firmware support tx frame management over WMI, otherwise it's HTT */ @@ -378,8 +407,9 @@ enum ath10k_fw_features { /* Firmware does not support P2P */ ATH10K_FW_FEATURE_NO_P2P = 3, - /* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature bit - * is required to be set as well. + /* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature + * bit is required to be set as well. Deprecated, don't use in new + * code. */ ATH10K_FW_FEATURE_WMI_10_2 = 4, @@ -401,6 +431,7 @@ enum ath10k_dev_flags { enum ath10k_cal_mode { ATH10K_CAL_MODE_FILE, ATH10K_CAL_MODE_OTP, + ATH10K_CAL_MODE_DT, }; static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode) @@ -410,6 +441,8 @@ static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode) return "file"; case ATH10K_CAL_MODE_OTP: return "otp"; + case ATH10K_CAL_MODE_DT: + return "dt"; } return "unknown"; @@ -444,6 +477,7 @@ struct ath10k { struct device *dev; u8 mac_addr[ETH_ALEN]; + enum ath10k_hw_rev hw_rev; u32 chip_id; u32 target_version; u8 fw_version_major; @@ -459,9 +493,6 @@ struct ath10k { DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT); - struct targetdef *targetdef; - struct hostdef *hostdef; - bool p2p; struct { @@ -471,6 +502,7 @@ struct ath10k { struct completion target_suspend; + const struct ath10k_hw_regs *regs; struct ath10k_bmi bmi; struct ath10k_wmi wmi; struct ath10k_htc htc; @@ -480,12 +512,15 @@ struct ath10k { u32 id; const char *name; u32 patch_load_addr; + int uart_pin; struct ath10k_hw_params_fw { const char *dir; const char *fw; const char *otp; const char *board; + size_t board_size; + size_t board_ext_size; } fw; } hw_params; @@ -548,7 +583,6 @@ struct ath10k { u8 cfg_tx_chainmask; u8 cfg_rx_chainmask; - struct wmi_pdev_set_wmm_params_arg wmm_params; struct completion install_key_done; struct completion vdev_setup_done; @@ -571,6 +605,7 @@ struct ath10k { int max_num_peers; int max_num_stations; + int max_num_vdevs; struct work_struct offchan_tx_work; struct sk_buff_head offchan_tx_queue; @@ -610,6 +645,7 @@ struct ath10k { /* protected by conf_mutex */ const struct firmware *utf; DECLARE_BITMAP(orig_fw_features, ATH10K_FW_FEATURE_COUNT); + enum ath10k_fw_wmi_op_version orig_wmi_op_version; /* protected by data_lock */ bool utf_monitor; @@ -622,12 +658,15 @@ struct ath10k { u32 fw_cold_reset_counter; } stats; + struct ath10k_thermal thermal; + /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); }; struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, enum ath10k_bus bus, + enum ath10k_hw_rev hw_rev, const struct ath10k_hif_ops *hif_ops); void ath10k_core_destroy(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index a716758f14b0..d2281e5c2ffe 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -23,6 +23,7 @@ #include "core.h" #include "debug.h" #include "hif.h" +#include "wmi-ops.h" /* ms */ #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000 @@ -123,7 +124,7 @@ EXPORT_SYMBOL(ath10k_info); void ath10k_print_driver_info(struct ath10k *ar) { - ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s max_sta %d\n", + ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n", ar->hw_params.name, ar->target_version, ar->chip_id, @@ -131,10 +132,7 @@ void ath10k_print_driver_info(struct ath10k *ar) ar->fw_api, ar->htt.target_version_major, ar->htt.target_version_minor, - ar->fw_version_major, - ar->fw_version_minor, - ar->fw_version_release, - ar->fw_version_build, + ar->wmi.op_version, ath10k_cal_mode_str(ar->cal_mode), ar->max_num_stations); ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n", @@ -373,7 +371,7 @@ static int ath10k_debug_fw_stats_request(struct ath10k *ar) ret = wait_for_completion_timeout(&ar->debug.fw_stats_complete, 1*HZ); - if (ret <= 0) + if (ret == 0) return -ETIMEDOUT; spin_lock_bh(&ar->data_lock); @@ -1320,10 +1318,10 @@ static ssize_t ath10k_read_fw_dbglog(struct file *file, { struct ath10k *ar = file->private_data; unsigned int len; - char buf[32]; + char buf[64]; - len = scnprintf(buf, sizeof(buf), "0x%08x\n", - ar->debug.fw_dbglog_mask); + len = scnprintf(buf, sizeof(buf), "0x%08x %u\n", + ar->debug.fw_dbglog_mask, ar->debug.fw_dbglog_level); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -1333,19 +1331,32 @@ static ssize_t ath10k_write_fw_dbglog(struct file *file, size_t count, loff_t *ppos) { struct ath10k *ar = file->private_data; - unsigned long mask; int ret; + char buf[64]; + unsigned int log_level, mask; - ret = kstrtoul_from_user(user_buf, count, 0, &mask); - if (ret) - return ret; + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + + /* make sure that buf is null terminated */ + buf[sizeof(buf) - 1] = 0; + + ret = sscanf(buf, "%x %u", &mask, &log_level); + + if (!ret) + return -EINVAL; + + if (ret == 1) + /* default if user did not specify */ + log_level = ATH10K_DBGLOG_LEVEL_WARN; mutex_lock(&ar->conf_mutex); ar->debug.fw_dbglog_mask = mask; + ar->debug.fw_dbglog_level = log_level; if (ar->state == ATH10K_STATE_ON) { - ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask); + ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask, + ar->debug.fw_dbglog_level); if (ret) { ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n", ret); @@ -1607,6 +1618,73 @@ static const struct file_operations fops_cal_data = { .llseek = default_llseek, }; +static ssize_t ath10k_read_nf_cal_period(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + unsigned int len; + char buf[32]; + + len = scnprintf(buf, sizeof(buf), "%d\n", + ar->debug.nf_cal_period); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath10k_write_nf_cal_period(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + unsigned long period; + int ret; + + ret = kstrtoul_from_user(user_buf, count, 0, &period); + if (ret) + return ret; + + if (period > WMI_PDEV_PARAM_CAL_PERIOD_MAX) + return -EINVAL; + + /* there's no way to switch back to the firmware default */ + if (period == 0) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + + ar->debug.nf_cal_period = period; + + if (ar->state != ATH10K_STATE_ON) { + /* firmware is not running, nothing else to do */ + ret = count; + goto exit; + } + + ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->cal_period, + ar->debug.nf_cal_period); + if (ret) { + ath10k_warn(ar, "cal period cfg failed from debugfs: %d\n", + ret); + goto exit; + } + + ret = count; + +exit: + mutex_unlock(&ar->conf_mutex); + + return ret; +} + +static const struct file_operations fops_nf_cal_period = { + .read = ath10k_read_nf_cal_period, + .write = ath10k_write_nf_cal_period, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath10k_debug_start(struct ath10k *ar) { int ret; @@ -1620,7 +1698,8 @@ int ath10k_debug_start(struct ath10k *ar) ret); if (ar->debug.fw_dbglog_mask) { - ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask); + ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask, + ATH10K_DBGLOG_LEVEL_WARN); if (ret) /* not serious */ ath10k_warn(ar, "failed to enable dbglog during start: %d", @@ -1642,6 +1721,16 @@ int ath10k_debug_start(struct ath10k *ar) ath10k_warn(ar, "failed to disable pktlog: %d\n", ret); } + if (ar->debug.nf_cal_period) { + ret = ath10k_wmi_pdev_set_param(ar, + ar->wmi.pdev_param->cal_period, + ar->debug.nf_cal_period); + if (ret) + /* not serious */ + ath10k_warn(ar, "cal period cfg failed from debug start: %d\n", + ret); + } + return ret; } @@ -1880,6 +1969,9 @@ int ath10k_debug_register(struct ath10k *ar) debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_cal_data); + debugfs_create_file("nf_cal_period", S_IRUSR | S_IWUSR, + ar->debug.debugfs_phy, ar, &fops_nf_cal_period); + if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) { debugfs_create_file("dfs_simulate_radar", S_IWUSR, ar->debug.debugfs_phy, ar, diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 1b87a5dbec53..a12b8323f9f1 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -48,6 +48,12 @@ enum ath10k_pktlog_filter { ATH10K_PKTLOG_ANY = 0x00000001f, }; +enum ath10k_dbg_aggr_mode { + ATH10K_DBG_AGGR_MODE_AUTO, + ATH10K_DBG_AGGR_MODE_MANUAL, + ATH10K_DBG_AGGR_MODE_MAX, +}; + extern unsigned int ath10k_debug_mask; __printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...); @@ -77,7 +83,6 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw, void ath10k_debug_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ethtool_stats *stats, u64 *data); - #else static inline int ath10k_debug_start(struct ath10k *ar) { @@ -129,6 +134,10 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) #define ath10k_debug_get_et_stats NULL #endif /* CONFIG_ATH10K_DEBUGFS */ +#ifdef CONFIG_MAC80211_DEBUGFS +void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct dentry *dir); +#endif /* CONFIG_MAC80211_DEBUGFS */ #ifdef CONFIG_ATH10K_DEBUG __printf(3, 4) void ath10k_dbg(struct ath10k *ar, diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c new file mode 100644 index 000000000000..95b5c49374e0 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "wmi-ops.h" +#include "debug.h" + +static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = arsta->arvif->ar; + char buf[32]; + int len = 0; + + mutex_lock(&ar->conf_mutex); + len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n", + (arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ? + "auto" : "manual"); + mutex_unlock(&ar->conf_mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = arsta->arvif->ar; + u32 aggr_mode; + int ret; + + if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode)) + return -EINVAL; + + if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + if ((ar->state != ATH10K_STATE_ON) || + (aggr_mode == arsta->aggr_mode)) { + ret = count; + goto out; + } + + ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr); + if (ret) { + ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret); + goto out; + } + + arsta->aggr_mode = aggr_mode; +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static const struct file_operations fops_aggr_mode = { + .read = ath10k_dbg_sta_read_aggr_mode, + .write = ath10k_dbg_sta_write_aggr_mode, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath10k_dbg_sta_write_addba(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = arsta->arvif->ar; + u32 tid, buf_size; + int ret; + char buf[64]; + + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + + /* make sure that buf is null terminated */ + buf[sizeof(buf) - 1] = '\0'; + + ret = sscanf(buf, "%u %u", &tid, &buf_size); + if (ret != 2) + return -EINVAL; + + /* Valid TID values are 0 through 15 */ + if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + if ((ar->state != ATH10K_STATE_ON) || + (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { + ret = count; + goto out; + } + + ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr, + tid, buf_size); + if (ret) { + ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n", + arsta->arvif->vdev_id, sta->addr, tid, buf_size); + } + + ret = count; +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static const struct file_operations fops_addba = { + .write = ath10k_dbg_sta_write_addba, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = arsta->arvif->ar; + u32 tid, status; + int ret; + char buf[64]; + + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + + /* make sure that buf is null terminated */ + buf[sizeof(buf) - 1] = '\0'; + + ret = sscanf(buf, "%u %u", &tid, &status); + if (ret != 2) + return -EINVAL; + + /* Valid TID values are 0 through 15 */ + if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + if ((ar->state != ATH10K_STATE_ON) || + (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { + ret = count; + goto out; + } + + ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr, + tid, status); + if (ret) { + ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n", + arsta->arvif->vdev_id, sta->addr, tid, status); + } + ret = count; +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static const struct file_operations fops_addba_resp = { + .write = ath10k_dbg_sta_write_addba_resp, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath10k_dbg_sta_write_delba(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = arsta->arvif->ar; + u32 tid, initiator, reason; + int ret; + char buf[64]; + + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + + /* make sure that buf is null terminated */ + buf[sizeof(buf) - 1] = '\0'; + + ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason); + if (ret != 3) + return -EINVAL; + + /* Valid TID values are 0 through 15 */ + if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + if ((ar->state != ATH10K_STATE_ON) || + (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { + ret = count; + goto out; + } + + ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr, + tid, initiator, reason); + if (ret) { + ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n", + arsta->arvif->vdev_id, sta->addr, tid, initiator, + reason); + } + ret = count; +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static const struct file_operations fops_delba = { + .write = ath10k_dbg_sta_write_delba, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct dentry *dir) +{ + debugfs_create_file("aggr_mode", S_IRUGO | S_IWUSR, dir, sta, + &fops_aggr_mode); + debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba); + debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp); + debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba); +} diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index f1946a6be442..2fd9e180272b 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -703,11 +703,9 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, /* wait for response */ status = wait_for_completion_timeout(&htc->ctl_resp, ATH10K_HTC_CONN_SVC_TIMEOUT_HZ); - if (status <= 0) { - if (status == 0) - status = -ETIMEDOUT; + if (status == 0) { ath10k_err(ar, "Service connect timeout: %d\n", status); - return status; + return -ETIMEDOUT; } /* we controlled the buffer creation, it's aligned */ diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 56cb4aceb383..4f59ab923e48 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -53,7 +53,6 @@ int ath10k_htt_init(struct ath10k *ar) struct ath10k_htt *htt = &ar->htt; htt->ar = ar; - htt->max_throughput_mbps = 800; /* * Prefetch enough data to satisfy target @@ -102,7 +101,7 @@ int ath10k_htt_setup(struct ath10k_htt *htt) status = wait_for_completion_timeout(&htt->target_version_received, HTT_TARGET_VERSION_TIMEOUT_HZ); - if (status <= 0) { + if (status == 0) { ath10k_warn(ar, "htt version request timed out\n"); return -ETIMEDOUT; } diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 1bd5545af903..874bf44ff7a2 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "htc.h" @@ -286,7 +287,19 @@ enum htt_t2h_msg_type { HTT_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc, HTT_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd, HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION = 0xe, + HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf, + HTT_T2H_MSG_TYPE_RX_PN_IND = 0x10, + HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11, + HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND = 0x12, + /* 0x13 reservd */ + HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE = 0x14, + + /* FIXME: Do not depend on this event id. Numbering of this event id is + * broken across different firmware revisions and HTT version fails to + * indicate this. + */ HTT_T2H_MSG_TYPE_TEST, + /* keep this last */ HTT_T2H_NUM_MSGS }; @@ -655,6 +668,53 @@ struct htt_rx_fragment_indication { #define HTT_RX_FRAG_IND_INFO1_FLUSH_SEQ_NUM_END_MASK 0x00000FC0 #define HTT_RX_FRAG_IND_INFO1_FLUSH_SEQ_NUM_END_LSB 6 +struct htt_rx_pn_ind { + __le16 peer_id; + u8 tid; + u8 seqno_start; + u8 seqno_end; + u8 pn_ie_count; + u8 reserved; + u8 pn_ies[0]; +} __packed; + +struct htt_rx_offload_msdu { + __le16 msdu_len; + __le16 peer_id; + u8 vdev_id; + u8 tid; + u8 fw_desc; + u8 payload[0]; +} __packed; + +struct htt_rx_offload_ind { + u8 reserved; + __le16 msdu_count; +} __packed; + +struct htt_rx_in_ord_msdu_desc { + __le32 msdu_paddr; + __le16 msdu_len; + u8 fw_desc; + u8 reserved; +} __packed; + +struct htt_rx_in_ord_ind { + u8 info; + __le16 peer_id; + u8 vdev_id; + u8 reserved; + __le16 msdu_count; + struct htt_rx_in_ord_msdu_desc msdu_descs[0]; +} __packed; + +#define HTT_RX_IN_ORD_IND_INFO_TID_MASK 0x0000001f +#define HTT_RX_IN_ORD_IND_INFO_TID_LSB 0 +#define HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK 0x00000020 +#define HTT_RX_IN_ORD_IND_INFO_OFFLOAD_LSB 5 +#define HTT_RX_IN_ORD_IND_INFO_FRAG_MASK 0x00000040 +#define HTT_RX_IN_ORD_IND_INFO_FRAG_LSB 6 + /* * target -> host test message definition * @@ -1150,6 +1210,9 @@ struct htt_resp { struct htt_rx_test rx_test; struct htt_pktlog_msg pktlog_msg; struct htt_stats_conf stats_conf; + struct htt_rx_pn_ind rx_pn_ind; + struct htt_rx_offload_ind rx_offload_ind; + struct htt_rx_in_ord_ind rx_in_ord_ind; }; } __packed; @@ -1182,7 +1245,6 @@ struct ath10k_htt { struct ath10k *ar; enum ath10k_htc_ep_id eid; - int max_throughput_mbps; u8 target_version_major; u8 target_version_minor; struct completion target_version_received; @@ -1198,6 +1260,20 @@ struct ath10k_htt { * filled. */ struct sk_buff **netbufs_ring; + + /* This is used only with firmware supporting IN_ORD_IND. + * + * With Full Rx Reorder the HTT Rx Ring is more of a temporary + * buffer ring from which buffer addresses are copied by the + * firmware to MAC Rx ring. Firmware then delivers IN_ORD_IND + * pointing to specific (re-ordered) buffers. + * + * FIXME: With kernel generic hashing functions there's a lot + * of hash collisions for sk_buffs. + */ + bool in_ord_rx; + DECLARE_HASHTABLE(skb_table, 4); + /* * Ring of buffer addresses - * This ring holds the "physical" device address of the @@ -1252,12 +1328,11 @@ struct ath10k_htt { unsigned int prefetch_len; - /* Protects access to %pending_tx, %used_msdu_ids */ + /* Protects access to pending_tx, num_pending_tx */ spinlock_t tx_lock; int max_num_pending_tx; int num_pending_tx; - struct sk_buff **pending_tx; - unsigned long *used_msdu_ids; /* bitmap */ + struct idr pending_tx; wait_queue_head_t empty_tx_wq; struct dma_pool *tx_pool; @@ -1271,6 +1346,7 @@ struct ath10k_htt { struct tasklet_struct txrx_compl_task; struct sk_buff_head tx_compl_q; struct sk_buff_head rx_compl_q; + struct sk_buff_head rx_in_ord_compl_q; /* rx_status template */ struct ieee80211_rx_status rx_status; @@ -1334,6 +1410,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt); void ath10k_htt_tx_free(struct ath10k_htt *htt); int ath10k_htt_rx_alloc(struct ath10k_htt *htt); +int ath10k_htt_rx_ring_refill(struct ath10k *ar); void ath10k_htt_rx_free(struct ath10k_htt *htt); void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb); @@ -1346,7 +1423,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, u8 max_subfrms_amsdu); void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt); -int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt); +int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb); void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id); int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *); int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *); diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 9c782a42665e..c1da44f65a4d 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -25,8 +25,8 @@ #include -#define HTT_RX_RING_SIZE 1024 -#define HTT_RX_RING_FILL_LEVEL 1000 +#define HTT_RX_RING_SIZE HTT_RX_RING_SIZE_MAX +#define HTT_RX_RING_FILL_LEVEL (((HTT_RX_RING_SIZE) / 2) - 1) /* when under memory pressure rx ring refill may fail and needs a retry */ #define HTT_RX_RING_REFILL_RETRY_MS 50 @@ -34,31 +34,70 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb); static void ath10k_htt_txrx_compl_task(unsigned long ptr); +static struct sk_buff * +ath10k_htt_rx_find_skb_paddr(struct ath10k *ar, u32 paddr) +{ + struct ath10k_skb_rxcb *rxcb; + + hash_for_each_possible(ar->htt.rx_ring.skb_table, rxcb, hlist, paddr) + if (rxcb->paddr == paddr) + return ATH10K_RXCB_SKB(rxcb); + + WARN_ON_ONCE(1); + return NULL; +} + static void ath10k_htt_rx_ring_free(struct ath10k_htt *htt) { struct sk_buff *skb; - struct ath10k_skb_cb *cb; + struct ath10k_skb_rxcb *rxcb; + struct hlist_node *n; int i; - for (i = 0; i < htt->rx_ring.fill_cnt; i++) { - skb = htt->rx_ring.netbufs_ring[i]; - cb = ATH10K_SKB_CB(skb); - dma_unmap_single(htt->ar->dev, cb->paddr, - skb->len + skb_tailroom(skb), - DMA_FROM_DEVICE); - dev_kfree_skb_any(skb); + if (htt->rx_ring.in_ord_rx) { + hash_for_each_safe(htt->rx_ring.skb_table, i, n, rxcb, hlist) { + skb = ATH10K_RXCB_SKB(rxcb); + dma_unmap_single(htt->ar->dev, rxcb->paddr, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + hash_del(&rxcb->hlist); + dev_kfree_skb_any(skb); + } + } else { + for (i = 0; i < htt->rx_ring.size; i++) { + skb = htt->rx_ring.netbufs_ring[i]; + if (!skb) + continue; + + rxcb = ATH10K_SKB_RXCB(skb); + dma_unmap_single(htt->ar->dev, rxcb->paddr, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + } } htt->rx_ring.fill_cnt = 0; + hash_init(htt->rx_ring.skb_table); + memset(htt->rx_ring.netbufs_ring, 0, + htt->rx_ring.size * sizeof(htt->rx_ring.netbufs_ring[0])); } static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num) { struct htt_rx_desc *rx_desc; + struct ath10k_skb_rxcb *rxcb; struct sk_buff *skb; dma_addr_t paddr; int ret = 0, idx; + /* The Full Rx Reorder firmware has no way of telling the host + * implicitly when it copied HTT Rx Ring buffers to MAC Rx Ring. + * To keep things simple make sure ring is always half empty. This + * guarantees there'll be no replenishment overruns possible. + */ + BUILD_BUG_ON(HTT_RX_RING_FILL_LEVEL >= HTT_RX_RING_SIZE / 2); + idx = __le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr); while (num > 0) { skb = dev_alloc_skb(HTT_RX_BUF_SIZE + HTT_RX_DESC_ALIGN); @@ -86,17 +125,29 @@ static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num) goto fail; } - ATH10K_SKB_CB(skb)->paddr = paddr; + rxcb = ATH10K_SKB_RXCB(skb); + rxcb->paddr = paddr; htt->rx_ring.netbufs_ring[idx] = skb; htt->rx_ring.paddrs_ring[idx] = __cpu_to_le32(paddr); htt->rx_ring.fill_cnt++; + if (htt->rx_ring.in_ord_rx) { + hash_add(htt->rx_ring.skb_table, + &ATH10K_SKB_RXCB(skb)->hlist, + (u32)paddr); + } + num--; idx++; idx &= htt->rx_ring.size_mask; } fail: + /* + * Make sure the rx buffer is updated before available buffer + * index to avoid any potential rx ring corruption. + */ + mb(); *htt->rx_ring.alloc_idx.vaddr = __cpu_to_le32(idx); return ret; } @@ -153,22 +204,20 @@ static void ath10k_htt_rx_ring_refill_retry(unsigned long arg) ath10k_htt_rx_msdu_buff_replenish(htt); } -static void ath10k_htt_rx_ring_clean_up(struct ath10k_htt *htt) +int ath10k_htt_rx_ring_refill(struct ath10k *ar) { - struct sk_buff *skb; - int i; + struct ath10k_htt *htt = &ar->htt; + int ret; - for (i = 0; i < htt->rx_ring.size; i++) { - skb = htt->rx_ring.netbufs_ring[i]; - if (!skb) - continue; + spin_lock_bh(&htt->rx_ring.lock); + ret = ath10k_htt_rx_ring_fill_n(htt, (htt->rx_ring.fill_level - + htt->rx_ring.fill_cnt)); + spin_unlock_bh(&htt->rx_ring.lock); - dma_unmap_single(htt->ar->dev, ATH10K_SKB_CB(skb)->paddr, - skb->len + skb_tailroom(skb), - DMA_FROM_DEVICE); - dev_kfree_skb_any(skb); - htt->rx_ring.netbufs_ring[i] = NULL; - } + if (ret) + ath10k_htt_rx_ring_free(htt); + + return ret; } void ath10k_htt_rx_free(struct ath10k_htt *htt) @@ -179,8 +228,9 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt) skb_queue_purge(&htt->tx_compl_q); skb_queue_purge(&htt->rx_compl_q); + skb_queue_purge(&htt->rx_in_ord_compl_q); - ath10k_htt_rx_ring_clean_up(htt); + ath10k_htt_rx_ring_free(htt); dma_free_coherent(htt->ar->dev, (htt->rx_ring.size * @@ -212,6 +262,7 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) idx = htt->rx_ring.sw_rd_idx.msdu_payld; msdu = htt->rx_ring.netbufs_ring[idx]; htt->rx_ring.netbufs_ring[idx] = NULL; + htt->rx_ring.paddrs_ring[idx] = 0; idx++; idx &= htt->rx_ring.size_mask; @@ -219,7 +270,7 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) htt->rx_ring.fill_cnt--; dma_unmap_single(htt->ar->dev, - ATH10K_SKB_CB(msdu)->paddr, + ATH10K_SKB_RXCB(msdu)->paddr, msdu->len + skb_tailroom(msdu), DMA_FROM_DEVICE); ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx netbuf pop: ", @@ -379,6 +430,82 @@ static void ath10k_htt_rx_replenish_task(unsigned long ptr) ath10k_htt_rx_msdu_buff_replenish(htt); } +static struct sk_buff *ath10k_htt_rx_pop_paddr(struct ath10k_htt *htt, + u32 paddr) +{ + struct ath10k *ar = htt->ar; + struct ath10k_skb_rxcb *rxcb; + struct sk_buff *msdu; + + lockdep_assert_held(&htt->rx_ring.lock); + + msdu = ath10k_htt_rx_find_skb_paddr(ar, paddr); + if (!msdu) + return NULL; + + rxcb = ATH10K_SKB_RXCB(msdu); + hash_del(&rxcb->hlist); + htt->rx_ring.fill_cnt--; + + dma_unmap_single(htt->ar->dev, rxcb->paddr, + msdu->len + skb_tailroom(msdu), + DMA_FROM_DEVICE); + ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx netbuf pop: ", + msdu->data, msdu->len + skb_tailroom(msdu)); + + return msdu; +} + +static int ath10k_htt_rx_pop_paddr_list(struct ath10k_htt *htt, + struct htt_rx_in_ord_ind *ev, + struct sk_buff_head *list) +{ + struct ath10k *ar = htt->ar; + struct htt_rx_in_ord_msdu_desc *msdu_desc = ev->msdu_descs; + struct htt_rx_desc *rxd; + struct sk_buff *msdu; + int msdu_count; + bool is_offload; + u32 paddr; + + lockdep_assert_held(&htt->rx_ring.lock); + + msdu_count = __le16_to_cpu(ev->msdu_count); + is_offload = !!(ev->info & HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK); + + while (msdu_count--) { + paddr = __le32_to_cpu(msdu_desc->msdu_paddr); + + msdu = ath10k_htt_rx_pop_paddr(htt, paddr); + if (!msdu) { + __skb_queue_purge(list); + return -ENOENT; + } + + __skb_queue_tail(list, msdu); + + if (!is_offload) { + rxd = (void *)msdu->data; + + trace_ath10k_htt_rx_desc(ar, rxd, sizeof(*rxd)); + + skb_put(msdu, sizeof(*rxd)); + skb_pull(msdu, sizeof(*rxd)); + skb_put(msdu, __le16_to_cpu(msdu_desc->msdu_len)); + + if (!(__le32_to_cpu(rxd->attention.flags) & + RX_ATTENTION_FLAGS_MSDU_DONE)) { + ath10k_warn(htt->ar, "tried to pop an incomplete frame, oops!\n"); + return -EIO; + } + } + + msdu_desc++; + } + + return 0; +} + int ath10k_htt_rx_alloc(struct ath10k_htt *htt) { struct ath10k *ar = htt->ar; @@ -424,7 +551,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) htt->rx_ring.alloc_idx.vaddr = vaddr; htt->rx_ring.alloc_idx.paddr = paddr; - htt->rx_ring.sw_rd_idx.msdu_payld = 0; + htt->rx_ring.sw_rd_idx.msdu_payld = htt->rx_ring.size_mask; *htt->rx_ring.alloc_idx.vaddr = 0; /* Initialize the Rx refill retry timer */ @@ -433,14 +560,15 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) spin_lock_init(&htt->rx_ring.lock); htt->rx_ring.fill_cnt = 0; - if (__ath10k_htt_rx_ring_fill_n(htt, htt->rx_ring.fill_level)) - goto err_fill_ring; + htt->rx_ring.sw_rd_idx.msdu_payld = 0; + hash_init(htt->rx_ring.skb_table); tasklet_init(&htt->rx_replenish_task, ath10k_htt_rx_replenish_task, (unsigned long)htt); skb_queue_head_init(&htt->tx_compl_q); skb_queue_head_init(&htt->rx_compl_q); + skb_queue_head_init(&htt->rx_in_ord_compl_q); tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task, (unsigned long)htt); @@ -449,12 +577,6 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) htt->rx_ring.size, htt->rx_ring.fill_level); return 0; -err_fill_ring: - ath10k_htt_rx_ring_free(htt); - dma_free_coherent(htt->ar->dev, - sizeof(*htt->rx_ring.alloc_idx.vaddr), - htt->rx_ring.alloc_idx.vaddr, - htt->rx_ring.alloc_idx.paddr); err_dma_idx: dma_free_coherent(htt->ar->dev, (htt->rx_ring.size * @@ -691,7 +813,7 @@ static void ath10k_htt_rx_h_mactime(struct ath10k *ar, * * FIXME: Can we get/compute 64bit TSF? */ - status->mactime = __le32_to_cpu(rxd->ppdu_end.tsf_timestamp); + status->mactime = __le32_to_cpu(rxd->ppdu_end.common.tsf_timestamp); status->flag |= RX_FLAG_MACTIME_END; } @@ -1578,6 +1700,194 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp) spin_unlock_bh(&ar->data_lock); } +static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list, + struct sk_buff_head *amsdu) +{ + struct sk_buff *msdu; + struct htt_rx_desc *rxd; + + if (skb_queue_empty(list)) + return -ENOBUFS; + + if (WARN_ON(!skb_queue_empty(amsdu))) + return -EINVAL; + + while ((msdu = __skb_dequeue(list))) { + __skb_queue_tail(amsdu, msdu); + + rxd = (void *)msdu->data - sizeof(*rxd); + if (rxd->msdu_end.info0 & + __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)) + break; + } + + msdu = skb_peek_tail(amsdu); + rxd = (void *)msdu->data - sizeof(*rxd); + if (!(rxd->msdu_end.info0 & + __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU))) { + skb_queue_splice_init(amsdu, list); + return -EAGAIN; + } + + return 0; +} + +static void ath10k_htt_rx_h_rx_offload_prot(struct ieee80211_rx_status *status, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (!ieee80211_has_protected(hdr->frame_control)) + return; + + /* Offloaded frames are already decrypted but firmware insists they are + * protected in the 802.11 header. Strip the flag. Otherwise mac80211 + * will drop the frame. + */ + + hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); + status->flag |= RX_FLAG_DECRYPTED | + RX_FLAG_IV_STRIPPED | + RX_FLAG_MMIC_STRIPPED; +} + +static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar, + struct sk_buff_head *list) +{ + struct ath10k_htt *htt = &ar->htt; + struct ieee80211_rx_status *status = &htt->rx_status; + struct htt_rx_offload_msdu *rx; + struct sk_buff *msdu; + size_t offset; + + while ((msdu = __skb_dequeue(list))) { + /* Offloaded frames don't have Rx descriptor. Instead they have + * a short meta information header. + */ + + rx = (void *)msdu->data; + + skb_put(msdu, sizeof(*rx)); + skb_pull(msdu, sizeof(*rx)); + + if (skb_tailroom(msdu) < __le16_to_cpu(rx->msdu_len)) { + ath10k_warn(ar, "dropping frame: offloaded rx msdu is too long!\n"); + dev_kfree_skb_any(msdu); + continue; + } + + skb_put(msdu, __le16_to_cpu(rx->msdu_len)); + + /* Offloaded rx header length isn't multiple of 2 nor 4 so the + * actual payload is unaligned. Align the frame. Otherwise + * mac80211 complains. This shouldn't reduce performance much + * because these offloaded frames are rare. + */ + offset = 4 - ((unsigned long)msdu->data & 3); + skb_put(msdu, offset); + memmove(msdu->data + offset, msdu->data, msdu->len); + skb_pull(msdu, offset); + + /* FIXME: The frame is NWifi. Re-construct QoS Control + * if possible later. + */ + + memset(status, 0, sizeof(*status)); + status->flag |= RX_FLAG_NO_SIGNAL_VAL; + + ath10k_htt_rx_h_rx_offload_prot(status, msdu); + ath10k_htt_rx_h_channel(ar, status); + ath10k_process_rx(ar, status, msdu); + } +} + +static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) +{ + struct ath10k_htt *htt = &ar->htt; + struct htt_resp *resp = (void *)skb->data; + struct ieee80211_rx_status *status = &htt->rx_status; + struct sk_buff_head list; + struct sk_buff_head amsdu; + u16 peer_id; + u16 msdu_count; + u8 vdev_id; + u8 tid; + bool offload; + bool frag; + int ret; + + lockdep_assert_held(&htt->rx_ring.lock); + + if (htt->rx_confused) + return; + + skb_pull(skb, sizeof(resp->hdr)); + skb_pull(skb, sizeof(resp->rx_in_ord_ind)); + + peer_id = __le16_to_cpu(resp->rx_in_ord_ind.peer_id); + msdu_count = __le16_to_cpu(resp->rx_in_ord_ind.msdu_count); + vdev_id = resp->rx_in_ord_ind.vdev_id; + tid = SM(resp->rx_in_ord_ind.info, HTT_RX_IN_ORD_IND_INFO_TID); + offload = !!(resp->rx_in_ord_ind.info & + HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK); + frag = !!(resp->rx_in_ord_ind.info & HTT_RX_IN_ORD_IND_INFO_FRAG_MASK); + + ath10k_dbg(ar, ATH10K_DBG_HTT, + "htt rx in ord vdev %i peer %i tid %i offload %i frag %i msdu count %i\n", + vdev_id, peer_id, tid, offload, frag, msdu_count); + + if (skb->len < msdu_count * sizeof(*resp->rx_in_ord_ind.msdu_descs)) { + ath10k_warn(ar, "dropping invalid in order rx indication\n"); + return; + } + + /* The event can deliver more than 1 A-MSDU. Each A-MSDU is later + * extracted and processed. + */ + __skb_queue_head_init(&list); + ret = ath10k_htt_rx_pop_paddr_list(htt, &resp->rx_in_ord_ind, &list); + if (ret < 0) { + ath10k_warn(ar, "failed to pop paddr list: %d\n", ret); + htt->rx_confused = true; + return; + } + + /* Offloaded frames are very different and need to be handled + * separately. + */ + if (offload) + ath10k_htt_rx_h_rx_offload(ar, &list); + + while (!skb_queue_empty(&list)) { + __skb_queue_head_init(&amsdu); + ret = ath10k_htt_rx_extract_amsdu(&list, &amsdu); + switch (ret) { + case 0: + /* Note: The in-order indication may report interleaved + * frames from different PPDUs meaning reported rx rate + * to mac80211 isn't accurate/reliable. It's still + * better to report something than nothing though. This + * should still give an idea about rx rate to the user. + */ + ath10k_htt_rx_h_ppdu(ar, &amsdu, status); + ath10k_htt_rx_h_filter(ar, &amsdu, status); + ath10k_htt_rx_h_mpdu(ar, &amsdu, status); + ath10k_htt_rx_h_deliver(ar, &amsdu, status); + break; + case -EAGAIN: + /* fall through */ + default: + /* Should not happen. */ + ath10k_warn(ar, "failed to extract amsdu: %d\n", ret); + htt->rx_confused = true; + __skb_queue_purge(&list); + return; + } + } + + tasklet_schedule(&htt->rx_replenish_task); +} + void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) { struct ath10k_htt *htt = &ar->htt; @@ -1700,6 +2010,20 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) */ break; } + case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: { + spin_lock_bh(&htt->rx_ring.lock); + __skb_queue_tail(&htt->rx_in_ord_compl_q, skb); + spin_unlock_bh(&htt->rx_ring.lock); + tasklet_schedule(&htt->txrx_compl_task); + return; + } + case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND: + /* FIXME: This WMI-TLV event is overlapping with 10.2 + * CHAN_CHANGE - both being 0xF. Neither is being used in + * practice so no immediate action is necessary. Nevertheless + * HTT may need an abstraction layer like WMI has one day. + */ + break; default: ath10k_warn(ar, "htt event (%d) not handled\n", resp->hdr.msg_type); @@ -1715,6 +2039,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) static void ath10k_htt_txrx_compl_task(unsigned long ptr) { struct ath10k_htt *htt = (struct ath10k_htt *)ptr; + struct ath10k *ar = htt->ar; struct htt_resp *resp; struct sk_buff *skb; @@ -1731,5 +2056,10 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr) ath10k_htt_rx_handler(htt, &resp->rx_ind); dev_kfree_skb_any(skb); } + + while ((skb = __skb_dequeue(&htt->rx_in_ord_compl_q))) { + ath10k_htt_rx_in_ord_ind(ar, skb); + dev_kfree_skb_any(skb); + } spin_unlock_bh(&htt->rx_ring.lock); } diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 4bc51d8a14a3..cbd2bc9e6202 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -56,21 +56,18 @@ exit: return ret; } -int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt) +int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb) { struct ath10k *ar = htt->ar; - int msdu_id; + int ret; lockdep_assert_held(&htt->tx_lock); - msdu_id = find_first_zero_bit(htt->used_msdu_ids, - htt->max_num_pending_tx); - if (msdu_id == htt->max_num_pending_tx) - return -ENOBUFS; + ret = idr_alloc(&htt->pending_tx, skb, 0, 0x10000, GFP_ATOMIC); - ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id); - __set_bit(msdu_id, htt->used_msdu_ids); - return msdu_id; + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", ret); + + return ret; } void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) @@ -79,79 +76,53 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) lockdep_assert_held(&htt->tx_lock); - if (!test_bit(msdu_id, htt->used_msdu_ids)) - ath10k_warn(ar, "trying to free unallocated msdu_id %d\n", - msdu_id); - ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id); - __clear_bit(msdu_id, htt->used_msdu_ids); + + idr_remove(&htt->pending_tx, msdu_id); } int ath10k_htt_tx_alloc(struct ath10k_htt *htt) { struct ath10k *ar = htt->ar; - spin_lock_init(&htt->tx_lock); - - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, htt->ar->fw_features)) - htt->max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; - else - htt->max_num_pending_tx = TARGET_NUM_MSDU_DESC; - ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", htt->max_num_pending_tx); - htt->pending_tx = kzalloc(sizeof(*htt->pending_tx) * - htt->max_num_pending_tx, GFP_KERNEL); - if (!htt->pending_tx) - return -ENOMEM; - - htt->used_msdu_ids = kzalloc(sizeof(unsigned long) * - BITS_TO_LONGS(htt->max_num_pending_tx), - GFP_KERNEL); - if (!htt->used_msdu_ids) { - kfree(htt->pending_tx); - return -ENOMEM; - } + spin_lock_init(&htt->tx_lock); + idr_init(&htt->pending_tx); htt->tx_pool = dma_pool_create("ath10k htt tx pool", htt->ar->dev, sizeof(struct ath10k_htt_txbuf), 4, 0); if (!htt->tx_pool) { - kfree(htt->used_msdu_ids); - kfree(htt->pending_tx); + idr_destroy(&htt->pending_tx); return -ENOMEM; } return 0; } -static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt) +static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) { - struct ath10k *ar = htt->ar; + struct ath10k *ar = ctx; + struct ath10k_htt *htt = &ar->htt; struct htt_tx_done tx_done = {0}; - int msdu_id; + + ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n", msdu_id); + + tx_done.discard = 1; + tx_done.msdu_id = msdu_id; spin_lock_bh(&htt->tx_lock); - for (msdu_id = 0; msdu_id < htt->max_num_pending_tx; msdu_id++) { - if (!test_bit(msdu_id, htt->used_msdu_ids)) - continue; - - ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n", - msdu_id); - - tx_done.discard = 1; - tx_done.msdu_id = msdu_id; - - ath10k_txrx_tx_unref(htt, &tx_done); - } + ath10k_txrx_tx_unref(htt, &tx_done); spin_unlock_bh(&htt->tx_lock); + + return 0; } void ath10k_htt_tx_free(struct ath10k_htt *htt) { - ath10k_htt_tx_free_pending(htt); - kfree(htt->pending_tx); - kfree(htt->used_msdu_ids); + idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar); + idr_destroy(&htt->pending_tx); dma_pool_destroy(htt->tx_pool); } @@ -383,13 +354,12 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) len += sizeof(cmd->mgmt_tx); spin_lock_bh(&htt->tx_lock); - res = ath10k_htt_tx_alloc_msdu_id(htt); + res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); if (res < 0) { spin_unlock_bh(&htt->tx_lock); goto err_tx_dec; } msdu_id = res; - htt->pending_tx[msdu_id] = msdu; spin_unlock_bh(&htt->tx_lock); txdesc = ath10k_htc_alloc_skb(ar, len); @@ -428,7 +398,6 @@ err_free_txdesc: dev_kfree_skb_any(txdesc); err_free_msdu_id: spin_lock_bh(&htt->tx_lock); - htt->pending_tx[msdu_id] = NULL; ath10k_htt_tx_free_msdu_id(htt, msdu_id); spin_unlock_bh(&htt->tx_lock); err_tx_dec: @@ -460,13 +429,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) goto err; spin_lock_bh(&htt->tx_lock); - res = ath10k_htt_tx_alloc_msdu_id(htt); + res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); if (res < 0) { spin_unlock_bh(&htt->tx_lock); goto err_tx_dec; } msdu_id = res; - htt->pending_tx[msdu_id] = msdu; spin_unlock_bh(&htt->tx_lock); prefetch_len = min(htt->prefetch_len, msdu->len); @@ -480,10 +448,18 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC, &paddr); - if (!skb_cb->htt.txbuf) + if (!skb_cb->htt.txbuf) { + res = -ENOMEM; goto err_free_msdu_id; + } skb_cb->htt.txbuf_paddr = paddr; + if ((ieee80211_is_action(hdr->frame_control) || + ieee80211_is_deauth(hdr->frame_control) || + ieee80211_is_disassoc(hdr->frame_control)) && + ieee80211_has_protected(hdr->frame_control)) + skb_put(msdu, IEEE80211_CCMP_MIC_LEN); + skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, DMA_TO_DEVICE); res = dma_mapping_error(dev, skb_cb->paddr); @@ -539,8 +515,10 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); - flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; - flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; + if (msdu->ip_summed == CHECKSUM_PARTIAL) { + flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; + flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; + } /* Prevent firmware from sending up tx inspection requests. There's * nothing ath10k can do with frames requested for inspection so force @@ -598,7 +576,6 @@ err_free_txbuf: skb_cb->htt.txbuf_paddr); err_free_msdu_id: spin_lock_bh(&htt->tx_lock); - htt->pending_tx[msdu_id] = NULL; ath10k_htt_tx_free_msdu_id(htt, msdu_id); spin_unlock_bh(&htt->tx_lock); err_tx_dec: diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c new file mode 100644 index 000000000000..839a8791fb9e --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "hw.h" + +const struct ath10k_hw_regs qca988x_regs = { + .rtc_state_cold_reset_mask = 0x00000400, + .rtc_soc_base_address = 0x00004000, + .rtc_wmac_base_address = 0x00005000, + .soc_core_base_address = 0x00009000, + .ce_wrapper_base_address = 0x00057000, + .ce0_base_address = 0x00057400, + .ce1_base_address = 0x00057800, + .ce2_base_address = 0x00057c00, + .ce3_base_address = 0x00058000, + .ce4_base_address = 0x00058400, + .ce5_base_address = 0x00058800, + .ce6_base_address = 0x00058c00, + .ce7_base_address = 0x00059000, + .soc_reset_control_si0_rst_mask = 0x00000001, + .soc_reset_control_ce_rst_mask = 0x00040000, + .soc_chip_id_address = 0x00ec, + .scratch_3_address = 0x0030, +}; + +const struct ath10k_hw_regs qca6174_regs = { + .rtc_state_cold_reset_mask = 0x00002000, + .rtc_soc_base_address = 0x00000800, + .rtc_wmac_base_address = 0x00001000, + .soc_core_base_address = 0x0003a000, + .ce_wrapper_base_address = 0x00034000, + .ce0_base_address = 0x00034400, + .ce1_base_address = 0x00034800, + .ce2_base_address = 0x00034c00, + .ce3_base_address = 0x00035000, + .ce4_base_address = 0x00035400, + .ce5_base_address = 0x00035800, + .ce6_base_address = 0x00035c00, + .ce7_base_address = 0x00036000, + .soc_reset_control_si0_rst_mask = 0x00000000, + .soc_reset_control_ce_rst_mask = 0x00000001, + .soc_chip_id_address = 0x000f0, + .scratch_3_address = 0x0028, +}; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index dfedfd0e0f34..460771fcfe9e 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -34,9 +34,50 @@ #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin" #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234 +/* QCA6174 target BMI version signatures */ +#define QCA6174_HW_1_0_VERSION 0x05000000 +#define QCA6174_HW_1_1_VERSION 0x05000001 +#define QCA6174_HW_1_3_VERSION 0x05000003 +#define QCA6174_HW_2_1_VERSION 0x05010000 +#define QCA6174_HW_3_0_VERSION 0x05020000 +#define QCA6174_HW_3_2_VERSION 0x05030000 + +enum qca6174_pci_rev { + QCA6174_PCI_REV_1_1 = 0x11, + QCA6174_PCI_REV_1_3 = 0x13, + QCA6174_PCI_REV_2_0 = 0x20, + QCA6174_PCI_REV_3_0 = 0x30, +}; + +enum qca6174_chip_id_rev { + QCA6174_HW_1_0_CHIP_ID_REV = 0, + QCA6174_HW_1_1_CHIP_ID_REV = 1, + QCA6174_HW_1_3_CHIP_ID_REV = 2, + QCA6174_HW_2_1_CHIP_ID_REV = 4, + QCA6174_HW_2_2_CHIP_ID_REV = 5, + QCA6174_HW_3_0_CHIP_ID_REV = 8, + QCA6174_HW_3_1_CHIP_ID_REV = 9, + QCA6174_HW_3_2_CHIP_ID_REV = 10, +}; + +#define QCA6174_HW_2_1_FW_DIR "ath10k/QCA6174/hw2.1" +#define QCA6174_HW_2_1_FW_FILE "firmware.bin" +#define QCA6174_HW_2_1_OTP_FILE "otp.bin" +#define QCA6174_HW_2_1_BOARD_DATA_FILE "board.bin" +#define QCA6174_HW_2_1_PATCH_LOAD_ADDR 0x1234 + +#define QCA6174_HW_3_0_FW_DIR "ath10k/QCA6174/hw3.0" +#define QCA6174_HW_3_0_FW_FILE "firmware.bin" +#define QCA6174_HW_3_0_OTP_FILE "otp.bin" +#define QCA6174_HW_3_0_BOARD_DATA_FILE "board.bin" +#define QCA6174_HW_3_0_PATCH_LOAD_ADDR 0x1234 + #define ATH10K_FW_API2_FILE "firmware-2.bin" #define ATH10K_FW_API3_FILE "firmware-3.bin" +/* added support for ATH10K_FW_IE_WMI_OP_VERSION */ +#define ATH10K_FW_API4_FILE "firmware-4.bin" + #define ATH10K_FW_UTF_FILE "utf.bin" /* includes also the null byte */ @@ -58,8 +99,57 @@ enum ath10k_fw_ie_type { ATH10K_FW_IE_FEATURES = 2, ATH10K_FW_IE_FW_IMAGE = 3, ATH10K_FW_IE_OTP_IMAGE = 4, + + /* WMI "operations" interface version, 32 bit value. Supported from + * FW API 4 and above. + */ + ATH10K_FW_IE_WMI_OP_VERSION = 5, }; +enum ath10k_fw_wmi_op_version { + ATH10K_FW_WMI_OP_VERSION_UNSET = 0, + + ATH10K_FW_WMI_OP_VERSION_MAIN = 1, + ATH10K_FW_WMI_OP_VERSION_10_1 = 2, + ATH10K_FW_WMI_OP_VERSION_10_2 = 3, + ATH10K_FW_WMI_OP_VERSION_TLV = 4, + ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5, + + /* keep last */ + ATH10K_FW_WMI_OP_VERSION_MAX, +}; + +enum ath10k_hw_rev { + ATH10K_HW_QCA988X, + ATH10K_HW_QCA6174, +}; + +struct ath10k_hw_regs { + u32 rtc_state_cold_reset_mask; + u32 rtc_soc_base_address; + u32 rtc_wmac_base_address; + u32 soc_core_base_address; + u32 ce_wrapper_base_address; + u32 ce0_base_address; + u32 ce1_base_address; + u32 ce2_base_address; + u32 ce3_base_address; + u32 ce4_base_address; + u32 ce5_base_address; + u32 ce6_base_address; + u32 ce7_base_address; + u32 soc_reset_control_si0_rst_mask; + u32 soc_reset_control_ce_rst_mask; + u32 soc_chip_id_address; + u32 scratch_3_address; +}; + +extern const struct ath10k_hw_regs qca988x_regs; +extern const struct ath10k_hw_regs qca6174_regs; + +#define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X) +#define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174) + /* Known pecularities: * - current FW doesn't support raw rx mode (last tested v599) * - current FW dumps upon raw tx mode (last tested v599) @@ -162,6 +252,18 @@ struct ath10k_pktlog_hdr { #define TARGET_10X_NUM_MSDU_DESC (1024 + 400) #define TARGET_10X_MAX_FRAG_ENTRIES 0 +/* 10.2 parameters */ +#define TARGET_10_2_DMA_BURST_SIZE 1 + +/* Target specific defines for WMI-TLV firmware */ +#define TARGET_TLV_NUM_VDEVS 3 +#define TARGET_TLV_NUM_STATIONS 32 +#define TARGET_TLV_NUM_PEERS ((TARGET_TLV_NUM_STATIONS) + \ + (TARGET_TLV_NUM_VDEVS) + \ + 2) +#define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2) +#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32) + /* Number of Copy Engines supported */ #define CE_COUNT 8 @@ -192,7 +294,7 @@ struct ath10k_pktlog_hdr { /* as of IP3.7.1 */ #define RTC_STATE_V_ON 3 -#define RTC_STATE_COLD_RESET_MASK 0x00000400 +#define RTC_STATE_COLD_RESET_MASK ar->regs->rtc_state_cold_reset_mask #define RTC_STATE_V_LSB 0 #define RTC_STATE_V_MASK 0x00000007 #define RTC_STATE_ADDRESS 0x0000 @@ -201,12 +303,12 @@ struct ath10k_pktlog_hdr { #define PCIE_SOC_WAKE_RESET 0x00000000 #define SOC_GLOBAL_RESET_ADDRESS 0x0008 -#define RTC_SOC_BASE_ADDRESS 0x00004000 -#define RTC_WMAC_BASE_ADDRESS 0x00005000 +#define RTC_SOC_BASE_ADDRESS ar->regs->rtc_soc_base_address +#define RTC_WMAC_BASE_ADDRESS ar->regs->rtc_wmac_base_address #define MAC_COEX_BASE_ADDRESS 0x00006000 #define BT_COEX_BASE_ADDRESS 0x00007000 #define SOC_PCIE_BASE_ADDRESS 0x00008000 -#define SOC_CORE_BASE_ADDRESS 0x00009000 +#define SOC_CORE_BASE_ADDRESS ar->regs->soc_core_base_address #define WLAN_UART_BASE_ADDRESS 0x0000c000 #define WLAN_SI_BASE_ADDRESS 0x00010000 #define WLAN_GPIO_BASE_ADDRESS 0x00014000 @@ -215,23 +317,23 @@ struct ath10k_pktlog_hdr { #define EFUSE_BASE_ADDRESS 0x00030000 #define FPGA_REG_BASE_ADDRESS 0x00039000 #define WLAN_UART2_BASE_ADDRESS 0x00054c00 -#define CE_WRAPPER_BASE_ADDRESS 0x00057000 -#define CE0_BASE_ADDRESS 0x00057400 -#define CE1_BASE_ADDRESS 0x00057800 -#define CE2_BASE_ADDRESS 0x00057c00 -#define CE3_BASE_ADDRESS 0x00058000 -#define CE4_BASE_ADDRESS 0x00058400 -#define CE5_BASE_ADDRESS 0x00058800 -#define CE6_BASE_ADDRESS 0x00058c00 -#define CE7_BASE_ADDRESS 0x00059000 +#define CE_WRAPPER_BASE_ADDRESS ar->regs->ce_wrapper_base_address +#define CE0_BASE_ADDRESS ar->regs->ce0_base_address +#define CE1_BASE_ADDRESS ar->regs->ce1_base_address +#define CE2_BASE_ADDRESS ar->regs->ce2_base_address +#define CE3_BASE_ADDRESS ar->regs->ce3_base_address +#define CE4_BASE_ADDRESS ar->regs->ce4_base_address +#define CE5_BASE_ADDRESS ar->regs->ce5_base_address +#define CE6_BASE_ADDRESS ar->regs->ce6_base_address +#define CE7_BASE_ADDRESS ar->regs->ce7_base_address #define DBI_BASE_ADDRESS 0x00060000 #define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000 #define PCIE_LOCAL_BASE_ADDRESS 0x00080000 #define SOC_RESET_CONTROL_ADDRESS 0x00000000 #define SOC_RESET_CONTROL_OFFSET 0x00000000 -#define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001 -#define SOC_RESET_CONTROL_CE_RST_MASK 0x00040000 +#define SOC_RESET_CONTROL_SI0_RST_MASK ar->regs->soc_reset_control_si0_rst_mask +#define SOC_RESET_CONTROL_CE_RST_MASK ar->regs->soc_reset_control_ce_rst_mask #define SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 #define SOC_CPU_CLOCK_OFFSET 0x00000020 #define SOC_CPU_CLOCK_STANDARD_LSB 0 @@ -245,7 +347,7 @@ struct ath10k_pktlog_hdr { #define SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050 #define SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004 -#define SOC_CHIP_ID_ADDRESS 0x000000ec +#define SOC_CHIP_ID_ADDRESS ar->regs->soc_chip_id_address #define SOC_CHIP_ID_REV_LSB 8 #define SOC_CHIP_ID_REV_MASK 0x00000f00 @@ -301,7 +403,7 @@ struct ath10k_pktlog_hdr { #define PCIE_INTR_ENABLE_ADDRESS 0x0008 #define PCIE_INTR_CAUSE_ADDRESS 0x000c #define PCIE_INTR_CLR_ADDRESS 0x0014 -#define SCRATCH_3_ADDRESS 0x0030 +#define SCRATCH_3_ADDRESS ar->regs->scratch_3_address #define CPU_INTR_ADDRESS 0x0010 /* Firmware indications to the Host via SCRATCH_3 register. */ diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c4005670cba2..d6d2f0f00caa 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -27,6 +27,8 @@ #include "htt.h" #include "txrx.h" #include "testmode.h" +#include "wmi.h" +#include "wmi-ops.h" /**********/ /* Crypto */ @@ -35,7 +37,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif, struct ieee80211_key_conf *key, enum set_key_cmd cmd, - const u8 *macaddr) + const u8 *macaddr, bool def_idx) { struct ath10k *ar = arvif->ar; struct wmi_vdev_install_key_arg arg = { @@ -56,10 +58,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif, switch (key->cipher) { case WLAN_CIPHER_SUITE_CCMP: arg.key_cipher = WMI_CIPHER_AES_CCM; - if (arvif->vdev_type == WMI_VDEV_TYPE_AP) - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; - else - key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; break; case WLAN_CIPHER_SUITE_TKIP: arg.key_cipher = WMI_CIPHER_TKIP; @@ -73,7 +72,13 @@ static int ath10k_send_key(struct ath10k_vif *arvif, * Otherwise pairwise key must be set */ if (memcmp(macaddr, arvif->vif->addr, ETH_ALEN)) arg.key_flags = WMI_KEY_PAIRWISE; + + if (def_idx) + arg.key_flags |= WMI_KEY_TX_USAGE; break; + case WLAN_CIPHER_SUITE_AES_CMAC: + /* this one needs to be done in software */ + return 1; default: ath10k_warn(ar, "cipher %d is not supported\n", key->cipher); return -EOPNOTSUPP; @@ -90,7 +95,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif, static int ath10k_install_key(struct ath10k_vif *arvif, struct ieee80211_key_conf *key, enum set_key_cmd cmd, - const u8 *macaddr) + const u8 *macaddr, bool def_idx) { struct ath10k *ar = arvif->ar; int ret; @@ -99,7 +104,7 @@ static int ath10k_install_key(struct ath10k_vif *arvif, reinit_completion(&ar->install_key_done); - ret = ath10k_send_key(arvif, key, cmd, macaddr); + ret = ath10k_send_key(arvif, key, cmd, macaddr, def_idx); if (ret) return ret; @@ -117,6 +122,7 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, struct ath10k_peer *peer; int ret; int i; + bool def_idx; lockdep_assert_held(&ar->conf_mutex); @@ -130,9 +136,14 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, for (i = 0; i < ARRAY_SIZE(arvif->wep_keys); i++) { if (arvif->wep_keys[i] == NULL) continue; + /* set TX_USAGE flag for default key id */ + if (arvif->def_wep_key_idx == i) + def_idx = true; + else + def_idx = false; ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY, - addr); + addr, def_idx); if (ret) return ret; @@ -166,8 +177,9 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif, if (peer->keys[i] == NULL) continue; + /* key flags are not required to delete the key */ ret = ath10k_install_key(arvif, peer->keys[i], - DISABLE_KEY, addr); + DISABLE_KEY, addr, false); if (ret && first_errno == 0) first_errno = ret; @@ -241,8 +253,8 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, if (i == ARRAY_SIZE(peer->keys)) break; - - ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr); + /* key flags are not required to delete the key */ + ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, false); if (ret && first_errno == 0) first_errno = ret; @@ -267,7 +279,10 @@ chan_to_phymode(const struct cfg80211_chan_def *chandef) case IEEE80211_BAND_2GHZ: switch (chandef->width) { case NL80211_CHAN_WIDTH_20_NOHT: - phymode = MODE_11G; + if (chandef->chan->flags & IEEE80211_CHAN_NO_OFDM) + phymode = MODE_11B; + else + phymode = MODE_11G; break; case NL80211_CHAN_WIDTH_20: phymode = MODE_11NG_HT20; @@ -519,10 +534,14 @@ void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif) dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr, arvif->beacon->len, DMA_TO_DEVICE); + if (WARN_ON(arvif->beacon_state != ATH10K_BEACON_SCHEDULED && + arvif->beacon_state != ATH10K_BEACON_SENT)) + return; + dev_kfree_skb_any(arvif->beacon); arvif->beacon = NULL; - arvif->beacon_sent = false; + arvif->beacon_state = ATH10K_BEACON_SCHEDULED; } static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif) @@ -962,6 +981,143 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) return ret; } +static int ath10k_mac_setup_bcn_p2p_ie(struct ath10k_vif *arvif, + struct sk_buff *bcn) +{ + struct ath10k *ar = arvif->ar; + struct ieee80211_mgmt *mgmt; + const u8 *p2p_ie; + int ret; + + if (arvif->vdev_type != WMI_VDEV_TYPE_AP) + return 0; + + if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO) + return 0; + + mgmt = (void *)bcn->data; + p2p_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, + mgmt->u.beacon.variable, + bcn->len - (mgmt->u.beacon.variable - + bcn->data)); + if (!p2p_ie) + return -ENOENT; + + ret = ath10k_wmi_p2p_go_bcn_ie(ar, arvif->vdev_id, p2p_ie); + if (ret) { + ath10k_warn(ar, "failed to submit p2p go bcn ie for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return 0; +} + +static int ath10k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, + u8 oui_type, size_t ie_offset) +{ + size_t len; + const u8 *next; + const u8 *end; + u8 *ie; + + if (WARN_ON(skb->len < ie_offset)) + return -EINVAL; + + ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, + skb->data + ie_offset, + skb->len - ie_offset); + if (!ie) + return -ENOENT; + + len = ie[1] + 2; + end = skb->data + skb->len; + next = ie + len; + + if (WARN_ON(next > end)) + return -EINVAL; + + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); + + return 0; +} + +static int ath10k_mac_setup_bcn_tmpl(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + struct ieee80211_hw *hw = ar->hw; + struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_mutable_offsets offs = {}; + struct sk_buff *bcn; + int ret; + + if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) + return 0; + + bcn = ieee80211_beacon_get_template(hw, vif, &offs); + if (!bcn) { + ath10k_warn(ar, "failed to get beacon template from mac80211\n"); + return -EPERM; + } + + ret = ath10k_mac_setup_bcn_p2p_ie(arvif, bcn); + if (ret) { + ath10k_warn(ar, "failed to setup p2p go bcn ie: %d\n", ret); + kfree_skb(bcn); + return ret; + } + + /* P2P IE is inserted by firmware automatically (as configured above) + * so remove it from the base beacon template to avoid duplicate P2P + * IEs in beacon frames. + */ + ath10k_mac_remove_vendor_ie(bcn, WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, + offsetof(struct ieee80211_mgmt, + u.beacon.variable)); + + ret = ath10k_wmi_bcn_tmpl(ar, arvif->vdev_id, offs.tim_offset, bcn, 0, + 0, NULL, 0); + kfree_skb(bcn); + + if (ret) { + ath10k_warn(ar, "failed to submit beacon template command: %d\n", + ret); + return ret; + } + + return 0; +} + +static int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + struct ieee80211_hw *hw = ar->hw; + struct ieee80211_vif *vif = arvif->vif; + struct sk_buff *prb; + int ret; + + if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) + return 0; + + prb = ieee80211_proberesp_get(hw, vif); + if (!prb) { + ath10k_warn(ar, "failed to get probe resp template from mac80211\n"); + return -EPERM; + } + + ret = ath10k_wmi_prb_tmpl(ar, arvif->vdev_id, prb); + kfree_skb(prb); + + if (ret) { + ath10k_warn(ar, "failed to submit probe resp template command: %d\n", + ret); + return ret; + } + + return 0; +} + static void ath10k_control_beaconing(struct ath10k_vif *arvif, struct ieee80211_bss_conf *info) { @@ -1046,28 +1202,85 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, arvif->vdev_id, ret); } -/* - * Review this when mac80211 gains per-interface powersave support. - */ +static int ath10k_mac_vif_recalc_ps_wake_threshold(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + u32 param; + u32 value; + int ret; + + lockdep_assert_held(&arvif->ar->conf_mutex); + + if (arvif->u.sta.uapsd) + value = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER; + else + value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS; + + param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD; + ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); + if (ret) { + ath10k_warn(ar, "failed to submit ps wake threshold %u on vdev %i: %d\n", + value, arvif->vdev_id, ret); + return ret; + } + + return 0; +} + +static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + u32 param; + u32 value; + int ret; + + lockdep_assert_held(&arvif->ar->conf_mutex); + + if (arvif->u.sta.uapsd) + value = WMI_STA_PS_PSPOLL_COUNT_UAPSD; + else + value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX; + + param = WMI_STA_PS_PARAM_PSPOLL_COUNT; + ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, + param, value); + if (ret) { + ath10k_warn(ar, "failed to submit ps poll count %u on vdev %i: %d\n", + value, arvif->vdev_id, ret); + return ret; + } + + return 0; +} + static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) { struct ath10k *ar = arvif->ar; + struct ieee80211_vif *vif = arvif->vif; struct ieee80211_conf *conf = &ar->hw->conf; enum wmi_sta_powersave_param param; enum wmi_sta_ps_mode psmode; int ret; + int ps_timeout; lockdep_assert_held(&arvif->ar->conf_mutex); if (arvif->vif->type != NL80211_IFTYPE_STATION) return 0; - if (conf->flags & IEEE80211_CONF_PS) { + if (vif->bss_conf.ps) { psmode = WMI_STA_PS_MODE_ENABLED; param = WMI_STA_PS_PARAM_INACTIVITY_TIME; + ps_timeout = conf->dynamic_ps_timeout; + if (ps_timeout == 0) { + /* Firmware doesn't like 0 */ + ps_timeout = ieee80211_tu_to_usec( + vif->bss_conf.beacon_int) / 1000; + } + ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, - conf->dynamic_ps_timeout); + ps_timeout); if (ret) { ath10k_warn(ar, "failed to set inactivity time for vdev %d: %i\n", arvif->vdev_id, ret); @@ -1090,6 +1303,38 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) return 0; } +static int ath10k_mac_vif_disable_keepalive(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + struct wmi_sta_keepalive_arg arg = {}; + int ret; + + lockdep_assert_held(&arvif->ar->conf_mutex); + + if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + return 0; + + if (!test_bit(WMI_SERVICE_STA_KEEP_ALIVE, ar->wmi.svc_map)) + return 0; + + /* Some firmware revisions have a bug and ignore the `enabled` field. + * Instead use the interval to disable the keepalive. + */ + arg.vdev_id = arvif->vdev_id; + arg.enabled = 1; + arg.method = WMI_STA_KEEPALIVE_METHOD_NULL_FRAME; + arg.interval = WMI_STA_KEEPALIVE_INTERVAL_DISABLE; + + ret = ath10k_wmi_sta_keepalive(ar, &arg); + if (ret) { + ath10k_warn(ar, "failed to submit keepalive on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return 0; +} + /**********************/ /* Station management */ /**********************/ @@ -1358,6 +1603,10 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, return; arg->peer_flags |= WMI_PEER_VHT; + + if (ar->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ) + arg->peer_flags |= WMI_PEER_VHT_2G; + arg->peer_vht_caps = vht_cap->cap; ampdu_factor = (vht_cap->cap & @@ -1409,9 +1658,22 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, if (vif->bss_conf.qos) arg->peer_flags |= WMI_PEER_QOS; break; + case WMI_VDEV_TYPE_IBSS: + if (sta->wme) + arg->peer_flags |= WMI_PEER_QOS; + break; default: break; } + + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM qos %d\n", + sta->addr, !!(arg->peer_flags & WMI_PEER_QOS)); +} + +static bool ath10k_mac_sta_has_11g_rates(struct ieee80211_sta *sta) +{ + /* First 4 rates in ath10k_rates are CCK (11b) rates. */ + return sta->supp_rates[IEEE80211_BAND_2GHZ] >> 4; } static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, @@ -1423,13 +1685,20 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, switch (ar->hw->conf.chandef.chan->band) { case IEEE80211_BAND_2GHZ: - if (sta->ht_cap.ht_supported) { + if (sta->vht_cap.vht_supported) { + if (sta->bandwidth == IEEE80211_STA_RX_BW_40) + phymode = MODE_11AC_VHT40; + else + phymode = MODE_11AC_VHT20; + } else if (sta->ht_cap.ht_supported) { if (sta->bandwidth == IEEE80211_STA_RX_BW_40) phymode = MODE_11NG_HT40; else phymode = MODE_11NG_HT20; - } else { + } else if (ath10k_mac_sta_has_11g_rates(sta)) { phymode = MODE_11G; + } else { + phymode = MODE_11B; } break; @@ -1603,7 +1872,8 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, ath10k_warn(ar, "faield to down vdev %i: %d\n", arvif->vdev_id, ret); - arvif->def_wep_key_idx = 0; + arvif->def_wep_key_idx = -1; + arvif->is_up = false; } @@ -1662,11 +1932,14 @@ static int ath10k_station_assoc(struct ath10k *ar, } } - ret = ath10k_install_peer_wep_keys(arvif, sta->addr); - if (ret) { - ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n", - arvif->vdev_id, ret); - return ret; + /* Plumb cached keys only for static WEP */ + if (arvif->def_wep_key_idx != -1) { + ret = ath10k_install_peer_wep_keys(arvif, sta->addr); + if (ret) { + ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } } } @@ -1931,75 +2204,13 @@ static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb) * used only for CQM purposes (e.g. hostapd station keepalive ping) so * it is safe to downgrade to NullFunc. */ + hdr = (void *)skb->data; if (ieee80211_is_qos_nullfunc(hdr->frame_control)) { hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA); cb->htt.tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST; } } -static void ath10k_tx_wep_key_work(struct work_struct *work) -{ - struct ath10k_vif *arvif = container_of(work, struct ath10k_vif, - wep_key_work); - struct ath10k *ar = arvif->ar; - int ret, keyidx = arvif->def_wep_key_newidx; - - mutex_lock(&arvif->ar->conf_mutex); - - if (arvif->ar->state != ATH10K_STATE_ON) - goto unlock; - - if (arvif->def_wep_key_idx == keyidx) - goto unlock; - - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n", - arvif->vdev_id, keyidx); - - ret = ath10k_wmi_vdev_set_param(arvif->ar, - arvif->vdev_id, - arvif->ar->wmi.vdev_param->def_keyid, - keyidx); - if (ret) { - ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n", - arvif->vdev_id, - ret); - goto unlock; - } - - arvif->def_wep_key_idx = keyidx; - -unlock: - mutex_unlock(&arvif->ar->conf_mutex); -} - -static void ath10k_tx_h_update_wep_key(struct ieee80211_vif *vif, - struct ieee80211_key_conf *key, - struct sk_buff *skb) -{ - struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); - struct ath10k *ar = arvif->ar; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - - if (!ieee80211_has_protected(hdr->frame_control)) - return; - - if (!key) - return; - - if (key->cipher != WLAN_CIPHER_SUITE_WEP40 && - key->cipher != WLAN_CIPHER_SUITE_WEP104) - return; - - if (key->keyidx == arvif->def_wep_key_idx) - return; - - /* FIXME: Most likely a few frames will be TXed with an old key. Simply - * queueing frames until key index is updated is not an option because - * sk_buff may need more processing to be done, e.g. offchannel */ - arvif->def_wep_key_newidx = key->keyidx; - ieee80211_queue_work(ar->hw, &arvif->wep_key_work); -} - static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct ieee80211_vif *vif, struct sk_buff *skb) @@ -2151,7 +2362,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) ret = wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ); - if (ret <= 0) + if (ret == 0) ath10k_warn(ar, "timed out waiting for offchannel skb %p\n", skb); @@ -2213,6 +2424,7 @@ void __ath10k_scan_finish(struct ath10k *ar) case ATH10K_SCAN_RUNNING: if (ar->scan.is_roc) ieee80211_remain_on_channel_expired(ar->hw); + /* fall through */ case ATH10K_SCAN_ABORTING: if (!ar->scan.is_roc) ieee80211_scan_completed(ar->hw, @@ -2359,7 +2571,6 @@ static void ath10k_tx(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; - struct ieee80211_key_conf *key = info->control.hw_key; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; /* We should disable CCK RATE due to P2P */ @@ -2373,7 +2584,6 @@ static void ath10k_tx(struct ieee80211_hw *hw, /* it makes no sense to process injected frames like that */ if (vif && vif->type != NL80211_IFTYPE_MONITOR) { ath10k_tx_h_nwifi(hw, skb); - ath10k_tx_h_update_wep_key(vif, key, skb); ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb); ath10k_tx_h_seq_no(vif, skb); } @@ -2871,6 +3081,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, int bit; u32 vdev_param; + vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; + mutex_lock(&ar->conf_mutex); memset(arvif, 0, sizeof(*arvif)); @@ -2878,7 +3090,6 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, arvif->ar = ar; arvif->vif = vif; - INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work); INIT_LIST_HEAD(&arvif->list); if (ar->free_vdev_map == 0) { @@ -2894,10 +3105,11 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, arvif->vdev_id = bit; arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; - if (ar->p2p) - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; - switch (vif->type) { + case NL80211_IFTYPE_P2P_DEVICE: + arvif->vdev_type = WMI_VDEV_TYPE_STA; + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; + break; case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: arvif->vdev_type = WMI_VDEV_TYPE_STA; @@ -2966,15 +3178,18 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ar->free_vdev_map &= ~(1LL << arvif->vdev_id); list_add(&arvif->list, &ar->arvifs); - vdev_param = ar->wmi.vdev_param->def_keyid; - ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param, - arvif->def_wep_key_idx); + /* It makes no sense to have firmware do keepalives. mac80211 already + * takes care of this with idle connection polling. + */ + ret = ath10k_mac_vif_disable_keepalive(arvif); if (ret) { - ath10k_warn(ar, "failed to set vdev %i default key id: %d\n", + ath10k_warn(ar, "failed to disable keepalive on vdev %i: %d\n", arvif->vdev_id, ret); goto err_vdev_delete; } + arvif->def_wep_key_idx = -1; + vdev_param = ar->wmi.vdev_param->tx_encap_type; ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, ATH10K_HW_TXRX_NATIVE_WIFI); @@ -3026,22 +3241,16 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, goto err_peer_delete; } - param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD; - value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS; - ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, - param, value); + ret = ath10k_mac_vif_recalc_ps_wake_threshold(arvif); if (ret) { - ath10k_warn(ar, "failed to set vdev %i TX wake thresh: %d\n", + ath10k_warn(ar, "failed to recalc ps wake threshold on vdev %i: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } - param = WMI_STA_PS_PARAM_PSPOLL_COUNT; - value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX; - ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, - param, value); + ret = ath10k_mac_vif_recalc_ps_poll_count(arvif); if (ret) { - ath10k_warn(ar, "failed to set vdev %i PSPOLL count: %d\n", + ath10k_warn(ar, "failed to recalc ps poll count on vdev %i: %d\n", arvif->vdev_id, ret); goto err_peer_delete; } @@ -3099,8 +3308,6 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); int ret; - cancel_work_sync(&arvif->wep_key_work); - mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); @@ -3211,9 +3418,21 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, if (ret) ath10k_warn(ar, "failed to set beacon mode for vdev %d: %i\n", arvif->vdev_id, ret); + + ret = ath10k_mac_setup_bcn_tmpl(arvif); + if (ret) + ath10k_warn(ar, "failed to update beacon template: %d\n", + ret); } - if (changed & BSS_CHANGED_BEACON_INFO) { + if (changed & BSS_CHANGED_AP_PROBE_RESP) { + ret = ath10k_mac_setup_prb_tmpl(arvif); + if (ret) + ath10k_warn(ar, "failed to setup probe resp template on vdev %i: %d\n", + arvif->vdev_id, ret); + } + + if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) { arvif->dtim_period = info->dtim_period; ath10k_dbg(ar, ATH10K_DBG_MAC, @@ -3314,6 +3533,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ath10k_warn(ar, "failed to recalc tx power: %d\n", ret); } + if (changed & BSS_CHANGED_PS) { + ret = ath10k_mac_vif_setup_ps(arvif); + if (ret) + ath10k_warn(ar, "failed to setup ps on vdev %i: %d\n", + arvif->vdev_id, ret); + } + mutex_unlock(&ar->conf_mutex); } @@ -3453,6 +3679,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *peer_addr; bool is_wep = key->cipher == WLAN_CIPHER_SUITE_WEP40 || key->cipher == WLAN_CIPHER_SUITE_WEP104; + bool def_idx = false; int ret = 0; if (key->keyidx > WMI_MAX_KEY_INDEX) @@ -3498,7 +3725,14 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ath10k_clear_vdev_key(arvif, key); } - ret = ath10k_install_key(arvif, key, cmd, peer_addr); + /* set TX_USAGE flag for all the keys incase of dot1x-WEP. For + * static WEP, do not set this flag for the keys whose key id + * is greater than default key id. + */ + if (arvif->def_wep_key_idx == -1) + def_idx = true; + + ret = ath10k_install_key(arvif, key, cmd, peer_addr, def_idx); if (ret) { ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n", arvif->vdev_id, peer_addr, ret); @@ -3523,6 +3757,39 @@ exit: return ret; } +static void ath10k_set_default_unicast_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + int keyidx) +{ + struct ath10k *ar = hw->priv; + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + int ret; + + mutex_lock(&arvif->ar->conf_mutex); + + if (arvif->ar->state != ATH10K_STATE_ON) + goto unlock; + + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n", + arvif->vdev_id, keyidx); + + ret = ath10k_wmi_vdev_set_param(arvif->ar, + arvif->vdev_id, + arvif->ar->wmi.vdev_param->def_keyid, + keyidx); + + if (ret) { + ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n", + arvif->vdev_id, + ret); + goto unlock; + } + + arvif->def_wep_key_idx = keyidx; +unlock: + mutex_unlock(&arvif->ar->conf_mutex); +} + static void ath10k_sta_rc_update_wk(struct work_struct *wk) { struct ath10k *ar; @@ -3583,8 +3850,9 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, smps, err); } - if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", + if (changed & IEEE80211_RC_SUPP_RATES_CHANGED || + changed & IEEE80211_RC_NSS_CHANGED) { + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n", sta->addr); err = ath10k_station_assoc(ar, arvif->vif, sta, true); @@ -3757,6 +4025,8 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, u16 ac, bool enable) { struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + struct wmi_sta_uapsd_auto_trig_arg arg = {}; + u32 prio = 0, acc = 0; u32 value = 0; int ret = 0; @@ -3769,18 +4039,26 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, case IEEE80211_AC_VO: value = WMI_STA_PS_UAPSD_AC3_DELIVERY_EN | WMI_STA_PS_UAPSD_AC3_TRIGGER_EN; + prio = 7; + acc = 3; break; case IEEE80211_AC_VI: value = WMI_STA_PS_UAPSD_AC2_DELIVERY_EN | WMI_STA_PS_UAPSD_AC2_TRIGGER_EN; + prio = 5; + acc = 2; break; case IEEE80211_AC_BE: value = WMI_STA_PS_UAPSD_AC1_DELIVERY_EN | WMI_STA_PS_UAPSD_AC1_TRIGGER_EN; + prio = 2; + acc = 1; break; case IEEE80211_AC_BK: value = WMI_STA_PS_UAPSD_AC0_DELIVERY_EN | WMI_STA_PS_UAPSD_AC0_TRIGGER_EN; + prio = 0; + acc = 0; break; } @@ -3808,6 +4086,43 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, if (ret) ath10k_warn(ar, "failed to set rx wake param: %d\n", ret); + ret = ath10k_mac_vif_recalc_ps_wake_threshold(arvif); + if (ret) { + ath10k_warn(ar, "failed to recalc ps wake threshold on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + ret = ath10k_mac_vif_recalc_ps_poll_count(arvif); + if (ret) { + ath10k_warn(ar, "failed to recalc ps poll count on vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + if (test_bit(WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, ar->wmi.svc_map) || + test_bit(WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, ar->wmi.svc_map)) { + /* Only userspace can make an educated decision when to send + * trigger frame. The following effectively disables u-UAPSD + * autotrigger in firmware (which is enabled by default + * provided the autotrigger service is available). + */ + + arg.wmm_ac = acc; + arg.user_priority = prio; + arg.service_interval = 0; + arg.suspend_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC; + arg.delay_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC; + + ret = ath10k_wmi_vdev_sta_uapsd(ar, arvif->vdev_id, + arvif->bssid, &arg, 1); + if (ret) { + ath10k_warn(ar, "failed to set uapsd auto trigger %d\n", + ret); + return ret; + } + } + exit: return ret; } @@ -3817,6 +4132,7 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw, const struct ieee80211_tx_queue_params *params) { struct ath10k *ar = hw->priv; + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct wmi_wmm_params_arg *p = NULL; int ret; @@ -3824,16 +4140,16 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw, switch (ac) { case IEEE80211_AC_VO: - p = &ar->wmm_params.ac_vo; + p = &arvif->wmm_params.ac_vo; break; case IEEE80211_AC_VI: - p = &ar->wmm_params.ac_vi; + p = &arvif->wmm_params.ac_vi; break; case IEEE80211_AC_BE: - p = &ar->wmm_params.ac_be; + p = &arvif->wmm_params.ac_be; break; case IEEE80211_AC_BK: - p = &ar->wmm_params.ac_bk; + p = &arvif->wmm_params.ac_bk; break; } @@ -3853,11 +4169,23 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw, */ p->txop = params->txop * 32; - /* FIXME: FW accepts wmm params per hw, not per vif */ - ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params); - if (ret) { - ath10k_warn(ar, "failed to set wmm params: %d\n", ret); - goto exit; + if (ar->wmi.ops->gen_vdev_wmm_conf) { + ret = ath10k_wmi_vdev_wmm_conf(ar, arvif->vdev_id, + &arvif->wmm_params); + if (ret) { + ath10k_warn(ar, "failed to set vdev wmm params on vdev %i: %d\n", + arvif->vdev_id, ret); + goto exit; + } + } else { + /* This won't work well with multi-interface cases but it's + * better than nothing. + */ + ret = ath10k_wmi_pdev_set_wmm_params(ar, &arvif->wmm_params); + if (ret) { + ath10k_warn(ar, "failed to set wmm params: %d\n", ret); + goto exit; + } } ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd); @@ -3989,29 +4317,6 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return ret; } -static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct ath10k *ar = hw->priv; - struct ath10k_vif *arvif; - int ret = 0; - - mutex_lock(&ar->conf_mutex); - list_for_each_entry(arvif, &ar->arvifs, list) { - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n", - arvif->vdev_id, value); - - ret = ath10k_mac_set_frag(arvif, value); - if (ret) { - ath10k_warn(ar, "failed to set fragmentation threshold for vdev %d: %d\n", - arvif->vdev_id, ret); - break; - } - } - mutex_unlock(&ar->conf_mutex); - - return ret; -} - static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { @@ -4650,12 +4955,12 @@ static const struct ieee80211_ops ath10k_ops = { .hw_scan = ath10k_hw_scan, .cancel_hw_scan = ath10k_cancel_hw_scan, .set_key = ath10k_set_key, + .set_default_unicast_key = ath10k_set_default_unicast_key, .sta_state = ath10k_sta_state, .conf_tx = ath10k_conf_tx, .remain_on_channel = ath10k_remain_on_channel, .cancel_remain_on_channel = ath10k_cancel_remain_on_channel, .set_rts_threshold = ath10k_set_rts_threshold, - .set_frag_threshold = ath10k_set_frag_threshold, .flush = ath10k_flush, .tx_last_beacon = ath10k_tx_last_beacon, .set_antenna = ath10k_set_antenna, @@ -4676,6 +4981,9 @@ static const struct ieee80211_ops ath10k_ops = { .suspend = ath10k_suspend, .resume = ath10k_resume, #endif +#ifdef CONFIG_MAC80211_DEBUGFS + .sta_add_debugfs = ath10k_sta_add_debugfs, +#endif }; #define RATETAB_ENT(_rate, _rateid, _flags) { \ @@ -4746,6 +5054,9 @@ static const struct ieee80211_channel ath10k_5ghz_channels[] = { CHAN5G(165, 5825, 0), }; +/* Note: Be careful if you re-order these. There is code which depends on this + * ordering. + */ static struct ieee80211_rate ath10k_rates[] = { /* CCK */ RATETAB_ENT(10, 0x82, 0), @@ -4799,6 +5110,10 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = { .types = BIT(NL80211_IFTYPE_P2P_GO) }, { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE) + }, + { .max = 7, .types = BIT(NL80211_IFTYPE_AP) }, @@ -4956,6 +5271,13 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id) int ath10k_mac_register(struct ath10k *ar) { + static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_AES_CMAC, + }; struct ieee80211_supported_band *band; struct ieee80211_sta_vht_cap vht_cap; struct ieee80211_sta_ht_cap ht_cap; @@ -4985,7 +5307,8 @@ int ath10k_mac_register(struct ath10k *ar) band->bitrates = ath10k_g_rates; band->ht_cap = ht_cap; - /* vht is not supported in 2.4 GHz */ + /* Enable the VHT support at 2.4 GHz */ + band->vht_cap = vht_cap; ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = band; } @@ -5018,18 +5341,19 @@ int ath10k_mac_register(struct ath10k *ar) if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features)) ar->hw->wiphy->interface_modes |= + BIT(NL80211_IFTYPE_P2P_DEVICE) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); ar->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | - IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_MFP_CAPABLE | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_AP_LINK_PS | - IEEE80211_HW_SPECTRUM_MGMT; + IEEE80211_HW_SPECTRUM_MGMT | + IEEE80211_HW_SW_CRYPTO_CONTROL; ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; @@ -5049,6 +5373,19 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; + if (test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) { + ar->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; + + /* Firmware delivers WPS/P2P Probe Requests frames to driver so + * that userspace (e.g. wpa_supplicant/hostapd) can generate + * correct Probe Responses. This is more of a hack advert.. + */ + ar->hw->wiphy->probe_resp_offload |= + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; + } + ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; ar->hw->wiphy->max_remain_on_channel_duration = 5000; @@ -5062,16 +5399,26 @@ int ath10k_mac_register(struct ath10k *ar) */ ar->hw->queues = 4; - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb; - ar->hw->wiphy->n_iface_combinations = - ARRAY_SIZE(ath10k_10x_if_comb); - } else { + switch (ar->wmi.op_version) { + case ATH10K_FW_WMI_OP_VERSION_MAIN: + case ATH10K_FW_WMI_OP_VERSION_TLV: ar->hw->wiphy->iface_combinations = ath10k_if_comb; ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_if_comb); - ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); + break; + case ATH10K_FW_WMI_OP_VERSION_10_1: + case ATH10K_FW_WMI_OP_VERSION_10_2: + case ATH10K_FW_WMI_OP_VERSION_10_2_4: + ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb; + ar->hw->wiphy->n_iface_combinations = + ARRAY_SIZE(ath10k_10x_if_comb); + break; + case ATH10K_FW_WMI_OP_VERSION_UNSET: + case ATH10K_FW_WMI_OP_VERSION_MAX: + WARN_ON(1); + ret = -EINVAL; + goto err_free; } ar->hw->netdev_features = NETIF_F_HW_CSUM; @@ -5093,6 +5440,9 @@ int ath10k_mac_register(struct ath10k *ar) goto err_free; } + ar->hw->wiphy->cipher_suites = cipher_suites; + ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + ret = ieee80211_register_hw(ar->hw); if (ret) { ath10k_err(ar, "failed to register ieee80211: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 7abb8367119a..e6972b09333e 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -58,12 +58,27 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); #define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3 #define QCA988X_2_0_DEVICE_ID (0x003c) +#define QCA6174_2_1_DEVICE_ID (0x003e) static const struct pci_device_id ath10k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ + { PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */ {0} }; +static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { + /* QCA988X pre 2.0 chips are not supported because they need some nasty + * hacks. ath10k doesn't have them and these devices crash horribly + * because of that. + */ + { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV }, + { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_1_CHIP_ID_REV }, + { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_2_CHIP_ID_REV }, + { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV }, + { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV }, + { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, +}; + static void ath10k_pci_buffer_cleanup(struct ath10k *ar); static int ath10k_pci_cold_reset(struct ath10k *ar); static int ath10k_pci_warm_reset(struct ath10k *ar); @@ -395,7 +410,7 @@ static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe) return -EIO; } - ATH10K_SKB_CB(skb)->paddr = paddr; + ATH10K_SKB_RXCB(skb)->paddr = paddr; ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr); if (ret) { @@ -864,7 +879,7 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) &flags) == 0) { skb = transfer_context; max_nbytes = skb->len + skb_tailroom(skb); - dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, + dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, max_nbytes, DMA_FROM_DEVICE); if (unlikely(max_nbytes < nbytes)) { @@ -1230,7 +1245,7 @@ static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) ce_ring->per_transfer_context[i] = NULL; - dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, + dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); dev_kfree_skb_any(skb); @@ -1498,6 +1513,35 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar) return 0; } +static int ath10k_pci_get_num_banks(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + + switch (ar_pci->pdev->device) { + case QCA988X_2_0_DEVICE_ID: + return 1; + case QCA6174_2_1_DEVICE_ID: + switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) { + case QCA6174_HW_1_0_CHIP_ID_REV: + case QCA6174_HW_1_1_CHIP_ID_REV: + return 3; + case QCA6174_HW_1_3_CHIP_ID_REV: + return 2; + case QCA6174_HW_2_1_CHIP_ID_REV: + case QCA6174_HW_2_2_CHIP_ID_REV: + return 6; + case QCA6174_HW_3_0_CHIP_ID_REV: + case QCA6174_HW_3_1_CHIP_ID_REV: + case QCA6174_HW_3_2_CHIP_ID_REV: + return 9; + } + break; + } + + ath10k_warn(ar, "unknown number of banks, assuming 1\n"); + return 1; +} + static int ath10k_pci_init_config(struct ath10k *ar) { u32 interconnect_targ_addr; @@ -1608,7 +1652,8 @@ static int ath10k_pci_init_config(struct ath10k *ar) /* first bank is switched to IRAM */ ealloc_value |= ((HI_EARLY_ALLOC_MAGIC << HI_EARLY_ALLOC_MAGIC_SHIFT) & HI_EARLY_ALLOC_MAGIC_MASK); - ealloc_value |= ((1 << HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) & + ealloc_value |= ((ath10k_pci_get_num_banks(ar) << + HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) & HI_EARLY_ALLOC_IRAM_BANKS_MASK); ret = ath10k_pci_diag_write32(ar, ealloc_targ_addr, ealloc_value); @@ -1804,12 +1849,12 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) return 0; } -static int ath10k_pci_chip_reset(struct ath10k *ar) +static int ath10k_pci_qca988x_chip_reset(struct ath10k *ar) { int i, ret; u32 val; - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot 988x chip reset\n"); /* Some hardware revisions (e.g. CUS223v2) has issues with cold reset. * It is thus preferred to use warm reset which is safer but may not be @@ -1873,11 +1918,53 @@ static int ath10k_pci_chip_reset(struct ath10k *ar) return ret; } - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset complete (cold)\n"); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca988x chip reset complete (cold)\n"); return 0; } +static int ath10k_pci_qca6174_chip_reset(struct ath10k *ar) +{ + int ret; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca6174 chip reset\n"); + + /* FIXME: QCA6174 requires cold + warm reset to work. */ + + ret = ath10k_pci_cold_reset(ar); + if (ret) { + ath10k_warn(ar, "failed to cold reset: %d\n", ret); + return ret; + } + + ret = ath10k_pci_wait_for_target_init(ar); + if (ret) { + ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", + ret); + return ret; + } + + ret = ath10k_pci_warm_reset(ar); + if (ret) { + ath10k_warn(ar, "failed to warm reset: %d\n", ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca6174 chip reset complete (cold)\n"); + + return 0; +} + +static int ath10k_pci_chip_reset(struct ath10k *ar) +{ + if (QCA_REV_988X(ar)) + return ath10k_pci_qca988x_chip_reset(ar); + else if (QCA_REV_6174(ar)) + return ath10k_pci_qca6174_chip_reset(ar); + else + return -ENOTSUPP; +} + static int ath10k_pci_hif_power_up(struct ath10k *ar) { int ret; @@ -1902,6 +1989,12 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar) */ ret = ath10k_pci_chip_reset(ar); if (ret) { + if (ath10k_pci_has_fw_crashed(ar)) { + ath10k_warn(ar, "firmware crashed during chip reset\n"); + ath10k_pci_fw_crashed_clear(ar); + ath10k_pci_fw_crashed_dump(ar); + } + ath10k_err(ar, "failed to reset chip: %d\n", ret); goto err_sleep; } @@ -2033,6 +2126,7 @@ static void ath10k_msi_err_tasklet(unsigned long data) return; } + ath10k_pci_irq_disable(ar); ath10k_pci_fw_crashed_clear(ar); ath10k_pci_fw_crashed_dump(ar); } @@ -2102,6 +2196,7 @@ static void ath10k_pci_tasklet(unsigned long data) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); if (ath10k_pci_has_fw_crashed(ar)) { + ath10k_pci_irq_disable(ar); ath10k_pci_fw_crashed_clear(ar); ath10k_pci_fw_crashed_dump(ar); return; @@ -2344,8 +2439,6 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) if (val & FW_IND_EVENT_PENDING) { ath10k_warn(ar, "device has crashed during init\n"); - ath10k_pci_fw_crashed_clear(ar); - ath10k_pci_fw_crashed_dump(ar); return -ECOMM; } @@ -2476,17 +2569,46 @@ static void ath10k_pci_release(struct ath10k *ar) pci_disable_device(pdev); } +static bool ath10k_pci_chip_is_supported(u32 dev_id, u32 chip_id) +{ + const struct ath10k_pci_supp_chip *supp_chip; + int i; + u32 rev_id = MS(chip_id, SOC_CHIP_ID_REV); + + for (i = 0; i < ARRAY_SIZE(ath10k_pci_supp_chips); i++) { + supp_chip = &ath10k_pci_supp_chips[i]; + + if (supp_chip->dev_id == dev_id && + supp_chip->rev_id == rev_id) + return true; + } + + return false; +} + static int ath10k_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_dev) { int ret = 0; struct ath10k *ar; struct ath10k_pci *ar_pci; + enum ath10k_hw_rev hw_rev; u32 chip_id; - ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev, - ATH10K_BUS_PCI, - &ath10k_pci_hif_ops); + switch (pci_dev->device) { + case QCA988X_2_0_DEVICE_ID: + hw_rev = ATH10K_HW_QCA988X; + break; + case QCA6174_2_1_DEVICE_ID: + hw_rev = ATH10K_HW_QCA6174; + break; + default: + WARN_ON(1); + return -ENOTSUPP; + } + + ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev, ATH10K_BUS_PCI, + hw_rev, &ath10k_pci_hif_ops); if (!ar) { dev_err(&pdev->dev, "failed to allocate core\n"); return -ENOMEM; @@ -2515,12 +2637,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_release; } - chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); - if (chip_id == 0xffffffff) { - ath10k_err(ar, "failed to get chip id\n"); - goto err_sleep; - } - ret = ath10k_pci_alloc_pipes(ar); if (ret) { ath10k_err(ar, "failed to allocate copy engine pipes: %d\n", @@ -2547,6 +2663,24 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_deinit_irq; } + ret = ath10k_pci_chip_reset(ar); + if (ret) { + ath10k_err(ar, "failed to reset chip: %d\n", ret); + goto err_free_irq; + } + + chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); + if (chip_id == 0xffffffff) { + ath10k_err(ar, "failed to get chip id\n"); + goto err_free_irq; + } + + if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) { + ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n", + pdev->device, chip_id); + goto err_sleep; + } + ath10k_pci_sleep(ar); ret = ath10k_core_register(ar, chip_id); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index cf36511c7f4d..bddf54320160 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -152,6 +152,11 @@ struct ath10k_pci_pipe { struct tasklet_struct intr; }; +struct ath10k_pci_supp_chip { + u32 dev_id; + u32 rev_id; +}; + struct ath10k_pci { struct pci_dev *pdev; struct device *dev; @@ -189,7 +194,7 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) #define ATH10K_PCI_RX_POST_RETRY_MS 50 #define ATH_PCI_RESET_WAIT_MAX 10 /* ms */ -#define PCIE_WAKE_TIMEOUT 5000 /* 5ms */ +#define PCIE_WAKE_TIMEOUT 10000 /* 10ms */ #define BAR_NUM 0 diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index e1ffdd57a18c..e9cc7787bf5f 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -850,7 +850,7 @@ struct rx_ppdu_start { #define RX_PPDU_END_INFO1_PPDU_DONE (1 << 15) -struct rx_ppdu_end { +struct rx_ppdu_end_common { __le32 evm_p0; __le32 evm_p1; __le32 evm_p2; @@ -873,10 +873,33 @@ struct rx_ppdu_end { u8 phy_err_code; __le16 flags; /* %RX_PPDU_END_FLAGS_ */ __le32 info0; /* %RX_PPDU_END_INFO0_ */ +} __packed; + +struct rx_ppdu_end_qca988x { __le16 bb_length; __le16 info1; /* %RX_PPDU_END_INFO1_ */ } __packed; +#define RX_PPDU_END_RTT_CORRELATION_VALUE_MASK 0x00ffffff +#define RX_PPDU_END_RTT_CORRELATION_VALUE_LSB 0 +#define RX_PPDU_END_RTT_UNUSED_MASK 0x7f000000 +#define RX_PPDU_END_RTT_UNUSED_LSB 24 +#define RX_PPDU_END_RTT_NORMAL_MODE BIT(31) + +struct rx_ppdu_end_qca6174 { + __le32 rtt; /* %RX_PPDU_END_RTT_ */ + __le16 bb_length; + __le16 info1; /* %RX_PPDU_END_INFO1_ */ +} __packed; + +struct rx_ppdu_end { + struct rx_ppdu_end_common common; + union { + struct rx_ppdu_end_qca988x qca988x; + struct rx_ppdu_end_qca6174 qca6174; + } __packed; +} __packed; + /* * evm_p0 * EVM for pilot 0. Contain EVM for streams: 0, 1, 2 and 3. diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c index 63ce61fcdac8..d22addf6118b 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.c +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -17,6 +17,7 @@ #include #include "core.h" #include "debug.h" +#include "wmi-ops.h" static void send_fft_sample(struct ath10k *ar, const struct fft_sample_tlv *fft_sample_tlv) diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index 9d0ae30f9ff1..a417aae52623 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -18,6 +18,8 @@ #ifndef __TARGADDRS_H__ #define __TARGADDRS_H__ +#include "hw.h" + /* * xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the * host_interest structure. It must match the address of the _host_interest @@ -445,4 +447,7 @@ Fw Mode/SubMode Mask #define QCA988X_BOARD_DATA_SZ 7168 #define QCA988X_BOARD_EXT_DATA_SZ 0 +#define QCA6174_BOARD_DATA_SZ 8192 +#define QCA6174_BOARD_EXT_DATA_SZ 0 + #endif /* __TARGADDRS_H__ */ diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c index 483db9cb8c96..b084f88da102 100644 --- a/drivers/net/wireless/ath/ath10k/testmode.c +++ b/drivers/net/wireless/ath/ath10k/testmode.c @@ -187,13 +187,14 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[]) memcpy(ar->testmode.orig_fw_features, ar->fw_features, sizeof(ar->fw_features)); + ar->testmode.orig_wmi_op_version = ar->wmi.op_version; /* utf.bin firmware image does not advertise firmware features. Do * an ugly hack where we force the firmware features so that wmi.c * will use the correct WMI interface. */ memset(ar->fw_features, 0, sizeof(ar->fw_features)); - __set_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features); + ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1; ret = ath10k_hif_power_up(ar); if (ret) { @@ -224,6 +225,7 @@ err_fw_features: /* return the original firmware features */ memcpy(ar->fw_features, ar->testmode.orig_fw_features, sizeof(ar->fw_features)); + ar->wmi.op_version = ar->testmode.orig_wmi_op_version; release_firmware(ar->testmode.utf); ar->testmode.utf = NULL; @@ -250,6 +252,7 @@ static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar) /* return the original firmware features */ memcpy(ar->fw_features, ar->testmode.orig_fw_features, sizeof(ar->fw_features)); + ar->wmi.op_version = ar->testmode.orig_wmi_op_version; release_firmware(ar->testmode.utf); ar->testmode.utf = NULL; diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c new file mode 100644 index 000000000000..aede750809fe --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include "core.h" +#include "debug.h" +#include "wmi-ops.h" + +static int ath10k_thermal_get_active_vifs(struct ath10k *ar, + enum wmi_vdev_type type) +{ + struct ath10k_vif *arvif; + int count = 0; + + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (!arvif->is_started) + continue; + + if (!arvif->is_up) + continue; + + if (arvif->vdev_type != type) + continue; + + count++; + } + return count; +} + +static int ath10k_thermal_get_max_dutycycle(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + *state = ATH10K_QUIET_DUTY_CYCLE_MAX; + + return 0; +} + +static int ath10k_thermal_get_cur_dutycycle(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct ath10k *ar = cdev->devdata; + + mutex_lock(&ar->conf_mutex); + *state = ar->thermal.duty_cycle; + mutex_unlock(&ar->conf_mutex); + + return 0; +} + +static int ath10k_thermal_set_cur_dutycycle(struct thermal_cooling_device *cdev, + unsigned long duty_cycle) +{ + struct ath10k *ar = cdev->devdata; + u32 period, duration, enabled; + int num_bss, ret = 0; + + mutex_lock(&ar->conf_mutex); + if (ar->state != ATH10K_STATE_ON) { + ret = -ENETDOWN; + goto out; + } + + if (duty_cycle > ATH10K_QUIET_DUTY_CYCLE_MAX) { + ath10k_warn(ar, "duty cycle %ld is exceeding the limit %d\n", + duty_cycle, ATH10K_QUIET_DUTY_CYCLE_MAX); + ret = -EINVAL; + goto out; + } + /* TODO: Right now, thermal mitigation is handled only for single/multi + * vif AP mode. Since quiet param is not validated in STA mode, it needs + * to be investigated further to handle multi STA and multi-vif (AP+STA) + * mode properly. + */ + num_bss = ath10k_thermal_get_active_vifs(ar, WMI_VDEV_TYPE_AP); + if (!num_bss) { + ath10k_warn(ar, "no active AP interfaces\n"); + ret = -ENETDOWN; + goto out; + } + period = max(ATH10K_QUIET_PERIOD_MIN, + (ATH10K_QUIET_PERIOD_DEFAULT / num_bss)); + duration = (period * duty_cycle) / 100; + enabled = duration ? 1 : 0; + + ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration, + ATH10K_QUIET_START_OFFSET, + enabled); + if (ret) { + ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n", + period, duration, enabled, ret); + goto out; + } + ar->thermal.duty_cycle = duty_cycle; +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static struct thermal_cooling_device_ops ath10k_thermal_ops = { + .get_max_state = ath10k_thermal_get_max_dutycycle, + .get_cur_state = ath10k_thermal_get_cur_dutycycle, + .set_cur_state = ath10k_thermal_set_cur_dutycycle, +}; + +static ssize_t ath10k_thermal_show_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ath10k *ar = dev_get_drvdata(dev); + int ret, temperature; + + mutex_lock(&ar->conf_mutex); + + /* Can't get temperature when the card is off */ + if (ar->state != ATH10K_STATE_ON) { + ret = -ENETDOWN; + goto out; + } + + reinit_completion(&ar->thermal.wmi_sync); + ret = ath10k_wmi_pdev_get_temperature(ar); + if (ret) { + ath10k_warn(ar, "failed to read temperature %d\n", ret); + goto out; + } + + if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) { + ret = -ESHUTDOWN; + goto out; + } + + ret = wait_for_completion_timeout(&ar->thermal.wmi_sync, + ATH10K_THERMAL_SYNC_TIMEOUT_HZ); + if (ret == 0) { + ath10k_warn(ar, "failed to synchronize thermal read\n"); + ret = -ETIMEDOUT; + goto out; + } + + spin_lock_bh(&ar->data_lock); + temperature = ar->thermal.temperature; + spin_unlock_bh(&ar->data_lock); + + /* display in millidegree celcius */ + ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000); +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature) +{ + spin_lock_bh(&ar->data_lock); + ar->thermal.temperature = temperature; + spin_unlock_bh(&ar->data_lock); + complete(&ar->thermal.wmi_sync); +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ath10k_thermal_show_temp, + NULL, 0); + +static struct attribute *ath10k_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(ath10k_hwmon); + +int ath10k_thermal_register(struct ath10k *ar) +{ + struct thermal_cooling_device *cdev; + struct device *hwmon_dev; + int ret; + + cdev = thermal_cooling_device_register("ath10k_thermal", ar, + &ath10k_thermal_ops); + + if (IS_ERR(cdev)) { + ath10k_err(ar, "failed to setup thermal device result: %ld\n", + PTR_ERR(cdev)); + return -EINVAL; + } + + ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj, + "cooling_device"); + if (ret) { + ath10k_err(ar, "failed to create thermal symlink\n"); + goto err_cooling_destroy; + } + + ar->thermal.cdev = cdev; + + /* Do not register hwmon device when temperature reading is not + * supported by firmware + */ + if (ar->wmi.op_version != ATH10K_FW_WMI_OP_VERSION_10_2_4) + return 0; + + /* Avoid linking error on devm_hwmon_device_register_with_groups, I + * guess linux/hwmon.h is missing proper stubs. */ + if (!config_enabled(CONFIG_HWMON)) + return 0; + + hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev, + "ath10k_hwmon", ar, + ath10k_hwmon_groups); + if (IS_ERR(hwmon_dev)) { + ath10k_err(ar, "failed to register hwmon device: %ld\n", + PTR_ERR(hwmon_dev)); + ret = -EINVAL; + goto err_remove_link; + } + return 0; + +err_remove_link: + sysfs_remove_link(&ar->dev->kobj, "thermal_sensor"); +err_cooling_destroy: + thermal_cooling_device_unregister(cdev); + return ret; +} + +void ath10k_thermal_unregister(struct ath10k *ar) +{ + thermal_cooling_device_unregister(ar->thermal.cdev); + sysfs_remove_link(&ar->dev->kobj, "cooling_device"); +} diff --git a/drivers/net/wireless/ath/ath10k/thermal.h b/drivers/net/wireless/ath/ath10k/thermal.h new file mode 100644 index 000000000000..bccc17ae0fde --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/thermal.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _THERMAL_ +#define _THERMAL_ + +#define ATH10K_QUIET_PERIOD_DEFAULT 100 +#define ATH10K_QUIET_PERIOD_MIN 25 +#define ATH10K_QUIET_START_OFFSET 10 +#define ATH10K_QUIET_DUTY_CYCLE_MAX 70 +#define ATH10K_HWMON_NAME_LEN 15 +#define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5*HZ) + +struct ath10k_thermal { + struct thermal_cooling_device *cdev; + struct completion wmi_sync; + + /* protected by conf_mutex */ + u32 duty_cycle; + /* temperature value in Celcius degree + * protected by data_lock + */ + int temperature; +}; + +#ifdef CONFIG_THERMAL +int ath10k_thermal_register(struct ath10k *ar); +void ath10k_thermal_unregister(struct ath10k *ar); +void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature); +#else +static inline int ath10k_thermal_register(struct ath10k *ar) +{ + return 0; +} + +static inline void ath10k_thermal_unregister(struct ath10k *ar) +{ +} + +static inline void ath10k_thermal_event_temperature(struct ath10k *ar, + int temperature) +{ +} + +#endif +#endif /* _THERMAL_ */ diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h index b289378b6e3e..5407887380ab 100644 --- a/drivers/net/wireless/ath/ath10k/trace.h +++ b/drivers/net/wireless/ath/ath10k/trace.h @@ -453,6 +453,74 @@ TRACE_EVENT(ath10k_htt_rx_desc, ) ); +TRACE_EVENT(ath10k_wmi_diag_container, + TP_PROTO(struct ath10k *ar, + u8 type, + u32 timestamp, + u32 code, + u16 len, + const void *data), + + TP_ARGS(ar, type, timestamp, code, len, data), + + TP_STRUCT__entry( + __string(device, dev_name(ar->dev)) + __string(driver, dev_driver_string(ar->dev)) + __field(u8, type) + __field(u32, timestamp) + __field(u32, code) + __field(u16, len) + __dynamic_array(u8, data, len) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ar->dev)); + __assign_str(driver, dev_driver_string(ar->dev)); + __entry->type = type; + __entry->timestamp = timestamp; + __entry->code = code; + __entry->len = len; + memcpy(__get_dynamic_array(data), data, len); + ), + + TP_printk( + "%s %s diag container type %hhu timestamp %u code %u len %d", + __get_str(driver), + __get_str(device), + __entry->type, + __entry->timestamp, + __entry->code, + __entry->len + ) +); + +TRACE_EVENT(ath10k_wmi_diag, + TP_PROTO(struct ath10k *ar, const void *data, size_t len), + + TP_ARGS(ar, data, len), + + TP_STRUCT__entry( + __string(device, dev_name(ar->dev)) + __string(driver, dev_driver_string(ar->dev)) + __field(u16, len) + __dynamic_array(u8, data, len) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ar->dev)); + __assign_str(driver, dev_driver_string(ar->dev)); + __entry->len = len; + memcpy(__get_dynamic_array(data), data, len); + ), + + TP_printk( + "%s %s tlv diag len %d", + __get_str(driver), + __get_str(device), + __entry->len + ) +); + #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ /* we don't want to use include/trace/events */ diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 7579de8e7a8c..3f00cec8aef5 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -64,7 +64,13 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, return; } - msdu = htt->pending_tx[tx_done->msdu_id]; + msdu = idr_find(&htt->pending_tx, tx_done->msdu_id); + if (!msdu) { + ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n", + tx_done->msdu_id); + return; + } + skb_cb = ATH10K_SKB_CB(msdu); dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); @@ -95,7 +101,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, /* we do not own the msdu anymore */ exit: - htt->pending_tx[tx_done->msdu_id] = NULL; ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); __ath10k_htt_tx_dec_pending(htt); if (htt->num_pending_tx == 0) diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h new file mode 100644 index 000000000000..04dc4b9db04e --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -0,0 +1,1064 @@ +/* + * Copyright (c) 2005-2011 Atheros Communications Inc. + * Copyright (c) 2011-2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WMI_OPS_H_ +#define _WMI_OPS_H_ + +struct ath10k; +struct sk_buff; + +struct wmi_ops { + void (*rx)(struct ath10k *ar, struct sk_buff *skb); + void (*map_svc)(const __le32 *in, unsigned long *out, size_t len); + + int (*pull_scan)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_scan_ev_arg *arg); + int (*pull_mgmt_rx)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_mgmt_rx_ev_arg *arg); + int (*pull_ch_info)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_ch_info_ev_arg *arg); + int (*pull_vdev_start)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_vdev_start_ev_arg *arg); + int (*pull_peer_kick)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_peer_kick_ev_arg *arg); + int (*pull_swba)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_swba_ev_arg *arg); + int (*pull_phyerr)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_phyerr_ev_arg *arg); + int (*pull_svc_rdy)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_svc_rdy_ev_arg *arg); + int (*pull_rdy)(struct ath10k *ar, struct sk_buff *skb, + struct wmi_rdy_ev_arg *arg); + int (*pull_fw_stats)(struct ath10k *ar, struct sk_buff *skb, + struct ath10k_fw_stats *stats); + + struct sk_buff *(*gen_pdev_suspend)(struct ath10k *ar, u32 suspend_opt); + struct sk_buff *(*gen_pdev_resume)(struct ath10k *ar); + struct sk_buff *(*gen_pdev_set_rd)(struct ath10k *ar, u16 rd, u16 rd2g, + u16 rd5g, u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg); + struct sk_buff *(*gen_pdev_set_param)(struct ath10k *ar, u32 id, + u32 value); + struct sk_buff *(*gen_init)(struct ath10k *ar); + struct sk_buff *(*gen_start_scan)(struct ath10k *ar, + const struct wmi_start_scan_arg *arg); + struct sk_buff *(*gen_stop_scan)(struct ath10k *ar, + const struct wmi_stop_scan_arg *arg); + struct sk_buff *(*gen_vdev_create)(struct ath10k *ar, u32 vdev_id, + enum wmi_vdev_type type, + enum wmi_vdev_subtype subtype, + const u8 macaddr[ETH_ALEN]); + struct sk_buff *(*gen_vdev_delete)(struct ath10k *ar, u32 vdev_id); + struct sk_buff *(*gen_vdev_start)(struct ath10k *ar, + const struct wmi_vdev_start_request_arg *arg, + bool restart); + struct sk_buff *(*gen_vdev_stop)(struct ath10k *ar, u32 vdev_id); + struct sk_buff *(*gen_vdev_up)(struct ath10k *ar, u32 vdev_id, u32 aid, + const u8 *bssid); + struct sk_buff *(*gen_vdev_down)(struct ath10k *ar, u32 vdev_id); + struct sk_buff *(*gen_vdev_set_param)(struct ath10k *ar, u32 vdev_id, + u32 param_id, u32 param_value); + struct sk_buff *(*gen_vdev_install_key)(struct ath10k *ar, + const struct wmi_vdev_install_key_arg *arg); + struct sk_buff *(*gen_vdev_spectral_conf)(struct ath10k *ar, + const struct wmi_vdev_spectral_conf_arg *arg); + struct sk_buff *(*gen_vdev_spectral_enable)(struct ath10k *ar, u32 vdev_id, + u32 trigger, u32 enable); + struct sk_buff *(*gen_vdev_wmm_conf)(struct ath10k *ar, u32 vdev_id, + const struct wmi_wmm_params_all_arg *arg); + struct sk_buff *(*gen_peer_create)(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]); + struct sk_buff *(*gen_peer_delete)(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]); + struct sk_buff *(*gen_peer_flush)(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN], + u32 tid_bitmap); + struct sk_buff *(*gen_peer_set_param)(struct ath10k *ar, u32 vdev_id, + const u8 *peer_addr, + enum wmi_peer_param param_id, + u32 param_value); + struct sk_buff *(*gen_peer_assoc)(struct ath10k *ar, + const struct wmi_peer_assoc_complete_arg *arg); + struct sk_buff *(*gen_set_psmode)(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_ps_mode psmode); + struct sk_buff *(*gen_set_sta_ps)(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_powersave_param param_id, + u32 value); + struct sk_buff *(*gen_set_ap_ps)(struct ath10k *ar, u32 vdev_id, + const u8 *mac, + enum wmi_ap_ps_peer_param param_id, + u32 value); + struct sk_buff *(*gen_scan_chan_list)(struct ath10k *ar, + const struct wmi_scan_chan_list_arg *arg); + struct sk_buff *(*gen_beacon_dma)(struct ath10k *ar, u32 vdev_id, + const void *bcn, size_t bcn_len, + u32 bcn_paddr, bool dtim_zero, + bool deliver_cab); + struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar, + const struct wmi_wmm_params_all_arg *arg); + struct sk_buff *(*gen_request_stats)(struct ath10k *ar, + enum wmi_stats_id stats_id); + struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar, + enum wmi_force_fw_hang_type type, + u32 delay_ms); + struct sk_buff *(*gen_mgmt_tx)(struct ath10k *ar, struct sk_buff *skb); + struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u32 module_enable, + u32 log_level); + struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter); + struct sk_buff *(*gen_pktlog_disable)(struct ath10k *ar); + struct sk_buff *(*gen_pdev_set_quiet_mode)(struct ath10k *ar, + u32 period, u32 duration, + u32 next_offset, + u32 enabled); + struct sk_buff *(*gen_pdev_get_temperature)(struct ath10k *ar); + struct sk_buff *(*gen_addba_clear_resp)(struct ath10k *ar, u32 vdev_id, + const u8 *mac); + struct sk_buff *(*gen_addba_send)(struct ath10k *ar, u32 vdev_id, + const u8 *mac, u32 tid, u32 buf_size); + struct sk_buff *(*gen_addba_set_resp)(struct ath10k *ar, u32 vdev_id, + const u8 *mac, u32 tid, + u32 status); + struct sk_buff *(*gen_delba_send)(struct ath10k *ar, u32 vdev_id, + const u8 *mac, u32 tid, u32 initiator, + u32 reason); + struct sk_buff *(*gen_bcn_tmpl)(struct ath10k *ar, u32 vdev_id, + u32 tim_ie_offset, struct sk_buff *bcn, + u32 prb_caps, u32 prb_erp, + void *prb_ies, size_t prb_ies_len); + struct sk_buff *(*gen_prb_tmpl)(struct ath10k *ar, u32 vdev_id, + struct sk_buff *bcn); + struct sk_buff *(*gen_p2p_go_bcn_ie)(struct ath10k *ar, u32 vdev_id, + const u8 *p2p_ie); + struct sk_buff *(*gen_vdev_sta_uapsd)(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN], + const struct wmi_sta_uapsd_auto_trig_arg *args, + u32 num_ac); + struct sk_buff *(*gen_sta_keepalive)(struct ath10k *ar, + const struct wmi_sta_keepalive_arg *arg); +}; + +int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); + +static inline int +ath10k_wmi_rx(struct ath10k *ar, struct sk_buff *skb) +{ + if (WARN_ON_ONCE(!ar->wmi.ops->rx)) + return -EOPNOTSUPP; + + ar->wmi.ops->rx(ar, skb); + return 0; +} + +static inline int +ath10k_wmi_map_svc(struct ath10k *ar, const __le32 *in, unsigned long *out, + size_t len) +{ + if (!ar->wmi.ops->map_svc) + return -EOPNOTSUPP; + + ar->wmi.ops->map_svc(in, out, len); + return 0; +} + +static inline int +ath10k_wmi_pull_scan(struct ath10k *ar, struct sk_buff *skb, + struct wmi_scan_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_scan) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_scan(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_mgmt_rx(struct ath10k *ar, struct sk_buff *skb, + struct wmi_mgmt_rx_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_mgmt_rx) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_mgmt_rx(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_ch_info(struct ath10k *ar, struct sk_buff *skb, + struct wmi_ch_info_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_ch_info) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_ch_info(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_vdev_start(struct ath10k *ar, struct sk_buff *skb, + struct wmi_vdev_start_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_vdev_start) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_vdev_start(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_peer_kick(struct ath10k *ar, struct sk_buff *skb, + struct wmi_peer_kick_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_peer_kick) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_peer_kick(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_swba(struct ath10k *ar, struct sk_buff *skb, + struct wmi_swba_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_swba) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_swba(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_phyerr(struct ath10k *ar, struct sk_buff *skb, + struct wmi_phyerr_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_phyerr) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_phyerr(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_svc_rdy(struct ath10k *ar, struct sk_buff *skb, + struct wmi_svc_rdy_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_svc_rdy) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_svc_rdy(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_rdy(struct ath10k *ar, struct sk_buff *skb, + struct wmi_rdy_ev_arg *arg) +{ + if (!ar->wmi.ops->pull_rdy) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_rdy(ar, skb, arg); +} + +static inline int +ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb, + struct ath10k_fw_stats *stats) +{ + if (!ar->wmi.ops->pull_fw_stats) + return -EOPNOTSUPP; + + return ar->wmi.ops->pull_fw_stats(ar, skb, stats); +} + +static inline int +ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu); + struct sk_buff *skb; + int ret; + + if (!ar->wmi.ops->gen_mgmt_tx) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_mgmt_tx(ar, msdu); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + ret = ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->mgmt_tx_cmdid); + if (ret) + return ret; + + /* FIXME There's no ACK event for Management Tx. This probably + * shouldn't be called here either. */ + info->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(ar->hw, msdu); + + return 0; +} + +static inline int +ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, u16 rd5g, + u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_set_rd) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_set_rd(ar, rd, rd2g, rd5g, ctl2g, ctl5g, + dfs_reg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_set_regdomain_cmdid); +} + +static inline int +ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_suspend) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_suspend(ar, suspend_opt); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid); +} + +static inline int +ath10k_wmi_pdev_resume_target(struct ath10k *ar) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_resume) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_resume(ar); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_resume_cmdid); +} + +static inline int +ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_set_param) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_set_param(ar, id, value); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid); +} + +static inline int +ath10k_wmi_cmd_init(struct ath10k *ar) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_init) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_init(ar); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->init_cmdid); +} + +static inline int +ath10k_wmi_start_scan(struct ath10k *ar, + const struct wmi_start_scan_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_start_scan) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_start_scan(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid); +} + +static inline int +ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_stop_scan) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_stop_scan(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid); +} + +static inline int +ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, + enum wmi_vdev_type type, + enum wmi_vdev_subtype subtype, + const u8 macaddr[ETH_ALEN]) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_create) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_create(ar, vdev_id, type, subtype, macaddr); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_create_cmdid); +} + +static inline int +ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_delete) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_delete(ar, vdev_id); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid); +} + +static inline int +ath10k_wmi_vdev_start(struct ath10k *ar, + const struct wmi_vdev_start_request_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_start) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_start(ar, arg, false); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->vdev_start_request_cmdid); +} + +static inline int +ath10k_wmi_vdev_restart(struct ath10k *ar, + const struct wmi_vdev_start_request_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_start) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_start(ar, arg, true); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->vdev_restart_request_cmdid); +} + +static inline int +ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_stop) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_stop(ar, vdev_id); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid); +} + +static inline int +ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_up) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_up(ar, vdev_id, aid, bssid); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_up_cmdid); +} + +static inline int +ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_down) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_down(ar, vdev_id); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid); +} + +static inline int +ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, u32 param_id, + u32 param_value) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_set_param) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_set_param(ar, vdev_id, param_id, + param_value); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_set_param_cmdid); +} + +static inline int +ath10k_wmi_vdev_install_key(struct ath10k *ar, + const struct wmi_vdev_install_key_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_vdev_install_key) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_install_key(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->vdev_install_key_cmdid); +} + +static inline int +ath10k_wmi_vdev_spectral_conf(struct ath10k *ar, + const struct wmi_vdev_spectral_conf_arg *arg) +{ + struct sk_buff *skb; + u32 cmd_id; + + skb = ar->wmi.ops->gen_vdev_spectral_conf(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + cmd_id = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid; + return ath10k_wmi_cmd_send(ar, skb, cmd_id); +} + +static inline int +ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger, + u32 enable) +{ + struct sk_buff *skb; + u32 cmd_id; + + skb = ar->wmi.ops->gen_vdev_spectral_enable(ar, vdev_id, trigger, + enable); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + cmd_id = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid; + return ath10k_wmi_cmd_send(ar, skb, cmd_id); +} + +static inline int +ath10k_wmi_vdev_sta_uapsd(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN], + const struct wmi_sta_uapsd_auto_trig_arg *args, + u32 num_ac) +{ + struct sk_buff *skb; + u32 cmd_id; + + if (!ar->wmi.ops->gen_vdev_sta_uapsd) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_vdev_sta_uapsd(ar, vdev_id, peer_addr, args, + num_ac); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + cmd_id = ar->wmi.cmd->sta_uapsd_auto_trig_cmdid; + return ath10k_wmi_cmd_send(ar, skb, cmd_id); +} + +static inline int +ath10k_wmi_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id, + const struct wmi_wmm_params_all_arg *arg) +{ + struct sk_buff *skb; + u32 cmd_id; + + skb = ar->wmi.ops->gen_vdev_wmm_conf(ar, vdev_id, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + cmd_id = ar->wmi.cmd->vdev_set_wmm_params_cmdid; + return ath10k_wmi_cmd_send(ar, skb, cmd_id); +} + +static inline int +ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_peer_create) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_peer_create(ar, vdev_id, peer_addr); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid); +} + +static inline int +ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_peer_delete) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_peer_delete(ar, vdev_id, peer_addr); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid); +} + +static inline int +ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN], u32 tid_bitmap) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_peer_flush) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_peer_flush(ar, vdev_id, peer_addr, tid_bitmap); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid); +} + +static inline int +ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, const u8 *peer_addr, + enum wmi_peer_param param_id, u32 param_value) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_peer_set_param) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_peer_set_param(ar, vdev_id, peer_addr, param_id, + param_value); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_set_param_cmdid); +} + +static inline int +ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_ps_mode psmode) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_set_psmode) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_set_psmode(ar, vdev_id, psmode); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->sta_powersave_mode_cmdid); +} + +static inline int +ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_powersave_param param_id, u32 value) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_set_sta_ps) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_set_sta_ps(ar, vdev_id, param_id, value); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->sta_powersave_param_cmdid); +} + +static inline int +ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, + enum wmi_ap_ps_peer_param param_id, u32 value) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_set_ap_ps) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_set_ap_ps(ar, vdev_id, mac, param_id, value); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->ap_ps_peer_param_cmdid); +} + +static inline int +ath10k_wmi_scan_chan_list(struct ath10k *ar, + const struct wmi_scan_chan_list_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_scan_chan_list) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_scan_chan_list(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid); +} + +static inline int +ath10k_wmi_peer_assoc(struct ath10k *ar, + const struct wmi_peer_assoc_complete_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_peer_assoc) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_peer_assoc(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid); +} + +static inline int +ath10k_wmi_beacon_send_ref_nowait(struct ath10k *ar, u32 vdev_id, + const void *bcn, size_t bcn_len, + u32 bcn_paddr, bool dtim_zero, + bool deliver_cab) +{ + struct sk_buff *skb; + int ret; + + if (!ar->wmi.ops->gen_beacon_dma) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_beacon_dma(ar, vdev_id, bcn, bcn_len, bcn_paddr, + dtim_zero, deliver_cab); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + ret = ath10k_wmi_cmd_send_nowait(ar, skb, + ar->wmi.cmd->pdev_send_bcn_cmdid); + if (ret) { + dev_kfree_skb(skb); + return ret; + } + + return 0; +} + +static inline int +ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, + const struct wmi_wmm_params_all_arg *arg) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_set_wmm) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_set_wmm(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_set_wmm_params_cmdid); +} + +static inline int +ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_request_stats) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_request_stats(ar, stats_id); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid); +} + +static inline int +ath10k_wmi_force_fw_hang(struct ath10k *ar, + enum wmi_force_fw_hang_type type, u32 delay_ms) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_force_fw_hang) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_force_fw_hang(ar, type, delay_ms); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid); +} + +static inline int +ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable, u32 log_level) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_dbglog_cfg) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_dbglog_cfg(ar, module_enable, log_level); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid); +} + +static inline int +ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 filter) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pktlog_enable) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pktlog_enable(ar, filter); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_pktlog_enable_cmdid); +} + +static inline int +ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pktlog_disable) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pktlog_disable(ar); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_pktlog_disable_cmdid); +} + +static inline int +ath10k_wmi_pdev_set_quiet_mode(struct ath10k *ar, u32 period, u32 duration, + u32 next_offset, u32 enabled) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_set_quiet_mode) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_set_quiet_mode(ar, period, duration, + next_offset, enabled); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_set_quiet_mode_cmdid); +} + +static inline int +ath10k_wmi_pdev_get_temperature(struct ath10k *ar) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_get_temperature) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_get_temperature(ar); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_get_temperature_cmdid); +} + +static inline int +ath10k_wmi_addba_clear_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_addba_clear_resp) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_addba_clear_resp(ar, vdev_id, mac); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->addba_clear_resp_cmdid); +} + +static inline int +ath10k_wmi_addba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, + u32 tid, u32 buf_size) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_addba_send) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_addba_send(ar, vdev_id, mac, tid, buf_size); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->addba_send_cmdid); +} + +static inline int +ath10k_wmi_addba_set_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac, + u32 tid, u32 status) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_addba_set_resp) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_addba_set_resp(ar, vdev_id, mac, tid, status); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->addba_set_resp_cmdid); +} + +static inline int +ath10k_wmi_delba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, + u32 tid, u32 initiator, u32 reason) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_delba_send) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_delba_send(ar, vdev_id, mac, tid, initiator, + reason); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->delba_send_cmdid); +} + +static inline int +ath10k_wmi_bcn_tmpl(struct ath10k *ar, u32 vdev_id, u32 tim_ie_offset, + struct sk_buff *bcn, u32 prb_caps, u32 prb_erp, + void *prb_ies, size_t prb_ies_len) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_bcn_tmpl) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_bcn_tmpl(ar, vdev_id, tim_ie_offset, bcn, + prb_caps, prb_erp, prb_ies, + prb_ies_len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->bcn_tmpl_cmdid); +} + +static inline int +ath10k_wmi_prb_tmpl(struct ath10k *ar, u32 vdev_id, struct sk_buff *prb) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_prb_tmpl) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_prb_tmpl(ar, vdev_id, prb); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->prb_tmpl_cmdid); +} + +static inline int +ath10k_wmi_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id, const u8 *p2p_ie) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_p2p_go_bcn_ie) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_p2p_go_bcn_ie(ar, vdev_id, p2p_ie); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->p2p_go_set_beacon_ie); +} + +static inline int +ath10k_wmi_sta_keepalive(struct ath10k *ar, + const struct wmi_sta_keepalive_arg *arg) +{ + struct sk_buff *skb; + u32 cmd_id; + + if (!ar->wmi.ops->gen_sta_keepalive) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_sta_keepalive(ar, arg); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + cmd_id = ar->wmi.cmd->sta_keepalive_cmd; + return ath10k_wmi_cmd_send(ar, skb, cmd_id); +} + +#endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c new file mode 100644 index 000000000000..71614ba1b145 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -0,0 +1,2696 @@ +/* + * Copyright (c) 2005-2011 Atheros Communications Inc. + * Copyright (c) 2011-2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "core.h" +#include "debug.h" +#include "hw.h" +#include "wmi.h" +#include "wmi-ops.h" +#include "wmi-tlv.h" + +/***************/ +/* TLV helpers */ +/**************/ + +struct wmi_tlv_policy { + size_t min_len; +}; + +static const struct wmi_tlv_policy wmi_tlv_policies[] = { + [WMI_TLV_TAG_ARRAY_BYTE] + = { .min_len = sizeof(u8) }, + [WMI_TLV_TAG_ARRAY_UINT32] + = { .min_len = sizeof(u32) }, + [WMI_TLV_TAG_STRUCT_SCAN_EVENT] + = { .min_len = sizeof(struct wmi_scan_event) }, + [WMI_TLV_TAG_STRUCT_MGMT_RX_HDR] + = { .min_len = sizeof(struct wmi_tlv_mgmt_rx_ev) }, + [WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT] + = { .min_len = sizeof(struct wmi_chan_info_event) }, + [WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT] + = { .min_len = sizeof(struct wmi_vdev_start_response_event) }, + [WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT] + = { .min_len = sizeof(struct wmi_peer_sta_kickout_event) }, + [WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT] + = { .min_len = sizeof(struct wmi_host_swba_event) }, + [WMI_TLV_TAG_STRUCT_TIM_INFO] + = { .min_len = sizeof(struct wmi_tim_info) }, + [WMI_TLV_TAG_STRUCT_P2P_NOA_INFO] + = { .min_len = sizeof(struct wmi_p2p_noa_info) }, + [WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT] + = { .min_len = sizeof(struct wmi_tlv_svc_rdy_ev) }, + [WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES] + = { .min_len = sizeof(struct hal_reg_capabilities) }, + [WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ] + = { .min_len = sizeof(struct wlan_host_mem_req) }, + [WMI_TLV_TAG_STRUCT_READY_EVENT] + = { .min_len = sizeof(struct wmi_tlv_rdy_ev) }, + [WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT] + = { .min_len = sizeof(struct wmi_tlv_bcn_tx_status_ev) }, + [WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT] + = { .min_len = sizeof(struct wmi_tlv_diag_data_ev) }, +}; + +static int +ath10k_wmi_tlv_iter(struct ath10k *ar, const void *ptr, size_t len, + int (*iter)(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data), + void *data) +{ + const void *begin = ptr; + const struct wmi_tlv *tlv; + u16 tlv_tag, tlv_len; + int ret; + + while (len > 0) { + if (len < sizeof(*tlv)) { + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n", + ptr - begin, len, sizeof(*tlv)); + return -EINVAL; + } + + tlv = ptr; + tlv_tag = __le16_to_cpu(tlv->tag); + tlv_len = __le16_to_cpu(tlv->len); + ptr += sizeof(*tlv); + len -= sizeof(*tlv); + + if (tlv_len > len) { + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv parse failure of tag %hhu at byte %zd (%zu bytes left, %hhu expected)\n", + tlv_tag, ptr - begin, len, tlv_len); + return -EINVAL; + } + + if (tlv_tag < ARRAY_SIZE(wmi_tlv_policies) && + wmi_tlv_policies[tlv_tag].min_len && + wmi_tlv_policies[tlv_tag].min_len > tlv_len) { + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv parse failure of tag %hhu at byte %zd (%hhu bytes is less than min length %zu)\n", + tlv_tag, ptr - begin, tlv_len, + wmi_tlv_policies[tlv_tag].min_len); + return -EINVAL; + } + + ret = iter(ar, tlv_tag, tlv_len, ptr, data); + if (ret) + return ret; + + ptr += tlv_len; + len -= tlv_len; + } + + return 0; +} + +static int ath10k_wmi_tlv_iter_parse(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data) +{ + const void **tb = data; + + if (tag < WMI_TLV_TAG_MAX) + tb[tag] = ptr; + + return 0; +} + +static int ath10k_wmi_tlv_parse(struct ath10k *ar, const void **tb, + const void *ptr, size_t len) +{ + return ath10k_wmi_tlv_iter(ar, ptr, len, ath10k_wmi_tlv_iter_parse, + (void *)tb); +} + +static const void ** +ath10k_wmi_tlv_parse_alloc(struct ath10k *ar, const void *ptr, + size_t len, gfp_t gfp) +{ + const void **tb; + int ret; + + tb = kzalloc(sizeof(*tb) * WMI_TLV_TAG_MAX, gfp); + if (!tb) + return ERR_PTR(-ENOMEM); + + ret = ath10k_wmi_tlv_parse(ar, tb, ptr, len); + if (ret) { + kfree(tb); + return ERR_PTR(ret); + } + + return tb; +} + +static u16 ath10k_wmi_tlv_len(const void *ptr) +{ + return __le16_to_cpu((((const struct wmi_tlv *)ptr) - 1)->len); +} + +/**************/ +/* TLV events */ +/**************/ +static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_tlv_bcn_tx_status_ev *ev; + u32 vdev_id, tx_status; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } + + tx_status = __le32_to_cpu(ev->tx_status); + vdev_id = __le32_to_cpu(ev->vdev_id); + + switch (tx_status) { + case WMI_TLV_BCN_TX_STATUS_OK: + break; + case WMI_TLV_BCN_TX_STATUS_XRETRY: + case WMI_TLV_BCN_TX_STATUS_DROP: + case WMI_TLV_BCN_TX_STATUS_FILTERED: + /* FIXME: It's probably worth telling mac80211 to stop the + * interface as it is crippled. + */ + ath10k_warn(ar, "received bcn tmpl tx status on vdev %i: %d", + vdev_id, tx_status); + break; + } + + kfree(tb); + return 0; +} + +static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_tlv_diag_data_ev *ev; + const struct wmi_tlv_diag_item *item; + const void *data; + int ret, num_items, len; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT]; + data = tb[WMI_TLV_TAG_ARRAY_BYTE]; + if (!ev || !data) { + kfree(tb); + return -EPROTO; + } + + num_items = __le32_to_cpu(ev->num_items); + len = ath10k_wmi_tlv_len(data); + + while (num_items--) { + if (len == 0) + break; + if (len < sizeof(*item)) { + ath10k_warn(ar, "failed to parse diag data: can't fit item header\n"); + break; + } + + item = data; + + if (len < sizeof(*item) + __le16_to_cpu(item->len)) { + ath10k_warn(ar, "failed to parse diag data: item is too long\n"); + break; + } + + trace_ath10k_wmi_diag_container(ar, + item->type, + __le32_to_cpu(item->timestamp), + __le32_to_cpu(item->code), + __le16_to_cpu(item->len), + item->payload); + + len -= sizeof(*item); + len -= roundup(__le16_to_cpu(item->len), 4); + + data += sizeof(*item); + data += roundup(__le16_to_cpu(item->len), 4); + } + + if (num_items != -1 || len != 0) + ath10k_warn(ar, "failed to parse diag data event: num_items %d len %d\n", + num_items, len); + + kfree(tb); + return 0; +} + +static int ath10k_wmi_tlv_event_diag(struct ath10k *ar, + struct sk_buff *skb) +{ + const void **tb; + const void *data; + int ret, len; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + data = tb[WMI_TLV_TAG_ARRAY_BYTE]; + if (!data) { + kfree(tb); + return -EPROTO; + } + len = ath10k_wmi_tlv_len(data); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv diag event len %d\n", len); + trace_ath10k_wmi_diag(ar, data, len); + + kfree(tb); + return 0; +} + +/***********/ +/* TLV ops */ +/***********/ + +static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_cmd_hdr *cmd_hdr; + enum wmi_tlv_event_id id; + + cmd_hdr = (struct wmi_cmd_hdr *)skb->data; + id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); + + if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL) + return; + + trace_ath10k_wmi_event(ar, id, skb->data, skb->len); + + switch (id) { + case WMI_TLV_MGMT_RX_EVENTID: + ath10k_wmi_event_mgmt_rx(ar, skb); + /* mgmt_rx() owns the skb now! */ + return; + case WMI_TLV_SCAN_EVENTID: + ath10k_wmi_event_scan(ar, skb); + break; + case WMI_TLV_CHAN_INFO_EVENTID: + ath10k_wmi_event_chan_info(ar, skb); + break; + case WMI_TLV_ECHO_EVENTID: + ath10k_wmi_event_echo(ar, skb); + break; + case WMI_TLV_DEBUG_MESG_EVENTID: + ath10k_wmi_event_debug_mesg(ar, skb); + break; + case WMI_TLV_UPDATE_STATS_EVENTID: + ath10k_wmi_event_update_stats(ar, skb); + break; + case WMI_TLV_VDEV_START_RESP_EVENTID: + ath10k_wmi_event_vdev_start_resp(ar, skb); + break; + case WMI_TLV_VDEV_STOPPED_EVENTID: + ath10k_wmi_event_vdev_stopped(ar, skb); + break; + case WMI_TLV_PEER_STA_KICKOUT_EVENTID: + ath10k_wmi_event_peer_sta_kickout(ar, skb); + break; + case WMI_TLV_HOST_SWBA_EVENTID: + ath10k_wmi_event_host_swba(ar, skb); + break; + case WMI_TLV_TBTTOFFSET_UPDATE_EVENTID: + ath10k_wmi_event_tbttoffset_update(ar, skb); + break; + case WMI_TLV_PHYERR_EVENTID: + ath10k_wmi_event_phyerr(ar, skb); + break; + case WMI_TLV_ROAM_EVENTID: + ath10k_wmi_event_roam(ar, skb); + break; + case WMI_TLV_PROFILE_MATCH: + ath10k_wmi_event_profile_match(ar, skb); + break; + case WMI_TLV_DEBUG_PRINT_EVENTID: + ath10k_wmi_event_debug_print(ar, skb); + break; + case WMI_TLV_PDEV_QVIT_EVENTID: + ath10k_wmi_event_pdev_qvit(ar, skb); + break; + case WMI_TLV_WLAN_PROFILE_DATA_EVENTID: + ath10k_wmi_event_wlan_profile_data(ar, skb); + break; + case WMI_TLV_RTT_MEASUREMENT_REPORT_EVENTID: + ath10k_wmi_event_rtt_measurement_report(ar, skb); + break; + case WMI_TLV_TSF_MEASUREMENT_REPORT_EVENTID: + ath10k_wmi_event_tsf_measurement_report(ar, skb); + break; + case WMI_TLV_RTT_ERROR_REPORT_EVENTID: + ath10k_wmi_event_rtt_error_report(ar, skb); + break; + case WMI_TLV_WOW_WAKEUP_HOST_EVENTID: + ath10k_wmi_event_wow_wakeup_host(ar, skb); + break; + case WMI_TLV_DCS_INTERFERENCE_EVENTID: + ath10k_wmi_event_dcs_interference(ar, skb); + break; + case WMI_TLV_PDEV_TPC_CONFIG_EVENTID: + ath10k_wmi_event_pdev_tpc_config(ar, skb); + break; + case WMI_TLV_PDEV_FTM_INTG_EVENTID: + ath10k_wmi_event_pdev_ftm_intg(ar, skb); + break; + case WMI_TLV_GTK_OFFLOAD_STATUS_EVENTID: + ath10k_wmi_event_gtk_offload_status(ar, skb); + break; + case WMI_TLV_GTK_REKEY_FAIL_EVENTID: + ath10k_wmi_event_gtk_rekey_fail(ar, skb); + break; + case WMI_TLV_TX_DELBA_COMPLETE_EVENTID: + ath10k_wmi_event_delba_complete(ar, skb); + break; + case WMI_TLV_TX_ADDBA_COMPLETE_EVENTID: + ath10k_wmi_event_addba_complete(ar, skb); + break; + case WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID: + ath10k_wmi_event_vdev_install_key_complete(ar, skb); + break; + case WMI_TLV_SERVICE_READY_EVENTID: + ath10k_wmi_event_service_ready(ar, skb); + break; + case WMI_TLV_READY_EVENTID: + ath10k_wmi_event_ready(ar, skb); + break; + case WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID: + ath10k_wmi_tlv_event_bcn_tx_status(ar, skb); + break; + case WMI_TLV_DIAG_DATA_CONTAINER_EVENTID: + ath10k_wmi_tlv_event_diag_data(ar, skb); + break; + case WMI_TLV_DIAG_EVENTID: + ath10k_wmi_tlv_event_diag(ar, skb); + break; + default: + ath10k_warn(ar, "Unknown eventid: %d\n", id); + break; + } + + dev_kfree_skb(skb); +} + +static int ath10k_wmi_tlv_op_pull_scan_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_scan_ev_arg *arg) +{ + const void **tb; + const struct wmi_scan_event *ev; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_SCAN_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } + + arg->event_type = ev->event_type; + arg->reason = ev->reason; + arg->channel_freq = ev->channel_freq; + arg->scan_req_id = ev->scan_req_id; + arg->scan_id = ev->scan_id; + arg->vdev_id = ev->vdev_id; + + kfree(tb); + return 0; +} + +static int ath10k_wmi_tlv_op_pull_mgmt_rx_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_mgmt_rx_ev_arg *arg) +{ + const void **tb; + const struct wmi_tlv_mgmt_rx_ev *ev; + const u8 *frame; + u32 msdu_len; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_MGMT_RX_HDR]; + frame = tb[WMI_TLV_TAG_ARRAY_BYTE]; + + if (!ev || !frame) { + kfree(tb); + return -EPROTO; + } + + arg->channel = ev->channel; + arg->buf_len = ev->buf_len; + arg->status = ev->status; + arg->snr = ev->snr; + arg->phy_mode = ev->phy_mode; + arg->rate = ev->rate; + + msdu_len = __le32_to_cpu(arg->buf_len); + + if (skb->len < (frame - skb->data) + msdu_len) { + kfree(tb); + return -EPROTO; + } + + /* shift the sk_buff to point to `frame` */ + skb_trim(skb, 0); + skb_put(skb, frame - skb->data); + skb_pull(skb, frame - skb->data); + skb_put(skb, msdu_len); + + kfree(tb); + return 0; +} + +static int ath10k_wmi_tlv_op_pull_ch_info_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_ch_info_ev_arg *arg) +{ + const void **tb; + const struct wmi_chan_info_event *ev; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } + + arg->err_code = ev->err_code; + arg->freq = ev->freq; + arg->cmd_flags = ev->cmd_flags; + arg->noise_floor = ev->noise_floor; + arg->rx_clear_count = ev->rx_clear_count; + arg->cycle_count = ev->cycle_count; + + kfree(tb); + return 0; +} + +static int +ath10k_wmi_tlv_op_pull_vdev_start_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_vdev_start_ev_arg *arg) +{ + const void **tb; + const struct wmi_vdev_start_response_event *ev; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } + + skb_pull(skb, sizeof(*ev)); + arg->vdev_id = ev->vdev_id; + arg->req_id = ev->req_id; + arg->resp_type = ev->resp_type; + arg->status = ev->status; + + kfree(tb); + return 0; +} + +static int ath10k_wmi_tlv_op_pull_peer_kick_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_peer_kick_ev_arg *arg) +{ + const void **tb; + const struct wmi_peer_sta_kickout_event *ev; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } + + arg->mac_addr = ev->peer_macaddr.addr; + + kfree(tb); + return 0; +} + +struct wmi_tlv_swba_parse { + const struct wmi_host_swba_event *ev; + bool tim_done; + bool noa_done; + size_t n_tim; + size_t n_noa; + struct wmi_swba_ev_arg *arg; +}; + +static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_tlv_swba_parse *swba = data; + + if (tag != WMI_TLV_TAG_STRUCT_TIM_INFO) + return -EPROTO; + + if (swba->n_tim >= ARRAY_SIZE(swba->arg->tim_info)) + return -ENOBUFS; + + swba->arg->tim_info[swba->n_tim++] = ptr; + return 0; +} + +static int ath10k_wmi_tlv_swba_noa_parse(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_tlv_swba_parse *swba = data; + + if (tag != WMI_TLV_TAG_STRUCT_P2P_NOA_INFO) + return -EPROTO; + + if (swba->n_noa >= ARRAY_SIZE(swba->arg->noa_info)) + return -ENOBUFS; + + swba->arg->noa_info[swba->n_noa++] = ptr; + return 0; +} + +static int ath10k_wmi_tlv_swba_parse(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_tlv_swba_parse *swba = data; + int ret; + + switch (tag) { + case WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT: + swba->ev = ptr; + break; + case WMI_TLV_TAG_ARRAY_STRUCT: + if (!swba->tim_done) { + swba->tim_done = true; + ret = ath10k_wmi_tlv_iter(ar, ptr, len, + ath10k_wmi_tlv_swba_tim_parse, + swba); + if (ret) + return ret; + } else if (!swba->noa_done) { + swba->noa_done = true; + ret = ath10k_wmi_tlv_iter(ar, ptr, len, + ath10k_wmi_tlv_swba_noa_parse, + swba); + if (ret) + return ret; + } + break; + default: + break; + } + return 0; +} + +static int ath10k_wmi_tlv_op_pull_swba_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_swba_ev_arg *arg) +{ + struct wmi_tlv_swba_parse swba = { .arg = arg }; + u32 map; + size_t n_vdevs; + int ret; + + ret = ath10k_wmi_tlv_iter(ar, skb->data, skb->len, + ath10k_wmi_tlv_swba_parse, &swba); + if (ret) { + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + if (!swba.ev) + return -EPROTO; + + arg->vdev_map = swba.ev->vdev_map; + + for (map = __le32_to_cpu(arg->vdev_map), n_vdevs = 0; map; map >>= 1) + if (map & BIT(0)) + n_vdevs++; + + if (n_vdevs != swba.n_tim || + n_vdevs != swba.n_noa) + return -EPROTO; + + return 0; +} + +static int ath10k_wmi_tlv_op_pull_phyerr_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_phyerr_ev_arg *arg) +{ + const void **tb; + const struct wmi_tlv_phyerr_ev *ev; + const void *phyerrs; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_COMB_PHYERR_RX_HDR]; + phyerrs = tb[WMI_TLV_TAG_ARRAY_BYTE]; + + if (!ev || !phyerrs) { + kfree(tb); + return -EPROTO; + } + + arg->num_phyerrs = ev->num_phyerrs; + arg->tsf_l32 = ev->tsf_l32; + arg->tsf_u32 = ev->tsf_u32; + arg->buf_len = ev->buf_len; + arg->phyerrs = phyerrs; + + kfree(tb); + return 0; +} + +#define WMI_TLV_ABI_VER_NS0 0x5F414351 +#define WMI_TLV_ABI_VER_NS1 0x00004C4D +#define WMI_TLV_ABI_VER_NS2 0x00000000 +#define WMI_TLV_ABI_VER_NS3 0x00000000 + +#define WMI_TLV_ABI_VER0_MAJOR 1 +#define WMI_TLV_ABI_VER0_MINOR 0 +#define WMI_TLV_ABI_VER0 ((((WMI_TLV_ABI_VER0_MAJOR) << 24) & 0xFF000000) | \ + (((WMI_TLV_ABI_VER0_MINOR) << 0) & 0x00FFFFFF)) +#define WMI_TLV_ABI_VER1 53 + +static int +ath10k_wmi_tlv_parse_mem_reqs(struct ath10k *ar, u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_svc_rdy_ev_arg *arg = data; + int i; + + if (tag != WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ) + return -EPROTO; + + for (i = 0; i < ARRAY_SIZE(arg->mem_reqs); i++) { + if (!arg->mem_reqs[i]) { + arg->mem_reqs[i] = ptr; + return 0; + } + } + + return -ENOMEM; +} + +static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_svc_rdy_ev_arg *arg) +{ + const void **tb; + const struct hal_reg_capabilities *reg; + const struct wmi_tlv_svc_rdy_ev *ev; + const __le32 *svc_bmap; + const struct wlan_host_mem_req *mem_reqs; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT]; + reg = tb[WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES]; + svc_bmap = tb[WMI_TLV_TAG_ARRAY_UINT32]; + mem_reqs = tb[WMI_TLV_TAG_ARRAY_STRUCT]; + + if (!ev || !reg || !svc_bmap || !mem_reqs) { + kfree(tb); + return -EPROTO; + } + + /* This is an internal ABI compatibility check for WMI TLV so check it + * here instead of the generic WMI code. + */ + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv abi 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x\n", + __le32_to_cpu(ev->abi.abi_ver0), WMI_TLV_ABI_VER0, + __le32_to_cpu(ev->abi.abi_ver_ns0), WMI_TLV_ABI_VER_NS0, + __le32_to_cpu(ev->abi.abi_ver_ns1), WMI_TLV_ABI_VER_NS1, + __le32_to_cpu(ev->abi.abi_ver_ns2), WMI_TLV_ABI_VER_NS2, + __le32_to_cpu(ev->abi.abi_ver_ns3), WMI_TLV_ABI_VER_NS3); + + if (__le32_to_cpu(ev->abi.abi_ver0) != WMI_TLV_ABI_VER0 || + __le32_to_cpu(ev->abi.abi_ver_ns0) != WMI_TLV_ABI_VER_NS0 || + __le32_to_cpu(ev->abi.abi_ver_ns1) != WMI_TLV_ABI_VER_NS1 || + __le32_to_cpu(ev->abi.abi_ver_ns2) != WMI_TLV_ABI_VER_NS2 || + __le32_to_cpu(ev->abi.abi_ver_ns3) != WMI_TLV_ABI_VER_NS3) { + kfree(tb); + return -ENOTSUPP; + } + + arg->min_tx_power = ev->hw_min_tx_power; + arg->max_tx_power = ev->hw_max_tx_power; + arg->ht_cap = ev->ht_cap_info; + arg->vht_cap = ev->vht_cap_info; + arg->sw_ver0 = ev->abi.abi_ver0; + arg->sw_ver1 = ev->abi.abi_ver1; + arg->fw_build = ev->fw_build_vers; + arg->phy_capab = ev->phy_capability; + arg->num_rf_chains = ev->num_rf_chains; + arg->eeprom_rd = reg->eeprom_rd; + arg->num_mem_reqs = ev->num_mem_reqs; + arg->service_map = svc_bmap; + arg->service_map_len = ath10k_wmi_tlv_len(svc_bmap); + + ret = ath10k_wmi_tlv_iter(ar, mem_reqs, ath10k_wmi_tlv_len(mem_reqs), + ath10k_wmi_tlv_parse_mem_reqs, arg); + if (ret) { + kfree(tb); + ath10k_warn(ar, "failed to parse mem_reqs tlv: %d\n", ret); + return ret; + } + + kfree(tb); + return 0; +} + +static int ath10k_wmi_tlv_op_pull_rdy_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_rdy_ev_arg *arg) +{ + const void **tb; + const struct wmi_tlv_rdy_ev *ev; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_READY_EVENT]; + if (!ev) { + kfree(tb); + return -EPROTO; + } + + arg->sw_version = ev->abi.abi_ver0; + arg->abi_version = ev->abi.abi_ver1; + arg->status = ev->status; + arg->mac_addr = ev->mac_addr.addr; + + kfree(tb); + return 0; +} + +static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar, + struct sk_buff *skb, + struct ath10k_fw_stats *stats) +{ + const void **tb; + const struct wmi_stats_event *ev; + const void *data; + u32 num_pdev_stats, num_vdev_stats, num_peer_stats; + size_t data_len; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TLV_TAG_STRUCT_STATS_EVENT]; + data = tb[WMI_TLV_TAG_ARRAY_BYTE]; + + if (!ev || !data) { + kfree(tb); + return -EPROTO; + } + + data_len = ath10k_wmi_tlv_len(data); + num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); + num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); + num_peer_stats = __le32_to_cpu(ev->num_peer_stats); + + WARN_ON(1); /* FIXME: not implemented yet */ + + kfree(tb); + return 0; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pdev_suspend(struct ath10k *ar, u32 opt) +{ + struct wmi_tlv_pdev_suspend *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SUSPEND_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->opt = __cpu_to_le32(opt); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev suspend\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pdev_resume(struct ath10k *ar) +{ + struct wmi_tlv_resume_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_RESUME_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->reserved = __cpu_to_le32(0); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev resume\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pdev_set_rd(struct ath10k *ar, + u16 rd, u16 rd2g, u16 rd5g, + u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg) +{ + struct wmi_tlv_pdev_set_rd_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_REGDOMAIN_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->regd = __cpu_to_le32(rd); + cmd->regd_2ghz = __cpu_to_le32(rd2g); + cmd->regd_5ghz = __cpu_to_le32(rd5g); + cmd->conform_limit_2ghz = __cpu_to_le32(rd2g); + cmd->conform_limit_5ghz = __cpu_to_le32(rd5g); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set rd\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pdev_set_param(struct ath10k *ar, u32 param_id, + u32 param_value) +{ + struct wmi_tlv_pdev_set_param_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_PARAM_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->param_id = __cpu_to_le32(param_id); + cmd->param_value = __cpu_to_le32(param_value); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set param\n"); + return skb; +} + +static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) +{ + struct sk_buff *skb; + struct wmi_tlv *tlv; + struct wmi_tlv_init_cmd *cmd; + struct wmi_tlv_resource_config *cfg; + struct wmi_host_mem_chunks *chunks; + size_t len, chunks_len; + void *ptr; + + chunks_len = ar->wmi.num_mem_chunks * sizeof(struct host_memory_chunk); + len = (sizeof(*tlv) + sizeof(*cmd)) + + (sizeof(*tlv) + sizeof(*cfg)) + + (sizeof(*tlv) + chunks_len); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = skb->data; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_INIT_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_RESOURCE_CONFIG); + tlv->len = __cpu_to_le16(sizeof(*cfg)); + cfg = (void *)tlv->value; + ptr += sizeof(*tlv); + ptr += sizeof(*cfg); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); + tlv->len = __cpu_to_le16(chunks_len); + chunks = (void *)tlv->value; + + ptr += sizeof(*tlv); + ptr += chunks_len; + + cmd->abi.abi_ver0 = __cpu_to_le32(WMI_TLV_ABI_VER0); + cmd->abi.abi_ver1 = __cpu_to_le32(WMI_TLV_ABI_VER1); + cmd->abi.abi_ver_ns0 = __cpu_to_le32(WMI_TLV_ABI_VER_NS0); + cmd->abi.abi_ver_ns1 = __cpu_to_le32(WMI_TLV_ABI_VER_NS1); + cmd->abi.abi_ver_ns2 = __cpu_to_le32(WMI_TLV_ABI_VER_NS2); + cmd->abi.abi_ver_ns3 = __cpu_to_le32(WMI_TLV_ABI_VER_NS3); + cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); + + cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); + cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS); + + if (test_bit(WMI_SERVICE_RX_FULL_REORDER, ar->wmi.svc_map)) { + cfg->num_offload_peers = __cpu_to_le32(3); + cfg->num_offload_reorder_bufs = __cpu_to_le32(3); + } else { + cfg->num_offload_peers = __cpu_to_le32(0); + cfg->num_offload_reorder_bufs = __cpu_to_le32(0); + } + + cfg->num_peer_keys = __cpu_to_le32(2); + cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS); + cfg->ast_skid_limit = __cpu_to_le32(0x10); + cfg->tx_chain_mask = __cpu_to_le32(0x7); + cfg->rx_chain_mask = __cpu_to_le32(0x7); + cfg->rx_timeout_pri[0] = __cpu_to_le32(0x64); + cfg->rx_timeout_pri[1] = __cpu_to_le32(0x64); + cfg->rx_timeout_pri[2] = __cpu_to_le32(0x64); + cfg->rx_timeout_pri[3] = __cpu_to_le32(0x28); + cfg->rx_decap_mode = __cpu_to_le32(1); + cfg->scan_max_pending_reqs = __cpu_to_le32(4); + cfg->bmiss_offload_max_vdev = __cpu_to_le32(3); + cfg->roam_offload_max_vdev = __cpu_to_le32(3); + cfg->roam_offload_max_ap_profiles = __cpu_to_le32(8); + cfg->num_mcast_groups = __cpu_to_le32(0); + cfg->num_mcast_table_elems = __cpu_to_le32(0); + cfg->mcast2ucast_mode = __cpu_to_le32(0); + cfg->tx_dbg_log_size = __cpu_to_le32(0x400); + cfg->num_wds_entries = __cpu_to_le32(0x20); + cfg->dma_burst_size = __cpu_to_le32(0); + cfg->mac_aggr_delim = __cpu_to_le32(0); + cfg->rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(0); + cfg->vow_config = __cpu_to_le32(0); + cfg->gtk_offload_max_vdev = __cpu_to_le32(2); + cfg->num_msdu_desc = __cpu_to_le32(TARGET_TLV_NUM_MSDU_DESC); + cfg->max_frag_entries = __cpu_to_le32(2); + cfg->num_tdls_vdevs = __cpu_to_le32(1); + cfg->num_tdls_conn_table_entries = __cpu_to_le32(0x20); + cfg->beacon_tx_offload_max_vdev = __cpu_to_le32(2); + cfg->num_multicast_filter_entries = __cpu_to_le32(5); + cfg->num_wow_filters = __cpu_to_le32(0x16); + cfg->num_keep_alive_pattern = __cpu_to_le32(6); + cfg->keep_alive_pattern_size = __cpu_to_le32(0); + cfg->max_tdls_concurrent_sleep_sta = __cpu_to_le32(1); + cfg->max_tdls_concurrent_buffer_sta = __cpu_to_le32(1); + + ath10k_wmi_put_host_mem_chunks(ar, chunks); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv init\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_start_scan(struct ath10k *ar, + const struct wmi_start_scan_arg *arg) +{ + struct wmi_tlv_start_scan_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len, chan_len, ssid_len, bssid_len, ie_len; + __le32 *chans; + struct wmi_ssid *ssids; + struct wmi_mac_addr *addrs; + void *ptr; + int i, ret; + + ret = ath10k_wmi_start_scan_verify(arg); + if (ret) + return ERR_PTR(ret); + + chan_len = arg->n_channels * sizeof(__le32); + ssid_len = arg->n_ssids * sizeof(struct wmi_ssid); + bssid_len = arg->n_bssids * sizeof(struct wmi_mac_addr); + ie_len = roundup(arg->ie_len, 4); + len = (sizeof(*tlv) + sizeof(*cmd)) + + (arg->n_channels ? sizeof(*tlv) + chan_len : 0) + + (arg->n_ssids ? sizeof(*tlv) + ssid_len : 0) + + (arg->n_bssids ? sizeof(*tlv) + bssid_len : 0) + + (arg->ie_len ? sizeof(*tlv) + ie_len : 0); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_START_SCAN_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + + ath10k_wmi_put_start_scan_common(&cmd->common, arg); + cmd->burst_duration_ms = __cpu_to_le32(0); + cmd->num_channels = __cpu_to_le32(arg->n_channels); + cmd->num_ssids = __cpu_to_le32(arg->n_ssids); + cmd->num_bssids = __cpu_to_le32(arg->n_bssids); + cmd->ie_len = __cpu_to_le32(arg->ie_len); + cmd->num_probes = __cpu_to_le32(3); + + /* FIXME: There are some scan flag inconsistencies across firmwares, + * e.g. WMI-TLV inverts the logic behind the following flag. + */ + cmd->common.scan_ctrl_flags ^= __cpu_to_le32(WMI_SCAN_FILTER_PROBE_REQ); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32); + tlv->len = __cpu_to_le16(chan_len); + chans = (void *)tlv->value; + for (i = 0; i < arg->n_channels; i++) + chans[i] = __cpu_to_le32(arg->channels[i]); + + ptr += sizeof(*tlv); + ptr += chan_len; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_FIXED_STRUCT); + tlv->len = __cpu_to_le16(ssid_len); + ssids = (void *)tlv->value; + for (i = 0; i < arg->n_ssids; i++) { + ssids[i].ssid_len = __cpu_to_le32(arg->ssids[i].len); + memcpy(ssids[i].ssid, arg->ssids[i].ssid, arg->ssids[i].len); + } + + ptr += sizeof(*tlv); + ptr += ssid_len; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_FIXED_STRUCT); + tlv->len = __cpu_to_le16(bssid_len); + addrs = (void *)tlv->value; + for (i = 0; i < arg->n_bssids; i++) + ether_addr_copy(addrs[i].addr, arg->bssids[i].bssid); + + ptr += sizeof(*tlv); + ptr += bssid_len; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(ie_len); + memcpy(tlv->value, arg->ie, arg->ie_len); + + ptr += sizeof(*tlv); + ptr += ie_len; + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv start scan\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_stop_scan(struct ath10k *ar, + const struct wmi_stop_scan_arg *arg) +{ + struct wmi_stop_scan_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + u32 scan_id; + u32 req_id; + + if (arg->req_id > 0xFFF) + return ERR_PTR(-EINVAL); + if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF) + return ERR_PTR(-EINVAL); + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + scan_id = arg->u.scan_id; + scan_id |= WMI_HOST_SCAN_REQ_ID_PREFIX; + + req_id = arg->req_id; + req_id |= WMI_HOST_SCAN_REQUESTOR_ID_PREFIX; + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STOP_SCAN_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->req_type = __cpu_to_le32(arg->req_type); + cmd->vdev_id = __cpu_to_le32(arg->u.vdev_id); + cmd->scan_id = __cpu_to_le32(scan_id); + cmd->scan_req_id = __cpu_to_le32(req_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv stop scan\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_create(struct ath10k *ar, + u32 vdev_id, + enum wmi_vdev_type vdev_type, + enum wmi_vdev_subtype vdev_subtype, + const u8 mac_addr[ETH_ALEN]) +{ + struct wmi_vdev_create_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_CREATE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->vdev_type = __cpu_to_le32(vdev_type); + cmd->vdev_subtype = __cpu_to_le32(vdev_subtype); + ether_addr_copy(cmd->vdev_macaddr.addr, mac_addr); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev create\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_delete(struct ath10k *ar, u32 vdev_id) +{ + struct wmi_vdev_delete_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_DELETE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev delete\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_start(struct ath10k *ar, + const struct wmi_vdev_start_request_arg *arg, + bool restart) +{ + struct wmi_tlv_vdev_start_cmd *cmd; + struct wmi_channel *ch; + struct wmi_p2p_noa_descriptor *noa; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len; + void *ptr; + u32 flags = 0; + + if (WARN_ON(arg->ssid && arg->ssid_len == 0)) + return ERR_PTR(-EINVAL); + if (WARN_ON(arg->hidden_ssid && !arg->ssid)) + return ERR_PTR(-EINVAL); + if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid))) + return ERR_PTR(-EINVAL); + + len = (sizeof(*tlv) + sizeof(*cmd)) + + (sizeof(*tlv) + sizeof(*ch)) + + (sizeof(*tlv) + 0); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + if (arg->hidden_ssid) + flags |= WMI_VDEV_START_HIDDEN_SSID; + if (arg->pmf_enabled) + flags |= WMI_VDEV_START_PMF_ENABLED; + + ptr = (void *)skb->data; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_START_REQUEST_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(arg->vdev_id); + cmd->bcn_intval = __cpu_to_le32(arg->bcn_intval); + cmd->dtim_period = __cpu_to_le32(arg->dtim_period); + cmd->flags = __cpu_to_le32(flags); + cmd->bcn_tx_rate = __cpu_to_le32(arg->bcn_tx_rate); + cmd->bcn_tx_power = __cpu_to_le32(arg->bcn_tx_power); + cmd->disable_hw_ack = __cpu_to_le32(arg->disable_hw_ack); + + if (arg->ssid) { + cmd->ssid.ssid_len = __cpu_to_le32(arg->ssid_len); + memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len); + } + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL); + tlv->len = __cpu_to_le16(sizeof(*ch)); + ch = (void *)tlv->value; + ath10k_wmi_put_wmi_channel(ch, &arg->channel); + + ptr += sizeof(*tlv); + ptr += sizeof(*ch); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); + tlv->len = 0; + noa = (void *)tlv->value; + + /* Note: This is a nested TLV containing: + * [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv].. + */ + + ptr += sizeof(*tlv); + ptr += 0; + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev start\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_stop(struct ath10k *ar, u32 vdev_id) +{ + struct wmi_vdev_stop_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_STOP_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev stop\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, + const u8 *bssid) + +{ + struct wmi_vdev_up_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_UP_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->vdev_assoc_id = __cpu_to_le32(aid); + ether_addr_copy(cmd->vdev_bssid.addr, bssid); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev up\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_down(struct ath10k *ar, u32 vdev_id) +{ + struct wmi_vdev_down_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_DOWN_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev down\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_set_param(struct ath10k *ar, u32 vdev_id, + u32 param_id, u32 param_value) +{ + struct wmi_vdev_set_param_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_SET_PARAM_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->param_id = __cpu_to_le32(param_id); + cmd->param_value = __cpu_to_le32(param_value); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev set param\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_install_key(struct ath10k *ar, + const struct wmi_vdev_install_key_arg *arg) +{ + struct wmi_vdev_install_key_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len; + void *ptr; + + if (arg->key_cipher == WMI_CIPHER_NONE && arg->key_data != NULL) + return ERR_PTR(-EINVAL); + if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL) + return ERR_PTR(-EINVAL); + + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + roundup(arg->key_len, sizeof(__le32)); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(arg->vdev_id); + cmd->key_idx = __cpu_to_le32(arg->key_idx); + cmd->key_flags = __cpu_to_le32(arg->key_flags); + cmd->key_cipher = __cpu_to_le32(arg->key_cipher); + cmd->key_len = __cpu_to_le32(arg->key_len); + cmd->key_txmic_len = __cpu_to_le32(arg->key_txmic_len); + cmd->key_rxmic_len = __cpu_to_le32(arg->key_rxmic_len); + + if (arg->macaddr) + ether_addr_copy(cmd->peer_macaddr.addr, arg->macaddr); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(roundup(arg->key_len, sizeof(__le32))); + if (arg->key_data) + memcpy(tlv->value, arg->key_data, arg->key_len); + + ptr += sizeof(*tlv); + ptr += roundup(arg->key_len, sizeof(__le32)); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev install key\n"); + return skb; +} + +static void *ath10k_wmi_tlv_put_uapsd_ac(struct ath10k *ar, void *ptr, + const struct wmi_sta_uapsd_auto_trig_arg *arg) +{ + struct wmi_sta_uapsd_auto_trig_param *ac; + struct wmi_tlv *tlv; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_PARAM); + tlv->len = __cpu_to_le16(sizeof(*ac)); + ac = (void *)tlv->value; + + ac->wmm_ac = __cpu_to_le32(arg->wmm_ac); + ac->user_priority = __cpu_to_le32(arg->user_priority); + ac->service_interval = __cpu_to_le32(arg->service_interval); + ac->suspend_interval = __cpu_to_le32(arg->suspend_interval); + ac->delay_interval = __cpu_to_le32(arg->delay_interval); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv vdev sta uapsd auto trigger ac %d prio %d svc int %d susp int %d delay int %d\n", + ac->wmm_ac, ac->user_priority, ac->service_interval, + ac->suspend_interval, ac->delay_interval); + + return ptr + sizeof(*tlv) + sizeof(*ac); +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_sta_uapsd(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN], + const struct wmi_sta_uapsd_auto_trig_arg *args, + u32 num_ac) +{ + struct wmi_sta_uapsd_auto_trig_cmd_fixed_param *cmd; + struct wmi_sta_uapsd_auto_trig_param *ac; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len; + size_t ac_tlv_len; + void *ptr; + int i; + + ac_tlv_len = num_ac * (sizeof(*tlv) + sizeof(*ac)); + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + ac_tlv_len; + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->num_ac = __cpu_to_le32(num_ac); + ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); + tlv->len = __cpu_to_le16(ac_tlv_len); + ac = (void *)tlv->value; + + ptr += sizeof(*tlv); + for (i = 0; i < num_ac; i++) + ptr = ath10k_wmi_tlv_put_uapsd_ac(ar, ptr, &args[i]); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev sta uapsd auto trigger\n"); + return skb; +} + +static void *ath10k_wmi_tlv_put_wmm(void *ptr, + const struct wmi_wmm_params_arg *arg) +{ + struct wmi_wmm_params *wmm; + struct wmi_tlv *tlv; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WMM_PARAMS); + tlv->len = __cpu_to_le16(sizeof(*wmm)); + wmm = (void *)tlv->value; + ath10k_wmi_set_wmm_param(wmm, arg); + + return ptr + sizeof(*tlv) + sizeof(*wmm); +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id, + const struct wmi_wmm_params_all_arg *arg) +{ + struct wmi_tlv_vdev_set_wmm_cmd *cmd; + struct wmi_wmm_params *wmm; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len; + void *ptr; + + len = (sizeof(*tlv) + sizeof(*cmd)) + + (4 * (sizeof(*tlv) + sizeof(*wmm))); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_SET_WMM_PARAMS_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_be); + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_bk); + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vi); + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vo); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev wmm conf\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_sta_keepalive(struct ath10k *ar, + const struct wmi_sta_keepalive_arg *arg) +{ + struct wmi_tlv_sta_keepalive_cmd *cmd; + struct wmi_sta_keepalive_arp_resp *arp; + struct sk_buff *skb; + struct wmi_tlv *tlv; + void *ptr; + size_t len; + + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + sizeof(*arp); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_KEEPALIVE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(arg->vdev_id); + cmd->enabled = __cpu_to_le32(arg->enabled); + cmd->method = __cpu_to_le32(arg->method); + cmd->interval = __cpu_to_le32(arg->interval); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_KEEPALVE_ARP_RESPONSE); + tlv->len = __cpu_to_le16(sizeof(*arp)); + arp = (void *)tlv->value; + + arp->src_ip4_addr = arg->src_ip4_addr; + arp->dest_ip4_addr = arg->dest_ip4_addr; + ether_addr_copy(arp->dest_mac_addr.addr, arg->dest_mac_addr); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv sta keepalive vdev %d enabled %d method %d inverval %d\n", + arg->vdev_id, arg->enabled, arg->method, arg->interval); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]) +{ + struct wmi_tlv_peer_create_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_CREATE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->peer_type = __cpu_to_le32(WMI_TLV_PEER_TYPE_DEFAULT); /* FIXME */ + ether_addr_copy(cmd->peer_addr.addr, peer_addr); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer create\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_peer_delete(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]) +{ + struct wmi_peer_delete_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_DELETE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer delete\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_peer_flush(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN], u32 tid_bitmap) +{ + struct wmi_peer_flush_tids_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_FLUSH_TIDS_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->peer_tid_bitmap = __cpu_to_le32(tid_bitmap); + ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer flush\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id, + const u8 *peer_addr, + enum wmi_peer_param param_id, + u32 param_value) +{ + struct wmi_peer_set_param_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_SET_PARAM_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->param_id = __cpu_to_le32(param_id); + cmd->param_value = __cpu_to_le32(param_value); + ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer set param\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_peer_assoc(struct ath10k *ar, + const struct wmi_peer_assoc_complete_arg *arg) +{ + struct wmi_tlv_peer_assoc_cmd *cmd; + struct wmi_vht_rate_set *vht_rate; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len, legacy_rate_len, ht_rate_len; + void *ptr; + + if (arg->peer_mpdu_density > 16) + return ERR_PTR(-EINVAL); + if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES) + return ERR_PTR(-EINVAL); + if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES) + return ERR_PTR(-EINVAL); + + legacy_rate_len = roundup(arg->peer_legacy_rates.num_rates, + sizeof(__le32)); + ht_rate_len = roundup(arg->peer_ht_rates.num_rates, sizeof(__le32)); + len = (sizeof(*tlv) + sizeof(*cmd)) + + (sizeof(*tlv) + legacy_rate_len) + + (sizeof(*tlv) + ht_rate_len) + + (sizeof(*tlv) + sizeof(*vht_rate)); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_ASSOC_COMPLETE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + + cmd->vdev_id = __cpu_to_le32(arg->vdev_id); + cmd->new_assoc = __cpu_to_le32(arg->peer_reassoc ? 0 : 1); + cmd->assoc_id = __cpu_to_le32(arg->peer_aid); + cmd->flags = __cpu_to_le32(arg->peer_flags); + cmd->caps = __cpu_to_le32(arg->peer_caps); + cmd->listen_intval = __cpu_to_le32(arg->peer_listen_intval); + cmd->ht_caps = __cpu_to_le32(arg->peer_ht_caps); + cmd->max_mpdu = __cpu_to_le32(arg->peer_max_mpdu); + cmd->mpdu_density = __cpu_to_le32(arg->peer_mpdu_density); + cmd->rate_caps = __cpu_to_le32(arg->peer_rate_caps); + cmd->nss = __cpu_to_le32(arg->peer_num_spatial_streams); + cmd->vht_caps = __cpu_to_le32(arg->peer_vht_caps); + cmd->phy_mode = __cpu_to_le32(arg->peer_phymode); + cmd->num_legacy_rates = __cpu_to_le32(arg->peer_legacy_rates.num_rates); + cmd->num_ht_rates = __cpu_to_le32(arg->peer_ht_rates.num_rates); + ether_addr_copy(cmd->mac_addr.addr, arg->addr); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(legacy_rate_len); + memcpy(tlv->value, arg->peer_legacy_rates.rates, + arg->peer_legacy_rates.num_rates); + + ptr += sizeof(*tlv); + ptr += legacy_rate_len; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(ht_rate_len); + memcpy(tlv->value, arg->peer_ht_rates.rates, + arg->peer_ht_rates.num_rates); + + ptr += sizeof(*tlv); + ptr += ht_rate_len; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VHT_RATE_SET); + tlv->len = __cpu_to_le16(sizeof(*vht_rate)); + vht_rate = (void *)tlv->value; + + vht_rate->rx_max_rate = __cpu_to_le32(arg->peer_vht_rates.rx_max_rate); + vht_rate->rx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.rx_mcs_set); + vht_rate->tx_max_rate = __cpu_to_le32(arg->peer_vht_rates.tx_max_rate); + vht_rate->tx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set); + + ptr += sizeof(*tlv); + ptr += sizeof(*vht_rate); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer assoc\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_ps_mode psmode) +{ + struct wmi_sta_powersave_mode_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_POWERSAVE_MODE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->sta_ps_mode = __cpu_to_le32(psmode); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set psmode\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_set_sta_ps(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_powersave_param param_id, + u32 param_value) +{ + struct wmi_sta_powersave_param_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_POWERSAVE_PARAM_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->param_id = __cpu_to_le32(param_id); + cmd->param_value = __cpu_to_le32(param_value); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set sta ps\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_set_ap_ps(struct ath10k *ar, u32 vdev_id, const u8 *mac, + enum wmi_ap_ps_peer_param param_id, u32 value) +{ + struct wmi_ap_ps_peer_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + if (!mac) + return ERR_PTR(-EINVAL); + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_AP_PS_PEER_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->param_id = __cpu_to_le32(param_id); + cmd->param_value = __cpu_to_le32(value); + ether_addr_copy(cmd->peer_macaddr.addr, mac); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv ap ps param\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_scan_chan_list(struct ath10k *ar, + const struct wmi_scan_chan_list_arg *arg) +{ + struct wmi_tlv_scan_chan_list_cmd *cmd; + struct wmi_channel *ci; + struct wmi_channel_arg *ch; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t chans_len, len; + int i; + void *ptr, *chans; + + chans_len = arg->n_channels * (sizeof(*tlv) + sizeof(*ci)); + len = (sizeof(*tlv) + sizeof(*cmd)) + + (sizeof(*tlv) + chans_len); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_SCAN_CHAN_LIST_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->num_scan_chans = __cpu_to_le32(arg->n_channels); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT); + tlv->len = __cpu_to_le16(chans_len); + chans = (void *)tlv->value; + + for (i = 0; i < arg->n_channels; i++) { + ch = &arg->channels[i]; + + tlv = chans; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL); + tlv->len = __cpu_to_le16(sizeof(*ci)); + ci = (void *)tlv->value; + + ath10k_wmi_put_wmi_channel(ci, ch); + + chans += sizeof(*tlv); + chans += sizeof(*ci); + } + + ptr += sizeof(*tlv); + ptr += chans_len; + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv scan chan list\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_beacon_dma(struct ath10k *ar, u32 vdev_id, + const void *bcn, size_t bcn_len, + u32 bcn_paddr, bool dtim_zero, + bool deliver_cab) + +{ + struct wmi_bcn_tx_ref_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + u16 fc; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + hdr = (struct ieee80211_hdr *)bcn; + fc = le16_to_cpu(hdr->frame_control); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_SEND_FROM_HOST_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->data_len = __cpu_to_le32(bcn_len); + cmd->data_ptr = __cpu_to_le32(bcn_paddr); + cmd->msdu_id = 0; + cmd->frame_control = __cpu_to_le32(fc); + cmd->flags = 0; + + if (dtim_zero) + cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO); + + if (deliver_cab) + cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv beacon dma\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pdev_set_wmm(struct ath10k *ar, + const struct wmi_wmm_params_all_arg *arg) +{ + struct wmi_tlv_pdev_set_wmm_cmd *cmd; + struct wmi_wmm_params *wmm; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len; + void *ptr; + + len = (sizeof(*tlv) + sizeof(*cmd)) + + (4 * (sizeof(*tlv) + sizeof(*wmm))); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_WMM_PARAMS_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + + /* nothing to set here */ + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_be); + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_bk); + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vi); + ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vo); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set wmm\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, + enum wmi_stats_id stats_id) +{ + struct wmi_request_stats_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->stats_id = __cpu_to_le32(stats_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv request stats\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_force_fw_hang(struct ath10k *ar, + enum wmi_force_fw_hang_type type, + u32 delay_ms) +{ + struct wmi_force_fw_hang_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_FORCE_FW_HANG_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->type = __cpu_to_le32(type); + cmd->delay_ms = __cpu_to_le32(delay_ms); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv force fw hang\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable, + u32 log_level) { + struct wmi_tlv_dbglog_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len, bmap_len; + u32 value; + void *ptr; + + if (module_enable) { + value = WMI_TLV_DBGLOG_LOG_LEVEL_VALUE( + module_enable, + WMI_TLV_DBGLOG_LOG_LEVEL_VERBOSE); + } else { + value = WMI_TLV_DBGLOG_LOG_LEVEL_VALUE( + WMI_TLV_DBGLOG_ALL_MODULES, + WMI_TLV_DBGLOG_LOG_LEVEL_WARN); + } + + bmap_len = 0; + len = sizeof(*tlv) + sizeof(*cmd) + sizeof(*tlv) + bmap_len; + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_DEBUG_LOG_CONFIG_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->param = __cpu_to_le32(WMI_TLV_DBGLOG_PARAM_LOG_LEVEL); + cmd->value = __cpu_to_le32(value); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32); + tlv->len = __cpu_to_le16(bmap_len); + + /* nothing to do here */ + + ptr += sizeof(*tlv); + ptr += sizeof(bmap_len); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv dbglog value 0x%08x\n", value); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pktlog_enable(struct ath10k *ar, u32 filter) +{ + struct wmi_tlv_pktlog_enable *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + size_t len; + + len = sizeof(*tlv) + sizeof(*cmd); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_ENABLE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->filter = __cpu_to_le32(filter); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pktlog enable filter 0x%08x\n", + filter); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_pktlog_disable(struct ath10k *ar) +{ + struct wmi_tlv_pktlog_disable *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + size_t len; + + len = sizeof(*tlv) + sizeof(*cmd); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_DISABLE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pktlog disable\n"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_bcn_tmpl(struct ath10k *ar, u32 vdev_id, + u32 tim_ie_offset, struct sk_buff *bcn, + u32 prb_caps, u32 prb_erp, void *prb_ies, + size_t prb_ies_len) +{ + struct wmi_tlv_bcn_tmpl_cmd *cmd; + struct wmi_tlv_bcn_prb_info *info; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + size_t len; + + if (WARN_ON(prb_ies_len > 0 && !prb_ies)) + return ERR_PTR(-EINVAL); + + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + sizeof(*info) + prb_ies_len + + sizeof(*tlv) + roundup(bcn->len, 4); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_TMPL_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->tim_ie_offset = __cpu_to_le32(tim_ie_offset); + cmd->buf_len = __cpu_to_le32(bcn->len); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + /* FIXME: prb_ies_len should be probably aligned to 4byte boundary but + * then it is then impossible to pass original ie len. + * This chunk is not used yet so if setting probe resp template yields + * problems with beaconing or crashes firmware look here. + */ + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_PRB_INFO); + tlv->len = __cpu_to_le16(sizeof(*info) + prb_ies_len); + info = (void *)tlv->value; + info->caps = __cpu_to_le32(prb_caps); + info->erp = __cpu_to_le32(prb_erp); + memcpy(info->ies, prb_ies, prb_ies_len); + + ptr += sizeof(*tlv); + ptr += sizeof(*info); + ptr += prb_ies_len; + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(roundup(bcn->len, 4)); + memcpy(tlv->value, bcn->data, bcn->len); + + /* FIXME: Adjust TSF? */ + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv bcn tmpl vdev_id %i\n", + vdev_id); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_prb_tmpl(struct ath10k *ar, u32 vdev_id, + struct sk_buff *prb) +{ + struct wmi_tlv_prb_tmpl_cmd *cmd; + struct wmi_tlv_bcn_prb_info *info; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + size_t len; + + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + sizeof(*info) + + sizeof(*tlv) + roundup(prb->len, 4); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PRB_TMPL_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->buf_len = __cpu_to_le32(prb->len); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_PRB_INFO); + tlv->len = __cpu_to_le16(sizeof(*info)); + info = (void *)tlv->value; + info->caps = 0; + info->erp = 0; + + ptr += sizeof(*tlv); + ptr += sizeof(*info); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(roundup(prb->len, 4)); + memcpy(tlv->value, prb->data, prb->len); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv prb tmpl vdev_id %i\n", + vdev_id); + return skb; +} + +static struct sk_buff * +ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id, + const u8 *p2p_ie) +{ + struct wmi_tlv_p2p_go_bcn_ie *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + size_t len; + + len = sizeof(*tlv) + sizeof(*cmd) + + sizeof(*tlv) + roundup(p2p_ie[1] + 2, 4); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ptr = (void *)skb->data; + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_P2P_GO_SET_BEACON_IE); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->ie_len = __cpu_to_le32(p2p_ie[1] + 2); + + ptr += sizeof(*tlv); + ptr += sizeof(*cmd); + + tlv = ptr; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE); + tlv->len = __cpu_to_le16(roundup(p2p_ie[1] + 2, 4)); + memcpy(tlv->value, p2p_ie, p2p_ie[1] + 2); + + ptr += sizeof(*tlv); + ptr += roundup(p2p_ie[1] + 2, 4); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv p2p go bcn ie for vdev %i\n", + vdev_id); + return skb; +} + +/****************/ +/* TLV mappings */ +/****************/ + +static struct wmi_cmd_map wmi_tlv_cmd_map = { + .init_cmdid = WMI_TLV_INIT_CMDID, + .start_scan_cmdid = WMI_TLV_START_SCAN_CMDID, + .stop_scan_cmdid = WMI_TLV_STOP_SCAN_CMDID, + .scan_chan_list_cmdid = WMI_TLV_SCAN_CHAN_LIST_CMDID, + .scan_sch_prio_tbl_cmdid = WMI_TLV_SCAN_SCH_PRIO_TBL_CMDID, + .pdev_set_regdomain_cmdid = WMI_TLV_PDEV_SET_REGDOMAIN_CMDID, + .pdev_set_channel_cmdid = WMI_TLV_PDEV_SET_CHANNEL_CMDID, + .pdev_set_param_cmdid = WMI_TLV_PDEV_SET_PARAM_CMDID, + .pdev_pktlog_enable_cmdid = WMI_TLV_PDEV_PKTLOG_ENABLE_CMDID, + .pdev_pktlog_disable_cmdid = WMI_TLV_PDEV_PKTLOG_DISABLE_CMDID, + .pdev_set_wmm_params_cmdid = WMI_TLV_PDEV_SET_WMM_PARAMS_CMDID, + .pdev_set_ht_cap_ie_cmdid = WMI_TLV_PDEV_SET_HT_CAP_IE_CMDID, + .pdev_set_vht_cap_ie_cmdid = WMI_TLV_PDEV_SET_VHT_CAP_IE_CMDID, + .pdev_set_dscp_tid_map_cmdid = WMI_TLV_PDEV_SET_DSCP_TID_MAP_CMDID, + .pdev_set_quiet_mode_cmdid = WMI_TLV_PDEV_SET_QUIET_MODE_CMDID, + .pdev_green_ap_ps_enable_cmdid = WMI_TLV_PDEV_GREEN_AP_PS_ENABLE_CMDID, + .pdev_get_tpc_config_cmdid = WMI_TLV_PDEV_GET_TPC_CONFIG_CMDID, + .pdev_set_base_macaddr_cmdid = WMI_TLV_PDEV_SET_BASE_MACADDR_CMDID, + .vdev_create_cmdid = WMI_TLV_VDEV_CREATE_CMDID, + .vdev_delete_cmdid = WMI_TLV_VDEV_DELETE_CMDID, + .vdev_start_request_cmdid = WMI_TLV_VDEV_START_REQUEST_CMDID, + .vdev_restart_request_cmdid = WMI_TLV_VDEV_RESTART_REQUEST_CMDID, + .vdev_up_cmdid = WMI_TLV_VDEV_UP_CMDID, + .vdev_stop_cmdid = WMI_TLV_VDEV_STOP_CMDID, + .vdev_down_cmdid = WMI_TLV_VDEV_DOWN_CMDID, + .vdev_set_param_cmdid = WMI_TLV_VDEV_SET_PARAM_CMDID, + .vdev_install_key_cmdid = WMI_TLV_VDEV_INSTALL_KEY_CMDID, + .peer_create_cmdid = WMI_TLV_PEER_CREATE_CMDID, + .peer_delete_cmdid = WMI_TLV_PEER_DELETE_CMDID, + .peer_flush_tids_cmdid = WMI_TLV_PEER_FLUSH_TIDS_CMDID, + .peer_set_param_cmdid = WMI_TLV_PEER_SET_PARAM_CMDID, + .peer_assoc_cmdid = WMI_TLV_PEER_ASSOC_CMDID, + .peer_add_wds_entry_cmdid = WMI_TLV_PEER_ADD_WDS_ENTRY_CMDID, + .peer_remove_wds_entry_cmdid = WMI_TLV_PEER_REMOVE_WDS_ENTRY_CMDID, + .peer_mcast_group_cmdid = WMI_TLV_PEER_MCAST_GROUP_CMDID, + .bcn_tx_cmdid = WMI_TLV_BCN_TX_CMDID, + .pdev_send_bcn_cmdid = WMI_TLV_PDEV_SEND_BCN_CMDID, + .bcn_tmpl_cmdid = WMI_TLV_BCN_TMPL_CMDID, + .bcn_filter_rx_cmdid = WMI_TLV_BCN_FILTER_RX_CMDID, + .prb_req_filter_rx_cmdid = WMI_TLV_PRB_REQ_FILTER_RX_CMDID, + .mgmt_tx_cmdid = WMI_TLV_MGMT_TX_CMDID, + .prb_tmpl_cmdid = WMI_TLV_PRB_TMPL_CMDID, + .addba_clear_resp_cmdid = WMI_TLV_ADDBA_CLEAR_RESP_CMDID, + .addba_send_cmdid = WMI_TLV_ADDBA_SEND_CMDID, + .addba_status_cmdid = WMI_TLV_ADDBA_STATUS_CMDID, + .delba_send_cmdid = WMI_TLV_DELBA_SEND_CMDID, + .addba_set_resp_cmdid = WMI_TLV_ADDBA_SET_RESP_CMDID, + .send_singleamsdu_cmdid = WMI_TLV_SEND_SINGLEAMSDU_CMDID, + .sta_powersave_mode_cmdid = WMI_TLV_STA_POWERSAVE_MODE_CMDID, + .sta_powersave_param_cmdid = WMI_TLV_STA_POWERSAVE_PARAM_CMDID, + .sta_mimo_ps_mode_cmdid = WMI_TLV_STA_MIMO_PS_MODE_CMDID, + .pdev_dfs_enable_cmdid = WMI_TLV_PDEV_DFS_ENABLE_CMDID, + .pdev_dfs_disable_cmdid = WMI_TLV_PDEV_DFS_DISABLE_CMDID, + .roam_scan_mode = WMI_TLV_ROAM_SCAN_MODE, + .roam_scan_rssi_threshold = WMI_TLV_ROAM_SCAN_RSSI_THRESHOLD, + .roam_scan_period = WMI_TLV_ROAM_SCAN_PERIOD, + .roam_scan_rssi_change_threshold = + WMI_TLV_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + .roam_ap_profile = WMI_TLV_ROAM_AP_PROFILE, + .ofl_scan_add_ap_profile = WMI_TLV_ROAM_AP_PROFILE, + .ofl_scan_remove_ap_profile = WMI_TLV_OFL_SCAN_REMOVE_AP_PROFILE, + .ofl_scan_period = WMI_TLV_OFL_SCAN_PERIOD, + .p2p_dev_set_device_info = WMI_TLV_P2P_DEV_SET_DEVICE_INFO, + .p2p_dev_set_discoverability = WMI_TLV_P2P_DEV_SET_DISCOVERABILITY, + .p2p_go_set_beacon_ie = WMI_TLV_P2P_GO_SET_BEACON_IE, + .p2p_go_set_probe_resp_ie = WMI_TLV_P2P_GO_SET_PROBE_RESP_IE, + .p2p_set_vendor_ie_data_cmdid = WMI_TLV_P2P_SET_VENDOR_IE_DATA_CMDID, + .ap_ps_peer_param_cmdid = WMI_TLV_AP_PS_PEER_PARAM_CMDID, + .ap_ps_peer_uapsd_coex_cmdid = WMI_TLV_AP_PS_PEER_UAPSD_COEX_CMDID, + .peer_rate_retry_sched_cmdid = WMI_TLV_PEER_RATE_RETRY_SCHED_CMDID, + .wlan_profile_trigger_cmdid = WMI_TLV_WLAN_PROFILE_TRIGGER_CMDID, + .wlan_profile_set_hist_intvl_cmdid = + WMI_TLV_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + .wlan_profile_get_profile_data_cmdid = + WMI_TLV_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + .wlan_profile_enable_profile_id_cmdid = + WMI_TLV_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + .wlan_profile_list_profile_id_cmdid = + WMI_TLV_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + .pdev_suspend_cmdid = WMI_TLV_PDEV_SUSPEND_CMDID, + .pdev_resume_cmdid = WMI_TLV_PDEV_RESUME_CMDID, + .add_bcn_filter_cmdid = WMI_TLV_ADD_BCN_FILTER_CMDID, + .rmv_bcn_filter_cmdid = WMI_TLV_RMV_BCN_FILTER_CMDID, + .wow_add_wake_pattern_cmdid = WMI_TLV_WOW_ADD_WAKE_PATTERN_CMDID, + .wow_del_wake_pattern_cmdid = WMI_TLV_WOW_DEL_WAKE_PATTERN_CMDID, + .wow_enable_disable_wake_event_cmdid = + WMI_TLV_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + .wow_enable_cmdid = WMI_TLV_WOW_ENABLE_CMDID, + .wow_hostwakeup_from_sleep_cmdid = + WMI_TLV_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + .rtt_measreq_cmdid = WMI_TLV_RTT_MEASREQ_CMDID, + .rtt_tsf_cmdid = WMI_TLV_RTT_TSF_CMDID, + .vdev_spectral_scan_configure_cmdid = WMI_TLV_SPECTRAL_SCAN_CONF_CMDID, + .vdev_spectral_scan_enable_cmdid = WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID, + .request_stats_cmdid = WMI_TLV_REQUEST_STATS_CMDID, + .set_arp_ns_offload_cmdid = WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID, + .network_list_offload_config_cmdid = + WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID, + .gtk_offload_cmdid = WMI_TLV_GTK_OFFLOAD_CMDID, + .csa_offload_enable_cmdid = WMI_TLV_CSA_OFFLOAD_ENABLE_CMDID, + .csa_offload_chanswitch_cmdid = WMI_TLV_CSA_OFFLOAD_CHANSWITCH_CMDID, + .chatter_set_mode_cmdid = WMI_TLV_CHATTER_SET_MODE_CMDID, + .peer_tid_addba_cmdid = WMI_TLV_PEER_TID_ADDBA_CMDID, + .peer_tid_delba_cmdid = WMI_TLV_PEER_TID_DELBA_CMDID, + .sta_dtim_ps_method_cmdid = WMI_TLV_STA_DTIM_PS_METHOD_CMDID, + .sta_uapsd_auto_trig_cmdid = WMI_TLV_STA_UAPSD_AUTO_TRIG_CMDID, + .sta_keepalive_cmd = WMI_TLV_STA_KEEPALIVE_CMDID, + .echo_cmdid = WMI_TLV_ECHO_CMDID, + .pdev_utf_cmdid = WMI_TLV_PDEV_UTF_CMDID, + .dbglog_cfg_cmdid = WMI_TLV_DBGLOG_CFG_CMDID, + .pdev_qvit_cmdid = WMI_TLV_PDEV_QVIT_CMDID, + .pdev_ftm_intg_cmdid = WMI_TLV_PDEV_FTM_INTG_CMDID, + .vdev_set_keepalive_cmdid = WMI_TLV_VDEV_SET_KEEPALIVE_CMDID, + .vdev_get_keepalive_cmdid = WMI_TLV_VDEV_GET_KEEPALIVE_CMDID, + .force_fw_hang_cmdid = WMI_TLV_FORCE_FW_HANG_CMDID, + .gpio_config_cmdid = WMI_TLV_GPIO_CONFIG_CMDID, + .gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID, + .pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED, + .vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID, +}; + +static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { + .tx_chain_mask = WMI_TLV_PDEV_PARAM_TX_CHAIN_MASK, + .rx_chain_mask = WMI_TLV_PDEV_PARAM_RX_CHAIN_MASK, + .txpower_limit2g = WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT2G, + .txpower_limit5g = WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT5G, + .txpower_scale = WMI_TLV_PDEV_PARAM_TXPOWER_SCALE, + .beacon_gen_mode = WMI_TLV_PDEV_PARAM_BEACON_GEN_MODE, + .beacon_tx_mode = WMI_TLV_PDEV_PARAM_BEACON_TX_MODE, + .resmgr_offchan_mode = WMI_TLV_PDEV_PARAM_RESMGR_OFFCHAN_MODE, + .protection_mode = WMI_TLV_PDEV_PARAM_PROTECTION_MODE, + .dynamic_bw = WMI_TLV_PDEV_PARAM_DYNAMIC_BW, + .non_agg_sw_retry_th = WMI_TLV_PDEV_PARAM_NON_AGG_SW_RETRY_TH, + .agg_sw_retry_th = WMI_TLV_PDEV_PARAM_AGG_SW_RETRY_TH, + .sta_kickout_th = WMI_TLV_PDEV_PARAM_STA_KICKOUT_TH, + .ac_aggrsize_scaling = WMI_TLV_PDEV_PARAM_AC_AGGRSIZE_SCALING, + .ltr_enable = WMI_TLV_PDEV_PARAM_LTR_ENABLE, + .ltr_ac_latency_be = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BE, + .ltr_ac_latency_bk = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BK, + .ltr_ac_latency_vi = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VI, + .ltr_ac_latency_vo = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VO, + .ltr_ac_latency_timeout = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, + .ltr_sleep_override = WMI_TLV_PDEV_PARAM_LTR_SLEEP_OVERRIDE, + .ltr_rx_override = WMI_TLV_PDEV_PARAM_LTR_RX_OVERRIDE, + .ltr_tx_activity_timeout = WMI_TLV_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + .l1ss_enable = WMI_TLV_PDEV_PARAM_L1SS_ENABLE, + .dsleep_enable = WMI_TLV_PDEV_PARAM_DSLEEP_ENABLE, + .pcielp_txbuf_flush = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_FLUSH, + .pcielp_txbuf_watermark = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, + .pcielp_txbuf_tmo_en = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, + .pcielp_txbuf_tmo_value = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, + .pdev_stats_update_period = WMI_TLV_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, + .vdev_stats_update_period = WMI_TLV_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, + .peer_stats_update_period = WMI_TLV_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, + .bcnflt_stats_update_period = + WMI_TLV_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, + .pmf_qos = WMI_TLV_PDEV_PARAM_PMF_QOS, + .arp_ac_override = WMI_TLV_PDEV_PARAM_ARP_AC_OVERRIDE, + .dcs = WMI_TLV_PDEV_PARAM_DCS, + .ani_enable = WMI_TLV_PDEV_PARAM_ANI_ENABLE, + .ani_poll_period = WMI_TLV_PDEV_PARAM_ANI_POLL_PERIOD, + .ani_listen_period = WMI_TLV_PDEV_PARAM_ANI_LISTEN_PERIOD, + .ani_ofdm_level = WMI_TLV_PDEV_PARAM_ANI_OFDM_LEVEL, + .ani_cck_level = WMI_TLV_PDEV_PARAM_ANI_CCK_LEVEL, + .dyntxchain = WMI_TLV_PDEV_PARAM_DYNTXCHAIN, + .proxy_sta = WMI_TLV_PDEV_PARAM_PROXY_STA, + .idle_ps_config = WMI_TLV_PDEV_PARAM_IDLE_PS_CONFIG, + .power_gating_sleep = WMI_TLV_PDEV_PARAM_POWER_GATING_SLEEP, + .fast_channel_reset = WMI_TLV_PDEV_PARAM_UNSUPPORTED, + .burst_dur = WMI_TLV_PDEV_PARAM_BURST_DUR, + .burst_enable = WMI_TLV_PDEV_PARAM_BURST_ENABLE, + .cal_period = WMI_PDEV_PARAM_UNSUPPORTED, +}; + +static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { + .rts_threshold = WMI_TLV_VDEV_PARAM_RTS_THRESHOLD, + .fragmentation_threshold = WMI_TLV_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + .beacon_interval = WMI_TLV_VDEV_PARAM_BEACON_INTERVAL, + .listen_interval = WMI_TLV_VDEV_PARAM_LISTEN_INTERVAL, + .multicast_rate = WMI_TLV_VDEV_PARAM_MULTICAST_RATE, + .mgmt_tx_rate = WMI_TLV_VDEV_PARAM_MGMT_TX_RATE, + .slot_time = WMI_TLV_VDEV_PARAM_SLOT_TIME, + .preamble = WMI_TLV_VDEV_PARAM_PREAMBLE, + .swba_time = WMI_TLV_VDEV_PARAM_SWBA_TIME, + .wmi_vdev_stats_update_period = WMI_TLV_VDEV_STATS_UPDATE_PERIOD, + .wmi_vdev_pwrsave_ageout_time = WMI_TLV_VDEV_PWRSAVE_AGEOUT_TIME, + .wmi_vdev_host_swba_interval = WMI_TLV_VDEV_HOST_SWBA_INTERVAL, + .dtim_period = WMI_TLV_VDEV_PARAM_DTIM_PERIOD, + .wmi_vdev_oc_scheduler_air_time_limit = + WMI_TLV_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, + .wds = WMI_TLV_VDEV_PARAM_WDS, + .atim_window = WMI_TLV_VDEV_PARAM_ATIM_WINDOW, + .bmiss_count_max = WMI_TLV_VDEV_PARAM_BMISS_COUNT_MAX, + .bmiss_first_bcnt = WMI_TLV_VDEV_PARAM_BMISS_FIRST_BCNT, + .bmiss_final_bcnt = WMI_TLV_VDEV_PARAM_BMISS_FINAL_BCNT, + .feature_wmm = WMI_TLV_VDEV_PARAM_FEATURE_WMM, + .chwidth = WMI_TLV_VDEV_PARAM_CHWIDTH, + .chextoffset = WMI_TLV_VDEV_PARAM_CHEXTOFFSET, + .disable_htprotection = WMI_TLV_VDEV_PARAM_DISABLE_HTPROTECTION, + .sta_quickkickout = WMI_TLV_VDEV_PARAM_STA_QUICKKICKOUT, + .mgmt_rate = WMI_TLV_VDEV_PARAM_MGMT_RATE, + .protection_mode = WMI_TLV_VDEV_PARAM_PROTECTION_MODE, + .fixed_rate = WMI_TLV_VDEV_PARAM_FIXED_RATE, + .sgi = WMI_TLV_VDEV_PARAM_SGI, + .ldpc = WMI_TLV_VDEV_PARAM_LDPC, + .tx_stbc = WMI_TLV_VDEV_PARAM_TX_STBC, + .rx_stbc = WMI_TLV_VDEV_PARAM_RX_STBC, + .intra_bss_fwd = WMI_TLV_VDEV_PARAM_INTRA_BSS_FWD, + .def_keyid = WMI_TLV_VDEV_PARAM_DEF_KEYID, + .nss = WMI_TLV_VDEV_PARAM_NSS, + .bcast_data_rate = WMI_TLV_VDEV_PARAM_BCAST_DATA_RATE, + .mcast_data_rate = WMI_TLV_VDEV_PARAM_MCAST_DATA_RATE, + .mcast_indicate = WMI_TLV_VDEV_PARAM_MCAST_INDICATE, + .dhcp_indicate = WMI_TLV_VDEV_PARAM_DHCP_INDICATE, + .unknown_dest_indicate = WMI_TLV_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + .ap_keepalive_min_idle_inactive_time_secs = + WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + .ap_keepalive_max_idle_inactive_time_secs = + WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + .ap_keepalive_max_unresponsive_time_secs = + WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + .ap_enable_nawds = WMI_TLV_VDEV_PARAM_AP_ENABLE_NAWDS, + .mcast2ucast_set = WMI_TLV_VDEV_PARAM_UNSUPPORTED, + .enable_rtscts = WMI_TLV_VDEV_PARAM_ENABLE_RTSCTS, + .txbf = WMI_TLV_VDEV_PARAM_TXBF, + .packet_powersave = WMI_TLV_VDEV_PARAM_PACKET_POWERSAVE, + .drop_unencry = WMI_TLV_VDEV_PARAM_DROP_UNENCRY, + .tx_encap_type = WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE, + .ap_detect_out_of_sync_sleeping_sta_time_secs = + WMI_TLV_VDEV_PARAM_UNSUPPORTED, +}; + +static const struct wmi_ops wmi_tlv_ops = { + .rx = ath10k_wmi_tlv_op_rx, + .map_svc = wmi_tlv_svc_map, + + .pull_scan = ath10k_wmi_tlv_op_pull_scan_ev, + .pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_tlv_op_pull_ch_info_ev, + .pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev, + .pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev, + .pull_swba = ath10k_wmi_tlv_op_pull_swba_ev, + .pull_phyerr = ath10k_wmi_tlv_op_pull_phyerr_ev, + .pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev, + .pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev, + .pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats, + + .gen_pdev_suspend = ath10k_wmi_tlv_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_tlv_op_gen_pdev_resume, + .gen_pdev_set_rd = ath10k_wmi_tlv_op_gen_pdev_set_rd, + .gen_pdev_set_param = ath10k_wmi_tlv_op_gen_pdev_set_param, + .gen_init = ath10k_wmi_tlv_op_gen_init, + .gen_start_scan = ath10k_wmi_tlv_op_gen_start_scan, + .gen_stop_scan = ath10k_wmi_tlv_op_gen_stop_scan, + .gen_vdev_create = ath10k_wmi_tlv_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_tlv_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_tlv_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_tlv_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_tlv_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_tlv_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_tlv_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_tlv_op_gen_vdev_install_key, + .gen_vdev_wmm_conf = ath10k_wmi_tlv_op_gen_vdev_wmm_conf, + .gen_peer_create = ath10k_wmi_tlv_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_tlv_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_tlv_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_tlv_op_gen_peer_set_param, + .gen_peer_assoc = ath10k_wmi_tlv_op_gen_peer_assoc, + .gen_set_psmode = ath10k_wmi_tlv_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_tlv_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_tlv_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_tlv_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_tlv_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm, + .gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats, + .gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang, + /* .gen_mgmt_tx = not implemented; HTT is used */ + .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable, + .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable, + /* .gen_pdev_set_quiet_mode not implemented */ + /* .gen_pdev_get_temperature not implemented */ + /* .gen_addba_clear_resp not implemented */ + /* .gen_addba_send not implemented */ + /* .gen_addba_set_resp not implemented */ + /* .gen_delba_send not implemented */ + .gen_bcn_tmpl = ath10k_wmi_tlv_op_gen_bcn_tmpl, + .gen_prb_tmpl = ath10k_wmi_tlv_op_gen_prb_tmpl, + .gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie, + .gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd, + .gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive, +}; + +/************/ +/* TLV init */ +/************/ + +void ath10k_wmi_tlv_attach(struct ath10k *ar) +{ + ar->wmi.cmd = &wmi_tlv_cmd_map; + ar->wmi.vdev_param = &wmi_tlv_vdev_param_map; + ar->wmi.pdev_param = &wmi_tlv_pdev_param_map; + ar->wmi.ops = &wmi_tlv_ops; +} diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h new file mode 100644 index 000000000000..de68fe76eae6 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -0,0 +1,1444 @@ +/* + * Copyright (c) 2005-2011 Atheros Communications Inc. + * Copyright (c) 2011-2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _WMI_TLV_H +#define _WMI_TLV_H + +#define WMI_TLV_CMD(grp_id) (((grp_id) << 12) | 0x1) +#define WMI_TLV_EV(grp_id) (((grp_id) << 12) | 0x1) +#define WMI_TLV_CMD_UNSUPPORTED 0 +#define WMI_TLV_PDEV_PARAM_UNSUPPORTED 0 +#define WMI_TLV_VDEV_PARAM_UNSUPPORTED 0 + +enum wmi_tlv_grp_id { + WMI_TLV_GRP_START = 0x3, + WMI_TLV_GRP_SCAN = WMI_TLV_GRP_START, + WMI_TLV_GRP_PDEV, + WMI_TLV_GRP_VDEV, + WMI_TLV_GRP_PEER, + WMI_TLV_GRP_MGMT, + WMI_TLV_GRP_BA_NEG, + WMI_TLV_GRP_STA_PS, + WMI_TLV_GRP_DFS, + WMI_TLV_GRP_ROAM, + WMI_TLV_GRP_OFL_SCAN, + WMI_TLV_GRP_P2P, + WMI_TLV_GRP_AP_PS, + WMI_TLV_GRP_RATECTL, + WMI_TLV_GRP_PROFILE, + WMI_TLV_GRP_SUSPEND, + WMI_TLV_GRP_BCN_FILTER, + WMI_TLV_GRP_WOW, + WMI_TLV_GRP_RTT, + WMI_TLV_GRP_SPECTRAL, + WMI_TLV_GRP_STATS, + WMI_TLV_GRP_ARP_NS_OFL, + WMI_TLV_GRP_NLO_OFL, + WMI_TLV_GRP_GTK_OFL, + WMI_TLV_GRP_CSA_OFL, + WMI_TLV_GRP_CHATTER, + WMI_TLV_GRP_TID_ADDBA, + WMI_TLV_GRP_MISC, + WMI_TLV_GRP_GPIO, + WMI_TLV_GRP_FWTEST, + WMI_TLV_GRP_TDLS, + WMI_TLV_GRP_RESMGR, + WMI_TLV_GRP_STA_SMPS, + WMI_TLV_GRP_WLAN_HB, + WMI_TLV_GRP_RMC, + WMI_TLV_GRP_MHF_OFL, + WMI_TLV_GRP_LOCATION_SCAN, + WMI_TLV_GRP_OEM, + WMI_TLV_GRP_NAN, + WMI_TLV_GRP_COEX, + WMI_TLV_GRP_OBSS_OFL, + WMI_TLV_GRP_LPI, + WMI_TLV_GRP_EXTSCAN, + WMI_TLV_GRP_DHCP_OFL, + WMI_TLV_GRP_IPA, + WMI_TLV_GRP_MDNS_OFL, + WMI_TLV_GRP_SAP_OFL, +}; + +enum wmi_tlv_cmd_id { + WMI_TLV_INIT_CMDID = 0x1, + WMI_TLV_START_SCAN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SCAN), + WMI_TLV_STOP_SCAN_CMDID, + WMI_TLV_SCAN_CHAN_LIST_CMDID, + WMI_TLV_SCAN_SCH_PRIO_TBL_CMDID, + WMI_TLV_SCAN_UPDATE_REQUEST_CMDID, + WMI_TLV_SCAN_PROB_REQ_OUI_CMDID, + WMI_TLV_PDEV_SET_REGDOMAIN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PDEV), + WMI_TLV_PDEV_SET_CHANNEL_CMDID, + WMI_TLV_PDEV_SET_PARAM_CMDID, + WMI_TLV_PDEV_PKTLOG_ENABLE_CMDID, + WMI_TLV_PDEV_PKTLOG_DISABLE_CMDID, + WMI_TLV_PDEV_SET_WMM_PARAMS_CMDID, + WMI_TLV_PDEV_SET_HT_CAP_IE_CMDID, + WMI_TLV_PDEV_SET_VHT_CAP_IE_CMDID, + WMI_TLV_PDEV_SET_DSCP_TID_MAP_CMDID, + WMI_TLV_PDEV_SET_QUIET_MODE_CMDID, + WMI_TLV_PDEV_GREEN_AP_PS_ENABLE_CMDID, + WMI_TLV_PDEV_GET_TPC_CONFIG_CMDID, + WMI_TLV_PDEV_SET_BASE_MACADDR_CMDID, + WMI_TLV_PDEV_DUMP_CMDID, + WMI_TLV_PDEV_SET_LED_CONFIG_CMDID, + WMI_TLV_PDEV_GET_TEMPERATURE_CMDID, + WMI_TLV_PDEV_SET_LED_FLASHING_CMDID, + WMI_TLV_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_VDEV), + WMI_TLV_VDEV_DELETE_CMDID, + WMI_TLV_VDEV_START_REQUEST_CMDID, + WMI_TLV_VDEV_RESTART_REQUEST_CMDID, + WMI_TLV_VDEV_UP_CMDID, + WMI_TLV_VDEV_STOP_CMDID, + WMI_TLV_VDEV_DOWN_CMDID, + WMI_TLV_VDEV_SET_PARAM_CMDID, + WMI_TLV_VDEV_INSTALL_KEY_CMDID, + WMI_TLV_VDEV_WNM_SLEEPMODE_CMDID, + WMI_TLV_VDEV_WMM_ADDTS_CMDID, + WMI_TLV_VDEV_WMM_DELTS_CMDID, + WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID, + WMI_TLV_VDEV_SET_GTX_PARAMS_CMDID, + WMI_TLV_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID, + WMI_TLV_VDEV_PLMREQ_START_CMDID, + WMI_TLV_VDEV_PLMREQ_STOP_CMDID, + WMI_TLV_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PEER), + WMI_TLV_PEER_DELETE_CMDID, + WMI_TLV_PEER_FLUSH_TIDS_CMDID, + WMI_TLV_PEER_SET_PARAM_CMDID, + WMI_TLV_PEER_ASSOC_CMDID, + WMI_TLV_PEER_ADD_WDS_ENTRY_CMDID, + WMI_TLV_PEER_REMOVE_WDS_ENTRY_CMDID, + WMI_TLV_PEER_MCAST_GROUP_CMDID, + WMI_TLV_PEER_INFO_REQ_CMDID, + WMI_TLV_PEER_GET_ESTIMATED_LINKSPEED_CMDID, + WMI_TLV_BCN_TX_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MGMT), + WMI_TLV_PDEV_SEND_BCN_CMDID, + WMI_TLV_BCN_TMPL_CMDID, + WMI_TLV_BCN_FILTER_RX_CMDID, + WMI_TLV_PRB_REQ_FILTER_RX_CMDID, + WMI_TLV_MGMT_TX_CMDID, + WMI_TLV_PRB_TMPL_CMDID, + WMI_TLV_ADDBA_CLEAR_RESP_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BA_NEG), + WMI_TLV_ADDBA_SEND_CMDID, + WMI_TLV_ADDBA_STATUS_CMDID, + WMI_TLV_DELBA_SEND_CMDID, + WMI_TLV_ADDBA_SET_RESP_CMDID, + WMI_TLV_SEND_SINGLEAMSDU_CMDID, + WMI_TLV_STA_POWERSAVE_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STA_PS), + WMI_TLV_STA_POWERSAVE_PARAM_CMDID, + WMI_TLV_STA_MIMO_PS_MODE_CMDID, + WMI_TLV_PDEV_DFS_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_DFS), + WMI_TLV_PDEV_DFS_DISABLE_CMDID, + WMI_TLV_DFS_PHYERR_FILTER_ENA_CMDID, + WMI_TLV_DFS_PHYERR_FILTER_DIS_CMDID, + WMI_TLV_ROAM_SCAN_MODE = WMI_TLV_CMD(WMI_TLV_GRP_ROAM), + WMI_TLV_ROAM_SCAN_RSSI_THRESHOLD, + WMI_TLV_ROAM_SCAN_PERIOD, + WMI_TLV_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + WMI_TLV_ROAM_AP_PROFILE, + WMI_TLV_ROAM_CHAN_LIST, + WMI_TLV_ROAM_SCAN_CMD, + WMI_TLV_ROAM_SYNCH_COMPLETE, + WMI_TLV_ROAM_SET_RIC_REQUEST_CMDID, + WMI_TLV_ROAM_INVOKE_CMDID, + WMI_TLV_OFL_SCAN_ADD_AP_PROFILE = WMI_TLV_CMD(WMI_TLV_GRP_OFL_SCAN), + WMI_TLV_OFL_SCAN_REMOVE_AP_PROFILE, + WMI_TLV_OFL_SCAN_PERIOD, + WMI_TLV_P2P_DEV_SET_DEVICE_INFO = WMI_TLV_CMD(WMI_TLV_GRP_P2P), + WMI_TLV_P2P_DEV_SET_DISCOVERABILITY, + WMI_TLV_P2P_GO_SET_BEACON_IE, + WMI_TLV_P2P_GO_SET_PROBE_RESP_IE, + WMI_TLV_P2P_SET_VENDOR_IE_DATA_CMDID, + WMI_TLV_P2P_DISC_OFFLOAD_CONFIG_CMDID, + WMI_TLV_P2P_DISC_OFFLOAD_APPIE_CMDID, + WMI_TLV_P2P_DISC_OFFLOAD_PATTERN_CMDID, + WMI_TLV_P2P_SET_OPPPS_PARAM_CMDID, + WMI_TLV_AP_PS_PEER_PARAM_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_AP_PS), + WMI_TLV_AP_PS_PEER_UAPSD_COEX_CMDID, + WMI_TLV_PEER_RATE_RETRY_SCHED_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RATECTL), + WMI_TLV_WLAN_PROFILE_TRIGGER_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PROFILE), + WMI_TLV_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + WMI_TLV_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + WMI_TLV_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + WMI_TLV_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + WMI_TLV_PDEV_SUSPEND_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SUSPEND), + WMI_TLV_PDEV_RESUME_CMDID, + WMI_TLV_ADD_BCN_FILTER_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BCN_FILTER), + WMI_TLV_RMV_BCN_FILTER_CMDID, + WMI_TLV_WOW_ADD_WAKE_PATTERN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_WOW), + WMI_TLV_WOW_DEL_WAKE_PATTERN_CMDID, + WMI_TLV_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + WMI_TLV_WOW_ENABLE_CMDID, + WMI_TLV_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + WMI_TLV_WOW_ACER_IOAC_ADD_KEEPALIVE_CMDID, + WMI_TLV_WOW_ACER_IOAC_DEL_KEEPALIVE_CMDID, + WMI_TLV_WOW_ACER_IOAC_ADD_WAKE_PATTERN_CMDID, + WMI_TLV_WOW_ACER_IOAC_DEL_WAKE_PATTERN_CMDID, + WMI_TLV_D0_WOW_ENABLE_DISABLE_CMDID, + WMI_TLV_EXTWOW_ENABLE_CMDID, + WMI_TLV_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID, + WMI_TLV_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID, + WMI_TLV_RTT_MEASREQ_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RTT), + WMI_TLV_RTT_TSF_CMDID, + WMI_TLV_SPECTRAL_SCAN_CONF_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SPECTRAL), + WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID, + WMI_TLV_REQUEST_STATS_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STATS), + WMI_TLV_MCC_SCHED_TRAFFIC_STATS_CMDID, + WMI_TLV_REQUEST_STATS_EXT_CMDID, + WMI_TLV_REQUEST_LINK_STATS_CMDID, + WMI_TLV_START_LINK_STATS_CMDID, + WMI_TLV_CLEAR_LINK_STATS_CMDID, + WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_ARP_NS_OFL), + WMI_TLV_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID, + WMI_TLV_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID, + WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID = + WMI_TLV_CMD(WMI_TLV_GRP_NLO_OFL), + WMI_TLV_APFIND_CMDID, + WMI_TLV_GTK_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_GTK_OFL), + WMI_TLV_CSA_OFFLOAD_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_CSA_OFL), + WMI_TLV_CSA_OFFLOAD_CHANSWITCH_CMDID, + WMI_TLV_CHATTER_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_CHATTER), + WMI_TLV_CHATTER_ADD_COALESCING_FILTER_CMDID, + WMI_TLV_CHATTER_DELETE_COALESCING_FILTER_CMDID, + WMI_TLV_CHATTER_COALESCING_QUERY_CMDID, + WMI_TLV_PEER_TID_ADDBA_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_TID_ADDBA), + WMI_TLV_PEER_TID_DELBA_CMDID, + WMI_TLV_STA_DTIM_PS_METHOD_CMDID, + WMI_TLV_STA_UAPSD_AUTO_TRIG_CMDID, + WMI_TLV_STA_KEEPALIVE_CMDID, + WMI_TLV_BA_REQ_SSN_CMDID, + WMI_TLV_ECHO_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MISC), + WMI_TLV_PDEV_UTF_CMDID, + WMI_TLV_DBGLOG_CFG_CMDID, + WMI_TLV_PDEV_QVIT_CMDID, + WMI_TLV_PDEV_FTM_INTG_CMDID, + WMI_TLV_VDEV_SET_KEEPALIVE_CMDID, + WMI_TLV_VDEV_GET_KEEPALIVE_CMDID, + WMI_TLV_FORCE_FW_HANG_CMDID, + WMI_TLV_SET_MCASTBCAST_FILTER_CMDID, + WMI_TLV_THERMAL_MGMT_CMDID, + WMI_TLV_HOST_AUTO_SHUTDOWN_CFG_CMDID, + WMI_TLV_TPC_CHAINMASK_CONFIG_CMDID, + WMI_TLV_SET_ANTENNA_DIVERSITY_CMDID, + WMI_TLV_GPIO_CONFIG_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_GPIO), + WMI_TLV_GPIO_OUTPUT_CMDID, + WMI_TLV_TXBF_CMDID, + WMI_TLV_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID = + WMI_TLV_CMD(WMI_TLV_GRP_FWTEST), + WMI_TLV_FWTEST_P2P_SET_NOA_PARAM_CMDID, + WMI_TLV_UNIT_TEST_CMDID, + WMI_TLV_TDLS_SET_STATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_TDLS), + WMI_TLV_TDLS_PEER_UPDATE_CMDID, + WMI_TLV_TDLS_SET_OFFCHAN_MODE_CMDID, + WMI_TLV_RESMGR_ADAPTIVE_OCS_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RESMGR), + WMI_TLV_RESMGR_SET_CHAN_TIME_QUOTA_CMDID, + WMI_TLV_RESMGR_SET_CHAN_LATENCY_CMDID, + WMI_TLV_STA_SMPS_FORCE_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STA_SMPS), + WMI_TLV_STA_SMPS_PARAM_CMDID, + WMI_TLV_HB_SET_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_WLAN_HB), + WMI_TLV_HB_SET_TCP_PARAMS_CMDID, + WMI_TLV_HB_SET_TCP_PKT_FILTER_CMDID, + WMI_TLV_HB_SET_UDP_PARAMS_CMDID, + WMI_TLV_HB_SET_UDP_PKT_FILTER_CMDID, + WMI_TLV_RMC_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RMC), + WMI_TLV_RMC_SET_ACTION_PERIOD_CMDID, + WMI_TLV_RMC_CONFIG_CMDID, + WMI_TLV_MHF_OFFLOAD_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MHF_OFL), + WMI_TLV_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID, + WMI_TLV_BATCH_SCAN_ENABLE_CMDID = + WMI_TLV_CMD(WMI_TLV_GRP_LOCATION_SCAN), + WMI_TLV_BATCH_SCAN_DISABLE_CMDID, + WMI_TLV_BATCH_SCAN_TRIGGER_RESULT_CMDID, + WMI_TLV_OEM_REQ_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_OEM), + WMI_TLV_NAN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_NAN), + WMI_TLV_MODEM_POWER_STATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_COEX), + WMI_TLV_CHAN_AVOID_UPDATE_CMDID, + WMI_TLV_OBSS_SCAN_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_OBSS_OFL), + WMI_TLV_OBSS_SCAN_DISABLE_CMDID, + WMI_TLV_LPI_MGMT_SNOOPING_CONFIG_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_LPI), + WMI_TLV_LPI_START_SCAN_CMDID, + WMI_TLV_LPI_STOP_SCAN_CMDID, + WMI_TLV_EXTSCAN_START_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_EXTSCAN), + WMI_TLV_EXTSCAN_STOP_CMDID, + WMI_TLV_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID, + WMI_TLV_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID, + WMI_TLV_EXTSCAN_GET_CACHED_RESULTS_CMDID, + WMI_TLV_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID, + WMI_TLV_EXTSCAN_SET_CAPABILITIES_CMDID, + WMI_TLV_EXTSCAN_GET_CAPABILITIES_CMDID, + WMI_TLV_SET_DHCP_SERVER_OFFLOAD_CMDID = + WMI_TLV_CMD(WMI_TLV_GRP_DHCP_OFL), + WMI_TLV_IPA_OFFLOAD_ENABLE_DISABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_IPA), + WMI_TLV_MDNS_OFFLOAD_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MDNS_OFL), + WMI_TLV_MDNS_SET_FQDN_CMDID, + WMI_TLV_MDNS_SET_RESPONSE_CMDID, + WMI_TLV_MDNS_GET_STATS_CMDID, + WMI_TLV_SAP_OFL_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SAP_OFL), +}; + +enum wmi_tlv_event_id { + WMI_TLV_SERVICE_READY_EVENTID = 0x1, + WMI_TLV_READY_EVENTID, + WMI_TLV_SCAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SCAN), + WMI_TLV_PDEV_TPC_CONFIG_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PDEV), + WMI_TLV_CHAN_INFO_EVENTID, + WMI_TLV_PHYERR_EVENTID, + WMI_TLV_PDEV_DUMP_EVENTID, + WMI_TLV_TX_PAUSE_EVENTID, + WMI_TLV_DFS_RADAR_EVENTID, + WMI_TLV_PDEV_L1SS_TRACK_EVENTID, + WMI_TLV_PDEV_TEMPERATURE_EVENTID, + WMI_TLV_VDEV_START_RESP_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_VDEV), + WMI_TLV_VDEV_STOPPED_EVENTID, + WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID, + WMI_TLV_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID, + WMI_TLV_PEER_STA_KICKOUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PEER), + WMI_TLV_PEER_INFO_EVENTID, + WMI_TLV_PEER_TX_FAIL_CNT_THR_EVENTID, + WMI_TLV_PEER_ESTIMATED_LINKSPEED_EVENTID, + WMI_TLV_PEER_STATE_EVENTID, + WMI_TLV_MGMT_RX_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MGMT), + WMI_TLV_HOST_SWBA_EVENTID, + WMI_TLV_TBTTOFFSET_UPDATE_EVENTID, + WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID, + WMI_TLV_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID, + WMI_TLV_TX_DELBA_COMPLETE_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_BA_NEG), + WMI_TLV_TX_ADDBA_COMPLETE_EVENTID, + WMI_TLV_BA_RSP_SSN_EVENTID, + WMI_TLV_AGGR_STATE_TRIG_EVENTID, + WMI_TLV_ROAM_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_ROAM), + WMI_TLV_PROFILE_MATCH, + WMI_TLV_ROAM_SYNCH_EVENTID, + WMI_TLV_P2P_DISC_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_P2P), + WMI_TLV_P2P_NOA_EVENTID, + WMI_TLV_PDEV_RESUME_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SUSPEND), + WMI_TLV_WOW_WAKEUP_HOST_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_WOW), + WMI_TLV_D0_WOW_DISABLE_ACK_EVENTID, + WMI_TLV_RTT_MEASUREMENT_REPORT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_RTT), + WMI_TLV_TSF_MEASUREMENT_REPORT_EVENTID, + WMI_TLV_RTT_ERROR_REPORT_EVENTID, + WMI_TLV_STATS_EXT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_STATS), + WMI_TLV_IFACE_LINK_STATS_EVENTID, + WMI_TLV_PEER_LINK_STATS_EVENTID, + WMI_TLV_RADIO_LINK_STATS_EVENTID, + WMI_TLV_NLO_MATCH_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_NLO_OFL), + WMI_TLV_NLO_SCAN_COMPLETE_EVENTID, + WMI_TLV_APFIND_EVENTID, + WMI_TLV_GTK_OFFLOAD_STATUS_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_GTK_OFL), + WMI_TLV_GTK_REKEY_FAIL_EVENTID, + WMI_TLV_CSA_HANDLING_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_CSA_OFL), + WMI_TLV_CHATTER_PC_QUERY_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_CHATTER), + WMI_TLV_ECHO_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MISC), + WMI_TLV_PDEV_UTF_EVENTID, + WMI_TLV_DEBUG_MESG_EVENTID, + WMI_TLV_UPDATE_STATS_EVENTID, + WMI_TLV_DEBUG_PRINT_EVENTID, + WMI_TLV_DCS_INTERFERENCE_EVENTID, + WMI_TLV_PDEV_QVIT_EVENTID, + WMI_TLV_WLAN_PROFILE_DATA_EVENTID, + WMI_TLV_PDEV_FTM_INTG_EVENTID, + WMI_TLV_WLAN_FREQ_AVOID_EVENTID, + WMI_TLV_VDEV_GET_KEEPALIVE_EVENTID, + WMI_TLV_THERMAL_MGMT_EVENTID, + WMI_TLV_DIAG_DATA_CONTAINER_EVENTID, + WMI_TLV_HOST_AUTO_SHUTDOWN_EVENTID, + WMI_TLV_UPDATE_WHAL_MIB_STATS_EVENTID, + WMI_TLV_UPDATE_VDEV_RATE_STATS_EVENTID, + WMI_TLV_DIAG_EVENTID, + WMI_TLV_GPIO_INPUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_GPIO), + WMI_TLV_UPLOADH_EVENTID, + WMI_TLV_CAPTUREH_EVENTID, + WMI_TLV_RFKILL_STATE_CHANGE_EVENTID, + WMI_TLV_TDLS_PEER_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_TDLS), + WMI_TLV_BATCH_SCAN_ENABLED_EVENTID = + WMI_TLV_EV(WMI_TLV_GRP_LOCATION_SCAN), + WMI_TLV_BATCH_SCAN_RESULT_EVENTID, + WMI_TLV_OEM_CAPABILITY_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_OEM), + WMI_TLV_OEM_MEASUREMENT_REPORT_EVENTID, + WMI_TLV_OEM_ERROR_REPORT_EVENTID, + WMI_TLV_NAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_NAN), + WMI_TLV_LPI_RESULT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_LPI), + WMI_TLV_LPI_STATUS_EVENTID, + WMI_TLV_LPI_HANDOFF_EVENTID, + WMI_TLV_EXTSCAN_START_STOP_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_EXTSCAN), + WMI_TLV_EXTSCAN_OPERATION_EVENTID, + WMI_TLV_EXTSCAN_TABLE_USAGE_EVENTID, + WMI_TLV_EXTSCAN_CACHED_RESULTS_EVENTID, + WMI_TLV_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID, + WMI_TLV_EXTSCAN_HOTLIST_MATCH_EVENTID, + WMI_TLV_EXTSCAN_CAPABILITIES_EVENTID, + WMI_TLV_MDNS_STATS_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MDNS_OFL), + WMI_TLV_SAP_OFL_ADD_STA_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SAP_OFL), + WMI_TLV_SAP_OFL_DEL_STA_EVENTID, +}; + +enum wmi_tlv_pdev_param { + WMI_TLV_PDEV_PARAM_TX_CHAIN_MASK = 0x1, + WMI_TLV_PDEV_PARAM_RX_CHAIN_MASK, + WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT2G, + WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT5G, + WMI_TLV_PDEV_PARAM_TXPOWER_SCALE, + WMI_TLV_PDEV_PARAM_BEACON_GEN_MODE, + WMI_TLV_PDEV_PARAM_BEACON_TX_MODE, + WMI_TLV_PDEV_PARAM_RESMGR_OFFCHAN_MODE, + WMI_TLV_PDEV_PARAM_PROTECTION_MODE, + WMI_TLV_PDEV_PARAM_DYNAMIC_BW, + WMI_TLV_PDEV_PARAM_NON_AGG_SW_RETRY_TH, + WMI_TLV_PDEV_PARAM_AGG_SW_RETRY_TH, + WMI_TLV_PDEV_PARAM_STA_KICKOUT_TH, + WMI_TLV_PDEV_PARAM_AC_AGGRSIZE_SCALING, + WMI_TLV_PDEV_PARAM_LTR_ENABLE, + WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BE, + WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BK, + WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VI, + WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VO, + WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, + WMI_TLV_PDEV_PARAM_LTR_SLEEP_OVERRIDE, + WMI_TLV_PDEV_PARAM_LTR_RX_OVERRIDE, + WMI_TLV_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + WMI_TLV_PDEV_PARAM_L1SS_ENABLE, + WMI_TLV_PDEV_PARAM_DSLEEP_ENABLE, + WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_FLUSH, + WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_WATERMARK, + WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, + WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, + WMI_TLV_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, + WMI_TLV_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, + WMI_TLV_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, + WMI_TLV_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, + WMI_TLV_PDEV_PARAM_PMF_QOS, + WMI_TLV_PDEV_PARAM_ARP_AC_OVERRIDE, + WMI_TLV_PDEV_PARAM_DCS, + WMI_TLV_PDEV_PARAM_ANI_ENABLE, + WMI_TLV_PDEV_PARAM_ANI_POLL_PERIOD, + WMI_TLV_PDEV_PARAM_ANI_LISTEN_PERIOD, + WMI_TLV_PDEV_PARAM_ANI_OFDM_LEVEL, + WMI_TLV_PDEV_PARAM_ANI_CCK_LEVEL, + WMI_TLV_PDEV_PARAM_DYNTXCHAIN, + WMI_TLV_PDEV_PARAM_PROXY_STA, + WMI_TLV_PDEV_PARAM_IDLE_PS_CONFIG, + WMI_TLV_PDEV_PARAM_POWER_GATING_SLEEP, + WMI_TLV_PDEV_PARAM_RFKILL_ENABLE, + WMI_TLV_PDEV_PARAM_BURST_DUR, + WMI_TLV_PDEV_PARAM_BURST_ENABLE, + WMI_TLV_PDEV_PARAM_HW_RFKILL_CONFIG, + WMI_TLV_PDEV_PARAM_LOW_POWER_RF_ENABLE, + WMI_TLV_PDEV_PARAM_L1SS_TRACK, + WMI_TLV_PDEV_PARAM_HYST_EN, + WMI_TLV_PDEV_PARAM_POWER_COLLAPSE_ENABLE, + WMI_TLV_PDEV_PARAM_LED_SYS_STATE, + WMI_TLV_PDEV_PARAM_LED_ENABLE, + WMI_TLV_PDEV_PARAM_AUDIO_OVER_WLAN_LATENCY, + WMI_TLV_PDEV_PARAM_AUDIO_OVER_WLAN_ENABLE, + WMI_TLV_PDEV_PARAM_WHAL_MIB_STATS_UPDATE_ENABLE, + WMI_TLV_PDEV_PARAM_VDEV_RATE_STATS_UPDATE_PERIOD, + WMI_TLV_PDEV_PARAM_TXPOWER_REASON_NONE, + WMI_TLV_PDEV_PARAM_TXPOWER_REASON_SAR, + WMI_TLV_PDEV_PARAM_TXPOWER_REASON_MAX, +}; + +enum wmi_tlv_vdev_param { + WMI_TLV_VDEV_PARAM_RTS_THRESHOLD = 0x1, + WMI_TLV_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + WMI_TLV_VDEV_PARAM_BEACON_INTERVAL, + WMI_TLV_VDEV_PARAM_LISTEN_INTERVAL, + WMI_TLV_VDEV_PARAM_MULTICAST_RATE, + WMI_TLV_VDEV_PARAM_MGMT_TX_RATE, + WMI_TLV_VDEV_PARAM_SLOT_TIME, + WMI_TLV_VDEV_PARAM_PREAMBLE, + WMI_TLV_VDEV_PARAM_SWBA_TIME, + WMI_TLV_VDEV_STATS_UPDATE_PERIOD, + WMI_TLV_VDEV_PWRSAVE_AGEOUT_TIME, + WMI_TLV_VDEV_HOST_SWBA_INTERVAL, + WMI_TLV_VDEV_PARAM_DTIM_PERIOD, + WMI_TLV_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, + WMI_TLV_VDEV_PARAM_WDS, + WMI_TLV_VDEV_PARAM_ATIM_WINDOW, + WMI_TLV_VDEV_PARAM_BMISS_COUNT_MAX, + WMI_TLV_VDEV_PARAM_BMISS_FIRST_BCNT, + WMI_TLV_VDEV_PARAM_BMISS_FINAL_BCNT, + WMI_TLV_VDEV_PARAM_FEATURE_WMM, + WMI_TLV_VDEV_PARAM_CHWIDTH, + WMI_TLV_VDEV_PARAM_CHEXTOFFSET, + WMI_TLV_VDEV_PARAM_DISABLE_HTPROTECTION, + WMI_TLV_VDEV_PARAM_STA_QUICKKICKOUT, + WMI_TLV_VDEV_PARAM_MGMT_RATE, + WMI_TLV_VDEV_PARAM_PROTECTION_MODE, + WMI_TLV_VDEV_PARAM_FIXED_RATE, + WMI_TLV_VDEV_PARAM_SGI, + WMI_TLV_VDEV_PARAM_LDPC, + WMI_TLV_VDEV_PARAM_TX_STBC, + WMI_TLV_VDEV_PARAM_RX_STBC, + WMI_TLV_VDEV_PARAM_INTRA_BSS_FWD, + WMI_TLV_VDEV_PARAM_DEF_KEYID, + WMI_TLV_VDEV_PARAM_NSS, + WMI_TLV_VDEV_PARAM_BCAST_DATA_RATE, + WMI_TLV_VDEV_PARAM_MCAST_DATA_RATE, + WMI_TLV_VDEV_PARAM_MCAST_INDICATE, + WMI_TLV_VDEV_PARAM_DHCP_INDICATE, + WMI_TLV_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + WMI_TLV_VDEV_PARAM_AP_ENABLE_NAWDS, + WMI_TLV_VDEV_PARAM_ENABLE_RTSCTS, + WMI_TLV_VDEV_PARAM_TXBF, + WMI_TLV_VDEV_PARAM_PACKET_POWERSAVE, + WMI_TLV_VDEV_PARAM_DROP_UNENCRY, + WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE, + WMI_TLV_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + WMI_TLV_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, + WMI_TLV_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, + WMI_TLV_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, + WMI_TLV_VDEV_PARAM_EARLY_RX_SLOP_STEP, + WMI_TLV_VDEV_PARAM_EARLY_RX_INIT_SLOP, + WMI_TLV_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, + WMI_TLV_VDEV_PARAM_TX_PWRLIMIT, + WMI_TLV_VDEV_PARAM_SNR_NUM_FOR_CAL, + WMI_TLV_VDEV_PARAM_ROAM_FW_OFFLOAD, + WMI_TLV_VDEV_PARAM_ENABLE_RMC, + WMI_TLV_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS, + WMI_TLV_VDEV_PARAM_MAX_RATE, + WMI_TLV_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE, + WMI_TLV_VDEV_PARAM_SET_IBSS_TX_FAIL_CNT_THR, + WMI_TLV_VDEV_PARAM_EBT_RESYNC_TIMEOUT, + WMI_TLV_VDEV_PARAM_AGGR_TRIG_EVENT_ENABLE, + WMI_TLV_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED, + WMI_TLV_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED, + WMI_TLV_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED, + WMI_TLV_VDEV_PARAM_INACTIVITY_CNT, + WMI_TLV_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS, + WMI_TLV_VDEV_PARAM_DTIM_POLICY, + WMI_TLV_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS, + WMI_TLV_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE, +}; + +enum wmi_tlv_tag { + WMI_TLV_TAG_LAST_RESERVED = 15, + + WMI_TLV_TAG_FIRST_ARRAY_ENUM, + WMI_TLV_TAG_ARRAY_UINT32 = WMI_TLV_TAG_FIRST_ARRAY_ENUM, + WMI_TLV_TAG_ARRAY_BYTE, + WMI_TLV_TAG_ARRAY_STRUCT, + WMI_TLV_TAG_ARRAY_FIXED_STRUCT, + WMI_TLV_TAG_LAST_ARRAY_ENUM = 31, + + WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT, + WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES, + WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ, + WMI_TLV_TAG_STRUCT_READY_EVENT, + WMI_TLV_TAG_STRUCT_SCAN_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_TPC_CONFIG_EVENT, + WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT, + WMI_TLV_TAG_STRUCT_COMB_PHYERR_RX_HDR, + WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_STOPPED_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_COMPLETE_EVENT, + WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT, + WMI_TLV_TAG_STRUCT_MGMT_RX_HDR, + WMI_TLV_TAG_STRUCT_TBTT_OFFSET_EVENT, + WMI_TLV_TAG_STRUCT_TX_DELBA_COMPLETE_EVENT, + WMI_TLV_TAG_STRUCT_TX_ADDBA_COMPLETE_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_EVENT, + WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO, + WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO_SECTION_BITMAP, + WMI_TLV_TAG_STRUCT_RTT_EVENT_HEADER, + WMI_TLV_TAG_STRUCT_RTT_ERROR_REPORT_EVENT, + WMI_TLV_TAG_STRUCT_RTT_MEAS_EVENT, + WMI_TLV_TAG_STRUCT_ECHO_EVENT, + WMI_TLV_TAG_STRUCT_FTM_INTG_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_GET_KEEPALIVE_EVENT, + WMI_TLV_TAG_STRUCT_GPIO_INPUT_EVENT, + WMI_TLV_TAG_STRUCT_CSA_EVENT, + WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_STATUS_EVENT, + WMI_TLV_TAG_STRUCT_IGTK_INFO, + WMI_TLV_TAG_STRUCT_DCS_INTERFERENCE_EVENT, + WMI_TLV_TAG_STRUCT_ATH_DCS_CW_INT, + WMI_TLV_TAG_STRUCT_ATH_DCS_WLAN_INT_STAT, + WMI_TLV_TAG_STRUCT_WLAN_PROFILE_CTX_T, + WMI_TLV_TAG_STRUCT_WLAN_PROFILE_T, + WMI_TLV_TAG_STRUCT_PDEV_QVIT_EVENT, + WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT, + WMI_TLV_TAG_STRUCT_TIM_INFO, + WMI_TLV_TAG_STRUCT_P2P_NOA_INFO, + WMI_TLV_TAG_STRUCT_STATS_EVENT, + WMI_TLV_TAG_STRUCT_AVOID_FREQ_RANGES_EVENT, + WMI_TLV_TAG_STRUCT_AVOID_FREQ_RANGE_DESC, + WMI_TLV_TAG_STRUCT_GTK_REKEY_FAIL_EVENT, + WMI_TLV_TAG_STRUCT_INIT_CMD, + WMI_TLV_TAG_STRUCT_RESOURCE_CONFIG, + WMI_TLV_TAG_STRUCT_WLAN_HOST_MEMORY_CHUNK, + WMI_TLV_TAG_STRUCT_START_SCAN_CMD, + WMI_TLV_TAG_STRUCT_STOP_SCAN_CMD, + WMI_TLV_TAG_STRUCT_SCAN_CHAN_LIST_CMD, + WMI_TLV_TAG_STRUCT_CHANNEL, + WMI_TLV_TAG_STRUCT_PDEV_SET_REGDOMAIN_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_PARAM_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_WMM_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_WMM_PARAMS, + WMI_TLV_TAG_STRUCT_PDEV_SET_QUIET_CMD, + WMI_TLV_TAG_STRUCT_VDEV_CREATE_CMD, + WMI_TLV_TAG_STRUCT_VDEV_DELETE_CMD, + WMI_TLV_TAG_STRUCT_VDEV_START_REQUEST_CMD, + WMI_TLV_TAG_STRUCT_P2P_NOA_DESCRIPTOR, + WMI_TLV_TAG_STRUCT_P2P_GO_SET_BEACON_IE, + WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_CMD, + WMI_TLV_TAG_STRUCT_VDEV_UP_CMD, + WMI_TLV_TAG_STRUCT_VDEV_STOP_CMD, + WMI_TLV_TAG_STRUCT_VDEV_DOWN_CMD, + WMI_TLV_TAG_STRUCT_VDEV_SET_PARAM_CMD, + WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_CMD, + WMI_TLV_TAG_STRUCT_PEER_CREATE_CMD, + WMI_TLV_TAG_STRUCT_PEER_DELETE_CMD, + WMI_TLV_TAG_STRUCT_PEER_FLUSH_TIDS_CMD, + WMI_TLV_TAG_STRUCT_PEER_SET_PARAM_CMD, + WMI_TLV_TAG_STRUCT_PEER_ASSOC_COMPLETE_CMD, + WMI_TLV_TAG_STRUCT_VHT_RATE_SET, + WMI_TLV_TAG_STRUCT_BCN_TMPL_CMD, + WMI_TLV_TAG_STRUCT_PRB_TMPL_CMD, + WMI_TLV_TAG_STRUCT_BCN_PRB_INFO, + WMI_TLV_TAG_STRUCT_PEER_TID_ADDBA_CMD, + WMI_TLV_TAG_STRUCT_PEER_TID_DELBA_CMD, + WMI_TLV_TAG_STRUCT_STA_POWERSAVE_MODE_CMD, + WMI_TLV_TAG_STRUCT_STA_POWERSAVE_PARAM_CMD, + WMI_TLV_TAG_STRUCT_STA_DTIM_PS_METHOD_CMD, + WMI_TLV_TAG_STRUCT_ROAM_SCAN_MODE, + WMI_TLV_TAG_STRUCT_ROAM_SCAN_RSSI_THRESHOLD, + WMI_TLV_TAG_STRUCT_ROAM_SCAN_PERIOD, + WMI_TLV_TAG_STRUCT_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + WMI_TLV_TAG_STRUCT_PDEV_SUSPEND_CMD, + WMI_TLV_TAG_STRUCT_PDEV_RESUME_CMD, + WMI_TLV_TAG_STRUCT_ADD_BCN_FILTER_CMD, + WMI_TLV_TAG_STRUCT_RMV_BCN_FILTER_CMD, + WMI_TLV_TAG_STRUCT_WOW_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_WOW_HOSTWAKEUP_FROM_SLEEP_CMD, + WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_CMD, + WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_PARAM, + WMI_TLV_TAG_STRUCT_SET_ARP_NS_OFFLOAD_CMD, + WMI_TLV_TAG_STRUCT_ARP_OFFLOAD_TUPLE, + WMI_TLV_TAG_STRUCT_NS_OFFLOAD_TUPLE, + WMI_TLV_TAG_STRUCT_FTM_INTG_CMD, + WMI_TLV_TAG_STRUCT_STA_KEEPALIVE_CMD, + WMI_TLV_TAG_STRUCT_STA_KEEPALVE_ARP_RESPONSE, + WMI_TLV_TAG_STRUCT_P2P_SET_VENDOR_IE_DATA_CMD, + WMI_TLV_TAG_STRUCT_AP_PS_PEER_CMD, + WMI_TLV_TAG_STRUCT_PEER_RATE_RETRY_SCHED_CMD, + WMI_TLV_TAG_STRUCT_WLAN_PROFILE_TRIGGER_CMD, + WMI_TLV_TAG_STRUCT_WLAN_PROFILE_SET_HIST_INTVL_CMD, + WMI_TLV_TAG_STRUCT_WLAN_PROFILE_GET_PROF_DATA_CMD, + WMI_TLV_TAG_STRUCT_WLAN_PROFILE_ENABLE_PROFILE_ID_CMD, + WMI_TLV_TAG_STRUCT_WOW_DEL_PATTERN_CMD, + WMI_TLV_TAG_STRUCT_WOW_ADD_DEL_EVT_CMD, + WMI_TLV_TAG_STRUCT_RTT_MEASREQ_HEAD, + WMI_TLV_TAG_STRUCT_RTT_MEASREQ_BODY, + WMI_TLV_TAG_STRUCT_RTT_TSF_CMD, + WMI_TLV_TAG_STRUCT_VDEV_SPECTRAL_CONFIGURE_CMD, + WMI_TLV_TAG_STRUCT_VDEV_SPECTRAL_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD, + WMI_TLV_TAG_STRUCT_NLO_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_NLO_CONFIGURED_PARAMETERS, + WMI_TLV_TAG_STRUCT_CSA_OFFLOAD_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_CSA_OFFLOAD_CHANSWITCH_CMD, + WMI_TLV_TAG_STRUCT_CHATTER_SET_MODE_CMD, + WMI_TLV_TAG_STRUCT_ECHO_CMD, + WMI_TLV_TAG_STRUCT_VDEV_SET_KEEPALIVE_CMD, + WMI_TLV_TAG_STRUCT_VDEV_GET_KEEPALIVE_CMD, + WMI_TLV_TAG_STRUCT_FORCE_FW_HANG_CMD, + WMI_TLV_TAG_STRUCT_GPIO_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_GPIO_OUTPUT_CMD, + WMI_TLV_TAG_STRUCT_PEER_ADD_WDS_ENTRY_CMD, + WMI_TLV_TAG_STRUCT_PEER_REMOVE_WDS_ENTRY_CMD, + WMI_TLV_TAG_STRUCT_BCN_TX_HDR, + WMI_TLV_TAG_STRUCT_BCN_SEND_FROM_HOST_CMD, + WMI_TLV_TAG_STRUCT_MGMT_TX_HDR, + WMI_TLV_TAG_STRUCT_ADDBA_CLEAR_RESP_CMD, + WMI_TLV_TAG_STRUCT_ADDBA_SEND_CMD, + WMI_TLV_TAG_STRUCT_DELBA_SEND_CMD, + WMI_TLV_TAG_STRUCT_ADDBA_SETRESPONSE_CMD, + WMI_TLV_TAG_STRUCT_SEND_SINGLEAMSDU_CMD, + WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_DISABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_HT_IE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_VHT_IE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_DSCP_TID_MAP_CMD, + WMI_TLV_TAG_STRUCT_PDEV_GREEN_AP_PS_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_GET_TPC_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_PDEV_SET_BASE_MACADDR_CMD, + WMI_TLV_TAG_STRUCT_PEER_MCAST_GROUP_CMD, + WMI_TLV_TAG_STRUCT_ROAM_AP_PROFILE, + WMI_TLV_TAG_STRUCT_AP_PROFILE, + WMI_TLV_TAG_STRUCT_SCAN_SCH_PRIORITY_TABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_DFS_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_DFS_DISABLE_CMD, + WMI_TLV_TAG_STRUCT_WOW_ADD_PATTERN_CMD, + WMI_TLV_TAG_STRUCT_WOW_BITMAP_PATTERN_T, + WMI_TLV_TAG_STRUCT_WOW_IPV4_SYNC_PATTERN_T, + WMI_TLV_TAG_STRUCT_WOW_IPV6_SYNC_PATTERN_T, + WMI_TLV_TAG_STRUCT_WOW_MAGIC_PATTERN_CMD, + WMI_TLV_TAG_STRUCT_SCAN_UPDATE_REQUEST_CMD, + WMI_TLV_TAG_STRUCT_CHATTER_PKT_COALESCING_FILTER, + WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_ADD_FILTER_CMD, + WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_DELETE_FILTER_CMD, + WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_QUERY_CMD, + WMI_TLV_TAG_STRUCT_TXBF_CMD, + WMI_TLV_TAG_STRUCT_DEBUG_LOG_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_NLO_EVENT, + WMI_TLV_TAG_STRUCT_CHATTER_QUERY_REPLY_EVENT, + WMI_TLV_TAG_STRUCT_UPLOAD_H_HDR, + WMI_TLV_TAG_STRUCT_CAPTURE_H_EVENT_HDR, + WMI_TLV_TAG_STRUCT_VDEV_WNM_SLEEPMODE_CMD, + WMI_TLV_TAG_STRUCT_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD, + WMI_TLV_TAG_STRUCT_VDEV_WMM_ADDTS_CMD, + WMI_TLV_TAG_STRUCT_VDEV_WMM_DELTS_CMD, + WMI_TLV_TAG_STRUCT_VDEV_SET_WMM_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_TDLS_SET_STATE_CMD, + WMI_TLV_TAG_STRUCT_TDLS_PEER_UPDATE_CMD, + WMI_TLV_TAG_STRUCT_TDLS_PEER_EVENT, + WMI_TLV_TAG_STRUCT_TDLS_PEER_CAPABILITIES, + WMI_TLV_TAG_STRUCT_VDEV_MCC_SET_TBTT_MODE_CMD, + WMI_TLV_TAG_STRUCT_ROAM_CHAN_LIST, + WMI_TLV_TAG_STRUCT_VDEV_MCC_BCN_INTVL_CHANGE_EVENT, + WMI_TLV_TAG_STRUCT_RESMGR_ADAPTIVE_OCS_CMD, + WMI_TLV_TAG_STRUCT_RESMGR_SET_CHAN_TIME_QUOTA_CMD, + WMI_TLV_TAG_STRUCT_RESMGR_SET_CHAN_LATENCY_CMD, + WMI_TLV_TAG_STRUCT_BA_REQ_SSN_CMD, + WMI_TLV_TAG_STRUCT_BA_RSP_SSN_EVENT, + WMI_TLV_TAG_STRUCT_STA_SMPS_FORCE_MODE_CMD, + WMI_TLV_TAG_STRUCT_SET_MCASTBCAST_FILTER_CMD, + WMI_TLV_TAG_STRUCT_P2P_SET_OPPPS_CMD, + WMI_TLV_TAG_STRUCT_P2P_SET_NOA_CMD, + WMI_TLV_TAG_STRUCT_BA_REQ_SSN_CMD_SUB_STRUCT_PARAM, + WMI_TLV_TAG_STRUCT_BA_REQ_SSN_EVENT_SUB_STRUCT_PARAM, + WMI_TLV_TAG_STRUCT_STA_SMPS_PARAM_CMD, + WMI_TLV_TAG_STRUCT_VDEV_SET_GTX_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_MCC_SCHED_TRAFFIC_STATS_CMD, + WMI_TLV_TAG_STRUCT_MCC_SCHED_STA_TRAFFIC_STATS, + WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT, + WMI_TLV_TAG_STRUCT_P2P_NOA_EVENT, + WMI_TLV_TAG_STRUCT_HB_SET_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_HB_SET_TCP_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_HB_SET_TCP_PKT_FILTER_CMD, + WMI_TLV_TAG_STRUCT_HB_SET_UDP_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_HB_SET_UDP_PKT_FILTER_CMD, + WMI_TLV_TAG_STRUCT_HB_IND_EVENT, + WMI_TLV_TAG_STRUCT_TX_PAUSE_EVENT, + WMI_TLV_TAG_STRUCT_RFKILL_EVENT, + WMI_TLV_TAG_STRUCT_DFS_RADAR_EVENT, + WMI_TLV_TAG_STRUCT_DFS_PHYERR_FILTER_ENA_CMD, + WMI_TLV_TAG_STRUCT_DFS_PHYERR_FILTER_DIS_CMD, + WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_SCAN_LIST, + WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_NETWORK_INFO, + WMI_TLV_TAG_STRUCT_BATCH_SCAN_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_BATCH_SCAN_DISABLE_CMD, + WMI_TLV_TAG_STRUCT_BATCH_SCAN_TRIGGER_RESULT_CMD, + WMI_TLV_TAG_STRUCT_BATCH_SCAN_ENABLED_EVENT, + WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_PLMREQ_START_CMD, + WMI_TLV_TAG_STRUCT_VDEV_PLMREQ_STOP_CMD, + WMI_TLV_TAG_STRUCT_THERMAL_MGMT_CMD, + WMI_TLV_TAG_STRUCT_THERMAL_MGMT_EVENT, + WMI_TLV_TAG_STRUCT_PEER_INFO_REQ_CMD, + WMI_TLV_TAG_STRUCT_PEER_INFO_EVENT, + WMI_TLV_TAG_STRUCT_PEER_INFO, + WMI_TLV_TAG_STRUCT_PEER_TX_FAIL_CNT_THR_EVENT, + WMI_TLV_TAG_STRUCT_RMC_SET_MODE_CMD, + WMI_TLV_TAG_STRUCT_RMC_SET_ACTION_PERIOD_CMD, + WMI_TLV_TAG_STRUCT_RMC_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_SET_MODE_CMD, + WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_PLUMB_ROUTING_TABLE_CMD, + WMI_TLV_TAG_STRUCT_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD, + WMI_TLV_TAG_STRUCT_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD, + WMI_TLV_TAG_STRUCT_NAN_CMD_PARAM, + WMI_TLV_TAG_STRUCT_NAN_EVENT_HDR, + WMI_TLV_TAG_STRUCT_PDEV_L1SS_TRACK_EVENT, + WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT, + WMI_TLV_TAG_STRUCT_MODEM_POWER_STATE_CMD_PARAM, + WMI_TLV_TAG_STRUCT_PEER_GET_ESTIMATED_LINKSPEED_CMD, + WMI_TLV_TAG_STRUCT_PEER_ESTIMATED_LINKSPEED_EVENT, + WMI_TLV_TAG_STRUCT_AGGR_STATE_TRIG_EVENT, + WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_ROUTING_TABLE_ENTRY, + WMI_TLV_TAG_STRUCT_ROAM_SCAN_CMD, + WMI_TLV_TAG_STRUCT_REQ_STATS_EXT_CMD, + WMI_TLV_TAG_STRUCT_STATS_EXT_EVENT, + WMI_TLV_TAG_STRUCT_OBSS_SCAN_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_OBSS_SCAN_DISABLE_CMD, + WMI_TLV_TAG_STRUCT_OFFLOAD_PRB_RSP_TX_STATUS_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_SET_LED_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_HOST_AUTO_SHUTDOWN_CFG_CMD, + WMI_TLV_TAG_STRUCT_HOST_AUTO_SHUTDOWN_EVENT, + WMI_TLV_TAG_STRUCT_UPDATE_WHAL_MIB_STATS_EVENT, + WMI_TLV_TAG_STRUCT_CHAN_AVOID_UPDATE_CMD_PARAM, + WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_PKT_PATTERN_T, + WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_TMR_PATTERN_T, + WMI_TLV_TAG_STRUCT_WOW_IOAC_ADD_KEEPALIVE_CMD, + WMI_TLV_TAG_STRUCT_WOW_IOAC_DEL_KEEPALIVE_CMD, + WMI_TLV_TAG_STRUCT_WOW_IOAC_KEEPALIVE_T, + WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_ADD_PATTERN_CMD, + WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_DEL_PATTERN_CMD, + WMI_TLV_TAG_STRUCT_START_LINK_STATS_CMD, + WMI_TLV_TAG_STRUCT_CLEAR_LINK_STATS_CMD, + WMI_TLV_TAG_STRUCT_REQUEST_LINK_STATS_CMD, + WMI_TLV_TAG_STRUCT_IFACE_LINK_STATS_EVENT, + WMI_TLV_TAG_STRUCT_RADIO_LINK_STATS_EVENT, + WMI_TLV_TAG_STRUCT_PEER_STATS_EVENT, + WMI_TLV_TAG_STRUCT_CHANNEL_STATS, + WMI_TLV_TAG_STRUCT_RADIO_LINK_STATS, + WMI_TLV_TAG_STRUCT_RATE_STATS, + WMI_TLV_TAG_STRUCT_PEER_LINK_STATS, + WMI_TLV_TAG_STRUCT_WMM_AC_STATS, + WMI_TLV_TAG_STRUCT_IFACE_LINK_STATS, + WMI_TLV_TAG_STRUCT_LPI_MGMT_SNOOPING_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_LPI_START_SCAN_CMD, + WMI_TLV_TAG_STRUCT_LPI_STOP_SCAN_CMD, + WMI_TLV_TAG_STRUCT_LPI_RESULT_EVENT, + WMI_TLV_TAG_STRUCT_PEER_STATE_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_BUCKET_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_BUCKET_CHANNEL_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_START_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_STOP_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_BSSID_PARAM_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_GET_CACHED_RESULTS_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_SET_CAPABILITIES_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_GET_CAPABILITIES_CMD, + WMI_TLV_TAG_STRUCT_EXTSCAN_OPERATION_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_START_STOP_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_TABLE_USAGE_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_DESCRIPTOR_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_RSSI_INFO_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_CACHED_RESULTS_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_RESULTS_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_RESULT_BSSID_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_MATCH_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_CAPABILITIES_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_CACHE_CAPABILITIES_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_MONITOR_CAPABILITIES_EVENT, + WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_MONITOR_CAPABILITIES_EVENT, + WMI_TLV_TAG_STRUCT_D0_WOW_ENABLE_DISABLE_CMD, + WMI_TLV_TAG_STRUCT_D0_WOW_DISABLE_ACK_EVENT, + WMI_TLV_TAG_STRUCT_UNIT_TEST_CMD, + WMI_TLV_TAG_STRUCT_ROAM_OFFLOAD_TLV_PARAM, + WMI_TLV_TAG_STRUCT_ROAM_11I_OFFLOAD_TLV_PARAM, + WMI_TLV_TAG_STRUCT_ROAM_11R_OFFLOAD_TLV_PARAM, + WMI_TLV_TAG_STRUCT_ROAM_ESE_OFFLOAD_TLV_PARAM, + WMI_TLV_TAG_STRUCT_ROAM_SYNCH_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_SYNCH_COMPLETE, + WMI_TLV_TAG_STRUCT_EXTWOW_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_EXTWOW_SET_APP_TYPE1_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_EXTWOW_SET_APP_TYPE2_PARAMS_CMD, + WMI_TLV_TAG_STRUCT_LPI_STATUS_EVENT, + WMI_TLV_TAG_STRUCT_LPI_HANDOFF_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_RATE_STATS_EVENT, + WMI_TLV_TAG_STRUCT_VDEV_RATE_HT_INFO, + WMI_TLV_TAG_STRUCT_RIC_REQUEST, + WMI_TLV_TAG_STRUCT_PDEV_GET_TEMPERATURE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_TEMPERATURE_EVENT, + WMI_TLV_TAG_STRUCT_SET_DHCP_SERVER_OFFLOAD_CMD, + WMI_TLV_TAG_STRUCT_TPC_CHAINMASK_CONFIG_CMD, + WMI_TLV_TAG_STRUCT_RIC_TSPEC, + WMI_TLV_TAG_STRUCT_TPC_CHAINMASK_CONFIG, + WMI_TLV_TAG_STRUCT_IPA_OFFLOAD_CMD, + WMI_TLV_TAG_STRUCT_SCAN_PROB_REQ_OUI_CMD, + WMI_TLV_TAG_STRUCT_KEY_MATERIAL, + WMI_TLV_TAG_STRUCT_TDLS_SET_OFFCHAN_MODE_CMD, + WMI_TLV_TAG_STRUCT_SET_LED_FLASHING_CMD, + WMI_TLV_TAG_STRUCT_MDNS_OFFLOAD_CMD, + WMI_TLV_TAG_STRUCT_MDNS_SET_FQDN_CMD, + WMI_TLV_TAG_STRUCT_MDNS_SET_RESP_CMD, + WMI_TLV_TAG_STRUCT_MDNS_GET_STATS_CMD, + WMI_TLV_TAG_STRUCT_MDNS_STATS_EVENT, + WMI_TLV_TAG_STRUCT_ROAM_INVOKE_CMD, + WMI_TLV_TAG_STRUCT_PDEV_RESUME_EVENT, + WMI_TLV_TAG_STRUCT_PDEV_SET_ANTENNA_DIVERSITY_CMD, + WMI_TLV_TAG_STRUCT_SAP_OFL_ENABLE_CMD, + WMI_TLV_TAG_STRUCT_SAP_OFL_ADD_STA_EVENT, + WMI_TLV_TAG_STRUCT_SAP_OFL_DEL_STA_EVENT, + WMI_TLV_TAG_STRUCT_APFIND_CMD_PARAM, + WMI_TLV_TAG_STRUCT_APFIND_EVENT_HDR, + + WMI_TLV_TAG_MAX +}; + +enum wmi_tlv_service { + WMI_TLV_SERVICE_BEACON_OFFLOAD = 0, + WMI_TLV_SERVICE_SCAN_OFFLOAD, + WMI_TLV_SERVICE_ROAM_SCAN_OFFLOAD, + WMI_TLV_SERVICE_BCN_MISS_OFFLOAD, + WMI_TLV_SERVICE_STA_PWRSAVE, + WMI_TLV_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_TLV_SERVICE_AP_UAPSD, + WMI_TLV_SERVICE_AP_DFS, + WMI_TLV_SERVICE_11AC, + WMI_TLV_SERVICE_BLOCKACK, + WMI_TLV_SERVICE_PHYERR, + WMI_TLV_SERVICE_BCN_FILTER, + WMI_TLV_SERVICE_RTT, + WMI_TLV_SERVICE_WOW, + WMI_TLV_SERVICE_RATECTRL_CACHE, + WMI_TLV_SERVICE_IRAM_TIDS, + WMI_TLV_SERVICE_ARPNS_OFFLOAD, + WMI_TLV_SERVICE_NLO, + WMI_TLV_SERVICE_GTK_OFFLOAD, + WMI_TLV_SERVICE_SCAN_SCH, + WMI_TLV_SERVICE_CSA_OFFLOAD, + WMI_TLV_SERVICE_CHATTER, + WMI_TLV_SERVICE_COEX_FREQAVOID, + WMI_TLV_SERVICE_PACKET_POWER_SAVE, + WMI_TLV_SERVICE_FORCE_FW_HANG, + WMI_TLV_SERVICE_GPIO, + WMI_TLV_SERVICE_STA_DTIM_PS_MODULATED_DTIM, + WMI_TLV_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_TLV_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_TLV_SERVICE_STA_KEEP_ALIVE, + WMI_TLV_SERVICE_TX_ENCAP, + WMI_TLV_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, + WMI_TLV_SERVICE_EARLY_RX, + WMI_TLV_SERVICE_STA_SMPS, + WMI_TLV_SERVICE_FWTEST, + WMI_TLV_SERVICE_STA_WMMAC, + WMI_TLV_SERVICE_TDLS, + WMI_TLV_SERVICE_BURST, + WMI_TLV_SERVICE_MCC_BCN_INTERVAL_CHANGE, + WMI_TLV_SERVICE_ADAPTIVE_OCS, + WMI_TLV_SERVICE_BA_SSN_SUPPORT, + WMI_TLV_SERVICE_FILTER_IPSEC_NATKEEPALIVE, + WMI_TLV_SERVICE_WLAN_HB, + WMI_TLV_SERVICE_LTE_ANT_SHARE_SUPPORT, + WMI_TLV_SERVICE_BATCH_SCAN, + WMI_TLV_SERVICE_QPOWER, + WMI_TLV_SERVICE_PLMREQ, + WMI_TLV_SERVICE_THERMAL_MGMT, + WMI_TLV_SERVICE_RMC, + WMI_TLV_SERVICE_MHF_OFFLOAD, + WMI_TLV_SERVICE_COEX_SAR, + WMI_TLV_SERVICE_BCN_TXRATE_OVERRIDE, + WMI_TLV_SERVICE_NAN, + WMI_TLV_SERVICE_L1SS_STAT, + WMI_TLV_SERVICE_ESTIMATE_LINKSPEED, + WMI_TLV_SERVICE_OBSS_SCAN, + WMI_TLV_SERVICE_TDLS_OFFCHAN, + WMI_TLV_SERVICE_TDLS_UAPSD_BUFFER_STA, + WMI_TLV_SERVICE_TDLS_UAPSD_SLEEP_STA, + WMI_TLV_SERVICE_IBSS_PWRSAVE, + WMI_TLV_SERVICE_LPASS, + WMI_TLV_SERVICE_EXTSCAN, + WMI_TLV_SERVICE_D0WOW, + WMI_TLV_SERVICE_HSOFFLOAD, + WMI_TLV_SERVICE_ROAM_HO_OFFLOAD, + WMI_TLV_SERVICE_RX_FULL_REORDER, + WMI_TLV_SERVICE_DHCP_OFFLOAD, + WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, + WMI_TLV_SERVICE_MDNS_OFFLOAD, + WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD, +}; + +#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ + ((svc_id) < (len) && \ + __le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \ + BIT((svc_id)%(sizeof(u32)))) + +#define SVCMAP(x, y, len) \ + do { \ + if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \ + __set_bit(y, out); \ + } while (0) + +static inline void +wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len) +{ + SVCMAP(WMI_TLV_SERVICE_BEACON_OFFLOAD, + WMI_SERVICE_BEACON_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_SCAN_OFFLOAD, + WMI_SERVICE_SCAN_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_ROAM_SCAN_OFFLOAD, + WMI_SERVICE_ROAM_SCAN_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_BCN_MISS_OFFLOAD, + WMI_SERVICE_BCN_MISS_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_STA_PWRSAVE, + WMI_SERVICE_STA_PWRSAVE, len); + SVCMAP(WMI_TLV_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); + SVCMAP(WMI_TLV_SERVICE_AP_UAPSD, + WMI_SERVICE_AP_UAPSD, len); + SVCMAP(WMI_TLV_SERVICE_AP_DFS, + WMI_SERVICE_AP_DFS, len); + SVCMAP(WMI_TLV_SERVICE_11AC, + WMI_SERVICE_11AC, len); + SVCMAP(WMI_TLV_SERVICE_BLOCKACK, + WMI_SERVICE_BLOCKACK, len); + SVCMAP(WMI_TLV_SERVICE_PHYERR, + WMI_SERVICE_PHYERR, len); + SVCMAP(WMI_TLV_SERVICE_BCN_FILTER, + WMI_SERVICE_BCN_FILTER, len); + SVCMAP(WMI_TLV_SERVICE_RTT, + WMI_SERVICE_RTT, len); + SVCMAP(WMI_TLV_SERVICE_WOW, + WMI_SERVICE_WOW, len); + SVCMAP(WMI_TLV_SERVICE_RATECTRL_CACHE, + WMI_SERVICE_RATECTRL_CACHE, len); + SVCMAP(WMI_TLV_SERVICE_IRAM_TIDS, + WMI_SERVICE_IRAM_TIDS, len); + SVCMAP(WMI_TLV_SERVICE_ARPNS_OFFLOAD, + WMI_SERVICE_ARPNS_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_NLO, + WMI_SERVICE_NLO, len); + SVCMAP(WMI_TLV_SERVICE_GTK_OFFLOAD, + WMI_SERVICE_GTK_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_SCAN_SCH, + WMI_SERVICE_SCAN_SCH, len); + SVCMAP(WMI_TLV_SERVICE_CSA_OFFLOAD, + WMI_SERVICE_CSA_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_CHATTER, + WMI_SERVICE_CHATTER, len); + SVCMAP(WMI_TLV_SERVICE_COEX_FREQAVOID, + WMI_SERVICE_COEX_FREQAVOID, len); + SVCMAP(WMI_TLV_SERVICE_PACKET_POWER_SAVE, + WMI_SERVICE_PACKET_POWER_SAVE, len); + SVCMAP(WMI_TLV_SERVICE_FORCE_FW_HANG, + WMI_SERVICE_FORCE_FW_HANG, len); + SVCMAP(WMI_TLV_SERVICE_GPIO, + WMI_SERVICE_GPIO, len); + SVCMAP(WMI_TLV_SERVICE_STA_DTIM_PS_MODULATED_DTIM, + WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, len); + SVCMAP(WMI_TLV_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len); + SVCMAP(WMI_TLV_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len); + SVCMAP(WMI_TLV_SERVICE_STA_KEEP_ALIVE, + WMI_SERVICE_STA_KEEP_ALIVE, len); + SVCMAP(WMI_TLV_SERVICE_TX_ENCAP, + WMI_SERVICE_TX_ENCAP, len); + SVCMAP(WMI_TLV_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, + WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, len); + SVCMAP(WMI_TLV_SERVICE_EARLY_RX, + WMI_SERVICE_EARLY_RX, len); + SVCMAP(WMI_TLV_SERVICE_STA_SMPS, + WMI_SERVICE_STA_SMPS, len); + SVCMAP(WMI_TLV_SERVICE_FWTEST, + WMI_SERVICE_FWTEST, len); + SVCMAP(WMI_TLV_SERVICE_STA_WMMAC, + WMI_SERVICE_STA_WMMAC, len); + SVCMAP(WMI_TLV_SERVICE_TDLS, + WMI_SERVICE_TDLS, len); + SVCMAP(WMI_TLV_SERVICE_BURST, + WMI_SERVICE_BURST, len); + SVCMAP(WMI_TLV_SERVICE_MCC_BCN_INTERVAL_CHANGE, + WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE, len); + SVCMAP(WMI_TLV_SERVICE_ADAPTIVE_OCS, + WMI_SERVICE_ADAPTIVE_OCS, len); + SVCMAP(WMI_TLV_SERVICE_BA_SSN_SUPPORT, + WMI_SERVICE_BA_SSN_SUPPORT, len); + SVCMAP(WMI_TLV_SERVICE_FILTER_IPSEC_NATKEEPALIVE, + WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE, len); + SVCMAP(WMI_TLV_SERVICE_WLAN_HB, + WMI_SERVICE_WLAN_HB, len); + SVCMAP(WMI_TLV_SERVICE_LTE_ANT_SHARE_SUPPORT, + WMI_SERVICE_LTE_ANT_SHARE_SUPPORT, len); + SVCMAP(WMI_TLV_SERVICE_BATCH_SCAN, + WMI_SERVICE_BATCH_SCAN, len); + SVCMAP(WMI_TLV_SERVICE_QPOWER, + WMI_SERVICE_QPOWER, len); + SVCMAP(WMI_TLV_SERVICE_PLMREQ, + WMI_SERVICE_PLMREQ, len); + SVCMAP(WMI_TLV_SERVICE_THERMAL_MGMT, + WMI_SERVICE_THERMAL_MGMT, len); + SVCMAP(WMI_TLV_SERVICE_RMC, + WMI_SERVICE_RMC, len); + SVCMAP(WMI_TLV_SERVICE_MHF_OFFLOAD, + WMI_SERVICE_MHF_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_COEX_SAR, + WMI_SERVICE_COEX_SAR, len); + SVCMAP(WMI_TLV_SERVICE_BCN_TXRATE_OVERRIDE, + WMI_SERVICE_BCN_TXRATE_OVERRIDE, len); + SVCMAP(WMI_TLV_SERVICE_NAN, + WMI_SERVICE_NAN, len); + SVCMAP(WMI_TLV_SERVICE_L1SS_STAT, + WMI_SERVICE_L1SS_STAT, len); + SVCMAP(WMI_TLV_SERVICE_ESTIMATE_LINKSPEED, + WMI_SERVICE_ESTIMATE_LINKSPEED, len); + SVCMAP(WMI_TLV_SERVICE_OBSS_SCAN, + WMI_SERVICE_OBSS_SCAN, len); + SVCMAP(WMI_TLV_SERVICE_TDLS_OFFCHAN, + WMI_SERVICE_TDLS_OFFCHAN, len); + SVCMAP(WMI_TLV_SERVICE_TDLS_UAPSD_BUFFER_STA, + WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, len); + SVCMAP(WMI_TLV_SERVICE_TDLS_UAPSD_SLEEP_STA, + WMI_SERVICE_TDLS_UAPSD_SLEEP_STA, len); + SVCMAP(WMI_TLV_SERVICE_IBSS_PWRSAVE, + WMI_SERVICE_IBSS_PWRSAVE, len); + SVCMAP(WMI_TLV_SERVICE_LPASS, + WMI_SERVICE_LPASS, len); + SVCMAP(WMI_TLV_SERVICE_EXTSCAN, + WMI_SERVICE_EXTSCAN, len); + SVCMAP(WMI_TLV_SERVICE_D0WOW, + WMI_SERVICE_D0WOW, len); + SVCMAP(WMI_TLV_SERVICE_HSOFFLOAD, + WMI_SERVICE_HSOFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_ROAM_HO_OFFLOAD, + WMI_SERVICE_ROAM_HO_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_RX_FULL_REORDER, + WMI_SERVICE_RX_FULL_REORDER, len); + SVCMAP(WMI_TLV_SERVICE_DHCP_OFFLOAD, + WMI_SERVICE_DHCP_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, + WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, len); + SVCMAP(WMI_TLV_SERVICE_MDNS_OFFLOAD, + WMI_SERVICE_MDNS_OFFLOAD, len); + SVCMAP(WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD, + WMI_SERVICE_SAP_AUTH_OFFLOAD, len); +} + +#undef SVCMAP + +struct wmi_tlv { + __le16 len; + __le16 tag; + u8 value[0]; +} __packed; + +#define WMI_TLV_MGMT_RX_NUM_RSSI 4 + +struct wmi_tlv_mgmt_rx_ev { + __le32 channel; + __le32 snr; + __le32 rate; + __le32 phy_mode; + __le32 buf_len; + __le32 status; + __le32 rssi[WMI_TLV_MGMT_RX_NUM_RSSI]; +} __packed; + +struct wmi_tlv_abi_version { + __le32 abi_ver0; + __le32 abi_ver1; + __le32 abi_ver_ns0; + __le32 abi_ver_ns1; + __le32 abi_ver_ns2; + __le32 abi_ver_ns3; +} __packed; + +enum wmi_tlv_hw_bd_id { + WMI_TLV_HW_BD_LEGACY = 0, + WMI_TLV_HW_BD_QCA6174 = 1, + WMI_TLV_HW_BD_QCA2582 = 2, +}; + +struct wmi_tlv_hw_bd_info { + u8 rev; + u8 project_id; + u8 custom_id; + u8 reference_design_id; +} __packed; + +struct wmi_tlv_svc_rdy_ev { + __le32 fw_build_vers; + struct wmi_tlv_abi_version abi; + __le32 phy_capability; + __le32 max_frag_entry; + __le32 num_rf_chains; + __le32 ht_cap_info; + __le32 vht_cap_info; + __le32 vht_supp_mcs; + __le32 hw_min_tx_power; + __le32 hw_max_tx_power; + __le32 sys_cap_info; + __le32 min_pkt_size_enable; + __le32 max_bcn_ie_size; + __le32 num_mem_reqs; + __le32 max_num_scan_chans; + __le32 hw_bd_id; /* 0 means hw_bd_info is invalid */ + struct wmi_tlv_hw_bd_info hw_bd_info[5]; +} __packed; + +struct wmi_tlv_rdy_ev { + struct wmi_tlv_abi_version abi; + struct wmi_mac_addr mac_addr; + __le32 status; +} __packed; + +struct wmi_tlv_resource_config { + __le32 num_vdevs; + __le32 num_peers; + __le32 num_offload_peers; + __le32 num_offload_reorder_bufs; + __le32 num_peer_keys; + __le32 num_tids; + __le32 ast_skid_limit; + __le32 tx_chain_mask; + __le32 rx_chain_mask; + __le32 rx_timeout_pri[4]; + __le32 rx_decap_mode; + __le32 scan_max_pending_reqs; + __le32 bmiss_offload_max_vdev; + __le32 roam_offload_max_vdev; + __le32 roam_offload_max_ap_profiles; + __le32 num_mcast_groups; + __le32 num_mcast_table_elems; + __le32 mcast2ucast_mode; + __le32 tx_dbg_log_size; + __le32 num_wds_entries; + __le32 dma_burst_size; + __le32 mac_aggr_delim; + __le32 rx_skip_defrag_timeout_dup_detection_check; + __le32 vow_config; + __le32 gtk_offload_max_vdev; + __le32 num_msdu_desc; + __le32 max_frag_entries; + __le32 num_tdls_vdevs; + __le32 num_tdls_conn_table_entries; + __le32 beacon_tx_offload_max_vdev; + __le32 num_multicast_filter_entries; + __le32 num_wow_filters; + __le32 num_keep_alive_pattern; + __le32 keep_alive_pattern_size; + __le32 max_tdls_concurrent_sleep_sta; + __le32 max_tdls_concurrent_buffer_sta; +} __packed; + +struct wmi_tlv_init_cmd { + struct wmi_tlv_abi_version abi; + __le32 num_host_mem_chunks; +} __packed; + +struct wmi_tlv_pdev_set_param_cmd { + __le32 pdev_id; /* not used yet */ + __le32 param_id; + __le32 param_value; +} __packed; + +struct wmi_tlv_pdev_set_rd_cmd { + __le32 pdev_id; /* not used yet */ + __le32 regd; + __le32 regd_2ghz; + __le32 regd_5ghz; + __le32 conform_limit_2ghz; + __le32 conform_limit_5ghz; +} __packed; + +struct wmi_tlv_scan_chan_list_cmd { + __le32 num_scan_chans; +} __packed; + +struct wmi_tlv_start_scan_cmd { + struct wmi_start_scan_common common; + __le32 burst_duration_ms; + __le32 num_channels; + __le32 num_bssids; + __le32 num_ssids; + __le32 ie_len; + __le32 num_probes; +} __packed; + +struct wmi_tlv_vdev_start_cmd { + __le32 vdev_id; + __le32 requestor_id; + __le32 bcn_intval; + __le32 dtim_period; + __le32 flags; + struct wmi_ssid ssid; + __le32 bcn_tx_rate; + __le32 bcn_tx_power; + __le32 num_noa_descr; + __le32 disable_hw_ack; +} __packed; + +enum { + WMI_TLV_PEER_TYPE_DEFAULT = 0, /* generic / non-BSS / self-peer */ + WMI_TLV_PEER_TYPE_BSS = 1, + WMI_TLV_PEER_TYPE_TDLS = 2, + WMI_TLV_PEER_TYPE_HOST_MAX = 127, + WMI_TLV_PEER_TYPE_ROAMOFFLOAD_TMP = 128, +}; + +struct wmi_tlv_peer_create_cmd { + __le32 vdev_id; + struct wmi_mac_addr peer_addr; + __le32 peer_type; +} __packed; + +struct wmi_tlv_peer_assoc_cmd { + struct wmi_mac_addr mac_addr; + __le32 vdev_id; + __le32 new_assoc; + __le32 assoc_id; + __le32 flags; + __le32 caps; + __le32 listen_intval; + __le32 ht_caps; + __le32 max_mpdu; + __le32 mpdu_density; + __le32 rate_caps; + __le32 nss; + __le32 vht_caps; + __le32 phy_mode; + __le32 ht_info[2]; + __le32 num_legacy_rates; + __le32 num_ht_rates; +} __packed; + +struct wmi_tlv_pdev_suspend { + __le32 pdev_id; /* not used yet */ + __le32 opt; +} __packed; + +struct wmi_tlv_pdev_set_wmm_cmd { + __le32 pdev_id; /* not used yet */ + __le32 dg_type; /* no idea.. */ +} __packed; + +struct wmi_tlv_vdev_set_wmm_cmd { + __le32 vdev_id; +} __packed; + +struct wmi_tlv_phyerr_ev { + __le32 num_phyerrs; + __le32 tsf_l32; + __le32 tsf_u32; + __le32 buf_len; +} __packed; + +enum wmi_tlv_dbglog_param { + WMI_TLV_DBGLOG_PARAM_LOG_LEVEL = 1, + WMI_TLV_DBGLOG_PARAM_VDEV_ENABLE, + WMI_TLV_DBGLOG_PARAM_VDEV_DISABLE, + WMI_TLV_DBGLOG_PARAM_VDEV_ENABLE_BITMAP, + WMI_TLV_DBGLOG_PARAM_VDEV_DISABLE_BITMAP, +}; + +enum wmi_tlv_dbglog_log_level { + WMI_TLV_DBGLOG_LOG_LEVEL_VERBOSE = 0, + WMI_TLV_DBGLOG_LOG_LEVEL_INFO, + WMI_TLV_DBGLOG_LOG_LEVEL_INFO_LVL_1, + WMI_TLV_DBGLOG_LOG_LEVEL_INFO_LVL_2, + WMI_TLV_DBGLOG_LOG_LEVEL_WARN, + WMI_TLV_DBGLOG_LOG_LEVEL_ERR, +}; + +#define WMI_TLV_DBGLOG_BITMAP_MAX_IDS 512 +#define WMI_TLV_DBGLOG_BITMAP_MAX_WORDS (WMI_TLV_DBGLOG_BITMAP_MAX_IDS / \ + sizeof(__le32)) +#define WMI_TLV_DBGLOG_ALL_MODULES 0xffff +#define WMI_TLV_DBGLOG_LOG_LEVEL_VALUE(module_id, log_level) \ + (((module_id << 16) & 0xffff0000) | \ + ((log_level << 0) & 0x000000ff)) + +struct wmi_tlv_dbglog_cmd { + __le32 param; + __le32 value; +} __packed; + +struct wmi_tlv_resume_cmd { + __le32 reserved; +} __packed; + +struct wmi_tlv_req_stats_cmd { + __le32 stats_id; /* wmi_stats_id */ + __le32 vdev_id; + struct wmi_mac_addr peer_macaddr; +} __packed; + +struct wmi_tlv_vdev_stats { + __le32 vdev_id; + __le32 beacon_snr; + __le32 data_snr; + __le32 num_tx_frames[4]; /* per-AC */ + __le32 num_rx_frames; + __le32 num_tx_frames_retries[4]; + __le32 num_tx_frames_failures[4]; + __le32 num_rts_fail; + __le32 num_rts_success; + __le32 num_rx_err; + __le32 num_rx_discard; + __le32 num_tx_not_acked; + __le32 tx_rate_history[10]; + __le32 beacon_rssi_history[10]; +} __packed; + +struct wmi_tlv_pktlog_enable { + __le32 reserved; + __le32 filter; +} __packed; + +struct wmi_tlv_pktlog_disable { + __le32 reserved; +} __packed; + +enum wmi_tlv_bcn_tx_status { + WMI_TLV_BCN_TX_STATUS_OK, + WMI_TLV_BCN_TX_STATUS_XRETRY, + WMI_TLV_BCN_TX_STATUS_DROP, + WMI_TLV_BCN_TX_STATUS_FILTERED, +}; + +struct wmi_tlv_bcn_tx_status_ev { + __le32 vdev_id; + __le32 tx_status; +} __packed; + +struct wmi_tlv_bcn_prb_info { + __le32 caps; + __le32 erp; + u8 ies[0]; +} __packed; + +struct wmi_tlv_bcn_tmpl_cmd { + __le32 vdev_id; + __le32 tim_ie_offset; + __le32 buf_len; +} __packed; + +struct wmi_tlv_prb_tmpl_cmd { + __le32 vdev_id; + __le32 buf_len; +} __packed; + +struct wmi_tlv_p2p_go_bcn_ie { + __le32 vdev_id; + __le32 ie_len; +} __packed; + +enum wmi_tlv_diag_item_type { + WMI_TLV_DIAG_ITEM_TYPE_FW_EVENT, + WMI_TLV_DIAG_ITEM_TYPE_FW_LOG, + WMI_TLV_DIAG_ITEM_TYPE_FW_DEBUG_MSG, +}; + +struct wmi_tlv_diag_item { + u8 type; + u8 reserved; + __le16 len; + __le32 timestamp; + __le32 code; + u8 payload[0]; +} __packed; + +struct wmi_tlv_diag_data_ev { + __le32 num_items; +} __packed; + +struct wmi_tlv_sta_keepalive_cmd { + __le32 vdev_id; + __le32 enabled; + __le32 method; /* WMI_STA_KEEPALIVE_METHOD_ */ + __le32 interval; /* in seconds */ +} __packed; + +void ath10k_wmi_tlv_attach(struct ath10k *ar); + +#endif diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index c0f3e4d09263..aeea1c793943 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -22,8 +22,10 @@ #include "htc.h" #include "debug.h" #include "wmi.h" +#include "wmi-tlv.h" #include "mac.h" #include "testmode.h" +#include "wmi-ops.h" /* MAIN WMI cmd track */ static struct wmi_cmd_map wmi_cmd_map = { @@ -143,6 +145,7 @@ static struct wmi_cmd_map wmi_cmd_map = { .force_fw_hang_cmdid = WMI_FORCE_FW_HANG_CMDID, .gpio_config_cmdid = WMI_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_GPIO_OUTPUT_CMDID, + .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.X WMI cmd track */ @@ -265,6 +268,129 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED, .gpio_config_cmdid = WMI_10X_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_10X_GPIO_OUTPUT_CMDID, + .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, +}; + +/* 10.2.4 WMI cmd track */ +static struct wmi_cmd_map wmi_10_2_4_cmd_map = { + .init_cmdid = WMI_10_2_INIT_CMDID, + .start_scan_cmdid = WMI_10_2_START_SCAN_CMDID, + .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID, + .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID, + .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID, + .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID, + .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID, + .pdev_pktlog_enable_cmdid = WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID, + .pdev_pktlog_disable_cmdid = WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID, + .pdev_set_wmm_params_cmdid = WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID, + .pdev_set_ht_cap_ie_cmdid = WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID, + .pdev_set_vht_cap_ie_cmdid = WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID, + .pdev_set_quiet_mode_cmdid = WMI_10_2_PDEV_SET_QUIET_MODE_CMDID, + .pdev_green_ap_ps_enable_cmdid = WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID, + .pdev_get_tpc_config_cmdid = WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID, + .pdev_set_base_macaddr_cmdid = WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID, + .vdev_create_cmdid = WMI_10_2_VDEV_CREATE_CMDID, + .vdev_delete_cmdid = WMI_10_2_VDEV_DELETE_CMDID, + .vdev_start_request_cmdid = WMI_10_2_VDEV_START_REQUEST_CMDID, + .vdev_restart_request_cmdid = WMI_10_2_VDEV_RESTART_REQUEST_CMDID, + .vdev_up_cmdid = WMI_10_2_VDEV_UP_CMDID, + .vdev_stop_cmdid = WMI_10_2_VDEV_STOP_CMDID, + .vdev_down_cmdid = WMI_10_2_VDEV_DOWN_CMDID, + .vdev_set_param_cmdid = WMI_10_2_VDEV_SET_PARAM_CMDID, + .vdev_install_key_cmdid = WMI_10_2_VDEV_INSTALL_KEY_CMDID, + .peer_create_cmdid = WMI_10_2_PEER_CREATE_CMDID, + .peer_delete_cmdid = WMI_10_2_PEER_DELETE_CMDID, + .peer_flush_tids_cmdid = WMI_10_2_PEER_FLUSH_TIDS_CMDID, + .peer_set_param_cmdid = WMI_10_2_PEER_SET_PARAM_CMDID, + .peer_assoc_cmdid = WMI_10_2_PEER_ASSOC_CMDID, + .peer_add_wds_entry_cmdid = WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID, + .peer_remove_wds_entry_cmdid = WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID, + .peer_mcast_group_cmdid = WMI_10_2_PEER_MCAST_GROUP_CMDID, + .bcn_tx_cmdid = WMI_10_2_BCN_TX_CMDID, + .pdev_send_bcn_cmdid = WMI_10_2_PDEV_SEND_BCN_CMDID, + .bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED, + .bcn_filter_rx_cmdid = WMI_10_2_BCN_FILTER_RX_CMDID, + .prb_req_filter_rx_cmdid = WMI_10_2_PRB_REQ_FILTER_RX_CMDID, + .mgmt_tx_cmdid = WMI_10_2_MGMT_TX_CMDID, + .prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED, + .addba_clear_resp_cmdid = WMI_10_2_ADDBA_CLEAR_RESP_CMDID, + .addba_send_cmdid = WMI_10_2_ADDBA_SEND_CMDID, + .addba_status_cmdid = WMI_10_2_ADDBA_STATUS_CMDID, + .delba_send_cmdid = WMI_10_2_DELBA_SEND_CMDID, + .addba_set_resp_cmdid = WMI_10_2_ADDBA_SET_RESP_CMDID, + .send_singleamsdu_cmdid = WMI_10_2_SEND_SINGLEAMSDU_CMDID, + .sta_powersave_mode_cmdid = WMI_10_2_STA_POWERSAVE_MODE_CMDID, + .sta_powersave_param_cmdid = WMI_10_2_STA_POWERSAVE_PARAM_CMDID, + .sta_mimo_ps_mode_cmdid = WMI_10_2_STA_MIMO_PS_MODE_CMDID, + .pdev_dfs_enable_cmdid = WMI_10_2_PDEV_DFS_ENABLE_CMDID, + .pdev_dfs_disable_cmdid = WMI_10_2_PDEV_DFS_DISABLE_CMDID, + .roam_scan_mode = WMI_10_2_ROAM_SCAN_MODE, + .roam_scan_rssi_threshold = WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD, + .roam_scan_period = WMI_10_2_ROAM_SCAN_PERIOD, + .roam_scan_rssi_change_threshold = + WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + .roam_ap_profile = WMI_10_2_ROAM_AP_PROFILE, + .ofl_scan_add_ap_profile = WMI_10_2_OFL_SCAN_ADD_AP_PROFILE, + .ofl_scan_remove_ap_profile = WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE, + .ofl_scan_period = WMI_10_2_OFL_SCAN_PERIOD, + .p2p_dev_set_device_info = WMI_10_2_P2P_DEV_SET_DEVICE_INFO, + .p2p_dev_set_discoverability = WMI_10_2_P2P_DEV_SET_DISCOVERABILITY, + .p2p_go_set_beacon_ie = WMI_10_2_P2P_GO_SET_BEACON_IE, + .p2p_go_set_probe_resp_ie = WMI_10_2_P2P_GO_SET_PROBE_RESP_IE, + .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED, + .ap_ps_peer_param_cmdid = WMI_10_2_AP_PS_PEER_PARAM_CMDID, + .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED, + .peer_rate_retry_sched_cmdid = WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID, + .wlan_profile_trigger_cmdid = WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID, + .wlan_profile_set_hist_intvl_cmdid = + WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + .wlan_profile_get_profile_data_cmdid = + WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + .wlan_profile_enable_profile_id_cmdid = + WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + .wlan_profile_list_profile_id_cmdid = + WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + .pdev_suspend_cmdid = WMI_10_2_PDEV_SUSPEND_CMDID, + .pdev_resume_cmdid = WMI_10_2_PDEV_RESUME_CMDID, + .add_bcn_filter_cmdid = WMI_10_2_ADD_BCN_FILTER_CMDID, + .rmv_bcn_filter_cmdid = WMI_10_2_RMV_BCN_FILTER_CMDID, + .wow_add_wake_pattern_cmdid = WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID, + .wow_del_wake_pattern_cmdid = WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID, + .wow_enable_disable_wake_event_cmdid = + WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + .wow_enable_cmdid = WMI_10_2_WOW_ENABLE_CMDID, + .wow_hostwakeup_from_sleep_cmdid = + WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + .rtt_measreq_cmdid = WMI_10_2_RTT_MEASREQ_CMDID, + .rtt_tsf_cmdid = WMI_10_2_RTT_TSF_CMDID, + .vdev_spectral_scan_configure_cmdid = + WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, + .vdev_spectral_scan_enable_cmdid = + WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, + .request_stats_cmdid = WMI_10_2_REQUEST_STATS_CMDID, + .set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED, + .network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED, + .gtk_offload_cmdid = WMI_CMD_UNSUPPORTED, + .csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED, + .csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED, + .chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED, + .peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED, + .peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED, + .sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED, + .sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED, + .sta_keepalive_cmd = WMI_CMD_UNSUPPORTED, + .echo_cmdid = WMI_10_2_ECHO_CMDID, + .pdev_utf_cmdid = WMI_10_2_PDEV_UTF_CMDID, + .dbglog_cfg_cmdid = WMI_10_2_DBGLOG_CFG_CMDID, + .pdev_qvit_cmdid = WMI_10_2_PDEV_QVIT_CMDID, + .pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED, + .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID, + .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, + .pdev_get_temperature_cmdid = WMI_10_2_PDEV_GET_TEMPERATURE_CMDID, }; /* MAIN WMI VDEV param map */ @@ -385,6 +511,64 @@ static struct wmi_vdev_param_map wmi_10x_vdev_param_map = { WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, }; +static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { + .rts_threshold = WMI_10X_VDEV_PARAM_RTS_THRESHOLD, + .fragmentation_threshold = WMI_10X_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + .beacon_interval = WMI_10X_VDEV_PARAM_BEACON_INTERVAL, + .listen_interval = WMI_10X_VDEV_PARAM_LISTEN_INTERVAL, + .multicast_rate = WMI_10X_VDEV_PARAM_MULTICAST_RATE, + .mgmt_tx_rate = WMI_10X_VDEV_PARAM_MGMT_TX_RATE, + .slot_time = WMI_10X_VDEV_PARAM_SLOT_TIME, + .preamble = WMI_10X_VDEV_PARAM_PREAMBLE, + .swba_time = WMI_10X_VDEV_PARAM_SWBA_TIME, + .wmi_vdev_stats_update_period = WMI_10X_VDEV_STATS_UPDATE_PERIOD, + .wmi_vdev_pwrsave_ageout_time = WMI_10X_VDEV_PWRSAVE_AGEOUT_TIME, + .wmi_vdev_host_swba_interval = WMI_10X_VDEV_HOST_SWBA_INTERVAL, + .dtim_period = WMI_10X_VDEV_PARAM_DTIM_PERIOD, + .wmi_vdev_oc_scheduler_air_time_limit = + WMI_10X_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, + .wds = WMI_10X_VDEV_PARAM_WDS, + .atim_window = WMI_10X_VDEV_PARAM_ATIM_WINDOW, + .bmiss_count_max = WMI_10X_VDEV_PARAM_BMISS_COUNT_MAX, + .bmiss_first_bcnt = WMI_VDEV_PARAM_UNSUPPORTED, + .bmiss_final_bcnt = WMI_VDEV_PARAM_UNSUPPORTED, + .feature_wmm = WMI_10X_VDEV_PARAM_FEATURE_WMM, + .chwidth = WMI_10X_VDEV_PARAM_CHWIDTH, + .chextoffset = WMI_10X_VDEV_PARAM_CHEXTOFFSET, + .disable_htprotection = WMI_10X_VDEV_PARAM_DISABLE_HTPROTECTION, + .sta_quickkickout = WMI_10X_VDEV_PARAM_STA_QUICKKICKOUT, + .mgmt_rate = WMI_10X_VDEV_PARAM_MGMT_RATE, + .protection_mode = WMI_10X_VDEV_PARAM_PROTECTION_MODE, + .fixed_rate = WMI_10X_VDEV_PARAM_FIXED_RATE, + .sgi = WMI_10X_VDEV_PARAM_SGI, + .ldpc = WMI_10X_VDEV_PARAM_LDPC, + .tx_stbc = WMI_10X_VDEV_PARAM_TX_STBC, + .rx_stbc = WMI_10X_VDEV_PARAM_RX_STBC, + .intra_bss_fwd = WMI_10X_VDEV_PARAM_INTRA_BSS_FWD, + .def_keyid = WMI_10X_VDEV_PARAM_DEF_KEYID, + .nss = WMI_10X_VDEV_PARAM_NSS, + .bcast_data_rate = WMI_10X_VDEV_PARAM_BCAST_DATA_RATE, + .mcast_data_rate = WMI_10X_VDEV_PARAM_MCAST_DATA_RATE, + .mcast_indicate = WMI_10X_VDEV_PARAM_MCAST_INDICATE, + .dhcp_indicate = WMI_10X_VDEV_PARAM_DHCP_INDICATE, + .unknown_dest_indicate = WMI_10X_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + .ap_keepalive_min_idle_inactive_time_secs = + WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + .ap_keepalive_max_idle_inactive_time_secs = + WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + .ap_keepalive_max_unresponsive_time_secs = + WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + .ap_enable_nawds = WMI_10X_VDEV_PARAM_AP_ENABLE_NAWDS, + .mcast2ucast_set = WMI_10X_VDEV_PARAM_MCAST2UCAST_SET, + .enable_rtscts = WMI_10X_VDEV_PARAM_ENABLE_RTSCTS, + .txbf = WMI_VDEV_PARAM_UNSUPPORTED, + .packet_powersave = WMI_VDEV_PARAM_UNSUPPORTED, + .drop_unencry = WMI_VDEV_PARAM_UNSUPPORTED, + .tx_encap_type = WMI_VDEV_PARAM_UNSUPPORTED, + .ap_detect_out_of_sync_sleeping_sta_time_secs = + WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, +}; + static struct wmi_pdev_param_map wmi_pdev_param_map = { .tx_chain_mask = WMI_PDEV_PARAM_TX_CHAIN_MASK, .rx_chain_mask = WMI_PDEV_PARAM_RX_CHAIN_MASK, @@ -434,6 +618,7 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = { .fast_channel_reset = WMI_PDEV_PARAM_UNSUPPORTED, .burst_dur = WMI_PDEV_PARAM_UNSUPPORTED, .burst_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .cal_period = WMI_PDEV_PARAM_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { @@ -486,6 +671,60 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { .fast_channel_reset = WMI_10X_PDEV_PARAM_FAST_CHANNEL_RESET, .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR, .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE, + .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, +}; + +static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = { + .tx_chain_mask = WMI_10X_PDEV_PARAM_TX_CHAIN_MASK, + .rx_chain_mask = WMI_10X_PDEV_PARAM_RX_CHAIN_MASK, + .txpower_limit2g = WMI_10X_PDEV_PARAM_TXPOWER_LIMIT2G, + .txpower_limit5g = WMI_10X_PDEV_PARAM_TXPOWER_LIMIT5G, + .txpower_scale = WMI_10X_PDEV_PARAM_TXPOWER_SCALE, + .beacon_gen_mode = WMI_10X_PDEV_PARAM_BEACON_GEN_MODE, + .beacon_tx_mode = WMI_10X_PDEV_PARAM_BEACON_TX_MODE, + .resmgr_offchan_mode = WMI_10X_PDEV_PARAM_RESMGR_OFFCHAN_MODE, + .protection_mode = WMI_10X_PDEV_PARAM_PROTECTION_MODE, + .dynamic_bw = WMI_10X_PDEV_PARAM_DYNAMIC_BW, + .non_agg_sw_retry_th = WMI_10X_PDEV_PARAM_NON_AGG_SW_RETRY_TH, + .agg_sw_retry_th = WMI_10X_PDEV_PARAM_AGG_SW_RETRY_TH, + .sta_kickout_th = WMI_10X_PDEV_PARAM_STA_KICKOUT_TH, + .ac_aggrsize_scaling = WMI_10X_PDEV_PARAM_AC_AGGRSIZE_SCALING, + .ltr_enable = WMI_10X_PDEV_PARAM_LTR_ENABLE, + .ltr_ac_latency_be = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_BE, + .ltr_ac_latency_bk = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_BK, + .ltr_ac_latency_vi = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_VI, + .ltr_ac_latency_vo = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_VO, + .ltr_ac_latency_timeout = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, + .ltr_sleep_override = WMI_10X_PDEV_PARAM_LTR_SLEEP_OVERRIDE, + .ltr_rx_override = WMI_10X_PDEV_PARAM_LTR_RX_OVERRIDE, + .ltr_tx_activity_timeout = WMI_10X_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + .l1ss_enable = WMI_10X_PDEV_PARAM_L1SS_ENABLE, + .dsleep_enable = WMI_10X_PDEV_PARAM_DSLEEP_ENABLE, + .pcielp_txbuf_flush = WMI_PDEV_PARAM_UNSUPPORTED, + .pcielp_txbuf_watermark = WMI_PDEV_PARAM_UNSUPPORTED, + .pcielp_txbuf_tmo_en = WMI_PDEV_PARAM_UNSUPPORTED, + .pcielp_txbuf_tmo_value = WMI_PDEV_PARAM_UNSUPPORTED, + .pdev_stats_update_period = WMI_10X_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, + .vdev_stats_update_period = WMI_10X_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, + .peer_stats_update_period = WMI_10X_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, + .bcnflt_stats_update_period = + WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, + .pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS, + .arp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE, + .dcs = WMI_10X_PDEV_PARAM_DCS, + .ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE, + .ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD, + .ani_listen_period = WMI_10X_PDEV_PARAM_ANI_LISTEN_PERIOD, + .ani_ofdm_level = WMI_10X_PDEV_PARAM_ANI_OFDM_LEVEL, + .ani_cck_level = WMI_10X_PDEV_PARAM_ANI_CCK_LEVEL, + .dyntxchain = WMI_10X_PDEV_PARAM_DYNTXCHAIN, + .proxy_sta = WMI_PDEV_PARAM_UNSUPPORTED, + .idle_ps_config = WMI_PDEV_PARAM_UNSUPPORTED, + .power_gating_sleep = WMI_PDEV_PARAM_UNSUPPORTED, + .fast_channel_reset = WMI_10X_PDEV_PARAM_FAST_CHANNEL_RESET, + .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR, + .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE, + .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, }; /* firmware 10.2 specific mappings */ @@ -607,11 +846,11 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED, .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, + .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, }; -static void -ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, - const struct wmi_channel_arg *arg) +void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, + const struct wmi_channel_arg *arg) { u32 flags = 0; @@ -685,8 +924,8 @@ static void ath10k_wmi_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) dev_kfree_skb(skb); } -static int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, - u32 cmd_id) +int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, + u32 cmd_id) { struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); struct wmi_cmd_hdr *cmd_hdr; @@ -717,23 +956,45 @@ err_pull: static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) { + struct ath10k *ar = arvif->ar; + struct ath10k_skb_cb *cb; + struct sk_buff *bcn; int ret; - lockdep_assert_held(&arvif->ar->data_lock); + spin_lock_bh(&ar->data_lock); - if (arvif->beacon == NULL) - return; + bcn = arvif->beacon; - if (arvif->beacon_sent) - return; + if (!bcn) + goto unlock; - ret = ath10k_wmi_beacon_send_ref_nowait(arvif); - if (ret) - return; + cb = ATH10K_SKB_CB(bcn); - /* We need to retain the arvif->beacon reference for DMA unmapping and - * freeing the skbuff later. */ - arvif->beacon_sent = true; + switch (arvif->beacon_state) { + case ATH10K_BEACON_SENDING: + case ATH10K_BEACON_SENT: + break; + case ATH10K_BEACON_SCHEDULED: + arvif->beacon_state = ATH10K_BEACON_SENDING; + spin_unlock_bh(&ar->data_lock); + + ret = ath10k_wmi_beacon_send_ref_nowait(arvif->ar, + arvif->vdev_id, + bcn->data, bcn->len, + cb->paddr, + cb->bcn.dtim_zero, + cb->bcn.deliver_cab); + + spin_lock_bh(&ar->data_lock); + + if (ret == 0) + arvif->beacon_state = ATH10K_BEACON_SENT; + else + arvif->beacon_state = ATH10K_BEACON_SCHEDULED; + } + +unlock: + spin_unlock_bh(&ar->data_lock); } static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, @@ -746,12 +1007,10 @@ static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, static void ath10k_wmi_tx_beacons_nowait(struct ath10k *ar) { - spin_lock_bh(&ar->data_lock); ieee80211_iterate_active_interfaces_atomic(ar->hw, IEEE80211_IFACE_ITER_NORMAL, ath10k_wmi_tx_beacons_iter, NULL); - spin_unlock_bh(&ar->data_lock); } static void ath10k_wmi_op_ep_tx_credits(struct ath10k *ar) @@ -792,24 +1051,23 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id) return ret; } -int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) +static struct sk_buff * +ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) { - int ret = 0; struct wmi_mgmt_tx_cmd *cmd; struct ieee80211_hdr *hdr; - struct sk_buff *wmi_skb; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct sk_buff *skb; int len; - u32 buf_len = skb->len; + u32 buf_len = msdu->len; u16 fc; - hdr = (struct ieee80211_hdr *)skb->data; + hdr = (struct ieee80211_hdr *)msdu->data; fc = le16_to_cpu(hdr->frame_control); if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control))) - return -EINVAL; + return ERR_PTR(-EINVAL); - len = sizeof(cmd->hdr) + skb->len; + len = sizeof(cmd->hdr) + msdu->len; if ((ieee80211_is_action(hdr->frame_control) || ieee80211_is_deauth(hdr->frame_control) || @@ -821,36 +1079,27 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) len = round_up(len, 4); - wmi_skb = ath10k_wmi_alloc_skb(ar, len); - if (!wmi_skb) - return -ENOMEM; + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); - cmd = (struct wmi_mgmt_tx_cmd *)wmi_skb->data; + cmd = (struct wmi_mgmt_tx_cmd *)skb->data; - cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(skb)->vdev_id); + cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(msdu)->vdev_id); cmd->hdr.tx_rate = 0; cmd->hdr.tx_power = 0; cmd->hdr.buf_len = __cpu_to_le32(buf_len); ether_addr_copy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr)); - memcpy(cmd->buf, skb->data, skb->len); + memcpy(cmd->buf, msdu->data, msdu->len); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n", - wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE, + msdu, skb->len, fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE); trace_ath10k_tx_hdr(ar, skb->data, skb->len); trace_ath10k_tx_payload(ar, skb->data, skb->len); - /* Send the management frame buffer to the target */ - ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid); - if (ret) - return ret; - - /* TODO: report tx status to mac80211 - temporary just ACK */ - info->flags |= IEEE80211_TX_STAT_ACK; - ieee80211_tx_status_irqsafe(ar->hw, skb); - - return ret; + return skb; } static void ath10k_wmi_event_scan_started(struct ath10k *ar) @@ -977,22 +1226,48 @@ ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type, } } -static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) +static int ath10k_wmi_op_pull_scan_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_scan_ev_arg *arg) { - struct wmi_scan_event *event = (struct wmi_scan_event *)skb->data; + struct wmi_scan_event *ev = (void *)skb->data; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->event_type = ev->event_type; + arg->reason = ev->reason; + arg->channel_freq = ev->channel_freq; + arg->scan_req_id = ev->scan_req_id; + arg->scan_id = ev->scan_id; + arg->vdev_id = ev->vdev_id; + + return 0; +} + +int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_scan_ev_arg arg = {}; enum wmi_scan_event_type event_type; enum wmi_scan_completion_reason reason; u32 freq; u32 req_id; u32 scan_id; u32 vdev_id; + int ret; - event_type = __le32_to_cpu(event->event_type); - reason = __le32_to_cpu(event->reason); - freq = __le32_to_cpu(event->channel_freq); - req_id = __le32_to_cpu(event->scan_req_id); - scan_id = __le32_to_cpu(event->scan_id); - vdev_id = __le32_to_cpu(event->vdev_id); + ret = ath10k_wmi_pull_scan(ar, skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse scan event: %d\n", ret); + return ret; + } + + event_type = __le32_to_cpu(arg.event_type); + reason = __le32_to_cpu(arg.reason); + freq = __le32_to_cpu(arg.channel_freq); + req_id = __le32_to_cpu(arg.scan_req_id); + scan_id = __le32_to_cpu(arg.scan_id); + vdev_id = __le32_to_cpu(arg.vdev_id); spin_lock_bh(&ar->data_lock); @@ -1147,21 +1422,14 @@ static void ath10k_wmi_handle_wep_reauth(struct ath10k *ar, } } -static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) +static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_mgmt_rx_ev_arg *arg) { struct wmi_mgmt_rx_event_v1 *ev_v1; struct wmi_mgmt_rx_event_v2 *ev_v2; struct wmi_mgmt_rx_hdr_v1 *ev_hdr; - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - struct ieee80211_hdr *hdr; - u32 rx_status; - u32 channel; - u32 phy_mode; - u32 snr; - u32 rate; - u32 buf_len; - u16 fc; - int pull_len; + size_t pull_len; + u32 msdu_len; if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) { ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data; @@ -1173,12 +1441,55 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) pull_len = sizeof(*ev_v1); } - channel = __le32_to_cpu(ev_hdr->channel); - buf_len = __le32_to_cpu(ev_hdr->buf_len); - rx_status = __le32_to_cpu(ev_hdr->status); - snr = __le32_to_cpu(ev_hdr->snr); - phy_mode = __le32_to_cpu(ev_hdr->phy_mode); - rate = __le32_to_cpu(ev_hdr->rate); + if (skb->len < pull_len) + return -EPROTO; + + skb_pull(skb, pull_len); + arg->channel = ev_hdr->channel; + arg->buf_len = ev_hdr->buf_len; + arg->status = ev_hdr->status; + arg->snr = ev_hdr->snr; + arg->phy_mode = ev_hdr->phy_mode; + arg->rate = ev_hdr->rate; + + msdu_len = __le32_to_cpu(arg->buf_len); + if (skb->len < msdu_len) + return -EPROTO; + + /* the WMI buffer might've ended up being padded to 4 bytes due to HTC + * trailer with credit update. Trim the excess garbage. + */ + skb_trim(skb, msdu_len); + + return 0; +} + +int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_mgmt_rx_ev_arg arg = {}; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_hdr *hdr; + u32 rx_status; + u32 channel; + u32 phy_mode; + u32 snr; + u32 rate; + u32 buf_len; + u16 fc; + int ret; + + ret = ath10k_wmi_pull_mgmt_rx(ar, skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse mgmt rx event: %d\n", ret); + return ret; + } + + channel = __le32_to_cpu(arg.channel); + buf_len = __le32_to_cpu(arg.buf_len); + rx_status = __le32_to_cpu(arg.status); + snr = __le32_to_cpu(arg.snr); + phy_mode = __le32_to_cpu(arg.phy_mode); + rate = __le32_to_cpu(arg.rate); memset(status, 0, sizeof(*status)); @@ -1232,8 +1543,6 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR; status->rate_idx = get_rate_idx(rate, status->band); - skb_pull(skb, pull_len); - hdr = (struct ieee80211_hdr *)skb->data; fc = le16_to_cpu(hdr->frame_control); @@ -1266,12 +1575,6 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) status->freq, status->band, status->signal, status->rate_idx); - /* - * packets from HTC come aligned to 4byte boundaries - * because they can originally come in along with a trailer - */ - skb_trim(skb, buf_len); - ieee80211_rx(ar->hw, skb); return 0; } @@ -1295,21 +1598,44 @@ exit: return idx; } -static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) +static int ath10k_wmi_op_pull_ch_info_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_ch_info_ev_arg *arg) { - struct wmi_chan_info_event *ev; + struct wmi_chan_info_event *ev = (void *)skb->data; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->err_code = ev->err_code; + arg->freq = ev->freq; + arg->cmd_flags = ev->cmd_flags; + arg->noise_floor = ev->noise_floor; + arg->rx_clear_count = ev->rx_clear_count; + arg->cycle_count = ev->cycle_count; + + return 0; +} + +void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_ch_info_ev_arg arg = {}; struct survey_info *survey; u32 err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count; - int idx; + int idx, ret; - ev = (struct wmi_chan_info_event *)skb->data; + ret = ath10k_wmi_pull_ch_info(ar, skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse chan info event: %d\n", ret); + return; + } - err_code = __le32_to_cpu(ev->err_code); - freq = __le32_to_cpu(ev->freq); - cmd_flags = __le32_to_cpu(ev->cmd_flags); - noise_floor = __le32_to_cpu(ev->noise_floor); - rx_clear_count = __le32_to_cpu(ev->rx_clear_count); - cycle_count = __le32_to_cpu(ev->cycle_count); + err_code = __le32_to_cpu(arg.err_code); + freq = __le32_to_cpu(arg.freq); + cmd_flags = __le32_to_cpu(arg.cmd_flags); + noise_floor = __le32_to_cpu(arg.noise_floor); + rx_clear_count = __le32_to_cpu(arg.rx_clear_count); + cycle_count = __le32_to_cpu(arg.cycle_count); ath10k_dbg(ar, ATH10K_DBG_WMI, "chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n", @@ -1344,11 +1670,11 @@ static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) rx_clear_count -= ar->survey_last_rx_clear_count; survey = &ar->survey[idx]; - survey->channel_time = WMI_CHAN_INFO_MSEC(cycle_count); - survey->channel_time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count); + survey->time = WMI_CHAN_INFO_MSEC(cycle_count); + survey->time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count); survey->noise = noise_floor; - survey->filled = SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_RX | + survey->filled = SURVEY_INFO_TIME | + SURVEY_INFO_TIME_RX | SURVEY_INFO_NOISE_DBM; } @@ -1359,12 +1685,12 @@ exit: spin_unlock_bh(&ar->data_lock); } -static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb) +void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n"); } -static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb) +int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug mesg len %d\n", skb->len); @@ -1374,12 +1700,9 @@ static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb) return 0; } -static void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src, - struct ath10k_fw_stats_pdev *dst) +void ath10k_wmi_pull_pdev_stats_base(const struct wmi_pdev_stats_base *src, + struct ath10k_fw_stats_pdev *dst) { - const struct wal_dbg_tx_stats *tx = &src->wal.tx; - const struct wal_dbg_rx_stats *rx = &src->wal.rx; - dst->ch_noise_floor = __le32_to_cpu(src->chan_nf); dst->tx_frame_count = __le32_to_cpu(src->tx_frame_count); dst->rx_frame_count = __le32_to_cpu(src->rx_frame_count); @@ -1387,57 +1710,76 @@ static void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src, dst->cycle_count = __le32_to_cpu(src->cycle_count); dst->phy_err_count = __le32_to_cpu(src->phy_err_count); dst->chan_tx_power = __le32_to_cpu(src->chan_tx_pwr); - - dst->comp_queued = __le32_to_cpu(tx->comp_queued); - dst->comp_delivered = __le32_to_cpu(tx->comp_delivered); - dst->msdu_enqued = __le32_to_cpu(tx->msdu_enqued); - dst->mpdu_enqued = __le32_to_cpu(tx->mpdu_enqued); - dst->wmm_drop = __le32_to_cpu(tx->wmm_drop); - dst->local_enqued = __le32_to_cpu(tx->local_enqued); - dst->local_freed = __le32_to_cpu(tx->local_freed); - dst->hw_queued = __le32_to_cpu(tx->hw_queued); - dst->hw_reaped = __le32_to_cpu(tx->hw_reaped); - dst->underrun = __le32_to_cpu(tx->underrun); - dst->tx_abort = __le32_to_cpu(tx->tx_abort); - dst->mpdus_requed = __le32_to_cpu(tx->mpdus_requed); - dst->tx_ko = __le32_to_cpu(tx->tx_ko); - dst->data_rc = __le32_to_cpu(tx->data_rc); - dst->self_triggers = __le32_to_cpu(tx->self_triggers); - dst->sw_retry_failure = __le32_to_cpu(tx->sw_retry_failure); - dst->illgl_rate_phy_err = __le32_to_cpu(tx->illgl_rate_phy_err); - dst->pdev_cont_xretry = __le32_to_cpu(tx->pdev_cont_xretry); - dst->pdev_tx_timeout = __le32_to_cpu(tx->pdev_tx_timeout); - dst->pdev_resets = __le32_to_cpu(tx->pdev_resets); - dst->phy_underrun = __le32_to_cpu(tx->phy_underrun); - dst->txop_ovf = __le32_to_cpu(tx->txop_ovf); - - dst->mid_ppdu_route_change = __le32_to_cpu(rx->mid_ppdu_route_change); - dst->status_rcvd = __le32_to_cpu(rx->status_rcvd); - dst->r0_frags = __le32_to_cpu(rx->r0_frags); - dst->r1_frags = __le32_to_cpu(rx->r1_frags); - dst->r2_frags = __le32_to_cpu(rx->r2_frags); - dst->r3_frags = __le32_to_cpu(rx->r3_frags); - dst->htt_msdus = __le32_to_cpu(rx->htt_msdus); - dst->htt_mpdus = __le32_to_cpu(rx->htt_mpdus); - dst->loc_msdus = __le32_to_cpu(rx->loc_msdus); - dst->loc_mpdus = __le32_to_cpu(rx->loc_mpdus); - dst->oversize_amsdu = __le32_to_cpu(rx->oversize_amsdu); - dst->phy_errs = __le32_to_cpu(rx->phy_errs); - dst->phy_err_drop = __le32_to_cpu(rx->phy_err_drop); - dst->mpdu_errs = __le32_to_cpu(rx->mpdu_errs); } -static void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src, - struct ath10k_fw_stats_peer *dst) +void ath10k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src, + struct ath10k_fw_stats_pdev *dst) +{ + dst->comp_queued = __le32_to_cpu(src->comp_queued); + dst->comp_delivered = __le32_to_cpu(src->comp_delivered); + dst->msdu_enqued = __le32_to_cpu(src->msdu_enqued); + dst->mpdu_enqued = __le32_to_cpu(src->mpdu_enqued); + dst->wmm_drop = __le32_to_cpu(src->wmm_drop); + dst->local_enqued = __le32_to_cpu(src->local_enqued); + dst->local_freed = __le32_to_cpu(src->local_freed); + dst->hw_queued = __le32_to_cpu(src->hw_queued); + dst->hw_reaped = __le32_to_cpu(src->hw_reaped); + dst->underrun = __le32_to_cpu(src->underrun); + dst->tx_abort = __le32_to_cpu(src->tx_abort); + dst->mpdus_requed = __le32_to_cpu(src->mpdus_requed); + dst->tx_ko = __le32_to_cpu(src->tx_ko); + dst->data_rc = __le32_to_cpu(src->data_rc); + dst->self_triggers = __le32_to_cpu(src->self_triggers); + dst->sw_retry_failure = __le32_to_cpu(src->sw_retry_failure); + dst->illgl_rate_phy_err = __le32_to_cpu(src->illgl_rate_phy_err); + dst->pdev_cont_xretry = __le32_to_cpu(src->pdev_cont_xretry); + dst->pdev_tx_timeout = __le32_to_cpu(src->pdev_tx_timeout); + dst->pdev_resets = __le32_to_cpu(src->pdev_resets); + dst->phy_underrun = __le32_to_cpu(src->phy_underrun); + dst->txop_ovf = __le32_to_cpu(src->txop_ovf); +} + +void ath10k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src, + struct ath10k_fw_stats_pdev *dst) +{ + dst->mid_ppdu_route_change = __le32_to_cpu(src->mid_ppdu_route_change); + dst->status_rcvd = __le32_to_cpu(src->status_rcvd); + dst->r0_frags = __le32_to_cpu(src->r0_frags); + dst->r1_frags = __le32_to_cpu(src->r1_frags); + dst->r2_frags = __le32_to_cpu(src->r2_frags); + dst->r3_frags = __le32_to_cpu(src->r3_frags); + dst->htt_msdus = __le32_to_cpu(src->htt_msdus); + dst->htt_mpdus = __le32_to_cpu(src->htt_mpdus); + dst->loc_msdus = __le32_to_cpu(src->loc_msdus); + dst->loc_mpdus = __le32_to_cpu(src->loc_mpdus); + dst->oversize_amsdu = __le32_to_cpu(src->oversize_amsdu); + dst->phy_errs = __le32_to_cpu(src->phy_errs); + dst->phy_err_drop = __le32_to_cpu(src->phy_err_drop); + dst->mpdu_errs = __le32_to_cpu(src->mpdu_errs); +} + +void ath10k_wmi_pull_pdev_stats_extra(const struct wmi_pdev_stats_extra *src, + struct ath10k_fw_stats_pdev *dst) +{ + dst->ack_rx_bad = __le32_to_cpu(src->ack_rx_bad); + dst->rts_bad = __le32_to_cpu(src->rts_bad); + dst->rts_good = __le32_to_cpu(src->rts_good); + dst->fcs_bad = __le32_to_cpu(src->fcs_bad); + dst->no_beacons = __le32_to_cpu(src->no_beacons); + dst->mib_int_count = __le32_to_cpu(src->mib_int_count); +} + +void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src, + struct ath10k_fw_stats_peer *dst) { ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr); dst->peer_rssi = __le32_to_cpu(src->peer_rssi); dst->peer_tx_rate = __le32_to_cpu(src->peer_tx_rate); } -static int ath10k_wmi_main_pull_fw_stats(struct ath10k *ar, - struct sk_buff *skb, - struct ath10k_fw_stats *stats) +static int ath10k_wmi_main_op_pull_fw_stats(struct ath10k *ar, + struct sk_buff *skb, + struct ath10k_fw_stats *stats) { const struct wmi_stats_event *ev = (void *)skb->data; u32 num_pdev_stats, num_vdev_stats, num_peer_stats; @@ -1462,7 +1804,10 @@ static int ath10k_wmi_main_pull_fw_stats(struct ath10k *ar, if (!dst) continue; - ath10k_wmi_pull_pdev_stats(src, dst); + ath10k_wmi_pull_pdev_stats_base(&src->base, dst); + ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst); + ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); + list_add_tail(&dst->list, &stats->pdevs); } @@ -1487,9 +1832,9 @@ static int ath10k_wmi_main_pull_fw_stats(struct ath10k *ar, return 0; } -static int ath10k_wmi_10x_pull_fw_stats(struct ath10k *ar, - struct sk_buff *skb, - struct ath10k_fw_stats *stats) +static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k *ar, + struct sk_buff *skb, + struct ath10k_fw_stats *stats) { const struct wmi_stats_event *ev = (void *)skb->data; u32 num_pdev_stats, num_vdev_stats, num_peer_stats; @@ -1514,14 +1859,10 @@ static int ath10k_wmi_10x_pull_fw_stats(struct ath10k *ar, if (!dst) continue; - ath10k_wmi_pull_pdev_stats(&src->old, dst); - - dst->ack_rx_bad = __le32_to_cpu(src->ack_rx_bad); - dst->rts_bad = __le32_to_cpu(src->rts_bad); - dst->rts_good = __le32_to_cpu(src->rts_good); - dst->fcs_bad = __le32_to_cpu(src->fcs_bad); - dst->no_beacons = __le32_to_cpu(src->no_beacons); - dst->mib_int_count = __le32_to_cpu(src->mib_int_count); + ath10k_wmi_pull_pdev_stats_base(&src->base, dst); + ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst); + ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); + ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst); list_add_tail(&dst->list, &stats->pdevs); } @@ -1550,61 +1891,250 @@ static int ath10k_wmi_10x_pull_fw_stats(struct ath10k *ar, return 0; } -int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb, - struct ath10k_fw_stats *stats) +static int ath10k_wmi_10_2_op_pull_fw_stats(struct ath10k *ar, + struct sk_buff *skb, + struct ath10k_fw_stats *stats) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - return ath10k_wmi_10x_pull_fw_stats(ar, skb, stats); - else - return ath10k_wmi_main_pull_fw_stats(ar, skb, stats); + const struct wmi_10_2_stats_event *ev = (void *)skb->data; + u32 num_pdev_stats; + u32 num_pdev_ext_stats; + u32 num_vdev_stats; + u32 num_peer_stats; + int i; + + if (!skb_pull(skb, sizeof(*ev))) + return -EPROTO; + + num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); + num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats); + num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); + num_peer_stats = __le32_to_cpu(ev->num_peer_stats); + + for (i = 0; i < num_pdev_stats; i++) { + const struct wmi_10_2_pdev_stats *src; + struct ath10k_fw_stats_pdev *dst; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ath10k_wmi_pull_pdev_stats_base(&src->base, dst); + ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst); + ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); + ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst); + /* FIXME: expose 10.2 specific values */ + + list_add_tail(&dst->list, &stats->pdevs); + } + + for (i = 0; i < num_pdev_ext_stats; i++) { + const struct wmi_10_2_pdev_ext_stats *src; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + /* FIXME: expose values to userspace + * + * Note: Even though this loop seems to do nothing it is + * required to parse following sub-structures properly. + */ + } + + /* fw doesn't implement vdev stats */ + + for (i = 0; i < num_peer_stats; i++) { + const struct wmi_10_2_peer_stats *src; + struct ath10k_fw_stats_peer *dst; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ath10k_wmi_pull_peer_stats(&src->old, dst); + + dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate); + /* FIXME: expose 10.2 specific values */ + + list_add_tail(&dst->list, &stats->peers); + } + + return 0; } -static void ath10k_wmi_event_update_stats(struct ath10k *ar, - struct sk_buff *skb) +static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar, + struct sk_buff *skb, + struct ath10k_fw_stats *stats) +{ + const struct wmi_10_2_stats_event *ev = (void *)skb->data; + u32 num_pdev_stats; + u32 num_pdev_ext_stats; + u32 num_vdev_stats; + u32 num_peer_stats; + int i; + + if (!skb_pull(skb, sizeof(*ev))) + return -EPROTO; + + num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); + num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats); + num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); + num_peer_stats = __le32_to_cpu(ev->num_peer_stats); + + for (i = 0; i < num_pdev_stats; i++) { + const struct wmi_10_2_pdev_stats *src; + struct ath10k_fw_stats_pdev *dst; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ath10k_wmi_pull_pdev_stats_base(&src->base, dst); + ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst); + ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst); + ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst); + /* FIXME: expose 10.2 specific values */ + + list_add_tail(&dst->list, &stats->pdevs); + } + + for (i = 0; i < num_pdev_ext_stats; i++) { + const struct wmi_10_2_pdev_ext_stats *src; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + /* FIXME: expose values to userspace + * + * Note: Even though this loop seems to do nothing it is + * required to parse following sub-structures properly. + */ + } + + /* fw doesn't implement vdev stats */ + + for (i = 0; i < num_peer_stats; i++) { + const struct wmi_10_2_4_peer_stats *src; + struct ath10k_fw_stats_peer *dst; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ath10k_wmi_pull_peer_stats(&src->common.old, dst); + + dst->peer_rx_rate = __le32_to_cpu(src->common.peer_rx_rate); + /* FIXME: expose 10.2 specific values */ + + list_add_tail(&dst->list, &stats->peers); + } + + return 0; +} + +void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n"); ath10k_debug_fw_stats_process(ar, skb); } -static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, - struct sk_buff *skb) +static int +ath10k_wmi_op_pull_vdev_start_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_vdev_start_ev_arg *arg) { - struct wmi_vdev_start_response_event *ev; + struct wmi_vdev_start_response_event *ev = (void *)skb->data; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->vdev_id = ev->vdev_id; + arg->req_id = ev->req_id; + arg->resp_type = ev->resp_type; + arg->status = ev->status; + + return 0; +} + +void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_vdev_start_ev_arg arg = {}; + int ret; ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n"); - ev = (struct wmi_vdev_start_response_event *)skb->data; + ret = ath10k_wmi_pull_vdev_start(ar, skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse vdev start event: %d\n", ret); + return; + } - if (WARN_ON(__le32_to_cpu(ev->status))) + if (WARN_ON(__le32_to_cpu(arg.status))) return; complete(&ar->vdev_setup_done); } -static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n"); complete(&ar->vdev_setup_done); } -static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, - struct sk_buff *skb) +static int +ath10k_wmi_op_pull_peer_kick_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_peer_kick_ev_arg *arg) { - struct wmi_peer_sta_kickout_event *ev; - struct ieee80211_sta *sta; + struct wmi_peer_sta_kickout_event *ev = (void *)skb->data; - ev = (struct wmi_peer_sta_kickout_event *)skb->data; + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->mac_addr = ev->peer_macaddr.addr; + + return 0; +} + +void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_peer_kick_ev_arg arg = {}; + struct ieee80211_sta *sta; + int ret; + + ret = ath10k_wmi_pull_peer_kick(ar, skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse peer kickout event: %d\n", + ret); + return; + } ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n", - ev->peer_macaddr.addr); + arg.mac_addr); rcu_read_lock(); - sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL); + sta = ieee80211_find_sta_by_ifaddr(ar->hw, arg.mac_addr, NULL); if (!sta) { ath10k_warn(ar, "Spurious quick kickout for STA %pM\n", - ev->peer_macaddr.addr); + arg.mac_addr); goto exit; } @@ -1641,7 +2171,7 @@ exit: static void ath10k_wmi_update_tim(struct ath10k *ar, struct ath10k_vif *arvif, struct sk_buff *bcn, - struct wmi_bcn_info *bcn_info) + const struct wmi_tim_info *tim_info) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)bcn->data; struct ieee80211_tim_ie *tim; @@ -1652,14 +2182,14 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, /* if next SWBA has no tim_changed the tim_bitmap is garbage. * we must copy the bitmap upon change and reuse it later */ - if (__le32_to_cpu(bcn_info->tim_info.tim_changed)) { + if (__le32_to_cpu(tim_info->tim_changed)) { int i; BUILD_BUG_ON(sizeof(arvif->u.ap.tim_bitmap) != - sizeof(bcn_info->tim_info.tim_bitmap)); + sizeof(tim_info->tim_bitmap)); for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) { - t = bcn_info->tim_info.tim_bitmap[i / 4]; + t = tim_info->tim_bitmap[i / 4]; v = __le32_to_cpu(t); arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF; } @@ -1711,13 +2241,13 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, return; } - tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast); + tim->bitmap_ctrl = !!__le32_to_cpu(tim_info->tim_mcast); memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len); if (tim->dtim_count == 0) { ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true; - if (__le32_to_cpu(bcn_info->tim_info.tim_mcast) == 1) + if (__le32_to_cpu(tim_info->tim_mcast) == 1) ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true; } @@ -1727,7 +2257,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, } static void ath10k_p2p_fill_noa_ie(u8 *data, u32 len, - struct wmi_p2p_noa_info *noa) + const struct wmi_p2p_noa_info *noa) { struct ieee80211_p2p_noa_attr *noa_attr; u8 ctwindow_oppps = noa->ctwindow_oppps; @@ -1769,7 +2299,7 @@ static void ath10k_p2p_fill_noa_ie(u8 *data, u32 len, *noa_attr_len = __cpu_to_le16(attr_len); } -static u32 ath10k_p2p_calc_noa_ie_len(struct wmi_p2p_noa_info *noa) +static u32 ath10k_p2p_calc_noa_ie_len(const struct wmi_p2p_noa_info *noa) { u32 len = 0; u8 noa_descriptors = noa->num_descriptors; @@ -1789,9 +2319,8 @@ static u32 ath10k_p2p_calc_noa_ie_len(struct wmi_p2p_noa_info *noa) static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif, struct sk_buff *bcn, - struct wmi_bcn_info *bcn_info) + const struct wmi_p2p_noa_info *noa) { - struct wmi_p2p_noa_info *noa = &bcn_info->p2p_noa_info; u8 *new_data, *old_data = arvif->u.ap.noa_data; u32 new_len; @@ -1832,22 +2361,59 @@ cleanup: kfree(old_data); } -static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) +static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_swba_ev_arg *arg) { - struct wmi_host_swba_event *ev; + struct wmi_host_swba_event *ev = (void *)skb->data; + u32 map; + size_t i; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->vdev_map = ev->vdev_map; + + for (i = 0, map = __le32_to_cpu(ev->vdev_map); map; map >>= 1) { + if (!(map & BIT(0))) + continue; + + /* If this happens there were some changes in firmware and + * ath10k should update the max size of tim_info array. + */ + if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info))) + break; + + arg->tim_info[i] = &ev->bcn_info[i].tim_info; + arg->noa_info[i] = &ev->bcn_info[i].p2p_noa_info; + i++; + } + + return 0; +} + +void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_swba_ev_arg arg = {}; u32 map; int i = -1; - struct wmi_bcn_info *bcn_info; + const struct wmi_tim_info *tim_info; + const struct wmi_p2p_noa_info *noa_info; struct ath10k_vif *arvif; struct sk_buff *bcn; dma_addr_t paddr; int ret, vdev_id = 0; - ev = (struct wmi_host_swba_event *)skb->data; - map = __le32_to_cpu(ev->vdev_map); + ret = ath10k_wmi_pull_swba(ar, skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse swba event: %d\n", ret); + return; + } + + map = __le32_to_cpu(arg.vdev_map); ath10k_dbg(ar, ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n", - ev->vdev_map); + map); for (; map; map >>= 1, vdev_id++) { if (!(map & 0x1)) @@ -1860,19 +2426,20 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) break; } - bcn_info = &ev->bcn_info[i]; + tim_info = arg.tim_info[i]; + noa_info = arg.noa_info[i]; ath10k_dbg(ar, ATH10K_DBG_MGMT, "mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n", i, - __le32_to_cpu(bcn_info->tim_info.tim_len), - __le32_to_cpu(bcn_info->tim_info.tim_mcast), - __le32_to_cpu(bcn_info->tim_info.tim_changed), - __le32_to_cpu(bcn_info->tim_info.tim_num_ps_pending), - __le32_to_cpu(bcn_info->tim_info.tim_bitmap[3]), - __le32_to_cpu(bcn_info->tim_info.tim_bitmap[2]), - __le32_to_cpu(bcn_info->tim_info.tim_bitmap[1]), - __le32_to_cpu(bcn_info->tim_info.tim_bitmap[0])); + __le32_to_cpu(tim_info->tim_len), + __le32_to_cpu(tim_info->tim_mcast), + __le32_to_cpu(tim_info->tim_changed), + __le32_to_cpu(tim_info->tim_num_ps_pending), + __le32_to_cpu(tim_info->tim_bitmap[3]), + __le32_to_cpu(tim_info->tim_bitmap[2]), + __le32_to_cpu(tim_info->tim_bitmap[1]), + __le32_to_cpu(tim_info->tim_bitmap[0])); arvif = ath10k_get_arvif(ar, vdev_id); if (arvif == NULL) { @@ -1899,15 +2466,25 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) } ath10k_tx_h_seq_no(arvif->vif, bcn); - ath10k_wmi_update_tim(ar, arvif, bcn, bcn_info); - ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info); + ath10k_wmi_update_tim(ar, arvif, bcn, tim_info); + ath10k_wmi_update_noa(ar, arvif, bcn, noa_info); spin_lock_bh(&ar->data_lock); if (arvif->beacon) { - if (!arvif->beacon_sent) - ath10k_warn(ar, "SWBA overrun on vdev %d\n", + switch (arvif->beacon_state) { + case ATH10K_BEACON_SENT: + break; + case ATH10K_BEACON_SCHEDULED: + ath10k_warn(ar, "SWBA overrun on vdev %d, skipped old beacon\n", arvif->vdev_id); + break; + case ATH10K_BEACON_SENDING: + ath10k_warn(ar, "SWBA overrun on vdev %d, skipped new beacon\n", + arvif->vdev_id); + dev_kfree_skb(bcn); + goto skip; + } ath10k_mac_vif_beacon_free(arvif); } @@ -1935,19 +2512,19 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) } arvif->beacon = bcn; - arvif->beacon_sent = false; + arvif->beacon_state = ATH10K_BEACON_SCHEDULED; trace_ath10k_tx_hdr(ar, bcn->data, bcn->len); trace_ath10k_tx_payload(ar, bcn->data, bcn->len); - ath10k_wmi_tx_beacon_nowait(arvif); skip: spin_unlock_bh(&ar->data_lock); } + + ath10k_wmi_tx_beacons_nowait(ar); } -static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n"); } @@ -2068,9 +2645,9 @@ static int ath10k_dfs_fft_report(struct ath10k *ar, return 0; } -static void ath10k_wmi_event_dfs(struct ath10k *ar, - const struct wmi_phyerr *phyerr, - u64 tsf) +void ath10k_wmi_event_dfs(struct ath10k *ar, + const struct wmi_phyerr *phyerr, + u64 tsf) { int buf_len, tlv_len, res, i = 0; const struct phyerr_tlv *tlv; @@ -2133,10 +2710,9 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar, } } -static void -ath10k_wmi_event_spectral_scan(struct ath10k *ar, - const struct wmi_phyerr *phyerr, - u64 tsf) +void ath10k_wmi_event_spectral_scan(struct ath10k *ar, + const struct wmi_phyerr *phyerr, + u64 tsf) { int buf_len, tlv_len, res, i = 0; struct phyerr_tlv *tlv; @@ -2188,37 +2764,53 @@ ath10k_wmi_event_spectral_scan(struct ath10k *ar, } } -static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) +static int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_phyerr_ev_arg *arg) { - const struct wmi_phyerr_event *ev; + struct wmi_phyerr_event *ev = (void *)skb->data; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + arg->num_phyerrs = ev->num_phyerrs; + arg->tsf_l32 = ev->tsf_l32; + arg->tsf_u32 = ev->tsf_u32; + arg->buf_len = __cpu_to_le32(skb->len - sizeof(*ev)); + arg->phyerrs = ev->phyerrs; + + return 0; +} + +void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_phyerr_ev_arg arg = {}; const struct wmi_phyerr *phyerr; u32 count, i, buf_len, phy_err_code; u64 tsf; - int left_len = skb->len; + int left_len, ret; ATH10K_DFS_STAT_INC(ar, phy_errors); - /* Check if combined event available */ - if (left_len < sizeof(*ev)) { - ath10k_warn(ar, "wmi phyerr combined event wrong len\n"); + ret = ath10k_wmi_pull_phyerr(ar, skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse phyerr event: %d\n", ret); return; } - left_len -= sizeof(*ev); + left_len = __le32_to_cpu(arg.buf_len); /* Check number of included events */ - ev = (const struct wmi_phyerr_event *)skb->data; - count = __le32_to_cpu(ev->num_phyerrs); + count = __le32_to_cpu(arg.num_phyerrs); - tsf = __le32_to_cpu(ev->tsf_u32); + tsf = __le32_to_cpu(arg.tsf_u32); tsf <<= 32; - tsf |= __le32_to_cpu(ev->tsf_l32); + tsf |= __le32_to_cpu(arg.tsf_l32); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event phyerr count %d tsf64 0x%llX\n", count, tsf); - phyerr = ev->phyerrs; + phyerr = arg.phyerrs; for (i = 0; i < count; i++) { /* Check if we can read event header */ if (left_len < sizeof(*phyerr)) { @@ -2258,19 +2850,17 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) } } -static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb) +void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n"); } -static void ath10k_wmi_event_profile_match(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n"); } -static void ath10k_wmi_event_debug_print(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_debug_print(struct ath10k *ar, struct sk_buff *skb) { char buf[101], c; int i; @@ -2303,103 +2893,90 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar, ath10k_dbg(ar, ATH10K_DBG_WMI_PRINT, "wmi print '%s'\n", buf); } -static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb) +void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n"); } -static void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n"); } -static void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar, + struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n"); } -static void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar, + struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n"); } -static void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n"); } -static void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n"); } -static void ath10k_wmi_event_dcs_interference(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n"); } -static void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n"); } -static void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n"); } -static void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n"); } -static void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n"); } -static void ath10k_wmi_event_delba_complete(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_delba_complete(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n"); } -static void ath10k_wmi_event_addba_complete(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_addba_complete(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n"); } -static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar, + struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n"); } -static void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n"); } -static void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n"); } -static void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb) { ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n"); } @@ -2435,8 +3012,9 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id, return 0; } -static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb, - struct wmi_svc_rdy_ev_arg *arg) +static int +ath10k_wmi_main_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_svc_rdy_ev_arg *arg) { struct wmi_service_ready_event *ev; size_t i, n; @@ -2471,8 +3049,9 @@ static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb, return 0; } -static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb, - struct wmi_svc_rdy_ev_arg *arg) +static int +ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_svc_rdy_ev_arg *arg) { struct wmi_10x_service_ready_event *ev; int i, n; @@ -2506,30 +3085,22 @@ static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb, return 0; } -static void ath10k_wmi_event_service_ready(struct ath10k *ar, - struct sk_buff *skb) +void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) { struct wmi_svc_rdy_ev_arg arg = {}; u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i; int ret; - memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map)); - - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - ret = ath10k_wmi_10x_pull_svc_rdy_ev(skb, &arg); - wmi_10x_svc_map(arg.service_map, ar->wmi.svc_map, - arg.service_map_len); - } else { - ret = ath10k_wmi_main_pull_svc_rdy_ev(skb, &arg); - wmi_main_svc_map(arg.service_map, ar->wmi.svc_map, - arg.service_map_len); - } - + ret = ath10k_wmi_pull_svc_rdy(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse service ready: %d\n", ret); return; } + memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map)); + ath10k_wmi_map_svc(ar, arg.service_map, ar->wmi.svc_map, + arg.service_map_len); + ar->hw_min_tx_power = __le32_to_cpu(arg.min_tx_power); ar->hw_max_tx_power = __le32_to_cpu(arg.max_tx_power); ar->ht_cap_info = __le32_to_cpu(arg.ht_cap); @@ -2607,13 +3178,14 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar, } ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n", + "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x fw_build 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n", __le32_to_cpu(arg.min_tx_power), __le32_to_cpu(arg.max_tx_power), __le32_to_cpu(arg.ht_cap), __le32_to_cpu(arg.vht_cap), __le32_to_cpu(arg.sw_ver0), __le32_to_cpu(arg.sw_ver1), + __le32_to_cpu(arg.fw_build), __le32_to_cpu(arg.phy_capab), __le32_to_cpu(arg.num_rf_chains), __le32_to_cpu(arg.eeprom_rd), @@ -2622,27 +3194,59 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar, complete(&ar->wmi.service_ready); } -static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) +static int ath10k_wmi_op_pull_rdy_ev(struct ath10k *ar, struct sk_buff *skb, + struct wmi_rdy_ev_arg *arg) { - struct wmi_ready_event *ev = (struct wmi_ready_event *)skb->data; + struct wmi_ready_event *ev = (void *)skb->data; - if (WARN_ON(skb->len < sizeof(*ev))) - return -EINVAL; + if (skb->len < sizeof(*ev)) + return -EPROTO; - ether_addr_copy(ar->mac_addr, ev->mac_addr.addr); + skb_pull(skb, sizeof(*ev)); + arg->sw_version = ev->sw_version; + arg->abi_version = ev->abi_version; + arg->status = ev->status; + arg->mac_addr = ev->mac_addr.addr; + + return 0; +} + +int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_rdy_ev_arg arg = {}; + int ret; + + ret = ath10k_wmi_pull_rdy(ar, skb, &arg); + if (ret) { + ath10k_warn(ar, "failed to parse ready event: %d\n", ret); + return ret; + } ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n", - __le32_to_cpu(ev->sw_version), - __le32_to_cpu(ev->abi_version), - ev->mac_addr.addr, - __le32_to_cpu(ev->status), skb->len, sizeof(*ev)); + "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n", + __le32_to_cpu(arg.sw_version), + __le32_to_cpu(arg.abi_version), + arg.mac_addr, + __le32_to_cpu(arg.status)); + ether_addr_copy(ar->mac_addr, arg.mac_addr); complete(&ar->wmi.unified_ready); return 0; } -static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb) +static int ath10k_wmi_event_temperature(struct ath10k *ar, struct sk_buff *skb) +{ + const struct wmi_pdev_temperature_event *ev; + + ev = (struct wmi_pdev_temperature_event *)skb->data; + if (WARN_ON(skb->len < sizeof(*ev))) + return -EPROTO; + + ath10k_thermal_event_temperature(ar, __le32_to_cpu(ev->temperature)); + return 0; +} + +static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; enum wmi_event_id id; @@ -2758,7 +3362,7 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb) dev_kfree_skb(skb); } -static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb) +static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; enum wmi_10x_event_id id; @@ -2882,7 +3486,7 @@ out: dev_kfree_skb(skb); } -static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb) +static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; enum wmi_10_2_event_id id; @@ -2981,6 +3585,9 @@ static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_2_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; + case WMI_10_2_PDEV_TEMPERATURE_EVENTID: + ath10k_wmi_event_temperature(ar, skb); + break; case WMI_10_2_RTT_KEEPALIVE_EVENTID: case WMI_10_2_GPIO_INPUT_EVENTID: case WMI_10_2_PEER_RATECODE_LIST_EVENTID: @@ -3001,14 +3608,11 @@ static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb) static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) - ath10k_wmi_10_2_process_rx(ar, skb); - else - ath10k_wmi_10x_process_rx(ar, skb); - } else { - ath10k_wmi_main_process_rx(ar, skb); - } + int ret; + + ret = ath10k_wmi_rx(ar, skb); + if (ret) + ath10k_warn(ar, "failed to process wmi rx: %d\n", ret); } int ath10k_wmi_connect(struct ath10k *ar) @@ -3039,16 +3643,17 @@ int ath10k_wmi_connect(struct ath10k *ar) return 0; } -static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd, - u16 rd2g, u16 rd5g, u16 ctl2g, - u16 ctl5g) +static struct sk_buff * +ath10k_wmi_op_gen_pdev_set_rd(struct ath10k *ar, u16 rd, u16 rd2g, u16 rd5g, + u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg) { struct wmi_pdev_set_regdomain_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_pdev_set_regdomain_cmd *)skb->data; cmd->reg_domain = __cpu_to_le32(rd); @@ -3060,22 +3665,20 @@ static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x\n", rd, rd2g, rd5g, ctl2g, ctl5g); - - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->pdev_set_regdomain_cmdid); + return skb; } -static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd, - u16 rd2g, u16 rd5g, - u16 ctl2g, u16 ctl5g, - enum wmi_dfs_region dfs_reg) +static struct sk_buff * +ath10k_wmi_10x_op_gen_pdev_set_rd(struct ath10k *ar, u16 rd, u16 rd2g, u16 + rd5g, u16 ctl2g, u16 ctl5g, + enum wmi_dfs_region dfs_reg) { struct wmi_pdev_set_regdomain_cmd_10x *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_pdev_set_regdomain_cmd_10x *)skb->data; cmd->reg_domain = __cpu_to_le32(rd); @@ -3088,50 +3691,39 @@ static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n", rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg); - - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->pdev_set_regdomain_cmdid); + return skb; } -int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, - u16 rd5g, u16 ctl2g, u16 ctl5g, - enum wmi_dfs_region dfs_reg) -{ - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - return ath10k_wmi_10x_pdev_set_regdomain(ar, rd, rd2g, rd5g, - ctl2g, ctl5g, dfs_reg); - else - return ath10k_wmi_main_pdev_set_regdomain(ar, rd, rd2g, rd5g, - ctl2g, ctl5g); -} - -int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt) +static struct sk_buff * +ath10k_wmi_op_gen_pdev_suspend(struct ath10k *ar, u32 suspend_opt) { struct wmi_pdev_suspend_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_pdev_suspend_cmd *)skb->data; cmd->suspend_opt = __cpu_to_le32(suspend_opt); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid); + return skb; } -int ath10k_wmi_pdev_resume_target(struct ath10k *ar) +static struct sk_buff * +ath10k_wmi_op_gen_pdev_resume(struct ath10k *ar) { struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, 0); - if (skb == NULL) - return -ENOMEM; + if (!skb) + return ERR_PTR(-ENOMEM); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_resume_cmdid); + return skb; } -int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value) +static struct sk_buff * +ath10k_wmi_op_gen_pdev_set_param(struct ath10k *ar, u32 id, u32 value) { struct wmi_pdev_set_param_cmd *cmd; struct sk_buff *skb; @@ -3139,12 +3731,12 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value) if (id == WMI_PDEV_PARAM_UNSUPPORTED) { ath10k_warn(ar, "pdev param %d not supported by firmware\n", id); - return -EOPNOTSUPP; + return ERR_PTR(-EOPNOTSUPP); } skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_pdev_set_param_cmd *)skb->data; cmd->param_id = __cpu_to_le32(id); @@ -3152,11 +3744,11 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value) ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n", id, value); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid); + return skb; } -static void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar, - struct wmi_host_mem_chunks *chunks) +void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar, + struct wmi_host_mem_chunks *chunks) { struct host_memory_chunk *chunk; int i; @@ -3177,7 +3769,7 @@ static void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar, } } -static int ath10k_wmi_main_cmd_init(struct ath10k *ar) +static struct sk_buff *ath10k_wmi_op_gen_init(struct ath10k *ar) { struct wmi_init_cmd *cmd; struct sk_buff *buf; @@ -3240,7 +3832,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) buf = ath10k_wmi_alloc_skb(ar, len); if (!buf) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_init_cmd *)buf->data; @@ -3248,10 +3840,10 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n"); - return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); + return buf; } -static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) +static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar) { struct wmi_init_cmd_10x *cmd; struct sk_buff *buf; @@ -3306,7 +3898,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) buf = ath10k_wmi_alloc_skb(ar, len); if (!buf) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_init_cmd_10x *)buf->data; @@ -3314,15 +3906,15 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n"); - return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); + return buf; } -static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar) +static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) { struct wmi_init_cmd_10_2 *cmd; struct sk_buff *buf; struct wmi_resource_config_10x config = {}; - u32 len, val; + u32 len, val, features; config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS); config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS); @@ -3356,7 +3948,7 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar) config.mcast2ucast_mode = __cpu_to_le32(TARGET_10X_MCAST2UCAST_MODE); config.tx_dbg_log_size = __cpu_to_le32(TARGET_10X_TX_DBG_LOG_SIZE); config.num_wds_entries = __cpu_to_le32(TARGET_10X_NUM_WDS_ENTRIES); - config.dma_burst_size = __cpu_to_le32(TARGET_10X_DMA_BURST_SIZE); + config.dma_burst_size = __cpu_to_le32(TARGET_10_2_DMA_BURST_SIZE); config.mac_aggr_delim = __cpu_to_le32(TARGET_10X_MAC_AGGR_DELIM); val = TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK; @@ -3372,34 +3964,21 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar) buf = ath10k_wmi_alloc_skb(ar, len); if (!buf) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_init_cmd_10_2 *)buf->data; + features = WMI_10_2_RX_BATCH_MODE; + cmd->resource_config.feature_mask = __cpu_to_le32(features); + memcpy(&cmd->resource_config.common, &config, sizeof(config)); ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n"); - return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); + return buf; } -int ath10k_wmi_cmd_init(struct ath10k *ar) -{ - int ret; - - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) - ret = ath10k_wmi_10_2_cmd_init(ar); - else - ret = ath10k_wmi_10x_cmd_init(ar); - } else { - ret = ath10k_wmi_main_cmd_init(ar); - } - - return ret; -} - -static int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg) +int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg) { if (arg->ie_len && !arg->ie) return -EINVAL; @@ -3450,9 +4029,8 @@ ath10k_wmi_start_scan_tlvs_len(const struct wmi_start_scan_arg *arg) return len; } -static void -ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn, - const struct wmi_start_scan_arg *arg) +void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn, + const struct wmi_start_scan_arg *arg) { u32 scan_id; u32 scan_req_id; @@ -3546,46 +4124,60 @@ ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs, } } -int ath10k_wmi_start_scan(struct ath10k *ar, - const struct wmi_start_scan_arg *arg) +static struct sk_buff * +ath10k_wmi_op_gen_start_scan(struct ath10k *ar, + const struct wmi_start_scan_arg *arg) { + struct wmi_start_scan_cmd *cmd; struct sk_buff *skb; size_t len; int ret; ret = ath10k_wmi_start_scan_verify(arg); if (ret) - return ret; - - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - len = sizeof(struct wmi_10x_start_scan_cmd) + - ath10k_wmi_start_scan_tlvs_len(arg); - else - len = sizeof(struct wmi_start_scan_cmd) + - ath10k_wmi_start_scan_tlvs_len(arg); + return ERR_PTR(ret); + len = sizeof(*cmd) + ath10k_wmi_start_scan_tlvs_len(arg); skb = ath10k_wmi_alloc_skb(ar, len); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - struct wmi_10x_start_scan_cmd *cmd; + cmd = (struct wmi_start_scan_cmd *)skb->data; - cmd = (struct wmi_10x_start_scan_cmd *)skb->data; - ath10k_wmi_put_start_scan_common(&cmd->common, arg); - ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); - } else { - struct wmi_start_scan_cmd *cmd; + ath10k_wmi_put_start_scan_common(&cmd->common, arg); + ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); - cmd = (struct wmi_start_scan_cmd *)skb->data; - cmd->burst_duration_ms = __cpu_to_le32(0); - - ath10k_wmi_put_start_scan_common(&cmd->common, arg); - ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); - } + cmd->burst_duration_ms = __cpu_to_le32(0); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi start scan\n"); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid); + return skb; +} + +static struct sk_buff * +ath10k_wmi_10x_op_gen_start_scan(struct ath10k *ar, + const struct wmi_start_scan_arg *arg) +{ + struct wmi_10x_start_scan_cmd *cmd; + struct sk_buff *skb; + size_t len; + int ret; + + ret = ath10k_wmi_start_scan_verify(arg); + if (ret) + return ERR_PTR(ret); + + len = sizeof(*cmd) + ath10k_wmi_start_scan_tlvs_len(arg); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_10x_start_scan_cmd *)skb->data; + + ath10k_wmi_put_start_scan_common(&cmd->common, arg); + ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi 10x start scan\n"); + return skb; } void ath10k_wmi_start_scan_init(struct ath10k *ar, @@ -3614,7 +4206,9 @@ void ath10k_wmi_start_scan_init(struct ath10k *ar, arg->bssids[0].bssid = "\xFF\xFF\xFF\xFF\xFF\xFF"; } -int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg) +static struct sk_buff * +ath10k_wmi_op_gen_stop_scan(struct ath10k *ar, + const struct wmi_stop_scan_arg *arg) { struct wmi_stop_scan_cmd *cmd; struct sk_buff *skb; @@ -3622,13 +4216,13 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg) u32 req_id; if (arg->req_id > 0xFFF) - return -EINVAL; + return ERR_PTR(-EINVAL); if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF) - return -EINVAL; + return ERR_PTR(-EINVAL); skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); scan_id = arg->u.scan_id; scan_id |= WMI_HOST_SCAN_REQ_ID_PREFIX; @@ -3645,20 +4239,21 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg) ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi stop scan reqid %d req_type %d vdev/scan_id %d\n", arg->req_id, arg->req_type, arg->u.scan_id); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid); + return skb; } -int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, - enum wmi_vdev_type type, - enum wmi_vdev_subtype subtype, - const u8 macaddr[ETH_ALEN]) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_create(struct ath10k *ar, u32 vdev_id, + enum wmi_vdev_type type, + enum wmi_vdev_subtype subtype, + const u8 macaddr[ETH_ALEN]) { struct wmi_vdev_create_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_create_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -3669,58 +4264,52 @@ int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI vdev create: id %d type %d subtype %d macaddr %pM\n", vdev_id, type, subtype, macaddr); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_create_cmdid); + return skb; } -int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_delete(struct ath10k *ar, u32 vdev_id) { struct wmi_vdev_delete_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_delete_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI vdev delete id %d\n", vdev_id); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid); + return skb; } -static int -ath10k_wmi_vdev_start_restart(struct ath10k *ar, - const struct wmi_vdev_start_request_arg *arg, - u32 cmd_id) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_start(struct ath10k *ar, + const struct wmi_vdev_start_request_arg *arg, + bool restart) { struct wmi_vdev_start_request_cmd *cmd; struct sk_buff *skb; const char *cmdname; u32 flags = 0; - if (cmd_id != ar->wmi.cmd->vdev_start_request_cmdid && - cmd_id != ar->wmi.cmd->vdev_restart_request_cmdid) - return -EINVAL; if (WARN_ON(arg->ssid && arg->ssid_len == 0)) - return -EINVAL; + return ERR_PTR(-EINVAL); if (WARN_ON(arg->hidden_ssid && !arg->ssid)) - return -EINVAL; + return ERR_PTR(-EINVAL); if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid))) - return -EINVAL; + return ERR_PTR(-EINVAL); - if (cmd_id == ar->wmi.cmd->vdev_start_request_cmdid) - cmdname = "start"; - else if (cmd_id == ar->wmi.cmd->vdev_restart_request_cmdid) + if (restart) cmdname = "restart"; else - return -EINVAL; /* should not happen, we already check cmd_id */ + cmdname = "start"; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); if (arg->hidden_ssid) flags |= WMI_VDEV_START_HIDDEN_SSID; @@ -3749,50 +4338,36 @@ ath10k_wmi_vdev_start_restart(struct ath10k *ar, flags, arg->channel.freq, arg->channel.mode, cmd->chan.flags, arg->channel.max_power); - return ath10k_wmi_cmd_send(ar, skb, cmd_id); + return skb; } -int ath10k_wmi_vdev_start(struct ath10k *ar, - const struct wmi_vdev_start_request_arg *arg) -{ - u32 cmd_id = ar->wmi.cmd->vdev_start_request_cmdid; - - return ath10k_wmi_vdev_start_restart(ar, arg, cmd_id); -} - -int ath10k_wmi_vdev_restart(struct ath10k *ar, - const struct wmi_vdev_start_request_arg *arg) -{ - u32 cmd_id = ar->wmi.cmd->vdev_restart_request_cmdid; - - return ath10k_wmi_vdev_start_restart(ar, arg, cmd_id); -} - -int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_stop(struct ath10k *ar, u32 vdev_id) { struct wmi_vdev_stop_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_stop_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid); + return skb; } -int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, + const u8 *bssid) { struct wmi_vdev_up_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_up_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -3802,30 +4377,30 @@ int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid) ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt vdev up id 0x%x assoc id %d bssid %pM\n", vdev_id, aid, bssid); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_up_cmdid); + return skb; } -int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_down(struct ath10k *ar, u32 vdev_id) { struct wmi_vdev_down_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_down_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt vdev down id 0x%x\n", vdev_id); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid); + return skb; } -int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, - u32 param_id, u32 param_value) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_set_param(struct ath10k *ar, u32 vdev_id, + u32 param_id, u32 param_value) { struct wmi_vdev_set_param_cmd *cmd; struct sk_buff *skb; @@ -3834,12 +4409,12 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "vdev param %d not supported by firmware\n", param_id); - return -EOPNOTSUPP; + return ERR_PTR(-EOPNOTSUPP); } skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_set_param_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -3849,24 +4424,24 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev id 0x%x set param %d value %d\n", vdev_id, param_id, param_value); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_set_param_cmdid); + return skb; } -int ath10k_wmi_vdev_install_key(struct ath10k *ar, - const struct wmi_vdev_install_key_arg *arg) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_install_key(struct ath10k *ar, + const struct wmi_vdev_install_key_arg *arg) { struct wmi_vdev_install_key_cmd *cmd; struct sk_buff *skb; if (arg->key_cipher == WMI_CIPHER_NONE && arg->key_data != NULL) - return -EINVAL; + return ERR_PTR(-EINVAL); if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL) - return -EINVAL; + return ERR_PTR(-EINVAL); skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + arg->key_len); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_install_key_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(arg->vdev_id); @@ -3885,20 +4460,19 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev install key idx %d cipher %d len %d\n", arg->key_idx, arg->key_cipher, arg->key_len); - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->vdev_install_key_cmdid); + return skb; } -int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar, - const struct wmi_vdev_spectral_conf_arg *arg) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_spectral_conf(struct ath10k *ar, + const struct wmi_vdev_spectral_conf_arg *arg) { struct wmi_vdev_spectral_conf_cmd *cmd; struct sk_buff *skb; - u32 cmdid; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_spectral_conf_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(arg->vdev_id); @@ -3921,39 +4495,38 @@ int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar, cmd->scan_dbm_adj = __cpu_to_le32(arg->scan_dbm_adj); cmd->scan_chn_mask = __cpu_to_le32(arg->scan_chn_mask); - cmdid = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid; - return ath10k_wmi_cmd_send(ar, skb, cmdid); + return skb; } -int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger, - u32 enable) +static struct sk_buff * +ath10k_wmi_op_gen_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, + u32 trigger, u32 enable) { struct wmi_vdev_spectral_enable_cmd *cmd; struct sk_buff *skb; - u32 cmdid; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_vdev_spectral_enable_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); cmd->trigger_cmd = __cpu_to_le32(trigger); cmd->enable_cmd = __cpu_to_le32(enable); - cmdid = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid; - return ath10k_wmi_cmd_send(ar, skb, cmdid); + return skb; } -int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, - const u8 peer_addr[ETH_ALEN]) +static struct sk_buff * +ath10k_wmi_op_gen_peer_create(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]) { struct wmi_peer_create_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_peer_create_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -3962,18 +4535,19 @@ int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi peer create vdev_id %d peer_addr %pM\n", vdev_id, peer_addr); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid); + return skb; } -int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, - const u8 peer_addr[ETH_ALEN]) +static struct sk_buff * +ath10k_wmi_op_gen_peer_delete(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN]) { struct wmi_peer_delete_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_peer_delete_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -3982,18 +4556,19 @@ int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi peer delete vdev_id %d peer_addr %pM\n", vdev_id, peer_addr); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid); + return skb; } -int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, - const u8 peer_addr[ETH_ALEN], u32 tid_bitmap) +static struct sk_buff * +ath10k_wmi_op_gen_peer_flush(struct ath10k *ar, u32 vdev_id, + const u8 peer_addr[ETH_ALEN], u32 tid_bitmap) { struct wmi_peer_flush_tids_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_peer_flush_tids_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -4003,19 +4578,21 @@ int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi peer flush vdev_id %d peer_addr %pM tids %08x\n", vdev_id, peer_addr, tid_bitmap); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid); + return skb; } -int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, - const u8 *peer_addr, enum wmi_peer_param param_id, - u32 param_value) +static struct sk_buff * +ath10k_wmi_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id, + const u8 *peer_addr, + enum wmi_peer_param param_id, + u32 param_value) { struct wmi_peer_set_param_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_peer_set_param_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -4026,19 +4603,19 @@ int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev %d peer 0x%pM set param %d value %d\n", vdev_id, peer_addr, param_id, param_value); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_set_param_cmdid); + return skb; } -int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, - enum wmi_sta_ps_mode psmode) +static struct sk_buff * +ath10k_wmi_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_ps_mode psmode) { struct wmi_sta_powersave_mode_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_sta_powersave_mode_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -4047,21 +4624,20 @@ int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi set powersave id 0x%x mode %d\n", vdev_id, psmode); - - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->sta_powersave_mode_cmdid); + return skb; } -int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, - enum wmi_sta_powersave_param param_id, - u32 value) +static struct sk_buff * +ath10k_wmi_op_gen_set_sta_ps(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_powersave_param param_id, + u32 value) { struct wmi_sta_powersave_param_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_sta_powersave_param_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -4071,22 +4647,22 @@ int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sta ps param vdev_id 0x%x param %d value %d\n", vdev_id, param_id, value); - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->sta_powersave_param_cmdid); + return skb; } -int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, - enum wmi_ap_ps_peer_param param_id, u32 value) +static struct sk_buff * +ath10k_wmi_op_gen_set_ap_ps(struct ath10k *ar, u32 vdev_id, const u8 *mac, + enum wmi_ap_ps_peer_param param_id, u32 value) { struct wmi_ap_ps_peer_cmd *cmd; struct sk_buff *skb; if (!mac) - return -EINVAL; + return ERR_PTR(-EINVAL); skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_ap_ps_peer_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); @@ -4097,13 +4673,12 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi ap ps param vdev_id 0x%X param %d value %d mac_addr %pM\n", vdev_id, param_id, value, mac); - - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->ap_ps_peer_param_cmdid); + return skb; } -int ath10k_wmi_scan_chan_list(struct ath10k *ar, - const struct wmi_scan_chan_list_arg *arg) +static struct sk_buff * +ath10k_wmi_op_gen_scan_chan_list(struct ath10k *ar, + const struct wmi_scan_chan_list_arg *arg) { struct wmi_scan_chan_list_cmd *cmd; struct sk_buff *skb; @@ -4116,7 +4691,7 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar, skb = ath10k_wmi_alloc_skb(ar, len); if (!skb) - return -EINVAL; + return ERR_PTR(-EINVAL); cmd = (struct wmi_scan_chan_list_cmd *)skb->data; cmd->num_scan_chans = __cpu_to_le32(arg->n_channels); @@ -4128,7 +4703,7 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar, ath10k_wmi_put_wmi_channel(ci, ch); } - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid); + return skb; } static void @@ -4209,12 +4784,9 @@ ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf, cmd->info0 = __cpu_to_le32(info0); } -int ath10k_wmi_peer_assoc(struct ath10k *ar, - const struct wmi_peer_assoc_complete_arg *arg) +static int +ath10k_wmi_peer_assoc_check_arg(const struct wmi_peer_assoc_complete_arg *arg) { - struct sk_buff *skb; - int len; - if (arg->peer_mpdu_density > 16) return -EINVAL; if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES) @@ -4222,79 +4794,135 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES) return -EINVAL; - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) - len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd); - else - len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd); - } else { - len = sizeof(struct wmi_main_peer_assoc_complete_cmd); - } + return 0; +} + +static struct sk_buff * +ath10k_wmi_op_gen_peer_assoc(struct ath10k *ar, + const struct wmi_peer_assoc_complete_arg *arg) +{ + size_t len = sizeof(struct wmi_main_peer_assoc_complete_cmd); + struct sk_buff *skb; + int ret; + + ret = ath10k_wmi_peer_assoc_check_arg(arg); + if (ret) + return ERR_PTR(ret); skb = ath10k_wmi_alloc_skb(ar, len); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) - ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg); - else - ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg); - } else { - ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg); - } + ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi peer assoc vdev %d addr %pM (%s)\n", arg->vdev_id, arg->addr, arg->peer_reassoc ? "reassociate" : "new"); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid); + return skb; +} + +static struct sk_buff * +ath10k_wmi_10_1_op_gen_peer_assoc(struct ath10k *ar, + const struct wmi_peer_assoc_complete_arg *arg) +{ + size_t len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd); + struct sk_buff *skb; + int ret; + + ret = ath10k_wmi_peer_assoc_check_arg(arg); + if (ret) + return ERR_PTR(ret); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi peer assoc vdev %d addr %pM (%s)\n", + arg->vdev_id, arg->addr, + arg->peer_reassoc ? "reassociate" : "new"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_10_2_op_gen_peer_assoc(struct ath10k *ar, + const struct wmi_peer_assoc_complete_arg *arg) +{ + size_t len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd); + struct sk_buff *skb; + int ret; + + ret = ath10k_wmi_peer_assoc_check_arg(arg); + if (ret) + return ERR_PTR(ret); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi peer assoc vdev %d addr %pM (%s)\n", + arg->vdev_id, arg->addr, + arg->peer_reassoc ? "reassociate" : "new"); + return skb; +} + +static struct sk_buff * +ath10k_wmi_10_2_op_gen_pdev_get_temperature(struct ath10k *ar) +{ + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, 0); + if (!skb) + return ERR_PTR(-ENOMEM); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev get temperature\n"); + return skb; } /* This function assumes the beacon is already DMA mapped */ -int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif) +static struct sk_buff * +ath10k_wmi_op_gen_beacon_dma(struct ath10k *ar, u32 vdev_id, const void *bcn, + size_t bcn_len, u32 bcn_paddr, bool dtim_zero, + bool deliver_cab) { struct wmi_bcn_tx_ref_cmd *cmd; struct sk_buff *skb; - struct sk_buff *beacon = arvif->beacon; - struct ath10k *ar = arvif->ar; struct ieee80211_hdr *hdr; - int ret; u16 fc; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - hdr = (struct ieee80211_hdr *)beacon->data; + hdr = (struct ieee80211_hdr *)bcn; fc = le16_to_cpu(hdr->frame_control); cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data; - cmd->vdev_id = __cpu_to_le32(arvif->vdev_id); - cmd->data_len = __cpu_to_le32(beacon->len); - cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr); + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->data_len = __cpu_to_le32(bcn_len); + cmd->data_ptr = __cpu_to_le32(bcn_paddr); cmd->msdu_id = 0; cmd->frame_control = __cpu_to_le32(fc); cmd->flags = 0; cmd->antenna_mask = __cpu_to_le32(WMI_BCN_TX_REF_DEF_ANTENNA); - if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero) + if (dtim_zero) cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO); - if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab) + if (deliver_cab) cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB); - ret = ath10k_wmi_cmd_send_nowait(ar, skb, - ar->wmi.cmd->pdev_send_bcn_cmdid); - - if (ret) - dev_kfree_skb(skb); - - return ret; + return skb; } -static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, - const struct wmi_wmm_params_arg *arg) +void ath10k_wmi_set_wmm_param(struct wmi_wmm_params *params, + const struct wmi_wmm_params_arg *arg) { params->cwmin = __cpu_to_le32(arg->cwmin); params->cwmax = __cpu_to_le32(arg->cwmax); @@ -4304,52 +4932,54 @@ static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params, params->no_ack = __cpu_to_le32(arg->no_ack); } -int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, - const struct wmi_pdev_set_wmm_params_arg *arg) +static struct sk_buff * +ath10k_wmi_op_gen_pdev_set_wmm(struct ath10k *ar, + const struct wmi_wmm_params_all_arg *arg) { struct wmi_pdev_set_wmm_params *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_pdev_set_wmm_params *)skb->data; - ath10k_wmi_pdev_set_wmm_param(&cmd->ac_be, &arg->ac_be); - ath10k_wmi_pdev_set_wmm_param(&cmd->ac_bk, &arg->ac_bk); - ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vi, &arg->ac_vi); - ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vo, &arg->ac_vo); + ath10k_wmi_set_wmm_param(&cmd->ac_be, &arg->ac_be); + ath10k_wmi_set_wmm_param(&cmd->ac_bk, &arg->ac_bk); + ath10k_wmi_set_wmm_param(&cmd->ac_vi, &arg->ac_vi); + ath10k_wmi_set_wmm_param(&cmd->ac_vo, &arg->ac_vo); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set wmm params\n"); - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->pdev_set_wmm_params_cmdid); + return skb; } -int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) +static struct sk_buff * +ath10k_wmi_op_gen_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) { struct wmi_request_stats_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_request_stats_cmd *)skb->data; cmd->stats_id = __cpu_to_le32(stats_id); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid); + return skb; } -int ath10k_wmi_force_fw_hang(struct ath10k *ar, - enum wmi_force_fw_hang_type type, u32 delay_ms) +static struct sk_buff * +ath10k_wmi_op_gen_force_fw_hang(struct ath10k *ar, + enum wmi_force_fw_hang_type type, u32 delay_ms) { struct wmi_force_fw_hang_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_force_fw_hang_cmd *)skb->data; cmd->type = __cpu_to_le32(type); @@ -4357,10 +4987,12 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n", type, delay_ms); - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid); + return skb; } -int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable) +static struct sk_buff * +ath10k_wmi_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable, + u32 log_level) { struct wmi_dbglog_cfg_cmd *cmd; struct sk_buff *skb; @@ -4368,12 +5000,12 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable) skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); cmd = (struct wmi_dbglog_cfg_cmd *)skb->data; if (module_enable) { - cfg = SM(ATH10K_DBGLOG_LEVEL_VERBOSE, + cfg = SM(log_level, ATH10K_DBGLOG_CFG_LOG_LVL); } else { /* set back defaults, all modules with WARN level */ @@ -4393,57 +5025,449 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable) __le32_to_cpu(cmd->module_valid), __le32_to_cpu(cmd->config_enable), __le32_to_cpu(cmd->config_valid)); - - return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid); + return skb; } -int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_bitmap) +static struct sk_buff * +ath10k_wmi_op_gen_pktlog_enable(struct ath10k *ar, u32 ev_bitmap) { struct wmi_pdev_pktlog_enable_cmd *cmd; struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); ev_bitmap &= ATH10K_PKTLOG_ANY; - ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi enable pktlog filter:%x\n", ev_bitmap); cmd = (struct wmi_pdev_pktlog_enable_cmd *)skb->data; cmd->ev_bitmap = __cpu_to_le32(ev_bitmap); - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->pdev_pktlog_enable_cmdid); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi enable pktlog filter 0x%08x\n", + ev_bitmap); + return skb; } -int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar) +static struct sk_buff * +ath10k_wmi_op_gen_pktlog_disable(struct ath10k *ar) { struct sk_buff *skb; skb = ath10k_wmi_alloc_skb(ar, 0); if (!skb) - return -ENOMEM; + return ERR_PTR(-ENOMEM); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi disable pktlog\n"); - - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->pdev_pktlog_disable_cmdid); + return skb; } +static struct sk_buff * +ath10k_wmi_op_gen_pdev_set_quiet_mode(struct ath10k *ar, u32 period, + u32 duration, u32 next_offset, + u32 enabled) +{ + struct wmi_pdev_set_quiet_cmd *cmd; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_pdev_set_quiet_cmd *)skb->data; + cmd->period = __cpu_to_le32(period); + cmd->duration = __cpu_to_le32(duration); + cmd->next_start = __cpu_to_le32(next_offset); + cmd->enabled = __cpu_to_le32(enabled); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi quiet param: period %u duration %u enabled %d\n", + period, duration, enabled); + return skb; +} + +static struct sk_buff * +ath10k_wmi_op_gen_addba_clear_resp(struct ath10k *ar, u32 vdev_id, + const u8 *mac) +{ + struct wmi_addba_clear_resp_cmd *cmd; + struct sk_buff *skb; + + if (!mac) + return ERR_PTR(-EINVAL); + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_addba_clear_resp_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(vdev_id); + ether_addr_copy(cmd->peer_macaddr.addr, mac); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi addba clear resp vdev_id 0x%X mac_addr %pM\n", + vdev_id, mac); + return skb; +} + +static struct sk_buff * +ath10k_wmi_op_gen_addba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, + u32 tid, u32 buf_size) +{ + struct wmi_addba_send_cmd *cmd; + struct sk_buff *skb; + + if (!mac) + return ERR_PTR(-EINVAL); + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_addba_send_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(vdev_id); + ether_addr_copy(cmd->peer_macaddr.addr, mac); + cmd->tid = __cpu_to_le32(tid); + cmd->buffersize = __cpu_to_le32(buf_size); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi addba send vdev_id 0x%X mac_addr %pM tid %u bufsize %u\n", + vdev_id, mac, tid, buf_size); + return skb; +} + +static struct sk_buff * +ath10k_wmi_op_gen_addba_set_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac, + u32 tid, u32 status) +{ + struct wmi_addba_setresponse_cmd *cmd; + struct sk_buff *skb; + + if (!mac) + return ERR_PTR(-EINVAL); + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_addba_setresponse_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(vdev_id); + ether_addr_copy(cmd->peer_macaddr.addr, mac); + cmd->tid = __cpu_to_le32(tid); + cmd->statuscode = __cpu_to_le32(status); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi addba set resp vdev_id 0x%X mac_addr %pM tid %u status %u\n", + vdev_id, mac, tid, status); + return skb; +} + +static struct sk_buff * +ath10k_wmi_op_gen_delba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac, + u32 tid, u32 initiator, u32 reason) +{ + struct wmi_delba_send_cmd *cmd; + struct sk_buff *skb; + + if (!mac) + return ERR_PTR(-EINVAL); + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_delba_send_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(vdev_id); + ether_addr_copy(cmd->peer_macaddr.addr, mac); + cmd->tid = __cpu_to_le32(tid); + cmd->initiator = __cpu_to_le32(initiator); + cmd->reasoncode = __cpu_to_le32(reason); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi delba send vdev_id 0x%X mac_addr %pM tid %u initiator %u reason %u\n", + vdev_id, mac, tid, initiator, reason); + return skb; +} + +static const struct wmi_ops wmi_ops = { + .rx = ath10k_wmi_op_rx, + .map_svc = wmi_main_svc_map, + + .pull_scan = ath10k_wmi_op_pull_scan_ev, + .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev, + .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, + .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, + .pull_swba = ath10k_wmi_op_pull_swba_ev, + .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, + .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, + .pull_rdy = ath10k_wmi_op_pull_rdy_ev, + .pull_fw_stats = ath10k_wmi_main_op_pull_fw_stats, + + .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, + .gen_pdev_set_rd = ath10k_wmi_op_gen_pdev_set_rd, + .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, + .gen_init = ath10k_wmi_op_gen_init, + .gen_start_scan = ath10k_wmi_op_gen_start_scan, + .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, + .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, + .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, + .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, + /* .gen_vdev_wmm_conf not implemented */ + .gen_peer_create = ath10k_wmi_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, + .gen_peer_assoc = ath10k_wmi_op_gen_peer_assoc, + .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, + .gen_request_stats = ath10k_wmi_op_gen_request_stats, + .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, + .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, + .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, + .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, + .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, + /* .gen_pdev_get_temperature not implemented */ + .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, + .gen_addba_send = ath10k_wmi_op_gen_addba_send, + .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, + .gen_delba_send = ath10k_wmi_op_gen_delba_send, + /* .gen_bcn_tmpl not implemented */ + /* .gen_prb_tmpl not implemented */ + /* .gen_p2p_go_bcn_ie not implemented */ +}; + +static const struct wmi_ops wmi_10_1_ops = { + .rx = ath10k_wmi_10_1_op_rx, + .map_svc = wmi_10x_svc_map, + .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev, + .pull_fw_stats = ath10k_wmi_10x_op_pull_fw_stats, + .gen_init = ath10k_wmi_10_1_op_gen_init, + .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, + .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan, + .gen_peer_assoc = ath10k_wmi_10_1_op_gen_peer_assoc, + /* .gen_pdev_get_temperature not implemented */ + + /* shared with main branch */ + .pull_scan = ath10k_wmi_op_pull_scan_ev, + .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev, + .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, + .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, + .pull_swba = ath10k_wmi_op_pull_swba_ev, + .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, + .pull_rdy = ath10k_wmi_op_pull_rdy_ev, + + .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, + .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, + .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, + .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, + .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, + .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, + /* .gen_vdev_wmm_conf not implemented */ + .gen_peer_create = ath10k_wmi_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, + .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, + .gen_request_stats = ath10k_wmi_op_gen_request_stats, + .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, + .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, + .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, + .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, + .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, + .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, + .gen_addba_send = ath10k_wmi_op_gen_addba_send, + .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, + .gen_delba_send = ath10k_wmi_op_gen_delba_send, + /* .gen_bcn_tmpl not implemented */ + /* .gen_prb_tmpl not implemented */ + /* .gen_p2p_go_bcn_ie not implemented */ +}; + +static const struct wmi_ops wmi_10_2_ops = { + .rx = ath10k_wmi_10_2_op_rx, + .pull_fw_stats = ath10k_wmi_10_2_op_pull_fw_stats, + .gen_init = ath10k_wmi_10_2_op_gen_init, + .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, + /* .gen_pdev_get_temperature not implemented */ + + /* shared with 10.1 */ + .map_svc = wmi_10x_svc_map, + .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev, + .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, + .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan, + + .pull_scan = ath10k_wmi_op_pull_scan_ev, + .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev, + .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, + .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, + .pull_swba = ath10k_wmi_op_pull_swba_ev, + .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, + .pull_rdy = ath10k_wmi_op_pull_rdy_ev, + + .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, + .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, + .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, + .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, + .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, + .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, + /* .gen_vdev_wmm_conf not implemented */ + .gen_peer_create = ath10k_wmi_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, + .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, + .gen_request_stats = ath10k_wmi_op_gen_request_stats, + .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, + .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, + .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, + .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, + .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, + .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, + .gen_addba_send = ath10k_wmi_op_gen_addba_send, + .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, + .gen_delba_send = ath10k_wmi_op_gen_delba_send, +}; + +static const struct wmi_ops wmi_10_2_4_ops = { + .rx = ath10k_wmi_10_2_op_rx, + .pull_fw_stats = ath10k_wmi_10_2_4_op_pull_fw_stats, + .gen_init = ath10k_wmi_10_2_op_gen_init, + .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, + .gen_pdev_get_temperature = ath10k_wmi_10_2_op_gen_pdev_get_temperature, + + /* shared with 10.1 */ + .map_svc = wmi_10x_svc_map, + .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev, + .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, + .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan, + + .pull_scan = ath10k_wmi_op_pull_scan_ev, + .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev, + .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, + .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, + .pull_swba = ath10k_wmi_op_pull_swba_ev, + .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev, + .pull_rdy = ath10k_wmi_op_pull_rdy_ev, + + .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, + .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, + .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, + .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, + .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, + .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, + .gen_peer_create = ath10k_wmi_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, + .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, + .gen_request_stats = ath10k_wmi_op_gen_request_stats, + .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, + .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, + .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, + .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, + .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, + .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp, + .gen_addba_send = ath10k_wmi_op_gen_addba_send, + .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp, + .gen_delba_send = ath10k_wmi_op_gen_delba_send, + /* .gen_bcn_tmpl not implemented */ + /* .gen_prb_tmpl not implemented */ + /* .gen_p2p_go_bcn_ie not implemented */ +}; + int ath10k_wmi_attach(struct ath10k *ar) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) - ar->wmi.cmd = &wmi_10_2_cmd_map; - else - ar->wmi.cmd = &wmi_10x_cmd_map; - + switch (ar->wmi.op_version) { + case ATH10K_FW_WMI_OP_VERSION_10_2_4: + ar->wmi.cmd = &wmi_10_2_4_cmd_map; + ar->wmi.ops = &wmi_10_2_4_ops; + ar->wmi.vdev_param = &wmi_10_2_4_vdev_param_map; + ar->wmi.pdev_param = &wmi_10_2_4_pdev_param_map; + break; + case ATH10K_FW_WMI_OP_VERSION_10_2: + ar->wmi.cmd = &wmi_10_2_cmd_map; + ar->wmi.ops = &wmi_10_2_ops; ar->wmi.vdev_param = &wmi_10x_vdev_param_map; ar->wmi.pdev_param = &wmi_10x_pdev_param_map; - } else { + break; + case ATH10K_FW_WMI_OP_VERSION_10_1: + ar->wmi.cmd = &wmi_10x_cmd_map; + ar->wmi.ops = &wmi_10_1_ops; + ar->wmi.vdev_param = &wmi_10x_vdev_param_map; + ar->wmi.pdev_param = &wmi_10x_pdev_param_map; + break; + case ATH10K_FW_WMI_OP_VERSION_MAIN: ar->wmi.cmd = &wmi_cmd_map; + ar->wmi.ops = &wmi_ops; ar->wmi.vdev_param = &wmi_vdev_param_map; ar->wmi.pdev_param = &wmi_pdev_param_map; + break; + case ATH10K_FW_WMI_OP_VERSION_TLV: + ath10k_wmi_tlv_attach(ar); + break; + case ATH10K_FW_WMI_OP_VERSION_UNSET: + case ATH10K_FW_WMI_OP_VERSION_MAX: + ath10k_err(ar, "unsupported WMI op version: %d\n", + ar->wmi.op_version); + return -EINVAL; } init_completion(&ar->wmi.service_ready); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 21391929d318..20ce3603e64b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -109,6 +109,45 @@ enum wmi_service { WMI_SERVICE_BURST, WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT, WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, + WMI_SERVICE_ROAM_SCAN_OFFLOAD, + WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, + WMI_SERVICE_EARLY_RX, + WMI_SERVICE_STA_SMPS, + WMI_SERVICE_FWTEST, + WMI_SERVICE_STA_WMMAC, + WMI_SERVICE_TDLS, + WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE, + WMI_SERVICE_ADAPTIVE_OCS, + WMI_SERVICE_BA_SSN_SUPPORT, + WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE, + WMI_SERVICE_WLAN_HB, + WMI_SERVICE_LTE_ANT_SHARE_SUPPORT, + WMI_SERVICE_BATCH_SCAN, + WMI_SERVICE_QPOWER, + WMI_SERVICE_PLMREQ, + WMI_SERVICE_THERMAL_MGMT, + WMI_SERVICE_RMC, + WMI_SERVICE_MHF_OFFLOAD, + WMI_SERVICE_COEX_SAR, + WMI_SERVICE_BCN_TXRATE_OVERRIDE, + WMI_SERVICE_NAN, + WMI_SERVICE_L1SS_STAT, + WMI_SERVICE_ESTIMATE_LINKSPEED, + WMI_SERVICE_OBSS_SCAN, + WMI_SERVICE_TDLS_OFFCHAN, + WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, + WMI_SERVICE_TDLS_UAPSD_SLEEP_STA, + WMI_SERVICE_IBSS_PWRSAVE, + WMI_SERVICE_LPASS, + WMI_SERVICE_EXTSCAN, + WMI_SERVICE_D0WOW, + WMI_SERVICE_HSOFFLOAD, + WMI_SERVICE_ROAM_HO_OFFLOAD, + WMI_SERVICE_RX_FULL_REORDER, + WMI_SERVICE_DHCP_OFFLOAD, + WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, + WMI_SERVICE_MDNS_OFFLOAD, + WMI_SERVICE_SAP_AUTH_OFFLOAD, /* keep last */ WMI_SERVICE_MAX, @@ -215,6 +254,45 @@ static inline char *wmi_service_name(int service_id) SVCSTR(WMI_SERVICE_BURST); SVCSTR(WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT); SVCSTR(WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT); + SVCSTR(WMI_SERVICE_ROAM_SCAN_OFFLOAD); + SVCSTR(WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC); + SVCSTR(WMI_SERVICE_EARLY_RX); + SVCSTR(WMI_SERVICE_STA_SMPS); + SVCSTR(WMI_SERVICE_FWTEST); + SVCSTR(WMI_SERVICE_STA_WMMAC); + SVCSTR(WMI_SERVICE_TDLS); + SVCSTR(WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE); + SVCSTR(WMI_SERVICE_ADAPTIVE_OCS); + SVCSTR(WMI_SERVICE_BA_SSN_SUPPORT); + SVCSTR(WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE); + SVCSTR(WMI_SERVICE_WLAN_HB); + SVCSTR(WMI_SERVICE_LTE_ANT_SHARE_SUPPORT); + SVCSTR(WMI_SERVICE_BATCH_SCAN); + SVCSTR(WMI_SERVICE_QPOWER); + SVCSTR(WMI_SERVICE_PLMREQ); + SVCSTR(WMI_SERVICE_THERMAL_MGMT); + SVCSTR(WMI_SERVICE_RMC); + SVCSTR(WMI_SERVICE_MHF_OFFLOAD); + SVCSTR(WMI_SERVICE_COEX_SAR); + SVCSTR(WMI_SERVICE_BCN_TXRATE_OVERRIDE); + SVCSTR(WMI_SERVICE_NAN); + SVCSTR(WMI_SERVICE_L1SS_STAT); + SVCSTR(WMI_SERVICE_ESTIMATE_LINKSPEED); + SVCSTR(WMI_SERVICE_OBSS_SCAN); + SVCSTR(WMI_SERVICE_TDLS_OFFCHAN); + SVCSTR(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA); + SVCSTR(WMI_SERVICE_TDLS_UAPSD_SLEEP_STA); + SVCSTR(WMI_SERVICE_IBSS_PWRSAVE); + SVCSTR(WMI_SERVICE_LPASS); + SVCSTR(WMI_SERVICE_EXTSCAN); + SVCSTR(WMI_SERVICE_D0WOW); + SVCSTR(WMI_SERVICE_HSOFFLOAD); + SVCSTR(WMI_SERVICE_ROAM_HO_OFFLOAD); + SVCSTR(WMI_SERVICE_RX_FULL_REORDER); + SVCSTR(WMI_SERVICE_DHCP_OFFLOAD); + SVCSTR(WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT); + SVCSTR(WMI_SERVICE_MDNS_OFFLOAD); + SVCSTR(WMI_SERVICE_SAP_AUTH_OFFLOAD); default: return NULL; } @@ -472,6 +550,8 @@ struct wmi_cmd_map { u32 force_fw_hang_cmdid; u32 gpio_config_cmdid; u32 gpio_output_cmdid; + u32 pdev_get_temperature_cmdid; + u32 vdev_set_wmm_params_cmdid; }; /* @@ -1076,6 +1156,11 @@ enum wmi_10_2_cmd_id { WMI_10_2_PDEV_SET_MIMOGAIN_TABLE_CMDID, WMI_10_2_PDEV_RATEPWR_TABLE_CMDID, WMI_10_2_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID, + WMI_10_2_PDEV_GET_INFO, + WMI_10_2_VDEV_GET_INFO, + WMI_10_2_VDEV_ATF_REQUEST_CMDID, + WMI_10_2_PEER_ATF_REQUEST_CMDID, + WMI_10_2_PDEV_GET_TEMPERATURE_CMDID, WMI_10_2_PDEV_UTF_CMDID = WMI_10_2_END_CMDID - 1, }; @@ -1117,6 +1202,8 @@ enum wmi_10_2_event_id { WMI_10_2_MCAST_BUF_RELEASE_EVENTID, WMI_10_2_MCAST_LIST_AGEOUT_EVENTID, WMI_10_2_WDS_PEER_EVENTID, + WMI_10_2_PEER_STA_PS_STATECHG_EVENTID, + WMI_10_2_PDEV_TEMPERATURE_EVENTID, WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1, }; @@ -1862,6 +1949,11 @@ struct wmi_resource_config_10x { __le32 max_frag_entries; } __packed; +enum wmi_10_2_feature_mask { + WMI_10_2_RX_BATCH_MODE = BIT(0), + WMI_10_2_ATF_CONFIG = BIT(1), +}; + struct wmi_resource_config_10_2 { struct wmi_resource_config_10x common; __le32 max_peer_ext_stats; @@ -1870,7 +1962,7 @@ struct wmi_resource_config_10_2 { __le32 be_min_free; __le32 vi_min_free; __le32 vo_min_free; - __le32 rx_batchmode; /* 0-disable, 1-enable */ + __le32 feature_mask; } __packed; #define NUM_UNITS_IS_NUM_VDEVS 0x1 @@ -2505,6 +2597,7 @@ struct wmi_pdev_param_map { u32 fast_channel_reset; u32 burst_dur; u32 burst_enable; + u32 cal_period; }; #define WMI_PDEV_PARAM_UNSUPPORTED 0 @@ -2715,6 +2808,9 @@ enum wmi_10x_pdev_param { WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_MODE, WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_BUFFER, WMI_10X_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER, + WMI_10X_PDEV_PARAM_PEER_STA_PS_STATECHG_ENABLE, + WMI_10X_PDEV_PARAM_RTS_FIXED_RATE, + WMI_10X_PDEV_PARAM_CAL_PERIOD }; struct wmi_pdev_set_param_cmd { @@ -2722,6 +2818,9 @@ struct wmi_pdev_set_param_cmd { __le32 param_value; } __packed; +/* valid period is 1 ~ 60000ms, unit in millisecond */ +#define WMI_PDEV_PARAM_CAL_PERIOD_MAX 60000 + struct wmi_pdev_get_tpc_config_cmd { /* parameter */ __le32 param; @@ -2841,14 +2940,14 @@ struct wmi_wmm_params_arg { u32 no_ack; }; -struct wmi_pdev_set_wmm_params_arg { +struct wmi_wmm_params_all_arg { struct wmi_wmm_params_arg ac_be; struct wmi_wmm_params_arg ac_bk; struct wmi_wmm_params_arg ac_vi; struct wmi_wmm_params_arg ac_vo; }; -struct wal_dbg_tx_stats { +struct wmi_pdev_stats_tx { /* Num HTT cookies queued to dispatch list */ __le32 comp_queued; @@ -2918,7 +3017,7 @@ struct wal_dbg_tx_stats { __le32 txop_ovf; } __packed; -struct wal_dbg_rx_stats { +struct wmi_pdev_stats_rx { /* Cnts any change in ring routing mid-ppdu */ __le32 mid_ppdu_route_change; @@ -2952,17 +3051,11 @@ struct wal_dbg_rx_stats { __le32 mpdu_errs; } __packed; -struct wal_dbg_peer_stats { +struct wmi_pdev_stats_peer { /* REMOVE THIS ONCE REAL PEER STAT COUNTERS ARE ADDED */ __le32 dummy; } __packed; -struct wal_dbg_stats { - struct wal_dbg_tx_stats tx; - struct wal_dbg_rx_stats rx; - struct wal_dbg_peer_stats peer; -} __packed; - enum wmi_stats_id { WMI_REQUEST_PEER_STAT = 0x01, WMI_REQUEST_AP_STAT = 0x02 @@ -3029,23 +3122,38 @@ struct wmi_stats_event { u8 data[0]; } __packed; +struct wmi_10_2_stats_event { + __le32 stats_id; /* %WMI_REQUEST_ */ + __le32 num_pdev_stats; + __le32 num_pdev_ext_stats; + __le32 num_vdev_stats; + __le32 num_peer_stats; + __le32 num_bcnflt_stats; + u8 data[0]; +} __packed; + /* * PDEV statistics * TODO: add all PDEV stats here */ -struct wmi_pdev_stats { - __le32 chan_nf; /* Channel noise floor */ - __le32 tx_frame_count; /* TX frame count */ - __le32 rx_frame_count; /* RX frame count */ - __le32 rx_clear_count; /* rx clear count */ - __le32 cycle_count; /* cycle count */ - __le32 phy_err_count; /* Phy error count */ - __le32 chan_tx_pwr; /* channel tx power */ - struct wal_dbg_stats wal; /* WAL dbg stats */ +struct wmi_pdev_stats_base { + __le32 chan_nf; + __le32 tx_frame_count; + __le32 rx_frame_count; + __le32 rx_clear_count; + __le32 cycle_count; + __le32 phy_err_count; + __le32 chan_tx_pwr; } __packed; -struct wmi_10x_pdev_stats { - struct wmi_pdev_stats old; +struct wmi_pdev_stats { + struct wmi_pdev_stats_base base; + struct wmi_pdev_stats_tx tx; + struct wmi_pdev_stats_rx rx; + struct wmi_pdev_stats_peer peer; +} __packed; + +struct wmi_pdev_stats_extra { __le32 ack_rx_bad; __le32 rts_bad; __le32 rts_good; @@ -3054,6 +3162,30 @@ struct wmi_10x_pdev_stats { __le32 mib_int_count; } __packed; +struct wmi_10x_pdev_stats { + struct wmi_pdev_stats_base base; + struct wmi_pdev_stats_tx tx; + struct wmi_pdev_stats_rx rx; + struct wmi_pdev_stats_peer peer; + struct wmi_pdev_stats_extra extra; +} __packed; + +struct wmi_pdev_stats_mem { + __le32 dram_free; + __le32 iram_free; +} __packed; + +struct wmi_10_2_pdev_stats { + struct wmi_pdev_stats_base base; + struct wmi_pdev_stats_tx tx; + __le32 mc_drop; + struct wmi_pdev_stats_rx rx; + __le32 pdev_rx_timeout; + struct wmi_pdev_stats_mem mem; + struct wmi_pdev_stats_peer peer; + struct wmi_pdev_stats_extra extra; +} __packed; + /* * VDEV statistics * TODO: add all VDEV stats here @@ -3077,6 +3209,32 @@ struct wmi_10x_peer_stats { __le32 peer_rx_rate; } __packed; +struct wmi_10_2_peer_stats { + struct wmi_peer_stats old; + __le32 peer_rx_rate; + __le32 current_per; + __le32 retries; + __le32 tx_rate_count; + __le32 max_4ms_frame_len; + __le32 total_sub_frames; + __le32 tx_bytes; + __le32 num_pkt_loss_overflow[4]; + __le32 num_pkt_loss_excess_retry[4]; +} __packed; + +struct wmi_10_2_4_peer_stats { + struct wmi_10_2_peer_stats common; + __le32 unknown_value; /* FIXME: what is this word? */ +} __packed; + +struct wmi_10_2_pdev_ext_stats { + __le32 rx_rssi_comb; + __le32 rx_rssi[4]; + __le32 rx_mcs[10]; + __le32 tx_mcs[10]; + __le32 ack_rssi; +} __packed; + struct wmi_vdev_create_cmd { __le32 vdev_id; __le32 vdev_type; @@ -3930,6 +4088,13 @@ enum wmi_sta_ps_param_pspoll_count { * Values greater than 0 indicate the maximum numer of PS-Poll frames * FW will send before waking up. */ + + /* When u-APSD is enabled the firmware will be very reluctant to exit + * STA PS. This could result in very poor Rx performance with STA doing + * PS-Poll for each and every buffered frame. This value is a bit + * arbitrary. + */ + WMI_STA_PS_PSPOLL_COUNT_UAPSD = 3, }; /* @@ -3955,6 +4120,30 @@ enum wmi_sta_ps_param_uapsd { WMI_STA_PS_UAPSD_AC3_TRIGGER_EN = (1 << 7), }; +#define WMI_STA_UAPSD_MAX_INTERVAL_MSEC UINT_MAX + +struct wmi_sta_uapsd_auto_trig_param { + __le32 wmm_ac; + __le32 user_priority; + __le32 service_interval; + __le32 suspend_interval; + __le32 delay_interval; +}; + +struct wmi_sta_uapsd_auto_trig_cmd_fixed_param { + __le32 vdev_id; + struct wmi_mac_addr peer_macaddr; + __le32 num_ac; +}; + +struct wmi_sta_uapsd_auto_trig_arg { + u32 wmm_ac; + u32 user_priority; + u32 service_interval; + u32 suspend_interval; + u32 delay_interval; +}; + enum wmi_sta_powersave_param { /* * Controls how frames are retrievd from AP while STA is sleeping @@ -4120,7 +4309,7 @@ struct wmi_bcn_info { struct wmi_host_swba_event { __le32 vdev_map; - struct wmi_bcn_info bcn_info[1]; + struct wmi_bcn_info bcn_info[0]; } __packed; #define WMI_MAX_AP_VDEV 16 @@ -4325,7 +4514,7 @@ struct wmi_peer_set_q_empty_callback_cmd { #define WMI_PEER_SPATIAL_MUX 0x00200000 #define WMI_PEER_VHT 0x02000000 #define WMI_PEER_80MHZ 0x04000000 -#define WMI_PEER_PMF 0x08000000 +#define WMI_PEER_VHT_2G 0x08000000 /* * Peer rate capabilities. @@ -4476,6 +4665,11 @@ enum wmi_sta_keepalive_method { WMI_STA_KEEPALIVE_METHOD_UNSOLICITATED_ARP_RESPONSE = 2, }; +#define WMI_STA_KEEPALIVE_INTERVAL_DISABLE 0 + +/* Firmware crashes if keepalive interval exceeds this limit */ +#define WMI_STA_KEEPALIVE_INTERVAL_MAX_SECONDS 0xffff + /* note: ip4 addresses are in network byte order, i.e. big endian */ struct wmi_sta_keepalive_arp_resp { __be32 src_ip4_addr; @@ -4491,6 +4685,16 @@ struct wmi_sta_keepalive_cmd { struct wmi_sta_keepalive_arp_resp arp_resp; } __packed; +struct wmi_sta_keepalive_arg { + u32 vdev_id; + u32 enabled; + u32 method; + u32 interval; + __be32 src_ip4_addr; + __be32 dest_ip4_addr; + const u8 dest_mac_addr[ETH_ALEN]; +}; + enum wmi_force_fw_hang_type { WMI_FORCE_FW_HANG_ASSERT = 1, WMI_FORCE_FW_HANG_NO_DETECT, @@ -4567,6 +4771,58 @@ struct wmi_dbglog_cfg_cmd { #define WMI_MAX_MEM_REQS 16 +struct wmi_scan_ev_arg { + __le32 event_type; /* %WMI_SCAN_EVENT_ */ + __le32 reason; /* %WMI_SCAN_REASON_ */ + __le32 channel_freq; /* only valid for WMI_SCAN_EVENT_FOREIGN_CHANNEL */ + __le32 scan_req_id; + __le32 scan_id; + __le32 vdev_id; +}; + +struct wmi_mgmt_rx_ev_arg { + __le32 channel; + __le32 snr; + __le32 rate; + __le32 phy_mode; + __le32 buf_len; + __le32 status; /* %WMI_RX_STATUS_ */ +}; + +struct wmi_ch_info_ev_arg { + __le32 err_code; + __le32 freq; + __le32 cmd_flags; + __le32 noise_floor; + __le32 rx_clear_count; + __le32 cycle_count; +}; + +struct wmi_vdev_start_ev_arg { + __le32 vdev_id; + __le32 req_id; + __le32 resp_type; /* %WMI_VDEV_RESP_ */ + __le32 status; +}; + +struct wmi_peer_kick_ev_arg { + const u8 *mac_addr; +}; + +struct wmi_swba_ev_arg { + __le32 vdev_map; + const struct wmi_tim_info *tim_info[WMI_MAX_AP_VDEV]; + const struct wmi_p2p_noa_info *noa_info[WMI_MAX_AP_VDEV]; +}; + +struct wmi_phyerr_ev_arg { + __le32 num_phyerrs; + __le32 tsf_l32; + __le32 tsf_u32; + __le32 buf_len; + const struct wmi_phyerr *phyerrs; +}; + struct wmi_svc_rdy_ev_arg { __le32 min_tx_power; __le32 max_tx_power; @@ -4574,6 +4830,7 @@ struct wmi_svc_rdy_ev_arg { __le32 vht_cap; __le32 sw_ver0; __le32 sw_ver1; + __le32 fw_build; __le32 phy_capab; __le32 num_rf_chains; __le32 eeprom_rd; @@ -4583,83 +4840,99 @@ struct wmi_svc_rdy_ev_arg { const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS]; }; +struct wmi_rdy_ev_arg { + __le32 sw_version; + __le32 abi_version; + __le32 status; + const u8 *mac_addr; +}; + +struct wmi_pdev_temperature_event { + /* temperature value in Celcius degree */ + __le32 temperature; +} __packed; + struct ath10k; struct ath10k_vif; -struct ath10k_fw_stats; +struct ath10k_fw_stats_pdev; +struct ath10k_fw_stats_peer; int ath10k_wmi_attach(struct ath10k *ar); void ath10k_wmi_detach(struct ath10k *ar); int ath10k_wmi_wait_for_service_ready(struct ath10k *ar); int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar); +struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len); int ath10k_wmi_connect(struct ath10k *ar); struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len); int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); - -int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt); -int ath10k_wmi_pdev_resume_target(struct ath10k *ar); -int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, - u16 rd5g, u16 ctl2g, u16 ctl5g, - enum wmi_dfs_region dfs_reg); -int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value); -int ath10k_wmi_cmd_init(struct ath10k *ar); -int ath10k_wmi_start_scan(struct ath10k *ar, const struct wmi_start_scan_arg *); +int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, + u32 cmd_id); void ath10k_wmi_start_scan_init(struct ath10k *ar, struct wmi_start_scan_arg *); -int ath10k_wmi_stop_scan(struct ath10k *ar, - const struct wmi_stop_scan_arg *arg); -int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id, - enum wmi_vdev_type type, - enum wmi_vdev_subtype subtype, - const u8 macaddr[ETH_ALEN]); -int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id); -int ath10k_wmi_vdev_start(struct ath10k *ar, - const struct wmi_vdev_start_request_arg *); -int ath10k_wmi_vdev_restart(struct ath10k *ar, - const struct wmi_vdev_start_request_arg *); -int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id); -int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, - const u8 *bssid); -int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id); -int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, - u32 param_id, u32 param_value); -int ath10k_wmi_vdev_install_key(struct ath10k *ar, - const struct wmi_vdev_install_key_arg *arg); -int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar, - const struct wmi_vdev_spectral_conf_arg *arg); -int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger, - u32 enable); -int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id, - const u8 peer_addr[ETH_ALEN]); -int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id, - const u8 peer_addr[ETH_ALEN]); -int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id, - const u8 peer_addr[ETH_ALEN], u32 tid_bitmap); -int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, - const u8 *peer_addr, - enum wmi_peer_param param_id, u32 param_value); -int ath10k_wmi_peer_assoc(struct ath10k *ar, - const struct wmi_peer_assoc_complete_arg *arg); -int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id, - enum wmi_sta_ps_mode psmode); -int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id, - enum wmi_sta_powersave_param param_id, - u32 value); -int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac, - enum wmi_ap_ps_peer_param param_id, u32 value); -int ath10k_wmi_scan_chan_list(struct ath10k *ar, - const struct wmi_scan_chan_list_arg *arg); -int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif); -int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, - const struct wmi_pdev_set_wmm_params_arg *arg); -int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id); -int ath10k_wmi_force_fw_hang(struct ath10k *ar, - enum wmi_force_fw_hang_type type, u32 delay_ms); -int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb); -int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable); -int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb, - struct ath10k_fw_stats *stats); -int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_list); -int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar); + +void ath10k_wmi_pull_pdev_stats_base(const struct wmi_pdev_stats_base *src, + struct ath10k_fw_stats_pdev *dst); +void ath10k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src, + struct ath10k_fw_stats_pdev *dst); +void ath10k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src, + struct ath10k_fw_stats_pdev *dst); +void ath10k_wmi_pull_pdev_stats_extra(const struct wmi_pdev_stats_extra *src, + struct ath10k_fw_stats_pdev *dst); +void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src, + struct ath10k_fw_stats_peer *dst); +void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar, + struct wmi_host_mem_chunks *chunks); +void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn, + const struct wmi_start_scan_arg *arg); +void ath10k_wmi_set_wmm_param(struct wmi_wmm_params *params, + const struct wmi_wmm_params_arg *arg); +void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, + const struct wmi_channel_arg *arg); +int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg); + +int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb); +int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb); +int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_dfs(struct ath10k *ar, + const struct wmi_phyerr *phyerr, u64 tsf); +void ath10k_wmi_event_spectral_scan(struct ath10k *ar, + const struct wmi_phyerr *phyerr, + u64 tsf); +void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_debug_print(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar, + struct sk_buff *skb); +void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar, + struct sk_buff *skb); +void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar, + struct sk_buff *skb); +void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_delba_complete(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_addba_complete(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar, + struct sk_buff *skb); +void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb); +void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb); +int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb); #endif /* _WMI_H_ */ diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index 8f387cf67340..2ca88b593e4c 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -227,7 +227,6 @@ static struct platform_driver ath_ahb_driver = { .remove = ath_ahb_remove, .driver = { .name = "ar231x-wmac", - .owner = THIS_MODULE, }, }; diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 19eab2a69ad5..3b4a6463d87a 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -672,10 +672,10 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) spin_lock_bh(&common->cc_lock); ath_hw_cycle_counters_update(common); if (cc->cycles > 0) { - ah->survey.channel_time += cc->cycles / div; - ah->survey.channel_time_busy += cc->rx_busy / div; - ah->survey.channel_time_rx += cc->rx_frame / div; - ah->survey.channel_time_tx += cc->tx_frame / div; + ah->survey.time += cc->cycles / div; + ah->survey.time_busy += cc->rx_busy / div; + ah->survey.time_rx += cc->rx_frame / div; + ah->survey.time_tx += cc->tx_frame / div; } memset(cc, 0, sizeof(*cc)); spin_unlock_bh(&common->cc_lock); @@ -686,10 +686,10 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) survey->noise = ah->ah_noise_floor; survey->filled = SURVEY_INFO_NOISE_DBM | SURVEY_INFO_IN_USE | - SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_RX | - SURVEY_INFO_CHANNEL_TIME_TX; + SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_RX | + SURVEY_INFO_TIME_TX; return 0; } diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index c60d36aa13e2..bf29da5e90da 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -912,6 +912,7 @@ ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | (ah->ah_version == AR5K_AR5210 ? AR5K_STA_ID1_PWR_SV : 0); + /* fall through */ case NL80211_IFTYPE_MONITOR: pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE | (ah->ah_version == AR5K_AR5210 ? diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index a3399c4f13a9..b9b651ea9851 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -478,7 +478,7 @@ ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags) regval = ioread32(reg); iowrite32(regval | val, reg); regval = ioread32(reg); - usleep_range(100, 150); + udelay(100); /* NB: should be atomic */ /* Bring BB/MAC out of reset */ iowrite32(regval & ~val, reg); diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 7a5337877a0c..85da63a67faf 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1799,20 +1799,20 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, if (vif->target_stats.rx_byte) { sinfo->rx_bytes = vif->target_stats.rx_byte; - sinfo->filled |= STATION_INFO_RX_BYTES64; + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64); sinfo->rx_packets = vif->target_stats.rx_pkt; - sinfo->filled |= STATION_INFO_RX_PACKETS; + sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS); } if (vif->target_stats.tx_byte) { sinfo->tx_bytes = vif->target_stats.tx_byte; - sinfo->filled |= STATION_INFO_TX_BYTES64; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64); sinfo->tx_packets = vif->target_stats.tx_pkt; - sinfo->filled |= STATION_INFO_TX_PACKETS; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); } sinfo->signal = vif->target_stats.cs_rssi; - sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); rate = vif->target_stats.tx_ucast_rate; @@ -1827,6 +1827,7 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, } sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + sinfo->txrate.bw = RATE_INFO_BW_20; } else if (is_rate_ht40(rate, &mcs, &sgi)) { if (sgi) { sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; @@ -1835,7 +1836,7 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, sinfo->txrate.mcs = mcs; } - sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + sinfo->txrate.bw = RATE_INFO_BW_40; sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; } else { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, @@ -1844,12 +1845,12 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, return 0; } - sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); if (test_bit(CONNECTED, &vif->flags) && test_bit(DTIM_PERIOD_AVAIL, &vif->flags) && vif->nw_type == INFRA_NETWORK) { - sinfo->filled |= STATION_INFO_BSS_PARAM; + sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM); sinfo->bss_param.flags = 0; sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period; sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int; diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 933aef025698..b42ba46b5030 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -488,7 +488,6 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr, sinfo.assoc_req_ies = ies; sinfo.assoc_req_ies_len = ies_len; - sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; cfg80211_new_sta(vif->ndev, mac_addr, &sinfo, GFP_KERNEL); diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index e000c4c27881..bd4a1a655f42 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -43,6 +43,10 @@ static const struct platform_device_id ath9k_platform_id_table[] = { .name = "qca953x_wmac", .driver_data = AR9300_DEVID_AR953X, }, + { + .name = "qca956x_wmac", + .driver_data = AR9300_DEVID_QCA956X, + }, {}, }; diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index ba502a2d199b..ca01d17d130f 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -259,7 +259,8 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel, entry_cck->fir_step_level); /* Skip MRC CCK for pre AR9003 families */ - if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) + if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah) || + AR_SREV_9565(ah) || AR_SREV_9561(ah)) return; if (aniState->mrcCCK != entry_cck->mrc_cck_on) diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 5829074208fa..f273427fdd29 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -22,6 +22,21 @@ /* All code below is for AR5008, AR9001, AR9002 */ +#define AR5008_OFDM_RATES 8 +#define AR5008_HT_SS_RATES 8 +#define AR5008_HT_DS_RATES 8 + +#define AR5008_HT20_SHIFT 16 +#define AR5008_HT40_SHIFT 24 + +#define AR5008_11NA_OFDM_SHIFT 0 +#define AR5008_11NA_HT_SS_SHIFT 8 +#define AR5008_11NA_HT_DS_SHIFT 16 + +#define AR5008_11NG_OFDM_SHIFT 4 +#define AR5008_11NG_HT_SS_SHIFT 12 +#define AR5008_11NG_HT_DS_SHIFT 20 + static const int firstep_table[] = /* level: 0 1 2 3 4 5 6 7 8 */ { -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */ @@ -1235,6 +1250,71 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah) conf->radar_inband = 8; } +static void ar5008_hw_init_txpower_cck(struct ath_hw *ah, int16_t *rate_array) +{ +#define CCK_DELTA(x) ((OLC_FOR_AR9280_20_LATER) ? max((x) - 2, 0) : (x)) + ah->tx_power[0] = CCK_DELTA(rate_array[rate1l]); + ah->tx_power[1] = CCK_DELTA(min(rate_array[rate2l], + rate_array[rate2s])); + ah->tx_power[2] = CCK_DELTA(min(rate_array[rate5_5l], + rate_array[rate5_5s])); + ah->tx_power[3] = CCK_DELTA(min(rate_array[rate11l], + rate_array[rate11s])); +#undef CCK_DELTA +} + +static void ar5008_hw_init_txpower_ofdm(struct ath_hw *ah, int16_t *rate_array, + int offset) +{ + int i, idx = 0; + + for (i = offset; i < offset + AR5008_OFDM_RATES; i++) { + ah->tx_power[i] = rate_array[idx]; + idx++; + } +} + +static void ar5008_hw_init_txpower_ht(struct ath_hw *ah, int16_t *rate_array, + int ss_offset, int ds_offset, + bool is_40, int ht40_delta) +{ + int i, mcs_idx = (is_40) ? AR5008_HT40_SHIFT : AR5008_HT20_SHIFT; + + for (i = ss_offset; i < ss_offset + AR5008_HT_SS_RATES; i++) { + ah->tx_power[i] = rate_array[mcs_idx] + ht40_delta; + mcs_idx++; + } + memcpy(&ah->tx_power[ds_offset], &ah->tx_power[ss_offset], + AR5008_HT_SS_RATES); +} + +void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array, + struct ath9k_channel *chan, int ht40_delta) +{ + if (IS_CHAN_5GHZ(chan)) { + ar5008_hw_init_txpower_ofdm(ah, rate_array, + AR5008_11NA_OFDM_SHIFT); + if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) { + ar5008_hw_init_txpower_ht(ah, rate_array, + AR5008_11NA_HT_SS_SHIFT, + AR5008_11NA_HT_DS_SHIFT, + IS_CHAN_HT40(chan), + ht40_delta); + } + } else { + ar5008_hw_init_txpower_cck(ah, rate_array); + ar5008_hw_init_txpower_ofdm(ah, rate_array, + AR5008_11NG_OFDM_SHIFT); + if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) { + ar5008_hw_init_txpower_ht(ah, rate_array, + AR5008_11NG_HT_SS_SHIFT, + AR5008_11NG_HT_DS_SHIFT, + IS_CHAN_HT40(chan), + ht40_delta); + } + } +} + int ar5008_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 06ab71db6e80..174442beb952 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1203,24 +1203,41 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah) static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) { int offset[8] = {0}, total = 0, test; - int agc_out, i; + int agc_out, i, peak_detect_threshold; + if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) + peak_detect_threshold = 8; + else + peak_detect_threshold = 0; + + /* + * Turn off LNA/SW. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0x1); REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC, 0x0); - if (is_2g) - REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), - AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0); - else - REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), - AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0); + if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9330_11(ah)) { + if (is_2g) + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0); + else + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0); + } + + /* + * Turn off RXON. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), AR_PHY_65NM_RXTX2_RXON_OVR, 0x1); REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), AR_PHY_65NM_RXTX2_RXON, 0x0); + /* + * Turn on AGC for cal. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1); REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), @@ -1228,16 +1245,19 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0x1); - if (AR_SREV_9330_11(ah)) { + if (AR_SREV_9330_11(ah)) REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0); - } else { + + if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) { if (is_2g) REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), - AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, 0x0); + AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, + peak_detect_threshold); else REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), - AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, 0x0); + AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, + peak_detect_threshold); } for (i = 6; i > 0; i--) { @@ -1266,10 +1286,19 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, total); + /* + * Turn on LNA. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0); + /* + * Turn off RXON. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), AR_PHY_65NM_RXTX2_RXON_OVR, 0); + /* + * Turn off peak detect calibration. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0); } @@ -1611,8 +1640,14 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, skip_tx_iqcal: if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { - if (AR_SREV_9330_11(ah)) - ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan)); + if (AR_SREV_9330_11(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) { + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->rxchainmask & (1 << i))) + continue; + ar9003_hw_manual_peak_cal(ah, i, + IS_CHAN_2GHZ(chan)); + } + } /* * For non-AR9550 chips, we just trigger AGC calibration diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 08225a0067c2..8b4561e8ce1a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3536,7 +3536,7 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) int bias = ar9003_modal_header(ah, is2ghz)->xpaBiasLvl; if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah) || - AR_SREV_9531(ah)) + AR_SREV_9531(ah) || AR_SREV_9561(ah)) REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); else if (AR_SREV_9462(ah) || AR_SREV_9550(ah) || AR_SREV_9565(ah)) REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); @@ -3599,7 +3599,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_AR9462_ALL, value); - } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) { REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_AR9550_ALL, value); } else @@ -3929,9 +3929,13 @@ void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set); if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set)) return; - } else if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { + } else if (AR_SREV_9462(ah) || AR_SREV_9565(ah) || + AR_SREV_9561(ah)) { reg_val = le32_to_cpu(pBase->swreg); REG_WRITE(ah, AR_PHY_PMU1, reg_val); + + if (AR_SREV_9561(ah)) + REG_WRITE(ah, AR_PHY_PMU2, 0x10200000); } else { /* Internal regulator is ON. Write swreg register. */ reg_val = le32_to_cpu(pBase->swreg); @@ -4034,7 +4038,8 @@ static void ar9003_hw_xpa_timing_control_apply(struct ath_hw *ah, bool is2ghz) if (!AR_SREV_9300(ah) && !AR_SREV_9340(ah) && !AR_SREV_9580(ah) && - !AR_SREV_9531(ah)) + !AR_SREV_9531(ah) && + !AR_SREV_9561(ah)) return; xpa_ctl = ar9003_modal_header(ah, is2ghz)->txFrameToXpaOn; @@ -4812,7 +4817,7 @@ static void ar9003_hw_power_control_override(struct ath_hw *ah, } tempslope: - if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) { u8 txmask = (eep->baseEepHeader.txrxMask & 0xf0) >> 4; /* diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 06ad2172030e..4335ccbe7d7e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -29,6 +29,7 @@ #include "ar9565_1p0_initvals.h" #include "ar9565_1p1_initvals.h" #include "ar953x_initvals.h" +#include "ar956x_initvals.h" /* General hardware code for the AR9003 hadware family */ @@ -358,6 +359,40 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModesFastClock, qca953x_1p0_modes_fast_clock); + } else if (AR_SREV_9561(ah)) { + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], + qca956x_1p0_mac_core); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + qca956x_1p0_mac_postamble); + + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + qca956x_1p0_baseband_core); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + qca956x_1p0_baseband_postamble); + + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + qca956x_1p0_radio_core); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + qca956x_1p0_radio_postamble); + + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + qca956x_1p0_soc_preamble); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + qca956x_1p0_soc_postamble); + + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca956x_1p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca956x_1p0_common_wo_xlna_rx_gain_bounds); + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_no_xpa_tx_gain_table); + + INIT_INI_ARRAY(&ah->ini_dfs, + qca956x_1p0_baseband_postamble_dfs_channel); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + qca956x_1p0_baseband_core_txfir_coeff_japan_2484); + INIT_INI_ARRAY(&ah->iniModesFastClock, + qca956x_1p0_modes_fast_clock); } else if (AR_SREV_9580(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], @@ -544,6 +579,9 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) else if (AR_SREV_9531_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, qca953x_2p0_modes_xpa_tx_gain_table); + else if (AR_SREV_9561(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_xpa_tx_gain_table); else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_lowest_ob_db_tx_gain_table); @@ -594,7 +632,10 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) else INIT_INI_ARRAY(&ah->iniModesTxGain, qca953x_1p0_modes_no_xpa_tx_gain_table); - } else if (AR_SREV_9462_21(ah)) + } else if (AR_SREV_9561(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_no_xpa_tx_gain_table); + else if (AR_SREV_9462_21(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9462_2p1_modes_high_ob_db_tx_gain); else if (AR_SREV_9462_20(ah)) @@ -628,6 +669,9 @@ static void ar9003_tx_gain_table_mode2(struct ath_hw *ah) else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_low_ob_db_tx_gain_table); + else if (AR_SREV_9561(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_no_xpa_low_ob_db_tx_gain_table); else if (AR_SREV_9565_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p1_modes_low_ob_db_tx_gain_table); @@ -699,6 +743,9 @@ static void ar9003_tx_gain_table_mode5(struct ath_hw *ah) else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_type5_tx_gain_table); + else if (AR_SREV_9561(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_no_xpa_green_tx_gain_table); else if (AR_SREV_9300_22(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_type5_tx_gain_table_2p2); @@ -770,6 +817,13 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) qca953x_1p0_common_rx_gain_table); INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, qca953x_1p0_common_rx_gain_bounds); + } else if (AR_SREV_9561(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca956x_1p0_common_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca956x_1p0_common_rx_gain_bounds); + INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna, + qca956x_1p0_xlna_only); } else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9580_1p0_rx_gain_table); @@ -825,6 +879,11 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) qca953x_2p0_common_wo_xlna_rx_gain_table); INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, qca953x_2p0_common_wo_xlna_rx_gain_bounds); + } else if (AR_SREV_9561(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca956x_1p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca956x_1p0_common_wo_xlna_rx_gain_bounds); } else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9580_1p0_wo_xlna_rx_gain_table); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index ae6cde273414..1ad66b76749b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -183,7 +183,8 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) } else { channelSel = CHANSEL_2G(freq) >> 1; } - } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) { if (ah->is_clk_25mhz) div = 75; else @@ -198,7 +199,8 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) /* Set to 2G mode */ bMode = 1; } else { - if ((AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) && + if ((AR_SREV_9340(ah) || AR_SREV_9550(ah) || + AR_SREV_9531(ah) || AR_SREV_9561(ah)) && ah->is_clk_25mhz) { channelSel = freq / 75; chan_frac = ((freq % 75) * 0x20000) / 75; @@ -265,7 +267,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, */ if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || - AR_SREV_9550(ah)) { + AR_SREV_9550(ah) || AR_SREV_9561(ah)) { if (spur_fbin_ptr[0] == 0) /* No spur */ return; max_spur_cnts = 5; @@ -292,7 +294,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, negative = 0; if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || - AR_SREV_9550(ah)) + AR_SREV_9550(ah) || AR_SREV_9561(ah)) cur_bb_spur = ath9k_hw_fbin2freq(spur_fbin_ptr[i], IS_CHAN_2GHZ(chan)); else @@ -641,8 +643,10 @@ static void ar9003_hw_set_channel_regs(struct ath_hw *ah, (REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO); /* Enable 11n HT, 20 MHz */ - phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 | - AR_PHY_GC_SHORT_GI_40 | enableDacFifo; + phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SHORT_GI_40 | enableDacFifo; + + if (!AR_SREV_9561(ah)) + phymode |= AR_PHY_GC_SINGLE_HT_LTF1; /* Configure baseband for dynamic 20/40 operation */ if (IS_CHAN_HT40(chan)) { @@ -745,7 +749,8 @@ static void ar9003_hw_override_ini(struct ath_hw *ah) else ah->enabled_cals &= ~TX_CL_CAL; - if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) { + if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah) || + AR_SREV_9561(ah)) { if (ah->is_clk_25mhz) { REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1); REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); @@ -812,6 +817,19 @@ static int ar9550_hw_get_modes_txgain_index(struct ath_hw *ah, return ret; } +static int ar9561_hw_get_modes_txgain_index(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + if (IS_CHAN_2GHZ(chan)) { + if (IS_CHAN_HT40(chan)) + return 1; + else + return 2; + } + + return 0; +} + static void ar9003_doubler_fix(struct ath_hw *ah) { if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9550(ah)) { @@ -911,21 +929,29 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, REG_WRITE_ARRAY(&ah->ini_modes_rxgain_5g_xlna, modesIndex, regWrites); } + + if (AR_SREV_9561(ah) && (ar9003_hw_get_rx_gain_idx(ah) == 0)) + REG_WRITE_ARRAY(&ah->ini_modes_rxgain_5g_xlna, + modesIndex, regWrites); } - if (AR_SREV_9550(ah)) + if (AR_SREV_9550(ah) || AR_SREV_9561(ah)) REG_WRITE_ARRAY(&ah->ini_modes_rx_gain_bounds, modesIndex, regWrites); /* * TXGAIN initvals. */ - if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) { int modes_txgain_index = 1; if (AR_SREV_9550(ah)) modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan); + if (AR_SREV_9561(ah)) + modes_txgain_index = + ar9561_hw_get_modes_txgain_index(ah, chan); + if (modes_txgain_index < 0) return -EINVAL; @@ -1989,7 +2015,8 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) priv_ops->rf_set_freq = ar9003_hw_set_channel; priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate; - if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) priv_ops->compute_pll_control = ar9003_hw_compute_pll_control_soc; else priv_ops->compute_pll_control = ar9003_hw_compute_pll_control; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index fd090b1f2d0f..c311b2bfdb00 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -454,7 +454,7 @@ #define AR_PHY_GEN_CTRL (AR_SM_BASE + 0x4) #define AR_PHY_MODE (AR_SM_BASE + 0x8) #define AR_PHY_ACTIVE (AR_SM_BASE + 0xc) -#define AR_PHY_SPUR_MASK_A (AR_SM_BASE + 0x20) +#define AR_PHY_SPUR_MASK_A (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x18 : 0x20)) #define AR_PHY_SPUR_MASK_B (AR_SM_BASE + 0x24) #define AR_PHY_SPECTRAL_SCAN (AR_SM_BASE + 0x28) #define AR_PHY_RADAR_BW_FILTER (AR_SM_BASE + 0x2c) @@ -506,7 +506,7 @@ #define AR_PHY_TEST_CHAIN_SEL 0xC0000000 #define AR_PHY_TEST_CHAIN_SEL_S 30 -#define AR_PHY_TEST_CTL_STATUS (AR_SM_BASE + 0x164) +#define AR_PHY_TEST_CTL_STATUS (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x160 : 0x164)) #define AR_PHY_TEST_CTL_TSTDAC_EN 0x1 #define AR_PHY_TEST_CTL_TSTDAC_EN_S 0 #define AR_PHY_TEST_CTL_TX_OBS_SEL 0x1C @@ -525,7 +525,7 @@ #define AR_PHY_CHAN_STATUS (AR_SM_BASE + 0x16c) -#define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + 0x170) +#define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x16c : 0x170)) #define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ 0x00000008 #define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ_S 3 @@ -536,7 +536,7 @@ #define AR_PHY_SCRAMBLER_SEED (AR_SM_BASE + 0x190) #define AR_PHY_CCK_TX_CTRL (AR_SM_BASE + 0x194) -#define AR_PHY_HEAVYCLIP_CTL (AR_SM_BASE + 0x1a4) +#define AR_PHY_HEAVYCLIP_CTL (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x198 : 0x1a4)) #define AR_PHY_HEAVYCLIP_20 (AR_SM_BASE + 0x1a8) #define AR_PHY_HEAVYCLIP_40 (AR_SM_BASE + 0x1ac) #define AR_PHY_ILLEGAL_TXRATE (AR_SM_BASE + 0x1b0) @@ -726,21 +726,24 @@ #define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \ (AR_SREV_9462(ah) ? 0x16290 : 0x16284)) -#define AR_CH0_TOP2_XPABIASLVL 0xf000 +#define AR_CH0_TOP2_XPABIASLVL (AR_SREV_9561(ah) ? 0x1e00 : 0xf000) #define AR_CH0_TOP2_XPABIASLVL_S 12 #define AR_CH0_XTAL (AR_SREV_9300(ah) ? 0x16294 : \ - ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16298 : 0x16290)) + ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16298 : \ + (AR_SREV_9561(ah) ? 0x162c0 : 0x16290))) #define AR_CH0_XTAL_CAPINDAC 0x7f000000 #define AR_CH0_XTAL_CAPINDAC_S 24 #define AR_CH0_XTAL_CAPOUTDAC 0x00fe0000 #define AR_CH0_XTAL_CAPOUTDAC_S 17 -#define AR_PHY_PMU1 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16340 : 0x16c40) +#define AR_PHY_PMU1 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16340 : \ + (AR_SREV_9561(ah) ? 0x16cc0 : 0x16c40)) #define AR_PHY_PMU1_PWD 0x1 #define AR_PHY_PMU1_PWD_S 0 -#define AR_PHY_PMU2 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16344 : 0x16c44) +#define AR_PHY_PMU2 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16344 : \ + (AR_SREV_9561(ah) ? 0x16cc4 : 0x16c44)) #define AR_PHY_PMU2_PGM 0x00200000 #define AR_PHY_PMU2_PGM_S 21 diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c index 81c88dd606dc..86bfc9604dca 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -17,23 +17,9 @@ #include #include "ath9k.h" #include "reg.h" +#include "reg_wow.h" #include "hw-ops.h" -const char *ath9k_hw_wow_event_to_string(u32 wow_event) -{ - if (wow_event & AH_WOW_MAGIC_PATTERN_EN) - return "Magic pattern"; - if (wow_event & AH_WOW_USER_PATTERN_EN) - return "User pattern"; - if (wow_event & AH_WOW_LINK_CHANGE) - return "Link change"; - if (wow_event & AH_WOW_BEACON_MISS) - return "Beacon miss"; - - return "unknown reason"; -} -EXPORT_SYMBOL(ath9k_hw_wow_event_to_string); - static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -49,6 +35,15 @@ static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) return; } + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { + if (!REG_READ(ah, AR_MAC_PCU_GEN_TIMER_TSF_SEL)) + REG_CLR_BIT(ah, AR_DIRECT_CONNECT, AR_DC_TSF2_ENABLE); + } else if (AR_SREV_9485(ah)){ + if (!(REG_READ(ah, AR_NDP2_TIMER_MODE) & + AR_GEN_TIMERS2_MODE_ENABLE_MASK)) + REG_CLR_BIT(ah, AR_DIRECT_CONNECT, AR_DC_TSF2_ENABLE); + } + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); } @@ -67,11 +62,15 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) /* set the transmit buffer */ ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16)); ctl[1] = 0; - ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */ ctl[4] = 0; ctl[7] = (ah->txchainmask) << 2; ctl[2] = 0xf << 16; /* tx_tries 0 */ + if (IS_CHAN_2GHZ(ah->curchan)) + ctl[3] = 0x1b; /* CCK_1M */ + else + ctl[3] = 0xb; /* OFDM_6M */ + for (i = 0; i < KAL_NUM_DESC_WORDS; i++) REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); @@ -103,21 +102,22 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) } -void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, - u8 *user_mask, int pattern_count, - int pattern_len) +int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, + u8 *user_mask, int pattern_count, + int pattern_len) { int i; u32 pattern_val, mask_val; u32 set, clr; - /* FIXME: should check count by querying the hardware capability */ - if (pattern_count >= MAX_NUM_PATTERN) - return; + if (pattern_count >= ah->wow.max_patterns) + return -ENOSPC; - REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count)); + if (pattern_count < MAX_NUM_PATTERN_LEGACY) + REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count)); + else + REG_SET_BIT(ah, AR_MAC_PCU_WOW4, BIT(pattern_count - 8)); - /* set the registers for pattern */ for (i = 0; i < MAX_PATTERN_SIZE; i += 4) { memcpy(&pattern_val, user_pattern, 4); REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i), @@ -125,49 +125,42 @@ void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, user_pattern += 4; } - /* set the registers for mask */ for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) { memcpy(&mask_val, user_mask, 4); REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val); user_mask += 4; } - /* set the pattern length to be matched - * - * AR_WOW_LENGTH1_REG1 - * bit 31:24 pattern 0 length - * bit 23:16 pattern 1 length - * bit 15:8 pattern 2 length - * bit 7:0 pattern 3 length - * - * AR_WOW_LENGTH1_REG2 - * bit 31:24 pattern 4 length - * bit 23:16 pattern 5 length - * bit 15:8 pattern 6 length - * bit 7:0 pattern 7 length - * - * the below logic writes out the new - * pattern length for the corresponding - * pattern_count, while masking out the - * other fields - */ - - ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); + if (pattern_count < MAX_NUM_PATTERN_LEGACY) + ah->wow.wow_event_mask |= + BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); + else + ah->wow.wow_event_mask2 |= + BIT((pattern_count - 8) + AR_WOW_PAT_FOUND_SHIFT); if (pattern_count < 4) { - /* Pattern 0-3 uses AR_WOW_LENGTH1 register */ set = (pattern_len & AR_WOW_LENGTH_MAX) << AR_WOW_LEN1_SHIFT(pattern_count); clr = AR_WOW_LENGTH1_MASK(pattern_count); REG_RMW(ah, AR_WOW_LENGTH1, set, clr); - } else { - /* Pattern 4-7 uses AR_WOW_LENGTH2 register */ + } else if (pattern_count < 8) { set = (pattern_len & AR_WOW_LENGTH_MAX) << AR_WOW_LEN2_SHIFT(pattern_count); clr = AR_WOW_LENGTH2_MASK(pattern_count); REG_RMW(ah, AR_WOW_LENGTH2, set, clr); + } else if (pattern_count < 12) { + set = (pattern_len & AR_WOW_LENGTH_MAX) << + AR_WOW_LEN3_SHIFT(pattern_count); + clr = AR_WOW_LENGTH3_MASK(pattern_count); + REG_RMW(ah, AR_WOW_LENGTH3, set, clr); + } else if (pattern_count < MAX_NUM_PATTERN) { + set = (pattern_len & AR_WOW_LENGTH_MAX) << + AR_WOW_LEN4_SHIFT(pattern_count); + clr = AR_WOW_LENGTH4_MASK(pattern_count); + REG_RMW(ah, AR_WOW_LENGTH4, set, clr); } + return 0; } EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern); @@ -189,7 +182,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) * register. This mask will clean it up. */ - val &= ah->wow_event_mask; + val &= ah->wow.wow_event_mask; if (val) { if (val & AR_WOW_MAGIC_PAT_FOUND) @@ -233,190 +226,192 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) if (ah->is_pciexpress) ath9k_hw_configpcipowersave(ah, false); - ah->wow_event_mask = 0; + ah->wow.wow_event_mask = 0; return wow_status; } EXPORT_SYMBOL(ath9k_hw_wow_wakeup); +static void ath9k_hw_wow_set_arwr_reg(struct ath_hw *ah) +{ + u32 wa_reg; + + if (!ah->is_pciexpress) + return; + + /* + * We need to untie the internal POR (power-on-reset) + * to the external PCI-E reset. We also need to tie + * the PCI-E Phy reset to the PCI-E reset. + */ + wa_reg = REG_READ(ah, AR_WA); + wa_reg &= ~AR_WA_UNTIE_RESET_EN; + wa_reg |= AR_WA_RESET_EN; + wa_reg |= AR_WA_POR_SHORT; + + REG_WRITE(ah, AR_WA, wa_reg); +} + void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) { u32 wow_event_mask; - u32 set, clr; + u32 keep_alive, magic_pattern, host_pm_ctrl; + + wow_event_mask = ah->wow.wow_event_mask; /* - * wow_event_mask is a mask to the AR_WOW_PATTERN register to - * indicate which WoW events we have enabled. The WoW events - * are from the 'pattern_enable' in this function and - * 'pattern_count' of ath9k_hw_wow_apply_pattern() - */ - wow_event_mask = ah->wow_event_mask; - - /* - * Untie Power-on-Reset from the PCI-E-Reset. When we are in - * WOW sleep, we do want the Reset from the PCI-E to disturb - * our hw state - */ - if (ah->is_pciexpress) { - /* - * we need to untie the internal POR (power-on-reset) - * to the external PCI-E reset. We also need to tie - * the PCI-E Phy reset to the PCI-E reset. - */ - set = AR_WA_RESET_EN | AR_WA_POR_SHORT; - clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE; - REG_RMW(ah, AR_WA, set, clr); - } - - /* - * set the power states appropriately and enable PME - */ - set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA | - AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR; - - /* - * set and clear WOW_PME_CLEAR registers for the chip + * AR_PMCTRL_HOST_PME_EN - Override PME enable in configuration + * space and allow MAC to generate WoW anyway. + * + * AR_PMCTRL_PWR_PM_CTRL_ENA - ??? + * + * AR_PMCTRL_AUX_PWR_DET - PCI core SYS_AUX_PWR_DET signal, + * needs to be set for WoW in PCI mode. + * + * AR_PMCTRL_WOW_PME_CLR - WoW Clear Signal going to the MAC. + * + * Set the power states appropriately and enable PME. + * + * Set and clear WOW_PME_CLEAR for the chip * to generate next wow signal. */ - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); - clr = AR_PMCTRL_WOW_PME_CLR; - REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); + REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_HOST_PME_EN | + AR_PMCTRL_PWR_PM_CTRL_ENA | + AR_PMCTRL_AUX_PWR_DET | + AR_PMCTRL_WOW_PME_CLR); + REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR); /* - * Setup for: - * - beacon misses - * - magic pattern - * - keep alive timeout - * - pattern matching + * Random Backoff. + * + * 31:28 in AR_WOW_PATTERN : Indicates the number of bits used in the + * contention window. For value N, + * the random backoff will be selected between + * 0 and (2 ^ N) - 1. */ + REG_SET_BIT(ah, AR_WOW_PATTERN, + AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF)); /* - * Program default values for pattern backoff, aifs/slot/KAL count, - * beacon miss timeout, KAL timeout, etc. + * AIFS time, Slot time, Keep Alive count. + */ + REG_SET_BIT(ah, AR_WOW_COUNT, AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | + AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | + AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT)); + /* + * Beacon timeout. */ - set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF); - REG_SET_BIT(ah, AR_WOW_PATTERN, set); - - set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | - AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | - AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT); - REG_SET_BIT(ah, AR_WOW_COUNT, set); - if (pattern_enable & AH_WOW_BEACON_MISS) - set = AR_WOW_BEACON_TIMO; - /* We are not using beacon miss, program a large value */ + REG_WRITE(ah, AR_WOW_BCN_TIMO, AR_WOW_BEACON_TIMO); else - set = AR_WOW_BEACON_TIMO_MAX; - - REG_WRITE(ah, AR_WOW_BCN_TIMO, set); + REG_WRITE(ah, AR_WOW_BCN_TIMO, AR_WOW_BEACON_TIMO_MAX); /* - * Keep alive timo in ms except AR9280 + * Keep alive timeout in ms. */ if (!pattern_enable) - set = AR_WOW_KEEP_ALIVE_NEVER; + REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, AR_WOW_KEEP_ALIVE_NEVER); else - set = KAL_TIMEOUT * 32; - - REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set); + REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, KAL_TIMEOUT * 32); /* - * Keep alive delay in us. based on 'power on clock', - * therefore in usec + * Keep alive delay in us. */ - set = KAL_DELAY * 1000; - REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set); + REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, KAL_DELAY * 1000); /* - * Create keep alive pattern to respond to beacons + * Create keep alive pattern to respond to beacons. */ ath9k_wow_create_keep_alive_pattern(ah); /* - * Configure MAC WoW Registers + * Configure keep alive register. */ - set = 0; + keep_alive = REG_READ(ah, AR_WOW_KEEP_ALIVE); + /* Send keep alive timeouts anyway */ - clr = AR_WOW_KEEP_ALIVE_AUTO_DIS; + keep_alive &= ~AR_WOW_KEEP_ALIVE_AUTO_DIS; - if (pattern_enable & AH_WOW_LINK_CHANGE) + if (pattern_enable & AH_WOW_LINK_CHANGE) { + keep_alive &= ~AR_WOW_KEEP_ALIVE_FAIL_DIS; wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL; - else - set = AR_WOW_KEEP_ALIVE_FAIL_DIS; + } else { + keep_alive |= AR_WOW_KEEP_ALIVE_FAIL_DIS; + } - set = AR_WOW_KEEP_ALIVE_FAIL_DIS; - REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr); + REG_WRITE(ah, AR_WOW_KEEP_ALIVE, keep_alive); /* - * we are relying on a bmiss failure. ensure we have - * enough threshold to prevent false positives + * We are relying on a bmiss failure, ensure we have + * enough threshold to prevent false positives. */ REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, AR_WOW_BMISSTHRESHOLD); - set = 0; - clr = 0; - if (pattern_enable & AH_WOW_BEACON_MISS) { - set = AR_WOW_BEACON_FAIL_EN; wow_event_mask |= AR_WOW_BEACON_FAIL; + REG_SET_BIT(ah, AR_WOW_BCN_EN, AR_WOW_BEACON_FAIL_EN); } else { - clr = AR_WOW_BEACON_FAIL_EN; + REG_CLR_BIT(ah, AR_WOW_BCN_EN, AR_WOW_BEACON_FAIL_EN); } - REG_RMW(ah, AR_WOW_BCN_EN, set, clr); - - set = 0; - clr = 0; /* - * Enable the magic packet registers + * Enable the magic packet registers. */ + magic_pattern = REG_READ(ah, AR_WOW_PATTERN); + magic_pattern |= AR_WOW_MAC_INTR_EN; + if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) { - set = AR_WOW_MAGIC_EN; + magic_pattern |= AR_WOW_MAGIC_EN; wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND; } else { - clr = AR_WOW_MAGIC_EN; + magic_pattern &= ~AR_WOW_MAGIC_EN; } - set |= AR_WOW_MAC_INTR_EN; - REG_RMW(ah, AR_WOW_PATTERN, set, clr); + REG_WRITE(ah, AR_WOW_PATTERN, magic_pattern); + + /* + * Enable pattern matching for packets which are less + * than 256 bytes. + */ REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B, AR_WOW_PATTERN_SUPPORTED); /* - * Set the power states appropriately and enable PME + * Set the power states appropriately and enable PME. */ - clr = 0; - set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN | - AR_PMCTRL_PWR_PM_CTRL_ENA; + host_pm_ctrl = REG_READ(ah, AR_PCIE_PM_CTRL); + host_pm_ctrl |= AR_PMCTRL_PWR_STATE_D1D3 | + AR_PMCTRL_HOST_PME_EN | + AR_PMCTRL_PWR_PM_CTRL_ENA; + host_pm_ctrl &= ~AR_PCIE_PM_CTRL_ENA; - clr = AR_PCIE_PM_CTRL_ENA; - REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr); + if (AR_SREV_9462(ah)) { + /* + * This is needed to prevent the chip waking up + * the host within 3-4 seconds with certain + * platform/BIOS. + */ + host_pm_ctrl &= ~AR_PMCTRL_PWR_STATE_D1D3; + host_pm_ctrl |= AR_PMCTRL_PWR_STATE_D1D3_REAL; + } + + REG_WRITE(ah, AR_PCIE_PM_CTRL, host_pm_ctrl); /* - * this is needed to prevent the chip waking up - * the host within 3-4 seconds with certain - * platform/BIOS. The fix is to enable - * D1 & D3 to match original definition and - * also match the OTP value. Anyway this - * is more related to SW WOW. + * Enable sequence number generation when asleep. */ - clr = AR_PMCTRL_PWR_STATE_D1D3; - REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); - - set = AR_PMCTRL_PWR_STATE_D1D3_REAL; - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); - REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); - /* to bring down WOW power low margin */ - set = BIT(13); - REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set); + /* To bring down WOW power low margin */ + REG_SET_BIT(ah, AR_PCIE_PHY_REG3, BIT(13)); + + ath9k_hw_wow_set_arwr_reg(ah); + /* HW WoW */ - clr = BIT(5); - REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr); + REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, BIT(5)); ath9k_hw_set_powermode_wow_sleep(ah); - ah->wow_event_mask = wow_event_mask; + ah->wow.wow_event_mask = wow_event_mask; } EXPORT_SYMBOL(ath9k_hw_wow_enable); diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h index 159cc6fd2362..6fc0d07e5ec6 100644 --- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h @@ -358,7 +358,7 @@ static const u32 qca953x_1p0_baseband_postamble[][5] = { {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822}, + {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10820, 0xcfa10820}, {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -378,7 +378,7 @@ static const u32 qca953x_1p0_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18}, {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, diff --git a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h index fd6a84ccd49e..148562addd38 100644 --- a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h @@ -63,7 +63,7 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = { {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822}, + {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10820, 0xcfa10820}, {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -83,7 +83,7 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18}, {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, diff --git a/drivers/net/wireless/ath/ath9k/ar956x_initvals.h b/drivers/net/wireless/ath/ath9k/ar956x_initvals.h new file mode 100644 index 000000000000..c3a47eaaf0c0 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar956x_initvals.h @@ -0,0 +1,1046 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INITVALS_956X_H +#define INITVALS_956X_H + +#define qca956x_1p0_mac_core ar955x_1p0_mac_core + +#define qca956x_1p0_mac_postamble ar9331_1p1_mac_postamble + +#define qca956x_1p0_soc_preamble ar955x_1p0_soc_preamble + +#define qca956x_1p0_soc_postamble ar9300_2p2_soc_postamble + +#define qca956x_1p0_common_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define qca956x_1p0_baseband_postamble_dfs_channel ar9300_2p2_baseband_postamble_dfs_channel + +#define qca956x_1p0_common_wo_xlna_rx_gain_bounds ar955x_1p0_common_wo_xlna_rx_gain_bounds + +#define qca956x_1p0_common_rx_gain_bounds ar955x_1p0_common_rx_gain_bounds + +#define qca956x_1p0_modes_fast_clock ar9462_2p0_modes_fast_clock + +static const u32 qca956x_1p0_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a9f6b}, + {0x0000980c, 0x04900000}, + {0x00009814, 0x0280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x6400a190}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14000600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x32840cbf}, + {0x000098bc, 0x00000002}, + {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, 0x990bb514}, + {0x00009e28, 0x0c6f0000}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009fc0, 0x813e4789}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x02993b93}, + {0x0000a20c, 0x00000000}, + {0x0000a218, 0x00000000}, + {0x0000a21c, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a248, 0x00000140}, + {0x0000a2a0, 0x00000007}, + {0x0000a2c0, 0x00000007}, + {0x0000a2c8, 0x00000000}, + {0x0000a2d4, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a360, 0x00000000}, + {0x0000a36c, 0x00000000}, + {0x0000a384, 0x00000001}, + {0x0000a388, 0x00000444}, + {0x0000a38c, 0x00000000}, + {0x0000a390, 0x210d0401}, + {0x0000a394, 0xab9a7144}, + {0x0000a398, 0x00000201}, + {0x0000a39c, 0x42424848}, + {0x0000a3a0, 0x3c466478}, + {0x0000a3a4, 0x3a363600}, + {0x0000a3a8, 0x0000003a}, + {0x0000a3ac, 0x00000000}, + {0x0000a3b0, 0x009011fe}, + {0x0000a3b4, 0x00000034}, + {0x0000a3b8, 0x00b3ec0a}, + {0x0000a3bc, 0x00000036}, + {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, 0x00000000}, + {0x0000a3f8, 0x0c9bd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce739ce}, + {0x0000a418, 0x2d0019ce}, + {0x0000a41c, 0x1ce739ce}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce739ce}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00100000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x05000080}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a454, 0x05000000}, + {0x0000a458, 0x00000000}, + {0x0000a644, 0xbfad9fee}, + {0x0000a648, 0x0048660d}, + {0x0000a64c, 0x00003c37}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x21200504}, + {0x0000a678, 0x61602322}, + {0x0000a67c, 0x65646362}, + {0x0000a680, 0x6b6a6968}, + {0x0000a684, 0xe2706d6c}, + {0x0000a688, 0x000000e3}, + {0x0000a690, 0x00000838}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000000}, + {0x0000a8d0, 0x004b6a8e}, + {0x0000a8d4, 0x00000820}, + {0x0000a8dc, 0x00000000}, + {0x0000a8f0, 0x00000000}, + {0x0000a8f4, 0x00000000}, + {0x0000b2d0, 0x00000080}, + {0x0000b2d4, 0x00000000}, + {0x0000b2ec, 0x00000000}, + {0x0000b2f0, 0x00000000}, + {0x0000b2f4, 0x00000000}, + {0x0000b2f8, 0x00000000}, + {0x0000b408, 0x0e79e5c0}, + {0x0000b40c, 0x00820820}, + {0x0000b420, 0x00000000}, + {0x0000b8d0, 0x004b6a8e}, + {0x0000b8d4, 0x00000820}, + {0x0000b8dc, 0x00000000}, + {0x0000b8f0, 0x00000000}, + {0x0000b8f4, 0x00000000}, + {0x0000c2d0, 0x00000080}, + {0x0000c2d4, 0x00000000}, + {0x0000c2ec, 0x00000000}, + {0x0000c2f0, 0x00000000}, + {0x0000c2f4, 0x00000000}, + {0x0000c2f8, 0x00000000}, + {0x0000c408, 0x0e79e5c0}, + {0x0000c40c, 0x00820820}, + {0x0000c420, 0x00000000}, +}; + +static const u32 qca956x_1p0_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac621f1, 0x5ac621f1}, + {0x00009828, 0x06903081, 0x06903081, 0x07d43881, 0x07d43881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, + {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, + {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000de, 0x6c4000de}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x337d605e, 0x337d5d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003a6, 0x000003a6}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcf946222, 0xcf946222}, + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x045c0cc4, 0x045c0cc0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f}, + {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, + {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, + {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e}, + {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, + {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, + {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, + {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, + {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, + {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001a6, 0x000001a6}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, + {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000be04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, + {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000be20, 0x000001b5, 0x000001b5, 0x000001a6, 0x000001a6}, + {0x0000c284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, +}; + +static const u32 qca956x_1p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db6db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016040, 0x3f80fff8}, + {0x0001604c, 0x000f0278}, + {0x00016050, 0x8036db6c}, + {0x00016054, 0x6db60000}, + {0x00016080, 0x00080000}, + {0x00016084, 0x0e48048c}, + {0x00016088, 0x14214514}, + {0x0001608c, 0x119f080a}, + {0x00016090, 0x24926490}, + {0x00016094, 0x00000000}, + {0x000160a0, 0xc2108ffe}, + {0x000160a4, 0x812fc370}, + {0x000160a8, 0x423c8000}, + {0x000160b4, 0x92480000}, + {0x000160c0, 0x006db6d8}, + {0x000160c4, 0x24b6db6c}, + {0x000160c8, 0x6db6db6c}, + {0x000160cc, 0x6db6fb7c}, + {0x000160d0, 0x6db6da44}, + {0x00016100, 0x07ff8001}, + {0x00016108, 0x00080010}, + {0x00016144, 0x01884080}, + {0x00016148, 0x00008058}, + {0x00016288, 0x001c6000}, + {0x0001628c, 0x50000000}, + {0x000162c0, 0x4b962100}, + {0x000162c4, 0x00000480}, + {0x000162c8, 0x04000144}, + {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, 0x3f80fff8}, + {0x0001644c, 0x000f0278}, + {0x00016450, 0x8036db6c}, + {0x00016454, 0x6db60000}, + {0x00016500, 0x07ff8001}, + {0x00016508, 0x00080010}, + {0x00016544, 0x01884080}, + {0x00016548, 0x00008058}, + {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}, + {0x00016800, 0x36db6db6}, + {0x00016804, 0x6db6db40}, + {0x00016808, 0x73f00000}, + {0x0001680c, 0x00000000}, + {0x00016840, 0x3f80fff8}, + {0x0001684c, 0x000f0278}, + {0x00016850, 0x8036db6c}, + {0x00016854, 0x6db60000}, + {0x00016900, 0x07ff8001}, + {0x00016908, 0x00080010}, + {0x00016944, 0x01884080}, + {0x00016948, 0x00008058}, + {0x00016b80, 0x00000000}, + {0x00016b84, 0x00000000}, + {0x00016b88, 0x00800700}, + {0x00016b8c, 0x00800700}, + {0x00016b90, 0x00800700}, + {0x00016b94, 0x00000000}, + {0x00016b98, 0x00000000}, + {0x00016b9c, 0x00000000}, + {0x00016ba0, 0x00000001}, + {0x00016ba4, 0x00000001}, + {0x00016ba8, 0x00000000}, + {0x00016bac, 0x00000000}, + {0x00016bb0, 0x00000000}, + {0x00016bb4, 0x00000000}, + {0x00016bb8, 0x00000000}, + {0x00016bbc, 0x00000000}, + {0x00016bc0, 0x000000a0}, + {0x00016bc4, 0x000c0000}, + {0x00016bc8, 0x14021402}, + {0x00016bcc, 0x00001402}, + {0x00016bd0, 0x00000000}, + {0x00016bd4, 0x00000000}, +}; + +static const u32 qca956x_1p0_radio_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xc4128f5c, 0xc4128f5c}, + {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0fd08f25, 0x0fd08f25}, + {0x000160ac, 0xa4647c00, 0xa4647c00, 0x24646800, 0x24646800}, + {0x000160b0, 0x01885f52, 0x01885f52, 0x00fe7f46, 0x00fe7f46}, + {0x00016104, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001}, + {0x0001610c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, + {0x00016140, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, + {0x00016504, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001}, + {0x0001650c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, + {0x00016540, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, + {0x00016904, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001}, + {0x0001690c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, + {0x00016940, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, +}; + +static const u32 qca956x_1p0_baseband_core_txfir_coeff_japan_2484[][2] = { + /* Addr allmodes */ + {0x0000a38c, 0x00000000}, + {0x0000a390, 0x6f7f0301}, + {0x0000a394, 0xca9228ee}, +}; + +static const u32 qca956x_1p0_modes_no_xpa_tx_gain_table[][3] = { + /* Addr 5G 2G */ + {0x0000a2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000a2e0, 0xff323118, 0xff323118}, + {0x0000a2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000a2e8, 0xffc00000, 0xffc00000}, + {0x0000a39c, 0x42424242, 0x42424242}, + {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00}, + {0x0000a3b0, 0x00a01404, 0x00a01404}, + {0x0000a3b4, 0x00000034, 0x00000034}, + {0x0000a3b8, 0x00800408, 0x00800408}, + {0x0000a3bc, 0x00000036, 0x00000036}, + {0x0000a410, 0x000050dc, 0x000050dc}, + {0x0000a500, 0x09000040, 0x09000040}, + {0x0000a504, 0x0b000041, 0x0b000041}, + {0x0000a508, 0x0d000042, 0x0d000042}, + {0x0000a50c, 0x11000044, 0x11000044}, + {0x0000a510, 0x15000046, 0x15000046}, + {0x0000a514, 0x1d000440, 0x1d000440}, + {0x0000a518, 0x1f000441, 0x1f000441}, + {0x0000a51c, 0x23000443, 0x23000443}, + {0x0000a520, 0x25000444, 0x25000444}, + {0x0000a524, 0x280004e0, 0x280004e0}, + {0x0000a528, 0x2c0004e2, 0x2c0004e2}, + {0x0000a52c, 0x2e0004e3, 0x2e0004e3}, + {0x0000a530, 0x300004e4, 0x300004e4}, + {0x0000a534, 0x340004e6, 0x340004e6}, + {0x0000a538, 0x37000ce0, 0x37000ce0}, + {0x0000a53c, 0x3b000ce2, 0x3b000ce2}, + {0x0000a540, 0x3d000ce3, 0x3d000ce3}, + {0x0000a544, 0x3f000ce4, 0x3f000ce4}, + {0x0000a548, 0x45001ee0, 0x45001ee0}, + {0x0000a54c, 0x49001ee2, 0x49001ee2}, + {0x0000a550, 0x4d001ee4, 0x4d001ee4}, + {0x0000a554, 0x51001ee6, 0x51001ee6}, + {0x0000a558, 0x55001eea, 0x55001eea}, + {0x0000a55c, 0x59001eec, 0x59001eec}, + {0x0000a560, 0x5d001ef0, 0x5d001ef0}, + {0x0000a564, 0x5f001ef1, 0x5f001ef1}, + {0x0000a568, 0x60001ef2, 0x60001ef2}, + {0x0000a56c, 0x61001ef3, 0x61001ef3}, + {0x0000a570, 0x62001ef4, 0x62001ef4}, + {0x0000a574, 0x63001ef5, 0x63001ef5}, + {0x0000a578, 0x64001ffc, 0x64001ffc}, + {0x0000a57c, 0x64001ffc, 0x64001ffc}, + {0x0000a600, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000}, + {0x0000a614, 0x00804201, 0x00804201}, + {0x0000a618, 0x00804201, 0x00804201}, + {0x0000a61c, 0x00804201, 0x00804201}, + {0x0000a620, 0x00804201, 0x00804201}, + {0x0000a624, 0x00804201, 0x00804201}, + {0x0000a628, 0x00804201, 0x00804201}, + {0x0000a62c, 0x02808a02, 0x02808a02}, + {0x0000a630, 0x0340cd03, 0x0340cd03}, + {0x0000a634, 0x0340cd03, 0x0340cd03}, + {0x0000a638, 0x0340cd03, 0x0340cd03}, + {0x0000a63c, 0x05011404, 0x05011404}, + {0x0000b2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000b2e0, 0xff323118, 0xff323118}, + {0x0000b2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000b2e8, 0xffc00000, 0xffc00000}, + {0x0000c2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000c2e0, 0xff323118, 0xff323118}, + {0x0000c2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000c2e8, 0xffc00000, 0xffc00000}, + {0x00016044, 0x049242db, 0x049242db}, + {0x00016048, 0x64925a70, 0x64925a70}, + {0x00016148, 0x00008050, 0x00008050}, + {0x00016280, 0x41110005, 0x41110005}, + {0x00016284, 0x453a6000, 0x453a6000}, + {0x00016444, 0x049242db, 0x049242db}, + {0x00016448, 0x6c925a70, 0x6c925a70}, + {0x00016548, 0x00008050, 0x00008050}, + {0x00016844, 0x049242db, 0x049242db}, + {0x00016848, 0x6c925a70, 0x6c925a70}, + {0x00016948, 0x00008050, 0x00008050}, +}; + +static const u32 qca956x_1p0_modes_xpa_tx_gain_table[][3] = { + /* Addr 5G 2G */ + {0x0000a2dc, 0xcc69ac94, 0xcc69ac94}, + {0x0000a2e0, 0xf0b23118, 0xf0b23118}, + {0x0000a2e4, 0xffffc000, 0xffffc000}, + {0x0000a2e8, 0xc0000000, 0xc0000000}, + {0x0000a410, 0x000050d2, 0x000050d2}, + {0x0000a500, 0x0a000040, 0x0a000040}, + {0x0000a504, 0x0c000041, 0x0c000041}, + {0x0000a508, 0x0e000042, 0x0e000042}, + {0x0000a50c, 0x12000044, 0x12000044}, + {0x0000a510, 0x16000046, 0x16000046}, + {0x0000a514, 0x1d000440, 0x1d000440}, + {0x0000a518, 0x1f000441, 0x1f000441}, + {0x0000a51c, 0x23000443, 0x23000443}, + {0x0000a520, 0x25000444, 0x25000444}, + {0x0000a524, 0x29000a40, 0x29000a40}, + {0x0000a528, 0x2d000a42, 0x2d000a42}, + {0x0000a52c, 0x2f000a43, 0x2f000a43}, + {0x0000a530, 0x31000a44, 0x31000a44}, + {0x0000a534, 0x35000a46, 0x35000a46}, + {0x0000a538, 0x38000ce0, 0x38000ce0}, + {0x0000a53c, 0x3c000ce2, 0x3c000ce2}, + {0x0000a540, 0x3e000ce3, 0x3e000ce3}, + {0x0000a544, 0x40000ce4, 0x40000ce4}, + {0x0000a548, 0x46001ee0, 0x46001ee0}, + {0x0000a54c, 0x4a001ee2, 0x4a001ee2}, + {0x0000a550, 0x4e001ee4, 0x4e001ee4}, + {0x0000a554, 0x52001ee6, 0x52001ee6}, + {0x0000a558, 0x56001eea, 0x56001eea}, + {0x0000a55c, 0x5a001eec, 0x5a001eec}, + {0x0000a560, 0x5e001ef0, 0x5e001ef0}, + {0x0000a564, 0x60001ef1, 0x60001ef1}, + {0x0000a568, 0x61001ef2, 0x61001ef2}, + {0x0000a56c, 0x62001ef3, 0x62001ef3}, + {0x0000a570, 0x63001ef4, 0x63001ef4}, + {0x0000a574, 0x64001ef5, 0x64001ef5}, + {0x0000a578, 0x65001ffc, 0x65001ffc}, + {0x0000a57c, 0x65001ffc, 0x65001ffc}, + {0x0000a600, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000}, + {0x0000a614, 0x00000000, 0x00000000}, + {0x0000a618, 0x00000000, 0x00000000}, + {0x0000a61c, 0x00804201, 0x00804201}, + {0x0000a620, 0x00804201, 0x00804201}, + {0x0000a624, 0x00804201, 0x00804201}, + {0x0000a628, 0x00804201, 0x00804201}, + {0x0000a62c, 0x02808a02, 0x02808a02}, + {0x0000a630, 0x0340cd03, 0x0340cd03}, + {0x0000a634, 0x0340cd03, 0x0340cd03}, + {0x0000a638, 0x0340cd03, 0x0340cd03}, + {0x0000a63c, 0x05011404, 0x05011404}, + {0x0000b2dc, 0xcc69ac94, 0xcc69ac94}, + {0x0000b2e0, 0xf0b23118, 0xf0b23118}, + {0x0000b2e4, 0xffffc000, 0xffffc000}, + {0x0000b2e8, 0xc0000000, 0xc0000000}, + {0x0000c2dc, 0xcc69ac94, 0xcc69ac94}, + {0x0000c2e0, 0xf0b23118, 0xf0b23118}, + {0x0000c2e4, 0xffffc000, 0xffffc000}, + {0x0000c2e8, 0xc0000000, 0xc0000000}, + {0x00016044, 0x012492db, 0x012492db}, + {0x00016048, 0x6c927a70, 0x6c927a70}, + {0x00016050, 0x8036d36c, 0x8036d36c}, + {0x00016280, 0x41110005, 0x41110005}, + {0x00016284, 0x453a7e00, 0x453a7e00}, + {0x00016444, 0x012492db, 0x012492db}, + {0x00016448, 0x6c927a70, 0x6c927a70}, + {0x00016450, 0x8036d36c, 0x8036d36c}, + {0x00016844, 0x012492db, 0x012492db}, + {0x00016848, 0x6c927a70, 0x6c927a70}, + {0x00016850, 0x8036d36c, 0x8036d36c}, +}; + +static const u32 qca956x_1p0_modes_no_xpa_low_ob_db_tx_gain_table[][3] = { + /* Addr 5G 2G */ + {0x0000a2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000a2e0, 0xff323118, 0xff323118}, + {0x0000a2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000a2e8, 0xffc00000, 0xffc00000}, + {0x0000a39c, 0x42424242, 0x42424242}, + {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00}, + {0x0000a3b0, 0x00a01404, 0x00a01404}, + {0x0000a3b4, 0x00000034, 0x00000034}, + {0x0000a3b8, 0x00800408, 0x00800408}, + {0x0000a3bc, 0x00000036, 0x00000036}, + {0x0000a410, 0x000050dc, 0x000050dc}, + {0x0000a414, 0x16b739ce, 0x16b739ce}, + {0x0000a418, 0x2d00198b, 0x2d00198b}, + {0x0000a41c, 0x16b5adce, 0x16b5adce}, + {0x0000a420, 0x0000014a, 0x0000014a}, + {0x0000a424, 0x14a525cc, 0x14a525cc}, + {0x0000a428, 0x0000012a, 0x0000012a}, + {0x0000a42c, 0x14a5294a, 0x14a5294a}, + {0x0000a430, 0x1294a929, 0x1294a929}, + {0x0000a500, 0x09000040, 0x09000040}, + {0x0000a504, 0x0b000041, 0x0b000041}, + {0x0000a508, 0x0d000042, 0x0d000042}, + {0x0000a50c, 0x11000044, 0x11000044}, + {0x0000a510, 0x15000046, 0x15000046}, + {0x0000a514, 0x1d000440, 0x1d000440}, + {0x0000a518, 0x1f000441, 0x1f000441}, + {0x0000a51c, 0x23000443, 0x23000443}, + {0x0000a520, 0x25000444, 0x25000444}, + {0x0000a524, 0x280004e0, 0x280004e0}, + {0x0000a528, 0x2c0004e2, 0x2c0004e2}, + {0x0000a52c, 0x2e0004e3, 0x2e0004e3}, + {0x0000a530, 0x300004e4, 0x300004e4}, + {0x0000a534, 0x340004e6, 0x340004e6}, + {0x0000a538, 0x37000ce0, 0x37000ce0}, + {0x0000a53c, 0x3b000ce2, 0x3b000ce2}, + {0x0000a540, 0x3d000ce3, 0x3d000ce3}, + {0x0000a544, 0x3f000ce4, 0x3f000ce4}, + {0x0000a548, 0x45001ee0, 0x45001ee0}, + {0x0000a54c, 0x49001ee2, 0x49001ee2}, + {0x0000a550, 0x4d001ee4, 0x4d001ee4}, + {0x0000a554, 0x51001ee6, 0x51001ee6}, + {0x0000a558, 0x55001eea, 0x55001eea}, + {0x0000a55c, 0x59001eec, 0x59001eec}, + {0x0000a560, 0x5d001ef0, 0x5d001ef0}, + {0x0000a564, 0x5f001ef1, 0x5f001ef1}, + {0x0000a568, 0x60001ef2, 0x60001ef2}, + {0x0000a56c, 0x61001ef3, 0x61001ef3}, + {0x0000a570, 0x62001ef4, 0x62001ef4}, + {0x0000a574, 0x63001ef5, 0x63001ef5}, + {0x0000a578, 0x64001ffc, 0x64001ffc}, + {0x0000a57c, 0x64001ffc, 0x64001ffc}, + {0x0000a600, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000}, + {0x0000a614, 0x00804201, 0x00804201}, + {0x0000a618, 0x00804201, 0x00804201}, + {0x0000a61c, 0x00804201, 0x00804201}, + {0x0000a620, 0x00804201, 0x00804201}, + {0x0000a624, 0x00804201, 0x00804201}, + {0x0000a628, 0x00804201, 0x00804201}, + {0x0000a62c, 0x02808a02, 0x02808a02}, + {0x0000a630, 0x0340cd03, 0x0340cd03}, + {0x0000a634, 0x0340cd03, 0x0340cd03}, + {0x0000a638, 0x0340cd03, 0x0340cd03}, + {0x0000a63c, 0x05011404, 0x05011404}, + {0x0000b2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000b2e0, 0xff323118, 0xff323118}, + {0x0000b2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000b2e8, 0xffc00000, 0xffc00000}, + {0x0000c2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000c2e0, 0xff323118, 0xff323118}, + {0x0000c2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000c2e8, 0xffc00000, 0xffc00000}, + {0x00016044, 0x046e42db, 0x046e42db}, + {0x00016048, 0x64925a70, 0x64925a70}, + {0x00016148, 0x00008050, 0x00008050}, + {0x00016280, 0x41110005, 0x41110005}, + {0x00016284, 0x453a6000, 0x453a6000}, + {0x00016444, 0x046e42db, 0x046e42db}, + {0x00016448, 0x6c925a70, 0x6c925a70}, + {0x00016548, 0x00008050, 0x00008050}, + {0x00016844, 0x046e42db, 0x046e42db}, + {0x00016848, 0x6c925a70, 0x6c925a70}, + {0x00016948, 0x00008050, 0x00008050}, +}; + +static const u32 qca956x_1p0_modes_no_xpa_green_tx_gain_table[][3] = { + /* Addr 5G 2G */ + {0x000098bc, 0x00000001, 0x00000001}, + {0x0000a2dc, 0xd3555284, 0xd3555284}, + {0x0000a2e0, 0x1c666318, 0x1c666318}, + {0x0000a2e4, 0xe07bbc00, 0xe07bbc00}, + {0x0000a2e8, 0xff800000, 0xff800000}, + {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00}, + {0x0000a410, 0x000050dc, 0x000050dc}, + {0x0000a500, 0x02000040, 0x02000040}, + {0x0000a504, 0x04000041, 0x04000041}, + {0x0000a508, 0x06000042, 0x06000042}, + {0x0000a50c, 0x0a000044, 0x0a000044}, + {0x0000a510, 0x0c000045, 0x0c000045}, + {0x0000a514, 0x13000440, 0x13000440}, + {0x0000a518, 0x15000441, 0x15000441}, + {0x0000a51c, 0x19000443, 0x19000443}, + {0x0000a520, 0x1b000444, 0x1b000444}, + {0x0000a524, 0x1e0004e0, 0x1e0004e0}, + {0x0000a528, 0x220004e2, 0x220004e2}, + {0x0000a52c, 0x240004e3, 0x240004e3}, + {0x0000a530, 0x260004e4, 0x260004e4}, + {0x0000a534, 0x2a0004e6, 0x2a0004e6}, + {0x0000a538, 0x32000ce0, 0x32000ce0}, + {0x0000a53c, 0x36000ce2, 0x36000ce2}, + {0x0000a540, 0x3a000ce4, 0x3a000ce4}, + {0x0000a544, 0x3e000ce6, 0x3e000ce6}, + {0x0000a548, 0x45001ee0, 0x45001ee0}, + {0x0000a54c, 0x49001ee2, 0x49001ee2}, + {0x0000a550, 0x4d001ee4, 0x4d001ee4}, + {0x0000a554, 0x51001ee6, 0x51001ee6}, + {0x0000a558, 0x55001eea, 0x55001eea}, + {0x0000a55c, 0x59001eec, 0x59001eec}, + {0x0000a560, 0x5d001ef0, 0x5d001ef0}, + {0x0000a564, 0x5f001ef1, 0x5f001ef1}, + {0x0000a568, 0x60001ef2, 0x60001ef2}, + {0x0000a56c, 0x61001ef3, 0x61001ef3}, + {0x0000a570, 0x62001ef4, 0x62001ef4}, + {0x0000a574, 0x63001ff5, 0x63001ff5}, + {0x0000a578, 0x64001ffc, 0x64001ffc}, + {0x0000a57c, 0x64001ffc, 0x64001ffc}, + {0x0000a600, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000}, + {0x0000a614, 0x00804201, 0x00804201}, + {0x0000a618, 0x00804201, 0x00804201}, + {0x0000a61c, 0x00804201, 0x00804201}, + {0x0000a620, 0x00804201, 0x00804201}, + {0x0000a624, 0x00804201, 0x00804201}, + {0x0000a628, 0x00804201, 0x00804201}, + {0x0000a62c, 0x02808a02, 0x02808a02}, + {0x0000a630, 0x0340cd03, 0x0340cd03}, + {0x0000a634, 0x0340cd03, 0x0340cd03}, + {0x0000a638, 0x0340cd03, 0x0340cd03}, + {0x0000a63c, 0x05011404, 0x05011404}, + {0x0000b2dc, 0xd3555284, 0xd3555284}, + {0x0000b2e0, 0x1c666318, 0x1c666318}, + {0x0000b2e4, 0xe07bbc00, 0xe07bbc00}, + {0x0000b2e8, 0xff800000, 0xff800000}, + {0x0000c2dc, 0xd3555284, 0xd3555284}, + {0x0000c2e0, 0x1c666318, 0x1c666318}, + {0x0000c2e4, 0xe07bbc00, 0xe07bbc00}, + {0x0000c2e8, 0xff800000, 0xff800000}, + {0x00016044, 0x849242db, 0x849242db}, + {0x00016048, 0x64925a70, 0x64925a70}, + {0x00016280, 0x41110005, 0x41110005}, + {0x00016284, 0x453a6000, 0x453a6000}, + {0x00016444, 0x849242db, 0x849242db}, + {0x00016448, 0x6c925a70, 0x6c925a70}, + {0x00016844, 0x849242db, 0x849242db}, + {0x00016848, 0x6c925a70, 0x6c925a70}, + {0x0000a7f0, 0x800002cc, 0x800002cc}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000028, 0x00000028}, + {0x0000a7f4, 0x00000028, 0x00000028}, + {0x0000a7f4, 0x00000028, 0x00000028}, + {0x0000a7f4, 0x00000028, 0x00000028}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, +}; + +static const u32 qca956x_1p0_common_rx_gain_table[][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, 0x22222222}, + {0x0000a084, 0x1d1d1d1d}, + {0x0000a088, 0x1d1d1d1d}, + {0x0000a08c, 0x1d1d1d1d}, + {0x0000a090, 0x17171717}, + {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, 0x23232323}, + {0x0000b084, 0x21232323}, + {0x0000b088, 0x19191c1e}, + {0x0000b08c, 0x12141417}, + {0x0000b090, 0x07070e0e}, + {0x0000b094, 0x03030305}, + {0x0000b098, 0x00000003}, + {0x0000b09c, 0x00000000}, + {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 qca956x_1p0_xlna_only[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac621f1, 0x5ac621f1}, + {0x00009828, 0x06903081, 0x06903081, 0x07d43881, 0x07d43881}, + {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x03721720}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000de, 0x6c4000da}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec86d2e, 0x7ec8ad2e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x317a6062, 0x317a5ae2}, + {0x00009e18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003b2, 0x000003b2}, + {0x00009fc0, 0x813e4788, 0x813e4788, 0x813e4789, 0x813e4789}, + {0x0000ae18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001b2, 0x000001b2}, + {0x0000be18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000}, + {0x0000be20, 0x000001b5, 0x000001b5, 0x000001b2, 0x000001b2}, +}; + +#endif /* INITVALS_956X_H */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 1a9fe0983a6b..0f8e9464e4ab 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -34,7 +34,7 @@ struct ath_vif; extern struct ieee80211_ops ath9k_ops; extern int ath9k_modparam_nohwcrypt; -extern int led_blink; +extern int ath9k_led_blink; extern bool is_ath9k_unloaded; extern int ath9k_use_chanctx; @@ -830,14 +830,9 @@ static inline void ath_fill_led_pin(struct ath_softc *sc) /* Wake on Wireless LAN */ /************************/ -struct ath9k_wow_pattern { - u8 pattern_bytes[MAX_PATTERN_SIZE]; - u8 mask_bytes[MAX_PATTERN_SIZE]; - u32 pattern_len; -}; - #ifdef CONFIG_ATH9K_WOW void ath9k_init_wow(struct ieee80211_hw *hw); +void ath9k_deinit_wow(struct ieee80211_hw *hw); int ath9k_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); int ath9k_resume(struct ieee80211_hw *hw); @@ -846,6 +841,9 @@ void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled); static inline void ath9k_init_wow(struct ieee80211_hw *hw) { } +static inline void ath9k_deinit_wow(struct ieee80211_hw *hw) +{ +} static inline int ath9k_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { @@ -1039,9 +1037,8 @@ struct ath_softc { s16 tx99_power; #ifdef CONFIG_ATH9K_WOW - atomic_t wow_got_bmiss_intr; - atomic_t wow_sleep_proc_intr; /* in the middle of WoW sleep ? */ u32 wow_intr_before_sleep; + bool force_wow; #endif }; diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index ec93ddf0863a..5cee231cca1f 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -582,7 +582,7 @@ static struct rchan_callbacks rfs_spec_scan_cb = { void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv) { - if (config_enabled(CONFIG_ATH9K_DEBUGFS) && spec_priv->rfs_chan_spec_scan) { + if (config_enabled(CONFIG_ATH9K_DEBUGFS)) { relay_close(spec_priv->rfs_chan_spec_scan); spec_priv->rfs_chan_spec_scan = NULL; } diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 871e969409bf..50a2e0ac3b8b 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -403,7 +403,8 @@ static const struct file_operations fops_antenna_diversity = { static int read_file_dma(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; int i, qcuOffset = 0, dcuOffset = 0; @@ -470,20 +471,6 @@ static int read_file_dma(struct seq_file *file, void *data) return 0; } -static int open_file_dma(struct inode *inode, struct file *f) -{ - return single_open(f, read_file_dma, inode->i_private); -} - -static const struct file_operations fops_dma = { - .open = open_file_dma, - .read = seq_read, - .owner = THIS_MODULE, - .llseek = seq_lseek, - .release = single_release, -}; - - void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) { if (status) @@ -539,7 +526,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) static int read_file_interrupt(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; #define PR_IS(a, s) \ do { \ @@ -600,22 +588,10 @@ static int read_file_interrupt(struct seq_file *file, void *data) return 0; } -static int open_file_interrupt(struct inode *inode, struct file *f) -{ - return single_open(f, read_file_interrupt, inode->i_private); -} - -static const struct file_operations fops_interrupt = { - .read = seq_read, - .open = open_file_interrupt, - .owner = THIS_MODULE, - .llseek = seq_lseek, - .release = single_release, -}; - static int read_file_xmit(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; seq_printf(file, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO"); @@ -661,7 +637,8 @@ static void print_queue(struct ath_softc *sc, struct ath_txq *txq, static int read_file_queues(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; struct ath_txq *txq; int i; static const char *qname[4] = { @@ -682,7 +659,8 @@ static int read_file_queues(struct seq_file *file, void *data) static int read_file_misc(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath9k_vif_iter_data iter_data; struct ath_chanctx *ctx; @@ -773,7 +751,8 @@ static int read_file_misc(struct seq_file *file, void *data) static int read_file_reset(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; static const char * const reset_cause[__RESET_TYPE_MAX] = { [RESET_TYPE_BB_HANG] = "Baseband Hang", [RESET_TYPE_BB_WATCHDOG] = "Baseband Watchdog", @@ -837,58 +816,6 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, TX_STAT_INC(qnum, delim_underrun); } -static int open_file_xmit(struct inode *inode, struct file *f) -{ - return single_open(f, read_file_xmit, inode->i_private); -} - -static const struct file_operations fops_xmit = { - .read = seq_read, - .open = open_file_xmit, - .owner = THIS_MODULE, - .llseek = seq_lseek, - .release = single_release, -}; - -static int open_file_queues(struct inode *inode, struct file *f) -{ - return single_open(f, read_file_queues, inode->i_private); -} - -static const struct file_operations fops_queues = { - .read = seq_read, - .open = open_file_queues, - .owner = THIS_MODULE, - .llseek = seq_lseek, - .release = single_release, -}; - -static int open_file_misc(struct inode *inode, struct file *f) -{ - return single_open(f, read_file_misc, inode->i_private); -} - -static const struct file_operations fops_misc = { - .read = seq_read, - .open = open_file_misc, - .owner = THIS_MODULE, - .llseek = seq_lseek, - .release = single_release, -}; - -static int open_file_reset(struct inode *inode, struct file *f) -{ - return single_open(f, read_file_reset, inode->i_private); -} - -static const struct file_operations fops_reset = { - .read = seq_read, - .open = open_file_reset, - .owner = THIS_MODULE, - .llseek = seq_lseek, - .release = single_release, -}; - void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) { ath9k_cmn_debug_stat_rx(&sc->debug.stats.rxstats, rs); @@ -1018,7 +945,8 @@ static const struct file_operations fops_regdump = { static int read_file_dump_nfcal(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath9k_nfcal_hist *h = sc->cur_chan->caldata.nfCalHist; struct ath_common *common = ath9k_hw_common(ah); @@ -1115,6 +1043,133 @@ static const struct file_operations fops_ackto = { }; #endif +#ifdef CONFIG_ATH9K_WOW + +static ssize_t read_file_wow(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + unsigned int len = 0, size = 32; + ssize_t retval; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += scnprintf(buf + len, size - len, "WOW: %s\n", + sc->force_wow ? "ENABLED" : "DISABLED"); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static ssize_t write_file_wow(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + unsigned long val; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val != 1) + return -EINVAL; + + if (!sc->force_wow) { + sc->force_wow = true; + ath9k_init_wow(sc->hw); + } + + return count; +} + +static const struct file_operations fops_wow = { + .read = read_file_wow, + .write = write_file_wow, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +#endif + +static ssize_t read_file_tpc(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + unsigned int len = 0, size = 32; + ssize_t retval; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += scnprintf(buf + len, size - len, "%s\n", + ah->tpc_enabled ? "ENABLED" : "DISABLED"); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static ssize_t write_file_tpc(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + unsigned long val; + char buf[32]; + ssize_t len; + bool tpc_enabled; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val < 0 || val > 1) + return -EINVAL; + + tpc_enabled = !!val; + + if (tpc_enabled != ah->tpc_enabled) { + ah->tpc_enabled = tpc_enabled; + ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); + } + + return count; +} + +static const struct file_operations fops_tpc = { + .read = read_file_tpc, + .write = write_file_tpc, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + /* Ethtool support for get-stats */ #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" @@ -1260,14 +1315,14 @@ int ath9k_init_debug(struct ath_hw *ah) ath9k_tx99_init_debug(sc); ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy); - 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("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_xmit); - debugfs_create_file("queues", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_queues); + debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy, + read_file_dma); + debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy, + read_file_interrupt); + debugfs_create_devm_seqfile(sc->dev, "xmit", sc->debug.debugfs_phy, + read_file_xmit); + debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy, + read_file_queues); debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->tx.txq_max_pending[IEEE80211_AC_BK]); debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, @@ -1276,10 +1331,10 @@ int ath9k_init_debug(struct ath_hw *ah) &sc->tx.txq_max_pending[IEEE80211_AC_VI]); debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->tx.txq_max_pending[IEEE80211_AC_VO]); - debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_misc); - debugfs_create_file("reset", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_reset); + debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy, + read_file_misc); + debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy, + read_file_reset); ath9k_cmn_debug_recv(sc->debug.debugfs_phy, &sc->debug.stats.rxstats); ath9k_cmn_debug_phy_err(sc->debug.debugfs_phy, &sc->debug.stats.rxstats); @@ -1301,8 +1356,9 @@ int ath9k_init_debug(struct ath_hw *ah) &ah->config.cwm_ignore_extcca); debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_regdump); - debugfs_create_file("dump_nfcal", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_dump_nfcal); + debugfs_create_devm_seqfile(sc->dev, "dump_nfcal", + sc->debug.debugfs_phy, + read_file_dump_nfcal); ath9k_cmn_debug_base_eeprom(sc->debug.debugfs_phy, sc->sc_ah); ath9k_cmn_debug_modal_eeprom(sc->debug.debugfs_phy, sc->sc_ah); @@ -1320,10 +1376,17 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_btcoex); #endif +#ifdef CONFIG_ATH9K_WOW + debugfs_create_file("wow", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_wow); +#endif + #ifdef CONFIG_ATH9K_DYNACK debugfs_create_file("ack_to", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_ackto); #endif + debugfs_create_file("tpc", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_tpc); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 07b806c56c56..e5a78d4fd66e 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -748,6 +748,20 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } + /* TPC initializations */ + if (ah->tpc_enabled) { + int ht40_delta; + + ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0; + ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta); + /* Enable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, + MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE); + } else { + /* Disable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER); + } + REGWRITE_BUFFER_FLUSH(ah); } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 5ba1385c9838..6ca33dfde1fd 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -886,6 +886,21 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } + + /* TPC initializations */ + if (ah->tpc_enabled) { + int ht40_delta; + + ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0; + ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta); + /* Enable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, + MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE); + } else { + /* Disable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER); + } + REGWRITE_BUFFER_FLUSH(ah); } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 122b846b8ec0..098059039351 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -1332,6 +1332,20 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + /* TPC initializations */ + if (ah->tpc_enabled) { + int ht40_delta; + + ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0; + ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta); + /* Enable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, + MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE); + } else { + /* Disable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER); + } + REGWRITE_BUFFER_FLUSH(ah); } diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 2fef7a480fec..da344b27326c 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -49,7 +49,7 @@ void ath_init_leds(struct ath_softc *sc) if (AR_SREV_9100(sc->sc_ah)) return; - if (!led_blink) + if (!ath9k_led_blink) sc->led_cdev.default_trigger = ieee80211_get_radio_led_name(sc->hw); diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 9dde265d3f84..300d3671d0ef 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -44,6 +44,9 @@ extern struct ieee80211_ops ath9k_htc_ops; extern int htc_modparam_nohwcrypt; +#ifdef CONFIG_MAC80211_LEDS +extern int ath9k_htc_led_blink; +#endif enum htc_phymode { HTC_MODE_11NA = 0, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 50f74a2a4cf8..2aabcbdaba4e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -279,6 +279,10 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv) else priv->ah->led_pin = ATH_LED_PIN_DEF; + if (!ath9k_htc_led_blink) + priv->led_cdev.default_trigger = + ieee80211_get_radio_led_name(priv->hw); + ath9k_configure_leds(priv); snprintf(priv->led_name, sizeof(priv->led_name), diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index e8fa9448da24..fd229409f676 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -39,6 +39,10 @@ module_param_named(ps_enable, ath9k_ps_enable, int, 0444); MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); #ifdef CONFIG_MAC80211_LEDS +int ath9k_htc_led_blink = 1; +module_param_named(blink, ath9k_htc_led_blink, int, 0444); +MODULE_PARM_DESC(blink, "Enable LED blink on activity"); + static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { { .throughput = 0 * 1024, .blink_time = 334 }, { .throughput = 1 * 1024, .blink_time = 260 }, diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index a0ff5b637054..d2408da38c1c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -351,11 +351,7 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, return; ret: - /* HTC-generated packets are freed here. */ - if (htc_hdr && htc_hdr->endpoint_id != ENDPOINT0) - dev_kfree_skb_any(skb); - else - kfree_skb(skb); + kfree_skb(skb); } static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle, diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6d4b273469b1..60aa8d71e753 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -246,6 +246,8 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) case AR9300_DEVID_AR953X: ah->hw_version.macVersion = AR_SREV_VERSION_9531; return; + case AR9300_DEVID_QCA956X: + ah->hw_version.macVersion = AR_SREV_VERSION_9561; } val = REG_READ(ah, AR_SREV) & AR_SREV_ID; @@ -422,6 +424,8 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->power_mode = ATH9K_PM_UNDEFINED; ah->htc_reset_init = true; + ah->tpc_enabled = true; + ah->ani_function = ATH9K_ANI_ALL; if (!AR_SREV_9300_20_OR_LATER(ah)) ah->ani_function &= ~ATH9K_ANI_MRC_CCK; @@ -536,6 +540,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) case AR_SREV_VERSION_9550: case AR_SREV_VERSION_9565: case AR_SREV_VERSION_9531: + case AR_SREV_VERSION_9561: break; default: ath_err(common, @@ -636,6 +641,7 @@ int ath9k_hw_init(struct ath_hw *ah) case AR9485_DEVID_AR1111: case AR9300_DEVID_AR9565: case AR9300_DEVID_AR953X: + case AR9300_DEVID_QCA956X: break; default: if (common->bus_ops->ath_bus_type == ATH_USB) @@ -776,7 +782,8 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, /* program BB PLL phase_shift */ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x1); - } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) { u32 regval, pll2_divint, pll2_divfrac, refdiv; REG_WRITE(ah, AR_RTC_PLL_CONTROL, @@ -787,7 +794,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, udelay(100); if (ah->is_clk_25mhz) { - if (AR_SREV_9531(ah)) { + if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) { pll2_divint = 0x1c; pll2_divfrac = 0xa3d2; refdiv = 1; @@ -803,14 +810,15 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, refdiv = 5; } else { pll2_divint = 0x11; - pll2_divfrac = - AR_SREV_9531(ah) ? 0x26665 : 0x26666; + pll2_divfrac = (AR_SREV_9531(ah) || + AR_SREV_9561(ah)) ? + 0x26665 : 0x26666; refdiv = 1; } } regval = REG_READ(ah, AR_PHY_PLL_MODE); - if (AR_SREV_9531(ah)) + if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) regval |= (0x1 << 22); else regval |= (0x1 << 16); @@ -828,14 +836,16 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, (0x1 << 13) | (0x4 << 26) | (0x18 << 19); - else if (AR_SREV_9531(ah)) + else if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) { regval = (regval & 0x01c00fff) | (0x1 << 31) | (0x2 << 29) | (0xa << 25) | - (0x1 << 19) | - (0x6 << 12); - else + (0x1 << 19); + + if (AR_SREV_9531(ah)) + regval |= (0x6 << 12); + } else regval = (regval & 0x80071fff) | (0x3 << 30) | (0x1 << 13) | @@ -843,7 +853,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, (0x60 << 19); REG_WRITE(ah, AR_PHY_PLL_MODE, regval); - if (AR_SREV_9531(ah)) + if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) REG_WRITE(ah, AR_PHY_PLL_MODE, REG_READ(ah, AR_PHY_PLL_MODE) & 0xffbfffff); else @@ -882,7 +892,8 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, AR_IMR_RXORN | AR_IMR_BCNMISC; - if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; if (AR_SREV_9300_20_OR_LATER(ah)) { @@ -1671,7 +1682,8 @@ static void ath9k_hw_init_desc(struct ath_hw *ah) } #ifdef __BIG_ENDIAN else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) || - AR_SREV_9550(ah) || AR_SREV_9531(ah)) + AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(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); @@ -2459,7 +2471,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9300_20_OR_LATER(ah)) { pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_FASTCLOCK; - if (!AR_SREV_9330(ah) && !AR_SREV_9485(ah) && !AR_SREV_9565(ah)) + if (!AR_SREV_9330(ah) && !AR_SREV_9485(ah) && + !AR_SREV_9561(ah) && !AR_SREV_9565(ah)) pCap->hw_caps |= ATH9K_HW_CAP_LDPC; pCap->rx_hp_qdepth = ATH9K_HW_RX_HP_QDEPTH; @@ -2476,7 +2489,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9300_20_OR_LATER(ah)) pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED; - if (AR_SREV_9300_20_OR_LATER(ah)) + if (AR_SREV_9561(ah)) + ah->ent_mode = 0x3BDA000; + else if (AR_SREV_9300_20_OR_LATER(ah)) ah->ent_mode = REG_READ(ah, AR_ENT_OTP); if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah)) @@ -2529,13 +2544,17 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->hw_caps |= ATH9K_HW_CAP_RTT; } - if (AR_SREV_9462(ah)) - pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE; - if (AR_SREV_9300_20_OR_LATER(ah) && ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) pCap->hw_caps |= ATH9K_HW_CAP_PAPRD; +#ifdef CONFIG_ATH9K_WOW + if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565_11_OR_LATER(ah)) + ah->wow.max_patterns = MAX_NUM_PATTERN; + else + ah->wow.max_patterns = MAX_NUM_PATTERN_LEGACY; +#endif + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 1cbd33551513..e82e570de330 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -54,6 +54,7 @@ #define AR9485_DEVID_AR1111 0x0037 #define AR9300_DEVID_AR9565 0x0036 #define AR9300_DEVID_AR953X 0x003d +#define AR9300_DEVID_QCA956X 0x003f #define AR5416_AR9100_DEVID 0x000b @@ -198,12 +199,13 @@ #define KAL_NUM_DESC_WORDS 12 #define KAL_ANTENNA_MODE 1 #define KAL_TO_DS 1 -#define KAL_DELAY 4 /*delay of 4ms between 2 KAL frames */ +#define KAL_DELAY 4 /* delay of 4ms between 2 KAL frames */ #define KAL_TIMEOUT 900 #define MAX_PATTERN_SIZE 256 #define MAX_PATTERN_MASK_SIZE 32 -#define MAX_NUM_PATTERN 8 +#define MAX_NUM_PATTERN 16 +#define MAX_NUM_PATTERN_LEGACY 8 #define MAX_NUM_USER_PATTERN 6 /* deducting the disassociate and deauthenticate packets */ @@ -247,12 +249,10 @@ enum ath9k_hw_caps { #ifdef CONFIG_ATH9K_PCOEM ATH9K_HW_CAP_RTT = BIT(14), ATH9K_HW_CAP_MCI = BIT(15), - ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(16), ATH9K_HW_CAP_BT_ANT_DIV = BIT(17), #else ATH9K_HW_CAP_RTT = 0, ATH9K_HW_CAP_MCI = 0, - ATH9K_HW_WOW_DEVICE_CAPABLE = 0, ATH9K_HW_CAP_BT_ANT_DIV = 0, #endif ATH9K_HW_CAP_DFS = BIT(18), @@ -271,6 +271,12 @@ enum ath9k_hw_caps { * of those types. */ +struct ath9k_hw_wow { + u32 wow_event_mask; + u32 wow_event_mask2; + u8 max_patterns; +}; + struct ath9k_hw_capabilities { u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ u16 rts_aggr_limit; @@ -929,7 +935,7 @@ struct ath_hw { u32 ent_mode; #ifdef CONFIG_ATH9K_WOW - u32 wow_event_mask; + struct ath9k_hw_wow wow; #endif bool is_clk_25mhz; int (*get_mac_revision)(void); @@ -1086,6 +1092,8 @@ bool ar9003_is_paprd_enabled(struct ath_hw *ah); void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx); void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array, struct ath9k_channel *chan); +void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array, + struct ath9k_channel *chan, int ht40_delta); /* Hardware family op attach helpers */ int ar5008_hw_attach_phy_ops(struct ath_hw *ah); @@ -1145,23 +1153,19 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) #ifdef CONFIG_ATH9K_WOW -const char *ath9k_hw_wow_event_to_string(u32 wow_event); -void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, - u8 *user_mask, int pattern_count, - int pattern_len); +int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, + u8 *user_mask, int pattern_count, + int pattern_len); u32 ath9k_hw_wow_wakeup(struct ath_hw *ah); void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable); #else -static inline const char *ath9k_hw_wow_event_to_string(u32 wow_event) -{ - return NULL; -} -static inline void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, - u8 *user_pattern, - u8 *user_mask, - int pattern_count, - int pattern_len) +static inline int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, + u8 *user_pattern, + u8 *user_mask, + int pattern_count, + int pattern_len) { + return 0; } static inline u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index d1c39346b264..6c6e88495394 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -45,8 +45,8 @@ int ath9k_modparam_nohwcrypt; module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); -int led_blink; -module_param_named(blink, led_blink, int, 0444); +int ath9k_led_blink; +module_param_named(blink, ath9k_led_blink, int, 0444); MODULE_PARM_DESC(blink, "Enable LED blink on activity"); static int ath9k_btcoex_enable; @@ -996,6 +996,7 @@ void ath9k_deinit_device(struct ath_softc *sc) ath9k_ps_restore(sc); ath9k_deinit_debug(sc); + ath9k_deinit_wow(hw); ieee80211_unregister_hw(hw); ath_rx_cleanup(sc); ath9k_deinit_softc(sc); diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index b829263e3d0a..90631d768a60 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -516,14 +516,14 @@ int ath_update_survey_stats(struct ath_softc *sc) ath_hw_cycle_counters_update(common); if (cc->cycles > 0) { - survey->filled |= SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_RX | - SURVEY_INFO_CHANNEL_TIME_TX; - survey->channel_time += cc->cycles / div; - survey->channel_time_busy += cc->rx_busy / div; - survey->channel_time_rx += cc->rx_frame / div; - survey->channel_time_tx += cc->tx_frame / div; + survey->filled |= SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_RX | + SURVEY_INFO_TIME_TX; + survey->time += cc->cycles / div; + survey->time_busy += cc->rx_busy / div; + survey->time_rx += cc->rx_frame / div; + survey->time_tx += cc->tx_frame / div; } if (cc->cycles < div) diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 3e58bfa0c1fd..bba85d1a6cd1 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -820,7 +820,8 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) return; } - if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; async_mask = AR_INTR_MAC_IRQ; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9a72640237cb..9ede991b8d76 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -285,6 +285,7 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) __ath_cancel_work(sc); + disable_irq(sc->irq); tasklet_disable(&sc->intr_tq); tasklet_disable(&sc->bcon_tasklet); spin_lock_bh(&sc->sc_pcu_lock); @@ -331,6 +332,7 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) r = -EIO; out: + enable_irq(sc->irq); spin_unlock_bh(&sc->sc_pcu_lock); tasklet_enable(&sc->bcon_tasklet); tasklet_enable(&sc->intr_tq); @@ -512,9 +514,6 @@ irqreturn_t ath_isr(int irq, void *dev) if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags)) return IRQ_NONE; - if (!AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags)) - return IRQ_NONE; - /* shared irq, not for us */ if (!ath9k_hw_intrpend(ah)) return IRQ_NONE; @@ -529,7 +528,7 @@ irqreturn_t ath_isr(int irq, void *dev) ath9k_debug_sync_cause(sc, sync_cause); status &= ah->imask; /* discard unasked-for bits */ - if (AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags)) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) return IRQ_HANDLED; /* @@ -556,15 +555,6 @@ irqreturn_t ath_isr(int irq, void *dev) (status & ATH9K_INT_BB_WATCHDOG)) goto chip_reset; -#ifdef CONFIG_ATH9K_WOW - if (status & ATH9K_INT_BMISS) { - if (atomic_read(&sc->wow_sleep_proc_intr) == 0) { - atomic_inc(&sc->wow_got_bmiss_intr); - atomic_dec(&sc->wow_sleep_proc_intr); - } - } -#endif - if (status & ATH9K_INT_SWBA) tasklet_schedule(&sc->bcon_tasklet); diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index f009b5b57e5e..e6fef1be9977 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -424,6 +424,11 @@ static const struct pci_device_id ath_pci_id_table[] = { 0x11AD, /* LITEON */ 0x0842), .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x1842), + .driver_data = ATH9K_PCI_AR9565_1ANT }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, 0x11AD, /* LITEON */ @@ -444,11 +449,21 @@ static const struct pci_device_id ath_pci_id_table[] = { 0x1B9A, /* XAVI */ 0x28A1), .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x28A3), + .driver_data = ATH9K_PCI_AR9565_1ANT }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_AZWAVE, 0x218A), .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x2F8A), + .driver_data = ATH9K_PCI_AR9565_1ANT }, /* WB335 1-ANT / Antenna Diversity */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, @@ -506,6 +521,11 @@ static const struct pci_device_id ath_pci_id_table[] = { PCI_VENDOR_ID_AZWAVE, 0x213A), .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x213C), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_HP, @@ -553,6 +573,16 @@ static const struct pci_device_id ath_pci_id_table[] = { PCI_VENDOR_ID_SAMSUNG, 0x411E), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x4129), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x412A), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_ATHEROS, @@ -583,11 +613,26 @@ static const struct pci_device_id ath_pci_id_table[] = { 0x11AD, /* LITEON */ 0x0832), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x1832), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, 0x11AD, /* LITEON */ 0x0692), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0803), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0813), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_AZWAVE, @@ -603,6 +648,21 @@ static const struct pci_device_id ath_pci_id_table[] = { PCI_VENDOR_ID_AZWAVE, 0x2182), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x218B), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x218C), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x2F82), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, 0x144F, /* ASKEY */ @@ -613,11 +673,21 @@ static const struct pci_device_id ath_pci_id_table[] = { 0x1B9A, /* XAVI */ 0x2810), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x2813), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, 0x1B9A, /* XAVI */ 0x28A2), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x28A4), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, 0x185F, /* WNC */ @@ -633,11 +703,26 @@ static const struct pci_device_id ath_pci_id_table[] = { PCI_VENDOR_ID_FOXCONN, 0xE07F), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE08F), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_FOXCONN, 0xE081), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE091), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE099), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_LENOVO, @@ -913,9 +998,12 @@ static int ath_pci_suspend(struct device *device) struct pci_dev *pdev = to_pci_dev(device); struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); - if (sc->wow_enabled) + if (test_bit(ATH_OP_WOW_ENABLED, &common->op_flags)) { + dev_info(&pdev->dev, "WOW is enabled, bypassing PCI suspend\n"); return 0; + } /* The device has to be moved to FULLSLEEP forcibly. * Otherwise the chip never moved to full sleep, diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 7395afbc5124..6fb40ef86fd6 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -425,7 +425,8 @@ u32 ath_calcrxfilter(struct ath_softc *sc) rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; } - if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah)) + if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah) || + AR_SREV_9561(sc->sc_ah)) rfilt |= ATH9K_RX_FILTER_4ADDRESS; if (ath9k_is_chanctx_enabled() && diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index fb11a9172f38..9587ec655680 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -814,6 +814,7 @@ #define AR_SREV_REVISION_9531_10 0 #define AR_SREV_REVISION_9531_11 1 #define AR_SREV_REVISION_9531_20 2 +#define AR_SREV_VERSION_9561 0x600 #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -899,10 +900,13 @@ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485)) #define AR_SREV_9565(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565)) +#define AR_SREV_9003_PCOEM(_ah) \ + (AR_SREV_9462(_ah) || AR_SREV_9485(_ah) || AR_SREV_9565(_ah)) #else #define AR_SREV_9462(_ah) 0 #define AR_SREV_9485(_ah) 0 #define AR_SREV_9565(_ah) 0 +#define AR_SREV_9003_PCOEM(_ah) 0 #endif #define AR_SREV_9485_11_OR_LATER(_ah) \ @@ -974,6 +978,9 @@ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_20)) +#define AR_SREV_9561(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9561)) + /* NOTE: When adding chips newer than Peacock, add chip check here */ #define AR_SREV_9580_10_OR_LATER(_ah) \ (AR_SREV_9580(_ah)) @@ -1876,6 +1883,7 @@ enum { #define AR_FIRST_NDP_TIMER 7 #define AR_NDP2_PERIOD 0x81a0 #define AR_NDP2_TIMER_MODE 0x81c0 +#define AR_GEN_TIMERS2_MODE_ENABLE_MASK 0x000000FF #define AR_GEN_TIMERS(_i) (0x8200 + ((_i) << 2)) #define AR_NEXT_TBTT_TIMER AR_GEN_TIMERS(0) @@ -1971,6 +1979,7 @@ enum { #define AR_DIRECT_CONNECT 0x83a0 #define AR_DC_AP_STA_EN 0x00000001 +#define AR_DC_TSF2_ENABLE 0x00000001 #define AR_AES_MUTE_MASK0 0x805c #define AR_AES_MUTE_MASK0_FC 0x0000FFFF @@ -2003,126 +2012,6 @@ enum { #define AR_WOW_BEACON_TIMO_MAX 0xffffffff -/* - * MAC WoW Registers - */ - -#define AR_WOW_PATTERN 0x825C -#define AR_WOW_COUNT 0x8260 -#define AR_WOW_BCN_EN 0x8270 -#define AR_WOW_BCN_TIMO 0x8274 -#define AR_WOW_KEEP_ALIVE_TIMO 0x8278 -#define AR_WOW_KEEP_ALIVE 0x827c -#define AR_WOW_US_SCALAR 0x8284 -#define AR_WOW_KEEP_ALIVE_DELAY 0x8288 -#define AR_WOW_PATTERN_MATCH 0x828c -#define AR_WOW_PATTERN_OFF1 0x8290 /* pattern bytes 0 -> 3 */ -#define AR_WOW_PATTERN_OFF2 0x8294 /* pattern bytes 4 -> 7 */ - -/* for AR9285 or later version of chips */ -#define AR_WOW_EXACT 0x829c -#define AR_WOW_LENGTH1 0x8360 -#define AR_WOW_LENGTH2 0X8364 -/* register to enable match for less than 256 bytes packets */ -#define AR_WOW_PATTERN_MATCH_LT_256B 0x8368 - -#define AR_SW_WOW_CONTROL 0x20018 -#define AR_SW_WOW_ENABLE 0x1 -#define AR_SWITCH_TO_REFCLK 0x2 -#define AR_RESET_CONTROL 0x4 -#define AR_RESET_VALUE_MASK 0x8 -#define AR_HW_WOW_DISABLE 0x10 -#define AR_CLR_MAC_INTERRUPT 0x20 -#define AR_CLR_KA_INTERRUPT 0x40 - -/* AR_WOW_PATTERN register values */ -#define AR_WOW_BACK_OFF_SHIFT(x) ((x & 0xf) << 28) /* in usecs */ -#define AR_WOW_MAC_INTR_EN 0x00040000 -#define AR_WOW_MAGIC_EN 0x00010000 -#define AR_WOW_PATTERN_EN(x) (x & 0xff) -#define AR_WOW_PAT_FOUND_SHIFT 8 -#define AR_WOW_PATTERN_FOUND(x) (x & (0xff << AR_WOW_PAT_FOUND_SHIFT)) -#define AR_WOW_PATTERN_FOUND_MASK ((0xff) << AR_WOW_PAT_FOUND_SHIFT) -#define AR_WOW_MAGIC_PAT_FOUND 0x00020000 -#define AR_WOW_MAC_INTR 0x00080000 -#define AR_WOW_KEEP_ALIVE_FAIL 0x00100000 -#define AR_WOW_BEACON_FAIL 0x00200000 - -#define AR_WOW_STATUS(x) (x & (AR_WOW_PATTERN_FOUND_MASK | \ - AR_WOW_MAGIC_PAT_FOUND | \ - AR_WOW_KEEP_ALIVE_FAIL | \ - AR_WOW_BEACON_FAIL)) -#define AR_WOW_CLEAR_EVENTS(x) (x & ~(AR_WOW_PATTERN_EN(0xff) | \ - AR_WOW_MAGIC_EN | \ - AR_WOW_MAC_INTR_EN | \ - AR_WOW_BEACON_FAIL | \ - AR_WOW_KEEP_ALIVE_FAIL)) - -/* AR_WOW_COUNT register values */ -#define AR_WOW_AIFS_CNT(x) (x & 0xff) -#define AR_WOW_SLOT_CNT(x) ((x & 0xff) << 8) -#define AR_WOW_KEEP_ALIVE_CNT(x) ((x & 0xff) << 16) - -/* AR_WOW_BCN_EN register */ -#define AR_WOW_BEACON_FAIL_EN 0x00000001 - -/* AR_WOW_BCN_TIMO rgister */ -#define AR_WOW_BEACON_TIMO 0x40000000 /* valid if BCN_EN is set */ - -/* AR_WOW_KEEP_ALIVE_TIMO register */ -#define AR_WOW_KEEP_ALIVE_TIMO_VALUE -#define AR_WOW_KEEP_ALIVE_NEVER 0xffffffff - -/* AR_WOW_KEEP_ALIVE register */ -#define AR_WOW_KEEP_ALIVE_AUTO_DIS 0x00000001 -#define AR_WOW_KEEP_ALIVE_FAIL_DIS 0x00000002 - -/* AR_WOW_KEEP_ALIVE_DELAY register */ -#define AR_WOW_KEEP_ALIVE_DELAY_VALUE 0x000003e8 /* 1 msec */ - - -/* - * keep it long for beacon workaround - ensure no false alarm - */ -#define AR_WOW_BMISSTHRESHOLD 0x20 - -/* AR_WOW_PATTERN_MATCH register */ -#define AR_WOW_PAT_END_OF_PKT(x) (x & 0xf) -#define AR_WOW_PAT_OFF_MATCH(x) ((x & 0xf) << 8) - -/* - * default values for Wow Configuration for backoff, aifs, slot, keep-alive - * to be programmed into various registers. - */ -#define AR_WOW_PAT_BACKOFF 0x00000004 /* AR_WOW_PATTERN_REG */ -#define AR_WOW_CNT_AIFS_CNT 0x00000022 /* AR_WOW_COUNT_REG */ -#define AR_WOW_CNT_SLOT_CNT 0x00000009 /* AR_WOW_COUNT_REG */ -/* - * Keepalive count applicable for AR9280 2.0 and above. - */ -#define AR_WOW_CNT_KA_CNT 0x00000008 /* AR_WOW_COUNT register */ - -/* WoW - Transmit buffer for keep alive frames */ -#define AR_WOW_TRANSMIT_BUFFER 0xe000 /* E000 - EFFC */ - -#define AR_WOW_TXBUF(i) (AR_WOW_TRANSMIT_BUFFER + ((i) << 2)) - -#define AR_WOW_KA_DESC_WORD2 0xe000 - -#define AR_WOW_KA_DATA_WORD0 0xe030 - -/* WoW Transmit Buffer for patterns */ -#define AR_WOW_TB_PATTERN(i) (0xe100 + (i << 8)) -#define AR_WOW_TB_MASK(i) (0xec00 + (i << 5)) - -/* Currently Pattern 0-7 are supported - so bit 0-7 are set */ -#define AR_WOW_PATTERN_SUPPORTED 0xff -#define AR_WOW_LENGTH_MAX 0xff -#define AR_WOW_LEN1_SHIFT(_i) ((0x3 - ((_i) & 0x3)) << 0x3) -#define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i)) -#define AR_WOW_LEN2_SHIFT(_i) ((0x7 - ((_i) & 0x7)) << 0x3) -#define AR_WOW_LENGTH2_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN2_SHIFT(_i)) - #define AR9271_CORE_CLOCK 117 /* clock to 117Mhz */ #define AR9271_TARGET_BAUD_RATE 19200 /* 115200 */ diff --git a/drivers/net/wireless/ath/ath9k/reg_wow.h b/drivers/net/wireless/ath/ath9k/reg_wow.h new file mode 100644 index 000000000000..3abfca56ca58 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/reg_wow.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef REG_WOW_H +#define REG_WOW_H + +#define AR_WOW_PATTERN 0x825C +#define AR_WOW_COUNT 0x8260 +#define AR_WOW_BCN_EN 0x8270 +#define AR_WOW_BCN_TIMO 0x8274 +#define AR_WOW_KEEP_ALIVE_TIMO 0x8278 +#define AR_WOW_KEEP_ALIVE 0x827c +#define AR_WOW_KEEP_ALIVE_DELAY 0x8288 +#define AR_WOW_PATTERN_MATCH 0x828c + +/* + * AR_WOW_LENGTH1 + * bit 31:24 pattern 0 length + * bit 23:16 pattern 1 length + * bit 15:8 pattern 2 length + * bit 7:0 pattern 3 length + * + * AR_WOW_LENGTH2 + * bit 31:24 pattern 4 length + * bit 23:16 pattern 5 length + * bit 15:8 pattern 6 length + * bit 7:0 pattern 7 length + * + * AR_WOW_LENGTH3 + * bit 31:24 pattern 8 length + * bit 23:16 pattern 9 length + * bit 15:8 pattern 10 length + * bit 7:0 pattern 11 length + * + * AR_WOW_LENGTH4 + * bit 31:24 pattern 12 length + * bit 23:16 pattern 13 length + * bit 15:8 pattern 14 length + * bit 7:0 pattern 15 length + */ +#define AR_WOW_LENGTH1 0x8360 +#define AR_WOW_LENGTH2 0X8364 +#define AR_WOW_LENGTH3 0X8380 +#define AR_WOW_LENGTH4 0X8384 + +#define AR_WOW_PATTERN_MATCH_LT_256B 0x8368 +#define AR_MAC_PCU_WOW4 0x8370 + +#define AR_SW_WOW_CONTROL 0x20018 +#define AR_SW_WOW_ENABLE 0x1 +#define AR_SWITCH_TO_REFCLK 0x2 +#define AR_RESET_CONTROL 0x4 +#define AR_RESET_VALUE_MASK 0x8 +#define AR_HW_WOW_DISABLE 0x10 +#define AR_CLR_MAC_INTERRUPT 0x20 +#define AR_CLR_KA_INTERRUPT 0x40 + +#define AR_WOW_BACK_OFF_SHIFT(x) ((x & 0xf) << 27) /* in usecs */ +#define AR_WOW_MAC_INTR_EN 0x00040000 +#define AR_WOW_MAGIC_EN 0x00010000 +#define AR_WOW_PATTERN_EN(x) (x & 0xff) +#define AR_WOW_PAT_FOUND_SHIFT 8 +#define AR_WOW_PATTERN_FOUND(x) (x & (0xff << AR_WOW_PAT_FOUND_SHIFT)) +#define AR_WOW_PATTERN_FOUND_MASK ((0xff) << AR_WOW_PAT_FOUND_SHIFT) +#define AR_WOW_MAGIC_PAT_FOUND 0x00020000 +#define AR_WOW_MAC_INTR 0x00080000 +#define AR_WOW_KEEP_ALIVE_FAIL 0x00100000 +#define AR_WOW_BEACON_FAIL 0x00200000 + +#define AR_WOW_STATUS(x) (x & (AR_WOW_PATTERN_FOUND_MASK | \ + AR_WOW_MAGIC_PAT_FOUND | \ + AR_WOW_KEEP_ALIVE_FAIL | \ + AR_WOW_BEACON_FAIL)) +#define AR_WOW_CLEAR_EVENTS(x) (x & ~(AR_WOW_PATTERN_EN(0xff) | \ + AR_WOW_MAGIC_EN | \ + AR_WOW_MAC_INTR_EN | \ + AR_WOW_BEACON_FAIL | \ + AR_WOW_KEEP_ALIVE_FAIL)) + +#define AR_WOW_AIFS_CNT(x) (x & 0xff) +#define AR_WOW_SLOT_CNT(x) ((x & 0xff) << 8) +#define AR_WOW_KEEP_ALIVE_CNT(x) ((x & 0xff) << 16) + +#define AR_WOW_BEACON_FAIL_EN 0x00000001 +#define AR_WOW_BEACON_TIMO 0x40000000 +#define AR_WOW_KEEP_ALIVE_NEVER 0xffffffff +#define AR_WOW_KEEP_ALIVE_AUTO_DIS 0x00000001 +#define AR_WOW_KEEP_ALIVE_FAIL_DIS 0x00000002 +#define AR_WOW_KEEP_ALIVE_DELAY_VALUE 0x000003e8 /* 1 msec */ +#define AR_WOW_BMISSTHRESHOLD 0x20 +#define AR_WOW_PAT_END_OF_PKT(x) (x & 0xf) +#define AR_WOW_PAT_OFF_MATCH(x) ((x & 0xf) << 8) +#define AR_WOW_PAT_BACKOFF 0x00000004 +#define AR_WOW_CNT_AIFS_CNT 0x00000022 +#define AR_WOW_CNT_SLOT_CNT 0x00000009 +#define AR_WOW_CNT_KA_CNT 0x00000008 + +#define AR_WOW_TRANSMIT_BUFFER 0xe000 +#define AR_WOW_TXBUF(i) (AR_WOW_TRANSMIT_BUFFER + ((i) << 2)) +#define AR_WOW_KA_DESC_WORD2 0xe000 +#define AR_WOW_TB_PATTERN(i) (0xe100 + (i << 8)) +#define AR_WOW_TB_MASK(i) (0xec00 + (i << 5)) +#define AR_WOW_PATTERN_SUPPORTED_LEGACY 0xff +#define AR_WOW_PATTERN_SUPPORTED 0xffff +#define AR_WOW_LENGTH_MAX 0xff +#define AR_WOW_LEN1_SHIFT(_i) ((0x3 - ((_i) & 0x3)) << 0x3) +#define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i)) +#define AR_WOW_LEN2_SHIFT(_i) ((0x7 - ((_i) & 0x7)) << 0x3) +#define AR_WOW_LENGTH2_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN2_SHIFT(_i)) +#define AR_WOW_LEN3_SHIFT(_i) ((0xb - ((_i) & 0xb)) << 0x3) +#define AR_WOW_LENGTH3_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN3_SHIFT(_i)) +#define AR_WOW_LEN4_SHIFT(_i) ((0xf - ((_i) & 0xf)) << 0x3) +#define AR_WOW_LENGTH4_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN4_SHIFT(_i)) + +#endif /* REG_WOW_H */ diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 5f30e580d942..8d0b1730a9d5 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -16,36 +16,43 @@ #include "ath9k.h" -static const struct wiphy_wowlan_support ath9k_wowlan_support = { +static const struct wiphy_wowlan_support ath9k_wowlan_support_legacy = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, .n_patterns = MAX_NUM_USER_PATTERN, .pattern_min_len = 1, .pattern_max_len = MAX_PATTERN_SIZE, }; -static void ath9k_wow_map_triggers(struct ath_softc *sc, - struct cfg80211_wowlan *wowlan, - u32 *wow_triggers) +static const struct wiphy_wowlan_support ath9k_wowlan_support = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .n_patterns = MAX_NUM_PATTERN - 2, + .pattern_min_len = 1, + .pattern_max_len = MAX_PATTERN_SIZE, +}; + +static u8 ath9k_wow_map_triggers(struct ath_softc *sc, + struct cfg80211_wowlan *wowlan) { + u8 wow_triggers = 0; + if (wowlan->disconnect) - *wow_triggers |= AH_WOW_LINK_CHANGE | - AH_WOW_BEACON_MISS; + wow_triggers |= AH_WOW_LINK_CHANGE | + AH_WOW_BEACON_MISS; if (wowlan->magic_pkt) - *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; + wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; if (wowlan->n_patterns) - *wow_triggers |= AH_WOW_USER_PATTERN_EN; - - sc->wow_enabled = *wow_triggers; + wow_triggers |= AH_WOW_USER_PATTERN_EN; + return wow_triggers; } -static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) +static int ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); int pattern_count = 0; - int i, byte_cnt; + int ret, i, byte_cnt = 0; u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; u8 dis_deauth_mask[MAX_PATTERN_SIZE]; @@ -80,12 +87,7 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) * | x:x:x:x:x:x -- 22 bytes */ - /* Create Disassociate Pattern first */ - - byte_cnt = 0; - /* Fill out the mask with all FF's */ - for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++) dis_deauth_mask[i] = 0xff; @@ -108,19 +110,17 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) byte_cnt += 6; /* copy the bssid, its same as the source mac address */ - memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); /* Create Disassociate pattern mask */ - dis_deauth_mask[0] = 0xfe; dis_deauth_mask[1] = 0x03; dis_deauth_mask[2] = 0xc0; - ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); - - ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, - pattern_count, byte_cnt); + ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, + pattern_count, byte_cnt); + if (ret) + goto exit; pattern_count++; /* @@ -129,59 +129,39 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) */ dis_deauth_pattern[0] = 0xC0; - ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, - pattern_count, byte_cnt); - + ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, + pattern_count, byte_cnt); +exit: + return ret; } -static void ath9k_wow_add_pattern(struct ath_softc *sc, - struct cfg80211_wowlan *wowlan) +static int ath9k_wow_add_pattern(struct ath_softc *sc, + struct cfg80211_wowlan *wowlan) { struct ath_hw *ah = sc->sc_ah; - struct ath9k_wow_pattern *wow_pattern = NULL; struct cfg80211_pkt_pattern *patterns = wowlan->patterns; - int mask_len; + u8 wow_pattern[MAX_PATTERN_SIZE]; + u8 wow_mask[MAX_PATTERN_SIZE]; + int mask_len, ret = 0; s8 i = 0; - if (!wowlan->n_patterns) - return; - - /* - * Add the new user configured patterns - */ for (i = 0; i < wowlan->n_patterns; i++) { + mask_len = DIV_ROUND_UP(patterns[i].pattern_len, 8); + memset(wow_pattern, 0, MAX_PATTERN_SIZE); + memset(wow_mask, 0, MAX_PATTERN_SIZE); + memcpy(wow_pattern, patterns[i].pattern, patterns[i].pattern_len); + memcpy(wow_mask, patterns[i].mask, mask_len); - wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL); - - if (!wow_pattern) - return; - - /* - * TODO: convert the generic user space pattern to - * appropriate chip specific/802.11 pattern. - */ - - mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); - memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE); - memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE); - memcpy(wow_pattern->pattern_bytes, patterns[i].pattern, - patterns[i].pattern_len); - memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len); - wow_pattern->pattern_len = patterns[i].pattern_len; - - /* - * just need to take care of deauth and disssoc pattern, - * make sure we don't overwrite them. - */ - - ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes, - wow_pattern->mask_bytes, - i + 2, - wow_pattern->pattern_len); - kfree(wow_pattern); - + ret = ath9k_hw_wow_apply_pattern(ah, + wow_pattern, + wow_mask, + i + 2, + patterns[i].pattern_len); + if (ret) + break; } + return ret; } int ath9k_suspend(struct ieee80211_hw *hw, @@ -190,58 +170,55 @@ int ath9k_suspend(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); - u32 wow_triggers_enabled = 0; + u8 triggers; int ret = 0; ath9k_deinit_channel_context(sc); mutex_lock(&sc->mutex); - ath_cancel_work(sc); - ath_stop_ani(sc); - if (test_bit(ATH_OP_INVALID, &common->op_flags)) { - ath_dbg(common, ANY, "Device not present\n"); - ret = -EINVAL; + ath_err(common, "Device not present\n"); + ret = -ENODEV; goto fail_wow; } if (WARN_ON(!wowlan)) { - ath_dbg(common, WOW, "None of the WoW triggers enabled\n"); + ath_err(common, "None of the WoW triggers enabled\n"); ret = -EINVAL; goto fail_wow; } - if (!device_can_wakeup(sc->dev)) { - ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n"); - ret = 1; - goto fail_wow; - } - - /* - * none of the sta vifs are associated - * and we are not currently handling multivif - * cases, for instance we have to seperately - * configure 'keep alive frame' for each - * STA. - */ - - if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { - ath_dbg(common, WOW, "None of the STA vifs are associated\n"); - ret = 1; - goto fail_wow; - } - if (sc->cur_chan->nvifs > 1) { ath_dbg(common, WOW, "WoW for multivif is not yet supported\n"); ret = 1; goto fail_wow; } - ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled); + if (ath9k_is_chanctx_enabled()) { + if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) { + ath_dbg(common, WOW, + "Multi-channel WOW is not supported\n"); + ret = 1; + goto fail_wow; + } + } - ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n", - wow_triggers_enabled); + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { + ath_dbg(common, WOW, "None of the STA vifs are associated\n"); + ret = 1; + goto fail_wow; + } + + triggers = ath9k_wow_map_triggers(sc, wowlan); + if (!triggers) { + ath_dbg(common, WOW, "No valid WoW triggers\n"); + ret = 1; + goto fail_wow; + } + + ath_cancel_work(sc); + ath_stop_ani(sc); ath9k_ps_wakeup(sc); @@ -251,10 +228,21 @@ int ath9k_suspend(struct ieee80211_hw *hw, * Enable wake up on recieving disassoc/deauth * frame by default. */ - ath9k_wow_add_disassoc_deauth_pattern(sc); + ret = ath9k_wow_add_disassoc_deauth_pattern(sc); + if (ret) { + ath_err(common, + "Unable to add disassoc/deauth pattern: %d\n", ret); + goto fail_wow; + } - if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN) - ath9k_wow_add_pattern(sc, wowlan); + if (triggers & AH_WOW_USER_PATTERN_EN) { + ret = ath9k_wow_add_pattern(sc, wowlan); + if (ret) { + ath_err(common, + "Unable to add user pattern: %d\n", ret); + goto fail_wow; + } + } spin_lock_bh(&sc->sc_pcu_lock); /* @@ -278,12 +266,12 @@ int ath9k_suspend(struct ieee80211_hw *hw, synchronize_irq(sc->irq); tasklet_kill(&sc->intr_tq); - ath9k_hw_wow_enable(ah, wow_triggers_enabled); + ath9k_hw_wow_enable(ah, triggers); ath9k_ps_restore(sc); - ath_dbg(common, ANY, "WoW enabled in ath9k\n"); - atomic_inc(&sc->wow_sleep_proc_intr); + ath_dbg(common, WOW, "Suspend with WoW triggers: 0x%x\n", triggers); + set_bit(ATH_OP_WOW_ENABLED, &common->op_flags); fail_wow: mutex_unlock(&sc->mutex); return ret; @@ -294,7 +282,7 @@ int ath9k_resume(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); - u32 wow_status; + u8 status; mutex_lock(&sc->mutex); @@ -309,29 +297,14 @@ int ath9k_resume(struct ieee80211_hw *hw) spin_unlock_bh(&sc->sc_pcu_lock); - wow_status = ath9k_hw_wow_wakeup(ah); - - if (atomic_read(&sc->wow_got_bmiss_intr) == 0) { - /* - * some devices may not pick beacon miss - * as the reason they woke up so we add - * that here for that shortcoming. - */ - wow_status |= AH_WOW_BEACON_MISS; - atomic_dec(&sc->wow_got_bmiss_intr); - ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n"); - } - - atomic_dec(&sc->wow_sleep_proc_intr); - - if (wow_status) { - ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n", - ath9k_hw_wow_event_to_string(wow_status), wow_status); - } + status = ath9k_hw_wow_wakeup(ah); + ath_dbg(common, WOW, "Resume with WoW status: 0x%x\n", status); ath_restart_work(sc); ath9k_start_btcoex(sc); + clear_bit(ATH_OP_WOW_ENABLED, &common->op_flags); + ath9k_ps_restore(sc); mutex_unlock(&sc->mutex); @@ -341,22 +314,35 @@ int ath9k_resume(struct ieee80211_hw *hw) void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); mutex_lock(&sc->mutex); - device_init_wakeup(sc->dev, 1); device_set_wakeup_enable(sc->dev, enabled); mutex_unlock(&sc->mutex); + + ath_dbg(common, WOW, "WoW wakeup source is %s\n", + (enabled) ? "enabled" : "disabled"); } void ath9k_init_wow(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; - if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && - (sc->driver_data & ATH9K_PCI_WOW) && - device_can_wakeup(sc->dev)) - hw->wiphy->wowlan = &ath9k_wowlan_support; + if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow) { + if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565_11_OR_LATER(ah)) + hw->wiphy->wowlan = &ath9k_wowlan_support; + else + hw->wiphy->wowlan = &ath9k_wowlan_support_legacy; - atomic_set(&sc->wow_sleep_proc_intr, -1); - atomic_set(&sc->wow_got_bmiss_intr, -1); + device_init_wakeup(sc->dev, 1); + } +} + +void ath9k_deinit_wow(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + + if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow) + device_init_wakeup(sc->dev, 0); } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index e9bd02c2e844..1b8e75c4d2c2 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1097,24 +1097,65 @@ void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop) } static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, - u8 rateidx) + u8 rateidx, bool is_40, bool is_cck) { u8 max_power; + struct sk_buff *skb; + struct ath_frame_info *fi; + struct ieee80211_tx_info *info; struct ath_hw *ah = sc->sc_ah; - if (sc->tx99_state) + if (sc->tx99_state || !ah->tpc_enabled) return MAX_RATE_POWER; + skb = bf->bf_mpdu; + fi = get_frame_info(skb); + info = IEEE80211_SKB_CB(skb); + if (!AR_SREV_9300_20_OR_LATER(ah)) { - /* ar9002 is not sipported for the moment */ - return MAX_RATE_POWER; - } + int txpower = fi->tx_power; - if (!bf->bf_state.bfs_paprd) { - struct sk_buff *skb = bf->bf_mpdu; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ath_frame_info *fi = get_frame_info(skb); + if (is_40) { + u8 power_ht40delta; + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) { + bool is_2ghz; + struct modal_eep_header *pmodal; + + is_2ghz = info->band == IEEE80211_BAND_2GHZ; + pmodal = &eep->modalHeader[is_2ghz]; + power_ht40delta = pmodal->ht40PowerIncForPdadc; + } else { + power_ht40delta = 2; + } + txpower += power_ht40delta; + } + + if (AR_SREV_9287(ah) || AR_SREV_9285(ah) || + AR_SREV_9271(ah)) { + txpower -= 2 * AR9287_PWR_TABLE_OFFSET_DB; + } else if (AR_SREV_9280_20_OR_LATER(ah)) { + s8 power_offset; + + power_offset = ah->eep_ops->get_eeprom(ah, + EEP_PWR_TABLE_OFFSET); + txpower -= 2 * power_offset; + } + + if (OLC_FOR_AR9280_20_LATER && is_cck) + txpower -= 2; + + txpower = max(txpower, 0); + max_power = min_t(u8, ah->tx_power[rateidx], txpower); + + /* XXX: clamp minimum TX power at 1 for AR9160 since if + * max_power is set to 0, frames are transmitted at max + * TX power + */ + if (!max_power && !AR_SREV_9280_20_OR_LATER(ah)) + max_power = 1; + } else if (!bf->bf_state.bfs_paprd) { if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC)) max_power = min(ah->tx_power_stbc[rateidx], fi->tx_power); @@ -1152,7 +1193,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, info->rtscts_rate = fi->rtscts_rate; for (i = 0; i < ARRAY_SIZE(bf->rates); i++) { - bool is_40, is_sgi, is_sp; + bool is_40, is_sgi, is_sp, is_cck; int phy; if (!rates[i].count || (rates[i].idx < 0)) @@ -1198,7 +1239,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC; - info->txpower[i] = ath_get_rate_txpower(sc, bf, rix); + info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, + is_40, false); continue; } @@ -1227,7 +1269,9 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah, phy, rate->bitrate * 100, len, rix, is_sp); - info->txpower[i] = ath_get_rate_txpower(sc, bf, rix); + is_cck = IS_CCK_RATE(info->rates[i].Rate); + info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, false, + is_cck); } /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ @@ -2259,7 +2303,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_txq *txq = txctl->txq; struct ath_atx_tid *tid = NULL; struct ath_buf *bf; - bool queue, skip_uapsd = false; + bool queue, skip_uapsd = false, ps_resp; int q, ret; if (vif) @@ -2268,6 +2312,8 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) txctl->force_channel = true; + ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE); + ret = ath_tx_prepare(hw, skb, txctl); if (ret) return ret; @@ -2310,7 +2356,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, if (txctl->an && queue) tid = ath_get_skb_tid(sc, txctl->an, skb); - if (!skip_uapsd && (info->flags & IEEE80211_TX_CTL_PS_RESPONSE)) { + if (!skip_uapsd && ps_resp) { ath_txq_unlock(sc, txq); txq = sc->tx.uapsdq; ath_txq_lock(sc, txq); @@ -2443,9 +2489,12 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, if (sc->sc_ah->caldata) set_bit(PAPRD_PACKET_SENT, &sc->sc_ah->caldata->cal_flags); - if (!(tx_flags & ATH_TX_ERROR)) - /* Frame was ACKed */ - tx_info->flags |= IEEE80211_TX_STAT_ACK; + if (!(tx_flags & ATH_TX_ERROR)) { + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) + tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + else + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } padpos = ieee80211_hdrlen(hdr->frame_control); padsize = padpos & 3; diff --git a/drivers/net/wireless/ath/carl9170/cmd.c b/drivers/net/wireless/ath/carl9170/cmd.c index 39a63874b275..f2b4f537e4c1 100644 --- a/drivers/net/wireless/ath/carl9170/cmd.c +++ b/drivers/net/wireless/ath/carl9170/cmd.c @@ -188,12 +188,12 @@ int carl9170_collect_tally(struct ar9170 *ar) if (ar->channel) { info = &ar->survey[ar->channel->hw_value]; - info->channel_time = ar->tally.active; - info->channel_time_busy = ar->tally.cca; - info->channel_time_tx = ar->tally.tx_time; - do_div(info->channel_time, 1000); - do_div(info->channel_time_busy, 1000); - do_div(info->channel_time_tx, 1000); + info->time = ar->tally.active; + info->time_busy = ar->tally.cca; + info->time_tx = ar->tally.tx_time; + do_div(info->time, 1000); + do_div(info->time_busy, 1000); + do_div(info->time_tx, 1000); } } return 0; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index ef5b6dc7b7f1..f1455a04cb62 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1690,9 +1690,9 @@ found: survey->filled |= SURVEY_INFO_IN_USE; if (ar->fw.hw_counters) { - survey->filled |= SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_TX; + survey->filled |= SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_TX; } return 0; diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c index cfd0554cf140..3d57f8772389 100644 --- a/drivers/net/wireless/ath/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/dfs_pattern_detector.c @@ -86,7 +86,7 @@ static const struct radar_detector_specs fcc_radar_ref_types[] = { FCC_PATTERN(1, 0, 5, 150, 230, 1, 23), FCC_PATTERN(2, 6, 10, 200, 500, 1, 16), FCC_PATTERN(3, 11, 20, 200, 500, 1, 12), - FCC_PATTERN(4, 50, 100, 1000, 2000, 1, 20), + FCC_PATTERN(4, 50, 100, 1000, 2000, 1, 1), FCC_PATTERN(5, 0, 1, 333, 333, 1, 9), }; diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 73f12f196f14..086549b732b9 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -84,6 +84,7 @@ static int wcn36xx_dxe_allocate_ctl_block(struct wcn36xx_dxe_ch *ch) if (!cur_ctl) goto out_fail; + spin_lock_init(&cur_ctl->skb_lock); cur_ctl->ctl_blk_order = i; if (i == 0) { ch->head_blk_ctl = cur_ctl; @@ -354,6 +355,8 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) * and while-do will not make any cycles. */ do { + if (ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK) + break; if (ctl->skb) { dma_unmap_single(NULL, ctl->desc->src_addr_l, ctl->skb->len, DMA_TO_DEVICE); diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 7dd8873f757e..0783d2ed8238 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -298,6 +298,8 @@ static int wcn36xx_start(struct ieee80211_hw *hw) wcn36xx_debugfs_init(wcn); INIT_LIST_HEAD(&wcn->vif_list); + spin_lock_init(&wcn->dxe_lock); + return 0; out_smd_stop: @@ -795,6 +797,7 @@ static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n", vif, sta->addr); + spin_lock_init(&sta_priv->ampdu_lock); vif_priv->sta = sta_priv; sta_priv->vif = vif_priv; /* @@ -873,21 +876,32 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, get_sta_index(vif, sta_priv)); wcn36xx_smd_add_ba(wcn); wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv)); - ieee80211_start_tx_ba_session(sta, tid, 0); break; case IEEE80211_AMPDU_RX_STOP: wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv)); break; case IEEE80211_AMPDU_TX_START: + spin_lock_bh(&sta_priv->ampdu_lock); + sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START; + spin_unlock_bh(&sta_priv->ampdu_lock); + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: + spin_lock_bh(&sta_priv->ampdu_lock); + sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL; + spin_unlock_bh(&sta_priv->ampdu_lock); + wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1, get_sta_index(vif, sta_priv)); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: case IEEE80211_AMPDU_TX_STOP_CONT: + spin_lock_bh(&sta_priv->ampdu_lock); + sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_NONE; + spin_unlock_bh(&sta_priv->ampdu_lock); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; default: diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 63986931829e..69ed39731902 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -21,6 +21,61 @@ #include #include "smd.h" +struct wcn36xx_cfg_val { + u32 cfg_id; + u32 value; +}; + +#define WCN36XX_CFG_VAL(id, val) \ +{ \ + .cfg_id = WCN36XX_HAL_CFG_ ## id, \ + .value = val \ +} + +static struct wcn36xx_cfg_val wcn36xx_cfg_vals[] = { + WCN36XX_CFG_VAL(CURRENT_TX_ANTENNA, 1), + WCN36XX_CFG_VAL(CURRENT_RX_ANTENNA, 1), + WCN36XX_CFG_VAL(LOW_GAIN_OVERRIDE, 0), + WCN36XX_CFG_VAL(POWER_STATE_PER_CHAIN, 785), + WCN36XX_CFG_VAL(CAL_PERIOD, 5), + WCN36XX_CFG_VAL(CAL_CONTROL, 1), + WCN36XX_CFG_VAL(PROXIMITY, 0), + WCN36XX_CFG_VAL(NETWORK_DENSITY, 3), + WCN36XX_CFG_VAL(MAX_MEDIUM_TIME, 6000), + WCN36XX_CFG_VAL(MAX_MPDUS_IN_AMPDU, 64), + WCN36XX_CFG_VAL(RTS_THRESHOLD, 2347), + WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 6), + WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 6), + WCN36XX_CFG_VAL(FRAGMENTATION_THRESHOLD, 8000), + WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ZERO, 5), + WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ONE, 10), + WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_TWO, 15), + WCN36XX_CFG_VAL(FIXED_RATE, 0), + WCN36XX_CFG_VAL(RETRYRATE_POLICY, 4), + WCN36XX_CFG_VAL(RETRYRATE_SECONDARY, 0), + WCN36XX_CFG_VAL(RETRYRATE_TERTIARY, 0), + WCN36XX_CFG_VAL(FORCE_POLICY_PROTECTION, 5), + WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_24GHZ, 1), + WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_5GHZ, 5), + WCN36XX_CFG_VAL(DEFAULT_RATE_INDEX_5GHZ, 5), + WCN36XX_CFG_VAL(MAX_BA_SESSIONS, 40), + WCN36XX_CFG_VAL(PS_DATA_INACTIVITY_TIMEOUT, 200), + WCN36XX_CFG_VAL(PS_ENABLE_BCN_FILTER, 1), + WCN36XX_CFG_VAL(PS_ENABLE_RSSI_MONITOR, 1), + WCN36XX_CFG_VAL(NUM_BEACON_PER_RSSI_AVERAGE, 20), + WCN36XX_CFG_VAL(STATS_PERIOD, 10), + WCN36XX_CFG_VAL(CFP_MAX_DURATION, 30000), + WCN36XX_CFG_VAL(FRAME_TRANS_ENABLED, 0), + WCN36XX_CFG_VAL(BA_THRESHOLD_HIGH, 128), + WCN36XX_CFG_VAL(MAX_BA_BUFFERS, 2560), + WCN36XX_CFG_VAL(DYNAMIC_PS_POLL_VALUE, 0), + WCN36XX_CFG_VAL(TX_PWR_CTRL_ENABLE, 1), + WCN36XX_CFG_VAL(ENABLE_CLOSE_LOOP, 1), + WCN36XX_CFG_VAL(ENABLE_LPWR_IMG_TRANSITION, 0), + WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10), + WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0), +}; + static int put_cfg_tlv_u32(struct wcn36xx *wcn, size_t *len, u32 id, u32 value) { struct wcn36xx_hal_cfg *entry; @@ -357,8 +412,10 @@ static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len) int wcn36xx_smd_start(struct wcn36xx *wcn) { - struct wcn36xx_hal_mac_start_req_msg msg_body; + struct wcn36xx_hal_mac_start_req_msg msg_body, *body; int ret = 0; + int i; + size_t len; mutex_lock(&wcn->hal_mutex); INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_REQ); @@ -368,10 +425,22 @@ int wcn36xx_smd_start(struct wcn36xx *wcn) PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + body = (struct wcn36xx_hal_mac_start_req_msg *)wcn->hal_buf; + len = body->header.len; + + for (i = 0; i < ARRAY_SIZE(wcn36xx_cfg_vals); i++) { + ret = put_cfg_tlv_u32(wcn, &len, wcn36xx_cfg_vals[i].cfg_id, + wcn36xx_cfg_vals[i].value); + if (ret) + goto out; + } + body->header.len = len; + body->params.len = len - sizeof(*body); + wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start type %d\n", msg_body.params.type); - ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); + ret = wcn36xx_smd_send_and_wait(wcn, body->header.len); if (ret) { wcn36xx_err("Sending hal_start failed\n"); goto out; diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 32bb26a0db2a..9bec8237231d 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -93,6 +93,7 @@ static void wcn36xx_set_tx_pdu(struct wcn36xx_tx_bd *bd, bd->pdu.mpdu_header_off; bd->pdu.mpdu_len = len; bd->pdu.tid = tid; + bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_QOS; } static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn, @@ -110,15 +111,54 @@ static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn, wcn36xx_warn("vif %pM not found\n", addr); return NULL; } + +static void wcn36xx_tx_start_ampdu(struct wcn36xx *wcn, + struct wcn36xx_sta *sta_priv, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_sta *sta; + u8 *qc, tid; + + if (!conf_is_ht(&wcn->hw->conf)) + return; + + sta = wcn36xx_priv_to_sta(sta_priv); + + if (WARN_ON(!ieee80211_is_data_qos(hdr->frame_control))) + return; + + if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) + return; + + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + + spin_lock(&sta_priv->ampdu_lock); + if (sta_priv->ampdu_state[tid] != WCN36XX_AMPDU_NONE) + goto out_unlock; + + if (sta_priv->non_agg_frame_ct++ >= WCN36XX_AMPDU_START_THRESH) { + sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START; + sta_priv->non_agg_frame_ct = 0; + ieee80211_start_tx_ba_session(sta, tid, 0); + } +out_unlock: + spin_unlock(&sta_priv->ampdu_lock); +} + static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, struct wcn36xx *wcn, struct wcn36xx_vif **vif_priv, struct wcn36xx_sta *sta_priv, - struct ieee80211_hdr *hdr, + struct sk_buff *skb, bool bcast) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_vif *vif = NULL; struct wcn36xx_vif *__vif_priv = NULL; + bool is_data_qos; + bd->bd_rate = WCN36XX_BD_RATE_DATA; /* @@ -157,14 +197,26 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd, bd->ack_policy = 1; } *vif_priv = __vif_priv; + + is_data_qos = ieee80211_is_data_qos(hdr->frame_control); + + wcn36xx_set_tx_pdu(bd, + is_data_qos ? + sizeof(struct ieee80211_qos_hdr) : + sizeof(struct ieee80211_hdr_3addr), + skb->len, sta_priv ? sta_priv->tid : 0); + + if (sta_priv && is_data_qos) + wcn36xx_tx_start_ampdu(wcn, sta_priv, skb); } static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd, struct wcn36xx *wcn, struct wcn36xx_vif **vif_priv, - struct ieee80211_hdr *hdr, + struct sk_buff *skb, bool bcast) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct wcn36xx_vif *__vif_priv = get_vif_by_addr(wcn, hdr->addr2); bd->sta_index = __vif_priv->self_sta_index; @@ -198,6 +250,12 @@ static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd, } else bd->queue_id = WCN36XX_TX_U_WQ_ID; *vif_priv = __vif_priv; + + wcn36xx_set_tx_pdu(bd, + ieee80211_is_data_qos(hdr->frame_control) ? + sizeof(struct ieee80211_qos_hdr) : + sizeof(struct ieee80211_hdr_3addr), + skb->len, WCN36XX_TID); } int wcn36xx_start_tx(struct wcn36xx *wcn, @@ -237,7 +295,7 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, bd->dpu_rf = WCN36XX_BMU_WQ_TX; - bd->tx_comp = info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS; + bd->tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS); if (bd->tx_comp) { wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n"); spin_lock_irqsave(&wcn->dxe_lock, flags); @@ -259,22 +317,11 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, } /* Data frames served first*/ - if (is_low) { - wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, hdr, bcast); - wcn36xx_set_tx_pdu(bd, - ieee80211_is_data_qos(hdr->frame_control) ? - sizeof(struct ieee80211_qos_hdr) : - sizeof(struct ieee80211_hdr_3addr), - skb->len, sta_priv ? sta_priv->tid : 0); - } else { + if (is_low) + wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, skb, bcast); + else /* MGMT and CTRL frames are handeld here*/ - wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, hdr, bcast); - wcn36xx_set_tx_pdu(bd, - ieee80211_is_data_qos(hdr->frame_control) ? - sizeof(struct ieee80211_qos_hdr) : - sizeof(struct ieee80211_hdr_3addr), - skb->len, WCN36XX_TID); - } + wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, skb, bcast); buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32)); bd->tx_bd_sign = 0xbdbdbdbd; diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.h b/drivers/net/wireless/ath/wcn36xx/txrx.h index bbfbcf808c77..032216e82b2b 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.h +++ b/drivers/net/wireless/ath/wcn36xx/txrx.h @@ -32,6 +32,12 @@ #define WCN36XX_BD_RATE_MGMT 2 #define WCN36XX_BD_RATE_CTRL 3 +enum wcn36xx_txbd_ssn_type { + WCN36XX_TXBD_SSN_FILL_HOST = 0, + WCN36XX_TXBD_SSN_FILL_DPU_NON_QOS = 1, + WCN36XX_TXBD_SSN_FILL_DPU_QOS = 2, +}; + struct wcn36xx_pdu { u32 dpu_fb:8; u32 adu_fb:8; @@ -50,7 +56,8 @@ struct wcn36xx_pdu { /* 0x0c*/ u32 reserved4:8; u32 tid:4; - u32 reserved3:4; + u32 bd_ssn:2; + u32 reserved3:2; u32 mpdu_len:16; }; diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index f0fb81dfd17b..7b41e833e18c 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -32,6 +32,9 @@ #define WLAN_NV_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin" #define WCN36XX_AGGR_BUFFER_SIZE 64 +/* How many frames until we start a-mpdu TX session */ +#define WCN36XX_AMPDU_START_THRESH 20 + extern unsigned int wcn36xx_dbg_mask; enum wcn36xx_debug_mask { @@ -74,6 +77,13 @@ enum wcn36xx_debug_mask { buf, len, false); \ } while (0) +enum wcn36xx_ampdu_state { + WCN36XX_AMPDU_NONE, + WCN36XX_AMPDU_INIT, + WCN36XX_AMPDU_START, + WCN36XX_AMPDU_OPERATIONAL, +}; + #define WCN36XX_HW_CHANNEL(__wcn) (__wcn->hw->conf.chandef.chan->hw_value) #define WCN36XX_BAND(__wcn) (__wcn->hw->conf.chandef.chan->band) #define WCN36XX_CENTER_FREQ(__wcn) (__wcn->hw->conf.chandef.chan->center_freq) @@ -165,6 +175,10 @@ struct wcn36xx_sta { bool is_data_encrypted; /* Rates */ struct wcn36xx_hal_supported_rates supported_rates; + + spinlock_t ampdu_lock; /* protects next two fields */ + enum wcn36xx_ampdu_state ampdu_state[16]; + int non_agg_frame_ct; }; struct wcn36xx_dxe_ch; struct wcn36xx { @@ -243,4 +257,10 @@ static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn, } void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates); +static inline +struct ieee80211_sta *wcn36xx_priv_to_sta(struct wcn36xx_sta *sta_priv) +{ + return container_of((void *)sta_priv, struct ieee80211_sta, drv_priv); +} + #endif /* _WCN36XX_H_ */ diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig index 481680a3aa55..ce8c0381825e 100644 --- a/drivers/net/wireless/ath/wil6210/Kconfig +++ b/drivers/net/wireless/ath/wil6210/Kconfig @@ -39,12 +39,3 @@ config WIL6210_TRACING option if you are interested in debugging the driver. If unsure, say Y to make it easier to debug problems. - -config WIL6210_PLATFORM_MSM - bool "wil6210 MSM platform specific support" - depends on WIL6210 - depends on ARCH_MSM - default y - ---help--- - Say Y here to enable wil6210 driver support for MSM - platform specific features diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 8ad4b5f97e04..caa717bf52f3 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -14,7 +14,6 @@ wil6210-y += ioctl.o wil6210-y += fw.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o wil6210-y += wil_platform.o -wil6210-$(CONFIG_WIL6210_PLATFORM_MSM) += wil_platform_msm.o wil6210-y += ethtool.o # for tracing framework to find trace.h diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 38332a6dfb3a..2d5ea21be47e 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -142,14 +142,14 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, sinfo->generation = wil->sinfo_gen; - sinfo->filled = STATION_INFO_RX_BYTES | - STATION_INFO_TX_BYTES | - STATION_INFO_RX_PACKETS | - STATION_INFO_TX_PACKETS | - STATION_INFO_RX_BITRATE | - STATION_INFO_TX_BITRATE | - STATION_INFO_RX_DROP_MISC | - STATION_INFO_TX_FAILED; + sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) | + BIT(NL80211_STA_INFO_TX_BYTES) | + BIT(NL80211_STA_INFO_RX_PACKETS) | + BIT(NL80211_STA_INFO_TX_PACKETS) | + BIT(NL80211_STA_INFO_RX_BITRATE) | + BIT(NL80211_STA_INFO_TX_BITRATE) | + BIT(NL80211_STA_INFO_RX_DROP_MISC) | + BIT(NL80211_STA_INFO_TX_FAILED); sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs); @@ -162,8 +162,8 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, sinfo->tx_packets = stats->tx_packets; sinfo->tx_failed = stats->tx_errors; - if (test_bit(wil_status_fwconnected, &wil->status)) { - sinfo->filled |= STATION_INFO_SIGNAL; + if (test_bit(wil_status_fwconnected, wil->status)) { + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); sinfo->signal = reply.evt.sqi; } @@ -282,7 +282,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, } /* FW don't support scan after connection attempt */ - if (test_bit(wil_status_dontscan, &wil->status)) { + if (test_bit(wil_status_dontscan, wil->status)) { wil_err(wil, "Can't scan now\n"); return -EBUSY; } @@ -334,6 +334,30 @@ out: return rc; } +static void wil_print_crypto(struct wil6210_priv *wil, + struct cfg80211_crypto_settings *c) +{ + int i, n; + + wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n", + c->wpa_versions, c->cipher_group); + wil_dbg_misc(wil, "Pairwise ciphers [%d] {\n", c->n_ciphers_pairwise); + n = min_t(int, c->n_ciphers_pairwise, ARRAY_SIZE(c->ciphers_pairwise)); + for (i = 0; i < n; i++) + wil_dbg_misc(wil, " [%d] = 0x%08x\n", i, + c->ciphers_pairwise[i]); + wil_dbg_misc(wil, "}\n"); + wil_dbg_misc(wil, "AKM suites [%d] {\n", c->n_akm_suites); + n = min_t(int, c->n_akm_suites, ARRAY_SIZE(c->akm_suites)); + for (i = 0; i < n; i++) + wil_dbg_misc(wil, " [%d] = 0x%08x\n", i, + c->akm_suites[i]); + wil_dbg_misc(wil, "}\n"); + wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n", + c->control_port, be16_to_cpu(c->control_port_ethertype), + c->control_port_no_encrypt); +} + static void wil_print_connect_params(struct wil6210_priv *wil, struct cfg80211_connect_params *sme) { @@ -348,6 +372,7 @@ static void wil_print_connect_params(struct wil6210_priv *wil, print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET, 16, 1, sme->ssid, sme->ssid_len, true); wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open"); + wil_print_crypto(wil, &sme->crypto); } static int wil_cfg80211_connect(struct wiphy *wiphy, @@ -362,8 +387,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, int ch; int rc = 0; - if (test_bit(wil_status_fwconnecting, &wil->status) || - test_bit(wil_status_fwconnected, &wil->status)) + if (test_bit(wil_status_fwconnecting, wil->status) || + test_bit(wil_status_fwconnected, wil->status)) return -EALREADY; wil_print_connect_params(wil, sme); @@ -450,15 +475,16 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, memcpy(conn.bssid, bss->bssid, ETH_ALEN); memcpy(conn.dst_mac, bss->bssid, ETH_ALEN); - set_bit(wil_status_fwconnecting, &wil->status); + set_bit(wil_status_fwconnecting, wil->status); rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); if (rc == 0) { + netif_carrier_on(ndev); /* Connect can take lots of time */ mod_timer(&wil->connect_timer, jiffies + msecs_to_jiffies(2000)); } else { - clear_bit(wil_status_fwconnecting, &wil->status); + clear_bit(wil_status_fwconnecting, wil->status); } out: @@ -618,18 +644,6 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b) b->assocresp_ies, b->assocresp_ies_len); } -static void wil_print_crypto(struct wil6210_priv *wil, - struct cfg80211_crypto_settings *c) -{ - wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n", - c->wpa_versions, c->cipher_group); - wil_dbg_misc(wil, "Pairwise ciphers [%d]\n", c->n_ciphers_pairwise); - wil_dbg_misc(wil, "AKM suites [%d]\n", c->n_akm_suites); - wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n", - c->control_port, be16_to_cpu(c->control_port_ethertype), - c->control_port_no_encrypt); -} - static int wil_fix_bcon(struct wil6210_priv *wil, struct cfg80211_beacon_data *bcon) { @@ -757,12 +771,12 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil->secure_pcp = info->privacy; + netif_carrier_on(ndev); + rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, channel->hw_value); if (rc) - goto out; - - netif_carrier_on(ndev); + netif_carrier_off(ndev); out: mutex_unlock(&wil->mutex); @@ -772,23 +786,26 @@ out: static int wil_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) { - int rc, rc1; struct wil6210_priv *wil = wiphy_to_wil(wiphy); wil_dbg_misc(wil, "%s()\n", __func__); + netif_carrier_off(ndev); wil_set_recovery_state(wil, fw_recovery_idle); mutex_lock(&wil->mutex); - rc = wmi_pcp_stop(wil); + wmi_pcp_stop(wil); __wil_down(wil); - rc1 = __wil_up(wil); + __wil_up(wil); mutex_unlock(&wil->mutex); - return min(rc, rc1); + /* some functions above might fail (e.g. __wil_up). Nevertheless, we + * return success because AP has stopped + */ + return 0; } static int wil_cfg80211_del_station(struct wiphy *wiphy, @@ -804,6 +821,96 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy, return 0; } +/* probe_client handling */ +static void wil_probe_client_handle(struct wil6210_priv *wil, + struct wil_probe_client_req *req) +{ + struct net_device *ndev = wil_to_ndev(wil); + struct wil_sta_info *sta = &wil->sta[req->cid]; + /* assume STA is alive if it is still connected, + * else FW will disconnect it + */ + bool alive = (sta->status == wil_sta_connected); + + cfg80211_probe_status(ndev, sta->addr, req->cookie, alive, GFP_KERNEL); +} + +static struct list_head *next_probe_client(struct wil6210_priv *wil) +{ + struct list_head *ret = NULL; + + mutex_lock(&wil->probe_client_mutex); + + if (!list_empty(&wil->probe_client_pending)) { + ret = wil->probe_client_pending.next; + list_del(ret); + } + + mutex_unlock(&wil->probe_client_mutex); + + return ret; +} + +void wil_probe_client_worker(struct work_struct *work) +{ + struct wil6210_priv *wil = container_of(work, struct wil6210_priv, + probe_client_worker); + struct wil_probe_client_req *req; + struct list_head *lh; + + while ((lh = next_probe_client(wil)) != NULL) { + req = list_entry(lh, struct wil_probe_client_req, list); + + wil_probe_client_handle(wil, req); + kfree(req); + } +} + +void wil_probe_client_flush(struct wil6210_priv *wil) +{ + struct wil_probe_client_req *req, *t; + + wil_dbg_misc(wil, "%s()\n", __func__); + + mutex_lock(&wil->probe_client_mutex); + + list_for_each_entry_safe(req, t, &wil->probe_client_pending, list) { + list_del(&req->list); + kfree(req); + } + + mutex_unlock(&wil->probe_client_mutex); +} + +static int wil_cfg80211_probe_client(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, u64 *cookie) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil_probe_client_req *req; + int cid = wil_find_cid(wil, peer); + + wil_dbg_misc(wil, "%s(%pM => CID %d)\n", __func__, peer, cid); + + if (cid < 0) + return -ENOLINK; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->cid = cid; + req->cookie = cid; + + mutex_lock(&wil->probe_client_mutex); + list_add_tail(&req->list, &wil->probe_client_pending); + mutex_unlock(&wil->probe_client_mutex); + + *cookie = req->cookie; + queue_work(wil->wq_service, &wil->probe_client_worker); + return 0; +} + static struct cfg80211_ops wil_cfg80211_ops = { .scan = wil_cfg80211_scan, .connect = wil_cfg80211_connect, @@ -823,6 +930,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { .start_ap = wil_cfg80211_start_ap, .stop_ap = wil_cfg80211_stop_ap, .del_station = wil_cfg80211_del_station, + .probe_client = wil_cfg80211_probe_client, }; static void wil_wiphy_init(struct wiphy *wiphy) @@ -854,6 +962,7 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->cipher_suites = wil_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); wiphy->mgmt_stypes = wil_mgmt_stypes; + wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; } struct wireless_dev *wil_cfg80211_init(struct device *dev) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 4e6e14501c2f..45c3558ec804 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -50,6 +50,7 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, char _s, char _h) { void __iomem *x = wmi_addr(wil, vring->hwtail); + u32 v; seq_printf(s, "VRING %s = {\n", name); seq_printf(s, " pa = %pad\n", &vring->pa); @@ -58,10 +59,12 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, seq_printf(s, " swtail = %d\n", vring->swtail); seq_printf(s, " swhead = %d\n", vring->swhead); seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail); - if (x) - seq_printf(s, "0x%08x\n", ioread32(x)); - else + if (x) { + v = ioread32(x); + seq_printf(s, "0x%08x = %d\n", v, v); + } else { seq_puts(s, "???\n"); + } if (vring->va && (vring->size < 1025)) { uint i; @@ -101,8 +104,8 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) char name[10]; /* performance monitoring */ cycles_t now = get_cycles(); - cycles_t idle = txdata->idle * 100; - cycles_t total = now - txdata->begin; + uint64_t idle = txdata->idle * 100; + uint64_t total = now - txdata->begin; do_div(idle, total); txdata->begin = now; @@ -110,9 +113,12 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) snprintf(name, sizeof(name), "tx_%2d", i); - seq_printf(s, "\n%pM CID %d TID %d [%3d|%3d] idle %3d%%\n", - wil->sta[cid].addr, cid, tid, used, avail, - (int)idle); + seq_printf(s, + "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %3d%%\n", + wil->sta[cid].addr, cid, tid, + txdata->agg_wsize, txdata->agg_timeout, + txdata->agg_amsdu ? "+" : "-", + used, avail, (int)idle); wil_print_vring(s, wil, name, vring, '_', 'H'); } @@ -384,24 +390,67 @@ static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil, return 0; } -static const struct dbg_off itr_cnt_off[] = { +static const struct dbg_off lgc_itr_cnt_off[] = { {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32}, {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32}, {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32}, {}, }; +static const struct dbg_off tx_itr_cnt_off[] = { + {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH), + doff_io32}, + {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA), + doff_io32}, + {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL), + doff_io32}, + {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH), + doff_io32}, + {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA), + doff_io32}, + {"IDL_CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL), + doff_io32}, + {}, +}; + +static const struct dbg_off rx_itr_cnt_off[] = { + {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH), + doff_io32}, + {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA), + doff_io32}, + {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL), + doff_io32}, + {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH), + doff_io32}, + {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA), + doff_io32}, + {"IDL_CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL), + doff_io32}, + {}, +}; + static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil, struct dentry *parent) { - struct dentry *d = debugfs_create_dir("ITR_CNT", parent); + struct dentry *d, *dtx, *drx; + d = debugfs_create_dir("ITR_CNT", parent); if (IS_ERR_OR_NULL(d)) return -ENODEV; - wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr, - itr_cnt_off); + dtx = debugfs_create_dir("TX", d); + drx = debugfs_create_dir("RX", d); + if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx)) + return -ENODEV; + wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr, + lgc_itr_cnt_off); + + wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr, + tx_itr_cnt_off); + + wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr, + rx_itr_cnt_off); return 0; } @@ -558,6 +607,87 @@ static const struct file_operations fops_rxon = { .open = simple_open, }; +/* block ack control, write: + * - "add " to trigger ADDBA + * - "del_tx " to trigger DELBA for Tx side + * - "del_rx " to trigger DELBA for Rx side + */ +static ssize_t wil_write_back(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + int rc; + char *kbuf = kmalloc(len + 1, GFP_KERNEL); + char cmd[8]; + int p1, p2, p3; + + if (!kbuf) + return -ENOMEM; + + rc = simple_write_to_buffer(kbuf, len, ppos, buf, len); + if (rc != len) { + kfree(kbuf); + return rc >= 0 ? -EIO : rc; + } + + kbuf[len] = '\0'; + rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3); + kfree(kbuf); + + if (rc < 0) + return rc; + if (rc < 2) + return -EINVAL; + + if (0 == strcmp(cmd, "add")) { + if (rc < 3) { + wil_err(wil, "BACK: add require at least 2 params\n"); + return -EINVAL; + } + if (rc < 4) + p3 = 0; + wmi_addba(wil, p1, p2, p3); + } else if (0 == strcmp(cmd, "del_tx")) { + if (rc < 3) + p2 = WLAN_REASON_QSTA_LEAVE_QBSS; + wmi_delba_tx(wil, p1, p2); + } else if (0 == strcmp(cmd, "del_rx")) { + if (rc < 3) { + wil_err(wil, + "BACK: del_rx require at least 2 params\n"); + return -EINVAL; + } + if (rc < 4) + p3 = WLAN_REASON_QSTA_LEAVE_QBSS; + wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3); + } else { + wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd); + return -EINVAL; + } + + return len; +} + +static ssize_t wil_read_back(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + static const char text[] = "block ack control, write:\n" + " - \"add \" to trigger ADDBA\n" + "If missing, defaults to 0\n" + " - \"del_tx \" to trigger DELBA for Tx side\n" + " - \"del_rx \" to trigger DELBA for Rx side\n" + "If missing, set to \"STA_LEAVING\" (36)\n"; + + return simple_read_from_buffer(user_buf, count, ppos, text, + sizeof(text)); +} + +static const struct file_operations fops_back = { + .read = wil_read_back, + .write = wil_write_back, + .open = simple_open, +}; + /*---tx_mgmt---*/ /* Write mgmt frame to this file to send it */ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, @@ -1116,7 +1246,8 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) int i; u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; - seq_printf(s, "0x%03x [", r->head_seq_num); + seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout, + r->head_seq_num); for (i = 0; i < r->buf_size; i++) { if (i == index) seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|'); @@ -1127,10 +1258,10 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) } static int wil_sta_debugfs_show(struct seq_file *s, void *data) +__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) { struct wil6210_priv *wil = s->private; int i, tid; - unsigned long flags; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { struct wil_sta_info *p = &wil->sta[i]; @@ -1151,7 +1282,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) (p->data_port_open ? " data_port_open" : "")); if (p->status == wil_sta_connected) { - spin_lock_irqsave(&p->tid_rx_lock, flags); + spin_lock_bh(&p->tid_rx_lock); for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { struct wil_tid_ampdu_rx *r = p->tid_rx[tid]; @@ -1160,7 +1291,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) wil_print_rxtid(s, r); } } - spin_unlock_irqrestore(&p->tid_rx_lock, flags); + spin_unlock_bh(&p->tid_rx_lock); } } @@ -1217,6 +1348,7 @@ static const struct { {"rxon", S_IWUSR, &fops_rxon}, {"tx_mgmt", S_IWUSR, &fops_txmgmt}, {"wmi_send", S_IWUSR, &fops_wmi}, + {"back", S_IRUGO | S_IWUSR, &fops_back}, {"temp", S_IRUGO, &fops_temp}, {"freq", S_IRUGO, &fops_freq}, {"link", S_IRUGO, &fops_link}, @@ -1261,7 +1393,7 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil, /* fields in struct wil6210_priv */ static const struct dbg_off dbg_wil_off[] = { WIL_FIELD(secure_pcp, S_IRUGO | S_IWUSR, doff_u32), - WIL_FIELD(status, S_IRUGO | S_IWUSR, doff_ulong), + WIL_FIELD(status[0], S_IRUGO | S_IWUSR, doff_ulong), WIL_FIELD(fw_version, S_IRUGO, doff_u32), WIL_FIELD(hw_version, S_IRUGO, doff_x32), WIL_FIELD(recovery_count, S_IRUGO, doff_u32), diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c index d686638972be..4c44a82c34d7 100644 --- a/drivers/net/wireless/ath/wil6210/ethtool.c +++ b/drivers/net/wireless/ath/wil6210/ethtool.c @@ -45,16 +45,35 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *cp) { struct wil6210_priv *wil = ndev_to_wil(ndev); - u32 itr_en, itr_val = 0; + u32 tx_itr_en, tx_itr_val = 0; + u32 rx_itr_en, rx_itr_val = 0; wil_dbg_misc(wil, "%s()\n", __func__); - itr_en = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); - if (itr_en & BIT_DMA_ITR_CNT_CRL_EN) - itr_val = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); + if (test_bit(hw_capability_advanced_itr_moderation, + wil->hw_capabilities)) { + tx_itr_en = ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL)); + if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) + tx_itr_val = + ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH)); - cp->rx_coalesce_usecs = itr_val; + rx_itr_en = ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL)); + if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) + rx_itr_val = + ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH)); + } else { + rx_itr_en = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); + if (rx_itr_en & BIT_DMA_ITR_CNT_CRL_EN) + rx_itr_val = ioread32(wil->csr + + HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); + } + cp->tx_coalesce_usecs = tx_itr_val; + cp->rx_coalesce_usecs = rx_itr_val; return 0; } @@ -63,22 +82,25 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev, { struct wil6210_priv *wil = ndev_to_wil(ndev); - wil_dbg_misc(wil, "%s(%d usec)\n", __func__, cp->rx_coalesce_usecs); + wil_dbg_misc(wil, "%s(rx %d usec, tx %d usec)\n", __func__, + cp->rx_coalesce_usecs, cp->tx_coalesce_usecs); if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n"); return -EINVAL; } - /* only @rx_coalesce_usecs supported, ignore - * other parameters + /* only @rx_coalesce_usecs and @tx_coalesce_usecs supported, + * ignore other parameters */ - if (cp->rx_coalesce_usecs > WIL6210_ITR_TRSH_MAX) + if (cp->rx_coalesce_usecs > WIL6210_ITR_TRSH_MAX || + cp->tx_coalesce_usecs > WIL6210_ITR_TRSH_MAX) goto out_bad; - wil->itr_trsh = cp->rx_coalesce_usecs; - wil_set_itr_trsh(wil); + wil->tx_max_burst_duration = cp->tx_coalesce_usecs; + wil->rx_max_burst_duration = cp->rx_coalesce_usecs; + wil_configure_interrupt_moderation(wil); return 0; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 4bcbd6297b3e..a6f923086f31 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -102,7 +102,7 @@ static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) iowrite32(WIL6210_IRQ_DISABLE, wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); - clear_bit(wil_status_irqen, &wil->status); + clear_bit(wil_status_irqen, wil->status); } void wil6210_unmask_irq_tx(struct wil6210_priv *wil) @@ -130,7 +130,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) { wil_dbg_irq(wil, "%s()\n", __func__); - set_bit(wil_status_irqen, &wil->status); + set_bit(wil_status_irqen, wil->status); iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); @@ -157,15 +157,91 @@ void wil_unmask_irq(struct wil6210_priv *wil) iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICC)); - /* interrupt moderation parameters */ - wil_set_itr_trsh(wil); - wil6210_unmask_irq_pseudo(wil); wil6210_unmask_irq_tx(wil); wil6210_unmask_irq_rx(wil); wil6210_unmask_irq_misc(wil); } +/* target write operation */ +#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) + +static +void wil_configure_interrupt_moderation_new(struct wil6210_priv *wil) +{ + /* Disable and clear tx counter before (re)configuration */ + W(RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR); + W(RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration); + wil_info(wil, "set ITR_TX_CNT_TRSH = %d usec\n", + wil->tx_max_burst_duration); + /* Configure TX max burst duration timer to use usec units */ + W(RGF_DMA_ITR_TX_CNT_CTL, + BIT_DMA_ITR_TX_CNT_CTL_EN | BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL); + + /* Disable and clear tx idle counter before (re)configuration */ + W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR); + W(RGF_DMA_ITR_TX_IDL_CNT_TRSH, wil->tx_interframe_timeout); + wil_info(wil, "set ITR_TX_IDL_CNT_TRSH = %d usec\n", + wil->tx_interframe_timeout); + /* Configure TX max burst duration timer to use usec units */ + W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_EN | + BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL); + + /* Disable and clear rx counter before (re)configuration */ + W(RGF_DMA_ITR_RX_CNT_CTL, BIT_DMA_ITR_RX_CNT_CTL_CLR); + W(RGF_DMA_ITR_RX_CNT_TRSH, wil->rx_max_burst_duration); + wil_info(wil, "set ITR_RX_CNT_TRSH = %d usec\n", + wil->rx_max_burst_duration); + /* Configure TX max burst duration timer to use usec units */ + W(RGF_DMA_ITR_RX_CNT_CTL, + BIT_DMA_ITR_RX_CNT_CTL_EN | BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL); + + /* Disable and clear rx idle counter before (re)configuration */ + W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR); + W(RGF_DMA_ITR_RX_IDL_CNT_TRSH, wil->rx_interframe_timeout); + wil_info(wil, "set ITR_RX_IDL_CNT_TRSH = %d usec\n", + wil->rx_interframe_timeout); + /* Configure TX max burst duration timer to use usec units */ + W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_EN | + BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL); +} + +static +void wil_configure_interrupt_moderation_lgc(struct wil6210_priv *wil) +{ + /* disable, use usec resolution */ + W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_CLR); + + wil_info(wil, "set ITR_TRSH = %d usec\n", wil->rx_max_burst_duration); + W(RGF_DMA_ITR_CNT_TRSH, wil->rx_max_burst_duration); + /* start it */ + W(RGF_DMA_ITR_CNT_CRL, + BIT_DMA_ITR_CNT_CRL_EN | BIT_DMA_ITR_CNT_CRL_EXT_TICK); +} + +#undef W + +void wil_configure_interrupt_moderation(struct wil6210_priv *wil) +{ + wil_dbg_irq(wil, "%s()\n", __func__); + + /* disable interrupt moderation for monitor + * to get better timestamp precision + */ + if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) + return; + + if (test_bit(hw_capability_advanced_itr_moderation, + wil->hw_capabilities)) + wil_configure_interrupt_moderation_new(wil); + else { + /* Advanced interrupt moderation is not available before + * Sparrow v2. Will use legacy interrupt moderation + */ + wil_configure_interrupt_moderation_lgc(wil); + } +} + static irqreturn_t wil6210_irq_rx(int irq, void *cookie) { struct wil6210_priv *wil = cookie; @@ -194,18 +270,19 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) wil_dbg_irq(wil, "RX done\n"); if (isr & BIT_DMA_EP_RX_ICR_RX_HTRSH) - wil_err_ratelimited(wil, "Received \"Rx buffer is in risk " - "of overflow\" interrupt\n"); + wil_err_ratelimited(wil, + "Received \"Rx buffer is in risk of overflow\" interrupt\n"); - isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH); - if (test_bit(wil_status_reset_done, &wil->status)) { - if (test_bit(wil_status_napi_en, &wil->status)) { + isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | + BIT_DMA_EP_RX_ICR_RX_HTRSH); + if (test_bit(wil_status_reset_done, wil->status)) { + if (test_bit(wil_status_napi_en, wil->status)) { wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); need_unmask = false; napi_schedule(&wil->napi_rx); } else { - wil_err(wil, "Got Rx interrupt while " - "stopping interface\n"); + wil_err(wil, + "Got Rx interrupt while stopping interface\n"); } } else { wil_err(wil, "Got Rx interrupt while in reset\n"); @@ -248,7 +325,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; /* clear also all VRING interrupts */ isr &= ~(BIT(25) - 1UL); - if (test_bit(wil_status_reset_done, &wil->status)) { + if (test_bit(wil_status_reset_done, wil->status)) { wil_dbg_txrx(wil, "NAPI(Tx) schedule\n"); need_unmask = false; napi_schedule(&wil->napi_tx); @@ -310,7 +387,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) if (isr & ISR_MISC_FW_ERROR) { wil_err(wil, "Firmware error detected\n"); - clear_bit(wil_status_fwready, &wil->status); + clear_bit(wil_status_fwready, wil->status); /* * do not clear @isr here - we do 2-nd part in thread * there, user space get notified, and it should be done @@ -321,7 +398,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) if (isr & ISR_MISC_FW_READY) { wil_dbg_irq(wil, "IRQ: FW ready\n"); wil_cache_mbox_regs(wil); - set_bit(wil_status_reset_done, &wil->status); + set_bit(wil_status_reset_done, wil->status); /** * Actual FW ready indicated by the * WMI_FW_READY_EVENTID @@ -394,7 +471,7 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie) */ static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause) { - if (!test_bit(wil_status_irqen, &wil->status)) { + if (!test_bit(wil_status_irqen, wil->status)) { u32 icm_rx = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + offsetof(struct RGF_ICR, ICM)); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 8ff3fe34fe05..b04e0afdcb21 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -33,15 +33,18 @@ static bool no_fw_load = true; module_param(no_fw_load, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash."); -static unsigned int itr_trsh = WIL6210_ITR_TRSH_DEFAULT; - -module_param(itr_trsh, uint, S_IRUGO); -MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs."); +/* if not set via modparam, will be set to default value of 1/8 of + * rx ring size during init flow + */ +unsigned short rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_INIT; +module_param(rx_ring_overflow_thrsh, ushort, S_IRUGO); +MODULE_PARM_DESC(rx_ring_overflow_thrsh, + " RX ring overflow threshold in descriptors."); /* We allow allocation of more than 1 page buffers to support large packets. * It is suboptimal behavior performance wise in case MTU above page size. */ -unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - ETH_HLEN; +unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD; static int mtu_max_set(const char *val, const struct kernel_param *kp) { int ret; @@ -53,7 +56,7 @@ static int mtu_max_set(const char *val, const struct kernel_param *kp) if (ret) return ret; - if (mtu_max < 68 || mtu_max > IEEE80211_MAX_DATA_LEN_DMG) + if (mtu_max < 68 || mtu_max > WIL_MAX_ETH_MTU) ret = -EINVAL; return ret; @@ -135,12 +138,14 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, static void wil_disconnect_cid(struct wil6210_priv *wil, int cid, u16 reason_code, bool from_event) +__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { uint i; struct net_device *ndev = wil_to_ndev(wil); struct wireless_dev *wdev = wil->wdev; struct wil_sta_info *sta = &wil->sta[cid]; + might_sleep(); wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid, sta->status); @@ -163,15 +168,14 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid, for (i = 0; i < WIL_STA_TID_NUM; i++) { struct wil_tid_ampdu_rx *r; - unsigned long flags; - spin_lock_irqsave(&sta->tid_rx_lock, flags); + spin_lock_bh(&sta->tid_rx_lock); r = sta->tid_rx[i]; sta->tid_rx[i] = NULL; wil_tid_ampdu_rx_free(wil, r); - spin_unlock_irqrestore(&sta->tid_rx_lock, flags); + spin_unlock_bh(&sta->tid_rx_lock); } for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { if (wil->vring2cid_tid[i][0] == cid) @@ -188,34 +192,47 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, struct wireless_dev *wdev = wil->wdev; might_sleep(); - if (bssid) { - cid = wil_find_cid(wil, bssid); - wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid); - } else { - wil_dbg_misc(wil, "%s(all)\n", __func__); - } + wil_dbg_misc(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid, + reason_code, from_event ? "+" : "-"); - if (cid >= 0) /* disconnect 1 peer */ - wil_disconnect_cid(wil, cid, reason_code, from_event); - else /* disconnect all */ + /* Cases are: + * - disconnect single STA, still connected + * - disconnect single STA, already disconnected + * - disconnect all + * + * For "disconnect all", there are 2 options: + * - bssid == NULL + * - bssid is our MAC address + */ + if (bssid && memcmp(ndev->dev_addr, bssid, ETH_ALEN)) { + cid = wil_find_cid(wil, bssid); + wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n", + bssid, cid, reason_code); + if (cid >= 0) /* disconnect 1 peer */ + wil_disconnect_cid(wil, cid, reason_code, from_event); + } else { /* all */ + wil_dbg_misc(wil, "Disconnect all\n"); for (cid = 0; cid < WIL6210_MAX_CID; cid++) wil_disconnect_cid(wil, cid, reason_code, from_event); + } /* link state */ switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - wil_link_off(wil); - if (test_bit(wil_status_fwconnected, &wil->status)) { - clear_bit(wil_status_fwconnected, &wil->status); + netif_tx_stop_all_queues(ndev); + netif_carrier_off(ndev); + + if (test_bit(wil_status_fwconnected, wil->status)) { + clear_bit(wil_status_fwconnected, wil->status); cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL); - } else if (test_bit(wil_status_fwconnecting, &wil->status)) { + } else if (test_bit(wil_status_fwconnecting, wil->status)) { cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL); } - clear_bit(wil_status_fwconnecting, &wil->status); + clear_bit(wil_status_fwconnecting, wil->status); break; default: break; @@ -248,7 +265,7 @@ static void wil_scan_timer_fn(ulong x) { struct wil6210_priv *wil = (void *)x; - clear_bit(wil_status_fwready, &wil->status); + clear_bit(wil_status_fwready, wil->status); wil_err(wil, "Scan timeout detected, start fw error recovery\n"); wil->recovery_state = fw_recovery_pending; schedule_work(&wil->fw_error_worker); @@ -352,6 +369,8 @@ static void wil_connect_worker(struct work_struct *work) int rc; struct wil6210_priv *wil = container_of(work, struct wil6210_priv, connect_worker); + struct net_device *ndev = wil_to_ndev(wil); + int cid = wil->pending_connect_cid; int ringid = wil_find_free_vring(wil); @@ -366,7 +385,7 @@ static void wil_connect_worker(struct work_struct *work) wil->pending_connect_cid = -1; if (rc == 0) { wil->sta[cid].status = wil_sta_connected; - wil_link_on(wil); + netif_tx_wake_all_queues(ndev); } else { wil->sta[cid].status = wil_sta_unused; } @@ -384,6 +403,9 @@ int wil_priv_init(struct wil6210_priv *wil) mutex_init(&wil->mutex); mutex_init(&wil->wmi_mutex); + mutex_init(&wil->back_rx_mutex); + mutex_init(&wil->back_tx_mutex); + mutex_init(&wil->probe_client_mutex); init_completion(&wil->wmi_ready); init_completion(&wil->wmi_call); @@ -396,25 +418,39 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker); INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); + INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker); + INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker); + INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker); INIT_LIST_HEAD(&wil->pending_wmi_ev); + INIT_LIST_HEAD(&wil->back_rx_pending); + INIT_LIST_HEAD(&wil->back_tx_pending); + INIT_LIST_HEAD(&wil->probe_client_pending); spin_lock_init(&wil->wmi_ev_lock); init_waitqueue_head(&wil->wq); - wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi"); + wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi"); if (!wil->wmi_wq) return -EAGAIN; - wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect"); - if (!wil->wmi_wq_conn) { - destroy_workqueue(wil->wmi_wq); - return -EAGAIN; - } + wil->wq_service = create_singlethread_workqueue(WIL_NAME "_service"); + if (!wil->wq_service) + goto out_wmi_wq; wil->last_fw_recovery = jiffies; - wil->itr_trsh = itr_trsh; + wil->tx_interframe_timeout = WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT; + wil->rx_interframe_timeout = WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT; + wil->tx_max_burst_duration = WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT; + wil->rx_max_burst_duration = WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT; + if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT) + rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT; return 0; + +out_wmi_wq: + destroy_workqueue(wil->wmi_wq); + + return -EAGAIN; } /** @@ -448,7 +484,13 @@ void wil_priv_deinit(struct wil6210_priv *wil) wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); mutex_unlock(&wil->mutex); wmi_event_flush(wil); - destroy_workqueue(wil->wmi_wq_conn); + wil_back_rx_flush(wil); + cancel_work_sync(&wil->back_rx_worker); + wil_back_tx_flush(wil); + cancel_work_sync(&wil->back_tx_worker); + wil_probe_client_flush(wil); + cancel_work_sync(&wil->probe_client_worker); + destroy_workqueue(wil->wq_service); destroy_workqueue(wil->wmi_wq); } @@ -478,13 +520,10 @@ static int wil_target_reset(struct wil6210_priv *wil) { int delay = 0; u32 x; - u32 rev_id; - bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW); + bool is_reset_v2 = test_bit(hw_capability_reset_v2, + wil->hw_capabilities); - wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name); - - wil->hw_version = R(RGF_USER_FW_REV_ID); - rev_id = wil->hw_version & 0xff; + wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name); /* Clear MAC link up */ S(RGF_HP_CTRL, BIT(15)); @@ -496,7 +535,7 @@ static int wil_target_reset(struct wil6210_priv *wil) /* Clear Fw Download notification */ C(RGF_USER_USAGE_6, BIT(0)); - if (is_sparrow) { + if (is_reset_v2) { S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); /* XTAL stabilization should take about 3ms */ usleep_range(5000, 7000); @@ -517,10 +556,11 @@ static int wil_target_reset(struct wil6210_priv *wil) W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, + is_reset_v2 ? 0x000000f0 : 0x00000170); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00); - if (is_sparrow) { + if (is_reset_v2) { W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); } @@ -530,19 +570,14 @@ static int wil_target_reset(struct wil6210_priv *wil) W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - if (is_sparrow) { + if (is_reset_v2) { W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); /* reset A2 PCIE AHB */ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); } else { W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); - if (rev_id == 1) { - /* reset A1 BOTH PCIE AHB & PCIE RGF */ - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); - } else { - W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); - } + W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8)); + W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); } /* TODO: check order here!!! Erez code is different */ @@ -559,8 +594,7 @@ static int wil_target_reset(struct wil6210_priv *wil) } } while (x != HW_MACHINE_BOOT_DONE); - /* TODO: Erez check rev_id != 1 */ - if (!is_sparrow && (rev_id != 1)) + if (!is_reset_v2) W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8)); C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); @@ -569,26 +603,6 @@ static int wil_target_reset(struct wil6210_priv *wil) return 0; } -/** - * wil_set_itr_trsh: - apply interrupt coalescing params - */ -void wil_set_itr_trsh(struct wil6210_priv *wil) -{ - /* disable, use usec resolution */ - W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_EXT_TICK); - - /* disable interrupt moderation for monitor - * to get better timestamp precision - */ - if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) - return; - - wil_info(wil, "set ITR_TRSH = %d usec\n", wil->itr_trsh); - W(RGF_DMA_ITR_CNT_TRSH, wil->itr_trsh); - W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_EN | - BIT_DMA_ITR_CNT_CRL_EXT_TICK); /* start it */ -} - #undef R #undef W #undef S @@ -629,13 +643,17 @@ int wil_reset(struct wil6210_priv *wil) wil_dbg_misc(wil, "%s()\n", __func__); + if (wil->hw_version == HW_VER_UNKNOWN) + return -ENODEV; + WARN_ON(!mutex_is_locked(&wil->mutex)); - WARN_ON(test_bit(wil_status_napi_en, &wil->status)); + WARN_ON(test_bit(wil_status_napi_en, wil->status)); cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); - wil->status = 0; /* prevent NAPI from being scheduled */ + /* prevent NAPI from being scheduled */ + bitmap_zero(wil->status, wil_status_last); if (wil->scan_request) { wil_dbg_misc(wil, "Abort scan_request 0x%p\n", @@ -649,7 +667,7 @@ int wil_reset(struct wil6210_priv *wil) wmi_event_flush(wil); - flush_workqueue(wil->wmi_wq_conn); + flush_workqueue(wil->wq_service); flush_workqueue(wil->wmi_wq); rc = wil_target_reset(wil); @@ -688,6 +706,7 @@ int wil_reset(struct wil6210_priv *wil) reinit_completion(&wil->wmi_ready); reinit_completion(&wil->wmi_call); + wil_configure_interrupt_moderation(wil); wil_unmask_irq(wil); /* we just started MAC, wait for FW ready */ @@ -703,28 +722,6 @@ void wil_fw_error_recovery(struct wil6210_priv *wil) schedule_work(&wil->fw_error_worker); } -void wil_link_on(struct wil6210_priv *wil) -{ - struct net_device *ndev = wil_to_ndev(wil); - - wil_dbg_misc(wil, "%s()\n", __func__); - - netif_carrier_on(ndev); - wil_dbg_misc(wil, "netif_tx_wake : link on\n"); - netif_tx_wake_all_queues(ndev); -} - -void wil_link_off(struct wil6210_priv *wil) -{ - struct net_device *ndev = wil_to_ndev(wil); - - wil_dbg_misc(wil, "%s()\n", __func__); - - netif_tx_stop_all_queues(ndev); - wil_dbg_misc(wil, "netif_tx_stop : link off\n"); - netif_carrier_off(ndev); -} - int __wil_up(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); @@ -774,7 +771,7 @@ int __wil_up(struct wil6210_priv *wil) wil_dbg_misc(wil, "NAPI enable\n"); napi_enable(&wil->napi_rx); napi_enable(&wil->napi_tx); - set_bit(wil_status_napi_en, &wil->status); + set_bit(wil_status_napi_en, wil->status); if (wil->platform_ops.bus_request) wil->platform_ops.bus_request(wil->platform_handle, @@ -807,7 +804,7 @@ int __wil_down(struct wil6210_priv *wil) wil->platform_ops.bus_request(wil->platform_handle, 0); wil_disable_irq(wil); - if (test_and_clear_bit(wil_status_napi_en, &wil->status)) { + if (test_and_clear_bit(wil_status_napi_en, wil->status)) { napi_disable(&wil->napi_rx); napi_disable(&wil->napi_tx); wil_dbg_misc(wil, "NAPI disable\n"); @@ -822,15 +819,15 @@ int __wil_down(struct wil6210_priv *wil) wil->scan_request = NULL; } - if (test_bit(wil_status_fwconnected, &wil->status) || - test_bit(wil_status_fwconnecting, &wil->status)) + if (test_bit(wil_status_fwconnected, wil->status) || + test_bit(wil_status_fwconnecting, wil->status)) wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0); /* make sure wil is idle (not connected) */ mutex_unlock(&wil->mutex); while (iter--) { - int idle = !test_bit(wil_status_fwconnected, &wil->status) && - !test_bit(wil_status_fwconnecting, &wil->status); + int idle = !test_bit(wil_status_fwconnected, wil->status) && + !test_bit(wil_status_fwconnecting, wil->status); if (idle) break; msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS); diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index e81703ca7701..ace30c1b5c64 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,7 +15,6 @@ */ #include - #include "wil6210.h" #include "txrx.h" @@ -122,6 +121,12 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) return min(tx_done, budget); } +static void wil_dev_setup(struct net_device *dev) +{ + ether_setup(dev); + dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT; +} + void *wil_if_alloc(struct device *dev, void __iomem *csr) { struct net_device *ndev; @@ -153,7 +158,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); - ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, ether_setup); + ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup); if (!ndev) { dev_err(dev, "alloc_netdev_mqs failed\n"); rc = -ENOMEM; @@ -174,7 +179,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) netif_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx, WIL6210_NAPI_BUDGET); - wil_link_off(wil); + netif_tx_stop_all_queues(ndev); return wil; @@ -217,8 +222,6 @@ int wil_if_add(struct wil6210_priv *wil) return rc; } - wil_link_off(wil); - return 0; } diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 66626a8ee728..3dd26709ccb2 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -31,6 +31,46 @@ static bool debug_fw; /* = false; */ module_param(debug_fw, bool, S_IRUGO); MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug"); +static +void wil_set_capabilities(struct wil6210_priv *wil) +{ + u32 rev_id = ioread32(wil->csr + HOSTADDR(RGF_USER_JTAG_DEV_ID)); + + bitmap_zero(wil->hw_capabilities, hw_capability_last); + + switch (rev_id) { + case JTAG_DEV_ID_MARLON_B0: + wil->hw_name = "Marlon B0"; + wil->hw_version = HW_VER_MARLON_B0; + break; + case JTAG_DEV_ID_SPARROW_A0: + wil->hw_name = "Sparrow A0"; + wil->hw_version = HW_VER_SPARROW_A0; + break; + case JTAG_DEV_ID_SPARROW_A1: + wil->hw_name = "Sparrow A1"; + wil->hw_version = HW_VER_SPARROW_A1; + break; + case JTAG_DEV_ID_SPARROW_B0: + wil->hw_name = "Sparrow B0"; + wil->hw_version = HW_VER_SPARROW_B0; + break; + default: + wil_err(wil, "Unknown board hardware 0x%08x\n", rev_id); + wil->hw_name = "Unknown"; + wil->hw_version = HW_VER_UNKNOWN; + } + + wil_info(wil, "Board hardware is %s\n", wil->hw_name); + + if (wil->hw_version >= HW_VER_SPARROW_A0) + set_bit(hw_capability_reset_v2, wil->hw_capabilities); + + if (wil->hw_version >= HW_VER_SPARROW_B0) + set_bit(hw_capability_advanced_itr_moderation, + wil->hw_capabilities); +} + void wil_disable_irq(struct wil6210_priv *wil) { int irq = wil->pdev->irq; @@ -149,12 +189,11 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct wil6210_priv *wil; struct device *dev = &pdev->dev; void __iomem *csr; - struct wil_board *board = (struct wil_board *)id->driver_data; int rc; /* check HW */ dev_info(&pdev->dev, WIL_NAME - " \"%s\" device found [%04x:%04x] (rev %x)\n", board->name, + " device found [%04x:%04x] (rev %x)\n", (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) { @@ -204,8 +243,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, wil); wil->pdev = pdev; - wil->board = board; - + wil_set_capabilities(wil); wil6210_clear_irq(wil); wil->platform_handle = @@ -266,23 +304,10 @@ static void wil_pcie_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static const struct wil_board wil_board_marlon = { - .board = WIL_BOARD_MARLON, - .name = "marlon", -}; - -static const struct wil_board wil_board_sparrow = { - .board = WIL_BOARD_SPARROW, - .name = "sparrow", -}; - static const struct pci_device_id wil6210_pcie_ids[] = { - { PCI_DEVICE(0x1ae9, 0x0301), - .driver_data = (kernel_ulong_t)&wil_board_marlon }, - { PCI_DEVICE(0x1ae9, 0x0310), - .driver_data = (kernel_ulong_t)&wil_board_sparrow }, - { PCI_DEVICE(0x1ae9, 0x0302), /* same as above, firmware broken */ - .driver_data = (kernel_ulong_t)&wil_board_sparrow }, + { PCI_DEVICE(0x1ae9, 0x0301) }, + { PCI_DEVICE(0x1ae9, 0x0310) }, + { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */ { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 489cb73d139b..ca10dcf0986e 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. + * Copyright (c) 2014-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -89,7 +89,9 @@ static void wil_reorder_release(struct wil6210_priv *wil, } } +/* called in NAPI context */ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) +__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { struct net_device *ndev = wil_to_ndev(wil); struct vring_rx_desc *d = wil_skb_rxdesc(skb); @@ -97,22 +99,26 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) int cid = wil_rxdesc_cid(d); int mid = wil_rxdesc_mid(d); u16 seq = wil_rxdesc_seq(d); + int mcast = wil_rxdesc_mcast(d); struct wil_sta_info *sta = &wil->sta[cid]; struct wil_tid_ampdu_rx *r; u16 hseq; int index; - unsigned long flags; - wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n", - mid, cid, tid, seq); + wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n", + mid, cid, tid, seq, mcast); - spin_lock_irqsave(&sta->tid_rx_lock, flags); + if (unlikely(mcast)) { + wil_netif_rx_any(skb, ndev); + return; + } + + spin_lock(&sta->tid_rx_lock); r = sta->tid_rx[tid]; if (!r) { - spin_unlock_irqrestore(&sta->tid_rx_lock, flags); wil_netif_rx_any(skb, ndev); - return; + goto out; } hseq = r->head_seq_num; @@ -121,13 +127,24 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) * reported, and data Rx, few packets may be pass up before reorder * buffer get allocated. Catch up by pretending SSN is what we * see in the 1-st Rx packet + * + * Another scenario, Rx get delayed and we got packet from before + * BACK. Pass it to the stack and wait. */ if (r->first_time) { r->first_time = false; if (seq != r->head_seq_num) { - wil_err(wil, "Error: 1-st frame with wrong sequence" - " %d, should be %d. Fixing...\n", seq, - r->head_seq_num); + if (seq_less(seq, r->head_seq_num)) { + wil_err(wil, + "Error: frame with early sequence 0x%03x, should be 0x%03x. Waiting...\n", + seq, r->head_seq_num); + r->first_time = true; + wil_netif_rx_any(skb, ndev); + goto out; + } + wil_err(wil, + "Error: 1-st frame with wrong sequence 0x%03x, should be 0x%03x. Fixing...\n", + seq, r->head_seq_num); r->head_seq_num = seq; r->ssn = seq; } @@ -179,7 +196,7 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) wil_reorder_release(wil, r); out: - spin_unlock_irqrestore(&sta->tid_rx_lock, flags); + spin_unlock(&sta->tid_rx_lock); } struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, @@ -219,3 +236,241 @@ void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, kfree(r->reorder_time); kfree(r); } + +/* ADDBA processing */ +static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize) +{ + u16 max_agg_size = min_t(u16, WIL_MAX_AGG_WSIZE, WIL_MAX_AMPDU_SIZE / + (mtu_max + WIL_MAX_MPDU_OVERHEAD)); + + if (!req_agg_wsize) + return max_agg_size; + + return min(max_agg_size, req_agg_wsize); +} + +/* Block Ack - Rx side (recipient */ +int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, + u8 dialog_token, __le16 ba_param_set, + __le16 ba_timeout, __le16 ba_seq_ctrl) +{ + struct wil_back_rx *req = kzalloc(sizeof(*req), GFP_KERNEL); + + if (!req) + return -ENOMEM; + + req->cidxtid = cidxtid; + req->dialog_token = dialog_token; + req->ba_param_set = le16_to_cpu(ba_param_set); + req->ba_timeout = le16_to_cpu(ba_timeout); + req->ba_seq_ctrl = le16_to_cpu(ba_seq_ctrl); + + mutex_lock(&wil->back_rx_mutex); + list_add_tail(&req->list, &wil->back_rx_pending); + mutex_unlock(&wil->back_rx_mutex); + + queue_work(wil->wq_service, &wil->back_rx_worker); + + return 0; +} + +static void wil_back_rx_handle(struct wil6210_priv *wil, + struct wil_back_rx *req) +__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) +{ + struct wil_sta_info *sta; + u8 cid, tid; + u16 agg_wsize = 0; + /* bit 0: A-MSDU supported + * bit 1: policy (should be 0 for us) + * bits 2..5: TID + * bits 6..15: buffer size + */ + u16 req_agg_wsize = WIL_GET_BITS(req->ba_param_set, 6, 15); + bool agg_amsdu = !!(req->ba_param_set & BIT(0)); + int ba_policy = req->ba_param_set & BIT(1); + u16 agg_timeout = req->ba_timeout; + u16 status = WLAN_STATUS_SUCCESS; + u16 ssn = req->ba_seq_ctrl >> 4; + struct wil_tid_ampdu_rx *r; + int rc; + + might_sleep(); + parse_cidxtid(req->cidxtid, &cid, &tid); + + /* sanity checks */ + if (cid >= WIL6210_MAX_CID) { + wil_err(wil, "BACK: invalid CID %d\n", cid); + return; + } + + sta = &wil->sta[cid]; + if (sta->status != wil_sta_connected) { + wil_err(wil, "BACK: CID %d not connected\n", cid); + return; + } + + wil_dbg_wmi(wil, + "ADDBA request for CID %d %pM TID %d size %d timeout %d AMSDU%s policy %d token %d SSN 0x%03x\n", + cid, sta->addr, tid, req_agg_wsize, req->ba_timeout, + agg_amsdu ? "+" : "-", !!ba_policy, req->dialog_token, ssn); + + /* apply policies */ + if (ba_policy) { + wil_err(wil, "BACK requested unsupported ba_policy == 1\n"); + status = WLAN_STATUS_INVALID_QOS_PARAM; + } + if (status == WLAN_STATUS_SUCCESS) + agg_wsize = wil_agg_size(wil, req_agg_wsize); + + rc = wmi_addba_rx_resp(wil, cid, tid, req->dialog_token, status, + agg_amsdu, agg_wsize, agg_timeout); + if (rc || (status != WLAN_STATUS_SUCCESS)) + return; + + /* apply */ + r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn); + spin_lock_bh(&sta->tid_rx_lock); + wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]); + sta->tid_rx[tid] = r; + spin_unlock_bh(&sta->tid_rx_lock); +} + +void wil_back_rx_flush(struct wil6210_priv *wil) +{ + struct wil_back_rx *evt, *t; + + wil_dbg_misc(wil, "%s()\n", __func__); + + mutex_lock(&wil->back_rx_mutex); + + list_for_each_entry_safe(evt, t, &wil->back_rx_pending, list) { + list_del(&evt->list); + kfree(evt); + } + + mutex_unlock(&wil->back_rx_mutex); +} + +/* Retrieve next ADDBA request from the pending list */ +static struct list_head *next_back_rx(struct wil6210_priv *wil) +{ + struct list_head *ret = NULL; + + mutex_lock(&wil->back_rx_mutex); + + if (!list_empty(&wil->back_rx_pending)) { + ret = wil->back_rx_pending.next; + list_del(ret); + } + + mutex_unlock(&wil->back_rx_mutex); + + return ret; +} + +void wil_back_rx_worker(struct work_struct *work) +{ + struct wil6210_priv *wil = container_of(work, struct wil6210_priv, + back_rx_worker); + struct wil_back_rx *evt; + struct list_head *lh; + + while ((lh = next_back_rx(wil)) != NULL) { + evt = list_entry(lh, struct wil_back_rx, list); + + wil_back_rx_handle(wil, evt); + kfree(evt); + } +} + +/* BACK - Tx (originator) side */ +static void wil_back_tx_handle(struct wil6210_priv *wil, + struct wil_back_tx *req) +{ + struct vring_tx_data *txdata = &wil->vring_tx_data[req->ringid]; + int rc; + + if (txdata->addba_in_progress) { + wil_dbg_misc(wil, "ADDBA for vring[%d] already in progress\n", + req->ringid); + return; + } + if (txdata->agg_wsize) { + wil_dbg_misc(wil, + "ADDBA for vring[%d] already established wsize %d\n", + req->ringid, txdata->agg_wsize); + return; + } + txdata->addba_in_progress = true; + rc = wmi_addba(wil, req->ringid, req->agg_wsize, req->agg_timeout); + if (rc) + txdata->addba_in_progress = false; +} + +static struct list_head *next_back_tx(struct wil6210_priv *wil) +{ + struct list_head *ret = NULL; + + mutex_lock(&wil->back_tx_mutex); + + if (!list_empty(&wil->back_tx_pending)) { + ret = wil->back_tx_pending.next; + list_del(ret); + } + + mutex_unlock(&wil->back_tx_mutex); + + return ret; +} + +void wil_back_tx_worker(struct work_struct *work) +{ + struct wil6210_priv *wil = container_of(work, struct wil6210_priv, + back_tx_worker); + struct wil_back_tx *evt; + struct list_head *lh; + + while ((lh = next_back_tx(wil)) != NULL) { + evt = list_entry(lh, struct wil_back_tx, list); + + wil_back_tx_handle(wil, evt); + kfree(evt); + } +} + +void wil_back_tx_flush(struct wil6210_priv *wil) +{ + struct wil_back_tx *evt, *t; + + wil_dbg_misc(wil, "%s()\n", __func__); + + mutex_lock(&wil->back_tx_mutex); + + list_for_each_entry_safe(evt, t, &wil->back_tx_pending, list) { + list_del(&evt->list); + kfree(evt); + } + + mutex_unlock(&wil->back_tx_mutex); +} + +int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize) +{ + struct wil_back_tx *req = kzalloc(sizeof(*req), GFP_KERNEL); + + if (!req) + return -ENOMEM; + + req->ringid = ringid; + req->agg_wsize = wil_agg_size(wil, wsize); + req->agg_timeout = 0; + + mutex_lock(&wil->back_tx_mutex); + list_add_tail(&req->list, &wil->back_tx_pending); + mutex_unlock(&wil->back_tx_mutex); + + queue_work(wil->wq_service, &wil->back_tx_worker); + + return 0; +} diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index e3f8bdce5abc..8439f65db259 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -463,7 +463,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, * and in case of error drop the packet * higher stack layers will handle retransmission (if required) */ - if (d->dma.status & RX_DMA_STATUS_L4_IDENT) { + if (d->dma.status & RX_DMA_STATUS_L4I) { /* L4 protocol identified, csum calculated */ if ((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0) skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -581,14 +581,8 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) skb->protocol = htons(ETH_P_802_2); wil_netif_rx_any(skb, ndev); } else { - struct ethhdr *eth = (void *)skb->data; - skb->protocol = eth_type_trans(skb, ndev); - - if (is_unicast_ether_addr(eth->h_dest)) - wil_rx_reorder(wil, skb); - else - wil_netif_rx_any(skb, ndev); + wil_rx_reorder(wil, skb); } } wil_rx_refill(wil, v->size); @@ -645,7 +639,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, .vring_cfg = { .tx_sw_ring = { .max_mpdu_size = - cpu_to_le16(mtu_max + ETH_HLEN), + cpu_to_le16(wil_mtu2macbuf(mtu_max)), .ring_size = cpu_to_le16(size), }, .ringid = id, @@ -653,7 +647,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, .mac_ctrl = 0, .to_resolution = 0, - .agg_max_wsize = 16, + .agg_max_wsize = 0, .schd_params = { .priority = cpu_to_le16(0), .timeslot_us = cpu_to_le16(0xfff), @@ -677,6 +671,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, } memset(txdata, 0, sizeof(*txdata)); + spin_lock_init(&txdata->lock); vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) @@ -701,6 +696,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); txdata->enabled = 1; + if (wil->sta[cid].data_port_open && (agg_wsize >= 0)) + wil_addba_tx_request(wil, id, agg_wsize); return 0; out_free: @@ -713,6 +710,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, void wil_vring_fini_tx(struct wil6210_priv *wil, int id) { struct vring *vring = &wil->vring_tx[id]; + struct vring_tx_data *txdata = &wil->vring_tx_data[id]; WARN_ON(!mutex_is_locked(&wil->mutex)); @@ -721,12 +719,15 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) wil_dbg_misc(wil, "%s() id=%d\n", __func__, id); + spin_lock_bh(&txdata->lock); + txdata->enabled = 0; /* no Tx can be in progress or start anew */ + spin_unlock_bh(&txdata->lock); /* make sure NAPI won't touch this vring */ - wil->vring_tx_data[id].enabled = 0; - if (test_bit(wil_status_napi_en, &wil->status)) + if (test_bit(wil_status_napi_en, wil->status)) napi_synchronize(&wil->napi_tx); wil_vring_free(wil, vring, 1); + memset(txdata, 0, sizeof(*txdata)); } static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, @@ -773,6 +774,38 @@ static void wil_set_da_for_vring(struct wil6210_priv *wil, static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, struct sk_buff *skb); + +static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil, + struct sk_buff *skb) +{ + struct vring *v; + int i; + u8 cid; + + /* In the STA mode, it is expected to have only 1 VRING + * for the AP we connected to. + * find 1-st vring and see whether it is eligible for data + */ + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + v = &wil->vring_tx[i]; + if (!v->va) + continue; + + cid = wil->vring2cid_tid[i][0]; + if (!wil->sta[cid].data_port_open && + (skb->protocol != cpu_to_be16(ETH_P_PAE))) + break; + + wil_dbg_txrx(wil, "Tx -> ring %d\n", i); + + return v; + } + + wil_dbg_txrx(wil, "Tx while no vrings active?\n"); + + return NULL; +} + /* * Find 1-st vring and return it; set dest address for this vring in skb * duplicate skb and send it to other active vrings @@ -843,9 +876,6 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, d->mac.d[1] = 0; d->mac.d[2] = 0; d->mac.ucode_cmd = 0; - /* use dst index 0 */ - d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS) | - (0 << MAC_CFG_DESC_TX_1_DST_INDEX_POS); /* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */ d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) | (1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS); @@ -908,8 +938,8 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, return 0; } -static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, - struct sk_buff *skb) +static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, + struct sk_buff *skb) { struct device *dev = wil_to_dev(wil); struct vring_tx_desc dd, *d = ⅆ @@ -925,18 +955,21 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, wil_dbg_txrx(wil, "%s()\n", __func__); + if (unlikely(!txdata->enabled)) + return -EINVAL; + if (avail < 1 + nr_frags) { wil_err_ratelimited(wil, - "Tx ring full. No space for %d fragments\n", - 1 + nr_frags); + "Tx ring[%2d] full. No space for %d fragments\n", + vring_index, 1 + nr_frags); return -ENOMEM; } _d = &vring->va[i].tx; pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); - wil_dbg_txrx(wil, "Tx skb %d bytes 0x%p -> %pad\n", skb_headlen(skb), - skb->data, &pa); + wil_dbg_txrx(wil, "Tx[%2d] skb %d bytes 0x%p -> %pad\n", vring_index, + skb_headlen(skb), skb->data, &pa); wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb_headlen(skb), false); @@ -947,15 +980,13 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index); /* Process TCP/UDP checksum offloading */ if (wil_tx_desc_offload_cksum_set(wil, d, skb)) { - wil_err(wil, "VRING #%d Failed to set cksum, drop packet\n", + wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n", vring_index); goto dma_error; } vring->ctx[i].nr_frags = nr_frags; wil_tx_desc_set_nr_frags(d, nr_frags); - if (nr_frags) - *_d = *d; /* middle segments */ for (; f < nr_frags; f++) { @@ -963,6 +994,10 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, &skb_shinfo(skb)->frags[f]; int len = skb_frag_size(frag); + *_d = *d; + wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i); + wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4, + (const void *)d, sizeof(*d), false); i = (swhead + f + 1) % vring->size; _d = &vring->va[i].tx; pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), @@ -976,13 +1011,15 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, * it will succeed here too */ wil_tx_desc_offload_cksum_set(wil, d, skb); - *_d = *d; } /* for the last seg only */ d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_MARK_WB_POS); d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); *_d = *d; + wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i); + wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4, + (const void *)d, sizeof(*d), false); /* hold reference to skb * to prevent skb release before accounting @@ -990,15 +1027,13 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, */ vring->ctx[i].skb = skb_get(skb); - wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, - (const void *)d, sizeof(*d), false); - if (wil_vring_is_empty(vring)) /* performance monitoring */ txdata->idle += get_cycles() - txdata->last_idle; /* advance swhead */ wil_vring_advance_head(vring, nr_frags + 1); - wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); + wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", vring_index, swhead, + vring->swhead); trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags); iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); @@ -1025,6 +1060,19 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, return -EINVAL; } +static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, + struct sk_buff *skb) +{ + int vring_index = vring - wil->vring_tx; + struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; + int rc; + + spin_lock(&txdata->lock); + rc = __wil_tx_vring(wil, vring, skb); + spin_unlock(&txdata->lock); + return rc; +} + netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); @@ -1034,14 +1082,14 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) int rc; wil_dbg_txrx(wil, "%s()\n", __func__); - if (!test_bit(wil_status_fwready, &wil->status)) { + if (!test_bit(wil_status_fwready, wil->status)) { if (!pr_once_fw) { wil_err(wil, "FW not ready\n"); pr_once_fw = true; } goto drop; } - if (!test_bit(wil_status_fwconnected, &wil->status)) { + if (!test_bit(wil_status_fwconnected, wil->status)) { wil_err(wil, "FW not connected\n"); goto drop; } @@ -1052,15 +1100,19 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) pr_once_fw = false; /* find vring */ - if (is_unicast_ether_addr(eth->h_dest)) - vring = wil_find_tx_vring(wil, skb); - else - vring = wil_tx_bcast(wil, skb); + if (wil->wdev->iftype == NL80211_IFTYPE_STATION) { + /* in STA mode (ESS), all to same VRING */ + vring = wil_find_tx_vring_sta(wil, skb); + } else { /* direct communication, find matching VRING */ + if (is_unicast_ether_addr(eth->h_dest)) + vring = wil_find_tx_vring(wil, skb); + else + vring = wil_tx_bcast(wil, skb); + } if (!vring) { wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest); goto drop; } - /* set up vring entry */ rc = wil_tx_vring(wil, vring, skb); @@ -1087,6 +1139,22 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NET_XMIT_DROP; } +static inline bool wil_need_txstat(struct sk_buff *skb) +{ + struct ethhdr *eth = (void *)skb->data; + + return is_unicast_ether_addr(eth->h_dest) && skb->sk && + (skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS); +} + +static inline void wil_consume_skb(struct sk_buff *skb, bool acked) +{ + if (unlikely(wil_need_txstat(skb))) + skb_complete_wifi_ack(skb, acked); + else + acked ? dev_consume_skb_any(skb) : dev_kfree_skb_any(skb); +} + /** * Clean up transmitted skb's from the Tx VRING * @@ -1147,10 +1215,10 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) trace_wil6210_tx_done(ringid, vring->swtail, dmalen, d->dma.error); wil_dbg_txrx(wil, - "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", - vring->swtail, dmalen, d->dma.status, - d->dma.error); - wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, + "TxC[%2d][%3d] : %d bytes, status 0x%02x err 0x%02x\n", + ringid, vring->swtail, dmalen, + d->dma.status, d->dma.error); + wil_hex_dump_txrx("TxCD ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); wil_txdesc_unmap(dev, d, ctx); @@ -1165,8 +1233,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) ndev->stats.tx_errors++; stats->tx_errors++; } - - dev_kfree_skb_any(skb); + wil_consume_skb(skb, d->dma.error == 0); } memset(ctx, 0, sizeof(*ctx)); /* There is no need to touch HW descriptor: diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 630aeb5fa7f4..d90c8aa20c15 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -20,17 +20,15 @@ #define BUF_SW_OWNED (1) #define BUF_HW_OWNED (0) -/* size of max. Tx/Rx buffers, as supported by FW */ -#define TXRX_BUF_LEN_DEFAULT (2242) +/* default size of MAC Tx/Rx buffers */ +#define TXRX_BUF_LEN_DEFAULT (2048) /* how many bytes to reserve for rtap header? */ #define WIL6210_RTAP_SIZE (128) /* Tx/Rx path */ -/* - * Common representation of physical address in Vring - */ +/* Common representation of physical address in Vring */ struct vring_dma_addr { __le32 addr_low; __le16 addr_high; @@ -49,11 +47,10 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr, addr->addr_high = cpu_to_le16((u16)upper_32_bits(pa)); } -/* - * Tx descriptor - MAC part +/* Tx descriptor - MAC part * [dword 0] * bit 0.. 9 : lifetime_expiry_value:10 - * bit 10 : interrup_en:1 + * bit 10 : interrupt_en:1 * bit 11 : status_en:1 * bit 12..13 : txss_override:2 * bit 14 : timestamp_insertion:1 @@ -61,15 +58,12 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr, * bit 16..21 : reserved0:6 * bit 22..26 : mcs_index:5 * bit 27 : mcs_en:1 - * bit 28..29 : reserved1:2 - * bit 30 : reserved2:1 + * bit 28..30 : reserved1:3 * bit 31 : sn_preserved:1 * [dword 1] * bit 0.. 3 : pkt_mode:4 * bit 4 : pkt_mode_en:1 - * bit 5.. 7 : reserved0:3 - * bit 8..13 : reserved1:6 - * bit 14 : reserved2:1 + * bit 5..14 : reserved0:10 * bit 15 : ack_policy_en:1 * bit 16..19 : dst_index:4 * bit 20 : dst_index_en:1 @@ -80,7 +74,7 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr, * [dword 2] * bit 0.. 7 : num_of_descriptors:8 * bit 8..17 : reserved:10 - * bit 18..19 : l2_translation_type:2 + * bit 18..19 : l2_translation_type:2 00 - bypass, 01 - 802.3, 10 - 802.11 * bit 20 : snap_hdr_insertion_en:1 * bit 21 : vlan_removal_en:1 * bit 22..31 : reserved0:10 @@ -247,6 +241,46 @@ struct vring_tx_mac { #define TX_DMA_STATUS_DU BIT(0) +/* Tx descriptor - DMA part + * [dword 0] + * bit 0.. 7 : l4_length:8 layer 4 length + * bit 8 : cmd_eop:1 This descriptor is the last one in the packet + * bit 9 : reserved + * bit 10 : cmd_dma_it:1 immediate interrupt + * bit 11..12 : SBD - Segment Buffer Details + * 00 - Header Segment + * 01 - First Data Segment + * 10 - Medium Data Segment + * 11 - Last Data Segment + * bit 13 : TSE - TCP Segmentation Enable + * bit 14 : IIC - Directs the HW to Insert IPv4 Checksum + * bit 15 : ITC - Directs the HW to Insert TCP/UDP Checksum + * bit 16..20 : QID - The target QID that the packet should be stored + * in the MAC. + * bit 21 : PO - Pseudo header Offload: + * 0 - Use the pseudo header value from the TCP checksum field + * 1- Calculate Pseudo header Checksum + * bit 22 : NC - No UDP Checksum + * bit 23..29 : reserved + * bit 30..31 : L4T - Layer 4 Type: 00 - UDP , 10 - TCP , 10, 11 - Reserved + * If L4Len equal 0, no L4 at all + * [dword 1] + * bit 0..31 : addr_low:32 The payload buffer low address + * [dword 2] + * bit 0..15 : addr_high:16 The payload buffer high address + * bit 16..23 : ip_length:8 The IP header length for the TX IP checksum + * offload feature + * bit 24..30 : mac_length:7 + * bit 31 : ip_version:1 1 - IPv4, 0 - IPv6 + * [dword 3] + * [byte 12] error + * bit 0 2 : mac_status:3 + * bit 3 7 : reserved:5 + * [byte 13] status + * bit 0 : DU:1 Descriptor Used + * bit 1 7 : reserved:7 + * [word 7] length + */ struct vring_tx_dma { u32 d0; struct vring_dma_addr addr; @@ -257,45 +291,45 @@ struct vring_tx_dma { __le16 length; } __packed; -/* - * Rx descriptor - MAC part +/* Rx descriptor - MAC part * [dword 0] * bit 0.. 3 : tid:4 The QoS (b3-0) TID Field - * bit 4.. 6 : connection_id:3 :The Source index that was found during - * Parsing the TA. This field is used to define the source of the packet + * bit 4.. 6 : cid:3 The Source index that was found during parsing the TA. + * This field is used to define the source of the packet * bit 7 : reserved:1 - * bit 8.. 9 : mac_id:2 : The MAC virtual Ring number (always zero) - * bit 10..11 : frame_type:2 : The FC Control (b3-2) - MPDU Type - * (management, data, control and extension) - * bit 12..15 : frame_subtype:4 : The FC Control (b7-4) - Frame Subtype + * bit 8.. 9 : mid:2 The MAC virtual number + * bit 10..11 : frame_type:2 : The FC (b3-2) - MPDU Type + * (management, data, control and extension) + * bit 12..15 : frame_subtype:4 : The FC (b7-4) - Frame Subtype * bit 16..27 : seq_number:12 The received Sequence number field * bit 28..31 : extended:4 extended subtype * [dword 1] * bit 0.. 3 : reserved * bit 4.. 5 : key_id:2 * bit 6 : decrypt_bypass:1 - * bit 7 : security:1 - * bit 8.. 9 : ds_bits:2 - * bit 10 : a_msdu_present:1 from qos header - * bit 11 : a_msdu_type:1 from qos header + * bit 7 : security:1 FC (b14) + * bit 8.. 9 : ds_bits:2 FC (b9-8) + * bit 10 : a_msdu_present:1 QoS (b7) + * bit 11 : a_msdu_type:1 QoS (b8) * bit 12 : a_mpdu:1 part of AMPDU aggregation * bit 13 : broadcast:1 * bit 14 : mutlicast:1 * bit 15 : reserved:1 - * bit 16..20 : rx_mac_qid:5 The Queue Identifier that the packet - * is received from + * bit 16..20 : rx_mac_qid:5 The Queue Identifier that the packet + * is received from * bit 21..24 : mcs:4 - * bit 25..28 : mic_icr:4 + * bit 25..28 : mic_icr:4 this signal tells the DMA to assert an interrupt + * after it writes the packet * bit 29..31 : reserved:3 * [dword 2] * bit 0.. 2 : time_slot:3 The timeslot that the MPDU is received - * bit 3 : fc_protocol_ver:1 The FC Control (b0) - Protocol Version - * bit 4 : fc_order:1 The FC Control (b15) -Order - * bit 5.. 7 : qos_ack_policy:3 The QoS (b6-5) ack policy Field + * bit 3.. 4 : fc_protocol_ver:1 The FC (b1-0) - Protocol Version + * bit 5 : fc_order:1 The FC Control (b15) -Order + * bit 6.. 7 : qos_ack_policy:2 The QoS (b6-5) ack policy Field * bit 8 : esop:1 The QoS (b4) ESOP field - * bit 9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG field - * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved field - * bit 15 : qos_ac_constraint:1 + * bit 9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG field + * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved field + * bit 15 : qos_ac_constraint:1 QoS (b15) * bit 16..31 : pn_15_0:16 low 2 bytes of PN * [dword 3] * bit 0..31 : pn_47_16:32 high 4 bytes of PN @@ -308,35 +342,46 @@ struct vring_rx_mac { u32 pn_47_16; } __packed; -/* - * Rx descriptor - DMA part +/* Rx descriptor - DMA part * [dword 0] - * bit 0.. 7 : l4_length:8 layer 4 length - * bit 8.. 9 : reserved:2 - * bit 10 : cmd_dma_it:1 + * bit 0.. 7 : l4_length:8 layer 4 length. The field is only valid if + * L4I bit is set + * bit 8 : cmd_eop:1 set to 1 + * bit 9 : cmd_rt:1 set to 1 + * bit 10 : cmd_dma_it:1 immediate interrupt * bit 11..15 : reserved:5 - * bit 16..29 : phy_info_length:14 + * bit 16..29 : phy_info_length:14 It is valid when the PII is set. + * When the FFM bit is set bits 29-27 are used for for + * Flex Filter Match. Matching Index to one of the L2 + * EtherType Flex Filter * bit 30..31 : l4_type:2 valid if the L4I bit is set in the status field + * 00 - UDP, 01 - TCP, 10, 11 - reserved * [dword 1] * bit 0..31 : addr_low:32 The payload buffer low address * [dword 2] * bit 0..15 : addr_high:16 The payload buffer high address - * bit 16..23 : ip_length:8 + * bit 16..23 : ip_length:8 The filed is valid only if the L3I bit is set * bit 24..30 : mac_length:7 - * bit 31 : ip_version:1 + * bit 31 : ip_version:1 1 - IPv4, 0 - IPv6 * [dword 3] * [byte 12] error + * bit 0 : FCS:1 + * bit 1 : MIC:1 + * bit 2 : Key miss:1 + * bit 3 : Replay:1 + * bit 4 : L3:1 IPv4 checksum + * bit 5 : L4:1 TCP/UDP checksum + * bit 6 7 : reserved:2 * [byte 13] status - * bit 0 : du:1 - * bit 1 : eop:1 + * bit 0 : DU:1 Descriptor Used + * bit 1 : EOP:1 The descriptor indicates the End of Packet * bit 2 : error:1 - * bit 3 : mi:1 - * bit 4 : l3_identified:1 - * bit 5 : l4_identified:1 - * bit 6 : phy_info_included:1 - * bit 7 : reserved:1 + * bit 3 : MI:1 MAC Interrupt is asserted (according to parser decision) + * bit 4 : L3I:1 L3 identified and checksum calculated + * bit 5 : L4I:1 L4 identified and checksum calculated + * bit 6 : PII:1 PHY Info Included in the packet + * bit 7 : FFM:1 EtherType Flex Filter Match * [word 7] length - * */ #define RX_DMA_D0_CMD_DMA_IT BIT(10) @@ -349,9 +394,9 @@ struct vring_rx_mac { #define RX_DMA_STATUS_DU BIT(0) #define RX_DMA_STATUS_ERROR BIT(2) -#define RX_DMA_STATUS_L3_IDENT BIT(4) -#define RX_DMA_STATUS_L4_IDENT BIT(5) -#define RX_DMA_STATUS_PHY_INFO BIT(6) +#define RX_DMA_STATUS_L3I BIT(4) +#define RX_DMA_STATUS_L4I BIT(5) +#define RX_DMA_STATUS_PHY_INFO BIT(6) struct vring_rx_dma { u32 d0; @@ -423,6 +468,11 @@ static inline int wil_rxdesc_mcs(struct vring_rx_desc *d) return WIL_GET_BITS(d->mac.d1, 21, 24); } +static inline int wil_rxdesc_mcast(struct vring_rx_desc *d) +{ + return WIL_GET_BITS(d->mac.d1, 13, 14); +} + static inline int wil_rxdesc_phy_length(struct vring_rx_desc *d) { return WIL_GET_BITS(d->dma.d0, 16, 29); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c6ec5b99ac7d..94611568fc9a 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. + * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,19 +25,14 @@ extern bool no_fw_recovery; extern unsigned int mtu_max; +extern unsigned short rx_ring_overflow_thrsh; +extern int agg_wsize; #define WIL_NAME "wil6210" #define WIL_FW_NAME "wil6210.fw" #define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */ -struct wil_board { - int board; -#define WIL_BOARD_MARLON (1) -#define WIL_BOARD_SPARROW (2) - const char * const name; -}; - /** * extract bits [@b0:@b1] (inclusive) from the value @x * it should be @b0 <= @b1, or result is incorrect @@ -49,21 +44,50 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL6210_MEM_SIZE (2*1024*1024UL) -#define WIL_RX_RING_SIZE_ORDER_DEFAULT (9) -#define WIL_TX_RING_SIZE_ORDER_DEFAULT (9) +#define WIL_TX_Q_LEN_DEFAULT (4000) +#define WIL_RX_RING_SIZE_ORDER_DEFAULT (10) +#define WIL_TX_RING_SIZE_ORDER_DEFAULT (10) /* limit ring size in range [32..32k] */ #define WIL_RING_SIZE_ORDER_MIN (5) #define WIL_RING_SIZE_ORDER_MAX (15) #define WIL6210_MAX_TX_RINGS (24) /* HW limit */ #define WIL6210_MAX_CID (8) /* HW limit */ #define WIL6210_NAPI_BUDGET (16) /* arbitrary */ +#define WIL_MAX_AMPDU_SIZE (64 * 1024) /* FW/HW limit */ +#define WIL_MAX_AGG_WSIZE (32) /* FW/HW limit */ +/* Hardware offload block adds the following: + * 26 bytes - 3-address QoS data header + * 8 bytes - IV + EIV (for GCMP) + * 8 bytes - SNAP + * 16 bytes - MIC (for GCMP) + * 4 bytes - CRC + */ +#define WIL_MAX_MPDU_OVERHEAD (62) + +/* Calculate MAC buffer size for the firmware. It includes all overhead, + * as it will go over the air, and need to be 8 byte aligned + */ +static inline u32 wil_mtu2macbuf(u32 mtu) +{ + return ALIGN(mtu + WIL_MAX_MPDU_OVERHEAD, 8); +} + +/* MTU for Ethernet need to take into account 8-byte SNAP header + * to be added when encapsulating Ethernet frame into 802.11 + */ +#define WIL_MAX_ETH_MTU (IEEE80211_MAX_DATA_LEN_DMG - 8) /* Max supported by wil6210 value for interrupt threshold is 5sec. */ #define WIL6210_ITR_TRSH_MAX (5000000) -#define WIL6210_ITR_TRSH_DEFAULT (300) /* usec */ +#define WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT (13) /* usec */ +#define WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT (13) /* usec */ +#define WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT (500) /* usec */ +#define WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT (500) /* usec */ #define WIL6210_FW_RECOVERY_RETRIES (5) /* try to recover this many times */ #define WIL6210_FW_RECOVERY_TO msecs_to_jiffies(5000) #define WIL6210_SCAN_TO msecs_to_jiffies(10000) - +#define WIL6210_RX_HIGH_TRSH_INIT (0) +#define WIL6210_RX_HIGH_TRSH_DEFAULT \ + (1 << (WIL_RX_RING_SIZE_ORDER_DEFAULT - 3)) /* Hardware definitions begin */ /* @@ -135,7 +159,7 @@ struct RGF_ICR { #define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1) #define BIT_DMA_EP_MISC_ICR_FW_INT(n) BIT(28+n) /* n = [0..3] */ -/* Interrupt moderation control */ +/* Legacy interrupt moderation control (before Sparrow v2)*/ #define RGF_DMA_ITR_CNT_TRSH (0x881c5c) #define RGF_DMA_ITR_CNT_DATA (0x881c60) #define RGF_DMA_ITR_CNT_CRL (0x881c64) @@ -145,6 +169,46 @@ struct RGF_ICR { #define BIT_DMA_ITR_CNT_CRL_CLR BIT(3) #define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4) +/* New (sparrow v2+) interrupt moderation control */ +#define RGF_DMA_ITR_TX_DESQ_NO_MOD (0x881d40) +#define RGF_DMA_ITR_TX_CNT_TRSH (0x881d34) +#define RGF_DMA_ITR_TX_CNT_DATA (0x881d38) +#define RGF_DMA_ITR_TX_CNT_CTL (0x881d3c) + #define BIT_DMA_ITR_TX_CNT_CTL_EN BIT(0) + #define BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL BIT(1) + #define BIT_DMA_ITR_TX_CNT_CTL_FOREVER BIT(2) + #define BIT_DMA_ITR_TX_CNT_CTL_CLR BIT(3) + #define BIT_DMA_ITR_TX_CNT_CTL_REACHED_TRESH BIT(4) + #define BIT_DMA_ITR_TX_CNT_CTL_CROSS_EN BIT(5) + #define BIT_DMA_ITR_TX_CNT_CTL_FREE_RUNNIG BIT(6) +#define RGF_DMA_ITR_TX_IDL_CNT_TRSH (0x881d60) +#define RGF_DMA_ITR_TX_IDL_CNT_DATA (0x881d64) +#define RGF_DMA_ITR_TX_IDL_CNT_CTL (0x881d68) + #define BIT_DMA_ITR_TX_IDL_CNT_CTL_EN BIT(0) + #define BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL BIT(1) + #define BIT_DMA_ITR_TX_IDL_CNT_CTL_FOREVER BIT(2) + #define BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR BIT(3) + #define BIT_DMA_ITR_TX_IDL_CNT_CTL_REACHED_TRESH BIT(4) +#define RGF_DMA_ITR_RX_DESQ_NO_MOD (0x881d50) +#define RGF_DMA_ITR_RX_CNT_TRSH (0x881d44) +#define RGF_DMA_ITR_RX_CNT_DATA (0x881d48) +#define RGF_DMA_ITR_RX_CNT_CTL (0x881d4c) + #define BIT_DMA_ITR_RX_CNT_CTL_EN BIT(0) + #define BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL BIT(1) + #define BIT_DMA_ITR_RX_CNT_CTL_FOREVER BIT(2) + #define BIT_DMA_ITR_RX_CNT_CTL_CLR BIT(3) + #define BIT_DMA_ITR_RX_CNT_CTL_REACHED_TRESH BIT(4) + #define BIT_DMA_ITR_RX_CNT_CTL_CROSS_EN BIT(5) + #define BIT_DMA_ITR_RX_CNT_CTL_FREE_RUNNIG BIT(6) +#define RGF_DMA_ITR_RX_IDL_CNT_TRSH (0x881d54) +#define RGF_DMA_ITR_RX_IDL_CNT_DATA (0x881d58) +#define RGF_DMA_ITR_RX_IDL_CNT_CTL (0x881d5c) + #define BIT_DMA_ITR_RX_IDL_CNT_CTL_EN BIT(0) + #define BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL BIT(1) + #define BIT_DMA_ITR_RX_IDL_CNT_CTL_FOREVER BIT(2) + #define BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR BIT(3) + #define BIT_DMA_ITR_RX_IDL_CNT_CTL_REACHED_TRESH BIT(4) + #define RGF_DMA_PSEUDO_CAUSE (0x881c68) #define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c) #define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70) @@ -164,6 +228,20 @@ struct RGF_ICR { #define RGF_CAF_PLL_LOCK_STATUS (0x88afec) #define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0) +#define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */ + #define JTAG_DEV_ID_MARLON_B0 (0x0612072f) + #define JTAG_DEV_ID_SPARROW_A0 (0x0632072f) + #define JTAG_DEV_ID_SPARROW_A1 (0x1632072f) + #define JTAG_DEV_ID_SPARROW_B0 (0x2632072f) + +enum { + HW_VER_UNKNOWN, + HW_VER_MARLON_B0, /* JTAG_DEV_ID_MARLON_B0 */ + HW_VER_SPARROW_A0, /* JTAG_DEV_ID_SPARROW_A0 */ + HW_VER_SPARROW_A1, /* JTAG_DEV_ID_SPARROW_A1 */ + HW_VER_SPARROW_B0, /* JTAG_DEV_ID_SPARROW_B0 */ +}; + /* popular locations */ #define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD) #define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \ @@ -303,6 +381,11 @@ struct vring { struct vring_tx_data { int enabled; cycles_t idle, last_idle, begin; + u8 agg_wsize; /* agreed aggregation window, 0 - no agg */ + u16 agg_timeout; + u8 agg_amsdu; + bool addba_in_progress; /* if set, agg_xxx is for request in progress */ + spinlock_t lock; }; enum { /* for wil6210_priv.status */ @@ -313,6 +396,7 @@ enum { /* for wil6210_priv.status */ wil_status_reset_done, wil_status_irqen, /* FIXME: interrupts enabled - for debug */ wil_status_napi_en, /* NAPI enabled protected by wil->mutex */ + wil_status_last /* keep last */ }; struct pci_dev; @@ -397,15 +481,46 @@ enum { fw_recovery_running = 2, }; +enum { + hw_capability_reset_v2 = 0, + hw_capability_advanced_itr_moderation = 1, + hw_capability_last +}; + +struct wil_back_rx { + struct list_head list; + /* request params, converted to CPU byte order - what we asked for */ + u8 cidxtid; + u8 dialog_token; + u16 ba_param_set; + u16 ba_timeout; + u16 ba_seq_ctrl; +}; + +struct wil_back_tx { + struct list_head list; + /* request params, converted to CPU byte order - what we asked for */ + u8 ringid; + u8 agg_wsize; + u16 agg_timeout; +}; + +struct wil_probe_client_req { + struct list_head list; + u64 cookie; + u8 cid; +}; + struct wil6210_priv { struct pci_dev *pdev; int n_msi; struct wireless_dev *wdev; void __iomem *csr; - ulong status; + DECLARE_BITMAP(status, wil_status_last); u32 fw_version; u32 hw_version; - struct wil_board *board; + const char *hw_name; + DECLARE_BITMAP(hw_capabilities, hw_capability_last); u8 n_mids; /* number of additional MIDs as reported by FW */ u32 recovery_count; /* num of FW recovery attempts in a short time */ u32 recovery_state; /* FW recovery state machine */ @@ -415,7 +530,11 @@ struct wil6210_priv { u32 monitor_flags; u32 secure_pcp; /* create secure PCP? */ int sinfo_gen; - u32 itr_trsh; + /* interrupt moderation */ + u32 tx_max_burst_duration; + u32 tx_interframe_timeout; + u32 rx_max_burst_duration; + u32 rx_interframe_timeout; /* cached ISR registers */ u32 isr_misc; /* mailbox related */ @@ -429,7 +548,7 @@ struct wil6210_priv { u16 reply_size; struct workqueue_struct *wmi_wq; /* for deferred calls */ struct work_struct wmi_event_worker; - struct workqueue_struct *wmi_wq_conn; /* for connect worker */ + struct workqueue_struct *wq_service; struct work_struct connect_worker; struct work_struct disconnect_worker; struct work_struct fw_error_worker; /* for FW error recovery */ @@ -445,6 +564,17 @@ struct wil6210_priv { spinlock_t wmi_ev_lock; struct napi_struct napi_rx; struct napi_struct napi_tx; + /* BACK */ + struct list_head back_rx_pending; + struct mutex back_rx_mutex; /* protect @back_rx_pending */ + struct work_struct back_rx_worker; + struct list_head back_tx_pending; + struct mutex back_tx_mutex; /* protect @back_tx_pending */ + struct work_struct back_tx_worker; + /* keep alive */ + struct list_head probe_client_pending; + struct mutex probe_client_mutex; /* protect @probe_client_pending */ + struct work_struct probe_client_worker; /* DMA related */ struct vring vring_rx; struct vring vring_tx[WIL6210_MAX_TX_RINGS]; @@ -529,11 +659,8 @@ void wil_if_remove(struct wil6210_priv *wil); int wil_priv_init(struct wil6210_priv *wil); void wil_priv_deinit(struct wil6210_priv *wil); int wil_reset(struct wil6210_priv *wil); -void wil_set_itr_trsh(struct wil6210_priv *wil); void wil_fw_error_recovery(struct wil6210_priv *wil); void wil_set_recovery_state(struct wil6210_priv *wil, int state); -void wil_link_on(struct wil6210_priv *wil); -void wil_link_off(struct wil6210_priv *wil); int wil_up(struct wil6210_priv *wil); int __wil_up(struct wil6210_priv *wil); int wil_down(struct wil6210_priv *wil); @@ -567,12 +694,26 @@ int wmi_p2p_cfg(struct wil6210_priv *wil, int channel); int wmi_rxon(struct wil6210_priv *wil, bool on); int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason); +int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout); +int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason); +int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason); +int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, + u16 status, bool amsdu, u16 agg_wsize, u16 timeout); +int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, + u8 dialog_token, __le16 ba_param_set, + __le16 ba_timeout, __le16 ba_seq_ctrl); +void wil_back_rx_worker(struct work_struct *work); +void wil_back_rx_flush(struct wil6210_priv *wil); +int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize); +void wil_back_tx_worker(struct work_struct *work); +void wil_back_tx_flush(struct wil6210_priv *wil); void wil6210_clear_irq(struct wil6210_priv *wil); int wil6210_init_irq(struct wil6210_priv *wil, int irq); void wil6210_fini_irq(struct wil6210_priv *wil, int irq); void wil_mask_irq(struct wil6210_priv *wil); void wil_unmask_irq(struct wil6210_priv *wil); +void wil_configure_interrupt_moderation(struct wil6210_priv *wil); void wil_disable_irq(struct wil6210_priv *wil); void wil_enable_irq(struct wil6210_priv *wil); int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, @@ -592,6 +733,8 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan); int wmi_pcp_stop(struct wil6210_priv *wil); void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, u16 reason_code, bool from_event); +void wil_probe_client_flush(struct wil6210_priv *wil); +void wil_probe_client_worker(struct work_struct *work); int wil_rx_init(struct wil6210_priv *wil, u16 size); void wil_rx_fini(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c index 8f1d78f8a74d..976a071ba74e 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.c +++ b/drivers/net/wireless/ath/wil6210/wil_platform.c @@ -17,10 +17,6 @@ #include "linux/device.h" #include "wil_platform.h" -#ifdef CONFIG_WIL6210_PLATFORM_MSM -#include "wil_platform_msm.h" -#endif - /** * wil_platform_init() - wil6210 platform module init * @@ -37,13 +33,7 @@ void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops) return NULL; } -#ifdef CONFIG_WIL6210_PLATFORM_MSM - handle = wil_platform_msm_init(dev, ops); - if (handle) - return handle; -#endif - - /* other platform specific init functions should be called here */ + /* platform specific init functions should be called here */ return handle; } diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.c b/drivers/net/wireless/ath/wil6210/wil_platform_msm.c deleted file mode 100644 index b354a743240d..000000000000 --- a/drivers/net/wireless/ath/wil6210/wil_platform_msm.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (c) 2014 Qualcomm Atheros, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#include "wil_platform.h" -#include "wil_platform_msm.h" - -/** - * struct wil_platform_msm - wil6210 msm platform module info - * - * @dev: device object - * @msm_bus_handle: handle for using msm_bus API - * @pdata: bus scale info retrieved from DT - */ -struct wil_platform_msm { - struct device *dev; - uint32_t msm_bus_handle; - struct msm_bus_scale_pdata *pdata; -}; - -#define KBTOB(a) (a * 1000ULL) - -/** - * wil_platform_get_pdata() - Generate bus client data from device tree - * provided by clients. - * - * dev: device object - * of_node: Device tree node to extract information from - * - * The function returns a valid pointer to the allocated bus-scale-pdata - * if the vectors were correctly read from the client's device node. - * Any error in reading or parsing the device node will return NULL - * to the caller. - */ -static struct msm_bus_scale_pdata *wil_platform_get_pdata( - struct device *dev, - struct device_node *of_node) -{ - struct msm_bus_scale_pdata *pdata; - struct msm_bus_paths *usecase; - int i, j, ret, len; - unsigned int num_usecases, num_paths, mem_size; - const uint32_t *vec_arr; - struct msm_bus_vectors *vectors; - - /* first read num_usecases and num_paths so we can calculate - * amount of memory to allocate - */ - ret = of_property_read_u32(of_node, "qcom,msm-bus,num-cases", - &num_usecases); - if (ret) { - dev_err(dev, "Error: num-usecases not found\n"); - return NULL; - } - - ret = of_property_read_u32(of_node, "qcom,msm-bus,num-paths", - &num_paths); - if (ret) { - dev_err(dev, "Error: num_paths not found\n"); - return NULL; - } - - /* pdata memory layout: - * msm_bus_scale_pdata - * msm_bus_paths[num_usecases] - * msm_bus_vectors[num_usecases][num_paths] - */ - mem_size = sizeof(struct msm_bus_scale_pdata) + - sizeof(struct msm_bus_paths) * num_usecases + - sizeof(struct msm_bus_vectors) * num_usecases * num_paths; - - pdata = kzalloc(mem_size, GFP_KERNEL); - if (!pdata) - return NULL; - - ret = of_property_read_string(of_node, "qcom,msm-bus,name", - &pdata->name); - if (ret) { - dev_err(dev, "Error: Client name not found\n"); - goto err; - } - - if (of_property_read_bool(of_node, "qcom,msm-bus,active-only")) { - pdata->active_only = 1; - } else { - dev_info(dev, "active_only flag absent.\n"); - dev_info(dev, "Using dual context by default\n"); - } - - pdata->num_usecases = num_usecases; - pdata->usecase = (struct msm_bus_paths *)(pdata + 1); - - vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len); - if (vec_arr == NULL) { - dev_err(dev, "Error: Vector array not found\n"); - goto err; - } - - if (len != num_usecases * num_paths * sizeof(uint32_t) * 4) { - dev_err(dev, "Error: Length-error on getting vectors\n"); - goto err; - } - - vectors = (struct msm_bus_vectors *)(pdata->usecase + num_usecases); - for (i = 0; i < num_usecases; i++) { - usecase = &pdata->usecase[i]; - usecase->num_paths = num_paths; - usecase->vectors = &vectors[i]; - - for (j = 0; j < num_paths; j++) { - int index = ((i * num_paths) + j) * 4; - - usecase->vectors[j].src = be32_to_cpu(vec_arr[index]); - usecase->vectors[j].dst = - be32_to_cpu(vec_arr[index + 1]); - usecase->vectors[j].ab = (uint64_t) - KBTOB(be32_to_cpu(vec_arr[index + 2])); - usecase->vectors[j].ib = (uint64_t) - KBTOB(be32_to_cpu(vec_arr[index + 3])); - } - } - - return pdata; - -err: - kfree(pdata); - - return NULL; -} - -/* wil_platform API (callbacks) */ - -static int wil_platform_bus_request(void *handle, - uint32_t kbps /* KBytes/Sec */) -{ - int rc, i; - struct wil_platform_msm *msm = (struct wil_platform_msm *)handle; - int vote = 0; /* vote 0 in case requested kbps cannot be satisfied */ - struct msm_bus_paths *usecase; - uint32_t usecase_kbps; - uint32_t min_kbps = ~0; - - /* find the lowest usecase that is bigger than requested kbps */ - for (i = 0; i < msm->pdata->num_usecases; i++) { - usecase = &msm->pdata->usecase[i]; - /* assume we have single path (vectors[0]). If we ever - * have multiple paths, need to define the behavior */ - usecase_kbps = div64_u64(usecase->vectors[0].ib, 1000); - if (usecase_kbps >= kbps && usecase_kbps < min_kbps) { - min_kbps = usecase_kbps; - vote = i; - } - } - - rc = msm_bus_scale_client_update_request(msm->msm_bus_handle, vote); - if (rc) - dev_err(msm->dev, "Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n", - kbps, vote, rc); - else - /* TOOD: remove */ - dev_info(msm->dev, "msm_bus_scale_client_update_request succeeded. kbps=%d vote=%d\n", - kbps, vote); - - return rc; -} - -static void wil_platform_uninit(void *handle) -{ - struct wil_platform_msm *msm = (struct wil_platform_msm *)handle; - - dev_info(msm->dev, "wil_platform_uninit\n"); - - if (msm->msm_bus_handle) - msm_bus_scale_unregister_client(msm->msm_bus_handle); - - kfree(msm->pdata); - kfree(msm); -} - -static int wil_platform_msm_bus_register(struct wil_platform_msm *msm, - struct device_node *node) -{ - msm->pdata = wil_platform_get_pdata(msm->dev, node); - if (!msm->pdata) { - dev_err(msm->dev, "Failed getting DT info\n"); - return -EINVAL; - } - - msm->msm_bus_handle = msm_bus_scale_register_client(msm->pdata); - if (!msm->msm_bus_handle) { - dev_err(msm->dev, "Failed msm_bus registration\n"); - return -EINVAL; - } - - dev_info(msm->dev, "msm_bus registration succeeded! handle 0x%x\n", - msm->msm_bus_handle); - - return 0; -} - -/** - * wil_platform_msm_init() - wil6210 msm platform module init - * - * The function must be called before all other functions in this module. - * It returns a handle which is used with the rest of the API - * - */ -void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops) -{ - struct device_node *of_node; - struct wil_platform_msm *msm; - int rc; - - of_node = of_find_compatible_node(NULL, NULL, "qcom,wil6210"); - if (!of_node) { - /* this could mean non-msm platform */ - dev_err(dev, "DT node not found\n"); - return NULL; - } - - msm = kzalloc(sizeof(*msm), GFP_KERNEL); - if (!msm) - return NULL; - - msm->dev = dev; - - /* register with msm_bus module for scaling requests */ - rc = wil_platform_msm_bus_register(msm, of_node); - if (rc) - goto cleanup; - - memset(ops, 0, sizeof(*ops)); - ops->bus_request = wil_platform_bus_request; - ops->uninit = wil_platform_uninit; - - return (void *)msm; - -cleanup: - kfree(msm); - return NULL; -} diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 63476c86cd0e..0f3e4334c8e3 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -23,10 +23,15 @@ #include "wmi.h" #include "trace.h" -static uint max_assoc_sta = 1; +static uint max_assoc_sta = WIL6210_MAX_CID; module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP"); +int agg_wsize; /* = 0; */ +module_param(agg_wsize, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;" + " 0 - use default; < 0 - don't auto-establish"); + /** * WMI event receiving - theory of operations * @@ -197,7 +202,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) might_sleep(); - if (!test_bit(wil_status_fwready, &wil->status)) { + if (!test_bit(wil_status_fwready, wil->status)) { wil_err(wil, "WMI: cannot send command while FW not ready\n"); return -EAGAIN; } @@ -300,7 +305,7 @@ static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, wil_dbg_wmi(wil, "WMI: got FW ready event\n"); wil_set_recovery_state(wil, fw_recovery_idle); - set_bit(wil_status_fwready, &wil->status); + set_bit(wil_status_fwready, wil->status); /* let the reset sequence continue */ complete(&wil->wmi_ready); } @@ -438,7 +443,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) if ((wdev->iftype == NL80211_IFTYPE_STATION) || (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { - if (!test_bit(wil_status_fwconnecting, &wil->status)) { + if (!test_bit(wil_status_fwconnecting, wil->status)) { wil_err(wil, "Not in connecting state\n"); return; } @@ -457,13 +462,12 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) if (assoc_req_ie) { sinfo.assoc_req_ies = assoc_req_ie; sinfo.assoc_req_ies_len = assoc_req_ielen; - sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; } cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL); } - clear_bit(wil_status_fwconnecting, &wil->status); - set_bit(wil_status_fwconnected, &wil->status); + clear_bit(wil_status_fwconnecting, wil->status); + set_bit(wil_status_fwconnected, wil->status); /* FIXME FW can transmit only ucast frames to peer */ /* FIXME real ring_id instead of hard coded 0 */ @@ -471,7 +475,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) wil->sta[evt->cid].status = wil_sta_conn_pending; wil->pending_connect_cid = evt->cid; - queue_work(wil->wmi_wq_conn, &wil->connect_worker); + queue_work(wil->wq_service, &wil->connect_worker); } static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, @@ -544,9 +548,24 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, } } +static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid, u16 wsize) +{ + struct vring_tx_data *t; + int i; + + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + if (cid != wil->vring2cid_tid[i][0]) + continue; + t = &wil->vring_tx_data[i]; + if (!t->enabled) + continue; + + wil_addba_tx_request(wil, i, wsize); + } +} + static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) { - struct net_device *ndev = wil_to_ndev(wil); struct wmi_data_port_open_event *evt = d; u8 cid = evt->cid; @@ -558,7 +577,8 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len) } wil->sta[cid].data_port_open = true; - netif_carrier_on(ndev); + if (agg_wsize >= 0) + wil_addba_tx_cid(wil, cid, agg_wsize); } static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len) @@ -583,55 +603,89 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, int len) { struct wmi_vring_ba_status_event *evt = d; - struct wil_sta_info *sta; - uint i, cid; + struct vring_tx_data *txdata; - /* TODO: use Rx BA status, not Tx one */ - - wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n", + wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d AMSDU%s\n", evt->ringid, evt->status == WMI_BA_AGREED ? "OK" : "N/A", - evt->agg_wsize, __le16_to_cpu(evt->ba_timeout)); + evt->agg_wsize, __le16_to_cpu(evt->ba_timeout), + evt->amsdu ? "+" : "-"); if (evt->ringid >= WIL6210_MAX_TX_RINGS) { wil_err(wil, "invalid ring id %d\n", evt->ringid); return; } - mutex_lock(&wil->mutex); + if (evt->status != WMI_BA_AGREED) { + evt->ba_timeout = 0; + evt->agg_wsize = 0; + evt->amsdu = 0; + } - cid = wil->vring2cid_tid[evt->ringid][0]; - if (cid >= WIL6210_MAX_CID) { - wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid); - goto out; + txdata = &wil->vring_tx_data[evt->ringid]; + + txdata->agg_timeout = le16_to_cpu(evt->ba_timeout); + txdata->agg_wsize = evt->agg_wsize; + txdata->agg_amsdu = evt->amsdu; + txdata->addba_in_progress = false; +} + +static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d, + int len) +{ + struct wmi_rcp_addba_req_event *evt = d; + + wil_addba_rx_request(wil, evt->cidxtid, evt->dialog_token, + evt->ba_param_set, evt->ba_timeout, + evt->ba_seq_ctrl); +} + +static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len) +__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) +{ + struct wmi_delba_event *evt = d; + u8 cid, tid; + u16 reason = __le16_to_cpu(evt->reason); + struct wil_sta_info *sta; + struct wil_tid_ampdu_rx *r; + + might_sleep(); + parse_cidxtid(evt->cidxtid, &cid, &tid); + wil_dbg_wmi(wil, "DELBA CID %d TID %d from %s reason %d\n", + cid, tid, + evt->from_initiator ? "originator" : "recipient", + reason); + if (!evt->from_initiator) { + int i; + /* find Tx vring it belongs to */ + for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) { + if ((wil->vring2cid_tid[i][0] == cid) && + (wil->vring2cid_tid[i][1] == tid)) { + struct vring_tx_data *txdata = + &wil->vring_tx_data[i]; + + wil_dbg_wmi(wil, "DELBA Tx vring %d\n", i); + txdata->agg_timeout = 0; + txdata->agg_wsize = 0; + txdata->addba_in_progress = false; + + break; /* max. 1 matching ring */ + } + } + if (i >= ARRAY_SIZE(wil->vring2cid_tid)) + wil_err(wil, "DELBA: unable to find Tx vring\n"); + return; } sta = &wil->sta[cid]; - if (sta->status == wil_sta_unused) { - wil_err(wil, "CID %d unused\n", cid); - goto out; - } - wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr); - for (i = 0; i < WIL_STA_TID_NUM; i++) { - struct wil_tid_ampdu_rx *r; - unsigned long flags; + spin_lock_bh(&sta->tid_rx_lock); - spin_lock_irqsave(&sta->tid_rx_lock, flags); + r = sta->tid_rx[tid]; + sta->tid_rx[tid] = NULL; + wil_tid_ampdu_rx_free(wil, r); - r = sta->tid_rx[i]; - sta->tid_rx[i] = NULL; - wil_tid_ampdu_rx_free(wil, r); - - spin_unlock_irqrestore(&sta->tid_rx_lock, flags); - - if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize) - sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil, - evt->agg_wsize, 0); - } - -out: - mutex_unlock(&wil->mutex); + spin_unlock_bh(&sta->tid_rx_lock); } static const struct { @@ -649,6 +703,8 @@ static const struct { {WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_linkup}, {WMI_WBE_LINKDOWN_EVENTID, wmi_evt_linkdown}, {WMI_BA_STATUS_EVENTID, wmi_evt_ba_status}, + {WMI_RCP_ADDBA_REQ_EVENTID, wmi_evt_addba_rx_req}, + {WMI_DELBA_EVENTID, wmi_evt_delba}, }; /* @@ -668,7 +724,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) ulong flags; unsigned n; - if (!test_bit(wil_status_reset_done, &wil->status)) { + if (!test_bit(wil_status_reset_done, wil->status)) { wil_err(wil, "Reset in progress. Cannot handle WMI event\n"); return; } @@ -1025,13 +1081,14 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) struct wmi_cfg_rx_chain_cmd cmd = { .action = WMI_RX_CHAIN_ADD, .rx_sw_ring = { - .max_mpdu_size = cpu_to_le16(mtu_max + ETH_HLEN), + .max_mpdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)), .ring_mem_base = cpu_to_le64(vring->pa), .ring_size = cpu_to_le16(vring->size), }, .mid = 0, /* TODO - what is it? */ .decap_trans_type = WMI_DECAP_TYPE_802_3, .reorder_type = WMI_RX_SW_REORDER, + .host_thrsh = cpu_to_le16(rx_ring_overflow_thrsh), }; struct { struct wil6210_mbox_hdr_wmi wmi; @@ -1074,12 +1131,13 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) return rc; } -int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r) +int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf) { int rc; struct wmi_temp_sense_cmd cmd = { - .measure_marlon_m_en = cpu_to_le32(!!t_m), - .measure_marlon_r_en = cpu_to_le32(!!t_r), + .measure_baseband_en = cpu_to_le32(!!t_bb), + .measure_rf_en = cpu_to_le32(!!t_rf), + .measure_mode = cpu_to_le32(TEMPERATURE_MEASURE_NOW), }; struct { struct wil6210_mbox_hdr_wmi wmi; @@ -1091,10 +1149,10 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r) if (rc) return rc; - if (t_m) - *t_m = le32_to_cpu(reply.evt.marlon_m_t1000); - if (t_r) - *t_r = le32_to_cpu(reply.evt.marlon_r_t1000); + if (t_bb) + *t_bb = le32_to_cpu(reply.evt.baseband_t1000); + if (t_rf) + *t_rf = le32_to_cpu(reply.evt.rf_t1000); return 0; } @@ -1111,6 +1169,87 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason) return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd)); } +int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout) +{ + struct wmi_vring_ba_en_cmd cmd = { + .ringid = ringid, + .agg_max_wsize = size, + .ba_timeout = cpu_to_le16(timeout), + .amsdu = 0, + }; + + wil_dbg_wmi(wil, "%s(ring %d size %d timeout %d)\n", __func__, + ringid, size, timeout); + + return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd)); +} + +int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason) +{ + struct wmi_vring_ba_dis_cmd cmd = { + .ringid = ringid, + .reason = cpu_to_le16(reason), + }; + + wil_dbg_wmi(wil, "%s(ring %d reason %d)\n", __func__, + ringid, reason); + + return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd)); +} + +int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason) +{ + struct wmi_rcp_delba_cmd cmd = { + .cidxtid = cidxtid, + .reason = cpu_to_le16(reason), + }; + + wil_dbg_wmi(wil, "%s(CID %d TID %d reason %d)\n", __func__, + cidxtid & 0xf, (cidxtid >> 4) & 0xf, reason); + + return wmi_send(wil, WMI_RCP_DELBA_CMDID, &cmd, sizeof(cmd)); +} + +int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, + u16 status, bool amsdu, u16 agg_wsize, u16 timeout) +{ + int rc; + struct wmi_rcp_addba_resp_cmd cmd = { + .cidxtid = mk_cidxtid(cid, tid), + .dialog_token = token, + .status_code = cpu_to_le16(status), + /* bit 0: A-MSDU supported + * bit 1: policy (should be 0 for us) + * bits 2..5: TID + * bits 6..15: buffer size + */ + .ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) | + (agg_wsize << 6)), + .ba_timeout = cpu_to_le16(timeout), + }; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_rcp_addba_resp_sent_event evt; + } __packed reply; + + wil_dbg_wmi(wil, + "ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s\n", + cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-"); + + rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, &cmd, sizeof(cmd), + WMI_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply), 100); + if (rc) + return rc; + + if (reply.evt.status) { + wil_err(wil, "ADDBA response failed with status %d\n", + le16_to_cpu(reply.evt.status)); + rc = -EINVAL; + } + + return rc; +} + void wmi_event_flush(struct wil6210_priv *wil) { struct pending_wmi_event *evt, *t; diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 27b97432d1c2..8a4af613e191 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -29,8 +29,10 @@ /* General */ #define WILOCITY_MAX_ASSOC_STA (8) +#define WILOCITY_DEFAULT_ASSOC_STA (1) #define WMI_MAC_LEN (6) #define WMI_PROX_RANGE_NUM (3) +#define WMI_MAX_LOSS_DMG_BEACONS (32) /* List of Commands */ enum wmi_command_id { @@ -48,7 +50,7 @@ enum wmi_command_id { WMI_SET_WSC_STATUS_CMDID = 0x0041, WMI_PXMT_RANGE_CFG_CMDID = 0x0042, WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x0043, - WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, +/* WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, */ WMI_MEM_READ_CMDID = 0x0800, WMI_MEM_WR_CMDID = 0x0801, WMI_ECHO_CMDID = 0x0803, @@ -102,6 +104,8 @@ enum wmi_command_id { WMI_MAINTAIN_RESUME_CMDID = 0x0851, WMI_RS_MGMT_CMDID = 0x0852, WMI_RF_MGMT_CMDID = 0x0853, + WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x0854, + WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x0855, /* Performance monitoring commands */ WMI_BF_CTRL_CMDID = 0x0862, WMI_NOTIFY_REQ_CMDID = 0x0863, @@ -136,6 +140,7 @@ enum wmi_command_id { WMI_EAPOL_TX_CMDID = 0xf04c, WMI_MAC_ADDR_REQ_CMDID = 0xf04d, WMI_FW_VER_CMDID = 0xf04e, + WMI_PMC_CMDID = 0xf04f, }; /* @@ -283,8 +288,8 @@ enum wmi_scan_type { WMI_LONG_SCAN = 0, WMI_SHORT_SCAN = 1, WMI_PBC_SCAN = 2, - WMI_ACTIVE_SCAN = 3, - WMI_DIRECT_SCAN = 4, + WMI_DIRECT_SCAN = 3, + WMI_ACTIVE_SCAN = 4, }; struct wmi_start_scan_cmd { @@ -374,6 +379,17 @@ struct wmi_rf_mgmt_cmd { __le32 rf_mgmt_type; } __packed; +/* + * WMI_THERMAL_THROTTLING_CTRL_CMDID + */ +#define THERMAL_THROTTLING_USE_DEFAULT_MAX_TXOP_LENGTH (0xFFFFFFFF) + +struct wmi_thermal_throttling_ctrl_cmd { + __le32 time_on_usec; + __le32 time_off_usec; + __le32 max_txop_length_usec; +} __packed; + /* * WMI_RF_RX_TEST_CMDID */ @@ -586,6 +602,7 @@ struct wmi_vring_ba_en_cmd { u8 ringid; u8 agg_max_wsize; __le16 ba_timeout; + u8 amsdu; } __packed; /* @@ -647,6 +664,7 @@ enum wmi_cfg_rx_chain_cmd_action { enum wmi_cfg_rx_chain_cmd_decap_trans_type { WMI_DECAP_TYPE_802_3 = 0, WMI_DECAP_TYPE_NATIVE_WIFI = 1, + WMI_DECAP_TYPE_NONE = 2, }; enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type { @@ -784,9 +802,17 @@ struct wmi_echo_cmd { * * Measure MAC and radio temperatures */ + +/* Possible modes for temperature measurement */ +enum wmi_temperature_measure_mode { + TEMPERATURE_USE_OLD_VALUE = 0x1, + TEMPERATURE_MEASURE_NOW = 0x2, +}; + struct wmi_temp_sense_cmd { - __le32 measure_marlon_m_en; - __le32 measure_marlon_r_en; + __le32 measure_baseband_en; + __le32 measure_rf_en; + __le32 measure_mode; } __packed; /* @@ -842,6 +868,7 @@ enum wmi_event_id { WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839, WMI_RS_MGMT_DONE_EVENTID = 0x1852, WMI_RF_MGMT_STATUS_EVENTID = 0x1853, + WMI_THERMAL_THROTTLING_STATUS_EVENTID = 0x1855, WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838, WMI_RX_MGMT_PACKET_EVENTID = 0x1840, WMI_TX_MGMT_PACKET_EVENTID = 0x1841, @@ -858,6 +885,7 @@ enum wmi_event_id { WMI_FLASH_READ_DONE_EVENTID = 0x1902, WMI_FLASH_WRITE_DONE_EVENTID = 0x1903, /*P2P*/ + WMI_P2P_CFG_DONE_EVENTID = 0x1910, WMI_PORT_ALLOCATED_EVENTID = 0x1911, WMI_PORT_DELETED_EVENTID = 0x1912, WMI_LISTEN_STARTED_EVENTID = 0x1914, @@ -897,6 +925,15 @@ struct wmi_rf_mgmt_status_event { __le32 rf_status; } __packed; +/* + * WMI_THERMAL_THROTTLING_STATUS_EVENTID + */ +struct wmi_thermal_throttling_status_event { + __le32 time_on_usec; + __le32 time_off_usec; + __le32 max_txop_length_usec; +} __packed; + /* * WMI_GET_STATUS_DONE_EVENTID */ @@ -1052,14 +1089,23 @@ struct wmi_scan_complete_event { enum wmi_vring_ba_status { WMI_BA_AGREED = 0, WMI_BA_NON_AGREED = 1, + /* BA_EN in middle of teardown flow */ + WMI_BA_TD_WIP = 2, + /* BA_DIS or BA_EN in middle of BA SETUP flow */ + WMI_BA_SETUP_WIP = 3, + /* BA_EN when the BA session is already active */ + WMI_BA_SESSION_ACTIVE = 4, + /* BA_DIS when the BA session is not active */ + WMI_BA_SESSION_NOT_ACTIVE = 5, }; struct wmi_vring_ba_status_event { - __le16 status; + __le16 status; /* enum wmi_vring_ba_status */ u8 reserved[2]; u8 ringid; u8 agg_wsize; __le16 ba_timeout; + u8 amsdu; } __packed; /* @@ -1144,6 +1190,14 @@ struct wmi_get_pcp_channel_event { u8 reserved[3]; } __packed; +/* + * WMI_P2P_CFG_DONE_EVENTID + */ +struct wmi_p2p_cfg_done_event { + u8 status; /* wmi_fw_status */ + u8 reserved[3]; +} __packed; + /* * WMI_PORT_ALLOCATED_EVENTID */ @@ -1272,8 +1326,8 @@ struct wmi_echo_event { * Measure MAC and radio temperatures */ struct wmi_temp_sense_done_event { - __le32 marlon_m_t1000; - __le32 marlon_r_t1000; + __le32 baseband_t1000; + __le32 rf_t1000; } __packed; #endif /* __WILOCITY_WMI_H__ */ diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 9183f1cf89a7..55db9f03eb2a 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include @@ -2699,16 +2698,7 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) domain[REGDOMAINSZ] = 0; rc = -EINVAL; for (i = 0; i < ARRAY_SIZE(channel_table); i++) { - /* strcasecmp doesn't exist in the library */ - char *a = channel_table[i].name; - char *b = domain; - while (*a) { - char c1 = *a++; - char c2 = *b++; - if (tolower(c1) != tolower(c2)) - break; - } - if (!*a && !*b) { + if (!strcasecmp(channel_table[i].name, domain)) { priv->config_reg_domain = channel_table[i].reg_domain; rc = 0; } diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 64a5b672e30a..759fb8d41fc9 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -166,6 +166,15 @@ config B43_PHY_LCN Say N, this is BROKEN and crashes driver. +config B43_PHY_AC + bool "Support for AC-PHY (802.11ac) devices (BROKEN)" + depends on B43 && B43_BCMA && BROKEN + ---help--- + This PHY type can be found in the following chipsets: + PCI: BCM4352, BCM4360 + + Say N, this is BROKEN and crashes driver. + # This config option automatically enables b43 LEDS support, # if it's possible. config B43_LEDS diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 9f7965aae93d..c624d4d90e4f 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -13,6 +13,7 @@ b43-$(CONFIG_B43_PHY_HT) += phy_ht.o b43-$(CONFIG_B43_PHY_HT) += tables_phy_ht.o b43-$(CONFIG_B43_PHY_HT) += radio_2059.o b43-$(CONFIG_B43_PHY_LCN) += phy_lcn.o tables_phy_lcn.o +b43-$(CONFIG_B43_PHY_AC) += phy_ac.o b43-y += sysfs.o b43-y += xmit.o b43-y += dma.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index bb12586cd7cd..036552439816 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -500,6 +500,8 @@ enum { #define B43_BCMA_IOCTL_PHY_BW_10MHZ 0x00000000 /* 10 MHz bandwidth, 40 MHz PHY */ #define B43_BCMA_IOCTL_PHY_BW_20MHZ 0x00000040 /* 20 MHz bandwidth, 80 MHz PHY */ #define B43_BCMA_IOCTL_PHY_BW_40MHZ 0x00000080 /* 40 MHz bandwidth, 160 MHz PHY */ +#define B43_BCMA_IOCTL_PHY_BW_80MHZ 0x000000C0 /* 80 MHz bandwidth */ +#define B43_BCMA_IOCTL_DAC 0x00000300 /* Highspeed DAC mode control field */ #define B43_BCMA_IOCTL_GMODE 0x00002000 /* G Mode Enable */ /* BCMA 802.11 core specific IO status (BCMA_IOST) flags */ @@ -941,6 +943,7 @@ struct b43_wl { bool beacon1_uploaded; bool beacon_templates_virgin; /* Never wrote the templates? */ struct work_struct beacon_update_trigger; + spinlock_t beacon_lock; /* The current QOS parameters for the 4 queues. */ struct b43_qos_params qos_params[B43_QOS_QUEUE_NUM]; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 47731cb0d815..2c9088633ec6 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1262,6 +1262,23 @@ static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode) flags |= B43_BCMA_IOCTL_GMODE; b43_device_enable(dev, flags); + if (dev->phy.type == B43_PHYTYPE_AC) { + u16 tmp; + + tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL); + tmp &= ~B43_BCMA_IOCTL_DAC; + tmp |= 0x100; + bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp); + + tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL); + tmp &= ~B43_BCMA_IOCTL_PHY_CLKEN; + bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp); + + tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL); + tmp |= B43_BCMA_IOCTL_PHY_CLKEN; + bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp); + } + bcma_core_set_clockmode(dev->dev->bdev, BCMA_CLKMODE_FAST); b43_bcma_phy_reset(dev); bcma_core_pll_ctl(dev->dev->bdev, req, status, true); @@ -1601,12 +1618,26 @@ static void b43_write_beacon_template(struct b43_wldev *dev, unsigned int rate; u16 ctl; int antenna; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon); + struct ieee80211_tx_info *info; + unsigned long flags; + struct sk_buff *beacon_skb; - bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); - len = min_t(size_t, dev->wl->current_beacon->len, - 0x200 - sizeof(struct b43_plcp_hdr6)); + spin_lock_irqsave(&dev->wl->beacon_lock, flags); + info = IEEE80211_SKB_CB(dev->wl->current_beacon); rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value; + /* Clone the beacon, so it cannot go away, while we write it to hw. */ + beacon_skb = skb_clone(dev->wl->current_beacon, GFP_ATOMIC); + spin_unlock_irqrestore(&dev->wl->beacon_lock, flags); + + if (!beacon_skb) { + b43dbg(dev->wl, "Could not upload beacon. " + "Failed to clone beacon skb."); + return; + } + + bcn = (const struct ieee80211_mgmt *)(beacon_skb->data); + len = min_t(size_t, beacon_skb->len, + 0x200 - sizeof(struct b43_plcp_hdr6)); b43_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); @@ -1674,6 +1705,8 @@ static void b43_write_beacon_template(struct b43_wldev *dev, B43_SHM_SH_DTIMPER, 0); } b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset); + + dev_kfree_skb_any(beacon_skb); } static void b43_upload_beacon0(struct b43_wldev *dev) @@ -1790,13 +1823,13 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) mutex_unlock(&wl->mutex); } -/* Asynchronously update the packet templates in template RAM. - * Locking: Requires wl->mutex to be locked. */ +/* Asynchronously update the packet templates in template RAM. */ static void b43_update_templates(struct b43_wl *wl) { - struct sk_buff *beacon; + struct sk_buff *beacon, *old_beacon; + unsigned long flags; - /* This is the top half of the ansynchronous beacon update. + /* This is the top half of the asynchronous beacon update. * The bottom half is the beacon IRQ. * Beacon update must be asynchronous to avoid sending an * invalid beacon. This can happen for example, if the firmware @@ -1810,12 +1843,17 @@ static void b43_update_templates(struct b43_wl *wl) if (unlikely(!beacon)) return; - if (wl->current_beacon) - dev_kfree_skb_any(wl->current_beacon); + spin_lock_irqsave(&wl->beacon_lock, flags); + old_beacon = wl->current_beacon; wl->current_beacon = beacon; wl->beacon0_uploaded = false; wl->beacon1_uploaded = false; + spin_unlock_irqrestore(&wl->beacon_lock, flags); + ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger); + + if (old_beacon) + dev_kfree_skb_any(old_beacon); } static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) @@ -4318,6 +4356,7 @@ redo: mutex_unlock(&wl->mutex); cancel_delayed_work_sync(&dev->periodic_work); cancel_work_sync(&wl->tx_work); + b43_leds_stop(dev); mutex_lock(&wl->mutex); dev = wl->current_dev; if (!dev || b43_status(dev) < B43_STAT_STARTED) { @@ -4504,6 +4543,12 @@ static int b43_phy_versioning(struct b43_wldev *dev) if (phy_rev > 1) unsupported = 1; break; +#endif +#ifdef CONFIG_B43_PHY_AC + case B43_PHYTYPE_AC: + if (phy_rev > 1) + unsupported = 1; + break; #endif default: unsupported = 1; @@ -4601,6 +4646,10 @@ static int b43_phy_versioning(struct b43_wldev *dev) if (radio_id != 0x2064) unsupported = 1; break; + case B43_PHYTYPE_AC: + if (radio_id != 0x2069) + unsupported = 1; + break; default: B43_WARN_ON(1); } @@ -5094,7 +5143,6 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, { struct b43_wl *wl = hw_to_b43_wl(hw); - /* FIXME: add locking */ b43_update_templates(wl); return 0; @@ -5584,6 +5632,7 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) wl->hw = hw; mutex_init(&wl->mutex); spin_lock_init(&wl->hardirq_lock); + spin_lock_init(&wl->beacon_lock); INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); INIT_WORK(&wl->tx_work, b43_tx_work); diff --git a/drivers/net/wireless/b43/phy_ac.c b/drivers/net/wireless/b43/phy_ac.c new file mode 100644 index 000000000000..e75633d67938 --- /dev/null +++ b/drivers/net/wireless/b43/phy_ac.c @@ -0,0 +1,92 @@ +/* + * Broadcom B43 wireless driver + * IEEE 802.11ac AC-PHY support + * + * Copyright (c) 2015 Rafał Miłecki + * + * 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 "b43.h" +#include "phy_ac.h" + +/************************************************** + * Basic PHY ops + **************************************************/ + +static int b43_phy_ac_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_ac *phy_ac; + + phy_ac = kzalloc(sizeof(*phy_ac), GFP_KERNEL); + if (!phy_ac) + return -ENOMEM; + dev->phy.ac = phy_ac; + + return 0; +} + +static void b43_phy_ac_op_free(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_ac *phy_ac = phy->ac; + + kfree(phy_ac); + phy->ac = NULL; +} + +static void b43_phy_ac_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, + u16 set) +{ + b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, + (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set); +} + +static u16 b43_phy_ac_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO24_DATA); +} + +static void b43_phy_ac_op_radio_write(struct b43_wldev *dev, u16 reg, + u16 value) +{ + b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO24_DATA, value); +} + +static unsigned int b43_phy_ac_op_get_default_chan(struct b43_wldev *dev) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + return 11; + return 36; +} + +static enum b43_txpwr_result +b43_phy_ac_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi) +{ + return B43_TXPWR_RES_DONE; +} + +static void b43_phy_ac_op_adjust_txpower(struct b43_wldev *dev) +{ +} + +/************************************************** + * PHY ops struct + **************************************************/ + +const struct b43_phy_operations b43_phyops_ac = { + .allocate = b43_phy_ac_op_allocate, + .free = b43_phy_ac_op_free, + .phy_maskset = b43_phy_ac_op_maskset, + .radio_read = b43_phy_ac_op_radio_read, + .radio_write = b43_phy_ac_op_radio_write, + .get_default_chan = b43_phy_ac_op_get_default_chan, + .recalc_txpower = b43_phy_ac_op_recalc_txpower, + .adjust_txpower = b43_phy_ac_op_adjust_txpower, +}; diff --git a/drivers/net/wireless/b43/phy_ac.h b/drivers/net/wireless/b43/phy_ac.h new file mode 100644 index 000000000000..d1ca79e0eb24 --- /dev/null +++ b/drivers/net/wireless/b43/phy_ac.h @@ -0,0 +1,38 @@ +#ifndef B43_PHY_AC_H_ +#define B43_PHY_AC_H_ + +#include "phy_common.h" + +#define B43_PHY_AC_BBCFG 0x001 +#define B43_PHY_AC_BBCFG_RSTCCA 0x4000 /* Reset CCA */ +#define B43_PHY_AC_BANDCTL 0x003 /* Band control */ +#define B43_PHY_AC_BANDCTL_5GHZ 0x0001 +#define B43_PHY_AC_TABLE_ID 0x00d +#define B43_PHY_AC_TABLE_OFFSET 0x00e +#define B43_PHY_AC_TABLE_DATA1 0x00f +#define B43_PHY_AC_TABLE_DATA2 0x010 +#define B43_PHY_AC_TABLE_DATA3 0x011 +#define B43_PHY_AC_CLASSCTL 0x140 /* Classifier control */ +#define B43_PHY_AC_CLASSCTL_CCKEN 0x0001 /* CCK enable */ +#define B43_PHY_AC_CLASSCTL_OFDMEN 0x0002 /* OFDM enable */ +#define B43_PHY_AC_CLASSCTL_WAITEDEN 0x0004 /* Waited enable */ +#define B43_PHY_AC_BW1A 0x371 +#define B43_PHY_AC_BW2 0x372 +#define B43_PHY_AC_BW3 0x373 +#define B43_PHY_AC_BW4 0x374 +#define B43_PHY_AC_BW5 0x375 +#define B43_PHY_AC_BW6 0x376 +#define B43_PHY_AC_RFCTL_CMD 0x408 +#define B43_PHY_AC_C1_CLIP 0x6d4 +#define B43_PHY_AC_C1_CLIP_DIS 0x4000 +#define B43_PHY_AC_C2_CLIP 0x8d4 +#define B43_PHY_AC_C2_CLIP_DIS 0x4000 +#define B43_PHY_AC_C3_CLIP 0xad4 +#define B43_PHY_AC_C3_CLIP_DIS 0x4000 + +struct b43_phy_ac { +}; + +extern const struct b43_phy_operations b43_phyops_ac; + +#endif /* B43_PHY_AC_H_ */ diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index ee27b06074e1..ec2b9c577b90 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -33,6 +33,7 @@ #include "phy_lp.h" #include "phy_ht.h" #include "phy_lcn.h" +#include "phy_ac.h" #include "b43.h" #include "main.h" @@ -68,6 +69,11 @@ int b43_phy_allocate(struct b43_wldev *dev) case B43_PHYTYPE_LCN: #ifdef CONFIG_B43_PHY_LCN phy->ops = &b43_phyops_lcn; +#endif + break; + case B43_PHYTYPE_AC: +#ifdef CONFIG_B43_PHY_AC + phy->ops = &b43_phyops_ac; #endif break; } @@ -572,7 +578,8 @@ void b43_phy_force_clock(struct b43_wldev *dev, bool force) u32 tmp; WARN_ON(dev->phy.type != B43_PHYTYPE_N && - dev->phy.type != B43_PHYTYPE_HT); + dev->phy.type != B43_PHYTYPE_HT && + dev->phy.type != B43_PHYTYPE_AC); switch (dev->dev->bus_type) { #ifdef CONFIG_B43_BCMA diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 3912274f71e3..78d86526799e 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -222,6 +222,8 @@ struct b43_phy { struct b43_phy_ht *ht; /* LCN-PHY specific information */ struct b43_phy_lcn *lcn; + /* AC-PHY specific information */ + struct b43_phy_ac *ac; }; /* Band support flags. */ diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index 896177690394..9501420340a9 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -1743,25 +1743,6 @@ u16 freq_r3A_value(u16 frequency) return value; } -void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev) -{ - static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; - static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; - u16 tmp = b43legacy_radio_read16(dev, 0x001E); - int i; - int j; - - for (i = 0; i < 5; i++) { - for (j = 0; j < 5; j++) { - if (tmp == (data_high[i] | data_low[j])) { - b43legacy_phy_write(dev, 0x0069, (i - j) << 8 | - 0x00C0); - return; - } - } - } -} - int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, u8 channel, int synthetic_pu_workaround) diff --git a/drivers/net/wireless/b43legacy/radio.h b/drivers/net/wireless/b43legacy/radio.h index bccb3d7da682..dd2976d1d561 100644 --- a/drivers/net/wireless/b43legacy/radio.h +++ b/drivers/net/wireless/b43legacy/radio.h @@ -92,7 +92,6 @@ void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val); void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val); void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev); -void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev); u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev); #endif /* B43legacy_RADIO_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 9880dae2a569..7944224e3fc9 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -97,25 +97,6 @@ static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func) { } -static bool brcmf_sdiod_pm_resume_error(struct brcmf_sdio_dev *sdiodev) -{ - bool is_err = false; -#ifdef CONFIG_PM_SLEEP - is_err = atomic_read(&sdiodev->suspend); -#endif - return is_err; -} - -static void brcmf_sdiod_pm_resume_wait(struct brcmf_sdio_dev *sdiodev, - wait_queue_head_t *wq) -{ -#ifdef CONFIG_PM_SLEEP - int retry = 0; - while (atomic_read(&sdiodev->suspend) && retry++ != 30) - wait_event_timeout(*wq, false, HZ/100); -#endif -} - int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) { int ret = 0; @@ -244,10 +225,6 @@ static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn, brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", write, fn, addr, regsz); - brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_word_wait); - if (brcmf_sdiod_pm_resume_error(sdiodev)) - return -EIO; - /* only allow byte access on F0 */ if (WARN_ON(regsz > 1 && !fn)) return -EINVAL; @@ -292,6 +269,12 @@ static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn, return ret; } +static void brcmf_sdiod_nomedium_state(struct brcmf_sdio_dev *sdiodev) +{ + sdiodev->state = BRCMF_STATE_NOMEDIUM; + brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN); +} + static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, u8 regsz, void *data, bool write) { @@ -299,7 +282,7 @@ static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, s32 retry = 0; int ret; - if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM) + if (sdiodev->state == BRCMF_STATE_NOMEDIUM) return -ENOMEDIUM; /* @@ -325,7 +308,7 @@ static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, retry++ < SDIOH_API_ACCESS_RETRY_LIMIT); if (ret == -ENOMEDIUM) - brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM); + brcmf_sdiod_nomedium_state(sdiodev); else if (ret != 0) { /* * SleepCSR register access can fail when @@ -348,7 +331,7 @@ brcmf_sdiod_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address) int err = 0, i; u8 addr[3]; - if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM) + if (sdiodev->state == BRCMF_STATE_NOMEDIUM) return -ENOMEDIUM; addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK; @@ -462,10 +445,6 @@ static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn, unsigned int req_sz; int err; - brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); - if (brcmf_sdiod_pm_resume_error(sdiodev)) - return -EIO; - /* Single skb use the standard mmc interface */ req_sz = pkt->len + 3; req_sz &= (uint)~3; @@ -481,7 +460,7 @@ static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn, err = sdio_readsb(sdiodev->func[fn], ((u8 *)(pkt->data)), addr, req_sz); if (err == -ENOMEDIUM) - brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM); + brcmf_sdiod_nomedium_state(sdiodev); return err; } @@ -516,10 +495,6 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, if (!pktlist->qlen) return -EINVAL; - brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); - if (brcmf_sdiod_pm_resume_error(sdiodev)) - return -EIO; - target_list = pktlist; /* for host with broken sg support, prepare a page aligned list */ __skb_queue_head_init(&local_list); @@ -620,8 +595,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error; if (ret == -ENOMEDIUM) { - brcmf_bus_change_state(sdiodev->bus_if, - BRCMF_BUS_NOMEDIUM); + brcmf_sdiod_nomedium_state(sdiodev); break; } else if (ret != 0) { brcmf_err("CMD53 sg block %s failed %d\n", @@ -996,18 +970,20 @@ out: } #define BRCMF_SDIO_DEVICE(dev_id) \ - {SDIO_DEVICE(BRCM_SDIO_VENDOR_ID_BROADCOM, dev_id)} + {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, dev_id)} /* devices we support, null terminated */ static const struct sdio_device_id brcmf_sdmmc_ids[] = { - BRCMF_SDIO_DEVICE(BRCM_SDIO_43143_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_43241_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_4329_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_4330_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_4334_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_43362_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_4335_4339_DEVICE_ID), - BRCMF_SDIO_DEVICE(BRCM_SDIO_4354_DEVICE_ID), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43143), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43241), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4329), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4330), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4334), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354), { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); @@ -1074,9 +1050,9 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, bus_if->wowl_supported = true; #endif + sdiodev->sleeping = false; atomic_set(&sdiodev->suspend, false); - init_waitqueue_head(&sdiodev->request_word_wait); - init_waitqueue_head(&sdiodev->request_buffer_wait); + init_waitqueue_head(&sdiodev->idle_wait); brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n"); err = brcmf_sdiod_probe(sdiodev); @@ -1138,12 +1114,23 @@ void brcmf_sdio_wowl_config(struct device *dev, bool enabled) #ifdef CONFIG_PM_SLEEP static int brcmf_ops_sdio_suspend(struct device *dev) { - struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; + struct brcmf_bus *bus_if; + struct brcmf_sdio_dev *sdiodev; mmc_pm_flag_t sdio_flags; brcmf_dbg(SDIO, "Enter\n"); + bus_if = dev_get_drvdata(dev); + sdiodev = bus_if->bus_priv.sdio; + + /* wait for watchdog to go idle */ + if (wait_event_timeout(sdiodev->idle_wait, sdiodev->sleeping, + msecs_to_jiffies(3 * BRCMF_WD_POLL_MS)) == 0) { + brcmf_err("bus still active\n"); + return -EBUSY; + } + /* disable watchdog */ + brcmf_sdio_wd_timer(sdiodev->bus, 0); atomic_set(&sdiodev->suspend, true); if (sdiodev->wowl_enabled) { @@ -1155,9 +1142,6 @@ static int brcmf_ops_sdio_suspend(struct device *dev) if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags)) brcmf_err("Failed to set pm_flags %x\n", sdio_flags); } - - brcmf_sdio_wd_timer(sdiodev->bus, 0); - return 0; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/brcm80211/brcmfmac/bus.h index ef344e47218a..89e6a4dc105e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h @@ -33,11 +33,8 @@ /* The level of bus communication with the dongle */ enum brcmf_bus_state { - BRCMF_BUS_UNKNOWN, /* Not determined yet */ - BRCMF_BUS_NOMEDIUM, /* No medium access to dongle */ BRCMF_BUS_DOWN, /* Not ready for frame transfers */ - BRCMF_BUS_LOAD, /* Download access only (CPU reset) */ - BRCMF_BUS_DATA /* Ready for frame transfers */ + BRCMF_BUS_UP /* Ready for frame transfers */ }; /* The level of bus communication with the dongle */ @@ -188,22 +185,6 @@ void brcmf_bus_wowl_config(struct brcmf_bus *bus, bool enabled) bus->ops->wowl_config(bus->dev, enabled); } -static inline bool brcmf_bus_ready(struct brcmf_bus *bus) -{ - return bus->state == BRCMF_BUS_LOAD || bus->state == BRCMF_BUS_DATA; -} - -static inline void brcmf_bus_change_state(struct brcmf_bus *bus, - enum brcmf_bus_state new_state) -{ - /* NOMEDIUM is permanent */ - if (bus->state == BRCMF_BUS_NOMEDIUM) - return; - - brcmf_dbg(TRACE, "%d -> %d\n", bus->state, new_state); - bus->state = new_state; -} - /* * interface functions from common layer */ @@ -226,6 +207,9 @@ void brcmf_txflowblock(struct device *dev, bool state); /* Notify the bus has transferred the tx packet to firmware */ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success); +/* Configure the "global" bus state used by upper layers */ +void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state); + int brcmf_bus_start(struct device *dev); s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len); void brcmf_bus_add_txhdrlen(struct device *dev, uint len); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index 3aecc5f48719..b59b8c6c42ab 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -38,6 +38,7 @@ #include "proto.h" #include "vendor.h" #include "bus.h" +#include "common.h" #define BRCMF_SCAN_IE_LEN_MAX 2048 #define BRCMF_PNO_VERSION 2 @@ -452,16 +453,16 @@ static void convert_key_from_CPU(struct brcmf_wsec_key *key, } static int -send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key) +send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key) { int err; struct brcmf_wsec_key_le key_le; convert_key_from_CPU(key, &key_le); - brcmf_netdev_wait_pend8021x(ndev); + brcmf_netdev_wait_pend8021x(ifp); - err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le, + err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le, sizeof(key_le)); if (err) @@ -1228,7 +1229,25 @@ static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof) memset(prof, 0, sizeof(*prof)); } -static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) +static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e) +{ + u16 reason; + + switch (e->event_code) { + case BRCMF_E_DEAUTH: + case BRCMF_E_DEAUTH_IND: + case BRCMF_E_DISASSOC_IND: + reason = e->reason; + break; + case BRCMF_E_LINK: + default: + reason = 0; + break; + } + return reason; +} + +static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy); s32 err = 0; @@ -1243,7 +1262,8 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) brcmf_err("WLC_DISASSOC failed (%d)\n", err); } clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state); - cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL); + cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0, + GFP_KERNEL); } clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state); @@ -1413,7 +1433,7 @@ brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) if (!check_vif_up(ifp->vif)) return -EIO; - brcmf_link_down(ifp->vif); + brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING); brcmf_dbg(TRACE, "Exit\n"); @@ -1670,7 +1690,7 @@ brcmf_set_sharedkey(struct net_device *ndev, brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n", key.len, key.index, key.algo); brcmf_dbg(CONN, "key \"%s\"\n", key.data); - err = send_key_to_dongle(ndev, &key); + err = send_key_to_dongle(netdev_priv(ndev), &key); if (err) return err; @@ -2052,7 +2072,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, /* check for key index change */ if (key.len == 0) { /* key delete */ - err = send_key_to_dongle(ndev, &key); + err = send_key_to_dongle(ifp, &key); if (err) brcmf_err("key delete error (%d)\n", err); } else { @@ -2108,7 +2128,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("Invalid cipher (0x%x)\n", params->cipher); return -EINVAL; } - err = send_key_to_dongle(ndev, &key); + err = send_key_to_dongle(ifp, &key); if (err) brcmf_err("wsec_key error (%d)\n", err); } @@ -2121,7 +2141,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, struct key_params *params) { struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_wsec_key key; + struct brcmf_wsec_key *key; s32 val; s32 wsec; s32 err = 0; @@ -2132,54 +2152,62 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, if (!check_vif_up(ifp->vif)) return -EIO; + if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) { + /* we ignore this key index in this case */ + brcmf_err("invalid key index (%d)\n", key_idx); + return -EINVAL; + } + if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) && (params->cipher != WLAN_CIPHER_SUITE_WEP104)) { brcmf_dbg(TRACE, "Exit"); return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params); } - memset(&key, 0, sizeof(key)); - key.len = (u32) params->key_len; - key.index = (u32) key_idx; + key = &ifp->vif->profile.key[key_idx]; + memset(key, 0, sizeof(*key)); - if (key.len > sizeof(key.data)) { - brcmf_err("Too long key length (%u)\n", key.len); + if (params->key_len > sizeof(key->data)) { + brcmf_err("Too long key length (%u)\n", params->key_len); err = -EINVAL; goto done; } - memcpy(key.data, params->key, key.len); + key->len = params->key_len; + key->index = key_idx; - key.flags = BRCMF_PRIMARY_KEY; + memcpy(key->data, params->key, key->len); + + key->flags = BRCMF_PRIMARY_KEY; switch (params->cipher) { case WLAN_CIPHER_SUITE_WEP40: - key.algo = CRYPTO_ALGO_WEP1; + key->algo = CRYPTO_ALGO_WEP1; val = WEP_ENABLED; brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n"); break; case WLAN_CIPHER_SUITE_WEP104: - key.algo = CRYPTO_ALGO_WEP128; + key->algo = CRYPTO_ALGO_WEP128; val = WEP_ENABLED; brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n"); break; case WLAN_CIPHER_SUITE_TKIP: if (!brcmf_is_apmode(ifp->vif)) { brcmf_dbg(CONN, "Swapping RX/TX MIC key\n"); - memcpy(keybuf, &key.data[24], sizeof(keybuf)); - memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); - memcpy(&key.data[16], keybuf, sizeof(keybuf)); + memcpy(keybuf, &key->data[24], sizeof(keybuf)); + memcpy(&key->data[24], &key->data[16], sizeof(keybuf)); + memcpy(&key->data[16], keybuf, sizeof(keybuf)); } - key.algo = CRYPTO_ALGO_TKIP; + key->algo = CRYPTO_ALGO_TKIP; val = TKIP_ENABLED; brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n"); break; case WLAN_CIPHER_SUITE_AES_CMAC: - key.algo = CRYPTO_ALGO_AES_CCM; + key->algo = CRYPTO_ALGO_AES_CCM; val = AES_ENABLED; brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n"); break; case WLAN_CIPHER_SUITE_CCMP: - key.algo = CRYPTO_ALGO_AES_CCM; + key->algo = CRYPTO_ALGO_AES_CCM; val = AES_ENABLED; brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n"); break; @@ -2189,7 +2217,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, goto done; } - err = send_key_to_dongle(ndev, &key); + err = send_key_to_dongle(ifp, key); if (err) goto done; @@ -2222,7 +2250,7 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, if (!check_vif_up(ifp->vif)) return -EIO; - if (key_idx >= DOT11_MAX_DEFAULT_KEYS) { + if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) { /* we ignore this key index in this case */ brcmf_err("invalid key index (%d)\n", key_idx); return -EINVAL; @@ -2237,7 +2265,7 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, brcmf_dbg(CONN, "key index (%d)\n", key_idx); /* Set the new key/index */ - err = send_key_to_dongle(ndev, &key); + err = send_key_to_dongle(ifp, &key); brcmf_dbg(TRACE, "Exit\n"); return err; @@ -2305,6 +2333,39 @@ brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, return -EOPNOTSUPP; } +static void +brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp) +{ + s32 err; + u8 key_idx; + struct brcmf_wsec_key *key; + s32 wsec; + + for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) { + key = &ifp->vif->profile.key[key_idx]; + if ((key->algo == CRYPTO_ALGO_WEP1) || + (key->algo == CRYPTO_ALGO_WEP128)) + break; + } + if (key_idx == BRCMF_MAX_DEFAULT_KEYS) + return; + + err = send_key_to_dongle(ifp, key); + if (err) { + brcmf_err("Setting WEP key failed (%d)\n", err); + return; + } + err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec); + if (err) { + brcmf_err("get wsec error (%d)\n", err); + return; + } + wsec |= WEP_ENABLED; + err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec); + if (err) + brcmf_err("set wsec error (%d)\n", err); +} + static s32 brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_info *sinfo) @@ -2333,10 +2394,10 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("GET STA INFO failed, %d\n", err); goto done; } - sinfo->filled = STATION_INFO_INACTIVE_TIME; + sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME); sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000; if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) { - sinfo->filled |= STATION_INFO_CONNECTED_TIME; + sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME); sinfo->connected_time = le32_to_cpu(sta_info_le.in); } brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n", @@ -2354,7 +2415,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("Could not get rate (%d)\n", err); goto done; } else { - sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); sinfo->txrate.legacy = rate * 5; brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2); } @@ -2369,7 +2430,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, goto done; } else { rssi = le32_to_cpu(scb_val.val); - sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); sinfo->signal = rssi; brcmf_dbg(CONN, "RSSI %d dBm\n", rssi); } @@ -2396,7 +2457,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, brcmf_dbg(CONN, "DTIM peroid %d\n", dtim_period); } - sinfo->filled |= STATION_INFO_BSS_PARAM; + sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM); } } else err = -EPERM; @@ -2999,7 +3060,7 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, * disassociate from AP to save power while system is * in suspended state */ - brcmf_link_down(vif); + brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED); /* Make sure WPA_Supplicant receives all the event * generated due to DISASSOC call to the fw to keep * the state fw and WPA_Supplicant state consistent @@ -3695,17 +3756,12 @@ static u32 brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd) { - __le32 iecount_le; - __le32 pktflag_le; - strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1); iebuf[VNDR_IE_CMD_LEN - 1] = '\0'; - iecount_le = cpu_to_le32(1); - memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le)); + put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]); - pktflag_le = cpu_to_le32(pktflag); - memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le)); + put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]); memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len); @@ -3924,6 +3980,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); const struct brcmf_tlv *ssid_ie; + const struct brcmf_tlv *country_ie; struct brcmf_ssid_le ssid_le; s32 err = -EPERM; const struct brcmf_tlv *rsn_ie; @@ -3933,6 +3990,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct brcmf_fil_bss_enable_le bss_enable; u16 chanspec; bool mbss; + int is_11d; brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n", settings->chandef.chan->hw_value, @@ -3941,10 +3999,16 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n", settings->ssid, settings->ssid_len, settings->auth_type, settings->inactivity_timeout); - dev_role = ifp->vif->wdev.iftype; mbss = ifp->vif->mbss; + /* store current 11d setting */ + brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY, &ifp->vif->is_11d); + country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, + settings->beacon.tail_len, + WLAN_EID_COUNTRY); + is_11d = country_ie ? 1 : 0; + memset(&ssid_le, 0, sizeof(ssid_le)); if (settings->ssid == NULL || settings->ssid_len == 0) { ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; @@ -4010,6 +4074,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, goto exit; } + if (is_11d != ifp->vif->is_11d) { + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY, + is_11d); + if (err < 0) { + brcmf_err("Regulatory Set Error, %d\n", err); + goto exit; + } + } if (settings->beacon_interval) { err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, settings->beacon_interval); @@ -4042,6 +4114,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("SET INFRA error %d\n", err); goto exit; } + } else if (WARN_ON(is_11d != ifp->vif->is_11d)) { + /* Multiple-BSS should use same 11d configuration */ + err = -EINVAL; + goto exit; } if (dev_role == NL80211_IFTYPE_AP) { if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss)) @@ -4057,6 +4133,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("BRCMF_C_UP error (%d)\n", err); goto exit; } + /* On DOWN the firmware removes the WEP keys, reconfigure + * them if they were set. + */ + brcmf_cfg80211_reconfigure_wep(ifp); memset(&join_params, 0, sizeof(join_params)); /* join parameters starts with ssid */ @@ -4133,6 +4213,11 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) brcmf_err("setting INFRA mode failed %d\n", err); if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) brcmf_fil_iovar_int_set(ifp, "mbss", 0); + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY, + ifp->vif->is_11d); + if (err < 0) + brcmf_err("restoring REGULATORY setting failed %d\n", + err); /* Bring device back up so it can be used again */ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); if (err < 0) @@ -4197,6 +4282,34 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, return err; } +static int +brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_parameters *params) +{ + struct brcmf_if *ifp = netdev_priv(ndev); + s32 err; + + brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac, + params->sta_flags_mask, params->sta_flags_set); + + /* Ignore all 00 MAC */ + if (is_zero_ether_addr(mac)) + return 0; + + if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) + return 0; + + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED)) + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE, + (void *)mac, ETH_ALEN); + else + err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE, + (void *)mac, ETH_ALEN); + if (err < 0) + brcmf_err("Setting SCB (de-)authorize failed, %d\n", err); + + return err; +} static void brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy, @@ -4471,6 +4584,7 @@ static struct cfg80211_ops wl_cfg80211_ops = { .stop_ap = brcmf_cfg80211_stop_ap, .change_beacon = brcmf_cfg80211_change_beacon, .del_station = brcmf_cfg80211_del_station, + .change_station = brcmf_cfg80211_change_station, .sched_scan_start = brcmf_cfg80211_sched_scan_start, .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register, @@ -4778,7 +4892,6 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) && (reason == BRCMF_E_STATUS_SUCCESS)) { memset(&sinfo, 0, sizeof(sinfo)); - sinfo.filled = STATION_INFO_ASSOC_REQ_IES; if (!data) { brcmf_err("No IEs present in ASSOC/REASSOC_IND"); return -EINVAL; @@ -4833,7 +4946,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, if (!brcmf_is_ibssmode(ifp->vif)) { brcmf_bss_connect_done(cfg, ndev, e, false); } - brcmf_link_down(ifp->vif); + brcmf_link_down(ifp->vif, brcmf_map_fw_linkdown_reason(e)); brcmf_init_prof(ndev_to_prof(ndev)); if (ndev != cfg_to_ndev(cfg)) complete(&cfg->vif_disabled); @@ -5774,7 +5887,7 @@ static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp) * from AP to save power */ if (check_vif_up(ifp->vif)) { - brcmf_link_down(ifp->vif); + brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED); /* Make sure WPA_Supplicant receives all the event generated due to DISASSOC call to the fw to keep @@ -5876,6 +5989,29 @@ int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, vif_event_equals(event, action), timeout); } +static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *req) +{ + struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); + struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); + struct brcmf_fil_country_le ccreq; + int i; + + brcmf_dbg(TRACE, "enter: initiator=%d, alpha=%c%c\n", req->initiator, + req->alpha2[0], req->alpha2[1]); + + /* ignore non-ISO3166 country codes */ + for (i = 0; i < sizeof(req->alpha2); i++) + if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { + brcmf_err("not a ISO3166 code\n"); + return; + } + memset(&ccreq, 0, sizeof(ccreq)); + ccreq.rev = cpu_to_le32(-1); + memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2)); + brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq)); +} + static void brcmf_free_wiphy(struct wiphy *wiphy) { kfree(wiphy->iface_combinations); @@ -5952,6 +6088,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, goto priv_out; brcmf_dbg(INFO, "Registering custom regulatory\n"); + wiphy->reg_notifier = brcmf_cfg80211_reg_notifier; wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h index 9e98b8d52757..d9e6d01b2b69 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h @@ -75,6 +75,8 @@ #define BRCMF_VNDR_IE_P2PAF_SHIFT 12 +#define BRCMF_MAX_DEFAULT_KEYS 4 + /** * enum brcmf_scan_status - scan engine status @@ -125,11 +127,13 @@ struct brcmf_cfg80211_security { * @ssid: ssid of associated/associating ap. * @bssid: bssid of joined/joining ibss. * @sec: security information. + * @key: key information */ struct brcmf_cfg80211_profile { struct brcmf_ssid ssid; u8 bssid[ETH_ALEN]; struct brcmf_cfg80211_security sec; + struct brcmf_wsec_key key[BRCMF_MAX_DEFAULT_KEYS]; }; /** @@ -196,6 +200,7 @@ struct brcmf_cfg80211_vif { struct list_head list; u16 mgmt_rx_reg; bool mbss; + int is_11d; }; /* association inform */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c index ddae0b5e56ec..04d2ca0d87d6 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c @@ -101,14 +101,7 @@ /* ARM Cortex M3 core, ID 0x82a */ #define BCM4329_CORE_ARM_BASE 0x18002000 #define BCM4329_RAMSIZE 0x48000 - /* bcm43143 */ -/* SDIO device core */ -#define BCM43143_CORE_BUS_BASE 0x18002000 -/* internal memory core */ -#define BCM43143_CORE_SOCRAM_BASE 0x18004000 -/* ARM Cortex M3 core, ID 0x82a */ -#define BCM43143_CORE_ARM_BASE 0x18003000 #define BCM43143_RAMSIZE 0x70000 #define CORE_SB(base, field) \ @@ -164,13 +157,6 @@ struct brcmf_core_priv { struct brcmf_chip_priv *chip; }; -/* ARM CR4 core specific control flag bits */ -#define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020 - -/* D11 core specific control flag bits */ -#define D11_BCMA_IOCTL_PHYCLOCKEN 0x0004 -#define D11_BCMA_IOCTL_PHYRESET 0x0008 - struct brcmf_chip_priv { struct brcmf_chip pub; const struct brcmf_buscore_ops *ops; @@ -495,6 +481,7 @@ static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci) ci->pub.ramsize = 0x48000; break; case BRCM_CC_4334_CHIP_ID: + case BRCM_CC_43340_CHIP_ID: ci->pub.ramsize = 0x80000; break; case BRCM_CC_4335_CHIP_ID: diff --git a/drivers/net/wireless/brcm80211/brcmfmac/common.c b/drivers/net/wireless/brcm80211/brcmfmac/common.c index 1861a13e8d03..fe54844c75e0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/common.c @@ -25,6 +25,9 @@ #include "fwil.h" #include "fwil_types.h" #include "tracepoint.h" +#include "common.h" + +const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; #define BRCMF_DEFAULT_BCN_TIMEOUT 3 #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40 @@ -38,6 +41,8 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) s8 eventmask[BRCMF_EVENTING_MASK_LEN]; u8 buf[BRCMF_DCMD_SMLEN]; struct brcmf_join_pref_params join_pref_params[2]; + struct brcmf_rev_info_le revinfo; + struct brcmf_rev_info *ri; char *ptr; s32 err; @@ -45,12 +50,37 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr, sizeof(ifp->mac_addr)); if (err < 0) { - brcmf_err("Retreiving cur_etheraddr failed, %d\n", - err); + brcmf_err("Retreiving cur_etheraddr failed, %d\n", err); goto done; } memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac)); + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO, + &revinfo, sizeof(revinfo)); + ri = &ifp->drvr->revinfo; + if (err < 0) { + brcmf_err("retrieving revision info failed, %d\n", err); + } else { + ri->vendorid = le32_to_cpu(revinfo.vendorid); + ri->deviceid = le32_to_cpu(revinfo.deviceid); + ri->radiorev = le32_to_cpu(revinfo.radiorev); + ri->chiprev = le32_to_cpu(revinfo.chiprev); + ri->corerev = le32_to_cpu(revinfo.corerev); + ri->boardid = le32_to_cpu(revinfo.boardid); + ri->boardvendor = le32_to_cpu(revinfo.boardvendor); + ri->boardrev = le32_to_cpu(revinfo.boardrev); + ri->driverrev = le32_to_cpu(revinfo.driverrev); + ri->ucoderev = le32_to_cpu(revinfo.ucoderev); + ri->bus = le32_to_cpu(revinfo.bus); + ri->chipnum = le32_to_cpu(revinfo.chipnum); + ri->phytype = le32_to_cpu(revinfo.phytype); + ri->phyrev = le32_to_cpu(revinfo.phyrev); + ri->anarev = le32_to_cpu(revinfo.anarev); + ri->chippkg = le32_to_cpu(revinfo.chippkg); + ri->nvramrev = le32_to_cpu(revinfo.nvramrev); + } + ri->result = err; + /* query for 'ver' to get version info from firmware */ memset(buf, 0, sizeof(buf)); strcpy(buf, "ver"); diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.h b/drivers/net/wireless/brcm80211/brcmfmac/common.h similarity index 50% rename from drivers/net/wireless/ath/wil6210/wil_platform_msm.h rename to drivers/net/wireless/brcm80211/brcmfmac/common.h index 2f2229edb498..0d39d80cee28 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform_msm.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/common.h @@ -1,5 +1,4 @@ -/* - * Copyright (c) 2014 Qualcomm Atheros, Inc. +/* Copyright (c) 2014 Broadcom Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -7,18 +6,15 @@ * * 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. + * 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 BRCMFMAC_COMMON_H +#define BRCMFMAC_COMMON_H -#ifndef __WIL_PLATFORM__MSM_H__ -#define __WIL_PLATFORM_MSM_H__ +extern const u8 ALLFFMAC[ETH_ALEN]; -#include "wil_platform.h" - -void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops); - -#endif /* __WIL_PLATFORM__MSM_H__ */ +#endif /* BRCMFMAC_COMMON_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h index 002336e35764..3d404016a92e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h @@ -37,6 +37,8 @@ struct brcmf_commonring { unsigned long flags; bool inited; bool was_full; + + atomic_t outstanding_tx; }; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c index effe6d7831d9..2d6e2cc1b12c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c @@ -197,7 +197,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, brcmf_dbg(DATA, "Enter, idx=%d\n", ifp->bssidx); /* Can the device send data? */ - if (drvr->bus_if->state != BRCMF_BUS_DATA) { + if (drvr->bus_if->state != BRCMF_BUS_UP) { brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state); netif_stop_queue(ndev); dev_kfree_skb(skb); @@ -601,9 +601,12 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev, { struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pub *drvr = ifp->drvr; + char drev[BRCMU_DOTREV_LEN] = "n/a"; + if (drvr->revinfo.result == 0) + brcmu_dotrev_str(drvr->revinfo.driverrev, drev); strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); - snprintf(info->version, sizeof(info->version), "n/a"); + strlcpy(info->version, drev, sizeof(info->version)); strlcpy(info->fw_version, drvr->fwver, sizeof(info->fw_version)); strlcpy(info->bus_info, dev_name(drvr->bus_if->dev), sizeof(info->bus_info)); @@ -637,7 +640,7 @@ static int brcmf_netdev_open(struct net_device *ndev) brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); /* If bus is not ready, can't continue */ - if (bus_if->state != BRCMF_BUS_DATA) { + if (bus_if->state != BRCMF_BUS_UP) { brcmf_err("failed bus is not ready\n"); return -EAGAIN; } @@ -964,13 +967,20 @@ int brcmf_bus_start(struct device *dev) p2p_ifp = NULL; /* signal bus ready */ - brcmf_bus_change_state(bus_if, BRCMF_BUS_DATA); + brcmf_bus_change_state(bus_if, BRCMF_BUS_UP); /* Bus is ready, do any initialization */ ret = brcmf_c_preinit_dcmds(ifp); if (ret < 0) goto fail; + /* assure we have chipid before feature attach */ + if (!bus_if->chip) { + bus_if->chip = drvr->revinfo.chipnum; + bus_if->chiprev = drvr->revinfo.chiprev; + brcmf_dbg(INFO, "firmware revinfo: chip %x (%d) rev %d\n", + bus_if->chip, bus_if->chip, bus_if->chiprev); + } brcmf_feat_attach(drvr); ret = brcmf_fws_init(drvr); @@ -1093,9 +1103,8 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp) return atomic_read(&ifp->pend_8021x_cnt); } -int brcmf_netdev_wait_pend8021x(struct net_device *ndev) +int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp) { - struct brcmf_if *ifp = netdev_priv(ndev); int err; err = wait_event_timeout(ifp->pend_8021x_wait, @@ -1107,6 +1116,27 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev) return !err; } +void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state) +{ + struct brcmf_pub *drvr = bus->drvr; + struct net_device *ndev; + int ifidx; + + brcmf_dbg(TRACE, "%d -> %d\n", bus->state, state); + bus->state = state; + + if (state == BRCMF_BUS_UP) { + for (ifidx = 0; ifidx < BRCMF_MAX_IFS; ifidx++) { + if ((drvr->iflist[ifidx]) && + (drvr->iflist[ifidx]->ndev)) { + ndev = drvr->iflist[ifidx]->ndev; + if (netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + } + } + } +} + static void brcmf_driver_register(struct work_struct *work) { #ifdef CONFIG_BRCMFMAC_SDIO diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.h b/drivers/net/wireless/brcm80211/brcmfmac/core.h index 23f74b139cc8..fd74a9c6e9ac 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h @@ -29,8 +29,6 @@ /* For supporting multiple interfaces */ #define BRCMF_MAX_IFS 16 -#define DOT11_MAX_DEFAULT_KEYS 4 - /* Small, medium and maximum buffer size for dcmd */ #define BRCMF_DCMD_SMLEN 256 @@ -73,6 +71,35 @@ struct brcmf_proto; /* device communication protocol info */ struct brcmf_cfg80211_dev; /* cfg80211 device info */ struct brcmf_fws_info; /* firmware signalling info */ +/* + * struct brcmf_rev_info + * + * The result field stores the error code of the + * revision info request from firmware. For the + * other fields see struct brcmf_rev_info_le in + * fwil_types.h + */ +struct brcmf_rev_info { + int result; + u32 vendorid; + u32 deviceid; + u32 radiorev; + u32 chiprev; + u32 corerev; + u32 boardid; + u32 boardvendor; + u32 boardrev; + u32 driverrev; + u32 ucoderev; + u32 bus; + u32 chipnum; + u32 phytype; + u32 phyrev; + u32 anarev; + u32 chippkg; + u32 nvramrev; +}; + /* Common structure for module and instance linkage */ struct brcmf_pub { /* Linkage ponters */ @@ -106,6 +133,7 @@ struct brcmf_pub { u32 feat_flags; u32 chip_quirks; + struct brcmf_rev_info revinfo; #ifdef DEBUG struct dentry *dbgfs_dir; #endif @@ -167,7 +195,7 @@ struct brcmf_skb_reorder_data { u8 *reorder; }; -int brcmf_netdev_wait_pend8021x(struct net_device *ndev); +int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp); /* Return pointer to interface name */ char *brcmf_ifname(struct brcmf_pub *drvr, int idx); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c index 1ff787d1a36b..9cb99152ad17 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c @@ -103,7 +103,11 @@ static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp) c = nvp->fwnv->data[nvp->pos]; if (c == '=') { - st = VALUE; + /* ignore RAW1 by treating as comment */ + if (strncmp(&nvp->fwnv->data[nvp->entry], "RAW1", 4) == 0) + st = COMMENT; + else + st = VALUE; } else if (!is_nvram_char(c)) { brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n", nvp->line, nvp->column); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c index 44f3a84d1999..910fbb561469 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c @@ -25,6 +25,7 @@ #include "proto.h" #include "flowring.h" #include "msgbuf.h" +#include "common.h" #define BRCMF_FLOWRING_HIGH 1024 @@ -34,9 +35,6 @@ #define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] + fifo + ifidx * 16) #define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16) -static const u8 ALLZEROMAC[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; -static const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - static const u8 brcmf_flowring_prio2fifo[] = { 1, 0, @@ -137,7 +135,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN], hash = flow->hash; for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { if ((hash[hash_idx].ifidx == BRCMF_FLOWRING_INVALID_IFIDX) && - (memcmp(hash[hash_idx].mac, ALLZEROMAC, ETH_ALEN) == 0)) { + (is_zero_ether_addr(hash[hash_idx].mac))) { found = true; break; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c index 03f2c406a17b..dcfa0bb149ce 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c @@ -109,7 +109,7 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) struct brcmf_pub *drvr = ifp->drvr; s32 err; - if (drvr->bus_if->state != BRCMF_BUS_DATA) { + if (drvr->bus_if->state != BRCMF_BUS_UP) { brcmf_err("bus is down. we have nothing to do.\n"); return -EIO; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h index a30be683f4a1..5434dcf64f7d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h @@ -43,6 +43,8 @@ #define BRCMF_C_SET_RADIO 38 #define BRCMF_C_GET_PHYTYPE 39 #define BRCMF_C_SET_KEY 45 +#define BRCMF_C_GET_REGULATORY 46 +#define BRCMF_C_SET_REGULATORY 47 #define BRCMF_C_SET_PASSIVE_SCAN 49 #define BRCMF_C_SCAN 50 #define BRCMF_C_SCAN_RESULTS 51 @@ -57,9 +59,12 @@ #define BRCMF_C_SET_COUNTRY 84 #define BRCMF_C_GET_PM 85 #define BRCMF_C_SET_PM 86 +#define BRCMF_C_GET_REVINFO 98 #define BRCMF_C_GET_CURR_RATESET 114 #define BRCMF_C_GET_AP 117 #define BRCMF_C_SET_AP 118 +#define BRCMF_C_SET_SCB_AUTHORIZE 121 +#define BRCMF_C_SET_SCB_DEAUTHORIZE 122 #define BRCMF_C_GET_RSSI 127 #define BRCMF_C_GET_WSEC 133 #define BRCMF_C_SET_WSEC 134 diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h index 50891c02c4c1..374920965108 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h @@ -112,6 +112,7 @@ #define BRCMF_WOWL_MAXPATTERNS 8 #define BRCMF_WOWL_MAXPATTERNSIZE 128 +#define BRCMF_COUNTRY_BUF_SZ 4 /* join preference types for join_pref iovar */ enum brcmf_join_pref_types { @@ -525,4 +526,58 @@ struct brcmf_mbss_ssid_le { unsigned char SSID[32]; }; +/** + * struct brcmf_fil_country_le - country configuration structure. + * + * @country_abbrev: null-terminated country code used in the country IE. + * @rev: revision specifier for ccode. on set, -1 indicates unspecified. + * @ccode: null-terminated built-in country code. + */ +struct brcmf_fil_country_le { + char country_abbrev[BRCMF_COUNTRY_BUF_SZ]; + __le32 rev; + char ccode[BRCMF_COUNTRY_BUF_SZ]; +}; + +/** + * struct brcmf_rev_info_le - device revision info. + * + * @vendorid: PCI vendor id. + * @deviceid: device id of chip. + * @radiorev: radio revision. + * @chiprev: chip revision. + * @corerev: core revision. + * @boardid: board identifier (usu. PCI sub-device id). + * @boardvendor: board vendor (usu. PCI sub-vendor id). + * @boardrev: board revision. + * @driverrev: driver version. + * @ucoderev: microcode version. + * @bus: bus type. + * @chipnum: chip number. + * @phytype: phy type. + * @phyrev: phy revision. + * @anarev: anacore rev. + * @chippkg: chip package info. + * @nvramrev: nvram revision number. + */ +struct brcmf_rev_info_le { + __le32 vendorid; + __le32 deviceid; + __le32 radiorev; + __le32 chiprev; + __le32 corerev; + __le32 boardid; + __le32 boardvendor; + __le32 boardrev; + __le32 driverrev; + __le32 ucoderev; + __le32 bus; + __le32 chipnum; + __le32 phytype; + __le32 phyrev; + __le32 anarev; + __le32 chippkg; + __le32 nvramrev; +}; + #endif /* FWIL_TYPES_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c index 456944a6a2db..6262612dec45 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c @@ -73,6 +73,8 @@ #define BRCMF_MSGBUF_TX_FLUSH_CNT1 32 #define BRCMF_MSGBUF_TX_FLUSH_CNT2 96 +#define BRCMF_MSGBUF_DELAY_TXWORKER_THRS 64 +#define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS 32 struct msgbuf_common_hdr { u8 msgtype; @@ -583,7 +585,7 @@ brcmf_msgbuf_flowring_create_worker(struct brcmf_msgbuf *msgbuf, u32 flowid; void *dma_buf; u32 dma_sz; - long long address; + u64 address; int err; flowid = work->flowid; @@ -620,7 +622,7 @@ brcmf_msgbuf_flowring_create_worker(struct brcmf_msgbuf *msgbuf, BRCMF_NROF_H2D_COMMON_MSGRINGS); memcpy(create->sa, work->sa, ETH_ALEN); memcpy(create->da, work->da, ETH_ALEN); - address = (long long)(long)msgbuf->flowring_dma_handle[flowid]; + address = (u64)msgbuf->flowring_dma_handle[flowid]; create->flow_ring_addr.high_addr = cpu_to_le32(address >> 32); create->flow_ring_addr.low_addr = cpu_to_le32(address & 0xffffffff); create->max_items = cpu_to_le16(BRCMF_H2D_TXFLOWRING_MAX_ITEM); @@ -698,7 +700,7 @@ static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid) dma_addr_t physaddr; u32 pktid; struct msgbuf_tx_msghdr *tx_msghdr; - long long address; + u64 address; commonring = msgbuf->flowrings[flowid]; if (!brcmf_commonring_write_available(commonring)) @@ -742,13 +744,14 @@ static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid) tx_msghdr->seg_cnt = 1; memcpy(tx_msghdr->txhdr, skb->data, ETH_HLEN); tx_msghdr->data_len = cpu_to_le16(skb->len - ETH_HLEN); - address = (long long)(long)physaddr; + address = (u64)physaddr; tx_msghdr->data_buf_addr.high_addr = cpu_to_le32(address >> 32); tx_msghdr->data_buf_addr.low_addr = cpu_to_le32(address & 0xffffffff); tx_msghdr->metadata_buf_len = 0; tx_msghdr->metadata_buf_addr.high_addr = 0; tx_msghdr->metadata_buf_addr.low_addr = 0; + atomic_inc(&commonring->outstanding_tx); if (count >= BRCMF_MSGBUF_TX_FLUSH_CNT2) { brcmf_commonring_write_complete(commonring); count = 0; @@ -773,10 +776,16 @@ static void brcmf_msgbuf_txflow_worker(struct work_struct *worker) } -static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid) +static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid, + bool force) { + struct brcmf_commonring *commonring; + set_bit(flowid, msgbuf->flow_map); - queue_work(msgbuf->txflow_wq, &msgbuf->txflow_work); + commonring = msgbuf->flowrings[flowid]; + if ((force) || (atomic_read(&commonring->outstanding_tx) < + BRCMF_MSGBUF_DELAY_TXWORKER_THRS)) + queue_work(msgbuf->txflow_wq, &msgbuf->txflow_work); return 0; } @@ -797,7 +806,7 @@ static int brcmf_msgbuf_txdata(struct brcmf_pub *drvr, int ifidx, return -ENOMEM; } brcmf_flowring_enqueue(flow, flowid, skb); - brcmf_msgbuf_schedule_txdata(msgbuf, flowid); + brcmf_msgbuf_schedule_txdata(msgbuf, flowid, false); return 0; } @@ -854,6 +863,7 @@ brcmf_msgbuf_process_ioctl_complete(struct brcmf_msgbuf *msgbuf, void *buf) static void brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf) { + struct brcmf_commonring *commonring; struct msgbuf_tx_status *tx_status; u32 idx; struct sk_buff *skb; @@ -871,6 +881,8 @@ brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf) } set_bit(flowid, msgbuf->txstatus_done_map); + commonring = msgbuf->flowrings[flowid]; + atomic_dec(&commonring->outstanding_tx); brcmf_txfinalize(msgbuf->drvr, skb, tx_status->msg.ifidx, true); } @@ -885,7 +897,7 @@ static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count) u32 pktlen; dma_addr_t physaddr; struct msgbuf_rx_bufpost *rx_bufpost; - long long address; + u64 address; u32 pktid; u32 i; @@ -894,7 +906,7 @@ static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count) count, &alloced); if (!ret_ptr) { - brcmf_err("Failed to reserve space in commonring\n"); + brcmf_dbg(MSGBUF, "Failed to reserve space in commonring\n"); return 0; } @@ -921,7 +933,7 @@ static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count) } if (msgbuf->rx_metadata_offset) { - address = (long long)(long)physaddr; + address = (u64)physaddr; rx_bufpost->metadata_buf_len = cpu_to_le16(msgbuf->rx_metadata_offset); rx_bufpost->metadata_buf_addr.high_addr = @@ -936,7 +948,7 @@ static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count) rx_bufpost->msg.msgtype = MSGBUF_TYPE_RXBUF_POST; rx_bufpost->msg.request_id = cpu_to_le32(pktid); - address = (long long)(long)physaddr; + address = (u64)physaddr; rx_bufpost->data_buf_len = cpu_to_le16((u16)pktlen); rx_bufpost->data_buf_addr.high_addr = cpu_to_le32(address >> 32); @@ -992,7 +1004,7 @@ brcmf_msgbuf_rxbuf_ctrl_post(struct brcmf_msgbuf *msgbuf, bool event_buf, u32 pktlen; dma_addr_t physaddr; struct msgbuf_rx_ioctl_resp_or_event *rx_bufpost; - long long address; + u64 address; u32 pktid; u32 i; @@ -1035,7 +1047,7 @@ brcmf_msgbuf_rxbuf_ctrl_post(struct brcmf_msgbuf *msgbuf, bool event_buf, MSGBUF_TYPE_IOCTLRESP_BUF_POST; rx_bufpost->msg.request_id = cpu_to_le32(pktid); - address = (long long)(long)physaddr; + address = (u64)physaddr; rx_bufpost->host_buf_len = cpu_to_le16((u16)pktlen); rx_bufpost->host_buf_addr.high_addr = cpu_to_le32(address >> 32); @@ -1181,7 +1193,7 @@ brcmf_msgbuf_process_flow_ring_create_response(struct brcmf_msgbuf *msgbuf, brcmf_flowring_open(msgbuf->flow, flowid); - brcmf_msgbuf_schedule_txdata(msgbuf, flowid); + brcmf_msgbuf_schedule_txdata(msgbuf, flowid, true); } @@ -1280,8 +1292,10 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev) struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; + struct brcmf_commonring *commonring; void *buf; u32 flowid; + int qlen; buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE]; brcmf_msgbuf_process_rx(msgbuf, buf); @@ -1293,8 +1307,12 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev) for_each_set_bit(flowid, msgbuf->txstatus_done_map, msgbuf->nrof_flowrings) { clear_bit(flowid, msgbuf->txstatus_done_map); - if (brcmf_flowring_qlen(msgbuf->flow, flowid)) - brcmf_msgbuf_schedule_txdata(msgbuf, flowid); + commonring = msgbuf->flowrings[flowid]; + qlen = brcmf_flowring_qlen(msgbuf->flow, flowid); + if ((qlen > BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) || + ((qlen) && (atomic_read(&commonring->outstanding_tx) < + BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS))) + brcmf_msgbuf_schedule_txdata(msgbuf, flowid, true); } return 0; @@ -1348,7 +1366,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) { struct brcmf_bus_msgbuf *if_msgbuf; struct brcmf_msgbuf *msgbuf; - long long address; + u64 address; u32 count; if_msgbuf = drvr->bus_if->msgbuf; @@ -1379,7 +1397,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) GFP_KERNEL); if (!msgbuf->ioctbuf) goto fail; - address = (long long)(long)msgbuf->ioctbuf_handle; + address = (u64)msgbuf->ioctbuf_handle; msgbuf->ioctbuf_phys_hi = address >> 32; msgbuf->ioctbuf_phys_lo = address & 0xffffffff; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c index 905991fdb7b1..61c053a729be 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c @@ -959,14 +959,14 @@ brcmf_pcie_init_dmabuffer_for_device(struct brcmf_pciedev_info *devinfo, dma_addr_t *dma_handle) { void *ring; - long long address; + u64 address; ring = dma_alloc_coherent(&devinfo->pdev->dev, size, dma_handle, GFP_KERNEL); if (!ring) return NULL; - address = (long long)(long)*dma_handle; + address = (u64)*dma_handle; brcmf_pcie_write_tcm32(devinfo, tcm_dma_phys_addr, address & 0xffffffff); brcmf_pcie_write_tcm32(devinfo, tcm_dma_phys_addr + 4, address >> 32); @@ -1166,7 +1166,7 @@ brcmf_pcie_release_scratchbuffers(struct brcmf_pciedev_info *devinfo) static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo) { - long long address; + u64 address; u32 addr; devinfo->shared.scratch = dma_alloc_coherent(&devinfo->pdev->dev, @@ -1180,7 +1180,7 @@ static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo) addr = devinfo->shared.tcm_base_address + BRCMF_SHARED_DMA_SCRATCH_ADDR_OFFSET; - address = (long long)(long)devinfo->shared.scratch_dmahandle; + address = (u64)devinfo->shared.scratch_dmahandle; brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); addr = devinfo->shared.tcm_base_address + @@ -1198,7 +1198,7 @@ static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo) addr = devinfo->shared.tcm_base_address + BRCMF_SHARED_DMA_RINGUPD_ADDR_OFFSET; - address = (long long)(long)devinfo->shared.ringupd_dmahandle; + address = (u64)devinfo->shared.ringupd_dmahandle; brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff); brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32); addr = devinfo->shared.tcm_base_address + @@ -1828,7 +1828,7 @@ static int brcmf_pcie_resume(struct pci_dev *pdev) goto cleanup; brcmf_dbg(PCIE, "Hot resume, continue....\n"); brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); - brcmf_bus_change_state(bus, BRCMF_BUS_DATA); + brcmf_bus_change_state(bus, BRCMF_BUS_UP); brcmf_pcie_intr_enable(devinfo); return 0; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 0b0d51a61060..faec35c899ec 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -44,7 +44,8 @@ #include "chip.h" #include "firmware.h" -#define DCMD_RESP_TIMEOUT 2000 /* In milli second */ +#define DCMD_RESP_TIMEOUT 2000 /* In milli second */ +#define CTL_DONE_TIMEOUT 2000 /* In milli second */ #ifdef DEBUG @@ -495,9 +496,9 @@ struct brcmf_sdio { u8 *ctrl_frame_buf; u16 ctrl_frame_len; bool ctrl_frame_stat; + int ctrl_frame_err; spinlock_t txq_lock; /* protect bus->txq */ - struct semaphore tx_seq_lock; /* protect bus->tx_seq */ wait_queue_head_t ctrl_wait; wait_queue_head_t dcmd_resp_wait; @@ -514,7 +515,6 @@ struct brcmf_sdio { bool txoff; /* Transmit flow-controlled */ struct brcmf_sdio_count sdcnt; bool sr_enabled; /* SaveRestore enabled */ - bool sleeping; /* SDIO bus sleeping */ u8 tx_hdrlen; /* sdio bus header length for tx packet */ bool txglom; /* host tx glomming enable flag */ @@ -608,6 +608,8 @@ static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = { #define BCM4330_NVRAM_NAME "brcm/brcmfmac4330-sdio.txt" #define BCM4334_FIRMWARE_NAME "brcm/brcmfmac4334-sdio.bin" #define BCM4334_NVRAM_NAME "brcm/brcmfmac4334-sdio.txt" +#define BCM43340_FIRMWARE_NAME "brcm/brcmfmac43340-sdio.bin" +#define BCM43340_NVRAM_NAME "brcm/brcmfmac43340-sdio.txt" #define BCM4335_FIRMWARE_NAME "brcm/brcmfmac4335-sdio.bin" #define BCM4335_NVRAM_NAME "brcm/brcmfmac4335-sdio.txt" #define BCM43362_FIRMWARE_NAME "brcm/brcmfmac43362-sdio.bin" @@ -629,6 +631,8 @@ MODULE_FIRMWARE(BCM4330_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4330_NVRAM_NAME); MODULE_FIRMWARE(BCM4334_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4334_NVRAM_NAME); +MODULE_FIRMWARE(BCM43340_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM43340_NVRAM_NAME); MODULE_FIRMWARE(BCM4335_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4335_NVRAM_NAME); MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME); @@ -660,6 +664,7 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = { { BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) }, { BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) }, { BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) }, + { BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43340) }, { BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }, { BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) }, { BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }, @@ -1008,12 +1013,12 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) brcmf_dbg(SDIO, "Enter: request %s currently %s\n", (sleep ? "SLEEP" : "WAKE"), - (bus->sleeping ? "SLEEP" : "WAKE")); + (bus->sdiodev->sleeping ? "SLEEP" : "WAKE")); /* If SR is enabled control bus state with KSO */ if (bus->sr_enabled) { /* Done if we're already in the requested state */ - if (sleep == bus->sleeping) + if (sleep == bus->sdiodev->sleeping) goto end; /* Going to sleep */ @@ -1045,12 +1050,7 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) bus->idlecount = 0; err = brcmf_sdio_kso_control(bus, true); } - if (!err) { - /* Change state */ - bus->sleeping = sleep; - brcmf_dbg(SDIO, "new state %s\n", - (sleep ? "SLEEP" : "WAKE")); - } else { + if (err) { brcmf_err("error while changing bus sleep state %d\n", err); goto done; @@ -1065,6 +1065,11 @@ end: } else { brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok); } + bus->sdiodev->sleeping = sleep; + if (sleep) + wake_up(&bus->sdiodev->idle_wait); + brcmf_dbg(SDIO, "new state %s\n", + (sleep ? "SLEEP" : "WAKE")); done: brcmf_dbg(SDIO, "Exit: err=%d\n", err); return err; @@ -1904,7 +1909,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) bus->rxpending = true; for (rd->seq_num = bus->rx_seq, rxleft = maxframes; - !bus->rxskip && rxleft && brcmf_bus_ready(bus->sdiodev->bus_if); + !bus->rxskip && rxleft && bus->sdiodev->state == BRCMF_STATE_DATA; rd->seq_num++, rxleft--) { /* Handle glomming separately */ @@ -2371,8 +2376,6 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes) /* Send frames until the limit or some other event */ for (cnt = 0; (cnt < maxframes) && data_ok(bus);) { pkt_num = 1; - if (down_interruptible(&bus->tx_seq_lock)) - return cnt; if (bus->txglom) pkt_num = min_t(u8, bus->tx_max - bus->tx_seq, bus->sdiodev->txglomsz); @@ -2388,13 +2391,10 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes) __skb_queue_tail(&pktq, pkt); } spin_unlock_bh(&bus->txq_lock); - if (i == 0) { - up(&bus->tx_seq_lock); + if (i == 0) break; - } ret = brcmf_sdio_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL); - up(&bus->tx_seq_lock); cnt += i; @@ -2415,7 +2415,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes) } /* Deflow-control stack if needed */ - if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) && + if ((bus->sdiodev->state == BRCMF_STATE_DATA) && bus->txoff && (pktq_len(&bus->txq) < TXLOW)) { bus->txoff = false; brcmf_txflowblock(bus->sdiodev->dev, false); @@ -2503,7 +2503,7 @@ static void brcmf_sdio_bus_stop(struct device *dev) bus->watchdog_tsk = NULL; } - if (bus_if->state == BRCMF_BUS_DOWN) { + if (sdiodev->state != BRCMF_STATE_NOMEDIUM) { sdio_claim_host(sdiodev->func[1]); /* Enable clock for device interrupts */ @@ -2538,8 +2538,7 @@ static void brcmf_sdio_bus_stop(struct device *dev) brcmu_pktq_flush(&bus->txq, true, NULL, NULL); /* Clear any held glomming stuff */ - if (bus->glomd) - brcmu_pkt_buf_free_skb(bus->glomd); + brcmu_pkt_buf_free_skb(bus->glomd); brcmf_sdio_free_glom(bus); /* Clear rx control and wake any waiters */ @@ -2604,6 +2603,21 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus) return ret; } +static int brcmf_sdio_pm_resume_wait(struct brcmf_sdio_dev *sdiodev) +{ +#ifdef CONFIG_PM_SLEEP + int retry; + + /* Wait for possible resume to complete */ + retry = 0; + while ((atomic_read(&sdiodev->suspend)) && (retry++ != 50)) + msleep(20); + if (atomic_read(&sdiodev->suspend)) + return -EIO; +#endif + return 0; +} + static void brcmf_sdio_dpc(struct brcmf_sdio *bus) { u32 newstatus = 0; @@ -2614,6 +2628,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) brcmf_dbg(TRACE, "Enter\n"); + if (brcmf_sdio_pm_resume_wait(bus->sdiodev)) + return; + sdio_claim_host(bus->sdiodev->func[1]); /* If waiting for HTAVAIL, check status */ @@ -2720,17 +2737,14 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) brcmf_sdio_clrintr(bus); if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) && - (down_interruptible(&bus->tx_seq_lock) == 0)) { - if (data_ok(bus)) { - sdio_claim_host(bus->sdiodev->func[1]); - err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, - bus->ctrl_frame_len); - sdio_release_host(bus->sdiodev->func[1]); - - bus->ctrl_frame_stat = false; - brcmf_sdio_wait_event_wakeup(bus); - } - up(&bus->tx_seq_lock); + data_ok(bus)) { + sdio_claim_host(bus->sdiodev->func[1]); + err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, + bus->ctrl_frame_len); + sdio_release_host(bus->sdiodev->func[1]); + bus->ctrl_frame_err = err; + bus->ctrl_frame_stat = false; + brcmf_sdio_wait_event_wakeup(bus); } /* Send queued frames (limit 1 if rx may still be pending) */ if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) && @@ -2741,7 +2755,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) brcmf_sdio_sendfromq(bus, framecnt); } - if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) { + if ((bus->sdiodev->state != BRCMF_STATE_DATA) || (err != 0)) { brcmf_err("failed backplane access over SDIO, halting operation\n"); atomic_set(&bus->intstatus, 0); } else if (atomic_read(&bus->intstatus) || @@ -2942,43 +2956,30 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; - int ret = -1; + int ret; brcmf_dbg(TRACE, "Enter\n"); - if (down_interruptible(&bus->tx_seq_lock)) - return -EINTR; - - if (!data_ok(bus)) { - brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n", - bus->tx_max, bus->tx_seq); - up(&bus->tx_seq_lock); - /* Send from dpc */ - bus->ctrl_frame_buf = msg; - bus->ctrl_frame_len = msglen; - bus->ctrl_frame_stat = true; - - wait_event_interruptible_timeout(bus->ctrl_wait, - !bus->ctrl_frame_stat, - msecs_to_jiffies(2000)); - - if (!bus->ctrl_frame_stat) { - brcmf_dbg(SDIO, "ctrl_frame_stat == false\n"); - ret = 0; - } else { - brcmf_dbg(SDIO, "ctrl_frame_stat == true\n"); - bus->ctrl_frame_stat = false; - if (down_interruptible(&bus->tx_seq_lock)) - return -EINTR; - ret = -1; - } + /* Send from dpc */ + bus->ctrl_frame_buf = msg; + bus->ctrl_frame_len = msglen; + bus->ctrl_frame_stat = true; + if (atomic_read(&bus->dpc_tskcnt) == 0) { + atomic_inc(&bus->dpc_tskcnt); + queue_work(bus->brcmf_wq, &bus->datawork); } - if (ret == -1) { - sdio_claim_host(bus->sdiodev->func[1]); - brcmf_sdio_bus_sleep(bus, false, false); - ret = brcmf_sdio_tx_ctrlframe(bus, msg, msglen); - sdio_release_host(bus->sdiodev->func[1]); - up(&bus->tx_seq_lock); + + wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat, + msecs_to_jiffies(CTL_DONE_TIMEOUT)); + + if (!bus->ctrl_frame_stat) { + brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n", + bus->ctrl_frame_err); + ret = bus->ctrl_frame_err; + } else { + brcmf_dbg(SDIO, "ctrl_frame timeout\n"); + bus->ctrl_frame_stat = false; + ret = -ETIMEDOUT; } if (ret) @@ -2986,7 +2987,7 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) else bus->sdcnt.tx_ctlpkts++; - return ret ? -EIO : 0; + return ret; } #ifdef DEBUG @@ -3409,8 +3410,8 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus, goto err; } - /* Allow HT Clock now that the ARM is running. */ - brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_LOAD); + /* Allow full data communication using DPC from now on. */ + bus->sdiodev->state = BRCMF_STATE_DATA; bcmerror = 0; err: @@ -3556,7 +3557,7 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus) return; } - if (!brcmf_bus_ready(bus->sdiodev->bus_if)) { + if (bus->sdiodev->state != BRCMF_STATE_DATA) { brcmf_err("bus is down. we have nothing to do\n"); return; } @@ -3579,10 +3580,6 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus) static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus) { -#ifdef DEBUG - struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev); -#endif /* DEBUG */ - brcmf_dbg(TIMER, "Enter\n"); /* Poll period: check device if appropriate. */ @@ -3626,7 +3623,7 @@ static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus) } #ifdef DEBUG /* Poll for console output periodically */ - if (bus_if && bus_if->state == BRCMF_BUS_DATA && + if (bus->sdiodev->state == BRCMF_STATE_DATA && bus->console_interval != 0) { bus->console.count += BRCMF_WD_POLL_MS; if (bus->console.count >= bus->console_interval) { @@ -3811,7 +3808,7 @@ static u32 brcmf_sdio_buscore_read32(void *ctx, u32 addr) u32 val, rev; val = brcmf_sdiod_regrl(sdiodev, addr, NULL); - if (sdiodev->func[0]->device == BRCM_SDIO_4335_4339_DEVICE_ID && + if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 && addr == CORE_CC_REG(SI_ENUM_BASE, chipid)) { rev = (val & CID_REV_MASK) >> CID_REV_SHIFT; if (rev >= 2) { @@ -3867,11 +3864,6 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) goto fail; } - /* SDIO register access works so moving - * state from UNKNOWN to DOWN. - */ - brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN); - bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops); if (IS_ERR(bus->ci)) { brcmf_err("brcmf_chip_attach failed!\n"); @@ -4005,18 +3997,16 @@ static void brcmf_sdio_firmware_callback(struct device *dev, brcmf_dbg(TRACE, "Enter: dev=%s\n", dev_name(dev)); - /* try to download image and nvram to the dongle */ - if (bus_if->state == BRCMF_BUS_DOWN) { - bus->alp_only = true; - err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len); - if (err) - goto fail; - bus->alp_only = false; - } - if (!bus_if->drvr) return; + /* try to download image and nvram to the dongle */ + bus->alp_only = true; + err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len); + if (err) + goto fail; + bus->alp_only = false; + /* Start the watchdog timer */ bus->sdcnt.tickcnt = 0; brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS); @@ -4142,7 +4132,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) spin_lock_init(&bus->rxctl_lock); spin_lock_init(&bus->txq_lock); - sema_init(&bus->tx_seq_lock, 1); init_waitqueue_head(&bus->ctrl_wait); init_waitqueue_head(&bus->dcmd_resp_wait); @@ -4213,7 +4202,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) bus->idleclock = BRCMF_IDLE_ACTIVE; /* SR state */ - bus->sleeping = false; bus->sr_enabled = false; brcmf_sdio_debugfs_create(bus); @@ -4254,7 +4242,7 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) destroy_workqueue(bus->brcmf_wq); if (bus->ci) { - if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) { + if (bus->sdiodev->state != BRCMF_STATE_NOMEDIUM) { sdio_claim_host(bus->sdiodev->func[1]); brcmf_sdio_clkctl(bus, CLK_AVAIL, false); /* Leave the device in state where it is @@ -4289,7 +4277,7 @@ void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick) } /* don't start the wd until fw is loaded */ - if (bus->sdiodev->bus_if->state != BRCMF_BUS_DATA) + if (bus->sdiodev->state != BRCMF_STATE_DATA) return; if (wdtick) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h index 8eb42620129c..ec2586a8425c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h @@ -155,6 +155,13 @@ /* watchdog polling interval in ms */ #define BRCMF_WD_POLL_MS 10 +/* The state of the bus */ +enum brcmf_sdio_state { + BRCMF_STATE_DOWN, /* Device available, still initialising */ + BRCMF_STATE_DATA, /* Ready for data transfers, DPC enabled */ + BRCMF_STATE_NOMEDIUM /* No medium access to dongle possible */ +}; + struct brcmf_sdreg { int func; int offset; @@ -169,8 +176,8 @@ struct brcmf_sdio_dev { u32 sbwad; /* Save backplane window address */ struct brcmf_sdio *bus; atomic_t suspend; /* suspend flag */ - wait_queue_head_t request_word_wait; - wait_queue_head_t request_buffer_wait; + bool sleeping; + wait_queue_head_t idle_wait; struct device *dev; struct brcmf_bus *bus_if; struct brcmfmac_sdio_platform_data *pdata; @@ -187,6 +194,7 @@ struct brcmf_sdio_dev { char fw_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN]; char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN]; bool wowl_enabled; + enum brcmf_sdio_state state; }; /* sdio core registers */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 4572defc280f..5df6aa72cc2d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -421,7 +421,7 @@ fail: brcmf_err("fail!\n"); while (!list_empty(q)) { req = list_entry(q->next, struct brcmf_usbreq, list); - if (req && req->urb) + if (req) usb_free_urb(req->urb); list_del(q->next); } @@ -576,7 +576,7 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state) brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DOWN); } else if (state == BRCMFMAC_USB_STATE_UP) { brcmf_dbg(USB, "DBUS is up\n"); - brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DATA); + brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_UP); } else { brcmf_dbg(USB, "DBUS current state=%d\n", state); } @@ -1263,6 +1263,8 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) ret = brcmf_usb_bus_setup(devinfo); if (ret) goto fail; + /* we are done */ + return 0; } bus->chip = bus_pub->devid; bus->chiprev = bus_pub->chiprev; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/brcm80211/brcmsmac/debug.c index c9a8b9360ab1..7a1fbb2e3a71 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/debug.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/debug.c @@ -78,7 +78,7 @@ int brcms_debugfs_hardware_read(struct seq_file *s, void *data) struct brcms_hardware *hw = drvr->wlc->hw; struct bcma_device *core = hw->d11core; struct bcma_bus *bus = core->bus; - char boardrev[10]; + char boardrev[BRCMU_BOARDREV_LEN]; seq_printf(s, "chipnum 0x%x\n" "chiprev 0x%x\n" diff --git a/drivers/net/wireless/brcm80211/brcmutil/utils.c b/drivers/net/wireless/brcm80211/brcmutil/utils.c index 906e89ddf319..0543607002fd 100644 --- a/drivers/net/wireless/brcm80211/brcmutil/utils.c +++ b/drivers/net/wireless/brcm80211/brcmutil/utils.c @@ -267,15 +267,43 @@ char *brcmu_boardrev_str(u32 brev, char *buf) char c; if (brev < 0x100) { - snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); + snprintf(buf, BRCMU_BOARDREV_LEN, "%d.%d", + (brev & 0xf0) >> 4, brev & 0xf); } else { c = (brev & 0xf000) == 0x1000 ? 'P' : 'A'; - snprintf(buf, 8, "%c%03x", c, brev & 0xfff); + snprintf(buf, BRCMU_BOARDREV_LEN, "%c%03x", c, brev & 0xfff); } return buf; } EXPORT_SYMBOL(brcmu_boardrev_str); +char *brcmu_dotrev_str(u32 dotrev, char *buf) +{ + u8 dotval[4]; + + if (!dotrev) { + snprintf(buf, BRCMU_DOTREV_LEN, "unknown"); + return buf; + } + dotval[0] = (dotrev >> 24) & 0xFF; + dotval[1] = (dotrev >> 16) & 0xFF; + dotval[2] = (dotrev >> 8) & 0xFF; + dotval[3] = dotrev & 0xFF; + + if (dotval[3]) + snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d.%d.%d", dotval[0], + dotval[1], dotval[2], dotval[3]); + else if (dotval[2]) + snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d.%d", dotval[0], + dotval[1], dotval[2]); + else + snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d", dotval[0], + dotval[1]); + + return buf; +} +EXPORT_SYMBOL(brcmu_dotrev_str); + #if defined(DEBUG) /* pretty hex print a pkt buffer chain */ void brcmu_prpkt(const char *msg, struct sk_buff *p0) diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index 6996fcc144cf..2124a17d0bfd 100644 --- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h @@ -22,7 +22,6 @@ #define BRCM_USB_VENDOR_ID_BROADCOM 0x0a5c #define BRCM_PCIE_VENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM -#define BRCM_SDIO_VENDOR_ID_BROADCOM SDIO_VENDOR_ID_BROADCOM /* Chipcommon Core Chip IDs */ #define BRCM_CC_43143_CHIP_ID 43143 @@ -34,6 +33,7 @@ #define BRCM_CC_4329_CHIP_ID 0x4329 #define BRCM_CC_4330_CHIP_ID 0x4330 #define BRCM_CC_4334_CHIP_ID 0x4334 +#define BRCM_CC_43340_CHIP_ID 43340 #define BRCM_CC_43362_CHIP_ID 43362 #define BRCM_CC_4335_CHIP_ID 0x4335 #define BRCM_CC_4339_CHIP_ID 0x4339 @@ -45,16 +45,6 @@ #define BRCM_CC_43570_CHIP_ID 43570 #define BRCM_CC_43602_CHIP_ID 43602 -/* SDIO Device IDs */ -#define BRCM_SDIO_43143_DEVICE_ID BRCM_CC_43143_CHIP_ID -#define BRCM_SDIO_43241_DEVICE_ID BRCM_CC_43241_CHIP_ID -#define BRCM_SDIO_4329_DEVICE_ID BRCM_CC_4329_CHIP_ID -#define BRCM_SDIO_4330_DEVICE_ID BRCM_CC_4330_CHIP_ID -#define BRCM_SDIO_4334_DEVICE_ID BRCM_CC_4334_CHIP_ID -#define BRCM_SDIO_43362_DEVICE_ID BRCM_CC_43362_CHIP_ID -#define BRCM_SDIO_4335_4339_DEVICE_ID BRCM_CC_4335_CHIP_ID -#define BRCM_SDIO_4354_DEVICE_ID BRCM_CC_4354_CHIP_ID - /* USB Device IDs */ #define BRCM_USB_43143_DEVICE_ID 0xbd1e #define BRCM_USB_43236_DEVICE_ID 0xbd17 diff --git a/drivers/net/wireless/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/brcm80211/include/brcmu_utils.h index a043e29f07e2..41969527b459 100644 --- a/drivers/net/wireless/brcm80211/include/brcmu_utils.h +++ b/drivers/net/wireless/brcm80211/include/brcmu_utils.h @@ -218,6 +218,10 @@ void brcmu_dbg_hex_dump(const void *data, size_t size, const char *fmt, ...) } #endif +#define BRCMU_BOARDREV_LEN 8 +#define BRCMU_DOTREV_LEN 16 + char *brcmu_boardrev_str(u32 brev, char *buf); +char *brcmu_dotrev_str(u32 dotrev, char *buf); #endif /* _BRCMU_UTILS_H_ */ diff --git a/drivers/net/wireless/cw1200/fwio.c b/drivers/net/wireless/cw1200/fwio.c index 6f1b9aace8b3..30e7646d04af 100644 --- a/drivers/net/wireless/cw1200/fwio.c +++ b/drivers/net/wireless/cw1200/fwio.c @@ -66,25 +66,31 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) do { \ ret = cw1200_apb_write_32(priv, CW1200_APB(reg), (val)); \ if (ret < 0) \ - goto error; \ + goto exit; \ + } while (0) +#define APB_WRITE2(reg, val) \ + do { \ + ret = cw1200_apb_write_32(priv, CW1200_APB(reg), (val)); \ + if (ret < 0) \ + goto free_buffer; \ } while (0) #define APB_READ(reg, val) \ do { \ ret = cw1200_apb_read_32(priv, CW1200_APB(reg), &(val)); \ if (ret < 0) \ - goto error; \ + goto free_buffer; \ } while (0) #define REG_WRITE(reg, val) \ do { \ ret = cw1200_reg_write_32(priv, (reg), (val)); \ if (ret < 0) \ - goto error; \ + goto exit; \ } while (0) #define REG_READ(reg, val) \ do { \ ret = cw1200_reg_read_32(priv, (reg), &(val)); \ if (ret < 0) \ - goto error; \ + goto exit; \ } while (0) switch (priv->hw_revision) { @@ -142,14 +148,14 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) ret = request_firmware(&firmware, fw_path, priv->pdev); if (ret) { pr_err("Can't load firmware file %s.\n", fw_path); - goto error; + goto exit; } buf = kmalloc(DOWNLOAD_BLOCK_SIZE, GFP_KERNEL | GFP_DMA); if (!buf) { pr_err("Can't allocate firmware load buffer.\n"); ret = -ENOMEM; - goto error; + goto firmware_release; } /* Check if the bootloader is ready */ @@ -163,7 +169,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) if (val32 != DOWNLOAD_I_AM_HERE) { pr_err("Bootloader is not ready.\n"); ret = -ETIMEDOUT; - goto error; + goto free_buffer; } /* Calculcate number of download blocks */ @@ -171,7 +177,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) /* Updating the length in Download Ctrl Area */ val32 = firmware->size; /* Explicit cast from size_t to u32 */ - APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, val32); + APB_WRITE2(DOWNLOAD_IMAGE_SIZE_REG, val32); /* Firmware downloading loop */ for (block = 0; block < num_blocks; block++) { @@ -183,7 +189,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) if (val32 != DOWNLOAD_PENDING) { pr_err("Bootloader reported error %d.\n", val32); ret = -EIO; - goto error; + goto free_buffer; } /* loop until put - get <= 24K */ @@ -198,7 +204,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) if ((put - get) > (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) { pr_err("Timeout waiting for FIFO.\n"); ret = -ETIMEDOUT; - goto error; + goto free_buffer; } /* calculate the block size */ @@ -220,12 +226,12 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) if (ret < 0) { pr_err("Can't write firmware block @ %d!\n", put & (DOWNLOAD_FIFO_SIZE - 1)); - goto error; + goto free_buffer; } /* update the put register */ put += block_size; - APB_WRITE(DOWNLOAD_PUT_REG, put); + APB_WRITE2(DOWNLOAD_PUT_REG, put); } /* End of firmware download loop */ /* Wait for the download completion */ @@ -238,19 +244,21 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) if (val32 != DOWNLOAD_SUCCESS) { pr_err("Wait for download completion failed: 0x%.8X\n", val32); ret = -ETIMEDOUT; - goto error; + goto free_buffer; } else { pr_info("Firmware download completed.\n"); ret = 0; } -error: +free_buffer: kfree(buf); - if (firmware) - release_firmware(firmware); +firmware_release: + release_firmware(firmware); +exit: return ret; #undef APB_WRITE +#undef APB_WRITE2 #undef APB_READ #undef REG_WRITE #undef REG_READ diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c index 3e78cc3ccb78..3689dbbd10bd 100644 --- a/drivers/net/wireless/cw1200/main.c +++ b/drivers/net/wireless/cw1200/main.c @@ -282,7 +282,6 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr, IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | IEEE80211_HW_REPORTS_TX_ACK_STATUS | - IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | @@ -374,9 +373,8 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr, INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work); INIT_WORK(&priv->set_beacon_wakeup_period_work, cw1200_set_beacon_wakeup_period_work); - init_timer(&priv->mcast_timeout); - priv->mcast_timeout.data = (unsigned long)priv; - priv->mcast_timeout.function = cw1200_mcast_timeout; + setup_timer(&priv->mcast_timeout, cw1200_mcast_timeout, + (unsigned long)priv); if (cw1200_queue_stats_init(&priv->tx_queue_stats, CW1200_LINK_ID_MAX, diff --git a/drivers/net/wireless/cw1200/pm.c b/drivers/net/wireless/cw1200/pm.c index 6907c8fd4578..d2202ae92bdd 100644 --- a/drivers/net/wireless/cw1200/pm.c +++ b/drivers/net/wireless/cw1200/pm.c @@ -101,9 +101,8 @@ int cw1200_pm_init(struct cw1200_pm_state *pm, { spin_lock_init(&pm->lock); - init_timer(&pm->stay_awake); - pm->stay_awake.data = (unsigned long)pm; - pm->stay_awake.function = cw1200_pm_stay_awake_tmo; + setup_timer(&pm->stay_awake, cw1200_pm_stay_awake_tmo, + (unsigned long)pm); return 0; } diff --git a/drivers/net/wireless/cw1200/queue.c b/drivers/net/wireless/cw1200/queue.c index 9c3925f58d79..0ba5ef9b3e7b 100644 --- a/drivers/net/wireless/cw1200/queue.c +++ b/drivers/net/wireless/cw1200/queue.c @@ -179,9 +179,7 @@ int cw1200_queue_init(struct cw1200_queue *queue, INIT_LIST_HEAD(&queue->pending); INIT_LIST_HEAD(&queue->free_pool); spin_lock_init(&queue->lock); - init_timer(&queue->gc); - queue->gc.data = (unsigned long)queue; - queue->gc.function = cw1200_queue_gc; + setup_timer(&queue->gc, cw1200_queue_gc, (unsigned long)queue); queue->pool = kzalloc(sizeof(struct cw1200_queue_item) * capacity, GFP_KERNEL); diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c index f2e276faca70..bff81b8d4164 100644 --- a/drivers/net/wireless/cw1200/scan.c +++ b/drivers/net/wireless/cw1200/scan.c @@ -39,9 +39,9 @@ static int cw1200_scan_start(struct cw1200_common *priv, struct wsm_scan *scan) cancel_delayed_work_sync(&priv->clear_recent_scan_work); atomic_set(&priv->scan.in_progress, 1); atomic_set(&priv->recent_scan, 1); - cw1200_pm_stay_awake(&priv->pm_state, tmo * HZ / 1000); + cw1200_pm_stay_awake(&priv->pm_state, msecs_to_jiffies(tmo)); queue_delayed_work(priv->workqueue, &priv->scan.timeout, - tmo * HZ / 1000); + msecs_to_jiffies(tmo)); ret = wsm_scan(priv, scan); if (ret) { atomic_set(&priv->scan.in_progress, 0); @@ -386,8 +386,8 @@ void cw1200_probe_work(struct work_struct *work) if (down_trylock(&priv->scan.lock)) { /* Scan is already in progress. Requeue self. */ schedule(); - queue_delayed_work(priv->workqueue, - &priv->scan.probe_work, HZ / 10); + queue_delayed_work(priv->workqueue, &priv->scan.probe_work, + msecs_to_jiffies(100)); mutex_unlock(&priv->conf_mutex); return; } diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c index 5b84664db13b..4a47c7f8a246 100644 --- a/drivers/net/wireless/cw1200/sta.c +++ b/drivers/net/wireless/cw1200/sta.c @@ -213,6 +213,7 @@ int cw1200_add_interface(struct ieee80211_hw *dev, /* __le32 auto_calibration_mode = __cpu_to_le32(1); */ vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_UAPSD | IEEE80211_VIF_SUPPORTS_CQM_RSSI; mutex_lock(&priv->conf_mutex); @@ -708,7 +709,8 @@ int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, if (sta) peer_addr = sta->addr; - key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; + key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE | + IEEE80211_KEY_FLAG_RESERVE_TAILROOM; switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 596525528f50..fd8d83dd4f62 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -145,7 +145,7 @@ static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) if (sta->aid > 0) ap->sta_aid[sta->aid - 1] = NULL; - if (!sta->ap && sta->u.sta.challenge) + if (!sta->ap) kfree(sta->u.sta.challenge); del_timer_sync(&sta->timer); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index dc1d20cf64ee..e5665804d986 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -3429,9 +3429,7 @@ il3945_setup_deferred_work(struct il_priv *il) il3945_hw_setup_deferred_work(il); - init_timer(&il->watchdog); - il->watchdog.data = (unsigned long)il; - il->watchdog.function = il_bg_watchdog; + setup_timer(&il->watchdog, il_bg_watchdog, (unsigned long)il); tasklet_init(&il->irq_tasklet, (void (*)(unsigned long))il3945_irq_tasklet, diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 2748fde4b90c..976f65fe9c38 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -6247,13 +6247,10 @@ il4965_setup_deferred_work(struct il_priv *il) INIT_WORK(&il->txpower_work, il4965_bg_txpower_work); - init_timer(&il->stats_periodic); - il->stats_periodic.data = (unsigned long)il; - il->stats_periodic.function = il4965_bg_stats_periodic; + setup_timer(&il->stats_periodic, il4965_bg_stats_periodic, + (unsigned long)il); - init_timer(&il->watchdog); - il->watchdog.data = (unsigned long)il; - il->watchdog.function = il_bg_watchdog; + setup_timer(&il->watchdog, il_bg_watchdog, (unsigned long)il); tasklet_init(&il->irq_tasklet, (void (*)(unsigned long))il4965_irq_tasklet, diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 0b7f46f0b079..c4d6dd7402d9 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -64,22 +64,8 @@ * ******************************************************************************/ -/* - * module name, copyright, version, etc. - */ #define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link AGN driver for Linux" - -#ifdef CONFIG_IWLWIFI_DEBUG -#define VD "d" -#else -#define VD -#endif - -#define DRV_VERSION IWLWIFI_VERSION VD - - MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); @@ -1011,13 +997,11 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) if (priv->lib->bt_params) iwlagn_bt_setup_deferred_work(priv); - init_timer(&priv->statistics_periodic); - priv->statistics_periodic.data = (unsigned long)priv; - priv->statistics_periodic.function = iwl_bg_statistics_periodic; + setup_timer(&priv->statistics_periodic, iwl_bg_statistics_periodic, + (unsigned long)priv); - init_timer(&priv->ucode_trace); - priv->ucode_trace.data = (unsigned long)priv; - priv->ucode_trace.function = iwl_bg_ucode_trace; + setup_timer(&priv->ucode_trace, iwl_bg_ucode_trace, + (unsigned long)priv); } void iwl_cancel_deferred_work(struct iwl_priv *priv) @@ -1244,11 +1228,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K; - if (!iwlwifi_mod_params.wd_disable) - trans_cfg.queue_watchdog_timeout = - priv->cfg->base_params->wd_timeout; - else - trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED; + trans_cfg.cmd_q_wdg_timeout = IWL_WATCHDOG_DISABLED; + trans_cfg.command_names = iwl_dvm_cmd_strings; trans_cfg.cmd_fifo = IWLAGN_CMD_FIFO_NUM; diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c index acb981a0a0aa..c4736c8834c5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tt.c +++ b/drivers/net/wireless/iwlwifi/dvm/tt.c @@ -612,15 +612,10 @@ void iwl_tt_initialize(struct iwl_priv *priv) memset(tt, 0, sizeof(struct iwl_tt_mgmt)); tt->state = IWL_TI_0; - init_timer(&priv->thermal_throttle.ct_kill_exit_tm); - priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv; - priv->thermal_throttle.ct_kill_exit_tm.function = - iwl_tt_check_exit_ct_kill; - init_timer(&priv->thermal_throttle.ct_kill_waiting_tm); - priv->thermal_throttle.ct_kill_waiting_tm.data = - (unsigned long)priv; - priv->thermal_throttle.ct_kill_waiting_tm.function = - iwl_tt_ready_for_ct_kill; + setup_timer(&priv->thermal_throttle.ct_kill_exit_tm, + iwl_tt_check_exit_ct_kill, (unsigned long)priv); + setup_timer(&priv->thermal_throttle.ct_kill_waiting_tm, + iwl_tt_ready_for_ct_kill, (unsigned long)priv); /* setup deferred ct kill work */ INIT_WORK(&priv->tt_work, iwl_bg_tt_work); INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index d1ce3ce13591..1e40a12de077 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -715,7 +715,7 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif, fifo = ctx->ac_to_fifo[tid_to_ac[tid]]; iwl_trans_txq_enable(priv->trans, q, fifo, sta_priv->sta_id, tid, - buf_size, ssn); + buf_size, ssn, 0); /* * If the limit is 0, then it wasn't initialised yet, diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index d5cee1530597..4dbef7e58c2e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -267,7 +267,7 @@ static int iwl_alive_notify(struct iwl_priv *priv) for (i = 0; i < n_queues; i++) if (queue_to_txf[i] != IWL_TX_FIFO_UNUSED) iwl_trans_ac_txq_enable(priv->trans, i, - queue_to_txf[i]); + queue_to_txf[i], 0); priv->passive_no_rx = false; priv->transport_queue_stop = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index a5f9198d5747..97e38d2e2983 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -92,6 +92,12 @@ #define IWL7265D_NVM_VERSION 0x0c11 #define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ +/* DCCM offsets and lengths */ +#define IWL7000_DCCM_OFFSET 0x800000 +#define IWL7260_DCCM_LEN 0x14000 +#define IWL3160_DCCM_LEN 0x10000 +#define IWL7265_DCCM_LEN 0x17A00 + #define IWL7260_FW_PRE "iwlwifi-7260-" #define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode" @@ -138,7 +144,8 @@ static const struct iwl_ht_params iwl7000_ht_params = { .led_mode = IWL_LED_RF_STATE, \ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \ .non_shared_ant = ANT_A, \ - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ + .dccm_offset = IWL7000_DCCM_OFFSET const struct iwl_cfg iwl7260_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 7260", @@ -149,6 +156,7 @@ const struct iwl_cfg iwl7260_2ac_cfg = { .nvm_calib_ver = IWL7260_TX_POWER_VERSION, .host_interrupt_operation_mode = true, .lp_xtal_workaround = true, + .dccm_len = IWL7260_DCCM_LEN, }; const struct iwl_cfg iwl7260_2ac_cfg_high_temp = { @@ -161,6 +169,7 @@ const struct iwl_cfg iwl7260_2ac_cfg_high_temp = { .high_temp = true, .host_interrupt_operation_mode = true, .lp_xtal_workaround = true, + .dccm_len = IWL7260_DCCM_LEN, }; const struct iwl_cfg iwl7260_2n_cfg = { @@ -172,6 +181,7 @@ const struct iwl_cfg iwl7260_2n_cfg = { .nvm_calib_ver = IWL7260_TX_POWER_VERSION, .host_interrupt_operation_mode = true, .lp_xtal_workaround = true, + .dccm_len = IWL7260_DCCM_LEN, }; const struct iwl_cfg iwl7260_n_cfg = { @@ -183,6 +193,7 @@ const struct iwl_cfg iwl7260_n_cfg = { .nvm_calib_ver = IWL7260_TX_POWER_VERSION, .host_interrupt_operation_mode = true, .lp_xtal_workaround = true, + .dccm_len = IWL7260_DCCM_LEN, }; const struct iwl_cfg iwl3160_2ac_cfg = { @@ -193,6 +204,7 @@ const struct iwl_cfg iwl3160_2ac_cfg = { .nvm_ver = IWL3160_NVM_VERSION, .nvm_calib_ver = IWL3160_TX_POWER_VERSION, .host_interrupt_operation_mode = true, + .dccm_len = IWL3160_DCCM_LEN, }; const struct iwl_cfg iwl3160_2n_cfg = { @@ -203,6 +215,7 @@ const struct iwl_cfg iwl3160_2n_cfg = { .nvm_ver = IWL3160_NVM_VERSION, .nvm_calib_ver = IWL3160_TX_POWER_VERSION, .host_interrupt_operation_mode = true, + .dccm_len = IWL3160_DCCM_LEN, }; const struct iwl_cfg iwl3160_n_cfg = { @@ -213,6 +226,7 @@ const struct iwl_cfg iwl3160_n_cfg = { .nvm_ver = IWL3160_NVM_VERSION, .nvm_calib_ver = IWL3160_TX_POWER_VERSION, .host_interrupt_operation_mode = true, + .dccm_len = IWL3160_DCCM_LEN, }; static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = { @@ -240,6 +254,7 @@ const struct iwl_cfg iwl3165_2ac_cfg = { .nvm_ver = IWL3165_NVM_VERSION, .nvm_calib_ver = IWL3165_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, }; const struct iwl_cfg iwl7265_2ac_cfg = { @@ -250,6 +265,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = { .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, }; const struct iwl_cfg iwl7265_2n_cfg = { @@ -260,6 +276,7 @@ const struct iwl_cfg iwl7265_2n_cfg = { .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, }; const struct iwl_cfg iwl7265_n_cfg = { @@ -270,6 +287,7 @@ const struct iwl_cfg iwl7265_n_cfg = { .nvm_ver = IWL7265_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, }; const struct iwl_cfg iwl7265d_2ac_cfg = { @@ -280,6 +298,7 @@ const struct iwl_cfg iwl7265d_2ac_cfg = { .nvm_ver = IWL7265D_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, }; const struct iwl_cfg iwl7265d_2n_cfg = { @@ -290,6 +309,7 @@ const struct iwl_cfg iwl7265d_2n_cfg = { .nvm_ver = IWL7265D_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, }; const struct iwl_cfg iwl7265d_n_cfg = { @@ -300,6 +320,7 @@ const struct iwl_cfg iwl7265d_n_cfg = { .nvm_ver = IWL7265D_NVM_VERSION, .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, + .dccm_len = IWL7265_DCCM_LEN, }; MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 3668fc57e770..2f7fe8167dc9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -81,12 +81,21 @@ #define IWL8000_NVM_VERSION 0x0a1d #define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */ +/* Memory offsets and lengths */ +#define IWL8260_DCCM_OFFSET 0x800000 +#define IWL8260_DCCM_LEN 0x18000 +#define IWL8260_DCCM2_OFFSET 0x880000 +#define IWL8260_DCCM2_LEN 0x8000 +#define IWL8260_SMEM_OFFSET 0x400000 +#define IWL8260_SMEM_LEN 0x68000 + #define IWL8000_FW_PRE "iwlwifi-8000" #define IWL8000_MODULE_FIRMWARE(api) \ IWL8000_FW_PRE "-" __stringify(api) ".ucode" #define NVM_HW_SECTION_NUM_FAMILY_8000 10 -#define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin" +#define DEFAULT_NVM_FILE_FAMILY_8000A "iwl_nvm_8000.bin" +#define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000B.bin" /* Max SDIO RX aggregation size of the ADDBA request/response */ #define MAX_RX_AGG_SIZE_8260_SDIO 28 @@ -124,7 +133,13 @@ static const struct iwl_ht_params iwl8000_ht_params = { .led_mode = IWL_LED_RF_STATE, \ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \ .d0i3 = true, \ - .non_shared_ant = ANT_A + .non_shared_ant = ANT_A, \ + .dccm_offset = IWL8260_DCCM_OFFSET, \ + .dccm_len = IWL8260_DCCM_LEN, \ + .dccm2_offset = IWL8260_DCCM2_OFFSET, \ + .dccm2_len = IWL8260_DCCM2_LEN, \ + .smem_offset = IWL8260_SMEM_OFFSET, \ + .smem_len = IWL8260_SMEM_LEN const struct iwl_cfg iwl8260_2n_cfg = { .name = "Intel(R) Dual Band Wireless N 8260", @@ -145,6 +160,16 @@ const struct iwl_cfg iwl8260_2ac_cfg = { .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; +const struct iwl_cfg iwl4165_2ac_cfg = { + .name = "Intel(R) Dual Band Wireless AC 4165", + .fw_name_pre = IWL8000_FW_PRE, + IWL_DEVICE_8000, + .ht_params = &iwl8000_ht_params, + .nvm_ver = IWL8000_NVM_VERSION, + .nvm_calib_ver = IWL8000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + const struct iwl_cfg iwl8260_2ac_sdio_cfg = { .name = "Intel(R) Dual Band Wireless-AC 8260", .fw_name_pre = IWL8000_FW_PRE, @@ -153,6 +178,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { .nvm_ver = IWL8000_NVM_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, + .default_nvm_file_8000A = DEFAULT_NVM_FILE_FAMILY_8000A, .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, .disable_dummy_notification = true, .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, @@ -167,6 +193,7 @@ const struct iwl_cfg iwl4165_2ac_sdio_cfg = { .nvm_ver = IWL8000_NVM_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, + .default_nvm_file_8000A = DEFAULT_NVM_FILE_FAMILY_8000A, .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, .bt_shared_single_ant = true, .disable_dummy_notification = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 3a4b9c7fc083..4b190d98a1ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -126,7 +126,7 @@ enum iwl_led_mode { /* TX queue watchdog timeouts in mSecs */ #define IWL_WATCHDOG_DISABLED 0 -#define IWL_DEF_WD_TIMEOUT 2000 +#define IWL_DEF_WD_TIMEOUT 2500 #define IWL_LONG_WD_TIMEOUT 10000 #define IWL_MAX_WD_TIMEOUT 120000 @@ -261,6 +261,12 @@ struct iwl_pwr_tx_backoff { * station can receive in HT * @max_vht_ampdu_exponent: the exponent of the max length of A-MPDU that the * station can receive in VHT + * @dccm_offset: offset from which DCCM begins + * @dccm_len: length of DCCM (including runtime stack CCM) + * @dccm2_offset: offset from which the second DCCM begins + * @dccm2_len: length of the second DCCM + * @smem_offset: offset from which the SMEM begins + * @smem_len: the length of SMEM * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -298,11 +304,18 @@ struct iwl_cfg { const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; bool no_power_up_nic_in_init; const char *default_nvm_file; + const char *default_nvm_file_8000A; unsigned int max_rx_agg_size; bool disable_dummy_notification; unsigned int max_tx_agg_size; unsigned int max_ht_ampdu_exponent; unsigned int max_vht_ampdu_exponent; + const u32 dccm_offset; + const u32 dccm_len; + const u32 dccm2_offset; + const u32 dccm2_len; + const u32 smem_offset; + const u32 smem_len; }; /* @@ -369,8 +382,8 @@ extern const struct iwl_cfg iwl7265d_2n_cfg; extern const struct iwl_cfg iwl7265d_n_cfg; extern const struct iwl_cfg iwl8260_2n_cfg; extern const struct iwl_cfg iwl8260_2ac_cfg; +extern const struct iwl_cfg iwl4165_2ac_cfg; extern const struct iwl_cfg iwl8260_2ac_sdio_cfg; -extern const struct iwl_cfg iwl4265_2ac_sdio_cfg; extern const struct iwl_cfg iwl4165_2ac_sdio_cfg; #endif /* CONFIG_IWLMVM */ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index aff63c3f5bf8..faa17f2e352a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -184,6 +184,7 @@ #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ #define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */ #define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ +#define CSR_HW_IF_CONFIG_REG_ENABLE_PME (0x10000000) #define CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */ #define CSR_MBOX_SET_REG_OS_ALIVE BIT(5) @@ -306,6 +307,7 @@ enum { SILICON_A_STEP = 0, SILICON_B_STEP, + SILICON_C_STEP, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 850b85a47806..996e7f16adf9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -84,21 +84,8 @@ * ******************************************************************************/ -/* - * module name, copyright, version, etc. - */ #define DRV_DESCRIPTION "Intel(R) Wireless WiFi driver for Linux" - -#ifdef CONFIG_IWLWIFI_DEBUG -#define VD "d" -#else -#define VD -#endif - -#define DRV_VERSION IWLWIFI_VERSION VD - MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); @@ -250,9 +237,6 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) /* * Starting 8000B - FW name format has changed. This overwrites the * previous name and uses the new format. - * - * TODO: - * Once there is only one supported step for 8000 family - delete this! */ if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { char rev_step[2] = { @@ -263,13 +247,6 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) if (CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP) rev_step[0] = 0; - /* - * If hw_rev wasn't set yet - default as B-step. If it IS A-step - * we'll reload that FW later instead. - */ - if (drv->trans->hw_rev == 0) - rev_step[0] = 'B'; - snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%s-%s.ucode", name_pre, rev_step, tag); } @@ -926,6 +903,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, IWL_UCODE_REGULAR_USNIFFER, tlv_len); break; + case IWL_UCODE_TLV_SDIO_ADMA_ADDR: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + drv->fw.sdio_adma_addr = + le32_to_cpup((__le32 *)tlv_data); + break; default: IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); break; @@ -1082,7 +1065,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) u32 api_ver; int i; bool load_module = false; - u32 hw_rev = drv->trans->hw_rev; fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH; fw->ucode_capa.standard_phy_calibration_size = @@ -1275,50 +1257,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) op->name, err); #endif } - - /* - * We may have loaded the wrong FW file in 8000 HW family if it is an - * A-step card, and if drv->trans->hw_rev wasn't properly read when - * the FW file had been loaded. (This might happen in SDIO.) In such a - * case - unload and reload the correct file. - * - * TODO: - * Once there is only one supported step for 8000 family - delete this! - */ - if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 && - CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP && - drv->trans->hw_rev != hw_rev) { - char firmware_name[32]; - - /* Free previous FW resources */ - if (drv->op_mode) - _iwl_op_mode_stop(drv); - iwl_dealloc_ucode(drv); - - /* Build name of correct-step FW */ - snprintf(firmware_name, sizeof(firmware_name), - strrchr(drv->firmware_name, '-')); - snprintf(drv->firmware_name, sizeof(drv->firmware_name), - "%s%s", drv->cfg->fw_name_pre, firmware_name); - - /* Clear data before loading correct FW */ - list_del(&drv->list); - - /* Request correct FW file this time */ - IWL_DEBUG_INFO(drv, "attempting to load A-step FW %s\n", - drv->firmware_name); - err = request_firmware(&ucode_raw, drv->firmware_name, - drv->trans->dev); - if (err) { - IWL_ERR(drv, "Failed swapping FW!\n"); - goto out_unbind; - } - - /* Redo callback function - this time with right FW */ - iwl_req_fw_callback(ucode_raw, context); - } - - kfree(pieces); return; try_again: @@ -1429,7 +1367,7 @@ struct iwl_mod_params iwlwifi_mod_params = { .restart_fw = true, .bt_coex_active = true, .power_level = IWL_POWER_INDEX_1, - .wd_disable = true, + .d0i3_disable = true, #ifndef CONFIG_IWLWIFI_UAPSD .uapsd_disable = true, #endif /* CONFIG_IWLWIFI_UAPSD */ @@ -1492,7 +1430,7 @@ static int __init iwl_drv_init(void) for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv); - pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n"); + pr_info(DRV_DESCRIPTION "\n"); pr_info(DRV_COPYRIGHT "\n"); #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1539,15 +1477,15 @@ module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling, MODULE_PARM_DESC(antenna_coupling, "specify antenna coupling in dB (default: 0 dB)"); -module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO); -MODULE_PARM_DESC(wd_disable, - "Disable stuck queue watchdog timer 0=system default, 1=disable (default: 1)"); - module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO); MODULE_PARM_DESC(nvm_file, "NVM file name"); -module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, +module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable, bool, S_IRUGO); +MODULE_PARM_DESC(d0i3_disable, "disable d0i3 functionality (default: Y)"); + +module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, + bool, S_IRUGO | S_IWUSR); #ifdef CONFIG_IWLWIFI_UAPSD MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: N)"); #else diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h index be4f8972241a..adf522c756e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h @@ -68,7 +68,6 @@ /* for all modules */ #define DRV_NAME "iwlwifi" -#define IWLWIFI_VERSION "in-tree:" #define DRV_COPYRIGHT "Copyright(c) 2003- 2014 Intel Corporation" #define DRV_AUTHOR "" diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index 20a8a64c9fe3..919a2548a92c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -71,7 +71,6 @@ /** * enum iwl_fw_error_dump_type - types of data in the dump file - * @IWL_FW_ERROR_DUMP_SRAM: * @IWL_FW_ERROR_DUMP_CSR: Control Status Registers - from offset 0 * @IWL_FW_ERROR_DUMP_RXF: * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as @@ -82,9 +81,10 @@ * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several * sections like this in a single file. * @IWL_FW_ERROR_DUMP_FH_REGS: range of FH registers + * @IWL_FW_ERROR_DUMP_MEM: chunk of memory */ enum iwl_fw_error_dump_type { - IWL_FW_ERROR_DUMP_SRAM = 0, + /* 0 is deprecated */ IWL_FW_ERROR_DUMP_CSR = 1, IWL_FW_ERROR_DUMP_RXF = 2, IWL_FW_ERROR_DUMP_TXCMD = 3, @@ -93,6 +93,7 @@ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_PRPH = 6, IWL_FW_ERROR_DUMP_TXF = 7, IWL_FW_ERROR_DUMP_FH_REGS = 8, + IWL_FW_ERROR_DUMP_MEM = 9, IWL_FW_ERROR_DUMP_MAX, }; @@ -133,6 +134,27 @@ struct iwl_fw_error_dump_txcmd { u8 data[]; } __packed; +/** + * struct iwl_fw_error_dump_fifo - RX/TX FIFO data + * @fifo_num: number of FIFO (starting from 0) + * @available_bytes: num of bytes available in FIFO (may be less than FIFO size) + * @wr_ptr: position of write pointer + * @rd_ptr: position of read pointer + * @fence_ptr: position of fence pointer + * @fence_mode: the current mode of the fence (before locking) - + * 0=follow RD pointer ; 1 = freeze + * @data: all of the FIFO's data + */ +struct iwl_fw_error_dump_fifo { + __le32 fifo_num; + __le32 available_bytes; + __le32 wr_ptr; + __le32 rd_ptr; + __le32 fence_ptr; + __le32 fence_mode; + u8 data[]; +} __packed; + enum iwl_fw_error_dump_family { IWL_FW_ERROR_DUMP_FAMILY_7 = 7, IWL_FW_ERROR_DUMP_FAMILY_8 = 8, @@ -180,6 +202,23 @@ struct iwl_fw_error_dump_prph { __le32 data[]; }; +enum iwl_fw_error_dump_mem_type { + IWL_FW_ERROR_DUMP_MEM_SRAM, + IWL_FW_ERROR_DUMP_MEM_SMEM, +}; + +/** + * struct iwl_fw_error_dump_mem - chunk of memory + * @type: %enum iwl_fw_error_dump_mem_type + * @offset: the offset from which the memory was read + * @data: the content of the memory + */ +struct iwl_fw_error_dump_mem { + __le32 type; + __le32 offset; + u8 data[]; +}; + /** * iwl_fw_error_next_data - advance fw error dump data pointer * @data: previous data block diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 1bbe4fc47b97..016d91384681 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -132,6 +132,7 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, IWL_UCODE_TLV_N_SCAN_CHANNELS = 31, IWL_UCODE_TLV_SEC_RT_USNIFFER = 34, + IWL_UCODE_TLV_SDIO_ADMA_ADDR = 35, IWL_UCODE_TLV_FW_DBG_DEST = 38, IWL_UCODE_TLV_FW_DBG_CONF = 39, }; @@ -234,29 +235,34 @@ enum iwl_ucode_tlv_flag { /** * enum iwl_ucode_tlv_api - ucode api - * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. - * @IWL_UCODE_TLV_CAPA_EXTENDED_BEACON: Support Extended beacon notification * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex - * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API. * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time * longer than the passive one, which is essential for fragmented scan. + * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command, * regardless of the band or the number of the probes. FW will calculate * the actual dwell time. + * @IWL_UCODE_TLV_API_SCD_CFG: This firmware can configure the scheduler + * through the dedicated host command. + * @IWL_UCODE_TLV_API_SINGLE_SCAN_EBS: EBS is supported for single scans too. + * @IWL_UCODE_TLV_API_ASYNC_DTM: Async temperature notifications are supported. + * @IWL_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params */ enum iwl_ucode_tlv_api { - IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), - IWL_UCODE_TLV_CAPA_EXTENDED_BEACON = BIT(1), IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), - IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6), IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), + IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10), IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13), + IWL_UCODE_TLV_API_SCD_CFG = BIT(15), + IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = BIT(16), + IWL_UCODE_TLV_API_ASYNC_DTM = BIT(17), + IWL_UCODE_TLV_API_LQ_SS_PARAMS = BIT(18), }; /** @@ -264,6 +270,7 @@ enum iwl_ucode_tlv_api { * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory * @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. + * @IWL_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer * @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current * tx power value into TPC Report action frame and Link Measurement Report @@ -282,6 +289,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), IWL_UCODE_TLV_CAPA_LAR_SUPPORT = BIT(1), IWL_UCODE_TLV_CAPA_UMAC_SCAN = BIT(2), + IWL_UCODE_TLV_CAPA_BEAMFORMER = BIT(3), IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = BIT(6), IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = BIT(8), IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9), diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index e6dc3b870949..ffd785cc67d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -152,6 +152,8 @@ struct iwl_fw_cscheme_list { * @mvm_fw: indicates this is MVM firmware * @cipher_scheme: optional external cipher scheme. * @human_readable: human readable version + * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until + * we get the ALIVE from the uCode * @dbg_dest_tlv: points to the destination TLV for debug * @dbg_conf_tlv: array of pointers to configuration TLVs for debug * @dbg_conf_tlv_len: lengths of the @dbg_conf_tlv entries @@ -181,6 +183,8 @@ struct iwl_fw { struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; u8 human_readable[FW_VER_HUMAN_READABLE_SZ]; + u32 sdio_adma_addr; + struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv; struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX]; size_t dbg_conf_tlv_len[FW_DBG_MAX]; diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 7a2cbf6f90db..03250a45272e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -193,11 +193,15 @@ void iwl_force_nmi(struct iwl_trans *trans) * DEVICE_SET_NMI_8000B_REG - is used. */ if ((trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) || - (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)) - iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL); - else + (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)) { + iwl_write_prph(trans, DEVICE_SET_NMI_REG, + DEVICE_SET_NMI_VAL_DRV); + iwl_write_prph(trans, DEVICE_SET_NMI_REG, + DEVICE_SET_NMI_VAL_HW); + } else { iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG, DEVICE_SET_NMI_8000B_VAL); + } } IWL_EXPORT_SYMBOL(iwl_force_nmi); diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index 71507cf490e6..e8eabd21ccfe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -96,13 +96,13 @@ enum iwl_disable_11n { * use IWL_[DIS,EN]ABLE_HT_* constants * @amsdu_size_8K: enable 8K amsdu size, default = 0 * @restart_fw: restart firmware, default = 1 - * @wd_disable: disable stuck queue check, default = 1 * @bt_coex_active: enable bt coex, default = true * @led_mode: system default, default = 0 * @power_save: enable power save, default = false * @power_level: power level, default = 1 * @debug_level: levels are IWL_DL_* * @ant_coupling: antenna coupling in dB, default = 0 + * @d0i3_disable: disable d0i3, default = 1, * @fw_monitor: allow to use firmware monitor */ struct iwl_mod_params { @@ -110,7 +110,6 @@ struct iwl_mod_params { unsigned int disable_11n; int amsdu_size_8K; bool restart_fw; - int wd_disable; bool bt_coex_active; int led_mode; bool power_save; @@ -121,6 +120,7 @@ struct iwl_mod_params { int ant_coupling; char *nvm_file; bool uapsd_disable; + bool d0i3_disable; bool fw_monitor; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 06e02fcd6f7b..c74f1a4edf23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -468,6 +468,8 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg); data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg); data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg); + data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(radio_cfg); + data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg); } static void iwl_set_hw_address(const struct iwl_cfg *cfg, @@ -592,6 +594,10 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw); iwl_set_radio_cfg(cfg, data, radio_cfg); + if (data->valid_tx_ant) + tx_chains &= data->valid_tx_ant; + if (data->valid_rx_ant) + rx_chains &= data->valid_rx_ant; sku = iwl_get_sku(cfg, nvm_sw); data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 2df51eab1348..6221e4dfc64f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -99,6 +99,7 @@ #define APMG_PCIDEV_STT_VAL_PERSIST_DIS (0x00000200) #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) +#define APMG_PCIDEV_STT_VAL_WAKE_ME (0x00004000) #define APMG_RTC_INT_STT_RFKILL (0x10000000) @@ -107,7 +108,8 @@ /* Device NMI register */ #define DEVICE_SET_NMI_REG 0x00a01c30 -#define DEVICE_SET_NMI_VAL 0x1 +#define DEVICE_SET_NMI_VAL_HW BIT(0) +#define DEVICE_SET_NMI_VAL_DRV BIT(7) #define DEVICE_SET_NMI_8000B_REG 0x00a01c24 #define DEVICE_SET_NMI_8000B_VAL 0x1000000 @@ -250,6 +252,7 @@ #define SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F) #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) +#define SCD_GP_CTRL_ENABLE_31_QUEUES BIT(0) /* Context Data */ #define SCD_CONTEXT_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x600) @@ -283,32 +286,9 @@ #define SCD_CHAINEXT_EN (SCD_BASE + 0x244) #define SCD_AGGR_SEL (SCD_BASE + 0x248) #define SCD_INTERRUPT_MASK (SCD_BASE + 0x108) +#define SCD_GP_CTRL (SCD_BASE + 0x1a8) #define SCD_EN_CTRL (SCD_BASE + 0x254) -static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl) -{ - if (chnl < 20) - return SCD_BASE + 0x18 + chnl * 4; - WARN_ON_ONCE(chnl >= 32); - return SCD_BASE + 0x284 + (chnl - 20) * 4; -} - -static inline unsigned int SCD_QUEUE_RDPTR(unsigned int chnl) -{ - if (chnl < 20) - return SCD_BASE + 0x68 + chnl * 4; - WARN_ON_ONCE(chnl >= 32); - return SCD_BASE + 0x2B4 + (chnl - 20) * 4; -} - -static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl) -{ - if (chnl < 20) - return SCD_BASE + 0x10c + chnl * 4; - WARN_ON_ONCE(chnl >= 32); - return SCD_BASE + 0x384 + (chnl - 20) * 4; -} - /*********************** END TX SCHEDULER *************************************/ /* Oscillator clock */ @@ -358,18 +338,40 @@ enum secure_load_status_reg { /* Rx FIFO */ #define RXF_SIZE_ADDR (0xa00c88) +#define RXF_RD_D_SPACE (0xa00c40) +#define RXF_RD_WR_PTR (0xa00c50) +#define RXF_RD_RD_PTR (0xa00c54) +#define RXF_RD_FENCE_PTR (0xa00c4c) +#define RXF_SET_FENCE_MODE (0xa00c14) +#define RXF_LD_WR2FENCE (0xa00c1c) +#define RXF_FIFO_RD_FENCE_INC (0xa00c68) #define RXF_SIZE_BYTE_CND_POS (7) #define RXF_SIZE_BYTE_CNT_MSK (0x3ff << RXF_SIZE_BYTE_CND_POS) +#define RXF_DIFF_FROM_PREV (0x200) #define RXF_LD_FENCE_OFFSET_ADDR (0xa00c10) #define RXF_FIFO_RD_FENCE_ADDR (0xa00c0c) +/* Tx FIFO */ +#define TXF_FIFO_ITEM_CNT (0xa00438) +#define TXF_WR_PTR (0xa00414) +#define TXF_RD_PTR (0xa00410) +#define TXF_FENCE_PTR (0xa00418) +#define TXF_LOCK_FENCE (0xa00424) +#define TXF_LARC_NUM (0xa0043c) +#define TXF_READ_MODIFY_DATA (0xa00448) +#define TXF_READ_MODIFY_ADDR (0xa0044c) + /* FW monitor */ +#define MON_BUFF_SAMPLE_CTL (0xa03c00) #define MON_BUFF_BASE_ADDR (0xa03c3c) #define MON_BUFF_END_ADDR (0xa03c40) #define MON_BUFF_WRPTR (0xa03c44) #define MON_BUFF_CYCLE_CNT (0xa03c48) +#define DBGC_IN_SAMPLE (0xa03c00) +#define DBGC_OUT_CTRL (0xa03c0c) + /* FW chicken bits */ #define LMPM_CHICK 0xA01FF8 enum { diff --git a/drivers/net/wireless/iwlwifi/iwl-scd.h b/drivers/net/wireless/iwlwifi/iwl-scd.h index 6c622b21bba7..f2353ebf2666 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scd.h +++ b/drivers/net/wireless/iwlwifi/iwl-scd.h @@ -69,14 +69,6 @@ #include "iwl-prph.h" -static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans, - u16 txq_id) -{ - iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), - (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| - (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); -} - static inline void iwl_scd_txq_set_chain(struct iwl_trans *trans, u16 txq_id) { @@ -115,4 +107,37 @@ static inline void iwl_scd_enable_set_active(struct iwl_trans *trans, { iwl_write_prph(trans, SCD_EN_CTRL, value); } + +static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl) +{ + if (chnl < 20) + return SCD_BASE + 0x18 + chnl * 4; + WARN_ON_ONCE(chnl >= 32); + return SCD_BASE + 0x284 + (chnl - 20) * 4; +} + +static inline unsigned int SCD_QUEUE_RDPTR(unsigned int chnl) +{ + if (chnl < 20) + return SCD_BASE + 0x68 + chnl * 4; + WARN_ON_ONCE(chnl >= 32); + return SCD_BASE + 0x2B4 + chnl * 4; +} + +static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl) +{ + if (chnl < 20) + return SCD_BASE + 0x10c + chnl * 4; + WARN_ON_ONCE(chnl >= 32); + return SCD_BASE + 0x334 + chnl * 4; +} + +static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans, + u16 txq_id) +{ + iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), + (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| + (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); +} + #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 028408a6ecba..a96bd8db6ceb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -368,6 +368,7 @@ enum iwl_trans_status { * @cmd_queue: the index of the command queue. * Must be set before start_fw. * @cmd_fifo: the fifo for host commands + * @cmd_q_wdg_timeout: the timeout of the watchdog timer for the command queue. * @no_reclaim_cmds: Some devices erroneously don't set the * SEQ_RX_FRAME bit on some notifications, this is the * list of such notifications to filter. Max length is @@ -378,24 +379,26 @@ enum iwl_trans_status { * @bc_table_dword: set to true if the BC table expects the byte count to be * in DWORD (as opposed to bytes) * @scd_set_active: should the transport configure the SCD for HCMD queue - * @queue_watchdog_timeout: time (in ms) after which queues - * are considered stuck and will trigger device restart * @command_names: array of command names, must be 256 entries * (one for each command); for debugging only + * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until + * we get the ALIVE from the uCode */ struct iwl_trans_config { struct iwl_op_mode *op_mode; u8 cmd_queue; u8 cmd_fifo; + unsigned int cmd_q_wdg_timeout; const u8 *no_reclaim_cmds; unsigned int n_no_reclaim_cmds; bool rx_buf_size_8k; bool bc_table_dword; bool scd_set_active; - unsigned int queue_watchdog_timeout; const char *const *command_names; + + u32 sdio_adma_addr; }; struct iwl_trans_dump_data { @@ -507,7 +510,8 @@ struct iwl_trans_ops { struct sk_buff_head *skbs); void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn, - const struct iwl_trans_txq_scd_cfg *cfg); + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int queue_wdg_timeout); void (*txq_disable)(struct iwl_trans *trans, int queue, bool configure_scd); @@ -551,6 +555,21 @@ enum iwl_trans_state { IWL_TRANS_FW_ALIVE = 1, }; +/** + * enum iwl_d0i3_mode - d0i3 mode + * + * @IWL_D0I3_MODE_OFF - d0i3 is disabled + * @IWL_D0I3_MODE_ON_IDLE - enter d0i3 when device is idle + * (e.g. no active references) + * @IWL_D0I3_MODE_ON_SUSPEND - enter d0i3 only on suspend + * (in case of 'any' trigger) + */ +enum iwl_d0i3_mode { + IWL_D0I3_MODE_OFF = 0, + IWL_D0I3_MODE_ON_IDLE, + IWL_D0I3_MODE_ON_SUSPEND, +}; + /** * struct iwl_trans - transport common data * @@ -612,6 +631,8 @@ struct iwl_trans { const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX]; u8 dbg_dest_reg_num; + enum iwl_d0i3_mode d0i3_mode; + /* pointer to trans specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ char trans_specific[0] __aligned(sizeof(void *)); @@ -808,19 +829,21 @@ static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue, static inline void iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, - const struct iwl_trans_txq_scd_cfg *cfg) + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int queue_wdg_timeout) { might_sleep(); if (unlikely((trans->state != IWL_TRANS_FW_ALIVE))) IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - trans->ops->txq_enable(trans, queue, ssn, cfg); + trans->ops->txq_enable(trans, queue, ssn, cfg, queue_wdg_timeout); } static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, int fifo, int sta_id, int tid, - int frame_limit, u16 ssn) + int frame_limit, u16 ssn, + unsigned int queue_wdg_timeout) { struct iwl_trans_txq_scd_cfg cfg = { .fifo = fifo, @@ -830,11 +853,12 @@ static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, .aggregate = sta_id >= 0, }; - iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg); + iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg, queue_wdg_timeout); } -static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, - int fifo) +static inline +void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, int fifo, + unsigned int queue_wdg_timeout) { struct iwl_trans_txq_scd_cfg cfg = { .fifo = fifo, @@ -844,16 +868,16 @@ static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, .aggregate = false, }; - iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg); + iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg, queue_wdg_timeout); } static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, - u32 txq_bm) + u32 txqs) { if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return trans->ops->wait_tx_queue_empty(trans, txq_bm); + return trans->ops->wait_tx_queue_empty(trans, txqs); } static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index a3bfda45d9e6..1ec4d55155f7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -342,7 +342,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 12, .lut20 = { - cpu_to_le32(0x00000001), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -363,7 +363,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 20, .lut20 = { - cpu_to_le32(0x00000002), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -384,7 +384,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 21, .lut20 = { - cpu_to_le32(0x00000003), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -405,7 +405,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 23, .lut20 = { - cpu_to_le32(0x00000004), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -426,7 +426,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 27, .lut20 = { - cpu_to_le32(0x00000005), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -447,7 +447,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 30, .lut20 = { - cpu_to_le32(0x00000006), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -468,7 +468,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 32, .lut20 = { - cpu_to_le32(0x00000007), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -489,7 +489,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 33, .lut20 = { - cpu_to_le32(0x00000008), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -989,7 +989,7 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { - struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_bt_iterator_data *data = _data; struct iwl_mvm *mvm = data->mvm; @@ -1025,7 +1025,7 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_rssi_event rssi_event) { - struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_bt_iterator_data data = { .mvm = mvm, }; diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index b3210cfbecc8..d530ef3da107 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -330,7 +330,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 12, .lut20 = { - cpu_to_le32(0x00000001), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -351,7 +351,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 20, .lut20 = { - cpu_to_le32(0x00000002), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -372,7 +372,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 21, .lut20 = { - cpu_to_le32(0x00000003), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -393,7 +393,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 23, .lut20 = { - cpu_to_le32(0x00000004), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -414,7 +414,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 27, .lut20 = { - cpu_to_le32(0x00000005), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -435,7 +435,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 30, .lut20 = { - cpu_to_le32(0x00000006), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -456,7 +456,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 32, .lut20 = { - cpu_to_le32(0x00000007), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -477,7 +477,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = { { .range = 33, .lut20 = { - cpu_to_le32(0x00000008), cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), @@ -1034,7 +1034,7 @@ int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { - struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_bt_iterator_data *data = _data; struct iwl_mvm *mvm = data->mvm; @@ -1070,7 +1070,7 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_rssi_event rssi_event) { - struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_bt_iterator_data data = { .mvm = mvm, }; diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 3bd93476ec1c..beba375489f1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -94,13 +94,42 @@ #define IWL_MVM_BT_COEX_MPLUT 1 #define IWL_MVM_BT_COEX_RRC 1 #define IWL_MVM_BT_COEX_TTC 1 -#define IWL_MVM_BT_COEX_MPLUT_REG0 0x28412201 +#define IWL_MVM_BT_COEX_MPLUT_REG0 0x22002200 #define IWL_MVM_BT_COEX_MPLUT_REG1 0x11118451 #define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 #define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0 -#define IWL_MVM_QUOTA_THRESHOLD 8 +#define IWL_MVM_QUOTA_THRESHOLD 4 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 -#define IWL_MVM_RS_DISABLE_MIMO 0 +#define IWL_MVM_RS_DISABLE_P2P_MIMO 0 +#define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 +#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 +#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 +#define IWL_MVM_RS_INITIAL_MIMO_NUM_RATES 3 +#define IWL_MVM_RS_INITIAL_SISO_NUM_RATES 3 +#define IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES 2 +#define IWL_MVM_RS_INITIAL_LEGACY_RETRIES 2 +#define IWL_MVM_RS_SECONDARY_LEGACY_RETRIES 1 +#define IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES 16 +#define IWL_MVM_RS_SECONDARY_SISO_NUM_RATES 3 +#define IWL_MVM_RS_SECONDARY_SISO_RETRIES 1 +#define IWL_MVM_RS_RATE_MIN_FAILURE_TH 3 +#define IWL_MVM_RS_RATE_MIN_SUCCESS_TH 8 +#define IWL_MVM_RS_STAY_IN_COLUMN_TIMEOUT 5 /* Seconds */ +#define IWL_MVM_RS_IDLE_TIMEOUT 5 /* Seconds */ +#define IWL_MVM_RS_MISSED_RATE_MAX 15 +#define IWL_MVM_RS_LEGACY_FAILURE_LIMIT 160 +#define IWL_MVM_RS_LEGACY_SUCCESS_LIMIT 480 +#define IWL_MVM_RS_LEGACY_TABLE_COUNT 160 +#define IWL_MVM_RS_NON_LEGACY_FAILURE_LIMIT 400 +#define IWL_MVM_RS_NON_LEGACY_SUCCESS_LIMIT 4500 +#define IWL_MVM_RS_NON_LEGACY_TABLE_COUNT 1500 +#define IWL_MVM_RS_SR_FORCE_DECREASE 15 /* percent */ +#define IWL_MVM_RS_SR_NO_DECREASE 85 /* percent */ +#define IWL_MVM_RS_AGG_TIME_LIMIT 4000 /* 4 msecs. valid 100-8000 */ +#define IWL_MVM_RS_AGG_DISABLE_START 3 +#define IWL_MVM_RS_TPC_SR_FORCE_INCREASE 75 /* percent */ +#define IWL_MVM_RS_TPC_SR_NO_INCREASE 85 /* percent */ +#define IWL_MVM_RS_TPC_TX_POWER_STEP 3 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 744de262373e..14e8fd661889 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -793,7 +793,7 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, struct ieee80211_sta *ap_sta) { int ret; - struct iwl_mvm_sta *mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; + struct iwl_mvm_sta *mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); /* TODO: wowlan_config_cmd->wowlan_ba_teardown_tids */ @@ -1137,12 +1137,43 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, return ret; } +static int iwl_mvm_enter_d0i3_sync(struct iwl_mvm *mvm) +{ + struct iwl_notification_wait wait_d3; + static const u8 d3_notif[] = { D3_CONFIG_CMD }; + int ret; + + iwl_init_notification_wait(&mvm->notif_wait, &wait_d3, + d3_notif, ARRAY_SIZE(d3_notif), + NULL, NULL); + + ret = iwl_mvm_enter_d0i3(mvm->hw->priv); + if (ret) + goto remove_notif; + + ret = iwl_wait_notification(&mvm->notif_wait, &wait_d3, HZ); + WARN_ON_ONCE(ret); + return ret; + +remove_notif: + iwl_remove_notification(&mvm->notif_wait, &wait_d3); + return ret; +} + int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); iwl_trans_suspend(mvm->trans); - if (iwl_mvm_is_d0i3_supported(mvm)) { + if (wowlan->any) { + /* 'any' trigger means d0i3 usage */ + if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) { + int ret = iwl_mvm_enter_d0i3_sync(mvm); + + if (ret) + return ret; + } + mutex_lock(&mvm->d0i3_suspend_mutex); __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); mutex_unlock(&mvm->d0i3_suspend_mutex); @@ -1626,7 +1657,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, if (IS_ERR_OR_NULL(ap_sta)) goto out_free; - mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; + mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); for (i = 0; i < IWL_MAX_TID_COUNT; i++) { u16 seq = status.qos_seq_ctr[i]; /* firmware stores last-used value, we store next value */ @@ -1876,8 +1907,20 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) iwl_trans_resume(mvm->trans); - if (iwl_mvm_is_d0i3_supported(mvm)) + if (mvm->hw->wiphy->wowlan_config->any) { + /* 'any' trigger means d0i3 usage */ + if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) { + int ret = iwl_mvm_exit_d0i3(hw->priv); + + if (ret) + return ret; + /* + * d0i3 exit will be deferred until reconfig_complete. + * make sure there we are out of d0i3. + */ + } return 0; + } return __iwl_mvm_resume(mvm, false); } diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 9aa2311a776c..5fe14591e1c4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -268,7 +268,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id], lockdep_is_held(&mvm->mutex)); if (!IS_ERR_OR_NULL(sta)) { - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); pos += scnprintf(buf+pos, bufsz-pos, "ap_sta_id %d - reduced Tx power %d\n", @@ -517,6 +517,34 @@ static ssize_t iwl_dbgfs_low_latency_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf)); } +static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + char buf[20]; + int len; + + len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif, + char *buf, size_t count, + loff_t *ppos) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + bool ret; + + mutex_lock(&mvm->mutex); + ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid); + mutex_unlock(&mvm->mutex); + + return ret ? count : -EINVAL; +} + #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ @@ -531,6 +559,7 @@ MVM_DEBUGFS_READ_FILE_OPS(mac_params); MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32); MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20); void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -564,6 +593,8 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, + S_IRUSR | S_IWUSR); if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && mvmvif == mvm->bf_allowed_vif) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 33bf915cd7ea..82c09d86af8c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -654,10 +654,10 @@ out: return ret ?: count; } -#define PRINT_STATS_LE32(_str, _val) \ +#define PRINT_STATS_LE32(_struct, _memb) \ pos += scnprintf(buf + pos, bufsz - pos, \ - fmt_table, _str, \ - le32_to_cpu(_val)) + fmt_table, #_memb, \ + le32_to_cpu(_struct->_memb)) static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, char __user *user_buf, size_t count, @@ -692,97 +692,89 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - OFDM"); - PRINT_STATS_LE32("ina_cnt", ofdm->ina_cnt); - PRINT_STATS_LE32("fina_cnt", ofdm->fina_cnt); - PRINT_STATS_LE32("plcp_err", ofdm->plcp_err); - PRINT_STATS_LE32("crc32_err", ofdm->crc32_err); - PRINT_STATS_LE32("overrun_err", ofdm->overrun_err); - PRINT_STATS_LE32("early_overrun_err", ofdm->early_overrun_err); - PRINT_STATS_LE32("crc32_good", ofdm->crc32_good); - PRINT_STATS_LE32("false_alarm_cnt", ofdm->false_alarm_cnt); - PRINT_STATS_LE32("fina_sync_err_cnt", ofdm->fina_sync_err_cnt); - PRINT_STATS_LE32("sfd_timeout", ofdm->sfd_timeout); - PRINT_STATS_LE32("fina_timeout", ofdm->fina_timeout); - PRINT_STATS_LE32("unresponded_rts", ofdm->unresponded_rts); - PRINT_STATS_LE32("rxe_frame_lmt_overrun", - ofdm->rxe_frame_limit_overrun); - PRINT_STATS_LE32("sent_ack_cnt", ofdm->sent_ack_cnt); - PRINT_STATS_LE32("sent_cts_cnt", ofdm->sent_cts_cnt); - PRINT_STATS_LE32("sent_ba_rsp_cnt", ofdm->sent_ba_rsp_cnt); - PRINT_STATS_LE32("dsp_self_kill", ofdm->dsp_self_kill); - PRINT_STATS_LE32("mh_format_err", ofdm->mh_format_err); - PRINT_STATS_LE32("re_acq_main_rssi_sum", ofdm->re_acq_main_rssi_sum); - PRINT_STATS_LE32("reserved", ofdm->reserved); + PRINT_STATS_LE32(ofdm, ina_cnt); + PRINT_STATS_LE32(ofdm, fina_cnt); + PRINT_STATS_LE32(ofdm, plcp_err); + PRINT_STATS_LE32(ofdm, crc32_err); + PRINT_STATS_LE32(ofdm, overrun_err); + PRINT_STATS_LE32(ofdm, early_overrun_err); + PRINT_STATS_LE32(ofdm, crc32_good); + PRINT_STATS_LE32(ofdm, false_alarm_cnt); + PRINT_STATS_LE32(ofdm, fina_sync_err_cnt); + PRINT_STATS_LE32(ofdm, sfd_timeout); + PRINT_STATS_LE32(ofdm, fina_timeout); + PRINT_STATS_LE32(ofdm, unresponded_rts); + PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun); + PRINT_STATS_LE32(ofdm, sent_ack_cnt); + PRINT_STATS_LE32(ofdm, sent_cts_cnt); + PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt); + PRINT_STATS_LE32(ofdm, dsp_self_kill); + PRINT_STATS_LE32(ofdm, mh_format_err); + PRINT_STATS_LE32(ofdm, re_acq_main_rssi_sum); + PRINT_STATS_LE32(ofdm, reserved); pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - CCK"); - PRINT_STATS_LE32("ina_cnt", cck->ina_cnt); - PRINT_STATS_LE32("fina_cnt", cck->fina_cnt); - PRINT_STATS_LE32("plcp_err", cck->plcp_err); - PRINT_STATS_LE32("crc32_err", cck->crc32_err); - PRINT_STATS_LE32("overrun_err", cck->overrun_err); - PRINT_STATS_LE32("early_overrun_err", cck->early_overrun_err); - PRINT_STATS_LE32("crc32_good", cck->crc32_good); - PRINT_STATS_LE32("false_alarm_cnt", cck->false_alarm_cnt); - PRINT_STATS_LE32("fina_sync_err_cnt", cck->fina_sync_err_cnt); - PRINT_STATS_LE32("sfd_timeout", cck->sfd_timeout); - PRINT_STATS_LE32("fina_timeout", cck->fina_timeout); - PRINT_STATS_LE32("unresponded_rts", cck->unresponded_rts); - PRINT_STATS_LE32("rxe_frame_lmt_overrun", - cck->rxe_frame_limit_overrun); - PRINT_STATS_LE32("sent_ack_cnt", cck->sent_ack_cnt); - PRINT_STATS_LE32("sent_cts_cnt", cck->sent_cts_cnt); - PRINT_STATS_LE32("sent_ba_rsp_cnt", cck->sent_ba_rsp_cnt); - PRINT_STATS_LE32("dsp_self_kill", cck->dsp_self_kill); - PRINT_STATS_LE32("mh_format_err", cck->mh_format_err); - PRINT_STATS_LE32("re_acq_main_rssi_sum", cck->re_acq_main_rssi_sum); - PRINT_STATS_LE32("reserved", cck->reserved); + PRINT_STATS_LE32(cck, ina_cnt); + PRINT_STATS_LE32(cck, fina_cnt); + PRINT_STATS_LE32(cck, plcp_err); + PRINT_STATS_LE32(cck, crc32_err); + PRINT_STATS_LE32(cck, overrun_err); + PRINT_STATS_LE32(cck, early_overrun_err); + PRINT_STATS_LE32(cck, crc32_good); + PRINT_STATS_LE32(cck, false_alarm_cnt); + PRINT_STATS_LE32(cck, fina_sync_err_cnt); + PRINT_STATS_LE32(cck, sfd_timeout); + PRINT_STATS_LE32(cck, fina_timeout); + PRINT_STATS_LE32(cck, unresponded_rts); + PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun); + PRINT_STATS_LE32(cck, sent_ack_cnt); + PRINT_STATS_LE32(cck, sent_cts_cnt); + PRINT_STATS_LE32(cck, sent_ba_rsp_cnt); + PRINT_STATS_LE32(cck, dsp_self_kill); + PRINT_STATS_LE32(cck, mh_format_err); + PRINT_STATS_LE32(cck, re_acq_main_rssi_sum); + PRINT_STATS_LE32(cck, reserved); pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - GENERAL"); - PRINT_STATS_LE32("bogus_cts", general->bogus_cts); - PRINT_STATS_LE32("bogus_ack", general->bogus_ack); - PRINT_STATS_LE32("non_bssid_frames", general->non_bssid_frames); - PRINT_STATS_LE32("filtered_frames", general->filtered_frames); - PRINT_STATS_LE32("non_channel_beacons", general->non_channel_beacons); - PRINT_STATS_LE32("channel_beacons", general->channel_beacons); - PRINT_STATS_LE32("num_missed_bcon", general->num_missed_bcon); - PRINT_STATS_LE32("adc_rx_saturation_time", - general->adc_rx_saturation_time); - PRINT_STATS_LE32("ina_detection_search_time", - general->ina_detection_search_time); - PRINT_STATS_LE32("beacon_silence_rssi_a", - general->beacon_silence_rssi_a); - PRINT_STATS_LE32("beacon_silence_rssi_b", - general->beacon_silence_rssi_b); - PRINT_STATS_LE32("beacon_silence_rssi_c", - general->beacon_silence_rssi_c); - PRINT_STATS_LE32("interference_data_flag", - general->interference_data_flag); - PRINT_STATS_LE32("channel_load", general->channel_load); - PRINT_STATS_LE32("dsp_false_alarms", general->dsp_false_alarms); - PRINT_STATS_LE32("beacon_rssi_a", general->beacon_rssi_a); - PRINT_STATS_LE32("beacon_rssi_b", general->beacon_rssi_b); - PRINT_STATS_LE32("beacon_rssi_c", general->beacon_rssi_c); - PRINT_STATS_LE32("beacon_energy_a", general->beacon_energy_a); - PRINT_STATS_LE32("beacon_energy_b", general->beacon_energy_b); - PRINT_STATS_LE32("beacon_energy_c", general->beacon_energy_c); - PRINT_STATS_LE32("num_bt_kills", general->num_bt_kills); - PRINT_STATS_LE32("mac_id", general->mac_id); - PRINT_STATS_LE32("directed_data_mpdu", general->directed_data_mpdu); + PRINT_STATS_LE32(general, bogus_cts); + PRINT_STATS_LE32(general, bogus_ack); + PRINT_STATS_LE32(general, non_bssid_frames); + PRINT_STATS_LE32(general, filtered_frames); + PRINT_STATS_LE32(general, non_channel_beacons); + PRINT_STATS_LE32(general, channel_beacons); + PRINT_STATS_LE32(general, num_missed_bcon); + PRINT_STATS_LE32(general, adc_rx_saturation_time); + PRINT_STATS_LE32(general, ina_detection_search_time); + PRINT_STATS_LE32(general, beacon_silence_rssi_a); + PRINT_STATS_LE32(general, beacon_silence_rssi_b); + PRINT_STATS_LE32(general, beacon_silence_rssi_c); + PRINT_STATS_LE32(general, interference_data_flag); + PRINT_STATS_LE32(general, channel_load); + PRINT_STATS_LE32(general, dsp_false_alarms); + PRINT_STATS_LE32(general, beacon_rssi_a); + PRINT_STATS_LE32(general, beacon_rssi_b); + PRINT_STATS_LE32(general, beacon_rssi_c); + PRINT_STATS_LE32(general, beacon_energy_a); + PRINT_STATS_LE32(general, beacon_energy_b); + PRINT_STATS_LE32(general, beacon_energy_c); + PRINT_STATS_LE32(general, num_bt_kills); + PRINT_STATS_LE32(general, mac_id); + PRINT_STATS_LE32(general, directed_data_mpdu); pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - HT"); - PRINT_STATS_LE32("plcp_err", ht->plcp_err); - PRINT_STATS_LE32("overrun_err", ht->overrun_err); - PRINT_STATS_LE32("early_overrun_err", ht->early_overrun_err); - PRINT_STATS_LE32("crc32_good", ht->crc32_good); - PRINT_STATS_LE32("crc32_err", ht->crc32_err); - PRINT_STATS_LE32("mh_format_err", ht->mh_format_err); - PRINT_STATS_LE32("agg_crc32_good", ht->agg_crc32_good); - PRINT_STATS_LE32("agg_mpdu_cnt", ht->agg_mpdu_cnt); - PRINT_STATS_LE32("agg_cnt", ht->agg_cnt); - PRINT_STATS_LE32("unsupport_mcs", ht->unsupport_mcs); + PRINT_STATS_LE32(ht, plcp_err); + PRINT_STATS_LE32(ht, overrun_err); + PRINT_STATS_LE32(ht, early_overrun_err); + PRINT_STATS_LE32(ht, crc32_good); + PRINT_STATS_LE32(ht, crc32_err); + PRINT_STATS_LE32(ht, mh_format_err); + PRINT_STATS_LE32(ht, agg_crc32_good); + PRINT_STATS_LE32(ht, agg_mpdu_cnt); + PRINT_STATS_LE32(ht, agg_cnt); + PRINT_STATS_LE32(ht, unsupport_mcs); mutex_unlock(&mvm->mutex); @@ -933,7 +925,7 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, return -EINVAL; if (scan_rx_ant > ANT_ABC) return -EINVAL; - if (scan_rx_ant & ~mvm->fw->valid_rx_ant) + if (scan_rx_ant & ~(iwl_mvm_get_valid_rx_ant(mvm))) return -EINVAL; if (mvm->scan_rx_ant != scan_rx_ant) { @@ -945,6 +937,61 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, return count; } +static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + enum iwl_fw_dbg_conf conf; + char buf[8]; + const size_t bufsz = sizeof(buf); + int pos = 0; + + mutex_lock(&mvm->mutex); + conf = mvm->fw_dbg_conf; + mutex_unlock(&mvm->mutex); + + pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) +{ + int ret, conf_id; + + ret = kstrtoint(buf, 0, &conf_id); + if (ret) + return ret; + + if (WARN_ON(conf_id >= FW_DBG_MAX)) + return -EINVAL; + + mutex_lock(&mvm->mutex); + ret = iwl_mvm_start_fw_dbg_conf(mvm, conf_id); + mutex_unlock(&mvm->mutex); + + return ret ?: count; +} + +static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) +{ + int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE); + + if (ret) + return ret; + + iwl_mvm_fw_dbg_collect(mvm); + + iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); + + return count; +} + #define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__) #ifdef CONFIG_IWLWIFI_BCAST_FILTERING static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file, @@ -1340,6 +1387,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, PRINT_MVM_REF(IWL_MVM_REF_TM_CMD); PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK); PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA); + PRINT_MVM_REF(IWL_MVM_REF_FW_DBG_COLLECT); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -1439,6 +1487,26 @@ out: return count; } +static ssize_t iwl_dbgfs_enable_scan_iteration_notif_write(struct iwl_mvm *mvm, + char *buf, + size_t count, + loff_t *ppos) +{ + int val; + + mutex_lock(&mvm->mutex); + + if (kstrtoint(buf, 10, &val)) { + mutex_unlock(&mvm->mutex); + return -EINVAL; + } + + mvm->scan_iter_notif_enabled = val; + mutex_unlock(&mvm->mutex); + + return count; +} + MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); /* Device wide debugfs entries */ @@ -1459,6 +1527,9 @@ MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10); MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8); +MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 8); +MVM_DEBUGFS_WRITE_FILE_OPS(enable_scan_iteration_notif, 8); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); @@ -1500,6 +1571,10 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) S_IWUSR | S_IRUSR); MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR); MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR); + MVM_DEBUGFS_ADD_FILE(enable_scan_iteration_notif, mvm->debugfs_dir, + S_IWUSR); #ifdef CONFIG_IWLWIFI_BCAST_FILTERING if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) { diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index 430020047b77..4fc0938b3fb6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -91,15 +91,33 @@ enum iwl_ltr_config_flags { LTR_CFG_FLAG_DENIE_C10_ON_PD = BIT(6), }; +/** + * struct iwl_ltr_config_cmd_v1 - configures the LTR + * @flags: See %enum iwl_ltr_config_flags + */ +struct iwl_ltr_config_cmd_v1 { + __le32 flags; + __le32 static_long; + __le32 static_short; +} __packed; /* LTR_CAPABLE_API_S_VER_1 */ + +#define LTR_VALID_STATES_NUM 4 + /** * struct iwl_ltr_config_cmd - configures the LTR * @flags: See %enum iwl_ltr_config_flags + * @static_long: + * @static_short: + * @ltr_cfg_values: + * @ltr_short_idle_timeout: */ struct iwl_ltr_config_cmd { __le32 flags; __le32 static_long; __le32 static_short; -} __packed; + __le32 ltr_cfg_values[LTR_VALID_STATES_NUM]; + __le32 ltr_short_idle_timeout; +} __packed; /* LTR_CAPABLE_API_S_VER_2 */ /* Radio LP RX Energy Threshold measured in dBm */ #define POWER_LPRX_RSSI_THRESHOLD 75 diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h index 8bb5b94bf963..0f1ea80a55ef 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h @@ -308,6 +308,42 @@ enum { #define LQ_FLAG_DYNAMIC_BW_POS 6 #define LQ_FLAG_DYNAMIC_BW_MSK (1 << LQ_FLAG_DYNAMIC_BW_POS) +/* Single Stream Tx Parameters (lq_cmd->ss_params) + * Flags to control a smart FW decision about whether BFER/STBC/SISO will be + * used for single stream Tx. + */ + +/* Bit 0-1: Max STBC streams allowed. Can be 0-3. + * (0) - No STBC allowed + * (1) - 2x1 STBC allowed (HT/VHT) + * (2) - 4x2 STBC allowed (HT/VHT) + * (3) - 3x2 STBC allowed (HT only) + * All our chips are at most 2 antennas so only (1) is valid for now. + */ +#define LQ_SS_STBC_ALLOWED_POS 0 +#define LQ_SS_STBC_ALLOWED_MSK (3 << LQ_SS_STBC_ALLOWED_MSK) + +/* 2x1 STBC is allowed */ +#define LQ_SS_STBC_1SS_ALLOWED (1 << LQ_SS_STBC_ALLOWED_POS) + +/* Bit 2: Beamformer (VHT only) is allowed */ +#define LQ_SS_BFER_ALLOWED_POS 2 +#define LQ_SS_BFER_ALLOWED (1 << LQ_SS_BFER_ALLOWED_POS) + +/* Bit 3: Force BFER or STBC for testing + * If this is set: + * If BFER is allowed then force the ucode to choose BFER else + * If STBC is allowed then force the ucode to choose STBC over SISO + */ +#define LQ_SS_FORCE_POS 3 +#define LQ_SS_FORCE (1 << LQ_SS_FORCE_POS) + +/* Bit 31: ss_params field is valid. Used for FW backward compatibility + * with other drivers which don't support the ss_params API yet + */ +#define LQ_SS_PARAMS_VALID_POS 31 +#define LQ_SS_PARAMS_VALID (1 << LQ_SS_PARAMS_VALID_POS) + /** * struct iwl_lq_cmd - link quality command * @sta_id: station to update @@ -330,7 +366,7 @@ enum { * 2 - 0x3f: maximal number of frames (up to 3f == 63) * @rs_table: array of rates for each TX try, each is rate_n_flags, * meaning it is a combination of RATE_MCS_* and IWL_RATE_*_PLCP - * @bf_params: beam forming params, currently not used + * @ss_params: single stream features. declare whether STBC or BFER are allowed. */ struct iwl_lq_cmd { u8 sta_id; @@ -348,6 +384,6 @@ struct iwl_lq_cmd { u8 agg_frame_cnt_limit; __le32 reserved2; __le32 rs_table[LQ_MAX_RETRY_NUM]; - __le32 bf_params; + __le32 ss_params; }; /* LINK_QUALITY_CMD_API_S_VER_1 */ #endif /* __fw_api_rs_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 201846de94e7..cfc0e65b34a5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -653,8 +653,11 @@ enum iwl_scan_channel_flags { }; /* iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S - * @flags: enum iwl_scan_channel_flgs - * @non_ebs_ratio: how many regular scan iteration before EBS + * @flags: enum iwl_scan_channel_flags + * @non_ebs_ratio: defines the ratio of number of scan iterations where EBS is + * involved. + * 1 - EBS is disabled. + * 2 - every second scan will be full scan(and so on). */ struct iwl_scan_channel_opt { __le16 flags; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h new file mode 100644 index 000000000000..928168b18346 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h @@ -0,0 +1,277 @@ +/****************************************************************************** + * + * 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) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * + * 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 COPYING. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * 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 __fw_api_stats_h__ +#define __fw_api_stats_h__ + +struct mvm_statistics_dbg { + __le32 burst_check; + __le32 burst_count; + __le32 wait_for_silence_timeout_cnt; + __le32 reserved[3]; +} __packed; /* STATISTICS_DEBUG_API_S_VER_2 */ + +struct mvm_statistics_div { + __le32 tx_on_a; + __le32 tx_on_b; + __le32 exec_time; + __le32 probe_time; + __le32 rssi_ant; + __le32 reserved2; +} __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */ + +struct mvm_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 */ + __le32 channel_beacons; /* beacons with our bss id and in our + * serving channel */ + __le32 num_missed_bcon; /* number of missed beacons */ + __le32 adc_rx_saturation_time; /* count in 0.8us units the time the + * ADC was in saturation */ + __le32 ina_detection_search_time;/* total time (in 0.8us) searched + * for INA */ + __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */ + __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */ + __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */ + __le32 interference_data_flag; /* flag for interference data + * availability. 1 when data is + * available. */ + __le32 channel_load; /* counts RX Enable time in uSec */ + __le32 dsp_false_alarms; /* DSP false alarm (both OFDM + * and CCK) counter */ + __le32 beacon_rssi_a; + __le32 beacon_rssi_b; + __le32 beacon_rssi_c; + __le32 beacon_energy_a; + __le32 beacon_energy_b; + __le32 beacon_energy_c; + __le32 num_bt_kills; + __le32 mac_id; + __le32 directed_data_mpdu; +} __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_3 */ + +struct mvm_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_lmt_overrun; + __le32 sent_ack_cnt; + __le32 sent_cts_cnt; + __le32 sent_ba_rsp_cnt; + __le32 dsp_self_kill; + __le32 mh_format_err; + __le32 re_acq_main_rssi_sum; + __le32 reserved; +} __packed; /* STATISTICS_RX_PHY_API_S_VER_2 */ + +struct mvm_statistics_rx_ht_phy { + __le32 plcp_err; + __le32 overrun_err; + __le32 early_overrun_err; + __le32 crc32_good; + __le32 crc32_err; + __le32 mh_format_err; + __le32 agg_crc32_good; + __le32 agg_mpdu_cnt; + __le32 agg_cnt; + __le32 unsupport_mcs; +} __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_1 */ + +struct mvm_statistics_tx_non_phy { + __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; + __le32 dump_msdu_cnt; + __le32 burst_abort_next_frame_mismatch_cnt; + __le32 burst_abort_missing_next_frame_cnt; + __le32 cts_timeout_collision; + __le32 ack_or_ba_timeout_collision; +} __packed; /* STATISTICS_TX_NON_PHY_API_S_VER_3 */ + +#define MAX_CHAINS 3 + +struct mvm_statistics_tx_non_phy_agg { + __le32 ba_timeout; + __le32 ba_reschedule_frames; + __le32 scd_query_agg_frame_cnt; + __le32 scd_query_no_agg; + __le32 scd_query_agg; + __le32 scd_query_mismatch; + __le32 frame_not_ready; + __le32 underrun; + __le32 bt_prio_kill; + __le32 rx_ba_rsp_cnt; + __s8 txpower[MAX_CHAINS]; + __s8 reserved; + __le32 reserved2; +} __packed; /* STATISTICS_TX_NON_PHY_AGG_API_S_VER_1 */ + +struct mvm_statistics_tx_channel_width { + __le32 ext_cca_narrow_ch20[1]; + __le32 ext_cca_narrow_ch40[2]; + __le32 ext_cca_narrow_ch80[3]; + __le32 ext_cca_narrow_ch160[4]; + __le32 last_tx_ch_width_indx; + __le32 rx_detected_per_ch_width[4]; + __le32 success_per_ch_width[4]; + __le32 fail_per_ch_width[4]; +}; /* STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */ + +struct mvm_statistics_tx { + struct mvm_statistics_tx_non_phy general; + struct mvm_statistics_tx_non_phy_agg agg; + struct mvm_statistics_tx_channel_width channel_width; +} __packed; /* STATISTICS_TX_API_S_VER_4 */ + + +struct mvm_statistics_bt_activity { + __le32 hi_priority_tx_req_cnt; + __le32 hi_priority_tx_denied_cnt; + __le32 lo_priority_tx_req_cnt; + __le32 lo_priority_tx_denied_cnt; + __le32 hi_priority_rx_req_cnt; + __le32 hi_priority_rx_denied_cnt; + __le32 lo_priority_rx_req_cnt; + __le32 lo_priority_rx_denied_cnt; +} __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */ + +struct mvm_statistics_general { + __le32 radio_temperature; + __le32 radio_voltage; + struct mvm_statistics_dbg dbg; + __le32 sleep_time; + __le32 slots_out; + __le32 slots_idle; + __le32 ttl_timestamp; + struct mvm_statistics_div slow_div; + __le32 rx_enable_counter; + /* + * num_of_sos_states: + * count the number of times we have to re-tune + * in order to get out of bad PHY status + */ + __le32 num_of_sos_states; + __le32 beacon_filtered; + __le32 missed_beacons; + __s8 beacon_filter_average_energy; + __s8 beacon_filter_reason; + __s8 beacon_filter_current_energy; + __s8 beacon_filter_reserved; + __le32 beacon_filter_delta_time; + struct mvm_statistics_bt_activity bt_activity; +} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */ + +struct mvm_statistics_rx { + struct mvm_statistics_rx_phy ofdm; + struct mvm_statistics_rx_phy cck; + struct mvm_statistics_rx_non_phy general; + struct mvm_statistics_rx_ht_phy ofdm_ht; +} __packed; /* STATISTICS_RX_API_S_VER_3 */ + +/* + * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command) + * + * By default, uCode issues this notification after receiving a beacon + * while associated. To disable this behavior, set DISABLE_NOTIF flag in the + * REPLY_STATISTICS_CMD 0x9c, above. + * + * Statistics counters continue to increment beacon after beacon, but are + * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD + * 0x9c with CLEAR_STATS bit set (see above). + * + * uCode also issues this notification during scans. uCode clears statistics + * appropriately so that each notification contains statistics for only the + * one channel that has just been scanned. + */ + +struct iwl_notif_statistics { + __le32 flag; + struct mvm_statistics_rx rx; + struct mvm_statistics_tx tx; + struct mvm_statistics_general general; +} __packed; /* STATISTICS_NTFY_API_S_VER_8 */ + +#endif /* __fw_api_stats_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index 5bca1f8bfebf..81c4ea3c6958 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h @@ -592,4 +592,43 @@ static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm_tx_resp *tx_resp) tx_resp->frame_count) & 0xfff; } +/** + * struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command + * @token: + * @sta_id: station id + * @tid: + * @scd_queue: scheduler queue to confiug + * @enable: 1 queue enable, 0 queue disable + * @aggregate: 1 aggregated queue, 0 otherwise + * @tx_fifo: %enum iwl_mvm_tx_fifo + * @window: BA window size + * @ssn: SSN for the BA agreement + */ +struct iwl_scd_txq_cfg_cmd { + u8 token; + u8 sta_id; + u8 tid; + u8 scd_queue; + u8 enable; + u8 aggregate; + u8 tx_fifo; + u8 window; + __le16 ssn; + __le16 reserved; +} __packed; /* SCD_QUEUE_CFG_CMD_API_S_VER_1 */ + +/** + * struct iwl_scd_txq_cfg_rsp + * @token: taken from the command + * @sta_id: station id from the command + * @tid: tid from the command + * @scd_queue: scd_queue from the command + */ +struct iwl_scd_txq_cfg_rsp { + u8 token; + u8 sta_id; + u8 tid; + u8 scd_queue; +} __packed; /* SCD_QUEUE_CFG_RSP_API_S_VER_1 */ + #endif /* __fw_api_tx_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 88af6dd2ceaa..b56154fe8ec5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -74,6 +74,7 @@ #include "fw-api-d3.h" #include "fw-api-coex.h" #include "fw-api-scan.h" +#include "fw-api-stats.h" /* Tx queue numbers */ enum { @@ -128,6 +129,9 @@ enum { /* global key */ WEP_KEY = 0x20, + /* Memory */ + SHARED_MEM_CFG = 0x25, + /* TDLS */ TDLS_CHANNEL_SWITCH_CMD = 0x27, TDLS_CHANNEL_SWITCH_NOTIFICATION = 0xaa, @@ -1381,214 +1385,6 @@ struct iwl_mvm_marker { __le32 metadata[0]; } __packed; /* MARKER_API_S_VER_1 */ -struct mvm_statistics_dbg { - __le32 burst_check; - __le32 burst_count; - __le32 wait_for_silence_timeout_cnt; - __le32 reserved[3]; -} __packed; /* STATISTICS_DEBUG_API_S_VER_2 */ - -struct mvm_statistics_div { - __le32 tx_on_a; - __le32 tx_on_b; - __le32 exec_time; - __le32 probe_time; - __le32 rssi_ant; - __le32 reserved2; -} __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */ - -struct mvm_statistics_general_common { - __le32 temperature; /* radio temperature */ - __le32 temperature_m; /* radio voltage */ - struct mvm_statistics_dbg dbg; - __le32 sleep_time; - __le32 slots_out; - __le32 slots_idle; - __le32 ttl_timestamp; - struct mvm_statistics_div div; - __le32 rx_enable_counter; - /* - * num_of_sos_states: - * count the number of times we have to re-tune - * in order to get out of bad PHY status - */ - __le32 num_of_sos_states; -} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */ - -struct mvm_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 */ - __le32 channel_beacons; /* beacons with our bss id and in our - * serving channel */ - __le32 num_missed_bcon; /* number of missed beacons */ - __le32 adc_rx_saturation_time; /* count in 0.8us units the time the - * ADC was in saturation */ - __le32 ina_detection_search_time;/* total time (in 0.8us) searched - * for INA */ - __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */ - __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */ - __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */ - __le32 interference_data_flag; /* flag for interference data - * availability. 1 when data is - * available. */ - __le32 channel_load; /* counts RX Enable time in uSec */ - __le32 dsp_false_alarms; /* DSP false alarm (both OFDM - * and CCK) counter */ - __le32 beacon_rssi_a; - __le32 beacon_rssi_b; - __le32 beacon_rssi_c; - __le32 beacon_energy_a; - __le32 beacon_energy_b; - __le32 beacon_energy_c; - __le32 num_bt_kills; - __le32 mac_id; - __le32 directed_data_mpdu; -} __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_3 */ - -struct mvm_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; - __le32 sent_ba_rsp_cnt; - __le32 dsp_self_kill; - __le32 mh_format_err; - __le32 re_acq_main_rssi_sum; - __le32 reserved; -} __packed; /* STATISTICS_RX_PHY_API_S_VER_2 */ - -struct mvm_statistics_rx_ht_phy { - __le32 plcp_err; - __le32 overrun_err; - __le32 early_overrun_err; - __le32 crc32_good; - __le32 crc32_err; - __le32 mh_format_err; - __le32 agg_crc32_good; - __le32 agg_mpdu_cnt; - __le32 agg_cnt; - __le32 unsupport_mcs; -} __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_1 */ - -#define MAX_CHAINS 3 - -struct mvm_statistics_tx_non_phy_agg { - __le32 ba_timeout; - __le32 ba_reschedule_frames; - __le32 scd_query_agg_frame_cnt; - __le32 scd_query_no_agg; - __le32 scd_query_agg; - __le32 scd_query_mismatch; - __le32 frame_not_ready; - __le32 underrun; - __le32 bt_prio_kill; - __le32 rx_ba_rsp_cnt; - __s8 txpower[MAX_CHAINS]; - __s8 reserved; - __le32 reserved2; -} __packed; /* STATISTICS_TX_NON_PHY_AGG_API_S_VER_1 */ - -struct mvm_statistics_tx_channel_width { - __le32 ext_cca_narrow_ch20[1]; - __le32 ext_cca_narrow_ch40[2]; - __le32 ext_cca_narrow_ch80[3]; - __le32 ext_cca_narrow_ch160[4]; - __le32 last_tx_ch_width_indx; - __le32 rx_detected_per_ch_width[4]; - __le32 success_per_ch_width[4]; - __le32 fail_per_ch_width[4]; -}; /* STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */ - -struct mvm_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; - __le32 dump_msdu_cnt; - __le32 burst_abort_next_frame_mismatch_cnt; - __le32 burst_abort_missing_next_frame_cnt; - __le32 cts_timeout_collision; - __le32 ack_or_ba_timeout_collision; - struct mvm_statistics_tx_non_phy_agg agg; - struct mvm_statistics_tx_channel_width channel_width; -} __packed; /* STATISTICS_TX_API_S_VER_4 */ - - -struct mvm_statistics_bt_activity { - __le32 hi_priority_tx_req_cnt; - __le32 hi_priority_tx_denied_cnt; - __le32 lo_priority_tx_req_cnt; - __le32 lo_priority_tx_denied_cnt; - __le32 hi_priority_rx_req_cnt; - __le32 hi_priority_rx_denied_cnt; - __le32 lo_priority_rx_req_cnt; - __le32 lo_priority_rx_denied_cnt; -} __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */ - -struct mvm_statistics_general { - struct mvm_statistics_general_common common; - __le32 beacon_filtered; - __le32 missed_beacons; - __s8 beacon_filter_average_energy; - __s8 beacon_filter_reason; - __s8 beacon_filter_current_energy; - __s8 beacon_filter_reserved; - __le32 beacon_filter_delta_time; - struct mvm_statistics_bt_activity bt_activity; -} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */ - -struct mvm_statistics_rx { - struct mvm_statistics_rx_phy ofdm; - struct mvm_statistics_rx_phy cck; - struct mvm_statistics_rx_non_phy general; - struct mvm_statistics_rx_ht_phy ofdm_ht; -} __packed; /* STATISTICS_RX_API_S_VER_3 */ - -/* - * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command) - * - * By default, uCode issues this notification after receiving a beacon - * while associated. To disable this behavior, set DISABLE_NOTIF flag in the - * REPLY_STATISTICS_CMD 0x9c, above. - * - * Statistics counters continue to increment beacon after beacon, but are - * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD - * 0x9c with CLEAR_STATS bit set (see above). - * - * uCode also issues this notification during scans. uCode clears statistics - * appropriately so that each notification contains statistics for only the - * one channel that has just been scanned. - */ - -struct iwl_notif_statistics { /* STATISTICS_NTFY_API_S_VER_8 */ - __le32 flag; - struct mvm_statistics_rx rx; - struct mvm_statistics_tx tx; - struct mvm_statistics_general general; -} __packed; - /*********************************** * Smart Fifo API ***********************************/ @@ -1680,63 +1476,6 @@ struct iwl_dts_measurement_notif { __le32 voltage; } __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */ -/** - * enum iwl_scd_control - scheduler config command control flags - * @IWL_SCD_CONTROL_RM_TID: remove TID from this queue - * @IWL_SCD_CONTROL_SET_SSN: use the SSN and program it into HW - */ -enum iwl_scd_control { - IWL_SCD_CONTROL_RM_TID = BIT(4), - IWL_SCD_CONTROL_SET_SSN = BIT(5), -}; - -/** - * enum iwl_scd_flags - scheduler config command flags - * @IWL_SCD_FLAGS_SHARE_TID: multiple TIDs map to this queue - * @IWL_SCD_FLAGS_SHARE_RA: multiple RAs map to this queue - * @IWL_SCD_FLAGS_DQA_ENABLED: DQA is enabled - */ -enum iwl_scd_flags { - IWL_SCD_FLAGS_SHARE_TID = BIT(0), - IWL_SCD_FLAGS_SHARE_RA = BIT(1), - IWL_SCD_FLAGS_DQA_ENABLED = BIT(2), -}; - -#define IWL_SCDQ_INVALID_STA 0xff - -/** - * struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command - * @token: dialog token addba - unused legacy - * @sta_id: station id 4-bit - * @tid: TID 0..7 - * @scd_queue: TFD queue num 0 .. 31 - * @enable: 1 queue enable, 0 queue disable - * @aggregate: 1 aggregated queue, 0 otherwise - * @tx_fifo: tx fifo num 0..7 - * @window: up to 64 - * @ssn: starting seq num 12-bit - * @control: command control flags - * @flags: flags - see &enum iwl_scd_flags - * - * Note that every time the command is sent, all parameters must - * be filled with the exception of - * - the SSN, which is only used with @IWL_SCD_CONTROL_SET_SSN - * - the window, which is only relevant when starting aggregation - */ -struct iwl_scd_txq_cfg_cmd { - u8 token; - u8 sta_id; - u8 tid; - u8 scd_queue; - u8 enable; - u8 aggregate; - u8 tx_fifo; - u8 window; - __le16 ssn; - u8 control; - u8 flags; -} __packed; - /*********************************** * TDLS API ***********************************/ @@ -1878,4 +1617,36 @@ struct iwl_tdls_config_res { struct iwl_tdls_config_sta_info_res sta_info[IWL_MVM_TDLS_STA_COUNT]; } __packed; /* TDLS_CONFIG_RSP_API_S_VER_1 */ +#define TX_FIFO_MAX_NUM 8 +#define RX_FIFO_MAX_NUM 2 + +/** + * Shared memory configuration information from the FW + * + * @shared_mem_addr: shared memory addr (pre 8000 HW set to 0x0 as MARBH is not + * accessible) + * @shared_mem_size: shared memory size + * @sample_buff_addr: internal sample (mon/adc) buff addr (pre 8000 HW set to + * 0x0 as accessible only via DBGM RDAT) + * @sample_buff_size: internal sample buff size + * @txfifo_addr: start addr of TXF0 (excluding the context table 0.5KB), (pre + * 8000 HW set to 0x0 as not accessible) + * @txfifo_size: size of TXF0 ... TXF7 + * @rxfifo_size: RXF1, RXF2 sizes. If there is no RXF2, it'll have a value of 0 + * @page_buff_addr: used by UMAC and performance debug (page miss analysis), + * when paging is not supported this should be 0 + * @page_buff_size: size of %page_buff_addr + */ +struct iwl_shared_mem_cfg { + __le32 shared_mem_addr; + __le32 shared_mem_size; + __le32 sample_buff_addr; + __le32 sample_buff_size; + __le32 txfifo_addr; + __le32 txfifo_size[TX_FIFO_MAX_NUM]; + __le32 rxfifo_size[RX_FIFO_MAX_NUM]; + __le32 page_buff_addr; + __le32 page_buff_size; +} __packed; /* SHARED_MEM_ALLOC_API_S_VER_1 */ + #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index d0fa6e9ed590..ca38e9817374 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -70,6 +70,7 @@ #include "iwl-debug.h" #include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */ #include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */ +#include "iwl-prph.h" #include "iwl-eeprom-parse.h" #include "mvm.h" @@ -269,7 +270,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) enum iwl_ucode_type ucode_type = mvm->cur_ucode; /* Set parameters */ - phy_cfg_cmd.phy_cfg = cpu_to_le32(mvm->fw->phy_config); + phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm)); phy_cfg_cmd.calib_control.event_trigger = mvm->fw->default_calib[ucode_type].event_trigger; phy_cfg_cmd.calib_control.flow_trigger = @@ -346,7 +347,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) mvm->calibrating = true; /* Send TX valid antennas before triggering calibrations */ - ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); + ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); if (ret) goto error; @@ -399,8 +400,71 @@ out: return ret; } -static int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, - enum iwl_fw_dbg_conf conf_id) +static void iwl_mvm_get_shared_mem_conf(struct iwl_mvm *mvm) +{ + struct iwl_host_cmd cmd = { + .id = SHARED_MEM_CFG, + .flags = CMD_WANT_SKB, + .data = { NULL, }, + .len = { 0, }, + }; + struct iwl_rx_packet *pkt; + struct iwl_shared_mem_cfg *mem_cfg; + u32 i; + + lockdep_assert_held(&mvm->mutex); + + if (WARN_ON(iwl_mvm_send_cmd(mvm, &cmd))) + return; + + pkt = cmd.resp_pkt; + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERR(mvm, "Bad return from SHARED_MEM_CFG (0x%08X)\n", + pkt->hdr.flags); + goto exit; + } + + mem_cfg = (void *)pkt->data; + + mvm->shared_mem_cfg.shared_mem_addr = + le32_to_cpu(mem_cfg->shared_mem_addr); + mvm->shared_mem_cfg.shared_mem_size = + le32_to_cpu(mem_cfg->shared_mem_size); + mvm->shared_mem_cfg.sample_buff_addr = + le32_to_cpu(mem_cfg->sample_buff_addr); + mvm->shared_mem_cfg.sample_buff_size = + le32_to_cpu(mem_cfg->sample_buff_size); + mvm->shared_mem_cfg.txfifo_addr = le32_to_cpu(mem_cfg->txfifo_addr); + for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size); i++) + mvm->shared_mem_cfg.txfifo_size[i] = + le32_to_cpu(mem_cfg->txfifo_size[i]); + for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.rxfifo_size); i++) + mvm->shared_mem_cfg.rxfifo_size[i] = + le32_to_cpu(mem_cfg->rxfifo_size[i]); + mvm->shared_mem_cfg.page_buff_addr = + le32_to_cpu(mem_cfg->page_buff_addr); + mvm->shared_mem_cfg.page_buff_size = + le32_to_cpu(mem_cfg->page_buff_size); + IWL_DEBUG_INFO(mvm, "SHARED MEM CFG: got memory offsets/sizes\n"); + +exit: + iwl_free_resp(&cmd); +} + +void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm) +{ + /* stop recording */ + if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { + iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); + } else { + iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0); + iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0); + } + + schedule_work(&mvm->fw_error_dump_wk); +} + +int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id) { u8 *ptr; int ret; @@ -435,6 +499,35 @@ static int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, return ret; } +static int iwl_mvm_config_ltr_v1(struct iwl_mvm *mvm) +{ + struct iwl_ltr_config_cmd_v1 cmd_v1 = { + .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE), + }; + + if (!mvm->trans->ltr_enabled) + return 0; + + return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, + sizeof(cmd_v1), &cmd_v1); +} + +static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) +{ + struct iwl_ltr_config_cmd cmd = { + .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE), + }; + + if (!mvm->trans->ltr_enabled) + return 0; + + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_HDC_PHASE_0)) + return iwl_mvm_config_ltr_v1(mvm); + + return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, + sizeof(cmd), &cmd); +} + int iwl_mvm_up(struct iwl_mvm *mvm) { int ret, i; @@ -482,6 +575,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } + if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10) + iwl_mvm_get_shared_mem_conf(mvm); + ret = iwl_mvm_sf_update(mvm, NULL, false); if (ret) IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); @@ -489,7 +585,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) mvm->fw_dbg_conf = FW_DBG_INVALID; iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_CUSTOM); - ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); + ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); if (ret) goto error; @@ -538,14 +634,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) /* Initialize tx backoffs to the minimal possible */ iwl_mvm_tt_tx_backoff(mvm, 0); - if (mvm->trans->ltr_enabled) { - struct iwl_ltr_config_cmd cmd = { - .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE), - }; - - WARN_ON(iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, - sizeof(cmd), &cmd)); - } + WARN_ON(iwl_mvm_config_ltr(mvm)); ret = iwl_mvm_power_update_device(mvm); if (ret) @@ -584,7 +673,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) goto error; } - ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant); + ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); if (ret) goto error; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index f6d86ccce6a8..7bdc6220743f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -208,8 +208,10 @@ u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif) if (vif->type == NL80211_IFTYPE_P2P_DEVICE) return BIT(IWL_MVM_OFFCHANNEL_QUEUE); - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - qmask |= BIT(vif->hw_queue[ac]); + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) + qmask |= BIT(vif->hw_queue[ac]); + } if (vif->type == NL80211_IFTYPE_AP) qmask |= BIT(vif->cab_queue); @@ -460,6 +462,9 @@ exit_fail: int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { + unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? + mvm->cfg->base_params->wd_timeout : + IWL_WATCHDOG_DISABLED; u32 ac; int ret; @@ -472,16 +477,17 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) switch (vif->type) { case NL80211_IFTYPE_P2P_DEVICE: iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, - IWL_MVM_TX_FIFO_VO); + IWL_MVM_TX_FIFO_VO, wdg_timeout); break; case NL80211_IFTYPE_AP: iwl_mvm_enable_ac_txq(mvm, vif->cab_queue, - IWL_MVM_TX_FIFO_MCAST); + IWL_MVM_TX_FIFO_MCAST, wdg_timeout); /* fall through */ default: for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac], - iwl_mvm_ac_to_tx_fifo[ac]); + iwl_mvm_ac_to_tx_fifo[ac], + wdg_timeout); break; } @@ -496,14 +502,14 @@ void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif) switch (vif->type) { case NL80211_IFTYPE_P2P_DEVICE: - iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE); + iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, 0); break; case NL80211_IFTYPE_AP: - iwl_mvm_disable_txq(mvm, vif->cab_queue); + iwl_mvm_disable_txq(mvm, vif->cab_queue, 0); /* fall through */ default: for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - iwl_mvm_disable_txq(mvm, vif->hw_queue[ac]); + iwl_mvm_disable_txq(mvm, vif->hw_queue[ac], 0); } } @@ -975,7 +981,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags); mvm->mgmt_last_antenna_idx = - iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, + iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm), mvm->mgmt_last_antenna_idx); beacon_cmd.tx.rate_n_flags = diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e880f9d4717b..1ff7ec08532d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -85,6 +85,7 @@ #include "testmode.h" #include "iwl-fw-error-dump.h" #include "iwl-prph.h" +#include "iwl-csr.h" static const struct ieee80211_iface_limit iwl_mvm_limits[] = { { @@ -105,7 +106,7 @@ static const struct ieee80211_iface_limit iwl_mvm_limits[] = { static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = { { - .num_different_channels = 1, + .num_different_channels = 2, .max_interfaces = 3, .limits = iwl_mvm_limits, .n_limits = ARRAY_SIZE(iwl_mvm_limits), @@ -326,6 +327,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC | IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED; hw->rate_control_algorithm = "iwl-mvm-rs"; + hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES; + hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; /* * Enable 11w if advertised by firmware and software crypto @@ -336,13 +339,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) !iwlwifi_mod_params.sw_crypto) hw->flags |= IEEE80211_HW_MFP_CAPABLE; - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT && - !iwlwifi_mod_params.uapsd_disable) { - hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; - hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES; - hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; - } - if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN || mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS; @@ -377,6 +373,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->max_remain_on_channel_duration = 10000; hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; + /* we can compensate an offset of up to 3 channels = 15 MHz */ + hw->wiphy->max_adj_channel_rssi_comp = 3 * 5; /* Extract MAC address */ memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN); @@ -403,10 +401,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; - if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels) + if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels) { hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; + if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER) + hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |= + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; + } + hw->wiphy->hw_version = mvm->trans->hw_id; if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) @@ -459,15 +462,17 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) device_can_wakeup(mvm->trans->dev)) { mvm->wowlan.flags = WIPHY_WOWLAN_ANY; hw->wiphy->wowlan = &mvm->wowlan; - } else if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len && + } + + if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len && mvm->trans->ops->d3_suspend && mvm->trans->ops->d3_resume && device_can_wakeup(mvm->trans->dev)) { - mvm->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | - WIPHY_WOWLAN_DISCONNECT | - WIPHY_WOWLAN_EAP_IDENTITY_REQ | - WIPHY_WOWLAN_RFKILL_RELEASE | - WIPHY_WOWLAN_NET_DETECT; + mvm->wowlan.flags |= WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_EAP_IDENTITY_REQ | + WIPHY_WOWLAN_RFKILL_RELEASE | + WIPHY_WOWLAN_NET_DETECT; if (!iwlwifi_mod_params.sw_crypto) mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_GTK_REKEY_FAILURE | @@ -707,9 +712,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, mvmvif->uploaded = false; mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; - /* does this make sense at all? */ - mvmvif->color++; - spin_lock_bh(&mvm->time_event_lock); iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data); spin_unlock_bh(&mvm->time_event_lock); @@ -761,41 +763,215 @@ static void iwl_mvm_free_coredump(const void *data) kfree(fw_error_dump); } +static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, + struct iwl_fw_error_dump_data **dump_data) +{ + struct iwl_fw_error_dump_fifo *fifo_hdr; + u32 *fifo_data; + u32 fifo_len; + unsigned long flags; + int i, j; + + if (!iwl_trans_grab_nic_access(mvm->trans, false, &flags)) + return; + + /* Pull RXF data from all RXFs */ + for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.rxfifo_size); i++) { + /* + * Keep aside the additional offset that might be needed for + * next RXF + */ + u32 offset_diff = RXF_DIFF_FROM_PREV * i; + + fifo_hdr = (void *)(*dump_data)->data; + fifo_data = (void *)fifo_hdr->data; + fifo_len = mvm->shared_mem_cfg.rxfifo_size[i]; + + /* No need to try to read the data if the length is 0 */ + if (fifo_len == 0) + continue; + + /* Add a TLV for the RXF */ + (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); + (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr)); + + fifo_hdr->fifo_num = cpu_to_le32(i); + fifo_hdr->available_bytes = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_RD_D_SPACE + + offset_diff)); + fifo_hdr->wr_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_RD_WR_PTR + + offset_diff)); + fifo_hdr->rd_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_RD_RD_PTR + + offset_diff)); + fifo_hdr->fence_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_RD_FENCE_PTR + + offset_diff)); + fifo_hdr->fence_mode = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + RXF_SET_FENCE_MODE + + offset_diff)); + + /* Lock fence */ + iwl_trans_write_prph(mvm->trans, + RXF_SET_FENCE_MODE + offset_diff, 0x1); + /* Set fence pointer to the same place like WR pointer */ + iwl_trans_write_prph(mvm->trans, + RXF_LD_WR2FENCE + offset_diff, 0x1); + /* Set fence offset */ + iwl_trans_write_prph(mvm->trans, + RXF_LD_FENCE_OFFSET_ADDR + offset_diff, + 0x0); + + /* Read FIFO */ + fifo_len /= sizeof(u32); /* Size in DWORDS */ + for (j = 0; j < fifo_len; j++) + fifo_data[j] = iwl_trans_read_prph(mvm->trans, + RXF_FIFO_RD_FENCE_INC + + offset_diff); + *dump_data = iwl_fw_error_next_data(*dump_data); + } + + /* Pull TXF data from all TXFs */ + for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size); i++) { + /* Mark the number of TXF we're pulling now */ + iwl_trans_write_prph(mvm->trans, TXF_LARC_NUM, i); + + fifo_hdr = (void *)(*dump_data)->data; + fifo_data = (void *)fifo_hdr->data; + fifo_len = mvm->shared_mem_cfg.txfifo_size[i]; + + /* No need to try to read the data if the length is 0 */ + if (fifo_len == 0) + continue; + + /* Add a TLV for the FIFO */ + (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXF); + (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr)); + + fifo_hdr->fifo_num = cpu_to_le32(i); + fifo_hdr->available_bytes = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_FIFO_ITEM_CNT)); + fifo_hdr->wr_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_WR_PTR)); + fifo_hdr->rd_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_RD_PTR)); + fifo_hdr->fence_ptr = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_FENCE_PTR)); + fifo_hdr->fence_mode = + cpu_to_le32(iwl_trans_read_prph(mvm->trans, + TXF_LOCK_FENCE)); + + /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */ + iwl_trans_write_prph(mvm->trans, TXF_READ_MODIFY_ADDR, + TXF_WR_PTR); + + /* Dummy-read to advance the read pointer to the head */ + iwl_trans_read_prph(mvm->trans, TXF_READ_MODIFY_DATA); + + /* Read FIFO */ + fifo_len /= sizeof(u32); /* Size in DWORDS */ + for (j = 0; j < fifo_len; j++) + fifo_data[j] = iwl_trans_read_prph(mvm->trans, + TXF_READ_MODIFY_DATA); + *dump_data = iwl_fw_error_next_data(*dump_data); + } + + iwl_trans_release_nic_access(mvm->trans, &flags); +} + void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) { struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_info *dump_info; + struct iwl_fw_error_dump_mem *dump_mem; struct iwl_mvm_dump_ptrs *fw_error_dump; - const struct fw_img *img; u32 sram_len, sram_ofs; - u32 file_len, rxf_len; - unsigned long flags; - int reg_val; + u32 file_len, fifo_data_len = 0; + u32 smem_len = mvm->cfg->smem_len; + u32 sram2_len = mvm->cfg->dccm2_len; lockdep_assert_held(&mvm->mutex); + /* W/A for 8000 HW family A-step */ + if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 && + CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) { + if (smem_len) + smem_len = 0x38000; + + if (sram2_len) + sram2_len = 0x10000; + } + fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL); if (!fw_error_dump) return; - img = &mvm->fw->img[mvm->cur_ucode]; - sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; - sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; + /* SRAM - include stack CCM if driver knows the values for it */ + if (!mvm->cfg->dccm_offset || !mvm->cfg->dccm_len) { + const struct fw_img *img; - /* reading buffer size */ - reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR); - rxf_len = (reg_val & RXF_SIZE_BYTE_CNT_MSK) >> RXF_SIZE_BYTE_CND_POS; + img = &mvm->fw->img[mvm->cur_ucode]; + sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; + sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; + } else { + sram_ofs = mvm->cfg->dccm_offset; + sram_len = mvm->cfg->dccm_len; + } - /* the register holds the value divided by 128 */ - rxf_len = rxf_len << 7; + /* reading RXF/TXF sizes */ + if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) { + struct iwl_mvm_shared_mem_cfg *mem_cfg = &mvm->shared_mem_cfg; + int i; + + fifo_data_len = 0; + + /* Count RXF size */ + for (i = 0; i < ARRAY_SIZE(mem_cfg->rxfifo_size); i++) { + if (!mem_cfg->rxfifo_size[i]) + continue; + + /* Add header info */ + fifo_data_len += mem_cfg->rxfifo_size[i] + + sizeof(*dump_data) + + sizeof(struct iwl_fw_error_dump_fifo); + } + + for (i = 0; i < ARRAY_SIZE(mem_cfg->txfifo_size); i++) { + if (!mem_cfg->txfifo_size[i]) + continue; + + /* Add header info */ + fifo_data_len += mem_cfg->txfifo_size[i] + + sizeof(*dump_data) + + sizeof(struct iwl_fw_error_dump_fifo); + } + } file_len = sizeof(*dump_file) + - sizeof(*dump_data) * 3 + - sram_len + - rxf_len + + sizeof(*dump_data) * 2 + + sram_len + sizeof(*dump_mem) + + fifo_data_len + sizeof(*dump_info); + /* Make room for the SMEM, if it exists */ + if (smem_len) + file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len; + + /* Make room for the secondary SRAM, if it exists */ + if (sram2_len) + file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len; + dump_file = vzalloc(file_len); if (!dump_file) { kfree(fw_error_dump); @@ -814,6 +990,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ? cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) : cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8); + dump_info->hw_step = cpu_to_le32(CSR_HW_REV_STEP(mvm->trans->hw_rev)); memcpy(dump_info->fw_human_readable, mvm->fw->human_readable, sizeof(dump_info->fw_human_readable)); strncpy(dump_info->dev_human_readable, mvm->cfg->name, @@ -822,28 +999,39 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) sizeof(dump_info->bus_human_readable)); dump_data = iwl_fw_error_next_data(dump_data); - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); - dump_data->len = cpu_to_le32(rxf_len); + /* We only dump the FIFOs if the FW is in error state */ + if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) + iwl_mvm_dump_fifos(mvm, &dump_data); - if (iwl_trans_grab_nic_access(mvm->trans, false, &flags)) { - u32 *rxf = (void *)dump_data->data; - int i; + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); + dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem)); + dump_mem = (void *)dump_data->data; + dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); + dump_mem->offset = cpu_to_le32(sram_ofs); + iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_mem->data, + sram_len); - for (i = 0; i < (rxf_len / sizeof(u32)); i++) { - iwl_trans_write_prph(mvm->trans, - RXF_LD_FENCE_OFFSET_ADDR, - i * sizeof(u32)); - rxf[i] = iwl_trans_read_prph(mvm->trans, - RXF_FIFO_RD_FENCE_ADDR); - } - iwl_trans_release_nic_access(mvm->trans, &flags); + if (smem_len) { + dump_data = iwl_fw_error_next_data(dump_data); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); + dump_data->len = cpu_to_le32(smem_len + sizeof(*dump_mem)); + dump_mem = (void *)dump_data->data; + dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SMEM); + dump_mem->offset = cpu_to_le32(mvm->cfg->smem_offset); + iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->smem_offset, + dump_mem->data, smem_len); } - dump_data = iwl_fw_error_next_data(dump_data); - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM); - dump_data->len = cpu_to_le32(sram_len); - iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, - sram_len); + if (sram2_len) { + dump_data = iwl_fw_error_next_data(dump_data); + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); + dump_data->len = cpu_to_le32(sram2_len + sizeof(*dump_mem)); + dump_mem = (void *)dump_data->data; + dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); + dump_mem->offset = cpu_to_le32(mvm->cfg->dccm2_offset); + iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->dccm2_offset, + dump_mem->data, sram2_len); + } fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans); fw_error_dump->op_mode_len = file_len; @@ -864,6 +1052,11 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status)) iwl_mvm_fw_error_dump(mvm); + /* cleanup all stale references (scan, roc), but keep the + * ucode_down ref until reconfig is complete + */ + iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN); + iwl_trans_stop_device(mvm->trans); mvm->scan_status = IWL_MVM_SCAN_NONE; @@ -893,10 +1086,6 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) ieee80211_wake_queues(mvm->hw); - /* cleanup all stale references (scan, roc), but keep the - * ucode_down ref until reconfig is complete */ - iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN); - /* clear any stale d0i3 state */ clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); @@ -933,6 +1122,19 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw) struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; + /* Some hw restart cleanups must not hold the mutex */ + if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + /* + * Make sure we are out of d0i3. This is needed + * to make sure the reference accounting is correct + * (and there is no stale d0i3_exit_work). + */ + wait_event_timeout(mvm->d0i3_exit_waitq, + !test_bit(IWL_MVM_STATUS_IN_D0I3, + &mvm->status), + HZ); + } + mutex_lock(&mvm->mutex); ret = __iwl_mvm_mac_start(mvm); mutex_unlock(&mvm->mutex); @@ -982,6 +1184,13 @@ static void iwl_mvm_resume_complete(struct iwl_mvm *mvm) IWL_DEBUG_RPM(mvm, "Run deferred d0i3 exit\n"); _iwl_mvm_exit_d0i3(mvm); } + + if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) + if (!wait_event_timeout(mvm->d0i3_exit_waitq, + !test_bit(IWL_MVM_STATUS_IN_D0I3, + &mvm->status), + HZ)) + WARN_ONCE(1, "D0i3 exit on resume timed out\n"); } static void @@ -1146,7 +1355,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, ret = iwl_mvm_power_update_mac(mvm); if (ret) - goto out_release; + goto out_remove_mac; /* beacon filtering */ ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); @@ -2088,7 +2297,7 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); /* * This is called before mac80211 does RCU synchronisation, @@ -2105,6 +2314,20 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } +static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + const u8 *bssid) +{ + if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT)) + return; + + if (iwlwifi_mod_params.uapsd_disable) { + vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD; + return; + } + + vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; +} + static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -2164,6 +2387,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, * Reset EBS status here assuming environment has been changed. */ mvm->last_ebs_successful = true; + iwl_mvm_check_uapsd(mvm, vif, sta->addr); ret = 0; } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) { @@ -3103,7 +3327,7 @@ static int iwl_mvm_set_tim(struct ieee80211_hw *hw, bool set) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); if (!mvm_sta || !mvm_sta->vif) { IWL_ERR(mvm, "Station is not associated to a vif\n"); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d24660fb4ef2..6c69d0584f6c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -119,11 +119,13 @@ extern const struct ieee80211_ops iwl_mvm_hw_ops; * We will register to mac80211 to have testmode working. The NIC must not * be up'ed after the INIT fw asserted. This is useful to be able to use * proprietary tools over testmode to debug the INIT fw. + * @tfd_q_hang_detect: enabled the detection of hung transmit queues * @power_scheme: CAM(Continuous Active Mode)-1, BPS(Balanced Power * Save)-2(default), LP(Low Power)-3 */ struct iwl_mvm_mod_params { bool init_dbg; + bool tfd_q_hang_detect; int power_scheme; }; extern struct iwl_mvm_mod_params iwlmvm_mod_params; @@ -276,6 +278,7 @@ enum iwl_mvm_ref_type { IWL_MVM_REF_TM_CMD, IWL_MVM_REF_EXIT_WORK, IWL_MVM_REF_PROTECT_CSA, + IWL_MVM_REF_FW_DBG_COLLECT, /* update debugfs.c when changing this */ @@ -531,10 +534,23 @@ enum { enum iwl_mvm_tdls_cs_state { IWL_MVM_TDLS_SW_IDLE = 0, IWL_MVM_TDLS_SW_REQ_SENT, + IWL_MVM_TDLS_SW_RESP_RCVD, IWL_MVM_TDLS_SW_REQ_RCVD, IWL_MVM_TDLS_SW_ACTIVE, }; +struct iwl_mvm_shared_mem_cfg { + u32 shared_mem_addr; + u32 shared_mem_size; + u32 sample_buff_addr; + u32 sample_buff_size; + u32 txfifo_addr; + u32 txfifo_size[TX_FIFO_MAX_NUM]; + u32 rxfifo_size[RX_FIFO_MAX_NUM]; + u32 page_buff_addr; + u32 page_buff_size; +}; + struct iwl_mvm { /* for logger access */ struct device *dev; @@ -641,6 +657,8 @@ struct iwl_mvm { bool disable_power_off; bool disable_power_off_d3; + bool scan_iter_notif_enabled; + struct debugfs_blob_wrapper nvm_hw_blob; struct debugfs_blob_wrapper nvm_sw_blob; struct debugfs_blob_wrapper nvm_calib_blob; @@ -782,8 +800,13 @@ struct iwl_mvm { struct cfg80211_chan_def chandef; struct sk_buff *skb; /* ch sw template */ u32 ch_sw_tm_ie; + + /* timestamp of last ch-sw request sent (GP2 time) */ + u32 sent_timestamp; } peer; } tdls_cs; + + struct iwl_mvm_shared_mem_cfg shared_mem_cfg; }; /* Extract MVM priv from op_mode and _hw */ @@ -850,12 +873,14 @@ iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id) static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) { return mvm->trans->cfg->d0i3 && + mvm->trans->d0i3_mode != IWL_D0I3_MODE_OFF && + !iwlwifi_mod_params.d0i3_disable && (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); } -static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm) +static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm) { - return mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_DQA_SUPPORT; + return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG; } extern const u8 iwl_mvm_ac_to_tx_fifo[]; @@ -937,6 +962,33 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic); int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm); +static inline u8 iwl_mvm_get_valid_tx_ant(struct iwl_mvm *mvm) +{ + return mvm->nvm_data && mvm->nvm_data->valid_tx_ant ? + mvm->fw->valid_tx_ant & mvm->nvm_data->valid_tx_ant : + mvm->fw->valid_tx_ant; +} + +static inline u8 iwl_mvm_get_valid_rx_ant(struct iwl_mvm *mvm) +{ + return mvm->nvm_data && mvm->nvm_data->valid_rx_ant ? + mvm->fw->valid_rx_ant & mvm->nvm_data->valid_rx_ant : + mvm->fw->valid_rx_ant; +} + +static inline u32 iwl_mvm_get_phy_config(struct iwl_mvm *mvm) +{ + u32 phy_config = ~(FW_PHY_CFG_TX_CHAIN | + FW_PHY_CFG_RX_CHAIN); + u32 valid_rx_ant = iwl_mvm_get_valid_rx_ant(mvm); + u32 valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm); + + phy_config |= valid_tx_ant << FW_PHY_CFG_TX_CHAIN_POS | + valid_rx_ant << FW_PHY_CFG_RX_CHAIN_POS; + + return mvm->fw->phy_config & phy_config; +} + int iwl_mvm_up(struct iwl_mvm *mvm); int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm); @@ -970,6 +1022,9 @@ int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); +int iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd); /* MVM PHY */ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, @@ -1031,6 +1086,9 @@ int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan); int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); +int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd); int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, @@ -1091,9 +1149,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) /* rate scaling */ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init); -void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, - struct iwl_mvm_frame_stats *stats, - u32 rate, bool agg); +void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg); int rs_pretty_print_rate(char *buf, const u32 rate); void rs_update_last_rssi(struct iwl_mvm *mvm, struct iwl_lq_sta *lq_sta, @@ -1159,6 +1215,8 @@ void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); bool iwl_mvm_ref_taken(struct iwl_mvm *mvm); void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq); +int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode); +int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode); int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); /* BT Coex */ @@ -1260,11 +1318,13 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) /* hw scheduler queue config */ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, - const struct iwl_trans_txq_scd_cfg *cfg); -void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue); + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int wdg_timeout); +void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, u8 flags); -static inline void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, - u8 fifo) +static inline +void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, + u8 fifo, unsigned int wdg_timeout) { struct iwl_trans_txq_scd_cfg cfg = { .fifo = fifo, @@ -1273,12 +1333,13 @@ static inline void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, .frame_limit = IWL_FRAME_LIMIT, }; - iwl_mvm_enable_txq(mvm, queue, 0, &cfg); + iwl_mvm_enable_txq(mvm, queue, 0, &cfg, wdg_timeout); } static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, int tid, - int frame_limit, u16 ssn) + int frame_limit, u16 ssn, + unsigned int wdg_timeout) { struct iwl_trans_txq_scd_cfg cfg = { .fifo = fifo, @@ -1288,7 +1349,7 @@ static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue, .aggregate = true, }; - iwl_mvm_enable_txq(mvm, queue, ssn, &cfg); + iwl_mvm_enable_txq(mvm, queue, ssn, &cfg, wdg_timeout); } /* Assoc status */ @@ -1344,4 +1405,7 @@ struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm); void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); +int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf id); +void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm); + #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index d55fd8e3654c..5383429d96c1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -356,7 +356,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) max_section_size = IWL_MAX_NVM_SECTION_SIZE; else if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE; - else /* Family 8000 B-step */ + else /* Family 8000 B-step or C-step */ max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE; /* @@ -565,6 +565,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) mvm->nvm_data = iwl_parse_nvm_sections(mvm); if (!mvm->nvm_data) return -ENODATA; + IWL_DEBUG_EEPROM(mvm->trans->dev, "nvm version = %x\n", + mvm->nvm_data->nvm_version); return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 97dfba50c682..2dffc3600ed3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -84,15 +84,8 @@ #include "time-event.h" #include "iwl-fw-error-dump.h" -/* - * module name, copyright, version, etc. - */ #define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" - -#define DRV_VERSION IWLWIFI_VERSION - MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); @@ -100,6 +93,7 @@ static const struct iwl_op_mode_ops iwl_mvm_ops; struct iwl_mvm_mod_params iwlmvm_mod_params = { .power_scheme = IWL_POWER_SCHEME_BPS, + .tfd_q_hang_detect = true /* rest of fields are 0 by default */ }; @@ -109,6 +103,10 @@ MODULE_PARM_DESC(init_dbg, module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, S_IRUGO); MODULE_PARM_DESC(power_scheme, "power management scheme: 1-active, 2-balanced, 3-low power, default: 2"); +module_param_named(tfd_q_hang_detect, iwlmvm_mod_params.tfd_q_hang_detect, + bool, S_IRUGO); +MODULE_PARM_DESC(tfd_q_hang_detect, + "TFD queues hang detection (default: true"); /* * module init and exit functions @@ -146,13 +144,14 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; u32 reg_val = 0; + u32 phy_config = iwl_mvm_get_phy_config(mvm); - radio_cfg_type = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_TYPE) >> - FW_PHY_CFG_RADIO_TYPE_POS; - radio_cfg_step = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_STEP) >> - FW_PHY_CFG_RADIO_STEP_POS; - radio_cfg_dash = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_DASH) >> - FW_PHY_CFG_RADIO_DASH_POS; + radio_cfg_type = (phy_config & FW_PHY_CFG_RADIO_TYPE) >> + FW_PHY_CFG_RADIO_TYPE_POS; + radio_cfg_step = (phy_config & FW_PHY_CFG_RADIO_STEP) >> + FW_PHY_CFG_RADIO_STEP_POS; + radio_cfg_dash = (phy_config & FW_PHY_CFG_RADIO_DASH) >> + FW_PHY_CFG_RADIO_DASH_POS; /* SKU control */ reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) << @@ -240,6 +239,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, true), + RX_HANDLER(SCAN_ITERATION_COMPLETE, + iwl_mvm_rx_scan_offload_iter_complete_notif, false), RX_HANDLER(SCAN_OFFLOAD_COMPLETE, iwl_mvm_rx_scan_offload_complete_notif, true), RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results, @@ -274,6 +275,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(MGMT_MCAST_KEY), CMD(TX_CMD), CMD(TXPATH_FLUSH), + CMD(SHARED_MEM_CFG), CMD(MAC_CONTEXT_CMD), CMD(TIME_EVENT_CMD), CMD(TIME_EVENT_NOTIFICATION), @@ -476,17 +478,19 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE) trans_cfg.bc_table_dword = true; - if (!iwlwifi_mod_params.wd_disable) - trans_cfg.queue_watchdog_timeout = cfg->base_params->wd_timeout; - else - trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED; - trans_cfg.command_names = iwl_mvm_cmd_strings; trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD; trans_cfg.scd_set_active = true; + trans_cfg.sdio_adma_addr = fw->sdio_adma_addr; + + /* Set a short watchdog for the command queue */ + trans_cfg.cmd_q_wdg_timeout = + iwlmvm_mod_params.tfd_q_hang_detect ? IWL_DEF_WD_TIMEOUT : + IWL_WATCHDOG_DISABLED; + snprintf(mvm->hw->wiphy->fw_version, sizeof(mvm->hw->wiphy->fw_version), "%s", fw->fw_version); @@ -517,10 +521,15 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, min_backoff = calc_min_backoff(trans, cfg); iwl_mvm_tt_initialize(mvm, min_backoff); /* set the nvm_file_name according to priority */ - if (iwlwifi_mod_params.nvm_file) + if (iwlwifi_mod_params.nvm_file) { mvm->nvm_file_name = iwlwifi_mod_params.nvm_file; - else - mvm->nvm_file_name = mvm->cfg->default_nvm_file; + } else { + if ((trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) && + (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)) + mvm->nvm_file_name = mvm->cfg->default_nvm_file_8000A; + else + mvm->nvm_file_name = mvm->cfg->default_nvm_file; + } if (WARN(cfg->no_power_up_nic_in_init && !mvm->nvm_file_name, "not allowing power-up and not having nvm_file\n")) @@ -559,6 +568,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (!mvm->scan_cmd) goto out_free; + /* Set EBS as successful as long as not stated otherwise by the FW. */ + mvm->last_ebs_successful = true; + err = iwl_mvm_mac_setup_register(mvm); if (err) goto out_free; @@ -817,9 +829,20 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) struct iwl_mvm *mvm = container_of(work, struct iwl_mvm, fw_error_dump_wk); + if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_FW_DBG_COLLECT)) + return; + mutex_lock(&mvm->mutex); iwl_mvm_fw_error_dump(mvm); + + /* start recording again if the firmware is not crashed */ + WARN_ON_ONCE((!test_bit(STATUS_FW_ERROR, &mvm->trans->status)) && + mvm->fw->dbg_dest_tlv && + iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf)); + mutex_unlock(&mvm->mutex); + + iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT); } void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) @@ -855,7 +878,10 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) * If WoWLAN fw asserted, don't restart either, mac80211 * can't recover this since we're already half suspended. */ - if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + if (!mvm->restart_fw && fw_error) { + schedule_work(&mvm->fw_error_dump_wk); + } else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, + &mvm->status)) { struct iwl_mvm_reprobe *reprobe; IWL_ERR(mvm, @@ -879,16 +905,13 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) reprobe->dev = mvm->trans->dev; INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); schedule_work(&reprobe->work); - } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && - (!fw_error || mvm->restart_fw)) { + } else if (mvm->cur_ucode == IWL_UCODE_REGULAR) { /* don't let the transport/FW power down */ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); if (fw_error && mvm->restart_fw > 0) mvm->restart_fw--; ieee80211_restart_hw(mvm->hw); - } else if (fw_error) { - schedule_work(&mvm->fw_error_dump_wk); } } @@ -1031,7 +1054,8 @@ static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm, out: rcu_read_unlock(); } -static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) + +int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE; @@ -1047,6 +1071,7 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) }; struct iwl_d3_manager_config d3_cfg_cmd = { .min_sleep_time = cpu_to_le32(1000), + .wakeup_flags = cpu_to_le32(IWL_WAKEUP_D3_CONFIG_FW_ERROR), }; IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n"); @@ -1146,7 +1171,7 @@ void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq) if (mvm->d0i3_offloading && qos_seq) { /* update qos seq numbers if offloading was enabled */ - mvm_ap_sta = (struct iwl_mvm_sta *)sta->drv_priv; + mvm_ap_sta = iwl_mvm_sta_from_mac80211(sta); for (i = 0; i < IWL_MAX_TID_COUNT; i++) { u16 seq = le16_to_cpu(qos_seq[i]); /* firmware stores last-used one, we store next one */ @@ -1245,7 +1270,7 @@ out: return ret; } -static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) +int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index 1c0d4a45c1a8..5b43616eeb06 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c @@ -170,13 +170,13 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, active_cnt = 2; } - cmd->rxchain_info = cpu_to_le32(mvm->fw->valid_rx_ant << + cmd->rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) << PHY_RX_CHAIN_VALID_POS); cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); cmd->rxchain_info |= cpu_to_le32(active_cnt << PHY_RX_CHAIN_MIMO_CNT_POS); - cmd->txchain_info = cpu_to_le32(mvm->fw->valid_tx_ant); + cmd->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); } /* diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 30ceb67ed7a7..194bd1f939ca 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -39,28 +39,16 @@ #include "sta.h" #include "iwl-op-mode.h" #include "mvm.h" +#include "debugfs.h" #define RS_NAME "iwl-mvm-rs" -#define NUM_TRY_BEFORE_ANT_TOGGLE 1 -#define RS_LEGACY_RETRIES_PER_RATE 1 -#define RS_HT_VHT_RETRIES_PER_RATE 2 -#define RS_HT_VHT_RETRIES_PER_RATE_TW 1 -#define RS_INITIAL_MIMO_NUM_RATES 3 -#define RS_INITIAL_SISO_NUM_RATES 3 -#define RS_INITIAL_LEGACY_NUM_RATES LINK_QUAL_MAX_RETRY_NUM -#define RS_SECONDARY_LEGACY_NUM_RATES LINK_QUAL_MAX_RETRY_NUM -#define RS_SECONDARY_SISO_NUM_RATES 3 -#define RS_SECONDARY_SISO_RETRIES 1 - #define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */ -#define IWL_RATE_MIN_FAILURE_TH 3 /* min failures to calc tpt */ -#define IWL_RATE_MIN_SUCCESS_TH 8 /* min successes to calc tpt */ -/* max allowed rate miss before sync LQ cmd */ -#define IWL_MISSED_RATE_MAX 15 -#define RS_STAY_IN_COLUMN_TIMEOUT (5*HZ) -#define RS_IDLE_TIMEOUT (5*HZ) +/* Calculations of success ratio are done in fixed point where 12800 is 100%. + * Use this macro when dealing with thresholds consts set as a percentage + */ +#define RS_PERCENT(x) (128 * x) static u8 rs_ht_to_legacy[] = { [IWL_RATE_MCS_0_INDEX] = IWL_RATE_6M_INDEX, @@ -173,7 +161,7 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (sta->smps_mode == IEEE80211_SMPS_STATIC) return false; - if (num_of_ant(mvm->fw->valid_tx_ant) < 2) + if (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) < 2) return false; if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) @@ -613,7 +601,8 @@ static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index) * at this rate. window->data contains the bitmask of successful * packets. */ -static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, +static int _rs_collect_tx_data(struct iwl_mvm *mvm, + struct iwl_scale_tbl_info *tbl, int scale_index, int attempts, int successes, struct iwl_rate_scale_data *window) { @@ -668,8 +657,8 @@ static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, fail_count = window->counter - window->success_counter; /* Calculate average throughput, if we have enough history. */ - if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) || - (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH)) + if ((fail_count >= IWL_MVM_RS_RATE_MIN_FAILURE_TH) || + (window->success_counter >= IWL_MVM_RS_RATE_MIN_SUCCESS_TH)) window->average_tpt = (window->success_ratio * tpt + 64) / 128; else window->average_tpt = IWL_INVALID_VALUE; @@ -677,7 +666,8 @@ static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl, return 0; } -static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta, +static int rs_collect_tx_data(struct iwl_mvm *mvm, + struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl, int scale_index, int attempts, int successes, u8 reduced_txp) @@ -698,7 +688,7 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta, /* Select window for current tx bit rate */ window = &(tbl->win[scale_index]); - ret = _rs_collect_tx_data(tbl, scale_index, attempts, successes, + ret = _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes, window); if (ret) return ret; @@ -707,7 +697,7 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta, return -EINVAL; window = &tbl->tpc_win[reduced_txp]; - return _rs_collect_tx_data(tbl, scale_index, attempts, successes, + return _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes, window); } @@ -928,7 +918,6 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask, break; if (rate_mask & (1 << low)) break; - IWL_DEBUG_RATE(mvm, "Skipping masked lower rate: %d\n", low); } high = index; @@ -938,7 +927,6 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask, break; if (rate_mask & (1 << high)) break; - IWL_DEBUG_RATE(mvm, "Skipping masked higher rate: %d\n", high); } return (high << 8) | low; @@ -1004,7 +992,7 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, } if (num_of_ant(rate->ant) > 1) - rate->ant = first_antenna(mvm->fw->valid_tx_ant); + rate->ant = first_antenna(iwl_mvm_get_valid_tx_ant(mvm)); /* Relevant in both switching to SISO or Legacy */ rate->sgi = false; @@ -1125,7 +1113,8 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, } if (time_after(jiffies, - (unsigned long)(lq_sta->last_tx + RS_IDLE_TIMEOUT))) { + (unsigned long)(lq_sta->last_tx + + (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) { int t; IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); @@ -1158,7 +1147,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, * ... driver. */ lq_sta->missed_rate_counter++; - if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) { + if (lq_sta->missed_rate_counter > IWL_MVM_RS_MISSED_RATE_MAX) { lq_sta->missed_rate_counter = 0; IWL_DEBUG_RATE(mvm, "Too many rates mismatch. Send sync LQ. rs_state %d\n", @@ -1213,7 +1202,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ucode_rate = le32_to_cpu(table->rs_table[0]); rs_rate_from_ucode_rate(ucode_rate, info->band, &rate); - rs_collect_tx_data(lq_sta, curr_tbl, rate.index, + rs_collect_tx_data(mvm, lq_sta, curr_tbl, rate.index, info->status.ampdu_len, info->status.ampdu_ack_len, reduced_txp); @@ -1249,7 +1238,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, else continue; - rs_collect_tx_data(lq_sta, tmp_tbl, rate.index, 1, + rs_collect_tx_data(mvm, lq_sta, tmp_tbl, rate.index, 1, i < retries ? 0 : legacy_success, reduced_txp); } @@ -1303,13 +1292,13 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, IWL_DEBUG_RATE(mvm, "Moving to RS_STATE_STAY_IN_COLUMN\n"); lq_sta->rs_state = RS_STATE_STAY_IN_COLUMN; if (is_legacy) { - lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT; - lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; - lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT; + lq_sta->table_count_limit = IWL_MVM_RS_LEGACY_TABLE_COUNT; + lq_sta->max_failure_limit = IWL_MVM_RS_LEGACY_FAILURE_LIMIT; + lq_sta->max_success_limit = IWL_MVM_RS_LEGACY_SUCCESS_LIMIT; } else { - lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT; - lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT; - lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT; + lq_sta->table_count_limit = IWL_MVM_RS_NON_LEGACY_TABLE_COUNT; + lq_sta->max_failure_limit = IWL_MVM_RS_NON_LEGACY_FAILURE_LIMIT; + lq_sta->max_success_limit = IWL_MVM_RS_NON_LEGACY_SUCCESS_LIMIT; } lq_sta->table_count = 0; lq_sta->total_failed = 0; @@ -1318,6 +1307,13 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, lq_sta->visited_columns = 0; } +static inline int rs_get_max_rate_from_mask(unsigned long rate_mask) +{ + if (rate_mask) + return find_last_bit(&rate_mask, BITS_PER_LONG); + return IWL_RATE_INVALID; +} + static int rs_get_max_allowed_rate(struct iwl_lq_sta *lq_sta, const struct rs_tx_column *column) { @@ -1420,7 +1416,7 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, u32 target_tpt; int rate_idx; - if (success_ratio > RS_SR_NO_DECREASE) { + if (success_ratio > IWL_MVM_RS_SR_NO_DECREASE) { target_tpt = 100 * expected_current_tpt; IWL_DEBUG_RATE(mvm, "SR %d high. Find rate exceeding EXPECTED_CURRENT %d\n", @@ -1488,7 +1484,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) flush_interval_passed = time_after(jiffies, (unsigned long)(lq_sta->flush_timer + - RS_STAY_IN_COLUMN_TIMEOUT)); + (IWL_MVM_RS_STAY_IN_COLUMN_TIMEOUT * HZ))); /* * Check if we should allow search for new modulation mode. @@ -1567,7 +1563,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column]; const struct rs_tx_column *next_col; allow_column_func_t allow_func; - u8 valid_ants = mvm->fw->valid_tx_ant; + u8 valid_ants = iwl_mvm_get_valid_tx_ant(mvm); const u16 *expected_tpt_tbl; u16 tpt, max_expected_tpt; @@ -1613,8 +1609,12 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, continue; max_rate = rs_get_max_allowed_rate(lq_sta, next_col); - if (WARN_ON_ONCE(max_rate == IWL_RATE_INVALID)) + if (max_rate == IWL_RATE_INVALID) { + IWL_DEBUG_RATE(mvm, + "Skip column %d: no rate is allowed in this column\n", + next_col_id); continue; + } max_expected_tpt = expected_tpt_tbl[max_rate]; if (tpt >= max_expected_tpt) { @@ -1724,7 +1724,8 @@ static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm, { enum rs_action action = RS_ACTION_STAY; - if ((sr <= RS_SR_FORCE_DECREASE) || (current_tpt == 0)) { + if ((sr <= RS_PERCENT(IWL_MVM_RS_SR_FORCE_DECREASE)) || + (current_tpt == 0)) { IWL_DEBUG_RATE(mvm, "Decrease rate because of low SR\n"); return RS_ACTION_DOWNSCALE; @@ -1783,7 +1784,7 @@ static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm, out: if ((action == RS_ACTION_DOWNSCALE) && (low != IWL_RATE_INVALID)) { - if (sr >= RS_SR_NO_DECREASE) { + if (sr >= RS_PERCENT(IWL_MVM_RS_SR_NO_DECREASE)) { IWL_DEBUG_RATE(mvm, "SR is above NO DECREASE. Avoid downscale\n"); action = RS_ACTION_STAY; @@ -1802,18 +1803,10 @@ out: static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta) { - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - struct ieee80211_vif *vif = mvmsta->vif; - bool sta_ps_disabled = (vif->type == NL80211_IFTYPE_STATION && - !vif->bss_conf.ps); - /* Our chip supports Tx STBC and the peer is an HT/VHT STA which * supports STBC of at least 1*SS */ - if (!lq_sta->stbc) - return false; - - if (!mvm->ps_disabled && !sta_ps_disabled) + if (!lq_sta->stbc_capable) return false; if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) @@ -1825,11 +1818,11 @@ static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index, int *weaker, int *stronger) { - *weaker = index + TPC_TX_POWER_STEP; + *weaker = index + IWL_MVM_RS_TPC_TX_POWER_STEP; if (*weaker > TPC_MAX_REDUCTION) *weaker = TPC_INVALID; - *stronger = index - TPC_TX_POWER_STEP; + *stronger = index - IWL_MVM_RS_TPC_TX_POWER_STEP; if (*stronger < 0) *stronger = TPC_INVALID; } @@ -1885,7 +1878,8 @@ static enum tpc_action rs_get_tpc_action(struct iwl_mvm *mvm, } /* Too many failures, increase txp */ - if (sr <= TPC_SR_FORCE_INCREASE || current_tpt == 0) { + if (sr <= RS_PERCENT(IWL_MVM_RS_TPC_SR_FORCE_INCREASE) || + current_tpt == 0) { IWL_DEBUG_RATE(mvm, "increase txp because of weak SR\n"); return TPC_ACTION_NO_RESTIRCTION; } @@ -1908,7 +1902,8 @@ static enum tpc_action rs_get_tpc_action(struct iwl_mvm *mvm, } /* next, increase if needed */ - if (sr < TPC_SR_NO_INCREASE && strong != TPC_INVALID) { + if (sr < RS_PERCENT(IWL_MVM_RS_TPC_SR_NO_INCREASE) && + strong != TPC_INVALID) { if (weak_tpt == IWL_INVALID_VALUE && strong_tpt != IWL_INVALID_VALUE && current_tpt < strong_tpt) { @@ -1935,7 +1930,7 @@ static bool rs_tpc_perform(struct iwl_mvm *mvm, struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl) { - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); struct ieee80211_vif *vif = mvm_sta->vif; struct ieee80211_chanctx_conf *chanctx_conf; enum ieee80211_band band; @@ -2044,7 +2039,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, u16 high_low; s32 sr; u8 prev_agg = lq_sta->is_agg; - struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv; + struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data; struct rs_rate *rate; @@ -2106,8 +2101,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, * in current association (use new rate found above). */ fail_count = window->counter - window->success_counter; - if ((fail_count < IWL_RATE_MIN_FAILURE_TH) && - (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) { + if ((fail_count < IWL_MVM_RS_RATE_MIN_FAILURE_TH) && + (window->success_counter < IWL_MVM_RS_RATE_MIN_SUCCESS_TH)) { IWL_DEBUG_RATE(mvm, "(%s: %d): Test Window: succ %d total %d\n", rs_pretty_lq_type(rate->type), @@ -2385,7 +2380,7 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, int i, nentries; s8 best_rssi = S8_MIN; u8 best_ant = ANT_NONE; - u8 valid_tx_ant = mvm->fw->valid_tx_ant; + u8 valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm); const struct rs_init_rate_info *initial_rates; for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) { @@ -2530,7 +2525,7 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, gfp_t gfp) { - struct iwl_mvm_sta *sta_priv = (struct iwl_mvm_sta *)sta->drv_priv; + struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta); struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_rate; struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); struct iwl_lq_sta *lq_sta = &sta_priv->lq_sta; @@ -2606,68 +2601,121 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta, } } +static void rs_ht_init(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta, + struct ieee80211_sta_ht_cap *ht_cap) +{ + /* active_siso_rate mask includes 9 MBits (bit 5), + * and CCK (bits 0-3), supp_rates[] does not; + * shift to convert format, force 9 MBits off. + */ + lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1; + lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1; + lq_sta->active_siso_rate &= ~((u16)0x2); + lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; + + lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1; + lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1; + lq_sta->active_mimo2_rate &= ~((u16)0x2); + lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; + + if (mvm->cfg->ht_params->ldpc && + (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) + lq_sta->ldpc = true; + + if (mvm->cfg->ht_params->stbc && + (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && + (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) + lq_sta->stbc_capable = true; + + lq_sta->is_vht = false; +} + +static void rs_vht_init(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta, + struct ieee80211_sta_vht_cap *vht_cap) +{ + rs_vht_set_enabled_rates(sta, vht_cap, lq_sta); + + if (mvm->cfg->ht_params->ldpc && + (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)) + lq_sta->ldpc = true; + + if (mvm->cfg->ht_params->stbc && + (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && + (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)) + lq_sta->stbc_capable = true; + + if ((mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER) && + (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && + (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)) + lq_sta->bfer_capable = true; + + lq_sta->is_vht = true; +} + #ifdef CONFIG_IWLWIFI_DEBUGFS -static void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm, - struct iwl_mvm_frame_stats *stats) +static void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm) { spin_lock_bh(&mvm->drv_stats_lock); - memset(stats, 0, sizeof(*stats)); + memset(&mvm->drv_rx_stats, 0, sizeof(mvm->drv_rx_stats)); spin_unlock_bh(&mvm->drv_stats_lock); } -void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, - struct iwl_mvm_frame_stats *stats, - u32 rate, bool agg) +void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg) { u8 nss = 0, mcs = 0; spin_lock(&mvm->drv_stats_lock); if (agg) - stats->agg_frames++; + mvm->drv_rx_stats.agg_frames++; - stats->success_frames++; + mvm->drv_rx_stats.success_frames++; switch (rate & RATE_MCS_CHAN_WIDTH_MSK) { case RATE_MCS_CHAN_WIDTH_20: - stats->bw_20_frames++; + mvm->drv_rx_stats.bw_20_frames++; break; case RATE_MCS_CHAN_WIDTH_40: - stats->bw_40_frames++; + mvm->drv_rx_stats.bw_40_frames++; break; case RATE_MCS_CHAN_WIDTH_80: - stats->bw_80_frames++; + mvm->drv_rx_stats.bw_80_frames++; break; default: WARN_ONCE(1, "bad BW. rate 0x%x", rate); } if (rate & RATE_MCS_HT_MSK) { - stats->ht_frames++; + mvm->drv_rx_stats.ht_frames++; mcs = rate & RATE_HT_MCS_RATE_CODE_MSK; nss = ((rate & RATE_HT_MCS_NSS_MSK) >> RATE_HT_MCS_NSS_POS) + 1; } else if (rate & RATE_MCS_VHT_MSK) { - stats->vht_frames++; + mvm->drv_rx_stats.vht_frames++; mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK; nss = ((rate & RATE_VHT_MCS_NSS_MSK) >> RATE_VHT_MCS_NSS_POS) + 1; } else { - stats->legacy_frames++; + mvm->drv_rx_stats.legacy_frames++; } if (nss == 1) - stats->siso_frames++; + mvm->drv_rx_stats.siso_frames++; else if (nss == 2) - stats->mimo2_frames++; + mvm->drv_rx_stats.mimo2_frames++; if (rate & RATE_MCS_SGI_MSK) - stats->sgi_frames++; + mvm->drv_rx_stats.sgi_frames++; else - stats->ngi_frames++; + mvm->drv_rx_stats.ngi_frames++; - stats->last_rates[stats->last_frame_idx] = rate; - stats->last_frame_idx = (stats->last_frame_idx + 1) % - ARRAY_SIZE(stats->last_rates); + mvm->drv_rx_stats.last_rates[mvm->drv_rx_stats.last_frame_idx] = rate; + mvm->drv_rx_stats.last_frame_idx = + (mvm->drv_rx_stats.last_frame_idx + 1) % + ARRAY_SIZE(mvm->drv_rx_stats.last_rates); spin_unlock(&mvm->drv_stats_lock); } @@ -2683,14 +2731,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct ieee80211_hw *hw = mvm->hw; struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; - struct iwl_mvm_sta *sta_priv; - struct iwl_lq_sta *lq_sta; + struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta); + struct iwl_lq_sta *lq_sta = &sta_priv->lq_sta; struct ieee80211_supported_band *sband; unsigned long supp; /* must be unsigned long for for_each_set_bit */ - sta_priv = (struct iwl_mvm_sta *)sta->drv_priv; - lq_sta = &sta_priv->lq_sta; - /* clear all non-persistent lq data */ memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers)); @@ -2712,7 +2757,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, * previous packets? Need to have IEEE 802.1X auth succeed immediately * after assoc.. */ - lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; + lq_sta->missed_rate_counter = IWL_MVM_RS_MISSED_RATE_MAX; lq_sta->band = sband->band; /* * active legacy rates as per supported rates bitmap @@ -2723,61 +2768,28 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value); /* TODO: should probably account for rx_highest for both HT/VHT */ - if (!vht_cap || !vht_cap->vht_supported) { - /* active_siso_rate mask includes 9 MBits (bit 5), - * and CCK (bits 0-3), supp_rates[] does not; - * shift to convert format, force 9 MBits off. - */ - lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1; - lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1; - lq_sta->active_siso_rate &= ~((u16)0x2); - lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; + if (!vht_cap || !vht_cap->vht_supported) + rs_ht_init(mvm, sta, lq_sta, ht_cap); + else + rs_vht_init(mvm, sta, lq_sta, vht_cap); - /* Same here */ - lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1; - lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1; - lq_sta->active_mimo2_rate &= ~((u16)0x2); - lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; - - lq_sta->is_vht = false; - if (mvm->cfg->ht_params->ldpc && - (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) - lq_sta->ldpc = true; - - if (mvm->cfg->ht_params->stbc && - (num_of_ant(mvm->fw->valid_tx_ant) > 1) && - (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) - lq_sta->stbc = true; - } else { - rs_vht_set_enabled_rates(sta, vht_cap, lq_sta); - lq_sta->is_vht = true; - - if (mvm->cfg->ht_params->ldpc && - (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)) - lq_sta->ldpc = true; - - if (mvm->cfg->ht_params->stbc && - (num_of_ant(mvm->fw->valid_tx_ant) > 1) && - (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)) - lq_sta->stbc = true; - } - - if (IWL_MVM_RS_DISABLE_MIMO) + if (IWL_MVM_RS_DISABLE_P2P_MIMO && sta_priv->vif->p2p) lq_sta->active_mimo2_rate = 0; - lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate, - BITS_PER_LONG); - lq_sta->max_siso_rate_idx = find_last_bit(&lq_sta->active_siso_rate, - BITS_PER_LONG); - lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate, - BITS_PER_LONG); + lq_sta->max_legacy_rate_idx = + rs_get_max_rate_from_mask(lq_sta->active_legacy_rate); + lq_sta->max_siso_rate_idx = + rs_get_max_rate_from_mask(lq_sta->active_siso_rate); + lq_sta->max_mimo2_rate_idx = + rs_get_max_rate_from_mask(lq_sta->active_mimo2_rate); IWL_DEBUG_RATE(mvm, - "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC%d\n", + "LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC=%d BFER=%d\n", lq_sta->active_legacy_rate, lq_sta->active_siso_rate, lq_sta->active_mimo2_rate, - lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc); + lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc_capable, + lq_sta->bfer_capable); IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", lq_sta->max_legacy_rate_idx, lq_sta->max_siso_rate_idx, @@ -2785,14 +2797,14 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, /* These values will be overridden later */ lq_sta->lq.single_stream_ant_msk = - first_antenna(mvm->fw->valid_tx_ant); + first_antenna(iwl_mvm_get_valid_tx_ant(mvm)); lq_sta->lq.dual_stream_ant_msk = ANT_AB; /* as default allow aggregation for all tids */ lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; lq_sta->is_agg = 0; #ifdef CONFIG_IWLWIFI_DEBUGFS - iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats); + iwl_mvm_reset_frame_stats(mvm); #endif rs_initialize_lq(mvm, sta, lq_sta, band, init); } @@ -2861,12 +2873,13 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm, int index = *rs_table_index; for (i = 0; i < num_rates && index < end; i++) { - ucode_rate = cpu_to_le32(ucode_rate_from_rs_rate(mvm, rate)); - for (j = 0; j < num_retries && index < end; j++, index++) + for (j = 0; j < num_retries && index < end; j++, index++) { + ucode_rate = cpu_to_le32(ucode_rate_from_rs_rate(mvm, + rate)); rs_table[index] = ucode_rate; - - if (toggle_ant) - rs_toggle_antenna(valid_tx_ant, rate); + if (toggle_ant) + rs_toggle_antenna(valid_tx_ant, rate); + } prev_rate_idx = rate->index; bottom_reached = rs_get_lower_rate_in_column(lq_sta, rate); @@ -2874,7 +2887,7 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm, break; } - if (!bottom_reached) + if (!bottom_reached && !is_legacy(rate)) rate->index = prev_rate_idx; *rs_table_index = index; @@ -2913,18 +2926,22 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, memcpy(&rate, initial_rate, sizeof(rate)); - valid_tx_ant = mvm->fw->valid_tx_ant; - rate.stbc = rs_stbc_allow(mvm, sta, lq_sta); + valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm); + + /* TODO: remove old API when min FW API hits 14 */ + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) && + rs_stbc_allow(mvm, sta, lq_sta)) + rate.stbc = true; if (is_siso(&rate)) { - num_rates = RS_INITIAL_SISO_NUM_RATES; - num_retries = RS_HT_VHT_RETRIES_PER_RATE; + num_rates = IWL_MVM_RS_INITIAL_SISO_NUM_RATES; + num_retries = IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE; } else if (is_mimo(&rate)) { - num_rates = RS_INITIAL_MIMO_NUM_RATES; - num_retries = RS_HT_VHT_RETRIES_PER_RATE; + num_rates = IWL_MVM_RS_INITIAL_MIMO_NUM_RATES; + num_retries = IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE; } else { - num_rates = RS_INITIAL_LEGACY_NUM_RATES; - num_retries = RS_LEGACY_RETRIES_PER_RATE; + num_rates = IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES; + num_retries = IWL_MVM_RS_INITIAL_LEGACY_RETRIES; toggle_ant = true; } @@ -2935,12 +2952,12 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, rs_get_lower_rate_down_column(lq_sta, &rate); if (is_siso(&rate)) { - num_rates = RS_SECONDARY_SISO_NUM_RATES; - num_retries = RS_SECONDARY_SISO_RETRIES; + num_rates = IWL_MVM_RS_SECONDARY_SISO_NUM_RATES; + num_retries = IWL_MVM_RS_SECONDARY_SISO_RETRIES; lq_cmd->mimo_delim = index; } else if (is_legacy(&rate)) { - num_rates = RS_SECONDARY_LEGACY_NUM_RATES; - num_retries = RS_LEGACY_RETRIES_PER_RATE; + num_rates = IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES; + num_retries = IWL_MVM_RS_SECONDARY_LEGACY_RETRIES; } else { WARN_ON_ONCE(1); } @@ -2953,8 +2970,8 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, rs_get_lower_rate_down_column(lq_sta, &rate); - num_rates = RS_SECONDARY_LEGACY_NUM_RATES; - num_retries = RS_LEGACY_RETRIES_PER_RATE; + num_rates = IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES; + num_retries = IWL_MVM_RS_SECONDARY_LEGACY_RETRIES; rs_fill_rates_for_column(mvm, lq_sta, &rate, lq_cmd->rs_table, &index, num_rates, num_retries, valid_tx_ant, @@ -2962,6 +2979,142 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, } +struct rs_bfer_active_iter_data { + struct ieee80211_sta *exclude_sta; + struct iwl_mvm_sta *bfer_mvmsta; +}; + +static void rs_bfer_active_iter(void *_data, + struct ieee80211_sta *sta) +{ + struct rs_bfer_active_iter_data *data = _data; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_lq_cmd *lq_cmd = &mvmsta->lq_sta.lq; + u32 ss_params = le32_to_cpu(lq_cmd->ss_params); + + if (sta == data->exclude_sta) + return; + + /* The current sta has BFER allowed */ + if (ss_params & LQ_SS_BFER_ALLOWED) { + WARN_ON_ONCE(data->bfer_mvmsta != NULL); + + data->bfer_mvmsta = mvmsta; + } +} + +static int rs_bfer_priority(struct iwl_mvm_sta *sta) +{ + int prio = -1; + enum nl80211_iftype viftype = ieee80211_vif_type_p2p(sta->vif); + + switch (viftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + prio = 3; + break; + case NL80211_IFTYPE_P2P_CLIENT: + prio = 2; + break; + case NL80211_IFTYPE_STATION: + prio = 1; + break; + default: + WARN_ONCE(true, "viftype %d sta_id %d", viftype, sta->sta_id); + prio = -1; + } + + return prio; +} + +/* Returns >0 if sta1 has a higher BFER priority compared to sta2 */ +static int rs_bfer_priority_cmp(struct iwl_mvm_sta *sta1, + struct iwl_mvm_sta *sta2) +{ + int prio1 = rs_bfer_priority(sta1); + int prio2 = rs_bfer_priority(sta2); + + if (prio1 > prio2) + return 1; + if (prio1 < prio2) + return -1; + return 0; +} + +static void rs_set_lq_ss_params(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta, + const struct rs_rate *initial_rate) +{ + struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct rs_bfer_active_iter_data data = { + .exclude_sta = sta, + .bfer_mvmsta = NULL, + }; + struct iwl_mvm_sta *bfer_mvmsta = NULL; + u32 ss_params = LQ_SS_PARAMS_VALID; + + if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) + goto out; + + /* Check if forcing the decision is configured. + * Note that SISO is forced by not allowing STBC or BFER + */ + if (lq_sta->ss_force == RS_SS_FORCE_STBC) + ss_params |= (LQ_SS_STBC_1SS_ALLOWED | LQ_SS_FORCE); + else if (lq_sta->ss_force == RS_SS_FORCE_BFER) + ss_params |= (LQ_SS_BFER_ALLOWED | LQ_SS_FORCE); + + if (lq_sta->ss_force != RS_SS_FORCE_NONE) { + IWL_DEBUG_RATE(mvm, "Forcing single stream Tx decision %d\n", + lq_sta->ss_force); + goto out; + } + + if (lq_sta->stbc_capable) + ss_params |= LQ_SS_STBC_1SS_ALLOWED; + + if (!lq_sta->bfer_capable) + goto out; + + ieee80211_iterate_stations_atomic(mvm->hw, + rs_bfer_active_iter, + &data); + bfer_mvmsta = data.bfer_mvmsta; + + /* This code is safe as it doesn't run concurrently for different + * stations. This is guaranteed by the fact that calls to + * ieee80211_tx_status wouldn't run concurrently for a single HW. + */ + if (!bfer_mvmsta) { + IWL_DEBUG_RATE(mvm, "No sta with BFER allowed found. Allow\n"); + + ss_params |= LQ_SS_BFER_ALLOWED; + goto out; + } + + IWL_DEBUG_RATE(mvm, "Found existing sta %d with BFER activated\n", + bfer_mvmsta->sta_id); + + /* Disallow BFER on another STA if active and we're a higher priority */ + if (rs_bfer_priority_cmp(mvmsta, bfer_mvmsta) > 0) { + struct iwl_lq_cmd *bfersta_lq_cmd = &bfer_mvmsta->lq_sta.lq; + u32 bfersta_ss_params = le32_to_cpu(bfersta_lq_cmd->ss_params); + + bfersta_ss_params &= ~LQ_SS_BFER_ALLOWED; + bfersta_lq_cmd->ss_params = cpu_to_le32(bfersta_ss_params); + iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd, false); + + ss_params |= LQ_SS_BFER_ALLOWED; + IWL_DEBUG_RATE(mvm, + "Lower priority BFER sta found (%d). Switch BFER\n", + bfer_mvmsta->sta_id); + } +out: + lq_cmd->ss_params = cpu_to_le32(ss_params); +} + static void rs_fill_lq_cmd(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, @@ -2971,9 +3124,9 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta; struct iwl_mvm_vif *mvmvif; - lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; + lq_cmd->agg_disable_start_th = IWL_MVM_RS_AGG_DISABLE_START; lq_cmd->agg_time_limit = - cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); + cpu_to_le16(IWL_MVM_RS_AGG_TIME_LIMIT); #ifdef CONFIG_MAC80211_DEBUGFS if (lq_sta->pers.dbg_fixed_rate) { @@ -2988,6 +3141,9 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, rs_build_rates_table(mvm, sta, lq_sta, initial_rate); + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) + rs_set_lq_ss_params(mvm, sta, lq_sta, initial_rate); + if (num_of_ant(initial_rate->ant) == 1) lq_cmd->single_stream_ant_msk = initial_rate->ant; @@ -3167,9 +3323,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, desc += sprintf(buff+desc, "fixed rate 0x%X\n", lq_sta->pers.dbg_fixed_rate); desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n", - (mvm->fw->valid_tx_ant & ANT_A) ? "ANT_A," : "", - (mvm->fw->valid_tx_ant & ANT_B) ? "ANT_B," : "", - (mvm->fw->valid_tx_ant & ANT_C) ? "ANT_C" : ""); + (iwl_mvm_get_valid_tx_ant(mvm) & ANT_A) ? "ANT_A," : "", + (iwl_mvm_get_valid_tx_ant(mvm) & ANT_B) ? "ANT_B," : "", + (iwl_mvm_get_valid_tx_ant(mvm) & ANT_C) ? "ANT_C" : ""); desc += sprintf(buff+desc, "lq type %s\n", (is_legacy(rate)) ? "legacy" : is_vht(rate) ? "VHT" : "HT"); @@ -3361,9 +3517,73 @@ static const struct file_operations rs_sta_dbgfs_drv_tx_stats_ops = { .llseek = default_llseek, }; +static ssize_t iwl_dbgfs_ss_force_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_lq_sta *lq_sta = file->private_data; + char buf[12]; + int bufsz = sizeof(buf); + int pos = 0; + static const char * const ss_force_name[] = { + [RS_SS_FORCE_NONE] = "none", + [RS_SS_FORCE_STBC] = "stbc", + [RS_SS_FORCE_BFER] = "bfer", + [RS_SS_FORCE_SISO] = "siso", + }; + + pos += scnprintf(buf+pos, bufsz-pos, "%s\n", + ss_force_name[lq_sta->ss_force]); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_ss_force_write(struct iwl_lq_sta *lq_sta, char *buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = lq_sta->pers.drv; + int ret = 0; + + if (!strncmp("none", buf, 4)) { + lq_sta->ss_force = RS_SS_FORCE_NONE; + } else if (!strncmp("siso", buf, 4)) { + lq_sta->ss_force = RS_SS_FORCE_SISO; + } else if (!strncmp("stbc", buf, 4)) { + if (lq_sta->stbc_capable) { + lq_sta->ss_force = RS_SS_FORCE_STBC; + } else { + IWL_ERR(mvm, + "can't force STBC. peer doesn't support\n"); + ret = -EINVAL; + } + } else if (!strncmp("bfer", buf, 4)) { + if (lq_sta->bfer_capable) { + lq_sta->ss_force = RS_SS_FORCE_BFER; + } else { + IWL_ERR(mvm, + "can't force BFER. peer doesn't support\n"); + ret = -EINVAL; + } + } else { + IWL_ERR(mvm, "valid values none|siso|stbc|bfer\n"); + ret = -EINVAL; + } + return ret ?: count; +} + +#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ + _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_lq_sta) +#define MVM_DEBUGFS_ADD_FILE_RS(name, parent, mode) do { \ + if (!debugfs_create_file(#name, mode, parent, lq_sta, \ + &iwl_dbgfs_##name##_ops)) \ + goto err; \ + } while (0) + +MVM_DEBUGFS_READ_WRITE_FILE_OPS(ss_force, 32); + static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) { struct iwl_lq_sta *lq_sta = mvm_sta; + debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, lq_sta, &rs_sta_dbgfs_scale_table_ops); debugfs_create_file("rate_stats_table", S_IRUSR, dir, @@ -3374,6 +3594,11 @@ static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) &lq_sta->tx_agg_tid_en); debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir, &lq_sta->pers.dbg_fixed_txp_reduction); + + MVM_DEBUGFS_ADD_FILE_RS(ss_force, dir, S_IRUSR | S_IWUSR); + return; +err: + IWL_ERR((struct iwl_mvm *)mvm, "Can't create debugfs entity\n"); } static void rs_remove_debugfs(void *mvm, void *mvm_sta) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index defd70a6d9e6..dc4ef3dfafe1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -137,42 +137,10 @@ enum { #define IWL_INVALID_VALUE -1 -#define IWL_MIN_RSSI_VAL -100 -#define IWL_MAX_RSSI_VAL 0 - -/* These values specify how many Tx frame attempts before - * searching for a new modulation mode */ -#define IWL_LEGACY_FAILURE_LIMIT 160 -#define IWL_LEGACY_SUCCESS_LIMIT 480 -#define IWL_LEGACY_TABLE_COUNT 160 - -#define IWL_NONE_LEGACY_FAILURE_LIMIT 400 -#define IWL_NONE_LEGACY_SUCCESS_LIMIT 4500 -#define IWL_NONE_LEGACY_TABLE_COUNT 1500 - -/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */ -#define IWL_RS_GOOD_RATIO 12800 /* 100% */ -#define IWL_RATE_SCALE_SWITCH 10880 /* 85% */ -#define IWL_RATE_HIGH_TH 10880 /* 85% */ -#define IWL_RATE_INCREASE_TH 6400 /* 50% */ -#define RS_SR_FORCE_DECREASE 1920 /* 15% */ -#define RS_SR_NO_DECREASE 10880 /* 85% */ - -#define TPC_SR_FORCE_INCREASE 9600 /* 75% */ -#define TPC_SR_NO_INCREASE 10880 /* 85% */ -#define TPC_TX_POWER_STEP 3 #define TPC_MAX_REDUCTION 15 #define TPC_NO_REDUCTION 0 #define TPC_INVALID 0xff -#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */ -#define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000) -#define LINK_QUAL_AGG_TIME_LIMIT_MIN (100) - -#define LINK_QUAL_AGG_DISABLE_START_DEF (3) -#define LINK_QUAL_AGG_DISABLE_START_MAX (255) -#define LINK_QUAL_AGG_DISABLE_START_MIN (0) - #define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) @@ -181,14 +149,7 @@ enum { /* load per tid defines for A-MPDU activation */ #define IWL_AGG_TPT_THREHOLD 0 -#define IWL_AGG_LOAD_THRESHOLD 10 #define IWL_AGG_ALL_TID 0xff -#define TID_QUEUE_CELL_SPACING 50 /*mS */ -#define TID_QUEUE_MAX_SIZE 20 -#define TID_ROUND_VALUE 5 /* mS */ - -#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING) -#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) enum iwl_table_type { LQ_NONE, @@ -279,6 +240,13 @@ enum rs_column { RS_COLUMN_INVALID, }; +enum rs_ss_force_opt { + RS_SS_FORCE_NONE = 0, + RS_SS_FORCE_STBC, + RS_SS_FORCE_BFER, + RS_SS_FORCE_SISO, +}; + /* Packet stats per rate */ struct rs_rate_stats { u64 success; @@ -332,7 +300,9 @@ struct iwl_lq_sta { u64 last_tx; bool is_vht; bool ldpc; /* LDPC Rx is supported by the STA */ - bool stbc; /* Tx STBC is supported by chip and Rx by STA */ + bool stbc_capable; /* Tx STBC is supported by chip and Rx by STA */ + bool bfer_capable; /* Remote supports beamformee and we BFer */ + enum ieee80211_band band; /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ @@ -361,6 +331,9 @@ struct iwl_lq_sta { /* tx power reduce for this sta */ int tpc_reduce; + /* force STBC/BFER/SISO for testing */ + enum rs_ss_force_opt ss_force; + /* persistent fields - initialized only once - keep last! */ struct lq_sta_pers { #ifdef CONFIG_MAC80211_DEBUGFS diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 94b6e7297a1e..f922131b4eab 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -407,7 +407,7 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, } #ifdef CONFIG_IWLWIFI_DEBUGFS - iwl_mvm_update_frame_stats(mvm, &mvm->drv_rx_stats, rate_n_flags, + iwl_mvm_update_frame_stats(mvm, rate_n_flags, rx_status->flag & RX_FLAG_AMPDU_DETAILS); #endif iwl_mvm_pass_packet_to_mac80211(mvm, skb, hdr, len, ampdu_status, @@ -511,13 +511,17 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_notif_statistics *stats = (void *)&pkt->data; - struct mvm_statistics_general_common *common = &stats->general.common; struct iwl_mvm_stat_data data = { .stats = stats, .mvm = mvm, }; - iwl_mvm_tt_temp_changed(mvm, le32_to_cpu(common->temperature)); + /* Only handle rx statistics temperature changes if async temp + * notifications are not supported + */ + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_ASYNC_DTM)) + iwl_mvm_tt_temp_changed(mvm, + le32_to_cpu(stats->general.radio_temperature)); iwl_mvm_update_rx_statistics(mvm, stats); diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index ec9a8e7bae1d..7e9aa3cb3254 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -72,6 +72,8 @@ #define IWL_PLCP_QUIET_THRESH 1 #define IWL_ACTIVE_QUIET_TIME 10 +#define IWL_DENSE_EBS_SCAN_RATIO 5 +#define IWL_SPARSE_EBS_SCAN_RATIO 1 struct iwl_mvm_scan_params { u32 max_out_time; @@ -97,7 +99,7 @@ static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm) { if (mvm->scan_rx_ant != ANT_NONE) return mvm->scan_rx_ant; - return mvm->fw->valid_rx_ant; + return iwl_mvm_get_valid_rx_ant(mvm); } static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) @@ -128,7 +130,7 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band, u32 tx_ant; mvm->scan_last_antenna_idx = - iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, + iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm), mvm->scan_last_antenna_idx); tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS; @@ -288,11 +290,11 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - bool *global_bound = data; + int *global_cnt = data; if (vif->type != NL80211_IFTYPE_P2P_DEVICE && mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < MAX_PHYS) - *global_bound = true; + *global_cnt += 1; } static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, @@ -300,27 +302,31 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm, int n_ssids, u32 flags, struct iwl_mvm_scan_params *params) { - bool global_bound = false; + int global_cnt = 0; enum ieee80211_band band; u8 frag_passive_dwell = 0; ieee80211_iterate_active_interfaces_atomic(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_scan_condition_iterator, - &global_bound); + &global_cnt); - if (!global_bound) + if (!global_cnt) goto not_bound; params->suspend_time = 30; - params->max_out_time = 170; + params->max_out_time = 120; if (iwl_mvm_low_latency(mvm)) { if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_FRAGMENTED_SCAN) { params->suspend_time = 105; - params->max_out_time = 70; - frag_passive_dwell = 20; + /* + * If there is more than one active interface make + * passive scan more fragmented. + */ + frag_passive_dwell = (global_cnt < 2) ? 40 : 20; + params->max_out_time = frag_passive_dwell; } else { params->suspend_time = 120; params->max_out_time = 120; @@ -537,6 +543,19 @@ int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, return 0; } +int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_scan_complete_notif *notif = (void *)pkt->data; + + IWL_DEBUG_SCAN(mvm, + "Scan offload iteration complete: status=0x%x scanned channels=%d\n", + notif->status, notif->scanned_channels); + return 0; +} + int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd) { @@ -685,7 +704,8 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); } - mvm->last_ebs_successful = !ebs_status; + if (ebs_status) + mvm->last_ebs_successful = false; return 0; } @@ -1105,6 +1125,12 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify) return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN, notify); + if (mvm->scan_status == IWL_MVM_SCAN_NONE) + return 0; + + if (iwl_mvm_is_radio_killed(mvm)) + goto out; + if (mvm->scan_status != IWL_MVM_SCAN_SCHED && (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) || mvm->scan_status != IWL_MVM_SCAN_OS)) { @@ -1141,6 +1167,7 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify) if (mvm->scan_status == IWL_MVM_SCAN_OS) iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); +out: mvm->scan_status = IWL_MVM_SCAN_NONE; if (notify) { @@ -1297,18 +1324,6 @@ iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm, cmd->scan_prio = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH); cmd->iter_num = cpu_to_le32(1); - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT && - mvm->last_ebs_successful) { - cmd->channel_opt[0].flags = - cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS | - IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | - IWL_SCAN_CHANNEL_FLAG_CACHE_ADD); - cmd->channel_opt[1].flags = - cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS | - IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | - IWL_SCAN_CHANNEL_FLAG_CACHE_ADD); - } - if (iwl_mvm_rrm_scan_needed(mvm)) cmd->scan_flags |= cpu_to_le32(IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED); @@ -1383,6 +1398,22 @@ int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm, cmd->schedule[1].iterations = 0; cmd->schedule[1].full_scan_mul = 0; + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SINGLE_SCAN_EBS && + mvm->last_ebs_successful) { + cmd->channel_opt[0].flags = + cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS | + IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | + IWL_SCAN_CHANNEL_FLAG_CACHE_ADD); + cmd->channel_opt[0].non_ebs_ratio = + cpu_to_le16(IWL_DENSE_EBS_SCAN_RATIO); + cmd->channel_opt[1].flags = + cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS | + IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | + IWL_SCAN_CHANNEL_FLAG_CACHE_ADD); + cmd->channel_opt[1].non_ebs_ratio = + cpu_to_le16(IWL_SPARSE_EBS_SCAN_RATIO); + } + for (i = 1; i <= req->req.n_ssids; i++) ssid_bitmap |= BIT(i); @@ -1467,6 +1498,11 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, if (req->n_ssids == 0) flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE; +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (mvm->scan_iter_notif_enabled) + flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE; +#endif + cmd->scan_flags |= cpu_to_le32(flags); cmd->flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band); @@ -1483,6 +1519,22 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, cmd->schedule[1].iterations = 0xff; cmd->schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER; + if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT && + mvm->last_ebs_successful) { + cmd->channel_opt[0].flags = + cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS | + IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | + IWL_SCAN_CHANNEL_FLAG_CACHE_ADD); + cmd->channel_opt[0].non_ebs_ratio = + cpu_to_le16(IWL_DENSE_EBS_SCAN_RATIO); + cmd->channel_opt[1].flags = + cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS | + IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | + IWL_SCAN_CHANNEL_FLAG_CACHE_ADD); + cmd->channel_opt[1].non_ebs_ratio = + cpu_to_le16(IWL_SPARSE_EBS_SCAN_RATIO); + } + iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels, ssid_bitmap, cmd); @@ -1612,7 +1664,7 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) SCAN_CONFIG_FLAG_SET_MAC_ADDR | SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS| SCAN_CONFIG_N_CHANNELS(num_channels)); - scan_config->tx_chains = cpu_to_le32(mvm->fw->valid_tx_ant); + scan_config->tx_chains = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); scan_config->rx_chains = cpu_to_le32(iwl_mvm_scan_rx_ant(mvm)); scan_config->legacy_rates = iwl_mvm_scan_config_rates(mvm); scan_config->out_of_channel_time = cpu_to_le32(170); @@ -1631,10 +1683,10 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) band = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; for (i = 0; i < band->n_channels; i++, j++) - scan_config->channel_array[j] = band->channels[i].center_freq; + scan_config->channel_array[j] = band->channels[i].hw_value; band = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; for (i = 0; i < band->n_channels; i++, j++) - scan_config->channel_array[j] = band->channels[i].center_freq; + scan_config->channel_array[j] = band->channels[i].hw_value; cmd.data[0] = scan_config; cmd.len[0] = cmd_size; @@ -1811,6 +1863,13 @@ int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL; cmd->general_flags = cpu_to_le32(flags); + + if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SINGLE_SCAN_EBS && + mvm->last_ebs_successful) + cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS | + IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | + IWL_SCAN_CHANNEL_FLAG_CACHE_ADD; + cmd->n_channels = req->req.n_channels; for (i = 0; i < req->req.n_ssids; i++) @@ -1974,7 +2033,9 @@ int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, notif->ebs_status == IWL_SCAN_EBS_SUCCESS ? "success" : "failed"); - mvm->last_ebs_successful = !notif->ebs_status; + if (notif->ebs_status) + mvm->last_ebs_successful = false; + mvm->scan_uid[uid_idx] = 0; if (!sched) { @@ -2007,10 +2068,14 @@ static bool iwl_scan_umac_done_check(struct iwl_notif_wait_data *notif_wait, /* * Clear scan uid of scans that was aborted from above and completed - * in FW so the RX handler does nothing. + * in FW so the RX handler does nothing. Set last_ebs_successful here if + * needed. */ scan_done->mvm->scan_uid[uid_idx] = 0; + if (notif->ebs_status) + scan_done->mvm->last_ebs_successful = false; + return !iwl_mvm_find_scan_type(scan_done->mvm, scan_done->type); } diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index d86fe432e51f..5c23cddaaae3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -99,7 +99,7 @@ static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, bool update) { - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_add_sta_cmd add_sta_cmd = { .sta_id = mvm_sta->sta_id, .mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color), @@ -209,6 +209,9 @@ static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm, { unsigned long used_hw_queues; struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? + mvm->cfg->base_params->wd_timeout : + IWL_WATCHDOG_DISABLED; u32 ac; lockdep_assert_held(&mvm->mutex); @@ -232,7 +235,7 @@ static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm, /* Found a place for all queues - enable them */ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { iwl_mvm_enable_ac_txq(mvm, mvmsta->hw_queue[ac], - iwl_mvm_ac_to_tx_fifo[ac]); + iwl_mvm_ac_to_tx_fifo[ac], wdg_timeout); mvmsta->tfd_queue_msk |= BIT(mvmsta->hw_queue[ac]); } @@ -250,8 +253,8 @@ static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm, /* disable the TDLS STA-specific queues */ sta_msk = mvmsta->tfd_queue_msk; - for_each_set_bit(i, &sta_msk, sizeof(sta_msk)) - iwl_mvm_disable_txq(mvm, i); + for_each_set_bit(i, &sta_msk, sizeof(sta_msk) * BITS_PER_BYTE) + iwl_mvm_disable_txq(mvm, i, 0); } int iwl_mvm_add_sta(struct iwl_mvm *mvm, @@ -259,7 +262,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); int i, ret, sta_id; lockdep_assert_held(&mvm->mutex); @@ -464,8 +467,8 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk) if (mvm->tfd_drained[sta_id]) { unsigned long i, msk = mvm->tfd_drained[sta_id]; - for_each_set_bit(i, &msk, sizeof(msk)) - iwl_mvm_disable_txq(mvm, i); + for_each_set_bit(i, &msk, sizeof(msk) * BITS_PER_BYTE) + iwl_mvm_disable_txq(mvm, i, 0); mvm->tfd_drained[sta_id] = 0; IWL_DEBUG_TDLS(mvm, "Drained sta %d, with queues %ld\n", @@ -481,7 +484,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); int ret; lockdep_assert_held(&mvm->mutex); @@ -626,13 +629,16 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) { + unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? + mvm->cfg->base_params->wd_timeout : + IWL_WATCHDOG_DISABLED; int ret; lockdep_assert_held(&mvm->mutex); /* Map Aux queue to fifo - needs to happen before adding Aux station */ iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, - IWL_MVM_TX_FIFO_MCAST); + IWL_MVM_TX_FIFO_MCAST, wdg_timeout); /* Allocate aux station and assign to it the aux queue */ ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue), @@ -774,7 +780,7 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, u16 ssn, bool start) { - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_add_sta_cmd cmd = {}; int ret; u32 status; @@ -834,7 +840,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, u8 queue, bool start) { - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_add_sta_cmd cmd = {}; int ret; u32 status; @@ -965,6 +971,9 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; + unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? + mvm->cfg->base_params->wd_timeout : + IWL_WATCHDOG_DISABLED; int queue, fifo, ret; u16 ssn; @@ -988,7 +997,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return -EIO; iwl_mvm_enable_agg_txq(mvm, queue, fifo, mvmsta->sta_id, tid, - buf_size, ssn); + buf_size, ssn, wdg_timeout); /* * Even though in theory the peer could have different @@ -1058,7 +1067,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); - iwl_mvm_disable_txq(mvm, txq_id); + iwl_mvm_disable_txq(mvm, txq_id, 0); return 0; case IWL_AGG_STARTING: case IWL_EMPTYING_HW_QUEUE_ADDBA: @@ -1116,7 +1125,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); - iwl_mvm_disable_txq(mvm, tid_data->txq_id); + iwl_mvm_disable_txq(mvm, tid_data->txq_id, 0); } mvm->queue_to_mac80211[tid_data->txq_id] = @@ -1144,10 +1153,10 @@ static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm) static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); if (sta) { - struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); return mvm_sta->sta_id; } @@ -1196,6 +1205,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, break; case WLAN_CIPHER_SUITE_WEP104: key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_13BYTES); + /* fall through */ case WLAN_CIPHER_SUITE_WEP40: key_flags |= cpu_to_le16(STA_KEY_FLG_WEP); memcpy(cmd.key + 3, keyconf->key, keyconf->keylen); @@ -1280,7 +1290,7 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); if (sta) return sta->addr; diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c index c0e00bae5bd0..a87b506c8c72 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c @@ -64,6 +64,8 @@ #include #include "mvm.h" #include "time-event.h" +#include "iwl-io.h" +#include "iwl-prph.h" #define TU_TO_US(x) (x * 1024) #define TU_TO_MS(x) (TU_TO_US(x) / 1000) @@ -228,6 +230,8 @@ iwl_mvm_tdls_cs_state_str(enum iwl_mvm_tdls_cs_state state) return "IDLE"; case IWL_MVM_TDLS_SW_REQ_SENT: return "REQ SENT"; + case IWL_MVM_TDLS_SW_RESP_RCVD: + return "RESP RECEIVED"; case IWL_MVM_TDLS_SW_REQ_RCVD: return "REQ RECEIVED"; case IWL_MVM_TDLS_SW_ACTIVE: @@ -248,6 +252,11 @@ static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm, iwl_mvm_tdls_cs_state_str(state)); mvm->tdls_cs.state = state; + /* we only send requests to our switching peer - update sent time */ + if (state == IWL_MVM_TDLS_SW_REQ_SENT) + mvm->tdls_cs.peer.sent_timestamp = + iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG); + if (state == IWL_MVM_TDLS_SW_IDLE) mvm->tdls_cs.cur_sta_id = IWL_MVM_STATION_COUNT; } @@ -300,7 +309,7 @@ out: static int iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, enum iwl_tdls_channel_switch_type type, - const u8 *peer, bool peer_initiator) + const u8 *peer, bool peer_initiator, u32 timestamp) { bool same_peer = false; int ret = 0; @@ -325,17 +334,30 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, ret = -EINVAL; break; case IWL_MVM_TDLS_SW_REQ_SENT: + /* only allow requests from the same peer */ + if (!same_peer) + ret = -EBUSY; + else if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH && + !peer_initiator) + /* + * We received a ch-switch request while an outgoing + * one is pending. Allow it if the peer is the link + * initiator. + */ + ret = -EBUSY; + else if (type == TDLS_SEND_CHAN_SW_REQ) + /* wait for idle before sending another request */ + ret = -EBUSY; + else if (timestamp <= mvm->tdls_cs.peer.sent_timestamp) + /* we got a stale response - ignore it */ + ret = -EINVAL; + break; + case IWL_MVM_TDLS_SW_RESP_RCVD: /* - * We received a ch-switch request while an outgoing one is - * pending. Allow it to proceed if the other peer is the same - * one we sent to, and we are not the link initiator. + * we are waiting for the FW to give an "active" notification, + * so ignore requests in the meantime */ - if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH) { - if (!same_peer) - ret = -EBUSY; - else if (!peer_initiator) /* we are the initiator */ - ret = -EBUSY; - } + ret = -EBUSY; break; case IWL_MVM_TDLS_SW_REQ_RCVD: /* as above, allow the link initiator to proceed */ @@ -349,9 +371,12 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, } break; case IWL_MVM_TDLS_SW_ACTIVE: - /* we don't allow initiations during active channel switch */ - if (type == TDLS_SEND_CHAN_SW_REQ) - ret = -EINVAL; + /* + * the only valid request when active is a request to return + * to the base channel by the current off-channel peer + */ + if (type != TDLS_MOVE_CH || !same_peer) + ret = -EBUSY; break; } @@ -384,7 +409,8 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator); + ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator, + timestamp); if (ret) return ret; @@ -473,6 +499,8 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, type == TDLS_SEND_CHAN_SW_REQ ? IWL_MVM_TDLS_SW_REQ_SENT : IWL_MVM_TDLS_SW_REQ_RCVD); + } else { + iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_RESP_RCVD); } out: @@ -657,12 +685,15 @@ iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); enum iwl_tdls_channel_switch_type type; unsigned int delay; + const char *action_str = + params->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST ? + "REQ" : "RESP"; mutex_lock(&mvm->mutex); IWL_DEBUG_TDLS(mvm, - "Received TDLS ch switch action %d from %pM status %d\n", - params->action_code, params->sta->addr, params->status); + "Received TDLS ch switch action %s from %pM status %d\n", + action_str, params->sta->addr, params->status); /* * we got a non-zero status from a peer we were switching to - move to diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 2b1e61fac34a..ba615ad2176c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -69,6 +69,7 @@ static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) { + struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; u32 duration = mvm->thermal_throttle.params->ct_kill_duration; if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) @@ -77,12 +78,15 @@ static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) IWL_ERR(mvm, "Enter CT Kill\n"); iwl_mvm_set_hw_ctkill_state(mvm, true); + tt->throttle = false; + tt->dynamic_smps = false; + /* Don't schedule an exit work if we're in test mode, since * the temperature will not change unless we manually set it * again (or disable testing). */ if (!mvm->temperature_test) - schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, + schedule_delayed_work(&tt->ct_kill_exit, round_jiffies_relative(duration * HZ)); } @@ -452,6 +456,7 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff) tt->params = &iwl7000_tt_params; tt->throttle = false; + tt->dynamic_smps = false; tt->min_backoff = min_backoff; INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); } diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 4333306ccdee..07304e1fd64a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -90,8 +90,6 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, if (ieee80211_is_probe_resp(fc)) tx_flags |= TX_CMD_FLG_TSF; - else if (ieee80211_is_back_req(fc)) - tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR; if (ieee80211_has_morefrags(fc)) tx_flags |= TX_CMD_FLG_MORE_FRAG; @@ -100,6 +98,15 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, u8 *qc = ieee80211_get_qos_ctl(hdr); tx_cmd->tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL; + } else if (ieee80211_is_back_req(fc)) { + struct ieee80211_bar *bar = (void *)skb->data; + u16 control = le16_to_cpu(bar->control); + + tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR; + tx_cmd->tid_tspec = (control & + IEEE80211_BAR_CTRL_TID_INFO_MASK) >> + IEEE80211_BAR_CTRL_TID_INFO_SHIFT; + WARN_ON_ONCE(tx_cmd->tid_tspec >= IWL_MAX_TID_COUNT); } else { tx_cmd->tid_tspec = IWL_TID_NON_QOS; if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) @@ -213,7 +220,7 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx); mvm->mgmt_last_antenna_idx = - iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, + iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm), mvm->mgmt_last_antenna_idx); if (info->band == IEEE80211_BAND_2GHZ && @@ -500,7 +507,7 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, IWL_DEBUG_TX_QUEUES(mvm, "Can continue DELBA flow ssn = next_recl = %d\n", tid_data->next_reclaimed); - iwl_mvm_disable_txq(mvm, tid_data->txq_id); + iwl_mvm_disable_txq(mvm, tid_data->txq_id, CMD_ASYNC); tid_data->state = IWL_AGG_OFF; /* * we can't hold the mutex - but since we are after a sequence @@ -660,7 +667,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, /* Single frame failure in an AMPDU queue => send BAR */ if (txq_id >= mvm->first_agg_queue && - !(info->flags & IEEE80211_TX_STAT_ACK)) + !(info->flags & IEEE80211_TX_STAT_ACK) && + !(info->flags & IEEE80211_TX_STAT_TX_FILTERED)) info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; /* W/A FW bug: seq_ctl is wrong when the status isn't success */ @@ -923,6 +931,11 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, sta_id = ba_notif->sta_id; tid = ba_notif->tid; + if (WARN_ONCE(sta_id >= IWL_MVM_STATION_COUNT || + tid >= IWL_MAX_TID_COUNT, + "sta_id %d tid %d", sta_id, tid)) + return 0; + rcu_read_lock(); sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 917431e30f74..8decf9953229 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -432,7 +432,7 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) mvm->status, table.valid); } - IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, + IWL_ERR(mvm, "0x%08X | %s\n", table.error_id, desc_lookup(table.error_id)); IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1); IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2); @@ -531,49 +531,50 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) } void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, - const struct iwl_trans_txq_scd_cfg *cfg) + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int wdg_timeout) { - if (iwl_mvm_is_dqa_supported(mvm)) { - struct iwl_scd_txq_cfg_cmd cmd = { - .scd_queue = queue, - .enable = 1, - .window = cfg->frame_limit, - .sta_id = cfg->sta_id, - .ssn = cpu_to_le16(ssn), - .tx_fifo = cfg->fifo, - .aggregate = cfg->aggregate, - .flags = IWL_SCD_FLAGS_DQA_ENABLED, - .tid = cfg->tid, - .control = IWL_SCD_CONTROL_SET_SSN, - }; - int ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, - sizeof(cmd), &cmd); - if (ret) - IWL_ERR(mvm, - "Failed to configure queue %d on FIFO %d\n", - queue, cfg->fifo); + struct iwl_scd_txq_cfg_cmd cmd = { + .scd_queue = queue, + .enable = 1, + .window = cfg->frame_limit, + .sta_id = cfg->sta_id, + .ssn = cpu_to_le16(ssn), + .tx_fifo = cfg->fifo, + .aggregate = cfg->aggregate, + .tid = cfg->tid, + }; + + if (!iwl_mvm_is_scd_cfg_supported(mvm)) { + iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, cfg, + wdg_timeout); + return; } - iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, - iwl_mvm_is_dqa_supported(mvm) ? NULL : cfg); + iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL, wdg_timeout); + WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd), + "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo); } -void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue) +void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, u8 flags) { - iwl_trans_txq_disable(mvm->trans, queue, - !iwl_mvm_is_dqa_supported(mvm)); + struct iwl_scd_txq_cfg_cmd cmd = { + .scd_queue = queue, + .enable = 0, + }; + int ret; - if (iwl_mvm_is_dqa_supported(mvm)) { - struct iwl_scd_txq_cfg_cmd cmd = { - .scd_queue = queue, - .enable = 0, - }; - int ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, CMD_ASYNC, - sizeof(cmd), &cmd); - if (ret) - IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n", - queue, ret); + if (!iwl_mvm_is_scd_cfg_supported(mvm)) { + iwl_trans_txq_disable(mvm->trans, queue, true); + return; } + + iwl_trans_txq_disable(mvm->trans, queue, false); + ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags, + sizeof(cmd), &cmd); + if (ret) + IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n", + queue, ret); } /** @@ -620,7 +621,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, lockdep_assert_held(&mvm->mutex); /* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */ - if (num_of_ant(mvm->fw->valid_rx_ant) == 1) + if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1) return; if (vif->type == NL80211_IFTYPE_AP) @@ -662,7 +663,7 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); - if (num_of_ant(mvm->fw->valid_rx_ant) == 1) + if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1) return false; if (mvm->cfg->rx_with_siso_diversity) diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index d5aadb00dd9e..dbd6bcf52205 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -415,6 +415,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F5, 0x0010, iwl4165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F6, 0x0030, iwl4165_2ac_cfg)}, #endif /* CONFIG_IWLMVM */ {0} diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 1aea6b66c594..cae0eb8835ce 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -216,6 +216,7 @@ struct iwl_pcie_txq_scratch_buf { * @need_update: indicates need to update read/write index * @active: stores if queue is active * @ampdu: true if this queue is an ampdu queue for an specific RA/TID + * @wd_timeout: queue watchdog timeout (jiffies) - per queue * * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame * descriptors) and required locking structures. @@ -232,6 +233,7 @@ struct iwl_txq { bool need_update; u8 active; bool ampdu; + unsigned long wd_timeout; }; static inline dma_addr_t @@ -259,7 +261,6 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) * @scd_set_active: should the transport configure the SCD for HCMD queue * @rx_page_order: page order for receive buffer size - * @wd_timeout: queue watchdog timeout (jiffies) * @reg_lock: protect hw register access * @cmd_in_flight: true when we have a host command in flight * @fw_mon_phys: physical address of the buffer for the firmware monitor @@ -302,6 +303,7 @@ struct iwl_trans_pcie { u8 cmd_queue; u8 cmd_fifo; + unsigned int cmd_q_wdg_timeout; u8 n_no_reclaim_cmds; u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS]; @@ -312,12 +314,14 @@ struct iwl_trans_pcie { const char *const *command_names; - /* queue watchdog */ - unsigned long wd_timeout; - /*protect hw register */ spinlock_t reg_lock; bool cmd_in_flight; + bool ref_cmd_in_flight; + + /* protect ref counter */ + spinlock_t ref_lock; + u32 ref_count; dma_addr_t fw_mon_phys; struct page *fw_mon_page; @@ -368,7 +372,8 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr); int iwl_pcie_tx_stop(struct iwl_trans *trans); void iwl_pcie_tx_free(struct iwl_trans *trans); void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn, - const struct iwl_trans_txq_scd_cfg *cfg); + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int wdg_timeout); void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue, bool configure_scd); int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, @@ -381,6 +386,9 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, struct sk_buff_head *skbs); void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); +void iwl_trans_pcie_ref(struct iwl_trans *trans); +void iwl_trans_pcie_unref(struct iwl_trans *trans); + static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx) { struct iwl_tfd_tb *tb = &tfd->tbs[idx]; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 523fe0c88dcb..69935aa5a1b3 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -75,6 +75,7 @@ #include "iwl-trans.h" #include "iwl-csr.h" #include "iwl-prph.h" +#include "iwl-scd.h" #include "iwl-agn-hw.h" #include "iwl-fw-error-dump.h" #include "internal.h" @@ -443,10 +444,25 @@ static int iwl_pcie_apm_stop_master(struct iwl_trans *trans) return ret; } -static void iwl_pcie_apm_stop(struct iwl_trans *trans) +static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) { IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n"); + if (op_mode_leave) { + if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status)) + iwl_pcie_apm_init(trans); + + /* inform ME that we are leaving */ + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) + iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_WAKE_ME); + else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PREPARE | + CSR_HW_IF_CONFIG_REG_ENABLE_PME); + mdelay(5); + } + clear_bit(STATUS_DEVICE_ENABLED, &trans->status); /* Stop device's DMA activity */ @@ -707,6 +723,11 @@ static int iwl_pcie_load_cpu_sections_8000b(struct iwl_trans *trans, *first_ucode_section = last_read_idx; + if (cpu == 1) + iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFF); + else + iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFFFFFF); + return 0; } @@ -893,8 +914,8 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans, if (ret) return ret; - /* Notify FW loading is done */ - iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFFFFFF); + if (trans->dbg_dest_tlv) + iwl_pcie_apply_destination(trans); /* wait for image verification to complete */ ret = iwl_poll_prph_bit(trans, LMPM_SECURE_BOOT_CPU1_STATUS_ADDR_B0, @@ -916,6 +937,7 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans, static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, const struct fw_img *fw, bool run_in_rfkill) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; bool hw_rfkill; @@ -945,6 +967,9 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, return ret; } + /* init ref_count to 1 (should be cleared when ucode is loaded) */ + trans_pcie->ref_count = 1; + /* make sure rfkill handshake bits are cleared */ iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, @@ -960,7 +985,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, /* Load the given image to the HW */ if ((trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) && - (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_B_STEP)) + (CSR_HW_REV_STEP(trans->hw_rev) != SILICON_A_STEP)) return iwl_pcie_load_given_ucode_8000b(trans, fw); else return iwl_pcie_load_given_ucode(trans, fw); @@ -1010,7 +1035,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); /* Stop the device, and put it in low power state */ - iwl_pcie_apm_stop(trans); + iwl_pcie_apm_stop(trans, false); /* stop and reset the on-board processor */ iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); @@ -1192,7 +1217,7 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) iwl_disable_interrupts(trans); spin_unlock(&trans_pcie->irq_lock); - iwl_pcie_apm_stop(trans); + iwl_pcie_apm_stop(trans, true); spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); @@ -1244,6 +1269,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, trans_pcie->cmd_queue = trans_cfg->cmd_queue; trans_pcie->cmd_fifo = trans_cfg->cmd_fifo; + trans_pcie->cmd_q_wdg_timeout = trans_cfg->cmd_q_wdg_timeout; if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS)) trans_pcie->n_no_reclaim_cmds = 0; else @@ -1258,9 +1284,6 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, else trans_pcie->rx_page_order = get_order(4 * 1024); - trans_pcie->wd_timeout = - msecs_to_jiffies(trans_cfg->queue_watchdog_timeout); - trans_pcie->command_names = trans_cfg->command_names; trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; trans_pcie->scd_set_active = trans_cfg->scd_set_active; @@ -1540,6 +1563,38 @@ static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg, spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); } +void iwl_trans_pcie_ref(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + unsigned long flags; + + if (iwlwifi_mod_params.d0i3_disable) + return; + + spin_lock_irqsave(&trans_pcie->ref_lock, flags); + IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count); + trans_pcie->ref_count++; + spin_unlock_irqrestore(&trans_pcie->ref_lock, flags); +} + +void iwl_trans_pcie_unref(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + unsigned long flags; + + if (iwlwifi_mod_params.d0i3_disable) + return; + + spin_lock_irqsave(&trans_pcie->ref_lock, flags); + IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count); + if (WARN_ON_ONCE(trans_pcie->ref_count == 0)) { + spin_unlock_irqrestore(&trans_pcie->ref_lock, flags); + return; + } + trans_pcie->ref_count--; + spin_unlock_irqrestore(&trans_pcie->ref_lock, flags); +} + static const char *get_csr_string(int cmd) { #define IWL_CMD(x) case x: return #x @@ -2264,6 +2319,9 @@ static const struct iwl_trans_ops trans_ops_pcie = { .release_nic_access = iwl_trans_pcie_release_nic_access, .set_bits_mask = iwl_trans_pcie_set_bits_mask, + .ref = iwl_trans_pcie_ref, + .unref = iwl_trans_pcie_unref, + .dump_data = iwl_trans_pcie_dump_data, }; @@ -2291,6 +2349,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie->trans = trans; spin_lock_init(&trans_pcie->irq_lock); spin_lock_init(&trans_pcie->reg_lock); + spin_lock_init(&trans_pcie->ref_lock); init_waitqueue_head(&trans_pcie->ucode_write_waitq); err = pci_enable_device(pdev); @@ -2404,6 +2463,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, } trans_pcie->inta_mask = CSR_INI_SET_MASK; + trans->d0i3_mode = IWL_D0I3_MODE_ON_SUSPEND; return trans; diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 8a6c7a084aa1..af0bce736358 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -147,7 +147,6 @@ static void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, static void iwl_pcie_txq_stuck_timer(unsigned long data) { struct iwl_txq *txq = (void *)data; - struct iwl_queue *q = &txq->q; struct iwl_trans_pcie *trans_pcie = txq->trans_pcie; struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie); u32 scd_sram_addr = trans_pcie->scd_base_addr + @@ -164,7 +163,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) spin_unlock(&txq->lock); IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id, - jiffies_to_msecs(trans_pcie->wd_timeout)); + jiffies_to_msecs(txq->wd_timeout)); IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", txq->q.read_ptr, txq->q.write_ptr); @@ -198,11 +197,6 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) iwl_read_prph(trans, SCD_QUEUE_WRPTR(i))); } - for (i = q->read_ptr; i != q->write_ptr; - i = iwl_queue_inc_wrap(i)) - IWL_ERR(trans, "scratch %d = 0x%08x\n", i, - le32_to_cpu(txq->scratchbufs[i].scratch)); - iwl_force_nmi(trans); } @@ -680,7 +674,8 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) iwl_write_prph(trans, SCD_CHAINEXT_EN, 0); iwl_trans_ac_txq_enable(trans, trans_pcie->cmd_queue, - trans_pcie->cmd_fifo); + trans_pcie->cmd_fifo, + trans_pcie->cmd_q_wdg_timeout); /* Activate all Tx DMA/FIFO channels */ iwl_scd_activate_fifos(trans); @@ -722,7 +717,12 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, trans_pcie->kw.dma >> 4); - iwl_pcie_tx_start(trans, trans_pcie->scd_base_addr); + /* + * Send 0 as the scd_base_addr since the device may have be reset + * while we were in WoWLAN in which case SCD_SRAM_BASE_ADDR will + * contain garbage. + */ + iwl_pcie_tx_start(trans, 0); } /* @@ -898,6 +898,10 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) } } + if (trans->cfg->base_params->num_of_queues > 20) + iwl_set_bits_prph(trans, SCD_GP_CTRL, + SCD_GP_CTRL_ENABLE_31_QUEUES); + return 0; error: /*Upon error, free only if we allocated something */ @@ -906,10 +910,9 @@ error: return ret; } -static inline void iwl_pcie_txq_progress(struct iwl_trans_pcie *trans_pcie, - struct iwl_txq *txq) +static inline void iwl_pcie_txq_progress(struct iwl_txq *txq) { - if (!trans_pcie->wd_timeout) + if (!txq->wd_timeout) return; /* @@ -919,7 +922,7 @@ static inline void iwl_pcie_txq_progress(struct iwl_trans_pcie *trans_pcie, if (txq->q.read_ptr == txq->q.write_ptr) del_timer(&txq->stuck_timer); else - mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); + mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); } /* Frees buffers until index _not_ inclusive */ @@ -981,21 +984,35 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, iwl_pcie_txq_free_tfd(trans, txq); } - iwl_pcie_txq_progress(trans_pcie, txq); + iwl_pcie_txq_progress(txq); if (iwl_queue_space(&txq->q) > txq->q.low_mark) iwl_wake_queue(trans, txq); + + if (q->read_ptr == q->write_ptr) { + IWL_DEBUG_RPM(trans, "Q %d - last tx reclaimed\n", q->id); + iwl_trans_pcie_unref(trans); + } + out: spin_unlock_bh(&txq->lock); } -static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans) +static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans, + const struct iwl_host_cmd *cmd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; lockdep_assert_held(&trans_pcie->reg_lock); + if (!(cmd->flags & CMD_SEND_IN_IDLE) && + !trans_pcie->ref_cmd_in_flight) { + trans_pcie->ref_cmd_in_flight = true; + IWL_DEBUG_RPM(trans, "set ref_cmd_in_flight - ref\n"); + iwl_trans_pcie_ref(trans); + } + if (trans_pcie->cmd_in_flight) return 0; @@ -1036,6 +1053,12 @@ static int iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans) lockdep_assert_held(&trans_pcie->reg_lock); + if (trans_pcie->ref_cmd_in_flight) { + trans_pcie->ref_cmd_in_flight = false; + IWL_DEBUG_RPM(trans, "clear ref_cmd_in_flight - unref\n"); + iwl_trans_pcie_unref(trans); + } + if (WARN_ON(!trans_pcie->cmd_in_flight)) return 0; @@ -1089,7 +1112,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); } - iwl_pcie_txq_progress(trans_pcie, txq); + iwl_pcie_txq_progress(txq); } static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, @@ -1122,14 +1145,18 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, - const struct iwl_trans_txq_scd_cfg *cfg) + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int wdg_timeout) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_txq *txq = &trans_pcie->txq[txq_id]; int fifo = -1; if (test_and_set_bit(txq_id, trans_pcie->queue_used)) WARN_ONCE(1, "queue %d already used - expect issues", txq_id); + txq->wd_timeout = msecs_to_jiffies(wdg_timeout); + if (cfg) { fifo = cfg->fifo; @@ -1153,7 +1180,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, /* enable aggregations for the queue */ iwl_scd_txq_enable_agg(trans, txq_id); - trans_pcie->txq[txq_id].ampdu = true; + txq->ampdu = true; } else { /* * disable aggregations for the queue, this will also @@ -1162,20 +1189,20 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, */ iwl_scd_txq_disable_agg(trans, txq_id); - ssn = trans_pcie->txq[txq_id].q.read_ptr; + ssn = txq->q.read_ptr; } } /* Place first TFD at index corresponding to start sequence number. * Assumes that ssn_idx is valid (!= 0xFFF) */ - trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff); - trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff); + txq->q.read_ptr = (ssn & 0xff); + txq->q.write_ptr = (ssn & 0xff); + iwl_write_direct32(trans, HBUS_TARG_WRPTR, + (ssn & 0xff) | (txq_id << 8)); if (cfg) { u8 frame_limit = cfg->frame_limit; - iwl_write_direct32(trans, HBUS_TARG_WRPTR, - (ssn & 0xff) | (txq_id << 8)); iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn); /* Set up Tx window size and frame limit for this queue */ @@ -1200,11 +1227,17 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, if (txq_id == trans_pcie->cmd_queue && trans_pcie->scd_set_active) iwl_scd_enable_set_active(trans, BIT(txq_id)); + + IWL_DEBUG_TX_QUEUES(trans, + "Activate queue %d on FIFO %d WrPtr: %d\n", + txq_id, fifo, ssn & 0xff); + } else { + IWL_DEBUG_TX_QUEUES(trans, + "Activate queue %d WrPtr: %d\n", + txq_id, ssn & 0xff); } - trans_pcie->txq[txq_id].active = true; - IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n", - txq_id, fifo, ssn & 0xff); + txq->active = true; } void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, @@ -1469,11 +1502,11 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); /* start timer if queue currently empty */ - if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) - mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); + if (q->read_ptr == q->write_ptr && txq->wd_timeout) + mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); spin_lock_irqsave(&trans_pcie->reg_lock, flags); - ret = iwl_pcie_set_cmd_in_flight(trans); + ret = iwl_pcie_set_cmd_in_flight(trans, cmd); if (ret < 0) { idx = ret; spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); @@ -1819,9 +1852,12 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, wait_write_ptr = ieee80211_has_morefrags(fc); /* start timer if queue currently empty */ - if (txq->need_update && q->read_ptr == q->write_ptr && - trans_pcie->wd_timeout) - mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); + if (q->read_ptr == q->write_ptr) { + if (txq->wd_timeout) + mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); + IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id); + iwl_trans_pcie_ref(trans); + } /* Tell device the write index *just past* this latest filled TFD */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr); diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 34f09ef90bb3..a92985a6ea21 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -1616,10 +1616,10 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, lbs_deb_enter(LBS_DEB_CFG80211); - sinfo->filled |= STATION_INFO_TX_BYTES | - STATION_INFO_TX_PACKETS | - STATION_INFO_RX_BYTES | - STATION_INFO_RX_PACKETS; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES) | + BIT(NL80211_STA_INFO_TX_PACKETS) | + BIT(NL80211_STA_INFO_RX_BYTES) | + BIT(NL80211_STA_INFO_RX_PACKETS); sinfo->tx_bytes = priv->dev->stats.tx_bytes; sinfo->tx_packets = priv->dev->stats.tx_packets; sinfo->rx_bytes = priv->dev->stats.rx_bytes; @@ -1629,14 +1629,14 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, ret = lbs_get_rssi(priv, &signal, &noise); if (ret == 0) { sinfo->signal = signal; - sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); } /* Convert priv->cur_rate from hw_value to NL80211 value */ for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) { if (priv->cur_rate == lbs_rates[i].hw_value) { sinfo->txrate.legacy = lbs_rates[i].bitrate; - sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); break; } } diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index ef58a8862d91..4a4c6586a8d2 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -625,22 +625,22 @@ static int hwsim_fops_ps_write(void *dat, u64 val) old_ps = data->ps; data->ps = val; + local_bh_disable(); if (val == PS_MANUAL_POLL) { - ieee80211_iterate_active_interfaces(data->hw, - IEEE80211_IFACE_ITER_NORMAL, - hwsim_send_ps_poll, data); + ieee80211_iterate_active_interfaces_atomic( + data->hw, IEEE80211_IFACE_ITER_NORMAL, + hwsim_send_ps_poll, data); data->ps_poll_pending = true; } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { - ieee80211_iterate_active_interfaces(data->hw, - IEEE80211_IFACE_ITER_NORMAL, - hwsim_send_nullfunc_ps, - data); + ieee80211_iterate_active_interfaces_atomic( + data->hw, IEEE80211_IFACE_ITER_NORMAL, + hwsim_send_nullfunc_ps, data); } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { - ieee80211_iterate_active_interfaces(data->hw, - IEEE80211_IFACE_ITER_NORMAL, - hwsim_send_nullfunc_no_ps, - data); + ieee80211_iterate_active_interfaces_atomic( + data->hw, IEEE80211_IFACE_ITER_NORMAL, + hwsim_send_nullfunc_no_ps, data); } + local_bh_enable(); return 0; } @@ -2149,14 +2149,14 @@ static int append_radio_msg(struct sk_buff *skb, int id, if (param->regd) { int i; - for (i = 0; hwsim_world_regdom_custom[i] != param->regd && - i < ARRAY_SIZE(hwsim_world_regdom_custom); i++) - ; + for (i = 0; i < ARRAY_SIZE(hwsim_world_regdom_custom); i++) { + if (hwsim_world_regdom_custom[i] != param->regd) + continue; - if (i < ARRAY_SIZE(hwsim_world_regdom_custom)) { ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i); if (ret < 0) return ret; + break; } } @@ -2557,7 +2557,8 @@ static int mac80211_hwsim_get_radio(struct sk_buff *skb, if (res < 0) goto out_err; - return genlmsg_end(skb, hdr); + genlmsg_end(skb, hdr); + return 0; out_err: genlmsg_cancel(skb, hdr); diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c index 2668e83afbb6..3ab87a855122 100644 --- a/drivers/net/wireless/mwifiex/11h.c +++ b/drivers/net/wireless/mwifiex/11h.c @@ -21,6 +21,16 @@ #include "fw.h" +void mwifiex_init_11h_params(struct mwifiex_private *priv) +{ + priv->state_11h.is_11h_enabled = true; + priv->state_11h.is_11h_active = false; +} + +inline int mwifiex_is_11h_active(struct mwifiex_private *priv) +{ + return priv->state_11h.is_11h_active; +} /* This function appends 11h info to a buffer while joining an * infrastructure BSS */ @@ -39,7 +49,7 @@ mwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer, return; radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); - sband = priv->wdev->wiphy->bands[radio_type]; + sband = priv->wdev.wiphy->bands[radio_type]; cap = (struct mwifiex_ie_types_pwr_capability *)*buffer; cap->header.type = cpu_to_le16(WLAN_EID_PWR_CAPABILITY); @@ -69,10 +79,14 @@ mwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer, } /* Enable or disable the 11h extensions in the firmware */ -static int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag) +int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag) { u32 enable = flag; + /* enable master mode radar detection on AP interface */ + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && enable) + enable |= MWIFIEX_MASTER_RADAR_DET_MASK; + return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GEN_SET, DOT11H_I, &enable, true); } @@ -91,11 +105,191 @@ void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer, * bit */ mwifiex_11h_activate(priv, true); + priv->state_11h.is_11h_active = true; bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_SPECTRUM_MGMT; mwifiex_11h_process_infra_join(priv, buffer, bss_desc); } else { /* Deactivate 11h functions in the firmware */ mwifiex_11h_activate(priv, false); + priv->state_11h.is_11h_active = false; bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT; } } + +/* This is DFS CAC work queue function. + * This delayed work emits CAC finished event for cfg80211 if + * CAC was started earlier. + */ +void mwifiex_dfs_cac_work_queue(struct work_struct *work) +{ + struct cfg80211_chan_def chandef; + struct delayed_work *delayed_work = + container_of(work, struct delayed_work, work); + struct mwifiex_private *priv = + container_of(delayed_work, struct mwifiex_private, + dfs_cac_work); + + if (WARN_ON(!priv)) + return; + + chandef = priv->dfs_chandef; + if (priv->wdev.cac_started) { + dev_dbg(priv->adapter->dev, + "CAC timer finished; No radar detected\n"); + cfg80211_cac_event(priv->netdev, &chandef, + NL80211_RADAR_CAC_FINISHED, + GFP_KERNEL); + } +} + +/* This function prepares channel report request command to FW for + * starting radar detection. + */ +int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_chan_rpt_req *cr_req = &cmd->params.chan_rpt_req; + struct mwifiex_radar_params *radar_params = (void *)data_buf; + + cmd->command = cpu_to_le16(HostCmd_CMD_CHAN_REPORT_REQUEST); + cmd->size = cpu_to_le16(S_DS_GEN); + le16_add_cpu(&cmd->size, sizeof(struct host_cmd_ds_chan_rpt_req)); + + cr_req->chan_desc.start_freq = cpu_to_le16(MWIFIEX_A_BAND_START_FREQ); + cr_req->chan_desc.chan_num = radar_params->chandef->chan->hw_value; + cr_req->chan_desc.chan_width = radar_params->chandef->width; + cr_req->msec_dwell_time = cpu_to_le32(radar_params->cac_time_ms); + + dev_dbg(priv->adapter->dev, + "11h: issuing DFS Radar check for channel=%d\n", + radar_params->chandef->chan->hw_value); + + return 0; +} + +/* This function is to abort ongoing CAC upon stopping AP operations + * or during unload. + */ +void mwifiex_abort_cac(struct mwifiex_private *priv) +{ + if (priv->wdev.cac_started) { + dev_dbg(priv->adapter->dev, + "Aborting delayed work for CAC.\n"); + cancel_delayed_work_sync(&priv->dfs_cac_work); + cfg80211_cac_event(priv->netdev, &priv->dfs_chandef, + NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); + } +} + +/* This function handles channel report event from FW during CAC period. + * If radar is detected during CAC, driver indicates the same to cfg80211 + * and also cancels ongoing delayed work. + */ +int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + struct host_cmd_ds_chan_rpt_event *rpt_event; + struct mwifiex_ie_types_chan_rpt_data *rpt; + u8 *evt_buf; + u16 event_len, tlv_len; + + rpt_event = (void *)(skb->data + sizeof(u32)); + event_len = skb->len - (sizeof(struct host_cmd_ds_chan_rpt_event)+ + sizeof(u32)); + + if (le32_to_cpu(rpt_event->result) != HostCmd_RESULT_OK) { + dev_err(priv->adapter->dev, "Error in channel report event\n"); + return -1; + } + + evt_buf = (void *)&rpt_event->tlvbuf; + + while (event_len >= sizeof(struct mwifiex_ie_types_header)) { + rpt = (void *)&rpt_event->tlvbuf; + tlv_len = le16_to_cpu(rpt->header.len); + + switch (le16_to_cpu(rpt->header.type)) { + case TLV_TYPE_CHANRPT_11H_BASIC: + if (rpt->map.radar) { + dev_notice(priv->adapter->dev, + "RADAR Detected on channel %d!\n", + priv->dfs_chandef.chan->hw_value); + cancel_delayed_work_sync(&priv->dfs_cac_work); + cfg80211_cac_event(priv->netdev, + &priv->dfs_chandef, + NL80211_RADAR_DETECTED, + GFP_KERNEL); + } + break; + default: + break; + } + + evt_buf += (tlv_len + sizeof(rpt->header)); + event_len -= (tlv_len + sizeof(rpt->header)); + } + + return 0; +} + +/* Handler for radar detected event from FW.*/ +int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + struct mwifiex_radar_det_event *rdr_event; + + rdr_event = (void *)(skb->data + sizeof(u32)); + + if (le32_to_cpu(rdr_event->passed)) { + dev_notice(priv->adapter->dev, + "radar detected; indicating kernel\n"); + cfg80211_radar_event(priv->adapter->wiphy, &priv->dfs_chandef, + GFP_KERNEL); + dev_dbg(priv->adapter->dev, "regdomain: %d\n", + rdr_event->reg_domain); + dev_dbg(priv->adapter->dev, "radar detection type: %d\n", + rdr_event->det_type); + } else { + dev_dbg(priv->adapter->dev, "false radar detection event!\n"); + } + + return 0; +} + +/* This is work queue function for channel switch handling. + * This function takes care of updating new channel definitin to + * bss config structure, restart AP and indicate channel switch success + * to cfg80211. + */ +void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work) +{ + struct mwifiex_uap_bss_param *bss_cfg; + struct delayed_work *delayed_work = + container_of(work, struct delayed_work, work); + struct mwifiex_private *priv = + container_of(delayed_work, struct mwifiex_private, + dfs_chan_sw_work); + + if (WARN_ON(!priv)) + return; + + bss_cfg = &priv->bss_cfg; + if (!bss_cfg->beacon_period) { + dev_err(priv->adapter->dev, + "channel switch: AP already stopped\n"); + return; + } + + mwifiex_uap_set_channel(bss_cfg, priv->dfs_chandef); + + if (mwifiex_config_start_uap(priv, bss_cfg)) { + dev_dbg(priv->adapter->dev, + "Failed to start AP after channel switch\n"); + return; + } + + dev_notice(priv->adapter->dev, + "indicating channel switch completion to kernel\n"); + cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef); +} diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 9d4786e7ddff..543148d27b01 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -39,7 +39,7 @@ int mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type, { uint16_t ht_ext_cap = le16_to_cpu(ht_cap->extended_ht_cap_info); struct ieee80211_supported_band *sband = - priv->wdev->wiphy->bands[radio_type]; + priv->wdev.wiphy->bands[radio_type]; if (WARN_ON_ONCE(!sband)) { dev_err(priv->adapter->dev, "Invalid radio type!\n"); @@ -314,7 +314,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, return ret_len; radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); - sband = priv->wdev->wiphy->bands[radio_type]; + sband = priv->wdev.wiphy->bands[radio_type]; if (bss_desc->bcn_ht_cap) { ht_cap = (struct mwifiex_ie_types_htcap *) *buffer; @@ -558,10 +558,10 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) spin_lock_irqsave(&priv->sta_list_spinlock, flags); sta_ptr = mwifiex_get_sta_entry(priv, peer_mac); if (!sta_ptr) { + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); dev_warn(priv->adapter->dev, "BA setup with unknown TDLS peer %pM!\n", peer_mac); - spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); return -1; } if (sta_ptr->is_11ac_enabled) diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index f275675cdbd3..8e2e39422ad8 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h @@ -130,7 +130,9 @@ static inline u8 mwifiex_space_avail_for_new_ba_stream( { struct mwifiex_private *priv; u8 i; - u32 ba_stream_num = 0; + u32 ba_stream_num = 0, ba_stream_max; + + ba_stream_max = MWIFIEX_MAX_TX_BASTREAM_SUPPORTED; for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; @@ -139,8 +141,14 @@ static inline u8 mwifiex_space_avail_for_new_ba_stream( &priv->tx_ba_stream_tbl_ptr); } - return ((ba_stream_num < - MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) ? true : false); + if (adapter->fw_api_ver == MWIFIEX_FW_V15) { + ba_stream_max = + GETSUPP_TXBASTREAMS(adapter->hw_dot_11n_dev_cap); + if (!ba_stream_max) + ba_stream_max = MWIFIEX_MAX_TX_BASTREAM_SUPPORTED; + } + + return ((ba_stream_num < ba_stream_max) ? true : false); } /* diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 8720a3d3c755..9b983b5cebbd 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -101,6 +101,13 @@ mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, { struct txpd *local_tx_pd; struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); + unsigned int pad; + int headroom = (priv->adapter->iface_type == + MWIFIEX_USB) ? 0 : INTF_HEADER_LEN; + + pad = ((void *)skb->data - sizeof(*local_tx_pd) - + headroom - NULL) & (MWIFIEX_DMA_ALIGN_SZ - 1); + skb_push(skb, pad); skb_push(skb, sizeof(*local_tx_pd)); @@ -114,10 +121,12 @@ mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, 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_offset = cpu_to_le16(sizeof(struct txpd) + + pad); 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)); + sizeof(*local_tx_pd) - + pad); if (tx_info->flags & MWIFIEX_BUF_FLAG_TDLS_PKT) local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_TDLS_PACKET; @@ -182,7 +191,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, ra_list_flags); return -1; } - skb_reserve(skb_aggr, headroom + sizeof(struct txpd)); + skb_reserve(skb_aggr, MWIFIEX_MIN_DATA_HEADER_LEN); tx_info_aggr = MWIFIEX_SKB_TXCB(skb_aggr); memset(tx_info_aggr, 0, sizeof(*tx_info_aggr)); diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index d73fda312c87..a2e8817b56d8 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -45,7 +45,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv, skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length)); ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, - priv->wdev->iftype, 0, false); + priv->wdev.iftype, 0, false); while (!skb_queue_empty(&list)) { rx_skb = __skb_dequeue(&list); @@ -353,9 +353,6 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, spin_lock_irqsave(&priv->sta_list_spinlock, flags); if (mwifiex_queuing_ra_based(priv)) { - dev_dbg(priv->adapter->dev, - "info: AP/ADHOC:last_seq=%d start_win=%d\n", - last_seq, new_node->start_win); if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) { node = mwifiex_get_sta_entry(priv, ta); if (node) @@ -370,6 +367,9 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, } spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + dev_dbg(priv->adapter->dev, "info: last_seq=%d start_win=%d\n", + last_seq, new_node->start_win); + if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM && last_seq >= new_node->start_win) { new_node->start_win = last_seq + 1; @@ -391,10 +391,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, new_node->timer_context.priv = priv; new_node->timer_context.timer_is_set = false; - 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; + setup_timer(&new_node->timer_context.timer, mwifiex_flush_data, + (unsigned long)&new_node->timer_context); for (i = 0; i < win_size; ++i) new_node->rx_reorder_ptr[i] = NULL; @@ -468,10 +466,10 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, sta_ptr = mwifiex_get_sta_entry(priv, cmd_addba_req->peer_mac_addr); if (!sta_ptr) { + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); dev_warn(priv->adapter->dev, "BA setup with unknown TDLS peer %pM!\n", cmd_addba_req->peer_mac_addr); - spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); return -1; } if (sta_ptr->is_11ac_enabled) diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile index 9487d728ac20..fdfd9bf15ed4 100644 --- a/drivers/net/wireless/mwifiex/Makefile +++ b/drivers/net/wireless/mwifiex/Makefile @@ -53,3 +53,5 @@ obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o mwifiex_usb-y += usb.o obj-$(CONFIG_MWIFIEX_USB) += mwifiex_usb.o + +ccflags-y += -D__CHECK_ENDIAN diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 4a66a6555366..41c8e25df954 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -590,77 +590,62 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv; struct mwifiex_uap_bss_param *bss_cfg; - int ret, bss_started, i; + int ret; - for (i = 0; i < adapter->priv_num; i++) { - priv = adapter->priv[i]; + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); - switch (priv->bss_role) { - case MWIFIEX_BSS_ROLE_UAP: - bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), - GFP_KERNEL); - if (!bss_cfg) - return -ENOMEM; - - mwifiex_set_sys_config_invalid_data(bss_cfg); - - if (changed & WIPHY_PARAM_RTS_THRESHOLD) - bss_cfg->rts_threshold = wiphy->rts_threshold; - if (changed & WIPHY_PARAM_FRAG_THRESHOLD) - bss_cfg->frag_threshold = wiphy->frag_threshold; - if (changed & WIPHY_PARAM_RETRY_LONG) - bss_cfg->retry_limit = wiphy->retry_long; - - bss_started = priv->bss_started; - - ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, - HostCmd_ACT_GEN_SET, 0, - NULL, true); - if (ret) { - wiphy_err(wiphy, "Failed to stop the BSS\n"); - kfree(bss_cfg); - return ret; - } - - ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, - HostCmd_ACT_GEN_SET, - UAP_BSS_PARAMS_I, bss_cfg, - false); - - kfree(bss_cfg); - - if (ret) { - wiphy_err(wiphy, "Failed to set bss config\n"); - return ret; - } - - if (!bss_started) - break; - - ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, - HostCmd_ACT_GEN_SET, 0, - NULL, false); - if (ret) { - wiphy_err(wiphy, "Failed to start BSS\n"); - return ret; - } - - break; - case MWIFIEX_BSS_ROLE_STA: - 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); - if (ret) - return ret; - } - break; + switch (priv->bss_role) { + case MWIFIEX_BSS_ROLE_UAP: + if (priv->bss_started) { + dev_err(adapter->dev, + "cannot change wiphy params when bss started"); + return -EINVAL; } + + bss_cfg = kzalloc(sizeof(*bss_cfg), GFP_KERNEL); + if (!bss_cfg) + return -ENOMEM; + + mwifiex_set_sys_config_invalid_data(bss_cfg); + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) + bss_cfg->rts_threshold = wiphy->rts_threshold; + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) + bss_cfg->frag_threshold = wiphy->frag_threshold; + if (changed & WIPHY_PARAM_RETRY_LONG) + bss_cfg->retry_limit = wiphy->retry_long; + + ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, + HostCmd_ACT_GEN_SET, + UAP_BSS_PARAMS_I, bss_cfg, + false); + + kfree(bss_cfg); + if (ret) { + wiphy_err(wiphy, "Failed to set wiphy phy params\n"); + return ret; + } + break; + + case MWIFIEX_BSS_ROLE_STA: + if (priv->media_connected) { + dev_err(adapter->dev, + "cannot change wiphy params when connected"); + return -EINVAL; + } + 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); + if (ret) + return ret; + } + break; } return 0; @@ -671,9 +656,6 @@ mwifiex_cfg80211_deinit_p2p(struct mwifiex_private *priv) { u16 mode = P2P_MODE_DISABLE; - if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) - mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_STA); - if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG, HostCmd_ACT_GEN_SET, 0, &mode, true)) return -1; @@ -730,12 +712,249 @@ mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv) HostCmd_ACT_GEN_SET, 0, &mode, true)) return -1; - if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) - mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_UAP); + return 0; +} + +static int mwifiex_deinit_priv_params(struct mwifiex_private *priv) +{ + priv->mgmt_frame_mask = 0; + if (mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG, + HostCmd_ACT_GEN_SET, 0, + &priv->mgmt_frame_mask, false)) { + dev_warn(priv->adapter->dev, + "could not unregister mgmt frame rx\n"); + return -1; + } + + mwifiex_deauthenticate(priv, NULL); + mwifiex_free_priv(priv); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; return 0; } +static int +mwifiex_init_new_priv_params(struct mwifiex_private *priv, + struct net_device *dev, + enum nl80211_iftype type) +{ + mwifiex_init_priv(priv); + + priv->bss_mode = type; + priv->wdev.iftype = type; + + mwifiex_init_priv_params(priv, priv->netdev); + priv->bss_started = 0; + + switch (type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + priv->bss_role = MWIFIEX_BSS_ROLE_STA; + priv->bss_type = MWIFIEX_BSS_TYPE_STA; + break; + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + priv->bss_role = MWIFIEX_BSS_ROLE_STA; + priv->bss_type = MWIFIEX_BSS_TYPE_P2P; + break; + case NL80211_IFTYPE_AP: + priv->bss_type = MWIFIEX_BSS_TYPE_UAP; + priv->bss_role = MWIFIEX_BSS_ROLE_UAP; + break; + default: + dev_err(priv->adapter->dev, + "%s: changing to %d not supported\n", + dev->name, type); + return -EOPNOTSUPP; + } + + return 0; +} + +static int +mwifiex_change_vif_to_p2p(struct net_device *dev, + enum nl80211_iftype curr_iftype, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct mwifiex_private *priv; + struct mwifiex_adapter *adapter; + + priv = mwifiex_netdev_get_priv(dev); + + if (!priv) + return -1; + + adapter = priv->adapter; + + if (adapter->curr_iface_comb.p2p_intf == + adapter->iface_limit.p2p_intf) { + dev_err(adapter->dev, + "cannot create multiple P2P ifaces\n"); + return -1; + } + + dev_dbg(priv->adapter->dev, "%s: changing role to p2p\n", dev->name); + + if (mwifiex_deinit_priv_params(priv)) + return -1; + if (mwifiex_init_new_priv_params(priv, dev, type)) + return -1; + + switch (type) { + case NL80211_IFTYPE_P2P_CLIENT: + if (mwifiex_cfg80211_init_p2p_client(priv)) + return -EFAULT; + break; + case NL80211_IFTYPE_P2P_GO: + if (mwifiex_cfg80211_init_p2p_go(priv)) + return -EFAULT; + break; + default: + dev_err(priv->adapter->dev, + "%s: changing to %d not supported\n", + dev->name, type); + return -EOPNOTSUPP; + } + + if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL, true)) + return -1; + + if (mwifiex_sta_init_cmd(priv, false, false)) + return -1; + + switch (curr_iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + adapter->curr_iface_comb.sta_intf--; + break; + case NL80211_IFTYPE_AP: + adapter->curr_iface_comb.uap_intf--; + break; + default: + break; + } + + adapter->curr_iface_comb.p2p_intf++; + dev->ieee80211_ptr->iftype = type; + + return 0; +} + +static int +mwifiex_change_vif_to_sta_adhoc(struct net_device *dev, + enum nl80211_iftype curr_iftype, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct mwifiex_private *priv; + struct mwifiex_adapter *adapter; + + priv = mwifiex_netdev_get_priv(dev); + + if (!priv) + return -1; + + adapter = priv->adapter; + + if ((curr_iftype != NL80211_IFTYPE_P2P_CLIENT && + curr_iftype != NL80211_IFTYPE_P2P_GO) && + (adapter->curr_iface_comb.sta_intf == + adapter->iface_limit.sta_intf)) { + dev_err(adapter->dev, + "cannot create multiple station/adhoc ifaces\n"); + return -1; + } + + if (type == NL80211_IFTYPE_STATION) + dev_notice(adapter->dev, + "%s: changing role to station\n", dev->name); + else + dev_notice(adapter->dev, + "%s: changing role to adhoc\n", dev->name); + + if (mwifiex_deinit_priv_params(priv)) + return -1; + if (mwifiex_init_new_priv_params(priv, dev, type)) + return -1; + if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL, true)) + return -1; + if (mwifiex_sta_init_cmd(priv, false, false)) + return -1; + + switch (curr_iftype) { + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + adapter->curr_iface_comb.p2p_intf--; + break; + case NL80211_IFTYPE_AP: + adapter->curr_iface_comb.uap_intf--; + break; + default: + break; + } + + adapter->curr_iface_comb.sta_intf++; + dev->ieee80211_ptr->iftype = type; + return 0; +} + +static int +mwifiex_change_vif_to_ap(struct net_device *dev, + enum nl80211_iftype curr_iftype, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct mwifiex_private *priv; + struct mwifiex_adapter *adapter; + + priv = mwifiex_netdev_get_priv(dev); + + if (!priv) + return -1; + + adapter = priv->adapter; + + if (adapter->curr_iface_comb.uap_intf == + adapter->iface_limit.uap_intf) { + dev_err(adapter->dev, + "cannot create multiple AP ifaces\n"); + return -1; + } + + dev_notice(adapter->dev, "%s: changing role to AP\n", dev->name); + + if (mwifiex_deinit_priv_params(priv)) + return -1; + if (mwifiex_init_new_priv_params(priv, dev, type)) + return -1; + if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL, true)) + return -1; + if (mwifiex_sta_init_cmd(priv, false, false)) + return -1; + + switch (curr_iftype) { + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + adapter->curr_iface_comb.p2p_intf--; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + adapter->curr_iface_comb.sta_intf--; + break; + default: + break; + } + + adapter->curr_iface_comb.uap_intf++; + dev->ieee80211_ptr->iftype = type; + return 0; +} /* * CFG802.11 operation handler to change interface type. */ @@ -745,19 +964,32 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - int ret; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + enum nl80211_iftype curr_iftype = dev->ieee80211_ptr->iftype; - switch (dev->ieee80211_ptr->iftype) { + switch (curr_iftype) { case NL80211_IFTYPE_ADHOC: switch (type) { case NL80211_IFTYPE_STATION: - break; + priv->bss_mode = type; + priv->sec_info.authentication_mode = + NL80211_AUTHTYPE_OPEN_SYSTEM; + dev->ieee80211_ptr->iftype = type; + mwifiex_deauthenticate(priv, NULL); + return mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL, + true); + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + return mwifiex_change_vif_to_p2p(dev, curr_iftype, + type, flags, params); + case NL80211_IFTYPE_AP: + return mwifiex_change_vif_to_ap(dev, curr_iftype, type, + flags, params); case NL80211_IFTYPE_UNSPECIFIED: wiphy_warn(wiphy, "%s: kept type as IBSS\n", dev->name); case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */ return 0; - case NL80211_IFTYPE_AP: default: wiphy_err(wiphy, "%s: changing to %d not supported\n", dev->name, type); @@ -767,22 +999,25 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_STATION: switch (type) { case NL80211_IFTYPE_ADHOC: - break; + priv->bss_mode = type; + priv->sec_info.authentication_mode = + NL80211_AUTHTYPE_OPEN_SYSTEM; + dev->ieee80211_ptr->iftype = type; + mwifiex_deauthenticate(priv, NULL); + return mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL, + true); case NL80211_IFTYPE_P2P_CLIENT: - if (mwifiex_cfg80211_init_p2p_client(priv)) - return -EFAULT; - dev->ieee80211_ptr->iftype = type; - return 0; case NL80211_IFTYPE_P2P_GO: - if (mwifiex_cfg80211_init_p2p_go(priv)) - return -EFAULT; - dev->ieee80211_ptr->iftype = type; - return 0; + return mwifiex_change_vif_to_p2p(dev, curr_iftype, + type, flags, params); + case NL80211_IFTYPE_AP: + return mwifiex_change_vif_to_ap(dev, curr_iftype, type, + flags, params); case NL80211_IFTYPE_UNSPECIFIED: wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name); case NL80211_IFTYPE_STATION: /* This shouldn't happen */ return 0; - case NL80211_IFTYPE_AP: default: wiphy_err(wiphy, "%s: changing to %d not supported\n", dev->name, type); @@ -791,12 +1026,20 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, break; case NL80211_IFTYPE_AP: switch (type) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype, + type, flags, + params); + break; + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + return mwifiex_change_vif_to_p2p(dev, curr_iftype, + type, flags, params); case NL80211_IFTYPE_UNSPECIFIED: wiphy_warn(wiphy, "%s: kept type as AP\n", dev->name); case NL80211_IFTYPE_AP: /* This shouldn't happen */ return 0; - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_STATION: default: wiphy_err(wiphy, "%s: changing to %d not supported\n", dev->name, type); @@ -807,11 +1050,30 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_P2P_GO: switch (type) { case NL80211_IFTYPE_STATION: - if (mwifiex_cfg80211_deinit_p2p(priv)) + if (mwifiex_cfg80211_init_p2p_client(priv)) return -EFAULT; dev->ieee80211_ptr->iftype = type; + break; + case NL80211_IFTYPE_ADHOC: + if (mwifiex_cfg80211_deinit_p2p(priv)) + return -EFAULT; + return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype, + type, flags, + params); + break; + case NL80211_IFTYPE_AP: + if (mwifiex_cfg80211_deinit_p2p(priv)) + return -EFAULT; + return mwifiex_change_vif_to_ap(dev, curr_iftype, type, + flags, params); + case NL80211_IFTYPE_UNSPECIFIED: + wiphy_warn(wiphy, "%s: kept type as P2P\n", dev->name); + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: return 0; default: + wiphy_err(wiphy, "%s: changing to %d not supported\n", + dev->name, type); return -EOPNOTSUPP; } break; @@ -821,16 +1083,8 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, return -EOPNOTSUPP; } - dev->ieee80211_ptr->iftype = type; - priv->bss_mode = type; - mwifiex_deauthenticate(priv, NULL); - priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; - - ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, - HostCmd_ACT_GEN_SET, 0, NULL, true); - - return ret; + return 0; } static void @@ -856,16 +1110,16 @@ mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo, /* HT or VHT */ switch (tx_htinfo & (BIT(3) | BIT(2))) { case 0: - /* This will be 20MHz */ + rate->bw = RATE_INFO_BW_20; break; case (BIT(2)): - rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + rate->bw = RATE_INFO_BW_40; break; case (BIT(3)): - rate->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; + rate->bw = RATE_INFO_BW_80; break; case (BIT(3) | BIT(2)): - rate->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; + rate->bw = RATE_INFO_BW_160; break; } @@ -885,8 +1139,9 @@ mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo, if ((tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) { rate->mcs = priv->tx_rate; rate->flags |= RATE_INFO_FLAGS_MCS; + rate->bw = RATE_INFO_BW_20; if (tx_htinfo & BIT(1)) - rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + rate->bw = RATE_INFO_BW_40; if (tx_htinfo & BIT(2)) rate->flags |= RATE_INFO_FLAGS_SHORT_GI; } @@ -910,10 +1165,10 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, { u32 rate; - sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | - STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS | - STATION_INFO_TX_BITRATE | - STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; + sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) | BIT(NL80211_STA_INFO_TX_BYTES) | + BIT(NL80211_STA_INFO_RX_PACKETS) | BIT(NL80211_STA_INFO_TX_PACKETS) | + BIT(NL80211_STA_INFO_TX_BITRATE) | + BIT(NL80211_STA_INFO_SIGNAL) | BIT(NL80211_STA_INFO_SIGNAL_AVG); /* Get signal information from the firmware */ if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO, @@ -944,7 +1199,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, sinfo->txrate.legacy = rate * 5; if (priv->bss_mode == NL80211_IFTYPE_STATION) { - sinfo->filled |= STATION_INFO_BSS_PARAM; + sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM); sinfo->bss_param.flags = 0; if (priv->curr_bss_params.bss_descriptor.cap_info_bitmap & WLAN_CAPABILITY_SHORT_PREAMBLE) @@ -1037,10 +1292,11 @@ mwifiex_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *dev, survey->channel = ieee80211_get_channel(wiphy, ieee80211_channel_to_frequency(pchan_stats[idx].chan_num, band)); survey->filled = SURVEY_INFO_NOISE_DBM | - SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME_BUSY; + SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY; survey->noise = pchan_stats[idx].noise; - survey->channel_time = pchan_stats[idx].cca_scan_dur; - survey->channel_time_busy = pchan_stats[idx].cca_busy_dur; + survey->time = pchan_stats[idx].cca_scan_dur; + survey->time_busy = pchan_stats[idx].cca_busy_dur; return 0; } @@ -1395,10 +1651,13 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + mwifiex_abort_cac(priv); + if (mwifiex_del_mgmt_ies(priv)) wiphy_err(wiphy, "Failed to delete mgmt IEs!\n"); priv->ap_11n_enabled = 0; + memset(&priv->bss_cfg, 0, sizeof(priv->bss_cfg)); if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, HostCmd_ACT_GEN_SET, 0, NULL, true)) { @@ -1420,12 +1679,9 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, { struct mwifiex_uap_bss_param *bss_cfg; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - u8 config_bands = 0; if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) return -1; - if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon)) - return -1; bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); if (!bss_cfg) @@ -1442,6 +1698,11 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len); bss_cfg->ssid.ssid_len = params->ssid_len; } + if (params->inactivity_timeout > 0) { + /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */ + bss_cfg->sta_ao_timer = 10 * params->inactivity_timeout; + bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout; + } switch (params->hidden_ssid) { case NL80211_HIDDEN_SSID_NOT_IN_USE: @@ -1457,33 +1718,8 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, return -EINVAL; } - bss_cfg->channel = ieee80211_frequency_to_channel( - params->chandef.chan->center_freq); - - /* Set appropriate bands */ - if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) { - bss_cfg->band_cfg = BAND_CONFIG_BG; - config_bands = BAND_B | BAND_G; - - if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT) - config_bands |= BAND_GN; - } else { - bss_cfg->band_cfg = BAND_CONFIG_A; - config_bands = BAND_A; - - if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT) - config_bands |= BAND_AN; - - if (params->chandef.width > NL80211_CHAN_WIDTH_40) - config_bands |= BAND_AAC; - } - - if (!((config_bands | priv->adapter->fw_bands) & - ~priv->adapter->fw_bands)) - priv->adapter->config_bands = config_bands; - + mwifiex_uap_set_channel(bss_cfg, params->chandef); mwifiex_set_uap_rates(bss_cfg, params); - mwifiex_send_domain_info_cmd_fw(wiphy); if (mwifiex_set_secure_params(priv, bss_cfg, params)) { kfree(bss_cfg); @@ -1506,45 +1742,29 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, mwifiex_set_wmm_params(priv, bss_cfg, params); - if (params->inactivity_timeout > 0) { - /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */ - bss_cfg->sta_ao_timer = 10 * params->inactivity_timeout; - bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout; + if (mwifiex_is_11h_active(priv) && + !cfg80211_chandef_dfs_required(wiphy, ¶ms->chandef, + priv->bss_mode)) { + dev_dbg(priv->adapter->dev, "Disable 11h extensions in FW\n"); + if (mwifiex_11h_activate(priv, false)) { + dev_err(priv->adapter->dev, + "Failed to disable 11h extensions!!"); + return -1; + } + priv->state_11h.is_11h_active = true; } - if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, - HostCmd_ACT_GEN_SET, 0, NULL, true)) { - wiphy_err(wiphy, "Failed to stop the BSS\n"); + if (mwifiex_config_start_uap(priv, bss_cfg)) { + wiphy_err(wiphy, "Failed to start AP\n"); kfree(bss_cfg); return -1; } - if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, - HostCmd_ACT_GEN_SET, - UAP_BSS_PARAMS_I, bss_cfg, false)) { - wiphy_err(wiphy, "Failed to set the SSID\n"); - kfree(bss_cfg); + if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon)) return -1; - } + memcpy(&priv->bss_cfg, bss_cfg, sizeof(priv->bss_cfg)); kfree(bss_cfg); - - if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, - HostCmd_ACT_GEN_SET, 0, NULL, false)) { - wiphy_err(wiphy, "Failed to start the BSS\n"); - return -1; - } - - if (priv->sec_info.wep_enabled) - priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; - else - priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; - - if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, - HostCmd_ACT_GEN_SET, 0, - &priv->curr_pkt_filter, true)) - return -1; - return 0; } @@ -1603,15 +1823,15 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) ie_len = ie_buf[1] + sizeof(struct ieee_types_header); band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); - chan = __ieee80211_get_channel(priv->wdev->wiphy, + chan = __ieee80211_get_channel(priv->wdev.wiphy, ieee80211_channel_to_frequency(bss_info.bss_chan, band)); - bss = cfg80211_inform_bss(priv->wdev->wiphy, chan, + bss = cfg80211_inform_bss(priv->wdev.wiphy, chan, CFG80211_BSS_FTYPE_UNKNOWN, bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, 0, ie_buf, ie_len, 0, GFP_KERNEL); - cfg80211_put_bss(priv->wdev->wiphy, bss); + cfg80211_put_bss(priv->wdev.wiphy, bss); memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); return 0; @@ -1732,12 +1952,12 @@ done: /* Find the BSS we want using available scan results */ if (mode == NL80211_IFTYPE_ADHOC) - bss = cfg80211_get_bss(priv->wdev->wiphy, channel, + bss = cfg80211_get_bss(priv->wdev.wiphy, channel, bssid, ssid, ssid_len, WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); else - bss = cfg80211_get_bss(priv->wdev->wiphy, channel, + bss = cfg80211_get_bss(priv->wdev.wiphy, channel, bssid, ssid, ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); @@ -1784,6 +2004,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_adapter *adapter = priv->adapter; int ret; if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) { @@ -1793,11 +2014,18 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; } - if (priv->wdev && priv->wdev->current_bss) { + if (priv->wdev.current_bss) { wiphy_warn(wiphy, "%s: already connected\n", dev->name); return -EALREADY; } + if (adapter->surprise_removed || adapter->is_cmd_timedout) { + wiphy_err(wiphy, + "%s: Ignore connection. Card removed or FW in bad state\n", + dev->name); + return -EFAULT; + } + wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", (char *) sme->ssid, sme->bssid); @@ -1844,7 +2072,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, static int mwifiex_set_ibss_params(struct mwifiex_private *priv, struct cfg80211_ibss_params *params) { - struct wiphy *wiphy = priv->wdev->wiphy; + struct wiphy *wiphy = priv->wdev.wiphy; struct mwifiex_adapter *adapter = priv->adapter; int index = 0, i; u8 config_bands = 0; @@ -2169,6 +2397,7 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; } +#define MWIFIEX_MAX_WQ_LEN 30 /* * create a new virtual interface with the given name */ @@ -2182,7 +2411,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, struct mwifiex_private *priv; struct net_device *dev; void *mdev_priv; - struct wireless_dev *wdev; + char dfs_cac_str[MWIFIEX_MAX_WQ_LEN], dfs_chsw_str[MWIFIEX_MAX_WQ_LEN]; if (!adapter) return ERR_PTR(-EFAULT); @@ -2191,20 +2420,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: - priv = adapter->priv[MWIFIEX_BSS_TYPE_STA]; - if (priv->bss_mode) { + if (adapter->curr_iface_comb.sta_intf == + adapter->iface_limit.sta_intf) { wiphy_err(wiphy, "cannot create multiple sta/adhoc ifaces\n"); return ERR_PTR(-EINVAL); } - wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); - if (!wdev) - return ERR_PTR(-ENOMEM); + priv = mwifiex_get_unused_priv(adapter); + if (!priv) { + wiphy_err(wiphy, + "could not get free private struct\n"); + return ERR_PTR(-EFAULT); + } - wdev->wiphy = wiphy; - priv->wdev = wdev; - wdev->iftype = NL80211_IFTYPE_STATION; + priv->wdev.wiphy = wiphy; + priv->wdev.iftype = NL80211_IFTYPE_STATION; if (type == NL80211_IFTYPE_UNSPECIFIED) priv->bss_mode = NL80211_IFTYPE_STATION; @@ -2219,20 +2450,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, break; case NL80211_IFTYPE_AP: - priv = adapter->priv[MWIFIEX_BSS_TYPE_UAP]; - - if (priv->bss_mode) { - wiphy_err(wiphy, "Can't create multiple AP interfaces"); + if (adapter->curr_iface_comb.uap_intf == + adapter->iface_limit.uap_intf) { + wiphy_err(wiphy, + "cannot create multiple AP ifaces\n"); return ERR_PTR(-EINVAL); } - wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); - if (!wdev) - return ERR_PTR(-ENOMEM); + priv = mwifiex_get_unused_priv(adapter); + if (!priv) { + wiphy_err(wiphy, + "could not get free private struct\n"); + return ERR_PTR(-EFAULT); + } - priv->wdev = wdev; - wdev->wiphy = wiphy; - wdev->iftype = NL80211_IFTYPE_AP; + priv->wdev.wiphy = wiphy; + priv->wdev.iftype = NL80211_IFTYPE_AP; priv->bss_type = MWIFIEX_BSS_TYPE_UAP; priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; @@ -2244,24 +2477,25 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, break; case NL80211_IFTYPE_P2P_CLIENT: - priv = adapter->priv[MWIFIEX_BSS_TYPE_P2P]; - - if (priv->bss_mode) { - wiphy_err(wiphy, "Can't create multiple P2P ifaces"); + if (adapter->curr_iface_comb.p2p_intf == + adapter->iface_limit.p2p_intf) { + wiphy_err(wiphy, + "cannot create multiple P2P ifaces\n"); return ERR_PTR(-EINVAL); } - wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); - if (!wdev) - return ERR_PTR(-ENOMEM); - - priv->wdev = wdev; - wdev->wiphy = wiphy; + priv = mwifiex_get_unused_priv(adapter); + if (!priv) { + wiphy_err(wiphy, + "could not get free private struct\n"); + return ERR_PTR(-EFAULT); + } + priv->wdev.wiphy = wiphy; /* At start-up, wpa_supplicant tries to change the interface * to NL80211_IFTYPE_STATION if it is not managed mode. */ - wdev->iftype = NL80211_IFTYPE_P2P_CLIENT; + priv->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT; priv->bss_mode = NL80211_IFTYPE_P2P_CLIENT; /* Setting bss_type to P2P tells firmware that this interface @@ -2277,8 +2511,9 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, priv->bss_num = 0; if (mwifiex_cfg80211_init_p2p_client(priv)) { - wdev = ERR_PTR(-EFAULT); - goto done; + memset(&priv->wdev, 0, sizeof(priv->wdev)); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(-EFAULT); } break; @@ -2292,9 +2527,10 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, IEEE80211_NUM_ACS, 1); if (!dev) { wiphy_err(wiphy, "no memory available for netdevice\n"); + memset(&priv->wdev, 0, sizeof(priv->wdev)); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; - wdev = ERR_PTR(-ENOMEM); - goto done; + return ERR_PTR(-ENOMEM); } mwifiex_init_priv_params(priv, dev); @@ -2314,7 +2550,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, &wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap, priv); dev_net_set(dev, wiphy_net(wiphy)); - dev->ieee80211_ptr = priv->wdev; + dev->ieee80211_ptr = &priv->wdev; dev->ieee80211_ptr->iftype = priv->bss_mode; memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN); SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); @@ -2335,10 +2571,47 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, free_netdev(dev); priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; priv->netdev = NULL; - wdev = ERR_PTR(-EFAULT); - goto done; + memset(&priv->wdev, 0, sizeof(priv->wdev)); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(-EFAULT); } + strcpy(dfs_cac_str, "MWIFIEX_DFS_CAC"); + strcat(dfs_cac_str, name); + priv->dfs_cac_workqueue = alloc_workqueue(dfs_cac_str, + WQ_HIGHPRI | + WQ_MEM_RECLAIM | + WQ_UNBOUND, 1); + if (!priv->dfs_cac_workqueue) { + wiphy_err(wiphy, "cannot register virtual network device\n"); + free_netdev(dev); + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + priv->netdev = NULL; + memset(&priv->wdev, 0, sizeof(priv->wdev)); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(-ENOMEM); + } + + INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue); + + strcpy(dfs_chsw_str, "MWIFIEX_DFS_CHSW"); + strcat(dfs_chsw_str, name); + priv->dfs_chan_sw_workqueue = alloc_workqueue(dfs_chsw_str, + WQ_HIGHPRI | WQ_UNBOUND | + WQ_MEM_RECLAIM, 1); + if (!priv->dfs_chan_sw_workqueue) { + wiphy_err(wiphy, "cannot register virtual network device\n"); + free_netdev(dev); + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + priv->netdev = NULL; + memset(&priv->wdev, 0, sizeof(priv->wdev)); + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(-ENOMEM); + } + + INIT_DELAYED_WORK(&priv->dfs_chan_sw_work, + mwifiex_dfs_chan_sw_work_queue); + sema_init(&priv->async_sem, 1); dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); @@ -2347,13 +2620,24 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, mwifiex_dev_debugfs_init(priv); #endif -done: - if (IS_ERR(wdev)) { - kfree(priv->wdev); - priv->wdev = NULL; + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + adapter->curr_iface_comb.sta_intf++; + break; + case NL80211_IFTYPE_AP: + adapter->curr_iface_comb.uap_intf++; + break; + case NL80211_IFTYPE_P2P_CLIENT: + adapter->curr_iface_comb.p2p_intf++; + break; + default: + wiphy_err(wiphy, "type not supported\n"); + return ERR_PTR(-EINVAL); } - return wdev; + return &priv->wdev; } EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); @@ -2363,12 +2647,13 @@ EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); + struct mwifiex_adapter *adapter = priv->adapter; #ifdef CONFIG_DEBUG_FS mwifiex_dev_debugfs_remove(priv); #endif - mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); + mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); @@ -2376,16 +2661,48 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) if (wdev->netdev->reg_state == NETREG_REGISTERED) unregister_netdevice(wdev->netdev); + if (priv->dfs_cac_workqueue) { + flush_workqueue(priv->dfs_cac_workqueue); + destroy_workqueue(priv->dfs_cac_workqueue); + priv->dfs_cac_workqueue = NULL; + } + + if (priv->dfs_chan_sw_workqueue) { + flush_workqueue(priv->dfs_chan_sw_workqueue); + destroy_workqueue(priv->dfs_chan_sw_workqueue); + priv->dfs_chan_sw_workqueue = NULL; + } /* Clear the priv in adapter */ priv->netdev->ieee80211_ptr = NULL; priv->netdev = NULL; - kfree(wdev); - priv->wdev = NULL; + priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; priv->media_connected = false; + switch (priv->bss_mode) { + case NL80211_IFTYPE_UNSPECIFIED: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + adapter->curr_iface_comb.sta_intf++; + break; + case NL80211_IFTYPE_AP: + adapter->curr_iface_comb.uap_intf++; + break; + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_P2P_GO: + adapter->curr_iface_comb.p2p_intf++; + break; + default: + dev_err(adapter->dev, "del_virtual_intf: type not supported\n"); + break; + } + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || + GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) + kfree(priv->hist_data); + return 0; } EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf); @@ -2421,30 +2738,16 @@ mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq, } #ifdef CONFIG_PM -static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, - struct cfg80211_wowlan *wowlan) +static int mwifiex_set_mef_filter(struct mwifiex_private *priv, + struct cfg80211_wowlan *wowlan) { - struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); - struct mwifiex_ds_mef_cfg mef_cfg; - struct mwifiex_mef_entry *mef_entry; - int i, filt_num = 0, ret; + int i, filt_num = 0, ret = 0; bool first_pat = true; u8 byte_seq[MWIFIEX_MEF_MAX_BYTESEQ + 1]; const u8 ipv4_mc_mac[] = {0x33, 0x33}; const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e}; - struct mwifiex_private *priv = - mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); - - if (!wowlan) { - dev_warn(adapter->dev, "None of the WOWLAN triggers enabled\n"); - return 0; - } - - if (!priv->media_connected) { - dev_warn(adapter->dev, - "Can not configure WOWLAN in disconnected state\n"); - return 0; - } + struct mwifiex_ds_mef_cfg mef_cfg; + struct mwifiex_mef_entry *mef_entry; mef_entry = kzalloc(sizeof(*mef_entry), GFP_KERNEL); if (!mef_entry) @@ -2459,9 +2762,9 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, for (i = 0; i < wowlan->n_patterns; i++) { memset(byte_seq, 0, sizeof(byte_seq)); if (!mwifiex_is_pattern_supported(&wowlan->patterns[i], - byte_seq, - MWIFIEX_MEF_MAX_BYTESEQ)) { - wiphy_err(wiphy, "Pattern not supported\n"); + byte_seq, + MWIFIEX_MEF_MAX_BYTESEQ)) { + dev_err(priv->adapter->dev, "Pattern not supported\n"); kfree(mef_entry); return -EOPNOTSUPP; } @@ -2485,9 +2788,9 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, mef_entry->filter[filt_num].repeat = 1; mef_entry->filter[filt_num].offset = - wowlan->patterns[i].pkt_offset; + wowlan->patterns[i].pkt_offset; memcpy(mef_entry->filter[filt_num].byte_seq, byte_seq, - sizeof(byte_seq)); + sizeof(byte_seq)); mef_entry->filter[filt_num].filt_type = TYPE_EQ; if (first_pat) @@ -2502,9 +2805,9 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST; mef_entry->filter[filt_num].repeat = 16; memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr, - ETH_ALEN); + ETH_ALEN); mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = - ETH_ALEN; + ETH_ALEN; mef_entry->filter[filt_num].offset = 28; mef_entry->filter[filt_num].filt_type = TYPE_EQ; if (filt_num) @@ -2513,9 +2816,9 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, filt_num++; mef_entry->filter[filt_num].repeat = 16; memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr, - ETH_ALEN); + ETH_ALEN); mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = - ETH_ALEN; + ETH_ALEN; mef_entry->filter[filt_num].offset = 56; mef_entry->filter[filt_num].filt_type = TYPE_EQ; mef_entry->filter[filt_num].filt_action = TYPE_OR; @@ -2523,16 +2826,61 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, if (!mef_cfg.criteria) mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST | - MWIFIEX_CRITERIA_UNICAST | - MWIFIEX_CRITERIA_MULTICAST; + MWIFIEX_CRITERIA_UNICAST | + MWIFIEX_CRITERIA_MULTICAST; ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG, - HostCmd_ACT_GEN_SET, 0, &mef_cfg, true); + HostCmd_ACT_GEN_SET, 0, &mef_cfg, true); kfree(mef_entry); return ret; } +static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, + struct cfg80211_wowlan *wowlan) +{ + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + struct mwifiex_ds_hs_cfg hs_cfg; + int ret = 0; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + + if (!wowlan) { + dev_warn(adapter->dev, "None of the WOWLAN triggers enabled\n"); + return 0; + } + + if (!priv->media_connected) { + dev_warn(adapter->dev, + "Can not configure WOWLAN in disconnected state\n"); + return 0; + } + + if (wowlan->n_patterns || wowlan->magic_pkt) { + ret = mwifiex_set_mef_filter(priv, wowlan); + if (ret) { + dev_err(adapter->dev, "Failed to set MEF filter\n"); + return ret; + } + } + + if (wowlan->disconnect) { + memset(&hs_cfg, 0, sizeof(hs_cfg)); + hs_cfg.is_invoke_hostcmd = false; + hs_cfg.conditions = HS_CFG_COND_MAC_EVENT; + hs_cfg.gpio = HS_CFG_GPIO_DEF; + hs_cfg.gap = HS_CFG_GAP_DEF; + ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, + MWIFIEX_SYNC_CMD, &hs_cfg); + if (ret) { + dev_err(adapter->dev, "Failed to set HS params\n"); + return ret; + } + } + + return ret; +} + static int mwifiex_cfg80211_resume(struct wiphy *wiphy) { return 0; @@ -2802,6 +3150,102 @@ mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev, return mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CREATE_LINK); } +static int +mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_csa_settings *params) +{ + struct ieee_types_header *chsw_ie; + struct ieee80211_channel_sw_ie *channel_sw; + int chsw_msec; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + if (priv->adapter->scan_processing) { + dev_err(priv->adapter->dev, + "radar detection: scan in process...\n"); + return -EBUSY; + } + + if (priv->wdev.cac_started) + return -EBUSY; + + if (cfg80211_chandef_identical(¶ms->chandef, + &priv->dfs_chandef)) + return -EINVAL; + + chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH, + params->beacon_csa.tail, + params->beacon_csa.tail_len); + if (!chsw_ie) { + dev_err(priv->adapter->dev, + "Could not parse channel switch announcement IE\n"); + return -EINVAL; + } + + channel_sw = (void *)(chsw_ie + 1); + if (channel_sw->mode) { + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter); + } + + if (mwifiex_del_mgmt_ies(priv)) + wiphy_err(wiphy, "Failed to delete mgmt IEs!\n"); + + if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon_csa)) { + wiphy_err(wiphy, "%s: setting mgmt ies failed\n", __func__); + return -EFAULT; + } + + memcpy(&priv->dfs_chandef, ¶ms->chandef, sizeof(priv->dfs_chandef)); + memcpy(&priv->beacon_after, ¶ms->beacon_after, + sizeof(priv->beacon_after)); + + chsw_msec = max(channel_sw->count * priv->bss_cfg.beacon_period, 100); + queue_delayed_work(priv->dfs_chan_sw_workqueue, &priv->dfs_chan_sw_work, + msecs_to_jiffies(chsw_msec)); + return 0; +} + +static int +mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, + u32 cac_time_ms) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_radar_params radar_params; + + if (priv->adapter->scan_processing) { + dev_err(priv->adapter->dev, + "radar detection: scan already in process...\n"); + return -EBUSY; + } + + if (!mwifiex_is_11h_active(priv)) { + dev_dbg(priv->adapter->dev, "Enable 11h extensions in FW\n"); + if (mwifiex_11h_activate(priv, true)) { + dev_err(priv->adapter->dev, + "Failed to activate 11h extensions!!"); + return -1; + } + priv->state_11h.is_11h_active = true; + } + + memset(&radar_params, 0, sizeof(struct mwifiex_radar_params)); + radar_params.chandef = chandef; + radar_params.cac_time_ms = cac_time_ms; + + memcpy(&priv->dfs_chandef, chandef, sizeof(priv->dfs_chandef)); + + if (mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST, + HostCmd_ACT_GEN_SET, 0, &radar_params, true)) + return -1; + + queue_delayed_work(priv->dfs_cac_workqueue, &priv->dfs_cac_work, + msecs_to_jiffies(cac_time_ms)); + return 0; +} + static int mwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac, @@ -2866,11 +3310,13 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .tdls_oper = mwifiex_cfg80211_tdls_oper, .add_station = mwifiex_cfg80211_add_station, .change_station = mwifiex_cfg80211_change_station, + .start_radar_detection = mwifiex_cfg80211_start_radar_detection, + .channel_switch = mwifiex_cfg80211_channel_switch, }; #ifdef CONFIG_PM static const struct wiphy_wowlan_support mwifiex_wowlan_support = { - .flags = WIPHY_WOWLAN_MAGIC_PKT, + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, .n_patterns = MWIFIEX_MEF_MAX_FILTERS, .pattern_min_len = 1, .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN, @@ -2964,12 +3410,13 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->cipher_suites = mwifiex_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); - memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN); + ether_addr_copy(wiphy->perm_addr, adapter->perm_addr); wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | WIPHY_FLAG_AP_UAPSD | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_HAS_CHANNEL_SWITCH; if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index b8242eb2be6f..e9df8826f124 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -322,9 +322,9 @@ mwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq) return cfp; if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG) - sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; + sband = priv->wdev.wiphy->bands[IEEE80211_BAND_2GHZ]; else - sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; + sband = priv->wdev.wiphy->bands[IEEE80211_BAND_5GHZ]; if (!sband) { dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d\n", @@ -509,3 +509,21 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) return k; } + +u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv, + u8 rx_rate, u8 rate_info) +{ + u8 rate_index = 0; + + /* HT40 */ + if ((rate_info & BIT(0)) && (rate_info & BIT(1))) + rate_index = MWIFIEX_RATE_INDEX_MCS0 + + MWIFIEX_BW20_MCS_NUM + rx_rate; + else if (rate_info & BIT(0)) /* HT20 */ + rate_index = MWIFIEX_RATE_INDEX_MCS0 + rx_rate; + else + rate_index = (rx_rate > MWIFIEX_RATE_INDEX_OFDM0) ? + rx_rate - 1 : rx_rate; + + return rate_index; +} diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 85597200badc..c5a14ff7eb82 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -315,22 +315,19 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) 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 (!le16_to_cpu(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 (!le16_to_cpu(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); - } + if (!le16_to_cpu(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 (!le16_to_cpu(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_ANY), true); } return ret; @@ -450,6 +447,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) 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; @@ -462,12 +460,6 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) } dev_dbg(adapter->dev, "EVENT: cause: %#x\n", eventcause); - if (eventcause == EVENT_PS_SLEEP || eventcause == EVENT_PS_AWAKE) { - /* Handle PS_SLEEP/AWAKE events on STA */ - priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); - if (!priv) - priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); - } if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) ret = mwifiex_process_uap_event(priv); @@ -1008,11 +1000,9 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) 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); @@ -1070,12 +1060,8 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) 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); } spin_unlock_irqrestore(&adapter->scan_pending_q_lock, scan_pending_q_flags); @@ -1588,9 +1574,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, 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); - + ether_addr_copy(priv->adapter->perm_addr, hw_spec->permanent_addr); adapter->region_code = le16_to_cpu(hw_spec->region_code); for (i = 0; i < MWIFIEX_MAX_REGION_CODE; i++) diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 2713f7acd35e..1fb329dc6744 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -39,111 +39,6 @@ static char *bss_modes[] = { "P2P_DEVICE", }; -/* 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}, - {"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}, - {"is_cmd_timedout", item_size(is_cmd_timedout), - item_addr(is_cmd_timedout), 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); - /* * Proc info file read handler. * @@ -297,6 +192,8 @@ mwifiex_fw_dump_read(struct file *file, char __user *ubuf, * - Number of FCS errors * - Number of Tx frames * - WEP ICV error counts + * - Number of received beacons + * - Number of missed beacons */ static ssize_t mwifiex_getlog_read(struct file *file, char __user *ubuf, @@ -333,7 +230,9 @@ mwifiex_getlog_read(struct file *file, char __user *ubuf, "wepicverrcnt-1 %u\n" "wepicverrcnt-2 %u\n" "wepicverrcnt-3 %u\n" - "wepicverrcnt-4 %u\n", + "wepicverrcnt-4 %u\n" + "bcn_rcv_cnt %u\n" + "bcn_miss_cnt %u\n", stats.mcast_tx_frame, stats.failed, stats.retry, @@ -349,7 +248,9 @@ mwifiex_getlog_read(struct file *file, char __user *ubuf, stats.wep_icv_error[0], stats.wep_icv_error[1], stats.wep_icv_error[2], - stats.wep_icv_error[3]); + stats.wep_icv_error[3], + stats.bcn_rcv_cnt, + stats.bcn_miss_cnt); ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, @@ -360,6 +261,103 @@ free_and_exit: return ret; } +/* Sysfs histogram file read handler. + * + * This function is called when the 'histogram' file is opened for reading + * It prints the following histogram information - + * - Number of histogram samples + * - Receive packet number of each rx_rate + * - Receive packet number of each snr + * - Receive packet number of each nosie_flr + * - Receive packet number of each signal streath + */ +static ssize_t +mwifiex_histogram_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *)file->private_data; + ssize_t ret; + struct mwifiex_histogram_data *phist_data; + int i, value; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *)page; + + if (!p) + return -ENOMEM; + + if (!priv || !priv->hist_data) + return -EFAULT; + phist_data = priv->hist_data; + + p += sprintf(p, "\n" + "total samples = %d\n", + atomic_read(&phist_data->num_samples)); + + p += sprintf(p, "rx rates (in Mbps): 0=1M 1=2M"); + p += sprintf(p, "2=5.5M 3=11M 4=6M 5=9M 6=12M\n"); + p += sprintf(p, "7=18M 8=24M 9=36M 10=48M 11=54M"); + p += sprintf(p, "12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n"); + + if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { + p += sprintf(p, "44-53=MCS0-9(VHT:BW20)"); + p += sprintf(p, "54-63=MCS0-9(VHT:BW40)"); + p += sprintf(p, "64-73=MCS0-9(VHT:BW80)\n\n"); + } else { + p += sprintf(p, "\n"); + } + + for (i = 0; i < MWIFIEX_MAX_RX_RATES; i++) { + value = atomic_read(&phist_data->rx_rate[i]); + if (value) + p += sprintf(p, "rx_rate[%02d] = %d\n", i, value); + } + + if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { + for (i = MWIFIEX_MAX_RX_RATES; i < MWIFIEX_MAX_AC_RX_RATES; + i++) { + value = atomic_read(&phist_data->rx_rate[i]); + if (value) + p += sprintf(p, "rx_rate[%02d] = %d\n", + i, value); + } + } + + for (i = 0; i < MWIFIEX_MAX_SNR; i++) { + value = atomic_read(&phist_data->snr[i]); + if (value) + p += sprintf(p, "snr[%02ddB] = %d\n", i, value); + } + for (i = 0; i < MWIFIEX_MAX_NOISE_FLR; i++) { + value = atomic_read(&phist_data->noise_flr[i]); + if (value) + p += sprintf(p, "noise_flr[-%02ddBm] = %d\n", + (int)(i-128), value); + } + for (i = 0; i < MWIFIEX_MAX_SIG_STRENGTH; i++) { + value = atomic_read(&phist_data->sig_str[i]); + if (value) + p += sprintf(p, "sig_strength[-%02ddBm] = %d\n", + i, value); + } + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, + (unsigned long)p - page); + + return ret; +} + +static ssize_t +mwifiex_histogram_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = (void *)file->private_data; + + if (priv && priv->hist_data) + mwifiex_hist_data_reset(priv); + return 0; +} + static struct mwifiex_debug_info info; /* @@ -415,13 +413,9 @@ mwifiex_debug_read(struct file *file, char __user *ubuf, { 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; @@ -430,68 +424,7 @@ mwifiex_debug_read(struct file *file, char __user *ubuf, 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 = %pM\n", - info.tx_tbl[i].tid, info.tx_tbl[i].ra); - } - - 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 = %pM, " - "start_win = %d, " - "win_size = %d, buffer: ", - info.rx_tbl[i].tid, - info.rx_tbl[i].ta, - 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"); - } - } + p += mwifiex_debug_info_to_buffer(priv, p, &info); ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, (unsigned long) p - page); @@ -817,6 +750,7 @@ MWIFIEX_DFS_FILE_READ_OPS(fw_dump); MWIFIEX_DFS_FILE_OPS(regrdwr); MWIFIEX_DFS_FILE_OPS(rdeeprom); MWIFIEX_DFS_FILE_OPS(hscfg); +MWIFIEX_DFS_FILE_OPS(histogram); /* * This function creates the debug FS directory structure and the files. @@ -840,6 +774,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv) MWIFIEX_DFS_ADD_FILE(rdeeprom); MWIFIEX_DFS_ADD_FILE(fw_dump); MWIFIEX_DFS_ADD_FILE(hscfg); + MWIFIEX_DFS_ADD_FILE(histogram); } /* diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 2269acf41ad8..88d0eade6bb1 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -32,15 +32,19 @@ #define MWIFIEX_MAX_BSS_NUM (3) -#define MWIFIEX_MIN_DATA_HEADER_LEN 36 /* sizeof(mwifiex_txpd) - * + 4 byte alignment - */ +#define MWIFIEX_DMA_ALIGN_SZ 64 +#define MAX_TXPD_SZ 32 +#define INTF_HDR_ALIGN 4 + +#define MWIFIEX_MIN_DATA_HEADER_LEN (MWIFIEX_DMA_ALIGN_SZ + INTF_HDR_ALIGN + \ + MAX_TXPD_SZ) #define MWIFIEX_MGMT_FRAME_HEADER_SIZE 8 /* sizeof(pkt_type) * + sizeof(tx_control) */ #define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2 #define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16 +#define MWIFIEX_MAX_TDLS_PEER_SUPPORTED 8 #define MWIFIEX_STA_AMPDU_DEF_TXWINSIZE 64 #define MWIFIEX_STA_AMPDU_DEF_RXWINSIZE 64 @@ -92,6 +96,20 @@ #define MWIFIEX_TDLS_MAX_FAIL_COUNT 4 #define MWIFIEX_AUTO_TDLS_IDLE_TIME 10 +/* 54M rates, index from 0 to 11 */ +#define MWIFIEX_RATE_INDEX_MCS0 12 +/* 12-27=MCS0-15(BW20) */ +#define MWIFIEX_BW20_MCS_NUM 15 + +/* Rate index for OFDM 0 */ +#define MWIFIEX_RATE_INDEX_OFDM0 4 + +#define MWIFIEX_MAX_STA_NUM 1 +#define MWIFIEX_MAX_UAP_NUM 1 +#define MWIFIEX_MAX_P2P_NUM 1 + +#define MWIFIEX_A_BAND_START_FREQ 5000 + enum mwifiex_bss_type { MWIFIEX_BSS_TYPE_STA = 0, MWIFIEX_BSS_TYPE_UAP = 1, @@ -204,4 +222,35 @@ struct mwifiex_chan_stats { u16 cca_scan_dur; u16 cca_busy_dur; } __packed; + +#define MWIFIEX_HIST_MAX_SAMPLES 1048576 +#define MWIFIEX_MAX_RX_RATES 44 +#define MWIFIEX_MAX_AC_RX_RATES 74 +#define MWIFIEX_MAX_SNR 256 +#define MWIFIEX_MAX_NOISE_FLR 256 +#define MWIFIEX_MAX_SIG_STRENGTH 256 + +struct mwifiex_histogram_data { + atomic_t rx_rate[MWIFIEX_MAX_AC_RX_RATES]; + atomic_t snr[MWIFIEX_MAX_SNR]; + atomic_t noise_flr[MWIFIEX_MAX_NOISE_FLR]; + atomic_t sig_str[MWIFIEX_MAX_SIG_STRENGTH]; + atomic_t num_samples; +}; + +struct mwifiex_iface_comb { + u8 sta_intf; + u8 uap_intf; + u8 p2p_intf; +}; + +struct mwifiex_radar_params { + struct cfg80211_chan_def *chandef; + u32 cac_time_ms; +} __packed; + +struct mwifiex_11h_intf_state { + bool is_11h_enabled; + bool is_11h_active; +} __packed; #endif /* !_MWIFIEX_DECL_H_ */ diff --git a/drivers/net/wireless/mwifiex/ethtool.c b/drivers/net/wireless/mwifiex/ethtool.c index 04e56b5fc535..65d8d6d4b6ba 100644 --- a/drivers/net/wireless/mwifiex/ethtool.c +++ b/drivers/net/wireless/mwifiex/ethtool.c @@ -76,7 +76,9 @@ mwifiex_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump) dump->flag = adapter->curr_mem_idx; dump->version = 1; - if (adapter->curr_mem_idx != MWIFIEX_FW_DUMP_IDX) { + if (adapter->curr_mem_idx == MWIFIEX_DRV_INFO_IDX) { + dump->len = adapter->drv_info_size; + } else if (adapter->curr_mem_idx != MWIFIEX_FW_DUMP_IDX) { entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx]; dump->len = entry->mem_size; } else { @@ -98,6 +100,13 @@ mwifiex_get_dump_data(struct net_device *dev, struct ethtool_dump *dump, if (!adapter->if_ops.fw_dump) return -ENOTSUPP; + if (adapter->curr_mem_idx == MWIFIEX_DRV_INFO_IDX) { + if (!adapter->drv_info_dump) + return -EFAULT; + memcpy(p, adapter->drv_info_dump, adapter->drv_info_size); + return 0; + } + if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) { dev_err(adapter->dev, "firmware dump in progress!!\n"); return -EBUSY; @@ -125,6 +134,11 @@ static int mwifiex_set_dump(struct net_device *dev, struct ethtool_dump *val) if (!adapter->if_ops.fw_dump) return -ENOTSUPP; + if (val->flag == MWIFIEX_DRV_INFO_IDX) { + adapter->curr_mem_idx = MWIFIEX_DRV_INFO_IDX; + return 0; + } + if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) { dev_err(adapter->dev, "firmware dump in progress!!\n"); return -EBUSY; diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index fb5936eb82e3..df553e86a0ad 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -158,6 +158,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84) #define TLV_TYPE_BSS_SCAN_RSP (PROPRIETARY_TLV_BASE_ID + 86) #define TLV_TYPE_BSS_SCAN_INFO (PROPRIETARY_TLV_BASE_ID + 87) +#define TLV_TYPE_CHANRPT_11H_BASIC (PROPRIETARY_TLV_BASE_ID + 91) #define TLV_TYPE_UAP_RETRY_LIMIT (PROPRIETARY_TLV_BASE_ID + 93) #define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94) #define TLV_TYPE_UAP_MGMT_FRAME (PROPRIETARY_TLV_BASE_ID + 104) @@ -233,6 +234,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & BIT(22)) #define ISSUPP_BEAMFORMING(Dot11nDevCap) (Dot11nDevCap & BIT(30)) #define ISALLOWED_CHANWIDTH40(ht_param) (ht_param & BIT(2)) +#define GETSUPP_TXBASTREAMS(Dot11nDevCap) ((Dot11nDevCap >> 18) & 0xF) /* httxcfg bitmap * 0 reserved @@ -335,6 +337,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_11N_ADDBA_RSP 0x00cf #define HostCmd_CMD_11N_DELBA 0x00d0 #define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9 +#define HostCmd_CMD_CHAN_REPORT_REQUEST 0x00dd #define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df #define HostCmd_CMD_TXPWR_CFG 0x00d1 #define HostCmd_CMD_TX_RATE_CFG 0x00d6 @@ -492,6 +495,8 @@ enum P2P_MODES { #define EVENT_HOSTWAKE_STAIE 0x0000004d #define EVENT_CHANNEL_SWITCH_ANN 0x00000050 #define EVENT_TDLS_GENERIC_EVENT 0x00000052 +#define EVENT_RADAR_DETECTED 0x00000053 +#define EVENT_CHANNEL_REPORT_RDY 0x00000054 #define EVENT_EXT_SCAN_REPORT 0x00000058 #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f #define EVENT_TX_STATUS_REPORT 0x00000074 @@ -529,6 +534,8 @@ enum P2P_MODES { #define MWIFIEX_FW_V15 15 +#define MWIFIEX_MASTER_RADAR_DET_MASK BIT(1) + struct mwifiex_ie_types_header { __le16 type; __le16 len; @@ -1076,6 +1083,8 @@ struct host_cmd_ds_802_11_get_log { __le32 tx_frame; __le32 reserved; __le32 wep_icv_err_cnt[4]; + __le32 bcn_rcv_cnt; + __le32 bcn_miss_cnt; }; /* Enumeration for rate format */ @@ -1213,6 +1222,24 @@ struct host_cmd_ds_tdls_oper { u8 peer_mac[ETH_ALEN]; } __packed; +struct mwifiex_chan_desc { + __le16 start_freq; + u8 chan_width; + u8 chan_num; +} __packed; + +struct host_cmd_ds_chan_rpt_req { + struct mwifiex_chan_desc chan_desc; + __le32 msec_dwell_time; +} __packed; + +struct host_cmd_ds_chan_rpt_event { + __le32 result; + __le64 start_tsf; + __le32 duration; + u8 tlvbuf[0]; +} __packed; + struct mwifiex_fixed_bcn_param { __le64 timestamp; __le16 beacon_period; @@ -1789,6 +1816,39 @@ struct mwifiex_ie_types_rssi_threshold { u8 evt_freq; } __packed; +#define MWIFIEX_DFS_REC_HDR_LEN 8 +#define MWIFIEX_DFS_REC_HDR_NUM 10 +#define MWIFIEX_BIN_COUNTER_LEN 7 + +struct mwifiex_radar_det_event { + __le32 detect_count; + u8 reg_domain; /*1=fcc, 2=etsi, 3=mic*/ + u8 det_type; /*0=none, 1=pw(chirp), 2=pri(radar)*/ + __le16 pw_chirp_type; + u8 pw_chirp_idx; + u8 pw_value; + u8 pri_radar_type; + u8 pri_bincnt; + u8 bin_counter[MWIFIEX_BIN_COUNTER_LEN]; + u8 num_dfs_records; + u8 dfs_record_hdr[MWIFIEX_DFS_REC_HDR_NUM][MWIFIEX_DFS_REC_HDR_LEN]; + __le32 passed; +} __packed; + +struct meas_rpt_map { + u8 rssi:3; + u8 unmeasured:1; + u8 radar:1; + u8 unidentified_sig:1; + u8 ofdm_preamble:1; + u8 bss:1; +} __packed; + +struct mwifiex_ie_types_chan_rpt_data { + struct mwifiex_ie_types_header header; + struct meas_rpt_map map; +} __packed; + struct host_cmd_ds_802_11_subsc_evt { __le16 action; __le16 events; @@ -1901,6 +1961,7 @@ struct host_cmd_ds_command { struct host_cmd_11ac_vht_cfg vht_cfg; struct host_cmd_ds_coalesce_cfg coalesce_cfg; struct host_cmd_ds_tdls_oper tdls_oper; + struct host_cmd_ds_chan_rpt_req chan_rpt_req; } params; } __packed; diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index b933794758b7..f3b6ed249403 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -317,27 +317,27 @@ done: return ret; } -/* This function parses different IEs-tail IEs, beacon IEs, probe response IEs, - * association response IEs from cfg80211_ap_settings function and sets these IE - * to FW. +/* This function parses head and tail IEs, from cfg80211_beacon_data and sets + * these IE to FW. */ -int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, - struct cfg80211_beacon_data *info) +static int mwifiex_uap_set_head_tail_ies(struct mwifiex_private *priv, + struct cfg80211_beacon_data *info) { struct mwifiex_ie *gen_ie; - struct ieee_types_header *rsn_ie, *wpa_ie = NULL; - u16 rsn_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0; + struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL; + struct ieee_types_header *chsw_ie = NULL; + u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0; const u8 *vendor_ie; - if (info->tail && info->tail_len) { - gen_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); - if (!gen_ie) - return -ENOMEM; - gen_ie->ie_index = cpu_to_le16(rsn_idx); - gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON | - MGMT_MASK_PROBE_RESP | - MGMT_MASK_ASSOC_RESP); + gen_ie = kzalloc(sizeof(*gen_ie), GFP_KERNEL); + if (!gen_ie) + return -ENOMEM; + gen_ie->ie_index = cpu_to_le16(gen_idx); + gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON | + MGMT_MASK_PROBE_RESP | + MGMT_MASK_ASSOC_RESP); + if (info->tail && info->tail_len) { rsn_ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, info->tail, info->tail_len); if (rsn_ie) { @@ -358,19 +358,41 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, gen_ie->ie_length = cpu_to_le16(ie_len); } - if (rsn_ie || wpa_ie) { - if (mwifiex_update_uap_custom_ie(priv, gen_ie, &rsn_idx, - NULL, NULL, - NULL, NULL)) { - kfree(gen_ie); - return -1; - } - priv->rsn_idx = rsn_idx; + chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH, + info->tail, info->tail_len); + if (chsw_ie) { + memcpy(gen_ie->ie_buffer + ie_len, + chsw_ie, chsw_ie->len + 2); + ie_len += chsw_ie->len + 2; + gen_ie->ie_length = cpu_to_le16(ie_len); } - - kfree(gen_ie); } + if (rsn_ie || wpa_ie || chsw_ie) { + if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, + NULL, NULL, NULL)) { + kfree(gen_ie); + return -1; + } + priv->gen_idx = gen_idx; + } + + kfree(gen_ie); + return 0; +} + +/* This function parses different IEs-head & tail IEs, beacon IEs, + * probe response IEs, association response IEs from cfg80211_ap_settings + * function and sets these IE to FW. + */ +int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, + struct cfg80211_beacon_data *info) +{ + int ret; + + ret = mwifiex_uap_set_head_tail_ies(priv, info); + return ret; + return mwifiex_set_mgmt_beacon_data_ies(priv, info); } @@ -378,25 +400,25 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, int mwifiex_del_mgmt_ies(struct mwifiex_private *priv) { struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL; - struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL; + struct mwifiex_ie *ar_ie = NULL, *gen_ie = NULL; int ret = 0; - if (priv->rsn_idx != MWIFIEX_AUTO_IDX_MASK) { - rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); - if (!rsn_ie) + if (priv->gen_idx != MWIFIEX_AUTO_IDX_MASK) { + gen_ie = kmalloc(sizeof(*gen_ie), GFP_KERNEL); + if (!gen_ie) return -ENOMEM; - rsn_ie->ie_index = cpu_to_le16(priv->rsn_idx); - rsn_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK); - rsn_ie->ie_length = 0; - if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &priv->rsn_idx, + gen_ie->ie_index = cpu_to_le16(priv->gen_idx); + gen_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK); + gen_ie->ie_length = 0; + if (mwifiex_update_uap_custom_ie(priv, gen_ie, &priv->gen_idx, NULL, &priv->proberesp_idx, NULL, &priv->assocresp_idx)) { ret = -1; goto done; } - priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK; + priv->gen_idx = MWIFIEX_AUTO_IDX_MASK; } if (priv->beacon_idx != MWIFIEX_AUTO_IDX_MASK) { @@ -440,7 +462,6 @@ done: kfree(beacon_ie); kfree(pr_ie); kfree(ar_ie); - kfree(rsn_ie); return ret; } diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 520ad4a3018b..b77ba743e1c4 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -52,6 +52,18 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv) return 0; } +static void wakeup_timer_fn(unsigned long data) +{ + struct mwifiex_adapter *adapter = (struct mwifiex_adapter *)data; + + dev_err(adapter->dev, "Firmware wakeup failed\n"); + adapter->hw_status = MWIFIEX_HW_STATUS_RESET; + mwifiex_cancel_all_pending_cmd(adapter); + + if (adapter->if_ops.card_reset) + adapter->if_ops.card_reset(adapter); +} + /* * This function initializes the private structure and sets default * values to the members. @@ -140,6 +152,8 @@ int mwifiex_init_priv(struct mwifiex_private *priv) priv->check_tdls_tx = false; memcpy(priv->tos_to_tid_inv, tos_to_tid_inv, MAX_NUM_TID); + mwifiex_init_11h_params(priv); + return mwifiex_add_bss_prio_tbl(priv); } @@ -282,9 +296,16 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); adapter->arp_filter_size = 0; adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX; - adapter->ext_scan = true; + adapter->ext_scan = false; adapter->key_api_major_ver = 0; adapter->key_api_minor_ver = 0; + memset(adapter->perm_addr, 0xff, ETH_ALEN); + adapter->iface_limit.sta_intf = MWIFIEX_MAX_STA_NUM; + adapter->iface_limit.uap_intf = MWIFIEX_MAX_UAP_NUM; + adapter->iface_limit.p2p_intf = MWIFIEX_MAX_P2P_NUM; + + setup_timer(&adapter->wakeup_timer, wakeup_timer_fn, + (unsigned long)adapter); } /* @@ -391,7 +412,10 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) return; } + del_timer(&adapter->wakeup_timer); mwifiex_cancel_all_pending_cmd(adapter); + wake_up_interruptible(&adapter->cmd_wait_q.wait); + wake_up_interruptible(&adapter->hs_activate_wait_q); /* Free lock variables */ mwifiex_free_lock_list(adapter); @@ -411,6 +435,11 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) entry->mem_size = 0; } + if (adapter->drv_info_dump) { + vfree(adapter->drv_info_dump); + adapter->drv_info_size = 0; + } + if (adapter->sleep_cfm) dev_kfree_skb_any(adapter->sleep_cfm); } @@ -528,7 +557,8 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter) for (i = 0; i < adapter->priv_num; i++) { if (adapter->priv[i]) { - ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta); + ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta, + true); if (ret == -1) return -1; @@ -653,6 +683,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) priv = adapter->priv[i]; mwifiex_clean_auto_tdls(priv); + mwifiex_abort_cac(priv); mwifiex_clean_txrx(priv); mwifiex_delete_bss_prio_tbl(priv); } diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 0847f3e07ab7..d2b05c3a96da 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -137,6 +137,8 @@ struct mwifiex_ds_get_stats { u32 fcs_error; u32 tx_frame; u32 wep_icv_error[4]; + u32 bcn_rcv_cnt; + u32 bcn_miss_cnt; }; #define MWIFIEX_MAX_VER_STR_LEN 128 @@ -180,7 +182,11 @@ struct mwifiex_ds_tx_ba_stream_tbl { u8 amsdu; }; -#define DBG_CMD_NUM 5 +#define DBG_CMD_NUM 5 + +struct tdls_peer_info { + u8 peer_addr[ETH_ALEN]; +}; struct mwifiex_debug_info { u32 int_counter; @@ -193,6 +199,9 @@ struct mwifiex_debug_info { u32 rx_tbl_num; struct mwifiex_ds_rx_reorder_tbl rx_tbl [MWIFIEX_MAX_RX_BASTREAM_SUPPORTED]; + u32 tdls_peer_num; + struct tdls_peer_info tdls_list + [MWIFIEX_MAX_TDLS_PEER_SUPPORTED]; u16 ps_mode; u32 ps_state; u8 is_deep_sleep; diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index d4d2223d1f31..7e74b4fccddd 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -83,9 +83,8 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, } mwifiex_init_lock_list(adapter); - init_timer(&adapter->cmd_timer); - adapter->cmd_timer.function = mwifiex_cmd_timeout_func; - adapter->cmd_timer.data = (unsigned long) adapter; + setup_timer(&adapter->cmd_timer, mwifiex_cmd_timeout_func, + (unsigned long)adapter); return 0; @@ -237,6 +236,7 @@ process_start: (is_command_pending(adapter) || !mwifiex_wmm_lists_empty(adapter))) { adapter->pm_wakeup_fw_try = true; + mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3)); adapter->if_ops.wakeup(adapter); continue; } @@ -244,6 +244,7 @@ process_start: if (IS_CARD_RX_RCVD(adapter)) { adapter->data_received = false; adapter->pm_wakeup_fw_try = false; + del_timer_sync(&adapter->wakeup_timer); if (adapter->ps_state == PS_STATE_SLEEP) adapter->ps_state = PS_STATE_AWAKE; } else { @@ -511,8 +512,7 @@ err_dnld_fw: if (adapter->if_ops.unregister_dev) adapter->if_ops.unregister_dev(adapter); - if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || - (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { + if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) { pr_debug("info: %s: shutdown mwifiex\n", __func__); adapter->init_wait_q_woken = false; @@ -562,7 +562,8 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) static int mwifiex_open(struct net_device *dev) { - netif_tx_start_all_queues(dev); + netif_carrier_off(dev); + return 0; } @@ -801,6 +802,114 @@ mwifiex_tx_timeout(struct net_device *dev) } } +void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter) +{ + void *p; + char drv_version[64]; + struct usb_card_rec *cardp; + struct sdio_mmc_card *sdio_card; + struct mwifiex_private *priv; + int i, idx; + struct netdev_queue *txq; + struct mwifiex_debug_info *debug_info; + + if (adapter->drv_info_dump) { + vfree(adapter->drv_info_dump); + adapter->drv_info_size = 0; + } + + dev_info(adapter->dev, "=== DRIVER INFO DUMP START===\n"); + + adapter->drv_info_dump = vzalloc(MWIFIEX_DRV_INFO_SIZE_MAX); + + if (!adapter->drv_info_dump) + return; + + p = (char *)(adapter->drv_info_dump); + p += sprintf(p, "driver_name = " "\"mwifiex\"\n"); + + mwifiex_drv_get_driver_version(adapter, drv_version, + sizeof(drv_version) - 1); + p += sprintf(p, "driver_version = %s\n", drv_version); + + if (adapter->iface_type == MWIFIEX_USB) { + cardp = (struct usb_card_rec *)adapter->card; + p += sprintf(p, "tx_cmd_urb_pending = %d\n", + atomic_read(&cardp->tx_cmd_urb_pending)); + p += sprintf(p, "tx_data_urb_pending = %d\n", + atomic_read(&cardp->tx_data_urb_pending)); + p += sprintf(p, "rx_cmd_urb_pending = %d\n", + atomic_read(&cardp->rx_cmd_urb_pending)); + p += sprintf(p, "rx_data_urb_pending = %d\n", + atomic_read(&cardp->rx_data_urb_pending)); + } + + p += sprintf(p, "tx_pending = %d\n", + atomic_read(&adapter->tx_pending)); + p += sprintf(p, "rx_pending = %d\n", + atomic_read(&adapter->rx_pending)); + + if (adapter->iface_type == MWIFIEX_SDIO) { + sdio_card = (struct sdio_mmc_card *)adapter->card; + p += sprintf(p, "\nmp_rd_bitmap=0x%x curr_rd_port=0x%x\n", + sdio_card->mp_rd_bitmap, sdio_card->curr_rd_port); + p += sprintf(p, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n", + sdio_card->mp_wr_bitmap, sdio_card->curr_wr_port); + } + + for (i = 0; i < adapter->priv_num; i++) { + if (!adapter->priv[i] || !adapter->priv[i]->netdev) + continue; + priv = adapter->priv[i]; + p += sprintf(p, "\n[interface : \"%s\"]\n", + priv->netdev->name); + p += sprintf(p, "wmm_tx_pending[0] = %d\n", + atomic_read(&priv->wmm_tx_pending[0])); + p += sprintf(p, "wmm_tx_pending[1] = %d\n", + atomic_read(&priv->wmm_tx_pending[1])); + p += sprintf(p, "wmm_tx_pending[2] = %d\n", + atomic_read(&priv->wmm_tx_pending[2])); + p += sprintf(p, "wmm_tx_pending[3] = %d\n", + atomic_read(&priv->wmm_tx_pending[3])); + p += sprintf(p, "media_state=\"%s\"\n", !priv->media_connected ? + "Disconnected" : "Connected"); + p += sprintf(p, "carrier %s\n", (netif_carrier_ok(priv->netdev) + ? "on" : "off")); + for (idx = 0; idx < priv->netdev->num_tx_queues; idx++) { + txq = netdev_get_tx_queue(priv->netdev, idx); + p += sprintf(p, "tx queue %d:%s ", idx, + netif_tx_queue_stopped(txq) ? + "stopped" : "started"); + } + p += sprintf(p, "\n%s: num_tx_timeout = %d\n", + priv->netdev->name, priv->num_tx_timeout); + } + + if (adapter->iface_type == MWIFIEX_SDIO) { + p += sprintf(p, "\n=== SDIO register DUMP===\n"); + if (adapter->if_ops.reg_dump) + p += adapter->if_ops.reg_dump(adapter, p); + } + + p += sprintf(p, "\n=== MORE DEBUG INFORMATION\n"); + debug_info = kzalloc(sizeof(*debug_info), GFP_KERNEL); + if (debug_info) { + for (i = 0; i < adapter->priv_num; i++) { + if (!adapter->priv[i] || !adapter->priv[i]->netdev) + continue; + priv = adapter->priv[i]; + mwifiex_get_debug_info(priv, debug_info); + p += mwifiex_debug_info_to_buffer(priv, p, debug_info); + break; + } + kfree(debug_info); + } + + adapter->drv_info_size = p - adapter->drv_info_dump; + dev_info(adapter->dev, "=== DRIVER INFO DUMP END===\n"); +} +EXPORT_SYMBOL_GPL(mwifiex_dump_drv_info); + /* * CFG802.11 network device handler for statistics retrieval. */ @@ -847,26 +956,34 @@ static const struct net_device_ops mwifiex_netdev_ops = { * - Nick name : Set to null * - Number of Tx timeout : Set to 0 * - Device address : Set to current address + * - Rx histogram statistc : Set to 0 * * In addition, the CFG80211 work queue is also created. */ void mwifiex_init_priv_params(struct mwifiex_private *priv, - struct net_device *dev) + struct net_device *dev) { dev->netdev_ops = &mwifiex_netdev_ops; dev->destructor = free_netdev; /* Initialize private structure */ priv->current_key_index = 0; priv->media_connected = false; - memset(&priv->nick_name, 0, sizeof(priv->nick_name)); memset(priv->mgmt_ie, 0, sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX); priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK; priv->proberesp_idx = MWIFIEX_AUTO_IDX_MASK; priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK; - priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK; + priv->gen_idx = MWIFIEX_AUTO_IDX_MASK; priv->num_tx_timeout = 0; + ether_addr_copy(priv->curr_addr, priv->adapter->perm_addr); memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); + + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || + GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { + priv->hist_data = kmalloc(sizeof(*priv->hist_data), GFP_KERNEL); + if (priv->hist_data) + mwifiex_hist_data_reset(priv); + } } /* @@ -1000,8 +1117,7 @@ err_init_fw: pr_debug("info: %s: unregister device\n", __func__); if (adapter->if_ops.unregister_dev) adapter->if_ops.unregister_dev(adapter); - if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || - (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { + if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) { pr_debug("info: %s: shutdown mwifiex\n", __func__); adapter->init_wait_q_woken = false; @@ -1052,6 +1168,8 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) adapter->surprise_removed = true; + mwifiex_terminate_workqueue(adapter); + /* Stop data */ for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; @@ -1086,16 +1204,15 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) continue; rtnl_lock(); - if (priv->wdev && priv->netdev) - mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev); + if (priv->netdev && + priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED) + mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev); rtnl_unlock(); } wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); - mwifiex_terminate_workqueue(adapter); - /* Unregister device */ dev_dbg(adapter->dev, "info: unregister device\n"); if (adapter->if_ops.unregister_dev) diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index e66993cb5daf..f0a6af179af0 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -41,6 +41,8 @@ #include "util.h" #include "fw.h" #include "pcie.h" +#include "usb.h" +#include "sdio.h" extern const char driver_version[]; @@ -136,6 +138,8 @@ enum { /* Threshold for tx_timeout_cnt before we trigger a card reset */ #define TX_TIMEOUT_THRESHOLD 6 +#define MWIFIEX_DRV_INFO_SIZE_MAX 0x40000 + struct mwifiex_dbg { u32 num_cmd_host_to_card_failure; u32 num_cmd_sleep_cfm_host_to_card_failure; @@ -161,7 +165,6 @@ struct mwifiex_dbg { 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, @@ -413,6 +416,7 @@ struct mwifiex_roc_cfg { }; #define MWIFIEX_FW_DUMP_IDX 0xff +#define MWIFIEX_DRV_INFO_IDX 20 #define FW_DUMP_MAX_NAME_LEN 8 #define FW_DUMP_HOST_READY 0xEE #define FW_DUMP_DONE 0xFF @@ -543,13 +547,12 @@ struct mwifiex_private { u32 curr_bcn_size; /* spin lock for beacon buffer */ spinlock_t curr_bcn_buf_lock; - struct wireless_dev *wdev; + 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]; u16 current_key_index; struct semaphore async_sem; struct cfg80211_scan_request *scan_request; @@ -564,7 +567,7 @@ struct mwifiex_private { u16 beacon_idx; u16 proberesp_idx; u16 assocresp_idx; - u16 rsn_idx; + u16 gen_idx; u8 ap_11n_enabled; u8 ap_11ac_enabled; u32 mgmt_frame_mask; @@ -574,6 +577,7 @@ struct mwifiex_private { unsigned long csa_expire_time; u8 del_list_idx; bool hs2_enabled; + struct mwifiex_uap_bss_param bss_cfg; struct station_parameters *sta_params; struct sk_buff_head tdls_txq; u8 check_tdls_tx; @@ -582,6 +586,16 @@ struct mwifiex_private { struct idr ack_status_frames; /* spin lock for ack status */ spinlock_t ack_status_lock; + /** rx histogram data */ + struct mwifiex_histogram_data *hist_data; + struct cfg80211_chan_def dfs_chandef; + struct workqueue_struct *dfs_cac_workqueue; + struct delayed_work dfs_cac_work; + struct timer_list dfs_chan_switch_timer; + struct workqueue_struct *dfs_chan_sw_workqueue; + struct delayed_work dfs_chan_sw_work; + struct cfg80211_beacon_data beacon_after; + struct mwifiex_11h_intf_state state_11h; }; enum mwifiex_ba_status { @@ -717,6 +731,7 @@ struct mwifiex_if_ops { int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); void (*card_reset) (struct mwifiex_adapter *); void (*fw_dump)(struct mwifiex_adapter *); + int (*reg_dump)(struct mwifiex_adapter *, char *); int (*clean_pcie_ring) (struct mwifiex_adapter *adapter); void (*iface_work)(struct work_struct *work); void (*submit_rem_rx_urbs)(struct mwifiex_adapter *adapter); @@ -724,6 +739,8 @@ struct mwifiex_if_ops { struct mwifiex_adapter { u8 iface_type; + struct mwifiex_iface_comb iface_limit; + struct mwifiex_iface_comb curr_iface_comb; struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM]; u8 priv_num; const struct firmware *firmware; @@ -731,6 +748,7 @@ struct mwifiex_adapter { int winner; struct device *dev; struct wiphy *wiphy; + u8 perm_addr[ETH_ALEN]; bool surprise_removed; u32 fw_release_number; u16 init_wait_q_woken; @@ -744,6 +762,8 @@ struct mwifiex_adapter { struct work_struct main_work; struct workqueue_struct *rx_workqueue; struct work_struct rx_work; + struct workqueue_struct *dfs_workqueue; + struct work_struct dfs_work; bool rx_work_enabled; bool rx_processing; bool delay_main_work; @@ -823,6 +843,7 @@ struct mwifiex_adapter { u16 gen_null_pkt; u16 pps_uapsd_mode; u32 pm_wakeup_fw_try; + struct timer_list wakeup_timer; u8 is_hs_configured; struct mwifiex_hs_config_param hs_cfg; u8 hs_activated; @@ -865,6 +886,8 @@ struct mwifiex_adapter { struct memory_type_mapping *mem_type_mapping_tbl; u8 num_mem_types; u8 curr_mem_idx; + void *drv_info_dump; + u32 drv_info_size; bool scan_chan_gap_enabled; struct sk_buff_head rx_data_q; struct mwifiex_chan_stats *chan_stats; @@ -979,7 +1002,7 @@ void mwifiex_wmm_del_peer_ra_list(struct mwifiex_private *priv, const u8 *ra_addr); void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb); void *mwifiex_process_uap_txpd(struct mwifiex_private *, struct sk_buff *skb); -int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta); +int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta, bool init); int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, struct mwifiex_scan_cmd_config *scan_cfg); void mwifiex_queue_scan_cmd(struct mwifiex_private *priv, @@ -1139,6 +1162,25 @@ mwifiex_get_priv(struct mwifiex_adapter *adapter, return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); } +/* + * This function returns the first available unused private structure pointer. + */ +static inline struct mwifiex_private * +mwifiex_get_unused_priv(struct mwifiex_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + if (adapter->priv[i]->bss_mode == + NL80211_IFTYPE_UNSPECIFIED) + break; + } + } + + return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); +} + /* * This function returns the driver private structure of a network device. */ @@ -1230,8 +1272,6 @@ int mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action, struct ieee80211_channel *chan, unsigned int duration); -int mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role); - int mwifiex_get_stats_info(struct mwifiex_private *priv, struct mwifiex_ds_get_stats *log); @@ -1291,9 +1331,17 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, struct cfg80211_beacon_data *data); int mwifiex_del_mgmt_ies(struct mwifiex_private *priv); u8 *mwifiex_11d_code_2_region(u8 code); +void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg, + struct cfg80211_chan_def chandef); +int mwifiex_config_start_uap(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_cfg); void mwifiex_uap_del_sta_data(struct mwifiex_private *priv, struct mwifiex_sta_node *node); +void mwifiex_init_11h_params(struct mwifiex_private *priv); +int mwifiex_is_11h_active(struct mwifiex_private *priv); +int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag); + void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer, struct mwifiex_bssdescriptor *bss_desc); int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv); @@ -1324,6 +1372,8 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, u8 *buf, int len); int mwifiex_tdls_oper(struct mwifiex_private *priv, const u8 *peer, u8 action); int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, const u8 *mac); +int mwifiex_get_tdls_list(struct mwifiex_private *priv, + struct tdls_peer_info *buf); void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv); bool mwifiex_is_bss_in_11ac_mode(struct mwifiex_private *priv); u8 mwifiex_get_center_freq_index(struct mwifiex_private *priv, u8 band, @@ -1340,6 +1390,11 @@ void mwifiex_check_auto_tdls(unsigned long context); void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac); void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv); void mwifiex_clean_auto_tdls(struct mwifiex_private *priv); +int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv, + struct sk_buff *skb); void mwifiex_parse_tx_status_event(struct mwifiex_private *priv, void *event_body); @@ -1347,6 +1402,21 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv, struct sk_buff * mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv, struct sk_buff *skb, u8 flag, u64 *cookie); +void mwifiex_dfs_cac_work_queue(struct work_struct *work); +void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work); +void mwifiex_abort_cac(struct mwifiex_private *priv); +int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv, + struct sk_buff *skb); + +void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr, + s8 nflr); +void mwifiex_hist_data_reset(struct mwifiex_private *priv); +void mwifiex_hist_data_add(struct mwifiex_private *priv, + u8 rx_rate, s8 snr, s8 nflr); +u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv, + u8 rx_rate, u8 ht_info); + +void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index c3a20f94f3c9..a5828da59365 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -204,6 +204,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, card->pcie.blksz_fw_dl = data->blksz_fw_dl; card->pcie.tx_buf_size = data->tx_buf_size; card->pcie.supports_fw_dump = data->supports_fw_dump; + card->pcie.can_ext_scan = data->can_ext_scan; } if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops, @@ -1952,8 +1953,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, offset += txlen; } while (true); - dev_dbg(adapter->dev, "info:\nFW download over, size %d bytes\n", - offset); + dev_notice(adapter->dev, + "info: FW download over, size %d bytes\n", offset); ret = 0; @@ -2064,6 +2065,7 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) * state until cookie is set */ adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_fw_try = false; + del_timer(&adapter->wakeup_timer); } } } @@ -2562,6 +2564,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) adapter->mem_type_mapping_tbl = mem_type_mapping_tbl; adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); strcpy(adapter->fw_name, card->pcie.firmware); + adapter->ext_scan = card->pcie.can_ext_scan; return 0; } diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h index 200e8b0cb582..666d40e9dbc3 100644 --- a/drivers/net/wireless/mwifiex/pcie.h +++ b/drivers/net/wireless/mwifiex/pcie.h @@ -206,6 +206,7 @@ struct mwifiex_pcie_device { u16 blksz_fw_dl; u16 tx_buf_size; bool supports_fw_dump; + bool can_ext_scan; }; static const struct mwifiex_pcie_device mwifiex_pcie8766 = { @@ -214,6 +215,7 @@ static const struct mwifiex_pcie_device mwifiex_pcie8766 = { .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, .supports_fw_dump = false, + .can_ext_scan = true, }; static const struct mwifiex_pcie_device mwifiex_pcie8897 = { @@ -222,6 +224,7 @@ static const struct mwifiex_pcie_device mwifiex_pcie8897 = { .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, .supports_fw_dump = true, + .can_ext_scan = true, }; struct mwifiex_evt_buf_desc { diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 984a7a4fa93b..0ffdb7c5afd2 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -496,10 +496,10 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) { - if (!priv->wdev->wiphy->bands[band]) + if (!priv->wdev.wiphy->bands[band]) continue; - sband = priv->wdev->wiphy->bands[band]; + sband = priv->wdev.wiphy->bands[band]; for (i = 0; (i < sband->n_channels) ; i++) { ch = &sband->channels[i]; @@ -1429,6 +1429,12 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, return -EBUSY; } + if (adapter->surprise_removed || adapter->is_cmd_timedout) { + dev_err(adapter->dev, + "Ignore scan. Card removed or firmware in bad state\n"); + return -EFAULT; + } + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); adapter->scan_processing = true; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); @@ -1727,10 +1733,10 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info, freq = cfp ? cfp->freq : 0; - chan = ieee80211_get_channel(priv->wdev->wiphy, freq); + chan = ieee80211_get_channel(priv->wdev.wiphy, freq); if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { - bss = cfg80211_inform_bss(priv->wdev->wiphy, + bss = cfg80211_inform_bss(priv->wdev.wiphy, chan, CFG80211_BSS_FTYPE_UNKNOWN, bssid, timestamp, cap_info_bitmap, beacon_period, @@ -1742,7 +1748,7 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info, !memcmp(bssid, priv->curr_bss_params.bss_descriptor .mac_address, ETH_ALEN)) mwifiex_update_curr_bss_params(priv, bss); - cfg80211_put_bss(priv->wdev->wiphy, bss); + cfg80211_put_bss(priv->wdev.wiphy, bss); } } else { dev_dbg(adapter->dev, "missing BSS channel IE\n"); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 933dae137850..91e36cda9543 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -107,6 +107,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size; card->supports_fw_dump = data->supports_fw_dump; card->auto_tdls = data->auto_tdls; + card->can_ext_scan = data->can_ext_scan; } sdio_claim_host(func); @@ -282,6 +283,9 @@ static int mwifiex_sdio_suspend(struct device *dev) #define SDIO_DEVICE_ID_MARVELL_8897 (0x912d) /* Device ID for SD8887 */ #define SDIO_DEVICE_ID_MARVELL_8887 (0x9135) +/* Device ID for SD8801 */ +#define SDIO_DEVICE_ID_MARVELL_8801 (0x9139) + /* WLAN IDs */ static const struct sdio_device_id mwifiex_ids[] = { @@ -295,6 +299,8 @@ static const struct sdio_device_id mwifiex_ids[] = { .driver_data = (unsigned long) &mwifiex_sdio_sd8897}, {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887), .driver_data = (unsigned long)&mwifiex_sdio_sd8887}, + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8801), + .driver_data = (unsigned long)&mwifiex_sdio_sd8801}, {}, }; @@ -986,8 +992,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, offset += txlen; } while (true); - dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n", - offset); + dev_notice(adapter->dev, + "info: FW download over, size %d bytes\n", offset); ret = 0; done: @@ -1882,6 +1888,7 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) } adapter->auto_tdls = card->auto_tdls; + adapter->ext_scan = card->can_ext_scan; return ret; } @@ -1958,8 +1965,8 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) pr_err("Resetting card...\n"); mmc_remove_host(target); - /* 20ms delay is based on experiment with sdhci controller */ - mdelay(20); + /* 200ms delay is based on experiment with sdhci controller */ + mdelay(200); target->rescan_entered = 0; /* rescan non-removable cards */ mmc_add_host(target); } @@ -2023,6 +2030,8 @@ static void mwifiex_sdio_fw_dump_work(struct work_struct *work) u32 memory_size; static char *env[] = { "DRIVER=mwifiex_sdio", "EVENT=fw_dump", NULL }; + mwifiex_dump_drv_info(adapter); + if (!card->supports_fw_dump) return; @@ -2166,6 +2175,99 @@ static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter) schedule_work(&adapter->iface_work); } +/* Function to dump SDIO function registers and SDIO scratch registers in case + * of FW crash + */ +static int +mwifiex_sdio_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf) +{ + char *p = drv_buf; + struct sdio_mmc_card *cardp = adapter->card; + int ret = 0; + u8 count, func, data, index = 0, size = 0; + u8 reg, reg_start, reg_end; + char buf[256], *ptr; + + if (!p) + return 0; + + dev_info(adapter->dev, "SDIO register DUMP START\n"); + + mwifiex_pm_wakeup_card(adapter); + + sdio_claim_host(cardp->func); + + for (count = 0; count < 5; count++) { + memset(buf, 0, sizeof(buf)); + ptr = buf; + + switch (count) { + case 0: + /* Read the registers of SDIO function0 */ + func = count; + reg_start = 0; + reg_end = 9; + break; + case 1: + /* Read the registers of SDIO function1 */ + func = count; + reg_start = cardp->reg->func1_dump_reg_start; + reg_end = cardp->reg->func1_dump_reg_end; + break; + case 2: + index = 0; + func = 1; + reg_start = cardp->reg->func1_spec_reg_table[index++]; + size = cardp->reg->func1_spec_reg_num; + reg_end = cardp->reg->func1_spec_reg_table[size-1]; + break; + default: + /* Read the scratch registers of SDIO function1 */ + if (count == 4) + mdelay(100); + func = 1; + reg_start = cardp->reg->func1_scratch_reg; + reg_end = reg_start + MWIFIEX_SDIO_SCRATCH_SIZE; + } + + if (count != 2) + ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", + func, reg_start, reg_end); + else + ptr += sprintf(ptr, "SDIO Func%d: ", func); + + for (reg = reg_start; reg <= reg_end;) { + if (func == 0) + data = sdio_f0_readb(cardp->func, reg, &ret); + else + data = sdio_readb(cardp->func, reg, &ret); + + if (count == 2) + ptr += sprintf(ptr, "(%#x) ", reg); + if (!ret) { + ptr += sprintf(ptr, "%02x ", data); + } else { + ptr += sprintf(ptr, "ERR"); + break; + } + + if (count == 2 && reg < reg_end) + reg = cardp->reg->func1_spec_reg_table[index++]; + else + reg++; + } + + dev_info(adapter->dev, "%s\n", buf); + p += sprintf(p, "%s\n", buf); + } + + sdio_release_host(cardp->func); + + dev_info(adapter->dev, "SDIO register DUMP END\n"); + + return p - drv_buf; +} + static struct mwifiex_if_ops sdio_ops = { .init_if = mwifiex_init_sdio, .cleanup_if = mwifiex_cleanup_sdio, @@ -2188,6 +2290,7 @@ static struct mwifiex_if_ops sdio_ops = { .card_reset = mwifiex_sdio_card_reset, .iface_work = mwifiex_sdio_work, .fw_dump = mwifiex_sdio_fw_dump, + .reg_dump = mwifiex_sdio_reg_dump, }; /* diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 54c07156dd78..957cca246618 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -34,6 +34,7 @@ #define SD8797_DEFAULT_FW_NAME "mrvl/sd8797_uapsta.bin" #define SD8897_DEFAULT_FW_NAME "mrvl/sd8897_uapsta.bin" #define SD8887_DEFAULT_FW_NAME "mrvl/sd8887_uapsta.bin" +#define SD8801_DEFAULT_FW_NAME "mrvl/sd8801_uapsta.bin" #define BLOCK_MODE 1 #define BYTE_MODE 0 @@ -44,6 +45,9 @@ #define MWIFIEX_SDIO_BYTE_MODE_MASK 0x80000000 +#define MWIFIEX_MAX_FUNC2_REG_NUM 13 +#define MWIFIEX_SDIO_SCRATCH_SIZE 10 + #define SDIO_MPA_ADDR_BASE 0x1000 #define CTRL_PORT 0 #define CTRL_PORT_MASK 0x0001 @@ -219,6 +223,11 @@ struct mwifiex_sdio_card_reg { u8 fw_dump_ctrl; u8 fw_dump_start; u8 fw_dump_end; + u8 func1_dump_reg_start; + u8 func1_dump_reg_end; + u8 func1_scratch_reg; + u8 func1_spec_reg_num; + u8 func1_spec_reg_table[MWIFIEX_MAX_FUNC2_REG_NUM]; }; struct sdio_mmc_card { @@ -247,6 +256,7 @@ struct sdio_mmc_card { u8 *mp_regs; u8 auto_tdls; + bool can_ext_scan; struct mwifiex_sdio_mpa_tx mpa_tx; struct mwifiex_sdio_mpa_rx mpa_rx; @@ -264,6 +274,7 @@ struct mwifiex_sdio_device { u32 mp_tx_agg_buf_size; u32 mp_rx_agg_buf_size; u8 auto_tdls; + bool can_ext_scan; }; static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = { @@ -291,6 +302,11 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = { .rd_len_p0_l = 0x08, .rd_len_p0_u = 0x09, .card_misc_cfg_reg = 0x6c, + .func1_dump_reg_start = 0x0, + .func1_dump_reg_end = 0x9, + .func1_scratch_reg = 0x60, + .func1_spec_reg_num = 5, + .func1_spec_reg_table = {0x28, 0x30, 0x34, 0x38, 0x3c}, }; static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = { @@ -335,6 +351,12 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = { .fw_dump_ctrl = 0xe2, .fw_dump_start = 0xe3, .fw_dump_end = 0xea, + .func1_dump_reg_start = 0x0, + .func1_dump_reg_end = 0xb, + .func1_scratch_reg = 0xc0, + .func1_spec_reg_num = 8, + .func1_spec_reg_table = {0x4C, 0x50, 0x54, 0x55, 0x58, + 0x59, 0x5c, 0x5d}, }; static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8887 = { @@ -376,6 +398,13 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8887 = { .cmd_cfg_1 = 0xc5, .cmd_cfg_2 = 0xc6, .cmd_cfg_3 = 0xc7, + .func1_dump_reg_start = 0x10, + .func1_dump_reg_end = 0x17, + .func1_scratch_reg = 0x90, + .func1_spec_reg_num = 13, + .func1_spec_reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, + 0x61, 0x62, 0x64, 0x65, 0x66, + 0x68, 0x69, 0x6a}, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = { @@ -390,6 +419,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = { .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, .supports_fw_dump = false, .auto_tdls = false, + .can_ext_scan = false, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { @@ -404,6 +434,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, .supports_fw_dump = false, .auto_tdls = false, + .can_ext_scan = true, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { @@ -418,6 +449,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, .supports_fw_dump = false, .auto_tdls = false, + .can_ext_scan = true, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { @@ -432,6 +464,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, .supports_fw_dump = true, .auto_tdls = false, + .can_ext_scan = true, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = { @@ -446,6 +479,22 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = { .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, .supports_fw_dump = false, .auto_tdls = true, + .can_ext_scan = true, +}; + +static const struct mwifiex_sdio_device mwifiex_sdio_sd8801 = { + .firmware = SD8801_DEFAULT_FW_NAME, + .reg = &mwifiex_reg_sd87xx, + .max_ports = 16, + .mp_agg_pkt_limit = 8, + .supports_sdio_new_mode = false, + .has_control_mask = true, + .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, + .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, + .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, + .supports_fw_dump = false, + .auto_tdls = false, + .can_ext_scan = true, }; /* diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 1c2ca291d1f5..f7d204ffd6e9 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -26,6 +26,10 @@ #include "11n.h" #include "11ac.h" +static bool disable_auto_ds; +module_param(disable_auto_ds, bool, 0); +MODULE_PARM_DESC(disable_auto_ds, + "deepsleep enabled=0(default), deepsleep disabled=1"); /* * This function prepares command to set/get RSSI information. * @@ -1893,6 +1897,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, case HostCmd_CMD_TDLS_OPER: ret = mwifiex_cmd_tdls_oper(priv, cmd_ptr, data_buf); break; + case HostCmd_CMD_CHAN_REPORT_REQUEST: + ret = mwifiex_cmd_issue_chan_report_request(priv, cmd_ptr, + data_buf); + break; default: dev_err(priv->adapter->dev, "PREP_CMD: unknown cmd- %#x\n", cmd_no); @@ -1907,6 +1915,8 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, * * This is called after firmware download to bring the card to * working state. + * Function is also called during reinitialization of virtual + * interfaces. * * The following commands are issued sequentially - * - Set PCI-Express host buffer configuration (PCIE only) @@ -1921,7 +1931,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, * - 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 mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) { struct mwifiex_adapter *adapter = priv->adapter; int ret; @@ -2031,7 +2041,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) if (ret) return -1; - if (first_sta && priv->adapter->iface_type != MWIFIEX_USB && + if (!disable_auto_ds && + first_sta && priv->adapter->iface_type != MWIFIEX_USB && priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { /* Enable auto deep sleep */ auto_ds.auto_ds = DEEP_SLEEP_ON; @@ -2054,9 +2065,6 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) "11D: failed to enable 11D\n"); } - /* set last_init_cmd before sending the command */ - priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG; - /* Send cmd to FW to configure 11n specific configuration * (Short GI, Channel BW, Green field support etc.) for transmit */ @@ -2064,7 +2072,11 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_CFG, HostCmd_ACT_GEN_SET, 0, &tx_cfg, true); - ret = -EINPROGRESS; + if (init) { + /* set last_init_cmd before sending the command */ + priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG; + ret = -EINPROGRESS; + } return ret; } diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index b65e1014b0fc..5f8da5924666 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -248,6 +248,8 @@ static int mwifiex_ret_get_log(struct mwifiex_private *priv, 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]); + stats->bcn_rcv_cnt = le32_to_cpu(get_log->bcn_rcv_cnt); + stats->bcn_miss_cnt = le32_to_cpu(get_log->bcn_miss_cnt); } return 0; @@ -1103,6 +1105,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, case HostCmd_CMD_UAP_SYS_CONFIG: break; case HostCmd_CMD_UAP_BSS_START: + adapter->tx_lock_flag = false; + adapter->pps_uapsd_mode = false; + adapter->delay_null_pkt = false; priv->bss_started = 1; break; case HostCmd_CMD_UAP_BSS_STOP: @@ -1117,6 +1122,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, case HostCmd_CMD_TDLS_OPER: ret = mwifiex_ret_tdls_oper(priv, resp); break; + case HostCmd_CMD_CHAN_REPORT_REQUEST: + break; default: dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", resp->command); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index b8c171df6223..80ffe7412496 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -90,6 +90,10 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) priv->is_data_rate_auto = true; priv->data_rate = 0; + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || + GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && priv->hist_data) + mwifiex_hist_data_reset(priv); + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { priv->adhoc_state = ADHOC_IDLE; priv->adhoc_is_link_sensed = false; @@ -308,6 +312,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_card_req = false; adapter->pm_wakeup_fw_try = false; + del_timer_sync(&adapter->wakeup_timer); break; } if (!mwifiex_send_null_packet @@ -322,6 +327,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_card_req = false; adapter->pm_wakeup_fw_try = false; + del_timer_sync(&adapter->wakeup_timer); break; @@ -480,7 +486,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_REMAIN_ON_CHAN_EXPIRED: dev_dbg(adapter->dev, "event: Remain on channel expired\n"); - cfg80211_remain_on_channel_expired(priv->wdev, + cfg80211_remain_on_channel_expired(&priv->wdev, priv->roc_cfg.cookie, &priv->roc_cfg.chan, GFP_ATOMIC); @@ -509,6 +515,16 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) mwifiex_parse_tx_status_event(priv, adapter->event_body); break; + case EVENT_CHANNEL_REPORT_RDY: + dev_dbg(adapter->dev, "event: Channel Report\n"); + ret = mwifiex_11h_handle_chanrpt_ready(priv, + adapter->event_skb); + break; + case EVENT_RADAR_DETECTED: + dev_dbg(adapter->dev, "event: Radar detected\n"); + ret = mwifiex_11h_handle_radar_detected(priv, + adapter->event_skb); + break; default: dev_dbg(adapter->dev, "event: unknown event id: %#x\n", eventcause); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 1626868a4b5c..0599e41e253c 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -219,7 +219,7 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv, if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) { rcu_read_unlock(); - wiphy_dbg(priv->wdev->wiphy, + wiphy_dbg(priv->wdev.wiphy, "11D: skip setting domain info in FW\n"); return 0; } @@ -902,9 +902,12 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, if (wep_key->key_length) { void *enc_key; - if (encrypt_key->key_disable) + if (encrypt_key->key_disable) { memset(&priv->wep_key[index], 0, sizeof(struct mwifiex_wep_key)); + if (wep_key->key_length) + goto done; + } if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) enc_key = encrypt_key; @@ -918,6 +921,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, return ret; } +done: if (priv->sec_info.wep_enabled) priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; else @@ -1131,36 +1135,6 @@ mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action, return roc_cfg.status; } -int -mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role) -{ - if (GET_BSS_ROLE(priv) == bss_role) { - dev_dbg(priv->adapter->dev, - "info: already in the desired role.\n"); - return 0; - } - - mwifiex_free_priv(priv); - mwifiex_init_priv(priv); - - priv->bss_role = bss_role; - switch (bss_role) { - case MWIFIEX_BSS_ROLE_UAP: - priv->bss_mode = NL80211_IFTYPE_AP; - break; - case MWIFIEX_BSS_ROLE_STA: - case MWIFIEX_BSS_ROLE_ANY: - default: - priv->bss_mode = NL80211_IFTYPE_STATION; - break; - } - - mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, - HostCmd_ACT_GEN_SET, 0, NULL, true); - - return mwifiex_sta_init_cmd(priv, false); -} - /* * Sends IOCTL request to get statistics information. * diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index c2ad3b63ae70..b8729c9394e9 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -90,6 +90,7 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, struct ethhdr *eth; u16 rx_pkt_off, rx_pkt_len; u8 *offset; + u8 adj_rx_rate = 0; local_rx_pd = (struct rxpd *) (skb->data); @@ -155,6 +156,14 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv, priv->rxpd_htinfo = local_rx_pd->ht_info; + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || + GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { + adj_rx_rate = mwifiex_adjust_data_rate(priv, priv->rxpd_rate, + priv->rxpd_htinfo); + mwifiex_hist_data_add(priv, adj_rx_rate, local_rx_pd->snr, + local_rx_pd->nf); + } + ret = mwifiex_recv_packet(priv, skb); if (ret == -1) dev_err(priv->adapter->dev, "recv packet failed\n"); diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c index b896d7375b52..5ce2d9a4f919 100644 --- a/drivers/net/wireless/mwifiex/sta_tx.c +++ b/drivers/net/wireless/mwifiex/sta_tx.c @@ -47,8 +47,10 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; struct txpd *local_tx_pd; struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); - u8 pad; + unsigned int pad; u16 pkt_type, pkt_offset; + int hroom = (priv->adapter->iface_type == MWIFIEX_USB) ? 0 : + INTF_HEADER_LEN; if (!skb->len) { dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len); @@ -56,13 +58,12 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, return skb->data; } + BUG_ON(skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN); + pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0; - /* If skb->data is not aligned; add padding */ - pad = (4 - (((void *)skb->data - NULL) & 0x3)) % 4; - - BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN - + pad)); + pad = ((void *)skb->data - (sizeof(*local_tx_pd) + hroom)- + NULL) & (MWIFIEX_DMA_ALIGN_SZ - 1); skb_push(skb, sizeof(*local_tx_pd) + pad); local_tx_pd = (struct txpd *) skb->data; @@ -70,8 +71,8 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, 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) - + pad))); + (sizeof(struct txpd) + + pad))); local_tx_pd->priority = (u8) skb->priority; local_tx_pd->pkt_delay_2ms = @@ -115,7 +116,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, local_tx_pd->tx_pkt_offset = cpu_to_le16(pkt_offset); /* make space for INTF_HEADER_LEN */ - skb_push(skb, INTF_HEADER_LEN); + skb_push(skb, hroom); if (!local_tx_pd->tx_control) /* TxCtrl set by user or default */ @@ -182,9 +183,13 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) } switch (ret) { case -EBUSY: - adapter->data_sent = true; - /* Fall through FAILURE handling */ + 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 -1: + adapter->data_sent = false; dev_kfree_skb_any(skb); dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n", __func__, ret); @@ -197,6 +202,7 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) adapter->tx_lock_flag = true; break; case -EINPROGRESS: + adapter->tx_lock_flag = true; break; default: break; diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 22884b429be7..087d84762cd3 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -1123,6 +1123,36 @@ int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, const u8 *mac) return TDLS_NOT_SETUP; } +int mwifiex_get_tdls_list(struct mwifiex_private *priv, + struct tdls_peer_info *buf) +{ + struct mwifiex_sta_node *sta_ptr; + struct tdls_peer_info *peer = buf; + int count = 0; + unsigned long flags; + + if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return 0; + + /* make sure we are in station mode and connected */ + if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) + return 0; + + spin_lock_irqsave(&priv->sta_list_spinlock, flags); + list_for_each_entry(sta_ptr, &priv->sta_list, list) { + if (sta_ptr->tdls_status == TDLS_SETUP_COMPLETE) { + ether_addr_copy(peer->peer_addr, sta_ptr->mac_addr); + peer++; + count++; + if (count >= MWIFIEX_MAX_TDLS_PEER_SUPPORTED) + break; + } + } + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + + return count; +} + void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv) { struct mwifiex_sta_node *sta_ptr; @@ -1367,9 +1397,8 @@ void mwifiex_check_auto_tdls(unsigned long context) void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv) { - init_timer(&priv->auto_tdls_timer); - priv->auto_tdls_timer.function = mwifiex_check_auto_tdls; - priv->auto_tdls_timer.data = (unsigned long)priv; + setup_timer(&priv->auto_tdls_timer, mwifiex_check_auto_tdls, + (unsigned long)priv); priv->auto_tdls_timer_active = true; mod_timer(&priv->auto_tdls_timer, jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S)); diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 6ae133333363..ac93557cbdc9 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -227,7 +227,7 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv, /* consumes ack_skb */ skb_complete_wifi_ack(ack_skb, !tx_status->status); } else { - cfg80211_mgmt_tx_status(priv->wdev, tx_info->cookie, + cfg80211_mgmt_tx_status(&priv->wdev, tx_info->cookie, ack_skb->data, ack_skb->len, !tx_status->status, GFP_ATOMIC); dev_kfree_skb_any(ack_skb); diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index 0f347fdefa0a..f5c2af01ba0a 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -761,6 +761,11 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no, if (mwifiex_cmd_uap_sta_deauth(priv, cmd, data_buf)) return -1; break; + case HostCmd_CMD_CHAN_REPORT_REQUEST: + if (mwifiex_cmd_issue_chan_report_request(priv, cmd_buf, + data_buf)) + return -1; + break; default: dev_err(priv->adapter->dev, "PREP_CMD: unknown cmd %#x\n", cmd_no); @@ -769,3 +774,68 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no, return 0; } + +void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg, + struct cfg80211_chan_def chandef) +{ + u8 config_bands = 0; + + bss_cfg->channel = ieee80211_frequency_to_channel( + chandef.chan->center_freq); + + /* Set appropriate bands */ + if (chandef.chan->band == IEEE80211_BAND_2GHZ) { + bss_cfg->band_cfg = BAND_CONFIG_BG; + config_bands = BAND_B | BAND_G; + + if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT) + config_bands |= BAND_GN; + } else { + bss_cfg->band_cfg = BAND_CONFIG_A; + config_bands = BAND_A; + + if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT) + config_bands |= BAND_AN; + + if (chandef.width > NL80211_CHAN_WIDTH_40) + config_bands |= BAND_AAC; + } +} + +int mwifiex_config_start_uap(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_cfg) +{ + if (mwifiex_del_mgmt_ies(priv)) + dev_err(priv->adapter->dev, "Failed to delete mgmt IEs!\n"); + + if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, + HostCmd_ACT_GEN_SET, 0, NULL, true)) { + dev_err(priv->adapter->dev, "Failed to stop the BSS\n"); + return -1; + } + + if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, + HostCmd_ACT_GEN_SET, + UAP_BSS_PARAMS_I, bss_cfg, false)) { + dev_err(priv->adapter->dev, "Failed to set the SSID\n"); + return -1; + } + + if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, + HostCmd_ACT_GEN_SET, 0, NULL, false)) { + dev_err(priv->adapter->dev, "Failed to start the BSS\n"); + return -1; + } + + if (priv->sec_info.wep_enabled) + priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; + else + priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; + + if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &priv->curr_pkt_filter, true)) + return -1; + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index c54a537e31fb..f4794cdc36d2 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -68,7 +68,6 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) len = ETH_ALEN; if (len != -1) { - sinfo.filled = STATION_INFO_ASSOC_REQ_IES; sinfo.assoc_req_ies = &event->data[len]; len = (u8 *)sinfo.assoc_req_ies - (u8 *)&event->frame_control; @@ -132,6 +131,8 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause); memcpy(priv->netdev->dev_addr, adapter->event_body + 2, ETH_ALEN); + if (priv->hist_data) + mwifiex_hist_data_reset(priv); break; case EVENT_UAP_MIC_COUNTERMEASURES: /* For future development */ @@ -177,6 +178,53 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) dev_dbg(adapter->dev, "event: TX_STATUS Report\n"); mwifiex_parse_tx_status_event(priv, adapter->event_body); 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) { + adapter->ps_state = PS_STATE_AWAKE; + adapter->pm_wakeup_card_req = false; + adapter->pm_wakeup_fw_try = false; + break; + } + 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_CHANNEL_REPORT_RDY: + dev_dbg(adapter->dev, "event: Channel Report\n"); + mwifiex_11h_handle_chanrpt_ready(priv, adapter->event_skb); + break; + case EVENT_RADAR_DETECTED: + dev_dbg(adapter->dev, "event: Radar detected\n"); + mwifiex_11h_handle_radar_detected(priv, adapter->event_skb); + break; default: dev_dbg(adapter->dev, "event: unknown event id: %#x\n", eventcause); diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c index be3a203a529b..38ac4d74c486 100644 --- a/drivers/net/wireless/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/mwifiex/uap_txrx.c @@ -348,8 +348,10 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; struct uap_txpd *txpd; struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); - int pad, len; - u16 pkt_type; + int pad; + u16 pkt_type, pkt_offset; + int hroom = (priv->adapter->iface_type == MWIFIEX_USB) ? 0 : + INTF_HEADER_LEN; if (!skb->len) { dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len); @@ -357,22 +359,21 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv, return skb->data; } + BUG_ON(skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN); + pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0; - /* If skb->data is not aligned, add padding */ - pad = (4 - (((void *)skb->data - NULL) & 0x3)) % 4; + pad = ((void *)skb->data - (sizeof(*txpd) + hroom) - NULL) & + (MWIFIEX_DMA_ALIGN_SZ - 1); - len = sizeof(*txpd) + pad; - - BUG_ON(skb_headroom(skb) < len + INTF_HEADER_LEN); - - skb_push(skb, len); + skb_push(skb, sizeof(*txpd) + pad); txpd = (struct uap_txpd *)skb->data; memset(txpd, 0, sizeof(*txpd)); txpd->bss_num = priv->bss_num; txpd->bss_type = priv->bss_type; - txpd->tx_pkt_length = cpu_to_le16((u16)(skb->len - len)); + txpd->tx_pkt_length = cpu_to_le16((u16)(skb->len - (sizeof(*txpd) + + pad))); txpd->priority = (u8)skb->priority; txpd->pkt_delay_2ms = mwifiex_wmm_compute_drv_pkt_delay(priv, skb); @@ -392,16 +393,17 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv, cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[txpd->priority]); /* Offset of actual data */ + pkt_offset = sizeof(*txpd) + pad; if (pkt_type == PKT_TYPE_MGMT) { /* Set the packet type and add header for management frame */ txpd->tx_pkt_type = cpu_to_le16(pkt_type); - len += MWIFIEX_MGMT_FRAME_HEADER_SIZE; + pkt_offset += MWIFIEX_MGMT_FRAME_HEADER_SIZE; } - txpd->tx_pkt_offset = cpu_to_le16(len); + txpd->tx_pkt_offset = cpu_to_le16(pkt_offset); /* make space for INTF_HEADER_LEN */ - skb_push(skb, INTF_HEADER_LEN); + skb_push(skb, hroom); if (!txpd->tx_control) /* TxCtrl set by user or default */ diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 1b56495ec872..223873022ffe 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -37,6 +37,11 @@ static struct usb_device_id mwifiex_usb_table[] = { {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8797_PID_2, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff)}, + /* 8801 */ + {USB_DEVICE(USB8XXX_VID, USB8801_PID_1)}, + {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8801_PID_2, + USB_CLASS_VENDOR_SPEC, + USB_SUBCLASS_VENDOR_SPEC, 0xff)}, /* 8897 */ {USB_DEVICE(USB8XXX_VID, USB8897_PID_1)}, {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8897_PID_2, @@ -361,11 +366,13 @@ static int mwifiex_usb_probe(struct usb_interface *intf, switch (id_product) { case USB8766_PID_1: case USB8797_PID_1: + case USB8801_PID_1: case USB8897_PID_1: card->usb_boot_state = USB8XXX_FW_DNLD; break; case USB8766_PID_2: case USB8797_PID_2: + case USB8801_PID_2: case USB8897_PID_2: card->usb_boot_state = USB8XXX_FW_READY; break; @@ -792,11 +799,19 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) case USB8897_PID_2: adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; strcpy(adapter->fw_name, USB8897_DEFAULT_FW_NAME); + adapter->ext_scan = true; break; case USB8766_PID_1: case USB8766_PID_2: adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; strcpy(adapter->fw_name, USB8766_DEFAULT_FW_NAME); + adapter->ext_scan = true; + break; + case USB8801_PID_1: + case USB8801_PID_2: + adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + strcpy(adapter->fw_name, USB8801_DEFAULT_FW_NAME); + adapter->ext_scan = false; break; case USB8797_PID_1: case USB8797_PID_2: @@ -930,7 +945,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, } while ((dnld_cmd != FW_HAS_LAST_BLOCK) && retries); cleanup: - dev_dbg(adapter->dev, "%s: %d bytes downloaded\n", __func__, tlen); + dev_notice(adapter->dev, + "info: FW download over, size %d bytes\n", tlen); kfree(recv_buff); kfree(fwdata); @@ -990,6 +1006,7 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) { /* Simulation of HS_AWAKE event */ adapter->pm_wakeup_fw_try = false; + del_timer_sync(&adapter->wakeup_timer); adapter->pm_wakeup_card_req = false; adapter->ps_state = PS_STATE_AWAKE; @@ -1010,6 +1027,13 @@ static void mwifiex_usb_submit_rem_rx_urbs(struct mwifiex_adapter *adapter) } } +/* This function is called after the card has woken up. */ +static inline int +mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) +{ + return 0; +} + static struct mwifiex_if_ops usb_ops = { .register_dev = mwifiex_register_dev, .unregister_dev = mwifiex_unregister_dev, @@ -1074,4 +1098,5 @@ MODULE_VERSION(USB_VERSION); MODULE_LICENSE("GPL v2"); MODULE_FIRMWARE(USB8766_DEFAULT_FW_NAME); MODULE_FIRMWARE(USB8797_DEFAULT_FW_NAME); +MODULE_FIRMWARE(USB8801_DEFAULT_FW_NAME); MODULE_FIRMWARE(USB8897_DEFAULT_FW_NAME); diff --git a/drivers/net/wireless/mwifiex/usb.h b/drivers/net/wireless/mwifiex/usb.h index a7cbba1355af..57e1a5736318 100644 --- a/drivers/net/wireless/mwifiex/usb.h +++ b/drivers/net/wireless/mwifiex/usb.h @@ -30,6 +30,9 @@ #define USB8797_PID_2 0x2044 #define USB8897_PID_1 0x2045 #define USB8897_PID_2 0x2046 +#define USB8801_PID_1 0x2049 +#define USB8801_PID_2 0x204a + #define USB8XXX_FW_DNLD 1 #define USB8XXX_FW_READY 2 @@ -41,6 +44,7 @@ #define USB8766_DEFAULT_FW_NAME "mrvl/usb8766_uapsta.bin" #define USB8797_DEFAULT_FW_NAME "mrvl/usb8797_uapsta.bin" +#define USB8801_DEFAULT_FW_NAME "mrvl/usb8801_uapsta.bin" #define USB8897_DEFAULT_FW_NAME "mrvl/usb8897_uapsta.bin" #define FW_DNLD_TX_BUF_SIZE 620 @@ -96,11 +100,4 @@ struct fw_data { u8 data[1]; }; -/* This function is called after the card has woken up. */ -static inline int -mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) -{ - return 0; -} - #endif /*_MWIFIEX_USB_H */ diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index b1768fbf98f2..308550611f22 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -25,6 +25,96 @@ #include "wmm.h" #include "11n.h" +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}, + {"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}, + {"is_cmd_timedout", item_size(is_cmd_timedout), + item_addr(is_cmd_timedout), 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); + /* * Firmware initialization complete callback handler. * @@ -97,6 +187,8 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv, info->rx_tbl); info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl(priv, info->tx_tbl); + info->tdls_peer_num = mwifiex_get_tdls_list(priv, + info->tdls_list); info->ps_mode = adapter->ps_mode; info->ps_state = adapter->ps_state; info->is_deep_sleep = adapter->is_deep_sleep; @@ -141,6 +233,93 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv, return 0; } +int mwifiex_debug_info_to_buffer(struct mwifiex_private *priv, char *buf, + struct mwifiex_debug_info *info) +{ + char *p = buf; + struct mwifiex_debug_data *d = &items[0]; + size_t size, addr; + long val; + int i, j; + + if (!info) + return 0; + + 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 = %pM\n", + info->tx_tbl[i].tid, info->tx_tbl[i].ra); + } + + 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 = %pM, ", + info->rx_tbl[i].tid, + info->rx_tbl[i].ta); + p += sprintf(p, "start_win = %d, ", + info->rx_tbl[i].start_win); + p += sprintf(p, "win_size = %d, buffer: ", + 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"); + } + } + + if (info->tdls_peer_num) { + p += sprintf(p, "TDLS peer table:\n"); + for (i = 0; i < info->tdls_peer_num; i++) { + p += sprintf(p, "peer = %pM", + info->tdls_list[i].peer_addr); + p += sprintf(p, "\n"); + } + } + + return p - buf; +} + static int mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len, struct rxpd *rx_pd) @@ -208,7 +387,7 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, pkt_len -= ETH_ALEN + sizeof(pkt_len); rx_pd->rx_pkt_length = cpu_to_le16(pkt_len); - cfg80211_rx_mgmt(priv->wdev, priv->roc_cfg.chan.center_freq, + cfg80211_rx_mgmt(&priv->wdev, priv->roc_cfg.chan.center_freq, CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len, 0); @@ -404,3 +583,44 @@ void mwifiex_del_all_sta_list(struct mwifiex_private *priv) spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); return; } + +/* This function adds histogram data to histogram array*/ +void mwifiex_hist_data_add(struct mwifiex_private *priv, + u8 rx_rate, s8 snr, s8 nflr) +{ + struct mwifiex_histogram_data *phist_data = priv->hist_data; + + if (atomic_read(&phist_data->num_samples) > MWIFIEX_HIST_MAX_SAMPLES) + mwifiex_hist_data_reset(priv); + mwifiex_hist_data_set(priv, rx_rate, snr, nflr); +} + +/* function to add histogram record */ +void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr, + s8 nflr) +{ + struct mwifiex_histogram_data *phist_data = priv->hist_data; + + atomic_inc(&phist_data->num_samples); + atomic_inc(&phist_data->rx_rate[rx_rate]); + atomic_inc(&phist_data->snr[snr]); + atomic_inc(&phist_data->noise_flr[128 + nflr]); + atomic_inc(&phist_data->sig_str[nflr - snr]); +} + +/* function to reset histogram data during init/reset */ +void mwifiex_hist_data_reset(struct mwifiex_private *priv) +{ + int ix; + struct mwifiex_histogram_data *phist_data = priv->hist_data; + + atomic_set(&phist_data->num_samples, 0); + for (ix = 0; ix < MWIFIEX_MAX_AC_RX_RATES; ix++) + atomic_set(&phist_data->rx_rate[ix], 0); + for (ix = 0; ix < MWIFIEX_MAX_SNR; ix++) + atomic_set(&phist_data->snr[ix], 0); + for (ix = 0; ix < MWIFIEX_MAX_NOISE_FLR; ix++) + atomic_set(&phist_data->noise_flr[ix], 0); + for (ix = 0; ix < MWIFIEX_MAX_SIG_STRENGTH; ix++) + atomic_set(&phist_data->sig_str[ix], 0); +} diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h index 40296cb4a3f1..b541d66c01eb 100644 --- a/drivers/net/wireless/mwifiex/util.h +++ b/drivers/net/wireless/mwifiex/util.h @@ -20,6 +20,8 @@ #ifndef _MWIFIEX_UTIL_H_ #define _MWIFIEX_UTIL_H_ +struct mwifiex_private; + struct mwifiex_dma_mapping { dma_addr_t addr; size_t len; @@ -33,6 +35,21 @@ struct mwifiex_cb { }; }; +/* 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 inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb) { struct mwifiex_cb *cb = (struct mwifiex_cb *)skb->cb; @@ -73,4 +90,7 @@ static inline dma_addr_t MWIFIEX_SKB_DMA_ADDR(struct sk_buff *skb) return mapping.addr; } +int mwifiex_debug_info_to_buffer(struct mwifiex_private *priv, char *buf, + struct mwifiex_debug_info *info); + #endif /* !_MWIFIEX_UTIL_H_ */ diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index ffffd2c5a76e..ef717acec8b7 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -1228,6 +1228,9 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, case -EINPROGRESS: if (adapter->iface_type != MWIFIEX_PCIE) adapter->data_sent = false; + break; + case 0: + mwifiex_write_data_complete(adapter, skb, 0, ret); default: break; } diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b8d1e04aa9b9..f9b1218c761a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3098,14 +3098,14 @@ static void mwl8k_update_survey(struct mwl8k_priv *priv, cca_cnt = ioread32(priv->regs + NOK_CCA_CNT_REG); cca_cnt /= 1000; /* uSecs to mSecs */ - survey->channel_time_busy = (u64) cca_cnt; + survey->time_busy = (u64) cca_cnt; rx_rdy = ioread32(priv->regs + BBU_RXRDY_CNT_REG); rx_rdy /= 1000; /* uSecs to mSecs */ - survey->channel_time_rx = (u64) rx_rdy; + survey->time_rx = (u64) rx_rdy; priv->channel_time = jiffies - priv->channel_time; - survey->channel_time = jiffies_to_msecs(priv->channel_time); + survey->time = jiffies_to_msecs(priv->channel_time); survey->channel = channel; @@ -3115,9 +3115,9 @@ static void mwl8k_update_survey(struct mwl8k_priv *priv, survey->noise = nf * -1; survey->filled = SURVEY_INFO_NOISE_DBM | - SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_RX; + SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_RX; } /* diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig index 60698b020851..6d831d4d1b5f 100644 --- a/drivers/net/wireless/orinoco/Kconfig +++ b/drivers/net/wireless/orinoco/Kconfig @@ -1,7 +1,8 @@ config HERMES tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" depends on (PPC_PMAC || PCI || PCMCIA) - depends on CFG80211 && CFG80211_WEXT + depends on CFG80211 + select CFG80211_WEXT select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 38ec8d19ac29..c410180479e6 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -2342,7 +2342,7 @@ void free_orinocodev(struct orinoco_private *priv) list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) { list_del(&sd->list); - if ((sd->len > 0) && sd->buf) + if (sd->len > 0) kfree(sd->buf); kfree(sd); } diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c index b6bdad632842..74219d59d7e1 100644 --- a/drivers/net/wireless/orinoco/orinoco_pci.c +++ b/drivers/net/wireless/orinoco/orinoco_pci.c @@ -94,7 +94,7 @@ static int orinoco_pci_cor_reset(struct orinoco_private *priv) mdelay(HERMES_PCI_COR_OFFT); /* The card is ready when it's no longer busy */ - timeout = jiffies + (HERMES_PCI_COR_BUSYT * HZ / 1000); + timeout = jiffies + msecs_to_jiffies(HERMES_PCI_COR_BUSYT); reg = hermes_read_regn(hw, CMD); while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { mdelay(1); diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c index b8f6e5c431ae..8b045236b6e0 100644 --- a/drivers/net/wireless/orinoco/orinoco_plx.c +++ b/drivers/net/wireless/orinoco/orinoco_plx.c @@ -121,7 +121,7 @@ static int orinoco_plx_cor_reset(struct orinoco_private *priv) mdelay(1); /* Just in case, wait more until the card is no longer busy */ - timeout = jiffies + (PLX_RESET_TIME * HZ / 1000); + timeout = jiffies + msecs_to_jiffies(PLX_RESET_TIME); reg = hermes_read_regn(hw, CMD); while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { mdelay(1); diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c index 79d0e33b625e..20ce569b8a43 100644 --- a/drivers/net/wireless/orinoco/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco/orinoco_tmd.c @@ -71,7 +71,7 @@ static int orinoco_tmd_cor_reset(struct orinoco_private *priv) mdelay(1); /* Just in case, wait more until the card is no longer busy */ - timeout = jiffies + (TMD_RESET_TIME * HZ / 1000); + timeout = jiffies + msecs_to_jiffies(TMD_RESET_TIME); reg = hermes_read_regn(hw, CMD); while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { mdelay(1); diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c index 995846422dc0..91f05442de28 100644 --- a/drivers/net/wireless/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/orinoco/orinoco_usb.c @@ -364,9 +364,7 @@ static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv, atomic_set(&ctx->refcount, 1); init_completion(&ctx->done); - init_timer(&ctx->timer); - ctx->timer.function = ezusb_request_timerfn; - ctx->timer.data = (u_long) ctx; + setup_timer(&ctx->timer, ezusb_request_timerfn, (u_long)ctx); return ctx; } diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 0fe67d2da208..2fe713eda7ad 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -196,9 +196,9 @@ static int p54_generate_band(struct ieee80211_hw *dev, dest->max_power = chan->max_power; priv->survey[*chan_num].channel = &tmp->channels[j]; priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM | - SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_TX; + SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_TX; dest->hw_value = (*chan_num); j++; (*chan_num)++; diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index bc065e8e348b..5367d510b22d 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -220,6 +220,7 @@ int p54_download_eeprom(struct p54_common *priv, void *buf, struct sk_buff *skb; size_t eeprom_hdr_size; int ret = 0; + long timeout; if (priv->fw_var >= 0x509) eeprom_hdr_size = sizeof(*eeprom_hdr); @@ -249,9 +250,11 @@ int p54_download_eeprom(struct p54_common *priv, void *buf, p54_tx(priv, skb); - if (!wait_for_completion_interruptible_timeout( - &priv->eeprom_comp, HZ)) { - wiphy_err(priv->hw->wiphy, "device does not respond!\n"); + timeout = wait_for_completion_interruptible_timeout( + &priv->eeprom_comp, HZ); + if (timeout <= 0) { + wiphy_err(priv->hw->wiphy, + "device does not respond or signal received!\n"); ret = -EBUSY; } priv->eeprom = NULL; diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 97aeff0edb84..b9250d75d253 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -305,9 +305,9 @@ static void p54_reset_stats(struct p54_common *priv) struct survey_info *info = &priv->survey[chan->hw_value]; /* only reset channel statistics, don't touch .filled, etc. */ - info->channel_time = 0; - info->channel_time_busy = 0; - info->channel_time_tx = 0; + info->time = 0; + info->time_busy = 0; + info->time_tx = 0; } priv->update_stats = true; @@ -575,6 +575,8 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, key->hw_key_idx = 0xff; goto out_unlock; } + + key->flags |= IEEE80211_KEY_FLAG_RESERVE_TAILROOM; } else { slot = key->hw_key_idx; @@ -634,7 +636,7 @@ static int p54_get_survey(struct ieee80211_hw *dev, int idx, if (in_use) { /* test if the reported statistics are valid. */ - if (survey->channel_time != 0) { + if (survey->time != 0) { survey->filled |= SURVEY_INFO_IN_USE; } else { /* diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index d4aee64fb5ea..27a49068d32d 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -431,6 +431,7 @@ static int p54p_open(struct ieee80211_hw *dev) { struct p54p_priv *priv = dev->priv; int err; + long timeout; init_completion(&priv->boot_comp); err = request_irq(priv->pdev->irq, p54p_interrupt, @@ -468,10 +469,12 @@ static int p54p_open(struct ieee80211_hw *dev) P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); P54P_READ(dev_int); - if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) { + timeout = wait_for_completion_interruptible_timeout( + &priv->boot_comp, HZ); + if (timeout <= 0) { wiphy_err(dev->wiphy, "Cannot boot firmware!\n"); p54p_stop(dev); - return -ETIMEDOUT; + return timeout ? -ERESTARTSYS : -ETIMEDOUT; } P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)); diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 153c61539ec8..24e5ff9a9272 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -587,13 +587,13 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb) if (chan) { struct survey_info *survey = &priv->survey[chan->hw_value]; survey->noise = clamp(priv->noise, -128, 127); - survey->channel_time = priv->survey_raw.active; - survey->channel_time_tx = priv->survey_raw.tx; - survey->channel_time_busy = priv->survey_raw.tx + + survey->time = priv->survey_raw.active; + survey->time_tx = priv->survey_raw.tx; + survey->time_busy = priv->survey_raw.tx + priv->survey_raw.cca; - do_div(survey->channel_time, 1024); - do_div(survey->channel_time_tx, 1024); - do_div(survey->channel_time_busy, 1024); + do_div(survey->time, 1024); + do_div(survey->time_tx, 1024); + do_div(survey->time_busy, 1024); } tmp = p54_find_and_unlink_skb(priv, hdr->req_id); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 1a4facd1fbf3..60d44ce9c017 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2478,7 +2478,7 @@ static void rndis_fill_station_info(struct usbnet *usbdev, ret = rndis_query_oid(usbdev, RNDIS_OID_GEN_LINK_SPEED, &linkspeed, &len); if (ret == 0) { sinfo->txrate.legacy = le32_to_cpu(linkspeed) / 1000; - sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); } len = sizeof(rssi); @@ -2486,7 +2486,7 @@ static void rndis_fill_station_info(struct usbnet *usbdev, &rssi, &len); if (ret == 0) { sinfo->signal = level_to_qual(le32_to_cpu(rssi)); - sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); } } diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index 4834a9abc171..b6cc9ff47fc2 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -172,7 +172,6 @@ static int rsi_load_ta_instructions(struct rsi_common *common) (struct rsi_91x_sdiodev *)adapter->rsi_dev; u32 len; u32 num_blocks; - const u8 *fw; const struct firmware *fw_entry = NULL; u32 block_size = dev->tx_blk_size; int status = 0; @@ -201,7 +200,6 @@ static int rsi_load_ta_instructions(struct rsi_common *common) return status; } - fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); len = fw_entry->size; if (len % 4) @@ -212,7 +210,7 @@ static int rsi_load_ta_instructions(struct rsi_common *common) rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len); rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks); - status = rsi_copy_to_card(common, fw, len, num_blocks); + status = rsi_copy_to_card(common, fw_entry->data, len, num_blocks); release_firmware(fw_entry); return status; } diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 81ee481487cf..be2d54f257b1 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -8020,13 +8020,13 @@ int rt2800_get_survey(struct ieee80211_hw *hw, int idx, rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &busy_ext); if (idle || busy) { - survey->filled = SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_EXT_BUSY; + survey->filled = SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_EXT_BUSY; - survey->channel_time = (idle + busy) / 1000; - survey->channel_time_busy = busy / 1000; - survey->channel_time_ext_busy = busy_ext / 1000; + survey->time = (idle + busy) / 1000; + survey->time_busy = busy / 1000; + survey->time_ext_busy = busy_ext / 1000; } if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 1122dc44c9fd..48a2cad29477 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -240,7 +240,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, rt2x00dev->rf_channel = libconf.rf.channel; } - if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_PS_AUTOWAKE) && (ieee80211_flags & IEEE80211_CONF_CHANGE_PS)) cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); @@ -257,7 +257,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, rt2x00link_reset_tuner(rt2x00dev, false); if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && - test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && + rt2x00_has_cap_flag(rt2x00dev, REQUIRE_PS_AUTOWAKE) && (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) && (conf->flags & IEEE80211_CONF_PS)) { beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9967a1d9f0ec..5639ed816813 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -351,7 +351,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, /* * Remove L2 padding which was added during */ - if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_L2PAD)) rt2x00queue_remove_l2pad(entry->skb, header_length); /* @@ -460,7 +460,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, * send the status report back. */ if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) { - if (test_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_TASKLET_CONTEXT)) ieee80211_tx_status(rt2x00dev->hw, entry->skb); else ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb); @@ -1056,9 +1056,9 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Take TX headroom required for alignment into account. */ - if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_L2PAD)) rt2x00dev->hw->extra_tx_headroom += RT2X00_L2PAD_SIZE; - else if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) + else if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DMA)) rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE; /* @@ -1069,7 +1069,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Allocate tx status FIFO for driver use. */ - if (test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags)) { + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_TXSTATUS_FIFO)) { /* * Allocate the txstatus fifo. In the worst case the tx * status fifo has to hold the tx status of all entries @@ -1131,7 +1131,7 @@ static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) /* * Stop rfkill polling. */ - if (test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DELAYED_RFKILL)) rt2x00rfkill_unregister(rt2x00dev); /* @@ -1173,7 +1173,7 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) /* * Start rfkill polling. */ - if (test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DELAYED_RFKILL)) rt2x00rfkill_register(rt2x00dev); return 0; @@ -1389,7 +1389,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) /* * Start rfkill polling. */ - if (!test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags)) + if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DELAYED_RFKILL)) rt2x00rfkill_register(rt2x00dev); return 0; @@ -1408,7 +1408,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) /* * Stop rfkill polling. */ - if (!test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags)) + if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DELAYED_RFKILL)) rt2x00rfkill_unregister(rt2x00dev); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c index fbae2799e3ee..5813300f68a2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00firmware.c +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c @@ -96,7 +96,7 @@ int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev) { int retval; - if (!test_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags)) + if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_FIRMWARE)) return 0; if (!rt2x00dev->fw) { diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index cb40245a0695..300876df056f 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, * Use the ATIM queue if appropriate and present. */ if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && - test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) + rt2x00_has_cap_flag(rt2x00dev, REQUIRE_ATIM_QUEUE)) qid = QID_ATIM; queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 66ff36447b94..68b620b2462f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -85,7 +85,7 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp) memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->entry = entry; - if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) { + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DMA)) { dma_addr_t skb_dma; skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len, @@ -198,7 +198,7 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev, __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); - if (!test_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags)) { + if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_SW_SEQNO)) { /* * rt2800 has a H/W (or F/W) bug, device incorrectly increase * seqno on retransmited data (non-QOS) frames. To workaround @@ -484,7 +484,7 @@ static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, rt2x00crypto_create_tx_descriptor(rt2x00dev, skb, txdesc); rt2x00queue_create_tx_descriptor_seq(rt2x00dev, skb, txdesc); - if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_HT_TX_DESC)) rt2x00queue_create_tx_descriptor_ht(rt2x00dev, skb, txdesc, sta, hwrate); else @@ -526,7 +526,7 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry, /* * Map the skb to DMA. */ - if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags) && + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DMA) && rt2x00queue_map_txskb(entry)) return -ENOMEM; @@ -646,7 +646,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(REQUIRE_COPY_IV, &queue->rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(queue->rt2x00dev, REQUIRE_COPY_IV)) rt2x00crypto_tx_copy_iv(skb, &txdesc); else rt2x00crypto_tx_remove_iv(skb, &txdesc); @@ -660,9 +660,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(REQUIRE_L2PAD, &queue->rt2x00dev->cap_flags)) + if (rt2x00_has_cap_flag(queue->rt2x00dev, REQUIRE_L2PAD)) rt2x00queue_insert_l2pad(skb, txdesc.header_length); - else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags)) + else if (rt2x00_has_cap_flag(queue->rt2x00dev, REQUIRE_DMA)) rt2x00queue_align_frame(skb); /* @@ -1178,7 +1178,7 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev) if (status) goto exit; - if (test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) { + if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_ATIM_QUEUE)) { status = rt2x00queue_alloc_entries(rt2x00dev->atim); if (status) goto exit; @@ -1234,7 +1234,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; enum data_queue_qid qid; unsigned int req_atim = - !!test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); + rt2x00_has_cap_flag(rt2x00dev, REQUIRE_ATIM_QUEUE); /* * We need the following queues: diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 892270dd3e7b..7627af6098eb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -274,7 +274,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) * Schedule the delayed work for reading the TX status * from the device. */ - if (!test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags) || + if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_TXSTATUS_FIFO) || !kfifo_is_empty(&rt2x00dev->txstatus_fifo)) queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); } @@ -456,7 +456,7 @@ static bool rt2x00usb_flush_entry(struct queue_entry *entry, void *data) * Kill guardian urb (if required by driver). */ if ((entry->queue->qid == QID_BEACON) && - (test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags))) + (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_BEACON_GUARD))) usb_kill_urb(bcn_priv->guardian_urb); return false; @@ -655,7 +655,7 @@ static int rt2x00usb_alloc_entries(struct data_queue *queue) * then we are done. */ if (queue->qid != QID_BEACON || - !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags)) + !rt2x00_has_cap_flag(rt2x00dev, REQUIRE_BEACON_GUARD)) return 0; for (i = 0; i < queue->limit; i++) { @@ -690,7 +690,7 @@ static void rt2x00usb_free_entries(struct data_queue *queue) * then we are done. */ if (queue->qid != QID_BEACON || - !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags)) + !rt2x00_has_cap_flag(rt2x00dev, REQUIRE_BEACON_GUARD)) return; for (i = 0; i < queue->limit; i++) { diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 40b6d1d006d7..1d4677460711 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -867,63 +867,135 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw, * * B/G rate: * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92_RATE1M-->DESC92_RATE54M ==> idx is 0-->11, + * DESC_RATE1M-->DESC_RATE54M ==> idx is 0-->11, * * N rate: * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15 + * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15 * * 5G band:rx_status->band == IEEE80211_BAND_5GHZ * A rate: * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92_RATE6M-->DESC92_RATE54M ==> idx is 0-->7, + * DESC_RATE6M-->DESC_RATE54M ==> idx is 0-->7, * * N rate: * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15 + * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15 + * + * VHT rates: + * DESC_RATEVHT1SS_MCS0-->DESC_RATEVHT1SS_MCS9 ==> idx is 0-->9 + * DESC_RATEVHT2SS_MCS0-->DESC_RATEVHT2SS_MCS9 ==> idx is 0-->9 */ -int rtlwifi_rate_mapping(struct ieee80211_hw *hw, - bool isht, u8 desc_rate, bool first_ampdu) +int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, bool isvht, + u8 desc_rate) { int rate_idx; + if (isvht) { + switch (desc_rate) { + case DESC_RATEVHT1SS_MCS0: + rate_idx = 0; + break; + case DESC_RATEVHT1SS_MCS1: + rate_idx = 1; + break; + case DESC_RATEVHT1SS_MCS2: + rate_idx = 2; + break; + case DESC_RATEVHT1SS_MCS3: + rate_idx = 3; + break; + case DESC_RATEVHT1SS_MCS4: + rate_idx = 4; + break; + case DESC_RATEVHT1SS_MCS5: + rate_idx = 5; + break; + case DESC_RATEVHT1SS_MCS6: + rate_idx = 6; + break; + case DESC_RATEVHT1SS_MCS7: + rate_idx = 7; + break; + case DESC_RATEVHT1SS_MCS8: + rate_idx = 8; + break; + case DESC_RATEVHT1SS_MCS9: + rate_idx = 9; + break; + case DESC_RATEVHT2SS_MCS0: + rate_idx = 0; + break; + case DESC_RATEVHT2SS_MCS1: + rate_idx = 1; + break; + case DESC_RATEVHT2SS_MCS2: + rate_idx = 2; + break; + case DESC_RATEVHT2SS_MCS3: + rate_idx = 3; + break; + case DESC_RATEVHT2SS_MCS4: + rate_idx = 4; + break; + case DESC_RATEVHT2SS_MCS5: + rate_idx = 5; + break; + case DESC_RATEVHT2SS_MCS6: + rate_idx = 6; + break; + case DESC_RATEVHT2SS_MCS7: + rate_idx = 7; + break; + case DESC_RATEVHT2SS_MCS8: + rate_idx = 8; + break; + case DESC_RATEVHT2SS_MCS9: + rate_idx = 9; + break; + default: + rate_idx = 0; + break; + } + return rate_idx; + } if (false == isht) { if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { switch (desc_rate) { - case DESC92_RATE1M: + case DESC_RATE1M: rate_idx = 0; break; - case DESC92_RATE2M: + case DESC_RATE2M: rate_idx = 1; break; - case DESC92_RATE5_5M: + case DESC_RATE5_5M: rate_idx = 2; break; - case DESC92_RATE11M: + case DESC_RATE11M: rate_idx = 3; break; - case DESC92_RATE6M: + case DESC_RATE6M: rate_idx = 4; break; - case DESC92_RATE9M: + case DESC_RATE9M: rate_idx = 5; break; - case DESC92_RATE12M: + case DESC_RATE12M: rate_idx = 6; break; - case DESC92_RATE18M: + case DESC_RATE18M: rate_idx = 7; break; - case DESC92_RATE24M: + case DESC_RATE24M: rate_idx = 8; break; - case DESC92_RATE36M: + case DESC_RATE36M: rate_idx = 9; break; - case DESC92_RATE48M: + case DESC_RATE48M: rate_idx = 10; break; - case DESC92_RATE54M: + case DESC_RATE54M: rate_idx = 11; break; default: @@ -932,28 +1004,28 @@ int rtlwifi_rate_mapping(struct ieee80211_hw *hw, } } else { switch (desc_rate) { - case DESC92_RATE6M: + case DESC_RATE6M: rate_idx = 0; break; - case DESC92_RATE9M: + case DESC_RATE9M: rate_idx = 1; break; - case DESC92_RATE12M: + case DESC_RATE12M: rate_idx = 2; break; - case DESC92_RATE18M: + case DESC_RATE18M: rate_idx = 3; break; - case DESC92_RATE24M: + case DESC_RATE24M: rate_idx = 4; break; - case DESC92_RATE36M: + case DESC_RATE36M: rate_idx = 5; break; - case DESC92_RATE48M: + case DESC_RATE48M: rate_idx = 6; break; - case DESC92_RATE54M: + case DESC_RATE54M: rate_idx = 7; break; default: @@ -963,52 +1035,52 @@ int rtlwifi_rate_mapping(struct ieee80211_hw *hw, } } else { switch (desc_rate) { - case DESC92_RATEMCS0: + case DESC_RATEMCS0: rate_idx = 0; break; - case DESC92_RATEMCS1: + case DESC_RATEMCS1: rate_idx = 1; break; - case DESC92_RATEMCS2: + case DESC_RATEMCS2: rate_idx = 2; break; - case DESC92_RATEMCS3: + case DESC_RATEMCS3: rate_idx = 3; break; - case DESC92_RATEMCS4: + case DESC_RATEMCS4: rate_idx = 4; break; - case DESC92_RATEMCS5: + case DESC_RATEMCS5: rate_idx = 5; break; - case DESC92_RATEMCS6: + case DESC_RATEMCS6: rate_idx = 6; break; - case DESC92_RATEMCS7: + case DESC_RATEMCS7: rate_idx = 7; break; - case DESC92_RATEMCS8: + case DESC_RATEMCS8: rate_idx = 8; break; - case DESC92_RATEMCS9: + case DESC_RATEMCS9: rate_idx = 9; break; - case DESC92_RATEMCS10: + case DESC_RATEMCS10: rate_idx = 10; break; - case DESC92_RATEMCS11: + case DESC_RATEMCS11: rate_idx = 11; break; - case DESC92_RATEMCS12: + case DESC_RATEMCS12: rate_idx = 12; break; - case DESC92_RATEMCS13: + case DESC_RATEMCS13: rate_idx = 13; break; - case DESC92_RATEMCS14: + case DESC_RATEMCS14: rate_idx = 14; break; - case DESC92_RATEMCS15: + case DESC_RATEMCS15: rate_idx = 15; break; default: diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h index 982f2450feea..c6cb49c3ee32 100644 --- a/drivers/net/wireless/rtlwifi/base.h +++ b/drivers/net/wireless/rtlwifi/base.h @@ -123,8 +123,8 @@ 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); -int rtlwifi_rate_mapping(struct ieee80211_hw *hw, - bool isht, u8 desc_rate, bool first_ampdu); +int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, + bool isvht, u8 desc_rate); 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); diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 5fc6f52641bd..a31a12775f1a 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -95,7 +95,8 @@ void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data) } EXPORT_SYMBOL(rtl_bb_delay); -void rtl_fw_cb(const struct firmware *firmware, void *context) +static void rtl_fw_do_work(const struct firmware *firmware, void *context, + bool is_wow) { struct ieee80211_hw *hw = context; struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -125,12 +126,31 @@ found_alt: release_firmware(firmware); return; } - memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size); + if (!is_wow) { + memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, + firmware->size); + rtlpriv->rtlhal.fwsize = firmware->size; + } else { + memcpy(rtlpriv->rtlhal.wowlan_firmware, firmware->data, + firmware->size); + rtlpriv->rtlhal.wowlan_fwsize = firmware->size; + } rtlpriv->rtlhal.fwsize = firmware->size; release_firmware(firmware); } + +void rtl_fw_cb(const struct firmware *firmware, void *context) +{ + rtl_fw_do_work(firmware, context, false); +} EXPORT_SYMBOL(rtl_fw_cb); +void rtl_wowlan_fw_cb(const struct firmware *firmware, void *context) +{ + rtl_fw_do_work(firmware, context, true); +} +EXPORT_SYMBOL(rtl_wowlan_fw_cb); + /*mutex for start & stop is must here. */ static int rtl_op_start(struct ieee80211_hw *hw) { @@ -990,6 +1010,16 @@ static int rtl_op_conf_tx(struct ieee80211_hw *hw, return 0; } +static void send_beacon_frame(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct sk_buff *skb = ieee80211_beacon_get(hw, vif); + + if (skb) + rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, NULL); +} + static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -1020,6 +1050,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, if (rtlpriv->cfg->ops->linked_set_reg) rtlpriv->cfg->ops->linked_set_reg(hw); + send_beacon_frame(hw, vif); } } if ((changed & BSS_CHANGED_BEACON_ENABLED && @@ -1851,3 +1882,40 @@ bool rtl_btc_status_false(void) return false; } EXPORT_SYMBOL_GPL(rtl_btc_status_false); + +void rtl_dm_diginit(struct ieee80211_hw *hw, u32 cur_igvalue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *dm_digtable = &rtlpriv->dm_digtable; + + dm_digtable->dig_enable_flag = true; + dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + dm_digtable->cur_igvalue = cur_igvalue; + dm_digtable->pre_igvalue = 0; + dm_digtable->cur_sta_cstate = DIG_STA_DISCONNECT; + dm_digtable->presta_cstate = DIG_STA_DISCONNECT; + dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT; + dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; + dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; + dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; + dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; + dm_digtable->rx_gain_max = DM_DIG_MAX; + dm_digtable->rx_gain_min = DM_DIG_MIN; + dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; + dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; + dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; + dm_digtable->pre_cck_cca_thres = 0xff; + dm_digtable->cur_cck_cca_thres = 0x83; + dm_digtable->forbidden_igi = DM_DIG_MIN; + dm_digtable->large_fa_hit = 0; + dm_digtable->recover_cnt = 0; + dm_digtable->dig_min_0 = 0x25; + dm_digtable->dig_min_1 = 0x25; + dm_digtable->media_connect_0 = false; + dm_digtable->media_connect_1 = false; + rtlpriv->dm.dm_initialgain_enable = true; + dm_digtable->bt30_cur_igi = 0x32; + dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX; + dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_LOWRSSI; +} +EXPORT_SYMBOL(rtl_dm_diginit); diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h index 624e1dc16d31..7b64e34f421e 100644 --- a/drivers/net/wireless/rtlwifi/core.h +++ b/drivers/net/wireless/rtlwifi/core.h @@ -35,13 +35,55 @@ #define RTL_SUPPORTED_CTRL_FILTER 0xFF +#define DM_DIG_THRESH_HIGH 40 +#define DM_DIG_THRESH_LOW 35 +#define DM_FALSEALARM_THRESH_LOW 400 +#define DM_FALSEALARM_THRESH_HIGH 1000 + +#define DM_DIG_MAX 0x3e +#define DM_DIG_MIN 0x1e +#define DM_DIG_MAX_AP 0x32 +#define DM_DIG_BACKOFF_MAX 12 +#define DM_DIG_BACKOFF_MIN -4 +#define DM_DIG_BACKOFF_DEFAULT 10 + +enum cck_packet_detection_threshold { + CCK_PD_STAGE_LOWRSSI = 0, + CCK_PD_STAGE_HIGHRSSI = 1, + CCK_FA_STAGE_LOW = 2, + CCK_FA_STAGE_HIGH = 3, + CCK_PD_STAGE_MAX = 4, +}; + +enum dm_dig_ext_port_alg_e { + 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_dig_connect_e { + DIG_STA_DISCONNECT, + DIG_STA_CONNECT, + DIG_STA_BEFORE_CONNECT, + DIG_MULTISTA_DISCONNECT, + DIG_MULTISTA_CONNECT, + DIG_AP_DISCONNECT, + DIG_AP_CONNECT, + DIG_AP_ADD_STATION, + DIG_CONNECT_MAX +}; + extern const struct ieee80211_ops rtl_ops; void rtl_fw_cb(const struct firmware *firmware, void *context); +void rtl_wowlan_fw_cb(const struct firmware *firmware, void *context); void rtl_addr_delay(u32 addr); void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr, u32 mask, u32 data); void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data); bool rtl_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb); bool rtl_btc_status_false(void); +void rtl_dm_diginit(struct ieee80211_hw *hw, u32 cur_igval); #endif diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index c70efb9a6e78..ec456f0d972e 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -578,6 +578,13 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) else entry = (u8 *)(&ring->desc[ring->idx]); + if (rtlpriv->cfg->ops->get_available_desc && + rtlpriv->cfg->ops->get_available_desc(hw, prio) <= 1) { + RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_DMESG, + "no available desc!\n"); + return; + } + if (!rtlpriv->cfg->ops->is_tx_desc_closed(hw, prio, ring->idx)) return; ring->idx = (ring->idx + 1) % ring->entries; @@ -641,10 +648,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) ieee80211_tx_status_irqsafe(hw, skb); - if ((ring->entries - skb_queue_len(&ring->queue)) - == 2) { + if ((ring->entries - skb_queue_len(&ring->queue)) <= 4) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, + RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%x\n", prio, ring->idx, skb_queue_len(&ring->queue)); @@ -793,7 +799,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) rx_remained_cnt = rtlpriv->cfg->ops->rx_desc_buff_remained_cnt(hw, hw_queue); - if (rx_remained_cnt < 1) + if (rx_remained_cnt == 0) return; } else { /* rx descriptor */ @@ -848,18 +854,18 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) else skb_reserve(skb, stats.rx_drvinfo_size + stats.rx_bufshift); - } else { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "skb->end - skb->tail = %d, len is %d\n", skb->end - skb->tail, len); - break; + dev_kfree_skb_any(skb); + goto new_trx_end; } /* handle command packet here */ if (rtlpriv->cfg->ops->rx_command_packet && rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) { dev_kfree_skb_any(skb); - goto end; + goto new_trx_end; } /* @@ -909,6 +915,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) } else { dev_kfree_skb_any(skb); } +new_trx_end: if (rtlpriv->use_new_trx_flow) { rtlpci->rx_ring[hw_queue].next_rx_rp += 1; rtlpci->rx_ring[hw_queue].next_rx_rp %= @@ -924,7 +931,6 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) rtlpriv->enter_ps = false; schedule_work(&rtlpriv->works.lps_change_work); } -end: skb = new_skb; no_new: if (rtlpriv->use_new_trx_flow) { @@ -1688,6 +1694,15 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, } } + if (rtlpriv->cfg->ops->get_available_desc && + rtlpriv->cfg->ops->get_available_desc(hw, hw_queue) == 0) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "get_available_desc fail\n"); + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, + flags); + return skb->len; + } + if (ieee80211_is_data_qos(fc)) { tid = rtl_get_tid(skb); if (sta) { diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index 5e832306dba9..d4567d12e07e 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -325,4 +325,11 @@ static inline void pci_write32_async(struct rtl_priv *rtlpriv, writel(val, (u8 __iomem *) rtlpriv->io.pci_mem_start + addr); } +static inline u16 calc_fifo_space(u16 rp, u16 wp) +{ + if (rp <= wp) + return RTL_PCI_MAX_RX_COUNT - 1 + rp - wp; + return rp - wp - 1; +} + #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c index 2aa34d9055f0..d930c1f78721 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c @@ -26,6 +26,7 @@ #include "../wifi.h" #include "../base.h" #include "../pci.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -341,38 +342,6 @@ static void dm_tx_pwr_track_set_pwr(struct ieee80211_hw *hw, } } -static void rtl88e_dm_diginit(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *dm_dig = &rtlpriv->dm_digtable; - - dm_dig->dig_enable_flag = true; - dm_dig->cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f); - dm_dig->pre_igvalue = 0; - dm_dig->cur_sta_cstate = DIG_STA_DISCONNECT; - dm_dig->presta_cstate = DIG_STA_DISCONNECT; - dm_dig->curmultista_cstate = DIG_MULTISTA_DISCONNECT; - dm_dig->rssi_lowthresh = DM_DIG_THRESH_LOW; - dm_dig->rssi_highthresh = DM_DIG_THRESH_HIGH; - dm_dig->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - dm_dig->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - dm_dig->rx_gain_max = DM_DIG_MAX; - dm_dig->rx_gain_min = DM_DIG_MIN; - dm_dig->back_val = DM_DIG_BACKOFF_DEFAULT; - dm_dig->back_range_max = DM_DIG_BACKOFF_MAX; - dm_dig->back_range_min = DM_DIG_BACKOFF_MIN; - dm_dig->pre_cck_cca_thres = 0xff; - dm_dig->cur_cck_cca_thres = 0x83; - dm_dig->forbidden_igi = DM_DIG_MIN; - dm_dig->large_fa_hit = 0; - dm_dig->recover_cnt = 0; - dm_dig->dig_min_0 = 0x25; - dm_dig->dig_min_1 = 0x25; - dm_dig->media_connect_0 = false; - dm_dig->media_connect_1 = false; - rtlpriv->dm.dm_initialgain_enable = true; -} - static u8 rtl88e_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1796,9 +1765,10 @@ static void rtl88e_dm_antenna_diversity(struct ieee80211_hw *hw) void rtl88e_dm_init(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f); rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; - rtl88e_dm_diginit(hw); + rtl_dm_diginit(hw, cur_igvalue); rtl88e_dm_init_dynamic_txpower(hw); rtl88e_dm_init_edca_turbo(hw); rtl88e_dm_init_rate_adaptive_mask(hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h index 64f1f3ea9807..071ccee69eae 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h @@ -186,28 +186,12 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1e - -#define DM_DIG_MAX_AP 0x32 -#define DM_DIG_MIN_AP 0x20 - #define DM_DIG_FA_UPPER 0x3e #define DM_DIG_FA_LOWER 0x1e #define DM_DIG_FA_TH0 0x200 #define DM_DIG_FA_TH1 0x300 #define DM_DIG_FA_TH2 0x400 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_W 30 #define RXPATHSELECTION_DIFF_TH 18 @@ -262,14 +246,6 @@ enum tag_dynamic_init_gain_operation_type_definition { DIG_OP_TYPE_MAX }; -enum tag_cck_packet_detection_threshold_type_definition { - CCK_PD_STAGE_LOWRSSI = 0, - CCK_PD_STAGE_HIGHRSSI = 1, - CCK_FA_STAGE_LOW = 2, - CCK_FA_STAGE_HIGH = 3, - CCK_PD_STAGE_MAX = 4, -}; - enum dm_1r_cca_e { CCA_1R = 0, CCA_2R = 1, @@ -288,23 +264,6 @@ enum dm_sw_ant_switch_e { ANS_ANTENNA_MAX = 3, }; -enum dm_dig_ext_port_alg_e { - 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_dig_connect_e { - DIG_STA_DISCONNECT = 0, - DIG_STA_CONNECT = 1, - DIG_STA_BEFORE_CONNECT = 2, - DIG_MULTISTA_DISCONNECT = 3, - DIG_MULTISTA_CONNECT = 4, - DIG_CONNECT_MAX -}; - enum pwr_track_control_method { BBSWING, TXAGC diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c index df549c96adef..791efbe6b18c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c @@ -47,164 +47,6 @@ static u8 _rtl88ee_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -/* mac80211's rate_idx is like this: - * - * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ - * - * B/G rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - * - * 5G band:rx_status->band == IEEE80211_BAND_5GHZ - * A rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - */ -static int _rtl88ee_rate_mapping(struct ieee80211_hw *hw, - bool isht, u8 desc_rate) -{ - int rate_idx; - - if (!isht) { - if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { - switch (desc_rate) { - case DESC92C_RATE1M: - rate_idx = 0; - break; - case DESC92C_RATE2M: - rate_idx = 1; - break; - case DESC92C_RATE5_5M: - rate_idx = 2; - break; - case DESC92C_RATE11M: - rate_idx = 3; - break; - case DESC92C_RATE6M: - rate_idx = 4; - break; - case DESC92C_RATE9M: - rate_idx = 5; - break; - case DESC92C_RATE12M: - rate_idx = 6; - break; - case DESC92C_RATE18M: - rate_idx = 7; - break; - case DESC92C_RATE24M: - rate_idx = 8; - break; - case DESC92C_RATE36M: - rate_idx = 9; - break; - case DESC92C_RATE48M: - rate_idx = 10; - break; - case DESC92C_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 0; - break; - } - } else { - switch (desc_rate) { - case DESC92C_RATE6M: - rate_idx = 0; - break; - case DESC92C_RATE9M: - rate_idx = 1; - break; - case DESC92C_RATE12M: - rate_idx = 2; - break; - case DESC92C_RATE18M: - rate_idx = 3; - break; - case DESC92C_RATE24M: - rate_idx = 4; - break; - case DESC92C_RATE36M: - rate_idx = 5; - break; - case DESC92C_RATE48M: - rate_idx = 6; - break; - case DESC92C_RATE54M: - rate_idx = 7; - break; - default: - rate_idx = 0; - break; - } - } - } else { - switch (desc_rate) { - case DESC92C_RATEMCS0: - rate_idx = 0; - break; - case DESC92C_RATEMCS1: - rate_idx = 1; - break; - case DESC92C_RATEMCS2: - rate_idx = 2; - break; - case DESC92C_RATEMCS3: - rate_idx = 3; - break; - case DESC92C_RATEMCS4: - rate_idx = 4; - break; - case DESC92C_RATEMCS5: - rate_idx = 5; - break; - case DESC92C_RATEMCS6: - rate_idx = 6; - break; - case DESC92C_RATEMCS7: - rate_idx = 7; - break; - case DESC92C_RATEMCS8: - rate_idx = 8; - break; - case DESC92C_RATEMCS9: - rate_idx = 9; - break; - case DESC92C_RATEMCS10: - rate_idx = 10; - break; - case DESC92C_RATEMCS11: - rate_idx = 11; - break; - case DESC92C_RATEMCS12: - rate_idx = 12; - break; - case DESC92C_RATEMCS13: - rate_idx = 13; - break; - case DESC92C_RATEMCS14: - rate_idx = 14; - break; - case DESC92C_RATEMCS15: - rate_idx = 15; - break; - default: - rate_idx = 0; - break; - } - } - return rate_idx; -} - static void _rtl88ee_query_rxphystatus(struct ieee80211_hw *hw, struct rtl_stats *pstatus, u8 *pdesc, struct rx_fwinfo_88e *p_drvinfo, @@ -630,8 +472,8 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw, * are use (RX_FLAG_HT) * Notice: this is diff with windows define */ - rx_status->rate_idx = _rtl88ee_rate_mapping(hw, - status->is_ht, status->rate); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, + false, status->rate); rx_status->mactime = status->timestamp_low; if (phystatus == true) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index f6cb5aedfdd1..f5ee67cda73a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -32,6 +32,7 @@ #include "phy_common.h" #include "../pci.h" #include "../base.h" +#include "../core.h" #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) @@ -194,36 +195,6 @@ void dm_savepowerindex(struct ieee80211_hw *hw) } EXPORT_SYMBOL_GPL(dm_savepowerindex); -static void rtl92c_dm_diginit(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *dm_digtable = &rtlpriv->dm_digtable; - - dm_digtable->dig_enable_flag = true; - dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; - dm_digtable->cur_igvalue = 0x20; - dm_digtable->pre_igvalue = 0x0; - dm_digtable->cursta_cstate = DIG_STA_DISCONNECT; - dm_digtable->presta_cstate = DIG_STA_DISCONNECT; - dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT; - dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; - dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; - dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - dm_digtable->rx_gain_max = DM_DIG_MAX; - dm_digtable->rx_gain_min = DM_DIG_MIN; - dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; - dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; - dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; - dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX; - dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_LowRssi; - - dm_digtable->forbidden_igi = DM_DIG_MIN; - dm_digtable->large_fa_hit = 0; - dm_digtable->recover_cnt = 0; - dm_digtable->dig_dynamic_min = 0x25; -} - static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -507,27 +478,27 @@ static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) if (dm_digtable->rssi_val_min > 100) dm_digtable->rssi_val_min = 100; - if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) { + if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { if (dm_digtable->rssi_val_min <= 25) dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_LowRssi; + CCK_PD_STAGE_LOWRSSI; else dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_HighRssi; + CCK_PD_STAGE_HIGHRSSI; } else { if (dm_digtable->rssi_val_min <= 20) dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_LowRssi; + CCK_PD_STAGE_LOWRSSI; else dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_HighRssi; + CCK_PD_STAGE_HIGHRSSI; } } else { dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; } if (dm_digtable->pre_cck_pd_state != dm_digtable->cur_cck_pd_state) { - if ((dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) || + if ((dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI) || (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_MAX)) rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x83); else @@ -1374,7 +1345,7 @@ void rtl92c_dm_init(struct ieee80211_hw *hw) rtlpriv->dm.undec_sm_pwdb = -1; rtlpriv->dm.undec_sm_cck = -1; rtlpriv->dm.dm_initialgain_enable = true; - rtl92c_dm_diginit(hw); + rtl_dm_diginit(hw, 0x20); rtlpriv->dm.dm_flag |= HAL_DM_HIPWR_DISABLE; rtl92c_dm_init_dynamic_txpower(hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h index 4f232a063636..4422e31fedd9 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h @@ -47,25 +47,12 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1e - #define DM_DIG_FA_UPPER 0x32 #define DM_DIG_FA_LOWER 0x20 #define DM_DIG_FA_TH0 0x20 #define DM_DIG_FA_TH1 0x100 #define DM_DIG_FA_TH2 0x200 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_lOW 30 #define RXPATHSELECTION_DIFF_TH 18 @@ -123,14 +110,6 @@ enum tag_dynamic_init_gain_operation_type_definition { DIG_OP_TYPE_MAX }; -enum tag_cck_packet_detection_threshold_type_definition { - CCK_PD_STAGE_LowRssi = 0, - CCK_PD_STAGE_HighRssi = 1, - CCK_FA_STAGE_Low = 2, - CCK_FA_STAGE_High = 3, - CCK_PD_STAGE_MAX = 4, -}; - enum dm_1r_cca_e { CCA_1R = 0, CCA_2R = 1, @@ -149,23 +128,6 @@ enum dm_sw_ant_switch_e { ANS_ANTENNA_MAX = 3, }; -enum dm_dig_ext_port_alg_e { - 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_dig_connect_e { - DIG_STA_DISCONNECT = 0, - DIG_STA_CONNECT = 1, - DIG_STA_BEFORE_CONNECT = 2, - DIG_MULTISTA_DISCONNECT = 3, - DIG_MULTISTA_CONNECT = 4, - DIG_CONNECT_MAX -}; - void rtl92c_dm_init(struct ieee80211_hw *hw); void rtl92c_dm_watchdog(struct ieee80211_hw *hw); void rtl92c_dm_write_dig(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h index b64ae45dc674..e9f4281f5067 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h @@ -37,6 +37,7 @@ #define FW_8192C_POLLING_DELAY 5 #define FW_8192C_POLLING_TIMEOUT_COUNT 100 #define NORMAL_CHIP BIT(4) +#define H2C_92C_KEEP_ALIVE_CTRL 48 #define IS_FW_HEADER_EXIST(_pfwhdr) \ ((le16_to_cpu(_pfwhdr->signature)&0xFFF0) == 0x92C0 ||\ diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c index 74f9c083b80d..09898cf2e07a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c @@ -30,6 +30,7 @@ #include "../wifi.h" #include "../base.h" #include "../pci.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h index 9c5311c299fd..38ba707015f5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h @@ -42,25 +42,12 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1e - #define DM_DIG_FA_UPPER 0x32 #define DM_DIG_FA_LOWER 0x20 #define DM_DIG_FA_TH0 0x20 #define DM_DIG_FA_TH1 0x100 #define DM_DIG_FA_TH2 0x200 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_lOW 30 #define RXPATHSELECTION_DIFF_TH 18 diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index 5c646d5f7bb8..303b299376c9 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -544,8 +544,13 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) (u8 *)(&fw_current_inps)); } break; } - case HW_VAR_KEEP_ALIVE: - break; + case HW_VAR_KEEP_ALIVE: { + u8 array[2]; + + array[0] = 0xff; + array[1] = *((u8 *)val); + rtl92c_fill_h2c_cmd(hw, H2C_92C_KEEP_ALIVE_CTRL, 2, array); + break; } default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "switch case %d not processed\n", variable); @@ -1156,47 +1161,35 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); u8 bt_msr = rtl_read_byte(rtlpriv, MSR); enum led_ctl_mode ledaction = LED_CTL_NO_LINK; - bt_msr &= 0xfc; + u8 mode = MSR_NOLINK; - if (type == NL80211_IFTYPE_UNSPECIFIED || - type == NL80211_IFTYPE_STATION) { - _rtl92ce_stop_tx_beacon(hw); - _rtl92ce_enable_bcn_sub_func(hw); - } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP || - type == NL80211_IFTYPE_MESH_POINT) { - _rtl92ce_resume_tx_beacon(hw); - _rtl92ce_disable_bcn_sub_func(hw); - } else { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - "Set HW_VAR_MEDIA_STATUS: No such media status(%x)\n", - type); - } + bt_msr &= 0xfc; switch (type) { case NL80211_IFTYPE_UNSPECIFIED: - bt_msr |= MSR_NOLINK; - ledaction = LED_CTL_LINK; + mode = MSR_NOLINK; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Set Network type to NO LINK!\n"); break; case NL80211_IFTYPE_ADHOC: - bt_msr |= MSR_ADHOC; + mode = MSR_ADHOC; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Set Network type to Ad Hoc!\n"); break; case NL80211_IFTYPE_STATION: - bt_msr |= MSR_INFRA; + mode = MSR_INFRA; 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_AP; + mode = MSR_AP; + ledaction = LED_CTL_LINK; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Set Network type to AP!\n"); break; case NL80211_IFTYPE_MESH_POINT: - bt_msr |= MSR_ADHOC; + mode = MSR_ADHOC; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Set Network type to Mesh Point!\n"); break; @@ -1207,9 +1200,32 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, } - rtl_write_byte(rtlpriv, (MSR), bt_msr); + /* MSR_INFRA == Link in infrastructure network; + * MSR_ADHOC == Link in ad hoc network; + * Therefore, check link state is necessary. + * + * MSR_AP == AP mode; link state does not matter here. + */ + if (mode != MSR_AP && + rtlpriv->mac80211.link_state < MAC80211_LINKED) { + mode = MSR_NOLINK; + ledaction = LED_CTL_NO_LINK; + } + if (mode == MSR_NOLINK || mode == MSR_INFRA) { + _rtl92ce_stop_tx_beacon(hw); + _rtl92ce_enable_bcn_sub_func(hw); + } else if (mode == MSR_ADHOC || mode == MSR_AP) { + _rtl92ce_resume_tx_beacon(hw); + _rtl92ce_disable_bcn_sub_func(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n", + mode); + } + rtl_write_byte(rtlpriv, MSR, bt_msr | mode); + rtlpriv->cfg->ops->led_control(hw, ledaction); - if ((bt_msr & MSR_MASK) == MSR_AP) + if (mode == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); else rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); @@ -1833,7 +1849,6 @@ static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw, u32 ratr_value; u8 ratr_index = 0; u8 nmode = mac->ht_enable; - u8 mimo_ps = IEEE80211_SMPS_OFF; u16 shortgi_rate; u32 tmp_ratr_value; u8 curtxbw_40mhz = mac->bw_40; @@ -1842,6 +1857,7 @@ static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw, u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? 1 : 0; enum wireless_mode wirelessmode = mac->mode; + u32 ratr_mask; if (rtlhal->current_bandtype == BAND_ON_5G) ratr_value = sta->supp_rates[1] << 4; @@ -1865,19 +1881,13 @@ static 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 == IEEE80211_SMPS_STATIC) { - ratr_value &= 0x0007F005; - } else { - u32 ratr_mask; + if (get_rf_type(rtlphy) == RF_1T2R || + get_rf_type(rtlphy) == RF_1T1R) + ratr_mask = 0x000ff005; + else + ratr_mask = 0x0f0ff005; - if (get_rf_type(rtlphy) == RF_1T2R || - get_rf_type(rtlphy) == RF_1T1R) - ratr_mask = 0x000ff005; - else - ratr_mask = 0x0f0ff005; - - ratr_value &= ratr_mask; - } + ratr_value &= ratr_mask; break; default: if (rtlphy->rf_type == RF_1T2R) @@ -1930,17 +1940,16 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, struct rtl_sta_info *sta_entry = NULL; u32 ratr_bitmap; u8 ratr_index; - u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; - u8 curshortgi_40mhz = curtxbw_40mhz && - (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? - 1 : 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; u8 rate_mask[5]; u8 macid = 0; - u8 mimo_ps = IEEE80211_SMPS_OFF; sta_entry = (struct rtl_sta_info *) sta->drv_priv; wirelessmode = sta_entry->wireless_mode; @@ -1985,47 +1994,38 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, case WIRELESS_MODE_N_5G: 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 (curtxbw_40mhz) { - if (rssi_level == 1) - ratr_bitmap &= 0x000f0000; - else if (rssi_level == 2) - ratr_bitmap &= 0x000ff000; - else - ratr_bitmap &= 0x000ff015; - } else { - if (rssi_level == 1) - ratr_bitmap &= 0x000f0000; - else if (rssi_level == 2) - ratr_bitmap &= 0x000ff000; - else - ratr_bitmap &= 0x000ff005; - } + if (rtlphy->rf_type == RF_1T2R || + rtlphy->rf_type == RF_1T1R) { + if (curtxbw_40mhz) { + if (rssi_level == 1) + ratr_bitmap &= 0x000f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x000ff000; + else + ratr_bitmap &= 0x000ff015; } else { - if (curtxbw_40mhz) { - if (rssi_level == 1) - ratr_bitmap &= 0x0f0f0000; - else if (rssi_level == 2) - ratr_bitmap &= 0x0f0ff000; - else - ratr_bitmap &= 0x0f0ff015; - } else { - if (rssi_level == 1) - ratr_bitmap &= 0x0f0f0000; - else if (rssi_level == 2) - ratr_bitmap &= 0x0f0ff000; - else - ratr_bitmap &= 0x0f0ff005; - } + if (rssi_level == 1) + ratr_bitmap &= 0x000f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x000ff000; + else + ratr_bitmap &= 0x000ff005; + } + } else { + if (curtxbw_40mhz) { + if (rssi_level == 1) + ratr_bitmap &= 0x0f0f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0f0ff000; + else + ratr_bitmap &= 0x0f0ff015; + } else { + if (rssi_level == 1) + ratr_bitmap &= 0x0f0f0000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0f0ff000; + else + ratr_bitmap &= 0x0f0ff005; } } @@ -2058,9 +2058,6 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, "Rate_index:%x, ratr_val:%x, %5phC\n", ratr_index, ratr_bitmap, rate_mask); 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, diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c index bc5ca989b915..1ee5a6ae9960 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c @@ -518,11 +518,12 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, } case ERFSLEEP:{ if (ppsc->rfpwr_state == ERFOFF) - return false; + 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) { + if (queue_id == BEACON_QUEUE || + skb_queue_len(&ring->queue) == 0) { queue_id++; continue; } else { diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index dd5aa089126a..de6cb6c3a48c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -334,21 +334,21 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = { .maps[RTL_IMR_ROK] = IMR_ROK, .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), - .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, - .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, - .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, - .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, - .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, - .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, - .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, - .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, - .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, - .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, - .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, - .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, + .maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC_RATE54M, - .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, - .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, + .maps[RTL_RC_HT_RATEMCS7] = DESC_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15, }; static const struct pci_device_id rtl92ce_pci_ids[] = { diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index e88dcd0e0af1..84ddd4d07a1d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -257,8 +257,8 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw, pstats->recvsignalpower = rx_pwr_all; /* (3)EVM of HT rate */ - if (pstats->is_ht && pstats->rate >= DESC92_RATEMCS8 && - pstats->rate <= DESC92_RATEMCS15) + if (pstats->is_ht && pstats->rate >= DESC_RATEMCS8 && + pstats->rate <= DESC_RATEMCS15) max_spatial_stream = 2; else max_spatial_stream = 1; @@ -400,9 +400,8 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, * are use (RX_FLAG_HT) * Notice: this is diff with windows define */ - rx_status->rate_idx = rtlwifi_rate_mapping(hw, - stats->is_ht, stats->rate, - stats->isfirst_ampdu); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht, + false, stats->rate); rx_status->mactime = stats->timestamp_low; if (phystatus) { @@ -501,7 +500,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RTS_BW(pdesc, 0); SET_TX_DESC_RTS_SC(pdesc, tcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(pdesc, - ((tcb_desc->rts_rate <= DESC92_RATE54M) ? + ((tcb_desc->rts_rate <= DESC_RATE54M) ? (tcb_desc->rts_use_shortpreamble ? 1 : 0) : (tcb_desc->rts_use_shortgi ? 1 : 0))); @@ -624,7 +623,7 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, if (firstseg) SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); - SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M); + SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M); SET_TX_DESC_SEQ(pdesc, 0); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 551321728ae0..fe4b699a12f5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -1000,6 +1000,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) local_save_flags(flags); local_irq_enable(); + rtlhal->fw_ready = false; rtlhal->hw_type = HARDWARE_TYPE_RTL8192CU; err = _rtl92cu_init_mac(hw); if (err) { @@ -1013,6 +1014,8 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw) err = 1; goto exit; } + + rtlhal->fw_ready = true; rtlhal->last_hmeboxnum = 0; /* h2c */ _rtl92cu_phy_param_tab_init(hw); rtl92cu_phy_mac_config(hw); @@ -1509,6 +1512,7 @@ void rtl92cu_set_beacon_related_registers(struct ieee80211_hw *hw) /* TODO: Modify later (Find the right parameters) * NOTE: Fix test chip's bug (about contention windows's randomness) */ if ((mac->opmode == NL80211_IFTYPE_ADHOC) || + (mac->opmode == NL80211_IFTYPE_MESH_POINT) || (mac->opmode == NL80211_IFTYPE_AP)) { rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x50); rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x50); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index c2d8ec6afcda..133e395b7401 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -880,8 +880,8 @@ static void _rtl92c_query_rxphystatus(struct ieee80211_hw *hw, pstats->rxpower = rx_pwr_all; pstats->recvsignalpower = rx_pwr_all; if (GET_RX_DESC_RX_MCS(pdesc) && - GET_RX_DESC_RX_MCS(pdesc) >= DESC92_RATEMCS8 && - GET_RX_DESC_RX_MCS(pdesc) <= DESC92_RATEMCS15) + GET_RX_DESC_RX_MCS(pdesc) >= DESC_RATEMCS8 && + GET_RX_DESC_RX_MCS(pdesc) <= DESC_RATEMCS15) max_spatial_stream = 2; else max_spatial_stream = 1; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index e06bafee37f9..90a714c189a8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -257,20 +257,20 @@ static struct rtl_hal_cfg rtl92cu_hal_cfg = { .maps[RTL_IMR_ROK] = IMR_ROK, .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), - .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, - .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, - .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, - .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, - .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, - .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, - .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, - .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, - .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, - .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, - .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, - .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, - .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, - .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, + .maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC_RATE54M, + .maps[RTL_RC_HT_RATEMCS7] = DESC_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15, }; #define USB_VENDER_ID_REALTEK 0x0bda diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index f383d5f1fed5..cbead007171f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -325,6 +325,7 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw, && (GET_RX_DESC_FAGGR(pdesc) == 1)); stats->timestamp_low = GET_RX_DESC_TSFL(pdesc); stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc); + stats->is_ht = (bool)GET_RX_DESC_RX_HT(pdesc); rx_status->freq = hw->conf.chandef.chan->center_freq; rx_status->band = hw->conf.chandef.chan->band; if (GET_RX_DESC_CRC32(pdesc)) @@ -338,10 +339,8 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw, rx_status->flag |= RX_FLAG_MACTIME_START; if (stats->decrypted) rx_status->flag |= RX_FLAG_DECRYPTED; - rx_status->rate_idx = rtlwifi_rate_mapping(hw, - (bool)GET_RX_DESC_RX_HT(pdesc), - (u8)GET_RX_DESC_RX_MCS(pdesc), - (bool)GET_RX_DESC_PAGGR(pdesc)); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht, + false, stats->rate); rx_status->mactime = GET_RX_DESC_TSFL(pdesc); if (phystatus) { p_drvinfo = (struct rx_fwinfo_92c *)(skb->data + @@ -393,6 +392,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) && (GET_RX_DESC_FAGGR(rxdesc) == 1)); stats.timestamp_low = GET_RX_DESC_TSFL(rxdesc); stats.rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(rxdesc); + stats.is_ht = (bool)GET_RX_DESC_RX_HT(rxdesc); /* TODO: is center_freq changed when doing scan? */ /* TODO: Shall we add protection or just skip those two step? */ rx_status->freq = hw->conf.chandef.chan->center_freq; @@ -406,10 +406,8 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) if (GET_RX_DESC_RX_HT(rxdesc)) rx_status->flag |= RX_FLAG_HT; /* Data rate */ - rx_status->rate_idx = rtlwifi_rate_mapping(hw, - (bool)GET_RX_DESC_RX_HT(rxdesc), - (u8)GET_RX_DESC_RX_MCS(rxdesc), - (bool)GET_RX_DESC_PAGGR(rxdesc)); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats.is_ht, + false, stats.rate); /* There is a phy status after this rx descriptor. */ if (GET_RX_DESC_PHY_STATUS(rxdesc)) { p_drvinfo = (struct rx_fwinfo_92c *)(rxdesc + RTL_RX_DESC_SIZE); @@ -545,7 +543,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RTS_BW(txdesc, 0); SET_TX_DESC_RTS_SC(txdesc, tcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(txdesc, - ((tcb_desc->rts_rate <= DESC92_RATE54M) ? + ((tcb_desc->rts_rate <= DESC_RATE54M) ? (tcb_desc->rts_use_shortpreamble ? 1 : 0) : (tcb_desc->rts_use_shortgi ? 1 : 0))); if (mac->bw_40) { @@ -644,7 +642,7 @@ void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc, } SET_TX_DESC_USE_RATE(pDesc, 1); /* use data rate which is set by Sw */ SET_TX_DESC_OWN(pDesc, 1); - SET_TX_DESC_TX_RATE(pDesc, DESC92_RATE1M); + SET_TX_DESC_TX_RATE(pDesc, DESC_RATE1M); _rtl_tx_desc_checksum(pDesc); } @@ -660,7 +658,7 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, memset((void *)pdesc, 0, RTL_TX_HEADER_SIZE); if (firstseg) SET_TX_DESC_OFFSET(pdesc, RTL_TX_HEADER_SIZE); - SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M); + SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M); SET_TX_DESC_SEQ(pdesc, 0); SET_TX_DESC_LINIP(pdesc, 0); SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c index 304c443b89b2..a1be5a68edfb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c @@ -29,6 +29,7 @@ #include "../wifi.h" #include "../base.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -155,34 +156,6 @@ static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB */ }; -static void rtl92d_dm_diginit(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *de_digtable = &rtlpriv->dm_digtable; - - de_digtable->dig_enable_flag = true; - de_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; - de_digtable->cur_igvalue = 0x20; - de_digtable->pre_igvalue = 0x0; - de_digtable->cursta_cstate = DIG_STA_DISCONNECT; - de_digtable->presta_cstate = DIG_STA_DISCONNECT; - de_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT; - de_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; - de_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; - de_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - de_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - de_digtable->rx_gain_max = DM_DIG_FA_UPPER; - de_digtable->rx_gain_min = DM_DIG_FA_LOWER; - de_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; - de_digtable->back_range_max = DM_DIG_BACKOFF_MAX; - de_digtable->back_range_min = DM_DIG_BACKOFF_MIN; - de_digtable->pre_cck_pd_state = CCK_PD_STAGE_LOWRSSI; - de_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; - de_digtable->large_fa_hit = 0; - de_digtable->recover_cnt = 0; - de_digtable->forbidden_igi = DM_DIG_FA_LOWER; -} - static void rtl92d_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) { u32 ret_value; @@ -1305,7 +1278,9 @@ void rtl92d_dm_init(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; - rtl92d_dm_diginit(hw); + rtl_dm_diginit(hw, 0x20); + rtlpriv->dm_digtable.rx_gain_max = DM_DIG_FA_UPPER; + rtlpriv->dm_digtable.rx_gain_min = DM_DIG_FA_LOWER; rtl92d_dm_init_dynamic_txpower(hw); rtl92d_dm_init_edca_turbo(hw); rtl92d_dm_init_rate_adaptive_mask(hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.h b/drivers/net/wireless/rtlwifi/rtl8192de/dm.h index 3fea0c11c24a..f2d318ceeb28 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.h @@ -42,25 +42,12 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1c - #define DM_DIG_FA_UPPER 0x32 #define DM_DIG_FA_LOWER 0x20 #define DM_DIG_FA_TH0 0x100 #define DM_DIG_FA_TH1 0x400 #define DM_DIG_FA_TH2 0x600 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_lOW 30 #define RXPATHSELECTION_DIFF_TH 18 @@ -108,14 +95,6 @@ enum tag_dynamic_init_gain_operation_type_definition { DIG_OP_TYPE_MAX }; -enum tag_cck_packet_detection_threshold_type_definition { - CCK_PD_STAGE_LOWRSSI = 0, - CCK_PD_STAGE_HIGHRSSI = 1, - CCK_FA_STAGE_LOW = 2, - CCK_FA_STAGE_HIGH = 3, - CCK_PD_STAGE_MAX = 4, -}; - enum dm_1r_cca { CCA_1R = 0, CCA_2R = 1, @@ -134,23 +113,6 @@ enum dm_sw_ant_switch { ANS_ANTENNA_MAX = 3, }; -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_dig_connect { - DIG_STA_DISCONNECT = 0, - DIG_STA_CONNECT = 1, - DIG_STA_BEFORE_CONNECT = 2, - DIG_MULTISTA_DISCONNECT = 3, - DIG_MULTISTA_CONNECT = 4, - DIG_CONNECT_MAX -}; - void rtl92d_dm_init(struct ieee80211_hw *hw); void rtl92d_dm_watchdog(struct ieee80211_hw *hw); void rtl92d_dm_init_edca_turbo(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c index 23177076b97f..62ef8209718f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c @@ -540,23 +540,6 @@ void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw, return; } -void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 u1_h2c_set_pwrmode[3] = { 0 }; - struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode); - SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode); - SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1); - SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode, - ppsc->reg_max_lps_awakeintvl); - RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, - "rtl92d_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode", - u1_h2c_set_pwrmode, 3); - rtl92d_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode); -} - static bool _rtl92d_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.h b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h index a55a803a0b4d..1646e7c3d0f8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/fw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h @@ -136,7 +136,6 @@ int rtl92d_download_fw(struct ieee80211_hw *hw); void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); void rtl92d_firmware_selfreset(struct ieee80211_hw *hw); -void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c index 280c3da42993..01bcc2d218dc 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c @@ -546,7 +546,7 @@ static bool _rtl92de_llt_table_init(struct ieee80211_hw *hw) txpktbuf_bndy = 246; value8 = 0; value32 = 0x80bf0d29; - } else if (rtlpriv->rtlhal.macphymode != SINGLEMAC_SINGLEPHY) { + } else { maxPage = 127; txpktbuf_bndy = 123; value8 = 0; diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c index a0aba088259a..b19d0398215f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c @@ -337,21 +337,21 @@ static struct rtl_hal_cfg rtl92de_hal_cfg = { .maps[RTL_IMR_ROK] = IMR_ROK, .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), - .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, - .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, - .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, - .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, - .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, - .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, - .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, - .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, - .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, - .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, - .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, - .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, + .maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC_RATE54M, - .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, - .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, + .maps[RTL_RC_HT_RATEMCS7] = DESC_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15, }; static struct pci_device_id rtl92de_pci_ids[] = { diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c index 8efbcc7af250..1feaa629dd4f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c @@ -235,8 +235,8 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw, pstats->rx_pwdb_all = pwdb_all; pstats->rxpower = rx_pwr_all; pstats->recvsignalpower = rx_pwr_all; - if (pdesc->rxht && pdesc->rxmcs >= DESC92_RATEMCS8 && - pdesc->rxmcs <= DESC92_RATEMCS15) + if (pdesc->rxht && pdesc->rxmcs >= DESC_RATEMCS8 && + pdesc->rxmcs <= DESC_RATEMCS15) max_spatial_stream = 2; else max_spatial_stream = 1; @@ -499,6 +499,7 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, && (GET_RX_DESC_FAGGR(pdesc) == 1)); stats->timestamp_low = GET_RX_DESC_TSFL(pdesc); stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc); + stats->is_ht = (bool)GET_RX_DESC_RXHT(pdesc); rx_status->freq = hw->conf.chandef.chan->center_freq; rx_status->band = hw->conf.chandef.chan->band; if (GET_RX_DESC_CRC32(pdesc)) @@ -512,10 +513,8 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, rx_status->flag |= RX_FLAG_MACTIME_START; if (stats->decrypted) rx_status->flag |= RX_FLAG_DECRYPTED; - rx_status->rate_idx = rtlwifi_rate_mapping(hw, - (bool)GET_RX_DESC_RXHT(pdesc), - (u8)GET_RX_DESC_RXMCS(pdesc), - (bool)GET_RX_DESC_PAGGR(pdesc)); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht, + false, stats->rate); rx_status->mactime = GET_RX_DESC_TSFL(pdesc); if (phystatus) { p_drvinfo = (struct rx_fwinfo_92d *)(skb->data + @@ -612,14 +611,14 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, } /* 5G have no CCK rate */ if (rtlhal->current_bandtype == BAND_ON_5G) - if (ptcb_desc->hw_rate < DESC92_RATE6M) - ptcb_desc->hw_rate = DESC92_RATE6M; + if (ptcb_desc->hw_rate < DESC_RATE6M) + ptcb_desc->hw_rate = DESC_RATE6M; SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble) SET_TX_DESC_DATA_SHORTGI(pdesc, 1); if (rtlhal->macphymode == DUALMAC_DUALPHY && - ptcb_desc->hw_rate == DESC92_RATEMCS7) + ptcb_desc->hw_rate == DESC_RATEMCS7) SET_TX_DESC_DATA_SHORTGI(pdesc, 1); if (info->flags & IEEE80211_TX_CTL_AMPDU) { @@ -635,13 +634,13 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0)); /* 5G have no CCK rate */ if (rtlhal->current_bandtype == BAND_ON_5G) - if (ptcb_desc->rts_rate < DESC92_RATE6M) - ptcb_desc->rts_rate = DESC92_RATE6M; + if (ptcb_desc->rts_rate < DESC_RATE6M) + ptcb_desc->rts_rate = DESC_RATE6M; SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); SET_TX_DESC_RTS_BW(pdesc, 0); SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <= - DESC92_RATE54M) ? + DESC_RATE54M) ? (ptcb_desc->rts_use_shortpreamble ? 1 : 0) : (ptcb_desc->rts_use_shortgi ? 1 : 0))); if (bw_40) { @@ -756,9 +755,9 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, * The braces are needed no matter what checkpatch says */ if (rtlhal->current_bandtype == BAND_ON_5G) { - SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE6M); + SET_TX_DESC_TX_RATE(pdesc, DESC_RATE6M); } else { - SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M); + SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M); } SET_TX_DESC_SEQ(pdesc, 0); SET_TX_DESC_LINIP(pdesc, 0); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c index 77deedf79d1d..459f3d0efa2f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c @@ -26,6 +26,7 @@ #include "../wifi.h" #include "../base.h" #include "../pci.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -151,35 +152,6 @@ static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB */ }; -static void rtl92ee_dm_diginit(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *dm_dig = &rtlpriv->dm_digtable; - - dm_dig->cur_igvalue = rtl_get_bbreg(hw, DM_REG_IGI_A_11N, - DM_BIT_IGI_11N); - dm_dig->rssi_lowthresh = DM_DIG_THRESH_LOW; - dm_dig->rssi_highthresh = DM_DIG_THRESH_HIGH; - dm_dig->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - dm_dig->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - dm_dig->rx_gain_max = DM_DIG_MAX; - dm_dig->rx_gain_min = DM_DIG_MIN; - dm_dig->back_val = DM_DIG_BACKOFF_DEFAULT; - dm_dig->back_range_max = DM_DIG_BACKOFF_MAX; - dm_dig->back_range_min = DM_DIG_BACKOFF_MIN; - dm_dig->pre_cck_cca_thres = 0xff; - dm_dig->cur_cck_cca_thres = 0x83; - dm_dig->forbidden_igi = DM_DIG_MIN; - dm_dig->large_fa_hit = 0; - dm_dig->recover_cnt = 0; - dm_dig->dig_dynamic_min = DM_DIG_MIN; - dm_dig->dig_dynamic_min_1 = DM_DIG_MIN; - dm_dig->media_connect_0 = false; - dm_dig->media_connect_1 = false; - rtlpriv->dm.dm_initialgain_enable = true; - dm_dig->bt30_cur_igi = 0x32; -} - static void rtl92ee_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) { u32 ret_value; @@ -298,7 +270,7 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct dig_t *dm_dig = &rtlpriv->dm_digtable; - u8 dig_dynamic_min , dig_maxofmin; + u8 dig_min_0, dig_maxofmin; bool bfirstconnect , bfirstdisconnect; u8 dm_dig_max, dm_dig_min; u8 current_igi = dm_dig->cur_igvalue; @@ -308,7 +280,7 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw) if (mac->act_scanning) return; - dig_dynamic_min = dm_dig->dig_dynamic_min; + dig_min_0 = dm_dig->dig_min_0; bfirstconnect = (mac->link_state >= MAC80211_LINKED) && !dm_dig->media_connect_0; bfirstdisconnect = (mac->link_state < MAC80211_LINKED) && @@ -329,19 +301,19 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw) if (rtlpriv->dm.one_entry_only) { offset = 0; if (dm_dig->rssi_val_min - offset < dm_dig_min) - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; else if (dm_dig->rssi_val_min - offset > dig_maxofmin) - dig_dynamic_min = dig_maxofmin; + dig_min_0 = dig_maxofmin; else - dig_dynamic_min = dm_dig->rssi_val_min - offset; + dig_min_0 = dm_dig->rssi_val_min - offset; } else { - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; } } else { dm_dig->rx_gain_max = dm_dig_max; - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "no link\n"); } @@ -368,10 +340,10 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw) } else { if (dm_dig->large_fa_hit < 3) { if ((dm_dig->forbidden_igi - 1) < - dig_dynamic_min) { - dm_dig->forbidden_igi = dig_dynamic_min; + dig_min_0) { + dm_dig->forbidden_igi = dig_min_0; dm_dig->rx_gain_min = - dig_dynamic_min; + dig_min_0; } else { dm_dig->forbidden_igi--; dm_dig->rx_gain_min = @@ -430,7 +402,7 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw) rtl92ee_dm_write_dig(hw , current_igi); dm_dig->media_connect_0 = ((mac->link_state >= MAC80211_LINKED) ? true : false); - dm_dig->dig_dynamic_min = dig_dynamic_min; + dm_dig->dig_min_0 = dig_min_0; } void rtl92ee_dm_write_cck_cca_thres(struct ieee80211_hw *hw, u8 cur_thres) @@ -1088,10 +1060,11 @@ static void rtl92ee_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw) void rtl92ee_dm_init(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 cur_igvalue = rtl_get_bbreg(hw, DM_REG_IGI_A_11N, DM_BIT_IGI_11N); rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; - rtl92ee_dm_diginit(hw); + rtl_dm_diginit(hw, cur_igvalue); rtl92ee_dm_init_rate_adaptive_mask(hw); rtl92ee_dm_init_primary_cca_check(hw); rtl92ee_dm_init_edca_turbo(hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h index 881db7d6fef7..107d5a488fa8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h @@ -189,28 +189,12 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1e - -#define DM_DIG_MAX_AP 0x32 -#define DM_DIG_MIN_AP 0x20 - #define DM_DIG_FA_UPPER 0x3e #define DM_DIG_FA_LOWER 0x1e #define DM_DIG_FA_TH0 0x200 #define DM_DIG_FA_TH1 0x300 #define DM_DIG_FA_TH2 0x400 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_LOW 30 #define RXPATHSELECTION_DIFF_TH 18 diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c index 45c128b91f7f..c5d4b8013cde 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c @@ -666,7 +666,6 @@ void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) struct sk_buff *skb = NULL; u32 totalpacketlen; - bool rtstatus; u8 u1rsvdpageloc[5] = { 0 }; bool b_dlok = false; @@ -728,10 +727,7 @@ void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) memcpy((u8 *)skb_put(skb, totalpacketlen), &reserved_page_packet, totalpacketlen); - rtstatus = rtl_cmd_send_packet(hw, skb); - - if (rtstatus) - b_dlok = true; + b_dlok = true; if (b_dlok) { RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD , diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c index 1a87edca2c3f..b461b3128da5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c @@ -85,29 +85,6 @@ static void _rtl92ee_enable_bcn_sub_func(struct ieee80211_hw *hw) _rtl92ee_set_bcn_ctrl_reg(hw, 0, BIT(1)); } -static void _rtl92ee_return_beacon_queue_skb(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; - unsigned long flags; - - spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); - while (skb_queue_len(&ring->queue)) { - struct rtl_tx_buffer_desc *entry = - &ring->buffer_desc[ring->idx]; - struct sk_buff *skb = __skb_dequeue(&ring->queue); - - pci_unmap_single(rtlpci->pdev, - rtlpriv->cfg->ops->get_desc( - (u8 *)entry, true, HW_DESC_TXBUFF_ADDR), - skb->len, PCI_DMA_TODEVICE); - kfree_skb(skb); - ring->idx = (ring->idx + 1) % ring->entries; - } - spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); -} - static void _rtl92ee_disable_bcn_sub_func(struct ieee80211_hw *hw) { _rtl92ee_set_bcn_ctrl_reg(hw, BIT(1), 0); @@ -403,9 +380,6 @@ static void _rtl92ee_download_rsvd_page(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_DWBCN0_CTRL + 2, bcnvalid_reg | BIT(0)); - /* Return Beacon TCB */ - _rtl92ee_return_beacon_queue_skb(hw); - /* download rsvd page */ rtl92ee_set_fw_rsvdpagepkt(hw, false); @@ -1163,6 +1137,139 @@ void rtl92ee_enable_hw_security_config(struct ieee80211_hw *hw) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); } +static bool _rtl8192ee_check_pcie_dma_hang(struct rtl_priv *rtlpriv) +{ + u8 tmp; + + /* write reg 0x350 Bit[26]=1. Enable debug port. */ + tmp = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3); + if (!(tmp & BIT(2))) { + rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3, + tmp | BIT(2)); + mdelay(100); /* Suggested by DD Justin_tsai. */ + } + + /* read reg 0x350 Bit[25] if 1 : RX hang + * read reg 0x350 Bit[24] if 1 : TX hang + */ + tmp = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3); + if ((tmp & BIT(0)) || (tmp & BIT(1))) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "CheckPcieDMAHang8192EE(): true!!\n"); + return true; + } + return false; +} + +static void _rtl8192ee_reset_pcie_interface_dma(struct rtl_priv *rtlpriv, + bool mac_power_on) +{ + u8 tmp; + bool release_mac_rx_pause; + u8 backup_pcie_dma_pause; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "ResetPcieInterfaceDMA8192EE()\n"); + + /* Revise Note: Follow the document "PCIe RX DMA Hang Reset Flow_v03" + * released by SD1 Alan. + */ + + /* 1. disable register write lock + * write 0x1C bit[1:0] = 2'h0 + * write 0xCC bit[2] = 1'b1 + */ + tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL); + tmp &= ~(BIT(1) | BIT(0)); + rtl_write_byte(rtlpriv, REG_RSV_CTRL, tmp); + tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2); + tmp |= BIT(2); + rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp); + + /* 2. Check and pause TRX DMA + * write 0x284 bit[18] = 1'b1 + * write 0x301 = 0xFF + */ + tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL); + if (tmp & BIT(2)) { + /* Already pause before the function for another reason. */ + release_mac_rx_pause = false; + } else { + rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, (tmp | BIT(2))); + release_mac_rx_pause = true; + } + + backup_pcie_dma_pause = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG + 1); + if (backup_pcie_dma_pause != 0xFF) + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xFF); + + if (mac_power_on) { + /* 3. reset TRX function + * write 0x100 = 0x00 + */ + rtl_write_byte(rtlpriv, REG_CR, 0); + } + + /* 4. Reset PCIe DMA + * write 0x003 bit[0] = 0 + */ + tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + tmp &= ~(BIT(0)); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp); + + /* 5. Enable PCIe DMA + * write 0x003 bit[0] = 1 + */ + tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + tmp |= BIT(0); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp); + + if (mac_power_on) { + /* 6. enable TRX function + * write 0x100 = 0xFF + */ + rtl_write_byte(rtlpriv, REG_CR, 0xFF); + + /* We should init LLT & RQPN and + * prepare Tx/Rx descrptor address later + * because MAC function is reset. + */ + } + + /* 7. Restore PCIe autoload down bit + * write 0xF8 bit[17] = 1'b1 + */ + tmp = rtl_read_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2); + tmp |= BIT(1); + rtl_write_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2, tmp); + + /* In MAC power on state, BB and RF maybe in ON state, + * if we release TRx DMA here + * it will cause packets to be started to Tx/Rx, + * so we release Tx/Rx DMA later. + */ + if (!mac_power_on) { + /* 8. release TRX DMA + * write 0x284 bit[18] = 1'b0 + * write 0x301 = 0x00 + */ + if (release_mac_rx_pause) { + tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL); + rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, + (tmp & (~BIT(2)))); + } + rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, + backup_pcie_dma_pause); + } + + /* 9. lock system register + * write 0xCC bit[2] = 1'b0 + */ + tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2); + tmp &= ~(BIT(2)); + rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp); +} + int rtl92ee_hw_init(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1188,6 +1295,13 @@ int rtl92ee_hw_init(struct ieee80211_hw *hw) rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_92E; } + if (_rtl8192ee_check_pcie_dma_hang(rtlpriv)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "92ee dma hang!\n"); + _rtl8192ee_reset_pcie_interface_dma(rtlpriv, + rtlhal->mac_func_enable); + rtlhal->mac_func_enable = false; + } + rtstatus = _rtl92ee_init_mac(hw); rtl_write_byte(rtlpriv, 0x577, 0x03); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h index 3f2a9596e7cd..1eaa1fab550d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h @@ -77,9 +77,11 @@ #define REG_HIMRE 0x00B8 #define REG_HISRE 0x00BC +#define REG_PMC_DBG_CTRL2 0x00CC #define REG_EFUSE_ACCESS 0x00CF #define REG_HPON_FSM 0x00EC #define REG_SYS_CFG1 0x00F0 +#define REG_MAC_PHY_CTRL_NORMAL 0x00F8 #define REG_SYS_CFG2 0x00FC #define REG_CR 0x0100 diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c index 9b5a7d5be121..c31c6bfb536d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c @@ -113,8 +113,6 @@ int rtl92ee_init_sw_vars(struct ieee80211_hw *hw) RCR_HTC_LOC_CTRL | RCR_AMF | RCR_ACF | - RCR_ADF | - RCR_AICV | RCR_ACRC32 | RCR_AB | RCR_AM | @@ -241,6 +239,7 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = { .set_desc = rtl92ee_set_desc, .get_desc = rtl92ee_get_desc, .is_tx_desc_closed = rtl92ee_is_tx_desc_closed, + .get_available_desc = rtl92ee_get_available_desc, .tx_polling = rtl92ee_tx_polling, .enable_hw_sec = rtl92ee_enable_hw_security_config, .set_key = rtl92ee_set_key, diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c index 2fcbef1d029f..d39ee67f6113 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c @@ -47,164 +47,6 @@ static u8 _rtl92ee_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -/* mac80211's rate_idx is like this: - * - * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ - * - * B/G rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - * - * 5G band:rx_status->band == IEEE80211_BAND_5GHZ - * A rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - */ -static int _rtl92ee_rate_mapping(struct ieee80211_hw *hw, - bool isht, u8 desc_rate) -{ - int rate_idx; - - if (!isht) { - if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { - switch (desc_rate) { - case DESC92C_RATE1M: - rate_idx = 0; - break; - case DESC92C_RATE2M: - rate_idx = 1; - break; - case DESC92C_RATE5_5M: - rate_idx = 2; - break; - case DESC92C_RATE11M: - rate_idx = 3; - break; - case DESC92C_RATE6M: - rate_idx = 4; - break; - case DESC92C_RATE9M: - rate_idx = 5; - break; - case DESC92C_RATE12M: - rate_idx = 6; - break; - case DESC92C_RATE18M: - rate_idx = 7; - break; - case DESC92C_RATE24M: - rate_idx = 8; - break; - case DESC92C_RATE36M: - rate_idx = 9; - break; - case DESC92C_RATE48M: - rate_idx = 10; - break; - case DESC92C_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 0; - break; - } - } else { - switch (desc_rate) { - case DESC92C_RATE6M: - rate_idx = 0; - break; - case DESC92C_RATE9M: - rate_idx = 1; - break; - case DESC92C_RATE12M: - rate_idx = 2; - break; - case DESC92C_RATE18M: - rate_idx = 3; - break; - case DESC92C_RATE24M: - rate_idx = 4; - break; - case DESC92C_RATE36M: - rate_idx = 5; - break; - case DESC92C_RATE48M: - rate_idx = 6; - break; - case DESC92C_RATE54M: - rate_idx = 7; - break; - default: - rate_idx = 0; - break; - } - } - } else { - switch (desc_rate) { - case DESC92C_RATEMCS0: - rate_idx = 0; - break; - case DESC92C_RATEMCS1: - rate_idx = 1; - break; - case DESC92C_RATEMCS2: - rate_idx = 2; - break; - case DESC92C_RATEMCS3: - rate_idx = 3; - break; - case DESC92C_RATEMCS4: - rate_idx = 4; - break; - case DESC92C_RATEMCS5: - rate_idx = 5; - break; - case DESC92C_RATEMCS6: - rate_idx = 6; - break; - case DESC92C_RATEMCS7: - rate_idx = 7; - break; - case DESC92C_RATEMCS8: - rate_idx = 8; - break; - case DESC92C_RATEMCS9: - rate_idx = 9; - break; - case DESC92C_RATEMCS10: - rate_idx = 10; - break; - case DESC92C_RATEMCS11: - rate_idx = 11; - break; - case DESC92C_RATEMCS12: - rate_idx = 12; - break; - case DESC92C_RATEMCS13: - rate_idx = 13; - break; - case DESC92C_RATEMCS14: - rate_idx = 14; - break; - case DESC92C_RATEMCS15: - rate_idx = 15; - break; - default: - rate_idx = 0; - break; - } - } - return rate_idx; -} - static void _rtl92ee_query_rxphystatus(struct ieee80211_hw *hw, struct rtl_stats *pstatus, u8 *pdesc, struct rx_fwinfo *p_drvinfo, @@ -345,8 +187,8 @@ static void _rtl92ee_query_rxphystatus(struct ieee80211_hw *hw, pstatus->recvsignalpower = rx_pwr_all; /* (3)EVM of HT rate */ - if (pstatus->rate >= DESC92C_RATEMCS8 && - pstatus->rate <= DESC92C_RATEMCS15) + if (pstatus->rate >= DESC_RATEMCS8 && + pstatus->rate <= DESC_RATEMCS15) max_spatial_stream = 2; else max_spatial_stream = 1; @@ -512,6 +354,10 @@ bool rtl92ee_rx_query_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr; u32 phystatus = GET_RX_DESC_PHYST(pdesc); + if (GET_RX_STATUS_DESC_RPT_SEL(pdesc) == 0) + status->packet_report_type = NORMAL_RX; + else + status->packet_report_type = C2H_PACKET; status->length = (u16)GET_RX_DESC_PKT_LEN(pdesc); status->rx_drvinfo_size = (u8)GET_RX_DESC_DRV_INFO_SIZE(pdesc) * RX_DRV_INFO_SIZE_UNIT; @@ -576,9 +422,8 @@ bool rtl92ee_rx_query_desc(struct ieee80211_hw *hw, * are use (RX_FLAG_HT) * Notice: this is diff with windows define */ - rx_status->rate_idx = _rtl92ee_rate_mapping(hw, - status->is_ht, - status->rate); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, + false, status->rate); rx_status->mactime = status->timestamp_low; if (phystatus) { @@ -654,14 +499,7 @@ u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw, u8 queue_index) if (!start_rx) return 0; - if ((last_read_point > (RX_DESC_NUM_92E / 2)) && - (read_point <= (RX_DESC_NUM_92E / 2))) { - remind_cnt = RX_DESC_NUM_92E - write_point; - } else { - remind_cnt = (read_point >= write_point) ? - (read_point - write_point) : - (RX_DESC_NUM_92E - write_point + read_point); - } + remind_cnt = calc_fifo_space(read_point, write_point); if (remind_cnt == 0) return 0; @@ -710,7 +548,7 @@ static u16 get_desc_addr_fr_q_idx(u16 queue_index) return desc_address; } -void rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 q_idx) +u16 rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 q_idx) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -723,12 +561,11 @@ void rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 q_idx) current_tx_read_point = (u16)((tmp_4byte >> 16) & 0x0fff); current_tx_write_point = (u16)((tmp_4byte) & 0x0fff); - point_diff = ((current_tx_read_point > current_tx_write_point) ? - (current_tx_read_point - current_tx_write_point) : - (TX_DESC_NUM_92E - current_tx_write_point + - current_tx_read_point)); + point_diff = calc_fifo_space(current_tx_read_point, + current_tx_write_point); rtlpci->tx_ring[q_idx].avl_desc = point_diff; + return point_diff; } void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw, @@ -901,13 +738,13 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, } else { if (rtlpriv->ra.is_special_data) { ptcb_desc->use_driver_rate = true; - SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE11M); + SET_TX_DESC_TX_RATE(pdesc, DESC_RATE11M); } else { ptcb_desc->use_driver_rate = false; } } - if (ptcb_desc->hw_rate > DESC92C_RATEMCS0) + if (ptcb_desc->hw_rate > DESC_RATEMCS0) short_gi = (ptcb_desc->use_shortgi) ? 1 : 0; else short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0; @@ -927,7 +764,7 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(pdesc, - ((ptcb_desc->rts_rate <= DESC92C_RATE54M) ? + ((ptcb_desc->rts_rate <= DESC_RATE54M) ? (ptcb_desc->rts_use_shortpreamble ? 1 : 0) : (ptcb_desc->rts_use_shortgi ? 1 : 0))); @@ -1038,7 +875,7 @@ void rtl92ee_tx_fill_cmddesc(struct ieee80211_hw *hw, if (firstseg) SET_TX_DESC_OFFSET(pdesc, txdesc_len); - SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M); + SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M); SET_TX_DESC_SEQ(pdesc, 0); @@ -1207,8 +1044,7 @@ bool rtl92ee_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index) static u8 stop_report_cnt; struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; - /*checking Read/Write Point each interrupt wastes CPU */ - if (stop_report_cnt > 15 || !rtlpriv->link_info.busytraffic) { + { u16 point_diff = 0; u16 cur_tx_rp, cur_tx_wp; u32 tmpu32 = 0; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h index 6f9be1c7515c..8f78ac9e6040 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h @@ -542,6 +542,8 @@ LE_BITS_TO_4BYTE(__pdesc+8, 12, 4) #define GET_RX_DESC_RX_IS_QOS(__pdesc) \ LE_BITS_TO_4BYTE(__pdesc+8, 16, 1) +#define GET_RX_STATUS_DESC_RPT_SEL(__pdesc) \ + LE_BITS_TO_4BYTE(__pdesc+8, 28, 1) #define GET_RX_DESC_RXMCS(__pdesc) \ LE_BITS_TO_4BYTE(__pdesc+12, 0, 7) @@ -591,10 +593,10 @@ do { \ } while (0) #define RTL92EE_RX_HAL_IS_CCK_RATE(rxmcs)\ - (rxmcs == DESC92C_RATE1M ||\ - rxmcs == DESC92C_RATE2M ||\ - rxmcs == DESC92C_RATE5_5M ||\ - rxmcs == DESC92C_RATE11M) + (rxmcs == DESC_RATE1M ||\ + rxmcs == DESC_RATE2M ||\ + rxmcs == DESC_RATE5_5M ||\ + rxmcs == DESC_RATE11M) #define IS_LITTLE_ENDIAN 1 @@ -829,7 +831,7 @@ void rtl92ee_rx_check_dma_ok(struct ieee80211_hw *hw, u8 *header_desc, u8 queue_index); u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw, u8 queue_index); -void rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 queue_index); +u16 rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 queue_index); void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw, u8 *tx_bd_desc, u8 *desc, u8 queue_index, struct sk_buff *skb, dma_addr_t addr); diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h index 6e7a70b43949..ef87c09b77d0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h @@ -450,10 +450,10 @@ SHIFT_AND_MASK_LE(__pdesc + 24, 0, 32) #define SE_RX_HAL_IS_CCK_RATE(_pdesc)\ - (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE1M || \ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE2M || \ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE5_5M ||\ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE11M) + (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE1M || \ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE2M || \ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE5_5M ||\ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE11M) enum rf_optype { RF_OP_BY_SW_3WIRE = 0, diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c index b3a2d5ec59e6..575980b88658 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c @@ -29,6 +29,7 @@ #include "../wifi.h" #include "../base.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -469,7 +470,7 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) if (digtable->backoff_enable_flag) rtl92s_backoff_enable_flag(hw); else - digtable->back_val = DM_DIG_BACKOFF; + digtable->back_val = DM_DIG_BACKOFF_MAX; if ((digtable->rssi_val + 10 - digtable->back_val) > digtable->rx_gain_max) @@ -503,7 +504,7 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_ENABLE); - digtable->back_val = DM_DIG_BACKOFF; + digtable->back_val = DM_DIG_BACKOFF_MAX; digtable->cur_igvalue = rtlpriv->phy.default_initialgain[0]; digtable->pre_igvalue = 0; return; @@ -691,7 +692,7 @@ static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw) /* for dig debug rssi value */ digtable->rssi_val = 50; - digtable->back_val = DM_DIG_BACKOFF; + digtable->back_val = DM_DIG_BACKOFF_MAX; digtable->rx_gain_max = DM_DIG_MAX; digtable->rx_gain_min = DM_DIG_MIN; diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h index 2e9052c8fe4b..de6ac796c74d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h @@ -54,24 +54,6 @@ enum dm_dig_sta { 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, @@ -99,22 +81,12 @@ enum dm_ratr_sta { #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 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/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c index fb003868bdef..e1fd27c888bf 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -383,21 +383,21 @@ static struct rtl_hal_cfg rtl92se_hal_cfg = { .maps[RTL_IMR_ROK] = IMR_ROK, .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), - .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, - .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, - .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, - .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, - .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, - .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, - .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, - .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, - .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, - .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, - .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, - .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, + .maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC_RATE54M, - .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, - .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, + .maps[RTL_RC_HT_RATEMCS7] = DESC_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15, }; static struct pci_device_id rtl92se_pci_ids[] = { diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index 672fd3b02835..125b29bd2f93 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -191,8 +191,8 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw, pstats->rxpower = rx_pwr_all; pstats->recvsignalpower = rx_pwr_all; - if (pstats->is_ht && pstats->rate >= DESC92_RATEMCS8 && - pstats->rate <= DESC92_RATEMCS15) + if (pstats->is_ht && pstats->rate >= DESC_RATEMCS8 && + pstats->rate <= DESC_RATEMCS15) max_spatial_stream = 2; else max_spatial_stream = 1; @@ -264,7 +264,6 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, struct rx_fwinfo *p_drvinfo; u32 phystatus = (u32)GET_RX_STATUS_DESC_PHY_STATUS(pdesc); struct ieee80211_hdr *hdr; - bool first_ampdu = false; stats->length = (u16)GET_RX_STATUS_DESC_PKT_LEN(pdesc); stats->rx_drvinfo_size = (u8)GET_RX_STATUS_DESC_DRVINFO_SIZE(pdesc) * 8; @@ -319,8 +318,8 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, rx_status->flag |= RX_FLAG_DECRYPTED; } - rx_status->rate_idx = rtlwifi_rate_mapping(hw, - stats->is_ht, stats->rate, first_ampdu); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht, + false, stats->rate); rx_status->mactime = stats->timestamp_low; if (phystatus) { @@ -394,14 +393,14 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RSVD_MACID(pdesc, reserved_macid); SET_TX_DESC_TXHT(pdesc, ((ptcb_desc->hw_rate >= - DESC92_RATEMCS0) ? 1 : 0)); + DESC_RATEMCS0) ? 1 : 0)); if (rtlhal->version == VERSION_8192S_ACUT) { - if (ptcb_desc->hw_rate == DESC92_RATE1M || - ptcb_desc->hw_rate == DESC92_RATE2M || - ptcb_desc->hw_rate == DESC92_RATE5_5M || - ptcb_desc->hw_rate == DESC92_RATE11M) { - ptcb_desc->hw_rate = DESC92_RATE12M; + if (ptcb_desc->hw_rate == DESC_RATE1M || + ptcb_desc->hw_rate == DESC_RATE2M || + ptcb_desc->hw_rate == DESC_RATE5_5M || + ptcb_desc->hw_rate == DESC_RATE11M) { + ptcb_desc->hw_rate = DESC_RATE12M; } } @@ -430,7 +429,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, 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 <= - DESC92_RATE54M) ? + DESC_RATE54M) ? (ptcb_desc->rts_use_shortpreamble ? 1 : 0) : (ptcb_desc->rts_use_shortgi ? 1 : 0))); diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c index a0e86922780a..4c1c96c96a5a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c @@ -26,6 +26,7 @@ #include "../wifi.h" #include "../base.h" #include "../pci.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -146,31 +147,6 @@ static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} }; -static void rtl8723e_dm_diginit(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *dm_digtable = &rtlpriv->dm_digtable; - - dm_digtable->dig_enable_flag = true; - dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; - dm_digtable->cur_igvalue = 0x20; - dm_digtable->pre_igvalue = 0x0; - dm_digtable->cursta_cstate = DIG_STA_DISCONNECT; - dm_digtable->presta_cstate = DIG_STA_DISCONNECT; - dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT; - dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; - dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; - dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - dm_digtable->rx_gain_max = DM_DIG_MAX; - dm_digtable->rx_gain_min = DM_DIG_MIN; - dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; - dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; - dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; - dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX; - dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; -} - static u8 rtl8723e_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -395,30 +371,30 @@ static void rtl8723e_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) if (dm_digtable->cursta_cstate == DIG_STA_CONNECT) { dm_digtable->rssi_val_min = rtl8723e_dm_initial_gain_min_pwdb(hw); - if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) { + if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { if (dm_digtable->rssi_val_min <= 25) dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_LowRssi; + CCK_PD_STAGE_LOWRSSI; else dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_HighRssi; + CCK_PD_STAGE_HIGHRSSI; } else { if (dm_digtable->rssi_val_min <= 20) dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_LowRssi; + CCK_PD_STAGE_LOWRSSI; else dm_digtable->cur_cck_pd_state = - CCK_PD_STAGE_HighRssi; + CCK_PD_STAGE_HIGHRSSI; } } else { dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; } if (dm_digtable->pre_cck_pd_state != dm_digtable->cur_cck_pd_state) { - if (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) { + if (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { if (rtlpriv->falsealm_cnt.cnt_cck_fail > 800) dm_digtable->cur_cck_fa_state = - CCK_FA_STAGE_High; + CCK_FA_STAGE_HIGH; else dm_digtable->cur_cck_fa_state = CCK_FA_STAGE_LOW; @@ -818,7 +794,7 @@ void rtl8723e_dm_init(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; - rtl8723e_dm_diginit(hw); + rtl_dm_diginit(hw, 0x20); rtl8723_dm_init_dynamic_txpower(hw); rtl8723_dm_init_edca_turbo(hw); rtl8723e_dm_init_rate_adaptive_mask(hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h index 6fa0feb05f6d..57111052e86b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h @@ -42,25 +42,12 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1e - #define DM_DIG_FA_UPPER 0x32 #define DM_DIG_FA_LOWER 0x20 #define DM_DIG_FA_TH0 0x20 #define DM_DIG_FA_TH1 0x100 #define DM_DIG_FA_TH2 0x200 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_LOW 30 #define RXPATHSELECTION_DIFF_TH 18 @@ -108,14 +95,6 @@ enum tag_dynamic_init_gain_operation_type_definition { DIG_OP_TYPE_MAX }; -enum tag_cck_packet_detection_threshold_type_definition { - CCK_PD_STAGE_LowRssi = 0, - CCK_PD_STAGE_HighRssi = 1, - CCK_FA_STAGE_LOW = 2, - CCK_FA_STAGE_High = 3, - CCK_PD_STAGE_MAX = 4, -}; - enum dm_1r_cca_e { CCA_1R = 0, CCA_2R = 1, @@ -134,23 +113,6 @@ enum dm_sw_ant_switch_e { ANS_ANTENNA_MAX = 3, }; -enum dm_dig_ext_port_alg_e { - 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_dig_connect_e { - DIG_STA_DISCONNECT = 0, - DIG_STA_CONNECT = 1, - DIG_STA_BEFORE_CONNECT = 2, - DIG_MULTISTA_DISCONNECT = 3, - DIG_MULTISTA_CONNECT = 4, - DIG_CONNECT_MAX -}; - #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) diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c index d372ccaf3465..2f7c144d7980 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c @@ -45,164 +45,6 @@ static u8 _rtl8723e_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -/* mac80211's rate_idx is like this: - * - * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ - * - * B/G rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - * - * 5G band:rx_status->band == IEEE80211_BAND_5GHZ - * A rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - */ -static int _rtl8723e_rate_mapping(struct ieee80211_hw *hw, - bool isht, u8 desc_rate) -{ - int rate_idx; - - if (!isht) { - if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { - switch (desc_rate) { - case DESC92C_RATE1M: - rate_idx = 0; - break; - case DESC92C_RATE2M: - rate_idx = 1; - break; - case DESC92C_RATE5_5M: - rate_idx = 2; - break; - case DESC92C_RATE11M: - rate_idx = 3; - break; - case DESC92C_RATE6M: - rate_idx = 4; - break; - case DESC92C_RATE9M: - rate_idx = 5; - break; - case DESC92C_RATE12M: - rate_idx = 6; - break; - case DESC92C_RATE18M: - rate_idx = 7; - break; - case DESC92C_RATE24M: - rate_idx = 8; - break; - case DESC92C_RATE36M: - rate_idx = 9; - break; - case DESC92C_RATE48M: - rate_idx = 10; - break; - case DESC92C_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 0; - break; - } - } else { - switch (desc_rate) { - case DESC92C_RATE6M: - rate_idx = 0; - break; - case DESC92C_RATE9M: - rate_idx = 1; - break; - case DESC92C_RATE12M: - rate_idx = 2; - break; - case DESC92C_RATE18M: - rate_idx = 3; - break; - case DESC92C_RATE24M: - rate_idx = 4; - break; - case DESC92C_RATE36M: - rate_idx = 5; - break; - case DESC92C_RATE48M: - rate_idx = 6; - break; - case DESC92C_RATE54M: - rate_idx = 7; - break; - default: - rate_idx = 0; - break; - } - } - } else { - switch (desc_rate) { - case DESC92C_RATEMCS0: - rate_idx = 0; - break; - case DESC92C_RATEMCS1: - rate_idx = 1; - break; - case DESC92C_RATEMCS2: - rate_idx = 2; - break; - case DESC92C_RATEMCS3: - rate_idx = 3; - break; - case DESC92C_RATEMCS4: - rate_idx = 4; - break; - case DESC92C_RATEMCS5: - rate_idx = 5; - break; - case DESC92C_RATEMCS6: - rate_idx = 6; - break; - case DESC92C_RATEMCS7: - rate_idx = 7; - break; - case DESC92C_RATEMCS8: - rate_idx = 8; - break; - case DESC92C_RATEMCS9: - rate_idx = 9; - break; - case DESC92C_RATEMCS10: - rate_idx = 10; - break; - case DESC92C_RATEMCS11: - rate_idx = 11; - break; - case DESC92C_RATEMCS12: - rate_idx = 12; - break; - case DESC92C_RATEMCS13: - rate_idx = 13; - break; - case DESC92C_RATEMCS14: - rate_idx = 14; - break; - case DESC92C_RATEMCS15: - rate_idx = 15; - break; - default: - rate_idx = 0; - break; - } - } - return rate_idx; -} - static void _rtl8723e_query_rxphystatus(struct ieee80211_hw *hw, struct rtl_stats *pstatus, u8 *pdesc, struct rx_fwinfo_8723e *p_drvinfo, @@ -503,8 +345,8 @@ bool rtl8723e_rx_query_desc(struct ieee80211_hw *hw, * are use (RX_FLAG_HT) * Notice: this is diff with windows define */ - rx_status->rate_idx = _rtl8723e_rate_mapping(hw, - status->is_ht, status->rate); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, + false, status->rate); rx_status->mactime = status->timestamp_low; if (phystatus == true) { diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c index dd7eb4371f49..2367e8f47a5b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c @@ -26,6 +26,7 @@ #include "../wifi.h" #include "../base.h" #include "../pci.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -211,35 +212,6 @@ void rtl8723be_dm_txpower_track_adjust(struct ieee80211_hw *hw, u8 type, (pwr_val << 16) | (pwr_val << 24); } -static void rtl8723be_dm_diginit(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *dm_digtable = &rtlpriv->dm_digtable; - - dm_digtable->dig_enable_flag = true; - dm_digtable->cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f); - dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; - dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; - dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - dm_digtable->rx_gain_max = DM_DIG_MAX; - dm_digtable->rx_gain_min = DM_DIG_MIN; - dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; - dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; - dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; - dm_digtable->pre_cck_cca_thres = 0xff; - dm_digtable->cur_cck_cca_thres = 0x83; - dm_digtable->forbidden_igi = DM_DIG_MIN; - dm_digtable->large_fa_hit = 0; - dm_digtable->recover_cnt = 0; - dm_digtable->dig_dynamic_min = DM_DIG_MIN; - dm_digtable->dig_dynamic_min_1 = DM_DIG_MIN; - dm_digtable->media_connect_0 = false; - dm_digtable->media_connect_1 = false; - rtlpriv->dm.dm_initialgain_enable = true; - dm_digtable->bt30_cur_igi = 0x32; -} - void rtl8723be_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -293,9 +265,10 @@ static void rtl8723be_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw) void rtl8723be_dm_init(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f); rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; - rtl8723be_dm_diginit(hw); + rtl_dm_diginit(hw, cur_igvalue); rtl8723be_dm_init_rate_adaptive_mask(hw); rtl8723_dm_init_edca_turbo(hw); rtl8723_dm_init_dynamic_bb_powersaving(hw); @@ -424,7 +397,7 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct dig_t *dm_digtable = &rtlpriv->dm_digtable; struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u8 dig_dynamic_min, dig_maxofmin; + u8 dig_min_0, dig_maxofmin; bool bfirstconnect, bfirstdisconnect; u8 dm_dig_max, dm_dig_min; u8 current_igi = dm_digtable->cur_igvalue; @@ -434,7 +407,7 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw) if (mac->act_scanning) return; - dig_dynamic_min = dm_digtable->dig_dynamic_min; + dig_min_0 = dm_digtable->dig_min_0; bfirstconnect = (mac->link_state >= MAC80211_LINKED) && !dm_digtable->media_connect_0; bfirstdisconnect = (mac->link_state < MAC80211_LINKED) && @@ -456,20 +429,20 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw) if (rtlpriv->dm.one_entry_only) { offset = 12; if (dm_digtable->rssi_val_min - offset < dm_dig_min) - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; else if (dm_digtable->rssi_val_min - offset > dig_maxofmin) - dig_dynamic_min = dig_maxofmin; + dig_min_0 = dig_maxofmin; else - dig_dynamic_min = + dig_min_0 = dm_digtable->rssi_val_min - offset; } else { - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; } } else { dm_digtable->rx_gain_max = dm_dig_max; - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "no link\n"); } @@ -497,11 +470,11 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw) } else { if (dm_digtable->large_fa_hit < 3) { if ((dm_digtable->forbidden_igi - 1) < - dig_dynamic_min) { + dig_min_0) { dm_digtable->forbidden_igi = - dig_dynamic_min; + dig_min_0; dm_digtable->rx_gain_min = - dig_dynamic_min; + dig_min_0; } else { dm_digtable->forbidden_igi--; dm_digtable->rx_gain_min = @@ -552,7 +525,7 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw) rtl8723be_dm_write_dig(hw, current_igi); dm_digtable->media_connect_0 = ((mac->link_state >= MAC80211_LINKED) ? true : false); - dm_digtable->dig_dynamic_min = dig_dynamic_min; + dm_digtable->dig_min_0 = dig_min_0; } static void rtl8723be_dm_false_alarm_counter_statistics( diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h index e4c0e8ae6f47..f752a2cad63d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h @@ -180,28 +180,12 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1e - -#define DM_DIG_MAX_AP 0x32 -#define DM_DIG_MIN_AP 0x20 - #define DM_DIG_FA_UPPER 0x3e #define DM_DIG_FA_LOWER 0x1e #define DM_DIG_FA_TH0 0x200 #define DM_DIG_FA_TH1 0x300 #define DM_DIG_FA_TH2 0x400 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_LOW 30 #define RXPATHSELECTION_DIFF_TH 18 @@ -252,23 +236,6 @@ enum dm_sw_ant_switch_e { ANS_ANTENNA_MAX = 3, }; -enum dm_dig_ext_port_alg_e { - 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_dig_connect_e { - DIG_STA_DISCONNECT = 0, - DIG_STA_CONNECT = 1, - DIG_STA_BEFORE_CONNECT = 2, - DIG_MULTISTA_DISCONNECT = 3, - DIG_MULTISTA_CONNECT = 4, - DIG_CONNECT_MAX -}; - enum pwr_track_control_method { BBSWING, TXAGC diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c index 20dcc25c506c..b7b73cbe346d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c @@ -874,31 +874,6 @@ void rtl8723be_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) ROFDM0_RXDETECTOR3, rtlphy->framesync); } -void rtl8723be_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_phy *rtlphy = &rtlpriv->phy; - u8 txpwr_level; - long txpwr_dbm; - - txpwr_level = rtlphy->cur_cck_txpwridx; - txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B, - txpwr_level); - txpwr_level = rtlphy->cur_ofdm24g_txpwridx; - if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) > - txpwr_dbm) - txpwr_dbm = - rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, - txpwr_level); - txpwr_level = rtlphy->cur_ofdm24g_txpwridx; - if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, - txpwr_level) > txpwr_dbm) - txpwr_dbm = - rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, - txpwr_level); - *powerlevel = txpwr_dbm; -} - static u8 _rtl8723be_phy_get_ratesection_intxpower_byrate(enum radio_path path, u8 rate) { diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.h b/drivers/net/wireless/rtlwifi/rtl8723be/phy.h index 6339738a0e33..9021d4745ab7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/phy.h +++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.h @@ -114,8 +114,6 @@ bool rtl8723be_phy_mac_config(struct ieee80211_hw *hw); bool rtl8723be_phy_bb_config(struct ieee80211_hw *hw); bool rtl8723be_phy_rf_config(struct ieee80211_hw *hw); void rtl8723be_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); -void rtl8723be_phy_get_txpower_level(struct ieee80211_hw *hw, - long *powerlevel); void rtl8723be_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); void rtl8723be_phy_scan_operation_backup(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c index 223eb42992bd..1017f02d7bf7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c @@ -387,12 +387,14 @@ module_param_named(swlps, rtl8723be_mod_params.swctrl_lps, bool, 0444); module_param_named(fwlps, rtl8723be_mod_params.fwctrl_lps, bool, 0444); module_param_named(disable_watchdog, rtl8723be_mod_params.disable_watchdog, 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"); +MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); +MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); +MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); +MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 0)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); -MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n"); +MODULE_PARM_DESC(disable_watchdog, + "Set to 1 to disable the watchdog (default 0)\n"); static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c index d6a1c70cb657..338ec9a9d09b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c @@ -47,164 +47,6 @@ static u8 _rtl8723be_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -/* mac80211's rate_idx is like this: - * - * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ - * - * B/G rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - * - * 5G band:rx_status->band == IEEE80211_BAND_5GHZ - * A rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15 - */ -static int _rtl8723be_rate_mapping(struct ieee80211_hw *hw, - bool isht, u8 desc_rate) -{ - int rate_idx; - - if (!isht) { - if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { - switch (desc_rate) { - case DESC92C_RATE1M: - rate_idx = 0; - break; - case DESC92C_RATE2M: - rate_idx = 1; - break; - case DESC92C_RATE5_5M: - rate_idx = 2; - break; - case DESC92C_RATE11M: - rate_idx = 3; - break; - case DESC92C_RATE6M: - rate_idx = 4; - break; - case DESC92C_RATE9M: - rate_idx = 5; - break; - case DESC92C_RATE12M: - rate_idx = 6; - break; - case DESC92C_RATE18M: - rate_idx = 7; - break; - case DESC92C_RATE24M: - rate_idx = 8; - break; - case DESC92C_RATE36M: - rate_idx = 9; - break; - case DESC92C_RATE48M: - rate_idx = 10; - break; - case DESC92C_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 0; - break; - } - } else { - switch (desc_rate) { - case DESC92C_RATE6M: - rate_idx = 0; - break; - case DESC92C_RATE9M: - rate_idx = 1; - break; - case DESC92C_RATE12M: - rate_idx = 2; - break; - case DESC92C_RATE18M: - rate_idx = 3; - break; - case DESC92C_RATE24M: - rate_idx = 4; - break; - case DESC92C_RATE36M: - rate_idx = 5; - break; - case DESC92C_RATE48M: - rate_idx = 6; - break; - case DESC92C_RATE54M: - rate_idx = 7; - break; - default: - rate_idx = 0; - break; - } - } - } else { - switch (desc_rate) { - case DESC92C_RATEMCS0: - rate_idx = 0; - break; - case DESC92C_RATEMCS1: - rate_idx = 1; - break; - case DESC92C_RATEMCS2: - rate_idx = 2; - break; - case DESC92C_RATEMCS3: - rate_idx = 3; - break; - case DESC92C_RATEMCS4: - rate_idx = 4; - break; - case DESC92C_RATEMCS5: - rate_idx = 5; - break; - case DESC92C_RATEMCS6: - rate_idx = 6; - break; - case DESC92C_RATEMCS7: - rate_idx = 7; - break; - case DESC92C_RATEMCS8: - rate_idx = 8; - break; - case DESC92C_RATEMCS9: - rate_idx = 9; - break; - case DESC92C_RATEMCS10: - rate_idx = 10; - break; - case DESC92C_RATEMCS11: - rate_idx = 11; - break; - case DESC92C_RATEMCS12: - rate_idx = 12; - break; - case DESC92C_RATEMCS13: - rate_idx = 13; - break; - case DESC92C_RATEMCS14: - rate_idx = 14; - break; - case DESC92C_RATEMCS15: - rate_idx = 15; - break; - default: - rate_idx = 0; - break; - } - } - return rate_idx; -} - static void _rtl8723be_query_rxphystatus(struct ieee80211_hw *hw, struct rtl_stats *pstatus, u8 *pdesc, struct rx_fwinfo_8723be *p_drvinfo, @@ -558,8 +400,8 @@ bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw, * supported rates or MCS index if HT rates * are use (RX_FLAG_HT) */ - rx_status->rate_idx = _rtl8723be_rate_mapping(hw, status->is_ht, - status->rate); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, + false, status->rate); rx_status->mactime = status->timestamp_low; if (phystatus) { diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/def.h b/drivers/net/wireless/rtlwifi/rtl8821ae/def.h index a730985ae81d..ee7c208bd070 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/def.h @@ -373,60 +373,6 @@ enum rtl_desc_qsel { QSLT_CMD = 0x13, }; -enum rtl_desc8821ae_rate { - DESC_RATE1M = 0x00, - DESC_RATE2M = 0x01, - DESC_RATE5_5M = 0x02, - DESC_RATE11M = 0x03, - - DESC_RATE6M = 0x04, - DESC_RATE9M = 0x05, - DESC_RATE12M = 0x06, - DESC_RATE18M = 0x07, - DESC_RATE24M = 0x08, - DESC_RATE36M = 0x09, - DESC_RATE48M = 0x0a, - DESC_RATE54M = 0x0b, - - DESC_RATEMCS0 = 0x0c, - DESC_RATEMCS1 = 0x0d, - DESC_RATEMCS2 = 0x0e, - DESC_RATEMCS3 = 0x0f, - DESC_RATEMCS4 = 0x10, - DESC_RATEMCS5 = 0x11, - DESC_RATEMCS6 = 0x12, - DESC_RATEMCS7 = 0x13, - DESC_RATEMCS8 = 0x14, - DESC_RATEMCS9 = 0x15, - DESC_RATEMCS10 = 0x16, - DESC_RATEMCS11 = 0x17, - DESC_RATEMCS12 = 0x18, - DESC_RATEMCS13 = 0x19, - DESC_RATEMCS14 = 0x1a, - DESC_RATEMCS15 = 0x1b, - - DESC_RATEVHT1SS_MCS0 = 0x2c, - DESC_RATEVHT1SS_MCS1 = 0x2d, - DESC_RATEVHT1SS_MCS2 = 0x2e, - DESC_RATEVHT1SS_MCS3 = 0x2f, - DESC_RATEVHT1SS_MCS4 = 0x30, - DESC_RATEVHT1SS_MCS5 = 0x31, - DESC_RATEVHT1SS_MCS6 = 0x32, - DESC_RATEVHT1SS_MCS7 = 0x33, - DESC_RATEVHT1SS_MCS8 = 0x34, - DESC_RATEVHT1SS_MCS9 = 0x35, - DESC_RATEVHT2SS_MCS0 = 0x36, - DESC_RATEVHT2SS_MCS1 = 0x37, - DESC_RATEVHT2SS_MCS2 = 0x38, - DESC_RATEVHT2SS_MCS3 = 0x39, - DESC_RATEVHT2SS_MCS4 = 0x3a, - DESC_RATEVHT2SS_MCS5 = 0x3b, - DESC_RATEVHT2SS_MCS6 = 0x3c, - DESC_RATEVHT2SS_MCS7 = 0x3d, - DESC_RATEVHT2SS_MCS8 = 0x3e, - DESC_RATEVHT2SS_MCS9 = 0x3f, -}; - enum rx_packet_type { NORMAL_RX, TX_REPORT1, diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c index ba30b0d250fd..0b2082dc48f1 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c @@ -26,6 +26,7 @@ #include "../wifi.h" #include "../base.h" #include "../pci.h" +#include "../core.h" #include "reg.h" #include "def.h" #include "phy.h" @@ -519,34 +520,6 @@ void rtl8821ae_dm_initialize_txpower_tracking_thermalmeter( } } -static void rtl8821ae_dm_diginit(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct dig_t *dm_digtable = &rtlpriv->dm_digtable; - - dm_digtable->cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f); - dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; - dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; - dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - dm_digtable->rx_gain_max = DM_DIG_MAX; - dm_digtable->rx_gain_min = DM_DIG_MIN; - dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT; - dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX; - dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN; - dm_digtable->pre_cck_cca_thres = 0xff; - dm_digtable->cur_cck_cca_thres = 0x83; - dm_digtable->forbidden_igi = DM_DIG_MIN; - dm_digtable->large_fa_hit = 0; - dm_digtable->recover_cnt = 0; - dm_digtable->dig_dynamic_min = DM_DIG_MIN; - dm_digtable->dig_dynamic_min_1 = DM_DIG_MIN; - dm_digtable->media_connect_0 = false; - dm_digtable->media_connect_1 = false; - rtlpriv->dm.dm_initialgain_enable = true; - dm_digtable->bt30_cur_igi = 0x32; -} - void rtl8821ae_dm_init_edca_turbo(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -606,6 +579,7 @@ void rtl8821ae_dm_init(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &rtlpriv->phy; + u32 cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f); spin_lock(&rtlpriv->locks.iqk_lock); rtlphy->lck_inprogress = false; @@ -613,7 +587,7 @@ void rtl8821ae_dm_init(struct ieee80211_hw *hw) rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; rtl8821ae_dm_common_info_self_init(hw); - rtl8821ae_dm_diginit(hw); + rtl_dm_diginit(hw, cur_igvalue); rtl8821ae_dm_init_rate_adaptive_mask(hw); rtl8821ae_dm_init_edca_turbo(hw); rtl8821ae_dm_initialize_txpower_tracking_thermalmeter(hw); @@ -822,7 +796,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) struct dig_t *dm_digtable = &rtlpriv->dm_digtable; struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u8 dig_dynamic_min; + u8 dig_min_0; u8 dig_max_of_min; bool first_connect, first_disconnect; u8 dm_dig_max, dm_dig_min, offset; @@ -837,7 +811,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) } /*add by Neil Chen to avoid PSD is processing*/ - dig_dynamic_min = dm_digtable->dig_dynamic_min; + dig_min_0 = dm_digtable->dig_min_0; first_connect = (mac->link_state >= MAC80211_LINKED) && (!dm_digtable->media_connect_0); first_disconnect = (mac->link_state < MAC80211_LINKED) && @@ -876,23 +850,23 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) offset = 0; if (dm_digtable->rssi_val_min - offset < dm_dig_min) - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; else if (dm_digtable->rssi_val_min - offset > dig_max_of_min) - dig_dynamic_min = dig_max_of_min; + dig_min_0 = dig_max_of_min; else - dig_dynamic_min = + dig_min_0 = dm_digtable->rssi_val_min - offset; RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, - "bOneEntryOnly=TRUE, dig_dynamic_min=0x%x\n", - dig_dynamic_min); + "bOneEntryOnly=TRUE, dig_min_0=0x%x\n", + dig_min_0); } else { - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; } } else { dm_digtable->rx_gain_max = dm_dig_max; - dig_dynamic_min = dm_dig_min; + dig_min_0 = dm_dig_min; RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "No Link\n"); } @@ -925,11 +899,11 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) } else { if (dm_digtable->large_fa_hit < 3) { if ((dm_digtable->forbidden_igi - 1) < - dig_dynamic_min) { + dig_min_0) { dm_digtable->forbidden_igi = - dig_dynamic_min; + dig_min_0; dm_digtable->rx_gain_min = - dig_dynamic_min; + dig_min_0; RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "Normal Case: At Lower Bound\n"); } else { @@ -1024,7 +998,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) rtl8821ae_dm_write_dig(hw, current_igi); dm_digtable->media_connect_0 = ((mac->link_state >= MAC80211_LINKED) ? true : false); - dm_digtable->dig_dynamic_min = dig_dynamic_min; + dm_digtable->dig_min_0 = dig_min_0; } static void rtl8821ae_dm_common_info_self_update(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h index 9dd40dd316c1..625a6bbb21fc 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h @@ -187,28 +187,12 @@ #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_FALSEALARM_THRESH_LOW 400 -#define DM_FALSEALARM_THRESH_HIGH 1000 - -#define DM_DIG_MAX 0x3e -#define DM_DIG_MIN 0x1e - -#define DM_DIG_MAX_AP 0x32 -#define DM_DIG_MIN_AP 0x20 - #define DM_DIG_FA_UPPER 0x3e #define DM_DIG_FA_LOWER 0x1e #define DM_DIG_FA_TH0 200 #define DM_DIG_FA_TH1 0x300 #define DM_DIG_FA_TH2 0x400 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 -#define DM_DIG_BACKOFF_DEFAULT 10 - #define RXPATHSELECTION_SS_TH_LOW 30 #define RXPATHSELECTION_DIFF_TH 18 @@ -262,14 +246,6 @@ enum tag_dynamic_init_gain_operation_type_definition { DIG_OP_TYPE_MAX }; -enum tag_cck_packet_detection_threshold_type_definition { - CCK_PD_STAGE_LOWRSSI = 0, - CCK_PD_STAGE_HIGHRSSI = 1, - CCK_FA_STAGE_LOW = 2, - CCK_FA_STAGE_HIGH = 3, - CCK_PD_STAGE_MAX = 4, -}; - enum dm_1r_cca_e { CCA_1R = 0, CCA_2R = 1, @@ -288,23 +264,6 @@ enum dm_sw_ant_switch_e { ANS_ANTENNA_MAX = 3, }; -enum dm_dig_ext_port_alg_e { - 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_dig_connect_e { - DIG_STA_DISCONNECT = 0, - DIG_STA_CONNECT = 1, - DIG_STA_BEFORE_CONNECT = 2, - DIG_MULTISTA_DISCONNECT = 3, - DIG_MULTISTA_CONNECT = 4, - DIG_CONNECT_MAX -}; - enum pwr_track_control_method { BBSWING, TXAGC, diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h index bf0b0ce9519c..36b3e91d996e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h @@ -93,9 +93,9 @@ #define RTL8812_TRANS_CARDEMU_TO_SUS \ {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\ - PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xcc}, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xc0}, \ {0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\ - PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xEC}, \ + PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xE0}, \ {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x07 \ /* gpio11 input mode, gpio10~8 output mode */}, \ diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c index fc92dd6a0d07..a4988121e1ab 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c @@ -85,52 +85,6 @@ static void rtl8821ae_init_aspm_vars(struct ieee80211_hw *hw) rtlpci->const_support_pciaspm = 1; } -static void load_wowlan_fw(struct rtl_priv *rtlpriv) -{ - /* callback routine to load wowlan firmware after main fw has - * been loaded - */ - const struct firmware *wowlan_firmware; - char *fw_name = NULL; - int err; - - /* for wowlan firmware buf */ - rtlpriv->rtlhal.wowlan_firmware = vzalloc(0x8000); - if (!rtlpriv->rtlhal.wowlan_firmware) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "Can't alloc buffer for wowlan fw.\n"); - return; - } - - if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8821AE) - fw_name = "rtlwifi/rtl8821aefw_wowlan.bin"; - else - fw_name = "rtlwifi/rtl8812aefw_wowlan.bin"; - err = request_firmware(&wowlan_firmware, fw_name, rtlpriv->io.dev); - if (err) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "Failed to request wowlan firmware!\n"); - goto error; - } - - if (wowlan_firmware->size > 0x8000) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "Wowlan Firmware is too big!\n"); - goto error; - } - - memcpy(rtlpriv->rtlhal.wowlan_firmware, wowlan_firmware->data, - wowlan_firmware->size); - rtlpriv->rtlhal.wowlan_fwsize = wowlan_firmware->size; - release_firmware(wowlan_firmware); - - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "WOWLAN FirmwareDownload OK\n"); - return; -error: - release_firmware(wowlan_firmware); - vfree(rtlpriv->rtlhal.wowlan_firmware); -} - /*InitializeVariables8812E*/ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) { @@ -231,7 +185,6 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) else if (rtlpriv->psc.reg_fwctrl_lps == 3) rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; - rtlpriv->rtl_fw_second_cb = load_wowlan_fw; /* for firmware buf */ rtlpriv->rtlhal.pfirmware = vzalloc(0x8000); if (!rtlpriv->rtlhal.pfirmware) { @@ -239,20 +192,41 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) "Can't alloc buffer for fw.\n"); return 1; } + rtlpriv->rtlhal.wowlan_firmware = vzalloc(0x8000); + if (!rtlpriv->rtlhal.wowlan_firmware) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Can't alloc buffer for wowlan fw.\n"); + return 1; + } - if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { rtlpriv->cfg->fw_name = "rtlwifi/rtl8812aefw.bin"; - else + rtlpriv->cfg->wowlan_fw_name = "rtlwifi/rtl8812aefw_wowlan.bin"; + } else { rtlpriv->cfg->fw_name = "rtlwifi/rtl8821aefw.bin"; + rtlpriv->cfg->wowlan_fw_name = "rtlwifi/rtl8821aefw_wowlan.bin"; + } rtlpriv->max_fw_size = 0x8000; + /*load normal firmware*/ pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name); err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); if (err) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - "Failed to request firmware!\n"); + "Failed to request normal firmware!\n"); + return 1; + } + /*load wowlan firmware*/ + pr_info("Using firmware %s\n", rtlpriv->cfg->wowlan_fw_name); + err = request_firmware_nowait(THIS_MODULE, 1, + rtlpriv->cfg->wowlan_fw_name, + rtlpriv->io.dev, GFP_KERNEL, hw, + rtl_wowlan_fw_cb); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + "Failed to request wowlan firmware!\n"); return 1; } return 0; diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c index 383b86b05cba..72af4b9ee32b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c @@ -48,232 +48,6 @@ static u8 _rtl8821ae_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -/* mac80211's rate_idx is like this: - * - * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ - * - * B/G rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC_RATE1M-->DESC_RATE54M ==> idx is 0-->11, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15 - * - * 5G band:rx_status->band == IEEE80211_BAND_5GHZ - * A rate: - * (rx_status->flag & RX_FLAG_HT) = 0, - * DESC_RATE6M-->DESC_RATE54M ==> idx is 0-->7, - * - * N rate: - * (rx_status->flag & RX_FLAG_HT) = 1, - * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15 - */ -static int _rtl8821ae_rate_mapping(struct ieee80211_hw *hw, - bool isht, bool isvht, u8 desc_rate) -{ - int rate_idx; - - if (!isht) { - if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) { - switch (desc_rate) { - case DESC_RATE1M: - rate_idx = 0; - break; - case DESC_RATE2M: - rate_idx = 1; - break; - case DESC_RATE5_5M: - rate_idx = 2; - break; - case DESC_RATE11M: - rate_idx = 3; - break; - case DESC_RATE6M: - rate_idx = 4; - break; - case DESC_RATE9M: - rate_idx = 5; - break; - case DESC_RATE12M: - rate_idx = 6; - break; - case DESC_RATE18M: - rate_idx = 7; - break; - case DESC_RATE24M: - rate_idx = 8; - break; - case DESC_RATE36M: - rate_idx = 9; - break; - case DESC_RATE48M: - rate_idx = 10; - break; - case DESC_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 0; - break; - } - } else { - switch (desc_rate) { - case DESC_RATE6M: - rate_idx = 0; - break; - case DESC_RATE9M: - rate_idx = 1; - break; - case DESC_RATE12M: - rate_idx = 2; - break; - case DESC_RATE18M: - rate_idx = 3; - break; - case DESC_RATE24M: - rate_idx = 4; - break; - case DESC_RATE36M: - rate_idx = 5; - break; - case DESC_RATE48M: - rate_idx = 6; - break; - case DESC_RATE54M: - rate_idx = 7; - break; - default: - rate_idx = 0; - break; - } - } - } else { - switch (desc_rate) { - case DESC_RATEMCS0: - rate_idx = 0; - break; - case DESC_RATEMCS1: - rate_idx = 1; - break; - case DESC_RATEMCS2: - rate_idx = 2; - break; - case DESC_RATEMCS3: - rate_idx = 3; - break; - case DESC_RATEMCS4: - rate_idx = 4; - break; - case DESC_RATEMCS5: - rate_idx = 5; - break; - case DESC_RATEMCS6: - rate_idx = 6; - break; - case DESC_RATEMCS7: - rate_idx = 7; - break; - case DESC_RATEMCS8: - rate_idx = 8; - break; - case DESC_RATEMCS9: - rate_idx = 9; - break; - case DESC_RATEMCS10: - rate_idx = 10; - break; - case DESC_RATEMCS11: - rate_idx = 11; - break; - case DESC_RATEMCS12: - rate_idx = 12; - break; - case DESC_RATEMCS13: - rate_idx = 13; - break; - case DESC_RATEMCS14: - rate_idx = 14; - break; - case DESC_RATEMCS15: - rate_idx = 15; - break; - default: - rate_idx = 0; - break; - } - } - - if (isvht) { - switch (desc_rate) { - case DESC_RATEVHT1SS_MCS0: - rate_idx = 0; - break; - case DESC_RATEVHT1SS_MCS1: - rate_idx = 1; - break; - case DESC_RATEVHT1SS_MCS2: - rate_idx = 2; - break; - case DESC_RATEVHT1SS_MCS3: - rate_idx = 3; - break; - case DESC_RATEVHT1SS_MCS4: - rate_idx = 4; - break; - case DESC_RATEVHT1SS_MCS5: - rate_idx = 5; - break; - case DESC_RATEVHT1SS_MCS6: - rate_idx = 6; - break; - case DESC_RATEVHT1SS_MCS7: - rate_idx = 7; - break; - case DESC_RATEVHT1SS_MCS8: - rate_idx = 8; - break; - case DESC_RATEVHT1SS_MCS9: - rate_idx = 9; - break; - case DESC_RATEVHT2SS_MCS0: - rate_idx = 0; - break; - case DESC_RATEVHT2SS_MCS1: - rate_idx = 1; - break; - case DESC_RATEVHT2SS_MCS2: - rate_idx = 2; - break; - case DESC_RATEVHT2SS_MCS3: - rate_idx = 3; - break; - case DESC_RATEVHT2SS_MCS4: - rate_idx = 4; - break; - case DESC_RATEVHT2SS_MCS5: - rate_idx = 5; - break; - case DESC_RATEVHT2SS_MCS6: - rate_idx = 6; - break; - case DESC_RATEVHT2SS_MCS7: - rate_idx = 7; - break; - case DESC_RATEVHT2SS_MCS8: - rate_idx = 8; - break; - case DESC_RATEVHT2SS_MCS9: - rate_idx = 9; - break; - default: - rate_idx = 0; - break; - } - } - return rate_idx; -} - static u16 odm_cfo(char value) { int ret_val; @@ -766,9 +540,9 @@ bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw, * supported rates or MCS index if HT rates * are use (RX_FLAG_HT) */ - rx_status->rate_idx = - _rtl8821ae_rate_mapping(hw, status->is_ht, - status->is_vht, status->rate); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht, + status->is_vht, + status->rate); rx_status->mactime = status->timestamp_low; if (phystatus) { diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 6866dcf24340..51572912c53d 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -331,10 +331,10 @@ enum hardware_type { (IS_HARDWARE_TYPE_8723E(rtlhal) || IS_HARDWARE_TYPE_8723U(rtlhal)) #define RX_HAL_IS_CCK_RATE(rxmcs) \ - ((rxmcs) == DESC92_RATE1M || \ - (rxmcs) == DESC92_RATE2M || \ - (rxmcs) == DESC92_RATE5_5M || \ - (rxmcs) == DESC92_RATE11M) + ((rxmcs) == DESC_RATE1M || \ + (rxmcs) == DESC_RATE2M || \ + (rxmcs) == DESC_RATE5_5M || \ + (rxmcs) == DESC_RATE11M) enum scan_operation_backup_opt { SCAN_OPT_BACKUP = 0, @@ -579,38 +579,59 @@ enum rtl_hal_state { }; enum rtl_desc92_rate { - DESC92_RATE1M = 0x00, - DESC92_RATE2M = 0x01, - DESC92_RATE5_5M = 0x02, - DESC92_RATE11M = 0x03, + DESC_RATE1M = 0x00, + DESC_RATE2M = 0x01, + DESC_RATE5_5M = 0x02, + DESC_RATE11M = 0x03, - DESC92_RATE6M = 0x04, - DESC92_RATE9M = 0x05, - DESC92_RATE12M = 0x06, - DESC92_RATE18M = 0x07, - DESC92_RATE24M = 0x08, - DESC92_RATE36M = 0x09, - DESC92_RATE48M = 0x0a, - DESC92_RATE54M = 0x0b, + DESC_RATE6M = 0x04, + DESC_RATE9M = 0x05, + DESC_RATE12M = 0x06, + DESC_RATE18M = 0x07, + DESC_RATE24M = 0x08, + DESC_RATE36M = 0x09, + DESC_RATE48M = 0x0a, + DESC_RATE54M = 0x0b, - DESC92_RATEMCS0 = 0x0c, - DESC92_RATEMCS1 = 0x0d, - DESC92_RATEMCS2 = 0x0e, - DESC92_RATEMCS3 = 0x0f, - DESC92_RATEMCS4 = 0x10, - DESC92_RATEMCS5 = 0x11, - DESC92_RATEMCS6 = 0x12, - DESC92_RATEMCS7 = 0x13, - DESC92_RATEMCS8 = 0x14, - DESC92_RATEMCS9 = 0x15, - DESC92_RATEMCS10 = 0x16, - DESC92_RATEMCS11 = 0x17, - DESC92_RATEMCS12 = 0x18, - DESC92_RATEMCS13 = 0x19, - DESC92_RATEMCS14 = 0x1a, - DESC92_RATEMCS15 = 0x1b, - DESC92_RATEMCS15_SG = 0x1c, - DESC92_RATEMCS32 = 0x20, + DESC_RATEMCS0 = 0x0c, + DESC_RATEMCS1 = 0x0d, + DESC_RATEMCS2 = 0x0e, + DESC_RATEMCS3 = 0x0f, + DESC_RATEMCS4 = 0x10, + DESC_RATEMCS5 = 0x11, + DESC_RATEMCS6 = 0x12, + DESC_RATEMCS7 = 0x13, + DESC_RATEMCS8 = 0x14, + DESC_RATEMCS9 = 0x15, + DESC_RATEMCS10 = 0x16, + DESC_RATEMCS11 = 0x17, + DESC_RATEMCS12 = 0x18, + DESC_RATEMCS13 = 0x19, + DESC_RATEMCS14 = 0x1a, + DESC_RATEMCS15 = 0x1b, + DESC_RATEMCS15_SG = 0x1c, + DESC_RATEMCS32 = 0x20, + + DESC_RATEVHT1SS_MCS0 = 0x2c, + DESC_RATEVHT1SS_MCS1 = 0x2d, + DESC_RATEVHT1SS_MCS2 = 0x2e, + DESC_RATEVHT1SS_MCS3 = 0x2f, + DESC_RATEVHT1SS_MCS4 = 0x30, + DESC_RATEVHT1SS_MCS5 = 0x31, + DESC_RATEVHT1SS_MCS6 = 0x32, + DESC_RATEVHT1SS_MCS7 = 0x33, + DESC_RATEVHT1SS_MCS8 = 0x34, + DESC_RATEVHT1SS_MCS9 = 0x35, + DESC_RATEVHT2SS_MCS0 = 0x36, + DESC_RATEVHT2SS_MCS1 = 0x37, + DESC_RATEVHT2SS_MCS2 = 0x38, + DESC_RATEVHT2SS_MCS3 = 0x39, + DESC_RATEVHT2SS_MCS4 = 0x3a, + DESC_RATEVHT2SS_MCS5 = 0x3b, + DESC_RATEVHT2SS_MCS6 = 0x3c, + DESC_RATEVHT2SS_MCS7 = 0x3d, + DESC_RATEVHT2SS_MCS8 = 0x3e, + DESC_RATEVHT2SS_MCS9 = 0x3f, }; enum rtl_var_map { @@ -2161,6 +2182,7 @@ struct rtl_hal_ops { void (*add_wowlan_pattern)(struct ieee80211_hw *hw, struct rtl_wow_pattern *rtl_pattern, u8 index); + u16 (*get_available_desc)(struct ieee80211_hw *hw, u8 q_idx); }; struct rtl_intf_ops { @@ -2242,6 +2264,7 @@ struct rtl_hal_cfg { char *name; char *fw_name; char *alt_fw_name; + char *wowlan_fw_name; struct rtl_hal_ops *ops; struct rtl_mod_params *mod_params; struct rtl_hal_usbint_cfg *usb_interface_cfg; @@ -2390,8 +2413,6 @@ struct dig_t { u8 pre_ccastate; u8 cur_ccasate; u8 large_fa_hit; - u8 dig_dynamic_min; - u8 dig_dynamic_min_1; u8 forbidden_igi; u8 dig_state; u8 dig_highpwrstate; @@ -2518,8 +2539,6 @@ struct proxim { struct rtl_priv { struct ieee80211_hw *hw; - /* Used to load a second firmware */ - void (*rtl_fw_second_cb)(struct rtl_priv *rtlpriv); struct completion firmware_loading_complete; struct list_head list; struct rtl_priv *buddy_priv; diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 0b30a7b4d663..d4ba009ac9aa 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -500,6 +500,7 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, int ret = 0; vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_UAPSD | IEEE80211_VIF_SUPPORTS_CQM_RSSI; wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", @@ -1480,9 +1481,7 @@ int wl1251_init_ieee80211(struct wl1251 *wl) /* unit us */ /* FIXME: find a proper value */ - wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_UAPSD; + wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS; wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index d6d0d6d9c7a8..144d1f8ba473 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -250,6 +250,7 @@ static struct wlcore_conf wl12xx_conf = { .keep_alive_interval = 55000, .max_listen_interval = 20, .sta_sleep_auth = WL1271_PSM_ILLEGAL, + .suspend_rx_ba_activity = 0, }, .itrim = { .enable = false, @@ -1728,6 +1729,9 @@ static struct wlcore_ops wl12xx_ops = { .convert_hwaddr = wl12xx_convert_hwaddr, .lnk_high_prio = wl12xx_lnk_high_prio, .lnk_low_prio = wl12xx_lnk_low_prio, + .interrupt_notify = NULL, + .rx_ba_filter = NULL, + .ap_sleep = NULL, }; static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c index a169bb5a5dbf..67f2a0eec854 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.c +++ b/drivers/net/wireless/ti/wl18xx/acx.c @@ -24,6 +24,7 @@ #include "../wlcore/acx.h" #include "acx.h" +#include "wl18xx.h" int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, u32 sdio_blk_size, u32 extra_mem_blks, @@ -194,3 +195,90 @@ out: kfree(acx); return ret; } + +/* + * When the host is suspended, we don't want to get any fast-link/PSM + * notifications + */ +int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, + bool action) +{ + struct wl18xx_acx_interrupt_notify *acx; + int ret = 0; + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->enable = action; + ret = wl1271_cmd_configure(wl, ACX_INTERRUPT_NOTIFY, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx interrupt notify setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +/* + * When the host is suspended, we can configure the FW to disable RX BA + * notifications. + */ +int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action) +{ + struct wl18xx_acx_rx_ba_filter *acx; + int ret = 0; + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->enable = (u32)action; + ret = wl1271_cmd_configure(wl, ACX_RX_BA_FILTER, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx rx ba activity filter setting failed: %d", + ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl18xx_acx_ap_sleep(struct wl1271 *wl) +{ + struct wl18xx_priv *priv = wl->priv; + struct acx_ap_sleep_cfg *acx; + struct conf_ap_sleep_settings *conf = &priv->conf.ap_sleep; + int ret; + + wl1271_debug(DEBUG_ACX, "acx config ap sleep"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->idle_duty_cycle = conf->idle_duty_cycle; + acx->connected_duty_cycle = conf->connected_duty_cycle; + acx->max_stations_thresh = conf->max_stations_thresh; + acx->idle_conn_thresh = conf->idle_conn_thresh; + + ret = wl1271_cmd_configure(wl, ACX_AP_SLEEP_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx config ap-sleep failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h index 0e636def1217..4afccd4b9467 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.h +++ b/drivers/net/wireless/ti/wl18xx/acx.h @@ -32,7 +32,10 @@ enum { ACX_SIM_CONFIG = 0x0053, ACX_CLEAR_STATISTICS = 0x0054, ACX_AUTO_RX_STREAMING = 0x0055, - ACX_PEER_CAP = 0x0056 + ACX_PEER_CAP = 0x0056, + ACX_INTERRUPT_NOTIFY = 0x0057, + ACX_RX_BA_FILTER = 0x0058, + ACX_AP_SLEEP_CFG = 0x0059 }; /* numbers of bits the length field takes (add 1 for the actual number) */ @@ -326,6 +329,44 @@ struct wlcore_acx_peer_cap { u8 padding; } __packed; +/* + * ACX_INTERRUPT_NOTIFY + * enable/disable fast-link/PSM notification from FW + */ +struct wl18xx_acx_interrupt_notify { + struct acx_header header; + u32 enable; +}; + +/* + * ACX_RX_BA_FILTER + * enable/disable RX BA filtering in FW + */ +struct wl18xx_acx_rx_ba_filter { + struct acx_header header; + u32 enable; +}; + +struct acx_ap_sleep_cfg { + struct acx_header header; + /* Duty Cycle (20-80% of staying Awake) for IDLE AP + * (0: disable) + */ + u8 idle_duty_cycle; + /* Duty Cycle (20-80% of staying Awake) for Connected AP + * (0: disable) + */ + u8 connected_duty_cycle; + /* Maximum stations that are allowed to be connected to AP + * (255: no limit) + */ + u8 max_stations_thresh; + /* Timeout till enabling the Sleep Mechanism after data stops + * [unit: 100 msec] + */ + u8 idle_conn_thresh; +} __packed; + int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, u32 sdio_blk_size, u32 extra_mem_blks, u32 len_field_size); @@ -336,5 +377,8 @@ int wl18xx_acx_set_peer_cap(struct wl1271 *wl, struct ieee80211_sta_ht_cap *ht_cap, bool allow_ht_operation, u32 rate_set, u8 hlid); +int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, bool action); +int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action); +int wl18xx_acx_ap_sleep(struct wl1271 *wl); #endif /* __WL18XX_ACX_H__ */ diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c index 44f0b205b065..a8d176ddc73c 100644 --- a/drivers/net/wireless/ti/wl18xx/cmd.c +++ b/drivers/net/wireless/ti/wl18xx/cmd.c @@ -33,7 +33,8 @@ int wl18xx_cmd_channel_switch(struct wl1271 *wl, u32 supported_rates; int ret; - wl1271_debug(DEBUG_ACX, "cmd channel switch"); + wl1271_debug(DEBUG_ACX, "cmd channel switch (count=%d)", + ch_switch->count); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -60,8 +61,12 @@ int wl18xx_cmd_channel_switch(struct wl1271 *wl, goto out_free; } - supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES | - wlcore_hw_sta_get_ap_rate_mask(wl, wlvif); + supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES; + if (wlvif->bss_type == BSS_TYPE_STA_BSS) + supported_rates |= wlcore_hw_sta_get_ap_rate_mask(wl, wlvif); + else + supported_rates |= + wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif); if (wlvif->p2p) supported_rates &= ~CONF_TX_CCK_RATES; cmd->local_supported_rates = cpu_to_le32(supported_rates); @@ -167,3 +172,85 @@ out_free: out: return ret; } + +int wl18xx_cmd_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start) +{ + struct wlcore_cmd_cac_start *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd cac (channel %d) %s", + wlvif->channel, start ? "start" : "stop"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->role_id = wlvif->role_id; + cmd->channel = wlvif->channel; + if (wlvif->band == IEEE80211_BAND_5GHZ) + cmd->band = WLCORE_BAND_5GHZ; + cmd->bandwidth = wlcore_get_native_channel_type(wlvif->channel_type); + + ret = wl1271_cmd_send(wl, + start ? CMD_CAC_START : CMD_CAC_STOP, + cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send cac command"); + goto out_free; + } + +out_free: + kfree(cmd); + return ret; +} + +int wl18xx_cmd_radar_detection_debug(struct wl1271 *wl, u8 channel) +{ + struct wl18xx_cmd_dfs_radar_debug *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd radar detection debug (chan %d)", + channel); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->channel = channel; + + ret = wl1271_cmd_send(wl, CMD_DFS_RADAR_DETECTION_DEBUG, + cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send radar detection debug command"); + goto out_free; + } + +out_free: + kfree(cmd); + return ret; +} + +int wl18xx_cmd_dfs_master_restart(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct wl18xx_cmd_dfs_master_restart *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd dfs master restart (role %d)", + wlvif->role_id); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->role_id = wlvif->role_id; + + ret = wl1271_cmd_send(wl, CMD_DFS_MASTER_RESTART, + cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send dfs master restart command"); + goto out_free; + } +out_free: + kfree(cmd); + return ret; +} diff --git a/drivers/net/wireless/ti/wl18xx/cmd.h b/drivers/net/wireless/ti/wl18xx/cmd.h index 92499e2dfa83..7f9440a2bff8 100644 --- a/drivers/net/wireless/ti/wl18xx/cmd.h +++ b/drivers/net/wireless/ti/wl18xx/cmd.h @@ -59,6 +59,30 @@ struct wl18xx_cmd_smart_config_set_group_key { u8 key[16]; } __packed; +struct wl18xx_cmd_dfs_radar_debug { + struct wl1271_cmd_header header; + + u8 channel; + u8 padding[3]; +} __packed; + +struct wl18xx_cmd_dfs_master_restart { + struct wl1271_cmd_header header; + + u8 role_id; + u8 padding[3]; +} __packed; + +/* cac_start and cac_stop share the same params */ +struct wlcore_cmd_cac_start { + struct wl1271_cmd_header header; + + u8 role_id; + u8 channel; + u8 band; + u8 bandwidth; +} __packed; + int wl18xx_cmd_channel_switch(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct ieee80211_channel_switch *ch_switch); @@ -66,4 +90,7 @@ int wl18xx_cmd_smart_config_start(struct wl1271 *wl, u32 group_bitmap); int wl18xx_cmd_smart_config_stop(struct wl1271 *wl); int wl18xx_cmd_smart_config_set_group_key(struct wl1271 *wl, u16 group_id, u8 key_len, u8 *key); +int wl18xx_cmd_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start); +int wl18xx_cmd_radar_detection_debug(struct wl1271 *wl, u8 channel); +int wl18xx_cmd_dfs_master_restart(struct wl1271 *wl, struct wl12xx_vif *wlvif); #endif diff --git a/drivers/net/wireless/ti/wl18xx/conf.h b/drivers/net/wireless/ti/wl18xx/conf.h index e34302e3b51d..71f1ec448ba5 100644 --- a/drivers/net/wireless/ti/wl18xx/conf.h +++ b/drivers/net/wireless/ti/wl18xx/conf.h @@ -23,7 +23,7 @@ #define __WL18XX_CONF_H__ #define WL18XX_CONF_MAGIC 0x10e100ca -#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0006) +#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0007) #define WL18XX_CONF_MASK 0x0000ffff #define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \ sizeof(struct wl18xx_priv_conf)) @@ -110,12 +110,33 @@ struct wl18xx_ht_settings { u8 mode; } __packed; +struct conf_ap_sleep_settings { + /* Duty Cycle (20-80% of staying Awake) for IDLE AP + * (0: disable) + */ + u8 idle_duty_cycle; + /* Duty Cycle (20-80% of staying Awake) for Connected AP + * (0: disable) + */ + u8 connected_duty_cycle; + /* Maximum stations that are allowed to be connected to AP + * (255: no limit) + */ + u8 max_stations_thresh; + /* Timeout till enabling the Sleep Mechanism after data stops + * [unit: 100 msec] + */ + u8 idle_conn_thresh; +} __packed; + struct wl18xx_priv_conf { /* Module params structures */ struct wl18xx_ht_settings ht; /* this structure is copied wholesale to FW */ struct wl18xx_mac_and_phy_params phy; + + struct conf_ap_sleep_settings ap_sleep; } __packed; #endif /* __WL18XX_CONF_H__ */ diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c index 7f1669cdea09..c93fae95baac 100644 --- a/drivers/net/wireless/ti/wl18xx/debugfs.c +++ b/drivers/net/wireless/ti/wl18xx/debugfs.c @@ -22,9 +22,12 @@ #include "../wlcore/debugfs.h" #include "../wlcore/wlcore.h" +#include "../wlcore/debug.h" +#include "../wlcore/ps.h" #include "wl18xx.h" #include "acx.h" +#include "cmd.h" #include "debugfs.h" #define WL18XX_DEBUGFS_FWSTATS_FILE(a, b, c) \ @@ -239,6 +242,45 @@ static const struct file_operations clear_fw_stats_ops = { .llseek = default_llseek, }; +static ssize_t radar_detection_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + int ret; + u8 channel; + + ret = kstrtou8_from_user(user_buf, count, 10, &channel); + if (ret < 0) { + wl1271_warning("illegal channel"); + return -EINVAL; + } + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl18xx_cmd_radar_detection_debug(wl, channel); + if (ret < 0) + count = ret; + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + return count; +} + +static const struct file_operations radar_detection_ops = { + .write = radar_detection_write, + .open = simple_open, + .llseek = default_llseek, +}; + int wl18xx_debugfs_add_files(struct wl1271 *wl, struct dentry *rootdir) { @@ -390,6 +432,7 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_FWSTATS_ADD(mem, fw_gen_free_mem_blks); DEBUGFS_ADD(conf, moddir); + DEBUGFS_ADD(radar_detection, moddir); return 0; diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c index eb1848e08424..c28f06854195 100644 --- a/drivers/net/wireless/ti/wl18xx/event.c +++ b/drivers/net/wireless/ti/wl18xx/event.c @@ -47,6 +47,19 @@ int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout); } +static const char *wl18xx_radar_type_decode(u8 radar_type) +{ + switch (radar_type) { + case RADAR_TYPE_REGULAR: + return "REGULAR"; + case RADAR_TYPE_CHIRP: + return "CHIRP"; + case RADAR_TYPE_NONE: + default: + return "N/A"; + } +} + static int wlcore_smart_config_sync_event(struct wl1271 *wl, u8 sync_channel, u8 sync_band) { @@ -115,6 +128,14 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl) wl18xx_scan_completed(wl, wl->scan_wlvif); } + if (vector & RADAR_DETECTED_EVENT_ID) { + wl1271_info("radar event: channel %d type %s", + mbox->radar_channel, + wl18xx_radar_type_decode(mbox->radar_type)); + + ieee80211_radar_detected(wl->hw); + } + if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT (results %d)", diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h index 0680312d4943..266ee87834e4 100644 --- a/drivers/net/wireless/ti/wl18xx/event.h +++ b/drivers/net/wireless/ti/wl18xx/event.h @@ -42,6 +42,12 @@ enum { SMART_CONFIG_DECODE_EVENT_ID = BIT(23), }; +enum wl18xx_radar_types { + RADAR_TYPE_NONE, + RADAR_TYPE_REGULAR, + RADAR_TYPE_CHIRP +}; + struct wl18xx_event_mailbox { __le32 events_vector; @@ -83,13 +89,19 @@ struct wl18xx_event_mailbox { u8 sc_token_len; u8 padding1; u8 sc_ssid[32]; - u8 sc_pwd[32]; + u8 sc_pwd[64]; u8 sc_token[32]; /* smart config sync channel */ u8 sc_sync_channel; u8 sc_sync_band; u8 padding2[2]; + + /* radar detect */ + u8 radar_channel; + u8 radar_type; + + u8 padding3[2]; } __packed; int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 8e562610bf16..717c4f5a02c2 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -378,6 +378,7 @@ static struct wlcore_conf wl18xx_conf = { .keep_alive_interval = 55000, .max_listen_interval = 20, .sta_sleep_auth = WL1271_PSM_ILLEGAL, + .suspend_rx_ba_activity = 0, }, .itrim = { .enable = false, @@ -567,6 +568,12 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = { .high_power_val_2nd = 0xff, .tx_rf_margin = 1, }, + .ap_sleep = { /* disabled by default */ + .idle_duty_cycle = 0, + .connected_duty_cycle = 0, + .max_stations_thresh = 0, + .idle_conn_thresh = 0, + }, }; static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = { @@ -648,7 +655,7 @@ static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = { }; /* TODO: maybe move to a new header file? */ -#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-3.bin" +#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-4.bin" static int wl18xx_identify_chip(struct wl1271 *wl) { @@ -983,6 +990,7 @@ static int wl18xx_boot(struct wl1271 *wl) wl->event_mask = BSS_LOSS_EVENT_ID | SCAN_COMPLETE_EVENT_ID | + RADAR_DETECTED_EVENT_ID | RSSI_SNR_TRIGGER_0_EVENT_ID | PERIODIC_SCAN_COMPLETE_EVENT_ID | PERIODIC_SCAN_REPORT_EVENT_ID | @@ -1559,26 +1567,19 @@ static u32 wl18xx_pre_pkt_send(struct wl1271 *wl, } static void wl18xx_sta_rc_update(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta, - u32 changed) + struct wl12xx_vif *wlvif) { - bool wide = sta->bandwidth >= IEEE80211_STA_RX_BW_40; + bool wide = wlvif->rc_update_bw >= IEEE80211_STA_RX_BW_40; wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide); - if (!(changed & IEEE80211_RC_BW_CHANGED)) - return; - - mutex_lock(&wl->mutex); - /* sanity */ if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS)) - goto out; + return; /* ignore the change before association */ if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) - goto out; + return; /* * If we started out as wide, we can change the operation mode. If we @@ -1589,9 +1590,6 @@ static void wl18xx_sta_rc_update(struct wl1271 *wl, wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide); else ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif)); - -out: - mutex_unlock(&wl->mutex); } static int wl18xx_set_peer_cap(struct wl1271 *wl, @@ -1703,6 +1701,11 @@ static struct wlcore_ops wl18xx_ops = { .smart_config_start = wl18xx_cmd_smart_config_start, .smart_config_stop = wl18xx_cmd_smart_config_stop, .smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key, + .interrupt_notify = wl18xx_acx_interrupt_notify_config, + .rx_ba_filter = wl18xx_acx_rx_ba_filter, + .ap_sleep = wl18xx_acx_ap_sleep, + .set_cac = wl18xx_cmd_set_cac, + .dfs_master_restart = wl18xx_cmd_dfs_master_restart, }; /* HT cap appropriate for wide channels in 2Ghz */ @@ -1796,6 +1799,10 @@ wl18xx_iface_combinations[] = { .limits = wl18xx_iface_ap_limits, .n_limits = ARRAY_SIZE(wl18xx_iface_ap_limits), .num_different_channels = 1, + .radar_detect_widths = BIT(NL80211_CHAN_NO_HT) | + BIT(NL80211_CHAN_HT20) | + BIT(NL80211_CHAN_HT40MINUS) | + BIT(NL80211_CHAN_HT40PLUS), } }; diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h index 6a2b88030c1d..71e9e382ce80 100644 --- a/drivers/net/wireless/ti/wl18xx/wl18xx.h +++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h @@ -26,10 +26,10 @@ /* minimum FW required for driver */ #define WL18XX_CHIP_VER 8 -#define WL18XX_IFTYPE_VER 8 +#define WL18XX_IFTYPE_VER 9 #define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE #define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE -#define WL18XX_MINOR_VER 13 +#define WL18XX_MINOR_VER 11 #define WL18XX_CMD_MAX_SIZE 740 diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c index b924ceadc02c..f28fa3b5029d 100644 --- a/drivers/net/wireless/ti/wlcore/acx.c +++ b/drivers/net/wireless/ti/wlcore/acx.c @@ -1725,7 +1725,7 @@ int wl12xx_acx_config_hangover(struct wl1271 *wl) acx->decrease_delta = conf->decrease_delta; acx->quiet_time = conf->quiet_time; acx->increase_time = conf->increase_time; - acx->window_size = acx->window_size; + acx->window_size = conf->window_size; ret = wl1271_cmd_configure(wl, ACX_CONFIG_HANGOVER, acx, sizeof(*acx)); diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index b82661962d33..c26fc2106e5b 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -403,7 +403,7 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) WARN_ON_ONCE(wl->active_link_count < 0); } -static u8 wlcore_get_native_channel_type(u8 nl_channel_type) +u8 wlcore_get_native_channel_type(u8 nl_channel_type) { switch (nl_channel_type) { case NL80211_CHAN_NO_HT: @@ -419,6 +419,7 @@ static u8 wlcore_get_native_channel_type(u8 nl_channel_type) return WLCORE_CHAN_NO_HT; } } +EXPORT_SYMBOL_GPL(wlcore_get_native_channel_type); static int wl12xx_cmd_role_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif, @@ -1686,9 +1687,7 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl) { struct wl12xx_cmd_regdomain_dfs_config *cmd = NULL; int ret = 0, i, b, ch_bit_idx; - struct ieee80211_channel *channel; u32 tmp_ch_bitmap[2]; - u16 ch; struct wiphy *wiphy = wl->hw->wiphy; struct ieee80211_supported_band *band; bool timeout = false; @@ -1703,12 +1702,16 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl) for (b = IEEE80211_BAND_2GHZ; b <= IEEE80211_BAND_5GHZ; b++) { band = wiphy->bands[b]; for (i = 0; i < band->n_channels; i++) { - channel = &band->channels[i]; - ch = channel->hw_value; + struct ieee80211_channel *channel = &band->channels[i]; + u16 ch = channel->hw_value; + u32 flags = channel->flags; - if (channel->flags & (IEEE80211_CHAN_DISABLED | - IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_NO_IR)) + if (flags & (IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_NO_IR)) + continue; + + if ((flags & IEEE80211_CHAN_RADAR) && + channel->dfs_state != NL80211_DFS_AVAILABLE) continue; ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch); @@ -1733,6 +1736,7 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl) cmd->ch_bit_map1 = cpu_to_le32(tmp_ch_bitmap[0]); cmd->ch_bit_map2 = cpu_to_le32(tmp_ch_bitmap[1]); + cmd->dfs_region = wl->dfs_region; wl1271_debug(DEBUG_CMD, "cmd reg domain bitmap1: 0x%08x, bitmap2: 0x%08x", diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index 453684a71d30..e14cd407a6ae 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -105,6 +105,7 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid); int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask, bool *timeout); +u8 wlcore_get_native_channel_type(u8 nl_channel_type); enum wl1271_commands { CMD_INTERROGATE = 1, /* use this to read information elements */ @@ -172,6 +173,11 @@ enum wl1271_commands { CMD_SMART_CONFIG_STOP = 62, CMD_SMART_CONFIG_SET_GROUP_KEY = 63, + CMD_CAC_START = 64, + CMD_CAC_STOP = 65, + CMD_DFS_MASTER_RESTART = 66, + CMD_DFS_RADAR_DETECTION_DEBUG = 67, + MAX_COMMAND_ID = 0xFFFF, }; @@ -642,6 +648,8 @@ struct wl12xx_cmd_regdomain_dfs_config { __le32 ch_bit_map1; __le32 ch_bit_map2; + u8 dfs_region; + u8 padding[3]; } __packed; struct wl12xx_cmd_config_fwlog { diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h index 40995c42bef8..166add00b50f 100644 --- a/drivers/net/wireless/ti/wlcore/conf.h +++ b/drivers/net/wireless/ti/wlcore/conf.h @@ -997,6 +997,11 @@ struct conf_conn_settings { * whether we can go to ELP. */ u8 sta_sleep_auth; + + /* + * Default RX BA Activity filter configuration + */ + u8 suspend_rx_ba_activity; } __packed; enum { @@ -1347,7 +1352,7 @@ struct conf_recovery_settings { * version, the two LSB are the lower driver's private conf * version. */ -#define WLCORE_CONF_VERSION (0x0005 << 16) +#define WLCORE_CONF_VERSION (0x0006 << 16) #define WLCORE_CONF_MASK 0xffff0000 #define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \ sizeof(struct wlcore_conf)) diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c index 0be21f62fcb0..68f3bf229b5a 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/drivers/net/wireless/ti/wlcore/debugfs.c @@ -929,17 +929,10 @@ static ssize_t beacon_filtering_write(struct file *file, { struct wl1271 *wl = file->private_data; struct wl12xx_vif *wlvif; - 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); + ret = kstrtoul_from_user(user_buf, count, 0, &value); if (ret < 0) { wl1271_warning("illegal value for beacon_filtering!"); return -EINVAL; diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index 5153640f4532..c42e78955e7b 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c @@ -139,7 +139,7 @@ void wlcore_event_channel_switch(struct wl1271 *wl, wl1271_debug(DEBUG_EVENT, "%s: roles=0x%lx success=%d", __func__, roles_bitmap, success); - wl12xx_for_each_wlvif_sta(wl, wlvif) { + wl12xx_for_each_wlvif(wl, wlvif) { if (wlvif->role_id == WL12XX_INVALID_ROLE_ID || !test_bit(wlvif->role_id , &roles_bitmap)) continue; @@ -150,8 +150,13 @@ void wlcore_event_channel_switch(struct wl1271 *wl, vif = wl12xx_wlvif_to_vif(wlvif); - ieee80211_chswitch_done(vif, success); - cancel_delayed_work(&wlvif->channel_switch_work); + if (wlvif->bss_type == BSS_TYPE_STA_BSS) { + ieee80211_chswitch_done(vif, success); + cancel_delayed_work(&wlvif->channel_switch_work); + } else { + set_bit(WLVIF_FLAG_BEACON_DISABLED, &wlvif->flags); + ieee80211_csa_finish(vif); + } } } EXPORT_SYMBOL_GPL(wlcore_event_channel_switch); diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h index aa9f82c72296..eec56935b1b6 100644 --- a/drivers/net/wireless/ti/wlcore/hw_ops.h +++ b/drivers/net/wireless/ti/wlcore/hw_ops.h @@ -211,11 +211,35 @@ wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len) } static inline void -wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta, u32 changed) +wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif) { if (wl->ops->sta_rc_update) - wl->ops->sta_rc_update(wl, wlvif, sta, changed); + wl->ops->sta_rc_update(wl, wlvif); +} + +static inline int +wlcore_hw_interrupt_notify(struct wl1271 *wl, bool action) +{ + if (wl->ops->interrupt_notify) + return wl->ops->interrupt_notify(wl, action); + return 0; +} + +static inline int +wlcore_hw_rx_ba_filter(struct wl1271 *wl, bool action) +{ + if (wl->ops->rx_ba_filter) + return wl->ops->rx_ba_filter(wl, action); + return 0; +} + +static inline int +wlcore_hw_ap_sleep(struct wl1271 *wl) +{ + if (wl->ops->ap_sleep) + return wl->ops->ap_sleep(wl); + + return 0; } static inline int @@ -287,4 +311,22 @@ wlcore_smart_config_set_group_key(struct wl1271 *wl, u16 group_id, return wl->ops->smart_config_set_group_key(wl, group_id, key_len, key); } + +static inline int +wlcore_hw_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start) +{ + if (!wl->ops->set_cac) + return -EINVAL; + + return wl->ops->set_cac(wl, wlvif, start); +} + +static inline int +wlcore_hw_dfs_master_restart(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + if (!wl->ops->dfs_master_restart) + return -EINVAL; + + return wl->ops->dfs_master_restart(wl, wlvif); +} #endif diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c index 199e94120864..5ca1fb161a50 100644 --- a/drivers/net/wireless/ti/wlcore/init.c +++ b/drivers/net/wireless/ti/wlcore/init.c @@ -392,6 +392,11 @@ static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) if (ret < 0) return ret; + /* configure AP sleep, if enabled */ + ret = wlcore_hw_ap_sleep(wl); + if (ret < 0) + return ret; + return 0; } @@ -567,8 +572,7 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif) /* consider all existing roles before configuring psm. */ if (wl->ap_count == 0 && is_ap) { /* first AP */ - /* Configure for power always on */ - ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); if (ret < 0) return ret; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 6ad3fcedab9b..1e136993580f 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -79,22 +79,12 @@ static int wl12xx_set_authorized(struct wl1271 *wl, struct wl12xx_vif *wlvif) static void wl1271_reg_notify(struct wiphy *wiphy, struct regulatory_request *request) { - struct ieee80211_supported_band *band; - struct ieee80211_channel *ch; - int i; struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct wl1271 *wl = hw->priv; - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - for (i = 0; i < band->n_channels; i++) { - ch = &band->channels[i]; - if (ch->flags & IEEE80211_CHAN_DISABLED) - continue; - - if (ch->flags & IEEE80211_CHAN_RADAR) - ch->flags |= IEEE80211_CHAN_NO_IR; - - } + /* copy the current dfs region */ + if (request) + wl->dfs_region = request->dfs_region; wlcore_regdomain_config(wl); } @@ -226,6 +216,29 @@ void wl12xx_rearm_tx_watchdog_locked(struct wl1271 *wl) msecs_to_jiffies(wl->conf.tx.tx_watchdog_timeout)); } +static void wlcore_rc_update_work(struct work_struct *work) +{ + int ret; + struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif, + rc_update_work); + struct wl1271 *wl = wlvif->wl; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wlcore_hw_sta_rc_update(wl, wlvif); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + static void wl12xx_tx_watchdog_work(struct work_struct *work) { struct delayed_work *dwork; @@ -1662,19 +1675,15 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl, if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) goto out; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - ret = wl1271_configure_wowlan(wl, wow); if (ret < 0) - goto out_sleep; + goto out; if ((wl->conf.conn.suspend_wake_up_event == wl->conf.conn.wake_up_event) && (wl->conf.conn.suspend_listen_interval == wl->conf.conn.listen_interval)) - goto out_sleep; + goto out; ret = wl1271_acx_wake_up_conditions(wl, wlvif, wl->conf.conn.suspend_wake_up_event, @@ -1682,29 +1691,28 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl, if (ret < 0) wl1271_error("suspend: set wake up conditions failed: %d", ret); - -out_sleep: - wl1271_ps_elp_sleep(wl); out: return ret; } static int wl1271_configure_suspend_ap(struct wl1271 *wl, - struct wl12xx_vif *wlvif) + struct wl12xx_vif *wlvif, + struct cfg80211_wowlan *wow) { int ret = 0; if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) goto out; - ret = wl1271_ps_elp_wakeup(wl); + ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); if (ret < 0) goto out; - ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); + ret = wl1271_configure_wowlan(wl, wow); + if (ret < 0) + goto out; - wl1271_ps_elp_sleep(wl); out: return ret; @@ -1717,7 +1725,7 @@ static int wl1271_configure_suspend(struct wl1271 *wl, if (wlvif->bss_type == BSS_TYPE_STA_BSS) return wl1271_configure_suspend_sta(wl, wlvif, wow); if (wlvif->bss_type == BSS_TYPE_AP_BSS) - return wl1271_configure_suspend_ap(wl, wlvif); + return wl1271_configure_suspend_ap(wl, wlvif, wow); return 0; } @@ -1730,21 +1738,18 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif) if ((!is_ap) && (!is_sta)) return; - if (is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + if ((is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) || + (is_ap && !test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))) return; - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - return; + wl1271_configure_wowlan(wl, NULL); if (is_sta) { - wl1271_configure_wowlan(wl, NULL); - if ((wl->conf.conn.suspend_wake_up_event == wl->conf.conn.wake_up_event) && (wl->conf.conn.suspend_listen_interval == wl->conf.conn.listen_interval)) - goto out_sleep; + return; ret = wl1271_acx_wake_up_conditions(wl, wlvif, wl->conf.conn.wake_up_event, @@ -1757,9 +1762,6 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif) } else if (is_ap) { ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); } - -out_sleep: - wl1271_ps_elp_sleep(wl); } static int wl1271_op_suspend(struct ieee80211_hw *hw, @@ -1781,6 +1783,13 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, wl1271_tx_flush(wl); mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) { + mutex_unlock(&wl->mutex); + return ret; + } + wl->wow_enabled = true; wl12xx_for_each_wlvif(wl, wlvif) { ret = wl1271_configure_suspend(wl, wlvif, wow); @@ -1790,7 +1799,27 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, return ret; } } + + /* disable fast link flow control notifications from FW */ + ret = wlcore_hw_interrupt_notify(wl, false); + if (ret < 0) + goto out_sleep; + + /* if filtering is enabled, configure the FW to drop all RX BA frames */ + ret = wlcore_hw_rx_ba_filter(wl, + !!wl->conf.conn.suspend_rx_ba_activity); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); mutex_unlock(&wl->mutex); + + if (ret < 0) { + wl1271_warning("couldn't prepare device to suspend"); + return ret; + } + /* flush any remaining work */ wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); @@ -1864,13 +1893,29 @@ static int wl1271_op_resume(struct ieee80211_hw *hw) if (pending_recovery) { wl1271_warning("queuing forgotten recovery on resume"); ieee80211_queue_work(wl->hw, &wl->recovery_work); - goto out; + goto out_sleep; } + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + wl12xx_for_each_wlvif(wl, wlvif) { wl1271_configure_resume(wl, wlvif); } + ret = wlcore_hw_interrupt_notify(wl, true); + if (ret < 0) + goto out_sleep; + + /* if filtering is enabled, configure the FW to drop all RX BA frames */ + ret = wlcore_hw_rx_ba_filter(wl, false); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); + out: wl->wow_enabled = false; @@ -2279,6 +2324,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) wl1271_rx_streaming_enable_work); INIT_WORK(&wlvif->rx_streaming_disable_work, wl1271_rx_streaming_disable_work); + INIT_WORK(&wlvif->rc_update_work, wlcore_rc_update_work); INIT_DELAYED_WORK(&wlvif->channel_switch_work, wlcore_channel_switch_work); INIT_DELAYED_WORK(&wlvif->connection_loss_work, @@ -2508,6 +2554,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, } vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_UAPSD | IEEE80211_VIF_SUPPORTS_CQM_RSSI; wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", @@ -2723,6 +2770,7 @@ unlock: del_timer_sync(&wlvif->rx_streaming_timer); cancel_work_sync(&wlvif->rx_streaming_enable_work); cancel_work_sync(&wlvif->rx_streaming_disable_work); + cancel_work_sync(&wlvif->rc_update_work); cancel_delayed_work_sync(&wlvif->connection_loss_work); cancel_delayed_work_sync(&wlvif->channel_switch_work); cancel_delayed_work_sync(&wlvif->pending_auth_complete_work); @@ -4072,8 +4120,14 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, ret = wlcore_set_beacon_template(wl, vif, is_ap); if (ret < 0) goto out; - } + if (test_and_clear_bit(WLVIF_FLAG_BEACON_DISABLED, + &wlvif->flags)) { + ret = wlcore_hw_dfs_master_restart(wl, wlvif); + if (ret < 0) + goto out; + } + } out: if (ret != 0) wl1271_error("beacon info change failed: %d", ret); @@ -4574,10 +4628,46 @@ static void wlcore_op_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx, u32 changed) { + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; + int ret; + int channel = ieee80211_frequency_to_channel( + ctx->def.chan->center_freq); + wl1271_debug(DEBUG_MAC80211, "mac80211 change chanctx %d (type %d) changed 0x%x", - ieee80211_frequency_to_channel(ctx->def.chan->center_freq), - cfg80211_get_chandef_type(&ctx->def), changed); + channel, cfg80211_get_chandef_type(&ctx->def), changed); + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl12xx_for_each_wlvif(wl, wlvif) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + + rcu_read_lock(); + if (rcu_access_pointer(vif->chanctx_conf) != ctx) { + rcu_read_unlock(); + continue; + } + rcu_read_unlock(); + + /* start radar if needed */ + if (changed & IEEE80211_CHANCTX_CHANGE_RADAR && + wlvif->bss_type == BSS_TYPE_AP_BSS && + ctx->radar_enabled && !wlvif->radar_enabled && + ctx->def.chan->dfs_state == NL80211_DFS_USABLE) { + wl1271_debug(DEBUG_MAC80211, "Start radar detection"); + wlcore_hw_set_cac(wl, wlvif, true); + wlvif->radar_enabled = true; + } + } + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); } static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, @@ -4588,13 +4678,26 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int channel = ieee80211_frequency_to_channel( ctx->def.chan->center_freq); + int ret = -EINVAL; wl1271_debug(DEBUG_MAC80211, - "mac80211 assign chanctx (role %d) %d (type %d)", - wlvif->role_id, channel, cfg80211_get_chandef_type(&ctx->def)); + "mac80211 assign chanctx (role %d) %d (type %d) (radar %d dfs_state %d)", + wlvif->role_id, channel, + cfg80211_get_chandef_type(&ctx->def), + ctx->radar_enabled, ctx->def.chan->dfs_state); mutex_lock(&wl->mutex); + if (unlikely(wl->state != WLCORE_STATE_ON)) + goto out; + + if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + wlvif->band = ctx->def.chan->band; wlvif->channel = channel; wlvif->channel_type = cfg80211_get_chandef_type(&ctx->def); @@ -4602,6 +4705,15 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, /* update default rates according to the band */ wl1271_set_band_rate(wl, wlvif); + if (ctx->radar_enabled && + ctx->def.chan->dfs_state == NL80211_DFS_USABLE) { + wl1271_debug(DEBUG_MAC80211, "Start radar detection"); + wlcore_hw_set_cac(wl, wlvif, true); + wlvif->radar_enabled = true; + } + + wl1271_ps_elp_sleep(wl); +out: mutex_unlock(&wl->mutex); return 0; @@ -4613,6 +4725,7 @@ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw, { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 unassign chanctx (role %d) %d (type %d)", @@ -4621,6 +4734,99 @@ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw, cfg80211_get_chandef_type(&ctx->def)); wl1271_tx_flush(wl); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) + goto out; + + if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (wlvif->radar_enabled) { + wl1271_debug(DEBUG_MAC80211, "Stop radar detection"); + wlcore_hw_set_cac(wl, wlvif, false); + wlvif->radar_enabled = false; + } + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + +static int __wlcore_switch_vif_chan(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct ieee80211_chanctx_conf *new_ctx) +{ + int channel = ieee80211_frequency_to_channel( + new_ctx->def.chan->center_freq); + + wl1271_debug(DEBUG_MAC80211, + "switch vif (role %d) %d -> %d chan_type: %d", + wlvif->role_id, wlvif->channel, channel, + cfg80211_get_chandef_type(&new_ctx->def)); + + if (WARN_ON_ONCE(wlvif->bss_type != BSS_TYPE_AP_BSS)) + return 0; + + WARN_ON(!test_bit(WLVIF_FLAG_BEACON_DISABLED, &wlvif->flags)); + + if (wlvif->radar_enabled) { + wl1271_debug(DEBUG_MAC80211, "Stop radar detection"); + wlcore_hw_set_cac(wl, wlvif, false); + wlvif->radar_enabled = false; + } + + wlvif->band = new_ctx->def.chan->band; + wlvif->channel = channel; + wlvif->channel_type = cfg80211_get_chandef_type(&new_ctx->def); + + /* start radar if needed */ + if (new_ctx->radar_enabled) { + wl1271_debug(DEBUG_MAC80211, "Start radar detection"); + wlcore_hw_set_cac(wl, wlvif, true); + wlvif->radar_enabled = true; + } + + return 0; +} + +static int +wlcore_op_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs, + enum ieee80211_chanctx_switch_mode mode) +{ + struct wl1271 *wl = hw->priv; + int i, ret; + + wl1271_debug(DEBUG_MAC80211, + "mac80211 switch chanctx n_vifs %d mode %d", + n_vifs, mode); + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + for (i = 0; i < n_vifs; i++) { + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vifs[i].vif); + + ret = __wlcore_switch_vif_chan(wl, wlvif, vifs[i].new_ctx); + if (ret) + goto out_sleep; + } +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + + return 0; } static int wl1271_op_conf_tx(struct ieee80211_hw *hw, @@ -5228,6 +5434,83 @@ out: mutex_unlock(&wl->mutex); } +static const void *wlcore_get_beacon_ie(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + u8 eid) +{ + int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); + struct sk_buff *beacon = + ieee80211_beacon_get(wl->hw, wl12xx_wlvif_to_vif(wlvif)); + + if (!beacon) + return NULL; + + return cfg80211_find_ie(eid, + beacon->data + ieoffset, + beacon->len - ieoffset); +} + +static int wlcore_get_csa_count(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 *csa_count) +{ + const u8 *ie; + const struct ieee80211_channel_sw_ie *ie_csa; + + ie = wlcore_get_beacon_ie(wl, wlvif, WLAN_EID_CHANNEL_SWITCH); + if (!ie) + return -EINVAL; + + ie_csa = (struct ieee80211_channel_sw_ie *)&ie[2]; + *csa_count = ie_csa->count; + + return 0; +} + +static void wlcore_op_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct ieee80211_channel_switch ch_switch = { + .block_tx = true, + .chandef = *chandef, + }; + int ret; + + wl1271_debug(DEBUG_MAC80211, + "mac80211 channel switch beacon (role %d)", + wlvif->role_id); + + ret = wlcore_get_csa_count(wl, wlvif, &ch_switch.count); + if (ret < 0) { + wl1271_error("error getting beacon (for CSA counter)"); + return; + } + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state != WLCORE_STATE_ON)) { + ret = -EBUSY; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl->ops->channel_switch(wl, wlvif, &ch_switch); + if (ret) + goto out_sleep; + + set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags); + +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + static void wlcore_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { @@ -5370,19 +5653,26 @@ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw, u32 changed) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct wl1271 *wl = hw->priv; - wlcore_hw_sta_rc_update(wl, wlvif, sta, changed); + wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update"); + + if (!(changed & IEEE80211_RC_BW_CHANGED)) + return; + + /* this callback is atomic, so schedule a new work */ + wlvif->rc_update_bw = sta->bandwidth; + ieee80211_queue_work(hw, &wlvif->rc_update_work); } -static int wlcore_op_get_rssi(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - s8 *rssi_dbm) +static void wlcore_op_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int ret = 0; + s8 rssi_dbm; + int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi"); @@ -5395,17 +5685,18 @@ static int wlcore_op_get_rssi(struct ieee80211_hw *hw, if (ret < 0) goto out_sleep; - ret = wlcore_acx_average_rssi(wl, wlvif, rssi_dbm); + ret = wlcore_acx_average_rssi(wl, wlvif, &rssi_dbm); if (ret < 0) goto out_sleep; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + sinfo->signal = rssi_dbm; + out_sleep: wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); - - return ret; } static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) @@ -5596,6 +5887,7 @@ static const struct ieee80211_ops wl1271_ops = { .set_bitrate_mask = wl12xx_set_bitrate_mask, .set_default_unicast_key = wl1271_op_set_default_key_idx, .channel_switch = wl12xx_op_channel_switch, + .channel_switch_beacon = wlcore_op_channel_switch_beacon, .flush = wlcore_op_flush, .remain_on_channel = wlcore_op_remain_on_channel, .cancel_remain_on_channel = wlcore_op_cancel_remain_on_channel, @@ -5604,8 +5896,9 @@ static const struct ieee80211_ops wl1271_ops = { .change_chanctx = wlcore_op_change_chanctx, .assign_vif_chanctx = wlcore_op_assign_vif_chanctx, .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx, + .switch_vif_chanctx = wlcore_op_switch_vif_chanctx, .sta_rc_update = wlcore_op_sta_rc_update, - .get_rssi = wlcore_op_get_rssi, + .sta_statistics = wlcore_op_sta_statistics, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; @@ -5776,7 +6069,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | - IEEE80211_HW_SUPPORTS_UAPSD | IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_REPORTS_TX_ACK_STATUS | @@ -5811,7 +6103,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | - WIPHY_FLAG_SUPPORTS_SCHED_SCAN; + WIPHY_FLAG_SUPPORTS_SCHED_SCAN | + WIPHY_FLAG_HAS_CHANNEL_SWITCH; /* make sure all our channels fit in the scanned_ch bitmask */ BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c index b52516eed7b2..4cd316e61466 100644 --- a/drivers/net/wireless/ti/wlcore/ps.c +++ b/drivers/net/wireless/ti/wlcore/ps.c @@ -56,9 +56,6 @@ void wl1271_elp_work(struct work_struct *work) goto out; wl12xx_for_each_wlvif(wl, wlvif) { - if (wlvif->bss_type == BSS_TYPE_AP_BSS) - goto out; - if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) && test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) goto out; @@ -95,9 +92,6 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) return; wl12xx_for_each_wlvif(wl, wlvif) { - if (wlvif->bss_type == BSS_TYPE_AP_BSS) - return; - if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) && test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) return; @@ -108,6 +102,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, msecs_to_jiffies(timeout)); } +EXPORT_SYMBOL_GPL(wl1271_ps_elp_sleep); int wl1271_ps_elp_wakeup(struct wl1271 *wl) { @@ -175,6 +170,7 @@ err: out: return 0; } +EXPORT_SYMBOL_GPL(wl1271_ps_elp_wakeup); int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, enum wl1271_cmd_ps_mode mode) diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.c b/drivers/net/wireless/ti/wlcore/vendor_cmd.c index ad86a48dcfcb..fd4e9ba176c9 100644 --- a/drivers/net/wireless/ti/wlcore/vendor_cmd.c +++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.c @@ -21,7 +21,7 @@ static const struct nla_policy wlcore_vendor_attr_policy[NUM_WLCORE_VENDOR_ATTR] = { [WLCORE_VENDOR_ATTR_FREQ] = { .type = NLA_U32 }, [WLCORE_VENDOR_ATTR_GROUP_ID] = { .type = NLA_U32 }, - [WLCORE_VENDOR_ATTR_GROUP_KEY] = { .type = NLA_U32, + [WLCORE_VENDOR_ATTR_GROUP_KEY] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, }; diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index df78cf12ef15..d599c869e6e8 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -106,8 +106,7 @@ struct wlcore_ops { struct wl12xx_vif *wlvif, struct ieee80211_channel_switch *ch_switch); u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len); - void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta, u32 changed); + void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif); int (*set_peer_cap)(struct wl1271 *wl, struct ieee80211_sta_ht_cap *ht_cap, bool allow_ht_operation, @@ -117,10 +116,16 @@ struct wlcore_ops { struct wl1271_link *lnk); bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid, struct wl1271_link *lnk); + int (*interrupt_notify)(struct wl1271 *wl, bool action); + int (*rx_ba_filter)(struct wl1271 *wl, bool action); + int (*ap_sleep)(struct wl1271 *wl); int (*smart_config_start)(struct wl1271 *wl, u32 group_bitmap); int (*smart_config_stop)(struct wl1271 *wl); int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id, u8 key_len, u8 *key); + int (*set_cac)(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool start); + int (*dfs_master_restart)(struct wl1271 *wl, struct wl12xx_vif *wlvif); }; enum wlcore_partitions { @@ -460,6 +465,9 @@ struct wl1271 { /* HW HT (11n) capabilities */ struct ieee80211_sta_ht_cap ht_cap[WLCORE_NUM_BANDS]; + /* the current dfs region */ + enum nl80211_dfs_regions dfs_region; + /* size of the private FW status data */ size_t fw_status_len; size_t fw_status_priv_len; diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 0e52556044d9..3396ce5a934d 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -251,6 +251,7 @@ enum wl12xx_vif_flags { WLVIF_FLAG_AP_PROBE_RESP_SET, WLVIF_FLAG_IN_USE, WLVIF_FLAG_ACTIVE, + WLVIF_FLAG_BEACON_DISABLED, }; struct wl12xx_vif; @@ -434,6 +435,8 @@ struct wl12xx_vif { bool wmm_enabled; + bool radar_enabled; + /* Rx Streaming */ struct work_struct rx_streaming_enable_work; struct work_struct rx_streaming_disable_work; @@ -463,6 +466,10 @@ struct wl12xx_vif { /* work for canceling ROC after pending auth reply */ struct delayed_work pending_auth_complete_work; + /* update rate conrol */ + enum ieee80211_sta_rx_bandwidth rc_update_bw; + struct work_struct rc_update_work; + /* * total freed FW packets on the link. * For STA this holds the PN of the link to the AP. diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 5f1fda44882b..589fa256256b 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -251,7 +251,6 @@ struct xenvif { struct xenvif_rx_cb { unsigned long expires; int meta_slots_used; - bool full_coalesce; }; #define XENVIF_RX_CB(skb) ((struct xenvif_rx_cb *)(skb)->cb) diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 9259a732e8a4..f38227afe099 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -80,7 +80,7 @@ static irqreturn_t xenvif_tx_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -int xenvif_poll(struct napi_struct *napi, int budget) +static int xenvif_poll(struct napi_struct *napi, int budget) { struct xenvif_queue *queue = container_of(napi, struct xenvif_queue, napi); @@ -483,9 +483,8 @@ int xenvif_init_queue(struct xenvif_queue *queue) * better enable it. The long term solution would be to use just a * bunch of valid page descriptors, without dependency on ballooning */ - err = alloc_xenballooned_pages(MAX_PENDING_REQS, - queue->mmap_pages, - false); + err = gnttab_alloc_pages(MAX_PENDING_REQS, + queue->mmap_pages); if (err) { netdev_err(queue->vif->dev, "Could not reserve mmap_pages\n"); return -ENOMEM; @@ -578,6 +577,7 @@ int xenvif_connect(struct xenvif_queue *queue, unsigned long tx_ring_ref, goto err_rx_unbind; } queue->task = task; + get_task_struct(task); task = kthread_create(xenvif_dealloc_kthread, (void *)queue, "%s-dealloc", queue->name); @@ -634,6 +634,7 @@ void xenvif_disconnect(struct xenvif *vif) if (queue->task) { kthread_stop(queue->task); + put_task_struct(queue->task); queue->task = NULL; } @@ -662,7 +663,7 @@ void xenvif_disconnect(struct xenvif *vif) */ void xenvif_deinit_queue(struct xenvif_queue *queue) { - free_xenballooned_pages(MAX_PENDING_REQS, queue->mmap_pages); + gnttab_free_pages(MAX_PENDING_REQS, queue->mmap_pages); } void xenvif_free(struct xenvif *vif) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 908e65e9b821..f7a31d2cb3f1 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -233,51 +233,6 @@ static void xenvif_rx_queue_drop_expired(struct xenvif_queue *queue) } } -/* - * Returns true if we should start a new receive buffer instead of - * adding 'size' bytes to a buffer which currently contains 'offset' - * bytes. - */ -static bool start_new_rx_buffer(int offset, unsigned long size, int head, - bool full_coalesce) -{ - /* simple case: we have completely filled the current buffer. */ - if (offset == MAX_BUFFER_OFFSET) - return true; - - /* - * complex case: start a fresh buffer if the current frag - * would overflow the current buffer but only if: - * (i) this frag would fit completely in the next buffer - * and (ii) there is already some data in the current buffer - * and (iii) this is not the head buffer. - * and (iv) there is no need to fully utilize the buffers - * - * Where: - * - (i) stops us splitting a frag into two copies - * unless the frag is too large for a single buffer. - * - (ii) stops us from leaving a buffer pointlessly empty. - * - (iii) stops us leaving the first buffer - * empty. Strictly speaking this is already covered - * by (ii) but is explicitly checked because - * netfront relies on the first buffer being - * non-empty and can crash otherwise. - * - (iv) is needed for skbs which can use up more than MAX_SKB_FRAGS - * slot - * - * This means we will effectively linearise small - * frags but do not needlessly split large buffers - * into multiple copies tend to give large frags their - * own buffers as before. - */ - BUG_ON(size > MAX_BUFFER_OFFSET); - if ((offset + size > MAX_BUFFER_OFFSET) && offset && !head && - !full_coalesce) - return true; - - return false; -} - struct netrx_pending_operations { unsigned copy_prod, copy_cons; unsigned meta_prod, meta_cons; @@ -314,9 +269,7 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif_queue *queue, static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff *skb, struct netrx_pending_operations *npo, struct page *page, unsigned long size, - unsigned long offset, int *head, - struct xenvif_queue *foreign_queue, - grant_ref_t foreign_gref) + unsigned long offset, int *head) { struct gnttab_copy *copy_gop; struct xenvif_rx_meta *meta; @@ -333,27 +286,18 @@ static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff *skb offset &= ~PAGE_MASK; while (size > 0) { + struct xen_page_foreign *foreign; + BUG_ON(offset >= PAGE_SIZE); BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET); - bytes = PAGE_SIZE - offset; + if (npo->copy_off == MAX_BUFFER_OFFSET) + meta = get_next_rx_buffer(queue, npo); + bytes = PAGE_SIZE - offset; if (bytes > size) bytes = size; - if (start_new_rx_buffer(npo->copy_off, - bytes, - *head, - XENVIF_RX_CB(skb)->full_coalesce)) { - /* - * Netfront requires there to be some data in the head - * buffer. - */ - BUG_ON(*head); - - meta = get_next_rx_buffer(queue, npo); - } - if (npo->copy_off + bytes > MAX_BUFFER_OFFSET) bytes = MAX_BUFFER_OFFSET - npo->copy_off; @@ -361,9 +305,10 @@ static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff *skb copy_gop->flags = GNTCOPY_dest_gref; copy_gop->len = bytes; - if (foreign_queue) { - copy_gop->source.domid = foreign_queue->vif->domid; - copy_gop->source.u.ref = foreign_gref; + foreign = xen_page_foreign(page); + if (foreign) { + copy_gop->source.domid = foreign->domid; + copy_gop->source.u.ref = foreign->gref; copy_gop->flags |= GNTCOPY_source_gref; } else { copy_gop->source.domid = DOMID_SELF; @@ -405,35 +350,6 @@ static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff *skb } } -/* - * Find the grant ref for a given frag in a chain of struct ubuf_info's - * skb: the skb itself - * i: the frag's number - * ubuf: a pointer to an element in the chain. It should not be NULL - * - * Returns a pointer to the element in the chain where the page were found. If - * not found, returns NULL. - * See the definition of callback_struct in common.h for more details about - * the chain. - */ -static const struct ubuf_info *xenvif_find_gref(const struct sk_buff *const skb, - const int i, - const struct ubuf_info *ubuf) -{ - struct xenvif_queue *foreign_queue = ubuf_to_queue(ubuf); - - do { - u16 pending_idx = ubuf->desc; - - if (skb_shinfo(skb)->frags[i].page.p == - foreign_queue->mmap_pages[pending_idx]) - break; - ubuf = (struct ubuf_info *) ubuf->ctx; - } while (ubuf); - - return ubuf; -} - /* * Prepare an SKB to be transmitted to the frontend. * @@ -459,8 +375,6 @@ static int xenvif_gop_skb(struct sk_buff *skb, int head = 1; int old_meta_prod; int gso_type; - const struct ubuf_info *ubuf = skb_shinfo(skb)->destructor_arg; - const struct ubuf_info *const head_ubuf = ubuf; old_meta_prod = npo->meta_prod; @@ -507,68 +421,16 @@ static int xenvif_gop_skb(struct sk_buff *skb, len = skb_tail_pointer(skb) - data; xenvif_gop_frag_copy(queue, skb, npo, - virt_to_page(data), len, offset, &head, - NULL, - 0); + virt_to_page(data), len, offset, &head); data += len; } for (i = 0; i < nr_frags; i++) { - /* This variable also signals whether foreign_gref has a real - * value or not. - */ - struct xenvif_queue *foreign_queue = NULL; - grant_ref_t foreign_gref; - - if ((skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) && - (ubuf->callback == &xenvif_zerocopy_callback)) { - const struct ubuf_info *const startpoint = ubuf; - - /* Ideally ubuf points to the chain element which - * belongs to this frag. Or if frags were removed from - * the beginning, then shortly before it. - */ - ubuf = xenvif_find_gref(skb, i, ubuf); - - /* Try again from the beginning of the list, if we - * haven't tried from there. This only makes sense in - * the unlikely event of reordering the original frags. - * For injected local pages it's an unnecessary second - * run. - */ - if (unlikely(!ubuf) && startpoint != head_ubuf) - ubuf = xenvif_find_gref(skb, i, head_ubuf); - - if (likely(ubuf)) { - u16 pending_idx = ubuf->desc; - - foreign_queue = ubuf_to_queue(ubuf); - foreign_gref = - foreign_queue->pending_tx_info[pending_idx].req.gref; - /* Just a safety measure. If this was the last - * element on the list, the for loop will - * iterate again if a local page were added to - * the end. Using head_ubuf here prevents the - * second search on the chain. Or the original - * frags changed order, but that's less likely. - * In any way, ubuf shouldn't be NULL. - */ - ubuf = ubuf->ctx ? - (struct ubuf_info *) ubuf->ctx : - head_ubuf; - } else - /* This frag was a local page, added to the - * array after the skb left netback. - */ - ubuf = head_ubuf; - } xenvif_gop_frag_copy(queue, skb, npo, skb_frag_page(&skb_shinfo(skb)->frags[i]), skb_frag_size(&skb_shinfo(skb)->frags[i]), skb_shinfo(skb)->frags[i].page_offset, - &head, - foreign_queue, - foreign_queue ? foreign_gref : UINT_MAX); + &head); } return npo->meta_prod - old_meta_prod; @@ -652,60 +514,15 @@ static void xenvif_rx_action(struct xenvif_queue *queue) while (xenvif_rx_ring_slots_available(queue, XEN_NETBK_RX_SLOTS_MAX) && (skb = xenvif_rx_dequeue(queue)) != NULL) { - RING_IDX max_slots_needed; RING_IDX old_req_cons; RING_IDX ring_slots_used; - int i; queue->last_rx_time = jiffies; - /* We need a cheap worse case estimate for the number of - * slots we'll use. - */ - - max_slots_needed = DIV_ROUND_UP(offset_in_page(skb->data) + - skb_headlen(skb), - PAGE_SIZE); - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - unsigned int size; - unsigned int offset; - - size = skb_frag_size(&skb_shinfo(skb)->frags[i]); - offset = skb_shinfo(skb)->frags[i].page_offset; - - /* For a worse-case estimate we need to factor in - * the fragment page offset as this will affect the - * number of times xenvif_gop_frag_copy() will - * call start_new_rx_buffer(). - */ - max_slots_needed += DIV_ROUND_UP(offset + size, - PAGE_SIZE); - } - - /* To avoid the estimate becoming too pessimal for some - * frontends that limit posted rx requests, cap the estimate - * at MAX_SKB_FRAGS. In this case netback will fully coalesce - * the skb into the provided slots. - */ - if (max_slots_needed > MAX_SKB_FRAGS) { - max_slots_needed = MAX_SKB_FRAGS; - XENVIF_RX_CB(skb)->full_coalesce = true; - } else { - XENVIF_RX_CB(skb)->full_coalesce = false; - } - - /* We may need one more slot for GSO metadata */ - if (skb_is_gso(skb) && - (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 || - skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)) - max_slots_needed++; - old_req_cons = queue->rx.req_cons; XENVIF_RX_CB(skb)->meta_slots_used = xenvif_gop_skb(skb, &npo, queue); ring_slots_used = queue->rx.req_cons - old_req_cons; - BUG_ON(ring_slots_used > max_slots_needed); - __skb_queue_tail(&rxq, skb); } @@ -1241,12 +1058,6 @@ static void xenvif_fill_frags(struct xenvif_queue *queue, struct sk_buff *skb) /* Take an extra reference to offset network stack's put_page */ get_page(queue->mmap_pages[pending_idx]); } - /* FIXME: __skb_fill_page_desc set this to true because page->pfmemalloc - * overlaps with "index", and "mapping" is not set. I think mapping - * should be set. If delivered to local stack, it would drop this - * skb in sk_filter unless the socket has the right to use it. - */ - skb->pfmemalloc = false; } static int xenvif_get_extras(struct xenvif_queue *queue, @@ -2109,8 +1920,7 @@ int xenvif_kthread_guest_rx(void *data) */ if (unlikely(vif->disabled && queue->id == 0)) { xenvif_carrier_off(vif); - xenvif_rx_queue_purge(queue); - continue; + break; } if (!skb_queue_empty(&queue->rx_queue)) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index d8c10764f130..e9b960f0ff32 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -142,10 +142,6 @@ struct netfront_queue { struct sk_buff *rx_skbs[NET_RX_RING_SIZE]; grant_ref_t gref_rx_head; grant_ref_t grant_rx_ref[NET_RX_RING_SIZE]; - - unsigned long rx_pfn_array[NET_RX_RING_SIZE]; - struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1]; - struct mmu_update rx_mmu[NET_RX_RING_SIZE]; }; struct netfront_info { @@ -223,11 +219,7 @@ static grant_ref_t xennet_get_rx_ref(struct netfront_queue *queue, } #ifdef CONFIG_SYSFS -static int xennet_sysfs_addif(struct net_device *netdev); -static void xennet_sysfs_delif(struct net_device *netdev); -#else /* !CONFIG_SYSFS */ -#define xennet_sysfs_addif(dev) (0) -#define xennet_sysfs_delif(dev) do { } while (0) +static const struct attribute_group xennet_dev_group; #endif static bool xennet_can_sg(struct net_device *dev) @@ -424,109 +416,68 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue) xennet_maybe_wake_tx(queue); } -static void xennet_make_frags(struct sk_buff *skb, struct netfront_queue *queue, - struct xen_netif_tx_request *tx) +static struct xen_netif_tx_request *xennet_make_one_txreq( + struct netfront_queue *queue, struct sk_buff *skb, + struct page *page, unsigned int offset, unsigned int len) { - char *data = skb->data; - unsigned long mfn; - RING_IDX prod = queue->tx.req_prod_pvt; - int frags = skb_shinfo(skb)->nr_frags; - unsigned int offset = offset_in_page(data); - unsigned int len = skb_headlen(skb); unsigned int id; + struct xen_netif_tx_request *tx; grant_ref_t ref; - int i; - /* While the header overlaps a page boundary (including being - larger than a page), split it it into page-sized chunks. */ - while (len > PAGE_SIZE - offset) { - tx->size = PAGE_SIZE - offset; + len = min_t(unsigned int, PAGE_SIZE - offset, len); + + id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs); + tx = RING_GET_REQUEST(&queue->tx, queue->tx.req_prod_pvt++); + ref = gnttab_claim_grant_reference(&queue->gref_tx_head); + BUG_ON((signed short)ref < 0); + + gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id, + page_to_mfn(page), GNTMAP_readonly); + + queue->tx_skbs[id].skb = skb; + queue->grant_tx_page[id] = page; + queue->grant_tx_ref[id] = ref; + + tx->id = id; + tx->gref = ref; + tx->offset = offset; + tx->size = len; + tx->flags = 0; + + return tx; +} + +static struct xen_netif_tx_request *xennet_make_txreqs( + struct netfront_queue *queue, struct xen_netif_tx_request *tx, + struct sk_buff *skb, struct page *page, + unsigned int offset, unsigned int len) +{ + /* Skip unused frames from start of page */ + page += offset >> PAGE_SHIFT; + offset &= ~PAGE_MASK; + + while (len) { tx->flags |= XEN_NETTXF_more_data; - len -= tx->size; - data += tx->size; + tx = xennet_make_one_txreq(queue, skb_get(skb), + page, offset, len); + page++; offset = 0; - - id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs); - queue->tx_skbs[id].skb = skb_get(skb); - tx = RING_GET_REQUEST(&queue->tx, prod++); - tx->id = id; - ref = gnttab_claim_grant_reference(&queue->gref_tx_head); - BUG_ON((signed short)ref < 0); - - mfn = virt_to_mfn(data); - gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id, - mfn, GNTMAP_readonly); - - queue->grant_tx_page[id] = virt_to_page(data); - tx->gref = queue->grant_tx_ref[id] = ref; - tx->offset = offset; - tx->size = len; - tx->flags = 0; + len -= tx->size; } - /* Grant backend access to each skb fragment page. */ - for (i = 0; i < frags; i++) { - skb_frag_t *frag = skb_shinfo(skb)->frags + i; - struct page *page = skb_frag_page(frag); - - len = skb_frag_size(frag); - offset = frag->page_offset; - - /* Skip unused frames from start of page */ - page += offset >> PAGE_SHIFT; - offset &= ~PAGE_MASK; - - while (len > 0) { - unsigned long bytes; - - bytes = PAGE_SIZE - offset; - if (bytes > len) - bytes = len; - - tx->flags |= XEN_NETTXF_more_data; - - id = get_id_from_freelist(&queue->tx_skb_freelist, - queue->tx_skbs); - queue->tx_skbs[id].skb = skb_get(skb); - tx = RING_GET_REQUEST(&queue->tx, prod++); - tx->id = id; - ref = gnttab_claim_grant_reference(&queue->gref_tx_head); - BUG_ON((signed short)ref < 0); - - mfn = pfn_to_mfn(page_to_pfn(page)); - gnttab_grant_foreign_access_ref(ref, - queue->info->xbdev->otherend_id, - mfn, GNTMAP_readonly); - - queue->grant_tx_page[id] = page; - tx->gref = queue->grant_tx_ref[id] = ref; - tx->offset = offset; - tx->size = bytes; - tx->flags = 0; - - offset += bytes; - len -= bytes; - - /* Next frame */ - if (offset == PAGE_SIZE && len) { - BUG_ON(!PageCompound(page)); - page++; - offset = 0; - } - } - } - - queue->tx.req_prod_pvt = prod; + return tx; } /* - * Count how many ring slots are required to send the frags of this - * skb. Each frag might be a compound page. + * Count how many ring slots are required to send this skb. Each frag + * might be a compound page. */ -static int xennet_count_skb_frag_slots(struct sk_buff *skb) +static int xennet_count_skb_slots(struct sk_buff *skb) { int i, frags = skb_shinfo(skb)->nr_frags; - int pages = 0; + int pages; + + pages = PFN_UP(offset_in_page(skb->data) + skb_headlen(skb)); for (i = 0; i < frags; i++) { skb_frag_t *frag = skb_shinfo(skb)->frags + i; @@ -562,18 +513,15 @@ static u16 xennet_select_queue(struct net_device *dev, struct sk_buff *skb, static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) { - unsigned short id; struct netfront_info *np = netdev_priv(dev); struct netfront_stats *tx_stats = this_cpu_ptr(np->tx_stats); - struct xen_netif_tx_request *tx; - char *data = skb->data; - RING_IDX i; - grant_ref_t ref; - unsigned long mfn; + struct xen_netif_tx_request *tx, *first_tx; + unsigned int i; int notify; int slots; - unsigned int offset = offset_in_page(data); - unsigned int len = skb_headlen(skb); + struct page *page; + unsigned int offset; + unsigned int len; unsigned long flags; struct netfront_queue *queue = NULL; unsigned int num_queues = dev->real_num_tx_queues; @@ -596,18 +544,18 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) goto drop; } - slots = DIV_ROUND_UP(offset + len, PAGE_SIZE) + - xennet_count_skb_frag_slots(skb); + slots = xennet_count_skb_slots(skb); if (unlikely(slots > MAX_SKB_FRAGS + 1)) { net_dbg_ratelimited("xennet: skb rides the rocket: %d slots, %d bytes\n", slots, skb->len); if (skb_linearize(skb)) goto drop; - data = skb->data; - offset = offset_in_page(data); - len = skb_headlen(skb); } + page = virt_to_page(skb->data); + offset = offset_in_page(skb->data); + len = skb_headlen(skb); + spin_lock_irqsave(&queue->tx_lock, flags); if (unlikely(!netif_carrier_ok(dev) || @@ -617,25 +565,13 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) goto drop; } - i = queue->tx.req_prod_pvt; + /* First request for the linear area. */ + first_tx = tx = xennet_make_one_txreq(queue, skb, + page, offset, len); + page++; + offset = 0; + len -= tx->size; - id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs); - queue->tx_skbs[id].skb = skb; - - tx = RING_GET_REQUEST(&queue->tx, i); - - tx->id = id; - ref = gnttab_claim_grant_reference(&queue->gref_tx_head); - BUG_ON((signed short)ref < 0); - mfn = virt_to_mfn(data); - gnttab_grant_foreign_access_ref( - ref, queue->info->xbdev->otherend_id, mfn, GNTMAP_readonly); - queue->grant_tx_page[id] = virt_to_page(data); - tx->gref = queue->grant_tx_ref[id] = ref; - tx->offset = offset; - tx->size = len; - - tx->flags = 0; if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */ tx->flags |= XEN_NETTXF_csum_blank | XEN_NETTXF_data_validated; @@ -643,11 +579,12 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) /* remote but checksummed. */ tx->flags |= XEN_NETTXF_data_validated; + /* Optional extra info after the first request. */ if (skb_shinfo(skb)->gso_size) { struct xen_netif_extra_info *gso; gso = (struct xen_netif_extra_info *) - RING_GET_REQUEST(&queue->tx, ++i); + RING_GET_REQUEST(&queue->tx, queue->tx.req_prod_pvt++); tx->flags |= XEN_NETTXF_extra_info; @@ -662,10 +599,19 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) gso->flags = 0; } - queue->tx.req_prod_pvt = i + 1; + /* Requests for the rest of the linear area. */ + tx = xennet_make_txreqs(queue, tx, skb, page, offset, len); - xennet_make_frags(skb, queue, tx); - tx->size = skb->len; + /* Requests for all the frags. */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + tx = xennet_make_txreqs(queue, tx, skb, + skb_frag_page(frag), frag->page_offset, + skb_frag_size(frag)); + } + + /* First request has the packet length. */ + first_tx->size = skb->len; RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&queue->tx, notify); if (notify) @@ -1367,20 +1313,15 @@ static int netfront_probe(struct xenbus_device *dev, info = netdev_priv(netdev); dev_set_drvdata(&dev->dev, info); - +#ifdef CONFIG_SYSFS + info->netdev->sysfs_groups[0] = &xennet_dev_group; +#endif err = register_netdev(info->netdev); if (err) { pr_warn("%s: register_netdev err=%d\n", __func__, err); goto fail; } - err = xennet_sysfs_addif(info->netdev); - if (err) { - unregister_netdev(info->netdev); - pr_warn("%s: add sysfs failed err=%d\n", __func__, err); - goto fail; - } - return 0; fail: @@ -2144,39 +2085,20 @@ static ssize_t store_rxbuf(struct device *dev, return len; } -static struct device_attribute xennet_attrs[] = { - __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf, store_rxbuf), - __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf, store_rxbuf), - __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf, NULL), +static DEVICE_ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf, store_rxbuf); +static DEVICE_ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf, store_rxbuf); +static DEVICE_ATTR(rxbuf_cur, S_IRUGO, show_rxbuf, NULL); + +static struct attribute *xennet_dev_attrs[] = { + &dev_attr_rxbuf_min.attr, + &dev_attr_rxbuf_max.attr, + &dev_attr_rxbuf_cur.attr, + NULL }; -static int xennet_sysfs_addif(struct net_device *netdev) -{ - int i; - int err; - - for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) { - err = device_create_file(&netdev->dev, - &xennet_attrs[i]); - if (err) - goto fail; - } - return 0; - - fail: - while (--i >= 0) - device_remove_file(&netdev->dev, &xennet_attrs[i]); - return err; -} - -static void xennet_sysfs_delif(struct net_device *netdev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) - device_remove_file(&netdev->dev, &xennet_attrs[i]); -} - +static const struct attribute_group xennet_dev_group = { + .attrs = xennet_dev_attrs +}; #endif /* CONFIG_SYSFS */ static int xennet_remove(struct xenbus_device *dev) @@ -2190,8 +2112,6 @@ static int xennet_remove(struct xenbus_device *dev) xennet_disconnect_backend(info); - xennet_sysfs_delif(info->netdev); - unregister_netdev(info->netdev); for (i = 0; i < num_queues; ++i) { diff --git a/drivers/nfc/microread/microread.c b/drivers/nfc/microread/microread.c index 963a4a5dc88e..f454dc68cc03 100644 --- a/drivers/nfc/microread/microread.c +++ b/drivers/nfc/microread/microread.c @@ -557,10 +557,11 @@ exit: pr_err("Failed to handle discovered target err=%d\n", r); } -static int microread_event_received(struct nfc_hci_dev *hdev, u8 gate, +static int microread_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, struct sk_buff *skb) { int r; + u8 gate = hdev->pipes[pipe].gate; u8 mode; pr_info("Microread received event 0x%x to gate 0x%x\n", event, gate); diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index fc02e8d6a193..cdde745b96bd 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -24,11 +24,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -41,6 +43,11 @@ #define PN544_I2C_FRAME_HEADROOM 1 #define PN544_I2C_FRAME_TAILROOM 2 +/* GPIO names */ +#define PN544_GPIO_NAME_IRQ "pn544_irq" +#define PN544_GPIO_NAME_FW "pn544_fw" +#define PN544_GPIO_NAME_EN "pn544_en" + /* framing in HCI mode */ #define PN544_HCI_I2C_LLC_LEN 1 #define PN544_HCI_I2C_LLC_CRC 2 @@ -58,6 +65,13 @@ static struct i2c_device_id pn544_hci_i2c_id_table[] = { MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table); +static const struct acpi_device_id pn544_hci_i2c_acpi_match[] = { + {"NXP5440", 0}, + {} +}; + +MODULE_DEVICE_TABLE(acpi, pn544_hci_i2c_acpi_match); + #define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c" /* @@ -195,18 +209,19 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy) nfc_info(&phy->i2c_dev->dev, "Detecting nfc_en polarity\n"); /* Disable fw download */ - gpio_set_value(phy->gpio_fw, 0); + gpio_set_value_cansleep(phy->gpio_fw, 0); for (polarity = 0; polarity < 2; polarity++) { phy->en_polarity = polarity; retry = 3; while (retry--) { /* power off */ - gpio_set_value(phy->gpio_en, !phy->en_polarity); + gpio_set_value_cansleep(phy->gpio_en, + !phy->en_polarity); usleep_range(10000, 15000); /* power on */ - gpio_set_value(phy->gpio_en, phy->en_polarity); + gpio_set_value_cansleep(phy->gpio_en, phy->en_polarity); usleep_range(10000, 15000); /* send reset */ @@ -225,13 +240,14 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy) "Could not detect nfc_en polarity, fallback to active high\n"); out: - gpio_set_value(phy->gpio_en, !phy->en_polarity); + gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity); } static void pn544_hci_i2c_enable_mode(struct pn544_i2c_phy *phy, int run_mode) { - gpio_set_value(phy->gpio_fw, run_mode == PN544_FW_MODE ? 1 : 0); - gpio_set_value(phy->gpio_en, phy->en_polarity); + gpio_set_value_cansleep(phy->gpio_fw, + run_mode == PN544_FW_MODE ? 1 : 0); + gpio_set_value_cansleep(phy->gpio_en, phy->en_polarity); usleep_range(10000, 15000); phy->run_mode = run_mode; @@ -254,14 +270,14 @@ static void pn544_hci_i2c_disable(void *phy_id) { struct pn544_i2c_phy *phy = phy_id; - gpio_set_value(phy->gpio_fw, 0); - gpio_set_value(phy->gpio_en, !phy->en_polarity); + gpio_set_value_cansleep(phy->gpio_fw, 0); + gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity); usleep_range(10000, 15000); - gpio_set_value(phy->gpio_en, phy->en_polarity); + gpio_set_value_cansleep(phy->gpio_en, phy->en_polarity); usleep_range(10000, 15000); - gpio_set_value(phy->gpio_en, !phy->en_polarity); + gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity); usleep_range(10000, 15000); phy->powered = 0; @@ -859,6 +875,90 @@ exit_state_wait_secure_write_answer: } } +static int pn544_hci_i2c_acpi_request_resources(struct i2c_client *client) +{ + struct pn544_i2c_phy *phy = i2c_get_clientdata(client); + const struct acpi_device_id *id; + struct gpio_desc *gpiod_en, *gpiod_irq, *gpiod_fw; + struct device *dev; + int ret; + + if (!client) + return -EINVAL; + + dev = &client->dev; + + /* Match the struct device against a given list of ACPI IDs */ + id = acpi_match_device(dev->driver->acpi_match_table, dev); + + if (!id) + return -ENODEV; + + /* Get EN GPIO from ACPI */ + gpiod_en = devm_gpiod_get_index(dev, PN544_GPIO_NAME_EN, 1); + if (IS_ERR(gpiod_en)) { + nfc_err(dev, + "Unable to get EN GPIO\n"); + return -ENODEV; + } + + phy->gpio_en = desc_to_gpio(gpiod_en); + + /* Configuration EN GPIO */ + ret = gpiod_direction_output(gpiod_en, 0); + if (ret) { + nfc_err(dev, "Fail EN pin direction\n"); + return ret; + } + + /* Get FW GPIO from ACPI */ + gpiod_fw = devm_gpiod_get_index(dev, PN544_GPIO_NAME_FW, 2); + if (IS_ERR(gpiod_fw)) { + nfc_err(dev, + "Unable to get FW GPIO\n"); + return -ENODEV; + } + + phy->gpio_fw = desc_to_gpio(gpiod_fw); + + /* Configuration FW GPIO */ + ret = gpiod_direction_output(gpiod_fw, 0); + if (ret) { + nfc_err(dev, "Fail FW pin direction\n"); + return ret; + } + + /* Get IRQ GPIO */ + gpiod_irq = devm_gpiod_get_index(dev, PN544_GPIO_NAME_IRQ, 0); + if (IS_ERR(gpiod_irq)) { + nfc_err(dev, + "Unable to get IRQ GPIO\n"); + return -ENODEV; + } + + phy->gpio_irq = desc_to_gpio(gpiod_irq); + + /* Configure IRQ GPIO */ + ret = gpiod_direction_input(gpiod_irq); + if (ret) { + nfc_err(dev, "Fail IRQ pin direction\n"); + return ret; + } + + /* Map the pin to an IRQ */ + ret = gpiod_to_irq(gpiod_irq); + if (ret < 0) { + nfc_err(dev, "Fail pin IRQ mapping\n"); + return ret; + } + + nfc_info(dev, "GPIO resource, no:%d irq:%d\n", + desc_to_gpio(gpiod_irq), ret); + client->irq = ret; + + return 0; +} + #ifdef CONFIG_OF static int pn544_hci_i2c_of_request_resources(struct i2c_client *client) @@ -884,7 +984,7 @@ static int pn544_hci_i2c_of_request_resources(struct i2c_client *client) phy->gpio_en = ret; /* Configuration of EN GPIO */ - ret = gpio_request(phy->gpio_en, "pn544_en"); + ret = gpio_request(phy->gpio_en, PN544_GPIO_NAME_EN); if (ret) { nfc_err(&client->dev, "Fail EN pin\n"); goto err_dt; @@ -906,7 +1006,7 @@ static int pn544_hci_i2c_of_request_resources(struct i2c_client *client) phy->gpio_fw = ret; /* Configuration of FW GPIO */ - ret = gpio_request(phy->gpio_fw, "pn544_fw"); + ret = gpio_request(phy->gpio_fw, PN544_GPIO_NAME_FW); if (ret) { nfc_err(&client->dev, "Fail FW pin\n"); goto err_gpio_en; @@ -1001,6 +1101,14 @@ static int pn544_hci_i2c_probe(struct i2c_client *client, phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE); phy->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET); phy->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ); + /* Using ACPI */ + } else if (ACPI_HANDLE(&client->dev)) { + r = pn544_hci_i2c_acpi_request_resources(client); + if (r) { + nfc_err(&client->dev, + "Cannot get ACPI data\n"); + return r; + } } else { nfc_err(&client->dev, "No platform data\n"); return -EINVAL; @@ -1080,6 +1188,7 @@ static struct i2c_driver pn544_hci_i2c_driver = { .name = PN544_HCI_I2C_DRIVER_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(of_pn544_i2c_match), + .acpi_match_table = ACPI_PTR(pn544_hci_i2c_acpi_match), }, .probe = pn544_hci_i2c_probe, .id_table = pn544_hci_i2c_id_table, diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c index 9c8051d20cea..12e819ddf17a 100644 --- a/drivers/nfc/pn544/pn544.c +++ b/drivers/nfc/pn544/pn544.c @@ -724,10 +724,11 @@ static int pn544_hci_check_presence(struct nfc_hci_dev *hdev, * <= 0: driver handled the event, skb consumed * 1: driver does not handle the event, please do standard processing */ -static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, u8 event, +static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, struct sk_buff *skb) { struct sk_buff *rgb_skb = NULL; + u8 gate = hdev->pipes[pipe].gate; int r; pr_debug("hci event %d\n", event); diff --git a/drivers/nfc/st21nfca/Makefile b/drivers/nfc/st21nfca/Makefile index 7d688f97aa27..97edab4bbdf8 100644 --- a/drivers/nfc/st21nfca/Makefile +++ b/drivers/nfc/st21nfca/Makefile @@ -2,7 +2,7 @@ # Makefile for ST21NFCA HCI based NFC driver # -st21nfca_hci-objs = st21nfca.o st21nfca_dep.o +st21nfca_hci-objs = st21nfca.o st21nfca_dep.o st21nfca_se.o obj-$(CONFIG_NFC_ST21NFCA) += st21nfca_hci.o st21nfca_i2c-objs = i2c.o diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index 05722085a59f..a32143951616 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -74,6 +74,8 @@ struct st21nfca_i2c_phy { unsigned int gpio_ena; unsigned int irq_polarity; + struct st21nfca_se_status se_status; + struct sk_buff *pending_skb; int current_read_len; /* @@ -537,6 +539,11 @@ static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client) phy->irq_polarity = irq_get_trigger_type(client->irq); + phy->se_status.is_ese_present = + of_property_read_bool(pp, "ese-present"); + phy->se_status.is_uicc_present = + of_property_read_bool(pp, "uicc-present"); + return 0; } #else @@ -571,6 +578,9 @@ static int st21nfca_hci_i2c_request_resources(struct i2c_client *client) } } + phy->se_status.is_ese_present = pdata->is_ese_present; + phy->se_status.is_uicc_present = pdata->is_uicc_present; + return 0; } @@ -591,11 +601,8 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client, phy = devm_kzalloc(&client->dev, sizeof(struct st21nfca_i2c_phy), GFP_KERNEL); - if (!phy) { - nfc_err(&client->dev, - "Cannot allocate memory for st21nfca i2c phy.\n"); + if (!phy) return -ENOMEM; - } phy->i2c_dev = client; phy->pending_skb = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE * 2, GFP_KERNEL); @@ -641,8 +648,11 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client, } return st21nfca_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME, - ST21NFCA_FRAME_HEADROOM, ST21NFCA_FRAME_TAILROOM, - ST21NFCA_HCI_LLC_MAX_PAYLOAD, &phy->hdev); + ST21NFCA_FRAME_HEADROOM, + ST21NFCA_FRAME_TAILROOM, + ST21NFCA_HCI_LLC_MAX_PAYLOAD, + &phy->hdev, + &phy->se_status); } static int st21nfca_hci_i2c_remove(struct i2c_client *client) @@ -661,6 +671,7 @@ static int st21nfca_hci_i2c_remove(struct i2c_client *client) #ifdef CONFIG_OF static const struct of_device_id of_st21nfca_i2c_match[] = { + { .compatible = "st,st21nfca-i2c", }, { .compatible = "st,st21nfca_i2c", }, {} }; diff --git a/drivers/nfc/st21nfca/st21nfca.c b/drivers/nfc/st21nfca/st21nfca.c index f2596c8d68b0..24d3d240d5f4 100644 --- a/drivers/nfc/st21nfca/st21nfca.c +++ b/drivers/nfc/st21nfca/st21nfca.c @@ -23,6 +23,7 @@ #include "st21nfca.h" #include "st21nfca_dep.h" +#include "st21nfca_se.h" #define DRIVER_DESC "HCI NFC driver for ST21NFCA" @@ -62,7 +63,6 @@ #define ST21NFCA_RF_CARD_F_DATARATE 0x08 #define ST21NFCA_RF_CARD_F_DATARATE_212_424 0x01 -#define ST21NFCA_DEVICE_MGNT_GATE 0x01 #define ST21NFCA_DEVICE_MGNT_PIPE 0x02 #define ST21NFCA_DM_GETINFO 0x13 @@ -78,6 +78,11 @@ #define ST21NFCA_NFC_MODE 0x03 /* NFC_MODE parameter*/ +#define ST21NFCA_EVT_HOT_PLUG 0x03 +#define ST21NFCA_EVT_HOT_PLUG_IS_INHIBITED(x) (x->data[0] & 0x80) + +#define ST21NFCA_SE_TO_PIPES 2000 + static DECLARE_BITMAP(dev_mask, ST21NFCA_NUM_DEVICES); static struct nfc_hci_gate st21nfca_gates[] = { @@ -92,6 +97,10 @@ static struct nfc_hci_gate st21nfca_gates[] = { {ST21NFCA_RF_READER_14443_3_A_GATE, NFC_HCI_INVALID_PIPE}, {ST21NFCA_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE}, {ST21NFCA_RF_CARD_F_GATE, NFC_HCI_INVALID_PIPE}, + + /* Secure element pipes are created by secure element host */ + {ST21NFCA_CONNECTIVITY_GATE, NFC_HCI_DO_NOT_CREATE_PIPE}, + {ST21NFCA_APDU_READER_GATE, NFC_HCI_DO_NOT_CREATE_PIPE}, }; struct st21nfca_pipe_info { @@ -118,18 +127,6 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev) NFC_HCI_TERMINAL_HOST_ID, 0 }; - skb_pipe_list = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE, GFP_KERNEL); - if (!skb_pipe_list) { - r = -ENOMEM; - goto free_list; - } - - skb_pipe_info = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE, GFP_KERNEL); - if (!skb_pipe_info) { - r = -ENOMEM; - goto free_info; - } - /* On ST21NFCA device pipes number are dynamics * A maximum of 16 pipes can be created at the same time * If pipes are already created, hci_dev_up will fail. @@ -148,7 +145,8 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev) * Pipe can be closed and need to be open. */ r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, - ST21NFCA_DEVICE_MGNT_GATE, ST21NFCA_DEVICE_MGNT_PIPE); + ST21NFCA_DEVICE_MGNT_GATE, + ST21NFCA_DEVICE_MGNT_PIPE); if (r < 0) goto free_info; @@ -179,17 +177,28 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev) * - destination gid (1byte) */ info = (struct st21nfca_pipe_info *) skb_pipe_info->data; + if (info->dst_gate_id == ST21NFCA_APDU_READER_GATE && + info->src_host_id != ST21NFCA_ESE_HOST_ID) { + pr_err("Unexpected apdu_reader pipe on host %x\n", + info->src_host_id); + continue; + } + for (j = 0; (j < ARRAY_SIZE(st21nfca_gates)) && - (st21nfca_gates[j].gate != info->dst_gate_id); - j++) + (st21nfca_gates[j].gate != info->dst_gate_id) ; j++) ; if (j < ARRAY_SIZE(st21nfca_gates) && st21nfca_gates[j].gate == info->dst_gate_id && ST21NFCA_DM_IS_PIPE_OPEN(info->pipe_state)) { st21nfca_gates[j].pipe = pipe_info[2]; + hdev->gate2pipe[st21nfca_gates[j].gate] = - st21nfca_gates[j].pipe; + st21nfca_gates[j].pipe; + hdev->pipes[st21nfca_gates[j].pipe].gate = + st21nfca_gates[j].gate; + hdev->pipes[st21nfca_gates[j].pipe].dest_host = + info->src_host_id; } } @@ -199,7 +208,7 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev) */ if (skb_pipe_list->len + 3 < ARRAY_SIZE(st21nfca_gates)) { for (i = skb_pipe_list->len + 3; - i < ARRAY_SIZE(st21nfca_gates); i++) { + i < ARRAY_SIZE(st21nfca_gates) - 2; i++) { r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, st21nfca_gates[i].gate, @@ -212,7 +221,6 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev) memcpy(hdev->init_data.gates, st21nfca_gates, sizeof(st21nfca_gates)); free_info: kfree_skb(skb_pipe_info); -free_list: kfree_skb(skb_pipe_list); return r; } @@ -257,16 +265,33 @@ out: static int st21nfca_hci_ready(struct nfc_hci_dev *hdev) { + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); struct sk_buff *skb; u8 param; + u8 white_list[2]; + int wl_size = 0; int r; - param = NFC_HCI_UICC_HOST_ID; - r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE, - NFC_HCI_ADMIN_WHITELIST, ¶m, 1); - if (r < 0) - return r; + if (info->se_status->is_ese_present && + info->se_status->is_uicc_present) { + white_list[wl_size++] = NFC_HCI_UICC_HOST_ID; + white_list[wl_size++] = ST21NFCA_ESE_HOST_ID; + } else if (!info->se_status->is_ese_present && + info->se_status->is_uicc_present) { + white_list[wl_size++] = NFC_HCI_UICC_HOST_ID; + } else if (info->se_status->is_ese_present && + !info->se_status->is_uicc_present) { + white_list[wl_size++] = ST21NFCA_ESE_HOST_ID; + } + + if (wl_size) { + r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE, + NFC_HCI_ADMIN_WHITELIST, + (u8 *) &white_list, wl_size); + if (r < 0) + return r; + } /* Set NFC_MODE in device management gate to enable */ r = nfc_hci_get_param(hdev, ST21NFCA_DEVICE_MGNT_GATE, @@ -274,8 +299,9 @@ static int st21nfca_hci_ready(struct nfc_hci_dev *hdev) if (r < 0) return r; - if (skb->data[0] == 0) { - kfree_skb(skb); + param = skb->data[0]; + kfree_skb(skb); + if (param == 0) { param = 1; r = nfc_hci_set_param(hdev, ST21NFCA_DEVICE_MGNT_GATE, @@ -417,9 +443,12 @@ static int st21nfca_hci_start_poll(struct nfc_hci_dev *hdev, r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE, ST21NFCA_RF_CARD_F_DATARATE, param, 1); - if (r < 0) + if (r < 0) { + kfree_skb(datarate_skb); return r; + } } + kfree_skb(datarate_skb); /* * Configure sens_res @@ -673,15 +702,15 @@ static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev, struct nfc_target *target) { int r; - struct sk_buff *nfcid2_skb = NULL, *nfcid1_skb; + struct sk_buff *nfcid_skb = NULL; if (gate == ST21NFCA_RF_READER_F_GATE) { r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE, - ST21NFCA_RF_READER_F_NFCID2, &nfcid2_skb); + ST21NFCA_RF_READER_F_NFCID2, &nfcid_skb); if (r < 0) goto exit; - if (nfcid2_skb->len > NFC_SENSF_RES_MAXSIZE) { + if (nfcid_skb->len > NFC_SENSF_RES_MAXSIZE) { r = -EPROTO; goto exit; } @@ -693,11 +722,11 @@ static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev, * - After the reception of SEL_RES with NFCIP-1 compliant bit * set for type A frame NFCID1 will be updated */ - if (nfcid2_skb->len > 0) { + if (nfcid_skb->len > 0) { /* P2P in type F */ - memcpy(target->sensf_res, nfcid2_skb->data, - nfcid2_skb->len); - target->sensf_res_len = nfcid2_skb->len; + memcpy(target->sensf_res, nfcid_skb->data, + nfcid_skb->len); + target->sensf_res_len = nfcid_skb->len; /* NFC Forum Digital Protocol Table 44 */ if (target->sensf_res[0] == 0x01 && target->sensf_res[1] == 0xfe) @@ -707,27 +736,28 @@ static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev, target->supported_protocols = NFC_PROTO_FELICA_MASK; } else { + kfree_skb(nfcid_skb); /* P2P in type A */ r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE, ST21NFCA_RF_READER_F_NFCID1, - &nfcid1_skb); + &nfcid_skb); if (r < 0) goto exit; - if (nfcid1_skb->len > NFC_NFCID1_MAXSIZE) { + if (nfcid_skb->len > NFC_NFCID1_MAXSIZE) { r = -EPROTO; goto exit; } - memcpy(target->sensf_res, nfcid1_skb->data, - nfcid1_skb->len); - target->sensf_res_len = nfcid1_skb->len; + memcpy(target->sensf_res, nfcid_skb->data, + nfcid_skb->len); + target->sensf_res_len = nfcid_skb->len; target->supported_protocols = NFC_PROTO_NFC_DEP_MASK; } target->hci_reader_gate = ST21NFCA_RF_READER_F_GATE; } r = 1; exit: - kfree_skb(nfcid2_skb); + kfree_skb(nfcid_skb); return r; } @@ -829,24 +859,82 @@ static int st21nfca_hci_check_presence(struct nfc_hci_dev *hdev, } } +static void st21nfca_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, + struct sk_buff *skb) +{ + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + u8 gate = hdev->pipes[pipe].gate; + + pr_debug("cmd: %x\n", cmd); + + switch (cmd) { + case NFC_HCI_ANY_OPEN_PIPE: + if (gate != ST21NFCA_APDU_READER_GATE && + hdev->pipes[pipe].dest_host != NFC_HCI_UICC_HOST_ID) + info->se_info.count_pipes++; + + if (info->se_info.count_pipes == info->se_info.expected_pipes) { + del_timer_sync(&info->se_info.se_active_timer); + info->se_info.se_active = false; + info->se_info.count_pipes = 0; + complete(&info->se_info.req_completion); + } + break; + } +} + +static int st21nfca_admin_event_received(struct nfc_hci_dev *hdev, u8 event, + struct sk_buff *skb) +{ + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + pr_debug("admin event: %x\n", event); + + switch (event) { + case ST21NFCA_EVT_HOT_PLUG: + if (info->se_info.se_active) { + if (!ST21NFCA_EVT_HOT_PLUG_IS_INHIBITED(skb)) { + del_timer_sync(&info->se_info.se_active_timer); + info->se_info.se_active = false; + complete(&info->se_info.req_completion); + } else { + mod_timer(&info->se_info.se_active_timer, + jiffies + + msecs_to_jiffies(ST21NFCA_SE_TO_PIPES)); + } + } + break; + } + kfree_skb(skb); + return 0; +} + /* * Returns: * <= 0: driver handled the event, skb consumed * 1: driver does not handle the event, please do standard processing */ -static int st21nfca_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, +static int st21nfca_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, struct sk_buff *skb) { + u8 gate = hdev->pipes[pipe].gate; + u8 host = hdev->pipes[pipe].dest_host; + pr_debug("hci event: %d gate: %x\n", event, gate); switch (gate) { + case NFC_HCI_ADMIN_GATE: + return st21nfca_admin_event_received(hdev, event, skb); case ST21NFCA_RF_CARD_F_GATE: return st21nfca_dep_event_received(hdev, event, skb); + case ST21NFCA_CONNECTIVITY_GATE: + return st21nfca_connectivity_event_received(hdev, host, + event, skb); + case ST21NFCA_APDU_READER_GATE: + return st21nfca_apdu_reader_event_received(hdev, event, skb); default: return 1; } - kfree_skb(skb); - return 0; } static struct nfc_hci_ops st21nfca_hci_ops = { @@ -865,11 +953,17 @@ static struct nfc_hci_ops st21nfca_hci_ops = { .tm_send = st21nfca_hci_tm_send, .check_presence = st21nfca_hci_check_presence, .event_received = st21nfca_hci_event_received, + .cmd_received = st21nfca_hci_cmd_received, + .discover_se = st21nfca_hci_discover_se, + .enable_se = st21nfca_hci_enable_se, + .disable_se = st21nfca_hci_disable_se, + .se_io = st21nfca_hci_se_io, }; int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, int phy_headroom, int phy_tailroom, - int phy_payload, struct nfc_hci_dev **hdev) + int phy_payload, struct nfc_hci_dev **hdev, + struct st21nfca_se_status *se_status) { struct st21nfca_hci_info *info; int r = 0; @@ -929,6 +1023,8 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, goto err_alloc_hdev; } + info->se_status = se_status; + nfc_hci_set_clientdata(info->hdev, info); r = nfc_hci_register_device(info->hdev); @@ -937,6 +1033,7 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, *hdev = info->hdev; st21nfca_dep_init(info->hdev); + st21nfca_se_init(info->hdev); return 0; @@ -955,6 +1052,7 @@ void st21nfca_hci_remove(struct nfc_hci_dev *hdev) struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); st21nfca_dep_deinit(hdev); + st21nfca_se_deinit(hdev); nfc_hci_unregister_device(hdev); nfc_hci_free_device(hdev); kfree(info); diff --git a/drivers/nfc/st21nfca/st21nfca.h b/drivers/nfc/st21nfca/st21nfca.h index 7c2a85292230..15a78d330a9f 100644 --- a/drivers/nfc/st21nfca/st21nfca.h +++ b/drivers/nfc/st21nfca/st21nfca.h @@ -20,6 +20,7 @@ #include #include "st21nfca_dep.h" +#include "st21nfca_se.h" #define HCI_MODE 0 @@ -51,9 +52,15 @@ #define ST21NFCA_NUM_DEVICES 256 +struct st21nfca_se_status { + bool is_ese_present; + bool is_uicc_present; +}; + int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, int phy_headroom, int phy_tailroom, - int phy_payload, struct nfc_hci_dev **hdev); + int phy_payload, struct nfc_hci_dev **hdev, + struct st21nfca_se_status *se_status); void st21nfca_hci_remove(struct nfc_hci_dev *hdev); enum st21nfca_state { @@ -66,6 +73,7 @@ struct st21nfca_hci_info { void *phy_id; struct nfc_hci_dev *hdev; + struct st21nfca_se_status *se_status; enum st21nfca_state state; @@ -76,13 +84,16 @@ struct st21nfca_hci_info { void *async_cb_context; struct st21nfca_dep_info dep_info; + struct st21nfca_se_info se_info; }; /* Reader RF commands */ -#define ST21NFCA_WR_XCHG_DATA 0x10 +#define ST21NFCA_WR_XCHG_DATA 0x10 -#define ST21NFCA_RF_READER_F_GATE 0x14 - -#define ST21NFCA_RF_CARD_F_GATE 0x24 +#define ST21NFCA_DEVICE_MGNT_GATE 0x01 +#define ST21NFCA_RF_READER_F_GATE 0x14 +#define ST21NFCA_RF_CARD_F_GATE 0x24 +#define ST21NFCA_APDU_READER_GATE 0xf0 +#define ST21NFCA_CONNECTIVITY_GATE 0x41 #endif /* __LOCAL_ST21NFCA_H_ */ diff --git a/drivers/nfc/st21nfca/st21nfca_se.c b/drivers/nfc/st21nfca/st21nfca_se.c new file mode 100644 index 000000000000..bd13cac9c66a --- /dev/null +++ b/drivers/nfc/st21nfca/st21nfca_se.c @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#include "st21nfca.h" +#include "st21nfca_se.h" + +#define ST21NFCA_EVT_UICC_ACTIVATE 0x10 +#define ST21NFCA_EVT_UICC_DEACTIVATE 0x13 +#define ST21NFCA_EVT_SE_HARD_RESET 0x20 +#define ST21NFCA_EVT_SE_SOFT_RESET 0x11 +#define ST21NFCA_EVT_SE_END_OF_APDU_TRANSFER 0x21 +#define ST21NFCA_EVT_SE_ACTIVATE 0x22 +#define ST21NFCA_EVT_SE_DEACTIVATE 0x23 + +#define ST21NFCA_EVT_TRANSMIT_DATA 0x10 +#define ST21NFCA_EVT_WTX_REQUEST 0x11 + +#define ST21NFCA_EVT_CONNECTIVITY 0x10 +#define ST21NFCA_EVT_TRANSACTION 0x12 + +#define ST21NFCA_ESE_HOST_ID 0xc0 + +#define ST21NFCA_SE_TO_HOT_PLUG 1000 +/* Connectivity pipe only */ +#define ST21NFCA_SE_COUNT_PIPE_UICC 0x01 +/* Connectivity + APDU Reader pipe */ +#define ST21NFCA_SE_COUNT_PIPE_EMBEDDED 0x02 + +#define ST21NFCA_SE_MODE_OFF 0x00 +#define ST21NFCA_SE_MODE_ON 0x01 + +#define ST21NFCA_PARAM_ATR 0x01 +#define ST21NFCA_ATR_DEFAULT_BWI 0x04 + +/* + * WT = 2^BWI/10[s], convert into msecs and add a secure + * room by increasing by 2 this timeout + */ +#define ST21NFCA_BWI_TO_TIMEOUT(x) ((1 << x) * 200) +#define ST21NFCA_ATR_GET_Y_FROM_TD(x) (x >> 4) + +/* If TA is present bit 0 is set */ +#define ST21NFCA_ATR_TA_PRESENT(x) (x & 0x01) +/* If TB is present bit 1 is set */ +#define ST21NFCA_ATR_TB_PRESENT(x) (x & 0x02) + +static u8 st21nfca_se_get_bwi(struct nfc_hci_dev *hdev) +{ + int i; + u8 td; + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + /* Bits 8 to 5 of the first TB for T=1 encode BWI from zero to nine */ + for (i = 1; i < ST21NFCA_ESE_MAX_LENGTH; i++) { + td = ST21NFCA_ATR_GET_Y_FROM_TD(info->se_info.atr[i]); + if (ST21NFCA_ATR_TA_PRESENT(td)) + i++; + if (ST21NFCA_ATR_TB_PRESENT(td)) { + i++; + return info->se_info.atr[i] >> 4; + } + } + return ST21NFCA_ATR_DEFAULT_BWI; +} + +static void st21nfca_se_get_atr(struct nfc_hci_dev *hdev) +{ + int r; + struct sk_buff *skb; + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + r = nfc_hci_get_param(hdev, ST21NFCA_APDU_READER_GATE, + ST21NFCA_PARAM_ATR, &skb); + if (r < 0) + return; + + if (skb->len <= ST21NFCA_ESE_MAX_LENGTH) { + memcpy(info->se_info.atr, skb->data, skb->len); + info->se_info.wt_timeout = + ST21NFCA_BWI_TO_TIMEOUT(st21nfca_se_get_bwi(hdev)); + } + kfree_skb(skb); +} + +static int st21nfca_hci_control_se(struct nfc_hci_dev *hdev, u32 se_idx, + u8 state) +{ + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + int r; + struct sk_buff *sk_host_list; + u8 se_event, host_id; + + switch (se_idx) { + case NFC_HCI_UICC_HOST_ID: + se_event = (state == ST21NFCA_SE_MODE_ON ? + ST21NFCA_EVT_UICC_ACTIVATE : + ST21NFCA_EVT_UICC_DEACTIVATE); + + info->se_info.count_pipes = 0; + info->se_info.expected_pipes = ST21NFCA_SE_COUNT_PIPE_UICC; + break; + case ST21NFCA_ESE_HOST_ID: + se_event = (state == ST21NFCA_SE_MODE_ON ? + ST21NFCA_EVT_SE_ACTIVATE : + ST21NFCA_EVT_SE_DEACTIVATE); + + info->se_info.count_pipes = 0; + info->se_info.expected_pipes = ST21NFCA_SE_COUNT_PIPE_EMBEDDED; + break; + default: + return -EINVAL; + } + + /* + * Wait for an EVT_HOT_PLUG in order to + * retrieve a relevant host list. + */ + reinit_completion(&info->se_info.req_completion); + r = nfc_hci_send_event(hdev, ST21NFCA_DEVICE_MGNT_GATE, se_event, + NULL, 0); + if (r < 0) + return r; + + mod_timer(&info->se_info.se_active_timer, jiffies + + msecs_to_jiffies(ST21NFCA_SE_TO_HOT_PLUG)); + info->se_info.se_active = true; + + /* Ignore return value and check in any case the host_list */ + wait_for_completion_interruptible(&info->se_info.req_completion); + + r = nfc_hci_get_param(hdev, NFC_HCI_ADMIN_GATE, + NFC_HCI_ADMIN_HOST_LIST, + &sk_host_list); + if (r < 0) + return r; + + host_id = sk_host_list->data[sk_host_list->len - 1]; + kfree_skb(sk_host_list); + + if (state == ST21NFCA_SE_MODE_ON && host_id == se_idx) + return se_idx; + else if (state == ST21NFCA_SE_MODE_OFF && host_id != se_idx) + return se_idx; + + return -1; +} + +int st21nfca_hci_discover_se(struct nfc_hci_dev *hdev) +{ + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + int se_count = 0; + + if (info->se_status->is_uicc_present) { + nfc_add_se(hdev->ndev, NFC_HCI_UICC_HOST_ID, NFC_SE_UICC); + se_count++; + } + + if (info->se_status->is_ese_present) { + nfc_add_se(hdev->ndev, ST21NFCA_ESE_HOST_ID, NFC_SE_EMBEDDED); + se_count++; + } + + return !se_count; +} +EXPORT_SYMBOL(st21nfca_hci_discover_se); + +int st21nfca_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx) +{ + int r; + + /* + * According to upper layer, se_idx == NFC_SE_UICC when + * info->se_status->is_uicc_enable is true should never happen. + * Same for eSE. + */ + r = st21nfca_hci_control_se(hdev, se_idx, ST21NFCA_SE_MODE_ON); + + if (r == ST21NFCA_ESE_HOST_ID) { + st21nfca_se_get_atr(hdev); + r = nfc_hci_send_event(hdev, ST21NFCA_APDU_READER_GATE, + ST21NFCA_EVT_SE_SOFT_RESET, NULL, 0); + if (r < 0) + return r; + } else if (r < 0) { + /* + * The activation tentative failed, the secure element + * is not connected. Remove from the list. + */ + nfc_remove_se(hdev->ndev, se_idx); + return r; + } + + return 0; +} +EXPORT_SYMBOL(st21nfca_hci_enable_se); + +int st21nfca_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx) +{ + int r; + + /* + * According to upper layer, se_idx == NFC_SE_UICC when + * info->se_status->is_uicc_enable is true should never happen + * Same for eSE. + */ + r = st21nfca_hci_control_se(hdev, se_idx, ST21NFCA_SE_MODE_OFF); + if (r < 0) + return r; + + return 0; +} +EXPORT_SYMBOL(st21nfca_hci_disable_se); + +int st21nfca_hci_se_io(struct nfc_hci_dev *hdev, u32 se_idx, + u8 *apdu, size_t apdu_length, + se_io_cb_t cb, void *cb_context) +{ + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + pr_debug("se_io %x\n", se_idx); + + switch (se_idx) { + case ST21NFCA_ESE_HOST_ID: + info->se_info.cb = cb; + info->se_info.cb_context = cb_context; + mod_timer(&info->se_info.bwi_timer, jiffies + + msecs_to_jiffies(info->se_info.wt_timeout)); + info->se_info.bwi_active = true; + return nfc_hci_send_event(hdev, ST21NFCA_APDU_READER_GATE, + ST21NFCA_EVT_TRANSMIT_DATA, + apdu, apdu_length); + default: + return -ENODEV; + } +} +EXPORT_SYMBOL(st21nfca_hci_se_io); + +static void st21nfca_se_wt_timeout(unsigned long data) +{ + /* + * No answer from the secure element + * within the defined timeout. + * Let's send a reset request as recovery procedure. + * According to the situation, we first try to send a software reset + * to the secure element. If the next command is still not + * answering in time, we send to the CLF a secure element hardware + * reset request. + */ + /* hardware reset managed through VCC_UICC_OUT power supply */ + u8 param = 0x01; + struct st21nfca_hci_info *info = (struct st21nfca_hci_info *) data; + + pr_debug("\n"); + + info->se_info.bwi_active = false; + + if (!info->se_info.xch_error) { + info->se_info.xch_error = true; + nfc_hci_send_event(info->hdev, ST21NFCA_APDU_READER_GATE, + ST21NFCA_EVT_SE_SOFT_RESET, NULL, 0); + } else { + info->se_info.xch_error = false; + nfc_hci_send_event(info->hdev, ST21NFCA_DEVICE_MGNT_GATE, + ST21NFCA_EVT_SE_HARD_RESET, ¶m, 1); + } + info->se_info.cb(info->se_info.cb_context, NULL, 0, -ETIME); +} + +static void st21nfca_se_activation_timeout(unsigned long data) +{ + struct st21nfca_hci_info *info = (struct st21nfca_hci_info *) data; + + pr_debug("\n"); + + info->se_info.se_active = false; + + complete(&info->se_info.req_completion); +} + +/* + * Returns: + * <= 0: driver handled the event, skb consumed + * 1: driver does not handle the event, please do standard processing + */ +int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host, + u8 event, struct sk_buff *skb) +{ + int r = 0; + struct device *dev = &hdev->ndev->dev; + struct nfc_evt_transaction *transaction; + + pr_debug("connectivity gate event: %x\n", event); + + switch (event) { + case ST21NFCA_EVT_CONNECTIVITY: + break; + case ST21NFCA_EVT_TRANSACTION: + if (skb->len < NFC_MIN_AID_LENGTH + 2 && + skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG) + return -EPROTO; + + transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev, + skb->len - 2, GFP_KERNEL); + + transaction->aid_len = skb->data[1]; + memcpy(transaction->aid, &skb->data[2], skb->data[1]); + + if (skb->data[transaction->aid_len + 2] != + NFC_EVT_TRANSACTION_PARAMS_TAG) + return -EPROTO; + + transaction->params_len = skb->data[transaction->aid_len + 3]; + memcpy(transaction->params, skb->data + + transaction->aid_len + 4, transaction->params_len); + + r = nfc_se_transaction(hdev->ndev, host, transaction); + break; + default: + return 1; + } + kfree_skb(skb); + return r; +} +EXPORT_SYMBOL(st21nfca_connectivity_event_received); + +int st21nfca_apdu_reader_event_received(struct nfc_hci_dev *hdev, + u8 event, struct sk_buff *skb) +{ + int r = 0; + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + pr_debug("apdu reader gate event: %x\n", event); + + switch (event) { + case ST21NFCA_EVT_TRANSMIT_DATA: + del_timer_sync(&info->se_info.bwi_timer); + info->se_info.bwi_active = false; + r = nfc_hci_send_event(hdev, ST21NFCA_DEVICE_MGNT_GATE, + ST21NFCA_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0); + if (r < 0) + goto exit; + + info->se_info.cb(info->se_info.cb_context, + skb->data, skb->len, 0); + break; + case ST21NFCA_EVT_WTX_REQUEST: + mod_timer(&info->se_info.bwi_timer, jiffies + + msecs_to_jiffies(info->se_info.wt_timeout)); + break; + } + +exit: + kfree_skb(skb); + return r; +} +EXPORT_SYMBOL(st21nfca_apdu_reader_event_received); + +void st21nfca_se_init(struct nfc_hci_dev *hdev) +{ + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + init_completion(&info->se_info.req_completion); + /* initialize timers */ + init_timer(&info->se_info.bwi_timer); + info->se_info.bwi_timer.data = (unsigned long)info; + info->se_info.bwi_timer.function = st21nfca_se_wt_timeout; + info->se_info.bwi_active = false; + + init_timer(&info->se_info.se_active_timer); + info->se_info.se_active_timer.data = (unsigned long)info; + info->se_info.se_active_timer.function = st21nfca_se_activation_timeout; + info->se_info.se_active = false; + + info->se_info.count_pipes = 0; + info->se_info.expected_pipes = 0; + + info->se_info.xch_error = false; + + info->se_info.wt_timeout = + ST21NFCA_BWI_TO_TIMEOUT(ST21NFCA_ATR_DEFAULT_BWI); +} +EXPORT_SYMBOL(st21nfca_se_init); + +void st21nfca_se_deinit(struct nfc_hci_dev *hdev) +{ + struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); + + if (info->se_info.bwi_active) + del_timer_sync(&info->se_info.bwi_timer); + if (info->se_info.se_active) + del_timer_sync(&info->se_info.se_active_timer); + + info->se_info.bwi_active = false; + info->se_info.se_active = false; +} +EXPORT_SYMBOL(st21nfca_se_deinit); diff --git a/drivers/nfc/st21nfca/st21nfca_se.h b/drivers/nfc/st21nfca/st21nfca_se.h new file mode 100644 index 000000000000..b172cfcaeb90 --- /dev/null +++ b/drivers/nfc/st21nfca/st21nfca_se.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef __ST21NFCA_SE_H +#define __ST21NFCA_SE_H + +#include +#include + +/* + * ref ISO7816-3 chap 8.1. the initial character TS is followed by a + * sequence of at most 32 characters. + */ +#define ST21NFCA_ESE_MAX_LENGTH 33 +#define ST21NFCA_ESE_HOST_ID 0xc0 + +struct st21nfca_se_info { + u8 atr[ST21NFCA_ESE_MAX_LENGTH]; + struct completion req_completion; + + struct timer_list bwi_timer; + int wt_timeout; /* in msecs */ + bool bwi_active; + + struct timer_list se_active_timer; + bool se_active; + int expected_pipes; + int count_pipes; + + bool xch_error; + + se_io_cb_t cb; + void *cb_context; +}; + +int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host, + u8 event, struct sk_buff *skb); +int st21nfca_apdu_reader_event_received(struct nfc_hci_dev *hdev, + u8 event, struct sk_buff *skb); + +int st21nfca_hci_discover_se(struct nfc_hci_dev *hdev); +int st21nfca_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx); +int st21nfca_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx); +int st21nfca_hci_se_io(struct nfc_hci_dev *hdev, u32 se_idx, + u8 *apdu, size_t apdu_length, + se_io_cb_t cb, void *cb_context); + +void st21nfca_se_init(struct nfc_hci_dev *hdev); +void st21nfca_se_deinit(struct nfc_hci_dev *hdev); +#endif /* __ST21NFCA_SE_H */ diff --git a/drivers/nfc/st21nfcb/Makefile b/drivers/nfc/st21nfcb/Makefile index f4d835dd15f2..ce659a9e5a1a 100644 --- a/drivers/nfc/st21nfcb/Makefile +++ b/drivers/nfc/st21nfcb/Makefile @@ -2,7 +2,7 @@ # Makefile for ST21NFCB NCI based NFC driver # -st21nfcb_nci-objs = ndlc.o st21nfcb.o +st21nfcb_nci-objs = ndlc.o st21nfcb.o st21nfcb_se.o obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb_nci.o st21nfcb_i2c-objs = i2c.o diff --git a/drivers/nfc/st21nfcb/i2c.c b/drivers/nfc/st21nfcb/i2c.c index 01ba865863ee..eb886932d972 100644 --- a/drivers/nfc/st21nfcb/i2c.c +++ b/drivers/nfc/st21nfcb/i2c.c @@ -199,7 +199,7 @@ static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id) struct sk_buff *skb = NULL; int r; - if (!phy || irq != phy->i2c_dev->irq) { + if (!phy || !phy->ndlc || irq != phy->i2c_dev->irq) { WARN_ON_ONCE(1); return IRQ_NONE; } @@ -343,18 +343,22 @@ static int st21nfcb_nci_i2c_probe(struct i2c_client *client, return -ENODEV; } + r = ndlc_probe(phy, &i2c_phy_ops, &client->dev, + ST21NFCB_FRAME_HEADROOM, ST21NFCB_FRAME_TAILROOM, + &phy->ndlc); + if (r < 0) { + nfc_err(&client->dev, "Unable to register ndlc layer\n"); + return r; + } + r = devm_request_threaded_irq(&client->dev, client->irq, NULL, st21nfcb_nci_irq_thread_fn, phy->irq_polarity | IRQF_ONESHOT, ST21NFCB_NCI_DRIVER_NAME, phy); - if (r < 0) { + if (r < 0) nfc_err(&client->dev, "Unable to register IRQ handler\n"); - return r; - } - return ndlc_probe(phy, &i2c_phy_ops, &client->dev, - ST21NFCB_FRAME_HEADROOM, ST21NFCB_FRAME_TAILROOM, - &phy->ndlc); + return r; } static int st21nfcb_nci_i2c_remove(struct i2c_client *client) @@ -373,6 +377,7 @@ static int st21nfcb_nci_i2c_remove(struct i2c_client *client) #ifdef CONFIG_OF static const struct of_device_id of_st21nfcb_i2c_match[] = { + { .compatible = "st,st21nfcb-i2c", }, { .compatible = "st,st21nfcb_i2c", }, {} }; diff --git a/drivers/nfc/st21nfcb/ndlc.c b/drivers/nfc/st21nfcb/ndlc.c index bac50e805f1d..5fbf59d2138c 100644 --- a/drivers/nfc/st21nfcb/ndlc.c +++ b/drivers/nfc/st21nfcb/ndlc.c @@ -138,7 +138,7 @@ static void llt_ndlc_requeue_data_pending(struct llt_ndlc *ndlc) default: pr_err("UNKNOWN Packet Control Byte=%d\n", pcb); kfree_skb(skb); - break; + continue; } skb_queue_head(&ndlc->send_q, skb); } @@ -297,6 +297,5 @@ void ndlc_remove(struct llt_ndlc *ndlc) skb_queue_purge(&ndlc->send_q); st21nfcb_nci_remove(ndlc->ndev); - kfree(ndlc); } EXPORT_SYMBOL(ndlc_remove); diff --git a/drivers/nfc/st21nfcb/st21nfcb.c b/drivers/nfc/st21nfcb/st21nfcb.c index ea63d5877831..ca9871ab3fb3 100644 --- a/drivers/nfc/st21nfcb/st21nfcb.c +++ b/drivers/nfc/st21nfcb/st21nfcb.c @@ -22,6 +22,7 @@ #include #include "st21nfcb.h" +#include "st21nfcb_se.h" #define DRIVER_DESC "NCI NFC driver for ST21NFCB" @@ -78,6 +79,13 @@ static struct nci_ops st21nfcb_nci_ops = { .close = st21nfcb_nci_close, .send = st21nfcb_nci_send, .get_rfprotocol = st21nfcb_nci_get_rfprotocol, + .discover_se = st21nfcb_nci_discover_se, + .enable_se = st21nfcb_nci_enable_se, + .disable_se = st21nfcb_nci_disable_se, + .se_io = st21nfcb_nci_se_io, + .hci_load_session = st21nfcb_hci_load_session, + .hci_event_received = st21nfcb_hci_event_received, + .hci_cmd_received = st21nfcb_hci_cmd_received, }; int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, @@ -114,9 +122,10 @@ int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, if (r) { pr_err("Cannot register nfc device to nci core\n"); nci_free_device(ndlc->ndev); + return r; } - return r; + return st21nfcb_se_init(ndlc->ndev); } EXPORT_SYMBOL_GPL(st21nfcb_nci_probe); diff --git a/drivers/nfc/st21nfcb/st21nfcb.h b/drivers/nfc/st21nfcb/st21nfcb.h index ea58a56ad794..5ef8a58c9839 100644 --- a/drivers/nfc/st21nfcb/st21nfcb.h +++ b/drivers/nfc/st21nfcb/st21nfcb.h @@ -19,6 +19,7 @@ #ifndef __LOCAL_ST21NFCB_H_ #define __LOCAL_ST21NFCB_H_ +#include "st21nfcb_se.h" #include "ndlc.h" /* Define private flags: */ @@ -27,6 +28,7 @@ struct st21nfcb_nci_info { struct llt_ndlc *ndlc; unsigned long flags; + struct st21nfcb_se_info se_info; }; void st21nfcb_nci_remove(struct nci_dev *ndev); diff --git a/drivers/nfc/st21nfcb/st21nfcb_se.c b/drivers/nfc/st21nfcb/st21nfcb_se.c new file mode 100644 index 000000000000..7c82e9d87a65 --- /dev/null +++ b/drivers/nfc/st21nfcb/st21nfcb_se.c @@ -0,0 +1,707 @@ +/* + * NCI based Driver for STMicroelectronics NFC Chip + * + * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include + +#include "st21nfcb.h" +#include "st21nfcb_se.h" + +struct st21nfcb_pipe_info { + u8 pipe_state; + u8 src_host_id; + u8 src_gate_id; + u8 dst_host_id; + u8 dst_gate_id; +} __packed; + +/* Hosts */ +#define ST21NFCB_HOST_CONTROLLER_ID 0x00 +#define ST21NFCB_TERMINAL_HOST_ID 0x01 +#define ST21NFCB_UICC_HOST_ID 0x02 +#define ST21NFCB_ESE_HOST_ID 0xc0 + +/* Gates */ +#define ST21NFCB_DEVICE_MGNT_GATE 0x01 +#define ST21NFCB_APDU_READER_GATE 0xf0 +#define ST21NFCB_CONNECTIVITY_GATE 0x41 + +/* Pipes */ +#define ST21NFCB_DEVICE_MGNT_PIPE 0x02 + +/* Connectivity pipe only */ +#define ST21NFCB_SE_COUNT_PIPE_UICC 0x01 +/* Connectivity + APDU Reader pipe */ +#define ST21NFCB_SE_COUNT_PIPE_EMBEDDED 0x02 + +#define ST21NFCB_SE_TO_HOT_PLUG 1000 /* msecs */ +#define ST21NFCB_SE_TO_PIPES 2000 + +#define ST21NFCB_EVT_HOT_PLUG_IS_INHIBITED(x) (x->data[0] & 0x80) + +#define NCI_HCI_APDU_PARAM_ATR 0x01 +#define NCI_HCI_ADMIN_PARAM_SESSION_IDENTITY 0x01 +#define NCI_HCI_ADMIN_PARAM_WHITELIST 0x03 +#define NCI_HCI_ADMIN_PARAM_HOST_LIST 0x04 + +#define ST21NFCB_EVT_SE_HARD_RESET 0x20 +#define ST21NFCB_EVT_TRANSMIT_DATA 0x10 +#define ST21NFCB_EVT_WTX_REQUEST 0x11 +#define ST21NFCB_EVT_SE_SOFT_RESET 0x11 +#define ST21NFCB_EVT_SE_END_OF_APDU_TRANSFER 0x21 +#define ST21NFCB_EVT_HOT_PLUG 0x03 + +#define ST21NFCB_SE_MODE_OFF 0x00 +#define ST21NFCB_SE_MODE_ON 0x01 + +#define ST21NFCB_EVT_CONNECTIVITY 0x10 +#define ST21NFCB_EVT_TRANSACTION 0x12 + +#define ST21NFCB_DM_GETINFO 0x13 +#define ST21NFCB_DM_GETINFO_PIPE_LIST 0x02 +#define ST21NFCB_DM_GETINFO_PIPE_INFO 0x01 +#define ST21NFCB_DM_PIPE_CREATED 0x02 +#define ST21NFCB_DM_PIPE_OPEN 0x04 +#define ST21NFCB_DM_RF_ACTIVE 0x80 +#define ST21NFCB_DM_DISCONNECT 0x30 + +#define ST21NFCB_DM_IS_PIPE_OPEN(p) \ + ((p & 0x0f) == (ST21NFCB_DM_PIPE_CREATED | ST21NFCB_DM_PIPE_OPEN)) + +#define ST21NFCB_ATR_DEFAULT_BWI 0x04 + +/* + * WT = 2^BWI/10[s], convert into msecs and add a secure + * room by increasing by 2 this timeout + */ +#define ST21NFCB_BWI_TO_TIMEOUT(x) ((1 << x) * 200) +#define ST21NFCB_ATR_GET_Y_FROM_TD(x) (x >> 4) + +/* If TA is present bit 0 is set */ +#define ST21NFCB_ATR_TA_PRESENT(x) (x & 0x01) +/* If TB is present bit 1 is set */ +#define ST21NFCB_ATR_TB_PRESENT(x) (x & 0x02) + +#define ST21NFCB_NUM_DEVICES 256 + +static DECLARE_BITMAP(dev_mask, ST21NFCB_NUM_DEVICES); + +/* Here are the mandatory pipe for st21nfcb */ +static struct nci_hci_gate st21nfcb_gates[] = { + {NCI_HCI_ADMIN_GATE, NCI_HCI_ADMIN_PIPE, + ST21NFCB_HOST_CONTROLLER_ID}, + {NCI_HCI_LINK_MGMT_GATE, NCI_HCI_LINK_MGMT_PIPE, + ST21NFCB_HOST_CONTROLLER_ID}, + {ST21NFCB_DEVICE_MGNT_GATE, ST21NFCB_DEVICE_MGNT_PIPE, + ST21NFCB_HOST_CONTROLLER_ID}, + + /* Secure element pipes are created by secure element host */ + {ST21NFCB_CONNECTIVITY_GATE, NCI_HCI_DO_NOT_OPEN_PIPE, + ST21NFCB_HOST_CONTROLLER_ID}, + {ST21NFCB_APDU_READER_GATE, NCI_HCI_DO_NOT_OPEN_PIPE, + ST21NFCB_HOST_CONTROLLER_ID}, +}; + +static u8 st21nfcb_se_get_bwi(struct nci_dev *ndev) +{ + int i; + u8 td; + struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); + + /* Bits 8 to 5 of the first TB for T=1 encode BWI from zero to nine */ + for (i = 1; i < ST21NFCB_ESE_MAX_LENGTH; i++) { + td = ST21NFCB_ATR_GET_Y_FROM_TD(info->se_info.atr[i]); + if (ST21NFCB_ATR_TA_PRESENT(td)) + i++; + if (ST21NFCB_ATR_TB_PRESENT(td)) { + i++; + return info->se_info.atr[i] >> 4; + } + } + return ST21NFCB_ATR_DEFAULT_BWI; +} + +static void st21nfcb_se_get_atr(struct nci_dev *ndev) +{ + struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); + int r; + struct sk_buff *skb; + + r = nci_hci_get_param(ndev, ST21NFCB_APDU_READER_GATE, + NCI_HCI_APDU_PARAM_ATR, &skb); + if (r < 0) + return; + + if (skb->len <= ST21NFCB_ESE_MAX_LENGTH) { + memcpy(info->se_info.atr, skb->data, skb->len); + + info->se_info.wt_timeout = + ST21NFCB_BWI_TO_TIMEOUT(st21nfcb_se_get_bwi(ndev)); + } + kfree_skb(skb); +} + +int st21nfcb_hci_load_session(struct nci_dev *ndev) +{ + int i, j, r; + struct sk_buff *skb_pipe_list, *skb_pipe_info; + struct st21nfcb_pipe_info *dm_pipe_info; + u8 pipe_list[] = { ST21NFCB_DM_GETINFO_PIPE_LIST, + ST21NFCB_TERMINAL_HOST_ID}; + u8 pipe_info[] = { ST21NFCB_DM_GETINFO_PIPE_INFO, + ST21NFCB_TERMINAL_HOST_ID, 0}; + + /* On ST21NFCB device pipes number are dynamics + * If pipes are already created, hci_dev_up will fail. + * Doing a clear all pipe is a bad idea because: + * - It does useless EEPROM cycling + * - It might cause issue for secure elements support + * (such as removing connectivity or APDU reader pipe) + * A better approach on ST21NFCB is to: + * - get a pipe list for each host. + * (eg: ST21NFCB_HOST_CONTROLLER_ID for now). + * (TODO Later on UICC HOST and eSE HOST) + * - get pipe information + * - match retrieved pipe list in st21nfcb_gates + * ST21NFCB_DEVICE_MGNT_GATE is a proprietary gate + * with ST21NFCB_DEVICE_MGNT_PIPE. + * Pipe can be closed and need to be open. + */ + r = nci_hci_connect_gate(ndev, ST21NFCB_HOST_CONTROLLER_ID, + ST21NFCB_DEVICE_MGNT_GATE, + ST21NFCB_DEVICE_MGNT_PIPE); + if (r < 0) + goto free_info; + + /* Get pipe list */ + r = nci_hci_send_cmd(ndev, ST21NFCB_DEVICE_MGNT_GATE, + ST21NFCB_DM_GETINFO, pipe_list, sizeof(pipe_list), + &skb_pipe_list); + if (r < 0) + goto free_info; + + /* Complete the existing gate_pipe table */ + for (i = 0; i < skb_pipe_list->len; i++) { + pipe_info[2] = skb_pipe_list->data[i]; + r = nci_hci_send_cmd(ndev, ST21NFCB_DEVICE_MGNT_GATE, + ST21NFCB_DM_GETINFO, pipe_info, + sizeof(pipe_info), &skb_pipe_info); + + if (r) + continue; + + /* + * Match pipe ID and gate ID + * Output format from ST21NFC_DM_GETINFO is: + * - pipe state (1byte) + * - source hid (1byte) + * - source gid (1byte) + * - destination hid (1byte) + * - destination gid (1byte) + */ + dm_pipe_info = (struct st21nfcb_pipe_info *)skb_pipe_info->data; + if (dm_pipe_info->dst_gate_id == ST21NFCB_APDU_READER_GATE && + dm_pipe_info->src_host_id != ST21NFCB_ESE_HOST_ID) { + pr_err("Unexpected apdu_reader pipe on host %x\n", + dm_pipe_info->src_host_id); + continue; + } + + for (j = 0; (j < ARRAY_SIZE(st21nfcb_gates)) && + (st21nfcb_gates[j].gate != dm_pipe_info->dst_gate_id); j++) + ; + + if (j < ARRAY_SIZE(st21nfcb_gates) && + st21nfcb_gates[j].gate == dm_pipe_info->dst_gate_id && + ST21NFCB_DM_IS_PIPE_OPEN(dm_pipe_info->pipe_state)) { + st21nfcb_gates[j].pipe = pipe_info[2]; + + ndev->hci_dev->gate2pipe[st21nfcb_gates[j].gate] = + st21nfcb_gates[j].pipe; + ndev->hci_dev->pipes[st21nfcb_gates[j].pipe].gate = + st21nfcb_gates[j].gate; + ndev->hci_dev->pipes[st21nfcb_gates[j].pipe].host = + dm_pipe_info->src_host_id; + } + } + + memcpy(ndev->hci_dev->init_data.gates, st21nfcb_gates, + sizeof(st21nfcb_gates)); + +free_info: + kfree_skb(skb_pipe_info); + kfree_skb(skb_pipe_list); + return r; +} +EXPORT_SYMBOL_GPL(st21nfcb_hci_load_session); + +static void st21nfcb_hci_admin_event_received(struct nci_dev *ndev, + u8 event, struct sk_buff *skb) +{ + struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); + + switch (event) { + case ST21NFCB_EVT_HOT_PLUG: + if (info->se_info.se_active) { + if (!ST21NFCB_EVT_HOT_PLUG_IS_INHIBITED(skb)) { + del_timer_sync(&info->se_info.se_active_timer); + info->se_info.se_active = false; + complete(&info->se_info.req_completion); + } else { + mod_timer(&info->se_info.se_active_timer, + jiffies + + msecs_to_jiffies(ST21NFCB_SE_TO_PIPES)); + } + } + break; + } +} + +static int st21nfcb_hci_apdu_reader_event_received(struct nci_dev *ndev, + u8 event, + struct sk_buff *skb) +{ + int r = 0; + struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); + + pr_debug("apdu reader gate event: %x\n", event); + + switch (event) { + case ST21NFCB_EVT_TRANSMIT_DATA: + del_timer_sync(&info->se_info.bwi_timer); + info->se_info.bwi_active = false; + info->se_info.cb(info->se_info.cb_context, + skb->data, skb->len, 0); + break; + case ST21NFCB_EVT_WTX_REQUEST: + mod_timer(&info->se_info.bwi_timer, jiffies + + msecs_to_jiffies(info->se_info.wt_timeout)); + break; + } + + kfree_skb(skb); + return r; +} + +/* + * Returns: + * <= 0: driver handled the event, skb consumed + * 1: driver does not handle the event, please do standard processing + */ +static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev, + u8 host, u8 event, + struct sk_buff *skb) +{ + int r = 0; + struct device *dev = &ndev->nfc_dev->dev; + struct nfc_evt_transaction *transaction; + + pr_debug("connectivity gate event: %x\n", event); + + switch (event) { + case ST21NFCB_EVT_CONNECTIVITY: + + break; + case ST21NFCB_EVT_TRANSACTION: + if (skb->len < NFC_MIN_AID_LENGTH + 2 && + skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG) + return -EPROTO; + + transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev, + skb->len - 2, GFP_KERNEL); + + transaction->aid_len = skb->data[1]; + memcpy(transaction->aid, &skb->data[2], skb->data[1]); + + if (skb->data[transaction->aid_len + 2] != + NFC_EVT_TRANSACTION_PARAMS_TAG) + return -EPROTO; + + transaction->params_len = skb->data[transaction->aid_len + 3]; + memcpy(transaction->params, skb->data + + transaction->aid_len + 4, transaction->params_len); + + r = nfc_se_transaction(ndev->nfc_dev, host, transaction); + default: + return 1; + } + kfree_skb(skb); + return r; +} + +void st21nfcb_hci_event_received(struct nci_dev *ndev, u8 pipe, + u8 event, struct sk_buff *skb) +{ + u8 gate = ndev->hci_dev->pipes[pipe].gate; + u8 host = ndev->hci_dev->pipes[pipe].host; + + switch (gate) { + case NCI_HCI_ADMIN_GATE: + st21nfcb_hci_admin_event_received(ndev, event, skb); + break; + case ST21NFCB_APDU_READER_GATE: + st21nfcb_hci_apdu_reader_event_received(ndev, event, skb); + break; + case ST21NFCB_CONNECTIVITY_GATE: + st21nfcb_hci_connectivity_event_received(ndev, host, event, + skb); + break; + } +} +EXPORT_SYMBOL_GPL(st21nfcb_hci_event_received); + + +void st21nfcb_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd, + struct sk_buff *skb) +{ + struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); + u8 gate = ndev->hci_dev->pipes[pipe].gate; + + pr_debug("cmd: %x\n", cmd); + + switch (cmd) { + case NCI_HCI_ANY_OPEN_PIPE: + if (gate != ST21NFCB_APDU_READER_GATE && + ndev->hci_dev->pipes[pipe].host != ST21NFCB_UICC_HOST_ID) + ndev->hci_dev->count_pipes++; + + if (ndev->hci_dev->count_pipes == + ndev->hci_dev->expected_pipes) { + del_timer_sync(&info->se_info.se_active_timer); + info->se_info.se_active = false; + ndev->hci_dev->count_pipes = 0; + complete(&info->se_info.req_completion); + } + break; + } +} +EXPORT_SYMBOL_GPL(st21nfcb_hci_cmd_received); + +/* + * Remarks: On some early st21nfcb firmware, nci_nfcee_mode_set(0) + * is rejected + */ +static int st21nfcb_nci_control_se(struct nci_dev *ndev, u8 se_idx, + u8 state) +{ + struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); + int r; + struct sk_buff *sk_host_list; + u8 host_id; + + switch (se_idx) { + case ST21NFCB_UICC_HOST_ID: + ndev->hci_dev->count_pipes = 0; + ndev->hci_dev->expected_pipes = ST21NFCB_SE_COUNT_PIPE_UICC; + break; + case ST21NFCB_ESE_HOST_ID: + ndev->hci_dev->count_pipes = 0; + ndev->hci_dev->expected_pipes = ST21NFCB_SE_COUNT_PIPE_EMBEDDED; + break; + default: + return -EINVAL; + } + + /* + * Wait for an EVT_HOT_PLUG in order to + * retrieve a relevant host list. + */ + reinit_completion(&info->se_info.req_completion); + r = nci_nfcee_mode_set(ndev, se_idx, NCI_NFCEE_ENABLE); + if (r != NCI_STATUS_OK) + return r; + + mod_timer(&info->se_info.se_active_timer, jiffies + + msecs_to_jiffies(ST21NFCB_SE_TO_HOT_PLUG)); + info->se_info.se_active = true; + + /* Ignore return value and check in any case the host_list */ + wait_for_completion_interruptible(&info->se_info.req_completion); + + /* There might be some "collision" after receiving a HOT_PLUG event + * This may cause the CLF to not answer to the next hci command. + * There is no possible synchronization to prevent this. + * Adding a small delay is the only way to solve the issue. + */ + usleep_range(3000, 5000); + + r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE, + NCI_HCI_ADMIN_PARAM_HOST_LIST, &sk_host_list); + if (r != NCI_HCI_ANY_OK) + return r; + + host_id = sk_host_list->data[sk_host_list->len - 1]; + kfree_skb(sk_host_list); + if (state == ST21NFCB_SE_MODE_ON && host_id == se_idx) + return se_idx; + else if (state == ST21NFCB_SE_MODE_OFF && host_id != se_idx) + return se_idx; + + return -1; +} + +int st21nfcb_nci_disable_se(struct nci_dev *ndev, u32 se_idx) +{ + int r; + + pr_debug("st21nfcb_nci_disable_se\n"); + + if (se_idx == NFC_SE_EMBEDDED) { + r = nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE, + ST21NFCB_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0); + if (r < 0) + return r; + } + + return 0; +} +EXPORT_SYMBOL_GPL(st21nfcb_nci_disable_se); + +int st21nfcb_nci_enable_se(struct nci_dev *ndev, u32 se_idx) +{ + int r; + + pr_debug("st21nfcb_nci_enable_se\n"); + + if (se_idx == ST21NFCB_HCI_HOST_ID_ESE) { + r = nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE, + ST21NFCB_EVT_SE_SOFT_RESET, NULL, 0); + if (r < 0) + return r; + } + + return 0; +} +EXPORT_SYMBOL_GPL(st21nfcb_nci_enable_se); + +static int st21nfcb_hci_network_init(struct nci_dev *ndev) +{ + struct core_conn_create_dest_spec_params *dest_params; + struct dest_spec_params spec_params; + struct nci_conn_info *conn_info; + int r, dev_num; + + dest_params = + kzalloc(sizeof(struct core_conn_create_dest_spec_params) + + sizeof(struct dest_spec_params), GFP_KERNEL); + if (dest_params == NULL) { + r = -ENOMEM; + goto exit; + } + + dest_params->type = NCI_DESTINATION_SPECIFIC_PARAM_NFCEE_TYPE; + dest_params->length = sizeof(struct dest_spec_params); + spec_params.id = ndev->hci_dev->nfcee_id; + spec_params.protocol = NCI_NFCEE_INTERFACE_HCI_ACCESS; + memcpy(dest_params->value, &spec_params, sizeof(struct dest_spec_params)); + r = nci_core_conn_create(ndev, NCI_DESTINATION_NFCEE, 1, + sizeof(struct core_conn_create_dest_spec_params) + + sizeof(struct dest_spec_params), + dest_params); + if (r != NCI_STATUS_OK) + goto free_dest_params; + + conn_info = ndev->hci_dev->conn_info; + if (!conn_info) + goto free_dest_params; + + memcpy(ndev->hci_dev->init_data.gates, st21nfcb_gates, + sizeof(st21nfcb_gates)); + + /* + * Session id must include the driver name + i2c bus addr + * persistent info to discriminate 2 identical chips + */ + dev_num = find_first_zero_bit(dev_mask, ST21NFCB_NUM_DEVICES); + if (dev_num >= ST21NFCB_NUM_DEVICES) { + r = -ENODEV; + goto free_dest_params; + } + + scnprintf(ndev->hci_dev->init_data.session_id, + sizeof(ndev->hci_dev->init_data.session_id), + "%s%2x", "ST21BH", dev_num); + + r = nci_hci_dev_session_init(ndev); + if (r != NCI_HCI_ANY_OK) + goto exit; + + r = nci_nfcee_mode_set(ndev, ndev->hci_dev->conn_info->id, + NCI_NFCEE_ENABLE); + if (r != NCI_STATUS_OK) + goto exit; + + return 0; + +free_dest_params: + kfree(dest_params); + +exit: + return r; +} + +int st21nfcb_nci_discover_se(struct nci_dev *ndev) +{ + u8 param[2]; + int r; + int se_count = 0; + + pr_debug("st21nfcb_nci_discover_se\n"); + + r = st21nfcb_hci_network_init(ndev); + if (r != 0) + return r; + + param[0] = ST21NFCB_UICC_HOST_ID; + param[1] = ST21NFCB_HCI_HOST_ID_ESE; + r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE, + NCI_HCI_ADMIN_PARAM_WHITELIST, + param, sizeof(param)); + if (r != NCI_HCI_ANY_OK) + return r; + + r = st21nfcb_nci_control_se(ndev, ST21NFCB_UICC_HOST_ID, + ST21NFCB_SE_MODE_ON); + if (r == ST21NFCB_UICC_HOST_ID) { + nfc_add_se(ndev->nfc_dev, ST21NFCB_UICC_HOST_ID, NFC_SE_UICC); + se_count++; + } + + /* Try to enable eSE in order to check availability */ + r = st21nfcb_nci_control_se(ndev, ST21NFCB_HCI_HOST_ID_ESE, + ST21NFCB_SE_MODE_ON); + if (r == ST21NFCB_HCI_HOST_ID_ESE) { + nfc_add_se(ndev->nfc_dev, ST21NFCB_HCI_HOST_ID_ESE, + NFC_SE_EMBEDDED); + se_count++; + st21nfcb_se_get_atr(ndev); + } + + return !se_count; +} +EXPORT_SYMBOL_GPL(st21nfcb_nci_discover_se); + +int st21nfcb_nci_se_io(struct nci_dev *ndev, u32 se_idx, + u8 *apdu, size_t apdu_length, + se_io_cb_t cb, void *cb_context) +{ + struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); + + pr_debug("\n"); + + switch (se_idx) { + case ST21NFCB_HCI_HOST_ID_ESE: + info->se_info.cb = cb; + info->se_info.cb_context = cb_context; + mod_timer(&info->se_info.bwi_timer, jiffies + + msecs_to_jiffies(info->se_info.wt_timeout)); + info->se_info.bwi_active = true; + return nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE, + ST21NFCB_EVT_TRANSMIT_DATA, apdu, + apdu_length); + default: + return -ENODEV; + } +} +EXPORT_SYMBOL(st21nfcb_nci_se_io); + +static void st21nfcb_se_wt_timeout(unsigned long data) +{ + /* + * No answer from the secure element + * within the defined timeout. + * Let's send a reset request as recovery procedure. + * According to the situation, we first try to send a software reset + * to the secure element. If the next command is still not + * answering in time, we send to the CLF a secure element hardware + * reset request. + */ + /* hardware reset managed through VCC_UICC_OUT power supply */ + u8 param = 0x01; + struct st21nfcb_nci_info *info = (struct st21nfcb_nci_info *) data; + + pr_debug("\n"); + + info->se_info.bwi_active = false; + + if (!info->se_info.xch_error) { + info->se_info.xch_error = true; + nci_hci_send_event(info->ndlc->ndev, ST21NFCB_APDU_READER_GATE, + ST21NFCB_EVT_SE_SOFT_RESET, NULL, 0); + } else { + info->se_info.xch_error = false; + nci_hci_send_event(info->ndlc->ndev, ST21NFCB_DEVICE_MGNT_GATE, + ST21NFCB_EVT_SE_HARD_RESET, ¶m, 1); + } + info->se_info.cb(info->se_info.cb_context, NULL, 0, -ETIME); +} + +static void st21nfcb_se_activation_timeout(unsigned long data) +{ + struct st21nfcb_nci_info *info = (struct st21nfcb_nci_info *) data; + + pr_debug("\n"); + + info->se_info.se_active = false; + + complete(&info->se_info.req_completion); +} + +int st21nfcb_se_init(struct nci_dev *ndev) +{ + struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); + + init_completion(&info->se_info.req_completion); + /* initialize timers */ + init_timer(&info->se_info.bwi_timer); + info->se_info.bwi_timer.data = (unsigned long)info; + info->se_info.bwi_timer.function = st21nfcb_se_wt_timeout; + info->se_info.bwi_active = false; + + init_timer(&info->se_info.se_active_timer); + info->se_info.se_active_timer.data = (unsigned long)info; + info->se_info.se_active_timer.function = + st21nfcb_se_activation_timeout; + info->se_info.se_active = false; + + info->se_info.xch_error = false; + + info->se_info.wt_timeout = + ST21NFCB_BWI_TO_TIMEOUT(ST21NFCB_ATR_DEFAULT_BWI); + + return 0; +} +EXPORT_SYMBOL(st21nfcb_se_init); + +void st21nfcb_se_deinit(struct nci_dev *ndev) +{ + struct st21nfcb_nci_info *info = nci_get_drvdata(ndev); + + if (info->se_info.bwi_active) + del_timer_sync(&info->se_info.bwi_timer); + if (info->se_info.se_active) + del_timer_sync(&info->se_info.se_active_timer); + + info->se_info.se_active = false; + info->se_info.bwi_active = false; +} +EXPORT_SYMBOL(st21nfcb_se_deinit); + diff --git a/drivers/nfc/st21nfcb/st21nfcb_se.h b/drivers/nfc/st21nfcb/st21nfcb_se.h new file mode 100644 index 000000000000..52a323872bea --- /dev/null +++ b/drivers/nfc/st21nfcb/st21nfcb_se.h @@ -0,0 +1,61 @@ +/* + * NCI based Driver for STMicroelectronics NFC Chip + * + * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef __LOCAL_ST21NFCB_SE_H_ +#define __LOCAL_ST21NFCB_SE_H_ + +/* + * ref ISO7816-3 chap 8.1. the initial character TS is followed by a + * sequence of at most 32 characters. + */ +#define ST21NFCB_ESE_MAX_LENGTH 33 +#define ST21NFCB_HCI_HOST_ID_ESE 0xc0 + +struct st21nfcb_se_info { + u8 atr[ST21NFCB_ESE_MAX_LENGTH]; + struct completion req_completion; + + struct timer_list bwi_timer; + int wt_timeout; /* in msecs */ + bool bwi_active; + + struct timer_list se_active_timer; + bool se_active; + + bool xch_error; + + se_io_cb_t cb; + void *cb_context; +}; + +int st21nfcb_se_init(struct nci_dev *ndev); +void st21nfcb_se_deinit(struct nci_dev *ndev); + +int st21nfcb_nci_discover_se(struct nci_dev *ndev); +int st21nfcb_nci_enable_se(struct nci_dev *ndev, u32 se_idx); +int st21nfcb_nci_disable_se(struct nci_dev *ndev, u32 se_idx); +int st21nfcb_nci_se_io(struct nci_dev *ndev, u32 se_idx, + u8 *apdu, size_t apdu_length, + se_io_cb_t cb, void *cb_context); +int st21nfcb_hci_load_session(struct nci_dev *ndev); +void st21nfcb_hci_event_received(struct nci_dev *ndev, u8 pipe, + u8 event, struct sk_buff *skb); +void st21nfcb_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd, + struct sk_buff *skb); + + +#endif /* __LOCAL_ST21NFCB_NCI_H_ */ diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index b5e0c873d4e1..38d1c51f58b1 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -10,7 +10,6 @@ menu "Device Tree and Open Firmware support" config OF_UNITTEST bool "Device Tree runtime unit tests" depends on OF_IRQ && OF_EARLY_FLATTREE - select OF_DYNAMIC select OF_RESOLVE help This option builds in test cases for the device tree infrastructure diff --git a/drivers/of/base.c b/drivers/of/base.c index 36536b6a8834..0a8aeb8523fe 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1303,6 +1303,7 @@ int of_property_read_u64_array(const struct device_node *np, } return 0; } +EXPORT_SYMBOL_GPL(of_property_read_u64_array); /** * of_property_read_string - Find and read a string from a property diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 510074226d57..3a896c9aeb74 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -762,7 +762,7 @@ static inline void early_init_dt_check_for_initrd(unsigned long node) #ifdef CONFIG_SERIAL_EARLYCON extern struct of_device_id __earlycon_of_table[]; -int __init early_init_dt_scan_chosen_serial(void) +static int __init early_init_dt_scan_chosen_serial(void) { int offset; const char *p; diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 88471d3d98cd..110fece2ff53 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -140,6 +140,7 @@ int of_pci_get_host_bridge_resources(struct device_node *dev, unsigned char busno, unsigned char bus_max, struct list_head *resources, resource_size_t *io_base) { + struct resource_entry *window; struct resource *res; struct resource *bus_range; struct of_pci_range range; @@ -225,7 +226,10 @@ int of_pci_get_host_bridge_resources(struct device_node *dev, conversion_failed: kfree(res); parse_failed: + resource_list_for_each_entry(window, resources) + kfree(window->res); pci_free_resource_list(resources); + kfree(bus_range); return err; } EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources); diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index dc566b38645f..726ebe792813 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -265,6 +265,7 @@ int of_reserved_mem_device_init(struct device *dev) return ret; } +EXPORT_SYMBOL_GPL(of_reserved_mem_device_init); /** * of_reserved_mem_device_release() - release reserved memory device structures @@ -289,3 +290,4 @@ void of_reserved_mem_device_release(struct device *dev) rmem->ops->device_release(rmem, dev); } +EXPORT_SYMBOL_GPL(of_reserved_mem_device_release); diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index ea63fbd228ed..352b4f28f82c 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -114,17 +114,6 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov, ret = of_overlay_apply_one(ov, tchild, child); if (ret) return ret; - - /* The properties are already copied, now do the child nodes */ - for_each_child_of_node(child, grandchild) { - ret = of_overlay_apply_single_device_node(ov, tchild, grandchild); - if (ret) { - pr_err("%s: Failed to apply single node @%s/%s\n", - __func__, tchild->full_name, - grandchild->name); - return ret; - } - } } return ret; diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 5b33c6a21807..b0d50d70a8a1 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -188,7 +188,7 @@ static void of_dma_configure(struct device *dev) size = dev->coherent_dma_mask; } else { offset = PFN_DOWN(paddr - dma_addr); - dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", dev->dma_pfn_offset); + dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", offset); } dev->dma_pfn_offset = offset; @@ -566,6 +566,10 @@ static int of_platform_notify(struct notifier_block *nb, if (!of_node_check_flag(rd->dn->parent, OF_POPULATED_BUS)) return NOTIFY_OK; /* not for us */ + /* already populated? (driver using of_populate manually) */ + if (of_node_check_flag(rd->dn, OF_POPULATED)) + return NOTIFY_OK; + /* pdev_parent may be NULL when no bus platform device */ pdev_parent = of_find_device_by_node(rd->dn->parent); pdev = of_platform_device_create(rd->dn, NULL, @@ -581,6 +585,11 @@ static int of_platform_notify(struct notifier_block *nb, break; case OF_RECONFIG_CHANGE_REMOVE: + + /* already depopulated? */ + if (!of_node_check_flag(rd->dn, OF_POPULATED)) + return NOTIFY_OK; + /* find our device by node */ pdev = of_find_device_by_node(rd->dn); if (pdev == NULL) diff --git a/drivers/of/unittest-data/tests-overlay.dtsi b/drivers/of/unittest-data/tests-overlay.dtsi index 75976da22b2e..244226cbb5a3 100644 --- a/drivers/of/unittest-data/tests-overlay.dtsi +++ b/drivers/of/unittest-data/tests-overlay.dtsi @@ -68,6 +68,48 @@ status = "disabled"; reg = <8>; }; + + i2c-test-bus { + compatible = "selftest-i2c-bus"; + status = "okay"; + reg = <50>; + + #address-cells = <1>; + #size-cells = <0>; + + test-selftest12 { + reg = <8>; + compatible = "selftest-i2c-dev"; + status = "disabled"; + }; + + test-selftest13 { + reg = <9>; + compatible = "selftest-i2c-dev"; + status = "okay"; + }; + + test-selftest14 { + reg = <10>; + compatible = "selftest-i2c-mux"; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + test-mux-dev { + reg = <32>; + compatible = "selftest-i2c-dev"; + status = "okay"; + }; + }; + }; + }; }; }; @@ -176,5 +218,112 @@ }; }; + overlay10 { + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus"; + __overlay__ { + + /* suppress DTC warning */ + #address-cells = <1>; + #size-cells = <0>; + + test-selftest10 { + compatible = "selftest"; + status = "okay"; + reg = <10>; + + #address-cells = <1>; + #size-cells = <0>; + + test-selftest101 { + compatible = "selftest"; + status = "okay"; + reg = <1>; + }; + + }; + }; + }; + }; + + overlay11 { + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus"; + __overlay__ { + + /* suppress DTC warning */ + #address-cells = <1>; + #size-cells = <0>; + + test-selftest11 { + compatible = "selftest"; + status = "okay"; + reg = <11>; + + #address-cells = <1>; + #size-cells = <0>; + + test-selftest111 { + compatible = "selftest"; + status = "okay"; + reg = <1>; + }; + + }; + }; + }; + }; + + /* test enable using absolute target path (i2c) */ + overlay12 { + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-selftest12"; + __overlay__ { + status = "okay"; + }; + }; + }; + + /* test disable using absolute target path (i2c) */ + overlay13 { + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-selftest13"; + __overlay__ { + status = "disabled"; + }; + }; + }; + + /* test mux overlay */ + overlay15 { + fragment@0 { + target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus"; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + test-selftest15 { + reg = <11>; + compatible = "selftest-i2c-mux"; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + test-mux-dev { + reg = <32>; + compatible = "selftest-i2c-dev"; + status = "okay"; + }; + }; + }; + }; + }; + }; + }; }; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 844838e11ef1..0cf9a236d438 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -20,6 +20,9 @@ #include #include +#include +#include + #include "of_private.h" static struct selftest_results { @@ -27,11 +30,6 @@ static struct selftest_results { int failed; } selftest_results; -#define NO_OF_NODES 3 -static struct device_node *nodes[NO_OF_NODES]; -static int last_node_index; -static bool selftest_live_tree; - #define selftest(result, fmt, ...) ({ \ bool failed = !(result); \ if (failed) { \ @@ -822,6 +820,7 @@ static void update_node_properties(struct device_node *np, static int attach_node_and_children(struct device_node *np) { struct device_node *next, *dup, *child; + unsigned long flags; dup = of_find_node_by_path(np->full_name); if (dup) { @@ -829,17 +828,19 @@ static int attach_node_and_children(struct device_node *np) return 0; } - /* Children of the root need to be remembered for removal */ - if (np->parent == of_root) { - if (WARN_ON(last_node_index >= NO_OF_NODES)) - return -EINVAL; - nodes[last_node_index++] = np; - } - child = np->child; np->child = NULL; - np->sibling = NULL; - of_attach_node(np); + + mutex_lock(&of_mutex); + raw_spin_lock_irqsave(&devtree_lock, flags); + np->sibling = np->parent->child; + np->parent->child = np; + of_node_clear_flag(np, OF_DETACHED); + raw_spin_unlock_irqrestore(&devtree_lock, flags); + + __of_attach_node_sysfs(np); + mutex_unlock(&of_mutex); + while (child) { next = child->sibling; attach_node_and_children(child); @@ -889,10 +890,7 @@ static int __init selftest_data_add(void) } if (!of_root) { - /* enabling flag for removing nodes */ - selftest_live_tree = true; of_root = selftest_data_node; - for_each_of_allnodes(np) __of_attach_node_sysfs(np); of_aliases = of_find_node_by_path("/aliases"); @@ -911,59 +909,6 @@ static int __init selftest_data_add(void) return 0; } -/** - * detach_node_and_children - detaches node - * and its children from live tree - * - * @np: Node to detach from live tree - */ -static void detach_node_and_children(struct device_node *np) -{ - while (np->child) - detach_node_and_children(np->child); - of_detach_node(np); -} - -/** - * selftest_data_remove - removes the selftest data - * nodes from the live tree - */ -static void selftest_data_remove(void) -{ - struct device_node *np; - struct property *prop; - - if (selftest_live_tree) { - of_node_put(of_aliases); - of_node_put(of_chosen); - of_aliases = NULL; - of_chosen = NULL; - for_each_child_of_node(of_root, np) - detach_node_and_children(np); - __of_detach_node_sysfs(of_root); - of_root = NULL; - return; - } - - while (last_node_index-- > 0) { - if (nodes[last_node_index]) { - np = of_find_node_by_path(nodes[last_node_index]->full_name); - if (np == nodes[last_node_index]) { - if (of_aliases == np) { - of_node_put(of_aliases); - of_aliases = NULL; - } - detach_node_and_children(np); - } else { - for_each_property_of_node(np, prop) { - if (strcmp(prop->name, "testcase-alias") == 0) - of_remove_property(np, prop); - } - } - } - } -} - #ifdef CONFIG_OF_OVERLAY static int selftest_probe(struct platform_device *pdev) @@ -978,6 +923,9 @@ static int selftest_probe(struct platform_device *pdev) } dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name); + + of_platform_populate(np, NULL, NULL, &pdev->dev); + return 0; } @@ -1031,17 +979,94 @@ static int of_path_platform_device_exists(const char *path) return pdev != NULL; } -static const char *selftest_path(int nr) +#if IS_ENABLED(CONFIG_I2C) + +/* get the i2c client device instantiated at the path */ +static struct i2c_client *of_path_to_i2c_client(const char *path) { + struct device_node *np; + struct i2c_client *client; + + np = of_find_node_by_path(path); + if (np == NULL) + return NULL; + + client = of_find_i2c_device_by_node(np); + of_node_put(np); + + return client; +} + +/* find out if a i2c client device exists at that path */ +static int of_path_i2c_client_exists(const char *path) +{ + struct i2c_client *client; + + client = of_path_to_i2c_client(path); + if (client) + put_device(&client->dev); + return client != NULL; +} +#else +static int of_path_i2c_client_exists(const char *path) +{ + return 0; +} +#endif + +enum overlay_type { + PDEV_OVERLAY, + I2C_OVERLAY +}; + +static int of_path_device_type_exists(const char *path, + enum overlay_type ovtype) +{ + switch (ovtype) { + case PDEV_OVERLAY: + return of_path_platform_device_exists(path); + case I2C_OVERLAY: + return of_path_i2c_client_exists(path); + } + return 0; +} + +static const char *selftest_path(int nr, enum overlay_type ovtype) +{ + const char *base; static char buf[256]; - snprintf(buf, sizeof(buf) - 1, - "/testcase-data/overlay-node/test-bus/test-selftest%d", nr); + switch (ovtype) { + case PDEV_OVERLAY: + base = "/testcase-data/overlay-node/test-bus"; + break; + case I2C_OVERLAY: + base = "/testcase-data/overlay-node/test-bus/i2c-test-bus"; + break; + default: + buf[0] = '\0'; + return buf; + } + snprintf(buf, sizeof(buf) - 1, "%s/test-selftest%d", base, nr); buf[sizeof(buf) - 1] = '\0'; - return buf; } +static int of_selftest_device_exists(int selftest_nr, enum overlay_type ovtype) +{ + const char *path; + + path = selftest_path(selftest_nr, ovtype); + + switch (ovtype) { + case PDEV_OVERLAY: + return of_path_platform_device_exists(path); + case I2C_OVERLAY: + return of_path_i2c_client_exists(path); + } + return 0; +} + static const char *overlay_path(int nr) { static char buf[256]; @@ -1090,16 +1115,15 @@ out: /* apply an overlay while checking before and after states */ static int of_selftest_apply_overlay_check(int overlay_nr, int selftest_nr, - int before, int after) + int before, int after, enum overlay_type ovtype) { int ret; /* selftest device must not be in before state */ - if (of_path_platform_device_exists(selftest_path(selftest_nr)) - != before) { + if (of_selftest_device_exists(selftest_nr, ovtype) != before) { selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", overlay_path(overlay_nr), - selftest_path(selftest_nr), + selftest_path(selftest_nr, ovtype), !before ? "enabled" : "disabled"); return -EINVAL; } @@ -1111,11 +1135,10 @@ static int of_selftest_apply_overlay_check(int overlay_nr, int selftest_nr, } /* selftest device must be to set to after state */ - if (of_path_platform_device_exists(selftest_path(selftest_nr)) - != after) { + if (of_selftest_device_exists(selftest_nr, ovtype) != after) { selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n", overlay_path(overlay_nr), - selftest_path(selftest_nr), + selftest_path(selftest_nr, ovtype), !after ? "enabled" : "disabled"); return -EINVAL; } @@ -1125,16 +1148,16 @@ static int of_selftest_apply_overlay_check(int overlay_nr, int selftest_nr, /* apply an overlay and then revert it while checking before, after states */ static int of_selftest_apply_revert_overlay_check(int overlay_nr, - int selftest_nr, int before, int after) + int selftest_nr, int before, int after, + enum overlay_type ovtype) { int ret, ov_id; /* selftest device must be in before state */ - if (of_path_platform_device_exists(selftest_path(selftest_nr)) - != before) { + if (of_selftest_device_exists(selftest_nr, ovtype) != before) { selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", overlay_path(overlay_nr), - selftest_path(selftest_nr), + selftest_path(selftest_nr, ovtype), !before ? "enabled" : "disabled"); return -EINVAL; } @@ -1147,11 +1170,10 @@ static int of_selftest_apply_revert_overlay_check(int overlay_nr, } /* selftest device must be in after state */ - if (of_path_platform_device_exists(selftest_path(selftest_nr)) - != after) { + if (of_selftest_device_exists(selftest_nr, ovtype) != after) { selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n", overlay_path(overlay_nr), - selftest_path(selftest_nr), + selftest_path(selftest_nr, ovtype), !after ? "enabled" : "disabled"); return -EINVAL; } @@ -1160,16 +1182,15 @@ static int of_selftest_apply_revert_overlay_check(int overlay_nr, if (ret != 0) { selftest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n", overlay_path(overlay_nr), - selftest_path(selftest_nr)); + selftest_path(selftest_nr, ovtype)); return ret; } /* selftest device must be again in before state */ - if (of_path_platform_device_exists(selftest_path(selftest_nr)) - != before) { + if (of_selftest_device_exists(selftest_nr, PDEV_OVERLAY) != before) { selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", overlay_path(overlay_nr), - selftest_path(selftest_nr), + selftest_path(selftest_nr, ovtype), !before ? "enabled" : "disabled"); return -EINVAL; } @@ -1183,7 +1204,7 @@ static void of_selftest_overlay_0(void) int ret; /* device should enable */ - ret = of_selftest_apply_overlay_check(0, 0, 0, 1); + ret = of_selftest_apply_overlay_check(0, 0, 0, 1, PDEV_OVERLAY); if (ret != 0) return; @@ -1196,7 +1217,7 @@ static void of_selftest_overlay_1(void) int ret; /* device should disable */ - ret = of_selftest_apply_overlay_check(1, 1, 1, 0); + ret = of_selftest_apply_overlay_check(1, 1, 1, 0, PDEV_OVERLAY); if (ret != 0) return; @@ -1209,7 +1230,7 @@ static void of_selftest_overlay_2(void) int ret; /* device should enable */ - ret = of_selftest_apply_overlay_check(2, 2, 0, 1); + ret = of_selftest_apply_overlay_check(2, 2, 0, 1, PDEV_OVERLAY); if (ret != 0) return; @@ -1222,7 +1243,7 @@ static void of_selftest_overlay_3(void) int ret; /* device should disable */ - ret = of_selftest_apply_overlay_check(3, 3, 1, 0); + ret = of_selftest_apply_overlay_check(3, 3, 1, 0, PDEV_OVERLAY); if (ret != 0) return; @@ -1235,7 +1256,7 @@ static void of_selftest_overlay_4(void) int ret; /* device should disable */ - ret = of_selftest_apply_overlay_check(4, 4, 0, 1); + ret = of_selftest_apply_overlay_check(4, 4, 0, 1, PDEV_OVERLAY); if (ret != 0) return; @@ -1248,7 +1269,7 @@ static void of_selftest_overlay_5(void) int ret; /* device should disable */ - ret = of_selftest_apply_revert_overlay_check(5, 5, 0, 1); + ret = of_selftest_apply_revert_overlay_check(5, 5, 0, 1, PDEV_OVERLAY); if (ret != 0) return; @@ -1265,12 +1286,12 @@ static void of_selftest_overlay_6(void) /* selftest device must be in before state */ for (i = 0; i < 2; i++) { - if (of_path_platform_device_exists( - selftest_path(selftest_nr + i)) + if (of_selftest_device_exists(selftest_nr + i, PDEV_OVERLAY) != before) { selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", overlay_path(overlay_nr + i), - selftest_path(selftest_nr + i), + selftest_path(selftest_nr + i, + PDEV_OVERLAY), !before ? "enabled" : "disabled"); return; } @@ -1297,12 +1318,12 @@ static void of_selftest_overlay_6(void) for (i = 0; i < 2; i++) { /* selftest device must be in after state */ - if (of_path_platform_device_exists( - selftest_path(selftest_nr + i)) + if (of_selftest_device_exists(selftest_nr + i, PDEV_OVERLAY) != after) { selftest(0, "overlay @\"%s\" failed @\"%s\" %s\n", overlay_path(overlay_nr + i), - selftest_path(selftest_nr + i), + selftest_path(selftest_nr + i, + PDEV_OVERLAY), !after ? "enabled" : "disabled"); return; } @@ -1313,19 +1334,20 @@ static void of_selftest_overlay_6(void) if (ret != 0) { selftest(0, "overlay @\"%s\" failed destroy @\"%s\"\n", overlay_path(overlay_nr + i), - selftest_path(selftest_nr + i)); + selftest_path(selftest_nr + i, + PDEV_OVERLAY)); return; } } for (i = 0; i < 2; i++) { /* selftest device must be again in before state */ - if (of_path_platform_device_exists( - selftest_path(selftest_nr + i)) + if (of_selftest_device_exists(selftest_nr + i, PDEV_OVERLAY) != before) { selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n", overlay_path(overlay_nr + i), - selftest_path(selftest_nr + i), + selftest_path(selftest_nr + i, + PDEV_OVERLAY), !before ? "enabled" : "disabled"); return; } @@ -1367,7 +1389,8 @@ static void of_selftest_overlay_8(void) if (ret == 0) { selftest(0, "overlay @\"%s\" was destroyed @\"%s\"\n", overlay_path(overlay_nr + 0), - selftest_path(selftest_nr)); + selftest_path(selftest_nr, + PDEV_OVERLAY)); return; } @@ -1377,7 +1400,8 @@ static void of_selftest_overlay_8(void) if (ret != 0) { selftest(0, "overlay @\"%s\" not destroyed @\"%s\"\n", overlay_path(overlay_nr + i), - selftest_path(selftest_nr)); + selftest_path(selftest_nr, + PDEV_OVERLAY)); return; } } @@ -1385,6 +1409,360 @@ static void of_selftest_overlay_8(void) selftest(1, "overlay test %d passed\n", 8); } +/* test insertion of a bus with parent devices */ +static void of_selftest_overlay_10(void) +{ + int ret; + char *child_path; + + /* device should disable */ + ret = of_selftest_apply_overlay_check(10, 10, 0, 1, PDEV_OVERLAY); + if (selftest(ret == 0, + "overlay test %d failed; overlay application\n", 10)) + return; + + child_path = kasprintf(GFP_KERNEL, "%s/test-selftest101", + selftest_path(10, PDEV_OVERLAY)); + if (selftest(child_path, "overlay test %d failed; kasprintf\n", 10)) + return; + + ret = of_path_device_type_exists(child_path, PDEV_OVERLAY); + kfree(child_path); + if (selftest(ret, "overlay test %d failed; no child device\n", 10)) + return; +} + +/* test insertion of a bus with parent devices (and revert) */ +static void of_selftest_overlay_11(void) +{ + int ret; + + /* device should disable */ + ret = of_selftest_apply_revert_overlay_check(11, 11, 0, 1, + PDEV_OVERLAY); + if (selftest(ret == 0, + "overlay test %d failed; overlay application\n", 11)) + return; +} + +#if IS_ENABLED(CONFIG_I2C) && IS_ENABLED(CONFIG_OF_OVERLAY) + +struct selftest_i2c_bus_data { + struct platform_device *pdev; + struct i2c_adapter adap; +}; + +static int selftest_i2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct selftest_i2c_bus_data *std = i2c_get_adapdata(adap); + + (void)std; + + return num; +} + +static u32 selftest_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm selftest_i2c_algo = { + .master_xfer = selftest_i2c_master_xfer, + .functionality = selftest_i2c_functionality, +}; + +static int selftest_i2c_bus_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct selftest_i2c_bus_data *std; + struct i2c_adapter *adap; + int ret; + + if (np == NULL) { + dev_err(dev, "No OF data for device\n"); + return -EINVAL; + + } + + dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name); + + std = devm_kzalloc(dev, sizeof(*std), GFP_KERNEL); + if (!std) { + dev_err(dev, "Failed to allocate selftest i2c data\n"); + return -ENOMEM; + } + + /* link them together */ + std->pdev = pdev; + platform_set_drvdata(pdev, std); + + adap = &std->adap; + i2c_set_adapdata(adap, std); + adap->nr = -1; + strlcpy(adap->name, pdev->name, sizeof(adap->name)); + adap->class = I2C_CLASS_DEPRECATED; + adap->algo = &selftest_i2c_algo; + adap->dev.parent = dev; + adap->dev.of_node = dev->of_node; + adap->timeout = 5 * HZ; + adap->retries = 3; + + ret = i2c_add_numbered_adapter(adap); + if (ret != 0) { + dev_err(dev, "Failed to add I2C adapter\n"); + return ret; + } + + return 0; +} + +static int selftest_i2c_bus_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct selftest_i2c_bus_data *std = platform_get_drvdata(pdev); + + dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name); + i2c_del_adapter(&std->adap); + + return 0; +} + +static struct of_device_id selftest_i2c_bus_match[] = { + { .compatible = "selftest-i2c-bus", }, + {}, +}; + +static struct platform_driver selftest_i2c_bus_driver = { + .probe = selftest_i2c_bus_probe, + .remove = selftest_i2c_bus_remove, + .driver = { + .name = "selftest-i2c-bus", + .of_match_table = of_match_ptr(selftest_i2c_bus_match), + }, +}; + +static int selftest_i2c_dev_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct device_node *np = client->dev.of_node; + + if (!np) { + dev_err(dev, "No OF node\n"); + return -EINVAL; + } + + dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name); + + return 0; +}; + +static int selftest_i2c_dev_remove(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct device_node *np = client->dev.of_node; + + dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name); + return 0; +} + +static const struct i2c_device_id selftest_i2c_dev_id[] = { + { .name = "selftest-i2c-dev" }, + { } +}; + +static struct i2c_driver selftest_i2c_dev_driver = { + .driver = { + .name = "selftest-i2c-dev", + .owner = THIS_MODULE, + }, + .probe = selftest_i2c_dev_probe, + .remove = selftest_i2c_dev_remove, + .id_table = selftest_i2c_dev_id, +}; + +#if IS_ENABLED(CONFIG_I2C_MUX) + +struct selftest_i2c_mux_data { + int nchans; + struct i2c_adapter *adap[]; +}; + +static int selftest_i2c_mux_select_chan(struct i2c_adapter *adap, + void *client, u32 chan) +{ + return 0; +} + +static int selftest_i2c_mux_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret, i, nchans, size; + struct device *dev = &client->dev; + struct i2c_adapter *adap = to_i2c_adapter(dev->parent); + struct device_node *np = client->dev.of_node, *child; + struct selftest_i2c_mux_data *stm; + u32 reg, max_reg; + + dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name); + + if (!np) { + dev_err(dev, "No OF node\n"); + return -EINVAL; + } + + max_reg = (u32)-1; + for_each_child_of_node(np, child) { + ret = of_property_read_u32(child, "reg", ®); + if (ret) + continue; + if (max_reg == (u32)-1 || reg > max_reg) + max_reg = reg; + } + nchans = max_reg == (u32)-1 ? 0 : max_reg + 1; + if (nchans == 0) { + dev_err(dev, "No channels\n"); + return -EINVAL; + } + + size = offsetof(struct selftest_i2c_mux_data, adap[nchans]); + stm = devm_kzalloc(dev, size, GFP_KERNEL); + if (!stm) { + dev_err(dev, "Out of memory\n"); + return -ENOMEM; + } + stm->nchans = nchans; + for (i = 0; i < nchans; i++) { + stm->adap[i] = i2c_add_mux_adapter(adap, dev, client, + 0, i, 0, selftest_i2c_mux_select_chan, NULL); + if (!stm->adap[i]) { + dev_err(dev, "Failed to register mux #%d\n", i); + for (i--; i >= 0; i--) + i2c_del_mux_adapter(stm->adap[i]); + return -ENODEV; + } + } + + i2c_set_clientdata(client, stm); + + return 0; +}; + +static int selftest_i2c_mux_remove(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct device_node *np = client->dev.of_node; + struct selftest_i2c_mux_data *stm = i2c_get_clientdata(client); + int i; + + dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name); + for (i = stm->nchans - 1; i >= 0; i--) + i2c_del_mux_adapter(stm->adap[i]); + return 0; +} + +static const struct i2c_device_id selftest_i2c_mux_id[] = { + { .name = "selftest-i2c-mux" }, + { } +}; + +static struct i2c_driver selftest_i2c_mux_driver = { + .driver = { + .name = "selftest-i2c-mux", + .owner = THIS_MODULE, + }, + .probe = selftest_i2c_mux_probe, + .remove = selftest_i2c_mux_remove, + .id_table = selftest_i2c_mux_id, +}; + +#endif + +static int of_selftest_overlay_i2c_init(void) +{ + int ret; + + ret = i2c_add_driver(&selftest_i2c_dev_driver); + if (selftest(ret == 0, + "could not register selftest i2c device driver\n")) + return ret; + + ret = platform_driver_register(&selftest_i2c_bus_driver); + if (selftest(ret == 0, + "could not register selftest i2c bus driver\n")) + return ret; + +#if IS_ENABLED(CONFIG_I2C_MUX) + ret = i2c_add_driver(&selftest_i2c_mux_driver); + if (selftest(ret == 0, + "could not register selftest i2c mux driver\n")) + return ret; +#endif + + return 0; +} + +static void of_selftest_overlay_i2c_cleanup(void) +{ +#if IS_ENABLED(CONFIG_I2C_MUX) + i2c_del_driver(&selftest_i2c_mux_driver); +#endif + platform_driver_unregister(&selftest_i2c_bus_driver); + i2c_del_driver(&selftest_i2c_dev_driver); +} + +static void of_selftest_overlay_i2c_12(void) +{ + int ret; + + /* device should enable */ + ret = of_selftest_apply_overlay_check(12, 12, 0, 1, I2C_OVERLAY); + if (ret != 0) + return; + + selftest(1, "overlay test %d passed\n", 12); +} + +/* test deactivation of device */ +static void of_selftest_overlay_i2c_13(void) +{ + int ret; + + /* device should disable */ + ret = of_selftest_apply_overlay_check(13, 13, 1, 0, I2C_OVERLAY); + if (ret != 0) + return; + + selftest(1, "overlay test %d passed\n", 13); +} + +/* just check for i2c mux existence */ +static void of_selftest_overlay_i2c_14(void) +{ +} + +static void of_selftest_overlay_i2c_15(void) +{ + int ret; + + /* device should enable */ + ret = of_selftest_apply_overlay_check(16, 15, 0, 1, I2C_OVERLAY); + if (ret != 0) + return; + + selftest(1, "overlay test %d passed\n", 15); +} + +#else + +static inline void of_selftest_overlay_i2c_14(void) { } +static inline void of_selftest_overlay_i2c_15(void) { } + +#endif + static void __init of_selftest_overlay(void) { struct device_node *bus_np = NULL; @@ -1409,15 +1787,15 @@ static void __init of_selftest_overlay(void) goto out; } - if (!of_path_platform_device_exists(selftest_path(100))) { + if (!of_selftest_device_exists(100, PDEV_OVERLAY)) { selftest(0, "could not find selftest0 @ \"%s\"\n", - selftest_path(100)); + selftest_path(100, PDEV_OVERLAY)); goto out; } - if (of_path_platform_device_exists(selftest_path(101))) { + if (of_selftest_device_exists(101, PDEV_OVERLAY)) { selftest(0, "selftest1 @ \"%s\" should not exist\n", - selftest_path(101)); + selftest_path(101, PDEV_OVERLAY)); goto out; } @@ -1433,6 +1811,21 @@ static void __init of_selftest_overlay(void) of_selftest_overlay_6(); of_selftest_overlay_8(); + of_selftest_overlay_10(); + of_selftest_overlay_11(); + +#if IS_ENABLED(CONFIG_I2C) + if (selftest(of_selftest_overlay_i2c_init() == 0, "i2c init failed\n")) + goto out; + + of_selftest_overlay_i2c_12(); + of_selftest_overlay_i2c_13(); + of_selftest_overlay_i2c_14(); + of_selftest_overlay_i2c_15(); + + of_selftest_overlay_i2c_cleanup(); +#endif + out: of_node_put(bus_np); } @@ -1475,9 +1868,6 @@ static int __init of_selftest(void) of_selftest_platform_populate(); of_selftest_overlay(); - /* removing selftest data from live tree */ - selftest_data_remove(); - /* Double check linkage after removing testcase data */ of_selftest_check_tree_linkage(); diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 37e71ff6408d..dceb9ddfd99a 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -694,9 +694,8 @@ lba_fixup_bus(struct pci_bus *bus) int i; /* PCI-PCI Bridge */ pci_read_bridge_bases(bus); - for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) { - pci_claim_resource(bus->self, i); - } + for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) + pci_claim_bridge_resource(bus->self, i); } else { /* Host-PCI Bridge */ int err; diff --git a/drivers/parport/parport_atari.c b/drivers/parport/parport_atari.c index 7ad59ac68cf6..a81cd2a2747f 100644 --- a/drivers/parport/parport_atari.c +++ b/drivers/parport/parport_atari.c @@ -192,8 +192,8 @@ static int __init parport_atari_init(void) &parport_atari_ops); if (!p) return -ENODEV; - if (request_irq(IRQ_MFP_BUSY, parport_irq_handler, - IRQ_TYPE_SLOW, p->name, p)) { + if (request_irq(IRQ_MFP_BUSY, parport_irq_handler, 0, p->name, + p)) { parport_put_port (p); return -ENODEV; } diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 49dd766852ba..d9b64a175990 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -67,6 +67,93 @@ EXPORT_SYMBOL(pci_bus_write_config_byte); EXPORT_SYMBOL(pci_bus_write_config_word); EXPORT_SYMBOL(pci_bus_write_config_dword); +int pci_generic_config_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + void __iomem *addr; + + addr = bus->ops->map_bus(bus, devfn, where); + if (!addr) { + *val = ~0; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + if (size == 1) + *val = readb(addr); + else if (size == 2) + *val = readw(addr); + else + *val = readl(addr); + + return PCIBIOS_SUCCESSFUL; +} +EXPORT_SYMBOL_GPL(pci_generic_config_read); + +int pci_generic_config_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + void __iomem *addr; + + addr = bus->ops->map_bus(bus, devfn, where); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (size == 1) + writeb(val, addr); + else if (size == 2) + writew(val, addr); + else + writel(val, addr); + + return PCIBIOS_SUCCESSFUL; +} +EXPORT_SYMBOL_GPL(pci_generic_config_write); + +int pci_generic_config_read32(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + void __iomem *addr; + + addr = bus->ops->map_bus(bus, devfn, where & ~0x3); + if (!addr) { + *val = ~0; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + *val = readl(addr); + + if (size <= 2) + *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1); + + return PCIBIOS_SUCCESSFUL; +} +EXPORT_SYMBOL_GPL(pci_generic_config_read32); + +int pci_generic_config_write32(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + void __iomem *addr; + u32 mask, tmp; + + addr = bus->ops->map_bus(bus, devfn, where & ~0x3); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (size == 4) { + writel(val, addr); + return PCIBIOS_SUCCESSFUL; + } else { + mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); + } + + tmp = readl(addr) & mask; + tmp |= val << ((where & 0x3) * 8); + writel(tmp, addr); + + return PCIBIOS_SUCCESSFUL; +} +EXPORT_SYMBOL_GPL(pci_generic_config_write32); + /** * pci_bus_set_ops - Set raw operations of pci bus * @bus: pci bus struct diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 73aef51a28f0..90fa3a78fb7c 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -20,17 +20,16 @@ void pci_add_resource_offset(struct list_head *resources, struct resource *res, resource_size_t offset) { - struct pci_host_bridge_window *window; + struct resource_entry *entry; - window = kzalloc(sizeof(struct pci_host_bridge_window), GFP_KERNEL); - if (!window) { + entry = resource_list_create_entry(res, 0); + if (!entry) { printk(KERN_ERR "PCI: can't add host bridge window %pR\n", res); return; } - window->res = res; - window->offset = offset; - list_add_tail(&window->list, resources); + entry->offset = offset; + resource_list_add_tail(entry, resources); } EXPORT_SYMBOL(pci_add_resource_offset); @@ -42,12 +41,7 @@ EXPORT_SYMBOL(pci_add_resource); void pci_free_resource_list(struct list_head *resources) { - struct pci_host_bridge_window *window, *tmp; - - list_for_each_entry_safe(window, tmp, resources, list) { - list_del(&window->list); - kfree(window); - } + resource_list_free(resources); } EXPORT_SYMBOL(pci_free_resource_list); @@ -228,6 +222,49 @@ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, } EXPORT_SYMBOL(pci_bus_alloc_resource); +/* + * The @idx resource of @dev should be a PCI-PCI bridge window. If this + * resource fits inside a window of an upstream bridge, do nothing. If it + * overlaps an upstream window but extends outside it, clip the resource so + * it fits completely inside. + */ +bool pci_bus_clip_resource(struct pci_dev *dev, int idx) +{ + struct pci_bus *bus = dev->bus; + struct resource *res = &dev->resource[idx]; + struct resource orig_res = *res; + struct resource *r; + int i; + + pci_bus_for_each_resource(bus, r, i) { + resource_size_t start, end; + + if (!r) + continue; + + if (resource_type(res) != resource_type(r)) + continue; + + start = max(r->start, res->start); + end = min(r->end, res->end); + + if (start > end) + continue; /* no overlap */ + + if (res->start == start && res->end == end) + return false; /* no change */ + + res->start = start; + res->end = end; + dev_printk(KERN_DEBUG, &dev->dev, "%pR clipped to %pR\n", + &orig_res, res); + + return true; + } + + return false; +} + void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { } /** diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c index 0e5f3c95af5b..39b2dbe585aa 100644 --- a/drivers/pci/host-bridge.c +++ b/drivers/pci/host-bridge.c @@ -35,10 +35,10 @@ void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region, struct resource *res) { struct pci_host_bridge *bridge = find_pci_host_bridge(bus); - struct pci_host_bridge_window *window; + struct resource_entry *window; resource_size_t offset = 0; - list_for_each_entry(window, &bridge->windows, list) { + resource_list_for_each_entry(window, &bridge->windows) { if (resource_contains(window->res, res)) { offset = window->offset; break; @@ -60,10 +60,10 @@ void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res, struct pci_bus_region *region) { struct pci_host_bridge *bridge = find_pci_host_bridge(bus); - struct pci_host_bridge_window *window; + struct resource_entry *window; resource_size_t offset = 0; - list_for_each_entry(window, &bridge->windows, list) { + resource_list_for_each_entry(window, &bridge->windows) { struct pci_bus_region bus_region; if (resource_type(res) != resource_type(window->res)) diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index c4b6568e486d..7b892a9cc4fc 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -102,4 +102,8 @@ config PCI_LAYERSCAPE help Say Y here if you want PCIe controller support on Layerscape SoCs. +config PCI_VERSATILE + bool "ARM Versatile PB PCI controller" + depends on ARCH_VERSATILE + endmenu diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 44c26998027f..e61d91c92bf1 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o obj-$(CONFIG_PCI_XGENE) += pci-xgene.o obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o +obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c index 6eb1aa75bd37..ba46e581db99 100644 --- a/drivers/pci/host/pci-host-generic.c +++ b/drivers/pci/host/pci-host-generic.c @@ -76,55 +76,9 @@ static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops = { .map_bus = gen_pci_map_cfg_bus_ecam, }; -static int gen_pci_config_read(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *val) -{ - void __iomem *addr; - struct pci_sys_data *sys = bus->sysdata; - struct gen_pci *pci = sys->private_data; - - addr = pci->cfg.ops->map_bus(bus, devfn, where); - - switch (size) { - case 1: - *val = readb(addr); - break; - case 2: - *val = readw(addr); - break; - default: - *val = readl(addr); - } - - return PCIBIOS_SUCCESSFUL; -} - -static int gen_pci_config_write(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val) -{ - void __iomem *addr; - struct pci_sys_data *sys = bus->sysdata; - struct gen_pci *pci = sys->private_data; - - addr = pci->cfg.ops->map_bus(bus, devfn, where); - - switch (size) { - case 1: - writeb(val, addr); - break; - case 2: - writew(val, addr); - break; - default: - writel(val, addr); - } - - return PCIBIOS_SUCCESSFUL; -} - static struct pci_ops gen_pci_ops = { - .read = gen_pci_config_read, - .write = gen_pci_config_write, + .read = pci_generic_config_read, + .write = pci_generic_config_write, }; static const struct of_device_id gen_pci_of_match[] = { @@ -149,14 +103,14 @@ static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci) struct device *dev = pci->host.dev.parent; struct device_node *np = dev->of_node; resource_size_t iobase; - struct pci_host_bridge_window *win; + struct resource_entry *win; err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources, &iobase); if (err) return err; - list_for_each_entry(win, &pci->resources, list) { + resource_list_for_each_entry(win, &pci->resources) { struct resource *parent, *res = win->res; switch (resource_type(res)) { @@ -287,6 +241,7 @@ static int gen_pci_probe(struct platform_device *pdev) of_id = of_match_node(gen_pci_of_match, np); pci->cfg.ops = of_id->data; + gen_pci_ops.map_bus = pci->cfg.ops->map_bus; pci->host.dev.parent = dev; INIT_LIST_HEAD(&pci->host.windows); INIT_LIST_HEAD(&pci->resources); diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c index 78f79e31ac5c..75333b0c4f0a 100644 --- a/drivers/pci/host/pci-keystone.c +++ b/drivers/pci/host/pci-keystone.c @@ -119,7 +119,7 @@ static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc) struct pcie_port *pp = &ks_pcie->pp; struct irq_chip *chip = irq_desc_get_chip(desc); - dev_dbg(pp->dev, "ks_pci_msi_irq_handler, irq %d\n", irq); + dev_dbg(pp->dev, "%s, irq %d\n", __func__, irq); /* * The chained irq handler installation would have replaced normal @@ -197,7 +197,7 @@ static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie, */ for (temp = 0; temp < max_host_irqs; temp++) { host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp); - if (host_irqs[temp] < 0) + if (!host_irqs[temp]) break; } if (temp) { diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c index 6697b1a4d4fa..68c9e5e9b0a8 100644 --- a/drivers/pci/host/pci-layerscape.c +++ b/drivers/pci/host/pci-layerscape.c @@ -167,7 +167,6 @@ MODULE_DEVICE_TABLE(of, ls_pcie_of_match); static struct platform_driver ls_pcie_driver = { .driver = { .name = "layerscape-pcie", - .owner = THIS_MODULE, .of_match_table = ls_pcie_of_match, }, }; diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 1dd759596b0a..1309cfbaa719 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -101,9 +101,7 @@ struct mvebu_pcie { struct mvebu_pcie_port *ports; struct msi_controller *msi; struct resource io; - char io_name[30]; struct resource realio; - char mem_name[30]; struct resource mem; struct resource busn; int nports; @@ -723,18 +721,9 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys) { struct mvebu_pcie *pcie = sys_to_pcie(sys); int i; - int domain = 0; -#ifdef CONFIG_PCI_DOMAINS - domain = sys->domain; -#endif - - snprintf(pcie->mem_name, sizeof(pcie->mem_name), "PCI MEM %04x", - domain); - pcie->mem.name = pcie->mem_name; - - snprintf(pcie->io_name, sizeof(pcie->io_name), "PCI I/O %04x", domain); - pcie->realio.name = pcie->io_name; + pcie->mem.name = "PCI MEM"; + pcie->realio.name = "PCI I/O"; if (request_resource(&iomem_resource, &pcie->mem)) return 0; diff --git a/drivers/pci/host/pci-rcar-gen2.c b/drivers/pci/host/pci-rcar-gen2.c index d9c042febb1a..dd6b84e6206c 100644 --- a/drivers/pci/host/pci-rcar-gen2.c +++ b/drivers/pci/host/pci-rcar-gen2.c @@ -131,52 +131,6 @@ static void __iomem *rcar_pci_cfg_base(struct pci_bus *bus, unsigned int devfn, return priv->reg + (slot >> 1) * 0x100 + where; } -static int rcar_pci_read_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *val) -{ - void __iomem *reg = rcar_pci_cfg_base(bus, devfn, where); - - if (!reg) - return PCIBIOS_DEVICE_NOT_FOUND; - - switch (size) { - case 1: - *val = ioread8(reg); - break; - case 2: - *val = ioread16(reg); - break; - default: - *val = ioread32(reg); - break; - } - - return PCIBIOS_SUCCESSFUL; -} - -static int rcar_pci_write_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val) -{ - void __iomem *reg = rcar_pci_cfg_base(bus, devfn, where); - - if (!reg) - return PCIBIOS_DEVICE_NOT_FOUND; - - switch (size) { - case 1: - iowrite8(val, reg); - break; - case 2: - iowrite16(val, reg); - break; - default: - iowrite32(val, reg); - break; - } - - return PCIBIOS_SUCCESSFUL; -} - /* PCI interrupt mapping */ static int rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { @@ -325,8 +279,9 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys) } static struct pci_ops rcar_pci_ops = { - .read = rcar_pci_read_config, - .write = rcar_pci_write_config, + .map_bus = rcar_pci_cfg_base, + .read = pci_generic_config_read, + .write = pci_generic_config_write, }; static int rcar_pci_probe(struct platform_device *pdev) diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index a800ae916394..00e92720d7f7 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -480,59 +480,10 @@ static void __iomem *tegra_pcie_conf_address(struct pci_bus *bus, return addr; } -static int tegra_pcie_read_conf(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *value) -{ - void __iomem *addr; - - addr = tegra_pcie_conf_address(bus, devfn, where); - if (!addr) { - *value = 0xffffffff; - return PCIBIOS_DEVICE_NOT_FOUND; - } - - *value = readl(addr); - - if (size == 1) - *value = (*value >> (8 * (where & 3))) & 0xff; - else if (size == 2) - *value = (*value >> (8 * (where & 3))) & 0xffff; - - return PCIBIOS_SUCCESSFUL; -} - -static int tegra_pcie_write_conf(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 value) -{ - void __iomem *addr; - u32 mask, tmp; - - addr = tegra_pcie_conf_address(bus, devfn, where); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - - if (size == 4) { - writel(value, addr); - return PCIBIOS_SUCCESSFUL; - } - - if (size == 2) - mask = ~(0xffff << ((where & 0x3) * 8)); - else if (size == 1) - mask = ~(0xff << ((where & 0x3) * 8)); - else - return PCIBIOS_BAD_REGISTER_NUMBER; - - tmp = readl(addr) & mask; - tmp |= value << ((where & 0x3) * 8); - writel(tmp, addr); - - return PCIBIOS_SUCCESSFUL; -} - static struct pci_ops tegra_pcie_ops = { - .read = tegra_pcie_read_conf, - .write = tegra_pcie_write_conf, + .map_bus = tegra_pcie_conf_address, + .read = pci_generic_config_read32, + .write = pci_generic_config_write32, }; static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port) @@ -625,19 +576,6 @@ static void tegra_pcie_port_free(struct tegra_pcie_port *port) devm_kfree(pcie->dev, port); } -static void tegra_pcie_fixup_bridge(struct pci_dev *dev) -{ - u16 reg; - - if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) { - pci_read_config_word(dev, PCI_COMMAND, ®); - reg |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | PCI_COMMAND_SERR); - pci_write_config_word(dev, PCI_COMMAND, reg); - } -} -DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_fixup_bridge); - /* Tegra PCIE root complex wrongly reports device class */ static void tegra_pcie_fixup_class(struct pci_dev *dev) { diff --git a/drivers/pci/host/pci-versatile.c b/drivers/pci/host/pci-versatile.c new file mode 100644 index 000000000000..1ec694a52379 --- /dev/null +++ b/drivers/pci/host/pci-versatile.c @@ -0,0 +1,237 @@ +/* + * Copyright 2004 Koninklijke Philips Electronics NV + * + * Conversion to platform driver and DT: + * Copyright 2014 Linaro Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 14/04/2005 Initial version, colin.king@philips.com + */ +#include +#include +#include +#include +#include +#include +#include + +static void __iomem *versatile_pci_base; +static void __iomem *versatile_cfg_base[2]; + +#define PCI_IMAP(m) (versatile_pci_base + ((m) * 4)) +#define PCI_SMAP(m) (versatile_pci_base + 0x14 + ((m) * 4)) +#define PCI_SELFID (versatile_pci_base + 0xc) + +#define VP_PCI_DEVICE_ID 0x030010ee +#define VP_PCI_CLASS_ID 0x0b400000 + +static u32 pci_slot_ignore; + +static int __init versatile_pci_slot_ignore(char *str) +{ + int retval; + int slot; + + while ((retval = get_option(&str, &slot))) { + if ((slot < 0) || (slot > 31)) + pr_err("Illegal slot value: %d\n", slot); + else + pci_slot_ignore |= (1 << slot); + } + return 1; +} +__setup("pci_slot_ignore=", versatile_pci_slot_ignore); + + +static void __iomem *versatile_map_bus(struct pci_bus *bus, + unsigned int devfn, int offset) +{ + unsigned int busnr = bus->number; + + if (pci_slot_ignore & (1 << PCI_SLOT(devfn))) + return NULL; + + return versatile_cfg_base[1] + ((busnr << 16) | (devfn << 8) | offset); +} + +static struct pci_ops pci_versatile_ops = { + .map_bus = versatile_map_bus, + .read = pci_generic_config_read32, + .write = pci_generic_config_write, +}; + +static int versatile_pci_parse_request_of_pci_ranges(struct device *dev, + struct list_head *res) +{ + int err, mem = 1, res_valid = 0; + struct device_node *np = dev->of_node; + resource_size_t iobase; + struct resource_entry *win; + + err = of_pci_get_host_bridge_resources(np, 0, 0xff, res, &iobase); + if (err) + return err; + + resource_list_for_each_entry(win, res, list) { + struct resource *parent, *res = win->res; + + switch (resource_type(res)) { + case IORESOURCE_IO: + parent = &ioport_resource; + err = pci_remap_iospace(res, iobase); + if (err) { + dev_warn(dev, "error %d: failed to map resource %pR\n", + err, res); + continue; + } + break; + case IORESOURCE_MEM: + parent = &iomem_resource; + res_valid |= !(res->flags & IORESOURCE_PREFETCH); + + writel(res->start >> 28, PCI_IMAP(mem)); + writel(PHYS_OFFSET >> 28, PCI_SMAP(mem)); + mem++; + + break; + case IORESOURCE_BUS: + default: + continue; + } + + err = devm_request_resource(dev, parent, res); + if (err) + goto out_release_res; + } + + if (!res_valid) { + dev_err(dev, "non-prefetchable memory resource required\n"); + err = -EINVAL; + goto out_release_res; + } + + return 0; + +out_release_res: + pci_free_resource_list(res); + return err; +} + +/* Unused, temporary to satisfy ARM arch code */ +struct pci_sys_data sys; + +static int versatile_pci_probe(struct platform_device *pdev) +{ + struct resource *res; + int ret, i, myslot = -1; + u32 val; + void __iomem *local_pci_cfg_base; + struct pci_bus *bus; + LIST_HEAD(pci_res); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + versatile_pci_base = devm_ioremap_resource(&pdev->dev, res); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) + return -ENODEV; + versatile_cfg_base[0] = devm_ioremap_resource(&pdev->dev, res); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + if (!res) + return -ENODEV; + versatile_cfg_base[1] = devm_ioremap_resource(&pdev->dev, res); + + ret = versatile_pci_parse_request_of_pci_ranges(&pdev->dev, &pci_res); + if (ret) + return ret; + + /* + * We need to discover the PCI core first to configure itself + * before the main PCI probing is performed + */ + for (i = 0; i < 32; i++) { + if ((readl(versatile_cfg_base[0] + (i << 11) + PCI_VENDOR_ID) == VP_PCI_DEVICE_ID) && + (readl(versatile_cfg_base[0] + (i << 11) + PCI_CLASS_REVISION) == VP_PCI_CLASS_ID)) { + myslot = i; + break; + } + } + if (myslot == -1) { + dev_err(&pdev->dev, "Cannot find PCI core!\n"); + return -EIO; + } + /* + * Do not to map Versatile FPGA PCI device into memory space + */ + pci_slot_ignore |= (1 << myslot); + + dev_info(&pdev->dev, "PCI core found (slot %d)\n", myslot); + + writel(myslot, PCI_SELFID); + local_pci_cfg_base = versatile_cfg_base[1] + (myslot << 11); + + val = readl(local_pci_cfg_base + PCI_COMMAND); + val |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; + writel(val, local_pci_cfg_base + PCI_COMMAND); + + /* + * Configure the PCI inbound memory windows to be 1:1 mapped to SDRAM + */ + writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_0); + writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_1); + writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_2); + + /* + * For many years the kernel and QEMU were symbiotically buggy + * in that they both assumed the same broken IRQ mapping. + * QEMU therefore attempts to auto-detect old broken kernels + * so that they still work on newer QEMU as they did on old + * QEMU. Since we now use the correct (ie matching-hardware) + * IRQ mapping we write a definitely different value to a + * PCI_INTERRUPT_LINE register to tell QEMU that we expect + * real hardware behaviour and it need not be backwards + * compatible for us. This write is harmless on real hardware. + */ + writel(0, versatile_cfg_base[0] + PCI_INTERRUPT_LINE); + + pci_add_flags(PCI_ENABLE_PROC_DOMAINS); + pci_add_flags(PCI_REASSIGN_ALL_BUS | PCI_REASSIGN_ALL_RSRC); + + bus = pci_scan_root_bus(&pdev->dev, 0, &pci_versatile_ops, &sys, &pci_res); + if (!bus) + return -ENOMEM; + + pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); + pci_assign_unassigned_bus_resources(bus); + + return 0; +} + +static const struct of_device_id versatile_pci_of_match[] = { + { .compatible = "arm,versatile-pci", }, + { }, +}; +MODULE_DEVICE_TABLE(of, versatile_pci_of_match); + +static struct platform_driver versatile_pci_driver = { + .driver = { + .name = "versatile-pci", + .of_match_table = versatile_pci_of_match, + }, + .probe = versatile_pci_probe, +}; +module_platform_driver(versatile_pci_driver); + +MODULE_DESCRIPTION("Versatile PCI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c index b1d0596457c5..aab55474dd0d 100644 --- a/drivers/pci/host/pci-xgene.c +++ b/drivers/pci/host/pci-xgene.c @@ -16,7 +16,7 @@ * GNU General Public License for more details. * */ -#include +#include #include #include #include @@ -74,92 +74,6 @@ static inline u32 pcie_bar_low_val(u32 addr, u32 flags) return (addr & PCI_BASE_ADDRESS_MEM_MASK) | flags; } -/* PCIe Configuration Out/In */ -static inline void xgene_pcie_cfg_out32(void __iomem *addr, int offset, u32 val) -{ - writel(val, addr + offset); -} - -static inline void xgene_pcie_cfg_out16(void __iomem *addr, int offset, u16 val) -{ - u32 val32 = readl(addr + (offset & ~0x3)); - - switch (offset & 0x3) { - case 2: - val32 &= ~0xFFFF0000; - val32 |= (u32)val << 16; - break; - case 0: - default: - val32 &= ~0xFFFF; - val32 |= val; - break; - } - writel(val32, addr + (offset & ~0x3)); -} - -static inline void xgene_pcie_cfg_out8(void __iomem *addr, int offset, u8 val) -{ - u32 val32 = readl(addr + (offset & ~0x3)); - - switch (offset & 0x3) { - case 0: - val32 &= ~0xFF; - val32 |= val; - break; - case 1: - val32 &= ~0xFF00; - val32 |= (u32)val << 8; - break; - case 2: - val32 &= ~0xFF0000; - val32 |= (u32)val << 16; - break; - case 3: - default: - val32 &= ~0xFF000000; - val32 |= (u32)val << 24; - break; - } - writel(val32, addr + (offset & ~0x3)); -} - -static inline void xgene_pcie_cfg_in32(void __iomem *addr, int offset, u32 *val) -{ - *val = readl(addr + offset); -} - -static inline void xgene_pcie_cfg_in16(void __iomem *addr, int offset, u32 *val) -{ - *val = readl(addr + (offset & ~0x3)); - - switch (offset & 0x3) { - case 2: - *val >>= 16; - break; - } - - *val &= 0xFFFF; -} - -static inline void xgene_pcie_cfg_in8(void __iomem *addr, int offset, u32 *val) -{ - *val = readl(addr + (offset & ~0x3)); - - switch (offset & 0x3) { - case 3: - *val = *val >> 24; - break; - case 2: - *val = *val >> 16; - break; - case 1: - *val = *val >> 8; - break; - } - *val &= 0xFF; -} - /* * When the address bit [17:16] is 2'b01, the Configuration access will be * treated as Type 1 and it will be forwarded to external PCIe device. @@ -213,69 +127,23 @@ static bool xgene_pcie_hide_rc_bars(struct pci_bus *bus, int offset) return false; } -static int xgene_pcie_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) +static int xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, + int offset) { struct xgene_pcie_port *port = bus->sysdata; - void __iomem *addr; - if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up) - return PCIBIOS_DEVICE_NOT_FOUND; - - if (xgene_pcie_hide_rc_bars(bus, offset)) { - *val = 0; - return PCIBIOS_SUCCESSFUL; - } + if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up || + xgene_pcie_hide_rc_bars(bus, offset)) + return NULL; xgene_pcie_set_rtdid_reg(bus, devfn); - addr = xgene_pcie_get_cfg_base(bus); - switch (len) { - case 1: - xgene_pcie_cfg_in8(addr, offset, val); - break; - case 2: - xgene_pcie_cfg_in16(addr, offset, val); - break; - default: - xgene_pcie_cfg_in32(addr, offset, val); - break; - } - - return PCIBIOS_SUCCESSFUL; -} - -static int xgene_pcie_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct xgene_pcie_port *port = bus->sysdata; - void __iomem *addr; - - if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up) - return PCIBIOS_DEVICE_NOT_FOUND; - - if (xgene_pcie_hide_rc_bars(bus, offset)) - return PCIBIOS_SUCCESSFUL; - - xgene_pcie_set_rtdid_reg(bus, devfn); - addr = xgene_pcie_get_cfg_base(bus); - switch (len) { - case 1: - xgene_pcie_cfg_out8(addr, offset, (u8)val); - break; - case 2: - xgene_pcie_cfg_out16(addr, offset, (u16)val); - break; - default: - xgene_pcie_cfg_out32(addr, offset, val); - break; - } - - return PCIBIOS_SUCCESSFUL; + return xgene_pcie_get_cfg_base(bus); } static struct pci_ops xgene_pcie_ops = { - .read = xgene_pcie_read_config, - .write = xgene_pcie_write_config + .map_bus = xgene_pcie_map_bus, + .read = pci_generic_config_read32, + .write = pci_generic_config_write32, }; static u64 xgene_pcie_set_ib_mask(void __iomem *csr_base, u32 addr, @@ -401,11 +269,11 @@ static int xgene_pcie_map_ranges(struct xgene_pcie_port *port, struct list_head *res, resource_size_t io_base) { - struct pci_host_bridge_window *window; + struct resource_entry *window; struct device *dev = port->dev; int ret; - list_for_each_entry(window, res, list) { + resource_list_for_each_entry(window, res) { struct resource *res = window->res; u64 restype = resource_type(res); diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index df781cdf13c1..1f4ea6f2d910 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -283,6 +283,9 @@ static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev, struct msi_msg msg; struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata); + if (desc->msi_attrib.is_msix) + return -EINVAL; + irq = assign_irq(1, desc, &pos); if (irq < 0) return irq; @@ -508,9 +511,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp) dw_pci.private_data = (void **)&pp; pci_common_init_dev(pp->dev, &dw_pci); -#ifdef CONFIG_PCI_DOMAINS - dw_pci.domain++; -#endif return 0; } diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c index 748786c402fc..c57bd0ac39a0 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/host/pcie-rcar.c @@ -397,9 +397,6 @@ static void rcar_pcie_enable(struct rcar_pcie *pcie) #endif pci_common_init_dev(&pdev->dev, &rcar_pci); -#ifdef CONFIG_PCI_DOMAINS - rcar_pci.domain++; -#endif } static int phy_wait_for_ack(struct rcar_pcie *pcie) @@ -757,7 +754,7 @@ static int rcar_pcie_get_resources(struct platform_device *pdev, goto err_map_reg; i = irq_of_parse_and_map(pdev->dev.of_node, 0); - if (i < 0) { + if (!i) { dev_err(pcie->dev, "cannot get platform resources for msi interrupt\n"); err = -ENOENT; goto err_map_reg; @@ -765,7 +762,7 @@ static int rcar_pcie_get_resources(struct platform_device *pdev, pcie->msi.irq1 = i; i = irq_of_parse_and_map(pdev->dev.of_node, 1); - if (i < 0) { + if (!i) { dev_err(pcie->dev, "cannot get platform resources for msi interrupt\n"); err = -ENOENT; goto err_map_reg; diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c index ef3ebaf9a738..f1a06a091ccb 100644 --- a/drivers/pci/host/pcie-xilinx.c +++ b/drivers/pci/host/pcie-xilinx.c @@ -148,10 +148,10 @@ static inline bool xilinx_pcie_link_is_up(struct xilinx_pcie_port *port) */ static void xilinx_pcie_clear_err_interrupts(struct xilinx_pcie_port *port) { - u32 val = pcie_read(port, XILINX_PCIE_REG_RPEFR); + unsigned long val = pcie_read(port, XILINX_PCIE_REG_RPEFR); if (val & XILINX_PCIE_RPEFR_ERR_VALID) { - dev_dbg(port->dev, "Requester ID %d\n", + dev_dbg(port->dev, "Requester ID %lu\n", val & XILINX_PCIE_RPEFR_REQ_ID); pcie_write(port, XILINX_PCIE_RPEFR_ALL_MASK, XILINX_PCIE_REG_RPEFR); @@ -189,7 +189,7 @@ static bool xilinx_pcie_valid_device(struct pci_bus *bus, unsigned int devfn) } /** - * xilinx_pcie_config_base - Get configuration base + * xilinx_pcie_map_bus - Get configuration base * @bus: PCI Bus structure * @devfn: Device/function * @where: Offset from base @@ -197,96 +197,26 @@ static bool xilinx_pcie_valid_device(struct pci_bus *bus, unsigned int devfn) * Return: Base address of the configuration space needed to be * accessed. */ -static void __iomem *xilinx_pcie_config_base(struct pci_bus *bus, - unsigned int devfn, int where) +static void __iomem *xilinx_pcie_map_bus(struct pci_bus *bus, + unsigned int devfn, int where) { struct xilinx_pcie_port *port = sys_to_pcie(bus->sysdata); int relbus; + if (!xilinx_pcie_valid_device(bus, devfn)) + return NULL; + relbus = (bus->number << ECAM_BUS_NUM_SHIFT) | (devfn << ECAM_DEV_NUM_SHIFT); return port->reg_base + relbus + where; } -/** - * xilinx_pcie_read_config - Read configuration space - * @bus: PCI Bus structure - * @devfn: Device/function - * @where: Offset from base - * @size: Byte/word/dword - * @val: Value to be read - * - * Return: PCIBIOS_SUCCESSFUL on success - * PCIBIOS_DEVICE_NOT_FOUND on failure - */ -static int xilinx_pcie_read_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *val) -{ - void __iomem *addr; - - if (!xilinx_pcie_valid_device(bus, devfn)) { - *val = 0xFFFFFFFF; - return PCIBIOS_DEVICE_NOT_FOUND; - } - - addr = xilinx_pcie_config_base(bus, devfn, where); - - switch (size) { - case 1: - *val = readb(addr); - break; - case 2: - *val = readw(addr); - break; - default: - *val = readl(addr); - break; - } - - return PCIBIOS_SUCCESSFUL; -} - -/** - * xilinx_pcie_write_config - Write configuration space - * @bus: PCI Bus structure - * @devfn: Device/function - * @where: Offset from base - * @size: Byte/word/dword - * @val: Value to be written to device - * - * Return: PCIBIOS_SUCCESSFUL on success - * PCIBIOS_DEVICE_NOT_FOUND on failure - */ -static int xilinx_pcie_write_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val) -{ - void __iomem *addr; - - if (!xilinx_pcie_valid_device(bus, devfn)) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = xilinx_pcie_config_base(bus, devfn, where); - - switch (size) { - case 1: - writeb(val, addr); - break; - case 2: - writew(val, addr); - break; - default: - writel(val, addr); - break; - } - - return PCIBIOS_SUCCESSFUL; -} - /* PCIe operations */ static struct pci_ops xilinx_pcie_ops = { - .read = xilinx_pcie_read_config, - .write = xilinx_pcie_write_config, + .map_bus = xilinx_pcie_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, }; /* MSI functions */ @@ -737,7 +667,7 @@ static int xilinx_pcie_parse_and_add_res(struct xilinx_pcie_port *port) resource_size_t offset; struct of_pci_range_parser parser; struct of_pci_range range; - struct pci_host_bridge_window *win; + struct resource_entry *win; int err = 0, mem_resno = 0; /* Get the ranges */ @@ -807,7 +737,7 @@ static int xilinx_pcie_parse_and_add_res(struct xilinx_pcie_port *port) free_resources: release_child_resources(&iomem_resource); - list_for_each_entry(win, &port->resources, list) + resource_list_for_each_entry(win, &port->resources) devm_kfree(dev, win->res); pci_free_resource_list(&port->resources); diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index a5a7fd8332ac..46db29395a62 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -214,8 +214,7 @@ static void release_slot(struct hotplug_slot *hotplug_slot) kfree(slot->hotplug_slot->info); kfree(slot->hotplug_slot); - if (slot->dev) - pci_dev_put(slot->dev); + pci_dev_put(slot->dev); kfree(slot); } diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index ff32e85e1de6..f052e951b23e 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -532,8 +532,6 @@ static void interrupt_event_handler(struct work_struct *work) pciehp_green_led_off(p_slot); break; case INT_PRESENCE_ON: - if (!HP_SUPR_RM(ctrl)) - break; ctrl_dbg(ctrl, "Surprise Insertion\n"); handle_surprise_event(p_slot); break; diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index bada20999870..c32fb786d48e 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -475,7 +475,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) struct slot *slot = bss_hotplug_slot->private; struct pci_dev *dev, *temp; int rc; - acpi_owner_id ssdt_id = 0; + acpi_handle ssdt_hdl = NULL; /* Acquire update access to the bus */ mutex_lock(&sn_hotplug_mutex); @@ -522,7 +522,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) if (ACPI_SUCCESS(ret) && (adr>>16) == (slot->device_num + 1)) { /* retain the owner id */ - acpi_get_id(chandle, &ssdt_id); + ssdt_hdl = chandle; ret = acpi_bus_get_device(chandle, &device); @@ -547,12 +547,13 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) pci_unlock_rescan_remove(); /* Remove the SSDT for the slot from the ACPI namespace */ - if (SN_ACPI_BASE_SUPPORT() && ssdt_id) { + if (SN_ACPI_BASE_SUPPORT() && ssdt_hdl) { acpi_status ret; - ret = acpi_unload_table_id(ssdt_id); + ret = acpi_unload_parent_table(ssdt_hdl); if (ACPI_FAILURE(ret)) { - printk(KERN_ERR "%s: acpi_unload_table_id failed (0x%x) for id %d\n", - __func__, ret, ssdt_id); + acpi_handle_err(ssdt_hdl, + "%s: acpi_unload_parent_table failed (0x%x)\n", + __func__, ret); /* try to continue on */ } } diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index fd60806d3fd0..c3e7dfcf9ff5 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -694,11 +694,16 @@ static void __iomem *msix_map_region(struct pci_dev *dev, unsigned nr_entries) { resource_size_t phys_addr; u32 table_offset; + unsigned long flags; u8 bir; pci_read_config_dword(dev, dev->msix_cap + PCI_MSIX_TABLE, &table_offset); bir = (u8)(table_offset & PCI_MSIX_TABLE_BIR); + flags = pci_resource_flags(dev, bir); + if (!flags || (flags & IORESOURCE_UNSET)) + return NULL; + table_offset &= PCI_MSIX_TABLE_OFFSET; phys_addr = pci_resource_start(dev, bir) + table_offset; diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 3542150fc8a3..489063987325 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -501,12 +501,29 @@ static int acpi_pci_run_wake(struct pci_dev *dev, bool enable) return 0; } +static bool acpi_pci_need_resume(struct pci_dev *dev) +{ + struct acpi_device *adev = ACPI_COMPANION(&dev->dev); + + if (!adev || !acpi_device_power_manageable(adev)) + return false; + + if (device_may_wakeup(&dev->dev) != !!adev->wakeup.prepare_count) + return true; + + if (acpi_target_system_state() == ACPI_STATE_S0) + return false; + + return !!adev->power.flags.dsw_present; +} + static struct pci_platform_pm_ops acpi_pci_platform_pm = { .is_manageable = acpi_pci_power_manageable, .set_state = acpi_pci_set_power_state, .choose_state = acpi_pci_choose_state, .sleep_wake = acpi_pci_sleep_wake, .run_wake = acpi_pci_run_wake, + .need_resume = acpi_pci_need_resume, }; void acpi_pci_add_bus(struct pci_bus *bus) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 887e6bd95af7..3cb2210de553 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -653,7 +653,6 @@ static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev) static int pci_pm_prepare(struct device *dev) { struct device_driver *drv = dev->driver; - int error = 0; /* * Devices having power.ignore_children set may still be necessary for @@ -662,10 +661,12 @@ static int pci_pm_prepare(struct device *dev) if (dev->power.ignore_children) pm_runtime_resume(dev); - if (drv && drv->pm && drv->pm->prepare) - error = drv->pm->prepare(dev); - - return error; + if (drv && drv->pm && drv->pm->prepare) { + int error = drv->pm->prepare(dev); + if (error) + return error; + } + return pci_dev_keep_suspended(to_pci_dev(dev)); } @@ -1383,7 +1384,7 @@ static int pci_uevent(struct device *dev, struct kobj_uevent_env *env) if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev))) return -ENOMEM; - if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", + if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02X", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device, (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index cab05f31223f..81f06e8dcc04 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -521,6 +523,11 @@ static inline int platform_pci_run_wake(struct pci_dev *dev, bool enable) pci_platform_pm->run_wake(dev, enable) : -ENODEV; } +static inline bool platform_pci_need_resume(struct pci_dev *dev) +{ + return pci_platform_pm ? pci_platform_pm->need_resume(dev) : false; +} + /** * pci_raw_set_power_state - Use PCI PM registers to set the power state of * given PCI device @@ -1999,6 +2006,27 @@ bool pci_dev_run_wake(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_dev_run_wake); +/** + * pci_dev_keep_suspended - Check if the device can stay in the suspended state. + * @pci_dev: Device to check. + * + * Return 'true' if the device is runtime-suspended, it doesn't have to be + * reconfigured due to wakeup settings difference between system and runtime + * suspend and the current power state of it is suitable for the upcoming + * (system) transition. + */ +bool pci_dev_keep_suspended(struct pci_dev *pci_dev) +{ + struct device *dev = &pci_dev->dev; + + if (!pm_runtime_suspended(dev) + || (device_can_wakeup(dev) && !device_may_wakeup(dev)) + || platform_pci_need_resume(pci_dev)) + return false; + + return pci_target_state(pci_dev) == pci_dev->current_state; +} + void pci_config_pm_runtime_get(struct pci_dev *pdev) { struct device *dev = &pdev->dev; @@ -3197,7 +3225,7 @@ static int pci_pm_reset(struct pci_dev *dev, int probe) { u16 csr; - if (!dev->pm_cap) + if (!dev->pm_cap || dev->dev_flags & PCI_DEV_FLAGS_NO_PM_RESET) return -ENOTTY; pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &csr); @@ -3271,7 +3299,8 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe) { struct pci_dev *pdev; - if (pci_is_root_bus(dev->bus) || dev->subordinate || !dev->bus->self) + if (pci_is_root_bus(dev->bus) || dev->subordinate || + !dev->bus->self || dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET) return -ENOTTY; list_for_each_entry(pdev, &dev->bus->devices, bus_list) @@ -3305,7 +3334,8 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe) { struct pci_dev *pdev; - if (dev->subordinate || !dev->slot) + if (dev->subordinate || !dev->slot || + dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET) return -ENOTTY; list_for_each_entry(pdev, &dev->bus->devices, bus_list) @@ -3557,6 +3587,20 @@ int pci_try_reset_function(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_try_reset_function); +/* Do any devices on or below this bus prevent a bus reset? */ +static bool pci_bus_resetable(struct pci_bus *bus) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET || + (dev->subordinate && !pci_bus_resetable(dev->subordinate))) + return false; + } + + return true; +} + /* Lock devices from the top of the tree down */ static void pci_bus_lock(struct pci_bus *bus) { @@ -3607,6 +3651,22 @@ unlock: return 0; } +/* Do any devices on or below this slot prevent a bus reset? */ +static bool pci_slot_resetable(struct pci_slot *slot) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &slot->bus->devices, bus_list) { + if (!dev->slot || dev->slot != slot) + continue; + if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET || + (dev->subordinate && !pci_bus_resetable(dev->subordinate))) + return false; + } + + return true; +} + /* Lock devices from the top of the tree down */ static void pci_slot_lock(struct pci_slot *slot) { @@ -3728,7 +3788,7 @@ static int pci_slot_reset(struct pci_slot *slot, int probe) { int rc; - if (!slot) + if (!slot || !pci_slot_resetable(slot)) return -ENOTTY; if (!probe) @@ -3820,7 +3880,7 @@ EXPORT_SYMBOL_GPL(pci_try_reset_slot); static int pci_bus_reset(struct pci_bus *bus, int probe) { - if (!bus->self) + if (!bus->self || !pci_bus_resetable(bus)) return -ENOTTY; if (probe) @@ -4439,6 +4499,53 @@ int pci_get_new_domain_nr(void) { return atomic_inc_return(&__domain_nr); } + +#ifdef CONFIG_PCI_DOMAINS_GENERIC +void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent) +{ + static int use_dt_domains = -1; + int domain = of_get_pci_domain_nr(parent->of_node); + + /* + * Check DT domain and use_dt_domains values. + * + * If DT domain property is valid (domain >= 0) and + * use_dt_domains != 0, the DT assignment is valid since this means + * we have not previously allocated a domain number by using + * pci_get_new_domain_nr(); we should also update use_dt_domains to + * 1, to indicate that we have just assigned a domain number from + * DT. + * + * If DT domain property value is not valid (ie domain < 0), and we + * have not previously assigned a domain number from DT + * (use_dt_domains != 1) we should assign a domain number by + * using the: + * + * pci_get_new_domain_nr() + * + * API and update the use_dt_domains value to keep track of method we + * are using to assign domain numbers (use_dt_domains = 0). + * + * All other combinations imply we have a platform that is trying + * to mix domain numbers obtained from DT and pci_get_new_domain_nr(), + * which is a recipe for domain mishandling and it is prevented by + * invalidating the domain value (domain = -1) and printing a + * corresponding error. + */ + if (domain >= 0 && use_dt_domains) { + use_dt_domains = 1; + } else if (domain < 0 && use_dt_domains != 1) { + use_dt_domains = 0; + domain = pci_get_new_domain_nr(); + } else { + dev_err(parent, "Node %s has inconsistent \"linux,pci-domain\" property in DT\n", + parent->of_node->full_name); + domain = -1; + } + + bus->domain_nr = domain; +} +#endif #endif /** diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 8aff29a804ff..4091f82239cd 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -50,6 +50,10 @@ int pci_probe_reset_function(struct pci_dev *dev); * for given device (the device's wake-up capability has to be * enabled by @sleep_wake for this feature to work) * + * @need_resume: returns 'true' if the given device (which is currently + * suspended) needs to be resumed to be configured for system + * wakeup. + * * If given platform is generally capable of power managing PCI devices, all of * these callbacks are mandatory. */ @@ -59,6 +63,7 @@ struct pci_platform_pm_ops { pci_power_t (*choose_state)(struct pci_dev *dev); int (*sleep_wake)(struct pci_dev *dev, bool enable); int (*run_wake)(struct pci_dev *dev, bool enable); + bool (*need_resume)(struct pci_dev *dev); }; int pci_set_platform_pm(struct pci_platform_pm_ops *ops); @@ -67,6 +72,7 @@ void pci_power_up(struct pci_dev *dev); void pci_disable_enabled_device(struct pci_dev *dev); int pci_finish_runtime_suspend(struct pci_dev *dev); int __pci_pme_wakeup(struct pci_dev *dev, void *ign); +bool pci_dev_keep_suspended(struct pci_dev *dev); void pci_config_pm_runtime_get(struct pci_dev *dev); void pci_config_pm_runtime_put(struct pci_dev *dev); void pci_pm_init(struct pci_dev *dev); @@ -208,6 +214,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, void __pci_bus_assign_resources(const struct pci_bus *bus, struct list_head *realloc_head, struct list_head *fail_head); +bool pci_bus_clip_resource(struct pci_dev *dev, int idx); /** * pci_ari_enabled - query ARI forwarding status diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index e1e7026b838d..820740a22e94 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -859,7 +859,10 @@ static ssize_t link_state_store(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); struct pcie_link_state *link, *root = pdev->link_state->root; - u32 val = buf[0] - '0', state = 0; + u32 val, state = 0; + + if (kstrtouint(buf, 10, &val)) + return -EINVAL; if (aspm_disabled) return -EPERM; @@ -900,15 +903,14 @@ static ssize_t clk_ctl_store(struct device *dev, size_t n) { struct pci_dev *pdev = to_pci_dev(dev); - int state; + bool state; - if (n < 1) + if (strtobool(buf, &state)) return -EINVAL; - state = buf[0]-'0'; down_read(&pci_bus_sem); mutex_lock(&aspm_lock); - pcie_set_clkpm_nocheck(pdev->link_state, !!state); + pcie_set_clkpm_nocheck(pdev->link_state, state); mutex_unlock(&aspm_lock); up_read(&pci_bus_sem); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 23212f8ae09b..8d2f400e96cb 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1895,7 +1895,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, int error; struct pci_host_bridge *bridge; struct pci_bus *b, *b2; - struct pci_host_bridge_window *window, *n; + struct resource_entry *window, *n; struct resource *res; resource_size_t offset; char bus_addr[64]; @@ -1959,8 +1959,8 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev)); /* Add initial resources to the bus */ - list_for_each_entry_safe(window, n, resources, list) { - list_move_tail(&window->list, &bridge->windows); + resource_list_for_each_entry_safe(window, n, resources) { + list_move_tail(&window->node, &bridge->windows); res = window->res; offset = window->offset; if (res->flags & IORESOURCE_BUS) @@ -2060,12 +2060,12 @@ void pci_bus_release_busn_res(struct pci_bus *b) struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata, struct list_head *resources) { - struct pci_host_bridge_window *window; + struct resource_entry *window; bool found = false; struct pci_bus *b; int max; - list_for_each_entry(window, resources, list) + resource_list_for_each_entry(window, resources) if (window->res->flags & IORESOURCE_BUS) { found = true; break; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ed6f89b6efe5..85f247e28a80 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -324,18 +324,52 @@ static void quirk_s3_64M(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M); +static void quirk_io(struct pci_dev *dev, int pos, unsigned size, + const char *name) +{ + u32 region; + struct pci_bus_region bus_region; + struct resource *res = dev->resource + pos; + + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (pos << 2), ®ion); + + if (!region) + return; + + res->name = pci_name(dev); + res->flags = region & ~PCI_BASE_ADDRESS_IO_MASK; + res->flags |= + (IORESOURCE_IO | IORESOURCE_PCI_FIXED | IORESOURCE_SIZEALIGN); + region &= ~(size - 1); + + /* Convert from PCI bus to resource space */ + bus_region.start = region; + bus_region.end = region + size - 1; + pcibios_bus_to_resource(dev->bus, res, &bus_region); + + dev_info(&dev->dev, FW_BUG "%s quirk: reg 0x%x: %pR\n", + name, PCI_BASE_ADDRESS_0 + (pos << 2), res); +} + /* * Some CS5536 BIOSes (for example, the Soekris NET5501 board w/ comBIOS * ver. 1.33 20070103) don't set the correct ISA PCI region header info. * BAR0 should be 8 bytes; instead, it may be set to something like 8k * (which conflicts w/ BAR1's memory range). + * + * CS553x's ISA PCI BARs may also be read-only (ref: + * https://bugzilla.kernel.org/show_bug.cgi?id=85991 - Comment #4 forward). */ static void quirk_cs5536_vsa(struct pci_dev *dev) { + static char *name = "CS5536 ISA bridge"; + if (pci_resource_len(dev, 0) != 8) { - struct resource *res = &dev->resource[0]; - res->end = res->start + 8 - 1; - dev_info(&dev->dev, "CS5536 ISA bridge bug detected (incorrect header); workaround applied\n"); + quirk_io(dev, 0, 8, name); /* SMB */ + quirk_io(dev, 1, 256, name); /* GPIO */ + quirk_io(dev, 2, 64, name); /* MFGPT */ + dev_info(&dev->dev, "%s bug detected (incorrect header); workaround applied\n", + name); } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_cs5536_vsa); @@ -3028,6 +3062,41 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x8169, DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID, quirk_broken_intx_masking); +static void quirk_no_bus_reset(struct pci_dev *dev) +{ + dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET; +} + +/* + * Atheros AR93xx chips do not behave after a bus reset. The device will + * throw a Link Down error on AER-capable systems and regardless of AER, + * config space of the device is never accessible again and typically + * causes the system to hang or reset when access is attempted. + * http://www.spinics.net/lists/linux-pci/msg34797.html + */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset); + +static void quirk_no_pm_reset(struct pci_dev *dev) +{ + /* + * We can't do a bus reset on root bus devices, but an ineffective + * PM reset may be better than nothing. + */ + if (!pci_is_root_bus(dev->bus)) + dev->dev_flags |= PCI_DEV_FLAGS_NO_PM_RESET; +} + +/* + * Some AMD/ATI GPUS (HD8570 - Oland) report that a D3hot->D0 transition + * causes a reset (i.e., they advertise NoSoftRst-). This transition seems + * to have no effect on the device: it retains the framebuffer contents and + * monitor sync. Advertising this support makes other layers, like VFIO, + * assume pci_reset_function() is viable for this device. Mark it as + * unavailable to skip it when testing reset methods. + */ +DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_ATI, PCI_ANY_ID, + PCI_CLASS_DISPLAY_VGA, 8, quirk_no_pm_reset); + #ifdef CONFIG_ACPI /* * Apple: Shutdown Cactus Ridge Thunderbolt controller. @@ -3527,6 +3596,44 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB388_ESD, quirk_dma_func1_alias); +/* + * Some devices DMA with the wrong devfn, not just the wrong function. + * quirk_fixed_dma_alias() uses this table to create fixed aliases, where + * the alias is "fixed" and independent of the device devfn. + * + * For example, the Adaptec 3405 is a PCIe card with an Intel 80333 I/O + * processor. To software, this appears as a PCIe-to-PCI/X bridge with a + * single device on the secondary bus. In reality, the single exposed + * device at 0e.0 is the Address Translation Unit (ATU) of the controller + * that provides a bridge to the internal bus of the I/O processor. The + * controller supports private devices, which can be hidden from PCI config + * space. In the case of the Adaptec 3405, a private device at 01.0 + * appears to be the DMA engine, which therefore needs to become a DMA + * alias for the device. + */ +static const struct pci_device_id fixed_dma_alias_tbl[] = { + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x0285, + PCI_VENDOR_ID_ADAPTEC2, 0x02bb), /* Adaptec 3405 */ + .driver_data = PCI_DEVFN(1, 0) }, + { 0 } +}; + +static void quirk_fixed_dma_alias(struct pci_dev *dev) +{ + const struct pci_device_id *id; + + id = pci_match_id(fixed_dma_alias_tbl, dev); + if (id) { + dev->dma_alias_devfn = id->driver_data; + dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN; + dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n", + PCI_SLOT(dev->dma_alias_devfn), + PCI_FUNC(dev->dma_alias_devfn)); + } +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADAPTEC2, 0x0285, quirk_fixed_dma_alias); + /* * A few PCIe-to-PCI bridges fail to expose a PCIe capability, resulting in * using the wrong DMA alias for the device. Some of these devices can be @@ -3630,6 +3737,9 @@ static const u16 pci_quirk_intel_pch_acs_ids[] = { 0x9c98, 0x9c99, 0x9c9a, 0x9c9b, /* Patsburg (X79) PCH */ 0x1d10, 0x1d12, 0x1d14, 0x1d16, 0x1d18, 0x1d1a, 0x1d1c, 0x1d1e, + /* Wellsburg (X99) PCH */ + 0x8d10, 0x8d11, 0x8d12, 0x8d13, 0x8d14, 0x8d15, 0x8d16, 0x8d17, + 0x8d18, 0x8d19, 0x8d1a, 0x8d1b, 0x8d1c, 0x8d1d, 0x8d1e, }; static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev) @@ -3713,6 +3823,8 @@ static const struct pci_dev_acs_enabled { { PCI_VENDOR_ID_INTEL, 0x1551, pci_quirk_mf_endpoint_acs }, { PCI_VENDOR_ID_INTEL, 0x1558, pci_quirk_mf_endpoint_acs }, { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs }, + { 0x19a2, 0x710, pci_quirk_mf_endpoint_acs }, /* Emulex BE3-R */ + { 0x10df, 0x720, pci_quirk_mf_endpoint_acs }, /* Emulex Skyhawk-R */ { 0 } }; diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index f955edb9bea7..eb0ad530dc43 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -71,6 +71,7 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size) { void __iomem *image; int last_image; + unsigned length; image = rom; do { @@ -93,9 +94,9 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size) if (readb(pds + 3) != 'R') break; last_image = readb(pds + 21) & 0x80; - /* this length is reliable */ - image += readw(pds + 16) * 512; - } while (!last_image); + length = readw(pds + 16); + image += length * 512; + } while (length && !last_image); /* never return a size larger than the PCI resource window */ /* there are known ROMs that get the size wrong */ diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 0482235eee92..e3e17f3c0f0f 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -530,9 +530,8 @@ EXPORT_SYMBOL(pci_setup_cardbus); config space writes, so it's quite possible that an I/O window of the bridge will have some undesirable address (e.g. 0) after the first write. Ditto 64-bit prefetchable MMIO. */ -static void pci_setup_bridge_io(struct pci_bus *bus) +static void pci_setup_bridge_io(struct pci_dev *bridge) { - struct pci_dev *bridge = bus->self; struct resource *res; struct pci_bus_region region; unsigned long io_mask; @@ -545,7 +544,7 @@ static void pci_setup_bridge_io(struct pci_bus *bus) io_mask = PCI_IO_1K_RANGE_MASK; /* Set up the top and bottom of the PCI I/O segment for this bus. */ - res = bus->resource[0]; + res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0]; pcibios_resource_to_bus(bridge->bus, ®ion, res); if (res->flags & IORESOURCE_IO) { pci_read_config_word(bridge, PCI_IO_BASE, &l); @@ -568,15 +567,14 @@ static void pci_setup_bridge_io(struct pci_bus *bus) pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16); } -static void pci_setup_bridge_mmio(struct pci_bus *bus) +static void pci_setup_bridge_mmio(struct pci_dev *bridge) { - struct pci_dev *bridge = bus->self; struct resource *res; struct pci_bus_region region; u32 l; /* Set up the top and bottom of the PCI Memory segment for this bus. */ - res = bus->resource[1]; + res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1]; pcibios_resource_to_bus(bridge->bus, ®ion, res); if (res->flags & IORESOURCE_MEM) { l = (region.start >> 16) & 0xfff0; @@ -588,9 +586,8 @@ static void pci_setup_bridge_mmio(struct pci_bus *bus) pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); } -static void pci_setup_bridge_mmio_pref(struct pci_bus *bus) +static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge) { - struct pci_dev *bridge = bus->self; struct resource *res; struct pci_bus_region region; u32 l, bu, lu; @@ -602,7 +599,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_bus *bus) /* Set up PREF base/limit. */ bu = lu = 0; - res = bus->resource[2]; + res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2]; pcibios_resource_to_bus(bridge->bus, ®ion, res); if (res->flags & IORESOURCE_PREFETCH) { l = (region.start >> 16) & 0xfff0; @@ -630,13 +627,13 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type) &bus->busn_res); if (type & IORESOURCE_IO) - pci_setup_bridge_io(bus); + pci_setup_bridge_io(bridge); if (type & IORESOURCE_MEM) - pci_setup_bridge_mmio(bus); + pci_setup_bridge_mmio(bridge); if (type & IORESOURCE_PREFETCH) - pci_setup_bridge_mmio_pref(bus); + pci_setup_bridge_mmio_pref(bridge); pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); } @@ -649,6 +646,41 @@ void pci_setup_bridge(struct pci_bus *bus) __pci_setup_bridge(bus, type); } + +int pci_claim_bridge_resource(struct pci_dev *bridge, int i) +{ + if (i < PCI_BRIDGE_RESOURCES || i > PCI_BRIDGE_RESOURCE_END) + return 0; + + if (pci_claim_resource(bridge, i) == 0) + return 0; /* claimed the window */ + + if ((bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI) + return 0; + + if (!pci_bus_clip_resource(bridge, i)) + return -EINVAL; /* clipping didn't change anything */ + + switch (i - PCI_BRIDGE_RESOURCES) { + case 0: + pci_setup_bridge_io(bridge); + break; + case 1: + pci_setup_bridge_mmio(bridge); + break; + case 2: + pci_setup_bridge_mmio_pref(bridge); + break; + default: + return -EINVAL; + } + + if (pci_claim_resource(bridge, i) == 0) + return 0; /* claimed a smaller window */ + + return -EINVAL; +} + /* Check whether the bridge supports optional I/O and prefetchable memory ranges. If not, the respective base/limit registers must be read-only and read as 0. */ diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index ccad8809ecb1..26a7623e551e 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -277,4 +277,11 @@ config PHY_STIH41X_USB Enable this to support the USB transceiver that is part of STMicroelectronics STiH41x SoC series. +config PHY_QCOM_UFS + tristate "Qualcomm UFS PHY driver" + depends on OF && ARCH_MSM + select GENERIC_PHY + help + Support for UFS PHY on QCOM chipsets. + endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index aa74f961e44e..cfbb72064516 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -34,3 +34,6 @@ obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o obj-$(CONFIG_PHY_STIH41X_USB) += phy-stih41x-usb.o +obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o +obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o +obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c index 6ab43a814ad2..6c80154e8bff 100644 --- a/drivers/phy/phy-miphy365x.c +++ b/drivers/phy/phy-miphy365x.c @@ -141,7 +141,7 @@ struct miphy365x_phy { bool pcie_tx_pol_inv; bool sata_tx_pol_inv; u32 sata_gen; - u64 ctrlreg; + u32 ctrlreg; u8 type; }; @@ -179,7 +179,7 @@ static int miphy365x_set_path(struct miphy365x_phy *miphy_phy, bool sata = (miphy_phy->type == MIPHY_TYPE_SATA); return regmap_update_bits(miphy_dev->regmap, - (unsigned int)miphy_phy->ctrlreg, + miphy_phy->ctrlreg, SYSCFG_SELECT_SATA_MASK, sata << SYSCFG_SELECT_SATA_POS); } @@ -445,7 +445,6 @@ int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy, { struct device_node *phynode = miphy_phy->phy->dev.of_node; const char *name; - const __be32 *taddr; int type = miphy_phy->type; int ret; @@ -455,22 +454,6 @@ int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy, return ret; } - if (!strncmp(name, "syscfg", 6)) { - taddr = of_get_address(phynode, index, NULL, NULL); - if (!taddr) { - dev_err(dev, "failed to fetch syscfg address\n"); - return -EINVAL; - } - - miphy_phy->ctrlreg = of_translate_address(phynode, taddr); - if (miphy_phy->ctrlreg == OF_BAD_ADDR) { - dev_err(dev, "failed to translate syscfg address\n"); - return -EINVAL; - } - - return 0; - } - if (!((!strncmp(name, "sata", 4) && type == MIPHY_TYPE_SATA) || (!strncmp(name, "pcie", 4) && type == MIPHY_TYPE_PCIE))) return 0; @@ -606,7 +589,15 @@ static int miphy365x_probe(struct platform_device *pdev) return ret; phy_set_drvdata(phy, miphy_dev->phys[port]); + port++; + /* sysconfig offsets are indexed from 1 */ + ret = of_property_read_u32_index(np, "st,syscfg", port, + &miphy_phy->ctrlreg); + if (ret) { + dev_err(&pdev->dev, "No sysconfig offset found\n"); + return ret; + } } provider = devm_of_phy_provider_register(&pdev->dev, miphy365x_xlate); diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/phy-qcom-ufs-i.h new file mode 100644 index 000000000000..591a39175e8a --- /dev/null +++ b/drivers/phy/phy-qcom-ufs-i.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef UFS_QCOM_PHY_I_H_ +#define UFS_QCOM_PHY_I_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \ +({ \ + ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \ + might_sleep_if(timeout_us); \ + for (;;) { \ + (val) = readl(addr); \ + if (cond) \ + break; \ + if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \ + (val) = readl(addr); \ + break; \ + } \ + if (sleep_us) \ + usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \ + } \ + (cond) ? 0 : -ETIMEDOUT; \ +}) + +#define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \ + { \ + .reg_offset = reg, \ + .cfg_value = val, \ + } + +#define UFS_QCOM_PHY_NAME_LEN 30 + +enum { + MASK_SERDES_START = 0x1, + MASK_PCS_READY = 0x1, +}; + +enum { + OFFSET_SERDES_START = 0x0, +}; + +struct ufs_qcom_phy_stored_attributes { + u32 att; + u32 value; +}; + + +struct ufs_qcom_phy_calibration { + u32 reg_offset; + u32 cfg_value; +}; + +struct ufs_qcom_phy_vreg { + const char *name; + struct regulator *reg; + int max_uA; + int min_uV; + int max_uV; + bool enabled; + bool is_always_on; +}; + +struct ufs_qcom_phy { + struct list_head list; + struct device *dev; + void __iomem *mmio; + void __iomem *dev_ref_clk_ctrl_mmio; + struct clk *tx_iface_clk; + struct clk *rx_iface_clk; + bool is_iface_clk_enabled; + struct clk *ref_clk_src; + struct clk *ref_clk_parent; + struct clk *ref_clk; + bool is_ref_clk_enabled; + bool is_dev_ref_clk_enabled; + struct ufs_qcom_phy_vreg vdda_pll; + struct ufs_qcom_phy_vreg vdda_phy; + struct ufs_qcom_phy_vreg vddp_ref_clk; + unsigned int quirks; + + /* + * If UFS link is put into Hibern8 and if UFS PHY analog hardware is + * power collapsed (by clearing UFS_PHY_POWER_DOWN_CONTROL), Hibern8 + * exit might fail even after powering on UFS PHY analog hardware. + * Enabling this quirk will help to solve above issue by doing + * custom PHY settings just before PHY analog power collapse. + */ + #define UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE BIT(0) + + u8 host_ctrl_rev_major; + u16 host_ctrl_rev_minor; + u16 host_ctrl_rev_step; + + char name[UFS_QCOM_PHY_NAME_LEN]; + struct ufs_qcom_phy_calibration *cached_regs; + int cached_regs_table_size; + bool is_powered_on; + struct ufs_qcom_phy_specific_ops *phy_spec_ops; +}; + +/** + * struct ufs_qcom_phy_specific_ops - set of pointers to functions which have a + * specific implementation per phy. Each UFS phy, should implement + * those functions according to its spec and requirements + * @calibrate_phy: pointer to a function that calibrate the phy + * @start_serdes: pointer to a function that starts the serdes + * @is_physical_coding_sublayer_ready: pointer to a function that + * checks pcs readiness. returns 0 for success and non-zero for error. + * @set_tx_lane_enable: pointer to a function that enable tx lanes + * @power_control: pointer to a function that controls analog rail of phy + * and writes to QSERDES_RX_SIGDET_CNTRL attribute + */ +struct ufs_qcom_phy_specific_ops { + int (*calibrate_phy)(struct ufs_qcom_phy *phy, bool is_rate_B); + void (*start_serdes)(struct ufs_qcom_phy *phy); + int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy); + void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val); + void (*power_control)(struct ufs_qcom_phy *phy, bool val); +}; + +struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy); +int ufs_qcom_phy_power_on(struct phy *generic_phy); +int ufs_qcom_phy_power_off(struct phy *generic_phy); +int ufs_qcom_phy_exit(struct phy *generic_phy); +int ufs_qcom_phy_init_clks(struct phy *generic_phy, + struct ufs_qcom_phy *phy_common); +int ufs_qcom_phy_init_vregulators(struct phy *generic_phy, + struct ufs_qcom_phy *phy_common); +int ufs_qcom_phy_remove(struct phy *generic_phy, + struct ufs_qcom_phy *ufs_qcom_phy); +struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev, + struct ufs_qcom_phy *common_cfg, + struct phy_ops *ufs_qcom_phy_gen_ops, + struct ufs_qcom_phy_specific_ops *phy_spec_ops); +int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, + struct ufs_qcom_phy_calibration *tbl_A, int tbl_size_A, + struct ufs_qcom_phy_calibration *tbl_B, int tbl_size_B, + bool is_rate_B); +#endif diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c b/drivers/phy/phy-qcom-ufs-qmp-14nm.c new file mode 100644 index 000000000000..f5fc50a9fce7 --- /dev/null +++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "phy-qcom-ufs-qmp-14nm.h" + +#define UFS_PHY_NAME "ufs_phy_qmp_14nm" +#define UFS_PHY_VDDA_PHY_UV (925000) + +static +int ufs_qcom_phy_qmp_14nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, + bool is_rate_B) +{ + int tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A); + int tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); + int err; + + err = ufs_qcom_phy_calibrate(ufs_qcom_phy, phy_cal_table_rate_A, + tbl_size_A, phy_cal_table_rate_B, tbl_size_B, is_rate_B); + + if (err) + dev_err(ufs_qcom_phy->dev, + "%s: ufs_qcom_phy_calibrate() failed %d\n", + __func__, err); + return err; +} + +static +void ufs_qcom_phy_qmp_14nm_advertise_quirks(struct ufs_qcom_phy *phy_common) +{ + phy_common->quirks = + UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE; +} + +static int ufs_qcom_phy_qmp_14nm_init(struct phy *generic_phy) +{ + struct ufs_qcom_phy_qmp_14nm *phy = phy_get_drvdata(generic_phy); + struct ufs_qcom_phy *phy_common = &phy->common_cfg; + int err; + + err = ufs_qcom_phy_init_clks(generic_phy, phy_common); + if (err) { + dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n", + __func__, err); + goto out; + } + + err = ufs_qcom_phy_init_vregulators(generic_phy, phy_common); + if (err) { + dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n", + __func__, err); + goto out; + } + phy_common->vdda_phy.max_uV = UFS_PHY_VDDA_PHY_UV; + phy_common->vdda_phy.min_uV = UFS_PHY_VDDA_PHY_UV; + + ufs_qcom_phy_qmp_14nm_advertise_quirks(phy_common); + +out: + return err; +} + +static +void ufs_qcom_phy_qmp_14nm_power_control(struct ufs_qcom_phy *phy, bool val) +{ + writel_relaxed(val ? 0x1 : 0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL); + /* + * Before any transactions involving PHY, ensure PHY knows + * that it's analog rail is powered ON (or OFF). + */ + mb(); +} + +static inline +void ufs_qcom_phy_qmp_14nm_set_tx_lane_enable(struct ufs_qcom_phy *phy, u32 val) +{ + /* + * 14nm PHY does not have TX_LANE_ENABLE register. + * Implement this function so as not to propagate error to caller. + */ +} + +static inline void ufs_qcom_phy_qmp_14nm_start_serdes(struct ufs_qcom_phy *phy) +{ + u32 tmp; + + tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START); + tmp &= ~MASK_SERDES_START; + tmp |= (1 << OFFSET_SERDES_START); + writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START); + /* Ensure register value is committed */ + mb(); +} + +static int ufs_qcom_phy_qmp_14nm_is_pcs_ready(struct ufs_qcom_phy *phy_common) +{ + int err = 0; + u32 val; + + err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS, + val, (val & MASK_PCS_READY), 10, 1000000); + if (err) + dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n", + __func__, err); + return err; +} + +static struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = { + .init = ufs_qcom_phy_qmp_14nm_init, + .exit = ufs_qcom_phy_exit, + .power_on = ufs_qcom_phy_power_on, + .power_off = ufs_qcom_phy_power_off, + .owner = THIS_MODULE, +}; + +static struct ufs_qcom_phy_specific_ops phy_14nm_ops = { + .calibrate_phy = ufs_qcom_phy_qmp_14nm_phy_calibrate, + .start_serdes = ufs_qcom_phy_qmp_14nm_start_serdes, + .is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_14nm_is_pcs_ready, + .set_tx_lane_enable = ufs_qcom_phy_qmp_14nm_set_tx_lane_enable, + .power_control = ufs_qcom_phy_qmp_14nm_power_control, +}; + +static int ufs_qcom_phy_qmp_14nm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy *generic_phy; + struct ufs_qcom_phy_qmp_14nm *phy; + int err = 0; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) { + dev_err(dev, "%s: failed to allocate phy\n", __func__); + err = -ENOMEM; + goto out; + } + + generic_phy = ufs_qcom_phy_generic_probe(pdev, &phy->common_cfg, + &ufs_qcom_phy_qmp_14nm_phy_ops, &phy_14nm_ops); + + if (!generic_phy) { + dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n", + __func__); + err = -EIO; + goto out; + } + + phy_set_drvdata(generic_phy, phy); + + strlcpy(phy->common_cfg.name, UFS_PHY_NAME, + sizeof(phy->common_cfg.name)); + +out: + return err; +} + +static int ufs_qcom_phy_qmp_14nm_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy *generic_phy = to_phy(dev); + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy); + int err = 0; + + err = ufs_qcom_phy_remove(generic_phy, ufs_qcom_phy); + if (err) + dev_err(dev, "%s: ufs_qcom_phy_remove failed = %d\n", + __func__, err); + + return err; +} + +static const struct of_device_id ufs_qcom_phy_qmp_14nm_of_match[] = { + {.compatible = "qcom,ufs-phy-qmp-14nm"}, + {}, +}; +MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qmp_14nm_of_match); + +static struct platform_driver ufs_qcom_phy_qmp_14nm_driver = { + .probe = ufs_qcom_phy_qmp_14nm_probe, + .remove = ufs_qcom_phy_qmp_14nm_remove, + .driver = { + .of_match_table = ufs_qcom_phy_qmp_14nm_of_match, + .name = "ufs_qcom_phy_qmp_14nm", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(ufs_qcom_phy_qmp_14nm_driver); + +MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QMP 14nm"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.h b/drivers/phy/phy-qcom-ufs-qmp-14nm.h new file mode 100644 index 000000000000..3aefdbacbcd0 --- /dev/null +++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef UFS_QCOM_PHY_QMP_14NM_H_ +#define UFS_QCOM_PHY_QMP_14NM_H_ + +#include "phy-qcom-ufs-i.h" + +/* QCOM UFS PHY control registers */ +#define COM_OFF(x) (0x000 + x) +#define PHY_OFF(x) (0xC00 + x) +#define TX_OFF(n, x) (0x400 + (0x400 * n) + x) +#define RX_OFF(n, x) (0x600 + (0x400 * n) + x) + +/* UFS PHY QSERDES COM registers */ +#define QSERDES_COM_BG_TIMER COM_OFF(0x0C) +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN COM_OFF(0x34) +#define QSERDES_COM_SYS_CLK_CTRL COM_OFF(0x3C) +#define QSERDES_COM_LOCK_CMP1_MODE0 COM_OFF(0x4C) +#define QSERDES_COM_LOCK_CMP2_MODE0 COM_OFF(0x50) +#define QSERDES_COM_LOCK_CMP3_MODE0 COM_OFF(0x54) +#define QSERDES_COM_LOCK_CMP1_MODE1 COM_OFF(0x58) +#define QSERDES_COM_LOCK_CMP2_MODE1 COM_OFF(0x5C) +#define QSERDES_COM_LOCK_CMP3_MODE1 COM_OFF(0x60) +#define QSERDES_COM_CP_CTRL_MODE0 COM_OFF(0x78) +#define QSERDES_COM_CP_CTRL_MODE1 COM_OFF(0x7C) +#define QSERDES_COM_PLL_RCTRL_MODE0 COM_OFF(0x84) +#define QSERDES_COM_PLL_RCTRL_MODE1 COM_OFF(0x88) +#define QSERDES_COM_PLL_CCTRL_MODE0 COM_OFF(0x90) +#define QSERDES_COM_PLL_CCTRL_MODE1 COM_OFF(0x94) +#define QSERDES_COM_SYSCLK_EN_SEL COM_OFF(0xAC) +#define QSERDES_COM_RESETSM_CNTRL COM_OFF(0xB4) +#define QSERDES_COM_LOCK_CMP_EN COM_OFF(0xC8) +#define QSERDES_COM_LOCK_CMP_CFG COM_OFF(0xCC) +#define QSERDES_COM_DEC_START_MODE0 COM_OFF(0xD0) +#define QSERDES_COM_DEC_START_MODE1 COM_OFF(0xD4) +#define QSERDES_COM_DIV_FRAC_START1_MODE0 COM_OFF(0xDC) +#define QSERDES_COM_DIV_FRAC_START2_MODE0 COM_OFF(0xE0) +#define QSERDES_COM_DIV_FRAC_START3_MODE0 COM_OFF(0xE4) +#define QSERDES_COM_DIV_FRAC_START1_MODE1 COM_OFF(0xE8) +#define QSERDES_COM_DIV_FRAC_START2_MODE1 COM_OFF(0xEC) +#define QSERDES_COM_DIV_FRAC_START3_MODE1 COM_OFF(0xF0) +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 COM_OFF(0x108) +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 COM_OFF(0x10C) +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 COM_OFF(0x110) +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 COM_OFF(0x114) +#define QSERDES_COM_VCO_TUNE_CTRL COM_OFF(0x124) +#define QSERDES_COM_VCO_TUNE_MAP COM_OFF(0x128) +#define QSERDES_COM_VCO_TUNE1_MODE0 COM_OFF(0x12C) +#define QSERDES_COM_VCO_TUNE2_MODE0 COM_OFF(0x130) +#define QSERDES_COM_VCO_TUNE1_MODE1 COM_OFF(0x134) +#define QSERDES_COM_VCO_TUNE2_MODE1 COM_OFF(0x138) +#define QSERDES_COM_VCO_TUNE_TIMER1 COM_OFF(0x144) +#define QSERDES_COM_VCO_TUNE_TIMER2 COM_OFF(0x148) +#define QSERDES_COM_CLK_SELECT COM_OFF(0x174) +#define QSERDES_COM_HSCLK_SEL COM_OFF(0x178) +#define QSERDES_COM_CORECLK_DIV COM_OFF(0x184) +#define QSERDES_COM_CORE_CLK_EN COM_OFF(0x18C) +#define QSERDES_COM_CMN_CONFIG COM_OFF(0x194) +#define QSERDES_COM_SVS_MODE_CLK_SEL COM_OFF(0x19C) +#define QSERDES_COM_CORECLK_DIV_MODE1 COM_OFF(0x1BC) + +/* UFS PHY registers */ +#define UFS_PHY_PHY_START PHY_OFF(0x00) +#define UFS_PHY_POWER_DOWN_CONTROL PHY_OFF(0x04) +#define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x168) + +/* UFS PHY TX registers */ +#define QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN TX_OFF(0, 0x68) +#define QSERDES_TX_LANE_MODE TX_OFF(0, 0x94) + +/* UFS PHY RX registers */ +#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN RX_OFF(0, 0x40) +#define QSERDES_RX_RX_TERM_BW RX_OFF(0, 0x90) +#define QSERDES_RX_RX_EQ_GAIN1_LSB RX_OFF(0, 0xC4) +#define QSERDES_RX_RX_EQ_GAIN1_MSB RX_OFF(0, 0xC8) +#define QSERDES_RX_RX_EQ_GAIN2_LSB RX_OFF(0, 0xCC) +#define QSERDES_RX_RX_EQ_GAIN2_MSB RX_OFF(0, 0xD0) +#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 RX_OFF(0, 0xD8) +#define QSERDES_RX_SIGDET_CNTRL RX_OFF(0, 0x114) +#define QSERDES_RX_SIGDET_LVL RX_OFF(0, 0x118) +#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL RX_OFF(0, 0x11C) +#define QSERDES_RX_RX_INTERFACE_MODE RX_OFF(0, 0x12C) + +/* + * This structure represents the 14nm specific phy. + * common_cfg MUST remain the first field in this structure + * in case extra fields are added. This way, when calling + * get_ufs_qcom_phy() of generic phy, we can extract the + * common phy structure (struct ufs_qcom_phy) out of it + * regardless of the relevant specific phy. + */ +struct ufs_qcom_phy_qmp_14nm { + struct ufs_qcom_phy common_cfg; +}; + +static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = { + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_CONFIG, 0x0e), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0xd7), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CLK_SELECT, 0x30), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYS_CLK_CTRL, 0x06), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BG_TIMER, 0x0a), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_HSCLK_SEL, 0x05), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV, 0x0a), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_EN, 0x01), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_CTRL, 0x10), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x20), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORE_CLK_EN, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_CFG, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER1, 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x14), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE0, 0x82), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x0b), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0x28), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE0, 0x02), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE1, 0x98), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x0b), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE1, 0x16), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x28), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE1, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE1, 0x00), + + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN, 0x45), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE, 0x02), + + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_LVL, 0x24), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL, 0x02), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_INTERFACE_MODE, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x18), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_TERM_BW, 0x5B), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xFF), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xFF), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x0F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0E), +}; + +static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = { + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x54), +}; + +#endif diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/phy-qcom-ufs-qmp-20nm.c new file mode 100644 index 000000000000..8332f96b2c4a --- /dev/null +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "phy-qcom-ufs-qmp-20nm.h" + +#define UFS_PHY_NAME "ufs_phy_qmp_20nm" + +static +int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, + bool is_rate_B) +{ + struct ufs_qcom_phy_calibration *tbl_A, *tbl_B; + int tbl_size_A, tbl_size_B; + u8 major = ufs_qcom_phy->host_ctrl_rev_major; + u16 minor = ufs_qcom_phy->host_ctrl_rev_minor; + u16 step = ufs_qcom_phy->host_ctrl_rev_step; + int err; + + if ((major == 0x1) && (minor == 0x002) && (step == 0x0000)) { + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_2_0); + tbl_A = phy_cal_table_rate_A_1_2_0; + } else if ((major == 0x1) && (minor == 0x003) && (step == 0x0000)) { + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_3_0); + tbl_A = phy_cal_table_rate_A_1_3_0; + } else { + dev_err(ufs_qcom_phy->dev, "%s: Unknown UFS-PHY version, no calibration values\n", + __func__); + err = -ENODEV; + goto out; + } + + tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); + tbl_B = phy_cal_table_rate_B; + + err = ufs_qcom_phy_calibrate(ufs_qcom_phy, tbl_A, tbl_size_A, + tbl_B, tbl_size_B, is_rate_B); + + if (err) + dev_err(ufs_qcom_phy->dev, "%s: ufs_qcom_phy_calibrate() failed %d\n", + __func__, err); + +out: + return err; +} + +static +void ufs_qcom_phy_qmp_20nm_advertise_quirks(struct ufs_qcom_phy *phy_common) +{ + phy_common->quirks = + UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE; +} + +static int ufs_qcom_phy_qmp_20nm_init(struct phy *generic_phy) +{ + struct ufs_qcom_phy_qmp_20nm *phy = phy_get_drvdata(generic_phy); + struct ufs_qcom_phy *phy_common = &phy->common_cfg; + int err = 0; + + err = ufs_qcom_phy_init_clks(generic_phy, phy_common); + if (err) { + dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n", + __func__, err); + goto out; + } + + err = ufs_qcom_phy_init_vregulators(generic_phy, phy_common); + if (err) { + dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n", + __func__, err); + goto out; + } + + ufs_qcom_phy_qmp_20nm_advertise_quirks(phy_common); + +out: + return err; +} + +static +void ufs_qcom_phy_qmp_20nm_power_control(struct ufs_qcom_phy *phy, bool val) +{ + bool hibern8_exit_after_pwr_collapse = phy->quirks & + UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE; + + if (val) { + writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL); + /* + * Before any transactions involving PHY, ensure PHY knows + * that it's analog rail is powered ON. + */ + mb(); + + if (hibern8_exit_after_pwr_collapse) { + /* + * Give atleast 1us delay after restoring PHY analog + * power. + */ + usleep_range(1, 2); + writel_relaxed(0x0A, phy->mmio + + QSERDES_COM_SYSCLK_EN_SEL_TXBAND); + writel_relaxed(0x08, phy->mmio + + QSERDES_COM_SYSCLK_EN_SEL_TXBAND); + /* + * Make sure workaround is deactivated before proceeding + * with normal PHY operations. + */ + mb(); + } + } else { + if (hibern8_exit_after_pwr_collapse) { + writel_relaxed(0x0A, phy->mmio + + QSERDES_COM_SYSCLK_EN_SEL_TXBAND); + writel_relaxed(0x02, phy->mmio + + QSERDES_COM_SYSCLK_EN_SEL_TXBAND); + /* + * Make sure that above workaround is activated before + * PHY analog power collapse. + */ + mb(); + } + + writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL); + /* + * ensure that PHY knows its PHY analog rail is going + * to be powered down + */ + mb(); + } +} + +static +void ufs_qcom_phy_qmp_20nm_set_tx_lane_enable(struct ufs_qcom_phy *phy, u32 val) +{ + writel_relaxed(val & UFS_PHY_TX_LANE_ENABLE_MASK, + phy->mmio + UFS_PHY_TX_LANE_ENABLE); + mb(); +} + +static inline void ufs_qcom_phy_qmp_20nm_start_serdes(struct ufs_qcom_phy *phy) +{ + u32 tmp; + + tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START); + tmp &= ~MASK_SERDES_START; + tmp |= (1 << OFFSET_SERDES_START); + writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START); + mb(); +} + +static int ufs_qcom_phy_qmp_20nm_is_pcs_ready(struct ufs_qcom_phy *phy_common) +{ + int err = 0; + u32 val; + + err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS, + val, (val & MASK_PCS_READY), 10, 1000000); + if (err) + dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n", + __func__, err); + return err; +} + +static struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = { + .init = ufs_qcom_phy_qmp_20nm_init, + .exit = ufs_qcom_phy_exit, + .power_on = ufs_qcom_phy_power_on, + .power_off = ufs_qcom_phy_power_off, + .owner = THIS_MODULE, +}; + +static struct ufs_qcom_phy_specific_ops phy_20nm_ops = { + .calibrate_phy = ufs_qcom_phy_qmp_20nm_phy_calibrate, + .start_serdes = ufs_qcom_phy_qmp_20nm_start_serdes, + .is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_20nm_is_pcs_ready, + .set_tx_lane_enable = ufs_qcom_phy_qmp_20nm_set_tx_lane_enable, + .power_control = ufs_qcom_phy_qmp_20nm_power_control, +}; + +static int ufs_qcom_phy_qmp_20nm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy *generic_phy; + struct ufs_qcom_phy_qmp_20nm *phy; + int err = 0; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) { + dev_err(dev, "%s: failed to allocate phy\n", __func__); + err = -ENOMEM; + goto out; + } + + generic_phy = ufs_qcom_phy_generic_probe(pdev, &phy->common_cfg, + &ufs_qcom_phy_qmp_20nm_phy_ops, &phy_20nm_ops); + + if (!generic_phy) { + dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n", + __func__); + err = -EIO; + goto out; + } + + phy_set_drvdata(generic_phy, phy); + + strlcpy(phy->common_cfg.name, UFS_PHY_NAME, + sizeof(phy->common_cfg.name)); + +out: + return err; +} + +static int ufs_qcom_phy_qmp_20nm_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy *generic_phy = to_phy(dev); + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy); + int err = 0; + + err = ufs_qcom_phy_remove(generic_phy, ufs_qcom_phy); + if (err) + dev_err(dev, "%s: ufs_qcom_phy_remove failed = %d\n", + __func__, err); + + return err; +} + +static const struct of_device_id ufs_qcom_phy_qmp_20nm_of_match[] = { + {.compatible = "qcom,ufs-phy-qmp-20nm"}, + {}, +}; +MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qmp_20nm_of_match); + +static struct platform_driver ufs_qcom_phy_qmp_20nm_driver = { + .probe = ufs_qcom_phy_qmp_20nm_probe, + .remove = ufs_qcom_phy_qmp_20nm_remove, + .driver = { + .of_match_table = ufs_qcom_phy_qmp_20nm_of_match, + .name = "ufs_qcom_phy_qmp_20nm", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(ufs_qcom_phy_qmp_20nm_driver); + +MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QMP 20nm"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.h b/drivers/phy/phy-qcom-ufs-qmp-20nm.h new file mode 100644 index 000000000000..4f3076bb3d71 --- /dev/null +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef UFS_QCOM_PHY_QMP_20NM_H_ +#define UFS_QCOM_PHY_QMP_20NM_H_ + +#include "phy-qcom-ufs-i.h" + +/* QCOM UFS PHY control registers */ + +#define COM_OFF(x) (0x000 + x) +#define PHY_OFF(x) (0xC00 + x) +#define TX_OFF(n, x) (0x400 + (0x400 * n) + x) +#define RX_OFF(n, x) (0x600 + (0x400 * n) + x) + +/* UFS PHY PLL block registers */ +#define QSERDES_COM_SYS_CLK_CTRL COM_OFF(0x0) +#define QSERDES_COM_PLL_VCOTAIL_EN COM_OFF(0x04) +#define QSERDES_COM_PLL_CNTRL COM_OFF(0x14) +#define QSERDES_COM_PLL_IP_SETI COM_OFF(0x24) +#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL COM_OFF(0x28) +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN COM_OFF(0x30) +#define QSERDES_COM_PLL_CP_SETI COM_OFF(0x34) +#define QSERDES_COM_PLL_IP_SETP COM_OFF(0x38) +#define QSERDES_COM_PLL_CP_SETP COM_OFF(0x3C) +#define QSERDES_COM_SYSCLK_EN_SEL_TXBAND COM_OFF(0x48) +#define QSERDES_COM_RESETSM_CNTRL COM_OFF(0x4C) +#define QSERDES_COM_RESETSM_CNTRL2 COM_OFF(0x50) +#define QSERDES_COM_PLLLOCK_CMP1 COM_OFF(0x90) +#define QSERDES_COM_PLLLOCK_CMP2 COM_OFF(0x94) +#define QSERDES_COM_PLLLOCK_CMP3 COM_OFF(0x98) +#define QSERDES_COM_PLLLOCK_CMP_EN COM_OFF(0x9C) +#define QSERDES_COM_BGTC COM_OFF(0xA0) +#define QSERDES_COM_DEC_START1 COM_OFF(0xAC) +#define QSERDES_COM_PLL_AMP_OS COM_OFF(0xB0) +#define QSERDES_COM_RES_CODE_UP_OFFSET COM_OFF(0xD8) +#define QSERDES_COM_RES_CODE_DN_OFFSET COM_OFF(0xDC) +#define QSERDES_COM_DIV_FRAC_START1 COM_OFF(0x100) +#define QSERDES_COM_DIV_FRAC_START2 COM_OFF(0x104) +#define QSERDES_COM_DIV_FRAC_START3 COM_OFF(0x108) +#define QSERDES_COM_DEC_START2 COM_OFF(0x10C) +#define QSERDES_COM_PLL_RXTXEPCLK_EN COM_OFF(0x110) +#define QSERDES_COM_PLL_CRCTRL COM_OFF(0x114) +#define QSERDES_COM_PLL_CLKEPDIV COM_OFF(0x118) + +/* TX LANE n (0, 1) registers */ +#define QSERDES_TX_EMP_POST1_LVL(n) TX_OFF(n, 0x08) +#define QSERDES_TX_DRV_LVL(n) TX_OFF(n, 0x0C) +#define QSERDES_TX_LANE_MODE(n) TX_OFF(n, 0x54) + +/* RX LANE n (0, 1) registers */ +#define QSERDES_RX_CDR_CONTROL1(n) RX_OFF(n, 0x0) +#define QSERDES_RX_CDR_CONTROL_HALF(n) RX_OFF(n, 0x8) +#define QSERDES_RX_RX_EQ_GAIN1_LSB(n) RX_OFF(n, 0xA8) +#define QSERDES_RX_RX_EQ_GAIN1_MSB(n) RX_OFF(n, 0xAC) +#define QSERDES_RX_RX_EQ_GAIN2_LSB(n) RX_OFF(n, 0xB0) +#define QSERDES_RX_RX_EQ_GAIN2_MSB(n) RX_OFF(n, 0xB4) +#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(n) RX_OFF(n, 0xBC) +#define QSERDES_RX_CDR_CONTROL_QUARTER(n) RX_OFF(n, 0xC) +#define QSERDES_RX_SIGDET_CNTRL(n) RX_OFF(n, 0x100) + +/* UFS PHY registers */ +#define UFS_PHY_PHY_START PHY_OFF(0x00) +#define UFS_PHY_POWER_DOWN_CONTROL PHY_OFF(0x4) +#define UFS_PHY_TX_LANE_ENABLE PHY_OFF(0x44) +#define UFS_PHY_PWM_G1_CLK_DIVIDER PHY_OFF(0x08) +#define UFS_PHY_PWM_G2_CLK_DIVIDER PHY_OFF(0x0C) +#define UFS_PHY_PWM_G3_CLK_DIVIDER PHY_OFF(0x10) +#define UFS_PHY_PWM_G4_CLK_DIVIDER PHY_OFF(0x14) +#define UFS_PHY_CORECLK_PWM_G1_CLK_DIVIDER PHY_OFF(0x34) +#define UFS_PHY_CORECLK_PWM_G2_CLK_DIVIDER PHY_OFF(0x38) +#define UFS_PHY_CORECLK_PWM_G3_CLK_DIVIDER PHY_OFF(0x3C) +#define UFS_PHY_CORECLK_PWM_G4_CLK_DIVIDER PHY_OFF(0x40) +#define UFS_PHY_OMC_STATUS_RDVAL PHY_OFF(0x68) +#define UFS_PHY_LINE_RESET_TIME PHY_OFF(0x28) +#define UFS_PHY_LINE_RESET_GRANULARITY PHY_OFF(0x2C) +#define UFS_PHY_TSYNC_RSYNC_CNTL PHY_OFF(0x48) +#define UFS_PHY_PLL_CNTL PHY_OFF(0x50) +#define UFS_PHY_TX_LARGE_AMP_DRV_LVL PHY_OFF(0x54) +#define UFS_PHY_TX_SMALL_AMP_DRV_LVL PHY_OFF(0x5C) +#define UFS_PHY_TX_LARGE_AMP_POST_EMP_LVL PHY_OFF(0x58) +#define UFS_PHY_TX_SMALL_AMP_POST_EMP_LVL PHY_OFF(0x60) +#define UFS_PHY_CFG_CHANGE_CNT_VAL PHY_OFF(0x64) +#define UFS_PHY_RX_SYNC_WAIT_TIME PHY_OFF(0x6C) +#define UFS_PHY_TX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xB4) +#define UFS_PHY_RX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xE0) +#define UFS_PHY_TX_MIN_STALL_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xB8) +#define UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xE4) +#define UFS_PHY_TX_MIN_SAVE_CONFIG_TIME_CAPABILITY PHY_OFF(0xBC) +#define UFS_PHY_RX_MIN_SAVE_CONFIG_TIME_CAPABILITY PHY_OFF(0xE8) +#define UFS_PHY_RX_PWM_BURST_CLOSURE_LENGTH_CAPABILITY PHY_OFF(0xFC) +#define UFS_PHY_RX_MIN_ACTIVATETIME_CAPABILITY PHY_OFF(0x100) +#define UFS_PHY_RX_SIGDET_CTRL3 PHY_OFF(0x14c) +#define UFS_PHY_RMMI_ATTR_CTRL PHY_OFF(0x160) +#define UFS_PHY_RMMI_RX_CFGUPDT_L1 (1 << 7) +#define UFS_PHY_RMMI_TX_CFGUPDT_L1 (1 << 6) +#define UFS_PHY_RMMI_CFGWR_L1 (1 << 5) +#define UFS_PHY_RMMI_CFGRD_L1 (1 << 4) +#define UFS_PHY_RMMI_RX_CFGUPDT_L0 (1 << 3) +#define UFS_PHY_RMMI_TX_CFGUPDT_L0 (1 << 2) +#define UFS_PHY_RMMI_CFGWR_L0 (1 << 1) +#define UFS_PHY_RMMI_CFGRD_L0 (1 << 0) +#define UFS_PHY_RMMI_ATTRID PHY_OFF(0x164) +#define UFS_PHY_RMMI_ATTRWRVAL PHY_OFF(0x168) +#define UFS_PHY_RMMI_ATTRRDVAL_L0_STATUS PHY_OFF(0x16C) +#define UFS_PHY_RMMI_ATTRRDVAL_L1_STATUS PHY_OFF(0x170) +#define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x174) + +#define UFS_PHY_TX_LANE_ENABLE_MASK 0x3 + +/* + * This structure represents the 20nm specific phy. + * common_cfg MUST remain the first field in this structure + * in case extra fields are added. This way, when calling + * get_ufs_qcom_phy() of generic phy, we can extract the + * common phy structure (struct ufs_qcom_phy) out of it + * regardless of the relevant specific phy. + */ +struct ufs_qcom_phy_qmp_20nm { + struct ufs_qcom_phy common_cfg; +}; + +static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_1_2_0[] = { + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL3, 0x0D), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_VCOTAIL_EN, 0xe1), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CRCTRL, 0xcc), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL_TXBAND, 0x08), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CLKEPDIV, 0x03), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RXTXEPCLK_EN, 0x10), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x82), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START2, 0x03), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1, 0x80), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2, 0x80), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3, 0x40), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x19), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP3, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP_EN, 0x03), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x90), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL2, 0x03), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(0), 0xf2), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(0), 0x0c), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(0), 0x12), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(1), 0xf2), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(1), 0x0c), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(1), 0x12), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(0), 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(0), 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(0), 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(0), 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(1), 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(1), 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(1), 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(1), 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETI, 0x3f), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETP, 0x1b), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETP, 0x0f), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETI, 0x01), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_EMP_POST1_LVL(0), 0x2F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_DRV_LVL(0), 0x20), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_EMP_POST1_LVL(1), 0x2F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_DRV_LVL(1), 0x20), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(0), 0x68), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(1), 0x68), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(1), 0xdc), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(0), 0xdc), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3), +}; + +static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_1_3_0[] = { + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL3, 0x0D), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_VCOTAIL_EN, 0xe1), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CRCTRL, 0xcc), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL_TXBAND, 0x08), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CLKEPDIV, 0x03), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RXTXEPCLK_EN, 0x10), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x82), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START2, 0x03), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1, 0x80), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2, 0x80), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3, 0x40), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x19), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP3, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP_EN, 0x03), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x90), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL2, 0x03), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(0), 0xf2), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(0), 0x0c), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(0), 0x12), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(1), 0xf2), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(1), 0x0c), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(1), 0x12), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(0), 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(0), 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(0), 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(0), 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(1), 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(1), 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(1), 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(1), 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETI, 0x2b), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETP, 0x38), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETP, 0x3c), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RES_CODE_UP_OFFSET, 0x02), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RES_CODE_DN_OFFSET, 0x02), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETI, 0x01), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CNTRL, 0x40), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(0), 0x68), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(1), 0x68), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(1), 0xdc), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(0), 0xdc), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3), +}; + +static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = { + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x98), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0x65), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x1e), +}; + +#endif diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c new file mode 100644 index 000000000000..44ee983d57fe --- /dev/null +++ b/drivers/phy/phy-qcom-ufs.c @@ -0,0 +1,745 @@ +/* + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "phy-qcom-ufs-i.h" + +#define MAX_PROP_NAME 32 +#define VDDA_PHY_MIN_UV 1000000 +#define VDDA_PHY_MAX_UV 1000000 +#define VDDA_PLL_MIN_UV 1800000 +#define VDDA_PLL_MAX_UV 1800000 +#define VDDP_REF_CLK_MIN_UV 1200000 +#define VDDP_REF_CLK_MAX_UV 1200000 + +static int __ufs_qcom_phy_init_vreg(struct phy *, struct ufs_qcom_phy_vreg *, + const char *, bool); +static int ufs_qcom_phy_init_vreg(struct phy *, struct ufs_qcom_phy_vreg *, + const char *); +static int ufs_qcom_phy_base_init(struct platform_device *pdev, + struct ufs_qcom_phy *phy_common); + +int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, + struct ufs_qcom_phy_calibration *tbl_A, + int tbl_size_A, + struct ufs_qcom_phy_calibration *tbl_B, + int tbl_size_B, bool is_rate_B) +{ + int i; + int ret = 0; + + if (!tbl_A) { + dev_err(ufs_qcom_phy->dev, "%s: tbl_A is NULL", __func__); + ret = EINVAL; + goto out; + } + + for (i = 0; i < tbl_size_A; i++) + writel_relaxed(tbl_A[i].cfg_value, + ufs_qcom_phy->mmio + tbl_A[i].reg_offset); + + /* + * In case we would like to work in rate B, we need + * to override a registers that were configured in rate A table + * with registers of rate B table. + * table. + */ + if (is_rate_B) { + if (!tbl_B) { + dev_err(ufs_qcom_phy->dev, "%s: tbl_B is NULL", + __func__); + ret = EINVAL; + goto out; + } + + for (i = 0; i < tbl_size_B; i++) + writel_relaxed(tbl_B[i].cfg_value, + ufs_qcom_phy->mmio + tbl_B[i].reg_offset); + } + + /* flush buffered writes */ + mb(); + +out: + return ret; +} + +struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev, + struct ufs_qcom_phy *common_cfg, + struct phy_ops *ufs_qcom_phy_gen_ops, + struct ufs_qcom_phy_specific_ops *phy_spec_ops) +{ + int err; + struct device *dev = &pdev->dev; + struct phy *generic_phy = NULL; + struct phy_provider *phy_provider; + + err = ufs_qcom_phy_base_init(pdev, common_cfg); + if (err) { + dev_err(dev, "%s: phy base init failed %d\n", __func__, err); + goto out; + } + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) { + err = PTR_ERR(phy_provider); + dev_err(dev, "%s: failed to register phy %d\n", __func__, err); + goto out; + } + + generic_phy = devm_phy_create(dev, NULL, ufs_qcom_phy_gen_ops); + if (IS_ERR(generic_phy)) { + err = PTR_ERR(generic_phy); + dev_err(dev, "%s: failed to create phy %d\n", __func__, err); + goto out; + } + + common_cfg->phy_spec_ops = phy_spec_ops; + common_cfg->dev = dev; + +out: + return generic_phy; +} + +/* + * This assumes the embedded phy structure inside generic_phy is of type + * struct ufs_qcom_phy. In order to function properly it's crucial + * to keep the embedded struct "struct ufs_qcom_phy common_cfg" + * as the first inside generic_phy. + */ +struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy) +{ + return (struct ufs_qcom_phy *)phy_get_drvdata(generic_phy); +} + +static +int ufs_qcom_phy_base_init(struct platform_device *pdev, + struct ufs_qcom_phy *phy_common) +{ + struct device *dev = &pdev->dev; + struct resource *res; + int err = 0; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_mem"); + if (!res) { + dev_err(dev, "%s: phy_mem resource not found\n", __func__); + err = -ENOMEM; + goto out; + } + + phy_common->mmio = devm_ioremap_resource(dev, res); + if (IS_ERR((void const *)phy_common->mmio)) { + err = PTR_ERR((void const *)phy_common->mmio); + phy_common->mmio = NULL; + dev_err(dev, "%s: ioremap for phy_mem resource failed %d\n", + __func__, err); + goto out; + } + + /* "dev_ref_clk_ctrl_mem" is optional resource */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "dev_ref_clk_ctrl_mem"); + if (!res) { + dev_dbg(dev, "%s: dev_ref_clk_ctrl_mem resource not found\n", + __func__); + goto out; + } + + phy_common->dev_ref_clk_ctrl_mmio = devm_ioremap_resource(dev, res); + if (IS_ERR((void const *)phy_common->dev_ref_clk_ctrl_mmio)) { + err = PTR_ERR((void const *)phy_common->dev_ref_clk_ctrl_mmio); + phy_common->dev_ref_clk_ctrl_mmio = NULL; + dev_err(dev, "%s: ioremap for dev_ref_clk_ctrl_mem resource failed %d\n", + __func__, err); + } + +out: + return err; +} + +static int __ufs_qcom_phy_clk_get(struct phy *phy, + const char *name, struct clk **clk_out, bool err_print) +{ + struct clk *clk; + int err = 0; + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy); + struct device *dev = ufs_qcom_phy->dev; + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) { + err = PTR_ERR(clk); + if (err_print) + dev_err(dev, "failed to get %s err %d", name, err); + } else { + *clk_out = clk; + } + + return err; +} + +static +int ufs_qcom_phy_clk_get(struct phy *phy, + const char *name, struct clk **clk_out) +{ + return __ufs_qcom_phy_clk_get(phy, name, clk_out, true); +} + +int +ufs_qcom_phy_init_clks(struct phy *generic_phy, + struct ufs_qcom_phy *phy_common) +{ + int err; + + err = ufs_qcom_phy_clk_get(generic_phy, "tx_iface_clk", + &phy_common->tx_iface_clk); + if (err) + goto out; + + err = ufs_qcom_phy_clk_get(generic_phy, "rx_iface_clk", + &phy_common->rx_iface_clk); + if (err) + goto out; + + err = ufs_qcom_phy_clk_get(generic_phy, "ref_clk_src", + &phy_common->ref_clk_src); + if (err) + goto out; + + /* + * "ref_clk_parent" is optional hence don't abort init if it's not + * found. + */ + __ufs_qcom_phy_clk_get(generic_phy, "ref_clk_parent", + &phy_common->ref_clk_parent, false); + + err = ufs_qcom_phy_clk_get(generic_phy, "ref_clk", + &phy_common->ref_clk); + +out: + return err; +} + +int +ufs_qcom_phy_init_vregulators(struct phy *generic_phy, + struct ufs_qcom_phy *phy_common) +{ + int err; + + err = ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vdda_pll, + "vdda-pll"); + if (err) + goto out; + + err = ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vdda_phy, + "vdda-phy"); + + if (err) + goto out; + + /* vddp-ref-clk-* properties are optional */ + __ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vddp_ref_clk, + "vddp-ref-clk", true); +out: + return err; +} + +static int __ufs_qcom_phy_init_vreg(struct phy *phy, + struct ufs_qcom_phy_vreg *vreg, const char *name, bool optional) +{ + int err = 0; + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy); + struct device *dev = ufs_qcom_phy->dev; + + char prop_name[MAX_PROP_NAME]; + + vreg->name = kstrdup(name, GFP_KERNEL); + if (!vreg->name) { + err = -ENOMEM; + goto out; + } + + vreg->reg = devm_regulator_get(dev, name); + if (IS_ERR(vreg->reg)) { + err = PTR_ERR(vreg->reg); + vreg->reg = NULL; + if (!optional) + dev_err(dev, "failed to get %s, %d\n", name, err); + goto out; + } + + if (dev->of_node) { + snprintf(prop_name, MAX_PROP_NAME, "%s-max-microamp", name); + err = of_property_read_u32(dev->of_node, + prop_name, &vreg->max_uA); + if (err && err != -EINVAL) { + dev_err(dev, "%s: failed to read %s\n", + __func__, prop_name); + goto out; + } else if (err == -EINVAL || !vreg->max_uA) { + if (regulator_count_voltages(vreg->reg) > 0) { + dev_err(dev, "%s: %s is mandatory\n", + __func__, prop_name); + goto out; + } + err = 0; + } + snprintf(prop_name, MAX_PROP_NAME, "%s-always-on", name); + if (of_get_property(dev->of_node, prop_name, NULL)) + vreg->is_always_on = true; + else + vreg->is_always_on = false; + } + + if (!strcmp(name, "vdda-pll")) { + vreg->max_uV = VDDA_PLL_MAX_UV; + vreg->min_uV = VDDA_PLL_MIN_UV; + } else if (!strcmp(name, "vdda-phy")) { + vreg->max_uV = VDDA_PHY_MAX_UV; + vreg->min_uV = VDDA_PHY_MIN_UV; + } else if (!strcmp(name, "vddp-ref-clk")) { + vreg->max_uV = VDDP_REF_CLK_MAX_UV; + vreg->min_uV = VDDP_REF_CLK_MIN_UV; + } + +out: + if (err) + kfree(vreg->name); + return err; +} + +static int ufs_qcom_phy_init_vreg(struct phy *phy, + struct ufs_qcom_phy_vreg *vreg, const char *name) +{ + return __ufs_qcom_phy_init_vreg(phy, vreg, name, false); +} + +static +int ufs_qcom_phy_cfg_vreg(struct phy *phy, + struct ufs_qcom_phy_vreg *vreg, bool on) +{ + int ret = 0; + struct regulator *reg = vreg->reg; + const char *name = vreg->name; + int min_uV; + int uA_load; + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy); + struct device *dev = ufs_qcom_phy->dev; + + BUG_ON(!vreg); + + if (regulator_count_voltages(reg) > 0) { + min_uV = on ? vreg->min_uV : 0; + ret = regulator_set_voltage(reg, min_uV, vreg->max_uV); + if (ret) { + dev_err(dev, "%s: %s set voltage failed, err=%d\n", + __func__, name, ret); + goto out; + } + uA_load = on ? vreg->max_uA : 0; + ret = regulator_set_optimum_mode(reg, uA_load); + if (ret >= 0) { + /* + * regulator_set_optimum_mode() returns new regulator + * mode upon success. + */ + ret = 0; + } else { + dev_err(dev, "%s: %s set optimum mode(uA_load=%d) failed, err=%d\n", + __func__, name, uA_load, ret); + goto out; + } + } +out: + return ret; +} + +static +int ufs_qcom_phy_enable_vreg(struct phy *phy, + struct ufs_qcom_phy_vreg *vreg) +{ + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy); + struct device *dev = ufs_qcom_phy->dev; + int ret = 0; + + if (!vreg || vreg->enabled) + goto out; + + ret = ufs_qcom_phy_cfg_vreg(phy, vreg, true); + if (ret) { + dev_err(dev, "%s: ufs_qcom_phy_cfg_vreg() failed, err=%d\n", + __func__, ret); + goto out; + } + + ret = regulator_enable(vreg->reg); + if (ret) { + dev_err(dev, "%s: enable failed, err=%d\n", + __func__, ret); + goto out; + } + + vreg->enabled = true; +out: + return ret; +} + +int ufs_qcom_phy_enable_ref_clk(struct phy *generic_phy) +{ + int ret = 0; + struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy); + + if (phy->is_ref_clk_enabled) + goto out; + + /* + * reference clock is propagated in a daisy-chained manner from + * source to phy, so ungate them at each stage. + */ + ret = clk_prepare_enable(phy->ref_clk_src); + if (ret) { + dev_err(phy->dev, "%s: ref_clk_src enable failed %d\n", + __func__, ret); + goto out; + } + + /* + * "ref_clk_parent" is optional clock hence make sure that clk reference + * is available before trying to enable the clock. + */ + if (phy->ref_clk_parent) { + ret = clk_prepare_enable(phy->ref_clk_parent); + if (ret) { + dev_err(phy->dev, "%s: ref_clk_parent enable failed %d\n", + __func__, ret); + goto out_disable_src; + } + } + + ret = clk_prepare_enable(phy->ref_clk); + if (ret) { + dev_err(phy->dev, "%s: ref_clk enable failed %d\n", + __func__, ret); + goto out_disable_parent; + } + + phy->is_ref_clk_enabled = true; + goto out; + +out_disable_parent: + if (phy->ref_clk_parent) + clk_disable_unprepare(phy->ref_clk_parent); +out_disable_src: + clk_disable_unprepare(phy->ref_clk_src); +out: + return ret; +} + +static +int ufs_qcom_phy_disable_vreg(struct phy *phy, + struct ufs_qcom_phy_vreg *vreg) +{ + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy); + struct device *dev = ufs_qcom_phy->dev; + int ret = 0; + + if (!vreg || !vreg->enabled || vreg->is_always_on) + goto out; + + ret = regulator_disable(vreg->reg); + + if (!ret) { + /* ignore errors on applying disable config */ + ufs_qcom_phy_cfg_vreg(phy, vreg, false); + vreg->enabled = false; + } else { + dev_err(dev, "%s: %s disable failed, err=%d\n", + __func__, vreg->name, ret); + } +out: + return ret; +} + +void ufs_qcom_phy_disable_ref_clk(struct phy *generic_phy) +{ + struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy); + + if (phy->is_ref_clk_enabled) { + clk_disable_unprepare(phy->ref_clk); + /* + * "ref_clk_parent" is optional clock hence make sure that clk + * reference is available before trying to disable the clock. + */ + if (phy->ref_clk_parent) + clk_disable_unprepare(phy->ref_clk_parent); + clk_disable_unprepare(phy->ref_clk_src); + phy->is_ref_clk_enabled = false; + } +} + +#define UFS_REF_CLK_EN (1 << 5) + +static void ufs_qcom_phy_dev_ref_clk_ctrl(struct phy *generic_phy, bool enable) +{ + struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy); + + if (phy->dev_ref_clk_ctrl_mmio && + (enable ^ phy->is_dev_ref_clk_enabled)) { + u32 temp = readl_relaxed(phy->dev_ref_clk_ctrl_mmio); + + if (enable) + temp |= UFS_REF_CLK_EN; + else + temp &= ~UFS_REF_CLK_EN; + + /* + * If we are here to disable this clock immediately after + * entering into hibern8, we need to make sure that device + * ref_clk is active atleast 1us after the hibern8 enter. + */ + if (!enable) + udelay(1); + + writel_relaxed(temp, phy->dev_ref_clk_ctrl_mmio); + /* ensure that ref_clk is enabled/disabled before we return */ + wmb(); + /* + * If we call hibern8 exit after this, we need to make sure that + * device ref_clk is stable for atleast 1us before the hibern8 + * exit command. + */ + if (enable) + udelay(1); + + phy->is_dev_ref_clk_enabled = enable; + } +} + +void ufs_qcom_phy_enable_dev_ref_clk(struct phy *generic_phy) +{ + ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, true); +} + +void ufs_qcom_phy_disable_dev_ref_clk(struct phy *generic_phy) +{ + ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, false); +} + +/* Turn ON M-PHY RMMI interface clocks */ +int ufs_qcom_phy_enable_iface_clk(struct phy *generic_phy) +{ + struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy); + int ret = 0; + + if (phy->is_iface_clk_enabled) + goto out; + + ret = clk_prepare_enable(phy->tx_iface_clk); + if (ret) { + dev_err(phy->dev, "%s: tx_iface_clk enable failed %d\n", + __func__, ret); + goto out; + } + ret = clk_prepare_enable(phy->rx_iface_clk); + if (ret) { + clk_disable_unprepare(phy->tx_iface_clk); + dev_err(phy->dev, "%s: rx_iface_clk enable failed %d. disabling also tx_iface_clk\n", + __func__, ret); + goto out; + } + phy->is_iface_clk_enabled = true; + +out: + return ret; +} + +/* Turn OFF M-PHY RMMI interface clocks */ +void ufs_qcom_phy_disable_iface_clk(struct phy *generic_phy) +{ + struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy); + + if (phy->is_iface_clk_enabled) { + clk_disable_unprepare(phy->tx_iface_clk); + clk_disable_unprepare(phy->rx_iface_clk); + phy->is_iface_clk_enabled = false; + } +} + +int ufs_qcom_phy_start_serdes(struct phy *generic_phy) +{ + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy); + int ret = 0; + + if (!ufs_qcom_phy->phy_spec_ops->start_serdes) { + dev_err(ufs_qcom_phy->dev, "%s: start_serdes() callback is not supported\n", + __func__); + ret = -ENOTSUPP; + } else { + ufs_qcom_phy->phy_spec_ops->start_serdes(ufs_qcom_phy); + } + + return ret; +} + +int ufs_qcom_phy_set_tx_lane_enable(struct phy *generic_phy, u32 tx_lanes) +{ + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy); + int ret = 0; + + if (!ufs_qcom_phy->phy_spec_ops->set_tx_lane_enable) { + dev_err(ufs_qcom_phy->dev, "%s: set_tx_lane_enable() callback is not supported\n", + __func__); + ret = -ENOTSUPP; + } else { + ufs_qcom_phy->phy_spec_ops->set_tx_lane_enable(ufs_qcom_phy, + tx_lanes); + } + + return ret; +} + +void ufs_qcom_phy_save_controller_version(struct phy *generic_phy, + u8 major, u16 minor, u16 step) +{ + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy); + + ufs_qcom_phy->host_ctrl_rev_major = major; + ufs_qcom_phy->host_ctrl_rev_minor = minor; + ufs_qcom_phy->host_ctrl_rev_step = step; +} + +int ufs_qcom_phy_calibrate_phy(struct phy *generic_phy, bool is_rate_B) +{ + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy); + int ret = 0; + + if (!ufs_qcom_phy->phy_spec_ops->calibrate_phy) { + dev_err(ufs_qcom_phy->dev, "%s: calibrate_phy() callback is not supported\n", + __func__); + ret = -ENOTSUPP; + } else { + ret = ufs_qcom_phy->phy_spec_ops-> + calibrate_phy(ufs_qcom_phy, is_rate_B); + if (ret) + dev_err(ufs_qcom_phy->dev, "%s: calibrate_phy() failed %d\n", + __func__, ret); + } + + return ret; +} + +int ufs_qcom_phy_remove(struct phy *generic_phy, + struct ufs_qcom_phy *ufs_qcom_phy) +{ + phy_power_off(generic_phy); + + kfree(ufs_qcom_phy->vdda_pll.name); + kfree(ufs_qcom_phy->vdda_phy.name); + + return 0; +} + +int ufs_qcom_phy_exit(struct phy *generic_phy) +{ + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy); + + if (ufs_qcom_phy->is_powered_on) + phy_power_off(generic_phy); + + return 0; +} + +int ufs_qcom_phy_is_pcs_ready(struct phy *generic_phy) +{ + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy); + + if (!ufs_qcom_phy->phy_spec_ops->is_physical_coding_sublayer_ready) { + dev_err(ufs_qcom_phy->dev, "%s: is_physical_coding_sublayer_ready() callback is not supported\n", + __func__); + return -ENOTSUPP; + } + + return ufs_qcom_phy->phy_spec_ops-> + is_physical_coding_sublayer_ready(ufs_qcom_phy); +} + +int ufs_qcom_phy_power_on(struct phy *generic_phy) +{ + struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy); + struct device *dev = phy_common->dev; + int err; + + err = ufs_qcom_phy_enable_vreg(generic_phy, &phy_common->vdda_phy); + if (err) { + dev_err(dev, "%s enable vdda_phy failed, err=%d\n", + __func__, err); + goto out; + } + + phy_common->phy_spec_ops->power_control(phy_common, true); + + /* vdda_pll also enables ref clock LDOs so enable it first */ + err = ufs_qcom_phy_enable_vreg(generic_phy, &phy_common->vdda_pll); + if (err) { + dev_err(dev, "%s enable vdda_pll failed, err=%d\n", + __func__, err); + goto out_disable_phy; + } + + err = ufs_qcom_phy_enable_ref_clk(generic_phy); + if (err) { + dev_err(dev, "%s enable phy ref clock failed, err=%d\n", + __func__, err); + goto out_disable_pll; + } + + /* enable device PHY ref_clk pad rail */ + if (phy_common->vddp_ref_clk.reg) { + err = ufs_qcom_phy_enable_vreg(generic_phy, + &phy_common->vddp_ref_clk); + if (err) { + dev_err(dev, "%s enable vddp_ref_clk failed, err=%d\n", + __func__, err); + goto out_disable_ref_clk; + } + } + + phy_common->is_powered_on = true; + goto out; + +out_disable_ref_clk: + ufs_qcom_phy_disable_ref_clk(generic_phy); +out_disable_pll: + ufs_qcom_phy_disable_vreg(generic_phy, &phy_common->vdda_pll); +out_disable_phy: + ufs_qcom_phy_disable_vreg(generic_phy, &phy_common->vdda_phy); +out: + return err; +} + +int ufs_qcom_phy_power_off(struct phy *generic_phy) +{ + struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy); + + phy_common->phy_spec_ops->power_control(phy_common, false); + + if (phy_common->vddp_ref_clk.reg) + ufs_qcom_phy_disable_vreg(generic_phy, + &phy_common->vddp_ref_clk); + ufs_qcom_phy_disable_ref_clk(generic_phy); + + ufs_qcom_phy_disable_vreg(generic_phy, &phy_common->vdda_pll); + ufs_qcom_phy_disable_vreg(generic_phy, &phy_common->vdda_phy); + phy_common->is_powered_on = false; + + return 0; +} diff --git a/drivers/phy/phy-stih407-usb.c b/drivers/phy/phy-stih407-usb.c index 74f0fab3cd8a..1d5ae5f8ef69 100644 --- a/drivers/phy/phy-stih407-usb.c +++ b/drivers/phy/phy-stih407-usb.c @@ -22,6 +22,9 @@ #include #include +#define PHYPARAM_REG 1 +#define PHYCTRL_REG 2 + /* Default PHY_SEL and REFCLKSEL configuration */ #define STIH407_USB_PICOPHY_CTRL_PORT_CONF 0x6 #define STIH407_USB_PICOPHY_CTRL_PORT_MASK 0x1f @@ -93,7 +96,7 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct phy_provider *phy_provider; struct phy *phy; - struct resource *res; + int ret; phy_dev = devm_kzalloc(dev, sizeof(*phy_dev), GFP_KERNEL); if (!phy_dev) @@ -123,19 +126,19 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev) return PTR_ERR(phy_dev->regmap); } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl"); - if (!res) { - dev_err(dev, "No ctrl reg found\n"); - return -ENXIO; + ret = of_property_read_u32_index(np, "st,syscfg", PHYPARAM_REG, + &phy_dev->param); + if (ret) { + dev_err(dev, "can't get phyparam offset (%d)\n", ret); + return ret; } - phy_dev->ctrl = res->start; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "param"); - if (!res) { - dev_err(dev, "No param reg found\n"); - return -ENXIO; + ret = of_property_read_u32_index(np, "st,syscfg", PHYCTRL_REG, + &phy_dev->ctrl); + if (ret) { + dev_err(dev, "can't get phyctrl offset (%d)\n", ret); + return ret; } - phy_dev->param = res->start; phy = devm_phy_create(dev, NULL, &stih407_usb2_picophy_data); if (IS_ERR(phy)) { diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index d014f22f387a..ee9f44ad7f02 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -96,6 +96,14 @@ config PINCTRL_FALCON depends on SOC_FALCON depends on PINCTRL_LANTIQ +config PINCTRL_MESON + bool + select PINMUX + select PINCONF + select GENERIC_PINCONF + select OF_GPIO + select REGMAP_MMIO + config PINCTRL_ROCKCHIP bool select PINMUX @@ -113,7 +121,7 @@ config PINCTRL_SINGLE This selects the device tree based generic pinctrl driver. config PINCTRL_SIRF - bool "CSR SiRFprimaII/SiRFmarco pin controller driver" + bool "CSR SiRFprimaII pin controller driver" depends on ARCH_SIRF select PINMUX select GPIOLIB_IRQCHIP @@ -191,6 +199,14 @@ config PINCTRL_PALMAS open drain configuration for the Palmas series devices like TPS65913, TPS80036 etc. +config PINCTRL_ZYNQ + bool "Pinctrl driver for Xilinx Zynq" + depends on ARCH_ZYNQ + select PINMUX + select GENERIC_PINCONF + help + This selectes the pinctrl driver for Xilinx Zynq. + source "drivers/pinctrl/berlin/Kconfig" source "drivers/pinctrl/freescale/Kconfig" source "drivers/pinctrl/intel/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index c030b3db8034..0475206dd600 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -1,6 +1,6 @@ # generic pinmux support -ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG +subdir-ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG obj-$(CONFIG_PINCTRL) += core.o pinctrl-utils.o obj-$(CONFIG_PINMUX) += pinmux.o @@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o +obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o @@ -35,6 +36,7 @@ obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o +obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-y += freescale/ diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index e4f65510c87e..89dca77ca038 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -1801,14 +1801,15 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev) if (pctldev == NULL) return; - mutex_lock(&pinctrldev_list_mutex); mutex_lock(&pctldev->mutex); - pinctrl_remove_device_debugfs(pctldev); + mutex_unlock(&pctldev->mutex); if (!IS_ERR(pctldev->p)) pinctrl_put(pctldev->p); + mutex_lock(&pinctrldev_list_mutex); + mutex_lock(&pctldev->mutex); /* TODO: check that no pinmuxes are still active? */ list_del(&pctldev->node); /* Destroy descriptor tree */ diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index 52f2b9404fe0..448f10986c28 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -437,7 +437,7 @@ static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev, const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; unsigned long config; - if (!pin_reg || !pin_reg->conf_reg) { + if (!pin_reg || pin_reg->conf_reg == -1) { seq_printf(s, "N/A"); return; } diff --git a/drivers/pinctrl/freescale/pinctrl-imx25.c b/drivers/pinctrl/freescale/pinctrl-imx25.c index 8d1013a040c9..faf635654312 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx25.c +++ b/drivers/pinctrl/freescale/pinctrl-imx25.c @@ -27,150 +27,148 @@ enum imx25_pads { MX25_PAD_RESERVE0 = 1, - MX25_PAD_RESERVE1 = 2, - MX25_PAD_A10 = 3, - MX25_PAD_A13 = 4, - MX25_PAD_A14 = 5, - MX25_PAD_A15 = 6, - MX25_PAD_A16 = 7, - MX25_PAD_A17 = 8, - MX25_PAD_A18 = 9, - MX25_PAD_A19 = 10, - MX25_PAD_A20 = 11, - MX25_PAD_A21 = 12, - MX25_PAD_A22 = 13, - MX25_PAD_A23 = 14, - MX25_PAD_A24 = 15, - MX25_PAD_A25 = 16, - MX25_PAD_EB0 = 17, - MX25_PAD_EB1 = 18, - MX25_PAD_OE = 19, - MX25_PAD_CS0 = 20, - MX25_PAD_CS1 = 21, - MX25_PAD_CS4 = 22, - MX25_PAD_CS5 = 23, - MX25_PAD_NF_CE0 = 24, - MX25_PAD_ECB = 25, - MX25_PAD_LBA = 26, - MX25_PAD_BCLK = 27, - MX25_PAD_RW = 28, - MX25_PAD_NFWE_B = 29, - MX25_PAD_NFRE_B = 30, - MX25_PAD_NFALE = 31, - MX25_PAD_NFCLE = 32, - MX25_PAD_NFWP_B = 33, - MX25_PAD_NFRB = 34, - MX25_PAD_D15 = 35, - MX25_PAD_D14 = 36, - MX25_PAD_D13 = 37, - MX25_PAD_D12 = 38, - MX25_PAD_D11 = 39, - MX25_PAD_D10 = 40, - MX25_PAD_D9 = 41, - MX25_PAD_D8 = 42, - MX25_PAD_D7 = 43, - MX25_PAD_D6 = 44, - MX25_PAD_D5 = 45, - MX25_PAD_D4 = 46, - MX25_PAD_D3 = 47, - MX25_PAD_D2 = 48, - MX25_PAD_D1 = 49, - MX25_PAD_D0 = 50, - MX25_PAD_LD0 = 51, - MX25_PAD_LD1 = 52, - MX25_PAD_LD2 = 53, - MX25_PAD_LD3 = 54, - MX25_PAD_LD4 = 55, - MX25_PAD_LD5 = 56, - MX25_PAD_LD6 = 57, - MX25_PAD_LD7 = 58, - MX25_PAD_LD8 = 59, - MX25_PAD_LD9 = 60, - MX25_PAD_LD10 = 61, - MX25_PAD_LD11 = 62, - MX25_PAD_LD12 = 63, - MX25_PAD_LD13 = 64, - MX25_PAD_LD14 = 65, - MX25_PAD_LD15 = 66, - MX25_PAD_HSYNC = 67, - MX25_PAD_VSYNC = 68, - MX25_PAD_LSCLK = 69, - MX25_PAD_OE_ACD = 70, - MX25_PAD_CONTRAST = 71, - MX25_PAD_PWM = 72, - MX25_PAD_CSI_D2 = 73, - MX25_PAD_CSI_D3 = 74, - MX25_PAD_CSI_D4 = 75, - MX25_PAD_CSI_D5 = 76, - MX25_PAD_CSI_D6 = 77, - MX25_PAD_CSI_D7 = 78, - MX25_PAD_CSI_D8 = 79, - MX25_PAD_CSI_D9 = 80, - MX25_PAD_CSI_MCLK = 81, - MX25_PAD_CSI_VSYNC = 82, - MX25_PAD_CSI_HSYNC = 83, - MX25_PAD_CSI_PIXCLK = 84, - MX25_PAD_I2C1_CLK = 85, - MX25_PAD_I2C1_DAT = 86, - MX25_PAD_CSPI1_MOSI = 87, - MX25_PAD_CSPI1_MISO = 88, - MX25_PAD_CSPI1_SS0 = 89, - MX25_PAD_CSPI1_SS1 = 90, - MX25_PAD_CSPI1_SCLK = 91, - MX25_PAD_CSPI1_RDY = 92, - MX25_PAD_UART1_RXD = 93, - MX25_PAD_UART1_TXD = 94, - MX25_PAD_UART1_RTS = 95, - MX25_PAD_UART1_CTS = 96, - MX25_PAD_UART2_RXD = 97, - MX25_PAD_UART2_TXD = 98, - MX25_PAD_UART2_RTS = 99, - MX25_PAD_UART2_CTS = 100, - MX25_PAD_SD1_CMD = 101, - MX25_PAD_SD1_CLK = 102, - MX25_PAD_SD1_DATA0 = 103, - MX25_PAD_SD1_DATA1 = 104, - MX25_PAD_SD1_DATA2 = 105, - MX25_PAD_SD1_DATA3 = 106, - MX25_PAD_KPP_ROW0 = 107, - MX25_PAD_KPP_ROW1 = 108, - MX25_PAD_KPP_ROW2 = 109, - MX25_PAD_KPP_ROW3 = 110, - MX25_PAD_KPP_COL0 = 111, - MX25_PAD_KPP_COL1 = 112, - MX25_PAD_KPP_COL2 = 113, - MX25_PAD_KPP_COL3 = 114, - MX25_PAD_FEC_MDC = 115, - MX25_PAD_FEC_MDIO = 116, - MX25_PAD_FEC_TDATA0 = 117, - MX25_PAD_FEC_TDATA1 = 118, - MX25_PAD_FEC_TX_EN = 119, - MX25_PAD_FEC_RDATA0 = 120, - MX25_PAD_FEC_RDATA1 = 121, - MX25_PAD_FEC_RX_DV = 122, - MX25_PAD_FEC_TX_CLK = 123, - MX25_PAD_RTCK = 124, - MX25_PAD_DE_B = 125, - MX25_PAD_GPIO_A = 126, - MX25_PAD_GPIO_B = 127, - MX25_PAD_GPIO_C = 128, - MX25_PAD_GPIO_D = 129, - MX25_PAD_GPIO_E = 130, - MX25_PAD_GPIO_F = 131, - MX25_PAD_EXT_ARMCLK = 132, - MX25_PAD_UPLL_BYPCLK = 133, - MX25_PAD_VSTBY_REQ = 134, - MX25_PAD_VSTBY_ACK = 135, - MX25_PAD_POWER_FAIL = 136, - MX25_PAD_CLKO = 137, - MX25_PAD_BOOT_MODE0 = 138, - MX25_PAD_BOOT_MODE1 = 139, + MX25_PAD_A10 = 2, + MX25_PAD_A13 = 3, + MX25_PAD_A14 = 4, + MX25_PAD_A15 = 5, + MX25_PAD_A16 = 6, + MX25_PAD_A17 = 7, + MX25_PAD_A18 = 8, + MX25_PAD_A19 = 9, + MX25_PAD_A20 = 10, + MX25_PAD_A21 = 11, + MX25_PAD_A22 = 12, + MX25_PAD_A23 = 13, + MX25_PAD_A24 = 14, + MX25_PAD_A25 = 15, + MX25_PAD_EB0 = 16, + MX25_PAD_EB1 = 17, + MX25_PAD_OE = 18, + MX25_PAD_CS0 = 19, + MX25_PAD_CS1 = 20, + MX25_PAD_CS4 = 21, + MX25_PAD_CS5 = 22, + MX25_PAD_NF_CE0 = 23, + MX25_PAD_ECB = 24, + MX25_PAD_LBA = 25, + MX25_PAD_BCLK = 26, + MX25_PAD_RW = 27, + MX25_PAD_NFWE_B = 28, + MX25_PAD_NFRE_B = 29, + MX25_PAD_NFALE = 30, + MX25_PAD_NFCLE = 31, + MX25_PAD_NFWP_B = 32, + MX25_PAD_NFRB = 33, + MX25_PAD_D15 = 34, + MX25_PAD_D14 = 35, + MX25_PAD_D13 = 36, + MX25_PAD_D12 = 37, + MX25_PAD_D11 = 38, + MX25_PAD_D10 = 39, + MX25_PAD_D9 = 40, + MX25_PAD_D8 = 41, + MX25_PAD_D7 = 42, + MX25_PAD_D6 = 43, + MX25_PAD_D5 = 44, + MX25_PAD_D4 = 45, + MX25_PAD_D3 = 46, + MX25_PAD_D2 = 47, + MX25_PAD_D1 = 48, + MX25_PAD_D0 = 49, + MX25_PAD_LD0 = 50, + MX25_PAD_LD1 = 51, + MX25_PAD_LD2 = 52, + MX25_PAD_LD3 = 53, + MX25_PAD_LD4 = 54, + MX25_PAD_LD5 = 55, + MX25_PAD_LD6 = 56, + MX25_PAD_LD7 = 57, + MX25_PAD_LD8 = 58, + MX25_PAD_LD9 = 59, + MX25_PAD_LD10 = 60, + MX25_PAD_LD11 = 61, + MX25_PAD_LD12 = 62, + MX25_PAD_LD13 = 63, + MX25_PAD_LD14 = 64, + MX25_PAD_LD15 = 65, + MX25_PAD_HSYNC = 66, + MX25_PAD_VSYNC = 67, + MX25_PAD_LSCLK = 68, + MX25_PAD_OE_ACD = 69, + MX25_PAD_CONTRAST = 70, + MX25_PAD_PWM = 71, + MX25_PAD_CSI_D2 = 72, + MX25_PAD_CSI_D3 = 73, + MX25_PAD_CSI_D4 = 74, + MX25_PAD_CSI_D5 = 75, + MX25_PAD_CSI_D6 = 76, + MX25_PAD_CSI_D7 = 77, + MX25_PAD_CSI_D8 = 78, + MX25_PAD_CSI_D9 = 79, + MX25_PAD_CSI_MCLK = 80, + MX25_PAD_CSI_VSYNC = 81, + MX25_PAD_CSI_HSYNC = 82, + MX25_PAD_CSI_PIXCLK = 83, + MX25_PAD_I2C1_CLK = 84, + MX25_PAD_I2C1_DAT = 85, + MX25_PAD_CSPI1_MOSI = 86, + MX25_PAD_CSPI1_MISO = 87, + MX25_PAD_CSPI1_SS0 = 88, + MX25_PAD_CSPI1_SS1 = 89, + MX25_PAD_CSPI1_SCLK = 90, + MX25_PAD_CSPI1_RDY = 91, + MX25_PAD_UART1_RXD = 92, + MX25_PAD_UART1_TXD = 93, + MX25_PAD_UART1_RTS = 94, + MX25_PAD_UART1_CTS = 95, + MX25_PAD_UART2_RXD = 96, + MX25_PAD_UART2_TXD = 97, + MX25_PAD_UART2_RTS = 98, + MX25_PAD_UART2_CTS = 99, + MX25_PAD_SD1_CMD = 100, + MX25_PAD_SD1_CLK = 101, + MX25_PAD_SD1_DATA0 = 102, + MX25_PAD_SD1_DATA1 = 103, + MX25_PAD_SD1_DATA2 = 104, + MX25_PAD_SD1_DATA3 = 105, + MX25_PAD_KPP_ROW0 = 106, + MX25_PAD_KPP_ROW1 = 107, + MX25_PAD_KPP_ROW2 = 108, + MX25_PAD_KPP_ROW3 = 109, + MX25_PAD_KPP_COL0 = 110, + MX25_PAD_KPP_COL1 = 111, + MX25_PAD_KPP_COL2 = 112, + MX25_PAD_KPP_COL3 = 113, + MX25_PAD_FEC_MDC = 114, + MX25_PAD_FEC_MDIO = 115, + MX25_PAD_FEC_TDATA0 = 116, + MX25_PAD_FEC_TDATA1 = 117, + MX25_PAD_FEC_TX_EN = 118, + MX25_PAD_FEC_RDATA0 = 119, + MX25_PAD_FEC_RDATA1 = 120, + MX25_PAD_FEC_RX_DV = 121, + MX25_PAD_FEC_TX_CLK = 122, + MX25_PAD_RTCK = 123, + MX25_PAD_DE_B = 124, + MX25_PAD_GPIO_A = 125, + MX25_PAD_GPIO_B = 126, + MX25_PAD_GPIO_C = 127, + MX25_PAD_GPIO_D = 128, + MX25_PAD_GPIO_E = 129, + MX25_PAD_GPIO_F = 130, + MX25_PAD_EXT_ARMCLK = 131, + MX25_PAD_UPLL_BYPCLK = 132, + MX25_PAD_VSTBY_REQ = 133, + MX25_PAD_VSTBY_ACK = 134, + MX25_PAD_POWER_FAIL = 135, + MX25_PAD_CLKO = 136, + MX25_PAD_BOOT_MODE0 = 137, + MX25_PAD_BOOT_MODE1 = 138, }; /* Pad names for the pinmux subsystem */ static const struct pinctrl_pin_desc imx25_pinctrl_pads[] = { IMX_PINCTRL_PIN(MX25_PAD_RESERVE0), - IMX_PINCTRL_PIN(MX25_PAD_RESERVE1), IMX_PINCTRL_PIN(MX25_PAD_A10), IMX_PINCTRL_PIN(MX25_PAD_A13), IMX_PINCTRL_PIN(MX25_PAD_A14), diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index e9f8b39d1a9f..3034fd03bced 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -148,6 +148,11 @@ struct chv_community { size_t ngpios; }; +struct chv_pin_context { + u32 padctrl0; + u32 padctrl1; +}; + /** * struct chv_pinctrl - CHV pinctrl private structure * @dev: Pointer to the parent device @@ -172,6 +177,8 @@ struct chv_pinctrl { spinlock_t lock; unsigned intr_lines[16]; const struct chv_community *community; + u32 saved_intmask; + struct chv_pin_context *saved_pin_context; }; #define gpiochip_to_pinctrl(c) container_of(c, struct chv_pinctrl, chip) @@ -873,9 +880,22 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev, value &= ~CHV_PADCTRL1_INVRXTX_MASK; chv_writel(value, reg); - /* Switch to a GPIO mode */ reg = chv_padreg(pctrl, offset, CHV_PADCTRL0); - value = readl(reg) | CHV_PADCTRL0_GPIOEN; + value = readl(reg); + + /* + * If the pin is in HiZ mode (both TX and RX buffers are + * disabled) we turn it to be input now. + */ + if ((value & CHV_PADCTRL0_GPIOCFG_MASK) == + (CHV_PADCTRL0_GPIOCFG_HIZ << CHV_PADCTRL0_GPIOCFG_SHIFT)) { + value &= ~CHV_PADCTRL0_GPIOCFG_MASK; + value |= CHV_PADCTRL0_GPIOCFG_GPI << + CHV_PADCTRL0_GPIOCFG_SHIFT; + } + + /* Switch to a GPIO mode */ + value |= CHV_PADCTRL0_GPIOEN; chv_writel(value, reg); } @@ -1443,6 +1463,14 @@ static int chv_pinctrl_probe(struct platform_device *pdev) spin_lock_init(&pctrl->lock); pctrl->dev = &pdev->dev; +#ifdef CONFIG_PM_SLEEP + pctrl->saved_pin_context = devm_kcalloc(pctrl->dev, + pctrl->community->npins, sizeof(*pctrl->saved_pin_context), + GFP_KERNEL); + if (!pctrl->saved_pin_context) + return -ENOMEM; +#endif + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pctrl->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(pctrl->regs)) @@ -1486,6 +1514,94 @@ static int chv_pinctrl_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int chv_pinctrl_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct chv_pinctrl *pctrl = platform_get_drvdata(pdev); + int i; + + pctrl->saved_intmask = readl(pctrl->regs + CHV_INTMASK); + + for (i = 0; i < pctrl->community->npins; i++) { + const struct pinctrl_pin_desc *desc; + struct chv_pin_context *ctx; + void __iomem *reg; + + desc = &pctrl->community->pins[i]; + if (chv_pad_locked(pctrl, desc->number)) + continue; + + ctx = &pctrl->saved_pin_context[i]; + + reg = chv_padreg(pctrl, desc->number, CHV_PADCTRL0); + ctx->padctrl0 = readl(reg) & ~CHV_PADCTRL0_GPIORXSTATE; + + reg = chv_padreg(pctrl, desc->number, CHV_PADCTRL1); + ctx->padctrl1 = readl(reg); + } + + return 0; +} + +static int chv_pinctrl_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct chv_pinctrl *pctrl = platform_get_drvdata(pdev); + int i; + + /* + * Mask all interrupts before restoring per-pin configuration + * registers because we don't know in which state BIOS left them + * upon exiting suspend. + */ + chv_writel(0, pctrl->regs + CHV_INTMASK); + + for (i = 0; i < pctrl->community->npins; i++) { + const struct pinctrl_pin_desc *desc; + const struct chv_pin_context *ctx; + void __iomem *reg; + u32 val; + + desc = &pctrl->community->pins[i]; + if (chv_pad_locked(pctrl, desc->number)) + continue; + + ctx = &pctrl->saved_pin_context[i]; + + /* Only restore if our saved state differs from the current */ + reg = chv_padreg(pctrl, desc->number, CHV_PADCTRL0); + val = readl(reg) & ~CHV_PADCTRL0_GPIORXSTATE; + if (ctx->padctrl0 != val) { + chv_writel(ctx->padctrl0, reg); + dev_dbg(pctrl->dev, "restored pin %2u ctrl0 0x%08x\n", + desc->number, readl(reg)); + } + + reg = chv_padreg(pctrl, desc->number, CHV_PADCTRL1); + val = readl(reg); + if (ctx->padctrl1 != val) { + chv_writel(ctx->padctrl1, reg); + dev_dbg(pctrl->dev, "restored pin %2u ctrl1 0x%08x\n", + desc->number, readl(reg)); + } + } + + /* + * Now that all pins are restored to known state, we can restore + * the interrupt mask register as well. + */ + chv_writel(0xffff, pctrl->regs + CHV_INTSTAT); + chv_writel(pctrl->saved_intmask, pctrl->regs + CHV_INTMASK); + + return 0; +} +#endif + +static const struct dev_pm_ops chv_pinctrl_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(chv_pinctrl_suspend, chv_pinctrl_resume) +}; + static const struct acpi_device_id chv_pinctrl_acpi_match[] = { { "INT33FF" }, { } @@ -1497,7 +1613,7 @@ static struct platform_driver chv_pinctrl_driver = { .remove = chv_pinctrl_remove, .driver = { .name = "cherryview-pinctrl", - .owner = THIS_MODULE, + .pm = &chv_pinctrl_pm_ops, .acpi_match_table = chv_pinctrl_acpi_match, }, }; diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile new file mode 100644 index 000000000000..eafc216067a4 --- /dev/null +++ b/drivers/pinctrl/meson/Makefile @@ -0,0 +1,2 @@ +obj-y += pinctrl-meson8.o +obj-y += pinctrl-meson.o diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c new file mode 100644 index 000000000000..a2bf49ce16e7 --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -0,0 +1,761 @@ +/* + * Pin controller and GPIO driver for Amlogic Meson SoCs + * + * Copyright (C) 2014 Beniamino Galvani + * + * This 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * The available pins are organized in banks (A,B,C,D,E,X,Y,Z,AO, + * BOOT,CARD for meson6 and X,Y,DV,H,Z,AO,BOOT,CARD for meson8) and + * each bank has a variable number of pins. + * + * The AO bank is special because it belongs to the Always-On power + * domain which can't be powered off; the bank also uses a set of + * registers different from the other banks. + * + * For each of the two power domains (regular and always-on) there are + * 4 different register ranges that control the following properties + * of the pins: + * 1) pin muxing + * 2) pull enable/disable + * 3) pull up/down + * 4) GPIO direction, output value, input value + * + * In some cases the register ranges for pull enable and pull + * direction are the same and thus there are only 3 register ranges. + * + * Every pinmux group can be enabled by a specific bit in the first + * register range of the domain; when all groups for a given pin are + * disabled the pin acts as a GPIO. + * + * For the pull and GPIO configuration every bank uses a contiguous + * set of bits in the register sets described above; the same register + * can be shared by more banks with different offsets. + * + * In addition to this there are some registers shared between all + * banks that control the IRQ functionality. This feature is not + * supported at the moment by the driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../core.h" +#include "../pinctrl-utils.h" +#include "pinctrl-meson.h" + +/** + * meson_get_bank() - find the bank containing a given pin + * + * @domain: the domain containing the pin + * @pin: the pin number + * @bank: the found bank + * + * Return: 0 on success, a negative value on error + */ +static int meson_get_bank(struct meson_domain *domain, unsigned int pin, + struct meson_bank **bank) +{ + int i; + + for (i = 0; i < domain->data->num_banks; i++) { + if (pin >= domain->data->banks[i].first && + pin <= domain->data->banks[i].last) { + *bank = &domain->data->banks[i]; + return 0; + } + } + + return -EINVAL; +} + +/** + * meson_get_domain_and_bank() - find domain and bank containing a given pin + * + * @pc: Meson pin controller device + * @pin: the pin number + * @domain: the found domain + * @bank: the found bank + * + * Return: 0 on success, a negative value on error + */ +static int meson_get_domain_and_bank(struct meson_pinctrl *pc, unsigned int pin, + struct meson_domain **domain, + struct meson_bank **bank) +{ + struct meson_domain *d; + int i; + + for (i = 0; i < pc->data->num_domains; i++) { + d = &pc->domains[i]; + if (pin >= d->data->pin_base && + pin < d->data->pin_base + d->data->num_pins) { + *domain = d; + return meson_get_bank(d, pin, bank); + } + } + + return -EINVAL; +} + +/** + * meson_calc_reg_and_bit() - calculate register and bit for a pin + * + * @bank: the bank containing the pin + * @pin: the pin number + * @reg_type: the type of register needed (pull-enable, pull, etc...) + * @reg: the computed register offset + * @bit: the computed bit + */ +static void meson_calc_reg_and_bit(struct meson_bank *bank, unsigned int pin, + enum meson_reg_type reg_type, + unsigned int *reg, unsigned int *bit) +{ + struct meson_reg_desc *desc = &bank->regs[reg_type]; + + *reg = desc->reg * 4; + *bit = desc->bit + pin - bank->first; +} + +static int meson_get_groups_count(struct pinctrl_dev *pcdev) +{ + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + + return pc->data->num_groups; +} + +static const char *meson_get_group_name(struct pinctrl_dev *pcdev, + unsigned selector) +{ + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + + return pc->data->groups[selector].name; +} + +static int meson_get_group_pins(struct pinctrl_dev *pcdev, unsigned selector, + const unsigned **pins, unsigned *num_pins) +{ + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + + *pins = pc->data->groups[selector].pins; + *num_pins = pc->data->groups[selector].num_pins; + + return 0; +} + +static void meson_pin_dbg_show(struct pinctrl_dev *pcdev, struct seq_file *s, + unsigned offset) +{ + seq_printf(s, " %s", dev_name(pcdev->dev)); +} + +static const struct pinctrl_ops meson_pctrl_ops = { + .get_groups_count = meson_get_groups_count, + .get_group_name = meson_get_group_name, + .get_group_pins = meson_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinctrl_utils_dt_free_map, + .pin_dbg_show = meson_pin_dbg_show, +}; + +/** + * meson_pmx_disable_other_groups() - disable other groups using a given pin + * + * @pc: meson pin controller device + * @pin: number of the pin + * @sel_group: index of the selected group, or -1 if none + * + * The function disables all pinmux groups using a pin except the + * selected one. If @sel_group is -1 all groups are disabled, leaving + * the pin in GPIO mode. + */ +static void meson_pmx_disable_other_groups(struct meson_pinctrl *pc, + unsigned int pin, int sel_group) +{ + struct meson_pmx_group *group; + struct meson_domain *domain; + int i, j; + + for (i = 0; i < pc->data->num_groups; i++) { + group = &pc->data->groups[i]; + if (group->is_gpio || i == sel_group) + continue; + + for (j = 0; j < group->num_pins; j++) { + if (group->pins[j] == pin) { + /* We have found a group using the pin */ + domain = &pc->domains[group->domain]; + regmap_update_bits(domain->reg_mux, + group->reg * 4, + BIT(group->bit), 0); + } + } + } +} + +static int meson_pmx_set_mux(struct pinctrl_dev *pcdev, unsigned func_num, + unsigned group_num) +{ + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + struct meson_pmx_func *func = &pc->data->funcs[func_num]; + struct meson_pmx_group *group = &pc->data->groups[group_num]; + struct meson_domain *domain = &pc->domains[group->domain]; + int i, ret = 0; + + dev_dbg(pc->dev, "enable function %s, group %s\n", func->name, + group->name); + + /* + * Disable groups using the same pin. + * The selected group is not disabled to avoid glitches. + */ + for (i = 0; i < group->num_pins; i++) + meson_pmx_disable_other_groups(pc, group->pins[i], group_num); + + /* Function 0 (GPIO) doesn't need any additional setting */ + if (func_num) + ret = regmap_update_bits(domain->reg_mux, group->reg * 4, + BIT(group->bit), BIT(group->bit)); + + return ret; +} + +static int meson_pmx_request_gpio(struct pinctrl_dev *pcdev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + + meson_pmx_disable_other_groups(pc, range->pin_base + offset, -1); + + return 0; +} + +static int meson_pmx_get_funcs_count(struct pinctrl_dev *pcdev) +{ + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + + return pc->data->num_funcs; +} + +static const char *meson_pmx_get_func_name(struct pinctrl_dev *pcdev, + unsigned selector) +{ + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + + return pc->data->funcs[selector].name; +} + +static int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + + *groups = pc->data->funcs[selector].groups; + *num_groups = pc->data->funcs[selector].num_groups; + + return 0; +} + +static const struct pinmux_ops meson_pmx_ops = { + .set_mux = meson_pmx_set_mux, + .get_functions_count = meson_pmx_get_funcs_count, + .get_function_name = meson_pmx_get_func_name, + .get_function_groups = meson_pmx_get_groups, + .gpio_request_enable = meson_pmx_request_gpio, +}; + +static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, + unsigned long *configs, unsigned num_configs) +{ + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + struct meson_domain *domain; + struct meson_bank *bank; + enum pin_config_param param; + unsigned int reg, bit; + int i, ret; + u16 arg; + + ret = meson_get_domain_and_bank(pc, pin, &domain, &bank); + if (ret) + return ret; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + dev_dbg(pc->dev, "pin %u: disable bias\n", pin); + + meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); + ret = regmap_update_bits(domain->reg_pull, reg, + BIT(bit), 0); + if (ret) + return ret; + break; + case PIN_CONFIG_BIAS_PULL_UP: + dev_dbg(pc->dev, "pin %u: enable pull-up\n", pin); + + meson_calc_reg_and_bit(bank, pin, REG_PULLEN, + ®, &bit); + ret = regmap_update_bits(domain->reg_pullen, reg, + BIT(bit), BIT(bit)); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); + ret = regmap_update_bits(domain->reg_pull, reg, + BIT(bit), BIT(bit)); + if (ret) + return ret; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + dev_dbg(pc->dev, "pin %u: enable pull-down\n", pin); + + meson_calc_reg_and_bit(bank, pin, REG_PULLEN, + ®, &bit); + ret = regmap_update_bits(domain->reg_pullen, reg, + BIT(bit), BIT(bit)); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); + ret = regmap_update_bits(domain->reg_pull, reg, + BIT(bit), 0); + if (ret) + return ret; + break; + default: + return -ENOTSUPP; + } + } + + return 0; +} + +static int meson_pinconf_get_pull(struct meson_pinctrl *pc, unsigned int pin) +{ + struct meson_domain *domain; + struct meson_bank *bank; + unsigned int reg, bit, val; + int ret, conf; + + ret = meson_get_domain_and_bank(pc, pin, &domain, &bank); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, &bit); + + ret = regmap_read(domain->reg_pullen, reg, &val); + if (ret) + return ret; + + if (!(val & BIT(bit))) { + conf = PIN_CONFIG_BIAS_DISABLE; + } else { + meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); + + ret = regmap_read(domain->reg_pull, reg, &val); + if (ret) + return ret; + + if (val & BIT(bit)) + conf = PIN_CONFIG_BIAS_PULL_UP; + else + conf = PIN_CONFIG_BIAS_PULL_DOWN; + } + + return conf; +} + +static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin, + unsigned long *config) +{ + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + enum pin_config_param param = pinconf_to_config_param(*config); + u16 arg; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + if (meson_pinconf_get_pull(pc, pin) == param) + arg = 1; + else + return -EINVAL; + break; + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + dev_dbg(pc->dev, "pinconf for pin %u is %lu\n", pin, *config); + + return 0; +} + +static int meson_pinconf_group_set(struct pinctrl_dev *pcdev, + unsigned int num_group, + unsigned long *configs, unsigned num_configs) +{ + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + struct meson_pmx_group *group = &pc->data->groups[num_group]; + int i; + + dev_dbg(pc->dev, "set pinconf for group %s\n", group->name); + + for (i = 0; i < group->num_pins; i++) { + meson_pinconf_set(pcdev, group->pins[i], configs, + num_configs); + } + + return 0; +} + +static int meson_pinconf_group_get(struct pinctrl_dev *pcdev, + unsigned int group, unsigned long *config) +{ + return -ENOSYS; +} + +static const struct pinconf_ops meson_pinconf_ops = { + .pin_config_get = meson_pinconf_get, + .pin_config_set = meson_pinconf_set, + .pin_config_group_get = meson_pinconf_group_get, + .pin_config_group_set = meson_pinconf_group_set, + .is_generic = true, +}; + +static inline struct meson_domain *to_meson_domain(struct gpio_chip *chip) +{ + return container_of(chip, struct meson_domain, chip); +} + +static int meson_gpio_request(struct gpio_chip *chip, unsigned gpio) +{ + return pinctrl_request_gpio(chip->base + gpio); +} + +static void meson_gpio_free(struct gpio_chip *chip, unsigned gpio) +{ + struct meson_domain *domain = to_meson_domain(chip); + + pinctrl_free_gpio(domain->data->pin_base + gpio); +} + +static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + struct meson_domain *domain = to_meson_domain(chip); + unsigned int reg, bit, pin; + struct meson_bank *bank; + int ret; + + pin = domain->data->pin_base + gpio; + ret = meson_get_bank(domain, pin, &bank); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_DIR, ®, &bit); + + return regmap_update_bits(domain->reg_gpio, reg, BIT(bit), BIT(bit)); +} + +static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, + int value) +{ + struct meson_domain *domain = to_meson_domain(chip); + unsigned int reg, bit, pin; + struct meson_bank *bank; + int ret; + + pin = domain->data->pin_base + gpio; + ret = meson_get_bank(domain, pin, &bank); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_DIR, ®, &bit); + ret = regmap_update_bits(domain->reg_gpio, reg, BIT(bit), 0); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_OUT, ®, &bit); + return regmap_update_bits(domain->reg_gpio, reg, BIT(bit), + value ? BIT(bit) : 0); +} + +static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) +{ + struct meson_domain *domain = to_meson_domain(chip); + unsigned int reg, bit, pin; + struct meson_bank *bank; + int ret; + + pin = domain->data->pin_base + gpio; + ret = meson_get_bank(domain, pin, &bank); + if (ret) + return; + + meson_calc_reg_and_bit(bank, pin, REG_OUT, ®, &bit); + regmap_update_bits(domain->reg_gpio, reg, BIT(bit), + value ? BIT(bit) : 0); +} + +static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio) +{ + struct meson_domain *domain = to_meson_domain(chip); + unsigned int reg, bit, val, pin; + struct meson_bank *bank; + int ret; + + pin = domain->data->pin_base + gpio; + ret = meson_get_bank(domain, pin, &bank); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_IN, ®, &bit); + regmap_read(domain->reg_gpio, reg, &val); + + return !!(val & BIT(bit)); +} + +static const struct of_device_id meson_pinctrl_dt_match[] = { + { + .compatible = "amlogic,meson8-pinctrl", + .data = &meson8_pinctrl_data, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, meson_pinctrl_dt_match); + +static int meson_gpiolib_register(struct meson_pinctrl *pc) +{ + struct meson_domain *domain; + int i, ret; + + for (i = 0; i < pc->data->num_domains; i++) { + domain = &pc->domains[i]; + + domain->chip.label = domain->data->name; + domain->chip.dev = pc->dev; + domain->chip.request = meson_gpio_request; + domain->chip.free = meson_gpio_free; + domain->chip.direction_input = meson_gpio_direction_input; + domain->chip.direction_output = meson_gpio_direction_output; + domain->chip.get = meson_gpio_get; + domain->chip.set = meson_gpio_set; + domain->chip.base = -1; + domain->chip.ngpio = domain->data->num_pins; + domain->chip.can_sleep = false; + domain->chip.of_node = domain->of_node; + domain->chip.of_gpio_n_cells = 2; + + ret = gpiochip_add(&domain->chip); + if (ret) { + dev_err(pc->dev, "can't add gpio chip %s\n", + domain->data->name); + goto fail; + } + + ret = gpiochip_add_pin_range(&domain->chip, dev_name(pc->dev), + 0, domain->data->pin_base, + domain->chip.ngpio); + if (ret) { + dev_err(pc->dev, "can't add pin range\n"); + goto fail; + } + } + + return 0; +fail: + for (i--; i >= 0; i--) + gpiochip_remove(&pc->domains[i].chip); + + return ret; +} + +static struct meson_domain_data *meson_get_domain_data(struct meson_pinctrl *pc, + struct device_node *np) +{ + int i; + + for (i = 0; i < pc->data->num_domains; i++) { + if (!strcmp(np->name, pc->data->domain_data[i].name)) + return &pc->data->domain_data[i]; + } + + return NULL; +} + +static struct regmap_config meson_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static struct regmap *meson_map_resource(struct meson_pinctrl *pc, + struct device_node *node, char *name) +{ + struct resource res; + void __iomem *base; + int i; + + i = of_property_match_string(node, "reg-names", name); + if (of_address_to_resource(node, i, &res)) + return ERR_PTR(-ENOENT); + + base = devm_ioremap_resource(pc->dev, &res); + if (IS_ERR(base)) + return ERR_CAST(base); + + meson_regmap_config.max_register = resource_size(&res) - 4; + meson_regmap_config.name = devm_kasprintf(pc->dev, GFP_KERNEL, + "%s-%s", node->name, + name); + if (!meson_regmap_config.name) + return ERR_PTR(-ENOMEM); + + return devm_regmap_init_mmio(pc->dev, base, &meson_regmap_config); +} + +static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc, + struct device_node *node) +{ + struct device_node *np; + struct meson_domain *domain; + int i = 0, num_domains = 0; + + for_each_child_of_node(node, np) { + if (!of_find_property(np, "gpio-controller", NULL)) + continue; + num_domains++; + } + + if (num_domains != pc->data->num_domains) { + dev_err(pc->dev, "wrong number of subnodes\n"); + return -EINVAL; + } + + pc->domains = devm_kzalloc(pc->dev, num_domains * + sizeof(struct meson_domain), GFP_KERNEL); + if (!pc->domains) + return -ENOMEM; + + for_each_child_of_node(node, np) { + if (!of_find_property(np, "gpio-controller", NULL)) + continue; + + domain = &pc->domains[i]; + + domain->data = meson_get_domain_data(pc, np); + if (!domain->data) { + dev_err(pc->dev, "domain data not found for node %s\n", + np->name); + return -ENODEV; + } + + domain->of_node = np; + + domain->reg_mux = meson_map_resource(pc, np, "mux"); + if (IS_ERR(domain->reg_mux)) { + dev_err(pc->dev, "mux registers not found\n"); + return PTR_ERR(domain->reg_mux); + } + + domain->reg_pull = meson_map_resource(pc, np, "pull"); + if (IS_ERR(domain->reg_pull)) { + dev_err(pc->dev, "pull registers not found\n"); + return PTR_ERR(domain->reg_pull); + } + + domain->reg_pullen = meson_map_resource(pc, np, "pull-enable"); + /* Use pull region if pull-enable one is not present */ + if (IS_ERR(domain->reg_pullen)) + domain->reg_pullen = domain->reg_pull; + + domain->reg_gpio = meson_map_resource(pc, np, "gpio"); + if (IS_ERR(domain->reg_gpio)) { + dev_err(pc->dev, "gpio registers not found\n"); + return PTR_ERR(domain->reg_gpio); + } + + i++; + } + + return 0; +} + +static int meson_pinctrl_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct device *dev = &pdev->dev; + struct meson_pinctrl *pc; + int ret; + + pc = devm_kzalloc(dev, sizeof(struct meson_pinctrl), GFP_KERNEL); + if (!pc) + return -ENOMEM; + + pc->dev = dev; + match = of_match_node(meson_pinctrl_dt_match, pdev->dev.of_node); + pc->data = (struct meson_pinctrl_data *)match->data; + + ret = meson_pinctrl_parse_dt(pc, pdev->dev.of_node); + if (ret) + return ret; + + pc->desc.name = "pinctrl-meson"; + pc->desc.owner = THIS_MODULE; + pc->desc.pctlops = &meson_pctrl_ops; + pc->desc.pmxops = &meson_pmx_ops; + pc->desc.confops = &meson_pinconf_ops; + pc->desc.pins = pc->data->pins; + pc->desc.npins = pc->data->num_pins; + + pc->pcdev = pinctrl_register(&pc->desc, pc->dev, pc); + if (!pc->pcdev) { + dev_err(pc->dev, "can't register pinctrl device"); + return -EINVAL; + } + + ret = meson_gpiolib_register(pc); + if (ret) { + pinctrl_unregister(pc->pcdev); + return ret; + } + + return 0; +} + +static struct platform_driver meson_pinctrl_driver = { + .probe = meson_pinctrl_probe, + .driver = { + .name = "meson-pinctrl", + .of_match_table = meson_pinctrl_dt_match, + }, +}; +module_platform_driver(meson_pinctrl_driver); + +MODULE_AUTHOR("Beniamino Galvani "); +MODULE_DESCRIPTION("Amlogic Meson pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h new file mode 100644 index 000000000000..bfea8adc7953 --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-meson.h @@ -0,0 +1,209 @@ +/* + * Pin controller and GPIO driver for Amlogic Meson SoCs + * + * Copyright (C) 2014 Beniamino Galvani + * + * This 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +/** + * struct meson_pmx_group - a pinmux group + * + * @name: group name + * @pins: pins in the group + * @num_pins: number of pins in the group + * @is_gpio: whether the group is a single GPIO group + * @reg: register offset for the group in the domain mux registers + * @bit bit index enabling the group + * @domain: index of the domain this group belongs to + */ +struct meson_pmx_group { + const char *name; + const unsigned int *pins; + unsigned int num_pins; + bool is_gpio; + unsigned int reg; + unsigned int bit; + unsigned int domain; +}; + +/** + * struct meson_pmx_func - a pinmux function + * + * @name: function name + * @groups: groups in the function + * @num_groups: number of groups in the function + */ +struct meson_pmx_func { + const char *name; + const char * const *groups; + unsigned int num_groups; +}; + +/** + * struct meson_reg_desc - a register descriptor + * + * @reg: register offset in the regmap + * @bit: bit index in register + * + * The structure describes the information needed to control pull, + * pull-enable, direction, etc. for a single pin + */ +struct meson_reg_desc { + unsigned int reg; + unsigned int bit; +}; + +/** + * enum meson_reg_type - type of registers encoded in @meson_reg_desc + */ +enum meson_reg_type { + REG_PULLEN, + REG_PULL, + REG_DIR, + REG_OUT, + REG_IN, + NUM_REG, +}; + +/** + * struct meson bank + * + * @name: bank name + * @first: first pin of the bank + * @last: last pin of the bank + * @regs: array of register descriptors + * + * A bank represents a set of pins controlled by a contiguous set of + * bits in the domain registers. The structure specifies which bits in + * the regmap control the different functionalities. Each member of + * the @regs array refers to the first pin of the bank. + */ +struct meson_bank { + const char *name; + unsigned int first; + unsigned int last; + struct meson_reg_desc regs[NUM_REG]; +}; + +/** + * struct meson_domain_data - domain platform data + * + * @name: name of the domain + * @banks: set of banks belonging to the domain + * @num_banks: number of banks in the domain + */ +struct meson_domain_data { + const char *name; + struct meson_bank *banks; + unsigned int num_banks; + unsigned int pin_base; + unsigned int num_pins; +}; + +/** + * struct meson_domain + * + * @reg_mux: registers for mux settings + * @reg_pullen: registers for pull-enable settings + * @reg_pull: registers for pull settings + * @reg_gpio: registers for gpio settings + * @chip: gpio chip associated with the domain + * @data; platform data for the domain + * @node: device tree node for the domain + * + * A domain represents a set of banks controlled by the same set of + * registers. + */ +struct meson_domain { + struct regmap *reg_mux; + struct regmap *reg_pullen; + struct regmap *reg_pull; + struct regmap *reg_gpio; + + struct gpio_chip chip; + struct meson_domain_data *data; + struct device_node *of_node; +}; + +struct meson_pinctrl_data { + const struct pinctrl_pin_desc *pins; + struct meson_pmx_group *groups; + struct meson_pmx_func *funcs; + struct meson_domain_data *domain_data; + unsigned int num_pins; + unsigned int num_groups; + unsigned int num_funcs; + unsigned int num_domains; +}; + +struct meson_pinctrl { + struct device *dev; + struct pinctrl_dev *pcdev; + struct pinctrl_desc desc; + struct meson_pinctrl_data *data; + struct meson_domain *domains; +}; + +#define GROUP(grp, r, b) \ + { \ + .name = #grp, \ + .pins = grp ## _pins, \ + .num_pins = ARRAY_SIZE(grp ## _pins), \ + .reg = r, \ + .bit = b, \ + .domain = 0, \ + } + +#define GPIO_GROUP(gpio) \ + { \ + .name = #gpio, \ + .pins = (const unsigned int[]){ PIN_ ## gpio}, \ + .num_pins = 1, \ + .is_gpio = true, \ + } + +#define GROUP_AO(grp, r, b) \ + { \ + .name = #grp, \ + .pins = grp ## _pins, \ + .num_pins = ARRAY_SIZE(grp ## _pins), \ + .reg = r, \ + .bit = b, \ + .domain = 1, \ + } + +#define FUNCTION(fn) \ + { \ + .name = #fn, \ + .groups = fn ## _groups, \ + .num_groups = ARRAY_SIZE(fn ## _groups), \ + } + +#define BANK(n, f, l, per, peb, pr, pb, dr, db, or, ob, ir, ib) \ + { \ + .name = n, \ + .first = f, \ + .last = l, \ + .regs = { \ + [REG_PULLEN] = { per, peb }, \ + [REG_PULL] = { pr, pb }, \ + [REG_DIR] = { dr, db }, \ + [REG_OUT] = { or, ob }, \ + [REG_IN] = { ir, ib }, \ + }, \ + } + +#define MESON_PIN(x) PINCTRL_PIN(PIN_ ## x, #x) + +extern struct meson_pinctrl_data meson8_pinctrl_data; diff --git a/drivers/pinctrl/meson/pinctrl-meson8.c b/drivers/pinctrl/meson/pinctrl-meson8.c new file mode 100644 index 000000000000..f8aa3a281767 --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-meson8.c @@ -0,0 +1,1089 @@ +/* + * Pin controller and GPIO driver for Amlogic Meson8. + * + * Copyright (C) 2014 Beniamino Galvani + * + * This 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "pinctrl-meson.h" + +#define AO_OFFSET 120 + +#define PIN_GPIOX_0 GPIOX_0 +#define PIN_GPIOX_1 GPIOX_1 +#define PIN_GPIOX_2 GPIOX_2 +#define PIN_GPIOX_3 GPIOX_3 +#define PIN_GPIOX_4 GPIOX_4 +#define PIN_GPIOX_5 GPIOX_5 +#define PIN_GPIOX_6 GPIOX_6 +#define PIN_GPIOX_7 GPIOX_7 +#define PIN_GPIOX_8 GPIOX_8 +#define PIN_GPIOX_9 GPIOX_9 +#define PIN_GPIOX_10 GPIOX_10 +#define PIN_GPIOX_11 GPIOX_11 +#define PIN_GPIOX_12 GPIOX_12 +#define PIN_GPIOX_13 GPIOX_13 +#define PIN_GPIOX_14 GPIOX_14 +#define PIN_GPIOX_15 GPIOX_15 +#define PIN_GPIOX_16 GPIOX_16 +#define PIN_GPIOX_17 GPIOX_17 +#define PIN_GPIOX_18 GPIOX_18 +#define PIN_GPIOX_19 GPIOX_19 +#define PIN_GPIOX_20 GPIOX_20 +#define PIN_GPIOX_21 GPIOX_21 +#define PIN_GPIOY_0 GPIOY_0 +#define PIN_GPIOY_1 GPIOY_1 +#define PIN_GPIOY_2 GPIOY_2 +#define PIN_GPIOY_3 GPIOY_3 +#define PIN_GPIOY_4 GPIOY_4 +#define PIN_GPIOY_5 GPIOY_5 +#define PIN_GPIOY_6 GPIOY_6 +#define PIN_GPIOY_7 GPIOY_7 +#define PIN_GPIOY_8 GPIOY_8 +#define PIN_GPIOY_9 GPIOY_9 +#define PIN_GPIOY_10 GPIOY_10 +#define PIN_GPIOY_11 GPIOY_11 +#define PIN_GPIOY_12 GPIOY_12 +#define PIN_GPIOY_13 GPIOY_13 +#define PIN_GPIOY_14 GPIOY_14 +#define PIN_GPIOY_15 GPIOY_15 +#define PIN_GPIOY_16 GPIOY_16 +#define PIN_GPIODV_0 GPIODV_0 +#define PIN_GPIODV_1 GPIODV_1 +#define PIN_GPIODV_2 GPIODV_2 +#define PIN_GPIODV_3 GPIODV_3 +#define PIN_GPIODV_4 GPIODV_4 +#define PIN_GPIODV_5 GPIODV_5 +#define PIN_GPIODV_6 GPIODV_6 +#define PIN_GPIODV_7 GPIODV_7 +#define PIN_GPIODV_8 GPIODV_8 +#define PIN_GPIODV_9 GPIODV_9 +#define PIN_GPIODV_10 GPIODV_10 +#define PIN_GPIODV_11 GPIODV_11 +#define PIN_GPIODV_12 GPIODV_12 +#define PIN_GPIODV_13 GPIODV_13 +#define PIN_GPIODV_14 GPIODV_14 +#define PIN_GPIODV_15 GPIODV_15 +#define PIN_GPIODV_16 GPIODV_16 +#define PIN_GPIODV_17 GPIODV_17 +#define PIN_GPIODV_18 GPIODV_18 +#define PIN_GPIODV_19 GPIODV_19 +#define PIN_GPIODV_20 GPIODV_20 +#define PIN_GPIODV_21 GPIODV_21 +#define PIN_GPIODV_22 GPIODV_22 +#define PIN_GPIODV_23 GPIODV_23 +#define PIN_GPIODV_24 GPIODV_24 +#define PIN_GPIODV_25 GPIODV_25 +#define PIN_GPIODV_26 GPIODV_26 +#define PIN_GPIODV_27 GPIODV_27 +#define PIN_GPIODV_28 GPIODV_28 +#define PIN_GPIODV_29 GPIODV_29 +#define PIN_GPIOH_0 GPIOH_0 +#define PIN_GPIOH_1 GPIOH_1 +#define PIN_GPIOH_2 GPIOH_2 +#define PIN_GPIOH_3 GPIOH_3 +#define PIN_GPIOH_4 GPIOH_4 +#define PIN_GPIOH_5 GPIOH_5 +#define PIN_GPIOH_6 GPIOH_6 +#define PIN_GPIOH_7 GPIOH_7 +#define PIN_GPIOH_8 GPIOH_8 +#define PIN_GPIOH_9 GPIOH_9 +#define PIN_GPIOZ_0 GPIOZ_0 +#define PIN_GPIOZ_1 GPIOZ_1 +#define PIN_GPIOZ_2 GPIOZ_2 +#define PIN_GPIOZ_3 GPIOZ_3 +#define PIN_GPIOZ_4 GPIOZ_4 +#define PIN_GPIOZ_5 GPIOZ_5 +#define PIN_GPIOZ_6 GPIOZ_6 +#define PIN_GPIOZ_7 GPIOZ_7 +#define PIN_GPIOZ_8 GPIOZ_8 +#define PIN_GPIOZ_9 GPIOZ_9 +#define PIN_GPIOZ_10 GPIOZ_10 +#define PIN_GPIOZ_11 GPIOZ_11 +#define PIN_GPIOZ_12 GPIOZ_12 +#define PIN_GPIOZ_13 GPIOZ_13 +#define PIN_GPIOZ_14 GPIOZ_14 +#define PIN_CARD_0 CARD_0 +#define PIN_CARD_1 CARD_1 +#define PIN_CARD_2 CARD_2 +#define PIN_CARD_3 CARD_3 +#define PIN_CARD_4 CARD_4 +#define PIN_CARD_5 CARD_5 +#define PIN_CARD_6 CARD_6 +#define PIN_BOOT_0 BOOT_0 +#define PIN_BOOT_1 BOOT_1 +#define PIN_BOOT_2 BOOT_2 +#define PIN_BOOT_3 BOOT_3 +#define PIN_BOOT_4 BOOT_4 +#define PIN_BOOT_5 BOOT_5 +#define PIN_BOOT_6 BOOT_6 +#define PIN_BOOT_7 BOOT_7 +#define PIN_BOOT_8 BOOT_8 +#define PIN_BOOT_9 BOOT_9 +#define PIN_BOOT_10 BOOT_10 +#define PIN_BOOT_11 BOOT_11 +#define PIN_BOOT_12 BOOT_12 +#define PIN_BOOT_13 BOOT_13 +#define PIN_BOOT_14 BOOT_14 +#define PIN_BOOT_15 BOOT_15 +#define PIN_BOOT_16 BOOT_16 +#define PIN_BOOT_17 BOOT_17 +#define PIN_BOOT_18 BOOT_18 + +#define PIN_GPIOAO_0 (AO_OFFSET + GPIOAO_0) +#define PIN_GPIOAO_1 (AO_OFFSET + GPIOAO_1) +#define PIN_GPIOAO_2 (AO_OFFSET + GPIOAO_2) +#define PIN_GPIOAO_3 (AO_OFFSET + GPIOAO_3) +#define PIN_GPIOAO_4 (AO_OFFSET + GPIOAO_4) +#define PIN_GPIOAO_5 (AO_OFFSET + GPIOAO_5) +#define PIN_GPIOAO_6 (AO_OFFSET + GPIOAO_6) +#define PIN_GPIOAO_7 (AO_OFFSET + GPIOAO_7) +#define PIN_GPIOAO_8 (AO_OFFSET + GPIOAO_8) +#define PIN_GPIOAO_9 (AO_OFFSET + GPIOAO_9) +#define PIN_GPIOAO_10 (AO_OFFSET + GPIOAO_10) +#define PIN_GPIOAO_11 (AO_OFFSET + GPIOAO_11) +#define PIN_GPIOAO_12 (AO_OFFSET + GPIOAO_12) +#define PIN_GPIOAO_13 (AO_OFFSET + GPIOAO_13) +#define PIN_GPIO_BSD_EN (AO_OFFSET + GPIO_BSD_EN) +#define PIN_GPIO_TEST_N (AO_OFFSET + GPIO_TEST_N) + +static const struct pinctrl_pin_desc meson8_pins[] = { + MESON_PIN(GPIOX_0), + MESON_PIN(GPIOX_1), + MESON_PIN(GPIOX_2), + MESON_PIN(GPIOX_3), + MESON_PIN(GPIOX_4), + MESON_PIN(GPIOX_5), + MESON_PIN(GPIOX_6), + MESON_PIN(GPIOX_7), + MESON_PIN(GPIOX_8), + MESON_PIN(GPIOX_9), + MESON_PIN(GPIOX_10), + MESON_PIN(GPIOX_11), + MESON_PIN(GPIOX_12), + MESON_PIN(GPIOX_13), + MESON_PIN(GPIOX_14), + MESON_PIN(GPIOX_15), + MESON_PIN(GPIOX_16), + MESON_PIN(GPIOX_17), + MESON_PIN(GPIOX_18), + MESON_PIN(GPIOX_19), + MESON_PIN(GPIOX_20), + MESON_PIN(GPIOX_21), + MESON_PIN(GPIOY_0), + MESON_PIN(GPIOY_1), + MESON_PIN(GPIOY_2), + MESON_PIN(GPIOY_3), + MESON_PIN(GPIOY_4), + MESON_PIN(GPIOY_5), + MESON_PIN(GPIOY_6), + MESON_PIN(GPIOY_7), + MESON_PIN(GPIOY_8), + MESON_PIN(GPIOY_9), + MESON_PIN(GPIOY_10), + MESON_PIN(GPIOY_11), + MESON_PIN(GPIOY_12), + MESON_PIN(GPIOY_13), + MESON_PIN(GPIOY_14), + MESON_PIN(GPIOY_15), + MESON_PIN(GPIOY_16), + MESON_PIN(GPIODV_0), + MESON_PIN(GPIODV_1), + MESON_PIN(GPIODV_2), + MESON_PIN(GPIODV_3), + MESON_PIN(GPIODV_4), + MESON_PIN(GPIODV_5), + MESON_PIN(GPIODV_6), + MESON_PIN(GPIODV_7), + MESON_PIN(GPIODV_8), + MESON_PIN(GPIODV_9), + MESON_PIN(GPIODV_10), + MESON_PIN(GPIODV_11), + MESON_PIN(GPIODV_12), + MESON_PIN(GPIODV_13), + MESON_PIN(GPIODV_14), + MESON_PIN(GPIODV_15), + MESON_PIN(GPIODV_16), + MESON_PIN(GPIODV_17), + MESON_PIN(GPIODV_18), + MESON_PIN(GPIODV_19), + MESON_PIN(GPIODV_20), + MESON_PIN(GPIODV_21), + MESON_PIN(GPIODV_22), + MESON_PIN(GPIODV_23), + MESON_PIN(GPIODV_24), + MESON_PIN(GPIODV_25), + MESON_PIN(GPIODV_26), + MESON_PIN(GPIODV_27), + MESON_PIN(GPIODV_28), + MESON_PIN(GPIODV_29), + MESON_PIN(GPIOH_0), + MESON_PIN(GPIOH_1), + MESON_PIN(GPIOH_2), + MESON_PIN(GPIOH_3), + MESON_PIN(GPIOH_4), + MESON_PIN(GPIOH_5), + MESON_PIN(GPIOH_6), + MESON_PIN(GPIOH_7), + MESON_PIN(GPIOH_8), + MESON_PIN(GPIOH_9), + MESON_PIN(GPIOZ_0), + MESON_PIN(GPIOZ_1), + MESON_PIN(GPIOZ_2), + MESON_PIN(GPIOZ_3), + MESON_PIN(GPIOZ_4), + MESON_PIN(GPIOZ_5), + MESON_PIN(GPIOZ_6), + MESON_PIN(GPIOZ_7), + MESON_PIN(GPIOZ_8), + MESON_PIN(GPIOZ_9), + MESON_PIN(GPIOZ_10), + MESON_PIN(GPIOZ_11), + MESON_PIN(GPIOZ_12), + MESON_PIN(GPIOZ_13), + MESON_PIN(GPIOZ_14), + MESON_PIN(CARD_0), + MESON_PIN(CARD_1), + MESON_PIN(CARD_2), + MESON_PIN(CARD_3), + MESON_PIN(CARD_4), + MESON_PIN(CARD_5), + MESON_PIN(CARD_6), + MESON_PIN(BOOT_0), + MESON_PIN(BOOT_1), + MESON_PIN(BOOT_2), + MESON_PIN(BOOT_3), + MESON_PIN(BOOT_4), + MESON_PIN(BOOT_5), + MESON_PIN(BOOT_6), + MESON_PIN(BOOT_7), + MESON_PIN(BOOT_8), + MESON_PIN(BOOT_9), + MESON_PIN(BOOT_10), + MESON_PIN(BOOT_11), + MESON_PIN(BOOT_12), + MESON_PIN(BOOT_13), + MESON_PIN(BOOT_14), + MESON_PIN(BOOT_15), + MESON_PIN(BOOT_16), + MESON_PIN(BOOT_17), + MESON_PIN(BOOT_18), + MESON_PIN(GPIOAO_0), + MESON_PIN(GPIOAO_1), + MESON_PIN(GPIOAO_2), + MESON_PIN(GPIOAO_3), + MESON_PIN(GPIOAO_4), + MESON_PIN(GPIOAO_5), + MESON_PIN(GPIOAO_6), + MESON_PIN(GPIOAO_7), + MESON_PIN(GPIOAO_8), + MESON_PIN(GPIOAO_9), + MESON_PIN(GPIOAO_10), + MESON_PIN(GPIOAO_11), + MESON_PIN(GPIOAO_12), + MESON_PIN(GPIOAO_13), + MESON_PIN(GPIO_BSD_EN), + MESON_PIN(GPIO_TEST_N), +}; + +/* bank X */ +static const unsigned int sd_d0_a_pins[] = { PIN_GPIOX_0 }; +static const unsigned int sd_d1_a_pins[] = { PIN_GPIOX_1 }; +static const unsigned int sd_d2_a_pins[] = { PIN_GPIOX_2 }; +static const unsigned int sd_d3_a_pins[] = { PIN_GPIOX_3 }; +static const unsigned int sd_clk_a_pins[] = { PIN_GPIOX_8 }; +static const unsigned int sd_cmd_a_pins[] = { PIN_GPIOX_9 }; + +static const unsigned int sdxc_d0_a_pins[] = { PIN_GPIOX_0 }; +static const unsigned int sdxc_d13_a_pins[] = { PIN_GPIOX_1, PIN_GPIOX_2, + PIN_GPIOX_3 }; +static const unsigned int sdxc_d47_a_pins[] = { PIN_GPIOX_4, PIN_GPIOX_5, + PIN_GPIOX_6, PIN_GPIOX_7 }; +static const unsigned int sdxc_clk_a_pins[] = { PIN_GPIOX_8 }; +static const unsigned int sdxc_cmd_a_pins[] = { PIN_GPIOX_9 }; + +static const unsigned int pcm_out_a_pins[] = { PIN_GPIOX_4 }; +static const unsigned int pcm_in_a_pins[] = { PIN_GPIOX_5 }; +static const unsigned int pcm_fs_a_pins[] = { PIN_GPIOX_6 }; +static const unsigned int pcm_clk_a_pins[] = { PIN_GPIOX_7 }; + +static const unsigned int uart_tx_a0_pins[] = { PIN_GPIOX_4 }; +static const unsigned int uart_rx_a0_pins[] = { PIN_GPIOX_5 }; +static const unsigned int uart_cts_a0_pins[] = { PIN_GPIOX_6 }; +static const unsigned int uart_rts_a0_pins[] = { PIN_GPIOX_7 }; + +static const unsigned int uart_tx_a1_pins[] = { PIN_GPIOX_12 }; +static const unsigned int uart_rx_a1_pins[] = { PIN_GPIOX_13 }; +static const unsigned int uart_cts_a1_pins[] = { PIN_GPIOX_14 }; +static const unsigned int uart_rts_a1_pins[] = { PIN_GPIOX_15 }; + +static const unsigned int uart_tx_b0_pins[] = { PIN_GPIOX_16 }; +static const unsigned int uart_rx_b0_pins[] = { PIN_GPIOX_17 }; +static const unsigned int uart_cts_b0_pins[] = { PIN_GPIOX_18 }; +static const unsigned int uart_rts_b0_pins[] = { PIN_GPIOX_19 }; + +static const unsigned int iso7816_det_pins[] = { PIN_GPIOX_16 }; +static const unsigned int iso7816_reset_pins[] = { PIN_GPIOX_17 }; +static const unsigned int iso7816_clk_pins[] = { PIN_GPIOX_18 }; +static const unsigned int iso7816_data_pins[] = { PIN_GPIOX_19 }; + +static const unsigned int i2c_sda_d0_pins[] = { PIN_GPIOX_16 }; +static const unsigned int i2c_sck_d0_pins[] = { PIN_GPIOX_17 }; + +static const unsigned int xtal_32k_out_pins[] = { PIN_GPIOX_10 }; +static const unsigned int xtal_24m_out_pins[] = { PIN_GPIOX_11 }; + +/* bank Y */ +static const unsigned int uart_tx_c_pins[] = { PIN_GPIOY_0 }; +static const unsigned int uart_rx_c_pins[] = { PIN_GPIOY_1 }; +static const unsigned int uart_cts_c_pins[] = { PIN_GPIOY_2 }; +static const unsigned int uart_rts_c_pins[] = { PIN_GPIOY_3 }; + +static const unsigned int pcm_out_b_pins[] = { PIN_GPIOY_4 }; +static const unsigned int pcm_in_b_pins[] = { PIN_GPIOY_5 }; +static const unsigned int pcm_fs_b_pins[] = { PIN_GPIOY_6 }; +static const unsigned int pcm_clk_b_pins[] = { PIN_GPIOY_7 }; + +static const unsigned int i2c_sda_c0_pins[] = { PIN_GPIOY_0 }; +static const unsigned int i2c_sck_c0_pins[] = { PIN_GPIOY_1 }; + +/* bank DV */ +static const unsigned int dvin_rgb_pins[] = { PIN_GPIODV_0, PIN_GPIODV_1, + PIN_GPIODV_2, PIN_GPIODV_3, + PIN_GPIODV_4, PIN_GPIODV_5, + PIN_GPIODV_6, PIN_GPIODV_7, + PIN_GPIODV_8, PIN_GPIODV_9, + PIN_GPIODV_10, PIN_GPIODV_11, + PIN_GPIODV_12, PIN_GPIODV_13, + PIN_GPIODV_14, PIN_GPIODV_15, + PIN_GPIODV_16, PIN_GPIODV_17, + PIN_GPIODV_18, PIN_GPIODV_19, + PIN_GPIODV_20, PIN_GPIODV_21, + PIN_GPIODV_22, PIN_GPIODV_23 }; +static const unsigned int dvin_vs_pins[] = { PIN_GPIODV_24 }; +static const unsigned int dvin_hs_pins[] = { PIN_GPIODV_25 }; +static const unsigned int dvin_clk_pins[] = { PIN_GPIODV_26 }; +static const unsigned int dvin_de_pins[] = { PIN_GPIODV_27 }; + +static const unsigned int enc_0_pins[] = { PIN_GPIODV_0 }; +static const unsigned int enc_1_pins[] = { PIN_GPIODV_1 }; +static const unsigned int enc_2_pins[] = { PIN_GPIODV_2 }; +static const unsigned int enc_3_pins[] = { PIN_GPIODV_3 }; +static const unsigned int enc_4_pins[] = { PIN_GPIODV_4 }; +static const unsigned int enc_5_pins[] = { PIN_GPIODV_5 }; +static const unsigned int enc_6_pins[] = { PIN_GPIODV_6 }; +static const unsigned int enc_7_pins[] = { PIN_GPIODV_7 }; +static const unsigned int enc_8_pins[] = { PIN_GPIODV_8 }; +static const unsigned int enc_9_pins[] = { PIN_GPIODV_9 }; +static const unsigned int enc_10_pins[] = { PIN_GPIODV_10 }; +static const unsigned int enc_11_pins[] = { PIN_GPIODV_11 }; +static const unsigned int enc_12_pins[] = { PIN_GPIODV_12 }; +static const unsigned int enc_13_pins[] = { PIN_GPIODV_13 }; +static const unsigned int enc_14_pins[] = { PIN_GPIODV_14 }; +static const unsigned int enc_15_pins[] = { PIN_GPIODV_15 }; +static const unsigned int enc_16_pins[] = { PIN_GPIODV_16 }; +static const unsigned int enc_17_pins[] = { PIN_GPIODV_17 }; + +static const unsigned int uart_tx_b1_pins[] = { PIN_GPIODV_24 }; +static const unsigned int uart_rx_b1_pins[] = { PIN_GPIODV_25 }; +static const unsigned int uart_cts_b1_pins[] = { PIN_GPIODV_26 }; +static const unsigned int uart_rts_b1_pins[] = { PIN_GPIODV_27 }; + +static const unsigned int vga_vs_pins[] = { PIN_GPIODV_24 }; +static const unsigned int vga_hs_pins[] = { PIN_GPIODV_25 }; + +/* bank H */ +static const unsigned int hdmi_hpd_pins[] = { PIN_GPIOH_0 }; +static const unsigned int hdmi_sda_pins[] = { PIN_GPIOH_1 }; +static const unsigned int hdmi_scl_pins[] = { PIN_GPIOH_2 }; +static const unsigned int hdmi_cec_pins[] = { PIN_GPIOH_3 }; + +static const unsigned int spi_ss0_0_pins[] = { PIN_GPIOH_3 }; +static const unsigned int spi_miso_0_pins[] = { PIN_GPIOH_4 }; +static const unsigned int spi_mosi_0_pins[] = { PIN_GPIOH_5 }; +static const unsigned int spi_sclk_0_pins[] = { PIN_GPIOH_6 }; + +static const unsigned int i2c_sda_d1_pins[] = { PIN_GPIOH_7 }; +static const unsigned int i2c_sck_d1_pins[] = { PIN_GPIOH_8 }; + +/* bank Z */ +static const unsigned int spi_ss0_1_pins[] = { PIN_GPIOZ_9 }; +static const unsigned int spi_ss1_1_pins[] = { PIN_GPIOZ_10 }; +static const unsigned int spi_sclk_1_pins[] = { PIN_GPIOZ_11 }; +static const unsigned int spi_mosi_1_pins[] = { PIN_GPIOZ_12 }; +static const unsigned int spi_miso_1_pins[] = { PIN_GPIOZ_13 }; +static const unsigned int spi_ss2_1_pins[] = { PIN_GPIOZ_14 }; + +static const unsigned int eth_tx_clk_50m_pins[] = { PIN_GPIOZ_4 }; +static const unsigned int eth_tx_en_pins[] = { PIN_GPIOZ_5 }; +static const unsigned int eth_txd1_pins[] = { PIN_GPIOZ_6 }; +static const unsigned int eth_txd0_pins[] = { PIN_GPIOZ_7 }; +static const unsigned int eth_rx_clk_in_pins[] = { PIN_GPIOZ_8 }; +static const unsigned int eth_rx_dv_pins[] = { PIN_GPIOZ_9 }; +static const unsigned int eth_rxd1_pins[] = { PIN_GPIOZ_10 }; +static const unsigned int eth_rxd0_pins[] = { PIN_GPIOZ_11 }; +static const unsigned int eth_mdio_pins[] = { PIN_GPIOZ_12 }; +static const unsigned int eth_mdc_pins[] = { PIN_GPIOZ_13 }; + +static const unsigned int i2c_sda_a0_pins[] = { PIN_GPIOZ_0 }; +static const unsigned int i2c_sck_a0_pins[] = { PIN_GPIOZ_1 }; + +static const unsigned int i2c_sda_b_pins[] = { PIN_GPIOZ_2 }; +static const unsigned int i2c_sck_b_pins[] = { PIN_GPIOZ_3 }; + +static const unsigned int i2c_sda_c1_pins[] = { PIN_GPIOZ_4 }; +static const unsigned int i2c_sck_c1_pins[] = { PIN_GPIOZ_5 }; + +static const unsigned int i2c_sda_a1_pins[] = { PIN_GPIOZ_0 }; +static const unsigned int i2c_sck_a1_pins[] = { PIN_GPIOZ_1 }; + +static const unsigned int i2c_sda_a2_pins[] = { PIN_GPIOZ_0 }; +static const unsigned int i2c_sck_a2_pins[] = { PIN_GPIOZ_1 }; + +/* bank BOOT */ +static const unsigned int sd_d0_c_pins[] = { PIN_BOOT_0 }; +static const unsigned int sd_d1_c_pins[] = { PIN_BOOT_1 }; +static const unsigned int sd_d2_c_pins[] = { PIN_BOOT_2 }; +static const unsigned int sd_d3_c_pins[] = { PIN_BOOT_3 }; +static const unsigned int sd_cmd_c_pins[] = { PIN_BOOT_16 }; +static const unsigned int sd_clk_c_pins[] = { PIN_BOOT_17 }; + +static const unsigned int sdxc_d0_c_pins[] = { PIN_BOOT_0}; +static const unsigned int sdxc_d13_c_pins[] = { PIN_BOOT_1, PIN_BOOT_2, + PIN_BOOT_3 }; +static const unsigned int sdxc_d47_c_pins[] = { PIN_BOOT_4, PIN_BOOT_5, + PIN_BOOT_6, PIN_BOOT_7 }; +static const unsigned int sdxc_cmd_c_pins[] = { PIN_BOOT_16 }; +static const unsigned int sdxc_clk_c_pins[] = { PIN_BOOT_17 }; + +static const unsigned int nand_io_pins[] = { PIN_BOOT_0, PIN_BOOT_1, + PIN_BOOT_2, PIN_BOOT_3, + PIN_BOOT_4, PIN_BOOT_5, + PIN_BOOT_6, PIN_BOOT_7 }; +static const unsigned int nand_io_ce0_pins[] = { PIN_BOOT_8 }; +static const unsigned int nand_io_ce1_pins[] = { PIN_BOOT_9 }; +static const unsigned int nand_io_rb0_pins[] = { PIN_BOOT_10 }; +static const unsigned int nand_ale_pins[] = { PIN_BOOT_11 }; +static const unsigned int nand_cle_pins[] = { PIN_BOOT_12 }; +static const unsigned int nand_wen_clk_pins[] = { PIN_BOOT_13 }; +static const unsigned int nand_ren_clk_pins[] = { PIN_BOOT_14 }; +static const unsigned int nand_dqs_pins[] = { PIN_BOOT_15 }; +static const unsigned int nand_ce2_pins[] = { PIN_BOOT_16 }; +static const unsigned int nand_ce3_pins[] = { PIN_BOOT_17 }; + +static const unsigned int nor_d_pins[] = { PIN_BOOT_11 }; +static const unsigned int nor_q_pins[] = { PIN_BOOT_12 }; +static const unsigned int nor_c_pins[] = { PIN_BOOT_13 }; +static const unsigned int nor_cs_pins[] = { PIN_BOOT_18 }; + +/* bank CARD */ +static const unsigned int sd_d1_b_pins[] = { PIN_CARD_0 }; +static const unsigned int sd_d0_b_pins[] = { PIN_CARD_1 }; +static const unsigned int sd_clk_b_pins[] = { PIN_CARD_2 }; +static const unsigned int sd_cmd_b_pins[] = { PIN_CARD_3 }; +static const unsigned int sd_d3_b_pins[] = { PIN_CARD_4 }; +static const unsigned int sd_d2_b_pins[] = { PIN_CARD_5 }; + +static const unsigned int sdxc_d13_b_pins[] = { PIN_CARD_0, PIN_CARD_4, + PIN_CARD_5 }; +static const unsigned int sdxc_d0_b_pins[] = { PIN_CARD_1 }; +static const unsigned int sdxc_clk_b_pins[] = { PIN_CARD_2 }; +static const unsigned int sdxc_cmd_b_pins[] = { PIN_CARD_3 }; + +/* bank AO */ +static const unsigned int uart_tx_ao_a_pins[] = { PIN_GPIOAO_0 }; +static const unsigned int uart_rx_ao_a_pins[] = { PIN_GPIOAO_1 }; +static const unsigned int uart_cts_ao_a_pins[] = { PIN_GPIOAO_2 }; +static const unsigned int uart_rts_ao_a_pins[] = { PIN_GPIOAO_3 }; + +static const unsigned int remote_input_pins[] = { PIN_GPIOAO_7 }; + +static const unsigned int i2c_slave_sck_ao_pins[] = { PIN_GPIOAO_4 }; +static const unsigned int i2c_slave_sda_ao_pins[] = { PIN_GPIOAO_5 }; + +static const unsigned int uart_tx_ao_b0_pins[] = { PIN_GPIOAO_0 }; +static const unsigned int uart_rx_ao_b0_pins[] = { PIN_GPIOAO_1 }; + +static const unsigned int uart_tx_ao_b1_pins[] = { PIN_GPIOAO_4 }; +static const unsigned int uart_rx_ao_b1_pins[] = { PIN_GPIOAO_5 }; + +static const unsigned int i2c_mst_sck_ao_pins[] = { PIN_GPIOAO_4 }; +static const unsigned int i2c_mst_sda_ao_pins[] = { PIN_GPIOAO_5 }; + +static struct meson_pmx_group meson8_groups[] = { + GPIO_GROUP(GPIOX_0), + GPIO_GROUP(GPIOX_1), + GPIO_GROUP(GPIOX_2), + GPIO_GROUP(GPIOX_3), + GPIO_GROUP(GPIOX_4), + GPIO_GROUP(GPIOX_5), + GPIO_GROUP(GPIOX_6), + GPIO_GROUP(GPIOX_7), + GPIO_GROUP(GPIOX_8), + GPIO_GROUP(GPIOX_9), + GPIO_GROUP(GPIOX_10), + GPIO_GROUP(GPIOX_11), + GPIO_GROUP(GPIOX_12), + GPIO_GROUP(GPIOX_13), + GPIO_GROUP(GPIOX_14), + GPIO_GROUP(GPIOX_15), + GPIO_GROUP(GPIOX_16), + GPIO_GROUP(GPIOX_17), + GPIO_GROUP(GPIOX_18), + GPIO_GROUP(GPIOX_19), + GPIO_GROUP(GPIOX_20), + GPIO_GROUP(GPIOX_21), + GPIO_GROUP(GPIOY_0), + GPIO_GROUP(GPIOY_1), + GPIO_GROUP(GPIOY_2), + GPIO_GROUP(GPIOY_3), + GPIO_GROUP(GPIOY_4), + GPIO_GROUP(GPIOY_5), + GPIO_GROUP(GPIOY_6), + GPIO_GROUP(GPIOY_7), + GPIO_GROUP(GPIOY_8), + GPIO_GROUP(GPIOY_9), + GPIO_GROUP(GPIOY_10), + GPIO_GROUP(GPIOY_11), + GPIO_GROUP(GPIOY_12), + GPIO_GROUP(GPIOY_13), + GPIO_GROUP(GPIOY_14), + GPIO_GROUP(GPIOY_15), + GPIO_GROUP(GPIOY_16), + GPIO_GROUP(GPIODV_0), + GPIO_GROUP(GPIODV_1), + GPIO_GROUP(GPIODV_2), + GPIO_GROUP(GPIODV_3), + GPIO_GROUP(GPIODV_4), + GPIO_GROUP(GPIODV_5), + GPIO_GROUP(GPIODV_6), + GPIO_GROUP(GPIODV_7), + GPIO_GROUP(GPIODV_8), + GPIO_GROUP(GPIODV_9), + GPIO_GROUP(GPIODV_10), + GPIO_GROUP(GPIODV_11), + GPIO_GROUP(GPIODV_12), + GPIO_GROUP(GPIODV_13), + GPIO_GROUP(GPIODV_14), + GPIO_GROUP(GPIODV_15), + GPIO_GROUP(GPIODV_16), + GPIO_GROUP(GPIODV_17), + GPIO_GROUP(GPIODV_18), + GPIO_GROUP(GPIODV_19), + GPIO_GROUP(GPIODV_20), + GPIO_GROUP(GPIODV_21), + GPIO_GROUP(GPIODV_22), + GPIO_GROUP(GPIODV_23), + GPIO_GROUP(GPIODV_24), + GPIO_GROUP(GPIODV_25), + GPIO_GROUP(GPIODV_26), + GPIO_GROUP(GPIODV_27), + GPIO_GROUP(GPIODV_28), + GPIO_GROUP(GPIODV_29), + GPIO_GROUP(GPIOH_0), + GPIO_GROUP(GPIOH_1), + GPIO_GROUP(GPIOH_2), + GPIO_GROUP(GPIOH_3), + GPIO_GROUP(GPIOH_4), + GPIO_GROUP(GPIOH_5), + GPIO_GROUP(GPIOH_6), + GPIO_GROUP(GPIOH_7), + GPIO_GROUP(GPIOH_8), + GPIO_GROUP(GPIOH_9), + GPIO_GROUP(GPIOZ_0), + GPIO_GROUP(GPIOZ_1), + GPIO_GROUP(GPIOZ_2), + GPIO_GROUP(GPIOZ_3), + GPIO_GROUP(GPIOZ_4), + GPIO_GROUP(GPIOZ_5), + GPIO_GROUP(GPIOZ_6), + GPIO_GROUP(GPIOZ_7), + GPIO_GROUP(GPIOZ_8), + GPIO_GROUP(GPIOZ_9), + GPIO_GROUP(GPIOZ_10), + GPIO_GROUP(GPIOZ_11), + GPIO_GROUP(GPIOZ_12), + GPIO_GROUP(GPIOZ_13), + GPIO_GROUP(GPIOZ_14), + GPIO_GROUP(GPIOAO_0), + GPIO_GROUP(GPIOAO_1), + GPIO_GROUP(GPIOAO_2), + GPIO_GROUP(GPIOAO_3), + GPIO_GROUP(GPIOAO_4), + GPIO_GROUP(GPIOAO_5), + GPIO_GROUP(GPIOAO_6), + GPIO_GROUP(GPIOAO_7), + GPIO_GROUP(GPIOAO_8), + GPIO_GROUP(GPIOAO_9), + GPIO_GROUP(GPIOAO_10), + GPIO_GROUP(GPIOAO_11), + GPIO_GROUP(GPIOAO_12), + GPIO_GROUP(GPIOAO_13), + GPIO_GROUP(GPIO_BSD_EN), + GPIO_GROUP(GPIO_TEST_N), + + /* bank X */ + GROUP(sd_d0_a, 8, 5), + GROUP(sd_d1_a, 8, 4), + GROUP(sd_d2_a, 8, 3), + GROUP(sd_d3_a, 8, 2), + GROUP(sd_clk_a, 8, 1), + GROUP(sd_cmd_a, 8, 0), + + GROUP(sdxc_d0_a, 5, 14), + GROUP(sdxc_d13_a, 5, 13), + GROUP(sdxc_d47_a, 5, 12), + GROUP(sdxc_clk_a, 5, 11), + GROUP(sdxc_cmd_a, 5, 10), + + GROUP(pcm_out_a, 3, 30), + GROUP(pcm_in_a, 3, 29), + GROUP(pcm_fs_a, 3, 28), + GROUP(pcm_clk_a, 3, 27), + + GROUP(uart_tx_a0, 4, 17), + GROUP(uart_rx_a0, 4, 16), + GROUP(uart_cts_a0, 4, 15), + GROUP(uart_rts_a0, 4, 14), + + GROUP(uart_tx_a1, 4, 13), + GROUP(uart_rx_a1, 4, 12), + GROUP(uart_cts_a1, 4, 11), + GROUP(uart_rts_a1, 4, 10), + + GROUP(uart_tx_b0, 4, 9), + GROUP(uart_rx_b0, 4, 8), + GROUP(uart_cts_b0, 4, 7), + GROUP(uart_rts_b0, 4, 6), + + GROUP(iso7816_det, 4, 21), + GROUP(iso7816_reset, 4, 20), + GROUP(iso7816_clk, 4, 19), + GROUP(iso7816_data, 4, 18), + + GROUP(i2c_sda_d0, 4, 5), + GROUP(i2c_sck_d0, 4, 4), + + GROUP(xtal_32k_out, 3, 22), + GROUP(xtal_24m_out, 3, 23), + + /* bank Y */ + GROUP(uart_tx_c, 1, 19), + GROUP(uart_rx_c, 1, 18), + GROUP(uart_cts_c, 1, 17), + GROUP(uart_rts_c, 1, 16), + + GROUP(pcm_out_b, 4, 25), + GROUP(pcm_in_b, 4, 24), + GROUP(pcm_fs_b, 4, 23), + GROUP(pcm_clk_b, 4, 22), + + GROUP(i2c_sda_c0, 1, 15), + GROUP(i2c_sck_c0, 1, 14), + + /* bank DV */ + GROUP(dvin_rgb, 0, 6), + GROUP(dvin_vs, 0, 9), + GROUP(dvin_hs, 0, 8), + GROUP(dvin_clk, 0, 7), + GROUP(dvin_de, 0, 10), + + GROUP(enc_0, 7, 0), + GROUP(enc_1, 7, 1), + GROUP(enc_2, 7, 2), + GROUP(enc_3, 7, 3), + GROUP(enc_4, 7, 4), + GROUP(enc_5, 7, 5), + GROUP(enc_6, 7, 6), + GROUP(enc_7, 7, 7), + GROUP(enc_8, 7, 8), + GROUP(enc_9, 7, 9), + GROUP(enc_10, 7, 10), + GROUP(enc_11, 7, 11), + GROUP(enc_12, 7, 12), + GROUP(enc_13, 7, 13), + GROUP(enc_14, 7, 14), + GROUP(enc_15, 7, 15), + GROUP(enc_16, 7, 16), + GROUP(enc_17, 7, 17), + + GROUP(uart_tx_b1, 6, 23), + GROUP(uart_rx_b1, 6, 22), + GROUP(uart_cts_b1, 6, 21), + GROUP(uart_rts_b1, 6, 20), + + GROUP(vga_vs, 0, 21), + GROUP(vga_hs, 0, 20), + + /* bank H */ + GROUP(hdmi_hpd, 1, 26), + GROUP(hdmi_sda, 1, 25), + GROUP(hdmi_scl, 1, 24), + GROUP(hdmi_cec, 1, 23), + + GROUP(spi_ss0_0, 9, 13), + GROUP(spi_miso_0, 9, 12), + GROUP(spi_mosi_0, 9, 11), + GROUP(spi_sclk_0, 9, 10), + + GROUP(i2c_sda_d1, 4, 3), + GROUP(i2c_sck_d1, 4, 2), + + /* bank Z */ + GROUP(spi_ss0_1, 8, 16), + GROUP(spi_ss1_1, 8, 12), + GROUP(spi_sclk_1, 8, 15), + GROUP(spi_mosi_1, 8, 14), + GROUP(spi_miso_1, 8, 13), + GROUP(spi_ss2_1, 8, 17), + + GROUP(eth_tx_clk_50m, 6, 15), + GROUP(eth_tx_en, 6, 14), + GROUP(eth_txd1, 6, 13), + GROUP(eth_txd0, 6, 12), + GROUP(eth_rx_clk_in, 6, 10), + GROUP(eth_rx_dv, 6, 11), + GROUP(eth_rxd1, 6, 8), + GROUP(eth_rxd0, 6, 7), + GROUP(eth_mdio, 6, 6), + GROUP(eth_mdc, 6, 5), + + GROUP(i2c_sda_a0, 5, 31), + GROUP(i2c_sck_a0, 5, 30), + + GROUP(i2c_sda_b, 5, 27), + GROUP(i2c_sck_b, 5, 26), + + GROUP(i2c_sda_c1, 5, 25), + GROUP(i2c_sck_c1, 5, 24), + + GROUP(i2c_sda_a1, 5, 9), + GROUP(i2c_sck_a1, 5, 8), + + GROUP(i2c_sda_a2, 5, 7), + GROUP(i2c_sck_a2, 5, 6), + + /* bank BOOT */ + GROUP(sd_d0_c, 6, 29), + GROUP(sd_d1_c, 6, 28), + GROUP(sd_d2_c, 6, 27), + GROUP(sd_d3_c, 6, 26), + GROUP(sd_cmd_c, 6, 25), + GROUP(sd_clk_c, 6, 24), + + GROUP(sdxc_d0_c, 4, 30), + GROUP(sdxc_d13_c, 4, 29), + GROUP(sdxc_d47_c, 4, 28), + GROUP(sdxc_cmd_c, 4, 27), + GROUP(sdxc_clk_c, 4, 26), + + GROUP(nand_io, 2, 26), + GROUP(nand_io_ce0, 2, 25), + GROUP(nand_io_ce1, 2, 24), + GROUP(nand_io_rb0, 2, 17), + GROUP(nand_ale, 2, 21), + GROUP(nand_cle, 2, 20), + GROUP(nand_wen_clk, 2, 19), + GROUP(nand_ren_clk, 2, 18), + GROUP(nand_dqs, 2, 27), + GROUP(nand_ce2, 2, 23), + GROUP(nand_ce3, 2, 22), + + GROUP(nor_d, 5, 1), + GROUP(nor_q, 5, 3), + GROUP(nor_c, 5, 2), + GROUP(nor_cs, 5, 0), + + /* bank CARD */ + GROUP(sd_d1_b, 2, 14), + GROUP(sd_d0_b, 2, 15), + GROUP(sd_clk_b, 2, 11), + GROUP(sd_cmd_b, 2, 10), + GROUP(sd_d3_b, 2, 12), + GROUP(sd_d2_b, 2, 13), + + GROUP(sdxc_d13_b, 2, 6), + GROUP(sdxc_d0_b, 2, 7), + GROUP(sdxc_clk_b, 2, 5), + GROUP(sdxc_cmd_b, 2, 4), + + /* bank AO */ + GROUP_AO(uart_tx_ao_a, 0, 12), + GROUP_AO(uart_rx_ao_a, 0, 11), + GROUP_AO(uart_cts_ao_a, 0, 10), + GROUP_AO(uart_rts_ao_a, 0, 9), + + GROUP_AO(remote_input, 0, 0), + + GROUP_AO(i2c_slave_sck_ao, 0, 2), + GROUP_AO(i2c_slave_sda_ao, 0, 1), + + GROUP_AO(uart_tx_ao_b0, 0, 26), + GROUP_AO(uart_rx_ao_b0, 0, 25), + + GROUP_AO(uart_tx_ao_b1, 0, 24), + GROUP_AO(uart_rx_ao_b1, 0, 23), + + GROUP_AO(i2c_mst_sck_ao, 0, 6), + GROUP_AO(i2c_mst_sda_ao, 0, 5), +}; + +static const char * const gpio_groups[] = { + "GPIOX_0", "GPIOX_1", "GPIOX_2", "GPIOX_3", "GPIOX_4", + "GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9", + "GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14", + "GPIOX_15", "GPIOX_16", "GPIOX_17", "GPIOX_18", "GPIOX_19", + "GPIOX_20", "GPIOX_21", + + "GPIOY_0", "GPIOY_1", "GPIOY_2", "GPIOY_3", "GPIOY_4", + "GPIOY_5", "GPIOY_6", "GPIOY_7", "GPIOY_8", "GPIOY_9", + "GPIOY_10", "GPIOY_11", "GPIOY_12", "GPIOY_13", "GPIOY_14", + "GPIOY_15", "GPIOY_16", + + "GPIODV_0", "GPIODV_1", "GPIODV_2", "GPIODV_3", "GPIODV_4", + "GPIODV_5", "GPIODV_6", "GPIODV_7", "GPIODV_8", "GPIODV_9", + "GPIODV_10", "GPIODV_11", "GPIODV_12", "GPIODV_13", "GPIODV_14", + "GPIODV_15", "GPIODV_16", "GPIODV_17", "GPIODV_18", "GPIODV_19", + "GPIODV_20", "GPIODV_21", "GPIODV_22", "GPIODV_23", "GPIODV_24", + "GPIODV_25", "GPIODV_26", "GPIODV_27", "GPIODV_28", "GPIODV_29", + + "GPIOH_0", "GPIOH_1", "GPIOH_2", "GPIOH_3", "GPIOH_4", + "GPIOH_5", "GPIOH_6", "GPIOH_7", "GPIOH_8", "GPIOH_9", + + "GPIOZ_0", "GPIOZ_1", "GPIOZ_2", "GPIOZ_3", "GPIOZ_4", + "GPIOZ_5", "GPIOZ_6", "GPIOZ_7", "GPIOZ_8", "GPIOZ_9", + "GPIOZ_10", "GPIOZ_11", "GPIOZ_12", "GPIOZ_13", "GPIOZ_14", + + "CARD_0", "CARD_1", "CARD_2", "CARD_3", "CARD_4", + "CARD_5", "CARD_6", + + "BOOT_0", "BOOT_1", "BOOT_2", "BOOT_3", "BOOT_4", + "BOOT_5", "BOOT_6", "BOOT_7", "BOOT_8", "BOOT_9", + "BOOT_10", "BOOT_11", "BOOT_12", "BOOT_13", "BOOT_14", + "BOOT_15", "BOOT_16", "BOOT_17", "BOOT_18", + + "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", + "GPIOAO_4", "GPIOAO_5", "GPIOAO_6", "GPIOAO_7", + "GPIOAO_8", "GPIOAO_9", "GPIOAO_10", "GPIOAO_11", + "GPIOAO_12", "GPIOAO_13", "GPIO_BSD_EN", "GPIO_TEST_N" +}; + +static const char * const sd_a_groups[] = { + "sd_d0_a", "sd_d1_a", "sd_d2_a", "sd_d3_a", "sd_clk_a", "sd_cmd_a" +}; + +static const char * const sdxc_a_groups[] = { + "sdxc_d0_a", "sdxc_d13_a", "sdxc_d47_a", "sdxc_clk_a", "sdxc_cmd_a" +}; + +static const char * const pcm_a_groups[] = { + "pcm_out_a", "pcm_in_a", "pcm_fs_a", "pcm_clk_a" +}; + +static const char * const uart_a_groups[] = { + "uart_tx_a0", "uart_rx_a0", "uart_cts_a0", "uart_rts_a0", + "uart_tx_a1", "uart_rx_a1", "uart_cts_a1", "uart_rts_a1" +}; + +static const char * const uart_b_groups[] = { + "uart_tx_b0", "uart_rx_b0", "uart_cts_b0", "uart_rts_b0", + "uart_tx_b1", "uart_rx_b1", "uart_cts_b1", "uart_rts_b1" +}; + +static const char * const iso7816_groups[] = { + "iso7816_det", "iso7816_reset", "iso7816_clk", "iso7816_data" +}; + +static const char * const i2c_d_groups[] = { + "i2c_sda_d0", "i2c_sck_d0", "i2c_sda_d1", "i2c_sck_d1" +}; + +static const char * const xtal_groups[] = { + "xtal_32k_out", "xtal_24m_out" +}; + +static const char * const uart_c_groups[] = { + "uart_tx_c", "uart_rx_c", "uart_cts_c", "uart_rts_c" +}; + +static const char * const pcm_b_groups[] = { + "pcm_out_b", "pcm_in_b", "pcm_fs_b", "pcm_clk_b" +}; + +static const char * const i2c_c_groups[] = { + "i2c_sda_c0", "i2c_sck_c0", "i2c_sda_c1", "i2c_sck_c1" +}; + +static const char * const dvin_groups[] = { + "dvin_rgb", "dvin_vs", "dvin_hs", "dvin_clk", "dvin_de" +}; + +static const char * const enc_groups[] = { + "enc_0", "enc_1", "enc_2", "enc_3", "enc_4", "enc_5", + "enc_6", "enc_7", "enc_8", "enc_9", "enc_10", "enc_11", + "enc_12", "enc_13", "enc_14", "enc_15", "enc_16", "enc_17" +}; + +static const char * const vga_groups[] = { + "vga_vs", "vga_hs" +}; + +static const char * const hdmi_groups[] = { + "hdmi_hpd", "hdmi_sda", "hdmi_scl", "hdmi_cec" +}; + +static const char * const spi_groups[] = { + "spi_ss0_0", "spi_miso_0", "spi_mosi_0", "spi_sclk_0", + "spi_ss0_1", "spi_ss1_1", "spi_sclk_1", "spi_mosi_1", + "spi_miso_1", "spi_ss2_1" +}; + +static const char * const ethernet_groups[] = { + "eth_tx_clk_50m", "eth_tx_en", "eth_txd1", + "eth_txd0", "eth_rx_clk_in", "eth_rx_dv", + "eth_rxd1", "eth_rxd0", "eth_mdio", "eth_mdc" +}; + +static const char * const i2c_a_groups[] = { + "i2c_sda_a0", "i2c_sck_a0", "i2c_sda_a1", "i2c_sck_a1", + "i2c_sda_a2", "i2c_sck_a2" +}; + +static const char * const i2c_b_groups[] = { + "i2c_sda_b", "i2c_sck_b" +}; + +static const char * const sd_c_groups[] = { + "sd_d0_c", "sd_d1_c", "sd_d2_c", "sd_d3_c", + "sd_cmd_c", "sd_clk_c" +}; + +static const char * const sdxc_c_groups[] = { + "sdxc_d0_c", "sdxc_d13_c", "sdxc_d47_c", "sdxc_cmd_c", + "sdxc_clk_c" +}; + +static const char * const nand_groups[] = { + "nand_io", "nand_io_ce0", "nand_io_ce1", + "nand_io_rb0", "nand_ale", "nand_cle", + "nand_wen_clk", "nand_ren_clk", "nand_dqs", + "nand_ce2", "nand_ce3" +}; + +static const char * const nor_groups[] = { + "nor_d", "nor_q", "nor_c", "nor_cs" +}; + +static const char * const sd_b_groups[] = { + "sd_d1_b", "sd_d0_b", "sd_clk_b", "sd_cmd_b", + "sd_d3_b", "sd_d2_b" +}; + +static const char * const sdxc_b_groups[] = { + "sdxc_d13_b", "sdxc_d0_b", "sdxc_clk_b", "sdxc_cmd_b" +}; + +static const char * const uart_ao_groups[] = { + "uart_tx_ao_a", "uart_rx_ao_a", "uart_cts_ao_a", "uart_rts_ao_a" +}; + +static const char * const remote_groups[] = { + "remote_input" +}; + +static const char * const i2c_slave_ao_groups[] = { + "i2c_slave_sck_ao", "i2c_slave_sda_ao" +}; + +static const char * const uart_ao_b_groups[] = { + "uart_tx_ao_b0", "uart_rx_ao_b0", "uart_tx_ao_b1", "uart_rx_ao_b1" +}; + +static const char * const i2c_mst_ao_groups[] = { + "i2c_mst_sck_ao", "i2c_mst_sda_ao" +}; + +static struct meson_pmx_func meson8_functions[] = { + FUNCTION(gpio), + FUNCTION(sd_a), + FUNCTION(sdxc_a), + FUNCTION(pcm_a), + FUNCTION(uart_a), + FUNCTION(uart_b), + FUNCTION(iso7816), + FUNCTION(i2c_d), + FUNCTION(xtal), + FUNCTION(uart_c), + FUNCTION(pcm_b), + FUNCTION(i2c_c), + FUNCTION(dvin), + FUNCTION(enc), + FUNCTION(vga), + FUNCTION(hdmi), + FUNCTION(spi), + FUNCTION(ethernet), + FUNCTION(i2c_a), + FUNCTION(i2c_b), + FUNCTION(sd_c), + FUNCTION(sdxc_c), + FUNCTION(nand), + FUNCTION(nor), + FUNCTION(sd_b), + FUNCTION(sdxc_b), + FUNCTION(uart_ao), + FUNCTION(remote), + FUNCTION(i2c_slave_ao), + FUNCTION(uart_ao_b), + FUNCTION(i2c_mst_ao), +}; + +static struct meson_bank meson8_banks[] = { + /* name first last pullen pull dir out in */ + BANK("X", PIN_GPIOX_0, PIN_GPIOX_21, 4, 0, 4, 0, 0, 0, 1, 0, 2, 0), + BANK("Y", PIN_GPIOY_0, PIN_GPIOY_16, 3, 0, 3, 0, 3, 0, 4, 0, 5, 0), + BANK("DV", PIN_GPIODV_0, PIN_GPIODV_29, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0), + BANK("H", PIN_GPIOH_0, PIN_GPIOH_9, 1, 16, 1, 16, 9, 19, 10, 19, 11, 19), + BANK("Z", PIN_GPIOZ_0, PIN_GPIOZ_14, 1, 0, 1, 0, 3, 17, 4, 17, 5, 17), + BANK("CARD", PIN_CARD_0, PIN_CARD_6, 2, 20, 2, 20, 0, 22, 1, 22, 2, 22), + BANK("BOOT", PIN_BOOT_0, PIN_BOOT_18, 2, 0, 2, 0, 9, 0, 10, 0, 11, 0), +}; + +static struct meson_bank meson8_ao_banks[] = { + /* name first last pullen pull dir out in */ + BANK("AO", PIN_GPIOAO_0, PIN_GPIO_TEST_N, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0), +}; + +static struct meson_domain_data meson8_domain_data[] = { + { + .name = "banks", + .banks = meson8_banks, + .num_banks = ARRAY_SIZE(meson8_banks), + .pin_base = 0, + .num_pins = 120, + }, + { + .name = "ao-bank", + .banks = meson8_ao_banks, + .num_banks = ARRAY_SIZE(meson8_ao_banks), + .pin_base = 120, + .num_pins = 16, + }, +}; + +struct meson_pinctrl_data meson8_pinctrl_data = { + .pins = meson8_pins, + .groups = meson8_groups, + .funcs = meson8_functions, + .domain_data = meson8_domain_data, + .num_pins = ARRAY_SIZE(meson8_pins), + .num_groups = ARRAY_SIZE(meson8_groups), + .num_funcs = ARRAY_SIZE(meson8_functions), + .num_domains = ARRAY_SIZE(meson8_domain_data), +}; diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c index 224c6cff6aa2..7302f66f4f19 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c @@ -145,14 +145,16 @@ static struct mvebu_mpp_mode armada_38x_mpp_modes[] = { MPP_VAR_FUNCTION(2, "ptp", "event_req", V_88F6810_PLUS), MPP_VAR_FUNCTION(3, "pcie0", "clkreq", V_88F6810_PLUS), MPP_VAR_FUNCTION(4, "sata1", "prsnt", V_88F6810_PLUS), - MPP_VAR_FUNCTION(5, "ua0", "cts", V_88F6810_PLUS)), + MPP_VAR_FUNCTION(5, "ua0", "cts", V_88F6810_PLUS), + MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6810_PLUS)), MPP_MODE(20, MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS), MPP_VAR_FUNCTION(1, "ge0", "txclk", V_88F6810_PLUS), MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS), MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS), MPP_VAR_FUNCTION(4, "sata0", "prsnt", V_88F6810_PLUS), - MPP_VAR_FUNCTION(5, "ua0", "rts", V_88F6810_PLUS)), + MPP_VAR_FUNCTION(5, "ua0", "rts", V_88F6810_PLUS), + MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6810_PLUS)), MPP_MODE(21, MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS), MPP_VAR_FUNCTION(1, "spi0", "cs1", V_88F6810_PLUS), diff --git a/drivers/pinctrl/mvebu/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c index 89a52e15f0ae..95bfd0653e8f 100644 --- a/drivers/pinctrl/mvebu/pinctrl-dove.c +++ b/drivers/pinctrl/mvebu/pinctrl-dove.c @@ -751,12 +751,12 @@ static struct mvebu_pinctrl_soc_info dove_pinctrl_info = { static struct clk *clk; -static struct of_device_id dove_pinctrl_of_match[] = { +static const struct of_device_id dove_pinctrl_of_match[] = { { .compatible = "marvell,dove-pinctrl", .data = &dove_pinctrl_info }, { } }; -static struct regmap_config gc_regmap_config = { +static const struct regmap_config gc_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index 3d6d97228523..1806b24faa14 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -914,7 +914,7 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev, } } - ret = pinconf_generic_parse_dt_config(np, &configs, &nconfigs); + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, &nconfigs); if (nconfigs) { const char *gpio_name; const char *pin; diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index f78b416d7984..4db92f64b4de 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -27,17 +27,6 @@ #include "pinctrl-utils.h" #ifdef CONFIG_DEBUG_FS - -struct pin_config_item { - const enum pin_config_param param; - const char * const display; - const char * const format; - bool has_arg; -}; - -#define PCONFDUMP(a, b, c, d) { .param = a, .display = b, .format = c, \ - .has_arg = d } - static const struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false), PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL, false), @@ -60,22 +49,25 @@ static const struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level", true), }; -void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, - struct seq_file *s, unsigned pin) +static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev, + struct seq_file *s, const char *gname, + unsigned pin, + const struct pin_config_item *items, + int nitems) { - const struct pinconf_ops *ops = pctldev->desc->confops; int i; - if (!ops->is_generic) - return; - - for (i = 0; i < ARRAY_SIZE(conf_items); i++) { + for (i = 0; i < nitems; i++) { unsigned long config; int ret; /* We want to check out this parameter */ - config = pinconf_to_config_packed(conf_items[i].param, 0); - ret = pin_config_get_for_pin(pctldev, pin, &config); + config = pinconf_to_config_packed(items[i].param, 0); + if (gname) + ret = pin_config_group_get(dev_name(pctldev->dev), + gname, &config); + else + ret = pin_config_get_for_pin(pctldev, pin, &config); /* These are legal errors */ if (ret == -EINVAL || ret == -ENOTSUPP) continue; @@ -85,56 +77,47 @@ void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, } /* Space between multiple configs */ seq_puts(s, " "); - seq_puts(s, conf_items[i].display); + seq_puts(s, items[i].display); /* Print unit if available */ - if (conf_items[i].has_arg) { + if (items[i].has_arg) { seq_printf(s, " (%u", pinconf_to_config_argument(config)); - if (conf_items[i].format) - seq_printf(s, " %s)", conf_items[i].format); + if (items[i].format) + seq_printf(s, " %s)", items[i].format); else seq_puts(s, ")"); } } } -void pinconf_generic_dump_group(struct pinctrl_dev *pctldev, - struct seq_file *s, const char *gname) +/** + * pinconf_generic_dump_pins - Print information about pin or group of pins + * @pctldev: Pincontrol device + * @s: File to print to + * @gname: Group name specifying pins + * @pin: Pin number specyfying pin + * + * Print the pinconf configuration for the requested pin(s) to @s. Pins can be + * specified either by pin using @pin or by group using @gname. Only one needs + * to be specified the other can be NULL/0. + */ +void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, struct seq_file *s, + const char *gname, unsigned pin) { const struct pinconf_ops *ops = pctldev->desc->confops; - int i; if (!ops->is_generic) return; - for (i = 0; i < ARRAY_SIZE(conf_items); i++) { - unsigned long config; - int ret; - - /* We want to check out this parameter */ - config = pinconf_to_config_packed(conf_items[i].param, 0); - ret = pin_config_group_get(dev_name(pctldev->dev), gname, - &config); - /* These are legal errors */ - if (ret == -EINVAL || ret == -ENOTSUPP) - continue; - if (ret) { - seq_printf(s, "ERROR READING CONFIG SETTING %d ", i); - continue; - } - /* Space between multiple configs */ - seq_puts(s, " "); - seq_puts(s, conf_items[i].display); - /* Print unit if available */ - if (conf_items[i].has_arg) { - seq_printf(s, " (%u", - pinconf_to_config_argument(config)); - if (conf_items[i].format) - seq_printf(s, " %s)", conf_items[i].format); - else - seq_puts(s, ")"); - } - } + /* generic parameters */ + pinconf_generic_dump_one(pctldev, s, gname, pin, conf_items, + ARRAY_SIZE(conf_items)); + /* driver-specific parameters */ + if (pctldev->desc->num_custom_params && + pctldev->desc->custom_conf_items) + pinconf_generic_dump_one(pctldev, s, gname, pin, + pctldev->desc->custom_conf_items, + pctldev->desc->num_custom_params); } void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, @@ -148,18 +131,25 @@ void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, seq_printf(s, "%s: 0x%x", conf_items[i].display, pinconf_to_config_argument(config)); } + + if (!pctldev->desc->num_custom_params || + !pctldev->desc->custom_conf_items) + return; + + for (i = 0; i < pctldev->desc->num_custom_params; i++) { + if (pinconf_to_config_param(config) != + pctldev->desc->custom_conf_items[i].param) + continue; + seq_printf(s, "%s: 0x%x", + pctldev->desc->custom_conf_items[i].display, + pinconf_to_config_argument(config)); + } } EXPORT_SYMBOL_GPL(pinconf_generic_dump_config); #endif #ifdef CONFIG_OF -struct pinconf_generic_dt_params { - const char * const property; - enum pin_config_param param; - u32 default_value; -}; - -static const struct pinconf_generic_dt_params dt_params[] = { +static const struct pinconf_generic_params dt_params[] = { { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 }, { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 }, @@ -184,32 +174,30 @@ static const struct pinconf_generic_dt_params dt_params[] = { }; /** - * pinconf_generic_parse_dt_config() - * parse the config properties into generic pinconfig values. - * @np: node containing the pinconfig properties - * @configs: array with nconfigs entries containing the generic pinconf values - * @nconfigs: umber of configurations + * parse_dt_cfg() - Parse DT pinconf parameters + * @np: DT node + * @params: Array of describing generic parameters + * @count: Number of entries in @params + * @cfg: Array of parsed config options + * @ncfg: Number of entries in @cfg + * + * Parse the config options described in @params from @np and puts the result + * in @cfg. @cfg does not need to be empty, entries are added beggining at + * @ncfg. @ncfg is updated to reflect the number of entries after parsing. @cfg + * needs to have enough memory allocated to hold all possible entries. */ -int pinconf_generic_parse_dt_config(struct device_node *np, - unsigned long **configs, - unsigned int *nconfigs) +static void parse_dt_cfg(struct device_node *np, + const struct pinconf_generic_params *params, + unsigned int count, unsigned long *cfg, + unsigned int *ncfg) { - unsigned long *cfg; - unsigned int ncfg = 0; - int ret; int i; - u32 val; - if (!np) - return -EINVAL; + for (i = 0; i < count; i++) { + u32 val; + int ret; + const struct pinconf_generic_params *par = ¶ms[i]; - /* allocate a temporary array big enough to hold one of each option */ - cfg = kzalloc(sizeof(*cfg) * ARRAY_SIZE(dt_params), GFP_KERNEL); - if (!cfg) - return -ENOMEM; - - for (i = 0; i < ARRAY_SIZE(dt_params); i++) { - const struct pinconf_generic_dt_params *par = &dt_params[i]; ret = of_property_read_u32(np, par->property, &val); /* property not found */ @@ -221,9 +209,43 @@ int pinconf_generic_parse_dt_config(struct device_node *np, val = par->default_value; pr_debug("found %s with value %u\n", par->property, val); - cfg[ncfg] = pinconf_to_config_packed(par->param, val); - ncfg++; + cfg[*ncfg] = pinconf_to_config_packed(par->param, val); + (*ncfg)++; } +} + +/** + * pinconf_generic_parse_dt_config() + * parse the config properties into generic pinconfig values. + * @np: node containing the pinconfig properties + * @configs: array with nconfigs entries containing the generic pinconf values + * @nconfigs: umber of configurations + */ +int pinconf_generic_parse_dt_config(struct device_node *np, + struct pinctrl_dev *pctldev, + unsigned long **configs, + unsigned int *nconfigs) +{ + unsigned long *cfg; + unsigned int max_cfg, ncfg = 0; + int ret; + + if (!np) + return -EINVAL; + + /* allocate a temporary array big enough to hold one of each option */ + max_cfg = ARRAY_SIZE(dt_params); + if (pctldev) + max_cfg += pctldev->desc->num_custom_params; + cfg = kcalloc(max_cfg, sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg); + if (pctldev && pctldev->desc->num_custom_params && + pctldev->desc->custom_params) + parse_dt_cfg(np, pctldev->desc->custom_params, + pctldev->desc->num_custom_params, cfg, &ncfg); ret = 0; @@ -264,6 +286,7 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, unsigned reserve; struct property *prop; const char *group; + const char *subnode_target_type = "pins"; ret = of_property_read_string(np, "function", &function); if (ret < 0) { @@ -273,7 +296,8 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, function = NULL; } - ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, + &num_configs); if (ret < 0) { dev_err(dev, "could not parse node property\n"); return ret; @@ -284,10 +308,20 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, reserve++; if (num_configs) reserve++; + ret = of_property_count_strings(np, "pins"); if (ret < 0) { - dev_err(dev, "could not parse property pins\n"); - goto exit; + ret = of_property_count_strings(np, "groups"); + if (ret < 0) { + dev_err(dev, "could not parse property pins/groups\n"); + goto exit; + } + if (type == PIN_MAP_TYPE_INVALID) + type = PIN_MAP_TYPE_CONFIGS_GROUP; + subnode_target_type = "groups"; + } else { + if (type == PIN_MAP_TYPE_INVALID) + type = PIN_MAP_TYPE_CONFIGS_PIN; } reserve *= ret; @@ -296,7 +330,7 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (ret < 0) goto exit; - of_property_for_each_string(np, "pins", prop, group) { + of_property_for_each_string(np, subnode_target_type, prop, group) { if (function) { ret = pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, num_maps, group, diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 8bfa0643e5dc..1fc09dc20199 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -288,7 +288,7 @@ static void pinconf_dump_pin(struct pinctrl_dev *pctldev, const struct pinconf_ops *ops = pctldev->desc->confops; /* no-op when not using generic pin config */ - pinconf_generic_dump_pin(pctldev, s, pin); + pinconf_generic_dump_pins(pctldev, s, NULL, pin); if (ops && ops->pin_config_dbg_show) ops->pin_config_dbg_show(pctldev, s, pin); } @@ -333,7 +333,7 @@ static void pinconf_dump_group(struct pinctrl_dev *pctldev, const struct pinconf_ops *ops = pctldev->desc->confops; /* no-op when not using generic pin config */ - pinconf_generic_dump_group(pctldev, s, gname); + pinconf_generic_dump_pins(pctldev, s, gname, 0); if (ops && ops->pin_config_group_dbg_show) ops->pin_config_group_dbg_show(pctldev, s, selector); } diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index a4a5417e1413..55c75780b3b2 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h @@ -92,26 +92,17 @@ static inline void pinconf_init_device_debugfs(struct dentry *devroot, #if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_DEBUG_FS) -void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, - struct seq_file *s, unsigned pin); - -void pinconf_generic_dump_group(struct pinctrl_dev *pctldev, - struct seq_file *s, const char *gname); +void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, + struct seq_file *s, const char *gname, + unsigned pin); void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned long config); #else -static inline void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, - struct seq_file *s, - unsigned pin) -{ - return; -} - -static inline void pinconf_generic_dump_group(struct pinctrl_dev *pctldev, - struct seq_file *s, - const char *gname) +static inline void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, + struct seq_file *s, + const char *gname, unsigned pin) { return; } @@ -126,6 +117,7 @@ static inline void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, #if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_OF) int pinconf_generic_parse_dt_config(struct device_node *np, + struct pinctrl_dev *pctldev, unsigned long **configs, unsigned int *nconfigs); #endif diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index dfd021e8268f..f4cd0b9b2438 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -177,7 +177,7 @@ struct at91_pinctrl { struct device *dev; struct pinctrl_dev *pctl; - int nbanks; + int nactive_banks; uint32_t *mux_mask; int nmux; @@ -653,12 +653,18 @@ static int pin_check_config(struct at91_pinctrl *info, const char *name, int mux; /* check if it's a valid config */ - if (pin->bank >= info->nbanks) { + if (pin->bank >= gpio_banks) { dev_err(info->dev, "%s: pin conf %d bank_id %d >= nbanks %d\n", - name, index, pin->bank, info->nbanks); + name, index, pin->bank, gpio_banks); return -EINVAL; } + if (!gpio_chips[pin->bank]) { + dev_err(info->dev, "%s: pin conf %d bank_id %d not enabled\n", + name, index, pin->bank); + return -ENXIO; + } + if (pin->pin >= MAX_NB_GPIO_PER_BANK) { dev_err(info->dev, "%s: pin conf %d pin_bank_id %d >= %d\n", name, index, pin->pin, MAX_NB_GPIO_PER_BANK); @@ -981,7 +987,8 @@ static void at91_pinctrl_child_count(struct at91_pinctrl *info, for_each_child_of_node(np, child) { if (of_device_is_compatible(child, gpio_compat)) { - info->nbanks++; + if (of_device_is_available(child)) + info->nactive_banks++; } else { info->nfunctions++; info->ngroups += of_get_child_count(child); @@ -1003,11 +1010,11 @@ static int at91_pinctrl_mux_mask(struct at91_pinctrl *info, } size /= sizeof(*list); - if (!size || size % info->nbanks) { - dev_err(info->dev, "wrong mux mask array should be by %d\n", info->nbanks); + if (!size || size % gpio_banks) { + dev_err(info->dev, "wrong mux mask array should be by %d\n", gpio_banks); return -EINVAL; } - info->nmux = size / info->nbanks; + info->nmux = size / gpio_banks; info->mux_mask = devm_kzalloc(info->dev, sizeof(u32) * size, GFP_KERNEL); if (!info->mux_mask) { @@ -1131,7 +1138,7 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev, of_match_device(at91_pinctrl_of_match, &pdev->dev)->data; at91_pinctrl_child_count(info, np); - if (info->nbanks < 1) { + if (gpio_banks < 1) { dev_err(&pdev->dev, "you need to specify at least one gpio-controller\n"); return -EINVAL; } @@ -1144,7 +1151,7 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev, dev_dbg(&pdev->dev, "mux-mask\n"); tmp = info->mux_mask; - for (i = 0; i < info->nbanks; i++) { + for (i = 0; i < gpio_banks; i++) { for (j = 0; j < info->nmux; j++, tmp++) { dev_dbg(&pdev->dev, "%d:%d\t0x%x\n", i, j, tmp[0]); } @@ -1162,7 +1169,7 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev, if (!info->groups) return -ENOMEM; - dev_dbg(&pdev->dev, "nbanks = %d\n", info->nbanks); + dev_dbg(&pdev->dev, "nbanks = %d\n", gpio_banks); dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions); dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups); @@ -1185,7 +1192,7 @@ static int at91_pinctrl_probe(struct platform_device *pdev) { struct at91_pinctrl *info; struct pinctrl_pin_desc *pdesc; - int ret, i, j, k; + int ret, i, j, k, ngpio_chips_enabled = 0; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) @@ -1200,23 +1207,27 @@ static int at91_pinctrl_probe(struct platform_device *pdev) * to obtain references to the struct gpio_chip * for them, and we * need this to proceed. */ - for (i = 0; i < info->nbanks; i++) { - if (!gpio_chips[i]) { - dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i); - devm_kfree(&pdev->dev, info); - return -EPROBE_DEFER; - } + for (i = 0; i < gpio_banks; i++) + if (gpio_chips[i]) + ngpio_chips_enabled++; + + if (ngpio_chips_enabled < info->nactive_banks) { + dev_warn(&pdev->dev, + "All GPIO chips are not registered yet (%d/%d)\n", + ngpio_chips_enabled, info->nactive_banks); + devm_kfree(&pdev->dev, info); + return -EPROBE_DEFER; } at91_pinctrl_desc.name = dev_name(&pdev->dev); - at91_pinctrl_desc.npins = info->nbanks * MAX_NB_GPIO_PER_BANK; + at91_pinctrl_desc.npins = gpio_banks * MAX_NB_GPIO_PER_BANK; at91_pinctrl_desc.pins = pdesc = devm_kzalloc(&pdev->dev, sizeof(*pdesc) * at91_pinctrl_desc.npins, GFP_KERNEL); if (!at91_pinctrl_desc.pins) return -ENOMEM; - for (i = 0 , k = 0; i < info->nbanks; i++) { + for (i = 0, k = 0; i < gpio_banks; i++) { for (j = 0; j < MAX_NB_GPIO_PER_BANK; j++, k++) { pdesc->number = k; pdesc->name = kasprintf(GFP_KERNEL, "pio%c%d", i + 'A', j); @@ -1234,8 +1245,9 @@ static int at91_pinctrl_probe(struct platform_device *pdev) } /* We will handle a range of GPIO pins */ - for (i = 0; i < info->nbanks; i++) - pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range); + for (i = 0; i < gpio_banks; i++) + if (gpio_chips[i]) + pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range); dev_info(&pdev->dev, "initialized AT91 pinctrl driver\n"); @@ -1613,9 +1625,10 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) static int at91_gpio_of_irq_setup(struct platform_device *pdev, struct at91_gpio_chip *at91_gpio) { + struct gpio_chip *gpiochip_prev = NULL; struct at91_gpio_chip *prev = NULL; struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq); - int ret; + int ret, i; at91_gpio->pioc_hwirq = irqd_to_hwirq(d); @@ -1641,24 +1654,33 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev, return ret; } - /* Setup chained handler */ - if (at91_gpio->pioc_idx) - prev = gpio_chips[at91_gpio->pioc_idx - 1]; - /* The top level handler handles one bank of GPIOs, except * on some SoC it can handle up to three... * We only set up the handler for the first of the list. */ - if (prev && prev->next == at91_gpio) + gpiochip_prev = irq_get_handler_data(at91_gpio->pioc_virq); + if (!gpiochip_prev) { + /* Then register the chain on the parent IRQ */ + gpiochip_set_chained_irqchip(&at91_gpio->chip, + &gpio_irqchip, + at91_gpio->pioc_virq, + gpio_irq_handler); return 0; + } - /* Then register the chain on the parent IRQ */ - gpiochip_set_chained_irqchip(&at91_gpio->chip, - &gpio_irqchip, - at91_gpio->pioc_virq, - gpio_irq_handler); + prev = container_of(gpiochip_prev, struct at91_gpio_chip, chip); - return 0; + /* we can only have 2 banks before */ + for (i = 0; i < 2; i++) { + if (prev->next) { + prev = prev->next; + } else { + prev->next = at91_gpio; + return 0; + } + } + + return -EINVAL; } /* This structure is replicated for each GPIO block allocated at probe time */ @@ -1675,24 +1697,6 @@ static struct gpio_chip at91_gpio_template = { .ngpio = MAX_NB_GPIO_PER_BANK, }; -static void at91_gpio_probe_fixup(void) -{ - unsigned i; - struct at91_gpio_chip *at91_gpio, *last = NULL; - - for (i = 0; i < gpio_banks; i++) { - at91_gpio = gpio_chips[i]; - - /* - * GPIO controller are grouped on some SoC: - * PIOC, PIOD and PIOE can share the same IRQ line - */ - if (last && last->pioc_virq == at91_gpio->pioc_virq) - last->next = at91_gpio; - last = at91_gpio; - } -} - static struct of_device_id at91_gpio_of_match[] = { { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, }, { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops }, @@ -1805,8 +1809,6 @@ static int at91_gpio_probe(struct platform_device *pdev) gpio_chips[alias_idx] = at91_chip; gpio_banks = max(gpio_banks, alias_idx + 1); - at91_gpio_probe_fixup(); - ret = at91_gpio_of_irq_setup(pdev, at91_chip); if (ret) goto irq_setup_err; diff --git a/drivers/pinctrl/pinctrl-bcm281xx.c b/drivers/pinctrl/pinctrl-bcm281xx.c index fa2a00f22ff1..b88cfe5ed55a 100644 --- a/drivers/pinctrl/pinctrl-bcm281xx.c +++ b/drivers/pinctrl/pinctrl-bcm281xx.c @@ -976,7 +976,7 @@ static inline void bcm281xx_pin_update(u32 *reg_val, u32 *reg_mask, *reg_mask |= param_mask; } -static struct regmap_config bcm281xx_pinctrl_regmap_config = { +static const struct regmap_config bcm281xx_pinctrl_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -1435,7 +1435,7 @@ static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev) return 0; } -static struct of_device_id bcm281xx_pinctrl_of_match[] = { +static const struct of_device_id bcm281xx_pinctrl_of_match[] = { { .compatible = "brcm,bcm11351-pinctrl", }, { }, }; diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c index 1d21dc226920..0b0fc2eb48e0 100644 --- a/drivers/pinctrl/pinctrl-falcon.c +++ b/drivers/pinctrl/pinctrl-falcon.c @@ -101,6 +101,7 @@ static void lantiq_load_pin_desc(struct pinctrl_pin_desc *d, int bank, int len) for (i = 0; i < len; i++) { /* strlen("ioXYZ") + 1 = 6 */ char *name = kzalloc(6, GFP_KERNEL); + snprintf(name, 6, "io%d", base + i); d[i].number = base + i; d[i].name = name; @@ -463,7 +464,7 @@ static int pinctrl_falcon_probe(struct platform_device *pdev) &res); if (IS_ERR(falcon_info.membase[*bank])) return PTR_ERR(falcon_info.membase[*bank]); - + avail = pad_r32(falcon_info.membase[*bank], LTQ_PADC_AVAIL); pins = fls(avail); diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 3c22dbebc80f..dee7d5f06c60 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -89,7 +89,7 @@ struct rockchip_iomux { * @reg_pull: optional separate register for additional pull settings * @clk: clock of the gpio bank * @irq: interrupt of the gpio bank - * @saved_enables: Saved content of GPIO_INTEN at suspend time. + * @saved_masks: Saved content of GPIO_INTEN at suspend time. * @pin_base: first pin number * @nr_pins: number of pins in this bank * @name: name of the bank @@ -108,7 +108,7 @@ struct rockchip_pin_bank { struct regmap *regmap_pull; struct clk *clk; int irq; - u32 saved_enables; + u32 saved_masks; u32 pin_base; u8 nr_pins; char *name; @@ -1142,7 +1142,7 @@ static int rockchip_pinctrl_parse_groups(struct device_node *np, return -EINVAL; np_config = of_find_node_by_phandle(be32_to_cpup(phandle)); - ret = pinconf_generic_parse_dt_config(np_config, + ret = pinconf_generic_parse_dt_config(np_config, NULL, &grp->data[j].configs, &grp->data[j].nconfigs); if (ret) return ret; @@ -1398,10 +1398,7 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) { struct irq_chip *chip = irq_get_chip(irq); struct rockchip_pin_bank *bank = irq_get_handler_data(irq); - u32 polarity = 0, data = 0; u32 pend; - bool edge_changed = false; - unsigned long flags; dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name); @@ -1409,12 +1406,6 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) pend = readl_relaxed(bank->reg_base + GPIO_INT_STATUS); - if (bank->toggle_edge_mode) { - polarity = readl_relaxed(bank->reg_base + - GPIO_INT_POLARITY); - data = readl_relaxed(bank->reg_base + GPIO_EXT_PORT); - } - while (pend) { unsigned int virq; @@ -1434,29 +1425,33 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) * needs manual intervention. */ if (bank->toggle_edge_mode & BIT(irq)) { - if (data & BIT(irq)) - polarity &= ~BIT(irq); - else - polarity |= BIT(irq); + u32 data, data_old, polarity; + unsigned long flags; - edge_changed = true; + data = readl_relaxed(bank->reg_base + GPIO_EXT_PORT); + do { + spin_lock_irqsave(&bank->slock, flags); + + polarity = readl_relaxed(bank->reg_base + + GPIO_INT_POLARITY); + if (data & BIT(irq)) + polarity &= ~BIT(irq); + else + polarity |= BIT(irq); + writel(polarity, + bank->reg_base + GPIO_INT_POLARITY); + + spin_unlock_irqrestore(&bank->slock, flags); + + data_old = data; + data = readl_relaxed(bank->reg_base + + GPIO_EXT_PORT); + } while ((data & BIT(irq)) != (data_old & BIT(irq))); } generic_handle_irq(virq); } - if (bank->toggle_edge_mode && edge_changed) { - /* Interrupt params should only be set with ints disabled */ - spin_lock_irqsave(&bank->slock, flags); - - data = readl_relaxed(bank->reg_base + GPIO_INTEN); - writel_relaxed(0, bank->reg_base + GPIO_INTEN); - writel(polarity, bank->reg_base + GPIO_INT_POLARITY); - writel(data, bank->reg_base + GPIO_INTEN); - - spin_unlock_irqrestore(&bank->slock, flags); - } - chained_irq_exit(chip, desc); } @@ -1550,8 +1545,8 @@ static void rockchip_irq_suspend(struct irq_data *d) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct rockchip_pin_bank *bank = gc->private; - bank->saved_enables = irq_reg_readl(gc, GPIO_INTEN); - irq_reg_writel(gc, gc->wake_active, GPIO_INTEN); + bank->saved_masks = irq_reg_readl(gc, GPIO_INTMASK); + irq_reg_writel(gc, ~gc->wake_active, GPIO_INTMASK); } static void rockchip_irq_resume(struct irq_data *d) @@ -1559,35 +1554,7 @@ static void rockchip_irq_resume(struct irq_data *d) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct rockchip_pin_bank *bank = gc->private; - irq_reg_writel(gc, bank->saved_enables, GPIO_INTEN); -} - -static void rockchip_irq_disable(struct irq_data *d) -{ - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - u32 val; - - irq_gc_lock(gc); - - val = irq_reg_readl(gc, GPIO_INTEN); - val &= ~d->mask; - irq_reg_writel(gc, val, GPIO_INTEN); - - irq_gc_unlock(gc); -} - -static void rockchip_irq_enable(struct irq_data *d) -{ - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - u32 val; - - irq_gc_lock(gc); - - val = irq_reg_readl(gc, GPIO_INTEN); - val |= d->mask; - irq_reg_writel(gc, val, GPIO_INTEN); - - irq_gc_unlock(gc); + irq_reg_writel(gc, bank->saved_masks, GPIO_INTMASK); } static int rockchip_interrupts_register(struct platform_device *pdev, @@ -1625,6 +1592,14 @@ static int rockchip_interrupts_register(struct platform_device *pdev, continue; } + /* + * Linux assumes that all interrupts start out disabled/masked. + * Our driver only uses the concept of masked and always keeps + * things enabled, so for us that's all masked and all enabled. + */ + writel_relaxed(0xffffffff, bank->reg_base + GPIO_INTMASK); + writel_relaxed(0xffffffff, bank->reg_base + GPIO_INTEN); + gc = irq_get_domain_generic_chip(bank->domain, 0); gc->reg_base = bank->reg_base; gc->private = bank; @@ -1633,8 +1608,6 @@ static int rockchip_interrupts_register(struct platform_device *pdev, gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit; - gc->chip_types[0].chip.irq_enable = rockchip_irq_enable; - gc->chip_types[0].chip.irq_disable = rockchip_irq_disable; gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake; gc->chip_types[0].chip.irq_suspend = rockchip_irq_suspend; gc->chip_types[0].chip.irq_resume = rockchip_irq_resume; diff --git a/drivers/pinctrl/pinctrl-tz1090-pdc.c b/drivers/pinctrl/pinctrl-tz1090-pdc.c index 146e48a9b839..fab6aafa6a9f 100644 --- a/drivers/pinctrl/pinctrl-tz1090-pdc.c +++ b/drivers/pinctrl/pinctrl-tz1090-pdc.c @@ -415,7 +415,7 @@ static int tz1090_pdc_pinctrl_dt_subnode_to_map(struct device *dev, function = NULL; } - ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); + ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &num_configs); if (ret) return ret; diff --git a/drivers/pinctrl/pinctrl-tz1090.c b/drivers/pinctrl/pinctrl-tz1090.c index df8cb1e5b7b4..8bd73075f9dd 100644 --- a/drivers/pinctrl/pinctrl-tz1090.c +++ b/drivers/pinctrl/pinctrl-tz1090.c @@ -1131,7 +1131,7 @@ static int tz1090_pinctrl_dt_subnode_to_map(struct device *dev, function = NULL; } - ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); + ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &num_configs); if (ret) return ret; diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c index c5cef59f5965..779950c62e53 100644 --- a/drivers/pinctrl/pinctrl-xway.c +++ b/drivers/pinctrl/pinctrl-xway.c @@ -798,10 +798,8 @@ static int pinmux_xway_probe(struct platform_device *pdev) /* load the gpio chip */ xway_chip.dev = &pdev->dev; - of_gpiochip_add(&xway_chip); ret = gpiochip_add(&xway_chip); if (ret) { - of_gpiochip_remove(&xway_chip); dev_err(&pdev->dev, "Failed to register gpio chip\n"); return ret; } diff --git a/drivers/pinctrl/pinctrl-zynq.c b/drivers/pinctrl/pinctrl-zynq.c new file mode 100644 index 000000000000..22280bddb9e2 --- /dev/null +++ b/drivers/pinctrl/pinctrl-zynq.c @@ -0,0 +1,1180 @@ +/* + * Zynq pin controller + * + * Copyright (C) 2014 Xilinx + * + * Sören Brinkmann + * + * 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, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pinctrl-utils.h" +#include "core.h" + +#define ZYNQ_NUM_MIOS 54 + +#define ZYNQ_PCTRL_MIO_MST_TRI0 0x10c +#define ZYNQ_PCTRL_MIO_MST_TRI1 0x110 + +#define ZYNQ_PINMUX_MUX_SHIFT 1 +#define ZYNQ_PINMUX_MUX_MASK (0x7f << ZYNQ_PINMUX_MUX_SHIFT) + +/** + * struct zynq_pinctrl - driver data + * @pctrl: Pinctrl device + * @syscon: Syscon regmap + * @pctrl_offset: Offset for pinctrl into the @syscon space + * @groups: Pingroups + * @ngroupos: Number of @groups + * @funcs: Pinmux functions + * @nfuncs: Number of @funcs + */ +struct zynq_pinctrl { + struct pinctrl_dev *pctrl; + struct regmap *syscon; + u32 pctrl_offset; + const struct zynq_pctrl_group *groups; + unsigned int ngroups; + const struct zynq_pinmux_function *funcs; + unsigned int nfuncs; +}; + +struct zynq_pctrl_group { + const char *name; + const unsigned int *pins; + const unsigned npins; +}; + +/** + * struct zynq_pinmux_function - a pinmux function + * @name: Name of the pinmux function. + * @groups: List of pingroups for this function. + * @ngroups: Number of entries in @groups. + * @mux_val: Selector for this function + * @mux: Offset of function specific mux + * @mux_mask: Mask for function specific selector + * @mux_shift: Shift for function specific selector + */ +struct zynq_pinmux_function { + const char *name; + const char * const *groups; + unsigned int ngroups; + unsigned int mux_val; + u32 mux; + u32 mux_mask; + u8 mux_shift; +}; + +enum zynq_pinmux_functions { + ZYNQ_PMUX_can0, + ZYNQ_PMUX_can1, + ZYNQ_PMUX_ethernet0, + ZYNQ_PMUX_ethernet1, + ZYNQ_PMUX_gpio0, + ZYNQ_PMUX_i2c0, + ZYNQ_PMUX_i2c1, + ZYNQ_PMUX_mdio0, + ZYNQ_PMUX_mdio1, + ZYNQ_PMUX_qspi0, + ZYNQ_PMUX_qspi1, + ZYNQ_PMUX_qspi_fbclk, + ZYNQ_PMUX_qspi_cs1, + ZYNQ_PMUX_spi0, + ZYNQ_PMUX_spi1, + ZYNQ_PMUX_sdio0, + ZYNQ_PMUX_sdio0_pc, + ZYNQ_PMUX_sdio0_cd, + ZYNQ_PMUX_sdio0_wp, + ZYNQ_PMUX_sdio1, + ZYNQ_PMUX_sdio1_pc, + ZYNQ_PMUX_sdio1_cd, + ZYNQ_PMUX_sdio1_wp, + ZYNQ_PMUX_smc0_nor, + ZYNQ_PMUX_smc0_nor_cs1, + ZYNQ_PMUX_smc0_nor_addr25, + ZYNQ_PMUX_smc0_nand, + ZYNQ_PMUX_ttc0, + ZYNQ_PMUX_ttc1, + ZYNQ_PMUX_uart0, + ZYNQ_PMUX_uart1, + ZYNQ_PMUX_usb0, + ZYNQ_PMUX_usb1, + ZYNQ_PMUX_swdt0, + ZYNQ_PMUX_MAX_FUNC +}; + +const struct pinctrl_pin_desc zynq_pins[] = { + PINCTRL_PIN(0, "MIO0"), + PINCTRL_PIN(1, "MIO1"), + PINCTRL_PIN(2, "MIO2"), + PINCTRL_PIN(3, "MIO3"), + PINCTRL_PIN(4, "MIO4"), + PINCTRL_PIN(5, "MIO5"), + PINCTRL_PIN(6, "MIO6"), + PINCTRL_PIN(7, "MIO7"), + PINCTRL_PIN(8, "MIO8"), + PINCTRL_PIN(9, "MIO9"), + PINCTRL_PIN(10, "MIO10"), + PINCTRL_PIN(11, "MIO11"), + PINCTRL_PIN(12, "MIO12"), + PINCTRL_PIN(13, "MIO13"), + PINCTRL_PIN(14, "MIO14"), + PINCTRL_PIN(15, "MIO15"), + PINCTRL_PIN(16, "MIO16"), + PINCTRL_PIN(17, "MIO17"), + PINCTRL_PIN(18, "MIO18"), + PINCTRL_PIN(19, "MIO19"), + PINCTRL_PIN(20, "MIO20"), + PINCTRL_PIN(21, "MIO21"), + PINCTRL_PIN(22, "MIO22"), + PINCTRL_PIN(23, "MIO23"), + PINCTRL_PIN(24, "MIO24"), + PINCTRL_PIN(25, "MIO25"), + PINCTRL_PIN(26, "MIO26"), + PINCTRL_PIN(27, "MIO27"), + PINCTRL_PIN(28, "MIO28"), + PINCTRL_PIN(29, "MIO29"), + PINCTRL_PIN(30, "MIO30"), + PINCTRL_PIN(31, "MIO31"), + PINCTRL_PIN(32, "MIO32"), + PINCTRL_PIN(33, "MIO33"), + PINCTRL_PIN(34, "MIO34"), + PINCTRL_PIN(35, "MIO35"), + PINCTRL_PIN(36, "MIO36"), + PINCTRL_PIN(37, "MIO37"), + PINCTRL_PIN(38, "MIO38"), + PINCTRL_PIN(39, "MIO39"), + PINCTRL_PIN(40, "MIO40"), + PINCTRL_PIN(41, "MIO41"), + PINCTRL_PIN(42, "MIO42"), + PINCTRL_PIN(43, "MIO43"), + PINCTRL_PIN(44, "MIO44"), + PINCTRL_PIN(45, "MIO45"), + PINCTRL_PIN(46, "MIO46"), + PINCTRL_PIN(47, "MIO47"), + PINCTRL_PIN(48, "MIO48"), + PINCTRL_PIN(49, "MIO49"), + PINCTRL_PIN(50, "MIO50"), + PINCTRL_PIN(51, "MIO51"), + PINCTRL_PIN(52, "MIO52"), + PINCTRL_PIN(53, "MIO53"), + PINCTRL_PIN(54, "EMIO_SD0_WP"), + PINCTRL_PIN(55, "EMIO_SD0_CD"), + PINCTRL_PIN(56, "EMIO_SD1_WP"), + PINCTRL_PIN(57, "EMIO_SD1_CD"), +}; + +/* pin groups */ +static const unsigned int ethernet0_0_pins[] = {16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27}; +static const unsigned int ethernet1_0_pins[] = {28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39}; +static const unsigned int mdio0_0_pins[] = {52, 53}; +static const unsigned int mdio1_0_pins[] = {52, 53}; +static const unsigned int qspi0_0_pins[] = {1, 2, 3, 4, 5, 6}; + +static const unsigned int qspi1_0_pins[] = {9, 10, 11, 12, 13}; +static const unsigned int qspi_cs1_pins[] = {0}; +static const unsigned int qspi_fbclk_pins[] = {8}; +static const unsigned int spi0_0_pins[] = {16, 17, 18, 19, 20, 21}; +static const unsigned int spi0_1_pins[] = {28, 29, 30, 31, 32, 33}; +static const unsigned int spi0_2_pins[] = {40, 41, 42, 43, 44, 45}; +static const unsigned int spi1_0_pins[] = {10, 11, 12, 13, 14, 15}; +static const unsigned int spi1_1_pins[] = {22, 23, 24, 25, 26, 27}; +static const unsigned int spi1_2_pins[] = {34, 35, 36, 37, 38, 39}; +static const unsigned int spi1_3_pins[] = {46, 47, 48, 49, 40, 51}; +static const unsigned int sdio0_0_pins[] = {16, 17, 18, 19, 20, 21}; +static const unsigned int sdio0_1_pins[] = {28, 29, 30, 31, 32, 33}; +static const unsigned int sdio0_2_pins[] = {40, 41, 42, 43, 44, 45}; +static const unsigned int sdio1_0_pins[] = {10, 11, 12, 13, 14, 15}; +static const unsigned int sdio1_1_pins[] = {22, 23, 24, 25, 26, 27}; +static const unsigned int sdio1_2_pins[] = {34, 35, 36, 37, 38, 39}; +static const unsigned int sdio1_3_pins[] = {46, 47, 48, 49, 40, 51}; +static const unsigned int sdio0_emio_wp_pins[] = {54}; +static const unsigned int sdio0_emio_cd_pins[] = {55}; +static const unsigned int sdio1_emio_wp_pins[] = {56}; +static const unsigned int sdio1_emio_cd_pins[] = {57}; +static const unsigned int smc0_nor_pins[] = {0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, + 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39}; +static const unsigned int smc0_nor_cs1_pins[] = {1}; +static const unsigned int smc0_nor_addr25_pins[] = {1}; +static const unsigned int smc0_nand_pins[] = {0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 16, 17, 18, 19, 20, + 21, 22, 23}; +/* Note: CAN MIO clock inputs are modeled in the clock framework */ +static const unsigned int can0_0_pins[] = {10, 11}; +static const unsigned int can0_1_pins[] = {14, 15}; +static const unsigned int can0_2_pins[] = {18, 19}; +static const unsigned int can0_3_pins[] = {22, 23}; +static const unsigned int can0_4_pins[] = {26, 27}; +static const unsigned int can0_5_pins[] = {30, 31}; +static const unsigned int can0_6_pins[] = {34, 35}; +static const unsigned int can0_7_pins[] = {38, 39}; +static const unsigned int can0_8_pins[] = {42, 43}; +static const unsigned int can0_9_pins[] = {46, 47}; +static const unsigned int can0_10_pins[] = {50, 51}; +static const unsigned int can1_0_pins[] = {8, 9}; +static const unsigned int can1_1_pins[] = {12, 13}; +static const unsigned int can1_2_pins[] = {16, 17}; +static const unsigned int can1_3_pins[] = {20, 21}; +static const unsigned int can1_4_pins[] = {24, 25}; +static const unsigned int can1_5_pins[] = {28, 29}; +static const unsigned int can1_6_pins[] = {32, 33}; +static const unsigned int can1_7_pins[] = {36, 37}; +static const unsigned int can1_8_pins[] = {40, 41}; +static const unsigned int can1_9_pins[] = {44, 45}; +static const unsigned int can1_10_pins[] = {48, 49}; +static const unsigned int can1_11_pins[] = {52, 53}; +static const unsigned int uart0_0_pins[] = {10, 11}; +static const unsigned int uart0_1_pins[] = {14, 15}; +static const unsigned int uart0_2_pins[] = {18, 19}; +static const unsigned int uart0_3_pins[] = {22, 23}; +static const unsigned int uart0_4_pins[] = {26, 27}; +static const unsigned int uart0_5_pins[] = {30, 31}; +static const unsigned int uart0_6_pins[] = {34, 35}; +static const unsigned int uart0_7_pins[] = {38, 39}; +static const unsigned int uart0_8_pins[] = {42, 43}; +static const unsigned int uart0_9_pins[] = {46, 47}; +static const unsigned int uart0_10_pins[] = {50, 51}; +static const unsigned int uart1_0_pins[] = {8, 9}; +static const unsigned int uart1_1_pins[] = {12, 13}; +static const unsigned int uart1_2_pins[] = {16, 17}; +static const unsigned int uart1_3_pins[] = {20, 21}; +static const unsigned int uart1_4_pins[] = {24, 25}; +static const unsigned int uart1_5_pins[] = {28, 29}; +static const unsigned int uart1_6_pins[] = {32, 33}; +static const unsigned int uart1_7_pins[] = {36, 37}; +static const unsigned int uart1_8_pins[] = {40, 41}; +static const unsigned int uart1_9_pins[] = {44, 45}; +static const unsigned int uart1_10_pins[] = {48, 49}; +static const unsigned int uart1_11_pins[] = {52, 53}; +static const unsigned int i2c0_0_pins[] = {10, 11}; +static const unsigned int i2c0_1_pins[] = {14, 15}; +static const unsigned int i2c0_2_pins[] = {18, 19}; +static const unsigned int i2c0_3_pins[] = {22, 23}; +static const unsigned int i2c0_4_pins[] = {26, 27}; +static const unsigned int i2c0_5_pins[] = {30, 31}; +static const unsigned int i2c0_6_pins[] = {34, 35}; +static const unsigned int i2c0_7_pins[] = {38, 39}; +static const unsigned int i2c0_8_pins[] = {42, 43}; +static const unsigned int i2c0_9_pins[] = {46, 47}; +static const unsigned int i2c0_10_pins[] = {50, 51}; +static const unsigned int i2c1_0_pins[] = {12, 13}; +static const unsigned int i2c1_1_pins[] = {16, 17}; +static const unsigned int i2c1_2_pins[] = {20, 21}; +static const unsigned int i2c1_3_pins[] = {24, 25}; +static const unsigned int i2c1_4_pins[] = {28, 29}; +static const unsigned int i2c1_5_pins[] = {32, 33}; +static const unsigned int i2c1_6_pins[] = {36, 37}; +static const unsigned int i2c1_7_pins[] = {40, 41}; +static const unsigned int i2c1_8_pins[] = {44, 45}; +static const unsigned int i2c1_9_pins[] = {48, 49}; +static const unsigned int i2c1_10_pins[] = {52, 53}; +static const unsigned int ttc0_0_pins[] = {18, 19}; +static const unsigned int ttc0_1_pins[] = {30, 31}; +static const unsigned int ttc0_2_pins[] = {42, 43}; +static const unsigned int ttc1_0_pins[] = {16, 17}; +static const unsigned int ttc1_1_pins[] = {28, 29}; +static const unsigned int ttc1_2_pins[] = {40, 41}; +static const unsigned int swdt0_0_pins[] = {14, 15}; +static const unsigned int swdt0_1_pins[] = {26, 27}; +static const unsigned int swdt0_2_pins[] = {38, 39}; +static const unsigned int swdt0_3_pins[] = {50, 51}; +static const unsigned int swdt0_4_pins[] = {52, 53}; +static const unsigned int gpio0_0_pins[] = {0}; +static const unsigned int gpio0_1_pins[] = {1}; +static const unsigned int gpio0_2_pins[] = {2}; +static const unsigned int gpio0_3_pins[] = {3}; +static const unsigned int gpio0_4_pins[] = {4}; +static const unsigned int gpio0_5_pins[] = {5}; +static const unsigned int gpio0_6_pins[] = {6}; +static const unsigned int gpio0_7_pins[] = {7}; +static const unsigned int gpio0_8_pins[] = {8}; +static const unsigned int gpio0_9_pins[] = {9}; +static const unsigned int gpio0_10_pins[] = {10}; +static const unsigned int gpio0_11_pins[] = {11}; +static const unsigned int gpio0_12_pins[] = {12}; +static const unsigned int gpio0_13_pins[] = {13}; +static const unsigned int gpio0_14_pins[] = {14}; +static const unsigned int gpio0_15_pins[] = {15}; +static const unsigned int gpio0_16_pins[] = {16}; +static const unsigned int gpio0_17_pins[] = {17}; +static const unsigned int gpio0_18_pins[] = {18}; +static const unsigned int gpio0_19_pins[] = {19}; +static const unsigned int gpio0_20_pins[] = {20}; +static const unsigned int gpio0_21_pins[] = {21}; +static const unsigned int gpio0_22_pins[] = {22}; +static const unsigned int gpio0_23_pins[] = {23}; +static const unsigned int gpio0_24_pins[] = {24}; +static const unsigned int gpio0_25_pins[] = {25}; +static const unsigned int gpio0_26_pins[] = {26}; +static const unsigned int gpio0_27_pins[] = {27}; +static const unsigned int gpio0_28_pins[] = {28}; +static const unsigned int gpio0_29_pins[] = {29}; +static const unsigned int gpio0_30_pins[] = {30}; +static const unsigned int gpio0_31_pins[] = {31}; +static const unsigned int gpio0_32_pins[] = {32}; +static const unsigned int gpio0_33_pins[] = {33}; +static const unsigned int gpio0_34_pins[] = {34}; +static const unsigned int gpio0_35_pins[] = {35}; +static const unsigned int gpio0_36_pins[] = {36}; +static const unsigned int gpio0_37_pins[] = {37}; +static const unsigned int gpio0_38_pins[] = {38}; +static const unsigned int gpio0_39_pins[] = {39}; +static const unsigned int gpio0_40_pins[] = {40}; +static const unsigned int gpio0_41_pins[] = {41}; +static const unsigned int gpio0_42_pins[] = {42}; +static const unsigned int gpio0_43_pins[] = {43}; +static const unsigned int gpio0_44_pins[] = {44}; +static const unsigned int gpio0_45_pins[] = {45}; +static const unsigned int gpio0_46_pins[] = {46}; +static const unsigned int gpio0_47_pins[] = {47}; +static const unsigned int gpio0_48_pins[] = {48}; +static const unsigned int gpio0_49_pins[] = {49}; +static const unsigned int gpio0_50_pins[] = {50}; +static const unsigned int gpio0_51_pins[] = {51}; +static const unsigned int gpio0_52_pins[] = {52}; +static const unsigned int gpio0_53_pins[] = {53}; +static const unsigned int usb0_0_pins[] = {28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39}; +static const unsigned int usb1_0_pins[] = {40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51}; + +#define DEFINE_ZYNQ_PINCTRL_GRP(nm) \ + { \ + .name = #nm "_grp", \ + .pins = nm ## _pins, \ + .npins = ARRAY_SIZE(nm ## _pins), \ + } + +struct zynq_pctrl_group zynq_pctrl_groups[] = { + DEFINE_ZYNQ_PINCTRL_GRP(ethernet0_0), + DEFINE_ZYNQ_PINCTRL_GRP(ethernet1_0), + DEFINE_ZYNQ_PINCTRL_GRP(mdio0_0), + DEFINE_ZYNQ_PINCTRL_GRP(mdio1_0), + DEFINE_ZYNQ_PINCTRL_GRP(qspi0_0), + DEFINE_ZYNQ_PINCTRL_GRP(qspi1_0), + DEFINE_ZYNQ_PINCTRL_GRP(qspi_fbclk), + DEFINE_ZYNQ_PINCTRL_GRP(qspi_cs1), + DEFINE_ZYNQ_PINCTRL_GRP(spi0_0), + DEFINE_ZYNQ_PINCTRL_GRP(spi0_1), + DEFINE_ZYNQ_PINCTRL_GRP(spi0_2), + DEFINE_ZYNQ_PINCTRL_GRP(spi1_0), + DEFINE_ZYNQ_PINCTRL_GRP(spi1_1), + DEFINE_ZYNQ_PINCTRL_GRP(spi1_2), + DEFINE_ZYNQ_PINCTRL_GRP(spi1_3), + DEFINE_ZYNQ_PINCTRL_GRP(sdio0_0), + DEFINE_ZYNQ_PINCTRL_GRP(sdio0_1), + DEFINE_ZYNQ_PINCTRL_GRP(sdio0_2), + DEFINE_ZYNQ_PINCTRL_GRP(sdio1_0), + DEFINE_ZYNQ_PINCTRL_GRP(sdio1_1), + DEFINE_ZYNQ_PINCTRL_GRP(sdio1_2), + DEFINE_ZYNQ_PINCTRL_GRP(sdio1_3), + DEFINE_ZYNQ_PINCTRL_GRP(sdio0_emio_wp), + DEFINE_ZYNQ_PINCTRL_GRP(sdio0_emio_cd), + DEFINE_ZYNQ_PINCTRL_GRP(sdio1_emio_wp), + DEFINE_ZYNQ_PINCTRL_GRP(sdio1_emio_cd), + DEFINE_ZYNQ_PINCTRL_GRP(smc0_nor), + DEFINE_ZYNQ_PINCTRL_GRP(smc0_nor_cs1), + DEFINE_ZYNQ_PINCTRL_GRP(smc0_nor_addr25), + DEFINE_ZYNQ_PINCTRL_GRP(smc0_nand), + DEFINE_ZYNQ_PINCTRL_GRP(can0_0), + DEFINE_ZYNQ_PINCTRL_GRP(can0_1), + DEFINE_ZYNQ_PINCTRL_GRP(can0_2), + DEFINE_ZYNQ_PINCTRL_GRP(can0_3), + DEFINE_ZYNQ_PINCTRL_GRP(can0_4), + DEFINE_ZYNQ_PINCTRL_GRP(can0_5), + DEFINE_ZYNQ_PINCTRL_GRP(can0_6), + DEFINE_ZYNQ_PINCTRL_GRP(can0_7), + DEFINE_ZYNQ_PINCTRL_GRP(can0_8), + DEFINE_ZYNQ_PINCTRL_GRP(can0_9), + DEFINE_ZYNQ_PINCTRL_GRP(can0_10), + DEFINE_ZYNQ_PINCTRL_GRP(can1_0), + DEFINE_ZYNQ_PINCTRL_GRP(can1_1), + DEFINE_ZYNQ_PINCTRL_GRP(can1_2), + DEFINE_ZYNQ_PINCTRL_GRP(can1_3), + DEFINE_ZYNQ_PINCTRL_GRP(can1_4), + DEFINE_ZYNQ_PINCTRL_GRP(can1_5), + DEFINE_ZYNQ_PINCTRL_GRP(can1_6), + DEFINE_ZYNQ_PINCTRL_GRP(can1_7), + DEFINE_ZYNQ_PINCTRL_GRP(can1_8), + DEFINE_ZYNQ_PINCTRL_GRP(can1_9), + DEFINE_ZYNQ_PINCTRL_GRP(can1_10), + DEFINE_ZYNQ_PINCTRL_GRP(can1_11), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_0), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_1), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_2), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_3), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_4), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_5), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_6), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_7), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_8), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_9), + DEFINE_ZYNQ_PINCTRL_GRP(uart0_10), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_0), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_1), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_2), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_3), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_4), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_5), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_6), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_7), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_8), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_9), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_10), + DEFINE_ZYNQ_PINCTRL_GRP(uart1_11), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_0), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_1), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_2), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_3), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_4), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_5), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_6), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_7), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_8), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_9), + DEFINE_ZYNQ_PINCTRL_GRP(i2c0_10), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_0), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_1), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_2), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_3), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_4), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_5), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_6), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_7), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_8), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_9), + DEFINE_ZYNQ_PINCTRL_GRP(i2c1_10), + DEFINE_ZYNQ_PINCTRL_GRP(ttc0_0), + DEFINE_ZYNQ_PINCTRL_GRP(ttc0_1), + DEFINE_ZYNQ_PINCTRL_GRP(ttc0_2), + DEFINE_ZYNQ_PINCTRL_GRP(ttc1_0), + DEFINE_ZYNQ_PINCTRL_GRP(ttc1_1), + DEFINE_ZYNQ_PINCTRL_GRP(ttc1_2), + DEFINE_ZYNQ_PINCTRL_GRP(swdt0_0), + DEFINE_ZYNQ_PINCTRL_GRP(swdt0_1), + DEFINE_ZYNQ_PINCTRL_GRP(swdt0_2), + DEFINE_ZYNQ_PINCTRL_GRP(swdt0_3), + DEFINE_ZYNQ_PINCTRL_GRP(swdt0_4), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_0), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_1), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_2), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_3), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_4), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_5), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_6), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_7), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_8), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_9), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_10), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_11), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_12), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_13), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_14), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_15), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_16), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_17), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_18), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_19), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_20), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_21), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_22), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_23), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_24), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_25), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_26), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_27), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_28), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_29), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_30), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_31), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_32), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_33), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_34), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_35), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_36), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_37), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_38), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_39), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_40), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_41), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_42), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_43), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_44), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_45), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_46), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_47), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_48), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_49), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_50), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_51), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_52), + DEFINE_ZYNQ_PINCTRL_GRP(gpio0_53), + DEFINE_ZYNQ_PINCTRL_GRP(usb0_0), + DEFINE_ZYNQ_PINCTRL_GRP(usb1_0), +}; + +/* function groups */ +static const char * const ethernet0_groups[] = {"ethernet0_0_grp"}; +static const char * const ethernet1_groups[] = {"ethernet1_0_grp"}; +static const char * const usb0_groups[] = {"usb0_0_grp"}; +static const char * const usb1_groups[] = {"usb1_0_grp"}; +static const char * const mdio0_groups[] = {"mdio0_0_grp"}; +static const char * const mdio1_groups[] = {"mdio1_0_grp"}; +static const char * const qspi0_groups[] = {"qspi0_0_grp"}; +static const char * const qspi1_groups[] = {"qspi0_1_grp"}; +static const char * const qspi_fbclk_groups[] = {"qspi_fbclk_grp"}; +static const char * const qspi_cs1_groups[] = {"qspi_cs1_grp"}; +static const char * const spi0_groups[] = {"spi0_0_grp", "spi0_1_grp", + "spi0_2_grp"}; +static const char * const spi1_groups[] = {"spi1_0_grp", "spi1_1_grp", + "spi1_2_grp", "spi1_3_grp"}; +static const char * const sdio0_groups[] = {"sdio0_0_grp", "sdio0_1_grp", + "sdio0_2_grp"}; +static const char * const sdio1_groups[] = {"sdio1_0_grp", "sdio1_1_grp", + "sdio1_2_grp", "sdio1_3_grp"}; +static const char * const sdio0_pc_groups[] = {"gpio0_0_grp", + "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp", + "gpio0_8_grp", "gpio0_10_grp", "gpio0_12_grp", + "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp", + "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp", + "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp", + "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp", + "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp", + "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp", + "gpio0_50_grp", "gpio0_52_grp"}; +static const char * const sdio1_pc_groups[] = {"gpio0_1_grp", + "gpio0_3_grp", "gpio0_5_grp", "gpio0_7_grp", + "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp", + "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp", + "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp", + "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp", + "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp", + "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp", + "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp", + "gpio0_51_grp", "gpio0_53_grp"}; +static const char * const sdio0_cd_groups[] = {"gpio0_0_grp", + "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp", + "gpio0_10_grp", "gpio0_12_grp", + "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp", + "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp", + "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp", + "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp", + "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp", + "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp", + "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp", + "gpio0_3_grp", "gpio0_5_grp", + "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp", + "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp", + "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp", + "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp", + "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp", + "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp", + "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp", + "gpio0_51_grp", "gpio0_53_grp", "sdio0_emio_cd_grp"}; +static const char * const sdio0_wp_groups[] = {"gpio0_0_grp", + "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp", + "gpio0_10_grp", "gpio0_12_grp", + "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp", + "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp", + "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp", + "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp", + "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp", + "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp", + "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp", + "gpio0_3_grp", "gpio0_5_grp", + "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp", + "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp", + "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp", + "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp", + "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp", + "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp", + "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp", + "gpio0_51_grp", "gpio0_53_grp", "sdio0_emio_wp_grp"}; +static const char * const sdio1_cd_groups[] = {"gpio0_0_grp", + "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp", + "gpio0_10_grp", "gpio0_12_grp", + "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp", + "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp", + "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp", + "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp", + "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp", + "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp", + "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp", + "gpio0_3_grp", "gpio0_5_grp", + "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp", + "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp", + "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp", + "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp", + "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp", + "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp", + "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp", + "gpio0_51_grp", "gpio0_53_grp", "sdio1_emio_cd_grp"}; +static const char * const sdio1_wp_groups[] = {"gpio0_0_grp", + "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp", + "gpio0_10_grp", "gpio0_12_grp", + "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp", + "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp", + "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp", + "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp", + "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp", + "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp", + "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp", + "gpio0_3_grp", "gpio0_5_grp", + "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp", + "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp", + "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp", + "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp", + "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp", + "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp", + "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp", + "gpio0_51_grp", "gpio0_53_grp", "sdio1_emio_wp_grp"}; +static const char * const smc0_nor_groups[] = {"smc0_nor"}; +static const char * const smc0_nor_cs1_groups[] = {"smc0_nor_cs1_grp"}; +static const char * const smc0_nor_addr25_groups[] = {"smc0_nor_addr25_grp"}; +static const char * const smc0_nand_groups[] = {"smc0_nand"}; +static const char * const can0_groups[] = {"can0_0_grp", "can0_1_grp", + "can0_2_grp", "can0_3_grp", "can0_4_grp", "can0_5_grp", + "can0_6_grp", "can0_7_grp", "can0_8_grp", "can0_9_grp", + "can0_10_grp"}; +static const char * const can1_groups[] = {"can1_0_grp", "can1_1_grp", + "can1_2_grp", "can1_3_grp", "can1_4_grp", "can1_5_grp", + "can1_6_grp", "can1_7_grp", "can1_8_grp", "can1_9_grp", + "can1_10_grp", "can1_11_grp"}; +static const char * const uart0_groups[] = {"uart0_0_grp", "uart0_1_grp", + "uart0_2_grp", "uart0_3_grp", "uart0_4_grp", "uart0_5_grp", + "uart0_6_grp", "uart0_7_grp", "uart0_8_grp", "uart0_9_grp", + "uart0_10_grp"}; +static const char * const uart1_groups[] = {"uart1_0_grp", "uart1_1_grp", + "uart1_2_grp", "uart1_3_grp", "uart1_4_grp", "uart1_5_grp", + "uart1_6_grp", "uart1_7_grp", "uart1_8_grp", "uart1_9_grp", + "uart1_10_grp", "uart1_11_grp"}; +static const char * const i2c0_groups[] = {"i2c0_0_grp", "i2c0_1_grp", + "i2c0_2_grp", "i2c0_3_grp", "i2c0_4_grp", "i2c0_5_grp", + "i2c0_6_grp", "i2c0_7_grp", "i2c0_8_grp", "i2c0_9_grp", + "i2c0_10_grp"}; +static const char * const i2c1_groups[] = {"i2c1_0_grp", "i2c1_1_grp", + "i2c1_2_grp", "i2c1_3_grp", "i2c1_4_grp", "i2c1_5_grp", + "i2c1_6_grp", "i2c1_7_grp", "i2c1_8_grp", "i2c1_9_grp", + "i2c1_10_grp"}; +static const char * const ttc0_groups[] = {"ttc0_0_grp", "ttc0_1_grp", + "ttc0_2_grp"}; +static const char * const ttc1_groups[] = {"ttc1_0_grp", "ttc1_1_grp", + "ttc1_2_grp"}; +static const char * const swdt0_groups[] = {"swdt0_0_grp", "swdt0_1_grp", + "swdt0_2_grp", "swdt0_3_grp", "swdt0_4_grp"}; +static const char * const gpio0_groups[] = {"gpio0_0_grp", + "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp", + "gpio0_8_grp", "gpio0_10_grp", "gpio0_12_grp", + "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp", + "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp", + "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp", + "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp", + "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp", + "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp", + "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp", + "gpio0_3_grp", "gpio0_5_grp", "gpio0_7_grp", + "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp", + "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp", + "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp", + "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp", + "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp", + "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp", + "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp", + "gpio0_51_grp", "gpio0_53_grp"}; + +#define DEFINE_ZYNQ_PINMUX_FUNCTION(fname, mval) \ + [ZYNQ_PMUX_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + .mux_val = mval, \ + } + +#define DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(fname, mval, mux, mask, shift) \ + [ZYNQ_PMUX_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + .mux_val = mval, \ + .mux_mask = mask, \ + .mux_shift = shift, \ + } + +#define ZYNQ_SDIO_WP_SHIFT 0 +#define ZYNQ_SDIO_WP_MASK (0x3f << ZYNQ_SDIO_WP_SHIFT) +#define ZYNQ_SDIO_CD_SHIFT 16 +#define ZYNQ_SDIO_CD_MASK (0x3f << ZYNQ_SDIO_CD_SHIFT) + +static const struct zynq_pinmux_function zynq_pmux_functions[] = { + DEFINE_ZYNQ_PINMUX_FUNCTION(ethernet0, 1), + DEFINE_ZYNQ_PINMUX_FUNCTION(ethernet1, 1), + DEFINE_ZYNQ_PINMUX_FUNCTION(usb0, 2), + DEFINE_ZYNQ_PINMUX_FUNCTION(usb1, 2), + DEFINE_ZYNQ_PINMUX_FUNCTION(mdio0, 0x40), + DEFINE_ZYNQ_PINMUX_FUNCTION(mdio1, 0x50), + DEFINE_ZYNQ_PINMUX_FUNCTION(qspi0, 1), + DEFINE_ZYNQ_PINMUX_FUNCTION(qspi1, 1), + DEFINE_ZYNQ_PINMUX_FUNCTION(qspi_fbclk, 1), + DEFINE_ZYNQ_PINMUX_FUNCTION(qspi_cs1, 1), + DEFINE_ZYNQ_PINMUX_FUNCTION(spi0, 0x50), + DEFINE_ZYNQ_PINMUX_FUNCTION(spi1, 0x50), + DEFINE_ZYNQ_PINMUX_FUNCTION(sdio0, 0x40), + DEFINE_ZYNQ_PINMUX_FUNCTION(sdio0_pc, 0xc), + DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio0_wp, 0, 130, ZYNQ_SDIO_WP_MASK, + ZYNQ_SDIO_WP_SHIFT), + DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio0_cd, 0, 130, ZYNQ_SDIO_CD_MASK, + ZYNQ_SDIO_CD_SHIFT), + DEFINE_ZYNQ_PINMUX_FUNCTION(sdio1, 0x40), + DEFINE_ZYNQ_PINMUX_FUNCTION(sdio1_pc, 0xc), + DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio1_wp, 0, 134, ZYNQ_SDIO_WP_MASK, + ZYNQ_SDIO_WP_SHIFT), + DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio1_cd, 0, 134, ZYNQ_SDIO_CD_MASK, + ZYNQ_SDIO_CD_SHIFT), + DEFINE_ZYNQ_PINMUX_FUNCTION(smc0_nor, 4), + DEFINE_ZYNQ_PINMUX_FUNCTION(smc0_nor_cs1, 8), + DEFINE_ZYNQ_PINMUX_FUNCTION(smc0_nor_addr25, 4), + DEFINE_ZYNQ_PINMUX_FUNCTION(smc0_nand, 8), + DEFINE_ZYNQ_PINMUX_FUNCTION(can0, 0x10), + DEFINE_ZYNQ_PINMUX_FUNCTION(can1, 0x10), + DEFINE_ZYNQ_PINMUX_FUNCTION(uart0, 0x70), + DEFINE_ZYNQ_PINMUX_FUNCTION(uart1, 0x70), + DEFINE_ZYNQ_PINMUX_FUNCTION(i2c0, 0x20), + DEFINE_ZYNQ_PINMUX_FUNCTION(i2c1, 0x20), + DEFINE_ZYNQ_PINMUX_FUNCTION(ttc0, 0x60), + DEFINE_ZYNQ_PINMUX_FUNCTION(ttc1, 0x60), + DEFINE_ZYNQ_PINMUX_FUNCTION(swdt0, 0x30), + DEFINE_ZYNQ_PINMUX_FUNCTION(gpio0, 0), +}; + + +/* pinctrl */ +static int zynq_pctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->ngroups; +} + +static const char *zynq_pctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->groups[selector].name; +} + +static int zynq_pctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned selector, + const unsigned **pins, + unsigned *num_pins) +{ + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = pctrl->groups[selector].pins; + *num_pins = pctrl->groups[selector].npins; + + return 0; +} + +static const struct pinctrl_ops zynq_pctrl_ops = { + .get_groups_count = zynq_pctrl_get_groups_count, + .get_group_name = zynq_pctrl_get_group_name, + .get_group_pins = zynq_pctrl_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +/* pinmux */ +static int zynq_pmux_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->nfuncs; +} + +static const char *zynq_pmux_get_function_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->funcs[selector].name; +} + +static int zynq_pmux_get_function_groups(struct pinctrl_dev *pctldev, + unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *groups = pctrl->funcs[selector].groups; + *num_groups = pctrl->funcs[selector].ngroups; + return 0; +} + +static int zynq_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) +{ + int i, ret; + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct zynq_pctrl_group *pgrp = &pctrl->groups[group]; + const struct zynq_pinmux_function *func = &pctrl->funcs[function]; + + /* + * SD WP & CD are special. They have dedicated registers + * to mux them in + */ + if (function == ZYNQ_PMUX_sdio0_cd || function == ZYNQ_PMUX_sdio0_wp || + function == ZYNQ_PMUX_sdio1_cd || + function == ZYNQ_PMUX_sdio1_wp) { + u32 reg; + + ret = regmap_read(pctrl->syscon, + pctrl->pctrl_offset + func->mux, ®); + if (ret) + return ret; + + reg &= ~func->mux_mask; + reg |= pgrp->pins[0] << func->mux_shift; + ret = regmap_write(pctrl->syscon, + pctrl->pctrl_offset + func->mux, reg); + if (ret) + return ret; + } else { + for (i = 0; i < pgrp->npins; i++) { + unsigned int pin = pgrp->pins[i]; + u32 reg, addr = pctrl->pctrl_offset + (4 * pin); + + ret = regmap_read(pctrl->syscon, addr, ®); + if (ret) + return ret; + + reg &= ~ZYNQ_PINMUX_MUX_MASK; + reg |= func->mux_val << ZYNQ_PINMUX_MUX_SHIFT; + ret = regmap_write(pctrl->syscon, addr, reg); + if (ret) + return ret; + } + } + + return 0; +} + +static const struct pinmux_ops zynq_pinmux_ops = { + .get_functions_count = zynq_pmux_get_functions_count, + .get_function_name = zynq_pmux_get_function_name, + .get_function_groups = zynq_pmux_get_function_groups, + .set_mux = zynq_pinmux_set_mux, +}; + +/* pinconfig */ +#define ZYNQ_PINCONF_TRISTATE BIT(0) +#define ZYNQ_PINCONF_SPEED BIT(8) +#define ZYNQ_PINCONF_PULLUP BIT(12) +#define ZYNQ_PINCONF_DISABLE_RECVR BIT(13) + +#define ZYNQ_PINCONF_IOTYPE_SHIFT 9 +#define ZYNQ_PINCONF_IOTYPE_MASK (7 << ZYNQ_PINCONF_IOTYPE_SHIFT) + +enum zynq_io_standards { + zynq_iostd_min, + zynq_iostd_lvcmos18, + zynq_iostd_lvcmos25, + zynq_iostd_lvcmos33, + zynq_iostd_hstl, + zynq_iostd_max +}; + +/** + * enum zynq_pin_config_param - possible pin configuration parameters + * @PIN_CONFIG_IOSTANDARD: if the pin can select an IO standard, the argument to + * this parameter (on a custom format) tells the driver which alternative + * IO standard to use. + */ +enum zynq_pin_config_param { + PIN_CONFIG_IOSTANDARD = PIN_CONFIG_END + 1, +}; + +static const struct pinconf_generic_params zynq_dt_params[] = { + {"io-standard", PIN_CONFIG_IOSTANDARD, zynq_iostd_lvcmos18}, +}; + +#ifdef CONFIG_DEBUG_FS +static const struct pin_config_item zynq_conf_items[ARRAY_SIZE(zynq_dt_params)] = { + PCONFDUMP(PIN_CONFIG_IOSTANDARD, "IO-standard", NULL, true), +}; +#endif + +static unsigned int zynq_pinconf_iostd_get(u32 reg) +{ + return (reg & ZYNQ_PINCONF_IOTYPE_MASK) >> ZYNQ_PINCONF_IOTYPE_SHIFT; +} + +static int zynq_pinconf_cfg_get(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *config) +{ + u32 reg; + int ret; + unsigned int arg = 0; + unsigned int param = pinconf_to_config_param(*config); + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + if (pin >= ZYNQ_NUM_MIOS) + return -ENOTSUPP; + + ret = regmap_read(pctrl->syscon, pctrl->pctrl_offset + (4 * pin), ®); + if (ret) + return -EIO; + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + if (!(reg & ZYNQ_PINCONF_PULLUP)) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + if (!(reg & ZYNQ_PINCONF_TRISTATE)) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_BIAS_DISABLE: + if (reg & ZYNQ_PINCONF_PULLUP || reg & ZYNQ_PINCONF_TRISTATE) + return -EINVAL; + break; + case PIN_CONFIG_SLEW_RATE: + arg = !!(reg & ZYNQ_PINCONF_SPEED); + break; + case PIN_CONFIG_LOW_POWER_MODE: + { + enum zynq_io_standards iostd = zynq_pinconf_iostd_get(reg); + + if (iostd != zynq_iostd_hstl) + return -EINVAL; + if (!(reg & ZYNQ_PINCONF_DISABLE_RECVR)) + return -EINVAL; + arg = !!(reg & ZYNQ_PINCONF_DISABLE_RECVR); + break; + } + case PIN_CONFIG_IOSTANDARD: + arg = zynq_pinconf_iostd_get(reg); + break; + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + return 0; +} + +static int zynq_pinconf_cfg_set(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *configs, + unsigned num_configs) +{ + int i, ret; + u32 reg; + u32 pullup = 0; + u32 tristate = 0; + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + if (pin >= ZYNQ_NUM_MIOS) + return -ENOTSUPP; + + ret = regmap_read(pctrl->syscon, pctrl->pctrl_offset + (4 * pin), ®); + if (ret) + return -EIO; + + for (i = 0; i < num_configs; i++) { + unsigned int param = pinconf_to_config_param(configs[i]); + unsigned int arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + pullup = ZYNQ_PINCONF_PULLUP; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + tristate = ZYNQ_PINCONF_TRISTATE; + break; + case PIN_CONFIG_BIAS_DISABLE: + reg &= ~(ZYNQ_PINCONF_PULLUP | ZYNQ_PINCONF_TRISTATE); + break; + case PIN_CONFIG_SLEW_RATE: + if (arg) + reg |= ZYNQ_PINCONF_SPEED; + else + reg &= ~ZYNQ_PINCONF_SPEED; + + break; + case PIN_CONFIG_IOSTANDARD: + if (arg <= zynq_iostd_min || arg >= zynq_iostd_max) { + dev_warn(pctldev->dev, + "unsupported IO standard '%u'\n", + param); + break; + } + reg &= ~ZYNQ_PINCONF_IOTYPE_MASK; + reg |= arg << ZYNQ_PINCONF_IOTYPE_SHIFT; + break; + case PIN_CONFIG_LOW_POWER_MODE: + if (arg) + reg |= ZYNQ_PINCONF_DISABLE_RECVR; + else + reg &= ~ZYNQ_PINCONF_DISABLE_RECVR; + + break; + default: + dev_warn(pctldev->dev, + "unsupported configuration parameter '%u'\n", + param); + continue; + } + } + + if (tristate || pullup) { + reg &= ~(ZYNQ_PINCONF_PULLUP | ZYNQ_PINCONF_TRISTATE); + reg |= tristate | pullup; + } + + ret = regmap_write(pctrl->syscon, pctrl->pctrl_offset + (4 * pin), reg); + if (ret) + return -EIO; + + return 0; +} + +static int zynq_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned selector, + unsigned long *configs, + unsigned num_configs) +{ + int i, ret; + struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct zynq_pctrl_group *pgrp = &pctrl->groups[selector]; + + for (i = 0; i < pgrp->npins; i++) { + ret = zynq_pinconf_cfg_set(pctldev, pgrp->pins[i], configs, + num_configs); + if (ret) + return ret; + } + + return 0; +} + +static const struct pinconf_ops zynq_pinconf_ops = { + .is_generic = true, + .pin_config_get = zynq_pinconf_cfg_get, + .pin_config_set = zynq_pinconf_cfg_set, + .pin_config_group_set = zynq_pinconf_group_set, +}; + +static struct pinctrl_desc zynq_desc = { + .name = "zynq_pinctrl", + .pins = zynq_pins, + .npins = ARRAY_SIZE(zynq_pins), + .pctlops = &zynq_pctrl_ops, + .pmxops = &zynq_pinmux_ops, + .confops = &zynq_pinconf_ops, + .num_custom_params = ARRAY_SIZE(zynq_dt_params), + .custom_params = zynq_dt_params, +#ifdef CONFIG_DEBUG_FS + .custom_conf_items = zynq_conf_items, +#endif + .owner = THIS_MODULE, +}; + +static int zynq_pinctrl_probe(struct platform_device *pdev) + +{ + struct resource *res; + struct zynq_pinctrl *pctrl; + + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->syscon = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "syscon"); + if (IS_ERR(pctrl->syscon)) { + dev_err(&pdev->dev, "unable to get syscon\n"); + return PTR_ERR(pctrl->syscon); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "missing IO resource\n"); + return -ENODEV; + } + pctrl->pctrl_offset = res->start; + + pctrl->groups = zynq_pctrl_groups; + pctrl->ngroups = ARRAY_SIZE(zynq_pctrl_groups); + pctrl->funcs = zynq_pmux_functions; + pctrl->nfuncs = ARRAY_SIZE(zynq_pmux_functions); + + pctrl->pctrl = pinctrl_register(&zynq_desc, &pdev->dev, pctrl); + if (!pctrl->pctrl) + return -ENOMEM; + + platform_set_drvdata(pdev, pctrl); + + dev_info(&pdev->dev, "zynq pinctrl initialized\n"); + + return 0; +} + +int zynq_pinctrl_remove(struct platform_device *pdev) +{ + struct zynq_pinctrl *pctrl = platform_get_drvdata(pdev); + + pinctrl_unregister(pctrl->pctrl); + + return 0; +} + +static const struct of_device_id zynq_pinctrl_of_match[] = { + { .compatible = "xlnx,pinctrl-zynq" }, + { } +}; +MODULE_DEVICE_TABLE(of, zynq_pinctrl_of_match); + +static struct platform_driver zynq_pinctrl_driver = { + .driver = { + .name = "zynq-pinctrl", + .of_match_table = zynq_pinctrl_of_match, + }, + .probe = zynq_pinctrl_probe, + .remove = zynq_pinctrl_remove, +}; + +module_platform_driver(zynq_pinctrl_driver); + +MODULE_AUTHOR("Sören Brinkmann "); +MODULE_DESCRIPTION("Xilinx Zynq pinctrl driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 3cd243c26b7d..ea575f60f001 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -47,6 +47,14 @@ config PINCTRL_MSM8X74 This is the pinctrl, pinmux, pinconf and gpiolib driver for the Qualcomm TLMM block found in the Qualcomm 8974 platform. +config PINCTRL_MSM8916 + tristate "Qualcomm 8916 pin controller driver" + depends on GPIOLIB && OF + select PINCTRL_MSM + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm TLMM block found on the Qualcomm 8916 platform. + config PINCTRL_QCOM_SPMI_PMIC tristate "Qualcomm SPMI PMIC pin controller driver" depends on GPIOLIB && OF && SPMI diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index bfd79af5f982..68958702917d 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -5,5 +5,6 @@ obj-$(CONFIG_PINCTRL_APQ8084) += pinctrl-apq8084.o obj-$(CONFIG_PINCTRL_IPQ8064) += pinctrl-ipq8064.o obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o +obj-$(CONFIG_PINCTRL_MSM8916) += pinctrl-msm8916.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index e730935fa457..a535f9c23678 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -204,21 +204,6 @@ static int msm_config_reg(struct msm_pinctrl *pctrl, return 0; } -static int msm_config_get(struct pinctrl_dev *pctldev, - unsigned int pin, - unsigned long *config) -{ - dev_err(pctldev->dev, "pin_config_set op not supported\n"); - return -ENOTSUPP; -} - -static int msm_config_set(struct pinctrl_dev *pctldev, unsigned int pin, - unsigned long *configs, unsigned num_configs) -{ - dev_err(pctldev->dev, "pin_config_set op not supported\n"); - return -ENOTSUPP; -} - #define MSM_NO_PULL 0 #define MSM_PULL_DOWN 1 #define MSM_KEEPER 2 @@ -372,8 +357,6 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev, } static const struct pinconf_ops msm_pinconf_ops = { - .pin_config_get = msm_config_get, - .pin_config_set = msm_config_set, .pin_config_group_get = msm_config_group_get, .pin_config_group_set = msm_config_group_set, }; @@ -865,10 +848,10 @@ static int msm_ps_hold_restart(struct notifier_block *nb, unsigned long action, static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) { - int i = 0; + int i; const struct msm_function *func = pctrl->soc->functions; - for (; i <= pctrl->soc->nfunctions; i++) + for (i = 0; i < pctrl->soc->nfunctions; i++) if (!strcmp(func[i].name, "ps_hold")) { pctrl->restart_nb.notifier_call = msm_ps_hold_restart; pctrl->restart_nb.priority = 128; diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h index b952c4b4a8e9..54fdd04ce9d5 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.h +++ b/drivers/pinctrl/qcom/pinctrl-msm.h @@ -70,11 +70,11 @@ struct msm_pingroup { unsigned *funcs; unsigned nfuncs; - s16 ctl_reg; - s16 io_reg; - s16 intr_cfg_reg; - s16 intr_status_reg; - s16 intr_target_reg; + u32 ctl_reg; + u32 io_reg; + u32 intr_cfg_reg; + u32 intr_status_reg; + u32 intr_target_reg; unsigned mux_bit:5; diff --git a/drivers/pinctrl/qcom/pinctrl-msm8916.c b/drivers/pinctrl/qcom/pinctrl-msm8916.c new file mode 100644 index 000000000000..20ebf244e80d --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-msm8916.c @@ -0,0 +1,1005 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "pinctrl-msm.h" + +static const struct pinctrl_pin_desc msm8916_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(63, "GPIO_63"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + PINCTRL_PIN(69, "GPIO_69"), + PINCTRL_PIN(70, "GPIO_70"), + PINCTRL_PIN(71, "GPIO_71"), + PINCTRL_PIN(72, "GPIO_72"), + PINCTRL_PIN(73, "GPIO_73"), + PINCTRL_PIN(74, "GPIO_74"), + PINCTRL_PIN(75, "GPIO_75"), + PINCTRL_PIN(76, "GPIO_76"), + PINCTRL_PIN(77, "GPIO_77"), + PINCTRL_PIN(78, "GPIO_78"), + PINCTRL_PIN(79, "GPIO_79"), + PINCTRL_PIN(80, "GPIO_80"), + PINCTRL_PIN(81, "GPIO_81"), + PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), + PINCTRL_PIN(86, "GPIO_86"), + PINCTRL_PIN(87, "GPIO_87"), + PINCTRL_PIN(88, "GPIO_88"), + PINCTRL_PIN(89, "GPIO_89"), + PINCTRL_PIN(90, "GPIO_90"), + PINCTRL_PIN(91, "GPIO_91"), + PINCTRL_PIN(92, "GPIO_92"), + PINCTRL_PIN(93, "GPIO_93"), + PINCTRL_PIN(94, "GPIO_94"), + PINCTRL_PIN(95, "GPIO_95"), + PINCTRL_PIN(96, "GPIO_96"), + PINCTRL_PIN(97, "GPIO_97"), + PINCTRL_PIN(98, "GPIO_98"), + PINCTRL_PIN(99, "GPIO_99"), + PINCTRL_PIN(100, "GPIO_100"), + PINCTRL_PIN(101, "GPIO_101"), + PINCTRL_PIN(102, "GPIO_102"), + PINCTRL_PIN(103, "GPIO_103"), + PINCTRL_PIN(104, "GPIO_104"), + PINCTRL_PIN(105, "GPIO_105"), + PINCTRL_PIN(106, "GPIO_106"), + PINCTRL_PIN(107, "GPIO_107"), + PINCTRL_PIN(108, "GPIO_108"), + PINCTRL_PIN(109, "GPIO_109"), + PINCTRL_PIN(110, "GPIO_110"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "GPIO_114"), + PINCTRL_PIN(115, "GPIO_115"), + PINCTRL_PIN(116, "GPIO_116"), + PINCTRL_PIN(117, "GPIO_117"), + PINCTRL_PIN(118, "GPIO_118"), + PINCTRL_PIN(119, "GPIO_119"), + PINCTRL_PIN(120, "GPIO_120"), + PINCTRL_PIN(121, "GPIO_121"), + PINCTRL_PIN(122, "SDC1_CLK"), + PINCTRL_PIN(123, "SDC1_CMD"), + PINCTRL_PIN(124, "SDC1_DATA"), + PINCTRL_PIN(125, "SDC2_CLK"), + PINCTRL_PIN(126, "SDC2_CMD"), + PINCTRL_PIN(127, "SDC2_DATA"), + PINCTRL_PIN(128, "QDSD_CLK"), + PINCTRL_PIN(129, "QDSD_CMD"), + PINCTRL_PIN(130, "QDSD_DATA0"), + PINCTRL_PIN(131, "QDSD_DATA1"), + PINCTRL_PIN(132, "QDSD_DATA2"), + PINCTRL_PIN(133, "QDSD_DATA3"), +}; + +#define DECLARE_MSM_GPIO_PINS(pin) \ + static const unsigned int gpio##pin##_pins[] = { pin } + +DECLARE_MSM_GPIO_PINS(0); +DECLARE_MSM_GPIO_PINS(1); +DECLARE_MSM_GPIO_PINS(2); +DECLARE_MSM_GPIO_PINS(3); +DECLARE_MSM_GPIO_PINS(4); +DECLARE_MSM_GPIO_PINS(5); +DECLARE_MSM_GPIO_PINS(6); +DECLARE_MSM_GPIO_PINS(7); +DECLARE_MSM_GPIO_PINS(8); +DECLARE_MSM_GPIO_PINS(9); +DECLARE_MSM_GPIO_PINS(10); +DECLARE_MSM_GPIO_PINS(11); +DECLARE_MSM_GPIO_PINS(12); +DECLARE_MSM_GPIO_PINS(13); +DECLARE_MSM_GPIO_PINS(14); +DECLARE_MSM_GPIO_PINS(15); +DECLARE_MSM_GPIO_PINS(16); +DECLARE_MSM_GPIO_PINS(17); +DECLARE_MSM_GPIO_PINS(18); +DECLARE_MSM_GPIO_PINS(19); +DECLARE_MSM_GPIO_PINS(20); +DECLARE_MSM_GPIO_PINS(21); +DECLARE_MSM_GPIO_PINS(22); +DECLARE_MSM_GPIO_PINS(23); +DECLARE_MSM_GPIO_PINS(24); +DECLARE_MSM_GPIO_PINS(25); +DECLARE_MSM_GPIO_PINS(26); +DECLARE_MSM_GPIO_PINS(27); +DECLARE_MSM_GPIO_PINS(28); +DECLARE_MSM_GPIO_PINS(29); +DECLARE_MSM_GPIO_PINS(30); +DECLARE_MSM_GPIO_PINS(31); +DECLARE_MSM_GPIO_PINS(32); +DECLARE_MSM_GPIO_PINS(33); +DECLARE_MSM_GPIO_PINS(34); +DECLARE_MSM_GPIO_PINS(35); +DECLARE_MSM_GPIO_PINS(36); +DECLARE_MSM_GPIO_PINS(37); +DECLARE_MSM_GPIO_PINS(38); +DECLARE_MSM_GPIO_PINS(39); +DECLARE_MSM_GPIO_PINS(40); +DECLARE_MSM_GPIO_PINS(41); +DECLARE_MSM_GPIO_PINS(42); +DECLARE_MSM_GPIO_PINS(43); +DECLARE_MSM_GPIO_PINS(44); +DECLARE_MSM_GPIO_PINS(45); +DECLARE_MSM_GPIO_PINS(46); +DECLARE_MSM_GPIO_PINS(47); +DECLARE_MSM_GPIO_PINS(48); +DECLARE_MSM_GPIO_PINS(49); +DECLARE_MSM_GPIO_PINS(50); +DECLARE_MSM_GPIO_PINS(51); +DECLARE_MSM_GPIO_PINS(52); +DECLARE_MSM_GPIO_PINS(53); +DECLARE_MSM_GPIO_PINS(54); +DECLARE_MSM_GPIO_PINS(55); +DECLARE_MSM_GPIO_PINS(56); +DECLARE_MSM_GPIO_PINS(57); +DECLARE_MSM_GPIO_PINS(58); +DECLARE_MSM_GPIO_PINS(59); +DECLARE_MSM_GPIO_PINS(60); +DECLARE_MSM_GPIO_PINS(61); +DECLARE_MSM_GPIO_PINS(62); +DECLARE_MSM_GPIO_PINS(63); +DECLARE_MSM_GPIO_PINS(64); +DECLARE_MSM_GPIO_PINS(65); +DECLARE_MSM_GPIO_PINS(66); +DECLARE_MSM_GPIO_PINS(67); +DECLARE_MSM_GPIO_PINS(68); +DECLARE_MSM_GPIO_PINS(69); +DECLARE_MSM_GPIO_PINS(70); +DECLARE_MSM_GPIO_PINS(71); +DECLARE_MSM_GPIO_PINS(72); +DECLARE_MSM_GPIO_PINS(73); +DECLARE_MSM_GPIO_PINS(74); +DECLARE_MSM_GPIO_PINS(75); +DECLARE_MSM_GPIO_PINS(76); +DECLARE_MSM_GPIO_PINS(77); +DECLARE_MSM_GPIO_PINS(78); +DECLARE_MSM_GPIO_PINS(79); +DECLARE_MSM_GPIO_PINS(80); +DECLARE_MSM_GPIO_PINS(81); +DECLARE_MSM_GPIO_PINS(82); +DECLARE_MSM_GPIO_PINS(83); +DECLARE_MSM_GPIO_PINS(84); +DECLARE_MSM_GPIO_PINS(85); +DECLARE_MSM_GPIO_PINS(86); +DECLARE_MSM_GPIO_PINS(87); +DECLARE_MSM_GPIO_PINS(88); +DECLARE_MSM_GPIO_PINS(89); +DECLARE_MSM_GPIO_PINS(90); +DECLARE_MSM_GPIO_PINS(91); +DECLARE_MSM_GPIO_PINS(92); +DECLARE_MSM_GPIO_PINS(93); +DECLARE_MSM_GPIO_PINS(94); +DECLARE_MSM_GPIO_PINS(95); +DECLARE_MSM_GPIO_PINS(96); +DECLARE_MSM_GPIO_PINS(97); +DECLARE_MSM_GPIO_PINS(98); +DECLARE_MSM_GPIO_PINS(99); +DECLARE_MSM_GPIO_PINS(100); +DECLARE_MSM_GPIO_PINS(101); +DECLARE_MSM_GPIO_PINS(102); +DECLARE_MSM_GPIO_PINS(103); +DECLARE_MSM_GPIO_PINS(104); +DECLARE_MSM_GPIO_PINS(105); +DECLARE_MSM_GPIO_PINS(106); +DECLARE_MSM_GPIO_PINS(107); +DECLARE_MSM_GPIO_PINS(108); +DECLARE_MSM_GPIO_PINS(109); +DECLARE_MSM_GPIO_PINS(110); +DECLARE_MSM_GPIO_PINS(111); +DECLARE_MSM_GPIO_PINS(112); +DECLARE_MSM_GPIO_PINS(113); +DECLARE_MSM_GPIO_PINS(114); +DECLARE_MSM_GPIO_PINS(115); +DECLARE_MSM_GPIO_PINS(116); +DECLARE_MSM_GPIO_PINS(117); +DECLARE_MSM_GPIO_PINS(118); +DECLARE_MSM_GPIO_PINS(119); +DECLARE_MSM_GPIO_PINS(120); +DECLARE_MSM_GPIO_PINS(121); + +static const unsigned int sdc1_clk_pins[] = { 122 }; +static const unsigned int sdc1_cmd_pins[] = { 123 }; +static const unsigned int sdc1_data_pins[] = { 124 }; +static const unsigned int sdc2_clk_pins[] = { 125 }; +static const unsigned int sdc2_cmd_pins[] = { 126 }; +static const unsigned int sdc2_data_pins[] = { 127 }; +static const unsigned int qdsd_clk_pins[] = { 128 }; +static const unsigned int qdsd_cmd_pins[] = { 129 }; +static const unsigned int qdsd_data0_pins[] = { 130 }; +static const unsigned int qdsd_data1_pins[] = { 131 }; +static const unsigned int qdsd_data2_pins[] = { 132 }; +static const unsigned int qdsd_data3_pins[] = { 133 }; + +#define FUNCTION(fname) \ + [MSM_MUX_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \ + { \ + .name = "gpio" #id, \ + .pins = gpio##id##_pins, \ + .npins = ARRAY_SIZE(gpio##id##_pins), \ + .funcs = (int[]){ \ + MSM_MUX_gpio, \ + MSM_MUX_##f1, \ + MSM_MUX_##f2, \ + MSM_MUX_##f3, \ + MSM_MUX_##f4, \ + MSM_MUX_##f5, \ + MSM_MUX_##f6, \ + MSM_MUX_##f7, \ + MSM_MUX_##f8, \ + MSM_MUX_##f9 \ + }, \ + .nfuncs = 10, \ + .ctl_reg = 0x1000 * id, \ + .io_reg = 0x4 + 0x1000 * id, \ + .intr_cfg_reg = 0x8 + 0x1000 * id, \ + .intr_status_reg = 0xc + 0x1000 * id, \ + .intr_target_reg = 0x8 + 0x1000 * id, \ + .mux_bit = 2, \ + .pull_bit = 0, \ + .drv_bit = 6, \ + .oe_bit = 9, \ + .in_bit = 0, \ + .out_bit = 1, \ + .intr_enable_bit = 0, \ + .intr_status_bit = 0, \ + .intr_target_bit = 5, \ + .intr_target_kpss_val = 4, \ + .intr_raw_status_bit = 4, \ + .intr_polarity_bit = 1, \ + .intr_detection_bit = 2, \ + .intr_detection_width = 2, \ + } + +#define SDC_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = ARRAY_SIZE(pg_name##_pins), \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_target_kpss_val = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +enum msm8916_functions { + MSM_MUX_adsp_ext, + MSM_MUX_alsp_int, + MSM_MUX_atest_bbrx0, + MSM_MUX_atest_bbrx1, + MSM_MUX_atest_char, + MSM_MUX_atest_char0, + MSM_MUX_atest_char1, + MSM_MUX_atest_char2, + MSM_MUX_atest_char3, + MSM_MUX_atest_combodac, + MSM_MUX_atest_gpsadc0, + MSM_MUX_atest_gpsadc1, + MSM_MUX_atest_tsens, + MSM_MUX_atest_wlan0, + MSM_MUX_atest_wlan1, + MSM_MUX_backlight_en, + MSM_MUX_bimc_dte0, + MSM_MUX_bimc_dte1, + MSM_MUX_blsp_i2c1, + MSM_MUX_blsp_i2c2, + MSM_MUX_blsp_i2c3, + MSM_MUX_blsp_i2c4, + MSM_MUX_blsp_i2c5, + MSM_MUX_blsp_i2c6, + MSM_MUX_blsp_spi1, + MSM_MUX_blsp_spi1_cs1, + MSM_MUX_blsp_spi1_cs2, + MSM_MUX_blsp_spi1_cs3, + MSM_MUX_blsp_spi2, + MSM_MUX_blsp_spi2_cs1, + MSM_MUX_blsp_spi2_cs2, + MSM_MUX_blsp_spi2_cs3, + MSM_MUX_blsp_spi3, + MSM_MUX_blsp_spi3_cs1, + MSM_MUX_blsp_spi3_cs2, + MSM_MUX_blsp_spi3_cs3, + MSM_MUX_blsp_spi4, + MSM_MUX_blsp_spi5, + MSM_MUX_blsp_spi6, + MSM_MUX_blsp_uart1, + MSM_MUX_blsp_uart2, + MSM_MUX_blsp_uim1, + MSM_MUX_blsp_uim2, + MSM_MUX_cam1_rst, + MSM_MUX_cam1_standby, + MSM_MUX_cam_mclk0, + MSM_MUX_cam_mclk1, + MSM_MUX_cci_async, + MSM_MUX_cci_i2c, + MSM_MUX_cci_timer0, + MSM_MUX_cci_timer1, + MSM_MUX_cci_timer2, + MSM_MUX_cdc_pdm0, + MSM_MUX_codec_mad, + MSM_MUX_dbg_out, + MSM_MUX_display_5v, + MSM_MUX_dmic0_clk, + MSM_MUX_dmic0_data, + MSM_MUX_dsi_rst, + MSM_MUX_ebi0_wrcdc, + MSM_MUX_euro_us, + MSM_MUX_ext_lpass, + MSM_MUX_flash_strobe, + MSM_MUX_gcc_gp1_clk_a, + MSM_MUX_gcc_gp1_clk_b, + MSM_MUX_gcc_gp2_clk_a, + MSM_MUX_gcc_gp2_clk_b, + MSM_MUX_gcc_gp3_clk_a, + MSM_MUX_gcc_gp3_clk_b, + MSM_MUX_gpio, + MSM_MUX_gsm0_tx0, + MSM_MUX_gsm0_tx1, + MSM_MUX_gsm1_tx0, + MSM_MUX_gsm1_tx1, + MSM_MUX_gyro_accl, + MSM_MUX_kpsns0, + MSM_MUX_kpsns1, + MSM_MUX_kpsns2, + MSM_MUX_ldo_en, + MSM_MUX_ldo_update, + MSM_MUX_mag_int, + MSM_MUX_mdp_vsync, + MSM_MUX_modem_tsync, + MSM_MUX_m_voc, + MSM_MUX_nav_pps, + MSM_MUX_nav_tsync, + MSM_MUX_pa_indicator, + MSM_MUX_pbs0, + MSM_MUX_pbs1, + MSM_MUX_pbs2, + MSM_MUX_pri_mi2s, + MSM_MUX_pri_mi2s_ws, + MSM_MUX_prng_rosc, + MSM_MUX_pwr_crypto_enabled_a, + MSM_MUX_pwr_crypto_enabled_b, + MSM_MUX_pwr_modem_enabled_a, + MSM_MUX_pwr_modem_enabled_b, + MSM_MUX_pwr_nav_enabled_a, + MSM_MUX_pwr_nav_enabled_b, + MSM_MUX_qdss_ctitrig_in_a0, + MSM_MUX_qdss_ctitrig_in_a1, + MSM_MUX_qdss_ctitrig_in_b0, + MSM_MUX_qdss_ctitrig_in_b1, + MSM_MUX_qdss_ctitrig_out_a0, + MSM_MUX_qdss_ctitrig_out_a1, + MSM_MUX_qdss_ctitrig_out_b0, + MSM_MUX_qdss_ctitrig_out_b1, + MSM_MUX_qdss_traceclk_a, + MSM_MUX_qdss_traceclk_b, + MSM_MUX_qdss_tracectl_a, + MSM_MUX_qdss_tracectl_b, + MSM_MUX_qdss_tracedata_a, + MSM_MUX_qdss_tracedata_b, + MSM_MUX_reset_n, + MSM_MUX_sd_card, + MSM_MUX_sd_write, + MSM_MUX_sec_mi2s, + MSM_MUX_smb_int, + MSM_MUX_ssbi_wtr0, + MSM_MUX_ssbi_wtr1, + MSM_MUX_uim1, + MSM_MUX_uim2, + MSM_MUX_uim3, + MSM_MUX_uim_batt, + MSM_MUX_wcss_bt, + MSM_MUX_wcss_fm, + MSM_MUX_wcss_wlan, + MSM_MUX_webcam1_rst, + MSM_MUX_NA, +}; + +static const char * const gpio_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", + "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", + "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", + "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", + "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", + "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49", + "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56", + "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", + "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70", + "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77", + "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84", + "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91", + "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98", + "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104", + "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110", + "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116", + "gpio117", "gpio118", "gpio119", "gpio120", "gpio121" +}; +static const char * const adsp_ext_groups[] = { "gpio38" }; +static const char * const alsp_int_groups[] = { "gpio113" }; +static const char * const atest_bbrx0_groups[] = { "gpio17" }; +static const char * const atest_bbrx1_groups[] = { "gpio16" }; +static const char * const atest_char_groups[] = { "gpio62" }; +static const char * const atest_char0_groups[] = { "gpio60" }; +static const char * const atest_char1_groups[] = { "gpio59" }; +static const char * const atest_char2_groups[] = { "gpio58" }; +static const char * const atest_char3_groups[] = { "gpio57" }; +static const char * const atest_combodac_groups[] = { + "gpio4", "gpio12", "gpio13", "gpio20", "gpio21", "gpio28", "gpio29", + "gpio30", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43", "gpio44", + "gpio45", "gpio46", "gpio47", "gpio48", "gpio69", "gpio107" +}; +static const char * const atest_gpsadc0_groups[] = { "gpio7" }; +static const char * const atest_gpsadc1_groups[] = { "gpio18" }; +static const char * const atest_tsens_groups[] = { "gpio112" }; +static const char * const atest_wlan0_groups[] = { "gpio22" }; +static const char * const atest_wlan1_groups[] = { "gpio23" }; +static const char * const backlight_en_groups[] = { "gpio98" }; +static const char * const bimc_dte0_groups[] = { "gpio63", "gpio65" }; +static const char * const bimc_dte1_groups[] = { "gpio64", "gpio66" }; +static const char * const blsp_i2c1_groups[] = { "gpio2", "gpio3" }; +static const char * const blsp_i2c2_groups[] = { "gpio6", "gpio7" }; +static const char * const blsp_i2c3_groups[] = { "gpio10", "gpio11" }; +static const char * const blsp_i2c4_groups[] = { "gpio14", "gpio15" }; +static const char * const blsp_i2c5_groups[] = { "gpio18", "gpio19" }; +static const char * const blsp_i2c6_groups[] = { "gpio22", "gpio23" }; +static const char * const blsp_spi1_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3" +}; +static const char * const blsp_spi1_cs1_groups[] = { "gpio110" }; +static const char * const blsp_spi1_cs2_groups[] = { "gpio16" }; +static const char * const blsp_spi1_cs3_groups[] = { "gpio4" }; +static const char * const blsp_spi2_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7" +}; +static const char * const blsp_spi2_cs1_groups[] = { "gpio121" }; +static const char * const blsp_spi2_cs2_groups[] = { "gpio17" }; +static const char * const blsp_spi2_cs3_groups[] = { "gpio5" }; +static const char * const blsp_spi3_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio11" +}; +static const char * const blsp_spi3_cs1_groups[] = { "gpio120" }; +static const char * const blsp_spi3_cs2_groups[] = { "gpio37" }; +static const char * const blsp_spi3_cs3_groups[] = { "gpio69" }; +static const char * const blsp_spi4_groups[] = { + "gpio12", "gpio13", "gpio14", "gpio15" +}; +static const char * const blsp_spi5_groups[] = { + "gpio16", "gpio17", "gpio18", "gpio19" +}; +static const char * const blsp_spi6_groups[] = { + "gpio20", "gpio21", "gpio22", "gpio23" +}; +static const char * const blsp_uart1_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3" +}; +static const char * const blsp_uart2_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7" +}; +static const char * const blsp_uim1_groups[] = { "gpio0", "gpio1" }; +static const char * const blsp_uim2_groups[] = { "gpio4", "gpio5" }; +static const char * const cam1_rst_groups[] = { "gpio35" }; +static const char * const cam1_standby_groups[] = { "gpio34" }; +static const char * const cam_mclk0_groups[] = { "gpio26" }; +static const char * const cam_mclk1_groups[] = { "gpio27" }; +static const char * const cci_async_groups[] = { "gpio33" }; +static const char * const cci_i2c_groups[] = { "gpio29", "gpio30" }; +static const char * const cci_timer0_groups[] = { "gpio31" }; +static const char * const cci_timer1_groups[] = { "gpio32" }; +static const char * const cci_timer2_groups[] = { "gpio38" }; +static const char * const cdc_pdm0_groups[] = { + "gpio63", "gpio64", "gpio65", "gpio66", "gpio67", "gpio68" +}; +static const char * const codec_mad_groups[] = { "gpio16" }; +static const char * const dbg_out_groups[] = { "gpio47" }; +static const char * const display_5v_groups[] = { "gpio97" }; +static const char * const dmic0_clk_groups[] = { "gpio0" }; +static const char * const dmic0_data_groups[] = { "gpio1" }; +static const char * const dsi_rst_groups[] = { "gpio25" }; +static const char * const ebi0_wrcdc_groups[] = { "gpio67" }; +static const char * const euro_us_groups[] = { "gpio120" }; +static const char * const ext_lpass_groups[] = { "gpio45" }; +static const char * const flash_strobe_groups[] = { "gpio31", "gpio32" }; +static const char * const gcc_gp1_clk_a_groups[] = { "gpio49" }; +static const char * const gcc_gp1_clk_b_groups[] = { "gpio97" }; +static const char * const gcc_gp2_clk_a_groups[] = { "gpio50" }; +static const char * const gcc_gp2_clk_b_groups[] = { "gpio12" }; +static const char * const gcc_gp3_clk_a_groups[] = { "gpio51" }; +static const char * const gcc_gp3_clk_b_groups[] = { "gpio13" }; +static const char * const gsm0_tx0_groups[] = { "gpio99" }; +static const char * const gsm0_tx1_groups[] = { "gpio100" }; +static const char * const gsm1_tx0_groups[] = { "gpio101" }; +static const char * const gsm1_tx1_groups[] = { "gpio102" }; +static const char * const gyro_accl_groups[] = {"gpio115" }; +static const char * const kpsns0_groups[] = { "gpio107" }; +static const char * const kpsns1_groups[] = { "gpio108" }; +static const char * const kpsns2_groups[] = { "gpio109" }; +static const char * const ldo_en_groups[] = { "gpio121" }; +static const char * const ldo_update_groups[] = { "gpio120" }; +static const char * const mag_int_groups[] = { "gpio69" }; +static const char * const mdp_vsync_groups[] = { "gpio24", "gpio25" }; +static const char * const modem_tsync_groups[] = { "gpio95" }; +static const char * const m_voc_groups[] = { "gpio8", "gpio119" }; +static const char * const nav_pps_groups[] = { "gpio95" }; +static const char * const nav_tsync_groups[] = { "gpio95" }; +static const char * const pa_indicator_groups[] = { "gpio86" }; +static const char * const pbs0_groups[] = { "gpio107" }; +static const char * const pbs1_groups[] = { "gpio108" }; +static const char * const pbs2_groups[] = { "gpio109" }; +static const char * const pri_mi2s_groups[] = { + "gpio113", "gpio114", "gpio115", "gpio116" +}; +static const char * const pri_mi2s_ws_groups[] = { "gpio110" }; +static const char * const prng_rosc_groups[] = { "gpio43" }; +static const char * const pwr_crypto_enabled_a_groups[] = { "gpio35" }; +static const char * const pwr_crypto_enabled_b_groups[] = { "gpio115" }; +static const char * const pwr_modem_enabled_a_groups[] = { "gpio28" }; +static const char * const pwr_modem_enabled_b_groups[] = { "gpio113" }; +static const char * const pwr_nav_enabled_a_groups[] = { "gpio34" }; +static const char * const pwr_nav_enabled_b_groups[] = { "gpio114" }; +static const char * const qdss_ctitrig_in_a0_groups[] = { "gpio20" }; +static const char * const qdss_ctitrig_in_a1_groups[] = { "gpio49" }; +static const char * const qdss_ctitrig_in_b0_groups[] = { "gpio21" }; +static const char * const qdss_ctitrig_in_b1_groups[] = { "gpio50" }; +static const char * const qdss_ctitrig_out_a0_groups[] = { "gpio23" }; +static const char * const qdss_ctitrig_out_a1_groups[] = { "gpio52" }; +static const char * const qdss_ctitrig_out_b0_groups[] = { "gpio22" }; +static const char * const qdss_ctitrig_out_b1_groups[] = { "gpio51" }; +static const char * const qdss_traceclk_a_groups[] = { "gpio46" }; +static const char * const qdss_traceclk_b_groups[] = { "gpio5" }; +static const char * const qdss_tracectl_a_groups[] = { "gpio45" }; +static const char * const qdss_tracectl_b_groups[] = { "gpio4" }; +static const char * const qdss_tracedata_a_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio39", "gpio40", "gpio41", "gpio42", + "gpio43", "gpio47", "gpio48", "gpio62", "gpio69", "gpio112", "gpio113", + "gpio114", "gpio115" +}; +static const char * const qdss_tracedata_b_groups[] = { + "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32", + "gpio33", "gpio34", "gpio35", "gpio36", "gpio37", "gpio110", "gpio111", + "gpio120", "gpio121" +}; +static const char * const reset_n_groups[] = { "gpio36" }; +static const char * const sd_card_groups[] = { "gpio38" }; +static const char * const sd_write_groups[] = { "gpio121" }; +static const char * const sec_mi2s_groups[] = { + "gpio112", "gpio117", "gpio118", "gpio119" +}; +static const char * const smb_int_groups[] = { "gpio62" }; +static const char * const ssbi_wtr0_groups[] = { "gpio103", "gpio104" }; +static const char * const ssbi_wtr1_groups[] = { "gpio105", "gpio106" }; +static const char * const uim1_groups[] = { + "gpio57", "gpio58", "gpio59", "gpio60" +}; + +static const char * const uim2_groups[] = { + "gpio53", "gpio54", "gpio55", "gpio56" +}; +static const char * const uim3_groups[] = { + "gpio49", "gpio50", "gpio51", "gpio52" +}; +static const char * const uim_batt_groups[] = { "gpio61" }; +static const char * const wcss_bt_groups[] = { "gpio39", "gpio47", "gpio48" }; +static const char * const wcss_fm_groups[] = { "gpio45", "gpio46" }; +static const char * const wcss_wlan_groups[] = { + "gpio40", "gpio41", "gpio42", "gpio43", "gpio44" +}; +static const char * const webcam1_rst_groups[] = { "gpio28" }; + +static const struct msm_function msm8916_functions[] = { + FUNCTION(adsp_ext), + FUNCTION(alsp_int), + FUNCTION(atest_bbrx0), + FUNCTION(atest_bbrx1), + FUNCTION(atest_char), + FUNCTION(atest_char0), + FUNCTION(atest_char1), + FUNCTION(atest_char2), + FUNCTION(atest_char3), + FUNCTION(atest_combodac), + FUNCTION(atest_gpsadc0), + FUNCTION(atest_gpsadc1), + FUNCTION(atest_tsens), + FUNCTION(atest_wlan0), + FUNCTION(atest_wlan1), + FUNCTION(backlight_en), + FUNCTION(bimc_dte0), + FUNCTION(bimc_dte1), + FUNCTION(blsp_i2c1), + FUNCTION(blsp_i2c2), + FUNCTION(blsp_i2c3), + FUNCTION(blsp_i2c4), + FUNCTION(blsp_i2c5), + FUNCTION(blsp_i2c6), + FUNCTION(blsp_spi1), + FUNCTION(blsp_spi1_cs1), + FUNCTION(blsp_spi1_cs2), + FUNCTION(blsp_spi1_cs3), + FUNCTION(blsp_spi2), + FUNCTION(blsp_spi2_cs1), + FUNCTION(blsp_spi2_cs2), + FUNCTION(blsp_spi2_cs3), + FUNCTION(blsp_spi3), + FUNCTION(blsp_spi3_cs1), + FUNCTION(blsp_spi3_cs2), + FUNCTION(blsp_spi3_cs3), + FUNCTION(blsp_spi4), + FUNCTION(blsp_spi5), + FUNCTION(blsp_spi6), + FUNCTION(blsp_uart1), + FUNCTION(blsp_uart2), + FUNCTION(blsp_uim1), + FUNCTION(blsp_uim2), + FUNCTION(cam1_rst), + FUNCTION(cam1_standby), + FUNCTION(cam_mclk0), + FUNCTION(cam_mclk1), + FUNCTION(cci_async), + FUNCTION(cci_i2c), + FUNCTION(cci_timer0), + FUNCTION(cci_timer1), + FUNCTION(cci_timer2), + FUNCTION(cdc_pdm0), + FUNCTION(codec_mad), + FUNCTION(dbg_out), + FUNCTION(display_5v), + FUNCTION(dmic0_clk), + FUNCTION(dmic0_data), + FUNCTION(dsi_rst), + FUNCTION(ebi0_wrcdc), + FUNCTION(euro_us), + FUNCTION(ext_lpass), + FUNCTION(flash_strobe), + FUNCTION(gcc_gp1_clk_a), + FUNCTION(gcc_gp1_clk_b), + FUNCTION(gcc_gp2_clk_a), + FUNCTION(gcc_gp2_clk_b), + FUNCTION(gcc_gp3_clk_a), + FUNCTION(gcc_gp3_clk_b), + FUNCTION(gpio), + FUNCTION(gsm0_tx0), + FUNCTION(gsm0_tx1), + FUNCTION(gsm1_tx0), + FUNCTION(gsm1_tx1), + FUNCTION(gyro_accl), + FUNCTION(kpsns0), + FUNCTION(kpsns1), + FUNCTION(kpsns2), + FUNCTION(ldo_en), + FUNCTION(ldo_update), + FUNCTION(mag_int), + FUNCTION(mdp_vsync), + FUNCTION(modem_tsync), + FUNCTION(m_voc), + FUNCTION(nav_pps), + FUNCTION(nav_tsync), + FUNCTION(pa_indicator), + FUNCTION(pbs0), + FUNCTION(pbs1), + FUNCTION(pbs2), + FUNCTION(pri_mi2s), + FUNCTION(pri_mi2s_ws), + FUNCTION(prng_rosc), + FUNCTION(pwr_crypto_enabled_a), + FUNCTION(pwr_crypto_enabled_b), + FUNCTION(pwr_modem_enabled_a), + FUNCTION(pwr_modem_enabled_b), + FUNCTION(pwr_nav_enabled_a), + FUNCTION(pwr_nav_enabled_b), + FUNCTION(qdss_ctitrig_in_a0), + FUNCTION(qdss_ctitrig_in_a1), + FUNCTION(qdss_ctitrig_in_b0), + FUNCTION(qdss_ctitrig_in_b1), + FUNCTION(qdss_ctitrig_out_a0), + FUNCTION(qdss_ctitrig_out_a1), + FUNCTION(qdss_ctitrig_out_b0), + FUNCTION(qdss_ctitrig_out_b1), + FUNCTION(qdss_traceclk_a), + FUNCTION(qdss_traceclk_b), + FUNCTION(qdss_tracectl_a), + FUNCTION(qdss_tracectl_b), + FUNCTION(qdss_tracedata_a), + FUNCTION(qdss_tracedata_b), + FUNCTION(reset_n), + FUNCTION(sd_card), + FUNCTION(sd_write), + FUNCTION(sec_mi2s), + FUNCTION(smb_int), + FUNCTION(ssbi_wtr0), + FUNCTION(ssbi_wtr1), + FUNCTION(uim1), + FUNCTION(uim2), + FUNCTION(uim3), + FUNCTION(uim_batt), + FUNCTION(wcss_bt), + FUNCTION(wcss_fm), + FUNCTION(wcss_wlan), + FUNCTION(webcam1_rst) +}; + +static const struct msm_pingroup msm8916_groups[] = { + PINGROUP(0, blsp_spi1, blsp_uart1, blsp_uim1, dmic0_clk, NA, NA, NA, NA, NA), + PINGROUP(1, blsp_spi1, blsp_uart1, blsp_uim1, dmic0_data, NA, NA, NA, NA, NA), + PINGROUP(2, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, NA, NA), + PINGROUP(3, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, NA, NA), + PINGROUP(4, blsp_spi2, blsp_uart2, blsp_uim2, blsp_spi1_cs3, qdss_tracectl_b, NA, atest_combodac, NA, NA), + PINGROUP(5, blsp_spi2, blsp_uart2, blsp_uim2, blsp_spi2_cs3, qdss_traceclk_b, NA, NA, NA, NA), + PINGROUP(6, blsp_spi2, blsp_uart2, blsp_i2c2, NA, NA, NA, NA, NA, NA), + PINGROUP(7, blsp_spi2, blsp_uart2, blsp_i2c2, NA, NA, NA, NA, NA, NA), + PINGROUP(8, blsp_spi3, m_voc, qdss_tracedata_a, NA, NA, NA, NA, NA, NA), + PINGROUP(9, blsp_spi3, qdss_tracedata_a, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(10, blsp_spi3, blsp_i2c3, qdss_tracedata_a, NA, NA, NA, NA, NA, NA), + PINGROUP(11, blsp_spi3, blsp_i2c3, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(12, blsp_spi4, gcc_gp2_clk_b, NA, atest_combodac, NA, NA, NA, NA, NA), + PINGROUP(13, blsp_spi4, gcc_gp3_clk_b, NA, atest_combodac, NA, NA, NA, NA, NA), + PINGROUP(14, blsp_spi4, blsp_i2c4, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(15, blsp_spi4, blsp_i2c4, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(16, blsp_spi5, blsp_spi1_cs2, NA, atest_bbrx1, NA, NA, NA, NA, NA), + PINGROUP(17, blsp_spi5, blsp_spi2_cs2, NA, atest_bbrx0, NA, NA, NA, NA, NA), + PINGROUP(18, blsp_spi5, blsp_i2c5, NA, atest_gpsadc1, NA, NA, NA, NA, NA), + PINGROUP(19, blsp_spi5, blsp_i2c5, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(20, blsp_spi6, NA, NA, NA, NA, NA, NA, qdss_ctitrig_in_a0, NA), + PINGROUP(21, blsp_spi6, NA, NA, NA, NA, NA, NA, qdss_ctitrig_in_b0, NA), + PINGROUP(22, blsp_spi6, blsp_i2c6, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(23, blsp_spi6, blsp_i2c6, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(24, mdp_vsync, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(25, mdp_vsync, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(26, cam_mclk0, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, NA), + PINGROUP(27, cam_mclk1, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b), + PINGROUP(28, pwr_modem_enabled_a, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, atest_combodac), + PINGROUP(29, cci_i2c, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, atest_combodac), + PINGROUP(30, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b), + PINGROUP(31, cci_timer0, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(32, cci_timer1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(33, cci_async, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b), + PINGROUP(34, pwr_nav_enabled_a, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b), + PINGROUP(35, pwr_crypto_enabled_a, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b), + PINGROUP(36, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b, NA), + PINGROUP(37, blsp_spi3_cs2, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, NA), + PINGROUP(38, cci_timer2, adsp_ext, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(39, wcss_bt, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA, NA), + PINGROUP(40, wcss_wlan, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA, NA), + PINGROUP(41, wcss_wlan, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA, NA), + PINGROUP(42, wcss_wlan, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA, NA), + PINGROUP(43, wcss_wlan, prng_rosc, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA), + PINGROUP(44, wcss_wlan, NA, atest_combodac, NA, NA, NA, NA, NA, NA), + PINGROUP(45, wcss_fm, ext_lpass, qdss_tracectl_a, NA, atest_combodac, NA, NA, NA, NA), + PINGROUP(46, wcss_fm, qdss_traceclk_a, NA, atest_combodac, NA, NA, NA, NA, NA), + PINGROUP(47, wcss_bt, dbg_out, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA), + PINGROUP(48, wcss_bt, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA, NA), + PINGROUP(49, uim3, gcc_gp1_clk_a, qdss_ctitrig_in_a1, NA, NA, NA, NA, NA, NA), + PINGROUP(50, uim3, gcc_gp2_clk_a, qdss_ctitrig_in_b1, NA, NA, NA, NA, NA, NA), + PINGROUP(51, uim3, gcc_gp3_clk_a, qdss_ctitrig_out_b1, NA, NA, NA, NA, NA, NA), + PINGROUP(52, uim3, NA, qdss_ctitrig_out_a1, NA, NA, NA, NA, NA, NA), + PINGROUP(53, uim2, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(54, uim2, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(55, uim2, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(56, uim2, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(57, uim1, atest_char3, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(58, uim1, atest_char2, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(59, uim1, atest_char1, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(60, uim1, atest_char0, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(61, uim_batt, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(62, atest_char, qdss_tracedata_a, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(63, cdc_pdm0, bimc_dte0, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(64, cdc_pdm0, bimc_dte1, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(65, cdc_pdm0, bimc_dte0, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(66, cdc_pdm0, bimc_dte1, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(67, cdc_pdm0, ebi0_wrcdc, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(68, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(69, blsp_spi3_cs3, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA, NA), + PINGROUP(70, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(71, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(72, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(73, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(74, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(75, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(76, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(77, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(78, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(79, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(80, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(81, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(82, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(83, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(84, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(85, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(86, NA, pa_indicator, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(87, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(88, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(89, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(90, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(91, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(92, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(93, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(94, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(95, NA, modem_tsync, nav_tsync, nav_pps, NA, NA, NA, NA, NA), + PINGROUP(96, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(97, gcc_gp1_clk_b, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(98, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(99, gsm0_tx0, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(100, gsm0_tx1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(101, gsm1_tx0, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(102, gsm1_tx1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(103, ssbi_wtr0, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(104, ssbi_wtr0, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(105, ssbi_wtr1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(106, ssbi_wtr1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(107, pbs0, NA, atest_combodac, NA, NA, NA, NA, NA, NA), + PINGROUP(108, pbs1, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(109, pbs2, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(110, blsp_spi1_cs1, pri_mi2s_ws, NA, qdss_tracedata_b, NA, NA, NA, NA, NA), + PINGROUP(111, qdss_tracedata_b, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(112, sec_mi2s, NA, NA, NA, qdss_tracedata_a, NA, atest_tsens, NA, NA), + PINGROUP(113, pri_mi2s, NA, pwr_modem_enabled_b, NA, NA, NA, NA, NA, qdss_tracedata_a), + PINGROUP(114, pri_mi2s, pwr_nav_enabled_b, NA, NA, NA, NA, NA, qdss_tracedata_a, NA), + PINGROUP(115, pri_mi2s, pwr_crypto_enabled_b, NA, NA, NA, NA, NA, qdss_tracedata_a, NA), + PINGROUP(116, pri_mi2s, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(117, sec_mi2s, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(118, sec_mi2s, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(119, sec_mi2s, m_voc, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(120, blsp_spi3_cs1, ldo_update, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(121, sd_write, blsp_spi2_cs1, ldo_en, NA, NA, NA, NA, NA, NA), + SDC_PINGROUP(sdc1_clk, 0x10a000, 13, 6), + SDC_PINGROUP(sdc1_cmd, 0x10a000, 11, 3), + SDC_PINGROUP(sdc1_data, 0x10a000, 9, 0), + SDC_PINGROUP(sdc2_clk, 0x109000, 14, 6), + SDC_PINGROUP(sdc2_cmd, 0x109000, 11, 3), + SDC_PINGROUP(sdc2_data, 0x109000, 9, 0), + SDC_PINGROUP(qdsd_clk, 0x19c000, 3, 0), + SDC_PINGROUP(qdsd_cmd, 0x19c000, 8, 5), + SDC_PINGROUP(qdsd_data0, 0x19c000, 13, 10), + SDC_PINGROUP(qdsd_data1, 0x19c000, 18, 15), + SDC_PINGROUP(qdsd_data2, 0x19c000, 23, 20), + SDC_PINGROUP(qdsd_data3, 0x19c000, 28, 25), +}; + +#define NUM_GPIO_PINGROUPS 122 + +static const struct msm_pinctrl_soc_data msm8916_pinctrl = { + .pins = msm8916_pins, + .npins = ARRAY_SIZE(msm8916_pins), + .functions = msm8916_functions, + .nfunctions = ARRAY_SIZE(msm8916_functions), + .groups = msm8916_groups, + .ngroups = ARRAY_SIZE(msm8916_groups), + .ngpios = NUM_GPIO_PINGROUPS, +}; + +static int msm8916_pinctrl_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &msm8916_pinctrl); +} + +static const struct of_device_id msm8916_pinctrl_of_match[] = { + { .compatible = "qcom,msm8916-pinctrl", }, + { }, +}; + +static struct platform_driver msm8916_pinctrl_driver = { + .driver = { + .name = "msm8916-pinctrl", + .of_match_table = msm8916_pinctrl_of_match, + }, + .probe = msm8916_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init msm8916_pinctrl_init(void) +{ + return platform_driver_register(&msm8916_pinctrl_driver); +} +arch_initcall(msm8916_pinctrl_init); + +static void __exit msm8916_pinctrl_exit(void) +{ + platform_driver_unregister(&msm8916_pinctrl_driver); +} +module_exit(msm8916_pinctrl_exit); + +MODULE_DESCRIPTION("Qualcomm msm8916 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, msm8916_pinctrl_of_match); diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index b863b5080890..0f11a26d932b 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -131,15 +131,17 @@ struct pmic_gpio_state { struct gpio_chip chip; }; -struct pmic_gpio_bindings { - const char *property; - unsigned param; +static const struct pinconf_generic_params pmic_gpio_bindings[] = { + {"qcom,pull-up-strength", PMIC_GPIO_CONF_PULL_UP, 0}, + {"qcom,drive-strength", PMIC_GPIO_CONF_STRENGTH, 0}, }; -static struct pmic_gpio_bindings pmic_gpio_bindings[] = { - {"qcom,pull-up-strength", PMIC_GPIO_CONF_PULL_UP}, - {"qcom,drive-strength", PMIC_GPIO_CONF_STRENGTH}, +#ifdef CONFIG_DEBUG_FS +static const struct pin_config_item pmic_conf_items[ARRAY_SIZE(pmic_gpio_bindings)] = { + PCONFDUMP(PMIC_GPIO_CONF_PULL_UP, "pull up strength", NULL, true), + PCONFDUMP(PMIC_GPIO_CONF_STRENGTH, "drive-strength", NULL, true), }; +#endif static const char *const pmic_gpio_groups[] = { "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8", @@ -209,118 +211,11 @@ static int pmic_gpio_get_group_pins(struct pinctrl_dev *pctldev, unsigned pin, return 0; } -static int pmic_gpio_parse_dt_config(struct device_node *np, - struct pinctrl_dev *pctldev, - unsigned long **configs, - unsigned int *nconfs) -{ - struct pmic_gpio_bindings *par; - unsigned long cfg; - int ret, i; - u32 val; - - for (i = 0; i < ARRAY_SIZE(pmic_gpio_bindings); i++) { - par = &pmic_gpio_bindings[i]; - ret = of_property_read_u32(np, par->property, &val); - - /* property not found */ - if (ret == -EINVAL) - continue; - - /* use zero as default value */ - if (ret) - val = 0; - - dev_dbg(pctldev->dev, "found %s with value %u\n", - par->property, val); - - cfg = pinconf_to_config_packed(par->param, val); - - ret = pinctrl_utils_add_config(pctldev, configs, nconfs, cfg); - if (ret) - return ret; - } - - return 0; -} - -static int pmic_gpio_dt_subnode_to_map(struct pinctrl_dev *pctldev, - struct device_node *np, - struct pinctrl_map **map, - unsigned *reserv, unsigned *nmaps, - enum pinctrl_map_type type) -{ - unsigned long *configs = NULL; - unsigned nconfs = 0; - struct property *prop; - const char *group; - int ret; - - ret = pmic_gpio_parse_dt_config(np, pctldev, &configs, &nconfs); - if (ret < 0) - return ret; - - if (!nconfs) - return 0; - - ret = of_property_count_strings(np, "pins"); - if (ret < 0) - goto exit; - - ret = pinctrl_utils_reserve_map(pctldev, map, reserv, nmaps, ret); - if (ret < 0) - goto exit; - - of_property_for_each_string(np, "pins", prop, group) { - ret = pinctrl_utils_add_map_configs(pctldev, map, - reserv, nmaps, group, - configs, nconfs, type); - if (ret < 0) - break; - } -exit: - kfree(configs); - return ret; -} - -static int pmic_gpio_dt_node_to_map(struct pinctrl_dev *pctldev, - struct device_node *np_config, - struct pinctrl_map **map, unsigned *nmaps) -{ - enum pinctrl_map_type type; - struct device_node *np; - unsigned reserv; - int ret; - - ret = 0; - *map = NULL; - *nmaps = 0; - reserv = 0; - type = PIN_MAP_TYPE_CONFIGS_GROUP; - - for_each_child_of_node(np_config, np) { - ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map, - &reserv, nmaps, type); - if (ret) - break; - - ret = pmic_gpio_dt_subnode_to_map(pctldev, np, map, &reserv, - nmaps, type); - if (ret) - break; - } - - if (ret < 0) - pinctrl_utils_dt_free_map(pctldev, *map, *nmaps); - - return ret; -} - static const struct pinctrl_ops pmic_gpio_pinctrl_ops = { .get_groups_count = pmic_gpio_get_groups_count, .get_group_name = pmic_gpio_get_group_name, .get_group_pins = pmic_gpio_get_group_pins, - .dt_node_to_map = pmic_gpio_dt_node_to_map, + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, .dt_free_map = pinctrl_utils_dt_free_map, }; @@ -590,6 +485,7 @@ static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev, } static const struct pinconf_ops pmic_gpio_pinconf_ops = { + .is_generic = true, .pin_config_group_get = pmic_gpio_config_get, .pin_config_group_set = pmic_gpio_config_set, .pin_config_group_dbg_show = pmic_gpio_config_dbg_show, @@ -848,6 +744,11 @@ static int pmic_gpio_probe(struct platform_device *pdev) pctrldesc->name = dev_name(dev); pctrldesc->pins = pindesc; pctrldesc->npins = npins; + pctrldesc->num_custom_params = ARRAY_SIZE(pmic_gpio_bindings); + pctrldesc->custom_params = pmic_gpio_bindings; +#ifdef CONFIG_DEBUG_FS + pctrldesc->custom_conf_items = pmic_conf_items; +#endif for (i = 0; i < npins; i++, pindesc++) { pad = &pads[i]; diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index becb3792977b..c8f83f96546c 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -1300,6 +1300,25 @@ static const struct samsung_pin_bank_data exynos7_pin_banks7[] __initconst = { EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpr3", 0x0c), }; +/* pin banks of exynos7 pin-controller - BUS1 */ +static const struct samsung_pin_bank_data exynos7_pin_banks8[] __initconst = { + EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpf0", 0x00), + EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpf1", 0x04), + EXYNOS_PIN_BANK_EINTG(4, 0x060, "gpf2", 0x08), + EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpf3", 0x0c), + EXYNOS_PIN_BANK_EINTG(8, 0x0a0, "gpf4", 0x10), + EXYNOS_PIN_BANK_EINTG(8, 0x0c0, "gpf5", 0x14), + EXYNOS_PIN_BANK_EINTG(5, 0x0e0, "gpg1", 0x18), + EXYNOS_PIN_BANK_EINTG(5, 0x100, "gpg2", 0x1c), + EXYNOS_PIN_BANK_EINTG(6, 0x120, "gph1", 0x20), + EXYNOS_PIN_BANK_EINTG(3, 0x140, "gpv6", 0x24), +}; + +static const struct samsung_pin_bank_data exynos7_pin_banks9[] __initconst = { + EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00), + EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04), +}; + const struct samsung_pin_ctrl exynos7_pin_ctrl[] __initconst = { { /* pin-controller instance 0 Alive data */ @@ -1342,5 +1361,15 @@ const struct samsung_pin_ctrl exynos7_pin_ctrl[] __initconst = { .pin_banks = exynos7_pin_banks7, .nr_banks = ARRAY_SIZE(exynos7_pin_banks7), .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 8 BUS1 data */ + .pin_banks = exynos7_pin_banks8, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks8), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 9 AUD data */ + .pin_banks = exynos7_pin_banks9, + .nr_banks = ARRAY_SIZE(exynos7_pin_banks9), + .eint_gpio_init = exynos_eint_gpio_init, }, }; diff --git a/drivers/pinctrl/sh-pfc/Kconfig b/drivers/pinctrl/sh-pfc/Kconfig index 26187aa5cf5b..8c4b3d391823 100644 --- a/drivers/pinctrl/sh-pfc/Kconfig +++ b/drivers/pinctrl/sh-pfc/Kconfig @@ -20,6 +20,11 @@ config GPIO_SH_PFC This enables support for GPIOs within the SoC's pin function controller. +config PINCTRL_PFC_EMEV2 + def_bool y + depends on ARCH_EMEV2 + select PINCTRL_SH_PFC + config PINCTRL_PFC_R8A73A4 def_bool y depends on ARCH_R8A73A4 @@ -68,11 +73,6 @@ config PINCTRL_PFC_SH7269 depends on GPIOLIB select PINCTRL_SH_PFC -config PINCTRL_PFC_SH7372 - def_bool y - depends on ARCH_SH7372 - select PINCTRL_SH_PFC - config PINCTRL_PFC_SH73A0 def_bool y depends on ARCH_SH73A0 diff --git a/drivers/pinctrl/sh-pfc/Makefile b/drivers/pinctrl/sh-pfc/Makefile index ad8f4cf9faaa..f4074e166bcf 100644 --- a/drivers/pinctrl/sh-pfc/Makefile +++ b/drivers/pinctrl/sh-pfc/Makefile @@ -3,6 +3,7 @@ ifeq ($(CONFIG_GPIO_SH_PFC),y) sh-pfc-objs += gpio.o endif obj-$(CONFIG_PINCTRL_SH_PFC) += sh-pfc.o +obj-$(CONFIG_PINCTRL_PFC_EMEV2) += pfc-emev2.o obj-$(CONFIG_PINCTRL_PFC_R8A73A4) += pfc-r8a73a4.o obj-$(CONFIG_PINCTRL_PFC_R8A7740) += pfc-r8a7740.o obj-$(CONFIG_PINCTRL_PFC_R8A7778) += pfc-r8a7778.o @@ -12,7 +13,6 @@ obj-$(CONFIG_PINCTRL_PFC_R8A7791) += pfc-r8a7791.o obj-$(CONFIG_PINCTRL_PFC_SH7203) += pfc-sh7203.o obj-$(CONFIG_PINCTRL_PFC_SH7264) += pfc-sh7264.o obj-$(CONFIG_PINCTRL_PFC_SH7269) += pfc-sh7269.o -obj-$(CONFIG_PINCTRL_PFC_SH7372) += pfc-sh7372.o obj-$(CONFIG_PINCTRL_PFC_SH73A0) += pfc-sh73a0.o obj-$(CONFIG_PINCTRL_PFC_SH7720) += pfc-sh7720.o obj-$(CONFIG_PINCTRL_PFC_SH7722) += pfc-sh7722.o diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index 66dc62d2156c..a56280814a3f 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -439,6 +439,12 @@ static int sh_pfc_init_ranges(struct sh_pfc *pfc) #ifdef CONFIG_OF static const struct of_device_id sh_pfc_of_table[] = { +#ifdef CONFIG_PINCTRL_PFC_EMEV2 + { + .compatible = "renesas,pfc-emev2", + .data = &emev2_pinmux_info, + }, +#endif #ifdef CONFIG_PINCTRL_PFC_R8A73A4 { .compatible = "renesas,pfc-r8a73a4", @@ -475,12 +481,6 @@ static const struct of_device_id sh_pfc_of_table[] = { .data = &r8a7791_pinmux_info, }, #endif -#ifdef CONFIG_PINCTRL_PFC_SH7372 - { - .compatible = "renesas,pfc-sh7372", - .data = &sh7372_pinmux_info, - }, -#endif #ifdef CONFIG_PINCTRL_PFC_SH73A0 { .compatible = "renesas,pfc-sh73a0", @@ -579,6 +579,9 @@ static int sh_pfc_remove(struct platform_device *pdev) } static const struct platform_device_id sh_pfc_id_table[] = { +#ifdef CONFIG_PINCTRL_PFC_EMEV2 + { "pfc-emev2", (kernel_ulong_t)&emev2_pinmux_info }, +#endif #ifdef CONFIG_PINCTRL_PFC_R8A73A4 { "pfc-r8a73a4", (kernel_ulong_t)&r8a73a4_pinmux_info }, #endif @@ -606,9 +609,6 @@ static const struct platform_device_id sh_pfc_id_table[] = { #ifdef CONFIG_PINCTRL_PFC_SH7269 { "pfc-sh7269", (kernel_ulong_t)&sh7269_pinmux_info }, #endif -#ifdef CONFIG_PINCTRL_PFC_SH7372 - { "pfc-sh7372", (kernel_ulong_t)&sh7372_pinmux_info }, -#endif #ifdef CONFIG_PINCTRL_PFC_SH73A0 { "pfc-sh73a0", (kernel_ulong_t)&sh73a0_pinmux_info }, #endif diff --git a/drivers/pinctrl/sh-pfc/core.h b/drivers/pinctrl/sh-pfc/core.h index 3daaa5241c47..6b59d63b9c01 100644 --- a/drivers/pinctrl/sh-pfc/core.h +++ b/drivers/pinctrl/sh-pfc/core.h @@ -65,6 +65,7 @@ void sh_pfc_write_raw_reg(void __iomem *mapped_reg, unsigned long reg_width, int sh_pfc_get_pin_index(struct sh_pfc *pfc, unsigned int pin); int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type); +extern const struct sh_pfc_soc_info emev2_pinmux_info; extern const struct sh_pfc_soc_info r8a73a4_pinmux_info; extern const struct sh_pfc_soc_info r8a7740_pinmux_info; extern const struct sh_pfc_soc_info r8a7778_pinmux_info; @@ -74,7 +75,6 @@ extern const struct sh_pfc_soc_info r8a7791_pinmux_info; extern const struct sh_pfc_soc_info sh7203_pinmux_info; extern const struct sh_pfc_soc_info sh7264_pinmux_info; extern const struct sh_pfc_soc_info sh7269_pinmux_info; -extern const struct sh_pfc_soc_info sh7372_pinmux_info; extern const struct sh_pfc_soc_info sh73a0_pinmux_info; extern const struct sh_pfc_soc_info sh7720_pinmux_info; extern const struct sh_pfc_soc_info sh7722_pinmux_info; diff --git a/drivers/pinctrl/sh-pfc/pfc-emev2.c b/drivers/pinctrl/sh-pfc/pfc-emev2.c new file mode 100644 index 000000000000..849c6943ed30 --- /dev/null +++ b/drivers/pinctrl/sh-pfc/pfc-emev2.c @@ -0,0 +1,1711 @@ +/* + * Pin Function Controller Support + * + * Copyright (C) 2015 Niklas Söderlund + * + * 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. + */ +#include +#include + +#include "sh_pfc.h" + +#define CPU_ALL_PORT(fn, pfx, sfx) \ + PORT_10(0, fn, pfx, sfx), PORT_90(0, fn, pfx, sfx), \ + PORT_10(100, fn, pfx##10, sfx), PORT_10(110, fn, pfx##11, sfx), \ + PORT_10(120, fn, pfx##12, sfx), PORT_10(130, fn, pfx##13, sfx), \ + PORT_10(140, fn, pfx##14, sfx), PORT_1(150, fn, pfx##150, sfx), \ + PORT_1(151, fn, pfx##151, sfx), PORT_1(152, fn, pfx##152, sfx), \ + PORT_1(153, fn, pfx##153, sfx), PORT_1(154, fn, pfx##154, sfx), \ + PORT_1(155, fn, pfx##155, sfx), PORT_1(156, fn, pfx##156, sfx), \ + PORT_1(157, fn, pfx##157, sfx), PORT_1(158, fn, pfx##158, sfx) + +enum { + PINMUX_RESERVED = 0, + + PINMUX_DATA_BEGIN, + PORT_ALL(DATA), + PINMUX_DATA_END, + + PINMUX_FUNCTION_BEGIN, + PORT_ALL(FN), + + /* GPSR0 */ + FN_LCD3_1_0_PORT18, FN_LCD3_1_0_PORT20, FN_LCD3_1_0_PORT21, + FN_LCD3_1_0_PORT22, FN_LCD3_1_0_PORT23, + FN_JT_SEL, FN_ERR_RST_REQB, FN_REF_CLKO, FN_EXT_CLKI, FN_LCD3_PXCLKB, + + /* GPSR1 */ + FN_LCD3_9_8_PORT38, FN_LCD3_9_8_PORT39, FN_LCD3_11_10_PORT40, + FN_LCD3_11_10_PORT41, FN_LCD3_11_10_PORT42, FN_LCD3_11_10_PORT43, + FN_IIC_1_0_PORT46, FN_IIC_1_0_PORT47, + FN_LCD3_R0, FN_LCD3_R1, FN_LCD3_R2, FN_LCD3_R3, FN_LCD3_R4, FN_LCD3_R5, + FN_IIC0_SCL, FN_IIC0_SDA, FN_SD_CKI, FN_SDI0_CKO, FN_SDI0_CKI, + FN_SDI0_CMD, FN_SDI0_DATA0, FN_SDI0_DATA1, FN_SDI0_DATA2, + FN_SDI0_DATA3, FN_SDI0_DATA4, FN_SDI0_DATA5, FN_SDI0_DATA6, + FN_SDI0_DATA7, FN_SDI1_CKO, FN_SDI1_CKI, FN_SDI1_CMD, + + /* GPSR2 */ + FN_AB_1_0_PORT71, FN_AB_1_0_PORT72, FN_AB_1_0_PORT73, + FN_AB_1_0_PORT74, FN_AB_1_0_PORT75, FN_AB_1_0_PORT76, + FN_AB_1_0_PORT77, FN_AB_1_0_PORT78, FN_AB_1_0_PORT79, + FN_AB_1_0_PORT80, FN_AB_1_0_PORT81, FN_AB_1_0_PORT82, + FN_AB_1_0_PORT83, FN_AB_1_0_PORT84, FN_AB_3_2_PORT85, + FN_AB_3_2_PORT86, FN_AB_3_2_PORT87, FN_AB_3_2_PORT88, + FN_AB_5_4_PORT89, FN_AB_5_4_PORT90, FN_AB_7_6_PORT91, + FN_AB_7_6_PORT92, FN_AB_1_0_PORT93, FN_AB_1_0_PORT94, + FN_AB_1_0_PORT95, + FN_SDI1_DATA0, FN_SDI1_DATA1, FN_SDI1_DATA2, FN_SDI1_DATA3, + FN_AB_CLK, FN_AB_CSB0, FN_AB_CSB1, + + /* GPSR3 */ + FN_AB_13_12_PORT104, FN_AB_13_12_PORT103, FN_AB_11_10_PORT102, + FN_AB_11_10_PORT101, FN_AB_11_10_PORT100, FN_AB_9_8_PORT99, + FN_AB_9_8_PORT98, FN_AB_9_8_PORT97, + FN_USI_1_0_PORT109, FN_USI_1_0_PORT110, FN_USI_1_0_PORT111, + FN_USI_1_0_PORT112, FN_USI_3_2_PORT113, FN_USI_3_2_PORT114, + FN_USI_5_4_PORT115, FN_USI_5_4_PORT116, FN_USI_5_4_PORT117, + FN_USI_5_4_PORT118, FN_USI_7_6_PORT119, FN_USI_9_8_PORT120, + FN_USI_9_8_PORT121, + FN_AB_A20, FN_USI0_CS1, FN_USI0_CS2, FN_USI1_DI, + FN_USI1_DO, + FN_NTSC_CLK, FN_NTSC_DATA0, FN_NTSC_DATA1, FN_NTSC_DATA2, + FN_NTSC_DATA3, FN_NTSC_DATA4, + + /* GPRS4 */ + FN_HSI_1_0_PORT143, FN_HSI_1_0_PORT144, FN_HSI_1_0_PORT145, + FN_HSI_1_0_PORT146, FN_HSI_1_0_PORT147, FN_HSI_1_0_PORT148, + FN_HSI_1_0_PORT149, FN_HSI_1_0_PORT150, + FN_UART_1_0_PORT157, FN_UART_1_0_PORT158, + FN_NTSC_DATA5, FN_NTSC_DATA6, FN_NTSC_DATA7, FN_CAM_CLKO, + FN_CAM_CLKI, FN_CAM_VS, FN_CAM_HS, FN_CAM_YUV0, + FN_CAM_YUV1, FN_CAM_YUV2, FN_CAM_YUV3, FN_CAM_YUV4, + FN_CAM_YUV5, FN_CAM_YUV6, FN_CAM_YUV7, + FN_JT_TDO, FN_JT_TDOEN, FN_LOWPWR, FN_USB_VBUS, FN_UART1_RX, + FN_UART1_TX, + + /* CHG_PINSEL_LCD3 */ + FN_SEL_LCD3_1_0_00, FN_SEL_LCD3_1_0_01, + FN_SEL_LCD3_9_8_00, FN_SEL_LCD3_9_8_10, + FN_SEL_LCD3_11_10_00, FN_SEL_LCD3_11_10_01, FN_SEL_LCD3_11_10_10, + + /* CHG_PINSEL_IIC */ + FN_SEL_IIC_1_0_00, FN_SEL_IIC_1_0_01, + + /* CHG_PINSEL_AB */ + FN_SEL_AB_1_0_00, FN_SEL_AB_1_0_10, FN_SEL_AB_3_2_00, + FN_SEL_AB_3_2_01, FN_SEL_AB_3_2_10, FN_SEL_AB_3_2_11, + FN_SEL_AB_5_4_00, FN_SEL_AB_5_4_01, FN_SEL_AB_5_4_10, + FN_SEL_AB_5_4_11, FN_SEL_AB_7_6_00, FN_SEL_AB_7_6_01, + FN_SEL_AB_7_6_10, + FN_SEL_AB_9_8_00, FN_SEL_AB_9_8_01, FN_SEL_AB_9_8_10, + FN_SEL_AB_11_10_00, FN_SEL_AB_11_10_10, + FN_SEL_AB_13_12_00, FN_SEL_AB_13_12_10, + + /* CHG_PINSEL_USI */ + FN_SEL_USI_1_0_00, FN_SEL_USI_1_0_01, + FN_SEL_USI_3_2_00, FN_SEL_USI_3_2_01, + FN_SEL_USI_5_4_00, FN_SEL_USI_5_4_01, + FN_SEL_USI_7_6_00, FN_SEL_USI_7_6_01, + FN_SEL_USI_9_8_00, FN_SEL_USI_9_8_01, + + /* CHG_PINSEL_HSI */ + FN_SEL_HSI_1_0_00, FN_SEL_HSI_1_0_01, + + /* CHG_PINSEL_UART */ + FN_SEL_UART_1_0_00, FN_SEL_UART_1_0_01, + + PINMUX_FUNCTION_END, + + PINMUX_MARK_BEGIN, + + /* GPSR0 */ + JT_SEL_MARK, ERR_RST_REQB_MARK, REF_CLKO_MARK, EXT_CLKI_MARK, + LCD3_PXCLKB_MARK, SD_CKI_MARK, + + /* GPSR1 */ + LCD3_R0_MARK, LCD3_R1_MARK, LCD3_R2_MARK, LCD3_R3_MARK, LCD3_R4_MARK, + LCD3_R5_MARK, IIC0_SCL_MARK, IIC0_SDA_MARK, SDI0_CKO_MARK, + SDI0_CKI_MARK, SDI0_CMD_MARK, SDI0_DATA0_MARK, SDI0_DATA1_MARK, + SDI0_DATA2_MARK, SDI0_DATA3_MARK, SDI0_DATA4_MARK, SDI0_DATA5_MARK, + SDI0_DATA6_MARK, SDI0_DATA7_MARK, SDI1_CKO_MARK, SDI1_CKI_MARK, + SDI1_CMD_MARK, + + /* GPSR2 */ + SDI1_DATA0_MARK, SDI1_DATA1_MARK, SDI1_DATA2_MARK, SDI1_DATA3_MARK, + AB_CLK_MARK, AB_CSB0_MARK, AB_CSB1_MARK, + + /* GPSR3 */ + AB_A20_MARK, USI0_CS1_MARK, USI0_CS2_MARK, USI1_DI_MARK, + USI1_DO_MARK, + NTSC_CLK_MARK, NTSC_DATA0_MARK, NTSC_DATA1_MARK, NTSC_DATA2_MARK, + NTSC_DATA3_MARK, NTSC_DATA4_MARK, + + /* GPSR3 */ + NTSC_DATA5_MARK, NTSC_DATA6_MARK, NTSC_DATA7_MARK, CAM_CLKO_MARK, + CAM_CLKI_MARK, CAM_VS_MARK, CAM_HS_MARK, CAM_YUV0_MARK, + CAM_YUV1_MARK, CAM_YUV2_MARK, CAM_YUV3_MARK, CAM_YUV4_MARK, + CAM_YUV5_MARK, CAM_YUV6_MARK, CAM_YUV7_MARK, + JT_TDO_MARK, JT_TDOEN_MARK, USB_VBUS_MARK, LOWPWR_MARK, + UART1_RX_MARK, UART1_TX_MARK, + + /* CHG_PINSEL_LCD3 */ + LCD3_PXCLK_MARK, LCD3_CLK_I_MARK, LCD3_HS_MARK, LCD3_VS_MARK, + LCD3_DE_MARK, LCD3_R6_MARK, LCD3_R7_MARK, LCD3_G0_MARK, LCD3_G1_MARK, + LCD3_G2_MARK, LCD3_G3_MARK, LCD3_G4_MARK, LCD3_G5_MARK, LCD3_G6_MARK, + LCD3_G7_MARK, LCD3_B0_MARK, LCD3_B1_MARK, LCD3_B2_MARK, LCD3_B3_MARK, + LCD3_B4_MARK, LCD3_B5_MARK, LCD3_B6_MARK, LCD3_B7_MARK, + YUV3_CLK_O_MARK, YUV3_CLK_I_MARK, YUV3_HS_MARK, YUV3_VS_MARK, + YUV3_DE_MARK, YUV3_D0_MARK, YUV3_D1_MARK, YUV3_D2_MARK, YUV3_D3_MARK, + YUV3_D4_MARK, YUV3_D5_MARK, YUV3_D6_MARK, YUV3_D7_MARK, YUV3_D8_MARK, + YUV3_D9_MARK, YUV3_D10_MARK, YUV3_D11_MARK, YUV3_D12_MARK, + YUV3_D13_MARK, YUV3_D14_MARK, YUV3_D15_MARK, + TP33_CLK_MARK, TP33_CTRL_MARK, TP33_DATA0_MARK, TP33_DATA1_MARK, + TP33_DATA2_MARK, TP33_DATA3_MARK, TP33_DATA4_MARK, TP33_DATA5_MARK, + TP33_DATA6_MARK, TP33_DATA7_MARK, TP33_DATA8_MARK, TP33_DATA9_MARK, + TP33_DATA10_MARK, TP33_DATA11_MARK, TP33_DATA12_MARK, TP33_DATA13_MARK, + TP33_DATA14_MARK, TP33_DATA15_MARK, + + /* CHG_PINSEL_IIC */ + IIC1_SCL_MARK, IIC1_SDA_MARK, UART3_RX_MARK, UART3_TX_MARK, + + /* CHG_PINSEL_AB */ + AB_CSB2_MARK, AB_CSB3_MARK, AB_RDB_MARK, AB_WRB_MARK, + AB_WAIT_MARK, AB_ADV_MARK, AB_AD0_MARK, AB_AD1_MARK, + AB_AD2_MARK, AB_AD3_MARK, AB_AD4_MARK, AB_AD5_MARK, + AB_AD6_MARK, AB_AD7_MARK, AB_AD8_MARK, AB_AD9_MARK, + AB_AD10_MARK, AB_AD11_MARK, AB_AD12_MARK, AB_AD13_MARK, + AB_AD14_MARK, AB_AD15_MARK, AB_A17_MARK, AB_A18_MARK, + AB_A19_MARK, AB_A21_MARK, AB_A22_MARK, AB_A23_MARK, + AB_A24_MARK, AB_A25_MARK, AB_A26_MARK, AB_A27_MARK, + AB_A28_MARK, AB_BEN0_MARK, AB_BEN1_MARK, + DTV_BCLK_A_MARK, DTV_PSYNC_A_MARK, DTV_VALID_A_MARK, + DTV_DATA_A_MARK, + SDI2_CKO_MARK, SDI2_CKI_MARK, SDI2_CMD_MARK, + SDI2_DATA0_MARK, SDI2_DATA1_MARK, SDI2_DATA2_MARK, + SDI2_DATA3_MARK, + CF_CSB0_MARK, CF_CSB1_MARK, CF_IORDB_MARK, + CF_IOWRB_MARK, CF_IORDY_MARK, CF_RESET_MARK, + CF_D00_MARK, CF_D01_MARK, CF_D02_MARK, CF_D03_MARK, + CF_D04_MARK, CF_D05_MARK, CF_D06_MARK, CF_D07_MARK, + CF_D08_MARK, CF_D09_MARK, CF_D10_MARK, CF_D11_MARK, + CF_D12_MARK, CF_D13_MARK, CF_D14_MARK, CF_D15_MARK, + CF_A00_MARK, CF_A01_MARK, CF_A02_MARK, + CF_INTRQ_MARK, CF_INPACKB_MARK, CF_CDB1_MARK, CF_CDB2_MARK, + USI5_CLK_A_MARK, USI5_DI_A_MARK, USI5_DO_A_MARK, + USI5_CS0_A_MARK, USI5_CS1_A_MARK, USI5_CS2_A_MARK, + + /* CHG_PINSEL_USI */ + USI0_CS3_MARK, USI0_CS4_MARK, USI0_CS5_MARK, + USI0_CS6_MARK, + USI2_CLK_MARK, USI2_DI_MARK, USI2_DO_MARK, + USI2_CS0_MARK, USI2_CS1_MARK, USI2_CS2_MARK, + USI3_CLK_MARK, USI3_DI_MARK, USI3_DO_MARK, + USI3_CS0_MARK, + USI4_CLK_MARK, USI4_DI_MARK, USI4_DO_MARK, + USI4_CS0_MARK, USI4_CS1_MARK, + PWM0_MARK, PWM1_MARK, + DTV_BCLK_B_MARK, DTV_PSYNC_B_MARK, DTV_VALID_B_MARK, + DTV_DATA_B_MARK, + + /* CHG_PINSEL_HSI */ + USI5_CLK_B_MARK, USI5_DO_B_MARK, USI5_CS0_B_MARK, USI5_CS1_B_MARK, + USI5_CS2_B_MARK, USI5_CS3_B_MARK, USI5_CS4_B_MARK, USI5_DI_B_MARK, + + /* CHG_PINSEL_UART */ + UART1_CTSB_MARK, UART1_RTSB_MARK, + UART2_RX_MARK, UART2_TX_MARK, + + PINMUX_MARK_END, +}; + +/* Pin numbers for pins without a corresponding GPIO port number are computed + * from the row and column numbers with a 1000 offset to avoid collisions with + * GPIO port numbers. */ +#define PIN_NUMBER(row, col) (1000+((row)-1)*23+(col)-1) + +/* Expand to a list of sh_pfc_pin entries (named PORT#). + * NOTE: No config are recorded since the driver do not handle pinconf. */ +#define __PIN_CFG(pn, pfx, sfx) SH_PFC_PIN_CFG(pfx, 0) +#define PINMUX_EMEV_GPIO_ALL() CPU_ALL_PORT(__PIN_CFG, , unused) + +static const struct sh_pfc_pin pinmux_pins[] = { + PINMUX_EMEV_GPIO_ALL(), + + /* Pins not associated with a GPIO port */ + SH_PFC_PIN_NAMED(2, 14, B14), + SH_PFC_PIN_NAMED(2, 15, B15), + SH_PFC_PIN_NAMED(2, 16, B16), + SH_PFC_PIN_NAMED(2, 17, B17), + SH_PFC_PIN_NAMED(3, 14, C14), + SH_PFC_PIN_NAMED(3, 15, C15), + SH_PFC_PIN_NAMED(3, 16, C16), + SH_PFC_PIN_NAMED(3, 17, C17), + SH_PFC_PIN_NAMED(4, 14, D14), + SH_PFC_PIN_NAMED(4, 15, D15), + SH_PFC_PIN_NAMED(4, 16, D16), + SH_PFC_PIN_NAMED(4, 17, D17), +}; + +/* Expand to a list of name_DATA, name_FN marks */ +#define __PORT_DATA(pn, pfx, sfx) PINMUX_DATA(PORT##pfx##_DATA, PORT##pfx##_FN) +#define PINMUX_EMEV_DATA_ALL() CPU_ALL_PORT(__PORT_DATA, , unused) + +static const u16 pinmux_data[] = { + PINMUX_EMEV_DATA_ALL(), /* PINMUX_DATA(PORTN_DATA, PORTN_FN), */ + + /* GPSR0 */ + /* V9 */ + PINMUX_DATA(JT_SEL_MARK, FN_JT_SEL), + /* U9 */ + PINMUX_DATA(ERR_RST_REQB_MARK, FN_ERR_RST_REQB), + /* V8 */ + PINMUX_DATA(REF_CLKO_MARK, FN_REF_CLKO), + /* U8 */ + PINMUX_DATA(EXT_CLKI_MARK, FN_EXT_CLKI), + /* B22*/ + PINMUX_IPSR_NOFN(LCD3_1_0_PORT18, LCD3_PXCLK, SEL_LCD3_1_0_00), + PINMUX_IPSR_NOFN(LCD3_1_0_PORT18, YUV3_CLK_O, SEL_LCD3_1_0_01), + /* C21 */ + PINMUX_DATA(LCD3_PXCLKB_MARK, FN_LCD3_PXCLKB), + /* A21 */ + PINMUX_IPSR_NOFN(LCD3_1_0_PORT20, LCD3_CLK_I, SEL_LCD3_1_0_00), + PINMUX_IPSR_NOFN(LCD3_1_0_PORT20, YUV3_CLK_I, SEL_LCD3_1_0_01), + /* B21 */ + PINMUX_IPSR_NOFN(LCD3_1_0_PORT21, LCD3_HS, SEL_LCD3_1_0_00), + PINMUX_IPSR_NOFN(LCD3_1_0_PORT21, YUV3_HS, SEL_LCD3_1_0_01), + /* C20 */ + PINMUX_IPSR_NOFN(LCD3_1_0_PORT22, LCD3_VS, SEL_LCD3_1_0_00), + PINMUX_IPSR_NOFN(LCD3_1_0_PORT22, YUV3_VS, SEL_LCD3_1_0_01), + /* D19 */ + PINMUX_IPSR_NOFN(LCD3_1_0_PORT23, LCD3_DE, SEL_LCD3_1_0_00), + PINMUX_IPSR_NOFN(LCD3_1_0_PORT23, YUV3_DE, SEL_LCD3_1_0_01), + + /* GPSR1 */ + /* A20 */ + PINMUX_DATA(LCD3_R0_MARK, FN_LCD3_R0), + /* B20 */ + PINMUX_DATA(LCD3_R1_MARK, FN_LCD3_R1), + /* A19 */ + PINMUX_DATA(LCD3_R2_MARK, FN_LCD3_R2), + /* B19 */ + PINMUX_DATA(LCD3_R3_MARK, FN_LCD3_R3), + /* C19 */ + PINMUX_DATA(LCD3_R4_MARK, FN_LCD3_R4), + /* B18 */ + PINMUX_DATA(LCD3_R5_MARK, FN_LCD3_R5), + /* C18 */ + PINMUX_IPSR_NOFN(LCD3_9_8_PORT38, LCD3_R6, SEL_LCD3_9_8_00), + PINMUX_IPSR_NOFN(LCD3_9_8_PORT38, TP33_CLK, SEL_LCD3_9_8_10), + /* D18 */ + PINMUX_IPSR_NOFN(LCD3_9_8_PORT39, LCD3_R7, SEL_LCD3_9_8_00), + PINMUX_IPSR_NOFN(LCD3_9_8_PORT39, TP33_CTRL, SEL_LCD3_9_8_10), + /* A18 */ + PINMUX_IPSR_NOFN(LCD3_11_10_PORT40, LCD3_G0, SEL_LCD3_11_10_00), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT40, YUV3_D0, SEL_LCD3_11_10_01), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT40, TP33_DATA0, SEL_LCD3_11_10_10), + /* A17 */ + PINMUX_IPSR_NOFN(LCD3_11_10_PORT41, LCD3_G1, SEL_LCD3_11_10_00), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT41, YUV3_D1, SEL_LCD3_11_10_01), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT41, TP33_DATA1, SEL_LCD3_11_10_10), + /* B17 */ + PINMUX_DATA(LCD3_G2_MARK, FN_SEL_LCD3_11_10_00), + PINMUX_DATA(YUV3_D2_MARK, FN_SEL_LCD3_11_10_01), + PINMUX_DATA(TP33_DATA2_MARK, FN_SEL_LCD3_11_10_10), + /* C17 */ + PINMUX_DATA(LCD3_G3_MARK, FN_SEL_LCD3_11_10_00), + PINMUX_DATA(YUV3_D3_MARK, FN_SEL_LCD3_11_10_01), + PINMUX_DATA(TP33_DATA3_MARK, FN_SEL_LCD3_11_10_10), + /* D17 */ + PINMUX_DATA(LCD3_G4_MARK, FN_SEL_LCD3_11_10_00), + PINMUX_DATA(YUV3_D4_MARK, FN_SEL_LCD3_11_10_01), + PINMUX_DATA(TP33_DATA4_MARK, FN_SEL_LCD3_11_10_10), + /* B16 */ + PINMUX_DATA(LCD3_G5_MARK, FN_SEL_LCD3_11_10_00), + PINMUX_DATA(YUV3_D5_MARK, FN_SEL_LCD3_11_10_01), + PINMUX_DATA(TP33_DATA5_MARK, FN_SEL_LCD3_11_10_10), + /* C16 */ + PINMUX_DATA(LCD3_G6_MARK, FN_SEL_LCD3_11_10_00), + PINMUX_DATA(YUV3_D6_MARK, FN_SEL_LCD3_11_10_01), + PINMUX_DATA(TP33_DATA6_MARK, FN_SEL_LCD3_11_10_10), + /* D16 */ + PINMUX_DATA(LCD3_G7_MARK, FN_SEL_LCD3_11_10_00), + PINMUX_DATA(YUV3_D7_MARK, FN_SEL_LCD3_11_10_01), + PINMUX_DATA(TP33_DATA7_MARK, FN_SEL_LCD3_11_10_10), + /* A16 */ + PINMUX_IPSR_NOFN(LCD3_11_10_PORT42, LCD3_B0, SEL_LCD3_11_10_00), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT42, YUV3_D8, SEL_LCD3_11_10_01), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT42, TP33_DATA8, SEL_LCD3_11_10_10), + /* A15 */ + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, LCD3_B1, SEL_LCD3_11_10_00), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D9, SEL_LCD3_11_10_01), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA9, SEL_LCD3_11_10_10), + /* B15 */ + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, LCD3_B2, SEL_LCD3_11_10_00), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D10, SEL_LCD3_11_10_01), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA10, SEL_LCD3_11_10_10), + /* C15 */ + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, LCD3_B3, SEL_LCD3_11_10_00), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D11, SEL_LCD3_11_10_01), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA11, SEL_LCD3_11_10_10), + /* D15 */ + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, LCD3_B4, SEL_LCD3_11_10_00), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D12, SEL_LCD3_11_10_01), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA12, SEL_LCD3_11_10_10), + /* B14 */ + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, LCD3_B5, SEL_LCD3_11_10_00), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D13, SEL_LCD3_11_10_01), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA13, SEL_LCD3_11_10_10), + /* C14 */ + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, LCD3_B6, SEL_LCD3_11_10_00), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D14, SEL_LCD3_11_10_01), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA14, SEL_LCD3_11_10_10), + /* D14 */ + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, LCD3_B7, SEL_LCD3_11_10_00), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D15, SEL_LCD3_11_10_01), + PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA15, SEL_LCD3_11_10_10), + /* AA9 */ + PINMUX_DATA(IIC0_SCL_MARK, FN_IIC0_SCL), + /* AA8 */ + PINMUX_DATA(IIC0_SDA_MARK, FN_IIC0_SDA), + /* Y9 */ + PINMUX_IPSR_NOFN(IIC_1_0_PORT46, IIC1_SCL, SEL_IIC_1_0_00), + PINMUX_IPSR_NOFN(IIC_1_0_PORT46, UART3_RX, SEL_IIC_1_0_01), + /* Y8 */ + PINMUX_IPSR_NOFN(IIC_1_0_PORT47, IIC1_SDA, SEL_IIC_1_0_00), + PINMUX_IPSR_NOFN(IIC_1_0_PORT47, UART3_TX, SEL_IIC_1_0_01), + /* AC19 */ + PINMUX_DATA(SD_CKI_MARK, FN_SD_CKI), + /* AB18 */ + PINMUX_DATA(SDI0_CKO_MARK, FN_SDI0_CKO), + /* AC18 */ + PINMUX_DATA(SDI0_CKI_MARK, FN_SDI0_CKI), + /* Y12 */ + PINMUX_DATA(SDI0_CMD_MARK, FN_SDI0_CMD), + /* AA13 */ + PINMUX_DATA(SDI0_DATA0_MARK, FN_SDI0_DATA0), + /* Y13 */ + PINMUX_DATA(SDI0_DATA1_MARK, FN_SDI0_DATA1), + /* AA14 */ + PINMUX_DATA(SDI0_DATA2_MARK, FN_SDI0_DATA2), + /* Y14 */ + PINMUX_DATA(SDI0_DATA3_MARK, FN_SDI0_DATA3), + /* AA15 */ + PINMUX_DATA(SDI0_DATA4_MARK, FN_SDI0_DATA4), + /* Y15 */ + PINMUX_DATA(SDI0_DATA5_MARK, FN_SDI0_DATA5), + /* AA16 */ + PINMUX_DATA(SDI0_DATA6_MARK, FN_SDI0_DATA6), + /* Y16 */ + PINMUX_DATA(SDI0_DATA7_MARK, FN_SDI0_DATA7), + /* AB22 */ + PINMUX_DATA(SDI1_CKO_MARK, FN_SDI1_CKO), + /* AA23 */ + PINMUX_DATA(SDI1_CKI_MARK, FN_SDI1_CKI), + /* AC21 */ + PINMUX_DATA(SDI1_CMD_MARK, FN_SDI1_CMD), + + /* GPSR2 */ + /* AB21 */ + PINMUX_DATA(SDI1_DATA0_MARK, FN_SDI1_DATA0), + /* AB20 */ + PINMUX_DATA(SDI1_DATA1_MARK, FN_SDI1_DATA1), + /* AB19 */ + PINMUX_DATA(SDI1_DATA2_MARK, FN_SDI1_DATA2), + /* AA19 */ + PINMUX_DATA(SDI1_DATA3_MARK, FN_SDI1_DATA3), + /* J23 */ + PINMUX_DATA(AB_CLK_MARK, FN_AB_CLK), + /* D21 */ + PINMUX_DATA(AB_CSB0_MARK, FN_AB_CSB0), + /* E21 */ + PINMUX_DATA(AB_CSB1_MARK, FN_AB_CSB1), + /* F20 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT71, AB_CSB2, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT71, CF_CSB0, SEL_AB_1_0_10), + /* G20 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT72, AB_CSB3, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT72, CF_CSB1, SEL_AB_1_0_10), + /* J20 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT73, AB_RDB, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT73, CF_IORDB, SEL_AB_1_0_10), + /* H20 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT74, AB_WRB, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT74, CF_IOWRB, SEL_AB_1_0_10), + /* L20 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT75, AB_WAIT, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT75, CF_IORDY, SEL_AB_1_0_10), + /* K20 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT76, AB_ADV, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT76, CF_RESET, SEL_AB_1_0_10), + /* C23 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT77, AB_AD0, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT77, CF_D00, SEL_AB_1_0_10), + /* C22 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT78, AB_AD1, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT78, CF_D01, SEL_AB_1_0_10), + /* D23 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT79, AB_AD2, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT79, CF_D02, SEL_AB_1_0_10), + /* D22 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT80, AB_AD3, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT80, CF_D03, SEL_AB_1_0_10), + /* E23 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT81, AB_AD4, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT81, CF_D04, SEL_AB_1_0_10), + /* E22 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT82, AB_AD5, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT82, CF_D05, SEL_AB_1_0_10), + /* F23 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT83, AB_AD6, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT83, CF_D06, SEL_AB_1_0_10), + /* F22 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT84, AB_AD7, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT84, CF_D07, SEL_AB_1_0_10), + /* F21 */ + PINMUX_IPSR_NOFN(AB_3_2_PORT85, AB_AD8, SEL_AB_3_2_00), + PINMUX_IPSR_NOFN(AB_3_2_PORT85, DTV_BCLK_A, SEL_AB_3_2_01), + PINMUX_IPSR_NOFN(AB_3_2_PORT85, CF_D08, SEL_AB_3_2_10), + PINMUX_IPSR_NOFN(AB_3_2_PORT85, USI5_CLK_A, SEL_AB_3_2_11), + /* G23 */ + PINMUX_IPSR_NOFN(AB_3_2_PORT86, AB_AD9, SEL_AB_3_2_00), + PINMUX_IPSR_NOFN(AB_3_2_PORT86, DTV_PSYNC_A, SEL_AB_3_2_01), + PINMUX_IPSR_NOFN(AB_3_2_PORT86, CF_D09, SEL_AB_3_2_10), + PINMUX_IPSR_NOFN(AB_3_2_PORT86, USI5_DI_A, SEL_AB_3_2_11), + /* G22 */ + PINMUX_IPSR_NOFN(AB_3_2_PORT87, AB_AD10, SEL_AB_3_2_00), + PINMUX_IPSR_NOFN(AB_3_2_PORT87, DTV_VALID_A, SEL_AB_3_2_01), + PINMUX_IPSR_NOFN(AB_3_2_PORT87, CF_D10, SEL_AB_3_2_10), + PINMUX_IPSR_NOFN(AB_3_2_PORT87, USI5_DO_A, SEL_AB_3_2_11), + /* G21 */ + PINMUX_IPSR_NOFN(AB_3_2_PORT88, AB_AD11, SEL_AB_3_2_00), + PINMUX_IPSR_NOFN(AB_3_2_PORT88, DTV_DATA_A, SEL_AB_3_2_01), + PINMUX_IPSR_NOFN(AB_3_2_PORT88, CF_D11, SEL_AB_3_2_10), + PINMUX_IPSR_NOFN(AB_3_2_PORT88, USI5_CS0_A, SEL_AB_3_2_11), + /* H23 */ + PINMUX_IPSR_NOFN(AB_5_4_PORT89, AB_AD12, SEL_AB_5_4_00), + PINMUX_IPSR_NOFN(AB_5_4_PORT89, SDI2_DATA0, SEL_AB_5_4_01), + PINMUX_IPSR_NOFN(AB_5_4_PORT89, CF_D12, SEL_AB_5_4_10), + PINMUX_IPSR_NOFN(AB_5_4_PORT89, USI5_CS1_A, SEL_AB_5_4_11), + /* H22 */ + PINMUX_IPSR_NOFN(AB_5_4_PORT90, AB_AD13, SEL_AB_5_4_00), + PINMUX_IPSR_NOFN(AB_5_4_PORT90, SDI2_DATA1, SEL_AB_5_4_01), + PINMUX_IPSR_NOFN(AB_5_4_PORT90, CF_D13, SEL_AB_5_4_10), + PINMUX_IPSR_NOFN(AB_5_4_PORT90, USI5_CS2_A, SEL_AB_5_4_11), + /* H21 */ + PINMUX_IPSR_NOFN(AB_7_6_PORT91, AB_AD14, SEL_AB_7_6_00), + PINMUX_IPSR_NOFN(AB_7_6_PORT91, SDI2_DATA2, SEL_AB_7_6_01), + PINMUX_IPSR_NOFN(AB_7_6_PORT91, CF_D14, SEL_AB_7_6_10), + /* J22 */ + PINMUX_IPSR_NOFN(AB_7_6_PORT92, AB_AD15, SEL_AB_7_6_00), + PINMUX_IPSR_NOFN(AB_7_6_PORT92, SDI2_DATA3, SEL_AB_7_6_01), + PINMUX_IPSR_NOFN(AB_7_6_PORT92, CF_D15, SEL_AB_7_6_10), + /* J21 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT93, AB_A17, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT93, CF_A00, SEL_AB_1_0_10), + /* K21 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT94, AB_A18, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT94, CF_A01, SEL_AB_1_0_10), + /* L21 */ + PINMUX_IPSR_NOFN(AB_1_0_PORT95, AB_A19, SEL_AB_1_0_00), + PINMUX_IPSR_NOFN(AB_1_0_PORT95, CF_A02, SEL_AB_1_0_10), + + /* GPSR3 */ + /* M21 */ + PINMUX_DATA(AB_A20_MARK, FN_AB_A20), + /* N21 */ + PINMUX_IPSR_NOFN(AB_9_8_PORT97, AB_A21, SEL_AB_9_8_00), + PINMUX_IPSR_NOFN(AB_9_8_PORT97, SDI2_CKO, SEL_AB_9_8_01), + PINMUX_IPSR_NOFN(AB_9_8_PORT97, CF_INTRQ, SEL_AB_9_8_10), + /* M20 */ + PINMUX_IPSR_NOFN(AB_9_8_PORT98, AB_A22, SEL_AB_9_8_00), + PINMUX_IPSR_NOFN(AB_9_8_PORT98, SDI2_CKI, SEL_AB_9_8_01), + /* N20 */ + PINMUX_IPSR_NOFN(AB_9_8_PORT99, AB_A23, SEL_AB_9_8_00), + PINMUX_IPSR_NOFN(AB_9_8_PORT99, SDI2_CMD, SEL_AB_9_8_01), + /* L18 */ + PINMUX_IPSR_NOFN(AB_11_10_PORT100, AB_A24, SEL_AB_11_10_00), + PINMUX_IPSR_NOFN(AB_11_10_PORT100, CF_INPACKB, SEL_AB_11_10_10), + /* M18 */ + PINMUX_IPSR_NOFN(AB_11_10_PORT101, AB_A25, SEL_AB_11_10_00), + PINMUX_IPSR_NOFN(AB_11_10_PORT101, CF_CDB1, SEL_AB_11_10_10), + /* N18 */ + PINMUX_IPSR_NOFN(AB_11_10_PORT102, AB_A26, SEL_AB_11_10_00), + PINMUX_IPSR_NOFN(AB_11_10_PORT102, CF_CDB2, SEL_AB_11_10_10), + /* L17 */ + PINMUX_IPSR_NOFN(AB_13_12_PORT103, AB_A27, SEL_AB_13_12_00), + PINMUX_IPSR_NOFN(AB_13_12_PORT103, AB_BEN0, SEL_AB_13_12_10), + /* M17 */ + PINMUX_IPSR_NOFN(AB_13_12_PORT104, AB_A28, SEL_AB_13_12_00), + PINMUX_IPSR_NOFN(AB_13_12_PORT104, AB_BEN1, SEL_AB_13_12_10), + /* B8 */ + PINMUX_DATA(USI0_CS1_MARK, FN_USI0_CS1), + /* B9 */ + PINMUX_DATA(USI0_CS2_MARK, FN_USI0_CS2), + /* C10 */ + PINMUX_DATA(USI1_DI_MARK, FN_USI1_DI), + /* D10 */ + PINMUX_DATA(USI1_DO_MARK, FN_USI1_DO), + /* AB5 */ + PINMUX_IPSR_NOFN(USI_1_0_PORT109, USI2_CLK, SEL_USI_1_0_00), + PINMUX_IPSR_NOFN(USI_1_0_PORT109, DTV_BCLK_B, SEL_USI_1_0_01), + /* AA6 */ + PINMUX_IPSR_NOFN(USI_1_0_PORT110, USI2_DI, SEL_USI_1_0_00), + PINMUX_IPSR_NOFN(USI_1_0_PORT110, DTV_PSYNC_B, SEL_USI_1_0_01), + /* AA5 */ + PINMUX_IPSR_NOFN(USI_1_0_PORT111, USI2_DO, SEL_USI_1_0_00), + PINMUX_IPSR_NOFN(USI_1_0_PORT111, DTV_VALID_B, SEL_USI_1_0_01), + /* Y7 */ + PINMUX_IPSR_NOFN(USI_1_0_PORT112, USI2_CS0, SEL_USI_1_0_00), + PINMUX_IPSR_NOFN(USI_1_0_PORT112, DTV_DATA_B, SEL_USI_1_0_01), + /* AA7 */ + PINMUX_IPSR_NOFN(USI_3_2_PORT113, USI2_CS1, SEL_USI_3_2_00), + PINMUX_IPSR_NOFN(USI_3_2_PORT113, USI4_CS0, SEL_USI_3_2_01), + /* Y6 */ + PINMUX_IPSR_NOFN(USI_3_2_PORT114, USI2_CS2, SEL_USI_3_2_00), + PINMUX_IPSR_NOFN(USI_3_2_PORT114, USI4_CS1, SEL_USI_3_2_01), + /* AC5 */ + PINMUX_IPSR_NOFN(USI_5_4_PORT115, USI3_CLK, SEL_USI_5_4_00), + PINMUX_IPSR_NOFN(USI_5_4_PORT115, USI0_CS3, SEL_USI_5_4_01), + /* AC4 */ + PINMUX_IPSR_NOFN(USI_5_4_PORT116, USI3_DI, SEL_USI_5_4_00), + PINMUX_IPSR_NOFN(USI_5_4_PORT116, USI0_CS4, SEL_USI_5_4_01), + /* AC3 */ + PINMUX_IPSR_NOFN(USI_5_4_PORT117, USI3_DO, SEL_USI_5_4_00), + PINMUX_IPSR_NOFN(USI_5_4_PORT117, USI0_CS5, SEL_USI_5_4_01), + /* AB4 */ + PINMUX_IPSR_NOFN(USI_5_4_PORT118, USI3_CS0, SEL_USI_5_4_00), + PINMUX_IPSR_NOFN(USI_5_4_PORT118, USI0_CS6, SEL_USI_5_4_01), + /* AB3 */ + PINMUX_IPSR_NOFN(USI_7_6_PORT119, USI4_CLK, SEL_USI_7_6_01), + /* AA4 */ + PINMUX_IPSR_NOFN(USI_9_8_PORT120, PWM0, SEL_USI_9_8_00), + PINMUX_IPSR_NOFN(USI_9_8_PORT120, USI4_DI, SEL_USI_9_8_01), + /* Y5 */ + PINMUX_IPSR_NOFN(USI_9_8_PORT121, PWM1, SEL_USI_9_8_00), + PINMUX_IPSR_NOFN(USI_9_8_PORT121, USI4_DO, SEL_USI_9_8_01), + /* V20 */ + PINMUX_DATA(NTSC_CLK_MARK, FN_NTSC_CLK), + /* P20 */ + PINMUX_DATA(NTSC_DATA0_MARK, FN_NTSC_DATA0), + /* P18 */ + PINMUX_DATA(NTSC_DATA1_MARK, FN_NTSC_DATA1), + /* R20 */ + PINMUX_DATA(NTSC_DATA2_MARK, FN_NTSC_DATA2), + /* R18 */ + PINMUX_DATA(NTSC_DATA3_MARK, FN_NTSC_DATA3), + /* T20 */ + PINMUX_DATA(NTSC_DATA4_MARK, FN_NTSC_DATA4), + + /* GPRS3 */ + /* T18 */ + PINMUX_DATA(NTSC_DATA5_MARK, FN_NTSC_DATA5), + /* U20 */ + PINMUX_DATA(NTSC_DATA6_MARK, FN_NTSC_DATA6), + /* U18 */ + PINMUX_DATA(NTSC_DATA7_MARK, FN_NTSC_DATA7), + /* W23 */ + PINMUX_DATA(CAM_CLKO_MARK, FN_CAM_CLKO), + /* Y23 */ + PINMUX_DATA(CAM_CLKI_MARK, FN_CAM_CLKI), + /* W22 */ + PINMUX_DATA(CAM_VS_MARK, FN_CAM_VS), + /* V21 */ + PINMUX_DATA(CAM_HS_MARK, FN_CAM_HS), + /* T21 */ + PINMUX_DATA(CAM_YUV0_MARK, FN_CAM_YUV0), + /* T22 */ + PINMUX_DATA(CAM_YUV1_MARK, FN_CAM_YUV1), + /* T23 */ + PINMUX_DATA(CAM_YUV2_MARK, FN_CAM_YUV2), + /* U21 */ + PINMUX_DATA(CAM_YUV3_MARK, FN_CAM_YUV3), + /* U22 */ + PINMUX_DATA(CAM_YUV4_MARK, FN_CAM_YUV4), + /* U23 */ + PINMUX_DATA(CAM_YUV5_MARK, FN_CAM_YUV5), + /* V22 */ + PINMUX_DATA(CAM_YUV6_MARK, FN_CAM_YUV6), + /* V23 */ + PINMUX_DATA(CAM_YUV7_MARK, FN_CAM_YUV7), + /* K22 */ + PINMUX_IPSR_NOFN(HSI_1_0_PORT143, USI5_CLK_B, SEL_HSI_1_0_01), + /* K23 */ + PINMUX_IPSR_NOFN(HSI_1_0_PORT144, USI5_DO_B, SEL_HSI_1_0_01), + /* L23 */ + PINMUX_IPSR_NOFN(HSI_1_0_PORT145, USI5_CS0_B, SEL_HSI_1_0_01), + /* L22 */ + PINMUX_IPSR_NOFN(HSI_1_0_PORT146, USI5_CS1_B, SEL_HSI_1_0_01), + /* N22 */ + PINMUX_IPSR_NOFN(HSI_1_0_PORT147, USI5_CS2_B, SEL_HSI_1_0_01), + /* N23 */ + PINMUX_IPSR_NOFN(HSI_1_0_PORT148, USI5_CS3_B, SEL_HSI_1_0_01), + /* M23 */ + PINMUX_IPSR_NOFN(HSI_1_0_PORT149, USI5_CS4_B, SEL_HSI_1_0_01), + /* M22 */ + PINMUX_IPSR_NOFN(HSI_1_0_PORT150, USI5_DI_B, SEL_HSI_1_0_01), + /* D13 */ + PINMUX_DATA(JT_TDO_MARK, FN_JT_TDO), + /* F13 */ + PINMUX_DATA(JT_TDOEN_MARK, FN_JT_TDOEN), + /* AA12 */ + PINMUX_DATA(USB_VBUS_MARK, FN_USB_VBUS), + /* A12 */ + PINMUX_DATA(LOWPWR_MARK, FN_LOWPWR), + /* Y11 */ + PINMUX_DATA(UART1_RX_MARK, FN_UART1_RX), + /* Y10 */ + PINMUX_DATA(UART1_TX_MARK, FN_UART1_TX), + /* AA10 */ + PINMUX_IPSR_NOFN(UART_1_0_PORT157, UART1_CTSB, SEL_UART_1_0_00), + PINMUX_IPSR_NOFN(UART_1_0_PORT157, UART2_RX, SEL_UART_1_0_01), + /* AB10 */ + PINMUX_IPSR_NOFN(UART_1_0_PORT158, UART1_RTSB, SEL_UART_1_0_00), + PINMUX_IPSR_NOFN(UART_1_0_PORT158, UART2_TX, SEL_UART_1_0_01), +}; + + +#define EMEV_MUX_PIN(name, pin, mark) \ + static const unsigned int name##_pins[] = { pin }; \ + static const unsigned int name##_mux[] = { mark##_MARK } + +/* = [ System ] =========== */ +EMEV_MUX_PIN(err_rst_reqb, 3, ERR_RST_REQB); +EMEV_MUX_PIN(ref_clko, 4, REF_CLKO); +EMEV_MUX_PIN(ext_clki, 5, EXT_CLKI); +EMEV_MUX_PIN(lowpwr, 154, LOWPWR); + +/* = [ External Memory] === */ +static const unsigned int ab_main_pins[] = { + /* AB_RDB, AB_WRB */ + 73, 74, + /* AB_AD[0:15] */ + 77, 78, 79, 80, + 81, 82, 83, 84, + 85, 86, 87, 88, + 89, 90, 91, 92, +}; +static const unsigned int ab_main_mux[] = { + AB_RDB_MARK, AB_WRB_MARK, + AB_AD0_MARK, AB_AD1_MARK, AB_AD2_MARK, AB_AD3_MARK, + AB_AD4_MARK, AB_AD5_MARK, AB_AD6_MARK, AB_AD7_MARK, + AB_AD8_MARK, AB_AD9_MARK, AB_AD10_MARK, AB_AD11_MARK, + AB_AD12_MARK, AB_AD13_MARK, AB_AD14_MARK, AB_AD15_MARK, +}; + +EMEV_MUX_PIN(ab_clk, 68, AB_CLK); +EMEV_MUX_PIN(ab_csb0, 69, AB_CSB0); +EMEV_MUX_PIN(ab_csb1, 70, AB_CSB1); +EMEV_MUX_PIN(ab_csb2, 71, AB_CSB2); +EMEV_MUX_PIN(ab_csb3, 72, AB_CSB3); +EMEV_MUX_PIN(ab_wait, 75, AB_WAIT); +EMEV_MUX_PIN(ab_adv, 76, AB_ADV); +EMEV_MUX_PIN(ab_a17, 93, AB_A17); +EMEV_MUX_PIN(ab_a18, 94, AB_A18); +EMEV_MUX_PIN(ab_a19, 95, AB_A19); +EMEV_MUX_PIN(ab_a20, 96, AB_A20); +EMEV_MUX_PIN(ab_a21, 97, AB_A21); +EMEV_MUX_PIN(ab_a22, 98, AB_A22); +EMEV_MUX_PIN(ab_a23, 99, AB_A23); +EMEV_MUX_PIN(ab_a24, 100, AB_A24); +EMEV_MUX_PIN(ab_a25, 101, AB_A25); +EMEV_MUX_PIN(ab_a26, 102, AB_A26); +EMEV_MUX_PIN(ab_a27, 103, AB_A27); +EMEV_MUX_PIN(ab_a28, 104, AB_A28); +EMEV_MUX_PIN(ab_ben0, 103, AB_BEN0); +EMEV_MUX_PIN(ab_ben1, 104, AB_BEN1); + +/* = [ CAM ] ============== */ +EMEV_MUX_PIN(cam_clko, 131, CAM_CLKO); +static const unsigned int cam_pins[] = { + /* CLKI, VS, HS */ + 132, 133, 134, + /* CAM_YUV[0:7] */ + 135, 136, 137, 138, + 139, 140, 141, 142, +}; +static const unsigned int cam_mux[] = { + CAM_CLKI_MARK, CAM_VS_MARK, CAM_HS_MARK, + CAM_YUV0_MARK, CAM_YUV1_MARK, CAM_YUV2_MARK, CAM_YUV3_MARK, + CAM_YUV4_MARK, CAM_YUV5_MARK, CAM_YUV6_MARK, CAM_YUV7_MARK, +}; + +/* = [ CF ] -============== */ +static const unsigned int cf_ctrl_pins[] = { + /* CSB0, CSB1, IORDB, IOWRB, IORDY, RESET, + * A00, A01, A02, INTRQ, INPACKB, CDB1, CDB2 */ + 71, 72, 73, 74, + 75, 76, 93, 94, + 95, 97, 100, 101, + 102, +}; +static const unsigned int cf_ctrl_mux[] = { + CF_CSB0_MARK, CF_CSB1_MARK, CF_IORDB_MARK, CF_IOWRB_MARK, + CF_IORDY_MARK, CF_RESET_MARK, CF_A00_MARK, CF_A01_MARK, + CF_A02_MARK, CF_INTRQ_MARK, CF_INPACKB_MARK, CF_CDB1_MARK, + CF_CDB2_MARK, +}; + +static const unsigned int cf_data8_pins[] = { + /* CF_D[0:8] */ + 77, 78, 79, 80, + 81, 82, 83, 84, +}; +static const unsigned int cf_data8_mux[] = { + CF_D00_MARK, CF_D01_MARK, CF_D02_MARK, CF_D03_MARK, + CF_D04_MARK, CF_D05_MARK, CF_D06_MARK, CF_D07_MARK, +}; +static const unsigned int cf_data16_pins[] = { + /* CF_D[0:15] */ + 77, 78, 79, 80, + 81, 82, 83, 84, + 85, 86, 87, 88, + 89, 90, 91, 92, +}; +static const unsigned int cf_data16_mux[] = { + CF_D00_MARK, CF_D01_MARK, CF_D02_MARK, CF_D03_MARK, + CF_D04_MARK, CF_D05_MARK, CF_D06_MARK, CF_D07_MARK, + CF_D08_MARK, CF_D09_MARK, CF_D10_MARK, CF_D11_MARK, + CF_D12_MARK, CF_D13_MARK, CF_D14_MARK, CF_D15_MARK, +}; + +/* = [ DTV ] ============== */ +static const unsigned int dtv_a_pins[] = { + /* BCLK, PSYNC, VALID, DATA */ + 85, 86, 87, 88, +}; +static const unsigned int dtv_a_mux[] = { + DTV_BCLK_A_MARK, DTV_PSYNC_A_MARK, DTV_VALID_A_MARK, DTV_DATA_A_MARK, +}; + +static const unsigned int dtv_b_pins[] = { + /* BCLK, PSYNC, VALID, DATA */ + 109, 110, 111, 112, +}; +static const unsigned int dtv_b_mux[] = { + DTV_BCLK_B_MARK, DTV_PSYNC_B_MARK, DTV_VALID_B_MARK, DTV_DATA_B_MARK, +}; + +/* = [ IIC0 ] ============= */ +static const unsigned int iic0_pins[] = { + /* SCL, SDA */ + 44, 45, +}; +static const unsigned int iic0_mux[] = { + IIC0_SCL_MARK, IIC0_SDA_MARK, +}; + +/* = [ IIC1 ] ============= */ +static const unsigned int iic1_pins[] = { + /* SCL, SDA */ + 46, 47, +}; +static const unsigned int iic1_mux[] = { + IIC1_SCL_MARK, IIC1_SDA_MARK, +}; + +/* = [ JTAG ] ============= */ +static const unsigned int jtag_pins[] = { + /* SEL, TDO, TDOEN */ + 2, 151, 152, +}; +static const unsigned int jtag_mux[] = { + JT_SEL_MARK, JT_TDO_MARK, JT_TDOEN_MARK, +}; + +/* = [ LCD/YUV ] ========== */ +EMEV_MUX_PIN(lcd3_pxclk, 18, LCD3_PXCLK); +EMEV_MUX_PIN(lcd3_pxclkb, 19, LCD3_PXCLKB); +EMEV_MUX_PIN(lcd3_clk_i, 20, LCD3_CLK_I); + +static const unsigned int lcd3_sync_pins[] = { + /* HS, VS, DE */ + 21, 22, 23, +}; +static const unsigned int lcd3_sync_mux[] = { + LCD3_HS_MARK, LCD3_VS_MARK, LCD3_DE_MARK, +}; + +static const unsigned int lcd3_rgb888_pins[] = { + /* R[0:7], G[0:7], B[0:7] */ + 32, 33, 34, 35, + 36, 37, 38, 39, + 40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17), + PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16), + PIN_NUMBER(4, 16), + 42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15), + PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14), + PIN_NUMBER(4, 14) +}; +static const unsigned int lcd3_rgb888_mux[] = { + LCD3_R0_MARK, LCD3_R1_MARK, LCD3_R2_MARK, LCD3_R3_MARK, + LCD3_R4_MARK, LCD3_R5_MARK, LCD3_R6_MARK, LCD3_R7_MARK, + LCD3_G0_MARK, LCD3_G1_MARK, LCD3_G2_MARK, LCD3_G3_MARK, + LCD3_G4_MARK, LCD3_G5_MARK, LCD3_G6_MARK, LCD3_G7_MARK, + LCD3_B0_MARK, LCD3_B1_MARK, LCD3_B2_MARK, LCD3_B3_MARK, + LCD3_B4_MARK, LCD3_B5_MARK, LCD3_B6_MARK, LCD3_B7_MARK, +}; + +EMEV_MUX_PIN(yuv3_clk_i, 20, YUV3_CLK_I); +static const unsigned int yuv3_pins[] = { + /* CLK_O, HS, VS, DE */ + 18, 21, 22, 23, + /* YUV3_D[0:15] */ + 40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17), + PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16), + PIN_NUMBER(4, 16), + 42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15), + PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14), + PIN_NUMBER(4, 14), +}; +static const unsigned int yuv3_mux[] = { + YUV3_CLK_O_MARK, YUV3_HS_MARK, YUV3_VS_MARK, YUV3_DE_MARK, + YUV3_D0_MARK, YUV3_D1_MARK, YUV3_D2_MARK, YUV3_D3_MARK, + YUV3_D4_MARK, YUV3_D5_MARK, YUV3_D6_MARK, YUV3_D7_MARK, + YUV3_D8_MARK, YUV3_D9_MARK, YUV3_D10_MARK, YUV3_D11_MARK, + YUV3_D12_MARK, YUV3_D13_MARK, YUV3_D14_MARK, YUV3_D15_MARK, +}; + +/* = [ NTSC ] ============= */ +EMEV_MUX_PIN(ntsc_clk, 122, NTSC_CLK); +static const unsigned int ntsc_data_pins[] = { + /* NTSC_DATA[0:7] */ + 123, 124, 125, 126, + 127, 128, 129, 130, +}; +static const unsigned int ntsc_data_mux[] = { + NTSC_DATA0_MARK, NTSC_DATA1_MARK, NTSC_DATA2_MARK, NTSC_DATA3_MARK, + NTSC_DATA4_MARK, NTSC_DATA5_MARK, NTSC_DATA6_MARK, NTSC_DATA7_MARK, +}; + +/* = [ PWM0 ] ============= */ +EMEV_MUX_PIN(pwm0, 120, PWM0); + +/* = [ PWM1 ] ============= */ +EMEV_MUX_PIN(pwm1, 121, PWM1); + +/* = [ SD ] =============== */ +EMEV_MUX_PIN(sd_cki, 48, SD_CKI); + +/* = [ SDIO0 ] ============ */ +static const unsigned int sdi0_ctrl_pins[] = { + /* CKO, CKI, CMD */ + 50, 51, 52, +}; +static const unsigned int sdi0_ctrl_mux[] = { + SDI0_CKO_MARK, SDI0_CKI_MARK, SDI0_CMD_MARK, +}; + +static const unsigned int sdi0_data1_pins[] = { + /* SDI0_DATA[0] */ + 53, +}; +static const unsigned int sdi0_data1_mux[] = { + SDI0_DATA0_MARK, +}; +static const unsigned int sdi0_data4_pins[] = { + /* SDI0_DATA[0:3] */ + 53, 54, 55, 56, +}; +static const unsigned int sdi0_data4_mux[] = { + SDI0_DATA0_MARK, SDI0_DATA1_MARK, SDI0_DATA2_MARK, SDI0_DATA3_MARK, +}; +static const unsigned int sdi0_data8_pins[] = { + /* SDI0_DATA[0:7] */ + 53, 54, 55, 56, + 57, 58, 59, 60 +}; +static const unsigned int sdi0_data8_mux[] = { + SDI0_DATA0_MARK, SDI0_DATA1_MARK, SDI0_DATA2_MARK, SDI0_DATA3_MARK, + SDI0_DATA4_MARK, SDI0_DATA5_MARK, SDI0_DATA6_MARK, SDI0_DATA7_MARK, +}; + +/* = [ SDIO1 ] ============ */ +static const unsigned int sdi1_ctrl_pins[] = { + /* CKO, CKI, CMD */ + 61, 62, 63, +}; +static const unsigned int sdi1_ctrl_mux[] = { + SDI1_CKO_MARK, SDI1_CKI_MARK, SDI1_CMD_MARK, +}; + +static const unsigned int sdi1_data1_pins[] = { + /* SDI1_DATA[0] */ + 64, +}; +static const unsigned int sdi1_data1_mux[] = { + SDI1_DATA0_MARK, +}; +static const unsigned int sdi1_data4_pins[] = { + /* SDI1_DATA[0:3] */ + 64, 65, 66, 67, +}; +static const unsigned int sdi1_data4_mux[] = { + SDI1_DATA0_MARK, SDI1_DATA1_MARK, SDI1_DATA2_MARK, SDI1_DATA3_MARK, +}; + +/* = [ SDIO2 ] ============ */ +static const unsigned int sdi2_ctrl_pins[] = { + /* CKO, CKI, CMD */ + 97, 98, 99, +}; +static const unsigned int sdi2_ctrl_mux[] = { + SDI2_CKO_MARK, SDI2_CKI_MARK, SDI2_CMD_MARK, +}; + +static const unsigned int sdi2_data1_pins[] = { + /* SDI2_DATA[0] */ + 89, +}; +static const unsigned int sdi2_data1_mux[] = { + SDI2_DATA0_MARK, +}; +static const unsigned int sdi2_data4_pins[] = { + /* SDI2_DATA[0:3] */ + 89, 90, 91, 92, +}; +static const unsigned int sdi2_data4_mux[] = { + SDI2_DATA0_MARK, SDI2_DATA1_MARK, SDI2_DATA2_MARK, SDI2_DATA3_MARK, +}; + +/* = [ TP33 ] ============= */ +static const unsigned int tp33_pins[] = { + /* CLK, CTRL */ + 38, 39, + /* TP33_DATA[0:15] */ + 40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17), + PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16), + PIN_NUMBER(4, 16), + 42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15), + PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14), + PIN_NUMBER(4, 14), +}; +static const unsigned int tp33_mux[] = { + TP33_CLK_MARK, TP33_CTRL_MARK, + TP33_DATA0_MARK, TP33_DATA1_MARK, TP33_DATA2_MARK, TP33_DATA3_MARK, + TP33_DATA4_MARK, TP33_DATA5_MARK, TP33_DATA6_MARK, TP33_DATA7_MARK, + TP33_DATA8_MARK, TP33_DATA9_MARK, TP33_DATA10_MARK, TP33_DATA11_MARK, + TP33_DATA12_MARK, TP33_DATA13_MARK, TP33_DATA14_MARK, TP33_DATA15_MARK, +}; + +/* = [ UART1 ] ============ */ +static const unsigned int uart1_data_pins[] = { + /* RX, TX */ + 155, 156, +}; +static const unsigned int uart1_data_mux[] = { + UART1_RX_MARK, UART1_TX_MARK, +}; + +static const unsigned int uart1_ctrl_pins[] = { + /* CTSB, RTSB */ + 157, 158, +}; +static const unsigned int uart1_ctrl_mux[] = { + UART1_CTSB_MARK, UART1_RTSB_MARK, +}; + +/* = [ UART2 ] ============ */ +static const unsigned int uart2_data_pins[] = { + /* RX, TX */ + 157, 158, +}; +static const unsigned int uart2_data_mux[] = { + UART2_RX_MARK, UART2_TX_MARK, +}; + +/* = [ UART3 ] ============ */ +static const unsigned int uart3_data_pins[] = { + /* RX, TX */ + 46, 47, +}; +static const unsigned int uart3_data_mux[] = { + UART3_RX_MARK, UART3_TX_MARK, +}; + +/* = [ USB ] ============== */ +EMEV_MUX_PIN(usb_vbus, 153, USB_VBUS); + +/* = [ USI0 ] ============== */ +EMEV_MUX_PIN(usi0_cs1, 105, USI0_CS1); +EMEV_MUX_PIN(usi0_cs2, 106, USI0_CS2); +EMEV_MUX_PIN(usi0_cs3, 115, USI0_CS3); +EMEV_MUX_PIN(usi0_cs4, 116, USI0_CS4); +EMEV_MUX_PIN(usi0_cs5, 117, USI0_CS5); +EMEV_MUX_PIN(usi0_cs6, 118, USI0_CS6); + +/* = [ USI1 ] ============== */ +static const unsigned int usi1_pins[] = { + /* DI, DO*/ + 107, 108, +}; +static const unsigned int usi1_mux[] = { + USI1_DI_MARK, USI1_DO_MARK, +}; + +/* = [ USI2 ] ============== */ +static const unsigned int usi2_pins[] = { + /* CLK, DI, DO*/ + 109, 110, 111, +}; +static const unsigned int usi2_mux[] = { + USI2_CLK_MARK, USI2_DI_MARK, USI2_DO_MARK, +}; +EMEV_MUX_PIN(usi2_cs0, 112, USI2_CS0); +EMEV_MUX_PIN(usi2_cs1, 113, USI2_CS1); +EMEV_MUX_PIN(usi2_cs2, 114, USI2_CS2); + +/* = [ USI3 ] ============== */ +static const unsigned int usi3_pins[] = { + /* CLK, DI, DO*/ + 115, 116, 117, +}; +static const unsigned int usi3_mux[] = { + USI3_CLK_MARK, USI3_DI_MARK, USI3_DO_MARK, +}; +EMEV_MUX_PIN(usi3_cs0, 118, USI3_CS0); + +/* = [ USI4 ] ============== */ +static const unsigned int usi4_pins[] = { + /* CLK, DI, DO*/ + 119, 120, 121, +}; +static const unsigned int usi4_mux[] = { + USI4_CLK_MARK, USI4_DI_MARK, USI4_DO_MARK, +}; +EMEV_MUX_PIN(usi4_cs0, 113, USI4_CS0); +EMEV_MUX_PIN(usi4_cs1, 114, USI4_CS1); + +/* = [ USI5 ] ============== */ +static const unsigned int usi5_a_pins[] = { + /* CLK, DI, DO*/ + 85, 86, 87, +}; +static const unsigned int usi5_a_mux[] = { + USI5_CLK_A_MARK, USI5_DI_A_MARK, USI5_DO_A_MARK, +}; +EMEV_MUX_PIN(usi5_cs0_a, 88, USI5_CS0_A); +EMEV_MUX_PIN(usi5_cs1_a, 89, USI5_CS1_A); +EMEV_MUX_PIN(usi5_cs2_a, 90, USI5_CS2_A); + +static const unsigned int usi5_b_pins[] = { + /* CLK, DI, DO*/ + 143, 144, 150, +}; +static const unsigned int usi5_b_mux[] = { + USI5_CLK_B_MARK, USI5_DI_B_MARK, USI5_DO_B_MARK, +}; +EMEV_MUX_PIN(usi5_cs0_b, 145, USI5_CS0_B); +EMEV_MUX_PIN(usi5_cs1_b, 146, USI5_CS1_B); +EMEV_MUX_PIN(usi5_cs2_b, 147, USI5_CS2_B); +EMEV_MUX_PIN(usi5_cs3_b, 148, USI5_CS3_B); +EMEV_MUX_PIN(usi5_cs4_b, 149, USI5_CS4_B); + +static const struct sh_pfc_pin_group pinmux_groups[] = { + SH_PFC_PIN_GROUP(err_rst_reqb), + SH_PFC_PIN_GROUP(ref_clko), + SH_PFC_PIN_GROUP(ext_clki), + SH_PFC_PIN_GROUP(lowpwr), + + SH_PFC_PIN_GROUP(ab_main), + SH_PFC_PIN_GROUP(ab_clk), + SH_PFC_PIN_GROUP(ab_csb0), + SH_PFC_PIN_GROUP(ab_csb1), + SH_PFC_PIN_GROUP(ab_csb2), + SH_PFC_PIN_GROUP(ab_csb3), + SH_PFC_PIN_GROUP(ab_wait), + SH_PFC_PIN_GROUP(ab_adv), + SH_PFC_PIN_GROUP(ab_a17), + SH_PFC_PIN_GROUP(ab_a18), + SH_PFC_PIN_GROUP(ab_a19), + SH_PFC_PIN_GROUP(ab_a20), + SH_PFC_PIN_GROUP(ab_a21), + SH_PFC_PIN_GROUP(ab_a22), + SH_PFC_PIN_GROUP(ab_a23), + SH_PFC_PIN_GROUP(ab_a24), + SH_PFC_PIN_GROUP(ab_a25), + SH_PFC_PIN_GROUP(ab_a26), + SH_PFC_PIN_GROUP(ab_a27), + SH_PFC_PIN_GROUP(ab_a28), + SH_PFC_PIN_GROUP(ab_ben0), + SH_PFC_PIN_GROUP(ab_ben1), + + SH_PFC_PIN_GROUP(cam_clko), + SH_PFC_PIN_GROUP(cam), + + SH_PFC_PIN_GROUP(cf_ctrl), + SH_PFC_PIN_GROUP(cf_data8), + SH_PFC_PIN_GROUP(cf_data16), + + SH_PFC_PIN_GROUP(dtv_a), + SH_PFC_PIN_GROUP(dtv_b), + + SH_PFC_PIN_GROUP(iic0), + + SH_PFC_PIN_GROUP(iic1), + + SH_PFC_PIN_GROUP(jtag), + + SH_PFC_PIN_GROUP(lcd3_pxclk), + SH_PFC_PIN_GROUP(lcd3_pxclkb), + SH_PFC_PIN_GROUP(lcd3_clk_i), + SH_PFC_PIN_GROUP(lcd3_sync), + SH_PFC_PIN_GROUP(lcd3_rgb888), + SH_PFC_PIN_GROUP(yuv3_clk_i), + SH_PFC_PIN_GROUP(yuv3), + + SH_PFC_PIN_GROUP(ntsc_clk), + SH_PFC_PIN_GROUP(ntsc_data), + + SH_PFC_PIN_GROUP(pwm0), + + SH_PFC_PIN_GROUP(pwm1), + + SH_PFC_PIN_GROUP(sd_cki), + + SH_PFC_PIN_GROUP(sdi0_ctrl), + SH_PFC_PIN_GROUP(sdi0_data1), + SH_PFC_PIN_GROUP(sdi0_data4), + SH_PFC_PIN_GROUP(sdi0_data8), + + SH_PFC_PIN_GROUP(sdi1_ctrl), + SH_PFC_PIN_GROUP(sdi1_data1), + SH_PFC_PIN_GROUP(sdi1_data4), + + SH_PFC_PIN_GROUP(sdi2_ctrl), + SH_PFC_PIN_GROUP(sdi2_data1), + SH_PFC_PIN_GROUP(sdi2_data4), + + SH_PFC_PIN_GROUP(tp33), + + SH_PFC_PIN_GROUP(uart1_data), + SH_PFC_PIN_GROUP(uart1_ctrl), + + SH_PFC_PIN_GROUP(uart2_data), + + SH_PFC_PIN_GROUP(uart3_data), + + SH_PFC_PIN_GROUP(usb_vbus), + + SH_PFC_PIN_GROUP(usi0_cs1), + SH_PFC_PIN_GROUP(usi0_cs2), + SH_PFC_PIN_GROUP(usi0_cs3), + SH_PFC_PIN_GROUP(usi0_cs4), + SH_PFC_PIN_GROUP(usi0_cs5), + SH_PFC_PIN_GROUP(usi0_cs6), + + SH_PFC_PIN_GROUP(usi1), + + SH_PFC_PIN_GROUP(usi2), + SH_PFC_PIN_GROUP(usi2_cs0), + SH_PFC_PIN_GROUP(usi2_cs1), + SH_PFC_PIN_GROUP(usi2_cs2), + + SH_PFC_PIN_GROUP(usi3), + SH_PFC_PIN_GROUP(usi3_cs0), + + SH_PFC_PIN_GROUP(usi4), + SH_PFC_PIN_GROUP(usi4_cs0), + SH_PFC_PIN_GROUP(usi4_cs1), + + SH_PFC_PIN_GROUP(usi5_a), + SH_PFC_PIN_GROUP(usi5_cs0_a), + SH_PFC_PIN_GROUP(usi5_cs1_a), + SH_PFC_PIN_GROUP(usi5_cs2_a), + SH_PFC_PIN_GROUP(usi5_b), + SH_PFC_PIN_GROUP(usi5_cs0_b), + SH_PFC_PIN_GROUP(usi5_cs1_b), + SH_PFC_PIN_GROUP(usi5_cs2_b), + SH_PFC_PIN_GROUP(usi5_cs3_b), + SH_PFC_PIN_GROUP(usi5_cs4_b), +}; + +static const char * const ab_groups[] = { + "ab_main", + "ab_clk", + "ab_csb0", + "ab_csb1", + "ab_csb2", + "ab_csb3", + "ab_wait", + "ab_adv", + "ab_a17", + "ab_a18", + "ab_a19", + "ab_a20", + "ab_a21", + "ab_a22", + "ab_a23", + "ab_a24", + "ab_a25", + "ab_a26", + "ab_a27", + "ab_a28", + "ab_ben0", + "ab_ben1", +}; + +static const char * const cam_groups[] = { + "cam_clko", + "cam", +}; + +static const char * const cf_groups[] = { + "cf_ctrl", + "cf_data8", + "cf_data16", +}; + +static const char * const dtv_groups[] = { + "dtv_a", + "dtv_b", +}; + +static const char * const iic0_groups[] = { + "iic0", +}; + +static const char * const iic1_groups[] = { + "iic1", +}; + +static const char * const jtag_groups[] = { + "jtag", +}; + +static const char * const lcd_groups[] = { + "lcd3_pxclk", + "lcd3_pxclkb", + "lcd3_clk_i", + "lcd3_sync", + "lcd3_rgb888", + "yuv3_clk_i", + "yuv3", +}; + +static const char * const ntsc_groups[] = { + "ntsc_clk", + "ntsc_data", +}; + +static const char * const pwm0_groups[] = { + "pwm0", +}; + +static const char * const pwm1_groups[] = { + "pwm1", +}; + +static const char * const sd_groups[] = { + "sd_cki", +}; + +static const char * const sdi0_groups[] = { + "sdi0_ctrl", + "sdi0_data1", + "sdi0_data4", + "sdi0_data8", +}; + +static const char * const sdi1_groups[] = { + "sdi1_ctrl", + "sdi1_data1", + "sdi1_data4", +}; + +static const char * const sdi2_groups[] = { + "sdi2_ctrl", + "sdi2_data1", + "sdi2_data4", +}; + +static const char * const tp33_groups[] = { + "tp33", +}; + +static const char * const uart1_groups[] = { + "uart1_data", + "uart1_ctrl", +}; + +static const char * const uart2_groups[] = { + "uart2_data", +}; + +static const char * const uart3_groups[] = { + "uart3_data", +}; + +static const char * const usb_groups[] = { + "usb_vbus", +}; + +static const char * const usi0_groups[] = { + "usi0_cs1", + "usi0_cs2", + "usi0_cs3", + "usi0_cs4", + "usi0_cs5", + "usi0_cs6", +}; + +static const char * const usi1_groups[] = { + "usi1", +}; + +static const char * const usi2_groups[] = { + "usi2", + "usi2_cs0", + "usi2_cs1", + "usi2_cs2", +}; + +static const char * const usi3_groups[] = { + "usi3", + "usi3_cs0", +}; + +static const char * const usi4_groups[] = { + "usi4", + "usi4_cs0", + "usi4_cs1", +}; + +static const char * const usi5_groups[] = { + "usi5_a", + "usi5_cs0_a", + "usi5_cs1_a", + "usi5_cs2_a", + "usi5_b", + "usi5_cs0_b", + "usi5_cs1_b", + "usi5_cs2_b", + "usi5_cs3_b", + "usi5_cs4_b", +}; + +static const struct sh_pfc_function pinmux_functions[] = { + SH_PFC_FUNCTION(ab), + SH_PFC_FUNCTION(cam), + SH_PFC_FUNCTION(cf), + SH_PFC_FUNCTION(dtv), + SH_PFC_FUNCTION(iic0), + SH_PFC_FUNCTION(iic1), + SH_PFC_FUNCTION(jtag), + SH_PFC_FUNCTION(lcd), + SH_PFC_FUNCTION(ntsc), + SH_PFC_FUNCTION(pwm0), + SH_PFC_FUNCTION(pwm1), + SH_PFC_FUNCTION(sd), + SH_PFC_FUNCTION(sdi0), + SH_PFC_FUNCTION(sdi1), + SH_PFC_FUNCTION(sdi2), + SH_PFC_FUNCTION(tp33), + SH_PFC_FUNCTION(uart1), + SH_PFC_FUNCTION(uart2), + SH_PFC_FUNCTION(uart3), + SH_PFC_FUNCTION(usb), + SH_PFC_FUNCTION(usi0), + SH_PFC_FUNCTION(usi1), + SH_PFC_FUNCTION(usi2), + SH_PFC_FUNCTION(usi3), + SH_PFC_FUNCTION(usi4), + SH_PFC_FUNCTION(usi5), +}; + +static const struct pinmux_cfg_reg pinmux_config_regs[] = { + { PINMUX_CFG_REG("GPSR0", 0xe0140200, 32, 1) { + 0, PORT31_FN, /* PIN: J18 */ + 0, PORT30_FN, /* PIN: H18 */ + 0, PORT29_FN, /* PIN: G18 */ + 0, PORT28_FN, /* PIN: F18 */ + 0, PORT27_FN, /* PIN: F17 */ + 0, PORT26_FN, /* PIN: F16 */ + 0, PORT25_FN, /* PIN: E20 */ + 0, PORT24_FN, /* PIN: D20 */ + FN_LCD3_1_0_PORT23, PORT23_FN, /* PIN: D19 */ + FN_LCD3_1_0_PORT22, PORT22_FN, /* PIN: C20 */ + FN_LCD3_1_0_PORT21, PORT21_FN, /* PIN: B21 */ + FN_LCD3_1_0_PORT20, PORT20_FN, /* PIN: A21 */ + FN_LCD3_PXCLKB, PORT19_FN, /* PIN: C21 */ + FN_LCD3_1_0_PORT18, PORT18_FN, /* PIN: B22 */ + 0, PORT17_FN, /* PIN: W20 */ + 0, PORT16_FN, /* PIN: W21 */ + 0, PORT15_FN, /* PIN: Y19 */ + 0, PORT14_FN, /* PIN: Y20 */ + 0, PORT13_FN, /* PIN: Y21 */ + 0, PORT12_FN, /* PIN: AA20 */ + 0, PORT11_FN, /* PIN: AA21 */ + 0, PORT10_FN, /* PIN: AA22 */ + 0, PORT9_FN, /* PIN: V15 */ + 0, PORT8_FN, /* PIN: V16 */ + 0, PORT7_FN, /* PIN: V17 */ + 0, PORT6_FN, /* PIN: V18 */ + FN_EXT_CLKI, PORT5_FN, /* PIN: U8 */ + FN_REF_CLKO, PORT4_FN, /* PIN: V8 */ + FN_ERR_RST_REQB, PORT3_FN, /* PIN: U9 */ + FN_JT_SEL, PORT2_FN, /* PIN: V9 */ + 0, PORT1_FN, /* PIN: U10 */ + 0, PORT0_FN, /* PIN: V10 */ + } + }, + { PINMUX_CFG_REG("GPSR1", 0xe0140204, 32, 1) { + FN_SDI1_CMD, PORT63_FN, /* PIN: AC21 */ + FN_SDI1_CKI, PORT62_FN, /* PIN: AA23 */ + FN_SDI1_CKO, PORT61_FN, /* PIN: AB22 */ + FN_SDI0_DATA7, PORT60_FN, /* PIN: Y16 */ + FN_SDI0_DATA6, PORT59_FN, /* PIN: AA16 */ + FN_SDI0_DATA5, PORT58_FN, /* PIN: Y15 */ + FN_SDI0_DATA4, PORT57_FN, /* PIN: AA15 */ + FN_SDI0_DATA3, PORT56_FN, /* PIN: Y14 */ + FN_SDI0_DATA2, PORT55_FN, /* PIN: AA14 */ + FN_SDI0_DATA1, PORT54_FN, /* PIN: Y13 */ + FN_SDI0_DATA0, PORT53_FN, /* PIN: AA13 */ + FN_SDI0_CMD, PORT52_FN, /* PIN: Y12 */ + FN_SDI0_CKI, PORT51_FN, /* PIN: AC18 */ + FN_SDI0_CKO, PORT50_FN, /* PIN: AB18 */ + 0, PORT49_FN, /* PIN: AB16 */ + FN_SD_CKI, PORT48_FN, /* PIN: AC19 */ + FN_IIC_1_0_PORT47, PORT47_FN, /* PIN: Y8 */ + FN_IIC_1_0_PORT46, PORT46_FN, /* PIN: Y9 */ + FN_IIC0_SDA, PORT45_FN, /* PIN: AA8 */ + FN_IIC0_SCL, PORT44_FN, /* PIN: AA9 */ + FN_LCD3_11_10_PORT43, PORT43_FN, /* PIN: A15 */ + FN_LCD3_11_10_PORT42, PORT42_FN, /* PIN: A16 */ + FN_LCD3_11_10_PORT41, PORT41_FN, /* PIN: A17 */ + FN_LCD3_11_10_PORT40, PORT40_FN, /* PIN: A18 */ + FN_LCD3_9_8_PORT39, PORT39_FN, /* PIN: D18 */ + FN_LCD3_9_8_PORT38, PORT38_FN, /* PIN: C18 */ + FN_LCD3_R5, PORT37_FN, /* PIN: B18 */ + FN_LCD3_R4, PORT36_FN, /* PIN: C19 */ + FN_LCD3_R3, PORT35_FN, /* PIN: B19 */ + FN_LCD3_R2, PORT34_FN, /* PIN: A19 */ + FN_LCD3_R1, PORT33_FN, /* PIN: B20 */ + FN_LCD3_R0, PORT32_FN, /* PIN: A20 */ + } + }, + { PINMUX_CFG_REG("GPSR2", 0xe0140208, 32, 1) { + FN_AB_1_0_PORT95, PORT95_FN, /* PIN: L21 */ + FN_AB_1_0_PORT94, PORT94_FN, /* PIN: K21 */ + FN_AB_1_0_PORT93, PORT93_FN, /* PIN: J21 */ + FN_AB_7_6_PORT92, PORT92_FN, /* PIN: J22 */ + FN_AB_7_6_PORT91, PORT91_FN, /* PIN: H21 */ + FN_AB_5_4_PORT90, PORT90_FN, /* PIN: H22 */ + FN_AB_5_4_PORT89, PORT89_FN, /* PIN: H23 */ + FN_AB_3_2_PORT88, PORT88_FN, /* PIN: G21 */ + FN_AB_3_2_PORT87, PORT87_FN, /* PIN: G22 */ + FN_AB_3_2_PORT86, PORT86_FN, /* PIN: G23 */ + FN_AB_3_2_PORT85, PORT85_FN, /* PIN: F21 */ + FN_AB_1_0_PORT84, PORT84_FN, /* PIN: F22 */ + FN_AB_1_0_PORT83, PORT83_FN, /* PIN: F23 */ + FN_AB_1_0_PORT82, PORT82_FN, /* PIN: E22 */ + FN_AB_1_0_PORT81, PORT81_FN, /* PIN: E23 */ + FN_AB_1_0_PORT80, PORT80_FN, /* PIN: D22 */ + FN_AB_1_0_PORT79, PORT79_FN, /* PIN: D23 */ + FN_AB_1_0_PORT78, PORT78_FN, /* PIN: C22 */ + FN_AB_1_0_PORT77, PORT77_FN, /* PIN: C23 */ + FN_AB_1_0_PORT76, PORT76_FN, /* PIN: K20 */ + FN_AB_1_0_PORT75, PORT75_FN, /* PIN: L20 */ + FN_AB_1_0_PORT74, PORT74_FN, /* PIN: H20 */ + FN_AB_1_0_PORT73, PORT73_FN, /* PIN: J20 */ + FN_AB_1_0_PORT72, PORT72_FN, /* PIN: G20 */ + FN_AB_1_0_PORT71, PORT71_FN, /* PIN: F20 */ + FN_AB_CSB1, PORT70_FN, /* PIN: E21 */ + FN_AB_CSB0, PORT69_FN, /* PIN: D21 */ + FN_AB_CLK, PORT68_FN, /* PIN: J23 */ + FN_SDI1_DATA3, PORT67_FN, /* PIN: AA19 */ + FN_SDI1_DATA2, PORT66_FN, /* PIN: AB19 */ + FN_SDI1_DATA1, PORT65_FN, /* PIN: AB20 */ + FN_SDI1_DATA0, PORT64_FN, /* PIN: AB21 */ + } + }, + { PINMUX_CFG_REG("GPSR3", 0xe014020c, 32, 1) { + FN_NTSC_DATA4, PORT127_FN, /* PIN: T20 */ + FN_NTSC_DATA3, PORT126_FN, /* PIN: R18 */ + FN_NTSC_DATA2, PORT125_FN, /* PIN: R20 */ + FN_NTSC_DATA1, PORT124_FN, /* PIN: P18 */ + FN_NTSC_DATA0, PORT123_FN, /* PIN: P20 */ + FN_NTSC_CLK, PORT122_FN, /* PIN: V20 */ + FN_USI_9_8_PORT121, PORT121_FN, /* PIN: Y5 */ + FN_USI_9_8_PORT120, PORT120_FN, /* PIN: AA4 */ + FN_USI_7_6_PORT119, PORT119_FN, /* PIN: AB3 */ + FN_USI_5_4_PORT118, PORT118_FN, /* PIN: AB4 */ + FN_USI_5_4_PORT117, PORT117_FN, /* PIN: AC3 */ + FN_USI_5_4_PORT116, PORT116_FN, /* PIN: AC4 */ + FN_USI_5_4_PORT115, PORT115_FN, /* PIN: AC5 */ + FN_USI_3_2_PORT114, PORT114_FN, /* PIN: Y6 */ + FN_USI_3_2_PORT113, PORT113_FN, /* PIN: AA7 */ + FN_USI_1_0_PORT112, PORT112_FN, /* PIN: Y7 */ + FN_USI_1_0_PORT111, PORT111_FN, /* PIN: AA5 */ + FN_USI_1_0_PORT110, PORT110_FN, /* PIN: AA6 */ + FN_USI_1_0_PORT109, PORT109_FN, /* PIN: AB5 */ + FN_USI1_DO, PORT108_FN, /* PIN: D10 */ + FN_USI1_DI, PORT107_FN, /* PIN: C10 */ + FN_USI0_CS2, PORT106_FN, /* PIN: B9 */ + FN_USI0_CS1, PORT105_FN, /* PIN: B8 */ + FN_AB_13_12_PORT104, PORT104_FN, /* PIN: M17 */ + FN_AB_13_12_PORT103, PORT103_FN, /* PIN: L17 */ + FN_AB_11_10_PORT102, PORT102_FN, /* PIN: N18 */ + FN_AB_11_10_PORT101, PORT101_FN, /* PIN: M18 */ + FN_AB_11_10_PORT100, PORT100_FN, /* PIN: L18 */ + FN_AB_9_8_PORT99, PORT99_FN, /* PIN: N20 */ + FN_AB_9_8_PORT98, PORT98_FN, /* PIN: M20 */ + FN_AB_9_8_PORT97, PORT97_FN, /* PIN: N21 */ + FN_AB_A20, PORT96_FN, /* PIN: M21 */ + } + }, + { PINMUX_CFG_REG("GPSR4", 0xe0140210, 32, 1) { + 0, 0, + FN_UART_1_0_PORT158, PORT158_FN, /* PIN: AB10 */ + FN_UART_1_0_PORT157, PORT157_FN, /* PIN: AA10 */ + FN_UART1_TX, PORT156_FN, /* PIN: Y10 */ + FN_UART1_RX, PORT155_FN, /* PIN: Y11 */ + FN_LOWPWR, PORT154_FN, /* PIN: A12 */ + FN_USB_VBUS, PORT153_FN, /* PIN: AA12 */ + FN_JT_TDOEN, PORT152_FN, /* PIN: F13 */ + FN_JT_TDO, PORT151_FN, /* PIN: D13 */ + FN_HSI_1_0_PORT150, PORT150_FN, /* PIN: M22 */ + FN_HSI_1_0_PORT149, PORT149_FN, /* PIN: M23 */ + FN_HSI_1_0_PORT148, PORT148_FN, /* PIN: N23 */ + FN_HSI_1_0_PORT147, PORT147_FN, /* PIN: N22 */ + FN_HSI_1_0_PORT146, PORT146_FN, /* PIN: L22 */ + FN_HSI_1_0_PORT145, PORT145_FN, /* PIN: L23 */ + FN_HSI_1_0_PORT144, PORT144_FN, /* PIN: K23 */ + FN_HSI_1_0_PORT143, PORT143_FN, /* PIN: K22 */ + FN_CAM_YUV7, PORT142_FN, /* PIN: V23 */ + FN_CAM_YUV6, PORT141_FN, /* PIN: V22 */ + FN_CAM_YUV5, PORT140_FN, /* PIN: U23 */ + FN_CAM_YUV4, PORT139_FN, /* PIN: U22 */ + FN_CAM_YUV3, PORT138_FN, /* PIN: U21 */ + FN_CAM_YUV2, PORT137_FN, /* PIN: T23 */ + FN_CAM_YUV1, PORT136_FN, /* PIN: T22 */ + FN_CAM_YUV0, PORT135_FN, /* PIN: T21 */ + FN_CAM_HS, PORT134_FN, /* PIN: V21 */ + FN_CAM_VS, PORT133_FN, /* PIN: W22 */ + FN_CAM_CLKI, PORT132_FN, /* PIN: Y23 */ + FN_CAM_CLKO, PORT131_FN, /* PIN: W23 */ + FN_NTSC_DATA7, PORT130_FN, /* PIN: U18 */ + FN_NTSC_DATA6, PORT129_FN, /* PIN: U20 */ + FN_NTSC_DATA5, PORT128_FN, /* PIN: T18 */ + } + }, + { PINMUX_CFG_REG_VAR("CHG_PINSEL_LCD3", 0xe0140284, 32, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2) { + /* 31 - 12 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 11 - 10 */ + FN_SEL_LCD3_11_10_00, FN_SEL_LCD3_11_10_01, + FN_SEL_LCD3_11_10_10, 0, + /* 9 - 8 */ + FN_SEL_LCD3_9_8_00, 0, FN_SEL_LCD3_9_8_10, 0, + /* 7 - 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 1 - 0 */ + FN_SEL_LCD3_1_0_00, FN_SEL_LCD3_1_0_01, 0, 0, + } + }, + { PINMUX_CFG_REG_VAR("CHG_PINSEL_UART", 0xe0140288, 32, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2) { + /* 31 - 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 1 - 0 */ + FN_SEL_UART_1_0_00, FN_SEL_UART_1_0_01, 0, 0, + } + }, + { PINMUX_CFG_REG_VAR("CHG_PINSEL_IIC", 0xe014028c, 32, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2) { + /* 31 - 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 1 - 0 */ + FN_SEL_IIC_1_0_00, FN_SEL_IIC_1_0_01, 0, 0, + } + }, + { PINMUX_CFG_REG_VAR("CHG_PINSEL_AB", 0xe0140294, 32, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2) { + /* 31 - 14 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + /* 13 - 12 */ + FN_SEL_AB_13_12_00, 0, FN_SEL_AB_13_12_10, 0, + /* 11 - 10 */ + FN_SEL_AB_11_10_00, 0, FN_SEL_AB_11_10_10, 0, + /* 9 - 8 */ + FN_SEL_AB_9_8_00, FN_SEL_AB_9_8_01, FN_SEL_AB_9_8_10, 0, + /* 7 - 6 */ + FN_SEL_AB_7_6_00, FN_SEL_AB_7_6_01, FN_SEL_AB_7_6_10, 0, + /* 5 - 4 */ + FN_SEL_AB_5_4_00, FN_SEL_AB_5_4_01, + FN_SEL_AB_5_4_10, FN_SEL_AB_5_4_11, + /* 3 - 2 */ + FN_SEL_AB_3_2_00, FN_SEL_AB_3_2_01, + FN_SEL_AB_3_2_10, FN_SEL_AB_3_2_11, + /* 1 - 0 */ + FN_SEL_AB_1_0_00, 0, FN_SEL_AB_1_0_10, 0, + } + }, + { PINMUX_CFG_REG_VAR("CHG_PINSEL_USI", 0xe0140298, 32, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2) { + /* 31 - 10 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 9 - 8 */ + FN_SEL_USI_9_8_00, FN_SEL_USI_9_8_01, 0, 0, + /* 7 - 6 */ + FN_SEL_USI_7_6_00, FN_SEL_USI_7_6_01, 0, 0, + /* 5 - 4 */ + FN_SEL_USI_5_4_00, FN_SEL_USI_5_4_01, 0, 0, + /* 3 - 2 */ + FN_SEL_USI_3_2_00, FN_SEL_USI_3_2_01, 0, 0, + /* 1 - 0 */ + FN_SEL_USI_1_0_00, FN_SEL_USI_1_0_01, 0, 0, + } + }, + { PINMUX_CFG_REG_VAR("CHG_PINSEL_HSI", 0xe01402a8, 32, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2) { + /* 31 - 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 1 - 0 */ + FN_SEL_HSI_1_0_00, FN_SEL_HSI_1_0_01, 0, 0, + } + }, + { }, +}; + +const struct sh_pfc_soc_info emev2_pinmux_info = { + .name = "emev2_pfc", + + .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END }, + + .pins = pinmux_pins, + .nr_pins = ARRAY_SIZE(pinmux_pins), + .groups = pinmux_groups, + .nr_groups = ARRAY_SIZE(pinmux_groups), + .functions = pinmux_functions, + .nr_functions = ARRAY_SIZE(pinmux_functions), + + .cfg_regs = pinmux_config_regs, + + .gpio_data = pinmux_data, + .gpio_data_size = ARRAY_SIZE(pinmux_data), +}; diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c index 9a179c94b4dc..80c1843bb6ad 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c @@ -2241,6 +2241,13 @@ static const unsigned int intc_irq3_pins[] = { static const unsigned int intc_irq3_mux[] = { IRQ3_MARK, }; +/* - MLB+ ------------------------------------------------------------------- */ +static const unsigned int mlb_3pin_pins[] = { + RCAR_GP_PIN(4, 0), RCAR_GP_PIN(4, 1), RCAR_GP_PIN(4, 2), +}; +static const unsigned int mlb_3pin_mux[] = { + MLB_CLK_MARK, MLB_SIG_MARK, MLB_DAT_MARK, +}; /* - MMCIF0 ----------------------------------------------------------------- */ static const unsigned int mmc0_data1_pins[] = { /* D[0] */ @@ -3873,6 +3880,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(intc_irq1), SH_PFC_PIN_GROUP(intc_irq2), SH_PFC_PIN_GROUP(intc_irq3), + SH_PFC_PIN_GROUP(mlb_3pin), SH_PFC_PIN_GROUP(mmc0_data1), SH_PFC_PIN_GROUP(mmc0_data4), SH_PFC_PIN_GROUP(mmc0_data8), @@ -4198,6 +4206,10 @@ static const char * const intc_groups[] = { "intc_irq3", }; +static const char * const mlb_groups[] = { + "mlb_3pin", +}; + static const char * const mmc0_groups[] = { "mmc0_data1", "mmc0_data4", @@ -4511,6 +4523,7 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(iic2), SH_PFC_FUNCTION(iic3), SH_PFC_FUNCTION(intc), + SH_PFC_FUNCTION(mlb), SH_PFC_FUNCTION(mmc0), SH_PFC_FUNCTION(mmc1), SH_PFC_FUNCTION(msiof0), diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c index c6e5deba238e..fdd2c8729791 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -378,7 +378,7 @@ enum { /* IPSR16 */ FN_HRX1, FN_SCIFB1_RXD, FN_VI1_R0_B, FN_GLO_SDATA_C, FN_VI1_DATA6_C, FN_HTX1, FN_SCIFB1_TXD, FN_VI1_R1_B, FN_GLO_SS_C, FN_VI1_DATA7_C, - FN_HSCK1, FN_SCIFB1_SCK, FN_MLB_CK, FN_GLO_RFON_C, + FN_HSCK1, FN_SCIFB1_SCK, FN_MLB_CLK, FN_GLO_RFON_C, FN_HCTS1_N, FN_SCIFB1_CTS_N, FN_MLB_SIG, FN_CAN1_TX_B, FN_HRTS1_N, FN_SCIFB1_RTS_N, FN_MLB_DAT, FN_CAN1_RX_B, @@ -764,7 +764,7 @@ enum { GLO_SDATA_C_MARK, VI1_DATA6_C_MARK, HTX1_MARK, SCIFB1_TXD_MARK, VI1_R1_B_MARK, GLO_SS_C_MARK, VI1_DATA7_C_MARK, - HSCK1_MARK, SCIFB1_SCK_MARK, MLB_CK_MARK, GLO_RFON_C_MARK, + HSCK1_MARK, SCIFB1_SCK_MARK, MLB_CLK_MARK, GLO_RFON_C_MARK, HCTS1_N_MARK, SCIFB1_CTS_N_MARK, MLB_SIG_MARK, CAN1_TX_B_MARK, HRTS1_N_MARK, SCIFB1_RTS_N_MARK, MLB_DAT_MARK, CAN1_RX_B_MARK, PINMUX_MARK_END, @@ -1664,7 +1664,7 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_MODSEL_DATA(IP16_5_3, VI1_DATA7_C, SEL_VI1_2), PINMUX_IPSR_MODSEL_DATA(IP16_7_6, HSCK1, SEL_HSCIF1_0), PINMUX_IPSR_MODSEL_DATA(IP16_7_6, SCIFB1_SCK, SEL_SCIFB1_0), - PINMUX_IPSR_DATA(IP16_7_6, MLB_CK), + PINMUX_IPSR_DATA(IP16_7_6, MLB_CLK), PINMUX_IPSR_MODSEL_DATA(IP16_7_6, GLO_RFON_C, SEL_GPS_2), PINMUX_IPSR_MODSEL_DATA(IP16_9_8, HCTS1_N, SEL_HSCIF1_0), PINMUX_IPSR_DATA(IP16_9_8, SCIFB1_CTS_N), @@ -2391,6 +2391,13 @@ static const unsigned int intc_irq3_pins[] = { static const unsigned int intc_irq3_mux[] = { IRQ3_MARK, }; +/* - MLB+ ------------------------------------------------------------------- */ +static const unsigned int mlb_3pin_pins[] = { + RCAR_GP_PIN(7, 7), RCAR_GP_PIN(7, 8), RCAR_GP_PIN(7, 9), +}; +static const unsigned int mlb_3pin_mux[] = { + MLB_CLK_MARK, MLB_SIG_MARK, MLB_DAT_MARK, +}; /* - MMCIF ------------------------------------------------------------------ */ static const unsigned int mmc_data1_pins[] = { /* D[0] */ @@ -4267,6 +4274,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(intc_irq1), SH_PFC_PIN_GROUP(intc_irq2), SH_PFC_PIN_GROUP(intc_irq3), + SH_PFC_PIN_GROUP(mlb_3pin), SH_PFC_PIN_GROUP(mmc_data1), SH_PFC_PIN_GROUP(mmc_data4), SH_PFC_PIN_GROUP(mmc_data8), @@ -4648,6 +4656,10 @@ static const char * const intc_groups[] = { "intc_irq3", }; +static const char * const mlb_groups[] = { + "mlb_3pin", +}; + static const char * const mmc_groups[] = { "mmc_data1", "mmc_data4", @@ -4972,6 +4984,7 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(i2c7), SH_PFC_FUNCTION(i2c8), SH_PFC_FUNCTION(intc), + SH_PFC_FUNCTION(mlb), SH_PFC_FUNCTION(mmc), SH_PFC_FUNCTION(msiof0), SH_PFC_FUNCTION(msiof1), @@ -5974,7 +5987,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { /* IP16_9_8 [2] */ FN_HCTS1_N, FN_SCIFB1_CTS_N, FN_MLB_SIG, FN_CAN1_TX_B, /* IP16_7_6 [2] */ - FN_HSCK1, FN_SCIFB1_SCK, FN_MLB_CK, FN_GLO_RFON_C, + FN_HSCK1, FN_SCIFB1_SCK, FN_MLB_CLK, FN_GLO_RFON_C, /* IP16_5_3 [3] */ FN_HTX1, FN_SCIFB1_TXD, FN_VI1_R1_B, FN_GLO_SS_C, FN_VI1_DATA7_C, diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7372.c b/drivers/pinctrl/sh-pfc/pfc-sh7372.c deleted file mode 100644 index 8211f66a2f68..000000000000 --- a/drivers/pinctrl/sh-pfc/pfc-sh7372.c +++ /dev/null @@ -1,2645 +0,0 @@ -/* - * sh7372 processor support - PFC hardware block - * - * Copyright (C) 2010 Kuninori Morimoto - * - * Based on - * sh7367 processor support - PFC hardware block - * Copyright (C) 2010 Magnus Damm - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include -#include -#include -#include - -#include "core.h" -#include "sh_pfc.h" - -#define CPU_ALL_PORT(fn, pfx, sfx) \ - PORT_10(0, fn, pfx, sfx), PORT_90(0, fn, pfx, sfx), \ - PORT_10(100, fn, pfx##10, sfx), PORT_10(110, fn, pfx##11, sfx), \ - PORT_10(120, fn, pfx##12, sfx), PORT_10(130, fn, pfx##13, sfx), \ - PORT_10(140, fn, pfx##14, sfx), PORT_10(150, fn, pfx##15, sfx), \ - PORT_10(160, fn, pfx##16, sfx), PORT_10(170, fn, pfx##17, sfx), \ - PORT_10(180, fn, pfx##18, sfx), PORT_1(190, fn, pfx##190, sfx) - -#define IRQC_PIN_MUX(irq, pin) \ -static const unsigned int intc_irq##irq##_pins[] = { \ - pin, \ -}; \ -static const unsigned int intc_irq##irq##_mux[] = { \ - IRQ##irq##_MARK, \ -} - -#define IRQC_PINS_MUX(irq, pin0, pin1) \ -static const unsigned int intc_irq##irq##_0_pins[] = { \ - pin0, \ -}; \ -static const unsigned int intc_irq##irq##_0_mux[] = { \ - IRQ##irq##_##pin0##_MARK, \ -}; \ -static const unsigned int intc_irq##irq##_1_pins[] = { \ - pin1, \ -}; \ -static const unsigned int intc_irq##irq##_1_mux[] = { \ - IRQ##irq##_##pin1##_MARK, \ -} - -enum { - PINMUX_RESERVED = 0, - - /* PORT0_DATA -> PORT190_DATA */ - PINMUX_DATA_BEGIN, - PORT_ALL(DATA), - PINMUX_DATA_END, - - /* PORT0_IN -> PORT190_IN */ - PINMUX_INPUT_BEGIN, - PORT_ALL(IN), - PINMUX_INPUT_END, - - /* PORT0_OUT -> PORT190_OUT */ - PINMUX_OUTPUT_BEGIN, - PORT_ALL(OUT), - PINMUX_OUTPUT_END, - - PINMUX_FUNCTION_BEGIN, - PORT_ALL(FN_IN), /* PORT0_FN_IN -> PORT190_FN_IN */ - PORT_ALL(FN_OUT), /* PORT0_FN_OUT -> PORT190_FN_OUT */ - PORT_ALL(FN0), /* PORT0_FN0 -> PORT190_FN0 */ - PORT_ALL(FN1), /* PORT0_FN1 -> PORT190_FN1 */ - PORT_ALL(FN2), /* PORT0_FN2 -> PORT190_FN2 */ - PORT_ALL(FN3), /* PORT0_FN3 -> PORT190_FN3 */ - PORT_ALL(FN4), /* PORT0_FN4 -> PORT190_FN4 */ - PORT_ALL(FN5), /* PORT0_FN5 -> PORT190_FN5 */ - PORT_ALL(FN6), /* PORT0_FN6 -> PORT190_FN6 */ - PORT_ALL(FN7), /* PORT0_FN7 -> PORT190_FN7 */ - - MSEL1CR_31_0, MSEL1CR_31_1, - MSEL1CR_30_0, MSEL1CR_30_1, - MSEL1CR_29_0, MSEL1CR_29_1, - MSEL1CR_28_0, MSEL1CR_28_1, - MSEL1CR_27_0, MSEL1CR_27_1, - MSEL1CR_26_0, MSEL1CR_26_1, - MSEL1CR_16_0, MSEL1CR_16_1, - MSEL1CR_15_0, MSEL1CR_15_1, - MSEL1CR_14_0, MSEL1CR_14_1, - MSEL1CR_13_0, MSEL1CR_13_1, - MSEL1CR_12_0, MSEL1CR_12_1, - MSEL1CR_9_0, MSEL1CR_9_1, - MSEL1CR_8_0, MSEL1CR_8_1, - MSEL1CR_7_0, MSEL1CR_7_1, - MSEL1CR_6_0, MSEL1CR_6_1, - MSEL1CR_4_0, MSEL1CR_4_1, - MSEL1CR_3_0, MSEL1CR_3_1, - MSEL1CR_2_0, MSEL1CR_2_1, - MSEL1CR_0_0, MSEL1CR_0_1, - - MSEL3CR_27_0, MSEL3CR_27_1, - MSEL3CR_26_0, MSEL3CR_26_1, - MSEL3CR_21_0, MSEL3CR_21_1, - MSEL3CR_20_0, MSEL3CR_20_1, - MSEL3CR_15_0, MSEL3CR_15_1, - MSEL3CR_9_0, MSEL3CR_9_1, - MSEL3CR_6_0, MSEL3CR_6_1, - - MSEL4CR_19_0, MSEL4CR_19_1, - MSEL4CR_18_0, MSEL4CR_18_1, - MSEL4CR_17_0, MSEL4CR_17_1, - MSEL4CR_16_0, MSEL4CR_16_1, - MSEL4CR_15_0, MSEL4CR_15_1, - MSEL4CR_14_0, MSEL4CR_14_1, - MSEL4CR_10_0, MSEL4CR_10_1, - MSEL4CR_6_0, MSEL4CR_6_1, - MSEL4CR_4_0, MSEL4CR_4_1, - MSEL4CR_1_0, MSEL4CR_1_1, - PINMUX_FUNCTION_END, - - PINMUX_MARK_BEGIN, - - /* IRQ */ - IRQ0_6_MARK, IRQ0_162_MARK, IRQ1_MARK, IRQ2_4_MARK, - IRQ2_5_MARK, IRQ3_8_MARK, IRQ3_16_MARK, IRQ4_17_MARK, - IRQ4_163_MARK, IRQ5_MARK, IRQ6_39_MARK, IRQ6_164_MARK, - IRQ7_40_MARK, IRQ7_167_MARK, IRQ8_41_MARK, IRQ8_168_MARK, - IRQ9_42_MARK, IRQ9_169_MARK, IRQ10_MARK, IRQ11_MARK, - IRQ12_80_MARK, IRQ12_137_MARK, IRQ13_81_MARK, IRQ13_145_MARK, - IRQ14_82_MARK, IRQ14_146_MARK, IRQ15_83_MARK, IRQ15_147_MARK, - IRQ16_84_MARK, IRQ16_170_MARK, IRQ17_MARK, IRQ18_MARK, - IRQ19_MARK, IRQ20_MARK, IRQ21_MARK, IRQ22_MARK, - IRQ23_MARK, IRQ24_MARK, IRQ25_MARK, IRQ26_121_MARK, - IRQ26_172_MARK, IRQ27_122_MARK, IRQ27_180_MARK, IRQ28_123_MARK, - IRQ28_181_MARK, IRQ29_129_MARK, IRQ29_182_MARK, IRQ30_130_MARK, - IRQ30_183_MARK, IRQ31_138_MARK, IRQ31_184_MARK, - - /* MSIOF0 */ - MSIOF0_TSYNC_MARK, MSIOF0_TSCK_MARK, MSIOF0_RXD_MARK, - MSIOF0_RSCK_MARK, MSIOF0_RSYNC_MARK, MSIOF0_MCK0_MARK, - MSIOF0_MCK1_MARK, MSIOF0_SS1_MARK, MSIOF0_SS2_MARK, - MSIOF0_TXD_MARK, - - /* MSIOF1 */ - MSIOF1_TSCK_39_MARK, MSIOF1_TSYNC_40_MARK, - MSIOF1_TSCK_88_MARK, MSIOF1_TSYNC_89_MARK, - MSIOF1_TXD_41_MARK, MSIOF1_RXD_42_MARK, - MSIOF1_TXD_90_MARK, MSIOF1_RXD_91_MARK, - MSIOF1_SS1_43_MARK, MSIOF1_SS2_44_MARK, - MSIOF1_SS1_92_MARK, MSIOF1_SS2_93_MARK, - MSIOF1_RSCK_MARK, MSIOF1_RSYNC_MARK, - MSIOF1_MCK0_MARK, MSIOF1_MCK1_MARK, - - /* MSIOF2 */ - MSIOF2_RSCK_MARK, MSIOF2_RSYNC_MARK, MSIOF2_MCK0_MARK, - MSIOF2_MCK1_MARK, MSIOF2_SS1_MARK, MSIOF2_SS2_MARK, - MSIOF2_TSYNC_MARK, MSIOF2_TSCK_MARK, MSIOF2_RXD_MARK, - MSIOF2_TXD_MARK, - - /* BBIF1 */ - BBIF1_RXD_MARK, BBIF1_TSYNC_MARK, BBIF1_TSCK_MARK, - BBIF1_TXD_MARK, BBIF1_RSCK_MARK, BBIF1_RSYNC_MARK, - BBIF1_FLOW_MARK, BB_RX_FLOW_N_MARK, - - /* BBIF2 */ - BBIF2_TSCK1_MARK, BBIF2_TSYNC1_MARK, - BBIF2_TXD1_MARK, BBIF2_RXD_MARK, - - /* FSI */ - FSIACK_MARK, FSIBCK_MARK, FSIAILR_MARK, FSIAIBT_MARK, - FSIAISLD_MARK, FSIAOMC_MARK, FSIAOLR_MARK, FSIAOBT_MARK, - FSIAOSLD_MARK, FSIASPDIF_11_MARK, FSIASPDIF_15_MARK, - - /* FMSI */ - FMSOCK_MARK, FMSOOLR_MARK, FMSIOLR_MARK, FMSOOBT_MARK, - FMSIOBT_MARK, FMSOSLD_MARK, FMSOILR_MARK, FMSIILR_MARK, - FMSOIBT_MARK, FMSIIBT_MARK, FMSISLD_MARK, FMSICK_MARK, - - /* SCIFA0 */ - SCIFA0_TXD_MARK, SCIFA0_RXD_MARK, SCIFA0_SCK_MARK, - SCIFA0_RTS_MARK, SCIFA0_CTS_MARK, - - /* SCIFA1 */ - SCIFA1_TXD_MARK, SCIFA1_RXD_MARK, SCIFA1_SCK_MARK, - SCIFA1_RTS_MARK, SCIFA1_CTS_MARK, - - /* SCIFA2 */ - SCIFA2_CTS1_MARK, SCIFA2_RTS1_MARK, SCIFA2_TXD1_MARK, - SCIFA2_RXD1_MARK, SCIFA2_SCK1_MARK, - - /* SCIFA3 */ - SCIFA3_CTS_43_MARK, SCIFA3_CTS_140_MARK, SCIFA3_RTS_44_MARK, - SCIFA3_RTS_141_MARK, SCIFA3_SCK_MARK, SCIFA3_TXD_MARK, - SCIFA3_RXD_MARK, - - /* SCIFA4 */ - SCIFA4_RXD_MARK, SCIFA4_TXD_MARK, - - /* SCIFA5 */ - SCIFA5_RXD_MARK, SCIFA5_TXD_MARK, - - /* SCIFB */ - SCIFB_SCK_MARK, SCIFB_RTS_MARK, SCIFB_CTS_MARK, - SCIFB_TXD_MARK, SCIFB_RXD_MARK, - - /* CEU */ - VIO_HD_MARK, VIO_CKO1_MARK, VIO_CKO2_MARK, VIO_VD_MARK, - VIO_CLK_MARK, VIO_FIELD_MARK, VIO_CKO_MARK, - VIO_D0_MARK, VIO_D1_MARK, VIO_D2_MARK, VIO_D3_MARK, - VIO_D4_MARK, VIO_D5_MARK, VIO_D6_MARK, VIO_D7_MARK, - VIO_D8_MARK, VIO_D9_MARK, VIO_D10_MARK, VIO_D11_MARK, - VIO_D12_MARK, VIO_D13_MARK, VIO_D14_MARK, VIO_D15_MARK, - - /* USB0 */ - IDIN_0_MARK, EXTLP_0_MARK, OVCN2_0_MARK, PWEN_0_MARK, - OVCN_0_MARK, VBUS0_0_MARK, - - /* USB1 */ - IDIN_1_18_MARK, IDIN_1_113_MARK, - PWEN_1_115_MARK, PWEN_1_138_MARK, - OVCN_1_114_MARK, OVCN_1_162_MARK, - EXTLP_1_MARK, OVCN2_1_MARK, - VBUS0_1_MARK, - - /* GPIO */ - GPI0_MARK, GPI1_MARK, GPO0_MARK, GPO1_MARK, - - /* BSC */ - BS_MARK, WE1_MARK, - CKO_MARK, WAIT_MARK, RDWR_MARK, - - A0_MARK, A1_MARK, A2_MARK, A3_MARK, - A6_MARK, A7_MARK, A8_MARK, A9_MARK, - A10_MARK, A11_MARK, A12_MARK, A13_MARK, - A14_MARK, A15_MARK, A16_MARK, A17_MARK, - A18_MARK, A19_MARK, A20_MARK, A21_MARK, - A22_MARK, A23_MARK, A24_MARK, A25_MARK, - A26_MARK, - - CS0_MARK, CS2_MARK, CS4_MARK, - CS5A_MARK, CS5B_MARK, CS6A_MARK, - - /* BSC/FLCTL */ - RD_FSC_MARK, WE0_FWE_MARK, A4_FOE_MARK, A5_FCDE_MARK, - D0_NAF0_MARK, D1_NAF1_MARK, D2_NAF2_MARK, D3_NAF3_MARK, - D4_NAF4_MARK, D5_NAF5_MARK, D6_NAF6_MARK, D7_NAF7_MARK, - D8_NAF8_MARK, D9_NAF9_MARK, D10_NAF10_MARK, D11_NAF11_MARK, - D12_NAF12_MARK, D13_NAF13_MARK, D14_NAF14_MARK, D15_NAF15_MARK, - - /* MMCIF(1) */ - MMCD0_0_MARK, MMCD0_1_MARK, MMCD0_2_MARK, MMCD0_3_MARK, - MMCD0_4_MARK, MMCD0_5_MARK, MMCD0_6_MARK, MMCD0_7_MARK, - MMCCMD0_MARK, MMCCLK0_MARK, - - /* MMCIF(2) */ - MMCD1_0_MARK, MMCD1_1_MARK, MMCD1_2_MARK, MMCD1_3_MARK, - MMCD1_4_MARK, MMCD1_5_MARK, MMCD1_6_MARK, MMCD1_7_MARK, - MMCCLK1_MARK, MMCCMD1_MARK, - - /* SPU2 */ - VINT_I_MARK, - - /* FLCTL */ - FCE1_MARK, FCE0_MARK, FRB_MARK, - - /* HSI */ - GP_RX_FLAG_MARK, GP_RX_DATA_MARK, GP_TX_READY_MARK, - GP_RX_WAKE_MARK, MP_TX_FLAG_MARK, MP_TX_DATA_MARK, - MP_RX_READY_MARK, MP_TX_WAKE_MARK, - - /* MFI */ - MFIv6_MARK, - MFIv4_MARK, - - MEMC_CS0_MARK, MEMC_BUSCLK_MEMC_A0_MARK, - MEMC_CS1_MEMC_A1_MARK, MEMC_ADV_MEMC_DREQ0_MARK, - MEMC_WAIT_MEMC_DREQ1_MARK, MEMC_NOE_MARK, - MEMC_NWE_MARK, MEMC_INT_MARK, - - MEMC_AD0_MARK, MEMC_AD1_MARK, MEMC_AD2_MARK, - MEMC_AD3_MARK, MEMC_AD4_MARK, MEMC_AD5_MARK, - MEMC_AD6_MARK, MEMC_AD7_MARK, MEMC_AD8_MARK, - MEMC_AD9_MARK, MEMC_AD10_MARK, MEMC_AD11_MARK, - MEMC_AD12_MARK, MEMC_AD13_MARK, MEMC_AD14_MARK, - MEMC_AD15_MARK, - - /* SIM */ - SIM_RST_MARK, SIM_CLK_MARK, SIM_D_MARK, - - /* TPU */ - TPU0TO0_MARK, TPU0TO1_MARK, - TPU0TO2_93_MARK, TPU0TO2_99_MARK, - TPU0TO3_MARK, - - /* I2C2 */ - I2C_SCL2_MARK, I2C_SDA2_MARK, - - /* I2C3(1) */ - I2C_SCL3_MARK, I2C_SDA3_MARK, - - /* I2C3(2) */ - I2C_SCL3S_MARK, I2C_SDA3S_MARK, - - /* I2C4(2) */ - I2C_SCL4_MARK, I2C_SDA4_MARK, - - /* I2C4(2) */ - I2C_SCL4S_MARK, I2C_SDA4S_MARK, - - /* KEYSC */ - KEYOUT0_MARK, KEYIN0_121_MARK, KEYIN0_136_MARK, - KEYOUT1_MARK, KEYIN1_122_MARK, KEYIN1_135_MARK, - KEYOUT2_MARK, KEYIN2_123_MARK, KEYIN2_134_MARK, - KEYOUT3_MARK, KEYIN3_124_MARK, KEYIN3_133_MARK, - KEYOUT4_MARK, KEYIN4_MARK, - KEYOUT5_MARK, KEYIN5_MARK, - KEYOUT6_MARK, KEYIN6_MARK, - KEYOUT7_MARK, KEYIN7_MARK, - - /* LCDC */ - LCDC0_SELECT_MARK, - LCDC1_SELECT_MARK, - LCDHSYN_MARK, LCDCS_MARK, LCDVSYN_MARK, LCDDCK_MARK, - LCDWR_MARK, LCDRD_MARK, LCDDISP_MARK, LCDRS_MARK, - LCDLCLK_MARK, LCDDON_MARK, - - LCDD0_MARK, LCDD1_MARK, LCDD2_MARK, LCDD3_MARK, - LCDD4_MARK, LCDD5_MARK, LCDD6_MARK, LCDD7_MARK, - LCDD8_MARK, LCDD9_MARK, LCDD10_MARK, LCDD11_MARK, - LCDD12_MARK, LCDD13_MARK, LCDD14_MARK, LCDD15_MARK, - LCDD16_MARK, LCDD17_MARK, LCDD18_MARK, LCDD19_MARK, - LCDD20_MARK, LCDD21_MARK, LCDD22_MARK, LCDD23_MARK, - - /* IRDA */ - IRDA_OUT_MARK, IRDA_IN_MARK, IRDA_FIRSEL_MARK, - IROUT_139_MARK, IROUT_140_MARK, - - /* TSIF1 */ - TS0_1SELECT_MARK, - TS0_2SELECT_MARK, - TS1_1SELECT_MARK, - TS1_2SELECT_MARK, - - TS_SPSYNC1_MARK, TS_SDAT1_MARK, - TS_SDEN1_MARK, TS_SCK1_MARK, - - /* TSIF2 */ - TS_SPSYNC2_MARK, TS_SDAT2_MARK, - TS_SDEN2_MARK, TS_SCK2_MARK, - - /* HDMI */ - HDMI_HPD_MARK, HDMI_CEC_MARK, - - /* SDHI0 */ - SDHICLK0_MARK, SDHICD0_MARK, - SDHICMD0_MARK, SDHIWP0_MARK, - SDHID0_0_MARK, SDHID0_1_MARK, - SDHID0_2_MARK, SDHID0_3_MARK, - - /* SDHI1 */ - SDHICLK1_MARK, SDHICMD1_MARK, SDHID1_0_MARK, - SDHID1_1_MARK, SDHID1_2_MARK, SDHID1_3_MARK, - - /* SDHI2 */ - SDHICLK2_MARK, SDHICMD2_MARK, SDHID2_0_MARK, - SDHID2_1_MARK, SDHID2_2_MARK, SDHID2_3_MARK, - - /* SDENC */ - SDENC_CPG_MARK, - SDENC_DV_CLKI_MARK, - - PINMUX_MARK_END, -}; - -static const u16 pinmux_data[] = { - PINMUX_DATA_ALL(), - - /* IRQ */ - PINMUX_DATA(IRQ0_6_MARK, PORT6_FN0, MSEL1CR_0_0), - PINMUX_DATA(IRQ0_162_MARK, PORT162_FN0, MSEL1CR_0_1), - PINMUX_DATA(IRQ1_MARK, PORT12_FN0), - PINMUX_DATA(IRQ2_4_MARK, PORT4_FN0, MSEL1CR_2_0), - PINMUX_DATA(IRQ2_5_MARK, PORT5_FN0, MSEL1CR_2_1), - PINMUX_DATA(IRQ3_8_MARK, PORT8_FN0, MSEL1CR_3_0), - PINMUX_DATA(IRQ3_16_MARK, PORT16_FN0, MSEL1CR_3_1), - PINMUX_DATA(IRQ4_17_MARK, PORT17_FN0, MSEL1CR_4_0), - PINMUX_DATA(IRQ4_163_MARK, PORT163_FN0, MSEL1CR_4_1), - PINMUX_DATA(IRQ5_MARK, PORT18_FN0), - PINMUX_DATA(IRQ6_39_MARK, PORT39_FN0, MSEL1CR_6_0), - PINMUX_DATA(IRQ6_164_MARK, PORT164_FN0, MSEL1CR_6_1), - PINMUX_DATA(IRQ7_40_MARK, PORT40_FN0, MSEL1CR_7_1), - PINMUX_DATA(IRQ7_167_MARK, PORT167_FN0, MSEL1CR_7_0), - PINMUX_DATA(IRQ8_41_MARK, PORT41_FN0, MSEL1CR_8_1), - PINMUX_DATA(IRQ8_168_MARK, PORT168_FN0, MSEL1CR_8_0), - PINMUX_DATA(IRQ9_42_MARK, PORT42_FN0, MSEL1CR_9_0), - PINMUX_DATA(IRQ9_169_MARK, PORT169_FN0, MSEL1CR_9_1), - PINMUX_DATA(IRQ10_MARK, PORT65_FN0, MSEL1CR_9_1), - PINMUX_DATA(IRQ11_MARK, PORT67_FN0), - PINMUX_DATA(IRQ12_80_MARK, PORT80_FN0, MSEL1CR_12_0), - PINMUX_DATA(IRQ12_137_MARK, PORT137_FN0, MSEL1CR_12_1), - PINMUX_DATA(IRQ13_81_MARK, PORT81_FN0, MSEL1CR_13_0), - PINMUX_DATA(IRQ13_145_MARK, PORT145_FN0, MSEL1CR_13_1), - PINMUX_DATA(IRQ14_82_MARK, PORT82_FN0, MSEL1CR_14_0), - PINMUX_DATA(IRQ14_146_MARK, PORT146_FN0, MSEL1CR_14_1), - PINMUX_DATA(IRQ15_83_MARK, PORT83_FN0, MSEL1CR_15_0), - PINMUX_DATA(IRQ15_147_MARK, PORT147_FN0, MSEL1CR_15_1), - PINMUX_DATA(IRQ16_84_MARK, PORT84_FN0, MSEL1CR_16_0), - PINMUX_DATA(IRQ16_170_MARK, PORT170_FN0, MSEL1CR_16_1), - PINMUX_DATA(IRQ17_MARK, PORT85_FN0), - PINMUX_DATA(IRQ18_MARK, PORT86_FN0), - PINMUX_DATA(IRQ19_MARK, PORT87_FN0), - PINMUX_DATA(IRQ20_MARK, PORT92_FN0), - PINMUX_DATA(IRQ21_MARK, PORT93_FN0), - PINMUX_DATA(IRQ22_MARK, PORT94_FN0), - PINMUX_DATA(IRQ23_MARK, PORT95_FN0), - PINMUX_DATA(IRQ24_MARK, PORT112_FN0), - PINMUX_DATA(IRQ25_MARK, PORT119_FN0), - PINMUX_DATA(IRQ26_121_MARK, PORT121_FN0, MSEL1CR_26_1), - PINMUX_DATA(IRQ26_172_MARK, PORT172_FN0, MSEL1CR_26_0), - PINMUX_DATA(IRQ27_122_MARK, PORT122_FN0, MSEL1CR_27_1), - PINMUX_DATA(IRQ27_180_MARK, PORT180_FN0, MSEL1CR_27_0), - PINMUX_DATA(IRQ28_123_MARK, PORT123_FN0, MSEL1CR_28_1), - PINMUX_DATA(IRQ28_181_MARK, PORT181_FN0, MSEL1CR_28_0), - PINMUX_DATA(IRQ29_129_MARK, PORT129_FN0, MSEL1CR_29_1), - PINMUX_DATA(IRQ29_182_MARK, PORT182_FN0, MSEL1CR_29_0), - PINMUX_DATA(IRQ30_130_MARK, PORT130_FN0, MSEL1CR_30_1), - PINMUX_DATA(IRQ30_183_MARK, PORT183_FN0, MSEL1CR_30_0), - PINMUX_DATA(IRQ31_138_MARK, PORT138_FN0, MSEL1CR_31_1), - PINMUX_DATA(IRQ31_184_MARK, PORT184_FN0, MSEL1CR_31_0), - - /* Function 1 */ - PINMUX_DATA(BBIF2_TSCK1_MARK, PORT0_FN1), - PINMUX_DATA(BBIF2_TSYNC1_MARK, PORT1_FN1), - PINMUX_DATA(BBIF2_TXD1_MARK, PORT2_FN1), - PINMUX_DATA(BBIF2_RXD_MARK, PORT3_FN1), - PINMUX_DATA(FSIACK_MARK, PORT4_FN1), - PINMUX_DATA(FSIAILR_MARK, PORT5_FN1), - PINMUX_DATA(FSIAIBT_MARK, PORT6_FN1), - PINMUX_DATA(FSIAISLD_MARK, PORT7_FN1), - PINMUX_DATA(FSIAOMC_MARK, PORT8_FN1), - PINMUX_DATA(FSIAOLR_MARK, PORT9_FN1), - PINMUX_DATA(FSIAOBT_MARK, PORT10_FN1), - PINMUX_DATA(FSIAOSLD_MARK, PORT11_FN1), - PINMUX_DATA(FMSOCK_MARK, PORT12_FN1), - PINMUX_DATA(FMSOOLR_MARK, PORT13_FN1), - PINMUX_DATA(FMSOOBT_MARK, PORT14_FN1), - PINMUX_DATA(FMSOSLD_MARK, PORT15_FN1), - PINMUX_DATA(FMSOILR_MARK, PORT16_FN1), - PINMUX_DATA(FMSOIBT_MARK, PORT17_FN1), - PINMUX_DATA(FMSISLD_MARK, PORT18_FN1), - PINMUX_DATA(A0_MARK, PORT19_FN1), - PINMUX_DATA(A1_MARK, PORT20_FN1), - PINMUX_DATA(A2_MARK, PORT21_FN1), - PINMUX_DATA(A3_MARK, PORT22_FN1), - PINMUX_DATA(A4_FOE_MARK, PORT23_FN1), - PINMUX_DATA(A5_FCDE_MARK, PORT24_FN1), - PINMUX_DATA(A6_MARK, PORT25_FN1), - PINMUX_DATA(A7_MARK, PORT26_FN1), - PINMUX_DATA(A8_MARK, PORT27_FN1), - PINMUX_DATA(A9_MARK, PORT28_FN1), - PINMUX_DATA(A10_MARK, PORT29_FN1), - PINMUX_DATA(A11_MARK, PORT30_FN1), - PINMUX_DATA(A12_MARK, PORT31_FN1), - PINMUX_DATA(A13_MARK, PORT32_FN1), - PINMUX_DATA(A14_MARK, PORT33_FN1), - PINMUX_DATA(A15_MARK, PORT34_FN1), - PINMUX_DATA(A16_MARK, PORT35_FN1), - PINMUX_DATA(A17_MARK, PORT36_FN1), - PINMUX_DATA(A18_MARK, PORT37_FN1), - PINMUX_DATA(A19_MARK, PORT38_FN1), - PINMUX_DATA(A20_MARK, PORT39_FN1), - PINMUX_DATA(A21_MARK, PORT40_FN1), - PINMUX_DATA(A22_MARK, PORT41_FN1), - PINMUX_DATA(A23_MARK, PORT42_FN1), - PINMUX_DATA(A24_MARK, PORT43_FN1), - PINMUX_DATA(A25_MARK, PORT44_FN1), - PINMUX_DATA(A26_MARK, PORT45_FN1), - PINMUX_DATA(D0_NAF0_MARK, PORT46_FN1), - PINMUX_DATA(D1_NAF1_MARK, PORT47_FN1), - PINMUX_DATA(D2_NAF2_MARK, PORT48_FN1), - PINMUX_DATA(D3_NAF3_MARK, PORT49_FN1), - PINMUX_DATA(D4_NAF4_MARK, PORT50_FN1), - PINMUX_DATA(D5_NAF5_MARK, PORT51_FN1), - PINMUX_DATA(D6_NAF6_MARK, PORT52_FN1), - PINMUX_DATA(D7_NAF7_MARK, PORT53_FN1), - PINMUX_DATA(D8_NAF8_MARK, PORT54_FN1), - PINMUX_DATA(D9_NAF9_MARK, PORT55_FN1), - PINMUX_DATA(D10_NAF10_MARK, PORT56_FN1), - PINMUX_DATA(D11_NAF11_MARK, PORT57_FN1), - PINMUX_DATA(D12_NAF12_MARK, PORT58_FN1), - PINMUX_DATA(D13_NAF13_MARK, PORT59_FN1), - PINMUX_DATA(D14_NAF14_MARK, PORT60_FN1), - PINMUX_DATA(D15_NAF15_MARK, PORT61_FN1), - PINMUX_DATA(CS0_MARK, PORT62_FN1), - PINMUX_DATA(CS2_MARK, PORT63_FN1), - PINMUX_DATA(CS4_MARK, PORT64_FN1), - PINMUX_DATA(CS5A_MARK, PORT65_FN1), - PINMUX_DATA(CS5B_MARK, PORT66_FN1), - PINMUX_DATA(CS6A_MARK, PORT67_FN1), - PINMUX_DATA(FCE0_MARK, PORT68_FN1), - PINMUX_DATA(RD_FSC_MARK, PORT69_FN1), - PINMUX_DATA(WE0_FWE_MARK, PORT70_FN1), - PINMUX_DATA(WE1_MARK, PORT71_FN1), - PINMUX_DATA(CKO_MARK, PORT72_FN1), - PINMUX_DATA(FRB_MARK, PORT73_FN1), - PINMUX_DATA(WAIT_MARK, PORT74_FN1), - PINMUX_DATA(RDWR_MARK, PORT75_FN1), - PINMUX_DATA(MEMC_AD0_MARK, PORT76_FN1), - PINMUX_DATA(MEMC_AD1_MARK, PORT77_FN1), - PINMUX_DATA(MEMC_AD2_MARK, PORT78_FN1), - PINMUX_DATA(MEMC_AD3_MARK, PORT79_FN1), - PINMUX_DATA(MEMC_AD4_MARK, PORT80_FN1), - PINMUX_DATA(MEMC_AD5_MARK, PORT81_FN1), - PINMUX_DATA(MEMC_AD6_MARK, PORT82_FN1), - PINMUX_DATA(MEMC_AD7_MARK, PORT83_FN1), - PINMUX_DATA(MEMC_AD8_MARK, PORT84_FN1), - PINMUX_DATA(MEMC_AD9_MARK, PORT85_FN1), - PINMUX_DATA(MEMC_AD10_MARK, PORT86_FN1), - PINMUX_DATA(MEMC_AD11_MARK, PORT87_FN1), - PINMUX_DATA(MEMC_AD12_MARK, PORT88_FN1), - PINMUX_DATA(MEMC_AD13_MARK, PORT89_FN1), - PINMUX_DATA(MEMC_AD14_MARK, PORT90_FN1), - PINMUX_DATA(MEMC_AD15_MARK, PORT91_FN1), - PINMUX_DATA(MEMC_CS0_MARK, PORT92_FN1), - PINMUX_DATA(MEMC_BUSCLK_MEMC_A0_MARK, PORT93_FN1), - PINMUX_DATA(MEMC_CS1_MEMC_A1_MARK, PORT94_FN1), - PINMUX_DATA(MEMC_ADV_MEMC_DREQ0_MARK, PORT95_FN1), - PINMUX_DATA(MEMC_WAIT_MEMC_DREQ1_MARK, PORT96_FN1), - PINMUX_DATA(MEMC_NOE_MARK, PORT97_FN1), - PINMUX_DATA(MEMC_NWE_MARK, PORT98_FN1), - PINMUX_DATA(MEMC_INT_MARK, PORT99_FN1), - PINMUX_DATA(VIO_VD_MARK, PORT100_FN1), - PINMUX_DATA(VIO_HD_MARK, PORT101_FN1), - PINMUX_DATA(VIO_D0_MARK, PORT102_FN1), - PINMUX_DATA(VIO_D1_MARK, PORT103_FN1), - PINMUX_DATA(VIO_D2_MARK, PORT104_FN1), - PINMUX_DATA(VIO_D3_MARK, PORT105_FN1), - PINMUX_DATA(VIO_D4_MARK, PORT106_FN1), - PINMUX_DATA(VIO_D5_MARK, PORT107_FN1), - PINMUX_DATA(VIO_D6_MARK, PORT108_FN1), - PINMUX_DATA(VIO_D7_MARK, PORT109_FN1), - PINMUX_DATA(VIO_D8_MARK, PORT110_FN1), - PINMUX_DATA(VIO_D9_MARK, PORT111_FN1), - PINMUX_DATA(VIO_D10_MARK, PORT112_FN1), - PINMUX_DATA(VIO_D11_MARK, PORT113_FN1), - PINMUX_DATA(VIO_D12_MARK, PORT114_FN1), - PINMUX_DATA(VIO_D13_MARK, PORT115_FN1), - PINMUX_DATA(VIO_D14_MARK, PORT116_FN1), - PINMUX_DATA(VIO_D15_MARK, PORT117_FN1), - PINMUX_DATA(VIO_CLK_MARK, PORT118_FN1), - PINMUX_DATA(VIO_FIELD_MARK, PORT119_FN1), - PINMUX_DATA(VIO_CKO_MARK, PORT120_FN1), - PINMUX_DATA(LCDD0_MARK, PORT121_FN1), - PINMUX_DATA(LCDD1_MARK, PORT122_FN1), - PINMUX_DATA(LCDD2_MARK, PORT123_FN1), - PINMUX_DATA(LCDD3_MARK, PORT124_FN1), - PINMUX_DATA(LCDD4_MARK, PORT125_FN1), - PINMUX_DATA(LCDD5_MARK, PORT126_FN1), - PINMUX_DATA(LCDD6_MARK, PORT127_FN1), - PINMUX_DATA(LCDD7_MARK, PORT128_FN1), - PINMUX_DATA(LCDD8_MARK, PORT129_FN1), - PINMUX_DATA(LCDD9_MARK, PORT130_FN1), - PINMUX_DATA(LCDD10_MARK, PORT131_FN1), - PINMUX_DATA(LCDD11_MARK, PORT132_FN1), - PINMUX_DATA(LCDD12_MARK, PORT133_FN1), - PINMUX_DATA(LCDD13_MARK, PORT134_FN1), - PINMUX_DATA(LCDD14_MARK, PORT135_FN1), - PINMUX_DATA(LCDD15_MARK, PORT136_FN1), - PINMUX_DATA(LCDD16_MARK, PORT137_FN1), - PINMUX_DATA(LCDD17_MARK, PORT138_FN1), - PINMUX_DATA(LCDD18_MARK, PORT139_FN1), - PINMUX_DATA(LCDD19_MARK, PORT140_FN1), - PINMUX_DATA(LCDD20_MARK, PORT141_FN1), - PINMUX_DATA(LCDD21_MARK, PORT142_FN1), - PINMUX_DATA(LCDD22_MARK, PORT143_FN1), - PINMUX_DATA(LCDD23_MARK, PORT144_FN1), - PINMUX_DATA(LCDHSYN_MARK, PORT145_FN1), - PINMUX_DATA(LCDVSYN_MARK, PORT146_FN1), - PINMUX_DATA(LCDDCK_MARK, PORT147_FN1), - PINMUX_DATA(LCDRD_MARK, PORT148_FN1), - PINMUX_DATA(LCDDISP_MARK, PORT149_FN1), - PINMUX_DATA(LCDLCLK_MARK, PORT150_FN1), - PINMUX_DATA(LCDDON_MARK, PORT151_FN1), - PINMUX_DATA(SCIFA0_TXD_MARK, PORT152_FN1), - PINMUX_DATA(SCIFA0_RXD_MARK, PORT153_FN1), - PINMUX_DATA(SCIFA1_TXD_MARK, PORT154_FN1), - PINMUX_DATA(SCIFA1_RXD_MARK, PORT155_FN1), - PINMUX_DATA(TS_SPSYNC1_MARK, PORT156_FN1), - PINMUX_DATA(TS_SDAT1_MARK, PORT157_FN1), - PINMUX_DATA(TS_SDEN1_MARK, PORT158_FN1), - PINMUX_DATA(TS_SCK1_MARK, PORT159_FN1), - PINMUX_DATA(TPU0TO0_MARK, PORT160_FN1), - PINMUX_DATA(TPU0TO1_MARK, PORT161_FN1), - PINMUX_DATA(SCIFB_SCK_MARK, PORT162_FN1), - PINMUX_DATA(SCIFB_RTS_MARK, PORT163_FN1), - PINMUX_DATA(SCIFB_CTS_MARK, PORT164_FN1), - PINMUX_DATA(SCIFB_TXD_MARK, PORT165_FN1), - PINMUX_DATA(SCIFB_RXD_MARK, PORT166_FN1), - PINMUX_DATA(VBUS0_0_MARK, PORT167_FN1), - PINMUX_DATA(VBUS0_1_MARK, PORT168_FN1), - PINMUX_DATA(HDMI_HPD_MARK, PORT169_FN1), - PINMUX_DATA(HDMI_CEC_MARK, PORT170_FN1), - PINMUX_DATA(SDHICLK0_MARK, PORT171_FN1), - PINMUX_DATA(SDHICD0_MARK, PORT172_FN1), - PINMUX_DATA(SDHID0_0_MARK, PORT173_FN1), - PINMUX_DATA(SDHID0_1_MARK, PORT174_FN1), - PINMUX_DATA(SDHID0_2_MARK, PORT175_FN1), - PINMUX_DATA(SDHID0_3_MARK, PORT176_FN1), - PINMUX_DATA(SDHICMD0_MARK, PORT177_FN1), - PINMUX_DATA(SDHIWP0_MARK, PORT178_FN1), - PINMUX_DATA(SDHICLK1_MARK, PORT179_FN1), - PINMUX_DATA(SDHID1_0_MARK, PORT180_FN1), - PINMUX_DATA(SDHID1_1_MARK, PORT181_FN1), - PINMUX_DATA(SDHID1_2_MARK, PORT182_FN1), - PINMUX_DATA(SDHID1_3_MARK, PORT183_FN1), - PINMUX_DATA(SDHICMD1_MARK, PORT184_FN1), - PINMUX_DATA(SDHICLK2_MARK, PORT185_FN1), - PINMUX_DATA(SDHID2_0_MARK, PORT186_FN1), - PINMUX_DATA(SDHID2_1_MARK, PORT187_FN1), - PINMUX_DATA(SDHID2_2_MARK, PORT188_FN1), - PINMUX_DATA(SDHID2_3_MARK, PORT189_FN1), - PINMUX_DATA(SDHICMD2_MARK, PORT190_FN1), - - /* Function 2 */ - PINMUX_DATA(FSIBCK_MARK, PORT4_FN2), - PINMUX_DATA(SCIFA4_RXD_MARK, PORT5_FN2), - PINMUX_DATA(SCIFA4_TXD_MARK, PORT6_FN2), - PINMUX_DATA(SCIFA5_RXD_MARK, PORT8_FN2), - PINMUX_DATA(FSIASPDIF_11_MARK, PORT11_FN2), - PINMUX_DATA(SCIFA5_TXD_MARK, PORT12_FN2), - PINMUX_DATA(FMSIOLR_MARK, PORT13_FN2), - PINMUX_DATA(FMSIOBT_MARK, PORT14_FN2), - PINMUX_DATA(FSIASPDIF_15_MARK, PORT15_FN2), - PINMUX_DATA(FMSIILR_MARK, PORT16_FN2), - PINMUX_DATA(FMSIIBT_MARK, PORT17_FN2), - PINMUX_DATA(BS_MARK, PORT19_FN2), - PINMUX_DATA(MSIOF0_TSYNC_MARK, PORT36_FN2), - PINMUX_DATA(MSIOF0_TSCK_MARK, PORT37_FN2), - PINMUX_DATA(MSIOF0_RXD_MARK, PORT38_FN2), - PINMUX_DATA(MSIOF0_RSCK_MARK, PORT39_FN2), - PINMUX_DATA(MSIOF0_RSYNC_MARK, PORT40_FN2), - PINMUX_DATA(MSIOF0_MCK0_MARK, PORT41_FN2), - PINMUX_DATA(MSIOF0_MCK1_MARK, PORT42_FN2), - PINMUX_DATA(MSIOF0_SS1_MARK, PORT43_FN2), - PINMUX_DATA(MSIOF0_SS2_MARK, PORT44_FN2), - PINMUX_DATA(MSIOF0_TXD_MARK, PORT45_FN2), - PINMUX_DATA(FMSICK_MARK, PORT65_FN2), - PINMUX_DATA(FCE1_MARK, PORT66_FN2), - PINMUX_DATA(BBIF1_RXD_MARK, PORT76_FN2), - PINMUX_DATA(BBIF1_TSYNC_MARK, PORT77_FN2), - PINMUX_DATA(BBIF1_TSCK_MARK, PORT78_FN2), - PINMUX_DATA(BBIF1_TXD_MARK, PORT79_FN2), - PINMUX_DATA(BBIF1_RSCK_MARK, PORT80_FN2), - PINMUX_DATA(BBIF1_RSYNC_MARK, PORT81_FN2), - PINMUX_DATA(BBIF1_FLOW_MARK, PORT82_FN2), - PINMUX_DATA(BB_RX_FLOW_N_MARK, PORT83_FN2), - PINMUX_DATA(MSIOF1_RSCK_MARK, PORT84_FN2), - PINMUX_DATA(MSIOF1_RSYNC_MARK, PORT85_FN2), - PINMUX_DATA(MSIOF1_MCK0_MARK, PORT86_FN2), - PINMUX_DATA(MSIOF1_MCK1_MARK, PORT87_FN2), - PINMUX_DATA(MSIOF1_TSCK_88_MARK, PORT88_FN2, MSEL4CR_10_1), - PINMUX_DATA(MSIOF1_TSYNC_89_MARK, PORT89_FN2, MSEL4CR_10_1), - PINMUX_DATA(MSIOF1_TXD_90_MARK, PORT90_FN2, MSEL4CR_10_1), - PINMUX_DATA(MSIOF1_RXD_91_MARK, PORT91_FN2, MSEL4CR_10_1), - PINMUX_DATA(MSIOF1_SS1_92_MARK, PORT92_FN2, MSEL4CR_10_1), - PINMUX_DATA(MSIOF1_SS2_93_MARK, PORT93_FN2, MSEL4CR_10_1), - PINMUX_DATA(SCIFA2_CTS1_MARK, PORT94_FN2), - PINMUX_DATA(SCIFA2_RTS1_MARK, PORT95_FN2), - PINMUX_DATA(SCIFA2_TXD1_MARK, PORT96_FN2), - PINMUX_DATA(SCIFA2_RXD1_MARK, PORT97_FN2), - PINMUX_DATA(SCIFA2_SCK1_MARK, PORT98_FN2), - PINMUX_DATA(I2C_SCL2_MARK, PORT110_FN2), - PINMUX_DATA(I2C_SDA2_MARK, PORT111_FN2), - PINMUX_DATA(I2C_SCL3_MARK, PORT114_FN2, MSEL4CR_16_1), - PINMUX_DATA(I2C_SDA3_MARK, PORT115_FN2, MSEL4CR_16_1), - PINMUX_DATA(I2C_SCL4_MARK, PORT116_FN2, MSEL4CR_17_1), - PINMUX_DATA(I2C_SDA4_MARK, PORT117_FN2, MSEL4CR_17_1), - PINMUX_DATA(MSIOF2_RSCK_MARK, PORT134_FN2), - PINMUX_DATA(MSIOF2_RSYNC_MARK, PORT135_FN2), - PINMUX_DATA(MSIOF2_MCK0_MARK, PORT136_FN2), - PINMUX_DATA(MSIOF2_MCK1_MARK, PORT137_FN2), - PINMUX_DATA(MSIOF2_SS1_MARK, PORT138_FN2), - PINMUX_DATA(MSIOF2_SS2_MARK, PORT139_FN2), - PINMUX_DATA(SCIFA3_CTS_140_MARK, PORT140_FN2, MSEL3CR_9_1), - PINMUX_DATA(SCIFA3_RTS_141_MARK, PORT141_FN2), - PINMUX_DATA(SCIFA3_SCK_MARK, PORT142_FN2), - PINMUX_DATA(SCIFA3_TXD_MARK, PORT143_FN2), - PINMUX_DATA(SCIFA3_RXD_MARK, PORT144_FN2), - PINMUX_DATA(MSIOF2_TSYNC_MARK, PORT148_FN2), - PINMUX_DATA(MSIOF2_TSCK_MARK, PORT149_FN2), - PINMUX_DATA(MSIOF2_RXD_MARK, PORT150_FN2), - PINMUX_DATA(MSIOF2_TXD_MARK, PORT151_FN2), - PINMUX_DATA(SCIFA0_SCK_MARK, PORT156_FN2), - PINMUX_DATA(SCIFA0_RTS_MARK, PORT157_FN2), - PINMUX_DATA(SCIFA0_CTS_MARK, PORT158_FN2), - PINMUX_DATA(SCIFA1_SCK_MARK, PORT159_FN2), - PINMUX_DATA(SCIFA1_RTS_MARK, PORT160_FN2), - PINMUX_DATA(SCIFA1_CTS_MARK, PORT161_FN2), - - /* Function 3 */ - PINMUX_DATA(VIO_CKO1_MARK, PORT16_FN3), - PINMUX_DATA(VIO_CKO2_MARK, PORT17_FN3), - PINMUX_DATA(IDIN_1_18_MARK, PORT18_FN3, MSEL4CR_14_1), - PINMUX_DATA(MSIOF1_TSCK_39_MARK, PORT39_FN3, MSEL4CR_10_0), - PINMUX_DATA(MSIOF1_TSYNC_40_MARK, PORT40_FN3, MSEL4CR_10_0), - PINMUX_DATA(MSIOF1_TXD_41_MARK, PORT41_FN3, MSEL4CR_10_0), - PINMUX_DATA(MSIOF1_RXD_42_MARK, PORT42_FN3, MSEL4CR_10_0), - PINMUX_DATA(MSIOF1_SS1_43_MARK, PORT43_FN3, MSEL4CR_10_0), - PINMUX_DATA(MSIOF1_SS2_44_MARK, PORT44_FN3, MSEL4CR_10_0), - PINMUX_DATA(MMCD1_0_MARK, PORT54_FN3, MSEL4CR_15_1), - PINMUX_DATA(MMCD1_1_MARK, PORT55_FN3, MSEL4CR_15_1), - PINMUX_DATA(MMCD1_2_MARK, PORT56_FN3, MSEL4CR_15_1), - PINMUX_DATA(MMCD1_3_MARK, PORT57_FN3, MSEL4CR_15_1), - PINMUX_DATA(MMCD1_4_MARK, PORT58_FN3, MSEL4CR_15_1), - PINMUX_DATA(MMCD1_5_MARK, PORT59_FN3, MSEL4CR_15_1), - PINMUX_DATA(MMCD1_6_MARK, PORT60_FN3, MSEL4CR_15_1), - PINMUX_DATA(MMCD1_7_MARK, PORT61_FN3, MSEL4CR_15_1), - PINMUX_DATA(VINT_I_MARK, PORT65_FN3), - PINMUX_DATA(MMCCLK1_MARK, PORT66_FN3, MSEL4CR_15_1), - PINMUX_DATA(MMCCMD1_MARK, PORT67_FN3, MSEL4CR_15_1), - PINMUX_DATA(TPU0TO2_93_MARK, PORT93_FN3), - PINMUX_DATA(TPU0TO2_99_MARK, PORT99_FN3), - PINMUX_DATA(TPU0TO3_MARK, PORT112_FN3), - PINMUX_DATA(IDIN_0_MARK, PORT113_FN3), - PINMUX_DATA(EXTLP_0_MARK, PORT114_FN3), - PINMUX_DATA(OVCN2_0_MARK, PORT115_FN3), - PINMUX_DATA(PWEN_0_MARK, PORT116_FN3), - PINMUX_DATA(OVCN_0_MARK, PORT117_FN3), - PINMUX_DATA(KEYOUT7_MARK, PORT121_FN3), - PINMUX_DATA(KEYOUT6_MARK, PORT122_FN3), - PINMUX_DATA(KEYOUT5_MARK, PORT123_FN3), - PINMUX_DATA(KEYOUT4_MARK, PORT124_FN3), - PINMUX_DATA(KEYOUT3_MARK, PORT125_FN3), - PINMUX_DATA(KEYOUT2_MARK, PORT126_FN3), - PINMUX_DATA(KEYOUT1_MARK, PORT127_FN3), - PINMUX_DATA(KEYOUT0_MARK, PORT128_FN3), - PINMUX_DATA(KEYIN7_MARK, PORT129_FN3), - PINMUX_DATA(KEYIN6_MARK, PORT130_FN3), - PINMUX_DATA(KEYIN5_MARK, PORT131_FN3), - PINMUX_DATA(KEYIN4_MARK, PORT132_FN3), - PINMUX_DATA(KEYIN3_133_MARK, PORT133_FN3, MSEL4CR_18_0), - PINMUX_DATA(KEYIN2_134_MARK, PORT134_FN3, MSEL4CR_18_0), - PINMUX_DATA(KEYIN1_135_MARK, PORT135_FN3, MSEL4CR_18_0), - PINMUX_DATA(KEYIN0_136_MARK, PORT136_FN3, MSEL4CR_18_0), - PINMUX_DATA(TS_SPSYNC2_MARK, PORT137_FN3), - PINMUX_DATA(IROUT_139_MARK, PORT139_FN3), - PINMUX_DATA(IRDA_OUT_MARK, PORT140_FN3), - PINMUX_DATA(IRDA_IN_MARK, PORT141_FN3), - PINMUX_DATA(IRDA_FIRSEL_MARK, PORT142_FN3), - PINMUX_DATA(TS_SDAT2_MARK, PORT145_FN3), - PINMUX_DATA(TS_SDEN2_MARK, PORT146_FN3), - PINMUX_DATA(TS_SCK2_MARK, PORT147_FN3), - - /* Function 4 */ - PINMUX_DATA(SCIFA3_CTS_43_MARK, PORT43_FN4, MSEL3CR_9_0), - PINMUX_DATA(SCIFA3_RTS_44_MARK, PORT44_FN4), - PINMUX_DATA(GP_RX_FLAG_MARK, PORT76_FN4), - PINMUX_DATA(GP_RX_DATA_MARK, PORT77_FN4), - PINMUX_DATA(GP_TX_READY_MARK, PORT78_FN4), - PINMUX_DATA(GP_RX_WAKE_MARK, PORT79_FN4), - PINMUX_DATA(MP_TX_FLAG_MARK, PORT80_FN4), - PINMUX_DATA(MP_TX_DATA_MARK, PORT81_FN4), - PINMUX_DATA(MP_RX_READY_MARK, PORT82_FN4), - PINMUX_DATA(MP_TX_WAKE_MARK, PORT83_FN4), - PINMUX_DATA(MMCD0_0_MARK, PORT84_FN4, MSEL4CR_15_0), - PINMUX_DATA(MMCD0_1_MARK, PORT85_FN4, MSEL4CR_15_0), - PINMUX_DATA(MMCD0_2_MARK, PORT86_FN4, MSEL4CR_15_0), - PINMUX_DATA(MMCD0_3_MARK, PORT87_FN4, MSEL4CR_15_0), - PINMUX_DATA(MMCD0_4_MARK, PORT88_FN4, MSEL4CR_15_0), - PINMUX_DATA(MMCD0_5_MARK, PORT89_FN4, MSEL4CR_15_0), - PINMUX_DATA(MMCD0_6_MARK, PORT90_FN4, MSEL4CR_15_0), - PINMUX_DATA(MMCD0_7_MARK, PORT91_FN4, MSEL4CR_15_0), - PINMUX_DATA(MMCCMD0_MARK, PORT92_FN4, MSEL4CR_15_0), - PINMUX_DATA(SIM_RST_MARK, PORT94_FN4), - PINMUX_DATA(SIM_CLK_MARK, PORT95_FN4), - PINMUX_DATA(SIM_D_MARK, PORT98_FN4), - PINMUX_DATA(MMCCLK0_MARK, PORT99_FN4, MSEL4CR_15_0), - PINMUX_DATA(IDIN_1_113_MARK, PORT113_FN4, MSEL4CR_14_0), - PINMUX_DATA(OVCN_1_114_MARK, PORT114_FN4, MSEL4CR_14_0), - PINMUX_DATA(PWEN_1_115_MARK, PORT115_FN4), - PINMUX_DATA(EXTLP_1_MARK, PORT116_FN4), - PINMUX_DATA(OVCN2_1_MARK, PORT117_FN4), - PINMUX_DATA(KEYIN0_121_MARK, PORT121_FN4, MSEL4CR_18_1), - PINMUX_DATA(KEYIN1_122_MARK, PORT122_FN4, MSEL4CR_18_1), - PINMUX_DATA(KEYIN2_123_MARK, PORT123_FN4, MSEL4CR_18_1), - PINMUX_DATA(KEYIN3_124_MARK, PORT124_FN4, MSEL4CR_18_1), - PINMUX_DATA(PWEN_1_138_MARK, PORT138_FN4), - PINMUX_DATA(IROUT_140_MARK, PORT140_FN4), - PINMUX_DATA(LCDCS_MARK, PORT145_FN4), - PINMUX_DATA(LCDWR_MARK, PORT147_FN4), - PINMUX_DATA(LCDRS_MARK, PORT149_FN4), - PINMUX_DATA(OVCN_1_162_MARK, PORT162_FN4, MSEL4CR_14_1), - - /* Function 5 */ - PINMUX_DATA(GPI0_MARK, PORT41_FN5), - PINMUX_DATA(GPI1_MARK, PORT42_FN5), - PINMUX_DATA(GPO0_MARK, PORT43_FN5), - PINMUX_DATA(GPO1_MARK, PORT44_FN5), - PINMUX_DATA(I2C_SCL3S_MARK, PORT137_FN5, MSEL4CR_16_0), - PINMUX_DATA(I2C_SDA3S_MARK, PORT145_FN5, MSEL4CR_16_0), - PINMUX_DATA(I2C_SCL4S_MARK, PORT146_FN5, MSEL4CR_17_0), - PINMUX_DATA(I2C_SDA4S_MARK, PORT147_FN5, MSEL4CR_17_0), - - /* Function select */ - PINMUX_DATA(LCDC0_SELECT_MARK, MSEL3CR_6_0), - PINMUX_DATA(LCDC1_SELECT_MARK, MSEL3CR_6_1), - - PINMUX_DATA(TS0_1SELECT_MARK, MSEL3CR_21_0, MSEL3CR_20_0), - PINMUX_DATA(TS0_2SELECT_MARK, MSEL3CR_21_0, MSEL3CR_20_1), - PINMUX_DATA(TS1_1SELECT_MARK, MSEL3CR_27_0, MSEL3CR_26_0), - PINMUX_DATA(TS1_2SELECT_MARK, MSEL3CR_27_0, MSEL3CR_26_1), - - PINMUX_DATA(SDENC_CPG_MARK, MSEL4CR_19_0), - PINMUX_DATA(SDENC_DV_CLKI_MARK, MSEL4CR_19_1), - - PINMUX_DATA(MFIv6_MARK, MSEL4CR_6_0), - PINMUX_DATA(MFIv4_MARK, MSEL4CR_6_1), -}; - -#define __I (SH_PFC_PIN_CFG_INPUT) -#define __O (SH_PFC_PIN_CFG_OUTPUT) -#define __IO (SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT) -#define __PD (SH_PFC_PIN_CFG_PULL_DOWN) -#define __PU (SH_PFC_PIN_CFG_PULL_UP) -#define __PUD (SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP) - -#define SH7372_PIN_I_PD(pin) SH_PFC_PIN_CFG(pin, __I | __PD) -#define SH7372_PIN_I_PU(pin) SH_PFC_PIN_CFG(pin, __I | __PU) -#define SH7372_PIN_I_PU_PD(pin) SH_PFC_PIN_CFG(pin, __I | __PUD) -#define SH7372_PIN_IO(pin) SH_PFC_PIN_CFG(pin, __IO) -#define SH7372_PIN_IO_PD(pin) SH_PFC_PIN_CFG(pin, __IO | __PD) -#define SH7372_PIN_IO_PU(pin) SH_PFC_PIN_CFG(pin, __IO | __PU) -#define SH7372_PIN_IO_PU_PD(pin) SH_PFC_PIN_CFG(pin, __IO | __PUD) -#define SH7372_PIN_O(pin) SH_PFC_PIN_CFG(pin, __O) -#define SH7372_PIN_O_PU_PD(pin) SH_PFC_PIN_CFG(pin, __O | __PUD) - -static const struct sh_pfc_pin pinmux_pins[] = { - /* Table 57-1 (I/O and Pull U/D) */ - SH7372_PIN_IO_PD(0), SH7372_PIN_IO_PD(1), - SH7372_PIN_O(2), SH7372_PIN_I_PD(3), - SH7372_PIN_I_PD(4), SH7372_PIN_I_PD(5), - SH7372_PIN_IO_PU_PD(6), SH7372_PIN_I_PD(7), - SH7372_PIN_IO_PD(8), SH7372_PIN_O(9), - SH7372_PIN_O(10), SH7372_PIN_O(11), - SH7372_PIN_IO_PU_PD(12), SH7372_PIN_IO_PD(13), - SH7372_PIN_IO_PD(14), SH7372_PIN_O(15), - SH7372_PIN_IO_PD(16), SH7372_PIN_IO_PD(17), - SH7372_PIN_I_PD(18), SH7372_PIN_IO(19), - SH7372_PIN_IO(20), SH7372_PIN_IO(21), - SH7372_PIN_IO(22), SH7372_PIN_IO(23), - SH7372_PIN_IO(24), SH7372_PIN_IO(25), - SH7372_PIN_IO(26), SH7372_PIN_IO(27), - SH7372_PIN_IO(28), SH7372_PIN_IO(29), - SH7372_PIN_IO(30), SH7372_PIN_IO(31), - SH7372_PIN_IO(32), SH7372_PIN_IO(33), - SH7372_PIN_IO(34), SH7372_PIN_IO(35), - SH7372_PIN_IO(36), SH7372_PIN_IO(37), - SH7372_PIN_IO(38), SH7372_PIN_IO(39), - SH7372_PIN_IO(40), SH7372_PIN_IO(41), - SH7372_PIN_IO(42), SH7372_PIN_IO(43), - SH7372_PIN_IO(44), SH7372_PIN_IO(45), - SH7372_PIN_IO_PU(46), SH7372_PIN_IO_PU(47), - SH7372_PIN_IO_PU(48), SH7372_PIN_IO_PU(49), - SH7372_PIN_IO_PU(50), SH7372_PIN_IO_PU(51), - SH7372_PIN_IO_PU(52), SH7372_PIN_IO_PU(53), - SH7372_PIN_IO_PU(54), SH7372_PIN_IO_PU(55), - SH7372_PIN_IO_PU(56), SH7372_PIN_IO_PU(57), - SH7372_PIN_IO_PU(58), SH7372_PIN_IO_PU(59), - SH7372_PIN_IO_PU(60), SH7372_PIN_IO_PU(61), - SH7372_PIN_IO(62), SH7372_PIN_O(63), - SH7372_PIN_O(64), SH7372_PIN_IO_PU(65), - SH7372_PIN_O_PU_PD(66), SH7372_PIN_IO_PU(67), - SH7372_PIN_O(68), SH7372_PIN_IO(69), - SH7372_PIN_IO(70), SH7372_PIN_IO(71), - SH7372_PIN_O(72), SH7372_PIN_I_PU(73), - SH7372_PIN_I_PU_PD(74), SH7372_PIN_IO_PU_PD(75), - SH7372_PIN_IO_PU_PD(76), SH7372_PIN_IO_PU_PD(77), - SH7372_PIN_IO_PU_PD(78), SH7372_PIN_IO_PU_PD(79), - SH7372_PIN_IO_PU_PD(80), SH7372_PIN_IO_PU_PD(81), - SH7372_PIN_IO_PU_PD(82), SH7372_PIN_IO_PU_PD(83), - SH7372_PIN_IO_PU_PD(84), SH7372_PIN_IO_PU_PD(85), - SH7372_PIN_IO_PU_PD(86), SH7372_PIN_IO_PU_PD(87), - SH7372_PIN_IO_PU_PD(88), SH7372_PIN_IO_PU_PD(89), - SH7372_PIN_IO_PU_PD(90), SH7372_PIN_IO_PU_PD(91), - SH7372_PIN_IO_PU_PD(92), SH7372_PIN_IO_PU_PD(93), - SH7372_PIN_IO_PU_PD(94), SH7372_PIN_IO_PU_PD(95), - SH7372_PIN_IO_PU(96), SH7372_PIN_IO_PU_PD(97), - SH7372_PIN_IO_PU_PD(98), SH7372_PIN_O_PU_PD(99), - SH7372_PIN_IO_PD(100), SH7372_PIN_IO_PD(101), - SH7372_PIN_IO_PD(102), SH7372_PIN_IO_PD(103), - SH7372_PIN_IO_PD(104), SH7372_PIN_IO_PD(105), - SH7372_PIN_IO_PU(106), SH7372_PIN_IO_PU(107), - SH7372_PIN_IO_PU(108), SH7372_PIN_IO_PU(109), - SH7372_PIN_IO_PU(110), SH7372_PIN_IO_PU(111), - SH7372_PIN_IO_PD(112), SH7372_PIN_IO_PD(113), - SH7372_PIN_IO_PU(114), SH7372_PIN_IO_PU(115), - SH7372_PIN_IO_PU(116), SH7372_PIN_IO_PU(117), - SH7372_PIN_IO_PU(118), SH7372_PIN_IO_PU(119), - SH7372_PIN_IO_PU(120), SH7372_PIN_IO_PD(121), - SH7372_PIN_IO_PD(122), SH7372_PIN_IO_PD(123), - SH7372_PIN_IO_PD(124), SH7372_PIN_IO_PD(125), - SH7372_PIN_IO_PD(126), SH7372_PIN_IO_PD(127), - SH7372_PIN_IO_PD(128), SH7372_PIN_IO_PU_PD(129), - SH7372_PIN_IO_PU_PD(130), SH7372_PIN_IO_PU_PD(131), - SH7372_PIN_IO_PU_PD(132), SH7372_PIN_IO_PU_PD(133), - SH7372_PIN_IO_PU_PD(134), SH7372_PIN_IO_PU_PD(135), - SH7372_PIN_IO_PD(136), SH7372_PIN_IO_PD(137), - SH7372_PIN_IO_PD(138), SH7372_PIN_IO_PD(139), - SH7372_PIN_IO_PD(140), SH7372_PIN_IO_PD(141), - SH7372_PIN_IO_PD(142), SH7372_PIN_IO_PU_PD(143), - SH7372_PIN_IO_PD(144), SH7372_PIN_IO_PD(145), - SH7372_PIN_IO_PD(146), SH7372_PIN_IO_PD(147), - SH7372_PIN_IO_PD(148), SH7372_PIN_IO_PD(149), - SH7372_PIN_IO_PD(150), SH7372_PIN_IO_PD(151), - SH7372_PIN_IO_PU_PD(152), SH7372_PIN_I_PD(153), - SH7372_PIN_IO_PU_PD(154), SH7372_PIN_I_PD(155), - SH7372_PIN_IO_PD(156), SH7372_PIN_IO_PD(157), - SH7372_PIN_I_PD(158), SH7372_PIN_IO_PD(159), - SH7372_PIN_O(160), SH7372_PIN_IO_PD(161), - SH7372_PIN_IO_PD(162), SH7372_PIN_IO_PD(163), - SH7372_PIN_I_PD(164), SH7372_PIN_IO_PD(165), - SH7372_PIN_I_PD(166), SH7372_PIN_I_PD(167), - SH7372_PIN_I_PD(168), SH7372_PIN_I_PD(169), - SH7372_PIN_I_PD(170), SH7372_PIN_O(171), - SH7372_PIN_IO_PU_PD(172), SH7372_PIN_IO_PU_PD(173), - SH7372_PIN_IO_PU_PD(174), SH7372_PIN_IO_PU_PD(175), - SH7372_PIN_IO_PU_PD(176), SH7372_PIN_IO_PU_PD(177), - SH7372_PIN_IO_PU_PD(178), SH7372_PIN_O(179), - SH7372_PIN_IO_PU_PD(180), SH7372_PIN_IO_PU_PD(181), - SH7372_PIN_IO_PU_PD(182), SH7372_PIN_IO_PU_PD(183), - SH7372_PIN_IO_PU_PD(184), SH7372_PIN_O(185), - SH7372_PIN_IO_PU_PD(186), SH7372_PIN_IO_PU_PD(187), - SH7372_PIN_IO_PU_PD(188), SH7372_PIN_IO_PU_PD(189), - SH7372_PIN_IO_PU_PD(190), -}; - -/* - BSC -------------------------------------------------------------------- */ -static const unsigned int bsc_data8_pins[] = { - /* D[0:7] */ - 46, 47, 48, 49, 50, 51, 52, 53, -}; -static const unsigned int bsc_data8_mux[] = { - D0_NAF0_MARK, D1_NAF1_MARK, D2_NAF2_MARK, D3_NAF3_MARK, - D4_NAF4_MARK, D5_NAF5_MARK, D6_NAF6_MARK, D7_NAF7_MARK, -}; -static const unsigned int bsc_data16_pins[] = { - /* D[0:15] */ - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -}; -static const unsigned int bsc_data16_mux[] = { - D0_NAF0_MARK, D1_NAF1_MARK, D2_NAF2_MARK, D3_NAF3_MARK, - D4_NAF4_MARK, D5_NAF5_MARK, D6_NAF6_MARK, D7_NAF7_MARK, - D8_NAF8_MARK, D9_NAF9_MARK, D10_NAF10_MARK, D11_NAF11_MARK, - D12_NAF12_MARK, D13_NAF13_MARK, D14_NAF14_MARK, D15_NAF15_MARK, -}; -static const unsigned int bsc_cs0_pins[] = { - /* CS */ - 62, -}; -static const unsigned int bsc_cs0_mux[] = { - CS0_MARK, -}; -static const unsigned int bsc_cs2_pins[] = { - /* CS */ - 63, -}; -static const unsigned int bsc_cs2_mux[] = { - CS2_MARK, -}; -static const unsigned int bsc_cs4_pins[] = { - /* CS */ - 64, -}; -static const unsigned int bsc_cs4_mux[] = { - CS4_MARK, -}; -static const unsigned int bsc_cs5a_pins[] = { - /* CS */ - 65, -}; -static const unsigned int bsc_cs5a_mux[] = { - CS5A_MARK, -}; -static const unsigned int bsc_cs5b_pins[] = { - /* CS */ - 66, -}; -static const unsigned int bsc_cs5b_mux[] = { - CS5B_MARK, -}; -static const unsigned int bsc_cs6a_pins[] = { - /* CS */ - 67, -}; -static const unsigned int bsc_cs6a_mux[] = { - CS6A_MARK, -}; -static const unsigned int bsc_rd_we8_pins[] = { - /* RD, WE[0] */ - 69, 70, -}; -static const unsigned int bsc_rd_we8_mux[] = { - RD_FSC_MARK, WE0_FWE_MARK, -}; -static const unsigned int bsc_rd_we16_pins[] = { - /* RD, WE[0:1] */ - 69, 70, 71, -}; -static const unsigned int bsc_rd_we16_mux[] = { - RD_FSC_MARK, WE0_FWE_MARK, WE1_MARK, -}; -static const unsigned int bsc_bs_pins[] = { - /* BS */ - 19, -}; -static const unsigned int bsc_bs_mux[] = { - BS_MARK, -}; -static const unsigned int bsc_rdwr_pins[] = { - /* RDWR */ - 75, -}; -static const unsigned int bsc_rdwr_mux[] = { - RDWR_MARK, -}; -static const unsigned int bsc_wait_pins[] = { - /* WAIT */ - 74, -}; -static const unsigned int bsc_wait_mux[] = { - WAIT_MARK, -}; -/* - CEU -------------------------------------------------------------------- */ -static const unsigned int ceu_data_0_7_pins[] = { - /* D[0:7] */ - 102, 103, 104, 105, 106, 107, 108, 109, -}; -static const unsigned int ceu_data_0_7_mux[] = { - VIO_D0_MARK, VIO_D1_MARK, VIO_D2_MARK, VIO_D3_MARK, - VIO_D4_MARK, VIO_D5_MARK, VIO_D6_MARK, VIO_D7_MARK, -}; -static const unsigned int ceu_data_8_15_pins[] = { - /* D[8:15] */ - 110, 111, 112, 113, 114, 115, 116, 117, -}; -static const unsigned int ceu_data_8_15_mux[] = { - VIO_D8_MARK, VIO_D9_MARK, VIO_D10_MARK, VIO_D11_MARK, - VIO_D12_MARK, VIO_D13_MARK, VIO_D14_MARK, VIO_D15_MARK, -}; -static const unsigned int ceu_clk_0_pins[] = { - /* CKO */ - 120, -}; -static const unsigned int ceu_clk_0_mux[] = { - VIO_CKO_MARK, -}; -static const unsigned int ceu_clk_1_pins[] = { - /* CKO */ - 16, -}; -static const unsigned int ceu_clk_1_mux[] = { - VIO_CKO1_MARK, -}; -static const unsigned int ceu_clk_2_pins[] = { - /* CKO */ - 17, -}; -static const unsigned int ceu_clk_2_mux[] = { - VIO_CKO2_MARK, -}; -static const unsigned int ceu_sync_pins[] = { - /* CLK, VD, HD */ - 118, 100, 101, -}; -static const unsigned int ceu_sync_mux[] = { - VIO_CLK_MARK, VIO_VD_MARK, VIO_HD_MARK, -}; -static const unsigned int ceu_field_pins[] = { - /* FIELD */ - 119, -}; -static const unsigned int ceu_field_mux[] = { - VIO_FIELD_MARK, -}; -/* - FLCTL ------------------------------------------------------------------ */ -static const unsigned int flctl_data_pins[] = { - /* NAF[0:15] */ - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -}; -static const unsigned int flctl_data_mux[] = { - D0_NAF0_MARK, D1_NAF1_MARK, D2_NAF2_MARK, D3_NAF3_MARK, - D4_NAF4_MARK, D5_NAF5_MARK, D6_NAF6_MARK, D7_NAF7_MARK, - D8_NAF8_MARK, D9_NAF9_MARK, D10_NAF10_MARK, D11_NAF11_MARK, - D12_NAF12_MARK, D13_NAF13_MARK, D14_NAF14_MARK, D15_NAF15_MARK, -}; -static const unsigned int flctl_ce0_pins[] = { - /* CE */ - 68, -}; -static const unsigned int flctl_ce0_mux[] = { - FCE0_MARK, -}; -static const unsigned int flctl_ce1_pins[] = { - /* CE */ - 66, -}; -static const unsigned int flctl_ce1_mux[] = { - FCE1_MARK, -}; -static const unsigned int flctl_ctrl_pins[] = { - /* FCDE, FOE, FSC, FWE, FRB */ - 24, 23, 69, 70, 73, -}; -static const unsigned int flctl_ctrl_mux[] = { - A5_FCDE_MARK, A4_FOE_MARK, RD_FSC_MARK, WE0_FWE_MARK, FRB_MARK, -}; -/* - FSIA ------------------------------------------------------------------- */ -static const unsigned int fsia_mclk_in_pins[] = { - /* CK */ - 4, -}; -static const unsigned int fsia_mclk_in_mux[] = { - FSIACK_MARK, -}; -static const unsigned int fsia_mclk_out_pins[] = { - /* OMC */ - 8, -}; -static const unsigned int fsia_mclk_out_mux[] = { - FSIAOMC_MARK, -}; -static const unsigned int fsia_sclk_in_pins[] = { - /* ILR, IBT */ - 5, 6, -}; -static const unsigned int fsia_sclk_in_mux[] = { - FSIAILR_MARK, FSIAIBT_MARK, -}; -static const unsigned int fsia_sclk_out_pins[] = { - /* OLR, OBT */ - 9, 10, -}; -static const unsigned int fsia_sclk_out_mux[] = { - FSIAOLR_MARK, FSIAOBT_MARK, -}; -static const unsigned int fsia_data_in_pins[] = { - /* ISLD */ - 7, -}; -static const unsigned int fsia_data_in_mux[] = { - FSIAISLD_MARK, -}; -static const unsigned int fsia_data_out_pins[] = { - /* OSLD */ - 11, -}; -static const unsigned int fsia_data_out_mux[] = { - FSIAOSLD_MARK, -}; -static const unsigned int fsia_spdif_0_pins[] = { - /* SPDIF */ - 11, -}; -static const unsigned int fsia_spdif_0_mux[] = { - FSIASPDIF_11_MARK, -}; -static const unsigned int fsia_spdif_1_pins[] = { - /* SPDIF */ - 15, -}; -static const unsigned int fsia_spdif_1_mux[] = { - FSIASPDIF_15_MARK, -}; -/* - FSIB ------------------------------------------------------------------- */ -static const unsigned int fsib_mclk_in_pins[] = { - /* CK */ - 4, -}; -static const unsigned int fsib_mclk_in_mux[] = { - FSIBCK_MARK, -}; -/* - HDMI ------------------------------------------------------------------- */ -static const unsigned int hdmi_pins[] = { - /* HPD, CEC */ - 169, 170, -}; -static const unsigned int hdmi_mux[] = { - HDMI_HPD_MARK, HDMI_CEC_MARK, -}; -/* - INTC ------------------------------------------------------------------- */ -IRQC_PINS_MUX(0, 6, 162); -IRQC_PIN_MUX(1, 12); -IRQC_PINS_MUX(2, 4, 5); -IRQC_PINS_MUX(3, 8, 16); -IRQC_PINS_MUX(4, 17, 163); -IRQC_PIN_MUX(5, 18); -IRQC_PINS_MUX(6, 39, 164); -IRQC_PINS_MUX(7, 40, 167); -IRQC_PINS_MUX(8, 41, 168); -IRQC_PINS_MUX(9, 42, 169); -IRQC_PIN_MUX(10, 65); -IRQC_PIN_MUX(11, 67); -IRQC_PINS_MUX(12, 80, 137); -IRQC_PINS_MUX(13, 81, 145); -IRQC_PINS_MUX(14, 82, 146); -IRQC_PINS_MUX(15, 83, 147); -IRQC_PINS_MUX(16, 84, 170); -IRQC_PIN_MUX(17, 85); -IRQC_PIN_MUX(18, 86); -IRQC_PIN_MUX(19, 87); -IRQC_PIN_MUX(20, 92); -IRQC_PIN_MUX(21, 93); -IRQC_PIN_MUX(22, 94); -IRQC_PIN_MUX(23, 95); -IRQC_PIN_MUX(24, 112); -IRQC_PIN_MUX(25, 119); -IRQC_PINS_MUX(26, 121, 172); -IRQC_PINS_MUX(27, 122, 180); -IRQC_PINS_MUX(28, 123, 181); -IRQC_PINS_MUX(29, 129, 182); -IRQC_PINS_MUX(30, 130, 183); -IRQC_PINS_MUX(31, 138, 184); -/* - KEYSC ------------------------------------------------------------------ */ -static const unsigned int keysc_in04_0_pins[] = { - /* KEYIN[0:4] */ - 136, 135, 134, 133, 132, -}; -static const unsigned int keysc_in04_0_mux[] = { - KEYIN0_136_MARK, KEYIN1_135_MARK, KEYIN2_134_MARK, KEYIN3_133_MARK, - KEYIN4_MARK, -}; -static const unsigned int keysc_in04_1_pins[] = { - /* KEYIN[0:4] */ - 121, 122, 123, 124, 132, -}; -static const unsigned int keysc_in04_1_mux[] = { - KEYIN0_121_MARK, KEYIN1_122_MARK, KEYIN2_123_MARK, KEYIN3_124_MARK, - KEYIN4_MARK, -}; -static const unsigned int keysc_in5_pins[] = { - /* KEYIN5 */ - 131, -}; -static const unsigned int keysc_in5_mux[] = { - KEYIN5_MARK, -}; -static const unsigned int keysc_in6_pins[] = { - /* KEYIN6 */ - 130, -}; -static const unsigned int keysc_in6_mux[] = { - KEYIN6_MARK, -}; -static const unsigned int keysc_in7_pins[] = { - /* KEYIN7 */ - 129, -}; -static const unsigned int keysc_in7_mux[] = { - KEYIN7_MARK, -}; -static const unsigned int keysc_out4_pins[] = { - /* KEYOUT[0:3] */ - 128, 127, 126, 125, -}; -static const unsigned int keysc_out4_mux[] = { - KEYOUT0_MARK, KEYOUT1_MARK, KEYOUT2_MARK, KEYOUT3_MARK, -}; -static const unsigned int keysc_out5_pins[] = { - /* KEYOUT[0:4] */ - 128, 127, 126, 125, 124, -}; -static const unsigned int keysc_out5_mux[] = { - KEYOUT0_MARK, KEYOUT1_MARK, KEYOUT2_MARK, KEYOUT3_MARK, - KEYOUT4_MARK, -}; -static const unsigned int keysc_out6_pins[] = { - /* KEYOUT[0:5] */ - 128, 127, 126, 125, 124, 123, -}; -static const unsigned int keysc_out6_mux[] = { - KEYOUT0_MARK, KEYOUT1_MARK, KEYOUT2_MARK, KEYOUT3_MARK, - KEYOUT4_MARK, KEYOUT5_MARK, -}; -static const unsigned int keysc_out8_pins[] = { - /* KEYOUT[0:7] */ - 128, 127, 126, 125, 124, 123, 122, 121, -}; -static const unsigned int keysc_out8_mux[] = { - KEYOUT0_MARK, KEYOUT1_MARK, KEYOUT2_MARK, KEYOUT3_MARK, - KEYOUT4_MARK, KEYOUT5_MARK, KEYOUT6_MARK, KEYOUT7_MARK, -}; -/* - LCD -------------------------------------------------------------------- */ -static const unsigned int lcd_data8_pins[] = { - /* D[0:7] */ - 121, 122, 123, 124, 125, 126, 127, 128, -}; -static const unsigned int lcd_data8_mux[] = { - /* LCDC */ - LCDD0_MARK, LCDD1_MARK, LCDD2_MARK, LCDD3_MARK, - LCDD4_MARK, LCDD5_MARK, LCDD6_MARK, LCDD7_MARK, -}; -static const unsigned int lcd_data9_pins[] = { - /* D[0:8] */ - 121, 122, 123, 124, 125, 126, 127, 128, - 129, - 137, 138, 139, 140, 141, 142, 143, 144, -}; -static const unsigned int lcd_data9_mux[] = { - LCDD0_MARK, LCDD1_MARK, LCDD2_MARK, LCDD3_MARK, - LCDD4_MARK, LCDD5_MARK, LCDD6_MARK, LCDD7_MARK, - LCDD8_MARK, -}; -static const unsigned int lcd_data12_pins[] = { - /* D[0:11] */ - 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, -}; -static const unsigned int lcd_data12_mux[] = { - LCDD0_MARK, LCDD1_MARK, LCDD2_MARK, LCDD3_MARK, - LCDD4_MARK, LCDD5_MARK, LCDD6_MARK, LCDD7_MARK, - LCDD8_MARK, LCDD9_MARK, LCDD10_MARK, LCDD11_MARK, -}; -static const unsigned int lcd_data16_pins[] = { - /* D[0:15] */ - 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, -}; -static const unsigned int lcd_data16_mux[] = { - LCDD0_MARK, LCDD1_MARK, LCDD2_MARK, LCDD3_MARK, - LCDD4_MARK, LCDD5_MARK, LCDD6_MARK, LCDD7_MARK, - LCDD8_MARK, LCDD9_MARK, LCDD10_MARK, LCDD11_MARK, - LCDD12_MARK, LCDD13_MARK, LCDD14_MARK, LCDD15_MARK, -}; -static const unsigned int lcd_data18_pins[] = { - /* D[0:17] */ - 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, -}; -static const unsigned int lcd_data18_mux[] = { - LCDD0_MARK, LCDD1_MARK, LCDD2_MARK, LCDD3_MARK, - LCDD4_MARK, LCDD5_MARK, LCDD6_MARK, LCDD7_MARK, - LCDD8_MARK, LCDD9_MARK, LCDD10_MARK, LCDD11_MARK, - LCDD12_MARK, LCDD13_MARK, LCDD14_MARK, LCDD15_MARK, - LCDD16_MARK, LCDD17_MARK, -}; -static const unsigned int lcd_data24_pins[] = { - /* D[0:23] */ - 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, -}; -static const unsigned int lcd_data24_mux[] = { - LCDD0_MARK, LCDD1_MARK, LCDD2_MARK, LCDD3_MARK, - LCDD4_MARK, LCDD5_MARK, LCDD6_MARK, LCDD7_MARK, - LCDD8_MARK, LCDD9_MARK, LCDD10_MARK, LCDD11_MARK, - LCDD12_MARK, LCDD13_MARK, LCDD14_MARK, LCDD15_MARK, - LCDD16_MARK, LCDD17_MARK, LCDD18_MARK, LCDD19_MARK, - LCDD20_MARK, LCDD21_MARK, LCDD22_MARK, LCDD23_MARK, -}; -static const unsigned int lcd_display_pins[] = { - /* DON */ - 151, -}; -static const unsigned int lcd_display_mux[] = { - LCDDON_MARK, -}; -static const unsigned int lcd_lclk_pins[] = { - /* LCLK */ - 150, -}; -static const unsigned int lcd_lclk_mux[] = { - LCDLCLK_MARK, -}; -static const unsigned int lcd_sync_pins[] = { - /* VSYN, HSYN, DCK, DISP */ - 146, 145, 147, 149, -}; -static const unsigned int lcd_sync_mux[] = { - LCDVSYN_MARK, LCDHSYN_MARK, LCDDCK_MARK, LCDDISP_MARK, -}; -static const unsigned int lcd_sys_pins[] = { - /* CS, WR, RD, RS */ - 145, 147, 148, 149, -}; -static const unsigned int lcd_sys_mux[] = { - LCDCS_MARK, LCDWR_MARK, LCDRD_MARK, LCDRS_MARK, -}; -/* - MMCIF ------------------------------------------------------------------ */ -static const unsigned int mmc0_data1_0_pins[] = { - /* D[0] */ - 84, -}; -static const unsigned int mmc0_data1_0_mux[] = { - MMCD0_0_MARK, -}; -static const unsigned int mmc0_data4_0_pins[] = { - /* D[0:3] */ - 84, 85, 86, 87, -}; -static const unsigned int mmc0_data4_0_mux[] = { - MMCD0_0_MARK, MMCD0_1_MARK, MMCD0_2_MARK, MMCD0_3_MARK, -}; -static const unsigned int mmc0_data8_0_pins[] = { - /* D[0:7] */ - 84, 85, 86, 87, 88, 89, 90, 91, -}; -static const unsigned int mmc0_data8_0_mux[] = { - MMCD0_0_MARK, MMCD0_1_MARK, MMCD0_2_MARK, MMCD0_3_MARK, - MMCD0_4_MARK, MMCD0_5_MARK, MMCD0_6_MARK, MMCD0_7_MARK, -}; -static const unsigned int mmc0_ctrl_0_pins[] = { - /* CMD, CLK */ - 92, 99, -}; -static const unsigned int mmc0_ctrl_0_mux[] = { - MMCCMD0_MARK, MMCCLK0_MARK, -}; - -static const unsigned int mmc0_data1_1_pins[] = { - /* D[0] */ - 54, -}; -static const unsigned int mmc0_data1_1_mux[] = { - MMCD1_0_MARK, -}; -static const unsigned int mmc0_data4_1_pins[] = { - /* D[0:3] */ - 54, 55, 56, 57, -}; -static const unsigned int mmc0_data4_1_mux[] = { - MMCD1_0_MARK, MMCD1_1_MARK, MMCD1_2_MARK, MMCD1_3_MARK, -}; -static const unsigned int mmc0_data8_1_pins[] = { - /* D[0:7] */ - 54, 55, 56, 57, 58, 59, 60, 61, -}; -static const unsigned int mmc0_data8_1_mux[] = { - MMCD1_0_MARK, MMCD1_1_MARK, MMCD1_2_MARK, MMCD1_3_MARK, - MMCD1_4_MARK, MMCD1_5_MARK, MMCD1_6_MARK, MMCD1_7_MARK, -}; -static const unsigned int mmc0_ctrl_1_pins[] = { - /* CMD, CLK */ - 67, 66, -}; -static const unsigned int mmc0_ctrl_1_mux[] = { - MMCCMD1_MARK, MMCCLK1_MARK, -}; -/* - SCIFA0 ----------------------------------------------------------------- */ -static const unsigned int scifa0_data_pins[] = { - /* RXD, TXD */ - 153, 152, -}; -static const unsigned int scifa0_data_mux[] = { - SCIFA0_RXD_MARK, SCIFA0_TXD_MARK, -}; -static const unsigned int scifa0_clk_pins[] = { - /* SCK */ - 156, -}; -static const unsigned int scifa0_clk_mux[] = { - SCIFA0_SCK_MARK, -}; -static const unsigned int scifa0_ctrl_pins[] = { - /* RTS, CTS */ - 157, 158, -}; -static const unsigned int scifa0_ctrl_mux[] = { - SCIFA0_RTS_MARK, SCIFA0_CTS_MARK, -}; -/* - SCIFA1 ----------------------------------------------------------------- */ -static const unsigned int scifa1_data_pins[] = { - /* RXD, TXD */ - 155, 154, -}; -static const unsigned int scifa1_data_mux[] = { - SCIFA1_RXD_MARK, SCIFA1_TXD_MARK, -}; -static const unsigned int scifa1_clk_pins[] = { - /* SCK */ - 159, -}; -static const unsigned int scifa1_clk_mux[] = { - SCIFA1_SCK_MARK, -}; -static const unsigned int scifa1_ctrl_pins[] = { - /* RTS, CTS */ - 160, 161, -}; -static const unsigned int scifa1_ctrl_mux[] = { - SCIFA1_RTS_MARK, SCIFA1_CTS_MARK, -}; -/* - SCIFA2 ----------------------------------------------------------------- */ -static const unsigned int scifa2_data_pins[] = { - /* RXD, TXD */ - 97, 96, -}; -static const unsigned int scifa2_data_mux[] = { - SCIFA2_RXD1_MARK, SCIFA2_TXD1_MARK, -}; -static const unsigned int scifa2_clk_pins[] = { - /* SCK */ - 98, -}; -static const unsigned int scifa2_clk_mux[] = { - SCIFA2_SCK1_MARK, -}; -static const unsigned int scifa2_ctrl_pins[] = { - /* RTS, CTS */ - 95, 94, -}; -static const unsigned int scifa2_ctrl_mux[] = { - SCIFA2_RTS1_MARK, SCIFA2_CTS1_MARK, -}; -/* - SCIFA3 ----------------------------------------------------------------- */ -static const unsigned int scifa3_data_pins[] = { - /* RXD, TXD */ - 144, 143, -}; -static const unsigned int scifa3_data_mux[] = { - SCIFA3_RXD_MARK, SCIFA3_TXD_MARK, -}; -static const unsigned int scifa3_clk_pins[] = { - /* SCK */ - 142, -}; -static const unsigned int scifa3_clk_mux[] = { - SCIFA3_SCK_MARK, -}; -static const unsigned int scifa3_ctrl_0_pins[] = { - /* RTS, CTS */ - 44, 43, -}; -static const unsigned int scifa3_ctrl_0_mux[] = { - SCIFA3_RTS_44_MARK, SCIFA3_CTS_43_MARK, -}; -static const unsigned int scifa3_ctrl_1_pins[] = { - /* RTS, CTS */ - 141, 140, -}; -static const unsigned int scifa3_ctrl_1_mux[] = { - SCIFA3_RTS_141_MARK, SCIFA3_CTS_140_MARK, -}; -/* - SCIFA4 ----------------------------------------------------------------- */ -static const unsigned int scifa4_data_pins[] = { - /* RXD, TXD */ - 5, 6, -}; -static const unsigned int scifa4_data_mux[] = { - SCIFA4_RXD_MARK, SCIFA4_TXD_MARK, -}; -/* - SCIFA5 ----------------------------------------------------------------- */ -static const unsigned int scifa5_data_pins[] = { - /* RXD, TXD */ - 8, 12, -}; -static const unsigned int scifa5_data_mux[] = { - SCIFA5_RXD_MARK, SCIFA5_TXD_MARK, -}; -/* - SCIFB ------------------------------------------------------------------ */ -static const unsigned int scifb_data_pins[] = { - /* RXD, TXD */ - 166, 165, -}; -static const unsigned int scifb_data_mux[] = { - SCIFB_RXD_MARK, SCIFB_TXD_MARK, -}; -static const unsigned int scifb_clk_pins[] = { - /* SCK */ - 162, -}; -static const unsigned int scifb_clk_mux[] = { - SCIFB_SCK_MARK, -}; -static const unsigned int scifb_ctrl_pins[] = { - /* RTS, CTS */ - 163, 164, -}; -static const unsigned int scifb_ctrl_mux[] = { - SCIFB_RTS_MARK, SCIFB_CTS_MARK, -}; -/* - SDHI0 ------------------------------------------------------------------ */ -static const unsigned int sdhi0_data1_pins[] = { - /* D0 */ - 173, -}; -static const unsigned int sdhi0_data1_mux[] = { - SDHID0_0_MARK, -}; -static const unsigned int sdhi0_data4_pins[] = { - /* D[0:3] */ - 173, 174, 175, 176, -}; -static const unsigned int sdhi0_data4_mux[] = { - SDHID0_0_MARK, SDHID0_1_MARK, SDHID0_2_MARK, SDHID0_3_MARK, -}; -static const unsigned int sdhi0_ctrl_pins[] = { - /* CMD, CLK */ - 177, 171, -}; -static const unsigned int sdhi0_ctrl_mux[] = { - SDHICMD0_MARK, SDHICLK0_MARK, -}; -static const unsigned int sdhi0_cd_pins[] = { - /* CD */ - 172, -}; -static const unsigned int sdhi0_cd_mux[] = { - SDHICD0_MARK, -}; -static const unsigned int sdhi0_wp_pins[] = { - /* WP */ - 178, -}; -static const unsigned int sdhi0_wp_mux[] = { - SDHIWP0_MARK, -}; -/* - SDHI1 ------------------------------------------------------------------ */ -static const unsigned int sdhi1_data1_pins[] = { - /* D0 */ - 180, -}; -static const unsigned int sdhi1_data1_mux[] = { - SDHID1_0_MARK, -}; -static const unsigned int sdhi1_data4_pins[] = { - /* D[0:3] */ - 180, 181, 182, 183, -}; -static const unsigned int sdhi1_data4_mux[] = { - SDHID1_0_MARK, SDHID1_1_MARK, SDHID1_2_MARK, SDHID1_3_MARK, -}; -static const unsigned int sdhi1_ctrl_pins[] = { - /* CMD, CLK */ - 184, 179, -}; -static const unsigned int sdhi1_ctrl_mux[] = { - SDHICMD1_MARK, SDHICLK1_MARK, -}; - -static const unsigned int sdhi2_data1_pins[] = { - /* D0 */ - 186, -}; -static const unsigned int sdhi2_data1_mux[] = { - SDHID2_0_MARK, -}; -static const unsigned int sdhi2_data4_pins[] = { - /* D[0:3] */ - 186, 187, 188, 189, -}; -static const unsigned int sdhi2_data4_mux[] = { - SDHID2_0_MARK, SDHID2_1_MARK, SDHID2_2_MARK, SDHID2_3_MARK, -}; -static const unsigned int sdhi2_ctrl_pins[] = { - /* CMD, CLK */ - 190, 185, -}; -static const unsigned int sdhi2_ctrl_mux[] = { - SDHICMD2_MARK, SDHICLK2_MARK, -}; -/* - USB0 ------------------------------------------------------------------- */ -static const unsigned int usb0_vbus_pins[] = { - /* VBUS */ - 167, -}; -static const unsigned int usb0_vbus_mux[] = { - VBUS0_0_MARK, -}; -static const unsigned int usb0_otg_id_pins[] = { - /* IDIN */ - 113, -}; -static const unsigned int usb0_otg_id_mux[] = { - IDIN_0_MARK, -}; -static const unsigned int usb0_otg_ctrl_pins[] = { - /* PWEN, EXTLP, OVCN, OVCN2 */ - 116, 114, 117, 115, -}; -static const unsigned int usb0_otg_ctrl_mux[] = { - PWEN_0_MARK, EXTLP_0_MARK, OVCN_0_MARK, OVCN2_0_MARK, -}; -/* - USB1 ------------------------------------------------------------------- */ -static const unsigned int usb1_vbus_pins[] = { - /* VBUS */ - 168, -}; -static const unsigned int usb1_vbus_mux[] = { - VBUS0_1_MARK, -}; -static const unsigned int usb1_otg_id_0_pins[] = { - /* IDIN */ - 113, -}; -static const unsigned int usb1_otg_id_0_mux[] = { - IDIN_1_113_MARK, -}; -static const unsigned int usb1_otg_id_1_pins[] = { - /* IDIN */ - 18, -}; -static const unsigned int usb1_otg_id_1_mux[] = { - IDIN_1_18_MARK, -}; -static const unsigned int usb1_otg_ctrl_0_pins[] = { - /* PWEN, EXTLP, OVCN, OVCN2 */ - 115, 116, 114, 117, 113, -}; -static const unsigned int usb1_otg_ctrl_0_mux[] = { - PWEN_1_115_MARK, EXTLP_1_MARK, OVCN_1_114_MARK, OVCN2_1_MARK, -}; -static const unsigned int usb1_otg_ctrl_1_pins[] = { - /* PWEN, EXTLP, OVCN, OVCN2 */ - 138, 116, 162, 117, 18, -}; -static const unsigned int usb1_otg_ctrl_1_mux[] = { - PWEN_1_138_MARK, EXTLP_1_MARK, OVCN_1_162_MARK, OVCN2_1_MARK, -}; - -static const struct sh_pfc_pin_group pinmux_groups[] = { - SH_PFC_PIN_GROUP(bsc_data8), - SH_PFC_PIN_GROUP(bsc_data16), - SH_PFC_PIN_GROUP(bsc_cs0), - SH_PFC_PIN_GROUP(bsc_cs2), - SH_PFC_PIN_GROUP(bsc_cs4), - SH_PFC_PIN_GROUP(bsc_cs5a), - SH_PFC_PIN_GROUP(bsc_cs5b), - SH_PFC_PIN_GROUP(bsc_cs6a), - SH_PFC_PIN_GROUP(bsc_rd_we8), - SH_PFC_PIN_GROUP(bsc_rd_we16), - SH_PFC_PIN_GROUP(bsc_bs), - SH_PFC_PIN_GROUP(bsc_rdwr), - SH_PFC_PIN_GROUP(ceu_data_0_7), - SH_PFC_PIN_GROUP(ceu_data_8_15), - SH_PFC_PIN_GROUP(ceu_clk_0), - SH_PFC_PIN_GROUP(ceu_clk_1), - SH_PFC_PIN_GROUP(ceu_clk_2), - SH_PFC_PIN_GROUP(ceu_sync), - SH_PFC_PIN_GROUP(ceu_field), - SH_PFC_PIN_GROUP(flctl_data), - SH_PFC_PIN_GROUP(flctl_ce0), - SH_PFC_PIN_GROUP(flctl_ce1), - SH_PFC_PIN_GROUP(flctl_ctrl), - SH_PFC_PIN_GROUP(fsia_mclk_in), - SH_PFC_PIN_GROUP(fsia_mclk_out), - SH_PFC_PIN_GROUP(fsia_sclk_in), - SH_PFC_PIN_GROUP(fsia_sclk_out), - SH_PFC_PIN_GROUP(fsia_data_in), - SH_PFC_PIN_GROUP(fsia_data_out), - SH_PFC_PIN_GROUP(fsia_spdif_0), - SH_PFC_PIN_GROUP(fsia_spdif_1), - SH_PFC_PIN_GROUP(fsib_mclk_in), - SH_PFC_PIN_GROUP(hdmi), - SH_PFC_PIN_GROUP(intc_irq0_0), - SH_PFC_PIN_GROUP(intc_irq0_1), - SH_PFC_PIN_GROUP(intc_irq1), - SH_PFC_PIN_GROUP(intc_irq2_0), - SH_PFC_PIN_GROUP(intc_irq2_1), - SH_PFC_PIN_GROUP(intc_irq3_0), - SH_PFC_PIN_GROUP(intc_irq3_1), - SH_PFC_PIN_GROUP(intc_irq4_0), - SH_PFC_PIN_GROUP(intc_irq4_1), - SH_PFC_PIN_GROUP(intc_irq5), - SH_PFC_PIN_GROUP(intc_irq6_0), - SH_PFC_PIN_GROUP(intc_irq6_1), - SH_PFC_PIN_GROUP(intc_irq7_0), - SH_PFC_PIN_GROUP(intc_irq7_1), - SH_PFC_PIN_GROUP(intc_irq8_0), - SH_PFC_PIN_GROUP(intc_irq8_1), - SH_PFC_PIN_GROUP(intc_irq9_0), - SH_PFC_PIN_GROUP(intc_irq9_1), - SH_PFC_PIN_GROUP(intc_irq10), - SH_PFC_PIN_GROUP(intc_irq11), - SH_PFC_PIN_GROUP(intc_irq12_0), - SH_PFC_PIN_GROUP(intc_irq12_1), - SH_PFC_PIN_GROUP(intc_irq13_0), - SH_PFC_PIN_GROUP(intc_irq13_1), - SH_PFC_PIN_GROUP(intc_irq14_0), - SH_PFC_PIN_GROUP(intc_irq14_1), - SH_PFC_PIN_GROUP(intc_irq15_0), - SH_PFC_PIN_GROUP(intc_irq15_1), - SH_PFC_PIN_GROUP(intc_irq16_0), - SH_PFC_PIN_GROUP(intc_irq16_1), - SH_PFC_PIN_GROUP(intc_irq17), - SH_PFC_PIN_GROUP(intc_irq18), - SH_PFC_PIN_GROUP(intc_irq19), - SH_PFC_PIN_GROUP(intc_irq20), - SH_PFC_PIN_GROUP(intc_irq21), - SH_PFC_PIN_GROUP(intc_irq22), - SH_PFC_PIN_GROUP(intc_irq23), - SH_PFC_PIN_GROUP(intc_irq24), - SH_PFC_PIN_GROUP(intc_irq25), - SH_PFC_PIN_GROUP(intc_irq26_0), - SH_PFC_PIN_GROUP(intc_irq26_1), - SH_PFC_PIN_GROUP(intc_irq27_0), - SH_PFC_PIN_GROUP(intc_irq27_1), - SH_PFC_PIN_GROUP(intc_irq28_0), - SH_PFC_PIN_GROUP(intc_irq28_1), - SH_PFC_PIN_GROUP(intc_irq29_0), - SH_PFC_PIN_GROUP(intc_irq29_1), - SH_PFC_PIN_GROUP(intc_irq30_0), - SH_PFC_PIN_GROUP(intc_irq30_1), - SH_PFC_PIN_GROUP(intc_irq31_0), - SH_PFC_PIN_GROUP(intc_irq31_1), - SH_PFC_PIN_GROUP(keysc_in04_0), - SH_PFC_PIN_GROUP(keysc_in04_1), - SH_PFC_PIN_GROUP(keysc_in5), - SH_PFC_PIN_GROUP(keysc_in6), - SH_PFC_PIN_GROUP(keysc_in7), - SH_PFC_PIN_GROUP(keysc_out4), - SH_PFC_PIN_GROUP(keysc_out5), - SH_PFC_PIN_GROUP(keysc_out6), - SH_PFC_PIN_GROUP(keysc_out8), - SH_PFC_PIN_GROUP(lcd_data8), - SH_PFC_PIN_GROUP(lcd_data9), - SH_PFC_PIN_GROUP(lcd_data12), - SH_PFC_PIN_GROUP(lcd_data16), - SH_PFC_PIN_GROUP(lcd_data18), - SH_PFC_PIN_GROUP(lcd_data24), - SH_PFC_PIN_GROUP(lcd_display), - SH_PFC_PIN_GROUP(lcd_lclk), - SH_PFC_PIN_GROUP(lcd_sync), - SH_PFC_PIN_GROUP(lcd_sys), - SH_PFC_PIN_GROUP(mmc0_data1_0), - SH_PFC_PIN_GROUP(mmc0_data4_0), - SH_PFC_PIN_GROUP(mmc0_data8_0), - SH_PFC_PIN_GROUP(mmc0_ctrl_0), - SH_PFC_PIN_GROUP(mmc0_data1_1), - SH_PFC_PIN_GROUP(mmc0_data4_1), - SH_PFC_PIN_GROUP(mmc0_data8_1), - SH_PFC_PIN_GROUP(mmc0_ctrl_1), - SH_PFC_PIN_GROUP(scifa0_data), - SH_PFC_PIN_GROUP(scifa0_clk), - SH_PFC_PIN_GROUP(scifa0_ctrl), - SH_PFC_PIN_GROUP(scifa1_data), - SH_PFC_PIN_GROUP(scifa1_clk), - SH_PFC_PIN_GROUP(scifa1_ctrl), - SH_PFC_PIN_GROUP(scifa2_data), - SH_PFC_PIN_GROUP(scifa2_clk), - SH_PFC_PIN_GROUP(scifa2_ctrl), - SH_PFC_PIN_GROUP(scifa3_data), - SH_PFC_PIN_GROUP(scifa3_clk), - SH_PFC_PIN_GROUP(scifa3_ctrl_0), - SH_PFC_PIN_GROUP(scifa3_ctrl_1), - SH_PFC_PIN_GROUP(scifa4_data), - SH_PFC_PIN_GROUP(scifa5_data), - SH_PFC_PIN_GROUP(scifb_data), - SH_PFC_PIN_GROUP(scifb_clk), - SH_PFC_PIN_GROUP(scifb_ctrl), - SH_PFC_PIN_GROUP(sdhi0_data1), - SH_PFC_PIN_GROUP(sdhi0_data4), - SH_PFC_PIN_GROUP(sdhi0_ctrl), - SH_PFC_PIN_GROUP(sdhi0_cd), - SH_PFC_PIN_GROUP(sdhi0_wp), - SH_PFC_PIN_GROUP(sdhi1_data1), - SH_PFC_PIN_GROUP(sdhi1_data4), - SH_PFC_PIN_GROUP(sdhi1_ctrl), - SH_PFC_PIN_GROUP(sdhi2_data1), - SH_PFC_PIN_GROUP(sdhi2_data4), - SH_PFC_PIN_GROUP(sdhi2_ctrl), - SH_PFC_PIN_GROUP(usb0_vbus), - SH_PFC_PIN_GROUP(usb0_otg_id), - SH_PFC_PIN_GROUP(usb0_otg_ctrl), - SH_PFC_PIN_GROUP(usb1_vbus), - SH_PFC_PIN_GROUP(usb1_otg_id_0), - SH_PFC_PIN_GROUP(usb1_otg_id_1), - SH_PFC_PIN_GROUP(usb1_otg_ctrl_0), - SH_PFC_PIN_GROUP(usb1_otg_ctrl_1), -}; - -static const char * const bsc_groups[] = { - "bsc_data8", - "bsc_data16", - "bsc_cs0", - "bsc_cs2", - "bsc_cs4", - "bsc_cs5a", - "bsc_cs5b", - "bsc_cs6a", - "bsc_rd_we8", - "bsc_rd_we16", - "bsc_bs", - "bsc_rdwr", -}; - -static const char * const ceu_groups[] = { - "ceu_data_0_7", - "ceu_data_8_15", - "ceu_clk_0", - "ceu_clk_1", - "ceu_clk_2", - "ceu_sync", - "ceu_field", -}; - -static const char * const flctl_groups[] = { - "flctl_data", - "flctl_ce0", - "flctl_ce1", - "flctl_ctrl", -}; - -static const char * const fsia_groups[] = { - "fsia_mclk_in", - "fsia_mclk_out", - "fsia_sclk_in", - "fsia_sclk_out", - "fsia_data_in", - "fsia_data_out", - "fsia_spdif_0", - "fsia_spdif_1", -}; - -static const char * const fsib_groups[] = { - "fsib_mclk_in", -}; - -static const char * const hdmi_groups[] = { - "hdmi", -}; - -static const char * const intc_groups[] = { - "intc_irq0_0", - "intc_irq0_1", - "intc_irq1", - "intc_irq2_0", - "intc_irq2_1", - "intc_irq3_0", - "intc_irq3_1", - "intc_irq4_0", - "intc_irq4_1", - "intc_irq5", - "intc_irq6_0", - "intc_irq6_1", - "intc_irq7_0", - "intc_irq7_1", - "intc_irq8_0", - "intc_irq8_1", - "intc_irq9_0", - "intc_irq9_1", - "intc_irq10", - "intc_irq11", - "intc_irq12_0", - "intc_irq12_1", - "intc_irq13_0", - "intc_irq13_1", - "intc_irq14_0", - "intc_irq14_1", - "intc_irq15_0", - "intc_irq15_1", - "intc_irq16_0", - "intc_irq16_1", - "intc_irq17", - "intc_irq18", - "intc_irq19", - "intc_irq20", - "intc_irq21", - "intc_irq22", - "intc_irq23", - "intc_irq24", - "intc_irq25", - "intc_irq26_0", - "intc_irq26_1", - "intc_irq27_0", - "intc_irq27_1", - "intc_irq28_0", - "intc_irq28_1", - "intc_irq29_0", - "intc_irq29_1", - "intc_irq30_0", - "intc_irq30_1", - "intc_irq31_0", - "intc_irq31_1", -}; - -static const char * const keysc_groups[] = { - "keysc_in04_0", - "keysc_in04_1", - "keysc_in5", - "keysc_in6", - "keysc_in7", - "keysc_out4", - "keysc_out5", - "keysc_out6", - "keysc_out8", -}; - -static const char * const lcd_groups[] = { - "lcd_data8", - "lcd_data9", - "lcd_data12", - "lcd_data16", - "lcd_data18", - "lcd_data24", - "lcd_display", - "lcd_lclk", - "lcd_sync", - "lcd_sys", -}; - -static const char * const mmc0_groups[] = { - "mmc0_data1_0", - "mmc0_data4_0", - "mmc0_data8_0", - "mmc0_ctrl_0", - "mmc0_data1_1", - "mmc0_data4_1", - "mmc0_data8_1", - "mmc0_ctrl_1", -}; - -static const char * const scifa0_groups[] = { - "scifa0_data", - "scifa0_clk", - "scifa0_ctrl", -}; - -static const char * const scifa1_groups[] = { - "scifa1_data", - "scifa1_clk", - "scifa1_ctrl", -}; - -static const char * const scifa2_groups[] = { - "scifa2_data", - "scifa2_clk", - "scifa2_ctrl", -}; - -static const char * const scifa3_groups[] = { - "scifa3_data", - "scifa3_clk", - "scifa3_ctrl_0", - "scifa3_ctrl_1", -}; - -static const char * const scifa4_groups[] = { - "scifa4_data", -}; - -static const char * const scifa5_groups[] = { - "scifa5_data", -}; - -static const char * const scifb_groups[] = { - "scifb_data", - "scifb_clk", - "scifb_ctrl", -}; - -static const char * const sdhi0_groups[] = { - "sdhi0_data1", - "sdhi0_data4", - "sdhi0_ctrl", - "sdhi0_cd", - "sdhi0_wp", -}; - -static const char * const sdhi1_groups[] = { - "sdhi1_data1", - "sdhi1_data4", - "sdhi1_ctrl", -}; - -static const char * const sdhi2_groups[] = { - "sdhi2_data1", - "sdhi2_data4", - "sdhi2_ctrl", -}; - -static const char * const usb0_groups[] = { - "usb0_vbus", - "usb0_otg_id", - "usb0_otg_ctrl", -}; - -static const char * const usb1_groups[] = { - "usb1_vbus", - "usb1_otg_id_0", - "usb1_otg_id_1", - "usb1_otg_ctrl_0", - "usb1_otg_ctrl_1", -}; - -static const struct sh_pfc_function pinmux_functions[] = { - SH_PFC_FUNCTION(bsc), - SH_PFC_FUNCTION(ceu), - SH_PFC_FUNCTION(flctl), - SH_PFC_FUNCTION(fsia), - SH_PFC_FUNCTION(fsib), - SH_PFC_FUNCTION(hdmi), - SH_PFC_FUNCTION(intc), - SH_PFC_FUNCTION(keysc), - SH_PFC_FUNCTION(lcd), - SH_PFC_FUNCTION(mmc0), - SH_PFC_FUNCTION(scifa0), - SH_PFC_FUNCTION(scifa1), - SH_PFC_FUNCTION(scifa2), - SH_PFC_FUNCTION(scifa3), - SH_PFC_FUNCTION(scifa4), - SH_PFC_FUNCTION(scifa5), - SH_PFC_FUNCTION(scifb), - SH_PFC_FUNCTION(sdhi0), - SH_PFC_FUNCTION(sdhi1), - SH_PFC_FUNCTION(sdhi2), - SH_PFC_FUNCTION(usb0), - SH_PFC_FUNCTION(usb1), -}; - -static const struct pinmux_cfg_reg pinmux_config_regs[] = { - PORTCR(0, 0xE6051000), /* PORT0CR */ - PORTCR(1, 0xE6051001), /* PORT1CR */ - PORTCR(2, 0xE6051002), /* PORT2CR */ - PORTCR(3, 0xE6051003), /* PORT3CR */ - PORTCR(4, 0xE6051004), /* PORT4CR */ - PORTCR(5, 0xE6051005), /* PORT5CR */ - PORTCR(6, 0xE6051006), /* PORT6CR */ - PORTCR(7, 0xE6051007), /* PORT7CR */ - PORTCR(8, 0xE6051008), /* PORT8CR */ - PORTCR(9, 0xE6051009), /* PORT9CR */ - PORTCR(10, 0xE605100A), /* PORT10CR */ - PORTCR(11, 0xE605100B), /* PORT11CR */ - PORTCR(12, 0xE605100C), /* PORT12CR */ - PORTCR(13, 0xE605100D), /* PORT13CR */ - PORTCR(14, 0xE605100E), /* PORT14CR */ - PORTCR(15, 0xE605100F), /* PORT15CR */ - PORTCR(16, 0xE6051010), /* PORT16CR */ - PORTCR(17, 0xE6051011), /* PORT17CR */ - PORTCR(18, 0xE6051012), /* PORT18CR */ - PORTCR(19, 0xE6051013), /* PORT19CR */ - PORTCR(20, 0xE6051014), /* PORT20CR */ - PORTCR(21, 0xE6051015), /* PORT21CR */ - PORTCR(22, 0xE6051016), /* PORT22CR */ - PORTCR(23, 0xE6051017), /* PORT23CR */ - PORTCR(24, 0xE6051018), /* PORT24CR */ - PORTCR(25, 0xE6051019), /* PORT25CR */ - PORTCR(26, 0xE605101A), /* PORT26CR */ - PORTCR(27, 0xE605101B), /* PORT27CR */ - PORTCR(28, 0xE605101C), /* PORT28CR */ - PORTCR(29, 0xE605101D), /* PORT29CR */ - PORTCR(30, 0xE605101E), /* PORT30CR */ - PORTCR(31, 0xE605101F), /* PORT31CR */ - PORTCR(32, 0xE6051020), /* PORT32CR */ - PORTCR(33, 0xE6051021), /* PORT33CR */ - PORTCR(34, 0xE6051022), /* PORT34CR */ - PORTCR(35, 0xE6051023), /* PORT35CR */ - PORTCR(36, 0xE6051024), /* PORT36CR */ - PORTCR(37, 0xE6051025), /* PORT37CR */ - PORTCR(38, 0xE6051026), /* PORT38CR */ - PORTCR(39, 0xE6051027), /* PORT39CR */ - PORTCR(40, 0xE6051028), /* PORT40CR */ - PORTCR(41, 0xE6051029), /* PORT41CR */ - PORTCR(42, 0xE605102A), /* PORT42CR */ - PORTCR(43, 0xE605102B), /* PORT43CR */ - PORTCR(44, 0xE605102C), /* PORT44CR */ - PORTCR(45, 0xE605102D), /* PORT45CR */ - PORTCR(46, 0xE605202E), /* PORT46CR */ - PORTCR(47, 0xE605202F), /* PORT47CR */ - PORTCR(48, 0xE6052030), /* PORT48CR */ - PORTCR(49, 0xE6052031), /* PORT49CR */ - PORTCR(50, 0xE6052032), /* PORT50CR */ - PORTCR(51, 0xE6052033), /* PORT51CR */ - PORTCR(52, 0xE6052034), /* PORT52CR */ - PORTCR(53, 0xE6052035), /* PORT53CR */ - PORTCR(54, 0xE6052036), /* PORT54CR */ - PORTCR(55, 0xE6052037), /* PORT55CR */ - PORTCR(56, 0xE6052038), /* PORT56CR */ - PORTCR(57, 0xE6052039), /* PORT57CR */ - PORTCR(58, 0xE605203A), /* PORT58CR */ - PORTCR(59, 0xE605203B), /* PORT59CR */ - PORTCR(60, 0xE605203C), /* PORT60CR */ - PORTCR(61, 0xE605203D), /* PORT61CR */ - PORTCR(62, 0xE605203E), /* PORT62CR */ - PORTCR(63, 0xE605203F), /* PORT63CR */ - PORTCR(64, 0xE6052040), /* PORT64CR */ - PORTCR(65, 0xE6052041), /* PORT65CR */ - PORTCR(66, 0xE6052042), /* PORT66CR */ - PORTCR(67, 0xE6052043), /* PORT67CR */ - PORTCR(68, 0xE6052044), /* PORT68CR */ - PORTCR(69, 0xE6052045), /* PORT69CR */ - PORTCR(70, 0xE6052046), /* PORT70CR */ - PORTCR(71, 0xE6052047), /* PORT71CR */ - PORTCR(72, 0xE6052048), /* PORT72CR */ - PORTCR(73, 0xE6052049), /* PORT73CR */ - PORTCR(74, 0xE605204A), /* PORT74CR */ - PORTCR(75, 0xE605204B), /* PORT75CR */ - PORTCR(76, 0xE605004C), /* PORT76CR */ - PORTCR(77, 0xE605004D), /* PORT77CR */ - PORTCR(78, 0xE605004E), /* PORT78CR */ - PORTCR(79, 0xE605004F), /* PORT79CR */ - PORTCR(80, 0xE6050050), /* PORT80CR */ - PORTCR(81, 0xE6050051), /* PORT81CR */ - PORTCR(82, 0xE6050052), /* PORT82CR */ - PORTCR(83, 0xE6050053), /* PORT83CR */ - PORTCR(84, 0xE6050054), /* PORT84CR */ - PORTCR(85, 0xE6050055), /* PORT85CR */ - PORTCR(86, 0xE6050056), /* PORT86CR */ - PORTCR(87, 0xE6050057), /* PORT87CR */ - PORTCR(88, 0xE6050058), /* PORT88CR */ - PORTCR(89, 0xE6050059), /* PORT89CR */ - PORTCR(90, 0xE605005A), /* PORT90CR */ - PORTCR(91, 0xE605005B), /* PORT91CR */ - PORTCR(92, 0xE605005C), /* PORT92CR */ - PORTCR(93, 0xE605005D), /* PORT93CR */ - PORTCR(94, 0xE605005E), /* PORT94CR */ - PORTCR(95, 0xE605005F), /* PORT95CR */ - PORTCR(96, 0xE6050060), /* PORT96CR */ - PORTCR(97, 0xE6050061), /* PORT97CR */ - PORTCR(98, 0xE6050062), /* PORT98CR */ - PORTCR(99, 0xE6050063), /* PORT99CR */ - PORTCR(100, 0xE6053064), /* PORT100CR */ - PORTCR(101, 0xE6053065), /* PORT101CR */ - PORTCR(102, 0xE6053066), /* PORT102CR */ - PORTCR(103, 0xE6053067), /* PORT103CR */ - PORTCR(104, 0xE6053068), /* PORT104CR */ - PORTCR(105, 0xE6053069), /* PORT105CR */ - PORTCR(106, 0xE605306A), /* PORT106CR */ - PORTCR(107, 0xE605306B), /* PORT107CR */ - PORTCR(108, 0xE605306C), /* PORT108CR */ - PORTCR(109, 0xE605306D), /* PORT109CR */ - PORTCR(110, 0xE605306E), /* PORT110CR */ - PORTCR(111, 0xE605306F), /* PORT111CR */ - PORTCR(112, 0xE6053070), /* PORT112CR */ - PORTCR(113, 0xE6053071), /* PORT113CR */ - PORTCR(114, 0xE6053072), /* PORT114CR */ - PORTCR(115, 0xE6053073), /* PORT115CR */ - PORTCR(116, 0xE6053074), /* PORT116CR */ - PORTCR(117, 0xE6053075), /* PORT117CR */ - PORTCR(118, 0xE6053076), /* PORT118CR */ - PORTCR(119, 0xE6053077), /* PORT119CR */ - PORTCR(120, 0xE6053078), /* PORT120CR */ - PORTCR(121, 0xE6050079), /* PORT121CR */ - PORTCR(122, 0xE605007A), /* PORT122CR */ - PORTCR(123, 0xE605007B), /* PORT123CR */ - PORTCR(124, 0xE605007C), /* PORT124CR */ - PORTCR(125, 0xE605007D), /* PORT125CR */ - PORTCR(126, 0xE605007E), /* PORT126CR */ - PORTCR(127, 0xE605007F), /* PORT127CR */ - PORTCR(128, 0xE6050080), /* PORT128CR */ - PORTCR(129, 0xE6050081), /* PORT129CR */ - PORTCR(130, 0xE6050082), /* PORT130CR */ - PORTCR(131, 0xE6050083), /* PORT131CR */ - PORTCR(132, 0xE6050084), /* PORT132CR */ - PORTCR(133, 0xE6050085), /* PORT133CR */ - PORTCR(134, 0xE6050086), /* PORT134CR */ - PORTCR(135, 0xE6050087), /* PORT135CR */ - PORTCR(136, 0xE6050088), /* PORT136CR */ - PORTCR(137, 0xE6050089), /* PORT137CR */ - PORTCR(138, 0xE605008A), /* PORT138CR */ - PORTCR(139, 0xE605008B), /* PORT139CR */ - PORTCR(140, 0xE605008C), /* PORT140CR */ - PORTCR(141, 0xE605008D), /* PORT141CR */ - PORTCR(142, 0xE605008E), /* PORT142CR */ - PORTCR(143, 0xE605008F), /* PORT143CR */ - PORTCR(144, 0xE6050090), /* PORT144CR */ - PORTCR(145, 0xE6050091), /* PORT145CR */ - PORTCR(146, 0xE6050092), /* PORT146CR */ - PORTCR(147, 0xE6050093), /* PORT147CR */ - PORTCR(148, 0xE6050094), /* PORT148CR */ - PORTCR(149, 0xE6050095), /* PORT149CR */ - PORTCR(150, 0xE6050096), /* PORT150CR */ - PORTCR(151, 0xE6050097), /* PORT151CR */ - PORTCR(152, 0xE6053098), /* PORT152CR */ - PORTCR(153, 0xE6053099), /* PORT153CR */ - PORTCR(154, 0xE605309A), /* PORT154CR */ - PORTCR(155, 0xE605309B), /* PORT155CR */ - PORTCR(156, 0xE605009C), /* PORT156CR */ - PORTCR(157, 0xE605009D), /* PORT157CR */ - PORTCR(158, 0xE605009E), /* PORT158CR */ - PORTCR(159, 0xE605009F), /* PORT159CR */ - PORTCR(160, 0xE60500A0), /* PORT160CR */ - PORTCR(161, 0xE60500A1), /* PORT161CR */ - PORTCR(162, 0xE60500A2), /* PORT162CR */ - PORTCR(163, 0xE60500A3), /* PORT163CR */ - PORTCR(164, 0xE60500A4), /* PORT164CR */ - PORTCR(165, 0xE60500A5), /* PORT165CR */ - PORTCR(166, 0xE60500A6), /* PORT166CR */ - PORTCR(167, 0xE60520A7), /* PORT167CR */ - PORTCR(168, 0xE60520A8), /* PORT168CR */ - PORTCR(169, 0xE60520A9), /* PORT169CR */ - PORTCR(170, 0xE60520AA), /* PORT170CR */ - PORTCR(171, 0xE60520AB), /* PORT171CR */ - PORTCR(172, 0xE60520AC), /* PORT172CR */ - PORTCR(173, 0xE60520AD), /* PORT173CR */ - PORTCR(174, 0xE60520AE), /* PORT174CR */ - PORTCR(175, 0xE60520AF), /* PORT175CR */ - PORTCR(176, 0xE60520B0), /* PORT176CR */ - PORTCR(177, 0xE60520B1), /* PORT177CR */ - PORTCR(178, 0xE60520B2), /* PORT178CR */ - PORTCR(179, 0xE60520B3), /* PORT179CR */ - PORTCR(180, 0xE60520B4), /* PORT180CR */ - PORTCR(181, 0xE60520B5), /* PORT181CR */ - PORTCR(182, 0xE60520B6), /* PORT182CR */ - PORTCR(183, 0xE60520B7), /* PORT183CR */ - PORTCR(184, 0xE60520B8), /* PORT184CR */ - PORTCR(185, 0xE60520B9), /* PORT185CR */ - PORTCR(186, 0xE60520BA), /* PORT186CR */ - PORTCR(187, 0xE60520BB), /* PORT187CR */ - PORTCR(188, 0xE60520BC), /* PORT188CR */ - PORTCR(189, 0xE60520BD), /* PORT189CR */ - PORTCR(190, 0xE60520BE), /* PORT190CR */ - - { PINMUX_CFG_REG("MSEL1CR", 0xE605800C, 32, 1) { - MSEL1CR_31_0, MSEL1CR_31_1, - MSEL1CR_30_0, MSEL1CR_30_1, - MSEL1CR_29_0, MSEL1CR_29_1, - MSEL1CR_28_0, MSEL1CR_28_1, - MSEL1CR_27_0, MSEL1CR_27_1, - MSEL1CR_26_0, MSEL1CR_26_1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - MSEL1CR_16_0, MSEL1CR_16_1, - MSEL1CR_15_0, MSEL1CR_15_1, - MSEL1CR_14_0, MSEL1CR_14_1, - MSEL1CR_13_0, MSEL1CR_13_1, - MSEL1CR_12_0, MSEL1CR_12_1, - 0, 0, 0, 0, - MSEL1CR_9_0, MSEL1CR_9_1, - MSEL1CR_8_0, MSEL1CR_8_1, - MSEL1CR_7_0, MSEL1CR_7_1, - MSEL1CR_6_0, MSEL1CR_6_1, - 0, 0, - MSEL1CR_4_0, MSEL1CR_4_1, - MSEL1CR_3_0, MSEL1CR_3_1, - MSEL1CR_2_0, MSEL1CR_2_1, - 0, 0, - MSEL1CR_0_0, MSEL1CR_0_1, - } - }, - { PINMUX_CFG_REG("MSEL3CR", 0xE6058020, 32, 1) { - 0, 0, 0, 0, - 0, 0, 0, 0, - MSEL3CR_27_0, MSEL3CR_27_1, - MSEL3CR_26_0, MSEL3CR_26_1, - 0, 0, 0, 0, - 0, 0, 0, 0, - MSEL3CR_21_0, MSEL3CR_21_1, - MSEL3CR_20_0, MSEL3CR_20_1, - 0, 0, 0, 0, - 0, 0, 0, 0, - MSEL3CR_15_0, MSEL3CR_15_1, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, - MSEL3CR_9_0, MSEL3CR_9_1, - 0, 0, 0, 0, - MSEL3CR_6_0, MSEL3CR_6_1, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - } - }, - { PINMUX_CFG_REG("MSEL4CR", 0xE6058024, 32, 1) { - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - MSEL4CR_19_0, MSEL4CR_19_1, - MSEL4CR_18_0, MSEL4CR_18_1, - MSEL4CR_17_0, MSEL4CR_17_1, - MSEL4CR_16_0, MSEL4CR_16_1, - MSEL4CR_15_0, MSEL4CR_15_1, - MSEL4CR_14_0, MSEL4CR_14_1, - 0, 0, 0, 0, - 0, 0, - MSEL4CR_10_0, MSEL4CR_10_1, - 0, 0, 0, 0, - 0, 0, - MSEL4CR_6_0, MSEL4CR_6_1, - 0, 0, - MSEL4CR_4_0, MSEL4CR_4_1, - 0, 0, 0, 0, - MSEL4CR_1_0, MSEL4CR_1_1, - 0, 0, - } - }, - { }, -}; - -static const struct pinmux_data_reg pinmux_data_regs[] = { - { PINMUX_DATA_REG("PORTL095_064DR", 0xE6054008, 32) { - PORT95_DATA, PORT94_DATA, PORT93_DATA, PORT92_DATA, - PORT91_DATA, PORT90_DATA, PORT89_DATA, PORT88_DATA, - PORT87_DATA, PORT86_DATA, PORT85_DATA, PORT84_DATA, - PORT83_DATA, PORT82_DATA, PORT81_DATA, PORT80_DATA, - PORT79_DATA, PORT78_DATA, PORT77_DATA, PORT76_DATA, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - } - }, - { PINMUX_DATA_REG("PORTL127_096DR", 0xE605400C, 32) { - PORT127_DATA, PORT126_DATA, PORT125_DATA, PORT124_DATA, - PORT123_DATA, PORT122_DATA, PORT121_DATA, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - PORT99_DATA, PORT98_DATA, PORT97_DATA, PORT96_DATA, - } - }, - { PINMUX_DATA_REG("PORTL159_128DR", 0xE6054010, 32) { - PORT159_DATA, PORT158_DATA, PORT157_DATA, PORT156_DATA, - 0, 0, 0, 0, - PORT151_DATA, PORT150_DATA, PORT149_DATA, PORT148_DATA, - PORT147_DATA, PORT146_DATA, PORT145_DATA, PORT144_DATA, - PORT143_DATA, PORT142_DATA, PORT141_DATA, PORT140_DATA, - PORT139_DATA, PORT138_DATA, PORT137_DATA, PORT136_DATA, - PORT135_DATA, PORT134_DATA, PORT133_DATA, PORT132_DATA, - PORT131_DATA, PORT130_DATA, PORT129_DATA, PORT128_DATA, - } - }, - { PINMUX_DATA_REG("PORTL191_160DR", 0xE6054014, 32) { - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, PORT166_DATA, PORT165_DATA, PORT164_DATA, - PORT163_DATA, PORT162_DATA, PORT161_DATA, PORT160_DATA, - } - }, - { PINMUX_DATA_REG("PORTD031_000DR", 0xE6055000, 32) { - PORT31_DATA, PORT30_DATA, PORT29_DATA, PORT28_DATA, - PORT27_DATA, PORT26_DATA, PORT25_DATA, PORT24_DATA, - PORT23_DATA, PORT22_DATA, PORT21_DATA, PORT20_DATA, - PORT19_DATA, PORT18_DATA, PORT17_DATA, PORT16_DATA, - PORT15_DATA, PORT14_DATA, PORT13_DATA, PORT12_DATA, - PORT11_DATA, PORT10_DATA, PORT9_DATA, PORT8_DATA, - PORT7_DATA, PORT6_DATA, PORT5_DATA, PORT4_DATA, - PORT3_DATA, PORT2_DATA, PORT1_DATA, PORT0_DATA, - } - }, - { PINMUX_DATA_REG("PORTD063_032DR", 0xE6055004, 32) { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, PORT45_DATA, PORT44_DATA, - PORT43_DATA, PORT42_DATA, PORT41_DATA, PORT40_DATA, - PORT39_DATA, PORT38_DATA, PORT37_DATA, PORT36_DATA, - PORT35_DATA, PORT34_DATA, PORT33_DATA, PORT32_DATA, - } - }, - { PINMUX_DATA_REG("PORTR063_032DR", 0xE6056004, 32) { - PORT63_DATA, PORT62_DATA, PORT61_DATA, PORT60_DATA, - PORT59_DATA, PORT58_DATA, PORT57_DATA, PORT56_DATA, - PORT55_DATA, PORT54_DATA, PORT53_DATA, PORT52_DATA, - PORT51_DATA, PORT50_DATA, PORT49_DATA, PORT48_DATA, - PORT47_DATA, PORT46_DATA, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - } - }, - { PINMUX_DATA_REG("PORTR095_064DR", 0xE6056008, 32) { - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - PORT75_DATA, PORT74_DATA, PORT73_DATA, PORT72_DATA, - PORT71_DATA, PORT70_DATA, PORT69_DATA, PORT68_DATA, - PORT67_DATA, PORT66_DATA, PORT65_DATA, PORT64_DATA, - } - }, - { PINMUX_DATA_REG("PORTR191_160DR", 0xE6056014, 32) { - 0, PORT190_DATA, PORT189_DATA, PORT188_DATA, - PORT187_DATA, PORT186_DATA, PORT185_DATA, PORT184_DATA, - PORT183_DATA, PORT182_DATA, PORT181_DATA, PORT180_DATA, - PORT179_DATA, PORT178_DATA, PORT177_DATA, PORT176_DATA, - PORT175_DATA, PORT174_DATA, PORT173_DATA, PORT172_DATA, - PORT171_DATA, PORT170_DATA, PORT169_DATA, PORT168_DATA, - PORT167_DATA, 0, 0, 0, - 0, 0, 0, 0, - } - }, - { PINMUX_DATA_REG("PORTU127_096DR", 0xE605700C, 32) { - 0, 0, 0, 0, - 0, 0, 0, PORT120_DATA, - PORT119_DATA, PORT118_DATA, PORT117_DATA, PORT116_DATA, - PORT115_DATA, PORT114_DATA, PORT113_DATA, PORT112_DATA, - PORT111_DATA, PORT110_DATA, PORT109_DATA, PORT108_DATA, - PORT107_DATA, PORT106_DATA, PORT105_DATA, PORT104_DATA, - PORT103_DATA, PORT102_DATA, PORT101_DATA, PORT100_DATA, - 0, 0, 0, 0, - } - }, - { PINMUX_DATA_REG("PORTU159_128DR", 0xE6057010, 32) { - 0, 0, 0, 0, - PORT155_DATA, PORT154_DATA, PORT153_DATA, PORT152_DATA, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - } - }, - { }, -}; - -#define EXT_IRQ16L(n) evt2irq(0x200 + ((n) << 5)) -#define EXT_IRQ16H(n) evt2irq(0x3200 + (((n) - 16) << 5)) -static const struct pinmux_irq pinmux_irqs[] = { - PINMUX_IRQ(EXT_IRQ16L(0), 6, 162), - PINMUX_IRQ(EXT_IRQ16L(1), 12), - PINMUX_IRQ(EXT_IRQ16L(2), 4, 5), - PINMUX_IRQ(EXT_IRQ16L(3), 8, 16), - PINMUX_IRQ(EXT_IRQ16L(4), 17, 163), - PINMUX_IRQ(EXT_IRQ16L(5), 18), - PINMUX_IRQ(EXT_IRQ16L(6), 39, 164), - PINMUX_IRQ(EXT_IRQ16L(7), 40, 167), - PINMUX_IRQ(EXT_IRQ16L(8), 41, 168), - PINMUX_IRQ(EXT_IRQ16L(9), 42, 169), - PINMUX_IRQ(EXT_IRQ16L(10), 65), - PINMUX_IRQ(EXT_IRQ16L(11), 67), - PINMUX_IRQ(EXT_IRQ16L(12), 80, 137), - PINMUX_IRQ(EXT_IRQ16L(13), 81, 145), - PINMUX_IRQ(EXT_IRQ16L(14), 82, 146), - PINMUX_IRQ(EXT_IRQ16L(15), 83, 147), - PINMUX_IRQ(EXT_IRQ16H(16), 84, 170), - PINMUX_IRQ(EXT_IRQ16H(17), 85), - PINMUX_IRQ(EXT_IRQ16H(18), 86), - PINMUX_IRQ(EXT_IRQ16H(19), 87), - PINMUX_IRQ(EXT_IRQ16H(20), 92), - PINMUX_IRQ(EXT_IRQ16H(21), 93), - PINMUX_IRQ(EXT_IRQ16H(22), 94), - PINMUX_IRQ(EXT_IRQ16H(23), 95), - PINMUX_IRQ(EXT_IRQ16H(24), 112), - PINMUX_IRQ(EXT_IRQ16H(25), 119), - PINMUX_IRQ(EXT_IRQ16H(26), 121, 172), - PINMUX_IRQ(EXT_IRQ16H(27), 122, 180), - PINMUX_IRQ(EXT_IRQ16H(28), 123, 181), - PINMUX_IRQ(EXT_IRQ16H(29), 129, 182), - PINMUX_IRQ(EXT_IRQ16H(30), 130, 183), - PINMUX_IRQ(EXT_IRQ16H(31), 138, 184), -}; - -#define PORTnCR_PULMD_OFF (0 << 6) -#define PORTnCR_PULMD_DOWN (2 << 6) -#define PORTnCR_PULMD_UP (3 << 6) -#define PORTnCR_PULMD_MASK (3 << 6) - -struct sh7372_portcr_group { - unsigned int end_pin; - unsigned int offset; -}; - -static const struct sh7372_portcr_group sh7372_portcr_offsets[] = { - { 45, 0x1000 }, { 75, 0x2000 }, { 99, 0x0000 }, { 120, 0x3000 }, - { 151, 0x0000 }, { 155, 0x3000 }, { 166, 0x0000 }, { 190, 0x2000 }, -}; - -static void __iomem *sh7372_pinmux_portcr(struct sh_pfc *pfc, unsigned int pin) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(sh7372_portcr_offsets); ++i) { - const struct sh7372_portcr_group *group = - &sh7372_portcr_offsets[i]; - - if (pin <= group->end_pin) - return pfc->windows->virt + group->offset + pin; - } - - return NULL; -} - -static unsigned int sh7372_pinmux_get_bias(struct sh_pfc *pfc, unsigned int pin) -{ - void __iomem *addr = sh7372_pinmux_portcr(pfc, pin); - u32 value = ioread8(addr) & PORTnCR_PULMD_MASK; - - switch (value) { - case PORTnCR_PULMD_UP: - return PIN_CONFIG_BIAS_PULL_UP; - case PORTnCR_PULMD_DOWN: - return PIN_CONFIG_BIAS_PULL_DOWN; - case PORTnCR_PULMD_OFF: - default: - return PIN_CONFIG_BIAS_DISABLE; - } -} - -static void sh7372_pinmux_set_bias(struct sh_pfc *pfc, unsigned int pin, - unsigned int bias) -{ - void __iomem *addr = sh7372_pinmux_portcr(pfc, pin); - u32 value = ioread8(addr) & ~PORTnCR_PULMD_MASK; - - switch (bias) { - case PIN_CONFIG_BIAS_PULL_UP: - value |= PORTnCR_PULMD_UP; - break; - case PIN_CONFIG_BIAS_PULL_DOWN: - value |= PORTnCR_PULMD_DOWN; - break; - } - - iowrite8(value, addr); -} - -static const struct sh_pfc_soc_operations sh7372_pfc_ops = { - .get_bias = sh7372_pinmux_get_bias, - .set_bias = sh7372_pinmux_set_bias, -}; - -const struct sh_pfc_soc_info sh7372_pinmux_info = { - .name = "sh7372_pfc", - .ops = &sh7372_pfc_ops, - - .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END }, - .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END }, - .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END }, - - .pins = pinmux_pins, - .nr_pins = ARRAY_SIZE(pinmux_pins), - .groups = pinmux_groups, - .nr_groups = ARRAY_SIZE(pinmux_groups), - .functions = pinmux_functions, - .nr_functions = ARRAY_SIZE(pinmux_functions), - - .cfg_regs = pinmux_config_regs, - .data_regs = pinmux_data_regs, - - .gpio_data = pinmux_data, - .gpio_data_size = ARRAY_SIZE(pinmux_data), - - .gpio_irq = pinmux_irqs, - .gpio_irq_size = ARRAY_SIZE(pinmux_irqs), -}; diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c index 910deaefa0ac..072e7c62cab7 100644 --- a/drivers/pinctrl/sh-pfc/pinctrl.c +++ b/drivers/pinctrl/sh-pfc/pinctrl.c @@ -122,7 +122,7 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, return ret; } - ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); + ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &num_configs); if (ret < 0) return ret; diff --git a/drivers/pinctrl/sh-pfc/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h index 5b7283182c1e..c83728626906 100644 --- a/drivers/pinctrl/sh-pfc/sh_pfc.h +++ b/drivers/pinctrl/sh-pfc/sh_pfc.h @@ -167,6 +167,8 @@ struct sh_pfc_soc_info { PINMUX_DATA(fn##_MARK, FN_##fn, FN_##ipsr) #define PINMUX_IPSR_NOGM(ispr, fn, ms) \ PINMUX_DATA(fn##_MARK, FN_##fn, FN_##ms) +#define PINMUX_IPSR_NOFN(ipsr, fn, ms) \ + PINMUX_DATA(fn##_MARK, FN_##ipsr, FN_##ms) #define PINMUX_IPSR_MSEL(ipsr, fn, ms) \ PINMUX_DATA(fn##_MARK, FN_##fn, FN_##ipsr, FN_##ms) #define PINMUX_IPSR_MODSEL_DATA(ipsr, fn, ms) \ diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index 4871647c7f85..2a1f07249b2f 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -38,7 +38,6 @@ struct sirfsoc_gpio_bank { struct sirfsoc_gpio_chip { struct of_mm_gpio_chip chip; - bool is_marco; /* for marco, some registers are different with prima2 */ struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS]; }; @@ -149,23 +148,14 @@ static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, for (i = 0; i < mux->muxmask_counts; i++) { u32 muxval; - if (!spmx->is_marco) { - muxval = readl(spmx->gpio_virtbase + - SIRFSOC_GPIO_PAD_EN(mask[i].group)); - if (enable) - muxval = muxval & ~mask[i].mask; - else - muxval = muxval | mask[i].mask; - writel(muxval, spmx->gpio_virtbase + - SIRFSOC_GPIO_PAD_EN(mask[i].group)); - } else { - if (enable) - writel(mask[i].mask, spmx->gpio_virtbase + - SIRFSOC_GPIO_PAD_EN_CLR(mask[i].group)); - else - writel(mask[i].mask, spmx->gpio_virtbase + - SIRFSOC_GPIO_PAD_EN(mask[i].group)); - } + muxval = readl(spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + if (enable) + muxval = muxval & ~mask[i].mask; + else + muxval = muxval | mask[i].mask; + writel(muxval, spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(mask[i].group)); } if (mux->funcmask && enable) { @@ -223,16 +213,11 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev, spmx = pinctrl_dev_get_drvdata(pmxdev); - if (!spmx->is_marco) { - muxval = readl(spmx->gpio_virtbase + - SIRFSOC_GPIO_PAD_EN(group)); - muxval = muxval | (1 << (offset - range->pin_base)); - writel(muxval, spmx->gpio_virtbase + - SIRFSOC_GPIO_PAD_EN(group)); - } else { - writel(1 << (offset - range->pin_base), spmx->gpio_virtbase + - SIRFSOC_GPIO_PAD_EN(group)); - } + muxval = readl(spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(group)); + muxval = muxval | (1 << (offset - range->pin_base)); + writel(muxval, spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(group)); return 0; } @@ -256,7 +241,6 @@ static void __iomem *sirfsoc_rsc_of_iomap(void) { const struct of_device_id rsc_ids[] = { { .compatible = "sirf,prima2-rsc" }, - { .compatible = "sirf,marco-rsc" }, {} }; struct device_node *np; @@ -284,7 +268,6 @@ static int sirfsoc_gpio_of_xlate(struct gpio_chip *gc, static const struct of_device_id pinmux_ids[] = { { .compatible = "sirf,prima2-pinctrl", .data = &prima2_pinctrl_data, }, { .compatible = "sirf,atlas6-pinctrl", .data = &atlas6_pinctrl_data, }, - { .compatible = "sirf,marco-pinctrl", .data = &prima2_pinctrl_data, }, {} }; @@ -317,9 +300,6 @@ static int sirfsoc_pinmux_probe(struct platform_device *pdev) goto out_no_rsc_remap; } - if (of_device_is_compatible(np, "sirf,marco-pinctrl")) - spmx->is_marco = 1; - pdata = of_match_node(pinmux_ids, np)->data; sirfsoc_pin_groups = pdata->grps; sirfsoc_pingrp_cnt = pdata->grps_cnt; @@ -803,7 +783,6 @@ static int sirfsoc_gpio_probe(struct device_node *np) struct sirfsoc_gpio_bank *bank; void __iomem *regs; struct platform_device *pdev; - bool is_marco = false; u32 pullups[SIRFSOC_GPIO_NO_OF_BANKS], pulldowns[SIRFSOC_GPIO_NO_OF_BANKS]; @@ -819,9 +798,6 @@ static int sirfsoc_gpio_probe(struct device_node *np) if (!regs) return -ENOMEM; - if (of_device_is_compatible(np, "sirf,marco-pinctrl")) - is_marco = 1; - sgpio->chip.gc.request = sirfsoc_gpio_request; sgpio->chip.gc.free = sirfsoc_gpio_free; sgpio->chip.gc.direction_input = sirfsoc_gpio_direction_input; @@ -836,7 +812,6 @@ static int sirfsoc_gpio_probe(struct device_node *np) sgpio->chip.gc.of_gpio_n_cells = 2; sgpio->chip.gc.dev = &pdev->dev; sgpio->chip.regs = regs; - sgpio->is_marco = is_marco; err = gpiochip_add(&sgpio->chip.gc); if (err) { diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.h b/drivers/pinctrl/sirf/pinctrl-sirf.h index d7f16b499ad9..9550335fe57a 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.h +++ b/drivers/pinctrl/sirf/pinctrl-sirf.h @@ -49,7 +49,6 @@ struct sirfsoc_pmx { u32 paden_regs[SIRFSOC_GPIO_NO_OF_BANKS]; u32 dspen_regs; u32 rsc_regs[3]; - bool is_marco; }; /* SIRFSOC_GPIO_PAD_EN set */ diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig index 230a952608cb..2eb893e0ea1e 100644 --- a/drivers/pinctrl/sunxi/Kconfig +++ b/drivers/pinctrl/sunxi/Kconfig @@ -21,6 +21,10 @@ config PINCTRL_SUN6I_A31 def_bool MACH_SUN6I select PINCTRL_SUNXI_COMMON +config PINCTRL_SUN6I_A31S + def_bool MACH_SUN6I + select PINCTRL_SUNXI_COMMON + config PINCTRL_SUN6I_A31_R def_bool MACH_SUN6I depends on RESET_CONTROLLER diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile index c7d92e4673b5..b796d579dce6 100644 --- a/drivers/pinctrl/sunxi/Makefile +++ b/drivers/pinctrl/sunxi/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_PINCTRL_SUN4I_A10) += pinctrl-sun4i-a10.o obj-$(CONFIG_PINCTRL_SUN5I_A10S) += pinctrl-sun5i-a10s.o obj-$(CONFIG_PINCTRL_SUN5I_A13) += pinctrl-sun5i-a13.o obj-$(CONFIG_PINCTRL_SUN6I_A31) += pinctrl-sun6i-a31.o +obj-$(CONFIG_PINCTRL_SUN6I_A31S) += pinctrl-sun6i-a31s.o obj-$(CONFIG_PINCTRL_SUN6I_A31_R) += pinctrl-sun6i-a31-r.o obj-$(CONFIG_PINCTRL_SUN7I_A20) += pinctrl-sun7i-a20.o obj-$(CONFIG_PINCTRL_SUN8I_A23) += pinctrl-sun8i-a23.o diff --git a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c index f42858eaca28..18038f0d6b52 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c +++ b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c @@ -134,24 +134,28 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = { SUNXI_FUNCTION(0x1, "gpio_out"), SUNXI_FUNCTION(0x2, "gmac"), /* RXD4 */ SUNXI_FUNCTION(0x3, "lcd1"), /* D15 */ + SUNXI_FUNCTION(0x4, "clk_out_a"), SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)), /* PA_EINT15 */ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 16), SUNXI_FUNCTION(0x0, "gpio_in"), SUNXI_FUNCTION(0x1, "gpio_out"), SUNXI_FUNCTION(0x2, "gmac"), /* RXD5 */ SUNXI_FUNCTION(0x3, "lcd1"), /* D16 */ + SUNXI_FUNCTION(0x4, "dmic"), /* CLK */ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)), /* PA_EINT16 */ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 17), SUNXI_FUNCTION(0x0, "gpio_in"), SUNXI_FUNCTION(0x1, "gpio_out"), SUNXI_FUNCTION(0x2, "gmac"), /* RXD6 */ SUNXI_FUNCTION(0x3, "lcd1"), /* D17 */ + SUNXI_FUNCTION(0x4, "dmic"), /* DIN */ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 17)), /* PA_EINT17 */ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 18), SUNXI_FUNCTION(0x0, "gpio_in"), SUNXI_FUNCTION(0x1, "gpio_out"), SUNXI_FUNCTION(0x2, "gmac"), /* RXD7 */ SUNXI_FUNCTION(0x3, "lcd1"), /* D18 */ + SUNXI_FUNCTION(0x4, "clk_out_b"), SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 18)), /* PA_EINT18 */ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 19), SUNXI_FUNCTION(0x0, "gpio_in"), @@ -207,6 +211,7 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = { SUNXI_FUNCTION(0x1, "gpio_out"), SUNXI_FUNCTION(0x2, "gmac"), /* MDC */ SUNXI_FUNCTION(0x3, "lcd1"), /* HSYNC */ + SUNXI_FUNCTION(0x4, "clk_out_c"), SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 26)), /* PA_EINT26 */ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 27), SUNXI_FUNCTION(0x0, "gpio_in"), diff --git a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c new file mode 100644 index 000000000000..9b5a91f610c7 --- /dev/null +++ b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c @@ -0,0 +1,815 @@ +/* + * Allwinner A31s SoCs pinctrl driver. + * + * Copyright (C) 2014 Hans de Goede + * + * Based on pinctrl-sun6i-a31.c, which is: + * Copyright (C) 2014 Maxime Ripard + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include + +#include "pinctrl-sunxi.h" + +static const struct sunxi_desc_pin sun6i_a31s_pins[] = { + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXD0 */ + SUNXI_FUNCTION(0x4, "uart1"), /* DTR */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)), /* PA_EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXD1 */ + SUNXI_FUNCTION(0x4, "uart1"), /* DSR */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)), /* PA_EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXD2 */ + SUNXI_FUNCTION(0x4, "uart1"), /* DCD */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)), /* PA_EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXD3 */ + SUNXI_FUNCTION(0x4, "uart1"), /* RING */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)), /* PA_EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXD4 */ + SUNXI_FUNCTION(0x4, "uart1"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)), /* PA_EINT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXD5 */ + SUNXI_FUNCTION(0x4, "uart1"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)), /* PA_EINT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXD6 */ + SUNXI_FUNCTION(0x4, "uart1"), /* RTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)), /* PA_EINT6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXD7 */ + SUNXI_FUNCTION(0x4, "uart1"), /* CTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)), /* PA_EINT7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXCLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)), /* PA_EINT8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXEN */ + SUNXI_FUNCTION(0x4, "mmc3"), /* CMD */ + SUNXI_FUNCTION(0x5, "mmc2"), /* CMD */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)), /* PA_EINT9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* GTXCLK */ + SUNXI_FUNCTION(0x4, "mmc3"), /* CLK */ + SUNXI_FUNCTION(0x5, "mmc2"), /* CLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 10)), /* PA_EINT10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXD0 */ + SUNXI_FUNCTION(0x4, "mmc3"), /* D0 */ + SUNXI_FUNCTION(0x5, "mmc2"), /* D0 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 11)), /* PA_EINT11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXD1 */ + SUNXI_FUNCTION(0x4, "mmc3"), /* D1 */ + SUNXI_FUNCTION(0x5, "mmc2"), /* D1 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 12)), /* PA_EINT12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXD2 */ + SUNXI_FUNCTION(0x4, "mmc3"), /* D2 */ + SUNXI_FUNCTION(0x5, "mmc2"), /* D2 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 13)), /* PA_EINT13 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXD3 */ + SUNXI_FUNCTION(0x4, "mmc3"), /* D3 */ + SUNXI_FUNCTION(0x5, "mmc2"), /* D3 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 14)), /* PA_EINT14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXD4 */ + SUNXI_FUNCTION(0x4, "clk_out_a"), + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)), /* PA_EINT15 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXD5 */ + SUNXI_FUNCTION(0x4, "dmic"), /* CLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)), /* PA_EINT16 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 17), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXD6 */ + SUNXI_FUNCTION(0x4, "dmic"), /* DIN */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 17)), /* PA_EINT17 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 18), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXD7 */ + SUNXI_FUNCTION(0x4, "clk_out_b"), + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 18)), /* PA_EINT18 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 19), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXDV */ + SUNXI_FUNCTION(0x4, "pwm3"), /* Positive */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 19)), /* PA_EINT19 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 20), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXCLK */ + SUNXI_FUNCTION(0x4, "pwm3"), /* Negative */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 20)), /* PA_EINT20 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 21), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* TXERR */ + SUNXI_FUNCTION(0x4, "spi3"), /* CS0 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 21)), /* PA_EINT21 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 22), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* RXERR */ + SUNXI_FUNCTION(0x4, "spi3"), /* CLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 22)), /* PA_EINT22 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 23), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* COL */ + SUNXI_FUNCTION(0x4, "spi3"), /* MOSI */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 23)), /* PA_EINT23 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 24), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* CRS */ + SUNXI_FUNCTION(0x4, "spi3"), /* MISO */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 24)), /* PA_EINT24 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 25), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* CLKIN */ + SUNXI_FUNCTION(0x4, "spi3"), /* CS1 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 25)), /* PA_EINT25 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 26), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* MDC */ + SUNXI_FUNCTION(0x4, "clk_out_c"), + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 26)), /* PA_EINT26 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 27), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "gmac"), /* MDIO */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 27)), /* PA_EINT27 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s0"), /* MCLK */ + SUNXI_FUNCTION(0x3, "uart3"), /* CTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)), /* PB_EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s0"), /* BCLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)), /* PB_EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s0"), /* LRCK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)), /* PB_EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s0"), /* DO0 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)), /* PB_EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s0"), /* DO1 */ + SUNXI_FUNCTION(0x3, "uart3"), /* RTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)), /* PB_EINT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s0"), /* DO2 */ + SUNXI_FUNCTION(0x3, "uart3"), /* TX */ + SUNXI_FUNCTION(0x4, "i2c3"), /* SCK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 5)), /* PB_EINT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2s0"), /* DO3 */ + SUNXI_FUNCTION(0x3, "uart3"), /* RX */ + SUNXI_FUNCTION(0x4, "i2c3"), /* SDA */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 6)), /* PB_EINT6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "i2s0"), /* DI */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 7)), /* PB_EINT7 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* WE */ + SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* ALE */ + SUNXI_FUNCTION(0x3, "spi0")), /* MISO */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* CLE */ + SUNXI_FUNCTION(0x3, "spi0")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* CE1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* CE0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* RE */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* RB0 */ + SUNXI_FUNCTION(0x3, "mmc2"), /* CMD */ + SUNXI_FUNCTION(0x4, "mmc3")), /* CMD */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* RB1 */ + SUNXI_FUNCTION(0x3, "mmc2"), /* CLK */ + SUNXI_FUNCTION(0x4, "mmc3")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ0 */ + SUNXI_FUNCTION(0x3, "mmc2"), /* D0 */ + SUNXI_FUNCTION(0x4, "mmc3")), /* D0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ1 */ + SUNXI_FUNCTION(0x3, "mmc2"), /* D1 */ + SUNXI_FUNCTION(0x4, "mmc3")), /* D1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ2 */ + SUNXI_FUNCTION(0x3, "mmc2"), /* D2 */ + SUNXI_FUNCTION(0x4, "mmc3")), /* D2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ3 */ + SUNXI_FUNCTION(0x3, "mmc2"), /* D3 */ + SUNXI_FUNCTION(0x4, "mmc3")), /* D3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ4 */ + SUNXI_FUNCTION(0x3, "mmc2"), /* D4 */ + SUNXI_FUNCTION(0x4, "mmc3")), /* D4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ5 */ + SUNXI_FUNCTION(0x3, "mmc2"), /* D5 */ + SUNXI_FUNCTION(0x4, "mmc3")), /* D5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ6 */ + SUNXI_FUNCTION(0x3, "mmc2"), /* D6 */ + SUNXI_FUNCTION(0x4, "mmc3")), /* D6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQ7 */ + SUNXI_FUNCTION(0x3, "mmc2"), /* D7 */ + SUNXI_FUNCTION(0x4, "mmc3")), /* D7 */ + /* Hole in pin numbering ! */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 24), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0"), /* DQS */ + SUNXI_FUNCTION(0x3, "mmc2"), /* RST */ + SUNXI_FUNCTION(0x4, "mmc3")), /* RST */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 25), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* CE2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 26), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "nand0")), /* CE3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 27), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x3, "spi0")), /* CS0 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D0 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VP0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D1 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VN0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VP1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VN1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VP2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VN2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VPC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D8 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VP3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0"), /* D9 */ + SUNXI_FUNCTION(0x3, "lvds0")), /* VN3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D13 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D15 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D16 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D17 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D18 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D19 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D20 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D21 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D22 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* D23 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* CLK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 25), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* DE */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 26), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* HSYNC */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 27), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "lcd0")), /* VSYNC */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* PCLK */ + SUNXI_FUNCTION(0x3, "ts"), /* CLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 0)), /* PE_EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* MCLK */ + SUNXI_FUNCTION(0x3, "ts"), /* ERR */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 1)), /* PE_EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* HSYNC */ + SUNXI_FUNCTION(0x3, "ts"), /* SYNC */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 2)), /* PE_EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* VSYNC */ + SUNXI_FUNCTION(0x3, "ts"), /* DVLD */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 3)), /* PE_EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D0 */ + SUNXI_FUNCTION(0x3, "uart5"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 4)), /* PE_EINT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D1 */ + SUNXI_FUNCTION(0x3, "uart5"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 5)), /* PE_EINT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D2 */ + SUNXI_FUNCTION(0x3, "uart5"), /* RTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 6)), /* PE_EINT6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D3 */ + SUNXI_FUNCTION(0x3, "uart5"), /* CTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 7)), /* PE_EINT7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D4 */ + SUNXI_FUNCTION(0x3, "ts"), /* D0 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 8)), /* PE_EINT8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D5 */ + SUNXI_FUNCTION(0x3, "ts"), /* D1 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 9)), /* PE_EINT9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D6 */ + SUNXI_FUNCTION(0x3, "ts"), /* D2 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 10)), /* PE_EINT10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D7 */ + SUNXI_FUNCTION(0x3, "ts"), /* D3 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 11)), /* PE_EINT11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D8 */ + SUNXI_FUNCTION(0x3, "ts"), /* D4 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 12)), /* PE_EINT12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D9 */ + SUNXI_FUNCTION(0x3, "ts"), /* D5 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 13)), /* PE_EINT13 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D10 */ + SUNXI_FUNCTION(0x3, "ts"), /* D6 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 14)), /* PE_EINT14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "csi"), /* D11 */ + SUNXI_FUNCTION(0x3, "ts"), /* D7 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 15)), /* PE_EINT15 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */ + SUNXI_FUNCTION(0x4, "jtag")), /* MS1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */ + SUNXI_FUNCTION(0x4, "jtag")), /* DI1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */ + SUNXI_FUNCTION(0x4, "uart0")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */ + SUNXI_FUNCTION(0x4, "jtag")), /* DO1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */ + SUNXI_FUNCTION(0x4, "uart0")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */ + SUNXI_FUNCTION(0x4, "jtag")), /* CK1 */ + /* Hole */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 0)), /* PG_EINT0 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 1)), /* PG_EINT1 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D0 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 2)), /* PG_EINT2 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 3)), /* PG_EINT3 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 4)), /* PG_EINT4 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 5)), /* PG_EINT5 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 6)), /* PG_EINT6 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 7)), /* PG_EINT7 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* RTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 8)), /* PG_EINT8 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart2"), /* CTS */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 9)), /* PG_EINT9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c3"), /* SCK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 10)), /* PG_EINT10 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c3"), /* SDA */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 11)), /* PG_EINT11 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* CS1 */ + SUNXI_FUNCTION(0x3, "i2s1"), /* MCLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 12)), /* PG_EINT12 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* CS0 */ + SUNXI_FUNCTION(0x3, "i2s1"), /* BCLK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 13)), /* PG_EINT13 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* CLK */ + SUNXI_FUNCTION(0x3, "i2s1"), /* LRCK */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 14)), /* PG_EINT14 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */ + SUNXI_FUNCTION(0x3, "i2s1"), /* DIN */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 15)), /* PG_EINT15 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi1"), /* MISO */ + SUNXI_FUNCTION(0x3, "i2s1"), /* DOUT */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 16)), /* PG_EINT16 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 17), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart4"), /* TX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 17)), /* PG_EINT17 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 18), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart4"), /* RX */ + SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 18)), /* PG_EINT18 */ + /* Hole, note H starts at pin 9 */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* CS0 */ + SUNXI_FUNCTION(0x3, "jtag"), /* MS0 */ + SUNXI_FUNCTION(0x4, "pwm1")), /* Positive */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 10), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* CLK */ + SUNXI_FUNCTION(0x3, "jtag"), /* CK0 */ + SUNXI_FUNCTION(0x4, "pwm1")), /* Negative */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 11), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* MOSI */ + SUNXI_FUNCTION(0x3, "jtag"), /* DO0 */ + SUNXI_FUNCTION(0x4, "pwm2")), /* Positive */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 12), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "spi2"), /* MISO */ + SUNXI_FUNCTION(0x3, "jtag"), /* DI0 */ + SUNXI_FUNCTION(0x4, "pwm2")), /* Negative */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 13), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "pwm0")), + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 14), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 15), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 16), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 17), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 18), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 19), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 20), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart0")), /* TX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 21), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out"), + SUNXI_FUNCTION(0x2, "uart0")), /* RX */ + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 22), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 23), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 24), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 25), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 26), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 27), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), + SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 28), + SUNXI_FUNCTION(0x0, "gpio_in"), + SUNXI_FUNCTION(0x1, "gpio_out")), +}; + +static const struct sunxi_pinctrl_desc sun6i_a31s_pinctrl_data = { + .pins = sun6i_a31s_pins, + .npins = ARRAY_SIZE(sun6i_a31s_pins), + .irq_banks = 4, +}; + +static int sun6i_a31s_pinctrl_probe(struct platform_device *pdev) +{ + return sunxi_pinctrl_init(pdev, + &sun6i_a31s_pinctrl_data); +} + +static struct of_device_id sun6i_a31s_pinctrl_match[] = { + { .compatible = "allwinner,sun6i-a31s-pinctrl", }, + {} +}; +MODULE_DEVICE_TABLE(of, sun6i_a31s_pinctrl_match); + +static struct platform_driver sun6i_a31s_pinctrl_driver = { + .probe = sun6i_a31s_pinctrl_probe, + .driver = { + .name = "sun6i-a31s-pinctrl", + .owner = THIS_MODULE, + .of_match_table = sun6i_a31s_pinctrl_match, + }, +}; +module_platform_driver(sun6i_a31s_pinctrl_driver); + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("Allwinner A31s pinctrl driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 9411eae39a4e..3d21efe11d7b 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -2,11 +2,9 @@ * Driver for Dell laptop extras * * Copyright (c) Red Hat - * Copyright (c) 2014 Gabriele Mazzotta - * Copyright (c) 2014 Pali Rohár * - * Based on documentation in the libsmbios package: - * Copyright (C) 2005-2014 Dell Inc. + * Based on documentation in the libsmbios package, Copyright (C) 2005 Dell + * 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 @@ -34,13 +32,6 @@ #include "../../firmware/dcdbas.h" #define BRIGHTNESS_TOKEN 0x7d -#define KBD_LED_OFF_TOKEN 0x01E1 -#define KBD_LED_ON_TOKEN 0x01E2 -#define KBD_LED_AUTO_TOKEN 0x01E3 -#define KBD_LED_AUTO_25_TOKEN 0x02EA -#define KBD_LED_AUTO_50_TOKEN 0x02EB -#define KBD_LED_AUTO_75_TOKEN 0x02EC -#define KBD_LED_AUTO_100_TOKEN 0x02F6 /* This structure will be modified by the firmware when we enter * system management mode, hence the volatiles */ @@ -71,13 +62,6 @@ struct calling_interface_structure { struct quirk_entry { u8 touchpad_led; - - int needs_kbd_timeouts; - /* - * Ordered list of timeouts expressed in seconds. - * The list must end with -1 - */ - int kbd_timeouts[]; }; static struct quirk_entry *quirks; @@ -92,15 +76,6 @@ static int __init dmi_matched(const struct dmi_system_id *dmi) return 1; } -/* - * These values come from Windows utility provided by Dell. If any other value - * is used then BIOS silently set timeout to 0 without any error message. - */ -static struct quirk_entry quirk_dell_xps13_9333 = { - .needs_kbd_timeouts = 1, - .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 }, -}; - static int da_command_address; static int da_command_code; static int da_num_tokens; @@ -292,15 +267,6 @@ static const struct dmi_system_id dell_quirks[] __initconst = { }, .driver_data = &quirk_dell_vostro_v130, }, - { - .callback = dmi_matched, - .ident = "Dell XPS13 9333", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "XPS13 9333"), - }, - .driver_data = &quirk_dell_xps13_9333, - }, { } }; @@ -365,29 +331,17 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy) } } -static int find_token_id(int tokenid) +static int find_token_location(int tokenid) { int i; - for (i = 0; i < da_num_tokens; i++) { if (da_tokens[i].tokenID == tokenid) - return i; + return da_tokens[i].location; } return -1; } -static int find_token_location(int tokenid) -{ - int id; - - id = find_token_id(tokenid); - if (id == -1) - return -1; - - return da_tokens[id].location; -} - static struct calling_interface_buffer * dell_send_request(struct calling_interface_buffer *buffer, int class, int select) @@ -408,20 +362,6 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, return buffer; } -static inline int dell_smi_error(int value) -{ - switch (value) { - case 0: /* Completed successfully */ - return 0; - case -1: /* Completed with error */ - return -EIO; - case -2: /* Function not supported */ - return -ENXIO; - default: /* Unknown error */ - return -EINVAL; - } -} - /* Derived from information in DellWirelessCtl.cpp: Class 17, select 11 is radio control. It returns an array of 32-bit values. @@ -776,7 +716,7 @@ static int dell_send_intensity(struct backlight_device *bd) else dell_send_request(buffer, 1, 1); - out: +out: release_buffer(); return ret; } @@ -800,7 +740,7 @@ static int dell_get_intensity(struct backlight_device *bd) ret = buffer->output[1]; - out: +out: release_buffer(); return ret; } @@ -849,984 +789,6 @@ static void touchpad_led_exit(void) led_classdev_unregister(&touchpad_led); } -/* - * Derived from information in smbios-keyboard-ctl: - * - * cbClass 4 - * cbSelect 11 - * Keyboard illumination - * cbArg1 determines the function to be performed - * - * cbArg1 0x0 = Get Feature Information - * cbRES1 Standard return codes (0, -1, -2) - * cbRES2, word0 Bitmap of user-selectable modes - * bit 0 Always off (All systems) - * bit 1 Always on (Travis ATG, Siberia) - * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG) - * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off - * bit 4 Auto: Input-activity-based On; input-activity based Off - * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off - * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off - * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off - * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off - * bits 9-15 Reserved for future use - * cbRES2, byte2 Reserved for future use - * cbRES2, byte3 Keyboard illumination type - * 0 Reserved - * 1 Tasklight - * 2 Backlight - * 3-255 Reserved for future use - * cbRES3, byte0 Supported auto keyboard illumination trigger bitmap. - * bit 0 Any keystroke - * bit 1 Touchpad activity - * bit 2 Pointing stick - * bit 3 Any mouse - * bits 4-7 Reserved for future use - * cbRES3, byte1 Supported timeout unit bitmap - * bit 0 Seconds - * bit 1 Minutes - * bit 2 Hours - * bit 3 Days - * bits 4-7 Reserved for future use - * cbRES3, byte2 Number of keyboard light brightness levels - * cbRES4, byte0 Maximum acceptable seconds value (0 if seconds not supported). - * cbRES4, byte1 Maximum acceptable minutes value (0 if minutes not supported). - * cbRES4, byte2 Maximum acceptable hours value (0 if hours not supported). - * cbRES4, byte3 Maximum acceptable days value (0 if days not supported) - * - * cbArg1 0x1 = Get Current State - * cbRES1 Standard return codes (0, -1, -2) - * cbRES2, word0 Bitmap of current mode state - * bit 0 Always off (All systems) - * bit 1 Always on (Travis ATG, Siberia) - * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG) - * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off - * bit 4 Auto: Input-activity-based On; input-activity based Off - * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off - * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off - * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off - * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off - * bits 9-15 Reserved for future use - * Note: Only One bit can be set - * cbRES2, byte2 Currently active auto keyboard illumination triggers. - * bit 0 Any keystroke - * bit 1 Touchpad activity - * bit 2 Pointing stick - * bit 3 Any mouse - * bits 4-7 Reserved for future use - * cbRES2, byte3 Current Timeout - * bits 7:6 Timeout units indicator: - * 00b Seconds - * 01b Minutes - * 10b Hours - * 11b Days - * bits 5:0 Timeout value (0-63) in sec/min/hr/day - * NOTE: A value of 0 means always on (no timeout) if any bits of RES3 byte - * are set upon return from the [Get feature information] call. - * cbRES3, byte0 Current setting of ALS value that turns the light on or off. - * cbRES3, byte1 Current ALS reading - * cbRES3, byte2 Current keyboard light level. - * - * cbArg1 0x2 = Set New State - * cbRES1 Standard return codes (0, -1, -2) - * cbArg2, word0 Bitmap of current mode state - * bit 0 Always off (All systems) - * bit 1 Always on (Travis ATG, Siberia) - * bit 2 Auto: ALS-based On; ALS-based Off (Travis ATG) - * bit 3 Auto: ALS- and input-activity-based On; input-activity based Off - * bit 4 Auto: Input-activity-based On; input-activity based Off - * bit 5 Auto: Input-activity-based On (illumination level 25%); input-activity based Off - * bit 6 Auto: Input-activity-based On (illumination level 50%); input-activity based Off - * bit 7 Auto: Input-activity-based On (illumination level 75%); input-activity based Off - * bit 8 Auto: Input-activity-based On (illumination level 100%); input-activity based Off - * bits 9-15 Reserved for future use - * Note: Only One bit can be set - * cbArg2, byte2 Desired auto keyboard illumination triggers. Must remain inactive to allow - * keyboard to turn off automatically. - * bit 0 Any keystroke - * bit 1 Touchpad activity - * bit 2 Pointing stick - * bit 3 Any mouse - * bits 4-7 Reserved for future use - * cbArg2, byte3 Desired Timeout - * bits 7:6 Timeout units indicator: - * 00b Seconds - * 01b Minutes - * 10b Hours - * 11b Days - * bits 5:0 Timeout value (0-63) in sec/min/hr/day - * cbArg3, byte0 Desired setting of ALS value that turns the light on or off. - * cbArg3, byte2 Desired keyboard light level. - */ - - -enum kbd_timeout_unit { - KBD_TIMEOUT_SECONDS = 0, - KBD_TIMEOUT_MINUTES, - KBD_TIMEOUT_HOURS, - KBD_TIMEOUT_DAYS, -}; - -enum kbd_mode_bit { - KBD_MODE_BIT_OFF = 0, - KBD_MODE_BIT_ON, - KBD_MODE_BIT_ALS, - KBD_MODE_BIT_TRIGGER_ALS, - KBD_MODE_BIT_TRIGGER, - KBD_MODE_BIT_TRIGGER_25, - KBD_MODE_BIT_TRIGGER_50, - KBD_MODE_BIT_TRIGGER_75, - KBD_MODE_BIT_TRIGGER_100, -}; - -#define kbd_is_als_mode_bit(bit) \ - ((bit) == KBD_MODE_BIT_ALS || (bit) == KBD_MODE_BIT_TRIGGER_ALS) -#define kbd_is_trigger_mode_bit(bit) \ - ((bit) >= KBD_MODE_BIT_TRIGGER_ALS && (bit) <= KBD_MODE_BIT_TRIGGER_100) -#define kbd_is_level_mode_bit(bit) \ - ((bit) >= KBD_MODE_BIT_TRIGGER_25 && (bit) <= KBD_MODE_BIT_TRIGGER_100) - -struct kbd_info { - u16 modes; - u8 type; - u8 triggers; - u8 levels; - u8 seconds; - u8 minutes; - u8 hours; - u8 days; -}; - -struct kbd_state { - u8 mode_bit; - u8 triggers; - u8 timeout_value; - u8 timeout_unit; - u8 als_setting; - u8 als_value; - u8 level; -}; - -static const int kbd_tokens[] = { - KBD_LED_OFF_TOKEN, - KBD_LED_AUTO_25_TOKEN, - KBD_LED_AUTO_50_TOKEN, - KBD_LED_AUTO_75_TOKEN, - KBD_LED_AUTO_100_TOKEN, - KBD_LED_ON_TOKEN, -}; - -static u16 kbd_token_bits; - -static struct kbd_info kbd_info; -static bool kbd_als_supported; -static bool kbd_triggers_supported; - -static u8 kbd_mode_levels[16]; -static int kbd_mode_levels_count; - -static u8 kbd_previous_level; -static u8 kbd_previous_mode_bit; - -static bool kbd_led_present; - -/* - * NOTE: there are three ways to set the keyboard backlight level. - * First, via kbd_state.mode_bit (assigning KBD_MODE_BIT_TRIGGER_* value). - * Second, via kbd_state.level (assigning numerical value <= kbd_info.levels). - * Third, via SMBIOS tokens (KBD_LED_* in kbd_tokens) - * - * There are laptops which support only one of these methods. If we want to - * support as many machines as possible we need to implement all three methods. - * The first two methods use the kbd_state structure. The third uses SMBIOS - * tokens. If kbd_info.levels == 0, the machine does not support setting the - * keyboard backlight level via kbd_state.level. - */ - -static int kbd_get_info(struct kbd_info *info) -{ - u8 units; - int ret; - - get_buffer(); - - buffer->input[0] = 0x0; - dell_send_request(buffer, 4, 11); - ret = buffer->output[0]; - - if (ret) { - ret = dell_smi_error(ret); - goto out; - } - - info->modes = buffer->output[1] & 0xFFFF; - info->type = (buffer->output[1] >> 24) & 0xFF; - info->triggers = buffer->output[2] & 0xFF; - units = (buffer->output[2] >> 8) & 0xFF; - info->levels = (buffer->output[2] >> 16) & 0xFF; - - if (units & BIT(0)) - info->seconds = (buffer->output[3] >> 0) & 0xFF; - if (units & BIT(1)) - info->minutes = (buffer->output[3] >> 8) & 0xFF; - if (units & BIT(2)) - info->hours = (buffer->output[3] >> 16) & 0xFF; - if (units & BIT(3)) - info->days = (buffer->output[3] >> 24) & 0xFF; - - out: - release_buffer(); - return ret; -} - -static unsigned int kbd_get_max_level(void) -{ - if (kbd_info.levels != 0) - return kbd_info.levels; - if (kbd_mode_levels_count > 0) - return kbd_mode_levels_count - 1; - return 0; -} - -static int kbd_get_level(struct kbd_state *state) -{ - int i; - - if (kbd_info.levels != 0) - return state->level; - - if (kbd_mode_levels_count > 0) { - for (i = 0; i < kbd_mode_levels_count; ++i) - if (kbd_mode_levels[i] == state->mode_bit) - return i; - return 0; - } - - return -EINVAL; -} - -static int kbd_set_level(struct kbd_state *state, u8 level) -{ - if (kbd_info.levels != 0) { - if (level != 0) - kbd_previous_level = level; - if (state->level == level) - return 0; - state->level = level; - if (level != 0 && state->mode_bit == KBD_MODE_BIT_OFF) - state->mode_bit = kbd_previous_mode_bit; - else if (level == 0 && state->mode_bit != KBD_MODE_BIT_OFF) { - kbd_previous_mode_bit = state->mode_bit; - state->mode_bit = KBD_MODE_BIT_OFF; - } - return 0; - } - - if (kbd_mode_levels_count > 0 && level < kbd_mode_levels_count) { - if (level != 0) - kbd_previous_level = level; - state->mode_bit = kbd_mode_levels[level]; - return 0; - } - - return -EINVAL; -} - -static int kbd_get_state(struct kbd_state *state) -{ - int ret; - - get_buffer(); - - buffer->input[0] = 0x1; - dell_send_request(buffer, 4, 11); - ret = buffer->output[0]; - - if (ret) { - ret = dell_smi_error(ret); - goto out; - } - - state->mode_bit = ffs(buffer->output[1] & 0xFFFF); - if (state->mode_bit != 0) - state->mode_bit--; - - state->triggers = (buffer->output[1] >> 16) & 0xFF; - state->timeout_value = (buffer->output[1] >> 24) & 0x3F; - state->timeout_unit = (buffer->output[1] >> 30) & 0x3; - state->als_setting = buffer->output[2] & 0xFF; - state->als_value = (buffer->output[2] >> 8) & 0xFF; - state->level = (buffer->output[2] >> 16) & 0xFF; - - out: - release_buffer(); - return ret; -} - -static int kbd_set_state(struct kbd_state *state) -{ - int ret; - - get_buffer(); - buffer->input[0] = 0x2; - buffer->input[1] = BIT(state->mode_bit) & 0xFFFF; - buffer->input[1] |= (state->triggers & 0xFF) << 16; - buffer->input[1] |= (state->timeout_value & 0x3F) << 24; - buffer->input[1] |= (state->timeout_unit & 0x3) << 30; - buffer->input[2] = state->als_setting & 0xFF; - buffer->input[2] |= (state->level & 0xFF) << 16; - dell_send_request(buffer, 4, 11); - ret = buffer->output[0]; - release_buffer(); - - return dell_smi_error(ret); -} - -static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old) -{ - int ret; - - ret = kbd_set_state(state); - if (ret == 0) - return 0; - - /* - * When setting the new state fails,try to restore the previous one. - * This is needed on some machines where BIOS sets a default state when - * setting a new state fails. This default state could be all off. - */ - - if (kbd_set_state(old)) - pr_err("Setting old previous keyboard state failed\n"); - - return ret; -} - -static int kbd_set_token_bit(u8 bit) -{ - int id; - int ret; - - if (bit >= ARRAY_SIZE(kbd_tokens)) - return -EINVAL; - - id = find_token_id(kbd_tokens[bit]); - if (id == -1) - return -EINVAL; - - get_buffer(); - buffer->input[0] = da_tokens[id].location; - buffer->input[1] = da_tokens[id].value; - dell_send_request(buffer, 1, 0); - ret = buffer->output[0]; - release_buffer(); - - return dell_smi_error(ret); -} - -static int kbd_get_token_bit(u8 bit) -{ - int id; - int ret; - int val; - - if (bit >= ARRAY_SIZE(kbd_tokens)) - return -EINVAL; - - id = find_token_id(kbd_tokens[bit]); - if (id == -1) - return -EINVAL; - - get_buffer(); - buffer->input[0] = da_tokens[id].location; - dell_send_request(buffer, 0, 0); - ret = buffer->output[0]; - val = buffer->output[1]; - release_buffer(); - - if (ret) - return dell_smi_error(ret); - - return (val == da_tokens[id].value); -} - -static int kbd_get_first_active_token_bit(void) -{ - int i; - int ret; - - for (i = 0; i < ARRAY_SIZE(kbd_tokens); ++i) { - ret = kbd_get_token_bit(i); - if (ret == 1) - return i; - } - - return ret; -} - -static int kbd_get_valid_token_counts(void) -{ - return hweight16(kbd_token_bits); -} - -static inline int kbd_init_info(void) -{ - struct kbd_state state; - int ret; - int i; - - ret = kbd_get_info(&kbd_info); - if (ret) - return ret; - - kbd_get_state(&state); - - /* NOTE: timeout value is stored in 6 bits so max value is 63 */ - if (kbd_info.seconds > 63) - kbd_info.seconds = 63; - if (kbd_info.minutes > 63) - kbd_info.minutes = 63; - if (kbd_info.hours > 63) - kbd_info.hours = 63; - if (kbd_info.days > 63) - kbd_info.days = 63; - - /* NOTE: On tested machines ON mode did not work and caused - * problems (turned backlight off) so do not use it - */ - kbd_info.modes &= ~BIT(KBD_MODE_BIT_ON); - - kbd_previous_level = kbd_get_level(&state); - kbd_previous_mode_bit = state.mode_bit; - - if (kbd_previous_level == 0 && kbd_get_max_level() != 0) - kbd_previous_level = 1; - - if (kbd_previous_mode_bit == KBD_MODE_BIT_OFF) { - kbd_previous_mode_bit = - ffs(kbd_info.modes & ~BIT(KBD_MODE_BIT_OFF)); - if (kbd_previous_mode_bit != 0) - kbd_previous_mode_bit--; - } - - if (kbd_info.modes & (BIT(KBD_MODE_BIT_ALS) | - BIT(KBD_MODE_BIT_TRIGGER_ALS))) - kbd_als_supported = true; - - if (kbd_info.modes & ( - BIT(KBD_MODE_BIT_TRIGGER_ALS) | BIT(KBD_MODE_BIT_TRIGGER) | - BIT(KBD_MODE_BIT_TRIGGER_25) | BIT(KBD_MODE_BIT_TRIGGER_50) | - BIT(KBD_MODE_BIT_TRIGGER_75) | BIT(KBD_MODE_BIT_TRIGGER_100) - )) - kbd_triggers_supported = true; - - /* kbd_mode_levels[0] is reserved, see below */ - for (i = 0; i < 16; ++i) - if (kbd_is_level_mode_bit(i) && (BIT(i) & kbd_info.modes)) - kbd_mode_levels[1 + kbd_mode_levels_count++] = i; - - /* - * Find the first supported mode and assign to kbd_mode_levels[0]. - * This should be 0 (off), but we cannot depend on the BIOS to - * support 0. - */ - if (kbd_mode_levels_count > 0) { - for (i = 0; i < 16; ++i) { - if (BIT(i) & kbd_info.modes) { - kbd_mode_levels[0] = i; - break; - } - } - kbd_mode_levels_count++; - } - - return 0; - -} - -static inline void kbd_init_tokens(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(kbd_tokens); ++i) - if (find_token_id(kbd_tokens[i]) != -1) - kbd_token_bits |= BIT(i); -} - -static void kbd_init(void) -{ - int ret; - - ret = kbd_init_info(); - kbd_init_tokens(); - - if (kbd_token_bits != 0 || ret == 0) - kbd_led_present = true; -} - -static ssize_t kbd_led_timeout_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct kbd_state new_state; - struct kbd_state state; - bool convert; - int value; - int ret; - char ch; - u8 unit; - int i; - - ret = sscanf(buf, "%d %c", &value, &ch); - if (ret < 1) - return -EINVAL; - else if (ret == 1) - ch = 's'; - - if (value < 0) - return -EINVAL; - - convert = false; - - switch (ch) { - case 's': - if (value > kbd_info.seconds) - convert = true; - unit = KBD_TIMEOUT_SECONDS; - break; - case 'm': - if (value > kbd_info.minutes) - convert = true; - unit = KBD_TIMEOUT_MINUTES; - break; - case 'h': - if (value > kbd_info.hours) - convert = true; - unit = KBD_TIMEOUT_HOURS; - break; - case 'd': - if (value > kbd_info.days) - convert = true; - unit = KBD_TIMEOUT_DAYS; - break; - default: - return -EINVAL; - } - - if (quirks && quirks->needs_kbd_timeouts) - convert = true; - - if (convert) { - /* Convert value from current units to seconds */ - switch (unit) { - case KBD_TIMEOUT_DAYS: - value *= 24; - case KBD_TIMEOUT_HOURS: - value *= 60; - case KBD_TIMEOUT_MINUTES: - value *= 60; - unit = KBD_TIMEOUT_SECONDS; - } - - if (quirks && quirks->needs_kbd_timeouts) { - for (i = 0; quirks->kbd_timeouts[i] != -1; i++) { - if (value <= quirks->kbd_timeouts[i]) { - value = quirks->kbd_timeouts[i]; - break; - } - } - } - - if (value <= kbd_info.seconds && kbd_info.seconds) { - unit = KBD_TIMEOUT_SECONDS; - } else if (value / 60 <= kbd_info.minutes && kbd_info.minutes) { - value /= 60; - unit = KBD_TIMEOUT_MINUTES; - } else if (value / (60 * 60) <= kbd_info.hours && kbd_info.hours) { - value /= (60 * 60); - unit = KBD_TIMEOUT_HOURS; - } else if (value / (60 * 60 * 24) <= kbd_info.days && kbd_info.days) { - value /= (60 * 60 * 24); - unit = KBD_TIMEOUT_DAYS; - } else { - return -EINVAL; - } - } - - ret = kbd_get_state(&state); - if (ret) - return ret; - - new_state = state; - new_state.timeout_value = value; - new_state.timeout_unit = unit; - - ret = kbd_set_state_safe(&new_state, &state); - if (ret) - return ret; - - return count; -} - -static ssize_t kbd_led_timeout_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct kbd_state state; - int ret; - int len; - - ret = kbd_get_state(&state); - if (ret) - return ret; - - len = sprintf(buf, "%d", state.timeout_value); - - switch (state.timeout_unit) { - case KBD_TIMEOUT_SECONDS: - return len + sprintf(buf+len, "s\n"); - case KBD_TIMEOUT_MINUTES: - return len + sprintf(buf+len, "m\n"); - case KBD_TIMEOUT_HOURS: - return len + sprintf(buf+len, "h\n"); - case KBD_TIMEOUT_DAYS: - return len + sprintf(buf+len, "d\n"); - default: - return -EINVAL; - } - - return len; -} - -static DEVICE_ATTR(stop_timeout, S_IRUGO | S_IWUSR, - kbd_led_timeout_show, kbd_led_timeout_store); - -static const char * const kbd_led_triggers[] = { - "keyboard", - "touchpad", - /*"trackstick"*/ NULL, /* NOTE: trackstick is just alias for touchpad */ - "mouse", -}; - -static ssize_t kbd_led_triggers_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct kbd_state new_state; - struct kbd_state state; - bool triggers_enabled = false; - bool als_enabled = false; - bool disable_als = false; - bool enable_als = false; - int trigger_bit = -1; - char trigger[21]; - int i, ret; - - ret = sscanf(buf, "%20s", trigger); - if (ret != 1) - return -EINVAL; - - if (trigger[0] != '+' && trigger[0] != '-') - return -EINVAL; - - ret = kbd_get_state(&state); - if (ret) - return ret; - - if (kbd_als_supported) - als_enabled = kbd_is_als_mode_bit(state.mode_bit); - - if (kbd_triggers_supported) - triggers_enabled = kbd_is_trigger_mode_bit(state.mode_bit); - - if (kbd_als_supported) { - if (strcmp(trigger, "+als") == 0) { - if (als_enabled) - return count; - enable_als = true; - } else if (strcmp(trigger, "-als") == 0) { - if (!als_enabled) - return count; - disable_als = true; - } - } - - if (enable_als || disable_als) { - new_state = state; - if (enable_als) { - if (triggers_enabled) - new_state.mode_bit = KBD_MODE_BIT_TRIGGER_ALS; - else - new_state.mode_bit = KBD_MODE_BIT_ALS; - } else { - if (triggers_enabled) { - new_state.mode_bit = KBD_MODE_BIT_TRIGGER; - kbd_set_level(&new_state, kbd_previous_level); - } else { - new_state.mode_bit = KBD_MODE_BIT_ON; - } - } - if (!(kbd_info.modes & BIT(new_state.mode_bit))) - return -EINVAL; - ret = kbd_set_state_safe(&new_state, &state); - if (ret) - return ret; - kbd_previous_mode_bit = new_state.mode_bit; - return count; - } - - if (kbd_triggers_supported) { - for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); ++i) { - if (!(kbd_info.triggers & BIT(i))) - continue; - if (!kbd_led_triggers[i]) - continue; - if (strcmp(trigger+1, kbd_led_triggers[i]) != 0) - continue; - if (trigger[0] == '+' && - triggers_enabled && (state.triggers & BIT(i))) - return count; - if (trigger[0] == '-' && - (!triggers_enabled || !(state.triggers & BIT(i)))) - return count; - trigger_bit = i; - break; - } - } - - if (trigger_bit != -1) { - new_state = state; - if (trigger[0] == '+') - new_state.triggers |= BIT(trigger_bit); - else { - new_state.triggers &= ~BIT(trigger_bit); - /* NOTE: trackstick bit (2) must be disabled when - * disabling touchpad bit (1), otherwise touchpad - * bit (1) will not be disabled */ - if (trigger_bit == 1) - new_state.triggers &= ~BIT(2); - } - if ((kbd_info.triggers & new_state.triggers) != - new_state.triggers) - return -EINVAL; - if (new_state.triggers && !triggers_enabled) { - if (als_enabled) - new_state.mode_bit = KBD_MODE_BIT_TRIGGER_ALS; - else { - new_state.mode_bit = KBD_MODE_BIT_TRIGGER; - kbd_set_level(&new_state, kbd_previous_level); - } - } else if (new_state.triggers == 0) { - if (als_enabled) - new_state.mode_bit = KBD_MODE_BIT_ALS; - else - kbd_set_level(&new_state, 0); - } - if (!(kbd_info.modes & BIT(new_state.mode_bit))) - return -EINVAL; - ret = kbd_set_state_safe(&new_state, &state); - if (ret) - return ret; - if (new_state.mode_bit != KBD_MODE_BIT_OFF) - kbd_previous_mode_bit = new_state.mode_bit; - return count; - } - - return -EINVAL; -} - -static ssize_t kbd_led_triggers_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct kbd_state state; - bool triggers_enabled; - int level, i, ret; - int len = 0; - - ret = kbd_get_state(&state); - if (ret) - return ret; - - len = 0; - - if (kbd_triggers_supported) { - triggers_enabled = kbd_is_trigger_mode_bit(state.mode_bit); - level = kbd_get_level(&state); - for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); ++i) { - if (!(kbd_info.triggers & BIT(i))) - continue; - if (!kbd_led_triggers[i]) - continue; - if ((triggers_enabled || level <= 0) && - (state.triggers & BIT(i))) - buf[len++] = '+'; - else - buf[len++] = '-'; - len += sprintf(buf+len, "%s ", kbd_led_triggers[i]); - } - } - - if (kbd_als_supported) { - if (kbd_is_als_mode_bit(state.mode_bit)) - len += sprintf(buf+len, "+als "); - else - len += sprintf(buf+len, "-als "); - } - - if (len) - buf[len - 1] = '\n'; - - return len; -} - -static DEVICE_ATTR(start_triggers, S_IRUGO | S_IWUSR, - kbd_led_triggers_show, kbd_led_triggers_store); - -static ssize_t kbd_led_als_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct kbd_state state; - struct kbd_state new_state; - u8 setting; - int ret; - - ret = kstrtou8(buf, 10, &setting); - if (ret) - return ret; - - ret = kbd_get_state(&state); - if (ret) - return ret; - - new_state = state; - new_state.als_setting = setting; - - ret = kbd_set_state_safe(&new_state, &state); - if (ret) - return ret; - - return count; -} - -static ssize_t kbd_led_als_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct kbd_state state; - int ret; - - ret = kbd_get_state(&state); - if (ret) - return ret; - - return sprintf(buf, "%d\n", state.als_setting); -} - -static DEVICE_ATTR(als_setting, S_IRUGO | S_IWUSR, - kbd_led_als_show, kbd_led_als_store); - -static struct attribute *kbd_led_attrs[] = { - &dev_attr_stop_timeout.attr, - &dev_attr_start_triggers.attr, - &dev_attr_als_setting.attr, - NULL, -}; -ATTRIBUTE_GROUPS(kbd_led); - -static enum led_brightness kbd_led_level_get(struct led_classdev *led_cdev) -{ - int ret; - u16 num; - struct kbd_state state; - - if (kbd_get_max_level()) { - ret = kbd_get_state(&state); - if (ret) - return 0; - ret = kbd_get_level(&state); - if (ret < 0) - return 0; - return ret; - } - - if (kbd_get_valid_token_counts()) { - ret = kbd_get_first_active_token_bit(); - if (ret < 0) - return 0; - for (num = kbd_token_bits; num != 0 && ret > 0; --ret) - num &= num - 1; /* clear the first bit set */ - if (num == 0) - return 0; - return ffs(num) - 1; - } - - pr_warn("Keyboard brightness level control not supported\n"); - return 0; -} - -static void kbd_led_level_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - struct kbd_state state; - struct kbd_state new_state; - u16 num; - - if (kbd_get_max_level()) { - if (kbd_get_state(&state)) - return; - new_state = state; - if (kbd_set_level(&new_state, value)) - return; - kbd_set_state_safe(&new_state, &state); - return; - } - - if (kbd_get_valid_token_counts()) { - for (num = kbd_token_bits; num != 0 && value > 0; --value) - num &= num - 1; /* clear the first bit set */ - if (num == 0) - return; - kbd_set_token_bit(ffs(num) - 1); - return; - } - - pr_warn("Keyboard brightness level control not supported\n"); -} - -static struct led_classdev kbd_led = { - .name = "dell::kbd_backlight", - .brightness_set = kbd_led_level_set, - .brightness_get = kbd_led_level_get, - .groups = kbd_led_groups, -}; - -static int __init kbd_led_init(struct device *dev) -{ - kbd_init(); - if (!kbd_led_present) - return -ENODEV; - kbd_led.max_brightness = kbd_get_max_level(); - if (!kbd_led.max_brightness) { - kbd_led.max_brightness = kbd_get_valid_token_counts(); - if (kbd_led.max_brightness) - kbd_led.max_brightness--; - } - return led_classdev_register(dev, &kbd_led); -} - -static void brightness_set_exit(struct led_classdev *led_cdev, - enum led_brightness value) -{ - /* Don't change backlight level on exit */ -}; - -static void kbd_led_exit(void) -{ - if (!kbd_led_present) - return; - kbd_led.brightness_set = brightness_set_exit; - led_classdev_unregister(&kbd_led); -} - static int __init dell_init(void) { int max_intensity = 0; @@ -1879,8 +841,6 @@ static int __init dell_init(void) if (quirks && quirks->touchpad_led) touchpad_led_init(&platform_device->dev); - kbd_led_init(&platform_device->dev); - dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL); if (dell_laptop_dir != NULL) debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL, @@ -1948,7 +908,6 @@ static void __exit dell_exit(void) debugfs_remove_recursive(dell_laptop_dir); if (quirks && quirks->touchpad_led) touchpad_led_exit(); - kbd_led_exit(); i8042_remove_filter(dell_laptop_i8042_filter); cancel_delayed_work_sync(&dell_rfkill_work); backlight_device_unregister(dell_backlight_device); @@ -1965,7 +924,5 @@ module_init(dell_init); module_exit(dell_exit); MODULE_AUTHOR("Matthew Garrett "); -MODULE_AUTHOR("Gabriele Mazzotta "); -MODULE_AUTHOR("Pali Rohár "); MODULE_DESCRIPTION("Dell laptop driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 66977ebf13b3..ff0356fb378f 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -180,20 +180,21 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, struct pnp_dev *dev = data; struct acpi_resource_dma *dma; struct acpi_resource_vendor_typed *vendor_typed; - struct resource r = {0}; + struct resource_win win = {{0}, 0}; + struct resource *r = &win.res; int i, flags; - if (acpi_dev_resource_address_space(res, &r) - || acpi_dev_resource_ext_address_space(res, &r)) { - pnp_add_resource(dev, &r); + if (acpi_dev_resource_address_space(res, &win) + || acpi_dev_resource_ext_address_space(res, &win)) { + pnp_add_resource(dev, &win.res); return AE_OK; } - r.flags = 0; - if (acpi_dev_resource_interrupt(res, 0, &r)) { - pnpacpi_add_irqresource(dev, &r); - for (i = 1; acpi_dev_resource_interrupt(res, i, &r); i++) - pnpacpi_add_irqresource(dev, &r); + r->flags = 0; + if (acpi_dev_resource_interrupt(res, 0, r)) { + pnpacpi_add_irqresource(dev, r); + for (i = 1; acpi_dev_resource_interrupt(res, i, r); i++) + pnpacpi_add_irqresource(dev, r); if (i > 1) { /* @@ -209,7 +210,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, } } return AE_OK; - } else if (r.flags & IORESOURCE_DISABLED) { + } else if (r->flags & IORESOURCE_DISABLED) { pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); return AE_OK; } @@ -218,13 +219,13 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, case ACPI_RESOURCE_TYPE_MEMORY24: case ACPI_RESOURCE_TYPE_MEMORY32: case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - if (acpi_dev_resource_memory(res, &r)) - pnp_add_resource(dev, &r); + if (acpi_dev_resource_memory(res, r)) + pnp_add_resource(dev, r); break; case ACPI_RESOURCE_TYPE_IO: case ACPI_RESOURCE_TYPE_FIXED_IO: - if (acpi_dev_resource_io(res, &r)) - pnp_add_resource(dev, &r); + if (acpi_dev_resource_io(res, r)) + pnp_add_resource(dev, r); break; case ACPI_RESOURCE_TYPE_DMA: dma = &res->data.dma; @@ -410,12 +411,12 @@ static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, if (p->resource_type == ACPI_MEMORY_RANGE) { if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) flags = IORESOURCE_MEM_WRITEABLE; - pnp_register_mem_resource(dev, option_flags, p->minimum, - p->minimum, 0, p->address_length, + pnp_register_mem_resource(dev, option_flags, p->address.minimum, + p->address.minimum, 0, p->address.address_length, flags); } else if (p->resource_type == ACPI_IO_RANGE) - pnp_register_port_resource(dev, option_flags, p->minimum, - p->minimum, 0, p->address_length, + pnp_register_port_resource(dev, option_flags, p->address.minimum, + p->address.minimum, 0, p->address.address_length, IORESOURCE_IO_FIXED); } @@ -429,12 +430,12 @@ static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, if (p->resource_type == ACPI_MEMORY_RANGE) { if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) flags = IORESOURCE_MEM_WRITEABLE; - pnp_register_mem_resource(dev, option_flags, p->minimum, - p->minimum, 0, p->address_length, + pnp_register_mem_resource(dev, option_flags, p->address.minimum, + p->address.minimum, 0, p->address.address_length, flags); } else if (p->resource_type == ACPI_IO_RANGE) - pnp_register_port_resource(dev, option_flags, p->minimum, - p->minimum, 0, p->address_length, + pnp_register_port_resource(dev, option_flags, p->address.minimum, + p->address.minimum, 0, p->address.address_length, IORESOURCE_IO_FIXED); } diff --git a/drivers/power/88pm860x_charger.c b/drivers/power/88pm860x_charger.c index 650930e4fa79..734ec4afa14d 100644 --- a/drivers/power/88pm860x_charger.c +++ b/drivers/power/88pm860x_charger.c @@ -711,6 +711,7 @@ static int pm860x_charger_probe(struct platform_device *pdev) return 0; out_irq: + power_supply_unregister(&info->usb); while (--i >= 0) free_irq(info->irq[i], info); out: diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 0108c2af005b..27b751b995fb 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -315,7 +315,7 @@ config CHARGER_GPIO config CHARGER_MANAGER bool "Battery charger manager for multiple chargers" - depends on REGULATOR && RTC_CLASS + depends on REGULATOR select EXTCON help Say Y to enable charger-manager support, which allows multiple @@ -327,11 +327,16 @@ config CHARGER_MANAGER config CHARGER_MAX14577 tristate "Maxim MAX14577/77836 battery charger driver" depends on MFD_MAX14577 - depends on SYSFS help Say Y to enable support for the battery charger control sysfs and platform data of MAX14577/77836 MUICs. +config CHARGER_MAX77693 + tristate "Maxim MAX77693 battery charger driver" + depends on MFD_MAX77693 + help + Say Y to enable support for the Maxim MAX77693 battery charger. + config CHARGER_MAX8997 tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver" depends on MFD_MAX8997 && REGULATOR_MAX8997 @@ -383,6 +388,14 @@ config CHARGER_TPS65090 Say Y here to enable support for battery charging with TPS65090 PMIC chips. +config BATTERY_GAUGE_LTC2941 + tristate "LTC2941/LTC2943 Battery Gauge Driver" + depends on I2C + help + Say Y here to include support for LTC2941 and LTC2943 Battery + Gauge IC. The driver reports the charge count continuously, and + measures the voltage and temperature every 10 seconds. + config AB8500_BM bool "AB8500 Battery Management Driver" depends on AB8500_CORE && AB8500_GPADC @@ -397,6 +410,14 @@ config BATTERY_GOLDFISH Say Y to enable support for the battery and AC power in the Goldfish emulator. +config BATTERY_RT5033 + tristate "RT5033 fuel gauge support" + depends on MFD_RT5033 + help + This adds support for battery fuel gauge in Richtek RT5033 PMIC. + The fuelgauge calculates and determines the battery state of charge + according to battery open circuit voltage. + source "drivers/power/reset/Kconfig" endif # POWER_SUPPLY diff --git a/drivers/power/Makefile b/drivers/power/Makefile index dfa894273926..36f9e0d10111 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o +obj-$(CONFIG_BATTERY_GAUGE_LTC2941) += ltc2941-battery-gauge.o obj-$(CONFIG_BATTERY_GOLDFISH) += goldfish_battery.o obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o @@ -34,6 +35,7 @@ obj-$(CONFIG_BATTERY_DA9052) += da9052-battery.o obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o obj-$(CONFIG_BATTERY_Z2) += z2_battery.o +obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o @@ -50,6 +52,7 @@ obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o +obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 69b80bcaa9e7..c908658aa31a 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -2435,20 +2435,6 @@ static void ab8500_fg_reinit_work(struct work_struct *work) } } -/** - * ab8500_fg_reinit() - forces FG algorithm to reinitialize with current values - * - * This function can be used to force the FG algorithm to recalculate a new - * voltage based battery capacity. - */ -void ab8500_fg_reinit(void) -{ - struct ab8500_fg *di = ab8500_fg_get(); - /* User won't be notified if a null pointer returned. */ - if (di != NULL) - queue_delayed_work(di->fg_wq, &di->fg_reinit_work, 0); -} - /* Exposure to the sysfs interface */ struct ab8500_fg_sysfs_entry { diff --git a/drivers/power/bq24190_charger.c b/drivers/power/bq24190_charger.c index ad3ff8fbfbbb..d0e8236a6404 100644 --- a/drivers/power/bq24190_charger.c +++ b/drivers/power/bq24190_charger.c @@ -929,7 +929,7 @@ static void bq24190_charger_init(struct power_supply *charger) charger->properties = bq24190_charger_properties; charger->num_properties = ARRAY_SIZE(bq24190_charger_properties); charger->supplied_to = bq24190_charger_supplied_to; - charger->num_supplies = ARRAY_SIZE(bq24190_charger_supplied_to); + charger->num_supplicants = ARRAY_SIZE(bq24190_charger_supplied_to); charger->get_property = bq24190_charger_get_property; charger->set_property = bq24190_charger_set_property; charger->property_is_writeable = bq24190_charger_property_is_writeable; @@ -1208,7 +1208,7 @@ static irqreturn_t bq24190_irq_handler_thread(int irq, void *data) { struct bq24190_dev_info *bdi = data; bool alert_userspace = false; - u8 ss_reg, f_reg; + u8 ss_reg = 0, f_reg = 0; int ret; pm_runtime_get_sync(bdi->dev); diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index a78ac201828e..b72ba7c1bd69 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -76,7 +76,8 @@ /* bq27425 register addresses are same as bq27x00 addresses minus 4 */ #define BQ27425_REG_OFFSET 0x04 -#define BQ27425_REG_SOC 0x18 /* Register address plus offset */ +#define BQ27425_REG_SOC (0x1C + BQ27425_REG_OFFSET) +#define BQ27425_REG_DCAP (0x3C + BQ27425_REG_OFFSET) #define BQ27000_RS 20 /* Resistor sense */ #define BQ27x00_POWER_CONSTANT (256 * 29200 / 1000) @@ -282,9 +283,12 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di) { int ilmd; - if (bq27xxx_is_chip_version_higher(di)) - ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false); - else + if (bq27xxx_is_chip_version_higher(di)) { + if (di->chip == BQ27425) + ilmd = bq27x00_read(di, BQ27425_REG_DCAP, false); + else + ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false); + } else ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true); if (ilmd < 0) { @@ -493,10 +497,11 @@ static void bq27x00_update(struct bq27x00_device_info *di) di->charge_design_full = bq27x00_battery_read_ilmd(di); } - if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) { - di->cache = cache; + if (di->cache.capacity != cache.capacity) power_supply_changed(&di->bat); - } + + if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) + di->cache = cache; di->last_update = jiffies; } diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c index 649052e1f2d9..14b0d85318eb 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c @@ -69,16 +69,10 @@ static LIST_HEAD(cm_list); static DEFINE_MUTEX(cm_list_mtx); /* About in-suspend (suspend-again) monitoring */ -static struct rtc_device *rtc_dev; -/* - * Backup RTC alarm - * Save the wakeup alarm before entering suspend-to-RAM - */ -static struct rtc_wkalrm rtc_wkalarm_save; -/* Backup RTC alarm time in terms of seconds since 01-01-1970 00:00:00 */ -static unsigned long rtc_wkalarm_save_time; +static struct alarm *cm_timer; + static bool cm_suspended; -static bool cm_rtc_set; +static bool cm_timer_set; static unsigned long cm_suspend_duration_ms; /* About normal (not suspended) monitoring */ @@ -87,9 +81,6 @@ static unsigned long next_polling; /* Next appointed polling time */ static struct workqueue_struct *cm_wq; /* init at driver add */ static struct delayed_work cm_monitor_work; /* init at driver add */ -/* Global charger-manager description */ -static struct charger_global_desc *g_desc; /* init with setup_charger_manager */ - /** * is_batt_present - See if the battery presents in place. * @cm: the Charger Manager representing the battery. @@ -1047,10 +1038,13 @@ static bool cm_setup_timer(void) { struct charger_manager *cm; unsigned int wakeup_ms = UINT_MAX; - bool ret = false; + int timer_req = 0; + + if (time_after(next_polling, jiffies)) + CM_MIN_VALID(wakeup_ms, + jiffies_to_msecs(next_polling - jiffies)); mutex_lock(&cm_list_mtx); - list_for_each_entry(cm, &cm_list, entry) { unsigned int fbchk_ms = 0; @@ -1070,162 +1064,38 @@ static bool cm_setup_timer(void) /* Skip if polling is not required for this CM */ if (!is_polling_required(cm) && !cm->emergency_stop) continue; + timer_req++; if (cm->desc->polling_interval_ms == 0) continue; CM_MIN_VALID(wakeup_ms, cm->desc->polling_interval_ms); } - mutex_unlock(&cm_list_mtx); - if (wakeup_ms < UINT_MAX && wakeup_ms > 0) { + if (timer_req && cm_timer) { + ktime_t now, add; + + /* + * Set alarm with the polling interval (wakeup_ms) + * The alarm time should be NOW + CM_RTC_SMALL or later. + */ + if (wakeup_ms == UINT_MAX || + wakeup_ms < CM_RTC_SMALL * MSEC_PER_SEC) + wakeup_ms = 2 * CM_RTC_SMALL * MSEC_PER_SEC; + pr_info("Charger Manager wakeup timer: %u ms\n", wakeup_ms); - if (rtc_dev) { - struct rtc_wkalrm tmp; - unsigned long time, now; - unsigned long add = DIV_ROUND_UP(wakeup_ms, 1000); - /* - * Set alarm with the polling interval (wakeup_ms) - * except when rtc_wkalarm_save comes first. - * However, the alarm time should be NOW + - * CM_RTC_SMALL or later. - */ - tmp.enabled = 1; - rtc_read_time(rtc_dev, &tmp.time); - rtc_tm_to_time(&tmp.time, &now); - if (add < CM_RTC_SMALL) - add = CM_RTC_SMALL; - time = now + add; + now = ktime_get_boottime(); + add = ktime_set(wakeup_ms / MSEC_PER_SEC, + (wakeup_ms % MSEC_PER_SEC) * NSEC_PER_MSEC); + alarm_start(cm_timer, ktime_add(now, add)); - ret = true; + cm_suspend_duration_ms = wakeup_ms; - if (rtc_wkalarm_save.enabled && - rtc_wkalarm_save_time && - rtc_wkalarm_save_time < time) { - if (rtc_wkalarm_save_time < now + CM_RTC_SMALL) - time = now + CM_RTC_SMALL; - else - time = rtc_wkalarm_save_time; - - /* The timer is not appointed by CM */ - ret = false; - } - - pr_info("Waking up after %lu secs\n", time - now); - - rtc_time_to_tm(time, &tmp.time); - rtc_set_alarm(rtc_dev, &tmp); - cm_suspend_duration_ms += wakeup_ms; - return ret; - } + return true; } - - if (rtc_dev) - rtc_set_alarm(rtc_dev, &rtc_wkalarm_save); return false; } -static void _cm_fbchk_in_suspend(struct charger_manager *cm) -{ - unsigned long jiffy_now = jiffies; - - if (!cm->fullbatt_vchk_jiffies_at) - return; - - if (g_desc && g_desc->assume_timer_stops_in_suspend) - jiffy_now += msecs_to_jiffies(cm_suspend_duration_ms); - - /* Execute now if it's going to be executed not too long after */ - jiffy_now += CM_JIFFIES_SMALL; - - if (time_after_eq(jiffy_now, cm->fullbatt_vchk_jiffies_at)) - fullbatt_vchk(&cm->fullbatt_vchk_work.work); -} - -/** - * cm_suspend_again - Determine whether suspend again or not - * - * Returns true if the system should be suspended again - * Returns false if the system should be woken up - */ -bool cm_suspend_again(void) -{ - struct charger_manager *cm; - bool ret = false; - - if (!g_desc || !g_desc->rtc_only_wakeup || !g_desc->rtc_only_wakeup() || - !cm_rtc_set) - return false; - - if (cm_monitor()) - goto out; - - ret = true; - mutex_lock(&cm_list_mtx); - list_for_each_entry(cm, &cm_list, entry) { - _cm_fbchk_in_suspend(cm); - - if (cm->status_save_ext_pwr_inserted != is_ext_pwr_online(cm) || - cm->status_save_batt != is_batt_present(cm)) { - ret = false; - break; - } - } - mutex_unlock(&cm_list_mtx); - - cm_rtc_set = cm_setup_timer(); -out: - /* It's about the time when the non-CM appointed timer goes off */ - if (rtc_wkalarm_save.enabled) { - unsigned long now; - struct rtc_time tmp; - - rtc_read_time(rtc_dev, &tmp); - rtc_tm_to_time(&tmp, &now); - - if (rtc_wkalarm_save_time && - now + CM_RTC_SMALL >= rtc_wkalarm_save_time) - return false; - } - return ret; -} -EXPORT_SYMBOL_GPL(cm_suspend_again); - -/** - * setup_charger_manager - initialize charger_global_desc data - * @gd: pointer to instance of charger_global_desc - */ -int setup_charger_manager(struct charger_global_desc *gd) -{ - if (!gd) - return -EINVAL; - - if (rtc_dev) - rtc_class_close(rtc_dev); - rtc_dev = NULL; - g_desc = NULL; - - if (!gd->rtc_only_wakeup) { - pr_err("The callback rtc_only_wakeup is not given\n"); - return -EINVAL; - } - - if (gd->rtc_name) { - rtc_dev = rtc_class_open(gd->rtc_name); - if (IS_ERR_OR_NULL(rtc_dev)) { - rtc_dev = NULL; - /* Retry at probe. RTC may be not registered yet */ - } - } else { - pr_warn("No wakeup timer is given for charger manager. " - "In-suspend monitoring won't work.\n"); - } - - g_desc = gd; - return 0; -} -EXPORT_SYMBOL_GPL(setup_charger_manager); - /** * charger_extcon_work - enable/diable charger according to the state * of charger cable @@ -1719,6 +1589,12 @@ static inline struct charger_desc *cm_get_drv_data(struct platform_device *pdev) return dev_get_platdata(&pdev->dev); } +static enum alarmtimer_restart cm_timer_func(struct alarm *alarm, ktime_t now) +{ + cm_timer_set = false; + return ALARMTIMER_NORESTART; +} + static int charger_manager_probe(struct platform_device *pdev) { struct charger_desc *desc = cm_get_drv_data(pdev); @@ -1728,16 +1604,6 @@ static int charger_manager_probe(struct platform_device *pdev) union power_supply_propval val; struct power_supply *fuel_gauge; - if (g_desc && !rtc_dev && g_desc->rtc_name) { - rtc_dev = rtc_class_open(g_desc->rtc_name); - if (IS_ERR_OR_NULL(rtc_dev)) { - rtc_dev = NULL; - dev_err(&pdev->dev, "Cannot get RTC %s\n", - g_desc->rtc_name); - return -ENODEV; - } - } - if (IS_ERR(desc)) { dev_err(&pdev->dev, "No platform data (desc) found\n"); return -ENODEV; @@ -1752,6 +1618,12 @@ static int charger_manager_probe(struct platform_device *pdev) cm->dev = &pdev->dev; cm->desc = desc; + /* Initialize alarm timer */ + if (alarmtimer_get_rtcdev()) { + cm_timer = devm_kzalloc(cm->dev, sizeof(*cm_timer), GFP_KERNEL); + alarm_init(cm_timer, ALARM_BOOTTIME, cm_timer_func); + } + /* * The following two do not need to be errors. * Users may intentionally ignore those two features. @@ -1993,38 +1865,41 @@ static int cm_suspend_noirq(struct device *dev) return ret; } +static bool cm_need_to_awake(void) +{ + struct charger_manager *cm; + + if (cm_timer) + return false; + + mutex_lock(&cm_list_mtx); + list_for_each_entry(cm, &cm_list, entry) { + if (is_charging(cm)) { + mutex_unlock(&cm_list_mtx); + return true; + } + } + mutex_unlock(&cm_list_mtx); + + return false; +} + static int cm_suspend_prepare(struct device *dev) { struct charger_manager *cm = dev_get_drvdata(dev); - if (!cm_suspended) { - if (rtc_dev) { - struct rtc_time tmp; - unsigned long now; + if (cm_need_to_awake()) + return -EBUSY; - rtc_read_alarm(rtc_dev, &rtc_wkalarm_save); - rtc_read_time(rtc_dev, &tmp); - - if (rtc_wkalarm_save.enabled) { - rtc_tm_to_time(&rtc_wkalarm_save.time, - &rtc_wkalarm_save_time); - rtc_tm_to_time(&tmp, &now); - if (now > rtc_wkalarm_save_time) - rtc_wkalarm_save_time = 0; - } else { - rtc_wkalarm_save_time = 0; - } - } + if (!cm_suspended) cm_suspended = true; - } - cancel_delayed_work(&cm->fullbatt_vchk_work); - cm->status_save_ext_pwr_inserted = is_ext_pwr_online(cm); - cm->status_save_batt = is_batt_present(cm); + cm_timer_set = cm_setup_timer(); - if (!cm_rtc_set) { - cm_suspend_duration_ms = 0; - cm_rtc_set = cm_setup_timer(); + if (cm_timer_set) { + cancel_work_sync(&setup_polling); + cancel_delayed_work_sync(&cm_monitor_work); + cancel_delayed_work(&cm->fullbatt_vchk_work); } return 0; @@ -2034,18 +1909,21 @@ static void cm_suspend_complete(struct device *dev) { struct charger_manager *cm = dev_get_drvdata(dev); - if (cm_suspended) { - if (rtc_dev) { - struct rtc_wkalrm tmp; - - rtc_read_alarm(rtc_dev, &tmp); - rtc_wkalarm_save.pending = tmp.pending; - rtc_set_alarm(rtc_dev, &rtc_wkalarm_save); - } + if (cm_suspended) cm_suspended = false; - cm_rtc_set = false; + + if (cm_timer_set) { + ktime_t remain; + + alarm_cancel(cm_timer); + cm_timer_set = false; + remain = alarm_expires_remaining(cm_timer); + cm_suspend_duration_ms -= ktime_to_ms(remain); + schedule_work(&setup_polling); } + _cm_monitor(cm); + /* Re-enqueue delayed work (fullbatt_vchk_work) */ if (cm->fullbatt_vchk_jiffies_at) { unsigned long delay = 0; @@ -2060,21 +1938,18 @@ static void cm_suspend_complete(struct device *dev) } /* - * Account for cm_suspend_duration_ms if - * assume_timer_stops_in_suspend is active + * Account for cm_suspend_duration_ms with assuming that + * timer stops in suspend. */ - if (g_desc && g_desc->assume_timer_stops_in_suspend) { - if (delay > cm_suspend_duration_ms) - delay -= cm_suspend_duration_ms; - else - delay = 0; - } + if (delay > cm_suspend_duration_ms) + delay -= cm_suspend_duration_ms; + else + delay = 0; queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work, msecs_to_jiffies(delay)); } device_set_wakeup_capable(cm->dev, false); - uevent_notify(cm, NULL); } static const struct dev_pm_ops charger_manager_pm = { diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c index d02ae02a7590..594e4dbc2d51 100644 --- a/drivers/power/collie_battery.c +++ b/drivers/power/collie_battery.c @@ -26,6 +26,7 @@ static DEFINE_MUTEX(bat_lock); /* protects gpio pins */ static struct work_struct bat_work; static struct ucb1x00 *ucb; +static int wakeup_enabled; struct collie_bat { int status; @@ -291,11 +292,21 @@ static int collie_bat_suspend(struct ucb1x00_dev *dev) { /* flush all pending status updates */ flush_work(&bat_work); + + if (device_may_wakeup(&dev->ucb->dev) && + collie_bat_main.status == POWER_SUPPLY_STATUS_CHARGING) + wakeup_enabled = !enable_irq_wake(gpio_to_irq(COLLIE_GPIO_CO)); + else + wakeup_enabled = 0; + return 0; } static int collie_bat_resume(struct ucb1x00_dev *dev) { + if (wakeup_enabled) + disable_irq_wake(gpio_to_irq(COLLIE_GPIO_CO)); + /* things may have changed while we were away */ schedule_work(&bat_work); return 0; @@ -334,10 +345,15 @@ static int collie_bat_probe(struct ucb1x00_dev *dev) collie_bat_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "main full", &collie_bat_main); - if (!ret) { - schedule_work(&bat_work); - return 0; - } + if (ret) + goto err_irq; + + device_init_wakeup(&ucb->dev, 1); + schedule_work(&bat_work); + + return 0; + +err_irq: power_supply_unregister(&collie_bat_bu.psy); err_psy_reg_bu: power_supply_unregister(&collie_bat_main.psy); diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c index aef74bdf7ab3..b7424c8501f1 100644 --- a/drivers/power/gpio-charger.c +++ b/drivers/power/gpio-charger.c @@ -229,7 +229,7 @@ static int gpio_charger_suspend(struct device *dev) if (device_may_wakeup(dev)) gpio_charger->wakeup_enabled = - enable_irq_wake(gpio_charger->irq); + !enable_irq_wake(gpio_charger->irq); return 0; } @@ -239,7 +239,7 @@ static int gpio_charger_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); - if (gpio_charger->wakeup_enabled) + if (device_may_wakeup(dev) && gpio_charger->wakeup_enabled) disable_irq_wake(gpio_charger->irq); power_supply_changed(&gpio_charger->charger); diff --git a/drivers/power/ltc2941-battery-gauge.c b/drivers/power/ltc2941-battery-gauge.c new file mode 100644 index 000000000000..e31c927a6d16 --- /dev/null +++ b/drivers/power/ltc2941-battery-gauge.c @@ -0,0 +1,547 @@ +/* + * I2C client/driver for the Linear Technology LTC2941 and LTC2943 + * Battery Gas Gauge IC + * + * Copyright (C) 2014 Topic Embedded Systems + * + * Author: Auryn Verwegen + * Author: Mike Looijmans + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define I16_MSB(x) ((x >> 8) & 0xFF) +#define I16_LSB(x) (x & 0xFF) + +#define LTC294X_WORK_DELAY 10 /* Update delay in seconds */ + +#define LTC294X_MAX_VALUE 0xFFFF +#define LTC294X_MID_SUPPLY 0x7FFF + +#define LTC2941_MAX_PRESCALER_EXP 7 +#define LTC2943_MAX_PRESCALER_EXP 6 + +enum ltc294x_reg { + LTC294X_REG_STATUS = 0x00, + LTC294X_REG_CONTROL = 0x01, + LTC294X_REG_ACC_CHARGE_MSB = 0x02, + LTC294X_REG_ACC_CHARGE_LSB = 0x03, + LTC294X_REG_THRESH_HIGH_MSB = 0x04, + LTC294X_REG_THRESH_HIGH_LSB = 0x05, + LTC294X_REG_THRESH_LOW_MSB = 0x06, + LTC294X_REG_THRESH_LOW_LSB = 0x07, + LTC294X_REG_VOLTAGE_MSB = 0x08, + LTC294X_REG_VOLTAGE_LSB = 0x09, + LTC294X_REG_CURRENT_MSB = 0x0E, + LTC294X_REG_CURRENT_LSB = 0x0F, + LTC294X_REG_TEMPERATURE_MSB = 0x14, + LTC294X_REG_TEMPERATURE_LSB = 0x15, +}; + +#define LTC2943_REG_CONTROL_MODE_MASK (BIT(7) | BIT(6)) +#define LTC2943_REG_CONTROL_MODE_SCAN BIT(7) +#define LTC294X_REG_CONTROL_PRESCALER_MASK (BIT(5) | BIT(4) | BIT(3)) +#define LTC294X_REG_CONTROL_SHUTDOWN_MASK (BIT(0)) +#define LTC294X_REG_CONTROL_PRESCALER_SET(x) \ + ((x << 3) & LTC294X_REG_CONTROL_PRESCALER_MASK) +#define LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED 0 + +#define LTC2941_NUM_REGS 0x08 +#define LTC2943_NUM_REGS 0x18 + +struct ltc294x_info { + struct i2c_client *client; /* I2C Client pointer */ + struct power_supply supply; /* Supply pointer */ + struct delayed_work work; /* Work scheduler */ + int num_regs; /* Number of registers (chip type) */ + int id; /* Identifier of ltc294x chip */ + int charge; /* Last charge register content */ + int r_sense; /* mOhm */ + int Qlsb; /* nAh */ +}; + +static DEFINE_IDR(ltc294x_id); +static DEFINE_MUTEX(ltc294x_lock); + +static inline int convert_bin_to_uAh( + const struct ltc294x_info *info, int Q) +{ + return ((Q * (info->Qlsb / 10))) / 100; +} + +static inline int convert_uAh_to_bin( + const struct ltc294x_info *info, int uAh) +{ + int Q; + + Q = (uAh * 100) / (info->Qlsb/10); + return (Q < LTC294X_MAX_VALUE) ? Q : LTC294X_MAX_VALUE; +} + +static int ltc294x_read_regs(struct i2c_client *client, + enum ltc294x_reg reg, u8 *buf, int num_regs) +{ + int ret; + struct i2c_msg msgs[2] = { }; + u8 reg_start = reg; + + msgs[0].addr = client->addr; + msgs[0].len = 1; + msgs[0].buf = ®_start; + + msgs[1].addr = client->addr; + msgs[1].len = num_regs; + msgs[1].buf = buf; + msgs[1].flags = I2C_M_RD; + + ret = i2c_transfer(client->adapter, &msgs[0], 2); + if (ret < 0) { + dev_err(&client->dev, "ltc2941 read_reg failed!\n"); + return ret; + } + + dev_dbg(&client->dev, "%s (%#x, %d) -> %#x\n", + __func__, reg, num_regs, *buf); + + return 0; +} + +static int ltc294x_write_regs(struct i2c_client *client, + enum ltc294x_reg reg, const u8 *buf, int num_regs) +{ + int ret; + u8 reg_start = reg; + + ret = i2c_smbus_write_i2c_block_data(client, reg_start, num_regs, buf); + if (ret < 0) { + dev_err(&client->dev, "ltc2941 write_reg failed!\n"); + return ret; + } + + dev_dbg(&client->dev, "%s (%#x, %d) -> %#x\n", + __func__, reg, num_regs, *buf); + + return 0; +} + +static int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp) +{ + int ret; + u8 value; + u8 control; + + /* Read status and control registers */ + ret = ltc294x_read_regs(info->client, LTC294X_REG_CONTROL, &value, 1); + if (ret < 0) { + dev_err(&info->client->dev, + "Could not read registers from device\n"); + goto error_exit; + } + + control = LTC294X_REG_CONTROL_PRESCALER_SET(prescaler_exp) | + LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED; + /* Put the 2943 into "monitor" mode, so it measures every 10 sec */ + if (info->num_regs == LTC2943_NUM_REGS) + control |= LTC2943_REG_CONTROL_MODE_SCAN; + + if (value != control) { + ret = ltc294x_write_regs(info->client, + LTC294X_REG_CONTROL, &control, 1); + if (ret < 0) { + dev_err(&info->client->dev, + "Could not write register\n"); + goto error_exit; + } + } + + return 0; + +error_exit: + return ret; +} + +static int ltc294x_read_charge_register(const struct ltc294x_info *info) +{ + int ret; + u8 datar[2]; + + ret = ltc294x_read_regs(info->client, + LTC294X_REG_ACC_CHARGE_MSB, &datar[0], 2); + if (ret < 0) + return ret; + return (datar[0] << 8) + datar[1]; +} + +static int ltc294x_get_charge_now(const struct ltc294x_info *info, int *val) +{ + int value = ltc294x_read_charge_register(info); + + if (value < 0) + return value; + /* When r_sense < 0, this counts up when the battery discharges */ + if (info->Qlsb < 0) + value -= 0xFFFF; + *val = convert_bin_to_uAh(info, value); + return 0; +} + +static int ltc294x_set_charge_now(const struct ltc294x_info *info, int val) +{ + int ret; + u8 dataw[2]; + u8 ctrl_reg; + s32 value; + + value = convert_uAh_to_bin(info, val); + /* Direction depends on how sense+/- were connected */ + if (info->Qlsb < 0) + value += 0xFFFF; + if ((value < 0) || (value > 0xFFFF)) /* input validation */ + return -EINVAL; + + /* Read control register */ + ret = ltc294x_read_regs(info->client, + LTC294X_REG_CONTROL, &ctrl_reg, 1); + if (ret < 0) + return ret; + /* Disable analog section */ + ctrl_reg |= LTC294X_REG_CONTROL_SHUTDOWN_MASK; + ret = ltc294x_write_regs(info->client, + LTC294X_REG_CONTROL, &ctrl_reg, 1); + if (ret < 0) + return ret; + /* Set new charge value */ + dataw[0] = I16_MSB(value); + dataw[1] = I16_LSB(value); + ret = ltc294x_write_regs(info->client, + LTC294X_REG_ACC_CHARGE_MSB, &dataw[0], 2); + if (ret < 0) + goto error_exit; + /* Enable analog section */ +error_exit: + ctrl_reg &= ~LTC294X_REG_CONTROL_SHUTDOWN_MASK; + ret = ltc294x_write_regs(info->client, + LTC294X_REG_CONTROL, &ctrl_reg, 1); + + return ret < 0 ? ret : 0; +} + +static int ltc294x_get_charge_counter( + const struct ltc294x_info *info, int *val) +{ + int value = ltc294x_read_charge_register(info); + + if (value < 0) + return value; + value -= LTC294X_MID_SUPPLY; + *val = convert_bin_to_uAh(info, value); + return 0; +} + +static int ltc294x_get_voltage(const struct ltc294x_info *info, int *val) +{ + int ret; + u8 datar[2]; + u32 value; + + ret = ltc294x_read_regs(info->client, + LTC294X_REG_VOLTAGE_MSB, &datar[0], 2); + value = (datar[0] << 8) | datar[1]; + *val = ((value * 23600) / 0xFFFF) * 1000; /* in uV */ + return ret; +} + +static int ltc294x_get_current(const struct ltc294x_info *info, int *val) +{ + int ret; + u8 datar[2]; + s32 value; + + ret = ltc294x_read_regs(info->client, + LTC294X_REG_CURRENT_MSB, &datar[0], 2); + value = (datar[0] << 8) | datar[1]; + value -= 0x7FFF; + /* Value is in range -32k..+32k, r_sense is usually 10..50 mOhm, + * the formula below keeps everything in s32 range while preserving + * enough digits */ + *val = 1000 * ((60000 * value) / (info->r_sense * 0x7FFF)); /* in uA */ + return ret; +} + +static int ltc294x_get_temperature(const struct ltc294x_info *info, int *val) +{ + int ret; + u8 datar[2]; + u32 value; + + ret = ltc294x_read_regs(info->client, + LTC294X_REG_TEMPERATURE_MSB, &datar[0], 2); + value = (datar[0] << 8) | datar[1]; + /* Full-scale is 510 Kelvin, convert to centidegrees */ + *val = (((51000 * value) / 0xFFFF) - 27215); + return ret; +} + +static int ltc294x_get_property(struct power_supply *psy, + enum power_supply_property prop, + union power_supply_propval *val) +{ + struct ltc294x_info *info = + container_of(psy, struct ltc294x_info, supply); + + switch (prop) { + case POWER_SUPPLY_PROP_CHARGE_NOW: + return ltc294x_get_charge_now(info, &val->intval); + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + return ltc294x_get_charge_counter(info, &val->intval); + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + return ltc294x_get_voltage(info, &val->intval); + case POWER_SUPPLY_PROP_CURRENT_NOW: + return ltc294x_get_current(info, &val->intval); + case POWER_SUPPLY_PROP_TEMP: + return ltc294x_get_temperature(info, &val->intval); + default: + return -EINVAL; + } +} + +static int ltc294x_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct ltc294x_info *info = + container_of(psy, struct ltc294x_info, supply); + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_NOW: + return ltc294x_set_charge_now(info, val->intval); + default: + return -EPERM; + } +} + +static int ltc294x_property_is_writeable( + struct power_supply *psy, enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_NOW: + return 1; + default: + return 0; + } +} + +static void ltc294x_update(struct ltc294x_info *info) +{ + int charge = ltc294x_read_charge_register(info); + + if (charge != info->charge) { + info->charge = charge; + power_supply_changed(&info->supply); + } +} + +static void ltc294x_work(struct work_struct *work) +{ + struct ltc294x_info *info; + + info = container_of(work, struct ltc294x_info, work.work); + ltc294x_update(info); + schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ); +} + +static enum power_supply_property ltc294x_properties[] = { + POWER_SUPPLY_PROP_CHARGE_COUNTER, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_TEMP, +}; + +static int ltc294x_i2c_remove(struct i2c_client *client) +{ + struct ltc294x_info *info = i2c_get_clientdata(client); + + cancel_delayed_work(&info->work); + power_supply_unregister(&info->supply); + kfree(info->supply.name); + mutex_lock(<c294x_lock); + idr_remove(<c294x_id, info->id); + mutex_unlock(<c294x_lock); + return 0; +} + +static int ltc294x_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ltc294x_info *info; + int ret; + int num; + u32 prescaler_exp; + s32 r_sense; + struct device_node *np; + + mutex_lock(<c294x_lock); + ret = idr_alloc(<c294x_id, client, 0, 0, GFP_KERNEL); + mutex_unlock(<c294x_lock); + if (ret < 0) + goto fail_id; + + num = ret; + + info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); + if (info == NULL) { + ret = -ENOMEM; + goto fail_info; + } + + i2c_set_clientdata(client, info); + + info->num_regs = id->driver_data; + info->supply.name = kasprintf(GFP_KERNEL, "%s-%d", client->name, num); + if (!info->supply.name) { + ret = -ENOMEM; + goto fail_name; + } + + np = of_node_get(client->dev.of_node); + + /* r_sense can be negative, when sense+ is connected to the battery + * instead of the sense-. This results in reversed measurements. */ + ret = of_property_read_u32(np, "lltc,resistor-sense", &r_sense); + if (ret < 0) { + dev_err(&client->dev, + "Could not find lltc,resistor-sense in devicetree\n"); + goto fail_name; + } + info->r_sense = r_sense; + + ret = of_property_read_u32(np, "lltc,prescaler-exponent", + &prescaler_exp); + if (ret < 0) { + dev_warn(&client->dev, + "lltc,prescaler-exponent not in devicetree\n"); + prescaler_exp = LTC2941_MAX_PRESCALER_EXP; + } + + if (info->num_regs == LTC2943_NUM_REGS) { + if (prescaler_exp > LTC2943_MAX_PRESCALER_EXP) + prescaler_exp = LTC2943_MAX_PRESCALER_EXP; + info->Qlsb = ((340 * 50000) / r_sense) / + (4096 / (1 << (2*prescaler_exp))); + } else { + if (prescaler_exp > LTC2941_MAX_PRESCALER_EXP) + prescaler_exp = LTC2941_MAX_PRESCALER_EXP; + info->Qlsb = ((58 * 50000) / r_sense) / + (128 / (1 << prescaler_exp)); + } + + info->client = client; + info->id = num; + info->supply.type = POWER_SUPPLY_TYPE_BATTERY; + info->supply.properties = ltc294x_properties; + if (info->num_regs >= LTC294X_REG_TEMPERATURE_LSB) + info->supply.num_properties = + ARRAY_SIZE(ltc294x_properties); + else if (info->num_regs >= LTC294X_REG_CURRENT_LSB) + info->supply.num_properties = + ARRAY_SIZE(ltc294x_properties) - 1; + else if (info->num_regs >= LTC294X_REG_VOLTAGE_LSB) + info->supply.num_properties = + ARRAY_SIZE(ltc294x_properties) - 2; + else + info->supply.num_properties = + ARRAY_SIZE(ltc294x_properties) - 3; + info->supply.get_property = ltc294x_get_property; + info->supply.set_property = ltc294x_set_property; + info->supply.property_is_writeable = ltc294x_property_is_writeable; + info->supply.external_power_changed = NULL; + + INIT_DELAYED_WORK(&info->work, ltc294x_work); + + ret = ltc294x_reset(info, prescaler_exp); + if (ret < 0) { + dev_err(&client->dev, "Communication with chip failed\n"); + goto fail_comm; + } + + ret = power_supply_register(&client->dev, &info->supply); + if (ret) { + dev_err(&client->dev, "failed to register ltc2941\n"); + goto fail_register; + } else { + schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ); + } + + return 0; + +fail_register: + kfree(info->supply.name); +fail_comm: +fail_name: +fail_info: + mutex_lock(<c294x_lock); + idr_remove(<c294x_id, num); + mutex_unlock(<c294x_lock); +fail_id: + return ret; +} + +#ifdef CONFIG_PM_SLEEP + +static int ltc294x_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ltc294x_info *info = i2c_get_clientdata(client); + + cancel_delayed_work(&info->work); + return 0; +} + +static int ltc294x_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ltc294x_info *info = i2c_get_clientdata(client); + + schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ); + return 0; +} + +static SIMPLE_DEV_PM_OPS(ltc294x_pm_ops, ltc294x_suspend, ltc294x_resume); +#define LTC294X_PM_OPS (<c294x_pm_ops) + +#else +#define LTC294X_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + + +static const struct i2c_device_id ltc294x_i2c_id[] = { + {"ltc2941", LTC2941_NUM_REGS}, + {"ltc2943", LTC2943_NUM_REGS}, + { }, +}; +MODULE_DEVICE_TABLE(i2c, ltc294x_i2c_id); + +static struct i2c_driver ltc294x_driver = { + .driver = { + .name = "LTC2941", + .pm = LTC294X_PM_OPS, + }, + .probe = ltc294x_i2c_probe, + .remove = ltc294x_i2c_remove, + .id_table = ltc294x_i2c_id, +}; +module_i2c_driver(ltc294x_driver); + +MODULE_AUTHOR("Auryn Verwegen, Topic Embedded Systems"); +MODULE_AUTHOR("Mike Looijmans, Topic Embedded Products"); +MODULE_DESCRIPTION("LTC2941/LTC2943 Battery Gas Gauge IC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c index 66da691c41cf..1da6c5fbdff5 100644 --- a/drivers/power/max17042_battery.c +++ b/drivers/power/max17042_battery.c @@ -658,7 +658,7 @@ max17042_get_pdata(struct device *dev) } #endif -static struct regmap_config max17042_regmap_config = { +static const struct regmap_config max17042_regmap_config = { .reg_bits = 8, .val_bits = 16, .val_format_endian = REGMAP_ENDIAN_NATIVE, diff --git a/drivers/power/max77693_charger.c b/drivers/power/max77693_charger.c new file mode 100644 index 000000000000..b042970fdeaf --- /dev/null +++ b/drivers/power/max77693_charger.c @@ -0,0 +1,753 @@ +/* + * max77693_charger.c - Battery charger driver for the Maxim 77693 + * + * Copyright (C) 2014 Samsung Electronics + * Krzysztof Kozlowski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 + +static const char *max77693_charger_name = "max77693-charger"; +static const char *max77693_charger_model = "MAX77693"; +static const char *max77693_charger_manufacturer = "Maxim Integrated"; + +struct max77693_charger { + struct device *dev; + struct max77693_dev *max77693; + struct power_supply charger; + + u32 constant_volt; + u32 min_system_volt; + u32 thermal_regulation_temp; + u32 batttery_overcurrent; + u32 charge_input_threshold_volt; +}; + +static int max77693_get_charger_state(struct regmap *regmap) +{ + int state; + unsigned int data; + + if (regmap_read(regmap, MAX77693_CHG_REG_CHG_DETAILS_01, &data) < 0) + return POWER_SUPPLY_STATUS_UNKNOWN; + + data &= CHG_DETAILS_01_CHG_MASK; + data >>= CHG_DETAILS_01_CHG_SHIFT; + + switch (data) { + case MAX77693_CHARGING_PREQUALIFICATION: + case MAX77693_CHARGING_FAST_CONST_CURRENT: + case MAX77693_CHARGING_FAST_CONST_VOLTAGE: + case MAX77693_CHARGING_TOP_OFF: + /* In high temp the charging current is reduced, but still charging */ + case MAX77693_CHARGING_HIGH_TEMP: + state = POWER_SUPPLY_STATUS_CHARGING; + break; + case MAX77693_CHARGING_DONE: + state = POWER_SUPPLY_STATUS_FULL; + break; + case MAX77693_CHARGING_TIMER_EXPIRED: + case MAX77693_CHARGING_THERMISTOR_SUSPEND: + state = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + case MAX77693_CHARGING_OFF: + case MAX77693_CHARGING_OVER_TEMP: + case MAX77693_CHARGING_WATCHDOG_EXPIRED: + state = POWER_SUPPLY_STATUS_DISCHARGING; + break; + case MAX77693_CHARGING_RESERVED: + default: + state = POWER_SUPPLY_STATUS_UNKNOWN; + } + + return state; +} + +static int max77693_get_charge_type(struct regmap *regmap) +{ + int state; + unsigned int data; + + if (regmap_read(regmap, MAX77693_CHG_REG_CHG_DETAILS_01, &data) < 0) + return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; + + data &= CHG_DETAILS_01_CHG_MASK; + data >>= CHG_DETAILS_01_CHG_SHIFT; + + switch (data) { + case MAX77693_CHARGING_PREQUALIFICATION: + /* + * Top-off: trickle or fast? In top-off the current varies between + * 100 and 250 mA. It is higher than prequalification current. + */ + case MAX77693_CHARGING_TOP_OFF: + state = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + case MAX77693_CHARGING_FAST_CONST_CURRENT: + case MAX77693_CHARGING_FAST_CONST_VOLTAGE: + /* In high temp the charging current is reduced, but still charging */ + case MAX77693_CHARGING_HIGH_TEMP: + state = POWER_SUPPLY_CHARGE_TYPE_FAST; + break; + case MAX77693_CHARGING_DONE: + case MAX77693_CHARGING_TIMER_EXPIRED: + case MAX77693_CHARGING_THERMISTOR_SUSPEND: + case MAX77693_CHARGING_OFF: + case MAX77693_CHARGING_OVER_TEMP: + case MAX77693_CHARGING_WATCHDOG_EXPIRED: + state = POWER_SUPPLY_CHARGE_TYPE_NONE; + break; + case MAX77693_CHARGING_RESERVED: + default: + state = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; + } + + return state; +} + +/* + * Supported health statuses: + * - POWER_SUPPLY_HEALTH_DEAD + * - POWER_SUPPLY_HEALTH_GOOD + * - POWER_SUPPLY_HEALTH_OVERVOLTAGE + * - POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE + * - POWER_SUPPLY_HEALTH_UNKNOWN + * - POWER_SUPPLY_HEALTH_UNSPEC_FAILURE + */ +static int max77693_get_battery_health(struct regmap *regmap) +{ + int state; + unsigned int data; + + if (regmap_read(regmap, MAX77693_CHG_REG_CHG_DETAILS_01, &data) < 0) + return POWER_SUPPLY_HEALTH_UNKNOWN; + + data &= CHG_DETAILS_01_BAT_MASK; + data >>= CHG_DETAILS_01_BAT_SHIFT; + + switch (data) { + case MAX77693_BATTERY_NOBAT: + state = POWER_SUPPLY_HEALTH_DEAD; + break; + case MAX77693_BATTERY_PREQUALIFICATION: + case MAX77693_BATTERY_GOOD: + case MAX77693_BATTERY_LOWVOLTAGE: + state = POWER_SUPPLY_HEALTH_GOOD; + break; + case MAX77693_BATTERY_TIMER_EXPIRED: + /* + * Took longer to charge than expected, charging suspended. + * Damaged battery? + */ + state = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; + break; + case MAX77693_BATTERY_OVERVOLTAGE: + state = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + break; + case MAX77693_BATTERY_OVERCURRENT: + state = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + break; + case MAX77693_BATTERY_RESERVED: + default: + state = POWER_SUPPLY_HEALTH_UNKNOWN; + break; + } + + return state; +} + +static int max77693_get_present(struct regmap *regmap) +{ + unsigned int data; + + /* + * Read CHG_INT_OK register. High DETBAT bit here should be + * equal to value 0x0 in CHG_DETAILS_01/BAT field. + */ + regmap_read(regmap, MAX77693_CHG_REG_CHG_INT_OK, &data); + if (data & CHG_INT_OK_DETBAT_MASK) + return 0; + return 1; +} + +static int max77693_get_online(struct regmap *regmap) +{ + unsigned int data; + + regmap_read(regmap, MAX77693_CHG_REG_CHG_INT_OK, &data); + if (data & CHG_INT_OK_CHGIN_MASK) + return 1; + return 0; +} + +static enum power_supply_property max77693_charger_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static int max77693_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct max77693_charger *chg = container_of(psy, + struct max77693_charger, + charger); + struct regmap *regmap = chg->max77693->regmap; + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = max77693_get_charger_state(regmap); + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + val->intval = max77693_get_charge_type(regmap); + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = max77693_get_battery_health(regmap); + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = max77693_get_present(regmap); + break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = max77693_get_online(regmap); + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = max77693_charger_model; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = max77693_charger_manufacturer; + break; + default: + return -EINVAL; + } + + return ret; +} + +static ssize_t device_attr_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count, + int (*fn)(struct max77693_charger *, unsigned long)) +{ + struct max77693_charger *chg = dev_get_drvdata(dev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + ret = fn(chg, val); + if (ret) + return ret; + + return count; +} + +static ssize_t fast_charge_timer_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct max77693_charger *chg = dev_get_drvdata(dev); + unsigned int data, val; + int ret; + + ret = regmap_read(chg->max77693->regmap, MAX77693_CHG_REG_CHG_CNFG_01, + &data); + if (ret < 0) + return ret; + + data &= CHG_CNFG_01_FCHGTIME_MASK; + data >>= CHG_CNFG_01_FCHGTIME_SHIFT; + switch (data) { + case 0x1 ... 0x7: + /* Starting from 4 hours, step by 2 hours */ + val = 4 + (data - 1) * 2; + break; + case 0x0: + default: + val = 0; + break; + } + + return scnprintf(buf, PAGE_SIZE, "%u\n", val); +} + +static int max77693_set_fast_charge_timer(struct max77693_charger *chg, + unsigned long hours) +{ + unsigned int data; + + /* + * 0x00 - disable + * 0x01 - 4h + * 0x02 - 6h + * ... + * 0x07 - 16h + * Round down odd values. + */ + switch (hours) { + case 4 ... 16: + data = (hours - 4) / 2 + 1; + break; + case 0: + /* Disable */ + data = 0; + break; + default: + return -EINVAL; + } + data <<= CHG_CNFG_01_FCHGTIME_SHIFT; + + return regmap_update_bits(chg->max77693->regmap, + MAX77693_CHG_REG_CHG_CNFG_01, + CHG_CNFG_01_FCHGTIME_MASK, data); +} + +static ssize_t fast_charge_timer_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return device_attr_store(dev, attr, buf, count, + max77693_set_fast_charge_timer); +} + +static ssize_t top_off_threshold_current_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct max77693_charger *chg = dev_get_drvdata(dev); + unsigned int data, val; + int ret; + + ret = regmap_read(chg->max77693->regmap, MAX77693_CHG_REG_CHG_CNFG_03, + &data); + if (ret < 0) + return ret; + + data &= CHG_CNFG_03_TOITH_MASK; + data >>= CHG_CNFG_03_TOITH_SHIFT; + + if (data <= 0x04) + val = 100000 + data * 25000; + else + val = data * 50000; + + return scnprintf(buf, PAGE_SIZE, "%u\n", val); +} + +static int max77693_set_top_off_threshold_current(struct max77693_charger *chg, + unsigned long uamp) +{ + unsigned int data; + + if (uamp < 100000 || uamp > 350000) + return -EINVAL; + + if (uamp <= 200000) + data = (uamp - 100000) / 25000; + else + /* (200000, 350000> */ + data = uamp / 50000; + + data <<= CHG_CNFG_03_TOITH_SHIFT; + + return regmap_update_bits(chg->max77693->regmap, + MAX77693_CHG_REG_CHG_CNFG_03, + CHG_CNFG_03_TOITH_MASK, data); +} + +static ssize_t top_off_threshold_current_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return device_attr_store(dev, attr, buf, count, + max77693_set_top_off_threshold_current); +} + +static ssize_t top_off_timer_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct max77693_charger *chg = dev_get_drvdata(dev); + unsigned int data, val; + int ret; + + ret = regmap_read(chg->max77693->regmap, MAX77693_CHG_REG_CHG_CNFG_03, + &data); + if (ret < 0) + return ret; + + data &= CHG_CNFG_03_TOTIME_MASK; + data >>= CHG_CNFG_03_TOTIME_SHIFT; + + val = data * 10; + + return scnprintf(buf, PAGE_SIZE, "%u\n", val); +} + +static int max77693_set_top_off_timer(struct max77693_charger *chg, + unsigned long minutes) +{ + unsigned int data; + + if (minutes > 70) + return -EINVAL; + + data = minutes / 10; + data <<= CHG_CNFG_03_TOTIME_SHIFT; + + return regmap_update_bits(chg->max77693->regmap, + MAX77693_CHG_REG_CHG_CNFG_03, + CHG_CNFG_03_TOTIME_MASK, data); +} + +static ssize_t top_off_timer_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return device_attr_store(dev, attr, buf, count, + max77693_set_top_off_timer); +} + +static DEVICE_ATTR_RW(fast_charge_timer); +static DEVICE_ATTR_RW(top_off_threshold_current); +static DEVICE_ATTR_RW(top_off_timer); + +static int max77693_set_constant_volt(struct max77693_charger *chg, + unsigned int uvolt) +{ + unsigned int data; + + /* + * 0x00 - 3.650 V + * 0x01 - 3.675 V + * ... + * 0x1b - 4.325 V + * 0x1c - 4.340 V + * 0x1d - 4.350 V + * 0x1e - 4.375 V + * 0x1f - 4.400 V + */ + if (uvolt >= 3650000 && uvolt < 4340000) + data = (uvolt - 3650000) / 25000; + else if (uvolt >= 4340000 && uvolt < 4350000) + data = 0x1c; + else if (uvolt >= 4350000 && uvolt <= 4400000) + data = 0x1d + (uvolt - 4350000) / 25000; + else { + dev_err(chg->dev, "Wrong value for charging constant voltage\n"); + return -EINVAL; + } + + data <<= CHG_CNFG_04_CHGCVPRM_SHIFT; + + dev_dbg(chg->dev, "Charging constant voltage: %u (0x%x)\n", uvolt, + data); + + return regmap_update_bits(chg->max77693->regmap, + MAX77693_CHG_REG_CHG_CNFG_04, + CHG_CNFG_04_CHGCVPRM_MASK, data); +} + +static int max77693_set_min_system_volt(struct max77693_charger *chg, + unsigned int uvolt) +{ + unsigned int data; + + if (uvolt < 3000000 || uvolt > 3700000) { + dev_err(chg->dev, "Wrong value for minimum system regulation voltage\n"); + return -EINVAL; + } + + data = (uvolt - 3000000) / 100000; + + data <<= CHG_CNFG_04_MINVSYS_SHIFT; + + dev_dbg(chg->dev, "Minimum system regulation voltage: %u (0x%x)\n", + uvolt, data); + + return regmap_update_bits(chg->max77693->regmap, + MAX77693_CHG_REG_CHG_CNFG_04, + CHG_CNFG_04_MINVSYS_MASK, data); +} + +static int max77693_set_thermal_regulation_temp(struct max77693_charger *chg, + unsigned int cels) +{ + unsigned int data; + + switch (cels) { + case 70: + case 85: + case 100: + case 115: + data = (cels - 70) / 15; + break; + default: + dev_err(chg->dev, "Wrong value for thermal regulation loop temperature\n"); + return -EINVAL; + } + + data <<= CHG_CNFG_07_REGTEMP_SHIFT; + + dev_dbg(chg->dev, "Thermal regulation loop temperature: %u (0x%x)\n", + cels, data); + + return regmap_update_bits(chg->max77693->regmap, + MAX77693_CHG_REG_CHG_CNFG_07, + CHG_CNFG_07_REGTEMP_MASK, data); +} + +static int max77693_set_batttery_overcurrent(struct max77693_charger *chg, + unsigned int uamp) +{ + unsigned int data; + + if (uamp && (uamp < 2000000 || uamp > 3500000)) { + dev_err(chg->dev, "Wrong value for battery overcurrent\n"); + return -EINVAL; + } + + if (uamp) + data = ((uamp - 2000000) / 250000) + 1; + else + data = 0; /* disable */ + + data <<= CHG_CNFG_12_B2SOVRC_SHIFT; + + dev_dbg(chg->dev, "Battery overcurrent: %u (0x%x)\n", uamp, data); + + return regmap_update_bits(chg->max77693->regmap, + MAX77693_CHG_REG_CHG_CNFG_12, + CHG_CNFG_12_B2SOVRC_MASK, data); +} + +static int max77693_set_charge_input_threshold_volt(struct max77693_charger *chg, + unsigned int uvolt) +{ + unsigned int data; + + switch (uvolt) { + case 4300000: + data = 0x0; + break; + case 4700000: + case 4800000: + case 4900000: + data = (uvolt - 4700000) / 100000; + default: + dev_err(chg->dev, "Wrong value for charge input voltage regulation threshold\n"); + return -EINVAL; + } + + data <<= CHG_CNFG_12_VCHGINREG_SHIFT; + + dev_dbg(chg->dev, "Charge input voltage regulation threshold: %u (0x%x)\n", + uvolt, data); + + return regmap_update_bits(chg->max77693->regmap, + MAX77693_CHG_REG_CHG_CNFG_12, + CHG_CNFG_12_VCHGINREG_MASK, data); +} + +/* + * Sets charger registers to proper and safe default values. + */ +static int max77693_reg_init(struct max77693_charger *chg) +{ + int ret; + unsigned int data; + + /* Unlock charger register protection */ + data = (0x3 << CHG_CNFG_06_CHGPROT_SHIFT); + ret = regmap_update_bits(chg->max77693->regmap, + MAX77693_CHG_REG_CHG_CNFG_06, + CHG_CNFG_06_CHGPROT_MASK, data); + if (ret) { + dev_err(chg->dev, "Error unlocking registers: %d\n", ret); + return ret; + } + + ret = max77693_set_fast_charge_timer(chg, DEFAULT_FAST_CHARGE_TIMER); + if (ret) + return ret; + + ret = max77693_set_top_off_threshold_current(chg, + DEFAULT_TOP_OFF_THRESHOLD_CURRENT); + if (ret) + return ret; + + ret = max77693_set_top_off_timer(chg, DEFAULT_TOP_OFF_TIMER); + if (ret) + return ret; + + ret = max77693_set_constant_volt(chg, chg->constant_volt); + if (ret) + return ret; + + ret = max77693_set_min_system_volt(chg, chg->min_system_volt); + if (ret) + return ret; + + ret = max77693_set_thermal_regulation_temp(chg, + chg->thermal_regulation_temp); + if (ret) + return ret; + + ret = max77693_set_batttery_overcurrent(chg, chg->batttery_overcurrent); + if (ret) + return ret; + + return max77693_set_charge_input_threshold_volt(chg, + chg->charge_input_threshold_volt); +} + +#ifdef CONFIG_OF +static int max77693_dt_init(struct device *dev, struct max77693_charger *chg) +{ + struct device_node *np = dev->of_node; + + if (!np) { + dev_err(dev, "no charger OF node\n"); + return -EINVAL; + } + + if (of_property_read_u32(np, "maxim,constant-microvolt", + &chg->constant_volt)) + chg->constant_volt = DEFAULT_CONSTANT_VOLT; + + if (of_property_read_u32(np, "maxim,min-system-microvolt", + &chg->min_system_volt)) + chg->min_system_volt = DEFAULT_MIN_SYSTEM_VOLT; + + if (of_property_read_u32(np, "maxim,thermal-regulation-celsius", + &chg->thermal_regulation_temp)) + chg->thermal_regulation_temp = DEFAULT_THERMAL_REGULATION_TEMP; + + if (of_property_read_u32(np, "maxim,battery-overcurrent-microamp", + &chg->batttery_overcurrent)) + chg->batttery_overcurrent = DEFAULT_BATTERY_OVERCURRENT; + + if (of_property_read_u32(np, "maxim,charge-input-threshold-microvolt", + &chg->charge_input_threshold_volt)) + chg->charge_input_threshold_volt = + DEFAULT_CHARGER_INPUT_THRESHOLD_VOLT; + + return 0; +} +#else /* CONFIG_OF */ +static int max77693_dt_init(struct device *dev, struct max77693_charger *chg) +{ + return 0; +} +#endif /* CONFIG_OF */ + +static int max77693_charger_probe(struct platform_device *pdev) +{ + struct max77693_charger *chg; + struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); + int ret; + + chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL); + if (!chg) + return -ENOMEM; + + platform_set_drvdata(pdev, chg); + chg->dev = &pdev->dev; + chg->max77693 = max77693; + + ret = max77693_dt_init(&pdev->dev, chg); + if (ret) + return ret; + + ret = max77693_reg_init(chg); + if (ret) + return ret; + + chg->charger.name = max77693_charger_name; + chg->charger.type = POWER_SUPPLY_TYPE_BATTERY; + chg->charger.properties = max77693_charger_props; + chg->charger.num_properties = ARRAY_SIZE(max77693_charger_props); + chg->charger.get_property = max77693_charger_get_property; + + ret = device_create_file(&pdev->dev, &dev_attr_fast_charge_timer); + if (ret) { + dev_err(&pdev->dev, "failed: create fast charge timer sysfs entry\n"); + goto err; + } + + ret = device_create_file(&pdev->dev, + &dev_attr_top_off_threshold_current); + if (ret) { + dev_err(&pdev->dev, "failed: create top off current sysfs entry\n"); + goto err; + } + + ret = device_create_file(&pdev->dev, &dev_attr_top_off_timer); + if (ret) { + dev_err(&pdev->dev, "failed: create top off timer sysfs entry\n"); + goto err; + } + + ret = power_supply_register(&pdev->dev, &chg->charger); + if (ret) { + dev_err(&pdev->dev, "failed: power supply register\n"); + goto err; + } + + return 0; + +err: + device_remove_file(&pdev->dev, &dev_attr_top_off_timer); + device_remove_file(&pdev->dev, &dev_attr_top_off_threshold_current); + device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer); + + return ret; +} + +static int max77693_charger_remove(struct platform_device *pdev) +{ + struct max77693_charger *chg = platform_get_drvdata(pdev); + + device_remove_file(&pdev->dev, &dev_attr_top_off_timer); + device_remove_file(&pdev->dev, &dev_attr_top_off_threshold_current); + device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer); + + power_supply_unregister(&chg->charger); + + return 0; +} + +static const struct platform_device_id max77693_charger_id[] = { + { "max77693-charger", 0, }, + { } +}; +MODULE_DEVICE_TABLE(platform, max77693_charger_id); + +static struct platform_driver max77693_charger_driver = { + .driver = { + .name = "max77693-charger", + }, + .probe = max77693_charger_probe, + .remove = max77693_charger_remove, + .id_table = max77693_charger_id, +}; +module_platform_driver(max77693_charger_driver); + +MODULE_AUTHOR("Krzysztof Kozlowski "); +MODULE_DESCRIPTION("Maxim 77693 charger driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 028e76504519..27f6646731b0 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -39,14 +39,13 @@ config POWER_RESET_AXXIA Say Y if you have an Axxia family SoC. config POWER_RESET_BRCMSTB - bool "Broadcom STB reset driver" if COMPILE_TEST - depends on ARM + bool "Broadcom STB reset driver" + depends on ARM || MIPS || COMPILE_TEST default ARCH_BRCMSTB help - This driver provides restart support for ARM-based Broadcom STB - boards. + This driver provides restart support for Broadcom STB boards. - Say Y here if you have an ARM-based Broadcom STB board and you wish + Say Y here if you have a Broadcom STB board and you wish to have restart support. config POWER_RESET_GPIO @@ -104,23 +103,16 @@ config POWER_RESET_QNAP config POWER_RESET_RESTART bool "Restart power-off driver" - depends on ARM help Some boards don't actually have the ability to power off. Instead they restart, and u-boot holds the SoC until the user presses a key. u-boot then boots into Linux. -config POWER_RESET_SUN6I - bool "Allwinner A31 SoC reset driver" - depends on ARCH_SUNXI - help - Reboot support for the Allwinner A31 SoCs. - config POWER_RESET_ST - bool "ST restart power-off driver" + bool "ST restart driver" depends on ARCH_STI help - Power off and reset support for STMicroelectronics boards. + Reset support for STMicroelectronics boards. config POWER_RESET_VERSATILE bool "ARM Versatile family reboot driver" @@ -159,5 +151,11 @@ config POWER_RESET_SYSCON help Reboot support for generic SYSCON mapped register reset. +config POWER_RESET_RMOBILE + tristate "Renesas R-Mobile reset driver" + depends on ARCH_RMOBILE || COMPILE_TEST + help + Reboot support for Renesas R-Mobile and SH-Mobile SoCs. + endif diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 1d4804d6b323..11de15bae52e 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -11,10 +11,10 @@ obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o -obj-$(CONFIG_POWER_RESET_SUN6I) += sun6i-reboot.o obj-$(CONFIG_POWER_RESET_ST) += st-poweroff.o obj-$(CONFIG_POWER_RESET_VERSATILE) += arm-versatile-reboot.o obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o +obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o diff --git a/drivers/power/reset/arm-versatile-reboot.c b/drivers/power/reset/arm-versatile-reboot.c index 5b08bffcf1a8..b208073c887d 100644 --- a/drivers/power/reset/arm-versatile-reboot.c +++ b/drivers/power/reset/arm-versatile-reboot.c @@ -13,16 +13,22 @@ #include #include #include -#include + +#define INTEGRATOR_HDR_CTRL_OFFSET 0x0C +#define INTEGRATOR_HDR_LOCK_OFFSET 0x14 +#define INTEGRATOR_CM_CTRL_RESET (1 << 3) #define REALVIEW_SYS_LOCK_OFFSET 0x20 -#define REALVIEW_SYS_LOCK_VAL 0xA05F #define REALVIEW_SYS_RESETCTL_OFFSET 0x40 +/* Magic unlocking token used on all Versatile boards */ +#define VERSATILE_LOCK_VAL 0xA05F + /* * We detect the different syscon types from the compatible strings. */ enum versatile_reboot { + INTEGRATOR_REBOOT_CM, REALVIEW_REBOOT_EB, REALVIEW_REBOOT_PB1176, REALVIEW_REBOOT_PB11MP, @@ -35,6 +41,10 @@ static struct regmap *syscon_regmap; static enum versatile_reboot versatile_reboot_type; static const struct of_device_id versatile_reboot_of_match[] = { + { + .compatible = "arm,core-module-integrator", + .data = (void *)INTEGRATOR_REBOOT_CM + }, { .compatible = "arm,realview-eb-syscon", .data = (void *)REALVIEW_REBOOT_EB, @@ -55,31 +65,47 @@ static const struct of_device_id versatile_reboot_of_match[] = { .compatible = "arm,realview-pbx-syscon", .data = (void *)REALVIEW_REBOOT_PBX, }, + {}, }; -static void versatile_reboot(enum reboot_mode mode, const char *cmd) +static int versatile_reboot(struct notifier_block *this, unsigned long mode, + void *cmd) { /* Unlock the reset register */ - regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET, - REALVIEW_SYS_LOCK_VAL); /* Then hit reset on the different machines */ switch (versatile_reboot_type) { + case INTEGRATOR_REBOOT_CM: + regmap_write(syscon_regmap, INTEGRATOR_HDR_LOCK_OFFSET, + VERSATILE_LOCK_VAL); + regmap_update_bits(syscon_regmap, + INTEGRATOR_HDR_CTRL_OFFSET, + INTEGRATOR_CM_CTRL_RESET, + INTEGRATOR_CM_CTRL_RESET); + break; case REALVIEW_REBOOT_EB: + regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET, + VERSATILE_LOCK_VAL); regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET, 0x0008); break; case REALVIEW_REBOOT_PB1176: + regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET, + VERSATILE_LOCK_VAL); regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET, 0x0100); break; case REALVIEW_REBOOT_PB11MP: case REALVIEW_REBOOT_PBA8: + regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET, + VERSATILE_LOCK_VAL); regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET, 0x0000); regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET, 0x0004); break; case REALVIEW_REBOOT_PBX: + regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET, + VERSATILE_LOCK_VAL); regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET, 0x00f0); regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET, @@ -87,12 +113,20 @@ static void versatile_reboot(enum reboot_mode mode, const char *cmd) break; } dsb(); + + return NOTIFY_DONE; } +static struct notifier_block versatile_reboot_nb = { + .notifier_call = versatile_reboot, + .priority = 192, +}; + static int __init versatile_reboot_probe(void) { const struct of_device_id *reboot_id; struct device_node *np; + int err; np = of_find_matching_node_and_match(NULL, versatile_reboot_of_match, &reboot_id); @@ -104,7 +138,10 @@ static int __init versatile_reboot_probe(void) if (IS_ERR(syscon_regmap)) return PTR_ERR(syscon_regmap); - arm_pm_restart = versatile_reboot; + err = register_restart_handler(&versatile_reboot_nb); + if (err) + return err; + pr_info("versatile reboot driver registered\n"); return 0; } diff --git a/drivers/power/reset/at91-poweroff.c b/drivers/power/reset/at91-poweroff.c index c61000333bb9..4b72ea51c364 100644 --- a/drivers/power/reset/at91-poweroff.c +++ b/drivers/power/reset/at91-poweroff.c @@ -71,10 +71,11 @@ static void at91_poweroff(void) writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, at91_shdwc_base + AT91_SHDW_CR); } -const enum wakeup_type at91_poweroff_get_wakeup_mode(struct device_node *np) +static int at91_poweroff_get_wakeup_mode(struct device_node *np) { const char *pm; - int err, i; + unsigned int i; + int err; err = of_property_read_string(np, "atmel,wakeup-mode", &pm); if (err < 0) @@ -90,7 +91,7 @@ const enum wakeup_type at91_poweroff_get_wakeup_mode(struct device_node *np) static void at91_poweroff_dt_set_wakeup_mode(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - enum wakeup_type wakeup_mode; + int wakeup_mode; u32 mode = 0, tmp; wakeup_mode = at91_poweroff_get_wakeup_mode(np); diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 69a75d99ae92..13584e24736a 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -17,8 +17,6 @@ #include #include -#include - #include #include @@ -54,7 +52,8 @@ static void __iomem *at91_ramc_base[2], *at91_rstc_base; * reset register it can be left driving the data bus and * killing the chance of a subsequent boot from NAND */ -static void at91sam9260_restart(enum reboot_mode mode, const char *cmd) +static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, + void *cmd) { asm volatile( /* Align to cache lines */ @@ -76,9 +75,12 @@ static void at91sam9260_restart(enum reboot_mode mode, const char *cmd) "r" (1), "r" (AT91_SDRAMC_LPCB_POWER_DOWN), "r" (AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)); + + return NOTIFY_DONE; } -static void at91sam9g45_restart(enum reboot_mode mode, const char *cmd) +static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, + void *cmd) { asm volatile( /* @@ -117,6 +119,8 @@ static void at91sam9g45_restart(enum reboot_mode mode, const char *cmd) "r" (AT91_DDRSDRC_LPCB_POWER_DOWN), "r" (AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST) : "r0"); + + return NOTIFY_DONE; } static void __init at91_reset_status(struct platform_device *pdev) @@ -161,6 +165,10 @@ static struct of_device_id at91_reset_of_match[] = { { /* sentinel */ } }; +static struct notifier_block at91_restart_nb = { + .priority = 192, +}; + static int at91_reset_of_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -183,9 +191,8 @@ static int at91_reset_of_probe(struct platform_device *pdev) } match = of_match_node(at91_reset_of_match, pdev->dev.of_node); - arm_pm_restart = match->data; - - return 0; + at91_restart_nb.notifier_call = match->data; + return register_restart_handler(&at91_restart_nb); } static int at91_reset_platform_probe(struct platform_device *pdev) @@ -212,10 +219,11 @@ static int at91_reset_platform_probe(struct platform_device *pdev) } match = platform_get_device_id(pdev); - arm_pm_restart = (void (*)(enum reboot_mode, const char*)) - match->driver_data; + at91_restart_nb.notifier_call = + (int (*)(struct notifier_block *, + unsigned long, void *)) match->driver_data; - return 0; + return register_restart_handler(&at91_restart_nb); } static int at91_reset_probe(struct platform_device *pdev) diff --git a/drivers/power/reset/brcmstb-reboot.c b/drivers/power/reset/brcmstb-reboot.c index 100606f9b3dc..884b53c483c0 100644 --- a/drivers/power/reset/brcmstb-reboot.c +++ b/drivers/power/reset/brcmstb-reboot.c @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -34,13 +35,20 @@ static struct regmap *regmap; static u32 rst_src_en; static u32 sw_mstr_rst; +struct reset_reg_mask { + u32 rst_src_en_mask; + u32 sw_mstr_rst_mask; +}; + +static const struct reset_reg_mask *reset_masks; + static int brcmstb_restart_handler(struct notifier_block *this, unsigned long mode, void *cmd) { int rc; u32 tmp; - rc = regmap_write(regmap, rst_src_en, 1); + rc = regmap_write(regmap, rst_src_en, reset_masks->rst_src_en_mask); if (rc) { pr_err("failed to write rst_src_en (%d)\n", rc); return NOTIFY_DONE; @@ -52,7 +60,7 @@ static int brcmstb_restart_handler(struct notifier_block *this, return NOTIFY_DONE; } - rc = regmap_write(regmap, sw_mstr_rst, 1); + rc = regmap_write(regmap, sw_mstr_rst, reset_masks->sw_mstr_rst_mask); if (rc) { pr_err("failed to write sw_mstr_rst (%d)\n", rc); return NOTIFY_DONE; @@ -75,10 +83,34 @@ static struct notifier_block brcmstb_restart_nb = { .priority = 128, }; +static const struct reset_reg_mask reset_bits_40nm = { + .rst_src_en_mask = BIT(0), + .sw_mstr_rst_mask = BIT(0), +}; + +static const struct reset_reg_mask reset_bits_65nm = { + .rst_src_en_mask = BIT(3), + .sw_mstr_rst_mask = BIT(31), +}; + +static const struct of_device_id of_match[] = { + { .compatible = "brcm,brcmstb-reboot", .data = &reset_bits_40nm }, + { .compatible = "brcm,bcm7038-reboot", .data = &reset_bits_65nm }, + {}, +}; + static int brcmstb_reboot_probe(struct platform_device *pdev) { int rc; struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id; + + of_id = of_match_node(of_match, np); + if (!of_id) { + pr_err("failed to look up compatible string\n"); + return -EINVAL; + } + reset_masks = of_id->data; regmap = syscon_regmap_lookup_by_phandle(np, "syscon"); if (IS_ERR(regmap)) { @@ -108,11 +140,6 @@ static int brcmstb_reboot_probe(struct platform_device *pdev) return rc; } -static const struct of_device_id of_match[] = { - { .compatible = "brcm,brcmstb-reboot", }, - {}, -}; - static struct platform_driver brcmstb_reboot_driver = { .probe = brcmstb_reboot_probe, .driver = { diff --git a/drivers/power/reset/ltc2952-poweroff.c b/drivers/power/reset/ltc2952-poweroff.c index 34f38a3dc3ff..7ef193b6f7fe 100644 --- a/drivers/power/reset/ltc2952-poweroff.c +++ b/drivers/power/reset/ltc2952-poweroff.c @@ -32,7 +32,9 @@ * - trigger (input) * A level change indicates the shut-down trigger. If it's state reverts * within the time-out defined by trigger_delay, the shut down is not - * executed. + * executed. If no pin is assigned to this input, the driver will start the + * watchdog toggle immediately. The chip will only power off the system if + * it is requested to do so through the kill line. * * - watchdog (output) * Once a shut down is triggered, the driver will toggle this signal, @@ -63,7 +65,7 @@ #include #include -struct ltc2952_poweroff_data { +struct ltc2952_poweroff { struct hrtimer timer_trigger; struct hrtimer timer_wde; @@ -72,22 +74,21 @@ struct ltc2952_poweroff_data { struct device *dev; - unsigned int virq; + struct gpio_desc *gpio_trigger; + struct gpio_desc *gpio_watchdog; + struct gpio_desc *gpio_kill; - /** - * 0: trigger - * 1: watchdog - * 2: kill - */ - struct gpio_desc *gpio[3]; + bool kernel_panic; + struct notifier_block panic_notifier; }; -static int ltc2952_poweroff_panic; -static struct ltc2952_poweroff_data *ltc2952_data; +#define to_ltc2952(p, m) container_of(p, struct ltc2952_poweroff, m) -#define POWERPATH_IO_TRIGGER 0 -#define POWERPATH_IO_WATCHDOG 1 -#define POWERPATH_IO_KILL 2 +/* + * This global variable is only needed for pm_power_off. We should + * remove it entirely once we don't need the global state anymore. + */ +static struct ltc2952_poweroff *ltc2952_data; /** * ltc2952_poweroff_timer_wde - Timer callback @@ -103,29 +104,24 @@ static enum hrtimer_restart ltc2952_poweroff_timer_wde(struct hrtimer *timer) ktime_t now; int state; unsigned long overruns; + struct ltc2952_poweroff *data = to_ltc2952(timer, timer_wde); - if (ltc2952_poweroff_panic) + if (data->kernel_panic) return HRTIMER_NORESTART; - state = gpiod_get_value(ltc2952_data->gpio[POWERPATH_IO_WATCHDOG]); - gpiod_set_value(ltc2952_data->gpio[POWERPATH_IO_WATCHDOG], !state); + state = gpiod_get_value(data->gpio_watchdog); + gpiod_set_value(data->gpio_watchdog, !state); now = hrtimer_cb_get_time(timer); - overruns = hrtimer_forward(timer, now, ltc2952_data->wde_interval); + overruns = hrtimer_forward(timer, now, data->wde_interval); return HRTIMER_RESTART; } -static enum hrtimer_restart ltc2952_poweroff_timer_trigger( - struct hrtimer *timer) +static void ltc2952_poweroff_start_wde(struct ltc2952_poweroff *data) { - int ret; - - ret = hrtimer_start(<c2952_data->timer_wde, - ltc2952_data->wde_interval, HRTIMER_MODE_REL); - - if (ret) { - dev_err(ltc2952_data->dev, "unable to start the timer\n"); + if (hrtimer_start(&data->timer_wde, data->wde_interval, + HRTIMER_MODE_REL)) { /* * The device will not toggle the watchdog reset, * thus shut down is only safe if the PowerPath controller @@ -134,10 +130,17 @@ static enum hrtimer_restart ltc2952_poweroff_timer_trigger( * * Only sending a warning as the system will power-off anyway */ + dev_err(data->dev, "unable to start the timer\n"); } +} - dev_info(ltc2952_data->dev, "executing shutdown\n"); +static enum hrtimer_restart +ltc2952_poweroff_timer_trigger(struct hrtimer *timer) +{ + struct ltc2952_poweroff *data = to_ltc2952(timer, timer_trigger); + ltc2952_poweroff_start_wde(data); + dev_info(data->dev, "executing shutdown\n"); orderly_poweroff(true); return HRTIMER_NORESTART; @@ -154,180 +157,161 @@ static enum hrtimer_restart ltc2952_poweroff_timer_trigger( */ static irqreturn_t ltc2952_poweroff_handler(int irq, void *dev_id) { - int ret; - struct ltc2952_poweroff_data *data = dev_id; + struct ltc2952_poweroff *data = dev_id; - if (ltc2952_poweroff_panic) - goto irq_ok; - - if (hrtimer_active(&data->timer_wde)) { + if (data->kernel_panic || hrtimer_active(&data->timer_wde)) { /* shutdown is already triggered, nothing to do any more */ - goto irq_ok; + return IRQ_HANDLED; } - if (!hrtimer_active(&data->timer_trigger)) { - ret = hrtimer_start(&data->timer_trigger, data->trigger_delay, - HRTIMER_MODE_REL); - - if (ret) + if (gpiod_get_value(data->gpio_trigger)) { + if (hrtimer_start(&data->timer_trigger, data->trigger_delay, + HRTIMER_MODE_REL)) dev_err(data->dev, "unable to start the wait timer\n"); } else { - ret = hrtimer_cancel(&data->timer_trigger); + hrtimer_cancel(&data->timer_trigger); /* omitting return value check, timer should have been valid */ } - -irq_ok: return IRQ_HANDLED; } static void ltc2952_poweroff_kill(void) { - gpiod_set_value(ltc2952_data->gpio[POWERPATH_IO_KILL], 1); + gpiod_set_value(ltc2952_data->gpio_kill, 1); } -static int ltc2952_poweroff_suspend(struct platform_device *pdev, - pm_message_t state) +static void ltc2952_poweroff_default(struct ltc2952_poweroff *data) { - return -ENOSYS; -} - -static int ltc2952_poweroff_resume(struct platform_device *pdev) -{ - return -ENOSYS; -} - -static void ltc2952_poweroff_default(struct ltc2952_poweroff_data *data) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(data->gpio); i++) - data->gpio[i] = NULL; - data->wde_interval = ktime_set(0, 300L*1E6L); data->trigger_delay = ktime_set(2, 500L*1E6L); hrtimer_init(&data->timer_trigger, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - data->timer_trigger.function = <c2952_poweroff_timer_trigger; + data->timer_trigger.function = ltc2952_poweroff_timer_trigger; hrtimer_init(&data->timer_wde, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - data->timer_wde.function = <c2952_poweroff_timer_wde; + data->timer_wde.function = ltc2952_poweroff_timer_wde; } static int ltc2952_poweroff_init(struct platform_device *pdev) { - int ret, virq; - unsigned int i; - struct ltc2952_poweroff_data *data; + int ret; + struct ltc2952_poweroff *data = platform_get_drvdata(pdev); - static char *name[] = { - "trigger", - "watchdog", - "kill", - NULL - }; + ltc2952_poweroff_default(data); - data = ltc2952_data; - ltc2952_poweroff_default(ltc2952_data); + data->gpio_watchdog = devm_gpiod_get(&pdev->dev, "watchdog", + GPIOD_OUT_LOW); + if (IS_ERR(data->gpio_watchdog)) { + ret = PTR_ERR(data->gpio_watchdog); + dev_err(&pdev->dev, "unable to claim gpio \"watchdog\"\n"); + return ret; + } - for (i = 0; i < ARRAY_SIZE(ltc2952_data->gpio); i++) { - ltc2952_data->gpio[i] = gpiod_get(&pdev->dev, name[i]); + data->gpio_kill = devm_gpiod_get(&pdev->dev, "kill", GPIOD_OUT_LOW); + if (IS_ERR(data->gpio_kill)) { + ret = PTR_ERR(data->gpio_kill); + dev_err(&pdev->dev, "unable to claim gpio \"kill\"\n"); + return ret; + } - if (IS_ERR(ltc2952_data->gpio[i])) { - ret = PTR_ERR(ltc2952_data->gpio[i]); + data->gpio_trigger = devm_gpiod_get(&pdev->dev, "trigger", GPIOD_IN); + if (IS_ERR(data->gpio_trigger)) { + /* + * It's not a problem if the trigger gpio isn't available, but + * it is worth a warning if its use was defined in the device + * tree. + */ + if (PTR_ERR(data->gpio_trigger) != -ENOENT) dev_err(&pdev->dev, - "unable to claim the following gpio: %s\n", - name[i]); - goto err_io; + "unable to claim gpio \"trigger\"\n"); + data->gpio_trigger = NULL; + } + + if (devm_request_irq(&pdev->dev, gpiod_to_irq(data->gpio_trigger), + ltc2952_poweroff_handler, + (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING), + "ltc2952-poweroff", + data)) { + /* + * Some things may have happened: + * - No trigger input was defined + * - Claiming the GPIO failed + * - We could not map to an IRQ + * - We couldn't register an interrupt handler + * + * None of these really are problems, but all of them + * disqualify the push button from controlling the power. + * + * It is therefore important to note that if the ltc2952 + * detects a button press for long enough, it will still start + * its own powerdown window and cut the power on us if we don't + * start the watchdog trigger. + */ + if (data->gpio_trigger) { + dev_warn(&pdev->dev, + "unable to configure the trigger interrupt\n"); + devm_gpiod_put(&pdev->dev, data->gpio_trigger); + data->gpio_trigger = NULL; } - } - - ret = gpiod_direction_output( - ltc2952_data->gpio[POWERPATH_IO_WATCHDOG], 0); - if (ret) { - dev_err(&pdev->dev, "unable to use watchdog-gpio as output\n"); - goto err_io; - } - - ret = gpiod_direction_output(ltc2952_data->gpio[POWERPATH_IO_KILL], 0); - if (ret) { - dev_err(&pdev->dev, "unable to use kill-gpio as output\n"); - goto err_io; - } - - virq = gpiod_to_irq(ltc2952_data->gpio[POWERPATH_IO_TRIGGER]); - if (virq < 0) { - dev_err(&pdev->dev, "cannot map GPIO as interrupt"); - goto err_io; - } - - ltc2952_data->virq = virq; - ret = request_irq(virq, - ltc2952_poweroff_handler, - (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING), - "ltc2952-poweroff", - ltc2952_data - ); - - if (ret) { - dev_err(&pdev->dev, "cannot configure an interrupt handler\n"); - goto err_io; + dev_info(&pdev->dev, + "power down trigger input will not be used\n"); + ltc2952_poweroff_start_wde(data); } return 0; +} -err_io: - for (i = 0; i < ARRAY_SIZE(ltc2952_data->gpio); i++) - if (ltc2952_data->gpio[i]) - gpiod_put(ltc2952_data->gpio[i]); +static int ltc2952_poweroff_notify_panic(struct notifier_block *nb, + unsigned long code, void *unused) +{ + struct ltc2952_poweroff *data = to_ltc2952(nb, panic_notifier); - return ret; + data->kernel_panic = true; + return NOTIFY_DONE; } static int ltc2952_poweroff_probe(struct platform_device *pdev) { int ret; + struct ltc2952_poweroff *data; if (pm_power_off) { dev_err(&pdev->dev, "pm_power_off already registered"); return -EBUSY; } - ltc2952_data = kzalloc(sizeof(*ltc2952_data), GFP_KERNEL); - if (!ltc2952_data) + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) return -ENOMEM; - ltc2952_data->dev = &pdev->dev; + data->dev = &pdev->dev; + platform_set_drvdata(pdev, data); ret = ltc2952_poweroff_init(pdev); if (ret) - goto err; + return ret; - pm_power_off = <c2952_poweroff_kill; + /* TODO: remove ltc2952_data */ + ltc2952_data = data; + pm_power_off = ltc2952_poweroff_kill; + data->panic_notifier.notifier_call = ltc2952_poweroff_notify_panic; + atomic_notifier_chain_register(&panic_notifier_list, + &data->panic_notifier); dev_info(&pdev->dev, "probe successful\n"); return 0; - -err: - kfree(ltc2952_data); - return ret; } static int ltc2952_poweroff_remove(struct platform_device *pdev) { - unsigned int i; + struct ltc2952_poweroff *data = platform_get_drvdata(pdev); pm_power_off = NULL; - - if (ltc2952_data) { - free_irq(ltc2952_data->virq, ltc2952_data); - - for (i = 0; i < ARRAY_SIZE(ltc2952_data->gpio); i++) - gpiod_put(ltc2952_data->gpio[i]); - - kfree(ltc2952_data); - } - + hrtimer_cancel(&data->timer_trigger); + hrtimer_cancel(&data->timer_wde); + atomic_notifier_chain_unregister(&panic_notifier_list, + &data->panic_notifier); return 0; } @@ -344,41 +328,9 @@ static struct platform_driver ltc2952_poweroff_driver = { .name = "ltc2952-poweroff", .of_match_table = of_ltc2952_poweroff_match, }, - .suspend = ltc2952_poweroff_suspend, - .resume = ltc2952_poweroff_resume, }; -static int ltc2952_poweroff_notify_panic(struct notifier_block *nb, - unsigned long code, void *unused) -{ - ltc2952_poweroff_panic = 1; - return NOTIFY_DONE; -} - -static struct notifier_block ltc2952_poweroff_panic_nb = { - .notifier_call = ltc2952_poweroff_notify_panic, -}; - -static int __init ltc2952_poweroff_platform_init(void) -{ - ltc2952_poweroff_panic = 0; - - atomic_notifier_chain_register(&panic_notifier_list, - <c2952_poweroff_panic_nb); - - return platform_driver_register(<c2952_poweroff_driver); -} - -static void __exit ltc2952_poweroff_platform_exit(void) -{ - atomic_notifier_chain_unregister(&panic_notifier_list, - <c2952_poweroff_panic_nb); - - platform_driver_unregister(<c2952_poweroff_driver); -} - -module_init(ltc2952_poweroff_platform_init); -module_exit(ltc2952_poweroff_platform_exit); +module_platform_driver(ltc2952_poweroff_driver); MODULE_AUTHOR("Ren Moll "); MODULE_DESCRIPTION("LTC PowerPath power-off driver"); diff --git a/drivers/power/reset/restart-poweroff.c b/drivers/power/reset/restart-poweroff.c index f46f2c2e4648..41b22c4d5236 100644 --- a/drivers/power/reset/restart-poweroff.c +++ b/drivers/power/reset/restart-poweroff.c @@ -16,7 +16,6 @@ #include #include #include -#include static void restart_poweroff_do_poweroff(void) { diff --git a/drivers/power/reset/rmobile-reset.c b/drivers/power/reset/rmobile-reset.c new file mode 100644 index 000000000000..e6569df76941 --- /dev/null +++ b/drivers/power/reset/rmobile-reset.c @@ -0,0 +1,91 @@ +/* + * Renesas R-Mobile Reset Driver + * + * Copyright (C) 2014 Glider bvba + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* SYSC Register Bank 2 */ +#define RESCNT2 0x20 /* Reset Control Register 2 */ + +/* Reset Control Register 2 */ +#define RESCNT2_PRES 0x80000000 /* Soft power-on reset */ + +static void __iomem *sysc_base2; + +static int rmobile_reset_handler(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + pr_debug("%s %lu\n", __func__, mode); + + /* Let's assume we have acquired the HPB semaphore */ + writel(RESCNT2_PRES, sysc_base2 + RESCNT2); + + return NOTIFY_DONE; +} + +static struct notifier_block rmobile_reset_nb = { + .notifier_call = rmobile_reset_handler, + .priority = 192, +}; + +static int rmobile_reset_probe(struct platform_device *pdev) +{ + int error; + + sysc_base2 = of_iomap(pdev->dev.of_node, 1); + if (!sysc_base2) + return -ENODEV; + + error = register_restart_handler(&rmobile_reset_nb); + if (error) { + dev_err(&pdev->dev, + "cannot register restart handler (err=%d)\n", error); + goto fail_unmap; + } + + return 0; + +fail_unmap: + iounmap(sysc_base2); + return error; +} + +static int rmobile_reset_remove(struct platform_device *pdev) +{ + unregister_restart_handler(&rmobile_reset_nb); + iounmap(sysc_base2); + return 0; +} + +static const struct of_device_id rmobile_reset_of_match[] = { + { .compatible = "renesas,sysc-rmobile", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rmobile_reset_of_match); + +static struct platform_driver rmobile_reset_driver = { + .probe = rmobile_reset_probe, + .remove = rmobile_reset_remove, + .driver = { + .name = "rmobile_reset", + .of_match_table = rmobile_reset_of_match, + }, +}; + +module_platform_driver(rmobile_reset_driver); + +MODULE_DESCRIPTION("Renesas R-Mobile Reset Driver"); +MODULE_AUTHOR("Geert Uytterhoeven "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/reset/st-poweroff.c b/drivers/power/reset/st-poweroff.c index a0acf25ee2a2..27383de9caa8 100644 --- a/drivers/power/reset/st-poweroff.c +++ b/drivers/power/reset/st-poweroff.c @@ -15,10 +15,9 @@ #include #include #include +#include #include -#include - struct reset_syscfg { struct regmap *regmap; /* syscfg used for reset */ @@ -75,7 +74,8 @@ static struct reset_syscfg stid127_reset = { static struct reset_syscfg *st_restart_syscfg; -static void st_restart(enum reboot_mode reboot_mode, const char *cmd) +static int st_restart(struct notifier_block *this, unsigned long mode, + void *cmd) { /* reset syscfg updated */ regmap_update_bits(st_restart_syscfg->regmap, @@ -88,8 +88,15 @@ static void st_restart(enum reboot_mode reboot_mode, const char *cmd) st_restart_syscfg->offset_rst_msk, st_restart_syscfg->mask_rst_msk, 0); + + return NOTIFY_DONE; } +static struct notifier_block st_restart_nb = { + .notifier_call = st_restart, + .priority = 192, +}; + static struct of_device_id st_reset_of_match[] = { { .compatible = "st,stih415-restart", @@ -126,9 +133,7 @@ static int st_reset_probe(struct platform_device *pdev) return PTR_ERR(st_restart_syscfg->regmap); } - arm_pm_restart = st_restart; - - return 0; + return register_restart_handler(&st_restart_nb); } static struct platform_driver st_reset_driver = { diff --git a/drivers/power/reset/sun6i-reboot.c b/drivers/power/reset/sun6i-reboot.c deleted file mode 100644 index af2cd7ff2fe8..000000000000 --- a/drivers/power/reset/sun6i-reboot.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Allwinner A31 SoCs reset code - * - * Copyright (C) 2012-2014 Maxime Ripard - * - * Maxime Ripard - * - * 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 - -#define SUN6I_WATCHDOG1_IRQ_REG 0x00 -#define SUN6I_WATCHDOG1_CTRL_REG 0x10 -#define SUN6I_WATCHDOG1_CTRL_RESTART BIT(0) -#define SUN6I_WATCHDOG1_CONFIG_REG 0x14 -#define SUN6I_WATCHDOG1_CONFIG_RESTART BIT(0) -#define SUN6I_WATCHDOG1_CONFIG_IRQ BIT(1) -#define SUN6I_WATCHDOG1_MODE_REG 0x18 -#define SUN6I_WATCHDOG1_MODE_ENABLE BIT(0) - -static void __iomem *wdt_base; - -static void sun6i_wdt_restart(enum reboot_mode mode, const char *cmd) -{ - if (!wdt_base) - return; - - /* Disable interrupts */ - writel(0, wdt_base + SUN6I_WATCHDOG1_IRQ_REG); - - /* We want to disable the IRQ and just reset the whole system */ - writel(SUN6I_WATCHDOG1_CONFIG_RESTART, - wdt_base + SUN6I_WATCHDOG1_CONFIG_REG); - - /* Enable timer. The default and lowest interval value is 0.5s */ - writel(SUN6I_WATCHDOG1_MODE_ENABLE, - wdt_base + SUN6I_WATCHDOG1_MODE_REG); - - /* Restart the watchdog. */ - writel(SUN6I_WATCHDOG1_CTRL_RESTART, - wdt_base + SUN6I_WATCHDOG1_CTRL_REG); - - while (1) { - mdelay(5); - writel(SUN6I_WATCHDOG1_MODE_ENABLE, - wdt_base + SUN6I_WATCHDOG1_MODE_REG); - } -} - -static int sun6i_reboot_probe(struct platform_device *pdev) -{ - wdt_base = of_iomap(pdev->dev.of_node, 0); - if (!wdt_base) { - WARN(1, "failed to map watchdog base address"); - return -ENODEV; - } - - arm_pm_restart = sun6i_wdt_restart; - - return 0; -} - -static struct of_device_id sun6i_reboot_of_match[] = { - { .compatible = "allwinner,sun6i-a31-wdt" }, - {} -}; - -static struct platform_driver sun6i_reboot_driver = { - .probe = sun6i_reboot_probe, - .driver = { - .name = "sun6i-reboot", - .of_match_table = sun6i_reboot_of_match, - }, -}; -module_platform_driver(sun6i_reboot_driver); diff --git a/drivers/power/reset/vexpress-poweroff.c b/drivers/power/reset/vexpress-poweroff.c index 9dfc9cee3232..be12d9b92957 100644 --- a/drivers/power/reset/vexpress-poweroff.c +++ b/drivers/power/reset/vexpress-poweroff.c @@ -111,23 +111,20 @@ static int _vexpress_register_restart_handler(struct device *dev) static int vexpress_reset_probe(struct platform_device *pdev) { - enum vexpress_reset_func func; const struct of_device_id *match = of_match_device(vexpress_reset_of_match, &pdev->dev); struct regmap *regmap; int ret = 0; - if (match) - func = (enum vexpress_reset_func)match->data; - else - func = pdev->id_entry->driver_data; + if (!match) + return -EINVAL; regmap = devm_regmap_init_vexpress_config(&pdev->dev); if (IS_ERR(regmap)) return PTR_ERR(regmap); dev_set_drvdata(&pdev->dev, regmap); - switch (func) { + switch ((enum vexpress_reset_func)match->data) { case FUNC_SHUTDOWN: vexpress_power_off_device = &pdev->dev; pm_power_off = vexpress_power_off; @@ -144,20 +141,12 @@ static int vexpress_reset_probe(struct platform_device *pdev) return ret; } -static const struct platform_device_id vexpress_reset_id_table[] = { - { .name = "vexpress-reset", .driver_data = FUNC_RESET, }, - { .name = "vexpress-shutdown", .driver_data = FUNC_SHUTDOWN, }, - { .name = "vexpress-reboot", .driver_data = FUNC_REBOOT, }, - {} -}; - static struct platform_driver vexpress_reset_driver = { .probe = vexpress_reset_probe, .driver = { .name = "vexpress-reset", .of_match_table = vexpress_reset_of_match, }, - .id_table = vexpress_reset_id_table, }; static int __init vexpress_reset_init(void) diff --git a/drivers/power/rt5033_battery.c b/drivers/power/rt5033_battery.c new file mode 100644 index 000000000000..7b898f41c595 --- /dev/null +++ b/drivers/power/rt5033_battery.c @@ -0,0 +1,177 @@ +/* + * Fuel gauge driver for Richtek RT5033 + * + * Copyright (C) 2014 Samsung Electronics, Co., Ltd. + * Author: Beomho Seo + * + * This 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 bythe Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +static int rt5033_battery_get_capacity(struct i2c_client *client) +{ + struct rt5033_battery *battery = i2c_get_clientdata(client); + u32 msb; + + regmap_read(battery->regmap, RT5033_FUEL_REG_SOC_H, &msb); + + return msb; +} + +static int rt5033_battery_get_present(struct i2c_client *client) +{ + struct rt5033_battery *battery = i2c_get_clientdata(client); + u32 val; + + regmap_read(battery->regmap, RT5033_FUEL_REG_CONFIG_L, &val); + + return (val & RT5033_FUEL_BAT_PRESENT) ? true : false; +} + +static int rt5033_battery_get_watt_prop(struct i2c_client *client, + enum power_supply_property psp) +{ + struct rt5033_battery *battery = i2c_get_clientdata(client); + unsigned int regh, regl; + int ret; + u32 msb, lsb; + + switch (psp) { + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + regh = RT5033_FUEL_REG_VBAT_H; + regl = RT5033_FUEL_REG_VBAT_L; + break; + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + regh = RT5033_FUEL_REG_AVG_VOLT_H; + regl = RT5033_FUEL_REG_AVG_VOLT_L; + break; + case POWER_SUPPLY_PROP_VOLTAGE_OCV: + regh = RT5033_FUEL_REG_OCV_H; + regl = RT5033_FUEL_REG_OCV_L; + break; + default: + return -EINVAL; + } + + regmap_read(battery->regmap, regh, &msb); + regmap_read(battery->regmap, regl, &lsb); + + ret = ((msb << 4) + (lsb >> 4)) * 1250 / 1000; + + return ret; +} + +static int rt5033_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct rt5033_battery *battery = container_of(psy, + struct rt5033_battery, psy); + + switch (psp) { + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + case POWER_SUPPLY_PROP_VOLTAGE_AVG: + case POWER_SUPPLY_PROP_VOLTAGE_OCV: + val->intval = rt5033_battery_get_watt_prop(battery->client, + psp); + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = rt5033_battery_get_present(battery->client); + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = rt5033_battery_get_capacity(battery->client); + break; + default: + return -EINVAL; + } + return 0; +} + +static enum power_supply_property rt5033_battery_props[] = { + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_AVG, + POWER_SUPPLY_PROP_VOLTAGE_OCV, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_CAPACITY, +}; + +static struct regmap_config rt5033_battery_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RT5033_FUEL_REG_END, +}; + +static int rt5033_battery_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct rt5033_battery *battery; + u32 ret; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) + return -EIO; + + battery = devm_kzalloc(&client->dev, sizeof(*battery), GFP_KERNEL); + if (!battery) + return -EINVAL; + + battery->client = client; + battery->regmap = devm_regmap_init_i2c(client, + &rt5033_battery_regmap_config); + if (IS_ERR(battery->regmap)) { + dev_err(&client->dev, "Failed to initialize regmap\n"); + return -EINVAL; + } + + i2c_set_clientdata(client, battery); + + battery->psy.name = "rt5033-battery"; + battery->psy.type = POWER_SUPPLY_TYPE_BATTERY; + battery->psy.get_property = rt5033_battery_get_property; + battery->psy.properties = rt5033_battery_props; + battery->psy.num_properties = ARRAY_SIZE(rt5033_battery_props); + + ret = power_supply_register(&client->dev, &battery->psy); + if (ret) { + dev_err(&client->dev, "Failed to register power supply\n"); + return ret; + } + + return 0; +} + +static int rt5033_battery_remove(struct i2c_client *client) +{ + struct rt5033_battery *battery = i2c_get_clientdata(client); + + power_supply_unregister(&battery->psy); + + return 0; +} + +static const struct i2c_device_id rt5033_battery_id[] = { + { "rt5033-battery", }, + { } +}; +MODULE_DEVICE_TABLE(platform, rt5033_battery_id); + +static struct i2c_driver rt5033_battery_driver = { + .driver = { + .name = "rt5033-battery", + }, + .probe = rt5033_battery_probe, + .remove = rt5033_battery_remove, + .id_table = rt5033_battery_id, +}; +module_i2c_driver(rt5033_battery_driver); + +MODULE_DESCRIPTION("Richtek RT5033 fuel gauge driver"); +MODULE_AUTHOR("Beomho Seo "); +MODULE_LICENSE("GPL"); diff --git a/drivers/power/test_power.c b/drivers/power/test_power.c index 0152f35dca5c..f26b1fa00fe1 100644 --- a/drivers/power/test_power.c +++ b/drivers/power/test_power.c @@ -21,6 +21,13 @@ #include #include +enum test_power_id { + TEST_AC, + TEST_BATTERY, + TEST_USB, + TEST_POWER_NUM, +}; + static int ac_online = 1; static int usb_online = 1; static int battery_status = POWER_SUPPLY_STATUS_DISCHARGING; @@ -147,7 +154,7 @@ static char *test_power_ac_supplied_to[] = { }; static struct power_supply test_power_supplies[] = { - { + [TEST_AC] = { .name = "test_ac", .type = POWER_SUPPLY_TYPE_MAINS, .supplied_to = test_power_ac_supplied_to, @@ -155,13 +162,15 @@ static struct power_supply test_power_supplies[] = { .properties = test_power_ac_props, .num_properties = ARRAY_SIZE(test_power_ac_props), .get_property = test_power_get_ac_property, - }, { + }, + [TEST_BATTERY] = { .name = "test_battery", .type = POWER_SUPPLY_TYPE_BATTERY, .properties = test_power_battery_props, .num_properties = ARRAY_SIZE(test_power_battery_props), .get_property = test_power_get_battery_property, - }, { + }, + [TEST_USB] = { .name = "test_usb", .type = POWER_SUPPLY_TYPE_USB, .supplied_to = test_power_ac_supplied_to, @@ -178,6 +187,8 @@ static int __init test_power_init(void) int i; int ret; + BUILD_BUG_ON(TEST_POWER_NUM != ARRAY_SIZE(test_power_supplies)); + for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) { ret = power_supply_register(NULL, &test_power_supplies[i]); if (ret) { @@ -309,7 +320,7 @@ static inline void signal_power_supply_changed(struct power_supply *psy) static int param_set_ac_online(const char *key, const struct kernel_param *kp) { ac_online = map_get_value(map_ac_online, key, ac_online); - signal_power_supply_changed(&test_power_supplies[0]); + signal_power_supply_changed(&test_power_supplies[TEST_AC]); return 0; } @@ -322,7 +333,7 @@ static int param_get_ac_online(char *buffer, const struct kernel_param *kp) static int param_set_usb_online(const char *key, const struct kernel_param *kp) { usb_online = map_get_value(map_ac_online, key, usb_online); - signal_power_supply_changed(&test_power_supplies[2]); + signal_power_supply_changed(&test_power_supplies[TEST_USB]); return 0; } @@ -336,7 +347,7 @@ static int param_set_battery_status(const char *key, const struct kernel_param *kp) { battery_status = map_get_value(map_status, key, battery_status); - signal_power_supply_changed(&test_power_supplies[1]); + signal_power_supply_changed(&test_power_supplies[TEST_BATTERY]); return 0; } @@ -350,7 +361,7 @@ static int param_set_battery_health(const char *key, const struct kernel_param *kp) { battery_health = map_get_value(map_health, key, battery_health); - signal_power_supply_changed(&test_power_supplies[1]); + signal_power_supply_changed(&test_power_supplies[TEST_BATTERY]); return 0; } @@ -364,7 +375,7 @@ static int param_set_battery_present(const char *key, const struct kernel_param *kp) { battery_present = map_get_value(map_present, key, battery_present); - signal_power_supply_changed(&test_power_supplies[0]); + signal_power_supply_changed(&test_power_supplies[TEST_AC]); return 0; } @@ -380,7 +391,7 @@ static int param_set_battery_technology(const char *key, { battery_technology = map_get_value(map_technology, key, battery_technology); - signal_power_supply_changed(&test_power_supplies[1]); + signal_power_supply_changed(&test_power_supplies[TEST_BATTERY]); return 0; } @@ -401,7 +412,7 @@ static int param_set_battery_capacity(const char *key, return -EINVAL; battery_capacity = tmp; - signal_power_supply_changed(&test_power_supplies[1]); + signal_power_supply_changed(&test_power_supplies[TEST_BATTERY]); return 0; } @@ -416,7 +427,7 @@ static int param_set_battery_voltage(const char *key, return -EINVAL; battery_voltage = tmp; - signal_power_supply_changed(&test_power_supplies[1]); + signal_power_supply_changed(&test_power_supplies[TEST_BATTERY]); return 0; } diff --git a/drivers/ps3/ps3-vuart.c b/drivers/ps3/ps3-vuart.c index bc1e5139ba29..d6db822bef84 100644 --- a/drivers/ps3/ps3-vuart.c +++ b/drivers/ps3/ps3-vuart.c @@ -151,11 +151,6 @@ static void __maybe_unused _dump_port_params(unsigned int port_number, #endif } -struct vuart_triggers { - unsigned long rx; - unsigned long tx; -}; - int ps3_vuart_get_triggers(struct ps3_system_bus_device *dev, struct vuart_triggers *trig) { diff --git a/drivers/ps3/sys-manager-core.c b/drivers/ps3/sys-manager-core.c index 0e41737ea835..c429ffca1ab7 100644 --- a/drivers/ps3/sys-manager-core.c +++ b/drivers/ps3/sys-manager-core.c @@ -47,7 +47,7 @@ void ps3_sys_manager_register_ops(const struct ps3_sys_manager_ops *ops) } EXPORT_SYMBOL_GPL(ps3_sys_manager_register_ops); -void ps3_sys_manager_power_off(void) +void __noreturn ps3_sys_manager_power_off(void) { if (ps3_sys_manager_ops.power_off) ps3_sys_manager_ops.power_off(ps3_sys_manager_ops.dev); @@ -55,7 +55,7 @@ void ps3_sys_manager_power_off(void) ps3_sys_manager_halt(); } -void ps3_sys_manager_restart(void) +void __noreturn ps3_sys_manager_restart(void) { if (ps3_sys_manager_ops.restart) ps3_sys_manager_ops.restart(ps3_sys_manager_ops.dev); @@ -63,7 +63,7 @@ void ps3_sys_manager_restart(void) ps3_sys_manager_halt(); } -void ps3_sys_manager_halt(void) +void __noreturn ps3_sys_manager_halt(void) { pr_emerg("System Halted, OK to turn off power\n"); local_irq_disable(); diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h index eb7f6d94a890..23358b719319 100644 --- a/drivers/ps3/vuart.h +++ b/drivers/ps3/vuart.h @@ -82,4 +82,20 @@ void ps3_vuart_cancel_async(struct ps3_system_bus_device *dev); void ps3_vuart_clear_rx_bytes(struct ps3_system_bus_device *dev, unsigned int bytes); +struct vuart_triggers { + unsigned long rx; + unsigned long tx; +}; + +int ps3_vuart_get_triggers(struct ps3_system_bus_device *dev, + struct vuart_triggers *trig); +int ps3_vuart_set_triggers(struct ps3_system_bus_device *dev, unsigned int tx, + unsigned int rx); +int ps3_vuart_enable_interrupt_tx(struct ps3_system_bus_device *dev); +int ps3_vuart_disable_interrupt_tx(struct ps3_system_bus_device *dev); +int ps3_vuart_enable_interrupt_rx(struct ps3_system_bus_device *dev); +int ps3_vuart_disable_interrupt_rx(struct ps3_system_bus_device *dev); +int ps3_vuart_enable_interrupt_disconnect(struct ps3_system_bus_device *dev); +int ps3_vuart_disable_interrupt_disconnect(struct ps3_system_bus_device *dev); + #endif diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c index 8bcfecd66281..eeca70ddbf61 100644 --- a/drivers/rapidio/devices/tsi721.c +++ b/drivers/rapidio/devices/tsi721.c @@ -2430,7 +2430,7 @@ static int tsi721_probe(struct pci_dev *pdev, pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_READRQ | PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN, - 0x2 << MAX_READ_REQUEST_SZ_SHIFT); + PCI_EXP_DEVCTL_READRQ_512B); /* Adjust PCIe completion timeout. */ pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL2, 0xf, 0x2); diff --git a/drivers/rapidio/devices/tsi721.h b/drivers/rapidio/devices/tsi721.h index a7b42680a06a..9d2502543ef6 100644 --- a/drivers/rapidio/devices/tsi721.h +++ b/drivers/rapidio/devices/tsi721.h @@ -72,8 +72,6 @@ #define TSI721_MSIXPBA_OFFSET 0x2a000 #define TSI721_PCIECFG_EPCTL 0x400 -#define MAX_READ_REQUEST_SZ_SHIFT 12 - /* * Event Management Registers */ diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index c3a60b57a865..a6f116aa5235 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -414,6 +414,14 @@ config REGULATOR_MAX77802 Exynos5420/Exynos5800 SoCs to control various voltages. It includes support for control of voltage and ramp speed. +config REGULATOR_MAX77843 + tristate "Maxim 77843 regulator" + depends on MFD_MAX77843 + help + This driver controls a Maxim 77843 regulator. + The regulator include two 'SAFEOUT' for USB(Universal Serial Bus) + This is suitable for Exynos5433 SoC chips. + config REGULATOR_MC13XXX_CORE tristate @@ -433,6 +441,15 @@ config REGULATOR_MC13892 Say y here to support the regulators found on the Freescale MC13892 PMIC. +config REGULATOR_MT6397 + tristate "MediaTek MT6397 PMIC" + depends on MFD_MT6397 + help + Say y here to select this option to enable the power regulator of + MediaTek MT6397 PMIC. + This driver supports the control of different power rails of device + through regulator interface. + config REGULATOR_PALMAS tristate "TI Palmas PMIC Regulators" depends on MFD_PALMAS diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 1f28ebfc6f3a..2c4da15e1545 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -55,9 +55,11 @@ obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o +obj-$(CONFIG_REGULATOR_MAX77843) += max77843.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o +obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index f23d7e1f2ee7..e4331f5e5d7d 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -32,11 +32,13 @@ #define AXP20X_FREQ_DCDC_MASK 0x0f -#define AXP20X_DESC_IO(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg, \ - _emask, _enable_val, _disable_val) \ +#define AXP20X_DESC_IO(_id, _match, _supply, _min, _max, _step, _vreg, _vmask, \ + _ereg, _emask, _enable_val, _disable_val) \ [AXP20X_##_id] = { \ .name = #_id, \ .supply_name = (_supply), \ + .of_match = of_match_ptr(_match), \ + .regulators_node = of_match_ptr("regulators"), \ .type = REGULATOR_VOLTAGE, \ .id = AXP20X_##_id, \ .n_voltages = (((_max) - (_min)) / (_step) + 1), \ @@ -52,11 +54,13 @@ .ops = &axp20x_ops, \ } -#define AXP20X_DESC(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg, \ - _emask) \ +#define AXP20X_DESC(_id, _match, _supply, _min, _max, _step, _vreg, _vmask, \ + _ereg, _emask) \ [AXP20X_##_id] = { \ .name = #_id, \ .supply_name = (_supply), \ + .of_match = of_match_ptr(_match), \ + .regulators_node = of_match_ptr("regulators"), \ .type = REGULATOR_VOLTAGE, \ .id = AXP20X_##_id, \ .n_voltages = (((_max) - (_min)) / (_step) + 1), \ @@ -70,10 +74,12 @@ .ops = &axp20x_ops, \ } -#define AXP20X_DESC_FIXED(_id, _supply, _volt) \ +#define AXP20X_DESC_FIXED(_id, _match, _supply, _volt) \ [AXP20X_##_id] = { \ .name = #_id, \ .supply_name = (_supply), \ + .of_match = of_match_ptr(_match), \ + .regulators_node = of_match_ptr("regulators"), \ .type = REGULATOR_VOLTAGE, \ .id = AXP20X_##_id, \ .n_voltages = 1, \ @@ -82,10 +88,13 @@ .ops = &axp20x_ops_fixed \ } -#define AXP20X_DESC_TABLE(_id, _supply, _table, _vreg, _vmask, _ereg, _emask) \ +#define AXP20X_DESC_TABLE(_id, _match, _supply, _table, _vreg, _vmask, _ereg, \ + _emask) \ [AXP20X_##_id] = { \ .name = #_id, \ .supply_name = (_supply), \ + .of_match = of_match_ptr(_match), \ + .regulators_node = of_match_ptr("regulators"), \ .type = REGULATOR_VOLTAGE, \ .id = AXP20X_##_id, \ .n_voltages = ARRAY_SIZE(_table), \ @@ -127,36 +136,20 @@ static struct regulator_ops axp20x_ops = { }; static const struct regulator_desc axp20x_regulators[] = { - AXP20X_DESC(DCDC2, "vin2", 700, 2275, 25, AXP20X_DCDC2_V_OUT, 0x3f, - AXP20X_PWR_OUT_CTRL, 0x10), - AXP20X_DESC(DCDC3, "vin3", 700, 3500, 25, AXP20X_DCDC3_V_OUT, 0x7f, - AXP20X_PWR_OUT_CTRL, 0x02), - AXP20X_DESC_FIXED(LDO1, "acin", 1300), - AXP20X_DESC(LDO2, "ldo24in", 1800, 3300, 100, AXP20X_LDO24_V_OUT, 0xf0, - AXP20X_PWR_OUT_CTRL, 0x04), - AXP20X_DESC(LDO3, "ldo3in", 700, 3500, 25, AXP20X_LDO3_V_OUT, 0x7f, - AXP20X_PWR_OUT_CTRL, 0x40), - AXP20X_DESC_TABLE(LDO4, "ldo24in", axp20x_ldo4_data, AXP20X_LDO24_V_OUT, 0x0f, - AXP20X_PWR_OUT_CTRL, 0x08), - AXP20X_DESC_IO(LDO5, "ldo5in", 1800, 3300, 100, AXP20X_LDO5_V_OUT, 0xf0, - AXP20X_GPIO0_CTRL, 0x07, AXP20X_IO_ENABLED, - AXP20X_IO_DISABLED), -}; - -#define AXP_MATCH(_name, _id) \ - [AXP20X_##_id] = { \ - .name = #_name, \ - .driver_data = (void *) &axp20x_regulators[AXP20X_##_id], \ - } - -static struct of_regulator_match axp20x_matches[] = { - AXP_MATCH(dcdc2, DCDC2), - AXP_MATCH(dcdc3, DCDC3), - AXP_MATCH(ldo1, LDO1), - AXP_MATCH(ldo2, LDO2), - AXP_MATCH(ldo3, LDO3), - AXP_MATCH(ldo4, LDO4), - AXP_MATCH(ldo5, LDO5), + AXP20X_DESC(DCDC2, "dcdc2", "vin2", 700, 2275, 25, AXP20X_DCDC2_V_OUT, + 0x3f, AXP20X_PWR_OUT_CTRL, 0x10), + AXP20X_DESC(DCDC3, "dcdc3", "vin3", 700, 3500, 25, AXP20X_DCDC3_V_OUT, + 0x7f, AXP20X_PWR_OUT_CTRL, 0x02), + AXP20X_DESC_FIXED(LDO1, "ldo1", "acin", 1300), + AXP20X_DESC(LDO2, "ldo2", "ldo24in", 1800, 3300, 100, + AXP20X_LDO24_V_OUT, 0xf0, AXP20X_PWR_OUT_CTRL, 0x04), + AXP20X_DESC(LDO3, "ldo3", "ldo3in", 700, 3500, 25, AXP20X_LDO3_V_OUT, + 0x7f, AXP20X_PWR_OUT_CTRL, 0x40), + AXP20X_DESC_TABLE(LDO4, "ldo4", "ldo24in", axp20x_ldo4_data, + AXP20X_LDO24_V_OUT, 0x0f, AXP20X_PWR_OUT_CTRL, 0x08), + AXP20X_DESC_IO(LDO5, "ldo5", "ldo5in", 1800, 3300, 100, + AXP20X_LDO5_V_OUT, 0xf0, AXP20X_GPIO0_CTRL, 0x07, + AXP20X_IO_ENABLED, AXP20X_IO_DISABLED), }; static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) @@ -193,13 +186,6 @@ static int axp20x_regulator_parse_dt(struct platform_device *pdev) if (!regulators) { dev_warn(&pdev->dev, "regulators node not found\n"); } else { - ret = of_regulator_match(&pdev->dev, regulators, axp20x_matches, - ARRAY_SIZE(axp20x_matches)); - if (ret < 0) { - dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); - return ret; - } - dcdcfreq = 1500; of_property_read_u32(regulators, "x-powers,dcdc-freq", &dcdcfreq); ret = axp20x_set_dcdc_freq(pdev, dcdcfreq); @@ -233,23 +219,17 @@ static int axp20x_regulator_probe(struct platform_device *pdev) { struct regulator_dev *rdev; struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); - struct regulator_config config = { }; - struct regulator_init_data *init_data; + struct regulator_config config = { + .dev = pdev->dev.parent, + .regmap = axp20x->regmap, + }; int ret, i; u32 workmode; - ret = axp20x_regulator_parse_dt(pdev); - if (ret) - return ret; + /* This only sets the dcdc freq. Ignore any errors */ + axp20x_regulator_parse_dt(pdev); for (i = 0; i < AXP20X_REG_ID_MAX; i++) { - init_data = axp20x_matches[i].init_data; - - config.dev = pdev->dev.parent; - config.init_data = init_data; - config.regmap = axp20x->regmap; - config.of_node = axp20x_matches[i].of_node; - rdev = devm_regulator_register(&pdev->dev, &axp20x_regulators[i], &config); if (IS_ERR(rdev)) { @@ -259,7 +239,8 @@ static int axp20x_regulator_probe(struct platform_device *pdev) return PTR_ERR(rdev); } - ret = of_property_read_u32(axp20x_matches[i].of_node, "x-powers,dcdc-workmode", + ret = of_property_read_u32(rdev->dev.of_node, + "x-powers,dcdc-workmode", &workmode); if (!ret) { if (axp20x_set_dcdc_workmode(rdev, i, workmode)) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e225711bb8bc..b899947d839d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -632,49 +632,34 @@ static ssize_t regulator_bypass_show(struct device *dev, static DEVICE_ATTR(bypass, 0444, regulator_bypass_show, NULL); -/* - * These are the only attributes are present for all regulators. - * Other attributes are a function of regulator functionality. - */ -static struct attribute *regulator_dev_attrs[] = { - &dev_attr_name.attr, - &dev_attr_num_users.attr, - &dev_attr_type.attr, - NULL, -}; -ATTRIBUTE_GROUPS(regulator_dev); - -static void regulator_dev_release(struct device *dev) -{ - struct regulator_dev *rdev = dev_get_drvdata(dev); - kfree(rdev); -} - -static struct class regulator_class = { - .name = "regulator", - .dev_release = regulator_dev_release, - .dev_groups = regulator_dev_groups, -}; - /* Calculate the new optimum regulator operating mode based on the new total * consumer load. All locks held by caller */ -static void drms_uA_update(struct regulator_dev *rdev) +static int drms_uA_update(struct regulator_dev *rdev) { struct regulator *sibling; int current_uA = 0, output_uV, input_uV, err; unsigned int mode; + /* + * first check to see if we can set modes at all, otherwise just + * tell the consumer everything is OK. + */ err = regulator_check_drms(rdev); - if (err < 0 || !rdev->desc->ops->get_optimum_mode || - (!rdev->desc->ops->get_voltage && - !rdev->desc->ops->get_voltage_sel) || - !rdev->desc->ops->set_mode) - return; + if (err < 0) + return 0; + + if (!rdev->desc->ops->get_optimum_mode) + return 0; + + if (!rdev->desc->ops->set_mode) + return -EINVAL; /* get output voltage */ output_uV = _regulator_get_voltage(rdev); - if (output_uV <= 0) - return; + if (output_uV <= 0) { + rdev_err(rdev, "invalid output voltage found\n"); + return -EINVAL; + } /* get input voltage */ input_uV = 0; @@ -682,8 +667,10 @@ static void drms_uA_update(struct regulator_dev *rdev) input_uV = regulator_get_voltage(rdev->supply); if (input_uV <= 0) input_uV = rdev->constraints->input_uV; - if (input_uV <= 0) - return; + if (input_uV <= 0) { + rdev_err(rdev, "invalid input voltage found\n"); + return -EINVAL; + } /* calc total requested load */ list_for_each_entry(sibling, &rdev->consumer_list, list) @@ -695,8 +682,17 @@ static void drms_uA_update(struct regulator_dev *rdev) /* check the new mode is allowed */ err = regulator_mode_constrain(rdev, &mode); - if (err == 0) - rdev->desc->ops->set_mode(rdev, mode); + if (err < 0) { + rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n", + current_uA, input_uV, output_uV); + return err; + } + + err = rdev->desc->ops->set_mode(rdev, mode); + if (err < 0) + rdev_err(rdev, "failed to set optimum mode %x\n", mode); + + return err; } static int suspend_set_state(struct regulator_dev *rdev, @@ -1488,7 +1484,7 @@ struct regulator *regulator_get_optional(struct device *dev, const char *id) } EXPORT_SYMBOL_GPL(regulator_get_optional); -/* Locks held by regulator_put() */ +/* regulator_list_mutex lock held by regulator_put() */ static void _regulator_put(struct regulator *regulator) { struct regulator_dev *rdev; @@ -1503,12 +1499,14 @@ static void _regulator_put(struct regulator *regulator) /* remove any sysfs entries */ if (regulator->dev) sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); + mutex_lock(&rdev->mutex); kfree(regulator->supply_name); list_del(®ulator->list); kfree(regulator); rdev->open_count--; rdev->exclusive = 0; + mutex_unlock(&rdev->mutex); module_put(rdev->owner); } @@ -3024,75 +3022,13 @@ EXPORT_SYMBOL_GPL(regulator_get_mode); int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) { struct regulator_dev *rdev = regulator->rdev; - struct regulator *consumer; - int ret, output_uV, input_uV = 0, total_uA_load = 0; - unsigned int mode; - - if (rdev->supply) - input_uV = regulator_get_voltage(rdev->supply); + int ret; mutex_lock(&rdev->mutex); - - /* - * first check to see if we can set modes at all, otherwise just - * tell the consumer everything is OK. - */ regulator->uA_load = uA_load; - ret = regulator_check_drms(rdev); - if (ret < 0) { - ret = 0; - goto out; - } - - if (!rdev->desc->ops->get_optimum_mode) - goto out; - - /* - * we can actually do this so any errors are indicators of - * potential real failure. - */ - ret = -EINVAL; - - if (!rdev->desc->ops->set_mode) - goto out; - - /* get output voltage */ - output_uV = _regulator_get_voltage(rdev); - if (output_uV <= 0) { - rdev_err(rdev, "invalid output voltage found\n"); - goto out; - } - - /* No supply? Use constraint voltage */ - if (input_uV <= 0) - input_uV = rdev->constraints->input_uV; - if (input_uV <= 0) { - rdev_err(rdev, "invalid input voltage found\n"); - goto out; - } - - /* calc total requested load for this regulator */ - list_for_each_entry(consumer, &rdev->consumer_list, list) - total_uA_load += consumer->uA_load; - - mode = rdev->desc->ops->get_optimum_mode(rdev, - input_uV, output_uV, - total_uA_load); - ret = regulator_mode_constrain(rdev, &mode); - if (ret < 0) { - rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n", - total_uA_load, input_uV, output_uV); - goto out; - } - - ret = rdev->desc->ops->set_mode(rdev, mode); - if (ret < 0) { - rdev_err(rdev, "failed to set optimum mode %x\n", mode); - goto out; - } - ret = mode; -out: + ret = drms_uA_update(rdev); mutex_unlock(&rdev->mutex); + return ret; } EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); @@ -3434,126 +3370,136 @@ int regulator_mode_to_status(unsigned int mode) } EXPORT_SYMBOL_GPL(regulator_mode_to_status); +static struct attribute *regulator_dev_attrs[] = { + &dev_attr_name.attr, + &dev_attr_num_users.attr, + &dev_attr_type.attr, + &dev_attr_microvolts.attr, + &dev_attr_microamps.attr, + &dev_attr_opmode.attr, + &dev_attr_state.attr, + &dev_attr_status.attr, + &dev_attr_bypass.attr, + &dev_attr_requested_microamps.attr, + &dev_attr_min_microvolts.attr, + &dev_attr_max_microvolts.attr, + &dev_attr_min_microamps.attr, + &dev_attr_max_microamps.attr, + &dev_attr_suspend_standby_state.attr, + &dev_attr_suspend_mem_state.attr, + &dev_attr_suspend_disk_state.attr, + &dev_attr_suspend_standby_microvolts.attr, + &dev_attr_suspend_mem_microvolts.attr, + &dev_attr_suspend_disk_microvolts.attr, + &dev_attr_suspend_standby_mode.attr, + &dev_attr_suspend_mem_mode.attr, + &dev_attr_suspend_disk_mode.attr, + NULL +}; + /* * To avoid cluttering sysfs (and memory) with useless state, only * create attributes that can be meaningfully displayed. */ -static int add_regulator_attributes(struct regulator_dev *rdev) +static umode_t regulator_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int idx) { - struct device *dev = &rdev->dev; + struct device *dev = kobj_to_dev(kobj); + struct regulator_dev *rdev = container_of(dev, struct regulator_dev, dev); const struct regulator_ops *ops = rdev->desc->ops; - int status = 0; + umode_t mode = attr->mode; + + /* these three are always present */ + if (attr == &dev_attr_name.attr || + attr == &dev_attr_num_users.attr || + attr == &dev_attr_type.attr) + return mode; /* some attributes need specific methods to be displayed */ - if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || - (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) || - (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) || - (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1))) { - status = device_create_file(dev, &dev_attr_microvolts); - if (status < 0) - return status; - } - if (ops->get_current_limit) { - status = device_create_file(dev, &dev_attr_microamps); - if (status < 0) - return status; - } - if (ops->get_mode) { - status = device_create_file(dev, &dev_attr_opmode); - if (status < 0) - return status; - } - if (rdev->ena_pin || ops->is_enabled) { - status = device_create_file(dev, &dev_attr_state); - if (status < 0) - return status; - } - if (ops->get_status) { - status = device_create_file(dev, &dev_attr_status); - if (status < 0) - return status; - } - if (ops->get_bypass) { - status = device_create_file(dev, &dev_attr_bypass); - if (status < 0) - return status; + if (attr == &dev_attr_microvolts.attr) { + if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || + (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) || + (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) || + (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1)) + return mode; + return 0; } + if (attr == &dev_attr_microamps.attr) + return ops->get_current_limit ? mode : 0; + + if (attr == &dev_attr_opmode.attr) + return ops->get_mode ? mode : 0; + + if (attr == &dev_attr_state.attr) + return (rdev->ena_pin || ops->is_enabled) ? mode : 0; + + if (attr == &dev_attr_status.attr) + return ops->get_status ? mode : 0; + + if (attr == &dev_attr_bypass.attr) + return ops->get_bypass ? mode : 0; + /* some attributes are type-specific */ - if (rdev->desc->type == REGULATOR_CURRENT) { - status = device_create_file(dev, &dev_attr_requested_microamps); - if (status < 0) - return status; - } + if (attr == &dev_attr_requested_microamps.attr) + return rdev->desc->type == REGULATOR_CURRENT ? mode : 0; /* all the other attributes exist to support constraints; * don't show them if there are no constraints, or if the * relevant supporting methods are missing. */ if (!rdev->constraints) - return status; + return 0; /* constraints need specific supporting methods */ - if (ops->set_voltage || ops->set_voltage_sel) { - status = device_create_file(dev, &dev_attr_min_microvolts); - if (status < 0) - return status; - status = device_create_file(dev, &dev_attr_max_microvolts); - if (status < 0) - return status; - } - if (ops->set_current_limit) { - status = device_create_file(dev, &dev_attr_min_microamps); - if (status < 0) - return status; - status = device_create_file(dev, &dev_attr_max_microamps); - if (status < 0) - return status; - } + if (attr == &dev_attr_min_microvolts.attr || + attr == &dev_attr_max_microvolts.attr) + return (ops->set_voltage || ops->set_voltage_sel) ? mode : 0; - status = device_create_file(dev, &dev_attr_suspend_standby_state); - if (status < 0) - return status; - status = device_create_file(dev, &dev_attr_suspend_mem_state); - if (status < 0) - return status; - status = device_create_file(dev, &dev_attr_suspend_disk_state); - if (status < 0) - return status; + if (attr == &dev_attr_min_microamps.attr || + attr == &dev_attr_max_microamps.attr) + return ops->set_current_limit ? mode : 0; - if (ops->set_suspend_voltage) { - status = device_create_file(dev, - &dev_attr_suspend_standby_microvolts); - if (status < 0) - return status; - status = device_create_file(dev, - &dev_attr_suspend_mem_microvolts); - if (status < 0) - return status; - status = device_create_file(dev, - &dev_attr_suspend_disk_microvolts); - if (status < 0) - return status; - } + if (attr == &dev_attr_suspend_standby_state.attr || + attr == &dev_attr_suspend_mem_state.attr || + attr == &dev_attr_suspend_disk_state.attr) + return mode; - if (ops->set_suspend_mode) { - status = device_create_file(dev, - &dev_attr_suspend_standby_mode); - if (status < 0) - return status; - status = device_create_file(dev, - &dev_attr_suspend_mem_mode); - if (status < 0) - return status; - status = device_create_file(dev, - &dev_attr_suspend_disk_mode); - if (status < 0) - return status; - } + if (attr == &dev_attr_suspend_standby_microvolts.attr || + attr == &dev_attr_suspend_mem_microvolts.attr || + attr == &dev_attr_suspend_disk_microvolts.attr) + return ops->set_suspend_voltage ? mode : 0; - return status; + if (attr == &dev_attr_suspend_standby_mode.attr || + attr == &dev_attr_suspend_mem_mode.attr || + attr == &dev_attr_suspend_disk_mode.attr) + return ops->set_suspend_mode ? mode : 0; + + return mode; } +static const struct attribute_group regulator_dev_group = { + .attrs = regulator_dev_attrs, + .is_visible = regulator_attr_is_visible, +}; + +static const struct attribute_group *regulator_dev_groups[] = { + ®ulator_dev_group, + NULL +}; + +static void regulator_dev_release(struct device *dev) +{ + struct regulator_dev *rdev = dev_get_drvdata(dev); + kfree(rdev); +} + +static struct class regulator_class = { + .name = "regulator", + .dev_release = regulator_dev_release, + .dev_groups = regulator_dev_groups, +}; + static void rdev_init_debugfs(struct regulator_dev *rdev) { rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root); @@ -3573,7 +3519,7 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) /** * regulator_register - register regulator * @regulator_desc: regulator to register - * @config: runtime configuration for regulator + * @cfg: runtime configuration for regulator * * Called by regulator drivers to register a regulator. * Returns a valid pointer to struct regulator_dev on success @@ -3581,20 +3527,21 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) */ struct regulator_dev * regulator_register(const struct regulator_desc *regulator_desc, - const struct regulator_config *config) + const struct regulator_config *cfg) { const struct regulation_constraints *constraints = NULL; const struct regulator_init_data *init_data; - static atomic_t regulator_no = ATOMIC_INIT(0); + struct regulator_config *config = NULL; + static atomic_t regulator_no = ATOMIC_INIT(-1); struct regulator_dev *rdev; struct device *dev; int ret, i; const char *supply = NULL; - if (regulator_desc == NULL || config == NULL) + if (regulator_desc == NULL || cfg == NULL) return ERR_PTR(-EINVAL); - dev = config->dev; + dev = cfg->dev; WARN_ON(!dev); if (regulator_desc->name == NULL || regulator_desc->ops == NULL) @@ -3624,7 +3571,17 @@ regulator_register(const struct regulator_desc *regulator_desc, if (rdev == NULL) return ERR_PTR(-ENOMEM); - init_data = regulator_of_get_init_data(dev, regulator_desc, + /* + * Duplicate the config so the driver could override it after + * parsing init data. + */ + config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL); + if (config == NULL) { + kfree(rdev); + return ERR_PTR(-ENOMEM); + } + + init_data = regulator_of_get_init_data(dev, regulator_desc, config, &rdev->dev.of_node); if (!init_data) { init_data = config->init_data; @@ -3658,8 +3615,8 @@ regulator_register(const struct regulator_desc *regulator_desc, /* register with sysfs */ rdev->dev.class = ®ulator_class; rdev->dev.parent = dev; - dev_set_name(&rdev->dev, "regulator.%d", - atomic_inc_return(®ulator_no) - 1); + dev_set_name(&rdev->dev, "regulator.%lu", + (unsigned long) atomic_inc_return(®ulator_no)); ret = device_register(&rdev->dev); if (ret != 0) { put_device(&rdev->dev); @@ -3692,11 +3649,6 @@ regulator_register(const struct regulator_desc *regulator_desc, if (ret < 0) goto scrub; - /* add attributes supported by this regulator */ - ret = add_regulator_attributes(rdev); - if (ret < 0) - goto scrub; - if (init_data && init_data->supply_regulator) supply = init_data->supply_regulator; else if (regulator_desc->supply_name) @@ -3752,6 +3704,7 @@ add_dev: rdev_init_debugfs(rdev); out: mutex_unlock(®ulator_list_mutex); + kfree(config); return rdev; unset_supplies: diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index c78d2106d6cb..01343419555e 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include "da9211-regulator.h" @@ -276,7 +277,10 @@ static struct da9211_pdata *da9211_parse_regulators_dt( continue; pdata->init_data[n] = da9211_matches[i].init_data; - + pdata->reg_node[n] = da9211_matches[i].of_node; + pdata->gpio_ren[n] = + of_get_named_gpio(da9211_matches[i].of_node, + "enable-gpios", 0); n++; } @@ -364,7 +368,15 @@ static int da9211_regulator_init(struct da9211 *chip) config.dev = chip->dev; config.driver_data = chip; config.regmap = chip->regmap; - config.of_node = chip->dev->of_node; + config.of_node = chip->pdata->reg_node[i]; + + if (gpio_is_valid(chip->pdata->gpio_ren[i])) { + config.ena_gpio = chip->pdata->gpio_ren[i]; + config.ena_gpio_initialized = true; + } else { + config.ena_gpio = -EINVAL; + config.ena_gpio_initialized = false; + } chip->rdev[i] = devm_regulator_register(chip->dev, &da9211_regulators[i], &config); diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 6c43ab2d5121..3c25db89a021 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -147,7 +147,7 @@ static unsigned int fan53555_get_mode(struct regulator_dev *rdev) return REGULATOR_MODE_NORMAL; } -static int slew_rates[] = { +static const int slew_rates[] = { 64000, 32000, 16000, @@ -296,7 +296,7 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, return PTR_ERR_OR_ZERO(di->rdev); } -static struct regmap_config fan53555_regmap_config = { +static const struct regmap_config fan53555_regmap_config = { .reg_bits = 8, .val_bits = 8, }; diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h index 80ba2a35a04b..c74ac8734023 100644 --- a/drivers/regulator/internal.h +++ b/drivers/regulator/internal.h @@ -38,11 +38,13 @@ struct regulator { #ifdef CONFIG_OF struct regulator_init_data *regulator_of_get_init_data(struct device *dev, const struct regulator_desc *desc, + struct regulator_config *config, struct device_node **node); #else static inline struct regulator_init_data * regulator_of_get_init_data(struct device *dev, const struct regulator_desc *desc, + struct regulator_config *config, struct device_node **node) { return NULL; diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c index 92fefd98da58..6e3a15fe00f1 100644 --- a/drivers/regulator/isl9305.c +++ b/drivers/regulator/isl9305.c @@ -177,8 +177,10 @@ static int isl9305_i2c_probe(struct i2c_client *i2c, #ifdef CONFIG_OF static const struct of_device_id isl9305_dt_ids[] = { - { .compatible = "isl,isl9305" }, - { .compatible = "isl,isl9305h" }, + { .compatible = "isl,isl9305" }, /* for backward compat., don't use */ + { .compatible = "isil,isl9305" }, + { .compatible = "isl,isl9305h" }, /* for backward compat., don't use */ + { .compatible = "isil,isl9305h" }, {}, }; #endif diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 021d64d856bb..3de328ab41f3 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -106,7 +106,6 @@ struct lp872x { struct device *dev; enum lp872x_id chipid; struct lp872x_platform_data *pdata; - struct regulator_dev **regulators; int num_regulators; enum lp872x_dvs_state dvs_pin; int dvs_gpio; @@ -801,8 +800,6 @@ static int lp872x_regulator_register(struct lp872x *lp) dev_err(lp->dev, "regulator register err"); return PTR_ERR(rdev); } - - *(lp->regulators + i) = rdev; } return 0; @@ -906,7 +903,7 @@ static struct lp872x_platform_data static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id) { struct lp872x *lp; - int ret, size, num_regulators; + int ret; const int lp872x_num_regulators[] = { [LP8720] = LP8720_NUM_REGULATORS, [LP8725] = LP8725_NUM_REGULATORS, @@ -918,38 +915,27 @@ static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id) lp = devm_kzalloc(&cl->dev, sizeof(struct lp872x), GFP_KERNEL); if (!lp) - goto err_mem; + return -ENOMEM; - num_regulators = lp872x_num_regulators[id->driver_data]; - size = sizeof(struct regulator_dev *) * num_regulators; - - lp->regulators = devm_kzalloc(&cl->dev, size, GFP_KERNEL); - if (!lp->regulators) - goto err_mem; + lp->num_regulators = lp872x_num_regulators[id->driver_data]; lp->regmap = devm_regmap_init_i2c(cl, &lp872x_regmap_config); if (IS_ERR(lp->regmap)) { ret = PTR_ERR(lp->regmap); dev_err(&cl->dev, "regmap init i2c err: %d\n", ret); - goto err_dev; + return ret; } lp->dev = &cl->dev; lp->pdata = dev_get_platdata(&cl->dev); lp->chipid = id->driver_data; - lp->num_regulators = num_regulators; i2c_set_clientdata(cl, lp); ret = lp872x_config(lp); if (ret) - goto err_dev; + return ret; return lp872x_regulator_register(lp); - -err_mem: - return -ENOMEM; -err_dev: - return ret; } static const struct of_device_id lp872x_dt_ids[] = { diff --git a/drivers/regulator/max14577.c b/drivers/regulator/max14577.c index bf9a44c5fdd2..b3678d289619 100644 --- a/drivers/regulator/max14577.c +++ b/drivers/regulator/max14577.c @@ -103,6 +103,8 @@ static struct regulator_ops max14577_charger_ops = { static const struct regulator_desc max14577_supported_regulators[] = { [MAX14577_SAFEOUT] = { .name = "SAFEOUT", + .of_match = of_match_ptr("SAFEOUT"), + .regulators_node = of_match_ptr("regulators"), .id = MAX14577_SAFEOUT, .ops = &max14577_safeout_ops, .type = REGULATOR_VOLTAGE, @@ -114,6 +116,8 @@ static const struct regulator_desc max14577_supported_regulators[] = { }, [MAX14577_CHARGER] = { .name = "CHARGER", + .of_match = of_match_ptr("CHARGER"), + .regulators_node = of_match_ptr("regulators"), .id = MAX14577_CHARGER, .ops = &max14577_charger_ops, .type = REGULATOR_CURRENT, @@ -137,6 +141,8 @@ static struct regulator_ops max77836_ldo_ops = { static const struct regulator_desc max77836_supported_regulators[] = { [MAX14577_SAFEOUT] = { .name = "SAFEOUT", + .of_match = of_match_ptr("SAFEOUT"), + .regulators_node = of_match_ptr("regulators"), .id = MAX14577_SAFEOUT, .ops = &max14577_safeout_ops, .type = REGULATOR_VOLTAGE, @@ -148,6 +154,8 @@ static const struct regulator_desc max77836_supported_regulators[] = { }, [MAX14577_CHARGER] = { .name = "CHARGER", + .of_match = of_match_ptr("CHARGER"), + .regulators_node = of_match_ptr("regulators"), .id = MAX14577_CHARGER, .ops = &max14577_charger_ops, .type = REGULATOR_CURRENT, @@ -157,6 +165,8 @@ static const struct regulator_desc max77836_supported_regulators[] = { }, [MAX77836_LDO1] = { .name = "LDO1", + .of_match = of_match_ptr("LDO1"), + .regulators_node = of_match_ptr("regulators"), .id = MAX77836_LDO1, .ops = &max77836_ldo_ops, .type = REGULATOR_VOLTAGE, @@ -171,6 +181,8 @@ static const struct regulator_desc max77836_supported_regulators[] = { }, [MAX77836_LDO2] = { .name = "LDO2", + .of_match = of_match_ptr("LDO2"), + .regulators_node = of_match_ptr("regulators"), .id = MAX77836_LDO2, .ops = &max77836_ldo_ops, .type = REGULATOR_VOLTAGE, @@ -198,43 +210,6 @@ static struct of_regulator_match max77836_regulator_matches[] = { { .name = "LDO2", }, }; -static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev, - enum maxim_device_type dev_type) -{ - int ret; - struct device_node *np; - struct of_regulator_match *regulator_matches; - unsigned int regulator_matches_size; - - np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); - if (!np) { - dev_err(&pdev->dev, "Failed to get child OF node for regulators\n"); - return -EINVAL; - } - - switch (dev_type) { - case MAXIM_DEVICE_TYPE_MAX77836: - regulator_matches = max77836_regulator_matches; - regulator_matches_size = ARRAY_SIZE(max77836_regulator_matches); - break; - case MAXIM_DEVICE_TYPE_MAX14577: - default: - regulator_matches = max14577_regulator_matches; - regulator_matches_size = ARRAY_SIZE(max14577_regulator_matches); - } - - ret = of_regulator_match(&pdev->dev, np, regulator_matches, - regulator_matches_size); - if (ret < 0) - dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); - else - ret = 0; - - of_node_put(np); - - return ret; -} - static inline struct regulator_init_data *match_init_data(int index, enum maxim_device_type dev_type) { @@ -261,11 +236,6 @@ static inline struct device_node *match_of_node(int index, } } #else /* CONFIG_OF */ -static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev, - enum maxim_device_type dev_type) -{ - return 0; -} static inline struct regulator_init_data *match_init_data(int index, enum maxim_device_type dev_type) { @@ -308,16 +278,12 @@ static int max14577_regulator_probe(struct platform_device *pdev) { struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent); struct max14577_platform_data *pdata = dev_get_platdata(max14577->dev); - int i, ret; + int i, ret = 0; struct regulator_config config = {}; const struct regulator_desc *supported_regulators; unsigned int supported_regulators_size; enum maxim_device_type dev_type = max14577->dev_type; - ret = max14577_regulator_dt_parse_pdata(pdev, dev_type); - if (ret) - return ret; - switch (dev_type) { case MAXIM_DEVICE_TYPE_MAX77836: supported_regulators = max77836_supported_regulators; @@ -329,7 +295,7 @@ static int max14577_regulator_probe(struct platform_device *pdev) supported_regulators_size = ARRAY_SIZE(max14577_supported_regulators); } - config.dev = &pdev->dev; + config.dev = max14577->dev; config.driver_data = max14577; for (i = 0; i < supported_regulators_size; i++) { diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c index 10d206266ac2..15fb1416bfbd 100644 --- a/drivers/regulator/max77686.c +++ b/drivers/regulator/max77686.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,11 @@ #define MAX77686_DVS_MINUV 600000 #define MAX77686_DVS_UVSTEP 12500 +/* + * Value for configuring buck[89] and LDO{20,21,22} as GPIO control. + * It is the same as 'off' for other regulators. + */ +#define MAX77686_GPIO_CONTROL 0x0 /* * Values used for configuring LDOs and bucks. * Forcing low power mode: LDO1, 3-5, 9, 13, 17-26 @@ -82,6 +88,8 @@ enum max77686_ramp_rate { }; struct max77686_data { + u64 gpio_enabled:MAX77686_REGULATORS; + /* Array indexed by regulator id */ unsigned int opmode[MAX77686_REGULATORS]; }; @@ -100,6 +108,26 @@ static unsigned int max77686_get_opmode_shift(int id) } } +/* + * When regulator is configured for GPIO control then it + * replaces "normal" mode. Any change from low power mode to normal + * should actually change to GPIO control. + * Map normal mode to proper value for such regulators. + */ +static unsigned int max77686_map_normal_mode(struct max77686_data *max77686, + int id) +{ + switch (id) { + case MAX77686_BUCK8: + case MAX77686_BUCK9: + case MAX77686_LDO20 ... MAX77686_LDO22: + if (max77686->gpio_enabled & (1 << id)) + return MAX77686_GPIO_CONTROL; + } + + return MAX77686_NORMAL; +} + /* Some BUCKs and LDOs supports Normal[ON/OFF] mode during suspend */ static int max77686_set_suspend_disable(struct regulator_dev *rdev) { @@ -136,7 +164,7 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev, val = MAX77686_LDO_LOWPOWER_PWRREQ; break; case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ - val = MAX77686_NORMAL; + val = max77686_map_normal_mode(max77686, id); break; default: pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n", @@ -160,7 +188,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev, { unsigned int val; struct max77686_data *max77686 = rdev_get_drvdata(rdev); - int ret; + int ret, id = rdev_get_id(rdev); switch (mode) { case REGULATOR_MODE_STANDBY: /* switch off */ @@ -170,7 +198,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev, val = MAX77686_LDO_LOWPOWER_PWRREQ; break; case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ - val = MAX77686_NORMAL; + val = max77686_map_normal_mode(max77686, id); break; default: pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n", @@ -184,7 +212,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev, if (ret) return ret; - max77686->opmode[rdev_get_id(rdev)] = val; + max77686->opmode[id] = val; return 0; } @@ -197,7 +225,7 @@ static int max77686_enable(struct regulator_dev *rdev) shift = max77686_get_opmode_shift(id); if (max77686->opmode[id] == MAX77686_OFF_PWRREQ) - max77686->opmode[id] = MAX77686_NORMAL; + max77686->opmode[id] = max77686_map_normal_mode(max77686, id); return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, rdev->desc->enable_mask, @@ -229,6 +257,36 @@ static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) MAX77686_RAMP_RATE_MASK, ramp_value << 6); } +static int max77686_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct max77686_data *max77686 = config->driver_data; + + switch (desc->id) { + case MAX77686_BUCK8: + case MAX77686_BUCK9: + case MAX77686_LDO20 ... MAX77686_LDO22: + config->ena_gpio = of_get_named_gpio(np, + "maxim,ena-gpios", 0); + config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH; + config->ena_gpio_initialized = true; + break; + default: + return 0; + } + + if (gpio_is_valid(config->ena_gpio)) { + max77686->gpio_enabled |= (1 << desc->id); + + return regmap_update_bits(config->regmap, desc->enable_reg, + desc->enable_mask, + MAX77686_GPIO_CONTROL); + } + + return 0; +} + static struct regulator_ops max77686_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -283,6 +341,7 @@ static struct regulator_ops max77686_buck_dvs_ops = { .name = "LDO"#num, \ .of_match = of_match_ptr("LDO"#num), \ .regulators_node = of_match_ptr("voltage-regulators"), \ + .of_parse_cb = max77686_of_parse_cb, \ .id = MAX77686_LDO##num, \ .ops = &max77686_ops, \ .type = REGULATOR_VOLTAGE, \ @@ -355,6 +414,7 @@ static struct regulator_ops max77686_buck_dvs_ops = { .name = "BUCK"#num, \ .of_match = of_match_ptr("BUCK"#num), \ .regulators_node = of_match_ptr("voltage-regulators"), \ + .of_parse_cb = max77686_of_parse_cb, \ .id = MAX77686_BUCK##num, \ .ops = &max77686_ops, \ .type = REGULATOR_VOLTAGE, \ diff --git a/drivers/regulator/max77843.c b/drivers/regulator/max77843.c new file mode 100644 index 000000000000..c132ef527cdd --- /dev/null +++ b/drivers/regulator/max77843.c @@ -0,0 +1,227 @@ +/* + * max77843.c - Regulator driver for the Maxim MAX77843 + * + * Copyright (C) 2015 Samsung Electronics + * Author: Jaewon Kim + * Author: Beomho Seo + * + * 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 + +enum max77843_regulator_type { + MAX77843_SAFEOUT1 = 0, + MAX77843_SAFEOUT2, + MAX77843_CHARGER, + + MAX77843_NUM, +}; + +static const unsigned int max77843_safeout_voltage_table[] = { + 4850000, + 4900000, + 4950000, + 3300000, +}; + +static int max77843_reg_is_enabled(struct regulator_dev *rdev) +{ + struct regmap *regmap = rdev->regmap; + int ret; + unsigned int reg; + + ret = regmap_read(regmap, rdev->desc->enable_reg, ®); + if (ret) { + dev_err(&rdev->dev, "Fialed to read charger register\n"); + return ret; + } + + return (reg & rdev->desc->enable_mask) == rdev->desc->enable_mask; +} + +static int max77843_reg_get_current_limit(struct regulator_dev *rdev) +{ + struct regmap *regmap = rdev->regmap; + unsigned int chg_min_uA = rdev->constraints->min_uA; + unsigned int chg_max_uA = rdev->constraints->max_uA; + unsigned int val; + int ret; + unsigned int reg, sel; + + ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_02, ®); + if (ret) { + dev_err(&rdev->dev, "Failed to read charger register\n"); + return ret; + } + + sel = reg & MAX77843_CHG_FAST_CHG_CURRENT_MASK; + + if (sel < 0x03) + sel = 0; + else + sel -= 2; + + val = chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel; + if (val > chg_max_uA) + return -EINVAL; + + return val; +} + +static int max77843_reg_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + struct regmap *regmap = rdev->regmap; + unsigned int chg_min_uA = rdev->constraints->min_uA; + int sel = 0; + + while (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel < min_uA) + sel++; + + if (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel > max_uA) + return -EINVAL; + + sel += 2; + + return regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_02, sel); +} + +static struct regulator_ops max77843_charger_ops = { + .is_enabled = max77843_reg_is_enabled, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_current_limit = max77843_reg_get_current_limit, + .set_current_limit = max77843_reg_set_current_limit, +}; + +static struct regulator_ops max77843_regulator_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_table, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static const struct regulator_desc max77843_supported_regulators[] = { + [MAX77843_SAFEOUT1] = { + .name = "SAFEOUT1", + .id = MAX77843_SAFEOUT1, + .ops = &max77843_regulator_ops, + .of_match = of_match_ptr("SAFEOUT1"), + .regulators_node = of_match_ptr("regulators"), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(max77843_safeout_voltage_table), + .volt_table = max77843_safeout_voltage_table, + .enable_reg = MAX77843_SYS_REG_SAFEOUTCTRL, + .enable_mask = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT1, + .vsel_reg = MAX77843_SYS_REG_SAFEOUTCTRL, + .vsel_mask = MAX77843_REG_SAFEOUTCTRL_SAFEOUT1_MASK, + }, + [MAX77843_SAFEOUT2] = { + .name = "SAFEOUT2", + .id = MAX77843_SAFEOUT2, + .ops = &max77843_regulator_ops, + .of_match = of_match_ptr("SAFEOUT2"), + .regulators_node = of_match_ptr("regulators"), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(max77843_safeout_voltage_table), + .volt_table = max77843_safeout_voltage_table, + .enable_reg = MAX77843_SYS_REG_SAFEOUTCTRL, + .enable_mask = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT2, + .vsel_reg = MAX77843_SYS_REG_SAFEOUTCTRL, + .vsel_mask = MAX77843_REG_SAFEOUTCTRL_SAFEOUT2_MASK, + }, + [MAX77843_CHARGER] = { + .name = "CHARGER", + .id = MAX77843_CHARGER, + .ops = &max77843_charger_ops, + .of_match = of_match_ptr("CHARGER"), + .regulators_node = of_match_ptr("regulators"), + .type = REGULATOR_CURRENT, + .owner = THIS_MODULE, + .enable_reg = MAX77843_CHG_REG_CHG_CNFG_00, + .enable_mask = MAX77843_CHG_MASK, + }, +}; + +static struct regmap *max77843_get_regmap(struct max77843 *max77843, int reg_id) +{ + switch (reg_id) { + case MAX77843_SAFEOUT1: + case MAX77843_SAFEOUT2: + return max77843->regmap; + case MAX77843_CHARGER: + return max77843->regmap_chg; + default: + return max77843->regmap; + } +} + +static int max77843_regulator_probe(struct platform_device *pdev) +{ + struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = {}; + int i; + + config.dev = max77843->dev; + config.driver_data = max77843; + + for (i = 0; i < ARRAY_SIZE(max77843_supported_regulators); i++) { + struct regulator_dev *regulator; + + config.regmap = max77843_get_regmap(max77843, + max77843_supported_regulators[i].id); + + regulator = devm_regulator_register(&pdev->dev, + &max77843_supported_regulators[i], &config); + if (IS_ERR(regulator)) { + dev_err(&pdev->dev, + "Failed to regiser regulator-%d\n", i); + return PTR_ERR(regulator); + } + } + + return 0; +} + +static const struct platform_device_id max77843_regulator_id[] = { + { "max77843-regulator", }, + { /* sentinel */ }, +}; + +static struct platform_driver max77843_regulator_driver = { + .driver = { + .name = "max77843-regulator", + }, + .probe = max77843_regulator_probe, + .id_table = max77843_regulator_id, +}; + +static int __init max77843_regulator_init(void) +{ + return platform_driver_register(&max77843_regulator_driver); +} +subsys_initcall(max77843_regulator_init); + +static void __exit max77843_regulator_exit(void) +{ + platform_driver_unregister(&max77843_regulator_driver); +} +module_exit(max77843_regulator_exit); + +MODULE_AUTHOR("Jaewon Kim "); +MODULE_AUTHOR("Beomho Seo "); +MODULE_DESCRIPTION("Maxim MAX77843 regulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index c8bddcc8f911..81229579ece9 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -115,7 +115,7 @@ static unsigned int max8649_get_mode(struct regulator_dev *rdev) return REGULATOR_MODE_NORMAL; } -static struct regulator_ops max8649_dcdc_ops = { +static const struct regulator_ops max8649_dcdc_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, @@ -143,7 +143,7 @@ static struct regulator_desc dcdc_desc = { .enable_is_inverted = true, }; -static struct regmap_config max8649_regmap_config = { +static const struct regmap_config max8649_regmap_config = { .reg_bits = 8, .val_bits = 8, }; diff --git a/drivers/regulator/mt6397-regulator.c b/drivers/regulator/mt6397-regulator.c new file mode 100644 index 000000000000..a5b2f4762677 --- /dev/null +++ b/drivers/regulator/mt6397-regulator.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Flora Fu + * + * This 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * MT6397 regulators' information + * + * @desc: standard fields of regulator description. + * @qi: Mask for query enable signal status of regulators + * @vselon_reg: Register sections for hardware control mode of bucks + * @vselctrl_reg: Register for controlling the buck control mode. + * @vselctrl_mask: Mask for query buck's voltage control mode. + */ +struct mt6397_regulator_info { + struct regulator_desc desc; + u32 qi; + u32 vselon_reg; + u32 vselctrl_reg; + u32 vselctrl_mask; +}; + +#define MT6397_BUCK(match, vreg, min, max, step, volt_ranges, enreg, \ + vosel, vosel_mask, voselon, vosel_ctrl) \ +[MT6397_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6397_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6397_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = (max - min)/step + 1, \ + .linear_ranges = volt_ranges, \ + .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ + .vsel_reg = vosel, \ + .vsel_mask = vosel_mask, \ + .enable_reg = enreg, \ + .enable_mask = BIT(0), \ + }, \ + .qi = BIT(13), \ + .vselon_reg = voselon, \ + .vselctrl_reg = vosel_ctrl, \ + .vselctrl_mask = BIT(1), \ +} + +#define MT6397_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel, \ + vosel_mask) \ +[MT6397_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6397_volt_table_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6397_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(ldo_volt_table), \ + .volt_table = ldo_volt_table, \ + .vsel_reg = vosel, \ + .vsel_mask = vosel_mask, \ + .enable_reg = enreg, \ + .enable_mask = BIT(enbit), \ + }, \ + .qi = BIT(15), \ +} + +#define MT6397_REG_FIXED(match, vreg, enreg, enbit, volt) \ +[MT6397_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6397_volt_fixed_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6397_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = 1, \ + .enable_reg = enreg, \ + .enable_mask = BIT(enbit), \ + .min_uV = volt, \ + }, \ + .qi = BIT(15), \ +} + +static const struct regulator_linear_range buck_volt_range1[] = { + REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250), +}; + +static const struct regulator_linear_range buck_volt_range2[] = { + REGULATOR_LINEAR_RANGE(800000, 0, 0x7f, 6250), +}; + +static const struct regulator_linear_range buck_volt_range3[] = { + REGULATOR_LINEAR_RANGE(1500000, 0, 0x1f, 20000), +}; + +static const u32 ldo_volt_table1[] = { + 1500000, 1800000, 2500000, 2800000, +}; + +static const u32 ldo_volt_table2[] = { + 1800000, 3300000, +}; + +static const u32 ldo_volt_table3[] = { + 3000000, 3300000, +}; + +static const u32 ldo_volt_table4[] = { + 1220000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000, +}; + +static const u32 ldo_volt_table5[] = { + 1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000, +}; + +static const u32 ldo_volt_table5_v2[] = { + 1200000, 1000000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000, +}; + +static const u32 ldo_volt_table6[] = { + 1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 2000000, +}; + +static const u32 ldo_volt_table7[] = { + 1300000, 1500000, 1800000, 2000000, 2500000, 2800000, 3000000, 3300000, +}; + +static int mt6397_get_status(struct regulator_dev *rdev) +{ + int ret; + u32 regval; + struct mt6397_regulator_info *info = rdev_get_drvdata(rdev); + + ret = regmap_read(rdev->regmap, info->desc.enable_reg, ®val); + if (ret != 0) { + dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret); + return ret; + } + + return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF; +} + +static struct regulator_ops mt6397_volt_range_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6397_get_status, +}; + +static struct regulator_ops mt6397_volt_table_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6397_get_status, +}; + +static struct regulator_ops mt6397_volt_fixed_ops = { + .list_voltage = regulator_list_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6397_get_status, +}; + +/* The array is indexed by id(MT6397_ID_XXX) */ +static struct mt6397_regulator_info mt6397_regulators[] = { + MT6397_BUCK("buck_vpca15", VPCA15, 700000, 1493750, 6250, + buck_volt_range1, MT6397_VCA15_CON7, MT6397_VCA15_CON9, 0x7f, + MT6397_VCA15_CON10, MT6397_VCA15_CON5), + MT6397_BUCK("buck_vpca7", VPCA7, 700000, 1493750, 6250, + buck_volt_range1, MT6397_VPCA7_CON7, MT6397_VPCA7_CON9, 0x7f, + MT6397_VPCA7_CON10, MT6397_VPCA7_CON5), + MT6397_BUCK("buck_vsramca15", VSRAMCA15, 700000, 1493750, 6250, + buck_volt_range1, MT6397_VSRMCA15_CON7, MT6397_VSRMCA15_CON9, + 0x7f, MT6397_VSRMCA15_CON10, MT6397_VSRMCA15_CON5), + MT6397_BUCK("buck_vsramca7", VSRAMCA7, 700000, 1493750, 6250, + buck_volt_range1, MT6397_VSRMCA7_CON7, MT6397_VSRMCA7_CON9, + 0x7f, MT6397_VSRMCA7_CON10, MT6397_VSRMCA7_CON5), + MT6397_BUCK("buck_vcore", VCORE, 700000, 1493750, 6250, + buck_volt_range1, MT6397_VCORE_CON7, MT6397_VCORE_CON9, 0x7f, + MT6397_VCORE_CON10, MT6397_VCORE_CON5), + MT6397_BUCK("buck_vgpu", VGPU, 700000, 1493750, 6250, buck_volt_range1, + MT6397_VGPU_CON7, MT6397_VGPU_CON9, 0x7f, + MT6397_VGPU_CON10, MT6397_VGPU_CON5), + MT6397_BUCK("buck_vdrm", VDRM, 800000, 1593750, 6250, buck_volt_range2, + MT6397_VDRM_CON7, MT6397_VDRM_CON9, 0x7f, + MT6397_VDRM_CON10, MT6397_VDRM_CON5), + MT6397_BUCK("buck_vio18", VIO18, 1500000, 2120000, 20000, + buck_volt_range3, MT6397_VIO18_CON7, MT6397_VIO18_CON9, 0x1f, + MT6397_VIO18_CON10, MT6397_VIO18_CON5), + MT6397_REG_FIXED("ldo_vtcxo", VTCXO, MT6397_ANALDO_CON0, 10, 2800000), + MT6397_REG_FIXED("ldo_va28", VA28, MT6397_ANALDO_CON1, 14, 2800000), + MT6397_LDO("ldo_vcama", VCAMA, ldo_volt_table1, + MT6397_ANALDO_CON2, 15, MT6397_ANALDO_CON6, 0xC0), + MT6397_REG_FIXED("ldo_vio28", VIO28, MT6397_DIGLDO_CON0, 14, 2800000), + MT6397_REG_FIXED("ldo_vusb", VUSB, MT6397_DIGLDO_CON1, 14, 3300000), + MT6397_LDO("ldo_vmc", VMC, ldo_volt_table2, + MT6397_DIGLDO_CON2, 12, MT6397_DIGLDO_CON29, 0x10), + MT6397_LDO("ldo_vmch", VMCH, ldo_volt_table3, + MT6397_DIGLDO_CON3, 14, MT6397_DIGLDO_CON17, 0x80), + MT6397_LDO("ldo_vemc3v3", VEMC3V3, ldo_volt_table3, + MT6397_DIGLDO_CON4, 14, MT6397_DIGLDO_CON18, 0x10), + MT6397_LDO("ldo_vgp1", VGP1, ldo_volt_table4, + MT6397_DIGLDO_CON5, 15, MT6397_DIGLDO_CON19, 0xE0), + MT6397_LDO("ldo_vgp2", VGP2, ldo_volt_table5, + MT6397_DIGLDO_CON6, 15, MT6397_DIGLDO_CON20, 0xE0), + MT6397_LDO("ldo_vgp3", VGP3, ldo_volt_table5, + MT6397_DIGLDO_CON7, 15, MT6397_DIGLDO_CON21, 0xE0), + MT6397_LDO("ldo_vgp4", VGP4, ldo_volt_table5, + MT6397_DIGLDO_CON8, 15, MT6397_DIGLDO_CON22, 0xE0), + MT6397_LDO("ldo_vgp5", VGP5, ldo_volt_table6, + MT6397_DIGLDO_CON9, 15, MT6397_DIGLDO_CON23, 0xE0), + MT6397_LDO("ldo_vgp6", VGP6, ldo_volt_table5, + MT6397_DIGLDO_CON10, 15, MT6397_DIGLDO_CON33, 0xE0), + MT6397_LDO("ldo_vibr", VIBR, ldo_volt_table7, + MT6397_DIGLDO_CON24, 15, MT6397_DIGLDO_CON25, 0xE00), +}; + +static int mt6397_set_buck_vosel_reg(struct platform_device *pdev) +{ + struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); + int i; + u32 regval; + + for (i = 0; i < MT6397_MAX_REGULATOR; i++) { + if (mt6397_regulators[i].vselctrl_reg) { + if (regmap_read(mt6397->regmap, + mt6397_regulators[i].vselctrl_reg, + ®val) < 0) { + dev_err(&pdev->dev, + "Failed to read buck ctrl\n"); + return -EIO; + } + + if (regval & mt6397_regulators[i].vselctrl_mask) { + mt6397_regulators[i].desc.vsel_reg = + mt6397_regulators[i].vselon_reg; + } + } + } + + return 0; +} + +static int mt6397_regulator_probe(struct platform_device *pdev) +{ + struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = {}; + struct regulator_dev *rdev; + int i; + u32 reg_value, version; + + /* Query buck controller to select activated voltage register part */ + if (mt6397_set_buck_vosel_reg(pdev)) + return -EIO; + + /* Read PMIC chip revision to update constraints and voltage table */ + if (regmap_read(mt6397->regmap, MT6397_CID, ®_value) < 0) { + dev_err(&pdev->dev, "Failed to read Chip ID\n"); + return -EIO; + } + dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value); + + version = (reg_value & 0xFF); + switch (version) { + case MT6397_REGULATOR_ID91: + mt6397_regulators[MT6397_ID_VGP2].desc.volt_table = + ldo_volt_table5_v2; + break; + default: + break; + } + + for (i = 0; i < MT6397_MAX_REGULATOR; i++) { + config.dev = &pdev->dev; + config.driver_data = &mt6397_regulators[i]; + config.regmap = mt6397->regmap; + rdev = devm_regulator_register(&pdev->dev, + &mt6397_regulators[i].desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", + mt6397_regulators[i].desc.name); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static struct platform_driver mt6397_regulator_driver = { + .driver = { + .name = "mt6397-regulator", + }, + .probe = mt6397_regulator_probe, +}; + +module_platform_driver(mt6397_regulator_driver); + +MODULE_AUTHOR("Flora Fu "); +MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:mt6397-regulator"); diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 91eaaf010524..24e812c48d93 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -270,6 +270,7 @@ EXPORT_SYMBOL_GPL(of_regulator_match); struct regulator_init_data *regulator_of_get_init_data(struct device *dev, const struct regulator_desc *desc, + struct regulator_config *config, struct device_node **node) { struct device_node *search, *child; @@ -307,6 +308,16 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev, break; } + if (desc->of_parse_cb) { + if (desc->of_parse_cb(child, desc, config)) { + dev_err(dev, + "driver callback failed to parse DT for regulator %s\n", + child->name); + init_data = NULL; + break; + } + } + of_node_get(child); *node = child; break; diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index c879dff597ee..8cc8d1877c44 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -56,7 +56,7 @@ #define PFUZE100_VGEN5VOL 0x70 #define PFUZE100_VGEN6VOL 0x71 -enum chips { PFUZE100, PFUZE200 }; +enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3 }; struct pfuze_regulator { struct regulator_desc desc; @@ -80,9 +80,18 @@ static const int pfuze100_vsnvs[] = { 1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000, }; +static const int pfuze3000_sw2lo[] = { + 1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, +}; + +static const int pfuze3000_sw2hi[] = { + 2500000, 2800000, 2850000, 3000000, 3100000, 3150000, 3200000, 3300000, +}; + static const struct i2c_device_id pfuze_device_id[] = { {.name = "pfuze100", .driver_data = PFUZE100}, {.name = "pfuze200", .driver_data = PFUZE200}, + {.name = "pfuze3000", .driver_data = PFUZE3000}, { } }; MODULE_DEVICE_TABLE(i2c, pfuze_device_id); @@ -90,6 +99,7 @@ MODULE_DEVICE_TABLE(i2c, pfuze_device_id); static const struct of_device_id pfuze_dt_ids[] = { { .compatible = "fsl,pfuze100", .data = (void *)PFUZE100}, { .compatible = "fsl,pfuze200", .data = (void *)PFUZE200}, + { .compatible = "fsl,pfuze3000", .data = (void *)PFUZE3000}, { } }; MODULE_DEVICE_TABLE(of, pfuze_dt_ids); @@ -219,6 +229,60 @@ static struct regulator_ops pfuze100_swb_regulator_ops = { .stby_mask = 0x20, \ } +#define PFUZE3000_VCC_REG(_chip, _name, base, min, max, step) { \ + .desc = { \ + .name = #_name, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .ops = &pfuze100_ldo_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = _chip ## _ ## _name, \ + .owner = THIS_MODULE, \ + .min_uV = (min), \ + .uV_step = (step), \ + .vsel_reg = (base), \ + .vsel_mask = 0x3, \ + .enable_reg = (base), \ + .enable_mask = 0x10, \ + }, \ + .stby_reg = (base), \ + .stby_mask = 0x20, \ +} + + +#define PFUZE3000_SW2_REG(_chip, _name, base, min, max, step) { \ + .desc = { \ + .name = #_name,\ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .ops = &pfuze100_sw_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = _chip ## _ ## _name, \ + .owner = THIS_MODULE, \ + .min_uV = (min), \ + .uV_step = (step), \ + .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ + .vsel_mask = 0x7, \ + }, \ + .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ + .stby_mask = 0x7, \ +} + +#define PFUZE3000_SW3_REG(_chip, _name, base, min, max, step) { \ + .desc = { \ + .name = #_name,\ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .ops = &pfuze100_sw_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = _chip ## _ ## _name, \ + .owner = THIS_MODULE, \ + .min_uV = (min), \ + .uV_step = (step), \ + .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ + .vsel_mask = 0xf, \ + }, \ + .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ + .stby_mask = 0xf, \ +} + /* PFUZE100 */ static struct pfuze_regulator pfuze100_regulators[] = { PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), @@ -254,6 +318,22 @@ static struct pfuze_regulator pfuze200_regulators[] = { PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), }; +static struct pfuze_regulator pfuze3000_regulators[] = { + PFUZE100_SW_REG(PFUZE3000, SW1A, PFUZE100_SW1ABVOL, 700000, 1475000, 25000), + PFUZE100_SW_REG(PFUZE3000, SW1B, PFUZE100_SW1CVOL, 700000, 1475000, 25000), + PFUZE100_SWB_REG(PFUZE3000, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo), + PFUZE3000_SW3_REG(PFUZE3000, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000), + PFUZE100_SWB_REG(PFUZE3000, SWBST, PFUZE100_SWBSTCON1, 0x3, pfuze100_swbst), + PFUZE100_SWB_REG(PFUZE3000, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), + PFUZE100_FIXED_REG(PFUZE3000, VREFDDR, PFUZE100_VREFDDRCON, 750000), + PFUZE100_VGEN_REG(PFUZE3000, VLDO1, PFUZE100_VGEN1VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE3000, VLDO2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), + PFUZE3000_VCC_REG(PFUZE3000, VCCSD, PFUZE100_VGEN3VOL, 2850000, 3300000, 150000), + PFUZE3000_VCC_REG(PFUZE3000, V33, PFUZE100_VGEN4VOL, 2850000, 3300000, 150000), + PFUZE100_VGEN_REG(PFUZE3000, VLDO3, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE3000, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), +}; + static struct pfuze_regulator *pfuze_regulators; #ifdef CONFIG_OF @@ -294,6 +374,24 @@ static struct of_regulator_match pfuze200_matches[] = { { .name = "vgen6", }, }; +/* PFUZE3000 */ +static struct of_regulator_match pfuze3000_matches[] = { + + { .name = "sw1a", }, + { .name = "sw1b", }, + { .name = "sw2", }, + { .name = "sw3", }, + { .name = "swbst", }, + { .name = "vsnvs", }, + { .name = "vrefddr", }, + { .name = "vldo1", }, + { .name = "vldo2", }, + { .name = "vccsd", }, + { .name = "v33", }, + { .name = "vldo3", }, + { .name = "vldo4", }, +}; + static struct of_regulator_match *pfuze_matches; static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) @@ -313,6 +411,11 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) } switch (chip->chip_id) { + case PFUZE3000: + pfuze_matches = pfuze3000_matches; + ret = of_regulator_match(dev, parent, pfuze3000_matches, + ARRAY_SIZE(pfuze3000_matches)); + break; case PFUZE200: pfuze_matches = pfuze200_matches; ret = of_regulator_match(dev, parent, pfuze200_matches, @@ -378,7 +481,8 @@ static int pfuze_identify(struct pfuze_chip *pfuze_chip) * as ID=8 in PFUZE100 */ dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8"); - } else if ((value & 0x0f) != pfuze_chip->chip_id) { + } else if ((value & 0x0f) != pfuze_chip->chip_id && + (value & 0xf0) >> 4 != pfuze_chip->chip_id) { /* device id NOT match with your setting */ dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value); return -ENODEV; @@ -417,7 +521,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client, int i, ret; const struct of_device_id *match; u32 regulator_num; - u32 sw_check_start, sw_check_end; + u32 sw_check_start, sw_check_end, sw_hi = 0x40; pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip), GFP_KERNEL); @@ -458,13 +562,19 @@ static int pfuze100_regulator_probe(struct i2c_client *client, /* use the right regulators after identify the right device */ switch (pfuze_chip->chip_id) { + case PFUZE3000: + pfuze_regulators = pfuze3000_regulators; + regulator_num = ARRAY_SIZE(pfuze3000_regulators); + sw_check_start = PFUZE3000_SW2; + sw_check_end = PFUZE3000_SW2; + sw_hi = 1 << 3; + break; case PFUZE200: pfuze_regulators = pfuze200_regulators; regulator_num = ARRAY_SIZE(pfuze200_regulators); sw_check_start = PFUZE200_SW2; sw_check_end = PFUZE200_SW3B; break; - case PFUZE100: default: pfuze_regulators = pfuze100_regulators; @@ -474,7 +584,8 @@ static int pfuze100_regulator_probe(struct i2c_client *client, break; } dev_info(&client->dev, "pfuze%s found.\n", - (pfuze_chip->chip_id == PFUZE100) ? "100" : "200"); + (pfuze_chip->chip_id == PFUZE100) ? "100" : + ((pfuze_chip->chip_id == PFUZE200) ? "200" : "3000")); memcpy(pfuze_chip->regulator_descs, pfuze_regulators, sizeof(pfuze_chip->regulator_descs)); @@ -498,10 +609,15 @@ static int pfuze100_regulator_probe(struct i2c_client *client, /* SW2~SW4 high bit check and modify the voltage value table */ if (i >= sw_check_start && i <= sw_check_end) { regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val); - if (val & 0x40) { - desc->min_uV = 800000; - desc->uV_step = 50000; - desc->n_voltages = 51; + if (val & sw_hi) { + if (pfuze_chip->chip_id == PFUZE3000) { + desc->volt_table = pfuze3000_sw2hi; + desc->n_voltages = ARRAY_SIZE(pfuze3000_sw2hi); + } else { + desc->min_uV = 800000; + desc->uV_step = 50000; + desc->n_voltages = 51; + } } } diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c index 8364ff331a81..e8647f7cf25e 100644 --- a/drivers/regulator/qcom_rpm-regulator.c +++ b/drivers/regulator/qcom_rpm-regulator.c @@ -227,9 +227,11 @@ static int rpm_reg_set_mV_sel(struct regulator_dev *rdev, return uV; mutex_lock(&vreg->lock); - vreg->uV = uV; if (vreg->is_enabled) - ret = rpm_reg_write(vreg, req, vreg->uV / 1000); + ret = rpm_reg_write(vreg, req, uV / 1000); + + if (!ret) + vreg->uV = uV; mutex_unlock(&vreg->lock); return ret; @@ -252,9 +254,11 @@ static int rpm_reg_set_uV_sel(struct regulator_dev *rdev, return uV; mutex_lock(&vreg->lock); - vreg->uV = uV; if (vreg->is_enabled) - ret = rpm_reg_write(vreg, req, vreg->uV); + ret = rpm_reg_write(vreg, req, uV); + + if (!ret) + vreg->uV = uV; mutex_unlock(&vreg->lock); return ret; @@ -674,6 +678,7 @@ static int rpm_reg_probe(struct platform_device *pdev) vreg->desc.owner = THIS_MODULE; vreg->desc.type = REGULATOR_VOLTAGE; vreg->desc.name = pdev->dev.of_node->name; + vreg->desc.supply_name = "vin"; vreg->rpm = dev_get_drvdata(pdev->dev.parent); if (!vreg->rpm) { @@ -768,7 +773,7 @@ static int rpm_reg_probe(struct platform_device *pdev) break; } - if (force_mode < 0) { + if (force_mode == -1) { dev_err(&pdev->dev, "invalid force mode\n"); return -EINVAL; } diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index c94a3e0f3b91..1f93b752a81c 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -97,7 +97,7 @@ static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) RK808_RAMP_RATE_MASK, ramp_value); } -int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv) +static int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv) { unsigned int reg; int sel = regulator_map_voltage_linear_range(rdev, uv, uv); @@ -112,7 +112,7 @@ int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv) sel); } -int rk808_set_suspend_enable(struct regulator_dev *rdev) +static int rk808_set_suspend_enable(struct regulator_dev *rdev) { unsigned int reg; @@ -123,7 +123,7 @@ int rk808_set_suspend_enable(struct regulator_dev *rdev) 0); } -int rk808_set_suspend_disable(struct regulator_dev *rdev) +static int rk808_set_suspend_disable(struct regulator_dev *rdev) { unsigned int reg; diff --git a/drivers/regulator/rt5033-regulator.c b/drivers/regulator/rt5033-regulator.c index 870cc49438db..96d2c18e051a 100644 --- a/drivers/regulator/rt5033-regulator.c +++ b/drivers/regulator/rt5033-regulator.c @@ -36,6 +36,8 @@ static struct regulator_ops rt5033_buck_ops = { static const struct regulator_desc rt5033_supported_regulators[] = { [RT5033_BUCK] = { .name = "BUCK", + .of_match = of_match_ptr("BUCK"), + .regulators_node = of_match_ptr("regulators"), .id = RT5033_BUCK, .ops = &rt5033_buck_ops, .type = REGULATOR_VOLTAGE, @@ -50,6 +52,8 @@ static const struct regulator_desc rt5033_supported_regulators[] = { }, [RT5033_LDO] = { .name = "LDO", + .of_match = of_match_ptr("LDO"), + .regulators_node = of_match_ptr("regulators"), .id = RT5033_LDO, .ops = &rt5033_buck_ops, .type = REGULATOR_VOLTAGE, @@ -64,6 +68,8 @@ static const struct regulator_desc rt5033_supported_regulators[] = { }, [RT5033_SAFE_LDO] = { .name = "SAFE_LDO", + .of_match = of_match_ptr("SAFE_LDO"), + .regulators_node = of_match_ptr("regulators"), .id = RT5033_SAFE_LDO, .ops = &rt5033_safe_ldo_ops, .type = REGULATOR_VOLTAGE, @@ -81,7 +87,7 @@ static int rt5033_regulator_probe(struct platform_device *pdev) int ret, i; struct regulator_config config = {}; - config.dev = &pdev->dev; + config.dev = rt5033->dev; config.driver_data = rt5033; for (i = 0; i < ARRAY_SIZE(rt5033_supported_regulators); i++) { diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 2809ae0d6bcd..ff828117798f 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -405,6 +405,40 @@ static struct regulator_ops s2mps14_reg_ops; .enable_mask = S2MPS14_ENABLE_MASK \ } +#define regulator_desc_s2mps13_buck7(num, min, step, min_sel) { \ + .name = "BUCK"#num, \ + .id = S2MPS13_BUCK##num, \ + .ops = &s2mps14_reg_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = min, \ + .uV_step = step, \ + .linear_min_sel = min_sel, \ + .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \ + .ramp_delay = S2MPS13_BUCK_RAMP_DELAY, \ + .vsel_reg = S2MPS13_REG_B1OUT + (num) * 2 - 1, \ + .vsel_mask = S2MPS14_BUCK_VSEL_MASK, \ + .enable_reg = S2MPS13_REG_B1CTRL + (num - 1) * 2, \ + .enable_mask = S2MPS14_ENABLE_MASK \ +} + +#define regulator_desc_s2mps13_buck8_10(num, min, step, min_sel) { \ + .name = "BUCK"#num, \ + .id = S2MPS13_BUCK##num, \ + .ops = &s2mps14_reg_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = min, \ + .uV_step = step, \ + .linear_min_sel = min_sel, \ + .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \ + .ramp_delay = S2MPS13_BUCK_RAMP_DELAY, \ + .vsel_reg = S2MPS13_REG_B1OUT + (num) * 2 - 1, \ + .vsel_mask = S2MPS14_BUCK_VSEL_MASK, \ + .enable_reg = S2MPS13_REG_B1CTRL + (num) * 2 - 1, \ + .enable_mask = S2MPS14_ENABLE_MASK \ +} + static const struct regulator_desc s2mps13_regulators[] = { regulator_desc_s2mps13_ldo(1, MIN_800_MV, STEP_12_5_MV, 0x00), regulator_desc_s2mps13_ldo(2, MIN_1400_MV, STEP_50_MV, 0x0C), @@ -452,10 +486,10 @@ static const struct regulator_desc s2mps13_regulators[] = { regulator_desc_s2mps13_buck(4, MIN_500_MV, STEP_6_25_MV, 0x10), regulator_desc_s2mps13_buck(5, MIN_500_MV, STEP_6_25_MV, 0x10), regulator_desc_s2mps13_buck(6, MIN_500_MV, STEP_6_25_MV, 0x10), - regulator_desc_s2mps13_buck(7, MIN_500_MV, STEP_6_25_MV, 0x10), - regulator_desc_s2mps13_buck(8, MIN_1000_MV, STEP_12_5_MV, 0x20), - regulator_desc_s2mps13_buck(9, MIN_1000_MV, STEP_12_5_MV, 0x20), - regulator_desc_s2mps13_buck(10, MIN_500_MV, STEP_6_25_MV, 0x10), + regulator_desc_s2mps13_buck7(7, MIN_500_MV, STEP_6_25_MV, 0x10), + regulator_desc_s2mps13_buck8_10(8, MIN_1000_MV, STEP_12_5_MV, 0x20), + regulator_desc_s2mps13_buck8_10(9, MIN_1000_MV, STEP_12_5_MV, 0x20), + regulator_desc_s2mps13_buck8_10(10, MIN_500_MV, STEP_6_25_MV, 0x10), }; static int s2mps14_regulator_enable(struct regulator_dev *rdev) diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 7380af8bd50d..b941e564b3f3 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -173,7 +173,7 @@ static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev, } /* Operations permitted on VDCDCx */ -static struct regulator_ops tps65023_dcdc_ops = { +static const struct regulator_ops tps65023_dcdc_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -184,7 +184,7 @@ static struct regulator_ops tps65023_dcdc_ops = { }; /* Operations permitted on LDOx */ -static struct regulator_ops tps65023_ldo_ops = { +static const struct regulator_ops tps65023_ldo_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -194,7 +194,7 @@ static struct regulator_ops tps65023_ldo_ops = { .map_voltage = regulator_map_voltage_ascend, }; -static struct regmap_config tps65023_regmap_config = { +static const struct regmap_config tps65023_regmap_config = { .reg_bits = 8, .val_bits = 8, }; diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c index 4aa60d74004e..6c719f23520a 100644 --- a/drivers/rtc/hctosys.c +++ b/drivers/rtc/hctosys.c @@ -26,7 +26,7 @@ static int __init rtc_hctosys(void) { int err = -ENODEV; struct rtc_time tm; - struct timespec tv = { + struct timespec64 tv64 = { .tv_nsec = NSEC_PER_SEC >> 1, }; struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); @@ -45,25 +45,17 @@ static int __init rtc_hctosys(void) } - err = rtc_valid_tm(&tm); - if (err) { - dev_err(rtc->dev.parent, - "hctosys: invalid date/time\n"); - goto err_invalid; - } + tv64.tv_sec = rtc_tm_to_time64(&tm); - rtc_tm_to_time(&tm, &tv.tv_sec); - - err = do_settimeofday(&tv); + err = do_settimeofday64(&tv64); dev_info(rtc->dev.parent, "setting system clock to " - "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + "%d-%02d-%02d %02d:%02d:%02d UTC (%lld)\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, - (unsigned int) tv.tv_sec); + (long long) tv64.tv_sec); -err_invalid: err_read: rtc_class_close(rtc); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 45bfc28ee3aa..37215cf983e9 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -73,10 +73,8 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) else if (rtc->ops->set_time) err = rtc->ops->set_time(rtc->dev.parent, tm); else if (rtc->ops->set_mmss) { - unsigned long secs; - err = rtc_tm_to_time(tm, &secs); - if (err == 0) - err = rtc->ops->set_mmss(rtc->dev.parent, secs); + time64_t secs64 = rtc_tm_to_time64(tm); + err = rtc->ops->set_mmss(rtc->dev.parent, secs64); } else err = -EINVAL; @@ -105,7 +103,7 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) err = rtc->ops->read_time(rtc->dev.parent, &old); if (err == 0) { - rtc_time_to_tm(secs, &new); + rtc_time64_to_tm(secs, &new); /* * avoid writing when we're going to change the day of @@ -157,7 +155,7 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) int err; struct rtc_time before, now; int first_time = 1; - unsigned long t_now, t_alm; + time64_t t_now, t_alm; enum { none, day, month, year } missing = none; unsigned days; @@ -258,8 +256,8 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) } /* with luck, no rollover is needed */ - rtc_tm_to_time(&now, &t_now); - rtc_tm_to_time(&alarm->time, &t_alm); + t_now = rtc_tm_to_time64(&now); + t_alm = rtc_tm_to_time64(&alarm->time); if (t_now < t_alm) goto done; @@ -273,7 +271,7 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) case day: dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day"); t_alm += 24 * 60 * 60; - rtc_time_to_tm(t_alm, &alarm->time); + rtc_time64_to_tm(t_alm, &alarm->time); break; /* Month rollover ... if it's the 31th, an alarm on the 3rd will @@ -346,19 +344,19 @@ EXPORT_SYMBOL_GPL(rtc_read_alarm); static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { struct rtc_time tm; - long now, scheduled; + time64_t now, scheduled; int err; err = rtc_valid_tm(&alarm->time); if (err) return err; - rtc_tm_to_time(&alarm->time, &scheduled); + scheduled = rtc_tm_to_time64(&alarm->time); /* Make sure we're not setting alarms in the past */ err = __rtc_read_time(rtc, &tm); if (err) return err; - rtc_tm_to_time(&tm, &now); + now = rtc_tm_to_time64(&tm); if (scheduled <= now) return -ETIME; /* diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index d04939369251..799c34bcb26f 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -304,12 +304,12 @@ static long rtc_dev_ioctl(struct file *file, * Not supported here. */ { - unsigned long now, then; + time64_t now, then; err = rtc_read_time(rtc, &tm); if (err < 0) return err; - rtc_tm_to_time(&tm, &now); + now = rtc_tm_to_time64(&tm); alarm.time.tm_mday = tm.tm_mday; alarm.time.tm_mon = tm.tm_mon; @@ -317,11 +317,11 @@ static long rtc_dev_ioctl(struct file *file, err = rtc_valid_tm(&alarm.time); if (err < 0) return err; - rtc_tm_to_time(&alarm.time, &then); + then = rtc_tm_to_time64(&alarm.time); /* alarm may need to wrap into tomorrow */ if (then < now) { - rtc_time_to_tm(now + 24 * 60 * 60, &tm); + rtc_time64_to_tm(now + 24 * 60 * 60, &tm); alarm.time.tm_mday = tm.tm_mday; alarm.time.tm_mon = tm.tm_mon; alarm.time.tm_year = tm.tm_year; diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index b37b0c80bd5a..cb989cd00b14 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -218,6 +218,7 @@ static int __init efi_rtc_probe(struct platform_device *dev) if (IS_ERR(rtc)) return PTR_ERR(rtc); + rtc->uie_unsupported = 1; platform_set_drvdata(dev, rtc); return 0; diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index b5e7c4670205..89ac1d5083c6 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -832,6 +832,7 @@ static SIMPLE_DEV_PM_OPS(s5m_rtc_pm_ops, s5m_rtc_suspend, s5m_rtc_resume); static const struct platform_device_id s5m_rtc_id[] = { { "s5m-rtc", S5M8767X }, { "s2mps14-rtc", S2MPS14X }, + { }, }; static struct platform_driver s5m_rtc_driver = { diff --git a/drivers/rtc/systohc.c b/drivers/rtc/systohc.c index bf3e242ccc5c..eb71872d0361 100644 --- a/drivers/rtc/systohc.c +++ b/drivers/rtc/systohc.c @@ -20,16 +20,16 @@ * * If temporary failure is indicated the caller should try again 'soon' */ -int rtc_set_ntp_time(struct timespec now) +int rtc_set_ntp_time(struct timespec64 now) { struct rtc_device *rtc; struct rtc_time tm; int err = -ENODEV; if (now.tv_nsec < (NSEC_PER_SEC >> 1)) - rtc_time_to_tm(now.tv_sec, &tm); + rtc_time64_to_tm(now.tv_sec, &tm); else - rtc_time_to_tm(now.tv_sec + 1, &tm); + rtc_time64_to_tm(now.tv_sec + 1, &tm); rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); if (rtc) { diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4abf11965484..be34ef41b7c7 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -674,8 +674,9 @@ EXPORT_SYMBOL(dasd_enable_device); unsigned int dasd_global_profile_level = DASD_PROFILE_OFF; #ifdef CONFIG_DASD_PROFILE -struct dasd_profile_info dasd_global_profile_data; -static struct dentry *dasd_global_profile_dentry; +struct dasd_profile dasd_global_profile = { + .lock = __SPIN_LOCK_UNLOCKED(dasd_global_profile.lock), +}; static struct dentry *dasd_debugfs_global_entry; /* @@ -696,11 +697,13 @@ static void dasd_profile_start(struct dasd_block *block, if (++counter >= 31) break; - if (dasd_global_profile_level) { - dasd_global_profile_data.dasd_io_nr_req[counter]++; + spin_lock(&dasd_global_profile.lock); + if (dasd_global_profile.data) { + dasd_global_profile.data->dasd_io_nr_req[counter]++; if (rq_data_dir(req) == READ) - dasd_global_profile_data.dasd_read_nr_req[counter]++; + dasd_global_profile.data->dasd_read_nr_req[counter]++; } + spin_unlock(&dasd_global_profile.lock); spin_lock(&block->profile.lock); if (block->profile.data) { @@ -825,8 +828,9 @@ static void dasd_profile_end(struct dasd_block *block, dasd_profile_counter(irqtime / sectors, irqtimeps_ind); dasd_profile_counter(endtime, endtime_ind); - if (dasd_global_profile_level) { - dasd_profile_end_add_data(&dasd_global_profile_data, + spin_lock(&dasd_global_profile.lock); + if (dasd_global_profile.data) { + dasd_profile_end_add_data(dasd_global_profile.data, cqr->startdev != block->base, cqr->cpmode == 1, rq_data_dir(req) == READ, @@ -835,6 +839,7 @@ static void dasd_profile_end(struct dasd_block *block, irqtime_ind, irqtimeps_ind, endtime_ind); } + spin_unlock(&dasd_global_profile.lock); spin_lock(&block->profile.lock); if (block->profile.data) @@ -876,12 +881,6 @@ void dasd_profile_reset(struct dasd_profile *profile) spin_unlock_bh(&profile->lock); } -void dasd_global_profile_reset(void) -{ - memset(&dasd_global_profile_data, 0, sizeof(dasd_global_profile_data)); - getnstimeofday(&dasd_global_profile_data.starttod); -} - int dasd_profile_on(struct dasd_profile *profile) { struct dasd_profile_info *data; @@ -949,12 +948,20 @@ static ssize_t dasd_stats_write(struct file *file, dasd_profile_reset(prof); } else if (strncmp(str, "on", 2) == 0) { rc = dasd_profile_on(prof); - if (!rc) - rc = user_len; + if (rc) + goto out; + rc = user_len; + if (prof == &dasd_global_profile) { + dasd_profile_reset(prof); + dasd_global_profile_level = DASD_PROFILE_GLOBAL_ONLY; + } } else if (strncmp(str, "off", 3) == 0) { + if (prof == &dasd_global_profile) + dasd_global_profile_level = DASD_PROFILE_OFF; dasd_profile_off(prof); } else rc = -EINVAL; +out: vfree(buffer); return rc; } @@ -1044,57 +1051,6 @@ static const struct file_operations dasd_stats_raw_fops = { .write = dasd_stats_write, }; -static ssize_t dasd_stats_global_write(struct file *file, - const char __user *user_buf, - size_t user_len, loff_t *pos) -{ - char *buffer, *str; - ssize_t rc; - - if (user_len > 65536) - user_len = 65536; - buffer = dasd_get_user_string(user_buf, user_len); - if (IS_ERR(buffer)) - return PTR_ERR(buffer); - str = skip_spaces(buffer); - rc = user_len; - if (strncmp(str, "reset", 5) == 0) { - dasd_global_profile_reset(); - } else if (strncmp(str, "on", 2) == 0) { - dasd_global_profile_reset(); - dasd_global_profile_level = DASD_PROFILE_GLOBAL_ONLY; - } else if (strncmp(str, "off", 3) == 0) { - dasd_global_profile_level = DASD_PROFILE_OFF; - } else - rc = -EINVAL; - vfree(buffer); - return rc; -} - -static int dasd_stats_global_show(struct seq_file *m, void *v) -{ - if (!dasd_global_profile_level) { - seq_puts(m, "disabled\n"); - return 0; - } - dasd_stats_seq_print(m, &dasd_global_profile_data); - return 0; -} - -static int dasd_stats_global_open(struct inode *inode, struct file *file) -{ - return single_open(file, dasd_stats_global_show, NULL); -} - -static const struct file_operations dasd_stats_global_fops = { - .owner = THIS_MODULE, - .open = dasd_stats_global_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = dasd_stats_global_write, -}; - static void dasd_profile_init(struct dasd_profile *profile, struct dentry *base_dentry) { @@ -1123,20 +1079,16 @@ static void dasd_profile_exit(struct dasd_profile *profile) static void dasd_statistics_removeroot(void) { dasd_global_profile_level = DASD_PROFILE_OFF; - debugfs_remove(dasd_global_profile_dentry); - dasd_global_profile_dentry = NULL; + dasd_profile_exit(&dasd_global_profile); debugfs_remove(dasd_debugfs_global_entry); debugfs_remove(dasd_debugfs_root_entry); } static void dasd_statistics_createroot(void) { - umode_t mode; struct dentry *pde; dasd_debugfs_root_entry = NULL; - dasd_debugfs_global_entry = NULL; - dasd_global_profile_dentry = NULL; pde = debugfs_create_dir("dasd", NULL); if (!pde || IS_ERR(pde)) goto error; @@ -1145,13 +1097,7 @@ static void dasd_statistics_createroot(void) if (!pde || IS_ERR(pde)) goto error; dasd_debugfs_global_entry = pde; - - mode = (S_IRUSR | S_IWUSR | S_IFREG); - pde = debugfs_create_file("statistics", mode, dasd_debugfs_global_entry, - NULL, &dasd_stats_global_fops); - if (!pde || IS_ERR(pde)) - goto error; - dasd_global_profile_dentry = pde; + dasd_profile_init(&dasd_global_profile, dasd_debugfs_global_entry); return; error: diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 8b5d4100abf7..227e3dea3155 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -651,7 +651,7 @@ dasd_check_blocksize(int bsize) #define DASD_PROFILE_GLOBAL_ONLY 2 extern debug_info_t *dasd_debug_area; -extern struct dasd_profile_info dasd_global_profile_data; +extern struct dasd_profile dasd_global_profile; extern unsigned int dasd_global_profile_level; extern const struct block_device_operations dasd_device_operations; @@ -728,7 +728,6 @@ int dasd_device_is_ro(struct dasd_device *); void dasd_profile_reset(struct dasd_profile *); int dasd_profile_on(struct dasd_profile *); void dasd_profile_off(struct dasd_profile *); -void dasd_global_profile_reset(void); char *dasd_get_user_string(const char __user *, size_t); /* externals in dasd_devmap.c */ diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 78ac905a5b7f..aa7bb2d1da81 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -212,14 +212,15 @@ static int dasd_stats_proc_show(struct seq_file *m, void *v) struct dasd_profile_info *prof; int factor; - /* check for active profiling */ - if (!dasd_global_profile_level) { + spin_lock_bh(&dasd_global_profile.lock); + prof = dasd_global_profile.data; + if (!prof) { + spin_unlock_bh(&dasd_global_profile.lock); seq_printf(m, "Statistics are off - they might be " "switched on using 'echo set on > " "/proc/dasd/statistics'\n"); return 0; } - prof = &dasd_global_profile_data; /* prevent counter 'overflow' on output */ for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999; @@ -255,6 +256,7 @@ static int dasd_stats_proc_show(struct seq_file *m, void *v) dasd_statistics_array(m, prof->dasd_io_time3, factor); seq_printf(m, "# of req in chanq at enqueuing (1..32) \n"); dasd_statistics_array(m, prof->dasd_io_nr_req, factor); + spin_unlock_bh(&dasd_global_profile.lock); #else seq_printf(m, "Statistics are not activated in this kernel\n"); #endif @@ -291,14 +293,19 @@ static ssize_t dasd_stats_proc_write(struct file *file, dasd_stats_all_block_off(); goto out_error; } - dasd_global_profile_reset(); + rc = dasd_profile_on(&dasd_global_profile); + if (rc) { + dasd_stats_all_block_off(); + goto out_error; + } + dasd_profile_reset(&dasd_global_profile); dasd_global_profile_level = DASD_PROFILE_ON; pr_info("The statistics feature has been switched " "on\n"); } else if (strcmp(str, "off") == 0) { - /* switch off and reset statistics profiling */ + /* switch off statistics profiling */ dasd_global_profile_level = DASD_PROFILE_OFF; - dasd_global_profile_reset(); + dasd_profile_off(&dasd_global_profile); dasd_stats_all_block_off(); pr_info("The statistics feature has been switched " "off\n"); @@ -306,7 +313,7 @@ static ssize_t dasd_stats_proc_write(struct file *file, goto out_parse_error; } else if (strncmp(str, "reset", 5) == 0) { /* reset the statistics */ - dasd_global_profile_reset(); + dasd_profile_reset(&dasd_global_profile); dasd_stats_all_block_reset(); pr_info("The statistics have been reset\n"); } else diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index b550c8c8d010..7f900229404d 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -438,7 +438,13 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char pr_info("All DCSSs that map to device %s are " "saved\n", dev_info->segment_name); list_for_each_entry(entry, &dev_info->seg_list, lh) { - segment_save(entry->segment_name); + if (entry->segment_type == SEG_TYPE_EN || + entry->segment_type == SEG_TYPE_SN) + pr_warn("DCSS %s is of type SN or EN" + " and cannot be saved\n", + entry->segment_name); + else + segment_save(entry->segment_name); } } else { // device is busy => we save it when it becomes @@ -797,7 +803,12 @@ dcssblk_release(struct gendisk *disk, fmode_t mode) pr_info("Device %s has become idle and is being saved " "now\n", dev_info->segment_name); list_for_each_entry(entry, &dev_info->seg_list, lh) { - segment_save(entry->segment_name); + if (entry->segment_type == SEG_TYPE_EN || + entry->segment_type == SEG_TYPE_SN) + pr_warn("DCSS %s is of type SN or EN and cannot" + " be saved\n", entry->segment_name); + else + segment_save(entry->segment_name); } dev_info->save_pending = 0; } diff --git a/drivers/s390/char/hmcdrv_ftp.c b/drivers/s390/char/hmcdrv_ftp.c index 4bd63322fc29..d4b61d9088fb 100644 --- a/drivers/s390/char/hmcdrv_ftp.c +++ b/drivers/s390/char/hmcdrv_ftp.c @@ -200,10 +200,9 @@ int hmcdrv_ftp_probe(void) rc = hmcdrv_ftp_startup(); if (rc) - return rc; + goto out; rc = hmcdrv_ftp_do(&ftp); - free_page((unsigned long) ftp.buf); hmcdrv_ftp_shutdown(); switch (rc) { @@ -216,7 +215,8 @@ int hmcdrv_ftp_probe(void) rc = 0; /* clear length (success) */ break; } /* switch */ - +out: + free_page((unsigned long) ftp.buf); return rc; } EXPORT_SYMBOL(hmcdrv_ftp_probe); diff --git a/drivers/s390/char/hmcdrv_mod.c b/drivers/s390/char/hmcdrv_mod.c index 505c6a78ee1a..251a318a9b75 100644 --- a/drivers/s390/char/hmcdrv_mod.c +++ b/drivers/s390/char/hmcdrv_mod.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include "hmcdrv_ftp.h" diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index 5bd6cb145a87..daf6cd5079ec 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -20,26 +20,31 @@ struct read_info_sccb { struct sccb_header header; /* 0-7 */ u16 rnmax; /* 8-9 */ u8 rnsize; /* 10 */ - u8 _reserved0[16 - 11]; /* 11-15 */ + u8 _pad_11[16 - 11]; /* 11-15 */ u16 ncpurl; /* 16-17 */ u16 cpuoff; /* 18-19 */ - u8 _reserved7[24 - 20]; /* 20-23 */ + u8 _pad_20[24 - 20]; /* 20-23 */ u8 loadparm[8]; /* 24-31 */ - u8 _reserved1[48 - 32]; /* 32-47 */ + u8 _pad_32[42 - 32]; /* 32-41 */ + u8 fac42; /* 42 */ + u8 fac43; /* 43 */ + u8 _pad_44[48 - 44]; /* 44-47 */ u64 facilities; /* 48-55 */ - u8 _reserved2a[76 - 56]; /* 56-75 */ + u8 _pad_56[66 - 56]; /* 56-65 */ + u8 fac66; /* 66 */ + u8 _pad_67[76 - 67]; /* 67-83 */ u32 ibc; /* 76-79 */ - u8 _reserved2b[84 - 80]; /* 80-83 */ + u8 _pad80[84 - 80]; /* 80-83 */ u8 fac84; /* 84 */ u8 fac85; /* 85 */ - u8 _reserved3[91 - 86]; /* 86-90 */ + u8 _pad_86[91 - 86]; /* 86-90 */ u8 flags; /* 91 */ - u8 _reserved4[100 - 92]; /* 92-99 */ + u8 _pad_92[100 - 92]; /* 92-99 */ u32 rnsize2; /* 100-103 */ u64 rnmax2; /* 104-111 */ - u8 _reserved5[120 - 112]; /* 112-119 */ + u8 _pad_112[120 - 112]; /* 112-119 */ u16 hcpua; /* 120-121 */ - u8 _reserved6[4096 - 122]; /* 122-4095 */ + u8 _pad_122[4096 - 122]; /* 122-4095 */ } __packed __aligned(PAGE_SIZE); static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata; @@ -50,6 +55,10 @@ static unsigned int sclp_max_cpu; static struct sclp_ipl_info sclp_ipl_info; static unsigned char sclp_siif; static u32 sclp_ibc; +static unsigned int sclp_mtid; +static unsigned int sclp_mtid_cp; +static unsigned int sclp_mtid_max; +static unsigned int sclp_mtid_prev; u64 sclp_facilities; u8 sclp_fac84; @@ -128,7 +137,7 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb) boot_cpu_address = stap(); cpue = (void *)sccb + sccb->cpuoff; for (cpu = 0; cpu < sccb->ncpurl; cpue++, cpu++) { - if (boot_cpu_address != cpue->address) + if (boot_cpu_address != cpue->core_id) continue; sclp_siif = cpue->siif; break; @@ -139,6 +148,11 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb) if (sccb->flags & 0x2) sclp_ipl_info.has_dump = 1; memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN); + + sclp_mtid = (sccb->fac42 & 0x80) ? (sccb->fac42 & 31) : 0; + sclp_mtid_cp = (sccb->fac42 & 0x80) ? (sccb->fac43 & 31) : 0; + sclp_mtid_max = max(sclp_mtid, sclp_mtid_cp); + sclp_mtid_prev = (sccb->fac42 & 0x80) ? (sccb->fac66 & 31) : 0; } bool __init sclp_has_linemode(void) @@ -178,6 +192,21 @@ unsigned int sclp_get_ibc(void) } EXPORT_SYMBOL(sclp_get_ibc); +unsigned int sclp_get_mtid(u8 cpu_type) +{ + return cpu_type ? sclp_mtid : sclp_mtid_cp; +} + +unsigned int sclp_get_mtid_max(void) +{ + return sclp_mtid_max; +} + +unsigned int sclp_get_mtid_prev(void) +{ + return sclp_mtid_prev; +} + /* * This function will be called after sclp_facilities_detect(), which gets * called from early.c code. The sclp_facilities_detect() function retrieves diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 9aa79702b370..de69f0ddc321 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -773,13 +773,11 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, "occurred\n"); return tape_34xx_erp_failed(request, -EIO); case 0x57: - if (device->cdev->id.driver_info == tape_3480) { - /* Attention intercept. */ - return tape_34xx_erp_retry(request); - } else { - /* Global status intercept. */ - return tape_34xx_erp_retry(request); - } + /* + * 3480: Attention intercept. + * 3490: Global status intercept. + */ + return tape_34xx_erp_retry(request); case 0x5a: /* * Tape length incompatible. The tape inserted is too long, diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 10eb738fc81a..3578105989a0 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -938,7 +938,7 @@ void reipl_ccw_dev(struct ccw_dev_id *devid) { struct subchannel_id uninitialized_var(schid); - s390_reset_system(NULL, NULL); + s390_reset_system(NULL, NULL, NULL); if (reipl_find_schid(devid, &schid) != 0) panic("IPL Device not found\n"); do_reipl_asm(*((__u32*)&schid)); diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c index 5a999084a229..b3e06a7b9480 100644 --- a/drivers/s390/cio/idset.c +++ b/drivers/s390/cio/idset.c @@ -38,11 +38,6 @@ void idset_free(struct idset *set) vfree(set); } -void idset_clear(struct idset *set) -{ - memset(set->bitmap, 0, bitmap_size(set->num_ssid, set->num_id)); -} - void idset_fill(struct idset *set) { memset(set->bitmap, 0xff, bitmap_size(set->num_ssid, set->num_id)); @@ -103,21 +98,6 @@ int idset_sch_contains(struct idset *set, struct subchannel_id schid) return idset_contains(set, schid.ssid, schid.sch_no); } -int idset_sch_get_first(struct idset *set, struct subchannel_id *schid) -{ - int ssid = 0; - int id = 0; - int rc; - - rc = idset_get_first(set, &ssid, &id); - if (rc) { - init_subchannel_id(schid); - schid->ssid = ssid; - schid->sch_no = id; - } - return rc; -} - int idset_is_empty(struct idset *set) { return bitmap_empty(set->bitmap, set->num_ssid * set->num_id); diff --git a/drivers/s390/cio/idset.h b/drivers/s390/cio/idset.h index 06d3bc01bb09..22b58104683b 100644 --- a/drivers/s390/cio/idset.h +++ b/drivers/s390/cio/idset.h @@ -11,7 +11,6 @@ struct idset; void idset_free(struct idset *set); -void idset_clear(struct idset *set); void idset_fill(struct idset *set); struct idset *idset_sch_new(void); @@ -19,7 +18,6 @@ void idset_sch_add(struct idset *set, struct subchannel_id id); void idset_sch_del(struct idset *set, struct subchannel_id id); void idset_sch_del_subseq(struct idset *set, struct subchannel_id schid); int idset_sch_contains(struct idset *set, struct subchannel_id id); -int idset_sch_get_first(struct idset *set, struct subchannel_id *id); int idset_is_empty(struct idset *set); void idset_add_set(struct idset *to, struct idset *from); diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 4d41bf75c233..3d7f19fb9a4e 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -203,6 +203,24 @@ ap_test_queue(ap_qid_t qid, int *queue_depth, int *device_type) return reg1; } +/** + * ap_query_facilities(): PQAP(TAPQ) query facilities. + * @qid: The AP queue number + * + * Returns content of general register 2 after the PQAP(TAPQ) + * instruction was called. + */ +static inline unsigned long ap_query_facilities(ap_qid_t qid) +{ + register unsigned long reg0 asm ("0") = qid | 0x00800000UL; + register unsigned long reg1 asm ("1"); + register unsigned long reg2 asm ("2") = 0UL; + + asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */ + : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); + return reg2; +} + /** * ap_reset_queue(): Reset adjunct processor queue. * @qid: The AP queue number @@ -1006,6 +1024,51 @@ void ap_bus_force_rescan(void) } EXPORT_SYMBOL(ap_bus_force_rescan); +/* + * ap_test_config(): helper function to extract the nrth bit + * within the unsigned int array field. + */ +static inline int ap_test_config(unsigned int *field, unsigned int nr) +{ + if (nr > 0xFFu) + return 0; + return ap_test_bit((field + (nr >> 5)), (nr & 0x1f)); +} + +/* + * ap_test_config_card_id(): Test, whether an AP card ID is configured. + * @id AP card ID + * + * Returns 0 if the card is not configured + * 1 if the card is configured or + * if the configuration information is not available + */ +static inline int ap_test_config_card_id(unsigned int id) +{ + if (!ap_configuration) + return 1; + return ap_test_config(ap_configuration->apm, id); +} + +/* + * ap_test_config_domain(): Test, whether an AP usage domain is configured. + * @domain AP usage domain ID + * + * Returns 0 if the usage domain is not configured + * 1 if the usage domain is configured or + * if the configuration information is not available + */ +static inline int ap_test_config_domain(unsigned int domain) +{ + if (!ap_configuration) /* QCI not supported */ + if (domain < 16) + return 1; /* then domains 0...15 are configured */ + else + return 0; + else + return ap_test_config(ap_configuration->aqm, domain); +} + /* * AP bus attributes. */ @@ -1121,6 +1184,42 @@ static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf, static BUS_ATTR(poll_timeout, 0644, poll_timeout_show, poll_timeout_store); +static ssize_t ap_max_domain_id_show(struct bus_type *bus, char *buf) +{ + ap_qid_t qid; + int i, nd, max_domain_id = -1; + unsigned long fbits; + + if (ap_configuration) { + if (ap_domain_index >= 0 && ap_domain_index < AP_DOMAINS) { + for (i = 0; i < AP_DEVICES; i++) { + if (!ap_test_config_card_id(i)) + continue; + qid = AP_MKQID(i, ap_domain_index); + fbits = ap_query_facilities(qid); + if (fbits & (1UL << 57)) { + /* the N bit is 0, Nd field is filled */ + nd = (int)((fbits & 0x00FF0000UL)>>16); + if (nd > 0) + max_domain_id = nd; + else + max_domain_id = 15; + } else { + /* N bit is 1, max 16 domains */ + max_domain_id = 15; + } + break; + } + } + } else { + /* no APXA support, older machines with max 16 domains */ + max_domain_id = 15; + } + return snprintf(buf, PAGE_SIZE, "%d\n", max_domain_id); +} + +static BUS_ATTR(ap_max_domain_id, 0444, ap_max_domain_id_show, NULL); + static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_ap_domain, &bus_attr_ap_control_domain_mask, @@ -1128,50 +1227,10 @@ static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_poll_thread, &bus_attr_ap_interrupts, &bus_attr_poll_timeout, + &bus_attr_ap_max_domain_id, NULL, }; -static inline int ap_test_config(unsigned int *field, unsigned int nr) -{ - if (nr > 0xFFu) - return 0; - return ap_test_bit((field + (nr >> 5)), (nr & 0x1f)); -} - -/* - * ap_test_config_card_id(): Test, whether an AP card ID is configured. - * @id AP card ID - * - * Returns 0 if the card is not configured - * 1 if the card is configured or - * if the configuration information is not available - */ -static inline int ap_test_config_card_id(unsigned int id) -{ - if (!ap_configuration) - return 1; - return ap_test_config(ap_configuration->apm, id); -} - -/* - * ap_test_config_domain(): Test, whether an AP usage domain is configured. - * @domain AP usage domain ID - * - * Returns 0 if the usage domain is not configured - * 1 if the usage domain is configured or - * if the configuration information is not available - */ -static inline int ap_test_config_domain(unsigned int domain) -{ - if (!ap_configuration) /* QCI not supported */ - if (domain < 16) - return 1; /* then domains 0...15 are configured */ - else - return 0; - else - return ap_test_config(ap_configuration->aqm, domain); -} - /** * ap_query_configuration(): Query AP configuration information. * @@ -1434,9 +1493,6 @@ static void ap_scan_bus(struct work_struct *unused) continue; } break; - case 11: - ap_dev->device_type = 10; - break; default: ap_dev->device_type = device_type; } diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 055a0f956d17..2737d261a324 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -117,6 +117,7 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr) #define AP_DEVICE_TYPE_CEX3A 8 #define AP_DEVICE_TYPE_CEX3C 9 #define AP_DEVICE_TYPE_CEX4 10 +#define AP_DEVICE_TYPE_CEX5 11 /* * Known function facilities diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index b3d496bfaa7e..750876891931 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -75,6 +75,7 @@ struct ica_z90_status { #define ZCRYPT_CEX3C 7 #define ZCRYPT_CEX3A 8 #define ZCRYPT_CEX4 10 +#define ZCRYPT_CEX5 11 /** * Large random numbers are pulled in 4096 byte chunks from the crypto cards diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index 569f8b1d86c0..71e698b85772 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -26,6 +26,10 @@ #define CEX4A_SPEED_RATING 900 /* TODO new card, new speed rating */ #define CEX4C_SPEED_RATING 6500 /* TODO new card, new speed rating */ +#define CEX4P_SPEED_RATING 7000 /* TODO new card, new speed rating */ +#define CEX5A_SPEED_RATING 450 /* TODO new card, new speed rating */ +#define CEX5C_SPEED_RATING 3250 /* TODO new card, new speed rating */ +#define CEX5P_SPEED_RATING 3500 /* TODO new card, new speed rating */ #define CEX4A_MAX_MESSAGE_SIZE MSGTYPE50_CRB3_MAX_MSG_SIZE #define CEX4C_MAX_MESSAGE_SIZE MSGTYPE06_MAX_MSG_SIZE @@ -39,6 +43,7 @@ static struct ap_device_id zcrypt_cex4_ids[] = { { AP_DEVICE(AP_DEVICE_TYPE_CEX4) }, + { AP_DEVICE(AP_DEVICE_TYPE_CEX5) }, { /* end of list */ }, }; @@ -70,11 +75,18 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) switch (ap_dev->device_type) { case AP_DEVICE_TYPE_CEX4: + case AP_DEVICE_TYPE_CEX5: if (ap_test_bit(&ap_dev->functions, AP_FUNC_ACCEL)) { zdev = zcrypt_device_alloc(CEX4A_MAX_MESSAGE_SIZE); if (!zdev) return -ENOMEM; - zdev->type_string = "CEX4A"; + if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { + zdev->type_string = "CEX4A"; + zdev->speed_rating = CEX4A_SPEED_RATING; + } else { + zdev->type_string = "CEX5A"; + zdev->speed_rating = CEX5A_SPEED_RATING; + } zdev->user_space_type = ZCRYPT_CEX3A; zdev->min_mod_size = CEX4A_MIN_MOD_SIZE; if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) && @@ -90,33 +102,42 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) CEX4A_MAX_MOD_SIZE_2K; } zdev->short_crt = 1; - zdev->speed_rating = CEX4A_SPEED_RATING; zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT); } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_COPRO)) { zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE); if (!zdev) return -ENOMEM; - zdev->type_string = "CEX4C"; + if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { + zdev->type_string = "CEX4C"; + zdev->speed_rating = CEX4C_SPEED_RATING; + } else { + zdev->type_string = "CEX5C"; + zdev->speed_rating = CEX5C_SPEED_RATING; + } zdev->user_space_type = ZCRYPT_CEX3C; zdev->min_mod_size = CEX4C_MIN_MOD_SIZE; zdev->max_mod_size = CEX4C_MAX_MOD_SIZE; zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; zdev->short_crt = 0; - zdev->speed_rating = CEX4C_SPEED_RATING; zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, MSGTYPE06_VARIANT_DEFAULT); } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_EP11)) { zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE); if (!zdev) return -ENOMEM; - zdev->type_string = "CEX4P"; + if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { + zdev->type_string = "CEX4P"; + zdev->speed_rating = CEX4P_SPEED_RATING; + } else { + zdev->type_string = "CEX5P"; + zdev->speed_rating = CEX5P_SPEED_RATING; + } zdev->user_space_type = ZCRYPT_CEX4; zdev->min_mod_size = CEX4C_MIN_MOD_SIZE; zdev->max_mod_size = CEX4C_MAX_MOD_SIZE; zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; zdev->short_crt = 0; - zdev->speed_rating = CEX4C_SPEED_RATING; zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, MSGTYPE06_VARIANT_EP11); } diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 213e54ee8a66..d609ca09aa94 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -109,10 +109,8 @@ static debug_info_t *claw_dbf_trace; static void claw_unregister_debug_facility(void) { - if (claw_dbf_setup) - debug_unregister(claw_dbf_setup); - if (claw_dbf_trace) - debug_unregister(claw_dbf_trace); + debug_unregister(claw_dbf_setup); + debug_unregister(claw_dbf_trace); } static int diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c index fb92524d24ef..fd5944bbe224 100644 --- a/drivers/s390/net/ctcm_fsms.c +++ b/drivers/s390/net/ctcm_fsms.c @@ -251,13 +251,11 @@ static void chx_txdone(fsm_instance *fi, int event, void *arg) int first = 1; int i; unsigned long duration; - struct timespec done_stamp = current_kernel_time(); /* xtime */ + unsigned long done_stamp = jiffies; CTCM_PR_DEBUG("%s(%s): %s\n", __func__, ch->id, dev->name); - duration = - (done_stamp.tv_sec - ch->prof.send_stamp.tv_sec) * 1000000 + - (done_stamp.tv_nsec - ch->prof.send_stamp.tv_nsec) / 1000; + duration = done_stamp - ch->prof.send_stamp; if (duration > ch->prof.tx_time) ch->prof.tx_time = duration; @@ -307,7 +305,7 @@ static void chx_txdone(fsm_instance *fi, int event, void *arg) spin_unlock(&ch->collect_lock); ch->ccw[1].count = ch->trans_skb->len; fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch); - ch->prof.send_stamp = current_kernel_time(); /* xtime */ + ch->prof.send_stamp = jiffies; rc = ccw_device_start(ch->cdev, &ch->ccw[0], (unsigned long)ch, 0xff, 0); ch->prof.doios_multi++; @@ -1229,14 +1227,12 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg) int rc; struct th_header *header; struct pdu *p_header; - struct timespec done_stamp = current_kernel_time(); /* xtime */ + unsigned long done_stamp = jiffies; CTCM_PR_DEBUG("Enter %s: %s cp:%i\n", __func__, dev->name, smp_processor_id()); - duration = - (done_stamp.tv_sec - ch->prof.send_stamp.tv_sec) * 1000000 + - (done_stamp.tv_nsec - ch->prof.send_stamp.tv_nsec) / 1000; + duration = done_stamp - ch->prof.send_stamp; if (duration > ch->prof.tx_time) ch->prof.tx_time = duration; @@ -1361,7 +1357,7 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg) ch->ccw[1].count = ch->trans_skb->len; fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch); - ch->prof.send_stamp = current_kernel_time(); /* xtime */ + ch->prof.send_stamp = jiffies; if (do_debug_ccw) ctcmpc_dumpit((char *)&ch->ccw[0], sizeof(struct ccw1) * 3); rc = ccw_device_start(ch->cdev, &ch->ccw[0], @@ -1827,7 +1823,7 @@ static void ctcmpc_chx_send_sweep(fsm_instance *fsm, int event, void *arg) fsm_newstate(wch->fsm, CTC_STATE_TX); spin_lock_irqsave(get_ccwdev_lock(wch->cdev), saveflags); - wch->prof.send_stamp = current_kernel_time(); /* xtime */ + wch->prof.send_stamp = jiffies; rc = ccw_device_start(wch->cdev, &wch->ccw[3], (unsigned long) wch, 0xff, 0); spin_unlock_irqrestore(get_ccwdev_lock(wch->cdev), saveflags); diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index e056dd4fe44d..05c37d6d4afe 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -567,7 +567,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb) fsm_newstate(ch->fsm, CTC_STATE_TX); fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch); spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags); - ch->prof.send_stamp = current_kernel_time(); /* xtime */ + ch->prof.send_stamp = jiffies; rc = ccw_device_start(ch->cdev, &ch->ccw[ccw_idx], (unsigned long)ch, 0xff, 0); spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags); @@ -831,7 +831,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb) sizeof(struct ccw1) * 3); spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags); - ch->prof.send_stamp = current_kernel_time(); /* xtime */ + ch->prof.send_stamp = jiffies; rc = ccw_device_start(ch->cdev, &ch->ccw[ccw_idx], (unsigned long)ch, 0xff, 0); spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags); diff --git a/drivers/s390/net/ctcm_main.h b/drivers/s390/net/ctcm_main.h index 477c933685f3..6f4417c80247 100644 --- a/drivers/s390/net/ctcm_main.h +++ b/drivers/s390/net/ctcm_main.h @@ -121,7 +121,7 @@ struct ctcm_profile { unsigned long doios_multi; unsigned long txlen; unsigned long tx_time; - struct timespec send_stamp; + unsigned long send_stamp; }; /* diff --git a/drivers/s390/net/ctcm_sysfs.c b/drivers/s390/net/ctcm_sysfs.c index 47773c4d235a..ddb0aa321339 100644 --- a/drivers/s390/net/ctcm_sysfs.c +++ b/drivers/s390/net/ctcm_sysfs.c @@ -100,8 +100,8 @@ static void ctcm_print_statistics(struct ctcm_priv *priv) priv->channel[WRITE]->prof.doios_multi); p += sprintf(p, " Netto bytes written: %ld\n", priv->channel[WRITE]->prof.txlen); - p += sprintf(p, " Max. TX IO-time: %ld\n", - priv->channel[WRITE]->prof.tx_time); + p += sprintf(p, " Max. TX IO-time: %u\n", + jiffies_to_usecs(priv->channel[WRITE]->prof.tx_time)); printk(KERN_INFO "Statistics for %s:\n%s", priv->channel[CTCM_WRITE]->netdev->name, sbuf); diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 92190aa20b9f..00b7d9c9fe48 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -88,10 +88,8 @@ static debug_info_t *lcs_dbf_trace; static void lcs_unregister_debug_facility(void) { - if (lcs_dbf_setup) - debug_unregister(lcs_dbf_setup); - if (lcs_dbf_trace) - debug_unregister(lcs_dbf_trace); + debug_unregister(lcs_dbf_setup); + debug_unregister(lcs_dbf_trace); } static int diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 0a87809c8af7..33f7040d711d 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -178,7 +178,7 @@ struct connection_profile { unsigned long doios_multi; unsigned long txlen; unsigned long tx_time; - struct timespec send_stamp; + unsigned long send_stamp; unsigned long tx_pending; unsigned long tx_max_pending; }; @@ -487,12 +487,9 @@ DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf); static void iucv_unregister_dbf_views(void) { - if (iucv_dbf_setup) - debug_unregister(iucv_dbf_setup); - if (iucv_dbf_data) - debug_unregister(iucv_dbf_data); - if (iucv_dbf_trace) - debug_unregister(iucv_dbf_trace); + debug_unregister(iucv_dbf_setup); + debug_unregister(iucv_dbf_data); + debug_unregister(iucv_dbf_trace); } static int iucv_register_dbf_views(void) { @@ -786,7 +783,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg) header.next = 0; memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); - conn->prof.send_stamp = current_kernel_time(); + conn->prof.send_stamp = jiffies; txmsg.class = 0; txmsg.tag = 0; rc = iucv_message_send(conn->path, &txmsg, 0, 0, @@ -1220,7 +1217,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn, memcpy(skb_put(nskb, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); fsm_newstate(conn->fsm, CONN_STATE_TX); - conn->prof.send_stamp = current_kernel_time(); + conn->prof.send_stamp = jiffies; msg.tag = 1; msg.class = 0; diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 7a8bb9f78e76..3abac028899f 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -596,7 +596,6 @@ struct qeth_channel { struct ccw1 ccw; spinlock_t iob_lock; wait_queue_head_t wait_q; - struct tasklet_struct irq_tasklet; struct ccw_device *ccwdev; /*command buffer for control data*/ struct qeth_cmd_buffer iob[QETH_CMD_BUFFER_NO]; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index f407e3763432..642c77c76b84 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1784,6 +1784,8 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel, QETH_DBF_TEXT(SETUP, 2, "idxanswr"); card = CARD_FROM_CDEV(channel->ccwdev); iob = qeth_get_buffer(channel); + if (!iob) + return -ENOMEM; iob->callback = idx_reply_cb; memcpy(&channel->ccw, READ_CCW, sizeof(struct ccw1)); channel->ccw.count = QETH_BUFSIZE; @@ -1834,6 +1836,8 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel, QETH_DBF_TEXT(SETUP, 2, "idxactch"); iob = qeth_get_buffer(channel); + if (!iob) + return -ENOMEM; iob->callback = idx_reply_cb; memcpy(&channel->ccw, WRITE_CCW, sizeof(struct ccw1)); channel->ccw.count = IDX_ACTIVATE_SIZE; @@ -2021,10 +2025,36 @@ void qeth_prepare_control_data(struct qeth_card *card, int len, } EXPORT_SYMBOL_GPL(qeth_prepare_control_data); +/** + * qeth_send_control_data() - send control command to the card + * @card: qeth_card structure pointer + * @len: size of the command buffer + * @iob: qeth_cmd_buffer pointer + * @reply_cb: callback function pointer + * @cb_card: pointer to the qeth_card structure + * @cb_reply: pointer to the qeth_reply structure + * @cb_cmd: pointer to the original iob for non-IPA + * commands, or to the qeth_ipa_cmd structure + * for the IPA commands. + * @reply_param: private pointer passed to the callback + * + * Returns the value of the `return_code' field of the response + * block returned from the hardware, or other error indication. + * Value of zero indicates successful execution of the command. + * + * Callback function gets called one or more times, with cb_cmd + * pointing to the response returned by the hardware. Callback + * function must return non-zero if more reply blocks are expected, + * and zero if the last or only reply block is received. Callback + * function can get the value of the reply_param pointer from the + * field 'param' of the structure qeth_reply. + */ + int qeth_send_control_data(struct qeth_card *card, int len, struct qeth_cmd_buffer *iob, - int (*reply_cb)(struct qeth_card *, struct qeth_reply *, - unsigned long), + int (*reply_cb)(struct qeth_card *cb_card, + struct qeth_reply *cb_reply, + unsigned long cb_cmd), void *reply_param) { int rc; @@ -2914,9 +2944,16 @@ struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *card, struct qeth_cmd_buffer *iob; struct qeth_ipa_cmd *cmd; - iob = qeth_wait_for_buffer(&card->write); - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); - qeth_fill_ipacmd_header(card, cmd, ipacmd, prot); + iob = qeth_get_buffer(&card->write); + if (iob) { + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + qeth_fill_ipacmd_header(card, cmd, ipacmd, prot); + } else { + dev_warn(&card->gdev->dev, + "The qeth driver ran out of channel command buffers\n"); + QETH_DBF_MESSAGE(1, "%s The qeth driver ran out of channel command buffers", + dev_name(&card->gdev->dev)); + } return iob; } @@ -2932,6 +2969,12 @@ void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, } EXPORT_SYMBOL_GPL(qeth_prepare_ipa_cmd); +/** + * qeth_send_ipa_cmd() - send an IPA command + * + * See qeth_send_control_data() for explanation of the arguments. + */ + int qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long), @@ -2968,6 +3011,8 @@ int qeth_send_startlan(struct qeth_card *card) QETH_DBF_TEXT(SETUP, 2, "strtlan"); iob = qeth_get_ipacmd_buffer(card, IPA_CMD_STARTLAN, 0); + if (!iob) + return -ENOMEM; rc = qeth_send_ipa_cmd(card, iob, NULL, NULL); return rc; } @@ -3013,11 +3058,13 @@ static struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *card, iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETADAPTERPARMS, QETH_PROT_IPV4); - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); - cmd->data.setadapterparms.hdr.cmdlength = cmdlen; - cmd->data.setadapterparms.hdr.command_code = command; - cmd->data.setadapterparms.hdr.used_total = 1; - cmd->data.setadapterparms.hdr.seq_no = 1; + if (iob) { + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd->data.setadapterparms.hdr.cmdlength = cmdlen; + cmd->data.setadapterparms.hdr.command_code = command; + cmd->data.setadapterparms.hdr.used_total = 1; + cmd->data.setadapterparms.hdr.seq_no = 1; + } return iob; } @@ -3030,6 +3077,8 @@ int qeth_query_setadapterparms(struct qeth_card *card) QETH_CARD_TEXT(card, 3, "queryadp"); iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_COMMANDS_SUPPORTED, sizeof(struct qeth_ipacmd_setadpparms)); + if (!iob) + return -ENOMEM; rc = qeth_send_ipa_cmd(card, iob, qeth_query_setadapterparms_cb, NULL); return rc; } @@ -3080,6 +3129,8 @@ int qeth_query_ipassists(struct qeth_card *card, enum qeth_prot_versions prot) QETH_DBF_TEXT_(SETUP, 2, "qipassi%i", prot); iob = qeth_get_ipacmd_buffer(card, IPA_CMD_QIPASSIST, prot); + if (!iob) + return -ENOMEM; rc = qeth_send_ipa_cmd(card, iob, qeth_query_ipassists_cb, NULL); return rc; } @@ -3119,6 +3170,8 @@ int qeth_query_switch_attributes(struct qeth_card *card, return -ENOMEDIUM; iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_SWITCH_ATTRIBUTES, sizeof(struct qeth_ipacmd_setadpparms_hdr)); + if (!iob) + return -ENOMEM; return qeth_send_ipa_cmd(card, iob, qeth_query_switch_attributes_cb, sw_info); } @@ -3146,6 +3199,8 @@ static int qeth_query_setdiagass(struct qeth_card *card) QETH_DBF_TEXT(SETUP, 2, "qdiagass"); iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); + if (!iob) + return -ENOMEM; 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; @@ -3197,6 +3252,8 @@ int qeth_hw_trap(struct qeth_card *card, enum qeth_diags_trap_action action) QETH_DBF_TEXT(SETUP, 2, "diagtrap"); iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); + if (!iob) + return -ENOMEM; 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; @@ -4162,6 +4219,8 @@ void qeth_setadp_promisc_mode(struct qeth_card *card) iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_PROMISC_MODE, sizeof(struct qeth_ipacmd_setadpparms)); + if (!iob) + return; cmd = (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE); cmd->data.setadapterparms.data.mode = mode; qeth_send_ipa_cmd(card, iob, qeth_setadp_promisc_mode_cb, NULL); @@ -4232,6 +4291,8 @@ int qeth_setadpparms_change_macaddr(struct qeth_card *card) iob = qeth_get_adapter_cmd(card, IPA_SETADP_ALTER_MAC_ADDRESS, sizeof(struct qeth_ipacmd_setadpparms)); + if (!iob) + return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); cmd->data.setadapterparms.data.change_addr.cmd = CHANGE_ADDR_READ_MAC; cmd->data.setadapterparms.data.change_addr.addr_size = OSA_ADDR_LEN; @@ -4345,6 +4406,8 @@ static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card, iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_ACCESS_CONTROL, sizeof(struct qeth_ipacmd_setadpparms_hdr) + sizeof(struct qeth_set_access_ctrl)); + if (!iob) + return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl; access_ctrl_req->subcmd_code = isolation; @@ -4588,6 +4651,10 @@ int qeth_snmp_command(struct qeth_card *card, char __user *udata) iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_SNMP_CONTROL, QETH_SNMP_SETADP_CMDLENGTH + req_len); + if (!iob) { + rc = -ENOMEM; + goto out; + } cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); memcpy(&cmd->data.setadapterparms.data.snmp, &ureq->cmd, req_len); rc = qeth_send_ipa_snmp_cmd(card, iob, QETH_SETADP_BASE_LEN + req_len, @@ -4599,7 +4666,7 @@ int qeth_snmp_command(struct qeth_card *card, char __user *udata) if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) rc = -EFAULT; } - +out: kfree(ureq); kfree(qinfo.udata); return rc; @@ -4670,6 +4737,10 @@ int qeth_query_oat_command(struct qeth_card *card, char __user *udata) iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_OAT, sizeof(struct qeth_ipacmd_setadpparms_hdr) + sizeof(struct qeth_query_oat)); + if (!iob) { + rc = -ENOMEM; + goto out_free; + } cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); oat_req = &cmd->data.setadapterparms.data.query_oat; oat_req->subcmd_code = oat_data.command; @@ -4735,6 +4806,8 @@ static int qeth_query_card_info(struct qeth_card *card, return -EOPNOTSUPP; iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_CARD_INFO, sizeof(struct qeth_ipacmd_setadpparms_hdr)); + if (!iob) + return -ENOMEM; return qeth_send_ipa_cmd(card, iob, qeth_query_card_info_cb, (void *)carrier_info); } @@ -5060,11 +5133,23 @@ retriable: card->options.adp.supported_funcs = 0; card->options.sbp.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); + rc = qeth_query_ipassists(card, QETH_PROT_IPV4); + if (rc == -ENOMEM) + goto out; + if (qeth_is_supported(card, IPA_SETADAPTERPARMS)) { + rc = qeth_query_setadapterparms(card); + if (rc < 0) { + QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); + goto out; + } + } + if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) { + rc = qeth_query_setdiagass(card); + if (rc < 0) { + QETH_DBF_TEXT_(SETUP, 2, "7err%d", rc); + goto out; + } + } return 0; out: dev_warn(&card->gdev->dev, "The qeth device driver failed to recover " diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 15523f0e4c03..423bec56cffa 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -231,7 +231,6 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev_get_drvdata(dev); - char *tmp; int rc = 0; if (!card) @@ -253,36 +252,35 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev, goto out; } - tmp = strsep((char **) &buf, "\n"); - if (!strcmp(tmp, "prio_queueing_prec")) { + if (sysfs_streq(buf, "prio_queueing_prec")) { card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_PREC; card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; - } else if (!strcmp(tmp, "prio_queueing_skb")) { + } else if (sysfs_streq(buf, "prio_queueing_skb")) { card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_SKB; card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; - } else if (!strcmp(tmp, "prio_queueing_tos")) { + } else if (sysfs_streq(buf, "prio_queueing_tos")) { card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_TOS; card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; - } else if (!strcmp(tmp, "prio_queueing_vlan")) { + } else if (sysfs_streq(buf, "prio_queueing_vlan")) { if (!card->options.layer2) { rc = -ENOTSUPP; goto out; } card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_VLAN; card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; - } else if (!strcmp(tmp, "no_prio_queueing:0")) { + } else if (sysfs_streq(buf, "no_prio_queueing:0")) { card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; card->qdio.default_out_queue = 0; - } else if (!strcmp(tmp, "no_prio_queueing:1")) { + } else if (sysfs_streq(buf, "no_prio_queueing:1")) { card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; card->qdio.default_out_queue = 1; - } else if (!strcmp(tmp, "no_prio_queueing:2")) { + } else if (sysfs_streq(buf, "no_prio_queueing:2")) { card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; card->qdio.default_out_queue = 2; - } else if (!strcmp(tmp, "no_prio_queueing:3")) { + } else if (sysfs_streq(buf, "no_prio_queueing:3")) { card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; card->qdio.default_out_queue = 3; - } else if (!strcmp(tmp, "no_prio_queueing")) { + } else if (sysfs_streq(buf, "no_prio_queueing")) { card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; } else @@ -497,8 +495,6 @@ static ssize_t qeth_dev_isolation_store(struct device *dev, struct qeth_card *card = dev_get_drvdata(dev); enum qeth_ipa_isolation_modes isolation; int rc = 0; - char *tmp, *curtoken; - curtoken = (char *) buf; if (!card) return -EINVAL; @@ -515,12 +511,11 @@ static ssize_t qeth_dev_isolation_store(struct device *dev, } /* parse input into isolation mode */ - tmp = strsep(&curtoken, "\n"); - if (!strcmp(tmp, ATTR_QETH_ISOLATION_NONE)) { + if (sysfs_streq(buf, ATTR_QETH_ISOLATION_NONE)) { isolation = ISOLATION_MODE_NONE; - } else if (!strcmp(tmp, ATTR_QETH_ISOLATION_FWD)) { + } else if (sysfs_streq(buf, ATTR_QETH_ISOLATION_FWD)) { isolation = ISOLATION_MODE_FWD; - } else if (!strcmp(tmp, ATTR_QETH_ISOLATION_DROP)) { + } else if (sysfs_streq(buf, ATTR_QETH_ISOLATION_DROP)) { isolation = ISOLATION_MODE_DROP; } else { rc = -EINVAL; @@ -531,8 +526,7 @@ static ssize_t qeth_dev_isolation_store(struct device *dev, /* defer IP assist if device is offline (until discipline->set_online)*/ card->options.prev_isolation = card->options.isolation; card->options.isolation = isolation; - if (card->state == CARD_STATE_SOFTSETUP || - card->state == CARD_STATE_UP) { + if (qeth_card_hw_is_reachable(card)) { int ipa_rc = qeth_set_access_ctrl_online(card, 1); if (ipa_rc != 0) rc = ipa_rc; @@ -555,7 +549,7 @@ static ssize_t qeth_dev_switch_attrs_show(struct device *dev, if (!card) return -EINVAL; - if (card->state != CARD_STATE_SOFTSETUP && card->state != CARD_STATE_UP) + if (!qeth_card_hw_is_reachable(card)) return sprintf(buf, "n/a\n"); rc = qeth_query_switch_attributes(card, &sw_info); @@ -598,19 +592,16 @@ static ssize_t qeth_hw_trap_store(struct device *dev, { 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) + if (qeth_card_hw_is_reachable(card)) state = 1; - tmp = strsep(&curtoken, "\n"); - if (!strcmp(tmp, "arm") && !card->info.hwtrap) { + if (sysfs_streq(buf, "arm") && !card->info.hwtrap) { if (state) { if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) { @@ -621,14 +612,14 @@ static ssize_t qeth_hw_trap_store(struct device *dev, rc = -EINVAL; } else card->info.hwtrap = 1; - } else if (!strcmp(tmp, "disarm") && card->info.hwtrap) { + } else if (sysfs_streq(buf, "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) + } else if (sysfs_streq(buf, "trap") && state && card->info.hwtrap) rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_CAPTURE); else rc = -EINVAL; diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index d02cd1a67943..0ea0869120cf 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -27,10 +27,7 @@ static int qeth_l2_set_offline(struct ccwgroup_device *); static int qeth_l2_stop(struct net_device *); static int qeth_l2_send_delmac(struct qeth_card *, __u8 *); static int qeth_l2_send_setdelmac(struct qeth_card *, __u8 *, - enum qeth_ipa_cmds, - int (*reply_cb) (struct qeth_card *, - struct qeth_reply*, - unsigned long)); + enum qeth_ipa_cmds); static void qeth_l2_set_multicast_list(struct net_device *); static int qeth_l2_recover(void *); static void qeth_bridgeport_query_support(struct qeth_card *card); @@ -48,8 +45,7 @@ static int qeth_l2_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if (!card) return -ENODEV; - if ((card->state != CARD_STATE_UP) && - (card->state != CARD_STATE_SOFTSETUP)) + if (!qeth_card_hw_is_reachable(card)) return -ENODEV; if (card->info.type == QETH_CARD_TYPE_OSN) @@ -130,56 +126,71 @@ static struct net_device *qeth_l2_netdev_by_devno(unsigned char *read_dev_no) return ndev; } -static int qeth_l2_send_setgroupmac_cb(struct qeth_card *card, - struct qeth_reply *reply, - unsigned long data) +static int qeth_setdel_makerc(struct qeth_card *card, int retcode) { - struct qeth_ipa_cmd *cmd; - __u8 *mac; + int rc; - QETH_CARD_TEXT(card, 2, "L2Sgmacb"); - cmd = (struct qeth_ipa_cmd *) data; - mac = &cmd->data.setdelmac.mac[0]; - /* MAC already registered, needed in couple/uncouple case */ - if (cmd->hdr.return_code == IPA_RC_L2_DUP_MAC) { - QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n", - mac, QETH_CARD_IFNAME(card)); - cmd->hdr.return_code = 0; + if (retcode) + QETH_CARD_TEXT_(card, 2, "err%04x", retcode); + switch (retcode) { + case IPA_RC_SUCCESS: + rc = 0; + break; + case IPA_RC_L2_UNSUPPORTED_CMD: + rc = -ENOSYS; + break; + case IPA_RC_L2_ADDR_TABLE_FULL: + rc = -ENOSPC; + break; + case IPA_RC_L2_DUP_MAC: + case IPA_RC_L2_DUP_LAYER3_MAC: + rc = -EEXIST; + break; + case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP: + case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: + rc = -EPERM; + break; + case IPA_RC_L2_MAC_NOT_FOUND: + rc = -ENOENT; + break; + case -ENOMEM: + rc = -ENOMEM; + break; + default: + rc = -EIO; + break; } - if (cmd->hdr.return_code) - QETH_DBF_MESSAGE(2, "Could not set group MAC %pM on %s: %x\n", - mac, QETH_CARD_IFNAME(card), cmd->hdr.return_code); - return 0; + return rc; } static int qeth_l2_send_setgroupmac(struct qeth_card *card, __u8 *mac) { + int rc; + QETH_CARD_TEXT(card, 2, "L2Sgmac"); - return qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETGMAC, - qeth_l2_send_setgroupmac_cb); -} - -static int qeth_l2_send_delgroupmac_cb(struct qeth_card *card, - struct qeth_reply *reply, - unsigned long data) -{ - struct qeth_ipa_cmd *cmd; - __u8 *mac; - - QETH_CARD_TEXT(card, 2, "L2Dgmacb"); - cmd = (struct qeth_ipa_cmd *) data; - mac = &cmd->data.setdelmac.mac[0]; - if (cmd->hdr.return_code) - QETH_DBF_MESSAGE(2, "Could not delete group MAC %pM on %s: %x\n", - mac, QETH_CARD_IFNAME(card), cmd->hdr.return_code); - return 0; + rc = qeth_setdel_makerc(card, qeth_l2_send_setdelmac(card, mac, + IPA_CMD_SETGMAC)); + if (rc == -EEXIST) + QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s\n", + mac, QETH_CARD_IFNAME(card)); + else if (rc) + QETH_DBF_MESSAGE(2, "Could not set group MAC %pM on %s: %d\n", + mac, QETH_CARD_IFNAME(card), rc); + return rc; } static int qeth_l2_send_delgroupmac(struct qeth_card *card, __u8 *mac) { + int rc; + QETH_CARD_TEXT(card, 2, "L2Dgmac"); - return qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELGMAC, - qeth_l2_send_delgroupmac_cb); + rc = qeth_setdel_makerc(card, qeth_l2_send_setdelmac(card, mac, + IPA_CMD_DELGMAC)); + if (rc) + QETH_DBF_MESSAGE(2, + "Could not delete group MAC %pM on %s: %d\n", + mac, QETH_CARD_IFNAME(card), rc); + return rc; } static void qeth_l2_add_mc(struct qeth_card *card, __u8 *mac, int vmac) @@ -197,10 +208,11 @@ static void qeth_l2_add_mc(struct qeth_card *card, __u8 *mac, int vmac) mc->is_vmac = vmac; if (vmac) { - rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC, - NULL); + rc = qeth_setdel_makerc(card, + qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC)); } else { - rc = qeth_l2_send_setgroupmac(card, mac); + rc = qeth_setdel_makerc(card, + qeth_l2_send_setgroupmac(card, mac)); } if (!rc) @@ -218,7 +230,7 @@ static void qeth_l2_del_all_mc(struct qeth_card *card, int del) if (del) { if (mc->is_vmac) qeth_l2_send_setdelmac(card, mc->mc_addr, - IPA_CMD_DELVMAC, NULL); + IPA_CMD_DELVMAC); else qeth_l2_send_delgroupmac(card, mc->mc_addr); } @@ -291,6 +303,8 @@ static int qeth_l2_send_setdelvlan(struct qeth_card *card, __u16 i, QETH_CARD_TEXT_(card, 4, "L2sdv%x", ipacmd); iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4); + if (!iob) + return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); cmd->data.setdelvlan.vlan_id = i; return qeth_send_ipa_cmd(card, iob, @@ -313,6 +327,7 @@ static int qeth_l2_vlan_rx_add_vid(struct net_device *dev, { struct qeth_card *card = dev->ml_priv; struct qeth_vlan_vid *id; + int rc; QETH_CARD_TEXT_(card, 4, "aid:%d", vid); if (!vid) @@ -328,7 +343,11 @@ static int qeth_l2_vlan_rx_add_vid(struct net_device *dev, id = kmalloc(sizeof(struct qeth_vlan_vid), GFP_ATOMIC); if (id) { id->vid = vid; - qeth_l2_send_setdelvlan(card, vid, IPA_CMD_SETVLAN); + rc = qeth_l2_send_setdelvlan(card, vid, IPA_CMD_SETVLAN); + if (rc) { + kfree(id); + return rc; + } spin_lock_bh(&card->vlanlock); list_add_tail(&id->list, &card->vid_list); spin_unlock_bh(&card->vlanlock); @@ -343,6 +362,7 @@ static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev, { struct qeth_vlan_vid *id, *tmpid = NULL; struct qeth_card *card = dev->ml_priv; + int rc = 0; QETH_CARD_TEXT_(card, 4, "kid:%d", vid); if (card->info.type == QETH_CARD_TYPE_OSM) { @@ -363,11 +383,11 @@ static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev, } spin_unlock_bh(&card->vlanlock); if (tmpid) { - qeth_l2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN); + rc = qeth_l2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN); kfree(tmpid); } qeth_l2_set_multicast_list(card->dev); - return 0; + return rc; } static int qeth_l2_stop_card(struct qeth_card *card, int recovery_mode) @@ -539,91 +559,62 @@ out: } static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac, - enum qeth_ipa_cmds ipacmd, - int (*reply_cb) (struct qeth_card *, - struct qeth_reply*, - unsigned long)) + enum qeth_ipa_cmds ipacmd) { struct qeth_ipa_cmd *cmd; struct qeth_cmd_buffer *iob; QETH_CARD_TEXT(card, 2, "L2sdmac"); iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4); + if (!iob) + return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); cmd->data.setdelmac.mac_length = OSA_ADDR_LEN; memcpy(&cmd->data.setdelmac.mac, mac, OSA_ADDR_LEN); - return qeth_send_ipa_cmd(card, iob, reply_cb, NULL); -} - -static int qeth_l2_send_setmac_cb(struct qeth_card *card, - struct qeth_reply *reply, - unsigned long data) -{ - struct qeth_ipa_cmd *cmd; - - QETH_CARD_TEXT(card, 2, "L2Smaccb"); - cmd = (struct qeth_ipa_cmd *) data; - if (cmd->hdr.return_code) { - QETH_CARD_TEXT_(card, 2, "L2er%x", cmd->hdr.return_code); - card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; - switch (cmd->hdr.return_code) { - case IPA_RC_L2_DUP_MAC: - case IPA_RC_L2_DUP_LAYER3_MAC: - dev_warn(&card->gdev->dev, - "MAC address %pM already exists\n", - cmd->data.setdelmac.mac); - break; - case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP: - case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: - dev_warn(&card->gdev->dev, - "MAC address %pM is not authorized\n", - cmd->data.setdelmac.mac); - break; - default: - break; - } - } else { - card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; - memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac, - OSA_ADDR_LEN); - dev_info(&card->gdev->dev, - "MAC address %pM successfully registered on device %s\n", - card->dev->dev_addr, card->dev->name); - } - return 0; + return qeth_send_ipa_cmd(card, iob, NULL, NULL); } static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac) { + int rc; + QETH_CARD_TEXT(card, 2, "L2Setmac"); - return qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC, - qeth_l2_send_setmac_cb); -} - -static int qeth_l2_send_delmac_cb(struct qeth_card *card, - struct qeth_reply *reply, - unsigned long data) -{ - struct qeth_ipa_cmd *cmd; - - QETH_CARD_TEXT(card, 2, "L2Dmaccb"); - cmd = (struct qeth_ipa_cmd *) data; - if (cmd->hdr.return_code) { - QETH_CARD_TEXT_(card, 2, "err%d", cmd->hdr.return_code); - return 0; + rc = qeth_setdel_makerc(card, qeth_l2_send_setdelmac(card, mac, + IPA_CMD_SETVMAC)); + if (rc == 0) { + card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; + memcpy(card->dev->dev_addr, mac, OSA_ADDR_LEN); + dev_info(&card->gdev->dev, + "MAC address %pM successfully registered on device %s\n", + card->dev->dev_addr, card->dev->name); + } else { + card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; + switch (rc) { + case -EEXIST: + dev_warn(&card->gdev->dev, + "MAC address %pM already exists\n", mac); + break; + case -EPERM: + dev_warn(&card->gdev->dev, + "MAC address %pM is not authorized\n", mac); + break; + } } - card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; - - return 0; + return rc; } static int qeth_l2_send_delmac(struct qeth_card *card, __u8 *mac) { + int rc; + QETH_CARD_TEXT(card, 2, "L2Delmac"); if (!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED)) return 0; - return qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELVMAC, - qeth_l2_send_delmac_cb); + rc = qeth_setdel_makerc(card, qeth_l2_send_setdelmac(card, mac, + IPA_CMD_DELVMAC)); + if (rc == 0) + card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; + return rc; } static int qeth_l2_request_initial_mac(struct qeth_card *card) @@ -651,7 +642,7 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card) if (rc) { QETH_DBF_MESSAGE(2, "couldn't get MAC address on " "device %s: x%x\n", CARD_BUS_ID(card), rc); - QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); + QETH_DBF_TEXT_(SETUP, 2, "1err%04x", rc); return rc; } QETH_DBF_HEX(SETUP, 2, card->dev->dev_addr, OSA_ADDR_LEN); @@ -687,7 +678,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p) return -ERESTARTSYS; } rc = qeth_l2_send_delmac(card, &card->dev->dev_addr[0]); - if (!rc || (rc == IPA_RC_L2_MAC_NOT_FOUND)) + if (!rc || (rc == -ENOENT)) rc = qeth_l2_send_setmac(card, addr->sa_data); return rc ? -EINVAL : 0; } @@ -996,7 +987,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) recover_flag = card->state; rc = qeth_core_hardsetup_card(card); if (rc) { - QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); + QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc); rc = -ENODEV; goto out_remove; } @@ -1344,8 +1335,7 @@ int qeth_osn_assist(struct net_device *dev, void *data, int data_len) if (!card) return -ENODEV; QETH_CARD_TEXT(card, 2, "osnsdmc"); - if ((card->state != CARD_STATE_UP) && - (card->state != CARD_STATE_SOFTSETUP)) + if (!qeth_card_hw_is_reachable(card)) return -ENODEV; iob = qeth_wait_for_buffer(&card->write); memcpy(iob->data+IPA_PDU_HEADER_SIZE, data, data_len); @@ -1730,6 +1720,8 @@ static void qeth_bridgeport_query_support(struct qeth_card *card) QETH_CARD_TEXT(card, 2, "brqsuppo"); iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0); + if (!iob) + return; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); cmd->data.sbp.hdr.cmdlength = sizeof(struct qeth_ipacmd_sbp_hdr) + @@ -1805,6 +1797,8 @@ int qeth_bridgeport_query_ports(struct qeth_card *card, if (!(card->options.sbp.supported_funcs & IPA_SBP_QUERY_BRIDGE_PORTS)) return -EOPNOTSUPP; iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0); + if (!iob) + return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); cmd->data.sbp.hdr.cmdlength = sizeof(struct qeth_ipacmd_sbp_hdr); @@ -1817,9 +1811,7 @@ int qeth_bridgeport_query_ports(struct qeth_card *card, if (rc) return rc; rc = qeth_bridgeport_makerc(card, &cbctl, IPA_SBP_QUERY_BRIDGE_PORTS); - if (rc) - return rc; - return 0; + return rc; } EXPORT_SYMBOL_GPL(qeth_bridgeport_query_ports); @@ -1873,6 +1865,8 @@ int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role) if (!(card->options.sbp.supported_funcs & setcmd)) return -EOPNOTSUPP; iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0); + if (!iob) + return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); cmd->data.sbp.hdr.cmdlength = cmdlength; cmd->data.sbp.hdr.command_code = setcmd; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 625227ad16ee..04e42c649134 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -432,10 +432,8 @@ void qeth_l3_set_ip_addr_list(struct qeth_card *card) QETH_CARD_TEXT(card, 2, "sdiplist"); QETH_CARD_HEX(card, 2, &card, sizeof(void *)); - if ((card->state != CARD_STATE_UP && - card->state != CARD_STATE_SOFTSETUP) || card->options.sniffer) { + if (!qeth_card_hw_is_reachable(card) || card->options.sniffer) return; - } spin_lock_irqsave(&card->ip_lock, flags); tbd_list = card->ip_tbd_list; @@ -549,6 +547,8 @@ static int qeth_l3_send_setdelmc(struct qeth_card *card, QETH_CARD_TEXT(card, 4, "setdelmc"); iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto); + if (!iob) + return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); memcpy(&cmd->data.setdelipm.mac, addr->mac, OSA_ADDR_LEN); if (addr->proto == QETH_PROT_IPV6) @@ -588,6 +588,8 @@ static int qeth_l3_send_setdelip(struct qeth_card *card, QETH_CARD_TEXT_(card, 4, "flags%02X", flags); iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto); + if (!iob) + return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); if (addr->proto == QETH_PROT_IPV6) { memcpy(cmd->data.setdelip6.ip_addr, &addr->u.a6.addr, @@ -616,6 +618,8 @@ static int qeth_l3_send_setrouting(struct qeth_card *card, QETH_CARD_TEXT(card, 4, "setroutg"); iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETRTG, prot); + if (!iob) + return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); cmd->data.setrtg.type = (type); rc = qeth_send_ipa_cmd(card, iob, NULL, NULL); @@ -1049,12 +1053,14 @@ static struct qeth_cmd_buffer *qeth_l3_get_setassparms_cmd( QETH_CARD_TEXT(card, 4, "getasscm"); iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETASSPARMS, prot); - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); - cmd->data.setassparms.hdr.assist_no = ipa_func; - cmd->data.setassparms.hdr.length = 8 + len; - cmd->data.setassparms.hdr.command_code = cmd_code; - cmd->data.setassparms.hdr.return_code = 0; - cmd->data.setassparms.hdr.seq_no = 0; + if (iob) { + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd->data.setassparms.hdr.assist_no = ipa_func; + cmd->data.setassparms.hdr.length = 8 + len; + cmd->data.setassparms.hdr.command_code = cmd_code; + cmd->data.setassparms.hdr.return_code = 0; + cmd->data.setassparms.hdr.seq_no = 0; + } return iob; } @@ -1090,6 +1096,8 @@ static int qeth_l3_send_simple_setassparms_ipv6(struct qeth_card *card, QETH_CARD_TEXT(card, 4, "simassp6"); iob = qeth_l3_get_setassparms_cmd(card, ipa_func, cmd_code, 0, QETH_PROT_IPV6); + if (!iob) + return -ENOMEM; rc = qeth_l3_send_setassparms(card, iob, 0, 0, qeth_l3_default_setassparms_cb, NULL); return rc; @@ -1108,6 +1116,8 @@ static int qeth_l3_send_simple_setassparms(struct qeth_card *card, length = sizeof(__u32); iob = qeth_l3_get_setassparms_cmd(card, ipa_func, cmd_code, length, QETH_PROT_IPV4); + if (!iob) + return -ENOMEM; rc = qeth_l3_send_setassparms(card, iob, length, data, qeth_l3_default_setassparms_cb, NULL); return rc; @@ -1494,6 +1504,8 @@ static int qeth_l3_iqd_read_initial_mac(struct qeth_card *card) iob = qeth_get_ipacmd_buffer(card, IPA_CMD_CREATE_ADDR, QETH_PROT_IPV6); + if (!iob) + return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); *((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) = card->info.unique_id; @@ -1537,6 +1549,8 @@ static int qeth_l3_get_unique_id(struct qeth_card *card) iob = qeth_get_ipacmd_buffer(card, IPA_CMD_CREATE_ADDR, QETH_PROT_IPV6); + if (!iob) + return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); *((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) = card->info.unique_id; @@ -1611,6 +1625,8 @@ qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd) QETH_DBF_TEXT(SETUP, 2, "diagtrac"); iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); + if (!iob) + return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); cmd->data.diagass.subcmd_len = 16; cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRACE; @@ -2442,6 +2458,8 @@ static int qeth_l3_query_arp_cache_info(struct qeth_card *card, IPA_CMD_ASS_ARP_QUERY_INFO, sizeof(struct qeth_arp_query_data) - sizeof(char), prot); + if (!iob) + return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); cmd->data.setassparms.data.query_arp.request_bits = 0x000F; cmd->data.setassparms.data.query_arp.reply_bits = 0; @@ -2535,6 +2553,8 @@ static int qeth_l3_arp_add_entry(struct qeth_card *card, IPA_CMD_ASS_ARP_ADD_ENTRY, sizeof(struct qeth_arp_cache_entry), QETH_PROT_IPV4); + if (!iob) + return -ENOMEM; rc = qeth_l3_send_setassparms(card, iob, sizeof(struct qeth_arp_cache_entry), (unsigned long) entry, @@ -2574,6 +2594,8 @@ static int qeth_l3_arp_remove_entry(struct qeth_card *card, IPA_CMD_ASS_ARP_REMOVE_ENTRY, 12, QETH_PROT_IPV4); + if (!iob) + return -ENOMEM; rc = qeth_l3_send_setassparms(card, iob, 12, (unsigned long)buf, qeth_l3_default_setassparms_cb, NULL); @@ -2626,8 +2648,7 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if (!card) return -ENODEV; - if ((card->state != CARD_STATE_UP) && - (card->state != CARD_STATE_SOFTSETUP)) + if (!qeth_card_hw_is_reachable(card)) return -ENODEV; switch (cmd) { @@ -2800,12 +2821,12 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, * before we're going to overwrite this location with next hop ip. * v6 uses passthrough, v4 sets the tag in the QDIO header. */ - if (vlan_tx_tag_present(skb)) { + if (skb_vlan_tag_present(skb)) { if ((ipv == 4) || (card->info.type == QETH_CARD_TYPE_IQD)) hdr->hdr.l3.ext_flags = QETH_HDR_EXT_VLAN_FRAME; else hdr->hdr.l3.ext_flags = QETH_HDR_EXT_INCLUDE_VLAN_TAG; - hdr->hdr.l3.vlan_id = vlan_tx_tag_get(skb); + hdr->hdr.l3.vlan_id = skb_vlan_tag_get(skb); } hdr->hdr.l3.length = skb->len - sizeof(struct qeth_hdr); @@ -2986,7 +3007,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_pull(new_skb, ETH_HLEN); } - if (ipv != 4 && vlan_tx_tag_present(new_skb)) { + if (ipv != 4 && skb_vlan_tag_present(new_skb)) { skb_push(new_skb, VLAN_HLEN); skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4); skb_copy_to_linear_data_offset(new_skb, 4, @@ -2995,7 +3016,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) new_skb->data + 12, 4); tag = (u16 *)(new_skb->data + 12); *tag = __constant_htons(ETH_P_8021Q); - *(tag + 1) = htons(vlan_tx_tag_get(new_skb)); + *(tag + 1) = htons(skb_vlan_tag_get(new_skb)); } } @@ -3262,6 +3283,8 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = { static int qeth_l3_setup_netdev(struct qeth_card *card) { + int rc; + if (card->info.type == QETH_CARD_TYPE_OSD || card->info.type == QETH_CARD_TYPE_OSX) { if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) || @@ -3293,7 +3316,9 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) return -ENODEV; card->dev->flags |= IFF_NOARP; card->dev->netdev_ops = &qeth_l3_netdev_ops; - qeth_l3_iqd_read_initial_mac(card); + rc = qeth_l3_iqd_read_initial_mac(card); + if (rc) + return rc; if (card->options.hsuid[0]) memcpy(card->dev->perm_addr, card->options.hsuid, 9); } else @@ -3360,7 +3385,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) recover_flag = card->state; rc = qeth_core_hardsetup_card(card); if (rc) { - QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); + QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc); rc = -ENODEV; goto out_remove; } @@ -3401,7 +3426,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) contin: rc = qeth_l3_setadapter_parms(card); if (rc) - QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); + QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc); if (!card->options.sniffer) { rc = qeth_l3_start_ipassists(card); if (rc) { @@ -3410,10 +3435,10 @@ contin: } rc = qeth_l3_setrouting_v4(card); if (rc) - QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); + QETH_DBF_TEXT_(SETUP, 2, "4err%04x", rc); rc = qeth_l3_setrouting_v6(card); if (rc) - QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); + QETH_DBF_TEXT_(SETUP, 2, "5err%04x", rc); } netif_tx_disable(card->dev); diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index adef5f5de118..386eb7b89b1e 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -57,29 +57,26 @@ static ssize_t qeth_l3_dev_route_store(struct qeth_card *card, const char *buf, size_t count) { enum qeth_routing_types old_route_type = route->type; - char *tmp; int rc = 0; - tmp = strsep((char **) &buf, "\n"); mutex_lock(&card->conf_mutex); - if (!strcmp(tmp, "no_router")) { + if (sysfs_streq(buf, "no_router")) { route->type = NO_ROUTER; - } else if (!strcmp(tmp, "primary_connector")) { + } else if (sysfs_streq(buf, "primary_connector")) { route->type = PRIMARY_CONNECTOR; - } else if (!strcmp(tmp, "secondary_connector")) { + } else if (sysfs_streq(buf, "secondary_connector")) { route->type = SECONDARY_CONNECTOR; - } else if (!strcmp(tmp, "primary_router")) { + } else if (sysfs_streq(buf, "primary_router")) { route->type = PRIMARY_ROUTER; - } else if (!strcmp(tmp, "secondary_router")) { + } else if (sysfs_streq(buf, "secondary_router")) { route->type = SECONDARY_ROUTER; - } else if (!strcmp(tmp, "multicast_router")) { + } else if (sysfs_streq(buf, "multicast_router")) { route->type = MULTICAST_ROUTER; } else { rc = -EINVAL; goto out; } - if (((card->state == CARD_STATE_SOFTSETUP) || - (card->state == CARD_STATE_UP)) && + if (qeth_card_hw_is_reachable(card) && (old_route_type != route->type)) { if (prot == QETH_PROT_IPV4) rc = qeth_l3_setrouting_v4(card); @@ -371,7 +368,6 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev, { struct qeth_card *card = dev_get_drvdata(dev); struct qeth_ipaddr *tmpipa, *t; - char *tmp; int rc = 0; if (!card) @@ -384,10 +380,9 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev, goto out; } - tmp = strsep((char **) &buf, "\n"); - if (!strcmp(tmp, "toggle")) { + if (sysfs_streq(buf, "toggle")) { card->ipato.enabled = (card->ipato.enabled)? 0 : 1; - } else if (!strcmp(tmp, "1")) { + } else if (sysfs_streq(buf, "1")) { card->ipato.enabled = 1; list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) { if ((tmpipa->type == QETH_IP_TYPE_NORMAL) && @@ -396,7 +391,7 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev, QETH_IPA_SETIP_TAKEOVER_FLAG; } - } else if (!strcmp(tmp, "0")) { + } else if (sysfs_streq(buf, "0")) { card->ipato.enabled = 0; list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) { if (tmpipa->set_flags & @@ -431,21 +426,19 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev, const char *buf, size_t count) { struct qeth_card *card = dev_get_drvdata(dev); - char *tmp; int rc = 0; if (!card) return -EINVAL; mutex_lock(&card->conf_mutex); - tmp = strsep((char **) &buf, "\n"); - if (!strcmp(tmp, "toggle")) { + if (sysfs_streq(buf, "toggle")) card->ipato.invert4 = (card->ipato.invert4)? 0 : 1; - } else if (!strcmp(tmp, "1")) { + else if (sysfs_streq(buf, "1")) card->ipato.invert4 = 1; - } else if (!strcmp(tmp, "0")) { + else if (sysfs_streq(buf, "0")) card->ipato.invert4 = 0; - } else + else rc = -EINVAL; mutex_unlock(&card->conf_mutex); return rc ? rc : count; @@ -613,21 +606,19 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct qeth_card *card = dev_get_drvdata(dev); - char *tmp; int rc = 0; if (!card) return -EINVAL; mutex_lock(&card->conf_mutex); - tmp = strsep((char **) &buf, "\n"); - if (!strcmp(tmp, "toggle")) { + if (sysfs_streq(buf, "toggle")) card->ipato.invert6 = (card->ipato.invert6)? 0 : 1; - } else if (!strcmp(tmp, "1")) { + else if (sysfs_streq(buf, "1")) card->ipato.invert6 = 1; - } else if (!strcmp(tmp, "0")) { + else if (sysfs_streq(buf, "0")) card->ipato.invert6 = 0; - } else + else rc = -EINVAL; mutex_unlock(&card->conf_mutex); return rc ? rc : count; diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index cd4129ff7ae4..7600639db4c4 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -608,7 +608,8 @@ static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed) } /* Load rest of compatibility struct */ - strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION)); + strlcpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, + sizeof(tw_dev->tw_compat_info.driver_version)); tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL; tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH; tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD; diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 8d66a6469e29..c7be7bb37209 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -3485,7 +3485,7 @@ static int blogic_show_info(struct seq_file *m, struct Scsi_Host *shost) seq_printf(m, "\n\ Current Driver Queue Depth: %d\n\ Currently Allocated CCBs: %d\n", adapter->drvr_qdepth, adapter->alloc_ccbs); - seq_printf(m, "\n\n\ + seq_puts(m, "\n\n\ DATA TRANSFER STATISTICS\n\ \n\ Target Tagged Queuing Queue Depth Active Attempted Completed\n\ @@ -3500,7 +3500,7 @@ Target Tagged Queuing Queue Depth Active Attempted Completed\n\ seq_printf(m, " %3d %3u %9u %9u\n", adapter->qdepth[tgt], adapter->active_cmds[tgt], tgt_stats[tgt].cmds_tried, tgt_stats[tgt].cmds_complete); } - seq_printf(m, "\n\ + seq_puts(m, "\n\ Target Read Commands Write Commands Total Bytes Read Total Bytes Written\n\ ====== ============= ============== =================== ===================\n"); for (tgt = 0; tgt < adapter->maxdev; tgt++) { @@ -3517,7 +3517,7 @@ Target Read Commands Write Commands Total Bytes Read Total Bytes Written\ else seq_printf(m, " %9u\n", tgt_stats[tgt].byteswritten.units); } - seq_printf(m, "\n\ + seq_puts(m, "\n\ Target Command 0-1KB 1-2KB 2-4KB 4-8KB 8-16KB\n\ ====== ======= ========= ========= ========= ========= =========\n"); for (tgt = 0; tgt < adapter->maxdev; tgt++) { @@ -3533,7 +3533,7 @@ Target Command 0-1KB 1-2KB 2-4KB 4-8KB 8-16KB\n\ tgt_stats[tgt].write_sz_buckets[0], tgt_stats[tgt].write_sz_buckets[1], tgt_stats[tgt].write_sz_buckets[2], tgt_stats[tgt].write_sz_buckets[3], tgt_stats[tgt].write_sz_buckets[4]); } - seq_printf(m, "\n\ + seq_puts(m, "\n\ Target Command 16-32KB 32-64KB 64-128KB 128-256KB 256KB+\n\ ====== ======= ========= ========= ========= ========= =========\n"); for (tgt = 0; tgt < adapter->maxdev; tgt++) { @@ -3549,7 +3549,7 @@ Target Command 16-32KB 32-64KB 64-128KB 128-256KB 256KB+\n\ tgt_stats[tgt].write_sz_buckets[5], tgt_stats[tgt].write_sz_buckets[6], tgt_stats[tgt].write_sz_buckets[7], tgt_stats[tgt].write_sz_buckets[8], tgt_stats[tgt].write_sz_buckets[9]); } - seq_printf(m, "\n\n\ + seq_puts(m, "\n\n\ ERROR RECOVERY STATISTICS\n\ \n\ Command Aborts Bus Device Resets Host Adapter Resets\n\ diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 9c92f415229f..b021bcb88537 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -201,12 +201,12 @@ config SCSI_ENCLOSURE certain enclosure conditions to be reported and is not required. config SCSI_CONSTANTS - bool "Verbose SCSI error reporting (kernel size +=12K)" + bool "Verbose SCSI error reporting (kernel size +=75K)" depends on SCSI help The error messages regarding your SCSI hardware will be easier to understand if you say Y here; it will enlarge your kernel by about - 12 KB. If in doubt, say Y. + 75 KB. If in doubt, say Y. config SCSI_LOGGING bool "SCSI logging facility" diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 58158f11ed7b..dee160a4f163 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -159,15 +159,15 @@ obj-$(CONFIG_SCSI_OSD_INITIATOR) += osd/ # This goes last, so that "real" scsi devices probe earlier obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o - -scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \ +scsi_mod-y += scsi.o hosts.o scsi_ioctl.o \ scsicam.o scsi_error.o scsi_lib.o +scsi_mod-$(CONFIG_SCSI_CONSTANTS) += constants.o scsi_mod-$(CONFIG_SCSI_DMA) += scsi_lib_dma.o scsi_mod-y += scsi_scan.o scsi_sysfs.o scsi_devinfo.o scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o -scsi_mod-y += scsi_trace.o +scsi_mod-y += scsi_trace.o scsi_logging.o scsi_mod-$(CONFIG_PM) += scsi_pm.o hv_storvsc-y := storvsc_drv.o diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 36244d63def2..8981701802ca 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -716,8 +716,6 @@ static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance, } #endif -#undef SPRINTF -#define SPRINTF(args...) seq_printf(m, ## args) static void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m); static @@ -734,19 +732,19 @@ static int __maybe_unused NCR5380_show_info(struct seq_file *m, hostdata = (struct NCR5380_hostdata *) instance->hostdata; #ifdef PSEUDO_DMA - SPRINTF("Highwater I/O busy spin counts: write %d, read %d\n", + seq_printf(m, "Highwater I/O busy spin counts: write %d, read %d\n", hostdata->spin_max_w, hostdata->spin_max_r); #endif spin_lock_irq(instance->host_lock); if (!hostdata->connected) - SPRINTF("scsi%d: no currently connected command\n", instance->host_no); + seq_printf(m, "scsi%d: no currently connected command\n", instance->host_no); else lprint_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected, m); - SPRINTF("scsi%d: issue_queue\n", instance->host_no); + seq_printf(m, "scsi%d: issue_queue\n", instance->host_no); for (ptr = (struct scsi_cmnd *) hostdata->issue_queue; ptr; ptr = (struct scsi_cmnd *) ptr->host_scribble) lprint_Scsi_Cmnd(ptr, m); - SPRINTF("scsi%d: disconnected_queue\n", instance->host_no); + seq_printf(m, "scsi%d: disconnected_queue\n", instance->host_no); for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr; ptr = (struct scsi_cmnd *) ptr->host_scribble) lprint_Scsi_Cmnd(ptr, m); spin_unlock_irq(instance->host_lock); @@ -755,8 +753,8 @@ static int __maybe_unused NCR5380_show_info(struct seq_file *m, static void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m) { - SPRINTF("scsi%d : destination target %d, lun %llu\n", cmd->device->host->host_no, cmd->device->id, cmd->device->lun); - SPRINTF(" command = "); + seq_printf(m, "scsi%d : destination target %d, lun %llu\n", cmd->device->host->host_no, cmd->device->id, cmd->device->lun); + seq_puts(m, " command = "); lprint_command(cmd->cmnd, m); } @@ -765,13 +763,13 @@ static void lprint_command(unsigned char *command, struct seq_file *m) int i, s; lprint_opcode(command[0], m); for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) - SPRINTF("%02x ", command[i]); - SPRINTF("\n"); + seq_printf(m, "%02x ", command[i]); + seq_putc(m, '\n'); } static void lprint_opcode(int opcode, struct seq_file *m) { - SPRINTF("%2d (0x%02x)", opcode, opcode); + seq_printf(m, "%2d (0x%02x)", opcode, opcode); } diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 2c5ce48c8f95..ae95e347f37d 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -2880,7 +2880,7 @@ static void asc_prt_board_devices(struct seq_file *m, struct Scsi_Host *shost) chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; } - seq_printf(m, "Target IDs Detected:"); + seq_puts(m, "Target IDs Detected:"); for (i = 0; i <= ADV_MAX_TID; i++) { if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) seq_printf(m, " %X,", i); @@ -2896,18 +2896,16 @@ static void asc_prt_adv_bios(struct seq_file *m, struct Scsi_Host *shost) struct asc_board *boardp = shost_priv(shost); ushort major, minor, letter; - seq_printf(m, "\nROM BIOS Version: "); + seq_puts(m, "\nROM BIOS Version: "); /* * If the BIOS saved a valid signature, then fill in * the BIOS code segment base address. */ if (boardp->bios_signature != 0x55AA) { - seq_printf(m, "Disabled or Pre-3.1\n"); - seq_printf(m, - "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n"); - seq_printf(m, - "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n"); + seq_puts(m, "Disabled or Pre-3.1\n" + "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n" + "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n"); } else { major = (boardp->bios_version >> 12) & 0xF; minor = (boardp->bios_version >> 8) & 0xF; @@ -2923,10 +2921,8 @@ static void asc_prt_adv_bios(struct seq_file *m, struct Scsi_Host *shost) */ if (major < 3 || (major <= 3 && minor < 1) || (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) { - seq_printf(m, - "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n"); - seq_printf(m, - "ftp://ftp.connectcom.net/pub\n"); + seq_puts(m, "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n" + "ftp://ftp.connectcom.net/pub\n"); } } } @@ -3056,11 +3052,10 @@ static void asc_prt_asc_board_eeprom(struct seq_file *m, struct Scsi_Host *shost == ASC_TRUE) seq_printf(m, " Serial Number: %s\n", serialstr); else if (ep->adapter_info[5] == 0xBB) - seq_printf(m, - " Default Settings Used for EEPROM-less Adapter.\n"); + seq_puts(m, + " Default Settings Used for EEPROM-less Adapter.\n"); else - seq_printf(m, - " Serial Number Signature Not Present.\n"); + seq_puts(m, " Serial Number Signature Not Present.\n"); seq_printf(m, " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", @@ -3070,34 +3065,30 @@ static void asc_prt_asc_board_eeprom(struct seq_file *m, struct Scsi_Host *shost seq_printf(m, " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam); - seq_printf(m, " Target ID: "); + seq_puts(m, " Target ID: "); for (i = 0; i <= ASC_MAX_TID; i++) seq_printf(m, " %d", i); - seq_printf(m, "\n"); - seq_printf(m, " Disconnects: "); + seq_puts(m, "\n Disconnects: "); for (i = 0; i <= ASC_MAX_TID; i++) seq_printf(m, " %c", (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); - seq_printf(m, "\n"); - seq_printf(m, " Command Queuing: "); + seq_puts(m, "\n Command Queuing: "); for (i = 0; i <= ASC_MAX_TID; i++) seq_printf(m, " %c", (ep->use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); - seq_printf(m, "\n"); - seq_printf(m, " Start Motor: "); + seq_puts(m, "\n Start Motor: "); for (i = 0; i <= ASC_MAX_TID; i++) seq_printf(m, " %c", (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); - seq_printf(m, "\n"); - seq_printf(m, " Synchronous Transfer:"); + seq_puts(m, "\n Synchronous Transfer:"); for (i = 0; i <= ASC_MAX_TID; i++) seq_printf(m, " %c", (ep->init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); - seq_printf(m, "\n"); + seq_putc(m, '\n'); #ifdef CONFIG_ISA if (asc_dvc_varp->bus_type & ASC_IS_ISA) { @@ -3151,7 +3142,7 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) seq_printf(m, " Serial Number: %s\n", serialstr); else - seq_printf(m, " Serial Number Signature Not Present.\n"); + seq_puts(m, " Serial Number Signature Not Present.\n"); if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) seq_printf(m, @@ -3209,10 +3200,10 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost ep_38C1600->termination_lvd, termstr, ep_38C1600->bios_ctrl); - seq_printf(m, " Target ID: "); + seq_puts(m, " Target ID: "); for (i = 0; i <= ADV_MAX_TID; i++) seq_printf(m, " %X", i); - seq_printf(m, "\n"); + seq_putc(m, '\n'); if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { word = ep_3550->disc_enable; @@ -3221,11 +3212,11 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost } else { word = ep_38C1600->disc_enable; } - seq_printf(m, " Disconnects: "); + seq_puts(m, " Disconnects: "); for (i = 0; i <= ADV_MAX_TID; i++) seq_printf(m, " %c", (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); - seq_printf(m, "\n"); + seq_putc(m, '\n'); if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { word = ep_3550->tagqng_able; @@ -3234,11 +3225,11 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost } else { word = ep_38C1600->tagqng_able; } - seq_printf(m, " Command Queuing: "); + seq_puts(m, " Command Queuing: "); for (i = 0; i <= ADV_MAX_TID; i++) seq_printf(m, " %c", (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); - seq_printf(m, "\n"); + seq_putc(m, '\n'); if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { word = ep_3550->start_motor; @@ -3247,28 +3238,28 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost } else { word = ep_38C1600->start_motor; } - seq_printf(m, " Start Motor: "); + seq_puts(m, " Start Motor: "); for (i = 0; i <= ADV_MAX_TID; i++) seq_printf(m, " %c", (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); - seq_printf(m, "\n"); + seq_putc(m, '\n'); if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - seq_printf(m, " Synchronous Transfer:"); + seq_puts(m, " Synchronous Transfer:"); for (i = 0; i <= ADV_MAX_TID; i++) seq_printf(m, " %c", (ep_3550->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); - seq_printf(m, "\n"); + seq_putc(m, '\n'); } if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - seq_printf(m, " Ultra Transfer: "); + seq_puts(m, " Ultra Transfer: "); for (i = 0; i <= ADV_MAX_TID; i++) seq_printf(m, " %c", (ep_3550->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); - seq_printf(m, "\n"); + seq_putc(m, '\n'); } if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { @@ -3278,16 +3269,15 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost } else { word = ep_38C1600->wdtr_able; } - seq_printf(m, " Wide Transfer: "); + seq_puts(m, " Wide Transfer: "); for (i = 0; i <= ADV_MAX_TID; i++) seq_printf(m, " %c", (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); - seq_printf(m, "\n"); + seq_putc(m, '\n'); if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 || adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) { - seq_printf(m, - " Synchronous Transfer Speed (Mhz):\n "); + seq_puts(m, " Synchronous Transfer Speed (Mhz):\n "); for (i = 0; i <= ADV_MAX_TID; i++) { char *speed_str; @@ -3325,10 +3315,10 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost } seq_printf(m, "%X:%s ", i, speed_str); if (i == 7) - seq_printf(m, "\n "); + seq_puts(m, "\n "); sdtr_speed >>= 4; } - seq_printf(m, "\n"); + seq_putc(m, '\n'); } } @@ -3403,7 +3393,7 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost) seq_printf(m, " Total Command Pending: %d\n", v->cur_total_qng); - seq_printf(m, " Command Queuing:"); + seq_puts(m, " Command Queuing:"); for (i = 0; i <= ASC_MAX_TID; i++) { if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { @@ -3413,10 +3403,9 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost) i, (v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); } - seq_printf(m, "\n"); /* Current number of commands waiting for a device. */ - seq_printf(m, " Command Queue Pending:"); + seq_puts(m, "\n Command Queue Pending:"); for (i = 0; i <= ASC_MAX_TID; i++) { if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { @@ -3424,10 +3413,9 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost) } seq_printf(m, " %X:%u", i, v->cur_dvc_qng[i]); } - seq_printf(m, "\n"); /* Current limit on number of commands that can be sent to a device. */ - seq_printf(m, " Command Queue Limit:"); + seq_puts(m, "\n Command Queue Limit:"); for (i = 0; i <= ASC_MAX_TID; i++) { if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { @@ -3435,10 +3423,9 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost) } seq_printf(m, " %X:%u", i, v->max_dvc_qng[i]); } - seq_printf(m, "\n"); /* Indicate whether the device has returned queue full status. */ - seq_printf(m, " Command Queue Full:"); + seq_puts(m, "\n Command Queue Full:"); for (i = 0; i <= ASC_MAX_TID; i++) { if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { @@ -3450,9 +3437,8 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost) else seq_printf(m, " %X:N", i); } - seq_printf(m, "\n"); - seq_printf(m, " Synchronous Transfer:"); + seq_puts(m, "\n Synchronous Transfer:"); for (i = 0; i <= ASC_MAX_TID; i++) { if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { @@ -3462,7 +3448,7 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost) i, (v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); } - seq_printf(m, "\n"); + seq_putc(m, '\n'); for (i = 0; i <= ASC_MAX_TID; i++) { uchar syn_period_ix; @@ -3476,7 +3462,7 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost) seq_printf(m, " %X:", i); if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) { - seq_printf(m, " Asynchronous"); + seq_puts(m, " Asynchronous"); } else { syn_period_ix = (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - @@ -3494,16 +3480,15 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost) } if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) { - seq_printf(m, "*\n"); + seq_puts(m, "*\n"); renegotiate = 1; } else { - seq_printf(m, "\n"); + seq_putc(m, '\n'); } } if (renegotiate) { - seq_printf(m, - " * = Re-negotiation pending before next command.\n"); + seq_puts(m, " * = Re-negotiation pending before next command.\n"); } } @@ -3548,7 +3533,7 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost) c->mcode_date, c->mcode_version); AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - seq_printf(m, " Queuing Enabled:"); + seq_puts(m, " Queuing Enabled:"); for (i = 0; i <= ADV_MAX_TID; i++) { if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { @@ -3559,9 +3544,8 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost) i, (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); } - seq_printf(m, "\n"); - seq_printf(m, " Queue Limit:"); + seq_puts(m, "\n Queue Limit:"); for (i = 0; i <= ADV_MAX_TID; i++) { if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { @@ -3573,9 +3557,8 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost) seq_printf(m, " %X:%d", i, lrambyte); } - seq_printf(m, "\n"); - seq_printf(m, " Command Pending:"); + seq_puts(m, "\n Command Pending:"); for (i = 0; i <= ADV_MAX_TID; i++) { if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { @@ -3587,10 +3570,10 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost) seq_printf(m, " %X:%d", i, lrambyte); } - seq_printf(m, "\n"); + seq_putc(m, '\n'); AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - seq_printf(m, " Wide Enabled:"); + seq_puts(m, " Wide Enabled:"); for (i = 0; i <= ADV_MAX_TID; i++) { if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { @@ -3601,10 +3584,10 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost) i, (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); } - seq_printf(m, "\n"); + seq_putc(m, '\n'); AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done); - seq_printf(m, " Transfer Bit Width:"); + seq_puts(m, " Transfer Bit Width:"); for (i = 0; i <= ADV_MAX_TID; i++) { if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { @@ -3620,14 +3603,14 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost) if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) && (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) { - seq_printf(m, "*"); + seq_putc(m, '*'); renegotiate = 1; } } - seq_printf(m, "\n"); + seq_putc(m, '\n'); AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - seq_printf(m, " Synchronous Enabled:"); + seq_puts(m, " Synchronous Enabled:"); for (i = 0; i <= ADV_MAX_TID; i++) { if ((chip_scsi_id == i) || ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { @@ -3638,7 +3621,7 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost) i, (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); } - seq_printf(m, "\n"); + seq_putc(m, '\n'); AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done); for (i = 0; i <= ADV_MAX_TID; i++) { @@ -3657,14 +3640,14 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost) seq_printf(m, " %X:", i); if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */ - seq_printf(m, " Asynchronous"); + seq_puts(m, " Asynchronous"); } else { - seq_printf(m, " Transfer Period Factor: "); + seq_puts(m, " Transfer Period Factor: "); if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */ - seq_printf(m, "9 (80.0 Mhz),"); + seq_puts(m, "9 (80.0 Mhz),"); } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */ - seq_printf(m, "10 (40.0 Mhz),"); + seq_puts(m, "10 (40.0 Mhz),"); } else { /* 20 Mhz or below. */ period = (((lramword >> 8) * 25) + 50) / 4; @@ -3684,16 +3667,15 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost) } if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) { - seq_printf(m, "*\n"); + seq_puts(m, "*\n"); renegotiate = 1; } else { - seq_printf(m, "\n"); + seq_putc(m, '\n'); } } if (renegotiate) { - seq_printf(m, - " * = Re-negotiation pending before next command.\n"); + seq_puts(m, " * = Re-negotiation pending before next command.\n"); } } diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 2b960b326daf..e31c460a1335 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -2490,299 +2490,296 @@ static void show_queues(struct Scsi_Host *shpnt) disp_enintr(shpnt); } -#undef SPRINTF -#define SPRINTF(args...) seq_printf(m, ##args) - static void get_command(struct seq_file *m, Scsi_Cmnd * ptr) { int i; - SPRINTF("%p: target=%d; lun=%d; cmnd=( ", + seq_printf(m, "%p: target=%d; lun=%d; cmnd=( ", ptr, ptr->device->id, (u8)ptr->device->lun); for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++) - SPRINTF("0x%02x ", ptr->cmnd[i]); + seq_printf(m, "0x%02x ", ptr->cmnd[i]); - SPRINTF("); resid=%d; residual=%d; buffers=%d; phase |", + seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |", scsi_get_resid(ptr), ptr->SCp.this_residual, ptr->SCp.buffers_residual); if (ptr->SCp.phase & not_issued) - SPRINTF("not issued|"); + seq_puts(m, "not issued|"); if (ptr->SCp.phase & selecting) - SPRINTF("selecting|"); + seq_puts(m, "selecting|"); if (ptr->SCp.phase & disconnected) - SPRINTF("disconnected|"); + seq_puts(m, "disconnected|"); if (ptr->SCp.phase & aborted) - SPRINTF("aborted|"); + seq_puts(m, "aborted|"); if (ptr->SCp.phase & identified) - SPRINTF("identified|"); + seq_puts(m, "identified|"); if (ptr->SCp.phase & completed) - SPRINTF("completed|"); + seq_puts(m, "completed|"); if (ptr->SCp.phase & spiordy) - SPRINTF("spiordy|"); + seq_puts(m, "spiordy|"); if (ptr->SCp.phase & syncneg) - SPRINTF("syncneg|"); - SPRINTF("; next=0x%p\n", SCNEXT(ptr)); + seq_puts(m, "syncneg|"); + seq_printf(m, "; next=0x%p\n", SCNEXT(ptr)); } static void get_ports(struct seq_file *m, struct Scsi_Host *shpnt) { int s; - SPRINTF("\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name); + seq_printf(m, "\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name); s = GETPORT(SCSISEQ); - SPRINTF("SCSISEQ( "); + seq_puts(m, "SCSISEQ( "); if (s & TEMODEO) - SPRINTF("TARGET MODE "); + seq_puts(m, "TARGET MODE "); if (s & ENSELO) - SPRINTF("SELO "); + seq_puts(m, "SELO "); if (s & ENSELI) - SPRINTF("SELI "); + seq_puts(m, "SELI "); if (s & ENRESELI) - SPRINTF("RESELI "); + seq_puts(m, "RESELI "); if (s & ENAUTOATNO) - SPRINTF("AUTOATNO "); + seq_puts(m, "AUTOATNO "); if (s & ENAUTOATNI) - SPRINTF("AUTOATNI "); + seq_puts(m, "AUTOATNI "); if (s & ENAUTOATNP) - SPRINTF("AUTOATNP "); + seq_puts(m, "AUTOATNP "); if (s & SCSIRSTO) - SPRINTF("SCSIRSTO "); - SPRINTF(");"); + seq_puts(m, "SCSIRSTO "); + seq_puts(m, ");"); - SPRINTF(" SCSISIG("); + seq_puts(m, " SCSISIG("); s = GETPORT(SCSISIG); switch (s & P_MASK) { case P_DATAO: - SPRINTF("DATA OUT"); + seq_puts(m, "DATA OUT"); break; case P_DATAI: - SPRINTF("DATA IN"); + seq_puts(m, "DATA IN"); break; case P_CMD: - SPRINTF("COMMAND"); + seq_puts(m, "COMMAND"); break; case P_STATUS: - SPRINTF("STATUS"); + seq_puts(m, "STATUS"); break; case P_MSGO: - SPRINTF("MESSAGE OUT"); + seq_puts(m, "MESSAGE OUT"); break; case P_MSGI: - SPRINTF("MESSAGE IN"); + seq_puts(m, "MESSAGE IN"); break; default: - SPRINTF("*invalid*"); + seq_puts(m, "*invalid*"); break; } - SPRINTF("); "); + seq_puts(m, "); "); - SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); + seq_printf(m, "INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - SPRINTF("SSTAT( "); + seq_puts(m, "SSTAT( "); s = GETPORT(SSTAT0); if (s & TARGET) - SPRINTF("TARGET "); + seq_puts(m, "TARGET "); if (s & SELDO) - SPRINTF("SELDO "); + seq_puts(m, "SELDO "); if (s & SELDI) - SPRINTF("SELDI "); + seq_puts(m, "SELDI "); if (s & SELINGO) - SPRINTF("SELINGO "); + seq_puts(m, "SELINGO "); if (s & SWRAP) - SPRINTF("SWRAP "); + seq_puts(m, "SWRAP "); if (s & SDONE) - SPRINTF("SDONE "); + seq_puts(m, "SDONE "); if (s & SPIORDY) - SPRINTF("SPIORDY "); + seq_puts(m, "SPIORDY "); if (s & DMADONE) - SPRINTF("DMADONE "); + seq_puts(m, "DMADONE "); s = GETPORT(SSTAT1); if (s & SELTO) - SPRINTF("SELTO "); + seq_puts(m, "SELTO "); if (s & ATNTARG) - SPRINTF("ATNTARG "); + seq_puts(m, "ATNTARG "); if (s & SCSIRSTI) - SPRINTF("SCSIRSTI "); + seq_puts(m, "SCSIRSTI "); if (s & PHASEMIS) - SPRINTF("PHASEMIS "); + seq_puts(m, "PHASEMIS "); if (s & BUSFREE) - SPRINTF("BUSFREE "); + seq_puts(m, "BUSFREE "); if (s & SCSIPERR) - SPRINTF("SCSIPERR "); + seq_puts(m, "SCSIPERR "); if (s & PHASECHG) - SPRINTF("PHASECHG "); + seq_puts(m, "PHASECHG "); if (s & REQINIT) - SPRINTF("REQINIT "); - SPRINTF("); "); + seq_puts(m, "REQINIT "); + seq_puts(m, "); "); - SPRINTF("SSTAT( "); + seq_puts(m, "SSTAT( "); s = GETPORT(SSTAT0) & GETPORT(SIMODE0); if (s & TARGET) - SPRINTF("TARGET "); + seq_puts(m, "TARGET "); if (s & SELDO) - SPRINTF("SELDO "); + seq_puts(m, "SELDO "); if (s & SELDI) - SPRINTF("SELDI "); + seq_puts(m, "SELDI "); if (s & SELINGO) - SPRINTF("SELINGO "); + seq_puts(m, "SELINGO "); if (s & SWRAP) - SPRINTF("SWRAP "); + seq_puts(m, "SWRAP "); if (s & SDONE) - SPRINTF("SDONE "); + seq_puts(m, "SDONE "); if (s & SPIORDY) - SPRINTF("SPIORDY "); + seq_puts(m, "SPIORDY "); if (s & DMADONE) - SPRINTF("DMADONE "); + seq_puts(m, "DMADONE "); s = GETPORT(SSTAT1) & GETPORT(SIMODE1); if (s & SELTO) - SPRINTF("SELTO "); + seq_puts(m, "SELTO "); if (s & ATNTARG) - SPRINTF("ATNTARG "); + seq_puts(m, "ATNTARG "); if (s & SCSIRSTI) - SPRINTF("SCSIRSTI "); + seq_puts(m, "SCSIRSTI "); if (s & PHASEMIS) - SPRINTF("PHASEMIS "); + seq_puts(m, "PHASEMIS "); if (s & BUSFREE) - SPRINTF("BUSFREE "); + seq_puts(m, "BUSFREE "); if (s & SCSIPERR) - SPRINTF("SCSIPERR "); + seq_puts(m, "SCSIPERR "); if (s & PHASECHG) - SPRINTF("PHASECHG "); + seq_puts(m, "PHASECHG "); if (s & REQINIT) - SPRINTF("REQINIT "); - SPRINTF("); "); + seq_puts(m, "REQINIT "); + seq_puts(m, "); "); - SPRINTF("SXFRCTL0( "); + seq_puts(m, "SXFRCTL0( "); s = GETPORT(SXFRCTL0); if (s & SCSIEN) - SPRINTF("SCSIEN "); + seq_puts(m, "SCSIEN "); if (s & DMAEN) - SPRINTF("DMAEN "); + seq_puts(m, "DMAEN "); if (s & CH1) - SPRINTF("CH1 "); + seq_puts(m, "CH1 "); if (s & CLRSTCNT) - SPRINTF("CLRSTCNT "); + seq_puts(m, "CLRSTCNT "); if (s & SPIOEN) - SPRINTF("SPIOEN "); + seq_puts(m, "SPIOEN "); if (s & CLRCH1) - SPRINTF("CLRCH1 "); - SPRINTF("); "); + seq_puts(m, "CLRCH1 "); + seq_puts(m, "); "); - SPRINTF("SIGNAL( "); + seq_puts(m, "SIGNAL( "); s = GETPORT(SCSISIG); if (s & SIG_ATNI) - SPRINTF("ATNI "); + seq_puts(m, "ATNI "); if (s & SIG_SELI) - SPRINTF("SELI "); + seq_puts(m, "SELI "); if (s & SIG_BSYI) - SPRINTF("BSYI "); + seq_puts(m, "BSYI "); if (s & SIG_REQI) - SPRINTF("REQI "); + seq_puts(m, "REQI "); if (s & SIG_ACKI) - SPRINTF("ACKI "); - SPRINTF("); "); + seq_puts(m, "ACKI "); + seq_puts(m, "); "); - SPRINTF("SELID(%02x), ", GETPORT(SELID)); + seq_printf(m, "SELID(%02x), ", GETPORT(SELID)); - SPRINTF("STCNT(%d), ", GETSTCNT()); + seq_printf(m, "STCNT(%d), ", GETSTCNT()); - SPRINTF("SSTAT2( "); + seq_puts(m, "SSTAT2( "); s = GETPORT(SSTAT2); if (s & SOFFSET) - SPRINTF("SOFFSET "); + seq_puts(m, "SOFFSET "); if (s & SEMPTY) - SPRINTF("SEMPTY "); + seq_puts(m, "SEMPTY "); if (s & SFULL) - SPRINTF("SFULL "); - SPRINTF("); SFCNT (%d); ", s & (SFULL | SFCNT)); + seq_puts(m, "SFULL "); + seq_printf(m, "); SFCNT (%d); ", s & (SFULL | SFCNT)); s = GETPORT(SSTAT3); - SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); + seq_printf(m, "SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); - SPRINTF("SSTAT4( "); + seq_puts(m, "SSTAT4( "); s = GETPORT(SSTAT4); if (s & SYNCERR) - SPRINTF("SYNCERR "); + seq_puts(m, "SYNCERR "); if (s & FWERR) - SPRINTF("FWERR "); + seq_puts(m, "FWERR "); if (s & FRERR) - SPRINTF("FRERR "); - SPRINTF("); "); + seq_puts(m, "FRERR "); + seq_puts(m, "); "); - SPRINTF("DMACNTRL0( "); + seq_puts(m, "DMACNTRL0( "); s = GETPORT(DMACNTRL0); - SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT"); - SPRINTF("%s ", s & DMA ? "DMA" : "PIO"); - SPRINTF("%s ", s & WRITE_READ ? "WRITE" : "READ"); + seq_printf(m, "%s ", s & _8BIT ? "8BIT" : "16BIT"); + seq_printf(m, "%s ", s & DMA ? "DMA" : "PIO"); + seq_printf(m, "%s ", s & WRITE_READ ? "WRITE" : "READ"); if (s & ENDMA) - SPRINTF("ENDMA "); + seq_puts(m, "ENDMA "); if (s & INTEN) - SPRINTF("INTEN "); + seq_puts(m, "INTEN "); if (s & RSTFIFO) - SPRINTF("RSTFIFO "); + seq_puts(m, "RSTFIFO "); if (s & SWINT) - SPRINTF("SWINT "); - SPRINTF("); "); + seq_puts(m, "SWINT "); + seq_puts(m, "); "); - SPRINTF("DMASTAT( "); + seq_puts(m, "DMASTAT( "); s = GETPORT(DMASTAT); if (s & ATDONE) - SPRINTF("ATDONE "); + seq_puts(m, "ATDONE "); if (s & WORDRDY) - SPRINTF("WORDRDY "); + seq_puts(m, "WORDRDY "); if (s & DFIFOFULL) - SPRINTF("DFIFOFULL "); + seq_puts(m, "DFIFOFULL "); if (s & DFIFOEMP) - SPRINTF("DFIFOEMP "); - SPRINTF(")\n"); + seq_puts(m, "DFIFOEMP "); + seq_puts(m, ")\n"); - SPRINTF("enabled interrupts( "); + seq_puts(m, "enabled interrupts( "); s = GETPORT(SIMODE0); if (s & ENSELDO) - SPRINTF("ENSELDO "); + seq_puts(m, "ENSELDO "); if (s & ENSELDI) - SPRINTF("ENSELDI "); + seq_puts(m, "ENSELDI "); if (s & ENSELINGO) - SPRINTF("ENSELINGO "); + seq_puts(m, "ENSELINGO "); if (s & ENSWRAP) - SPRINTF("ENSWRAP "); + seq_puts(m, "ENSWRAP "); if (s & ENSDONE) - SPRINTF("ENSDONE "); + seq_puts(m, "ENSDONE "); if (s & ENSPIORDY) - SPRINTF("ENSPIORDY "); + seq_puts(m, "ENSPIORDY "); if (s & ENDMADONE) - SPRINTF("ENDMADONE "); + seq_puts(m, "ENDMADONE "); s = GETPORT(SIMODE1); if (s & ENSELTIMO) - SPRINTF("ENSELTIMO "); + seq_puts(m, "ENSELTIMO "); if (s & ENATNTARG) - SPRINTF("ENATNTARG "); + seq_puts(m, "ENATNTARG "); if (s & ENPHASEMIS) - SPRINTF("ENPHASEMIS "); + seq_puts(m, "ENPHASEMIS "); if (s & ENBUSFREE) - SPRINTF("ENBUSFREE "); + seq_puts(m, "ENBUSFREE "); if (s & ENSCSIPERR) - SPRINTF("ENSCSIPERR "); + seq_puts(m, "ENSCSIPERR "); if (s & ENPHASECHG) - SPRINTF("ENPHASECHG "); + seq_puts(m, "ENPHASECHG "); if (s & ENREQINIT) - SPRINTF("ENREQINIT "); - SPRINTF(")\n"); + seq_puts(m, "ENREQINIT "); + seq_puts(m, ")\n"); } static int aha152x_set_info(struct Scsi_Host *shpnt, char *buffer, int length) @@ -2825,56 +2822,56 @@ static int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt) Scsi_Cmnd *ptr; unsigned long flags; - SPRINTF(AHA152X_REVID "\n"); + seq_puts(m, AHA152X_REVID "\n"); - SPRINTF("ioports 0x%04lx to 0x%04lx\n", + seq_printf(m, "ioports 0x%04lx to 0x%04lx\n", shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1); - SPRINTF("interrupt 0x%02x\n", shpnt->irq); - SPRINTF("disconnection/reconnection %s\n", + seq_printf(m, "interrupt 0x%02x\n", shpnt->irq); + seq_printf(m, "disconnection/reconnection %s\n", RECONNECT ? "enabled" : "disabled"); - SPRINTF("parity checking %s\n", + seq_printf(m, "parity checking %s\n", PARITY ? "enabled" : "disabled"); - SPRINTF("synchronous transfers %s\n", + seq_printf(m, "synchronous transfers %s\n", SYNCHRONOUS ? "enabled" : "disabled"); - SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands); + seq_printf(m, "%d commands currently queued\n", HOSTDATA(shpnt)->commands); if(SYNCHRONOUS) { - SPRINTF("synchronously operating targets (tick=50 ns):\n"); + seq_puts(m, "synchronously operating targets (tick=50 ns):\n"); for (i = 0; i < 8; i++) if (HOSTDATA(shpnt)->syncrate[i] & 0x7f) - SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n", + seq_printf(m, "target %d: period %dT/%dns; req/ack offset %d\n", i, (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2), (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50, HOSTDATA(shpnt)->syncrate[i] & 0x0f); } - SPRINTF("\nqueue status:\n"); + seq_puts(m, "\nqueue status:\n"); DO_LOCK(flags); if (ISSUE_SC) { - SPRINTF("not yet issued commands:\n"); + seq_puts(m, "not yet issued commands:\n"); for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr)) get_command(m, ptr); } else - SPRINTF("no not yet issued commands\n"); + seq_puts(m, "no not yet issued commands\n"); DO_UNLOCK(flags); if (CURRENT_SC) { - SPRINTF("current command:\n"); + seq_puts(m, "current command:\n"); get_command(m, CURRENT_SC); } else - SPRINTF("no current command\n"); + seq_puts(m, "no current command\n"); if (DISCONNECTED_SC) { - SPRINTF("disconnected commands:\n"); + seq_puts(m, "disconnected commands:\n"); for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr)) get_command(m, ptr); } else - SPRINTF("no disconnected commands\n"); + seq_puts(m, "no disconnected commands\n"); get_ports(m, shpnt); #if defined(AHA152X_STAT) - SPRINTF("statistics:\n" + seq_printf(m, "statistics:\n" "total commands: %d\n" "disconnections: %d\n" "busfree with check condition: %d\n" @@ -2894,7 +2891,7 @@ static int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt) HOSTDATA(shpnt)->busfree_without_done_command, HOSTDATA(shpnt)->busfree_without_any_action); for(i=0; icount_trans[i], HOSTDATA(shpnt)->count[i], diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 0bcacf71aef8..97f2accd3dbb 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -1298,7 +1298,7 @@ rescan_fifos: /* * Wait for any inprogress DMA to complete and clear DMA state - * if this if for an SCB in the qinfifo. + * if this is for an SCB in the qinfifo. */ while (((ccscbctl = ahd_inb(ahd, CCSCBCTL)) & (CCARREN|CCSCBEN)) != 0) { diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index 27dbfccea774..add2da581d66 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -97,7 +97,7 @@ ahd_format_transinfo(struct seq_file *m, struct ahd_transinfo *tinfo) u_int mb; if (tinfo->period == AHD_PERIOD_UNKNOWN) { - seq_printf(m, "Renegotiation Pending\n"); + seq_puts(m, "Renegotiation Pending\n"); return; } speed = 3300; @@ -119,40 +119,38 @@ ahd_format_transinfo(struct seq_file *m, struct ahd_transinfo *tinfo) printed_options = 0; seq_printf(m, " (%d.%03dMHz", freq / 1000, freq % 1000); if ((tinfo->ppr_options & MSG_EXT_PPR_RD_STRM) != 0) { - seq_printf(m, " RDSTRM"); + seq_puts(m, " RDSTRM"); printed_options++; } if ((tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0) { - seq_printf(m, "%s", printed_options ? "|DT" : " DT"); + seq_puts(m, printed_options ? "|DT" : " DT"); printed_options++; } if ((tinfo->ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - seq_printf(m, "%s", printed_options ? "|IU" : " IU"); + seq_puts(m, printed_options ? "|IU" : " IU"); printed_options++; } if ((tinfo->ppr_options & MSG_EXT_PPR_RTI) != 0) { - seq_printf(m, "%s", - printed_options ? "|RTI" : " RTI"); + seq_puts(m, printed_options ? "|RTI" : " RTI"); printed_options++; } if ((tinfo->ppr_options & MSG_EXT_PPR_QAS_REQ) != 0) { - seq_printf(m, "%s", - printed_options ? "|QAS" : " QAS"); + seq_puts(m, printed_options ? "|QAS" : " QAS"); printed_options++; } } if (tinfo->width > 0) { if (freq != 0) { - seq_printf(m, ", "); + seq_puts(m, ", "); } else { - seq_printf(m, " ("); + seq_puts(m, " ("); } seq_printf(m, "%dbit)", 8 * (0x01 << tinfo->width)); } else if (freq != 0) { - seq_printf(m, ")"); + seq_putc(m, ')'); } - seq_printf(m, "\n"); + seq_putc(m, '\n'); } static void @@ -167,15 +165,15 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct seq_file *m, tinfo = ahd_fetch_transinfo(ahd, channel, our_id, target_id, &tstate); seq_printf(m, "Target %d Negotiation Settings\n", target_id); - seq_printf(m, "\tUser: "); + seq_puts(m, "\tUser: "); ahd_format_transinfo(m, &tinfo->user); starget = ahd->platform_data->starget[target_id]; if (starget == NULL) return; - seq_printf(m, "\tGoal: "); + seq_puts(m, "\tGoal: "); ahd_format_transinfo(m, &tinfo->goal); - seq_printf(m, "\tCurr: "); + seq_puts(m, "\tCurr: "); ahd_format_transinfo(m, &tinfo->curr); for (lun = 0; lun < AHD_NUM_LUNS; lun++) { @@ -291,19 +289,19 @@ ahd_linux_show_info(struct seq_file *m, struct Scsi_Host *shost) max_targ = 16; if (ahd->seep_config == NULL) - seq_printf(m, "No Serial EEPROM\n"); + seq_puts(m, "No Serial EEPROM\n"); else { - seq_printf(m, "Serial EEPROM:\n"); + seq_puts(m, "Serial EEPROM:\n"); for (i = 0; i < sizeof(*ahd->seep_config)/2; i++) { if (((i % 8) == 0) && (i != 0)) { - seq_printf(m, "\n"); + seq_putc(m, '\n'); } seq_printf(m, "0x%.4x ", ((uint16_t*)ahd->seep_config)[i]); } - seq_printf(m, "\n"); + seq_putc(m, '\n'); } - seq_printf(m, "\n"); + seq_putc(m, '\n'); if ((ahd->features & AHD_WIDE) == 0) max_targ = 8; diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c index 64eec6c07a83..18459605d991 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_proc.c +++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c @@ -119,15 +119,15 @@ ahc_format_transinfo(struct seq_file *m, struct ahc_transinfo *tinfo) if (tinfo->width > 0) { if (freq != 0) { - seq_printf(m, ", "); + seq_puts(m, ", "); } else { - seq_printf(m, " ("); + seq_puts(m, " ("); } seq_printf(m, "%dbit)", 8 * (0x01 << tinfo->width)); } else if (freq != 0) { - seq_printf(m, ")"); + seq_putc(m, ')'); } - seq_printf(m, "\n"); + seq_putc(m, '\n'); } static void @@ -145,15 +145,15 @@ ahc_dump_target_state(struct ahc_softc *ahc, struct seq_file *m, if ((ahc->features & AHC_TWIN) != 0) seq_printf(m, "Channel %c ", channel); seq_printf(m, "Target %d Negotiation Settings\n", target_id); - seq_printf(m, "\tUser: "); + seq_puts(m, "\tUser: "); ahc_format_transinfo(m, &tinfo->user); starget = ahc->platform_data->starget[target_offset]; if (!starget) return; - seq_printf(m, "\tGoal: "); + seq_puts(m, "\tGoal: "); ahc_format_transinfo(m, &tinfo->goal); - seq_printf(m, "\tCurr: "); + seq_puts(m, "\tCurr: "); ahc_format_transinfo(m, &tinfo->curr); for (lun = 0; lun < AHC_NUM_LUNS; lun++) { @@ -303,19 +303,19 @@ ahc_linux_show_info(struct seq_file *m, struct Scsi_Host *shost) if (ahc->seep_config == NULL) - seq_printf(m, "No Serial EEPROM\n"); + seq_puts(m, "No Serial EEPROM\n"); else { - seq_printf(m, "Serial EEPROM:\n"); + seq_puts(m, "Serial EEPROM:\n"); for (i = 0; i < sizeof(*ahc->seep_config)/2; i++) { if (((i % 8) == 0) && (i != 0)) { - seq_printf(m, "\n"); + seq_putc(m, '\n'); } seq_printf(m, "0x%.4x ", ((uint16_t*)ahc->seep_config)[i]); } - seq_printf(m, "\n"); + seq_putc(m, '\n'); } - seq_printf(m, "\n"); + seq_putc(m, '\n'); max_targ = 16; if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0) diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index e64c3af7c1a0..decdc71b6b86 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -2990,7 +2990,7 @@ void fas216_print_devices(FAS216_Info *info, struct seq_file *m) struct fas216_device *dev; struct scsi_device *scd; - seq_printf(m, "Device/Lun TaggedQ Parity Sync\n"); + seq_puts(m, "Device/Lun TaggedQ Parity Sync\n"); shost_for_each_device(scd, info->host) { dev = &info->device[scd->id]; @@ -3000,7 +3000,7 @@ void fas216_print_devices(FAS216_Info *info, struct seq_file *m) scd->simple_tags ? "en" : "dis", scd->current_tag); else - seq_printf(m, "unsupported "); + seq_puts(m, "unsupported "); seq_printf(m, "%3sabled ", dev->parity_enabled ? "en" : "dis"); @@ -3008,7 +3008,7 @@ void fas216_print_devices(FAS216_Info *info, struct seq_file *m) seq_printf(m, "offset %d, %d ns\n", dev->sof, dev->period * 4); else - seq_printf(m, "async\n"); + seq_puts(m, "async\n"); } } diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index 6daed6b386d4..a70255413e7f 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -711,12 +711,12 @@ static void show_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m) unsigned char *command; seq_printf(m, "scsi%d: destination target %d, lun %llu\n", H_NO(cmd), cmd->device->id, cmd->device->lun); - seq_printf(m, " command = "); + seq_puts(m, " command = "); command = cmd->cmnd; seq_printf(m, "%2d (0x%02x)", command[0], command[0]); for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) seq_printf(m, " %02x", command[i]); - seq_printf(m, "\n"); + seq_putc(m, '\n'); } static int __maybe_unused NCR5380_show_info(struct seq_file *m, diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index a795d81ef875..0836433e3a2d 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -3101,9 +3101,8 @@ static const char *atp870u_info(struct Scsi_Host *notused) static int atp870u_show_info(struct seq_file *m, struct Scsi_Host *HBAptr) { - seq_printf(m, "ACARD AEC-671X Driver Version: 2.6+ac\n"); - seq_printf(m, "\n"); - seq_printf(m, "Adapter Configuration:\n"); + seq_puts(m, "ACARD AEC-671X Driver Version: 2.6+ac\n\n" + "Adapter Configuration:\n"); seq_printf(m, " Base IO: %#.4lx\n", HBAptr->io_port); seq_printf(m, " IRQ: %d\n", HBAptr->irq); return 0; diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 6bac8a746ee2..0045742fab7d 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -194,16 +194,10 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, int cmd_len, retry: errno = 0; - if (debug) { - DPRINTK("command: "); - __scsi_print_command(cmd, cmd_len); - } - result = scsi_execute_req(ch->device, cmd, direction, buffer, buflength, &sshdr, timeout * HZ, MAX_RETRIES, NULL); - DPRINTK("result: 0x%x\n",result); if (driver_byte(result) & DRIVER_SENSE) { if (debug) scsi_print_sense_hdr(ch->device, ch->name, &sshdr); diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index e2068a2621c4..fa09d4be2b53 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -18,14 +18,10 @@ #include #include - - /* Commands with service actions that change the command name */ #define THIRD_PARTY_COPY_OUT 0x83 #define THIRD_PARTY_COPY_IN 0x84 -#define VENDOR_SPECIFIC_CDB 0xc0 - struct sa_name_list { int opcode; const struct value_name_pair *arr; @@ -37,7 +33,6 @@ struct value_name_pair { const char * name; }; -#ifdef CONFIG_SCSI_CONSTANTS static const char * cdb_byte0_names[] = { /* 00-03 */ "Test Unit Ready", "Rezero Unit/Rewind", NULL, "Request Sense", /* 04-07 */ "Format Unit/Medium", "Read Block Limits", NULL, @@ -261,28 +256,8 @@ static struct sa_name_list sa_names_arr[] = { {0, NULL, 0}, }; -#else /* ifndef CONFIG_SCSI_CONSTANTS */ -static const char *cdb_byte0_names[0]; - -static struct sa_name_list sa_names_arr[] = { - {VARIABLE_LENGTH_CMD, NULL, 0}, - {MAINTENANCE_IN, NULL, 0}, - {MAINTENANCE_OUT, NULL, 0}, - {PERSISTENT_RESERVE_IN, NULL, 0}, - {PERSISTENT_RESERVE_OUT, NULL, 0}, - {SERVICE_ACTION_IN_12, NULL, 0}, - {SERVICE_ACTION_OUT_12, NULL, 0}, - {SERVICE_ACTION_BIDIRECTIONAL, NULL, 0}, - {SERVICE_ACTION_IN_16, NULL, 0}, - {SERVICE_ACTION_OUT_16, NULL, 0}, - {THIRD_PARTY_COPY_IN, NULL, 0}, - {THIRD_PARTY_COPY_OUT, NULL, 0}, - {0, NULL, 0}, -}; -#endif /* CONFIG_SCSI_CONSTANTS */ - -static bool scsi_opcode_sa_name(int opcode, int service_action, - const char **cdb_name, const char **sa_name) +bool scsi_opcode_sa_name(int opcode, int service_action, + const char **cdb_name, const char **sa_name) { struct sa_name_list *sa_name_ptr; const struct value_name_pair *arr = NULL; @@ -315,76 +290,6 @@ static bool scsi_opcode_sa_name(int opcode, int service_action, return true; } -static void print_opcode_name(const unsigned char *cdbp, size_t cdb_len) -{ - int sa, cdb0; - const char *cdb_name = NULL, *sa_name = NULL; - - cdb0 = cdbp[0]; - if (cdb0 == VARIABLE_LENGTH_CMD) { - if (cdb_len < 10) { - printk("short variable length command, len=%zu", - cdb_len); - return; - } - sa = (cdbp[8] << 8) + cdbp[9]; - } else - sa = cdbp[1] & 0x1f; - - if (!scsi_opcode_sa_name(cdb0, sa, &cdb_name, &sa_name)) { - if (cdb_name) - printk("%s", cdb_name); - else if (cdb0 >= VENDOR_SPECIFIC_CDB) - printk("cdb[0]=0x%x (vendor)", cdb0); - else if (cdb0 >= 0x60 && cdb0 < 0x7e) - printk("cdb[0]=0x%x (reserved)", cdb0); - else - printk("cdb[0]=0x%x", cdb0); - } else { - if (sa_name) - printk("%s", sa_name); - else if (cdb_name) - printk("%s, sa=0x%x", cdb_name, sa); - else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); - } -} - -void __scsi_print_command(const unsigned char *cdb, size_t cdb_len) -{ - int k, len; - - print_opcode_name(cdb, cdb_len); - len = scsi_command_size(cdb); - if (cdb_len < len) - len = cdb_len; - /* print out all bytes in cdb */ - for (k = 0; k < len; ++k) - printk(" %02x", cdb[k]); - printk("\n"); -} -EXPORT_SYMBOL(__scsi_print_command); - -void scsi_print_command(struct scsi_cmnd *cmd) -{ - int k; - - if (cmd->cmnd == NULL) - return; - - scmd_printk(KERN_INFO, cmd, "CDB: "); - print_opcode_name(cmd->cmnd, cmd->cmd_len); - - /* print out all bytes in cdb */ - printk(":"); - for (k = 0; k < cmd->cmd_len; ++k) - printk(" %02x", cmd->cmnd[k]); - printk("\n"); -} -EXPORT_SYMBOL(scsi_print_command); - -#ifdef CONFIG_SCSI_CONSTANTS - struct error_info { unsigned short code12; /* 0x0302 looks better than 0x03,0x02 */ const char * text; @@ -392,7 +297,7 @@ struct error_info { /* * The canonical list of T10 Additional Sense Codes is available at: - * http://www.t10.org/lists/asc-num.txt [most recent: 20130605] + * http://www.t10.org/lists/asc-num.txt [most recent: 20141221] */ static const struct error_info additional[] = @@ -421,6 +326,7 @@ static const struct error_info additional[] = {0x001E, "Conflicting SA creation request"}, {0x001F, "Logical unit transitioning to another power condition"}, {0x0020, "Extended copy information available"}, + {0x0021, "Atomic command aborted due to ACA"}, {0x0100, "No index/sector signal"}, @@ -446,6 +352,7 @@ static const struct error_info additional[] = {0x040C, "Logical unit not accessible, target port in unavailable " "state"}, {0x040D, "Logical unit not ready, structure check required"}, + {0x040E, "Logical unit not ready, security session in progress"}, {0x0410, "Logical unit not ready, auxiliary memory not accessible"}, {0x0411, "Logical unit not ready, notify (enable spinup) required"}, {0x0412, "Logical unit not ready, offline"}, @@ -462,6 +369,11 @@ static const struct error_info additional[] = {0x041C, "Logical unit not ready, additional power use not yet " "granted"}, {0x041D, "Logical unit not ready, configuration in progress"}, + {0x041E, "Logical unit not ready, microcode activation required"}, + {0x041F, "Logical unit not ready, microcode download required"}, + {0x0420, "Logical unit not ready, logical unit reset required"}, + {0x0421, "Logical unit not ready, hard reset required"}, + {0x0422, "Logical unit not ready, power cycle required"}, {0x0500, "Logical unit does not respond to selection"}, @@ -480,6 +392,7 @@ static const struct error_info additional[] = {0x0902, "Focus servo failure"}, {0x0903, "Spindle servo failure"}, {0x0904, "Head select fault"}, + {0x0905, "Vibration induced tracking error"}, {0x0A00, "Error log overflow"}, @@ -510,6 +423,7 @@ static const struct error_info additional[] = {0x0C0D, "Write error - not enough unsolicited data"}, {0x0C0E, "Multiple write errors"}, {0x0C0F, "Defects in error window"}, + {0x0C10, "Incomplete multiple atomic write operations"}, {0x0D00, "Error detected by third party temporary initiator"}, {0x0D01, "Third party device failure"}, @@ -635,6 +549,10 @@ static const struct error_info additional[] = {0x2101, "Invalid element address"}, {0x2102, "Invalid address for write"}, {0x2103, "Invalid write crossing layer jump"}, + {0x2104, "Unaligned write command"}, + {0x2105, "Write boundary violation"}, + {0x2106, "Attempt to read invalid data"}, + {0x2107, "Read boundary violation"}, {0x2200, "Illegal function (use 20 00, 24 00, or 26 00)"}, @@ -691,6 +609,7 @@ static const struct error_info additional[] = {0x2705, "Permanent write protect"}, {0x2706, "Conditional write protect"}, {0x2707, "Space allocation failed write protect"}, + {0x2708, "Zone is read only"}, {0x2800, "Not ready to ready change, medium may have changed"}, {0x2801, "Import or export element accessed"}, @@ -743,10 +662,15 @@ static const struct error_info additional[] = {0x2C0A, "Partition or collection contains user objects"}, {0x2C0B, "Not reserved"}, {0x2C0C, "Orwrite generation does not match"}, + {0x2C0D, "Reset write pointer not allowed"}, + {0x2C0E, "Zone is offline"}, {0x2D00, "Overwrite error on update in place"}, {0x2E00, "Insufficient time for operation"}, + {0x2E01, "Command timeout before processing"}, + {0x2E02, "Command timeout during processing"}, + {0x2E03, "Command timeout during processing due to error recovery"}, {0x2F00, "Commands cleared by another initiator"}, {0x2F01, "Commands cleared by power loss notification"}, @@ -868,6 +792,7 @@ static const struct error_info additional[] = {0x3F13, "iSCSI IP address removed"}, {0x3F14, "iSCSI IP address changed"}, {0x3F15, "Inspect referrals sense descriptors"}, + {0x3F16, "Microcode has been changed without reset"}, /* * {0x40NN, "Ram failure"}, * {0x40NN, "Diagnostic failure on component nn"}, @@ -946,6 +871,11 @@ static const struct error_info additional[] = {0x5306, "Volume identifier missing"}, {0x5307, "Duplicate volume identifier"}, {0x5308, "Element status unknown"}, + {0x5309, "Data transfer device error - load failed"}, + {0x530a, "Data transfer device error - unload failed"}, + {0x530b, "Data transfer device error - unload missing"}, + {0x530c, "Data transfer device error - eject failed"}, + {0x530d, "Data transfer device error - library communication failed"}, {0x5400, "Scsi to host system interface failure"}, @@ -963,6 +893,7 @@ static const struct error_info additional[] = {0x550B, "Insufficient power for operation"}, {0x550C, "Insufficient resources to create rod"}, {0x550D, "Insufficient resources to create rod token"}, + {0x550E, "Insufficient zone resources"}, {0x5700, "Unable to recover table-of-contents"}, @@ -1247,15 +1178,12 @@ static const char * const snstext[] = { "Completed", /* F: command completed sense data reported, may occur for successful command */ }; -#endif /* Get sense key string or NULL if not available */ const char * scsi_sense_key_string(unsigned char key) { -#ifdef CONFIG_SCSI_CONSTANTS if (key <= 0xE) return snstext[key]; -#endif return NULL; } EXPORT_SYMBOL(scsi_sense_key_string); @@ -1267,7 +1195,6 @@ EXPORT_SYMBOL(scsi_sense_key_string); const char * scsi_extd_sense_format(unsigned char asc, unsigned char ascq, const char **fmt) { -#ifdef CONFIG_SCSI_CONSTANTS int i; unsigned short code = ((asc << 8) | ascq); @@ -1283,122 +1210,10 @@ scsi_extd_sense_format(unsigned char asc, unsigned char ascq, const char **fmt) return additional2[i].str; } } -#else - *fmt = NULL; -#endif return NULL; } EXPORT_SYMBOL(scsi_extd_sense_format); -void -scsi_show_extd_sense(const struct scsi_device *sdev, const char *name, - unsigned char asc, unsigned char ascq) -{ - const char *extd_sense_fmt = NULL; - const char *extd_sense_str = scsi_extd_sense_format(asc, ascq, - &extd_sense_fmt); - - if (extd_sense_str) { - if (extd_sense_fmt) - sdev_prefix_printk(KERN_INFO, sdev, name, - "Add. Sense: %s (%s%x)", - extd_sense_str, extd_sense_fmt, - ascq); - else - sdev_prefix_printk(KERN_INFO, sdev, name, - "Add. Sense: %s", extd_sense_str); - - } else { - sdev_prefix_printk(KERN_INFO, sdev, name, - "%sASC=0x%x %sASCQ=0x%x\n", - asc >= 0x80 ? "<> " : "", asc, - ascq >= 0x80 ? "<> " : "", ascq); - } -} -EXPORT_SYMBOL(scsi_show_extd_sense); - -void -scsi_show_sense_hdr(const struct scsi_device *sdev, const char *name, - const struct scsi_sense_hdr *sshdr) -{ - const char *sense_txt; - - sense_txt = scsi_sense_key_string(sshdr->sense_key); - if (sense_txt) - sdev_prefix_printk(KERN_INFO, sdev, name, - "Sense Key : %s [%s]%s\n", sense_txt, - scsi_sense_is_deferred(sshdr) ? - "deferred" : "current", - sshdr->response_code >= 0x72 ? - " [descriptor]" : ""); - else - sdev_prefix_printk(KERN_INFO, sdev, name, - "Sense Key : 0x%x [%s]%s", sshdr->sense_key, - scsi_sense_is_deferred(sshdr) ? - "deferred" : "current", - sshdr->response_code >= 0x72 ? - " [descriptor]" : ""); -} -EXPORT_SYMBOL(scsi_show_sense_hdr); - -/* - * Print normalized SCSI sense header with a prefix. - */ -void -scsi_print_sense_hdr(const struct scsi_device *sdev, const char *name, - const struct scsi_sense_hdr *sshdr) -{ - scsi_show_sense_hdr(sdev, name, sshdr); - scsi_show_extd_sense(sdev, name, sshdr->asc, sshdr->ascq); -} -EXPORT_SYMBOL(scsi_print_sense_hdr); - -static void -scsi_dump_sense_buffer(const unsigned char *sense_buffer, int sense_len) -{ - int k, num; - - num = (sense_len < 32) ? sense_len : 32; - printk("Unrecognized sense data (in hex):"); - for (k = 0; k < num; ++k) { - if (0 == (k % 16)) { - printk("\n"); - printk(KERN_INFO " "); - } - printk("%02x ", sense_buffer[k]); - } - printk("\n"); - return; -} - -/* Normalize and print sense buffer with name prefix */ -void __scsi_print_sense(const struct scsi_device *sdev, const char *name, - const unsigned char *sense_buffer, int sense_len) -{ - struct scsi_sense_hdr sshdr; - - if (!scsi_normalize_sense(sense_buffer, sense_len, &sshdr)) { - scsi_dump_sense_buffer(sense_buffer, sense_len); - return; - } - scsi_show_sense_hdr(sdev, name, &sshdr); - scsi_show_extd_sense(sdev, name, sshdr.asc, sshdr.ascq); -} -EXPORT_SYMBOL(__scsi_print_sense); - -/* Normalize and print sense buffer in SCSI command */ -void scsi_print_sense(const struct scsi_cmnd *cmd) -{ - struct gendisk *disk = cmd->request->rq_disk; - const char *disk_name = disk ? disk->disk_name : NULL; - - __scsi_print_sense(cmd->device, disk_name, cmd->sense_buffer, - SCSI_SENSE_BUFFERSIZE); -} -EXPORT_SYMBOL(scsi_print_sense); - -#ifdef CONFIG_SCSI_CONSTANTS - static const char * const hostbyte_table[]={ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", @@ -1410,17 +1225,13 @@ static const char * const driverbyte_table[]={ "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"}; -#endif - const char *scsi_hostbyte_string(int result) { const char *hb_string = NULL; -#ifdef CONFIG_SCSI_CONSTANTS int hb = host_byte(result); if (hb < ARRAY_SIZE(hostbyte_table)) hb_string = hostbyte_table[hb]; -#endif return hb_string; } EXPORT_SYMBOL(scsi_hostbyte_string); @@ -1428,17 +1239,14 @@ EXPORT_SYMBOL(scsi_hostbyte_string); const char *scsi_driverbyte_string(int result) { const char *db_string = NULL; -#ifdef CONFIG_SCSI_CONSTANTS int db = driver_byte(result); if (db < ARRAY_SIZE(driverbyte_table)) db_string = driverbyte_table[db]; -#endif return db_string; } EXPORT_SYMBOL(scsi_driverbyte_string); -#ifdef CONFIG_SCSI_CONSTANTS #define scsi_mlreturn_name(result) { result, #result } static const struct value_name_pair scsi_mlreturn_arr[] = { scsi_mlreturn_name(NEEDS_RETRY), @@ -1451,11 +1259,9 @@ static const struct value_name_pair scsi_mlreturn_arr[] = { scsi_mlreturn_name(SCSI_RETURN_NOT_HANDLED), scsi_mlreturn_name(FAST_IO_FAIL) }; -#endif const char *scsi_mlreturn_string(int result) { -#ifdef CONFIG_SCSI_CONSTANTS const struct value_name_pair *arr = scsi_mlreturn_arr; int k; @@ -1463,29 +1269,6 @@ const char *scsi_mlreturn_string(int result) if (result == arr->value) return arr->name; } -#endif return NULL; } EXPORT_SYMBOL(scsi_mlreturn_string); - -void scsi_print_result(struct scsi_cmnd *cmd, const char *msg, int disposition) -{ - const char *mlret_string = scsi_mlreturn_string(disposition); - const char *hb_string = scsi_hostbyte_string(cmd->result); - const char *db_string = scsi_driverbyte_string(cmd->result); - - if (hb_string || db_string) - scmd_printk(KERN_INFO, cmd, - "%s%s Result: hostbyte=%s driverbyte=%s", - msg ? msg : "", - mlret_string ? mlret_string : "UNKNOWN", - hb_string ? hb_string : "invalid", - db_string ? db_string : "invalid"); - else - scmd_printk(KERN_INFO, cmd, - "%s%s Result: hostbyte=0x%02x driverbyte=0x%02x", - msg ? msg : "", - mlret_string ? mlret_string : "UNKNOWN", - host_byte(cmd->result), driver_byte(cmd->result)); -} -EXPORT_SYMBOL(scsi_print_result); diff --git a/drivers/scsi/csiostor/Makefile b/drivers/scsi/csiostor/Makefile index 913b9a92fb06..3681a3fbd499 100644 --- a/drivers/scsi/csiostor/Makefile +++ b/drivers/scsi/csiostor/Makefile @@ -8,5 +8,5 @@ ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4 obj-$(CONFIG_SCSI_CHELSIO_FCOE) += csiostor.o csiostor-objs := csio_attr.o csio_init.o csio_lnode.o csio_scsi.o \ - csio_hw.o csio_hw_t4.o csio_hw_t5.o csio_isr.o \ + csio_hw.o csio_hw_t5.o csio_isr.o \ csio_mb.o csio_rnode.o csio_wr.o diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c index 9ab997e18b20..2e66f34ebb79 100644 --- a/drivers/scsi/csiostor/csio_hw.c +++ b/drivers/scsi/csiostor/csio_hw.c @@ -60,37 +60,10 @@ int csio_msi = 2; static int dev_num; /* FCoE Adapter types & its description */ -static const struct csio_adap_desc csio_t4_fcoe_adapters[] = { - {"T440-Dbg 10G", "Chelsio T440-Dbg 10G [FCoE]"}, - {"T420-CR 10G", "Chelsio T420-CR 10G [FCoE]"}, - {"T422-CR 10G/1G", "Chelsio T422-CR 10G/1G [FCoE]"}, - {"T440-CR 10G", "Chelsio T440-CR 10G [FCoE]"}, - {"T420-BCH 10G", "Chelsio T420-BCH 10G [FCoE]"}, - {"T440-BCH 10G", "Chelsio T440-BCH 10G [FCoE]"}, - {"T440-CH 10G", "Chelsio T440-CH 10G [FCoE]"}, - {"T420-SO 10G", "Chelsio T420-SO 10G [FCoE]"}, - {"T420-CX4 10G", "Chelsio T420-CX4 10G [FCoE]"}, - {"T420-BT 10G", "Chelsio T420-BT 10G [FCoE]"}, - {"T404-BT 1G", "Chelsio T404-BT 1G [FCoE]"}, - {"B420-SR 10G", "Chelsio B420-SR 10G [FCoE]"}, - {"B404-BT 1G", "Chelsio B404-BT 1G [FCoE]"}, - {"T480-CR 10G", "Chelsio T480-CR 10G [FCoE]"}, - {"T440-LP-CR 10G", "Chelsio T440-LP-CR 10G [FCoE]"}, - {"AMSTERDAM 10G", "Chelsio AMSTERDAM 10G [FCoE]"}, - {"HUAWEI T480 10G", "Chelsio HUAWEI T480 10G [FCoE]"}, - {"HUAWEI T440 10G", "Chelsio HUAWEI T440 10G [FCoE]"}, - {"HUAWEI STG 10G", "Chelsio HUAWEI STG 10G [FCoE]"}, - {"ACROMAG XAUI 10G", "Chelsio ACROMAG XAUI 10G [FCoE]"}, - {"ACROMAG SFP+ 10G", "Chelsio ACROMAG SFP+ 10G [FCoE]"}, - {"QUANTA SFP+ 10G", "Chelsio QUANTA SFP+ 10G [FCoE]"}, - {"HUAWEI 10Gbase-T", "Chelsio HUAWEI 10Gbase-T [FCoE]"}, - {"HUAWEI T4TOE 10G", "Chelsio HUAWEI T4TOE 10G [FCoE]"} -}; - static const struct csio_adap_desc csio_t5_fcoe_adapters[] = { {"T580-Dbg 10G", "Chelsio T580-Dbg 10G [FCoE]"}, {"T520-CR 10G", "Chelsio T520-CR 10G [FCoE]"}, - {"T522-CR 10G/1G", "Chelsio T452-CR 10G/1G [FCoE]"}, + {"T522-CR 10G/1G", "Chelsio T522-CR 10G/1G [FCoE]"}, {"T540-CR 10G", "Chelsio T540-CR 10G [FCoE]"}, {"T520-BCH 10G", "Chelsio T520-BCH 10G [FCoE]"}, {"T540-BCH 10G", "Chelsio T540-BCH 10G [FCoE]"}, @@ -107,7 +80,9 @@ static const struct csio_adap_desc csio_t5_fcoe_adapters[] = { {"T580-LP-CR 40G", "Chelsio T580-LP-CR 40G [FCoE]"}, {"T520-LL-CR 10G", "Chelsio T520-LL-CR 10G [FCoE]"}, {"T560-CR 40G", "Chelsio T560-CR 40G [FCoE]"}, - {"T580-CR 40G", "Chelsio T580-CR 40G [FCoE]"} + {"T580-CR 40G", "Chelsio T580-CR 40G [FCoE]"}, + {"T580-SO 40G", "Chelsio T580-SO 40G [FCoE]"}, + {"T502-BT 1G", "Chelsio T502-BT 1G [FCoE]"} }; static void csio_mgmtm_cleanup(struct csio_mgmtm *); @@ -188,9 +163,9 @@ void csio_hw_tp_wr_bits_indirect(struct csio_hw *hw, unsigned int addr, unsigned int mask, unsigned int val) { - csio_wr_reg32(hw, addr, TP_PIO_ADDR); - val |= csio_rd_reg32(hw, TP_PIO_DATA) & ~mask; - csio_wr_reg32(hw, val, TP_PIO_DATA); + csio_wr_reg32(hw, addr, TP_PIO_ADDR_A); + val |= csio_rd_reg32(hw, TP_PIO_DATA_A) & ~mask; + csio_wr_reg32(hw, val, TP_PIO_DATA_A); } void @@ -256,7 +231,7 @@ csio_hw_seeprom_read(struct csio_hw *hw, uint32_t addr, uint32_t *data) } pci_read_config_dword(hw->pdev, base + PCI_VPD_DATA, data); - *data = le32_to_cpu(*data); + *data = le32_to_cpu(*(__le32 *)data); return 0; } @@ -421,17 +396,15 @@ csio_hw_sf1_read(struct csio_hw *hw, uint32_t byte_cnt, int32_t cont, if (!byte_cnt || byte_cnt > 4) return -EINVAL; - if (csio_rd_reg32(hw, SF_OP) & SF_BUSY) + if (csio_rd_reg32(hw, SF_OP_A) & SF_BUSY_F) return -EBUSY; - cont = cont ? SF_CONT : 0; - lock = lock ? SF_LOCK : 0; - - csio_wr_reg32(hw, lock | cont | BYTECNT(byte_cnt - 1), SF_OP); - ret = csio_hw_wait_op_done_val(hw, SF_OP, SF_BUSY, 0, SF_ATTEMPTS, - 10, NULL); + csio_wr_reg32(hw, SF_LOCK_V(lock) | SF_CONT_V(cont) | + BYTECNT_V(byte_cnt - 1), SF_OP_A); + ret = csio_hw_wait_op_done_val(hw, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, + 10, NULL); if (!ret) - *valp = csio_rd_reg32(hw, SF_DATA); + *valp = csio_rd_reg32(hw, SF_DATA_A); return ret; } @@ -453,16 +426,14 @@ csio_hw_sf1_write(struct csio_hw *hw, uint32_t byte_cnt, uint32_t cont, { if (!byte_cnt || byte_cnt > 4) return -EINVAL; - if (csio_rd_reg32(hw, SF_OP) & SF_BUSY) + if (csio_rd_reg32(hw, SF_OP_A) & SF_BUSY_F) return -EBUSY; - cont = cont ? SF_CONT : 0; - lock = lock ? SF_LOCK : 0; + csio_wr_reg32(hw, val, SF_DATA_A); + csio_wr_reg32(hw, SF_CONT_V(cont) | BYTECNT_V(byte_cnt - 1) | + OP_V(1) | SF_LOCK_V(lock), SF_OP_A); - csio_wr_reg32(hw, val, SF_DATA); - csio_wr_reg32(hw, cont | BYTECNT(byte_cnt - 1) | OP_WR | lock, SF_OP); - - return csio_hw_wait_op_done_val(hw, SF_OP, SF_BUSY, 0, SF_ATTEMPTS, + return csio_hw_wait_op_done_val(hw, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, 10, NULL); } @@ -533,11 +504,11 @@ csio_hw_read_flash(struct csio_hw *hw, uint32_t addr, uint32_t nwords, for ( ; nwords; nwords--, data++) { ret = csio_hw_sf1_read(hw, 4, nwords > 1, nwords == 1, data); if (nwords == 1) - csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */ + csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ if (ret) return ret; if (byte_oriented) - *data = htonl(*data); + *data = (__force __u32) htonl(*data); } return 0; } @@ -586,7 +557,7 @@ csio_hw_write_flash(struct csio_hw *hw, uint32_t addr, if (ret) goto unlock; - csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */ + csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ /* Read the page to verify the write succeeded */ ret = csio_hw_read_flash(hw, addr & ~0xff, ARRAY_SIZE(buf), buf, 1); @@ -603,7 +574,7 @@ csio_hw_write_flash(struct csio_hw *hw, uint32_t addr, return 0; unlock: - csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */ + csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ return ret; } @@ -641,7 +612,7 @@ out: if (ret) csio_err(hw, "erase of flash sector %d failed, error %d\n", start, ret); - csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */ + csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ return 0; } @@ -665,7 +636,7 @@ csio_hw_print_fw_version(struct csio_hw *hw, char *str) static int csio_hw_get_fw_version(struct csio_hw *hw, uint32_t *vers) { - return csio_hw_read_flash(hw, FW_IMG_START + + return csio_hw_read_flash(hw, FLASH_FW_START + offsetof(struct fw_hdr, fw_ver), 1, vers, 0); } @@ -685,43 +656,6 @@ csio_hw_get_tp_version(struct csio_hw *hw, u32 *vers) vers, 0); } -/* - * csio_hw_check_fw_version - check if the FW is compatible with - * this driver - * @hw: HW module - * - * Checks if an adapter's FW is compatible with the driver. Returns 0 - * if there's exact match, a negative error if the version could not be - * read or there's a major/minor version mismatch/minor. - */ -static int -csio_hw_check_fw_version(struct csio_hw *hw) -{ - int ret, major, minor, micro; - - ret = csio_hw_get_fw_version(hw, &hw->fwrev); - if (!ret) - ret = csio_hw_get_tp_version(hw, &hw->tp_vers); - if (ret) - return ret; - - major = FW_HDR_FW_VER_MAJOR_G(hw->fwrev); - minor = FW_HDR_FW_VER_MINOR_G(hw->fwrev); - micro = FW_HDR_FW_VER_MICRO_G(hw->fwrev); - - if (major != FW_VERSION_MAJOR(hw)) { /* major mismatch - fail */ - csio_err(hw, "card FW has major version %u, driver wants %u\n", - major, FW_VERSION_MAJOR(hw)); - return -EINVAL; - } - - if (minor == FW_VERSION_MINOR(hw) && micro == FW_VERSION_MICRO(hw)) - return 0; /* perfect match */ - - /* Minor/micro version mismatch */ - return -EINVAL; -} - /* * csio_hw_fw_dload - download firmware. * @hw: HW module @@ -762,9 +696,9 @@ csio_hw_fw_dload(struct csio_hw *hw, uint8_t *fw_data, uint32_t size) return -EINVAL; } - if (size > FW_MAX_SIZE) { + if (size > FLASH_FW_MAX_SIZE) { csio_err(hw, "FW image too large, max is %u bytes\n", - FW_MAX_SIZE); + FLASH_FW_MAX_SIZE); return -EINVAL; } @@ -780,10 +714,10 @@ csio_hw_fw_dload(struct csio_hw *hw, uint8_t *fw_data, uint32_t size) i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */ csio_dbg(hw, "Erasing sectors... start:%d end:%d\n", - FW_START_SEC, FW_START_SEC + i - 1); + FLASH_FW_START_SEC, FLASH_FW_START_SEC + i - 1); - ret = csio_hw_flash_erase_sectors(hw, FW_START_SEC, - FW_START_SEC + i - 1); + ret = csio_hw_flash_erase_sectors(hw, FLASH_FW_START_SEC, + FLASH_FW_START_SEC + i - 1); if (ret) { csio_err(hw, "Flash Erase failed\n"); goto out; @@ -796,14 +730,14 @@ csio_hw_fw_dload(struct csio_hw *hw, uint8_t *fw_data, uint32_t size) */ memcpy(first_page, fw_data, SF_PAGE_SIZE); ((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff); - ret = csio_hw_write_flash(hw, FW_IMG_START, SF_PAGE_SIZE, first_page); + ret = csio_hw_write_flash(hw, FLASH_FW_START, SF_PAGE_SIZE, first_page); if (ret) goto out; csio_dbg(hw, "Writing Flash .. start:%d end:%d\n", FW_IMG_START, FW_IMG_START + size); - addr = FW_IMG_START; + addr = FLASH_FW_START; for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { addr += SF_PAGE_SIZE; fw_data += SF_PAGE_SIZE; @@ -813,7 +747,7 @@ csio_hw_fw_dload(struct csio_hw *hw, uint8_t *fw_data, uint32_t size) } ret = csio_hw_write_flash(hw, - FW_IMG_START + + FLASH_FW_START + offsetof(struct fw_hdr, fw_ver), sizeof(hdr->fw_ver), (const uint8_t *)&hdr->fw_ver); @@ -833,7 +767,7 @@ csio_hw_get_flash_params(struct csio_hw *hw) ret = csio_hw_sf1_write(hw, 1, 1, 0, SF_RD_ID); if (!ret) ret = csio_hw_sf1_read(hw, 3, 0, 1, &info); - csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */ + csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */ if (ret != 0) return ret; @@ -861,17 +795,17 @@ csio_hw_dev_ready(struct csio_hw *hw) uint32_t reg; int cnt = 6; - while (((reg = csio_rd_reg32(hw, PL_WHOAMI)) == 0xFFFFFFFF) && - (--cnt != 0)) + while (((reg = csio_rd_reg32(hw, PL_WHOAMI_A)) == 0xFFFFFFFF) && + (--cnt != 0)) mdelay(100); - if ((cnt == 0) && (((int32_t)(SOURCEPF_GET(reg)) < 0) || - (SOURCEPF_GET(reg) >= CSIO_MAX_PFN))) { + if ((cnt == 0) && (((int32_t)(SOURCEPF_G(reg)) < 0) || + (SOURCEPF_G(reg) >= CSIO_MAX_PFN))) { csio_err(hw, "PL_WHOAMI returned 0x%x, cnt:%d\n", reg, cnt); return -EIO; } - hw->pfn = SOURCEPF_GET(reg); + hw->pfn = SOURCEPF_G(reg); return 0; } @@ -959,8 +893,8 @@ retry: * timeout ... and then retry if we haven't exhausted * our retries ... */ - pcie_fw = csio_rd_reg32(hw, PCIE_FW); - if (!(pcie_fw & (PCIE_FW_ERR|PCIE_FW_INIT))) { + pcie_fw = csio_rd_reg32(hw, PCIE_FW_A); + if (!(pcie_fw & (PCIE_FW_ERR_F|PCIE_FW_INIT_F))) { if (waiting <= 0) { if (retries-- > 0) goto retry; @@ -976,10 +910,10 @@ retry: * report errors preferentially. */ if (state) { - if (pcie_fw & PCIE_FW_ERR) { + if (pcie_fw & PCIE_FW_ERR_F) { *state = CSIO_DEV_STATE_ERR; rv = -ETIMEDOUT; - } else if (pcie_fw & PCIE_FW_INIT) + } else if (pcie_fw & PCIE_FW_INIT_F) *state = CSIO_DEV_STATE_INIT; } @@ -988,9 +922,9 @@ retry: * there's not a valid Master PF, grab its identity * for our caller. */ - if (mpfn == PCIE_FW_MASTER_MASK && - (pcie_fw & PCIE_FW_MASTER_VLD)) - mpfn = PCIE_FW_MASTER_GET(pcie_fw); + if (mpfn == PCIE_FW_MASTER_M && + (pcie_fw & PCIE_FW_MASTER_VLD_F)) + mpfn = PCIE_FW_MASTER_G(pcie_fw); break; } hw->flags &= ~CSIO_HWF_MASTER; @@ -1078,7 +1012,7 @@ csio_do_reset(struct csio_hw *hw, bool fw_rst) if (!fw_rst) { /* PIO reset */ - csio_wr_reg32(hw, PIORSTMODE | PIORST, PL_RST); + csio_wr_reg32(hw, PIORSTMODE_F | PIORST_F, PL_RST_A); mdelay(2000); return 0; } @@ -1090,7 +1024,7 @@ csio_do_reset(struct csio_hw *hw, bool fw_rst) } csio_mb_reset(hw, mbp, CSIO_MB_DEFAULT_TMO, - PIORSTMODE | PIORST, 0, NULL); + PIORSTMODE_F | PIORST_F, 0, NULL); if (csio_mb_issue(hw, mbp)) { csio_err(hw, "Issue of RESET command failed.n"); @@ -1156,7 +1090,7 @@ csio_hw_fw_halt(struct csio_hw *hw, uint32_t mbox, int32_t force) * If a legitimate mailbox is provided, issue a RESET command * with a HALT indication. */ - if (mbox <= PCIE_FW_MASTER_MASK) { + if (mbox <= PCIE_FW_MASTER_M) { struct csio_mb *mbp; mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); @@ -1166,7 +1100,7 @@ csio_hw_fw_halt(struct csio_hw *hw, uint32_t mbox, int32_t force) } csio_mb_reset(hw, mbp, CSIO_MB_DEFAULT_TMO, - PIORSTMODE | PIORST, FW_RESET_CMD_HALT_F, + PIORSTMODE_F | PIORST_F, FW_RESET_CMD_HALT_F, NULL); if (csio_mb_issue(hw, mbp)) { @@ -1193,8 +1127,9 @@ csio_hw_fw_halt(struct csio_hw *hw, uint32_t mbox, int32_t force) * rather than a RESET ... if it's new enough to understand that ... */ if (retval == 0 || force) { - csio_set_reg_field(hw, CIM_BOOT_CFG, UPCRST, UPCRST); - csio_set_reg_field(hw, PCIE_FW, PCIE_FW_HALT, PCIE_FW_HALT); + csio_set_reg_field(hw, CIM_BOOT_CFG_A, UPCRST_F, UPCRST_F); + csio_set_reg_field(hw, PCIE_FW_A, PCIE_FW_HALT_F, + PCIE_FW_HALT_F); } /* @@ -1234,7 +1169,7 @@ csio_hw_fw_restart(struct csio_hw *hw, uint32_t mbox, int32_t reset) * doing it automatically, we need to clear the PCIE_FW.HALT * bit. */ - csio_set_reg_field(hw, PCIE_FW, PCIE_FW_HALT, 0); + csio_set_reg_field(hw, PCIE_FW_A, PCIE_FW_HALT_F, 0); /* * If we've been given a valid mailbox, first try to get the @@ -1243,21 +1178,21 @@ csio_hw_fw_restart(struct csio_hw *hw, uint32_t mbox, int32_t reset) * valid mailbox or the RESET command failed, fall back to * hitting the chip with a hammer. */ - if (mbox <= PCIE_FW_MASTER_MASK) { - csio_set_reg_field(hw, CIM_BOOT_CFG, UPCRST, 0); + if (mbox <= PCIE_FW_MASTER_M) { + csio_set_reg_field(hw, CIM_BOOT_CFG_A, UPCRST_F, 0); msleep(100); if (csio_do_reset(hw, true) == 0) return 0; } - csio_wr_reg32(hw, PIORSTMODE | PIORST, PL_RST); + csio_wr_reg32(hw, PIORSTMODE_F | PIORST_F, PL_RST_A); msleep(2000); } else { int ms; - csio_set_reg_field(hw, CIM_BOOT_CFG, UPCRST, 0); + csio_set_reg_field(hw, CIM_BOOT_CFG_A, UPCRST_F, 0); for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) { - if (!(csio_rd_reg32(hw, PCIE_FW) & PCIE_FW_HALT)) + if (!(csio_rd_reg32(hw, PCIE_FW_A) & PCIE_FW_HALT_F)) return 0; msleep(100); ms += 100; @@ -1315,116 +1250,6 @@ csio_hw_fw_upgrade(struct csio_hw *hw, uint32_t mbox, return csio_hw_fw_restart(hw, mbox, reset); } - -/* - * csio_hw_fw_config_file - setup an adapter via a Configuration File - * @hw: the HW module - * @mbox: mailbox to use for the FW command - * @mtype: the memory type where the Configuration File is located - * @maddr: the memory address where the Configuration File is located - * @finiver: return value for CF [fini] version - * @finicsum: return value for CF [fini] checksum - * @cfcsum: return value for CF computed checksum - * - * Issue a command to get the firmware to process the Configuration - * File located at the specified mtype/maddress. If the Configuration - * File is processed successfully and return value pointers are - * provided, the Configuration File "[fini] section version and - * checksum values will be returned along with the computed checksum. - * It's up to the caller to decide how it wants to respond to the - * checksums not matching but it recommended that a prominant warning - * be emitted in order to help people rapidly identify changed or - * corrupted Configuration Files. - * - * Also note that it's possible to modify things like "niccaps", - * "toecaps",etc. between processing the Configuration File and telling - * the firmware to use the new configuration. Callers which want to - * do this will need to "hand-roll" their own CAPS_CONFIGS commands for - * Configuration Files if they want to do this. - */ -static int -csio_hw_fw_config_file(struct csio_hw *hw, - unsigned int mtype, unsigned int maddr, - uint32_t *finiver, uint32_t *finicsum, uint32_t *cfcsum) -{ - struct csio_mb *mbp; - struct fw_caps_config_cmd *caps_cmd; - int rv = -EINVAL; - enum fw_retval ret; - - mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); - if (!mbp) { - CSIO_INC_STATS(hw, n_err_nomem); - return -ENOMEM; - } - /* - * Tell the firmware to process the indicated Configuration File. - * If there are no errors and the caller has provided return value - * pointers for the [fini] section version, checksum and computed - * checksum, pass those back to the caller. - */ - caps_cmd = (struct fw_caps_config_cmd *)(mbp->mb); - CSIO_INIT_MBP(mbp, caps_cmd, CSIO_MB_DEFAULT_TMO, hw, NULL, 1); - caps_cmd->op_to_write = - htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | - FW_CMD_REQUEST_F | - FW_CMD_READ_F); - caps_cmd->cfvalid_to_len16 = - htonl(FW_CAPS_CONFIG_CMD_CFVALID_F | - FW_CAPS_CONFIG_CMD_MEMTYPE_CF_V(mtype) | - FW_CAPS_CONFIG_CMD_MEMADDR64K_CF_V(maddr >> 16) | - FW_LEN16(*caps_cmd)); - - if (csio_mb_issue(hw, mbp)) { - csio_err(hw, "Issue of FW_CAPS_CONFIG_CMD failed!\n"); - goto out; - } - - ret = csio_mb_fw_retval(mbp); - if (ret != FW_SUCCESS) { - csio_dbg(hw, "FW_CAPS_CONFIG_CMD returned %d!\n", rv); - goto out; - } - - if (finiver) - *finiver = ntohl(caps_cmd->finiver); - if (finicsum) - *finicsum = ntohl(caps_cmd->finicsum); - if (cfcsum) - *cfcsum = ntohl(caps_cmd->cfcsum); - - /* Validate device capabilities */ - if (csio_hw_validate_caps(hw, mbp)) { - rv = -ENOENT; - goto out; - } - - /* - * And now tell the firmware to use the configuration we just loaded. - */ - caps_cmd->op_to_write = - htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | - FW_CMD_REQUEST_F | - FW_CMD_WRITE_F); - caps_cmd->cfvalid_to_len16 = htonl(FW_LEN16(*caps_cmd)); - - if (csio_mb_issue(hw, mbp)) { - csio_err(hw, "Issue of FW_CAPS_CONFIG_CMD failed!\n"); - goto out; - } - - ret = csio_mb_fw_retval(mbp); - if (ret != FW_SUCCESS) { - csio_dbg(hw, "FW_CAPS_CONFIG_CMD returned %d!\n", rv); - goto out; - } - - rv = 0; -out: - mempool_free(mbp, hw->mb_mempool); - return rv; -} - /* * csio_get_device_params - Get device parameters. * @hw: HW module @@ -1547,7 +1372,8 @@ csio_config_device_caps(struct csio_hw *hw) } /* Validate device capabilities */ - if (csio_hw_validate_caps(hw, mbp)) + rv = csio_hw_validate_caps(hw, mbp); + if (rv != 0) goto out; /* Don't config device capabilities if already configured */ @@ -1756,9 +1582,9 @@ csio_hw_flash_config(struct csio_hw *hw, u32 *fw_cfg_param, char *path) uint32_t *cfg_data; int value_to_add = 0; - if (request_firmware(&cf, CSIO_CF_FNAME(hw), dev) < 0) { + if (request_firmware(&cf, FW_CFG_NAME_T5, dev) < 0) { csio_err(hw, "could not find config file %s, err: %d\n", - CSIO_CF_FNAME(hw), ret); + FW_CFG_NAME_T5, ret); return -ENOENT; } @@ -1798,8 +1624,8 @@ csio_hw_flash_config(struct csio_hw *hw, u32 *fw_cfg_param, char *path) } if (ret == 0) { csio_info(hw, "config file upgraded to %s\n", - CSIO_CF_FNAME(hw)); - snprintf(path, 64, "%s%s", "/lib/firmware/", CSIO_CF_FNAME(hw)); + FW_CFG_NAME_T5); + snprintf(path, 64, "%s%s", "/lib/firmware/", FW_CFG_NAME_T5); } leave: @@ -1827,11 +1653,13 @@ leave: static int csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param) { + struct csio_mb *mbp = NULL; + struct fw_caps_config_cmd *caps_cmd; unsigned int mtype, maddr; - int rv; + int rv = -EINVAL; uint32_t finiver = 0, finicsum = 0, cfcsum = 0; - int using_flash; char path[64]; + char *config_name = NULL; /* * Reset device if necessary @@ -1851,51 +1679,107 @@ csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param) rv = csio_hw_flash_config(hw, fw_cfg_param, path); spin_lock_irq(&hw->lock); if (rv != 0) { - if (rv == -ENOENT) { - /* - * config file was not found. Use default - * config file from flash. - */ - mtype = FW_MEMTYPE_CF_FLASH; - maddr = hw->chip_ops->chip_flash_cfg_addr(hw); - using_flash = 1; - } else { - /* - * we revert back to the hardwired config if - * flashing failed. - */ - goto bye; - } + /* + * config file was not found. Use default + * config file from flash. + */ + config_name = "On FLASH"; + mtype = FW_MEMTYPE_CF_FLASH; + maddr = hw->chip_ops->chip_flash_cfg_addr(hw); } else { + config_name = path; mtype = FW_PARAMS_PARAM_Y_G(*fw_cfg_param); maddr = FW_PARAMS_PARAM_Z_G(*fw_cfg_param) << 16; - using_flash = 0; } - hw->cfg_store = (uint8_t)mtype; - + mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); + if (!mbp) { + CSIO_INC_STATS(hw, n_err_nomem); + return -ENOMEM; + } /* - * Issue a Capability Configuration command to the firmware to get it - * to parse the Configuration File. + * Tell the firmware to process the indicated Configuration File. + * If there are no errors and the caller has provided return value + * pointers for the [fini] section version, checksum and computed + * checksum, pass those back to the caller. */ - rv = csio_hw_fw_config_file(hw, mtype, maddr, &finiver, - &finicsum, &cfcsum); - if (rv != 0) + caps_cmd = (struct fw_caps_config_cmd *)(mbp->mb); + CSIO_INIT_MBP(mbp, caps_cmd, CSIO_MB_DEFAULT_TMO, hw, NULL, 1); + caps_cmd->op_to_write = + htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_READ_F); + caps_cmd->cfvalid_to_len16 = + htonl(FW_CAPS_CONFIG_CMD_CFVALID_F | + FW_CAPS_CONFIG_CMD_MEMTYPE_CF_V(mtype) | + FW_CAPS_CONFIG_CMD_MEMADDR64K_CF_V(maddr >> 16) | + FW_LEN16(*caps_cmd)); + + if (csio_mb_issue(hw, mbp)) { + rv = -EINVAL; + goto bye; + } + + rv = csio_mb_fw_retval(mbp); + /* If the CAPS_CONFIG failed with an ENOENT (for a Firmware + * Configuration File in FLASH), our last gasp effort is to use the + * Firmware Configuration File which is embedded in the + * firmware. A very few early versions of the firmware didn't + * have one embedded but we can ignore those. + */ + if (rv == ENOENT) { + CSIO_INIT_MBP(mbp, caps_cmd, CSIO_MB_DEFAULT_TMO, hw, NULL, 1); + caps_cmd->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_READ_F); + caps_cmd->cfvalid_to_len16 = htonl(FW_LEN16(*caps_cmd)); + + if (csio_mb_issue(hw, mbp)) { + rv = -EINVAL; + goto bye; + } + + rv = csio_mb_fw_retval(mbp); + config_name = "Firmware Default"; + } + if (rv != FW_SUCCESS) goto bye; - hw->cfg_finiver = finiver; - hw->cfg_finicsum = finicsum; - hw->cfg_cfcsum = cfcsum; - hw->cfg_csum_status = true; + finiver = ntohl(caps_cmd->finiver); + finicsum = ntohl(caps_cmd->finicsum); + cfcsum = ntohl(caps_cmd->cfcsum); + /* + * And now tell the firmware to use the configuration we just loaded. + */ + caps_cmd->op_to_write = + htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_WRITE_F); + caps_cmd->cfvalid_to_len16 = htonl(FW_LEN16(*caps_cmd)); + + if (csio_mb_issue(hw, mbp)) { + rv = -EINVAL; + goto bye; + } + + rv = csio_mb_fw_retval(mbp); + if (rv != FW_SUCCESS) { + csio_dbg(hw, "FW_CAPS_CONFIG_CMD returned %d!\n", rv); + goto bye; + } + + mempool_free(mbp, hw->mb_mempool); if (finicsum != cfcsum) { csio_warn(hw, "Config File checksum mismatch: csum=%#x, computed=%#x\n", finicsum, cfcsum); - - hw->cfg_csum_status = false; } + /* Validate device capabilities */ + rv = csio_hw_validate_caps(hw, mbp); + if (rv != 0) + goto bye; /* * Note that we're operating with parameters * not supplied by the driver, rather than from hard-wired @@ -1918,56 +1802,184 @@ csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param) /* Post event to notify completion of configuration */ csio_post_event(&hw->sm, CSIO_HWE_INIT); - csio_info(hw, - "Firmware Configuration File %s, version %#x, computed checksum %#x\n", - (using_flash ? "in device FLASH" : path), finiver, cfcsum); - + csio_info(hw, "Successfully configure using Firmware " + "Configuration File %s, version %#x, computed checksum %#x\n", + config_name, finiver, cfcsum); return 0; /* * Something bad happened. Return the error ... */ bye: + if (mbp) + mempool_free(mbp, hw->mb_mempool); hw->flags &= ~CSIO_HWF_USING_SOFT_PARAMS; - csio_dbg(hw, "Configuration file error %d\n", rv); + csio_warn(hw, "Configuration file error %d\n", rv); return rv; } -/* - * Attempt to initialize the adapter via hard-coded, driver supplied - * parameters ... +/* Is the given firmware API compatible with the one the driver was compiled + * with? */ -static int -csio_hw_no_fwconfig(struct csio_hw *hw, int reset) +static int fw_compatible(const struct fw_hdr *hdr1, const struct fw_hdr *hdr2) { - int rv; - /* - * Reset device if necessary - */ - if (reset) { - rv = csio_do_reset(hw, true); - if (rv != 0) - goto out; + + /* short circuit if it's the exact same firmware version */ + if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver) + return 1; + +#define SAME_INTF(x) (hdr1->intfver_##x == hdr2->intfver_##x) + if (hdr1->chip == hdr2->chip && SAME_INTF(nic) && SAME_INTF(vnic) && + SAME_INTF(ri) && SAME_INTF(iscsi) && SAME_INTF(fcoe)) + return 1; +#undef SAME_INTF + + return 0; +} + +/* The firmware in the filesystem is usable, but should it be installed? + * This routine explains itself in detail if it indicates the filesystem + * firmware should be installed. + */ +static int csio_should_install_fs_fw(struct csio_hw *hw, int card_fw_usable, + int k, int c) +{ + const char *reason; + + if (!card_fw_usable) { + reason = "incompatible or unusable"; + goto install; } - /* Get and set device capabilities */ - rv = csio_config_device_caps(hw); - if (rv != 0) - goto out; + if (k > c) { + reason = "older than the version supported with this driver"; + goto install; + } - /* device parameters */ - rv = csio_get_device_params(hw); - if (rv != 0) - goto out; + return 0; - /* Configure SGE */ - csio_wr_sge_init(hw); +install: + csio_err(hw, "firmware on card (%u.%u.%u.%u) is %s, " + "installing firmware %u.%u.%u.%u on card.\n", + FW_HDR_FW_VER_MAJOR_G(c), FW_HDR_FW_VER_MINOR_G(c), + FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c), reason, + FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k), + FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k)); - /* Post event to notify completion of configuration */ - csio_post_event(&hw->sm, CSIO_HWE_INIT); + return 1; +} -out: - return rv; +static struct fw_info fw_info_array[] = { + { + .chip = CHELSIO_T5, + .fs_name = FW_CFG_NAME_T5, + .fw_mod_name = FW_FNAME_T5, + .fw_hdr = { + .chip = FW_HDR_CHIP_T5, + .fw_ver = __cpu_to_be32(FW_VERSION(T5)), + .intfver_nic = FW_INTFVER(T5, NIC), + .intfver_vnic = FW_INTFVER(T5, VNIC), + .intfver_ri = FW_INTFVER(T5, RI), + .intfver_iscsi = FW_INTFVER(T5, ISCSI), + .intfver_fcoe = FW_INTFVER(T5, FCOE), + }, + } +}; + +static struct fw_info *find_fw_info(int chip) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(fw_info_array); i++) { + if (fw_info_array[i].chip == chip) + return &fw_info_array[i]; + } + return NULL; +} + +static int csio_hw_prep_fw(struct csio_hw *hw, struct fw_info *fw_info, + const u8 *fw_data, unsigned int fw_size, + struct fw_hdr *card_fw, enum csio_dev_state state, + int *reset) +{ + int ret, card_fw_usable, fs_fw_usable; + const struct fw_hdr *fs_fw; + const struct fw_hdr *drv_fw; + + drv_fw = &fw_info->fw_hdr; + + /* Read the header of the firmware on the card */ + ret = csio_hw_read_flash(hw, FLASH_FW_START, + sizeof(*card_fw) / sizeof(uint32_t), + (uint32_t *)card_fw, 1); + if (ret == 0) { + card_fw_usable = fw_compatible(drv_fw, (const void *)card_fw); + } else { + csio_err(hw, + "Unable to read card's firmware header: %d\n", ret); + card_fw_usable = 0; + } + + if (fw_data != NULL) { + fs_fw = (const void *)fw_data; + fs_fw_usable = fw_compatible(drv_fw, fs_fw); + } else { + fs_fw = NULL; + fs_fw_usable = 0; + } + + if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver && + (!fs_fw_usable || fs_fw->fw_ver == drv_fw->fw_ver)) { + /* Common case: the firmware on the card is an exact match and + * the filesystem one is an exact match too, or the filesystem + * one is absent/incompatible. + */ + } else if (fs_fw_usable && state == CSIO_DEV_STATE_UNINIT && + csio_should_install_fs_fw(hw, card_fw_usable, + be32_to_cpu(fs_fw->fw_ver), + be32_to_cpu(card_fw->fw_ver))) { + ret = csio_hw_fw_upgrade(hw, hw->pfn, fw_data, + fw_size, 0); + if (ret != 0) { + csio_err(hw, + "failed to install firmware: %d\n", ret); + goto bye; + } + + /* Installed successfully, update the cached header too. */ + memcpy(card_fw, fs_fw, sizeof(*card_fw)); + card_fw_usable = 1; + *reset = 0; /* already reset as part of load_fw */ + } + + if (!card_fw_usable) { + uint32_t d, c, k; + + d = be32_to_cpu(drv_fw->fw_ver); + c = be32_to_cpu(card_fw->fw_ver); + k = fs_fw ? be32_to_cpu(fs_fw->fw_ver) : 0; + + csio_err(hw, "Cannot find a usable firmware: " + "chip state %d, " + "driver compiled with %d.%d.%d.%d, " + "card has %d.%d.%d.%d, filesystem has %d.%d.%d.%d\n", + state, + FW_HDR_FW_VER_MAJOR_G(d), FW_HDR_FW_VER_MINOR_G(d), + FW_HDR_FW_VER_MICRO_G(d), FW_HDR_FW_VER_BUILD_G(d), + FW_HDR_FW_VER_MAJOR_G(c), FW_HDR_FW_VER_MINOR_G(c), + FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c), + FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k), + FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k)); + ret = EINVAL; + goto bye; + } + + /* We're using whatever's on the card and it's known to be good. */ + hw->fwrev = be32_to_cpu(card_fw->fw_ver); + hw->tp_vers = be32_to_cpu(card_fw->tp_microcode_ver); + +bye: + return ret; } /* @@ -1977,48 +1989,52 @@ out: * latest firmware ECANCELED is returned */ static int -csio_hw_flash_fw(struct csio_hw *hw) +csio_hw_flash_fw(struct csio_hw *hw, int *reset) { int ret = -ECANCELED; const struct firmware *fw; - const struct fw_hdr *hdr; - u32 fw_ver; + struct fw_info *fw_info; + struct fw_hdr *card_fw; struct pci_dev *pci_dev = hw->pdev; struct device *dev = &pci_dev->dev ; + const u8 *fw_data = NULL; + unsigned int fw_size = 0; - if (request_firmware(&fw, CSIO_FW_FNAME(hw), dev) < 0) { - csio_err(hw, "could not find firmware image %s, err: %d\n", - CSIO_FW_FNAME(hw), ret); + /* This is the firmware whose headers the driver was compiled + * against + */ + fw_info = find_fw_info(CHELSIO_CHIP_VERSION(hw->chip_id)); + if (fw_info == NULL) { + csio_err(hw, + "unable to get firmware info for chip %d.\n", + CHELSIO_CHIP_VERSION(hw->chip_id)); return -EINVAL; } - hdr = (const struct fw_hdr *)fw->data; - fw_ver = ntohl(hdr->fw_ver); - if (FW_HDR_FW_VER_MAJOR_G(fw_ver) != FW_VERSION_MAJOR(hw)) - return -EINVAL; /* wrong major version, won't do */ + if (request_firmware(&fw, FW_FNAME_T5, dev) < 0) { + csio_err(hw, "could not find firmware image %s, err: %d\n", + FW_FNAME_T5, ret); + } else { + fw_data = fw->data; + fw_size = fw->size; + } - /* - * If the flash FW is unusable or we found something newer, load it. + /* allocate memory to read the header of the firmware on the + * card */ - if (FW_HDR_FW_VER_MAJOR_G(hw->fwrev) != FW_VERSION_MAJOR(hw) || - fw_ver > hw->fwrev) { - ret = csio_hw_fw_upgrade(hw, hw->pfn, fw->data, fw->size, - /*force=*/false); - if (!ret) - csio_info(hw, - "firmware upgraded to version %pI4 from %s\n", - &hdr->fw_ver, CSIO_FW_FNAME(hw)); - else - csio_err(hw, "firmware upgrade failed! err=%d\n", ret); - } else - ret = -EINVAL; + card_fw = kmalloc(sizeof(*card_fw), GFP_KERNEL); - release_firmware(fw); + /* upgrade FW logic */ + ret = csio_hw_prep_fw(hw, fw_info, fw_data, fw_size, card_fw, + hw->fw_state, reset); + /* Cleaning up */ + if (fw != NULL) + release_firmware(fw); + kfree(card_fw); return ret; } - /* * csio_hw_configure - Configure HW * @hw - HW module @@ -2039,7 +2055,7 @@ csio_hw_configure(struct csio_hw *hw) } /* HW version */ - hw->chip_ver = (char)csio_rd_reg32(hw, PL_REV); + hw->chip_ver = (char)csio_rd_reg32(hw, PL_REV_A); /* Needed for FW download */ rv = csio_hw_get_flash_params(hw); @@ -2074,51 +2090,44 @@ csio_hw_configure(struct csio_hw *hw) if (rv != 0) goto out; + csio_hw_get_fw_version(hw, &hw->fwrev); + csio_hw_get_tp_version(hw, &hw->tp_vers); if (csio_is_hw_master(hw) && hw->fw_state != CSIO_DEV_STATE_INIT) { - rv = csio_hw_check_fw_version(hw); - if (rv == -EINVAL) { /* Do firmware update */ - spin_unlock_irq(&hw->lock); - rv = csio_hw_flash_fw(hw); - spin_lock_irq(&hw->lock); - - if (rv == 0) { - reset = 0; - /* - * Note that the chip was reset as part of the - * firmware upgrade so we don't reset it again - * below and grab the new firmware version. - */ - rv = csio_hw_check_fw_version(hw); - } - } - /* - * If the firmware doesn't support Configuration - * Files, use the old Driver-based, hard-wired - * initialization. Otherwise, try using the - * Configuration File support and fall back to the - * Driver-based initialization if there's no - * Configuration File found. - */ - if (csio_hw_check_fwconfig(hw, param) == 0) { - rv = csio_hw_use_fwconfig(hw, reset, param); - if (rv == -ENOENT) - goto out; - if (rv != 0) { - csio_info(hw, - "No Configuration File present " - "on adapter. Using hard-wired " - "configuration parameters.\n"); - rv = csio_hw_no_fwconfig(hw, reset); - } - } else { - rv = csio_hw_no_fwconfig(hw, reset); - } + spin_unlock_irq(&hw->lock); + rv = csio_hw_flash_fw(hw, &reset); + spin_lock_irq(&hw->lock); if (rv != 0) goto out; + /* If the firmware doesn't support Configuration Files, + * return an error. + */ + rv = csio_hw_check_fwconfig(hw, param); + if (rv != 0) { + csio_info(hw, "Firmware doesn't support " + "Firmware Configuration files\n"); + goto out; + } + + /* The firmware provides us with a memory buffer where we can + * load a Configuration File from the host if we want to + * override the Configuration File in flash. + */ + rv = csio_hw_use_fwconfig(hw, reset, param); + if (rv == -ENOENT) { + csio_info(hw, "Could not initialize " + "adapter, error%d\n", rv); + goto out; + } + if (rv != 0) { + csio_info(hw, "Could not initialize " + "adapter, error%d\n", rv); + goto out; + } + } else { if (hw->fw_state == CSIO_DEV_STATE_INIT) { @@ -2217,7 +2226,7 @@ out: return; } -#define PF_INTR_MASK (PFSW | PFCIM) +#define PF_INTR_MASK (PFSW_F | PFCIM_F) /* * csio_hw_intr_enable - Enable HW interrupts @@ -2229,21 +2238,21 @@ static void csio_hw_intr_enable(struct csio_hw *hw) { uint16_t vec = (uint16_t)csio_get_mb_intr_idx(csio_hw_to_mbm(hw)); - uint32_t pf = SOURCEPF_GET(csio_rd_reg32(hw, PL_WHOAMI)); - uint32_t pl = csio_rd_reg32(hw, PL_INT_ENABLE); + uint32_t pf = SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A)); + uint32_t pl = csio_rd_reg32(hw, PL_INT_ENABLE_A); /* * Set aivec for MSI/MSIX. PCIE_PF_CFG.INTXType is set up * by FW, so do nothing for INTX. */ if (hw->intr_mode == CSIO_IM_MSIX) - csio_set_reg_field(hw, MYPF_REG(PCIE_PF_CFG), - AIVEC(AIVEC_MASK), vec); + csio_set_reg_field(hw, MYPF_REG(PCIE_PF_CFG_A), + AIVEC_V(AIVEC_M), vec); else if (hw->intr_mode == CSIO_IM_MSI) - csio_set_reg_field(hw, MYPF_REG(PCIE_PF_CFG), - AIVEC(AIVEC_MASK), 0); + csio_set_reg_field(hw, MYPF_REG(PCIE_PF_CFG_A), + AIVEC_V(AIVEC_M), 0); - csio_wr_reg32(hw, PF_INTR_MASK, MYPF_REG(PL_PF_INT_ENABLE)); + csio_wr_reg32(hw, PF_INTR_MASK, MYPF_REG(PL_PF_INT_ENABLE_A)); /* Turn on MB interrupts - this will internally flush PIO as well */ csio_mb_intr_enable(hw); @@ -2253,19 +2262,19 @@ csio_hw_intr_enable(struct csio_hw *hw) /* * Disable the Serial FLASH interrupt, if enabled! */ - pl &= (~SF); - csio_wr_reg32(hw, pl, PL_INT_ENABLE); + pl &= (~SF_F); + csio_wr_reg32(hw, pl, PL_INT_ENABLE_A); - csio_wr_reg32(hw, ERR_CPL_EXCEED_IQE_SIZE | - EGRESS_SIZE_ERR | ERR_INVALID_CIDX_INC | - ERR_CPL_OPCODE_0 | ERR_DROPPED_DB | - ERR_DATA_CPL_ON_HIGH_QID1 | - ERR_DATA_CPL_ON_HIGH_QID0 | ERR_BAD_DB_PIDX3 | - ERR_BAD_DB_PIDX2 | ERR_BAD_DB_PIDX1 | - ERR_BAD_DB_PIDX0 | ERR_ING_CTXT_PRIO | - ERR_EGR_CTXT_PRIO | INGRESS_SIZE_ERR, - SGE_INT_ENABLE3); - csio_set_reg_field(hw, PL_INT_MAP0, 0, 1 << pf); + csio_wr_reg32(hw, ERR_CPL_EXCEED_IQE_SIZE_F | + EGRESS_SIZE_ERR_F | ERR_INVALID_CIDX_INC_F | + ERR_CPL_OPCODE_0_F | ERR_DROPPED_DB_F | + ERR_DATA_CPL_ON_HIGH_QID1_F | + ERR_DATA_CPL_ON_HIGH_QID0_F | ERR_BAD_DB_PIDX3_F | + ERR_BAD_DB_PIDX2_F | ERR_BAD_DB_PIDX1_F | + ERR_BAD_DB_PIDX0_F | ERR_ING_CTXT_PRIO_F | + ERR_EGR_CTXT_PRIO_F | INGRESS_SIZE_ERR_F, + SGE_INT_ENABLE3_A); + csio_set_reg_field(hw, PL_INT_MAP0_A, 0, 1 << pf); } hw->flags |= CSIO_HWF_HW_INTR_ENABLED; @@ -2281,16 +2290,16 @@ csio_hw_intr_enable(struct csio_hw *hw) void csio_hw_intr_disable(struct csio_hw *hw) { - uint32_t pf = SOURCEPF_GET(csio_rd_reg32(hw, PL_WHOAMI)); + uint32_t pf = SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A)); if (!(hw->flags & CSIO_HWF_HW_INTR_ENABLED)) return; hw->flags &= ~CSIO_HWF_HW_INTR_ENABLED; - csio_wr_reg32(hw, 0, MYPF_REG(PL_PF_INT_ENABLE)); + csio_wr_reg32(hw, 0, MYPF_REG(PL_PF_INT_ENABLE_A)); if (csio_is_hw_master(hw)) - csio_set_reg_field(hw, PL_INT_MAP0, 1 << pf, 0); + csio_set_reg_field(hw, PL_INT_MAP0_A, 1 << pf, 0); /* Turn off MB interrupts */ csio_mb_intr_disable(hw); @@ -2300,7 +2309,7 @@ csio_hw_intr_disable(struct csio_hw *hw) void csio_hw_fatal_err(struct csio_hw *hw) { - csio_set_reg_field(hw, SGE_CONTROL, GLOBALENABLE, 0); + csio_set_reg_field(hw, SGE_CONTROL_A, GLOBALENABLE_F, 0); csio_hw_intr_disable(hw); /* Do not reset HW, we may need FW state for debugging */ @@ -2594,7 +2603,7 @@ csio_hws_removing(struct csio_hw *hw, enum csio_hw_ev evt) * register directly. */ csio_err(hw, "Resetting HW and waiting 2 seconds...\n"); - csio_wr_reg32(hw, PIORSTMODE | PIORST, PL_RST); + csio_wr_reg32(hw, PIORSTMODE_F | PIORST_F, PL_RST_A); mdelay(2000); break; @@ -2682,11 +2691,11 @@ static void csio_tp_intr_handler(struct csio_hw *hw) { static struct intr_info tp_intr_info[] = { { 0x3fffffff, "TP parity error", -1, 1 }, - { FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 }, + { FLMTXFLSTEMPTY_F, "TP out of Tx pages", -1, 1 }, { 0, NULL, 0, 0 } }; - if (csio_handle_intr_status(hw, TP_INT_CAUSE, tp_intr_info)) + if (csio_handle_intr_status(hw, TP_INT_CAUSE_A, tp_intr_info)) csio_hw_fatal_err(hw); } @@ -2698,52 +2707,52 @@ static void csio_sge_intr_handler(struct csio_hw *hw) uint64_t v; static struct intr_info sge_intr_info[] = { - { ERR_CPL_EXCEED_IQE_SIZE, + { ERR_CPL_EXCEED_IQE_SIZE_F, "SGE received CPL exceeding IQE size", -1, 1 }, - { ERR_INVALID_CIDX_INC, + { ERR_INVALID_CIDX_INC_F, "SGE GTS CIDX increment too large", -1, 0 }, - { ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 }, - { ERR_DROPPED_DB, "SGE doorbell dropped", -1, 0 }, - { ERR_DATA_CPL_ON_HIGH_QID1 | ERR_DATA_CPL_ON_HIGH_QID0, + { ERR_CPL_OPCODE_0_F, "SGE received 0-length CPL", -1, 0 }, + { ERR_DROPPED_DB_F, "SGE doorbell dropped", -1, 0 }, + { ERR_DATA_CPL_ON_HIGH_QID1_F | ERR_DATA_CPL_ON_HIGH_QID0_F, "SGE IQID > 1023 received CPL for FL", -1, 0 }, - { ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1, + { ERR_BAD_DB_PIDX3_F, "SGE DBP 3 pidx increment too large", -1, 0 }, - { ERR_BAD_DB_PIDX2, "SGE DBP 2 pidx increment too large", -1, + { ERR_BAD_DB_PIDX2_F, "SGE DBP 2 pidx increment too large", -1, 0 }, - { ERR_BAD_DB_PIDX1, "SGE DBP 1 pidx increment too large", -1, + { ERR_BAD_DB_PIDX1_F, "SGE DBP 1 pidx increment too large", -1, 0 }, - { ERR_BAD_DB_PIDX0, "SGE DBP 0 pidx increment too large", -1, + { ERR_BAD_DB_PIDX0_F, "SGE DBP 0 pidx increment too large", -1, 0 }, - { ERR_ING_CTXT_PRIO, + { ERR_ING_CTXT_PRIO_F, "SGE too many priority ingress contexts", -1, 0 }, - { ERR_EGR_CTXT_PRIO, + { ERR_EGR_CTXT_PRIO_F, "SGE too many priority egress contexts", -1, 0 }, - { INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 }, - { EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 }, + { INGRESS_SIZE_ERR_F, "SGE illegal ingress QID", -1, 0 }, + { EGRESS_SIZE_ERR_F, "SGE illegal egress QID", -1, 0 }, { 0, NULL, 0, 0 } }; - v = (uint64_t)csio_rd_reg32(hw, SGE_INT_CAUSE1) | - ((uint64_t)csio_rd_reg32(hw, SGE_INT_CAUSE2) << 32); + v = (uint64_t)csio_rd_reg32(hw, SGE_INT_CAUSE1_A) | + ((uint64_t)csio_rd_reg32(hw, SGE_INT_CAUSE2_A) << 32); if (v) { csio_fatal(hw, "SGE parity error (%#llx)\n", (unsigned long long)v); csio_wr_reg32(hw, (uint32_t)(v & 0xFFFFFFFF), - SGE_INT_CAUSE1); - csio_wr_reg32(hw, (uint32_t)(v >> 32), SGE_INT_CAUSE2); + SGE_INT_CAUSE1_A); + csio_wr_reg32(hw, (uint32_t)(v >> 32), SGE_INT_CAUSE2_A); } - v |= csio_handle_intr_status(hw, SGE_INT_CAUSE3, sge_intr_info); + v |= csio_handle_intr_status(hw, SGE_INT_CAUSE3_A, sge_intr_info); - if (csio_handle_intr_status(hw, SGE_INT_CAUSE3, sge_intr_info) || + if (csio_handle_intr_status(hw, SGE_INT_CAUSE3_A, sge_intr_info) || v != 0) csio_hw_fatal_err(hw); } -#define CIM_OBQ_INTR (OBQULP0PARERR | OBQULP1PARERR | OBQULP2PARERR |\ - OBQULP3PARERR | OBQSGEPARERR | OBQNCSIPARERR) -#define CIM_IBQ_INTR (IBQTP0PARERR | IBQTP1PARERR | IBQULPPARERR |\ - IBQSGEHIPARERR | IBQSGELOPARERR | IBQNCSIPARERR) +#define CIM_OBQ_INTR (OBQULP0PARERR_F | OBQULP1PARERR_F | OBQULP2PARERR_F |\ + OBQULP3PARERR_F | OBQSGEPARERR_F | OBQNCSIPARERR_F) +#define CIM_IBQ_INTR (IBQTP0PARERR_F | IBQTP1PARERR_F | IBQULPPARERR_F |\ + IBQSGEHIPARERR_F | IBQSGELOPARERR_F | IBQNCSIPARERR_F) /* * CIM interrupt handler. @@ -2751,53 +2760,53 @@ static void csio_sge_intr_handler(struct csio_hw *hw) static void csio_cim_intr_handler(struct csio_hw *hw) { static struct intr_info cim_intr_info[] = { - { PREFDROPINT, "CIM control register prefetch drop", -1, 1 }, + { PREFDROPINT_F, "CIM control register prefetch drop", -1, 1 }, { CIM_OBQ_INTR, "CIM OBQ parity error", -1, 1 }, { CIM_IBQ_INTR, "CIM IBQ parity error", -1, 1 }, - { MBUPPARERR, "CIM mailbox uP parity error", -1, 1 }, - { MBHOSTPARERR, "CIM mailbox host parity error", -1, 1 }, - { TIEQINPARERRINT, "CIM TIEQ outgoing parity error", -1, 1 }, - { TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 }, + { MBUPPARERR_F, "CIM mailbox uP parity error", -1, 1 }, + { MBHOSTPARERR_F, "CIM mailbox host parity error", -1, 1 }, + { TIEQINPARERRINT_F, "CIM TIEQ outgoing parity error", -1, 1 }, + { TIEQOUTPARERRINT_F, "CIM TIEQ incoming parity error", -1, 1 }, { 0, NULL, 0, 0 } }; static struct intr_info cim_upintr_info[] = { - { RSVDSPACEINT, "CIM reserved space access", -1, 1 }, - { ILLTRANSINT, "CIM illegal transaction", -1, 1 }, - { ILLWRINT, "CIM illegal write", -1, 1 }, - { ILLRDINT, "CIM illegal read", -1, 1 }, - { ILLRDBEINT, "CIM illegal read BE", -1, 1 }, - { ILLWRBEINT, "CIM illegal write BE", -1, 1 }, - { SGLRDBOOTINT, "CIM single read from boot space", -1, 1 }, - { SGLWRBOOTINT, "CIM single write to boot space", -1, 1 }, - { BLKWRBOOTINT, "CIM block write to boot space", -1, 1 }, - { SGLRDFLASHINT, "CIM single read from flash space", -1, 1 }, - { SGLWRFLASHINT, "CIM single write to flash space", -1, 1 }, - { BLKWRFLASHINT, "CIM block write to flash space", -1, 1 }, - { SGLRDEEPROMINT, "CIM single EEPROM read", -1, 1 }, - { SGLWREEPROMINT, "CIM single EEPROM write", -1, 1 }, - { BLKRDEEPROMINT, "CIM block EEPROM read", -1, 1 }, - { BLKWREEPROMINT, "CIM block EEPROM write", -1, 1 }, - { SGLRDCTLINT , "CIM single read from CTL space", -1, 1 }, - { SGLWRCTLINT , "CIM single write to CTL space", -1, 1 }, - { BLKRDCTLINT , "CIM block read from CTL space", -1, 1 }, - { BLKWRCTLINT , "CIM block write to CTL space", -1, 1 }, - { SGLRDPLINT , "CIM single read from PL space", -1, 1 }, - { SGLWRPLINT , "CIM single write to PL space", -1, 1 }, - { BLKRDPLINT , "CIM block read from PL space", -1, 1 }, - { BLKWRPLINT , "CIM block write to PL space", -1, 1 }, - { REQOVRLOOKUPINT , "CIM request FIFO overwrite", -1, 1 }, - { RSPOVRLOOKUPINT , "CIM response FIFO overwrite", -1, 1 }, - { TIMEOUTINT , "CIM PIF timeout", -1, 1 }, - { TIMEOUTMAINT , "CIM PIF MA timeout", -1, 1 }, + { RSVDSPACEINT_F, "CIM reserved space access", -1, 1 }, + { ILLTRANSINT_F, "CIM illegal transaction", -1, 1 }, + { ILLWRINT_F, "CIM illegal write", -1, 1 }, + { ILLRDINT_F, "CIM illegal read", -1, 1 }, + { ILLRDBEINT_F, "CIM illegal read BE", -1, 1 }, + { ILLWRBEINT_F, "CIM illegal write BE", -1, 1 }, + { SGLRDBOOTINT_F, "CIM single read from boot space", -1, 1 }, + { SGLWRBOOTINT_F, "CIM single write to boot space", -1, 1 }, + { BLKWRBOOTINT_F, "CIM block write to boot space", -1, 1 }, + { SGLRDFLASHINT_F, "CIM single read from flash space", -1, 1 }, + { SGLWRFLASHINT_F, "CIM single write to flash space", -1, 1 }, + { BLKWRFLASHINT_F, "CIM block write to flash space", -1, 1 }, + { SGLRDEEPROMINT_F, "CIM single EEPROM read", -1, 1 }, + { SGLWREEPROMINT_F, "CIM single EEPROM write", -1, 1 }, + { BLKRDEEPROMINT_F, "CIM block EEPROM read", -1, 1 }, + { BLKWREEPROMINT_F, "CIM block EEPROM write", -1, 1 }, + { SGLRDCTLINT_F, "CIM single read from CTL space", -1, 1 }, + { SGLWRCTLINT_F, "CIM single write to CTL space", -1, 1 }, + { BLKRDCTLINT_F, "CIM block read from CTL space", -1, 1 }, + { BLKWRCTLINT_F, "CIM block write to CTL space", -1, 1 }, + { SGLRDPLINT_F, "CIM single read from PL space", -1, 1 }, + { SGLWRPLINT_F, "CIM single write to PL space", -1, 1 }, + { BLKRDPLINT_F, "CIM block read from PL space", -1, 1 }, + { BLKWRPLINT_F, "CIM block write to PL space", -1, 1 }, + { REQOVRLOOKUPINT_F, "CIM request FIFO overwrite", -1, 1 }, + { RSPOVRLOOKUPINT_F, "CIM response FIFO overwrite", -1, 1 }, + { TIMEOUTINT_F, "CIM PIF timeout", -1, 1 }, + { TIMEOUTMAINT_F, "CIM PIF MA timeout", -1, 1 }, { 0, NULL, 0, 0 } }; int fat; - fat = csio_handle_intr_status(hw, CIM_HOST_INT_CAUSE, - cim_intr_info) + - csio_handle_intr_status(hw, CIM_HOST_UPACC_INT_CAUSE, - cim_upintr_info); + fat = csio_handle_intr_status(hw, CIM_HOST_INT_CAUSE_A, + cim_intr_info) + + csio_handle_intr_status(hw, CIM_HOST_UPACC_INT_CAUSE_A, + cim_upintr_info); if (fat) csio_hw_fatal_err(hw); } @@ -2813,7 +2822,7 @@ static void csio_ulprx_intr_handler(struct csio_hw *hw) { 0, NULL, 0, 0 } }; - if (csio_handle_intr_status(hw, ULP_RX_INT_CAUSE, ulprx_intr_info)) + if (csio_handle_intr_status(hw, ULP_RX_INT_CAUSE_A, ulprx_intr_info)) csio_hw_fatal_err(hw); } @@ -2823,19 +2832,19 @@ static void csio_ulprx_intr_handler(struct csio_hw *hw) static void csio_ulptx_intr_handler(struct csio_hw *hw) { static struct intr_info ulptx_intr_info[] = { - { PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1, + { PBL_BOUND_ERR_CH3_F, "ULPTX channel 3 PBL out of bounds", -1, 0 }, - { PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1, + { PBL_BOUND_ERR_CH2_F, "ULPTX channel 2 PBL out of bounds", -1, 0 }, - { PBL_BOUND_ERR_CH1, "ULPTX channel 1 PBL out of bounds", -1, + { PBL_BOUND_ERR_CH1_F, "ULPTX channel 1 PBL out of bounds", -1, 0 }, - { PBL_BOUND_ERR_CH0, "ULPTX channel 0 PBL out of bounds", -1, + { PBL_BOUND_ERR_CH0_F, "ULPTX channel 0 PBL out of bounds", -1, 0 }, { 0xfffffff, "ULPTX parity error", -1, 1 }, { 0, NULL, 0, 0 } }; - if (csio_handle_intr_status(hw, ULP_TX_INT_CAUSE, ulptx_intr_info)) + if (csio_handle_intr_status(hw, ULP_TX_INT_CAUSE_A, ulptx_intr_info)) csio_hw_fatal_err(hw); } @@ -2845,20 +2854,20 @@ static void csio_ulptx_intr_handler(struct csio_hw *hw) static void csio_pmtx_intr_handler(struct csio_hw *hw) { static struct intr_info pmtx_intr_info[] = { - { PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 }, - { PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 }, - { PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 }, - { ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 }, + { PCMD_LEN_OVFL0_F, "PMTX channel 0 pcmd too large", -1, 1 }, + { PCMD_LEN_OVFL1_F, "PMTX channel 1 pcmd too large", -1, 1 }, + { PCMD_LEN_OVFL2_F, "PMTX channel 2 pcmd too large", -1, 1 }, + { ZERO_C_CMD_ERROR_F, "PMTX 0-length pcmd", -1, 1 }, { 0xffffff0, "PMTX framing error", -1, 1 }, - { OESPI_PAR_ERROR, "PMTX oespi parity error", -1, 1 }, - { DB_OPTIONS_PAR_ERROR, "PMTX db_options parity error", -1, + { OESPI_PAR_ERROR_F, "PMTX oespi parity error", -1, 1 }, + { DB_OPTIONS_PAR_ERROR_F, "PMTX db_options parity error", -1, 1 }, - { ICSPI_PAR_ERROR, "PMTX icspi parity error", -1, 1 }, - { C_PCMD_PAR_ERROR, "PMTX c_pcmd parity error", -1, 1}, + { ICSPI_PAR_ERROR_F, "PMTX icspi parity error", -1, 1 }, + { PMTX_C_PCMD_PAR_ERROR_F, "PMTX c_pcmd parity error", -1, 1}, { 0, NULL, 0, 0 } }; - if (csio_handle_intr_status(hw, PM_TX_INT_CAUSE, pmtx_intr_info)) + if (csio_handle_intr_status(hw, PM_TX_INT_CAUSE_A, pmtx_intr_info)) csio_hw_fatal_err(hw); } @@ -2868,17 +2877,17 @@ static void csio_pmtx_intr_handler(struct csio_hw *hw) static void csio_pmrx_intr_handler(struct csio_hw *hw) { static struct intr_info pmrx_intr_info[] = { - { ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 }, + { ZERO_E_CMD_ERROR_F, "PMRX 0-length pcmd", -1, 1 }, { 0x3ffff0, "PMRX framing error", -1, 1 }, - { OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 }, - { DB_OPTIONS_PAR_ERROR, "PMRX db_options parity error", -1, + { OCSPI_PAR_ERROR_F, "PMRX ocspi parity error", -1, 1 }, + { DB_OPTIONS_PAR_ERROR_F, "PMRX db_options parity error", -1, 1 }, - { IESPI_PAR_ERROR, "PMRX iespi parity error", -1, 1 }, - { E_PCMD_PAR_ERROR, "PMRX e_pcmd parity error", -1, 1}, + { IESPI_PAR_ERROR_F, "PMRX iespi parity error", -1, 1 }, + { PMRX_E_PCMD_PAR_ERROR_F, "PMRX e_pcmd parity error", -1, 1}, { 0, NULL, 0, 0 } }; - if (csio_handle_intr_status(hw, PM_RX_INT_CAUSE, pmrx_intr_info)) + if (csio_handle_intr_status(hw, PM_RX_INT_CAUSE_A, pmrx_intr_info)) csio_hw_fatal_err(hw); } @@ -2888,16 +2897,16 @@ static void csio_pmrx_intr_handler(struct csio_hw *hw) static void csio_cplsw_intr_handler(struct csio_hw *hw) { static struct intr_info cplsw_intr_info[] = { - { CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 }, - { CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 }, - { TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 }, - { SGE_FRAMING_ERROR, "CPLSW SGE framing error", -1, 1 }, - { CIM_FRAMING_ERROR, "CPLSW CIM framing error", -1, 1 }, - { ZERO_SWITCH_ERROR, "CPLSW no-switch error", -1, 1 }, + { CIM_OP_MAP_PERR_F, "CPLSW CIM op_map parity error", -1, 1 }, + { CIM_OVFL_ERROR_F, "CPLSW CIM overflow", -1, 1 }, + { TP_FRAMING_ERROR_F, "CPLSW TP framing error", -1, 1 }, + { SGE_FRAMING_ERROR_F, "CPLSW SGE framing error", -1, 1 }, + { CIM_FRAMING_ERROR_F, "CPLSW CIM framing error", -1, 1 }, + { ZERO_SWITCH_ERROR_F, "CPLSW no-switch error", -1, 1 }, { 0, NULL, 0, 0 } }; - if (csio_handle_intr_status(hw, CPL_INTR_CAUSE, cplsw_intr_info)) + if (csio_handle_intr_status(hw, CPL_INTR_CAUSE_A, cplsw_intr_info)) csio_hw_fatal_err(hw); } @@ -2907,15 +2916,15 @@ static void csio_cplsw_intr_handler(struct csio_hw *hw) static void csio_le_intr_handler(struct csio_hw *hw) { static struct intr_info le_intr_info[] = { - { LIPMISS, "LE LIP miss", -1, 0 }, - { LIP0, "LE 0 LIP error", -1, 0 }, - { PARITYERR, "LE parity error", -1, 1 }, - { UNKNOWNCMD, "LE unknown command", -1, 1 }, - { REQQPARERR, "LE request queue parity error", -1, 1 }, + { LIPMISS_F, "LE LIP miss", -1, 0 }, + { LIP0_F, "LE 0 LIP error", -1, 0 }, + { PARITYERR_F, "LE parity error", -1, 1 }, + { UNKNOWNCMD_F, "LE unknown command", -1, 1 }, + { REQQPARERR_F, "LE request queue parity error", -1, 1 }, { 0, NULL, 0, 0 } }; - if (csio_handle_intr_status(hw, LE_DB_INT_CAUSE, le_intr_info)) + if (csio_handle_intr_status(hw, LE_DB_INT_CAUSE_A, le_intr_info)) csio_hw_fatal_err(hw); } @@ -2929,19 +2938,22 @@ static void csio_mps_intr_handler(struct csio_hw *hw) { 0, NULL, 0, 0 } }; static struct intr_info mps_tx_intr_info[] = { - { TPFIFO, "MPS Tx TP FIFO parity error", -1, 1 }, - { NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 }, - { TXDATAFIFO, "MPS Tx data FIFO parity error", -1, 1 }, - { TXDESCFIFO, "MPS Tx desc FIFO parity error", -1, 1 }, - { BUBBLE, "MPS Tx underflow", -1, 1 }, - { SECNTERR, "MPS Tx SOP/EOP error", -1, 1 }, - { FRMERR, "MPS Tx framing error", -1, 1 }, + { TPFIFO_V(TPFIFO_M), "MPS Tx TP FIFO parity error", -1, 1 }, + { NCSIFIFO_F, "MPS Tx NC-SI FIFO parity error", -1, 1 }, + { TXDATAFIFO_V(TXDATAFIFO_M), "MPS Tx data FIFO parity error", + -1, 1 }, + { TXDESCFIFO_V(TXDESCFIFO_M), "MPS Tx desc FIFO parity error", + -1, 1 }, + { BUBBLE_F, "MPS Tx underflow", -1, 1 }, + { SECNTERR_F, "MPS Tx SOP/EOP error", -1, 1 }, + { FRMERR_F, "MPS Tx framing error", -1, 1 }, { 0, NULL, 0, 0 } }; static struct intr_info mps_trc_intr_info[] = { - { FILTMEM, "MPS TRC filter parity error", -1, 1 }, - { PKTFIFO, "MPS TRC packet FIFO parity error", -1, 1 }, - { MISCPERR, "MPS TRC misc parity error", -1, 1 }, + { FILTMEM_V(FILTMEM_M), "MPS TRC filter parity error", -1, 1 }, + { PKTFIFO_V(PKTFIFO_M), "MPS TRC packet FIFO parity error", + -1, 1 }, + { MISCPERR_F, "MPS TRC misc parity error", -1, 1 }, { 0, NULL, 0, 0 } }; static struct intr_info mps_stat_sram_intr_info[] = { @@ -2957,36 +2969,37 @@ static void csio_mps_intr_handler(struct csio_hw *hw) { 0, NULL, 0, 0 } }; static struct intr_info mps_cls_intr_info[] = { - { MATCHSRAM, "MPS match SRAM parity error", -1, 1 }, - { MATCHTCAM, "MPS match TCAM parity error", -1, 1 }, - { HASHSRAM, "MPS hash SRAM parity error", -1, 1 }, + { MATCHSRAM_F, "MPS match SRAM parity error", -1, 1 }, + { MATCHTCAM_F, "MPS match TCAM parity error", -1, 1 }, + { HASHSRAM_F, "MPS hash SRAM parity error", -1, 1 }, { 0, NULL, 0, 0 } }; int fat; - fat = csio_handle_intr_status(hw, MPS_RX_PERR_INT_CAUSE, - mps_rx_intr_info) + - csio_handle_intr_status(hw, MPS_TX_INT_CAUSE, - mps_tx_intr_info) + - csio_handle_intr_status(hw, MPS_TRC_INT_CAUSE, - mps_trc_intr_info) + - csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_SRAM, - mps_stat_sram_intr_info) + - csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_TX_FIFO, - mps_stat_tx_intr_info) + - csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_RX_FIFO, - mps_stat_rx_intr_info) + - csio_handle_intr_status(hw, MPS_CLS_INT_CAUSE, - mps_cls_intr_info); + fat = csio_handle_intr_status(hw, MPS_RX_PERR_INT_CAUSE_A, + mps_rx_intr_info) + + csio_handle_intr_status(hw, MPS_TX_INT_CAUSE_A, + mps_tx_intr_info) + + csio_handle_intr_status(hw, MPS_TRC_INT_CAUSE_A, + mps_trc_intr_info) + + csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_SRAM_A, + mps_stat_sram_intr_info) + + csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_TX_FIFO_A, + mps_stat_tx_intr_info) + + csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_RX_FIFO_A, + mps_stat_rx_intr_info) + + csio_handle_intr_status(hw, MPS_CLS_INT_CAUSE_A, + mps_cls_intr_info); - csio_wr_reg32(hw, 0, MPS_INT_CAUSE); - csio_rd_reg32(hw, MPS_INT_CAUSE); /* flush */ + csio_wr_reg32(hw, 0, MPS_INT_CAUSE_A); + csio_rd_reg32(hw, MPS_INT_CAUSE_A); /* flush */ if (fat) csio_hw_fatal_err(hw); } -#define MEM_INT_MASK (PERR_INT_CAUSE | ECC_CE_INT_CAUSE | ECC_UE_INT_CAUSE) +#define MEM_INT_MASK (PERR_INT_CAUSE_F | ECC_CE_INT_CAUSE_F | \ + ECC_UE_INT_CAUSE_F) /* * EDC/MC interrupt handler. @@ -2998,28 +3011,28 @@ static void csio_mem_intr_handler(struct csio_hw *hw, int idx) unsigned int addr, cnt_addr, v; if (idx <= MEM_EDC1) { - addr = EDC_REG(EDC_INT_CAUSE, idx); - cnt_addr = EDC_REG(EDC_ECC_STATUS, idx); + addr = EDC_REG(EDC_INT_CAUSE_A, idx); + cnt_addr = EDC_REG(EDC_ECC_STATUS_A, idx); } else { - addr = MC_INT_CAUSE; - cnt_addr = MC_ECC_STATUS; + addr = MC_INT_CAUSE_A; + cnt_addr = MC_ECC_STATUS_A; } v = csio_rd_reg32(hw, addr) & MEM_INT_MASK; - if (v & PERR_INT_CAUSE) + if (v & PERR_INT_CAUSE_F) csio_fatal(hw, "%s FIFO parity error\n", name[idx]); - if (v & ECC_CE_INT_CAUSE) { - uint32_t cnt = ECC_CECNT_GET(csio_rd_reg32(hw, cnt_addr)); + if (v & ECC_CE_INT_CAUSE_F) { + uint32_t cnt = ECC_CECNT_G(csio_rd_reg32(hw, cnt_addr)); - csio_wr_reg32(hw, ECC_CECNT_MASK, cnt_addr); + csio_wr_reg32(hw, ECC_CECNT_V(ECC_CECNT_M), cnt_addr); csio_warn(hw, "%u %s correctable ECC data error%s\n", cnt, name[idx], cnt > 1 ? "s" : ""); } - if (v & ECC_UE_INT_CAUSE) + if (v & ECC_UE_INT_CAUSE_F) csio_fatal(hw, "%s uncorrectable ECC data error\n", name[idx]); csio_wr_reg32(hw, v, addr); - if (v & (PERR_INT_CAUSE | ECC_UE_INT_CAUSE)) + if (v & (PERR_INT_CAUSE_F | ECC_UE_INT_CAUSE_F)) csio_hw_fatal_err(hw); } @@ -3028,18 +3041,18 @@ static void csio_mem_intr_handler(struct csio_hw *hw, int idx) */ static void csio_ma_intr_handler(struct csio_hw *hw) { - uint32_t v, status = csio_rd_reg32(hw, MA_INT_CAUSE); + uint32_t v, status = csio_rd_reg32(hw, MA_INT_CAUSE_A); - if (status & MEM_PERR_INT_CAUSE) + if (status & MEM_PERR_INT_CAUSE_F) csio_fatal(hw, "MA parity error, parity status %#x\n", - csio_rd_reg32(hw, MA_PARITY_ERROR_STATUS)); - if (status & MEM_WRAP_INT_CAUSE) { - v = csio_rd_reg32(hw, MA_INT_WRAP_STATUS); + csio_rd_reg32(hw, MA_PARITY_ERROR_STATUS_A)); + if (status & MEM_WRAP_INT_CAUSE_F) { + v = csio_rd_reg32(hw, MA_INT_WRAP_STATUS_A); csio_fatal(hw, "MA address wrap-around error by client %u to address %#x\n", - MEM_WRAP_CLIENT_NUM_GET(v), MEM_WRAP_ADDRESS_GET(v) << 4); + MEM_WRAP_CLIENT_NUM_G(v), MEM_WRAP_ADDRESS_G(v) << 4); } - csio_wr_reg32(hw, status, MA_INT_CAUSE); + csio_wr_reg32(hw, status, MA_INT_CAUSE_A); csio_hw_fatal_err(hw); } @@ -3049,13 +3062,13 @@ static void csio_ma_intr_handler(struct csio_hw *hw) static void csio_smb_intr_handler(struct csio_hw *hw) { static struct intr_info smb_intr_info[] = { - { MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 }, - { MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 }, - { SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 }, + { MSTTXFIFOPARINT_F, "SMB master Tx FIFO parity error", -1, 1 }, + { MSTRXFIFOPARINT_F, "SMB master Rx FIFO parity error", -1, 1 }, + { SLVFIFOPARINT_F, "SMB slave FIFO parity error", -1, 1 }, { 0, NULL, 0, 0 } }; - if (csio_handle_intr_status(hw, SMB_INT_CAUSE, smb_intr_info)) + if (csio_handle_intr_status(hw, SMB_INT_CAUSE_A, smb_intr_info)) csio_hw_fatal_err(hw); } @@ -3065,14 +3078,14 @@ static void csio_smb_intr_handler(struct csio_hw *hw) static void csio_ncsi_intr_handler(struct csio_hw *hw) { static struct intr_info ncsi_intr_info[] = { - { CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 }, - { MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 }, - { TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 }, - { RXFIFO_PRTY_ERR, "NC-SI Rx FIFO parity error", -1, 1 }, + { CIM_DM_PRTY_ERR_F, "NC-SI CIM parity error", -1, 1 }, + { MPS_DM_PRTY_ERR_F, "NC-SI MPS parity error", -1, 1 }, + { TXFIFO_PRTY_ERR_F, "NC-SI Tx FIFO parity error", -1, 1 }, + { RXFIFO_PRTY_ERR_F, "NC-SI Rx FIFO parity error", -1, 1 }, { 0, NULL, 0, 0 } }; - if (csio_handle_intr_status(hw, NCSI_INT_CAUSE, ncsi_intr_info)) + if (csio_handle_intr_status(hw, NCSI_INT_CAUSE_A, ncsi_intr_info)) csio_hw_fatal_err(hw); } @@ -3081,17 +3094,17 @@ static void csio_ncsi_intr_handler(struct csio_hw *hw) */ static void csio_xgmac_intr_handler(struct csio_hw *hw, int port) { - uint32_t v = csio_rd_reg32(hw, CSIO_MAC_INT_CAUSE_REG(hw, port)); + uint32_t v = csio_rd_reg32(hw, T5_PORT_REG(port, MAC_PORT_INT_CAUSE_A)); - v &= TXFIFO_PRTY_ERR | RXFIFO_PRTY_ERR; + v &= TXFIFO_PRTY_ERR_F | RXFIFO_PRTY_ERR_F; if (!v) return; - if (v & TXFIFO_PRTY_ERR) + if (v & TXFIFO_PRTY_ERR_F) csio_fatal(hw, "XGMAC %d Tx FIFO parity error\n", port); - if (v & RXFIFO_PRTY_ERR) + if (v & RXFIFO_PRTY_ERR_F) csio_fatal(hw, "XGMAC %d Rx FIFO parity error\n", port); - csio_wr_reg32(hw, v, CSIO_MAC_INT_CAUSE_REG(hw, port)); + csio_wr_reg32(hw, v, T5_PORT_REG(port, MAC_PORT_INT_CAUSE_A)); csio_hw_fatal_err(hw); } @@ -3101,12 +3114,12 @@ static void csio_xgmac_intr_handler(struct csio_hw *hw, int port) static void csio_pl_intr_handler(struct csio_hw *hw) { static struct intr_info pl_intr_info[] = { - { FATALPERR, "T4 fatal parity error", -1, 1 }, - { PERRVFID, "PL VFID_MAP parity error", -1, 1 }, + { FATALPERR_F, "T4 fatal parity error", -1, 1 }, + { PERRVFID_F, "PL VFID_MAP parity error", -1, 1 }, { 0, NULL, 0, 0 } }; - if (csio_handle_intr_status(hw, PL_PL_INT_CAUSE, pl_intr_info)) + if (csio_handle_intr_status(hw, PL_PL_INT_CAUSE_A, pl_intr_info)) csio_hw_fatal_err(hw); } @@ -3121,7 +3134,7 @@ static void csio_pl_intr_handler(struct csio_hw *hw) int csio_hw_slow_intr_handler(struct csio_hw *hw) { - uint32_t cause = csio_rd_reg32(hw, PL_INT_CAUSE); + uint32_t cause = csio_rd_reg32(hw, PL_INT_CAUSE_A); if (!(cause & CSIO_GLBL_INTR_MASK)) { CSIO_INC_STATS(hw, n_plint_unexp); @@ -3132,75 +3145,75 @@ csio_hw_slow_intr_handler(struct csio_hw *hw) CSIO_INC_STATS(hw, n_plint_cnt); - if (cause & CIM) + if (cause & CIM_F) csio_cim_intr_handler(hw); - if (cause & MPS) + if (cause & MPS_F) csio_mps_intr_handler(hw); - if (cause & NCSI) + if (cause & NCSI_F) csio_ncsi_intr_handler(hw); - if (cause & PL) + if (cause & PL_F) csio_pl_intr_handler(hw); - if (cause & SMB) + if (cause & SMB_F) csio_smb_intr_handler(hw); - if (cause & XGMAC0) + if (cause & XGMAC0_F) csio_xgmac_intr_handler(hw, 0); - if (cause & XGMAC1) + if (cause & XGMAC1_F) csio_xgmac_intr_handler(hw, 1); - if (cause & XGMAC_KR0) + if (cause & XGMAC_KR0_F) csio_xgmac_intr_handler(hw, 2); - if (cause & XGMAC_KR1) + if (cause & XGMAC_KR1_F) csio_xgmac_intr_handler(hw, 3); - if (cause & PCIE) + if (cause & PCIE_F) hw->chip_ops->chip_pcie_intr_handler(hw); - if (cause & MC) + if (cause & MC_F) csio_mem_intr_handler(hw, MEM_MC); - if (cause & EDC0) + if (cause & EDC0_F) csio_mem_intr_handler(hw, MEM_EDC0); - if (cause & EDC1) + if (cause & EDC1_F) csio_mem_intr_handler(hw, MEM_EDC1); - if (cause & LE) + if (cause & LE_F) csio_le_intr_handler(hw); - if (cause & TP) + if (cause & TP_F) csio_tp_intr_handler(hw); - if (cause & MA) + if (cause & MA_F) csio_ma_intr_handler(hw); - if (cause & PM_TX) + if (cause & PM_TX_F) csio_pmtx_intr_handler(hw); - if (cause & PM_RX) + if (cause & PM_RX_F) csio_pmrx_intr_handler(hw); - if (cause & ULP_RX) + if (cause & ULP_RX_F) csio_ulprx_intr_handler(hw); - if (cause & CPL_SWITCH) + if (cause & CPL_SWITCH_F) csio_cplsw_intr_handler(hw); - if (cause & SGE) + if (cause & SGE_F) csio_sge_intr_handler(hw); - if (cause & ULP_TX) + if (cause & ULP_TX_F) csio_ulptx_intr_handler(hw); /* Clear the interrupts just processed for which we are the master. */ - csio_wr_reg32(hw, cause & CSIO_GLBL_INTR_MASK, PL_INT_CAUSE); - csio_rd_reg32(hw, PL_INT_CAUSE); /* flush */ + csio_wr_reg32(hw, cause & CSIO_GLBL_INTR_MASK, PL_INT_CAUSE_A); + csio_rd_reg32(hw, PL_INT_CAUSE_A); /* flush */ return 1; } @@ -3840,13 +3853,7 @@ csio_hw_set_description(struct csio_hw *hw, uint16_t ven_id, uint16_t dev_id) prot_type = (dev_id & CSIO_ASIC_DEVID_PROTO_MASK); adap_type = (dev_id & CSIO_ASIC_DEVID_TYPE_MASK); - if (prot_type == CSIO_T4_FCOE_ASIC) { - memcpy(hw->hw_ver, - csio_t4_fcoe_adapters[adap_type].model_no, 16); - memcpy(hw->model_desc, - csio_t4_fcoe_adapters[adap_type].description, - 32); - } else if (prot_type == CSIO_T5_FCOE_ASIC) { + if (prot_type == CSIO_T5_FCOE_ASIC) { memcpy(hw->hw_ver, csio_t5_fcoe_adapters[adap_type].model_no, 16); memcpy(hw->model_desc, @@ -3883,8 +3890,8 @@ csio_hw_init(struct csio_hw *hw) strcpy(hw->name, CSIO_HW_NAME); - /* Initialize the HW chip ops with T4/T5 specific ops */ - hw->chip_ops = csio_is_t4(hw->chip_id) ? &t4_ops : &t5_ops; + /* Initialize the HW chip ops T5 specific ops */ + hw->chip_ops = &t5_ops; /* Set the model & its description */ diff --git a/drivers/scsi/csiostor/csio_hw.h b/drivers/scsi/csiostor/csio_hw.h index 68248da1b9af..029bef82c057 100644 --- a/drivers/scsi/csiostor/csio_hw.h +++ b/drivers/scsi/csiostor/csio_hw.h @@ -48,6 +48,7 @@ #include #include +#include "t4_hw.h" #include "csio_hw_chip.h" #include "csio_wr.h" #include "csio_mb.h" @@ -117,10 +118,10 @@ extern int csio_msi; #define CSIO_ASIC_DEVID_PROTO_MASK 0xFF00 #define CSIO_ASIC_DEVID_TYPE_MASK 0x00FF -#define CSIO_GLBL_INTR_MASK (CIM | MPS | PL | PCIE | MC | EDC0 | \ - EDC1 | LE | TP | MA | PM_TX | PM_RX | \ - ULP_RX | CPL_SWITCH | SGE | \ - ULP_TX | SF) +#define CSIO_GLBL_INTR_MASK (CIM_F | MPS_F | PL_F | PCIE_F | MC_F | \ + EDC0_F | EDC1_F | LE_F | TP_F | MA_F | \ + PM_TX_F | PM_RX_F | ULP_RX_F | \ + CPL_SWITCH_F | SGE_F | ULP_TX_F | SF_F) /* * Hard parameters used to initialize the card in the absence of a @@ -174,16 +175,12 @@ struct csio_evt_msg { }; enum { - EEPROMVSIZE = 32768, /* Serial EEPROM virtual address space size */ SERNUM_LEN = 16, /* Serial # length */ EC_LEN = 16, /* E/C length */ ID_LEN = 16, /* ID length */ - TRACE_LEN = 112, /* length of trace data and mask */ }; enum { - SF_PAGE_SIZE = 256, /* serial flash page size */ - SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */ SF_SIZE = SF_SEC_SIZE * 16, /* serial flash size */ }; @@ -199,39 +196,8 @@ enum { SF_RD_DATA_FAST = 0xb, /* read flash */ SF_RD_ID = 0x9f, /* read ID */ SF_ERASE_SECTOR = 0xd8, /* erase sector */ - - FW_START_SEC = 8, /* first flash sector for FW */ - FW_END_SEC = 15, /* last flash sector for FW */ - FW_IMG_START = FW_START_SEC * SF_SEC_SIZE, - FW_MAX_SIZE = (FW_END_SEC - FW_START_SEC + 1) * SF_SEC_SIZE, - - FLASH_CFG_MAX_SIZE = 0x10000 , /* max size of the flash config file*/ - FLASH_CFG_OFFSET = 0x1f0000, - FLASH_CFG_START_SEC = FLASH_CFG_OFFSET / SF_SEC_SIZE, }; -/* - * Flash layout. - */ -#define FLASH_START(start) ((start) * SF_SEC_SIZE) -#define FLASH_MAX_SIZE(nsecs) ((nsecs) * SF_SEC_SIZE) - -enum { - /* - * Location of firmware image in FLASH. - */ - FLASH_FW_START_SEC = 8, - FLASH_FW_NSECS = 8, - FLASH_FW_START = FLASH_START(FLASH_FW_START_SEC), - FLASH_FW_MAX_SIZE = FLASH_MAX_SIZE(FLASH_FW_NSECS), - - /* Location of Firmware Configuration File in FLASH. */ - FLASH_CFG_START = FLASH_START(FLASH_CFG_START_SEC), -}; - -#undef FLASH_START -#undef FLASH_MAX_SIZE - /* Management module */ enum { CSIO_MGMT_EQ_WRSIZE = 512, @@ -482,11 +448,6 @@ struct csio_hw { uint32_t tp_vers; char chip_ver; uint16_t chip_id; /* Tells T4/T5 chip */ - uint32_t cfg_finiver; - uint32_t cfg_finicsum; - uint32_t cfg_cfcsum; - uint8_t cfg_csum_status; - uint8_t cfg_store; enum csio_dev_state fw_state; struct csio_vpd vpd; diff --git a/drivers/scsi/csiostor/csio_hw_chip.h b/drivers/scsi/csiostor/csio_hw_chip.h index 4752fed476df..b56a11d817be 100644 --- a/drivers/scsi/csiostor/csio_hw_chip.h +++ b/drivers/scsi/csiostor/csio_hw_chip.h @@ -37,24 +37,27 @@ #include "csio_defs.h" /* Define MACRO values */ -#define CSIO_HW_T4 0x4000 -#define CSIO_T4_FCOE_ASIC 0x4600 #define CSIO_HW_T5 0x5000 #define CSIO_T5_FCOE_ASIC 0x5600 #define CSIO_HW_CHIP_MASK 0xF000 -#define T4_REGMAP_SIZE (160 * 1024) #define T5_REGMAP_SIZE (332 * 1024) -#define FW_FNAME_T4 "cxgb4/t4fw.bin" #define FW_FNAME_T5 "cxgb4/t5fw.bin" -#define FW_CFG_NAME_T4 "cxgb4/t4-config.txt" #define FW_CFG_NAME_T5 "cxgb4/t5-config.txt" -/* Define static functions */ -static inline int csio_is_t4(uint16_t chip) -{ - return (chip == CSIO_HW_T4); -} +#define CHELSIO_CHIP_CODE(version, revision) (((version) << 4) | (revision)) +#define CHELSIO_CHIP_FPGA 0x100 +#define CHELSIO_CHIP_VERSION(code) (((code) >> 12) & 0xf) +#define CHELSIO_CHIP_RELEASE(code) ((code) & 0xf) + +#define CHELSIO_T5 0x5 + +enum chip_type { + T5_A0 = CHELSIO_CHIP_CODE(CHELSIO_T5, 0), + T5_A1 = CHELSIO_CHIP_CODE(CHELSIO_T5, 1), + T5_FIRST_REV = T5_A0, + T5_LAST_REV = T5_A1, +}; static inline int csio_is_t5(uint16_t chip) { @@ -65,30 +68,22 @@ static inline int csio_is_t5(uint16_t chip) #define CSIO_DEVICE(devid, idx) \ { PCI_VENDOR_ID_CHELSIO, (devid), PCI_ANY_ID, PCI_ANY_ID, 0, 0, (idx) } -#define CSIO_HW_PIDX(hw, index) \ - (csio_is_t4(hw->chip_id) ? (PIDX(index)) : \ - (PIDX_T5(index) | DBTYPE(1U))) +#include "t4fw_api.h" +#include "t4fw_version.h" -#define CSIO_HW_LP_INT_THRESH(hw, val) \ - (csio_is_t4(hw->chip_id) ? (LP_INT_THRESH(val)) : \ - (V_LP_INT_THRESH_T5(val))) +#define FW_VERSION(chip) ( \ + FW_HDR_FW_VER_MAJOR_G(chip##FW_VERSION_MAJOR) | \ + FW_HDR_FW_VER_MINOR_G(chip##FW_VERSION_MINOR) | \ + FW_HDR_FW_VER_MICRO_G(chip##FW_VERSION_MICRO) | \ + FW_HDR_FW_VER_BUILD_G(chip##FW_VERSION_BUILD)) +#define FW_INTFVER(chip, intf) (FW_HDR_INTFVER_##intf) -#define CSIO_HW_M_LP_INT_THRESH(hw) \ - (csio_is_t4(hw->chip_id) ? (LP_INT_THRESH_MASK) : (M_LP_INT_THRESH_T5)) - -#define CSIO_MAC_INT_CAUSE_REG(hw, port) \ - (csio_is_t4(hw->chip_id) ? (PORT_REG(port, XGMAC_PORT_INT_CAUSE)) : \ - (T5_PORT_REG(port, MAC_PORT_INT_CAUSE))) - -#define FW_VERSION_MAJOR(hw) (csio_is_t4(hw->chip_id) ? 1 : 0) -#define FW_VERSION_MINOR(hw) (csio_is_t4(hw->chip_id) ? 2 : 0) -#define FW_VERSION_MICRO(hw) (csio_is_t4(hw->chip_id) ? 8 : 0) - -#define CSIO_FW_FNAME(hw) \ - (csio_is_t4(hw->chip_id) ? FW_FNAME_T4 : FW_FNAME_T5) - -#define CSIO_CF_FNAME(hw) \ - (csio_is_t4(hw->chip_id) ? FW_CFG_NAME_T4 : FW_CFG_NAME_T5) +struct fw_info { + u8 chip; + char *fs_name; + char *fw_mod_name; + struct fw_hdr fw_hdr; +}; /* Declare ENUMS */ enum { MEM_EDC0, MEM_EDC1, MEM_MC, MEM_MC0 = MEM_MC, MEM_MC1 }; @@ -96,7 +91,6 @@ enum { MEM_EDC0, MEM_EDC1, MEM_MC, MEM_MC0 = MEM_MC, MEM_MC1 }; enum { MEMWIN_APERTURE = 2048, MEMWIN_BASE = 0x1b800, - MEMWIN_CSIOSTOR = 6, /* PCI-e Memory Window access */ }; /* Slow path handlers */ @@ -122,7 +116,6 @@ struct csio_hw_chip_ops { void (*chip_dfs_create_ext_mem)(struct csio_hw *); }; -extern struct csio_hw_chip_ops t4_ops; extern struct csio_hw_chip_ops t5_ops; #endif /* #ifndef __CSIO_HW_CHIP_H__ */ diff --git a/drivers/scsi/csiostor/csio_hw_t4.c b/drivers/scsi/csiostor/csio_hw_t4.c deleted file mode 100644 index 95d831857640..000000000000 --- a/drivers/scsi/csiostor/csio_hw_t4.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * This file is part of the Chelsio FCoE driver for Linux. - * - * Copyright (c) 2008-2013 Chelsio Communications, Inc. 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 - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "csio_hw.h" -#include "csio_init.h" - -/* - * Return the specified PCI-E Configuration Space register from our Physical - * Function. We try first via a Firmware LDST Command since we prefer to let - * the firmware own all of these registers, but if that fails we go for it - * directly ourselves. - */ -static uint32_t -csio_t4_read_pcie_cfg4(struct csio_hw *hw, int reg) -{ - u32 val = 0; - struct csio_mb *mbp; - int rv; - struct fw_ldst_cmd *ldst_cmd; - - mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); - if (!mbp) { - CSIO_INC_STATS(hw, n_err_nomem); - pci_read_config_dword(hw->pdev, reg, &val); - return val; - } - - csio_mb_ldst(hw, mbp, CSIO_MB_DEFAULT_TMO, reg); - rv = csio_mb_issue(hw, mbp); - - /* - * If the LDST Command suucceeded, exctract the returned register - * value. Otherwise read it directly ourself. - */ - if (rv == 0) { - ldst_cmd = (struct fw_ldst_cmd *)(mbp->mb); - val = ntohl(ldst_cmd->u.pcie.data[0]); - } else - pci_read_config_dword(hw->pdev, reg, &val); - - mempool_free(mbp, hw->mb_mempool); - - return val; -} - -static int -csio_t4_set_mem_win(struct csio_hw *hw, uint32_t win) -{ - u32 bar0; - u32 mem_win_base; - - /* - * Truncation intentional: we only read the bottom 32-bits of the - * 64-bit BAR0/BAR1 ... We use the hardware backdoor mechanism to - * read BAR0 instead of using pci_resource_start() because we could be - * operating from within a Virtual Machine which is trapping our - * accesses to our Configuration Space and we need to set up the PCI-E - * Memory Window decoders with the actual addresses which will be - * coming across the PCI-E link. - */ - bar0 = csio_t4_read_pcie_cfg4(hw, PCI_BASE_ADDRESS_0); - bar0 &= PCI_BASE_ADDRESS_MEM_MASK; - - mem_win_base = bar0 + MEMWIN_BASE; - - /* - * Set up memory window for accessing adapter memory ranges. (Read - * back MA register to ensure that changes propagate before we attempt - * to use the new values.) - */ - csio_wr_reg32(hw, mem_win_base | BIR(0) | - WINDOW(ilog2(MEMWIN_APERTURE) - 10), - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win)); - csio_rd_reg32(hw, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win)); - return 0; -} - -/* - * Interrupt handler for the PCIE module. - */ -static void -csio_t4_pcie_intr_handler(struct csio_hw *hw) -{ - static struct intr_info sysbus_intr_info[] = { - { RNPP, "RXNP array parity error", -1, 1 }, - { RPCP, "RXPC array parity error", -1, 1 }, - { RCIP, "RXCIF array parity error", -1, 1 }, - { RCCP, "Rx completions control array parity error", -1, 1 }, - { RFTP, "RXFT array parity error", -1, 1 }, - { 0, NULL, 0, 0 } - }; - static struct intr_info pcie_port_intr_info[] = { - { TPCP, "TXPC array parity error", -1, 1 }, - { TNPP, "TXNP array parity error", -1, 1 }, - { TFTP, "TXFT array parity error", -1, 1 }, - { TCAP, "TXCA array parity error", -1, 1 }, - { TCIP, "TXCIF array parity error", -1, 1 }, - { RCAP, "RXCA array parity error", -1, 1 }, - { OTDD, "outbound request TLP discarded", -1, 1 }, - { RDPE, "Rx data parity error", -1, 1 }, - { TDUE, "Tx uncorrectable data error", -1, 1 }, - { 0, NULL, 0, 0 } - }; - - static struct intr_info pcie_intr_info[] = { - { MSIADDRLPERR, "MSI AddrL parity error", -1, 1 }, - { MSIADDRHPERR, "MSI AddrH parity error", -1, 1 }, - { MSIDATAPERR, "MSI data parity error", -1, 1 }, - { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 }, - { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 }, - { MSIXDATAPERR, "MSI-X data parity error", -1, 1 }, - { MSIXDIPERR, "MSI-X DI parity error", -1, 1 }, - { PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 }, - { PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 }, - { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 }, - { CCNTPERR, "PCI CMD channel count parity error", -1, 1 }, - { CREQPERR, "PCI CMD channel request parity error", -1, 1 }, - { CRSPPERR, "PCI CMD channel response parity error", -1, 1 }, - { DCNTPERR, "PCI DMA channel count parity error", -1, 1 }, - { DREQPERR, "PCI DMA channel request parity error", -1, 1 }, - { DRSPPERR, "PCI DMA channel response parity error", -1, 1 }, - { HCNTPERR, "PCI HMA channel count parity error", -1, 1 }, - { HREQPERR, "PCI HMA channel request parity error", -1, 1 }, - { HRSPPERR, "PCI HMA channel response parity error", -1, 1 }, - { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 }, - { FIDPERR, "PCI FID parity error", -1, 1 }, - { INTXCLRPERR, "PCI INTx clear parity error", -1, 1 }, - { MATAGPERR, "PCI MA tag parity error", -1, 1 }, - { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 }, - { RXCPLPERR, "PCI Rx completion parity error", -1, 1 }, - { RXWRPERR, "PCI Rx write parity error", -1, 1 }, - { RPLPERR, "PCI replay buffer parity error", -1, 1 }, - { PCIESINT, "PCI core secondary fault", -1, 1 }, - { PCIEPINT, "PCI core primary fault", -1, 1 }, - { UNXSPLCPLERR, "PCI unexpected split completion error", -1, - 0 }, - { 0, NULL, 0, 0 } - }; - - int fat; - fat = csio_handle_intr_status(hw, - PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS, - sysbus_intr_info) + - csio_handle_intr_status(hw, - PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS, - pcie_port_intr_info) + - csio_handle_intr_status(hw, PCIE_INT_CAUSE, pcie_intr_info); - if (fat) - csio_hw_fatal_err(hw); -} - -/* - * csio_t4_flash_cfg_addr - return the address of the flash configuration file - * @hw: the HW module - * - * Return the address within the flash where the Firmware Configuration - * File is stored. - */ -static unsigned int -csio_t4_flash_cfg_addr(struct csio_hw *hw) -{ - return FLASH_CFG_OFFSET; -} - -/* - * csio_t4_mc_read - read from MC through backdoor accesses - * @hw: the hw module - * @idx: not used for T4 adapter - * @addr: address of first byte requested - * @data: 64 bytes of data containing the requested address - * @ecc: where to store the corresponding 64-bit ECC word - * - * Read 64 bytes of data from MC starting at a 64-byte-aligned address - * that covers the requested address @addr. If @parity is not %NULL it - * is assigned the 64-bit ECC word for the read data. - */ -static int -csio_t4_mc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data, - uint64_t *ecc) -{ - int i; - - if (csio_rd_reg32(hw, MC_BIST_CMD) & START_BIST) - return -EBUSY; - csio_wr_reg32(hw, addr & ~0x3fU, MC_BIST_CMD_ADDR); - csio_wr_reg32(hw, 64, MC_BIST_CMD_LEN); - csio_wr_reg32(hw, 0xc, MC_BIST_DATA_PATTERN); - csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1), - MC_BIST_CMD); - i = csio_hw_wait_op_done_val(hw, MC_BIST_CMD, START_BIST, - 0, 10, 1, NULL); - if (i) - return i; - -#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i) - - for (i = 15; i >= 0; i--) - *data++ = htonl(csio_rd_reg32(hw, MC_DATA(i))); - if (ecc) - *ecc = csio_rd_reg64(hw, MC_DATA(16)); -#undef MC_DATA - return 0; -} - -/* - * csio_t4_edc_read - read from EDC through backdoor accesses - * @hw: the hw module - * @idx: which EDC to access - * @addr: address of first byte requested - * @data: 64 bytes of data containing the requested address - * @ecc: where to store the corresponding 64-bit ECC word - * - * Read 64 bytes of data from EDC starting at a 64-byte-aligned address - * that covers the requested address @addr. If @parity is not %NULL it - * is assigned the 64-bit ECC word for the read data. - */ -static int -csio_t4_edc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data, - uint64_t *ecc) -{ - int i; - - idx *= EDC_STRIDE; - if (csio_rd_reg32(hw, EDC_BIST_CMD + idx) & START_BIST) - return -EBUSY; - csio_wr_reg32(hw, addr & ~0x3fU, EDC_BIST_CMD_ADDR + idx); - csio_wr_reg32(hw, 64, EDC_BIST_CMD_LEN + idx); - csio_wr_reg32(hw, 0xc, EDC_BIST_DATA_PATTERN + idx); - csio_wr_reg32(hw, BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST, - EDC_BIST_CMD + idx); - i = csio_hw_wait_op_done_val(hw, EDC_BIST_CMD + idx, START_BIST, - 0, 10, 1, NULL); - if (i) - return i; - -#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx) - - for (i = 15; i >= 0; i--) - *data++ = htonl(csio_rd_reg32(hw, EDC_DATA(i))); - if (ecc) - *ecc = csio_rd_reg64(hw, EDC_DATA(16)); -#undef EDC_DATA - return 0; -} - -/* - * csio_t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window - * @hw: the csio_hw - * @win: PCI-E memory Window to use - * @mtype: memory type: MEM_EDC0, MEM_EDC1, MEM_MC0 (or MEM_MC) or MEM_MC1 - * @addr: address within indicated memory type - * @len: amount of memory to transfer - * @buf: host memory buffer - * @dir: direction of transfer 1 => read, 0 => write - * - * Reads/writes an [almost] arbitrary memory region in the firmware: the - * firmware memory address, length and host buffer must be aligned on - * 32-bit boudaries. The memory is transferred as a raw byte sequence - * from/to the firmware's memory. If this memory contains data - * structures which contain multi-byte integers, it's the callers - * responsibility to perform appropriate byte order conversions. - */ -static int -csio_t4_memory_rw(struct csio_hw *hw, u32 win, int mtype, u32 addr, - u32 len, uint32_t *buf, int dir) -{ - u32 pos, start, offset, memoffset, bar0; - u32 edc_size, mc_size, mem_reg, mem_aperture, mem_base; - - /* - * Argument sanity checks ... - */ - if ((addr & 0x3) || (len & 0x3)) - return -EINVAL; - - /* Offset into the region of memory which is being accessed - * MEM_EDC0 = 0 - * MEM_EDC1 = 1 - * MEM_MC = 2 -- T4 - */ - edc_size = EDRAM0_SIZE_G(csio_rd_reg32(hw, MA_EDRAM0_BAR_A)); - if (mtype != MEM_MC1) - memoffset = (mtype * (edc_size * 1024 * 1024)); - else { - mc_size = EXT_MEM_SIZE_G(csio_rd_reg32(hw, - MA_EXT_MEMORY_BAR_A)); - memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024; - } - - /* Determine the PCIE_MEM_ACCESS_OFFSET */ - addr = addr + memoffset; - - /* - * Each PCI-E Memory Window is programmed with a window size -- or - * "aperture" -- which controls the granularity of its mapping onto - * adapter memory. We need to grab that aperture in order to know - * how to use the specified window. The window is also programmed - * with the base address of the Memory Window in BAR0's address - * space. For T4 this is an absolute PCI-E Bus Address. For T5 - * the address is relative to BAR0. - */ - mem_reg = csio_rd_reg32(hw, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win)); - mem_aperture = 1 << (WINDOW(mem_reg) + 10); - mem_base = GET_PCIEOFST(mem_reg) << 10; - - bar0 = csio_t4_read_pcie_cfg4(hw, PCI_BASE_ADDRESS_0); - bar0 &= PCI_BASE_ADDRESS_MEM_MASK; - mem_base -= bar0; - - start = addr & ~(mem_aperture-1); - offset = addr - start; - - csio_dbg(hw, "csio_t4_memory_rw: mem_reg: 0x%x, mem_aperture: 0x%x\n", - mem_reg, mem_aperture); - csio_dbg(hw, "csio_t4_memory_rw: mem_base: 0x%x, mem_offset: 0x%x\n", - mem_base, memoffset); - csio_dbg(hw, "csio_t4_memory_rw: bar0: 0x%x, start:0x%x, offset:0x%x\n", - bar0, start, offset); - csio_dbg(hw, "csio_t4_memory_rw: mtype: %d, addr: 0x%x, len: %d\n", - mtype, addr, len); - - for (pos = start; len > 0; pos += mem_aperture, offset = 0) { - /* - * Move PCI-E Memory Window to our current transfer - * position. Read it back to ensure that changes propagate - * before we attempt to use the new value. - */ - csio_wr_reg32(hw, pos, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win)); - csio_rd_reg32(hw, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win)); - - while (offset < mem_aperture && len > 0) { - if (dir) - *buf++ = csio_rd_reg32(hw, mem_base + offset); - else - csio_wr_reg32(hw, *buf++, mem_base + offset); - - offset += sizeof(__be32); - len -= sizeof(__be32); - } - } - return 0; -} - -/* - * csio_t4_dfs_create_ext_mem - setup debugfs for MC to read the values - * @hw: the csio_hw - * - * This function creates files in the debugfs with external memory region MC. - */ -static void -csio_t4_dfs_create_ext_mem(struct csio_hw *hw) -{ - u32 size; - int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE_A); - - if (i & EXT_MEM_ENABLE_F) { - size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR_A); - csio_add_debugfs_mem(hw, "mc", MEM_MC, - EXT_MEM_SIZE_G(size)); - } -} - -/* T4 adapter specific function */ -struct csio_hw_chip_ops t4_ops = { - .chip_set_mem_win = csio_t4_set_mem_win, - .chip_pcie_intr_handler = csio_t4_pcie_intr_handler, - .chip_flash_cfg_addr = csio_t4_flash_cfg_addr, - .chip_mc_read = csio_t4_mc_read, - .chip_edc_read = csio_t4_edc_read, - .chip_memory_rw = csio_t4_memory_rw, - .chip_dfs_create_ext_mem = csio_t4_dfs_create_ext_mem, -}; diff --git a/drivers/scsi/csiostor/csio_hw_t5.c b/drivers/scsi/csiostor/csio_hw_t5.c index 66e180a58718..3267f4f627c9 100644 --- a/drivers/scsi/csiostor/csio_hw_t5.c +++ b/drivers/scsi/csiostor/csio_hw_t5.c @@ -56,11 +56,11 @@ csio_t5_set_mem_win(struct csio_hw *hw, uint32_t win) * back MA register to ensure that changes propagate before we attempt * to use the new values.) */ - csio_wr_reg32(hw, mem_win_base | BIR(0) | - WINDOW(ilog2(MEMWIN_APERTURE) - 10), - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win)); + csio_wr_reg32(hw, mem_win_base | BIR_V(0) | + WINDOW_V(ilog2(MEMWIN_APERTURE) - 10), + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, win)); csio_rd_reg32(hw, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win)); + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, win)); return 0; } @@ -72,74 +72,74 @@ static void csio_t5_pcie_intr_handler(struct csio_hw *hw) { static struct intr_info sysbus_intr_info[] = { - { RNPP, "RXNP array parity error", -1, 1 }, - { RPCP, "RXPC array parity error", -1, 1 }, - { RCIP, "RXCIF array parity error", -1, 1 }, - { RCCP, "Rx completions control array parity error", -1, 1 }, - { RFTP, "RXFT array parity error", -1, 1 }, + { RNPP_F, "RXNP array parity error", -1, 1 }, + { RPCP_F, "RXPC array parity error", -1, 1 }, + { RCIP_F, "RXCIF array parity error", -1, 1 }, + { RCCP_F, "Rx completions control array parity error", -1, 1 }, + { RFTP_F, "RXFT array parity error", -1, 1 }, { 0, NULL, 0, 0 } }; static struct intr_info pcie_port_intr_info[] = { - { TPCP, "TXPC array parity error", -1, 1 }, - { TNPP, "TXNP array parity error", -1, 1 }, - { TFTP, "TXFT array parity error", -1, 1 }, - { TCAP, "TXCA array parity error", -1, 1 }, - { TCIP, "TXCIF array parity error", -1, 1 }, - { RCAP, "RXCA array parity error", -1, 1 }, - { OTDD, "outbound request TLP discarded", -1, 1 }, - { RDPE, "Rx data parity error", -1, 1 }, - { TDUE, "Tx uncorrectable data error", -1, 1 }, + { TPCP_F, "TXPC array parity error", -1, 1 }, + { TNPP_F, "TXNP array parity error", -1, 1 }, + { TFTP_F, "TXFT array parity error", -1, 1 }, + { TCAP_F, "TXCA array parity error", -1, 1 }, + { TCIP_F, "TXCIF array parity error", -1, 1 }, + { RCAP_F, "RXCA array parity error", -1, 1 }, + { OTDD_F, "outbound request TLP discarded", -1, 1 }, + { RDPE_F, "Rx data parity error", -1, 1 }, + { TDUE_F, "Tx uncorrectable data error", -1, 1 }, { 0, NULL, 0, 0 } }; static struct intr_info pcie_intr_info[] = { - { MSTGRPPERR, "Master Response Read Queue parity error", + { MSTGRPPERR_F, "Master Response Read Queue parity error", -1, 1 }, - { MSTTIMEOUTPERR, "Master Timeout FIFO parity error", -1, 1 }, - { MSIXSTIPERR, "MSI-X STI SRAM parity error", -1, 1 }, - { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 }, - { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 }, - { MSIXDATAPERR, "MSI-X data parity error", -1, 1 }, - { MSIXDIPERR, "MSI-X DI parity error", -1, 1 }, - { PIOCPLGRPPERR, "PCI PIO completion Group FIFO parity error", + { MSTTIMEOUTPERR_F, "Master Timeout FIFO parity error", -1, 1 }, + { MSIXSTIPERR_F, "MSI-X STI SRAM parity error", -1, 1 }, + { MSIXADDRLPERR_F, "MSI-X AddrL parity error", -1, 1 }, + { MSIXADDRHPERR_F, "MSI-X AddrH parity error", -1, 1 }, + { MSIXDATAPERR_F, "MSI-X data parity error", -1, 1 }, + { MSIXDIPERR_F, "MSI-X DI parity error", -1, 1 }, + { PIOCPLGRPPERR_F, "PCI PIO completion Group FIFO parity error", -1, 1 }, - { PIOREQGRPPERR, "PCI PIO request Group FIFO parity error", + { PIOREQGRPPERR_F, "PCI PIO request Group FIFO parity error", -1, 1 }, - { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 }, - { MSTTAGQPERR, "PCI master tag queue parity error", -1, 1 }, - { CREQPERR, "PCI CMD channel request parity error", -1, 1 }, - { CRSPPERR, "PCI CMD channel response parity error", -1, 1 }, - { DREQWRPERR, "PCI DMA channel write request parity error", + { TARTAGPERR_F, "PCI PCI target tag FIFO parity error", -1, 1 }, + { MSTTAGQPERR_F, "PCI master tag queue parity error", -1, 1 }, + { CREQPERR_F, "PCI CMD channel request parity error", -1, 1 }, + { CRSPPERR_F, "PCI CMD channel response parity error", -1, 1 }, + { DREQWRPERR_F, "PCI DMA channel write request parity error", -1, 1 }, - { DREQPERR, "PCI DMA channel request parity error", -1, 1 }, - { DRSPPERR, "PCI DMA channel response parity error", -1, 1 }, - { HREQWRPERR, "PCI HMA channel count parity error", -1, 1 }, - { HREQPERR, "PCI HMA channel request parity error", -1, 1 }, - { HRSPPERR, "PCI HMA channel response parity error", -1, 1 }, - { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 }, - { FIDPERR, "PCI FID parity error", -1, 1 }, - { VFIDPERR, "PCI INTx clear parity error", -1, 1 }, - { MAGRPPERR, "PCI MA group FIFO parity error", -1, 1 }, - { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 }, - { IPRXHDRGRPPERR, "PCI IP Rx header group parity error", + { DREQPERR_F, "PCI DMA channel request parity error", -1, 1 }, + { DRSPPERR_F, "PCI DMA channel response parity error", -1, 1 }, + { HREQWRPERR_F, "PCI HMA channel count parity error", -1, 1 }, + { HREQPERR_F, "PCI HMA channel request parity error", -1, 1 }, + { HRSPPERR_F, "PCI HMA channel response parity error", -1, 1 }, + { CFGSNPPERR_F, "PCI config snoop FIFO parity error", -1, 1 }, + { FIDPERR_F, "PCI FID parity error", -1, 1 }, + { VFIDPERR_F, "PCI INTx clear parity error", -1, 1 }, + { MAGRPPERR_F, "PCI MA group FIFO parity error", -1, 1 }, + { PIOTAGPERR_F, "PCI PIO tag parity error", -1, 1 }, + { IPRXHDRGRPPERR_F, "PCI IP Rx header group parity error", -1, 1 }, - { IPRXDATAGRPPERR, "PCI IP Rx data group parity error", + { IPRXDATAGRPPERR_F, "PCI IP Rx data group parity error", -1, 1 }, - { RPLPERR, "PCI IP replay buffer parity error", -1, 1 }, - { IPSOTPERR, "PCI IP SOT buffer parity error", -1, 1 }, - { TRGT1GRPPERR, "PCI TRGT1 group FIFOs parity error", -1, 1 }, - { READRSPERR, "Outbound read error", -1, 0 }, + { RPLPERR_F, "PCI IP replay buffer parity error", -1, 1 }, + { IPSOTPERR_F, "PCI IP SOT buffer parity error", -1, 1 }, + { TRGT1GRPPERR_F, "PCI TRGT1 group FIFOs parity error", -1, 1 }, + { READRSPERR_F, "Outbound read error", -1, 0 }, { 0, NULL, 0, 0 } }; int fat; fat = csio_handle_intr_status(hw, - PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS, + PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS_A, sysbus_intr_info) + csio_handle_intr_status(hw, - PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS, + PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS_A, pcie_port_intr_info) + - csio_handle_intr_status(hw, PCIE_INT_CAUSE, pcie_intr_info); + csio_handle_intr_status(hw, PCIE_INT_CAUSE_A, pcie_intr_info); if (fat) csio_hw_fatal_err(hw); } @@ -177,25 +177,25 @@ csio_t5_mc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data, uint32_t mc_bist_cmd_reg, mc_bist_cmd_addr_reg, mc_bist_cmd_len_reg; uint32_t mc_bist_status_rdata_reg, mc_bist_data_pattern_reg; - mc_bist_cmd_reg = MC_REG(MC_P_BIST_CMD, idx); - mc_bist_cmd_addr_reg = MC_REG(MC_P_BIST_CMD_ADDR, idx); - mc_bist_cmd_len_reg = MC_REG(MC_P_BIST_CMD_LEN, idx); - mc_bist_status_rdata_reg = MC_REG(MC_P_BIST_STATUS_RDATA, idx); - mc_bist_data_pattern_reg = MC_REG(MC_P_BIST_DATA_PATTERN, idx); + mc_bist_cmd_reg = MC_REG(MC_P_BIST_CMD_A, idx); + mc_bist_cmd_addr_reg = MC_REG(MC_P_BIST_CMD_ADDR_A, idx); + mc_bist_cmd_len_reg = MC_REG(MC_P_BIST_CMD_LEN_A, idx); + mc_bist_status_rdata_reg = MC_REG(MC_P_BIST_STATUS_RDATA_A, idx); + mc_bist_data_pattern_reg = MC_REG(MC_P_BIST_DATA_PATTERN_A, idx); - if (csio_rd_reg32(hw, mc_bist_cmd_reg) & START_BIST) + if (csio_rd_reg32(hw, mc_bist_cmd_reg) & START_BIST_F) return -EBUSY; csio_wr_reg32(hw, addr & ~0x3fU, mc_bist_cmd_addr_reg); csio_wr_reg32(hw, 64, mc_bist_cmd_len_reg); csio_wr_reg32(hw, 0xc, mc_bist_data_pattern_reg); - csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1), + csio_wr_reg32(hw, BIST_OPCODE_V(1) | START_BIST_F | BIST_CMD_GAP_V(1), mc_bist_cmd_reg); - i = csio_hw_wait_op_done_val(hw, mc_bist_cmd_reg, START_BIST, + i = csio_hw_wait_op_done_val(hw, mc_bist_cmd_reg, START_BIST_F, 0, 10, 1, NULL); if (i) return i; -#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i) +#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA_A, i) for (i = 15; i >= 0; i--) *data++ = htonl(csio_rd_reg32(hw, MC_DATA(i))); @@ -231,27 +231,27 @@ csio_t5_edc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data, #define EDC_STRIDE_T5 (EDC_T51_BASE_ADDR - EDC_T50_BASE_ADDR) #define EDC_REG_T5(reg, idx) (reg + EDC_STRIDE_T5 * idx) - edc_bist_cmd_reg = EDC_REG_T5(EDC_H_BIST_CMD, idx); - edc_bist_cmd_addr_reg = EDC_REG_T5(EDC_H_BIST_CMD_ADDR, idx); - edc_bist_cmd_len_reg = EDC_REG_T5(EDC_H_BIST_CMD_LEN, idx); - edc_bist_cmd_data_pattern = EDC_REG_T5(EDC_H_BIST_DATA_PATTERN, idx); - edc_bist_status_rdata_reg = EDC_REG_T5(EDC_H_BIST_STATUS_RDATA, idx); + edc_bist_cmd_reg = EDC_REG_T5(EDC_H_BIST_CMD_A, idx); + edc_bist_cmd_addr_reg = EDC_REG_T5(EDC_H_BIST_CMD_ADDR_A, idx); + edc_bist_cmd_len_reg = EDC_REG_T5(EDC_H_BIST_CMD_LEN_A, idx); + edc_bist_cmd_data_pattern = EDC_REG_T5(EDC_H_BIST_DATA_PATTERN_A, idx); + edc_bist_status_rdata_reg = EDC_REG_T5(EDC_H_BIST_STATUS_RDATA_A, idx); #undef EDC_REG_T5 #undef EDC_STRIDE_T5 - if (csio_rd_reg32(hw, edc_bist_cmd_reg) & START_BIST) + if (csio_rd_reg32(hw, edc_bist_cmd_reg) & START_BIST_F) return -EBUSY; csio_wr_reg32(hw, addr & ~0x3fU, edc_bist_cmd_addr_reg); csio_wr_reg32(hw, 64, edc_bist_cmd_len_reg); csio_wr_reg32(hw, 0xc, edc_bist_cmd_data_pattern); - csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1), + csio_wr_reg32(hw, BIST_OPCODE_V(1) | START_BIST_F | BIST_CMD_GAP_V(1), edc_bist_cmd_reg); - i = csio_hw_wait_op_done_val(hw, edc_bist_cmd_reg, START_BIST, + i = csio_hw_wait_op_done_val(hw, edc_bist_cmd_reg, START_BIST_F, 0, 10, 1, NULL); if (i) return i; -#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx) +#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA_A, i) + idx) for (i = 15; i >= 0; i--) *data++ = htonl(csio_rd_reg32(hw, EDC_DATA(i))); @@ -320,13 +320,13 @@ csio_t5_memory_rw(struct csio_hw *hw, u32 win, int mtype, u32 addr, * the address is relative to BAR0. */ mem_reg = csio_rd_reg32(hw, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win)); - mem_aperture = 1 << (WINDOW(mem_reg) + 10); - mem_base = GET_PCIEOFST(mem_reg) << 10; + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, win)); + mem_aperture = 1 << (WINDOW_V(mem_reg) + 10); + mem_base = PCIEOFST_G(mem_reg) << 10; start = addr & ~(mem_aperture-1); offset = addr - start; - win_pf = V_PFNUM(hw->pfn); + win_pf = PFNUM_V(hw->pfn); csio_dbg(hw, "csio_t5_memory_rw: mem_reg: 0x%x, mem_aperture: 0x%x\n", mem_reg, mem_aperture); @@ -344,9 +344,9 @@ csio_t5_memory_rw(struct csio_hw *hw, u32 win, int mtype, u32 addr, * before we attempt to use the new value. */ csio_wr_reg32(hw, pos | win_pf, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win)); + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win)); csio_rd_reg32(hw, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win)); + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win)); while (offset < mem_aperture && len > 0) { if (dir) diff --git a/drivers/scsi/csiostor/csio_init.c b/drivers/scsi/csiostor/csio_init.c index 34d20cc3e110..9b9794d42ffe 100644 --- a/drivers/scsi/csiostor/csio_init.c +++ b/drivers/scsi/csiostor/csio_init.c @@ -1176,9 +1176,8 @@ static struct pci_error_handlers csio_err_handler = { */ #define CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN \ static struct pci_device_id csio_pci_tbl[] = { -/* Define for iSCSI uses PF5, FCoE uses PF6 */ -#define CH_PCI_DEVICE_ID_FUNCTION 0x5 -#define CH_PCI_DEVICE_ID_FUNCTION2 0x6 +/* Define for FCoE uses PF6 */ +#define CH_PCI_DEVICE_ID_FUNCTION 0x6 #define CH_PCI_ID_TABLE_ENTRY(devid) \ { PCI_VDEVICE(CHELSIO, (devid)), 0 } @@ -1256,5 +1255,4 @@ MODULE_DESCRIPTION(CSIO_DRV_DESC); MODULE_LICENSE(CSIO_DRV_LICENSE); MODULE_DEVICE_TABLE(pci, csio_pci_tbl); MODULE_VERSION(CSIO_DRV_VERSION); -MODULE_FIRMWARE(FW_FNAME_T4); MODULE_FIRMWARE(FW_FNAME_T5); diff --git a/drivers/scsi/csiostor/csio_isr.c b/drivers/scsi/csiostor/csio_isr.c index a8c748a35f9c..2fb71c6c3b37 100644 --- a/drivers/scsi/csiostor/csio_isr.c +++ b/drivers/scsi/csiostor/csio_isr.c @@ -317,7 +317,7 @@ csio_fcoe_isr(int irq, void *dev_id) /* Disable the interrupt for this PCI function. */ if (hw->intr_mode == CSIO_IM_INTX) - csio_wr_reg32(hw, 0, MYPF_REG(PCIE_PF_CLI)); + csio_wr_reg32(hw, 0, MYPF_REG(PCIE_PF_CLI_A)); /* * The read in the following function will flush the diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c index 87f9280d9b43..c00b2ff72b55 100644 --- a/drivers/scsi/csiostor/csio_lnode.c +++ b/drivers/scsi/csiostor/csio_lnode.c @@ -1758,7 +1758,7 @@ csio_ln_mgmt_submit_wr(struct csio_mgmtm *mgmtm, struct csio_ioreq *io_req, else { /* Program DSGL to dma payload */ dsgl.cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | - ULPTX_MORE | ULPTX_NSGE(1)); + ULPTX_MORE_F | ULPTX_NSGE_V(1)); dsgl.len0 = cpu_to_be32(pld_len); dsgl.addr0 = cpu_to_be64(pld->paddr); csio_wr_copy_to_wrp(&dsgl, &wrp, ALIGN(wr_off, 8), diff --git a/drivers/scsi/csiostor/csio_mb.c b/drivers/scsi/csiostor/csio_mb.c index 08c265c0f353..9451787ca7f2 100644 --- a/drivers/scsi/csiostor/csio_mb.c +++ b/drivers/scsi/csiostor/csio_mb.c @@ -327,7 +327,8 @@ csio_mb_caps_config(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo, } #define CSIO_ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ - FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_ANEG) + FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G |\ + FW_PORT_CAP_ANEG) /* * csio_mb_port- FW PORT command helper @@ -1104,8 +1105,8 @@ csio_mb_process_portparams_rsp(struct csio_hw *hw, void csio_mb_intr_enable(struct csio_hw *hw) { - csio_wr_reg32(hw, MBMSGRDYINTEN(1), MYPF_REG(CIM_PF_HOST_INT_ENABLE)); - csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_ENABLE)); + csio_wr_reg32(hw, MBMSGRDYINTEN_F, MYPF_REG(CIM_PF_HOST_INT_ENABLE_A)); + csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_ENABLE_A)); } /* @@ -1117,8 +1118,9 @@ csio_mb_intr_enable(struct csio_hw *hw) void csio_mb_intr_disable(struct csio_hw *hw) { - csio_wr_reg32(hw, MBMSGRDYINTEN(0), MYPF_REG(CIM_PF_HOST_INT_ENABLE)); - csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_ENABLE)); + csio_wr_reg32(hw, MBMSGRDYINTEN_V(0), + MYPF_REG(CIM_PF_HOST_INT_ENABLE_A)); + csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_ENABLE_A)); } static void @@ -1153,8 +1155,8 @@ csio_mb_debug_cmd_handler(struct csio_hw *hw) { int i; __be64 cmd[CSIO_MB_MAX_REGS]; - uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL); - uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA); + uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL_A); + uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA_A); int size = sizeof(struct fw_debug_cmd); /* Copy mailbox data */ @@ -1164,8 +1166,8 @@ csio_mb_debug_cmd_handler(struct csio_hw *hw) csio_mb_dump_fw_dbg(hw, cmd); /* Notify FW of mailbox by setting owner as UP */ - csio_wr_reg32(hw, MBMSGVALID | MBINTREQ | MBOWNER(CSIO_MBOWNER_FW), - ctl_reg); + csio_wr_reg32(hw, MBMSGVALID_F | MBINTREQ_F | + MBOWNER_V(CSIO_MBOWNER_FW), ctl_reg); csio_rd_reg32(hw, ctl_reg); wmb(); @@ -1187,8 +1189,8 @@ csio_mb_issue(struct csio_hw *hw, struct csio_mb *mbp) __be64 *cmd = mbp->mb; __be64 hdr; struct csio_mbm *mbm = &hw->mbm; - uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL); - uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA); + uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL_A); + uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA_A); int size = mbp->mb_size; int rv = -EINVAL; struct fw_cmd_hdr *fw_hdr; @@ -1224,12 +1226,12 @@ csio_mb_issue(struct csio_hw *hw, struct csio_mb *mbp) } /* Now get ownership of mailbox */ - owner = MBOWNER_GET(csio_rd_reg32(hw, ctl_reg)); + owner = MBOWNER_G(csio_rd_reg32(hw, ctl_reg)); if (!csio_mb_is_host_owner(owner)) { for (i = 0; (owner == CSIO_MBOWNER_NONE) && (i < 3); i++) - owner = MBOWNER_GET(csio_rd_reg32(hw, ctl_reg)); + owner = MBOWNER_G(csio_rd_reg32(hw, ctl_reg)); /* * Mailbox unavailable. In immediate mode, fail the command. * In other modes, enqueue the request. @@ -1271,10 +1273,10 @@ csio_mb_issue(struct csio_hw *hw, struct csio_mb *mbp) if (mbp->mb_cbfn != NULL) { mbm->mcurrent = mbp; mod_timer(&mbm->timer, jiffies + msecs_to_jiffies(mbp->tmo)); - csio_wr_reg32(hw, MBMSGVALID | MBINTREQ | - MBOWNER(CSIO_MBOWNER_FW), ctl_reg); + csio_wr_reg32(hw, MBMSGVALID_F | MBINTREQ_F | + MBOWNER_V(CSIO_MBOWNER_FW), ctl_reg); } else - csio_wr_reg32(hw, MBMSGVALID | MBOWNER(CSIO_MBOWNER_FW), + csio_wr_reg32(hw, MBMSGVALID_F | MBOWNER_V(CSIO_MBOWNER_FW), ctl_reg); /* Flush posted writes */ @@ -1294,9 +1296,9 @@ csio_mb_issue(struct csio_hw *hw, struct csio_mb *mbp) /* Check for response */ ctl = csio_rd_reg32(hw, ctl_reg); - if (csio_mb_is_host_owner(MBOWNER_GET(ctl))) { + if (csio_mb_is_host_owner(MBOWNER_G(ctl))) { - if (!(ctl & MBMSGVALID)) { + if (!(ctl & MBMSGVALID_F)) { csio_wr_reg32(hw, 0, ctl_reg); continue; } @@ -1457,16 +1459,16 @@ csio_mb_isr_handler(struct csio_hw *hw) __be64 *cmd; uint32_t ctl, cim_cause, pl_cause; int i; - uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL); - uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA); + uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL_A); + uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA_A); int size; __be64 hdr; struct fw_cmd_hdr *fw_hdr; - pl_cause = csio_rd_reg32(hw, MYPF_REG(PL_PF_INT_CAUSE)); - cim_cause = csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_CAUSE)); + pl_cause = csio_rd_reg32(hw, MYPF_REG(PL_PF_INT_CAUSE_A)); + cim_cause = csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_CAUSE_A)); - if (!(pl_cause & PFCIM) || !(cim_cause & MBMSGRDYINT)) { + if (!(pl_cause & PFCIM_F) || !(cim_cause & MBMSGRDYINT_F)) { CSIO_INC_STATS(hw, n_mbint_unexp); return -EINVAL; } @@ -1477,16 +1479,16 @@ csio_mb_isr_handler(struct csio_hw *hw) * the upper level cause register. In other words, CIM-cause * first followed by PL-Cause next. */ - csio_wr_reg32(hw, MBMSGRDYINT, MYPF_REG(CIM_PF_HOST_INT_CAUSE)); - csio_wr_reg32(hw, PFCIM, MYPF_REG(PL_PF_INT_CAUSE)); + csio_wr_reg32(hw, MBMSGRDYINT_F, MYPF_REG(CIM_PF_HOST_INT_CAUSE_A)); + csio_wr_reg32(hw, PFCIM_F, MYPF_REG(PL_PF_INT_CAUSE_A)); ctl = csio_rd_reg32(hw, ctl_reg); - if (csio_mb_is_host_owner(MBOWNER_GET(ctl))) { + if (csio_mb_is_host_owner(MBOWNER_G(ctl))) { CSIO_DUMP_MB(hw, hw->pfn, data_reg); - if (!(ctl & MBMSGVALID)) { + if (!(ctl & MBMSGVALID_F)) { csio_warn(hw, "Stray mailbox interrupt recvd," " mailbox data not valid\n"); diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c index 3987284e0d2a..2c4562d82dc0 100644 --- a/drivers/scsi/csiostor/csio_scsi.c +++ b/drivers/scsi/csiostor/csio_scsi.c @@ -298,8 +298,8 @@ csio_scsi_init_ultptx_dsgl(struct csio_hw *hw, struct csio_ioreq *req, struct csio_dma_buf *dma_buf; struct scsi_cmnd *scmnd = csio_scsi_cmnd(req); - sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | ULPTX_MORE | - ULPTX_NSGE(req->nsge)); + sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | ULPTX_MORE_F | + ULPTX_NSGE_V(req->nsge)); /* Now add the data SGLs */ if (likely(!req->dcopy)) { scsi_for_each_sg(scmnd, sgel, req->nsge, i) { diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c index 773da14cfa14..e8f18174f2e9 100644 --- a/drivers/scsi/csiostor/csio_wr.c +++ b/drivers/scsi/csiostor/csio_wr.c @@ -51,12 +51,12 @@ int csio_intr_coalesce_time = 10; /* value:SGE_TIMER_VALUE_1 */ static int csio_sge_timer_reg = 1; #define CSIO_SET_FLBUF_SIZE(_hw, _reg, _val) \ - csio_wr_reg32((_hw), (_val), SGE_FL_BUFFER_SIZE##_reg) + csio_wr_reg32((_hw), (_val), SGE_FL_BUFFER_SIZE##_reg##_A) static void csio_get_flbuf_size(struct csio_hw *hw, struct csio_sge *sge, uint32_t reg) { - sge->sge_fl_buf_size[reg] = csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE0 + + sge->sge_fl_buf_size[reg] = csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE0_A + reg * sizeof(uint32_t)); } @@ -71,7 +71,7 @@ csio_wr_fl_bufsz(struct csio_sge *sge, struct csio_dma_buf *buf) static inline uint32_t csio_wr_qstat_pgsz(struct csio_hw *hw) { - return (hw->wrm.sge.sge_control & EGRSTATUSPAGESIZE(1)) ? 128 : 64; + return (hw->wrm.sge.sge_control & EGRSTATUSPAGESIZE_F) ? 128 : 64; } /* Ring freelist doorbell */ @@ -84,9 +84,9 @@ csio_wr_ring_fldb(struct csio_hw *hw, struct csio_q *flq) * 8 freelist buffer pointers (since each pointer is 8 bytes). */ if (flq->inc_idx >= 8) { - csio_wr_reg32(hw, DBPRIO(1) | QID(flq->un.fl.flid) | - CSIO_HW_PIDX(hw, flq->inc_idx / 8), - MYPF_REG(SGE_PF_KDOORBELL)); + csio_wr_reg32(hw, DBPRIO_F | QID_V(flq->un.fl.flid) | + PIDX_T5_V(flq->inc_idx / 8) | DBTYPE_F, + MYPF_REG(SGE_PF_KDOORBELL_A)); flq->inc_idx &= 7; } } @@ -95,10 +95,10 @@ csio_wr_ring_fldb(struct csio_hw *hw, struct csio_q *flq) static void csio_wr_sge_intr_enable(struct csio_hw *hw, uint16_t iqid) { - csio_wr_reg32(hw, CIDXINC(0) | - INGRESSQID(iqid) | - TIMERREG(X_TIMERREG_RESTART_COUNTER), - MYPF_REG(SGE_PF_GTS)); + csio_wr_reg32(hw, CIDXINC_V(0) | + INGRESSQID_V(iqid) | + TIMERREG_V(X_TIMERREG_RESTART_COUNTER), + MYPF_REG(SGE_PF_GTS_A)); } /* @@ -982,9 +982,9 @@ csio_wr_issue(struct csio_hw *hw, int qidx, bool prio) wmb(); /* Ring SGE Doorbell writing q->pidx into it */ - csio_wr_reg32(hw, DBPRIO(prio) | QID(q->un.eq.physeqid) | - CSIO_HW_PIDX(hw, q->inc_idx), - MYPF_REG(SGE_PF_KDOORBELL)); + csio_wr_reg32(hw, DBPRIO_V(prio) | QID_V(q->un.eq.physeqid) | + PIDX_T5_V(q->inc_idx) | DBTYPE_F, + MYPF_REG(SGE_PF_KDOORBELL_A)); q->inc_idx = 0; return 0; @@ -1242,10 +1242,10 @@ csio_wr_process_iq(struct csio_hw *hw, struct csio_q *q, restart: /* Now inform SGE about our incremental index value */ - csio_wr_reg32(hw, CIDXINC(q->inc_idx) | - INGRESSQID(q->un.iq.physiqid) | - TIMERREG(csio_sge_timer_reg), - MYPF_REG(SGE_PF_GTS)); + csio_wr_reg32(hw, CIDXINC_V(q->inc_idx) | + INGRESSQID_V(q->un.iq.physiqid) | + TIMERREG_V(csio_sge_timer_reg), + MYPF_REG(SGE_PF_GTS_A)); q->stats.n_tot_rsps += q->inc_idx; q->inc_idx = 0; @@ -1310,22 +1310,23 @@ csio_wr_fixup_host_params(struct csio_hw *hw) uint32_t ingpad = 0; uint32_t stat_len = clsz > 64 ? 128 : 64; - csio_wr_reg32(hw, HOSTPAGESIZEPF0(s_hps) | HOSTPAGESIZEPF1(s_hps) | - HOSTPAGESIZEPF2(s_hps) | HOSTPAGESIZEPF3(s_hps) | - HOSTPAGESIZEPF4(s_hps) | HOSTPAGESIZEPF5(s_hps) | - HOSTPAGESIZEPF6(s_hps) | HOSTPAGESIZEPF7(s_hps), - SGE_HOST_PAGE_SIZE); + csio_wr_reg32(hw, HOSTPAGESIZEPF0_V(s_hps) | HOSTPAGESIZEPF1_V(s_hps) | + HOSTPAGESIZEPF2_V(s_hps) | HOSTPAGESIZEPF3_V(s_hps) | + HOSTPAGESIZEPF4_V(s_hps) | HOSTPAGESIZEPF5_V(s_hps) | + HOSTPAGESIZEPF6_V(s_hps) | HOSTPAGESIZEPF7_V(s_hps), + SGE_HOST_PAGE_SIZE_A); sge->csio_fl_align = clsz < 32 ? 32 : clsz; ingpad = ilog2(sge->csio_fl_align) - 5; - csio_set_reg_field(hw, SGE_CONTROL, INGPADBOUNDARY_MASK | - EGRSTATUSPAGESIZE(1), - INGPADBOUNDARY(ingpad) | - EGRSTATUSPAGESIZE(stat_len != 64)); + csio_set_reg_field(hw, SGE_CONTROL_A, + INGPADBOUNDARY_V(INGPADBOUNDARY_M) | + EGRSTATUSPAGESIZE_F, + INGPADBOUNDARY_V(ingpad) | + EGRSTATUSPAGESIZE_V(stat_len != 64)); /* FL BUFFER SIZE#0 is Page size i,e already aligned to cache line */ - csio_wr_reg32(hw, PAGE_SIZE, SGE_FL_BUFFER_SIZE0); + csio_wr_reg32(hw, PAGE_SIZE, SGE_FL_BUFFER_SIZE0_A); /* * If using hard params, the following will get set correctly @@ -1333,23 +1334,24 @@ csio_wr_fixup_host_params(struct csio_hw *hw) */ if (hw->flags & CSIO_HWF_USING_SOFT_PARAMS) { csio_wr_reg32(hw, - (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE2) + + (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE2_A) + sge->csio_fl_align - 1) & ~(sge->csio_fl_align - 1), - SGE_FL_BUFFER_SIZE2); + SGE_FL_BUFFER_SIZE2_A); csio_wr_reg32(hw, - (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE3) + + (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE3_A) + sge->csio_fl_align - 1) & ~(sge->csio_fl_align - 1), - SGE_FL_BUFFER_SIZE3); + SGE_FL_BUFFER_SIZE3_A); } - csio_wr_reg32(hw, HPZ0(PAGE_SHIFT - 12), ULP_RX_TDDP_PSZ); + csio_wr_reg32(hw, HPZ0_V(PAGE_SHIFT - 12), ULP_RX_TDDP_PSZ_A); /* default value of rx_dma_offset of the NIC driver */ - csio_set_reg_field(hw, SGE_CONTROL, PKTSHIFT_MASK, - PKTSHIFT(CSIO_SGE_RX_DMA_OFFSET)); + csio_set_reg_field(hw, SGE_CONTROL_A, + PKTSHIFT_V(PKTSHIFT_M), + PKTSHIFT_V(CSIO_SGE_RX_DMA_OFFSET)); - csio_hw_tp_wr_bits_indirect(hw, TP_INGRESS_CONFIG, - CSUM_HAS_PSEUDO_HDR, 0); + csio_hw_tp_wr_bits_indirect(hw, TP_INGRESS_CONFIG_A, + CSUM_HAS_PSEUDO_HDR_F, 0); } static void @@ -1384,9 +1386,9 @@ csio_wr_get_sge(struct csio_hw *hw) u32 timer_value_0_and_1, timer_value_2_and_3, timer_value_4_and_5; u32 ingress_rx_threshold; - sge->sge_control = csio_rd_reg32(hw, SGE_CONTROL); + sge->sge_control = csio_rd_reg32(hw, SGE_CONTROL_A); - ingpad = INGPADBOUNDARY_GET(sge->sge_control); + ingpad = INGPADBOUNDARY_G(sge->sge_control); switch (ingpad) { case X_INGPCIEBOUNDARY_32B: @@ -1410,28 +1412,28 @@ csio_wr_get_sge(struct csio_hw *hw) for (i = 0; i < CSIO_SGE_FL_SIZE_REGS; i++) csio_get_flbuf_size(hw, sge, i); - timer_value_0_and_1 = csio_rd_reg32(hw, SGE_TIMER_VALUE_0_AND_1); - timer_value_2_and_3 = csio_rd_reg32(hw, SGE_TIMER_VALUE_2_AND_3); - timer_value_4_and_5 = csio_rd_reg32(hw, SGE_TIMER_VALUE_4_AND_5); + timer_value_0_and_1 = csio_rd_reg32(hw, SGE_TIMER_VALUE_0_AND_1_A); + timer_value_2_and_3 = csio_rd_reg32(hw, SGE_TIMER_VALUE_2_AND_3_A); + timer_value_4_and_5 = csio_rd_reg32(hw, SGE_TIMER_VALUE_4_AND_5_A); sge->timer_val[0] = (uint16_t)csio_core_ticks_to_us(hw, - TIMERVALUE0_GET(timer_value_0_and_1)); + TIMERVALUE0_G(timer_value_0_and_1)); sge->timer_val[1] = (uint16_t)csio_core_ticks_to_us(hw, - TIMERVALUE1_GET(timer_value_0_and_1)); + TIMERVALUE1_G(timer_value_0_and_1)); sge->timer_val[2] = (uint16_t)csio_core_ticks_to_us(hw, - TIMERVALUE2_GET(timer_value_2_and_3)); + TIMERVALUE2_G(timer_value_2_and_3)); sge->timer_val[3] = (uint16_t)csio_core_ticks_to_us(hw, - TIMERVALUE3_GET(timer_value_2_and_3)); + TIMERVALUE3_G(timer_value_2_and_3)); sge->timer_val[4] = (uint16_t)csio_core_ticks_to_us(hw, - TIMERVALUE4_GET(timer_value_4_and_5)); + TIMERVALUE4_G(timer_value_4_and_5)); sge->timer_val[5] = (uint16_t)csio_core_ticks_to_us(hw, - TIMERVALUE5_GET(timer_value_4_and_5)); + TIMERVALUE5_G(timer_value_4_and_5)); - ingress_rx_threshold = csio_rd_reg32(hw, SGE_INGRESS_RX_THRESHOLD); - sge->counter_val[0] = THRESHOLD_0_GET(ingress_rx_threshold); - sge->counter_val[1] = THRESHOLD_1_GET(ingress_rx_threshold); - sge->counter_val[2] = THRESHOLD_2_GET(ingress_rx_threshold); - sge->counter_val[3] = THRESHOLD_3_GET(ingress_rx_threshold); + ingress_rx_threshold = csio_rd_reg32(hw, SGE_INGRESS_RX_THRESHOLD_A); + sge->counter_val[0] = THRESHOLD_0_G(ingress_rx_threshold); + sge->counter_val[1] = THRESHOLD_1_G(ingress_rx_threshold); + sge->counter_val[2] = THRESHOLD_2_G(ingress_rx_threshold); + sge->counter_val[3] = THRESHOLD_3_G(ingress_rx_threshold); csio_init_intr_coalesce_parms(hw); } @@ -1454,9 +1456,9 @@ csio_wr_set_sge(struct csio_hw *hw) * Set up our basic SGE mode to deliver CPL messages to our Ingress * Queue and Packet Date to the Free List. */ - csio_set_reg_field(hw, SGE_CONTROL, RXPKTCPLMODE(1), RXPKTCPLMODE(1)); + csio_set_reg_field(hw, SGE_CONTROL_A, RXPKTCPLMODE_F, RXPKTCPLMODE_F); - sge->sge_control = csio_rd_reg32(hw, SGE_CONTROL); + sge->sge_control = csio_rd_reg32(hw, SGE_CONTROL_A); /* sge->csio_fl_align is set up by csio_wr_fixup_host_params(). */ @@ -1464,22 +1466,23 @@ csio_wr_set_sge(struct csio_hw *hw) * Set up to drop DOORBELL writes when the DOORBELL FIFO overflows * and generate an interrupt when this occurs so we can recover. */ - csio_set_reg_field(hw, SGE_DBFIFO_STATUS, - HP_INT_THRESH(HP_INT_THRESH_MASK) | - CSIO_HW_LP_INT_THRESH(hw, CSIO_HW_M_LP_INT_THRESH(hw)), - HP_INT_THRESH(CSIO_SGE_DBFIFO_INT_THRESH) | - CSIO_HW_LP_INT_THRESH(hw, CSIO_SGE_DBFIFO_INT_THRESH)); + csio_set_reg_field(hw, SGE_DBFIFO_STATUS_A, + LP_INT_THRESH_T5_V(LP_INT_THRESH_T5_M), + LP_INT_THRESH_T5_V(CSIO_SGE_DBFIFO_INT_THRESH)); + csio_set_reg_field(hw, SGE_DBFIFO_STATUS2_A, + HP_INT_THRESH_T5_V(LP_INT_THRESH_T5_M), + HP_INT_THRESH_T5_V(CSIO_SGE_DBFIFO_INT_THRESH)); - csio_set_reg_field(hw, SGE_DOORBELL_CONTROL, ENABLE_DROP, - ENABLE_DROP); + csio_set_reg_field(hw, SGE_DOORBELL_CONTROL_A, ENABLE_DROP_F, + ENABLE_DROP_F); /* SGE_FL_BUFFER_SIZE0 is set up by csio_wr_fixup_host_params(). */ CSIO_SET_FLBUF_SIZE(hw, 1, CSIO_SGE_FLBUF_SIZE1); csio_wr_reg32(hw, (CSIO_SGE_FLBUF_SIZE2 + sge->csio_fl_align - 1) - & ~(sge->csio_fl_align - 1), SGE_FL_BUFFER_SIZE2); + & ~(sge->csio_fl_align - 1), SGE_FL_BUFFER_SIZE2_A); csio_wr_reg32(hw, (CSIO_SGE_FLBUF_SIZE3 + sge->csio_fl_align - 1) - & ~(sge->csio_fl_align - 1), SGE_FL_BUFFER_SIZE3); + & ~(sge->csio_fl_align - 1), SGE_FL_BUFFER_SIZE3_A); CSIO_SET_FLBUF_SIZE(hw, 4, CSIO_SGE_FLBUF_SIZE4); CSIO_SET_FLBUF_SIZE(hw, 5, CSIO_SGE_FLBUF_SIZE5); CSIO_SET_FLBUF_SIZE(hw, 6, CSIO_SGE_FLBUF_SIZE6); @@ -1502,26 +1505,26 @@ csio_wr_set_sge(struct csio_hw *hw) sge->counter_val[2] = CSIO_SGE_INT_CNT_VAL_2; sge->counter_val[3] = CSIO_SGE_INT_CNT_VAL_3; - csio_wr_reg32(hw, THRESHOLD_0(sge->counter_val[0]) | - THRESHOLD_1(sge->counter_val[1]) | - THRESHOLD_2(sge->counter_val[2]) | - THRESHOLD_3(sge->counter_val[3]), - SGE_INGRESS_RX_THRESHOLD); + csio_wr_reg32(hw, THRESHOLD_0_V(sge->counter_val[0]) | + THRESHOLD_1_V(sge->counter_val[1]) | + THRESHOLD_2_V(sge->counter_val[2]) | + THRESHOLD_3_V(sge->counter_val[3]), + SGE_INGRESS_RX_THRESHOLD_A); csio_wr_reg32(hw, - TIMERVALUE0(csio_us_to_core_ticks(hw, sge->timer_val[0])) | - TIMERVALUE1(csio_us_to_core_ticks(hw, sge->timer_val[1])), - SGE_TIMER_VALUE_0_AND_1); + TIMERVALUE0_V(csio_us_to_core_ticks(hw, sge->timer_val[0])) | + TIMERVALUE1_V(csio_us_to_core_ticks(hw, sge->timer_val[1])), + SGE_TIMER_VALUE_0_AND_1_A); csio_wr_reg32(hw, - TIMERVALUE2(csio_us_to_core_ticks(hw, sge->timer_val[2])) | - TIMERVALUE3(csio_us_to_core_ticks(hw, sge->timer_val[3])), - SGE_TIMER_VALUE_2_AND_3); + TIMERVALUE2_V(csio_us_to_core_ticks(hw, sge->timer_val[2])) | + TIMERVALUE3_V(csio_us_to_core_ticks(hw, sge->timer_val[3])), + SGE_TIMER_VALUE_2_AND_3_A); csio_wr_reg32(hw, - TIMERVALUE4(csio_us_to_core_ticks(hw, sge->timer_val[4])) | - TIMERVALUE5(csio_us_to_core_ticks(hw, sge->timer_val[5])), - SGE_TIMER_VALUE_4_AND_5); + TIMERVALUE4_V(csio_us_to_core_ticks(hw, sge->timer_val[4])) | + TIMERVALUE5_V(csio_us_to_core_ticks(hw, sge->timer_val[5])), + SGE_TIMER_VALUE_4_AND_5_A); csio_init_intr_coalesce_parms(hw); } diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index a83d2ceded83..dd00e5fe4a5e 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -28,6 +28,7 @@ #include "t4fw_api.h" #include "l2t.h" #include "cxgb4i.h" +#include "clip_tbl.h" static unsigned int dbg_level; @@ -704,7 +705,7 @@ static void do_act_establish(struct cxgbi_device *cdev, struct sk_buff *skb) struct cpl_act_establish *req = (struct cpl_act_establish *)skb->data; unsigned short tcp_opt = ntohs(req->tcp_opt); unsigned int tid = GET_TID(req); - unsigned int atid = GET_TID_TID(ntohl(req->tos_atid)); + unsigned int atid = TID_TID_G(ntohl(req->tos_atid)); struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); struct tid_info *t = lldi->tids; u32 rcv_isn = be32_to_cpu(req->rcv_isn); @@ -752,15 +753,15 @@ static void do_act_establish(struct cxgbi_device *cdev, struct sk_buff *skb) if (cxgb4i_rcv_win > (RCV_BUFSIZ_MASK << 10)) csk->rcv_wup -= cxgb4i_rcv_win - (RCV_BUFSIZ_MASK << 10); - csk->advmss = lldi->mtus[GET_TCPOPT_MSS(tcp_opt)] - 40; - if (GET_TCPOPT_TSTAMP(tcp_opt)) + csk->advmss = lldi->mtus[TCPOPT_MSS_G(tcp_opt)] - 40; + if (TCPOPT_TSTAMP_G(tcp_opt)) csk->advmss -= 12; if (csk->advmss < 128) csk->advmss = 128; log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, "csk 0x%p, mss_idx %u, advmss %u.\n", - csk, GET_TCPOPT_MSS(tcp_opt), csk->advmss); + csk, TCPOPT_MSS_G(tcp_opt), csk->advmss); cxgbi_sock_established(csk, ntohl(req->snd_isn), ntohs(req->tcp_opt)); @@ -856,8 +857,8 @@ static void do_act_open_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) struct cpl_act_open_rpl *rpl = (struct cpl_act_open_rpl *)skb->data; unsigned int tid = GET_TID(rpl); unsigned int atid = - GET_TID_TID(GET_AOPEN_ATID(be32_to_cpu(rpl->atid_status))); - unsigned int status = GET_AOPEN_STATUS(be32_to_cpu(rpl->atid_status)); + TID_TID_G(AOPEN_ATID_G(be32_to_cpu(rpl->atid_status))); + unsigned int status = AOPEN_STATUS_G(be32_to_cpu(rpl->atid_status)); struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); struct tid_info *t = lldi->tids; @@ -1112,7 +1113,7 @@ static void do_rx_iscsi_hdr(struct cxgbi_device *cdev, struct sk_buff *skb) hlen = ntohs(cpl->len); dlen = ntohl(*(unsigned int *)(bhs + 4)) & 0xFFFFFF; - plen = ISCSI_PDU_LEN(pdu_len_ddp); + plen = ISCSI_PDU_LEN_G(pdu_len_ddp); if (is_t4(lldi->adapter_type)) plen -= 40; @@ -1322,6 +1323,9 @@ static inline void l2t_put(struct cxgbi_sock *csk) static void release_offload_resources(struct cxgbi_sock *csk) { struct cxgb4_lld_info *lldi; +#if IS_ENABLED(CONFIG_IPV6) + struct net_device *ndev = csk->cdev->ports[csk->port_id]; +#endif log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", @@ -1334,6 +1338,12 @@ static void release_offload_resources(struct cxgbi_sock *csk) } l2t_put(csk); +#if IS_ENABLED(CONFIG_IPV6) + if (csk->csk_family == AF_INET6) + cxgb4_clip_release(ndev, + (const u32 *)&csk->saddr6.sin6_addr, 1); +#endif + if (cxgbi_sock_flag(csk, CTPF_HAS_ATID)) free_atid(csk); else if (cxgbi_sock_flag(csk, CTPF_HAS_TID)) { @@ -1391,10 +1401,15 @@ static int init_act_open(struct cxgbi_sock *csk) csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, 0); if (!csk->l2t) { pr_err("%s, cannot alloc l2t.\n", ndev->name); - goto rel_resource; + goto rel_resource_without_clip; } cxgbi_sock_get(csk); +#if IS_ENABLED(CONFIG_IPV6) + if (csk->csk_family == AF_INET6) + cxgb4_clip_get(ndev, (const u32 *)&csk->saddr6.sin6_addr, 1); +#endif + if (t4) { size = sizeof(struct cpl_act_open_req); size6 = sizeof(struct cpl_act_open_req6); @@ -1451,6 +1466,12 @@ static int init_act_open(struct cxgbi_sock *csk) return 0; rel_resource: +#if IS_ENABLED(CONFIG_IPV6) + if (csk->csk_family == AF_INET6) + cxgb4_clip_release(ndev, + (const u32 *)&csk->saddr6.sin6_addr, 1); +#endif +rel_resource_without_clip: if (n) neigh_release(n); if (skb) @@ -1619,7 +1640,7 @@ static int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, unsigned int tid, req = (struct cpl_set_tcb_field *)skb->head; INIT_TP_WR(req, csk->tid); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, csk->tid)); - req->reply_ctrl = htons(NO_REPLY(reply) | QUEUENO(csk->rss_qid)); + req->reply_ctrl = htons(NO_REPLY_V(reply) | QUEUENO_V(csk->rss_qid)); req->word_cookie = htons(0); req->mask = cpu_to_be64(0x3 << 8); req->val = cpu_to_be64(pg_idx << 8); @@ -1651,7 +1672,7 @@ static int ddp_setup_conn_digest(struct cxgbi_sock *csk, unsigned int tid, req = (struct cpl_set_tcb_field *)skb->head; INIT_TP_WR(req, tid); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); - req->reply_ctrl = htons(NO_REPLY(reply) | QUEUENO(csk->rss_qid)); + req->reply_ctrl = htons(NO_REPLY_V(reply) | QUEUENO_V(csk->rss_qid)); req->word_cookie = htons(0); req->mask = cpu_to_be64(0x3 << 4); req->val = cpu_to_be64(((hcrc ? ULP_CRC_HEADER : 0) | diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 0c6be0a17f53..5ee7f44cf869 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -4610,13 +4610,10 @@ static void adapter_uninit(struct AdapterCtlBlk *acb) } -#undef SPRINTF -#define SPRINTF(args...) seq_printf(m,##args) - #undef YESNO #define YESNO(YN) \ - if (YN) SPRINTF(" Yes ");\ - else SPRINTF(" No ") + if (YN) seq_printf(m, " Yes ");\ + else seq_printf(m, " No ") static int dc395x_show_info(struct seq_file *m, struct Scsi_Host *host) { @@ -4626,47 +4623,45 @@ static int dc395x_show_info(struct seq_file *m, struct Scsi_Host *host) unsigned long flags; int dev; - SPRINTF(DC395X_BANNER " PCI SCSI Host Adapter\n"); - SPRINTF(" Driver Version " DC395X_VERSION "\n"); + seq_puts(m, DC395X_BANNER " PCI SCSI Host Adapter\n" + " Driver Version " DC395X_VERSION "\n"); DC395x_LOCK_IO(acb->scsi_host, flags); - SPRINTF("SCSI Host Nr %i, ", host->host_no); - SPRINTF("DC395U/UW/F DC315/U %s\n", + seq_printf(m, "SCSI Host Nr %i, ", host->host_no); + seq_printf(m, "DC395U/UW/F DC315/U %s\n", (acb->config & HCC_WIDE_CARD) ? "Wide" : ""); - SPRINTF("io_port_base 0x%04lx, ", acb->io_port_base); - SPRINTF("irq_level 0x%04x, ", acb->irq_level); - SPRINTF(" SelTimeout %ims\n", (1638 * acb->sel_timeout) / 1000); + seq_printf(m, "io_port_base 0x%04lx, ", acb->io_port_base); + seq_printf(m, "irq_level 0x%04x, ", acb->irq_level); + seq_printf(m, " SelTimeout %ims\n", (1638 * acb->sel_timeout) / 1000); - SPRINTF("MaxID %i, MaxLUN %llu, ", host->max_id, host->max_lun); - SPRINTF("AdapterID %i\n", host->this_id); + seq_printf(m, "MaxID %i, MaxLUN %llu, ", host->max_id, host->max_lun); + seq_printf(m, "AdapterID %i\n", host->this_id); - SPRINTF("tag_max_num %i", acb->tag_max_num); - /*SPRINTF(", DMA_Status %i\n", DC395x_read8(acb, TRM_S1040_DMA_STATUS)); */ - SPRINTF(", FilterCfg 0x%02x", + seq_printf(m, "tag_max_num %i", acb->tag_max_num); + /*seq_printf(m, ", DMA_Status %i\n", DC395x_read8(acb, TRM_S1040_DMA_STATUS)); */ + seq_printf(m, ", FilterCfg 0x%02x", DC395x_read8(acb, TRM_S1040_SCSI_CONFIG1)); - SPRINTF(", DelayReset %is\n", acb->eeprom.delay_time); - /*SPRINTF("\n"); */ + seq_printf(m, ", DelayReset %is\n", acb->eeprom.delay_time); + /*seq_printf(m, "\n"); */ - SPRINTF("Nr of DCBs: %i\n", list_size(&acb->dcb_list)); - SPRINTF - ("Map of attached LUNs: %02x %02x %02x %02x %02x %02x %02x %02x\n", + seq_printf(m, "Nr of DCBs: %i\n", list_size(&acb->dcb_list)); + seq_printf(m, "Map of attached LUNs: %02x %02x %02x %02x %02x %02x %02x %02x\n", acb->dcb_map[0], acb->dcb_map[1], acb->dcb_map[2], acb->dcb_map[3], acb->dcb_map[4], acb->dcb_map[5], acb->dcb_map[6], acb->dcb_map[7]); - SPRINTF - (" %02x %02x %02x %02x %02x %02x %02x %02x\n", + seq_printf(m, " %02x %02x %02x %02x %02x %02x %02x %02x\n", acb->dcb_map[8], acb->dcb_map[9], acb->dcb_map[10], acb->dcb_map[11], acb->dcb_map[12], acb->dcb_map[13], acb->dcb_map[14], acb->dcb_map[15]); - SPRINTF - ("Un ID LUN Prty Sync Wide DsCn SndS TagQ nego_period SyncFreq SyncOffs MaxCmd\n"); + seq_puts(m, + "Un ID LUN Prty Sync Wide DsCn SndS TagQ nego_period SyncFreq SyncOffs MaxCmd\n"); dev = 0; list_for_each_entry(dcb, &acb->dcb_list, list) { int nego_period; - SPRINTF("%02i %02i %02i ", dev, dcb->target_id, + seq_printf(m, "%02i %02i %02i ", dev, dcb->target_id, dcb->target_lun); YESNO(dcb->dev_mode & NTC_DO_PARITY_CHK); YESNO(dcb->sync_offset); @@ -4676,53 +4671,53 @@ static int dc395x_show_info(struct seq_file *m, struct Scsi_Host *host) YESNO(dcb->sync_mode & EN_TAG_QUEUEING); nego_period = clock_period[dcb->sync_period & 0x07] << 2; if (dcb->sync_offset) - SPRINTF(" %03i ns ", nego_period); + seq_printf(m, " %03i ns ", nego_period); else - SPRINTF(" (%03i ns)", (dcb->min_nego_period << 2)); + seq_printf(m, " (%03i ns)", (dcb->min_nego_period << 2)); if (dcb->sync_offset & 0x0f) { spd = 1000 / (nego_period); spd1 = 1000 % (nego_period); spd1 = (spd1 * 10 + nego_period / 2) / (nego_period); - SPRINTF(" %2i.%1i M %02i ", spd, spd1, + seq_printf(m, " %2i.%1i M %02i ", spd, spd1, (dcb->sync_offset & 0x0f)); } else - SPRINTF(" "); + seq_puts(m, " "); /* Add more info ... */ - SPRINTF(" %02i\n", dcb->max_command); + seq_printf(m, " %02i\n", dcb->max_command); dev++; } if (timer_pending(&acb->waiting_timer)) - SPRINTF("Waiting queue timer running\n"); + seq_puts(m, "Waiting queue timer running\n"); else - SPRINTF("\n"); + seq_putc(m, '\n'); list_for_each_entry(dcb, &acb->dcb_list, list) { struct ScsiReqBlk *srb; if (!list_empty(&dcb->srb_waiting_list)) - SPRINTF("DCB (%02i-%i): Waiting: %i:", + seq_printf(m, "DCB (%02i-%i): Waiting: %i:", dcb->target_id, dcb->target_lun, list_size(&dcb->srb_waiting_list)); list_for_each_entry(srb, &dcb->srb_waiting_list, list) - SPRINTF(" %p", srb->cmd); + seq_printf(m, " %p", srb->cmd); if (!list_empty(&dcb->srb_going_list)) - SPRINTF("\nDCB (%02i-%i): Going : %i:", + seq_printf(m, "\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(" %p", srb->cmd); + seq_printf(m, " %p", srb->cmd); if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list)) - SPRINTF("\n"); + seq_putc(m, '\n'); } if (debug_enabled(DBG_1)) { - SPRINTF("DCB list for ACB %p:\n", acb); + seq_printf(m, "DCB list for ACB %p:\n", acb); list_for_each_entry(dcb, &acb->dcb_list, list) { - SPRINTF("%p -> ", dcb); + seq_printf(m, "%p -> ", dcb); } - SPRINTF("END\n"); + seq_puts(m, "END\n"); } DC395x_UNLOCK_IO(acb->scsi_host, flags); diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 1dba62c5cf6a..1efebc9eedfb 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -136,11 +136,12 @@ static void __detach_handler (struct kref *kref) struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh; struct scsi_device *sdev = scsi_dh_data->sdev; + scsi_dh->detach(sdev); + spin_lock_irq(sdev->request_queue->queue_lock); sdev->scsi_dh_data = NULL; spin_unlock_irq(sdev->request_queue->queue_lock); - scsi_dh->detach(sdev); sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", scsi_dh->name); module_put(scsi_dh->module); } diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 0bf976936a10..2806cfbec2b9 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -568,7 +568,7 @@ static int adpt_show_info(struct seq_file *m, struct Scsi_Host *host) seq_printf(m, "\tpost fifo size = %d\n\treply fifo size = %d\n\tsg table size = %d\n\n", host->can_queue, (int) pHba->reply_fifo_size , host->sg_tablesize); - seq_printf(m, "Devices:\n"); + seq_puts(m, "Devices:\n"); for(chan = 0; chan < MAX_CHANNEL; chan++) { for(id = 0; id < MAX_ID; id++) { d = pHba->channel[chan].device[id]; diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index 8319d2b417b8..ca8003f0d8a3 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -102,7 +102,7 @@ static int eata_pio_show_info(struct seq_file *m, struct Scsi_Host *shost) shost->host_no, SD(shost)->name); seq_printf(m, "Firmware revision: v%s\n", SD(shost)->revision); - seq_printf(m, "IO: PIO\n"); + seq_puts(m, "IO: PIO\n"); seq_printf(m, "Base IO : %#.4x\n", (u32) shost->base); seq_printf(m, "Host Bus: %s\n", (SD(shost)->bustype == 'P')?"PCI ": diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c index 6776931e25d4..78ce4d61a69b 100644 --- a/drivers/scsi/esas2r/esas2r_init.c +++ b/drivers/scsi/esas2r/esas2r_init.c @@ -813,12 +813,13 @@ static void esas2r_init_pci_cfg_space(struct esas2r_adapter *a) pci_read_config_word(a->pcid, pcie_cap_reg + PCI_EXP_DEVCTL, &devcontrol); - if ((devcontrol & PCI_EXP_DEVCTL_READRQ) > 0x2000) { + if ((devcontrol & PCI_EXP_DEVCTL_READRQ) > + PCI_EXP_DEVCTL_READRQ_512B) { esas2r_log(ESAS2R_LOG_INFO, "max read request size > 512B"); devcontrol &= ~PCI_EXP_DEVCTL_READRQ; - devcontrol |= 0x2000; + devcontrol |= PCI_EXP_DEVCTL_READRQ_512B; pci_write_config_word(a->pcid, pcie_cap_reg + PCI_EXP_DEVCTL, devcontrol); diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index 7e1c21e6736b..31f8966b2e03 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -749,7 +749,7 @@ int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh) if (dev_count == 0) seq_puts(m, "none\n"); - seq_puts(m, "\n"); + seq_putc(m, '\n'); return 0; } diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index ce5bd52fe692..065b25df741b 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -2396,8 +2396,6 @@ int scsi_esp_register(struct esp *esp, struct device *dev) if (!esp->num_tags) esp->num_tags = ESP_DEFAULT_TAGS; - else if (esp->num_tags >= ESP_MAX_TAG) - esp->num_tags = ESP_MAX_TAG - 1; esp->host->transportt = esp_transport_template; esp->host->max_lun = ESP_MAX_LUN; esp->host->cmd_per_lun = 2; diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c index 9fb632684863..e66e997992e3 100644 --- a/drivers/scsi/gdth_proc.c +++ b/drivers/scsi/gdth_proc.c @@ -173,7 +173,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) /* request is i.e. "cat /proc/scsi/gdth/0" */ /* format: %-15s\t%-10s\t%-15s\t%s */ /* driver parameters */ - seq_printf(m, "Driver Parameters:\n"); + seq_puts(m, "Driver Parameters:\n"); if (reserve_list[0] == 0xff) strcpy(hrec, "--"); else { @@ -192,7 +192,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) max_ids, hdr_channel); /* controller information */ - seq_printf(m,"\nDisk Array Controller Information:\n"); + seq_puts(m, "\nDisk Array Controller Information:\n"); seq_printf(m, " Number: \t%d \tName: \t%s\n", ha->hanum, ha->binfo.type_string); @@ -219,7 +219,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) #ifdef GDTH_DMA_STATISTICS /* controller statistics */ - seq_printf(m,"\nController Statistics:\n"); + seq_puts(m, "\nController Statistics:\n"); seq_printf(m, " 32-bit DMA buffer:\t%lu\t64-bit DMA buffer:\t%lu\n", ha->dma32_cnt, ha->dma64_cnt); @@ -227,7 +227,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) if (ha->more_proc) { /* more information: 2. about physical devices */ - seq_printf(m, "\nPhysical Devices:"); + seq_puts(m, "\nPhysical Devices:"); flag = FALSE; buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr); @@ -326,10 +326,10 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); if (!flag) - seq_printf(m, "\n --\n"); + seq_puts(m, "\n --\n"); /* 3. about logical drives */ - seq_printf(m,"\nLogical Drives:"); + seq_puts(m, "\nLogical Drives:"); flag = FALSE; buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr); @@ -411,10 +411,10 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); if (!flag) - seq_printf(m, "\n --\n"); + seq_puts(m, "\n --\n"); /* 4. about array drives */ - seq_printf(m,"\nArray Drives:"); + seq_puts(m, "\nArray Drives:"); flag = FALSE; buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr); @@ -471,10 +471,10 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); if (!flag) - seq_printf(m, "\n --\n"); + seq_puts(m, "\n --\n"); /* 5. about host drives */ - seq_printf(m,"\nHost Drives:"); + seq_puts(m, "\nHost Drives:"); flag = FALSE; buf = gdth_ioctl_alloc(ha, sizeof(gdth_hget_str), FALSE, &paddr); @@ -527,11 +527,11 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host) } if (!flag) - seq_printf(m, "\n --\n"); + seq_puts(m, "\n --\n"); } /* controller events */ - seq_printf(m,"\nController Events:\n"); + seq_puts(m, "\nController Events:\n"); for (id = -1;;) { id = gdth_read_event(ha, id, estr); diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6bb4611b238a..95d581c45413 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include "hpsa_cmd.h" #include "hpsa.h" @@ -59,8 +60,11 @@ #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" -/* How long to wait (in milliseconds) for board to go into simple mode */ -#define MAX_CONFIG_WAIT 30000 +/* How long to wait for CISS doorbell communication */ +#define CLEAR_EVENT_WAIT_INTERVAL 20 /* ms for each msleep() call */ +#define MODE_CHANGE_WAIT_INTERVAL 10 /* ms for each msleep() call */ +#define MAX_CLEAR_EVENT_WAIT 30000 /* times 20 ms = 600 s */ +#define MAX_MODE_CHANGE_WAIT 2000 /* times 10 ms = 20 s */ #define MAX_IOCTL_CONFIG_WAIT 1000 /*define how many times we will try a command because of bus resets */ @@ -164,24 +168,24 @@ static struct board_type products[] = { {0x1926103C, "Smart Array P731m", &SA5_access}, {0x1928103C, "Smart Array P230i", &SA5_access}, {0x1929103C, "Smart Array P530", &SA5_access}, - {0x21BD103C, "Smart Array", &SA5_access}, - {0x21BE103C, "Smart Array", &SA5_access}, - {0x21BF103C, "Smart Array", &SA5_access}, - {0x21C0103C, "Smart Array", &SA5_access}, - {0x21C1103C, "Smart Array", &SA5_access}, - {0x21C2103C, "Smart Array", &SA5_access}, - {0x21C3103C, "Smart Array", &SA5_access}, + {0x21BD103C, "Smart Array P244br", &SA5_access}, + {0x21BE103C, "Smart Array P741m", &SA5_access}, + {0x21BF103C, "Smart HBA H240ar", &SA5_access}, + {0x21C0103C, "Smart Array P440ar", &SA5_access}, + {0x21C1103C, "Smart Array P840ar", &SA5_access}, + {0x21C2103C, "Smart Array P440", &SA5_access}, + {0x21C3103C, "Smart Array P441", &SA5_access}, {0x21C4103C, "Smart Array", &SA5_access}, - {0x21C5103C, "Smart Array", &SA5_access}, - {0x21C6103C, "Smart Array", &SA5_access}, - {0x21C7103C, "Smart Array", &SA5_access}, - {0x21C8103C, "Smart Array", &SA5_access}, + {0x21C5103C, "Smart Array P841", &SA5_access}, + {0x21C6103C, "Smart HBA H244br", &SA5_access}, + {0x21C7103C, "Smart HBA H240", &SA5_access}, + {0x21C8103C, "Smart HBA H241", &SA5_access}, {0x21C9103C, "Smart Array", &SA5_access}, - {0x21CA103C, "Smart Array", &SA5_access}, - {0x21CB103C, "Smart Array", &SA5_access}, + {0x21CA103C, "Smart Array P246br", &SA5_access}, + {0x21CB103C, "Smart Array P840", &SA5_access}, {0x21CC103C, "Smart Array", &SA5_access}, {0x21CD103C, "Smart Array", &SA5_access}, - {0x21CE103C, "Smart Array", &SA5_access}, + {0x21CE103C, "Smart HBA", &SA5_access}, {0x00761590, "HP Storage P1224 Array Controller", &SA5_access}, {0x00871590, "HP Storage P1224e Array Controller", &SA5_access}, {0x007D1590, "HP Storage P1228 Array Controller", &SA5_access}, @@ -195,8 +199,6 @@ static int number_of_controllers; static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id); static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id); static int hpsa_ioctl(struct scsi_device *dev, int cmd, void __user *arg); -static void lock_and_start_io(struct ctlr_info *h); -static void start_io(struct ctlr_info *h, unsigned long *flags); #ifdef CONFIG_COMPAT static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, @@ -204,18 +206,18 @@ static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, #endif static void cmd_free(struct ctlr_info *h, struct CommandList *c); -static void cmd_special_free(struct ctlr_info *h, struct CommandList *c); static struct CommandList *cmd_alloc(struct ctlr_info *h); -static struct CommandList *cmd_special_alloc(struct ctlr_info *h); static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, void *buff, size_t size, u16 page_code, unsigned char *scsi3addr, int cmd_type); +static void hpsa_free_cmd_pool(struct ctlr_info *h); #define VPD_PAGE (1 << 8) static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); static void hpsa_scan_start(struct Scsi_Host *); static int hpsa_scan_finished(struct Scsi_Host *sh, unsigned long elapsed_time); +static int hpsa_change_queue_depth(struct scsi_device *sdev, int qdepth); static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd); static int hpsa_eh_abort_handler(struct scsi_cmnd *scsicmd); @@ -229,7 +231,7 @@ static void check_ioctl_unit_attention(struct ctlr_info *h, struct CommandList *c); /* performant mode helper functions */ static void calc_bucket_map(int *bucket, int num_buckets, - int nsgs, int min_blocks, int *bucket_map); + int nsgs, int min_blocks, u32 *bucket_map); static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); static inline u32 next_command(struct ctlr_info *h, u8 q); static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr, @@ -241,14 +243,15 @@ static int hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id); static int hpsa_wait_for_board_state(struct pci_dev *pdev, void __iomem *vaddr, int wait_for_ready); static inline void finish_cmd(struct CommandList *c); -static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h); +static int hpsa_wait_for_mode_change_ack(struct ctlr_info *h); #define BOARD_NOT_READY 0 #define BOARD_READY 1 static void hpsa_drain_accel_commands(struct ctlr_info *h); static void hpsa_flush_cache(struct ctlr_info *h); static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, - u8 *scsi3addr); + u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk); +static void hpsa_command_resubmit_worker(struct work_struct *work); static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) { @@ -505,8 +508,8 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[]) return (scsi3addr[3] & 0xC0) == 0x40; } -static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", - "1(ADM)", "UNKNOWN" +static const char * const raid_label[] = { "0", "4", "1(+0)", "5", "5+1", "6", + "1(+0)ADM", "UNKNOWN" }; #define HPSA_RAID_0 0 #define HPSA_RAID_4 1 @@ -671,7 +674,7 @@ static struct scsi_host_template hpsa_driver_template = { .queuecommand = hpsa_scsi_queue_command, .scan_start = hpsa_scan_start, .scan_finished = hpsa_scan_finished, - .change_queue_depth = scsi_change_queue_depth, + .change_queue_depth = hpsa_change_queue_depth, .this_id = -1, .use_clustering = ENABLE_CLUSTERING, .eh_abort_handler = hpsa_eh_abort_handler, @@ -688,13 +691,6 @@ static struct scsi_host_template hpsa_driver_template = { .no_write_same = 1, }; - -/* Enqueuing and dequeuing functions for cmdlists. */ -static inline void addQ(struct list_head *list, struct CommandList *c) -{ - list_add_tail(&c->list, list); -} - static inline u32 next_command(struct ctlr_info *h, u8 q) { u32 a; @@ -828,31 +824,21 @@ static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h, static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c) { - unsigned long flags; - + dial_down_lockup_detection_during_fw_flash(h, c); + atomic_inc(&h->commands_outstanding); switch (c->cmd_type) { case CMD_IOACCEL1: set_ioaccel1_performant_mode(h, c); + writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); break; case CMD_IOACCEL2: set_ioaccel2_performant_mode(h, c); + writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32); break; default: set_performant_mode(h, c); + h->access.submit_command(h, c); } - dial_down_lockup_detection_during_fw_flash(h, c); - spin_lock_irqsave(&h->lock, flags); - addQ(&h->reqQ, c); - h->Qdepth++; - start_io(h, &flags); - spin_unlock_irqrestore(&h->lock, flags); -} - -static inline void removeQ(struct CommandList *c) -{ - if (WARN_ON(list_empty(&c->list))) - return; - list_del_init(&c->list); } static inline int is_hba_lunid(unsigned char scsi3addr[]) @@ -919,7 +905,7 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, /* If this device a non-zero lun of a multi-lun device * byte 4 of the 8-byte LUN addr will contain the logical - * unit no, zero otherise. + * unit no, zero otherwise. */ if (device->scsi3addr[4] == 0) { /* This is not a non-zero lun of a multi-lun device */ @@ -984,12 +970,24 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, /* Raid level changed. */ h->dev[entry]->raid_level = new_entry->raid_level; - /* Raid offload parameters changed. */ + /* Raid offload parameters changed. Careful about the ordering. */ + if (new_entry->offload_config && new_entry->offload_enabled) { + /* + * if drive is newly offload_enabled, we want to copy the + * raid map data first. If previously offload_enabled and + * offload_config were set, raid map data had better be + * the same as it was before. if raid map data is changed + * then it had better be the case that + * h->dev[entry]->offload_enabled is currently 0. + */ + h->dev[entry]->raid_map = new_entry->raid_map; + h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle; + wmb(); /* ensure raid map updated prior to ->offload_enabled */ + } h->dev[entry]->offload_config = new_entry->offload_config; - h->dev[entry]->offload_enabled = new_entry->offload_enabled; - h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle; h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror; - h->dev[entry]->raid_map = new_entry->raid_map; + h->dev[entry]->offload_enabled = new_entry->offload_enabled; + h->dev[entry]->queue_depth = new_entry->queue_depth; dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d updated.\n", scsi_device_type(new_entry->devtype), hostno, new_entry->bus, @@ -1115,6 +1113,8 @@ static inline int device_updated(struct hpsa_scsi_dev_t *dev1, return 1; if (dev1->offload_enabled != dev2->offload_enabled) return 1; + if (dev1->queue_depth != dev2->queue_depth) + return 1; return 0; } @@ -1260,6 +1260,85 @@ static void hpsa_show_volume_status(struct ctlr_info *h, } } +/* + * Figure the list of physical drive pointers for a logical drive with + * raid offload configured. + */ +static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, + struct hpsa_scsi_dev_t *dev[], int ndevices, + struct hpsa_scsi_dev_t *logical_drive) +{ + struct raid_map_data *map = &logical_drive->raid_map; + struct raid_map_disk_data *dd = &map->data[0]; + int i, j; + int total_disks_per_row = le16_to_cpu(map->data_disks_per_row) + + le16_to_cpu(map->metadata_disks_per_row); + int nraid_map_entries = le16_to_cpu(map->row_cnt) * + le16_to_cpu(map->layout_map_count) * + total_disks_per_row; + int nphys_disk = le16_to_cpu(map->layout_map_count) * + total_disks_per_row; + int qdepth; + + if (nraid_map_entries > RAID_MAP_MAX_ENTRIES) + nraid_map_entries = RAID_MAP_MAX_ENTRIES; + + qdepth = 0; + for (i = 0; i < nraid_map_entries; i++) { + logical_drive->phys_disk[i] = NULL; + if (!logical_drive->offload_config) + continue; + for (j = 0; j < ndevices; j++) { + if (dev[j]->devtype != TYPE_DISK) + continue; + if (is_logical_dev_addr_mode(dev[j]->scsi3addr)) + continue; + if (dev[j]->ioaccel_handle != dd[i].ioaccel_handle) + continue; + + logical_drive->phys_disk[i] = dev[j]; + if (i < nphys_disk) + qdepth = min(h->nr_cmds, qdepth + + logical_drive->phys_disk[i]->queue_depth); + break; + } + + /* + * This can happen if a physical drive is removed and + * the logical drive is degraded. In that case, the RAID + * map data will refer to a physical disk which isn't actually + * present. And in that case offload_enabled should already + * be 0, but we'll turn it off here just in case + */ + if (!logical_drive->phys_disk[i]) { + logical_drive->offload_enabled = 0; + logical_drive->queue_depth = h->nr_cmds; + } + } + if (nraid_map_entries) + /* + * This is correct for reads, too high for full stripe writes, + * way too high for partial stripe writes + */ + logical_drive->queue_depth = qdepth; + else + logical_drive->queue_depth = h->nr_cmds; +} + +static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h, + struct hpsa_scsi_dev_t *dev[], int ndevices) +{ + int i; + + for (i = 0; i < ndevices; i++) { + if (dev[i]->devtype != TYPE_DISK) + continue; + if (!is_logical_dev_addr_mode(dev[i]->scsi3addr)) + continue; + hpsa_figure_phys_disk_ptrs(h, dev, ndevices, dev[i]); + } +} + static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, struct hpsa_scsi_dev_t *sd[], int nsds) { @@ -1444,8 +1523,12 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) spin_lock_irqsave(&h->devlock, flags); sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), sdev_id(sdev), sdev->lun); - if (sd != NULL) + if (sd != NULL) { sdev->hostdata = sd; + if (sd->queue_depth) + scsi_change_queue_depth(sdev, sd->queue_depth); + atomic_set(&sd->ioaccel_cmds_out, 0); + } spin_unlock_irqrestore(&h->devlock, flags); return 0; } @@ -1478,13 +1561,17 @@ static int hpsa_allocate_sg_chain_blocks(struct ctlr_info *h) h->cmd_sg_list = kzalloc(sizeof(*h->cmd_sg_list) * h->nr_cmds, GFP_KERNEL); - if (!h->cmd_sg_list) + if (!h->cmd_sg_list) { + dev_err(&h->pdev->dev, "Failed to allocate SG list\n"); return -ENOMEM; + } for (i = 0; i < h->nr_cmds; i++) { h->cmd_sg_list[i] = kmalloc(sizeof(*h->cmd_sg_list[i]) * h->chainsize, GFP_KERNEL); - if (!h->cmd_sg_list[i]) + if (!h->cmd_sg_list[i]) { + dev_err(&h->pdev->dev, "Failed to allocate cmd SG\n"); goto clean; + } } return 0; @@ -1504,7 +1591,7 @@ static int hpsa_map_sg_chain_block(struct ctlr_info *h, chain_block = h->cmd_sg_list[c->cmdindex]; chain_sg->Ext = cpu_to_le32(HPSA_SG_CHAIN); chain_len = sizeof(*chain_sg) * - (c->Header.SGTotal - h->max_cmd_sg_entries); + (le16_to_cpu(c->Header.SGTotal) - h->max_cmd_sg_entries); chain_sg->Len = cpu_to_le32(chain_len); temp64 = pci_map_single(h->pdev, chain_block, chain_len, PCI_DMA_TODEVICE); @@ -1635,7 +1722,6 @@ static void process_ioaccel2_completion(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev) { struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; - int raid_retry = 0; /* check for good status */ if (likely(c2->error_data.serv_response == 0 && @@ -1652,26 +1738,22 @@ static void process_ioaccel2_completion(struct ctlr_info *h, if (is_logical_dev_addr_mode(dev->scsi3addr) && c2->error_data.serv_response == IOACCEL2_SERV_RESPONSE_FAILURE) { - dev->offload_enabled = 0; - h->drv_req_rescan = 1; /* schedule controller for a rescan */ - cmd->result = DID_SOFT_ERROR << 16; - cmd_free(h, c); - cmd->scsi_done(cmd); - return; - } - raid_retry = handle_ioaccel_mode2_error(h, c, cmd, c2); - /* If error found, disable Smart Path, schedule a rescan, - * and force a retry on the standard path. - */ - if (raid_retry) { - dev_warn(&h->pdev->dev, "%s: Retrying on standard path.\n", - "HP SSD Smart Path"); - dev->offload_enabled = 0; /* Disable Smart Path */ - h->drv_req_rescan = 1; /* schedule controller rescan */ - cmd->result = DID_SOFT_ERROR << 16; + if (c2->error_data.status == + IOACCEL2_STATUS_SR_IOACCEL_DISABLED) + dev->offload_enabled = 0; + goto retry_cmd; } + + if (handle_ioaccel_mode2_error(h, c, cmd, c2)) + goto retry_cmd; + cmd_free(h, c); cmd->scsi_done(cmd); + return; + +retry_cmd: + INIT_WORK(&c->work, hpsa_command_resubmit_worker); + queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work); } static void complete_scsi_command(struct CommandList *cp) @@ -1687,18 +1769,21 @@ static void complete_scsi_command(struct CommandList *cp) unsigned long sense_data_size; ei = cp->err_info; - cmd = (struct scsi_cmnd *) cp->scsi_cmd; + cmd = cp->scsi_cmd; h = cp->h; dev = cmd->device->hostdata; scsi_dma_unmap(cmd); /* undo the DMA mappings */ if ((cp->cmd_type == CMD_SCSI) && - (cp->Header.SGTotal > h->max_cmd_sg_entries)) + (le16_to_cpu(cp->Header.SGTotal) > h->max_cmd_sg_entries)) hpsa_unmap_sg_chain_block(h, cp); cmd->result = (DID_OK << 16); /* host byte */ cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ + if (cp->cmd_type == CMD_IOACCEL2 || cp->cmd_type == CMD_IOACCEL1) + atomic_dec(&cp->phys_disk->ioaccel_cmds_out); + if (cp->cmd_type == CMD_IOACCEL2) return process_ioaccel2_completion(h, cp, cmd, dev); @@ -1706,6 +1791,8 @@ static void complete_scsi_command(struct CommandList *cp) scsi_set_resid(cmd, ei->ResidualCnt); if (ei->CommandStatus == 0) { + if (cp->cmd_type == CMD_IOACCEL1) + atomic_dec(&cp->phys_disk->ioaccel_cmds_out); cmd_free(h, cp); cmd->scsi_done(cmd); return; @@ -1726,8 +1813,10 @@ static void complete_scsi_command(struct CommandList *cp) */ if (cp->cmd_type == CMD_IOACCEL1) { struct io_accel1_cmd *c = &h->ioaccel_cmd_pool[cp->cmdindex]; - cp->Header.SGList = cp->Header.SGTotal = scsi_sg_count(cmd); - cp->Request.CDBLen = c->io_flags & IOACCEL1_IOFLAGS_CDBLEN_MASK; + cp->Header.SGList = scsi_sg_count(cmd); + cp->Header.SGTotal = cpu_to_le16(cp->Header.SGList); + cp->Request.CDBLen = le16_to_cpu(c->io_flags) & + IOACCEL1_IOFLAGS_CDBLEN_MASK; cp->Header.tag = c->tag; memcpy(cp->Header.LUN.LunAddrBytes, c->CISS_LUN, 8); memcpy(cp->Request.CDB, c->CDB, cp->Request.CDBLen); @@ -1739,9 +1828,9 @@ static void complete_scsi_command(struct CommandList *cp) if (is_logical_dev_addr_mode(dev->scsi3addr)) { if (ei->CommandStatus == CMD_IOACCEL_DISABLED) dev->offload_enabled = 0; - cmd->result = DID_SOFT_ERROR << 16; - cmd_free(h, cp); - cmd->scsi_done(cmd); + INIT_WORK(&cp->work, hpsa_command_resubmit_worker); + queue_work_on(raw_smp_processor_id(), + h->resubmit_wq, &cp->work); return; } } @@ -1798,9 +1887,8 @@ static void complete_scsi_command(struct CommandList *cp) case CMD_DATA_UNDERRUN: /* let mid layer handle it. */ break; case CMD_DATA_OVERRUN: - dev_warn(&h->pdev->dev, "cp %p has" - " completed with data overrun " - "reported\n", cp); + dev_warn(&h->pdev->dev, + "CDB %16phN data overrun\n", cp->Request.CDB); break; case CMD_INVALID: { /* print_bytes(cp, sizeof(*cp), 1, 0); @@ -1816,34 +1904,38 @@ static void complete_scsi_command(struct CommandList *cp) break; case CMD_PROTOCOL_ERR: cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p has " - "protocol error\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : protocol error\n", + cp->Request.CDB); break; case CMD_HARDWARE_ERR: cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p had hardware error\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : hardware error\n", + cp->Request.CDB); break; case CMD_CONNECTION_LOST: cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p had connection lost\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : connection lost\n", + cp->Request.CDB); break; case CMD_ABORTED: cmd->result = DID_ABORT << 16; - dev_warn(&h->pdev->dev, "cp %p was aborted with status 0x%x\n", - cp, ei->ScsiStatus); + dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n", + cp->Request.CDB, ei->ScsiStatus); break; case CMD_ABORT_FAILED: cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p reports abort failed\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : abort failed\n", + cp->Request.CDB); break; case CMD_UNSOLICITED_ABORT: cmd->result = DID_SOFT_ERROR << 16; /* retry the command */ - dev_warn(&h->pdev->dev, "cp %p aborted due to an unsolicited " - "abort\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN : unsolicited abort\n", + cp->Request.CDB); break; case CMD_TIMEOUT: cmd->result = DID_TIME_OUT << 16; - dev_warn(&h->pdev->dev, "cp %p timedout\n", cp); + dev_warn(&h->pdev->dev, "CDB %16phN timed out\n", + cp->Request.CDB); break; case CMD_UNABORTABLE: cmd->result = DID_ERROR << 16; @@ -2048,10 +2140,10 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *c; struct ErrorInfo *ei; - c = cmd_special_alloc(h); + c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + if (c == NULL) { + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } @@ -2067,7 +2159,7 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr, rc = -1; } out: - cmd_special_free(h, c); + cmd_free(h, c); return rc; } @@ -2079,10 +2171,9 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, struct CommandList *c; struct ErrorInfo *ei; - c = cmd_special_alloc(h); - + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } @@ -2098,7 +2189,7 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, rc = -1; } out: - cmd_special_free(h, c); + cmd_free(h, c); return rc; } @@ -2109,10 +2200,10 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *c; struct ErrorInfo *ei; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } @@ -2128,7 +2219,7 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, hpsa_scsi_interpret_error(h, c); rc = -1; } - cmd_special_free(h, c); + cmd_free(h, c); return rc; } @@ -2191,15 +2282,13 @@ static void hpsa_debug_map_buff(struct ctlr_info *h, int rc, le16_to_cpu(map_buff->row_cnt)); dev_info(&h->pdev->dev, "layout_map_count = %u\n", le16_to_cpu(map_buff->layout_map_count)); - dev_info(&h->pdev->dev, "flags = %u\n", + dev_info(&h->pdev->dev, "flags = 0x%x\n", le16_to_cpu(map_buff->flags)); - if (map_buff->flags & RAID_MAP_FLAG_ENCRYPT_ON) - dev_info(&h->pdev->dev, "encrypytion = ON\n"); - else - dev_info(&h->pdev->dev, "encrypytion = OFF\n"); + dev_info(&h->pdev->dev, "encrypytion = %s\n", + le16_to_cpu(map_buff->flags) & + RAID_MAP_FLAG_ENCRYPT_ON ? "ON" : "OFF"); dev_info(&h->pdev->dev, "dekindex = %u\n", le16_to_cpu(map_buff->dekindex)); - map_cnt = le16_to_cpu(map_buff->layout_map_count); for (map = 0; map < map_cnt; map++) { dev_info(&h->pdev->dev, "Map%u:\n", map); @@ -2238,26 +2327,26 @@ static int hpsa_get_raid_map(struct ctlr_info *h, struct CommandList *c; struct ErrorInfo *ei; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } if (fill_cmd(c, HPSA_GET_RAID_MAP, h, &this_device->raid_map, sizeof(this_device->raid_map), 0, scsi3addr, TYPE_CMD)) { dev_warn(&h->pdev->dev, "Out of memory in hpsa_get_raid_map()\n"); - cmd_special_free(h, c); + cmd_free(h, c); return -ENOMEM; } hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE); ei = c->err_info; if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { hpsa_scsi_interpret_error(h, c); - cmd_special_free(h, c); + cmd_free(h, c); return -1; } - cmd_special_free(h, c); + cmd_free(h, c); /* @todo in the future, dynamically allocate RAID map memory */ if (le32_to_cpu(this_device->raid_map.structure_size) > @@ -2269,6 +2358,34 @@ static int hpsa_get_raid_map(struct ctlr_info *h, return rc; } +static int hpsa_bmic_id_physical_device(struct ctlr_info *h, + unsigned char scsi3addr[], u16 bmic_device_index, + struct bmic_identify_physical_device *buf, size_t bufsize) +{ + int rc = IO_OK; + struct CommandList *c; + struct ErrorInfo *ei; + + c = cmd_alloc(h); + rc = fill_cmd(c, BMIC_IDENTIFY_PHYSICAL_DEVICE, h, buf, bufsize, + 0, RAID_CTLR_LUNID, TYPE_CMD); + if (rc) + goto out; + + c->Request.CDB[2] = bmic_device_index & 0xff; + c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff; + + hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE); + ei = c->err_info; + if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { + hpsa_scsi_interpret_error(h, c); + rc = -1; + } +out: + cmd_free(h, c); + return rc; +} + static int hpsa_vpd_page_supported(struct ctlr_info *h, unsigned char scsi3addr[], u8 page) { @@ -2369,7 +2486,7 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr, } static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, - struct ReportLUNdata *buf, int bufsize, + void *buf, int bufsize, int extended_response) { int rc = IO_OK; @@ -2377,9 +2494,9 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, unsigned char scsi3addr[8]; struct ErrorInfo *ei; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ - dev_err(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -1; } /* address the controller */ @@ -2398,24 +2515,26 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, hpsa_scsi_interpret_error(h, c); rc = -1; } else { - if (buf->extended_response_flag != extended_response) { + struct ReportLUNdata *rld = buf; + + if (rld->extended_response_flag != extended_response) { dev_err(&h->pdev->dev, "report luns requested format %u, got %u\n", extended_response, - buf->extended_response_flag); + rld->extended_response_flag); rc = -1; } } out: - cmd_special_free(h, c); + cmd_free(h, c); return rc; } static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h, - struct ReportLUNdata *buf, - int bufsize, int extended_response) + struct ReportExtendedLUNdata *buf, int bufsize) { - return hpsa_scsi_do_report_luns(h, 0, buf, bufsize, extended_response); + return hpsa_scsi_do_report_luns(h, 0, buf, bufsize, + HPSA_REPORT_PHYS_EXTENDED); } static inline int hpsa_scsi_do_report_log_luns(struct ctlr_info *h, @@ -2590,6 +2709,7 @@ static int hpsa_update_device_info(struct ctlr_info *h, this_device->offload_config = 0; this_device->offload_enabled = 0; this_device->volume_offline = 0; + this_device->queue_depth = h->nr_cmds; } if (is_OBDR_device) { @@ -2732,7 +2852,6 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, { struct ReportExtendedLUNdata *physicals = NULL; int responsesize = 24; /* size of physical extended response */ - int extended = 2; /* flag forces reporting 'other dev info'. */ int reportsize = sizeof(*physicals) + HPSA_MAX_PHYS_LUN * responsesize; u32 nphysicals = 0; /* number of reported physical devs */ int found = 0; /* found match (1) or not (0) */ @@ -2741,8 +2860,8 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, struct scsi_cmnd *scmd; /* scsi command within request being aborted */ struct hpsa_scsi_dev_t *d; /* device of request being aborted */ struct io_accel2_cmd *c2a; /* ioaccel2 command to abort */ - u32 it_nexus; /* 4 byte device handle for the ioaccel2 cmd */ - u32 scsi_nexus; /* 4 byte device handle for the ioaccel2 cmd */ + __le32 it_nexus; /* 4 byte device handle for the ioaccel2 cmd */ + __le32 scsi_nexus; /* 4 byte device handle for the ioaccel2 cmd */ if (ioaccel2_cmd_to_abort->cmd_type != CMD_IOACCEL2) return 0; /* no match */ @@ -2761,8 +2880,8 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, return 0; /* no match */ it_nexus = cpu_to_le32(d->ioaccel_handle); - scsi_nexus = cpu_to_le32(c2a->scsi_nexus); - find = c2a->scsi_nexus; + scsi_nexus = c2a->scsi_nexus; + find = le32_to_cpu(c2a->scsi_nexus); if (h->raid_offload_debug > 0) dev_info(&h->pdev->dev, @@ -2779,8 +2898,7 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, physicals = kzalloc(reportsize, GFP_KERNEL); if (physicals == NULL) return 0; - if (hpsa_scsi_do_report_phys_luns(h, (struct ReportLUNdata *) physicals, - reportsize, extended)) { + if (hpsa_scsi_do_report_phys_luns(h, physicals, reportsize)) { dev_err(&h->pdev->dev, "Can't lookup %s device handle: report physical LUNs failed.\n", "HP SSD Smart Path"); @@ -2821,34 +2939,20 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, * Returns 0 on success, -1 otherwise. */ static int hpsa_gather_lun_info(struct ctlr_info *h, - int reportphyslunsize, int reportloglunsize, - struct ReportLUNdata *physdev, u32 *nphysicals, int *physical_mode, + struct ReportExtendedLUNdata *physdev, u32 *nphysicals, struct ReportLUNdata *logdev, u32 *nlogicals) { - int physical_entry_size = 8; - - *physical_mode = 0; - - /* For I/O accelerator mode we need to read physical device handles */ - if (h->transMethod & CFGTBL_Trans_io_accel1 || - h->transMethod & CFGTBL_Trans_io_accel2) { - *physical_mode = HPSA_REPORT_PHYS_EXTENDED; - physical_entry_size = 24; - } - if (hpsa_scsi_do_report_phys_luns(h, physdev, reportphyslunsize, - *physical_mode)) { + if (hpsa_scsi_do_report_phys_luns(h, physdev, sizeof(*physdev))) { dev_err(&h->pdev->dev, "report physical LUNs failed.\n"); return -1; } - *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / - physical_entry_size; + *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / 24; if (*nphysicals > HPSA_MAX_PHYS_LUN) { - dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded." - " %d LUNs ignored.\n", HPSA_MAX_PHYS_LUN, - *nphysicals - HPSA_MAX_PHYS_LUN); + dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded. %d LUNs ignored.\n", + HPSA_MAX_PHYS_LUN, *nphysicals - HPSA_MAX_PHYS_LUN); *nphysicals = HPSA_MAX_PHYS_LUN; } - if (hpsa_scsi_do_report_log_luns(h, logdev, reportloglunsize)) { + if (hpsa_scsi_do_report_log_luns(h, logdev, sizeof(*logdev))) { dev_err(&h->pdev->dev, "report logical LUNs failed.\n"); return -1; } @@ -2921,6 +3025,33 @@ static int hpsa_hba_mode_enabled(struct ctlr_info *h) return hba_mode_enabled; } +/* get physical drive ioaccel handle and queue depth */ +static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h, + struct hpsa_scsi_dev_t *dev, + u8 *lunaddrbytes, + struct bmic_identify_physical_device *id_phys) +{ + int rc; + struct ext_report_lun_entry *rle = + (struct ext_report_lun_entry *) lunaddrbytes; + + dev->ioaccel_handle = rle->ioaccel_handle; + memset(id_phys, 0, sizeof(*id_phys)); + rc = hpsa_bmic_id_physical_device(h, lunaddrbytes, + GET_BMIC_DRIVE_NUMBER(lunaddrbytes), id_phys, + sizeof(*id_phys)); + if (!rc) + /* Reserve space for FW operations */ +#define DRIVE_CMDS_RESERVED_FOR_FW 2 +#define DRIVE_QUEUE_DEPTH 7 + dev->queue_depth = + le16_to_cpu(id_phys->current_queue_depth_limit) - + DRIVE_CMDS_RESERVED_FOR_FW; + else + dev->queue_depth = DRIVE_QUEUE_DEPTH; /* conservative */ + atomic_set(&dev->ioaccel_cmds_out, 0); +} + static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) { /* the idea here is we could get notified @@ -2935,9 +3066,9 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) */ struct ReportExtendedLUNdata *physdev_list = NULL; struct ReportLUNdata *logdev_list = NULL; + struct bmic_identify_physical_device *id_phys = NULL; u32 nphysicals = 0; u32 nlogicals = 0; - int physical_mode = 0; u32 ndev_allocated = 0; struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice; int ncurrent = 0; @@ -2950,8 +3081,10 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) physdev_list = kzalloc(sizeof(*physdev_list), GFP_KERNEL); logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL); tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL); + id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL); - if (!currentsd || !physdev_list || !logdev_list || !tmpdevice) { + if (!currentsd || !physdev_list || !logdev_list || + !tmpdevice || !id_phys) { dev_err(&h->pdev->dev, "out of memory\n"); goto out; } @@ -2968,10 +3101,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) h->hba_mode_enabled = rescan_hba_mode; - if (hpsa_gather_lun_info(h, - sizeof(*physdev_list), sizeof(*logdev_list), - (struct ReportLUNdata *) physdev_list, &nphysicals, - &physical_mode, logdev_list, &nlogicals)) + if (hpsa_gather_lun_info(h, physdev_list, &nphysicals, + logdev_list, &nlogicals)) goto out; /* We might see up to the maximum number of logical and physical disks @@ -3068,10 +3199,11 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) ncurrent++; break; } - if (physical_mode == HPSA_REPORT_PHYS_EXTENDED) { - memcpy(&this_device->ioaccel_handle, - &lunaddrbytes[20], - sizeof(this_device->ioaccel_handle)); + if (h->transMethod & CFGTBL_Trans_io_accel1 || + h->transMethod & CFGTBL_Trans_io_accel2) { + hpsa_get_ioaccel_drive_info(h, this_device, + lunaddrbytes, id_phys); + atomic_set(&this_device->ioaccel_cmds_out, 0); ncurrent++; } break; @@ -3095,6 +3227,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) if (ncurrent >= HPSA_MAX_DEVICES) break; } + hpsa_update_log_drive_phys_drive_ptrs(h, currentsd, ncurrent); adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent); out: kfree(tmpdevice); @@ -3103,9 +3236,22 @@ out: kfree(currentsd); kfree(physdev_list); kfree(logdev_list); + kfree(id_phys); } -/* hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci +static void hpsa_set_sg_descriptor(struct SGDescriptor *desc, + struct scatterlist *sg) +{ + u64 addr64 = (u64) sg_dma_address(sg); + unsigned int len = sg_dma_len(sg); + + desc->Addr = cpu_to_le64(addr64); + desc->Len = cpu_to_le32(len); + desc->Ext = 0; +} + +/* + * hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci * dma mapping and fills in the scatter gather entries of the * hpsa command, cp. */ @@ -3113,9 +3259,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h, struct CommandList *cp, struct scsi_cmnd *cmd) { - unsigned int len; struct scatterlist *sg; - u64 addr64; int use_sg, i, sg_index, chained; struct SGDescriptor *curr_sg; @@ -3138,13 +3282,11 @@ static int hpsa_scatter_gather(struct ctlr_info *h, curr_sg = h->cmd_sg_list[cp->cmdindex]; sg_index = 0; } - addr64 = (u64) sg_dma_address(sg); - len = sg_dma_len(sg); - curr_sg->Addr = cpu_to_le64(addr64); - curr_sg->Len = cpu_to_le32(len); - curr_sg->Ext = cpu_to_le32(0); + hpsa_set_sg_descriptor(curr_sg, sg); curr_sg++; } + + /* Back the pointer up to the last entry and mark it as "last". */ (--curr_sg)->Ext = cpu_to_le32(HPSA_SG_LAST); if (use_sg + chained > h->maxSG) @@ -3163,7 +3305,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h, sglist_finished: cp->Header.SGList = (u8) use_sg; /* no. SGs contig in this cmd */ - cp->Header.SGTotal = cpu_to_le16(use_sg); /* total sgs in this cmd list */ + cp->Header.SGTotal = cpu_to_le16(use_sg); /* total sgs in cmd list */ return 0; } @@ -3217,7 +3359,7 @@ static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len) static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, - u8 *scsi3addr) + u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk) { struct scsi_cmnd *cmd = c->scsi_cmd; struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex]; @@ -3230,13 +3372,17 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, u32 control = IOACCEL1_CONTROL_SIMPLEQUEUE; /* TODO: implement chaining support */ - if (scsi_sg_count(cmd) > h->ioaccel_maxsg) + if (scsi_sg_count(cmd) > h->ioaccel_maxsg) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; + } BUG_ON(cmd->cmd_len > IOACCEL1_IOFLAGS_CDBLEN_MAX); - if (fixup_ioaccel_cdb(cdb, &cdb_len)) + if (fixup_ioaccel_cdb(cdb, &cdb_len)) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; + } c->cmd_type = CMD_IOACCEL1; @@ -3246,8 +3392,10 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, BUG_ON(c->busaddr & 0x0000007F); use_sg = scsi_dma_map(cmd); - if (use_sg < 0) + if (use_sg < 0) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return use_sg; + } if (use_sg) { curr_sg = cp->SG; @@ -3284,11 +3432,11 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, c->Header.SGList = use_sg; /* Fill out the command structure to submit */ - cp->dev_handle = ioaccel_handle & 0xFFFF; - cp->transfer_len = total_len; - cp->io_flags = IOACCEL1_IOFLAGS_IO_REQ | - (cdb_len & IOACCEL1_IOFLAGS_CDBLEN_MASK); - cp->control = control; + cp->dev_handle = cpu_to_le16(ioaccel_handle & 0xFFFF); + cp->transfer_len = cpu_to_le32(total_len); + cp->io_flags = cpu_to_le16(IOACCEL1_IOFLAGS_IO_REQ | + (cdb_len & IOACCEL1_IOFLAGS_CDBLEN_MASK)); + cp->control = cpu_to_le32(control); memcpy(cp->CDB, cdb, cdb_len); memcpy(cp->CISS_LUN, scsi3addr, 8); /* Tag was already set at init time. */ @@ -3306,8 +3454,10 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h, struct scsi_cmnd *cmd = c->scsi_cmd; struct hpsa_scsi_dev_t *dev = cmd->device->hostdata; + c->phys_disk = dev; + return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle, - cmd->cmnd, cmd->cmd_len, dev->scsi3addr); + cmd->cmnd, cmd->cmd_len, dev->scsi3addr, dev); } /* @@ -3321,10 +3471,8 @@ static void set_encrypt_ioaccel2(struct ctlr_info *h, struct raid_map_data *map = &dev->raid_map; u64 first_block; - BUG_ON(!(dev->offload_config && dev->offload_enabled)); - /* Are we doing encryption on this device */ - if (!(map->flags & RAID_MAP_FLAG_ENCRYPT_ON)) + if (!(le16_to_cpu(map->flags) & RAID_MAP_FLAG_ENCRYPT_ON)) return; /* Set the data encryption key index. */ cp->dekindex = map->dekindex; @@ -3340,101 +3488,38 @@ static void set_encrypt_ioaccel2(struct ctlr_info *h, /* Required? 6-byte cdbs eliminated by fixup_ioaccel_cdb */ case WRITE_6: case READ_6: - if (map->volume_blk_size == 512) { - cp->tweak_lower = - (((u32) cmd->cmnd[2]) << 8) | - cmd->cmnd[3]; - cp->tweak_upper = 0; - } else { - first_block = - (((u64) cmd->cmnd[2]) << 8) | - cmd->cmnd[3]; - first_block = (first_block * map->volume_blk_size)/512; - cp->tweak_lower = (u32)first_block; - cp->tweak_upper = (u32)(first_block >> 32); - } + first_block = get_unaligned_be16(&cmd->cmnd[2]); break; case WRITE_10: case READ_10: - if (map->volume_blk_size == 512) { - cp->tweak_lower = - (((u32) cmd->cmnd[2]) << 24) | - (((u32) cmd->cmnd[3]) << 16) | - (((u32) cmd->cmnd[4]) << 8) | - cmd->cmnd[5]; - cp->tweak_upper = 0; - } else { - first_block = - (((u64) cmd->cmnd[2]) << 24) | - (((u64) cmd->cmnd[3]) << 16) | - (((u64) cmd->cmnd[4]) << 8) | - cmd->cmnd[5]; - first_block = (first_block * map->volume_blk_size)/512; - cp->tweak_lower = (u32)first_block; - cp->tweak_upper = (u32)(first_block >> 32); - } - break; /* Required? 12-byte cdbs eliminated by fixup_ioaccel_cdb */ case WRITE_12: case READ_12: - if (map->volume_blk_size == 512) { - cp->tweak_lower = - (((u32) cmd->cmnd[2]) << 24) | - (((u32) cmd->cmnd[3]) << 16) | - (((u32) cmd->cmnd[4]) << 8) | - cmd->cmnd[5]; - cp->tweak_upper = 0; - } else { - first_block = - (((u64) cmd->cmnd[2]) << 24) | - (((u64) cmd->cmnd[3]) << 16) | - (((u64) cmd->cmnd[4]) << 8) | - cmd->cmnd[5]; - first_block = (first_block * map->volume_blk_size)/512; - cp->tweak_lower = (u32)first_block; - cp->tweak_upper = (u32)(first_block >> 32); - } + first_block = get_unaligned_be32(&cmd->cmnd[2]); break; case WRITE_16: case READ_16: - if (map->volume_blk_size == 512) { - cp->tweak_lower = - (((u32) cmd->cmnd[6]) << 24) | - (((u32) cmd->cmnd[7]) << 16) | - (((u32) cmd->cmnd[8]) << 8) | - cmd->cmnd[9]; - cp->tweak_upper = - (((u32) cmd->cmnd[2]) << 24) | - (((u32) cmd->cmnd[3]) << 16) | - (((u32) cmd->cmnd[4]) << 8) | - cmd->cmnd[5]; - } else { - first_block = - (((u64) cmd->cmnd[2]) << 56) | - (((u64) cmd->cmnd[3]) << 48) | - (((u64) cmd->cmnd[4]) << 40) | - (((u64) cmd->cmnd[5]) << 32) | - (((u64) cmd->cmnd[6]) << 24) | - (((u64) cmd->cmnd[7]) << 16) | - (((u64) cmd->cmnd[8]) << 8) | - cmd->cmnd[9]; - first_block = (first_block * map->volume_blk_size)/512; - cp->tweak_lower = (u32)first_block; - cp->tweak_upper = (u32)(first_block >> 32); - } + first_block = get_unaligned_be64(&cmd->cmnd[2]); break; default: dev_err(&h->pdev->dev, - "ERROR: %s: IOACCEL request CDB size not supported for encryption\n", - __func__); + "ERROR: %s: size (0x%x) not supported for encryption\n", + __func__, cmd->cmnd[0]); BUG(); break; } + + if (le32_to_cpu(map->volume_blk_size) != 512) + first_block = first_block * + le32_to_cpu(map->volume_blk_size)/512; + + cp->tweak_lower = cpu_to_le32(first_block); + cp->tweak_upper = cpu_to_le32(first_block >> 32); } static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, - u8 *scsi3addr) + u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk) { struct scsi_cmnd *cmd = c->scsi_cmd; struct io_accel2_cmd *cp = &h->ioaccel2_cmd_pool[c->cmdindex]; @@ -3445,11 +3530,16 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, u32 len; u32 total_len = 0; - if (scsi_sg_count(cmd) > h->ioaccel_maxsg) + if (scsi_sg_count(cmd) > h->ioaccel_maxsg) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; + } - if (fixup_ioaccel_cdb(cdb, &cdb_len)) + if (fixup_ioaccel_cdb(cdb, &cdb_len)) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; + } + c->cmd_type = CMD_IOACCEL2; /* Adjust the DMA address to point to the accelerated command buffer */ c->busaddr = (u32) h->ioaccel2_cmd_pool_dhandle + @@ -3460,8 +3550,10 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, cp->IU_type = IOACCEL2_IU_TYPE; use_sg = scsi_dma_map(cmd); - if (use_sg < 0) + if (use_sg < 0) { + atomic_dec(&phys_disk->ioaccel_cmds_out); return use_sg; + } if (use_sg) { BUG_ON(use_sg > IOACCEL2_MAXSGENTRIES); @@ -3506,9 +3598,8 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, /* Set encryption parameters, if necessary */ set_encrypt_ioaccel2(h, c, cp); - cp->scsi_nexus = ioaccel_handle; - cp->Tag = (c->cmdindex << DIRECT_LOOKUP_SHIFT) | - DIRECT_LOOKUP_BIT; + cp->scsi_nexus = cpu_to_le32(ioaccel_handle); + cp->Tag = cpu_to_le32(c->cmdindex << DIRECT_LOOKUP_SHIFT); memcpy(cp->cdb, cdb, sizeof(cp->cdb)); /* fill in sg elements */ @@ -3528,14 +3619,22 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, */ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len, - u8 *scsi3addr) + u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk) { + /* Try to honor the device's queue depth */ + if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) > + phys_disk->queue_depth) { + atomic_dec(&phys_disk->ioaccel_cmds_out); + return IO_ACCEL_INELIGIBLE; + } if (h->transMethod & CFGTBL_Trans_io_accel1) return hpsa_scsi_ioaccel1_queue_command(h, c, ioaccel_handle, - cdb, cdb_len, scsi3addr); + cdb, cdb_len, scsi3addr, + phys_disk); else return hpsa_scsi_ioaccel2_queue_command(h, c, ioaccel_handle, - cdb, cdb_len, scsi3addr); + cdb, cdb_len, scsi3addr, + phys_disk); } static void raid_map_helper(struct raid_map_data *map, @@ -3543,21 +3642,22 @@ static void raid_map_helper(struct raid_map_data *map, { if (offload_to_mirror == 0) { /* use physical disk in the first mirrored group. */ - *map_index %= map->data_disks_per_row; + *map_index %= le16_to_cpu(map->data_disks_per_row); return; } do { /* determine mirror group that *map_index indicates */ - *current_group = *map_index / map->data_disks_per_row; + *current_group = *map_index / + le16_to_cpu(map->data_disks_per_row); if (offload_to_mirror == *current_group) continue; - if (*current_group < (map->layout_map_count - 1)) { + if (*current_group < le16_to_cpu(map->layout_map_count) - 1) { /* select map index from next group */ - *map_index += map->data_disks_per_row; + *map_index += le16_to_cpu(map->data_disks_per_row); (*current_group)++; } else { /* select map index from first group */ - *map_index %= map->data_disks_per_row; + *map_index %= le16_to_cpu(map->data_disks_per_row); *current_group = 0; } } while (offload_to_mirror != *current_group); @@ -3595,13 +3695,12 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, u32 disk_block_cnt; u8 cdb[16]; u8 cdb_len; + u16 strip_size; #if BITS_PER_LONG == 32 u64 tmpdiv; #endif int offload_to_mirror; - BUG_ON(!(dev->offload_config && dev->offload_enabled)); - /* check for valid opcode, get LBA and block count */ switch (cmd->cmnd[0]) { case WRITE_6: @@ -3668,11 +3767,14 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, return IO_ACCEL_INELIGIBLE; /* check for invalid block or wraparound */ - if (last_block >= map->volume_blk_cnt || last_block < first_block) + if (last_block >= le64_to_cpu(map->volume_blk_cnt) || + last_block < first_block) return IO_ACCEL_INELIGIBLE; /* calculate stripe information for the request */ - blocks_per_row = map->data_disks_per_row * map->strip_size; + blocks_per_row = le16_to_cpu(map->data_disks_per_row) * + le16_to_cpu(map->strip_size); + strip_size = le16_to_cpu(map->strip_size); #if BITS_PER_LONG == 32 tmpdiv = first_block; (void) do_div(tmpdiv, blocks_per_row); @@ -3683,18 +3785,18 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, first_row_offset = (u32) (first_block - (first_row * blocks_per_row)); last_row_offset = (u32) (last_block - (last_row * blocks_per_row)); tmpdiv = first_row_offset; - (void) do_div(tmpdiv, map->strip_size); + (void) do_div(tmpdiv, strip_size); first_column = tmpdiv; tmpdiv = last_row_offset; - (void) do_div(tmpdiv, map->strip_size); + (void) do_div(tmpdiv, strip_size); last_column = tmpdiv; #else first_row = first_block / blocks_per_row; last_row = last_block / blocks_per_row; first_row_offset = (u32) (first_block - (first_row * blocks_per_row)); last_row_offset = (u32) (last_block - (last_row * blocks_per_row)); - first_column = first_row_offset / map->strip_size; - last_column = last_row_offset / map->strip_size; + first_column = first_row_offset / strip_size; + last_column = last_row_offset / strip_size; #endif /* if this isn't a single row/column then give to the controller */ @@ -3702,10 +3804,10 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, return IO_ACCEL_INELIGIBLE; /* proceeding with driver mapping */ - total_disks_per_row = map->data_disks_per_row + - map->metadata_disks_per_row; + total_disks_per_row = le16_to_cpu(map->data_disks_per_row) + + le16_to_cpu(map->metadata_disks_per_row); map_row = ((u32)(first_row >> map->parity_rotation_shift)) % - map->row_cnt; + le16_to_cpu(map->row_cnt); map_index = (map_row * total_disks_per_row) + first_column; switch (dev->raid_level) { @@ -3716,23 +3818,24 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, * (2-drive R1 and R10 with even # of drives.) * Appropriate for SSDs, not optimal for HDDs */ - BUG_ON(map->layout_map_count != 2); + BUG_ON(le16_to_cpu(map->layout_map_count) != 2); if (dev->offload_to_mirror) - map_index += map->data_disks_per_row; + map_index += le16_to_cpu(map->data_disks_per_row); dev->offload_to_mirror = !dev->offload_to_mirror; break; case HPSA_RAID_ADM: /* Handles N-way mirrors (R1-ADM) * and R10 with # of drives divisible by 3.) */ - BUG_ON(map->layout_map_count != 3); + BUG_ON(le16_to_cpu(map->layout_map_count) != 3); offload_to_mirror = dev->offload_to_mirror; raid_map_helper(map, offload_to_mirror, &map_index, ¤t_group); /* set mirror group to use next time */ offload_to_mirror = - (offload_to_mirror >= map->layout_map_count - 1) + (offload_to_mirror >= + le16_to_cpu(map->layout_map_count) - 1) ? 0 : offload_to_mirror + 1; dev->offload_to_mirror = offload_to_mirror; /* Avoid direct use of dev->offload_to_mirror within this @@ -3742,14 +3845,16 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, break; case HPSA_RAID_5: case HPSA_RAID_6: - if (map->layout_map_count <= 1) + if (le16_to_cpu(map->layout_map_count) <= 1) break; /* Verify first and last block are in same RAID group */ r5or6_blocks_per_row = - map->strip_size * map->data_disks_per_row; + le16_to_cpu(map->strip_size) * + le16_to_cpu(map->data_disks_per_row); BUG_ON(r5or6_blocks_per_row == 0); - stripesize = r5or6_blocks_per_row * map->layout_map_count; + stripesize = r5or6_blocks_per_row * + le16_to_cpu(map->layout_map_count); #if BITS_PER_LONG == 32 tmpdiv = first_block; first_group = do_div(tmpdiv, stripesize); @@ -3812,28 +3917,35 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, r5or6_blocks_per_row); first_column = r5or6_first_column = - r5or6_first_row_offset / map->strip_size; + r5or6_first_row_offset / le16_to_cpu(map->strip_size); r5or6_last_column = - r5or6_last_row_offset / map->strip_size; + r5or6_last_row_offset / le16_to_cpu(map->strip_size); #endif if (r5or6_first_column != r5or6_last_column) return IO_ACCEL_INELIGIBLE; /* Request is eligible */ map_row = ((u32)(first_row >> map->parity_rotation_shift)) % - map->row_cnt; + le16_to_cpu(map->row_cnt); map_index = (first_group * - (map->row_cnt * total_disks_per_row)) + + (le16_to_cpu(map->row_cnt) * total_disks_per_row)) + (map_row * total_disks_per_row) + first_column; break; default: return IO_ACCEL_INELIGIBLE; } + if (unlikely(map_index >= RAID_MAP_MAX_ENTRIES)) + return IO_ACCEL_INELIGIBLE; + + c->phys_disk = dev->phys_disk[map_index]; + disk_handle = dd[map_index].ioaccel_handle; - disk_block = map->disk_starting_blk + (first_row * map->strip_size) + - (first_row_offset - (first_column * map->strip_size)); + disk_block = le64_to_cpu(map->disk_starting_blk) + + first_row * le16_to_cpu(map->strip_size) + + (first_row_offset - first_column * + le16_to_cpu(map->strip_size)); disk_block_cnt = block_cnt; /* handle differing logical/physical block sizes */ @@ -3876,78 +3988,21 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, cdb_len = 10; } return hpsa_scsi_ioaccel_queue_command(h, c, disk_handle, cdb, cdb_len, - dev->scsi3addr); + dev->scsi3addr, + dev->phys_disk[map_index]); } -/* - * Running in struct Scsi_Host->host_lock less mode using LLD internal - * struct ctlr_info *h->lock w/ spin_lock_irqsave() protection. - */ -static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +/* Submit commands down the "normal" RAID stack path */ +static int hpsa_ciss_submit(struct ctlr_info *h, + struct CommandList *c, struct scsi_cmnd *cmd, + unsigned char scsi3addr[]) { - struct ctlr_info *h; - struct hpsa_scsi_dev_t *dev; - unsigned char scsi3addr[8]; - struct CommandList *c; - int rc = 0; - - /* Get the ptr to our adapter structure out of cmd->host. */ - h = sdev_to_hba(cmd->device); - dev = cmd->device->hostdata; - if (!dev) { - cmd->result = DID_NO_CONNECT << 16; - cmd->scsi_done(cmd); - return 0; - } - memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); - - if (unlikely(lockup_detected(h))) { - cmd->result = DID_ERROR << 16; - cmd->scsi_done(cmd); - return 0; - } - c = cmd_alloc(h); - if (c == NULL) { /* trouble... */ - dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return SCSI_MLQUEUE_HOST_BUSY; - } - - /* Fill in the command list header */ - /* save c in case we have to abort it */ cmd->host_scribble = (unsigned char *) c; - c->cmd_type = CMD_SCSI; c->scsi_cmd = cmd; - - /* Call alternate submit routine for I/O accelerated commands. - * Retries always go down the normal I/O path. - */ - if (likely(cmd->retries == 0 && - cmd->request->cmd_type == REQ_TYPE_FS && - h->acciopath_status)) { - if (dev->offload_enabled) { - rc = hpsa_scsi_ioaccel_raid_map(h, c); - if (rc == 0) - return 0; /* Sent on ioaccel path */ - if (rc < 0) { /* scsi_dma_map failed. */ - cmd_free(h, c); - return SCSI_MLQUEUE_HOST_BUSY; - } - } else if (dev->ioaccel_handle) { - rc = hpsa_scsi_ioaccel_direct_map(h, c); - if (rc == 0) - return 0; /* Sent on direct map path */ - if (rc < 0) { /* scsi_dma_map failed. */ - cmd_free(h, c); - return SCSI_MLQUEUE_HOST_BUSY; - } - } - } - c->Header.ReplyQueue = 0; /* unused in simple mode */ memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8); - c->Header.tag = cpu_to_le64((c->cmdindex << DIRECT_LOOKUP_SHIFT) | - DIRECT_LOOKUP_BIT); + c->Header.tag = cpu_to_le64((c->cmdindex << DIRECT_LOOKUP_SHIFT)); /* Fill in the request block... */ @@ -4003,25 +4058,108 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return 0; } -static int do_not_scan_if_controller_locked_up(struct ctlr_info *h) +static void hpsa_command_resubmit_worker(struct work_struct *work) +{ + struct scsi_cmnd *cmd; + struct hpsa_scsi_dev_t *dev; + struct CommandList *c = + container_of(work, struct CommandList, work); + + cmd = c->scsi_cmd; + dev = cmd->device->hostdata; + if (!dev) { + cmd->result = DID_NO_CONNECT << 16; + cmd->scsi_done(cmd); + return; + } + if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) { + /* + * If we get here, it means dma mapping failed. Try + * again via scsi mid layer, which will then get + * SCSI_MLQUEUE_HOST_BUSY. + */ + cmd->result = DID_IMM_RETRY << 16; + cmd->scsi_done(cmd); + } +} + +/* Running in struct Scsi_Host->host_lock less mode */ +static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +{ + struct ctlr_info *h; + struct hpsa_scsi_dev_t *dev; + unsigned char scsi3addr[8]; + struct CommandList *c; + int rc = 0; + + /* Get the ptr to our adapter structure out of cmd->host. */ + h = sdev_to_hba(cmd->device); + dev = cmd->device->hostdata; + if (!dev) { + cmd->result = DID_NO_CONNECT << 16; + cmd->scsi_done(cmd); + return 0; + } + memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); + + if (unlikely(lockup_detected(h))) { + cmd->result = DID_ERROR << 16; + cmd->scsi_done(cmd); + return 0; + } + c = cmd_alloc(h); + if (c == NULL) { /* trouble... */ + dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); + return SCSI_MLQUEUE_HOST_BUSY; + } + if (unlikely(lockup_detected(h))) { + cmd->result = DID_ERROR << 16; + cmd_free(h, c); + cmd->scsi_done(cmd); + return 0; + } + + /* + * Call alternate submit routine for I/O accelerated commands. + * Retries always go down the normal I/O path. + */ + if (likely(cmd->retries == 0 && + cmd->request->cmd_type == REQ_TYPE_FS && + h->acciopath_status)) { + + cmd->host_scribble = (unsigned char *) c; + c->cmd_type = CMD_SCSI; + c->scsi_cmd = cmd; + + if (dev->offload_enabled) { + rc = hpsa_scsi_ioaccel_raid_map(h, c); + if (rc == 0) + return 0; /* Sent on ioaccel path */ + if (rc < 0) { /* scsi_dma_map failed. */ + cmd_free(h, c); + return SCSI_MLQUEUE_HOST_BUSY; + } + } else if (dev->ioaccel_handle) { + rc = hpsa_scsi_ioaccel_direct_map(h, c); + if (rc == 0) + return 0; /* Sent on direct map path */ + if (rc < 0) { /* scsi_dma_map failed. */ + cmd_free(h, c); + return SCSI_MLQUEUE_HOST_BUSY; + } + } + } + return hpsa_ciss_submit(h, c, cmd, scsi3addr); +} + +static void hpsa_scan_complete(struct ctlr_info *h) { unsigned long flags; - /* - * Don't let rescans be initiated on a controller known - * to be locked up. If the controller locks up *during* - * a rescan, that thread is probably hosed, but at least - * we can prevent new rescan threads from piling up on a - * locked up controller. - */ - if (unlikely(lockup_detected(h))) { - spin_lock_irqsave(&h->scan_lock, flags); - h->scan_finished = 1; - wake_up_all(&h->scan_wait_queue); - spin_unlock_irqrestore(&h->scan_lock, flags); - return 1; - } - return 0; + spin_lock_irqsave(&h->scan_lock, flags); + h->scan_finished = 1; + wake_up_all(&h->scan_wait_queue); + spin_unlock_irqrestore(&h->scan_lock, flags); } static void hpsa_scan_start(struct Scsi_Host *sh) @@ -4029,8 +4167,14 @@ static void hpsa_scan_start(struct Scsi_Host *sh) struct ctlr_info *h = shost_to_hba(sh); unsigned long flags; - if (do_not_scan_if_controller_locked_up(h)) - return; + /* + * Don't let rescans be initiated on a controller known to be locked + * up. If the controller locks up *during* a rescan, that thread is + * probably hosed, but at least we can prevent new rescan threads from + * piling up on a locked up controller. + */ + if (unlikely(lockup_detected(h))) + return hpsa_scan_complete(h); /* wait until any scan already in progress is finished. */ while (1) { @@ -4048,15 +4192,27 @@ static void hpsa_scan_start(struct Scsi_Host *sh) h->scan_finished = 0; /* mark scan as in progress */ spin_unlock_irqrestore(&h->scan_lock, flags); - if (do_not_scan_if_controller_locked_up(h)) - return; + if (unlikely(lockup_detected(h))) + return hpsa_scan_complete(h); hpsa_update_scsi_devices(h, h->scsi_host->host_no); - spin_lock_irqsave(&h->scan_lock, flags); - h->scan_finished = 1; /* mark scan as finished. */ - wake_up_all(&h->scan_wait_queue); - spin_unlock_irqrestore(&h->scan_lock, flags); + hpsa_scan_complete(h); +} + +static int hpsa_change_queue_depth(struct scsi_device *sdev, int qdepth) +{ + struct hpsa_scsi_dev_t *logical_drive = sdev->hostdata; + + if (!logical_drive) + return -ENODEV; + + if (qdepth < 1) + qdepth = 1; + else if (qdepth > logical_drive->queue_depth) + qdepth = logical_drive->queue_depth; + + return scsi_change_queue_depth(sdev, qdepth); } static int hpsa_scan_finished(struct Scsi_Host *sh, @@ -4096,11 +4252,11 @@ static int hpsa_register_scsi(struct ctlr_info *h) sh->max_cmd_len = MAX_COMMAND_SIZE; sh->max_lun = HPSA_MAX_LUN; sh->max_id = HPSA_MAX_LUN; - sh->can_queue = h->nr_cmds; - if (h->hba_mode_enabled) - sh->cmd_per_lun = 7; - else - sh->cmd_per_lun = h->nr_cmds; + sh->can_queue = h->nr_cmds - + HPSA_CMDS_RESERVED_FOR_ABORTS - + HPSA_CMDS_RESERVED_FOR_DRIVER - + HPSA_MAX_CONCURRENT_PASSTHRUS; + sh->cmd_per_lun = sh->can_queue; sh->sg_tablesize = h->maxsgentries; h->scsi_host = sh; sh->hostdata[0] = (unsigned long) h; @@ -4131,7 +4287,7 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, int waittime = 1; /* seconds */ struct CommandList *c; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (!c) { dev_warn(&h->pdev->dev, "out of memory in " "wait_for_device_to_become_ready.\n"); @@ -4177,7 +4333,7 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, else dev_warn(&h->pdev->dev, "device is ready.\n"); - cmd_special_free(h, c); + cmd_free(h, c); return rc; } @@ -4194,6 +4350,10 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) h = sdev_to_hba(scsicmd->device); if (h == NULL) /* paranoia */ return FAILED; + + if (lockup_detected(h)) + return FAILED; + dev = scsicmd->device->hostdata; if (!dev) { dev_err(&h->pdev->dev, "hpsa_eh_device_reset_handler: " @@ -4227,13 +4387,15 @@ static void swizzle_abort_tag(u8 *tag) } static void hpsa_get_tag(struct ctlr_info *h, - struct CommandList *c, u32 *taglower, u32 *tagupper) + struct CommandList *c, __le32 *taglower, __le32 *tagupper) { + u64 tag; if (c->cmd_type == CMD_IOACCEL1) { struct io_accel1_cmd *cm1 = (struct io_accel1_cmd *) &h->ioaccel_cmd_pool[c->cmdindex]; - *tagupper = (u32) (cm1->tag >> 32); - *taglower = (u32) (cm1->tag & 0x0ffffffffULL); + tag = le64_to_cpu(cm1->tag); + *tagupper = cpu_to_le32(tag >> 32); + *taglower = cpu_to_le32(tag); return; } if (c->cmd_type == CMD_IOACCEL2) { @@ -4244,8 +4406,9 @@ static void hpsa_get_tag(struct ctlr_info *h, *taglower = cm2->Tag; return; } - *tagupper = (u32) (c->Header.tag >> 32); - *taglower = (u32) (c->Header.tag & 0x0ffffffffULL); + tag = le64_to_cpu(c->Header.tag); + *tagupper = cpu_to_le32(tag >> 32); + *taglower = cpu_to_le32(tag); } static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, @@ -4254,11 +4417,11 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, int rc = IO_OK; struct CommandList *c; struct ErrorInfo *ei; - u32 tagupper, taglower; + __le32 tagupper, taglower; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return -ENOMEM; } @@ -4287,62 +4450,12 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, rc = -1; break; } - cmd_special_free(h, c); + cmd_free(h, c); dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n", __func__, tagupper, taglower); return rc; } -/* - * hpsa_find_cmd_in_queue - * - * Used to determine whether a command (find) is still present - * in queue_head. Optionally excludes the last element of queue_head. - * - * This is used to avoid unnecessary aborts. Commands in h->reqQ have - * not yet been submitted, and so can be aborted by the driver without - * sending an abort to the hardware. - * - * Returns pointer to command if found in queue, NULL otherwise. - */ -static struct CommandList *hpsa_find_cmd_in_queue(struct ctlr_info *h, - struct scsi_cmnd *find, struct list_head *queue_head) -{ - unsigned long flags; - struct CommandList *c = NULL; /* ptr into cmpQ */ - - if (!find) - return NULL; - spin_lock_irqsave(&h->lock, flags); - list_for_each_entry(c, queue_head, list) { - if (c->scsi_cmd == NULL) /* e.g.: passthru ioctl */ - continue; - if (c->scsi_cmd == find) { - spin_unlock_irqrestore(&h->lock, flags); - return c; - } - } - spin_unlock_irqrestore(&h->lock, flags); - return NULL; -} - -static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h, - u8 *tag, struct list_head *queue_head) -{ - unsigned long flags; - struct CommandList *c; - - spin_lock_irqsave(&h->lock, flags); - list_for_each_entry(c, queue_head, list) { - if (memcmp(&c->Header.tag, tag, 8) != 0) - continue; - spin_unlock_irqrestore(&h->lock, flags); - return c; - } - spin_unlock_irqrestore(&h->lock, flags); - return NULL; -} - /* ioaccel2 path firmware cannot handle abort task requests. * Change abort requests to physical target reset, and send to the * address of the physical disk used for the ioaccel 2 command. @@ -4360,7 +4473,7 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, unsigned char *psa = &phys_scsi3addr[0]; /* Get a pointer to the hpsa logical device. */ - scmd = (struct scsi_cmnd *) abort->scsi_cmd; + scmd = abort->scsi_cmd; dev = (struct hpsa_scsi_dev_t *)(scmd->device->hostdata); if (dev == NULL) { dev_warn(&h->pdev->dev, @@ -4429,10 +4542,6 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h, static int hpsa_send_abort_both_ways(struct ctlr_info *h, unsigned char *scsi3addr, struct CommandList *abort) { - u8 swizzled_tag[8]; - struct CommandList *c; - int rc = 0, rc2 = 0; - /* ioccelerator mode 2 commands should be aborted via the * accelerated path, since RAID path is unaware of these commands, * but underlying firmware can't handle abort TMF. @@ -4441,27 +4550,8 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h, if (abort->cmd_type == CMD_IOACCEL2) return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort); - /* we do not expect to find the swizzled tag in our queue, but - * check anyway just to be sure the assumptions which make this - * the case haven't become wrong. - */ - memcpy(swizzled_tag, &abort->Request.CDB[4], 8); - swizzle_abort_tag(swizzled_tag); - c = hpsa_find_cmd_in_queue_by_tag(h, swizzled_tag, &h->cmpQ); - if (c != NULL) { - dev_warn(&h->pdev->dev, "Unexpectedly found byte-swapped tag in completion queue.\n"); - return hpsa_send_abort(h, scsi3addr, abort, 0); - } - rc = hpsa_send_abort(h, scsi3addr, abort, 0); - - /* if the command is still in our queue, we can't conclude that it was - * aborted (it might have just completed normally) but in any case - * we don't need to try to abort it another way. - */ - c = hpsa_find_cmd_in_queue(h, abort->scsi_cmd, &h->cmpQ); - if (c) - rc2 = hpsa_send_abort(h, scsi3addr, abort, 1); - return rc && rc2; + return hpsa_send_abort(h, scsi3addr, abort, 0) && + hpsa_send_abort(h, scsi3addr, abort, 1); } /* Send an abort for the specified command. @@ -4475,11 +4565,11 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; struct CommandList *abort; /* pointer to command to be aborted */ - struct CommandList *found; struct scsi_cmnd *as; /* ptr to scsi cmd inside aborted command. */ char msg[256]; /* For debug messaging. */ int ml = 0; - u32 tagupper, taglower; + __le32 tagupper, taglower; + int refcount; /* Find the controller of the command to be aborted */ h = sdev_to_hba(sc->device); @@ -4487,6 +4577,9 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) "ABORT REQUEST FAILED, Controller lookup failed.\n")) return FAILED; + if (lockup_detected(h)) + return FAILED; + /* Check that controller supports some kind of task abort */ if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags) && !(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags)) @@ -4508,41 +4601,23 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) /* Get SCSI command to be aborted */ abort = (struct CommandList *) sc->host_scribble; if (abort == NULL) { - dev_err(&h->pdev->dev, "%s FAILED, Command to abort is NULL.\n", - msg); - return FAILED; + /* This can happen if the command already completed. */ + return SUCCESS; + } + refcount = atomic_inc_return(&abort->refcount); + if (refcount == 1) { /* Command is done already. */ + cmd_free(h, abort); + return SUCCESS; } hpsa_get_tag(h, abort, &taglower, &tagupper); ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower); - as = (struct scsi_cmnd *) abort->scsi_cmd; + as = abort->scsi_cmd; if (as != NULL) ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ", as->cmnd[0], as->serial_number); dev_dbg(&h->pdev->dev, "%s\n", msg); dev_warn(&h->pdev->dev, "Abort request on C%d:B%d:T%d:L%d\n", h->scsi_host->host_no, dev->bus, dev->target, dev->lun); - - /* Search reqQ to See if command is queued but not submitted, - * if so, complete the command with aborted status and remove - * it from the reqQ. - */ - found = hpsa_find_cmd_in_queue(h, sc, &h->reqQ); - if (found) { - found->err_info->CommandStatus = CMD_ABORTED; - finish_cmd(found); - dev_info(&h->pdev->dev, "%s Request SUCCEEDED (driver queue).\n", - msg); - return SUCCESS; - } - - /* not in reqQ, if also not in cmpQ, must have already completed */ - found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ); - if (!found) { - dev_dbg(&h->pdev->dev, "%s Request SUCCEEDED (not known to driver).\n", - msg); - return SUCCESS; - } - /* * Command is in flight, or possibly already completed * by the firmware (but not to the scsi mid layer) but we can't @@ -4554,6 +4629,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) dev_warn(&h->pdev->dev, "FAILED abort on device C%d:B%d:T%d:L%d\n", h->scsi_host->host_no, dev->bus, dev->target, dev->lun); + cmd_free(h, abort); return FAILED; } dev_info(&h->pdev->dev, "%s REQUEST SUCCEEDED.\n", msg); @@ -4565,32 +4641,38 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) */ #define ABORT_COMPLETE_WAIT_SECS 30 for (i = 0; i < ABORT_COMPLETE_WAIT_SECS * 10; i++) { - found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ); - if (!found) + refcount = atomic_read(&abort->refcount); + if (refcount < 2) { + cmd_free(h, abort); return SUCCESS; - msleep(100); + } else { + msleep(100); + } } dev_warn(&h->pdev->dev, "%s FAILED. Aborted command has not completed after %d seconds.\n", msg, ABORT_COMPLETE_WAIT_SECS); + cmd_free(h, abort); return FAILED; } - /* * For operations that cannot sleep, a command block is allocated at init, * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track * which ones are free or in use. Lock must be held when calling this. * cmd_free() is the complement. */ + static struct CommandList *cmd_alloc(struct ctlr_info *h) { struct CommandList *c; int i; union u64bit temp64; dma_addr_t cmd_dma_handle, err_dma_handle; - int loopcount; + int refcount; + unsigned long offset; - /* There is some *extremely* small but non-zero chance that that + /* + * There is some *extremely* small but non-zero chance that that * multiple threads could get in here, and one thread could * be scanning through the list of bits looking for a free * one, but the free ones are always behind him, and other @@ -4601,24 +4683,30 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) * infrequently as to be indistinguishable from never. */ - loopcount = 0; - do { - i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds); - if (i == h->nr_cmds) - i = 0; - loopcount++; - } while (test_and_set_bit(i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0 && - loopcount < 10); + offset = h->last_allocation; /* benignly racy */ + for (;;) { + i = find_next_zero_bit(h->cmd_pool_bits, h->nr_cmds, offset); + if (unlikely(i == h->nr_cmds)) { + offset = 0; + continue; + } + c = h->cmd_pool + i; + refcount = atomic_inc_return(&c->refcount); + if (unlikely(refcount > 1)) { + cmd_free(h, c); /* already in use */ + offset = (i + 1) % h->nr_cmds; + continue; + } + set_bit(i & (BITS_PER_LONG - 1), + h->cmd_pool_bits + (i / BITS_PER_LONG)); + break; /* it's ours now. */ + } + h->last_allocation = i; /* benignly racy */ - /* Thread got starved? We do not expect this to ever happen. */ - if (loopcount >= 10) - return NULL; - - c = h->cmd_pool + i; - memset(c, 0, sizeof(*c)); - cmd_dma_handle = h->cmd_pool_dhandle - + i * sizeof(*c); + /* Zero out all of commandlist except the last field, refcount */ + memset(c, 0, offsetof(struct CommandList, refcount)); + c->Header.tag = cpu_to_le64((u64) (i << DIRECT_LOOKUP_SHIFT)); + cmd_dma_handle = h->cmd_pool_dhandle + i * sizeof(*c); c->err_info = h->errinfo_pool + i; memset(c->err_info, 0, sizeof(*c->err_info)); err_dma_handle = h->errinfo_pool_dhandle @@ -4626,45 +4714,10 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) c->cmdindex = i; - INIT_LIST_HEAD(&c->list); c->busaddr = (u32) cmd_dma_handle; temp64.val = (u64) err_dma_handle; - c->ErrDesc.Addr = cpu_to_le64(err_dma_handle); - c->ErrDesc.Len = cpu_to_le32(sizeof(*c->err_info)); - - c->h = h; - return c; -} - -/* For operations that can wait for kmalloc to possibly sleep, - * this routine can be called. Lock need not be held to call - * cmd_special_alloc. cmd_special_free() is the complement. - */ -static struct CommandList *cmd_special_alloc(struct ctlr_info *h) -{ - struct CommandList *c; - dma_addr_t cmd_dma_handle, err_dma_handle; - - c = pci_zalloc_consistent(h->pdev, sizeof(*c), &cmd_dma_handle); - if (c == NULL) - return NULL; - - c->cmd_type = CMD_SCSI; - c->cmdindex = -1; - - c->err_info = pci_zalloc_consistent(h->pdev, sizeof(*c->err_info), - &err_dma_handle); - - if (c->err_info == NULL) { - pci_free_consistent(h->pdev, - sizeof(*c), c, cmd_dma_handle); - return NULL; - } - - INIT_LIST_HEAD(&c->list); - c->busaddr = (u32) cmd_dma_handle; - c->ErrDesc.Addr = cpu_to_le64(err_dma_handle); - c->ErrDesc.Len = cpu_to_le32(sizeof(*c->err_info)); + c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle); + c->ErrDesc.Len = cpu_to_le32((u32) sizeof(*c->err_info)); c->h = h; return c; @@ -4672,20 +4725,13 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h) static void cmd_free(struct ctlr_info *h, struct CommandList *c) { - int i; + if (atomic_dec_and_test(&c->refcount)) { + int i; - i = c - h->cmd_pool; - clear_bit(i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG)); -} - -static void cmd_special_free(struct ctlr_info *h, struct CommandList *c) -{ - pci_free_consistent(h->pdev, sizeof(*c->err_info), - c->err_info, - (dma_addr_t) le64_to_cpu(c->ErrDesc.Addr)); - pci_free_consistent(h->pdev, sizeof(*c), - c, (dma_addr_t) (c->busaddr & DIRECT_LOOKUP_MASK)); + i = c - h->cmd_pool; + clear_bit(i & (BITS_PER_LONG - 1), + h->cmd_pool_bits + (i / BITS_PER_LONG)); + } } #ifdef CONFIG_COMPAT @@ -4866,7 +4912,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) memset(buff, 0, iocommand.buf_size); } } - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { rc = -ENOMEM; goto out_kfree; @@ -4883,8 +4929,6 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->Header.SGTotal = cpu_to_le16(0); } memcpy(&c->Header.LUN, &iocommand.LUN_info, sizeof(c->Header.LUN)); - /* use the kernel address the cmd block for tag */ - c->Header.tag = c->busaddr; /* Fill in Request block */ memcpy(&c->Request, &iocommand.Request, @@ -4925,7 +4969,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) } } out: - cmd_special_free(h, c); + cmd_free(h, c); out_kfree: kfree(buff); return rc; @@ -4940,7 +4984,6 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) u64 temp64; BYTE sg_used = 0; int status = 0; - int i; u32 left; u32 sz; BYTE __user *data_ptr; @@ -5004,7 +5047,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) data_ptr += sz; sg_used++; } - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (c == NULL) { status = -ENOMEM; goto cleanup1; @@ -5014,7 +5057,6 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) c->Header.SGList = (u8) sg_used; c->Header.SGTotal = cpu_to_le16(sg_used); memcpy(&c->Header.LUN, &ioc->LUN_info, sizeof(c->Header.LUN)); - c->Header.tag = c->busaddr; memcpy(&c->Request, &ioc->Request, sizeof(c->Request)); if (ioc->buf_size > 0) { int i; @@ -5047,6 +5089,8 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) goto cleanup0; } if ((ioc->Request.Type.Direction & XFER_READ) && ioc->buf_size > 0) { + int i; + /* Copy the data out of the buffer we created */ BYTE __user *ptr = ioc->buf; for (i = 0; i < sg_used; i++) { @@ -5059,9 +5103,11 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) } status = 0; cleanup0: - cmd_special_free(h, c); + cmd_free(h, c); cleanup1: if (buff) { + int i; + for (i = 0; i < sg_used; i++) kfree(buff[i]); kfree(buff); @@ -5079,35 +5125,6 @@ static void check_ioctl_unit_attention(struct ctlr_info *h, (void) check_for_unit_attention(h, c); } -static int increment_passthru_count(struct ctlr_info *h) -{ - unsigned long flags; - - spin_lock_irqsave(&h->passthru_count_lock, flags); - if (h->passthru_count >= HPSA_MAX_CONCURRENT_PASSTHRUS) { - spin_unlock_irqrestore(&h->passthru_count_lock, flags); - return -1; - } - h->passthru_count++; - spin_unlock_irqrestore(&h->passthru_count_lock, flags); - return 0; -} - -static void decrement_passthru_count(struct ctlr_info *h) -{ - unsigned long flags; - - spin_lock_irqsave(&h->passthru_count_lock, flags); - if (h->passthru_count <= 0) { - spin_unlock_irqrestore(&h->passthru_count_lock, flags); - /* not expecting to get here. */ - dev_warn(&h->pdev->dev, "Bug detected, passthru_count seems to be incorrect.\n"); - return; - } - h->passthru_count--; - spin_unlock_irqrestore(&h->passthru_count_lock, flags); -} - /* * ioctl */ @@ -5130,16 +5147,16 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void __user *arg) case CCISS_GETDRIVVER: return hpsa_getdrivver_ioctl(h, argp); case CCISS_PASSTHRU: - if (increment_passthru_count(h)) + if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0) return -EAGAIN; rc = hpsa_passthru_ioctl(h, argp); - decrement_passthru_count(h); + atomic_inc(&h->passthru_cmds_avail); return rc; case CCISS_BIG_PASSTHRU: - if (increment_passthru_count(h)) + if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0) return -EAGAIN; rc = hpsa_big_passthru_ioctl(h, argp); - decrement_passthru_count(h); + atomic_inc(&h->passthru_cmds_avail); return rc; default: return -ENOTTY; @@ -5173,7 +5190,6 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, { int pci_dir = XFER_NONE; struct CommandList *a; /* for commands to be aborted */ - u32 tupper, tlower; c->cmd_type = CMD_IOCTL_PEND; c->Header.ReplyQueue = 0; @@ -5184,7 +5200,6 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Header.SGList = 0; c->Header.SGTotal = cpu_to_le16(0); } - c->Header.tag = c->busaddr; memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8); if (cmd_type == TYPE_CMD) { @@ -5256,6 +5271,16 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[7] = (size >> 16) & 0xFF; c->Request.CDB[8] = (size >> 8) & 0xFF; break; + case BMIC_IDENTIFY_PHYSICAL_DEVICE: + c->Request.CDBLen = 10; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); + c->Request.Timeout = 0; + c->Request.CDB[0] = BMIC_READ; + c->Request.CDB[6] = BMIC_IDENTIFY_PHYSICAL_DEVICE; + c->Request.CDB[7] = (size >> 16) & 0xFF; + c->Request.CDB[8] = (size >> 8) & 0XFF; + break; default: dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd); BUG(); @@ -5281,10 +5306,9 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, break; case HPSA_ABORT_MSG: a = buff; /* point to command to be aborted */ - dev_dbg(&h->pdev->dev, "Abort Tag:0x%016llx using request Tag:0x%016llx", + dev_dbg(&h->pdev->dev, + "Abort Tag:0x%016llx request Tag:0x%016llx", a->Header.tag, c->Header.tag); - tlower = (u32) (a->Header.tag >> 32); - tupper = (u32) (a->Header.tag & 0x0ffffffffULL); c->Request.CDBLen = 16; c->Request.type_attr_dir = TYPE_ATTR_DIR(cmd_type, @@ -5295,14 +5319,8 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[2] = 0x00; /* reserved */ c->Request.CDB[3] = 0x00; /* reserved */ /* Tag to abort goes in CDB[4]-CDB[11] */ - c->Request.CDB[4] = tlower & 0xFF; - c->Request.CDB[5] = (tlower >> 8) & 0xFF; - c->Request.CDB[6] = (tlower >> 16) & 0xFF; - c->Request.CDB[7] = (tlower >> 24) & 0xFF; - c->Request.CDB[8] = tupper & 0xFF; - c->Request.CDB[9] = (tupper >> 8) & 0xFF; - c->Request.CDB[10] = (tupper >> 16) & 0xFF; - c->Request.CDB[11] = (tupper >> 24) & 0xFF; + memcpy(&c->Request.CDB[4], &a->Header.tag, + sizeof(a->Header.tag)); c->Request.CDB[12] = 0x00; /* reserved */ c->Request.CDB[13] = 0x00; /* reserved */ c->Request.CDB[14] = 0x00; /* reserved */ @@ -5349,47 +5367,6 @@ static void __iomem *remap_pci_mem(ulong base, ulong size) return page_remapped ? (page_remapped + page_offs) : NULL; } -/* Takes cmds off the submission queue and sends them to the hardware, - * then puts them on the queue of cmds waiting for completion. - * Assumes h->lock is held - */ -static void start_io(struct ctlr_info *h, unsigned long *flags) -{ - struct CommandList *c; - - while (!list_empty(&h->reqQ)) { - c = list_entry(h->reqQ.next, struct CommandList, list); - /* can't do anything if fifo is full */ - if ((h->access.fifo_full(h))) { - h->fifo_recently_full = 1; - dev_warn(&h->pdev->dev, "fifo full\n"); - break; - } - h->fifo_recently_full = 0; - - /* Get the first entry from the Request Q */ - removeQ(c); - h->Qdepth--; - - /* Put job onto the completed Q */ - addQ(&h->cmpQ, c); - atomic_inc(&h->commands_outstanding); - spin_unlock_irqrestore(&h->lock, *flags); - /* Tell the controller execute command */ - h->access.submit_command(h, c); - spin_lock_irqsave(&h->lock, *flags); - } -} - -static void lock_and_start_io(struct ctlr_info *h) -{ - unsigned long flags; - - spin_lock_irqsave(&h->lock, flags); - start_io(h, &flags); - spin_unlock_irqrestore(&h->lock, flags); -} - static inline unsigned long get_next_completion(struct ctlr_info *h, u8 q) { return h->access.command_completed(h, q); @@ -5418,53 +5395,12 @@ static inline int bad_tag(struct ctlr_info *h, u32 tag_index, static inline void finish_cmd(struct CommandList *c) { - unsigned long flags; - int io_may_be_stalled = 0; - struct ctlr_info *h = c->h; - int count; - - spin_lock_irqsave(&h->lock, flags); - removeQ(c); - - /* - * Check for possibly stalled i/o. - * - * If a fifo_full condition is encountered, requests will back up - * in h->reqQ. This queue is only emptied out by start_io which is - * only called when a new i/o request comes in. If no i/o's are - * forthcoming, the i/o's in h->reqQ can get stuck. So we call - * start_io from here if we detect such a danger. - * - * Normally, we shouldn't hit this case, but pounding on the - * CCISS_PASSTHRU ioctl can provoke it. Only call start_io if - * commands_outstanding is low. We want to avoid calling - * start_io from in here as much as possible, and esp. don't - * want to get in a cycle where we call start_io every time - * through here. - */ - count = atomic_read(&h->commands_outstanding); - spin_unlock_irqrestore(&h->lock, flags); - if (unlikely(h->fifo_recently_full) && count < 5) - io_may_be_stalled = 1; - dial_up_lockup_detection_on_fw_flash_complete(c->h, c); if (likely(c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_SCSI || c->cmd_type == CMD_IOACCEL2)) complete_scsi_command(c); else if (c->cmd_type == CMD_IOCTL_PEND) complete(c->waiting); - if (unlikely(io_may_be_stalled)) - lock_and_start_io(h); -} - -static inline u32 hpsa_tag_contains_index(u32 tag) -{ - return tag & DIRECT_LOOKUP_BIT; -} - -static inline u32 hpsa_tag_to_index(u32 tag) -{ - return tag >> DIRECT_LOOKUP_SHIFT; } @@ -5484,34 +5420,13 @@ static inline void process_indexed_cmd(struct ctlr_info *h, u32 tag_index; struct CommandList *c; - tag_index = hpsa_tag_to_index(raw_tag); + tag_index = raw_tag >> DIRECT_LOOKUP_SHIFT; if (!bad_tag(h, tag_index, raw_tag)) { c = h->cmd_pool + tag_index; finish_cmd(c); } } -/* process completion of a non-indexed command */ -static inline void process_nonindexed_cmd(struct ctlr_info *h, - u32 raw_tag) -{ - u32 tag; - struct CommandList *c = NULL; - unsigned long flags; - - tag = hpsa_tag_discard_error_bits(h, raw_tag); - spin_lock_irqsave(&h->lock, flags); - list_for_each_entry(c, &h->cmpQ, list) { - if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) { - spin_unlock_irqrestore(&h->lock, flags); - finish_cmd(c); - return; - } - } - spin_unlock_irqrestore(&h->lock, flags); - bad_tag(h, h->nr_cmds + 1, raw_tag); -} - /* 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 @@ -5589,10 +5504,7 @@ static irqreturn_t do_hpsa_intr_intx(int irq, void *queue) while (interrupt_pending(h)) { raw_tag = get_next_completion(h, q); while (raw_tag != FIFO_EMPTY) { - if (likely(hpsa_tag_contains_index(raw_tag))) - process_indexed_cmd(h, raw_tag); - else - process_nonindexed_cmd(h, raw_tag); + process_indexed_cmd(h, raw_tag); raw_tag = next_command(h, q); } } @@ -5608,10 +5520,7 @@ static irqreturn_t do_hpsa_intr_msi(int irq, void *queue) h->last_intr_timestamp = get_jiffies_64(); raw_tag = get_next_completion(h, q); while (raw_tag != FIFO_EMPTY) { - if (likely(hpsa_tag_contains_index(raw_tag))) - process_indexed_cmd(h, raw_tag); - else - process_nonindexed_cmd(h, raw_tag); + process_indexed_cmd(h, raw_tag); raw_tag = next_command(h, q); } return IRQ_HANDLED; @@ -5633,7 +5542,8 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, static const size_t cmd_sz = sizeof(*cmd) + sizeof(cmd->ErrorDescriptor); dma_addr_t paddr64; - uint32_t paddr32, tag; + __le32 paddr32; + u32 tag; void __iomem *vaddr; int i, err; @@ -5648,7 +5558,7 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { iounmap(vaddr); - return -ENOMEM; + return err; } cmd = pci_alloc_consistent(pdev, cmd_sz, &paddr64); @@ -5661,12 +5571,12 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, * although there's no guarantee, we assume that the address is at * least 4-byte aligned (most likely, it's page-aligned). */ - paddr32 = paddr64; + paddr32 = cpu_to_le32(paddr64); cmd->CommandHeader.ReplyQueue = 0; cmd->CommandHeader.SGList = 0; cmd->CommandHeader.SGTotal = cpu_to_le16(0); - cmd->CommandHeader.tag = paddr32; + cmd->CommandHeader.tag = cpu_to_le64(paddr64); memset(&cmd->CommandHeader.LUN.LunAddrBytes, 0, 8); cmd->Request.CDBLen = 16; @@ -5677,14 +5587,14 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, cmd->Request.CDB[1] = type; memset(&cmd->Request.CDB[2], 0, 14); /* rest of the CDB is reserved */ cmd->ErrorDescriptor.Addr = - cpu_to_le64((paddr32 + sizeof(*cmd))); + cpu_to_le64((le32_to_cpu(paddr32) + sizeof(*cmd))); cmd->ErrorDescriptor.Len = cpu_to_le32(sizeof(struct ErrorInfo)); - writel(paddr32, vaddr + SA5_REQUEST_PORT_OFFSET); + writel(le32_to_cpu(paddr32), vaddr + SA5_REQUEST_PORT_OFFSET); for (i = 0; i < HPSA_MSG_SEND_RETRY_LIMIT; i++) { tag = readl(vaddr + SA5_REPLY_PORT_OFFSET); - if ((tag & ~HPSA_SIMPLE_ERROR_BITS) == paddr32) + if ((tag & ~HPSA_SIMPLE_ERROR_BITS) == paddr64) break; msleep(HPSA_MSG_SEND_RETRY_INTERVAL_MSECS); } @@ -5718,8 +5628,6 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode, static int hpsa_controller_hard_reset(struct pci_dev *pdev, void __iomem *vaddr, u32 use_doorbell) { - u16 pmcsr; - int pos; if (use_doorbell) { /* For everything after the P600, the PCI power state method @@ -5745,26 +5653,21 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev, * this causes a secondary PCI reset which will reset the * controller." */ - pos = pci_find_capability(pdev, PCI_CAP_ID_PM); - if (pos == 0) { - dev_err(&pdev->dev, - "hpsa_reset_controller: " - "PCI PM not supported\n"); - return -ENODEV; - } + int rc = 0; + dev_info(&pdev->dev, "using PCI PM to reset controller\n"); + /* enter the D3hot power management state */ - pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr); - pmcsr &= ~PCI_PM_CTRL_STATE_MASK; - pmcsr |= PCI_D3hot; - pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr); + rc = pci_set_power_state(pdev, PCI_D3hot); + if (rc) + return rc; msleep(500); /* enter the D0 power management state */ - pmcsr &= ~PCI_PM_CTRL_STATE_MASK; - pmcsr |= PCI_D0; - pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr); + rc = pci_set_power_state(pdev, PCI_D0); + if (rc) + return rc; /* * The P600 requires a small delay when changing states. @@ -5858,8 +5761,12 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) */ rc = hpsa_lookup_board_id(pdev, &board_id); - if (rc < 0 || !ctlr_is_resettable(board_id)) { - dev_warn(&pdev->dev, "Not resetting device.\n"); + if (rc < 0) { + dev_warn(&pdev->dev, "Board ID not found\n"); + return rc; + } + if (!ctlr_is_resettable(board_id)) { + dev_warn(&pdev->dev, "Controller not resettable\n"); return -ENODEV; } @@ -5892,7 +5799,7 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) } rc = write_driver_ver_to_cfgtable(cfgtable); if (rc) - goto unmap_vaddr; + goto unmap_cfgtable; /* If reset via doorbell register is supported, use that. * There are two such methods. Favor the newest method. @@ -5904,8 +5811,8 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) } else { use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET; if (use_doorbell) { - dev_warn(&pdev->dev, "Soft reset not supported. " - "Firmware update is required.\n"); + dev_warn(&pdev->dev, + "Soft reset not supported. Firmware update is required.\n"); rc = -ENOTSUPP; /* try soft reset */ goto unmap_cfgtable; } @@ -5925,8 +5832,7 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY); if (rc) { dev_warn(&pdev->dev, - "failed waiting for board to become ready " - "after hard reset\n"); + "Failed waiting for board to become ready after hard reset\n"); goto unmap_cfgtable; } @@ -5977,7 +5883,7 @@ static void print_cfg_table(struct device *dev, struct CfgTable __iomem *tb) readl(&(tb->HostWrite.CoalIntDelay))); dev_info(dev, " Coalesce Interrupt Count = 0x%x\n", readl(&(tb->HostWrite.CoalIntCount))); - dev_info(dev, " Max outstanding commands = 0x%d\n", + dev_info(dev, " Max outstanding commands = %d\n", readl(&(tb->CmdsOutMax))); dev_info(dev, " Bus Types = 0x%x\n", readl(&(tb->BusTypes))); for (i = 0; i < 16; i++) @@ -6025,7 +5931,7 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr) } /* If MSI/MSI-X is supported by the kernel we will try to enable it on - * controllers that are capable. If not, we use IO-APIC mode. + * controllers that are capable. If not, we use legacy INTx mode. */ static void hpsa_interrupt_mode(struct ctlr_info *h) @@ -6044,7 +5950,7 @@ static void hpsa_interrupt_mode(struct ctlr_info *h) (h->board_id == 0x40820E11) || (h->board_id == 0x40830E11)) goto default_int_mode; if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) { - dev_info(&h->pdev->dev, "MSIX\n"); + dev_info(&h->pdev->dev, "MSI-X capable controller\n"); h->msix_vector = MAX_REPLY_QUEUES; if (h->msix_vector > num_online_cpus()) h->msix_vector = num_online_cpus(); @@ -6065,7 +5971,7 @@ static void hpsa_interrupt_mode(struct ctlr_info *h) } single_msi_mode: if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) { - dev_info(&h->pdev->dev, "MSI\n"); + dev_info(&h->pdev->dev, "MSI capable controller\n"); if (!pci_enable_msi(h->pdev)) h->msi_vector = 1; else @@ -6172,8 +6078,10 @@ static int hpsa_find_cfgtables(struct ctlr_info *h) return rc; h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev, cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable)); - if (!h->cfgtable) + if (!h->cfgtable) { + dev_err(&h->pdev->dev, "Failed mapping cfgtable\n"); return -ENOMEM; + } rc = write_driver_ver_to_cfgtable(h->cfgtable); if (rc) return rc; @@ -6204,6 +6112,15 @@ static void hpsa_get_max_perf_mode_cmds(struct ctlr_info *h) } } +/* If the controller reports that the total max sg entries is greater than 512, + * then we know that chained SG blocks work. (Original smart arrays did not + * support chained SG blocks and would return zero for max sg entries.) + */ +static int hpsa_supports_chained_sg_blocks(struct ctlr_info *h) +{ + return h->maxsgentries > 512; +} + /* Interrogate the hardware for some limits: * max commands, max SG elements without chaining, and with chaining, * SG chain block size, etc. @@ -6211,21 +6128,23 @@ static void hpsa_get_max_perf_mode_cmds(struct ctlr_info *h) static void hpsa_find_board_params(struct ctlr_info *h) { hpsa_get_max_perf_mode_cmds(h); - h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */ + h->nr_cmds = h->max_commands; h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements)); h->fw_support = readl(&(h->cfgtable->misc_fw_support)); - /* - * Limit in-command s/g elements to 32 save dma'able memory. - * Howvever spec says if 0, use 31 - */ - h->max_cmd_sg_entries = 31; - if (h->maxsgentries > 512) { + if (hpsa_supports_chained_sg_blocks(h)) { + /* Limit in-command s/g elements to 32 save dma'able memory. */ h->max_cmd_sg_entries = 32; h->chainsize = h->maxsgentries - h->max_cmd_sg_entries; h->maxsgentries--; /* save one for chain pointer */ } else { - h->chainsize = 0; + /* + * Original smart arrays supported at most 31 s/g entries + * embedded inline in the command (trying to use more + * would lock up the controller) + */ + h->max_cmd_sg_entries = 31; h->maxsgentries = 31; /* default to traditional values */ + h->chainsize = 0; } /* Find out what task management functions are supported and cache */ @@ -6239,7 +6158,7 @@ static void hpsa_find_board_params(struct ctlr_info *h) static inline bool hpsa_CISS_signature_present(struct ctlr_info *h) { if (!check_signature(h->cfgtable->Signature, "CISS", 4)) { - dev_warn(&h->pdev->dev, "not a valid CISS config table\n"); + dev_err(&h->pdev->dev, "not a valid CISS config table\n"); return false; } return true; @@ -6272,24 +6191,27 @@ static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h) writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG); } -static void hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h) +static int hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h) { int i; u32 doorbell_value; unsigned long flags; /* wait until the clear_event_notify bit 6 is cleared by controller. */ - for (i = 0; i < MAX_CONFIG_WAIT; i++) { + for (i = 0; i < MAX_CLEAR_EVENT_WAIT; i++) { spin_lock_irqsave(&h->lock, flags); doorbell_value = readl(h->vaddr + SA5_DOORBELL); spin_unlock_irqrestore(&h->lock, flags); if (!(doorbell_value & DOORBELL_CLEAR_EVENTS)) - break; + goto done; /* delay and try again */ - msleep(20); + msleep(CLEAR_EVENT_WAIT_INTERVAL); } + return -ENODEV; +done: + return 0; } -static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h) +static int hpsa_wait_for_mode_change_ack(struct ctlr_info *h) { int i; u32 doorbell_value; @@ -6299,17 +6221,21 @@ static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h) * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right * as we enter this code.) */ - for (i = 0; i < MAX_CONFIG_WAIT; i++) { + for (i = 0; i < MAX_MODE_CHANGE_WAIT; i++) { spin_lock_irqsave(&h->lock, flags); doorbell_value = readl(h->vaddr + SA5_DOORBELL); spin_unlock_irqrestore(&h->lock, flags); if (!(doorbell_value & CFGTBL_ChangeReq)) - break; + goto done; /* delay and try again */ - usleep_range(10000, 20000); + msleep(MODE_CHANGE_WAIT_INTERVAL); } + return -ENODEV; +done: + return 0; } +/* return -ENODEV or other reason on error, 0 on success */ static int hpsa_enter_simple_mode(struct ctlr_info *h) { u32 trans_support; @@ -6324,14 +6250,15 @@ static int hpsa_enter_simple_mode(struct ctlr_info *h) writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest)); writel(0, &h->cfgtable->HostWrite.command_pool_addr_hi); writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + if (hpsa_wait_for_mode_change_ack(h)) + goto error; print_cfg_table(&h->pdev->dev, h->cfgtable); if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) goto error; h->transMethod = CFGTBL_Trans_Simple; return 0; error: - dev_warn(&h->pdev->dev, "unable to get board into simple mode\n"); + dev_err(&h->pdev->dev, "failed to enter simple mode\n"); return -ENODEV; } @@ -6341,7 +6268,7 @@ static int hpsa_pci_init(struct ctlr_info *h) prod_index = hpsa_lookup_board_id(h->pdev, &h->board_id); if (prod_index < 0) - return -ENODEV; + return prod_index; h->product_name = products[prod_index].product_name; h->access = *(products[prod_index].access); @@ -6422,6 +6349,7 @@ static void hpsa_hba_inquiry(struct ctlr_info *h) static int hpsa_init_reset_devices(struct pci_dev *pdev) { int rc, i; + void __iomem *vaddr; if (!reset_devices) return 0; @@ -6445,6 +6373,14 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) pci_set_master(pdev); + vaddr = pci_ioremap_bar(pdev, 0); + if (vaddr == NULL) { + rc = -ENOMEM; + goto out_disable; + } + writel(SA5_INTR_OFF, vaddr + SA5_REPLY_INTR_MASK_OFFSET); + iounmap(vaddr); + /* Reset the controller with a PCI power-cycle or via doorbell */ rc = hpsa_kdump_hard_reset_controller(pdev); @@ -6453,14 +6389,11 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev) * "performant mode". Or, it might be 640x, which can't reset * due to concerns about shared bbwc between 6402/6404 pair. */ - if (rc) { - if (rc != -ENOTSUPP) /* just try to do the kdump anyhow. */ - rc = -ENODEV; + if (rc) goto out_disable; - } /* 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"); + dev_info(&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; @@ -6490,9 +6423,12 @@ static int hpsa_allocate_cmd_pool(struct ctlr_info *h) || (h->cmd_pool == NULL) || (h->errinfo_pool == NULL)) { dev_err(&h->pdev->dev, "out of memory in %s", __func__); - return -ENOMEM; + goto clean_up; } return 0; +clean_up: + hpsa_free_cmd_pool(h); + return -ENOMEM; } static void hpsa_free_cmd_pool(struct ctlr_info *h) @@ -6519,16 +6455,38 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h) static void hpsa_irq_affinity_hints(struct ctlr_info *h) { - int i, cpu, rc; + int i, cpu; cpu = cpumask_first(cpu_online_mask); for (i = 0; i < h->msix_vector; i++) { - rc = irq_set_affinity_hint(h->intr[i], get_cpu_mask(cpu)); + irq_set_affinity_hint(h->intr[i], get_cpu_mask(cpu)); cpu = cpumask_next(cpu, cpu_online_mask); } } -static int hpsa_request_irq(struct ctlr_info *h, +/* clear affinity hints and free MSI-X, MSI, or legacy INTx vectors */ +static void hpsa_free_irqs(struct ctlr_info *h) +{ + int i; + + if (!h->msix_vector || h->intr_mode != PERF_MODE_INT) { + /* Single reply queue, only one irq to free */ + i = h->intr_mode; + irq_set_affinity_hint(h->intr[i], NULL); + free_irq(h->intr[i], &h->q[i]); + return; + } + + for (i = 0; i < h->msix_vector; i++) { + irq_set_affinity_hint(h->intr[i], NULL); + free_irq(h->intr[i], &h->q[i]); + } + for (; i < MAX_REPLY_QUEUES; i++) + h->q[i] = 0; +} + +/* returns 0 on success; cleans up and returns -Enn on error */ +static int hpsa_request_irqs(struct ctlr_info *h, irqreturn_t (*msixhandler)(int, void *), irqreturn_t (*intxhandler)(int, void *)) { @@ -6543,10 +6501,25 @@ static int hpsa_request_irq(struct ctlr_info *h, if (h->intr_mode == PERF_MODE_INT && h->msix_vector > 0) { /* If performant mode and MSI-X, use multiple reply queues */ - for (i = 0; i < h->msix_vector; i++) + for (i = 0; i < h->msix_vector; i++) { rc = request_irq(h->intr[i], msixhandler, 0, h->devname, &h->q[i]); + if (rc) { + int j; + + dev_err(&h->pdev->dev, + "failed to get irq %d for %s\n", + h->intr[i], h->devname); + for (j = 0; j < i; j++) { + free_irq(h->intr[j], &h->q[j]); + h->q[j] = 0; + } + for (; j < MAX_REPLY_QUEUES; j++) + h->q[j] = 0; + return rc; + } + } hpsa_irq_affinity_hints(h); } else { /* Use single reply pool */ @@ -6592,27 +6565,9 @@ static int hpsa_kdump_soft_reset(struct ctlr_info *h) return 0; } -static void free_irqs(struct ctlr_info *h) -{ - int i; - - if (!h->msix_vector || h->intr_mode != PERF_MODE_INT) { - /* Single reply queue, only one irq to free */ - i = h->intr_mode; - irq_set_affinity_hint(h->intr[i], NULL); - free_irq(h->intr[i], &h->q[i]); - return; - } - - for (i = 0; i < h->msix_vector; i++) { - irq_set_affinity_hint(h->intr[i], NULL); - free_irq(h->intr[i], &h->q[i]); - } -} - static void hpsa_free_irqs_and_disable_msix(struct ctlr_info *h) { - free_irqs(h); + hpsa_free_irqs(h); #ifdef CONFIG_PCI_MSI if (h->msix_vector) { if (h->pdev->msix_enabled) @@ -6658,16 +6613,20 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) } /* Called when controller lockup detected. */ -static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list) +static void fail_all_outstanding_cmds(struct ctlr_info *h) { - struct CommandList *c = NULL; + int i, refcount; + struct CommandList *c; - assert_spin_locked(&h->lock); - /* Mark all outstanding commands as failed and complete them. */ - while (!list_empty(list)) { - c = list_entry(list->next, struct CommandList, list); - c->err_info->CommandStatus = CMD_HARDWARE_ERR; - finish_cmd(c); + flush_workqueue(h->resubmit_wq); /* ensure all cmds are fully built */ + for (i = 0; i < h->nr_cmds; i++) { + c = h->cmd_pool + i; + refcount = atomic_inc_return(&c->refcount); + if (refcount > 1) { + c->err_info->CommandStatus = CMD_HARDWARE_ERR; + finish_cmd(c); + } + cmd_free(h, c); } } @@ -6704,10 +6663,7 @@ static void controller_lockup_detected(struct ctlr_info *h) dev_warn(&h->pdev->dev, "Controller lockup detected: 0x%08x\n", lockup_detected); pci_disable_device(h->pdev); - spin_lock_irqsave(&h->lock, flags); - fail_all_cmds_on_list(h, &h->cmpQ); - fail_all_cmds_on_list(h, &h->reqQ); - spin_unlock_irqrestore(&h->lock, flags); + fail_all_outstanding_cmds(h); } static void detect_controller_lockup(struct ctlr_info *h) @@ -6750,8 +6706,8 @@ static void hpsa_ack_ctlr_events(struct ctlr_info *h) int i; char *event_type; - /* Clear the driver-requested rescan flag */ - h->drv_req_rescan = 0; + if (!(h->fw_support & MISC_FW_EVENT_NOTIFY)) + return; /* Ask the controller to clear the events we're handling. */ if ((h->transMethod & (CFGTBL_Trans_io_accel1 @@ -6798,9 +6754,6 @@ static void hpsa_ack_ctlr_events(struct ctlr_info *h) */ static int hpsa_ctlr_needs_rescan(struct ctlr_info *h) { - if (h->drv_req_rescan) - return 1; - if (!(h->fw_support & MISC_FW_EVENT_NOTIFY)) return 0; @@ -6834,34 +6787,60 @@ static int hpsa_offline_devices_ready(struct ctlr_info *h) return 0; } +static void hpsa_rescan_ctlr_worker(struct work_struct *work) +{ + unsigned long flags; + struct ctlr_info *h = container_of(to_delayed_work(work), + struct ctlr_info, rescan_ctlr_work); + + + if (h->remove_in_progress) + return; + + if (hpsa_ctlr_needs_rescan(h) || hpsa_offline_devices_ready(h)) { + scsi_host_get(h->scsi_host); + hpsa_ack_ctlr_events(h); + hpsa_scan_start(h->scsi_host); + scsi_host_put(h->scsi_host); + } + spin_lock_irqsave(&h->lock, flags); + if (!h->remove_in_progress) + queue_delayed_work(h->rescan_ctlr_wq, &h->rescan_ctlr_work, + h->heartbeat_sample_interval); + spin_unlock_irqrestore(&h->lock, flags); +} static void hpsa_monitor_ctlr_worker(struct work_struct *work) { unsigned long flags; struct ctlr_info *h = container_of(to_delayed_work(work), struct ctlr_info, monitor_ctlr_work); + detect_controller_lockup(h); if (lockup_detected(h)) return; - if (hpsa_ctlr_needs_rescan(h) || hpsa_offline_devices_ready(h)) { - scsi_host_get(h->scsi_host); - h->drv_req_rescan = 0; - hpsa_ack_ctlr_events(h); - hpsa_scan_start(h->scsi_host); - scsi_host_put(h->scsi_host); - } - spin_lock_irqsave(&h->lock, flags); - if (h->remove_in_progress) { - spin_unlock_irqrestore(&h->lock, flags); - return; - } - schedule_delayed_work(&h->monitor_ctlr_work, + if (!h->remove_in_progress) + schedule_delayed_work(&h->monitor_ctlr_work, h->heartbeat_sample_interval); spin_unlock_irqrestore(&h->lock, flags); } +static struct workqueue_struct *hpsa_create_controller_wq(struct ctlr_info *h, + char *name) +{ + struct workqueue_struct *wq = NULL; + char wq_name[20]; + + snprintf(wq_name, sizeof(wq_name), "%s_%d_hpsa", name, h->ctlr); + wq = alloc_ordered_workqueue(wq_name, 0); + if (!wq) + dev_err(&h->pdev->dev, "failed to create %s workqueue\n", name); + + return wq; +} + static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int dac, rc; @@ -6898,13 +6877,23 @@ reinit_after_soft_reset: h->pdev = pdev; h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT; - INIT_LIST_HEAD(&h->cmpQ); - INIT_LIST_HEAD(&h->reqQ); INIT_LIST_HEAD(&h->offline_device_list); spin_lock_init(&h->lock); spin_lock_init(&h->offline_device_lock); spin_lock_init(&h->scan_lock); - spin_lock_init(&h->passthru_count_lock); + atomic_set(&h->passthru_cmds_avail, HPSA_MAX_CONCURRENT_PASSTHRUS); + + h->rescan_ctlr_wq = hpsa_create_controller_wq(h, "rescan"); + if (!h->rescan_ctlr_wq) { + rc = -ENOMEM; + goto clean1; + } + + h->resubmit_wq = hpsa_create_controller_wq(h, "resubmit"); + if (!h->resubmit_wq) { + rc = -ENOMEM; + goto clean1; + } /* Allocate and clear per-cpu variable lockup_detected */ h->lockup_detected = alloc_percpu(u32); @@ -6939,13 +6928,14 @@ reinit_after_soft_reset: /* make sure the board interrupts are off */ h->access.set_intr_mask(h, HPSA_INTR_OFF); - if (hpsa_request_irq(h, do_hpsa_intr_msi, do_hpsa_intr_intx)) + if (hpsa_request_irqs(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"); - if (hpsa_allocate_cmd_pool(h)) - goto clean4; + rc = hpsa_allocate_cmd_pool(h); + if (rc) + goto clean2_and_free_irqs; if (hpsa_allocate_sg_chain_blocks(h)) goto clean4; init_waitqueue_head(&h->scan_wait_queue); @@ -6974,12 +6964,12 @@ reinit_after_soft_reset: spin_lock_irqsave(&h->lock, flags); h->access.set_intr_mask(h, HPSA_INTR_OFF); spin_unlock_irqrestore(&h->lock, flags); - free_irqs(h); - rc = hpsa_request_irq(h, hpsa_msix_discard_completions, + hpsa_free_irqs(h); + rc = hpsa_request_irqs(h, hpsa_msix_discard_completions, hpsa_intx_discard_completions); if (rc) { - dev_warn(&h->pdev->dev, "Failed to request_irq after " - "soft reset.\n"); + dev_warn(&h->pdev->dev, + "Failed to request_irq after soft reset.\n"); goto clean4; } @@ -7016,7 +7006,6 @@ reinit_after_soft_reset: /* Enable Accelerated IO path at driver layer */ h->acciopath_status = 1; - h->drv_req_rescan = 0; /* Turn the interrupts on so we can service requests */ h->access.set_intr_mask(h, HPSA_INTR_ON); @@ -7029,14 +7018,22 @@ reinit_after_soft_reset: INIT_DELAYED_WORK(&h->monitor_ctlr_work, hpsa_monitor_ctlr_worker); schedule_delayed_work(&h->monitor_ctlr_work, h->heartbeat_sample_interval); + INIT_DELAYED_WORK(&h->rescan_ctlr_work, hpsa_rescan_ctlr_worker); + queue_delayed_work(h->rescan_ctlr_wq, &h->rescan_ctlr_work, + h->heartbeat_sample_interval); return 0; clean4: hpsa_free_sg_chain_blocks(h); hpsa_free_cmd_pool(h); - free_irqs(h); +clean2_and_free_irqs: + hpsa_free_irqs(h); clean2: clean1: + if (h->resubmit_wq) + destroy_workqueue(h->resubmit_wq); + if (h->rescan_ctlr_wq) + destroy_workqueue(h->rescan_ctlr_wq); if (h->lockup_detected) free_percpu(h->lockup_detected); kfree(h); @@ -7055,9 +7052,9 @@ static void hpsa_flush_cache(struct ctlr_info *h) if (!flush_buf) return; - c = cmd_special_alloc(h); + c = cmd_alloc(h); if (!c) { - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n"); goto out_of_memory; } if (fill_cmd(c, HPSA_CACHE_FLUSH, h, flush_buf, 4, 0, @@ -7069,7 +7066,7 @@ static void hpsa_flush_cache(struct ctlr_info *h) out: dev_warn(&h->pdev->dev, "error flushing cache on controller\n"); - cmd_special_free(h, c); + cmd_free(h, c); out_of_memory: kfree(flush_buf); } @@ -7110,9 +7107,11 @@ static void hpsa_remove_one(struct pci_dev *pdev) /* Get rid of any controller monitoring work items */ spin_lock_irqsave(&h->lock, flags); h->remove_in_progress = 1; - cancel_delayed_work(&h->monitor_ctlr_work); spin_unlock_irqrestore(&h->lock, flags); - + cancel_delayed_work_sync(&h->monitor_ctlr_work); + cancel_delayed_work_sync(&h->rescan_ctlr_work); + destroy_workqueue(h->rescan_ctlr_wq); + destroy_workqueue(h->resubmit_wq); hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ hpsa_shutdown(pdev); iounmap(h->vaddr); @@ -7172,7 +7171,7 @@ static struct pci_driver hpsa_pci_driver = { * bits of the command address. */ static void calc_bucket_map(int bucket[], int num_buckets, - int nsgs, int min_blocks, int *bucket_map) + int nsgs, int min_blocks, u32 *bucket_map) { int i, j, b, size; @@ -7193,7 +7192,8 @@ static void calc_bucket_map(int bucket[], int num_buckets, } } -static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) +/* return -ENODEV or other reason on error, 0 on success */ +static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) { int i; unsigned long register_value; @@ -7285,12 +7285,16 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) } } writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + if (hpsa_wait_for_mode_change_ack(h)) { + dev_err(&h->pdev->dev, + "performant mode problem - doorbell timeout\n"); + return -ENODEV; + } register_value = readl(&(h->cfgtable->TransportActive)); if (!(register_value & CFGTBL_Trans_Performant)) { - dev_warn(&h->pdev->dev, "unable to get board into" - " performant mode\n"); - return; + dev_err(&h->pdev->dev, + "performant mode problem - transport not active\n"); + return -ENODEV; } /* Change the access methods to the performant access methods */ h->access = access; @@ -7298,7 +7302,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) if (!((trans_support & CFGTBL_Trans_io_accel1) || (trans_support & CFGTBL_Trans_io_accel2))) - return; + return 0; if (trans_support & CFGTBL_Trans_io_accel1) { /* Set up I/O accelerator mode */ @@ -7328,12 +7332,12 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) (i * sizeof(struct ErrorInfo))); cp->err_info_len = sizeof(struct ErrorInfo); cp->sgl_offset = IOACCEL1_SGLOFFSET; - cp->host_context_flags = IOACCEL1_HCFLAGS_CISS_FORMAT; + cp->host_context_flags = + cpu_to_le16(IOACCEL1_HCFLAGS_CISS_FORMAT); cp->timeout_sec = 0; cp->ReplyQueue = 0; cp->tag = - cpu_to_le64((i << DIRECT_LOOKUP_SHIFT) | - DIRECT_LOOKUP_BIT); + cpu_to_le64((i << DIRECT_LOOKUP_SHIFT)); cp->host_addr = cpu_to_le64(h->ioaccel_cmd_pool_dhandle + (i * sizeof(struct io_accel1_cmd))); @@ -7362,7 +7366,12 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support) writel(bft2[i], &h->ioaccel2_bft2_regs[i]); } writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); + if (hpsa_wait_for_mode_change_ack(h)) { + dev_err(&h->pdev->dev, + "performant mode problem - enabling ioaccel mode\n"); + return -ENODEV; + } + return 0; } static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h) @@ -7508,17 +7517,18 @@ static int is_accelerated_cmd(struct CommandList *c) static void hpsa_drain_accel_commands(struct ctlr_info *h) { struct CommandList *c = NULL; - unsigned long flags; - int accel_cmds_out; + int i, accel_cmds_out; + int refcount; - do { /* wait for all outstanding commands to drain out */ + do { /* wait for all outstanding ioaccel commands to drain out */ accel_cmds_out = 0; - spin_lock_irqsave(&h->lock, flags); - list_for_each_entry(c, &h->cmpQ, list) - accel_cmds_out += is_accelerated_cmd(c); - list_for_each_entry(c, &h->reqQ, list) - accel_cmds_out += is_accelerated_cmd(c); - spin_unlock_irqrestore(&h->lock, flags); + for (i = 0; i < h->nr_cmds; i++) { + c = h->cmd_pool + i; + refcount = atomic_inc_return(&c->refcount); + if (refcount > 1) /* Command is allocated */ + accel_cmds_out += is_accelerated_cmd(c); + cmd_free(h, c); + } if (accel_cmds_out <= 0) break; msleep(100); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 8e06d9e280ec..657713050349 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -32,7 +32,6 @@ struct access_method { void (*submit_command)(struct ctlr_info *h, struct CommandList *c); void (*set_intr_mask)(struct ctlr_info *h, unsigned long val); - unsigned long (*fifo_full)(struct ctlr_info *h); bool (*intr_pending)(struct ctlr_info *h); unsigned long (*command_completed)(struct ctlr_info *h, u8 q); }; @@ -47,6 +46,11 @@ struct hpsa_scsi_dev_t { unsigned char model[16]; /* bytes 16-31 of inquiry data */ unsigned char raid_level; /* from inquiry page 0xC1 */ unsigned char volume_offline; /* discovered via TUR or VPD */ + u16 queue_depth; /* max queue_depth for this device */ + atomic_t ioaccel_cmds_out; /* Only used for physical devices + * counts commands sent to physical + * device via "ioaccel" path. + */ u32 ioaccel_handle; int offload_config; /* I/O accel RAID offload configured */ int offload_enabled; /* I/O accel RAID offload enabled */ @@ -55,6 +59,15 @@ struct hpsa_scsi_dev_t { */ struct raid_map_data raid_map; /* I/O accelerator RAID map */ + /* + * Pointers from logical drive map indices to the phys drives that + * make those logical drives. Note, multiple logical drives may + * share physical drives. You can have for instance 5 physical + * drives with 3 logical drives each using those same 5 physical + * disks. We need these pointers for counting i/o's out to physical + * devices in order to honor physical device queue depth limits. + */ + struct hpsa_scsi_dev_t *phys_disk[RAID_MAP_MAX_ENTRIES]; }; struct reply_queue_buffer { @@ -115,9 +128,12 @@ struct ctlr_info { void __iomem *vaddr; unsigned long paddr; int nr_cmds; /* Number of commands allowed on this controller */ +#define HPSA_CMDS_RESERVED_FOR_ABORTS 2 +#define HPSA_CMDS_RESERVED_FOR_DRIVER 1 struct CfgTable __iomem *cfgtable; int interrupts_enabled; int max_commands; + int last_allocation; atomic_t commands_outstanding; # define PERF_MODE_INT 0 # define DOORBELL_INT 1 @@ -131,8 +147,6 @@ struct ctlr_info { char hba_mode_enabled; /* queue and queue Info */ - struct list_head reqQ; - struct list_head cmpQ; unsigned int Qdepth; unsigned int maxSG; spinlock_t lock; @@ -168,9 +182,8 @@ struct ctlr_info { unsigned long transMethod; /* cap concurrent passthrus at some reasonable maximum */ -#define HPSA_MAX_CONCURRENT_PASSTHRUS (20) - spinlock_t passthru_count_lock; /* protects passthru_count */ - int passthru_count; +#define HPSA_MAX_CONCURRENT_PASSTHRUS (10) + atomic_t passthru_cmds_avail; /* * Performant mode completion buffers @@ -194,8 +207,8 @@ struct ctlr_info { atomic_t firmware_flash_in_progress; u32 __percpu *lockup_detected; struct delayed_work monitor_ctlr_work; + struct delayed_work rescan_ctlr_work; int remove_in_progress; - u32 fifo_recently_full; /* Address of h->q[x] is passed to intr handler to know which queue */ u8 q[MAX_REPLY_QUEUES]; u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */ @@ -237,8 +250,9 @@ struct ctlr_info { spinlock_t offline_device_lock; struct list_head offline_device_list; int acciopath_status; - int drv_req_rescan; /* flag for driver to request rescan event */ int raid_offload_debug; + struct workqueue_struct *resubmit_wq; + struct workqueue_struct *rescan_ctlr_wq; }; struct offline_device_entry { @@ -297,6 +311,8 @@ struct offline_device_entry { */ #define SA5_DOORBELL 0x20 #define SA5_REQUEST_PORT_OFFSET 0x40 +#define SA5_REQUEST_PORT64_LO_OFFSET 0xC0 +#define SA5_REQUEST_PORT64_HI_OFFSET 0xC4 #define SA5_REPLY_INTR_MASK_OFFSET 0x34 #define SA5_REPLY_PORT_OFFSET 0x44 #define SA5_INTR_STATUS 0x30 @@ -353,10 +369,7 @@ static void SA5_submit_command_no_read(struct ctlr_info *h, static void SA5_submit_command_ioaccel2(struct ctlr_info *h, struct CommandList *c) { - if (c->cmd_type == CMD_IOACCEL2) - writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32); - else - writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); + writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); } /* @@ -398,19 +411,19 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) unsigned long register_value = FIFO_EMPTY; /* msi auto clears the interrupt pending bit. */ - if (!(h->msi_vector || h->msix_vector)) { + if (unlikely(!(h->msi_vector || h->msix_vector))) { /* flush the controller write of the reply queue by reading * outbound doorbell status register. */ - register_value = readl(h->vaddr + SA5_OUTDB_STATUS); + (void) readl(h->vaddr + SA5_OUTDB_STATUS); writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR); /* Do a read in order to flush the write to the controller * (as per spec.) */ - register_value = readl(h->vaddr + SA5_OUTDB_STATUS); + (void) readl(h->vaddr + SA5_OUTDB_STATUS); } - if ((rq->head[rq->current_entry] & 1) == rq->wraparound) { + if ((((u32) rq->head[rq->current_entry]) & 1) == rq->wraparound) { register_value = rq->head[rq->current_entry]; rq->current_entry++; atomic_dec(&h->commands_outstanding); @@ -425,14 +438,6 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) return register_value; } -/* - * Returns true if fifo is full. - * - */ -static unsigned long SA5_fifo_full(struct ctlr_info *h) -{ - return atomic_read(&h->commands_outstanding) >= h->max_commands; -} /* * returns value read from hardware. * returns FIFO_EMPTY if there is nothing to read @@ -473,9 +478,6 @@ static bool SA5_performant_intr_pending(struct ctlr_info *h) if (!register_value) return false; - if (h->msi_vector || h->msix_vector) - return true; - /* Read outbound doorbell to flush */ register_value = readl(h->vaddr + SA5_OUTDB_STATUS); return register_value & SA5_OUTDB_STATUS_PERF_BIT; @@ -525,7 +527,6 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q) static struct access_method SA5_access = { SA5_submit_command, SA5_intr_mask, - SA5_fifo_full, SA5_intr_pending, SA5_completed, }; @@ -533,7 +534,6 @@ static struct access_method SA5_access = { static struct access_method SA5_ioaccel_mode1_access = { SA5_submit_command, SA5_performant_intr_mask, - SA5_fifo_full, SA5_ioaccel_mode1_intr_pending, SA5_ioaccel_mode1_completed, }; @@ -541,7 +541,6 @@ static struct access_method SA5_ioaccel_mode1_access = { static struct access_method SA5_ioaccel_mode2_access = { SA5_submit_command_ioaccel2, SA5_performant_intr_mask, - SA5_fifo_full, SA5_performant_intr_pending, SA5_performant_completed, }; @@ -549,7 +548,6 @@ static struct access_method SA5_ioaccel_mode2_access = { static struct access_method SA5_performant_access = { SA5_submit_command, SA5_performant_intr_mask, - SA5_fifo_full, SA5_performant_intr_pending, SA5_performant_completed, }; @@ -557,7 +555,6 @@ static struct access_method SA5_performant_access = { static struct access_method SA5_performant_access_no_read = { SA5_submit_command_no_read, SA5_performant_intr_mask, - SA5_fifo_full, SA5_performant_intr_pending, SA5_performant_completed, }; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index cb988c41cad9..3a621c74b76f 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -206,27 +206,27 @@ struct raid_map_disk_data { }; struct raid_map_data { - u32 structure_size; /* Size of entire structure in bytes */ - u32 volume_blk_size; /* bytes / block in the volume */ - u64 volume_blk_cnt; /* logical blocks on the volume */ + __le32 structure_size; /* Size of entire structure in bytes */ + __le32 volume_blk_size; /* bytes / block in the volume */ + __le64 volume_blk_cnt; /* logical blocks on the volume */ u8 phys_blk_shift; /* Shift factor to convert between * units of logical blocks and physical * disk blocks */ u8 parity_rotation_shift; /* Shift factor to convert between units * of logical stripes and physical * stripes */ - u16 strip_size; /* blocks used on each disk / stripe */ - u64 disk_starting_blk; /* First disk block used in volume */ - u64 disk_blk_cnt; /* disk blocks used by volume / disk */ - u16 data_disks_per_row; /* data disk entries / row in the map */ - u16 metadata_disks_per_row; /* mirror/parity disk entries / row + __le16 strip_size; /* blocks used on each disk / stripe */ + __le64 disk_starting_blk; /* First disk block used in volume */ + __le64 disk_blk_cnt; /* disk blocks used by volume / disk */ + __le16 data_disks_per_row; /* data disk entries / row in the map */ + __le16 metadata_disks_per_row;/* mirror/parity disk entries / row * in the map */ - u16 row_cnt; /* rows in each layout map */ - u16 layout_map_count; /* layout maps (1 map per mirror/parity + __le16 row_cnt; /* rows in each layout map */ + __le16 layout_map_count; /* layout maps (1 map per mirror/parity * group) */ - u16 flags; /* Bit 0 set if encryption enabled */ + __le16 flags; /* Bit 0 set if encryption enabled */ #define RAID_MAP_FLAG_ENCRYPT_ON 0x01 - u16 dekindex; /* Data encryption key index. */ + __le16 dekindex; /* Data encryption key index. */ u8 reserved[16]; struct raid_map_disk_data data[RAID_MAP_MAX_ENTRIES]; }; @@ -240,6 +240,10 @@ struct ReportLUNdata { struct ext_report_lun_entry { u8 lunid[8]; +#define GET_BMIC_BUS(lunid) ((lunid)[7] & 0x3F) +#define GET_BMIC_LEVEL_TWO_TARGET(lunid) ((lunid)[6]) +#define GET_BMIC_DRIVE_NUMBER(lunid) (((GET_BMIC_BUS((lunid)) - 1) << 8) + \ + GET_BMIC_LEVEL_TWO_TARGET((lunid))) u8 wwid[8]; u8 device_type; u8 device_flags; @@ -268,6 +272,7 @@ struct SenseSubsystem_info { #define HPSA_CACHE_FLUSH 0x01 /* C2 was already being used by HPSA */ #define BMIC_FLASH_FIRMWARE 0xF7 #define BMIC_SENSE_CONTROLLER_PARAMETERS 0x64 +#define BMIC_IDENTIFY_PHYSICAL_DEVICE 0x15 /* Command List Structure */ union SCSI3Addr { @@ -313,8 +318,8 @@ union LUNAddr { struct CommandListHeader { u8 ReplyQueue; u8 SGList; - u16 SGTotal; - u64 tag; + __le16 SGTotal; + __le64 tag; union LUNAddr LUN; }; @@ -338,14 +343,14 @@ struct RequestBlock { }; struct ErrDescriptor { - u64 Addr; - u32 Len; + __le64 Addr; + __le32 Len; }; struct SGDescriptor { - u64 Addr; - u32 Len; - u32 Ext; + __le64 Addr; + __le32 Len; + __le32 Ext; }; union MoreErrInfo { @@ -375,22 +380,19 @@ struct ErrorInfo { #define CMD_IOACCEL1 0x04 #define CMD_IOACCEL2 0x05 -#define DIRECT_LOOKUP_SHIFT 5 -#define DIRECT_LOOKUP_BIT 0x10 +#define DIRECT_LOOKUP_SHIFT 4 #define DIRECT_LOOKUP_MASK (~((1 << DIRECT_LOOKUP_SHIFT) - 1)) #define HPSA_ERROR_BIT 0x02 struct ctlr_info; /* defined in hpsa.h */ -/* The size of this structure needs to be divisible by 32 - * on all architectures because low 5 bits of the addresses +/* The size of this structure needs to be divisible by 128 + * on all architectures. The low 4 bits of the addresses * are used as follows: * * bit 0: to device, used to indicate "performant mode" command * from device, indidcates error status. * bit 1-3: to device, indicates block fetch table entry for * reducing DMA in fetching commands from host memory. - * bit 4: used to indicate whether tag is "direct lookup" (index), - * or a bus address. */ #define COMMANDLIST_ALIGNMENT 128 @@ -405,9 +407,21 @@ struct CommandList { struct ctlr_info *h; int cmd_type; long cmdindex; - struct list_head list; struct completion *waiting; - void *scsi_cmd; + struct scsi_cmnd *scsi_cmd; + struct work_struct work; + + /* + * For commands using either of the two "ioaccel" paths to + * bypass the RAID stack and go directly to the physical disk + * phys_disk is a pointer to the hpsa_scsi_dev_t to which the + * i/o is destined. We need to store that here because the command + * may potentially encounter TASK SET FULL and need to be resubmitted + * For "normal" i/o's not using the "ioaccel" paths, phys_disk is + * not used. + */ + struct hpsa_scsi_dev_t *phys_disk; + atomic_t refcount; /* Must be last to avoid memset in cmd_alloc */ } __aligned(COMMANDLIST_ALIGNMENT); /* Max S/G elements in I/O accelerator command */ @@ -420,7 +434,7 @@ struct CommandList { */ #define IOACCEL1_COMMANDLIST_ALIGNMENT 128 struct io_accel1_cmd { - u16 dev_handle; /* 0x00 - 0x01 */ + __le16 dev_handle; /* 0x00 - 0x01 */ u8 reserved1; /* 0x02 */ u8 function; /* 0x03 */ u8 reserved2[8]; /* 0x04 - 0x0B */ @@ -430,20 +444,20 @@ struct io_accel1_cmd { u8 reserved4; /* 0x13 */ u8 sgl_offset; /* 0x14 */ u8 reserved5[7]; /* 0x15 - 0x1B */ - u32 transfer_len; /* 0x1C - 0x1F */ + __le32 transfer_len; /* 0x1C - 0x1F */ u8 reserved6[4]; /* 0x20 - 0x23 */ - u16 io_flags; /* 0x24 - 0x25 */ + __le16 io_flags; /* 0x24 - 0x25 */ u8 reserved7[14]; /* 0x26 - 0x33 */ u8 LUN[8]; /* 0x34 - 0x3B */ - u32 control; /* 0x3C - 0x3F */ + __le32 control; /* 0x3C - 0x3F */ u8 CDB[16]; /* 0x40 - 0x4F */ u8 reserved8[16]; /* 0x50 - 0x5F */ - u16 host_context_flags; /* 0x60 - 0x61 */ - u16 timeout_sec; /* 0x62 - 0x63 */ + __le16 host_context_flags; /* 0x60 - 0x61 */ + __le16 timeout_sec; /* 0x62 - 0x63 */ u8 ReplyQueue; /* 0x64 */ u8 reserved9[3]; /* 0x65 - 0x67 */ - u64 tag; /* 0x68 - 0x6F */ - u64 host_addr; /* 0x70 - 0x77 */ + __le64 tag; /* 0x68 - 0x6F */ + __le64 host_addr; /* 0x70 - 0x77 */ u8 CISS_LUN[8]; /* 0x78 - 0x7F */ struct SGDescriptor SG[IOACCEL1_MAXSGENTRIES]; } __aligned(IOACCEL1_COMMANDLIST_ALIGNMENT); @@ -470,8 +484,8 @@ struct io_accel1_cmd { #define IOACCEL1_BUSADDR_CMDTYPE 0x00000060 struct ioaccel2_sg_element { - u64 address; - u32 length; + __le64 address; + __le32 length; u8 reserved[3]; u8 chain_indicator; #define IOACCEL2_CHAIN 0x80 @@ -526,20 +540,20 @@ struct io_accel2_cmd { /* 0=off, 1=on */ u8 reply_queue; /* Reply Queue ID */ u8 reserved1; /* Reserved */ - u32 scsi_nexus; /* Device Handle */ - u32 Tag; /* cciss tag, lower 4 bytes only */ - u32 tweak_lower; /* Encryption tweak, lower 4 bytes */ + __le32 scsi_nexus; /* Device Handle */ + __le32 Tag; /* cciss tag, lower 4 bytes only */ + __le32 tweak_lower; /* Encryption tweak, lower 4 bytes */ u8 cdb[16]; /* SCSI Command Descriptor Block */ u8 cciss_lun[8]; /* 8 byte SCSI address */ - u32 data_len; /* Total bytes to transfer */ + __le32 data_len; /* Total bytes to transfer */ u8 cmd_priority_task_attr; /* priority and task attrs */ #define IOACCEL2_PRIORITY_MASK 0x78 #define IOACCEL2_ATTR_MASK 0x07 u8 sg_count; /* Number of sg elements */ - u16 dekindex; /* Data encryption key index */ - u64 err_ptr; /* Error Pointer */ - u32 err_len; /* Error Length*/ - u32 tweak_upper; /* Encryption tweak, upper 4 bytes */ + __le16 dekindex; /* Data encryption key index */ + __le64 err_ptr; /* Error Pointer */ + __le32 err_len; /* Error Length*/ + __le32 tweak_upper; /* Encryption tweak, upper 4 bytes */ struct ioaccel2_sg_element sg[IOACCEL2_MAXSGENTRIES]; struct io_accel2_scsi_response error_data; } __aligned(IOACCEL2_COMMANDLIST_ALIGNMENT); @@ -563,18 +577,18 @@ struct hpsa_tmf_struct { u8 reserved1; /* byte 3 Reserved */ u32 it_nexus; /* SCSI I-T Nexus */ u8 lun_id[8]; /* LUN ID for TMF request */ - u64 tag; /* cciss tag associated w/ request */ - u64 abort_tag; /* cciss tag of SCSI cmd or task to abort */ - u64 error_ptr; /* Error Pointer */ - u32 error_len; /* Error Length */ + __le64 tag; /* cciss tag associated w/ request */ + __le64 abort_tag; /* cciss tag of SCSI cmd or TMF to abort */ + __le64 error_ptr; /* Error Pointer */ + __le32 error_len; /* Error Length */ }; /* Configuration Table Structure */ struct HostWrite { - u32 TransportRequest; - u32 command_pool_addr_hi; - u32 CoalIntDelay; - u32 CoalIntCount; + __le32 TransportRequest; + __le32 command_pool_addr_hi; + __le32 CoalIntDelay; + __le32 CoalIntCount; }; #define SIMPLE_MODE 0x02 @@ -585,54 +599,54 @@ struct HostWrite { #define DRIVER_SUPPORT_UA_ENABLE 0x00000001 struct CfgTable { - u8 Signature[4]; - u32 SpecValence; - u32 TransportSupport; - u32 TransportActive; - struct HostWrite HostWrite; - u32 CmdsOutMax; - u32 BusTypes; - u32 TransMethodOffset; - u8 ServerName[16]; - u32 HeartBeat; - u32 driver_support; -#define ENABLE_SCSI_PREFETCH 0x100 -#define ENABLE_UNIT_ATTN 0x01 - u32 MaxScatterGatherElements; - u32 MaxLogicalUnits; - u32 MaxPhysicalDevices; - u32 MaxPhysicalDrivesPerLogicalUnit; - u32 MaxPerformantModeCommands; - u32 MaxBlockFetch; - u32 PowerConservationSupport; - u32 PowerConservationEnable; - u32 TMFSupportFlags; + u8 Signature[4]; + __le32 SpecValence; + __le32 TransportSupport; + __le32 TransportActive; + struct HostWrite HostWrite; + __le32 CmdsOutMax; + __le32 BusTypes; + __le32 TransMethodOffset; + u8 ServerName[16]; + __le32 HeartBeat; + __le32 driver_support; +#define ENABLE_SCSI_PREFETCH 0x100 +#define ENABLE_UNIT_ATTN 0x01 + __le32 MaxScatterGatherElements; + __le32 MaxLogicalUnits; + __le32 MaxPhysicalDevices; + __le32 MaxPhysicalDrivesPerLogicalUnit; + __le32 MaxPerformantModeCommands; + __le32 MaxBlockFetch; + __le32 PowerConservationSupport; + __le32 PowerConservationEnable; + __le32 TMFSupportFlags; u8 TMFTagMask[8]; u8 reserved[0x78 - 0x70]; - u32 misc_fw_support; /* offset 0x78 */ -#define MISC_FW_DOORBELL_RESET (0x02) -#define MISC_FW_DOORBELL_RESET2 (0x010) -#define MISC_FW_RAID_OFFLOAD_BASIC (0x020) -#define MISC_FW_EVENT_NOTIFY (0x080) + __le32 misc_fw_support; /* offset 0x78 */ +#define MISC_FW_DOORBELL_RESET 0x02 +#define MISC_FW_DOORBELL_RESET2 0x010 +#define MISC_FW_RAID_OFFLOAD_BASIC 0x020 +#define MISC_FW_EVENT_NOTIFY 0x080 u8 driver_version[32]; - u32 max_cached_write_size; - u8 driver_scratchpad[16]; - u32 max_error_info_length; - u32 io_accel_max_embedded_sg_count; - u32 io_accel_request_size_offset; - u32 event_notify; -#define HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE (1 << 30) -#define HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE (1 << 31) - u32 clear_event_notify; + __le32 max_cached_write_size; + u8 driver_scratchpad[16]; + __le32 max_error_info_length; + __le32 io_accel_max_embedded_sg_count; + __le32 io_accel_request_size_offset; + __le32 event_notify; +#define HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE (1 << 30) +#define HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE (1 << 31) + __le32 clear_event_notify; }; #define NUM_BLOCKFETCH_ENTRIES 8 struct TransTable_struct { - u32 BlockFetch[NUM_BLOCKFETCH_ENTRIES]; - u32 RepQSize; - u32 RepQCount; - u32 RepQCtrAddrLow32; - u32 RepQCtrAddrHigh32; + __le32 BlockFetch[NUM_BLOCKFETCH_ENTRIES]; + __le32 RepQSize; + __le32 RepQCount; + __le32 RepQCtrAddrLow32; + __le32 RepQCtrAddrHigh32; #define MAX_REPLY_QUEUES 64 struct vals32 RepQAddr[MAX_REPLY_QUEUES]; }; @@ -644,5 +658,137 @@ struct hpsa_pci_info { u32 board_id; }; +struct bmic_identify_physical_device { + u8 scsi_bus; /* SCSI Bus number on controller */ + u8 scsi_id; /* SCSI ID on this bus */ + __le16 block_size; /* sector size in bytes */ + __le32 total_blocks; /* number for sectors on drive */ + __le32 reserved_blocks; /* controller reserved (RIS) */ + u8 model[40]; /* Physical Drive Model */ + u8 serial_number[40]; /* Drive Serial Number */ + u8 firmware_revision[8]; /* drive firmware revision */ + u8 scsi_inquiry_bits; /* inquiry byte 7 bits */ + u8 compaq_drive_stamp; /* 0 means drive not stamped */ + u8 last_failure_reason; +#define BMIC_LAST_FAILURE_TOO_SMALL_IN_LOAD_CONFIG 0x01 +#define BMIC_LAST_FAILURE_ERROR_ERASING_RIS 0x02 +#define BMIC_LAST_FAILURE_ERROR_SAVING_RIS 0x03 +#define BMIC_LAST_FAILURE_FAIL_DRIVE_COMMAND 0x04 +#define BMIC_LAST_FAILURE_MARK_BAD_FAILED 0x05 +#define BMIC_LAST_FAILURE_MARK_BAD_FAILED_IN_FINISH_REMAP 0x06 +#define BMIC_LAST_FAILURE_TIMEOUT 0x07 +#define BMIC_LAST_FAILURE_AUTOSENSE_FAILED 0x08 +#define BMIC_LAST_FAILURE_MEDIUM_ERROR_1 0x09 +#define BMIC_LAST_FAILURE_MEDIUM_ERROR_2 0x0a +#define BMIC_LAST_FAILURE_NOT_READY_BAD_SENSE 0x0b +#define BMIC_LAST_FAILURE_NOT_READY 0x0c +#define BMIC_LAST_FAILURE_HARDWARE_ERROR 0x0d +#define BMIC_LAST_FAILURE_ABORTED_COMMAND 0x0e +#define BMIC_LAST_FAILURE_WRITE_PROTECTED 0x0f +#define BMIC_LAST_FAILURE_SPIN_UP_FAILURE_IN_RECOVER 0x10 +#define BMIC_LAST_FAILURE_REBUILD_WRITE_ERROR 0x11 +#define BMIC_LAST_FAILURE_TOO_SMALL_IN_HOT_PLUG 0x12 +#define BMIC_LAST_FAILURE_BUS_RESET_RECOVERY_ABORTED 0x13 +#define BMIC_LAST_FAILURE_REMOVED_IN_HOT_PLUG 0x14 +#define BMIC_LAST_FAILURE_INIT_REQUEST_SENSE_FAILED 0x15 +#define BMIC_LAST_FAILURE_INIT_START_UNIT_FAILED 0x16 +#define BMIC_LAST_FAILURE_INQUIRY_FAILED 0x17 +#define BMIC_LAST_FAILURE_NON_DISK_DEVICE 0x18 +#define BMIC_LAST_FAILURE_READ_CAPACITY_FAILED 0x19 +#define BMIC_LAST_FAILURE_INVALID_BLOCK_SIZE 0x1a +#define BMIC_LAST_FAILURE_HOT_PLUG_REQUEST_SENSE_FAILED 0x1b +#define BMIC_LAST_FAILURE_HOT_PLUG_START_UNIT_FAILED 0x1c +#define BMIC_LAST_FAILURE_WRITE_ERROR_AFTER_REMAP 0x1d +#define BMIC_LAST_FAILURE_INIT_RESET_RECOVERY_ABORTED 0x1e +#define BMIC_LAST_FAILURE_DEFERRED_WRITE_ERROR 0x1f +#define BMIC_LAST_FAILURE_MISSING_IN_SAVE_RIS 0x20 +#define BMIC_LAST_FAILURE_WRONG_REPLACE 0x21 +#define BMIC_LAST_FAILURE_GDP_VPD_INQUIRY_FAILED 0x22 +#define BMIC_LAST_FAILURE_GDP_MODE_SENSE_FAILED 0x23 +#define BMIC_LAST_FAILURE_DRIVE_NOT_IN_48BIT_MODE 0x24 +#define BMIC_LAST_FAILURE_DRIVE_TYPE_MIX_IN_HOT_PLUG 0x25 +#define BMIC_LAST_FAILURE_DRIVE_TYPE_MIX_IN_LOAD_CFG 0x26 +#define BMIC_LAST_FAILURE_PROTOCOL_ADAPTER_FAILED 0x27 +#define BMIC_LAST_FAILURE_FAULTY_ID_BAY_EMPTY 0x28 +#define BMIC_LAST_FAILURE_FAULTY_ID_BAY_OCCUPIED 0x29 +#define BMIC_LAST_FAILURE_FAULTY_ID_INVALID_BAY 0x2a +#define BMIC_LAST_FAILURE_WRITE_RETRIES_FAILED 0x2b + +#define BMIC_LAST_FAILURE_SMART_ERROR_REPORTED 0x37 +#define BMIC_LAST_FAILURE_PHY_RESET_FAILED 0x38 +#define BMIC_LAST_FAILURE_ONLY_ONE_CTLR_CAN_SEE_DRIVE 0x40 +#define BMIC_LAST_FAILURE_KC_VOLUME_FAILED 0x41 +#define BMIC_LAST_FAILURE_UNEXPECTED_REPLACEMENT 0x42 +#define BMIC_LAST_FAILURE_OFFLINE_ERASE 0x80 +#define BMIC_LAST_FAILURE_OFFLINE_TOO_SMALL 0x81 +#define BMIC_LAST_FAILURE_OFFLINE_DRIVE_TYPE_MIX 0x82 +#define BMIC_LAST_FAILURE_OFFLINE_ERASE_COMPLETE 0x83 + + u8 flags; + u8 more_flags; + u8 scsi_lun; /* SCSI LUN for phys drive */ + u8 yet_more_flags; + u8 even_more_flags; + __le32 spi_speed_rules;/* SPI Speed data:Ultra disable diagnose */ + u8 phys_connector[2]; /* connector number on controller */ + u8 phys_box_on_bus; /* phys enclosure this drive resides */ + u8 phys_bay_in_box; /* phys drv bay this drive resides */ + __le32 rpm; /* Drive rotational speed in rpm */ + u8 device_type; /* type of drive */ + u8 sata_version; /* only valid when drive_type is SATA */ + __le64 big_total_block_count; + __le64 ris_starting_lba; + __le32 ris_size; + u8 wwid[20]; + u8 controller_phy_map[32]; + __le16 phy_count; + u8 phy_connected_dev_type[256]; + u8 phy_to_drive_bay_num[256]; + __le16 phy_to_attached_dev_index[256]; + u8 box_index; + u8 reserved; + __le16 extra_physical_drive_flags; +#define BMIC_PHYS_DRIVE_SUPPORTS_GAS_GAUGE(idphydrv) \ + (idphydrv->extra_physical_drive_flags & (1 << 10)) + u8 negotiated_link_rate[256]; + u8 phy_to_phy_map[256]; + u8 redundant_path_present_map; + u8 redundant_path_failure_map; + u8 active_path_number; + __le16 alternate_paths_phys_connector[8]; + u8 alternate_paths_phys_box_on_port[8]; + u8 multi_lun_device_lun_count; + u8 minimum_good_fw_revision[8]; + u8 unique_inquiry_bytes[20]; + u8 current_temperature_degreesC; + u8 temperature_threshold_degreesC; + u8 max_temperature_degreesC; + u8 logical_blocks_per_phys_block_exp; /* phyblocksize = 512*2^exp */ + __le16 current_queue_depth_limit; + u8 switch_name[10]; + __le16 switch_port; + u8 alternate_paths_switch_name[40]; + u8 alternate_paths_switch_port[8]; + __le16 power_on_hours; /* valid only if gas gauge supported */ + __le16 percent_endurance_used; /* valid only if gas gauge supported. */ +#define BMIC_PHYS_DRIVE_SSD_WEAROUT(idphydrv) \ + ((idphydrv->percent_endurance_used & 0x80) || \ + (idphydrv->percent_endurance_used > 10000)) + u8 drive_authentication; +#define BMIC_PHYS_DRIVE_AUTHENTICATED(idphydrv) \ + (idphydrv->drive_authentication == 0x80) + u8 smart_carrier_authentication; +#define BMIC_SMART_CARRIER_AUTHENTICATION_SUPPORTED(idphydrv) \ + (idphydrv->smart_carrier_authentication != 0x0) +#define BMIC_SMART_CARRIER_AUTHENTICATED(idphydrv) \ + (idphydrv->smart_carrier_authentication == 0x01) + u8 smart_carrier_app_fw_version; + u8 smart_carrier_bootloader_fw_version; + u8 encryption_key_name[64]; + __le32 misc_drive_flags; + __le16 dek_index; + u8 padding[112]; +}; + #pragma pack() #endif /* HPSA_CMD_H */ diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c index ddf0694d87f0..3882d9f519c8 100644 --- a/drivers/scsi/in2000.c +++ b/drivers/scsi/in2000.c @@ -2226,36 +2226,36 @@ static int in2000_show_info(struct seq_file *m, struct Scsi_Host *instance) if (hd->proc & PR_INFO) { seq_printf(m, "\ndip_switch=%02x: irq=%d io=%02x floppy=%s sync/DOS5=%s", (hd->dip_switch & 0x7f), instance->irq, hd->io_base, (hd->dip_switch & 0x40) ? "Yes" : "No", (hd->dip_switch & 0x20) ? "Yes" : "No"); - seq_printf(m, "\nsync_xfer[] = "); + seq_puts(m, "\nsync_xfer[] = "); for (x = 0; x < 7; x++) seq_printf(m, "\t%02x", hd->sync_xfer[x]); - seq_printf(m, "\nsync_stat[] = "); + seq_puts(m, "\nsync_stat[] = "); for (x = 0; x < 7; x++) seq_printf(m, "\t%02x", hd->sync_stat[x]); } #ifdef PROC_STATISTICS if (hd->proc & PR_STATISTICS) { - seq_printf(m, "\ncommands issued: "); + seq_puts(m, "\ncommands issued: "); for (x = 0; x < 7; x++) seq_printf(m, "\t%ld", hd->cmd_cnt[x]); - seq_printf(m, "\ndisconnects allowed:"); + seq_puts(m, "\ndisconnects allowed:"); for (x = 0; x < 7; x++) seq_printf(m, "\t%ld", hd->disc_allowed_cnt[x]); - seq_printf(m, "\ndisconnects done: "); + seq_puts(m, "\ndisconnects done: "); for (x = 0; x < 7; x++) seq_printf(m, "\t%ld", hd->disc_done_cnt[x]); seq_printf(m, "\ninterrupts: \t%ld", hd->int_cnt); } #endif if (hd->proc & PR_CONNECTED) { - seq_printf(m, "\nconnected: "); + seq_puts(m, "\nconnected: "); if (hd->connected) { cmd = (Scsi_Cmnd *) hd->connected; seq_printf(m, " %d:%llu(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]); } } if (hd->proc & PR_INPUTQ) { - seq_printf(m, "\ninput_Q: "); + seq_puts(m, "\ninput_Q: "); cmd = (Scsi_Cmnd *) hd->input_Q; while (cmd) { seq_printf(m, " %d:%llu(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]); @@ -2263,7 +2263,7 @@ static int in2000_show_info(struct seq_file *m, struct Scsi_Host *instance) } } if (hd->proc & PR_DISCQ) { - seq_printf(m, "\ndisconnected_Q:"); + seq_puts(m, "\ndisconnected_Q:"); cmd = (Scsi_Cmnd *) hd->disconnected_Q; while (cmd) { seq_printf(m, " %d:%llu(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]); @@ -2273,7 +2273,7 @@ static int in2000_show_info(struct seq_file *m, struct Scsi_Host *instance) if (hd->proc & PR_TEST) { ; /* insert your own custom function here */ } - seq_printf(m, "\n"); + seq_putc(m, '\n'); spin_unlock_irqrestore(instance->host_lock, flags); #endif /* PROC_INTERFACE */ return 0; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index df4e27cd996a..9219953ee949 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -683,6 +683,7 @@ static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd, ipr_reinit_ipr_cmnd(ipr_cmd); ipr_cmd->u.scratch = 0; ipr_cmd->sibling = NULL; + ipr_cmd->eh_comp = NULL; ipr_cmd->fast_done = fast_done; init_timer(&ipr_cmd->timer); } @@ -848,6 +849,8 @@ static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd) scsi_dma_unmap(ipr_cmd->scsi_cmd); scsi_cmd->scsi_done(scsi_cmd); + if (ipr_cmd->eh_comp) + complete(ipr_cmd->eh_comp); list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); } @@ -4811,6 +4814,84 @@ static int ipr_slave_alloc(struct scsi_device *sdev) return rc; } +/** + * ipr_match_lun - Match function for specified LUN + * @ipr_cmd: ipr command struct + * @device: device to match (sdev) + * + * Returns: + * 1 if command matches sdev / 0 if command does not match sdev + **/ +static int ipr_match_lun(struct ipr_cmnd *ipr_cmd, void *device) +{ + if (ipr_cmd->scsi_cmd && ipr_cmd->scsi_cmd->device == device) + return 1; + return 0; +} + +/** + * ipr_wait_for_ops - Wait for matching commands to complete + * @ipr_cmd: ipr command struct + * @device: device to match (sdev) + * @match: match function to use + * + * Returns: + * SUCCESS / FAILED + **/ +static int ipr_wait_for_ops(struct ipr_ioa_cfg *ioa_cfg, void *device, + int (*match)(struct ipr_cmnd *, void *)) +{ + struct ipr_cmnd *ipr_cmd; + int wait; + unsigned long flags; + struct ipr_hrr_queue *hrrq; + signed long timeout = IPR_ABORT_TASK_TIMEOUT; + DECLARE_COMPLETION_ONSTACK(comp); + + ENTER; + do { + wait = 0; + + for_each_hrrq(hrrq, ioa_cfg) { + spin_lock_irqsave(hrrq->lock, flags); + list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) { + if (match(ipr_cmd, device)) { + ipr_cmd->eh_comp = ∁ + wait++; + } + } + spin_unlock_irqrestore(hrrq->lock, flags); + } + + if (wait) { + timeout = wait_for_completion_timeout(&comp, timeout); + + if (!timeout) { + wait = 0; + + for_each_hrrq(hrrq, ioa_cfg) { + spin_lock_irqsave(hrrq->lock, flags); + list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) { + if (match(ipr_cmd, device)) { + ipr_cmd->eh_comp = NULL; + wait++; + } + } + spin_unlock_irqrestore(hrrq->lock, flags); + } + + if (wait) + dev_err(&ioa_cfg->pdev->dev, "Timed out waiting for aborted commands\n"); + LEAVE; + return wait ? FAILED : SUCCESS; + } + } + } while (wait); + + LEAVE; + return SUCCESS; +} + static int ipr_eh_host_reset(struct scsi_cmnd *cmd) { struct ipr_ioa_cfg *ioa_cfg; @@ -5030,11 +5111,17 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd) static int ipr_eh_dev_reset(struct scsi_cmnd *cmd) { int rc; + struct ipr_ioa_cfg *ioa_cfg; + + ioa_cfg = (struct ipr_ioa_cfg *) cmd->device->host->hostdata; spin_lock_irq(cmd->device->host->host_lock); rc = __ipr_eh_dev_reset(cmd); spin_unlock_irq(cmd->device->host->host_lock); + if (rc == SUCCESS) + rc = ipr_wait_for_ops(ioa_cfg, cmd->device, ipr_match_lun); + return rc; } @@ -5234,13 +5321,18 @@ static int ipr_eh_abort(struct scsi_cmnd *scsi_cmd) { unsigned long flags; int rc; + struct ipr_ioa_cfg *ioa_cfg; ENTER; + ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; + spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags); rc = ipr_cancel_op(scsi_cmd); spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags); + if (rc == SUCCESS) + rc = ipr_wait_for_ops(ioa_cfg, scsi_cmd->device, ipr_match_lun); LEAVE; return rc; } diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index b4f3eec51bc9..ec03b42fa2b9 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1606,6 +1606,7 @@ struct ipr_cmnd { struct scsi_device *sdev; } u; + struct completion *eh_comp; struct ipr_hrr_queue *hrrq; struct ipr_ioa_cfg *ioa_cfg; }; diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index e5c28435d768..7542f11d3fcd 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -2038,15 +2038,14 @@ ips_host_info(ips_ha_t *ha, struct seq_file *m) { METHOD_TRACE("ips_host_info", 1); - seq_printf(m, "\nIBM ServeRAID General Information:\n\n"); + seq_puts(m, "\nIBM ServeRAID General Information:\n\n"); if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) && (le16_to_cpu(ha->nvram->adapter_type) != 0)) seq_printf(m, "\tController Type : %s\n", ips_adapter_name[ha->ad_type - 1]); else - seq_printf(m, - "\tController Type : Unknown\n"); + seq_puts(m, "\tController Type : Unknown\n"); if (ha->io_addr) seq_printf(m, @@ -2138,7 +2137,7 @@ ips_host_info(ips_ha_t *ha, struct seq_file *m) seq_printf(m, "\tCurrent Active PT Commands : %d\n", ha->num_ioctl); - seq_printf(m, "\n"); + seq_putc(m, '\n'); return 0; } diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 4c25485aa934..c66088d0fd2a 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2225,6 +2225,15 @@ lpfc_adisc_done(struct lpfc_vport *vport) if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && !(vport->fc_flag & FC_RSCN_MODE) && (phba->sli_rev < LPFC_SLI_REV4)) { + /* The ADISCs are complete. Doesn't matter if they + * succeeded or failed because the ADISC completion + * routine guarantees to call the state machine and + * the RPI is either unregistered (failed ADISC response) + * or the RPI is still valid and the node is marked + * mapped for a target. The exchanges should be in the + * correct state. This code is specific to SLI3. + */ + lpfc_issue_clear_la(phba, vport); lpfc_issue_reg_vpi(phba, vport); return; } diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 2485255f3414..bc7b34c02723 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -2240,7 +2240,7 @@ proc_show_battery(struct seq_file *m, void *v) goto free_pdev; if( mega_adapinq(adapter, dma_handle) != 0 ) { - seq_printf(m, "Adapter inquiry failed.\n"); + seq_puts(m, "Adapter inquiry failed.\n"); printk(KERN_WARNING "megaraid: inquiry failed.\n"); goto free_inquiry; } diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 0d44d91c2fce..14e5c7cea929 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -35,7 +35,7 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "06.805.06.01-rc1" +#define MEGASAS_VERSION "06.806.08.00-rc1" /* * Device IDs @@ -969,7 +969,20 @@ struct megasas_ctrl_info { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved:25; + u32 reserved:12; + u32 discardCacheDuringLDDelete:1; + u32 supportSecurityonJBOD:1; + u32 supportCacheBypassModes:1; + u32 supportDisableSESMonitoring:1; + u32 supportForceFlash:1; + u32 supportNVDRAM:1; + u32 supportDrvActivityLEDSetting:1; + u32 supportAllowedOpsforDrvRemoval:1; + u32 supportHOQRebuild:1; + u32 supportForceTo512e:1; + u32 supportNVCacheErase:1; + u32 supportDebugQueue:1; + u32 supportSwZone:1; u32 supportCrashDump:1; u32 supportMaxExtLDs:1; u32 supportT10RebuildAssist:1; @@ -981,9 +994,22 @@ struct megasas_ctrl_info { u32 supportThermalPollInterval:1; u32 supportDisableImmediateIO:1; u32 supportT10RebuildAssist:1; - u32 supportMaxExtLDs:1; - u32 supportCrashDump:1; - u32 reserved:25; + u32 supportMaxExtLDs:1; + u32 supportCrashDump:1; + u32 supportSwZone:1; + u32 supportDebugQueue:1; + u32 supportNVCacheErase:1; + u32 supportForceTo512e:1; + u32 supportHOQRebuild:1; + u32 supportAllowedOpsforDrvRemoval:1; + u32 supportDrvActivityLEDSetting:1; + u32 supportNVDRAM:1; + u32 supportForceFlash:1; + u32 supportDisableSESMonitoring:1; + u32 supportCacheBypassModes:1; + u32 supportSecurityonJBOD:1; + u32 discardCacheDuringLDDelete:1; + u32 reserved:12; #endif } adapterOperations3; @@ -1022,6 +1048,13 @@ enum MR_MFI_MPT_PTHR_FLAGS { MFI_MPT_ATTACHED = 2, }; +enum MR_SCSI_CMD_TYPE { + READ_WRITE_LDIO = 0, + NON_READ_WRITE_LDIO = 1, + READ_WRITE_SYSPDIO = 2, + NON_READ_WRITE_SYSPDIO = 3, +}; + /* Frame Type */ #define IO_FRAME 0 #define PTHRU_FRAME 1 @@ -1049,6 +1082,8 @@ enum MR_MFI_MPT_PTHR_FLAGS { */ #define MEGASAS_INT_CMDS 32 #define MEGASAS_SKINNY_INT_CMDS 5 +#define MEGASAS_FUSION_INTERNAL_CMDS 5 +#define MEGASAS_FUSION_IOCTL_CMDS 3 #define MEGASAS_MAX_MSIX_QUEUES 128 /* @@ -1194,19 +1229,23 @@ union megasas_sgl_frame { typedef union _MFI_CAPABILITIES { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved:27; + u32 reserved:25; + u32 security_protocol_cmds_fw:1; + u32 support_core_affinity:1; u32 support_ndrive_r1_lb:1; u32 support_max_255lds:1; - u32 reserved1:1; + u32 support_fastpath_wb:1; u32 support_additional_msix:1; u32 support_fp_remote_lun:1; #else u32 support_fp_remote_lun:1; u32 support_additional_msix:1; - u32 reserved1:1; + u32 support_fastpath_wb:1; u32 support_max_255lds:1; u32 support_ndrive_r1_lb:1; - u32 reserved:27; + u32 support_core_affinity:1; + u32 security_protocol_cmds_fw:1; + u32 reserved:25; #endif } mfi_capabilities; u32 reg; @@ -1638,20 +1677,20 @@ struct megasas_instance { u32 crash_dump_fw_support; u32 crash_dump_drv_support; u32 crash_dump_app_support; + u32 secure_jbod_support; spinlock_t crashdump_lock; struct megasas_register_set __iomem *reg_set; u32 *reply_post_host_index_addr[MR_MAX_MSIX_REG_ARRAY]; struct megasas_pd_list pd_list[MEGASAS_MAX_PD]; struct megasas_pd_list local_pd_list[MEGASAS_MAX_PD]; - u8 ld_ids[MEGASAS_MAX_LD_IDS]; + u8 ld_ids[MEGASAS_MAX_LD_IDS]; s8 init_id; u16 max_num_sge; u16 max_fw_cmds; - /* For Fusion its num IOCTL cmds, for others MFI based its - max_fw_cmds */ u16 max_mfi_cmds; + u16 max_scsi_cmds; u32 max_sectors_per_req; struct megasas_aen_event *ev; @@ -1727,7 +1766,7 @@ struct megasas_instance { u8 requestorId; char PlasmaFW111; char mpio; - int throttlequeuedepth; + u16 throttlequeuedepth; u8 mask_interrupts; u8 is_imr; }; @@ -1946,5 +1985,6 @@ void __megasas_return_cmd(struct megasas_instance *instance, void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance, struct megasas_cmd *cmd_mfi, struct megasas_cmd_fusion *cmd_fusion); +int megasas_cmd_type(struct scsi_cmnd *cmd); #endif /*LSI_MEGARAID_SAS_H */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index ff283d23788a..890637fdd61e 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -78,7 +78,7 @@ static int allow_vf_ioctls; module_param(allow_vf_ioctls, int, S_IRUGO); MODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0"); -static int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH; +static unsigned int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH; module_param(throttlequeuedepth, int, S_IRUGO); MODULE_PARM_DESC(throttlequeuedepth, "Adapter queue depth when throttled due to I/O timeout. Default: 16"); @@ -1417,16 +1417,15 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp, } /** - * megasas_is_ldio - Checks if the cmd is for logical drive + * megasas_cmd_type - Checks if the cmd is for logical drive/sysPD + * and whether it's RW or non RW * @scmd: SCSI command * - * Called by megasas_queue_command to find out if the command to be queued - * is a logical drive command */ -inline int megasas_is_ldio(struct scsi_cmnd *cmd) +inline int megasas_cmd_type(struct scsi_cmnd *cmd) { - if (!MEGASAS_IS_LOGICAL(cmd)) - return 0; + int ret; + switch (cmd->cmnd[0]) { case READ_10: case WRITE_10: @@ -1436,10 +1435,14 @@ inline int megasas_is_ldio(struct scsi_cmnd *cmd) case WRITE_6: case READ_16: case WRITE_16: - return 1; + ret = (MEGASAS_IS_LOGICAL(cmd)) ? + READ_WRITE_LDIO : READ_WRITE_SYSPDIO; + break; default: - return 0; + ret = (MEGASAS_IS_LOGICAL(cmd)) ? + NON_READ_WRITE_LDIO : NON_READ_WRITE_SYSPDIO; } + return ret; } /** @@ -1471,7 +1474,7 @@ megasas_dump_pending_frames(struct megasas_instance *instance) if(!cmd->scmd) continue; printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr); - if (megasas_is_ldio(cmd->scmd)){ + if (megasas_cmd_type(cmd->scmd) == READ_WRITE_LDIO) { ldio = (struct megasas_io_frame *)cmd->frame; mfi_sgl = &ldio->sgl; sgcount = ldio->sge_count; @@ -1531,7 +1534,7 @@ megasas_build_and_issue_cmd(struct megasas_instance *instance, /* * Logical drive command */ - if (megasas_is_ldio(scmd)) + if (megasas_cmd_type(scmd) == READ_WRITE_LDIO) frame_count = megasas_build_ldio(instance, scmd, cmd); else frame_count = megasas_build_dcdb(instance, scmd, cmd); @@ -1689,22 +1692,66 @@ static int megasas_slave_alloc(struct scsi_device *sdev) return 0; } +/* +* megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a +* kill adapter +* @instance: Adapter soft state +* +*/ +void megasas_complete_outstanding_ioctls(struct megasas_instance *instance) +{ + int i; + struct megasas_cmd *cmd_mfi; + struct megasas_cmd_fusion *cmd_fusion; + struct fusion_context *fusion = instance->ctrl_context; + + /* Find all outstanding ioctls */ + if (fusion) { + for (i = 0; i < instance->max_fw_cmds; i++) { + cmd_fusion = fusion->cmd_list[i]; + if (cmd_fusion->sync_cmd_idx != (u32)ULONG_MAX) { + cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx]; + if (cmd_mfi->sync_cmd && + cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT) + megasas_complete_cmd(instance, + cmd_mfi, DID_OK); + } + } + } else { + for (i = 0; i < instance->max_fw_cmds; i++) { + cmd_mfi = instance->cmd_list[i]; + if (cmd_mfi->sync_cmd && cmd_mfi->frame->hdr.cmd != + MFI_CMD_ABORT) + megasas_complete_cmd(instance, cmd_mfi, DID_OK); + } + } +} + + void megaraid_sas_kill_hba(struct megasas_instance *instance) { + /* Set critical error to block I/O & ioctls in case caller didn't */ + instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; + /* Wait 1 second to ensure IO or ioctls in build have posted */ + msleep(1000); if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { - writel(MFI_STOP_ADP, &instance->reg_set->doorbell); + (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + writel(MFI_STOP_ADP, + &instance->reg_set->doorbell); /* Flush */ readl(&instance->reg_set->doorbell); if (instance->mpio && instance->requestorId) memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); } else { - writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell); + writel(MFI_STOP_ADP, + &instance->reg_set->inbound_doorbell); } + /* Complete outstanding ioctls when adapter is killed */ + megasas_complete_outstanding_ioctls(instance); } /** @@ -1717,6 +1764,7 @@ void megasas_check_and_restore_queue_depth(struct megasas_instance *instance) { unsigned long flags; + if (instance->flag & MEGASAS_FW_BUSY && time_after(jiffies, instance->last_time + 5 * HZ) && atomic_read(&instance->fw_outstanding) < @@ -1724,13 +1772,8 @@ megasas_check_and_restore_queue_depth(struct megasas_instance *instance) spin_lock_irqsave(instance->host->host_lock, flags); instance->flag &= ~MEGASAS_FW_BUSY; - if (instance->is_imr) { - instance->host->can_queue = - instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS; - } else - instance->host->can_queue = - instance->max_fw_cmds - MEGASAS_INT_CMDS; + instance->host->can_queue = instance->max_scsi_cmds; spin_unlock_irqrestore(instance->host->host_lock, flags); } } @@ -3028,10 +3071,9 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance) "was tried multiple times during reset." "Shutting down the HBA\n", cmd, cmd->scmd, cmd->sync_cmd); + instance->instancet->disable_intr(instance); + atomic_set(&instance->fw_reset_no_pci_access, 1); megaraid_sas_kill_hba(instance); - - instance->adprecovery = - MEGASAS_HW_CRITICAL_ERROR; return; } } @@ -3165,8 +3207,8 @@ process_fw_state_change_wq(struct work_struct *work) if (megasas_transition_to_ready(instance, 1)) { printk(KERN_NOTICE "megaraid_sas:adapter not ready\n"); + atomic_set(&instance->fw_reset_no_pci_access, 1); megaraid_sas_kill_hba(instance); - instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; return ; } @@ -3547,7 +3589,6 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) int i; u32 max_cmd; u32 sge_sz; - u32 sgl_sz; u32 total_sz; u32 frame_count; struct megasas_cmd *cmd; @@ -3566,24 +3607,23 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) } /* - * Calculated the number of 64byte frames required for SGL + * For MFI controllers. + * max_num_sge = 60 + * max_sge_sz = 16 byte (sizeof megasas_sge_skinny) + * Total 960 byte (15 MFI frame of 64 byte) + * + * Fusion adapter require only 3 extra frame. + * max_num_sge = 16 (defined as MAX_IOCTL_SGE) + * max_sge_sz = 12 byte (sizeof megasas_sge64) + * Total 192 byte (3 MFI frame of 64 byte) */ - sgl_sz = sge_sz * instance->max_num_sge; - frame_count = (sgl_sz + MEGAMFI_FRAME_SIZE - 1) / MEGAMFI_FRAME_SIZE; - frame_count = 15; - - /* - * We need one extra frame for the MFI command - */ - frame_count++; - + frame_count = instance->ctrl_context ? (3 + 1) : (15 + 1); total_sz = MEGAMFI_FRAME_SIZE * frame_count; /* * Use DMA pool facility provided by PCI layer */ instance->frame_dma_pool = pci_pool_create("megasas frame pool", - instance->pdev, total_sz, 64, - 0); + instance->pdev, total_sz, 256, 0); if (!instance->frame_dma_pool) { printk(KERN_DEBUG "megasas: failed to setup frame pool\n"); @@ -4631,28 +4671,48 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->crash_dump_h); instance->crash_dump_buf = NULL; } + + instance->secure_jbod_support = + ctrl_info->adapterOperations3.supportSecurityonJBOD; + if (instance->secure_jbod_support) + dev_info(&instance->pdev->dev, "Firmware supports Secure JBOD\n"); instance->max_sectors_per_req = instance->max_num_sge * PAGE_SIZE / 512; if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors)) instance->max_sectors_per_req = tmp_sectors; - /* Check for valid throttlequeuedepth module parameter */ - if (instance->is_imr) { - if (throttlequeuedepth > (instance->max_fw_cmds - - MEGASAS_SKINNY_INT_CMDS)) - instance->throttlequeuedepth = - MEGASAS_THROTTLE_QUEUE_DEPTH; - else - instance->throttlequeuedepth = throttlequeuedepth; + /* + * 1. For fusion adapters, 3 commands for IOCTL and 5 commands + * for driver's internal DCMDs. + * 2. For MFI skinny adapters, 5 commands for IOCTL + driver's + * internal DCMDs. + * 3. For rest of MFI adapters, 27 commands reserved for IOCTLs + * and 5 commands for drivers's internal DCMD. + */ + if (instance->ctrl_context) { + instance->max_scsi_cmds = instance->max_fw_cmds - + (MEGASAS_FUSION_INTERNAL_CMDS + + MEGASAS_FUSION_IOCTL_CMDS); + sema_init(&instance->ioctl_sem, MEGASAS_FUSION_IOCTL_CMDS); + } else if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { + instance->max_scsi_cmds = instance->max_fw_cmds - + MEGASAS_SKINNY_INT_CMDS; + sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS); } else { - if (throttlequeuedepth > (instance->max_fw_cmds - - MEGASAS_INT_CMDS)) - instance->throttlequeuedepth = - MEGASAS_THROTTLE_QUEUE_DEPTH; - else - instance->throttlequeuedepth = throttlequeuedepth; + instance->max_scsi_cmds = instance->max_fw_cmds - + MEGASAS_INT_CMDS; + sema_init(&instance->ioctl_sem, (MEGASAS_INT_CMDS - 5)); } + /* Check for valid throttlequeuedepth module parameter */ + if (throttlequeuedepth && + throttlequeuedepth <= instance->max_scsi_cmds) + instance->throttlequeuedepth = throttlequeuedepth; + else + instance->throttlequeuedepth = + MEGASAS_THROTTLE_QUEUE_DEPTH; + /* * Setup tasklet for cmd completion */ @@ -4947,12 +5007,7 @@ static int megasas_io_attach(struct megasas_instance *instance) */ host->irq = instance->pdev->irq; host->unique_id = instance->unique_id; - if (instance->is_imr) { - host->can_queue = - instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS; - } else - host->can_queue = - instance->max_fw_cmds - MEGASAS_INT_CMDS; + host->can_queue = instance->max_scsi_cmds; host->this_id = instance->init_id; host->sg_tablesize = instance->max_num_sge; @@ -5130,8 +5185,6 @@ static int megasas_probe_one(struct pci_dev *pdev, ((1 << PAGE_SHIFT) << instance->ctrl_context_pages)); INIT_LIST_HEAD(&fusion->cmd_pool); spin_lock_init(&fusion->mpt_pool_lock); - memset(fusion->load_balance_info, 0, - sizeof(struct LD_LOAD_BALANCE_INFO) * MAX_LOGICAL_DRIVES_EXT); } break; default: /* For all other supported controllers */ @@ -5215,12 +5268,10 @@ static int megasas_probe_one(struct pci_dev *pdev, instance->init_id = MEGASAS_DEFAULT_INIT_ID; instance->ctrl_info = NULL; + if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { + (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) instance->flag_ieee = 1; - sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS); - } else - sema_init(&instance->ioctl_sem, (MEGASAS_INT_CMDS - 5)); megasas_dbg_lvl = 0; instance->flag = 0; @@ -6215,9 +6266,6 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) goto out_kfree_ioc; } - /* - * We will allow only MEGASAS_INT_CMDS number of parallel ioctl cmds - */ if (down_interruptible(&instance->ioctl_sem)) { error = -ERESTARTSYS; goto out_kfree_ioc; diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index 460c6a3d4ade..4f72287860ee 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -172,6 +172,7 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) struct MR_FW_RAID_MAP_ALL *fw_map_old = NULL; struct MR_FW_RAID_MAP *pFwRaidMap = NULL; int i; + u16 ld_count; struct MR_DRV_RAID_MAP_ALL *drv_map = @@ -191,9 +192,10 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) fw_map_old = (struct MR_FW_RAID_MAP_ALL *) fusion->ld_map[(instance->map_id & 1)]; pFwRaidMap = &fw_map_old->raidMap; + ld_count = (u16)le32_to_cpu(pFwRaidMap->ldCount); #if VD_EXT_DEBUG - for (i = 0; i < le16_to_cpu(pFwRaidMap->ldCount); i++) { + for (i = 0; i < ld_count; i++) { dev_dbg(&instance->pdev->dev, "(%d) :Index 0x%x " "Target Id 0x%x Seq Num 0x%x Size 0/%llx\n", instance->unique_id, i, @@ -205,12 +207,15 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) memset(drv_map, 0, fusion->drv_map_sz); pDrvRaidMap->totalSize = pFwRaidMap->totalSize; - pDrvRaidMap->ldCount = (__le16)pFwRaidMap->ldCount; + pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); pDrvRaidMap->fpPdIoTimeoutSec = pFwRaidMap->fpPdIoTimeoutSec; for (i = 0; i < MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS; i++) pDrvRaidMap->ldTgtIdToLd[i] = (u8)pFwRaidMap->ldTgtIdToLd[i]; - for (i = 0; i < le16_to_cpu(pDrvRaidMap->ldCount); i++) { + for (i = (MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS); + i < MAX_LOGICAL_DRIVES_EXT; i++) + pDrvRaidMap->ldTgtIdToLd[i] = 0xff; + for (i = 0; i < ld_count; i++) { pDrvRaidMap->ldSpanMap[i] = pFwRaidMap->ldSpanMap[i]; #if VD_EXT_DEBUG dev_dbg(&instance->pdev->dev, @@ -252,7 +257,7 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance) struct LD_LOAD_BALANCE_INFO *lbInfo; PLD_SPAN_INFO ldSpanInfo; struct MR_LD_RAID *raid; - int ldCount, num_lds; + u16 ldCount, num_lds; u16 ld; u32 expected_size; @@ -356,7 +361,7 @@ static int getSpanInfo(struct MR_DRV_RAID_MAP_ALL *map, for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) { ld = MR_TargetIdToLdGet(ldCount, map); - if (ld >= MAX_LOGICAL_DRIVES_EXT) + if (ld >= (MAX_LOGICAL_DRIVES_EXT - 1)) continue; raid = MR_LdRaidGet(ld, map); dev_dbg(&instance->pdev->dev, "LD %x: span_depth=%x\n", @@ -1157,7 +1162,7 @@ void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map, for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) { ld = MR_TargetIdToLdGet(ldCount, map); - if (ld >= MAX_LOGICAL_DRIVES_EXT) + if (ld >= (MAX_LOGICAL_DRIVES_EXT - 1)) continue; raid = MR_LdRaidGet(ld, map); for (element = 0; element < MAX_QUAD_DEPTH; element++) { diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 71557f64bb5e..675b5e7aba94 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -63,7 +63,6 @@ extern struct megasas_cmd *megasas_get_cmd(struct megasas_instance extern void megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, u8 alt_status); -int megasas_is_ldio(struct scsi_cmnd *cmd); int wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd, int seconds); @@ -103,6 +102,8 @@ megasas_enable_intr_fusion(struct megasas_instance *instance) { struct megasas_register_set __iomem *regs; regs = instance->reg_set; + + instance->mask_interrupts = 0; /* For Thunderbolt/Invader also clear intr on enable */ writel(~0, ®s->outbound_intr_status); readl(®s->outbound_intr_status); @@ -111,7 +112,6 @@ megasas_enable_intr_fusion(struct megasas_instance *instance) /* Dummy readl to force pci flush */ readl(®s->outbound_intr_mask); - instance->mask_interrupts = 0; } /** @@ -196,6 +196,7 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance, cmd->scmd = NULL; cmd->sync_cmd_idx = (u32)ULONG_MAX; + memset(cmd->io_request, 0, sizeof(struct MPI2_RAID_SCSI_IO_REQUEST)); list_add(&cmd->list, (&fusion->cmd_pool)->next); spin_unlock_irqrestore(&fusion->mpt_pool_lock, flags); @@ -689,6 +690,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) = 1; init_frame->driver_operations.mfi_capabilities.support_ndrive_r1_lb = 1; + init_frame->driver_operations.mfi_capabilities.security_protocol_cmds_fw + = 1; /* Convert capability to LE32 */ cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities); @@ -698,12 +701,11 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) cpu_to_le32(lower_32_bits(ioc_init_handle)); init_frame->data_xfer_len = cpu_to_le32(sizeof(struct MPI2_IOC_INIT_REQUEST)); - req_desc.Words = 0; + req_desc.u.low = cpu_to_le32(lower_32_bits(cmd->frame_phys_addr)); + req_desc.u.high = cpu_to_le32(upper_32_bits(cmd->frame_phys_addr)); req_desc.MFAIo.RequestFlags = (MEGASAS_REQ_DESCRIPT_FLAGS_MFA << - MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - cpu_to_le32s((u32 *)&req_desc.MFAIo); - req_desc.Words |= cpu_to_le64(cmd->frame_phys_addr); + MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); /* * disable the intr before firing the init frame @@ -1017,8 +1019,12 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) * does not exceed max cmds that the FW can support */ instance->max_fw_cmds = instance->max_fw_cmds-1; - /* Only internal cmds (DCMD) need to have MFI frames */ - instance->max_mfi_cmds = MEGASAS_INT_CMDS; + + /* + * Only Driver's internal DCMDs and IOCTL DCMDs needs to have MFI frames + */ + instance->max_mfi_cmds = + MEGASAS_FUSION_INTERNAL_CMDS + MEGASAS_FUSION_IOCTL_CMDS; max_cmd = instance->max_fw_cmds; @@ -1285,6 +1291,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, sgl_ptr = (struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame; + memset(sgl_ptr, 0, MEGASAS_MAX_SZ_CHAIN_FRAME); } } @@ -1658,6 +1665,8 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance, u32 device_id; struct MPI2_RAID_SCSI_IO_REQUEST *io_request; u16 pd_index = 0; + u16 os_timeout_value; + u16 timeout_limit; struct MR_DRV_RAID_MAP_ALL *local_map_ptr; struct fusion_context *fusion = instance->ctrl_context; u8 span, physArm; @@ -1674,52 +1683,66 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance, io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); - - /* Check if this is a system PD I/O */ if (scmd->device->channel < MEGASAS_MAX_PD_CHANNELS && instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) { - io_request->Function = 0; if (fusion->fast_path_io) io_request->DevHandle = local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; - io_request->RaidContext.timeoutValue = - local_map_ptr->raidMap.fpPdIoTimeoutSec; - io_request->RaidContext.regLockFlags = 0; - io_request->RaidContext.regLockRowLBA = 0; - io_request->RaidContext.regLockLength = 0; io_request->RaidContext.RAIDFlags = - MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD << - MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) - io_request->IoFlags |= cpu_to_le16( - MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); - cmd->request_desc->SCSIIO.RequestFlags = - (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << - MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - cmd->request_desc->SCSIIO.DevHandle = - local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; + MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD + << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; + cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle; cmd->request_desc->SCSIIO.MSIxIndex = instance->msix_vectors ? smp_processor_id() % instance->msix_vectors : 0; - /* - * If the command is for the tape device, set the - * FP timeout to the os layer timeout value. - */ - if (scmd->device->type == TYPE_TAPE) { - if ((scmd->request->timeout / HZ) > 0xFFFF) - io_request->RaidContext.timeoutValue = - 0xFFFF; - else - io_request->RaidContext.timeoutValue = - scmd->request->timeout / HZ; + os_timeout_value = scmd->request->timeout / HZ; + + if (instance->secure_jbod_support && + (megasas_cmd_type(scmd) == NON_READ_WRITE_SYSPDIO)) { + /* system pd firmware path */ + io_request->Function = + MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; + cmd->request_desc->SCSIIO.RequestFlags = + (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << + MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + io_request->RaidContext.timeoutValue = + cpu_to_le16(os_timeout_value); + } else { + /* system pd Fast Path */ + io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; + io_request->RaidContext.regLockFlags = 0; + io_request->RaidContext.regLockRowLBA = 0; + io_request->RaidContext.regLockLength = 0; + timeout_limit = (scmd->device->type == TYPE_DISK) ? + 255 : 0xFFFF; + io_request->RaidContext.timeoutValue = + cpu_to_le16((os_timeout_value > timeout_limit) ? + timeout_limit : os_timeout_value); + if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) + io_request->IoFlags |= + cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); + + cmd->request_desc->SCSIIO.RequestFlags = + (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << + MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); } } else { if (scmd->device->channel < MEGASAS_MAX_PD_CHANNELS) goto NonFastPath; + /* + * For older firmware, Driver should not access ldTgtIdToLd + * beyond index 127 and for Extended VD firmware, ldTgtIdToLd + * should not go beyond 255. + */ + + if ((!fusion->fast_path_io) || + (device_id >= instance->fw_supported_vd_count)) + goto NonFastPath; + ld = MR_TargetIdToLdGet(device_id, local_map_ptr); - if ((ld >= instance->fw_supported_vd_count) || - (!fusion->fast_path_io)) + + if (ld >= instance->fw_supported_vd_count) goto NonFastPath; raid = MR_LdRaidGet(ld, local_map_ptr); @@ -1811,7 +1834,7 @@ megasas_build_io_fusion(struct megasas_instance *instance, */ io_request->IoFlags = cpu_to_le16(scp->cmd_len); - if (megasas_is_ldio(scp)) + if (megasas_cmd_type(scp) == READ_WRITE_LDIO) megasas_build_ldio_fusion(instance, scp, cmd); else megasas_build_dcdb_fusion(instance, scp, cmd); @@ -2612,7 +2635,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) instance->host->host_no); megaraid_sas_kill_hba(instance); instance->skip_heartbeat_timer_del = 1; - instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; retval = FAILED; goto out; } @@ -2808,8 +2830,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) dev_info(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); - instance->adprecovery = - MEGASAS_HW_CRITICAL_ERROR; megaraid_sas_kill_hba(instance); retval = FAILED; } @@ -2858,7 +2878,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) "adapter scsi%d.\n", instance->host->host_no); megaraid_sas_kill_hba(instance); instance->skip_heartbeat_timer_del = 1; - instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; retval = FAILED; } else { /* For VF: Restart HB timer if we didn't OCR */ diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 5ab7daee11be..56e6db2d5874 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -306,14 +306,9 @@ struct MPI2_RAID_SCSI_IO_REQUEST { * MPT RAID MFA IO Descriptor. */ struct MEGASAS_RAID_MFA_IO_REQUEST_DESCRIPTOR { -#if defined(__BIG_ENDIAN_BITFIELD) - u32 MessageAddress1:24; /* bits 31:8*/ u32 RequestFlags:8; -#else - u32 RequestFlags:8; - u32 MessageAddress1:24; /* bits 31:8*/ -#endif - u32 MessageAddress2; /* bits 61:32 */ + u32 MessageAddress1:24; + u32 MessageAddress2; }; /* Default Request Descriptor */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h index 088eefa67da8..7fc6f23bd9dc 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.32 + * mpi2.h Version: 02.00.35 * * Version History * --------------- @@ -83,6 +83,9 @@ * 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT. * 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT. * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT. + * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT. + * 01-08-14 02.00.34 Bumped MPI2_HEADER_VERSION_UNIT. + * 06-13-14 02.00.35 Bumped MPI2_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -108,7 +111,7 @@ #define MPI2_VERSION_02_00 (0x0200) /* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x20) +#define MPI2_HEADER_VERSION_UNIT (0x23) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index 510ef0dc8d7b..ee8d2d695d55 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.26 + * mpi2_cnfg.h Version: 02.00.29 * * Version History * --------------- @@ -157,6 +157,20 @@ * 04-09-13 02.00.25 Added MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK. * Fixed MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS to * match the specification. + * 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for + * MPI2_CONFIG_PAGE_MAN_7. + * Added EnclosureLevel and ConnectorName fields to + * MPI2_CONFIG_PAGE_SAS_DEV_0. + * Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for + * MPI2_CONFIG_PAGE_SAS_DEV_0. + * Added EnclosureLevel field to + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * 01-08-14 02.00.28 Added more defines for the BiosOptions field of + * MPI2_CONFIG_PAGE_BIOS_1. + * 06-13-14 02.00.29 Added SSUTimeout field to MPI2_CONFIG_PAGE_BIOS_1, and + * more defines for the BiosOptions field. * -------------------------------------------------------------------------- */ @@ -706,6 +720,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7 #define MPI2_MANUFACTURING7_PAGEVERSION (0x01) /* defines for the Flags field */ +#define MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL (0x00000008) #define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002) #define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) @@ -1224,7 +1239,9 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1 MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ U32 BiosOptions; /* 0x04 */ U32 IOCSettings; /* 0x08 */ - U32 Reserved1; /* 0x0C */ + U8 SSUTimeout; /* 0x0C */ + U8 Reserved1; /* 0x0D */ + U16 Reserved2; /* 0x0E */ U32 DeviceSettings; /* 0x10 */ U16 NumberOfDevices; /* 0x14 */ U16 UEFIVersion; /* 0x16 */ @@ -1235,9 +1252,24 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1 } MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1, Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t; -#define MPI2_BIOSPAGE1_PAGEVERSION (0x05) +#define MPI2_BIOSPAGE1_PAGEVERSION (0x07) /* values for BIOS Page 1 BiosOptions field */ +#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800) +#define MPI2_BIOSPAGE1_OPTIONS_PNS_PBDHL (0x00000000) +#define MPI2_BIOSPAGE1_OPTIONS_PNS_ENCSLOSURE (0x00000800) +#define MPI2_BIOSPAGE1_OPTIONS_PNS_LWWID (0x00001000) +#define MPI2_BIOSPAGE1_OPTIONS_PNS_PSENS (0x00001800) +#define MPI2_BIOSPAGE1_OPTIONS_PNS_ESPHY (0x00002000) + +#define MPI2_BIOSPAGE1_OPTIONS_X86_DISABLE_BIOS (0x00000400) + +#define MPI2_BIOSPAGE1_OPTIONS_MASK_REGISTRATION_UEFI_BSD (0x00000300) +#define MPI2_BIOSPAGE1_OPTIONS_USE_BIT0_REGISTRATION_UEFI_BSD (0x00000000) +#define MPI2_BIOSPAGE1_OPTIONS_FULL_REGISTRATION_UEFI_BSD (0x00000100) +#define MPI2_BIOSPAGE1_OPTIONS_ADAPTER_REGISTRATION_UEFI_BSD (0x00000200) +#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_REGISTRATION_UEFI_BSD (0x00000300) + #define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0) #define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000) @@ -2420,13 +2452,13 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 U8 PortGroups; /* 0x2C */ U8 DmaGroup; /* 0x2D */ U8 ControlGroup; /* 0x2E */ - U8 Reserved1; /* 0x2F */ - U32 Reserved2; /* 0x30 */ + U8 EnclosureLevel; /* 0x2F */ + U8 ConnectorName[4]; /* 0x30 */ U32 Reserved3; /* 0x34 */ } MPI2_CONFIG_PAGE_SAS_DEV_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_0, Mpi2SasDevicePage0_t, MPI2_POINTER pMpi2SasDevicePage0_t; -#define MPI2_SASDEVICE0_PAGEVERSION (0x08) +#define MPI2_SASDEVICE0_PAGEVERSION (0x09) /* values for SAS Device Page 0 AccessStatus field */ #define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) @@ -2464,6 +2496,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 #define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) #define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) #define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) +#define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID (0x0002) #define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) @@ -2732,7 +2765,8 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 U16 EnclosureHandle; /* 0x16 */ U16 NumSlots; /* 0x18 */ U16 StartSlot; /* 0x1A */ - U16 Reserved2; /* 0x1C */ + U8 Reserved2; /* 0x1C */ + U8 EnclosureLevel; /* 0x1D */ U16 SEPDevHandle; /* 0x1E */ U32 Reserved3; /* 0x20 */ U32 Reserved4; /* 0x24 */ @@ -2740,9 +2774,10 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t; -#define MPI2_SASENCLOSURE0_PAGEVERSION (0x03) +#define MPI2_SASENCLOSURE0_PAGEVERSION (0x04) /* values for SAS Enclosure Page 0 Flags field */ +#define MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010) #define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F) #define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000) #define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index 2c3b0f28576b..b02de48be204 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -6,7 +6,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: October 11, 2006 * - * mpi2_ioc.h Version: 02.00.23 + * mpi2_ioc.h Version: 02.00.24 * * Version History * --------------- @@ -126,6 +126,7 @@ * Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE. * Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY. * Added Encrypted Hash Extended Image. + * 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS. * -------------------------------------------------------------------------- */ @@ -1589,6 +1590,7 @@ Mpi25EncryptedHashEntry_t, MPI2_POINTER pMpi25EncryptedHashEntry_t; /* values for HashImageType */ #define MPI25_HASH_IMAGE_TYPE_UNUSED (0x00) #define MPI25_HASH_IMAGE_TYPE_FIRMWARE (0x01) +#define MPI25_HASH_IMAGE_TYPE_BIOS (0x02) /* values for HashAlgorithm */ #define MPI25_HASH_ALGORITHM_UNUSED (0x00) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h index 9be03ed46180..659b8ac83ceb 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h @@ -6,7 +6,7 @@ * Title: MPI diagnostic tool structures and definitions * Creation Date: March 26, 2007 * - * mpi2_tool.h Version: 02.00.11 + * mpi2_tool.h Version: 02.00.12 * * Version History * --------------- @@ -29,7 +29,8 @@ * MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST. * 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that * it uses MPI Chain SGE as well as MPI Simple SGE. - * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info. + * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info. + * 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC. * -------------------------------------------------------------------------- */ @@ -101,6 +102,7 @@ typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST #define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000) #define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000) #define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000) +#define MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC (0x04000000) #define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000) #define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000) #define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 58e45216d1ec..11248de92b3b 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -4,7 +4,8 @@ * * This code is based on drivers/scsi/mpt2sas/mpt2_base.c * Copyright (C) 2007-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 20013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -639,6 +640,9 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc, if (!ioc->hide_ir_msg) desc = "Log Entry Added"; break; + case MPI2_EVENT_TEMP_THRESHOLD: + desc = "Temperature Threshold"; + break; } if (!desc) @@ -1296,6 +1300,8 @@ _base_free_irq(struct MPT2SAS_ADAPTER *ioc) list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) { list_del(&reply_q->list); + irq_set_affinity_hint(reply_q->vector, NULL); + free_cpumask_var(reply_q->affinity_hint); synchronize_irq(reply_q->vector); free_irq(reply_q->vector, reply_q); kfree(reply_q); @@ -1325,6 +1331,11 @@ _base_request_irq(struct MPT2SAS_ADAPTER *ioc, u8 index, u32 vector) reply_q->ioc = ioc; reply_q->msix_index = index; reply_q->vector = vector; + + if (!alloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL)) + return -ENOMEM; + cpumask_clear(reply_q->affinity_hint); + atomic_set(&reply_q->busy, 0); if (ioc->msix_enable) snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", @@ -1359,6 +1370,7 @@ static void _base_assign_reply_queues(struct MPT2SAS_ADAPTER *ioc) { unsigned int cpu, nr_cpus, nr_msix, index = 0; + struct adapter_reply_queue *reply_q; if (!_base_is_controller_msix_enabled(ioc)) return; @@ -1373,20 +1385,30 @@ _base_assign_reply_queues(struct MPT2SAS_ADAPTER *ioc) cpu = cpumask_first(cpu_online_mask); - do { + list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { + unsigned int i, group = nr_cpus / nr_msix; + if (cpu >= nr_cpus) + break; + if (index < nr_cpus % nr_msix) group++; for (i = 0 ; i < group ; i++) { ioc->cpu_msix_table[cpu] = index; + cpumask_or(reply_q->affinity_hint, + reply_q->affinity_hint, get_cpu_mask(cpu)); cpu = cpumask_next(cpu, cpu_online_mask); } + if (irq_set_affinity_hint(reply_q->vector, + reply_q->affinity_hint)) + dinitprintk(ioc, pr_info(MPT2SAS_FMT + "error setting affinity hint for irq vector %d\n", + ioc->name, reply_q->vector)); index++; - - } while (cpu < nr_cpus); + } } /** @@ -2338,6 +2360,7 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc) mpt2sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8); mpt2sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0); mpt2sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); + mpt2sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8); _base_display_ioc_capabilities(ioc); /* @@ -2355,6 +2378,8 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc) ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags); mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); + if (ioc->iounit_pg8.NumSensors) + ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors; } /** @@ -2486,9 +2511,13 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) /* command line tunables for max sgl entries */ if (max_sgl_entries != -1) { - ioc->shost->sg_tablesize = (max_sgl_entries < - MPT2SAS_SG_DEPTH) ? max_sgl_entries : - MPT2SAS_SG_DEPTH; + ioc->shost->sg_tablesize = min_t(unsigned short, + max_sgl_entries, SCSI_MAX_SG_CHAIN_SEGMENTS); + if (ioc->shost->sg_tablesize > MPT2SAS_SG_DEPTH) + printk(MPT2SAS_WARN_FMT + "sg_tablesize(%u) is bigger than kernel defined" + " SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name, + ioc->shost->sg_tablesize, MPT2SAS_SG_DEPTH); } else { ioc->shost->sg_tablesize = MPT2SAS_SG_DEPTH; } @@ -3236,7 +3265,7 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, u16 smid; u32 ioc_state; unsigned long timeleft; - u8 issue_reset; + bool issue_reset = false; int rc; void *request; u16 wait_state_count; @@ -3300,7 +3329,7 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, _debug_dump_mf(mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t)/4); if (!(ioc->base_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; + issue_reset = true; goto issue_host_reset; } if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID) @@ -3341,7 +3370,7 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, u16 smid; u32 ioc_state; unsigned long timeleft; - u8 issue_reset; + bool issue_reset = false; int rc; void *request; u16 wait_state_count; @@ -3398,7 +3427,7 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, _debug_dump_mf(mpi_request, sizeof(Mpi2SepRequest_t)/4); if (!(ioc->base_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; + issue_reset = true; goto issue_host_reset; } if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID) @@ -4594,6 +4623,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) _base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK); _base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS); _base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED); + _base_unmask_events(ioc, MPI2_EVENT_TEMP_THRESHOLD); r = _base_make_ioc_operational(ioc, CAN_SLEEP); if (r) goto out_free_resources; diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 239f169b0673..caff8d10cca4 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -4,7 +4,8 @@ * * This code is based on drivers/scsi/mpt2sas/mpt2_base.h * Copyright (C) 2007-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 20013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -67,10 +68,10 @@ /* driver versioning info */ #define MPT2SAS_DRIVER_NAME "mpt2sas" -#define MPT2SAS_AUTHOR "LSI Corporation " +#define MPT2SAS_AUTHOR "Avago Technologies " #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "18.100.00.00" -#define MPT2SAS_MAJOR_VERSION 18 +#define MPT2SAS_DRIVER_VERSION "20.100.00.00" +#define MPT2SAS_MAJOR_VERSION 20 #define MPT2SAS_MINOR_VERSION 100 #define MPT2SAS_BUILD_VERSION 00 #define MPT2SAS_RELEASE_VERSION 00 @@ -586,6 +587,7 @@ struct adapter_reply_queue { Mpi2ReplyDescriptorsUnion_t *reply_post_free; char name[MPT_NAME_LENGTH]; atomic_t busy; + cpumask_var_t affinity_hint; struct list_head list; }; @@ -725,6 +727,7 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc); * @ioc_pg8: static ioc page 8 * @iounit_pg0: static iounit page 0 * @iounit_pg1: static iounit page 1 + * @iounit_pg8: static iounit page 8 * @sas_hba: sas host object * @sas_expander_list: expander object list * @sas_node_lock: @@ -795,6 +798,7 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc); * @reply_post_host_index: head index in the pool where FW completes IO * @delayed_tr_list: target reset link list * @delayed_tr_volume_list: volume target reset link list + * @@temp_sensors_count: flag to carry the number of temperature sensors */ struct MPT2SAS_ADAPTER { struct list_head list; @@ -892,6 +896,7 @@ struct MPT2SAS_ADAPTER { Mpi2IOCPage8_t ioc_pg8; Mpi2IOUnitPage0_t iounit_pg0; Mpi2IOUnitPage1_t iounit_pg1; + Mpi2IOUnitPage8_t iounit_pg8; struct _boot_device req_boot_device; struct _boot_device req_alt_boot_device; @@ -992,6 +997,7 @@ struct MPT2SAS_ADAPTER { struct list_head delayed_tr_list; struct list_head delayed_tr_volume_list; + u8 temp_sensors_count; /* diag buffer support */ u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT]; @@ -1120,6 +1126,8 @@ int mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page); int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page); +int mpt2sas_config_get_iounit_pg8(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page); int mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz); int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index c72a2fff5dbb..c43815b1a485 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c @@ -3,7 +3,8 @@ * * This code is based on drivers/scsi/mpt2sas/mpt2_base.c * Copyright (C) 2007-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 20013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -718,6 +719,42 @@ mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc, return r; } +/** + * mpt2sas_config_get_iounit_pg8 - obtain iounit page 8 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_iounit_pg8(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; + mpi_request.Header.PageNumber = 8; + mpi_request.Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} + /** * mpt2sas_config_get_ioc_pg8 - obtain ioc page 8 * @ioc: per adapter object diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index ca4e563c01dd..4e509604b571 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -4,7 +4,8 @@ * * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c * Copyright (C) 2007-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 20013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h index 7f842c88abd2..46b2fc5b74af 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h @@ -4,7 +4,8 @@ * * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h * Copyright (C) 2007-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 20013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h index cc57ef31d0fe..277120d45648 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_debug.h +++ b/drivers/scsi/mpt2sas/mpt2sas_debug.h @@ -3,7 +3,8 @@ * * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c * Copyright (C) 2007-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 20013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 6a1c036a6f3f..3f26147bbc64 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -3,7 +3,8 @@ * * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c * Copyright (C) 2007-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 20013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -2729,9 +2730,18 @@ _scsih_host_reset(struct scsi_cmnd *scmd) ioc->name, scmd); scsi_print_command(scmd); + if (ioc->is_driver_loading) { + printk(MPT2SAS_INFO_FMT "Blocking the host reset\n", + ioc->name); + r = FAILED; + goto out; + } + retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); r = (retval < 0) ? FAILED : SUCCESS; + + out: printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n", ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); @@ -3646,6 +3656,31 @@ _scsih_check_volume_delete_events(struct MPT2SAS_ADAPTER *ioc, le16_to_cpu(event_data->VolDevHandle)); } +/** + * _scsih_temp_threshold_events - display temperature threshold exceeded events + * @ioc: per adapter object + * @event_data: the temp threshold event data + * Context: interrupt time. + * + * Return nothing. + */ +static void +_scsih_temp_threshold_events(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventDataTemperature_t *event_data) +{ + if (ioc->temp_sensors_count >= event_data->SensorNum) { + printk(MPT2SAS_ERR_FMT "Temperature Threshold flags %s%s%s%s" + " exceeded for Sensor: %d !!!\n", ioc->name, + ((le16_to_cpu(event_data->Status) & 0x1) == 1) ? "0 " : " ", + ((le16_to_cpu(event_data->Status) & 0x2) == 2) ? "1 " : " ", + ((le16_to_cpu(event_data->Status) & 0x4) == 4) ? "2 " : " ", + ((le16_to_cpu(event_data->Status) & 0x8) == 8) ? "3 " : " ", + event_data->SensorNum); + printk(MPT2SAS_ERR_FMT "Current Temp In Celsius: %d\n", + ioc->name, event_data->CurrentTemperature); + } +} + /** * _scsih_flush_running_cmds - completing outstanding commands. * @ioc: per adapter object @@ -4509,6 +4544,10 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) scmd->result = DID_TRANSPORT_DISRUPTED << 16; goto out; } + if (log_info == 0x32010081) { + scmd->result = DID_RESET << 16; + break; + } scmd->result = DID_SOFT_ERROR << 16; break; case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: @@ -7557,6 +7596,12 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, case MPI2_EVENT_IR_PHYSICAL_DISK: break; + case MPI2_EVENT_TEMP_THRESHOLD: + _scsih_temp_threshold_events(ioc, + (Mpi2EventDataTemperature_t *) + mpi_reply->EventData); + break; + default: /* ignore the rest */ return; } diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index e689bf20a3ea..ff2500ab9ba4 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -3,7 +3,8 @@ * * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c * Copyright (C) 2007-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 20013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 1560115079c7..14a781b6b88d 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -4,7 +4,8 @@ * * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c * Copyright (C) 2012-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 2013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -619,6 +620,9 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc, case MPI2_EVENT_LOG_ENTRY_ADDED: desc = "Log Entry Added"; break; + case MPI2_EVENT_TEMP_THRESHOLD: + desc = "Temperature Threshold"; + break; } if (!desc) @@ -1580,6 +1584,8 @@ _base_free_irq(struct MPT3SAS_ADAPTER *ioc) list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) { list_del(&reply_q->list); + irq_set_affinity_hint(reply_q->vector, NULL); + free_cpumask_var(reply_q->affinity_hint); synchronize_irq(reply_q->vector); free_irq(reply_q->vector, reply_q); kfree(reply_q); @@ -1609,6 +1615,11 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index, u32 vector) reply_q->ioc = ioc; reply_q->msix_index = index; reply_q->vector = vector; + + if (!alloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL)) + return -ENOMEM; + cpumask_clear(reply_q->affinity_hint); + atomic_set(&reply_q->busy, 0); if (ioc->msix_enable) snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", @@ -1643,6 +1654,7 @@ static void _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) { unsigned int cpu, nr_cpus, nr_msix, index = 0; + struct adapter_reply_queue *reply_q; if (!_base_is_controller_msix_enabled(ioc)) return; @@ -1657,20 +1669,30 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) cpu = cpumask_first(cpu_online_mask); - do { + list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { + unsigned int i, group = nr_cpus / nr_msix; + if (cpu >= nr_cpus) + break; + if (index < nr_cpus % nr_msix) group++; for (i = 0 ; i < group ; i++) { ioc->cpu_msix_table[cpu] = index; + cpumask_or(reply_q->affinity_hint, + reply_q->affinity_hint, get_cpu_mask(cpu)); cpu = cpumask_next(cpu, cpu_online_mask); } + if (irq_set_affinity_hint(reply_q->vector, + reply_q->affinity_hint)) + dinitprintk(ioc, pr_info(MPT3SAS_FMT + "error setting affinity hint for irq vector %d\n", + ioc->name, reply_q->vector)); index++; - - } while (cpu < nr_cpus); + } } /** @@ -2500,6 +2522,7 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) mpt3sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8); mpt3sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0); mpt3sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); + mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8); _base_display_ioc_capabilities(ioc); /* @@ -2516,6 +2539,9 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags); mpt3sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); + + if (ioc->iounit_pg8.NumSensors) + ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors; } /** @@ -2659,8 +2685,14 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) if (sg_tablesize < MPT3SAS_MIN_PHYS_SEGMENTS) sg_tablesize = MPT3SAS_MIN_PHYS_SEGMENTS; - else if (sg_tablesize > MPT3SAS_MAX_PHYS_SEGMENTS) - sg_tablesize = MPT3SAS_MAX_PHYS_SEGMENTS; + else if (sg_tablesize > MPT3SAS_MAX_PHYS_SEGMENTS) { + sg_tablesize = min_t(unsigned short, sg_tablesize, + SCSI_MAX_SG_CHAIN_SEGMENTS); + pr_warn(MPT3SAS_FMT + "sg_tablesize(%u) is bigger than kernel" + " defined SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name, + sg_tablesize, MPT3SAS_MAX_PHYS_SEGMENTS); + } ioc->shost->sg_tablesize = sg_tablesize; ioc->hi_priority_depth = facts->HighPriorityCredit; @@ -3419,7 +3451,7 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, u16 smid; u32 ioc_state; unsigned long timeleft; - u8 issue_reset; + bool issue_reset = false; int rc; void *request; u16 wait_state_count; @@ -3483,7 +3515,7 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, _debug_dump_mf(mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t)/4); if (!(ioc->base_cmds.status & MPT3_CMD_RESET)) - issue_reset = 1; + issue_reset = true; goto issue_host_reset; } if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID) @@ -3523,7 +3555,7 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, u16 smid; u32 ioc_state; unsigned long timeleft; - u8 issue_reset; + bool issue_reset = false; int rc; void *request; u16 wait_state_count; @@ -3581,7 +3613,7 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, _debug_dump_mf(mpi_request, sizeof(Mpi2SepRequest_t)/4); if (!(ioc->base_cmds.status & MPT3_CMD_RESET)) - issue_reset = 1; + issue_reset = false; goto issue_host_reset; } if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID) @@ -4720,6 +4752,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) _base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK); _base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS); _base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED); + _base_unmask_events(ioc, MPI2_EVENT_TEMP_THRESHOLD); r = _base_make_ioc_operational(ioc, CAN_SLEEP); if (r) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 40926aa9b24d..afa881682bef 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -4,7 +4,8 @@ * * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.h * Copyright (C) 2012-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 2013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -68,7 +69,7 @@ /* driver versioning info */ #define MPT3SAS_DRIVER_NAME "mpt3sas" -#define MPT3SAS_AUTHOR "LSI Corporation " +#define MPT3SAS_AUTHOR "Avago Technologies " #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" #define MPT3SAS_DRIVER_VERSION "04.100.00.00" #define MPT3SAS_MAJOR_VERSION 4 @@ -506,6 +507,7 @@ struct adapter_reply_queue { Mpi2ReplyDescriptorsUnion_t *reply_post_free; char name[MPT_NAME_LENGTH]; atomic_t busy; + cpumask_var_t affinity_hint; struct list_head list; }; @@ -659,6 +661,7 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @ioc_pg8: static ioc page 8 * @iounit_pg0: static iounit page 0 * @iounit_pg1: static iounit page 1 + * @iounit_pg8: static iounit page 8 * @sas_hba: sas host object * @sas_expander_list: expander object list * @sas_node_lock: @@ -728,6 +731,7 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @reply_post_host_index: head index in the pool where FW completes IO * @delayed_tr_list: target reset link list * @delayed_tr_volume_list: volume target reset link list + * @@temp_sensors_count: flag to carry the number of temperature sensors */ struct MPT3SAS_ADAPTER { struct list_head list; @@ -834,6 +838,7 @@ struct MPT3SAS_ADAPTER { Mpi2IOCPage8_t ioc_pg8; Mpi2IOUnitPage0_t iounit_pg0; Mpi2IOUnitPage1_t iounit_pg1; + Mpi2IOUnitPage8_t iounit_pg8; struct _boot_device req_boot_device; struct _boot_device req_alt_boot_device; @@ -934,6 +939,7 @@ struct MPT3SAS_ADAPTER { struct list_head delayed_tr_list; struct list_head delayed_tr_volume_list; + u8 temp_sensors_count; /* diag buffer support */ u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT]; @@ -1082,6 +1088,8 @@ int mpt3sas_config_get_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page); int mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page); +int mpt3sas_config_get_iounit_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2IOUnitPage8_t *config_page); int mpt3sas_config_get_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz); diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index 4472c2af9255..e45c4613ef0c 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -3,7 +3,8 @@ * * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c * Copyright (C) 2012-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 2013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -870,6 +871,42 @@ mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, return r; } +/** + * mpt3sas_config_get_iounit_pg8 - obtain iounit page 8 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_config_get_iounit_pg8(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; + mpi_request.Header.PageNumber = 8; + mpi_request.Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} + /** * mpt3sas_config_get_ioc_pg8 - obtain ioc page 8 * @ioc: per adapter object diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index dca14877d5ab..080c8a76d23d 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -4,7 +4,8 @@ * * This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.c * Copyright (C) 2012-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 2013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.h b/drivers/scsi/mpt3sas/mpt3sas_ctl.h index 5f3d7fd7c2f8..aee99ce67e54 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.h +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.h @@ -4,7 +4,8 @@ * * This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.h * Copyright (C) 2012-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 2013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/scsi/mpt3sas/mpt3sas_debug.h b/drivers/scsi/mpt3sas/mpt3sas_debug.h index 4778e7dd98bd..4e8a63fdb304 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_debug.h +++ b/drivers/scsi/mpt3sas/mpt3sas_debug.h @@ -3,7 +3,8 @@ * * This code is based on drivers/scsi/mpt3sas/mpt3sas_debug.c * Copyright (C) 2012-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 2013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 94261ee9e72d..5a97e3286719 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -3,7 +3,8 @@ * * This code is based on drivers/scsi/mpt3sas/mpt3sas_scsih.c * Copyright (C) 2012-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 2013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -2392,9 +2393,17 @@ _scsih_host_reset(struct scsi_cmnd *scmd) ioc->name, scmd); scsi_print_command(scmd); + if (ioc->is_driver_loading) { + pr_info(MPT3SAS_FMT "Blocking the host reset\n", + ioc->name); + r = FAILED; + goto out; + } + retval = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); r = (retval < 0) ? FAILED : SUCCESS; +out: pr_info(MPT3SAS_FMT "host reset: %s scmd(%p)\n", ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); @@ -3341,6 +3350,31 @@ _scsih_check_volume_delete_events(struct MPT3SAS_ADAPTER *ioc, le16_to_cpu(event_data->VolDevHandle)); } +/** + * _scsih_temp_threshold_events - display temperature threshold exceeded events + * @ioc: per adapter object + * @event_data: the temp threshold event data + * Context: interrupt time. + * + * Return nothing. + */ +static void +_scsih_temp_threshold_events(struct MPT3SAS_ADAPTER *ioc, + Mpi2EventDataTemperature_t *event_data) +{ + if (ioc->temp_sensors_count >= event_data->SensorNum) { + pr_err(MPT3SAS_FMT "Temperature Threshold flags %s%s%s%s" + " exceeded for Sensor: %d !!!\n", ioc->name, + ((le16_to_cpu(event_data->Status) & 0x1) == 1) ? "0 " : " ", + ((le16_to_cpu(event_data->Status) & 0x2) == 2) ? "1 " : " ", + ((le16_to_cpu(event_data->Status) & 0x4) == 4) ? "2 " : " ", + ((le16_to_cpu(event_data->Status) & 0x8) == 8) ? "3 " : " ", + event_data->SensorNum); + pr_err(MPT3SAS_FMT "Current Temp In Celsius: %d\n", + ioc->name, event_data->CurrentTemperature); + } +} + /** * _scsih_flush_running_cmds - completing outstanding commands. * @ioc: per adapter object @@ -7194,6 +7228,12 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, case MPI2_EVENT_IR_PHYSICAL_DISK: break; + case MPI2_EVENT_TEMP_THRESHOLD: + _scsih_temp_threshold_events(ioc, + (Mpi2EventDataTemperature_t *) + mpi_reply->EventData); + break; + default: /* ignore the rest */ return 1; } diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index 3637ae6c0171..efb98afc46e0 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -3,7 +3,8 @@ * * This code is based on drivers/scsi/mpt3sas/mpt3sas_transport.c * Copyright (C) 2012-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 2013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c index 8a2dd113f401..b60fd7a3b571 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c +++ b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c @@ -4,7 +4,8 @@ * * This code is based on drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c * Copyright (C) 2012-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 2013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h index f681db56c53b..6586a463bea9 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h +++ b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h @@ -5,7 +5,8 @@ * * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.h * Copyright (C) 2012-2014 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) + * Copyright (C) 2013-2014 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 90abb03c9074..c6077cefbeca 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -1441,8 +1441,6 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id) return IRQ_RETVAL(handled); } -#undef SPRINTF -#define SPRINTF(args...) seq_printf(m, ##args) static int nsp32_show_info(struct seq_file *m, struct Scsi_Host *host) { @@ -1458,64 +1456,63 @@ static int nsp32_show_info(struct seq_file *m, struct Scsi_Host *host) data = (nsp32_hw_data *)host->hostdata; base = host->io_port; - SPRINTF("NinjaSCSI-32 status\n\n"); - SPRINTF("Driver version: %s, $Revision: 1.33 $\n", nsp32_release_version); - SPRINTF("SCSI host No.: %d\n", hostno); - SPRINTF("IRQ: %d\n", host->irq); - SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); - SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1); - SPRINTF("sg_tablesize: %d\n", host->sg_tablesize); - SPRINTF("Chip revision: 0x%x\n", (nsp32_read2(base, INDEX_REG) >> 8) & 0xff); + seq_puts(m, "NinjaSCSI-32 status\n\n"); + seq_printf(m, "Driver version: %s, $Revision: 1.33 $\n", nsp32_release_version); + seq_printf(m, "SCSI host No.: %d\n", hostno); + seq_printf(m, "IRQ: %d\n", host->irq); + seq_printf(m, "IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); + seq_printf(m, "MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1); + seq_printf(m, "sg_tablesize: %d\n", host->sg_tablesize); + seq_printf(m, "Chip revision: 0x%x\n", (nsp32_read2(base, INDEX_REG) >> 8) & 0xff); mode_reg = nsp32_index_read1(base, CHIP_MODE); model = data->pci_devid->driver_data; #ifdef CONFIG_PM - SPRINTF("Power Management: %s\n", (mode_reg & OPTF) ? "yes" : "no"); + seq_printf(m, "Power Management: %s\n", (mode_reg & OPTF) ? "yes" : "no"); #endif - SPRINTF("OEM: %ld, %s\n", (mode_reg & (OEM0|OEM1)), nsp32_model[model]); + seq_printf(m, "OEM: %ld, %s\n", (mode_reg & (OEM0|OEM1)), nsp32_model[model]); spin_lock_irqsave(&(data->Lock), flags); - SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC); + seq_printf(m, "CurrentSC: 0x%p\n\n", data->CurrentSC); spin_unlock_irqrestore(&(data->Lock), flags); - SPRINTF("SDTR status\n"); + seq_puts(m, "SDTR status\n"); for (id = 0; id < ARRAY_SIZE(data->target); id++) { - SPRINTF("id %d: ", id); + seq_printf(m, "id %d: ", id); if (id == host->this_id) { - SPRINTF("----- NinjaSCSI-32 host adapter\n"); + seq_puts(m, "----- NinjaSCSI-32 host adapter\n"); continue; } if (data->target[id].sync_flag == SDTR_DONE) { if (data->target[id].period == 0 && data->target[id].offset == ASYNC_OFFSET ) { - SPRINTF("async"); + seq_puts(m, "async"); } else { - SPRINTF(" sync"); + seq_puts(m, " sync"); } } else { - SPRINTF(" none"); + seq_puts(m, " none"); } if (data->target[id].period != 0) { speed = 1000000 / (data->target[id].period * 4); - SPRINTF(" transfer %d.%dMB/s, offset %d", + seq_printf(m, " transfer %d.%dMB/s, offset %d", speed / 1000, speed % 1000, data->target[id].offset ); } - SPRINTF("\n"); + seq_putc(m, '\n'); } return 0; } -#undef SPRINTF diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 34aad32829f5..1b6c8833a304 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1364,9 +1364,6 @@ static const char *nsp_info(struct Scsi_Host *shpnt) return data->nspinfo; } -#undef SPRINTF -#define SPRINTF(args...) seq_printf(m, ##args) - static int nsp_show_info(struct seq_file *m, struct Scsi_Host *host) { int id; @@ -1378,75 +1375,74 @@ static int nsp_show_info(struct seq_file *m, struct Scsi_Host *host) hostno = host->host_no; data = (nsp_hw_data *)host->hostdata; - SPRINTF("NinjaSCSI status\n\n"); - SPRINTF("Driver version: $Revision: 1.23 $\n"); - SPRINTF("SCSI host No.: %d\n", hostno); - SPRINTF("IRQ: %d\n", host->irq); - SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); - SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1); - SPRINTF("sg_tablesize: %d\n", host->sg_tablesize); + seq_puts(m, "NinjaSCSI status\n\n" + "Driver version: $Revision: 1.23 $\n"); + seq_printf(m, "SCSI host No.: %d\n", hostno); + seq_printf(m, "IRQ: %d\n", host->irq); + seq_printf(m, "IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); + seq_printf(m, "MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1); + seq_printf(m, "sg_tablesize: %d\n", host->sg_tablesize); - SPRINTF("burst transfer mode: "); + seq_puts(m, "burst transfer mode: "); switch (nsp_burst_mode) { case BURST_IO8: - SPRINTF("io8"); + seq_puts(m, "io8"); break; case BURST_IO32: - SPRINTF("io32"); + seq_puts(m, "io32"); break; case BURST_MEM32: - SPRINTF("mem32"); + seq_puts(m, "mem32"); break; default: - SPRINTF("???"); + seq_puts(m, "???"); break; } - SPRINTF("\n"); + seq_putc(m, '\n'); spin_lock_irqsave(&(data->Lock), flags); - SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC); + seq_printf(m, "CurrentSC: 0x%p\n\n", data->CurrentSC); spin_unlock_irqrestore(&(data->Lock), flags); - SPRINTF("SDTR status\n"); + seq_puts(m, "SDTR status\n"); for(id = 0; id < ARRAY_SIZE(data->Sync); id++) { - SPRINTF("id %d: ", id); + seq_printf(m, "id %d: ", id); if (id == host->this_id) { - SPRINTF("----- NinjaSCSI-3 host adapter\n"); + seq_puts(m, "----- NinjaSCSI-3 host adapter\n"); continue; } switch(data->Sync[id].SyncNegotiation) { case SYNC_OK: - SPRINTF(" sync"); + seq_puts(m, " sync"); break; case SYNC_NG: - SPRINTF("async"); + seq_puts(m, "async"); break; case SYNC_NOT_YET: - SPRINTF(" none"); + seq_puts(m, " none"); break; default: - SPRINTF("?????"); + seq_puts(m, "?????"); break; } if (data->Sync[id].SyncPeriod != 0) { speed = 1000000 / (data->Sync[id].SyncPeriod * 4); - SPRINTF(" transfer %d.%dMB/s, offset %d", + seq_printf(m, " transfer %d.%dMB/s, offset %d", speed / 1000, speed % 1000, data->Sync[id].SyncOffset ); } - SPRINTF("\n"); + seq_putc(m, '\n'); } return 0; } -#undef SPRINTF /*---------------------------------------------------------------*/ /* error handler */ diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 8c27b6a77ec4..ed31d8cc6266 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -1473,13 +1473,7 @@ static int pmcraid_notify_aen( } /* send genetlink multicast message to notify appplications */ - result = genlmsg_end(skb, msg_header); - - if (result < 0) { - pmcraid_err("genlmsg_end failed\n"); - nlmsg_free(skb); - return result; - } + genlmsg_end(skb, msg_header); result = genlmsg_multicast(&pmcraid_event_family, skb, 0, 0, GFP_ATOMIC); @@ -4223,7 +4217,7 @@ static ssize_t pmcraid_show_adapter_id( static struct device_attribute pmcraid_adapter_id_attr = { .attr = { .name = "adapter_id", - .mode = S_IRUGO | S_IWUSR, + .mode = S_IRUGO, }, .show = pmcraid_show_adapter_id, }; diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 2ca39b8e7166..15cf074ffa3c 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -23,10 +23,10 @@ qla2x00_dfs_fce_show(struct seq_file *s, void *unused) mutex_lock(&ha->fce_mutex); - seq_printf(s, "FCE Trace Buffer\n"); + seq_puts(s, "FCE Trace Buffer\n"); seq_printf(s, "In Pointer = %llx\n\n", (unsigned long long)ha->fce_wr); seq_printf(s, "Base = %llx\n\n", (unsigned long long) ha->fce_dma); - seq_printf(s, "FCE Enable Registers\n"); + seq_puts(s, "FCE Enable Registers\n"); seq_printf(s, "%08x %08x %08x %08x %08x %08x\n", ha->fce_mb[0], ha->fce_mb[2], ha->fce_mb[3], ha->fce_mb[4], ha->fce_mb[5], ha->fce_mb[6]); @@ -38,11 +38,11 @@ qla2x00_dfs_fce_show(struct seq_file *s, void *unused) seq_printf(s, "\n%llx: ", (unsigned long long)((cnt * 4) + fce_start)); else - seq_printf(s, " "); + seq_putc(s, ' '); seq_printf(s, "%08x", *fce++); } - seq_printf(s, "\nEnd\n"); + seq_puts(s, "\nEnd\n"); mutex_unlock(&ha->fce_mutex); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index e02885451425..c9c3b579eece 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -531,7 +531,7 @@ void scsi_log_send(struct scsi_cmnd *cmd) * * 3: same as 2 * - * 4: same as 3 plus dump extra junk + * 4: same as 3 */ if (unlikely(scsi_logging_level)) { level = SCSI_LOG_LEVEL(SCSI_LOG_MLQUEUE_SHIFT, @@ -540,13 +540,6 @@ void scsi_log_send(struct scsi_cmnd *cmd) scmd_printk(KERN_INFO, cmd, "Send: scmd 0x%p\n", cmd); scsi_print_command(cmd); - if (level > 3) { - printk(KERN_INFO "buffer = 0x%p, bufflen = %d," - " queuecommand 0x%p\n", - scsi_sglist(cmd), scsi_bufflen(cmd), - cmd->device->host->hostt->queuecommand); - - } } } } @@ -572,7 +565,7 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) SCSI_LOG_MLCOMPLETE_BITS); if (((level > 0) && (cmd->result || disposition != SUCCESS)) || (level > 1)) { - scsi_print_result(cmd, "Done: ", disposition); + scsi_print_result(cmd, "Done", disposition); scsi_print_command(cmd); if (status_byte(cmd->result) & CHECK_CONDITION) scsi_print_sense(cmd); @@ -986,9 +979,9 @@ int scsi_device_get(struct scsi_device *sdev) return -ENXIO; if (!get_device(&sdev->sdev_gendev)) return -ENXIO; - /* We can fail this if we're doing SCSI operations + /* We can fail try_module_get if we're doing SCSI operations * from module exit (like cache flush) */ - try_module_get(sdev->host->hostt->module); + __module_get(sdev->host->hostt->module); return 0; } @@ -1004,14 +997,7 @@ EXPORT_SYMBOL(scsi_device_get); */ void scsi_device_put(struct scsi_device *sdev) { -#ifdef CONFIG_MODULE_UNLOAD - struct module *module = sdev->host->hostt->module; - - /* The module refcount will be zero if scsi_device_get() - * was called from a module removal routine */ - if (module && module_refcount(module) != 0) - module_put(module); -#endif + module_put(sdev->host->hostt->module); put_device(&sdev->sdev_gendev); } EXPORT_SYMBOL(scsi_device_put); diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 7b8b51bc29b4..113232135d27 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -80,6 +80,8 @@ static const char *scsi_debug_version_date = "20141022"; #define INVALID_FIELD_IN_PARAM_LIST 0x26 #define UA_RESET_ASC 0x29 #define UA_CHANGED_ASC 0x2a +#define TARGET_CHANGED_ASC 0x3f +#define LUNS_CHANGED_ASCQ 0x0e #define INSUFF_RES_ASC 0x55 #define INSUFF_RES_ASCQ 0x3 #define POWER_ON_RESET_ASCQ 0x0 @@ -91,6 +93,8 @@ static const char *scsi_debug_version_date = "20141022"; #define THRESHOLD_EXCEEDED 0x5d #define LOW_POWER_COND_ON 0x5e #define MISCOMPARE_VERIFY_ASC 0x1d +#define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ +#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 /* Additional Sense Code Qualifier (ASCQ) */ #define ACK_NAK_TO 0x3 @@ -180,7 +184,10 @@ static const char *scsi_debug_version_date = "20141022"; #define SDEBUG_UA_BUS_RESET 1 #define SDEBUG_UA_MODE_CHANGED 2 #define SDEBUG_UA_CAPACITY_CHANGED 3 -#define SDEBUG_NUM_UAS 4 +#define SDEBUG_UA_LUNS_CHANGED 4 +#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */ +#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6 +#define SDEBUG_NUM_UAS 7 /* for check_readiness() */ #define UAS_ONLY 1 /* check for UAs only */ @@ -326,6 +333,7 @@ static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); struct opcode_info_t { u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff @@ -480,8 +488,9 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10, NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, - {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* WRITE_BUFFER */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, + {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, + 0, 0, 0, 0} }, /* WRITE_BUFFER */ {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10, write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, @@ -782,6 +791,22 @@ static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) /* return -ENOTTY; // correct return but upsets fdisk */ } +static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) +{ + struct sdebug_host_info *sdhp; + struct sdebug_dev_info *dp; + + spin_lock(&sdebug_host_list_lock); + list_for_each_entry(sdhp, &sdebug_host_list, host_list) { + list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { + if ((devip->sdbg_host == dp->sdbg_host) && + (devip->target == dp->target)) + clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); + } + } + spin_unlock(&sdebug_host_list_lock); +} + static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only, struct sdebug_dev_info * devip) { @@ -817,6 +842,36 @@ static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only, if (debug) cp = "capacity data changed"; break; + case SDEBUG_UA_MICROCODE_CHANGED: + mk_sense_buffer(SCpnt, UNIT_ATTENTION, + TARGET_CHANGED_ASC, MICROCODE_CHANGED_ASCQ); + if (debug) + cp = "microcode has been changed"; + break; + case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: + mk_sense_buffer(SCpnt, UNIT_ATTENTION, + TARGET_CHANGED_ASC, + MICROCODE_CHANGED_WO_RESET_ASCQ); + if (debug) + cp = "microcode has been changed without reset"; + break; + case SDEBUG_UA_LUNS_CHANGED: + /* + * SPC-3 behavior is to report a UNIT ATTENTION with + * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN + * on the target, until a REPORT LUNS command is + * received. SPC-4 behavior is to report it only once. + * NOTE: scsi_debug_scsi_level does not use the same + * values as struct scsi_device->scsi_level. + */ + if (scsi_debug_scsi_level >= 6) /* SPC-4 and above */ + clear_luns_changed_on_target(devip); + mk_sense_buffer(SCpnt, UNIT_ATTENTION, + TARGET_CHANGED_ASC, + LUNS_CHANGED_ASCQ); + if (debug) + cp = "reported luns data has changed"; + break; default: pr_warn("%s: unexpected unit attention code=%d\n", __func__, k); @@ -1623,7 +1678,7 @@ resp_rsup_opcodes(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) req_opcode = cmd[3]; req_sa = get_unaligned_be16(cmd + 4); alloc_len = get_unaligned_be32(cmd + 6); - if (alloc_len < 4 && alloc_len > 0xffff) { + if (alloc_len < 4 || alloc_len > 0xffff) { mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); return check_condition_result; } @@ -1631,7 +1686,7 @@ resp_rsup_opcodes(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) a_len = 8192; else a_len = alloc_len; - arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_KERNEL); + arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); if (NULL == arr) { mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, INSUFF_RES_ASCQ); @@ -3033,6 +3088,55 @@ resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); } +/* Note the mode field is in the same position as the (lower) service action + * field. For the Report supported operation codes command, SPC-4 suggests + * each mode of this command should be reported separately; for future. */ +static int +resp_write_buffer(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) +{ + u8 *cmd = scp->cmnd; + struct scsi_device *sdp = scp->device; + struct sdebug_dev_info *dp; + u8 mode; + + mode = cmd[1] & 0x1f; + switch (mode) { + case 0x4: /* download microcode (MC) and activate (ACT) */ + /* set UAs on this device only */ + set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); + set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); + break; + case 0x5: /* download MC, save and ACT */ + set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); + break; + case 0x6: /* download MC with offsets and ACT */ + /* set UAs on most devices (LUs) in this target */ + list_for_each_entry(dp, + &devip->sdbg_host->dev_info_list, + dev_list) + if (dp->target == sdp->id) { + set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); + if (devip != dp) + set_bit(SDEBUG_UA_MICROCODE_CHANGED, + dp->uas_bm); + } + break; + case 0x7: /* download MC with offsets, save, and ACT */ + /* set UA on all devices (LUs) in this target */ + list_for_each_entry(dp, + &devip->sdbg_host->dev_info_list, + dev_list) + if (dp->target == sdp->id) + set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, + dp->uas_bm); + break; + default: + /* do nothing for this command for other mode values */ + break; + } + return 0; +} + static int resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) { @@ -3229,6 +3333,7 @@ static int resp_report_luns(struct scsi_cmnd * scp, unsigned char arr[SDEBUG_RLUN_ARR_SZ]; unsigned char * max_addr; + clear_luns_changed_on_target(devip); alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); shortish = (alloc_len < 4); if (shortish || (select_report > 2)) { @@ -4369,10 +4474,27 @@ static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, size_t count) { int n; + bool changed; if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { + changed = (scsi_debug_max_luns != n); scsi_debug_max_luns = n; sdebug_max_tgts_luns(); + if (changed && (scsi_debug_scsi_level >= 5)) { /* >= SPC-3 */ + struct sdebug_host_info *sdhp; + struct sdebug_dev_info *dp; + + spin_lock(&sdebug_host_list_lock); + list_for_each_entry(sdhp, &sdebug_host_list, + host_list) { + list_for_each_entry(dp, &sdhp->dev_info_list, + dev_list) { + set_bit(SDEBUG_UA_LUNS_CHANGED, + dp->uas_bm); + } + } + spin_unlock(&sdebug_host_list_lock); + } return count; } return -EINVAL; diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 8afb01604d51..4cdaffca17fc 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -124,41 +124,37 @@ scmd_eh_abort_handler(struct work_struct *work) if (scsi_host_eh_past_deadline(sdev->host)) { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "scmd %p eh timeout, not aborting\n", - scmd)); + "eh timeout, not aborting\n")); } else { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "aborting command %p\n", scmd)); + "aborting command\n")); rtn = scsi_try_to_abort_cmd(sdev->host->hostt, scmd); if (rtn == SUCCESS) { set_host_byte(scmd, DID_TIME_OUT); if (scsi_host_eh_past_deadline(sdev->host)) { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "scmd %p eh timeout, " - "not retrying aborted " - "command\n", scmd)); + "eh timeout, not retrying " + "aborted command\n")); } else if (!scsi_noretry_cmd(scmd) && (++scmd->retries <= scmd->allowed)) { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_WARNING, scmd, - "scmd %p retry " - "aborted command\n", scmd)); + "retry aborted command\n")); scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY); return; } else { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_WARNING, scmd, - "scmd %p finish " - "aborted command\n", scmd)); + "finish aborted command\n")); scsi_finish_command(scmd); return; } } else { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "scmd %p abort %s\n", scmd, + "cmd abort %s\n", (rtn == FAST_IO_FAIL) ? "not send" : "failed")); } @@ -167,8 +163,7 @@ scmd_eh_abort_handler(struct work_struct *work) if (!scsi_eh_scmd_add(scmd, 0)) { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_WARNING, scmd, - "scmd %p terminate " - "aborted command\n", scmd)); + "terminate aborted command\n")); set_host_byte(scmd, DID_TIME_OUT); scsi_finish_command(scmd); } @@ -194,7 +189,7 @@ scsi_abort_command(struct scsi_cmnd *scmd) scmd->eh_eflags &= ~SCSI_EH_ABORT_SCHEDULED; SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "scmd %p previous abort failed\n", scmd)); + "previous abort failed\n")); BUG_ON(delayed_work_pending(&scmd->abort_work)); return FAILED; } @@ -208,8 +203,7 @@ scsi_abort_command(struct scsi_cmnd *scmd) spin_unlock_irqrestore(shost->host_lock, flags); SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "scmd %p not aborting, host in recovery\n", - scmd)); + "not aborting, host in recovery\n")); return FAILED; } @@ -219,8 +213,7 @@ scsi_abort_command(struct scsi_cmnd *scmd) scmd->eh_eflags |= SCSI_EH_ABORT_SCHEDULED; SCSI_LOG_ERROR_RECOVERY(3, - scmd_printk(KERN_INFO, scmd, - "scmd %p abort scheduled\n", scmd)); + scmd_printk(KERN_INFO, scmd, "abort scheduled\n")); queue_delayed_work(shost->tmf_work_q, &scmd->abort_work, HZ / 100); return SUCCESS; } @@ -737,8 +730,7 @@ static void scsi_eh_done(struct scsi_cmnd *scmd) struct completion *eh_action; SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "%s scmd: %p result: %x\n", - __func__, scmd, scmd->result)); + "%s result: %x\n", __func__, scmd->result)); eh_action = scmd->device->host->eh_action; if (eh_action) @@ -868,6 +860,7 @@ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd) /** * scsi_try_to_abort_cmd - Ask host to abort a SCSI command + * @hostt: SCSI driver host template * @scmd: SCSI cmd used to send a target reset * * Return value: @@ -1052,8 +1045,8 @@ retry: scsi_log_completion(scmd, rtn); SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "%s: scmd: %p, timeleft: %ld\n", - __func__, scmd, timeleft)); + "%s timeleft: %ld\n", + __func__, timeleft)); /* * If there is time left scsi_eh_done got called, and we will examine @@ -1192,8 +1185,7 @@ int scsi_eh_get_sense(struct list_head *work_q, continue; SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "sense requested for %p result %x\n", - scmd, scmd->result)); + "sense requested, result %x\n", scmd->result)); SCSI_LOG_ERROR_RECOVERY(3, scsi_print_sense(scmd)); rtn = scsi_decide_disposition(scmd); @@ -1235,7 +1227,7 @@ retry_tur: scmd->device->eh_timeout, 0); SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "%s: scmd %p rtn %x\n", __func__, scmd, rtn)); + "%s return: %x\n", __func__, rtn)); switch (rtn) { case NEEDS_RETRY: @@ -2092,8 +2084,8 @@ void scsi_eh_flush_done_q(struct list_head *done_q) (++scmd->retries <= scmd->allowed)) { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "%s: flush retry cmd: %p\n", - current->comm, scmd)); + "%s: flush retry cmd\n", + current->comm)); scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY); } else { /* @@ -2105,8 +2097,8 @@ void scsi_eh_flush_done_q(struct list_head *done_q) scmd->result |= (DRIVER_TIMEOUT << 24); SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, - "%s: flush finish cmd: %p\n", - current->comm, scmd)); + "%s: flush finish cmd\n", + current->comm)); scsi_finish_command(scmd); } } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 6d5c0b8cb0bb..17bb541f7cc2 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1143,7 +1143,17 @@ int scsi_init_io(struct scsi_cmnd *cmd) struct scsi_data_buffer *prot_sdb = cmd->prot_sdb; int ivecs, count; - BUG_ON(prot_sdb == NULL); + if (prot_sdb == NULL) { + /* + * This can happen if someone (e.g. multipath) + * queues a command to a device on an adapter + * that does not support DIX. + */ + WARN_ON_ONCE(1); + error = BLKPREP_KILL; + goto err_exit; + } + ivecs = blk_rq_count_integrity_sg(rq->q, rq->bio); if (scsi_alloc_sgtable(prot_sdb, ivecs, is_mq)) { diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c new file mode 100644 index 000000000000..bd70339c1242 --- /dev/null +++ b/drivers/scsi/scsi_logging.c @@ -0,0 +1,485 @@ +/* + * scsi_logging.c + * + * Copyright (C) 2014 SUSE Linux Products GmbH + * Copyright (C) 2014 Hannes Reinecke + * + * This file is released under the GPLv2 + */ + +#include +#include + +#include +#include +#include +#include +#include + +#define SCSI_LOG_SPOOLSIZE 4096 + +#if (SCSI_LOG_SPOOLSIZE / SCSI_LOG_BUFSIZE) > BITS_PER_LONG +#warning SCSI logging bitmask too large +#endif + +struct scsi_log_buf { + char buffer[SCSI_LOG_SPOOLSIZE]; + unsigned long map; +}; + +static DEFINE_PER_CPU(struct scsi_log_buf, scsi_format_log); + +static char *scsi_log_reserve_buffer(size_t *len) +{ + struct scsi_log_buf *buf; + unsigned long map_bits = sizeof(buf->buffer) / SCSI_LOG_BUFSIZE; + unsigned long idx = 0; + + preempt_disable(); + buf = this_cpu_ptr(&scsi_format_log); + idx = find_first_zero_bit(&buf->map, map_bits); + if (likely(idx < map_bits)) { + while (test_and_set_bit(idx, &buf->map)) { + idx = find_next_zero_bit(&buf->map, map_bits, idx); + if (idx >= map_bits) + break; + } + } + if (WARN_ON(idx >= map_bits)) { + preempt_enable(); + return NULL; + } + *len = SCSI_LOG_BUFSIZE; + return buf->buffer + idx * SCSI_LOG_BUFSIZE; +} + +static void scsi_log_release_buffer(char *bufptr) +{ + struct scsi_log_buf *buf; + unsigned long idx; + int ret; + + buf = this_cpu_ptr(&scsi_format_log); + if (bufptr >= buf->buffer && + bufptr < buf->buffer + SCSI_LOG_SPOOLSIZE) { + idx = (bufptr - buf->buffer) / SCSI_LOG_BUFSIZE; + ret = test_and_clear_bit(idx, &buf->map); + WARN_ON(!ret); + } + preempt_enable(); +} + +static inline const char *scmd_name(const struct scsi_cmnd *scmd) +{ + return scmd->request->rq_disk ? + scmd->request->rq_disk->disk_name : NULL; +} + +static size_t sdev_format_header(char *logbuf, size_t logbuf_len, + const char *name, int tag) +{ + size_t off = 0; + + if (name) + off += scnprintf(logbuf + off, logbuf_len - off, + "[%s] ", name); + + if (WARN_ON(off >= logbuf_len)) + return off; + + if (tag >= 0) + off += scnprintf(logbuf + off, logbuf_len - off, + "tag#%d ", tag); + return off; +} + +void sdev_prefix_printk(const char *level, const struct scsi_device *sdev, + const char *name, const char *fmt, ...) +{ + va_list args; + char *logbuf; + size_t off = 0, logbuf_len; + + if (!sdev) + return; + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + return; + + if (name) + off += scnprintf(logbuf + off, logbuf_len - off, + "[%s] ", name); + if (!WARN_ON(off >= logbuf_len)) { + va_start(args, fmt); + off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args); + va_end(args); + } + dev_printk(level, &sdev->sdev_gendev, "%s", logbuf); + scsi_log_release_buffer(logbuf); +} +EXPORT_SYMBOL(sdev_prefix_printk); + +void scmd_printk(const char *level, const struct scsi_cmnd *scmd, + const char *fmt, ...) +{ + va_list args; + char *logbuf; + size_t off = 0, logbuf_len; + + if (!scmd || !scmd->cmnd) + return; + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + return; + off = sdev_format_header(logbuf, logbuf_len, scmd_name(scmd), + scmd->request->tag); + if (off < logbuf_len) { + va_start(args, fmt); + off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args); + va_end(args); + } + dev_printk(level, &scmd->device->sdev_gendev, "%s", logbuf); + scsi_log_release_buffer(logbuf); +} +EXPORT_SYMBOL(scmd_printk); + +static size_t scsi_format_opcode_name(char *buffer, size_t buf_len, + const unsigned char *cdbp) +{ + int sa, cdb0; + const char *cdb_name = NULL, *sa_name = NULL; + size_t off; + + cdb0 = cdbp[0]; + if (cdb0 == VARIABLE_LENGTH_CMD) { + int len = scsi_varlen_cdb_length(cdbp); + + if (len < 10) { + off = scnprintf(buffer, buf_len, + "short variable length command, len=%d", + len); + return off; + } + sa = (cdbp[8] << 8) + cdbp[9]; + } else + sa = cdbp[1] & 0x1f; + + if (!scsi_opcode_sa_name(cdb0, sa, &cdb_name, &sa_name)) { + if (cdb_name) + off = scnprintf(buffer, buf_len, "%s", cdb_name); + else { + off = scnprintf(buffer, buf_len, "opcode=0x%x", cdb0); + if (WARN_ON(off >= buf_len)) + return off; + if (cdb0 >= VENDOR_SPECIFIC_CDB) + off += scnprintf(buffer + off, buf_len - off, + " (vendor)"); + else if (cdb0 >= 0x60 && cdb0 < 0x7e) + off += scnprintf(buffer + off, buf_len - off, + " (reserved)"); + } + } else { + if (sa_name) + off = scnprintf(buffer, buf_len, "%s", sa_name); + else if (cdb_name) + off = scnprintf(buffer, buf_len, "%s, sa=0x%x", + cdb_name, sa); + else + off = scnprintf(buffer, buf_len, + "opcode=0x%x, sa=0x%x", cdb0, sa); + } + WARN_ON(off >= buf_len); + return off; +} + +size_t __scsi_format_command(char *logbuf, size_t logbuf_len, + const unsigned char *cdb, size_t cdb_len) +{ + int len, k; + size_t off; + + off = scsi_format_opcode_name(logbuf, logbuf_len, cdb); + if (off >= logbuf_len) + return off; + len = scsi_command_size(cdb); + if (cdb_len < len) + len = cdb_len; + /* print out all bytes in cdb */ + for (k = 0; k < len; ++k) { + if (off > logbuf_len - 3) + break; + off += scnprintf(logbuf + off, logbuf_len - off, + " %02x", cdb[k]); + } + return off; +} +EXPORT_SYMBOL(__scsi_format_command); + +void scsi_print_command(struct scsi_cmnd *cmd) +{ + int k; + char *logbuf; + size_t off, logbuf_len; + + if (!cmd->cmnd) + return; + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + return; + + off = sdev_format_header(logbuf, logbuf_len, + scmd_name(cmd), cmd->request->tag); + if (off >= logbuf_len) + goto out_printk; + off += scnprintf(logbuf + off, logbuf_len - off, "CDB: "); + if (WARN_ON(off >= logbuf_len)) + goto out_printk; + + off += scsi_format_opcode_name(logbuf + off, logbuf_len - off, + cmd->cmnd); + if (off >= logbuf_len) + goto out_printk; + + /* print out all bytes in cdb */ + if (cmd->cmd_len > 16) { + /* Print opcode in one line and use separate lines for CDB */ + off += scnprintf(logbuf + off, logbuf_len - off, "\n"); + dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf); + scsi_log_release_buffer(logbuf); + for (k = 0; k < cmd->cmd_len; k += 16) { + size_t linelen = min(cmd->cmd_len - k, 16); + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + break; + off = sdev_format_header(logbuf, logbuf_len, + scmd_name(cmd), + cmd->request->tag); + if (!WARN_ON(off > logbuf_len - 58)) { + off += scnprintf(logbuf + off, logbuf_len - off, + "CDB[%02x]: ", k); + hex_dump_to_buffer(&cmd->cmnd[k], linelen, + 16, 1, logbuf + off, + logbuf_len - off, false); + } + dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", + logbuf); + scsi_log_release_buffer(logbuf); + } + return; + } + if (!WARN_ON(off > logbuf_len - 49)) { + off += scnprintf(logbuf + off, logbuf_len - off, " "); + hex_dump_to_buffer(cmd->cmnd, cmd->cmd_len, 16, 1, + logbuf + off, logbuf_len - off, + false); + } +out_printk: + dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf); + scsi_log_release_buffer(logbuf); +} +EXPORT_SYMBOL(scsi_print_command); + +static size_t +scsi_format_extd_sense(char *buffer, size_t buf_len, + unsigned char asc, unsigned char ascq) +{ + size_t off = 0; + const char *extd_sense_fmt = NULL; + const char *extd_sense_str = scsi_extd_sense_format(asc, ascq, + &extd_sense_fmt); + + if (extd_sense_str) { + off = scnprintf(buffer, buf_len, "Add. Sense: %s", + extd_sense_str); + if (extd_sense_fmt) + off += scnprintf(buffer + off, buf_len - off, + "(%s%x)", extd_sense_fmt, ascq); + } else { + if (asc >= 0x80) + off = scnprintf(buffer, buf_len, "<>"); + off += scnprintf(buffer + off, buf_len - off, + "ASC=0x%x ", asc); + if (ascq >= 0x80) + off += scnprintf(buffer + off, buf_len - off, + "<>"); + off += scnprintf(buffer + off, buf_len - off, + "ASCQ=0x%x ", ascq); + } + return off; +} + +static size_t +scsi_format_sense_hdr(char *buffer, size_t buf_len, + const struct scsi_sense_hdr *sshdr) +{ + const char *sense_txt; + size_t off; + + off = scnprintf(buffer, buf_len, "Sense Key : "); + sense_txt = scsi_sense_key_string(sshdr->sense_key); + if (sense_txt) + off += scnprintf(buffer + off, buf_len - off, + "%s ", sense_txt); + else + off += scnprintf(buffer + off, buf_len - off, + "0x%x ", sshdr->sense_key); + off += scnprintf(buffer + off, buf_len - off, + scsi_sense_is_deferred(sshdr) ? "[deferred] " : "[current] "); + + if (sshdr->response_code >= 0x72) + off += scnprintf(buffer + off, buf_len - off, "[descriptor] "); + return off; +} + +static void +scsi_log_dump_sense(const struct scsi_device *sdev, const char *name, int tag, + const unsigned char *sense_buffer, int sense_len) +{ + char *logbuf; + size_t logbuf_len; + int i; + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + return; + + for (i = 0; i < sense_len; i += 16) { + int len = min(sense_len - i, 16); + size_t off; + + off = sdev_format_header(logbuf, logbuf_len, + name, tag); + hex_dump_to_buffer(&sense_buffer[i], len, 16, 1, + logbuf + off, logbuf_len - off, + false); + dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf); + } + scsi_log_release_buffer(logbuf); +} + +static void +scsi_log_print_sense_hdr(const struct scsi_device *sdev, const char *name, + int tag, const struct scsi_sense_hdr *sshdr) +{ + char *logbuf; + size_t off, logbuf_len; + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + return; + off = sdev_format_header(logbuf, logbuf_len, name, tag); + off += scsi_format_sense_hdr(logbuf + off, logbuf_len - off, sshdr); + dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf); + scsi_log_release_buffer(logbuf); + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + return; + off = sdev_format_header(logbuf, logbuf_len, name, tag); + off += scsi_format_extd_sense(logbuf + off, logbuf_len - off, + sshdr->asc, sshdr->ascq); + dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf); + scsi_log_release_buffer(logbuf); +} + +static void +scsi_log_print_sense(const struct scsi_device *sdev, const char *name, int tag, + const unsigned char *sense_buffer, int sense_len) +{ + struct scsi_sense_hdr sshdr; + + if (scsi_normalize_sense(sense_buffer, sense_len, &sshdr)) + scsi_log_print_sense_hdr(sdev, name, tag, &sshdr); + else + scsi_log_dump_sense(sdev, name, tag, sense_buffer, sense_len); +} + +/* + * Print normalized SCSI sense header with a prefix. + */ +void +scsi_print_sense_hdr(const struct scsi_device *sdev, const char *name, + const struct scsi_sense_hdr *sshdr) +{ + scsi_log_print_sense_hdr(sdev, name, -1, sshdr); +} +EXPORT_SYMBOL(scsi_print_sense_hdr); + +/* Normalize and print sense buffer with name prefix */ +void __scsi_print_sense(const struct scsi_device *sdev, const char *name, + const unsigned char *sense_buffer, int sense_len) +{ + scsi_log_print_sense(sdev, name, -1, sense_buffer, sense_len); +} +EXPORT_SYMBOL(__scsi_print_sense); + +/* Normalize and print sense buffer in SCSI command */ +void scsi_print_sense(const struct scsi_cmnd *cmd) +{ + scsi_log_print_sense(cmd->device, scmd_name(cmd), cmd->request->tag, + cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); +} +EXPORT_SYMBOL(scsi_print_sense); + +void scsi_print_result(const struct scsi_cmnd *cmd, const char *msg, + int disposition) +{ + char *logbuf; + size_t off, logbuf_len; + const char *mlret_string = scsi_mlreturn_string(disposition); + const char *hb_string = scsi_hostbyte_string(cmd->result); + const char *db_string = scsi_driverbyte_string(cmd->result); + + logbuf = scsi_log_reserve_buffer(&logbuf_len); + if (!logbuf) + return; + + off = sdev_format_header(logbuf, logbuf_len, + scmd_name(cmd), cmd->request->tag); + + if (off >= logbuf_len) + goto out_printk; + + if (msg) { + off += scnprintf(logbuf + off, logbuf_len - off, + "%s: ", msg); + if (WARN_ON(off >= logbuf_len)) + goto out_printk; + } + if (mlret_string) + off += scnprintf(logbuf + off, logbuf_len - off, + "%s ", mlret_string); + else + off += scnprintf(logbuf + off, logbuf_len - off, + "UNKNOWN(0x%02x) ", disposition); + if (WARN_ON(off >= logbuf_len)) + goto out_printk; + + off += scnprintf(logbuf + off, logbuf_len - off, "Result: "); + if (WARN_ON(off >= logbuf_len)) + goto out_printk; + + if (hb_string) + off += scnprintf(logbuf + off, logbuf_len - off, + "hostbyte=%s ", hb_string); + else + off += scnprintf(logbuf + off, logbuf_len - off, + "hostbyte=0x%02x ", host_byte(cmd->result)); + if (WARN_ON(off >= logbuf_len)) + goto out_printk; + + if (db_string) + off += scnprintf(logbuf + off, logbuf_len - off, + "driverbyte=%s", db_string); + else + off += scnprintf(logbuf + off, logbuf_len - off, + "driverbyte=0x%02x", driver_byte(cmd->result)); +out_printk: + dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf); + scsi_log_release_buffer(logbuf); +} +EXPORT_SYMBOL(scsi_print_result); diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 6fcefa2da503..251598eb3547 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -189,36 +189,36 @@ static int proc_print_scsidevice(struct device *dev, void *data) sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); for (i = 0; i < 8; i++) { if (sdev->vendor[i] >= 0x20) - seq_printf(s, "%c", sdev->vendor[i]); + seq_putc(s, sdev->vendor[i]); else - seq_printf(s, " "); + seq_putc(s, ' '); } - seq_printf(s, " Model: "); + seq_puts(s, " Model: "); for (i = 0; i < 16; i++) { if (sdev->model[i] >= 0x20) - seq_printf(s, "%c", sdev->model[i]); + seq_putc(s, sdev->model[i]); else - seq_printf(s, " "); + seq_putc(s, ' '); } - seq_printf(s, " Rev: "); + seq_puts(s, " Rev: "); for (i = 0; i < 4; i++) { if (sdev->rev[i] >= 0x20) - seq_printf(s, "%c", sdev->rev[i]); + seq_putc(s, sdev->rev[i]); else - seq_printf(s, " "); + seq_putc(s, ' '); } - seq_printf(s, "\n"); + seq_putc(s, '\n'); seq_printf(s, " Type: %s ", scsi_device_type(sdev->type)); seq_printf(s, " ANSI SCSI revision: %02x", sdev->scsi_level - (sdev->scsi_level > 1)); if (sdev->scsi_level == 2) - seq_printf(s, " CCS\n"); + seq_puts(s, " CCS\n"); else - seq_printf(s, "\n"); + seq_putc(s, '\n'); out: return 0; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 983aed10ff2f..0deb385ad4d6 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -98,20 +99,6 @@ char scsi_scan_type[6] = SCSI_SCAN_TYPE_DEFAULT; module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO); MODULE_PARM_DESC(scan, "sync, async or none"); -/* - * max_scsi_report_luns: the maximum number of LUNS that will be - * returned from the REPORT LUNS command. 8 times this value must - * be allocated. In theory this could be up to an 8 byte value, but - * in practice, the maximum number of LUNs suppored by any device - * is about 16k. - */ -static unsigned int max_scsi_report_luns = 511; - -module_param_named(max_report_luns, max_scsi_report_luns, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(max_report_luns, - "REPORT LUNS maximum number of LUNS received (should be" - " between 1 and 16384)"); - static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ + 18; module_param_named(inq_timeout, scsi_inq_timeout, uint, S_IRUGO|S_IWUSR); @@ -1367,7 +1354,6 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, unsigned int retries; int result; struct scsi_lun *lunp, *lun_data; - u8 *data; struct scsi_sense_hdr sshdr; struct scsi_device *sdev; struct Scsi_Host *shost = dev_to_shost(&starget->dev); @@ -1407,16 +1393,12 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, /* * Allocate enough to hold the header (the same size as one scsi_lun) - * plus the max number of luns we are requesting. - * - * Reallocating and trying again (with the exact amount we need) - * would be nice, but then we need to somehow limit the size - * allocated based on the available memory and the limits of - * kmalloc - we don't want a kmalloc() failure of a huge value to - * prevent us from finding any LUNs on this target. + * plus the number of luns we are requesting. 511 was the default + * value of the now removed max_report_luns parameter. */ - length = (max_scsi_report_luns + 1) * sizeof(struct scsi_lun); - lun_data = kmalloc(length, GFP_ATOMIC | + length = (511 + 1) * sizeof(struct scsi_lun); +retry: + lun_data = kmalloc(length, GFP_KERNEL | (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0)); if (!lun_data) { printk(ALLOC_FAILURE_MSG, __func__); @@ -1433,10 +1415,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, /* * bytes 6 - 9: length of the command. */ - scsi_cmd[6] = (unsigned char) (length >> 24) & 0xff; - scsi_cmd[7] = (unsigned char) (length >> 16) & 0xff; - scsi_cmd[8] = (unsigned char) (length >> 8) & 0xff; - scsi_cmd[9] = (unsigned char) length & 0xff; + put_unaligned_be32(length, &scsi_cmd[6]); scsi_cmd[10] = 0; /* reserved */ scsi_cmd[11] = 0; /* control */ @@ -1484,19 +1463,16 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, /* * Get the length from the first four bytes of lun_data. */ - data = (u8 *) lun_data->scsi_lun; - length = ((data[0] << 24) | (data[1] << 16) | - (data[2] << 8) | (data[3] << 0)); + if (get_unaligned_be32(lun_data->scsi_lun) + + sizeof(struct scsi_lun) > length) { + length = get_unaligned_be32(lun_data->scsi_lun) + + sizeof(struct scsi_lun); + kfree(lun_data); + goto retry; + } + length = get_unaligned_be32(lun_data->scsi_lun); num_luns = (length / sizeof(struct scsi_lun)); - if (num_luns > max_scsi_report_luns) { - sdev_printk(KERN_WARNING, sdev, - "Only %d (max_scsi_report_luns)" - " of %d luns reported, try increasing" - " max_scsi_report_luns.\n", - max_scsi_report_luns, num_luns); - num_luns = max_scsi_report_luns; - } SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev, "scsi scan: REPORT LUN scan\n")); diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c index 82af28b90294..08bb47b53bc3 100644 --- a/drivers/scsi/scsi_trace.c +++ b/drivers/scsi/scsi_trace.c @@ -143,7 +143,7 @@ scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) cmd = "WRITE_SAME"; break; default: - trace_seq_printf(p, "UNKNOWN"); + trace_seq_puts(p, "UNKNOWN"); goto out; } @@ -204,7 +204,7 @@ scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) cmd = "GET_LBA_STATUS"; break; default: - trace_seq_printf(p, "UNKNOWN"); + trace_seq_puts(p, "UNKNOWN"); goto out; } @@ -249,7 +249,7 @@ scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - trace_seq_printf(p, "-"); + trace_seq_putc(p, '-'); trace_seq_putc(p, 0); return ret; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 399516925d80..6b78476d04bb 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2800,9 +2800,11 @@ static int sd_revalidate_disk(struct gendisk *disk) */ sd_set_flush_flag(sdkp); - max_xfer = min_not_zero(queue_max_hw_sectors(sdkp->disk->queue), - sdkp->max_xfer_blocks); + max_xfer = sdkp->max_xfer_blocks; max_xfer <<= ilog2(sdp->sector_size) - 9; + + max_xfer = min_not_zero(queue_max_hw_sectors(sdkp->disk->queue), + max_xfer); blk_queue_max_hw_sectors(sdkp->disk->queue, max_xfer); set_capacity(disk, sdkp->capacity); sd_config_write_same(sdkp); @@ -3318,11 +3320,8 @@ module_exit(exit_sd); static void sd_print_sense_hdr(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr) { - scsi_show_sense_hdr(sdkp->device, - sdkp->disk ? sdkp->disk->disk_name : NULL, sshdr); - scsi_show_extd_sense(sdkp->device, - sdkp->disk ? sdkp->disk->disk_name : NULL, - sshdr->asc, sshdr->ascq); + scsi_print_sense_hdr(sdkp->device, + sdkp->disk ? sdkp->disk->disk_name : NULL, sshdr); } static void sd_print_result(const struct scsi_disk *sdkp, const char *msg, diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index b7e79e7646ad..dcb0d76d7312 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -47,7 +47,6 @@ struct ses_device { struct ses_component { u64 addr; - unsigned char *desc; }; static int ses_probe(struct device *dev) @@ -68,6 +67,20 @@ static int ses_probe(struct device *dev) #define SES_TIMEOUT (30 * HZ) #define SES_RETRIES 3 +static void init_device_slot_control(unsigned char *dest_desc, + struct enclosure_component *ecomp, + unsigned char *status) +{ + memcpy(dest_desc, status, 4); + dest_desc[0] = 0; + /* only clear byte 1 for ENCLOSURE_COMPONENT_DEVICE */ + if (ecomp->type == ENCLOSURE_COMPONENT_DEVICE) + dest_desc[1] = 0; + dest_desc[2] &= 0xde; + dest_desc[3] &= 0x3c; +} + + static int ses_recv_diag(struct scsi_device *sdev, int page_code, void *buf, int bufflen) { @@ -179,14 +192,22 @@ static int ses_set_fault(struct enclosure_device *edev, struct enclosure_component *ecomp, enum enclosure_component_setting val) { - unsigned char desc[4] = {0 }; + unsigned char desc[4]; + unsigned char *desc_ptr; + + desc_ptr = ses_get_page2_descriptor(edev, ecomp); + + if (!desc_ptr) + return -EIO; + + init_device_slot_control(desc, ecomp, desc_ptr); switch (val) { case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ + desc[3] &= 0xdf; break; case ENCLOSURE_SETTING_ENABLED: - desc[3] = 0x20; + desc[3] |= 0x20; break; default: /* SES doesn't do the SGPIO blink settings */ @@ -220,14 +241,22 @@ static int ses_set_locate(struct enclosure_device *edev, struct enclosure_component *ecomp, enum enclosure_component_setting val) { - unsigned char desc[4] = {0 }; + unsigned char desc[4]; + unsigned char *desc_ptr; + + desc_ptr = ses_get_page2_descriptor(edev, ecomp); + + if (!desc_ptr) + return -EIO; + + init_device_slot_control(desc, ecomp, desc_ptr); switch (val) { case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ + desc[2] &= 0xfd; break; case ENCLOSURE_SETTING_ENABLED: - desc[2] = 0x02; + desc[2] |= 0x02; break; default: /* SES doesn't do the SGPIO blink settings */ @@ -240,15 +269,23 @@ static int ses_set_active(struct enclosure_device *edev, struct enclosure_component *ecomp, enum enclosure_component_setting val) { - unsigned char desc[4] = {0 }; + unsigned char desc[4]; + unsigned char *desc_ptr; + + desc_ptr = ses_get_page2_descriptor(edev, ecomp); + + if (!desc_ptr) + return -EIO; + + init_device_slot_control(desc, ecomp, desc_ptr); switch (val) { case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ + desc[2] &= 0x7f; ecomp->active = 0; break; case ENCLOSURE_SETTING_ENABLED: - desc[2] = 0x80; + desc[2] |= 0x80; ecomp->active = 1; break; default: @@ -258,13 +295,63 @@ static int ses_set_active(struct enclosure_device *edev, return ses_set_page2_descriptor(edev, ecomp, desc); } +static int ses_show_id(struct enclosure_device *edev, char *buf) +{ + struct ses_device *ses_dev = edev->scratch; + unsigned long long id = get_unaligned_be64(ses_dev->page1+8+4); + + return sprintf(buf, "%#llx\n", id); +} + +static void ses_get_power_status(struct enclosure_device *edev, + struct enclosure_component *ecomp) +{ + unsigned char *desc; + + desc = ses_get_page2_descriptor(edev, ecomp); + if (desc) + ecomp->power_status = (desc[3] & 0x10) ? 0 : 1; +} + +static int ses_set_power_status(struct enclosure_device *edev, + struct enclosure_component *ecomp, + int val) +{ + unsigned char desc[4]; + unsigned char *desc_ptr; + + desc_ptr = ses_get_page2_descriptor(edev, ecomp); + + if (!desc_ptr) + return -EIO; + + init_device_slot_control(desc, ecomp, desc_ptr); + + switch (val) { + /* power = 1 is device_off = 0 and vice versa */ + case 0: + desc[3] |= 0x10; + break; + case 1: + desc[3] &= 0xef; + break; + default: + return -EINVAL; + } + ecomp->power_status = val; + return ses_set_page2_descriptor(edev, ecomp, desc); +} + static struct enclosure_component_callbacks ses_enclosure_callbacks = { .get_fault = ses_get_fault, .set_fault = ses_set_fault, .get_status = ses_get_status, .get_locate = ses_get_locate, .set_locate = ses_set_locate, + .get_power_status = ses_get_power_status, + .set_power_status = ses_set_power_status, .set_active = ses_set_active, + .show_id = ses_show_id, }; struct ses_host_edev { @@ -298,19 +385,26 @@ static void ses_process_descriptor(struct enclosure_component *ecomp, int invalid = desc[0] & 0x80; enum scsi_protocol proto = desc[0] & 0x0f; u64 addr = 0; + int slot = -1; struct ses_component *scomp = ecomp->scratch; unsigned char *d; - scomp->desc = desc; - if (invalid) return; switch (proto) { + case SCSI_PROTOCOL_FCP: + if (eip) { + d = desc + 4; + slot = d[3]; + } + break; case SCSI_PROTOCOL_SAS: - if (eip) + if (eip) { + d = desc + 4; + slot = d[3]; d = desc + 8; - else + } else d = desc + 4; /* only take the phy0 addr */ addr = (u64)d[12] << 56 | @@ -326,6 +420,7 @@ static void ses_process_descriptor(struct enclosure_component *ecomp, /* FIXME: Need to add more protocols than just SAS */ break; } + ecomp->slot = slot; scomp->addr = addr; } @@ -349,7 +444,8 @@ static int ses_enclosure_find_by_addr(struct enclosure_device *edev, if (scomp->addr != efd->addr) continue; - enclosure_add_device(edev, i, efd->dev); + if (enclosure_add_device(edev, i, efd->dev) == 0) + kobject_uevent(&efd->dev->kobj, KOBJ_CHANGE); return 1; } return 0; @@ -423,16 +519,24 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) { if (create) - ecomp = enclosure_component_register(edev, - components++, - type_ptr[0], - name); + ecomp = enclosure_component_alloc( + edev, + components++, + type_ptr[0], + name); else ecomp = &edev->component[components++]; - if (!IS_ERR(ecomp) && addl_desc_ptr) - ses_process_descriptor(ecomp, - addl_desc_ptr); + if (!IS_ERR(ecomp)) { + ses_get_power_status(edev, ecomp); + if (addl_desc_ptr) + ses_process_descriptor( + ecomp, + addl_desc_ptr); + if (create) + enclosure_component_register( + ecomp); + } } if (desc_ptr) desc_ptr += len; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index b14f64cb9724..a668c88ea150 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -763,7 +763,7 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp, unsigned char *cmnd, int timeout, int blocking) { - int k, data_dir, at_head; + int k, at_head; Sg_device *sdp = sfp->parentdp; sg_io_hdr_t *hp = &srp->header; @@ -793,21 +793,6 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, return -ENODEV; } - switch (hp->dxfer_direction) { - case SG_DXFER_TO_FROM_DEV: - case SG_DXFER_FROM_DEV: - data_dir = DMA_FROM_DEVICE; - break; - case SG_DXFER_TO_DEV: - data_dir = DMA_TO_DEVICE; - break; - case SG_DXFER_UNKNOWN: - data_dir = DMA_BIDIRECTIONAL; - break; - default: - data_dir = DMA_NONE; - break; - } hp->duration = jiffies_to_msecs(jiffies); if (hp->interface_id != '\0' && /* v3 (or later) interface */ (SG_FLAG_Q_AT_TAIL & hp->flags)) diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index fb929fac22ba..03054c0e7689 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -245,9 +245,6 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) sr_printk(KERN_INFO, cd, "CDROM not ready. Make sure there " "is a disc in the drive.\n"); -#ifdef DEBUG - scsi_print_sense_hdr(cd->device, cd->cdi.name, &sshdr); -#endif err = -ENOMEDIUM; break; case ILLEGAL_REQUEST: @@ -256,16 +253,8 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) sshdr.ascq == 0x00) /* sense: Invalid command operation code */ err = -EDRIVE_CANT_DO_THIS; -#ifdef DEBUG - __scsi_print_command(cgc->cmd, CDROM_PACKET_SIZE); - scsi_print_sense_hdr(cd->device, cd->cdi.name, &sshdr); -#endif break; default: - sr_printk(KERN_ERR, cd, - "CDROM (ioctl) error, command: "); - __scsi_print_command(cgc->cmd, CDROM_PACKET_SIZE); - scsi_print_sense_hdr(cd->device, cd->cdi.name, &sshdr); err = -EIO; } } diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 128d3b55bdd9..9a1c34205254 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -4551,18 +4551,15 @@ static int sgl_map_user_pages(struct st_buffer *STbp, return -ENOMEM; /* Try to fault in all of the necessary pages */ - down_read(¤t->mm->mmap_sem); /* rw==READ means read from drive, write into memory area */ - res = get_user_pages( + res = get_user_pages_unlocked( current, current->mm, uaddr, nr_pages, rw == READ, 0, /* don't force */ - pages, - NULL); - up_read(¤t->mm->mmap_sem); + pages); /* Errors and no page mapped should return here */ if (res < nr_pages) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 4cff0ddc2c25..efc6e446b6c8 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -309,14 +308,6 @@ enum storvsc_request_type { * This is the end of Protocol specific defines. */ - -/* - * We setup a mempool to allocate request structures for this driver - * on a per-lun basis. The following define specifies the number of - * elements in the pool. - */ - -#define STORVSC_MIN_BUF_NR 64 static int storvsc_ringbuffer_size = (20 * PAGE_SIZE); module_param(storvsc_ringbuffer_size, int, S_IRUGO); @@ -346,7 +337,6 @@ static void storvsc_on_channel_callback(void *context); #define STORVSC_IDE_MAX_CHANNELS 1 struct storvsc_cmd_request { - struct list_head entry; struct scsi_cmnd *cmd; unsigned int bounce_sgl_count; @@ -357,7 +347,6 @@ struct storvsc_cmd_request { /* Synchronize the request/response if needed */ struct completion wait_event; - unsigned char *sense_buffer; struct hv_multipage_buffer data_buffer; struct vstor_packet vstor_packet; }; @@ -389,11 +378,6 @@ struct storvsc_device { struct storvsc_cmd_request reset_request; }; -struct stor_mem_pools { - struct kmem_cache *request_pool; - mempool_t *request_mempool; -}; - struct hv_host_device { struct hv_device *dev; unsigned int port; @@ -426,21 +410,42 @@ done: kfree(wrk); } -static void storvsc_bus_scan(struct work_struct *work) +static void storvsc_host_scan(struct work_struct *work) { struct storvsc_scan_work *wrk; - int id, order_id; + struct Scsi_Host *host; + struct scsi_device *sdev; + unsigned long flags; wrk = container_of(work, struct storvsc_scan_work, work); - for (id = 0; id < wrk->host->max_id; ++id) { - if (wrk->host->reverse_ordering) - order_id = wrk->host->max_id - id - 1; - else - order_id = id; + host = wrk->host; - scsi_scan_target(&wrk->host->shost_gendev, 0, - order_id, SCAN_WILD_CARD, 1); + /* + * Before scanning the host, first check to see if any of the + * currrently known devices have been hot removed. We issue a + * "unit ready" command against all currently known devices. + * This I/O will result in an error for devices that have been + * removed. As part of handling the I/O error, we remove the device. + * + * When a LUN is added or removed, the host sends us a signal to + * scan the host. Thus we are forced to discover the LUNs that + * may have been removed this way. + */ + mutex_lock(&host->scan_mutex); + spin_lock_irqsave(host->host_lock, flags); + list_for_each_entry(sdev, &host->__devices, siblings) { + spin_unlock_irqrestore(host->host_lock, flags); + scsi_test_unit_ready(sdev, 1, 1, NULL); + spin_lock_irqsave(host->host_lock, flags); + continue; } + spin_unlock_irqrestore(host->host_lock, flags); + mutex_unlock(&host->scan_mutex); + /* + * Now scan the host to discover LUNs that may have been added. + */ + scsi_scan_host(host); + kfree(wrk); } @@ -1070,10 +1075,8 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) { struct scsi_cmnd *scmnd = cmd_request->cmd; struct hv_host_device *host_dev = shost_priv(scmnd->device->host); - void (*scsi_done_fn)(struct scsi_cmnd *); struct scsi_sense_hdr sense_hdr; struct vmscsi_request *vm_srb; - struct stor_mem_pools *memp = scmnd->device->hostdata; struct Scsi_Host *host; struct storvsc_device *stor_dev; struct hv_device *dev = host_dev->dev; @@ -1109,14 +1112,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) cmd_request->data_buffer.len - vm_srb->data_transfer_length); - scsi_done_fn = scmnd->scsi_done; - - scmnd->host_scribble = NULL; - scmnd->scsi_done = NULL; - - scsi_done_fn(scmnd); - - mempool_free(cmd_request, memp->request_mempool); + scmnd->scsi_done(scmnd); } static void storvsc_on_io_completion(struct hv_device *device, @@ -1160,7 +1156,7 @@ static void storvsc_on_io_completion(struct hv_device *device, SRB_STATUS_AUTOSENSE_VALID) { /* autosense data available */ - memcpy(request->sense_buffer, + memcpy(request->cmd->sense_buffer, vstor_packet->vm_srb.sense_data, vstor_packet->vm_srb.sense_info_length); @@ -1198,7 +1194,7 @@ static void storvsc_on_receive(struct hv_device *device, if (!work) return; - INIT_WORK(&work->work, storvsc_bus_scan); + INIT_WORK(&work->work, storvsc_host_scan); work->host = stor_device->host; schedule_work(&work->work); break; @@ -1378,55 +1374,6 @@ static int storvsc_do_io(struct hv_device *device, return ret; } -static int storvsc_device_alloc(struct scsi_device *sdevice) -{ - struct stor_mem_pools *memp; - int number = STORVSC_MIN_BUF_NR; - - memp = kzalloc(sizeof(struct stor_mem_pools), GFP_KERNEL); - if (!memp) - return -ENOMEM; - - memp->request_pool = - kmem_cache_create(dev_name(&sdevice->sdev_dev), - sizeof(struct storvsc_cmd_request), 0, - SLAB_HWCACHE_ALIGN, NULL); - - if (!memp->request_pool) - goto err0; - - memp->request_mempool = mempool_create(number, mempool_alloc_slab, - mempool_free_slab, - memp->request_pool); - - if (!memp->request_mempool) - goto err1; - - sdevice->hostdata = memp; - - return 0; - -err1: - kmem_cache_destroy(memp->request_pool); - -err0: - kfree(memp); - return -ENOMEM; -} - -static void storvsc_device_destroy(struct scsi_device *sdevice) -{ - struct stor_mem_pools *memp = sdevice->hostdata; - - if (!memp) - return; - - mempool_destroy(memp->request_mempool); - kmem_cache_destroy(memp->request_pool); - kfree(memp); - sdevice->hostdata = NULL; -} - static int storvsc_device_configure(struct scsi_device *sdevice) { scsi_change_queue_depth(sdevice, STORVSC_MAX_IO_REQUESTS); @@ -1447,6 +1394,19 @@ static int storvsc_device_configure(struct scsi_device *sdevice) */ sdevice->sdev_bflags |= msft_blist_flags; + /* + * If the host is WIN8 or WIN8 R2, claim conformance to SPC-3 + * if the device is a MSFT virtual device. + */ + if (!strncmp(sdevice->vendor, "Msft", 4)) { + switch (vmbus_proto_version) { + case VERSION_WIN8: + case VERSION_WIN8_1: + sdevice->scsi_level = SCSI_SPC_3; + break; + } + } + return 0; } @@ -1561,13 +1521,11 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) int ret; struct hv_host_device *host_dev = shost_priv(host); struct hv_device *dev = host_dev->dev; - struct storvsc_cmd_request *cmd_request; - unsigned int request_size = 0; + struct storvsc_cmd_request *cmd_request = scsi_cmd_priv(scmnd); int i; struct scatterlist *sgl; unsigned int sg_count = 0; struct vmscsi_request *vm_srb; - struct stor_mem_pools *memp = scmnd->device->hostdata; if (vmstor_current_major <= VMSTOR_WIN8_MAJOR) { /* @@ -1584,25 +1542,9 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) } } - request_size = sizeof(struct storvsc_cmd_request); - - cmd_request = mempool_alloc(memp->request_mempool, - GFP_ATOMIC); - - /* - * We might be invoked in an interrupt context; hence - * mempool_alloc() can fail. - */ - if (!cmd_request) - return SCSI_MLQUEUE_DEVICE_BUSY; - - memset(cmd_request, 0, sizeof(struct storvsc_cmd_request)); - /* Setup the cmd request */ cmd_request->cmd = scmnd; - scmnd->host_scribble = (unsigned char *)cmd_request; - vm_srb = &cmd_request->vstor_packet.vm_srb; vm_srb->win8_extension.time_out_value = 60; @@ -1637,9 +1579,6 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) memcpy(vm_srb->cdb, scmnd->cmnd, vm_srb->cdb_length); - cmd_request->sense_buffer = scmnd->sense_buffer; - - cmd_request->data_buffer.len = scsi_bufflen(scmnd); if (scsi_sg_count(scmnd)) { sgl = (struct scatterlist *)scsi_sglist(scmnd); @@ -1651,10 +1590,8 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) create_bounce_buffer(sgl, scsi_sg_count(scmnd), scsi_bufflen(scmnd), vm_srb->data_in); - if (!cmd_request->bounce_sgl) { - ret = SCSI_MLQUEUE_HOST_BUSY; - goto queue_error; - } + if (!cmd_request->bounce_sgl) + return SCSI_MLQUEUE_HOST_BUSY; cmd_request->bounce_sgl_count = ALIGN(scsi_bufflen(scmnd), PAGE_SIZE) >> @@ -1692,27 +1629,21 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) destroy_bounce_buffer(cmd_request->bounce_sgl, cmd_request->bounce_sgl_count); - ret = SCSI_MLQUEUE_DEVICE_BUSY; - goto queue_error; + return SCSI_MLQUEUE_DEVICE_BUSY; } return 0; - -queue_error: - mempool_free(cmd_request, memp->request_mempool); - scmnd->host_scribble = NULL; - return ret; } static struct scsi_host_template scsi_driver = { .module = THIS_MODULE, .name = "storvsc_host_t", + .cmd_size = sizeof(struct storvsc_cmd_request), .bios_param = storvsc_get_chs, .queuecommand = storvsc_queuecommand, .eh_host_reset_handler = storvsc_host_reset_handler, + .proc_name = "storvsc_host", .eh_timed_out = storvsc_eh_timed_out, - .slave_alloc = storvsc_device_alloc, - .slave_destroy = storvsc_device_destroy, .slave_configure = storvsc_device_configure, .cmd_per_lun = 255, .can_queue = STORVSC_MAX_IO_REQUESTS*STORVSC_MAX_TARGETS, @@ -1760,6 +1691,9 @@ static int storvsc_probe(struct hv_device *device, bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false); int target = 0; struct storvsc_device *stor_device; + int max_luns_per_target; + int max_targets; + int max_channels; /* * Based on the windows host we are running on, @@ -1773,12 +1707,18 @@ static int storvsc_probe(struct hv_device *device, vmscsi_size_delta = sizeof(struct vmscsi_win8_extension); vmstor_current_major = VMSTOR_WIN7_MAJOR; vmstor_current_minor = VMSTOR_WIN7_MINOR; + max_luns_per_target = STORVSC_IDE_MAX_LUNS_PER_TARGET; + max_targets = STORVSC_IDE_MAX_TARGETS; + max_channels = STORVSC_IDE_MAX_CHANNELS; break; default: sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE; vmscsi_size_delta = 0; vmstor_current_major = VMSTOR_WIN8_MAJOR; vmstor_current_minor = VMSTOR_WIN8_MINOR; + max_luns_per_target = STORVSC_MAX_LUNS_PER_TARGET; + max_targets = STORVSC_MAX_TARGETS; + max_channels = STORVSC_MAX_CHANNELS; break; } @@ -1826,9 +1766,9 @@ static int storvsc_probe(struct hv_device *device, break; case SCSI_GUID: - host->max_lun = STORVSC_MAX_LUNS_PER_TARGET; - host->max_id = STORVSC_MAX_TARGETS; - host->max_channel = STORVSC_MAX_CHANNELS - 1; + host->max_lun = max_luns_per_target; + host->max_id = max_targets; + host->max_channel = max_channels - 1; break; default: diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 6e07b2afddeb..8a1f4b355416 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -70,3 +70,16 @@ config SCSI_UFSHCD_PLATFORM If you have a controller with this interface, say Y or M here. If unsure, say N. + +config SCSI_UFS_QCOM + bool "QCOM specific hooks to UFS controller platform driver" + depends on SCSI_UFSHCD_PLATFORM && ARCH_MSM + select PHY_QCOM_UFS + help + This selects the QCOM specific additions to UFSHCD platform driver. + UFS host on QCOM needs some vendor specific configuration before + accessing the hardware which includes PHY configuration and vendor + specific registers. + + Select this if you have UFS controller on QCOM chipset. + If unsure, say N. diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index 1e5bd48457d6..8303bcce7a23 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -1,4 +1,5 @@ # UFSHCD makefile +obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c new file mode 100644 index 000000000000..9217af9bf734 --- /dev/null +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -0,0 +1,1004 @@ +/* + * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include + +#include +#include "ufshcd.h" +#include "unipro.h" +#include "ufs-qcom.h" +#include "ufshci.h" + +static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS]; + +static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result); +static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, + const char *speed_mode); +static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote); + +static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes) +{ + int err = 0; + + err = ufshcd_dme_get(hba, + UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), tx_lanes); + if (err) + dev_err(hba->dev, "%s: couldn't read PA_CONNECTEDTXDATALANES %d\n", + __func__, err); + + return err; +} + +static int ufs_qcom_host_clk_get(struct device *dev, + const char *name, struct clk **clk_out) +{ + struct clk *clk; + int err = 0; + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) { + err = PTR_ERR(clk); + dev_err(dev, "%s: failed to get %s err %d", + __func__, name, err); + } else { + *clk_out = clk; + } + + return err; +} + +static int ufs_qcom_host_clk_enable(struct device *dev, + const char *name, struct clk *clk) +{ + int err = 0; + + err = clk_prepare_enable(clk); + if (err) + dev_err(dev, "%s: %s enable failed %d\n", __func__, name, err); + + return err; +} + +static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host) +{ + if (!host->is_lane_clks_enabled) + return; + + clk_disable_unprepare(host->tx_l1_sync_clk); + clk_disable_unprepare(host->tx_l0_sync_clk); + clk_disable_unprepare(host->rx_l1_sync_clk); + clk_disable_unprepare(host->rx_l0_sync_clk); + + host->is_lane_clks_enabled = false; +} + +static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host) +{ + int err = 0; + struct device *dev = host->hba->dev; + + if (host->is_lane_clks_enabled) + return 0; + + err = ufs_qcom_host_clk_enable(dev, "rx_lane0_sync_clk", + host->rx_l0_sync_clk); + if (err) + goto out; + + err = ufs_qcom_host_clk_enable(dev, "tx_lane0_sync_clk", + host->tx_l0_sync_clk); + if (err) + goto disable_rx_l0; + + err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk", + host->rx_l1_sync_clk); + if (err) + goto disable_tx_l0; + + err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk", + host->tx_l1_sync_clk); + if (err) + goto disable_rx_l1; + + host->is_lane_clks_enabled = true; + goto out; + +disable_rx_l1: + clk_disable_unprepare(host->rx_l1_sync_clk); +disable_tx_l0: + clk_disable_unprepare(host->tx_l0_sync_clk); +disable_rx_l0: + clk_disable_unprepare(host->rx_l0_sync_clk); +out: + return err; +} + +static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) +{ + int err = 0; + struct device *dev = host->hba->dev; + + err = ufs_qcom_host_clk_get(dev, + "rx_lane0_sync_clk", &host->rx_l0_sync_clk); + if (err) + goto out; + + err = ufs_qcom_host_clk_get(dev, + "tx_lane0_sync_clk", &host->tx_l0_sync_clk); + if (err) + goto out; + + err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk", + &host->rx_l1_sync_clk); + if (err) + goto out; + + err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk", + &host->tx_l1_sync_clk); +out: + return err; +} + +static int ufs_qcom_link_startup_post_change(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = hba->priv; + struct phy *phy = host->generic_phy; + u32 tx_lanes; + int err = 0; + + err = ufs_qcom_get_connected_tx_lanes(hba, &tx_lanes); + if (err) + goto out; + + err = ufs_qcom_phy_set_tx_lane_enable(phy, tx_lanes); + if (err) + dev_err(hba->dev, "%s: ufs_qcom_phy_set_tx_lane_enable failed\n", + __func__); + +out: + return err; +} + +static int ufs_qcom_check_hibern8(struct ufs_hba *hba) +{ + int err; + u32 tx_fsm_val = 0; + unsigned long timeout = jiffies + msecs_to_jiffies(HBRN8_POLL_TOUT_MS); + + do { + err = ufshcd_dme_get(hba, + UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val); + if (err || tx_fsm_val == TX_FSM_HIBERN8) + break; + + /* sleep for max. 200us */ + usleep_range(100, 200); + } while (time_before(jiffies, timeout)); + + /* + * we might have scheduled out for long during polling so + * check the state again. + */ + if (time_after(jiffies, timeout)) + err = ufshcd_dme_get(hba, + UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val); + + if (err) { + dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n", + __func__, err); + } else if (tx_fsm_val != TX_FSM_HIBERN8) { + err = tx_fsm_val; + dev_err(hba->dev, "%s: invalid TX_FSM_STATE = %d\n", + __func__, err); + } + + return err; +} + +static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = hba->priv; + struct phy *phy = host->generic_phy; + int ret = 0; + u8 major; + u16 minor, step; + bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B) + ? true : false; + + /* Assert PHY reset and apply PHY calibration values */ + ufs_qcom_assert_reset(hba); + /* provide 1ms delay to let the reset pulse propagate */ + usleep_range(1000, 1100); + + ufs_qcom_get_controller_revision(hba, &major, &minor, &step); + ufs_qcom_phy_save_controller_version(phy, major, minor, step); + ret = ufs_qcom_phy_calibrate_phy(phy, is_rate_B); + if (ret) { + dev_err(hba->dev, "%s: ufs_qcom_phy_calibrate_phy() failed, ret = %d\n", + __func__, ret); + goto out; + } + + /* De-assert PHY reset and start serdes */ + ufs_qcom_deassert_reset(hba); + + /* + * after reset deassertion, phy will need all ref clocks, + * voltage, current to settle down before starting serdes. + */ + usleep_range(1000, 1100); + ret = ufs_qcom_phy_start_serdes(phy); + if (ret) { + dev_err(hba->dev, "%s: ufs_qcom_phy_start_serdes() failed, ret = %d\n", + __func__, ret); + goto out; + } + + ret = ufs_qcom_phy_is_pcs_ready(phy); + if (ret) + dev_err(hba->dev, "%s: is_physical_coding_sublayer_ready() failed, ret = %d\n", + __func__, ret); + +out: + return ret; +} + +/* + * The UTP controller has a number of internal clock gating cells (CGCs). + * Internal hardware sub-modules within the UTP controller control the CGCs. + * Hardware CGCs disable the clock to inactivate UTP sub-modules not involved + * in a specific operation, UTP controller CGCs are by default disabled and + * this function enables them (after every UFS link startup) to save some power + * leakage. + */ +static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba) +{ + ufshcd_writel(hba, + ufshcd_readl(hba, REG_UFS_CFG2) | REG_UFS_CFG2_CGC_EN_ALL, + REG_UFS_CFG2); + + /* Ensure that HW clock gating is enabled before next operations */ + mb(); +} + +static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status) +{ + struct ufs_qcom_host *host = hba->priv; + int err = 0; + + switch (status) { + case PRE_CHANGE: + ufs_qcom_power_up_sequence(hba); + /* + * The PHY PLL output is the source of tx/rx lane symbol + * clocks, hence, enable the lane clocks only after PHY + * is initialized. + */ + err = ufs_qcom_enable_lane_clks(host); + break; + case POST_CHANGE: + /* check if UFS PHY moved from DISABLED to HIBERN8 */ + err = ufs_qcom_check_hibern8(hba); + ufs_qcom_enable_hw_clk_gating(hba); + + break; + default: + dev_err(hba->dev, "%s: invalid status %d\n", __func__, status); + err = -EINVAL; + break; + } + return err; +} + +/** + * Returns non-zero for success (which rate of core_clk) and 0 + * in case of a failure + */ +static unsigned long +ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) +{ + struct ufs_clk_info *clki; + u32 core_clk_period_in_ns; + u32 tx_clk_cycles_per_us = 0; + unsigned long core_clk_rate = 0; + u32 core_clk_cycles_per_us = 0; + + static u32 pwm_fr_table[][2] = { + {UFS_PWM_G1, 0x1}, + {UFS_PWM_G2, 0x1}, + {UFS_PWM_G3, 0x1}, + {UFS_PWM_G4, 0x1}, + }; + + static u32 hs_fr_table_rA[][2] = { + {UFS_HS_G1, 0x1F}, + {UFS_HS_G2, 0x3e}, + }; + + static u32 hs_fr_table_rB[][2] = { + {UFS_HS_G1, 0x24}, + {UFS_HS_G2, 0x49}, + }; + + if (gear == 0) { + dev_err(hba->dev, "%s: invalid gear = %d\n", __func__, gear); + goto out_error; + } + + list_for_each_entry(clki, &hba->clk_list_head, list) { + if (!strcmp(clki->name, "core_clk")) + core_clk_rate = clk_get_rate(clki->clk); + } + + /* If frequency is smaller than 1MHz, set to 1MHz */ + if (core_clk_rate < DEFAULT_CLK_RATE_HZ) + core_clk_rate = DEFAULT_CLK_RATE_HZ; + + core_clk_cycles_per_us = core_clk_rate / USEC_PER_SEC; + ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US); + + core_clk_period_in_ns = NSEC_PER_SEC / core_clk_rate; + core_clk_period_in_ns <<= OFFSET_CLK_NS_REG; + core_clk_period_in_ns &= MASK_CLK_NS_REG; + + switch (hs) { + case FASTAUTO_MODE: + case FAST_MODE: + if (rate == PA_HS_MODE_A) { + if (gear > ARRAY_SIZE(hs_fr_table_rA)) { + dev_err(hba->dev, + "%s: index %d exceeds table size %zu\n", + __func__, gear, + ARRAY_SIZE(hs_fr_table_rA)); + goto out_error; + } + tx_clk_cycles_per_us = hs_fr_table_rA[gear-1][1]; + } else if (rate == PA_HS_MODE_B) { + if (gear > ARRAY_SIZE(hs_fr_table_rB)) { + dev_err(hba->dev, + "%s: index %d exceeds table size %zu\n", + __func__, gear, + ARRAY_SIZE(hs_fr_table_rB)); + goto out_error; + } + tx_clk_cycles_per_us = hs_fr_table_rB[gear-1][1]; + } else { + dev_err(hba->dev, "%s: invalid rate = %d\n", + __func__, rate); + goto out_error; + } + break; + case SLOWAUTO_MODE: + case SLOW_MODE: + if (gear > ARRAY_SIZE(pwm_fr_table)) { + dev_err(hba->dev, + "%s: index %d exceeds table size %zu\n", + __func__, gear, + ARRAY_SIZE(pwm_fr_table)); + goto out_error; + } + tx_clk_cycles_per_us = pwm_fr_table[gear-1][1]; + break; + case UNCHANGED: + default: + dev_err(hba->dev, "%s: invalid mode = %d\n", __func__, hs); + goto out_error; + } + + /* this register 2 fields shall be written at once */ + ufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us, + REG_UFS_TX_SYMBOL_CLK_NS_US); + goto out; + +out_error: + core_clk_rate = 0; +out: + return core_clk_rate; +} + +static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, bool status) +{ + unsigned long core_clk_rate = 0; + u32 core_clk_cycles_per_100ms; + + switch (status) { + case PRE_CHANGE: + core_clk_rate = ufs_qcom_cfg_timers(hba, UFS_PWM_G1, + SLOWAUTO_MODE, 0); + if (!core_clk_rate) { + dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", + __func__); + return -EINVAL; + } + core_clk_cycles_per_100ms = + (core_clk_rate / MSEC_PER_SEC) * 100; + ufshcd_writel(hba, core_clk_cycles_per_100ms, + REG_UFS_PA_LINK_STARTUP_TIMER); + break; + case POST_CHANGE: + ufs_qcom_link_startup_post_change(hba); + break; + default: + break; + } + + return 0; +} + +static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) +{ + struct ufs_qcom_host *host = hba->priv; + struct phy *phy = host->generic_phy; + int ret = 0; + + if (ufs_qcom_is_link_off(hba)) { + /* + * Disable the tx/rx lane symbol clocks before PHY is + * powered down as the PLL source should be disabled + * after downstream clocks are disabled. + */ + ufs_qcom_disable_lane_clks(host); + phy_power_off(phy); + + /* Assert PHY soft reset */ + ufs_qcom_assert_reset(hba); + goto out; + } + + /* + * If UniPro link is not active, PHY ref_clk, main PHY analog power + * rail and low noise analog power rail for PLL can be switched off. + */ + if (!ufs_qcom_is_link_active(hba)) + phy_power_off(phy); + +out: + return ret; +} + +static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) +{ + struct ufs_qcom_host *host = hba->priv; + struct phy *phy = host->generic_phy; + int err; + + err = phy_power_on(phy); + if (err) { + dev_err(hba->dev, "%s: failed enabling regs, err = %d\n", + __func__, err); + goto out; + } + + hba->is_sys_suspended = false; + +out: + return err; +} + +struct ufs_qcom_dev_params { + u32 pwm_rx_gear; /* pwm rx gear to work in */ + u32 pwm_tx_gear; /* pwm tx gear to work in */ + u32 hs_rx_gear; /* hs rx gear to work in */ + u32 hs_tx_gear; /* hs tx gear to work in */ + u32 rx_lanes; /* number of rx lanes */ + u32 tx_lanes; /* number of tx lanes */ + u32 rx_pwr_pwm; /* rx pwm working pwr */ + u32 tx_pwr_pwm; /* tx pwm working pwr */ + u32 rx_pwr_hs; /* rx hs working pwr */ + u32 tx_pwr_hs; /* tx hs working pwr */ + u32 hs_rate; /* rate A/B to work in HS */ + u32 desired_working_mode; +}; + +static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param, + struct ufs_pa_layer_attr *dev_max, + struct ufs_pa_layer_attr *agreed_pwr) +{ + int min_qcom_gear; + int min_dev_gear; + bool is_dev_sup_hs = false; + bool is_qcom_max_hs = false; + + if (dev_max->pwr_rx == FAST_MODE) + is_dev_sup_hs = true; + + if (qcom_param->desired_working_mode == FAST) { + is_qcom_max_hs = true; + min_qcom_gear = min_t(u32, qcom_param->hs_rx_gear, + qcom_param->hs_tx_gear); + } else { + min_qcom_gear = min_t(u32, qcom_param->pwm_rx_gear, + qcom_param->pwm_tx_gear); + } + + /* + * device doesn't support HS but qcom_param->desired_working_mode is + * HS, thus device and qcom_param don't agree + */ + if (!is_dev_sup_hs && is_qcom_max_hs) { + pr_err("%s: failed to agree on power mode (device doesn't support HS but requested power is HS)\n", + __func__); + return -ENOTSUPP; + } else if (is_dev_sup_hs && is_qcom_max_hs) { + /* + * since device supports HS, it supports FAST_MODE. + * since qcom_param->desired_working_mode is also HS + * then final decision (FAST/FASTAUTO) is done according + * to qcom_params as it is the restricting factor + */ + agreed_pwr->pwr_rx = agreed_pwr->pwr_tx = + qcom_param->rx_pwr_hs; + } else { + /* + * here qcom_param->desired_working_mode is PWM. + * it doesn't matter whether device supports HS or PWM, + * in both cases qcom_param->desired_working_mode will + * determine the mode + */ + agreed_pwr->pwr_rx = agreed_pwr->pwr_tx = + qcom_param->rx_pwr_pwm; + } + + /* + * we would like tx to work in the minimum number of lanes + * between device capability and vendor preferences. + * the same decision will be made for rx + */ + agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx, + qcom_param->tx_lanes); + agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx, + qcom_param->rx_lanes); + + /* device maximum gear is the minimum between device rx and tx gears */ + min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx); + + /* + * if both device capabilities and vendor pre-defined preferences are + * both HS or both PWM then set the minimum gear to be the chosen + * working gear. + * if one is PWM and one is HS then the one that is PWM get to decide + * what is the gear, as it is the one that also decided previously what + * pwr the device will be configured to. + */ + if ((is_dev_sup_hs && is_qcom_max_hs) || + (!is_dev_sup_hs && !is_qcom_max_hs)) + agreed_pwr->gear_rx = agreed_pwr->gear_tx = + min_t(u32, min_dev_gear, min_qcom_gear); + else if (!is_dev_sup_hs) + agreed_pwr->gear_rx = agreed_pwr->gear_tx = min_dev_gear; + else + agreed_pwr->gear_rx = agreed_pwr->gear_tx = min_qcom_gear; + + agreed_pwr->hs_rate = qcom_param->hs_rate; + return 0; +} + +static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) +{ + int vote; + int err = 0; + char mode[BUS_VECTOR_NAME_LEN]; + + ufs_qcom_get_speed_mode(&host->dev_req_params, mode); + + vote = ufs_qcom_get_bus_vote(host, mode); + if (vote >= 0) + err = ufs_qcom_set_bus_vote(host, vote); + else + err = vote; + + if (err) + dev_err(host->hba->dev, "%s: failed %d\n", __func__, err); + else + host->bus_vote.saved_vote = vote; + return err; +} + +static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, + bool status, + struct ufs_pa_layer_attr *dev_max_params, + struct ufs_pa_layer_attr *dev_req_params) +{ + u32 val; + struct ufs_qcom_host *host = hba->priv; + struct phy *phy = host->generic_phy; + struct ufs_qcom_dev_params ufs_qcom_cap; + int ret = 0; + int res = 0; + + if (!dev_req_params) { + pr_err("%s: incoming dev_req_params is NULL\n", __func__); + ret = -EINVAL; + goto out; + } + + switch (status) { + case PRE_CHANGE: + ufs_qcom_cap.tx_lanes = UFS_QCOM_LIMIT_NUM_LANES_TX; + ufs_qcom_cap.rx_lanes = UFS_QCOM_LIMIT_NUM_LANES_RX; + ufs_qcom_cap.hs_rx_gear = UFS_QCOM_LIMIT_HSGEAR_RX; + ufs_qcom_cap.hs_tx_gear = UFS_QCOM_LIMIT_HSGEAR_TX; + ufs_qcom_cap.pwm_rx_gear = UFS_QCOM_LIMIT_PWMGEAR_RX; + ufs_qcom_cap.pwm_tx_gear = UFS_QCOM_LIMIT_PWMGEAR_TX; + ufs_qcom_cap.rx_pwr_pwm = UFS_QCOM_LIMIT_RX_PWR_PWM; + ufs_qcom_cap.tx_pwr_pwm = UFS_QCOM_LIMIT_TX_PWR_PWM; + ufs_qcom_cap.rx_pwr_hs = UFS_QCOM_LIMIT_RX_PWR_HS; + ufs_qcom_cap.tx_pwr_hs = UFS_QCOM_LIMIT_TX_PWR_HS; + ufs_qcom_cap.hs_rate = UFS_QCOM_LIMIT_HS_RATE; + ufs_qcom_cap.desired_working_mode = + UFS_QCOM_LIMIT_DESIRED_MODE; + + ret = ufs_qcom_get_pwr_dev_param(&ufs_qcom_cap, + dev_max_params, + dev_req_params); + if (ret) { + pr_err("%s: failed to determine capabilities\n", + __func__); + goto out; + } + + break; + case POST_CHANGE: + if (!ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, + dev_req_params->pwr_rx, + dev_req_params->hs_rate)) { + dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", + __func__); + /* + * we return error code at the end of the routine, + * but continue to configure UFS_PHY_TX_LANE_ENABLE + * and bus voting as usual + */ + ret = -EINVAL; + } + + val = ~(MAX_U32 << dev_req_params->lane_tx); + res = ufs_qcom_phy_set_tx_lane_enable(phy, val); + if (res) { + dev_err(hba->dev, "%s: ufs_qcom_phy_set_tx_lane_enable() failed res = %d\n", + __func__, res); + ret = res; + } + + /* cache the power mode parameters to use internally */ + memcpy(&host->dev_req_params, + dev_req_params, sizeof(*dev_req_params)); + ufs_qcom_update_bus_bw_vote(host); + break; + default: + ret = -EINVAL; + break; + } +out: + return ret; +} + +/** + * ufs_qcom_advertise_quirks - advertise the known QCOM UFS controller quirks + * @hba: host controller instance + * + * QCOM UFS host controller might have some non standard behaviours (quirks) + * than what is specified by UFSHCI specification. Advertise all such + * quirks to standard UFS host controller driver so standard takes them into + * account. + */ +static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) +{ + u8 major; + u16 minor, step; + + ufs_qcom_get_controller_revision(hba, &major, &minor, &step); + + /* + * TBD + * here we should be advertising controller quirks according to + * controller version. + */ +} + +static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, + const char *speed_mode) +{ + struct device *dev = host->hba->dev; + struct device_node *np = dev->of_node; + int err; + const char *key = "qcom,bus-vector-names"; + + if (!speed_mode) { + err = -EINVAL; + goto out; + } + + if (host->bus_vote.is_max_bw_needed && !!strcmp(speed_mode, "MIN")) + err = of_property_match_string(np, key, "MAX"); + else + err = of_property_match_string(np, key, speed_mode); + +out: + if (err < 0) + dev_err(dev, "%s: Invalid %s mode %d\n", + __func__, speed_mode, err); + return err; +} + +static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) +{ + int err = 0; + + if (vote != host->bus_vote.curr_vote) + host->bus_vote.curr_vote = vote; + + return err; +} + +static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result) +{ + int gear = max_t(u32, p->gear_rx, p->gear_tx); + int lanes = max_t(u32, p->lane_rx, p->lane_tx); + int pwr; + + /* default to PWM Gear 1, Lane 1 if power mode is not initialized */ + if (!gear) + gear = 1; + + if (!lanes) + lanes = 1; + + if (!p->pwr_rx && !p->pwr_tx) { + pwr = SLOWAUTO_MODE; + snprintf(result, BUS_VECTOR_NAME_LEN, "MIN"); + } else if (p->pwr_rx == FAST_MODE || p->pwr_rx == FASTAUTO_MODE || + p->pwr_tx == FAST_MODE || p->pwr_tx == FASTAUTO_MODE) { + pwr = FAST_MODE; + snprintf(result, BUS_VECTOR_NAME_LEN, "%s_R%s_G%d_L%d", "HS", + p->hs_rate == PA_HS_MODE_B ? "B" : "A", gear, lanes); + } else { + pwr = SLOW_MODE; + snprintf(result, BUS_VECTOR_NAME_LEN, "%s_G%d_L%d", + "PWM", gear, lanes); + } +} + +static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on) +{ + struct ufs_qcom_host *host = hba->priv; + int err = 0; + int vote = 0; + + /* + * In case ufs_qcom_init() is not yet done, simply ignore. + * This ufs_qcom_setup_clocks() shall be called from + * ufs_qcom_init() after init is done. + */ + if (!host) + return 0; + + if (on) { + err = ufs_qcom_phy_enable_iface_clk(host->generic_phy); + if (err) + goto out; + + err = ufs_qcom_phy_enable_ref_clk(host->generic_phy); + if (err) { + dev_err(hba->dev, "%s enable phy ref clock failed, err=%d\n", + __func__, err); + ufs_qcom_phy_disable_iface_clk(host->generic_phy); + goto out; + } + /* enable the device ref clock */ + ufs_qcom_phy_enable_dev_ref_clk(host->generic_phy); + vote = host->bus_vote.saved_vote; + if (vote == host->bus_vote.min_bw_vote) + ufs_qcom_update_bus_bw_vote(host); + } else { + /* M-PHY RMMI interface clocks can be turned off */ + ufs_qcom_phy_disable_iface_clk(host->generic_phy); + if (!ufs_qcom_is_link_active(hba)) { + /* turn off UFS local PHY ref_clk */ + ufs_qcom_phy_disable_ref_clk(host->generic_phy); + /* disable device ref_clk */ + ufs_qcom_phy_disable_dev_ref_clk(host->generic_phy); + } + vote = host->bus_vote.min_bw_vote; + } + + err = ufs_qcom_set_bus_vote(host, vote); + if (err) + dev_err(hba->dev, "%s: set bus vote failed %d\n", + __func__, err); + +out: + return err; +} + +static ssize_t +show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + struct ufs_qcom_host *host = hba->priv; + + return snprintf(buf, PAGE_SIZE, "%u\n", + host->bus_vote.is_max_bw_needed); +} + +static ssize_t +store_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + struct ufs_qcom_host *host = hba->priv; + uint32_t value; + + if (!kstrtou32(buf, 0, &value)) { + host->bus_vote.is_max_bw_needed = !!value; + ufs_qcom_update_bus_bw_vote(host); + } + + return count; +} + +static int ufs_qcom_bus_register(struct ufs_qcom_host *host) +{ + int err; + struct device *dev = host->hba->dev; + struct device_node *np = dev->of_node; + + err = of_property_count_strings(np, "qcom,bus-vector-names"); + if (err < 0 ) { + dev_err(dev, "%s: qcom,bus-vector-names not specified correctly %d\n", + __func__, err); + goto out; + } + + /* cache the vote index for minimum and maximum bandwidth */ + host->bus_vote.min_bw_vote = ufs_qcom_get_bus_vote(host, "MIN"); + host->bus_vote.max_bw_vote = ufs_qcom_get_bus_vote(host, "MAX"); + + host->bus_vote.max_bus_bw.show = show_ufs_to_mem_max_bus_bw; + host->bus_vote.max_bus_bw.store = store_ufs_to_mem_max_bus_bw; + sysfs_attr_init(&host->bus_vote.max_bus_bw.attr); + host->bus_vote.max_bus_bw.attr.name = "max_bus_bw"; + host->bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR; + err = device_create_file(dev, &host->bus_vote.max_bus_bw); +out: + return err; +} + +#define ANDROID_BOOT_DEV_MAX 30 +static char android_boot_dev[ANDROID_BOOT_DEV_MAX]; +static int get_android_boot_dev(char *str) +{ + strlcpy(android_boot_dev, str, ANDROID_BOOT_DEV_MAX); + return 1; +} +__setup("androidboot.bootdevice=", get_android_boot_dev); + +/** + * ufs_qcom_init - bind phy with controller + * @hba: host controller instance + * + * Binds PHY with controller and powers up PHY enabling clocks + * and regulators. + * + * Returns -EPROBE_DEFER if binding fails, returns negative error + * on phy power up failure and returns zero on success. + */ +static int ufs_qcom_init(struct ufs_hba *hba) +{ + int err; + struct device *dev = hba->dev; + struct ufs_qcom_host *host; + + if (strlen(android_boot_dev) && strcmp(android_boot_dev, dev_name(dev))) + return -ENODEV; + + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); + if (!host) { + err = -ENOMEM; + dev_err(dev, "%s: no memory for qcom ufs host\n", __func__); + goto out; + } + + host->hba = hba; + hba->priv = (void *)host; + + host->generic_phy = devm_phy_get(dev, "ufsphy"); + + if (IS_ERR(host->generic_phy)) { + err = PTR_ERR(host->generic_phy); + dev_err(dev, "%s: PHY get failed %d\n", __func__, err); + goto out; + } + + err = ufs_qcom_bus_register(host); + if (err) + goto out_host_free; + + phy_init(host->generic_phy); + err = phy_power_on(host->generic_phy); + if (err) + goto out_unregister_bus; + + err = ufs_qcom_init_lane_clks(host); + if (err) + goto out_disable_phy; + + ufs_qcom_advertise_quirks(hba); + + hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_CLK_SCALING; + hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND; + + ufs_qcom_setup_clocks(hba, true); + + if (hba->dev->id < MAX_UFS_QCOM_HOSTS) + ufs_qcom_hosts[hba->dev->id] = host; + + goto out; + +out_disable_phy: + phy_power_off(host->generic_phy); +out_unregister_bus: + phy_exit(host->generic_phy); +out_host_free: + devm_kfree(dev, host); + hba->priv = NULL; +out: + return err; +} + +static void ufs_qcom_exit(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = hba->priv; + + ufs_qcom_disable_lane_clks(host); + phy_power_off(host->generic_phy); +} + +static +void ufs_qcom_clk_scale_notify(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = hba->priv; + struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params; + + if (!dev_req_params) + return; + + ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, + dev_req_params->pwr_rx, + dev_req_params->hs_rate); +} + +/** + * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations + * + * The variant operations configure the necessary controller and PHY + * handshake during initialization. + */ +static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { + .name = "qcom", + .init = ufs_qcom_init, + .exit = ufs_qcom_exit, + .clk_scale_notify = ufs_qcom_clk_scale_notify, + .setup_clocks = ufs_qcom_setup_clocks, + .hce_enable_notify = ufs_qcom_hce_enable_notify, + .link_startup_notify = ufs_qcom_link_startup_notify, + .pwr_change_notify = ufs_qcom_pwr_change_notify, + .suspend = ufs_qcom_suspend, + .resume = ufs_qcom_resume, +}; +EXPORT_SYMBOL(ufs_hba_qcom_vops); diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h new file mode 100644 index 000000000000..9a6febd007df --- /dev/null +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -0,0 +1,170 @@ +/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef UFS_QCOM_H_ +#define UFS_QCOM_H_ + +#define MAX_UFS_QCOM_HOSTS 1 +#define MAX_U32 (~(u32)0) +#define MPHY_TX_FSM_STATE 0x41 +#define TX_FSM_HIBERN8 0x1 +#define HBRN8_POLL_TOUT_MS 100 +#define DEFAULT_CLK_RATE_HZ 1000000 +#define BUS_VECTOR_NAME_LEN 32 + +#define UFS_HW_VER_MAJOR_SHFT (28) +#define UFS_HW_VER_MAJOR_MASK (0x000F << UFS_HW_VER_MAJOR_SHFT) +#define UFS_HW_VER_MINOR_SHFT (16) +#define UFS_HW_VER_MINOR_MASK (0x0FFF << UFS_HW_VER_MINOR_SHFT) +#define UFS_HW_VER_STEP_SHFT (0) +#define UFS_HW_VER_STEP_MASK (0xFFFF << UFS_HW_VER_STEP_SHFT) + +/* vendor specific pre-defined parameters */ +#define SLOW 1 +#define FAST 2 + +#define UFS_QCOM_LIMIT_NUM_LANES_RX 2 +#define UFS_QCOM_LIMIT_NUM_LANES_TX 2 +#define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G2 +#define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G2 +#define UFS_QCOM_LIMIT_PWMGEAR_RX UFS_PWM_G4 +#define UFS_QCOM_LIMIT_PWMGEAR_TX UFS_PWM_G4 +#define UFS_QCOM_LIMIT_RX_PWR_PWM SLOW_MODE +#define UFS_QCOM_LIMIT_TX_PWR_PWM SLOW_MODE +#define UFS_QCOM_LIMIT_RX_PWR_HS FAST_MODE +#define UFS_QCOM_LIMIT_TX_PWR_HS FAST_MODE +#define UFS_QCOM_LIMIT_HS_RATE PA_HS_MODE_B +#define UFS_QCOM_LIMIT_DESIRED_MODE FAST + +/* QCOM UFS host controller vendor specific registers */ +enum { + REG_UFS_SYS1CLK_1US = 0xC0, + REG_UFS_TX_SYMBOL_CLK_NS_US = 0xC4, + REG_UFS_LOCAL_PORT_ID_REG = 0xC8, + REG_UFS_PA_ERR_CODE = 0xCC, + REG_UFS_RETRY_TIMER_REG = 0xD0, + REG_UFS_PA_LINK_STARTUP_TIMER = 0xD8, + REG_UFS_CFG1 = 0xDC, + REG_UFS_CFG2 = 0xE0, + REG_UFS_HW_VERSION = 0xE4, + + UFS_DBG_RD_REG_UAWM = 0x100, + UFS_DBG_RD_REG_UARM = 0x200, + UFS_DBG_RD_REG_TXUC = 0x300, + UFS_DBG_RD_REG_RXUC = 0x400, + UFS_DBG_RD_REG_DFC = 0x500, + UFS_DBG_RD_REG_TRLUT = 0x600, + UFS_DBG_RD_REG_TMRLUT = 0x700, + UFS_UFS_DBG_RD_REG_OCSC = 0x800, + + UFS_UFS_DBG_RD_DESC_RAM = 0x1500, + UFS_UFS_DBG_RD_PRDT_RAM = 0x1700, + UFS_UFS_DBG_RD_RESP_RAM = 0x1800, + UFS_UFS_DBG_RD_EDTL_RAM = 0x1900, +}; + +/* bit definitions for REG_UFS_CFG2 register */ +#define UAWM_HW_CGC_EN (1 << 0) +#define UARM_HW_CGC_EN (1 << 1) +#define TXUC_HW_CGC_EN (1 << 2) +#define RXUC_HW_CGC_EN (1 << 3) +#define DFC_HW_CGC_EN (1 << 4) +#define TRLUT_HW_CGC_EN (1 << 5) +#define TMRLUT_HW_CGC_EN (1 << 6) +#define OCSC_HW_CGC_EN (1 << 7) + +#define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\ + TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\ + DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\ + TMRLUT_HW_CGC_EN | OCSC_HW_CGC_EN) + +/* bit offset */ +enum { + OFFSET_UFS_PHY_SOFT_RESET = 1, + OFFSET_CLK_NS_REG = 10, +}; + +/* bit masks */ +enum { + MASK_UFS_PHY_SOFT_RESET = 0x2, + MASK_TX_SYMBOL_CLK_1US_REG = 0x3FF, + MASK_CLK_NS_REG = 0xFFFC00, +}; + +enum ufs_qcom_phy_init_type { + UFS_PHY_INIT_FULL, + UFS_PHY_INIT_CFG_RESTORE, +}; + +static inline void +ufs_qcom_get_controller_revision(struct ufs_hba *hba, + u8 *major, u16 *minor, u16 *step) +{ + u32 ver = ufshcd_readl(hba, REG_UFS_HW_VERSION); + + *major = (ver & UFS_HW_VER_MAJOR_MASK) >> UFS_HW_VER_MAJOR_SHFT; + *minor = (ver & UFS_HW_VER_MINOR_MASK) >> UFS_HW_VER_MINOR_SHFT; + *step = (ver & UFS_HW_VER_STEP_MASK) >> UFS_HW_VER_STEP_SHFT; +}; + +static inline void ufs_qcom_assert_reset(struct ufs_hba *hba) +{ + ufshcd_rmwl(hba, MASK_UFS_PHY_SOFT_RESET, + 1 << OFFSET_UFS_PHY_SOFT_RESET, REG_UFS_CFG1); + + /* + * Make sure assertion of ufs phy reset is written to + * register before returning + */ + mb(); +} + +static inline void ufs_qcom_deassert_reset(struct ufs_hba *hba) +{ + ufshcd_rmwl(hba, MASK_UFS_PHY_SOFT_RESET, + 0 << OFFSET_UFS_PHY_SOFT_RESET, REG_UFS_CFG1); + + /* + * Make sure de-assertion of ufs phy reset is written to + * register before returning + */ + mb(); +} + +struct ufs_qcom_bus_vote { + uint32_t client_handle; + uint32_t curr_vote; + int min_bw_vote; + int max_bw_vote; + int saved_vote; + bool is_max_bw_needed; + struct device_attribute max_bus_bw; +}; + +struct ufs_qcom_host { + struct phy *generic_phy; + struct ufs_hba *hba; + struct ufs_qcom_bus_vote bus_vote; + struct ufs_pa_layer_attr dev_req_params; + struct clk *rx_l0_sync_clk; + struct clk *tx_l0_sync_clk; + struct clk *rx_l1_sync_clk; + struct clk *tx_l1_sync_clk; + bool is_lane_clks_enabled; +}; + +#define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba) +#define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba) +#define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba) + +#endif /* UFS_QCOM_H_ */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 2e4614b9dddf..5d60a868830d 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4714,10 +4714,8 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, sdev_printk(KERN_WARNING, sdp, "START_STOP failed for power mode: %d, result %x\n", pwr_mode, ret); - if (driver_byte(ret) & DRIVER_SENSE) { - scsi_show_sense_hdr(sdp, NULL, &sshdr); - scsi_show_extd_sense(sdp, NULL, sshdr.asc, sshdr.ascq); - } + if (driver_byte(ret) & DRIVER_SENSE) + scsi_print_sense_hdr(sdp, NULL, &sshdr); } if (!ret) diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index c0506de4f3b6..9e09da412b92 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -2143,22 +2143,22 @@ wd33c93_show_info(struct seq_file *m, struct Scsi_Host *instance) seq_printf(m, "\nclock_freq=%02x no_sync=%02x no_dma=%d" " dma_mode=%02x fast=%d", hd->clock_freq, hd->no_sync, hd->no_dma, hd->dma_mode, hd->fast); - seq_printf(m, "\nsync_xfer[] = "); + seq_puts(m, "\nsync_xfer[] = "); for (x = 0; x < 7; x++) seq_printf(m, "\t%02x", hd->sync_xfer[x]); - seq_printf(m, "\nsync_stat[] = "); + seq_puts(m, "\nsync_stat[] = "); for (x = 0; x < 7; x++) seq_printf(m, "\t%02x", hd->sync_stat[x]); } #ifdef PROC_STATISTICS if (hd->proc & PR_STATISTICS) { - seq_printf(m, "\ncommands issued: "); + seq_puts(m, "\ncommands issued: "); for (x = 0; x < 7; x++) seq_printf(m, "\t%ld", hd->cmd_cnt[x]); - seq_printf(m, "\ndisconnects allowed:"); + seq_puts(m, "\ndisconnects allowed:"); for (x = 0; x < 7; x++) seq_printf(m, "\t%ld", hd->disc_allowed_cnt[x]); - seq_printf(m, "\ndisconnects done: "); + seq_puts(m, "\ndisconnects done: "); for (x = 0; x < 7; x++) seq_printf(m, "\t%ld", hd->disc_done_cnt[x]); seq_printf(m, @@ -2167,7 +2167,7 @@ wd33c93_show_info(struct seq_file *m, struct Scsi_Host *instance) } #endif if (hd->proc & PR_CONNECTED) { - seq_printf(m, "\nconnected: "); + seq_puts(m, "\nconnected: "); if (hd->connected) { cmd = (struct scsi_cmnd *) hd->connected; seq_printf(m, " %d:%llu(%02x)", @@ -2175,7 +2175,7 @@ wd33c93_show_info(struct seq_file *m, struct Scsi_Host *instance) } } if (hd->proc & PR_INPUTQ) { - seq_printf(m, "\ninput_Q: "); + seq_puts(m, "\ninput_Q: "); cmd = (struct scsi_cmnd *) hd->input_Q; while (cmd) { seq_printf(m, " %d:%llu(%02x)", @@ -2184,7 +2184,7 @@ wd33c93_show_info(struct seq_file *m, struct Scsi_Host *instance) } } if (hd->proc & PR_DISCQ) { - seq_printf(m, "\ndisconnected_Q:"); + seq_puts(m, "\ndisconnected_Q:"); cmd = (struct scsi_cmnd *) hd->disconnected_Q; while (cmd) { seq_printf(m, " %d:%llu(%02x)", @@ -2192,7 +2192,7 @@ wd33c93_show_info(struct seq_file *m, struct Scsi_Host *instance) cmd = (struct scsi_cmnd *) cmd->host_scribble; } } - seq_printf(m, "\n"); + seq_putc(m, '\n'); spin_unlock_irq(&hd->lock); #endif /* PROC_INTERFACE */ return 0; diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index f94d73611ab4..0c0f17b9a3eb 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -1295,9 +1295,6 @@ static void wd7000_revision(Adapter * host) } -#undef SPRINTF -#define SPRINTF(args...) { seq_printf(m, ## args); } - static int wd7000_set_info(struct Scsi_Host *host, char *buffer, int length) { dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length); @@ -1320,43 +1317,43 @@ static int wd7000_show_info(struct seq_file *m, struct Scsi_Host *host) #endif spin_lock_irqsave(host->host_lock, flags); - SPRINTF("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", host->host_no, adapter->rev1, adapter->rev2); - SPRINTF(" IO base: 0x%x\n", adapter->iobase); - SPRINTF(" IRQ: %d\n", adapter->irq); - SPRINTF(" DMA channel: %d\n", adapter->dma); - SPRINTF(" Interrupts: %d\n", adapter->int_counter); - SPRINTF(" BUS_ON time: %d nanoseconds\n", adapter->bus_on * 125); - SPRINTF(" BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125); + seq_printf(m, "Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", host->host_no, adapter->rev1, adapter->rev2); + seq_printf(m, " IO base: 0x%x\n", adapter->iobase); + seq_printf(m, " IRQ: %d\n", adapter->irq); + seq_printf(m, " DMA channel: %d\n", adapter->dma); + seq_printf(m, " Interrupts: %d\n", adapter->int_counter); + seq_printf(m, " BUS_ON time: %d nanoseconds\n", adapter->bus_on * 125); + seq_printf(m, " BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125); #ifdef WD7000_DEBUG ogmbs = adapter->mb.ogmb; icmbs = adapter->mb.icmb; - SPRINTF("\nControl port value: 0x%x\n", adapter->control); - SPRINTF("Incoming mailbox:\n"); - SPRINTF(" size: %d\n", ICMB_CNT); - SPRINTF(" queued messages: "); + seq_printf(m, "\nControl port value: 0x%x\n", adapter->control); + seq_puts(m, "Incoming mailbox:\n"); + seq_printf(m, " size: %d\n", ICMB_CNT); + seq_puts(m, " queued messages: "); for (i = count = 0; i < ICMB_CNT; i++) if (icmbs[i].status) { count++; - SPRINTF("0x%x ", i); + seq_printf(m, "0x%x ", i); } - SPRINTF(count ? "\n" : "none\n"); + seq_puts(m, count ? "\n" : "none\n"); - SPRINTF("Outgoing mailbox:\n"); - SPRINTF(" size: %d\n", OGMB_CNT); - SPRINTF(" next message: 0x%x\n", adapter->next_ogmb); - SPRINTF(" queued messages: "); + seq_puts(m, "Outgoing mailbox:\n"); + seq_printf(m, " size: %d\n", OGMB_CNT); + seq_printf(m, " next message: 0x%x\n", adapter->next_ogmb); + seq_puts(m, " queued messages: "); for (i = count = 0; i < OGMB_CNT; i++) if (ogmbs[i].status) { count++; - SPRINTF("0x%x ", i); + seq_printf(m, "0x%x ", i); } - SPRINTF(count ? "\n" : "none\n"); + seq_puts(m, count ? "\n" : "none\n"); #endif spin_unlock_irqrestore(host->host_lock, flags); diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c index 1e824fb1649b..296db7a69c27 100644 --- a/drivers/sfi/sfi_core.c +++ b/drivers/sfi/sfi_core.c @@ -161,7 +161,7 @@ static int sfi_verify_table(struct sfi_table_header *table) * Check for common case that we can re-use mapping to SYST, * which requires syst_pa, syst_va to be initialized. */ -struct sfi_table_header *sfi_map_table(u64 pa) +static struct sfi_table_header *sfi_map_table(u64 pa) { struct sfi_table_header *th; u32 length; @@ -189,7 +189,7 @@ struct sfi_table_header *sfi_map_table(u64 pa) * Undoes effect of sfi_map_table() by unmapping table * if it did not completely fit on same page as SYST. */ -void sfi_unmap_table(struct sfi_table_header *th) +static void sfi_unmap_table(struct sfi_table_header *th) { if (!TABLE_ON_PAGE(syst_va, th, th->len)) sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ? diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 99829985c1a1..95ccedabba4f 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -185,6 +185,16 @@ config SPI_DAVINCI help SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules. +config SPI_DLN2 + tristate "Diolan DLN-2 USB SPI adapter" + depends on MFD_DLN2 + help + If you say yes to this option, support will be included for Diolan + DLN2, a USB to SPI interface. + + This driver can also be built as a module. If so, the module + will be called spi-dln2. + config SPI_EFM32 tristate "EFM32 SPI controller" depends on OF && ARM && (ARCH_EFM32 || COMPILE_TEST) @@ -279,7 +289,7 @@ config SPI_FSL_CPM depends on FSL_SOC config SPI_FSL_SPI - bool "Freescale SPI controller and Aeroflex Gaisler GRLIB SPI controller" + tristate "Freescale SPI controller and Aeroflex Gaisler GRLIB SPI controller" depends on OF select SPI_FSL_LIB select SPI_FSL_CPM if FSL_SOC @@ -292,7 +302,6 @@ config SPI_FSL_SPI config SPI_FSL_DSPI tristate "Freescale DSPI controller" - select SPI_BITBANG select REGMAP_MMIO depends on SOC_VF610 || COMPILE_TEST help @@ -300,7 +309,7 @@ config SPI_FSL_DSPI mode. VF610 platform uses the controller. config SPI_FSL_ESPI - bool "Freescale eSPI controller" + tristate "Freescale eSPI controller" depends on FSL_SOC select SPI_FSL_LIB help @@ -460,7 +469,6 @@ config SPI_S3C24XX_FIQ config SPI_S3C64XX tristate "Samsung S3C64XX series type SPI" depends on (PLAT_SAMSUNG || ARCH_EXYNOS) - select S3C64XX_PL080 if ARCH_S3C64XX help SPI driver for Samsung S3C64XX and newer SoCs. @@ -503,6 +511,13 @@ config SPI_SIRF help SPI driver for CSR SiRFprimaII SoCs +config SPI_ST_SSC4 + tristate "STMicroelectronics SPI SSC-based driver" + depends on ARCH_STI + help + STMicroelectronics SoCs support for SPI. If you say yes to + this option, support will be included for the SSC driven SPI. + config SPI_SUN4I tristate "Allwinner A10 SoCs SPI controller" depends on ARCH_SUNXI || COMPILE_TEST @@ -595,7 +610,6 @@ config SPI_XTENSA_XTFPGA 16 bit words in SPI mode 0, automatically asserting CS on transfer start and deasserting on end. - config SPI_NUC900 tristate "Nuvoton NUC900 series SPI" depends on ARCH_W90X900 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 6b9d2ac629cc..d8cbf654976b 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SPI_CADENCE) += spi-cadence.o obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o +obj-$(CONFIG_SPI_DLN2) += spi-dln2.o obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o @@ -76,6 +77,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o obj-$(CONFIG_SPI_SIRF) += spi-sirf.o +obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 23d8f5f56579..9af7841f2e8c 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1046,6 +1046,7 @@ static int atmel_spi_one_transfer(struct spi_master *master, struct atmel_spi_device *asd; int timeout; int ret; + unsigned long dma_timeout; as = spi_master_get_devdata(master); @@ -1103,15 +1104,12 @@ static int atmel_spi_one_transfer(struct spi_master *master, /* interrupts are disabled, so free the lock for schedule */ atmel_spi_unlock(as); - ret = wait_for_completion_timeout(&as->xfer_completion, - SPI_DMA_TIMEOUT); + dma_timeout = wait_for_completion_timeout(&as->xfer_completion, + SPI_DMA_TIMEOUT); atmel_spi_lock(as); - if (WARN_ON(ret == 0)) { - dev_err(&spi->dev, - "spi trasfer timeout, err %d\n", ret); + if (WARN_ON(dma_timeout == 0)) { + dev_err(&spi->dev, "spi transfer timeout\n"); as->done_status = -EIO; - } else { - ret = 0; } if (as->done_status) diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c index 326f47973684..f45e085c01a6 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c @@ -15,10 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 98aab457b24d..419a782ab6d5 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -17,10 +17,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index c20530982e26..e73e2b052c9c 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, */ #include diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index dc7d2c2d643e..5ef6638d5e8a 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -10,10 +10,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c index ee4f91ccd8fd..9a95862986c8 100644 --- a/drivers/spi/spi-butterfly.c +++ b/drivers/spi/spi-butterfly.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index 41b5dc4445f6..688956ff5095 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -12,11 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA - * */ #include diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index b3707badb1e5..5e991065f5b0 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/spi/spi-dln2.c b/drivers/spi/spi-dln2.c new file mode 100644 index 000000000000..3b7d91d94fea --- /dev/null +++ b/drivers/spi/spi-dln2.c @@ -0,0 +1,881 @@ +/* + * Driver for the Diolan DLN-2 USB-SPI adapter + * + * Copyright (c) 2014 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DLN2_SPI_MODULE_ID 0x02 +#define DLN2_SPI_CMD(cmd) DLN2_CMD(cmd, DLN2_SPI_MODULE_ID) + +/* SPI commands */ +#define DLN2_SPI_GET_PORT_COUNT DLN2_SPI_CMD(0x00) +#define DLN2_SPI_ENABLE DLN2_SPI_CMD(0x11) +#define DLN2_SPI_DISABLE DLN2_SPI_CMD(0x12) +#define DLN2_SPI_IS_ENABLED DLN2_SPI_CMD(0x13) +#define DLN2_SPI_SET_MODE DLN2_SPI_CMD(0x14) +#define DLN2_SPI_GET_MODE DLN2_SPI_CMD(0x15) +#define DLN2_SPI_SET_FRAME_SIZE DLN2_SPI_CMD(0x16) +#define DLN2_SPI_GET_FRAME_SIZE DLN2_SPI_CMD(0x17) +#define DLN2_SPI_SET_FREQUENCY DLN2_SPI_CMD(0x18) +#define DLN2_SPI_GET_FREQUENCY DLN2_SPI_CMD(0x19) +#define DLN2_SPI_READ_WRITE DLN2_SPI_CMD(0x1A) +#define DLN2_SPI_READ DLN2_SPI_CMD(0x1B) +#define DLN2_SPI_WRITE DLN2_SPI_CMD(0x1C) +#define DLN2_SPI_SET_DELAY_BETWEEN_SS DLN2_SPI_CMD(0x20) +#define DLN2_SPI_GET_DELAY_BETWEEN_SS DLN2_SPI_CMD(0x21) +#define DLN2_SPI_SET_DELAY_AFTER_SS DLN2_SPI_CMD(0x22) +#define DLN2_SPI_GET_DELAY_AFTER_SS DLN2_SPI_CMD(0x23) +#define DLN2_SPI_SET_DELAY_BETWEEN_FRAMES DLN2_SPI_CMD(0x24) +#define DLN2_SPI_GET_DELAY_BETWEEN_FRAMES DLN2_SPI_CMD(0x25) +#define DLN2_SPI_SET_SS DLN2_SPI_CMD(0x26) +#define DLN2_SPI_GET_SS DLN2_SPI_CMD(0x27) +#define DLN2_SPI_RELEASE_SS DLN2_SPI_CMD(0x28) +#define DLN2_SPI_SS_VARIABLE_ENABLE DLN2_SPI_CMD(0x2B) +#define DLN2_SPI_SS_VARIABLE_DISABLE DLN2_SPI_CMD(0x2C) +#define DLN2_SPI_SS_VARIABLE_IS_ENABLED DLN2_SPI_CMD(0x2D) +#define DLN2_SPI_SS_AAT_ENABLE DLN2_SPI_CMD(0x2E) +#define DLN2_SPI_SS_AAT_DISABLE DLN2_SPI_CMD(0x2F) +#define DLN2_SPI_SS_AAT_IS_ENABLED DLN2_SPI_CMD(0x30) +#define DLN2_SPI_SS_BETWEEN_FRAMES_ENABLE DLN2_SPI_CMD(0x31) +#define DLN2_SPI_SS_BETWEEN_FRAMES_DISABLE DLN2_SPI_CMD(0x32) +#define DLN2_SPI_SS_BETWEEN_FRAMES_IS_ENABLED DLN2_SPI_CMD(0x33) +#define DLN2_SPI_SET_CPHA DLN2_SPI_CMD(0x34) +#define DLN2_SPI_GET_CPHA DLN2_SPI_CMD(0x35) +#define DLN2_SPI_SET_CPOL DLN2_SPI_CMD(0x36) +#define DLN2_SPI_GET_CPOL DLN2_SPI_CMD(0x37) +#define DLN2_SPI_SS_MULTI_ENABLE DLN2_SPI_CMD(0x38) +#define DLN2_SPI_SS_MULTI_DISABLE DLN2_SPI_CMD(0x39) +#define DLN2_SPI_SS_MULTI_IS_ENABLED DLN2_SPI_CMD(0x3A) +#define DLN2_SPI_GET_SUPPORTED_MODES DLN2_SPI_CMD(0x40) +#define DLN2_SPI_GET_SUPPORTED_CPHA_VALUES DLN2_SPI_CMD(0x41) +#define DLN2_SPI_GET_SUPPORTED_CPOL_VALUES DLN2_SPI_CMD(0x42) +#define DLN2_SPI_GET_SUPPORTED_FRAME_SIZES DLN2_SPI_CMD(0x43) +#define DLN2_SPI_GET_SS_COUNT DLN2_SPI_CMD(0x44) +#define DLN2_SPI_GET_MIN_FREQUENCY DLN2_SPI_CMD(0x45) +#define DLN2_SPI_GET_MAX_FREQUENCY DLN2_SPI_CMD(0x46) +#define DLN2_SPI_GET_MIN_DELAY_BETWEEN_SS DLN2_SPI_CMD(0x47) +#define DLN2_SPI_GET_MAX_DELAY_BETWEEN_SS DLN2_SPI_CMD(0x48) +#define DLN2_SPI_GET_MIN_DELAY_AFTER_SS DLN2_SPI_CMD(0x49) +#define DLN2_SPI_GET_MAX_DELAY_AFTER_SS DLN2_SPI_CMD(0x4A) +#define DLN2_SPI_GET_MIN_DELAY_BETWEEN_FRAMES DLN2_SPI_CMD(0x4B) +#define DLN2_SPI_GET_MAX_DELAY_BETWEEN_FRAMES DLN2_SPI_CMD(0x4C) + +#define DLN2_SPI_MAX_XFER_SIZE 256 +#define DLN2_SPI_BUF_SIZE (DLN2_SPI_MAX_XFER_SIZE + 16) +#define DLN2_SPI_ATTR_LEAVE_SS_LOW BIT(0) +#define DLN2_TRANSFERS_WAIT_COMPLETE 1 +#define DLN2_TRANSFERS_CANCEL 0 +#define DLN2_RPM_AUTOSUSPEND_TIMEOUT 2000 + +struct dln2_spi { + struct platform_device *pdev; + struct spi_master *master; + u8 port; + + /* + * This buffer will be used mainly for read/write operations. Since + * they're quite large, we cannot use the stack. Protection is not + * needed because all SPI communication is serialized by the SPI core. + */ + void *buf; + + u8 bpw; + u32 speed; + u16 mode; + u8 cs; +}; + +/* + * Enable/Disable SPI module. The disable command will wait for transfers to + * complete first. + */ +static int dln2_spi_enable(struct dln2_spi *dln2, bool enable) +{ + u16 cmd; + struct { + u8 port; + u8 wait_for_completion; + } tx; + unsigned len = sizeof(tx); + + tx.port = dln2->port; + + if (enable) { + cmd = DLN2_SPI_ENABLE; + len -= sizeof(tx.wait_for_completion); + } else { + tx.wait_for_completion = DLN2_TRANSFERS_WAIT_COMPLETE; + cmd = DLN2_SPI_DISABLE; + } + + return dln2_transfer_tx(dln2->pdev, cmd, &tx, len); +} + +/* + * Select/unselect multiple CS lines. The selected lines will be automatically + * toggled LOW/HIGH by the board firmware during transfers, provided they're + * enabled first. + * + * Ex: cs_mask = 0x03 -> CS0 & CS1 will be selected and the next WR/RD operation + * will toggle the lines LOW/HIGH automatically. + */ +static int dln2_spi_cs_set(struct dln2_spi *dln2, u8 cs_mask) +{ + struct { + u8 port; + u8 cs; + } tx; + + tx.port = dln2->port; + + /* + * According to Diolan docs, "a slave device can be selected by changing + * the corresponding bit value to 0". The rest must be set to 1. Hence + * the bitwise NOT in front. + */ + tx.cs = ~cs_mask; + + return dln2_transfer_tx(dln2->pdev, DLN2_SPI_SET_SS, &tx, sizeof(tx)); +} + +/* + * Select one CS line. The other lines will be un-selected. + */ +static int dln2_spi_cs_set_one(struct dln2_spi *dln2, u8 cs) +{ + return dln2_spi_cs_set(dln2, BIT(cs)); +} + +/* + * Enable/disable CS lines for usage. The module has to be disabled first. + */ +static int dln2_spi_cs_enable(struct dln2_spi *dln2, u8 cs_mask, bool enable) +{ + struct { + u8 port; + u8 cs; + } tx; + u16 cmd; + + tx.port = dln2->port; + tx.cs = cs_mask; + cmd = enable ? DLN2_SPI_SS_MULTI_ENABLE : DLN2_SPI_SS_MULTI_DISABLE; + + return dln2_transfer_tx(dln2->pdev, cmd, &tx, sizeof(tx)); +} + +static int dln2_spi_cs_enable_all(struct dln2_spi *dln2, bool enable) +{ + u8 cs_mask = GENMASK(dln2->master->num_chipselect - 1, 0); + + return dln2_spi_cs_enable(dln2, cs_mask, enable); +} + +static int dln2_spi_get_cs_num(struct dln2_spi *dln2, u16 *cs_num) +{ + int ret; + struct { + u8 port; + } tx; + struct { + __le16 cs_count; + } rx; + unsigned rx_len = sizeof(rx); + + tx.port = dln2->port; + ret = dln2_transfer(dln2->pdev, DLN2_SPI_GET_SS_COUNT, &tx, sizeof(tx), + &rx, &rx_len); + if (ret < 0) + return ret; + if (rx_len < sizeof(rx)) + return -EPROTO; + + *cs_num = le16_to_cpu(rx.cs_count); + + dev_dbg(&dln2->pdev->dev, "cs_num = %d\n", *cs_num); + + return 0; +} + +static int dln2_spi_get_speed(struct dln2_spi *dln2, u16 cmd, u32 *freq) +{ + int ret; + struct { + u8 port; + } tx; + struct { + __le32 speed; + } rx; + unsigned rx_len = sizeof(rx); + + tx.port = dln2->port; + + ret = dln2_transfer(dln2->pdev, cmd, &tx, sizeof(tx), &rx, &rx_len); + if (ret < 0) + return ret; + if (rx_len < sizeof(rx)) + return -EPROTO; + + *freq = le32_to_cpu(rx.speed); + + return 0; +} + +/* + * Get bus min/max frequencies. + */ +static int dln2_spi_get_speed_range(struct dln2_spi *dln2, u32 *fmin, u32 *fmax) +{ + int ret; + + ret = dln2_spi_get_speed(dln2, DLN2_SPI_GET_MIN_FREQUENCY, fmin); + if (ret < 0) + return ret; + + ret = dln2_spi_get_speed(dln2, DLN2_SPI_GET_MAX_FREQUENCY, fmax); + if (ret < 0) + return ret; + + dev_dbg(&dln2->pdev->dev, "freq_min = %d, freq_max = %d\n", + *fmin, *fmax); + + return 0; +} + +/* + * Set the bus speed. The module will automatically round down to the closest + * available frequency and returns it. The module has to be disabled first. + */ +static int dln2_spi_set_speed(struct dln2_spi *dln2, u32 speed) +{ + int ret; + struct { + u8 port; + __le32 speed; + } __packed tx; + struct { + __le32 speed; + } rx; + int rx_len = sizeof(rx); + + tx.port = dln2->port; + tx.speed = cpu_to_le32(speed); + + ret = dln2_transfer(dln2->pdev, DLN2_SPI_SET_FREQUENCY, &tx, sizeof(tx), + &rx, &rx_len); + if (ret < 0) + return ret; + if (rx_len < sizeof(rx)) + return -EPROTO; + + return 0; +} + +/* + * Change CPOL & CPHA. The module has to be disabled first. + */ +static int dln2_spi_set_mode(struct dln2_spi *dln2, u8 mode) +{ + struct { + u8 port; + u8 mode; + } tx; + + tx.port = dln2->port; + tx.mode = mode; + + return dln2_transfer_tx(dln2->pdev, DLN2_SPI_SET_MODE, &tx, sizeof(tx)); +} + +/* + * Change frame size. The module has to be disabled first. + */ +static int dln2_spi_set_bpw(struct dln2_spi *dln2, u8 bpw) +{ + struct { + u8 port; + u8 bpw; + } tx; + + tx.port = dln2->port; + tx.bpw = bpw; + + return dln2_transfer_tx(dln2->pdev, DLN2_SPI_SET_FRAME_SIZE, + &tx, sizeof(tx)); +} + +static int dln2_spi_get_supported_frame_sizes(struct dln2_spi *dln2, + u32 *bpw_mask) +{ + int ret; + struct { + u8 port; + } tx; + struct { + u8 count; + u8 frame_sizes[36]; + } *rx = dln2->buf; + unsigned rx_len = sizeof(*rx); + int i; + + tx.port = dln2->port; + + ret = dln2_transfer(dln2->pdev, DLN2_SPI_GET_SUPPORTED_FRAME_SIZES, + &tx, sizeof(tx), rx, &rx_len); + if (ret < 0) + return ret; + if (rx_len < sizeof(*rx)) + return -EPROTO; + if (rx->count > ARRAY_SIZE(rx->frame_sizes)) + return -EPROTO; + + *bpw_mask = 0; + for (i = 0; i < rx->count; i++) + *bpw_mask |= BIT(rx->frame_sizes[i] - 1); + + dev_dbg(&dln2->pdev->dev, "bpw_mask = 0x%X\n", *bpw_mask); + + return 0; +} + +/* + * Copy the data to DLN2 buffer and change the byte order to LE, requested by + * DLN2 module. SPI core makes sure that the data length is a multiple of word + * size. + */ +static int dln2_spi_copy_to_buf(u8 *dln2_buf, const u8 *src, u16 len, u8 bpw) +{ +#ifdef __LITTLE_ENDIAN + memcpy(dln2_buf, src, len); +#else + if (bpw <= 8) { + memcpy(dln2_buf, src, len); + } else if (bpw <= 16) { + __le16 *d = (__le16 *)dln2_buf; + u16 *s = (u16 *)src; + + len = len / 2; + while (len--) + *d++ = cpu_to_le16p(s++); + } else { + __le32 *d = (__le32 *)dln2_buf; + u32 *s = (u32 *)src; + + len = len / 4; + while (len--) + *d++ = cpu_to_le32p(s++); + } +#endif + + return 0; +} + +/* + * Copy the data from DLN2 buffer and convert to CPU byte order since the DLN2 + * buffer is LE ordered. SPI core makes sure that the data length is a multiple + * of word size. The RX dln2_buf is 2 byte aligned so, for BE, we have to make + * sure we avoid unaligned accesses for 32 bit case. + */ +static int dln2_spi_copy_from_buf(u8 *dest, const u8 *dln2_buf, u16 len, u8 bpw) +{ +#ifdef __LITTLE_ENDIAN + memcpy(dest, dln2_buf, len); +#else + if (bpw <= 8) { + memcpy(dest, dln2_buf, len); + } else if (bpw <= 16) { + u16 *d = (u16 *)dest; + __le16 *s = (__le16 *)dln2_buf; + + len = len / 2; + while (len--) + *d++ = le16_to_cpup(s++); + } else { + u32 *d = (u32 *)dest; + __le32 *s = (__le32 *)dln2_buf; + + len = len / 4; + while (len--) + *d++ = get_unaligned_le32(s++); + } +#endif + + return 0; +} + +/* + * Perform one write operation. + */ +static int dln2_spi_write_one(struct dln2_spi *dln2, const u8 *data, + u16 data_len, u8 attr) +{ + struct { + u8 port; + __le16 size; + u8 attr; + u8 buf[DLN2_SPI_MAX_XFER_SIZE]; + } __packed *tx = dln2->buf; + unsigned tx_len; + + BUILD_BUG_ON(sizeof(*tx) > DLN2_SPI_BUF_SIZE); + + if (data_len > DLN2_SPI_MAX_XFER_SIZE) + return -EINVAL; + + tx->port = dln2->port; + tx->size = cpu_to_le16(data_len); + tx->attr = attr; + + dln2_spi_copy_to_buf(tx->buf, data, data_len, dln2->bpw); + + tx_len = sizeof(*tx) + data_len - DLN2_SPI_MAX_XFER_SIZE; + return dln2_transfer_tx(dln2->pdev, DLN2_SPI_WRITE, tx, tx_len); +} + +/* + * Perform one read operation. + */ +static int dln2_spi_read_one(struct dln2_spi *dln2, u8 *data, + u16 data_len, u8 attr) +{ + int ret; + struct { + u8 port; + __le16 size; + u8 attr; + } __packed tx; + struct { + __le16 size; + u8 buf[DLN2_SPI_MAX_XFER_SIZE]; + } __packed *rx = dln2->buf; + unsigned rx_len = sizeof(*rx); + + BUILD_BUG_ON(sizeof(*rx) > DLN2_SPI_BUF_SIZE); + + if (data_len > DLN2_SPI_MAX_XFER_SIZE) + return -EINVAL; + + tx.port = dln2->port; + tx.size = cpu_to_le16(data_len); + tx.attr = attr; + + ret = dln2_transfer(dln2->pdev, DLN2_SPI_READ, &tx, sizeof(tx), + rx, &rx_len); + if (ret < 0) + return ret; + if (rx_len < sizeof(rx->size) + data_len) + return -EPROTO; + if (le16_to_cpu(rx->size) != data_len) + return -EPROTO; + + dln2_spi_copy_from_buf(data, rx->buf, data_len, dln2->bpw); + + return 0; +} + +/* + * Perform one write & read operation. + */ +static int dln2_spi_read_write_one(struct dln2_spi *dln2, const u8 *tx_data, + u8 *rx_data, u16 data_len, u8 attr) +{ + int ret; + struct { + u8 port; + __le16 size; + u8 attr; + u8 buf[DLN2_SPI_MAX_XFER_SIZE]; + } __packed *tx; + struct { + __le16 size; + u8 buf[DLN2_SPI_MAX_XFER_SIZE]; + } __packed *rx; + unsigned tx_len, rx_len; + + BUILD_BUG_ON(sizeof(*tx) > DLN2_SPI_BUF_SIZE || + sizeof(*rx) > DLN2_SPI_BUF_SIZE); + + if (data_len > DLN2_SPI_MAX_XFER_SIZE) + return -EINVAL; + + /* + * Since this is a pseudo full-duplex communication, we're perfectly + * safe to use the same buffer for both tx and rx. When DLN2 sends the + * response back, with the rx data, we don't need the tx buffer anymore. + */ + tx = dln2->buf; + rx = dln2->buf; + + tx->port = dln2->port; + tx->size = cpu_to_le16(data_len); + tx->attr = attr; + + dln2_spi_copy_to_buf(tx->buf, tx_data, data_len, dln2->bpw); + + tx_len = sizeof(*tx) + data_len - DLN2_SPI_MAX_XFER_SIZE; + rx_len = sizeof(*rx); + + ret = dln2_transfer(dln2->pdev, DLN2_SPI_READ_WRITE, tx, tx_len, + rx, &rx_len); + if (ret < 0) + return ret; + if (rx_len < sizeof(rx->size) + data_len) + return -EPROTO; + if (le16_to_cpu(rx->size) != data_len) + return -EPROTO; + + dln2_spi_copy_from_buf(rx_data, rx->buf, data_len, dln2->bpw); + + return 0; +} + +/* + * Read/Write wrapper. It will automatically split an operation into multiple + * single ones due to device buffer constraints. + */ +static int dln2_spi_rdwr(struct dln2_spi *dln2, const u8 *tx_data, + u8 *rx_data, u16 data_len, u8 attr) { + int ret; + u16 len; + u8 temp_attr; + u16 remaining = data_len; + u16 offset; + + do { + if (remaining > DLN2_SPI_MAX_XFER_SIZE) { + len = DLN2_SPI_MAX_XFER_SIZE; + temp_attr = DLN2_SPI_ATTR_LEAVE_SS_LOW; + } else { + len = remaining; + temp_attr = attr; + } + + offset = data_len - remaining; + + if (tx_data && rx_data) { + ret = dln2_spi_read_write_one(dln2, + tx_data + offset, + rx_data + offset, + len, temp_attr); + } else if (tx_data) { + ret = dln2_spi_write_one(dln2, + tx_data + offset, + len, temp_attr); + } else if (rx_data) { + ret = dln2_spi_read_one(dln2, + rx_data + offset, + len, temp_attr); + } else { + return -EINVAL; + } + + if (ret < 0) + return ret; + + remaining -= len; + } while (remaining); + + return 0; +} + +static int dln2_spi_prepare_message(struct spi_master *master, + struct spi_message *message) +{ + int ret; + struct dln2_spi *dln2 = spi_master_get_devdata(master); + struct spi_device *spi = message->spi; + + if (dln2->cs != spi->chip_select) { + ret = dln2_spi_cs_set_one(dln2, spi->chip_select); + if (ret < 0) + return ret; + + dln2->cs = spi->chip_select; + } + + return 0; +} + +static int dln2_spi_transfer_setup(struct dln2_spi *dln2, u32 speed, + u8 bpw, u8 mode) +{ + int ret; + bool bus_setup_change; + + bus_setup_change = dln2->speed != speed || dln2->mode != mode || + dln2->bpw != bpw; + + if (!bus_setup_change) + return 0; + + ret = dln2_spi_enable(dln2, false); + if (ret < 0) + return ret; + + if (dln2->speed != speed) { + ret = dln2_spi_set_speed(dln2, speed); + if (ret < 0) + return ret; + + dln2->speed = speed; + } + + if (dln2->mode != mode) { + ret = dln2_spi_set_mode(dln2, mode & 0x3); + if (ret < 0) + return ret; + + dln2->mode = mode; + } + + if (dln2->bpw != bpw) { + ret = dln2_spi_set_bpw(dln2, bpw); + if (ret < 0) + return ret; + + dln2->bpw = bpw; + } + + return dln2_spi_enable(dln2, true); +} + +static int dln2_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct dln2_spi *dln2 = spi_master_get_devdata(master); + int status; + u8 attr = 0; + + status = dln2_spi_transfer_setup(dln2, xfer->speed_hz, + xfer->bits_per_word, + spi->mode); + if (status < 0) { + dev_err(&dln2->pdev->dev, "Cannot setup transfer\n"); + return status; + } + + if (!xfer->cs_change && !spi_transfer_is_last(master, xfer)) + attr = DLN2_SPI_ATTR_LEAVE_SS_LOW; + + status = dln2_spi_rdwr(dln2, xfer->tx_buf, xfer->rx_buf, + xfer->len, attr); + if (status < 0) + dev_err(&dln2->pdev->dev, "write/read failed!\n"); + + return status; +} + +static int dln2_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct dln2_spi *dln2; + struct dln2_platform_data *pdata = dev_get_platdata(&pdev->dev); + int ret; + + master = spi_alloc_master(&pdev->dev, sizeof(*dln2)); + if (!master) + return -ENOMEM; + + platform_set_drvdata(pdev, master); + + dln2 = spi_master_get_devdata(master); + + dln2->buf = devm_kmalloc(&pdev->dev, DLN2_SPI_BUF_SIZE, GFP_KERNEL); + if (!dln2->buf) { + ret = -ENOMEM; + goto exit_free_master; + } + + dln2->master = master; + dln2->pdev = pdev; + dln2->port = pdata->port; + /* cs/mode can never be 0xff, so the first transfer will set them */ + dln2->cs = 0xff; + dln2->mode = 0xff; + + /* disable SPI module before continuing with the setup */ + ret = dln2_spi_enable(dln2, false); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to disable SPI module\n"); + goto exit_free_master; + } + + ret = dln2_spi_get_cs_num(dln2, &master->num_chipselect); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get number of CS pins\n"); + goto exit_free_master; + } + + ret = dln2_spi_get_speed_range(dln2, + &master->min_speed_hz, + &master->max_speed_hz); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to read bus min/max freqs\n"); + goto exit_free_master; + } + + ret = dln2_spi_get_supported_frame_sizes(dln2, + &master->bits_per_word_mask); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to read supported frame sizes\n"); + goto exit_free_master; + } + + ret = dln2_spi_cs_enable_all(dln2, true); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable CS pins\n"); + goto exit_free_master; + } + + master->bus_num = -1; + master->mode_bits = SPI_CPOL | SPI_CPHA; + master->prepare_message = dln2_spi_prepare_message; + master->transfer_one = dln2_spi_transfer_one; + master->auto_runtime_pm = true; + + /* enable SPI module, we're good to go */ + ret = dln2_spi_enable(dln2, true); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable SPI module\n"); + goto exit_free_master; + } + + pm_runtime_set_autosuspend_delay(&pdev->dev, + DLN2_RPM_AUTOSUSPEND_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ret = devm_spi_register_master(&pdev->dev, master); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register master\n"); + goto exit_register; + } + + return ret; + +exit_register: + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + + if (dln2_spi_enable(dln2, false) < 0) + dev_err(&pdev->dev, "Failed to disable SPI module\n"); +exit_free_master: + spi_master_put(master); + + return ret; +} + +static int dln2_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); + struct dln2_spi *dln2 = spi_master_get_devdata(master); + + pm_runtime_disable(&pdev->dev); + + if (dln2_spi_enable(dln2, false) < 0) + dev_err(&pdev->dev, "Failed to disable SPI module\n"); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int dln2_spi_suspend(struct device *dev) +{ + int ret; + struct spi_master *master = dev_get_drvdata(dev); + struct dln2_spi *dln2 = spi_master_get_devdata(master); + + ret = spi_master_suspend(master); + if (ret < 0) + return ret; + + if (!pm_runtime_suspended(dev)) { + ret = dln2_spi_enable(dln2, false); + if (ret < 0) + return ret; + } + + /* + * USB power may be cut off during sleep. Resetting the following + * parameters will force the board to be set up before first transfer. + */ + dln2->cs = 0xff; + dln2->speed = 0; + dln2->bpw = 0; + dln2->mode = 0xff; + + return 0; +} + +static int dln2_spi_resume(struct device *dev) +{ + int ret; + struct spi_master *master = dev_get_drvdata(dev); + struct dln2_spi *dln2 = spi_master_get_devdata(master); + + if (!pm_runtime_suspended(dev)) { + ret = dln2_spi_cs_enable_all(dln2, true); + if (ret < 0) + return ret; + + ret = dln2_spi_enable(dln2, true); + if (ret < 0) + return ret; + } + + return spi_master_resume(master); +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM +static int dln2_spi_runtime_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct dln2_spi *dln2 = spi_master_get_devdata(master); + + return dln2_spi_enable(dln2, false); +} + +static int dln2_spi_runtime_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct dln2_spi *dln2 = spi_master_get_devdata(master); + + return dln2_spi_enable(dln2, true); +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops dln2_spi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(dln2_spi_suspend, dln2_spi_resume) + SET_RUNTIME_PM_OPS(dln2_spi_runtime_suspend, + dln2_spi_runtime_resume, NULL) +}; + +static struct platform_driver spi_dln2_driver = { + .driver = { + .name = "dln2-spi", + .pm = &dln2_spi_pm, + }, + .probe = dln2_spi_probe, + .remove = dln2_spi_remove, +}; +module_platform_driver(spi_dln2_driver); + +MODULE_DESCRIPTION("Driver for the Diolan DLN2 SPI master interface"); +MODULE_AUTHOR("Laurentiu Palcu "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:dln2-spi"); diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index 7281316a5ecb..a0197fd4e95c 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -247,9 +247,9 @@ static struct dw_spi_dma_ops mid_dma_ops = { /* Some specific info for SPI0 controller on Intel MID */ -/* HW info for MRST CLk Control Unit, one 32b reg */ +/* HW info for MRST Clk Control Unit, 32b reg per controller */ #define MRST_SPI_CLK_BASE 100000000 /* 100m */ -#define MRST_CLK_SPI0_REG 0xff11d86c +#define MRST_CLK_SPI_REG 0xff11d86c #define CLK_SPI_BDIV_OFFSET 0 #define CLK_SPI_BDIV_MASK 0x00000007 #define CLK_SPI_CDIV_OFFSET 9 @@ -261,17 +261,17 @@ int dw_spi_mid_init(struct dw_spi *dws) void __iomem *clk_reg; u32 clk_cdiv; - clk_reg = ioremap_nocache(MRST_CLK_SPI0_REG, 16); + clk_reg = ioremap_nocache(MRST_CLK_SPI_REG, 16); if (!clk_reg) return -ENOMEM; - /* get SPI controller operating freq info */ - clk_cdiv = (readl(clk_reg) & CLK_SPI_CDIV_MASK) >> CLK_SPI_CDIV_OFFSET; + /* Get SPI controller operating freq info */ + clk_cdiv = readl(clk_reg + dws->bus_num * sizeof(u32)); + clk_cdiv &= CLK_SPI_CDIV_MASK; + clk_cdiv >>= CLK_SPI_CDIV_OFFSET; dws->max_freq = MRST_SPI_CLK_BASE / (clk_cdiv + 1); - iounmap(clk_reg); - dws->num_cs = 16; - dws->fifo_len = 40; /* FIFO has 40 words buffer */ + iounmap(clk_reg); #ifdef CONFIG_SPI_DW_MID_DMA dws->dma_priv = kzalloc(sizeof(struct mid_dma), GFP_KERNEL); diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index ba68da12cdf0..5ba331047cbe 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -30,10 +30,20 @@ struct dw_spi_pci { struct spi_pci_desc { int (*setup)(struct dw_spi *); + u16 num_cs; + u16 bus_num; }; -static struct spi_pci_desc spi_pci_mid_desc = { +static struct spi_pci_desc spi_pci_mid_desc_1 = { .setup = dw_spi_mid_init, + .num_cs = 32, + .bus_num = 0, +}; + +static struct spi_pci_desc spi_pci_mid_desc_2 = { + .setup = dw_spi_mid_init, + .num_cs = 4, + .bus_num = 1, }; static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -65,18 +75,23 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dws->regs = pcim_iomap_table(pdev)[pci_bar]; - dws->bus_num = 0; - dws->num_cs = 4; dws->irq = pdev->irq; /* * Specific handling for paltforms, like dma setup, * clock rate, FIFO depth. */ - if (desc && desc->setup) { - ret = desc->setup(dws); - if (ret) - return ret; + if (desc) { + dws->num_cs = desc->num_cs; + dws->bus_num = desc->bus_num; + + if (desc->setup) { + ret = desc->setup(dws); + if (ret) + return ret; + } + } else { + return -ENODEV; } ret = dw_spi_add_host(&pdev->dev, dws); @@ -121,7 +136,14 @@ static SIMPLE_DEV_PM_OPS(dw_spi_pm_ops, spi_suspend, spi_resume); static const struct pci_device_id pci_ids[] = { /* Intel MID platform SPI controller 0 */ - { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc}, + /* + * The access to the device 8086:0801 is disabled by HW, since it's + * exclusively used by SCU to communicate with MSIC. + */ + /* Intel MID platform SPI controller 1 */ + { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc_1}, + /* Intel MID platform SPI controller 2 */ + { PCI_VDEVICE(INTEL, 0x0812), (kernel_ulong_t)&spi_pci_mid_desc_2}, {}, }; diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index d0d5542efc06..5a97a62b298a 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -608,7 +608,7 @@ static void dw_spi_cleanup(struct spi_device *spi) } /* Restart the controller, disable all interrupts, clean rx fifo */ -static void spi_hw_init(struct dw_spi *dws) +static void spi_hw_init(struct device *dev, struct dw_spi *dws) { spi_enable_chip(dws, 0); spi_mask_intr(dws, 0xff); @@ -621,14 +621,15 @@ static void spi_hw_init(struct dw_spi *dws) if (!dws->fifo_len) { u32 fifo; - for (fifo = 2; fifo <= 257; fifo++) { + for (fifo = 2; fifo <= 256; fifo++) { dw_writew(dws, DW_SPI_TXFLTR, fifo); if (fifo != dw_readw(dws, DW_SPI_TXFLTR)) break; } - - dws->fifo_len = (fifo == 257) ? 0 : fifo; dw_writew(dws, DW_SPI_TXFLTR, 0); + + dws->fifo_len = (fifo == 2) ? 0 : fifo - 1; + dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len); } } @@ -668,12 +669,12 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) master->dev.of_node = dev->of_node; /* Basic HW init */ - spi_hw_init(dws); + spi_hw_init(dev, dws); if (dws->dma_ops && dws->dma_ops->dma_init) { ret = dws->dma_ops->dma_init(dws); if (ret) { - dev_warn(&master->dev, "DMA init failed\n"); + dev_warn(dev, "DMA init failed\n"); dws->dma_inited = 0; } } @@ -731,7 +732,7 @@ int dw_spi_resume_host(struct dw_spi *dws) { int ret; - spi_hw_init(dws); + spi_hw_init(&dws->master->dev, dws); ret = spi_master_resume(dws->master); if (ret) dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret); diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c index 912b9037e9cf..286b2c81fc6b 100644 --- a/drivers/spi/spi-falcon.c +++ b/drivers/spi/spi-falcon.c @@ -353,16 +353,6 @@ static int falcon_sflash_setup(struct spi_device *spi) return 0; } -static int falcon_sflash_prepare_xfer(struct spi_master *master) -{ - return 0; -} - -static int falcon_sflash_unprepare_xfer(struct spi_master *master) -{ - return 0; -} - static int falcon_sflash_xfer_one(struct spi_master *master, struct spi_message *m) { @@ -420,9 +410,7 @@ static int falcon_sflash_probe(struct platform_device *pdev) master->mode_bits = SPI_MODE_3; master->flags = SPI_MASTER_HALF_DUPLEX; master->setup = falcon_sflash_setup; - master->prepare_transfer_hardware = falcon_sflash_prepare_xfer; master->transfer_one_message = falcon_sflash_xfer_one; - master->unprepare_transfer_hardware = falcon_sflash_unprepare_xfer; master->dev.of_node = pdev->dev.of_node; ret = devm_spi_register_master(&pdev->dev, master); diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c index e85ab1cb17a2..9c46a3058743 100644 --- a/drivers/spi/spi-fsl-cpm.c +++ b/drivers/spi/spi-fsl-cpm.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,7 @@ void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi) } } } +EXPORT_SYMBOL_GPL(fsl_spi_cpm_reinit_txrx); static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi) { @@ -162,6 +164,7 @@ err_rx_dma: dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE); return -ENOMEM; } +EXPORT_SYMBOL_GPL(fsl_spi_cpm_bufs); void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) { @@ -174,6 +177,7 @@ void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE); mspi->xfer_in_progress = NULL; } +EXPORT_SYMBOL_GPL(fsl_spi_cpm_bufs_complete); void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) { @@ -198,6 +202,7 @@ void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) else complete(&mspi->done); } +EXPORT_SYMBOL_GPL(fsl_spi_cpm_irq); static void *fsl_spi_alloc_dummy_rx(void) { @@ -375,6 +380,7 @@ err_pram: fsl_spi_free_dummy_rx(); return -ENOMEM; } +EXPORT_SYMBOL_GPL(fsl_spi_cpm_init); void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi) { @@ -389,3 +395,6 @@ void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi) cpm_muram_free(cpm_muram_offset(mspi->pram)); fsl_spi_free_dummy_rx(); } +EXPORT_SYMBOL_GPL(fsl_spi_cpm_free); + +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 4cda994d3f40..d1a39249704a 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -106,7 +106,7 @@ struct chip_data { }; struct fsl_dspi { - struct spi_bitbang bitbang; + struct spi_master *master; struct platform_device *pdev; struct regmap *regmap; @@ -114,6 +114,7 @@ struct fsl_dspi { struct clk *clk; struct spi_transfer *cur_transfer; + struct spi_message *cur_msg; struct chip_data *cur_chip; size_t len; void *tx; @@ -123,6 +124,7 @@ struct fsl_dspi { char dataflags; u8 cs; u16 void_write_data; + u32 cs_change; wait_queue_head_t waitq; u32 waitflags; @@ -225,6 +227,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi) if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1) { /* last transfer in the transfer */ dspi_pushr |= SPI_PUSHR_EOQ; + if ((dspi->cs_change) && (!dspi->len)) + dspi_pushr &= ~SPI_PUSHR_CONT; } else if (tx_word && (dspi->len == 1)) dspi_pushr |= SPI_PUSHR_EOQ; @@ -246,6 +250,7 @@ static int dspi_transfer_read(struct fsl_dspi *dspi) int rx_count = 0; int rx_word = is_double_byte_mode(dspi); u16 d; + while ((dspi->rx < dspi->rx_end) && (rx_count < DSPI_FIFO_SIZE)) { if (rx_word) { @@ -276,80 +281,72 @@ static int dspi_transfer_read(struct fsl_dspi *dspi) return rx_count; } -static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t) +static int dspi_transfer_one_message(struct spi_master *master, + struct spi_message *message) { - struct fsl_dspi *dspi = spi_master_get_devdata(spi->master); - dspi->cur_transfer = t; - dspi->cur_chip = spi_get_ctldata(spi); - dspi->cs = spi->chip_select; - dspi->void_write_data = dspi->cur_chip->void_write_data; + struct fsl_dspi *dspi = spi_master_get_devdata(master); + struct spi_device *spi = message->spi; + struct spi_transfer *transfer; + int status = 0; + message->actual_length = 0; - dspi->dataflags = 0; - dspi->tx = (void *)t->tx_buf; - dspi->tx_end = dspi->tx + t->len; - dspi->rx = t->rx_buf; - dspi->rx_end = dspi->rx + t->len; - dspi->len = t->len; + list_for_each_entry(transfer, &message->transfers, transfer_list) { + dspi->cur_transfer = transfer; + dspi->cur_msg = message; + dspi->cur_chip = spi_get_ctldata(spi); + dspi->cs = spi->chip_select; + if (dspi->cur_transfer->transfer_list.next + == &dspi->cur_msg->transfers) + transfer->cs_change = 1; + dspi->cs_change = transfer->cs_change; + dspi->void_write_data = dspi->cur_chip->void_write_data; - if (!dspi->rx) - dspi->dataflags |= TRAN_STATE_RX_VOID; + dspi->dataflags = 0; + dspi->tx = (void *)transfer->tx_buf; + dspi->tx_end = dspi->tx + transfer->len; + dspi->rx = transfer->rx_buf; + dspi->rx_end = dspi->rx + transfer->len; + dspi->len = transfer->len; - if (!dspi->tx) - dspi->dataflags |= TRAN_STATE_TX_VOID; + if (!dspi->rx) + dspi->dataflags |= TRAN_STATE_RX_VOID; - regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val); - regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val); - regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE); + if (!dspi->tx) + dspi->dataflags |= TRAN_STATE_TX_VOID; - if (t->speed_hz) + regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val); + regmap_update_bits(dspi->regmap, SPI_MCR, + SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF, + SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF); regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val); + if (transfer->speed_hz) + regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), + dspi->cur_chip->ctar_val); - dspi_transfer_write(dspi); + regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE); + message->actual_length += dspi_transfer_write(dspi); - if (wait_event_interruptible(dspi->waitq, dspi->waitflags)) - dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n"); - dspi->waitflags = 0; + if (wait_event_interruptible(dspi->waitq, dspi->waitflags)) + dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n"); + dspi->waitflags = 0; - return t->len - dspi->len; -} - -static void dspi_chipselect(struct spi_device *spi, int value) -{ - struct fsl_dspi *dspi = spi_master_get_devdata(spi->master); - unsigned int pushr; - - regmap_read(dspi->regmap, SPI_PUSHR, &pushr); - - switch (value) { - case BITBANG_CS_ACTIVE: - pushr |= SPI_PUSHR_CONT; - break; - case BITBANG_CS_INACTIVE: - pushr &= ~SPI_PUSHR_CONT; - break; + if (transfer->delay_usecs) + udelay(transfer->delay_usecs); } - regmap_write(dspi->regmap, SPI_PUSHR, pushr); + message->status = status; + spi_finalize_current_message(master); + + return status; } -static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) +static int dspi_setup(struct spi_device *spi) { struct chip_data *chip; struct fsl_dspi *dspi = spi_master_get_devdata(spi->master); unsigned char br = 0, pbr = 0, fmsz = 0; - /* Only alloc on first setup */ - chip = spi_get_ctldata(spi); - if (chip == NULL) { - chip = devm_kzalloc(&spi->dev, sizeof(struct chip_data), - GFP_KERNEL); - if (!chip) - return -ENOMEM; - } - - chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS | - SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF; if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) { fmsz = spi->bits_per_word - 1; } else { @@ -357,6 +354,17 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) return -ENODEV; } + /* Only alloc on first setup */ + chip = spi_get_ctldata(spi); + if (chip == NULL) { + chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); + if (!chip) + return -ENOMEM; + } + + chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS | + SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF; + chip->void_write_data = 0; hz_to_spi_baud(&pbr, &br, @@ -374,34 +382,34 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) return 0; } -static int dspi_setup(struct spi_device *spi) +static void dspi_cleanup(struct spi_device *spi) { - if (!spi->max_speed_hz) - return -EINVAL; + struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi); - return dspi_setup_transfer(spi, NULL); + dev_dbg(&spi->dev, "spi_device %u.%u cleanup\n", + spi->master->bus_num, spi->chip_select); + + kfree(chip); } static irqreturn_t dspi_interrupt(int irq, void *dev_id) { struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id; - regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF); + struct spi_message *msg = dspi->cur_msg; + regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF); dspi_transfer_read(dspi); if (!dspi->len) { if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs), - SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16)); + SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16)); dspi->waitflags = 1; wake_up_interruptible(&dspi->waitq); - } else { - dspi_transfer_write(dspi); - - return IRQ_HANDLED; - } + } else + msg->actual_length += dspi_transfer_write(dspi); return IRQ_HANDLED; } @@ -460,13 +468,14 @@ static int dspi_probe(struct platform_device *pdev) dspi = spi_master_get_devdata(master); dspi->pdev = pdev; - dspi->bitbang.master = master; - dspi->bitbang.chipselect = dspi_chipselect; - dspi->bitbang.setup_transfer = dspi_setup_transfer; - dspi->bitbang.txrx_bufs = dspi_txrx_transfer; - dspi->bitbang.master->setup = dspi_setup; - dspi->bitbang.master->dev.of_node = pdev->dev.of_node; + dspi->master = master; + master->transfer = NULL; + master->setup = dspi_setup; + master->transfer_one_message = dspi_transfer_one_message; + master->dev.of_node = pdev->dev.of_node; + + master->cleanup = dspi_cleanup; master->mode_bits = SPI_CPOL | SPI_CPHA; master->bits_per_word_mask = SPI_BPW_MASK(4) | SPI_BPW_MASK(8) | SPI_BPW_MASK(16); @@ -525,7 +534,7 @@ static int dspi_probe(struct platform_device *pdev) init_waitqueue_head(&dspi->waitq); platform_set_drvdata(pdev, master); - ret = spi_bitbang_start(&dspi->bitbang); + ret = spi_register_master(master); if (ret != 0) { dev_err(&pdev->dev, "Problem registering DSPI master\n"); goto out_clk_put; @@ -547,9 +556,9 @@ static int dspi_remove(struct platform_device *pdev) struct fsl_dspi *dspi = spi_master_get_devdata(master); /* Disconnect from the SPI framework */ - spi_bitbang_stop(&dspi->bitbang); clk_disable_unprepare(dspi->clk); - spi_master_put(dspi->bitbang.master); + spi_unregister_master(dspi->master); + spi_master_put(dspi->master); return 0; } diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c index 446b737e1532..cb35d2f0d0e6 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_FSL_SOC @@ -35,7 +36,8 @@ void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \ type *rx = mpc8xxx_spi->rx; \ *rx++ = (type)(data >> mpc8xxx_spi->rx_shift); \ mpc8xxx_spi->rx = rx; \ -} +} \ +EXPORT_SYMBOL_GPL(mpc8xxx_spi_rx_buf_##type); #define MPC8XXX_SPI_TX_BUF(type) \ u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \ @@ -47,7 +49,8 @@ u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \ data = *tx++ << mpc8xxx_spi->tx_shift; \ mpc8xxx_spi->tx = tx; \ return data; \ -} +} \ +EXPORT_SYMBOL_GPL(mpc8xxx_spi_tx_buf_##type); MPC8XXX_SPI_RX_BUF(u8) MPC8XXX_SPI_RX_BUF(u16) @@ -60,6 +63,7 @@ struct mpc8xxx_spi_probe_info *to_of_pinfo(struct fsl_spi_platform_data *pdata) { return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata); } +EXPORT_SYMBOL_GPL(to_of_pinfo); const char *mpc8xxx_spi_strmode(unsigned int flags) { @@ -75,6 +79,7 @@ const char *mpc8xxx_spi_strmode(unsigned int flags) } return "CPU"; } +EXPORT_SYMBOL_GPL(mpc8xxx_spi_strmode); void mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) @@ -102,13 +107,12 @@ void mpc8xxx_spi_probe(struct device *dev, struct resource *mem, mpc8xxx_spi->rx_shift = 0; mpc8xxx_spi->tx_shift = 0; - init_completion(&mpc8xxx_spi->done); - master->bus_num = pdata->bus_num; master->num_chipselect = pdata->max_chipselect; init_completion(&mpc8xxx_spi->done); } +EXPORT_SYMBOL_GPL(mpc8xxx_spi_probe); int mpc8xxx_spi_remove(struct device *dev) { @@ -127,6 +131,7 @@ int mpc8xxx_spi_remove(struct device *dev) return 0; } +EXPORT_SYMBOL_GPL(mpc8xxx_spi_remove); int of_mpc8xxx_spi_probe(struct platform_device *ofdev) { @@ -173,3 +178,6 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev) return 0; } +EXPORT_SYMBOL_GPL(of_mpc8xxx_spi_probe); + +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h index b4ed04e8862f..1326a392adca 100644 --- a/drivers/spi/spi-fsl-lib.h +++ b/drivers/spi/spi-fsl-lib.h @@ -28,7 +28,7 @@ struct mpc8xxx_spi { /* rx & tx bufs from the spi_transfer */ const void *tx; void *rx; -#ifdef CONFIG_SPI_FSL_ESPI +#if IS_ENABLED(CONFIG_SPI_FSL_ESPI) int len; #endif @@ -68,7 +68,7 @@ struct mpc8xxx_spi { unsigned int flags; -#ifdef CONFIG_SPI_FSL_SPI +#if IS_ENABLED(CONFIG_SPI_FSL_SPI) int type; int native_chipselects; u8 max_bits_per_word; diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index aee4e7589568..1c34c9314c8a 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include @@ -92,7 +88,7 @@ struct spi_gpio { /*----------------------------------------------------------------------*/ -static inline struct spi_gpio * __pure +static inline struct spi_gpio *__pure spi_to_spi_gpio(const struct spi_device *spi) { const struct spi_bitbang *bang; @@ -103,7 +99,7 @@ spi_to_spi_gpio(const struct spi_device *spi) return spi_gpio; } -static inline struct spi_gpio_platform_data * __pure +static inline struct spi_gpio_platform_data *__pure spi_to_pdata(const struct spi_device *spi) { return &spi_to_spi_gpio(spi)->pdata; diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index aad6683db81b..c01567d53581 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -160,16 +160,16 @@ static unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf, unsigned int count = 0; u32 status; - while (count < max) { + while (count < max / 4) { spfi_writel(spfi, SPFI_INTERRUPT_SDFUL, SPFI_INTERRUPT_CLEAR); status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); if (status & SPFI_INTERRUPT_SDFUL) break; - spfi_writel(spfi, buf[count / 4], SPFI_TX_32BIT_VALID_DATA); - count += 4; + spfi_writel(spfi, buf[count], SPFI_TX_32BIT_VALID_DATA); + count++; } - return count; + return count * 4; } static unsigned int spfi_pio_write8(struct img_spfi *spfi, const u8 *buf, @@ -196,17 +196,17 @@ static unsigned int spfi_pio_read32(struct img_spfi *spfi, u32 *buf, unsigned int count = 0; u32 status; - while (count < max) { + while (count < max / 4) { spfi_writel(spfi, SPFI_INTERRUPT_GDEX32BIT, SPFI_INTERRUPT_CLEAR); status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); if (!(status & SPFI_INTERRUPT_GDEX32BIT)) break; - buf[count / 4] = spfi_readl(spfi, SPFI_RX_32BIT_VALID_DATA); - count += 4; + buf[count] = spfi_readl(spfi, SPFI_RX_32BIT_VALID_DATA); + count++; } - return count; + return count * 4; } static unsigned int spfi_pio_read8(struct img_spfi *spfi, u8 *buf, @@ -251,17 +251,15 @@ static int img_spfi_start_pio(struct spi_master *master, time_before(jiffies, timeout)) { unsigned int tx_count, rx_count; - switch (xfer->bits_per_word) { - case 32: + if (tx_bytes >= 4) tx_count = spfi_pio_write32(spfi, tx_buf, tx_bytes); - rx_count = spfi_pio_read32(spfi, rx_buf, rx_bytes); - break; - case 8: - default: + else tx_count = spfi_pio_write8(spfi, tx_buf, tx_bytes); + + if (rx_bytes >= 4) + rx_count = spfi_pio_read32(spfi, rx_buf, rx_bytes); + else rx_count = spfi_pio_read8(spfi, rx_buf, rx_bytes); - break; - } tx_buf += tx_count; rx_buf += rx_count; @@ -331,14 +329,11 @@ static int img_spfi_start_dma(struct spi_master *master, if (xfer->rx_buf) { rxconf.direction = DMA_DEV_TO_MEM; - switch (xfer->bits_per_word) { - case 32: + if (xfer->len % 4 == 0) { rxconf.src_addr = spfi->phys + SPFI_RX_32BIT_VALID_DATA; rxconf.src_addr_width = 4; rxconf.src_maxburst = 4; - break; - case 8: - default: + } else { rxconf.src_addr = spfi->phys + SPFI_RX_8BIT_VALID_DATA; rxconf.src_addr_width = 1; rxconf.src_maxburst = 4; @@ -358,18 +353,14 @@ static int img_spfi_start_dma(struct spi_master *master, if (xfer->tx_buf) { txconf.direction = DMA_MEM_TO_DEV; - switch (xfer->bits_per_word) { - case 32: + if (xfer->len % 4 == 0) { txconf.dst_addr = spfi->phys + SPFI_TX_32BIT_VALID_DATA; txconf.dst_addr_width = 4; txconf.dst_maxburst = 4; - break; - case 8: - default: + } else { txconf.dst_addr = spfi->phys + SPFI_TX_8BIT_VALID_DATA; txconf.dst_addr_width = 1; txconf.dst_maxburst = 4; - break; } dmaengine_slave_config(spfi->tx_ch, &txconf); @@ -508,9 +499,7 @@ static void img_spfi_set_cs(struct spi_device *spi, bool enable) static bool img_spfi_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { - if (xfer->bits_per_word == 8 && xfer->len > SPFI_8BIT_FIFO_SIZE) - return true; - if (xfer->bits_per_word == 32 && xfer->len > SPFI_32BIT_FIFO_SIZE) + if (xfer->len > SPFI_32BIT_FIFO_SIZE) return true; return false; } diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 961b97d43b43..6fea4af51c41 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -89,7 +89,6 @@ struct spi_imx_data { struct completion xfer_done; void __iomem *base; - int irq; struct clk *clk_per; struct clk *clk_ipg; unsigned long spi_clk; @@ -823,6 +822,10 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx, struct dma_slave_config slave_config = {}; int ret; + /* use pio mode for i.mx6dl chip TKT238285 */ + if (of_machine_is_compatible("fsl,imx6dl")) + return 0; + /* Prepare for TX DMA: */ master->dma_tx = dma_request_slave_channel(dev, "tx"); if (!master->dma_tx) { @@ -892,6 +895,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, { struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL; int ret; + unsigned long timeout; u32 dma; int left; struct spi_master *master = spi_imx->bitbang.master; @@ -939,17 +943,17 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, dma_async_issue_pending(master->dma_tx); dma_async_issue_pending(master->dma_rx); /* Wait SDMA to finish the data transfer.*/ - ret = wait_for_completion_timeout(&spi_imx->dma_tx_completion, + timeout = wait_for_completion_timeout(&spi_imx->dma_tx_completion, IMX_DMA_TIMEOUT); - if (!ret) { + if (!timeout) { pr_warn("%s %s: I/O Error in DMA TX\n", dev_driver_string(&master->dev), dev_name(&master->dev)); dmaengine_terminate_all(master->dma_tx); } else { - ret = wait_for_completion_timeout(&spi_imx->dma_rx_completion, - IMX_DMA_TIMEOUT); - if (!ret) { + timeout = wait_for_completion_timeout( + &spi_imx->dma_rx_completion, IMX_DMA_TIMEOUT); + if (!timeout) { pr_warn("%s %s: I/O Error in DMA RX\n", dev_driver_string(&master->dev), dev_name(&master->dev)); @@ -964,9 +968,9 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, spi_imx->dma_finished = 1; spi_imx->devtype_data->trigger(spi_imx); - if (!ret) + if (!timeout) ret = -ETIMEDOUT; - else if (ret > 0) + else ret = transfer->len; return ret; @@ -1076,7 +1080,7 @@ static int spi_imx_probe(struct platform_device *pdev) struct spi_master *master; struct spi_imx_data *spi_imx; struct resource *res; - int i, ret, num_cs; + int i, ret, num_cs, irq; if (!np && !mxc_platform_info) { dev_err(&pdev->dev, "can't get the platform data\n"); @@ -1143,16 +1147,16 @@ static int spi_imx_probe(struct platform_device *pdev) goto out_master_put; } - spi_imx->irq = platform_get_irq(pdev, 0); - if (spi_imx->irq < 0) { - ret = spi_imx->irq; + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; goto out_master_put; } - ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0, + ret = devm_request_irq(&pdev->dev, irq, spi_imx_isr, 0, dev_name(&pdev->dev), spi_imx); if (ret) { - dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret); + dev_err(&pdev->dev, "can't get irq%d: %d\n", irq, ret); goto out_master_put; } diff --git a/drivers/spi/spi-lm70llp.c b/drivers/spi/spi-lm70llp.c index 41c5765be746..ba72347cb99d 100644 --- a/drivers/spi/spi-lm70llp.c +++ b/drivers/spi/spi-lm70llp.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c index 1bbac0378bf7..5468fc70dbf8 100644 --- a/drivers/spi/spi-meson-spifc.c +++ b/drivers/spi/spi-meson-spifc.c @@ -85,7 +85,7 @@ struct meson_spifc { struct device *dev; }; -static struct regmap_config spifc_regmap_config = { +static const struct regmap_config spifc_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 4045a1e580e1..5b0e9a3e83f6 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -282,9 +282,8 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, dmaengine_submit(desc); dma_async_issue_pending(ssp->dmach); - ret = wait_for_completion_timeout(&spi->c, - msecs_to_jiffies(SSP_TIMEOUT)); - if (!ret) { + if (!wait_for_completion_timeout(&spi->c, + msecs_to_jiffies(SSP_TIMEOUT))) { dev_err(ssp->dev, "DMA transfer timeout\n"); ret = -ETIMEDOUT; dmaengine_terminate_all(ssp->dmach); diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 79399ae9c84c..d890d309dff9 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -16,11 +16,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include #include diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index daf1ada5cd11..3c0844457c07 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -28,10 +28,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 3bc3cbabbbc0..4df8942058de 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -14,11 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 3dec9e0b99b8..861664776672 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -28,7 +28,12 @@ /* Runtime PM autosuspend timeout: PM is fairly light on this driver */ #define SPI_AUTOSUSPEND_TIMEOUT 200 -#define ORION_NUM_CHIPSELECTS 1 /* only one slave is supported*/ +/* Some SoCs using this driver support up to 8 chip selects. + * It is up to the implementer to only use the chip selects + * that are available. + */ +#define ORION_NUM_CHIPSELECTS 8 + #define ORION_SPI_WAIT_RDY_MAX_LOOP 2000 /* in usec */ #define ORION_SPI_IF_CTRL_REG 0x00 @@ -44,6 +49,10 @@ #define ARMADA_SPI_CLK_PRESCALE_MASK 0xDF #define ORION_SPI_MODE_MASK (ORION_SPI_MODE_CPOL | \ ORION_SPI_MODE_CPHA) +#define ORION_SPI_CS_MASK 0x1C +#define ORION_SPI_CS_SHIFT 2 +#define ORION_SPI_CS(cs) ((cs << ORION_SPI_CS_SHIFT) & \ + ORION_SPI_CS_MASK) enum orion_spi_type { ORION_SPI, @@ -215,9 +224,18 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) return 0; } -static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable) +static void orion_spi_set_cs(struct spi_device *spi, bool enable) { - if (enable) + struct orion_spi *orion_spi; + + orion_spi = spi_master_get_devdata(spi->master); + + orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS_MASK); + orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, + ORION_SPI_CS(spi->chip_select)); + + /* Chip select logic is inverted from spi_set_cs */ + if (!enable) orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1); else orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1); @@ -332,64 +350,31 @@ out: return xfer->len - count; } -static int orion_spi_transfer_one_message(struct spi_master *master, - struct spi_message *m) +static int orion_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) { - struct orion_spi *orion_spi = spi_master_get_devdata(master); - struct spi_device *spi = m->spi; - struct spi_transfer *t = NULL; - int par_override = 0; int status = 0; - int cs_active = 0; - - /* Load defaults */ - status = orion_spi_setup_transfer(spi, NULL); + status = orion_spi_setup_transfer(spi, t); if (status < 0) - goto msg_done; + return status; - list_for_each_entry(t, &m->transfers, transfer_list) { - if (par_override || t->speed_hz || t->bits_per_word) { - par_override = 1; - status = orion_spi_setup_transfer(spi, t); - if (status < 0) - break; - if (!t->speed_hz && !t->bits_per_word) - par_override = 0; - } + if (t->len) + orion_spi_write_read(spi, t); - if (!cs_active) { - orion_spi_set_cs(orion_spi, 1); - cs_active = 1; - } + return status; +} - if (t->len) - m->actual_length += orion_spi_write_read(spi, t); - - if (t->delay_usecs) - udelay(t->delay_usecs); - - if (t->cs_change) { - orion_spi_set_cs(orion_spi, 0); - cs_active = 0; - } - } - -msg_done: - if (cs_active) - orion_spi_set_cs(orion_spi, 0); - - m->status = status; - spi_finalize_current_message(master); - - return 0; +static int orion_spi_setup(struct spi_device *spi) +{ + return orion_spi_setup_transfer(spi, NULL); } static int orion_spi_reset(struct orion_spi *orion_spi) { /* Verify that the CS is deasserted */ - orion_spi_set_cs(orion_spi, 0); - + orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1); return 0; } @@ -442,9 +427,10 @@ static int orion_spi_probe(struct platform_device *pdev) /* we support only mode 0, and no options */ master->mode_bits = SPI_CPHA | SPI_CPOL; - - master->transfer_one_message = orion_spi_transfer_one_message; + master->set_cs = orion_spi_set_cs; + master->transfer_one = orion_spi_transfer_one; master->num_chipselect = ORION_NUM_CHIPSELECTS; + master->setup = orion_spi_setup; master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); master->auto_runtime_pm = true; diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 62a9297e96ac..66a173939be8 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -111,23 +111,24 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, * by using ->dma_running. */ if (atomic_dec_and_test(&drv_data->dma_running)) { - void __iomem *reg = drv_data->ioaddr; - /* * If the other CPU is still handling the ROR interrupt we * might not know about the error yet. So we re-check the * ROR bit here before we clear the status register. */ if (!error) { - u32 status = read_SSSR(reg) & drv_data->mask_sr; + u32 status = pxa2xx_spi_read(drv_data, SSSR) + & drv_data->mask_sr; error = status & SSSR_ROR; } /* Clear status & disable interrupts */ - write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); + pxa2xx_spi_write(drv_data, SSCR1, + pxa2xx_spi_read(drv_data, SSCR1) + & ~drv_data->dma_cr1); write_SSSR_CS(drv_data, drv_data->clear_sr); if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(0, reg); + pxa2xx_spi_write(drv_data, SSTO, 0); if (!error) { pxa2xx_spi_unmap_dma_buffers(drv_data); @@ -139,7 +140,9 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, msg->state = pxa2xx_spi_next_transfer(drv_data); } else { /* In case we got an error we disable the SSP now */ - write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); + pxa2xx_spi_write(drv_data, SSCR0, + pxa2xx_spi_read(drv_data, SSCR0) + & ~SSCR0_SSE); msg->state = ERROR_STATE; } @@ -247,7 +250,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) { u32 status; - status = read_SSSR(drv_data->ioaddr) & drv_data->mask_sr; + status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr; if (status & SSSR_ROR) { dev_err(&drv_data->pdev->dev, "FIFO overrun\n"); diff --git a/drivers/spi/spi-pxa2xx-pxadma.c b/drivers/spi/spi-pxa2xx-pxadma.c index e8a26f25d5c0..2e0796a0003f 100644 --- a/drivers/spi/spi-pxa2xx-pxadma.c +++ b/drivers/spi/spi-pxa2xx-pxadma.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include @@ -25,6 +21,7 @@ #include #include +#include #include "spi-pxa2xx.h" #define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR) @@ -118,11 +115,11 @@ static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data) drv_data->dma_mapped = 0; } -static int wait_ssp_rx_stall(void const __iomem *ioaddr) +static int wait_ssp_rx_stall(struct driver_data *drv_data) { unsigned long limit = loops_per_jiffy << 1; - while ((read_SSSR(ioaddr) & SSSR_BSY) && --limit) + while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit) cpu_relax(); return limit; @@ -141,17 +138,18 @@ static int wait_dma_channel_stop(int channel) static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data, const char *msg) { - void __iomem *reg = drv_data->ioaddr; - /* Stop and reset */ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; write_SSSR_CS(drv_data, drv_data->clear_sr); - write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); + pxa2xx_spi_write(drv_data, SSCR1, + pxa2xx_spi_read(drv_data, SSCR1) + & ~drv_data->dma_cr1); if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(0, reg); + pxa2xx_spi_write(drv_data, SSTO, 0); pxa2xx_spi_flush(drv_data); - write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); + pxa2xx_spi_write(drv_data, SSCR0, + pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); pxa2xx_spi_unmap_dma_buffers(drv_data); @@ -163,11 +161,12 @@ static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data, static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; struct spi_message *msg = drv_data->cur_msg; /* Clear and disable interrupts on SSP and DMA channels*/ - write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); + pxa2xx_spi_write(drv_data, SSCR1, + pxa2xx_spi_read(drv_data, SSCR1) + & ~drv_data->dma_cr1); write_SSSR_CS(drv_data, drv_data->clear_sr); DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; @@ -228,7 +227,7 @@ void pxa2xx_spi_dma_handler(int channel, void *data) && (drv_data->ssp_type == PXA25x_SSP)) { /* Wait for rx to stall */ - if (wait_ssp_rx_stall(drv_data->ioaddr) == 0) + if (wait_ssp_rx_stall(drv_data) == 0) dev_err(&drv_data->pdev->dev, "dma_handler: ssp rx stall failed\n"); @@ -240,9 +239,8 @@ void pxa2xx_spi_dma_handler(int channel, void *data) irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) { u32 irq_status; - void __iomem *reg = drv_data->ioaddr; - irq_status = read_SSSR(reg) & drv_data->mask_sr; + irq_status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr; if (irq_status & SSSR_ROR) { pxa2xx_spi_dma_error_stop(drv_data, "dma_transfer: fifo overrun"); @@ -252,7 +250,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) /* Check for false positive timeout */ if ((irq_status & SSSR_TINT) && (DCSR(drv_data->tx_channel) & DCSR_RUN)) { - write_SSSR(SSSR_TINT, reg); + pxa2xx_spi_write(drv_data, SSSR, SSSR_TINT); return IRQ_HANDLED; } @@ -261,7 +259,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) /* Clear and disable timeout interrupt, do the rest in * dma_transfer_complete */ if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(0, reg); + pxa2xx_spi_write(drv_data, SSTO, 0); /* finish this transfer, start the next */ pxa2xx_spi_dma_transfer_complete(drv_data); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 05c623cfb078..6f72ad01e041 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include @@ -45,8 +41,6 @@ MODULE_DESCRIPTION("PXA2xx SSP SPI Controller"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:pxa2xx-spi"); -#define MAX_BUSES 3 - #define TIMOUT_DFLT 1000 /* @@ -162,7 +156,6 @@ pxa2xx_spi_get_rx_default_thre(const struct driver_data *drv_data) static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; u32 mask; switch (drv_data->ssp_type) { @@ -174,7 +167,7 @@ static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data) break; } - return (read_SSSR(reg) & mask) == mask; + return (pxa2xx_spi_read(drv_data, SSSR) & mask) == mask; } static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data, @@ -253,9 +246,6 @@ static void lpss_ssp_setup(struct driver_data *drv_data) unsigned offset = 0x400; u32 value, orig; - if (!is_lpss_ssp(drv_data)) - return; - /* * Perform auto-detection of the LPSS SSP private registers. They * can be either at 1k or 2k offset from the base address. @@ -304,9 +294,6 @@ static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) { u32 value; - if (!is_lpss_ssp(drv_data)) - return; - value = __lpss_ssp_read_priv(drv_data, SPI_CS_CONTROL); if (enable) value &= ~SPI_CS_CONTROL_CS_HIGH; @@ -320,7 +307,7 @@ static void cs_assert(struct driver_data *drv_data) struct chip_data *chip = drv_data->cur_chip; if (drv_data->ssp_type == CE4100_SSP) { - write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSSR, drv_data->cur_chip->frm); return; } @@ -334,7 +321,8 @@ static void cs_assert(struct driver_data *drv_data) return; } - lpss_ssp_cs_control(drv_data, true); + if (is_lpss_ssp(drv_data)) + lpss_ssp_cs_control(drv_data, true); } static void cs_deassert(struct driver_data *drv_data) @@ -354,20 +342,18 @@ static void cs_deassert(struct driver_data *drv_data) return; } - lpss_ssp_cs_control(drv_data, false); + if (is_lpss_ssp(drv_data)) + lpss_ssp_cs_control(drv_data, false); } int pxa2xx_spi_flush(struct driver_data *drv_data) { unsigned long limit = loops_per_jiffy << 1; - void __iomem *reg = drv_data->ioaddr; - do { - while (read_SSSR(reg) & SSSR_RNE) { - read_SSDR(reg); - } - } while ((read_SSSR(reg) & SSSR_BSY) && --limit); + while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) + pxa2xx_spi_read(drv_data, SSDR); + } while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit); write_SSSR_CS(drv_data, SSSR_ROR); return limit; @@ -375,14 +361,13 @@ int pxa2xx_spi_flush(struct driver_data *drv_data) static int null_writer(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; u8 n_bytes = drv_data->n_bytes; if (pxa2xx_spi_txfifo_full(drv_data) || (drv_data->tx == drv_data->tx_end)) return 0; - write_SSDR(0, reg); + pxa2xx_spi_write(drv_data, SSDR, 0); drv_data->tx += n_bytes; return 1; @@ -390,12 +375,11 @@ static int null_writer(struct driver_data *drv_data) static int null_reader(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; u8 n_bytes = drv_data->n_bytes; - while ((read_SSSR(reg) & SSSR_RNE) - && (drv_data->rx < drv_data->rx_end)) { - read_SSDR(reg); + while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) + && (drv_data->rx < drv_data->rx_end)) { + pxa2xx_spi_read(drv_data, SSDR); drv_data->rx += n_bytes; } @@ -404,13 +388,11 @@ static int null_reader(struct driver_data *drv_data) static int u8_writer(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - if (pxa2xx_spi_txfifo_full(drv_data) || (drv_data->tx == drv_data->tx_end)) return 0; - write_SSDR(*(u8 *)(drv_data->tx), reg); + pxa2xx_spi_write(drv_data, SSDR, *(u8 *)(drv_data->tx)); ++drv_data->tx; return 1; @@ -418,11 +400,9 @@ static int u8_writer(struct driver_data *drv_data) static int u8_reader(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - - while ((read_SSSR(reg) & SSSR_RNE) - && (drv_data->rx < drv_data->rx_end)) { - *(u8 *)(drv_data->rx) = read_SSDR(reg); + while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) + && (drv_data->rx < drv_data->rx_end)) { + *(u8 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR); ++drv_data->rx; } @@ -431,13 +411,11 @@ static int u8_reader(struct driver_data *drv_data) static int u16_writer(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - if (pxa2xx_spi_txfifo_full(drv_data) || (drv_data->tx == drv_data->tx_end)) return 0; - write_SSDR(*(u16 *)(drv_data->tx), reg); + pxa2xx_spi_write(drv_data, SSDR, *(u16 *)(drv_data->tx)); drv_data->tx += 2; return 1; @@ -445,11 +423,9 @@ static int u16_writer(struct driver_data *drv_data) static int u16_reader(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - - while ((read_SSSR(reg) & SSSR_RNE) - && (drv_data->rx < drv_data->rx_end)) { - *(u16 *)(drv_data->rx) = read_SSDR(reg); + while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) + && (drv_data->rx < drv_data->rx_end)) { + *(u16 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR); drv_data->rx += 2; } @@ -458,13 +434,11 @@ static int u16_reader(struct driver_data *drv_data) static int u32_writer(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - if (pxa2xx_spi_txfifo_full(drv_data) || (drv_data->tx == drv_data->tx_end)) return 0; - write_SSDR(*(u32 *)(drv_data->tx), reg); + pxa2xx_spi_write(drv_data, SSDR, *(u32 *)(drv_data->tx)); drv_data->tx += 4; return 1; @@ -472,11 +446,9 @@ static int u32_writer(struct driver_data *drv_data) static int u32_reader(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - - while ((read_SSSR(reg) & SSSR_RNE) - && (drv_data->rx < drv_data->rx_end)) { - *(u32 *)(drv_data->rx) = read_SSDR(reg); + while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) + && (drv_data->rx < drv_data->rx_end)) { + *(u32 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR); drv_data->rx += 4; } @@ -546,33 +518,31 @@ static void giveback(struct driver_data *drv_data) cs_deassert(drv_data); } - spi_finalize_current_message(drv_data->master); drv_data->cur_chip = NULL; + spi_finalize_current_message(drv_data->master); } static void reset_sccr1(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; struct chip_data *chip = drv_data->cur_chip; u32 sccr1_reg; - sccr1_reg = read_SSCR1(reg) & ~drv_data->int_cr1; + sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1; sccr1_reg &= ~SSCR1_RFT; sccr1_reg |= chip->threshold; - write_SSCR1(sccr1_reg, reg); + pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg); } static void int_error_stop(struct driver_data *drv_data, const char* msg) { - void __iomem *reg = drv_data->ioaddr; - /* Stop and reset SSP */ write_SSSR_CS(drv_data, drv_data->clear_sr); reset_sccr1(drv_data); if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(0, reg); + pxa2xx_spi_write(drv_data, SSTO, 0); pxa2xx_spi_flush(drv_data); - write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); + pxa2xx_spi_write(drv_data, SSCR0, + pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); dev_err(&drv_data->pdev->dev, "%s\n", msg); @@ -582,13 +552,11 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg) static void int_transfer_complete(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; - /* Stop SSP */ write_SSSR_CS(drv_data, drv_data->clear_sr); reset_sccr1(drv_data); if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(0, reg); + pxa2xx_spi_write(drv_data, SSTO, 0); /* Update total byte transferred return count actual bytes read */ drv_data->cur_msg->actual_length += drv_data->len - @@ -607,12 +575,10 @@ static void int_transfer_complete(struct driver_data *drv_data) static irqreturn_t interrupt_transfer(struct driver_data *drv_data) { - void __iomem *reg = drv_data->ioaddr; + u32 irq_mask = (pxa2xx_spi_read(drv_data, SSCR1) & SSCR1_TIE) ? + drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS; - u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ? - drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS; - - u32 irq_status = read_SSSR(reg) & irq_mask; + u32 irq_status = pxa2xx_spi_read(drv_data, SSSR) & irq_mask; if (irq_status & SSSR_ROR) { int_error_stop(drv_data, "interrupt_transfer: fifo overrun"); @@ -620,7 +586,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) } if (irq_status & SSSR_TINT) { - write_SSSR(SSSR_TINT, reg); + pxa2xx_spi_write(drv_data, SSSR, SSSR_TINT); if (drv_data->read(drv_data)) { int_transfer_complete(drv_data); return IRQ_HANDLED; @@ -644,7 +610,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) u32 bytes_left; u32 sccr1_reg; - sccr1_reg = read_SSCR1(reg); + sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1); sccr1_reg &= ~SSCR1_TIE; /* @@ -670,7 +636,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) pxa2xx_spi_set_rx_thre(drv_data, &sccr1_reg, rx_thre); } - write_SSCR1(sccr1_reg, reg); + pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg); } /* We did something */ @@ -680,7 +646,6 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) static irqreturn_t ssp_int(int irq, void *dev_id) { struct driver_data *drv_data = dev_id; - void __iomem *reg = drv_data->ioaddr; u32 sccr1_reg; u32 mask = drv_data->mask_sr; u32 status; @@ -700,11 +665,11 @@ static irqreturn_t ssp_int(int irq, void *dev_id) * are all set to one. That means that the device is already * powered off. */ - status = read_SSSR(reg); + status = pxa2xx_spi_read(drv_data, SSSR); if (status == ~0) return IRQ_NONE; - sccr1_reg = read_SSCR1(reg); + sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1); /* Ignore possible writes if we don't need to write */ if (!(sccr1_reg & SSCR1_TIE)) @@ -715,10 +680,14 @@ static irqreturn_t ssp_int(int irq, void *dev_id) if (!drv_data->cur_msg) { - write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); - write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); + pxa2xx_spi_write(drv_data, SSCR0, + pxa2xx_spi_read(drv_data, SSCR0) + & ~SSCR0_SSE); + pxa2xx_spi_write(drv_data, SSCR1, + pxa2xx_spi_read(drv_data, SSCR1) + & ~drv_data->int_cr1); if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(0, reg); + pxa2xx_spi_write(drv_data, SSTO, 0); write_SSSR_CS(drv_data, drv_data->clear_sr); dev_err(&drv_data->pdev->dev, @@ -787,7 +756,6 @@ static void pump_transfers(unsigned long data) struct spi_transfer *transfer = NULL; struct spi_transfer *previous = NULL; struct chip_data *chip = NULL; - void __iomem *reg = drv_data->ioaddr; u32 clk_div = 0; u8 bits = 0; u32 speed = 0; @@ -931,7 +899,7 @@ static void pump_transfers(unsigned long data) /* Clear status and start DMA engine */ cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1; - write_SSSR(drv_data->clear_sr, reg); + pxa2xx_spi_write(drv_data, SSSR, drv_data->clear_sr); pxa2xx_spi_dma_start(drv_data); } else { @@ -944,39 +912,43 @@ static void pump_transfers(unsigned long data) } if (is_lpss_ssp(drv_data)) { - if ((read_SSIRF(reg) & 0xff) != chip->lpss_rx_threshold) - write_SSIRF(chip->lpss_rx_threshold, reg); - if ((read_SSITF(reg) & 0xffff) != chip->lpss_tx_threshold) - write_SSITF(chip->lpss_tx_threshold, reg); + if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff) + != chip->lpss_rx_threshold) + pxa2xx_spi_write(drv_data, SSIRF, + chip->lpss_rx_threshold); + if ((pxa2xx_spi_read(drv_data, SSITF) & 0xffff) + != chip->lpss_tx_threshold) + pxa2xx_spi_write(drv_data, SSITF, + chip->lpss_tx_threshold); } if (is_quark_x1000_ssp(drv_data) && - (read_DDS_RATE(reg) != chip->dds_rate)) - write_DDS_RATE(chip->dds_rate, reg); + (pxa2xx_spi_read(drv_data, DDS_RATE) != chip->dds_rate)) + pxa2xx_spi_write(drv_data, DDS_RATE, chip->dds_rate); /* see if we need to reload the config registers */ - if ((read_SSCR0(reg) != cr0) || - (read_SSCR1(reg) & change_mask) != (cr1 & change_mask)) { - + if ((pxa2xx_spi_read(drv_data, SSCR0) != cr0) + || (pxa2xx_spi_read(drv_data, SSCR1) & change_mask) + != (cr1 & change_mask)) { /* stop the SSP, and update the other bits */ - write_SSCR0(cr0 & ~SSCR0_SSE, reg); + pxa2xx_spi_write(drv_data, SSCR0, cr0 & ~SSCR0_SSE); if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(chip->timeout, reg); + pxa2xx_spi_write(drv_data, SSTO, chip->timeout); /* first set CR1 without interrupt and service enables */ - write_SSCR1(cr1 & change_mask, reg); + pxa2xx_spi_write(drv_data, SSCR1, cr1 & change_mask); /* restart the SSP */ - write_SSCR0(cr0, reg); + pxa2xx_spi_write(drv_data, SSCR0, cr0); } else { if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(chip->timeout, reg); + pxa2xx_spi_write(drv_data, SSTO, chip->timeout); } cs_assert(drv_data); /* after chip select, release the data by enabling service * requests and interrupts, without changing any mode bits */ - write_SSCR1(cr1, reg); + pxa2xx_spi_write(drv_data, SSCR1, cr1); } static int pxa2xx_spi_transfer_one_message(struct spi_master *master, @@ -1005,8 +977,8 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_master *master) struct driver_data *drv_data = spi_master_get_devdata(master); /* Disable the SSP now */ - write_SSCR0(read_SSCR0(drv_data->ioaddr) & ~SSCR0_SSE, - drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSCR0, + pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); return 0; } @@ -1289,6 +1261,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) struct driver_data *drv_data; struct ssp_device *ssp; int status; + u32 tmp; platform_info = dev_get_platdata(dev); if (!platform_info) { @@ -1386,38 +1359,35 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) drv_data->max_clk_rate = clk_get_rate(ssp->clk); /* Load default SSP configuration */ - write_SSCR0(0, drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSCR0, 0); switch (drv_data->ssp_type) { case QUARK_X1000_SSP: - write_SSCR1(QUARK_X1000_SSCR1_RxTresh( - RX_THRESH_QUARK_X1000_DFLT) | - QUARK_X1000_SSCR1_TxTresh( - TX_THRESH_QUARK_X1000_DFLT), - drv_data->ioaddr); + tmp = QUARK_X1000_SSCR1_RxTresh(RX_THRESH_QUARK_X1000_DFLT) + | QUARK_X1000_SSCR1_TxTresh(TX_THRESH_QUARK_X1000_DFLT); + pxa2xx_spi_write(drv_data, SSCR1, tmp); /* using the Motorola SPI protocol and use 8 bit frame */ - write_SSCR0(QUARK_X1000_SSCR0_Motorola - | QUARK_X1000_SSCR0_DataSize(8), - drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSCR0, + QUARK_X1000_SSCR0_Motorola + | QUARK_X1000_SSCR0_DataSize(8)); break; default: - write_SSCR1(SSCR1_RxTresh(RX_THRESH_DFLT) | - SSCR1_TxTresh(TX_THRESH_DFLT), - drv_data->ioaddr); - write_SSCR0(SSCR0_SCR(2) - | SSCR0_Motorola - | SSCR0_DataSize(8), - drv_data->ioaddr); + tmp = SSCR1_RxTresh(RX_THRESH_DFLT) | + SSCR1_TxTresh(TX_THRESH_DFLT); + pxa2xx_spi_write(drv_data, SSCR1, tmp); + tmp = SSCR0_SCR(2) | SSCR0_Motorola | SSCR0_DataSize(8); + pxa2xx_spi_write(drv_data, SSCR0, tmp); break; } if (!pxa25x_ssp_comp(drv_data)) - write_SSTO(0, drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSTO, 0); if (!is_quark_x1000_ssp(drv_data)) - write_SSPSP(0, drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSPSP, 0); - lpss_ssp_setup(drv_data); + if (is_lpss_ssp(drv_data)) + lpss_ssp_setup(drv_data); tasklet_init(&drv_data->pump_transfers, pump_transfers, (unsigned long)drv_data); @@ -1460,7 +1430,7 @@ static int pxa2xx_spi_remove(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); /* Disable the SSP at the peripheral and SOC level */ - write_SSCR0(0, drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSCR0, 0); clk_disable_unprepare(ssp->clk); /* Release DMA */ @@ -1497,7 +1467,7 @@ static int pxa2xx_spi_suspend(struct device *dev) status = spi_master_suspend(drv_data->master); if (status != 0) return status; - write_SSCR0(0, drv_data->ioaddr); + pxa2xx_spi_write(drv_data, SSCR0, 0); if (!pm_runtime_suspended(dev)) clk_disable_unprepare(ssp->clk); @@ -1518,7 +1488,8 @@ static int pxa2xx_spi_resume(struct device *dev) clk_prepare_enable(ssp->clk); /* Restore LPSS private register bits */ - lpss_ssp_setup(drv_data); + if (is_lpss_ssp(drv_data)) + lpss_ssp_setup(drv_data); /* Start the queue running */ status = spi_master_resume(drv_data->master); diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 6bec59c90cd4..85a58c906869 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -115,23 +115,17 @@ struct chip_data { void (*cs_control)(u32 command); }; -#define DEFINE_SSP_REG(reg, off) \ -static inline u32 read_##reg(void const __iomem *p) \ -{ return __raw_readl(p + (off)); } \ -\ -static inline void write_##reg(u32 v, void __iomem *p) \ -{ __raw_writel(v, p + (off)); } +static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, + unsigned reg) +{ + return __raw_readl(drv_data->ioaddr + reg); +} -DEFINE_SSP_REG(SSCR0, 0x00) -DEFINE_SSP_REG(SSCR1, 0x04) -DEFINE_SSP_REG(SSSR, 0x08) -DEFINE_SSP_REG(SSITR, 0x0c) -DEFINE_SSP_REG(SSDR, 0x10) -DEFINE_SSP_REG(DDS_RATE, 0x28) /* DDS Clock Rate */ -DEFINE_SSP_REG(SSTO, 0x28) -DEFINE_SSP_REG(SSPSP, 0x2c) -DEFINE_SSP_REG(SSITF, SSITF) -DEFINE_SSP_REG(SSIRF, SSIRF) +static inline void pxa2xx_spi_write(const struct driver_data *drv_data, + unsigned reg, u32 val) +{ + __raw_writel(val, drv_data->ioaddr + reg); +} #define START_STATE ((void *)0) #define RUNNING_STATE ((void *)1) @@ -155,13 +149,11 @@ static inline int pxa25x_ssp_comp(struct driver_data *drv_data) static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val) { - void __iomem *reg = drv_data->ioaddr; - if (drv_data->ssp_type == CE4100_SSP || drv_data->ssp_type == QUARK_X1000_SSP) - val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK; + val |= pxa2xx_spi_read(drv_data, SSSR) & SSSR_ALT_FRM_MASK; - write_SSSR(val, reg); + pxa2xx_spi_write(drv_data, SSSR, val); } extern int pxa2xx_spi_flush(struct driver_data *drv_data); diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index e7fb5a0d2e8d..ff9cdbdb6672 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -337,7 +337,7 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) { struct spi_qup *controller = spi_master_get_devdata(spi->master); - u32 config, iomode, mode; + u32 config, iomode, mode, control; int ret, n_words, w_size; if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) { @@ -392,6 +392,15 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) writel_relaxed(iomode, controller->base + QUP_IO_M_MODES); + control = readl_relaxed(controller->base + SPI_IO_CONTROL); + + if (spi->mode & SPI_CPOL) + control |= SPI_IO_C_CLK_IDLE_HIGH; + else + control &= ~SPI_IO_C_CLK_IDLE_HIGH; + + writel_relaxed(control, controller->base + SPI_IO_CONTROL); + config = readl_relaxed(controller->base + SPI_CONFIG); if (spi->mode & SPI_LOOP) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index daabbabd26b0..1a777dc261d6 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -437,6 +437,7 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs) rs->state &= ~TXBUSY; spin_unlock_irqrestore(&rs->lock, flags); + rxdesc = NULL; if (rs->rx) { rxconf.direction = rs->dma_rx.direction; rxconf.src_addr = rs->dma_rx.addr; @@ -453,6 +454,7 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs) rxdesc->callback_param = rs; } + txdesc = NULL; if (rs->tx) { txconf.direction = rs->dma_tx.direction; txconf.dst_addr = rs->dma_tx.addr; @@ -470,7 +472,7 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs) } /* rx must be started before tx due to spi instinct */ - if (rs->rx) { + if (rxdesc) { spin_lock_irqsave(&rs->lock, flags); rs->state |= RXBUSY; spin_unlock_irqrestore(&rs->lock, flags); @@ -478,7 +480,7 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs) dma_async_issue_pending(rs->dma_rx.ch); } - if (rs->tx) { + if (txdesc) { spin_lock_irqsave(&rs->lock, flags); rs->state |= TXBUSY; spin_unlock_irqrestore(&rs->lock, flags); diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 2071f788c6fb..46ce47076e63 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -15,11 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 37b19836f5cb..9231c34b5a5c 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c index 237f2e7a7179..5a56acf8a43e 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index fc29233d0650..20e800e70442 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -16,11 +16,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 96a5fc0878d8..e57eec0b2f46 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -82,7 +82,9 @@ struct sh_msiof_spi_priv { #define MDR1_SYNCMD_LR 0x30000000 /* L/R mode */ #define MDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */ #define MDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */ -#define MDR1_FLD_MASK 0x000000c0 /* Frame Sync Signal Interval (0-3) */ +#define MDR1_DTDL_SHIFT 20 /* Data Pin Bit Delay for MSIOF_SYNC */ +#define MDR1_SYNCDL_SHIFT 16 /* Frame Sync Signal Timing Delay */ +#define MDR1_FLD_MASK 0x0000000c /* Frame Sync Signal Interval (0-3) */ #define MDR1_FLD_SHIFT 2 #define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */ /* TMDR1 */ @@ -241,42 +243,80 @@ static irqreturn_t sh_msiof_spi_irq(int irq, void *data) static struct { unsigned short div; - unsigned short scr; -} const sh_msiof_spi_clk_table[] = { - { 1, SCR_BRPS( 1) | SCR_BRDV_DIV_1 }, - { 2, SCR_BRPS( 1) | SCR_BRDV_DIV_2 }, - { 4, SCR_BRPS( 1) | SCR_BRDV_DIV_4 }, - { 8, SCR_BRPS( 1) | SCR_BRDV_DIV_8 }, - { 16, SCR_BRPS( 1) | SCR_BRDV_DIV_16 }, - { 32, SCR_BRPS( 1) | SCR_BRDV_DIV_32 }, - { 64, SCR_BRPS(32) | SCR_BRDV_DIV_2 }, - { 128, SCR_BRPS(32) | SCR_BRDV_DIV_4 }, - { 256, SCR_BRPS(32) | SCR_BRDV_DIV_8 }, - { 512, SCR_BRPS(32) | SCR_BRDV_DIV_16 }, - { 1024, SCR_BRPS(32) | SCR_BRDV_DIV_32 }, + unsigned short brdv; +} const sh_msiof_spi_div_table[] = { + { 1, SCR_BRDV_DIV_1 }, + { 2, SCR_BRDV_DIV_2 }, + { 4, SCR_BRDV_DIV_4 }, + { 8, SCR_BRDV_DIV_8 }, + { 16, SCR_BRDV_DIV_16 }, + { 32, SCR_BRDV_DIV_32 }, }; static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, unsigned long parent_rate, u32 spi_hz) { unsigned long div = 1024; + u32 brps, scr; size_t k; if (!WARN_ON(!spi_hz || !parent_rate)) div = DIV_ROUND_UP(parent_rate, spi_hz); - /* TODO: make more fine grained */ - - for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_clk_table); k++) { - if (sh_msiof_spi_clk_table[k].div >= div) + for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_div_table); k++) { + brps = DIV_ROUND_UP(div, sh_msiof_spi_div_table[k].div); + if (brps <= 32) /* max of brdv is 32 */ break; } - k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1); + k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_div_table) - 1); - sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr); + scr = sh_msiof_spi_div_table[k].brdv | SCR_BRPS(brps); + sh_msiof_write(p, TSCR, scr); if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX)) - sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr); + sh_msiof_write(p, RSCR, scr); +} + +static u32 sh_msiof_get_delay_bit(u32 dtdl_or_syncdl) +{ + /* + * DTDL/SYNCDL bit : p->info->dtdl or p->info->syncdl + * b'000 : 0 + * b'001 : 100 + * b'010 : 200 + * b'011 (SYNCDL only) : 300 + * b'101 : 50 + * b'110 : 150 + */ + if (dtdl_or_syncdl % 100) + return dtdl_or_syncdl / 100 + 5; + else + return dtdl_or_syncdl / 100; +} + +static u32 sh_msiof_spi_get_dtdl_and_syncdl(struct sh_msiof_spi_priv *p) +{ + u32 val; + + if (!p->info) + return 0; + + /* check if DTDL and SYNCDL is allowed value */ + if (p->info->dtdl > 200 || p->info->syncdl > 300) { + dev_warn(&p->pdev->dev, "DTDL or SYNCDL is too large\n"); + return 0; + } + + /* check if the sum of DTDL and SYNCDL becomes an integer value */ + if ((p->info->dtdl + p->info->syncdl) % 100) { + dev_warn(&p->pdev->dev, "the sum of DTDL/SYNCDL is not good\n"); + return 0; + } + + val = sh_msiof_get_delay_bit(p->info->dtdl) << MDR1_DTDL_SHIFT; + val |= sh_msiof_get_delay_bit(p->info->syncdl) << MDR1_SYNCDL_SHIFT; + + return val; } static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, @@ -296,6 +336,7 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP; tmp |= !cs_high << MDR1_SYNCAC_SHIFT; tmp |= lsb_first << MDR1_BITLSB_SHIFT; + tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p); sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) { /* These bits are reserved if RX needs TX */ @@ -501,7 +542,7 @@ static int sh_msiof_spi_setup(struct spi_device *spi) gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); - pm_runtime_put_sync(&p->pdev->dev); + pm_runtime_put(&p->pdev->dev); return 0; } @@ -595,8 +636,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, } /* wait for tx fifo to be emptied / rx fifo to be filled */ - ret = wait_for_completion_timeout(&p->done, HZ); - if (!ret) { + if (!wait_for_completion_timeout(&p->done, HZ)) { dev_err(&p->pdev->dev, "PIO timeout\n"); ret = -ETIMEDOUT; goto stop_reset; @@ -706,8 +746,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, } /* wait for tx fifo to be emptied / rx fifo to be filled */ - ret = wait_for_completion_timeout(&p->done, HZ); - if (!ret) { + if (!wait_for_completion_timeout(&p->done, HZ)) { dev_err(&p->pdev->dev, "DMA timeout\n"); ret = -ETIMEDOUT; goto stop_reset; @@ -957,6 +996,8 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) &info->tx_fifo_override); of_property_read_u32(np, "renesas,rx-fifo-size", &info->rx_fifo_override); + of_property_read_u32(np, "renesas,dtdl", &info->dtdl); + of_property_read_u32(np, "renesas,syncdl", &info->syncdl); info->num_chipselect = num_cs; diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c index 1cfc906dd174..502501187c9e 100644 --- a/drivers/spi/spi-sh.c +++ b/drivers/spi/spi-sh.c @@ -14,11 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index d075191476f0..f5715c9f68b0 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -818,7 +818,6 @@ static SIMPLE_DEV_PM_OPS(spi_sirfsoc_pm_ops, spi_sirfsoc_suspend, static const struct of_device_id spi_sirfsoc_of_match[] = { { .compatible = "sirf,prima2-spi", }, - { .compatible = "sirf,marco-spi", }, {} }; MODULE_DEVICE_TABLE(of, spi_sirfsoc_of_match); diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c new file mode 100644 index 000000000000..2faeaa7b57a8 --- /dev/null +++ b/drivers/spi/spi-st-ssc4.c @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2008-2014 STMicroelectronics Limited + * + * Author: Angus Clark + * Patrice Chotard + * Lee Jones + * + * SPI master mode controller driver, used in STMicroelectronics devices. + * + * May be copied or modified under the terms of the GNU General Public + * License Version 2.0 only. See linux/COPYING for more information. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* SSC registers */ +#define SSC_BRG 0x000 +#define SSC_TBUF 0x004 +#define SSC_RBUF 0x008 +#define SSC_CTL 0x00C +#define SSC_IEN 0x010 +#define SSC_I2C 0x018 + +/* SSC Control */ +#define SSC_CTL_DATA_WIDTH_9 0x8 +#define SSC_CTL_DATA_WIDTH_MSK 0xf +#define SSC_CTL_BM 0xf +#define SSC_CTL_HB BIT(4) +#define SSC_CTL_PH BIT(5) +#define SSC_CTL_PO BIT(6) +#define SSC_CTL_SR BIT(7) +#define SSC_CTL_MS BIT(8) +#define SSC_CTL_EN BIT(9) +#define SSC_CTL_LPB BIT(10) +#define SSC_CTL_EN_TX_FIFO BIT(11) +#define SSC_CTL_EN_RX_FIFO BIT(12) +#define SSC_CTL_EN_CLST_RX BIT(13) + +/* SSC Interrupt Enable */ +#define SSC_IEN_TEEN BIT(2) + +#define FIFO_SIZE 8 + +struct spi_st { + /* SSC SPI Controller */ + void __iomem *base; + struct clk *clk; + struct device *dev; + + /* SSC SPI current transaction */ + const u8 *tx_ptr; + u8 *rx_ptr; + u16 bytes_per_word; + unsigned int words_remaining; + unsigned int baud; + struct completion done; +}; + +static int spi_st_clk_enable(struct spi_st *spi_st) +{ + /* + * Current platforms use one of the core clocks for SPI and I2C. + * If we attempt to disable the clock, the system will hang. + * + * TODO: Remove this when platform supports power domains. + */ + return 0; + + return clk_prepare_enable(spi_st->clk); +} + +static void spi_st_clk_disable(struct spi_st *spi_st) +{ + /* + * Current platforms use one of the core clocks for SPI and I2C. + * If we attempt to disable the clock, the system will hang. + * + * TODO: Remove this when platform supports power domains. + */ + return; + + clk_disable_unprepare(spi_st->clk); +} + +/* Load the TX FIFO */ +static void ssc_write_tx_fifo(struct spi_st *spi_st) +{ + unsigned int count, i; + uint32_t word = 0; + + if (spi_st->words_remaining > FIFO_SIZE) + count = FIFO_SIZE; + else + count = spi_st->words_remaining; + + for (i = 0; i < count; i++) { + if (spi_st->tx_ptr) { + if (spi_st->bytes_per_word == 1) { + word = *spi_st->tx_ptr++; + } else { + word = *spi_st->tx_ptr++; + word = *spi_st->tx_ptr++ | (word << 8); + } + } + writel_relaxed(word, spi_st->base + SSC_TBUF); + } +} + +/* Read the RX FIFO */ +static void ssc_read_rx_fifo(struct spi_st *spi_st) +{ + unsigned int count, i; + uint32_t word = 0; + + if (spi_st->words_remaining > FIFO_SIZE) + count = FIFO_SIZE; + else + count = spi_st->words_remaining; + + for (i = 0; i < count; i++) { + word = readl_relaxed(spi_st->base + SSC_RBUF); + + if (spi_st->rx_ptr) { + if (spi_st->bytes_per_word == 1) { + *spi_st->rx_ptr++ = (uint8_t)word; + } else { + *spi_st->rx_ptr++ = (word >> 8); + *spi_st->rx_ptr++ = word & 0xff; + } + } + } + spi_st->words_remaining -= count; +} + +static int spi_st_transfer_one(struct spi_master *master, + struct spi_device *spi, struct spi_transfer *t) +{ + struct spi_st *spi_st = spi_master_get_devdata(master); + uint32_t ctl = 0; + + /* Setup transfer */ + spi_st->tx_ptr = t->tx_buf; + spi_st->rx_ptr = t->rx_buf; + + if (spi->bits_per_word > 8) { + /* + * Anything greater than 8 bits-per-word requires 2 + * bytes-per-word in the RX/TX buffers + */ + spi_st->bytes_per_word = 2; + spi_st->words_remaining = t->len / 2; + + } else if (spi->bits_per_word == 8 && !(t->len & 0x1)) { + /* + * If transfer is even-length, and 8 bits-per-word, then + * implement as half-length 16 bits-per-word transfer + */ + spi_st->bytes_per_word = 2; + spi_st->words_remaining = t->len / 2; + + /* Set SSC_CTL to 16 bits-per-word */ + ctl = readl_relaxed(spi_st->base + SSC_CTL); + writel_relaxed((ctl | 0xf), spi_st->base + SSC_CTL); + + readl_relaxed(spi_st->base + SSC_RBUF); + + } else { + spi_st->bytes_per_word = 1; + spi_st->words_remaining = t->len; + } + + reinit_completion(&spi_st->done); + + /* Start transfer by writing to the TX FIFO */ + ssc_write_tx_fifo(spi_st); + writel_relaxed(SSC_IEN_TEEN, spi_st->base + SSC_IEN); + + /* Wait for transfer to complete */ + wait_for_completion(&spi_st->done); + + /* Restore SSC_CTL if necessary */ + if (ctl) + writel_relaxed(ctl, spi_st->base + SSC_CTL); + + spi_finalize_current_transfer(spi->master); + + return t->len; +} + +static void spi_st_cleanup(struct spi_device *spi) +{ + int cs = spi->cs_gpio; + + if (gpio_is_valid(cs)) + devm_gpio_free(&spi->dev, cs); +} + +/* the spi->mode bits understood by this driver: */ +#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_HIGH) +static int spi_st_setup(struct spi_device *spi) +{ + struct spi_st *spi_st = spi_master_get_devdata(spi->master); + u32 spi_st_clk, sscbrg, var; + u32 hz = spi->max_speed_hz; + int cs = spi->cs_gpio; + int ret; + + if (!hz) { + dev_err(&spi->dev, "max_speed_hz unspecified\n"); + return -EINVAL; + } + + if (!gpio_is_valid(cs)) { + dev_err(&spi->dev, "%d is not a valid gpio\n", cs); + return -EINVAL; + } + + if (devm_gpio_request(&spi->dev, cs, dev_name(&spi->dev))) { + dev_err(&spi->dev, "could not request gpio:%d\n", cs); + return -EINVAL; + } + + ret = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH); + if (ret) + return ret; + + spi_st_clk = clk_get_rate(spi_st->clk); + + /* Set SSC_BRF */ + sscbrg = spi_st_clk / (2 * hz); + if (sscbrg < 0x07 || sscbrg > BIT(16)) { + dev_err(&spi->dev, + "baudrate %d outside valid range %d\n", sscbrg, hz); + return -EINVAL; + } + + spi_st->baud = spi_st_clk / (2 * sscbrg); + if (sscbrg == BIT(16)) /* 16-bit counter wraps */ + sscbrg = 0x0; + + writel_relaxed(sscbrg, spi_st->base + SSC_BRG); + + dev_dbg(&spi->dev, + "setting baudrate:target= %u hz, actual= %u hz, sscbrg= %u\n", + hz, spi_st->baud, sscbrg); + + /* Set SSC_CTL and enable SSC */ + var = readl_relaxed(spi_st->base + SSC_CTL); + var |= SSC_CTL_MS; + + if (spi->mode & SPI_CPOL) + var |= SSC_CTL_PO; + else + var &= ~SSC_CTL_PO; + + if (spi->mode & SPI_CPHA) + var |= SSC_CTL_PH; + else + var &= ~SSC_CTL_PH; + + if ((spi->mode & SPI_LSB_FIRST) == 0) + var |= SSC_CTL_HB; + else + var &= ~SSC_CTL_HB; + + if (spi->mode & SPI_LOOP) + var |= SSC_CTL_LPB; + else + var &= ~SSC_CTL_LPB; + + var &= ~SSC_CTL_DATA_WIDTH_MSK; + var |= (spi->bits_per_word - 1); + + var |= SSC_CTL_EN_TX_FIFO | SSC_CTL_EN_RX_FIFO; + var |= SSC_CTL_EN; + + writel_relaxed(var, spi_st->base + SSC_CTL); + + /* Clear the status register */ + readl_relaxed(spi_st->base + SSC_RBUF); + + return 0; +} + +/* Interrupt fired when TX shift register becomes empty */ +static irqreturn_t spi_st_irq(int irq, void *dev_id) +{ + struct spi_st *spi_st = (struct spi_st *)dev_id; + + /* Read RX FIFO */ + ssc_read_rx_fifo(spi_st); + + /* Fill TX FIFO */ + if (spi_st->words_remaining) { + ssc_write_tx_fifo(spi_st); + } else { + /* TX/RX complete */ + writel_relaxed(0x0, spi_st->base + SSC_IEN); + /* + * read SSC_IEN to ensure that this bit is set + * before re-enabling interrupt + */ + readl(spi_st->base + SSC_IEN); + complete(&spi_st->done); + } + + return IRQ_HANDLED; +} + +static int spi_st_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct spi_master *master; + struct resource *res; + struct spi_st *spi_st; + int irq, ret = 0; + u32 var; + + master = spi_alloc_master(&pdev->dev, sizeof(*spi_st)); + if (!master) + return -ENOMEM; + + master->dev.of_node = np; + master->mode_bits = MODEBITS; + master->setup = spi_st_setup; + master->cleanup = spi_st_cleanup; + master->transfer_one = spi_st_transfer_one; + master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); + master->auto_runtime_pm = true; + master->bus_num = pdev->id; + spi_st = spi_master_get_devdata(master); + + spi_st->clk = devm_clk_get(&pdev->dev, "ssc"); + if (IS_ERR(spi_st->clk)) { + dev_err(&pdev->dev, "Unable to request clock\n"); + return PTR_ERR(spi_st->clk); + } + + ret = spi_st_clk_enable(spi_st); + if (ret) + return ret; + + init_completion(&spi_st->done); + + /* Get resources */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + spi_st->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(spi_st->base)) { + ret = PTR_ERR(spi_st->base); + goto clk_disable; + } + + /* Disable I2C and Reset SSC */ + writel_relaxed(0x0, spi_st->base + SSC_I2C); + var = readw_relaxed(spi_st->base + SSC_CTL); + var |= SSC_CTL_SR; + writel_relaxed(var, spi_st->base + SSC_CTL); + + udelay(1); + var = readl_relaxed(spi_st->base + SSC_CTL); + var &= ~SSC_CTL_SR; + writel_relaxed(var, spi_st->base + SSC_CTL); + + /* Set SSC into slave mode before reconfiguring PIO pins */ + var = readl_relaxed(spi_st->base + SSC_CTL); + var &= ~SSC_CTL_MS; + writel_relaxed(var, spi_st->base + SSC_CTL); + + irq = irq_of_parse_and_map(np, 0); + if (!irq) { + dev_err(&pdev->dev, "IRQ missing or invalid\n"); + ret = -EINVAL; + goto clk_disable; + } + + ret = devm_request_irq(&pdev->dev, irq, spi_st_irq, 0, + pdev->name, spi_st); + if (ret) { + dev_err(&pdev->dev, "Failed to request irq %d\n", irq); + goto clk_disable; + } + + /* by default the device is on */ + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + platform_set_drvdata(pdev, master); + + ret = devm_spi_register_master(&pdev->dev, master); + if (ret) { + dev_err(&pdev->dev, "Failed to register master\n"); + goto clk_disable; + } + + return 0; + +clk_disable: + spi_st_clk_disable(spi_st); + + return ret; +} + +static int spi_st_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct spi_st *spi_st = spi_master_get_devdata(master); + + spi_st_clk_disable(spi_st); + + pinctrl_pm_select_sleep_state(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_PM +static int spi_st_runtime_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct spi_st *spi_st = spi_master_get_devdata(master); + + writel_relaxed(0, spi_st->base + SSC_IEN); + pinctrl_pm_select_sleep_state(dev); + + spi_st_clk_disable(spi_st); + + return 0; +} + +static int spi_st_runtime_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct spi_st *spi_st = spi_master_get_devdata(master); + int ret; + + ret = spi_st_clk_enable(spi_st); + pinctrl_pm_select_default_state(dev); + + return ret; +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int spi_st_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + int ret; + + ret = spi_master_suspend(master); + if (ret) + return ret; + + return pm_runtime_force_suspend(dev); +} + +static int spi_st_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + int ret; + + ret = spi_master_resume(master); + if (ret) + return ret; + + return pm_runtime_force_resume(dev); +} +#endif + +static const struct dev_pm_ops spi_st_pm = { + SET_SYSTEM_SLEEP_PM_OPS(spi_st_suspend, spi_st_resume) + SET_RUNTIME_PM_OPS(spi_st_runtime_suspend, spi_st_runtime_resume, NULL) +}; + +static struct of_device_id stm_spi_match[] = { + { .compatible = "st,comms-ssc4-spi", }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm_spi_match); + +static struct platform_driver spi_st_driver = { + .driver = { + .name = "spi-st", + .pm = &spi_st_pm, + .of_match_table = of_match_ptr(stm_spi_match), + }, + .probe = spi_st_probe, + .remove = spi_st_remove, +}; +module_platform_driver(spi_st_driver); + +MODULE_AUTHOR("Patrice Chotard "); +MODULE_DESCRIPTION("STM SSC SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 6146c4cd6583..884a716e50cb 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -201,7 +201,7 @@ static void ti_qspi_restore_ctx(struct ti_qspi *qspi) static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) { - int wlen, count, ret; + int wlen, count; unsigned int cmd; const u8 *txbuf; @@ -230,9 +230,8 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) } ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); - ret = wait_for_completion_timeout(&qspi->transfer_complete, - QSPI_COMPLETION_TIMEOUT); - if (ret == 0) { + if (!wait_for_completion_timeout(&qspi->transfer_complete, + QSPI_COMPLETION_TIMEOUT)) { dev_err(qspi->dev, "write timed out\n"); return -ETIMEDOUT; } @@ -245,7 +244,7 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) { - int wlen, count, ret; + int wlen, count; unsigned int cmd; u8 *rxbuf; @@ -268,9 +267,8 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) while (count) { dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc); ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); - ret = wait_for_completion_timeout(&qspi->transfer_complete, - QSPI_COMPLETION_TIMEOUT); - if (ret == 0) { + if (!wait_for_completion_timeout(&qspi->transfer_complete, + QSPI_COMPLETION_TIMEOUT)) { dev_err(qspi->dev, "read timed out\n"); return -ETIMEDOUT; } diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index be692ad50442..93dfcee0f987 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #include diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 79bd84f43430..133f53a9c1d4 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -22,6 +22,8 @@ #include #include +#define XILINX_SPI_MAX_CS 32 + #define XILINX_SPI_NAME "xilinx_spi" /* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e) @@ -34,7 +36,8 @@ #define XSPI_CR_MASTER_MODE 0x04 #define XSPI_CR_CPOL 0x08 #define XSPI_CR_CPHA 0x10 -#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL) +#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL | \ + XSPI_CR_LSB_FIRST | XSPI_CR_LOOP) #define XSPI_CR_TXFIFO_RESET 0x20 #define XSPI_CR_RXFIFO_RESET 0x40 #define XSPI_CR_MANUAL_SSELECT 0x80 @@ -85,12 +88,11 @@ struct xilinx_spi { u8 *rx_ptr; /* pointer in the Tx buffer */ const u8 *tx_ptr; /* pointer in the Rx buffer */ - int remaining_bytes; /* the number of bytes left to transfer */ - u8 bits_per_word; + u8 bytes_per_word; + int buffer_size; /* buffer size in words */ + u32 cs_inactive; /* Level of the CS pins when inactive*/ unsigned int (*read_fn)(void __iomem *); void (*write_fn)(u32, void __iomem *); - void (*tx_fn)(struct xilinx_spi *); - void (*rx_fn)(struct xilinx_spi *); }; static void xspi_write32(u32 val, void __iomem *addr) @@ -113,49 +115,51 @@ static unsigned int xspi_read32_be(void __iomem *addr) return ioread32be(addr); } -static void xspi_tx8(struct xilinx_spi *xspi) +static void xilinx_spi_tx(struct xilinx_spi *xspi) { - xspi->write_fn(*xspi->tx_ptr, xspi->regs + XSPI_TXD_OFFSET); - xspi->tx_ptr++; -} + u32 data = 0; -static void xspi_tx16(struct xilinx_spi *xspi) -{ - xspi->write_fn(*(u16 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET); - xspi->tx_ptr += 2; -} - -static void xspi_tx32(struct xilinx_spi *xspi) -{ - xspi->write_fn(*(u32 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET); - xspi->tx_ptr += 4; -} - -static void xspi_rx8(struct xilinx_spi *xspi) -{ - u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET); - if (xspi->rx_ptr) { - *xspi->rx_ptr = data & 0xff; - xspi->rx_ptr++; + if (!xspi->tx_ptr) { + xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); + return; } -} -static void xspi_rx16(struct xilinx_spi *xspi) -{ - u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET); - if (xspi->rx_ptr) { - *(u16 *)(xspi->rx_ptr) = data & 0xffff; - xspi->rx_ptr += 2; + switch (xspi->bytes_per_word) { + case 1: + data = *(u8 *)(xspi->tx_ptr); + break; + case 2: + data = *(u16 *)(xspi->tx_ptr); + break; + case 4: + data = *(u32 *)(xspi->tx_ptr); + break; } + + xspi->write_fn(data, xspi->regs + XSPI_TXD_OFFSET); + xspi->tx_ptr += xspi->bytes_per_word; } -static void xspi_rx32(struct xilinx_spi *xspi) +static void xilinx_spi_rx(struct xilinx_spi *xspi) { u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET); - if (xspi->rx_ptr) { + + if (!xspi->rx_ptr) + return; + + switch (xspi->bytes_per_word) { + case 1: + *(u8 *)(xspi->rx_ptr) = data; + break; + case 2: + *(u16 *)(xspi->rx_ptr) = data; + break; + case 4: *(u32 *)(xspi->rx_ptr) = data; - xspi->rx_ptr += 4; + break; } + + xspi->rx_ptr += xspi->bytes_per_word; } static void xspi_init_hw(struct xilinx_spi *xspi) @@ -165,46 +169,56 @@ static void xspi_init_hw(struct xilinx_spi *xspi) /* Reset the SPI device */ xspi->write_fn(XIPIF_V123B_RESET_MASK, regs_base + XIPIF_V123B_RESETR_OFFSET); - /* Disable all the interrupts just in case */ - xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET); - /* Enable the global IPIF interrupt */ - xspi->write_fn(XIPIF_V123B_GINTR_ENABLE, - regs_base + XIPIF_V123B_DGIER_OFFSET); + /* Enable the transmit empty interrupt, which we use to determine + * progress on the transmission. + */ + xspi->write_fn(XSPI_INTR_TX_EMPTY, + regs_base + XIPIF_V123B_IIER_OFFSET); + /* Disable the global IPIF interrupt */ + xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET); /* Deselect the slave on the SPI bus */ xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET); /* Disable the transmitter, enable Manual Slave Select Assertion, * put SPI controller into master mode, and enable it */ - xspi->write_fn(XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT | - XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET | - XSPI_CR_RXFIFO_RESET, regs_base + XSPI_CR_OFFSET); + xspi->write_fn(XSPI_CR_MANUAL_SSELECT | XSPI_CR_MASTER_MODE | + XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET | XSPI_CR_RXFIFO_RESET, + regs_base + XSPI_CR_OFFSET); } static void xilinx_spi_chipselect(struct spi_device *spi, int is_on) { struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); + u16 cr; + u32 cs; if (is_on == BITBANG_CS_INACTIVE) { /* Deselect the slave on the SPI bus */ - xspi->write_fn(0xffff, xspi->regs + XSPI_SSR_OFFSET); - } else if (is_on == BITBANG_CS_ACTIVE) { - /* Set the SPI clock phase and polarity */ - u16 cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) - & ~XSPI_CR_MODE_MASK; - if (spi->mode & SPI_CPHA) - cr |= XSPI_CR_CPHA; - if (spi->mode & SPI_CPOL) - cr |= XSPI_CR_CPOL; - xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); - - /* We do not check spi->max_speed_hz here as the SPI clock - * frequency is not software programmable (the IP block design - * parameter) - */ - - /* Activate the chip select */ - xspi->write_fn(~(0x0001 << spi->chip_select), - xspi->regs + XSPI_SSR_OFFSET); + xspi->write_fn(xspi->cs_inactive, xspi->regs + XSPI_SSR_OFFSET); + return; } + + /* Set the SPI clock phase and polarity */ + cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_MODE_MASK; + if (spi->mode & SPI_CPHA) + cr |= XSPI_CR_CPHA; + if (spi->mode & SPI_CPOL) + cr |= XSPI_CR_CPOL; + if (spi->mode & SPI_LSB_FIRST) + cr |= XSPI_CR_LSB_FIRST; + if (spi->mode & SPI_LOOP) + cr |= XSPI_CR_LOOP; + xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); + + /* We do not check spi->max_speed_hz here as the SPI clock + * frequency is not software programmable (the IP block design + * parameter) + */ + + cs = xspi->cs_inactive; + cs ^= BIT(spi->chip_select); + + /* Activate the chip select */ + xspi->write_fn(cs, xspi->regs + XSPI_SSR_OFFSET); } /* spi_bitbang requires custom setup_transfer() to be defined if there is a @@ -213,85 +227,85 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on) static int xilinx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { + struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); + + if (spi->mode & SPI_CS_HIGH) + xspi->cs_inactive &= ~BIT(spi->chip_select); + else + xspi->cs_inactive |= BIT(spi->chip_select); + return 0; } -static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi) -{ - u8 sr; - - /* Fill the Tx FIFO with as many bytes as possible */ - sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); - while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) { - if (xspi->tx_ptr) - xspi->tx_fn(xspi); - else - xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); - xspi->remaining_bytes -= xspi->bits_per_word / 8; - sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); - } -} - static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) { struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); - u32 ipif_ier; + int remaining_words; /* the number of words left to transfer */ + bool use_irq = false; + u16 cr = 0; /* We get here with transmitter inhibited */ xspi->tx_ptr = t->tx_buf; xspi->rx_ptr = t->rx_buf; - xspi->remaining_bytes = t->len; + remaining_words = t->len / xspi->bytes_per_word; reinit_completion(&xspi->done); + if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) { + use_irq = true; + xspi->write_fn(XSPI_INTR_TX_EMPTY, + xspi->regs + XIPIF_V123B_IISR_OFFSET); + /* Enable the global IPIF interrupt */ + xspi->write_fn(XIPIF_V123B_GINTR_ENABLE, + xspi->regs + XIPIF_V123B_DGIER_OFFSET); + /* Inhibit irq to avoid spurious irqs on tx_empty*/ + cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); + xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, + xspi->regs + XSPI_CR_OFFSET); + } - /* Enable the transmit empty interrupt, which we use to determine - * progress on the transmission. - */ - ipif_ier = xspi->read_fn(xspi->regs + XIPIF_V123B_IIER_OFFSET); - xspi->write_fn(ipif_ier | XSPI_INTR_TX_EMPTY, - xspi->regs + XIPIF_V123B_IIER_OFFSET); + while (remaining_words) { + int n_words, tx_words, rx_words; - for (;;) { - u16 cr; - u8 sr; + n_words = min(remaining_words, xspi->buffer_size); - xilinx_spi_fill_tx_fifo(xspi); + tx_words = n_words; + while (tx_words--) + xilinx_spi_tx(xspi); /* Start the transfer by not inhibiting the transmitter any * longer */ - cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) & - ~XSPI_CR_TRANS_INHIBIT; - xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); - wait_for_completion(&xspi->done); + if (use_irq) { + xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); + wait_for_completion(&xspi->done); + } else + while (!(xspi->read_fn(xspi->regs + XSPI_SR_OFFSET) & + XSPI_SR_TX_EMPTY_MASK)) + ; /* A transmit has just completed. Process received data and * check for more data to transmit. Always inhibit the * transmitter while the Isr refills the transmit register/FIFO, * or make sure it is stopped if we're done. */ - cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); - xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, + if (use_irq) + xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, xspi->regs + XSPI_CR_OFFSET); /* Read out all the data from the Rx FIFO */ - sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); - while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) { - xspi->rx_fn(xspi); - sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); - } + rx_words = n_words; + while (rx_words--) + xilinx_spi_rx(xspi); - /* See if there is more data to send */ - if (xspi->remaining_bytes <= 0) - break; + remaining_words -= n_words; } - /* Disable the transmit empty interrupt */ - xspi->write_fn(ipif_ier, xspi->regs + XIPIF_V123B_IIER_OFFSET); + if (use_irq) + xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET); - return t->len - xspi->remaining_bytes; + return t->len; } @@ -316,6 +330,28 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi) +{ + u8 sr; + int n_words = 0; + + /* + * Before the buffer_size detection we reset the core + * to make sure we start with a clean state. + */ + xspi->write_fn(XIPIF_V123B_RESET_MASK, + xspi->regs + XIPIF_V123B_RESETR_OFFSET); + + /* Fill the Tx FIFO with as many words as possible */ + do { + xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET); + sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); + n_words++; + } while (!(sr & XSPI_SR_TX_FULL_MASK)); + + return n_words; +} + static const struct of_device_id xilinx_spi_of_match[] = { { .compatible = "xlnx,xps-spi-2.00.a", }, { .compatible = "xlnx,xps-spi-2.00.b", }, @@ -348,14 +384,21 @@ static int xilinx_spi_probe(struct platform_device *pdev) return -EINVAL; } + if (num_cs > XILINX_SPI_MAX_CS) { + dev_err(&pdev->dev, "Invalid number of spi slaves\n"); + return -EINVAL; + } + master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi)); if (!master) return -ENODEV; /* the spi->mode bits understood by this driver: */ - master->mode_bits = SPI_CPOL | SPI_CPHA; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | + SPI_CS_HIGH; xspi = spi_master_get_devdata(master); + xspi->cs_inactive = 0xffffffff; xspi->bitbang.master = master; xspi->bitbang.chipselect = xilinx_spi_chipselect; xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer; @@ -392,36 +435,21 @@ static int xilinx_spi_probe(struct platform_device *pdev) } master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word); - xspi->bits_per_word = bits_per_word; - if (xspi->bits_per_word == 8) { - xspi->tx_fn = xspi_tx8; - xspi->rx_fn = xspi_rx8; - } else if (xspi->bits_per_word == 16) { - xspi->tx_fn = xspi_tx16; - xspi->rx_fn = xspi_rx16; - } else if (xspi->bits_per_word == 32) { - xspi->tx_fn = xspi_tx32; - xspi->rx_fn = xspi_rx32; - } else { - ret = -EINVAL; - goto put_master; + xspi->bytes_per_word = bits_per_word / 8; + xspi->buffer_size = xilinx_spi_find_buffer_size(xspi); + + xspi->irq = platform_get_irq(pdev, 0); + if (xspi->irq >= 0) { + /* Register for SPI Interrupt */ + ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0, + dev_name(&pdev->dev), xspi); + if (ret) + goto put_master; } /* SPI controller initializations */ xspi_init_hw(xspi); - xspi->irq = platform_get_irq(pdev, 0); - if (xspi->irq < 0) { - ret = xspi->irq; - goto put_master; - } - - /* Register for SPI Interrupt */ - ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0, - dev_name(&pdev->dev), xspi); - if (ret) - goto put_master; - ret = spi_bitbang_start(&xspi->bitbang); if (ret) { dev_err(&pdev->dev, "spi_bitbang_start FAILED\n"); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 66a70e9bc743..c64a3e59fce3 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include @@ -788,7 +784,7 @@ static int spi_transfer_one_message(struct spi_master *master, struct spi_transfer *xfer; bool keep_cs = false; int ret = 0; - int ms = 1; + unsigned long ms = 1; spi_set_cs(msg->spi, true); @@ -875,31 +871,59 @@ void spi_finalize_current_transfer(struct spi_master *master) EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); /** - * spi_pump_messages - kthread work function which processes spi message queue - * @work: pointer to kthread work struct contained in the master struct + * __spi_pump_messages - function which processes spi message queue + * @master: master to process queue for + * @in_kthread: true if we are in the context of the message pump thread * * This function checks if there is any spi message in the queue that * needs processing and if so call out to the driver to initialize hardware * and transfer each message. * + * Note that it is called both from the kthread itself and also from + * inside spi_sync(); the queue extraction handling at the top of the + * function should deal with this safely. */ -static void spi_pump_messages(struct kthread_work *work) +static void __spi_pump_messages(struct spi_master *master, bool in_kthread) { - struct spi_master *master = - container_of(work, struct spi_master, pump_messages); unsigned long flags; bool was_busy = false; int ret; - /* Lock queue and check for queue work */ + /* Lock queue */ spin_lock_irqsave(&master->queue_lock, flags); + + /* Make sure we are not already running a message */ + if (master->cur_msg) { + spin_unlock_irqrestore(&master->queue_lock, flags); + return; + } + + /* If another context is idling the device then defer */ + if (master->idling) { + queue_kthread_work(&master->kworker, &master->pump_messages); + spin_unlock_irqrestore(&master->queue_lock, flags); + return; + } + + /* Check if the queue is idle */ if (list_empty(&master->queue) || !master->running) { if (!master->busy) { spin_unlock_irqrestore(&master->queue_lock, flags); return; } + + /* Only do teardown in the thread */ + if (!in_kthread) { + queue_kthread_work(&master->kworker, + &master->pump_messages); + spin_unlock_irqrestore(&master->queue_lock, flags); + return; + } + master->busy = false; + master->idling = true; spin_unlock_irqrestore(&master->queue_lock, flags); + kfree(master->dummy_rx); master->dummy_rx = NULL; kfree(master->dummy_tx); @@ -913,14 +937,13 @@ static void spi_pump_messages(struct kthread_work *work) pm_runtime_put_autosuspend(master->dev.parent); } trace_spi_master_idle(master); - return; - } - /* Make sure we are not already running a message */ - if (master->cur_msg) { + spin_lock_irqsave(&master->queue_lock, flags); + master->idling = false; spin_unlock_irqrestore(&master->queue_lock, flags); return; } + /* Extract head of queue */ master->cur_msg = list_first_entry(&master->queue, struct spi_message, queue); @@ -985,13 +1008,22 @@ static void spi_pump_messages(struct kthread_work *work) } } +/** + * spi_pump_messages - kthread work function which processes spi message queue + * @work: pointer to kthread work struct contained in the master struct + */ +static void spi_pump_messages(struct kthread_work *work) +{ + struct spi_master *master = + container_of(work, struct spi_master, pump_messages); + + __spi_pump_messages(master, true); +} + static int spi_init_queue(struct spi_master *master) { struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; - INIT_LIST_HEAD(&master->queue); - spin_lock_init(&master->queue_lock); - master->running = false; master->busy = false; @@ -1161,12 +1193,9 @@ static int spi_destroy_queue(struct spi_master *master) return 0; } -/** - * spi_queued_transfer - transfer function for queued transfers - * @spi: spi device which is requesting transfer - * @msg: spi message which is to handled is queued to driver queue - */ -static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg) +static int __spi_queued_transfer(struct spi_device *spi, + struct spi_message *msg, + bool need_pump) { struct spi_master *master = spi->master; unsigned long flags; @@ -1181,13 +1210,23 @@ static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg) msg->status = -EINPROGRESS; list_add_tail(&msg->queue, &master->queue); - if (!master->busy) + if (!master->busy && need_pump) queue_kthread_work(&master->kworker, &master->pump_messages); spin_unlock_irqrestore(&master->queue_lock, flags); return 0; } +/** + * spi_queued_transfer - transfer function for queued transfers + * @spi: spi device which is requesting transfer + * @msg: spi message which is to handled is queued to driver queue + */ +static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg) +{ + return __spi_queued_transfer(spi, msg, true); +} + static int spi_master_initialize_queue(struct spi_master *master) { int ret; @@ -1609,6 +1648,8 @@ int spi_register_master(struct spi_master *master) dynamic = 1; } + INIT_LIST_HEAD(&master->queue); + spin_lock_init(&master->queue_lock); spin_lock_init(&master->bus_lock_spinlock); mutex_init(&master->bus_lock_mutex); master->bus_lock_flag = 0; @@ -2114,19 +2155,46 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, DECLARE_COMPLETION_ONSTACK(done); int status; struct spi_master *master = spi->master; + unsigned long flags; + + status = __spi_validate(spi, message); + if (status != 0) + return status; message->complete = spi_complete; message->context = &done; + message->spi = spi; if (!bus_locked) mutex_lock(&master->bus_lock_mutex); - status = spi_async_locked(spi, message); + /* If we're not using the legacy transfer method then we will + * try to transfer in the calling context so special case. + * This code would be less tricky if we could remove the + * support for driver implemented message queues. + */ + if (master->transfer == spi_queued_transfer) { + spin_lock_irqsave(&master->bus_lock_spinlock, flags); + + trace_spi_message_submit(message); + + status = __spi_queued_transfer(spi, message, false); + + spin_unlock_irqrestore(&master->bus_lock_spinlock, flags); + } else { + status = spi_async_locked(spi, message); + } if (!bus_locked) mutex_unlock(&master->bus_lock_mutex); if (status == 0) { + /* Push out the messages in the calling context if we + * can. + */ + if (master->transfer == spi_queued_transfer) + __spi_pump_messages(master, false); + wait_for_completion(&done); status = message->status; } diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 6941e04afb8c..4eb7a980e670 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -14,10 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include @@ -317,6 +313,37 @@ done: return status; } +static struct spi_ioc_transfer * +spidev_get_ioc_message(unsigned int cmd, struct spi_ioc_transfer __user *u_ioc, + unsigned *n_ioc) +{ + struct spi_ioc_transfer *ioc; + u32 tmp; + + /* Check type, command number and direction */ + if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC + || _IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0)) + || _IOC_DIR(cmd) != _IOC_WRITE) + return ERR_PTR(-ENOTTY); + + tmp = _IOC_SIZE(cmd); + if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) + return ERR_PTR(-EINVAL); + *n_ioc = tmp / sizeof(struct spi_ioc_transfer); + if (*n_ioc == 0) + return NULL; + + /* copy into scratch area */ + ioc = kmalloc(tmp, GFP_KERNEL); + if (!ioc) + return ERR_PTR(-ENOMEM); + if (__copy_from_user(ioc, u_ioc, tmp)) { + kfree(ioc); + return ERR_PTR(-EFAULT); + } + return ioc; +} + static long spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -456,32 +483,15 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) default: /* segmented and/or full-duplex I/O request */ - if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0)) - || _IOC_DIR(cmd) != _IOC_WRITE) { - retval = -ENOTTY; - break; - } - - tmp = _IOC_SIZE(cmd); - if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) { - retval = -EINVAL; - break; - } - n_ioc = tmp / sizeof(struct spi_ioc_transfer); - if (n_ioc == 0) - break; - - /* copy into scratch area */ - ioc = kmalloc(tmp, GFP_KERNEL); - if (!ioc) { - retval = -ENOMEM; - break; - } - if (__copy_from_user(ioc, (void __user *)arg, tmp)) { - kfree(ioc); - retval = -EFAULT; + /* Check message and copy into scratch area */ + ioc = spidev_get_ioc_message(cmd, + (struct spi_ioc_transfer __user *)arg, &n_ioc); + if (IS_ERR(ioc)) { + retval = PTR_ERR(ioc); break; } + if (!ioc) + break; /* n_ioc is also 0 */ /* translate to spi_message, execute */ retval = spidev_message(spidev, ioc, n_ioc); @@ -495,9 +505,68 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } #ifdef CONFIG_COMPAT +static long +spidev_compat_ioc_message(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct spi_ioc_transfer __user *u_ioc; + int retval = 0; + struct spidev_data *spidev; + struct spi_device *spi; + unsigned n_ioc, n; + struct spi_ioc_transfer *ioc; + + u_ioc = (struct spi_ioc_transfer __user *) compat_ptr(arg); + if (!access_ok(VERIFY_READ, u_ioc, _IOC_SIZE(cmd))) + return -EFAULT; + + /* guard against device removal before, or while, + * we issue this ioctl. + */ + spidev = filp->private_data; + spin_lock_irq(&spidev->spi_lock); + spi = spi_dev_get(spidev->spi); + spin_unlock_irq(&spidev->spi_lock); + + if (spi == NULL) + return -ESHUTDOWN; + + /* SPI_IOC_MESSAGE needs the buffer locked "normally" */ + mutex_lock(&spidev->buf_lock); + + /* Check message and copy into scratch area */ + ioc = spidev_get_ioc_message(cmd, u_ioc, &n_ioc); + if (IS_ERR(ioc)) { + retval = PTR_ERR(ioc); + goto done; + } + if (!ioc) + goto done; /* n_ioc is also 0 */ + + /* Convert buffer pointers */ + for (n = 0; n < n_ioc; n++) { + ioc[n].rx_buf = (uintptr_t) compat_ptr(ioc[n].rx_buf); + ioc[n].tx_buf = (uintptr_t) compat_ptr(ioc[n].tx_buf); + } + + /* translate to spi_message, execute */ + retval = spidev_message(spidev, ioc, n_ioc); + kfree(ioc); + +done: + mutex_unlock(&spidev->buf_lock); + spi_dev_put(spi); + return retval; +} + static long spidev_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { + if (_IOC_TYPE(cmd) == SPI_IOC_MAGIC + && _IOC_NR(cmd) == _IOC_NR(SPI_IOC_MESSAGE(0)) + && _IOC_DIR(cmd) == _IOC_WRITE) + return spidev_compat_ioc_message(filp, cmd, arg); + return spidev_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); } #else diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 2fead3820849..1e180c400f17 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -90,25 +90,6 @@ found: } #endif /* CONFIG_SSB_PCMCIAHOST */ -#ifdef CONFIG_SSB_SDIOHOST -struct ssb_bus *ssb_sdio_func_to_bus(struct sdio_func *func) -{ - struct ssb_bus *bus; - - ssb_buses_lock(); - list_for_each_entry(bus, &buses, list) { - if (bus->bustype == SSB_BUSTYPE_SDIO && - bus->host_sdio == func) - goto found; - } - bus = NULL; -found: - ssb_buses_unlock(); - - return bus; -} -#endif /* CONFIG_SSB_SDIOHOST */ - int ssb_for_each_bus_call(unsigned long data, int (*func)(struct ssb_bus *bus, unsigned long data)) { diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 815de379a130..9049dd91b569 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -46,8 +46,6 @@ source "drivers/staging/rtl8723au/Kconfig" source "drivers/staging/rts5208/Kconfig" -source "drivers/staging/line6/Kconfig" - source "drivers/staging/octeon/Kconfig" source "drivers/staging/octeon-usb/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 33c640b49566..fe26ff162b42 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_R8712U) += rtl8712/ obj-$(CONFIG_R8188EU) += rtl8188eu/ obj-$(CONFIG_R8723AU) += rtl8723au/ obj-$(CONFIG_RTS5208) += rts5208/ -obj-$(CONFIG_LINE6_USB) += line6/ obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/ obj-$(CONFIG_OCTEON_ETHERNET) += octeon/ obj-$(CONFIG_OCTEON_USB) += octeon-usb/ diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index b545d3d1da3e..feafa172b155 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -160,7 +160,12 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) selected->pid, selected->comm, selected_oom_score_adj, selected_tasksize); lowmem_deathpending_timeout = jiffies + HZ; - set_tsk_thread_flag(selected, TIF_MEMDIE); + /* + * FIXME: lowmemorykiller shouldn't abuse global OOM killer + * infrastructure. There is no real reason why the selected + * task should have access to the memory reserves. + */ + mark_tsk_oom_victim(selected); send_sig(SIGKILL, selected, 0); rem += selected_tasksize; } diff --git a/drivers/staging/line6/Kconfig b/drivers/staging/line6/Kconfig deleted file mode 100644 index 4f1219b4c692..000000000000 --- a/drivers/staging/line6/Kconfig +++ /dev/null @@ -1,38 +0,0 @@ -menuconfig LINE6_USB - tristate "Line6 USB support" - depends on USB && SND - select SND_RAWMIDI - select SND_PCM - help - This is a driver for the guitar amp, cab, and effects modeller - PODxt Pro by Line6 (and similar devices), supporting the - following features: - * Reading/writing individual parameters - * Reading/writing complete channel, effects setup, and amp - setup data - * Channel switching - * Virtual MIDI interface - * Tuner access - * Playback/capture/mixer device for any ALSA-compatible PCM - audio application - * Signal routing (record clean/processed guitar signal, - re-amping) - - Preliminary support for the Variax Workbench and TonePort - devices is included. - -if LINE6_USB - -config LINE6_USB_IMPULSE_RESPONSE - bool "measure impulse response" - default n - help - Say Y here to add code to measure the impulse response of a Line6 - device. This is more accurate than user-space methods since it - bypasses any PCM data buffering (e.g., by ALSA or jack). This is - useful for assessing the performance of new devices, but is not - required for normal operation. - - If unsure, say N. - -endif # LINE6_USB diff --git a/drivers/staging/line6/Makefile b/drivers/staging/line6/Makefile deleted file mode 100644 index ae5c374b0f87..000000000000 --- a/drivers/staging/line6/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -obj-$(CONFIG_LINE6_USB) += line6usb.o - -line6usb-y := \ - audio.o \ - capture.o \ - driver.o \ - midi.o \ - midibuf.o \ - pcm.o \ - playback.o \ - pod.o \ - toneport.o \ - variax.o \ - podhd.o diff --git a/drivers/staging/line6/audio.c b/drivers/staging/line6/audio.c deleted file mode 100644 index 171d80c1b020..000000000000 --- a/drivers/staging/line6/audio.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include - -#include "driver.h" -#include "audio.h" - -/* - Initialize the Line6 USB audio system. -*/ -int line6_init_audio(struct usb_line6 *line6) -{ - struct snd_card *card; - int err; - - err = snd_card_new(line6->ifcdev, - SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, - THIS_MODULE, 0, &card); - if (err < 0) - return err; - - line6->card = card; - - strcpy(card->id, line6->properties->id); - strcpy(card->driver, DRIVER_NAME); - strcpy(card->shortname, line6->properties->name); - /* longname is 80 chars - see asound.h */ - sprintf(card->longname, "Line6 %s at USB %s", line6->properties->name, - dev_name(line6->ifcdev)); - return 0; -} - -/* - Register the Line6 USB audio system. -*/ -int line6_register_audio(struct usb_line6 *line6) -{ - int err; - - err = snd_card_register(line6->card); - if (err < 0) - return err; - - return 0; -} - -/* - Cleanup the Line6 USB audio system. -*/ -void line6_cleanup_audio(struct usb_line6 *line6) -{ - struct snd_card *card = line6->card; - - if (card == NULL) - return; - - snd_card_disconnect(card); - snd_card_free(card); - line6->card = NULL; -} diff --git a/drivers/staging/line6/audio.h b/drivers/staging/line6/audio.h deleted file mode 100644 index 5f8a09a0fa95..000000000000 --- a/drivers/staging/line6/audio.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef AUDIO_H -#define AUDIO_H - -#include "driver.h" - -extern void line6_cleanup_audio(struct usb_line6 *); -extern int line6_init_audio(struct usb_line6 *); -extern int line6_register_audio(struct usb_line6 *); - -#endif diff --git a/drivers/staging/line6/capture.c b/drivers/staging/line6/capture.c deleted file mode 100644 index e6ca631e3f79..000000000000 --- a/drivers/staging/line6/capture.c +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include -#include - -#include "audio.h" -#include "capture.h" -#include "driver.h" -#include "pcm.h" -#include "pod.h" - -/* - Find a free URB and submit it. -*/ -static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) -{ - int index; - unsigned long flags; - int i, urb_size; - int ret; - struct urb *urb_in; - - spin_lock_irqsave(&line6pcm->lock_audio_in, flags); - index = - find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS); - - if (index < 0 || index >= LINE6_ISO_BUFFERS) { - spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); - dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); - return -EINVAL; - } - - urb_in = line6pcm->urb_audio_in[index]; - urb_size = 0; - - for (i = 0; i < LINE6_ISO_PACKETS; ++i) { - struct usb_iso_packet_descriptor *fin = - &urb_in->iso_frame_desc[i]; - fin->offset = urb_size; - fin->length = line6pcm->max_packet_size; - urb_size += line6pcm->max_packet_size; - } - - urb_in->transfer_buffer = - line6pcm->buffer_in + - index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; - urb_in->transfer_buffer_length = urb_size; - urb_in->context = line6pcm; - - ret = usb_submit_urb(urb_in, GFP_ATOMIC); - - if (ret == 0) - set_bit(index, &line6pcm->active_urb_in); - else - dev_err(line6pcm->line6->ifcdev, - "URB in #%d submission failed (%d)\n", index, ret); - - spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); - return 0; -} - -/* - Submit all currently available capture URBs. -*/ -int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm) -{ - int ret, i; - - for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { - ret = submit_audio_in_urb(line6pcm); - if (ret < 0) - return ret; - } - - return 0; -} - -/* - Unlink all currently active capture URBs. -*/ -void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm) -{ - unsigned int i; - - for (i = LINE6_ISO_BUFFERS; i--;) { - if (test_bit(i, &line6pcm->active_urb_in)) { - if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) { - struct urb *u = line6pcm->urb_audio_in[i]; - - usb_unlink_urb(u); - } - } - } -} - -/* - Wait until unlinking of all currently active capture URBs has been - finished. -*/ -void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) -{ - int timeout = HZ; - unsigned int i; - int alive; - - do { - alive = 0; - for (i = LINE6_ISO_BUFFERS; i--;) { - if (test_bit(i, &line6pcm->active_urb_in)) - alive++; - } - if (!alive) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } while (--timeout > 0); - if (alive) - snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); -} - -/* - Unlink all currently active capture URBs, and wait for finishing. -*/ -void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) -{ - line6_unlink_audio_in_urbs(line6pcm); - line6_wait_clear_audio_in_urbs(line6pcm); -} - -/* - Copy data into ALSA capture buffer. -*/ -void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize) -{ - struct snd_pcm_substream *substream = - get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); - struct snd_pcm_runtime *runtime = substream->runtime; - const int bytes_per_frame = line6pcm->properties->bytes_per_frame; - int frames = fsize / bytes_per_frame; - - if (runtime == NULL) - return; - - if (line6pcm->pos_in_done + frames > runtime->buffer_size) { - /* - The transferred area goes over buffer boundary, - copy two separate chunks. - */ - int len; - - len = runtime->buffer_size - line6pcm->pos_in_done; - - if (len > 0) { - memcpy(runtime->dma_area + - line6pcm->pos_in_done * bytes_per_frame, fbuf, - len * bytes_per_frame); - memcpy(runtime->dma_area, fbuf + len * bytes_per_frame, - (frames - len) * bytes_per_frame); - } else { - /* this is somewhat paranoid */ - dev_err(line6pcm->line6->ifcdev, - "driver bug: len = %d\n", len); - } - } else { - /* copy single chunk */ - memcpy(runtime->dma_area + - line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize); - } - - line6pcm->pos_in_done += frames; - if (line6pcm->pos_in_done >= runtime->buffer_size) - line6pcm->pos_in_done -= runtime->buffer_size; -} - -void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) -{ - struct snd_pcm_substream *substream = - get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); - - line6pcm->bytes_in += length; - if (line6pcm->bytes_in >= line6pcm->period_in) { - line6pcm->bytes_in %= line6pcm->period_in; - snd_pcm_period_elapsed(substream); - } -} - -void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm) -{ - kfree(line6pcm->buffer_in); - line6pcm->buffer_in = NULL; -} - -/* - * Callback for completed capture URB. - */ -static void audio_in_callback(struct urb *urb) -{ - int i, index, length = 0, shutdown = 0; - unsigned long flags; - - struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; - - line6pcm->last_frame_in = urb->start_frame; - - /* find index of URB */ - for (index = 0; index < LINE6_ISO_BUFFERS; ++index) - if (urb == line6pcm->urb_audio_in[index]) - break; - - spin_lock_irqsave(&line6pcm->lock_audio_in, flags); - - for (i = 0; i < LINE6_ISO_PACKETS; ++i) { - char *fbuf; - int fsize; - struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i]; - - if (fin->status == -EXDEV) { - shutdown = 1; - break; - } - - fbuf = urb->transfer_buffer + fin->offset; - fsize = fin->actual_length; - - if (fsize > line6pcm->max_packet_size) { - dev_err(line6pcm->line6->ifcdev, - "driver and/or device bug: packet too large (%d > %d)\n", - fsize, line6pcm->max_packet_size); - } - - length += fsize; - - /* the following assumes LINE6_ISO_PACKETS == 1: */ - line6pcm->prev_fbuf = fbuf; - line6pcm->prev_fsize = fsize; - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) -#endif - if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, - &line6pcm->flags) && (fsize > 0)) - line6_capture_copy(line6pcm, fbuf, fsize); - } - - clear_bit(index, &line6pcm->active_urb_in); - - if (test_and_clear_bit(index, &line6pcm->unlink_urb_in)) - shutdown = 1; - - spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); - - if (!shutdown) { - submit_audio_in_urb(line6pcm); - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) -#endif - if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, - &line6pcm->flags)) - line6_capture_check_period(line6pcm, length); - } -} - -/* open capture callback */ -static int snd_line6_capture_open(struct snd_pcm_substream *substream) -{ - int err; - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - err = snd_pcm_hw_constraint_ratdens(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - (&line6pcm-> - properties->snd_line6_rates)); - if (err < 0) - return err; - - runtime->hw = line6pcm->properties->snd_line6_capture_hw; - return 0; -} - -/* close capture callback */ -static int snd_line6_capture_close(struct snd_pcm_substream *substream) -{ - return 0; -} - -/* hw_params capture callback */ -static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - int ret; - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - /* -- Florian Demski [FD] */ - /* don't ask me why, but this fixes the bug on my machine */ - if (line6pcm == NULL) { - if (substream->pcm == NULL) - return -ENOMEM; - if (substream->pcm->private_data == NULL) - return -ENOMEM; - substream->private_data = substream->pcm->private_data; - line6pcm = snd_pcm_substream_chip(substream); - } - /* -- [FD] end */ - - ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); - - if (ret < 0) - return ret; - - ret = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - if (ret < 0) { - line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); - return ret; - } - - line6pcm->period_in = params_period_bytes(hw_params); - return 0; -} - -/* hw_free capture callback */ -static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); - return snd_pcm_lib_free_pages(substream); -} - -/* trigger callback */ -int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd) -{ - int err; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: -#ifdef CONFIG_PM - case SNDRV_PCM_TRIGGER_RESUME: -#endif - err = line6_pcm_acquire(line6pcm, - LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); - - if (err < 0) - return err; - - break; - - case SNDRV_PCM_TRIGGER_STOP: -#ifdef CONFIG_PM - case SNDRV_PCM_TRIGGER_SUSPEND: -#endif - err = line6_pcm_release(line6pcm, - LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); - - if (err < 0) - return err; - - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* capture pointer callback */ -static snd_pcm_uframes_t -snd_line6_capture_pointer(struct snd_pcm_substream *substream) -{ - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - return line6pcm->pos_in_done; -} - -/* capture operators */ -struct snd_pcm_ops snd_line6_capture_ops = { - .open = snd_line6_capture_open, - .close = snd_line6_capture_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_line6_capture_hw_params, - .hw_free = snd_line6_capture_hw_free, - .prepare = snd_line6_prepare, - .trigger = snd_line6_trigger, - .pointer = snd_line6_capture_pointer, -}; - -int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) -{ - int i; - - /* create audio URBs and fill in constant values: */ - for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { - struct urb *urb; - - /* URB for audio in: */ - urb = line6pcm->urb_audio_in[i] = - usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); - - if (urb == NULL) { - dev_err(line6pcm->line6->ifcdev, "Out of memory\n"); - return -ENOMEM; - } - - urb->dev = line6pcm->line6->usbdev; - urb->pipe = - usb_rcvisocpipe(line6pcm->line6->usbdev, - line6pcm->ep_audio_read & - USB_ENDPOINT_NUMBER_MASK); - urb->transfer_flags = URB_ISO_ASAP; - urb->start_frame = -1; - urb->number_of_packets = LINE6_ISO_PACKETS; - urb->interval = LINE6_ISO_INTERVAL; - urb->error_count = 0; - urb->complete = audio_in_callback; - } - - return 0; -} diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c deleted file mode 100644 index 503b2d763595..000000000000 --- a/drivers/staging/line6/driver.c +++ /dev/null @@ -1,1162 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include -#include - -#include "audio.h" -#include "capture.h" -#include "driver.h" -#include "midi.h" -#include "playback.h" -#include "pod.h" -#include "podhd.h" -#include "revision.h" -#include "toneport.h" -#include "usbdefs.h" -#include "variax.h" - -#define DRIVER_AUTHOR "Markus Grabner " -#define DRIVER_DESC "Line6 USB Driver" -#define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION - -/* table of devices that work with this driver */ -static const struct usb_device_id line6_id_table[] = { - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXT)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTLIVE)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTPRO)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_GUITARPORT)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_POCKETPOD)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD300)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD400)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD500)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_GX)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX1)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX2)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3LIVE)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXT)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTLIVE)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTPRO)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_GX)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX1)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX2)}, - {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_VARIAX)}, - {}, -}; - -MODULE_DEVICE_TABLE(usb, line6_id_table); - -#define L6PROP(dev_bit, dev_id, dev_name, dev_cap)\ - {.device_bit = LINE6_BIT_##dev_bit, .id = dev_id,\ - .name = dev_name, .capabilities = LINE6_BIT_##dev_cap} - -/* *INDENT-OFF* */ -static const struct line6_properties line6_properties_table[] = { - L6PROP(BASSPODXT, "BassPODxt", "BassPODxt", CTRL_PCM_HW), - L6PROP(BASSPODXTLIVE, "BassPODxtLive", "BassPODxt Live", CTRL_PCM_HW), - L6PROP(BASSPODXTPRO, "BassPODxtPro", "BassPODxt Pro", CTRL_PCM_HW), - L6PROP(GUITARPORT, "GuitarPort", "GuitarPort", PCM), - L6PROP(POCKETPOD, "PocketPOD", "Pocket POD", CONTROL), - L6PROP(PODHD300, "PODHD300", "POD HD300", CTRL_PCM_HW), - L6PROP(PODHD400, "PODHD400", "POD HD400", CTRL_PCM_HW), - L6PROP(PODHD500, "PODHD500", "POD HD500", CTRL_PCM_HW), - L6PROP(PODSTUDIO_GX, "PODStudioGX", "POD Studio GX", PCM), - L6PROP(PODSTUDIO_UX1, "PODStudioUX1", "POD Studio UX1", PCM), - L6PROP(PODSTUDIO_UX2, "PODStudioUX2", "POD Studio UX2", PCM), - L6PROP(PODX3, "PODX3", "POD X3", PCM), - L6PROP(PODX3LIVE, "PODX3Live", "POD X3 Live", PCM), - L6PROP(PODXT, "PODxt", "PODxt", CTRL_PCM_HW), - L6PROP(PODXTLIVE, "PODxtLive", "PODxt Live", CTRL_PCM_HW), - L6PROP(PODXTPRO, "PODxtPro", "PODxt Pro", CTRL_PCM_HW), - L6PROP(TONEPORT_GX, "TonePortGX", "TonePort GX", PCM), - L6PROP(TONEPORT_UX1, "TonePortUX1", "TonePort UX1", PCM), - L6PROP(TONEPORT_UX2, "TonePortUX2", "TonePort UX2", PCM), - L6PROP(VARIAX, "Variax", "Variax Workbench", CONTROL), -}; -/* *INDENT-ON* */ - -/* - This is Line6's MIDI manufacturer ID. -*/ -const unsigned char line6_midi_id[] = { - 0x00, 0x01, 0x0c -}; - -/* - Code to request version of POD, Variax interface - (and maybe other devices). -*/ -static const char line6_request_version[] = { - 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7 -}; - -/** - Class for asynchronous messages. -*/ -struct message { - struct usb_line6 *line6; - const char *buffer; - int size; - int done; -}; - -/* - Forward declarations. -*/ -static void line6_data_received(struct urb *urb); -static int line6_send_raw_message_async_part(struct message *msg, - struct urb *urb); - -/* - Start to listen on endpoint. -*/ -static int line6_start_listen(struct usb_line6 *line6) -{ - int err; - - usb_fill_int_urb(line6->urb_listen, line6->usbdev, - usb_rcvintpipe(line6->usbdev, line6->ep_control_read), - line6->buffer_listen, LINE6_BUFSIZE_LISTEN, - line6_data_received, line6, line6->interval); - line6->urb_listen->actual_length = 0; - err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC); - return err; -} - -/* - Stop listening on endpoint. -*/ -static void line6_stop_listen(struct usb_line6 *line6) -{ - usb_kill_urb(line6->urb_listen); -} - -/* - Send raw message in pieces of wMaxPacketSize bytes. -*/ -int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, - int size) -{ - int i, done = 0; - - for (i = 0; i < size; i += line6->max_packet_size) { - int partial; - const char *frag_buf = buffer + i; - int frag_size = min(line6->max_packet_size, size - i); - int retval; - - retval = usb_interrupt_msg(line6->usbdev, - usb_sndintpipe(line6->usbdev, - line6->ep_control_write), - (char *)frag_buf, frag_size, - &partial, LINE6_TIMEOUT * HZ); - - if (retval) { - dev_err(line6->ifcdev, - "usb_interrupt_msg failed (%d)\n", retval); - break; - } - - done += frag_size; - } - - return done; -} - -/* - Notification of completion of asynchronous request transmission. -*/ -static void line6_async_request_sent(struct urb *urb) -{ - struct message *msg = (struct message *)urb->context; - - if (msg->done >= msg->size) { - usb_free_urb(urb); - kfree(msg); - } else - line6_send_raw_message_async_part(msg, urb); -} - -/* - Asynchronously send part of a raw message. -*/ -static int line6_send_raw_message_async_part(struct message *msg, - struct urb *urb) -{ - int retval; - struct usb_line6 *line6 = msg->line6; - int done = msg->done; - int bytes = min(msg->size - done, line6->max_packet_size); - - usb_fill_int_urb(urb, line6->usbdev, - usb_sndintpipe(line6->usbdev, line6->ep_control_write), - (char *)msg->buffer + done, bytes, - line6_async_request_sent, msg, line6->interval); - - msg->done += bytes; - retval = usb_submit_urb(urb, GFP_ATOMIC); - - if (retval < 0) { - dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n", - __func__, retval); - usb_free_urb(urb); - kfree(msg); - return retval; - } - - return 0; -} - -/* - Setup and start timer. -*/ -void line6_start_timer(struct timer_list *timer, unsigned int msecs, - void (*function)(unsigned long), unsigned long data) -{ - setup_timer(timer, function, data); - timer->expires = jiffies + msecs * HZ / 1000; - add_timer(timer); -} - -/* - Asynchronously send raw message. -*/ -int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer, - int size) -{ - struct message *msg; - struct urb *urb; - - /* create message: */ - msg = kmalloc(sizeof(struct message), GFP_ATOMIC); - if (msg == NULL) - return -ENOMEM; - - /* create URB: */ - urb = usb_alloc_urb(0, GFP_ATOMIC); - - if (urb == NULL) { - kfree(msg); - dev_err(line6->ifcdev, "Out of memory\n"); - return -ENOMEM; - } - - /* set message data: */ - msg->line6 = line6; - msg->buffer = buffer; - msg->size = size; - msg->done = 0; - - /* start sending: */ - return line6_send_raw_message_async_part(msg, urb); -} - -/* - Send asynchronous device version request. -*/ -int line6_version_request_async(struct usb_line6 *line6) -{ - char *buffer; - int retval; - - buffer = kmemdup(line6_request_version, - sizeof(line6_request_version), GFP_ATOMIC); - if (buffer == NULL) { - dev_err(line6->ifcdev, "Out of memory"); - return -ENOMEM; - } - - retval = line6_send_raw_message_async(line6, buffer, - sizeof(line6_request_version)); - kfree(buffer); - return retval; -} - -/* - Send sysex message in pieces of wMaxPacketSize bytes. -*/ -int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer, - int size) -{ - return line6_send_raw_message(line6, buffer, - size + SYSEX_EXTRA_SIZE) - - SYSEX_EXTRA_SIZE; -} - -/* - Allocate buffer for sysex message and prepare header. - @param code sysex message code - @param size number of bytes between code and sysex end -*/ -char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2, - int size) -{ - char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC); - - if (!buffer) - return NULL; - - buffer[0] = LINE6_SYSEX_BEGIN; - memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id)); - buffer[sizeof(line6_midi_id) + 1] = code1; - buffer[sizeof(line6_midi_id) + 2] = code2; - buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END; - return buffer; -} - -/* - Notification of data received from the Line6 device. -*/ -static void line6_data_received(struct urb *urb) -{ - struct usb_line6 *line6 = (struct usb_line6 *)urb->context; - struct midi_buffer *mb = &line6->line6midi->midibuf_in; - int done; - - if (urb->status == -ESHUTDOWN) - return; - - done = - line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length); - - if (done < urb->actual_length) { - line6_midibuf_ignore(mb, done); - dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n", - done, urb->actual_length); - } - - for (;;) { - done = - line6_midibuf_read(mb, line6->buffer_message, - LINE6_MESSAGE_MAXLEN); - - if (done == 0) - break; - - line6->message_length = done; - line6_midi_receive(line6, line6->buffer_message, done); - - switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) { - case LINE6_DEVID_BASSPODXT: - case LINE6_DEVID_BASSPODXTLIVE: - case LINE6_DEVID_BASSPODXTPRO: - case LINE6_DEVID_PODXT: - case LINE6_DEVID_PODXTPRO: - case LINE6_DEVID_POCKETPOD: - line6_pod_process_message((struct usb_line6_pod *) - line6); - break; - - case LINE6_DEVID_PODHD300: - case LINE6_DEVID_PODHD400: - case LINE6_DEVID_PODHD500: - break; /* let userspace handle MIDI */ - - case LINE6_DEVID_PODXTLIVE: - switch (line6->interface_number) { - case PODXTLIVE_INTERFACE_POD: - line6_pod_process_message((struct usb_line6_pod - *)line6); - break; - - case PODXTLIVE_INTERFACE_VARIAX: - line6_variax_process_message((struct - usb_line6_variax - *)line6); - break; - - default: - dev_err(line6->ifcdev, - "PODxt Live interface %d not supported\n", - line6->interface_number); - } - break; - - case LINE6_DEVID_VARIAX: - line6_variax_process_message((struct usb_line6_variax *) - line6); - break; - - default: - MISSING_CASE; - } - } - - line6_start_listen(line6); -} - -/* - Send channel number (i.e., switch to a different sound). -*/ -int line6_send_program(struct usb_line6 *line6, u8 value) -{ - int retval; - unsigned char *buffer; - int partial; - - buffer = kmalloc(2, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - buffer[0] = LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST; - buffer[1] = value; - - retval = usb_interrupt_msg(line6->usbdev, - usb_sndintpipe(line6->usbdev, - line6->ep_control_write), - buffer, 2, &partial, LINE6_TIMEOUT * HZ); - - if (retval) - dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n", - retval); - - kfree(buffer); - return retval; -} - -/* - Transmit Line6 control parameter. -*/ -int line6_transmit_parameter(struct usb_line6 *line6, int param, u8 value) -{ - int retval; - unsigned char *buffer; - int partial; - - buffer = kmalloc(3, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - buffer[0] = LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST; - buffer[1] = param; - buffer[2] = value; - - retval = usb_interrupt_msg(line6->usbdev, - usb_sndintpipe(line6->usbdev, - line6->ep_control_write), - buffer, 3, &partial, LINE6_TIMEOUT * HZ); - - if (retval) - dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n", - retval); - - kfree(buffer); - return retval; -} - -/* - Read data from device. -*/ -int line6_read_data(struct usb_line6 *line6, int address, void *data, - size_t datalen) -{ - struct usb_device *usbdev = line6->usbdev; - int ret; - unsigned char len; - - /* query the serial number: */ - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - (datalen << 8) | 0x21, address, - NULL, 0, LINE6_TIMEOUT * HZ); - - if (ret < 0) { - dev_err(line6->ifcdev, "read request failed (error %d)\n", ret); - return ret; - } - - /* Wait for data length. We'll get 0xff until length arrives. */ - do { - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_IN, - 0x0012, 0x0000, &len, 1, - LINE6_TIMEOUT * HZ); - if (ret < 0) { - dev_err(line6->ifcdev, - "receive length failed (error %d)\n", ret); - return ret; - } - } while (len == 0xff); - - if (len != datalen) { - /* should be equal or something went wrong */ - dev_err(line6->ifcdev, - "length mismatch (expected %d, got %d)\n", - (int)datalen, (int)len); - return -EINVAL; - } - - /* receive the result: */ - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x0013, 0x0000, data, datalen, - LINE6_TIMEOUT * HZ); - - if (ret < 0) { - dev_err(line6->ifcdev, "read failed (error %d)\n", ret); - return ret; - } - - return 0; -} - -/* - Write data to device. -*/ -int line6_write_data(struct usb_line6 *line6, int address, void *data, - size_t datalen) -{ - struct usb_device *usbdev = line6->usbdev; - int ret; - unsigned char status; - - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - 0x0022, address, data, datalen, - LINE6_TIMEOUT * HZ); - - if (ret < 0) { - dev_err(line6->ifcdev, - "write request failed (error %d)\n", ret); - return ret; - } - - do { - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), - 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_IN, - 0x0012, 0x0000, - &status, 1, LINE6_TIMEOUT * HZ); - - if (ret < 0) { - dev_err(line6->ifcdev, - "receiving status failed (error %d)\n", ret); - return ret; - } - } while (status == 0xff); - - if (status != 0) { - dev_err(line6->ifcdev, "write failed (error %d)\n", ret); - return -EINVAL; - } - - return 0; -} - -/* - Read Line6 device serial number. - (POD, TonePort, GuitarPort) -*/ -int line6_read_serial_number(struct usb_line6 *line6, int *serial_number) -{ - return line6_read_data(line6, 0x80d0, serial_number, - sizeof(*serial_number)); -} - -/* - No operation (i.e., unsupported). -*/ -ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr, - char *buf) -{ - return 0; -} - -/* - Generic destructor. -*/ -static void line6_destruct(struct usb_interface *interface) -{ - struct usb_line6 *line6; - - if (interface == NULL) - return; - line6 = usb_get_intfdata(interface); - if (line6 == NULL) - return; - - /* free buffer memory first: */ - kfree(line6->buffer_message); - kfree(line6->buffer_listen); - - /* then free URBs: */ - usb_free_urb(line6->urb_listen); - - /* make sure the device isn't destructed twice: */ - usb_set_intfdata(interface, NULL); - - /* free interface data: */ - kfree(line6); -} - -/* - Probe USB device. -*/ -static int line6_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - int devtype; - struct usb_device *usbdev; - struct usb_line6 *line6; - const struct line6_properties *properties; - int interface_number, alternate = 0; - int product; - int size = 0; - int ep_read = 0, ep_write = 0; - int ret; - - if (interface == NULL) - return -ENODEV; - usbdev = interface_to_usbdev(interface); - if (usbdev == NULL) - return -ENODEV; - - /* we don't handle multiple configurations */ - if (usbdev->descriptor.bNumConfigurations != 1) { - ret = -ENODEV; - goto err_put; - } - - /* check vendor and product id */ - for (devtype = ARRAY_SIZE(line6_id_table) - 1; devtype--;) { - u16 idVendor = le16_to_cpu(usbdev->descriptor.idVendor); - u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct); - - if (idVendor == line6_id_table[devtype].idVendor && - idProduct == line6_id_table[devtype].idProduct) - break; - } - - if (devtype < 0) { - ret = -ENODEV; - goto err_put; - } - - /* initialize device info: */ - properties = &line6_properties_table[devtype]; - dev_info(&interface->dev, "Line6 %s found\n", properties->name); - product = le16_to_cpu(usbdev->descriptor.idProduct); - - /* query interface number */ - interface_number = interface->cur_altsetting->desc.bInterfaceNumber; - - switch (product) { - case LINE6_DEVID_BASSPODXTLIVE: - case LINE6_DEVID_PODXTLIVE: - case LINE6_DEVID_VARIAX: - alternate = 1; - break; - - case LINE6_DEVID_POCKETPOD: - switch (interface_number) { - case 0: - return -ENODEV; /* this interface has no endpoints */ - case 1: - alternate = 0; - break; - default: - MISSING_CASE; - } - break; - - case LINE6_DEVID_PODHD500: - case LINE6_DEVID_PODX3: - case LINE6_DEVID_PODX3LIVE: - switch (interface_number) { - case 0: - alternate = 1; - break; - case 1: - alternate = 0; - break; - default: - MISSING_CASE; - } - break; - - case LINE6_DEVID_BASSPODXT: - case LINE6_DEVID_BASSPODXTPRO: - case LINE6_DEVID_PODXT: - case LINE6_DEVID_PODXTPRO: - case LINE6_DEVID_PODHD300: - case LINE6_DEVID_PODHD400: - alternate = 5; - break; - - case LINE6_DEVID_GUITARPORT: - case LINE6_DEVID_PODSTUDIO_GX: - case LINE6_DEVID_PODSTUDIO_UX1: - case LINE6_DEVID_TONEPORT_GX: - case LINE6_DEVID_TONEPORT_UX1: - alternate = 2; /* 1..4 seem to be ok */ - break; - - case LINE6_DEVID_TONEPORT_UX2: - case LINE6_DEVID_PODSTUDIO_UX2: - switch (interface_number) { - case 0: - /* defaults to 44.1kHz, 16-bit */ - alternate = 2; - break; - case 1: - /* don't know yet what this is ... - alternate = 1; - break; - */ - return -ENODEV; - default: - MISSING_CASE; - } - break; - - default: - MISSING_CASE; - ret = -ENODEV; - goto err_put; - } - - ret = usb_set_interface(usbdev, interface_number, alternate); - if (ret < 0) { - dev_err(&interface->dev, "set_interface failed\n"); - goto err_put; - } - - /* initialize device data based on product id: */ - switch (product) { - case LINE6_DEVID_BASSPODXT: - case LINE6_DEVID_BASSPODXTLIVE: - case LINE6_DEVID_BASSPODXTPRO: - case LINE6_DEVID_PODXT: - case LINE6_DEVID_PODXTPRO: - size = sizeof(struct usb_line6_pod); - ep_read = 0x84; - ep_write = 0x03; - break; - - case LINE6_DEVID_PODHD300: - case LINE6_DEVID_PODHD400: - size = sizeof(struct usb_line6_podhd); - ep_read = 0x84; - ep_write = 0x03; - break; - - case LINE6_DEVID_PODHD500: - size = sizeof(struct usb_line6_podhd); - ep_read = 0x81; - ep_write = 0x01; - break; - - case LINE6_DEVID_POCKETPOD: - size = sizeof(struct usb_line6_pod); - ep_read = 0x82; - ep_write = 0x02; - break; - - case LINE6_DEVID_PODX3: - case LINE6_DEVID_PODX3LIVE: - /* currently unused! */ - size = sizeof(struct usb_line6_pod); - ep_read = 0x81; - ep_write = 0x01; - break; - - case LINE6_DEVID_PODSTUDIO_GX: - case LINE6_DEVID_PODSTUDIO_UX1: - case LINE6_DEVID_PODSTUDIO_UX2: - case LINE6_DEVID_TONEPORT_GX: - case LINE6_DEVID_TONEPORT_UX1: - case LINE6_DEVID_TONEPORT_UX2: - case LINE6_DEVID_GUITARPORT: - size = sizeof(struct usb_line6_toneport); - /* these don't have a control channel */ - break; - - case LINE6_DEVID_PODXTLIVE: - switch (interface_number) { - case PODXTLIVE_INTERFACE_POD: - size = sizeof(struct usb_line6_pod); - ep_read = 0x84; - ep_write = 0x03; - break; - - case PODXTLIVE_INTERFACE_VARIAX: - size = sizeof(struct usb_line6_variax); - ep_read = 0x86; - ep_write = 0x05; - break; - - default: - ret = -ENODEV; - goto err_put; - } - break; - - case LINE6_DEVID_VARIAX: - size = sizeof(struct usb_line6_variax); - ep_read = 0x82; - ep_write = 0x01; - break; - - default: - MISSING_CASE; - ret = -ENODEV; - goto err_put; - } - - if (size == 0) { - dev_err(&interface->dev, - "driver bug: interface data size not set\n"); - ret = -ENODEV; - goto err_put; - } - - line6 = kzalloc(size, GFP_KERNEL); - if (line6 == NULL) { - ret = -ENODEV; - goto err_put; - } - - /* store basic data: */ - line6->interface_number = interface_number; - line6->properties = properties; - line6->usbdev = usbdev; - line6->ifcdev = &interface->dev; - line6->ep_control_read = ep_read; - line6->ep_control_write = ep_write; - line6->product = product; - - /* get data from endpoint descriptor (see usb_maxpacket): */ - { - struct usb_host_endpoint *ep; - unsigned epnum = - usb_pipeendpoint(usb_rcvintpipe(usbdev, ep_read)); - ep = usbdev->ep_in[epnum]; - - if (ep != NULL) { - line6->interval = ep->desc.bInterval; - line6->max_packet_size = - le16_to_cpu(ep->desc.wMaxPacketSize); - } else { - line6->interval = LINE6_FALLBACK_INTERVAL; - line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE; - dev_err(line6->ifcdev, - "endpoint not available, using fallback values"); - } - } - - usb_set_intfdata(interface, line6); - - if (properties->capabilities & LINE6_BIT_CONTROL) { - /* initialize USB buffers: */ - line6->buffer_listen = - kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); - if (line6->buffer_listen == NULL) { - ret = -ENOMEM; - goto err_destruct; - } - - line6->buffer_message = - kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL); - if (line6->buffer_message == NULL) { - ret = -ENOMEM; - goto err_destruct; - } - - line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); - - if (line6->urb_listen == NULL) { - dev_err(&interface->dev, "Out of memory\n"); - line6_destruct(interface); - ret = -ENOMEM; - goto err_destruct; - } - - ret = line6_start_listen(line6); - if (ret < 0) { - dev_err(&interface->dev, "%s: usb_submit_urb failed\n", - __func__); - goto err_destruct; - } - } - - /* initialize device data based on product id: */ - switch (product) { - case LINE6_DEVID_BASSPODXT: - case LINE6_DEVID_BASSPODXTLIVE: - case LINE6_DEVID_BASSPODXTPRO: - case LINE6_DEVID_POCKETPOD: - case LINE6_DEVID_PODX3: - case LINE6_DEVID_PODX3LIVE: - case LINE6_DEVID_PODXT: - case LINE6_DEVID_PODXTPRO: - ret = line6_pod_init(interface, (struct usb_line6_pod *)line6); - break; - - case LINE6_DEVID_PODHD300: - case LINE6_DEVID_PODHD400: - case LINE6_DEVID_PODHD500: - ret = line6_podhd_init(interface, - (struct usb_line6_podhd *)line6); - break; - - case LINE6_DEVID_PODXTLIVE: - switch (interface_number) { - case PODXTLIVE_INTERFACE_POD: - ret = - line6_pod_init(interface, - (struct usb_line6_pod *)line6); - break; - - case PODXTLIVE_INTERFACE_VARIAX: - ret = - line6_variax_init(interface, - (struct usb_line6_variax *)line6); - break; - - default: - dev_err(&interface->dev, - "PODxt Live interface %d not supported\n", - interface_number); - ret = -ENODEV; - } - - break; - - case LINE6_DEVID_VARIAX: - ret = - line6_variax_init(interface, - (struct usb_line6_variax *)line6); - break; - - case LINE6_DEVID_PODSTUDIO_GX: - case LINE6_DEVID_PODSTUDIO_UX1: - case LINE6_DEVID_PODSTUDIO_UX2: - case LINE6_DEVID_TONEPORT_GX: - case LINE6_DEVID_TONEPORT_UX1: - case LINE6_DEVID_TONEPORT_UX2: - case LINE6_DEVID_GUITARPORT: - ret = - line6_toneport_init(interface, - (struct usb_line6_toneport *)line6); - break; - - default: - MISSING_CASE; - ret = -ENODEV; - } - - if (ret < 0) - goto err_destruct; - - ret = sysfs_create_link(&interface->dev.kobj, &usbdev->dev.kobj, - "usb_device"); - if (ret < 0) - goto err_destruct; - - /* creation of additional special files should go here */ - - dev_info(&interface->dev, "Line6 %s now attached\n", - line6->properties->name); - - switch (product) { - case LINE6_DEVID_PODX3: - case LINE6_DEVID_PODX3LIVE: - dev_info(&interface->dev, - "NOTE: the Line6 %s is detected, but not yet supported\n", - line6->properties->name); - } - - /* increment reference counters: */ - usb_get_intf(interface); - usb_get_dev(usbdev); - - return 0; - -err_destruct: - line6_destruct(interface); -err_put: - return ret; -} - -/* - Line6 device disconnected. -*/ -static void line6_disconnect(struct usb_interface *interface) -{ - struct usb_line6 *line6; - struct usb_device *usbdev; - int interface_number; - - if (interface == NULL) - return; - usbdev = interface_to_usbdev(interface); - if (usbdev == NULL) - return; - - /* removal of additional special files should go here */ - - sysfs_remove_link(&interface->dev.kobj, "usb_device"); - - interface_number = interface->cur_altsetting->desc.bInterfaceNumber; - line6 = usb_get_intfdata(interface); - - if (line6 != NULL) { - if (line6->urb_listen != NULL) - line6_stop_listen(line6); - - if (usbdev != line6->usbdev) - dev_err(line6->ifcdev, - "driver bug: inconsistent usb device\n"); - - switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) { - case LINE6_DEVID_BASSPODXT: - case LINE6_DEVID_BASSPODXTLIVE: - case LINE6_DEVID_BASSPODXTPRO: - case LINE6_DEVID_POCKETPOD: - case LINE6_DEVID_PODX3: - case LINE6_DEVID_PODX3LIVE: - case LINE6_DEVID_PODXT: - case LINE6_DEVID_PODXTPRO: - line6_pod_disconnect(interface); - break; - - case LINE6_DEVID_PODHD300: - case LINE6_DEVID_PODHD400: - case LINE6_DEVID_PODHD500: - line6_podhd_disconnect(interface); - break; - - case LINE6_DEVID_PODXTLIVE: - switch (interface_number) { - case PODXTLIVE_INTERFACE_POD: - line6_pod_disconnect(interface); - break; - - case PODXTLIVE_INTERFACE_VARIAX: - line6_variax_disconnect(interface); - break; - } - - break; - - case LINE6_DEVID_VARIAX: - line6_variax_disconnect(interface); - break; - - case LINE6_DEVID_PODSTUDIO_GX: - case LINE6_DEVID_PODSTUDIO_UX1: - case LINE6_DEVID_PODSTUDIO_UX2: - case LINE6_DEVID_TONEPORT_GX: - case LINE6_DEVID_TONEPORT_UX1: - case LINE6_DEVID_TONEPORT_UX2: - case LINE6_DEVID_GUITARPORT: - line6_toneport_disconnect(interface); - break; - - default: - MISSING_CASE; - } - - dev_info(&interface->dev, "Line6 %s now disconnected\n", - line6->properties->name); - } - - line6_destruct(interface); - - /* decrement reference counters: */ - usb_put_intf(interface); - usb_put_dev(usbdev); -} - -#ifdef CONFIG_PM - -/* - Suspend Line6 device. -*/ -static int line6_suspend(struct usb_interface *interface, pm_message_t message) -{ - struct usb_line6 *line6 = usb_get_intfdata(interface); - struct snd_line6_pcm *line6pcm = line6->line6pcm; - - snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot); - - if (line6->properties->capabilities & LINE6_BIT_CONTROL) - line6_stop_listen(line6); - - if (line6pcm != NULL) { - snd_pcm_suspend_all(line6pcm->pcm); - line6_pcm_disconnect(line6pcm); - line6pcm->flags = 0; - } - - return 0; -} - -/* - Resume Line6 device. -*/ -static int line6_resume(struct usb_interface *interface) -{ - struct usb_line6 *line6 = usb_get_intfdata(interface); - - if (line6->properties->capabilities & LINE6_BIT_CONTROL) - line6_start_listen(line6); - - snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0); - return 0; -} - -/* - Resume Line6 device after reset. -*/ -static int line6_reset_resume(struct usb_interface *interface) -{ - struct usb_line6 *line6 = usb_get_intfdata(interface); - - switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) { - case LINE6_DEVID_PODSTUDIO_GX: - case LINE6_DEVID_PODSTUDIO_UX1: - case LINE6_DEVID_PODSTUDIO_UX2: - case LINE6_DEVID_TONEPORT_GX: - case LINE6_DEVID_TONEPORT_UX1: - case LINE6_DEVID_TONEPORT_UX2: - case LINE6_DEVID_GUITARPORT: - line6_toneport_reset_resume((struct usb_line6_toneport *)line6); - } - - return line6_resume(interface); -} - -#endif /* CONFIG_PM */ - -static struct usb_driver line6_driver = { - .name = DRIVER_NAME, - .probe = line6_probe, - .disconnect = line6_disconnect, -#ifdef CONFIG_PM - .suspend = line6_suspend, - .resume = line6_resume, - .reset_resume = line6_reset_resume, -#endif - .id_table = line6_id_table, -}; - -module_usb_driver(line6_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c deleted file mode 100644 index a3136b189ee5..000000000000 --- a/drivers/staging/line6/pcm.c +++ /dev/null @@ -1,576 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include -#include -#include - -#include "audio.h" -#include "capture.h" -#include "driver.h" -#include "playback.h" -#include "pod.h" - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - -static struct snd_line6_pcm *dev2pcm(struct device *dev) -{ - struct usb_interface *interface = to_usb_interface(dev); - struct usb_line6 *line6 = usb_get_intfdata(interface); - struct snd_line6_pcm *line6pcm = line6->line6pcm; - return line6pcm; -} - -/* - "read" request on "impulse_volume" special file. -*/ -static ssize_t impulse_volume_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume); -} - -/* - "write" request on "impulse_volume" special file. -*/ -static ssize_t impulse_volume_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct snd_line6_pcm *line6pcm = dev2pcm(dev); - int value; - int ret; - - ret = kstrtoint(buf, 10, &value); - if (ret < 0) - return ret; - - line6pcm->impulse_volume = value; - - if (value > 0) - line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE); - else - line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE); - - return count; -} -static DEVICE_ATTR_RW(impulse_volume); - -/* - "read" request on "impulse_period" special file. -*/ -static ssize_t impulse_period_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period); -} - -/* - "write" request on "impulse_period" special file. -*/ -static ssize_t impulse_period_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int value; - int ret; - - ret = kstrtoint(buf, 10, &value); - if (ret < 0) - return ret; - - dev2pcm(dev)->impulse_period = value; - return count; -} -static DEVICE_ATTR_RW(impulse_period); - -#endif - -static bool test_flags(unsigned long flags0, unsigned long flags1, - unsigned long mask) -{ - return ((flags0 & mask) == 0) && ((flags1 & mask) != 0); -} - -int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) -{ - unsigned long flags_old, flags_new, flags_final; - int err; - - do { - flags_old = ACCESS_ONCE(line6pcm->flags); - flags_new = flags_old | channels; - } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); - - flags_final = flags_old; - - line6pcm->prev_fbuf = NULL; - - if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) { - /* Invoked multiple times in a row so allocate once only */ - if (!line6pcm->buffer_in) { - line6pcm->buffer_in = - kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * - line6pcm->max_packet_size, GFP_KERNEL); - if (!line6pcm->buffer_in) { - err = -ENOMEM; - goto pcm_acquire_error; - } - - flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER; - } - } - - if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) { - /* - Waiting for completion of active URBs in the stop handler is - a bug, we therefore report an error if capturing is restarted - too soon. - */ - if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) { - dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); - return -EBUSY; - } - - line6pcm->count_in = 0; - line6pcm->prev_fsize = 0; - err = line6_submit_audio_in_all_urbs(line6pcm); - - if (err < 0) - goto pcm_acquire_error; - - flags_final |= channels & LINE6_BITS_CAPTURE_STREAM; - } - - if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) { - /* Invoked multiple times in a row so allocate once only */ - if (!line6pcm->buffer_out) { - line6pcm->buffer_out = - kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * - line6pcm->max_packet_size, GFP_KERNEL); - if (!line6pcm->buffer_out) { - err = -ENOMEM; - goto pcm_acquire_error; - } - - flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER; - } - } - - if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) { - /* - See comment above regarding PCM restart. - */ - if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) { - dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); - return -EBUSY; - } - - line6pcm->count_out = 0; - err = line6_submit_audio_out_all_urbs(line6pcm); - - if (err < 0) - goto pcm_acquire_error; - - flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM; - } - - return 0; - -pcm_acquire_error: - /* - If not all requested resources/streams could be obtained, release - those which were successfully obtained (if any). - */ - line6_pcm_release(line6pcm, flags_final & channels); - return err; -} - -int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) -{ - unsigned long flags_old, flags_new; - - do { - flags_old = ACCESS_ONCE(line6pcm->flags); - flags_new = flags_old & ~channels; - } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); - - if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM)) - line6_unlink_audio_in_urbs(line6pcm); - - if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) { - line6_wait_clear_audio_in_urbs(line6pcm); - line6_free_capture_buffer(line6pcm); - } - - if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM)) - line6_unlink_audio_out_urbs(line6pcm); - - if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) { - line6_wait_clear_audio_out_urbs(line6pcm); - line6_free_playback_buffer(line6pcm); - } - - return 0; -} - -/* trigger callback */ -int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - struct snd_pcm_substream *s; - int err; - unsigned long flags; - - spin_lock_irqsave(&line6pcm->lock_trigger, flags); - clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags); - - snd_pcm_group_for_each_entry(s, substream) { - switch (s->stream) { - case SNDRV_PCM_STREAM_PLAYBACK: - err = snd_line6_playback_trigger(line6pcm, cmd); - - if (err < 0) { - spin_unlock_irqrestore(&line6pcm->lock_trigger, - flags); - return err; - } - - break; - - case SNDRV_PCM_STREAM_CAPTURE: - err = snd_line6_capture_trigger(line6pcm, cmd); - - if (err < 0) { - spin_unlock_irqrestore(&line6pcm->lock_trigger, - flags); - return err; - } - - break; - - default: - dev_err(line6pcm->line6->ifcdev, - "Unknown stream direction %d\n", s->stream); - } - } - - spin_unlock_irqrestore(&line6pcm->lock_trigger, flags); - return 0; -} - -/* control info callback */ -static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 256; - return 0; -} - -/* control get callback */ -static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int i; - struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); - - for (i = 2; i--;) - ucontrol->value.integer.value[i] = line6pcm->volume_playback[i]; - - return 0; -} - -/* control put callback */ -static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int i, changed = 0; - struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); - - for (i = 2; i--;) - if (line6pcm->volume_playback[i] != - ucontrol->value.integer.value[i]) { - line6pcm->volume_playback[i] = - ucontrol->value.integer.value[i]; - changed = 1; - } - - return changed; -} - -/* control definition */ -static struct snd_kcontrol_new line6_control_playback = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .index = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_line6_control_playback_info, - .get = snd_line6_control_playback_get, - .put = snd_line6_control_playback_put -}; - -/* - Cleanup the PCM device. -*/ -static void line6_cleanup_pcm(struct snd_pcm *pcm) -{ - int i; - struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_volume); - device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_period); -#endif - - for (i = LINE6_ISO_BUFFERS; i--;) { - if (line6pcm->urb_audio_out[i]) { - usb_kill_urb(line6pcm->urb_audio_out[i]); - usb_free_urb(line6pcm->urb_audio_out[i]); - } - if (line6pcm->urb_audio_in[i]) { - usb_kill_urb(line6pcm->urb_audio_in[i]); - usb_free_urb(line6pcm->urb_audio_in[i]); - } - } -} - -/* create a PCM device */ -static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm) -{ - struct snd_pcm *pcm; - int err; - - err = snd_pcm_new(line6pcm->line6->card, - (char *)line6pcm->line6->properties->name, - 0, 1, 1, &pcm); - if (err < 0) - return err; - - pcm->private_data = line6pcm; - pcm->private_free = line6_cleanup_pcm; - line6pcm->pcm = pcm; - strcpy(pcm->name, line6pcm->line6->properties->name); - - /* set operators */ - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, - &snd_line6_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops); - - /* pre-allocation of buffers */ - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data - (GFP_KERNEL), 64 * 1024, - 128 * 1024); - - return 0; -} - -/* PCM device destructor */ -static int snd_line6_pcm_free(struct snd_device *device) -{ - return 0; -} - -/* - Stop substream if still running. -*/ -static void pcm_disconnect_substream(struct snd_pcm_substream *substream) -{ - if (substream->runtime && snd_pcm_running(substream)) { - snd_pcm_stream_lock_irq(substream); - snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); - snd_pcm_stream_unlock_irq(substream); - } -} - -/* - Stop PCM stream. -*/ -void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm) -{ - pcm_disconnect_substream(get_substream - (line6pcm, SNDRV_PCM_STREAM_CAPTURE)); - pcm_disconnect_substream(get_substream - (line6pcm, SNDRV_PCM_STREAM_PLAYBACK)); - line6_unlink_wait_clear_audio_out_urbs(line6pcm); - line6_unlink_wait_clear_audio_in_urbs(line6pcm); -} - -/* - Create and register the PCM device and mixer entries. - Create URBs for playback and capture. -*/ -int line6_init_pcm(struct usb_line6 *line6, - struct line6_pcm_properties *properties) -{ - static struct snd_device_ops pcm_ops = { - .dev_free = snd_line6_pcm_free, - }; - - int err; - int ep_read = 0, ep_write = 0; - struct snd_line6_pcm *line6pcm; - - if (!(line6->properties->capabilities & LINE6_BIT_PCM)) - return 0; /* skip PCM initialization and report success */ - - /* initialize PCM subsystem based on product id: */ - switch (line6->product) { - case LINE6_DEVID_BASSPODXT: - case LINE6_DEVID_BASSPODXTLIVE: - case LINE6_DEVID_BASSPODXTPRO: - case LINE6_DEVID_PODXT: - case LINE6_DEVID_PODXTLIVE: - case LINE6_DEVID_PODXTPRO: - case LINE6_DEVID_PODHD300: - case LINE6_DEVID_PODHD400: - ep_read = 0x82; - ep_write = 0x01; - break; - - case LINE6_DEVID_PODHD500: - case LINE6_DEVID_PODX3: - case LINE6_DEVID_PODX3LIVE: - ep_read = 0x86; - ep_write = 0x02; - break; - - case LINE6_DEVID_POCKETPOD: - ep_read = 0x82; - ep_write = 0x02; - break; - - case LINE6_DEVID_GUITARPORT: - case LINE6_DEVID_PODSTUDIO_GX: - case LINE6_DEVID_PODSTUDIO_UX1: - case LINE6_DEVID_PODSTUDIO_UX2: - case LINE6_DEVID_TONEPORT_GX: - case LINE6_DEVID_TONEPORT_UX1: - case LINE6_DEVID_TONEPORT_UX2: - ep_read = 0x82; - ep_write = 0x01; - break; - - /* this is for interface_number == 1: - case LINE6_DEVID_TONEPORT_UX2: - case LINE6_DEVID_PODSTUDIO_UX2: - ep_read = 0x87; - ep_write = 0x00; - break; */ - - default: - MISSING_CASE; - } - - line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL); - - if (line6pcm == NULL) - return -ENOMEM; - - line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; - line6pcm->volume_monitor = 255; - line6pcm->line6 = line6; - line6pcm->ep_audio_read = ep_read; - line6pcm->ep_audio_write = ep_write; - - /* Read and write buffers are sized identically, so choose minimum */ - line6pcm->max_packet_size = min( - usb_maxpacket(line6->usbdev, - usb_rcvisocpipe(line6->usbdev, ep_read), 0), - usb_maxpacket(line6->usbdev, - usb_sndisocpipe(line6->usbdev, ep_write), 1)); - - line6pcm->properties = properties; - line6->line6pcm = line6pcm; - - /* PCM device: */ - err = snd_device_new(line6->card, SNDRV_DEV_PCM, line6, &pcm_ops); - if (err < 0) - return err; - - err = snd_line6_new_pcm(line6pcm); - if (err < 0) - return err; - - spin_lock_init(&line6pcm->lock_audio_out); - spin_lock_init(&line6pcm->lock_audio_in); - spin_lock_init(&line6pcm->lock_trigger); - - err = line6_create_audio_out_urbs(line6pcm); - if (err < 0) - return err; - - err = line6_create_audio_in_urbs(line6pcm); - if (err < 0) - return err; - - /* mixer: */ - err = - snd_ctl_add(line6->card, - snd_ctl_new1(&line6_control_playback, line6pcm)); - if (err < 0) - return err; - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - /* impulse response test: */ - err = device_create_file(line6->ifcdev, &dev_attr_impulse_volume); - if (err < 0) - return err; - - err = device_create_file(line6->ifcdev, &dev_attr_impulse_period); - if (err < 0) - return err; - - line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD; -#endif - - return 0; -} - -/* prepare pcm callback */ -int snd_line6_prepare(struct snd_pcm_substream *substream) -{ - struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); - - switch (substream->stream) { - case SNDRV_PCM_STREAM_PLAYBACK: - if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0) - line6_unlink_wait_clear_audio_out_urbs(line6pcm); - - break; - - case SNDRV_PCM_STREAM_CAPTURE: - if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0) - line6_unlink_wait_clear_audio_in_urbs(line6pcm); - - break; - - default: - MISSING_CASE; - } - - if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) { - line6pcm->count_out = 0; - line6pcm->pos_out = 0; - line6pcm->pos_out_done = 0; - line6pcm->bytes_out = 0; - line6pcm->count_in = 0; - line6pcm->pos_in_done = 0; - line6pcm->bytes_in = 0; - } - - return 0; -} diff --git a/drivers/staging/line6/pcm.h b/drivers/staging/line6/pcm.h deleted file mode 100644 index 6aa0d46a2890..000000000000 --- a/drivers/staging/line6/pcm.h +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -/* - PCM interface to POD series devices. -*/ - -#ifndef PCM_H -#define PCM_H - -#include - -#include "driver.h" -#include "usbdefs.h" - -/* number of URBs */ -#define LINE6_ISO_BUFFERS 2 - -/* - number of USB frames per URB - The Line6 Windows driver always transmits two frames per packet, but - the Linux driver performs significantly better (i.e., lower latency) - with only one frame per packet. -*/ -#define LINE6_ISO_PACKETS 1 - -/* in a "full speed" device (such as the PODxt Pro) this means 1ms */ -#define LINE6_ISO_INTERVAL 1 - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE -#define LINE6_IMPULSE_DEFAULT_PERIOD 100 -#endif - -/* - Get substream from Line6 PCM data structure -*/ -#define get_substream(line6pcm, stream) \ - (line6pcm->pcm->streams[stream].substream) - -/* - PCM mode bits. - - There are several features of the Line6 USB driver which require PCM - data to be exchanged with the device: - *) PCM playback and capture via ALSA - *) software monitoring (for devices without hardware monitoring) - *) optional impulse response measurement - However, from the device's point of view, there is just a single - capture and playback stream, which must be shared between these - subsystems. It is therefore necessary to maintain the state of the - subsystems with respect to PCM usage. We define several constants of - the form LINE6_BIT_PCM___ with the - following meanings: - *) is one of - -) ALSA: PCM playback and capture via ALSA - -) MONITOR: software monitoring - -) IMPULSE: optional impulse response measurement - *) is one of - -) PLAYBACK: audio output (from host to device) - -) CAPTURE: audio input (from device to host) - *) is one of - -) BUFFER: buffer required by PCM data stream - -) STREAM: actual PCM data stream - - The subsystems call line6_pcm_acquire() to acquire the (shared) - resources needed for a particular operation (e.g., allocate the buffer - for ALSA playback or start the capture stream for software monitoring). - When a resource is no longer needed, it is released by calling - line6_pcm_release(). Buffer allocation and stream startup are handled - separately to allow the ALSA kernel driver to perform them at - appropriate places (since the callback which starts a PCM stream is not - allowed to sleep). -*/ -enum { - /* individual bit indices: */ - LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER, - LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, - LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER, - LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, - LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER, - LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM, - LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER, - LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM, -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER, - LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM, - LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER, - LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM, -#endif - LINE6_INDEX_PAUSE_PLAYBACK, - LINE6_INDEX_PREPARED, - - /* individual bit masks: */ - LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER), - LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM), - LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER), - LINE6_BIT(PCM_ALSA_CAPTURE_STREAM), - LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER), - LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM), - LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER), - LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM), -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER), - LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM), - LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER), - LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM), -#endif - LINE6_BIT(PAUSE_PLAYBACK), - LINE6_BIT(PREPARED), - - /* combined bit masks (by operation): */ - LINE6_BITS_PCM_ALSA_BUFFER = - LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | - LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER, - - LINE6_BITS_PCM_ALSA_STREAM = - LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | - LINE6_BIT_PCM_ALSA_CAPTURE_STREAM, - - LINE6_BITS_PCM_MONITOR = - LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER | - LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM | - LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER | - LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - LINE6_BITS_PCM_IMPULSE = - LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | - LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | - LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | - LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM, -#endif - - /* combined bit masks (by direction): */ - LINE6_BITS_PLAYBACK_BUFFER = -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | -#endif - LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | - LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER , - - LINE6_BITS_PLAYBACK_STREAM = -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | -#endif - LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | - LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM , - - LINE6_BITS_CAPTURE_BUFFER = -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | -#endif - LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER | - LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER , - - LINE6_BITS_CAPTURE_STREAM = -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM | -#endif - LINE6_BIT_PCM_ALSA_CAPTURE_STREAM | - LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, - - LINE6_BITS_STREAM = - LINE6_BITS_PLAYBACK_STREAM | - LINE6_BITS_CAPTURE_STREAM -}; - -struct line6_pcm_properties { - struct snd_pcm_hardware snd_line6_playback_hw, snd_line6_capture_hw; - struct snd_pcm_hw_constraint_ratdens snd_line6_rates; - int bytes_per_frame; -}; - -struct snd_line6_pcm { - /** - Pointer back to the Line6 driver data structure. - */ - struct usb_line6 *line6; - - /** - Properties. - */ - struct line6_pcm_properties *properties; - - /** - ALSA pcm stream - */ - struct snd_pcm *pcm; - - /** - URBs for audio playback. - */ - struct urb *urb_audio_out[LINE6_ISO_BUFFERS]; - - /** - URBs for audio capture. - */ - struct urb *urb_audio_in[LINE6_ISO_BUFFERS]; - - /** - Temporary buffer for playback. - Since the packet size is not known in advance, this buffer is - large enough to store maximum size packets. - */ - unsigned char *buffer_out; - - /** - Temporary buffer for capture. - Since the packet size is not known in advance, this buffer is - large enough to store maximum size packets. - */ - unsigned char *buffer_in; - - /** - Previously captured frame (for software monitoring). - */ - unsigned char *prev_fbuf; - - /** - Size of previously captured frame (for software monitoring). - */ - int prev_fsize; - - /** - Free frame position in the playback buffer. - */ - snd_pcm_uframes_t pos_out; - - /** - Count processed bytes for playback. - This is modulo period size (to determine when a period is - finished). - */ - unsigned bytes_out; - - /** - Counter to create desired playback sample rate. - */ - unsigned count_out; - - /** - Playback period size in bytes - */ - unsigned period_out; - - /** - Processed frame position in the playback buffer. - The contents of the output ring buffer have been consumed by - the USB subsystem (i.e., sent to the USB device) up to this - position. - */ - snd_pcm_uframes_t pos_out_done; - - /** - Count processed bytes for capture. - This is modulo period size (to determine when a period is - finished). - */ - unsigned bytes_in; - - /** - Counter to create desired capture sample rate. - */ - unsigned count_in; - - /** - Capture period size in bytes - */ - unsigned period_in; - - /** - Processed frame position in the capture buffer. - The contents of the output ring buffer have been consumed by - the USB subsystem (i.e., sent to the USB device) up to this - position. - */ - snd_pcm_uframes_t pos_in_done; - - /** - Bit mask of active playback URBs. - */ - unsigned long active_urb_out; - - /** - Maximum size of USB packet. - */ - int max_packet_size; - - /** - USB endpoint for listening to audio data. - */ - int ep_audio_read; - - /** - USB endpoint for writing audio data. - */ - int ep_audio_write; - - /** - Bit mask of active capture URBs. - */ - unsigned long active_urb_in; - - /** - Bit mask of playback URBs currently being unlinked. - */ - unsigned long unlink_urb_out; - - /** - Bit mask of capture URBs currently being unlinked. - */ - unsigned long unlink_urb_in; - - /** - Spin lock to protect updates of the playback buffer positions (not - contents!) - */ - spinlock_t lock_audio_out; - - /** - Spin lock to protect updates of the capture buffer positions (not - contents!) - */ - spinlock_t lock_audio_in; - - /** - Spin lock to protect trigger. - */ - spinlock_t lock_trigger; - - /** - PCM playback volume (left and right). - */ - int volume_playback[2]; - - /** - PCM monitor volume. - */ - int volume_monitor; - -#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE - /** - Volume of impulse response test signal (if zero, test is disabled). - */ - int impulse_volume; - - /** - Period of impulse response test signal. - */ - int impulse_period; - - /** - Counter for impulse response test signal. - */ - int impulse_count; -#endif - - /** - Several status bits (see LINE6_BIT_*). - */ - unsigned long flags; - - int last_frame_in, last_frame_out; -}; - -extern int line6_init_pcm(struct usb_line6 *line6, - struct line6_pcm_properties *properties); -extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd); -extern int snd_line6_prepare(struct snd_pcm_substream *substream); -extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm); -extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels); -extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels); - -#endif diff --git a/drivers/staging/line6/pod.h b/drivers/staging/line6/pod.h deleted file mode 100644 index 3e3f1671337a..000000000000 --- a/drivers/staging/line6/pod.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef POD_H -#define POD_H - -#include -#include -#include - -#include - -#include "driver.h" - -/* - PODxt Live interfaces -*/ -#define PODXTLIVE_INTERFACE_POD 0 -#define PODXTLIVE_INTERFACE_VARIAX 1 - -/* - Locate name in binary program dump -*/ -#define POD_NAME_OFFSET 0 -#define POD_NAME_LENGTH 16 - -/* - Other constants -*/ -#define POD_CONTROL_SIZE 0x80 -#define POD_BUFSIZE_DUMPREQ 7 -#define POD_STARTUP_DELAY 1000 - -/* - Stages of POD startup procedure -*/ -enum { - POD_STARTUP_INIT = 1, - POD_STARTUP_VERSIONREQ, - POD_STARTUP_WORKQUEUE, - POD_STARTUP_SETUP, - POD_STARTUP_LAST = POD_STARTUP_SETUP - 1 -}; - -struct usb_line6_pod { - /** - Generic Line6 USB data. - */ - struct usb_line6 line6; - - /** - Instrument monitor level. - */ - int monitor_level; - - /** - Timer for device initializaton. - */ - struct timer_list startup_timer; - - /** - Work handler for device initializaton. - */ - struct work_struct startup_work; - - /** - Current progress in startup procedure. - */ - int startup_progress; - - /** - Serial number of device. - */ - int serial_number; - - /** - Firmware version (x 100). - */ - int firmware_version; - - /** - Device ID. - */ - int device_id; -}; - -extern void line6_pod_disconnect(struct usb_interface *interface); -extern int line6_pod_init(struct usb_interface *interface, - struct usb_line6_pod *pod); -extern void line6_pod_process_message(struct usb_line6_pod *pod); -extern void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param, - u8 value); - -#endif diff --git a/drivers/staging/line6/podhd.c b/drivers/staging/line6/podhd.c deleted file mode 100644 index 7ef45437b4f2..000000000000 --- a/drivers/staging/line6/podhd.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Line6 Pod HD - * - * Copyright (C) 2011 Stefan Hajnoczi - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include - -#include "audio.h" -#include "driver.h" -#include "pcm.h" -#include "podhd.h" - -#define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ - -static struct snd_ratden podhd_ratden = { - .num_min = 48000, - .num_max = 48000, - .num_step = 1, - .den = 1, -}; - -static struct line6_pcm_properties podhd_pcm_properties = { - .snd_line6_playback_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | -#ifdef CONFIG_PM - SNDRV_PCM_INFO_RESUME | -#endif - SNDRV_PCM_INFO_SYNC_START), - .formats = SNDRV_PCM_FMTBIT_S24_3LE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 60000, - .period_bytes_min = 64, - .period_bytes_max = 8192, - .periods_min = 1, - .periods_max = 1024}, - .snd_line6_capture_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | -#ifdef CONFIG_PM - SNDRV_PCM_INFO_RESUME | -#endif - SNDRV_PCM_INFO_SYNC_START), - .formats = SNDRV_PCM_FMTBIT_S24_3LE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 60000, - .period_bytes_min = 64, - .period_bytes_max = 8192, - .periods_min = 1, - .periods_max = 1024}, - .snd_line6_rates = { - .nrats = 1, - .rats = &podhd_ratden}, - .bytes_per_frame = PODHD_BYTES_PER_FRAME -}; - -/* - POD HD destructor. -*/ -static void podhd_destruct(struct usb_interface *interface) -{ - struct usb_line6_podhd *podhd = usb_get_intfdata(interface); - - if (podhd == NULL) - return; - line6_cleanup_audio(&podhd->line6); -} - -/* - Try to init POD HD device. -*/ -static int podhd_try_init(struct usb_interface *interface, - struct usb_line6_podhd *podhd) -{ - int err; - struct usb_line6 *line6 = &podhd->line6; - - if ((interface == NULL) || (podhd == NULL)) - return -ENODEV; - - /* initialize audio system: */ - err = line6_init_audio(line6); - if (err < 0) - return err; - - /* initialize MIDI subsystem: */ - err = line6_init_midi(line6); - if (err < 0) - return err; - - /* initialize PCM subsystem: */ - err = line6_init_pcm(line6, &podhd_pcm_properties); - if (err < 0) - return err; - - /* register USB audio system: */ - err = line6_register_audio(line6); - return err; -} - -/* - Init POD HD device (and clean up in case of failure). -*/ -int line6_podhd_init(struct usb_interface *interface, - struct usb_line6_podhd *podhd) -{ - int err = podhd_try_init(interface, podhd); - - if (err < 0) - podhd_destruct(interface); - - return err; -} - -/* - POD HD device disconnected. -*/ -void line6_podhd_disconnect(struct usb_interface *interface) -{ - struct usb_line6_podhd *podhd; - - if (interface == NULL) - return; - podhd = usb_get_intfdata(interface); - - if (podhd != NULL) { - struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm; - - if (line6pcm != NULL) - line6_pcm_disconnect(line6pcm); - } - - podhd_destruct(interface); -} diff --git a/drivers/staging/line6/podhd.h b/drivers/staging/line6/podhd.h deleted file mode 100644 index 652f74056bb9..000000000000 --- a/drivers/staging/line6/podhd.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Line6 Pod HD - * - * Copyright (C) 2011 Stefan Hajnoczi - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef PODHD_H -#define PODHD_H - -#include - -#include "driver.h" - -struct usb_line6_podhd { - /** - Generic Line6 USB data. - */ - struct usb_line6 line6; -}; - -extern void line6_podhd_disconnect(struct usb_interface *interface); -extern int line6_podhd_init(struct usb_interface *interface, - struct usb_line6_podhd *podhd); - -#endif /* PODHD_H */ diff --git a/drivers/staging/line6/revision.h b/drivers/staging/line6/revision.h deleted file mode 100644 index b4eee2b73831..000000000000 --- a/drivers/staging/line6/revision.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef DRIVER_REVISION -/* current subversion revision */ -#define DRIVER_REVISION " (904)" -#endif diff --git a/drivers/staging/line6/toneport.h b/drivers/staging/line6/toneport.h deleted file mode 100644 index 8576b7263648..000000000000 --- a/drivers/staging/line6/toneport.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef TONEPORT_H -#define TONEPORT_H - -#include -#include - -#include "driver.h" - -struct usb_line6_toneport { - /** - Generic Line6 USB data. - */ - struct usb_line6 line6; - - /** - Source selector. - */ - int source; - - /** - Serial number of device. - */ - int serial_number; - - /** - Firmware version (x 100). - */ - int firmware_version; - - /** - Timer for delayed PCM startup. - */ - struct timer_list timer; -}; - -extern void line6_toneport_disconnect(struct usb_interface *interface); -extern int line6_toneport_init(struct usb_interface *interface, - struct usb_line6_toneport *toneport); -extern void line6_toneport_reset_resume(struct usb_line6_toneport *toneport); - -#endif diff --git a/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h deleted file mode 100644 index 2d1cc472bead..000000000000 --- a/drivers/staging/line6/usbdefs.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2005-2008 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef USBDEFS_H -#define USBDEFS_H - -#define LINE6_VENDOR_ID 0x0e41 - -#define USB_INTERVALS_PER_SECOND 1000 - -/* - Device ids. -*/ -#define LINE6_DEVID_BASSPODXT 0x4250 -#define LINE6_DEVID_BASSPODXTLIVE 0x4642 -#define LINE6_DEVID_BASSPODXTPRO 0x4252 -#define LINE6_DEVID_GUITARPORT 0x4750 -#define LINE6_DEVID_POCKETPOD 0x5051 -#define LINE6_DEVID_PODHD300 0x5057 -#define LINE6_DEVID_PODHD400 0x5058 -#define LINE6_DEVID_PODHD500 0x414D -#define LINE6_DEVID_PODSTUDIO_GX 0x4153 -#define LINE6_DEVID_PODSTUDIO_UX1 0x4150 -#define LINE6_DEVID_PODSTUDIO_UX2 0x4151 -#define LINE6_DEVID_PODX3 0x414a -#define LINE6_DEVID_PODX3LIVE 0x414b -#define LINE6_DEVID_PODXT 0x5044 -#define LINE6_DEVID_PODXTLIVE 0x4650 -#define LINE6_DEVID_PODXTPRO 0x5050 -#define LINE6_DEVID_TONEPORT_GX 0x4147 -#define LINE6_DEVID_TONEPORT_UX1 0x4141 -#define LINE6_DEVID_TONEPORT_UX2 0x4142 -#define LINE6_DEVID_VARIAX 0x534d - -#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x - -enum { - LINE6_INDEX_BASSPODXT, - LINE6_INDEX_BASSPODXTLIVE, - LINE6_INDEX_BASSPODXTPRO, - LINE6_INDEX_GUITARPORT, - LINE6_INDEX_POCKETPOD, - LINE6_INDEX_PODHD300, - LINE6_INDEX_PODHD400, - LINE6_INDEX_PODHD500, - LINE6_INDEX_PODSTUDIO_GX, - LINE6_INDEX_PODSTUDIO_UX1, - LINE6_INDEX_PODSTUDIO_UX2, - LINE6_INDEX_PODX3, - LINE6_INDEX_PODX3LIVE, - LINE6_INDEX_PODXT, - LINE6_INDEX_PODXTLIVE, - LINE6_INDEX_PODXTPRO, - LINE6_INDEX_TONEPORT_GX, - LINE6_INDEX_TONEPORT_UX1, - LINE6_INDEX_TONEPORT_UX2, - LINE6_INDEX_VARIAX, - - LINE6_BIT(BASSPODXT), - LINE6_BIT(BASSPODXTLIVE), - LINE6_BIT(BASSPODXTPRO), - LINE6_BIT(GUITARPORT), - LINE6_BIT(POCKETPOD), - LINE6_BIT(PODHD300), - LINE6_BIT(PODHD400), - LINE6_BIT(PODHD500), - LINE6_BIT(PODSTUDIO_GX), - LINE6_BIT(PODSTUDIO_UX1), - LINE6_BIT(PODSTUDIO_UX2), - LINE6_BIT(PODX3), - LINE6_BIT(PODX3LIVE), - LINE6_BIT(PODXT), - LINE6_BIT(PODXTLIVE), - LINE6_BIT(PODXTPRO), - LINE6_BIT(TONEPORT_GX), - LINE6_BIT(TONEPORT_UX1), - LINE6_BIT(TONEPORT_UX2), - LINE6_BIT(VARIAX), - - LINE6_BITS_PRO = LINE6_BIT_BASSPODXTPRO | LINE6_BIT_PODXTPRO, - LINE6_BITS_LIVE = LINE6_BIT_BASSPODXTLIVE | LINE6_BIT_PODXTLIVE | - LINE6_BIT_PODX3LIVE, - LINE6_BITS_PODXTALL = LINE6_BIT_PODXT | LINE6_BIT_PODXTLIVE | - LINE6_BIT_PODXTPRO, - LINE6_BITS_PODX3ALL = LINE6_BIT_PODX3 | LINE6_BIT_PODX3LIVE, - LINE6_BITS_PODHDALL = LINE6_BIT_PODHD300 | - LINE6_BIT_PODHD400 | - LINE6_BIT_PODHD500, - LINE6_BITS_BASSPODXTALL = LINE6_BIT_BASSPODXT | - LINE6_BIT_BASSPODXTLIVE | - LINE6_BIT_BASSPODXTPRO -}; - -/* device supports settings parameter via USB */ -#define LINE6_BIT_CONTROL (1 << 0) -/* device supports PCM input/output via USB */ -#define LINE6_BIT_PCM (1 << 1) -/* device support hardware monitoring */ -#define LINE6_BIT_HWMON (1 << 2) - -#define LINE6_BIT_CTRL_PCM_HW (LINE6_BIT_CONTROL | \ - LINE6_BIT_PCM | \ - LINE6_BIT_HWMON) - -#define LINE6_FALLBACK_INTERVAL 10 -#define LINE6_FALLBACK_MAXPACKETSIZE 16 - -#endif diff --git a/drivers/staging/line6/variax.h b/drivers/staging/line6/variax.h deleted file mode 100644 index 24de79620d89..000000000000 --- a/drivers/staging/line6/variax.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Line6 Linux USB driver - 0.9.1beta - * - * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#ifndef VARIAX_H -#define VARIAX_H - -#include -#include -#include -#include - -#include "driver.h" - -#define VARIAX_STARTUP_DELAY1 1000 -#define VARIAX_STARTUP_DELAY3 100 -#define VARIAX_STARTUP_DELAY4 100 - -/* - Stages of Variax startup procedure -*/ -enum { - VARIAX_STARTUP_INIT = 1, - VARIAX_STARTUP_VERSIONREQ, - VARIAX_STARTUP_WAIT, - VARIAX_STARTUP_ACTIVATE, - VARIAX_STARTUP_WORKQUEUE, - VARIAX_STARTUP_SETUP, - VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1 -}; - -struct usb_line6_variax { - /** - Generic Line6 USB data. - */ - struct usb_line6 line6; - - /** - Buffer for activation code. - */ - unsigned char *buffer_activate; - - /** - Handler for device initializaton. - */ - struct work_struct startup_work; - - /** - Timers for device initializaton. - */ - struct timer_list startup_timer1; - struct timer_list startup_timer2; - - /** - Current progress in startup procedure. - */ - int startup_progress; -}; - -extern void line6_variax_disconnect(struct usb_interface *interface); -extern int line6_variax_init(struct usb_interface *interface, - struct usb_line6_variax *variax); -extern void line6_variax_process_message(struct usb_line6_variax *variax); - -#endif diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index a3367bfb1456..45aaa1cc56bc 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -987,7 +987,7 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt) if (err) goto out_free; lsi->lsi_flags |= LSI_BDI_INITIALIZED; - lsi->lsi_bdi.capabilities = BDI_CAP_MAP_COPY; + lsi->lsi_bdi.capabilities = 0; err = ll_bdi_register(&lsi->lsi_bdi); if (err) goto out_free; @@ -1812,10 +1812,6 @@ void ll_read_inode2(struct inode *inode, void *opaque) /* OIDEBUG(inode); */ - /* initializing backing dev info. */ - inode->i_mapping->backing_dev_info = &s2lsi(inode->i_sb)->lsi_bdi; - - if (S_ISREG(inode->i_mode)) { struct ll_sb_info *sbi = ll_i2sbi(inode); diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c index 930f6010203e..65d610abe06e 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_io.c +++ b/drivers/staging/lustre/lustre/llite/vvp_io.c @@ -632,7 +632,7 @@ static int vvp_io_kernel_fault(struct vvp_fault_io *cfio) return 0; } - if (cfio->fault.ft_flags & VM_FAULT_SIGBUS) { + if (cfio->fault.ft_flags & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV)) { CDEBUG(D_PAGE, "got addr %p - SIGBUS\n", vmf->virtual_address); return -EFAULT; } diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 2a054a99d433..96498b7fc20e 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -27,18 +27,12 @@ source "drivers/staging/media/davinci_vpfe/Kconfig" source "drivers/staging/media/dt3155v4l/Kconfig" -source "drivers/staging/media/tlg2300/Kconfig" - source "drivers/staging/media/mn88472/Kconfig" source "drivers/staging/media/mn88473/Kconfig" source "drivers/staging/media/omap4iss/Kconfig" -source "drivers/staging/media/parport/Kconfig" - -source "drivers/staging/media/vino/Kconfig" - # Keep LIRC at the end, as it has sub-menus source "drivers/staging/media/lirc/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 412b28408398..a9006bcb4472 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -6,7 +6,3 @@ obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_DVB_MN88472) += mn88472/ obj-$(CONFIG_DVB_MN88473) += mn88473/ -obj-y += parport/ -obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/ -obj-y += vino/ - diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index 60a57b2a8fb2..538250667918 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c @@ -2684,9 +2684,7 @@ static int __exit bcm2048_i2c_driver_remove(struct i2c_client *client) vd = bdev->videodev; bcm2048_sysfs_unregister_properties(bdev, ARRAY_SIZE(attrs)); - - if (vd) - video_unregister_device(vd); + video_unregister_device(vd); if (bdev->power_state) bcm2048_set_power_state(bdev, BCM2048_POWER_OFF); @@ -2699,8 +2697,6 @@ static int __exit bcm2048_i2c_driver_remove(struct i2c_client *client) kfree(bdev); } - i2c_set_clientdata(client, NULL); - return 0; } diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c index 0ba0bf2c1cff..bcf762bc233d 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_isif.c +++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c @@ -1535,7 +1535,7 @@ isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, } /* - * isif_pad_set_crop() - set crop rectangle on pad + * isif_pad_set_selection() - set crop rectangle on pad * @sd: VPFE isif V4L2 subdevice * @fh: V4L2 subdev file handle * @code: pointer to v4l2_subdev_mbus_code_enum structure @@ -1543,35 +1543,36 @@ isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, * Return 0 on success, -EINVAL if pad is invalid */ static int -isif_pad_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +isif_pad_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - /* check wether its a valid pad */ - if (crop->pad != ISIF_PAD_SINK) + /* check whether it's a valid pad and target */ + if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - format = __isif_get_format(vpfe_isif, fh, crop->pad, crop->which); + format = __isif_get_format(vpfe_isif, fh, sel->pad, sel->which); if (format == NULL) return -EINVAL; /* check wether crop rect is within limits */ - if (crop->rect.top < 0 || crop->rect.left < 0 || - (crop->rect.left + crop->rect.width > + if (sel->r.top < 0 || sel->r.left < 0 || + (sel->r.left + sel->r.width > vpfe_isif->formats[ISIF_PAD_SINK].width) || - (crop->rect.top + crop->rect.height > + (sel->r.top + sel->r.height > vpfe_isif->formats[ISIF_PAD_SINK].height)) { - crop->rect.left = 0; - crop->rect.top = 0; - crop->rect.width = format->width; - crop->rect.height = format->height; + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = format->width; + sel->r.height = format->height; } /* adjust the width to 16 pixel boundary */ - crop->rect.width = ((crop->rect.width + 15) & ~0xf); - vpfe_isif->crop = crop->rect; - if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + sel->r.width = ((sel->r.width + 15) & ~0xf); + vpfe_isif->crop = sel->r; + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { isif_set_image_window(vpfe_isif); } else { struct v4l2_rect *rect; @@ -1583,7 +1584,7 @@ isif_pad_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, } /* - * isif_pad_get_crop() - get crop rectangle on pad + * isif_pad_get_selection() - get crop rectangle on pad * @sd: VPFE isif V4L2 subdevice * @fh: V4L2 subdev file handle * @code: pointer to v4l2_subdev_mbus_code_enum structure @@ -1591,22 +1592,23 @@ isif_pad_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, * Return 0 on success, -EINVAL if pad is invalid */ static int -isif_pad_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_crop *crop) +isif_pad_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) { struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); - /* check wether its a valid pad */ - if (crop->pad != ISIF_PAD_SINK) + /* check whether it's a valid pad and target */ + if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - if (crop->which == V4L2_SUBDEV_FORMAT_TRY) { + if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_rect *rect; rect = v4l2_subdev_get_try_crop(fh, ISIF_PAD_SINK); - memcpy(&crop->rect, rect, sizeof(*rect)); + memcpy(&sel->r, rect, sizeof(*rect)); } else { - crop->rect = vpfe_isif->crop; + sel->r = vpfe_isif->crop; } return 0; @@ -1626,7 +1628,7 @@ isif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_subdev_format format; - struct v4l2_subdev_crop crop; + struct v4l2_subdev_selection sel; memset(&format, 0, sizeof(format)); format.pad = ISIF_PAD_SINK; @@ -1644,12 +1646,13 @@ isif_init_formats(struct v4l2_subdev *sd, format.format.height = MAX_HEIGHT; isif_set_format(sd, fh, &format); - memset(&crop, 0, sizeof(crop)); - crop.pad = ISIF_PAD_SINK; - crop.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - crop.rect.width = MAX_WIDTH; - crop.rect.height = MAX_HEIGHT; - isif_pad_set_crop(sd, fh, &crop); + memset(&sel, 0, sizeof(sel)); + sel.pad = ISIF_PAD_SINK; + sel.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + sel.target = V4L2_SEL_TGT_CROP; + sel.r.width = MAX_WIDTH; + sel.r.height = MAX_HEIGHT; + isif_pad_set_selection(sd, fh, &sel); return 0; } @@ -1675,8 +1678,8 @@ static const struct v4l2_subdev_pad_ops isif_v4l2_pad_ops = { .enum_frame_size = isif_enum_frame_size, .get_fmt = isif_get_format, .set_fmt = isif_set_format, - .set_crop = isif_pad_set_crop, - .get_crop = isif_pad_get_crop, + .set_selection = isif_pad_set_selection, + .get_selection = isif_pad_get_selection, }; /* subdev operations */ diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c index eb4ccb8d2a93..19628d0104ab 100644 --- a/drivers/staging/media/lirc/lirc_serial.c +++ b/drivers/staging/media/lirc/lirc_serial.c @@ -107,7 +107,7 @@ static int io; static int irq; static bool iommap; static int ioshift; -static bool softcarrier = 1; +static bool softcarrier = true; static bool share_irq; static bool debug; static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ @@ -266,7 +266,7 @@ static unsigned long space_width; /* fetch serial input packet (1 byte) from register offset */ static u8 sinp(int offset) { - if (iommap != 0) + if (iommap) /* the register is memory-mapped */ offset <<= ioshift; @@ -276,7 +276,7 @@ static u8 sinp(int offset) /* write serial output packet (1 byte) of value to register offset */ static void soutp(int offset, u8 value) { - if (iommap != 0) + if (iommap) /* the register is memory-mapped */ offset <<= ioshift; @@ -799,10 +799,10 @@ static int lirc_serial_probe(struct platform_device *dev) * For memory mapped I/O you *might* need to use ioremap() first, * for the NSLU2 it's done in boot code. */ - if (((iommap != 0) + if (((iommap) && (devm_request_mem_region(&dev->dev, iommap, 8 << ioshift, LIRC_DRIVER_NAME) == NULL)) - || ((iommap == 0) + || ((!iommap) && (devm_request_region(&dev->dev, io, 8, LIRC_DRIVER_NAME) == NULL))) { dev_err(&dev->dev, "port %04x already in use\n", io); diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index cc872fb4ca68..e16627ca488e 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -369,17 +369,17 @@ static int add_to_buf(struct IR *ir) ret = i2c_master_send(rx->c, sendbuf, 1); if (ret != 1) { dev_err(ir->l.dev, "i2c_master_send failed with %d\n", - ret); + ret); if (failures >= 3) { mutex_unlock(&ir->ir_lock); - dev_err(ir->l.dev, "unable to read from the IR chip " - "after 3 resets, giving up\n"); + dev_err(ir->l.dev, + "unable to read from the IR chip after 3 resets, giving up\n"); break; } /* Looks like the chip crashed, reset it */ - dev_err(ir->l.dev, "polling the IR receiver chip failed, " - "trying reset\n"); + dev_err(ir->l.dev, + "polling the IR receiver chip failed, trying reset\n"); set_current_state(TASK_UNINTERRUPTIBLE); if (kthread_should_stop()) { @@ -405,14 +405,16 @@ static int add_to_buf(struct IR *ir) ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf)); mutex_unlock(&ir->ir_lock); if (ret != sizeof(keybuf)) { - dev_err(ir->l.dev, "i2c_master_recv failed with %d -- " - "keeping last read buffer\n", ret); + dev_err(ir->l.dev, + "i2c_master_recv failed with %d -- keeping last read buffer\n", + ret); } else { rx->b[0] = keybuf[3]; rx->b[1] = keybuf[4]; rx->b[2] = keybuf[5]; - dev_dbg(ir->l.dev, "key (0x%02x/0x%02x)\n", - rx->b[0], rx->b[1]); + dev_dbg(ir->l.dev, + "key (0x%02x/0x%02x)\n", + rx->b[0], rx->b[1]); } /* key pressed ? */ @@ -656,8 +658,8 @@ static int send_data_block(struct IR_tx *tx, unsigned char *data_block) dev_dbg(tx->ir->l.dev, "%*ph", 5, buf); ret = i2c_master_send(tx->c, buf, tosend + 1); if (ret != tosend + 1) { - dev_err(tx->ir->l.dev, "i2c_master_send failed with %d\n", - ret); + dev_err(tx->ir->l.dev, + "i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } i += tosend; @@ -710,11 +712,12 @@ static int send_boot_data(struct IR_tx *tx) } if ((buf[0] != 0x80) && (buf[0] != 0xa0)) { dev_err(tx->ir->l.dev, "unexpected IR TX init response: %02x\n", - buf[0]); + buf[0]); return 0; } - dev_notice(tx->ir->l.dev, "Zilog/Hauppauge IR blaster firmware version " - "%d.%d.%d loaded\n", buf[1], buf[2], buf[3]); + dev_notice(tx->ir->l.dev, + "Zilog/Hauppauge IR blaster firmware version %d.%d.%d loaded\n", + buf[1], buf[2], buf[3]); return 0; } @@ -759,8 +762,9 @@ static int fw_load(struct IR_tx *tx) /* Request codeset data file */ ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", tx->ir->l.dev); if (ret != 0) { - dev_err(tx->ir->l.dev, "firmware haup-ir-blaster.bin not available (%d)\n", - ret); + dev_err(tx->ir->l.dev, + "firmware haup-ir-blaster.bin not available (%d)\n", + ret); ret = ret < 0 ? ret : -EFAULT; goto out; } @@ -792,9 +796,9 @@ static int fw_load(struct IR_tx *tx) if (!read_uint8(&data, tx_data->endp, &version)) goto corrupt; if (version != 1) { - dev_err(tx->ir->l.dev, "unsupported code set file version (%u, expected" - "1) -- please upgrade to a newer driver", - version); + dev_err(tx->ir->l.dev, + "unsupported code set file version (%u, expected 1) -- please upgrade to a newer driver\n", + version); fw_unload_locked(); ret = -EFAULT; goto out; @@ -810,7 +814,7 @@ static int fw_load(struct IR_tx *tx) goto corrupt; dev_dbg(tx->ir->l.dev, "%u IR blaster codesets loaded\n", - tx_data->num_code_sets); + tx_data->num_code_sets); tx_data->code_sets = vmalloc( tx_data->num_code_sets * sizeof(char *)); @@ -940,8 +944,9 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n, unsigned char buf[MAX_XFER_SIZE]; if (rbuf->chunk_size > sizeof(buf)) { - dev_err(ir->l.dev, "chunk_size is too big (%d)!\n", - rbuf->chunk_size); + dev_err(ir->l.dev, + "chunk_size is too big (%d)!\n", + rbuf->chunk_size); ret = -EINVAL; break; } @@ -964,8 +969,8 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n, put_ir_rx(rx, false); set_current_state(TASK_RUNNING); - dev_dbg(ir->l.dev, "read result = %d (%s)\n", - ret, ret ? "Error" : "OK"); + dev_dbg(ir->l.dev, "read result = %d (%s)\n", ret, + ret ? "Error" : "OK"); return ret ? ret : written; } @@ -981,8 +986,9 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) ret = get_key_data(data_block, code, key); if (ret == -EPROTO) { - dev_err(tx->ir->l.dev, "failed to get data for code %u, key %u -- check " - "lircd.conf entries\n", code, key); + dev_err(tx->ir->l.dev, + "failed to get data for code %u, key %u -- check lircd.conf entries\n", + code, key); return ret; } else if (ret != 0) return ret; @@ -1057,12 +1063,14 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) ret = i2c_master_send(tx->c, buf, 1); if (ret == 1) break; - dev_dbg(tx->ir->l.dev, "NAK expected: i2c_master_send " - "failed with %d (try %d)\n", ret, i+1); + dev_dbg(tx->ir->l.dev, + "NAK expected: i2c_master_send failed with %d (try %d)\n", + ret, i+1); } if (ret != 1) { - dev_err(tx->ir->l.dev, "IR TX chip never got ready: last i2c_master_send " - "failed with %d\n", ret); + dev_err(tx->ir->l.dev, + "IR TX chip never got ready: last i2c_master_send failed with %d\n", + ret); return ret < 0 ? ret : -EFAULT; } @@ -1074,7 +1082,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) } if (buf[0] != 0x80) { dev_err(tx->ir->l.dev, "unexpected IR TX response #2: %02x\n", - buf[0]); + buf[0]); return -EFAULT; } @@ -1165,12 +1173,12 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n, */ if (ret != 0) { /* Looks like the chip crashed, reset it */ - dev_err(tx->ir->l.dev, "sending to the IR transmitter chip " - "failed, trying reset\n"); + dev_err(tx->ir->l.dev, + "sending to the IR transmitter chip failed, trying reset\n"); if (failures >= 3) { - dev_err(tx->ir->l.dev, "unable to send to the IR chip " - "after 3 resets, giving up\n"); + dev_err(tx->ir->l.dev, + "unable to send to the IR chip after 3 resets, giving up\n"); mutex_unlock(&ir->ir_lock); mutex_unlock(&tx->client_lock); put_ir_tx(tx, false); @@ -1226,7 +1234,7 @@ static unsigned int poll(struct file *filep, poll_table *wait) ret = lirc_buffer_empty(rbuf) ? 0 : (POLLIN|POLLRDNORM); dev_dbg(ir->l.dev, "poll result = %s\n", - ret ? "POLLIN|POLLRDNORM" : "none"); + ret ? "POLLIN|POLLRDNORM" : "none"); return ret; } @@ -1333,7 +1341,8 @@ static int close(struct inode *node, struct file *filep) struct IR *ir = filep->private_data; if (ir == NULL) { - dev_err(ir->l.dev, "close: no private_data attached to the file!\n"); + dev_err(ir->l.dev, + "close: no private_data attached to the file!\n"); return -ENODEV; } @@ -1540,8 +1549,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) /* Proceed only if the Rx client is also ready or not needed */ if (rx == NULL && !tx_only) { - dev_info(tx->ir->l.dev, "probe of IR Tx on %s (i2c-%d) done. Waiting" - " on IR Rx.\n", adap->name, adap->nr); + dev_info(tx->ir->l.dev, + "probe of IR Tx on %s (i2c-%d) done. Waiting on IR Rx.\n", + adap->name, adap->nr); goto out_ok; } } else { @@ -1579,8 +1589,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) "zilog-rx-i2c-%d", adap->nr); if (IS_ERR(rx->task)) { ret = PTR_ERR(rx->task); - dev_err(tx->ir->l.dev, "%s: could not start IR Rx polling thread" - "\n", __func__); + dev_err(tx->ir->l.dev, + "%s: could not start IR Rx polling thread\n", + __func__); /* Failed kthread, so put back the ir ref */ put_ir_device(ir, true); /* Failure exit, so put back rx ref from i2c_client */ @@ -1592,8 +1603,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) /* Proceed only if the Tx client is also ready */ if (tx == NULL) { - pr_info("probe of IR Rx on %s (i2c-%d) done. Waiting" - " on IR Tx.\n", adap->name, adap->nr); + pr_info("probe of IR Rx on %s (i2c-%d) done. Waiting on IR Tx.\n", + adap->name, adap->nr); goto out_ok; } } @@ -1602,13 +1613,15 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir->l.minor = minor; /* module option: user requested minor number */ ir->l.minor = lirc_register_driver(&ir->l); if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) { - dev_err(tx->ir->l.dev, "%s: \"minor\" must be between 0 and %d (%d)!\n", - __func__, MAX_IRCTL_DEVICES-1, ir->l.minor); + dev_err(tx->ir->l.dev, + "%s: \"minor\" must be between 0 and %d (%d)!\n", + __func__, MAX_IRCTL_DEVICES-1, ir->l.minor); ret = -EBADRQC; goto out_put_xx; } - dev_info(ir->l.dev, "IR unit on %s (i2c-%d) registered as lirc%d and ready\n", - adap->name, adap->nr, ir->l.minor); + dev_info(ir->l.dev, + "IR unit on %s (i2c-%d) registered as lirc%d and ready\n", + adap->name, adap->nr, ir->l.minor); out_ok: if (rx != NULL) @@ -1616,8 +1629,9 @@ out_ok: if (tx != NULL) put_ir_tx(tx, true); put_ir_device(ir, true); - dev_info(ir->l.dev, "probe of IR %s on %s (i2c-%d) done\n", - tx_probe ? "Tx" : "Rx", adap->name, adap->nr); + dev_info(ir->l.dev, + "probe of IR %s on %s (i2c-%d) done\n", + tx_probe ? "Tx" : "Rx", adap->name, adap->nr); mutex_unlock(&ir_devices_lock); return 0; @@ -1629,9 +1643,9 @@ out_put_xx: out_put_ir: put_ir_device(ir, true); out_no_ir: - dev_err(&client->dev, "%s: probing IR %s on %s (i2c-%d) failed with %d\n", - __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr, - ret); + dev_err(&client->dev, + "%s: probing IR %s on %s (i2c-%d) failed with %d\n", + __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr, ret); mutex_unlock(&ir_devices_lock); return ret; } diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/staging/media/mn88472/mn88472.c index 52de8f85d36c..6eebe564e557 100644 --- a/drivers/staging/media/mn88472/mn88472.c +++ b/drivers/staging/media/mn88472/mn88472.c @@ -30,6 +30,7 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; u32 if_frequency = 0; + u64 tmp; u8 delivery_system_val, if_val[3], bw_val[7], bw_val2; dev_dbg(&client->dev, @@ -57,36 +58,22 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) goto err; } - switch (c->delivery_system) { - case SYS_DVBT: - case SYS_DVBT2: - if (c->bandwidth_hz <= 6000000) { - /* IF 3570000 Hz, BW 6000000 Hz */ - memcpy(if_val, "\x2c\x94\xdb", 3); - memcpy(bw_val, "\xbf\x55\x55\x15\x6b\x15\x6b", 7); - bw_val2 = 0x02; - } else if (c->bandwidth_hz <= 7000000) { - /* IF 4570000 Hz, BW 7000000 Hz */ - memcpy(if_val, "\x39\x11\xbc", 3); - memcpy(bw_val, "\xa4\x00\x00\x0f\x2c\x0f\x2c", 7); - bw_val2 = 0x01; - } else if (c->bandwidth_hz <= 8000000) { - /* IF 4570000 Hz, BW 8000000 Hz */ - memcpy(if_val, "\x39\x11\xbc", 3); - memcpy(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7); - bw_val2 = 0x00; - } else { - ret = -EINVAL; - goto err; - } - break; - case SYS_DVBC_ANNEX_A: - /* IF 5070000 Hz, BW 8000000 Hz */ - memcpy(if_val, "\x3f\x50\x2c", 3); + if (c->bandwidth_hz <= 5000000) { + memcpy(bw_val, "\xe5\x99\x9a\x1b\xa9\x1b\xa9", 7); + bw_val2 = 0x03; + } else if (c->bandwidth_hz <= 6000000) { + /* IF 3570000 Hz, BW 6000000 Hz */ + memcpy(bw_val, "\xbf\x55\x55\x15\x6b\x15\x6b", 7); + bw_val2 = 0x02; + } else if (c->bandwidth_hz <= 7000000) { + /* IF 4570000 Hz, BW 7000000 Hz */ + memcpy(bw_val, "\xa4\x00\x00\x0f\x2c\x0f\x2c", 7); + bw_val2 = 0x01; + } else if (c->bandwidth_hz <= 8000000) { + /* IF 4570000 Hz, BW 8000000 Hz */ memcpy(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7); bw_val2 = 0x00; - break; - default: + } else { ret = -EINVAL; goto err; } @@ -106,17 +93,12 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency); } - switch (if_frequency) { - case 3570000: - case 4570000: - case 5070000: - break; - default: - dev_err(&client->dev, "IF frequency %d not supported\n", - if_frequency); - ret = -EINVAL; - goto err; - } + /* Calculate IF registers ( (1<<24)*IF / Xtal ) */ + tmp = div_u64(if_frequency * (u64)(1<<24) + (dev->xtal / 2), + dev->xtal); + if_val[0] = ((tmp >> 16) & 0xff); + if_val[1] = ((tmp >> 8) & 0xff); + if_val[2] = ((tmp >> 0) & 0xff); ret = regmap_write(dev->regmap[2], 0xfb, 0x13); ret = regmap_write(dev->regmap[2], 0xef, 0x13); @@ -198,6 +180,8 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) ret = regmap_write(dev->regmap[0], 0xae, 0x00); ret = regmap_write(dev->regmap[2], 0x08, 0x1d); ret = regmap_write(dev->regmap[0], 0xd9, 0xe3); + + /* Reset demod */ ret = regmap_write(dev->regmap[2], 0xf8, 0x9f); if (ret) goto err; @@ -411,6 +395,7 @@ static int mn88472_probe(struct i2c_client *client, } dev->i2c_wr_max = config->i2c_wr_max; + dev->xtal = config->xtal; dev->client[0] = client; dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); if (IS_ERR(dev->regmap[0])) { diff --git a/drivers/staging/media/mn88472/mn88472_priv.h b/drivers/staging/media/mn88472/mn88472_priv.h index 1095949f040d..b12b731e2d4e 100644 --- a/drivers/staging/media/mn88472/mn88472_priv.h +++ b/drivers/staging/media/mn88472/mn88472_priv.h @@ -31,6 +31,7 @@ struct mn88472_dev { u16 i2c_wr_max; fe_delivery_system_t delivery_system; bool warm; /* FW running */ + u32 xtal; }; #endif diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c index cc1dfadd91eb..44b81a2c8b6f 100644 --- a/drivers/staging/media/omap4iss/iss.c +++ b/drivers/staging/media/omap4iss/iss.c @@ -559,6 +559,61 @@ static int iss_pipeline_link_notify(struct media_link *link, u32 flags, * Pipeline stream management */ +/* + * iss_pipeline_disable - Disable streaming on a pipeline + * @pipe: ISS pipeline + * @until: entity at which to stop pipeline walk + * + * Walk the entities chain starting at the pipeline output video node and stop + * all modules in the chain. Wait synchronously for the modules to be stopped if + * necessary. + * + * If the until argument isn't NULL, stop the pipeline walk when reaching the + * until entity. This is used to disable a partially started pipeline due to a + * subdev start error. + */ +static int iss_pipeline_disable(struct iss_pipeline *pipe, + struct media_entity *until) +{ + struct iss_device *iss = pipe->output->iss; + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + int failure = 0; + int ret; + + entity = &pipe->output->video.entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + entity = pad->entity; + if (entity == until) + break; + + subdev = media_entity_to_v4l2_subdev(entity); + ret = v4l2_subdev_call(subdev, video, s_stream, 0); + if (ret < 0) { + dev_dbg(iss->dev, "%s: module stop timeout.\n", + subdev->name); + /* If the entity failed to stopped, assume it has + * crashed. Mark it as such, the ISS will be reset when + * applications will release it. + */ + iss->crashed |= 1U << subdev->entity.id; + failure = -ETIMEDOUT; + } + } + + return failure; +} + /* * iss_pipeline_enable - Enable streaming on a pipeline * @pipe: ISS pipeline @@ -610,60 +665,20 @@ static int iss_pipeline_enable(struct iss_pipeline *pipe, subdev = media_entity_to_v4l2_subdev(entity); ret = v4l2_subdev_call(subdev, video, s_stream, mode); - if (ret < 0 && ret != -ENOIOCTLCMD) + if (ret < 0 && ret != -ENOIOCTLCMD) { + iss_pipeline_disable(pipe, entity); return ret; + } + + if (subdev == &iss->csi2a.subdev || + subdev == &iss->csi2b.subdev) + pipe->do_propagation = true; } + iss_print_status(pipe->output->iss); return 0; } -/* - * iss_pipeline_disable - Disable streaming on a pipeline - * @pipe: ISS pipeline - * - * Walk the entities chain starting at the pipeline output video node and stop - * all modules in the chain. Wait synchronously for the modules to be stopped if - * necessary. - */ -static int iss_pipeline_disable(struct iss_pipeline *pipe) -{ - struct iss_device *iss = pipe->output->iss; - struct media_entity *entity; - struct media_pad *pad; - struct v4l2_subdev *subdev; - int failure = 0; - int ret; - - entity = &pipe->output->video.entity; - while (1) { - pad = &entity->pads[0]; - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - break; - - pad = media_entity_remote_pad(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - break; - - entity = pad->entity; - subdev = media_entity_to_v4l2_subdev(entity); - - ret = v4l2_subdev_call(subdev, video, s_stream, 0); - if (ret < 0) { - dev_dbg(iss->dev, "%s: module stop timeout.\n", - subdev->name); - /* If the entity failed to stopped, assume it has - * crashed. Mark it as such, the ISS will be reset when - * applications will release it. - */ - iss->crashed |= 1U << subdev->entity.id; - failure = -ETIMEDOUT; - } - } - - return failure; -} - /* * omap4iss_pipeline_set_stream - Enable/disable streaming on a pipeline * @pipe: ISS pipeline @@ -682,7 +697,7 @@ int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe, int ret; if (state == ISS_PIPELINE_STREAM_STOPPED) - ret = iss_pipeline_disable(pipe); + ret = iss_pipeline_disable(pipe, NULL); else ret = iss_pipeline_enable(pipe, state); diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c index 21971c675b8c..2d96fb3eca53 100644 --- a/drivers/staging/media/omap4iss/iss_csi2.c +++ b/drivers/staging/media/omap4iss/iss_csi2.c @@ -319,6 +319,8 @@ static void csi2_ctx_config(struct iss_csi2_device *csi2, { u32 reg = 0; + ctx->frame = 0; + /* Set up CSI2_CTx_CTRL1 */ if (ctx->eof_enabled) reg = CSI2_CTX_CTRL1_EOF_EN; @@ -396,21 +398,18 @@ static void csi2_timing_config(struct iss_csi2_device *csi2, */ static void csi2_irq_ctx_set(struct iss_csi2_device *csi2, int enable) { - u32 reg = CSI2_CTX_IRQ_FE; + const u32 mask = CSI2_CTX_IRQ_FE | CSI2_CTX_IRQ_FS; int i; - if (csi2->use_fs_irq) - reg |= CSI2_CTX_IRQ_FS; - for (i = 0; i < 8; i++) { iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(i), - reg); + mask); if (enable) iss_reg_set(csi2->iss, csi2->regs1, - CSI2_CTX_IRQENABLE(i), reg); + CSI2_CTX_IRQENABLE(i), mask); else iss_reg_clr(csi2->iss, csi2->regs1, - CSI2_CTX_IRQENABLE(i), reg); + CSI2_CTX_IRQENABLE(i), mask); } } @@ -679,8 +678,34 @@ static void csi2_isr_ctx(struct iss_csi2_device *csi2, if (status & CSI2_CTX_IRQ_FS) { struct iss_pipeline *pipe = to_iss_pipeline(&csi2->subdev.entity); - if (pipe->do_propagation) + u16 frame; + u16 delta; + + frame = iss_reg_read(csi2->iss, csi2->regs1, + CSI2_CTX_CTRL2(ctx->ctxnum)) + >> CSI2_CTX_CTRL2_FRAME_SHIFT; + + if (frame == 0) { + /* A zero value means that the counter isn't implemented + * by the source. Increment the frame number in software + * in that case. + */ atomic_inc(&pipe->frame_number); + } else { + /* Extend the 16 bit frame number to 32 bits by + * computing the delta between two consecutive CSI2 + * frame numbers and adding it to the software frame + * number. The hardware counter starts at 1 and wraps + * from 0xffff to 1 without going through 0, so subtract + * 1 when the counter wraps. + */ + delta = frame - ctx->frame; + if (frame < ctx->frame) + delta--; + ctx->frame = frame; + + atomic_add(delta, &pipe->frame_number); + } } if (!(status & CSI2_CTX_IRQ_FE)) @@ -1039,7 +1064,6 @@ static int csi2_set_stream(struct v4l2_subdev *sd, int enable) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct iss_device *iss = csi2->iss; - struct iss_pipeline *pipe = to_iss_pipeline(&csi2->subdev.entity); struct iss_video *video_out = &csi2->video_out; int ret = 0; @@ -1058,7 +1082,6 @@ static int csi2_set_stream(struct v4l2_subdev *sd, int enable) if (omap4iss_csiphy_acquire(csi2->phy) < 0) return -ENODEV; - csi2->use_fs_irq = pipe->do_propagation; csi2_configure(csi2); csi2_print_status(csi2); diff --git a/drivers/staging/media/omap4iss/iss_csi2.h b/drivers/staging/media/omap4iss/iss_csi2.h index 971aa7b08013..3b37978a3bdf 100644 --- a/drivers/staging/media/omap4iss/iss_csi2.h +++ b/drivers/staging/media/omap4iss/iss_csi2.h @@ -82,6 +82,7 @@ struct iss_csi2_ctx_cfg { u8 virtual_id; u16 format_id; /* as in CSI2_CTx_CTRL2[9:0] */ u8 dpcm_predictor; /* 1: simple, 0: advanced */ + u16 frame; /* Fields in CSI2_CTx_CTRL1/3 - Shadowed */ u16 alpha; @@ -137,7 +138,6 @@ struct iss_csi2_device { u32 output; /* output to IPIPEIF, memory or both? */ bool dpcm_decompress; unsigned int frame_skip; - bool use_fs_irq; struct iss_csiphy *phy; struct iss_csi2_ctx_cfg contexts[ISS_CSI2_MAX_CTX_NUM + 1]; diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c index 32a748398ced..3943fae699ee 100644 --- a/drivers/staging/media/omap4iss/iss_ipipeif.c +++ b/drivers/staging/media/omap4iss/iss_ipipeif.c @@ -241,23 +241,6 @@ static void ipipeif_isr_buffer(struct iss_ipipeif_device *ipipeif) ipipeif_write_enable(ipipeif, 1); } -/* - * ipipeif_isif0_isr - Handle ISIF0 event - * @ipipeif: Pointer to ISP IPIPEIF device. - * - * Executes LSC deferred enablement before next frame starts. - */ -static void ipipeif_isif0_isr(struct iss_ipipeif_device *ipipeif) -{ - struct iss_pipeline *pipe = - to_iss_pipeline(&ipipeif->subdev.entity); - if (pipe->do_propagation) - atomic_inc(&pipe->frame_number); - - if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) - ipipeif_isr_buffer(ipipeif); -} - /* * omap4iss_ipipeif_isr - Configure ipipeif during interframe time. * @ipipeif: Pointer to ISP IPIPEIF device. @@ -269,8 +252,9 @@ void omap4iss_ipipeif_isr(struct iss_ipipeif_device *ipipeif, u32 events) &ipipeif->stopping)) return; - if (events & ISP5_IRQ_ISIF_INT(0)) - ipipeif_isif0_isr(ipipeif); + if ((events & ISP5_IRQ_ISIF_INT(0)) && + (ipipeif->output & IPIPEIF_OUTPUT_MEMORY)) + ipipeif_isr_buffer(ipipeif); } /* ----------------------------------------------------------------------------- diff --git a/drivers/staging/media/omap4iss/iss_regs.h b/drivers/staging/media/omap4iss/iss_regs.h index efd0291a86f7..d2b6b6ae9174 100644 --- a/drivers/staging/media/omap4iss/iss_regs.h +++ b/drivers/staging/media/omap4iss/iss_regs.h @@ -215,6 +215,8 @@ #define CSI2_CTX_CTRL1_CTX_EN (1 << 0) #define CSI2_CTX_CTRL2(i) (0x74 + (0x20 * i)) +#define CSI2_CTX_CTRL2_FRAME_MASK (0xffff << 16) +#define CSI2_CTX_CTRL2_FRAME_SHIFT 16 #define CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT 13 #define CSI2_CTX_CTRL2_USER_DEF_MAP_MASK \ (0x3 << CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT) diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c index 88522a8cdf56..3ab972818f1b 100644 --- a/drivers/staging/media/omap4iss/iss_resizer.c +++ b/drivers/staging/media/omap4iss/iss_resizer.c @@ -282,22 +282,6 @@ static void resizer_isr_buffer(struct iss_resizer_device *resizer) resizer_enable(resizer, 1); } -/* - * resizer_isif0_isr - Handle ISIF0 event - * @resizer: Pointer to ISP RESIZER device. - * - * Executes LSC deferred enablement before next frame starts. - */ -static void resizer_int_dma_isr(struct iss_resizer_device *resizer) -{ - struct iss_pipeline *pipe = - to_iss_pipeline(&resizer->subdev.entity); - if (pipe->do_propagation) - atomic_inc(&pipe->frame_number); - - resizer_isr_buffer(resizer); -} - /* * omap4iss_resizer_isr - Configure resizer during interframe time. * @resizer: Pointer to ISP RESIZER device. @@ -322,7 +306,7 @@ void omap4iss_resizer_isr(struct iss_resizer_device *resizer, u32 events) return; if (events & ISP5_IRQ_RSZ_INT_DMA) - resizer_int_dma_isr(resizer); + resizer_isr_buffer(resizer); } /* ----------------------------------------------------------------------------- diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index cdee5966cbca..69550445a341 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -25,9 +25,6 @@ #include "iss_video.h" #include "iss.h" -static unsigned debug; -module_param(debug, uint, 0644); -MODULE_PARM_DESC(debug, "activates debug info"); /* ----------------------------------------------------------------------------- * Helper functions @@ -772,6 +769,14 @@ iss_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) return vb2_qbuf(&vfh->queue, b); } +static int +iss_video_expbuf(struct file *file, void *fh, struct v4l2_exportbuffer *e) +{ + struct iss_video_fh *vfh = to_iss_video_fh(fh); + + return vb2_expbuf(&vfh->queue, e); +} + static int iss_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) { @@ -1021,6 +1026,7 @@ static const struct v4l2_ioctl_ops iss_video_ioctl_ops = { .vidioc_reqbufs = iss_video_reqbufs, .vidioc_querybuf = iss_video_querybuf, .vidioc_qbuf = iss_video_qbuf, + .vidioc_expbuf = iss_video_expbuf, .vidioc_dqbuf = iss_video_dqbuf, .vidioc_streamon = iss_video_streamon, .vidioc_streamoff = iss_video_streamoff, @@ -1044,8 +1050,6 @@ static int iss_video_open(struct file *file) if (handle == NULL) return -ENOMEM; - video->video.debug = debug; - v4l2_fh_init(&handle->vfh, &video->video); v4l2_fh_add(&handle->vfh); @@ -1071,7 +1075,7 @@ static int iss_video_open(struct file *file) q = &handle->queue; q->type = video->type; - q->io_modes = VB2_MMAP; + q->io_modes = VB2_MMAP | VB2_DMABUF; q->drv_priv = handle; q->ops = &iss_video_vb2ops; q->mem_ops = &vb2_dma_contig_memops; diff --git a/drivers/staging/media/parport/Kconfig b/drivers/staging/media/parport/Kconfig deleted file mode 100644 index 15974efdba1d..000000000000 --- a/drivers/staging/media/parport/Kconfig +++ /dev/null @@ -1,69 +0,0 @@ -menuconfig MEDIA_PARPORT_SUPPORT - bool "ISA and parallel port devices" - depends on (ISA || PARPORT) && MEDIA_CAMERA_SUPPORT - help - Enables drivers for ISA and parallel port bus. If you - need media drivers using those legacy buses, say Y. - -if MEDIA_PARPORT_SUPPORT -config VIDEO_BWQCAM - tristate "Quickcam BW Video For Linux (Deprecated)" - depends on PARPORT && VIDEO_V4L2 - select VIDEOBUF2_VMALLOC - help - Say Y have if you the black and white version of the QuickCam - camera. See the next option for the color version. - - This driver is deprecated and will be removed soon. If you have - hardware for this and you want to work on this driver, then contact - the linux-media mailinglist. - - To compile this driver as a module, choose M here: the - module will be called bw-qcam. - -config VIDEO_CQCAM - tristate "QuickCam Colour Video For Linux (Deprecated)" - depends on PARPORT && VIDEO_V4L2 - help - This is the video4linux driver for the colour version of the - Connectix QuickCam. If you have one of these cameras, say Y here, - otherwise say N. This driver does not work with the original - monochrome QuickCam, QuickCam VC or QuickClip. It is also available - as a module (c-qcam). - Read for more information. - - This driver is deprecated and will be removed soon. If you have - hardware for this and you want to work on this driver, then contact - the linux-media mailinglist. - -config VIDEO_PMS - tristate "Mediavision Pro Movie Studio Video For Linux (Deprecated)" - depends on ISA && VIDEO_V4L2 - help - Say Y if you have the ISA Mediavision Pro Movie Studio - capture card. - - This driver is deprecated and will be removed soon. If you have - hardware for this and you want to work on this driver, then contact - the linux-media mailinglist. - - To compile this driver as a module, choose M here: the - module will be called pms. - -config VIDEO_W9966 - tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux (Deprecated)" - depends on PARPORT_1284 && PARPORT && VIDEO_V4L2 - help - Video4linux driver for Winbond's w9966 based Webcams. - Currently tested with the LifeView FlyCam Supra. - If you have one of these cameras, say Y here - otherwise say N. - This driver is also available as a module (w9966). - - Check out for more - information. - - This driver is deprecated and will be removed soon. If you have - hardware for this and you want to work on this driver, then contact - the linux-media mailinglist. -endif diff --git a/drivers/staging/media/parport/Makefile b/drivers/staging/media/parport/Makefile deleted file mode 100644 index 4eea06d7af5b..000000000000 --- a/drivers/staging/media/parport/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o -obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o -obj-$(CONFIG_VIDEO_W9966) += w9966.o -obj-$(CONFIG_VIDEO_PMS) += pms.o diff --git a/drivers/staging/media/parport/bw-qcam.c b/drivers/staging/media/parport/bw-qcam.c deleted file mode 100644 index 67b9da1dc43f..000000000000 --- a/drivers/staging/media/parport/bw-qcam.c +++ /dev/null @@ -1,1177 +0,0 @@ -/* - * QuickCam Driver For Video4Linux. - * - * Video4Linux conversion work by Alan Cox. - * Parport compatibility by Phil Blundell. - * Busy loop avoidance by Mark Cooke. - * - * Module parameters: - * - * maxpoll=<1 - 5000> - * - * When polling the QuickCam for a response, busy-wait for a - * maximum of this many loops. The default of 250 gives little - * impact on interactive response. - * - * NOTE: If this parameter is set too high, the processor - * will busy wait until this loop times out, and then - * slowly poll for a further 5 seconds before failing - * the transaction. You have been warned. - * - * yieldlines=<1 - 250> - * - * When acquiring a frame from the camera, the data gathering - * loop will yield back to the scheduler after completing - * this many lines. The default of 4 provides a trade-off - * between increased frame acquisition time and impact on - * interactive response. - */ - -/* qcam-lib.c -- Library for programming with the Connectix QuickCam. - * See the included documentation for usage instructions and details - * of the protocol involved. */ - - -/* Version 0.5, August 4, 1996 */ -/* Version 0.7, August 27, 1996 */ -/* Version 0.9, November 17, 1996 */ - - -/****************************************************************** - -Copyright (C) 1996 by Scott Laird - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL SCOTT LAIRD 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* One from column A... */ -#define QC_NOTSET 0 -#define QC_UNIDIR 1 -#define QC_BIDIR 2 -#define QC_SERIAL 3 - -/* ... and one from column B */ -#define QC_ANY 0x00 -#define QC_FORCE_UNIDIR 0x10 -#define QC_FORCE_BIDIR 0x20 -#define QC_FORCE_SERIAL 0x30 -/* in the port_mode member */ - -#define QC_MODE_MASK 0x07 -#define QC_FORCE_MASK 0x70 - -#define MAX_HEIGHT 243 -#define MAX_WIDTH 336 - -/* Bit fields for status flags */ -#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */ - -struct qcam { - struct v4l2_device v4l2_dev; - struct video_device vdev; - struct v4l2_ctrl_handler hdl; - struct vb2_queue vb_vidq; - struct pardevice *pdev; - struct parport *pport; - struct mutex lock; - struct mutex queue_lock; - int width, height; - int bpp; - int mode; - int contrast, brightness, whitebal; - int port_mode; - int transfer_scale; - int top, left; - int status; - unsigned int saved_bits; - unsigned long in_use; -}; - -static unsigned int maxpoll = 250; /* Maximum busy-loop count for qcam I/O */ -static unsigned int yieldlines = 4; /* Yield after this many during capture */ -static int video_nr = -1; -static unsigned int force_init; /* Whether to probe aggressively */ - -module_param(maxpoll, int, 0); -module_param(yieldlines, int, 0); -module_param(video_nr, int, 0); - -/* Set force_init=1 to avoid detection by polling status register and - * immediately attempt to initialize qcam */ -module_param(force_init, int, 0); - -#define MAX_CAMS 4 -static struct qcam *qcams[MAX_CAMS]; -static unsigned int num_cams; - -static inline int read_lpstatus(struct qcam *q) -{ - return parport_read_status(q->pport); -} - -static inline int read_lpdata(struct qcam *q) -{ - return parport_read_data(q->pport); -} - -static inline void write_lpdata(struct qcam *q, int d) -{ - parport_write_data(q->pport, d); -} - -static void write_lpcontrol(struct qcam *q, int d) -{ - if (d & 0x20) { - /* Set bidirectional mode to reverse (data in) */ - parport_data_reverse(q->pport); - } else { - /* Set bidirectional mode to forward (data out) */ - parport_data_forward(q->pport); - } - - /* Now issue the regular port command, but strip out the - * direction flag */ - d &= ~0x20; - parport_write_control(q->pport, d); -} - - -/* qc_waithand busy-waits for a handshake signal from the QuickCam. - * Almost all communication with the camera requires handshaking. */ - -static int qc_waithand(struct qcam *q, int val) -{ - int status; - int runs = 0; - - if (val) { - while (!((status = read_lpstatus(q)) & 8)) { - /* 1000 is enough spins on the I/O for all normal - cases, at that point we start to poll slowly - until the camera wakes up. However, we are - busy blocked until the camera responds, so - setting it lower is much better for interactive - response. */ - - if (runs++ > maxpoll) - msleep_interruptible(5); - if (runs > (maxpoll + 1000)) /* 5 seconds */ - return -1; - } - } else { - while (((status = read_lpstatus(q)) & 8)) { - /* 1000 is enough spins on the I/O for all normal - cases, at that point we start to poll slowly - until the camera wakes up. However, we are - busy blocked until the camera responds, so - setting it lower is much better for interactive - response. */ - - if (runs++ > maxpoll) - msleep_interruptible(5); - if (runs++ > (maxpoll + 1000)) /* 5 seconds */ - return -1; - } - } - - return status; -} - -/* Waithand2 is used when the qcam is in bidirectional mode, and the - * handshaking signal is CamRdy2 (bit 0 of data reg) instead of CamRdy1 - * (bit 3 of status register). It also returns the last value read, - * since this data is useful. */ - -static unsigned int qc_waithand2(struct qcam *q, int val) -{ - unsigned int status; - int runs = 0; - - do { - status = read_lpdata(q); - /* 1000 is enough spins on the I/O for all normal - cases, at that point we start to poll slowly - until the camera wakes up. However, we are - busy blocked until the camera responds, so - setting it lower is much better for interactive - response. */ - - if (runs++ > maxpoll) - msleep_interruptible(5); - if (runs++ > (maxpoll + 1000)) /* 5 seconds */ - return 0; - } while ((status & 1) != val); - - return status; -} - -/* qc_command is probably a bit of a misnomer -- it's used to send - * bytes *to* the camera. Generally, these bytes are either commands - * or arguments to commands, so the name fits, but it still bugs me a - * bit. See the documentation for a list of commands. */ - -static int qc_command(struct qcam *q, int command) -{ - int n1, n2; - int cmd; - - write_lpdata(q, command); - write_lpcontrol(q, 6); - - n1 = qc_waithand(q, 1); - - write_lpcontrol(q, 0xe); - n2 = qc_waithand(q, 0); - - cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); - return cmd; -} - -static int qc_readparam(struct qcam *q) -{ - int n1, n2; - int cmd; - - write_lpcontrol(q, 6); - n1 = qc_waithand(q, 1); - - write_lpcontrol(q, 0xe); - n2 = qc_waithand(q, 0); - - cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4); - return cmd; -} - - -/* Try to detect a QuickCam. It appears to flash the upper 4 bits of - the status register at 5-10 Hz. This is only used in the autoprobe - code. Be aware that this isn't the way Connectix detects the - camera (they send a reset and try to handshake), but this should be - almost completely safe, while their method screws up my printer if - I plug it in before the camera. */ - -static int qc_detect(struct qcam *q) -{ - int reg, lastreg; - int count = 0; - int i; - - if (force_init) - return 1; - - lastreg = reg = read_lpstatus(q) & 0xf0; - - for (i = 0; i < 500; i++) { - reg = read_lpstatus(q) & 0xf0; - if (reg != lastreg) - count++; - lastreg = reg; - mdelay(2); - } - - -#if 0 - /* Force camera detection during testing. Sometimes the camera - won't be flashing these bits. Possibly unloading the module - in the middle of a grab? Or some timeout condition? - I've seen this parameter as low as 19 on my 450Mhz box - mpc */ - printk(KERN_DEBUG "Debugging: QCam detection counter <30-200 counts as detected>: %d\n", count); - return 1; -#endif - - /* Be (even more) liberal in what you accept... */ - - if (count > 20 && count < 400) { - return 1; /* found */ - } else { - printk(KERN_ERR "No Quickcam found on port %s\n", - q->pport->name); - printk(KERN_DEBUG "Quickcam detection counter: %u\n", count); - return 0; /* not found */ - } -} - -/* Decide which scan mode to use. There's no real requirement that - * the scanmode match the resolution in q->height and q-> width -- the - * camera takes the picture at the resolution specified in the - * "scanmode" and then returns the image at the resolution specified - * with the resolution commands. If the scan is bigger than the - * requested resolution, the upper-left hand corner of the scan is - * returned. If the scan is smaller, then the rest of the image - * returned contains garbage. */ - -static int qc_setscanmode(struct qcam *q) -{ - int old_mode = q->mode; - - switch (q->transfer_scale) { - case 1: - q->mode = 0; - break; - case 2: - q->mode = 4; - break; - case 4: - q->mode = 8; - break; - } - - switch (q->bpp) { - case 4: - break; - case 6: - q->mode += 2; - break; - } - - switch (q->port_mode & QC_MODE_MASK) { - case QC_BIDIR: - q->mode += 1; - break; - case QC_NOTSET: - case QC_UNIDIR: - break; - } - - if (q->mode != old_mode) - q->status |= QC_PARAM_CHANGE; - - return 0; -} - - -/* Reset the QuickCam. This uses the same sequence the Windows - * QuickPic program uses. Someone with a bi-directional port should - * check that bi-directional mode is detected right, and then - * implement bi-directional mode in qc_readbyte(). */ - -static void qc_reset(struct qcam *q) -{ - switch (q->port_mode & QC_FORCE_MASK) { - case QC_FORCE_UNIDIR: - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; - break; - - case QC_FORCE_BIDIR: - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; - break; - - case QC_ANY: - write_lpcontrol(q, 0x20); - write_lpdata(q, 0x75); - - if (read_lpdata(q) != 0x75) - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR; - else - q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR; - break; - } - - write_lpcontrol(q, 0xb); - udelay(250); - write_lpcontrol(q, 0xe); - qc_setscanmode(q); /* in case port_mode changed */ -} - - - -/* Reset the QuickCam and program for brightness, contrast, - * white-balance, and resolution. */ - -static void qc_set(struct qcam *q) -{ - int val; - int val2; - - /* Set the brightness. Yes, this is repetitive, but it works. - * Shorter versions seem to fail subtly. Feel free to try :-). */ - /* I think the problem was in qc_command, not here -- bls */ - - qc_command(q, 0xb); - qc_command(q, q->brightness); - - val = q->height / q->transfer_scale; - qc_command(q, 0x11); - qc_command(q, val); - if ((q->port_mode & QC_MODE_MASK) == QC_UNIDIR && q->bpp == 6) { - /* The normal "transfers per line" calculation doesn't seem to work - as expected here (and yet it works fine in qc_scan). No idea - why this case is the odd man out. Fortunately, Laird's original - working version gives me a good way to guess at working values. - -- bls */ - val = q->width; - val2 = q->transfer_scale * 4; - } else { - val = q->width * q->bpp; - val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) * - q->transfer_scale; - } - val = DIV_ROUND_UP(val, val2); - qc_command(q, 0x13); - qc_command(q, val); - - /* Setting top and left -- bls */ - qc_command(q, 0xd); - qc_command(q, q->top); - qc_command(q, 0xf); - qc_command(q, q->left / 2); - - qc_command(q, 0x19); - qc_command(q, q->contrast); - qc_command(q, 0x1f); - qc_command(q, q->whitebal); - - /* Clear flag that we must update the grabbing parameters on the camera - before we grab the next frame */ - q->status &= (~QC_PARAM_CHANGE); -} - -/* Qc_readbytes reads some bytes from the QC and puts them in - the supplied buffer. It returns the number of bytes read, - or -1 on error. */ - -static inline int qc_readbytes(struct qcam *q, char buffer[]) -{ - int ret = 1; - unsigned int hi, lo; - unsigned int hi2, lo2; - static int state; - - if (buffer == NULL) { - state = 0; - return 0; - } - - switch (q->port_mode & QC_MODE_MASK) { - case QC_BIDIR: /* Bi-directional Port */ - write_lpcontrol(q, 0x26); - lo = (qc_waithand2(q, 1) >> 1); - hi = (read_lpstatus(q) >> 3) & 0x1f; - write_lpcontrol(q, 0x2e); - lo2 = (qc_waithand2(q, 0) >> 1); - hi2 = (read_lpstatus(q) >> 3) & 0x1f; - switch (q->bpp) { - case 4: - buffer[0] = lo & 0xf; - buffer[1] = ((lo & 0x70) >> 4) | ((hi & 1) << 3); - buffer[2] = (hi & 0x1e) >> 1; - buffer[3] = lo2 & 0xf; - buffer[4] = ((lo2 & 0x70) >> 4) | ((hi2 & 1) << 3); - buffer[5] = (hi2 & 0x1e) >> 1; - ret = 6; - break; - case 6: - buffer[0] = lo & 0x3f; - buffer[1] = ((lo & 0x40) >> 6) | (hi << 1); - buffer[2] = lo2 & 0x3f; - buffer[3] = ((lo2 & 0x40) >> 6) | (hi2 << 1); - ret = 4; - break; - } - break; - - case QC_UNIDIR: /* Unidirectional Port */ - write_lpcontrol(q, 6); - lo = (qc_waithand(q, 1) & 0xf0) >> 4; - write_lpcontrol(q, 0xe); - hi = (qc_waithand(q, 0) & 0xf0) >> 4; - - switch (q->bpp) { - case 4: - buffer[0] = lo; - buffer[1] = hi; - ret = 2; - break; - case 6: - switch (state) { - case 0: - buffer[0] = (lo << 2) | ((hi & 0xc) >> 2); - q->saved_bits = (hi & 3) << 4; - state = 1; - ret = 1; - break; - case 1: - buffer[0] = lo | q->saved_bits; - q->saved_bits = hi << 2; - state = 2; - ret = 1; - break; - case 2: - buffer[0] = ((lo & 0xc) >> 2) | q->saved_bits; - buffer[1] = ((lo & 3) << 4) | hi; - state = 0; - ret = 2; - break; - } - break; - } - break; - } - return ret; -} - -/* requests a scan from the camera. It sends the correct instructions - * to the camera and then reads back the correct number of bytes. In - * previous versions of this routine the return structure contained - * the raw output from the camera, and there was a 'qc_convertscan' - * function that converted that to a useful format. In version 0.3 I - * rolled qc_convertscan into qc_scan and now I only return the - * converted scan. The format is just an one-dimensional array of - * characters, one for each pixel, with 0=black up to n=white, where - * n=2^(bit depth)-1. Ask me for more details if you don't understand - * this. */ - -static long qc_capture(struct qcam *q, u8 *buf, unsigned long len) -{ - int i, j, k, yield; - int bytes; - int linestotrans, transperline; - int divisor; - int pixels_per_line; - int pixels_read = 0; - int got = 0; - char buffer[6]; - int shift = 8 - q->bpp; - char invert; - - if (q->mode == -1) - return -ENXIO; - - qc_command(q, 0x7); - qc_command(q, q->mode); - - if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) { - write_lpcontrol(q, 0x2e); /* turn port around */ - write_lpcontrol(q, 0x26); - qc_waithand(q, 1); - write_lpcontrol(q, 0x2e); - qc_waithand(q, 0); - } - - /* strange -- should be 15:63 below, but 4bpp is odd */ - invert = (q->bpp == 4) ? 16 : 63; - - linestotrans = q->height / q->transfer_scale; - pixels_per_line = q->width / q->transfer_scale; - transperline = q->width * q->bpp; - divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) * - q->transfer_scale; - transperline = DIV_ROUND_UP(transperline, divisor); - - for (i = 0, yield = yieldlines; i < linestotrans; i++) { - for (pixels_read = j = 0; j < transperline; j++) { - bytes = qc_readbytes(q, buffer); - for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++) { - int o; - if (buffer[k] == 0 && invert == 16) { - /* 4bpp is odd (again) -- inverter is 16, not 15, but output - must be 0-15 -- bls */ - buffer[k] = 16; - } - o = i * pixels_per_line + pixels_read + k; - if (o < len) { - u8 ch = invert - buffer[k]; - got++; - buf[o] = ch << shift; - } - } - pixels_read += bytes; - } - qc_readbytes(q, NULL); /* reset state machine */ - - /* Grabbing an entire frame from the quickcam is a lengthy - process. We don't (usually) want to busy-block the - processor for the entire frame. yieldlines is a module - parameter. If we yield every line, the minimum frame - time will be 240 / 200 = 1.2 seconds. The compile-time - default is to yield every 4 lines. */ - if (i >= yield) { - msleep_interruptible(5); - yield = i + yieldlines; - } - } - - if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) { - write_lpcontrol(q, 2); - write_lpcontrol(q, 6); - udelay(3); - write_lpcontrol(q, 0xe); - } - if (got < len) - return got; - return len; -} - -/* ------------------------------------------------------------------ - Videobuf operations - ------------------------------------------------------------------*/ -static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) -{ - struct qcam *dev = vb2_get_drv_priv(vq); - - if (0 == *nbuffers) - *nbuffers = 3; - *nplanes = 1; - mutex_lock(&dev->lock); - if (fmt) - sizes[0] = fmt->fmt.pix.width * fmt->fmt.pix.height; - else - sizes[0] = (dev->width / dev->transfer_scale) * - (dev->height / dev->transfer_scale); - mutex_unlock(&dev->lock); - return 0; -} - -static void buffer_queue(struct vb2_buffer *vb) -{ - vb2_buffer_done(vb, VB2_BUF_STATE_DONE); -} - -static void buffer_finish(struct vb2_buffer *vb) -{ - struct qcam *qcam = vb2_get_drv_priv(vb->vb2_queue); - void *vbuf = vb2_plane_vaddr(vb, 0); - int size = vb->vb2_queue->plane_sizes[0]; - int len; - - if (!vb2_is_streaming(vb->vb2_queue)) - return; - - mutex_lock(&qcam->lock); - parport_claim_or_block(qcam->pdev); - - qc_reset(qcam); - - /* Update the camera parameters if we need to */ - if (qcam->status & QC_PARAM_CHANGE) - qc_set(qcam); - - len = qc_capture(qcam, vbuf, size); - - parport_release(qcam->pdev); - mutex_unlock(&qcam->lock); - v4l2_get_timestamp(&vb->v4l2_buf.timestamp); - if (len != size) - vb->state = VB2_BUF_STATE_ERROR; - vb2_set_plane_payload(vb, 0, len); -} - -static struct vb2_ops qcam_video_qops = { - .queue_setup = queue_setup, - .buf_queue = buffer_queue, - .buf_finish = buffer_finish, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -/* - * Video4linux interfacing - */ - -static int qcam_querycap(struct file *file, void *priv, - struct v4l2_capability *vcap) -{ - struct qcam *qcam = video_drvdata(file); - - strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); - strlcpy(vcap->card, "Connectix B&W Quickcam", sizeof(vcap->card)); - strlcpy(vcap->bus_info, qcam->pport->name, sizeof(vcap->bus_info)); - vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; -} - -static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) -{ - if (vin->index > 0) - return -EINVAL; - strlcpy(vin->name, "Camera", sizeof(vin->name)); - vin->type = V4L2_INPUT_TYPE_CAMERA; - vin->audioset = 0; - vin->tuner = 0; - vin->std = 0; - vin->status = 0; - return 0; -} - -static int qcam_g_input(struct file *file, void *fh, unsigned int *inp) -{ - *inp = 0; - return 0; -} - -static int qcam_s_input(struct file *file, void *fh, unsigned int inp) -{ - return (inp > 0) ? -EINVAL : 0; -} - -static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct qcam *qcam = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - pix->width = qcam->width / qcam->transfer_scale; - pix->height = qcam->height / qcam->transfer_scale; - pix->pixelformat = (qcam->bpp == 4) ? V4L2_PIX_FMT_Y4 : V4L2_PIX_FMT_Y6; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = pix->width; - pix->sizeimage = pix->width * pix->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SRGB; - return 0; -} - -static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - if (pix->height <= 60 || pix->width <= 80) { - pix->height = 60; - pix->width = 80; - } else if (pix->height <= 120 || pix->width <= 160) { - pix->height = 120; - pix->width = 160; - } else { - pix->height = 240; - pix->width = 320; - } - if (pix->pixelformat != V4L2_PIX_FMT_Y4 && - pix->pixelformat != V4L2_PIX_FMT_Y6) - pix->pixelformat = V4L2_PIX_FMT_Y4; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = pix->width; - pix->sizeimage = pix->width * pix->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SRGB; - return 0; -} - -static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct qcam *qcam = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - int ret = qcam_try_fmt_vid_cap(file, fh, fmt); - - if (ret) - return ret; - if (vb2_is_busy(&qcam->vb_vidq)) - return -EBUSY; - qcam->width = 320; - qcam->height = 240; - if (pix->height == 60) - qcam->transfer_scale = 4; - else if (pix->height == 120) - qcam->transfer_scale = 2; - else - qcam->transfer_scale = 1; - if (pix->pixelformat == V4L2_PIX_FMT_Y6) - qcam->bpp = 6; - else - qcam->bpp = 4; - - qc_setscanmode(qcam); - /* We must update the camera before we grab. We could - just have changed the grab size */ - qcam->status |= QC_PARAM_CHANGE; - return 0; -} - -static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) -{ - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "4-Bit Monochrome", V4L2_PIX_FMT_Y4, - { 0, 0, 0, 0 } - }, - { 1, 0, 0, - "6-Bit Monochrome", V4L2_PIX_FMT_Y6, - { 0, 0, 0, 0 } - }, - }; - enum v4l2_buf_type type = fmt->type; - - if (fmt->index > 1) - return -EINVAL; - - *fmt = formats[fmt->index]; - fmt->type = type; - return 0; -} - -static int qcam_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - static const struct v4l2_frmsize_discrete sizes[] = { - { 80, 60 }, - { 160, 120 }, - { 320, 240 }, - }; - - if (fsize->index > 2) - return -EINVAL; - if (fsize->pixel_format != V4L2_PIX_FMT_Y4 && - fsize->pixel_format != V4L2_PIX_FMT_Y6) - return -EINVAL; - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete = sizes[fsize->index]; - return 0; -} - -static int qcam_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct qcam *qcam = - container_of(ctrl->handler, struct qcam, hdl); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - qcam->brightness = ctrl->val; - break; - case V4L2_CID_CONTRAST: - qcam->contrast = ctrl->val; - break; - case V4L2_CID_GAMMA: - qcam->whitebal = ctrl->val; - break; - default: - ret = -EINVAL; - break; - } - if (ret == 0) - qcam->status |= QC_PARAM_CHANGE; - return ret; -} - -static const struct v4l2_file_operations qcam_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vb2_fop_release, - .poll = vb2_fop_poll, - .unlocked_ioctl = video_ioctl2, - .read = vb2_fop_read, - .mmap = vb2_fop_mmap, -}; - -static const struct v4l2_ioctl_ops qcam_ioctl_ops = { - .vidioc_querycap = qcam_querycap, - .vidioc_g_input = qcam_g_input, - .vidioc_s_input = qcam_s_input, - .vidioc_enum_input = qcam_enum_input, - .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap, - .vidioc_enum_framesizes = qcam_enum_framesizes, - .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap, - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static const struct v4l2_ctrl_ops qcam_ctrl_ops = { - .s_ctrl = qcam_s_ctrl, -}; - -/* Initialize the QuickCam driver control structure. This is where - * defaults are set for people who don't have a config file.*/ - -static struct qcam *qcam_init(struct parport *port) -{ - struct qcam *qcam; - struct v4l2_device *v4l2_dev; - struct vb2_queue *q; - int err; - - qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL); - if (qcam == NULL) - return NULL; - - v4l2_dev = &qcam->v4l2_dev; - snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "bw-qcam%u", num_cams); - - if (v4l2_device_register(port->dev, v4l2_dev) < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - kfree(qcam); - return NULL; - } - - v4l2_ctrl_handler_init(&qcam->hdl, 3); - v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 180); - v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, 192); - v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops, - V4L2_CID_GAMMA, 0, 255, 1, 105); - if (qcam->hdl.error) { - v4l2_err(v4l2_dev, "couldn't register controls\n"); - goto exit; - } - - mutex_init(&qcam->lock); - mutex_init(&qcam->queue_lock); - - /* initialize queue */ - q = &qcam->vb_vidq; - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; - q->drv_priv = qcam; - q->ops = &qcam_video_qops; - q->mem_ops = &vb2_vmalloc_memops; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - err = vb2_queue_init(q); - if (err < 0) { - v4l2_err(v4l2_dev, "couldn't init vb2_queue for %s.\n", port->name); - goto exit; - } - qcam->vdev.queue = q; - qcam->vdev.queue->lock = &qcam->queue_lock; - - qcam->pport = port; - qcam->pdev = parport_register_device(port, v4l2_dev->name, NULL, NULL, - NULL, 0, NULL); - if (qcam->pdev == NULL) { - v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); - goto exit; - } - - strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name)); - qcam->vdev.v4l2_dev = v4l2_dev; - qcam->vdev.ctrl_handler = &qcam->hdl; - qcam->vdev.fops = &qcam_fops; - qcam->vdev.lock = &qcam->lock; - qcam->vdev.ioctl_ops = &qcam_ioctl_ops; - qcam->vdev.release = video_device_release_empty; - video_set_drvdata(&qcam->vdev, qcam); - - qcam->port_mode = (QC_ANY | QC_NOTSET); - qcam->width = 320; - qcam->height = 240; - qcam->bpp = 4; - qcam->transfer_scale = 2; - qcam->contrast = 192; - qcam->brightness = 180; - qcam->whitebal = 105; - qcam->top = 1; - qcam->left = 14; - qcam->mode = -1; - qcam->status = QC_PARAM_CHANGE; - return qcam; - -exit: - v4l2_ctrl_handler_free(&qcam->hdl); - kfree(qcam); - return NULL; -} - -static int qc_calibrate(struct qcam *q) -{ - /* - * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96 - * The white balance is an individual value for each - * quickcam. - */ - - int value; - int count = 0; - - qc_command(q, 27); /* AutoAdjustOffset */ - qc_command(q, 0); /* Dummy Parameter, ignored by the camera */ - - /* GetOffset (33) will read 255 until autocalibration */ - /* is finished. After that, a value of 1-254 will be */ - /* returned. */ - - do { - qc_command(q, 33); - value = qc_readparam(q); - mdelay(1); - schedule(); - count++; - } while (value == 0xff && count < 2048); - - q->whitebal = value; - return value; -} - -static int init_bwqcam(struct parport *port) -{ - struct qcam *qcam; - - if (num_cams == MAX_CAMS) { - printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS); - return -ENOSPC; - } - - qcam = qcam_init(port); - if (qcam == NULL) - return -ENODEV; - - parport_claim_or_block(qcam->pdev); - - qc_reset(qcam); - - if (qc_detect(qcam) == 0) { - parport_release(qcam->pdev); - parport_unregister_device(qcam->pdev); - kfree(qcam); - return -ENODEV; - } - qc_calibrate(qcam); - v4l2_ctrl_handler_setup(&qcam->hdl); - - parport_release(qcam->pdev); - - v4l2_info(&qcam->v4l2_dev, "Connectix Quickcam on %s\n", qcam->pport->name); - - if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { - parport_unregister_device(qcam->pdev); - kfree(qcam); - return -ENODEV; - } - - qcams[num_cams++] = qcam; - - return 0; -} - -static void close_bwqcam(struct qcam *qcam) -{ - video_unregister_device(&qcam->vdev); - v4l2_ctrl_handler_free(&qcam->hdl); - parport_unregister_device(qcam->pdev); - kfree(qcam); -} - -/* The parport parameter controls which parports will be scanned. - * Scanning all parports causes some printers to print a garbage page. - * -- March 14, 1999 Billy Donahue */ -#ifdef MODULE -static char *parport[MAX_CAMS] = { NULL, }; -module_param_array(parport, charp, NULL, 0); -#endif - -static int accept_bwqcam(struct parport *port) -{ -#ifdef MODULE - int n; - - if (parport[0] && strncmp(parport[0], "auto", 4) != 0) { - /* user gave parport parameters */ - for (n = 0; n < MAX_CAMS && parport[n]; n++) { - char *ep; - unsigned long r; - r = simple_strtoul(parport[n], &ep, 0); - if (ep == parport[n]) { - printk(KERN_ERR - "bw-qcam: bad port specifier \"%s\"\n", - parport[n]); - continue; - } - if (r == port->number) - return 1; - } - return 0; - } -#endif - return 1; -} - -static void bwqcam_attach(struct parport *port) -{ - if (accept_bwqcam(port)) - init_bwqcam(port); -} - -static void bwqcam_detach(struct parport *port) -{ - int i; - for (i = 0; i < num_cams; i++) { - struct qcam *qcam = qcams[i]; - if (qcam && qcam->pdev->port == port) { - qcams[i] = NULL; - close_bwqcam(qcam); - } - } -} - -static struct parport_driver bwqcam_driver = { - .name = "bw-qcam", - .attach = bwqcam_attach, - .detach = bwqcam_detach, -}; - -static void __exit exit_bw_qcams(void) -{ - parport_unregister_driver(&bwqcam_driver); -} - -static int __init init_bw_qcams(void) -{ -#ifdef MODULE - /* Do some sanity checks on the module parameters. */ - if (maxpoll > 5000) { - printk(KERN_INFO "Connectix Quickcam max-poll was above 5000. Using 5000.\n"); - maxpoll = 5000; - } - - if (yieldlines < 1) { - printk(KERN_INFO "Connectix Quickcam yieldlines was less than 1. Using 1.\n"); - yieldlines = 1; - } -#endif - return parport_register_driver(&bwqcam_driver); -} - -module_init(init_bw_qcams); -module_exit(exit_bw_qcams); - -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.0.3"); diff --git a/drivers/staging/media/parport/c-qcam.c b/drivers/staging/media/parport/c-qcam.c deleted file mode 100644 index b9010bd3ed3e..000000000000 --- a/drivers/staging/media/parport/c-qcam.c +++ /dev/null @@ -1,882 +0,0 @@ -/* - * Video4Linux Colour QuickCam driver - * Copyright 1997-2000 Philip Blundell - * - * Module parameters: - * - * parport=auto -- probe all parports (default) - * parport=0 -- parport0 becomes qcam1 - * parport=2,0,1 -- parports 2,0,1 are tried in that order - * - * probe=0 -- do no probing, assume camera is present - * probe=1 -- use IEEE-1284 autoprobe data only (default) - * probe=2 -- probe aggressively for cameras - * - * force_rgb=1 -- force data format to RGB (default is BGR) - * - * The parport parameter controls which parports will be scanned. - * Scanning all parports causes some printers to print a garbage page. - * -- March 14, 1999 Billy Donahue - * - * Fixed data format to BGR, added force_rgb parameter. Added missing - * parport_unregister_driver() on module removal. - * -- May 28, 2000 Claudio Matsuoka - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct qcam { - struct v4l2_device v4l2_dev; - struct video_device vdev; - struct v4l2_ctrl_handler hdl; - struct pardevice *pdev; - struct parport *pport; - int width, height; - int ccd_width, ccd_height; - int mode; - int contrast, brightness, whitebal; - int top, left; - unsigned int bidirectional; - struct mutex lock; -}; - -/* cameras maximum */ -#define MAX_CAMS 4 - -/* The three possible QuickCam modes */ -#define QC_MILLIONS 0x18 -#define QC_BILLIONS 0x10 -#define QC_THOUSANDS 0x08 /* with VIDEC compression (not supported) */ - -/* The three possible decimations */ -#define QC_DECIMATION_1 0 -#define QC_DECIMATION_2 2 -#define QC_DECIMATION_4 4 - -#define BANNER "Colour QuickCam for Video4Linux v0.06" - -static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; -static int probe = 2; -static bool force_rgb; -static int video_nr = -1; - -/* FIXME: parport=auto would never have worked, surely? --RR */ -MODULE_PARM_DESC(parport, "parport= for port detection method\n" - "probe=<0|1|2> for camera detection method\n" - "force_rgb=<0|1> for RGB data format (default BGR)"); -module_param_array(parport, int, NULL, 0); -module_param(probe, int, 0); -module_param(force_rgb, bool, 0); -module_param(video_nr, int, 0); - -static struct qcam *qcams[MAX_CAMS]; -static unsigned int num_cams; - -static inline void qcam_set_ack(struct qcam *qcam, unsigned int i) -{ - /* note: the QC specs refer to the PCAck pin by voltage, not - software level. PC ports have builtin inverters. */ - parport_frob_control(qcam->pport, 8, i ? 8 : 0); -} - -static inline unsigned int qcam_ready1(struct qcam *qcam) -{ - return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0; -} - -static inline unsigned int qcam_ready2(struct qcam *qcam) -{ - return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0; -} - -static unsigned int qcam_await_ready1(struct qcam *qcam, int value) -{ - struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; - unsigned long oldjiffies = jiffies; - unsigned int i; - - for (oldjiffies = jiffies; - time_before(jiffies, oldjiffies + msecs_to_jiffies(40));) - if (qcam_ready1(qcam) == value) - return 0; - - /* If the camera didn't respond within 1/25 second, poll slowly - for a while. */ - for (i = 0; i < 50; i++) { - if (qcam_ready1(qcam) == value) - return 0; - msleep_interruptible(100); - } - - /* Probably somebody pulled the plug out. Not much we can do. */ - v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value, - parport_read_status(qcam->pport), - parport_read_control(qcam->pport)); - return 1; -} - -static unsigned int qcam_await_ready2(struct qcam *qcam, int value) -{ - struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; - unsigned long oldjiffies = jiffies; - unsigned int i; - - for (oldjiffies = jiffies; - time_before(jiffies, oldjiffies + msecs_to_jiffies(40));) - if (qcam_ready2(qcam) == value) - return 0; - - /* If the camera didn't respond within 1/25 second, poll slowly - for a while. */ - for (i = 0; i < 50; i++) { - if (qcam_ready2(qcam) == value) - return 0; - msleep_interruptible(100); - } - - /* Probably somebody pulled the plug out. Not much we can do. */ - v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value, - parport_read_status(qcam->pport), - parport_read_control(qcam->pport), - parport_read_data(qcam->pport)); - return 1; -} - -static int qcam_read_data(struct qcam *qcam) -{ - unsigned int idata; - - qcam_set_ack(qcam, 0); - if (qcam_await_ready1(qcam, 1)) - return -1; - idata = parport_read_status(qcam->pport) & 0xf0; - qcam_set_ack(qcam, 1); - if (qcam_await_ready1(qcam, 0)) - return -1; - idata |= parport_read_status(qcam->pport) >> 4; - return idata; -} - -static int qcam_write_data(struct qcam *qcam, unsigned int data) -{ - struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; - unsigned int idata; - - parport_write_data(qcam->pport, data); - idata = qcam_read_data(qcam); - if (data != idata) { - v4l2_warn(v4l2_dev, "sent %x but received %x\n", data, - idata); - return 1; - } - return 0; -} - -static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data) -{ - if (qcam_write_data(qcam, cmd)) - return -1; - if (qcam_write_data(qcam, data)) - return -1; - return 0; -} - -static inline int qcam_get(struct qcam *qcam, unsigned int cmd) -{ - if (qcam_write_data(qcam, cmd)) - return -1; - return qcam_read_data(qcam); -} - -static int qc_detect(struct qcam *qcam) -{ - unsigned int stat, ostat, i, count = 0; - - /* The probe routine below is not very reliable. The IEEE-1284 - probe takes precedence. */ - /* XXX Currently parport provides no way to distinguish between - "the IEEE probe was not done" and "the probe was done, but - no device was found". Fix this one day. */ - if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA - && qcam->pport->probe_info[0].model - && !strcmp(qcam->pdev->port->probe_info[0].model, - "Color QuickCam 2.0")) { - printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n"); - return 1; - } - - if (probe < 2) - return 0; - - parport_write_control(qcam->pport, 0xc); - - /* look for a heartbeat */ - ostat = stat = parport_read_status(qcam->pport); - for (i = 0; i < 250; i++) { - mdelay(1); - stat = parport_read_status(qcam->pport); - if (ostat != stat) { - if (++count >= 3) - return 1; - ostat = stat; - } - } - - /* Reset the camera and try again */ - parport_write_control(qcam->pport, 0xc); - parport_write_control(qcam->pport, 0x8); - mdelay(1); - parport_write_control(qcam->pport, 0xc); - mdelay(1); - count = 0; - - ostat = stat = parport_read_status(qcam->pport); - for (i = 0; i < 250; i++) { - mdelay(1); - stat = parport_read_status(qcam->pport); - if (ostat != stat) { - if (++count >= 3) - return 1; - ostat = stat; - } - } - - /* no (or flatline) camera, give up */ - return 0; -} - -static void qc_reset(struct qcam *qcam) -{ - parport_write_control(qcam->pport, 0xc); - parport_write_control(qcam->pport, 0x8); - mdelay(1); - parport_write_control(qcam->pport, 0xc); - mdelay(1); -} - -/* Reset the QuickCam and program for brightness, contrast, - * white-balance, and resolution. */ - -static void qc_setup(struct qcam *qcam) -{ - qc_reset(qcam); - - /* Set the brightness. */ - qcam_set(qcam, 11, qcam->brightness); - - /* Set the height and width. These refer to the actual - CCD area *before* applying the selected decimation. */ - qcam_set(qcam, 17, qcam->ccd_height); - qcam_set(qcam, 19, qcam->ccd_width / 2); - - /* Set top and left. */ - qcam_set(qcam, 0xd, qcam->top); - qcam_set(qcam, 0xf, qcam->left); - - /* Set contrast and white balance. */ - qcam_set(qcam, 0x19, qcam->contrast); - qcam_set(qcam, 0x1f, qcam->whitebal); - - /* Set the speed. */ - qcam_set(qcam, 45, 2); -} - -/* Read some bytes from the camera and put them in the buffer. - nbytes should be a multiple of 3, because bidirectional mode gives - us three bytes at a time. */ - -static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes) -{ - unsigned int bytes = 0; - - qcam_set_ack(qcam, 0); - if (qcam->bidirectional) { - /* It's a bidirectional port */ - while (bytes < nbytes) { - unsigned int lo1, hi1, lo2, hi2; - unsigned char r, g, b; - - if (qcam_await_ready2(qcam, 1)) - return bytes; - lo1 = parport_read_data(qcam->pport) >> 1; - hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10; - qcam_set_ack(qcam, 1); - if (qcam_await_ready2(qcam, 0)) - return bytes; - lo2 = parport_read_data(qcam->pport) >> 1; - hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10; - qcam_set_ack(qcam, 0); - r = lo1 | ((hi1 & 1) << 7); - g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1); - b = lo2 | ((hi2 & 1) << 7); - if (force_rgb) { - buf[bytes++] = r; - buf[bytes++] = g; - buf[bytes++] = b; - } else { - buf[bytes++] = b; - buf[bytes++] = g; - buf[bytes++] = r; - } - } - } else { - /* It's a unidirectional port */ - int i = 0, n = bytes; - unsigned char rgb[3]; - - while (bytes < nbytes) { - unsigned int hi, lo; - - if (qcam_await_ready1(qcam, 1)) - return bytes; - hi = (parport_read_status(qcam->pport) & 0xf0); - qcam_set_ack(qcam, 1); - if (qcam_await_ready1(qcam, 0)) - return bytes; - lo = (parport_read_status(qcam->pport) & 0xf0); - qcam_set_ack(qcam, 0); - /* flip some bits */ - rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88; - if (i >= 2) { -get_fragment: - if (force_rgb) { - buf[n++] = rgb[0]; - buf[n++] = rgb[1]; - buf[n++] = rgb[2]; - } else { - buf[n++] = rgb[2]; - buf[n++] = rgb[1]; - buf[n++] = rgb[0]; - } - } - } - if (i) { - i = 0; - goto get_fragment; - } - } - return bytes; -} - -#define BUFSZ 150 - -static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len) -{ - struct v4l2_device *v4l2_dev = &qcam->v4l2_dev; - unsigned lines, pixelsperline; - unsigned int is_bi_dir = qcam->bidirectional; - size_t wantlen, outptr = 0; - char tmpbuf[BUFSZ]; - - if (!access_ok(VERIFY_WRITE, buf, len)) - return -EFAULT; - - /* Wait for camera to become ready */ - for (;;) { - int i = qcam_get(qcam, 41); - - if (i == -1) { - qc_setup(qcam); - return -EIO; - } - if ((i & 0x80) == 0) - break; - schedule(); - } - - if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1)) - return -EIO; - - lines = qcam->height; - pixelsperline = qcam->width; - - if (is_bi_dir) { - /* Turn the port around */ - parport_data_reverse(qcam->pport); - mdelay(3); - qcam_set_ack(qcam, 0); - if (qcam_await_ready1(qcam, 1)) { - qc_setup(qcam); - return -EIO; - } - qcam_set_ack(qcam, 1); - if (qcam_await_ready1(qcam, 0)) { - qc_setup(qcam); - return -EIO; - } - } - - wantlen = lines * pixelsperline * 24 / 8; - - while (wantlen) { - size_t t, s; - - s = (wantlen > BUFSZ) ? BUFSZ : wantlen; - t = qcam_read_bytes(qcam, tmpbuf, s); - if (outptr < len) { - size_t sz = len - outptr; - - if (sz > t) - sz = t; - if (__copy_to_user(buf + outptr, tmpbuf, sz)) - break; - outptr += sz; - } - wantlen -= t; - if (t < s) - break; - cond_resched(); - } - - len = outptr; - - if (wantlen) { - v4l2_err(v4l2_dev, "short read.\n"); - if (is_bi_dir) - parport_data_forward(qcam->pport); - qc_setup(qcam); - return len; - } - - if (is_bi_dir) { - int l; - - do { - l = qcam_read_bytes(qcam, tmpbuf, 3); - cond_resched(); - } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e)); - if (force_rgb) { - if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) - v4l2_err(v4l2_dev, "bad EOF\n"); - } else { - if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) - v4l2_err(v4l2_dev, "bad EOF\n"); - } - qcam_set_ack(qcam, 0); - if (qcam_await_ready1(qcam, 1)) { - v4l2_err(v4l2_dev, "no ack after EOF\n"); - parport_data_forward(qcam->pport); - qc_setup(qcam); - return len; - } - parport_data_forward(qcam->pport); - mdelay(3); - qcam_set_ack(qcam, 1); - if (qcam_await_ready1(qcam, 0)) { - v4l2_err(v4l2_dev, "no ack to port turnaround\n"); - qc_setup(qcam); - return len; - } - } else { - int l; - - do { - l = qcam_read_bytes(qcam, tmpbuf, 1); - cond_resched(); - } while (l && tmpbuf[0] == 0x7e); - l = qcam_read_bytes(qcam, tmpbuf + 1, 2); - if (force_rgb) { - if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) - v4l2_err(v4l2_dev, "bad EOF\n"); - } else { - if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) - v4l2_err(v4l2_dev, "bad EOF\n"); - } - } - - qcam_write_data(qcam, 0); - return len; -} - -/* - * Video4linux interfacing - */ - -static int qcam_querycap(struct file *file, void *priv, - struct v4l2_capability *vcap) -{ - struct qcam *qcam = video_drvdata(file); - - strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); - strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card)); - strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); - vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; - vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; -} - -static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) -{ - if (vin->index > 0) - return -EINVAL; - strlcpy(vin->name, "Camera", sizeof(vin->name)); - vin->type = V4L2_INPUT_TYPE_CAMERA; - vin->audioset = 0; - vin->tuner = 0; - vin->std = 0; - vin->status = 0; - return 0; -} - -static int qcam_g_input(struct file *file, void *fh, unsigned int *inp) -{ - *inp = 0; - return 0; -} - -static int qcam_s_input(struct file *file, void *fh, unsigned int inp) -{ - return (inp > 0) ? -EINVAL : 0; -} - -static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct qcam *qcam = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - pix->width = qcam->width; - pix->height = qcam->height; - pix->pixelformat = V4L2_PIX_FMT_RGB24; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = 3 * qcam->width; - pix->sizeimage = 3 * qcam->width * qcam->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SRGB; - return 0; -} - -static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - if (pix->height < 60 || pix->width < 80) { - pix->height = 60; - pix->width = 80; - } else if (pix->height < 120 || pix->width < 160) { - pix->height = 120; - pix->width = 160; - } else { - pix->height = 240; - pix->width = 320; - } - pix->pixelformat = V4L2_PIX_FMT_RGB24; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = 3 * pix->width; - pix->sizeimage = 3 * pix->width * pix->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SRGB; - return 0; -} - -static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct qcam *qcam = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - int ret = qcam_try_fmt_vid_cap(file, fh, fmt); - - if (ret) - return ret; - switch (pix->height) { - case 60: - qcam->mode = QC_DECIMATION_4; - break; - case 120: - qcam->mode = QC_DECIMATION_2; - break; - default: - qcam->mode = QC_DECIMATION_1; - break; - } - - mutex_lock(&qcam->lock); - qcam->mode |= QC_MILLIONS; - qcam->height = pix->height; - qcam->width = pix->width; - parport_claim_or_block(qcam->pdev); - qc_setup(qcam); - parport_release(qcam->pdev); - mutex_unlock(&qcam->lock); - return 0; -} - -static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) -{ - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "RGB 8:8:8", V4L2_PIX_FMT_RGB24, - { 0, 0, 0, 0 } - }, - }; - enum v4l2_buf_type type = fmt->type; - - if (fmt->index > 0) - return -EINVAL; - - *fmt = formats[fmt->index]; - fmt->type = type; - return 0; -} - -static ssize_t qcam_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct qcam *qcam = video_drvdata(file); - int len; - - mutex_lock(&qcam->lock); - parport_claim_or_block(qcam->pdev); - /* Probably should have a semaphore against multiple users */ - len = qc_capture(qcam, buf, count); - parport_release(qcam->pdev); - mutex_unlock(&qcam->lock); - return len; -} - -static int qcam_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct qcam *qcam = - container_of(ctrl->handler, struct qcam, hdl); - int ret = 0; - - mutex_lock(&qcam->lock); - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - qcam->brightness = ctrl->val; - break; - case V4L2_CID_CONTRAST: - qcam->contrast = ctrl->val; - break; - case V4L2_CID_GAMMA: - qcam->whitebal = ctrl->val; - break; - default: - ret = -EINVAL; - break; - } - if (ret == 0) { - parport_claim_or_block(qcam->pdev); - qc_setup(qcam); - parport_release(qcam->pdev); - } - mutex_unlock(&qcam->lock); - return ret; -} - -static const struct v4l2_file_operations qcam_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = v4l2_fh_release, - .poll = v4l2_ctrl_poll, - .unlocked_ioctl = video_ioctl2, - .read = qcam_read, -}; - -static const struct v4l2_ioctl_ops qcam_ioctl_ops = { - .vidioc_querycap = qcam_querycap, - .vidioc_g_input = qcam_g_input, - .vidioc_s_input = qcam_s_input, - .vidioc_enum_input = qcam_enum_input, - .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap, - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static const struct v4l2_ctrl_ops qcam_ctrl_ops = { - .s_ctrl = qcam_s_ctrl, -}; - -/* Initialize the QuickCam driver control structure. */ - -static struct qcam *qcam_init(struct parport *port) -{ - struct qcam *qcam; - struct v4l2_device *v4l2_dev; - - qcam = kzalloc(sizeof(*qcam), GFP_KERNEL); - if (qcam == NULL) - return NULL; - - v4l2_dev = &qcam->v4l2_dev; - strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name)); - - if (v4l2_device_register(NULL, v4l2_dev) < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - kfree(qcam); - return NULL; - } - - v4l2_ctrl_handler_init(&qcam->hdl, 3); - v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 240); - v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, 192); - v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops, - V4L2_CID_GAMMA, 0, 255, 1, 128); - if (qcam->hdl.error) { - v4l2_err(v4l2_dev, "couldn't register controls\n"); - v4l2_ctrl_handler_free(&qcam->hdl); - kfree(qcam); - return NULL; - } - - qcam->pport = port; - qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL, - NULL, 0, NULL); - - qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0; - - if (qcam->pdev == NULL) { - v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); - v4l2_ctrl_handler_free(&qcam->hdl); - kfree(qcam); - return NULL; - } - - strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name)); - qcam->vdev.v4l2_dev = v4l2_dev; - qcam->vdev.fops = &qcam_fops; - qcam->vdev.ioctl_ops = &qcam_ioctl_ops; - qcam->vdev.release = video_device_release_empty; - qcam->vdev.ctrl_handler = &qcam->hdl; - video_set_drvdata(&qcam->vdev, qcam); - - mutex_init(&qcam->lock); - qcam->width = qcam->ccd_width = 320; - qcam->height = qcam->ccd_height = 240; - qcam->mode = QC_MILLIONS | QC_DECIMATION_1; - qcam->contrast = 192; - qcam->brightness = 240; - qcam->whitebal = 128; - qcam->top = 1; - qcam->left = 14; - return qcam; -} - -static int init_cqcam(struct parport *port) -{ - struct qcam *qcam; - struct v4l2_device *v4l2_dev; - - if (parport[0] != -1) { - /* The user gave specific instructions */ - int i, found = 0; - - for (i = 0; i < MAX_CAMS && parport[i] != -1; i++) { - if (parport[0] == port->number) - found = 1; - } - if (!found) - return -ENODEV; - } - - if (num_cams == MAX_CAMS) - return -ENOSPC; - - qcam = qcam_init(port); - if (qcam == NULL) - return -ENODEV; - - v4l2_dev = &qcam->v4l2_dev; - - parport_claim_or_block(qcam->pdev); - - qc_reset(qcam); - - if (probe && qc_detect(qcam) == 0) { - parport_release(qcam->pdev); - parport_unregister_device(qcam->pdev); - kfree(qcam); - return -ENODEV; - } - - qc_setup(qcam); - - parport_release(qcam->pdev); - - if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { - v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n", - qcam->pport->name); - parport_unregister_device(qcam->pdev); - kfree(qcam); - return -ENODEV; - } - - v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n", - video_device_node_name(&qcam->vdev), qcam->pport->name); - - qcams[num_cams++] = qcam; - - return 0; -} - -static void close_cqcam(struct qcam *qcam) -{ - video_unregister_device(&qcam->vdev); - v4l2_ctrl_handler_free(&qcam->hdl); - parport_unregister_device(qcam->pdev); - kfree(qcam); -} - -static void cq_attach(struct parport *port) -{ - init_cqcam(port); -} - -static void cq_detach(struct parport *port) -{ - /* Write this some day. */ -} - -static struct parport_driver cqcam_driver = { - .name = "cqcam", - .attach = cq_attach, - .detach = cq_detach, -}; - -static int __init cqcam_init(void) -{ - printk(KERN_INFO BANNER "\n"); - - return parport_register_driver(&cqcam_driver); -} - -static void __exit cqcam_cleanup(void) -{ - unsigned int i; - - for (i = 0; i < num_cams; i++) - close_cqcam(qcams[i]); - - parport_unregister_driver(&cqcam_driver); -} - -MODULE_AUTHOR("Philip Blundell "); -MODULE_DESCRIPTION(BANNER); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.0.4"); - -module_init(cqcam_init); -module_exit(cqcam_cleanup); diff --git a/drivers/staging/media/parport/pms.c b/drivers/staging/media/parport/pms.c deleted file mode 100644 index e6b497528cea..000000000000 --- a/drivers/staging/media/parport/pms.c +++ /dev/null @@ -1,1156 +0,0 @@ -/* - * Media Vision Pro Movie Studio - * or - * "all you need is an I2C bus some RAM and a prayer" - * - * This draws heavily on code - * - * (c) Wolfgang Koehler, wolf@first.gmd.de, Dec. 1994 - * Kiefernring 15 - * 14478 Potsdam, Germany - * - * Most of this code is directly derived from his userspace driver. - * His driver works so send any reports to alan@lxorguk.ukuu.org.uk - * unless the userspace driver also doesn't work for you... - * - * Changes: - * 25-11-2009 Hans Verkuil - * - converted to version 2 of the V4L API. - * 08/07/2003 Daniele Bellucci - * - pms_capture: report back -EFAULT - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.0.5"); - -#define MOTOROLA 1 -#define PHILIPS2 2 /* SAA7191 */ -#define PHILIPS1 3 -#define MVVMEMORYWIDTH 0x40 /* 512 bytes */ - -struct i2c_info { - u8 slave; - u8 sub; - u8 data; - u8 hits; -}; - -struct pms { - struct v4l2_device v4l2_dev; - struct video_device vdev; - struct v4l2_ctrl_handler hdl; - int height; - int width; - int depth; - int input; - struct mutex lock; - int i2c_count; - struct i2c_info i2cinfo[64]; - - int decoder; - int standard; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */ - v4l2_std_id std; - int io; - int data; - void __iomem *mem; -}; - -/* - * I/O ports and Shared Memory - */ - -static int io_port = 0x250; -module_param(io_port, int, 0); - -static int mem_base = 0xc8000; -module_param(mem_base, int, 0); - -static int video_nr = -1; -module_param(video_nr, int, 0); - - -static inline void mvv_write(struct pms *dev, u8 index, u8 value) -{ - outw(index | (value << 8), dev->io); -} - -static inline u8 mvv_read(struct pms *dev, u8 index) -{ - outb(index, dev->io); - return inb(dev->data); -} - -static int pms_i2c_stat(struct pms *dev, u8 slave) -{ - int counter = 0; - int i; - - outb(0x28, dev->io); - - while ((inb(dev->data) & 0x01) == 0) - if (counter++ == 256) - break; - - while ((inb(dev->data) & 0x01) != 0) - if (counter++ == 256) - break; - - outb(slave, dev->io); - - counter = 0; - while ((inb(dev->data) & 0x01) == 0) - if (counter++ == 256) - break; - - while ((inb(dev->data) & 0x01) != 0) - if (counter++ == 256) - break; - - for (i = 0; i < 12; i++) { - char st = inb(dev->data); - - if ((st & 2) != 0) - return -1; - if ((st & 1) == 0) - break; - } - outb(0x29, dev->io); - return inb(dev->data); -} - -static int pms_i2c_write(struct pms *dev, u16 slave, u16 sub, u16 data) -{ - int skip = 0; - int count; - int i; - - for (i = 0; i < dev->i2c_count; i++) { - if ((dev->i2cinfo[i].slave == slave) && - (dev->i2cinfo[i].sub == sub)) { - if (dev->i2cinfo[i].data == data) - skip = 1; - dev->i2cinfo[i].data = data; - i = dev->i2c_count + 1; - } - } - - if (i == dev->i2c_count && dev->i2c_count < 64) { - dev->i2cinfo[dev->i2c_count].slave = slave; - dev->i2cinfo[dev->i2c_count].sub = sub; - dev->i2cinfo[dev->i2c_count].data = data; - dev->i2c_count++; - } - - if (skip) - return 0; - - mvv_write(dev, 0x29, sub); - mvv_write(dev, 0x2A, data); - mvv_write(dev, 0x28, slave); - - outb(0x28, dev->io); - - count = 0; - while ((inb(dev->data) & 1) == 0) - if (count > 255) - break; - while ((inb(dev->data) & 1) != 0) - if (count > 255) - break; - - count = inb(dev->data); - - if (count & 2) - return -1; - return count; -} - -static int pms_i2c_read(struct pms *dev, int slave, int sub) -{ - int i; - - for (i = 0; i < dev->i2c_count; i++) { - if (dev->i2cinfo[i].slave == slave && dev->i2cinfo[i].sub == sub) - return dev->i2cinfo[i].data; - } - return 0; -} - - -static void pms_i2c_andor(struct pms *dev, int slave, int sub, int and, int or) -{ - u8 tmp; - - tmp = pms_i2c_read(dev, slave, sub); - tmp = (tmp & and) | or; - pms_i2c_write(dev, slave, sub, tmp); -} - -/* - * Control functions - */ - - -static void pms_videosource(struct pms *dev, short source) -{ - switch (dev->decoder) { - case MOTOROLA: - break; - case PHILIPS2: - pms_i2c_andor(dev, 0x8a, 0x06, 0x7f, source ? 0x80 : 0); - break; - case PHILIPS1: - break; - } - mvv_write(dev, 0x2E, 0x31); - /* Was: mvv_write(dev, 0x2E, source ? 0x31 : 0x30); - But could not make this work correctly. Only Composite input - worked for me. */ -} - -static void pms_hue(struct pms *dev, short hue) -{ - switch (dev->decoder) { - case MOTOROLA: - pms_i2c_write(dev, 0x8a, 0x00, hue); - break; - case PHILIPS2: - pms_i2c_write(dev, 0x8a, 0x07, hue); - break; - case PHILIPS1: - pms_i2c_write(dev, 0x42, 0x07, hue); - break; - } -} - -static void pms_saturation(struct pms *dev, short sat) -{ - switch (dev->decoder) { - case MOTOROLA: - pms_i2c_write(dev, 0x8a, 0x00, sat); - break; - case PHILIPS1: - pms_i2c_write(dev, 0x42, 0x12, sat); - break; - } -} - - -static void pms_contrast(struct pms *dev, short contrast) -{ - switch (dev->decoder) { - case MOTOROLA: - pms_i2c_write(dev, 0x8a, 0x00, contrast); - break; - case PHILIPS1: - pms_i2c_write(dev, 0x42, 0x13, contrast); - break; - } -} - -static void pms_brightness(struct pms *dev, short brightness) -{ - switch (dev->decoder) { - case MOTOROLA: - pms_i2c_write(dev, 0x8a, 0x00, brightness); - pms_i2c_write(dev, 0x8a, 0x00, brightness); - pms_i2c_write(dev, 0x8a, 0x00, brightness); - break; - case PHILIPS1: - pms_i2c_write(dev, 0x42, 0x19, brightness); - break; - } -} - - -static void pms_format(struct pms *dev, short format) -{ - int target; - - dev->standard = format; - - if (dev->decoder == PHILIPS1) - target = 0x42; - else if (dev->decoder == PHILIPS2) - target = 0x8a; - else - return; - - switch (format) { - case 0: /* Auto */ - pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00); - pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x80); - break; - case 1: /* NTSC */ - pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00); - pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x40); - break; - case 2: /* PAL */ - pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00); - pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00); - break; - case 3: /* SECAM */ - pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x01); - pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00); - break; - } -} - -#ifdef FOR_FUTURE_EXPANSION - -/* - * These features of the PMS card are not currently exposes. They - * could become a private v4l ioctl for PMSCONFIG or somesuch if - * people need it. We also don't yet use the PMS interrupt. - */ - -static void pms_hstart(struct pms *dev, short start) -{ - switch (dev->decoder) { - case PHILIPS1: - pms_i2c_write(dev, 0x8a, 0x05, start); - pms_i2c_write(dev, 0x8a, 0x18, start); - break; - case PHILIPS2: - pms_i2c_write(dev, 0x42, 0x05, start); - pms_i2c_write(dev, 0x42, 0x18, start); - break; - } -} - -/* - * Bandpass filters - */ - -static void pms_bandpass(struct pms *dev, short pass) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x06, 0xcf, (pass & 0x03) << 4); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x06, 0xcf, (pass & 0x03) << 4); -} - -static void pms_antisnow(struct pms *dev, short snow) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x06, 0xf3, (snow & 0x03) << 2); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x06, 0xf3, (snow & 0x03) << 2); -} - -static void pms_sharpness(struct pms *dev, short sharp) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x06, 0xfc, sharp & 0x03); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x06, 0xfc, sharp & 0x03); -} - -static void pms_chromaagc(struct pms *dev, short agc) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x0c, 0x9f, (agc & 0x03) << 5); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x0c, 0x9f, (agc & 0x03) << 5); -} - -static void pms_vertnoise(struct pms *dev, short noise) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x10, 0xfc, noise & 3); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x10, 0xfc, noise & 3); -} - -static void pms_forcecolour(struct pms *dev, short colour) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x0c, 0x7f, (colour & 1) << 7); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x0c, 0x7, (colour & 1) << 7); -} - -static void pms_antigamma(struct pms *dev, short gamma) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0xb8, 0x00, 0x7f, (gamma & 1) << 7); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x20, 0x7, (gamma & 1) << 7); -} - -static void pms_prefilter(struct pms *dev, short filter) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x06, 0xbf, (filter & 1) << 6); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x06, 0xbf, (filter & 1) << 6); -} - -static void pms_hfilter(struct pms *dev, short filter) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0xb8, 0x04, 0x1f, (filter & 7) << 5); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x24, 0x1f, (filter & 7) << 5); -} - -static void pms_vfilter(struct pms *dev, short filter) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0xb8, 0x08, 0x9f, (filter & 3) << 5); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x28, 0x9f, (filter & 3) << 5); -} - -static void pms_killcolour(struct pms *dev, short colour) -{ - if (dev->decoder == PHILIPS2) { - pms_i2c_andor(dev, 0x8a, 0x08, 0x07, (colour & 0x1f) << 3); - pms_i2c_andor(dev, 0x8a, 0x09, 0x07, (colour & 0x1f) << 3); - } else if (dev->decoder == PHILIPS1) { - pms_i2c_andor(dev, 0x42, 0x08, 0x07, (colour & 0x1f) << 3); - pms_i2c_andor(dev, 0x42, 0x09, 0x07, (colour & 0x1f) << 3); - } -} - -static void pms_chromagain(struct pms *dev, short chroma) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_write(dev, 0x8a, 0x11, chroma); - else if (dev->decoder == PHILIPS1) - pms_i2c_write(dev, 0x42, 0x11, chroma); -} - - -static void pms_spacialcompl(struct pms *dev, short data) -{ - mvv_write(dev, 0x3b, data); -} - -static void pms_spacialcomph(struct pms *dev, short data) -{ - mvv_write(dev, 0x3a, data); -} - -static void pms_vstart(struct pms *dev, short start) -{ - mvv_write(dev, 0x16, start); - mvv_write(dev, 0x17, (start >> 8) & 0x01); -} - -#endif - -static void pms_secamcross(struct pms *dev, short cross) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x0f, 0xdf, (cross & 1) << 5); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x0f, 0xdf, (cross & 1) << 5); -} - - -static void pms_swsense(struct pms *dev, short sense) -{ - if (dev->decoder == PHILIPS2) { - pms_i2c_write(dev, 0x8a, 0x0a, sense); - pms_i2c_write(dev, 0x8a, 0x0b, sense); - } else if (dev->decoder == PHILIPS1) { - pms_i2c_write(dev, 0x42, 0x0a, sense); - pms_i2c_write(dev, 0x42, 0x0b, sense); - } -} - - -static void pms_framerate(struct pms *dev, short frr) -{ - int fps = (dev->std & V4L2_STD_525_60) ? 30 : 25; - - if (frr == 0) - return; - fps = fps/frr; - mvv_write(dev, 0x14, 0x80 | fps); - mvv_write(dev, 0x15, 1); -} - -static void pms_vert(struct pms *dev, u8 deciden, u8 decinum) -{ - mvv_write(dev, 0x1c, deciden); /* Denominator */ - mvv_write(dev, 0x1d, decinum); /* Numerator */ -} - -/* - * Turn 16bit ratios into best small ratio the chipset can grok - */ - -static void pms_vertdeci(struct pms *dev, unsigned short decinum, unsigned short deciden) -{ - /* Knock it down by / 5 once */ - if (decinum % 5 == 0) { - deciden /= 5; - decinum /= 5; - } - /* - * 3's - */ - while (decinum % 3 == 0 && deciden % 3 == 0) { - deciden /= 3; - decinum /= 3; - } - /* - * 2's - */ - while (decinum % 2 == 0 && deciden % 2 == 0) { - decinum /= 2; - deciden /= 2; - } - /* - * Fudgyify - */ - while (deciden > 32) { - deciden /= 2; - decinum = (decinum + 1) / 2; - } - if (deciden == 32) - deciden--; - pms_vert(dev, deciden, decinum); -} - -static void pms_horzdeci(struct pms *dev, short decinum, short deciden) -{ - if (decinum <= 512) { - if (decinum % 5 == 0) { - decinum /= 5; - deciden /= 5; - } - } else { - decinum = 512; - deciden = 640; /* 768 would be ideal */ - } - - while (((decinum | deciden) & 1) == 0) { - decinum >>= 1; - deciden >>= 1; - } - while (deciden > 32) { - deciden >>= 1; - decinum = (decinum + 1) >> 1; - } - if (deciden == 32) - deciden--; - - mvv_write(dev, 0x24, 0x80 | deciden); - mvv_write(dev, 0x25, decinum); -} - -static void pms_resolution(struct pms *dev, short width, short height) -{ - int fg_height; - - fg_height = height; - if (fg_height > 280) - fg_height = 280; - - mvv_write(dev, 0x18, fg_height); - mvv_write(dev, 0x19, fg_height >> 8); - - if (dev->std & V4L2_STD_525_60) { - mvv_write(dev, 0x1a, 0xfc); - mvv_write(dev, 0x1b, 0x00); - if (height > fg_height) - pms_vertdeci(dev, 240, 240); - else - pms_vertdeci(dev, fg_height, 240); - } else { - mvv_write(dev, 0x1a, 0x1a); - mvv_write(dev, 0x1b, 0x01); - if (fg_height > 256) - pms_vertdeci(dev, 270, 270); - else - pms_vertdeci(dev, fg_height, 270); - } - mvv_write(dev, 0x12, 0); - mvv_write(dev, 0x13, MVVMEMORYWIDTH); - mvv_write(dev, 0x42, 0x00); - mvv_write(dev, 0x43, 0x00); - mvv_write(dev, 0x44, MVVMEMORYWIDTH); - - mvv_write(dev, 0x22, width + 8); - mvv_write(dev, 0x23, (width + 8) >> 8); - - if (dev->std & V4L2_STD_525_60) - pms_horzdeci(dev, width, 640); - else - pms_horzdeci(dev, width + 8, 768); - - mvv_write(dev, 0x30, mvv_read(dev, 0x30) & 0xfe); - mvv_write(dev, 0x08, mvv_read(dev, 0x08) | 0x01); - mvv_write(dev, 0x01, mvv_read(dev, 0x01) & 0xfd); - mvv_write(dev, 0x32, 0x00); - mvv_write(dev, 0x33, MVVMEMORYWIDTH); -} - - -/* - * Set Input - */ - -static void pms_vcrinput(struct pms *dev, short input) -{ - if (dev->decoder == PHILIPS2) - pms_i2c_andor(dev, 0x8a, 0x0d, 0x7f, (input & 1) << 7); - else if (dev->decoder == PHILIPS1) - pms_i2c_andor(dev, 0x42, 0x0d, 0x7f, (input & 1) << 7); -} - - -static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count) -{ - int y; - int dw = 2 * dev->width; - char *tmp; /* using a temp buffer is faster than direct */ - int cnt = 0; - int len = 0; - unsigned char r8 = 0x5; /* value for reg8 */ - - tmp = kmalloc(dw + 32, GFP_KERNEL); - if (!tmp) - return 0; - - if (rgb555) - r8 |= 0x20; /* else use untranslated rgb = 565 */ - mvv_write(dev, 0x08, r8); /* capture rgb555/565, init DRAM, PC enable */ - -/* printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */ - - for (y = 0; y < dev->height; y++) { - writeb(0, dev->mem); /* synchronisiert neue Zeile */ - - /* - * This is in truth a fifo, be very careful as if you - * forgot this odd things will occur 8) - */ - - memcpy_fromio(tmp, dev->mem, dw + 32); /* discard 16 word */ - cnt -= dev->height; - while (cnt <= 0) { - /* - * Don't copy too far - */ - int dt = dw; - if (dt + len > count) - dt = count - len; - cnt += dev->height; - if (copy_to_user(buf, tmp + 32, dt)) - return len ? len : -EFAULT; - buf += dt; - len += dt; - } - } - kfree(tmp); - return len; -} - - -/* - * Video4linux interfacing - */ - -static int pms_querycap(struct file *file, void *priv, - struct v4l2_capability *vcap) -{ - struct pms *dev = video_drvdata(file); - - strlcpy(vcap->driver, dev->v4l2_dev.name, sizeof(vcap->driver)); - strlcpy(vcap->card, "Mediavision PMS", sizeof(vcap->card)); - snprintf(vcap->bus_info, sizeof(vcap->bus_info), - "ISA:%s", dev->v4l2_dev.name); - vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; - vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; -} - -static int pms_enum_input(struct file *file, void *fh, struct v4l2_input *vin) -{ - static const char *inputs[4] = { - "Composite", - "S-Video", - "Composite (VCR)", - "S-Video (VCR)" - }; - - if (vin->index > 3) - return -EINVAL; - strlcpy(vin->name, inputs[vin->index], sizeof(vin->name)); - vin->type = V4L2_INPUT_TYPE_CAMERA; - vin->audioset = 0; - vin->tuner = 0; - vin->std = V4L2_STD_ALL; - vin->status = 0; - return 0; -} - -static int pms_g_input(struct file *file, void *fh, unsigned int *inp) -{ - struct pms *dev = video_drvdata(file); - - *inp = dev->input; - return 0; -} - -static int pms_s_input(struct file *file, void *fh, unsigned int inp) -{ - struct pms *dev = video_drvdata(file); - - if (inp > 3) - return -EINVAL; - - dev->input = inp; - pms_videosource(dev, inp & 1); - pms_vcrinput(dev, inp >> 1); - return 0; -} - -static int pms_g_std(struct file *file, void *fh, v4l2_std_id *std) -{ - struct pms *dev = video_drvdata(file); - - *std = dev->std; - return 0; -} - -static int pms_s_std(struct file *file, void *fh, v4l2_std_id std) -{ - struct pms *dev = video_drvdata(file); - int ret = 0; - - dev->std = std; - if (dev->std & V4L2_STD_NTSC) { - pms_framerate(dev, 30); - pms_secamcross(dev, 0); - pms_format(dev, 1); - } else if (dev->std & V4L2_STD_PAL) { - pms_framerate(dev, 25); - pms_secamcross(dev, 0); - pms_format(dev, 2); - } else if (dev->std & V4L2_STD_SECAM) { - pms_framerate(dev, 25); - pms_secamcross(dev, 1); - pms_format(dev, 2); - } else { - ret = -EINVAL; - } - /* - switch (v->mode) { - case VIDEO_MODE_AUTO: - pms_framerate(dev, 25); - pms_secamcross(dev, 0); - pms_format(dev, 0); - break; - }*/ - return ret; -} - -static int pms_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct pms *dev = container_of(ctrl->handler, struct pms, hdl); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - pms_brightness(dev, ctrl->val); - break; - case V4L2_CID_CONTRAST: - pms_contrast(dev, ctrl->val); - break; - case V4L2_CID_SATURATION: - pms_saturation(dev, ctrl->val); - break; - case V4L2_CID_HUE: - pms_hue(dev, ctrl->val); - break; - default: - ret = -EINVAL; - break; - } - return ret; -} - -static int pms_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct pms *dev = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - pix->width = dev->width; - pix->height = dev->height; - pix->pixelformat = dev->width == 15 ? - V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB565; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = 2 * dev->width; - pix->sizeimage = 2 * dev->width * dev->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SRGB; - return 0; -} - -static int pms_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - if (pix->height < 16 || pix->height > 480) - return -EINVAL; - if (pix->width < 16 || pix->width > 640) - return -EINVAL; - if (pix->pixelformat != V4L2_PIX_FMT_RGB555 && - pix->pixelformat != V4L2_PIX_FMT_RGB565) - return -EINVAL; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = 2 * pix->width; - pix->sizeimage = 2 * pix->width * pix->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SRGB; - return 0; -} - -static int pms_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct pms *dev = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - int ret = pms_try_fmt_vid_cap(file, fh, fmt); - - if (ret) - return ret; - dev->width = pix->width; - dev->height = pix->height; - dev->depth = (pix->pixelformat == V4L2_PIX_FMT_RGB555) ? 15 : 16; - pms_resolution(dev, dev->width, dev->height); - /* Ok we figured out what to use from our wide choice */ - return 0; -} - -static int pms_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) -{ - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "RGB 5:5:5", V4L2_PIX_FMT_RGB555, - { 0, 0, 0, 0 } - }, - { 1, 0, 0, - "RGB 5:6:5", V4L2_PIX_FMT_RGB565, - { 0, 0, 0, 0 } - }, - }; - enum v4l2_buf_type type = fmt->type; - - if (fmt->index > 1) - return -EINVAL; - - *fmt = formats[fmt->index]; - fmt->type = type; - return 0; -} - -static ssize_t pms_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct pms *dev = video_drvdata(file); - int len; - - len = pms_capture(dev, buf, (dev->depth == 15), count); - return len; -} - -static unsigned int pms_poll(struct file *file, struct poll_table_struct *wait) -{ - struct v4l2_fh *fh = file->private_data; - unsigned int res = POLLIN | POLLRDNORM; - - if (v4l2_event_pending(fh)) - res |= POLLPRI; - poll_wait(file, &fh->wait, wait); - return res; -} - -static const struct v4l2_file_operations pms_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = v4l2_fh_release, - .poll = pms_poll, - .unlocked_ioctl = video_ioctl2, - .read = pms_read, -}; - -static const struct v4l2_ioctl_ops pms_ioctl_ops = { - .vidioc_querycap = pms_querycap, - .vidioc_g_input = pms_g_input, - .vidioc_s_input = pms_s_input, - .vidioc_enum_input = pms_enum_input, - .vidioc_g_std = pms_g_std, - .vidioc_s_std = pms_s_std, - .vidioc_enum_fmt_vid_cap = pms_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = pms_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = pms_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = pms_try_fmt_vid_cap, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -/* - * Probe for and initialise the Mediavision PMS - */ - -static int init_mediavision(struct pms *dev) -{ - int idec, decst; - int i; - static const unsigned char i2c_defs[] = { - 0x4c, 0x30, 0x00, 0xe8, - 0xb6, 0xe2, 0x00, 0x00, - 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x78, 0x98, - 0x00, 0x00, 0x00, 0x00, - 0x34, 0x0a, 0xf4, 0xce, - 0xe4 - }; - - dev->mem = ioremap(mem_base, 0x800); - if (!dev->mem) - return -ENOMEM; - - if (!request_region(0x9a01, 1, "Mediavision PMS config")) { - printk(KERN_WARNING "mediavision: unable to detect: 0x9a01 in use.\n"); - iounmap(dev->mem); - return -EBUSY; - } - if (!request_region(dev->io, 3, "Mediavision PMS")) { - printk(KERN_WARNING "mediavision: I/O port %d in use.\n", dev->io); - release_region(0x9a01, 1); - iounmap(dev->mem); - return -EBUSY; - } - outb(0xb8, 0x9a01); /* Unlock */ - outb(dev->io >> 4, 0x9a01); /* Set IO port */ - - - decst = pms_i2c_stat(dev, 0x43); - - if (decst != -1) - idec = 2; - else if (pms_i2c_stat(dev, 0xb9) != -1) - idec = 3; - else if (pms_i2c_stat(dev, 0x8b) != -1) - idec = 1; - else - idec = 0; - - printk(KERN_INFO "PMS type is %d\n", idec); - if (idec == 0) { - release_region(dev->io, 3); - release_region(0x9a01, 1); - iounmap(dev->mem); - return -ENODEV; - } - - /* - * Ok we have a PMS of some sort - */ - - mvv_write(dev, 0x04, mem_base >> 12); /* Set the memory area */ - - /* Ok now load the defaults */ - - for (i = 0; i < 0x19; i++) { - if (i2c_defs[i] == 0xff) - pms_i2c_andor(dev, 0x8a, i, 0x07, 0x00); - else - pms_i2c_write(dev, 0x8a, i, i2c_defs[i]); - } - - pms_i2c_write(dev, 0xb8, 0x00, 0x12); - pms_i2c_write(dev, 0xb8, 0x04, 0x00); - pms_i2c_write(dev, 0xb8, 0x07, 0x00); - pms_i2c_write(dev, 0xb8, 0x08, 0x00); - pms_i2c_write(dev, 0xb8, 0x09, 0xff); - pms_i2c_write(dev, 0xb8, 0x0a, 0x00); - pms_i2c_write(dev, 0xb8, 0x0b, 0x10); - pms_i2c_write(dev, 0xb8, 0x10, 0x03); - - mvv_write(dev, 0x01, 0x00); - mvv_write(dev, 0x05, 0xa0); - mvv_write(dev, 0x08, 0x25); - mvv_write(dev, 0x09, 0x00); - mvv_write(dev, 0x0a, 0x20 | MVVMEMORYWIDTH); - - mvv_write(dev, 0x10, 0x02); - mvv_write(dev, 0x1e, 0x0c); - mvv_write(dev, 0x1f, 0x03); - mvv_write(dev, 0x26, 0x06); - - mvv_write(dev, 0x2b, 0x00); - mvv_write(dev, 0x2c, 0x20); - mvv_write(dev, 0x2d, 0x00); - mvv_write(dev, 0x2f, 0x70); - mvv_write(dev, 0x32, 0x00); - mvv_write(dev, 0x33, MVVMEMORYWIDTH); - mvv_write(dev, 0x34, 0x00); - mvv_write(dev, 0x35, 0x00); - mvv_write(dev, 0x3a, 0x80); - mvv_write(dev, 0x3b, 0x10); - mvv_write(dev, 0x20, 0x00); - mvv_write(dev, 0x21, 0x00); - mvv_write(dev, 0x30, 0x22); - return 0; -} - -/* - * Initialization and module stuff - */ - -#ifndef MODULE -static int enable; -module_param(enable, int, 0); -#endif - -static const struct v4l2_ctrl_ops pms_ctrl_ops = { - .s_ctrl = pms_s_ctrl, -}; - -static int pms_probe(struct device *pdev, unsigned int card) -{ - struct pms *dev; - struct v4l2_device *v4l2_dev; - struct v4l2_ctrl_handler *hdl; - int res; - -#ifndef MODULE - if (!enable) { - pr_err("PMS: not enabled, use pms.enable=1 to probe\n"); - return -ENODEV; - } -#endif - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) - return -ENOMEM; - - dev->decoder = PHILIPS2; - dev->io = io_port; - dev->data = io_port + 1; - v4l2_dev = &dev->v4l2_dev; - hdl = &dev->hdl; - - res = v4l2_device_register(pdev, v4l2_dev); - if (res < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - goto free_dev; - } - v4l2_info(v4l2_dev, "Mediavision Pro Movie Studio driver 0.05\n"); - - res = init_mediavision(dev); - if (res) { - v4l2_err(v4l2_dev, "Board not found.\n"); - goto free_io; - } - - v4l2_ctrl_handler_init(hdl, 4); - v4l2_ctrl_new_std(hdl, &pms_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 139); - v4l2_ctrl_new_std(hdl, &pms_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, 70); - v4l2_ctrl_new_std(hdl, &pms_ctrl_ops, - V4L2_CID_SATURATION, 0, 255, 1, 64); - v4l2_ctrl_new_std(hdl, &pms_ctrl_ops, - V4L2_CID_HUE, 0, 255, 1, 0); - if (hdl->error) { - res = hdl->error; - goto free_hdl; - } - - mutex_init(&dev->lock); - strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); - dev->vdev.v4l2_dev = v4l2_dev; - dev->vdev.ctrl_handler = hdl; - dev->vdev.fops = &pms_fops; - dev->vdev.ioctl_ops = &pms_ioctl_ops; - dev->vdev.release = video_device_release_empty; - dev->vdev.lock = &dev->lock; - dev->vdev.tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; - video_set_drvdata(&dev->vdev, dev); - dev->std = V4L2_STD_NTSC_M; - dev->height = 240; - dev->width = 320; - dev->depth = 16; - pms_swsense(dev, 75); - pms_resolution(dev, 320, 240); - pms_videosource(dev, 0); - pms_vcrinput(dev, 0); - v4l2_ctrl_handler_setup(hdl); - res = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr); - if (res >= 0) - return 0; - -free_hdl: - v4l2_ctrl_handler_free(hdl); - v4l2_device_unregister(&dev->v4l2_dev); -free_io: - release_region(dev->io, 3); - release_region(0x9a01, 1); - iounmap(dev->mem); -free_dev: - kfree(dev); - return res; -} - -static int pms_remove(struct device *pdev, unsigned int card) -{ - struct pms *dev = dev_get_drvdata(pdev); - - video_unregister_device(&dev->vdev); - v4l2_ctrl_handler_free(&dev->hdl); - release_region(dev->io, 3); - release_region(0x9a01, 1); - iounmap(dev->mem); - return 0; -} - -static struct isa_driver pms_driver = { - .probe = pms_probe, - .remove = pms_remove, - .driver = { - .name = "pms", - }, -}; - -static int __init pms_init(void) -{ - return isa_register_driver(&pms_driver, 1); -} - -static void __exit pms_exit(void) -{ - isa_unregister_driver(&pms_driver); -} - -module_init(pms_init); -module_exit(pms_exit); diff --git a/drivers/staging/media/parport/w9966.c b/drivers/staging/media/parport/w9966.c deleted file mode 100644 index f7502f3a6a3c..000000000000 --- a/drivers/staging/media/parport/w9966.c +++ /dev/null @@ -1,980 +0,0 @@ -/* - Winbond w9966cf Webcam parport driver. - - Version 0.33 - - Copyright (C) 2001 Jakob Kemi - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -/* - Supported devices: - *Lifeview FlyCam Supra (using the Philips saa7111a chip) - - Does any other model using the w9966 interface chip exist ? - - Todo: - - *Add a working EPP mode, since DMA ECP read isn't implemented - in the parport drivers. (That's why it's so sloow) - - *Add support for other ccd-control chips than the saa7111 - please send me feedback on what kind of chips you have. - - *Add proper probing. I don't know what's wrong with the IEEE1284 - parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID) - and nibble read seems to be broken for some peripherals. - - *Add probing for onboard SRAM, port directions etc. (if possible) - - *Add support for the hardware compressed modes (maybe using v4l2) - - *Fix better support for the capture window (no skewed images, v4l - interface to capt. window) - - *Probably some bugs that I don't know of - - Please support me by sending feedback! - - Changes: - - Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE - and owner support for newer module locks -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/*#define DEBUG*/ /* Undef me for production */ - -#ifdef DEBUG -#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a) -#else -#define DPRINTF(x...) -#endif - -/* - * Defines, simple typedefs etc. - */ - -#define W9966_DRIVERNAME "W9966CF Webcam" -#define W9966_MAXCAMS 4 /* Maximum number of cameras */ -#define W9966_RBUFFER 2048 /* Read buffer (must be an even number) */ -#define W9966_SRAMSIZE 131072 /* 128kb */ -#define W9966_SRAMID 0x02 /* check w9966cf.pdf */ - -/* Empirically determined window limits */ -#define W9966_WND_MIN_X 16 -#define W9966_WND_MIN_Y 14 -#define W9966_WND_MAX_X 705 -#define W9966_WND_MAX_Y 253 -#define W9966_WND_MAX_W (W9966_WND_MAX_X - W9966_WND_MIN_X) -#define W9966_WND_MAX_H (W9966_WND_MAX_Y - W9966_WND_MIN_Y) - -/* Keep track of our current state */ -#define W9966_STATE_PDEV 0x01 -#define W9966_STATE_CLAIMED 0x02 -#define W9966_STATE_VDEV 0x04 - -#define W9966_I2C_W_ID 0x48 -#define W9966_I2C_R_ID 0x49 -#define W9966_I2C_R_DATA 0x08 -#define W9966_I2C_R_CLOCK 0x04 -#define W9966_I2C_W_DATA 0x02 -#define W9966_I2C_W_CLOCK 0x01 - -struct w9966 { - struct v4l2_device v4l2_dev; - struct v4l2_ctrl_handler hdl; - unsigned char dev_state; - unsigned char i2c_state; - unsigned short ppmode; - struct parport *pport; - struct pardevice *pdev; - struct video_device vdev; - unsigned short width; - unsigned short height; - unsigned char brightness; - signed char contrast; - signed char color; - signed char hue; - struct mutex lock; -}; - -/* - * Module specific properties - */ - -MODULE_AUTHOR("Jakob Kemi "); -MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.33.1"); - -#ifdef MODULE -static char *pardev[] = {[0 ... W9966_MAXCAMS] = ""}; -#else -static char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"}; -#endif -module_param_array(pardev, charp, NULL, 0); -MODULE_PARM_DESC(pardev, "pardev: where to search for\n" - "\teach camera. 'aggressive' means brute-force search.\n" - "\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n" - "\tcam 1 to parport3 and search every parport for cam 2 etc..."); - -static int parmode; -module_param(parmode, int, 0); -MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp"); - -static int video_nr = -1; -module_param(video_nr, int, 0); - -static struct w9966 w9966_cams[W9966_MAXCAMS]; - -/* - * Private function defines - */ - - -/* Set camera phase flags, so we know what to uninit when terminating */ -static inline void w9966_set_state(struct w9966 *cam, int mask, int val) -{ - cam->dev_state = (cam->dev_state & ~mask) ^ val; -} - -/* Get camera phase flags */ -static inline int w9966_get_state(struct w9966 *cam, int mask, int val) -{ - return ((cam->dev_state & mask) == val); -} - -/* Claim parport for ourself */ -static void w9966_pdev_claim(struct w9966 *cam) -{ - if (w9966_get_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED)) - return; - parport_claim_or_block(cam->pdev); - w9966_set_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED); -} - -/* Release parport for others to use */ -static void w9966_pdev_release(struct w9966 *cam) -{ - if (w9966_get_state(cam, W9966_STATE_CLAIMED, 0)) - return; - parport_release(cam->pdev); - w9966_set_state(cam, W9966_STATE_CLAIMED, 0); -} - -/* Read register from W9966 interface-chip - Expects a claimed pdev - -1 on error, else register data (byte) */ -static int w9966_read_reg(struct w9966 *cam, int reg) -{ - /* ECP, read, regtransfer, REG, REG, REG, REG, REG */ - const unsigned char addr = 0x80 | (reg & 0x1f); - unsigned char val; - - if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) - return -1; - if (parport_write(cam->pport, &addr, 1) != 1) - return -1; - if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) - return -1; - if (parport_read(cam->pport, &val, 1) != 1) - return -1; - - return val; -} - -/* Write register to W9966 interface-chip - Expects a claimed pdev - -1 on error */ -static int w9966_write_reg(struct w9966 *cam, int reg, int data) -{ - /* ECP, write, regtransfer, REG, REG, REG, REG, REG */ - const unsigned char addr = 0xc0 | (reg & 0x1f); - const unsigned char val = data; - - if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0) - return -1; - if (parport_write(cam->pport, &addr, 1) != 1) - return -1; - if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0) - return -1; - if (parport_write(cam->pport, &val, 1) != 1) - return -1; - - return 0; -} - -/* - * Ugly and primitive i2c protocol functions - */ - -/* Sets the data line on the i2c bus. - Expects a claimed pdev. */ -static void w9966_i2c_setsda(struct w9966 *cam, int state) -{ - if (state) - cam->i2c_state |= W9966_I2C_W_DATA; - else - cam->i2c_state &= ~W9966_I2C_W_DATA; - - w9966_write_reg(cam, 0x18, cam->i2c_state); - udelay(5); -} - -/* Get peripheral clock line - Expects a claimed pdev. */ -static int w9966_i2c_getscl(struct w9966 *cam) -{ - const unsigned char state = w9966_read_reg(cam, 0x18); - return ((state & W9966_I2C_R_CLOCK) > 0); -} - -/* Sets the clock line on the i2c bus. - Expects a claimed pdev. -1 on error */ -static int w9966_i2c_setscl(struct w9966 *cam, int state) -{ - unsigned long timeout; - - if (state) - cam->i2c_state |= W9966_I2C_W_CLOCK; - else - cam->i2c_state &= ~W9966_I2C_W_CLOCK; - - w9966_write_reg(cam, 0x18, cam->i2c_state); - udelay(5); - - /* we go to high, we also expect the peripheral to ack. */ - if (state) { - timeout = jiffies + 100; - while (!w9966_i2c_getscl(cam)) { - if (time_after(jiffies, timeout)) - return -1; - } - } - return 0; -} - -#if 0 -/* Get peripheral data line - Expects a claimed pdev. */ -static int w9966_i2c_getsda(struct w9966 *cam) -{ - const unsigned char state = w9966_read_reg(cam, 0x18); - return ((state & W9966_I2C_R_DATA) > 0); -} -#endif - -/* Write a byte with ack to the i2c bus. - Expects a claimed pdev. -1 on error */ -static int w9966_i2c_wbyte(struct w9966 *cam, int data) -{ - int i; - - for (i = 7; i >= 0; i--) { - w9966_i2c_setsda(cam, (data >> i) & 0x01); - - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - w9966_i2c_setscl(cam, 0); - } - - w9966_i2c_setsda(cam, 1); - - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - w9966_i2c_setscl(cam, 0); - - return 0; -} - -/* Read a data byte with ack from the i2c-bus - Expects a claimed pdev. -1 on error */ -#if 0 -static int w9966_i2c_rbyte(struct w9966 *cam) -{ - unsigned char data = 0x00; - int i; - - w9966_i2c_setsda(cam, 1); - - for (i = 0; i < 8; i++) { - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - data = data << 1; - if (w9966_i2c_getsda(cam)) - data |= 0x01; - - w9966_i2c_setscl(cam, 0); - } - return data; -} -#endif - -/* Read a register from the i2c device. - Expects claimed pdev. -1 on error */ -#if 0 -static int w9966_read_reg_i2c(struct w9966 *cam, int reg) -{ - int data; - - w9966_i2c_setsda(cam, 0); - w9966_i2c_setscl(cam, 0); - - if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || - w9966_i2c_wbyte(cam, reg) == -1) - return -1; - - w9966_i2c_setsda(cam, 1); - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - w9966_i2c_setsda(cam, 0); - w9966_i2c_setscl(cam, 0); - - if (w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1) - return -1; - data = w9966_i2c_rbyte(cam); - if (data == -1) - return -1; - - w9966_i2c_setsda(cam, 0); - - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - w9966_i2c_setsda(cam, 1); - - return data; -} -#endif - -/* Write a register to the i2c device. - Expects claimed pdev. -1 on error */ -static int w9966_write_reg_i2c(struct w9966 *cam, int reg, int data) -{ - w9966_i2c_setsda(cam, 0); - w9966_i2c_setscl(cam, 0); - - if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 || - w9966_i2c_wbyte(cam, reg) == -1 || - w9966_i2c_wbyte(cam, data) == -1) - return -1; - - w9966_i2c_setsda(cam, 0); - if (w9966_i2c_setscl(cam, 1) == -1) - return -1; - - w9966_i2c_setsda(cam, 1); - - return 0; -} - -/* Find a good length for capture window (used both for W and H) - A bit ugly but pretty functional. The capture length - have to match the downscale */ -static int w9966_findlen(int near, int size, int maxlen) -{ - int bestlen = size; - int besterr = abs(near - bestlen); - int len; - - for (len = size + 1; len < maxlen; len++) { - int err; - if (((64 * size) % len) != 0) - continue; - - err = abs(near - len); - - /* Only continue as long as we keep getting better values */ - if (err > besterr) - break; - - besterr = err; - bestlen = len; - } - - return bestlen; -} - -/* Modify capture window (if necessary) - and calculate downscaling - Return -1 on error */ -static int w9966_calcscale(int size, int min, int max, int *beg, int *end, unsigned char *factor) -{ - int maxlen = max - min; - int len = *end - *beg + 1; - int newlen = w9966_findlen(len, size, maxlen); - int err = newlen - len; - - /* Check for bad format */ - if (newlen > maxlen || newlen < size) - return -1; - - /* Set factor (6 bit fixed) */ - *factor = (64 * size) / newlen; - if (*factor == 64) - *factor = 0x00; /* downscale is disabled */ - else - *factor |= 0x80; /* set downscale-enable bit */ - - /* Modify old beginning and end */ - *beg -= err / 2; - *end += err - (err / 2); - - /* Move window if outside borders */ - if (*beg < min) { - *end += min - *beg; - *beg += min - *beg; - } - if (*end > max) { - *beg -= *end - max; - *end -= *end - max; - } - - return 0; -} - -/* Setup the cameras capture window etc. - Expects a claimed pdev - return -1 on error */ -static int w9966_setup(struct w9966 *cam, int x1, int y1, int x2, int y2, int w, int h) -{ - unsigned int i; - unsigned int enh_s, enh_e; - unsigned char scale_x, scale_y; - unsigned char regs[0x1c]; - unsigned char saa7111_regs[] = { - 0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00, - 0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00, - 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0 - }; - - - if (w * h * 2 > W9966_SRAMSIZE) { - DPRINTF("capture window exceeds SRAM size!.\n"); - w = 200; h = 160; /* Pick default values */ - } - - w &= ~0x1; - if (w < 2) - w = 2; - if (h < 1) - h = 1; - if (w > W9966_WND_MAX_W) - w = W9966_WND_MAX_W; - if (h > W9966_WND_MAX_H) - h = W9966_WND_MAX_H; - - cam->width = w; - cam->height = h; - - enh_s = 0; - enh_e = w * h * 2; - - /* Modify capture window if necessary and calculate downscaling */ - if (w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 || - w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0) - return -1; - - DPRINTF("%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n", - w, h, x1, x2, y1, y2, scale_x & ~0x80, scale_y & ~0x80); - - /* Setup registers */ - regs[0x00] = 0x00; /* Set normal operation */ - regs[0x01] = 0x18; /* Capture mode */ - regs[0x02] = scale_y; /* V-scaling */ - regs[0x03] = scale_x; /* H-scaling */ - - /* Capture window */ - regs[0x04] = (x1 & 0x0ff); /* X-start (8 low bits) */ - regs[0x05] = (x1 & 0x300)>>8; /* X-start (2 high bits) */ - regs[0x06] = (y1 & 0x0ff); /* Y-start (8 low bits) */ - regs[0x07] = (y1 & 0x300)>>8; /* Y-start (2 high bits) */ - regs[0x08] = (x2 & 0x0ff); /* X-end (8 low bits) */ - regs[0x09] = (x2 & 0x300)>>8; /* X-end (2 high bits) */ - regs[0x0a] = (y2 & 0x0ff); /* Y-end (8 low bits) */ - - regs[0x0c] = W9966_SRAMID; /* SRAM-banks (1x 128kb) */ - - /* Enhancement layer */ - regs[0x0d] = (enh_s & 0x000ff); /* Enh. start (0-7) */ - regs[0x0e] = (enh_s & 0x0ff00) >> 8; /* Enh. start (8-15) */ - regs[0x0f] = (enh_s & 0x70000) >> 16; /* Enh. start (16-17/18??) */ - regs[0x10] = (enh_e & 0x000ff); /* Enh. end (0-7) */ - regs[0x11] = (enh_e & 0x0ff00) >> 8; /* Enh. end (8-15) */ - regs[0x12] = (enh_e & 0x70000) >> 16; /* Enh. end (16-17/18??) */ - - /* Misc */ - regs[0x13] = 0x40; /* VEE control (raw 4:2:2) */ - regs[0x17] = 0x00; /* ??? */ - regs[0x18] = cam->i2c_state = 0x00; /* Serial bus */ - regs[0x19] = 0xff; /* I/O port direction control */ - regs[0x1a] = 0xff; /* I/O port data register */ - regs[0x1b] = 0x10; /* ??? */ - - /* SAA7111 chip settings */ - saa7111_regs[0x0a] = cam->brightness; - saa7111_regs[0x0b] = cam->contrast; - saa7111_regs[0x0c] = cam->color; - saa7111_regs[0x0d] = cam->hue; - - /* Reset (ECP-fifo & serial-bus) */ - if (w9966_write_reg(cam, 0x00, 0x03) == -1) - return -1; - - /* Write regs to w9966cf chip */ - for (i = 0; i < 0x1c; i++) - if (w9966_write_reg(cam, i, regs[i]) == -1) - return -1; - - /* Write regs to saa7111 chip */ - for (i = 0; i < 0x20; i++) - if (w9966_write_reg_i2c(cam, i, saa7111_regs[i]) == -1) - return -1; - - return 0; -} - -/* - * Video4linux interfacing - */ - -static int cam_querycap(struct file *file, void *priv, - struct v4l2_capability *vcap) -{ - struct w9966 *cam = video_drvdata(file); - - strlcpy(vcap->driver, cam->v4l2_dev.name, sizeof(vcap->driver)); - strlcpy(vcap->card, W9966_DRIVERNAME, sizeof(vcap->card)); - strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info)); - vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; - vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; -} - -static int cam_enum_input(struct file *file, void *fh, struct v4l2_input *vin) -{ - if (vin->index > 0) - return -EINVAL; - strlcpy(vin->name, "Camera", sizeof(vin->name)); - vin->type = V4L2_INPUT_TYPE_CAMERA; - vin->audioset = 0; - vin->tuner = 0; - vin->std = 0; - vin->status = 0; - return 0; -} - -static int cam_g_input(struct file *file, void *fh, unsigned int *inp) -{ - *inp = 0; - return 0; -} - -static int cam_s_input(struct file *file, void *fh, unsigned int inp) -{ - return (inp > 0) ? -EINVAL : 0; -} - -static int cam_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct w9966 *cam = - container_of(ctrl->handler, struct w9966, hdl); - int ret = 0; - - mutex_lock(&cam->lock); - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - cam->brightness = ctrl->val; - break; - case V4L2_CID_CONTRAST: - cam->contrast = ctrl->val; - break; - case V4L2_CID_SATURATION: - cam->color = ctrl->val; - break; - case V4L2_CID_HUE: - cam->hue = ctrl->val; - break; - default: - ret = -EINVAL; - break; - } - - if (ret == 0) { - w9966_pdev_claim(cam); - - if (w9966_write_reg_i2c(cam, 0x0a, cam->brightness) == -1 || - w9966_write_reg_i2c(cam, 0x0b, cam->contrast) == -1 || - w9966_write_reg_i2c(cam, 0x0c, cam->color) == -1 || - w9966_write_reg_i2c(cam, 0x0d, cam->hue) == -1) { - ret = -EIO; - } - - w9966_pdev_release(cam); - } - mutex_unlock(&cam->lock); - return ret; -} - -static int cam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct w9966 *cam = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - pix->width = cam->width; - pix->height = cam->height; - pix->pixelformat = V4L2_PIX_FMT_YUYV; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = 2 * cam->width; - pix->sizeimage = 2 * cam->width * cam->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - return 0; -} - -static int cam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - if (pix->width < 2) - pix->width = 2; - if (pix->height < 1) - pix->height = 1; - if (pix->width > W9966_WND_MAX_W) - pix->width = W9966_WND_MAX_W; - if (pix->height > W9966_WND_MAX_H) - pix->height = W9966_WND_MAX_H; - pix->pixelformat = V4L2_PIX_FMT_YUYV; - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = 2 * pix->width; - pix->sizeimage = 2 * pix->width * pix->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - return 0; -} - -static int cam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct w9966 *cam = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - int ret = cam_try_fmt_vid_cap(file, fh, fmt); - - if (ret) - return ret; - - mutex_lock(&cam->lock); - /* Update camera regs */ - w9966_pdev_claim(cam); - ret = w9966_setup(cam, 0, 0, 1023, 1023, pix->width, pix->height); - w9966_pdev_release(cam); - mutex_unlock(&cam->lock); - return ret; -} - -static int cam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) -{ - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "YUV 4:2:2", V4L2_PIX_FMT_YUYV, - { 0, 0, 0, 0 } - }, - }; - enum v4l2_buf_type type = fmt->type; - - if (fmt->index > 0) - return -EINVAL; - - *fmt = formats[fmt->index]; - fmt->type = type; - return 0; -} - -/* Capture data */ -static ssize_t w9966_v4l_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct w9966 *cam = video_drvdata(file); - unsigned char addr = 0xa0; /* ECP, read, CCD-transfer, 00000 */ - unsigned char __user *dest = (unsigned char __user *)buf; - unsigned long dleft = count; - unsigned char *tbuf; - - /* Why would anyone want more than this?? */ - if (count > cam->width * cam->height * 2) - return -EINVAL; - - mutex_lock(&cam->lock); - w9966_pdev_claim(cam); - w9966_write_reg(cam, 0x00, 0x02); /* Reset ECP-FIFO buffer */ - w9966_write_reg(cam, 0x00, 0x00); /* Return to normal operation */ - w9966_write_reg(cam, 0x01, 0x98); /* Enable capture */ - - /* write special capture-addr and negotiate into data transfer */ - if ((parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0) || - (parport_write(cam->pport, &addr, 1) != 1) || - (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0)) { - w9966_pdev_release(cam); - mutex_unlock(&cam->lock); - return -EFAULT; - } - - tbuf = kmalloc(W9966_RBUFFER, GFP_KERNEL); - if (tbuf == NULL) { - count = -ENOMEM; - goto out; - } - - while (dleft > 0) { - unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft; - - if (parport_read(cam->pport, tbuf, tsize) < tsize) { - count = -EFAULT; - goto out; - } - if (copy_to_user(dest, tbuf, tsize) != 0) { - count = -EFAULT; - goto out; - } - dest += tsize; - dleft -= tsize; - } - - w9966_write_reg(cam, 0x01, 0x18); /* Disable capture */ - -out: - kfree(tbuf); - w9966_pdev_release(cam); - mutex_unlock(&cam->lock); - - return count; -} - -static const struct v4l2_file_operations w9966_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = v4l2_fh_release, - .poll = v4l2_ctrl_poll, - .unlocked_ioctl = video_ioctl2, - .read = w9966_v4l_read, -}; - -static const struct v4l2_ioctl_ops w9966_ioctl_ops = { - .vidioc_querycap = cam_querycap, - .vidioc_g_input = cam_g_input, - .vidioc_s_input = cam_s_input, - .vidioc_enum_input = cam_enum_input, - .vidioc_enum_fmt_vid_cap = cam_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = cam_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = cam_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = cam_try_fmt_vid_cap, - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static const struct v4l2_ctrl_ops cam_ctrl_ops = { - .s_ctrl = cam_s_ctrl, -}; - - -/* Initialize camera device. Setup all internal flags, set a - default video mode, setup ccd-chip, register v4l device etc.. - Also used for 'probing' of hardware. - -1 on error */ -static int w9966_init(struct w9966 *cam, struct parport *port) -{ - struct v4l2_device *v4l2_dev = &cam->v4l2_dev; - - if (cam->dev_state != 0) - return -1; - - strlcpy(v4l2_dev->name, "w9966", sizeof(v4l2_dev->name)); - - if (v4l2_device_register(NULL, v4l2_dev) < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return -1; - } - - v4l2_ctrl_handler_init(&cam->hdl, 4); - v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); - v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops, - V4L2_CID_CONTRAST, -64, 64, 1, 64); - v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops, - V4L2_CID_SATURATION, -64, 64, 1, 64); - v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); - if (cam->hdl.error) { - v4l2_err(v4l2_dev, "couldn't register controls\n"); - return -1; - } - cam->pport = port; - cam->brightness = 128; - cam->contrast = 64; - cam->color = 64; - cam->hue = 0; - - /* Select requested transfer mode */ - switch (parmode) { - default: /* Auto-detect (priority: hw-ecp, hw-epp, sw-ecp) */ - case 0: - if (port->modes & PARPORT_MODE_ECP) - cam->ppmode = IEEE1284_MODE_ECP; - else if (port->modes & PARPORT_MODE_EPP) - cam->ppmode = IEEE1284_MODE_EPP; - else - cam->ppmode = IEEE1284_MODE_ECP; - break; - case 1: /* hw- or sw-ecp */ - cam->ppmode = IEEE1284_MODE_ECP; - break; - case 2: /* hw- or sw-epp */ - cam->ppmode = IEEE1284_MODE_EPP; - break; - } - - /* Tell the parport driver that we exists */ - cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL); - if (cam->pdev == NULL) { - DPRINTF("parport_register_device() failed\n"); - return -1; - } - w9966_set_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV); - - w9966_pdev_claim(cam); - - /* Setup a default capture mode */ - if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) { - DPRINTF("w9966_setup() failed.\n"); - return -1; - } - - w9966_pdev_release(cam); - - /* Fill in the video_device struct and register us to v4l */ - strlcpy(cam->vdev.name, W9966_DRIVERNAME, sizeof(cam->vdev.name)); - cam->vdev.v4l2_dev = v4l2_dev; - cam->vdev.fops = &w9966_fops; - cam->vdev.ioctl_ops = &w9966_ioctl_ops; - cam->vdev.release = video_device_release_empty; - cam->vdev.ctrl_handler = &cam->hdl; - video_set_drvdata(&cam->vdev, cam); - - mutex_init(&cam->lock); - - if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) - return -1; - - w9966_set_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); - - /* All ok */ - v4l2_info(v4l2_dev, "Found and initialized a webcam on %s.\n", - cam->pport->name); - return 0; -} - - -/* Terminate everything gracefully */ -static void w9966_term(struct w9966 *cam) -{ - /* Unregister from v4l */ - if (w9966_get_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) { - video_unregister_device(&cam->vdev); - w9966_set_state(cam, W9966_STATE_VDEV, 0); - } - - v4l2_ctrl_handler_free(&cam->hdl); - - /* Terminate from IEEE1284 mode and release pdev block */ - if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { - w9966_pdev_claim(cam); - parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT); - w9966_pdev_release(cam); - } - - /* Unregister from parport */ - if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) { - parport_unregister_device(cam->pdev); - w9966_set_state(cam, W9966_STATE_PDEV, 0); - } - memset(cam, 0, sizeof(*cam)); -} - - -/* Called once for every parport on init */ -static void w9966_attach(struct parport *port) -{ - int i; - - for (i = 0; i < W9966_MAXCAMS; i++) { - if (w9966_cams[i].dev_state != 0) /* Cam is already assigned */ - continue; - if (strcmp(pardev[i], "aggressive") == 0 || strcmp(pardev[i], port->name) == 0) { - if (w9966_init(&w9966_cams[i], port) != 0) - w9966_term(&w9966_cams[i]); - break; /* return */ - } - } -} - -/* Called once for every parport on termination */ -static void w9966_detach(struct parport *port) -{ - int i; - - for (i = 0; i < W9966_MAXCAMS; i++) - if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port) - w9966_term(&w9966_cams[i]); -} - - -static struct parport_driver w9966_ppd = { - .name = W9966_DRIVERNAME, - .attach = w9966_attach, - .detach = w9966_detach, -}; - -/* Module entry point */ -static int __init w9966_mod_init(void) -{ - int i; - - for (i = 0; i < W9966_MAXCAMS; i++) - w9966_cams[i].dev_state = 0; - - return parport_register_driver(&w9966_ppd); -} - -/* Module cleanup */ -static void __exit w9966_mod_term(void) -{ - parport_unregister_driver(&w9966_ppd); -} - -module_init(w9966_mod_init); -module_exit(w9966_mod_term); diff --git a/drivers/staging/media/tlg2300/Kconfig b/drivers/staging/media/tlg2300/Kconfig deleted file mode 100644 index 81784c6f7b88..000000000000 --- a/drivers/staging/media/tlg2300/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config VIDEO_TLG2300 - tristate "Telegent TLG2300 USB video capture support (Deprecated)" - depends on VIDEO_DEV && I2C && SND && DVB_CORE - select VIDEO_TUNER - select VIDEO_TVEEPROM - depends on RC_CORE - select VIDEOBUF_VMALLOC - select SND_PCM - select VIDEOBUF_DVB - - ---help--- - This is a video4linux driver for Telegent tlg2300 based TV cards. - The driver supports V4L2, DVB-T and radio. - - This driver is deprecated and will be removed soon. If you have - hardware for this and you want to work on this driver, then contact - the linux-media mailinglist. - - To compile this driver as a module, choose M here: the - module will be called poseidon diff --git a/drivers/staging/media/tlg2300/Makefile b/drivers/staging/media/tlg2300/Makefile deleted file mode 100644 index 137f8e38cdec..000000000000 --- a/drivers/staging/media/tlg2300/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -poseidon-objs := pd-video.o pd-alsa.o pd-dvb.o pd-radio.o pd-main.o - -obj-$(CONFIG_VIDEO_TLG2300) += poseidon.o - -ccflags-y += -Idrivers/media/i2c -ccflags-y += -Idrivers/media/tuners -ccflags-y += -Idrivers/media/dvb-core -ccflags-y += -Idrivers/media/dvb-frontends - diff --git a/drivers/staging/media/tlg2300/pd-alsa.c b/drivers/staging/media/tlg2300/pd-alsa.c deleted file mode 100644 index dd8fe100590f..000000000000 --- a/drivers/staging/media/tlg2300/pd-alsa.c +++ /dev/null @@ -1,337 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pd-common.h" -#include "vendorcmds.h" - -static void complete_handler_audio(struct urb *urb); -#define AUDIO_EP (0x83) -#define AUDIO_BUF_SIZE (512) -#define PERIOD_SIZE (1024 * 8) -#define PERIOD_MIN (4) -#define PERIOD_MAX PERIOD_MIN - -static struct snd_pcm_hardware snd_pd_hw_capture = { - .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID, - - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_48000, - - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = PERIOD_SIZE * PERIOD_MIN, - .period_bytes_min = PERIOD_SIZE, - .period_bytes_max = PERIOD_SIZE, - .periods_min = PERIOD_MIN, - .periods_max = PERIOD_MAX, - /* - .buffer_bytes_max = 62720 * 8, - .period_bytes_min = 64, - .period_bytes_max = 12544, - .periods_min = 2, - .periods_max = 98 - */ -}; - -static int snd_pd_capture_open(struct snd_pcm_substream *substream) -{ - struct poseidon *p = snd_pcm_substream_chip(substream); - struct poseidon_audio *pa = &p->audio; - struct snd_pcm_runtime *runtime = substream->runtime; - - if (!p) - return -ENODEV; - pa->users++; - pa->card_close = 0; - pa->capture_pcm_substream = substream; - runtime->private_data = p; - - runtime->hw = snd_pd_hw_capture; - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - usb_autopm_get_interface(p->interface); - kref_get(&p->kref); - return 0; -} - -static int snd_pd_pcm_close(struct snd_pcm_substream *substream) -{ - struct poseidon *p = snd_pcm_substream_chip(substream); - struct poseidon_audio *pa = &p->audio; - - pa->users--; - pa->card_close = 1; - usb_autopm_put_interface(p->interface); - kref_put(&p->kref, poseidon_delete); - return 0; -} - -static int snd_pd_hw_capture_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int size; - - size = params_buffer_bytes(hw_params); - if (runtime->dma_area) { - if (runtime->dma_bytes > size) - return 0; - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc(size); - if (!runtime->dma_area) - return -ENOMEM; - else - runtime->dma_bytes = size; - return 0; -} - -static int audio_buf_free(struct poseidon *p) -{ - struct poseidon_audio *pa = &p->audio; - int i; - - for (i = 0; i < AUDIO_BUFS; i++) - if (pa->urb_array[i]) - usb_kill_urb(pa->urb_array[i]); - free_all_urb_generic(pa->urb_array, AUDIO_BUFS); - logpm(); - return 0; -} - -static int snd_pd_hw_capture_free(struct snd_pcm_substream *substream) -{ - struct poseidon *p = snd_pcm_substream_chip(substream); - - logpm(); - audio_buf_free(p); - return 0; -} - -static int snd_pd_prepare(struct snd_pcm_substream *substream) -{ - return 0; -} - -#define AUDIO_TRAILER_SIZE (16) -static inline void handle_audio_data(struct urb *urb, int *period_elapsed) -{ - struct poseidon_audio *pa = urb->context; - struct snd_pcm_runtime *runtime = pa->capture_pcm_substream->runtime; - - int stride = runtime->frame_bits >> 3; - int len = urb->actual_length / stride; - unsigned char *cp = urb->transfer_buffer; - unsigned int oldptr = pa->rcv_position; - - if (urb->actual_length == AUDIO_BUF_SIZE - 4) - len -= (AUDIO_TRAILER_SIZE / stride); - - /* do the copy */ - if (oldptr + len >= runtime->buffer_size) { - unsigned int cnt = runtime->buffer_size - oldptr; - - memcpy(runtime->dma_area + oldptr * stride, cp, cnt * stride); - memcpy(runtime->dma_area, (cp + cnt * stride), - (len * stride - cnt * stride)); - } else - memcpy(runtime->dma_area + oldptr * stride, cp, len * stride); - - /* update the statas */ - snd_pcm_stream_lock(pa->capture_pcm_substream); - pa->rcv_position += len; - if (pa->rcv_position >= runtime->buffer_size) - pa->rcv_position -= runtime->buffer_size; - - pa->copied_position += (len); - if (pa->copied_position >= runtime->period_size) { - pa->copied_position -= runtime->period_size; - *period_elapsed = 1; - } - snd_pcm_stream_unlock(pa->capture_pcm_substream); -} - -static void complete_handler_audio(struct urb *urb) -{ - struct poseidon_audio *pa = urb->context; - struct snd_pcm_substream *substream = pa->capture_pcm_substream; - int period_elapsed = 0; - int ret; - - if (1 == pa->card_close || pa->capture_stream != STREAM_ON) - return; - - if (urb->status != 0) { - /*if (urb->status == -ESHUTDOWN)*/ - return; - } - - if (substream) { - if (urb->actual_length) { - handle_audio_data(urb, &period_elapsed); - if (period_elapsed) - snd_pcm_period_elapsed(substream); - } - } - - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret < 0) - log("audio urb failed (errcod = %i)", ret); - return; -} - -static int fire_audio_urb(struct poseidon *p) -{ - int i, ret = 0; - struct poseidon_audio *pa = &p->audio; - - alloc_bulk_urbs_generic(pa->urb_array, AUDIO_BUFS, - p->udev, AUDIO_EP, - AUDIO_BUF_SIZE, GFP_ATOMIC, - complete_handler_audio, pa); - - for (i = 0; i < AUDIO_BUFS; i++) { - ret = usb_submit_urb(pa->urb_array[i], GFP_KERNEL); - if (ret) - log("urb err : %d", ret); - } - log(); - return ret; -} - -static int snd_pd_capture_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct poseidon *p = snd_pcm_substream_chip(substream); - struct poseidon_audio *pa = &p->audio; - - if (debug_mode) - log("cmd %d, audio stat : %d\n", cmd, pa->capture_stream); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_START: - if (pa->capture_stream == STREAM_ON) - return 0; - - pa->rcv_position = pa->copied_position = 0; - pa->capture_stream = STREAM_ON; - - if (in_hibernation(p)) - return 0; - fire_audio_urb(p); - return 0; - - case SNDRV_PCM_TRIGGER_SUSPEND: - pa->capture_stream = STREAM_SUSPEND; - return 0; - case SNDRV_PCM_TRIGGER_STOP: - pa->capture_stream = STREAM_OFF; - return 0; - default: - return -EINVAL; - } -} - -static snd_pcm_uframes_t -snd_pd_capture_pointer(struct snd_pcm_substream *substream) -{ - struct poseidon *p = snd_pcm_substream_chip(substream); - struct poseidon_audio *pa = &p->audio; - return pa->rcv_position; -} - -static struct page *snd_pcm_pd_get_page(struct snd_pcm_substream *subs, - unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - return vmalloc_to_page(pageptr); -} - -static struct snd_pcm_ops pcm_capture_ops = { - .open = snd_pd_capture_open, - .close = snd_pd_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_pd_hw_capture_params, - .hw_free = snd_pd_hw_capture_free, - .prepare = snd_pd_prepare, - .trigger = snd_pd_capture_trigger, - .pointer = snd_pd_capture_pointer, - .page = snd_pcm_pd_get_page, -}; - -#ifdef CONFIG_PM -int pm_alsa_suspend(struct poseidon *p) -{ - logpm(p); - audio_buf_free(p); - return 0; -} - -int pm_alsa_resume(struct poseidon *p) -{ - logpm(p); - fire_audio_urb(p); - return 0; -} -#endif - -int poseidon_audio_init(struct poseidon *p) -{ - struct poseidon_audio *pa = &p->audio; - struct snd_card *card; - struct snd_pcm *pcm; - int ret; - - ret = snd_card_new(&p->interface->dev, -1, "Telegent", - THIS_MODULE, 0, &card); - if (ret != 0) - return ret; - - ret = snd_pcm_new(card, "poseidon audio", 0, 0, 1, &pcm); - if (ret < 0) { - snd_card_free(card); - return ret; - } - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops); - pcm->info_flags = 0; - pcm->private_data = p; - strcpy(pcm->name, "poseidon audio capture"); - - strcpy(card->driver, "ALSA driver"); - strcpy(card->shortname, "poseidon Audio"); - strcpy(card->longname, "poseidon ALSA Audio"); - - if (snd_card_register(card)) { - snd_card_free(card); - return -ENOMEM; - } - pa->card = card; - return 0; -} - -int poseidon_audio_free(struct poseidon *p) -{ - struct poseidon_audio *pa = &p->audio; - - if (pa->card) - snd_card_free(pa->card); - return 0; -} diff --git a/drivers/staging/media/tlg2300/pd-common.h b/drivers/staging/media/tlg2300/pd-common.h deleted file mode 100644 index 9e23ad32d2fe..000000000000 --- a/drivers/staging/media/tlg2300/pd-common.h +++ /dev/null @@ -1,271 +0,0 @@ -#ifndef PD_COMMON_H -#define PD_COMMON_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dmxdev.h" - -#define SBUF_NUM 8 -#define MAX_BUFFER_NUM 6 -#define PK_PER_URB 32 -#define ISO_PKT_SIZE 3072 - -#define POSEIDON_STATE_NONE (0x0000) -#define POSEIDON_STATE_ANALOG (0x0001) -#define POSEIDON_STATE_FM (0x0002) -#define POSEIDON_STATE_DVBT (0x0004) -#define POSEIDON_STATE_DISCONNECT (0x0080) - -#define PM_SUSPEND_DELAY 3 - -#define V4L_PAL_VBI_LINES 18 -#define V4L_NTSC_VBI_LINES 12 -#define V4L_PAL_VBI_FRAMESIZE (V4L_PAL_VBI_LINES * 1440 * 2) -#define V4L_NTSC_VBI_FRAMESIZE (V4L_NTSC_VBI_LINES * 1440 * 2) - -#define TUNER_FREQ_MIN (45000000U) -#define TUNER_FREQ_MAX (862000000U) - -struct vbi_data { - struct video_device v_dev; - struct video_data *video; - struct front_face *front; - - unsigned int copied; - unsigned int vbi_size; /* the whole size of two fields */ - int users; -}; - -/* - * This is the running context of the video, it is useful for - * resume() - */ -struct running_context { - u32 freq; /* VIDIOC_S_FREQUENCY */ - int audio_idx; /* VIDIOC_S_TUNER */ - v4l2_std_id tvnormid; /* VIDIOC_S_STD */ - int sig_index; /* VIDIOC_S_INPUT */ - struct v4l2_pix_format pix; /* VIDIOC_S_FMT */ -}; - -struct video_data { - /* v4l2 video device */ - struct video_device v_dev; - struct v4l2_ctrl_handler ctrl_handler; - - /* the working context */ - struct running_context context; - - /* for data copy */ - int field_count; - - char *dst; - int lines_copied; - int prev_left; - - int lines_per_field; - int lines_size; - - /* for communication */ - u8 endpoint_addr; - struct urb *urb_array[SBUF_NUM]; - struct vbi_data *vbi; - struct poseidon *pd; - struct front_face *front; - - int is_streaming; - int users; - - /* for bubble handler */ - struct work_struct bubble_work; -}; - -enum pcm_stream_state { - STREAM_OFF, - STREAM_ON, - STREAM_SUSPEND, -}; - -#define AUDIO_BUFS (3) -#define CAPTURE_STREAM_EN 1 -struct poseidon_audio { - struct urb *urb_array[AUDIO_BUFS]; - unsigned int copied_position; - struct snd_pcm_substream *capture_pcm_substream; - - unsigned int rcv_position; - struct snd_card *card; - int card_close; - - int users; - int pm_state; - enum pcm_stream_state capture_stream; -}; - -struct radio_data { - __u32 fm_freq; - unsigned int is_radio_streaming; - int pre_emphasis; - struct video_device fm_dev; - struct v4l2_ctrl_handler ctrl_handler; -}; - -#define DVB_SBUF_NUM 4 -#define DVB_URB_BUF_SIZE 0x2000 -struct pd_dvb_adapter { - struct dvb_adapter dvb_adap; - struct dvb_frontend dvb_fe; - struct dmxdev dmxdev; - struct dvb_demux demux; - - atomic_t users; - atomic_t active_feed; - - /* data transfer */ - s32 is_streaming; - struct urb *urb_array[DVB_SBUF_NUM]; - struct poseidon *pd_device; - u8 ep_addr; - u8 reserved[3]; - - /* data for power resume*/ - struct dtv_frontend_properties fe_param; - - /* for channel scanning */ - int prev_freq; - int bandwidth; - unsigned long last_jiffies; -}; - -struct front_face { - /* use this field to distinguish VIDEO and VBI */ - enum v4l2_buf_type type; - - /* for host */ - struct videobuf_queue q; - - /* the bridge for host and device */ - struct videobuf_buffer *curr_frame; - - /* for device */ - spinlock_t queue_lock; - struct list_head active; - struct poseidon *pd; -}; - -struct poseidon { - struct list_head device_list; - - struct mutex lock; - struct kref kref; - - /* for V4L2 */ - struct v4l2_device v4l2_dev; - - /* hardware info */ - struct usb_device *udev; - struct usb_interface *interface; - int cur_transfer_mode; - - struct video_data video_data; /* video */ - struct vbi_data vbi_data; /* vbi */ - struct poseidon_audio audio; /* audio (alsa) */ - struct radio_data radio_data; /* FM */ - struct pd_dvb_adapter dvb_data; /* DVB */ - - u32 state; - struct file *file_for_stream; /* the active stream*/ - -#ifdef CONFIG_PM - int (*pm_suspend)(struct poseidon *); - int (*pm_resume)(struct poseidon *); - pm_message_t msg; - - struct work_struct pm_work; - u8 portnum; -#endif -}; - -struct poseidon_format { - char *name; - int fourcc; /* video4linux 2 */ - int depth; /* bit/pixel */ - int flags; -}; - -struct poseidon_tvnorm { - v4l2_std_id v4l2_id; - char name[12]; - u32 tlg_tvnorm; -}; - -/* video */ -int pd_video_init(struct poseidon *); -void pd_video_exit(struct poseidon *); -int stop_all_video_stream(struct poseidon *); - -/* alsa audio */ -int poseidon_audio_init(struct poseidon *); -int poseidon_audio_free(struct poseidon *); -#ifdef CONFIG_PM -int pm_alsa_suspend(struct poseidon *); -int pm_alsa_resume(struct poseidon *); -#endif - -/* dvb */ -int pd_dvb_usb_device_init(struct poseidon *); -void pd_dvb_usb_device_exit(struct poseidon *); -void pd_dvb_usb_device_cleanup(struct poseidon *); -int pd_dvb_get_adapter_num(struct pd_dvb_adapter *); -void dvb_stop_streaming(struct pd_dvb_adapter *); - -/* FM */ -int poseidon_fm_init(struct poseidon *); -int poseidon_fm_exit(struct poseidon *); - -/* vendor command ops */ -int send_set_req(struct poseidon*, u8, s32, s32*); -int send_get_req(struct poseidon*, u8, s32, void*, s32*, s32); -s32 set_tuner_mode(struct poseidon*, unsigned char); - -/* bulk urb alloc/free */ -int alloc_bulk_urbs_generic(struct urb **urb_array, int num, - struct usb_device *udev, u8 ep_addr, - int buf_size, gfp_t gfp_flags, - usb_complete_t complete_fn, void *context); -void free_all_urb_generic(struct urb **urb_array, int num); - -/* misc */ -void poseidon_delete(struct kref *kref); -extern int debug_mode; -void set_debug_mode(struct video_device *vfd, int debug_mode); - -#ifdef CONFIG_PM -#define in_hibernation(pd) (pd->msg.event == PM_EVENT_FREEZE) -#else -#define in_hibernation(pd) (0) -#endif -#define get_pm_count(p) (atomic_read(&(p)->interface->pm_usage_cnt)) - -#define log(a, ...) printk(KERN_DEBUG "\t[ %s : %.3d ] "a"\n", \ - __func__, __LINE__, ## __VA_ARGS__) - -/* for power management */ -#define logpm(pd) do {\ - if (debug_mode & 0x10)\ - log();\ - } while (0) - -#endif diff --git a/drivers/staging/media/tlg2300/pd-dvb.c b/drivers/staging/media/tlg2300/pd-dvb.c deleted file mode 100644 index ca4994a5190c..000000000000 --- a/drivers/staging/media/tlg2300/pd-dvb.c +++ /dev/null @@ -1,597 +0,0 @@ -#include "pd-common.h" -#include -#include -#include -#include -#include -#include - -#include "vendorcmds.h" -#include -#include - -static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb); - -static int dvb_bandwidth[][2] = { - { TLG_BW_8, 8000000 }, - { TLG_BW_7, 7000000 }, - { TLG_BW_6, 6000000 } -}; -static int dvb_bandwidth_length = ARRAY_SIZE(dvb_bandwidth); - -static s32 dvb_start_streaming(struct pd_dvb_adapter *pd_dvb); -static int poseidon_check_mode_dvbt(struct poseidon *pd) -{ - s32 ret = 0, cmd_status = 0; - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); - - ret = usb_set_interface(pd->udev, 0, BULK_ALTERNATE_IFACE); - if (ret != 0) - return ret; - - ret = set_tuner_mode(pd, TLG_MODE_CAPS_DVB_T); - if (ret) - return ret; - - /* signal source */ - ret = send_set_req(pd, SGNL_SRC_SEL, TLG_SIG_SRC_ANTENNA, &cmd_status); - if (ret|cmd_status) - return ret; - - return 0; -} - -/* acquire : - * 1 == open - * 0 == release - */ -static int poseidon_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) -{ - struct poseidon *pd = fe->demodulator_priv; - struct pd_dvb_adapter *pd_dvb; - int ret = 0; - - if (!pd) - return -ENODEV; - - pd_dvb = container_of(fe, struct pd_dvb_adapter, dvb_fe); - if (acquire) { - mutex_lock(&pd->lock); - if (pd->state & POSEIDON_STATE_DISCONNECT) { - ret = -ENODEV; - goto open_out; - } - - if (pd->state && !(pd->state & POSEIDON_STATE_DVBT)) { - ret = -EBUSY; - goto open_out; - } - - usb_autopm_get_interface(pd->interface); - if (0 == pd->state) { - ret = poseidon_check_mode_dvbt(pd); - if (ret < 0) { - usb_autopm_put_interface(pd->interface); - goto open_out; - } - pd->state |= POSEIDON_STATE_DVBT; - pd_dvb->bandwidth = 0; - pd_dvb->prev_freq = 0; - } - atomic_inc(&pd_dvb->users); - kref_get(&pd->kref); -open_out: - mutex_unlock(&pd->lock); - } else { - dvb_stop_streaming(pd_dvb); - - if (atomic_dec_and_test(&pd_dvb->users)) { - mutex_lock(&pd->lock); - pd->state &= ~POSEIDON_STATE_DVBT; - mutex_unlock(&pd->lock); - } - kref_put(&pd->kref, poseidon_delete); - usb_autopm_put_interface(pd->interface); - } - return ret; -} - -#ifdef CONFIG_PM -static void poseidon_fe_release(struct dvb_frontend *fe) -{ - struct poseidon *pd = fe->demodulator_priv; - - pd->pm_suspend = NULL; - pd->pm_resume = NULL; -} -#else -#define poseidon_fe_release NULL -#endif - -static s32 poseidon_fe_sleep(struct dvb_frontend *fe) -{ - return 0; -} - -/* - * return true if we can satisfy the conditions, else return false. - */ -static bool check_scan_ok(__u32 freq, int bandwidth, - struct pd_dvb_adapter *adapter) -{ - if (bandwidth < 0) - return false; - - if (adapter->prev_freq == freq - && adapter->bandwidth == bandwidth) { - long nl = jiffies - adapter->last_jiffies; - unsigned int msec ; - - msec = jiffies_to_msecs(abs(nl)); - return msec > 15000 ? true : false; - } - return true; -} - -/* - * Check if the firmware delays too long for an invalid frequency. - */ -static int fw_delay_overflow(struct pd_dvb_adapter *adapter) -{ - long nl = jiffies - adapter->last_jiffies; - unsigned int msec ; - - msec = jiffies_to_msecs(abs(nl)); - return msec > 800 ? true : false; -} - -static int poseidon_set_fe(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *fep = &fe->dtv_property_cache; - s32 ret = 0, cmd_status = 0; - s32 i, bandwidth = -1; - struct poseidon *pd = fe->demodulator_priv; - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - - if (in_hibernation(pd)) - return -EBUSY; - - mutex_lock(&pd->lock); - for (i = 0; i < dvb_bandwidth_length; i++) - if (fep->bandwidth_hz == dvb_bandwidth[i][1]) - bandwidth = dvb_bandwidth[i][0]; - - if (check_scan_ok(fep->frequency, bandwidth, pd_dvb)) { - ret = send_set_req(pd, TUNE_FREQ_SELECT, - fep->frequency / 1000, &cmd_status); - if (ret | cmd_status) { - log("error line"); - goto front_out; - } - - ret = send_set_req(pd, DVBT_BANDW_SEL, - bandwidth, &cmd_status); - if (ret | cmd_status) { - log("error line"); - goto front_out; - } - - ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status); - if (ret | cmd_status) { - log("error line"); - goto front_out; - } - - /* save the context for future */ - memcpy(&pd_dvb->fe_param, fep, sizeof(*fep)); - pd_dvb->bandwidth = bandwidth; - pd_dvb->prev_freq = fep->frequency; - pd_dvb->last_jiffies = jiffies; - } -front_out: - mutex_unlock(&pd->lock); - return ret; -} - -#ifdef CONFIG_PM -static int pm_dvb_suspend(struct poseidon *pd) -{ - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - dvb_stop_streaming(pd_dvb); - dvb_urb_cleanup(pd_dvb); - msleep(500); - return 0; -} - -static int pm_dvb_resume(struct poseidon *pd) -{ - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - - poseidon_check_mode_dvbt(pd); - msleep(300); - poseidon_set_fe(&pd_dvb->dvb_fe); - - dvb_start_streaming(pd_dvb); - return 0; -} -#endif - -static s32 poseidon_fe_init(struct dvb_frontend *fe) -{ - struct poseidon *pd = fe->demodulator_priv; - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - -#ifdef CONFIG_PM - pd->pm_suspend = pm_dvb_suspend; - pd->pm_resume = pm_dvb_resume; -#endif - memset(&pd_dvb->fe_param, 0, - sizeof(struct dtv_frontend_properties)); - return 0; -} - -static int poseidon_get_fe(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *fep = &fe->dtv_property_cache; - struct poseidon *pd = fe->demodulator_priv; - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - - memcpy(fep, &pd_dvb->fe_param, sizeof(*fep)); - return 0; -} - -static int poseidon_fe_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - tune->min_delay_ms = 1000; - return 0; -} - -static int poseidon_read_status(struct dvb_frontend *fe, fe_status_t *stat) -{ - struct poseidon *pd = fe->demodulator_priv; - s32 ret = -1, cmd_status; - struct tuner_dtv_sig_stat_s status = {}; - - if (in_hibernation(pd)) - return -EBUSY; - mutex_lock(&pd->lock); - - ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_DVB_T, - &status, &cmd_status, sizeof(status)); - if (ret | cmd_status) { - log("get tuner status error"); - goto out; - } - - if (debug_mode) - log("P : %d, L %d, LB :%d", status.sig_present, - status.sig_locked, status.sig_lock_busy); - - if (status.sig_lock_busy) { - goto out; - } else if (status.sig_present || status.sig_locked) { - *stat |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER - | FE_HAS_SYNC | FE_HAS_VITERBI; - } else { - if (fw_delay_overflow(&pd->dvb_data)) - *stat |= FE_TIMEDOUT; - } -out: - mutex_unlock(&pd->lock); - return ret; -} - -static int poseidon_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct poseidon *pd = fe->demodulator_priv; - struct tuner_ber_rate_s tlg_ber = {}; - s32 ret = -1, cmd_status; - - mutex_lock(&pd->lock); - ret = send_get_req(pd, TUNER_BER_RATE, 0, - &tlg_ber, &cmd_status, sizeof(tlg_ber)); - if (ret | cmd_status) - goto out; - *ber = tlg_ber.ber_rate; -out: - mutex_unlock(&pd->lock); - return ret; -} - -static s32 poseidon_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct poseidon *pd = fe->demodulator_priv; - struct tuner_dtv_sig_stat_s status = {}; - s32 ret = 0, cmd_status; - - mutex_lock(&pd->lock); - ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_DVB_T, - &status, &cmd_status, sizeof(status)); - if (ret | cmd_status) - goto out; - if ((status.sig_present || status.sig_locked) && !status.sig_strength) - *strength = 0xFFFF; - else - *strength = status.sig_strength; -out: - mutex_unlock(&pd->lock); - return ret; -} - -static int poseidon_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - return 0; -} - -static int poseidon_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) -{ - *unc = 0; - return 0; -} - -static struct dvb_frontend_ops poseidon_frontend_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = "Poseidon DVB-T", - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 62500,/* FIXME */ - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = poseidon_fe_release, - - .init = poseidon_fe_init, - .sleep = poseidon_fe_sleep, - - .set_frontend = poseidon_set_fe, - .get_frontend = poseidon_get_fe, - .get_tune_settings = poseidon_fe_get_tune_settings, - - .read_status = poseidon_read_status, - .read_ber = poseidon_read_ber, - .read_signal_strength = poseidon_read_signal_strength, - .read_snr = poseidon_read_snr, - .read_ucblocks = poseidon_read_unc_blocks, - - .ts_bus_ctrl = poseidon_ts_bus_ctrl, -}; - -static void dvb_urb_irq(struct urb *urb) -{ - struct pd_dvb_adapter *pd_dvb = urb->context; - int len = urb->transfer_buffer_length; - struct dvb_demux *demux = &pd_dvb->demux; - s32 ret; - - if (!pd_dvb->is_streaming || urb->status) { - if (urb->status == -EPROTO) - goto resend; - return; - } - - if (urb->actual_length == len) - dvb_dmx_swfilter(demux, urb->transfer_buffer, len); - else if (urb->actual_length == len - 4) { - int offset; - u8 *buf = urb->transfer_buffer; - - /* - * The packet size is 512, - * last packet contains 456 bytes tsp data - */ - for (offset = 456; offset < len; offset += 512) { - if (!strncmp(buf + offset, "DVHS", 4)) { - dvb_dmx_swfilter(demux, buf, offset); - if (len > offset + 52 + 4) { - /*16 bytes trailer + 36 bytes padding */ - buf += offset + 52; - len -= offset + 52 + 4; - dvb_dmx_swfilter(demux, buf, len); - } - break; - } - } - } - -resend: - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) - log(" usb_submit_urb failed: error %d", ret); -} - -static int dvb_urb_init(struct pd_dvb_adapter *pd_dvb) -{ - if (pd_dvb->urb_array[0]) - return 0; - - alloc_bulk_urbs_generic(pd_dvb->urb_array, DVB_SBUF_NUM, - pd_dvb->pd_device->udev, pd_dvb->ep_addr, - DVB_URB_BUF_SIZE, GFP_KERNEL, - dvb_urb_irq, pd_dvb); - return 0; -} - -static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb) -{ - free_all_urb_generic(pd_dvb->urb_array, DVB_SBUF_NUM); -} - -static s32 dvb_start_streaming(struct pd_dvb_adapter *pd_dvb) -{ - struct poseidon *pd = pd_dvb->pd_device; - int ret = 0; - - if (pd->state & POSEIDON_STATE_DISCONNECT) - return -ENODEV; - - mutex_lock(&pd->lock); - if (!pd_dvb->is_streaming) { - s32 i, cmd_status = 0; - /* - * Once upon a time, there was a difficult bug lying here. - * ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status); - */ - - ret = send_set_req(pd, PLAY_SERVICE, 1, &cmd_status); - if (ret | cmd_status) - goto out; - - ret = dvb_urb_init(pd_dvb); - if (ret < 0) - goto out; - - pd_dvb->is_streaming = 1; - for (i = 0; i < DVB_SBUF_NUM; i++) { - ret = usb_submit_urb(pd_dvb->urb_array[i], - GFP_KERNEL); - if (ret) { - log(" submit urb error %d", ret); - goto out; - } - } - } -out: - mutex_unlock(&pd->lock); - return ret; -} - -void dvb_stop_streaming(struct pd_dvb_adapter *pd_dvb) -{ - struct poseidon *pd = pd_dvb->pd_device; - - mutex_lock(&pd->lock); - if (pd_dvb->is_streaming) { - s32 i, ret, cmd_status = 0; - - pd_dvb->is_streaming = 0; - - for (i = 0; i < DVB_SBUF_NUM; i++) - if (pd_dvb->urb_array[i]) - usb_kill_urb(pd_dvb->urb_array[i]); - - ret = send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP, - &cmd_status); - if (ret | cmd_status) - log("error"); - } - mutex_unlock(&pd->lock); -} - -static int pd_start_feed(struct dvb_demux_feed *feed) -{ - struct pd_dvb_adapter *pd_dvb = feed->demux->priv; - int ret = 0; - - if (!pd_dvb) - return -1; - if (atomic_inc_return(&pd_dvb->active_feed) == 1) - ret = dvb_start_streaming(pd_dvb); - return ret; -} - -static int pd_stop_feed(struct dvb_demux_feed *feed) -{ - struct pd_dvb_adapter *pd_dvb = feed->demux->priv; - - if (!pd_dvb) - return -1; - if (atomic_dec_and_test(&pd_dvb->active_feed)) - dvb_stop_streaming(pd_dvb); - return 0; -} - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -int pd_dvb_usb_device_init(struct poseidon *pd) -{ - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - struct dvb_demux *dvbdemux; - int ret = 0; - - pd_dvb->ep_addr = 0x82; - atomic_set(&pd_dvb->users, 0); - atomic_set(&pd_dvb->active_feed, 0); - pd_dvb->pd_device = pd; - - ret = dvb_register_adapter(&pd_dvb->dvb_adap, - "Poseidon dvbt adapter", - THIS_MODULE, - NULL /* for hibernation correctly*/, - adapter_nr); - if (ret < 0) - goto error1; - - /* register frontend */ - pd_dvb->dvb_fe.demodulator_priv = pd; - memcpy(&pd_dvb->dvb_fe.ops, &poseidon_frontend_ops, - sizeof(struct dvb_frontend_ops)); - ret = dvb_register_frontend(&pd_dvb->dvb_adap, &pd_dvb->dvb_fe); - if (ret < 0) - goto error2; - - /* register demux device */ - dvbdemux = &pd_dvb->demux; - dvbdemux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; - dvbdemux->priv = pd_dvb; - dvbdemux->feednum = dvbdemux->filternum = 64; - dvbdemux->start_feed = pd_start_feed; - dvbdemux->stop_feed = pd_stop_feed; - dvbdemux->write_to_decoder = NULL; - - ret = dvb_dmx_init(dvbdemux); - if (ret < 0) - goto error3; - - pd_dvb->dmxdev.filternum = pd_dvb->demux.filternum; - pd_dvb->dmxdev.demux = &pd_dvb->demux.dmx; - pd_dvb->dmxdev.capabilities = 0; - - ret = dvb_dmxdev_init(&pd_dvb->dmxdev, &pd_dvb->dvb_adap); - if (ret < 0) - goto error3; - return 0; - -error3: - dvb_unregister_frontend(&pd_dvb->dvb_fe); -error2: - dvb_unregister_adapter(&pd_dvb->dvb_adap); -error1: - return ret; -} - -void pd_dvb_usb_device_exit(struct poseidon *pd) -{ - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - - while (atomic_read(&pd_dvb->users) != 0 - || atomic_read(&pd_dvb->active_feed) != 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); - } - dvb_dmxdev_release(&pd_dvb->dmxdev); - dvb_unregister_frontend(&pd_dvb->dvb_fe); - dvb_unregister_adapter(&pd_dvb->dvb_adap); - pd_dvb_usb_device_cleanup(pd); -} - -void pd_dvb_usb_device_cleanup(struct poseidon *pd) -{ - struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; - - dvb_urb_cleanup(pd_dvb); -} - -int pd_dvb_get_adapter_num(struct pd_dvb_adapter *pd_dvb) -{ - return pd_dvb->dvb_adap.num; -} diff --git a/drivers/staging/media/tlg2300/pd-main.c b/drivers/staging/media/tlg2300/pd-main.c deleted file mode 100644 index b31f4791b8ff..000000000000 --- a/drivers/staging/media/tlg2300/pd-main.c +++ /dev/null @@ -1,553 +0,0 @@ -/* - * device driver for Telegent tlg2300 based TV cards - * - * Author : - * Kang Yong - * Zhang Xiaobing - * Huang Shijie or - * - * (c) 2009 Telegent Systems - * (c) 2010 Telegent Systems - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vendorcmds.h" -#include "pd-common.h" - -#define VENDOR_ID 0x1B24 -#define PRODUCT_ID 0x4001 -static struct usb_device_id id_table[] = { - { USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID, PRODUCT_ID, 255, 1, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID, PRODUCT_ID, 255, 1, 1) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -int debug_mode; -module_param(debug_mode, int, 0644); -MODULE_PARM_DESC(debug_mode, "0 = disable, 1 = enable, 2 = verbose"); - -#define TLG2300_FIRMWARE "tlg2300_firmware.bin" -static const char *firmware_name = TLG2300_FIRMWARE; -static LIST_HEAD(pd_device_list); - -/* - * send set request to USB firmware. - */ -s32 send_set_req(struct poseidon *pd, u8 cmdid, s32 param, s32 *cmd_status) -{ - s32 ret; - s8 data[32] = {}; - u16 lower_16, upper_16; - - if (pd->state & POSEIDON_STATE_DISCONNECT) - return -ENODEV; - - mdelay(30); - - if (param == 0) { - upper_16 = lower_16 = 0; - } else { - /* send 32 bit param as two 16 bit param,little endian */ - lower_16 = (unsigned short)(param & 0xffff); - upper_16 = (unsigned short)((param >> 16) & 0xffff); - } - ret = usb_control_msg(pd->udev, - usb_rcvctrlpipe(pd->udev, 0), - REQ_SET_CMD | cmdid, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - lower_16, - upper_16, - &data, - sizeof(*cmd_status), - USB_CTRL_GET_TIMEOUT); - - if (!ret) { - return -ENXIO; - } else { - /* 1st 4 bytes into cmd_status */ - memcpy((char *)cmd_status, &(data[0]), sizeof(*cmd_status)); - } - return 0; -} - -/* - * send get request to Poseidon firmware. - */ -s32 send_get_req(struct poseidon *pd, u8 cmdid, s32 param, - void *buf, s32 *cmd_status, s32 datalen) -{ - s32 ret; - s8 data[128] = {}; - u16 lower_16, upper_16; - - if (pd->state & POSEIDON_STATE_DISCONNECT) - return -ENODEV; - - mdelay(30); - if (param == 0) { - upper_16 = lower_16 = 0; - } else { - /*send 32 bit param as two 16 bit param, little endian */ - lower_16 = (unsigned short)(param & 0xffff); - upper_16 = (unsigned short)((param >> 16) & 0xffff); - } - ret = usb_control_msg(pd->udev, - usb_rcvctrlpipe(pd->udev, 0), - REQ_GET_CMD | cmdid, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - lower_16, - upper_16, - &data, - (datalen + sizeof(*cmd_status)), - USB_CTRL_GET_TIMEOUT); - - if (ret < 0) { - return -ENXIO; - } else { - /* 1st 4 bytes into cmd_status, remaining data into cmd_data */ - memcpy((char *)cmd_status, &data[0], sizeof(*cmd_status)); - memcpy((char *)buf, &data[sizeof(*cmd_status)], datalen); - } - return 0; -} - -static int pm_notifier_block(struct notifier_block *nb, - unsigned long event, void *dummy) -{ - struct poseidon *pd = NULL; - struct list_head *node, *next; - - switch (event) { - case PM_POST_HIBERNATION: - list_for_each_safe(node, next, &pd_device_list) { - struct usb_device *udev; - struct usb_interface *iface; - int rc = 0; - - pd = container_of(node, struct poseidon, device_list); - udev = pd->udev; - iface = pd->interface; - - /* It will cause the system to reload the firmware */ - rc = usb_lock_device_for_reset(udev, iface); - if (rc >= 0) { - usb_reset_device(udev); - usb_unlock_device(udev); - } - } - break; - default: - break; - } - log("event :%ld\n", event); - return 0; -} - -static struct notifier_block pm_notifer = { - .notifier_call = pm_notifier_block, -}; - -int set_tuner_mode(struct poseidon *pd, unsigned char mode) -{ - s32 ret, cmd_status; - - if (pd->state & POSEIDON_STATE_DISCONNECT) - return -ENODEV; - - ret = send_set_req(pd, TUNE_MODE_SELECT, mode, &cmd_status); - if (ret || cmd_status) - return -ENXIO; - return 0; -} - -void poseidon_delete(struct kref *kref) -{ - struct poseidon *pd = container_of(kref, struct poseidon, kref); - - if (!pd) - return; - list_del_init(&pd->device_list); - - pd_dvb_usb_device_cleanup(pd); - /* clean_audio_data(&pd->audio_data);*/ - - if (pd->udev) { - usb_put_dev(pd->udev); - pd->udev = NULL; - } - if (pd->interface) { - usb_put_intf(pd->interface); - pd->interface = NULL; - } - kfree(pd); - log(); -} - -static int firmware_download(struct usb_device *udev) -{ - int ret = 0, actual_length; - const struct firmware *fw = NULL; - void *fwbuf = NULL; - size_t fwlength = 0, offset; - size_t max_packet_size; - - ret = request_firmware(&fw, firmware_name, &udev->dev); - if (ret) { - log("download err : %d", ret); - return ret; - } - - fwlength = fw->size; - - fwbuf = kmemdup(fw->data, fwlength, GFP_KERNEL); - if (!fwbuf) { - ret = -ENOMEM; - goto out; - } - - max_packet_size = le16_to_cpu(udev->ep_out[0x1]->desc.wMaxPacketSize); - log("\t\t download size : %d", (int)max_packet_size); - - for (offset = 0; offset < fwlength; offset += max_packet_size) { - actual_length = 0; - ret = usb_bulk_msg(udev, - usb_sndbulkpipe(udev, 0x01), /* ep 1 */ - fwbuf + offset, - min(max_packet_size, fwlength - offset), - &actual_length, - HZ * 10); - if (ret) - break; - } - kfree(fwbuf); -out: - release_firmware(fw); - return ret; -} - -static inline struct poseidon *get_pd(struct usb_interface *intf) -{ - return usb_get_intfdata(intf); -} - -#ifdef CONFIG_PM -/* one-to-one map : poseidon{} <----> usb_device{}'s port */ -static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev) -{ - pd->portnum = udev->portnum; -} - -static inline int get_autopm_ref(struct poseidon *pd) -{ - return pd->video_data.users + pd->vbi_data.users + pd->audio.users - + atomic_read(&pd->dvb_data.users) + - !list_empty(&pd->radio_data.fm_dev.fh_list); -} - -/* fixup something for poseidon */ -static inline struct poseidon *fixup(struct poseidon *pd) -{ - int count; - - /* old udev and interface have gone, so put back reference . */ - count = get_autopm_ref(pd); - log("count : %d, ref count : %d", count, get_pm_count(pd)); - while (count--) - usb_autopm_put_interface(pd->interface); - /*usb_autopm_set_interface(pd->interface); */ - - usb_put_dev(pd->udev); - usb_put_intf(pd->interface); - log("event : %d\n", pd->msg.event); - return pd; -} - -static struct poseidon *find_old_poseidon(struct usb_device *udev) -{ - struct poseidon *pd; - - list_for_each_entry(pd, &pd_device_list, device_list) { - if (pd->portnum == udev->portnum && in_hibernation(pd)) - return fixup(pd); - } - return NULL; -} - -/* Is the card working now ? */ -static inline int is_working(struct poseidon *pd) -{ - return get_pm_count(pd) > 0; -} - -static int poseidon_suspend(struct usb_interface *intf, pm_message_t msg) -{ - struct poseidon *pd = get_pd(intf); - - if (!pd) - return 0; - if (!is_working(pd)) { - if (get_pm_count(pd) <= 0 && !in_hibernation(pd)) { - pd->msg.event = PM_EVENT_AUTO_SUSPEND; - pd->pm_resume = NULL; /* a good guard */ - printk(KERN_DEBUG "TLG2300 auto suspend\n"); - } - return 0; - } - pd->msg = msg; /* save it here */ - logpm(pd); - return pd->pm_suspend ? pd->pm_suspend(pd) : 0; -} - -static int poseidon_resume(struct usb_interface *intf) -{ - struct poseidon *pd = get_pd(intf); - - if (!pd) - return 0; - printk(KERN_DEBUG "TLG2300 resume\n"); - - if (!is_working(pd)) { - if (PM_EVENT_AUTO_SUSPEND == pd->msg.event) - pd->msg = PMSG_ON; - return 0; - } - if (in_hibernation(pd)) { - logpm(pd); - return 0; - } - logpm(pd); - return pd->pm_resume ? pd->pm_resume(pd) : 0; -} - -static void hibernation_resume(struct work_struct *w) -{ - struct poseidon *pd = container_of(w, struct poseidon, pm_work); - int count; - - pd->msg.event = 0; /* clear it here */ - pd->state &= ~POSEIDON_STATE_DISCONNECT; - - /* set the new interface's reference */ - count = get_autopm_ref(pd); - while (count--) - usb_autopm_get_interface(pd->interface); - - /* resume the context */ - logpm(pd); - if (pd->pm_resume) - pd->pm_resume(pd); -} -#else /* CONFIG_PM is not enabled: */ -static inline struct poseidon *find_old_poseidon(struct usb_device *udev) -{ - return NULL; -} - -static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev) -{ -} -#endif - -static int check_firmware(struct usb_device *udev) -{ - void *buf; - int ret; - struct cmd_firmware_vers_s *cmd_firm; - - buf = kzalloc(sizeof(*cmd_firm) + sizeof(u32), GFP_KERNEL); - if (!buf) - return -ENOMEM; - ret = usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - REQ_GET_CMD | GET_FW_ID, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, - 0, - buf, - sizeof(*cmd_firm) + sizeof(u32), - USB_CTRL_GET_TIMEOUT); - kfree(buf); - - if (ret < 0) - return firmware_download(udev); - return 0; -} - -static int poseidon_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct poseidon *pd = NULL; - int ret = 0; - int new_one = 0; - - /* download firmware */ - ret = check_firmware(udev); - if (ret) - return ret; - - /* Do I recovery from the hibernate ? */ - pd = find_old_poseidon(udev); - if (!pd) { - pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) - return -ENOMEM; - kref_init(&pd->kref); - set_map_flags(pd, udev); - new_one = 1; - } - - pd->udev = usb_get_dev(udev); - pd->interface = usb_get_intf(interface); - usb_set_intfdata(interface, pd); - - if (new_one) { - logpm(pd); - mutex_init(&pd->lock); - - /* register v4l2 device */ - ret = v4l2_device_register(&interface->dev, &pd->v4l2_dev); - if (ret) - goto err_v4l2; - - /* register devices in directory /dev */ - ret = pd_video_init(pd); - if (ret) - goto err_video; - ret = poseidon_audio_init(pd); - if (ret) - goto err_audio; - ret = poseidon_fm_init(pd); - if (ret) - goto err_fm; - ret = pd_dvb_usb_device_init(pd); - if (ret) - goto err_dvb; - - INIT_LIST_HEAD(&pd->device_list); - list_add_tail(&pd->device_list, &pd_device_list); - } - - device_init_wakeup(&udev->dev, 1); -#ifdef CONFIG_PM - pm_runtime_set_autosuspend_delay(&pd->udev->dev, - 1000 * PM_SUSPEND_DELAY); - usb_enable_autosuspend(pd->udev); - - if (in_hibernation(pd)) { - INIT_WORK(&pd->pm_work, hibernation_resume); - schedule_work(&pd->pm_work); - } -#endif - return 0; -err_dvb: - poseidon_fm_exit(pd); -err_fm: - poseidon_audio_free(pd); -err_audio: - pd_video_exit(pd); -err_video: - v4l2_device_unregister(&pd->v4l2_dev); -err_v4l2: - usb_put_intf(pd->interface); - usb_put_dev(pd->udev); - kfree(pd); - return ret; -} - -static void poseidon_disconnect(struct usb_interface *interface) -{ - struct poseidon *pd = get_pd(interface); - - if (!pd) - return; - logpm(pd); - if (in_hibernation(pd)) - return; - - mutex_lock(&pd->lock); - pd->state |= POSEIDON_STATE_DISCONNECT; - mutex_unlock(&pd->lock); - - /* stop urb transferring */ - stop_all_video_stream(pd); - dvb_stop_streaming(&pd->dvb_data); - - /*unregister v4l2 device */ - v4l2_device_unregister(&pd->v4l2_dev); - - pd_dvb_usb_device_exit(pd); - poseidon_fm_exit(pd); - - poseidon_audio_free(pd); - pd_video_exit(pd); - - usb_set_intfdata(interface, NULL); - kref_put(&pd->kref, poseidon_delete); -} - -static struct usb_driver poseidon_driver = { - .name = "poseidon", - .probe = poseidon_probe, - .disconnect = poseidon_disconnect, - .id_table = id_table, -#ifdef CONFIG_PM - .suspend = poseidon_suspend, - .resume = poseidon_resume, -#endif - .supports_autosuspend = 1, -}; - -static int __init poseidon_init(void) -{ - int ret; - - ret = usb_register(&poseidon_driver); - if (ret) - return ret; - register_pm_notifier(&pm_notifer); - return ret; -} - -static void __exit poseidon_exit(void) -{ - log(); - unregister_pm_notifier(&pm_notifer); - usb_deregister(&poseidon_driver); -} - -module_init(poseidon_init); -module_exit(poseidon_exit); - -MODULE_AUTHOR("Telegent Systems"); -MODULE_DESCRIPTION("For tlg2300-based USB device"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.0.2"); -MODULE_FIRMWARE(TLG2300_FIRMWARE); diff --git a/drivers/staging/media/tlg2300/pd-radio.c b/drivers/staging/media/tlg2300/pd-radio.c deleted file mode 100644 index b391194a840c..000000000000 --- a/drivers/staging/media/tlg2300/pd-radio.c +++ /dev/null @@ -1,339 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pd-common.h" -#include "vendorcmds.h" - -static int set_frequency(struct poseidon *p, __u32 frequency); -static int poseidon_fm_close(struct file *filp); -static int poseidon_fm_open(struct file *filp); - -#define TUNER_FREQ_MIN_FM 76000000U -#define TUNER_FREQ_MAX_FM 108000000U - -#define MAX_PREEMPHASIS (V4L2_PREEMPHASIS_75_uS + 1) -static int preemphasis[MAX_PREEMPHASIS] = { - TLG_TUNE_ASTD_NONE, /* V4L2_PREEMPHASIS_DISABLED */ - TLG_TUNE_ASTD_FM_EUR, /* V4L2_PREEMPHASIS_50_uS */ - TLG_TUNE_ASTD_FM_US, /* V4L2_PREEMPHASIS_75_uS */ -}; - -static int poseidon_check_mode_radio(struct poseidon *p) -{ - int ret; - u32 status; - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/2); - ret = usb_set_interface(p->udev, 0, BULK_ALTERNATE_IFACE); - if (ret < 0) - goto out; - - ret = set_tuner_mode(p, TLG_MODE_FM_RADIO); - if (ret != 0) - goto out; - - ret = send_set_req(p, SGNL_SRC_SEL, TLG_SIG_SRC_ANTENNA, &status); - ret = send_set_req(p, TUNER_AUD_ANA_STD, - p->radio_data.pre_emphasis, &status); - ret |= send_set_req(p, TUNER_AUD_MODE, - TLG_TUNE_TVAUDIO_MODE_STEREO, &status); - ret |= send_set_req(p, AUDIO_SAMPLE_RATE_SEL, - ATV_AUDIO_RATE_48K, &status); - ret |= send_set_req(p, TUNE_FREQ_SELECT, TUNER_FREQ_MIN_FM, &status); -out: - return ret; -} - -#ifdef CONFIG_PM -static int pm_fm_suspend(struct poseidon *p) -{ - logpm(p); - pm_alsa_suspend(p); - usb_set_interface(p->udev, 0, 0); - msleep(300); - return 0; -} - -static int pm_fm_resume(struct poseidon *p) -{ - logpm(p); - poseidon_check_mode_radio(p); - set_frequency(p, p->radio_data.fm_freq); - pm_alsa_resume(p); - return 0; -} -#endif - -static int poseidon_fm_open(struct file *filp) -{ - struct poseidon *p = video_drvdata(filp); - int ret = 0; - - mutex_lock(&p->lock); - if (p->state & POSEIDON_STATE_DISCONNECT) { - ret = -ENODEV; - goto out; - } - - if (p->state && !(p->state & POSEIDON_STATE_FM)) { - ret = -EBUSY; - goto out; - } - ret = v4l2_fh_open(filp); - if (ret) - goto out; - - usb_autopm_get_interface(p->interface); - if (0 == p->state) { - struct video_device *vfd = &p->radio_data.fm_dev; - - /* default pre-emphasis */ - if (p->radio_data.pre_emphasis == 0) - p->radio_data.pre_emphasis = TLG_TUNE_ASTD_FM_EUR; - set_debug_mode(vfd, debug_mode); - - ret = poseidon_check_mode_radio(p); - if (ret < 0) { - usb_autopm_put_interface(p->interface); - goto out; - } - p->state |= POSEIDON_STATE_FM; - } - kref_get(&p->kref); -out: - mutex_unlock(&p->lock); - return ret; -} - -static int poseidon_fm_close(struct file *filp) -{ - struct poseidon *p = video_drvdata(filp); - struct radio_data *fm = &p->radio_data; - uint32_t status; - - mutex_lock(&p->lock); - if (v4l2_fh_is_singular_file(filp)) - p->state &= ~POSEIDON_STATE_FM; - - if (fm->is_radio_streaming && filp == p->file_for_stream) { - fm->is_radio_streaming = 0; - send_set_req(p, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP, &status); - } - usb_autopm_put_interface(p->interface); - mutex_unlock(&p->lock); - - kref_put(&p->kref, poseidon_delete); - return v4l2_fh_release(filp); -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *v) -{ - struct poseidon *p = video_drvdata(file); - - strlcpy(v->driver, "tele-radio", sizeof(v->driver)); - strlcpy(v->card, "Telegent Poseidon", sizeof(v->card)); - usb_make_path(p->udev, v->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - /* Report all capabilities of the USB device */ - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS | - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_AUDIO | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - return 0; -} - -static const struct v4l2_file_operations poseidon_fm_fops = { - .owner = THIS_MODULE, - .open = poseidon_fm_open, - .release = poseidon_fm_close, - .poll = v4l2_ctrl_poll, - .unlocked_ioctl = video_ioctl2, -}; - -static int tlg_fm_vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *vt) -{ - struct poseidon *p = video_drvdata(file); - struct tuner_fm_sig_stat_s fm_stat = {}; - int ret, status, count = 5; - - if (vt->index != 0) - return -EINVAL; - - vt->type = V4L2_TUNER_RADIO; - vt->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW; - vt->rangelow = TUNER_FREQ_MIN_FM * 2 / 125; - vt->rangehigh = TUNER_FREQ_MAX_FM * 2 / 125; - vt->rxsubchans = V4L2_TUNER_SUB_STEREO; - vt->audmode = V4L2_TUNER_MODE_STEREO; - vt->signal = 0; - vt->afc = 0; - strlcpy(vt->name, "Radio", sizeof(vt->name)); - - mutex_lock(&p->lock); - ret = send_get_req(p, TUNER_STATUS, TLG_MODE_FM_RADIO, - &fm_stat, &status, sizeof(fm_stat)); - - while (fm_stat.sig_lock_busy && count-- && !ret) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); - - ret = send_get_req(p, TUNER_STATUS, TLG_MODE_FM_RADIO, - &fm_stat, &status, sizeof(fm_stat)); - } - mutex_unlock(&p->lock); - - if (ret || status) { - vt->signal = 0; - } else if ((fm_stat.sig_present || fm_stat.sig_locked) - && fm_stat.sig_strength == 0) { - vt->signal = 0xffff; - } else - vt->signal = (fm_stat.sig_strength * 255 / 10) << 8; - - return 0; -} - -static int fm_get_freq(struct file *file, void *priv, - struct v4l2_frequency *argp) -{ - struct poseidon *p = video_drvdata(file); - - if (argp->tuner) - return -EINVAL; - argp->frequency = p->radio_data.fm_freq; - return 0; -} - -static int set_frequency(struct poseidon *p, __u32 frequency) -{ - __u32 freq ; - int ret, status; - - mutex_lock(&p->lock); - - ret = send_set_req(p, TUNER_AUD_ANA_STD, - p->radio_data.pre_emphasis, &status); - - freq = (frequency * 125) / 2; /* Hz */ - freq = clamp(freq, TUNER_FREQ_MIN_FM, TUNER_FREQ_MAX_FM); - - ret = send_set_req(p, TUNE_FREQ_SELECT, freq, &status); - if (ret < 0) - goto error ; - ret = send_set_req(p, TAKE_REQUEST, 0, &status); - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); - if (!p->radio_data.is_radio_streaming) { - ret = send_set_req(p, TAKE_REQUEST, 0, &status); - ret = send_set_req(p, PLAY_SERVICE, - TLG_TUNE_PLAY_SVC_START, &status); - p->radio_data.is_radio_streaming = 1; - } - p->radio_data.fm_freq = freq * 2 / 125; -error: - mutex_unlock(&p->lock); - return ret; -} - -static int fm_set_freq(struct file *file, void *priv, - const struct v4l2_frequency *argp) -{ - struct poseidon *p = video_drvdata(file); - - if (argp->tuner) - return -EINVAL; - p->file_for_stream = file; -#ifdef CONFIG_PM - p->pm_suspend = pm_fm_suspend; - p->pm_resume = pm_fm_resume; -#endif - return set_frequency(p, argp->frequency); -} - -static int tlg_fm_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct poseidon *p = container_of(ctrl->handler, struct poseidon, - radio_data.ctrl_handler); - int pre_emphasis; - u32 status; - - switch (ctrl->id) { - case V4L2_CID_TUNE_PREEMPHASIS: - pre_emphasis = preemphasis[ctrl->val]; - send_set_req(p, TUNER_AUD_ANA_STD, pre_emphasis, &status); - p->radio_data.pre_emphasis = pre_emphasis; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) -{ - return vt->index > 0 ? -EINVAL : 0; -} - -static const struct v4l2_ctrl_ops tlg_fm_ctrl_ops = { - .s_ctrl = tlg_fm_s_ctrl, -}; - -static const struct v4l2_ioctl_ops poseidon_fm_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_tuner = tlg_fm_vidioc_g_tuner, - .vidioc_g_frequency = fm_get_freq, - .vidioc_s_frequency = fm_set_freq, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static struct video_device poseidon_fm_template = { - .name = "Telegent-Radio", - .fops = &poseidon_fm_fops, - .minor = -1, - .release = video_device_release_empty, - .ioctl_ops = &poseidon_fm_ioctl_ops, -}; - -int poseidon_fm_init(struct poseidon *p) -{ - struct video_device *vfd = &p->radio_data.fm_dev; - struct v4l2_ctrl_handler *hdl = &p->radio_data.ctrl_handler; - - *vfd = poseidon_fm_template; - - set_frequency(p, TUNER_FREQ_MIN_FM); - v4l2_ctrl_handler_init(hdl, 1); - v4l2_ctrl_new_std_menu(hdl, &tlg_fm_ctrl_ops, V4L2_CID_TUNE_PREEMPHASIS, - V4L2_PREEMPHASIS_75_uS, 0, V4L2_PREEMPHASIS_50_uS); - if (hdl->error) { - v4l2_ctrl_handler_free(hdl); - return hdl->error; - } - vfd->v4l2_dev = &p->v4l2_dev; - vfd->ctrl_handler = hdl; - video_set_drvdata(vfd, p); - return video_register_device(vfd, VFL_TYPE_RADIO, -1); -} - -int poseidon_fm_exit(struct poseidon *p) -{ - video_unregister_device(&p->radio_data.fm_dev); - v4l2_ctrl_handler_free(&p->radio_data.ctrl_handler); - return 0; -} diff --git a/drivers/staging/media/tlg2300/pd-video.c b/drivers/staging/media/tlg2300/pd-video.c deleted file mode 100644 index 8cd7f02fcf9f..000000000000 --- a/drivers/staging/media/tlg2300/pd-video.c +++ /dev/null @@ -1,1570 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "pd-common.h" -#include "vendorcmds.h" - -#ifdef CONFIG_PM -static int pm_video_suspend(struct poseidon *pd); -static int pm_video_resume(struct poseidon *pd); -#endif -static void iso_bubble_handler(struct work_struct *w); - -static int usb_transfer_mode; -module_param(usb_transfer_mode, int, 0644); -MODULE_PARM_DESC(usb_transfer_mode, "0 = Bulk, 1 = Isochronous"); - -static const struct poseidon_format poseidon_formats[] = { - { "YUV 422", V4L2_PIX_FMT_YUYV, 16, 0}, - { "RGB565", V4L2_PIX_FMT_RGB565, 16, 0}, -}; - -static const struct poseidon_tvnorm poseidon_tvnorms[] = { - { V4L2_STD_PAL_D, "PAL-D", TLG_TUNE_VSTD_PAL_D }, - { V4L2_STD_PAL_B, "PAL-B", TLG_TUNE_VSTD_PAL_B }, - { V4L2_STD_PAL_G, "PAL-G", TLG_TUNE_VSTD_PAL_G }, - { V4L2_STD_PAL_H, "PAL-H", TLG_TUNE_VSTD_PAL_H }, - { V4L2_STD_PAL_I, "PAL-I", TLG_TUNE_VSTD_PAL_I }, - { V4L2_STD_PAL_M, "PAL-M", TLG_TUNE_VSTD_PAL_M }, - { V4L2_STD_PAL_N, "PAL-N", TLG_TUNE_VSTD_PAL_N_COMBO }, - { V4L2_STD_PAL_Nc, "PAL-Nc", TLG_TUNE_VSTD_PAL_N_COMBO }, - { V4L2_STD_NTSC_M, "NTSC-M", TLG_TUNE_VSTD_NTSC_M }, - { V4L2_STD_NTSC_M_JP, "NTSC-JP", TLG_TUNE_VSTD_NTSC_M_J }, - { V4L2_STD_SECAM_B, "SECAM-B", TLG_TUNE_VSTD_SECAM_B }, - { V4L2_STD_SECAM_D, "SECAM-D", TLG_TUNE_VSTD_SECAM_D }, - { V4L2_STD_SECAM_G, "SECAM-G", TLG_TUNE_VSTD_SECAM_G }, - { V4L2_STD_SECAM_H, "SECAM-H", TLG_TUNE_VSTD_SECAM_H }, - { V4L2_STD_SECAM_K, "SECAM-K", TLG_TUNE_VSTD_SECAM_K }, - { V4L2_STD_SECAM_K1, "SECAM-K1", TLG_TUNE_VSTD_SECAM_K1 }, - { V4L2_STD_SECAM_L, "SECAM-L", TLG_TUNE_VSTD_SECAM_L }, - { V4L2_STD_SECAM_LC, "SECAM-LC", TLG_TUNE_VSTD_SECAM_L1 }, -}; -static const unsigned int POSEIDON_TVNORMS = ARRAY_SIZE(poseidon_tvnorms); - -struct pd_audio_mode { - u32 tlg_audio_mode; - u32 v4l2_audio_sub; - u32 v4l2_audio_mode; -}; - -static const struct pd_audio_mode pd_audio_modes[] = { - { TLG_TUNE_TVAUDIO_MODE_MONO, V4L2_TUNER_SUB_MONO, - V4L2_TUNER_MODE_MONO }, - { TLG_TUNE_TVAUDIO_MODE_STEREO, V4L2_TUNER_SUB_STEREO, - V4L2_TUNER_MODE_STEREO }, - { TLG_TUNE_TVAUDIO_MODE_LANG_A, V4L2_TUNER_SUB_LANG1, - V4L2_TUNER_MODE_LANG1 }, - { TLG_TUNE_TVAUDIO_MODE_LANG_B, V4L2_TUNER_SUB_LANG2, - V4L2_TUNER_MODE_LANG2 }, - { TLG_TUNE_TVAUDIO_MODE_LANG_C, V4L2_TUNER_SUB_LANG1, - V4L2_TUNER_MODE_LANG1_LANG2 } -}; -static const unsigned int POSEIDON_AUDIOMODS = ARRAY_SIZE(pd_audio_modes); - -struct pd_input { - char *name; - uint32_t tlg_src; -}; - -static const struct pd_input pd_inputs[] = { - { "TV Antenna", TLG_SIG_SRC_ANTENNA }, - { "TV Cable", TLG_SIG_SRC_CABLE }, - { "TV SVideo", TLG_SIG_SRC_SVIDEO }, - { "TV Composite", TLG_SIG_SRC_COMPOSITE } -}; -static const unsigned int POSEIDON_INPUTS = ARRAY_SIZE(pd_inputs); - -struct video_std_to_audio_std { - v4l2_std_id video_std; - int audio_std; -}; - -static const struct video_std_to_audio_std video_to_audio_map[] = { - /* country : { 27, 32, 33, 34, 36, 44, 45, 46, 47, 48, 64, - 65, 86, 351, 352, 353, 354, 358, 372, 852, 972 } */ - { (V4L2_STD_PAL_I | V4L2_STD_PAL_B | V4L2_STD_PAL_D | - V4L2_STD_SECAM_L | V4L2_STD_SECAM_D), TLG_TUNE_ASTD_NICAM }, - - /* country : { 1, 52, 54, 55, 886 } */ - {V4L2_STD_NTSC_M | V4L2_STD_PAL_N | V4L2_STD_PAL_M, TLG_TUNE_ASTD_BTSC}, - - /* country : { 81 } */ - { V4L2_STD_NTSC_M_JP, TLG_TUNE_ASTD_EIAJ }, - - /* other country : TLG_TUNE_ASTD_A2 */ -}; -static const unsigned int map_size = ARRAY_SIZE(video_to_audio_map); - -static int get_audio_std(v4l2_std_id v4l2_std) -{ - int i = 0; - - for (; i < map_size; i++) { - if (v4l2_std & video_to_audio_map[i].video_std) - return video_to_audio_map[i].audio_std; - } - return TLG_TUNE_ASTD_A2; -} - -static int vidioc_querycap(struct file *file, void *fh, - struct v4l2_capability *cap) -{ - struct video_device *vdev = video_devdata(file); - struct poseidon *p = video_get_drvdata(vdev); - - strcpy(cap->driver, "tele-video"); - strcpy(cap->card, "Telegent Poseidon"); - usb_make_path(p->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_TUNER | V4L2_CAP_AUDIO | - V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - if (vdev->vfl_type == VFL_TYPE_VBI) - cap->device_caps |= V4L2_CAP_VBI_CAPTURE; - else - cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS | - V4L2_CAP_RADIO | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE; - return 0; -} - -/*====================================================================*/ -static void init_copy(struct video_data *video, bool index) -{ - struct front_face *front = video->front; - - video->field_count = index; - video->lines_copied = 0; - video->prev_left = 0 ; - video->dst = (char *)videobuf_to_vmalloc(front->curr_frame) - + index * video->lines_size; - video->vbi->copied = 0; /* set it here */ -} - -static bool get_frame(struct front_face *front, int *need_init) -{ - struct videobuf_buffer *vb = front->curr_frame; - - if (vb) - return true; - - spin_lock(&front->queue_lock); - if (!list_empty(&front->active)) { - vb = list_entry(front->active.next, - struct videobuf_buffer, queue); - if (need_init) - *need_init = 1; - front->curr_frame = vb; - list_del_init(&vb->queue); - } - spin_unlock(&front->queue_lock); - - return !!vb; -} - -/* check if the video's buffer is ready */ -static bool get_video_frame(struct front_face *front, struct video_data *video) -{ - int need_init = 0; - bool ret = true; - - ret = get_frame(front, &need_init); - if (ret && need_init) - init_copy(video, 0); - return ret; -} - -static void submit_frame(struct front_face *front) -{ - struct videobuf_buffer *vb = front->curr_frame; - - if (vb == NULL) - return; - - front->curr_frame = NULL; - vb->state = VIDEOBUF_DONE; - vb->field_count++; - v4l2_get_timestamp(&vb->ts); - - wake_up(&vb->done); -} - -/* - * A frame is composed of two fields. If we receive all the two fields, - * call the submit_frame() to submit the whole frame to applications. - */ -static void end_field(struct video_data *video) -{ - if (1 == video->field_count) - submit_frame(video->front); - else - init_copy(video, 1); -} - -static void copy_video_data(struct video_data *video, char *src, - unsigned int count) -{ -#define copy_data(len) \ - do { \ - if (++video->lines_copied > video->lines_per_field) \ - goto overflow; \ - memcpy(video->dst, src, len);\ - video->dst += len + video->lines_size; \ - src += len; \ - count -= len; \ - } while (0) - - while (count && count >= video->lines_size) { - if (video->prev_left) { - copy_data(video->prev_left); - video->prev_left = 0; - continue; - } - copy_data(video->lines_size); - } - if (count && count < video->lines_size) { - memcpy(video->dst, src, count); - - video->prev_left = video->lines_size - count; - video->dst += count; - } - return; - -overflow: - end_field(video); -} - -static void check_trailer(struct video_data *video, char *src, int count) -{ - struct vbi_data *vbi = video->vbi; - int offset; /* trailer's offset */ - char *buf; - - offset = (video->context.pix.sizeimage / 2 + vbi->vbi_size / 2) - - (vbi->copied + video->lines_size * video->lines_copied); - if (video->prev_left) - offset -= (video->lines_size - video->prev_left); - - if (offset > count || offset <= 0) - goto short_package; - - buf = src + offset; - - /* trailer : (VFHS) + U32 + U32 + field_num */ - if (!strncmp(buf, "VFHS", 4)) { - int field_num = *((u32 *)(buf + 12)); - - if ((field_num & 1) ^ video->field_count) { - init_copy(video, video->field_count); - return; - } - copy_video_data(video, src, offset); - } -short_package: - end_field(video); -} - -/* ========== Check this more carefully! =========== */ -static inline void copy_vbi_data(struct vbi_data *vbi, - char *src, unsigned int count) -{ - struct front_face *front = vbi->front; - - if (front && get_frame(front, NULL)) { - char *buf = videobuf_to_vmalloc(front->curr_frame); - - if (vbi->video->field_count) - buf += (vbi->vbi_size / 2); - memcpy(buf + vbi->copied, src, count); - } - vbi->copied += count; -} - -/* - * Copy the normal data (VBI or VIDEO) without the trailer. - * VBI is not interlaced, while VIDEO is interlaced. - */ -static inline void copy_vbi_video_data(struct video_data *video, - char *src, unsigned int count) -{ - struct vbi_data *vbi = video->vbi; - unsigned int vbi_delta = (vbi->vbi_size / 2) - vbi->copied; - - if (vbi_delta >= count) { - copy_vbi_data(vbi, src, count); - } else { - if (vbi_delta) { - copy_vbi_data(vbi, src, vbi_delta); - - /* we receive the two fields of the VBI*/ - if (vbi->front && video->field_count) - submit_frame(vbi->front); - } - copy_video_data(video, src + vbi_delta, count - vbi_delta); - } -} - -static void urb_complete_bulk(struct urb *urb) -{ - struct front_face *front = urb->context; - struct video_data *video = &front->pd->video_data; - char *src = (char *)urb->transfer_buffer; - int count = urb->actual_length; - int ret = 0; - - if (!video->is_streaming || urb->status) { - if (urb->status == -EPROTO) - goto resend_it; - return; - } - if (!get_video_frame(front, video)) - goto resend_it; - - if (count == urb->transfer_buffer_length) - copy_vbi_video_data(video, src, count); - else - check_trailer(video, src, count); - -resend_it: - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) - log(" submit failed: error %d", ret); -} - -/************************* for ISO *********************/ -#define GET_SUCCESS (0) -#define GET_TRAILER (1) -#define GET_TOO_MUCH_BUBBLE (2) -#define GET_NONE (3) -static int get_chunk(int start, struct urb *urb, - int *head, int *tail, int *bubble_err) -{ - struct usb_iso_packet_descriptor *pkt = NULL; - int ret = GET_SUCCESS; - - for (*head = *tail = -1; start < urb->number_of_packets; start++) { - pkt = &urb->iso_frame_desc[start]; - - /* handle the bubble of the Hub */ - if (-EOVERFLOW == pkt->status) { - if (++*bubble_err > urb->number_of_packets / 3) - return GET_TOO_MUCH_BUBBLE; - continue; - } - - /* This is the gap */ - if (pkt->status || pkt->actual_length <= 0 - || pkt->actual_length > ISO_PKT_SIZE) { - if (*head != -1) - break; - continue; - } - - /* a good isochronous packet */ - if (pkt->actual_length == ISO_PKT_SIZE) { - if (*head == -1) - *head = start; - *tail = start; - continue; - } - - /* trailer is here */ - if (pkt->actual_length < ISO_PKT_SIZE) { - if (*head == -1) { - *head = start; - *tail = start; - return GET_TRAILER; - } - break; - } - } - - if (*head == -1 && *tail == -1) - ret = GET_NONE; - return ret; -} - -/* - * |__|------|___|-----|_______| - * ^ ^ - * | | - * gap gap - */ -static void urb_complete_iso(struct urb *urb) -{ - struct front_face *front = urb->context; - struct video_data *video = &front->pd->video_data; - int bubble_err = 0, head = 0, tail = 0; - char *src = (char *)urb->transfer_buffer; - int ret = 0; - - if (!video->is_streaming) - return; - - do { - if (!get_video_frame(front, video)) - goto out; - - switch (get_chunk(head, urb, &head, &tail, &bubble_err)) { - case GET_SUCCESS: - copy_vbi_video_data(video, src + (head * ISO_PKT_SIZE), - (tail - head + 1) * ISO_PKT_SIZE); - break; - case GET_TRAILER: - check_trailer(video, src + (head * ISO_PKT_SIZE), - ISO_PKT_SIZE); - break; - case GET_NONE: - goto out; - case GET_TOO_MUCH_BUBBLE: - log("\t We got too much bubble"); - schedule_work(&video->bubble_work); - return; - } - } while (head = tail + 1, head < urb->number_of_packets); - -out: - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) - log("usb_submit_urb err : %d", ret); -} -/*============================= [ end ] =====================*/ - -static int prepare_iso_urb(struct video_data *video) -{ - struct usb_device *udev = video->pd->udev; - int i; - - if (video->urb_array[0]) - return 0; - - for (i = 0; i < SBUF_NUM; i++) { - struct urb *urb; - void *mem; - int j; - - urb = usb_alloc_urb(PK_PER_URB, GFP_KERNEL); - if (urb == NULL) - goto out; - - video->urb_array[i] = urb; - mem = usb_alloc_coherent(udev, - ISO_PKT_SIZE * PK_PER_URB, - GFP_KERNEL, - &urb->transfer_dma); - - urb->complete = urb_complete_iso; /* handler */ - urb->dev = udev; - urb->context = video->front; - urb->pipe = usb_rcvisocpipe(udev, - video->endpoint_addr); - urb->interval = 1; - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->number_of_packets = PK_PER_URB; - urb->transfer_buffer = mem; - urb->transfer_buffer_length = PK_PER_URB * ISO_PKT_SIZE; - - for (j = 0; j < PK_PER_URB; j++) { - urb->iso_frame_desc[j].offset = ISO_PKT_SIZE * j; - urb->iso_frame_desc[j].length = ISO_PKT_SIZE; - } - } - return 0; -out: - for (; i > 0; i--) - ; - return -ENOMEM; -} - -/* return the succeeded number of the allocation */ -int alloc_bulk_urbs_generic(struct urb **urb_array, int num, - struct usb_device *udev, u8 ep_addr, - int buf_size, gfp_t gfp_flags, - usb_complete_t complete_fn, void *context) -{ - int i = 0; - - for (; i < num; i++) { - void *mem; - struct urb *urb = usb_alloc_urb(0, gfp_flags); - if (urb == NULL) - return i; - - mem = usb_alloc_coherent(udev, buf_size, gfp_flags, - &urb->transfer_dma); - if (mem == NULL) { - usb_free_urb(urb); - return i; - } - - usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, ep_addr), - mem, buf_size, complete_fn, context); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - urb_array[i] = urb; - } - return i; -} - -void free_all_urb_generic(struct urb **urb_array, int num) -{ - int i; - struct urb *urb; - - for (i = 0; i < num; i++) { - urb = urb_array[i]; - if (urb) { - usb_free_coherent(urb->dev, - urb->transfer_buffer_length, - urb->transfer_buffer, - urb->transfer_dma); - usb_free_urb(urb); - urb_array[i] = NULL; - } - } -} - -static int prepare_bulk_urb(struct video_data *video) -{ - if (video->urb_array[0]) - return 0; - - alloc_bulk_urbs_generic(video->urb_array, SBUF_NUM, - video->pd->udev, video->endpoint_addr, - 0x2000, GFP_KERNEL, - urb_complete_bulk, video->front); - return 0; -} - -/* free the URBs */ -static void free_all_urb(struct video_data *video) -{ - free_all_urb_generic(video->urb_array, SBUF_NUM); -} - -static void pd_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - videobuf_vmalloc_free(vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static void pd_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct front_face *front = q->priv_data; - vb->state = VIDEOBUF_QUEUED; - list_add_tail(&vb->queue, &front->active); -} - -static int pd_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct front_face *front = q->priv_data; - int rc; - - switch (front->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (VIDEOBUF_NEEDS_INIT == vb->state) { - struct v4l2_pix_format *pix; - - pix = &front->pd->video_data.context.pix; - vb->size = pix->sizeimage; /* real frame size */ - vb->width = pix->width; - vb->height = pix->height; - rc = videobuf_iolock(q, vb, NULL); - if (rc < 0) - return rc; - } - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->size = front->pd->vbi_data.vbi_size; - rc = videobuf_iolock(q, vb, NULL); - if (rc < 0) - return rc; - } - break; - default: - return -EINVAL; - } - vb->field = field; - vb->state = VIDEOBUF_PREPARED; - return 0; -} - -static int fire_all_urb(struct video_data *video) -{ - int i, ret; - - video->is_streaming = 1; - - for (i = 0; i < SBUF_NUM; i++) { - ret = usb_submit_urb(video->urb_array[i], GFP_KERNEL); - if (ret) - log("(%d) failed: error %d", i, ret); - } - return ret; -} - -static int start_video_stream(struct poseidon *pd) -{ - struct video_data *video = &pd->video_data; - s32 cmd_status; - - send_set_req(pd, TAKE_REQUEST, 0, &cmd_status); - send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_START, &cmd_status); - - if (pd->cur_transfer_mode) { - prepare_iso_urb(video); - INIT_WORK(&video->bubble_work, iso_bubble_handler); - } else { - /* The bulk mode does not need a bubble handler */ - prepare_bulk_urb(video); - } - fire_all_urb(video); - return 0; -} - -static int pd_buf_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - struct front_face *front = q->priv_data; - struct poseidon *pd = front->pd; - - switch (front->type) { - default: - return -EINVAL; - case V4L2_BUF_TYPE_VIDEO_CAPTURE: { - struct video_data *video = &pd->video_data; - struct v4l2_pix_format *pix = &video->context.pix; - - *size = PAGE_ALIGN(pix->sizeimage);/* page aligned frame size */ - if (*count < 4) - *count = 4; - if (1) { - /* same in different altersetting */ - video->endpoint_addr = 0x82; - video->vbi = &pd->vbi_data; - video->vbi->video = video; - video->pd = pd; - video->lines_per_field = pix->height / 2; - video->lines_size = pix->width * 2; - video->front = front; - } - return start_video_stream(pd); - } - - case V4L2_BUF_TYPE_VBI_CAPTURE: { - struct vbi_data *vbi = &pd->vbi_data; - - *size = PAGE_ALIGN(vbi->vbi_size); - log("size : %d", *size); - if (*count == 0) - *count = 4; - } - break; - } - return 0; -} - -static struct videobuf_queue_ops pd_video_qops = { - .buf_setup = pd_buf_setup, - .buf_prepare = pd_buf_prepare, - .buf_queue = pd_buf_queue, - .buf_release = pd_buf_release, -}; - -static int vidioc_enum_fmt(struct file *file, void *fh, - struct v4l2_fmtdesc *f) -{ - if (ARRAY_SIZE(poseidon_formats) <= f->index) - return -EINVAL; - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->flags = 0; - f->pixelformat = poseidon_formats[f->index].fourcc; - strcpy(f->description, poseidon_formats[f->index].name); - return 0; -} - -static int vidioc_g_fmt(struct file *file, void *fh, struct v4l2_format *f) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - - f->fmt.pix = pd->video_data.context.pix; - return 0; -} - -/* - * VLC calls VIDIOC_S_STD before VIDIOC_S_FMT, while - * Mplayer calls them in the reverse order. - */ -static int pd_vidioc_s_fmt(struct poseidon *pd, struct v4l2_pix_format *pix) -{ - struct video_data *video = &pd->video_data; - struct running_context *context = &video->context; - struct v4l2_pix_format *pix_def = &context->pix; - s32 ret = 0, cmd_status = 0, vid_resol; - - /* set the pixel format to firmware */ - if (pix->pixelformat == V4L2_PIX_FMT_RGB565) { - vid_resol = TLG_TUNER_VID_FORMAT_RGB_565; - } else { - pix->pixelformat = V4L2_PIX_FMT_YUYV; - vid_resol = TLG_TUNER_VID_FORMAT_YUV; - } - ret = send_set_req(pd, VIDEO_STREAM_FMT_SEL, - vid_resol, &cmd_status); - - /* set the resolution to firmware */ - vid_resol = TLG_TUNE_VID_RES_720; - switch (pix->width) { - case 704: - vid_resol = TLG_TUNE_VID_RES_704; - break; - default: - pix->width = 720; - case 720: - break; - } - ret |= send_set_req(pd, VIDEO_ROSOLU_SEL, - vid_resol, &cmd_status); - if (ret || cmd_status) - return -EBUSY; - - pix_def->pixelformat = pix->pixelformat; /* save it */ - pix->height = (context->tvnormid & V4L2_STD_525_60) ? 480 : 576; - - /* Compare with the default setting */ - if ((pix_def->width != pix->width) - || (pix_def->height != pix->height)) { - pix_def->width = pix->width; - pix_def->height = pix->height; - pix_def->bytesperline = pix->width * 2; - pix_def->sizeimage = pix->width * pix->height * 2; - } - *pix = *pix_def; - - return 0; -} - -static int vidioc_s_fmt(struct file *file, void *fh, struct v4l2_format *f) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - - /* stop VBI here */ - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type) - return -EINVAL; - - mutex_lock(&pd->lock); - if (pd->file_for_stream == NULL) - pd->file_for_stream = file; - else if (file != pd->file_for_stream) { - mutex_unlock(&pd->lock); - return -EINVAL; - } - - pd_vidioc_s_fmt(pd, &f->fmt.pix); - mutex_unlock(&pd->lock); - return 0; -} - -static int vidioc_g_fmt_vbi(struct file *file, void *fh, - struct v4l2_format *v4l2_f) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - struct v4l2_vbi_format *vbi_fmt = &v4l2_f->fmt.vbi; - - vbi_fmt->samples_per_line = 720 * 2; - vbi_fmt->sampling_rate = 6750000 * 4; - vbi_fmt->sample_format = V4L2_PIX_FMT_GREY; - vbi_fmt->offset = 64 * 4; /*FIXME: why offset */ - if (pd->video_data.context.tvnormid & V4L2_STD_525_60) { - vbi_fmt->start[0] = 10; - vbi_fmt->start[1] = 264; - vbi_fmt->count[0] = V4L_NTSC_VBI_LINES; - vbi_fmt->count[1] = V4L_NTSC_VBI_LINES; - } else { - vbi_fmt->start[0] = 6; - vbi_fmt->start[1] = 314; - vbi_fmt->count[0] = V4L_PAL_VBI_LINES; - vbi_fmt->count[1] = V4L_PAL_VBI_LINES; - } - vbi_fmt->flags = V4L2_VBI_UNSYNC; - return 0; -} - -static int set_std(struct poseidon *pd, v4l2_std_id norm) -{ - struct video_data *video = &pd->video_data; - struct vbi_data *vbi = &pd->vbi_data; - struct running_context *context; - struct v4l2_pix_format *pix; - s32 i, ret = 0, cmd_status, param; - int height; - - for (i = 0; i < POSEIDON_TVNORMS; i++) { - if (norm & poseidon_tvnorms[i].v4l2_id) { - param = poseidon_tvnorms[i].tlg_tvnorm; - log("name : %s", poseidon_tvnorms[i].name); - goto found; - } - } - return -EINVAL; -found: - mutex_lock(&pd->lock); - ret = send_set_req(pd, VIDEO_STD_SEL, param, &cmd_status); - if (ret || cmd_status) - goto out; - - /* Set vbi size and check the height of the frame */ - context = &video->context; - context->tvnormid = poseidon_tvnorms[i].v4l2_id; - if (context->tvnormid & V4L2_STD_525_60) { - vbi->vbi_size = V4L_NTSC_VBI_FRAMESIZE; - height = 480; - } else { - vbi->vbi_size = V4L_PAL_VBI_FRAMESIZE; - height = 576; - } - - pix = &context->pix; - if (pix->height != height) { - pix->height = height; - pix->sizeimage = pix->width * pix->height * 2; - } - -out: - mutex_unlock(&pd->lock); - return ret; -} - -static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id norm) -{ - struct front_face *front = fh; - - return set_std(front->pd, norm); -} - -static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) -{ - struct front_face *front = fh; - - *norm = front->pd->video_data.context.tvnormid; - return 0; -} - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in) -{ - if (in->index >= POSEIDON_INPUTS) - return -EINVAL; - strcpy(in->name, pd_inputs[in->index].name); - in->type = V4L2_INPUT_TYPE_TUNER; - - /* - * the audio input index mixed with this video input, - * Poseidon only have one audio/video, set to "0" - */ - in->audioset = 1; - in->tuner = 0; - in->std = V4L2_STD_ALL; - in->status = 0; - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - struct running_context *context = &pd->video_data.context; - - *i = context->sig_index; - return 0; -} - -/* We can support several inputs */ -static int vidioc_s_input(struct file *file, void *fh, unsigned int i) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - s32 ret, cmd_status; - - if (i >= POSEIDON_INPUTS) - return -EINVAL; - ret = send_set_req(pd, SGNL_SRC_SEL, - pd_inputs[i].tlg_src, &cmd_status); - if (ret) - return ret; - - pd->video_data.context.sig_index = i; - return 0; -} - -static int tlg_s_ctrl(struct v4l2_ctrl *c) -{ - struct poseidon *pd = container_of(c->handler, struct poseidon, - video_data.ctrl_handler); - struct tuner_custom_parameter_s param = {0}; - s32 ret = 0, cmd_status, params; - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - param.param_id = CUST_PARM_ID_BRIGHTNESS_CTRL; - break; - case V4L2_CID_CONTRAST: - param.param_id = CUST_PARM_ID_CONTRAST_CTRL; - break; - case V4L2_CID_HUE: - param.param_id = CUST_PARM_ID_HUE_CTRL; - break; - case V4L2_CID_SATURATION: - param.param_id = CUST_PARM_ID_SATURATION_CTRL; - break; - } - param.param_value = c->val; - params = *(s32 *)¶m; /* temp code */ - - mutex_lock(&pd->lock); - ret = send_set_req(pd, TUNER_CUSTOM_PARAMETER, params, &cmd_status); - ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status); - mutex_unlock(&pd->lock); - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); - return ret; -} - -/* Audio ioctls */ -static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a) -{ - if (0 != a->index) - return -EINVAL; - a->capability = V4L2_AUDCAP_STEREO; - strcpy(a->name, "USB audio in"); - /*Poseidon have no AVL function.*/ - a->mode = 0; - return 0; -} - -static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) -{ - a->index = 0; - a->capability = V4L2_AUDCAP_STEREO; - strcpy(a->name, "USB audio in"); - a->mode = 0; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *a) -{ - return (0 == a->index) ? 0 : -EINVAL; -} - -/* Tuner ioctls */ -static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *tuner) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - struct tuner_atv_sig_stat_s atv_stat; - s32 count = 5, ret, cmd_status; - int index; - - if (0 != tuner->index) - return -EINVAL; - - mutex_lock(&pd->lock); - ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_ANALOG_TV, - &atv_stat, &cmd_status, sizeof(atv_stat)); - - while (atv_stat.sig_lock_busy && count-- && !ret) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); - - ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_ANALOG_TV, - &atv_stat, &cmd_status, sizeof(atv_stat)); - } - mutex_unlock(&pd->lock); - - if (debug_mode) - log("P:%d,S:%d", atv_stat.sig_present, atv_stat.sig_strength); - - if (ret || cmd_status) - tuner->signal = 0; - else if (atv_stat.sig_present && !atv_stat.sig_strength) - tuner->signal = 0xFFFF; - else - tuner->signal = (atv_stat.sig_strength * 255 / 10) << 8; - - strcpy(tuner->name, "Telegent Systems"); - tuner->type = V4L2_TUNER_ANALOG_TV; - tuner->rangelow = TUNER_FREQ_MIN / 62500; - tuner->rangehigh = TUNER_FREQ_MAX / 62500; - tuner->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; - index = pd->video_data.context.audio_idx; - tuner->rxsubchans = pd_audio_modes[index].v4l2_audio_sub; - tuner->audmode = pd_audio_modes[index].v4l2_audio_mode; - tuner->afc = 0; - return 0; -} - -static int pd_vidioc_s_tuner(struct poseidon *pd, int index) -{ - s32 ret = 0, cmd_status, param, audiomode; - - mutex_lock(&pd->lock); - param = pd_audio_modes[index].tlg_audio_mode; - ret = send_set_req(pd, TUNER_AUD_MODE, param, &cmd_status); - audiomode = get_audio_std(pd->video_data.context.tvnormid); - ret |= send_set_req(pd, TUNER_AUD_ANA_STD, audiomode, - &cmd_status); - if (!ret) - pd->video_data.context.audio_idx = index; - mutex_unlock(&pd->lock); - return ret; -} - -static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *a) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - int index; - - if (0 != a->index) - return -EINVAL; - for (index = 0; index < POSEIDON_AUDIOMODS; index++) - if (a->audmode == pd_audio_modes[index].v4l2_audio_mode) - return pd_vidioc_s_tuner(pd, index); - return -EINVAL; -} - -static int vidioc_g_frequency(struct file *file, void *fh, - struct v4l2_frequency *freq) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - struct running_context *context = &pd->video_data.context; - - if (0 != freq->tuner) - return -EINVAL; - freq->frequency = context->freq; - freq->type = V4L2_TUNER_ANALOG_TV; - return 0; -} - -static int set_frequency(struct poseidon *pd, u32 *frequency) -{ - s32 ret = 0, param, cmd_status; - struct running_context *context = &pd->video_data.context; - - *frequency = clamp(*frequency, - TUNER_FREQ_MIN / 62500, TUNER_FREQ_MAX / 62500); - param = (*frequency) * 62500 / 1000; - - mutex_lock(&pd->lock); - ret = send_set_req(pd, TUNE_FREQ_SELECT, param, &cmd_status); - ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status); - - msleep(250); /* wait for a while until the hardware is ready. */ - context->freq = *frequency; - mutex_unlock(&pd->lock); - return ret; -} - -static int vidioc_s_frequency(struct file *file, void *fh, - const struct v4l2_frequency *freq) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - u32 frequency = freq->frequency; - - if (freq->tuner) - return -EINVAL; -#ifdef CONFIG_PM - pd->pm_suspend = pm_video_suspend; - pd->pm_resume = pm_video_resume; -#endif - return set_frequency(pd, &frequency); -} - -static int vidioc_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *b) -{ - struct front_face *front = file->private_data; - return videobuf_reqbufs(&front->q, b); -} - -static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct front_face *front = file->private_data; - return videobuf_querybuf(&front->q, b); -} - -static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct front_face *front = file->private_data; - return videobuf_qbuf(&front->q, b); -} - -static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct front_face *front = file->private_data; - return videobuf_dqbuf(&front->q, b, file->f_flags & O_NONBLOCK); -} - -/* Just stop the URBs, do not free the URBs */ -static int usb_transfer_stop(struct video_data *video) -{ - if (video->is_streaming) { - int i; - s32 cmd_status; - struct poseidon *pd = video->pd; - - video->is_streaming = 0; - for (i = 0; i < SBUF_NUM; ++i) { - if (video->urb_array[i]) - usb_kill_urb(video->urb_array[i]); - } - - send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP, - &cmd_status); - } - return 0; -} - -int stop_all_video_stream(struct poseidon *pd) -{ - struct video_data *video = &pd->video_data; - struct vbi_data *vbi = &pd->vbi_data; - - mutex_lock(&pd->lock); - if (video->is_streaming) { - struct front_face *front = video->front; - - /* stop the URBs */ - usb_transfer_stop(video); - free_all_urb(video); - - /* stop the host side of VIDEO */ - videobuf_stop(&front->q); - videobuf_mmap_free(&front->q); - - /* stop the host side of VBI */ - front = vbi->front; - if (front) { - videobuf_stop(&front->q); - videobuf_mmap_free(&front->q); - } - } - mutex_unlock(&pd->lock); - return 0; -} - -/* - * The bubbles can seriously damage the video's quality, - * though it occurs in very rare situation. - */ -static void iso_bubble_handler(struct work_struct *w) -{ - struct video_data *video; - struct poseidon *pd; - - video = container_of(w, struct video_data, bubble_work); - pd = video->pd; - - mutex_lock(&pd->lock); - usb_transfer_stop(video); - msleep(500); - start_video_stream(pd); - mutex_unlock(&pd->lock); -} - - -static int vidioc_streamon(struct file *file, void *fh, - enum v4l2_buf_type type) -{ - struct front_face *front = fh; - - if (unlikely(type != front->type)) - return -EINVAL; - return videobuf_streamon(&front->q); -} - -static int vidioc_streamoff(struct file *file, void *fh, - enum v4l2_buf_type type) -{ - struct front_face *front = file->private_data; - - if (unlikely(type != front->type)) - return -EINVAL; - return videobuf_streamoff(&front->q); -} - -/* Set the firmware's default values : need altersetting */ -static int pd_video_checkmode(struct poseidon *pd) -{ - s32 ret = 0, cmd_status, audiomode; - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/2); - - /* choose the altersetting */ - ret = usb_set_interface(pd->udev, 0, - (pd->cur_transfer_mode ? - ISO_3K_BULK_ALTERNATE_IFACE : - BULK_ALTERNATE_IFACE)); - if (ret < 0) - goto error; - - /* set default parameters for PAL-D , with the VBI enabled*/ - ret = set_tuner_mode(pd, TLG_MODE_ANALOG_TV); - ret |= send_set_req(pd, SGNL_SRC_SEL, - TLG_SIG_SRC_ANTENNA, &cmd_status); - ret |= send_set_req(pd, VIDEO_STD_SEL, - TLG_TUNE_VSTD_PAL_D, &cmd_status); - ret |= send_set_req(pd, VIDEO_STREAM_FMT_SEL, - TLG_TUNER_VID_FORMAT_YUV, &cmd_status); - ret |= send_set_req(pd, VIDEO_ROSOLU_SEL, - TLG_TUNE_VID_RES_720, &cmd_status); - ret |= send_set_req(pd, TUNE_FREQ_SELECT, TUNER_FREQ_MIN, &cmd_status); - ret |= send_set_req(pd, VBI_DATA_SEL, 1, &cmd_status);/* enable vbi */ - - /* set the audio */ - audiomode = get_audio_std(pd->video_data.context.tvnormid); - ret |= send_set_req(pd, TUNER_AUD_ANA_STD, audiomode, &cmd_status); - ret |= send_set_req(pd, TUNER_AUD_MODE, - TLG_TUNE_TVAUDIO_MODE_STEREO, &cmd_status); - ret |= send_set_req(pd, AUDIO_SAMPLE_RATE_SEL, - ATV_AUDIO_RATE_48K, &cmd_status); -error: - return ret; -} - -#ifdef CONFIG_PM -static int pm_video_suspend(struct poseidon *pd) -{ - /* stop audio */ - pm_alsa_suspend(pd); - - /* stop and free all the URBs */ - usb_transfer_stop(&pd->video_data); - free_all_urb(&pd->video_data); - - /* reset the interface */ - usb_set_interface(pd->udev, 0, 0); - msleep(300); - return 0; -} - -static int restore_v4l2_context(struct poseidon *pd, - struct running_context *context) -{ - struct front_face *front = pd->video_data.front; - - pd_video_checkmode(pd); - - set_std(pd, context->tvnormid); - vidioc_s_input(NULL, front, context->sig_index); - pd_vidioc_s_tuner(pd, context->audio_idx); - pd_vidioc_s_fmt(pd, &context->pix); - set_frequency(pd, &context->freq); - return 0; -} - -static int pm_video_resume(struct poseidon *pd) -{ - struct video_data *video = &pd->video_data; - - /* resume the video */ - /* [1] restore the origin V4L2 parameters */ - restore_v4l2_context(pd, &video->context); - - /* [2] initiate video copy variables */ - if (video->front->curr_frame) - init_copy(video, 0); - - /* [3] fire urbs */ - start_video_stream(pd); - - /* resume the audio */ - pm_alsa_resume(pd); - return 0; -} -#endif - -void set_debug_mode(struct video_device *vfd, int debug_mode) -{ - vfd->debug = 0; - if (debug_mode & 0x1) - vfd->debug = V4L2_DEBUG_IOCTL; - if (debug_mode & 0x2) - vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; -} - -static void init_video_context(struct running_context *context) -{ - context->sig_index = 0; - context->audio_idx = 1; /* stereo */ - context->tvnormid = V4L2_STD_PAL_D; - context->pix = (struct v4l2_pix_format) { - .width = 720, - .height = 576, - .pixelformat = V4L2_PIX_FMT_YUYV, - .field = V4L2_FIELD_INTERLACED, - .bytesperline = 720 * 2, - .sizeimage = 720 * 576 * 2, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - }; -} - -static int pd_video_open(struct file *file) -{ - struct video_device *vfd = video_devdata(file); - struct poseidon *pd = video_get_drvdata(vfd); - struct front_face *front = NULL; - int ret = -ENOMEM; - - mutex_lock(&pd->lock); - usb_autopm_get_interface(pd->interface); - - if (pd->state && !(pd->state & POSEIDON_STATE_ANALOG)) { - ret = -EBUSY; - goto out; - } - front = kzalloc(sizeof(struct front_face), GFP_KERNEL); - if (!front) - goto out; - if (vfd->vfl_type == VFL_TYPE_GRABBER) { - pd->cur_transfer_mode = usb_transfer_mode;/* bulk or iso */ - init_video_context(&pd->video_data.context); - - ret = pd_video_checkmode(pd); - if (ret < 0) { - kfree(front); - ret = -1; - goto out; - } - - front->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - pd->video_data.users++; - set_debug_mode(vfd, debug_mode); - - videobuf_queue_vmalloc_init(&front->q, &pd_video_qops, - NULL, &front->queue_lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED,/* video is interlacd */ - sizeof(struct videobuf_buffer),/*it's enough*/ - front, NULL); - } else { - front->type = V4L2_BUF_TYPE_VBI_CAPTURE; - pd->vbi_data.front = front; - pd->vbi_data.users++; - - videobuf_queue_vmalloc_init(&front->q, &pd_video_qops, - NULL, &front->queue_lock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_NONE, /* vbi is NONE mode */ - sizeof(struct videobuf_buffer), - front, NULL); - } - - pd->state |= POSEIDON_STATE_ANALOG; - front->pd = pd; - front->curr_frame = NULL; - INIT_LIST_HEAD(&front->active); - spin_lock_init(&front->queue_lock); - - file->private_data = front; - kref_get(&pd->kref); - - mutex_unlock(&pd->lock); - return 0; -out: - usb_autopm_put_interface(pd->interface); - mutex_unlock(&pd->lock); - return ret; -} - -static int pd_video_release(struct file *file) -{ - struct front_face *front = file->private_data; - struct poseidon *pd = front->pd; - s32 cmd_status = 0; - - mutex_lock(&pd->lock); - - if (front->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - /* stop the device, and free the URBs */ - usb_transfer_stop(&pd->video_data); - free_all_urb(&pd->video_data); - - /* stop the firmware */ - send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP, - &cmd_status); - - pd->file_for_stream = NULL; - pd->video_data.users--; - } else if (front->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - pd->vbi_data.front = NULL; - pd->vbi_data.users--; - } - if (!pd->vbi_data.users && !pd->video_data.users) - pd->state &= ~POSEIDON_STATE_ANALOG; - videobuf_stop(&front->q); - videobuf_mmap_free(&front->q); - - usb_autopm_put_interface(pd->interface); - mutex_unlock(&pd->lock); - - kfree(front); - file->private_data = NULL; - kref_put(&pd->kref, poseidon_delete); - return 0; -} - -static int pd_video_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct front_face *front = file->private_data; - return videobuf_mmap_mapper(&front->q, vma); -} - -static unsigned int pd_video_poll(struct file *file, poll_table *table) -{ - struct front_face *front = file->private_data; - return videobuf_poll_stream(file, &front->q, table); -} - -static ssize_t pd_video_read(struct file *file, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct front_face *front = file->private_data; - return videobuf_read_stream(&front->q, buffer, count, ppos, - 0, file->f_flags & O_NONBLOCK); -} - -/* This struct works for both VIDEO and VBI */ -static const struct v4l2_file_operations pd_video_fops = { - .owner = THIS_MODULE, - .open = pd_video_open, - .release = pd_video_release, - .read = pd_video_read, - .poll = pd_video_poll, - .mmap = pd_video_mmap, - .ioctl = video_ioctl2, /* maybe changed in future */ -}; - -static const struct v4l2_ioctl_ops pd_video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - - /* Video format */ - .vidioc_g_fmt_vid_cap = vidioc_g_fmt, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt, - .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi, /* VBI */ - - /* Input */ - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_enum_input = vidioc_enum_input, - - /* Audio ioctls */ - .vidioc_enumaudio = vidioc_enumaudio, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - - /* Tuner ioctls */ - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_std = vidioc_g_std, - .vidioc_s_std = vidioc_s_std, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - - /* Buffer handlers */ - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - - /* Stream on/off */ - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, -}; - -static struct video_device pd_video_template = { - .name = "Telegent-Video", - .fops = &pd_video_fops, - .minor = -1, - .release = video_device_release_empty, - .tvnorms = V4L2_STD_ALL, - .ioctl_ops = &pd_video_ioctl_ops, -}; - -static const struct v4l2_ctrl_ops tlg_ctrl_ops = { - .s_ctrl = tlg_s_ctrl, -}; - -void pd_video_exit(struct poseidon *pd) -{ - struct video_data *video = &pd->video_data; - struct vbi_data *vbi = &pd->vbi_data; - - video_unregister_device(&video->v_dev); - video_unregister_device(&vbi->v_dev); - v4l2_ctrl_handler_free(&video->ctrl_handler); - log(); -} - -int pd_video_init(struct poseidon *pd) -{ - struct video_data *video = &pd->video_data; - struct vbi_data *vbi = &pd->vbi_data; - struct v4l2_ctrl_handler *hdl = &video->ctrl_handler; - u32 freq = TUNER_FREQ_MIN / 62500; - int ret = -ENOMEM; - - v4l2_ctrl_handler_init(hdl, 4); - v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_BRIGHTNESS, - 0, 10000, 1, 100); - v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_CONTRAST, - 0, 10000, 1, 100); - v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_HUE, - 0, 10000, 1, 100); - v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_SATURATION, - 0, 10000, 1, 100); - if (hdl->error) { - v4l2_ctrl_handler_free(hdl); - return hdl->error; - } - set_frequency(pd, &freq); - video->v_dev = pd_video_template; - video->v_dev.v4l2_dev = &pd->v4l2_dev; - video->v_dev.ctrl_handler = hdl; - video_set_drvdata(&video->v_dev, pd); - - ret = video_register_device(&video->v_dev, VFL_TYPE_GRABBER, -1); - if (ret != 0) - goto out; - - /* VBI uses the same template as video */ - vbi->v_dev = pd_video_template; - vbi->v_dev.v4l2_dev = &pd->v4l2_dev; - vbi->v_dev.ctrl_handler = hdl; - video_set_drvdata(&vbi->v_dev, pd); - ret = video_register_device(&vbi->v_dev, VFL_TYPE_VBI, -1); - if (ret != 0) - goto out; - log("register VIDEO/VBI devices"); - return 0; -out: - log("VIDEO/VBI devices register failed, : %d", ret); - pd_video_exit(pd); - return ret; -} diff --git a/drivers/staging/media/tlg2300/vendorcmds.h b/drivers/staging/media/tlg2300/vendorcmds.h deleted file mode 100644 index ba6f4ae3b2c2..000000000000 --- a/drivers/staging/media/tlg2300/vendorcmds.h +++ /dev/null @@ -1,243 +0,0 @@ -#ifndef VENDOR_CMD_H_ -#define VENDOR_CMD_H_ - -#define BULK_ALTERNATE_IFACE (2) -#define ISO_3K_BULK_ALTERNATE_IFACE (1) -#define REQ_SET_CMD (0X00) -#define REQ_GET_CMD (0X80) - -enum tlg__analog_audio_standard { - TLG_TUNE_ASTD_NONE = 0x00000000, - TLG_TUNE_ASTD_A2 = 0x00000001, - TLG_TUNE_ASTD_NICAM = 0x00000002, - TLG_TUNE_ASTD_EIAJ = 0x00000004, - TLG_TUNE_ASTD_BTSC = 0x00000008, - TLG_TUNE_ASTD_FM_US = 0x00000010, - TLG_TUNE_ASTD_FM_EUR = 0x00000020, - TLG_TUNE_ASTD_ALL = 0x0000003f -}; - -/* - * identifiers for Custom Parameter messages. - * @typedef cmd_custom_param_id_t - */ -enum cmd_custom_param_id { - CUST_PARM_ID_NONE = 0x00, - CUST_PARM_ID_BRIGHTNESS_CTRL = 0x01, - CUST_PARM_ID_CONTRAST_CTRL = 0x02, - CUST_PARM_ID_HUE_CTRL = 0x03, - CUST_PARM_ID_SATURATION_CTRL = 0x04, - CUST_PARM_ID_AUDIO_SNR_THRESHOLD = 0x10, - CUST_PARM_ID_AUDIO_AGC_THRESHOLD = 0x11, - CUST_PARM_ID_MAX -}; - -struct tuner_custom_parameter_s { - uint16_t param_id; /* Parameter identifier */ - uint16_t param_value; /* Parameter value */ -}; - -struct tuner_ber_rate_s { - uint32_t ber_rate; /* BER sample rate in seconds */ -}; - -struct tuner_atv_sig_stat_s { - uint32_t sig_present; - uint32_t sig_locked; - uint32_t sig_lock_busy; - uint32_t sig_strength; /* milliDb */ - uint32_t tv_audio_chan; /* mono/stereo/sap*/ - uint32_t mvision_stat; /* macrovision status */ -}; - -struct tuner_dtv_sig_stat_s { - uint32_t sig_present; /* Boolean*/ - uint32_t sig_locked; /* Boolean */ - uint32_t sig_lock_busy; /* Boolean (Can this time-out?) */ - uint32_t sig_strength; /* milliDb*/ -}; - -struct tuner_fm_sig_stat_s { - uint32_t sig_present; /* Boolean*/ - uint32_t sig_locked; /* Boolean */ - uint32_t sig_lock_busy; /* Boolean */ - uint32_t sig_stereo_mono;/* TBD*/ - uint32_t sig_strength; /* milliDb*/ -}; - -enum _tag_tlg_tune_srv_cmd { - TLG_TUNE_PLAY_SVC_START = 1, - TLG_TUNE_PLAY_SVC_STOP -}; - -enum _tag_tune_atv_audio_mode_caps { - TLG_TUNE_TVAUDIO_MODE_MONO = 0x00000001, - TLG_TUNE_TVAUDIO_MODE_STEREO = 0x00000002, - TLG_TUNE_TVAUDIO_MODE_LANG_A = 0x00000010,/* Primary language*/ - TLG_TUNE_TVAUDIO_MODE_LANG_B = 0x00000020,/* 2nd avail language*/ - TLG_TUNE_TVAUDIO_MODE_LANG_C = 0x00000040 -}; - - -enum _tag_tuner_atv_audio_rates { - ATV_AUDIO_RATE_NONE = 0x00,/* Audio not supported*/ - ATV_AUDIO_RATE_32K = 0x01,/* Audio rate = 32 KHz*/ - ATV_AUDIO_RATE_48K = 0x02, /* Audio rate = 48 KHz*/ - ATV_AUDIO_RATE_31_25K = 0x04 /* Audio rate = 31.25KHz */ -}; - -enum _tag_tune_atv_vid_res_caps { - TLG_TUNE_VID_RES_NONE = 0x00000000, - TLG_TUNE_VID_RES_720 = 0x00000001, - TLG_TUNE_VID_RES_704 = 0x00000002, - TLG_TUNE_VID_RES_360 = 0x00000004 -}; - -enum _tag_tuner_analog_video_format { - TLG_TUNER_VID_FORMAT_YUV = 0x00000001, - TLG_TUNER_VID_FORMAT_YCRCB = 0x00000002, - TLG_TUNER_VID_FORMAT_RGB_565 = 0x00000004, -}; - -enum tlg_ext_audio_support { - TLG_EXT_AUDIO_NONE = 0x00,/* No external audio input supported */ - TLG_EXT_AUDIO_LR = 0x01/* LR external audio inputs supported*/ -}; - -enum { - TLG_MODE_NONE = 0x00, /* No Mode specified*/ - TLG_MODE_ANALOG_TV = 0x01, /* Analog Television mode*/ - TLG_MODE_ANALOG_TV_UNCOMP = 0x01, /* Analog Television mode*/ - TLG_MODE_ANALOG_TV_COMP = 0x02, /* Analog TV mode (compressed)*/ - TLG_MODE_FM_RADIO = 0x04, /* FM Radio mode*/ - TLG_MODE_DVB_T = 0x08, /* Digital TV (DVB-T)*/ -}; - -enum tlg_signal_sources_t { - TLG_SIG_SRC_NONE = 0x00,/* Signal source not specified */ - TLG_SIG_SRC_ANTENNA = 0x01,/* Signal src is: Antenna */ - TLG_SIG_SRC_CABLE = 0x02,/* Signal src is: Coax Cable*/ - TLG_SIG_SRC_SVIDEO = 0x04,/* Signal src is: S_VIDEO */ - TLG_SIG_SRC_COMPOSITE = 0x08 /* Signal src is: Composite Video */ -}; - -enum tuner_analog_video_standard { - TLG_TUNE_VSTD_NONE = 0x00000000, - TLG_TUNE_VSTD_NTSC_M = 0x00000001, - TLG_TUNE_VSTD_NTSC_M_J = 0x00000002,/* Japan */ - TLG_TUNE_VSTD_PAL_B = 0x00000010, - TLG_TUNE_VSTD_PAL_D = 0x00000020, - TLG_TUNE_VSTD_PAL_G = 0x00000040, - TLG_TUNE_VSTD_PAL_H = 0x00000080, - TLG_TUNE_VSTD_PAL_I = 0x00000100, - TLG_TUNE_VSTD_PAL_M = 0x00000200, - TLG_TUNE_VSTD_PAL_N = 0x00000400, - TLG_TUNE_VSTD_SECAM_B = 0x00001000, - TLG_TUNE_VSTD_SECAM_D = 0x00002000, - TLG_TUNE_VSTD_SECAM_G = 0x00004000, - TLG_TUNE_VSTD_SECAM_H = 0x00008000, - TLG_TUNE_VSTD_SECAM_K = 0x00010000, - TLG_TUNE_VSTD_SECAM_K1 = 0x00020000, - TLG_TUNE_VSTD_SECAM_L = 0x00040000, - TLG_TUNE_VSTD_SECAM_L1 = 0x00080000, - TLG_TUNE_VSTD_PAL_N_COMBO = 0x00100000 -}; - -enum tlg_mode_caps { - TLG_MODE_CAPS_NONE = 0x00, /* No Mode specified */ - TLG_MODE_CAPS_ANALOG_TV_UNCOMP = 0x01, /* Analog TV mode */ - TLG_MODE_CAPS_ANALOG_TV_COMP = 0x02, /* Analog TV (compressed)*/ - TLG_MODE_CAPS_FM_RADIO = 0x04, /* FM Radio mode */ - TLG_MODE_CAPS_DVB_T = 0x08, /* Digital TV (DVB-T) */ -}; - -enum poseidon_vendor_cmds { - LAST_CMD_STAT = 0x00, - GET_CHIP_ID = 0x01, - GET_FW_ID = 0x02, - PRODUCT_CAPS = 0x03, - - TUNE_MODE_CAP_ATV = 0x10, - TUNE_MODE_CAP_ATVCOMP = 0X10, - TUNE_MODE_CAP_DVBT = 0x10, - TUNE_MODE_CAP_FM = 0x10, - TUNE_MODE_SELECT = 0x11, - TUNE_FREQ_SELECT = 0x12, - SGNL_SRC_SEL = 0x13, - - VIDEO_STD_SEL = 0x14, - VIDEO_STREAM_FMT_SEL = 0x15, - VIDEO_ROSOLU_AVAIL = 0x16, - VIDEO_ROSOLU_SEL = 0x17, - VIDEO_CONT_PROTECT = 0x20, - - VCR_TIMING_MODSEL = 0x21, - EXT_AUDIO_CAP = 0x22, - EXT_AUDIO_SEL = 0x23, - TEST_PATTERN_SEL = 0x24, - VBI_DATA_SEL = 0x25, - AUDIO_SAMPLE_RATE_CAP = 0x28, - AUDIO_SAMPLE_RATE_SEL = 0x29, - TUNER_AUD_MODE = 0x2a, - TUNER_AUD_MODE_AVAIL = 0x2b, - TUNER_AUD_ANA_STD = 0x2c, - TUNER_CUSTOM_PARAMETER = 0x2f, - - DVBT_TUNE_MODE_SEL = 0x30, - DVBT_BANDW_CAP = 0x31, - DVBT_BANDW_SEL = 0x32, - DVBT_GUARD_INTERV_CAP = 0x33, - DVBT_GUARD_INTERV_SEL = 0x34, - DVBT_MODULATION_CAP = 0x35, - DVBT_MODULATION_SEL = 0x36, - DVBT_INNER_FEC_RATE_CAP = 0x37, - DVBT_INNER_FEC_RATE_SEL = 0x38, - DVBT_TRANS_MODE_CAP = 0x39, - DVBT_TRANS_MODE_SEL = 0x3a, - DVBT_SEARCH_RANG = 0x3c, - - TUNER_SETUP_ANALOG = 0x40, - TUNER_SETUP_DIGITAL = 0x41, - TUNER_SETUP_FM_RADIO = 0x42, - TAKE_REQUEST = 0x43, /* Take effect of the command */ - PLAY_SERVICE = 0x44, /* Play start or Play stop */ - TUNER_STATUS = 0x45, - TUNE_PROP_DVBT = 0x46, - ERR_RATE_STATS = 0x47, - TUNER_BER_RATE = 0x48, - - SCAN_CAPS = 0x50, - SCAN_SETUP = 0x51, - SCAN_SERVICE = 0x52, - SCAN_STATS = 0x53, - - PID_SET = 0x58, - PID_UNSET = 0x59, - PID_LIST = 0x5a, - - IRD_CAP = 0x60, - IRD_MODE_SEL = 0x61, - IRD_SETUP = 0x62, - - PTM_MODE_CAP = 0x70, - PTM_MODE_SEL = 0x71, - PTM_SERVICE = 0x72, - TUNER_REG_SCRIPT = 0x73, - CMD_CHIP_RST = 0x74, -}; - -enum tlg_bw { - TLG_BW_5 = 5, - TLG_BW_6 = 6, - TLG_BW_7 = 7, - TLG_BW_8 = 8, - TLG_BW_12 = 12, - TLG_BW_15 = 15 -}; - -struct cmd_firmware_vers_s { - uint8_t fw_rev_major; - uint8_t fw_rev_minor; - uint16_t fw_patch; -}; -#endif /* VENDOR_CMD_H_ */ diff --git a/drivers/staging/media/vino/Kconfig b/drivers/staging/media/vino/Kconfig deleted file mode 100644 index 03700dadafd8..000000000000 --- a/drivers/staging/media/vino/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -config VIDEO_VINO - tristate "SGI Vino Video For Linux (Deprecated)" - depends on I2C && SGI_IP22 && VIDEO_V4L2 - select VIDEO_SAA7191 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to build in support for the Vino video input system found - on SGI Indy machines. - - This driver is deprecated and will be removed soon. If you have - hardware for this and you want to work on this driver, then contact - the linux-media mailinglist. - -config VIDEO_SAA7191 - tristate "Philips SAA7191 video decoder (Deprecated)" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Philips SAA7191 video decoder. - - This driver is deprecated and will be removed soon. If you have - hardware for this and you want to work on this driver, then contact - the linux-media mailinglist. - - To compile this driver as a module, choose M here: the - module will be called saa7191. diff --git a/drivers/staging/media/vino/Makefile b/drivers/staging/media/vino/Makefile deleted file mode 100644 index 914c2513687c..000000000000 --- a/drivers/staging/media/vino/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_VIDEO_VINO) += indycam.o -obj-$(CONFIG_VIDEO_VINO) += vino.o -obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o diff --git a/drivers/staging/media/vino/indycam.c b/drivers/staging/media/vino/indycam.c deleted file mode 100644 index f1d192bbcb4c..000000000000 --- a/drivers/staging/media/vino/indycam.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * indycam.c - Silicon Graphics IndyCam digital camera driver - * - * Copyright (C) 2003 Ladislav Michl - * Copyright (C) 2004,2005 Mikael Nousiainen - * - * This 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 - -/* IndyCam decodes stream of photons into digital image representation ;-) */ -#include -#include -#include - -#include "indycam.h" - -#define INDYCAM_MODULE_VERSION "0.0.5" - -MODULE_DESCRIPTION("SGI IndyCam driver"); -MODULE_VERSION(INDYCAM_MODULE_VERSION); -MODULE_AUTHOR("Mikael Nousiainen "); -MODULE_LICENSE("GPL"); - - -// #define INDYCAM_DEBUG - -#ifdef INDYCAM_DEBUG -#define dprintk(x...) printk("IndyCam: " x); -#define indycam_regdump(client) indycam_regdump_debug(client) -#else -#define dprintk(x...) -#define indycam_regdump(client) -#endif - -struct indycam { - struct v4l2_subdev sd; - u8 version; -}; - -static inline struct indycam *to_indycam(struct v4l2_subdev *sd) -{ - return container_of(sd, struct indycam, sd); -} - -static const u8 initseq[] = { - INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */ - INDYCAM_SHUTTER_60, /* INDYCAM_SHUTTER */ - INDYCAM_GAIN_DEFAULT, /* INDYCAM_GAIN */ - 0x00, /* INDYCAM_BRIGHTNESS (read-only) */ - INDYCAM_RED_BALANCE_DEFAULT, /* INDYCAM_RED_BALANCE */ - INDYCAM_BLUE_BALANCE_DEFAULT, /* INDYCAM_BLUE_BALANCE */ - INDYCAM_RED_SATURATION_DEFAULT, /* INDYCAM_RED_SATURATION */ - INDYCAM_BLUE_SATURATION_DEFAULT,/* INDYCAM_BLUE_SATURATION */ -}; - -/* IndyCam register handling */ - -static int indycam_read_reg(struct v4l2_subdev *sd, u8 reg, u8 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (reg == INDYCAM_REG_RESET) { - dprintk("indycam_read_reg(): " - "skipping write-only register %d\n", reg); - *value = 0; - return 0; - } - - ret = i2c_smbus_read_byte_data(client, reg); - - if (ret < 0) { - printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, " - "register = 0x%02x\n", reg); - return ret; - } - - *value = (u8)ret; - - return 0; -} - -static int indycam_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int err; - - if (reg == INDYCAM_REG_BRIGHTNESS || reg == INDYCAM_REG_VERSION) { - dprintk("indycam_write_reg(): " - "skipping read-only register %d\n", reg); - return 0; - } - - dprintk("Writing Reg %d = 0x%02x\n", reg, value); - err = i2c_smbus_write_byte_data(client, reg, value); - - if (err) { - printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, " - "register = 0x%02x, value = 0x%02x\n", reg, value); - } - return err; -} - -static int indycam_write_block(struct v4l2_subdev *sd, u8 reg, - u8 length, u8 *data) -{ - int i, err; - - for (i = 0; i < length; i++) { - err = indycam_write_reg(sd, reg + i, data[i]); - if (err) - return err; - } - - return 0; -} - -/* Helper functions */ - -#ifdef INDYCAM_DEBUG -static void indycam_regdump_debug(struct v4l2_subdev *sd) -{ - int i; - u8 val; - - for (i = 0; i < 9; i++) { - indycam_read_reg(sd, i, &val); - dprintk("Reg %d = 0x%02x\n", i, val); - } -} -#endif - -static int indycam_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct indycam *camera = to_indycam(sd); - u8 reg; - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_AUTOGAIN: - case V4L2_CID_AUTO_WHITE_BALANCE: - ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, ®); - if (ret) - return -EIO; - if (ctrl->id == V4L2_CID_AUTOGAIN) - ctrl->value = (reg & INDYCAM_CONTROL_AGCENA) - ? 1 : 0; - else - ctrl->value = (reg & INDYCAM_CONTROL_AWBCTL) - ? 1 : 0; - break; - case V4L2_CID_EXPOSURE: - ret = indycam_read_reg(sd, INDYCAM_REG_SHUTTER, ®); - if (ret) - return -EIO; - ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1); - break; - case V4L2_CID_GAIN: - ret = indycam_read_reg(sd, INDYCAM_REG_GAIN, ®); - if (ret) - return -EIO; - ctrl->value = (s32)reg; - break; - case V4L2_CID_RED_BALANCE: - ret = indycam_read_reg(sd, INDYCAM_REG_RED_BALANCE, ®); - if (ret) - return -EIO; - ctrl->value = (s32)reg; - break; - case V4L2_CID_BLUE_BALANCE: - ret = indycam_read_reg(sd, INDYCAM_REG_BLUE_BALANCE, ®); - if (ret) - return -EIO; - ctrl->value = (s32)reg; - break; - case INDYCAM_CONTROL_RED_SATURATION: - ret = indycam_read_reg(sd, - INDYCAM_REG_RED_SATURATION, ®); - if (ret) - return -EIO; - ctrl->value = (s32)reg; - break; - case INDYCAM_CONTROL_BLUE_SATURATION: - ret = indycam_read_reg(sd, - INDYCAM_REG_BLUE_SATURATION, ®); - if (ret) - return -EIO; - ctrl->value = (s32)reg; - break; - case V4L2_CID_GAMMA: - if (camera->version == CAMERA_VERSION_MOOSE) { - ret = indycam_read_reg(sd, - INDYCAM_REG_GAMMA, ®); - if (ret) - return -EIO; - ctrl->value = (s32)reg; - } else { - ctrl->value = INDYCAM_GAMMA_DEFAULT; - } - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static int indycam_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct indycam *camera = to_indycam(sd); - u8 reg; - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_AUTOGAIN: - case V4L2_CID_AUTO_WHITE_BALANCE: - ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, ®); - if (ret) - break; - - if (ctrl->id == V4L2_CID_AUTOGAIN) { - if (ctrl->value) - reg |= INDYCAM_CONTROL_AGCENA; - else - reg &= ~INDYCAM_CONTROL_AGCENA; - } else { - if (ctrl->value) - reg |= INDYCAM_CONTROL_AWBCTL; - else - reg &= ~INDYCAM_CONTROL_AWBCTL; - } - - ret = indycam_write_reg(sd, INDYCAM_REG_CONTROL, reg); - break; - case V4L2_CID_EXPOSURE: - reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1); - ret = indycam_write_reg(sd, INDYCAM_REG_SHUTTER, reg); - break; - case V4L2_CID_GAIN: - ret = indycam_write_reg(sd, INDYCAM_REG_GAIN, ctrl->value); - break; - case V4L2_CID_RED_BALANCE: - ret = indycam_write_reg(sd, INDYCAM_REG_RED_BALANCE, - ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_BALANCE, - ctrl->value); - break; - case INDYCAM_CONTROL_RED_SATURATION: - ret = indycam_write_reg(sd, INDYCAM_REG_RED_SATURATION, - ctrl->value); - break; - case INDYCAM_CONTROL_BLUE_SATURATION: - ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_SATURATION, - ctrl->value); - break; - case V4L2_CID_GAMMA: - if (camera->version == CAMERA_VERSION_MOOSE) { - ret = indycam_write_reg(sd, INDYCAM_REG_GAMMA, - ctrl->value); - } - break; - default: - ret = -EINVAL; - } - - return ret; -} - -/* I2C-interface */ - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops indycam_core_ops = { - .g_ctrl = indycam_g_ctrl, - .s_ctrl = indycam_s_ctrl, -}; - -static const struct v4l2_subdev_ops indycam_ops = { - .core = &indycam_core_ops, -}; - -static int indycam_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int err = 0; - struct indycam *camera; - struct v4l2_subdev *sd; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - camera = kzalloc(sizeof(struct indycam), GFP_KERNEL); - if (!camera) - return -ENOMEM; - - sd = &camera->sd; - v4l2_i2c_subdev_init(sd, client, &indycam_ops); - - camera->version = i2c_smbus_read_byte_data(client, - INDYCAM_REG_VERSION); - if (camera->version != CAMERA_VERSION_INDY && - camera->version != CAMERA_VERSION_MOOSE) { - kfree(camera); - return -ENODEV; - } - - printk(KERN_INFO "IndyCam v%d.%d detected\n", - INDYCAM_VERSION_MAJOR(camera->version), - INDYCAM_VERSION_MINOR(camera->version)); - - indycam_regdump(sd); - - // initialize - err = indycam_write_block(sd, 0, sizeof(initseq), (u8 *)&initseq); - if (err) { - printk(KERN_ERR "IndyCam initialization failed\n"); - kfree(camera); - return -EIO; - } - - indycam_regdump(sd); - - // white balance - err = indycam_write_reg(sd, INDYCAM_REG_CONTROL, - INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL); - if (err) { - printk(KERN_ERR "IndyCam: White balancing camera failed\n"); - kfree(camera); - return -EIO; - } - - indycam_regdump(sd); - - printk(KERN_INFO "IndyCam initialized\n"); - - return 0; -} - -static int indycam_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - kfree(to_indycam(sd)); - return 0; -} - -static const struct i2c_device_id indycam_id[] = { - { "indycam", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, indycam_id); - -static struct i2c_driver indycam_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "indycam", - }, - .probe = indycam_probe, - .remove = indycam_remove, - .id_table = indycam_id, -}; - -module_i2c_driver(indycam_driver); diff --git a/drivers/staging/media/vino/indycam.h b/drivers/staging/media/vino/indycam.h deleted file mode 100644 index 881f21c474c4..000000000000 --- a/drivers/staging/media/vino/indycam.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * indycam.h - Silicon Graphics IndyCam digital camera driver - * - * Copyright (C) 2003 Ladislav Michl - * Copyright (C) 2004,2005 Mikael Nousiainen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _INDYCAM_H_ -#define _INDYCAM_H_ - -/* I2C address for the Guinness Camera */ -#define INDYCAM_ADDR 0x56 - -/* Camera version */ -#define CAMERA_VERSION_INDY 0x10 /* v1.0 */ -#define CAMERA_VERSION_MOOSE 0x12 /* v1.2 */ -#define INDYCAM_VERSION_MAJOR(x) (((x) & 0xf0) >> 4) -#define INDYCAM_VERSION_MINOR(x) ((x) & 0x0f) - -/* Register bus addresses */ -#define INDYCAM_REG_CONTROL 0x00 -#define INDYCAM_REG_SHUTTER 0x01 -#define INDYCAM_REG_GAIN 0x02 -#define INDYCAM_REG_BRIGHTNESS 0x03 /* read-only */ -#define INDYCAM_REG_RED_BALANCE 0x04 -#define INDYCAM_REG_BLUE_BALANCE 0x05 -#define INDYCAM_REG_RED_SATURATION 0x06 -#define INDYCAM_REG_BLUE_SATURATION 0x07 -#define INDYCAM_REG_GAMMA 0x08 -#define INDYCAM_REG_VERSION 0x0e /* read-only */ -#define INDYCAM_REG_RESET 0x0f /* write-only */ - -#define INDYCAM_REG_LED 0x46 -#define INDYCAM_REG_ORIENTATION 0x47 -#define INDYCAM_REG_BUTTON 0x48 - -/* Field definitions of registers */ -#define INDYCAM_CONTROL_AGCENA (1<<0) /* automatic gain control */ -#define INDYCAM_CONTROL_AWBCTL (1<<1) /* automatic white balance */ - /* 2-3 are reserved */ -#define INDYCAM_CONTROL_EVNFLD (1<<4) /* read-only */ - -#define INDYCAM_SHUTTER_10000 0x02 /* 1/10000 second */ -#define INDYCAM_SHUTTER_4000 0x04 /* 1/4000 second */ -#define INDYCAM_SHUTTER_2000 0x08 /* 1/2000 second */ -#define INDYCAM_SHUTTER_1000 0x10 /* 1/1000 second */ -#define INDYCAM_SHUTTER_500 0x20 /* 1/500 second */ -#define INDYCAM_SHUTTER_250 0x3f /* 1/250 second */ -#define INDYCAM_SHUTTER_125 0x7e /* 1/125 second */ -#define INDYCAM_SHUTTER_100 0x9e /* 1/100 second */ -#define INDYCAM_SHUTTER_60 0x00 /* 1/60 second */ - -#define INDYCAM_LED_ACTIVE 0x10 -#define INDYCAM_LED_INACTIVE 0x30 -#define INDYCAM_ORIENTATION_BOTTOM_TO_TOP 0x40 -#define INDYCAM_BUTTON_RELEASED 0x10 - -/* Values for controls */ -#define INDYCAM_SHUTTER_MIN 0x00 -#define INDYCAM_SHUTTER_MAX 0xff -#define INDYCAM_GAIN_MIN 0x00 -#define INDYCAM_GAIN_MAX 0xff -#define INDYCAM_RED_BALANCE_MIN 0x00 -#define INDYCAM_RED_BALANCE_MAX 0xff -#define INDYCAM_BLUE_BALANCE_MIN 0x00 -#define INDYCAM_BLUE_BALANCE_MAX 0xff -#define INDYCAM_RED_SATURATION_MIN 0x00 -#define INDYCAM_RED_SATURATION_MAX 0xff -#define INDYCAM_BLUE_SATURATION_MIN 0x00 -#define INDYCAM_BLUE_SATURATION_MAX 0xff -#define INDYCAM_GAMMA_MIN 0x00 -#define INDYCAM_GAMMA_MAX 0xff - -#define INDYCAM_AGC_DEFAULT 1 -#define INDYCAM_AWB_DEFAULT 0 -#define INDYCAM_SHUTTER_DEFAULT 0xff -#define INDYCAM_GAIN_DEFAULT 0x80 -#define INDYCAM_RED_BALANCE_DEFAULT 0x18 -#define INDYCAM_BLUE_BALANCE_DEFAULT 0xa4 -#define INDYCAM_RED_SATURATION_DEFAULT 0x80 -#define INDYCAM_BLUE_SATURATION_DEFAULT 0xc0 -#define INDYCAM_GAMMA_DEFAULT 0x80 - -/* Driver interface definitions */ - -#define INDYCAM_CONTROL_RED_SATURATION (V4L2_CID_PRIVATE_BASE + 0) -#define INDYCAM_CONTROL_BLUE_SATURATION (V4L2_CID_PRIVATE_BASE + 1) - -#endif diff --git a/drivers/staging/media/vino/saa7191.c b/drivers/staging/media/vino/saa7191.c deleted file mode 100644 index 8e9699268a63..000000000000 --- a/drivers/staging/media/vino/saa7191.c +++ /dev/null @@ -1,649 +0,0 @@ -/* - * saa7191.c - Philips SAA7191 video decoder driver - * - * Copyright (C) 2003 Ladislav Michl - * Copyright (C) 2004,2005 Mikael Nousiainen - * - * This 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 "saa7191.h" - -#define SAA7191_MODULE_VERSION "0.0.5" - -MODULE_DESCRIPTION("Philips SAA7191 video decoder driver"); -MODULE_VERSION(SAA7191_MODULE_VERSION); -MODULE_AUTHOR("Mikael Nousiainen "); -MODULE_LICENSE("GPL"); - - -// #define SAA7191_DEBUG - -#ifdef SAA7191_DEBUG -#define dprintk(x...) printk("SAA7191: " x); -#else -#define dprintk(x...) -#endif - -#define SAA7191_SYNC_COUNT 30 -#define SAA7191_SYNC_DELAY 100 /* milliseconds */ - -struct saa7191 { - struct v4l2_subdev sd; - - /* the register values are stored here as the actual - * I2C-registers are write-only */ - u8 reg[25]; - - int input; - v4l2_std_id norm; -}; - -static inline struct saa7191 *to_saa7191(struct v4l2_subdev *sd) -{ - return container_of(sd, struct saa7191, sd); -} - -static const u8 initseq[] = { - 0, /* Subaddress */ - - 0x50, /* (0x50) SAA7191_REG_IDEL */ - - /* 50 Hz signal timing */ - 0x30, /* (0x30) SAA7191_REG_HSYB */ - 0x00, /* (0x00) SAA7191_REG_HSYS */ - 0xe8, /* (0xe8) SAA7191_REG_HCLB */ - 0xb6, /* (0xb6) SAA7191_REG_HCLS */ - 0xf4, /* (0xf4) SAA7191_REG_HPHI */ - - /* control */ - SAA7191_LUMA_APER_1, /* (0x01) SAA7191_REG_LUMA - CVBS mode */ - 0x00, /* (0x00) SAA7191_REG_HUEC */ - 0xf8, /* (0xf8) SAA7191_REG_CKTQ */ - 0xf8, /* (0xf8) SAA7191_REG_CKTS */ - 0x90, /* (0x90) SAA7191_REG_PLSE */ - 0x90, /* (0x90) SAA7191_REG_SESE */ - 0x00, /* (0x00) SAA7191_REG_GAIN */ - SAA7191_STDC_NFEN | SAA7191_STDC_HRMV, /* (0x0c) SAA7191_REG_STDC - * - not SECAM, - * slow time constant */ - SAA7191_IOCK_OEDC | SAA7191_IOCK_OEHS | SAA7191_IOCK_OEVS - | SAA7191_IOCK_OEDY, /* (0x78) SAA7191_REG_IOCK - * - chroma from CVBS, GPSW1 & 2 off */ - SAA7191_CTL3_AUFD | SAA7191_CTL3_SCEN | SAA7191_CTL3_OFTS - | SAA7191_CTL3_YDEL0, /* (0x99) SAA7191_REG_CTL3 - * - automatic field detection */ - 0x00, /* (0x00) SAA7191_REG_CTL4 */ - 0x2c, /* (0x2c) SAA7191_REG_CHCV - PAL nominal value */ - 0x00, /* unused */ - 0x00, /* unused */ - - /* 60 Hz signal timing */ - 0x34, /* (0x34) SAA7191_REG_HS6B */ - 0x0a, /* (0x0a) SAA7191_REG_HS6S */ - 0xf4, /* (0xf4) SAA7191_REG_HC6B */ - 0xce, /* (0xce) SAA7191_REG_HC6S */ - 0xf4, /* (0xf4) SAA7191_REG_HP6I */ -}; - -/* SAA7191 register handling */ - -static u8 saa7191_read_reg(struct v4l2_subdev *sd, u8 reg) -{ - return to_saa7191(sd)->reg[reg]; -} - -static int saa7191_read_status(struct v4l2_subdev *sd, u8 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - ret = i2c_master_recv(client, value, 1); - if (ret < 0) { - printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed\n"); - return ret; - } - - return 0; -} - - -static int saa7191_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - to_saa7191(sd)->reg[reg] = value; - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* the first byte of data must be the first subaddress number (register) */ -static int saa7191_write_block(struct v4l2_subdev *sd, - u8 length, const u8 *data) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct saa7191 *decoder = to_saa7191(sd); - int i; - int ret; - - for (i = 0; i < (length - 1); i++) { - decoder->reg[data[0] + i] = data[i + 1]; - } - - ret = i2c_master_send(client, data, length); - if (ret < 0) { - printk(KERN_ERR "SAA7191: saa7191_write_block(): " - "write failed\n"); - return ret; - } - - return 0; -} - -/* Helper functions */ - -static int saa7191_s_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct saa7191 *decoder = to_saa7191(sd); - u8 luma = saa7191_read_reg(sd, SAA7191_REG_LUMA); - u8 iock = saa7191_read_reg(sd, SAA7191_REG_IOCK); - int err; - - switch (input) { - case SAA7191_INPUT_COMPOSITE: /* Set Composite input */ - iock &= ~(SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1 - | SAA7191_IOCK_GPSW2); - /* Chrominance trap active */ - luma &= ~SAA7191_LUMA_BYPS; - break; - case SAA7191_INPUT_SVIDEO: /* Set S-Video input */ - iock |= SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW2; - /* Chrominance trap bypassed */ - luma |= SAA7191_LUMA_BYPS; - break; - default: - return -EINVAL; - } - - err = saa7191_write_reg(sd, SAA7191_REG_LUMA, luma); - if (err) - return -EIO; - err = saa7191_write_reg(sd, SAA7191_REG_IOCK, iock); - if (err) - return -EIO; - - decoder->input = input; - - return 0; -} - -static int saa7191_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) -{ - struct saa7191 *decoder = to_saa7191(sd); - u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC); - u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3); - u8 chcv = saa7191_read_reg(sd, SAA7191_REG_CHCV); - int err; - - if (norm & V4L2_STD_PAL) { - stdc &= ~SAA7191_STDC_SECS; - ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL); - chcv = SAA7191_CHCV_PAL; - } else if (norm & V4L2_STD_NTSC) { - stdc &= ~SAA7191_STDC_SECS; - ctl3 &= ~SAA7191_CTL3_AUFD; - ctl3 |= SAA7191_CTL3_FSEL; - chcv = SAA7191_CHCV_NTSC; - } else if (norm & V4L2_STD_SECAM) { - stdc |= SAA7191_STDC_SECS; - ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL); - chcv = SAA7191_CHCV_PAL; - } else { - return -EINVAL; - } - - err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3); - if (err) - return -EIO; - err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc); - if (err) - return -EIO; - err = saa7191_write_reg(sd, SAA7191_REG_CHCV, chcv); - if (err) - return -EIO; - - decoder->norm = norm; - - dprintk("ctl3: %02x stdc: %02x chcv: %02x\n", ctl3, - stdc, chcv); - dprintk("norm: %llx\n", norm); - - return 0; -} - -static int saa7191_wait_for_signal(struct v4l2_subdev *sd, u8 *status) -{ - int i = 0; - - dprintk("Checking for signal...\n"); - - for (i = 0; i < SAA7191_SYNC_COUNT; i++) { - if (saa7191_read_status(sd, status)) - return -EIO; - - if (((*status) & SAA7191_STATUS_HLCK) == 0) { - dprintk("Signal found\n"); - return 0; - } - - msleep(SAA7191_SYNC_DELAY); - } - - dprintk("No signal\n"); - - return -EBUSY; -} - -static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm) -{ - struct saa7191 *decoder = to_saa7191(sd); - u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC); - u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3); - u8 status; - v4l2_std_id old_norm = decoder->norm; - int err = 0; - - dprintk("SAA7191 extended signal auto-detection...\n"); - - *norm &= V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; - stdc &= ~SAA7191_STDC_SECS; - ctl3 &= ~(SAA7191_CTL3_FSEL); - - err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc); - if (err) { - err = -EIO; - goto out; - } - err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3); - if (err) { - err = -EIO; - goto out; - } - - ctl3 |= SAA7191_CTL3_AUFD; - err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3); - if (err) { - err = -EIO; - goto out; - } - - msleep(SAA7191_SYNC_DELAY); - - err = saa7191_wait_for_signal(sd, &status); - if (err) - goto out; - - if (status & SAA7191_STATUS_FIDT) { - /* 60Hz signal -> NTSC */ - dprintk("60Hz signal: NTSC\n"); - *norm &= V4L2_STD_NTSC; - return 0; - } - - /* 50Hz signal */ - dprintk("50Hz signal: Trying PAL...\n"); - - /* try PAL first */ - err = saa7191_s_std(sd, V4L2_STD_PAL); - if (err) - goto out; - - msleep(SAA7191_SYNC_DELAY); - - err = saa7191_wait_for_signal(sd, &status); - if (err) - goto out; - - /* not 50Hz ? */ - if (status & SAA7191_STATUS_FIDT) { - dprintk("No 50Hz signal\n"); - saa7191_s_std(sd, old_norm); - *norm = V4L2_STD_UNKNOWN; - return 0; - } - - if (status & SAA7191_STATUS_CODE) { - dprintk("PAL\n"); - *norm &= V4L2_STD_PAL; - return saa7191_s_std(sd, old_norm); - } - - dprintk("No color detected with PAL - Trying SECAM...\n"); - - /* no color detected ? -> try SECAM */ - err = saa7191_s_std(sd, V4L2_STD_SECAM); - if (err) - goto out; - - msleep(SAA7191_SYNC_DELAY); - - err = saa7191_wait_for_signal(sd, &status); - if (err) - goto out; - - /* not 50Hz ? */ - if (status & SAA7191_STATUS_FIDT) { - dprintk("No 50Hz signal\n"); - *norm = V4L2_STD_UNKNOWN; - goto out; - } - - if (status & SAA7191_STATUS_CODE) { - /* Color detected -> SECAM */ - dprintk("SECAM\n"); - *norm &= V4L2_STD_SECAM; - return saa7191_s_std(sd, old_norm); - } - - dprintk("No color detected with SECAM - Going back to PAL.\n"); - *norm = V4L2_STD_UNKNOWN; - -out: - return saa7191_s_std(sd, old_norm); -} - -static int saa7191_autodetect_norm(struct v4l2_subdev *sd) -{ - u8 status; - - dprintk("SAA7191 signal auto-detection...\n"); - - dprintk("Reading status...\n"); - - if (saa7191_read_status(sd, &status)) - return -EIO; - - dprintk("Checking for signal...\n"); - - /* no signal ? */ - if (status & SAA7191_STATUS_HLCK) { - dprintk("No signal\n"); - return -EBUSY; - } - - dprintk("Signal found\n"); - - if (status & SAA7191_STATUS_FIDT) { - /* 60hz signal -> NTSC */ - dprintk("NTSC\n"); - return saa7191_s_std(sd, V4L2_STD_NTSC); - } else { - /* 50hz signal -> PAL */ - dprintk("PAL\n"); - return saa7191_s_std(sd, V4L2_STD_PAL); - } -} - -static int saa7191_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - u8 reg; - int ret = 0; - - switch (ctrl->id) { - case SAA7191_CONTROL_BANDPASS: - case SAA7191_CONTROL_BANDPASS_WEIGHT: - case SAA7191_CONTROL_CORING: - reg = saa7191_read_reg(sd, SAA7191_REG_LUMA); - switch (ctrl->id) { - case SAA7191_CONTROL_BANDPASS: - ctrl->value = ((s32)reg & SAA7191_LUMA_BPSS_MASK) - >> SAA7191_LUMA_BPSS_SHIFT; - break; - case SAA7191_CONTROL_BANDPASS_WEIGHT: - ctrl->value = ((s32)reg & SAA7191_LUMA_APER_MASK) - >> SAA7191_LUMA_APER_SHIFT; - break; - case SAA7191_CONTROL_CORING: - ctrl->value = ((s32)reg & SAA7191_LUMA_CORI_MASK) - >> SAA7191_LUMA_CORI_SHIFT; - break; - } - break; - case SAA7191_CONTROL_FORCE_COLOUR: - case SAA7191_CONTROL_CHROMA_GAIN: - reg = saa7191_read_reg(sd, SAA7191_REG_GAIN); - if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR) - ctrl->value = ((s32)reg & SAA7191_GAIN_COLO) ? 1 : 0; - else - ctrl->value = ((s32)reg & SAA7191_GAIN_LFIS_MASK) - >> SAA7191_GAIN_LFIS_SHIFT; - break; - case V4L2_CID_HUE: - reg = saa7191_read_reg(sd, SAA7191_REG_HUEC); - if (reg < 0x80) - reg += 0x80; - else - reg -= 0x80; - ctrl->value = (s32)reg; - break; - case SAA7191_CONTROL_VTRC: - reg = saa7191_read_reg(sd, SAA7191_REG_STDC); - ctrl->value = ((s32)reg & SAA7191_STDC_VTRC) ? 1 : 0; - break; - case SAA7191_CONTROL_LUMA_DELAY: - reg = saa7191_read_reg(sd, SAA7191_REG_CTL3); - ctrl->value = ((s32)reg & SAA7191_CTL3_YDEL_MASK) - >> SAA7191_CTL3_YDEL_SHIFT; - if (ctrl->value >= 4) - ctrl->value -= 8; - break; - case SAA7191_CONTROL_VNR: - reg = saa7191_read_reg(sd, SAA7191_REG_CTL4); - ctrl->value = ((s32)reg & SAA7191_CTL4_VNOI_MASK) - >> SAA7191_CTL4_VNOI_SHIFT; - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static int saa7191_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - u8 reg; - int ret = 0; - - switch (ctrl->id) { - case SAA7191_CONTROL_BANDPASS: - case SAA7191_CONTROL_BANDPASS_WEIGHT: - case SAA7191_CONTROL_CORING: - reg = saa7191_read_reg(sd, SAA7191_REG_LUMA); - switch (ctrl->id) { - case SAA7191_CONTROL_BANDPASS: - reg &= ~SAA7191_LUMA_BPSS_MASK; - reg |= (ctrl->value << SAA7191_LUMA_BPSS_SHIFT) - & SAA7191_LUMA_BPSS_MASK; - break; - case SAA7191_CONTROL_BANDPASS_WEIGHT: - reg &= ~SAA7191_LUMA_APER_MASK; - reg |= (ctrl->value << SAA7191_LUMA_APER_SHIFT) - & SAA7191_LUMA_APER_MASK; - break; - case SAA7191_CONTROL_CORING: - reg &= ~SAA7191_LUMA_CORI_MASK; - reg |= (ctrl->value << SAA7191_LUMA_CORI_SHIFT) - & SAA7191_LUMA_CORI_MASK; - break; - } - ret = saa7191_write_reg(sd, SAA7191_REG_LUMA, reg); - break; - case SAA7191_CONTROL_FORCE_COLOUR: - case SAA7191_CONTROL_CHROMA_GAIN: - reg = saa7191_read_reg(sd, SAA7191_REG_GAIN); - if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR) { - if (ctrl->value) - reg |= SAA7191_GAIN_COLO; - else - reg &= ~SAA7191_GAIN_COLO; - } else { - reg &= ~SAA7191_GAIN_LFIS_MASK; - reg |= (ctrl->value << SAA7191_GAIN_LFIS_SHIFT) - & SAA7191_GAIN_LFIS_MASK; - } - ret = saa7191_write_reg(sd, SAA7191_REG_GAIN, reg); - break; - case V4L2_CID_HUE: - reg = ctrl->value & 0xff; - if (reg < 0x80) - reg += 0x80; - else - reg -= 0x80; - ret = saa7191_write_reg(sd, SAA7191_REG_HUEC, reg); - break; - case SAA7191_CONTROL_VTRC: - reg = saa7191_read_reg(sd, SAA7191_REG_STDC); - if (ctrl->value) - reg |= SAA7191_STDC_VTRC; - else - reg &= ~SAA7191_STDC_VTRC; - ret = saa7191_write_reg(sd, SAA7191_REG_STDC, reg); - break; - case SAA7191_CONTROL_LUMA_DELAY: { - s32 value = ctrl->value; - if (value < 0) - value += 8; - reg = saa7191_read_reg(sd, SAA7191_REG_CTL3); - reg &= ~SAA7191_CTL3_YDEL_MASK; - reg |= (value << SAA7191_CTL3_YDEL_SHIFT) - & SAA7191_CTL3_YDEL_MASK; - ret = saa7191_write_reg(sd, SAA7191_REG_CTL3, reg); - break; - } - case SAA7191_CONTROL_VNR: - reg = saa7191_read_reg(sd, SAA7191_REG_CTL4); - reg &= ~SAA7191_CTL4_VNOI_MASK; - reg |= (ctrl->value << SAA7191_CTL4_VNOI_SHIFT) - & SAA7191_CTL4_VNOI_MASK; - ret = saa7191_write_reg(sd, SAA7191_REG_CTL4, reg); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -/* I2C-interface */ - -static int saa7191_g_input_status(struct v4l2_subdev *sd, u32 *status) -{ - u8 status_reg; - int res = V4L2_IN_ST_NO_SIGNAL; - - if (saa7191_read_status(sd, &status_reg)) - return -EIO; - if ((status_reg & SAA7191_STATUS_HLCK) == 0) - res = 0; - if (!(status_reg & SAA7191_STATUS_CODE)) - res |= V4L2_IN_ST_NO_COLOR; - *status = res; - return 0; -} - - -/* ----------------------------------------------------------------------- */ - -static const struct v4l2_subdev_core_ops saa7191_core_ops = { - .g_ctrl = saa7191_g_ctrl, - .s_ctrl = saa7191_s_ctrl, -}; - -static const struct v4l2_subdev_video_ops saa7191_video_ops = { - .s_std = saa7191_s_std, - .s_routing = saa7191_s_routing, - .querystd = saa7191_querystd, - .g_input_status = saa7191_g_input_status, -}; - -static const struct v4l2_subdev_ops saa7191_ops = { - .core = &saa7191_core_ops, - .video = &saa7191_video_ops, -}; - -static int saa7191_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int err = 0; - struct saa7191 *decoder; - struct v4l2_subdev *sd; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL); - if (!decoder) - return -ENOMEM; - - sd = &decoder->sd; - v4l2_i2c_subdev_init(sd, client, &saa7191_ops); - - err = saa7191_write_block(sd, sizeof(initseq), initseq); - if (err) { - printk(KERN_ERR "SAA7191 initialization failed\n"); - return err; - } - - printk(KERN_INFO "SAA7191 initialized\n"); - - decoder->input = SAA7191_INPUT_COMPOSITE; - decoder->norm = V4L2_STD_PAL; - - err = saa7191_autodetect_norm(sd); - if (err && (err != -EBUSY)) - printk(KERN_ERR "SAA7191: Signal auto-detection failed\n"); - - return 0; -} - -static int saa7191_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - v4l2_device_unregister_subdev(sd); - return 0; -} - -static const struct i2c_device_id saa7191_id[] = { - { "saa7191", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, saa7191_id); - -static struct i2c_driver saa7191_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "saa7191", - }, - .probe = saa7191_probe, - .remove = saa7191_remove, - .id_table = saa7191_id, -}; - -module_i2c_driver(saa7191_driver); diff --git a/drivers/staging/media/vino/saa7191.h b/drivers/staging/media/vino/saa7191.h deleted file mode 100644 index 803c74d6066f..000000000000 --- a/drivers/staging/media/vino/saa7191.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - * saa7191.h - Philips SAA7191 video decoder driver - * - * Copyright (C) 2003 Ladislav Michl - * Copyright (C) 2004,2005 Mikael Nousiainen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _SAA7191_H_ -#define _SAA7191_H_ - -/* Philips SAA7191 DMSD I2C bus address */ -#define SAA7191_ADDR 0x8a - -/* Register subaddresses. */ -#define SAA7191_REG_IDEL 0x00 -#define SAA7191_REG_HSYB 0x01 -#define SAA7191_REG_HSYS 0x02 -#define SAA7191_REG_HCLB 0x03 -#define SAA7191_REG_HCLS 0x04 -#define SAA7191_REG_HPHI 0x05 -#define SAA7191_REG_LUMA 0x06 -#define SAA7191_REG_HUEC 0x07 -#define SAA7191_REG_CKTQ 0x08 /* bits 3-7 */ -#define SAA7191_REG_CKTS 0x09 /* bits 3-7 */ -#define SAA7191_REG_PLSE 0x0a -#define SAA7191_REG_SESE 0x0b -#define SAA7191_REG_GAIN 0x0c -#define SAA7191_REG_STDC 0x0d -#define SAA7191_REG_IOCK 0x0e -#define SAA7191_REG_CTL3 0x0f -#define SAA7191_REG_CTL4 0x10 -#define SAA7191_REG_CHCV 0x11 -#define SAA7191_REG_HS6B 0x14 -#define SAA7191_REG_HS6S 0x15 -#define SAA7191_REG_HC6B 0x16 -#define SAA7191_REG_HC6S 0x17 -#define SAA7191_REG_HP6I 0x18 -#define SAA7191_REG_STATUS 0xff /* not really a subaddress */ - -/* Status Register definitions */ -#define SAA7191_STATUS_CODE 0x01 /* color detected flag */ -#define SAA7191_STATUS_FIDT 0x20 /* signal type 50/60 Hz */ -#define SAA7191_STATUS_HLCK 0x40 /* PLL unlocked(1)/locked(0) */ -#define SAA7191_STATUS_STTC 0x80 /* tv/vtr time constant */ - -/* Luminance Control Register definitions */ -/* input mode select bit: - * 0=CVBS (chrominance trap active), 1=S-Video (trap bypassed) */ -#define SAA7191_LUMA_BYPS 0x80 -/* pre-filter (only when chrominance trap is active) */ -#define SAA7191_LUMA_PREF 0x40 -/* aperture bandpass to select different characteristics with maximums - * (bits 4-5) */ -#define SAA7191_LUMA_BPSS_MASK 0x30 -#define SAA7191_LUMA_BPSS_SHIFT 4 -#define SAA7191_LUMA_BPSS_3 0x30 -#define SAA7191_LUMA_BPSS_2 0x20 -#define SAA7191_LUMA_BPSS_1 0x10 -#define SAA7191_LUMA_BPSS_0 0x00 -/* coring range for high frequency components according to 8-bit luminance - * (bits 2-3) - * 0=coring off, n= (+-)n LSB */ -#define SAA7191_LUMA_CORI_MASK 0x0c -#define SAA7191_LUMA_CORI_SHIFT 2 -#define SAA7191_LUMA_CORI_3 0x0c -#define SAA7191_LUMA_CORI_2 0x08 -#define SAA7191_LUMA_CORI_1 0x04 -#define SAA7191_LUMA_CORI_0 0x00 -/* aperture bandpass filter weights high frequency components of luminance - * signal (bits 0-1) - * 0=factor 0, 1=0.25, 2=0.5, 3=1 */ -#define SAA7191_LUMA_APER_MASK 0x03 -#define SAA7191_LUMA_APER_SHIFT 0 -#define SAA7191_LUMA_APER_3 0x03 -#define SAA7191_LUMA_APER_2 0x02 -#define SAA7191_LUMA_APER_1 0x01 -#define SAA7191_LUMA_APER_0 0x00 - -/* Chrominance Gain Control Settings Register definitions */ -/* colour on: 0=automatic colour-killer enabled, 1=forced colour on */ -#define SAA7191_GAIN_COLO 0x80 -/* chrominance gain control (AGC filter) - * 0=loop filter time constant slow, 1=medium, 2=fast, 3=actual gain */ -#define SAA7191_GAIN_LFIS_MASK 0x60 -#define SAA7191_GAIN_LFIS_SHIFT 5 -#define SAA7191_GAIN_LFIS_3 0x60 -#define SAA7191_GAIN_LFIS_2 0x40 -#define SAA7191_GAIN_LFIS_1 0x20 -#define SAA7191_GAIN_LFIS_0 0x00 - -/* Standard/Mode Control Register definitions */ -/* tv/vtr mode bit: 0=TV mode (slow time constant), - * 1=VTR mode (fast time constant) */ -#define SAA7191_STDC_VTRC 0x80 -/* SAA7191B-specific functions enable (RTCO, ODD and GPSW0 outputs) - * 0=outputs set to high-impedance (circuit equals SAA7191), 1=enabled */ -#define SAA7191_STDC_NFEN 0x08 -/* HREF generation: 0=like SAA7191, 1=HREF is 8xLLC2 clocks earlier */ -#define SAA7191_STDC_HRMV 0x04 -/* general purpose switch 0 - * (not used with VINO afaik) */ -#define SAA7191_STDC_GPSW0 0x02 -/* SECAM mode bit: 0=other standards, 1=SECAM */ -#define SAA7191_STDC_SECS 0x01 - -/* I/O and Clock Control Register definitions */ -/* horizontal clock PLL: 0=PLL closed, - * 1=PLL circuit open and horizontal freq fixed */ -#define SAA7191_IOCK_HPLL 0x80 -/* colour-difference output enable (outputs UV0-UV7) */ -#define SAA7191_IOCK_OEDC 0x40 -/* H-sync output enable */ -#define SAA7191_IOCK_OEHS 0x20 -/* V-sync output enable */ -#define SAA7191_IOCK_OEVS 0x10 -/* luminance output enable (outputs Y0-Y7) */ -#define SAA7191_IOCK_OEDY 0x08 -/* S-VHS bit (chrominance from CVBS or from chrominance input): - * 0=controlled by BYPS-bit, 1=from chrominance input */ -#define SAA7191_IOCK_CHRS 0x04 -/* general purpose switch 2 - * VINO-specific: 0=used with CVBS, 1=used with S-Video */ -#define SAA7191_IOCK_GPSW2 0x02 -/* general purpose switch 1 */ -/* VINO-specific: 0=always, 1=not used!*/ -#define SAA7191_IOCK_GPSW1 0x01 - -/* Miscellaneous Control #1 Register definitions */ -/* automatic field detection (50/60Hz standard) */ -#define SAA7191_CTL3_AUFD 0x80 -/* field select: (if AUFD=0) - * 0=50Hz (625 lines), 1=60Hz (525 lines) */ -#define SAA7191_CTL3_FSEL 0x40 -/* SECAM cross-colour reduction enable */ -#define SAA7191_CTL3_SXCR 0x20 -/* sync and clamping pulse enable (HCL and HSY outputs) */ -#define SAA7191_CTL3_SCEN 0x10 -/* output format: 0=4:1:1, 1=4:2:2 (4:2:2 for VINO) */ -#define SAA7191_CTL3_OFTS 0x08 -/* luminance delay compensation - * 0=0*2/LLC, 1=+1*2/LLC, 2=+2*2/LLC, 3=+3*2/LLC, - * 4=-4*2/LLC, 5=-3*2/LLC, 6=-2*2/LLC, 7=-1*2/LLC - * step size = 2/LLC = 67.8ns for 50Hz, 81.5ns for 60Hz */ -#define SAA7191_CTL3_YDEL_MASK 0x07 -#define SAA7191_CTL3_YDEL_SHIFT 0 -#define SAA7191_CTL3_YDEL2 0x04 -#define SAA7191_CTL3_YDEL1 0x02 -#define SAA7191_CTL3_YDEL0 0x01 - -/* Miscellaneous Control #2 Register definitions */ -/* select HREF position - * 0=normal, HREF is matched to YUV output port, - * 1=HREF is matched to CVBS input port */ -#define SAA7191_CTL4_HRFS 0x04 -/* vertical noise reduction - * 0=normal, 1=searching window, 2=auto-deflection, 3=reduction bypassed */ -#define SAA7191_CTL4_VNOI_MASK 0x03 -#define SAA7191_CTL4_VNOI_SHIFT 0 -#define SAA7191_CTL4_VNOI_3 0x03 -#define SAA7191_CTL4_VNOI_2 0x02 -#define SAA7191_CTL4_VNOI_1 0x01 -#define SAA7191_CTL4_VNOI_0 0x00 - -/* Chrominance Gain Control Register definitions - * - for QAM-modulated input signals, effects output amplitude - * (SECAM gain fixed) - * (nominal values for UV CCIR level) */ -#define SAA7191_CHCV_NTSC 0x2c -#define SAA7191_CHCV_PAL 0x59 - -/* Driver interface definitions */ -#define SAA7191_INPUT_COMPOSITE 0 -#define SAA7191_INPUT_SVIDEO 1 - -#define SAA7191_NORM_PAL 1 -#define SAA7191_NORM_NTSC 2 -#define SAA7191_NORM_SECAM 3 - -struct saa7191_status { - /* 0=no signal, 1=signal detected */ - int signal; - /* 0=50hz (pal) signal, 1=60hz (ntsc) signal */ - int signal_60hz; - /* 0=no color detected, 1=color detected */ - int color; - - /* current SAA7191_INPUT_ */ - int input; - /* current SAA7191_NORM_ */ - int norm; -}; - -#define SAA7191_BANDPASS_MIN 0x00 -#define SAA7191_BANDPASS_MAX 0x03 -#define SAA7191_BANDPASS_DEFAULT 0x00 - -#define SAA7191_BANDPASS_WEIGHT_MIN 0x00 -#define SAA7191_BANDPASS_WEIGHT_MAX 0x03 -#define SAA7191_BANDPASS_WEIGHT_DEFAULT 0x01 - -#define SAA7191_CORING_MIN 0x00 -#define SAA7191_CORING_MAX 0x03 -#define SAA7191_CORING_DEFAULT 0x00 - -#define SAA7191_HUE_MIN 0x00 -#define SAA7191_HUE_MAX 0xff -#define SAA7191_HUE_DEFAULT 0x80 - -#define SAA7191_VTRC_MIN 0x00 -#define SAA7191_VTRC_MAX 0x01 -#define SAA7191_VTRC_DEFAULT 0x00 - -#define SAA7191_FORCE_COLOUR_MIN 0x00 -#define SAA7191_FORCE_COLOUR_MAX 0x01 -#define SAA7191_FORCE_COLOUR_DEFAULT 0x00 - -#define SAA7191_CHROMA_GAIN_MIN 0x00 -#define SAA7191_CHROMA_GAIN_MAX 0x03 -#define SAA7191_CHROMA_GAIN_DEFAULT 0x00 - -#define SAA7191_LUMA_DELAY_MIN -0x04 -#define SAA7191_LUMA_DELAY_MAX 0x03 -#define SAA7191_LUMA_DELAY_DEFAULT 0x01 - -#define SAA7191_VNR_MIN 0x00 -#define SAA7191_VNR_MAX 0x03 -#define SAA7191_VNR_DEFAULT 0x00 - -#define SAA7191_CONTROL_BANDPASS (V4L2_CID_PRIVATE_BASE + 0) -#define SAA7191_CONTROL_BANDPASS_WEIGHT (V4L2_CID_PRIVATE_BASE + 1) -#define SAA7191_CONTROL_CORING (V4L2_CID_PRIVATE_BASE + 2) -#define SAA7191_CONTROL_FORCE_COLOUR (V4L2_CID_PRIVATE_BASE + 3) -#define SAA7191_CONTROL_CHROMA_GAIN (V4L2_CID_PRIVATE_BASE + 4) -#define SAA7191_CONTROL_VTRC (V4L2_CID_PRIVATE_BASE + 5) -#define SAA7191_CONTROL_LUMA_DELAY (V4L2_CID_PRIVATE_BASE + 6) -#define SAA7191_CONTROL_VNR (V4L2_CID_PRIVATE_BASE + 7) - -#define DECODER_SAA7191_GET_STATUS _IOR('d', 195, struct saa7191_status) -#define DECODER_SAA7191_SET_NORM _IOW('d', 196, int) - -#endif diff --git a/drivers/staging/media/vino/vino.c b/drivers/staging/media/vino/vino.c deleted file mode 100644 index 2c85357f774d..000000000000 --- a/drivers/staging/media/vino/vino.c +++ /dev/null @@ -1,4345 +0,0 @@ -/* - * Driver for the VINO (Video In No Out) system found in SGI Indys. - * - * This file is subject to the terms and conditions of the GNU General Public - * License version 2 as published by the Free Software Foundation. - * - * Copyright (C) 2004,2005 Mikael Nousiainen - * - * Based on the previous version of the driver for 2.4 kernels by: - * Copyright (C) 2003 Ladislav Michl - * - * v4l2_device/v4l2_subdev conversion by: - * Copyright (C) 2009 Hans Verkuil - * - * Note: this conversion is untested! Please contact the linux-media - * mailinglist if you can test this, together with the test results. - */ - -/* - * TODO: - * - remove "mark pages reserved-hacks" from memory allocation code - * and implement fault() - * - check decimation, calculating and reporting image size when - * using decimation - * - implement read(), user mode buffers and overlay (?) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "vino.h" -#include "saa7191.h" -#include "indycam.h" - -/* Uncomment the following line to get lots and lots of (mostly useless) - * debug info. - * Note that the debug output also slows down the driver significantly */ -// #define VINO_DEBUG -// #define VINO_DEBUG_INT - -#define VINO_MODULE_VERSION "0.0.7" - -MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver"); -MODULE_VERSION(VINO_MODULE_VERSION); -MODULE_AUTHOR("Mikael Nousiainen "); -MODULE_LICENSE("GPL"); - -#ifdef VINO_DEBUG -#define dprintk(x...) printk("VINO: " x); -#else -#define dprintk(x...) -#endif - -#define VINO_NO_CHANNEL 0 -#define VINO_CHANNEL_A 1 -#define VINO_CHANNEL_B 2 - -#define VINO_PAL_WIDTH 768 -#define VINO_PAL_HEIGHT 576 -#define VINO_NTSC_WIDTH 640 -#define VINO_NTSC_HEIGHT 480 - -#define VINO_MIN_WIDTH 32 -#define VINO_MIN_HEIGHT 32 - -#define VINO_CLIPPING_START_ODD_D1 1 -#define VINO_CLIPPING_START_ODD_PAL 15 -#define VINO_CLIPPING_START_ODD_NTSC 12 - -#define VINO_CLIPPING_START_EVEN_D1 2 -#define VINO_CLIPPING_START_EVEN_PAL 15 -#define VINO_CLIPPING_START_EVEN_NTSC 12 - -#define VINO_INPUT_CHANNEL_COUNT 3 - -/* the number is the index for vino_inputs */ -#define VINO_INPUT_NONE -1 -#define VINO_INPUT_COMPOSITE 0 -#define VINO_INPUT_SVIDEO 1 -#define VINO_INPUT_D1 2 - -#define VINO_PAGE_RATIO (PAGE_SIZE / VINO_PAGE_SIZE) - -#define VINO_FIFO_THRESHOLD_DEFAULT 16 - -#define VINO_FRAMEBUFFER_SIZE ((VINO_PAL_WIDTH \ - * VINO_PAL_HEIGHT * 4 \ - + 3 * PAGE_SIZE) & ~(PAGE_SIZE - 1)) - -#define VINO_FRAMEBUFFER_COUNT_MAX 8 - -#define VINO_FRAMEBUFFER_UNUSED 0 -#define VINO_FRAMEBUFFER_IN_USE 1 -#define VINO_FRAMEBUFFER_READY 2 - -#define VINO_QUEUE_ERROR -1 -#define VINO_QUEUE_MAGIC 0x20050125 - -#define VINO_MEMORY_NONE 0 -#define VINO_MEMORY_MMAP 1 -#define VINO_MEMORY_USERPTR 2 - -#define VINO_DUMMY_DESC_COUNT 4 -#define VINO_DESC_FETCH_DELAY 5 /* microseconds */ - -#define VINO_MAX_FRAME_SKIP_COUNT 128 - -/* the number is the index for vino_data_formats */ -#define VINO_DATA_FMT_NONE -1 -#define VINO_DATA_FMT_GREY 0 -#define VINO_DATA_FMT_RGB332 1 -#define VINO_DATA_FMT_RGB32 2 -#define VINO_DATA_FMT_YUV 3 - -#define VINO_DATA_FMT_COUNT 4 - -/* the number is the index for vino_data_norms */ -#define VINO_DATA_NORM_NONE -1 -#define VINO_DATA_NORM_NTSC 0 -#define VINO_DATA_NORM_PAL 1 -#define VINO_DATA_NORM_SECAM 2 -#define VINO_DATA_NORM_D1 3 - -#define VINO_DATA_NORM_COUNT 4 - -/* I2C controller flags */ -#define SGI_I2C_FORCE_IDLE (0 << 0) -#define SGI_I2C_NOT_IDLE (1 << 0) -#define SGI_I2C_WRITE (0 << 1) -#define SGI_I2C_READ (1 << 1) -#define SGI_I2C_RELEASE_BUS (0 << 2) -#define SGI_I2C_HOLD_BUS (1 << 2) -#define SGI_I2C_XFER_DONE (0 << 4) -#define SGI_I2C_XFER_BUSY (1 << 4) -#define SGI_I2C_ACK (0 << 5) -#define SGI_I2C_NACK (1 << 5) -#define SGI_I2C_BUS_OK (0 << 7) -#define SGI_I2C_BUS_ERR (1 << 7) - -/* Internal data structure definitions */ - -struct vino_input { - char *name; - v4l2_std_id std; -}; - -struct vino_clipping { - unsigned int left, right, top, bottom; -}; - -struct vino_data_format { - /* the description */ - char *description; - /* bytes per pixel */ - unsigned int bpp; - /* V4L2 fourcc code */ - __u32 pixelformat; - /* V4L2 colorspace (duh!) */ - enum v4l2_colorspace colorspace; -}; - -struct vino_data_norm { - char *description; - unsigned int width, height; - struct vino_clipping odd; - struct vino_clipping even; - - v4l2_std_id std; - unsigned int fps_min, fps_max; - __u32 framelines; -}; - -struct vino_descriptor_table { - /* the number of PAGE_SIZE sized pages in the buffer */ - unsigned int page_count; - /* virtual (kmalloc'd) pointers to the actual data - * (in PAGE_SIZE chunks, used with mmap streaming) */ - unsigned long *virtual; - - /* cpu address for the VINO descriptor table - * (contains DMA addresses, VINO_PAGE_SIZE chunks) */ - unsigned long *dma_cpu; - /* dma address for the VINO descriptor table - * (contains DMA addresses, VINO_PAGE_SIZE chunks) */ - dma_addr_t dma; -}; - -struct vino_framebuffer { - /* identifier nubmer */ - unsigned int id; - /* the length of the whole buffer */ - unsigned int size; - /* the length of actual data in buffer */ - unsigned int data_size; - /* the data format */ - unsigned int data_format; - /* the state of buffer data */ - unsigned int state; - /* is the buffer mapped in user space? */ - unsigned int map_count; - /* memory offset for mmap() */ - unsigned int offset; - /* frame counter */ - unsigned int frame_counter; - /* timestamp (written when image capture finishes) */ - struct timeval timestamp; - - struct vino_descriptor_table desc_table; - - spinlock_t state_lock; -}; - -struct vino_framebuffer_fifo { - unsigned int length; - - unsigned int used; - unsigned int head; - unsigned int tail; - - unsigned int data[VINO_FRAMEBUFFER_COUNT_MAX]; -}; - -struct vino_framebuffer_queue { - unsigned int magic; - - /* VINO_MEMORY_NONE, VINO_MEMORY_MMAP or VINO_MEMORY_USERPTR */ - unsigned int type; - unsigned int length; - - /* data field of in and out contain index numbers for buffer */ - struct vino_framebuffer_fifo in; - struct vino_framebuffer_fifo out; - - struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_COUNT_MAX]; - - spinlock_t queue_lock; - struct mutex queue_mutex; - wait_queue_head_t frame_wait_queue; -}; - -struct vino_interrupt_data { - struct timeval timestamp; - unsigned int frame_counter; - unsigned int skip_count; - unsigned int skip; -}; - -struct vino_channel_settings { - unsigned int channel; - - int input; - unsigned int data_format; - unsigned int data_norm; - struct vino_clipping clipping; - unsigned int decimation; - unsigned int line_size; - unsigned int alpha; - unsigned int fps; - unsigned int framert_reg; - - unsigned int fifo_threshold; - - struct vino_framebuffer_queue fb_queue; - - /* number of the current field */ - unsigned int field; - - /* read in progress */ - int reading; - /* streaming is active */ - int streaming; - /* the driver is currently processing the queue */ - int capturing; - - struct mutex mutex; - spinlock_t capture_lock; - - unsigned int users; - - struct vino_interrupt_data int_data; - - /* V4L support */ - struct video_device *vdev; -}; - -struct vino_settings { - struct v4l2_device v4l2_dev; - struct vino_channel_settings a; - struct vino_channel_settings b; - - /* the channel which owns this client: - * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */ - unsigned int decoder_owner; - struct v4l2_subdev *decoder; - unsigned int camera_owner; - struct v4l2_subdev *camera; - - /* a lock for vino register access */ - spinlock_t vino_lock; - /* a lock for channel input changes */ - spinlock_t input_lock; - - unsigned long dummy_page; - struct vino_descriptor_table dummy_desc_table; -}; - -/* Module parameters */ - -/* - * Using vino_pixel_conversion the ABGR32-format pixels supplied - * by the VINO chip can be converted to more common formats - * like RGBA32 (or probably RGB24 in the future). This way we - * can give out data that can be specified correctly with - * the V4L2-definitions. - * - * The pixel format is specified as RGBA32 when no conversion - * is used. - * - * Note that this only affects the 32-bit bit depth. - * - * Use non-zero value to enable conversion. - */ -static int vino_pixel_conversion; - -module_param_named(pixelconv, vino_pixel_conversion, int, 0); - -MODULE_PARM_DESC(pixelconv, - "enable pixel conversion (non-zero value enables)"); - -/* Internal data structures */ - -static struct sgi_vino *vino; - -static struct vino_settings *vino_drvdata; - -#define camera_call(o, f, args...) \ - v4l2_subdev_call(vino_drvdata->camera, o, f, ##args) -#define decoder_call(o, f, args...) \ - v4l2_subdev_call(vino_drvdata->decoder, o, f, ##args) - -static const char *vino_driver_name = "vino"; -static const char *vino_driver_description = "SGI VINO"; -static const char *vino_bus_name = "GIO64 bus"; -static const char *vino_vdev_name_a = "SGI VINO Channel A"; -static const char *vino_vdev_name_b = "SGI VINO Channel B"; - -static void vino_capture_tasklet(unsigned long channel); - -DECLARE_TASKLET(vino_tasklet_a, vino_capture_tasklet, VINO_CHANNEL_A); -DECLARE_TASKLET(vino_tasklet_b, vino_capture_tasklet, VINO_CHANNEL_B); - -static const struct vino_input vino_inputs[] = { - { - .name = "Composite", - .std = V4L2_STD_NTSC | V4L2_STD_PAL - | V4L2_STD_SECAM, - }, { - .name = "S-Video", - .std = V4L2_STD_NTSC | V4L2_STD_PAL - | V4L2_STD_SECAM, - }, { - .name = "D1/IndyCam", - .std = V4L2_STD_NTSC, - } -}; - -static const struct vino_data_format vino_data_formats[] = { - { - .description = "8-bit greyscale", - .bpp = 1, - .pixelformat = V4L2_PIX_FMT_GREY, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - }, { - .description = "8-bit dithered RGB 3-3-2", - .bpp = 1, - .pixelformat = V4L2_PIX_FMT_RGB332, - .colorspace = V4L2_COLORSPACE_SRGB, - }, { - .description = "32-bit RGB", - .bpp = 4, - .pixelformat = V4L2_PIX_FMT_RGB32, - .colorspace = V4L2_COLORSPACE_SRGB, - }, { - .description = "YUV 4:2:2", - .bpp = 2, - .pixelformat = V4L2_PIX_FMT_YUYV, // XXX: swapped? - .colorspace = V4L2_COLORSPACE_SMPTE170M, - } -}; - -static const struct vino_data_norm vino_data_norms[] = { - { - .description = "NTSC", - .std = V4L2_STD_NTSC, - .fps_min = 6, - .fps_max = 30, - .framelines = 525, - .width = VINO_NTSC_WIDTH, - .height = VINO_NTSC_HEIGHT, - .odd = { - .top = VINO_CLIPPING_START_ODD_NTSC, - .left = 0, - .bottom = VINO_CLIPPING_START_ODD_NTSC - + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, - }, - .even = { - .top = VINO_CLIPPING_START_EVEN_NTSC, - .left = 0, - .bottom = VINO_CLIPPING_START_EVEN_NTSC - + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, - }, - }, { - .description = "PAL", - .std = V4L2_STD_PAL, - .fps_min = 5, - .fps_max = 25, - .framelines = 625, - .width = VINO_PAL_WIDTH, - .height = VINO_PAL_HEIGHT, - .odd = { - .top = VINO_CLIPPING_START_ODD_PAL, - .left = 0, - .bottom = VINO_CLIPPING_START_ODD_PAL - + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, - }, - .even = { - .top = VINO_CLIPPING_START_EVEN_PAL, - .left = 0, - .bottom = VINO_CLIPPING_START_EVEN_PAL - + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, - }, - }, { - .description = "SECAM", - .std = V4L2_STD_SECAM, - .fps_min = 5, - .fps_max = 25, - .framelines = 625, - .width = VINO_PAL_WIDTH, - .height = VINO_PAL_HEIGHT, - .odd = { - .top = VINO_CLIPPING_START_ODD_PAL, - .left = 0, - .bottom = VINO_CLIPPING_START_ODD_PAL - + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, - }, - .even = { - .top = VINO_CLIPPING_START_EVEN_PAL, - .left = 0, - .bottom = VINO_CLIPPING_START_EVEN_PAL - + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, - }, - }, { - .description = "NTSC/D1", - .std = V4L2_STD_NTSC, - .fps_min = 6, - .fps_max = 30, - .framelines = 525, - .width = VINO_NTSC_WIDTH, - .height = VINO_NTSC_HEIGHT, - .odd = { - .top = VINO_CLIPPING_START_ODD_D1, - .left = 0, - .bottom = VINO_CLIPPING_START_ODD_D1 - + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, - }, - .even = { - .top = VINO_CLIPPING_START_EVEN_D1, - .left = 0, - .bottom = VINO_CLIPPING_START_EVEN_D1 - + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, - }, - } -}; - -#define VINO_INDYCAM_V4L2_CONTROL_COUNT 9 - -struct v4l2_queryctrl vino_indycam_v4l2_controls[] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Gain Control", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = INDYCAM_AGC_DEFAULT, - }, { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic White Balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = INDYCAM_AWB_DEFAULT, - }, { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = INDYCAM_GAIN_MIN, - .maximum = INDYCAM_GAIN_MAX, - .step = 1, - .default_value = INDYCAM_GAIN_DEFAULT, - }, { - .id = INDYCAM_CONTROL_RED_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Saturation", - .minimum = INDYCAM_RED_SATURATION_MIN, - .maximum = INDYCAM_RED_SATURATION_MAX, - .step = 1, - .default_value = INDYCAM_RED_SATURATION_DEFAULT, - }, { - .id = INDYCAM_CONTROL_BLUE_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Saturation", - .minimum = INDYCAM_BLUE_SATURATION_MIN, - .maximum = INDYCAM_BLUE_SATURATION_MAX, - .step = 1, - .default_value = INDYCAM_BLUE_SATURATION_DEFAULT, - }, { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = INDYCAM_RED_BALANCE_MIN, - .maximum = INDYCAM_RED_BALANCE_MAX, - .step = 1, - .default_value = INDYCAM_RED_BALANCE_DEFAULT, - }, { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = INDYCAM_BLUE_BALANCE_MIN, - .maximum = INDYCAM_BLUE_BALANCE_MAX, - .step = 1, - .default_value = INDYCAM_BLUE_BALANCE_DEFAULT, - }, { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Shutter Control", - .minimum = INDYCAM_SHUTTER_MIN, - .maximum = INDYCAM_SHUTTER_MAX, - .step = 1, - .default_value = INDYCAM_SHUTTER_DEFAULT, - }, { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = INDYCAM_GAMMA_MIN, - .maximum = INDYCAM_GAMMA_MAX, - .step = 1, - .default_value = INDYCAM_GAMMA_DEFAULT, - } -}; - -#define VINO_SAA7191_V4L2_CONTROL_COUNT 9 - -struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = SAA7191_HUE_MIN, - .maximum = SAA7191_HUE_MAX, - .step = 1, - .default_value = SAA7191_HUE_DEFAULT, - }, { - .id = SAA7191_CONTROL_BANDPASS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Luminance Bandpass", - .minimum = SAA7191_BANDPASS_MIN, - .maximum = SAA7191_BANDPASS_MAX, - .step = 1, - .default_value = SAA7191_BANDPASS_DEFAULT, - }, { - .id = SAA7191_CONTROL_BANDPASS_WEIGHT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Luminance Bandpass Weight", - .minimum = SAA7191_BANDPASS_WEIGHT_MIN, - .maximum = SAA7191_BANDPASS_WEIGHT_MAX, - .step = 1, - .default_value = SAA7191_BANDPASS_WEIGHT_DEFAULT, - }, { - .id = SAA7191_CONTROL_CORING, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "HF Luminance Coring", - .minimum = SAA7191_CORING_MIN, - .maximum = SAA7191_CORING_MAX, - .step = 1, - .default_value = SAA7191_CORING_DEFAULT, - }, { - .id = SAA7191_CONTROL_FORCE_COLOUR, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Force Colour", - .minimum = SAA7191_FORCE_COLOUR_MIN, - .maximum = SAA7191_FORCE_COLOUR_MAX, - .step = 1, - .default_value = SAA7191_FORCE_COLOUR_DEFAULT, - }, { - .id = SAA7191_CONTROL_CHROMA_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Chrominance Gain Control", - .minimum = SAA7191_CHROMA_GAIN_MIN, - .maximum = SAA7191_CHROMA_GAIN_MAX, - .step = 1, - .default_value = SAA7191_CHROMA_GAIN_DEFAULT, - }, { - .id = SAA7191_CONTROL_VTRC, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "VTR Time Constant", - .minimum = SAA7191_VTRC_MIN, - .maximum = SAA7191_VTRC_MAX, - .step = 1, - .default_value = SAA7191_VTRC_DEFAULT, - }, { - .id = SAA7191_CONTROL_LUMA_DELAY, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Luminance Delay Compensation", - .minimum = SAA7191_LUMA_DELAY_MIN, - .maximum = SAA7191_LUMA_DELAY_MAX, - .step = 1, - .default_value = SAA7191_LUMA_DELAY_DEFAULT, - }, { - .id = SAA7191_CONTROL_VNR, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Vertical Noise Reduction", - .minimum = SAA7191_VNR_MIN, - .maximum = SAA7191_VNR_MAX, - .step = 1, - .default_value = SAA7191_VNR_DEFAULT, - } -}; - -/* VINO framebuffer/DMA descriptor management */ - -static void vino_free_buffer_with_count(struct vino_framebuffer *fb, - unsigned int count) -{ - unsigned int i; - - dprintk("vino_free_buffer_with_count(): count = %d\n", count); - - for (i = 0; i < count; i++) { - ClearPageReserved(virt_to_page((void *)fb->desc_table.virtual[i])); - dma_unmap_single(NULL, - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i], - PAGE_SIZE, DMA_FROM_DEVICE); - free_page(fb->desc_table.virtual[i]); - } - - dma_free_coherent(NULL, - VINO_PAGE_RATIO * (fb->desc_table.page_count + 4) * - sizeof(dma_addr_t), (void *)fb->desc_table.dma_cpu, - fb->desc_table.dma); - kfree(fb->desc_table.virtual); - - memset(fb, 0, sizeof(struct vino_framebuffer)); -} - -static void vino_free_buffer(struct vino_framebuffer *fb) -{ - vino_free_buffer_with_count(fb, fb->desc_table.page_count); -} - -static int vino_allocate_buffer(struct vino_framebuffer *fb, - unsigned int size) -{ - unsigned int count, i, j; - int ret = 0; - - dprintk("vino_allocate_buffer():\n"); - - if (size < 1) - return -EINVAL; - - memset(fb, 0, sizeof(struct vino_framebuffer)); - - count = ((size / PAGE_SIZE) + 4) & ~3; - - dprintk("vino_allocate_buffer(): size = %d, count = %d\n", - size, count); - - /* allocate memory for table with virtual (page) addresses */ - fb->desc_table.virtual = - kmalloc(count * sizeof(unsigned long), GFP_KERNEL); - if (!fb->desc_table.virtual) - return -ENOMEM; - - /* allocate memory for table with dma addresses - * (has space for four extra descriptors) */ - fb->desc_table.dma_cpu = - dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) * - sizeof(dma_addr_t), &fb->desc_table.dma, - GFP_KERNEL | GFP_DMA); - if (!fb->desc_table.dma_cpu) { - ret = -ENOMEM; - goto out_free_virtual; - } - - /* allocate pages for the buffer and acquire the according - * dma addresses */ - for (i = 0; i < count; i++) { - dma_addr_t dma_data_addr; - - fb->desc_table.virtual[i] = - get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!fb->desc_table.virtual[i]) { - ret = -ENOBUFS; - break; - } - - dma_data_addr = - dma_map_single(NULL, - (void *)fb->desc_table.virtual[i], - PAGE_SIZE, DMA_FROM_DEVICE); - - for (j = 0; j < VINO_PAGE_RATIO; j++) { - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] = - dma_data_addr + VINO_PAGE_SIZE * j; - } - - SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i])); - } - - /* page_count needs to be set anyway, because the descriptor table has - * been allocated according to this number */ - fb->desc_table.page_count = count; - - if (ret) { - /* the descriptor with index i doesn't contain - * a valid address yet */ - vino_free_buffer_with_count(fb, i); - return ret; - } - - //fb->size = size; - fb->size = count * PAGE_SIZE; - fb->data_format = VINO_DATA_FMT_NONE; - - /* set the dma stop-bit for the last (count+1)th descriptor */ - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP; - return 0; - - out_free_virtual: - kfree(fb->desc_table.virtual); - return ret; -} - -#if 0 -/* user buffers not fully implemented yet */ -static int vino_prepare_user_buffer(struct vino_framebuffer *fb, - void *user, - unsigned int size) -{ - unsigned int count, i, j; - int ret = 0; - - dprintk("vino_prepare_user_buffer():\n"); - - if (size < 1) - return -EINVAL; - - memset(fb, 0, sizeof(struct vino_framebuffer)); - - count = ((size / PAGE_SIZE)) & ~3; - - dprintk("vino_prepare_user_buffer(): size = %d, count = %d\n", - size, count); - - /* allocate memory for table with virtual (page) addresses */ - fb->desc_table.virtual = (unsigned long *) - kmalloc(count * sizeof(unsigned long), GFP_KERNEL); - if (!fb->desc_table.virtual) - return -ENOMEM; - - /* allocate memory for table with dma addresses - * (has space for four extra descriptors) */ - fb->desc_table.dma_cpu = - dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) * - sizeof(dma_addr_t), &fb->desc_table.dma, - GFP_KERNEL | GFP_DMA); - if (!fb->desc_table.dma_cpu) { - ret = -ENOMEM; - goto out_free_virtual; - } - - /* allocate pages for the buffer and acquire the according - * dma addresses */ - for (i = 0; i < count; i++) { - dma_addr_t dma_data_addr; - - fb->desc_table.virtual[i] = - get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!fb->desc_table.virtual[i]) { - ret = -ENOBUFS; - break; - } - - dma_data_addr = - dma_map_single(NULL, - (void *)fb->desc_table.virtual[i], - PAGE_SIZE, DMA_FROM_DEVICE); - - for (j = 0; j < VINO_PAGE_RATIO; j++) { - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] = - dma_data_addr + VINO_PAGE_SIZE * j; - } - - SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i])); - } - - /* page_count needs to be set anyway, because the descriptor table has - * been allocated according to this number */ - fb->desc_table.page_count = count; - - if (ret) { - /* the descriptor with index i doesn't contain - * a valid address yet */ - vino_free_buffer_with_count(fb, i); - return ret; - } - - //fb->size = size; - fb->size = count * PAGE_SIZE; - - /* set the dma stop-bit for the last (count+1)th descriptor */ - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP; - return 0; - - out_free_virtual: - kfree(fb->desc_table.virtual); - return ret; -} -#endif - -static void vino_sync_buffer(struct vino_framebuffer *fb) -{ - int i; - - dprintk("vino_sync_buffer():\n"); - - for (i = 0; i < fb->desc_table.page_count; i++) - dma_sync_single_for_cpu(NULL, - fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i], - PAGE_SIZE, DMA_FROM_DEVICE); -} - -/* Framebuffer fifo functions (need to be locked externally) */ - -static inline void vino_fifo_init(struct vino_framebuffer_fifo *f, - unsigned int length) -{ - f->length = 0; - f->used = 0; - f->head = 0; - f->tail = 0; - - if (length > VINO_FRAMEBUFFER_COUNT_MAX) - length = VINO_FRAMEBUFFER_COUNT_MAX; - - f->length = length; -} - -/* returns true/false */ -static inline int vino_fifo_has_id(struct vino_framebuffer_fifo *f, - unsigned int id) -{ - unsigned int i; - - for (i = f->head; i == (f->tail - 1); i = (i + 1) % f->length) { - if (f->data[i] == id) - return 1; - } - - return 0; -} - -#if 0 -/* returns true/false */ -static inline int vino_fifo_full(struct vino_framebuffer_fifo *f) -{ - return (f->used == f->length); -} -#endif - -static inline unsigned int vino_fifo_get_used(struct vino_framebuffer_fifo *f) -{ - return f->used; -} - -static int vino_fifo_enqueue(struct vino_framebuffer_fifo *f, unsigned int id) -{ - if (id >= f->length) { - return VINO_QUEUE_ERROR; - } - - if (vino_fifo_has_id(f, id)) { - return VINO_QUEUE_ERROR; - } - - if (f->used < f->length) { - f->data[f->tail] = id; - f->tail = (f->tail + 1) % f->length; - f->used++; - } else { - return VINO_QUEUE_ERROR; - } - - return 0; -} - -static int vino_fifo_peek(struct vino_framebuffer_fifo *f, unsigned int *id) -{ - if (f->used > 0) { - *id = f->data[f->head]; - } else { - return VINO_QUEUE_ERROR; - } - - return 0; -} - -static int vino_fifo_dequeue(struct vino_framebuffer_fifo *f, unsigned int *id) -{ - if (f->used > 0) { - *id = f->data[f->head]; - f->head = (f->head + 1) % f->length; - f->used--; - } else { - return VINO_QUEUE_ERROR; - } - - return 0; -} - -/* Framebuffer queue functions */ - -/* execute with queue_lock locked */ -static void vino_queue_free_with_count(struct vino_framebuffer_queue *q, - unsigned int length) -{ - unsigned int i; - - q->length = 0; - memset(&q->in, 0, sizeof(struct vino_framebuffer_fifo)); - memset(&q->out, 0, sizeof(struct vino_framebuffer_fifo)); - for (i = 0; i < length; i++) { - dprintk("vino_queue_free_with_count(): freeing buffer %d\n", - i); - vino_free_buffer(q->buffer[i]); - kfree(q->buffer[i]); - } - - q->type = VINO_MEMORY_NONE; - q->magic = 0; -} - -static void vino_queue_free(struct vino_framebuffer_queue *q) -{ - dprintk("vino_queue_free():\n"); - - if (q->magic != VINO_QUEUE_MAGIC) - return; - if (q->type != VINO_MEMORY_MMAP) - return; - - mutex_lock(&q->queue_mutex); - - vino_queue_free_with_count(q, q->length); - - mutex_unlock(&q->queue_mutex); -} - -static int vino_queue_init(struct vino_framebuffer_queue *q, - unsigned int *length) -{ - unsigned int i; - int ret = 0; - - dprintk("vino_queue_init(): length = %d\n", *length); - - if (q->magic == VINO_QUEUE_MAGIC) { - dprintk("vino_queue_init(): queue already initialized!\n"); - return -EINVAL; - } - - if (q->type != VINO_MEMORY_NONE) { - dprintk("vino_queue_init(): queue already initialized!\n"); - return -EINVAL; - } - - if (*length < 1) - return -EINVAL; - - mutex_lock(&q->queue_mutex); - - if (*length > VINO_FRAMEBUFFER_COUNT_MAX) - *length = VINO_FRAMEBUFFER_COUNT_MAX; - - q->length = 0; - - for (i = 0; i < *length; i++) { - dprintk("vino_queue_init(): allocating buffer %d\n", i); - q->buffer[i] = kmalloc(sizeof(struct vino_framebuffer), - GFP_KERNEL); - if (!q->buffer[i]) { - dprintk("vino_queue_init(): kmalloc() failed\n"); - ret = -ENOMEM; - break; - } - - ret = vino_allocate_buffer(q->buffer[i], - VINO_FRAMEBUFFER_SIZE); - if (ret) { - kfree(q->buffer[i]); - dprintk("vino_queue_init(): " - "vino_allocate_buffer() failed\n"); - break; - } - - q->buffer[i]->id = i; - if (i > 0) { - q->buffer[i]->offset = q->buffer[i - 1]->offset + - q->buffer[i - 1]->size; - } else { - q->buffer[i]->offset = 0; - } - - spin_lock_init(&q->buffer[i]->state_lock); - - dprintk("vino_queue_init(): buffer = %d, offset = %d, " - "size = %d\n", i, q->buffer[i]->offset, - q->buffer[i]->size); - } - - if (ret) { - vino_queue_free_with_count(q, i); - *length = 0; - } else { - q->length = *length; - vino_fifo_init(&q->in, q->length); - vino_fifo_init(&q->out, q->length); - q->type = VINO_MEMORY_MMAP; - q->magic = VINO_QUEUE_MAGIC; - } - - mutex_unlock(&q->queue_mutex); - - return ret; -} - -static struct vino_framebuffer *vino_queue_add(struct - vino_framebuffer_queue *q, - unsigned int id) -{ - struct vino_framebuffer *ret = NULL; - unsigned int total; - unsigned long flags; - - dprintk("vino_queue_add(): id = %d\n", id); - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - if (id >= q->length) - goto out; - - /* not needed?: if (vino_fifo_full(&q->out)) { - goto out; - }*/ - /* check that outgoing queue isn't already full - * (or that it won't become full) */ - total = vino_fifo_get_used(&q->in) + - vino_fifo_get_used(&q->out); - if (total >= q->length) - goto out; - - if (vino_fifo_enqueue(&q->in, id)) - goto out; - - ret = q->buffer[id]; - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static struct vino_framebuffer *vino_queue_transfer(struct - vino_framebuffer_queue *q) -{ - struct vino_framebuffer *ret = NULL; - struct vino_framebuffer *fb; - int id; - unsigned long flags; - - dprintk("vino_queue_transfer():\n"); - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - // now this actually removes an entry from the incoming queue - if (vino_fifo_dequeue(&q->in, &id)) { - goto out; - } - - dprintk("vino_queue_transfer(): id = %d\n", id); - fb = q->buffer[id]; - - // we have already checked that the outgoing queue is not full, but... - if (vino_fifo_enqueue(&q->out, id)) { - printk(KERN_ERR "vino_queue_transfer(): " - "outgoing queue is full, this shouldn't happen!\n"); - goto out; - } - - ret = fb; -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -/* returns true/false */ -static int vino_queue_incoming_contains(struct vino_framebuffer_queue *q, - unsigned int id) -{ - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - ret = vino_fifo_has_id(&q->in, id); - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -/* returns true/false */ -static int vino_queue_outgoing_contains(struct vino_framebuffer_queue *q, - unsigned int id) -{ - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - ret = vino_fifo_has_id(&q->out, id); - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static int vino_queue_get_incoming(struct vino_framebuffer_queue *q, - unsigned int *used) -{ - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return VINO_QUEUE_ERROR; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) { - ret = VINO_QUEUE_ERROR; - goto out; - } - - *used = vino_fifo_get_used(&q->in); - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static int vino_queue_get_outgoing(struct vino_framebuffer_queue *q, - unsigned int *used) -{ - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return VINO_QUEUE_ERROR; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) { - ret = VINO_QUEUE_ERROR; - goto out; - } - - *used = vino_fifo_get_used(&q->out); - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -#if 0 -static int vino_queue_get_total(struct vino_framebuffer_queue *q, - unsigned int *total) -{ - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return VINO_QUEUE_ERROR; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) { - ret = VINO_QUEUE_ERROR; - goto out; - } - - *total = vino_fifo_get_used(&q->in) + - vino_fifo_get_used(&q->out); - -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} -#endif - -static struct vino_framebuffer *vino_queue_peek(struct - vino_framebuffer_queue *q, - unsigned int *id) -{ - struct vino_framebuffer *ret = NULL; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - if (vino_fifo_peek(&q->in, id)) { - goto out; - } - - ret = q->buffer[*id]; -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static struct vino_framebuffer *vino_queue_remove(struct - vino_framebuffer_queue *q, - unsigned int *id) -{ - struct vino_framebuffer *ret = NULL; - unsigned long flags; - dprintk("vino_queue_remove():\n"); - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - if (vino_fifo_dequeue(&q->out, id)) { - goto out; - } - - dprintk("vino_queue_remove(): id = %d\n", *id); - ret = q->buffer[*id]; -out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static struct -vino_framebuffer *vino_queue_get_buffer(struct vino_framebuffer_queue *q, - unsigned int id) -{ - struct vino_framebuffer *ret = NULL; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - - if (q->length == 0) - goto out; - - if (id >= q->length) - goto out; - - ret = q->buffer[id]; - out: - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -static unsigned int vino_queue_get_length(struct vino_framebuffer_queue *q) -{ - unsigned int length = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return length; - } - - spin_lock_irqsave(&q->queue_lock, flags); - length = q->length; - spin_unlock_irqrestore(&q->queue_lock, flags); - - return length; -} - -static int vino_queue_has_mapped_buffers(struct vino_framebuffer_queue *q) -{ - unsigned int i; - int ret = 0; - unsigned long flags; - - if (q->magic != VINO_QUEUE_MAGIC) { - return ret; - } - - spin_lock_irqsave(&q->queue_lock, flags); - for (i = 0; i < q->length; i++) { - if (q->buffer[i]->map_count > 0) { - ret = 1; - break; - } - } - spin_unlock_irqrestore(&q->queue_lock, flags); - - return ret; -} - -/* VINO functions */ - -/* execute with input_lock locked */ -static void vino_update_line_size(struct vino_channel_settings *vcs) -{ - unsigned int w = vcs->clipping.right - vcs->clipping.left; - unsigned int d = vcs->decimation; - unsigned int bpp = vino_data_formats[vcs->data_format].bpp; - unsigned int lsize; - - dprintk("update_line_size(): before: w = %d, d = %d, " - "line_size = %d\n", w, d, vcs->line_size); - - /* line size must be multiple of 8 bytes */ - lsize = (bpp * (w / d)) & ~7; - w = (lsize / bpp) * d; - - vcs->clipping.right = vcs->clipping.left + w; - vcs->line_size = lsize; - - dprintk("update_line_size(): after: w = %d, d = %d, " - "line_size = %d\n", w, d, vcs->line_size); -} - -/* execute with input_lock locked */ -static void vino_set_clipping(struct vino_channel_settings *vcs, - unsigned int x, unsigned int y, - unsigned int w, unsigned int h) -{ - unsigned int maxwidth, maxheight; - unsigned int d; - - maxwidth = vino_data_norms[vcs->data_norm].width; - maxheight = vino_data_norms[vcs->data_norm].height; - d = vcs->decimation; - - y &= ~1; /* odd/even fields */ - - if (x > maxwidth) { - x = 0; - } - if (y > maxheight) { - y = 0; - } - - if (((w / d) < VINO_MIN_WIDTH) - || ((h / d) < VINO_MIN_HEIGHT)) { - w = VINO_MIN_WIDTH * d; - h = VINO_MIN_HEIGHT * d; - } - - if ((x + w) > maxwidth) { - w = maxwidth - x; - if ((w / d) < VINO_MIN_WIDTH) - x = maxwidth - VINO_MIN_WIDTH * d; - } - if ((y + h) > maxheight) { - h = maxheight - y; - if ((h / d) < VINO_MIN_HEIGHT) - y = maxheight - VINO_MIN_HEIGHT * d; - } - - vcs->clipping.left = x; - vcs->clipping.top = y; - vcs->clipping.right = x + w; - vcs->clipping.bottom = y + h; - - vino_update_line_size(vcs); - - dprintk("clipping %d, %d, %d, %d / %d - %d\n", - vcs->clipping.left, vcs->clipping.top, vcs->clipping.right, - vcs->clipping.bottom, vcs->decimation, vcs->line_size); -} - -/* execute with input_lock locked */ -static inline void vino_set_default_clipping(struct vino_channel_settings *vcs) -{ - vino_set_clipping(vcs, 0, 0, vino_data_norms[vcs->data_norm].width, - vino_data_norms[vcs->data_norm].height); -} - -/* execute with input_lock locked */ -static void vino_set_scaling(struct vino_channel_settings *vcs, - unsigned int w, unsigned int h) -{ - unsigned int x, y, curw, curh, d; - - x = vcs->clipping.left; - y = vcs->clipping.top; - curw = vcs->clipping.right - vcs->clipping.left; - curh = vcs->clipping.bottom - vcs->clipping.top; - - d = max(curw / w, curh / h); - - dprintk("scaling w: %d, h: %d, curw: %d, curh: %d, d: %d\n", - w, h, curw, curh, d); - - if (d < 1) { - d = 1; - } else if (d > 8) { - d = 8; - } - - vcs->decimation = d; - vino_set_clipping(vcs, x, y, w * d, h * d); - - dprintk("scaling %d, %d, %d, %d / %d - %d\n", vcs->clipping.left, - vcs->clipping.top, vcs->clipping.right, vcs->clipping.bottom, - vcs->decimation, vcs->line_size); -} - -/* execute with input_lock locked */ -static inline void vino_set_default_scaling(struct vino_channel_settings *vcs) -{ - vino_set_scaling(vcs, vcs->clipping.right - vcs->clipping.left, - vcs->clipping.bottom - vcs->clipping.top); -} - -/* execute with input_lock locked */ -static void vino_set_framerate(struct vino_channel_settings *vcs, - unsigned int fps) -{ - unsigned int mask; - - switch (vcs->data_norm) { - case VINO_DATA_NORM_NTSC: - case VINO_DATA_NORM_D1: - fps = (unsigned int)(fps / 6) * 6; // FIXME: round! - - if (fps < vino_data_norms[vcs->data_norm].fps_min) - fps = vino_data_norms[vcs->data_norm].fps_min; - if (fps > vino_data_norms[vcs->data_norm].fps_max) - fps = vino_data_norms[vcs->data_norm].fps_max; - - switch (fps) { - case 6: - mask = 0x003; - break; - case 12: - mask = 0x0c3; - break; - case 18: - mask = 0x333; - break; - case 24: - mask = 0x3ff; - break; - case 30: - mask = 0xfff; - break; - default: - mask = VINO_FRAMERT_FULL; - } - vcs->framert_reg = VINO_FRAMERT_RT(mask); - break; - case VINO_DATA_NORM_PAL: - case VINO_DATA_NORM_SECAM: - fps = (unsigned int)(fps / 5) * 5; // FIXME: round! - - if (fps < vino_data_norms[vcs->data_norm].fps_min) - fps = vino_data_norms[vcs->data_norm].fps_min; - if (fps > vino_data_norms[vcs->data_norm].fps_max) - fps = vino_data_norms[vcs->data_norm].fps_max; - - switch (fps) { - case 5: - mask = 0x003; - break; - case 10: - mask = 0x0c3; - break; - case 15: - mask = 0x333; - break; - case 20: - mask = 0x0ff; - break; - case 25: - mask = 0x3ff; - break; - default: - mask = VINO_FRAMERT_FULL; - } - vcs->framert_reg = VINO_FRAMERT_RT(mask) | VINO_FRAMERT_PAL; - break; - } - - vcs->fps = fps; -} - -/* execute with input_lock locked */ -static inline void vino_set_default_framerate(struct - vino_channel_settings *vcs) -{ - vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max); -} - -/* VINO I2C bus functions */ - -struct i2c_algo_sgi_data { - void *data; /* private data for lowlevel routines */ - unsigned (*getctrl)(void *data); - void (*setctrl)(void *data, unsigned val); - unsigned (*rdata)(void *data); - void (*wdata)(void *data, unsigned val); - - int xfer_timeout; - int ack_timeout; -}; - -static int wait_xfer_done(struct i2c_algo_sgi_data *adap) -{ - int i; - - for (i = 0; i < adap->xfer_timeout; i++) { - if ((adap->getctrl(adap->data) & SGI_I2C_XFER_BUSY) == 0) - return 0; - udelay(1); - } - - return -ETIMEDOUT; -} - -static int wait_ack(struct i2c_algo_sgi_data *adap) -{ - int i; - - if (wait_xfer_done(adap)) - return -ETIMEDOUT; - for (i = 0; i < adap->ack_timeout; i++) { - if ((adap->getctrl(adap->data) & SGI_I2C_NACK) == 0) - return 0; - udelay(1); - } - - return -ETIMEDOUT; -} - -static int force_idle(struct i2c_algo_sgi_data *adap) -{ - int i; - - adap->setctrl(adap->data, SGI_I2C_FORCE_IDLE); - for (i = 0; i < adap->xfer_timeout; i++) { - if ((adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE) == 0) - goto out; - udelay(1); - } - return -ETIMEDOUT; -out: - if (adap->getctrl(adap->data) & SGI_I2C_BUS_ERR) - return -EIO; - return 0; -} - -static int do_address(struct i2c_algo_sgi_data *adap, unsigned int addr, - int rd) -{ - if (rd) - adap->setctrl(adap->data, SGI_I2C_NOT_IDLE); - /* Check if bus is idle, eventually force it to do so */ - if (adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE) - if (force_idle(adap)) - return -EIO; - /* Write out the i2c chip address and specify operation */ - adap->setctrl(adap->data, - SGI_I2C_HOLD_BUS | SGI_I2C_WRITE | SGI_I2C_NOT_IDLE); - if (rd) - addr |= 1; - adap->wdata(adap->data, addr); - if (wait_ack(adap)) - return -EIO; - return 0; -} - -static int i2c_read(struct i2c_algo_sgi_data *adap, unsigned char *buf, - unsigned int len) -{ - int i; - - adap->setctrl(adap->data, - SGI_I2C_HOLD_BUS | SGI_I2C_READ | SGI_I2C_NOT_IDLE); - for (i = 0; i < len; i++) { - if (wait_xfer_done(adap)) - return -EIO; - buf[i] = adap->rdata(adap->data); - } - adap->setctrl(adap->data, SGI_I2C_RELEASE_BUS | SGI_I2C_FORCE_IDLE); - - return 0; - -} - -static int i2c_write(struct i2c_algo_sgi_data *adap, unsigned char *buf, - unsigned int len) -{ - int i; - - /* We are already in write state */ - for (i = 0; i < len; i++) { - adap->wdata(adap->data, buf[i]); - if (wait_ack(adap)) - return -EIO; - } - return 0; -} - -static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, - int num) -{ - struct i2c_algo_sgi_data *adap = i2c_adap->algo_data; - struct i2c_msg *p; - int i, err = 0; - - for (i = 0; !err && i < num; i++) { - p = &msgs[i]; - err = do_address(adap, p->addr, p->flags & I2C_M_RD); - if (err || !p->len) - continue; - if (p->flags & I2C_M_RD) - err = i2c_read(adap, p->buf, p->len); - else - err = i2c_write(adap, p->buf, p->len); - } - - return (err < 0) ? err : i; -} - -static u32 sgi_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static const struct i2c_algorithm sgi_algo = { - .master_xfer = sgi_xfer, - .functionality = sgi_func, -}; - -static unsigned i2c_vino_getctrl(void *data) -{ - return vino->i2c_control; -} - -static void i2c_vino_setctrl(void *data, unsigned val) -{ - vino->i2c_control = val; -} - -static unsigned i2c_vino_rdata(void *data) -{ - return vino->i2c_data; -} - -static void i2c_vino_wdata(void *data, unsigned val) -{ - vino->i2c_data = val; -} - -static struct i2c_algo_sgi_data i2c_sgi_vino_data = { - .getctrl = &i2c_vino_getctrl, - .setctrl = &i2c_vino_setctrl, - .rdata = &i2c_vino_rdata, - .wdata = &i2c_vino_wdata, - .xfer_timeout = 200, - .ack_timeout = 1000, -}; - -static struct i2c_adapter vino_i2c_adapter = { - .name = "VINO I2C bus", - .algo = &sgi_algo, - .algo_data = &i2c_sgi_vino_data, - .owner = THIS_MODULE, -}; - -/* - * Prepare VINO for DMA transfer... - * (execute only with vino_lock and input_lock locked) - */ -static int vino_dma_setup(struct vino_channel_settings *vcs, - struct vino_framebuffer *fb) -{ - u32 ctrl, intr; - struct sgi_vino_channel *ch; - const struct vino_data_norm *norm; - - dprintk("vino_dma_setup():\n"); - - vcs->field = 0; - fb->frame_counter = 0; - - ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b; - norm = &vino_data_norms[vcs->data_norm]; - - ch->page_index = 0; - ch->line_count = 0; - - /* VINO line size register is set 8 bytes less than actual */ - ch->line_size = vcs->line_size - 8; - - /* let VINO know where to transfer data */ - ch->start_desc_tbl = fb->desc_table.dma; - ch->next_4_desc = fb->desc_table.dma; - - /* give vino time to fetch the first four descriptors, 5 usec - * should be more than enough time */ - udelay(VINO_DESC_FETCH_DELAY); - - dprintk("vino_dma_setup(): start desc = %08x, next 4 desc = %08x\n", - ch->start_desc_tbl, ch->next_4_desc); - - /* set the alpha register */ - ch->alpha = vcs->alpha; - - /* set clipping registers */ - ch->clip_start = VINO_CLIP_ODD(norm->odd.top + vcs->clipping.top / 2) | - VINO_CLIP_EVEN(norm->even.top + - vcs->clipping.top / 2) | - VINO_CLIP_X(vcs->clipping.left); - ch->clip_end = VINO_CLIP_ODD(norm->odd.top + - vcs->clipping.bottom / 2 - 1) | - VINO_CLIP_EVEN(norm->even.top + - vcs->clipping.bottom / 2 - 1) | - VINO_CLIP_X(vcs->clipping.right); - - /* set the size of actual content in the buffer (DECIMATION !) */ - fb->data_size = ((vcs->clipping.right - vcs->clipping.left) / - vcs->decimation) * - ((vcs->clipping.bottom - vcs->clipping.top) / - vcs->decimation) * - vino_data_formats[vcs->data_format].bpp; - - ch->frame_rate = vcs->framert_reg; - - ctrl = vino->control; - intr = vino->intr_status; - - if (vcs->channel == VINO_CHANNEL_A) { - /* All interrupt conditions for this channel was cleared - * so clear the interrupt status register and enable - * interrupts */ - intr &= ~VINO_INTSTAT_A; - ctrl |= VINO_CTRL_A_INT; - - /* enable synchronization */ - ctrl |= VINO_CTRL_A_SYNC_ENBL; - - /* enable frame assembly */ - ctrl |= VINO_CTRL_A_INTERLEAVE_ENBL; - - /* set decimation used */ - if (vcs->decimation < 2) - ctrl &= ~VINO_CTRL_A_DEC_ENBL; - else { - ctrl |= VINO_CTRL_A_DEC_ENBL; - ctrl &= ~VINO_CTRL_A_DEC_SCALE_MASK; - ctrl |= (vcs->decimation - 1) << - VINO_CTRL_A_DEC_SCALE_SHIFT; - } - - /* select input interface */ - if (vcs->input == VINO_INPUT_D1) - ctrl |= VINO_CTRL_A_SELECT; - else - ctrl &= ~VINO_CTRL_A_SELECT; - - /* palette */ - ctrl &= ~(VINO_CTRL_A_LUMA_ONLY | VINO_CTRL_A_RGB | - VINO_CTRL_A_DITHER); - } else { - intr &= ~VINO_INTSTAT_B; - ctrl |= VINO_CTRL_B_INT; - - ctrl |= VINO_CTRL_B_SYNC_ENBL; - ctrl |= VINO_CTRL_B_INTERLEAVE_ENBL; - - if (vcs->decimation < 2) - ctrl &= ~VINO_CTRL_B_DEC_ENBL; - else { - ctrl |= VINO_CTRL_B_DEC_ENBL; - ctrl &= ~VINO_CTRL_B_DEC_SCALE_MASK; - ctrl |= (vcs->decimation - 1) << - VINO_CTRL_B_DEC_SCALE_SHIFT; - - } - if (vcs->input == VINO_INPUT_D1) - ctrl |= VINO_CTRL_B_SELECT; - else - ctrl &= ~VINO_CTRL_B_SELECT; - - ctrl &= ~(VINO_CTRL_B_LUMA_ONLY | VINO_CTRL_B_RGB | - VINO_CTRL_B_DITHER); - } - - /* set palette */ - fb->data_format = vcs->data_format; - - switch (vcs->data_format) { - case VINO_DATA_FMT_GREY: - ctrl |= (vcs->channel == VINO_CHANNEL_A) ? - VINO_CTRL_A_LUMA_ONLY : VINO_CTRL_B_LUMA_ONLY; - break; - case VINO_DATA_FMT_RGB32: - ctrl |= (vcs->channel == VINO_CHANNEL_A) ? - VINO_CTRL_A_RGB : VINO_CTRL_B_RGB; - break; - case VINO_DATA_FMT_YUV: - /* nothing needs to be done */ - break; - case VINO_DATA_FMT_RGB332: - ctrl |= (vcs->channel == VINO_CHANNEL_A) ? - VINO_CTRL_A_RGB | VINO_CTRL_A_DITHER : - VINO_CTRL_B_RGB | VINO_CTRL_B_DITHER; - break; - } - - vino->intr_status = intr; - vino->control = ctrl; - - return 0; -} - -/* (execute only with vino_lock locked) */ -static inline void vino_dma_start(struct vino_channel_settings *vcs) -{ - u32 ctrl = vino->control; - - dprintk("vino_dma_start():\n"); - ctrl |= (vcs->channel == VINO_CHANNEL_A) ? - VINO_CTRL_A_DMA_ENBL : VINO_CTRL_B_DMA_ENBL; - vino->control = ctrl; -} - -/* (execute only with vino_lock locked) */ -static inline void vino_dma_stop(struct vino_channel_settings *vcs) -{ - u32 ctrl = vino->control; - - ctrl &= (vcs->channel == VINO_CHANNEL_A) ? - ~VINO_CTRL_A_DMA_ENBL : ~VINO_CTRL_B_DMA_ENBL; - ctrl &= (vcs->channel == VINO_CHANNEL_A) ? - ~VINO_CTRL_A_INT : ~VINO_CTRL_B_INT; - vino->control = ctrl; - dprintk("vino_dma_stop():\n"); -} - -/* - * Load dummy page to descriptor registers. This prevents generating of - * spurious interrupts. (execute only with vino_lock locked) - */ -static void vino_clear_interrupt(struct vino_channel_settings *vcs) -{ - struct sgi_vino_channel *ch; - - ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b; - - ch->page_index = 0; - ch->line_count = 0; - - ch->start_desc_tbl = vino_drvdata->dummy_desc_table.dma; - ch->next_4_desc = vino_drvdata->dummy_desc_table.dma; - - udelay(VINO_DESC_FETCH_DELAY); - dprintk("channel %c clear interrupt condition\n", - (vcs->channel == VINO_CHANNEL_A) ? 'A':'B'); -} - -static int vino_capture(struct vino_channel_settings *vcs, - struct vino_framebuffer *fb) -{ - int err = 0; - unsigned long flags, flags2; - - spin_lock_irqsave(&fb->state_lock, flags); - - if (fb->state == VINO_FRAMEBUFFER_IN_USE) - err = -EBUSY; - fb->state = VINO_FRAMEBUFFER_IN_USE; - - spin_unlock_irqrestore(&fb->state_lock, flags); - - if (err) - return err; - - spin_lock_irqsave(&vino_drvdata->vino_lock, flags); - spin_lock_irqsave(&vino_drvdata->input_lock, flags2); - - vino_dma_setup(vcs, fb); - vino_dma_start(vcs); - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags2); - spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags); - - return err; -} - -static -struct vino_framebuffer *vino_capture_enqueue(struct - vino_channel_settings *vcs, - unsigned int index) -{ - struct vino_framebuffer *fb; - unsigned long flags; - - dprintk("vino_capture_enqueue():\n"); - - spin_lock_irqsave(&vcs->capture_lock, flags); - - fb = vino_queue_add(&vcs->fb_queue, index); - if (fb == NULL) { - dprintk("vino_capture_enqueue(): vino_queue_add() failed, " - "queue full?\n"); - goto out; - } -out: - spin_unlock_irqrestore(&vcs->capture_lock, flags); - - return fb; -} - -static int vino_capture_next(struct vino_channel_settings *vcs, int start) -{ - struct vino_framebuffer *fb; - unsigned int incoming, id; - int err = 0; - unsigned long flags; - - dprintk("vino_capture_next():\n"); - - spin_lock_irqsave(&vcs->capture_lock, flags); - - if (start) { - /* start capture only if capture isn't in progress already */ - if (vcs->capturing) { - spin_unlock_irqrestore(&vcs->capture_lock, flags); - return 0; - } - - } else { - /* capture next frame: - * stop capture if capturing is not set */ - if (!vcs->capturing) { - spin_unlock_irqrestore(&vcs->capture_lock, flags); - return 0; - } - } - - err = vino_queue_get_incoming(&vcs->fb_queue, &incoming); - if (err) { - dprintk("vino_capture_next(): vino_queue_get_incoming() " - "failed\n"); - err = -EINVAL; - goto out; - } - if (incoming == 0) { - dprintk("vino_capture_next(): no buffers available\n"); - goto out; - } - - fb = vino_queue_peek(&vcs->fb_queue, &id); - if (fb == NULL) { - dprintk("vino_capture_next(): vino_queue_peek() failed\n"); - err = -EINVAL; - goto out; - } - - if (start) { - vcs->capturing = 1; - } - - spin_unlock_irqrestore(&vcs->capture_lock, flags); - - err = vino_capture(vcs, fb); - - return err; - -out: - vcs->capturing = 0; - spin_unlock_irqrestore(&vcs->capture_lock, flags); - - return err; -} - -static inline int vino_is_capturing(struct vino_channel_settings *vcs) -{ - int ret; - unsigned long flags; - - spin_lock_irqsave(&vcs->capture_lock, flags); - - ret = vcs->capturing; - - spin_unlock_irqrestore(&vcs->capture_lock, flags); - - return ret; -} - -/* waits until a frame is captured */ -static int vino_wait_for_frame(struct vino_channel_settings *vcs) -{ - wait_queue_t wait; - int err = 0; - - dprintk("vino_wait_for_frame():\n"); - - init_waitqueue_entry(&wait, current); - /* add ourselves into wait queue */ - add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait); - - /* to ensure that schedule_timeout will return immediately - * if VINO interrupt was triggered meanwhile */ - schedule_timeout_interruptible(msecs_to_jiffies(100)); - - if (signal_pending(current)) - err = -EINTR; - - remove_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait); - - dprintk("vino_wait_for_frame(): waiting for frame %s\n", - err ? "failed" : "ok"); - - return err; -} - -/* the function assumes that PAGE_SIZE % 4 == 0 */ -static void vino_convert_to_rgba(struct vino_framebuffer *fb) { - unsigned char *pageptr; - unsigned int page, i; - unsigned char a; - - for (page = 0; page < fb->desc_table.page_count; page++) { - pageptr = (unsigned char *)fb->desc_table.virtual[page]; - - for (i = 0; i < PAGE_SIZE; i += 4) { - a = pageptr[0]; - pageptr[0] = pageptr[3]; - pageptr[1] = pageptr[2]; - pageptr[2] = pageptr[1]; - pageptr[3] = a; - pageptr += 4; - } - } -} - -/* checks if the buffer is in correct state and syncs data */ -static int vino_check_buffer(struct vino_channel_settings *vcs, - struct vino_framebuffer *fb) -{ - int err = 0; - unsigned long flags; - - dprintk("vino_check_buffer():\n"); - - spin_lock_irqsave(&fb->state_lock, flags); - switch (fb->state) { - case VINO_FRAMEBUFFER_IN_USE: - err = -EIO; - break; - case VINO_FRAMEBUFFER_READY: - vino_sync_buffer(fb); - fb->state = VINO_FRAMEBUFFER_UNUSED; - break; - default: - err = -EINVAL; - } - spin_unlock_irqrestore(&fb->state_lock, flags); - - if (!err) { - if (vino_pixel_conversion - && (fb->data_format == VINO_DATA_FMT_RGB32)) { - vino_convert_to_rgba(fb); - } - } else if (err && (err != -EINVAL)) { - dprintk("vino_check_buffer(): buffer not ready\n"); - - spin_lock_irqsave(&vino_drvdata->vino_lock, flags); - vino_dma_stop(vcs); - vino_clear_interrupt(vcs); - spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags); - } - - return err; -} - -/* forcefully terminates capture */ -static void vino_capture_stop(struct vino_channel_settings *vcs) -{ - unsigned int incoming = 0, outgoing = 0, id; - unsigned long flags, flags2; - - dprintk("vino_capture_stop():\n"); - - spin_lock_irqsave(&vcs->capture_lock, flags); - - /* unset capturing to stop queue processing */ - vcs->capturing = 0; - - spin_lock_irqsave(&vino_drvdata->vino_lock, flags2); - - vino_dma_stop(vcs); - vino_clear_interrupt(vcs); - - spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags2); - - /* remove all items from the queue */ - if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) { - dprintk("vino_capture_stop(): " - "vino_queue_get_incoming() failed\n"); - goto out; - } - while (incoming > 0) { - vino_queue_transfer(&vcs->fb_queue); - - if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) { - dprintk("vino_capture_stop(): " - "vino_queue_get_incoming() failed\n"); - goto out; - } - } - - if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) { - dprintk("vino_capture_stop(): " - "vino_queue_get_outgoing() failed\n"); - goto out; - } - while (outgoing > 0) { - vino_queue_remove(&vcs->fb_queue, &id); - - if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) { - dprintk("vino_capture_stop(): " - "vino_queue_get_outgoing() failed\n"); - goto out; - } - } - -out: - spin_unlock_irqrestore(&vcs->capture_lock, flags); -} - -#if 0 -static int vino_capture_failed(struct vino_channel_settings *vcs) -{ - struct vino_framebuffer *fb; - unsigned long flags; - unsigned int i; - int ret; - - dprintk("vino_capture_failed():\n"); - - spin_lock_irqsave(&vino_drvdata->vino_lock, flags); - - vino_dma_stop(vcs); - vino_clear_interrupt(vcs); - - spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags); - - ret = vino_queue_get_incoming(&vcs->fb_queue, &i); - if (ret == VINO_QUEUE_ERROR) { - dprintk("vino_queue_get_incoming() failed\n"); - return -EINVAL; - } - if (i == 0) { - /* no buffers to process */ - return 0; - } - - fb = vino_queue_peek(&vcs->fb_queue, &i); - if (fb == NULL) { - dprintk("vino_queue_peek() failed\n"); - return -EINVAL; - } - - spin_lock_irqsave(&fb->state_lock, flags); - if (fb->state == VINO_FRAMEBUFFER_IN_USE) { - fb->state = VINO_FRAMEBUFFER_UNUSED; - vino_queue_transfer(&vcs->fb_queue); - vino_queue_remove(&vcs->fb_queue, &i); - /* we should actually discard the newest frame, - * but who cares ... */ - } - spin_unlock_irqrestore(&fb->state_lock, flags); - - return 0; -} -#endif - -static void vino_skip_frame(struct vino_channel_settings *vcs) -{ - struct vino_framebuffer *fb; - unsigned long flags; - unsigned int id; - - spin_lock_irqsave(&vcs->capture_lock, flags); - fb = vino_queue_peek(&vcs->fb_queue, &id); - if (!fb) { - spin_unlock_irqrestore(&vcs->capture_lock, flags); - dprintk("vino_skip_frame(): vino_queue_peek() failed!\n"); - return; - } - spin_unlock_irqrestore(&vcs->capture_lock, flags); - - spin_lock_irqsave(&fb->state_lock, flags); - fb->state = VINO_FRAMEBUFFER_UNUSED; - spin_unlock_irqrestore(&fb->state_lock, flags); - - vino_capture_next(vcs, 0); -} - -static void vino_frame_done(struct vino_channel_settings *vcs) -{ - struct vino_framebuffer *fb; - unsigned long flags; - - spin_lock_irqsave(&vcs->capture_lock, flags); - fb = vino_queue_transfer(&vcs->fb_queue); - if (!fb) { - spin_unlock_irqrestore(&vcs->capture_lock, flags); - dprintk("vino_frame_done(): vino_queue_transfer() failed!\n"); - return; - } - spin_unlock_irqrestore(&vcs->capture_lock, flags); - - fb->frame_counter = vcs->int_data.frame_counter; - memcpy(&fb->timestamp, &vcs->int_data.timestamp, - sizeof(struct timeval)); - - spin_lock_irqsave(&fb->state_lock, flags); - if (fb->state == VINO_FRAMEBUFFER_IN_USE) - fb->state = VINO_FRAMEBUFFER_READY; - spin_unlock_irqrestore(&fb->state_lock, flags); - - wake_up(&vcs->fb_queue.frame_wait_queue); - - vino_capture_next(vcs, 0); -} - -static void vino_capture_tasklet(unsigned long channel) { - struct vino_channel_settings *vcs; - - vcs = (channel == VINO_CHANNEL_A) - ? &vino_drvdata->a : &vino_drvdata->b; - - if (vcs->int_data.skip) - vcs->int_data.skip_count++; - - if (vcs->int_data.skip && (vcs->int_data.skip_count - <= VINO_MAX_FRAME_SKIP_COUNT)) { - vino_skip_frame(vcs); - } else { - vcs->int_data.skip_count = 0; - vino_frame_done(vcs); - } -} - -static irqreturn_t vino_interrupt(int irq, void *dev_id) -{ - u32 ctrl, intr; - unsigned int fc_a, fc_b; - int handled_a = 0, skip_a = 0, done_a = 0; - int handled_b = 0, skip_b = 0, done_b = 0; - -#ifdef VINO_DEBUG_INT - int loop = 0; - unsigned int line_count = vino->a.line_count, - page_index = vino->a.page_index, - field_counter = vino->a.field_counter, - start_desc_tbl = vino->a.start_desc_tbl, - next_4_desc = vino->a.next_4_desc; - unsigned int line_count_2, - page_index_2, - field_counter_2, - start_desc_tbl_2, - next_4_desc_2; -#endif - - spin_lock(&vino_drvdata->vino_lock); - - while ((intr = vino->intr_status)) { - fc_a = vino->a.field_counter >> 1; - fc_b = vino->b.field_counter >> 1; - - /* handle error-interrupts in some special way ? - * --> skips frames */ - if (intr & VINO_INTSTAT_A) { - if (intr & VINO_INTSTAT_A_EOF) { - vino_drvdata->a.field++; - if (vino_drvdata->a.field > 1) { - vino_dma_stop(&vino_drvdata->a); - vino_clear_interrupt(&vino_drvdata->a); - vino_drvdata->a.field = 0; - done_a = 1; - } else { - if (vino->a.page_index - != vino_drvdata->a.line_size) { - vino->a.line_count = 0; - vino->a.page_index = - vino_drvdata-> - a.line_size; - vino->a.next_4_desc = - vino->a.start_desc_tbl; - } - } - dprintk("channel A end-of-field " - "interrupt: %04x\n", intr); - } else { - vino_dma_stop(&vino_drvdata->a); - vino_clear_interrupt(&vino_drvdata->a); - vino_drvdata->a.field = 0; - skip_a = 1; - dprintk("channel A error interrupt: %04x\n", - intr); - } - -#ifdef VINO_DEBUG_INT - line_count_2 = vino->a.line_count; - page_index_2 = vino->a.page_index; - field_counter_2 = vino->a.field_counter; - start_desc_tbl_2 = vino->a.start_desc_tbl; - next_4_desc_2 = vino->a.next_4_desc; - - printk("intr = %04x, loop = %d, field = %d\n", - intr, loop, vino_drvdata->a.field); - printk("1- line count = %04d, page index = %04d, " - "start = %08x, next = %08x\n" - " fieldc = %d, framec = %d\n", - line_count, page_index, start_desc_tbl, - next_4_desc, field_counter, fc_a); - printk("12-line count = %04d, page index = %04d, " - " start = %08x, next = %08x\n", - line_count_2, page_index_2, start_desc_tbl_2, - next_4_desc_2); - - if (done_a) - printk("\n"); -#endif - } - - if (intr & VINO_INTSTAT_B) { - if (intr & VINO_INTSTAT_B_EOF) { - vino_drvdata->b.field++; - if (vino_drvdata->b.field > 1) { - vino_dma_stop(&vino_drvdata->b); - vino_clear_interrupt(&vino_drvdata->b); - vino_drvdata->b.field = 0; - done_b = 1; - } - dprintk("channel B end-of-field " - "interrupt: %04x\n", intr); - } else { - vino_dma_stop(&vino_drvdata->b); - vino_clear_interrupt(&vino_drvdata->b); - vino_drvdata->b.field = 0; - skip_b = 1; - dprintk("channel B error interrupt: %04x\n", - intr); - } - } - - /* Always remember to clear interrupt status. - * Disable VINO interrupts while we do this. */ - ctrl = vino->control; - vino->control = ctrl & ~(VINO_CTRL_A_INT | VINO_CTRL_B_INT); - vino->intr_status = ~intr; - vino->control = ctrl; - - spin_unlock(&vino_drvdata->vino_lock); - - if ((!handled_a) && (done_a || skip_a)) { - if (!skip_a) { - v4l2_get_timestamp( - &vino_drvdata->a.int_data.timestamp); - vino_drvdata->a.int_data.frame_counter = fc_a; - } - vino_drvdata->a.int_data.skip = skip_a; - - dprintk("channel A %s, interrupt: %d\n", - skip_a ? "skipping frame" : "frame done", - intr); - tasklet_hi_schedule(&vino_tasklet_a); - handled_a = 1; - } - - if ((!handled_b) && (done_b || skip_b)) { - if (!skip_b) { - v4l2_get_timestamp( - &vino_drvdata->b.int_data.timestamp); - vino_drvdata->b.int_data.frame_counter = fc_b; - } - vino_drvdata->b.int_data.skip = skip_b; - - dprintk("channel B %s, interrupt: %d\n", - skip_b ? "skipping frame" : "frame done", - intr); - tasklet_hi_schedule(&vino_tasklet_b); - handled_b = 1; - } - -#ifdef VINO_DEBUG_INT - loop++; -#endif - spin_lock(&vino_drvdata->vino_lock); - } - - spin_unlock(&vino_drvdata->vino_lock); - - return IRQ_HANDLED; -} - -/* VINO video input management */ - -static int vino_get_saa7191_input(int input) -{ - switch (input) { - case VINO_INPUT_COMPOSITE: - return SAA7191_INPUT_COMPOSITE; - case VINO_INPUT_SVIDEO: - return SAA7191_INPUT_SVIDEO; - default: - printk(KERN_ERR "VINO: vino_get_saa7191_input(): " - "invalid input!\n"); - return -1; - } -} - -/* execute with input_lock locked */ -static int vino_is_input_owner(struct vino_channel_settings *vcs) -{ - switch(vcs->input) { - case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: - return vino_drvdata->decoder_owner == vcs->channel; - case VINO_INPUT_D1: - return vino_drvdata->camera_owner == vcs->channel; - default: - return 0; - } -} - -static int vino_acquire_input(struct vino_channel_settings *vcs) -{ - unsigned long flags; - int ret = 0; - - dprintk("vino_acquire_input():\n"); - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - /* First try D1 and then SAA7191 */ - if (vino_drvdata->camera - && (vino_drvdata->camera_owner == VINO_NO_CHANNEL)) { - vino_drvdata->camera_owner = vcs->channel; - vcs->input = VINO_INPUT_D1; - vcs->data_norm = VINO_DATA_NORM_D1; - } else if (vino_drvdata->decoder - && (vino_drvdata->decoder_owner == VINO_NO_CHANNEL)) { - int input; - int data_norm = 0; - v4l2_std_id norm; - - input = VINO_INPUT_COMPOSITE; - - ret = decoder_call(video, s_routing, - vino_get_saa7191_input(input), 0, 0); - if (ret) { - ret = -EINVAL; - goto out; - } - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - /* Don't hold spinlocks while auto-detecting norm - * as it may take a while... */ - - ret = decoder_call(video, querystd, &norm); - if (!ret) { - for (data_norm = 0; data_norm < 3; data_norm++) { - if (vino_data_norms[data_norm].std & norm) - break; - } - if (data_norm == 3) - data_norm = VINO_DATA_NORM_PAL; - ret = decoder_call(video, s_std, norm); - } - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - if (ret) { - ret = -EINVAL; - goto out; - } - - vino_drvdata->decoder_owner = vcs->channel; - - vcs->input = input; - vcs->data_norm = data_norm; - } else { - vcs->input = (vcs->channel == VINO_CHANNEL_A) ? - vino_drvdata->b.input : vino_drvdata->a.input; - vcs->data_norm = (vcs->channel == VINO_CHANNEL_A) ? - vino_drvdata->b.data_norm : vino_drvdata->a.data_norm; - } - - if (vcs->input == VINO_INPUT_NONE) { - ret = -ENODEV; - goto out; - } - - vino_set_default_clipping(vcs); - vino_set_default_scaling(vcs); - vino_set_default_framerate(vcs); - - dprintk("vino_acquire_input(): %s\n", vino_inputs[vcs->input].name); - -out: - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return ret; -} - -static int vino_set_input(struct vino_channel_settings *vcs, int input) -{ - struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ? - &vino_drvdata->b : &vino_drvdata->a; - unsigned long flags; - int ret = 0; - - dprintk("vino_set_input():\n"); - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - if (vcs->input == input) - goto out; - - switch (input) { - case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: - if (!vino_drvdata->decoder) { - ret = -EINVAL; - goto out; - } - - if (vino_drvdata->decoder_owner == VINO_NO_CHANNEL) { - vino_drvdata->decoder_owner = vcs->channel; - } - - if (vino_drvdata->decoder_owner == vcs->channel) { - int data_norm = 0; - v4l2_std_id norm; - - ret = decoder_call(video, s_routing, - vino_get_saa7191_input(input), 0, 0); - if (ret) { - vino_drvdata->decoder_owner = VINO_NO_CHANNEL; - ret = -EINVAL; - goto out; - } - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - /* Don't hold spinlocks while auto-detecting norm - * as it may take a while... */ - - ret = decoder_call(video, querystd, &norm); - if (!ret) { - for (data_norm = 0; data_norm < 3; data_norm++) { - if (vino_data_norms[data_norm].std & norm) - break; - } - if (data_norm == 3) - data_norm = VINO_DATA_NORM_PAL; - ret = decoder_call(video, s_std, norm); - } - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - if (ret) { - vino_drvdata->decoder_owner = VINO_NO_CHANNEL; - ret = -EINVAL; - goto out; - } - - vcs->input = input; - vcs->data_norm = data_norm; - } else { - if (input != vcs2->input) { - ret = -EBUSY; - goto out; - } - - vcs->input = input; - vcs->data_norm = vcs2->data_norm; - } - - if (vino_drvdata->camera_owner == vcs->channel) { - /* Transfer the ownership or release the input */ - if (vcs2->input == VINO_INPUT_D1) { - vino_drvdata->camera_owner = vcs2->channel; - } else { - vino_drvdata->camera_owner = VINO_NO_CHANNEL; - } - } - break; - case VINO_INPUT_D1: - if (!vino_drvdata->camera) { - ret = -EINVAL; - goto out; - } - - if (vino_drvdata->camera_owner == VINO_NO_CHANNEL) - vino_drvdata->camera_owner = vcs->channel; - - if (vino_drvdata->decoder_owner == vcs->channel) { - /* Transfer the ownership or release the input */ - if ((vcs2->input == VINO_INPUT_COMPOSITE) || - (vcs2->input == VINO_INPUT_SVIDEO)) { - vino_drvdata->decoder_owner = vcs2->channel; - } else { - vino_drvdata->decoder_owner = VINO_NO_CHANNEL; - } - } - - vcs->input = input; - vcs->data_norm = VINO_DATA_NORM_D1; - break; - default: - ret = -EINVAL; - goto out; - } - - vino_set_default_clipping(vcs); - vino_set_default_scaling(vcs); - vino_set_default_framerate(vcs); - - dprintk("vino_set_input(): %s\n", vino_inputs[vcs->input].name); - -out: - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return ret; -} - -static void vino_release_input(struct vino_channel_settings *vcs) -{ - struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ? - &vino_drvdata->b : &vino_drvdata->a; - unsigned long flags; - - dprintk("vino_release_input():\n"); - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - /* Release ownership of the channel - * and if the other channel takes input from - * the same source, transfer the ownership */ - if (vino_drvdata->camera_owner == vcs->channel) { - if (vcs2->input == VINO_INPUT_D1) { - vino_drvdata->camera_owner = vcs2->channel; - } else { - vino_drvdata->camera_owner = VINO_NO_CHANNEL; - } - } else if (vino_drvdata->decoder_owner == vcs->channel) { - if ((vcs2->input == VINO_INPUT_COMPOSITE) || - (vcs2->input == VINO_INPUT_SVIDEO)) { - vino_drvdata->decoder_owner = vcs2->channel; - } else { - vino_drvdata->decoder_owner = VINO_NO_CHANNEL; - } - } - vcs->input = VINO_INPUT_NONE; - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); -} - -/* execute with input_lock locked */ -static int vino_set_data_norm(struct vino_channel_settings *vcs, - unsigned int data_norm, - unsigned long *flags) -{ - int err = 0; - - if (data_norm == vcs->data_norm) - return 0; - - switch (vcs->input) { - case VINO_INPUT_D1: - /* only one "norm" supported */ - if (data_norm != VINO_DATA_NORM_D1) - return -EINVAL; - break; - case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: { - v4l2_std_id norm; - - if ((data_norm != VINO_DATA_NORM_PAL) - && (data_norm != VINO_DATA_NORM_NTSC) - && (data_norm != VINO_DATA_NORM_SECAM)) - return -EINVAL; - - spin_unlock_irqrestore(&vino_drvdata->input_lock, *flags); - - /* Don't hold spinlocks while setting norm - * as it may take a while... */ - - norm = vino_data_norms[data_norm].std; - err = decoder_call(video, s_std, norm); - - spin_lock_irqsave(&vino_drvdata->input_lock, *flags); - - if (err) - goto out; - - vcs->data_norm = data_norm; - - vino_set_default_clipping(vcs); - vino_set_default_scaling(vcs); - vino_set_default_framerate(vcs); - break; - } - default: - return -EINVAL; - } - -out: - return err; -} - -/* V4L2 helper functions */ - -static int vino_find_data_format(__u32 pixelformat) -{ - int i; - - for (i = 0; i < VINO_DATA_FMT_COUNT; i++) { - if (vino_data_formats[i].pixelformat == pixelformat) - return i; - } - - return VINO_DATA_FMT_NONE; -} - -static int vino_int_enum_input(struct vino_channel_settings *vcs, __u32 index) -{ - int input = VINO_INPUT_NONE; - unsigned long flags; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - if (vino_drvdata->decoder && vino_drvdata->camera) { - switch (index) { - case 0: - input = VINO_INPUT_COMPOSITE; - break; - case 1: - input = VINO_INPUT_SVIDEO; - break; - case 2: - input = VINO_INPUT_D1; - break; - } - } else if (vino_drvdata->decoder) { - switch (index) { - case 0: - input = VINO_INPUT_COMPOSITE; - break; - case 1: - input = VINO_INPUT_SVIDEO; - break; - } - } else if (vino_drvdata->camera) { - switch (index) { - case 0: - input = VINO_INPUT_D1; - break; - } - } - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return input; -} - -/* execute with input_lock locked */ -static __u32 vino_find_input_index(struct vino_channel_settings *vcs) -{ - __u32 index = 0; - // FIXME: detect when no inputs available - - if (vino_drvdata->decoder && vino_drvdata->camera) { - switch (vcs->input) { - case VINO_INPUT_COMPOSITE: - index = 0; - break; - case VINO_INPUT_SVIDEO: - index = 1; - break; - case VINO_INPUT_D1: - index = 2; - break; - } - } else if (vino_drvdata->decoder) { - switch (vcs->input) { - case VINO_INPUT_COMPOSITE: - index = 0; - break; - case VINO_INPUT_SVIDEO: - index = 1; - break; - } - } else if (vino_drvdata->camera) { - switch (vcs->input) { - case VINO_INPUT_D1: - index = 0; - break; - } - } - - return index; -} - -/* V4L2 ioctls */ - -static int vino_querycap(struct file *file, void *__fh, - struct v4l2_capability *cap) -{ - memset(cap, 0, sizeof(struct v4l2_capability)); - - strcpy(cap->driver, vino_driver_name); - strcpy(cap->card, vino_driver_description); - strcpy(cap->bus_info, vino_bus_name); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; -} - -static int vino_enum_input(struct file *file, void *__fh, - struct v4l2_input *i) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - __u32 index = i->index; - int input; - dprintk("requested index = %d\n", index); - - input = vino_int_enum_input(vcs, index); - if (input == VINO_INPUT_NONE) - return -EINVAL; - - i->type = V4L2_INPUT_TYPE_CAMERA; - i->std = vino_inputs[input].std; - strcpy(i->name, vino_inputs[input].name); - - if (input == VINO_INPUT_COMPOSITE || input == VINO_INPUT_SVIDEO) - decoder_call(video, g_input_status, &i->status); - return 0; -} - -static int vino_g_input(struct file *file, void *__fh, - unsigned int *i) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - __u32 index; - int input; - unsigned long flags; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - input = vcs->input; - index = vino_find_input_index(vcs); - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - dprintk("input = %d\n", input); - - if (input == VINO_INPUT_NONE) { - return -EINVAL; - } - - *i = index; - - return 0; -} - -static int vino_s_input(struct file *file, void *__fh, - unsigned int i) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - int input; - dprintk("requested input = %d\n", i); - - input = vino_int_enum_input(vcs, i); - if (input == VINO_INPUT_NONE) - return -EINVAL; - - return vino_set_input(vcs, input); -} - -static int vino_querystd(struct file *file, void *__fh, - v4l2_std_id *std) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - int err = 0; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - switch (vcs->input) { - case VINO_INPUT_D1: - *std = vino_inputs[vcs->input].std; - break; - case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: { - decoder_call(video, querystd, std); - break; - } - default: - err = -EINVAL; - } - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return err; -} - -static int vino_g_std(struct file *file, void *__fh, - v4l2_std_id *std) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - *std = vino_data_norms[vcs->data_norm].std; - dprintk("current standard = %d\n", vcs->data_norm); - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return 0; -} - -static int vino_s_std(struct file *file, void *__fh, - v4l2_std_id std) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - if (!vino_is_input_owner(vcs)) { - ret = -EBUSY; - goto out; - } - - /* check if the standard is valid for the current input */ - if (std & vino_inputs[vcs->input].std) { - dprintk("standard accepted\n"); - - /* change the video norm for SAA7191 - * and accept NTSC for D1 (do nothing) */ - - if (vcs->input == VINO_INPUT_D1) - goto out; - - if (std & V4L2_STD_PAL) { - ret = vino_set_data_norm(vcs, VINO_DATA_NORM_PAL, - &flags); - } else if (std & V4L2_STD_NTSC) { - ret = vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC, - &flags); - } else if (std & V4L2_STD_SECAM) { - ret = vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM, - &flags); - } else { - ret = -EINVAL; - } - - if (ret) { - ret = -EINVAL; - } - } else { - ret = -EINVAL; - } - -out: - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return ret; -} - -static int vino_enum_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_fmtdesc *fd) -{ - dprintk("format index = %d\n", fd->index); - - if (fd->index >= VINO_DATA_FMT_COUNT) - return -EINVAL; - dprintk("format name = %s\n", vino_data_formats[fd->index].description); - - fd->pixelformat = vino_data_formats[fd->index].pixelformat; - strcpy(fd->description, vino_data_formats[fd->index].description); - return 0; -} - -static int vino_try_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_format *f) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - struct vino_channel_settings tempvcs; - unsigned long flags; - struct v4l2_pix_format *pf = &f->fmt.pix; - - dprintk("requested: w = %d, h = %d\n", - pf->width, pf->height); - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings)); - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - tempvcs.data_format = vino_find_data_format(pf->pixelformat); - if (tempvcs.data_format == VINO_DATA_FMT_NONE) { - tempvcs.data_format = VINO_DATA_FMT_GREY; - pf->pixelformat = - vino_data_formats[tempvcs.data_format]. - pixelformat; - } - - /* data format must be set before clipping/scaling */ - vino_set_scaling(&tempvcs, pf->width, pf->height); - - dprintk("data format = %s\n", - vino_data_formats[tempvcs.data_format].description); - - pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) / - tempvcs.decimation; - pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) / - tempvcs.decimation; - - pf->field = V4L2_FIELD_INTERLACED; - pf->bytesperline = tempvcs.line_size; - pf->sizeimage = tempvcs.line_size * - (tempvcs.clipping.bottom - tempvcs.clipping.top) / - tempvcs.decimation; - pf->colorspace = - vino_data_formats[tempvcs.data_format].colorspace; - - return 0; -} - -static int vino_g_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_format *f) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - struct v4l2_pix_format *pf = &f->fmt.pix; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - pf->width = (vcs->clipping.right - vcs->clipping.left) / - vcs->decimation; - pf->height = (vcs->clipping.bottom - vcs->clipping.top) / - vcs->decimation; - pf->pixelformat = - vino_data_formats[vcs->data_format].pixelformat; - - pf->field = V4L2_FIELD_INTERLACED; - pf->bytesperline = vcs->line_size; - pf->sizeimage = vcs->line_size * - (vcs->clipping.bottom - vcs->clipping.top) / - vcs->decimation; - pf->colorspace = - vino_data_formats[vcs->data_format].colorspace; - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - return 0; -} - -static int vino_s_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_format *f) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - int data_format; - unsigned long flags; - struct v4l2_pix_format *pf = &f->fmt.pix; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - data_format = vino_find_data_format(pf->pixelformat); - - if (data_format == VINO_DATA_FMT_NONE) { - vcs->data_format = VINO_DATA_FMT_GREY; - pf->pixelformat = - vino_data_formats[vcs->data_format]. - pixelformat; - } else { - vcs->data_format = data_format; - } - - /* data format must be set before clipping/scaling */ - vino_set_scaling(vcs, pf->width, pf->height); - - dprintk("data format = %s\n", - vino_data_formats[vcs->data_format].description); - - pf->width = vcs->clipping.right - vcs->clipping.left; - pf->height = vcs->clipping.bottom - vcs->clipping.top; - - pf->field = V4L2_FIELD_INTERLACED; - pf->bytesperline = vcs->line_size; - pf->sizeimage = vcs->line_size * - (vcs->clipping.bottom - vcs->clipping.top) / - vcs->decimation; - pf->colorspace = - vino_data_formats[vcs->data_format].colorspace; - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - return 0; -} - -static int vino_cropcap(struct file *file, void *__fh, - struct v4l2_cropcap *ccap) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - const struct vino_data_norm *norm; - unsigned long flags; - - switch (ccap->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - norm = &vino_data_norms[vcs->data_norm]; - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - ccap->bounds.left = 0; - ccap->bounds.top = 0; - ccap->bounds.width = norm->width; - ccap->bounds.height = norm->height; - memcpy(&ccap->defrect, &ccap->bounds, - sizeof(struct v4l2_rect)); - - ccap->pixelaspect.numerator = 1; - ccap->pixelaspect.denominator = 1; - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - default: - return -EINVAL; - } - - return 0; -} - -static int vino_g_crop(struct file *file, void *__fh, - struct v4l2_crop *c) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - - switch (c->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - c->c.left = vcs->clipping.left; - c->c.top = vcs->clipping.top; - c->c.width = vcs->clipping.right - vcs->clipping.left; - c->c.height = vcs->clipping.bottom - vcs->clipping.top; - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - default: - return -EINVAL; - } - - return 0; -} - -static int vino_s_crop(struct file *file, void *__fh, - const struct v4l2_crop *c) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - - switch (c->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - vino_set_clipping(vcs, c->c.left, c->c.top, - c->c.width, c->c.height); - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - default: - return -EINVAL; - } - - return 0; -} - -static int vino_g_parm(struct file *file, void *__fh, - struct v4l2_streamparm *sp) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - struct v4l2_captureparm *cp = &sp->parm.capture; - - cp->capability = V4L2_CAP_TIMEPERFRAME; - cp->timeperframe.numerator = 1; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - cp->timeperframe.denominator = vcs->fps; - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - /* TODO: cp->readbuffers = xxx; */ - - return 0; -} - -static int vino_s_parm(struct file *file, void *__fh, - struct v4l2_streamparm *sp) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - struct v4l2_captureparm *cp = &sp->parm.capture; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - if ((cp->timeperframe.numerator == 0) || - (cp->timeperframe.denominator == 0)) { - /* reset framerate */ - vino_set_default_framerate(vcs); - } else { - vino_set_framerate(vcs, cp->timeperframe.denominator / - cp->timeperframe.numerator); - } - - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return 0; -} - -static int vino_reqbufs(struct file *file, void *__fh, - struct v4l2_requestbuffers *rb) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - - if (vcs->reading) - return -EBUSY; - - /* TODO: check queue type */ - if (rb->memory != V4L2_MEMORY_MMAP) { - dprintk("type not mmap\n"); - return -EINVAL; - } - - dprintk("count = %d\n", rb->count); - if (rb->count > 0) { - if (vino_is_capturing(vcs)) { - dprintk("busy, capturing\n"); - return -EBUSY; - } - - if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) { - dprintk("busy, buffers still mapped\n"); - return -EBUSY; - } else { - vcs->streaming = 0; - vino_queue_free(&vcs->fb_queue); - vino_queue_init(&vcs->fb_queue, &rb->count); - } - } else { - vcs->streaming = 0; - vino_capture_stop(vcs); - vino_queue_free(&vcs->fb_queue); - } - - return 0; -} - -static void vino_v4l2_get_buffer_status(struct vino_channel_settings *vcs, - struct vino_framebuffer *fb, - struct v4l2_buffer *b) -{ - if (vino_queue_outgoing_contains(&vcs->fb_queue, - fb->id)) { - b->flags &= ~V4L2_BUF_FLAG_QUEUED; - b->flags |= V4L2_BUF_FLAG_DONE; - } else if (vino_queue_incoming_contains(&vcs->fb_queue, - fb->id)) { - b->flags &= ~V4L2_BUF_FLAG_DONE; - b->flags |= V4L2_BUF_FLAG_QUEUED; - } else { - b->flags &= ~(V4L2_BUF_FLAG_DONE | - V4L2_BUF_FLAG_QUEUED); - } - - b->flags &= ~(V4L2_BUF_FLAG_TIMECODE); - - if (fb->map_count > 0) - b->flags |= V4L2_BUF_FLAG_MAPPED; - - b->flags &= ~V4L2_BUF_FLAG_TIMESTAMP_MASK; - b->flags |= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - - b->index = fb->id; - b->memory = (vcs->fb_queue.type == VINO_MEMORY_MMAP) ? - V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR; - b->m.offset = fb->offset; - b->bytesused = fb->data_size; - b->length = fb->size; - b->field = V4L2_FIELD_INTERLACED; - b->sequence = fb->frame_counter; - memcpy(&b->timestamp, &fb->timestamp, - sizeof(struct timeval)); - // b->input ? - - dprintk("buffer %d: length = %d, bytesused = %d, offset = %d\n", - fb->id, fb->size, fb->data_size, fb->offset); -} - -static int vino_querybuf(struct file *file, void *__fh, - struct v4l2_buffer *b) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - struct vino_framebuffer *fb; - - if (vcs->reading) - return -EBUSY; - - /* TODO: check queue type */ - if (b->index >= vino_queue_get_length(&vcs->fb_queue)) { - dprintk("invalid index = %d\n", - b->index); - return -EINVAL; - } - - fb = vino_queue_get_buffer(&vcs->fb_queue, - b->index); - if (fb == NULL) { - dprintk("vino_queue_get_buffer() failed"); - return -EINVAL; - } - - vino_v4l2_get_buffer_status(vcs, fb, b); - - return 0; -} - -static int vino_qbuf(struct file *file, void *__fh, - struct v4l2_buffer *b) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - struct vino_framebuffer *fb; - int ret; - - if (vcs->reading) - return -EBUSY; - - /* TODO: check queue type */ - if (b->memory != V4L2_MEMORY_MMAP) { - dprintk("type not mmap\n"); - return -EINVAL; - } - - fb = vino_capture_enqueue(vcs, b->index); - if (fb == NULL) - return -EINVAL; - - vino_v4l2_get_buffer_status(vcs, fb, b); - - if (vcs->streaming) { - ret = vino_capture_next(vcs, 1); - if (ret) - return ret; - } - - return 0; -} - -static int vino_dqbuf(struct file *file, void *__fh, - struct v4l2_buffer *b) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned int nonblocking = file->f_flags & O_NONBLOCK; - struct vino_framebuffer *fb; - unsigned int incoming, outgoing; - int err; - - if (vcs->reading) - return -EBUSY; - - /* TODO: check queue type */ - - err = vino_queue_get_incoming(&vcs->fb_queue, &incoming); - if (err) { - dprintk("vino_queue_get_incoming() failed\n"); - return -EINVAL; - } - err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing); - if (err) { - dprintk("vino_queue_get_outgoing() failed\n"); - return -EINVAL; - } - - dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing); - - if (outgoing == 0) { - if (incoming == 0) { - dprintk("no incoming or outgoing buffers\n"); - return -EINVAL; - } - if (nonblocking) { - dprintk("non-blocking I/O was selected and " - "there are no buffers to dequeue\n"); - return -EAGAIN; - } - - err = vino_wait_for_frame(vcs); - if (err) { - err = vino_wait_for_frame(vcs); - if (err) { - /* interrupted or no frames captured because of - * frame skipping */ - /* vino_capture_failed(vcs); */ - return -EIO; - } - } - } - - fb = vino_queue_remove(&vcs->fb_queue, &b->index); - if (fb == NULL) { - dprintk("vino_queue_remove() failed\n"); - return -EINVAL; - } - - err = vino_check_buffer(vcs, fb); - - vino_v4l2_get_buffer_status(vcs, fb, b); - - if (err) - return -EIO; - - return 0; -} - -static int vino_streamon(struct file *file, void *__fh, - enum v4l2_buf_type i) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned int incoming; - int ret; - if (vcs->reading) - return -EBUSY; - - if (vcs->streaming) - return 0; - - // TODO: check queue type - - if (vino_queue_get_length(&vcs->fb_queue) < 1) { - dprintk("no buffers allocated\n"); - return -EINVAL; - } - - ret = vino_queue_get_incoming(&vcs->fb_queue, &incoming); - if (ret) { - dprintk("vino_queue_get_incoming() failed\n"); - return -EINVAL; - } - - vcs->streaming = 1; - - if (incoming > 0) { - ret = vino_capture_next(vcs, 1); - if (ret) { - vcs->streaming = 0; - - dprintk("couldn't start capture\n"); - return -EINVAL; - } - } - - return 0; -} - -static int vino_streamoff(struct file *file, void *__fh, - enum v4l2_buf_type i) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - if (vcs->reading) - return -EBUSY; - - if (!vcs->streaming) - return 0; - - vcs->streaming = 0; - vino_capture_stop(vcs); - - return 0; -} - -static int vino_queryctrl(struct file *file, void *__fh, - struct v4l2_queryctrl *queryctrl) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - int i; - int err = 0; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - switch (vcs->input) { - case VINO_INPUT_D1: - for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) { - if (vino_indycam_v4l2_controls[i].id == - queryctrl->id) { - memcpy(queryctrl, - &vino_indycam_v4l2_controls[i], - sizeof(struct v4l2_queryctrl)); - queryctrl->reserved[0] = 0; - goto found; - } - } - - err = -EINVAL; - break; - case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: - for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) { - if (vino_saa7191_v4l2_controls[i].id == - queryctrl->id) { - memcpy(queryctrl, - &vino_saa7191_v4l2_controls[i], - sizeof(struct v4l2_queryctrl)); - queryctrl->reserved[0] = 0; - goto found; - } - } - - err = -EINVAL; - break; - default: - err = -EINVAL; - } - - found: - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return err; -} - -static int vino_g_ctrl(struct file *file, void *__fh, - struct v4l2_control *control) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - int i; - int err = 0; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - switch (vcs->input) { - case VINO_INPUT_D1: { - err = -EINVAL; - for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) { - if (vino_indycam_v4l2_controls[i].id == control->id) { - err = 0; - break; - } - } - - if (err) - goto out; - - err = camera_call(core, g_ctrl, control); - if (err) - err = -EINVAL; - break; - } - case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: { - err = -EINVAL; - for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) { - if (vino_saa7191_v4l2_controls[i].id == control->id) { - err = 0; - break; - } - } - - if (err) - goto out; - - err = decoder_call(core, g_ctrl, control); - if (err) - err = -EINVAL; - break; - } - default: - err = -EINVAL; - } - -out: - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return err; -} - -static int vino_s_ctrl(struct file *file, void *__fh, - struct v4l2_control *control) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned long flags; - int i; - int err = 0; - - spin_lock_irqsave(&vino_drvdata->input_lock, flags); - - if (!vino_is_input_owner(vcs)) { - err = -EBUSY; - goto out; - } - - switch (vcs->input) { - case VINO_INPUT_D1: { - err = -EINVAL; - for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) { - if (vino_indycam_v4l2_controls[i].id == control->id) { - err = 0; - break; - } - } - if (err) - goto out; - if (control->value < vino_indycam_v4l2_controls[i].minimum || - control->value > vino_indycam_v4l2_controls[i].maximum) { - err = -ERANGE; - goto out; - } - err = camera_call(core, s_ctrl, control); - if (err) - err = -EINVAL; - break; - } - case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: { - err = -EINVAL; - for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) { - if (vino_saa7191_v4l2_controls[i].id == control->id) { - err = 0; - break; - } - } - if (err) - goto out; - if (control->value < vino_saa7191_v4l2_controls[i].minimum || - control->value > vino_saa7191_v4l2_controls[i].maximum) { - err = -ERANGE; - goto out; - } - - err = decoder_call(core, s_ctrl, control); - if (err) - err = -EINVAL; - break; - } - default: - err = -EINVAL; - } - -out: - spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - - return err; -} - -/* File operations */ - -static int vino_open(struct file *file) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - int ret = 0; - dprintk("open(): channel = %c\n", - (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B'); - - mutex_lock(&vcs->mutex); - - if (vcs->users) { - dprintk("open(): driver busy\n"); - ret = -EBUSY; - goto out; - } - - ret = vino_acquire_input(vcs); - if (ret) { - dprintk("open(): vino_acquire_input() failed\n"); - goto out; - } - - vcs->users++; - - out: - mutex_unlock(&vcs->mutex); - - dprintk("open(): %s!\n", ret ? "failed" : "complete"); - - return ret; -} - -static int vino_close(struct file *file) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - dprintk("close():\n"); - - mutex_lock(&vcs->mutex); - - vcs->users--; - - if (!vcs->users) { - vino_release_input(vcs); - - /* stop DMA and free buffers */ - vino_capture_stop(vcs); - vino_queue_free(&vcs->fb_queue); - } - - mutex_unlock(&vcs->mutex); - - return 0; -} - -static void vino_vm_open(struct vm_area_struct *vma) -{ - struct vino_framebuffer *fb = vma->vm_private_data; - - fb->map_count++; - dprintk("vino_vm_open(): count = %d\n", fb->map_count); -} - -static void vino_vm_close(struct vm_area_struct *vma) -{ - struct vino_framebuffer *fb = vma->vm_private_data; - - fb->map_count--; - dprintk("vino_vm_close(): count = %d\n", fb->map_count); -} - -static const struct vm_operations_struct vino_vm_ops = { - .open = vino_vm_open, - .close = vino_vm_close, -}; - -static int vino_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - - struct vino_framebuffer *fb = NULL; - unsigned int i, length; - int ret = 0; - - dprintk("mmap():\n"); - - // TODO: reject mmap if already mapped - - if (mutex_lock_interruptible(&vcs->mutex)) - return -EINTR; - - if (vcs->reading) { - ret = -EBUSY; - goto out; - } - - // TODO: check queue type - - if (!(vma->vm_flags & VM_WRITE)) { - dprintk("mmap(): app bug: PROT_WRITE please\n"); - ret = -EINVAL; - goto out; - } - if (!(vma->vm_flags & VM_SHARED)) { - dprintk("mmap(): app bug: MAP_SHARED please\n"); - ret = -EINVAL; - goto out; - } - - /* find the correct buffer using offset */ - length = vino_queue_get_length(&vcs->fb_queue); - if (length == 0) { - dprintk("mmap(): queue not initialized\n"); - ret = -EINVAL; - goto out; - } - - for (i = 0; i < length; i++) { - fb = vino_queue_get_buffer(&vcs->fb_queue, i); - if (fb == NULL) { - dprintk("mmap(): vino_queue_get_buffer() failed\n"); - ret = -EINVAL; - goto out; - } - - if (fb->offset == offset) - goto found; - } - - dprintk("mmap(): invalid offset = %lu\n", offset); - ret = -EINVAL; - goto out; - -found: - dprintk("mmap(): buffer = %d\n", i); - - if (size > (fb->desc_table.page_count * PAGE_SIZE)) { - dprintk("mmap(): failed: size = %lu > %lu\n", - size, fb->desc_table.page_count * PAGE_SIZE); - ret = -EINVAL; - goto out; - } - - for (i = 0; i < fb->desc_table.page_count; i++) { - unsigned long pfn = - virt_to_phys((void *)fb->desc_table.virtual[i]) >> - PAGE_SHIFT; - - if (size < PAGE_SIZE) - break; - - // protection was: PAGE_READONLY - if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, - vma->vm_page_prot)) { - dprintk("mmap(): remap_pfn_range() failed\n"); - ret = -EAGAIN; - goto out; - } - - start += PAGE_SIZE; - size -= PAGE_SIZE; - } - - fb->map_count = 1; - - vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_flags &= ~VM_IO; - vma->vm_private_data = fb; - vma->vm_file = file; - vma->vm_ops = &vino_vm_ops; - -out: - mutex_unlock(&vcs->mutex); - - return ret; -} - -static unsigned int vino_poll(struct file *file, poll_table *pt) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - unsigned int outgoing; - unsigned int ret = 0; - - // lock mutex (?) - // TODO: this has to be corrected for different read modes - - dprintk("poll():\n"); - - if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) { - dprintk("poll(): vino_queue_get_outgoing() failed\n"); - ret = POLLERR; - goto error; - } - if (outgoing > 0) - goto over; - - poll_wait(file, &vcs->fb_queue.frame_wait_queue, pt); - - if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) { - dprintk("poll(): vino_queue_get_outgoing() failed\n"); - ret = POLLERR; - goto error; - } - -over: - dprintk("poll(): data %savailable\n", - (outgoing > 0) ? "" : "not "); - - if (outgoing > 0) - ret = POLLIN | POLLRDNORM; - -error: - return ret; -} - -static long vino_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct vino_channel_settings *vcs = video_drvdata(file); - long ret; - - if (mutex_lock_interruptible(&vcs->mutex)) - return -EINTR; - - ret = video_ioctl2(file, cmd, arg); - - mutex_unlock(&vcs->mutex); - - return ret; -} - -/* Initialization and cleanup */ - -/* __initdata */ -static int vino_init_stage; - -const struct v4l2_ioctl_ops vino_ioctl_ops = { - .vidioc_enum_fmt_vid_cap = vino_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vino_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vino_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vino_try_fmt_vid_cap, - .vidioc_querycap = vino_querycap, - .vidioc_enum_input = vino_enum_input, - .vidioc_g_input = vino_g_input, - .vidioc_s_input = vino_s_input, - .vidioc_g_std = vino_g_std, - .vidioc_s_std = vino_s_std, - .vidioc_querystd = vino_querystd, - .vidioc_cropcap = vino_cropcap, - .vidioc_s_crop = vino_s_crop, - .vidioc_g_crop = vino_g_crop, - .vidioc_s_parm = vino_s_parm, - .vidioc_g_parm = vino_g_parm, - .vidioc_reqbufs = vino_reqbufs, - .vidioc_querybuf = vino_querybuf, - .vidioc_qbuf = vino_qbuf, - .vidioc_dqbuf = vino_dqbuf, - .vidioc_streamon = vino_streamon, - .vidioc_streamoff = vino_streamoff, - .vidioc_queryctrl = vino_queryctrl, - .vidioc_g_ctrl = vino_g_ctrl, - .vidioc_s_ctrl = vino_s_ctrl, -}; - -static const struct v4l2_file_operations vino_fops = { - .owner = THIS_MODULE, - .open = vino_open, - .release = vino_close, - .unlocked_ioctl = vino_ioctl, - .mmap = vino_mmap, - .poll = vino_poll, -}; - -static struct video_device vdev_template = { - .name = "NOT SET", - .fops = &vino_fops, - .ioctl_ops = &vino_ioctl_ops, - .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, -}; - -static void vino_module_cleanup(int stage) -{ - switch(stage) { - case 11: - video_unregister_device(vino_drvdata->b.vdev); - vino_drvdata->b.vdev = NULL; - case 10: - video_unregister_device(vino_drvdata->a.vdev); - vino_drvdata->a.vdev = NULL; - case 9: - i2c_del_adapter(&vino_i2c_adapter); - case 8: - free_irq(SGI_VINO_IRQ, NULL); - case 7: - if (vino_drvdata->b.vdev) { - video_device_release(vino_drvdata->b.vdev); - vino_drvdata->b.vdev = NULL; - } - case 6: - if (vino_drvdata->a.vdev) { - video_device_release(vino_drvdata->a.vdev); - vino_drvdata->a.vdev = NULL; - } - case 5: - /* all entries in dma_cpu dummy table have the same address */ - dma_unmap_single(NULL, - vino_drvdata->dummy_desc_table.dma_cpu[0], - PAGE_SIZE, DMA_FROM_DEVICE); - dma_free_coherent(NULL, VINO_DUMMY_DESC_COUNT - * sizeof(dma_addr_t), - (void *)vino_drvdata-> - dummy_desc_table.dma_cpu, - vino_drvdata->dummy_desc_table.dma); - case 4: - free_page(vino_drvdata->dummy_page); - case 3: - v4l2_device_unregister(&vino_drvdata->v4l2_dev); - case 2: - kfree(vino_drvdata); - case 1: - iounmap(vino); - case 0: - break; - default: - dprintk("vino_module_cleanup(): invalid cleanup stage = %d\n", - stage); - } -} - -static int vino_probe(void) -{ - unsigned long rev_id; - - if (ip22_is_fullhouse()) { - printk(KERN_ERR "VINO doesn't exist in IP22 Fullhouse\n"); - return -ENODEV; - } - - if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) { - printk(KERN_ERR "VINO is not found (EISA BUS not present)\n"); - return -ENODEV; - } - - vino = (struct sgi_vino *)ioremap(VINO_BASE, sizeof(struct sgi_vino)); - if (!vino) { - printk(KERN_ERR "VINO: ioremap() failed\n"); - return -EIO; - } - vino_init_stage++; - - if (get_dbe(rev_id, &(vino->rev_id))) { - printk(KERN_ERR "Failed to read VINO revision register\n"); - vino_module_cleanup(vino_init_stage); - return -ENODEV; - } - - if (VINO_ID_VALUE(rev_id) != VINO_CHIP_ID) { - printk(KERN_ERR "Unknown VINO chip ID (Rev/ID: 0x%02lx)\n", - rev_id); - vino_module_cleanup(vino_init_stage); - return -ENODEV; - } - - printk(KERN_INFO "VINO revision %ld found\n", VINO_REV_NUM(rev_id)); - - return 0; -} - -static int vino_init(void) -{ - dma_addr_t dma_dummy_address; - int err; - int i; - - vino_drvdata = kzalloc(sizeof(struct vino_settings), GFP_KERNEL); - if (!vino_drvdata) { - vino_module_cleanup(vino_init_stage); - return -ENOMEM; - } - vino_init_stage++; - strlcpy(vino_drvdata->v4l2_dev.name, "vino", - sizeof(vino_drvdata->v4l2_dev.name)); - err = v4l2_device_register(NULL, &vino_drvdata->v4l2_dev); - if (err) - return err; - vino_init_stage++; - - /* create a dummy dma descriptor */ - vino_drvdata->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!vino_drvdata->dummy_page) { - vino_module_cleanup(vino_init_stage); - return -ENOMEM; - } - vino_init_stage++; - - // TODO: use page_count in dummy_desc_table - - vino_drvdata->dummy_desc_table.dma_cpu = - dma_alloc_coherent(NULL, - VINO_DUMMY_DESC_COUNT * sizeof(dma_addr_t), - &vino_drvdata->dummy_desc_table.dma, - GFP_KERNEL | GFP_DMA); - if (!vino_drvdata->dummy_desc_table.dma_cpu) { - vino_module_cleanup(vino_init_stage); - return -ENOMEM; - } - vino_init_stage++; - - dma_dummy_address = dma_map_single(NULL, - (void *)vino_drvdata->dummy_page, - PAGE_SIZE, DMA_FROM_DEVICE); - for (i = 0; i < VINO_DUMMY_DESC_COUNT; i++) { - vino_drvdata->dummy_desc_table.dma_cpu[i] = dma_dummy_address; - } - - /* initialize VINO */ - - vino->control = 0; - vino->a.next_4_desc = vino_drvdata->dummy_desc_table.dma; - vino->b.next_4_desc = vino_drvdata->dummy_desc_table.dma; - udelay(VINO_DESC_FETCH_DELAY); - - vino->intr_status = 0; - - vino->a.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT; - vino->b.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT; - - return 0; -} - -static int vino_init_channel_settings(struct vino_channel_settings *vcs, - unsigned int channel, const char *name) -{ - vcs->channel = channel; - vcs->input = VINO_INPUT_NONE; - vcs->alpha = 0; - vcs->users = 0; - vcs->data_format = VINO_DATA_FMT_GREY; - vcs->data_norm = VINO_DATA_NORM_NTSC; - vcs->decimation = 1; - vino_set_default_clipping(vcs); - vino_set_default_framerate(vcs); - - vcs->capturing = 0; - - mutex_init(&vcs->mutex); - spin_lock_init(&vcs->capture_lock); - - mutex_init(&vcs->fb_queue.queue_mutex); - spin_lock_init(&vcs->fb_queue.queue_lock); - init_waitqueue_head(&vcs->fb_queue.frame_wait_queue); - - vcs->vdev = video_device_alloc(); - if (!vcs->vdev) { - vino_module_cleanup(vino_init_stage); - return -ENOMEM; - } - vino_init_stage++; - - memcpy(vcs->vdev, &vdev_template, - sizeof(struct video_device)); - strcpy(vcs->vdev->name, name); - vcs->vdev->release = video_device_release; - vcs->vdev->v4l2_dev = &vino_drvdata->v4l2_dev; - - video_set_drvdata(vcs->vdev, vcs); - - return 0; -} - -static int __init vino_module_init(void) -{ - int ret; - - printk(KERN_INFO "SGI VINO driver version %s\n", - VINO_MODULE_VERSION); - - ret = vino_probe(); - if (ret) - return ret; - - ret = vino_init(); - if (ret) - return ret; - - /* initialize data structures */ - - spin_lock_init(&vino_drvdata->vino_lock); - spin_lock_init(&vino_drvdata->input_lock); - - ret = vino_init_channel_settings(&vino_drvdata->a, VINO_CHANNEL_A, - vino_vdev_name_a); - if (ret) - return ret; - - ret = vino_init_channel_settings(&vino_drvdata->b, VINO_CHANNEL_B, - vino_vdev_name_b); - if (ret) - return ret; - - /* initialize hardware and register V4L devices */ - - ret = request_irq(SGI_VINO_IRQ, vino_interrupt, 0, - vino_driver_description, NULL); - if (ret) { - printk(KERN_ERR "VINO: requesting IRQ %02d failed\n", - SGI_VINO_IRQ); - vino_module_cleanup(vino_init_stage); - return -EAGAIN; - } - vino_init_stage++; - - ret = i2c_add_adapter(&vino_i2c_adapter); - if (ret) { - printk(KERN_ERR "VINO I2C bus registration failed\n"); - vino_module_cleanup(vino_init_stage); - return ret; - } - i2c_set_adapdata(&vino_i2c_adapter, &vino_drvdata->v4l2_dev); - vino_init_stage++; - - ret = video_register_device(vino_drvdata->a.vdev, - VFL_TYPE_GRABBER, -1); - if (ret < 0) { - printk(KERN_ERR "VINO channel A Video4Linux-device " - "registration failed\n"); - vino_module_cleanup(vino_init_stage); - return -EINVAL; - } - vino_init_stage++; - - ret = video_register_device(vino_drvdata->b.vdev, - VFL_TYPE_GRABBER, -1); - if (ret < 0) { - printk(KERN_ERR "VINO channel B Video4Linux-device " - "registration failed\n"); - vino_module_cleanup(vino_init_stage); - return -EINVAL; - } - vino_init_stage++; - - vino_drvdata->decoder = - v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter, - "saa7191", 0, I2C_ADDRS(0x45)); - vino_drvdata->camera = - v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter, - "indycam", 0, I2C_ADDRS(0x2b)); - - dprintk("init complete!\n"); - - return 0; -} - -static void __exit vino_module_exit(void) -{ - dprintk("exiting, stage = %d ...\n", vino_init_stage); - vino_module_cleanup(vino_init_stage); - dprintk("cleanup complete, exit!\n"); -} - -module_init(vino_module_init); -module_exit(vino_module_exit); diff --git a/drivers/staging/media/vino/vino.h b/drivers/staging/media/vino/vino.h deleted file mode 100644 index de2d615ae7c9..000000000000 --- a/drivers/staging/media/vino/vino.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Driver for the VINO (Video In No Out) system found in SGI Indys. - * - * This file is subject to the terms and conditions of the GNU General Public - * License version 2 as published by the Free Software Foundation. - * - * Copyright (C) 1999 Ulf Karlsson - * Copyright (C) 2003 Ladislav Michl - */ - -#ifndef _VINO_H_ -#define _VINO_H_ - -#define VINO_BASE 0x00080000 /* Vino is in the EISA address space, - * but it is not an EISA bus card */ -#define VINO_PAGE_SIZE 4096 - -struct sgi_vino_channel { - u32 _pad_alpha; - volatile u32 alpha; - -#define VINO_CLIP_X(x) ((x) & 0x3ff) /* bits 0:9 */ -#define VINO_CLIP_ODD(x) (((x) & 0x1ff) << 10) /* bits 10:18 */ -#define VINO_CLIP_EVEN(x) (((x) & 0x1ff) << 19) /* bits 19:27 */ - u32 _pad_clip_start; - volatile u32 clip_start; - u32 _pad_clip_end; - volatile u32 clip_end; - -#define VINO_FRAMERT_FULL 0xfff -#define VINO_FRAMERT_PAL (1<<0) /* 0=NTSC 1=PAL */ -#define VINO_FRAMERT_RT(x) (((x) & 0xfff) << 1) /* bits 1:12 */ - u32 _pad_frame_rate; - volatile u32 frame_rate; - - u32 _pad_field_counter; - volatile u32 field_counter; - u32 _pad_line_size; - volatile u32 line_size; - u32 _pad_line_count; - volatile u32 line_count; - u32 _pad_page_index; - volatile u32 page_index; - u32 _pad_next_4_desc; - volatile u32 next_4_desc; - u32 _pad_start_desc_tbl; - volatile u32 start_desc_tbl; - -#define VINO_DESC_JUMP (1<<30) -#define VINO_DESC_STOP (1<<31) -#define VINO_DESC_VALID (1<<32) - u32 _pad_desc_0; - volatile u32 desc_0; - u32 _pad_desc_1; - volatile u32 desc_1; - u32 _pad_desc_2; - volatile u32 desc_2; - u32 _pad_Bdesc_3; - volatile u32 desc_3; - - u32 _pad_fifo_thres; - volatile u32 fifo_thres; - u32 _pad_fifo_read; - volatile u32 fifo_read; - u32 _pad_fifo_write; - volatile u32 fifo_write; -}; - -struct sgi_vino { -#define VINO_CHIP_ID 0xb -#define VINO_REV_NUM(x) ((x) & 0x0f) -#define VINO_ID_VALUE(x) (((x) & 0xf0) >> 4) - u32 _pad_rev_id; - volatile u32 rev_id; - -#define VINO_CTRL_LITTLE_ENDIAN (1<<0) -#define VINO_CTRL_A_EOF_INT (1<<1) /* Field transferred int */ -#define VINO_CTRL_A_FIFO_INT (1<<2) /* FIFO overflow int */ -#define VINO_CTRL_A_EOD_INT (1<<3) /* End of desc table int */ -#define VINO_CTRL_A_INT (VINO_CTRL_A_EOF_INT | \ - VINO_CTRL_A_FIFO_INT | \ - VINO_CTRL_A_EOD_INT) -#define VINO_CTRL_B_EOF_INT (1<<4) /* Field transferred int */ -#define VINO_CTRL_B_FIFO_INT (1<<5) /* FIFO overflow int */ -#define VINO_CTRL_B_EOD_INT (1<<6) /* End of desc table int */ -#define VINO_CTRL_B_INT (VINO_CTRL_B_EOF_INT | \ - VINO_CTRL_B_FIFO_INT | \ - VINO_CTRL_B_EOD_INT) -#define VINO_CTRL_A_DMA_ENBL (1<<7) -#define VINO_CTRL_A_INTERLEAVE_ENBL (1<<8) -#define VINO_CTRL_A_SYNC_ENBL (1<<9) -#define VINO_CTRL_A_SELECT (1<<10) /* 1=D1 0=Philips */ -#define VINO_CTRL_A_RGB (1<<11) /* 1=RGB 0=YUV */ -#define VINO_CTRL_A_LUMA_ONLY (1<<12) -#define VINO_CTRL_A_DEC_ENBL (1<<13) /* Decimation */ -#define VINO_CTRL_A_DEC_SCALE_MASK 0x1c000 /* bits 14:17 */ -#define VINO_CTRL_A_DEC_SCALE_SHIFT (14) -#define VINO_CTRL_A_DEC_HOR_ONLY (1<<17) /* Horizontal only */ -#define VINO_CTRL_A_DITHER (1<<18) /* 24 -> 8 bit dither */ -#define VINO_CTRL_B_DMA_ENBL (1<<19) -#define VINO_CTRL_B_INTERLEAVE_ENBL (1<<20) -#define VINO_CTRL_B_SYNC_ENBL (1<<21) -#define VINO_CTRL_B_SELECT (1<<22) /* 1=D1 0=Philips */ -#define VINO_CTRL_B_RGB (1<<23) /* 1=RGB 0=YUV */ -#define VINO_CTRL_B_LUMA_ONLY (1<<24) -#define VINO_CTRL_B_DEC_ENBL (1<<25) /* Decimation */ -#define VINO_CTRL_B_DEC_SCALE_MASK 0x1c000000 /* bits 26:28 */ -#define VINO_CTRL_B_DEC_SCALE_SHIFT (26) -#define VINO_CTRL_B_DEC_HOR_ONLY (1<<29) /* Decimation horizontal only */ -#define VINO_CTRL_B_DITHER (1<<30) /* ChanB 24 -> 8 bit dither */ - u32 _pad_control; - volatile u32 control; - -#define VINO_INTSTAT_A_EOF (1<<0) /* Field transferred int */ -#define VINO_INTSTAT_A_FIFO (1<<1) /* FIFO overflow int */ -#define VINO_INTSTAT_A_EOD (1<<2) /* End of desc table int */ -#define VINO_INTSTAT_A (VINO_INTSTAT_A_EOF | \ - VINO_INTSTAT_A_FIFO | \ - VINO_INTSTAT_A_EOD) -#define VINO_INTSTAT_B_EOF (1<<3) /* Field transferred int */ -#define VINO_INTSTAT_B_FIFO (1<<4) /* FIFO overflow int */ -#define VINO_INTSTAT_B_EOD (1<<5) /* End of desc table int */ -#define VINO_INTSTAT_B (VINO_INTSTAT_B_EOF | \ - VINO_INTSTAT_B_FIFO | \ - VINO_INTSTAT_B_EOD) - u32 _pad_intr_status; - volatile u32 intr_status; - - u32 _pad_i2c_control; - volatile u32 i2c_control; - u32 _pad_i2c_data; - volatile u32 i2c_data; - - struct sgi_vino_channel a; - struct sgi_vino_channel b; -}; - -#endif diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 093535c6217b..120b70d72d79 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -85,23 +85,20 @@ static struct nvec_chip *nvec_power_handle; static const struct mfd_cell nvec_devices[] = { { .name = "nvec-kbd", - .id = 1, }, { .name = "nvec-mouse", - .id = 1, + }, + { + .name = "nvec-power", + .id = 0, }, { .name = "nvec-power", .id = 1, }, - { - .name = "nvec-power", - .id = 2, - }, { .name = "nvec-paz00", - .id = 1, }, }; @@ -891,7 +888,7 @@ static int tegra_nvec_probe(struct platform_device *pdev) nvec_msg_free(nvec, msg); } - ret = mfd_add_devices(nvec->dev, -1, nvec_devices, + ret = mfd_add_devices(nvec->dev, 0, nvec_devices, ARRAY_SIZE(nvec_devices), NULL, 0, NULL); if (ret) dev_err(nvec->dev, "error adding subdevices\n"); diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c index 82a8c06ab347..c5800ae71fcf 100644 --- a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c @@ -1091,17 +1091,17 @@ static int cfg80211_rtw_get_station(struct wiphy *wiphy, goto exit; } - sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); sinfo->signal = translate_percentage_to_dbm(padapter->recvpriv. signal_strength); - sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); sinfo->txrate.legacy = rtw_get_cur_max_rate(padapter); - sinfo->filled |= STATION_INFO_RX_PACKETS; + sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS); sinfo->rx_packets = sta_rx_data_pkts(psta); - sinfo->filled |= STATION_INFO_TX_PACKETS; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); sinfo->tx_packets = psta->sta_stats.tx_pkts; } @@ -2363,7 +2363,7 @@ void rtw_cfg80211_indicate_sta_assoc(struct rtw_adapter *padapter, ie_offset = offsetof(struct ieee80211_mgmt, u.reassoc_req.variable); - sinfo.filled = STATION_INFO_ASSOC_REQ_IES; + sinfo.filled = 0; sinfo.assoc_req_ies = pmgmt_frame + ie_offset; sinfo.assoc_req_ies_len = frame_len - ie_offset; cfg80211_new_sta(ndev, hdr->addr2, &sinfo, GFP_ATOMIC); diff --git a/drivers/staging/speakup/speakup_dtlk.c b/drivers/staging/speakup/speakup_dtlk.c index 4e059ea78d4c..89592c0b9151 100644 --- a/drivers/staging/speakup/speakup_dtlk.c +++ b/drivers/staging/speakup/speakup_dtlk.c @@ -325,7 +325,7 @@ static struct synth_settings *synth_interrogate(struct spk_synth *synth) static int synth_probe(struct spk_synth *synth) { - unsigned int port_val = 0; + unsigned int port_val = 0; int i = 0; struct synth_settings *sp; @@ -361,7 +361,8 @@ static int synth_probe(struct spk_synth *synth) port_val &= 0xfbff; if (port_val != 0x107f) { pr_info("DoubleTalk PC: not found\n"); - synth_release_region(synth_lpc, SYNTH_IO_EXTENT); + if (synth_lpc) + synth_release_region(synth_lpc, SYNTH_IO_EXTENT); return -ENODEV; } while (inw_p(synth_lpc) != 0x147f) @@ -369,7 +370,7 @@ static int synth_probe(struct spk_synth *synth) sp = synth_interrogate(synth); pr_info("%s: %03x-%03x, ROM ver %s, s/n %u, driver: %s\n", synth->long_name, synth_lpc, synth_lpc+SYNTH_IO_EXTENT - 1, - sp->rom_version, sp->serial_number, synth->version); + sp->rom_version, sp->serial_number, synth->version); synth->alive = 1; return 0; } diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index 8942dcb44180..7c87aecf4744 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c @@ -325,9 +325,9 @@ static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev, if (result == 0) { sinfo->txrate.legacy = quality.txrate.data; - sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); sinfo->signal = quality.level.data; - sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); } return result; diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 1157b559683b..1a1bcf71ec9d 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -784,9 +784,7 @@ static int tcmu_netlink_event(enum tcmu_genl_cmd cmd, const char *name, int mino if (ret < 0) goto free_skb; - ret = genlmsg_end(skb, msg_header); - if (ret < 0) - goto free_skb; + genlmsg_end(skb, msg_header); ret = genlmsg_multicast(&tcmu_genl_family, skb, 0, TCMU_MCGRP_CONFIG, GFP_KERNEL); diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 87e0b0782023..48491d1a81d6 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1759,11 +1759,7 @@ int thermal_generate_netlink_event(struct thermal_zone_device *tz, thermal_event->event = event; /* send multicast genetlink message */ - result = genlmsg_end(skb, msg_header); - if (result < 0) { - nlmsg_free(skb); - return result; - } + genlmsg_end(skb, msg_header); result = genlmsg_multicast(&thermal_event_genl_family, skb, 0, 0, GFP_ATOMIC); diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index ea74460f3638..f78a87b07872 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -1,10 +1,10 @@ /* - * hvc_iucv.c - z/VM IUCV hypervisor console (HVC) device driver + * z/VM IUCV hypervisor console (HVC) device driver * * This HVC device driver provides terminal access using * z/VM IUCV communication paths. * - * Copyright IBM Corp. 2008, 2009 + * Copyright IBM Corp. 2008, 2013 * * Author(s): Hendrik Brueckner */ @@ -102,6 +102,7 @@ static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; #define IUCV_HVC_CON_IDX (0) /* List of z/VM user ID filter entries (struct iucv_vmid_filter) */ #define MAX_VMID_FILTER (500) +#define FILTER_WILDCARD_CHAR '*' static size_t hvc_iucv_filter_size; static void *hvc_iucv_filter; static const char *hvc_iucv_filter_string; @@ -734,20 +735,31 @@ static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id) * hvc_iucv_filter_connreq() - Filter connection request based on z/VM user ID * @ipvmid: Originating z/VM user ID (right padded with blanks) * - * Returns 0 if the z/VM user ID @ipvmid is allowed to connection, otherwise - * non-zero. + * Returns 0 if the z/VM user ID that is specified with @ipvmid is permitted to + * connect, otherwise non-zero. */ static int hvc_iucv_filter_connreq(u8 ipvmid[8]) { - size_t i; + const char *wildcard, *filter_entry; + size_t i, len; /* Note: default policy is ACCEPT if no filter is set */ if (!hvc_iucv_filter_size) return 0; - for (i = 0; i < hvc_iucv_filter_size; i++) - if (0 == memcmp(ipvmid, hvc_iucv_filter + (8 * i), 8)) + for (i = 0; i < hvc_iucv_filter_size; i++) { + filter_entry = hvc_iucv_filter + (8 * i); + + /* If a filter entry contains the filter wildcard character, + * reduce the length to match the leading portion of the user + * ID only (wildcard match). Characters following the wildcard + * are ignored. + */ + wildcard = strnchr(filter_entry, 8, FILTER_WILDCARD_CHAR); + len = (wildcard) ? wildcard - filter_entry : 8; + if (0 == memcmp(ipvmid, filter_entry, len)) return 0; + } return 1; } @@ -1166,6 +1178,7 @@ static void __init hvc_iucv_destroy(struct hvc_iucv_private *priv) /** * hvc_iucv_parse_filter() - Parse filter for a single z/VM user ID * @filter: String containing a comma-separated list of z/VM user IDs + * @dest: Location where to store the parsed z/VM user ID */ static const char *hvc_iucv_parse_filter(const char *filter, char *dest) { @@ -1188,6 +1201,10 @@ static const char *hvc_iucv_parse_filter(const char *filter, char *dest) if (filter[len - 1] == '\n') len--; + /* prohibit filter entries containing the wildcard character only */ + if (len == 1 && *filter == FILTER_WILDCARD_CHAR) + return ERR_PTR(-EINVAL); + if (len > 8) return ERR_PTR(-EINVAL); diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 42bad18c66c9..259a4d5a4e8f 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -90,7 +90,7 @@ static void sysrq_handle_loglevel(int key) i = key - '0'; console_loglevel = CONSOLE_LOGLEVEL_DEFAULT; - printk("Loglevel set to %d\n", i); + pr_info("Loglevel set to %d\n", i); console_loglevel = i; } static struct sysrq_key_op sysrq_loglevel_op = { @@ -220,7 +220,7 @@ static void showacpu(void *dummy) return; spin_lock_irqsave(&show_lock, flags); - printk(KERN_INFO "CPU%d:\n", smp_processor_id()); + pr_info("CPU%d:\n", smp_processor_id()); show_stack(NULL, NULL); spin_unlock_irqrestore(&show_lock, flags); } @@ -243,7 +243,7 @@ static void sysrq_handle_showallcpus(int key) struct pt_regs *regs = get_irq_regs(); if (regs) { - printk(KERN_INFO "CPU%d:\n", smp_processor_id()); + pr_info("CPU%d:\n", smp_processor_id()); show_regs(regs); } schedule_work(&sysrq_showallcpus); @@ -355,8 +355,9 @@ static struct sysrq_key_op sysrq_term_op = { static void moom_callback(struct work_struct *ignored) { - out_of_memory(node_zonelist(first_memory_node, GFP_KERNEL), GFP_KERNEL, - 0, NULL, true); + if (!out_of_memory(node_zonelist(first_memory_node, GFP_KERNEL), + GFP_KERNEL, 0, NULL, true)) + pr_info("OOM request ignored because killer is disabled\n"); } static DECLARE_WORK(moom_work, moom_callback); @@ -522,7 +523,7 @@ void __handle_sysrq(int key, bool check_mask) */ orig_log_level = console_loglevel; console_loglevel = CONSOLE_LOGLEVEL_DEFAULT; - printk(KERN_INFO "SysRq : "); + pr_info("SysRq : "); op_p = __sysrq_get_key_op(key); if (op_p) { @@ -531,14 +532,14 @@ void __handle_sysrq(int key, bool check_mask) * should not) and is the invoked operation enabled? */ if (!check_mask || sysrq_on_mask(op_p->enable_mask)) { - printk("%s\n", op_p->action_msg); + pr_cont("%s\n", op_p->action_msg); console_loglevel = orig_log_level; op_p->handler(key); } else { - printk("This sysrq operation is disabled.\n"); + pr_cont("This sysrq operation is disabled.\n"); } } else { - printk("HELP : "); + pr_cont("HELP : "); /* Only print the help msg once per handler */ for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) { if (sysrq_key_table[i]) { @@ -549,10 +550,10 @@ void __handle_sysrq(int key, bool check_mask) ; if (j != i) continue; - printk("%s ", sysrq_key_table[i]->help_msg); + pr_cont("%s ", sysrq_key_table[i]->help_msg); } } - printk("\n"); + pr_cont("\n"); console_loglevel = orig_log_level; } rcu_read_unlock(); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index aeb50bb6ba9c..eaffb0248de1 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3452,8 +3452,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) return status; } -#ifdef CONFIG_PM - int usb_remote_wakeup(struct usb_device *udev) { int status = 0; @@ -3512,16 +3510,6 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, return connect_change; } -#else - -static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, - u16 portstatus, u16 portchange) -{ - return 0; -} - -#endif - static int check_ports_changed(struct usb_hub *hub) { int port1; diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h index de0c9c9d7091..a6315abe7b7c 100644 --- a/drivers/usb/core/otg_whitelist.h +++ b/drivers/usb/core/otg_whitelist.h @@ -55,6 +55,11 @@ static int is_targeted(struct usb_device *dev) le16_to_cpu(dev->descriptor.idProduct) == 0xbadd)) return 0; + /* OTG PET device is always targeted (see OTG 2.0 ECN 6.4.2) */ + if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a && + le16_to_cpu(dev->descriptor.idProduct) == 0x0200)) + return 1; + /* NOTE: can't use usb_match_id() since interface caches * aren't set up yet. this is cut/paste from that code. */ diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 0ffb4ed0a945..41e510ae8c83 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -179,6 +179,10 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0b05, 0x17e0), .driver_info = USB_QUIRK_IGNORE_REMOTE_WAKEUP }, + /* Protocol and OTG Electrical Test Device */ + { USB_DEVICE(0x1a0a, 0x0200), .driver_info = + USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + { } /* terminating entry must be last */ }; diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index ad43c5bc1ef1..02e3e2d4ea56 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -476,13 +476,13 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev) u32 gintsts; irqreturn_t retval = IRQ_NONE; + spin_lock(&hsotg->lock); + if (!dwc2_is_controller_alive(hsotg)) { dev_warn(hsotg->dev, "Controller is dead\n"); goto out; } - spin_lock(&hsotg->lock); - gintsts = dwc2_read_common_intr(hsotg); if (gintsts & ~GINTSTS_PRTINT) retval = IRQ_HANDLED; @@ -515,8 +515,8 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev) } } - spin_unlock(&hsotg->lock); out: + spin_unlock(&hsotg->lock); return retval; } EXPORT_SYMBOL_GPL(dwc2_handle_common_intr); diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index 1eac56fc384d..dd3e9fd31b80 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -2131,8 +2131,8 @@ static int xudc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, udc); - dev_vdbg(&pdev->dev, "%s at 0x%08X mapped to 0x%08X %s\n", - driver_name, (u32)res->start, (u32 __force)udc->addr, + dev_vdbg(&pdev->dev, "%s at 0x%08X mapped to %p %s\n", + driver_name, (u32)res->start, udc->addr, udc->dma_enabled ? "with DMA" : "without DMA"); return 0; diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index ccfdfb24b240..2f9735b35338 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -34,7 +34,7 @@ static struct usb_phy *__usb_find_phy(struct list_head *list, return phy; } - return ERR_PTR(-EPROBE_DEFER); + return ERR_PTR(-ENODEV); } static struct usb_phy *__usb_find_phy_dev(struct device *dev, diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 11c7a9676441..d684b4b8108f 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -507,7 +507,7 @@ UNUSUAL_DEV( 0x04e6, 0x000c, 0x0100, 0x0100, UNUSUAL_DEV( 0x04e6, 0x000f, 0x0000, 0x9999, "SCM Microsystems", "eUSB SCSI Adapter (Bus Powered)", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init, + USB_SC_SCSI, USB_PR_BULK, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG ), UNUSUAL_DEV( 0x04e6, 0x0101, 0x0200, 0x0200, @@ -1995,6 +1995,13 @@ UNUSUAL_DEV( 0x152d, 0x2329, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ), +/* Reported by Dmitry Nezhevenko */ +UNUSUAL_DEV( 0x152d, 0x2566, 0x0114, 0x0114, + "JMicron", + "USB to ATA/ATAPI Bridge", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BROKEN_FUA ), + /* Entrega Technologies U1-SC25 (later Xircom PortGear PGSCSI) * and Mac USB Dock USB-SCSI */ UNUSUAL_DEV( 0x1645, 0x0007, 0x0100, 0x0133, diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index 6df4357d9ee3..dbc00e56c7f5 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -140,3 +140,10 @@ UNUSUAL_DEV(0x4971, 0x1012, 0x0000, 0x9999, "External HDD", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_UAS), + +/* Reported-by: Richard Henderson */ +UNUSUAL_DEV(0x4971, 0x8017, 0x0000, 0x9999, + "SimpleTech", + "External HDD", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_REPORT_OPCODES), diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index d415d69dc237..8dccca9013ed 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -84,10 +84,6 @@ struct vhost_net_ubuf_ref { struct vhost_net_virtqueue { struct vhost_virtqueue vq; - /* hdr is used to store the virtio header. - * Since each iovec has >= 1 byte length, we never need more than - * header length entries to store the header. */ - struct iovec hdr[sizeof(struct virtio_net_hdr_mrg_rxbuf)]; size_t vhost_hlen; size_t sock_hlen; /* vhost zerocopy support fields below: */ @@ -235,44 +231,6 @@ static bool vhost_sock_zcopy(struct socket *sock) sock_flag(sock->sk, SOCK_ZEROCOPY); } -/* Pop first len bytes from iovec. Return number of segments used. */ -static int move_iovec_hdr(struct iovec *from, struct iovec *to, - size_t len, int iov_count) -{ - int seg = 0; - size_t size; - - while (len && seg < iov_count) { - size = min(from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - from->iov_len -= size; - from->iov_base += size; - len -= size; - ++from; - ++to; - ++seg; - } - return seg; -} -/* Copy iovec entries for len bytes from iovec. */ -static void copy_iovec_hdr(const struct iovec *from, struct iovec *to, - size_t len, int iovcount) -{ - int seg = 0; - size_t size; - - while (len && seg < iovcount) { - size = min(from->iov_len, len); - to->iov_base = from->iov_base; - to->iov_len = size; - len -= size; - ++from; - ++to; - ++seg; - } -} - /* In case of DMA done not in order in lower device driver for some reason. * upend_idx is used to track end of used idx, done_idx is used to track head * of used idx. Once lower device DMA done contiguously, we will signal KVM @@ -336,7 +294,7 @@ static void handle_tx(struct vhost_net *net) { struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX]; struct vhost_virtqueue *vq = &nvq->vq; - unsigned out, in, s; + unsigned out, in; int head; struct msghdr msg = { .msg_name = NULL, @@ -395,16 +353,17 @@ static void handle_tx(struct vhost_net *net) break; } /* Skip header. TODO: support TSO. */ - s = move_iovec_hdr(vq->iov, nvq->hdr, hdr_size, out); len = iov_length(vq->iov, out); iov_iter_init(&msg.msg_iter, WRITE, vq->iov, out, len); + iov_iter_advance(&msg.msg_iter, hdr_size); /* Sanity check */ - if (!len) { + if (!iov_iter_count(&msg.msg_iter)) { vq_err(vq, "Unexpected header len for TX: " "%zd expected %zd\n", - iov_length(nvq->hdr, s), hdr_size); + len, hdr_size); break; } + len = iov_iter_count(&msg.msg_iter); zcopy_used = zcopy && len >= VHOST_GOODCOPY_LEN && (nvq->upend_idx + 1) % UIO_MAXIOV != @@ -469,7 +428,7 @@ static int peek_head_len(struct sock *sk) head = skb_peek(&sk->sk_receive_queue); if (likely(head)) { len = head->len; - if (vlan_tx_tag_present(head)) + if (skb_vlan_tag_present(head)) len += VLAN_HLEN; } @@ -579,6 +538,7 @@ static void handle_rx(struct vhost_net *net) size_t vhost_hlen, sock_hlen; size_t vhost_len, sock_len; struct socket *sock; + struct iov_iter fixup; mutex_lock(&vq->mutex); sock = vq->private_data; @@ -623,14 +583,19 @@ static void handle_rx(struct vhost_net *net) break; } /* We don't need to be notified again. */ - if (unlikely((vhost_hlen))) - /* Skip header. TODO: support TSO. */ - move_iovec_hdr(vq->iov, nvq->hdr, vhost_hlen, in); - else - /* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF: - * needed because recvmsg can modify msg_iov. */ - copy_iovec_hdr(vq->iov, nvq->hdr, sock_hlen, in); - iov_iter_init(&msg.msg_iter, READ, vq->iov, in, sock_len); + iov_iter_init(&msg.msg_iter, READ, vq->iov, in, vhost_len); + fixup = msg.msg_iter; + if (unlikely((vhost_hlen))) { + /* We will supply the header ourselves + * TODO: support TSO. + */ + iov_iter_advance(&msg.msg_iter, vhost_hlen); + } else { + /* It'll come from socket; we'll need to patch + * ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF + */ + iov_iter_advance(&fixup, sizeof(hdr)); + } err = sock->ops->recvmsg(NULL, sock, &msg, sock_len, MSG_DONTWAIT | MSG_TRUNC); /* Userspace might have consumed the packet meanwhile: @@ -642,18 +607,18 @@ static void handle_rx(struct vhost_net *net) vhost_discard_vq_desc(vq, headcount); continue; } + /* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */ if (unlikely(vhost_hlen) && - memcpy_toiovecend(nvq->hdr, (unsigned char *)&hdr, 0, - vhost_hlen)) { + copy_to_iter(&hdr, sizeof(hdr), &fixup) != sizeof(hdr)) { vq_err(vq, "Unable to write vnet_hdr at addr %p\n", vq->iov->iov_base); break; } /* TODO: Should check and handle checksum. */ + + hdr.num_buffers = cpu_to_vhost16(vq, headcount); if (likely(mergeable) && - memcpy_toiovecend(nvq->hdr, (unsigned char *)&headcount, - offsetof(typeof(hdr), num_buffers), - sizeof hdr.num_buffers)) { + copy_to_iter(&hdr.num_buffers, 2, &fixup) != 2) { vq_err(vq, "Failed num_buffers write"); vhost_discard_vq_desc(vq, headcount); break; diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index d695b1673ae5..dc78d87e0fc2 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1079,7 +1079,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) req_size, vq->iov[0].iov_len); break; } - ret = memcpy_fromiovecend(req, &vq->iov[0], 0, req_size); + ret = copy_from_user(req, vq->iov[0].iov_base, req_size); if (unlikely(ret)) { vq_err(vq, "Faulted on virtio_scsi_cmd_req\n"); break; diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index cb807d0ea498..2ee28266fd07 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1125,6 +1125,7 @@ static int get_indirect(struct vhost_virtqueue *vq, struct vring_desc desc; unsigned int i = 0, count, found = 0; u32 len = vhost32_to_cpu(vq, indirect->len); + struct iov_iter from; int ret; /* Sanity check */ @@ -1142,6 +1143,7 @@ static int get_indirect(struct vhost_virtqueue *vq, vq_err(vq, "Translation failure %d in indirect.\n", ret); return ret; } + iov_iter_init(&from, READ, vq->indirect, ret, len); /* We will use the result as an address to read from, so most * architectures only need a compiler barrier here. */ @@ -1164,8 +1166,8 @@ static int get_indirect(struct vhost_virtqueue *vq, i, count); return -EINVAL; } - if (unlikely(memcpy_fromiovec((unsigned char *)&desc, - vq->indirect, sizeof desc))) { + if (unlikely(copy_from_iter(&desc, sizeof(desc), &from) != + sizeof(desc))) { vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n", i, (size_t)vhost64_to_cpu(vq, indirect->addr) + i * sizeof desc); return -EINVAL; diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index fe1cd0148e13..ba97efc3bf70 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -77,18 +77,22 @@ config DUMMY_CONSOLE config DUMMY_CONSOLE_COLUMNS int "Initial number of console screen columns" - depends on PARISC && DUMMY_CONSOLE - default "160" + depends on DUMMY_CONSOLE && !ARM + default 160 if PARISC + default 80 help - The default value is 160, which should fit a 1280x1024 monitor. + On PA-RISC, the default value is 160, which should fit a 1280x1024 + monitor. Select 80 if you use a 640x480 resolution by default. config DUMMY_CONSOLE_ROWS int "Initial number of console screen rows" - depends on PARISC && DUMMY_CONSOLE - default "64" + depends on DUMMY_CONSOLE && !ARM + default 64 if PARISC + default 25 help - The default value is 64, which should fit a 1280x1024 monitor. + On PA-RISC, the default value is 64, which should fit a 1280x1024 + monitor. Select 25 if you use a 640x480 resolution by default. config FRAMEBUFFER_CONSOLE diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 40bec8d64b0a..0efc52f11ad0 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -20,13 +20,10 @@ #if defined(__arm__) #define DUMMY_COLUMNS screen_info.orig_video_cols #define DUMMY_ROWS screen_info.orig_video_lines -#elif defined(__hppa__) +#else /* set by Kconfig. Use 80x25 for 640x480 and 160x64 for 1280x1024 */ #define DUMMY_COLUMNS CONFIG_DUMMY_CONSOLE_COLUMNS #define DUMMY_ROWS CONFIG_DUMMY_CONSOLE_ROWS -#else -#define DUMMY_COLUMNS 80 -#define DUMMY_ROWS 25 #endif static const char *dummycon_startup(void) diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index ea437245562e..b97210671a81 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -146,9 +146,6 @@ static const struct consw fb_con; static int fbcon_set_origin(struct vc_data *); -#define CURSOR_DRAW_DELAY (1) - -static int vbl_cursor_cnt; static int fbcon_cursor_noblink; #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) @@ -1329,7 +1326,6 @@ static void fbcon_cursor(struct vc_data *vc, int mode) ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1), get_color(vc, info, c, 0)); - vbl_cursor_cnt = CURSOR_DRAW_DELAY; } static int scrollback_phys_max = 0; diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 4916c97216f8..b3dd417b4719 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1530,13 +1530,11 @@ config FB_SIS_315 config FB_VIA tristate "VIA UniChrome (Pro) and Chrome9 display support" - depends on FB && PCI && X86 + depends on FB && PCI && X86 && GPIOLIB && I2C select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select I2C_ALGOBIT - select I2C - select GPIOLIB help This is the frame buffer device driver for Graphics chips of VIA UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/ @@ -2151,7 +2149,6 @@ config FB_PS3 select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT select FB_SYS_FOPS - select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE ---help--- Include support for the virtual frame buffer in the PS3 platform. diff --git a/drivers/video/fbdev/atafb.c b/drivers/video/fbdev/atafb.c index 4953b657635e..cb9ee2556850 100644 --- a/drivers/video/fbdev/atafb.c +++ b/drivers/video/fbdev/atafb.c @@ -3118,8 +3118,7 @@ int __init atafb_init(void) printk("atafb_init: initializing Falcon hw\n"); fbhw = &falcon_switch; atafb_ops.fb_setcolreg = &falcon_setcolreg; - error = request_irq(IRQ_AUTO_4, falcon_vbl_switcher, - IRQ_TYPE_PRIO, + error = request_irq(IRQ_AUTO_4, falcon_vbl_switcher, 0, "framebuffer:modeswitch", falcon_vbl_switcher); if (error) diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index 37ec09b3fffd..8789e487b96e 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -3948,7 +3948,7 @@ static struct notifier_block atyfb_reboot_notifier = { .notifier_call = atyfb_reboot_notify, }; -static const struct dmi_system_id atyfb_reboot_ids[] = { +static const struct dmi_system_id atyfb_reboot_ids[] __initconst = { { .ident = "HP OmniBook 500", .matches = { @@ -3960,6 +3960,7 @@ static const struct dmi_system_id atyfb_reboot_ids[] = { { } }; +static bool registered_notifier = false; static int __init atyfb_init(void) { @@ -3982,15 +3983,17 @@ static int __init atyfb_init(void) if (err1 && err2) return -ENODEV; - if (dmi_check_system(atyfb_reboot_ids)) + if (dmi_check_system(atyfb_reboot_ids)) { register_reboot_notifier(&atyfb_reboot_notifier); + registered_notifier = true; + } return 0; } static void __exit atyfb_exit(void) { - if (dmi_check_system(atyfb_reboot_ids)) + if (registered_notifier) unregister_reboot_notifier(&atyfb_reboot_notifier); #ifdef CONFIG_PCI diff --git a/drivers/video/fbdev/core/fbcvt.c b/drivers/video/fbdev/core/fbcvt.c index 7cb715dfc0e1..55d2bd0ce5c0 100644 --- a/drivers/video/fbdev/core/fbcvt.c +++ b/drivers/video/fbdev/core/fbcvt.c @@ -369,9 +369,9 @@ int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb) cvt.h_back_porch = cvt.hblank/2 + cvt.h_margin; cvt.h_front_porch = cvt.hblank - cvt.hsync - cvt.h_back_porch + 2 * cvt.h_margin; - cvt.v_back_porch = 3 + cvt.v_margin; - cvt.v_front_porch = cvt.vtotal - cvt.yres/cvt.interlace - - cvt.v_back_porch - cvt.vsync; + cvt.v_front_porch = 3 + cvt.v_margin; + cvt.v_back_porch = cvt.vtotal - cvt.yres/cvt.interlace - + cvt.v_front_porch - cvt.vsync; fb_cvt_print_name(&cvt); fb_cvt_convert_to_mode(&cvt, mode); diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c index 5b0e313849bd..95338593ebf4 100644 --- a/drivers/video/fbdev/core/fbmon.c +++ b/drivers/video/fbdev/core/fbmon.c @@ -496,56 +496,71 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode) } static int get_std_timing(unsigned char *block, struct fb_videomode *mode, - int ver, int rev) + int ver, int rev, const struct fb_monspecs *specs) { - int xres, yres = 0, refresh, ratio, i; + int i; - xres = (block[0] + 31) * 8; - if (xres <= 256) - return 0; - - ratio = (block[1] & 0xc0) >> 6; - switch (ratio) { - case 0: - /* in EDID 1.3 the meaning of 0 changed to 16:10 (prior 1:1) */ - if (ver < 1 || (ver == 1 && rev < 3)) - yres = xres; - else - yres = (xres * 10)/16; - break; - case 1: - yres = (xres * 3)/4; - break; - case 2: - yres = (xres * 4)/5; - break; - case 3: - yres = (xres * 9)/16; - break; + for (i = 0; i < DMT_SIZE; i++) { + u32 std_2byte_code = block[0] << 8 | block[1]; + if (std_2byte_code == dmt_modes[i].std_2byte_code) + break; } - refresh = (block[1] & 0x3f) + 60; - DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh); - for (i = 0; i < VESA_MODEDB_SIZE; i++) { - if (vesa_modes[i].xres == xres && - vesa_modes[i].yres == yres && - vesa_modes[i].refresh == refresh) { - *mode = vesa_modes[i]; - mode->flag |= FB_MODE_IS_STANDARD; - return 1; + if (i < DMT_SIZE && dmt_modes[i].mode) { + /* DMT mode found */ + *mode = *dmt_modes[i].mode; + mode->flag |= FB_MODE_IS_STANDARD; + DPRINTK(" DMT id=%d\n", dmt_modes[i].dmt_id); + + } else { + int xres, yres = 0, refresh, ratio; + + xres = (block[0] + 31) * 8; + if (xres <= 256) + return 0; + + ratio = (block[1] & 0xc0) >> 6; + switch (ratio) { + case 0: + /* in EDID 1.3 the meaning of 0 changed to 16:10 (prior 1:1) */ + if (ver < 1 || (ver == 1 && rev < 3)) + yres = xres; + else + yres = (xres * 10)/16; + break; + case 1: + yres = (xres * 3)/4; + break; + case 2: + yres = (xres * 4)/5; + break; + case 3: + yres = (xres * 9)/16; + break; } + refresh = (block[1] & 0x3f) + 60; + DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh); + + calc_mode_timings(xres, yres, refresh, mode); } - calc_mode_timings(xres, yres, refresh, mode); + + /* Check the mode we got is within valid spec of the monitor */ + if (specs && specs->dclkmax + && PICOS2KHZ(mode->pixclock) * 1000 > specs->dclkmax) { + DPRINTK(" mode exceed max DCLK\n"); + return 0; + } + return 1; } -static int get_dst_timing(unsigned char *block, - struct fb_videomode *mode, int ver, int rev) +static int get_dst_timing(unsigned char *block, struct fb_videomode *mode, + int ver, int rev, const struct fb_monspecs *specs) { int j, num = 0; for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE) - num += get_std_timing(block, &mode[num], ver, rev); + num += get_std_timing(block, &mode[num], ver, rev, specs); return num; } @@ -601,7 +616,8 @@ static void get_detailed_timing(unsigned char *block, * This function builds a mode database using the contents of the EDID * data */ -static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) +static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize, + const struct fb_monspecs *specs) { struct fb_videomode *mode, *m; unsigned char *block; @@ -643,12 +659,13 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) DPRINTK(" Standard Timings\n"); block = edid + STD_TIMING_DESCRIPTIONS_START; for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) - num += get_std_timing(block, &mode[num], ver, rev); + num += get_std_timing(block, &mode[num], ver, rev, specs); block = edid + DETAILED_TIMING_DESCRIPTIONS_START; for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa) - num += get_dst_timing(block + 5, &mode[num], ver, rev); + num += get_dst_timing(block + 5, &mode[num], + ver, rev, specs); } /* Yikes, EDID data is totally useless */ @@ -707,7 +724,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) int num_modes, hz, hscan, pixclock; int vtotal, htotal; - modes = fb_create_modedb(edid, &num_modes); + modes = fb_create_modedb(edid, &num_modes, specs); if (!modes) { DPRINTK("None Available\n"); return 1; @@ -964,7 +981,7 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) DPRINTK(" Display Characteristics:\n"); get_monspecs(edid, specs); - specs->modedb = fb_create_modedb(edid, &specs->modedb_len); + specs->modedb = fb_create_modedb(edid, &specs->modedb_len, specs); /* * Workaround for buggy EDIDs that sets that the first diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c index 388f7971494b..7d07cf824b64 100644 --- a/drivers/video/fbdev/core/modedb.c +++ b/drivers/video/fbdev/core/modedb.c @@ -468,8 +468,119 @@ const struct fb_videomode vesa_modes[] = { /* 33 1920x1440-75 VESA */ { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 34 1920x1200-60 RB VESA */ + { NULL, 60, 1920, 1200, 6493, 80, 48, 26, 3, 32, 6, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 35 1920x1200-60 VESA */ + { NULL, 60, 1920, 1200, 5174, 336, 136, 36, 3, 200, 6, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 36 1920x1200-75 VESA */ + { NULL, 75, 1920, 1200, 4077, 344, 136, 46, 3, 208, 6, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 37 1920x1200-85 VESA */ + { NULL, 85, 1920, 1200, 3555, 352, 144, 53, 3, 208, 6, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 38 2560x1600-60 RB VESA */ + { NULL, 60, 2560, 1600, 3724, 80, 48, 37, 3, 32, 6, + FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 39 2560x1600-60 VESA */ + { NULL, 60, 2560, 1600, 2869, 472, 192, 49, 3, 280, 6, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 40 2560x1600-75 VESA */ + { NULL, 75, 2560, 1600, 2256, 488, 208, 63, 3, 280, 6, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 41 2560x1600-85 VESA */ + { NULL, 85, 2560, 1600, 1979, 488, 208, 73, 3, 280, 6, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 42 2560x1600-120 RB VESA */ + { NULL, 120, 2560, 1600, 1809, 80, 48, 85, 3, 32, 6, + FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, }; EXPORT_SYMBOL(vesa_modes); + +const struct dmt_videomode dmt_modes[DMT_SIZE] = { + { 0x01, 0x0000, 0x000000, &vesa_modes[0] }, + { 0x02, 0x3119, 0x000000, &vesa_modes[1] }, + { 0x03, 0x0000, 0x000000, &vesa_modes[2] }, + { 0x04, 0x3140, 0x000000, &vesa_modes[3] }, + { 0x05, 0x314c, 0x000000, &vesa_modes[4] }, + { 0x06, 0x314f, 0x000000, &vesa_modes[5] }, + { 0x07, 0x3159, 0x000000, &vesa_modes[6] }, + { 0x08, 0x0000, 0x000000, &vesa_modes[7] }, + { 0x09, 0x4540, 0x000000, &vesa_modes[8] }, + { 0x0a, 0x454c, 0x000000, &vesa_modes[9] }, + { 0x0b, 0x454f, 0x000000, &vesa_modes[10] }, + { 0x0c, 0x4559, 0x000000, &vesa_modes[11] }, + { 0x0d, 0x0000, 0x000000, NULL }, + { 0x0e, 0x0000, 0x000000, NULL }, + { 0x0f, 0x0000, 0x000000, &vesa_modes[12] }, + { 0x10, 0x6140, 0x000000, &vesa_modes[13] }, + { 0x11, 0x614a, 0x000000, &vesa_modes[14] }, + { 0x12, 0x614f, 0x000000, &vesa_modes[15] }, + { 0x13, 0x6159, 0x000000, &vesa_modes[16] }, + { 0x14, 0x0000, 0x000000, NULL }, + { 0x15, 0x714f, 0x000000, &vesa_modes[17] }, + { 0x16, 0x0000, 0x7f1c21, NULL }, + { 0x17, 0x0000, 0x7f1c28, NULL }, + { 0x18, 0x0000, 0x7f1c44, NULL }, + { 0x19, 0x0000, 0x7f1c62, NULL }, + { 0x1a, 0x0000, 0x000000, NULL }, + { 0x1b, 0x0000, 0x8f1821, NULL }, + { 0x1c, 0x8100, 0x8f1828, NULL }, + { 0x1d, 0x810f, 0x8f1844, NULL }, + { 0x1e, 0x8119, 0x8f1862, NULL }, + { 0x1f, 0x0000, 0x000000, NULL }, + { 0x20, 0x8140, 0x000000, &vesa_modes[18] }, + { 0x21, 0x8159, 0x000000, &vesa_modes[19] }, + { 0x22, 0x0000, 0x000000, NULL }, + { 0x23, 0x8180, 0x000000, &vesa_modes[20] }, + { 0x24, 0x818f, 0x000000, &vesa_modes[21] }, + { 0x25, 0x8199, 0x000000, &vesa_modes[22] }, + { 0x26, 0x0000, 0x000000, NULL }, + { 0x27, 0x0000, 0x000000, NULL }, + { 0x28, 0x0000, 0x000000, NULL }, + { 0x29, 0x0000, 0x0c2021, NULL }, + { 0x2a, 0x9040, 0x0c2028, NULL }, + { 0x2b, 0x904f, 0x0c2044, NULL }, + { 0x2c, 0x9059, 0x0c2062, NULL }, + { 0x2d, 0x0000, 0x000000, NULL }, + { 0x2e, 0x9500, 0xc11821, NULL }, + { 0x2f, 0x9500, 0xc11828, NULL }, + { 0x30, 0x950f, 0xc11844, NULL }, + { 0x31, 0x9519, 0xc11868, NULL }, + { 0x32, 0x0000, 0x000000, NULL }, + { 0x33, 0xa940, 0x000000, &vesa_modes[23] }, + { 0x34, 0xa945, 0x000000, &vesa_modes[24] }, + { 0x35, 0xa94a, 0x000000, &vesa_modes[25] }, + { 0x36, 0xa94f, 0x000000, &vesa_modes[26] }, + { 0x37, 0xa959, 0x000000, &vesa_modes[27] }, + { 0x38, 0x0000, 0x000000, NULL }, + { 0x39, 0x0000, 0x0c2821, NULL }, + { 0x3a, 0xb300, 0x0c2828, NULL }, + { 0x3b, 0xb30f, 0x0c2844, NULL }, + { 0x3c, 0xb319, 0x0c2868, NULL }, + { 0x3d, 0x0000, 0x000000, NULL }, + { 0x3e, 0xc140, 0x000000, &vesa_modes[28] }, + { 0x3f, 0xc14f, 0x000000, &vesa_modes[29] }, + { 0x40, 0x0000, 0x000000, NULL}, + { 0x41, 0xc940, 0x000000, &vesa_modes[30] }, + { 0x42, 0xc94f, 0x000000, &vesa_modes[31] }, + { 0x43, 0x0000, 0x000000, NULL }, + { 0x44, 0x0000, 0x572821, &vesa_modes[34] }, + { 0x45, 0xd100, 0x572828, &vesa_modes[35] }, + { 0x46, 0xd10f, 0x572844, &vesa_modes[36] }, + { 0x47, 0xd119, 0x572862, &vesa_modes[37] }, + { 0x48, 0x0000, 0x000000, NULL }, + { 0x49, 0xd140, 0x000000, &vesa_modes[32] }, + { 0x4a, 0xd14f, 0x000000, &vesa_modes[33] }, + { 0x4b, 0x0000, 0x000000, NULL }, + { 0x4c, 0x0000, 0x1f3821, &vesa_modes[38] }, + { 0x4d, 0x0000, 0x1f3828, &vesa_modes[39] }, + { 0x4e, 0x0000, 0x1f3844, &vesa_modes[40] }, + { 0x4f, 0x0000, 0x1f3862, &vesa_modes[41] }, + { 0x50, 0x0000, 0x000000, &vesa_modes[42] }, +}; +EXPORT_SYMBOL(dmt_modes); #endif /* CONFIG_FB_MODE_HELPERS */ /** diff --git a/drivers/video/fbdev/core/syscopyarea.c b/drivers/video/fbdev/core/syscopyarea.c index 844a32fd38ed..c1eda3190968 100644 --- a/drivers/video/fbdev/core/syscopyarea.c +++ b/drivers/video/fbdev/core/syscopyarea.c @@ -25,8 +25,8 @@ */ static void -bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, - const unsigned long *src, int src_idx, int bits, unsigned n) +bitcpy(struct fb_info *p, unsigned long *dst, unsigned dst_idx, + const unsigned long *src, unsigned src_idx, int bits, unsigned n) { unsigned long first, last; int const shift = dst_idx-src_idx; @@ -86,15 +86,15 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, first &= last; if (shift > 0) { /* Single source word */ - *dst = comp(*src >> right, *dst, first); + *dst = comp(*src << left, *dst, first); } else if (src_idx+n <= bits) { /* Single source word */ - *dst = comp(*src << left, *dst, first); + *dst = comp(*src >> right, *dst, first); } else { /* 2 source words */ d0 = *src++; d1 = *src; - *dst = comp(d0 << left | d1 >> right, *dst, + *dst = comp(d0 >> right | d1 << left, *dst, first); } } else { @@ -109,13 +109,14 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, /* Leading bits */ if (shift > 0) { /* Single source word */ - *dst = comp(d0 >> right, *dst, first); + *dst = comp(d0 << left, *dst, first); dst++; n -= bits - dst_idx; } else { /* 2 source words */ d1 = *src++; - *dst = comp(d0 << left | *dst >> right, *dst, first); + *dst = comp(d0 >> right | d1 << left, *dst, + first); d0 = d1; dst++; n -= bits - dst_idx; @@ -126,36 +127,36 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, n /= bits; while (n >= 4) { d1 = *src++; - *dst++ = d0 << left | d1 >> right; + *dst++ = d0 >> right | d1 << left; d0 = d1; d1 = *src++; - *dst++ = d0 << left | d1 >> right; + *dst++ = d0 >> right | d1 << left; d0 = d1; d1 = *src++; - *dst++ = d0 << left | d1 >> right; + *dst++ = d0 >> right | d1 << left; d0 = d1; d1 = *src++; - *dst++ = d0 << left | d1 >> right; + *dst++ = d0 >> right | d1 << left; d0 = d1; n -= 4; } while (n--) { d1 = *src++; - *dst++ = d0 << left | d1 >> right; + *dst++ = d0 >> right | d1 << left; d0 = d1; } /* Trailing bits */ - if (last) { - if (m <= right) { + if (m) { + if (m <= bits - right) { /* Single source word */ - *dst = comp(d0 << left, *dst, last); + d0 >>= right; } else { /* 2 source words */ d1 = *src; - *dst = comp(d0 << left | d1 >> right, - *dst, last); + d0 = d0 >> right | d1 << left; } + *dst = comp(d0, *dst, last); } } } @@ -166,40 +167,35 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, */ static void -bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, - const unsigned long *src, int src_idx, int bits, unsigned n) +bitcpy_rev(struct fb_info *p, unsigned long *dst, unsigned dst_idx, + const unsigned long *src, unsigned src_idx, unsigned bits, + unsigned n) { unsigned long first, last; int shift; - dst += (n-1)/bits; - src += (n-1)/bits; - if ((n-1) % bits) { - dst_idx += (n-1) % bits; - dst += dst_idx >> (ffs(bits) - 1); - dst_idx &= bits - 1; - src_idx += (n-1) % bits; - src += src_idx >> (ffs(bits) - 1); - src_idx &= bits - 1; - } + dst += (dst_idx + n - 1) / bits; + src += (src_idx + n - 1) / bits; + dst_idx = (dst_idx + n - 1) % bits; + src_idx = (src_idx + n - 1) % bits; shift = dst_idx-src_idx; - first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx); - last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits))); + first = ~FB_SHIFT_HIGH(p, ~0UL, (dst_idx + 1) % bits); + last = FB_SHIFT_HIGH(p, ~0UL, (bits + dst_idx + 1 - n) % bits); if (!shift) { /* Same alignment for source and dest */ if ((unsigned long)dst_idx+1 >= n) { /* Single word */ - if (last) - first &= last; - *dst = comp(*src, *dst, first); + if (first) + last &= first; + *dst = comp(*src, *dst, last); } else { /* Multiple destination words */ /* Leading bits */ - if (first != ~0UL) { + if (first) { *dst = comp(*src, *dst, first); dst--; src--; @@ -222,29 +218,29 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, while (n--) *dst-- = *src--; /* Trailing bits */ - if (last) + if (last != -1UL) *dst = comp(*src, *dst, last); } } else { /* Different alignment for source and dest */ - int const left = -shift & (bits-1); - int const right = shift & (bits-1); + int const left = shift & (bits-1); + int const right = -shift & (bits-1); if ((unsigned long)dst_idx+1 >= n) { /* Single destination word */ - if (last) - first &= last; + if (first) + last &= first; if (shift < 0) { /* Single source word */ - *dst = comp(*src << left, *dst, first); + *dst = comp(*src >> right, *dst, last); } else if (1+(unsigned long)src_idx >= n) { /* Single source word */ - *dst = comp(*src >> right, *dst, first); + *dst = comp(*src << left, *dst, last); } else { /* 2 source words */ - *dst = comp(*src >> right | *(src-1) << left, - *dst, first); + *dst = comp(*src << left | *(src-1) >> right, + *dst, last); } } else { /* Multiple destination words */ @@ -261,14 +257,18 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, /* Leading bits */ if (shift < 0) { /* Single source word */ - *dst = comp(d0 << left, *dst, first); + d1 = d0; + d0 >>= right; } else { /* 2 source words */ d1 = *src--; - *dst = comp(d0 >> right | d1 << left, *dst, - first); - d0 = d1; + d0 = d0 << left | d1 >> right; } + if (!first) + *dst = d0; + else + *dst = comp(d0, *dst, first); + d0 = d1; dst--; n -= dst_idx+1; @@ -277,36 +277,36 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, n /= bits; while (n >= 4) { d1 = *src--; - *dst-- = d0 >> right | d1 << left; + *dst-- = d0 << left | d1 >> right; d0 = d1; d1 = *src--; - *dst-- = d0 >> right | d1 << left; + *dst-- = d0 << left | d1 >> right; d0 = d1; d1 = *src--; - *dst-- = d0 >> right | d1 << left; + *dst-- = d0 << left | d1 >> right; d0 = d1; d1 = *src--; - *dst-- = d0 >> right | d1 << left; + *dst-- = d0 << left | d1 >> right; d0 = d1; n -= 4; } while (n--) { d1 = *src--; - *dst-- = d0 >> right | d1 << left; + *dst-- = d0 << left | d1 >> right; d0 = d1; } /* Trailing bits */ - if (last) { - if (m <= left) { + if (m) { + if (m <= bits - left) { /* Single source word */ - *dst = comp(d0 >> right, *dst, last); + d0 <<= left; } else { /* 2 source words */ d1 = *src; - *dst = comp(d0 >> right | d1 << left, - *dst, last); + d0 = d0 << left | d1 >> right; } + *dst = comp(d0, *dst, last); } } } @@ -317,9 +317,9 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; u32 height = area->height, width = area->width; unsigned long const bits_per_line = p->fix.line_length*8u; - unsigned long *dst = NULL, *src = NULL; + unsigned long *base = NULL; int bits = BITS_PER_LONG, bytes = bits >> 3; - int dst_idx = 0, src_idx = 0, rev_copy = 0; + unsigned dst_idx = 0, src_idx = 0, rev_copy = 0; if (p->state != FBINFO_STATE_RUNNING) return; @@ -334,8 +334,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) /* split the base of the framebuffer into a long-aligned address and the index of the first bit */ - dst = src = (unsigned long *)((unsigned long)p->screen_base & - ~(bytes-1)); + base = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1)); dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1)); /* add offset of source and target area */ dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel; @@ -348,20 +347,14 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) while (height--) { dst_idx -= bits_per_line; src_idx -= bits_per_line; - dst += dst_idx >> (ffs(bits) - 1); - dst_idx &= (bytes - 1); - src += src_idx >> (ffs(bits) - 1); - src_idx &= (bytes - 1); - bitcpy_rev(p, dst, dst_idx, src, src_idx, bits, + bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits, + base + (src_idx / bits), src_idx % bits, bits, width*p->var.bits_per_pixel); } } else { while (height--) { - dst += dst_idx >> (ffs(bits) - 1); - dst_idx &= (bytes - 1); - src += src_idx >> (ffs(bits) - 1); - src_idx &= (bytes - 1); - bitcpy(p, dst, dst_idx, src, src_idx, bits, + bitcpy(p, base + (dst_idx / bits), dst_idx % bits, + base + (src_idx / bits), src_idx % bits, bits, width*p->var.bits_per_pixel); dst_idx += bits_per_line; src_idx += bits_per_line; diff --git a/drivers/video/fbdev/geode/gx1fb_core.c b/drivers/video/fbdev/geode/gx1fb_core.c index 2794ba11f332..9bee8744c438 100644 --- a/drivers/video/fbdev/geode/gx1fb_core.c +++ b/drivers/video/fbdev/geode/gx1fb_core.c @@ -374,10 +374,8 @@ static int gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id *id) release_mem_region(gx1_gx_base() + 0x8300, 0x100); } - if (info) { - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); return ret; } diff --git a/drivers/video/fbdev/geode/gxfb_core.c b/drivers/video/fbdev/geode/gxfb_core.c index 1790f14bab15..124d7c7e2d14 100644 --- a/drivers/video/fbdev/geode/gxfb_core.c +++ b/drivers/video/fbdev/geode/gxfb_core.c @@ -444,10 +444,8 @@ static int gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_release_region(pdev, 1); } - if (info) { - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); return ret; } diff --git a/drivers/video/fbdev/geode/lxfb_core.c b/drivers/video/fbdev/geode/lxfb_core.c index 9e1d19d673a1..138da6cb6cbc 100644 --- a/drivers/video/fbdev/geode/lxfb_core.c +++ b/drivers/video/fbdev/geode/lxfb_core.c @@ -577,10 +577,8 @@ err: pci_release_region(pdev, 3); } - if (info) { - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); return ret; } diff --git a/drivers/video/fbdev/hgafb.c b/drivers/video/fbdev/hgafb.c index 5ff9fe2116a4..15d3ccff2965 100644 --- a/drivers/video/fbdev/hgafb.c +++ b/drivers/video/fbdev/hgafb.c @@ -417,8 +417,7 @@ static int hgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { if (var->vmode & FB_VMODE_YWRAP) { - if (var->yoffset < 0 || - var->yoffset >= info->var.yres_virtual || + if (var->yoffset >= info->var.yres_virtual || var->xoffset) return -EINVAL; } else { diff --git a/drivers/video/fbdev/mmp/Makefile b/drivers/video/fbdev/mmp/Makefile index a014cb358bf8..924dd0930cc7 100644 --- a/drivers/video/fbdev/mmp/Makefile +++ b/drivers/video/fbdev/mmp/Makefile @@ -1 +1,3 @@ -obj-y += core.o hw/ panel/ fb/ +obj-$(CONFIG_MMP_DISP) += mmp_disp.o hw/ panel/ fb/ + +mmp_disp-y += core.o diff --git a/drivers/video/fbdev/mmp/fb/Kconfig b/drivers/video/fbdev/mmp/fb/Kconfig index 9b0141f105f5..985e1a7cd254 100644 --- a/drivers/video/fbdev/mmp/fb/Kconfig +++ b/drivers/video/fbdev/mmp/fb/Kconfig @@ -1,7 +1,7 @@ if MMP_DISP config MMP_FB - bool "fb driver for Marvell MMP Display Subsystem" + tristate "fb driver for Marvell MMP Display Subsystem" depends on FB select FB_CFB_FILLRECT select FB_CFB_COPYAREA diff --git a/drivers/video/fbdev/ocfb.c b/drivers/video/fbdev/ocfb.c index 7f9dc9bec309..de9819660ca0 100644 --- a/drivers/video/fbdev/ocfb.c +++ b/drivers/video/fbdev/ocfb.c @@ -61,7 +61,7 @@ struct ocfb_dev { /* flag indicating whether the regs are little endian accessed */ int little_endian; /* Physical and virtual addresses of framebuffer */ - phys_addr_t fb_phys; + dma_addr_t fb_phys; void __iomem *fb_virt; u32 pseudo_palette[PALETTE_SIZE]; }; diff --git a/drivers/video/fbdev/omap2/displays-new/Kconfig b/drivers/video/fbdev/omap2/displays-new/Kconfig index e6cfc38160d3..574710141a61 100644 --- a/drivers/video/fbdev/omap2/displays-new/Kconfig +++ b/drivers/video/fbdev/omap2/displays-new/Kconfig @@ -1,6 +1,12 @@ menu "OMAP Display Device Drivers (new device model)" depends on OMAP2_DSS +config DISPLAY_ENCODER_OPA362 + tristate "OPA362 external analog amplifier" + help + Driver for OPA362 external analog TV amplifier controlled + through a GPIO. + config DISPLAY_ENCODER_TFP410 tristate "TFP410 DPI to DVI Encoder" help diff --git a/drivers/video/fbdev/omap2/displays-new/Makefile b/drivers/video/fbdev/omap2/displays-new/Makefile index 0323a8a1c682..9aa176bfbf2e 100644 --- a/drivers/video/fbdev/omap2/displays-new/Makefile +++ b/drivers/video/fbdev/omap2/displays-new/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_DISPLAY_ENCODER_OPA362) += encoder-opa362.o obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o diff --git a/drivers/video/fbdev/omap2/displays-new/connector-analog-tv.c b/drivers/video/fbdev/omap2/displays-new/connector-analog-tv.c index 9a2b5ce58545..8511c648a15c 100644 --- a/drivers/video/fbdev/omap2/displays-new/connector-analog-tv.c +++ b/drivers/video/fbdev/omap2/displays-new/connector-analog-tv.c @@ -208,7 +208,7 @@ static int tvc_probe_pdata(struct platform_device *pdev) ddata->in = in; ddata->connector_type = pdata->connector_type; - ddata->invert_polarity = ddata->invert_polarity; + ddata->invert_polarity = pdata->invert_polarity; dssdev = &ddata->dssdev; dssdev->name = pdata->name; diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c b/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c new file mode 100644 index 000000000000..84a6b3367124 --- /dev/null +++ b/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c @@ -0,0 +1,285 @@ +/* + * OPA362 analog video amplifier with output/power control + * + * Copyright (C) 2014 Golden Delicious Computers + * Author: H. Nikolaus Schaller + * + * based on encoder-tfp410 + * + * Copyright (C) 2013 Texas Instruments + * Author: Tomi Valkeinen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include